@cydm/pie 2.6.12 → 2.7.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 (35) hide show
  1. package/README.md +85 -3
  2. package/dist/builtin/extensions/ask-user/index.js +3 -3
  3. package/dist/builtin/extensions/plan-mode/index.js +130 -21
  4. package/dist/builtin/extensions/subagent/index.js +15 -6
  5. package/dist/builtin/extensions/todo/index.js +3 -3
  6. package/dist/builtin/skills/computer-use-axi/SKILL.md +172 -0
  7. package/dist/builtin/{extensions/computer-use/index.js → skills/computer-use-axi/computer-use-axi-broker.js} +2122 -708
  8. package/dist/builtin/skills/computer-use-axi/computer-use-axi-cli.js +37 -0
  9. package/dist/builtin/skills/computer-use-axi/computer-use-axi-runtime.js +728 -0
  10. package/dist/builtin/skills/computer-use-axi/package.json +11 -0
  11. package/dist/chunks/{chunk-PPEWRUMQ.js → chunk-M44CWVDZ.js} +1249 -752
  12. package/dist/chunks/{chunk-HHNOENEH.js → chunk-NJFPBU36.js} +14 -1
  13. package/dist/chunks/{chunk-AAEBH6KX.js → chunk-W74NRSRV.js} +239 -231
  14. package/dist/chunks/{chunk-7B4IIBVS.js → chunk-XUROMYTT.js} +1747 -14
  15. package/dist/chunks/{src-OWQI5M6W.js → src-C4KA4G75.js} +2 -2
  16. package/dist/chunks/{test-stream-Y7WXELAJ.js → test-stream-A5ZELKNG.js} +1 -1
  17. package/dist/cli.js +863 -305
  18. package/models.schema.json +57 -0
  19. package/package.json +3 -3
  20. package/dist/builtin/extensions/computer-use/package.json +0 -14
  21. package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +0 -278
  22. package/dist/builtin/extensions/computer-use/scripts/test-native-retention.mjs +0 -204
  23. package/dist/chunks/chunk-5353DEEC.js +0 -130
  24. package/dist/chunks/webapi-MBCKO7ZV.js +0 -2481
  25. package/dist/code-intel-worker.cjs +0 -211227
  26. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/arm64/linux-bridge +0 -0
  27. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/x64/linux-bridge +0 -0
  28. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/arm64/pie-computer-use +0 -0
  29. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/Info.plist +0 -0
  30. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
  31. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/_CodeSignature/CodeResources +0 -0
  32. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/x64/pie-computer-use +0 -0
  33. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/windows/windows-bridge.exe +0 -0
  34. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/helper-path.mjs +0 -0
  35. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/setup-helper.mjs +0 -0
@@ -140,6 +140,11 @@
140
140
  "cacheWrite": {
141
141
  "type": "number",
142
142
  "minimum": 0
143
+ },
144
+ "cacheWriteLong": {
145
+ "type": "number",
146
+ "minimum": 0,
147
+ "description": "1h-TTL cache-write rate (per million tokens). Optional: omit for legacy configs; long writes are then estimated at 2x input unless the provider bills differently."
143
148
  }
144
149
  },
145
150
  "required": [
@@ -285,6 +290,15 @@
285
290
  "type": "object",
286
291
  "additionalProperties": false,
287
292
  "properties": {
293
+ "store": {
294
+ "type": "boolean"
295
+ },
296
+ "supportsEncryptedReasoning": {
297
+ "type": "boolean"
298
+ },
299
+ "responsesContinuation": {
300
+ "type": "boolean"
301
+ },
288
302
  "supportsStore": {
289
303
  "type": "boolean"
290
304
  },
@@ -347,10 +361,18 @@
347
361
  "pattern": "^[^\\u0000-\\u0008\\u000A-\\u001F\\u007F]*$"
348
362
  }
349
363
  },
