(
ctx: Pick<
ToolUseContext,
'getAppState' | 'setAppState' | 'sendOSNotification'
>,
)
| 28 | * No-ops cheaply on non-CU turns: both gate checks are zero-syscall. |
| 29 | */ |
| 30 | export async function cleanupComputerUseAfterTurn( |
| 31 | ctx: Pick< |
| 32 | ToolUseContext, |
| 33 | 'getAppState' | 'setAppState' | 'sendOSNotification' |
| 34 | >, |
| 35 | ): Promise<void> { |
| 36 | const appState = ctx.getAppState() |
| 37 | |
| 38 | const hidden = appState.computerUseMcpState?.hiddenDuringTurn |
| 39 | if (hidden && hidden.size > 0) { |
| 40 | const { unhideComputerUseApps } = await import('./executor.js') |
| 41 | const unhide = unhideComputerUseApps([...hidden]).catch(err => |
| 42 | logForDebugging( |
| 43 | `[Computer Use MCP] auto-unhide failed: ${errorMessage(err)}`, |
| 44 | ), |
| 45 | ) |
| 46 | const timeout = withResolvers<void>() |
| 47 | const timer = setTimeout(timeout.resolve, UNHIDE_TIMEOUT_MS) |
| 48 | await Promise.race([unhide, timeout.promise]).finally(() => |
| 49 | clearTimeout(timer), |
| 50 | ) |
| 51 | ctx.setAppState(prev => |
| 52 | prev.computerUseMcpState?.hiddenDuringTurn === undefined |
| 53 | ? prev |
| 54 | : { |
| 55 | ...prev, |
| 56 | computerUseMcpState: { |
| 57 | ...prev.computerUseMcpState, |
| 58 | hiddenDuringTurn: undefined, |
| 59 | }, |
| 60 | }, |
| 61 | ) |
| 62 | } |
| 63 | |
| 64 | // Zero-syscall pre-check so non-CU turns don't touch disk. Release is still |
| 65 | // idempotent (returns false if already released or owned by another session). |
| 66 | if (!isLockHeldLocally()) return |
| 67 | |
| 68 | // Unregister before lock release so the pump-retain drops as soon as the |
| 69 | // CU session ends. Idempotent — no-ops if registration failed at acquire. |
| 70 | // Swallow throws so a NAPI unregister error never prevents lock release — |
| 71 | // a held lock blocks the next CU session with "in use by another session". |
| 72 | try { |
| 73 | unregisterEscHotkey() |
| 74 | } catch (err) { |
| 75 | logForDebugging( |
| 76 | `[Computer Use MCP] unregisterEscHotkey failed: ${errorMessage(err)}`, |
| 77 | ) |
| 78 | } |
| 79 | |
| 80 | if (await releaseComputerUseLock()) { |
| 81 | ctx.sendOSNotification?.({ |
| 82 | message: 'Claude is done using your computer', |
| 83 | notificationType: 'computer_use_exit', |
| 84 | }) |
| 85 | } |
| 86 | } |
| 87 |
no test coverage detected