{"record":{"id":"eae74ed5e4b387ea","repo":"Hmbown/CodeWhale","slug":"the-native-helper-needs-an-update-for-disconnect-safe-held","errorCode":null,"errorMessage":"The native helper needs an update for disconnect-safe held input","messagePattern":"The native helper needs an update for disconnect-safe held input","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/darwin.mjs","lineNumber":317,"sourceCode":"    }\n    return result;\n  }\n\n  async function requireBackgroundActions() {\n    if ((await native(\"input_capabilities\"))?.background_actions !== 1) {\n      throw Object.assign(new ExecError(\"Update the Computer Use helper to use background focus, selection, context menus and scrolling.\"), { code: \"app_upgrade_required\" });\n    }\n  }\n\n  function assertBoundElement(target) {\n    if (!state.inputApp || target.app_ref?.pid !== state.inputApp.pid) throw new ExecError(\"element does not belong to the bound application — open_application and observe again\");\n    if (!Array.isArray(target.path) || !Number.isInteger(target.windowIndex) || !target.role) throw new ExecError(\"element has no resolved accessibility identity\");\n  }\n\n  async function nativeLease(tool, args) {\n    if (tool === \"pointer_sequence\") requireSharedPointer();\n    if (!exec.runInputLease) throw new ExecError(\"This executor cannot safely own held input; update Computer Use\");\n    if ((await native(\"input_capabilities\"))?.input_lease !== 1) throw new ExecError(\"The native helper needs an update for disconnect-safe held input\");\n    const helper = await nativeHelper();\n    try {\n      return await exec.runInputLease(helper, [JSON.stringify({ tool, args: { ...args, ...yieldArgs, input_app_ref: state.inputApp, foreground_input: state.foregroundInput, owner_pipe: true, input_lease: true } })]);\n    } catch (error) {\n      error.code = nativeErrorCode(error.message) ?? error.code;\n      throw error;\n    }\n  }\n\n  async function updatePreview(show = false) {\n    const win = await native(\"window_info\", { app_ref: state.inputApp });\n    const dir = path.join(stateDir(), \"preview\");\n    fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n    const temp = path.join(dir, \"next.png\"), file = path.join(dir, \"latest.png\");\n    const r = await runL(\"screencapture\", [\"-x\", \"-o\", \"-l\", String(win.window_id), \"-t\", \"png\", temp], { timeoutMs: 8000 });\n    if (r.code !== 0) throw new ExecError(`background preview capture failed: ${r.stderr}`);\n    fs.renameSync(temp, file);\n    const p = state.pointer;","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/darwin.mjs#L299-L335","documentation":"Even when the executor supports leases, the compiled native helper itself must advertise `input_lease: 1` in its input_capabilities for disconnect-safe held input. nativeLease queries the helper's capabilities and throws if the capability flag is missing, because older helpers would leak held pointer/keyboard state on disconnect.","triggerScenarios":"nativeLease runs `native(\"input_capabilities\")` and the returned object's input_lease is not 1 — the cached native helper at ~/.codewhale-cu/bin/accessibility-<hash> was compiled from an older helper source and is being reused after the backend was updated.","commonSituations":"A stale cached helper compiled before the input-lease feature was added; the app bundles an outdated helper so the clang-rebuild path (which would compile fresh source) is skipped; failed cache invalidation after a Computer Use upgrade.","solutions":["Delete the stale cached helper: rm ~/.codewhale-cu/bin/accessibility-* so the backend recompiles from current source.","Update Computer Use so a fresh helper with input_lease support is built/bundled.","Verify capabilities manually by running the helper's input_capabilities and checking input_lease === 1.","Avoid held-input tools until the helper is updated; use tap/accessibility actions instead."],"exampleFix":"// before (shell)\n# old cached helper reused\npointer_sequence({ hold: ... }) // helper needs an update\n\n// after (shell, one-time)\nrm -f ~/.codewhale-cu/bin/accessibility-*\npointer_sequence({ hold: ... })","handlingStrategy":"validation","validationCode":"const caps = await native('input_capabilities');\nif (caps?.input_lease !== 1) {\n  throw new Error('refresh helper cache: rm ~/.codewhale-cu/bin/accessibility-*');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await pointer_sequence(args);\n} catch (e) {\n  if (String(e.message).includes('needs an update for disconnect-safe held input')) {\n    throw new Error('delete cached native helper (~/.codewhale-cu/bin) and restart to rebuild');\n  }\n  throw e;\n}","preventionTips":["Clear the ~/.codewhale-cu/bin helper cache after every Computer Use upgrade.","Check input_capabilities.input_lease at session start before offering held-input tools.","Don't ship a bundled pre-built helper older than the backend source — let it rebuild.","Gate drag/hold features on a capability probe rather than assuming support."],"tags":["macos","held-input","version-compatibility","stale-cache"],"backgroundTag":"feature-not-enabled","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}