364
+ "api": {
365
+ "type": "string",
366
+ "enum": ["openai-completions", "openai-responses", "anthropic-messages"]
367
+ },
350
368
  "model": {
351
369
  "type": "object",
352
370
  "additionalProperties": false,
353
371
  "properties": {
372
+ "api": {
373
+ "$ref": "#/$defs/api",
374
+ "description": "Optional API selector; inherits profile api. A different API requires profile endpoints[api]."
375
+ },
354
376
  "id": {
355
377
  "type": "string",
356
378
  "minLength": 1,
@@ -420,6 +442,14 @@
420
442
  "attachmentPlatform": {
421
443
  "type": "string",
422
444
  "minLength": 1
445
+ },
446
+ "transport": {
447
+ "type": "string",
448
+ "enum": [
449
+ "sse",
450
+ "websocket",
451
+ "auto"
452
+ ]
423
453
  }
424
454
  },
425
455
  "required": [
@@ -434,6 +464,16 @@
434
464
  "type": "object",
435
465
  "additionalProperties": false,
436
466
  "properties": {
467
+ "endpoints": {
468
+ "type": "object",
469
+ "description": "Optional API-specific roots; keys must be supported APIs. Routing relationships are validated by the runtime.",
470
+ "propertyNames": { "$ref": "#/$defs/api" },
471
+ "additionalProperties": {
472
+ "type": "string",
473
+ "format": "uri",
474
+ "pattern": "^https?://"
475
+ }
476
+ },
437
477
  "baseUrl": {
438
478
  "type": "string",
439
479
  "format": "uri",
@@ -443,6 +483,7 @@
443
483
  "type": "string",
444
484
  "enum": [
445
485
  "openai-completions",
486
+ "openai-responses",
446
487
  "anthropic-messages"
447
488
  ]
448
489
  },
@@ -487,6 +528,14 @@
487
528
  "items": {
488
529
  "$ref": "#/$defs/model"
489
530
  }
531
+ },
532
+ "transport": {
533
+ "type": "string",
534
+ "enum": [
535
+ "sse",
536
+ "websocket",
537
+ "auto"
538
+ ]
490
539
  }
491
540
  },
492
541
  "required": [
@@ -576,6 +625,14 @@
576
625
  "displayName": {
577
626
  "type": "string",
578
627
  "minLength": 1
628
+ },
629
+ "transport": {
630
+ "type": "string",
631
+ "enum": [
632
+ "sse",
633
+ "websocket",
634
+ "auto"
635
+ ]
579
636
  }
580
637
  }
581
638
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cydm/pie",
3
- "version": "2.6.12",
3
+ "version": "2.7.1",
4
4
  "description": "Pie AI Agent CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,9 +17,9 @@
17
17
  "validate:models": "tsx scripts/validate-models-config.ts",
18
18
  "test": "npm run test:offline",
19
19
  "pretest:offline": "npm run build --workspace @pie/agent-framework && npm run build --workspace @pie/shared-headless-capabilities && npm run build && npm run test:skill-regressions",
20
- "test:skill-regressions": "node --test --import tsx test/bash-lifecycle.test.ts test/skill-creator-runner.test.ts test/tui-use-contract.test.ts test/tui-use-runtime.test.ts test/browser-runtime.test.ts test/axi-stop-semantics.test.ts test/computer-evidence.test.ts test/interactive-lifecycle.test.ts",
20
+ "test:skill-regressions": "node --test --import tsx test/bash-lifecycle.test.ts test/skill-creator-runner.test.ts test/tui-use-contract.test.ts test/tui-use-runtime.test.ts test/browser-runtime.test.ts test/axi-stop-semantics.test.ts test/computer-use-axi.test.ts test/computer-evidence.test.ts test/interactive-lifecycle.test.ts",
21
21
  "posttest:offline": "node --test --import tsx test/remote-model-catalog.test.ts",
22
- "test:offline": "node --test --test-concurrency=4 --import tsx test/cli-attention.test.ts test/builtin-extensions.test.ts test/core-services.test.ts test/cli.test.ts test/cli-auto-compaction.test.ts test/execution-state-manager.test.ts test/queued-steer-execution-state.test.ts test/architecture-boundaries.test.ts test/attachment-resolver.test.ts test/kimi-attachment-provider.test.ts test/document-attachment-extension.test.ts test/auto-compact-overflow.test.ts test/auto-compaction-ui.test.ts test/hierarchical-command-system.test.ts test/mcp-adapter.test.ts test/herdr-agent-state.test.ts test/extensions-enablement.test.ts test/extension-selector-shortcuts.test.ts test/skill-tool-enablement.test.ts test/message-queue-unit.test.ts test/evals-harness.test.ts test/session-trace.test.ts test/subagent-session-store.test.ts test/runtime-mode-context.test.ts test/tool-policy.test.ts test/retry-policy.test.ts test/yolo-command.test.ts test/footer-lifecycle.test.ts test/files-utils.test.ts test/source-size-guard.test.ts test/runtime-logger.test.ts test/release-readiness.test.ts test/package-artifacts.test.ts test/code-intel-typescript-provider.test.ts test/init-extension-contract.test.ts test/skills-runtime.test.ts test/skills-agents-discovery.test.ts test/skills-symlink.test.ts test/model-overrides.test.ts test/auth-storage.test.ts test/extension-register-provider.test.ts test/extension-reload.test.ts test/extension-terminal-input.test.ts test/extension-session-before-events.test.ts test/extension-widgets.test.ts test/extension-render-hint.test.ts test/extension-oauth-restore.test.ts test/cross-host-parity.test.ts test/tool-name-rendering.test.ts test/session-selector.test.ts test/tree-selector-pagination.test.ts test/context-report.test.ts test/context-signals.test.ts test/trace-report.test.ts test/boot-report.test.ts test/compaction-diff.test.ts test/entry-body-and-usage.test.ts test/session-control.test.ts test/terminal-title.test.ts test/interactive-controller-title.test.ts test/todo-title.terminal.test.ts test/plan-mode-extension.test.ts test/rendered-page-reader.test.ts test/tools-registry.test.ts test/system-prompt-contract.test.ts test/bash-yolo.test.ts test/bash-confirm-pending.test.ts test/interaction-status-lifecycle.test.ts test/bash-process-group.test.ts test/bash-artifact-sink.test.ts test/direct-bash.test.ts test/terminal-bell.test.ts test/ctrl-d-exit.test.ts test/session-display-title.test.ts test/calm-mode.test.ts test/stream-render-throttle.test.ts test/message-display-resync.test.ts test/project-root.test.ts test/guard-advisory-context.test.ts test/clear-command-usage.test.ts test/daily-agent-smoke.terminal.test.ts test/slash-menu-toggles.terminal.test.ts test/cli-args.test.ts test/extensions-configured-paths.test.ts test/extensions-loader-path.test.ts test/file-picker.test.ts test/interrupt-recovery.test.ts test/mention-insert-regression.test.ts test/mention-picker-navigation.test.ts test/pie-unity-rpc-skill.test.ts test/skill-creator-scripts.test.ts",
22
+ "test:offline": "node --test --test-concurrency=4 --import tsx test/cli-attention.test.ts test/builtin-extensions.test.ts test/core-services.test.ts test/cli.test.ts test/cli-auto-compaction.test.ts test/execution-state-manager.test.ts test/queued-steer-execution-state.test.ts test/architecture-boundaries.test.ts test/attachment-resolver.test.ts test/kimi-attachment-provider.test.ts test/document-attachment-extension.test.ts test/auto-compact-overflow.test.ts test/auto-compaction-ui.test.ts test/hierarchical-command-system.test.ts test/mcp-adapter.test.ts test/herdr-agent-state.test.ts test/extensions-enablement.test.ts test/extension-selector-shortcuts.test.ts test/skill-tool-enablement.test.ts test/message-queue-unit.test.ts test/evals-harness.test.ts test/session-trace.test.ts test/json-events-sidechat-diagnostics.test.ts test/subagent-session-store.test.ts test/runtime-mode-context.test.ts test/tool-policy.test.ts test/retry-policy.test.ts test/yolo-command.test.ts test/footer-lifecycle.test.ts test/files-utils.test.ts test/source-size-guard.test.ts test/runtime-logger.test.ts test/release-readiness.test.ts test/package-artifacts.test.ts test/init-extension-contract.test.ts test/skills-runtime.test.ts test/skills-agents-discovery.test.ts test/skills-symlink.test.ts test/model-overrides.test.ts test/auth-storage.test.ts test/extension-register-provider.test.ts test/extension-reload.test.ts test/extension-terminal-input.test.ts test/extension-session-before-events.test.ts test/extension-widgets.test.ts test/extension-render-hint.test.ts test/extension-oauth-restore.test.ts test/cross-host-parity.test.ts test/tool-name-rendering.test.ts test/session-selector.test.ts test/tree-selector-pagination.test.ts test/context-report.test.ts test/context-signals.test.ts test/plan-cache-stability.test.ts test/cache-invalidation-trace.test.ts test/cache-retention.test.ts test/trace-report.test.ts test/boot-report.test.ts test/compaction-diff.test.ts test/entry-body-and-usage.test.ts test/session-control.test.ts test/terminal-title.test.ts test/interactive-controller-title.test.ts test/todo-title.terminal.test.ts test/plan-mode-extension.test.ts test/rendered-page-reader.test.ts test/tools-registry.test.ts test/system-prompt-contract.test.ts test/bash-yolo.test.ts test/bash-confirm-pending.test.ts test/interaction-status-lifecycle.test.ts test/bash-process-group.test.ts test/bash-artifact-sink.test.ts test/direct-bash.test.ts test/terminal-bell.test.ts test/ctrl-d-exit.test.ts test/session-display-title.test.ts test/calm-mode.test.ts test/stream-render-throttle.test.ts test/message-display-resync.test.ts test/project-root.test.ts test/guard-advisory-context.test.ts test/clear-command-usage.test.ts test/daily-agent-smoke.terminal.test.ts test/slash-menu-toggles.terminal.test.ts test/cli-args.test.ts test/extensions-configured-paths.test.ts test/extensions-loader-path.test.ts test/file-picker.test.ts test/interrupt-recovery.test.ts test/mention-insert-regression.test.ts test/mention-picker-navigation.test.ts test/pie-unity-rpc-skill.test.ts test/skill-creator-scripts.test.ts test/interactive-compact-command.test.ts test/computer-use-broker.test.ts",
23
23
  "test:all": "npm run test:offline && npm run test:terminal:vitest",
24
24
  "test:terminal:vitest": "vitest run test/mention-file-select.terminal.test.ts test/tool-partial-display.terminal.test.ts test/footer-plan-mode.test.ts test/viewport-position-final.test.ts test/resume-header.terminal.test.ts --no-file-parallelism",
25
25
  "test:todo-tui": "node ../../scripts/run-with-env.mjs PIE_REAL_TODO_TUI=1 -- --test --import tsx test/todo-closure.terminal.test.ts",
@@ -1,14 +0,0 @@
1
- {
2
- "name": "@pie/extension-computer-use",
3
- "version": "0.5.1",
4
- "description": "Desktop computer-use tools (observe/act) vendored from @injaneity/pi-computer-use",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "test:native-retention": "node scripts/test-native-retention.mjs"
9
- },
10
- "pie": {
11
- "name": "computer-use",
12
- "main": "index.js"
13
- }
14
- }
@@ -1,278 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { spawn } from "node:child_process";
4
- import fs from "node:fs/promises";
5
- import os from "node:os";
6
- import path from "node:path";
7
- import { fileURLToPath } from "node:url";
8
-
9
- const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
10
- const macosSourcePaths = [
11
- "agent_cursor.swift",
12
- "agent_cursor_motion.swift",
13
- "bridge.swift",
14
- "ref_store.swift",
15
- ].map((file) => path.join(rootDir, "native", "macos", file));
16
- const windowsCrateDir = path.join(rootDir, "native", "windows", "bridge-rs");
17
- const linuxCrateDir = path.join(rootDir, "native", "linux", "bridge-rs");
18
- const linuxTargets = { x64: "x86_64-unknown-linux-gnu", arm64: "aarch64-unknown-linux-gnu" };
19
- const archTriples = {
20
- arm64: "arm64-apple-macosx",
21
- x64: "x86_64-apple-macosx",
22
- };
23
- const deploymentTarget = "14.0";
24
- const frameworks = ["ApplicationServices", "AppKit", "ScreenCaptureKit", "Foundation", "SwiftUI", "CryptoKit"];
25
- const defaultCodeSignIdentifier = "com.pie.computer-use";
26
-
27
- async function exists(filePath) {
28
- try {
29
- await fs.access(filePath);
30
- return true;
31
- } catch {
32
- return false;
33
- }
34
- }
35
-
36
- function getArg(name) {
37
- const index = process.argv.indexOf(name);
38
- if (index >= 0 && index + 1 < process.argv.length) {
39
- return process.argv[index + 1];
40
- }
41
- return undefined;
42
- }
43
-
44
- function hasArg(name) {
45
- return process.argv.includes(name);
46
- }
47
-
48
- function normalizeArch(arch) {
49
- if (arch === "universal" || arch === "all") return arch;
50
- if (arch === "arm64" || arch === "x64") return arch;
51
- throw new Error(`Unsupported architecture '${arch}'. Supported: arm64, x64, universal, all.`);
52
- }
53
-
54
- async function run(command, args) {
55
- await new Promise((resolve, reject) => {
56
- const child = spawn(command, args, { stdio: "inherit" });
57
- child.on("error", reject);
58
- child.on("close", (code) => {
59
- if (code === 0) {
60
- resolve();
61
- return;
62
- }
63
- reject(new Error(`Command failed (${code}): ${command} ${args.join(" ")}`));
64
- });
65
- });
66
- }
67
-
68
- function defaultOutputPath(arch) {
69
- return path.join(rootDir, "prebuilt", "macos", arch, "pie-computer-use");
70
- }
71
-
72
- function moduleCachePath(arch) {
73
- return path.join(os.tmpdir(), `pie-computer-use-swift-module-cache-${arch}`);
74
- }
75
-
76
- function swiftArgsForArch(arch, outputPath) {
77
- const args = [
78
- "swiftc",
79
- "-target",
80
- `${archTriples[arch]}${deploymentTarget}`,
81
- "-module-cache-path",
82
- moduleCachePath(arch),
83
- "-O",
84
- ];
85
- for (const framework of frameworks) args.push("-framework", framework);
86
- args.push(...macosSourcePaths, "-o", outputPath);
87
- return args;
88
- }
89
-
90
- async function signBinary(outputPath) {
91
- if (hasArg("--no-sign") || process.env.PIE_COMPUTER_USE_NO_SIGN === "1") {
92
- return;
93
- }
94
-
95
- const identity = getArg("--sign-identity") ?? process.env.PIE_COMPUTER_USE_CODESIGN_IDENTITY ?? "-";
96
- const identifier = getArg("--sign-identifier") ?? process.env.PIE_COMPUTER_USE_CODESIGN_IDENTIFIER ?? defaultCodeSignIdentifier;
97
- const args = ["--force", "-i", identifier];
98
- if (hasArg("--hardened-runtime")) {
99
- args.push("--options", "runtime");
100
- }
101
- if (hasArg("--timestamp")) {
102
- args.push("--timestamp");
103
- } else {
104
- args.push("--timestamp=none");
105
- }
106
- args.push("--sign", identity, outputPath);
107
- await run("codesign", args);
108
- }
109
-
110
- async function buildForArch(arch, outputPath) {
111
- await fs.mkdir(path.dirname(outputPath), { recursive: true });
112
- console.log(`Building native helper for ${arch}...`);
113
- await run("xcrun", swiftArgsForArch(arch, outputPath));
114
- await fs.chmod(outputPath, 0o755);
115
- await signBinary(outputPath);
116
- console.log(`Built helper at ${outputPath}`);
117
- }
118
-
119
- async function buildUniversal(outputPath) {
120
- const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "pie-computer-use-build-"));
121
- const x64Output = path.join(tempDir, "pie-computer-use-x64");
122
- const arm64Output = path.join(tempDir, "pie-computer-use-arm64");
123
- await buildForArch("x64", x64Output);
124
- await buildForArch("arm64", arm64Output);
125
- await fs.mkdir(path.dirname(outputPath), { recursive: true });
126
- await run("lipo", ["-create", "-output", outputPath, x64Output, arm64Output]);
127
- await fs.chmod(outputPath, 0o755);
128
- await signBinary(outputPath);
129
- console.log(`Built universal helper at ${outputPath}`);
130
- await fs.rm(tempDir, { recursive: true, force: true });
131
- }
132
-
133
- /**
134
- * Return the actual cargo binary path, handling platform suffix differences.
135
- * On Windows, the binary is named "windows-bridge.exe"; on other platforms it's "windows-bridge".
136
- */
137
- function windowsBinaryPath(crateDir, target) {
138
- const releaseDir = target
139
- ? path.join(crateDir, "target", target, "release")
140
- : path.join(crateDir, "target", "release");
141
- return path.join(releaseDir, "windows-bridge.exe");
142
- }
143
-
144
- async function buildWindowsHelper(prebuiltOutput) {
145
- const target = getArg("--target");
146
- if (process.platform !== "win32" && !target?.includes("windows")) {
147
- throw new Error("Refusing to label a host binary as Windows. Build on Windows or pass an explicit Windows --target triple.");
148
- }
149
- const prebuiltDir = prebuiltOutput
150
- ? path.resolve(process.cwd(), prebuiltOutput, "..")
151
- : path.join(rootDir, "prebuilt", "windows");
152
- const manifestPath = path.join(windowsCrateDir, "Cargo.toml");
153
-
154
- console.log("Building Windows helper with cargo...");
155
- const cargoArgs = [
156
- "build",
157
- "--release",
158
- "--manifest-path",
159
- manifestPath,
160
- ];
161
- if (target) cargoArgs.push("--target", target);
162
- await run("cargo", cargoArgs);
163
-
164
- await fs.mkdir(prebuiltDir, { recursive: true });
165
-
166
- const cargoOutput = windowsBinaryPath(windowsCrateDir, target);
167
- const handle = await fs.open(cargoOutput, "r");
168
- try {
169
- const signature = Buffer.alloc(2);
170
- await handle.read(signature, 0, 2, 0);
171
- if (signature.toString("ascii") !== "MZ") {
172
- throw new Error(`Cargo output is not a Windows PE executable: ${cargoOutput}`);
173
- }
174
- } finally {
175
- await handle.close();
176
- }
177
- const prebuiltDest = path.join(prebuiltDir, "windows-bridge.exe");
178
- await fs.copyFile(cargoOutput, prebuiltDest);
179
- await fs.chmod(prebuiltDest, 0o755);
180
- console.log(`Built Windows helper at ${prebuiltDest}`);
181
- }
182
-
183
- function linuxBinaryPath(crateDir, target) {
184
- const targetDir = target ? path.join("target", target) : "target";
185
- return path.join(crateDir, targetDir, "release", "linux-bridge");
186
- }
187
-
188
- function defaultLinuxOutputPath(arch) {
189
- return path.join(rootDir, "prebuilt", "linux", arch, "linux-bridge");
190
- }
191
-
192
- async function buildLinuxForArch(arch, outputPath) {
193
- const explicitTarget = getArg("--target");
194
- if (explicitTarget && !explicitTarget.includes("linux")) throw new Error(`Linux builds require a Linux --target triple, got ${explicitTarget}.`);
195
- const target = explicitTarget ?? (process.platform === "linux" && process.arch === arch ? undefined : linuxTargets[arch]);
196
- console.log(`Building Linux helper for ${arch} with cargo...`);
197
- const cargoArgs = ["build", "--release", "--manifest-path", path.join(linuxCrateDir, "Cargo.toml")];
198
- if (target) cargoArgs.push("--target", target);
199
- await run("cargo", cargoArgs);
200
- const cargoOutput = linuxBinaryPath(linuxCrateDir, target);
201
- const header = await fs.readFile(cargoOutput).then((data) => data.subarray(0, 20));
202
- if (header.length < 20 || !header.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46]))) throw new Error(`Cargo output is not a Linux ELF executable: ${cargoOutput}`);
203
- const machine = header.readUInt16LE(18);
204
- const expectedMachine = arch === "x64" ? 0x3e : 0xb7;
205
- if (machine !== expectedMachine) throw new Error(`Cargo output architecture does not match ${arch}: ${cargoOutput}`);
206
- await fs.mkdir(path.dirname(outputPath), { recursive: true });
207
- await fs.copyFile(cargoOutput, outputPath);
208
- await fs.chmod(outputPath, 0o755);
209
- console.log(`Built Linux helper at ${outputPath}`);
210
- }
211
-
212
- async function buildLinuxHelper() {
213
- const arch = normalizeArch(getArg("--arch") ?? process.arch);
214
- if (arch === "universal") throw new Error("Linux does not support --arch universal. Use x64, arm64, or all.");
215
- const outputArg = getArg("--output");
216
- if (arch === "all") {
217
- if (outputArg) throw new Error("--output is not supported with --arch all. Use a single architecture for one output.");
218
- for (const nextArch of ["x64", "arm64"]) await buildLinuxForArch(nextArch, defaultLinuxOutputPath(nextArch));
219
- return;
220
- }
221
- await buildLinuxForArch(arch, outputArg ? path.resolve(process.cwd(), outputArg) : defaultLinuxOutputPath(arch));
222
- }
223
-
224
- async function main() {
225
- const explicitPlatform = getArg("--platform");
226
-
227
- if (explicitPlatform === "windows") {
228
- await buildWindowsHelper(getArg("--output"));
229
- return;
230
- }
231
-
232
- if (explicitPlatform === "linux") {
233
- await buildLinuxHelper();
234
- return;
235
- }
236
-
237
- if (explicitPlatform === "darwin") {
238
- // Fall through to macOS build logic below.
239
- } else if (process.platform === "win32") {
240
- await buildWindowsHelper(getArg("--output"));
241
- return;
242
- } else if (process.platform === "linux") {
243
- await buildLinuxHelper();
244
- return;
245
- } else if (process.platform !== "darwin") {
246
- console.log(
247
- `Skipping native build: unsupported platform "${process.platform}". ` +
248
- "Use --platform windows or --platform linux to build a helper, or run on macOS for the macOS helper.",
249
- );
250
- return;
251
- }
252
-
253
- const arch = normalizeArch(getArg("--arch") ?? process.arch);
254
- const outputArg = getArg("--output");
255
-
256
- if (arch === "all") {
257
- if (outputArg) {
258
- throw new Error("--output is not supported with --arch all. Use a single architecture for one output.");
259
- }
260
- for (const nextArch of ["x64", "arm64"]) {
261
- await buildForArch(nextArch, defaultOutputPath(nextArch));
262
- }
263
- return;
264
- }
265
-
266
- const outputPath = outputArg ? path.resolve(process.cwd(), outputArg) : defaultOutputPath(arch);
267
- if (arch === "universal") {
268
- await buildUniversal(outputPath);
269
- return;
270
- }
271
-
272
- await buildForArch(arch, outputPath);
273
- }
274
-
275
- main().catch((error) => {
276
- console.error(error instanceof Error ? error.message : String(error));
277
- process.exit(1);
278
- });
@@ -1,204 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // Compiles and runs the macOS native AXRefStore retention tests
4
- // (native/macos/retention_tests.swift) from source, then compiles the full
5
- // helper and drives its stdin JSON-lines transport with permission-free
6
- // requests to assert the bridge-level stale-ref/stale-look integration.
7
- //
8
- // Nothing here needs Accessibility or Screen Recording permission or real UI
9
- // interaction: the store tests use synthetic AXUIElement values, and the
10
- // helper protocol probes only exercise failure paths (unknown look/element
11
- // ids, missing windows). This script is macOS-only by design; on other
12
- // platforms it skips with an explicit message (Linux/Windows helpers have
13
- // their own native suites).
14
-
15
- import { spawn } from "node:child_process";
16
- import fs from "node:fs/promises";
17
- import os from "node:os";
18
- import path from "node:path";
19
- import { fileURLToPath } from "node:url";
20
-
21
- const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
22
- const nativeDir = path.join(rootDir, "native", "macos");
23
- const storeTestSources = ["ref_store.swift", "retention_tests.swift"].map((file) => path.join(nativeDir, file));
24
- const helperSources = ["agent_cursor.swift", "agent_cursor_motion.swift", "bridge.swift", "ref_store.swift"].map((file) => path.join(nativeDir, file));
25
- const deploymentTarget = "14.0";
26
- const helperFrameworks = ["ApplicationServices", "AppKit", "ScreenCaptureKit", "Foundation", "SwiftUI", "CryptoKit"];
27
-
28
- function run(command, args, options = {}) {
29
- return new Promise((resolve, reject) => {
30
- const child = spawn(command, args, { stdio: "inherit", ...options });
31
- child.on("error", reject);
32
- child.on("close", (code) => {
33
- if (code === 0) {
34
- resolve();
35
- return;
36
- }
37
- reject(new Error(`Command failed (${code}): ${command} ${args.join(" ")}`));
38
- });
39
- });
40
- }
41
-
42
- function swiftcArgs(sources, output, moduleCache, frameworks) {
43
- const args = [
44
- "swiftc",
45
- "-target",
46
- `${process.arch === "arm64" ? "arm64" : "x86_64"}-apple-macosx${deploymentTarget}`,
47
- "-module-cache-path",
48
- moduleCache,
49
- "-O",
50
- ];
51
- for (const framework of frameworks) args.push("-framework", framework);
52
- args.push(...sources, "-o", output);
53
- return args;
54
- }
55
-
56
- /** Drives the helper over its stdin transport and resolves one response per request id. */
57
- function helperResponses(executable, requests, timeoutMs = 15_000) {
58
- return new Promise((resolve, reject) => {
59
- const child = spawn(executable, [], { stdio: ["pipe", "pipe", "ignore"] });
60
- const pending = new Map(requests.map((request) => [request.id, request]));
61
- const settled = new Map();
62
- const fail = (error) => {
63
- child.kill();
64
- reject(error);
65
- };
66
- const timer = setTimeout(() => fail(new Error(`Helper did not answer all requests within ${timeoutMs}ms`)), timeoutMs);
67
- let buffer = "";
68
- child.stdout.setEncoding("utf8");
69
- child.stdout.on("data", (chunk) => {
70
- buffer += chunk;
71
- let newline;
72
- while ((newline = buffer.indexOf("\n")) >= 0) {
73
- const line = buffer.slice(0, newline);
74
- buffer = buffer.slice(newline + 1);
75
- if (!line.trim()) continue;
76
- let response;
77
- try {
78
- response = JSON.parse(line);
79
- } catch {
80
- continue;
81
- }
82
- if (typeof response.id === "string" && pending.delete(response.id)) {
83
- settled.set(response.id, response);
84
- if (pending.size === 0) {
85
- clearTimeout(timer);
86
- child.stdin.end();
87
- child.on("close", () => resolve(settled));
88
- child.kill();
89
- }
90
- }
91
- }
92
- });
93
- child.on("error", fail);
94
- for (const request of requests) child.stdin.write(`${JSON.stringify(request)}\n`);
95
- });
96
- }
97
-
98
- /** Verifies the helper's true-exit path: shutdown answers, then the process exits zero on its own. */
99
- function helperShutdownExits(executable, timeoutMs = 8_000) {
100
- return new Promise((resolve, reject) => {
101
- const child = spawn(executable, [], { stdio: ["pipe", "pipe", "ignore"] });
102
- let buffer = "";
103
- let sawResponse = false;
104
- const fail = (error) => {
105
- child.kill();
106
- reject(error);
107
- };
108
- const timer = setTimeout(() => fail(new Error(`Helper did not shut down within ${timeoutMs}ms`)), timeoutMs);
109
- child.stdout.setEncoding("utf8");
110
- child.stdout.on("data", (chunk) => {
111
- buffer += chunk;
112
- let newline;
113
- while ((newline = buffer.indexOf("\n")) >= 0) {
114
- const line = buffer.slice(0, newline);
115
- buffer = buffer.slice(newline + 1);
116
- if (!line.trim()) continue;
117
- let response;
118
- try {
119
- response = JSON.parse(line);
120
- } catch {
121
- continue;
122
- }
123
- if (response.id === "shutdown" && response.ok === true && response.result?.shuttingDown === true) sawResponse = true;
124
- }
125
- });
126
- child.on("error", fail);
127
- child.on("close", (code, signal) => {
128
- clearTimeout(timer);
129
- if (!sawResponse) {
130
- reject(new Error("Helper did not acknowledge shutdown before exiting"));
131
- return;
132
- }
133
- if (code === 0) {
134
- resolve();
135
- return;
136
- }
137
- reject(new Error(`Helper exited with ${code ?? "null"}${signal ? ` (signal ${signal})` : ""} instead of 0`));
138
- });
139
- child.stdin.write(`${JSON.stringify({ id: "shutdown", cmd: "shutdown" })}\n`);
140
- });
141
- }
142
-
143
- function assert(condition, message) {
144
- if (!condition) throw new Error(`[pie-computer-use] bridge integration assertion failed: ${message}`);
145
- }
146
-
147
- async function runBridgeIntegration(helperPath) {
148
- const responses = await helperResponses(helperPath, [
149
- { id: "diag", cmd: "diagnostics" },
150
- { id: "act-stale", cmd: "act", lookId: "look_999", pid: 123, action: "press", target: { ref: "e1" } },
151
- { id: "batch-stale", cmd: "actBatch", actions: [{ lookId: "look_999", pid: 123, action: "press", target: { ref: "e1" } }] },
152
- { id: "hit-stale", cmd: "hitTest", lookId: "look_999", x: 10, y: 10 },
153
- { id: "read-stale", cmd: "axReadText", elementRef: "e999999" },
154
- { id: "look-stale-base", cmd: "look", baseLookId: "look_999", windowId: 12345 },
155
- ]);
156
- const diagnostics = responses.get("diag");
157
- assert(diagnostics?.ok === true, "diagnostics must succeed");
158
- assert(diagnostics.result?.protocolVersion === 6, "helper must keep protocol version 6");
159
- assert(Array.isArray(diagnostics.result?.invariants) && diagnostics.result.invariants.includes("bounded-observation-history"), "helper must report the bounded-observation-history invariant");
160
- for (const [id, expectedCode] of [
161
- ["act-stale", "stale_look"],
162
- ["batch-stale", "stale_look"],
163
- ["hit-stale", "stale_look"],
164
- ["read-stale", "element_ref_invalid"],
165
- ["look-stale-base", "stale_look"],
166
- ]) {
167
- const response = responses.get(id);
168
- assert(response?.ok === false, `${id} must fail`);
169
- assert(response.error?.code === expectedCode, `${id} must fail with ${expectedCode}, got ${response.error?.code}`);
170
- }
171
- console.log("[pie-computer-use] bridge integration probes passed (stale look/ref failures, protocol v6).");
172
- }
173
-
174
- async function main() {
175
- if (process.platform !== "darwin") {
176
- console.log(`[pie-computer-use] skipping native retention tests: they are macOS-only and cannot run on ${process.platform}.`);
177
- return;
178
- }
179
- let tempDir;
180
- try {
181
- tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "pie-computer-use-retention-"));
182
- const moduleCache = path.join(tempDir, "module-cache");
183
- const storeTestOutput = path.join(tempDir, "retention_tests");
184
- console.log("[pie-computer-use] compiling native retention tests...");
185
- await run("xcrun", swiftcArgs(storeTestSources, storeTestOutput, moduleCache, ["ApplicationServices", "CryptoKit"]));
186
- console.log("[pie-computer-use] running native retention tests...");
187
- await run(storeTestOutput, []);
188
-
189
- const helperOutput = path.join(tempDir, "pie-computer-use");
190
- console.log("[pie-computer-use] compiling native helper for bridge integration probes...");
191
- await run("xcrun", swiftcArgs(helperSources, helperOutput, moduleCache, helperFrameworks));
192
- await runBridgeIntegration(helperOutput);
193
- await helperShutdownExits(helperOutput);
194
- console.log("[pie-computer-use] helper shutdown exits cleanly with code 0.");
195
- console.log("[pie-computer-use] native retention tests passed.");
196
- } finally {
197
- if (tempDir) await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {});
198
- }
199
- }
200
-
201
- main().catch((error) => {
202
- console.error(error instanceof Error ? error.message : String(error));
203
- process.exit(1);
204
- });