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,171 @@
1
+ /**
2
+ * Staleness guard ported from the Vercept acquisition.
3
+ *
4
+ * Compares the model's last-seen screenshot against a fresh-right-now
5
+ * screenshot at the click target, so the model never clicks pixels it hasn't
6
+ * seen. If the 9×9 patch around the target differs, the click is aborted and
7
+ * the model is told to re-screenshot. This is NOT a popup detector.
8
+ *
9
+ * Semantics preserved exactly:
10
+ * - Skip on no `lastScreenshot` (cold start) — click proceeds.
11
+ * - Skip on any internal error (crop throws, screenshot fails, etc.) —
12
+ * click proceeds. Validation failure must never block the action.
13
+ * - 9×9 exact byte equality on raw pixel bytes. No fuzzing, no tolerance.
14
+ * - Compare in percentage coords so Retina scale doesn't matter.
15
+ *
16
+ * JPEG decode + crop is INJECTED via `ComputerUseHostAdapter.cropRawPatch`.
17
+ * The original used `sharp` (LGPL, native `.node` addon); we inject Electron's
18
+ * `nativeImage` (Chromium decoders, BSD, nothing to bundle) from the host, so
19
+ * this package never imports it — the crop is a function parameter.
20
+ */
21
+
22
+ import type { ScreenshotResult } from "./executor.js";
23
+ import type { Logger } from "./types.js";
24
+
25
+ /** Injected by the host. See `ComputerUseHostAdapter.cropRawPatch`. */
26
+ export type CropRawPatchFn = (
27
+ jpegBase64: string,
28
+ rect: { x: number; y: number; width: number; height: number },
29
+ ) => Buffer | null;
30
+
31
+ /** 9×9 is empirically the sweet spot — large enough to catch a tooltip
32
+ * appearing, small enough to not false-positive on surrounding animation.
33
+ **/
34
+ const DEFAULT_GRID_SIZE = 9;
35
+
36
+ export interface PixelCompareResult {
37
+ /** true → click may proceed. false → patch changed, abort the click. */
38
+ valid: boolean;
39
+ /** true → validation did not run (cold start, sub-gate off, or internal
40
+ * error). The caller MUST treat this identically to `valid: true`. */
41
+ skipped: boolean;
42
+ /** Populated when valid === false. Returned to the model verbatim. */
43
+ warning?: string;
44
+ }
45
+
46
+ /**
47
+ * Compute the crop rect for a patch centered on (xPercent, yPercent).
48
+ *
49
+ * Dimensions come from ScreenshotResult.width/height (physical pixels). Both
50
+ * screenshots have the same dimensions (same display, consecutive captures),
51
+ * so the rect is the same for both.
52
+ */
53
+ function computeCropRect(
54
+ imgW: number,
55
+ imgH: number,
56
+ xPercent: number,
57
+ yPercent: number,
58
+ gridSize: number,
59
+ ): { x: number; y: number; width: number; height: number } | null {
60
+ if (!imgW || !imgH) return null;
61
+
62
+ const clampedX = Math.max(0, Math.min(100, xPercent));
63
+ const clampedY = Math.max(0, Math.min(100, yPercent));
64
+
65
+ const centerX = Math.round((clampedX / 100.0) * imgW);
66
+ const centerY = Math.round((clampedY / 100.0) * imgH);
67
+
68
+ const halfGrid = Math.floor(gridSize / 2);
69
+ const cropX = Math.max(0, centerX - halfGrid);
70
+ const cropY = Math.max(0, centerY - halfGrid);
71
+ const cropW = Math.min(gridSize, imgW - cropX);
72
+ const cropH = Math.min(gridSize, imgH - cropY);
73
+ if (cropW <= 0 || cropH <= 0) return null;
74
+
75
+ return { x: cropX, y: cropY, width: cropW, height: cropH };
76
+ }
77
+
78
+ /**
79
+ * Compare the same patch location between two screenshots.
80
+ *
81
+ * @returns true when the raw pixel bytes are identical. false on any
82
+ * difference, or on any internal error (the caller treats an error here as
83
+ * `skipped`, so the false is harmless).
84
+ */
85
+ export function comparePixelAtLocation(
86
+ crop: CropRawPatchFn,
87
+ lastScreenshot: ScreenshotResult,
88
+ freshScreenshot: ScreenshotResult,
89
+ xPercent: number,
90
+ yPercent: number,
91
+ gridSize: number = DEFAULT_GRID_SIZE,
92
+ ): boolean {
93
+ // Both screenshots are of the same display — use the fresh one's
94
+ // dimensions (less likely to be stale than last's).
95
+ const rect = computeCropRect(
96
+ freshScreenshot.width,
97
+ freshScreenshot.height,
98
+ xPercent,
99
+ yPercent,
100
+ gridSize,
101
+ );
102
+ if (!rect) return false;
103
+
104
+ const patch1 = crop(lastScreenshot.base64, rect);
105
+ const patch2 = crop(freshScreenshot.base64, rect);
106
+ if (!patch1 || !patch2) return false;
107
+
108
+ // Direct buffer equality. Note: nativeImage.toBitmap() gives BGRA, sharp's
109
+ // .raw() gave RGB.
110
+ // Doesn't matter — we're comparing two same-format buffers for equality.
111
+ return patch1.equals(patch2);
112
+ }
113
+
114
+ /**
115
+ * Battle-tested click-target validation ported from the Vercept acquisition,
116
+ * with the fresh-screenshot capture delegated to the caller (we don't have
117
+ * a global `SystemActions.takeScreenshot()` — the executor is injected).
118
+ *
119
+ * Skip conditions (any of these → `{ valid: true, skipped: true }`):
120
+ * - `lastScreenshot` is undefined (cold start).
121
+ * - `takeFreshScreenshot()` throws or returns null.
122
+ * - Injected crop function returns null (decode failure).
123
+ * - Any other exception.
124
+ *
125
+ * The caller decides whether to invoke this at all (sub-gate check lives
126
+ * in toolCalls.ts, not here).
127
+ */
128
+ export async function validateClickTarget(
129
+ crop: CropRawPatchFn,
130
+ lastScreenshot: ScreenshotResult | undefined,
131
+ xPercent: number,
132
+ yPercent: number,
133
+ takeFreshScreenshot: () => Promise<ScreenshotResult | null>,
134
+ logger: Logger,
135
+ gridSize: number = DEFAULT_GRID_SIZE,
136
+ ): Promise<PixelCompareResult> {
137
+ if (!lastScreenshot) {
138
+ return { valid: true, skipped: true };
139
+ }
140
+
141
+ try {
142
+ const fresh = await takeFreshScreenshot();
143
+ if (!fresh) {
144
+ return { valid: true, skipped: true };
145
+ }
146
+
147
+ const pixelsMatch = comparePixelAtLocation(
148
+ crop,
149
+ lastScreenshot,
150
+ fresh,
151
+ xPercent,
152
+ yPercent,
153
+ gridSize,
154
+ );
155
+
156
+ if (pixelsMatch) {
157
+ return { valid: true, skipped: false };
158
+ }
159
+ return {
160
+ valid: false,
161
+ skipped: false,
162
+ warning:
163
+ "Screen content at the target location changed since the last screenshot. Take a new screenshot before clicking.",
164
+ };
165
+ } catch (err) {
166
+ // Skip validation on technical errors, execute action anyway.
167
+ // Battle-tested: validation failure must never block the click.
168
+ logger.debug("[pixelCompare] validation error, skipping", err);
169
+ return { valid: true, skipped: true };
170
+ }
171
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Bundle IDs that are escalations-in-disguise. The approval UI shows a warning
3
+ * badge for these; they are NOT blocked. Power users may legitimately want the
4
+ * model controlling a terminal.
5
+ *
6
+ * Imported by the renderer via the `./sentinelApps` subpath (package.json
7
+ * `exports`), which keeps Next.js from reaching index.ts → mcpServer.ts →
8
+ * @modelcontextprotocol/sdk (devDep, would fail module resolution). Keep
9
+ * this file import-free so the subpath stays clean.
10
+ */
11
+
12
+ /** These apps can execute arbitrary shell commands. */
13
+ const SHELL_ACCESS_BUNDLE_IDS = new Set([
14
+ "com.apple.Terminal",
15
+ "com.googlecode.iterm2",
16
+ "com.microsoft.VSCode",
17
+ "dev.warp.Warp-Stable",
18
+ "com.github.wez.wezterm",
19
+ "io.alacritty",
20
+ "net.kovidgoyal.kitty",
21
+ "com.jetbrains.intellij",
22
+ "com.jetbrains.pycharm",
23
+ ]);
24
+
25
+ /** Finder in the allowlist ≈ browse + open-any-file. */
26
+ const FILESYSTEM_ACCESS_BUNDLE_IDS = new Set(["com.apple.finder"]);
27
+
28
+ const SYSTEM_SETTINGS_BUNDLE_IDS = new Set(["com.apple.systempreferences"]);
29
+
30
+ export const SENTINEL_BUNDLE_IDS: ReadonlySet<string> = new Set([
31
+ ...SHELL_ACCESS_BUNDLE_IDS,
32
+ ...FILESYSTEM_ACCESS_BUNDLE_IDS,
33
+ ...SYSTEM_SETTINGS_BUNDLE_IDS,
34
+ ]);
35
+
36
+ export type SentinelCategory = "shell" | "filesystem" | "system_settings";
37
+
38
+ export function getSentinelCategory(bundleId: string): SentinelCategory | null {
39
+ if (SHELL_ACCESS_BUNDLE_IDS.has(bundleId)) return "shell";
40
+ if (FILESYSTEM_ACCESS_BUNDLE_IDS.has(bundleId)) return "filesystem";
41
+ if (SYSTEM_SETTINGS_BUNDLE_IDS.has(bundleId)) return "system_settings";
42
+ return null;
43
+ }
@@ -0,0 +1,19 @@
1
+ import type { CuSubGates } from './types.js'
2
+
3
+ export const ALL_SUB_GATES_ON: CuSubGates = {
4
+ pixelValidation: true,
5
+ clipboardPasteMultiline: true,
6
+ mouseAnimation: true,
7
+ hideBeforeAction: true,
8
+ autoTargetDisplay: true,
9
+ clipboardGuard: true,
10
+ }
11
+
12
+ export const ALL_SUB_GATES_OFF: CuSubGates = {
13
+ pixelValidation: false,
14
+ clipboardPasteMultiline: false,
15
+ mouseAnimation: false,
16
+ hideBeforeAction: false,
17
+ autoTargetDisplay: false,
18
+ clipboardGuard: false,
19
+ }