()
| 71 | } |
| 72 | |
| 73 | export function buildSessionContext(): ComputerUseSessionContext { |
| 74 | return { |
| 75 | // ── Read state fresh via the per-call ref ───────────────────────────── |
| 76 | getAllowedApps: () => tuc().getAppState().computerUseMcpState?.allowedApps ?? [], |
| 77 | getGrantFlags: () => tuc().getAppState().computerUseMcpState?.grantFlags ?? DEFAULT_GRANT_FLAGS, |
| 78 | // cc-2 has no Settings page for user-denied apps yet. |
| 79 | getUserDeniedBundleIds: () => [], |
| 80 | getSelectedDisplayId: () => tuc().getAppState().computerUseMcpState?.selectedDisplayId, |
| 81 | getDisplayPinnedByModel: () => tuc().getAppState().computerUseMcpState?.displayPinnedByModel ?? false, |
| 82 | getDisplayResolvedForApps: () => tuc().getAppState().computerUseMcpState?.displayResolvedForApps, |
| 83 | getLastScreenshotDims: (): ScreenshotDims | undefined => { |
| 84 | const d = tuc().getAppState().computerUseMcpState?.lastScreenshotDims; |
| 85 | return d |
| 86 | ? { |
| 87 | ...d, |
| 88 | displayId: d.displayId ?? 0, |
| 89 | originX: d.originX ?? 0, |
| 90 | originY: d.originY ?? 0, |
| 91 | } |
| 92 | : undefined; |
| 93 | }, |
| 94 | |
| 95 | // ── Write-backs ──────────────────────────────────────────────────────── |
| 96 | // `setToolJSX` is guaranteed present — the gate in `main.tsx` excludes |
| 97 | // non-interactive sessions. The package's `_dialogSignal` (tool-finished |
| 98 | // dismissal) is irrelevant here: `setToolJSX` blocks the tool call, so |
| 99 | // the dialog can't outlive it. Ctrl+C is what matters, and |
| 100 | // `runPermissionDialog` wires that from the per-call ref's abortController. |
| 101 | onPermissionRequest: (req, _dialogSignal) => runPermissionDialog(req), |
| 102 | |
| 103 | // Package does the merge (dedupe + truthy-only flags). We just persist. |
| 104 | onAllowedAppsChanged: (apps, flags) => |
| 105 | tuc().setAppState(prev => { |
| 106 | const cu = prev.computerUseMcpState; |
| 107 | const prevApps = cu?.allowedApps; |
| 108 | const prevFlags = cu?.grantFlags; |
| 109 | const sameApps = prevApps?.length === apps.length && apps.every((a, i) => prevApps[i]?.bundleId === a.bundleId); |
| 110 | const sameFlags = |
| 111 | prevFlags?.clipboardRead === flags.clipboardRead && |
| 112 | prevFlags?.clipboardWrite === flags.clipboardWrite && |
| 113 | prevFlags?.systemKeyCombos === flags.systemKeyCombos; |
| 114 | return sameApps && sameFlags |
| 115 | ? prev |
| 116 | : { |
| 117 | ...prev, |
| 118 | computerUseMcpState: { |
| 119 | ...cu, |
| 120 | allowedApps: [...apps], |
| 121 | grantFlags: flags, |
| 122 | }, |
| 123 | }; |
| 124 | }), |
| 125 | |
| 126 | onAppsHidden: ids => { |
| 127 | if (ids.length === 0) return; |
| 128 | tuc().setAppState(prev => { |
| 129 | const cu = prev.computerUseMcpState; |
| 130 | const existing = cu?.hiddenDuringTurn; |
no test coverage detected