@cydm/pie 1.0.51 → 2.1.0

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 (50) hide show
  1. package/README.md +32 -15
  2. package/dist/builtin/extensions/ask-user/index.js +4 -3
  3. package/dist/builtin/extensions/ask-user/package.json +8 -7
  4. package/dist/builtin/extensions/changelog/package.json +9 -9
  5. package/dist/builtin/extensions/computer-use/index.js +5466 -0
  6. package/dist/builtin/extensions/computer-use/package.json +11 -0
  7. package/dist/builtin/extensions/computer-use/prebuilt/linux/arm64/linux-bridge +0 -0
  8. package/dist/builtin/extensions/computer-use/prebuilt/linux/x64/linux-bridge +0 -0
  9. package/dist/builtin/extensions/computer-use/prebuilt/macos/arm64/pie-computer-use +0 -0
  10. package/dist/builtin/extensions/computer-use/prebuilt/macos/universal/pie-computer-use.app/Contents/Info.plist +24 -0
  11. package/dist/builtin/extensions/computer-use/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
  12. package/dist/builtin/extensions/computer-use/prebuilt/macos/universal/pie-computer-use.app/Contents/_CodeSignature/CodeResources +115 -0
  13. package/dist/builtin/extensions/computer-use/prebuilt/macos/x64/pie-computer-use +0 -0
  14. package/dist/builtin/extensions/computer-use/prebuilt/windows/windows-bridge.exe +0 -0
  15. package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +277 -0
  16. package/dist/builtin/extensions/computer-use/scripts/helper-path.mjs +48 -0
  17. package/dist/builtin/extensions/computer-use/scripts/setup-helper.mjs +549 -0
  18. package/dist/builtin/extensions/document-attachments/package.json +9 -9
  19. package/dist/builtin/extensions/init/package.json +9 -9
  20. package/dist/builtin/extensions/mcp-adapter/index.js +25250 -0
  21. package/dist/builtin/extensions/mcp-adapter/package.json +11 -0
  22. package/dist/builtin/extensions/plan-mode/index.js +4 -3
  23. package/dist/builtin/extensions/plan-mode/package.json +9 -9
  24. package/dist/builtin/extensions/subagent/index.js +6 -4
  25. package/dist/builtin/extensions/subagent/package.json +16 -12
  26. package/dist/builtin/extensions/todo/index.js +4 -3
  27. package/dist/builtin/extensions/todo/package.json +9 -9
  28. package/dist/builtin/skills/chrome-devtools-axi/CHANGELOG.md +5 -0
  29. package/dist/builtin/skills/chrome-devtools-axi/README.md +17 -0
  30. package/dist/builtin/skills/chrome-devtools-axi/SKILL.md +31 -0
  31. package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-cli.js +77 -0
  32. package/dist/builtin/skills/chrome-devtools-axi/package.json +12 -0
  33. package/dist/builtin/skills/tui-use/README.md +7 -0
  34. package/dist/builtin/skills/tui-use/SKILL.md +58 -0
  35. package/dist/chunks/chunk-5353DEEC.js +130 -0
  36. package/dist/chunks/{chunk-KDPAGHYY.js → chunk-G2POWIA5.js} +129 -194
  37. package/dist/chunks/{chunk-S2J3SZZX.js → chunk-IM43UYVV.js} +827 -3385
  38. package/dist/chunks/{chunk-A644H2XX.js → chunk-PMPD56N2.js} +159 -72
  39. package/dist/chunks/{chunk-B3SMW2XW.js → chunk-QJH6YN2W.js} +1 -1
  40. package/dist/chunks/chunk-XXGYUYXI.js +2718 -0
  41. package/dist/chunks/{src-UKCIAX6F.js → src-QSP2OPHU.js} +3 -2
  42. package/dist/chunks/{test-stream-NCBFPM2I.js → test-stream-CVGWFLSX.js} +2 -1
  43. package/dist/chunks/webapi-MBCKO7ZV.js +2481 -0
  44. package/dist/cli.js +149 -68
  45. package/package.json +5 -4
  46. package/dist/builtin/skills/browser-tools/CHANGELOG.md +0 -5
  47. package/dist/builtin/skills/browser-tools/README.md +0 -17
  48. package/dist/builtin/skills/browser-tools/SKILL.md +0 -43
  49. package/dist/builtin/skills/browser-tools/package.json +0 -12
  50. package/dist/builtin/skills/browser-tools/playwright-cli.js +0 -45
