gclm-code 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +1 -1
  2. package/bin/gc.js +53 -25
  3. package/bin/install-runtime.js +253 -0
  4. package/package.json +10 -5
  5. package/vendor/manifest.json +92 -0
  6. package/vendor/modules/node_modules/@ant/claude-for-chrome-mcp/package.json +9 -0
  7. package/vendor/modules/node_modules/@ant/claude-for-chrome-mcp/src/bridgeClient.ts +1126 -0
  8. package/vendor/modules/node_modules/@ant/claude-for-chrome-mcp/src/browserTools.ts +546 -0
  9. package/vendor/modules/node_modules/@ant/claude-for-chrome-mcp/src/index.ts +15 -0
  10. package/vendor/modules/node_modules/@ant/claude-for-chrome-mcp/src/mcpServer.ts +96 -0
  11. package/vendor/modules/node_modules/@ant/claude-for-chrome-mcp/src/mcpSocketClient.ts +493 -0
  12. package/vendor/modules/node_modules/@ant/claude-for-chrome-mcp/src/mcpSocketPool.ts +327 -0
  13. package/vendor/modules/node_modules/@ant/claude-for-chrome-mcp/src/toolCalls.ts +301 -0
  14. package/vendor/modules/node_modules/@ant/claude-for-chrome-mcp/src/types.ts +134 -0
  15. package/vendor/modules/node_modules/@ant/computer-use-input/package.json +9 -0
  16. package/vendor/modules/node_modules/@ant/computer-use-input/src/driver-jxa.js +341 -0
  17. package/vendor/modules/node_modules/@ant/computer-use-input/src/driver-swift.swift +417 -0
  18. package/vendor/modules/node_modules/@ant/computer-use-input/src/implementation.js +204 -0
  19. package/vendor/modules/node_modules/@ant/computer-use-input/src/index.js +5 -0
  20. package/vendor/modules/node_modules/@ant/computer-use-mcp/package.json +11 -0
  21. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/deniedApps.ts +553 -0
  22. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/imageResize.ts +108 -0
  23. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/index.ts +69 -0
  24. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/keyBlocklist.ts +153 -0
  25. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/mcpServer.ts +313 -0
  26. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/pixelCompare.ts +171 -0
  27. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/sentinelApps.ts +43 -0
  28. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/subGates.ts +19 -0
  29. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/toolCalls.ts +3872 -0
  30. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/tools.ts +706 -0
  31. package/vendor/modules/node_modules/@ant/computer-use-mcp/src/types.ts +635 -0
  32. package/vendor/modules/node_modules/@ant/computer-use-swift/package.json +9 -0
  33. package/vendor/modules/node_modules/@ant/computer-use-swift/src/driver-jxa.js +108 -0
  34. package/vendor/modules/node_modules/@ant/computer-use-swift/src/implementation.js +706 -0
  35. package/vendor/modules/node_modules/@ant/computer-use-swift/src/index.js +7 -0
  36. package/vendor/modules/node_modules/audio-capture-napi/package.json +8 -0
  37. package/vendor/modules/node_modules/audio-capture-napi/src/index.ts +226 -0
  38. package/vendor/modules/node_modules/image-processor-napi/package.json +11 -0
  39. package/vendor/modules/node_modules/image-processor-napi/src/index.ts +396 -0
  40. package/vendor/modules/node_modules/modifiers-napi/package.json +8 -0
  41. package/vendor/modules/node_modules/modifiers-napi/src/index.ts +79 -0
  42. package/vendor/modules/node_modules/url-handler-napi/package.json +8 -0
  43. package/vendor/modules/node_modules/url-handler-napi/src/index.ts +62 -0