@@ -0,0 +1,549 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createHash } from "node:crypto";
4
+ import { spawn, execFile as execFileCallback } from "node:child_process";
5
+ import { constants as fsConstants, realpathSync } from "node:fs";
6
+ import { promisify } from "node:util";
7
+ import fs from "node:fs/promises";
8
+ import os from "node:os";
9
+ import path from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ import { resolveMacosHelperAppPath } from "./helper-path.mjs";
12
+
13
+ const execFile = promisify(execFileCallback);
14
+ const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
15
+ const helperAppPath = resolveMacosHelperAppPath();
16
+ const helperAppExecutablePath = path.join(helperAppPath, "Contents", "MacOS", "pie-computer-use");
17
+ const helperSourceHashPath = path.join(helperAppPath, "Contents", "Resources", "source.sha256");
18
+ const helperBundleId = "com.pie.computer-use";
19
+ const windowsCrateDir = path.join(rootDir, "native", "windows", "bridge-rs");
20
+ const windowsHelperDestPath = process.env.PIE_COMPUTER_USE_WINDOWS_HELPER_PATH || path.join(resolvePieConfigDir(), "helpers", "computer-use", "windows-bridge.exe");
21
+ const linuxCrateDir = path.join(rootDir, "native", "linux", "bridge-rs");
22
+ const linuxHelperDestPath = process.env.PIE_COMPUTER_USE_LINUX_HELPER_PATH || path.join(resolvePieConfigDir(), "helpers", "computer-use", "linux-bridge");
23
+ const helperSourcePaths = ["agent_cursor.swift", "agent_cursor_motion.swift", "bridge.swift"]
24
+ .map((file) => path.join(rootDir, "native", "macos", file));
25
+ const packageJsonPath = path.join(rootDir, "package.json");
26
+ const localCodeSignCommonName = "pie-computer-use Local Signing (com.pie.computer-use)";
27
+ const localSigningLockPath = path.join(os.tmpdir(), `pie-computer-use-local-signing-${typeof process.getuid === "function" ? process.getuid() : "user"}.lock`);
28
+
29
+ const args = new Set(process.argv.slice(2));
30
+
31
+ /** Mirror of products/cli/src/config.ts getConfigDir() for standalone .mjs use. */
32
+ function resolvePieConfigDir() {
33
+ const envDir = process.env.PIE_CODING_AGENT_DIR;
34
+ if (envDir) {
35
+ if (envDir === "~") return os.homedir();
36
+ if (envDir.startsWith("~/")) return os.homedir() + envDir.slice(1);
37
+ return envDir;
38
+ }
39
+ return path.join(os.homedir(), ".pie");
40
+ }
41
+ const isPostinstall = args.has("--postinstall");
42
+ const allowBuildFallback = args.has("--allow-build") || args.has("--runtime") || process.env.PIE_COMPUTER_USE_ALLOW_BUILD === "1";
43
+ // Windows matches Linux: a first-tool-call runtime install must not trigger a
44
+ // full cargo source build (it far exceeds the 60s setup timeout); require an
45
+ // explicit --allow-build / PIE_COMPUTER_USE_ALLOW_BUILD=1 for that.
46
+ const allowWindowsBuildFallback = args.has("--allow-build") || process.env.PIE_COMPUTER_USE_ALLOW_BUILD === "1";
47
+ const allowLinuxBuildFallback = args.has("--allow-build") || process.env.PIE_COMPUTER_USE_ALLOW_BUILD === "1";
48
+ const allowAdhocUpdate = args.has("--allow-adhoc-update") || process.env.PIE_COMPUTER_USE_ALLOW_ADHOC_UPDATE === "1";
49
+
50
+ function getArg(name) {
51
+ const index = process.argv.indexOf(name);
52
+ if (index >= 0 && index + 1 < process.argv.length) return process.argv[index + 1];
53
+ return undefined;
54
+ }
55
+ const archTriples = {
56
+ arm64: "arm64-apple-macosx",
57
+ x64: "x86_64-apple-macosx",
58
+ };
59
+ const deploymentTarget = "14.0";
60
+ const frameworks = ["ApplicationServices", "AppKit", "ScreenCaptureKit", "Foundation", "SwiftUI"];
61
+ const defaultCodeSignIdentifier = "com.pie.computer-use";
62
+
63
+ function normalizeArch(arch) {
64
+ if (arch === "arm64" || arch === "x64") return arch;
65
+ throw new Error(`Unsupported architecture '${arch}'. Supported: arm64, x64.`);
66
+ }
67
+
68
+ function prebuiltPathForArch(arch) {
69
+ return path.join(rootDir, "prebuilt", "macos", arch, "pie-computer-use");
70
+ }
71
+
72
+ function prebuiltAppPathForArch(arch) {
73
+ return path.join(rootDir, "prebuilt", "macos", arch, "pie-computer-use.app");
74
+ }
75
+
76
+ async function packageVersion() {
77
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
78
+ if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
79
+ throw new Error(`Could not read package version from ${packageJsonPath}.`);
80
+ }
81
+ return packageJson.version;
82
+ }
83
+
84
+ async function exists(filePath) {
85
+ try {
86
+ await fs.access(filePath, fsConstants.F_OK);
87
+ return true;
88
+ } catch {
89
+ return false;
90
+ }
91
+ }
92
+
93
+ async function hashFile(filePath) {
94
+ const data = await fs.readFile(filePath);
95
+ return createHash("sha256").update(data).digest("hex");
96
+ }
97
+
98
+ async function copyIfChanged(sourcePath, destinationPath) {
99
+ const destinationExists = await exists(destinationPath);
100
+ if (destinationExists) {
101
+ const [sourceHash, destinationHash] = await Promise.all([hashFile(sourcePath), hashFile(destinationPath)]);
102
+ if (sourceHash === destinationHash) {
103
+ await fs.chmod(destinationPath, 0o755);
104
+ return { changed: false };
105
+ }
106
+ }
107
+
108
+ await fs.mkdir(path.dirname(destinationPath), { recursive: true });
109
+ const tempPath = `${destinationPath}.tmp-${process.pid}-${Date.now()}`;
110
+ await fs.copyFile(sourcePath, tempPath);
111
+ await fs.chmod(tempPath, 0o755);
112
+ try {
113
+ await fs.rename(tempPath, destinationPath);
114
+ } catch (err) {
115
+ await fs.rm(tempPath, { force: true }).catch(() => {});
116
+ if (err.code === "EPERM") {
117
+ throw new Error(`Cannot update helper at ${destinationPath} — the existing helper process is still running. Close the helper process and re-run this script.`);
118
+ }
119
+ throw err;
120
+ }
121
+ return { changed: true };
122
+ }
123
+
124
+ async function run(command, commandArgs) {
125
+ await new Promise((resolve, reject) => {
126
+ const child = spawn(command, commandArgs, { stdio: "inherit" });
127
+ child.on("error", reject);
128
+ child.on("close", (code) => {
129
+ if (code === 0) {
130
+ resolve();
131
+ return;
132
+ }
133
+ reject(new Error(`Command failed (${code}): ${command} ${commandArgs.join(" ")}`));
134
+ });
135
+ });
136
+ }
137
+
138
+ function moduleCachePath(arch) {
139
+ return path.join(os.tmpdir(), `pie-computer-use-swift-module-cache-${arch}`);
140
+ }
141
+
142
+ async function commandOutput(command, commandArgs) {
143
+ const { stdout } = await execFile(command, commandArgs, { encoding: "utf8" });
144
+ return stdout;
145
+ }
146
+
147
+ async function findDeveloperIdIdentity() {
148
+ const output = await commandOutput("security", ["find-identity", "-p", "codesigning", "-v"]).catch(() => "");
149
+ const line = output.split("\n").find((item) => item.includes("Developer ID Application"));
150
+ return line?.trim().split(/\s+/)[1];
151
+ }
152
+
153
+ export function parseCodeSigningIdentities(output, commonName = localCodeSignCommonName) {
154
+ return output.split("\n")
155
+ .map((line) => line.match(/^\s*\d+\)\s+([0-9A-F]{40})\s+"([^"]+)"/i))
156
+ .filter((match) => match?.[2] === commonName)
157
+ .map((match) => match[1].toUpperCase());
158
+ }
159
+
160
+ async function findLocalSigningIdentity() {
161
+ // Self-signed local identities appear as CSSMERR_TP_NOT_TRUSTED and are
162
+ // omitted by `-v`, but remain valid inputs to codesign. Match the identity
163
+ // list directly and return its fingerprint rather than its display name.
164
+ const output = await commandOutput("security", ["find-identity", "-p", "codesigning"]).catch(() => "");
165
+ return parseCodeSigningIdentities(output)[0];
166
+ }
167
+
168
+ function delay(ms) {
169
+ return new Promise((resolve) => setTimeout(resolve, ms));
170
+ }
171
+
172
+ export async function withDirectoryLock(lockPath, callback, { waitMs = 15_000, staleMs = 300_000, retryMs = 50 } = {}) {
173
+ const deadline = Date.now() + waitMs;
174
+ while (true) {
175
+ try {
176
+ await fs.mkdir(lockPath);
177
+ break;
178
+ } catch (error) {
179
+ if (error?.code !== "EEXIST") throw error;
180
+ const stat = await fs.stat(lockPath).catch(() => undefined);
181
+ if (stat && Date.now() - stat.mtimeMs > staleMs) {
182
+ await fs.rm(lockPath, { force: true, recursive: true }).catch(() => undefined);
183
+ continue;
184
+ }
185
+ if (Date.now() >= deadline) throw new Error(`Timed out waiting for local signing identity lock at ${lockPath}.`);
186
+ await delay(retryMs);
187
+ }
188
+ }
189
+ try {
190
+ return await callback();
191
+ } finally {
192
+ await fs.rm(lockPath, { force: true, recursive: true }).catch(() => undefined);
193
+ }
194
+ }
195
+
196
+ export async function ensureIdentityOnce(findIdentity, createIdentity, withLock) {
197
+ return (await findIdentity()) ?? await withLock(async () => (await findIdentity()) ?? await createIdentity());
198
+ }
199
+
200
+ async function loginKeychainPath() {
201
+ for (const candidate of [
202
+ path.join(os.homedir(), "Library", "Keychains", "login.keychain-db"),
203
+ path.join(os.homedir(), "Library", "Keychains", "login.keychain"),
204
+ ]) {
205
+ if (await exists(candidate)) return candidate;
206
+ }
207
+ return undefined;
208
+ }
209
+
210
+ async function ensureLocalSigningIdentity() {
211
+ if (process.platform !== "darwin") return undefined;
212
+ if (!(await commandOutput("which", ["codesign"]).catch(() => ""))) return undefined;
213
+ const existingIdentity = await findLocalSigningIdentity();
214
+ if (existingIdentity) return existingIdentity;
215
+ if (!(await commandOutput("which", ["openssl"]).catch(() => ""))) return undefined;
216
+ const keychain = await loginKeychainPath();
217
+ if (!keychain) return undefined;
218
+
219
+ return await ensureIdentityOnce(findLocalSigningIdentity, createLocalSigningIdentity, (callback) => withDirectoryLock(localSigningLockPath, callback));
220
+ }
221
+
222
+ async function createLocalSigningIdentity() {
223
+ const keychain = await loginKeychainPath();
224
+ if (!keychain) return undefined;
225
+ const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "pie-computer-use-signing-"));
226
+ const password = `pie-computer-use-local-${process.pid}-${Date.now()}`;
227
+ try {
228
+ const configPath = path.join(tempDir, "req.cnf");
229
+ await fs.writeFile(configPath, [
230
+ "[req]",
231
+ "distinguished_name=dn",
232
+ "x509_extensions=ext",
233
+ "prompt=no",
234
+ "[dn]",
235
+ `CN=${localCodeSignCommonName}`,
236
+ "[ext]",
237
+ "basicConstraints=critical,CA:FALSE",
238
+ "keyUsage=critical,digitalSignature",
239
+ "extendedKeyUsage=critical,codeSigning",
240
+ "",
241
+ ].join("\n"));
242
+ const keyPath = path.join(tempDir, "key.pem");
243
+ const certPath = path.join(tempDir, "cert.pem");
244
+ const p12Path = path.join(tempDir, "id.p12");
245
+ await execFile("openssl", ["req", "-x509", "-newkey", "rsa:2048", "-keyout", keyPath, "-out", certPath, "-days", "3650", "-nodes", "-config", configPath]);
246
+ await execFile("openssl", ["pkcs12", "-export", "-legacy", "-inkey", keyPath, "-in", certPath, "-out", p12Path, "-passout", `pass:${password}`, "-name", localCodeSignCommonName])
247
+ .catch(async () => {
248
+ await execFile("openssl", ["pkcs12", "-export", "-inkey", keyPath, "-in", certPath, "-out", p12Path, "-passout", `pass:${password}`, "-name", localCodeSignCommonName]);
249
+ });
250
+ await execFile("security", ["import", p12Path, "-k", keychain, "-P", password, "-A", "-T", "/usr/bin/codesign"]);
251
+ const identity = await findLocalSigningIdentity();
252
+ if (!identity) throw new Error("Imported local signing certificate is not a valid code-signing identity.");
253
+ return identity;
254
+ } catch (error) {
255
+ console.warn(`[pie-computer-use] could not create a valid local signing identity: ${error instanceof Error ? error.message : String(error)}`);
256
+ return undefined;
257
+ } finally {
258
+ await fs.rm(tempDir, { force: true, recursive: true }).catch(() => {});
259
+ }
260
+ }
261
+
262
+ async function resolveCodeSignIdentity() {
263
+ if (process.env.PIE_COMPUTER_USE_CODESIGN_IDENTITY) return process.env.PIE_COMPUTER_USE_CODESIGN_IDENTITY;
264
+ return (await findDeveloperIdIdentity()) ?? (await ensureLocalSigningIdentity()) ?? "-";
265
+ }
266
+
267
+ async function signHelper(outputPath, identifier = defaultCodeSignIdentifier) {
268
+ if (process.env.PIE_COMPUTER_USE_NO_SIGN === "1") {
269
+ return "unsigned";
270
+ }
271
+
272
+ const identity = await resolveCodeSignIdentity();
273
+ const commandArgs = ["--force", "--deep", "-i", identifier, "--timestamp=none", "--sign", identity, outputPath];
274
+ await run("codesign", commandArgs);
275
+ if (identity === "-") {
276
+ console.warn("[pie-computer-use] warning: signed helper ad-hoc; macOS may require permission review after native helper changes. Release installs should use a Developer ID-signed helper app.");
277
+ } else if (identity === await findLocalSigningIdentity()) {
278
+ console.log(`[pie-computer-use] signed ${outputPath} with local identity '${localCodeSignCommonName}'. macOS may still require permission review after local rebuilds.`);
279
+ }
280
+ return identity;
281
+ }
282
+
283
+ async function helperHasAdhocSignature() {
284
+ const output = await execFile("codesign", ["-dv", "--verbose=4", helperAppPath], { encoding: "utf8" }).then(
285
+ (result) => `${result.stdout ?? ""}\n${result.stderr ?? ""}`,
286
+ (error) => `${error.stdout ?? ""}\n${error.stderr ?? ""}`,
287
+ );
288
+ return /Signature=adhoc/i.test(output);
289
+ }
290
+
291
+ async function registerHelperApp() {
292
+ // Tests run the installer against throwaway HOMEs; registering those
293
+ // copies pollutes the user's Launch Services database (and those names
294
+ // later surface in TCC dialogs). Tests opt out via this env var.
295
+ if (process.env.PIE_COMPUTER_USE_SKIP_LS_REGISTER === "1") return;
296
+ const lsregister = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister";
297
+ if (!(await exists(lsregister))) return;
298
+ await run(lsregister, ["-f", helperAppPath]).catch(() => {});
299
+ }
300
+
301
+ async function ensureHelperParentDirectory() {
302
+ const parentPath = path.dirname(helperAppPath);
303
+ await fs.mkdir(parentPath, { recursive: true });
304
+ await fs.access(parentPath, fsConstants.W_OK);
305
+ }
306
+
307
+ async function installPrebuiltHelperApp(sourceAppPath) {
308
+ await ensureHelperParentDirectory();
309
+ const sourceExecutablePath = path.join(sourceAppPath, "Contents", "MacOS", "pie-computer-use");
310
+ const sourceInfoPath = path.join(sourceAppPath, "Contents", "Info.plist");
311
+ const existingExecutable = await fs.readFile(helperAppExecutablePath).catch(() => undefined);
312
+ const sourceExecutable = await fs.readFile(sourceExecutablePath);
313
+ const existingInfo = await fs.readFile(path.join(helperAppPath, "Contents", "Info.plist"), "utf8").catch(() => undefined);
314
+ const sourceInfo = await fs.readFile(sourceInfoPath, "utf8");
315
+ if (existingExecutable?.equals(sourceExecutable) && existingInfo === sourceInfo) {
316
+ await registerHelperApp();
317
+ return false;
318
+ }
319
+ // The sealed bundle must arrive intact — a broken signature would burn
320
+ // the user's TCC grants on an identity that can never validate.
321
+ await run("codesign", ["--verify", "--strict", sourceAppPath]);
322
+ await fs.rm(helperAppPath, { force: true, recursive: true });
323
+ // ditto preserves the bundle byte-for-byte (signature + stapled
324
+ // notarization ticket). The sealed app is NEVER re-signed here: its
325
+ // Developer ID designated requirement (identifier + team) is exactly
326
+ // what gives release builds their best chance of retaining TCC grants.
327
+ await run("/usr/bin/ditto", [sourceAppPath, helperAppPath]);
328
+ await registerHelperApp();
329
+ return true;
330
+ }
331
+
332
+ async function installHelperApp(sourcePath) {
333
+ await ensureHelperParentDirectory();
334
+ const version = await packageVersion();
335
+ const infoPlistPath = path.join(helperAppPath, "Contents", "Info.plist");
336
+ const infoPlist = `<?xml version="1.0" encoding="UTF-8"?>
337
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
338
+ <plist version="1.0"><dict>
339
+ <key>CFBundleIdentifier</key><string>${helperBundleId}</string>
340
+ <key>CFBundleName</key><string>pie-computer-use</string>
341
+ <key>CFBundleDisplayName</key><string>pie-computer-use</string>
342
+ <key>CFBundleExecutable</key><string>pie-computer-use</string>
343
+ <key>CFBundlePackageType</key><string>APPL</string>
344
+ <key>CFBundleShortVersionString</key><string>${version}</string>
345
+ <key>CFBundleVersion</key><string>${version}</string>
346
+ <key>LSMinimumSystemVersion</key><string>14.0</string>
347
+ <key>LSUIElement</key><true/>
348
+ </dict></plist>\n`;
349
+
350
+ const sourceExecutable = await fs.readFile(sourcePath);
351
+ const sourceHash = createHash("sha256").update(sourceExecutable).digest("hex");
352
+ const existingSourceHash = await fs.readFile(helperSourceHashPath, "utf8").catch(() => undefined);
353
+ const existingInfoPlist = await fs.readFile(infoPlistPath, "utf8").catch(() => undefined);
354
+ if (existingSourceHash?.trim() === sourceHash && existingInfoPlist === infoPlist) {
355
+ // If a real signing identity is available, upgrade older ad-hoc installs
356
+ // in place so local builds have a consistent identity. macOS may still
357
+ // require permission review after native code changes.
358
+ const signingIdentity = process.env.PIE_COMPUTER_USE_NO_SIGN === "1" ? "-" : await resolveCodeSignIdentity();
359
+ if (signingIdentity !== "-" && await helperHasAdhocSignature()) {
360
+ await signHelper(helperAppPath, helperBundleId);
361
+ await registerHelperApp();
362
+ return true;
363
+ }
364
+ await registerHelperApp();
365
+ return false;
366
+ }
367
+
368
+ const signingIdentity = process.env.PIE_COMPUTER_USE_NO_SIGN === "1" ? "-" : await resolveCodeSignIdentity();
369
+ if (signingIdentity === "-" && existingSourceHash !== undefined && !allowAdhocUpdate) {
370
+ throw new Error("Refusing to replace an installed helper with an ad-hoc signed rebuild because macOS may reset Accessibility/Screen Recording grants. Use a pre-signed helper app, install a Developer ID identity, or set PIE_COMPUTER_USE_ALLOW_ADHOC_UPDATE=1 for local development.");
371
+ }
372
+
373
+ await fs.mkdir(path.dirname(helperAppExecutablePath), { recursive: true });
374
+ await fs.mkdir(path.dirname(helperSourceHashPath), { recursive: true });
375
+ await fs.copyFile(sourcePath, helperAppExecutablePath);
376
+ await fs.chmod(helperAppExecutablePath, 0o755);
377
+ await fs.writeFile(infoPlistPath, infoPlist);
378
+ await fs.writeFile(helperSourceHashPath, `${sourceHash}\n`);
379
+ await signHelper(helperAppPath, helperBundleId);
380
+ await registerHelperApp();
381
+ return true;
382
+ }
383
+
384
+ async function buildHelper(arch, outputPath) {
385
+ for (const sourcePath of helperSourcePaths) {
386
+ if (!(await exists(sourcePath))) throw new Error(`Native helper source not found at ${sourcePath}`);
387
+ }
388
+
389
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
390
+ const swiftArgs = [
391
+ "swiftc",
392
+ "-target",
393
+ `${archTriples[arch]}${deploymentTarget}`,
394
+ "-module-cache-path",
395
+ moduleCachePath(arch),
396
+ "-O",
397
+ ];
398
+ for (const framework of frameworks) swiftArgs.push("-framework", framework);
399
+ swiftArgs.push(...helperSourcePaths, "-o", outputPath);
400
+
401
+ await run("xcrun", swiftArgs);
402
+ await fs.chmod(outputPath, 0o755);
403
+ await signHelper(outputPath);
404
+ }
405
+
406
+ function windowsBinaryPath() {
407
+ const releaseDir = path.join(windowsCrateDir, "target", "release");
408
+ return {
409
+ exePath: path.join(releaseDir, "windows-bridge.exe"),
410
+ binPath: path.join(releaseDir, "windows-bridge"),
411
+ };
412
+ }
413
+
414
+ async function setupWindowsHelper() {
415
+ const prebuiltPath = path.join(rootDir, "prebuilt", "windows", "windows-bridge.exe");
416
+ if (await exists(prebuiltPath)) {
417
+ const { changed } = await copyIfChanged(prebuiltPath, windowsHelperDestPath);
418
+ console.log(changed
419
+ ? `[pie-computer-use] installed Windows helper from prebuilt to ${windowsHelperDestPath}`
420
+ : `[pie-computer-use] Windows helper already up to date at ${windowsHelperDestPath}`);
421
+ return;
422
+ }
423
+
424
+ if (allowWindowsBuildFallback) {
425
+ console.log("[pie-computer-use] Windows prebuilt helper missing; attempting source build with cargo...");
426
+ await run("cargo", ["build", "--release", "--manifest-path", path.join(windowsCrateDir, "Cargo.toml")]);
427
+ const { exePath, binPath } = windowsBinaryPath();
428
+ const cargoOutput = (await exists(exePath)) ? exePath : (await exists(binPath)) ? binPath : exePath;
429
+ const { changed } = await copyIfChanged(cargoOutput, windowsHelperDestPath);
430
+ console.log(changed
431
+ ? `[pie-computer-use] built and installed Windows helper at ${windowsHelperDestPath}`
432
+ : `[pie-computer-use] Windows helper already up to date at ${windowsHelperDestPath}`);
433
+ return;
434
+ }
435
+
436
+ throw new Error(
437
+ `No Windows prebuilt helper found at ${prebuiltPath}. ` +
438
+ "Reinstall Pie to restore the bundled helper. Source builds (node scripts/build-native.mjs --platform windows; needs cargo and the native/ sources) only work in a Pie source checkout, not in an installed copy; PIE_COMPUTER_USE_ALLOW_BUILD=1 enables that fallback at install time.",
439
+ );
440
+ }
441
+
442
+ async function setupLinuxHelper() {
443
+ const arch = normalizeArch(process.arch);
444
+ const prebuiltPath = path.join(rootDir, "prebuilt", "linux", arch, "linux-bridge");
445
+ if (await exists(prebuiltPath)) {
446
+ const { changed } = await copyIfChanged(prebuiltPath, linuxHelperDestPath);
447
+ console.log(changed ? `[pie-computer-use] installed Linux helper (${arch}) from prebuilt to ${linuxHelperDestPath}` : `[pie-computer-use] Linux helper already up to date at ${linuxHelperDestPath}`);
448
+ return;
449
+ }
450
+ if (allowLinuxBuildFallback) {
451
+ if (process.platform !== "linux") throw new Error("The Linux helper source fallback must be built on Linux.");
452
+ console.log("[pie-computer-use] Linux prebuilt helper missing; attempting source build with cargo...");
453
+ await run("cargo", ["build", "--release", "--manifest-path", path.join(linuxCrateDir, "Cargo.toml")]);
454
+ const cargoOutput = path.join(linuxCrateDir, "target", "release", "linux-bridge");
455
+ const { changed } = await copyIfChanged(cargoOutput, linuxHelperDestPath);
456
+ console.log(changed ? `[pie-computer-use] built and installed Linux helper at ${linuxHelperDestPath}` : `[pie-computer-use] Linux helper already up to date at ${linuxHelperDestPath}`);
457
+ return;
458
+ }
459
+ throw new Error(`No Linux prebuilt helper found for ${arch} at ${prebuiltPath}. Reinstall Pie to restore the bundled helper. Source builds (node scripts/build-native.mjs --platform linux; needs cargo and the native/ sources) only work in a Pie source checkout, not in an installed copy; PIE_COMPUTER_USE_ALLOW_BUILD=1 enables that fallback at install time.`);
460
+ }
461
+
462
+ async function setup() {
463
+ const explicitPlatform = getArg("--platform");
464
+ if (explicitPlatform === "windows" || (!explicitPlatform && process.platform === "win32")) {
465
+ await setupWindowsHelper();
466
+ return;
467
+ }
468
+ if (explicitPlatform === "linux" || (!explicitPlatform && process.platform === "linux")) {
469
+ await setupLinuxHelper();
470
+ return;
471
+ }
472
+
473
+ if (process.platform !== "darwin") {
474
+ if (isPostinstall) {
475
+ console.warn("[pie-computer-use] skipping helper setup: platform is not macOS.");
476
+ return;
477
+ }
478
+ throw new Error("pie-computer-use helper is supported on macOS, Windows, and Linux. Use the matching --platform option.");
479
+ }
480
+
481
+ const arch = normalizeArch(process.arch);
482
+ // Prefer the universal bundle (one artifact for both arches, built and
483
+ // signed with Pie's identity via build-native.mjs) over per-arch
484
+ // bundles, over loose binaries (dev fallback).
485
+ const universalAppPath = prebuiltAppPathForArch("universal");
486
+ const prebuiltAppPath = (await exists(universalAppPath))
487
+ ? universalAppPath
488
+ : prebuiltAppPathForArch(arch);
489
+ const prebuiltPath = prebuiltPathForArch(arch);
490
+ const prebuiltAppExists = await exists(prebuiltAppPath);
491
+ const prebuiltExists = await exists(prebuiltPath);
492
+
493
+ if (prebuiltAppExists) {
494
+ const installed = await installPrebuiltHelperApp(prebuiltAppPath);
495
+ const bundleKind = prebuiltAppPath === universalAppPath ? "universal" : arch;
496
+ console.log(
497
+ installed
498
+ ? `[pie-computer-use] installed pre-signed helper app (${bundleKind}) at ${helperAppPath}`
499
+ : `[pie-computer-use] pre-signed helper app (${bundleKind}) already current at ${helperAppPath}`,
500
+ );
501
+ return;
502
+ }
503
+
504
+ if (prebuiltExists) {
505
+ const installed = await installHelperApp(prebuiltPath);
506
+ console.log(
507
+ installed
508
+ ? `[pie-computer-use] installed helper app (${arch}) at ${helperAppPath}`
509
+ : `[pie-computer-use] helper app (${arch}) already current at ${helperAppPath}`,
510
+ );
511
+ return;
512
+ }
513
+
514
+ if (allowBuildFallback) {
515
+ const tempPath = path.join(os.tmpdir(), `pie-computer-use-bridge-${process.pid}-${Date.now()}`);
516
+ try {
517
+ console.log("[pie-computer-use] prebuilt helper missing; attempting source build with xcrun swiftc...");
518
+ await buildHelper(arch, tempPath);
519
+ const installed = await installHelperApp(tempPath);
520
+ console.log(
521
+ installed
522
+ ? `[pie-computer-use] built helper app at ${helperAppPath}`
523
+ : `[pie-computer-use] built helper app; installed app already current at ${helperAppPath}`,
524
+ );
525
+ } finally {
526
+ await fs.rm(tempPath, { force: true }).catch(() => {});
527
+ }
528
+ return;
529
+ }
530
+
531
+ throw new Error(
532
+ `No prebuilt helper found for ${arch} at ${prebuiltPath}. Reinstall Pie to restore the bundled helper. Source builds (node scripts/build-native.mjs --arch ${arch}; needs Xcode command line tools and the native/ Swift sources) only work in a Pie source checkout, not in an installed copy; PIE_COMPUTER_USE_ALLOW_BUILD=1 enables that fallback at install time.`,
533
+ );
534
+ }
535
+
536
+ const normalizeMainPath = (candidate) => {
537
+ const normalized = path.normalize(realpathSync(candidate));
538
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
539
+ };
540
+ const isMain = process.argv[1] && normalizeMainPath(path.resolve(process.argv[1])) === normalizeMainPath(fileURLToPath(import.meta.url));
541
+ if (isMain) setup().catch((error) => {
542
+ if (isPostinstall) {
543
+ console.warn(`[pie-computer-use] postinstall helper setup skipped: ${error instanceof Error ? error.message : String(error)}`);
544
+ process.exit(0);
545
+ }
546
+
547
+ console.error(error instanceof Error ? error.message : String(error));
548
+ process.exit(1);
549
+ });
@@ -1,11 +1,11 @@
1
1
  {
2
- "name": "@pie/extension-document-attachments",
3
- "version": "1.0.0",
4
- "description": "Local document attachment preprocessing (PDF, HTML, plain text)",
5
- "main": "index.ts",
6
- "type": "module",
7
- "pie": {
8
- "name": "document-attachments",
9
- "main": "index.ts"
10
- }
2
+ "name": "@pie/extension-document-attachments",
3
+ "version": "1.0.0",
4
+ "description": "Local document attachment preprocessing (PDF, HTML, plain text)",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "pie": {
8
+ "name": "document-attachments",
9
+ "main": "index.js"
10
+ }
11
11
  }
@@ -1,11 +1,11 @@
1
1
  {
2
- "name": "@pie/extension-init",
3
- "version": "1.0.0",
4
- "description": "Project initialization and root AGENTS.md management",
5
- "main": "index.ts",
6
- "type": "module",
7
- "pie": {
8
- "name": "init",
9
- "main": "index.ts"
10
- }
2
+ "name": "@pie/extension-init",
3
+ "version": "1.0.0",
4
+ "description": "Project initialization and root AGENTS.md management",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "pie": {
8
+ "name": "init",
9
+ "main": "index.js"
10
+ }
11
11
  }