@@ -0,0 +1,635 @@
1
+ import type {
2
+ ComputerExecutor,
3
+ InstalledApp,
4
+ ScreenshotResult,
5
+ } from "./executor.js";
6
+
7
+ /** `ScreenshotResult` without the base64 blob. The shape hosts persist for
8
+ * cross-respawn `scaleCoord` survival. */
9
+ export type ScreenshotDims = Omit<ScreenshotResult, "base64">;
10
+
11
+ /** Shape mirrors claude-for-chrome-mcp/src/types.ts:1-7 */
12
+ export interface Logger {
13
+ info: (message: string, ...args: unknown[]) => void;
14
+ error: (message: string, ...args: unknown[]) => void;
15
+ warn: (message: string, ...args: unknown[]) => void;
16
+ debug: (message: string, ...args: unknown[]) => void;
17
+ silly: (message: string, ...args: unknown[]) => void;
18
+ }
19
+
20
+ /**
21
+ * Per-app permission tier. Hardcoded by category at grant time — the
22
+ * approval dialog displays the tier but the user cannot change it (for now).
23
+ *
24
+ * - `"read"` — visible in screenshots, NO interaction (no clicks, no typing).
25
+ * Browsers land here: the model can read a page that's already open, but
26
+ * must use the Claude-in-Chrome MCP for any navigation/clicking. Trading
27
+ * platforms land here too (no CiC alternative — the model asks the user).
28
+ * - `"click"` — visible + plain left-click, scroll. NO typing/keys,
29
+ * NO right/middle-click, NO modifier-clicks, NO drag-drop (all text-
30
+ * injection vectors). Terminals/IDEs land here: the model can click a
31
+ * Run button or scroll test output, but `type("rm -rf /")` is blocked
32
+ * and so is right-click→Paste and dragging text onto the terminal.
33
+ * - `"full"` — visible + click + type/key/paste. Everything else.
34
+ *
35
+ * Enforced in `runInputActionGates` via the frontmost-app check: keyboard
36
+ * actions require `"full"`, mouse actions require `"click"` or higher.
37
+ */
38
+ export type CuAppPermTier = "read" | "click" | "full";
39
+
40
+ /**
41
+ * A single app the user has approved for the current session. Session-scoped
42
+ * only — there is no "once" or "forever" scope (unlike Chrome's per-domain
43
+ * three-way). CU has no natural "once" unit; one task = hundreds of clicks.
44
+ * Mirrors how `chromeAllowedDomains` is a plain `string[]` with no per-item
45
+ * scope.
46
+ */
47
+ export interface AppGrant {
48
+ bundleId: string;
49
+ displayName: string;
50
+ /** Epoch ms. For Settings-page display ("Granted 3m ago"). */
51
+ grantedAt: number;
52
+ /** Undefined → `"full"` (back-compat for pre-tier grants persisted in
53
+ * session state). */
54
+ tier?: CuAppPermTier;
55
+ }
56
+
57
+ /** Orthogonal to the app allowlist. */
58
+ export interface CuGrantFlags {
59
+ clipboardRead: boolean;
60
+ clipboardWrite: boolean;
61
+ /**
62
+ * When false, the `key` tool rejects combos in `keyBlocklist.ts`
63
+ * (cmd+q, cmd+tab, cmd+space, cmd+shift+q, ctrl+alt+delete). All other
64
+ * key sequences work regardless.
65
+ */
66
+ systemKeyCombos: boolean;
67
+ }
68
+
69
+ export const DEFAULT_GRANT_FLAGS: CuGrantFlags = {
70
+ clipboardRead: false,
71
+ clipboardWrite: false,
72
+ systemKeyCombos: false,
73
+ };
74
+
75
+ /**
76
+ * Host picks via GrowthBook JSON feature `chicago_coordinate_mode`, baked
77
+ * into tool param descriptions at server-construction time. The model sees
78
+ * ONE convention and never learns the other exists. `normalized_0_100`
79
+ * sidesteps the Retina scaleFactor bug class entirely.
80
+ */
81
+ export type CoordinateMode = "pixels" | "normalized_0_100";
82
+
83
+ /**
84
+ * Independent kill switches for subtle/risky ported behaviors. Read from
85
+ * GrowthBook by the host adapter, consulted in `toolCalls.ts`.
86
+ */
87
+ export interface CuSubGates {
88
+ /** 9×9 exact-byte staleness guard before click. */
89
+ pixelValidation: boolean;
90
+ /** Route `type("foo\nbar")` through clipboard instead of keystroke-by-keystroke. */
91
+ clipboardPasteMultiline: boolean;
92
+ /**
93
+ * Ease-out-cubic mouse glide at 60fps, distance-proportional duration
94
+ * (2000 px/sec, capped at 0.5s). Adds up to ~0.5s latency
95
+ * per click. When off, cursor teleports instantly.
96
+ */
97
+ mouseAnimation: boolean;
98
+ /**
99
+ * Pre-action sequence: hide non-allowlisted apps, then defocus us (from the
100
+ * Vercept acquisition). When off, the
101
+ * frontmost gate fires in the normal case and the model gets stuck — this
102
+ * is the A/B-test-the-old-broken-behavior switch.
103
+ */
104
+ hideBeforeAction: boolean;
105
+ /**
106
+ * Auto-resolve the target display before each screenshot when the
107
+ * selected display has no allowed-app windows. When on, `handleScreenshot`
108
+ * uses the atomic backend path; off → sticks with `selectedDisplayId`.
109
+ */
110
+ autoTargetDisplay: boolean;
111
+ /**
112
+ * Stash+clear the clipboard while a tier-"click" app is frontmost.
113
+ * Closes the gap where a click-tier terminal/IDE has a UI Paste button
114
+ * that's plain-left-clickable — without this, the tier "click"
115
+ * keyboard block can be routed around by clicking Paste. Restored when
116
+ * a non-"click" app becomes frontmost, or at turn end.
117
+ */
118
+ clipboardGuard: boolean;
119
+ }
120
+
121
+ // ----------------------------------------------------------------------------
122
+ // Permission request/response (mirror of BridgePermissionRequest, types.ts:77-94)
123
+ // ----------------------------------------------------------------------------
124
+
125
+ /** One entry per app the model asked for, after name → bundle ID resolution. */
126
+ export interface ResolvedAppRequest {
127
+ /** What the model asked for (e.g. "Slack", "com.tinyspeck.slackmacgap"). */
128
+ requestedName: string;
129
+ /** The resolved InstalledApp if found, else undefined (shown greyed in the UI). */
130
+ resolved?: InstalledApp;
131
+ /** Shell-access-equivalent bundle IDs get a UI warning. See sentinelApps.ts. */
132
+ isSentinel: boolean;
133
+ /** Already in the allowlist → skip the checkbox, return in `granted` immediately. */
134
+ alreadyGranted: boolean;
135
+ /** Hardcoded tier for this app (browser→"read", terminal→"click", else "full").
136
+ * The dialog displays this read-only; the renderer passes it through
137
+ * verbatim in the AppGrant. */
138
+ proposedTier: CuAppPermTier;
139
+ }
140
+
141
+ /**
142
+ * Payload for the renderer approval dialog. Rides through the existing
143
+ * `ToolPermissionRequest.input: unknown` field
144
+ * (packages/utils/desktop/bridge/common/claude.web.ts:1262) — no IPC schema
145
+ * change needed.
146
+ */
147
+ export interface CuPermissionRequest {
148
+ requestId: string;
149
+ /** Model-provided reason string. Shown prominently in the approval UI. */
150
+ reason: string;
151
+ apps: ResolvedAppRequest[];
152
+ /** What the model asked for. User can toggle independently of apps. */
153
+ requestedFlags: Partial<CuGrantFlags>;
154
+ /**
155
+ * For the "On Windows, Claude can see all apps..." footnote. Taken from
156
+ * `executor.capabilities.screenshotFiltering` so the renderer doesn't
157
+ * need to know about platforms.
158
+ */
159
+ screenshotFiltering: "native" | "none";
160
+ /**
161
+ * Present only when TCC permissions are NOT yet granted. When present,
162
+ * the renderer shows a TCC toggle panel (two rows: Accessibility, Screen
163
+ * Recording) INSTEAD OF the app list. Clicking a row's "Request" button
164
+ * triggers the OS prompt; the store polls on window-focus and flips the
165
+ * toggle when the grant is detected. macOS itself prompts the user to
166
+ * restart after granting Screen Recording — we don't.
167
+ */
168
+ tccState?: {
169
+ accessibility: boolean;
170
+ screenRecording: boolean;
171
+ };
172
+ /**
173
+ * Apps with windows on the CU display that aren't in the requested
174
+ * allowlist. These will be hidden the first time Claude takes an action.
175
+ * Computed at request_access time — may be slightly stale by the time the
176
+ * user clicks Allow, but it's a preview, not a contract. Absent when
177
+ * empty so the renderer can skip the section cleanly.
178
+ */
179
+ willHide?: Array<{ bundleId: string; displayName: string }>;
180
+ /**
181
+ * `chicagoAutoUnhide` app preference at request time. The renderer picks
182
+ * between "...then restored when Claude is done" and "...will be hidden"
183
+ * copy. Absent when `willHide` is absent (same condition).
184
+ */
185
+ autoUnhideEnabled?: boolean;
186
+ }
187
+
188
+ /**
189
+ * What the renderer stuffs into `updatedInput._cuGrants` when the user clicks
190
+ * "Allow for this session" (mirror of the `_allowAllSites` sentinel at
191
+ * LocalAgentModeSessionManager.ts:2794).
192
+ */
193
+ export interface CuPermissionResponse {
194
+ granted: AppGrant[];
195
+ /** Bundle IDs the user unchecked, or apps that weren't installed. */
196
+ denied: Array<{ bundleId: string; reason: "user_denied" | "not_installed" }>;
197
+ flags: CuGrantFlags;
198
+ /**
199
+ * Whether the user clicked Allow in THIS dialog. Only set by the
200
+ * teach-mode handler — regular request_access doesn't need it (the
201
+ * session manager's `result.behavior` gates the merge there). Needed
202
+ * because when all requested apps are already granted (skipDialogGrants
203
+ * non-empty, needDialog empty), Allow and Deny produce identical
204
+ * `{granted:[], denied:[]}` payloads and the tool handler can't tell
205
+ * them apart without this. Undefined → legacy/regular path, do not
206
+ * gate on it.
207
+ */
208
+ userConsented?: boolean;
209
+ }
210
+
211
+ // ----------------------------------------------------------------------------
212
+ // Host adapter (mirror of ClaudeForChromeContext, types.ts:33-62)
213
+ // ----------------------------------------------------------------------------
214
+
215
+ /**
216
+ * Process-lifetime singleton dependencies. Everything that does NOT vary per
217
+ * tool call. Built once by `apps/desktop/src/main/nest-only/chicago/hostAdapter.ts`.
218
+ * No Electron imports in this package — the host injects everything.
219
+ */
220
+ export interface ComputerUseHostAdapter {
221
+ serverName: string;
222
+ logger: Logger;
223
+ executor: ComputerExecutor;
224
+
225
+ /**
226
+ * Capability-scoped TCC check on macOS. Callers specify which permissions the
227
+ * current tool path actually needs; hosts only request the missing subset
228
+ * when `requestMissing` is left enabled. `request_access` /
229
+ * `request_teach_access` call this with both flags set and
230
+ * `requestMissing:false` so the renderer can show the current state without
231
+ * triggering fresh OS prompts.
232
+ */
233
+ ensureOsPermissions(
234
+ required?: CuOsPermissionRequirements,
235
+ options?: { requestMissing?: boolean },
236
+ ): Promise<CuOsPermissionState>;
237
+
238
+ /** The Settings-page kill switch (`chicagoEnabled` app preference). */
239
+ isDisabled(): boolean;
240
+
241
+ /**
242
+ * The `chicagoAutoUnhide` app preference. Consumed by `buildAccessRequest`
243
+ * to populate `CuPermissionRequest.autoUnhideEnabled` so the renderer's
244
+ * "will be hidden" copy can say "then restored" only when true.
245
+ */
246
+ getAutoUnhideEnabled(): boolean;
247
+
248
+ /**
249
+ * Sub-gates re-read on every tool call so GrowthBook flips take effect
250
+ * mid-session without restart.
251
+ */
252
+ getSubGates(): CuSubGates;
253
+
254
+ /**
255
+ * JPEG decode + crop + raw pixel bytes, for the PixelCompare staleness guard.
256
+ * Injected so this package stays Electron-free. The host implements it via
257
+ * `nativeImage.createFromBuffer(jpeg).crop(rect).toBitmap()` — Chromium's
258
+ * decoders, BSD-licensed, no `.node` binary.
259
+ *
260
+ * Returns null on decode/crop failure — caller treats null as `skipped`,
261
+ * click proceeds (validation failure must never block the action).
262
+ */
263
+ cropRawPatch(
264
+ jpegBase64: string,
265
+ rect: { x: number; y: number; width: number; height: number },
266
+ ): Buffer | null;
267
+ }
268
+
269
+ export interface CuOsPermissionRequirements {
270
+ accessibility?: boolean;
271
+ screenRecording?: boolean;
272
+ }
273
+
274
+ export interface CuOsPermissionState {
275
+ granted: boolean;
276
+ accessibility: boolean;
277
+ screenRecording: boolean;
278
+ }
279
+
280
+ // ----------------------------------------------------------------------------
281
+ // Session context (getter/callback bag for bindSessionContext)
282
+ // ----------------------------------------------------------------------------
283
+
284
+ /**
285
+ * Per-session state binding for `bindSessionContext`. Hosts build this once
286
+ * per session with getters that read fresh from their session store and
287
+ * callbacks that write back. The returned dispatcher builds
288
+ * `ComputerUseOverrides` from these getters on every call.
289
+ *
290
+ * Callbacks must be set at construction time — `bindSessionContext` reads
291
+ * them once at bind, not per call.
292
+ *
293
+ * The lock hooks are **async** — `bindSessionContext` awaits them before
294
+ * `handleToolCall`, then passes `checkCuLock: undefined` in overrides so the
295
+ * sync Gate-3 in `handleToolCall` no-ops. Hosts with in-memory sync locks
296
+ * (Cowork) wrap them trivially; hosts with cross-process locks (the CLI's
297
+ * O_EXCL file) call the real async primitive directly.
298
+ */
299
+ export interface ComputerUseSessionContext {
300
+ // ── Read state fresh per call ──────────────────────────────────────
301
+
302
+ getAllowedApps(): readonly AppGrant[];
303
+ getGrantFlags(): CuGrantFlags;
304
+ /** Per-user auto-deny list (Settings page). Empty array = none. */
305
+ getUserDeniedBundleIds(): readonly string[];
306
+ getSelectedDisplayId(): number | undefined;
307
+ getDisplayPinnedByModel?(): boolean;
308
+ getDisplayResolvedForApps?(): string | undefined;
309
+ getTeachModeActive?(): boolean;
310
+ /** Dims-only fallback when `lastScreenshot` is unset (cross-respawn).
311
+ * `bindSessionContext` reconstructs `{...dims, base64: ""}` so scaleCoord
312
+ * works and pixelCompare correctly skips. */
313
+ getLastScreenshotDims?(): ScreenshotDims | undefined;
314
+
315
+ // ── Write-back callbacks ───────────────────────────────────────────
316
+
317
+ /** Shows the approval dialog. Host routes to its UI, awaits user. The
318
+ * signal is aborted if the tool call finishes before the user answers
319
+ * (MCP timeout, etc.) — hosts dismiss the dialog on abort. */
320
+ onPermissionRequest?(
321
+ req: CuPermissionRequest,
322
+ signal: AbortSignal,
323
+ ): Promise<CuPermissionResponse>;
324
+ /** Teach-mode sibling of `onPermissionRequest`. */
325
+ onTeachPermissionRequest?(
326
+ req: CuTeachPermissionRequest,
327
+ signal: AbortSignal,
328
+ ): Promise<CuPermissionResponse>;
329
+ /** Called by `bindSessionContext` after merging a permission response into
330
+ * the allowlist (dedupe on bundleId, truthy-only flag spread). Host
331
+ * persists for resume survival. */
332
+ onAllowedAppsChanged?(apps: readonly AppGrant[], flags: CuGrantFlags): void;
333
+ onAppsHidden?(bundleIds: string[]): void;
334
+ /** Reads the session's clipboardGuard stash. undefined → no stash held. */
335
+ getClipboardStash?(): string | undefined;
336
+ /** Writes the clipboardGuard stash. undefined clears it. */
337
+ onClipboardStashChanged?(stash: string | undefined): void;
338
+ onResolvedDisplayUpdated?(displayId: number): void;
339
+ onDisplayPinned?(displayId: number | undefined): void;
340
+ onDisplayResolvedForApps?(sortedBundleIdsKey: string): void;
341
+ /** Called after each screenshot. Host persists for respawn survival. */
342
+ onScreenshotCaptured?(dims: ScreenshotDims): void;
343
+ onTeachModeActivated?(): void;
344
+ onTeachStep?(req: TeachStepRequest): Promise<TeachStepResult>;
345
+ onTeachWorking?(): void;
346
+
347
+ // ── Lock (async) ───────────────────────────────────────────────────
348
+
349
+ /** At most one session uses CU at a time. Awaited by `bindSessionContext`
350
+ * before dispatch. Undefined → no lock gating (proceed). */
351
+ checkCuLock?(): Promise<{ holder: string | undefined; isSelf: boolean }>;
352
+ /** Take the lock. Called when `checkCuLock` returned `holder: undefined`
353
+ * on a non-deferring tool. Host emits enter-CU signals here. */
354
+ acquireCuLock?(): Promise<void>;
355
+ /** Host-specific lock-held error text. Default is the package's generic
356
+ * message. The CLI host includes the holder session-ID prefix. */
357
+ formatLockHeldMessage?(holder: string): string;
358
+
359
+ /** User-abort signal. Passed through to `ComputerUseOverrides.isAborted`
360
+ * for the mid-loop checks in handleComputerBatch / handleType. See that
361
+ * field for semantics. */
362
+ isAborted?(): boolean;
363
+ }
364
+
365
+ // ----------------------------------------------------------------------------
366
+ // Per-call overrides (mirror of PermissionOverrides, types.ts:97-102)
367
+ // ----------------------------------------------------------------------------
368
+
369
+ /**
370
+ * Built FRESH on every tool call by `bindSessionContext` from
371
+ * `ComputerUseSessionContext` getters. This is what lets a singleton MCP
372
+ * server carry per-session state — the state lives on the host's session
373
+ * store, not the server.
374
+ */
375
+ export interface ComputerUseOverrides {
376
+ allowedApps: AppGrant[];
377
+ grantFlags: CuGrantFlags;
378
+ coordinateMode: CoordinateMode;
379
+
380
+ /**
381
+ * User-configured auto-deny list (Settings → Desktop app → Computer Use).
382
+ * Bundle IDs
383
+ * here are stripped from request_access BEFORE the approval dialog — they
384
+ * never reach the user for approval regardless of tier. The response tells
385
+ * the agent to ask the user to remove the app from their deny list in
386
+ * Settings if access is genuinely needed.
387
+ *
388
+ * Per-USER, persists across restarts (read from appPreferences per call,
389
+ * not session state). Contrast with `allowedApps` which is per-session.
390
+ * Empty array = no user-configured denies (the default).
391
+ */
392
+ userDeniedBundleIds: readonly string[];
393
+
394
+ /**
395
+ * Display CU operates on; read fresh per call. `scaleCoord` uses the
396
+ * `originX/Y` snapshotted in `lastScreenshot`, so mid-session switches
397
+ * only affect the NEXT screenshot/prepare call.
398
+ */
399
+ selectedDisplayId?: number;
400
+
401
+ /**
402
+ * The `request_access` tool handler calls this and awaits. The wrapper
403
+ * closure in serverDef.ts (mirroring InternalMcpServerManager.ts:131-177)
404
+ * routes through `handleToolPermission` → IPC → renderer ChicagoApproval.
405
+ * When it resolves, the wrapper side-effectfully mutates
406
+ * `InternalServerContext.cuAllowedApps` BEFORE returning here.
407
+ *
408
+ * Undefined when the session wasn't wired with a permission handler (e.g.
409
+ * a future headless mode). `request_access` returns a tool error in that case.
410
+ */
411
+ onPermissionRequest?: (req: CuPermissionRequest) => Promise<CuPermissionResponse>;
412
+
413
+ /**
414
+ * For the pixel-validation staleness guard. The model's-last-screenshot,
415
+ * stashed by serverDef.ts after each `screenshot` tool call. Undefined on
416
+ * cold start → pixel validation skipped (click proceeds).
417
+ */
418
+ lastScreenshot?: ScreenshotResult;
419
+
420
+ /**
421
+ * Fired after every `prepareForAction` with the bundle IDs it just hid.
422
+ * The wrapper closure in serverDef.ts accumulates these into
423
+ * `Session.cuHiddenDuringTurn` via a write-through callback (same pattern
424
+ * as `onCuPermissionUpdated`). At turn end (`sdkMessage.type === "result"`),
425
+ * if the `chicagoAutoUnhide` setting is on, everything in the set is
426
+ * unhidden. Set is cleared regardless of the setting so it doesn't leak
427
+ * across turns.
428
+ *
429
+ * Undefined when the session wasn't wired with a tracker — unhide just
430
+ * doesn't happen.
431
+ */
432
+ onAppsHidden?: (bundleIds: string[]) => void;
433
+
434
+ /**
435
+ * Reads the clipboardGuard stash from session state. `undefined` means no
436
+ * stash is held — `syncClipboardStash` stashes on first entry to click-tier
437
+ * and clears on restore. Sibling of the `cuHiddenDuringTurn` getter pattern
438
+ * — state lives on the host's session, not module-level here.
439
+ */
440
+ getClipboardStash?: () => string | undefined;
441
+
442
+ /**
443
+ * Writes the clipboardGuard stash to session state. `undefined` clears.
444
+ * Sibling of `onAppsHidden` — the wrapper closure writes through to
445
+ * `Session.cuClipboardStash`. At turn end the host reads + clears it
446
+ * directly and restores via Electron's `clipboard.writeText` (no nest-only
447
+ * import surface).
448
+ */
449
+ onClipboardStashChanged?: (stash: string | undefined) => void;
450
+
451
+ /**
452
+ * Write the resolver's picked display back to session so teach overlay
453
+ * positioning and subsequent non-resolver calls use the same display.
454
+ * Fired by `handleScreenshot` in the atomic `autoTargetDisplay` path when
455
+ * `resolvePrepareCapture`'s pick differs from `selectedDisplayId`.
456
+ * Fire-and-forget.
457
+ */
458
+ onResolvedDisplayUpdated?: (displayId: number) => void;
459
+
460
+ /**
461
+ * Set when the model explicitly picked a display via `switch_display`.
462
+ * When true, `handleScreenshot` passes `autoResolve: false` so the backend
463
+ * resolver honors `selectedDisplayId` directly (straight cuDisplayInfo
464
+ * passthrough) instead of running the co-location/chase chain. The
465
+ * resolver's Step 2 ("host + allowed co-located → host") otherwise
466
+ * overrides any `selectedDisplayId` whenever an allowed app shares the
467
+ * host's monitor.
468
+ */
469
+ displayPinnedByModel?: boolean;
470
+
471
+ /**
472
+ * Write the model's explicit display pick to session. `displayId:
473
+ * undefined` clears both `selectedDisplayId` and the pin (back to auto).
474
+ * Sibling of `onResolvedDisplayUpdated` but also sets the pin flag —
475
+ * the two are semantically distinct (resolver-picked vs model-picked).
476
+ */
477
+ onDisplayPinned?: (displayId: number | undefined) => void;
478
+
479
+ /**
480
+ * Sorted comma-joined bundle-ID set the display was last auto-resolved
481
+ * for. `handleScreenshot` compares this to the current allowed set and
482
+ * only passes `autoResolve: true` when they differ — so the resolver
483
+ * doesn't yank the display on every screenshot, only when the app set
484
+ * has changed since the last resolve (or manual switch).
485
+ */
486
+ displayResolvedForApps?: string;
487
+
488
+ /**
489
+ * Records which app set the current display selection was made for. Fired
490
+ * alongside `onResolvedDisplayUpdated` when the resolver picks, so the next
491
+ * screenshot sees a matching set and skips auto-resolve.
492
+ */
493
+ onDisplayResolvedForApps?: (sortedBundleIdsKey: string) => void;
494
+
495
+ /**
496
+ * Global CU lock — at most one session actively uses CU at a time. Checked
497
+ * in `handleToolCall` after kill-switch/TCC, before dispatch. Every CU tool
498
+ * including `request_access` goes through it.
499
+ *
500
+ * - `holder === undefined` → lock is free, safe to acquire
501
+ * - `isSelf === true` → this session already holds it (no-op, proceed)
502
+ * - `holder !== undefined && !isSelf` → blocked, return tool error
503
+ *
504
+ * `undefined` callback → lock system not wired (e.g. CCD). Proceed without
505
+ * gating — absence of the mechanism ≠ locked out.
506
+ *
507
+ * The host manages release (on session idle/stop/archive) — this package
508
+ * never releases.
509
+ */
510
+ checkCuLock?: () => { holder: string | undefined; isSelf: boolean };
511
+
512
+ /**
513
+ * Take the lock for this session. `handleToolCall` calls this exactly once
514
+ * per turn, on the FIRST CU tool call when `checkCuLock().holder` is
515
+ * undefined. No-op if already held (defensive — the check should have
516
+ * short-circuited). Host emits an event the overlay listens to.
517
+ */
518
+ acquireCuLock?: () => void;
519
+
520
+ /**
521
+ * User-abort signal. Checked mid-iteration inside `handleComputerBatch`
522
+ * and `handleType`'s grapheme loop so an in-flight batch/type stops
523
+ * promptly on overlay Stop instead of running to completion after the
524
+ * host has already abandoned the tool result.
525
+ *
526
+ * Undefined → never aborts (e.g. unwired host). Live per-check read —
527
+ * same lazy-getter pattern as `checkCuLock`.
528
+ */
529
+ isAborted?: () => boolean;
530
+
531
+ // ── Teach mode ───────────────────────────────────────────────────────
532
+ // Wired only when the host's teachModeEnabled gate is on. All five
533
+ // undefined → `request_teach_access` / `teach_step` return tool errors
534
+ // and teach mode is effectively off.
535
+
536
+ /**
537
+ * Sibling of `onPermissionRequest`. Same blocking-await-on-renderer-dialog
538
+ * semantics, but routes to ComputerUseTeachApproval.tsx (which explains
539
+ * the window-hides-during-guide behavior) instead of ComputerUseApproval.
540
+ * The wrapper closure in serverDef.ts writes grants through to session state
541
+ * via `onCuPermissionUpdated` exactly as `onPermissionRequest` does.
542
+ */
543
+ onTeachPermissionRequest?: (
544
+ req: CuTeachPermissionRequest,
545
+ ) => Promise<CuPermissionResponse>;
546
+
547
+ /**
548
+ * Called by `handleRequestTeachAccess` after the user approves and at least
549
+ * one app was granted. Host sets `session.teachModeActive = true`, emits
550
+ * `teachModeChanged` → teach controller hides the main window and shows the
551
+ * fullscreen overlay. Cleared by the host on turn end (`transitionTo("idle")`)
552
+ * alongside the CU lock release.
553
+ */
554
+ onTeachModeActivated?: () => void;
555
+
556
+ /**
557
+ * Read by `handleRequestAccess` and `handleRequestTeachAccess` to
558
+ * short-circuit with a clear tool error when teach mode is active. The
559
+ * main window is hidden during teach mode, so permission dialogs render
560
+ * invisibly and handleToolPermission blocks forever on an invisible
561
+ * prompt. Better to tell the model to exit teach mode first. Getter
562
+ * (not a boolean field) because teach mode state lives on the session,
563
+ * not on this per-call overrides object.
564
+ */
565
+ getTeachModeActive?: () => boolean;
566
+
567
+ /**
568
+ * Called by `handleTeachStep` with the scaled anchor + text. Host stores
569
+ * the resolver, emits `teachStepRequested` → teach controller pushes the
570
+ * payload to the overlay → user reads, clicks Next → IPC → host calls the
571
+ * stored resolver → this promise resolves. `{action: "exit"}` when the user
572
+ * clicks Exit (or the turn is interrupted) — `handleTeachStep` short-circuits
573
+ * without executing actions.
574
+ *
575
+ * Same blocking-promise pattern as `onPermissionRequest`, but resolved by
576
+ * the teach overlay's own preload (not the main renderer's tool-approval UI).
577
+ */
578
+ onTeachStep?: (req: TeachStepRequest) => Promise<TeachStepResult>;
579
+
580
+ /**
581
+ * Called immediately after `onTeachStep` resolves with "next", before
582
+ * action dispatch begins. Host emits `teachStepWorking` → overlay flips to
583
+ * the spinner state (Next button gone, Exit stays, "Working…" + rotating
584
+ * notch). The next `onTeachStep` call replaces the spinner with the new
585
+ * tooltip content.
586
+ */
587
+ onTeachWorking?: () => void;
588
+ }
589
+
590
+ // ----------------------------------------------------------------------------
591
+ // Teach mode (guided-tour tooltips with Next-button action execution)
592
+ // ----------------------------------------------------------------------------
593
+
594
+ /**
595
+ * Payload the host pushes to the teach overlay BrowserWindow. Built by
596
+ * `handleTeachStep` in toolCalls.ts from the model's `teach_step` args.
597
+ *
598
+ * `anchorLogical` here is POST-`scaleCoord` — **full-display** logical
599
+ * macOS points (origin = monitor top-left, menu bar included, since
600
+ * cuDisplayInfo returns CGDisplayBounds). The overlay window is positioned
601
+ * at `workArea.{x,y}` (excludes menu bar/Dock), so `updateTeachStep` in
602
+ * teach/window.ts subtracts the workArea offset before IPC so the HTML's
603
+ * CSS coords match.
604
+ */
605
+ export interface TeachStepRequest {
606
+ explanation: string;
607
+ nextPreview: string;
608
+ /** Full-display logical points. Undefined → overlay centers the tooltip, hides the arrow. */
609
+ anchorLogical?: { x: number; y: number };
610
+ }
611
+
612
+ export type TeachStepResult = { action: "next" } | { action: "exit" };
613
+
614
+ /**
615
+ * Payload for the renderer's ComputerUseTeachApproval dialog. Rides through
616
+ * `ToolPermissionRequest.input: unknown` same as `CuPermissionRequest`.
617
+ * Separate type (not a flag on `CuPermissionRequest`) so the two approval
618
+ * components can narrow independently and the teach dialog is free to drop
619
+ * fields it doesn't render (no grant-flag checkboxes in teach mode).
620
+ */
621
+ export interface CuTeachPermissionRequest {
622
+ requestId: string;
623
+ /** Model-provided reason. Shown in the dialog headline ("guide you through {reason}"). */
624
+ reason: string;
625
+ apps: ResolvedAppRequest[];
626
+ screenshotFiltering: "native" | "none";
627
+ /** Present only when TCC is ungranted — same semantics as `CuPermissionRequest.tccState`. */
628
+ tccState?: {
629
+ accessibility: boolean;
630
+ screenRecording: boolean;
631
+ };
632
+ willHide?: Array<{ bundleId: string; displayName: string }>;
633
+ /** Same semantics as `CuPermissionRequest.autoUnhideEnabled`. */
634
+ autoUnhideEnabled?: boolean;
635
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@ant/computer-use-swift",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./src/index.js"
8
+ }
9
+ }