local-commander-agent 0.3.53 → 0.3.54

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.
@@ -1,38 +1,38 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import { createHash } from "node:crypto";
4
-
5
- const HASH=/^[a-f0-9]{64}$/;
6
- /** Signed bundles may be set up during install; an unsigned pilot only by an explicit owner command. */
7
- export function implicitSetupAllowed(manifest){return manifest?.signed===true;}
8
- const FILES=["JobHost.exe","libcronet.dll","sing-box.exe","wintun.dll","sing-box.LICENSE","wintun.LICENSE"];
9
- async function plainDirectory(directory) {
10
- const stat=await fs.lstat(directory);
11
- if(!stat.isDirectory()||stat.isSymbolicLink()||(await fs.realpath(directory)).toLowerCase()!==path.resolve(directory).toLowerCase())throw Error("NETWORK_BUNDLE_DIRECTORY_INVALID");
12
- }
13
- async function bytes(file,max) {
14
- const stat=await fs.lstat(file);
15
- if(!stat.isFile()||stat.isSymbolicLink()||stat.size<1||stat.size>max)throw Error("NETWORK_BUNDLE_FILE_INVALID");
16
- return fs.readFile(file);
17
- }
18
- export async function inspectNetworkBundle(directory) {
19
- try {await plainDirectory(directory);}catch(error){if(error.code==="ENOENT")return null;throw error;}
20
- const manifest=JSON.parse((await bytes(path.join(directory,"manifest.json"),8192)).toString("utf8"));
21
- if(manifest.schemaVersion!==1||manifest.configured!==true||!(manifest.signed===true||manifest.signing==="unsigned-pilot")||!HASH.test(manifest.bundleId)||!HASH.test(manifest.helperSha256)||
22
- !manifest.files||typeof manifest.files!=="object"||Array.isArray(manifest.files)||Object.keys(manifest.files).sort().join()!==[...FILES].sort().join())throw Error("NETWORK_BUNDLE_NOT_DEPLOYABLE");
23
- const names=[...FILES,"NetworkService.exe","manifest.json"];
24
- if((await fs.readdir(directory)).sort().join()!==names.sort().join())throw Error("NETWORK_BUNDLE_ALLOWLIST_FAILED");
25
- for(const name of [...FILES,"NetworkService.exe"]){const expected=name==="NetworkService.exe"?manifest.helperSha256:manifest.files[name];
26
- if(!HASH.test(expected)||createHash("sha256").update(await bytes(path.join(directory,name),128*1024*1024)).digest("hex")!==expected)throw Error("NETWORK_BUNDLE_DIGEST_MISMATCH");}
27
- return {bundleId:manifest.bundleId,files:names,manifest};
28
- }
29
- export async function copyNetworkBundle(source,destination) {
30
- const bundle=await inspectNetworkBundle(source);if(!bundle)return false;
31
- if(path.resolve(source).toLowerCase()===path.resolve(destination).toLowerCase())return true;
32
- const exists=await fs.lstat(destination).catch(e=>{if(e.code!=="ENOENT")throw e;return null;});
33
- if(exists){const previous=await inspectNetworkBundle(destination);if(previous?.bundleId===bundle.bundleId&&previous.manifest.helperSha256===bundle.manifest.helperSha256)return true;throw Error("NETWORK_BUNDLE_DESTINATION_CONFLICT");}
34
- await fs.mkdir(destination,{recursive:false,mode:0o700});
35
- try{for(const name of bundle.files)await fs.copyFile(path.join(source,name),path.join(destination,name),fs.constants.COPYFILE_EXCL);await inspectNetworkBundle(destination);}
36
- catch(error){for(const name of bundle.files)await fs.rm(path.join(destination,name),{force:true}).catch(()=>{});await fs.rmdir(destination).catch(()=>{});throw error;}
37
- return true;
38
- }
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { createHash } from "node:crypto";
4
+
5
+ const HASH=/^[a-f0-9]{64}$/;
6
+ /** Signed bundles may be set up during install; an unsigned pilot only by an explicit owner command. */
7
+ export function implicitSetupAllowed(manifest){return manifest?.signed===true;}
8
+ const FILES=["JobHost.exe","libcronet.dll","sing-box.exe","wintun.dll","sing-box.LICENSE","wintun.LICENSE"];
9
+ async function plainDirectory(directory) {
10
+ const stat=await fs.lstat(directory);
11
+ if(!stat.isDirectory()||stat.isSymbolicLink()||(await fs.realpath(directory)).toLowerCase()!==path.resolve(directory).toLowerCase())throw Error("NETWORK_BUNDLE_DIRECTORY_INVALID");
12
+ }
13
+ async function bytes(file,max) {
14
+ const stat=await fs.lstat(file);
15
+ if(!stat.isFile()||stat.isSymbolicLink()||stat.size<1||stat.size>max)throw Error("NETWORK_BUNDLE_FILE_INVALID");
16
+ return fs.readFile(file);
17
+ }
18
+ export async function inspectNetworkBundle(directory) {
19
+ try {await plainDirectory(directory);}catch(error){if(error.code==="ENOENT")return null;throw error;}
20
+ const manifest=JSON.parse((await bytes(path.join(directory,"manifest.json"),8192)).toString("utf8"));
21
+ if(manifest.schemaVersion!==1||manifest.configured!==true||!(manifest.signed===true||manifest.signing==="unsigned-pilot")||!HASH.test(manifest.bundleId)||!HASH.test(manifest.helperSha256)||
22
+ !manifest.files||typeof manifest.files!=="object"||Array.isArray(manifest.files)||Object.keys(manifest.files).sort().join()!==[...FILES].sort().join())throw Error("NETWORK_BUNDLE_NOT_DEPLOYABLE");
23
+ const names=[...FILES,"NetworkService.exe","manifest.json"];
24
+ if((await fs.readdir(directory)).sort().join()!==names.sort().join())throw Error("NETWORK_BUNDLE_ALLOWLIST_FAILED");
25
+ for(const name of [...FILES,"NetworkService.exe"]){const expected=name==="NetworkService.exe"?manifest.helperSha256:manifest.files[name];
26
+ if(!HASH.test(expected)||createHash("sha256").update(await bytes(path.join(directory,name),128*1024*1024)).digest("hex")!==expected)throw Error("NETWORK_BUNDLE_DIGEST_MISMATCH");}
27
+ return {bundleId:manifest.bundleId,files:names,manifest};
28
+ }
29
+ export async function copyNetworkBundle(source,destination) {
30
+ const bundle=await inspectNetworkBundle(source);if(!bundle)return false;
31
+ if(path.resolve(source).toLowerCase()===path.resolve(destination).toLowerCase())return true;
32
+ const exists=await fs.lstat(destination).catch(e=>{if(e.code!=="ENOENT")throw e;return null;});
33
+ if(exists){const previous=await inspectNetworkBundle(destination);if(previous?.bundleId===bundle.bundleId&&previous.manifest.helperSha256===bundle.manifest.helperSha256)return true;throw Error("NETWORK_BUNDLE_DESTINATION_CONFLICT");}
34
+ await fs.mkdir(destination,{recursive:false,mode:0o700});
35
+ try{for(const name of bundle.files)await fs.copyFile(path.join(source,name),path.join(destination,name),fs.constants.COPYFILE_EXCL);await inspectNetworkBundle(destination);}
36
+ catch(error){for(const name of bundle.files)await fs.rm(path.join(destination,name),{force:true}).catch(()=>{});await fs.rmdir(destination).catch(()=>{});throw error;}
37
+ return true;
38
+ }
package/bin/posix.mjs CHANGED
@@ -1,84 +1,84 @@
1
- // macOS and Linux: the runtime ships in a per-platform package (an optional dependency, so npm installs only the
2
- // matching one). Its lifecycle accepts only a private, owner-only artifact directory, so the files are copied from the
3
- // npx cache into a fresh private directory and the lifecycle installs from there into its own versions directory.
4
- import { constants } from "node:fs";
5
- import fs from "node:fs/promises";
6
- import os from "node:os";
7
- import path from "node:path";
8
- import { spawnSync } from "node:child_process";
9
- import { createRequire } from "node:module";
10
-
11
- const PACKAGES = { "darwin-arm64": "local-commander-agent-darwin-arm64", "linux-x64": "local-commander-agent-linux-x64", "linux-arm64": "local-commander-agent-linux-arm64" };
12
- // npm command -> lifecycle command. The default (`npx local-commander-agent@latest`) is setup, as on Windows.
13
- const COMMANDS = { bootstrap: "setup", install: "setup", setup: "setup", update: "update", pair: "pair", access: "access", "configure-access": "access",
14
- start: "start", stop: "stop", status: "status", rollback: "rollback", uninstall: "uninstall" };
15
- const EXECUTABLES = new Set(["node", "posix-host", "owner-store"]);
16
-
17
- function fail(code) { const error = new Error(code); error.code = code; throw error; }
18
-
19
- export function posixHelp() {
20
- return [
21
- "Local Commander",
22
- "",
23
- " npx local-commander-agent@latest set up this computer, pair it and choose access",
24
- " npx local-commander-agent@latest update install this version, keeping pairing and access",
25
- " npx local-commander-agent@latest status|start|stop|pair|access|rollback",
26
- " npx local-commander-agent@latest uninstall [--purge-state]",
27
- ""
28
- ].join("\n");
29
- }
30
-
31
- // Owner opt-out for take_screenshot under Full Access (#486): a marker in the installed service agent's state folder
32
- // (the service runs without XDG_DATA_HOME). No runtime staging is needed; the agent checks it on each capture.
33
- async function screenshotCommand(args) {
34
- const action = args[0] || "status";
35
- if (args.length > 1 || !["status", "on", "off"].includes(action)) fail("ARGUMENT_INVALID");
36
- if (typeof process.getuid === "function" && process.getuid() === 0) fail("POSIX_OWNER_REQUIRED");
37
- const state = path.join(os.homedir(), process.platform === "darwin" ? "Library/Application Support" : ".local/share", "LocalCommander", "Agent");
38
- const folder = await fs.lstat(state).catch(() => null);
39
- if (!folder?.isDirectory() || folder.uid !== process.getuid()) fail("AGENT_NOT_INSTALLED");
40
- const file = path.join(state, "screenshot-disabled-by-owner");
41
- if (action === "off") await fs.open(file, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600)
42
- .then(handle => handle.close(), error => { if (error?.code !== "EEXIST") throw error; });
43
- if (action === "on") await fs.rm(file, { force: true });
44
- const off = await fs.lstat(file).then(() => true, error => error?.code !== "ENOENT");
45
- process.stdout.write(JSON.stringify({ screenshot: off ? "off" : "on" }) + "\n");
46
- }
47
-
48
- export async function runPosix(argv, version) {
49
- const name = PACKAGES[process.platform + "-" + process.arch];
50
- if (!name) fail(process.platform === "darwin" ? "MACOS_APPLE_SILICON_REQUIRED" : process.platform === "linux" ? "LINUX_X64_OR_ARM64_REQUIRED" : "PLATFORM_UNSUPPORTED");
51
- const command = argv[0] || "bootstrap", args = argv.slice(1);
52
- if (command === "-h" || command === "--help" || command === "help") { process.stdout.write(posixHelp()); return; }
53
- if (command === "screenshot") { await screenshotCommand(args); return; }
54
- const lifecycle = COMMANDS[command];
55
- if (!lifecycle) fail("ARGUMENT_INVALID");
56
- if (lifecycle === "uninstall" ? args.length > 1 || (args.length === 1 && args[0] !== "--purge-state") : args.length) fail("ARGUMENT_INVALID");
57
- if (typeof process.getuid === "function" && process.getuid() === 0) fail("POSIX_OWNER_REQUIRED");
58
-
59
- let packageJson;
60
- try { packageJson = createRequire(import.meta.url).resolve(name + "/package.json"); } catch { fail("PLATFORM_PACKAGE_MISSING"); }
61
- const meta = JSON.parse(await fs.readFile(packageJson, "utf8"));
62
- if (meta.name !== name || meta.version !== version) fail("PLATFORM_PACKAGE_MISMATCH");
63
- const source = path.join(path.dirname(packageJson), "runtime");
64
- const manifest = JSON.parse(await fs.readFile(path.join(source, "manifest.json"), "utf8"));
65
- const files = Object.keys(manifest?.files ?? {});
66
- if (manifest?.platform !== process.platform || manifest?.arch !== process.arch || !files.length || files.some(file => !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u.test(file))) fail("PLATFORM_PACKAGE_INVALID");
67
-
68
- // Canonical parent: on macOS os.tmpdir() is under /var, a symlink to /private/var, and the lifecycle rejects aliases.
69
- const stage = await fs.mkdtemp(path.join(await fs.realpath(os.tmpdir()), "local-commander-"));
70
- try {
71
- await fs.chmod(stage, 0o700);
72
- for (const file of [...files, "manifest.json"]) {
73
- const target = path.join(stage, file);
74
- await fs.copyFile(path.join(source, file), target, constants.COPYFILE_EXCL);
75
- await fs.chmod(target, EXECUTABLES.has(file) ? 0o700 : 0o600);
76
- }
77
- // The lifecycle verifies every file against the manifest, then copies them into its own versions directory.
78
- const result = spawnSync(path.join(stage, "node"), [path.join(stage, "lifecycle.mjs"), lifecycle, ...args], { stdio: "inherit" });
79
- if (result.error) throw result.error;
80
- process.exitCode = result.status ?? 1;
81
- } finally {
82
- await fs.rm(stage, { recursive: true, force: true });
83
- }
84
- }
1
+ // macOS and Linux: the runtime ships in a per-platform package (an optional dependency, so npm installs only the
2
+ // matching one). Its lifecycle accepts only a private, owner-only artifact directory, so the files are copied from the
3
+ // npx cache into a fresh private directory and the lifecycle installs from there into its own versions directory.
4
+ import { constants } from "node:fs";
5
+ import fs from "node:fs/promises";
6
+ import os from "node:os";
7
+ import path from "node:path";
8
+ import { spawnSync } from "node:child_process";
9
+ import { createRequire } from "node:module";
10
+
11
+ const PACKAGES = { "darwin-arm64": "local-commander-agent-darwin-arm64", "linux-x64": "local-commander-agent-linux-x64", "linux-arm64": "local-commander-agent-linux-arm64" };
12
+ // npm command -> lifecycle command. The default (`npx local-commander-agent@latest`) is setup, as on Windows.
13
+ const COMMANDS = { bootstrap: "setup", install: "setup", setup: "setup", update: "update", pair: "pair", access: "access", "configure-access": "access",
14
+ start: "start", stop: "stop", status: "status", rollback: "rollback", uninstall: "uninstall" };
15
+ const EXECUTABLES = new Set(["node", "posix-host", "owner-store"]);
16
+
17
+ function fail(code) { const error = new Error(code); error.code = code; throw error; }
18
+
19
+ export function posixHelp() {
20
+ return [
21
+ "Local Commander",
22
+ "",
23
+ " npx local-commander-agent@latest set up this computer, pair it and choose access",
24
+ " npx local-commander-agent@latest update install this version, keeping pairing and access",
25
+ " npx local-commander-agent@latest status|start|stop|pair|access|rollback",
26
+ " npx local-commander-agent@latest uninstall [--purge-state]",
27
+ ""
28
+ ].join("\n");
29
+ }
30
+
31
+ // Owner opt-out for take_screenshot under Full Access (#486): a marker in the installed service agent's state folder
32
+ // (the service runs without XDG_DATA_HOME). No runtime staging is needed; the agent checks it on each capture.
33
+ async function screenshotCommand(args) {
34
+ const action = args[0] || "status";
35
+ if (args.length > 1 || !["status", "on", "off"].includes(action)) fail("ARGUMENT_INVALID");
36
+ if (typeof process.getuid === "function" && process.getuid() === 0) fail("POSIX_OWNER_REQUIRED");
37
+ const state = path.join(os.homedir(), process.platform === "darwin" ? "Library/Application Support" : ".local/share", "LocalCommander", "Agent");
38
+ const folder = await fs.lstat(state).catch(() => null);
39
+ if (!folder?.isDirectory() || folder.uid !== process.getuid()) fail("AGENT_NOT_INSTALLED");
40
+ const file = path.join(state, "screenshot-disabled-by-owner");
41
+ if (action === "off") await fs.open(file, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600)
42
+ .then(handle => handle.close(), error => { if (error?.code !== "EEXIST") throw error; });
43
+ if (action === "on") await fs.rm(file, { force: true });
44
+ const off = await fs.lstat(file).then(() => true, error => error?.code !== "ENOENT");
45
+ process.stdout.write(JSON.stringify({ screenshot: off ? "off" : "on" }) + "\n");
46
+ }
47
+
48
+ export async function runPosix(argv, version) {
49
+ const name = PACKAGES[process.platform + "-" + process.arch];
50
+ if (!name) fail(process.platform === "darwin" ? "MACOS_APPLE_SILICON_REQUIRED" : process.platform === "linux" ? "LINUX_X64_OR_ARM64_REQUIRED" : "PLATFORM_UNSUPPORTED");
51
+ const command = argv[0] || "bootstrap", args = argv.slice(1);
52
+ if (command === "-h" || command === "--help" || command === "help") { process.stdout.write(posixHelp()); return; }
53
+ if (command === "screenshot") { await screenshotCommand(args); return; }
54
+ const lifecycle = COMMANDS[command];
55
+ if (!lifecycle) fail("ARGUMENT_INVALID");
56
+ if (lifecycle === "uninstall" ? args.length > 1 || (args.length === 1 && args[0] !== "--purge-state") : args.length) fail("ARGUMENT_INVALID");
57
+ if (typeof process.getuid === "function" && process.getuid() === 0) fail("POSIX_OWNER_REQUIRED");
58
+
59
+ let packageJson;
60
+ try { packageJson = createRequire(import.meta.url).resolve(name + "/package.json"); } catch { fail("PLATFORM_PACKAGE_MISSING"); }
61
+ const meta = JSON.parse(await fs.readFile(packageJson, "utf8"));
62
+ if (meta.name !== name || meta.version !== version) fail("PLATFORM_PACKAGE_MISMATCH");
63
+ const source = path.join(path.dirname(packageJson), "runtime");
64
+ const manifest = JSON.parse(await fs.readFile(path.join(source, "manifest.json"), "utf8"));
65
+ const files = Object.keys(manifest?.files ?? {});
66
+ if (manifest?.platform !== process.platform || manifest?.arch !== process.arch || !files.length || files.some(file => !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u.test(file))) fail("PLATFORM_PACKAGE_INVALID");
67
+
68
+ // Canonical parent: on macOS os.tmpdir() is under /var, a symlink to /private/var, and the lifecycle rejects aliases.
69
+ const stage = await fs.mkdtemp(path.join(await fs.realpath(os.tmpdir()), "local-commander-"));
70
+ try {
71
+ await fs.chmod(stage, 0o700);
72
+ for (const file of [...files, "manifest.json"]) {
73
+ const target = path.join(stage, file);
74
+ await fs.copyFile(path.join(source, file), target, constants.COPYFILE_EXCL);
75
+ await fs.chmod(target, EXECUTABLES.has(file) ? 0o700 : 0o600);
76
+ }
77
+ // The lifecycle verifies every file against the manifest, then copies them into its own versions directory.
78
+ const result = spawnSync(path.join(stage, "node"), [path.join(stage, "lifecycle.mjs"), lifecycle, ...args], { stdio: "inherit" });
79
+ if (result.error) throw result.error;
80
+ process.exitCode = result.status ?? 1;
81
+ } finally {
82
+ await fs.rm(stage, { recursive: true, force: true });
83
+ }
84
+ }
package/package.json CHANGED
@@ -1,57 +1,57 @@
1
- {
2
- "name": "local-commander-agent",
3
- "version": "0.3.53",
4
- "description": "Computer companion for Local Commander: connect AI clients to local files, approved commands and localhost. Requires https://localcmd.app.",
5
- "type": "module",
6
- "bin": {
7
- "localcommander": "bin/localcommander.mjs"
8
- },
9
- "os": [
10
- "win32",
11
- "darwin",
12
- "linux"
13
- ],
14
- "cpu": [
15
- "x64",
16
- "arm64"
17
- ],
18
- "optionalDependencies": {
19
- "local-commander-agent-darwin-arm64": "0.3.53",
20
- "local-commander-agent-linux-arm64": "0.3.53",
21
- "local-commander-agent-linux-x64": "0.3.53"
22
- },
23
- "engines": {
24
- "node": ">=20.0.0"
25
- },
26
- "files": [
27
- "bin/",
28
- "runtime/",
29
- "README.md",
30
- "CHANGELOG.md"
31
- ],
32
- "scripts": {
33
- "prepack": "node ../../scripts/build-npm-agent.mjs",
34
- "prepublishOnly": "node ../../scripts/check-npm-publish-auth.mjs && node ../../scripts/verify-npm-agent.mjs"
35
- },
36
- "publishConfig": {
37
- "access": "public"
38
- },
39
- "keywords": [
40
- "mcp",
41
- "local",
42
- "agent",
43
- "chatgpt",
44
- "claude",
45
- "windows",
46
- "macos",
47
- "linux"
48
- ],
49
- "localCommander": {
50
- "controlPlaneOrigin": "https://localcmd.app"
51
- },
52
- "homepage": "https://localcmd.app",
53
- "bugs": {
54
- "url": "https://localcmd.app/support",
55
- "email": "peter.mamrukov@localcmd.app"
56
- }
57
- }
1
+ {
2
+ "name": "local-commander-agent",
3
+ "version": "0.3.54",
4
+ "description": "Computer companion for Local Commander: connect AI clients to local files, approved commands and localhost. Requires https://localcmd.app.",
5
+ "type": "module",
6
+ "bin": {
7
+ "localcommander": "bin/localcommander.mjs"
8
+ },
9
+ "os": [
10
+ "win32",
11
+ "darwin",
12
+ "linux"
13
+ ],
14
+ "cpu": [
15
+ "x64",
16
+ "arm64"
17
+ ],
18
+ "optionalDependencies": {
19
+ "local-commander-agent-darwin-arm64": "0.3.54",
20
+ "local-commander-agent-linux-arm64": "0.3.54",
21
+ "local-commander-agent-linux-x64": "0.3.54"
22
+ },
23
+ "engines": {
24
+ "node": ">=20.0.0"
25
+ },
26
+ "files": [
27
+ "bin/",
28
+ "runtime/",
29
+ "README.md",
30
+ "CHANGELOG.md"
31
+ ],
32
+ "scripts": {
33
+ "prepack": "node ../../scripts/build-npm-agent.mjs",
34
+ "prepublishOnly": "node ../../scripts/check-npm-publish-auth.mjs && node ../../scripts/verify-npm-agent.mjs"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "keywords": [
40
+ "mcp",
41
+ "local",
42
+ "agent",
43
+ "chatgpt",
44
+ "claude",
45
+ "windows",
46
+ "macos",
47
+ "linux"
48
+ ],
49
+ "localCommander": {
50
+ "controlPlaneOrigin": "https://localcmd.app"
51
+ },
52
+ "homepage": "https://localcmd.app",
53
+ "bugs": {
54
+ "url": "https://localcmd.app/support",
55
+ "email": "peter.mamrukov@localcmd.app"
56
+ }
57
+ }
Binary file
Binary file
Binary file
package/runtime/agent.mjs CHANGED
@@ -27137,11 +27137,13 @@ var NativeJournal = class _NativeJournal {
27137
27137
  }
27138
27138
  /** The journal lock is only taken over once the previous agent process has exited, so its in-process work is gone.
27139
27139
  * An interrupted entry is AGENT_RESTARTED (stopped, outcome unknown) when it recorded its supervisors and none is
27140
- * still alive; otherwise, including every entry from an older agent, it stays EXECUTION_UNKNOWN (#194). */
27140
+ * still alive; otherwise, including every entry from an older agent, it stays EXECUTION_UNKNOWN (#194).
27141
+ * Previously reported unknown work gets the same proof check on a later startup, never on a mere reconnect. */
27141
27142
  recoverAfterRestart(liveness) {
27142
27143
  return this.enqueue(async () => {
27143
27144
  let count4 = 0;
27144
- const interrupted = [...this.entries.values()].filter((e) => ["accepted", "running"].includes(e.state));
27145
+ const retryUnknown = (e) => e.state === "unknown" && e.resultCode === "EXECUTION_UNKNOWN" && !!e.workspaceGrantId && !!e.policyVersion && e.supervisors !== void 0;
27146
+ const interrupted = [...this.entries.values()].filter((e) => ["accepted", "running"].includes(e.state) || retryUnknown(e));
27145
27147
  const pids = [...new Set(interrupted.flatMap((e) => e.supervisors ?? []))];
27146
27148
  const linuxSupervisors = interrupted.flatMap((e) => e.linuxSupervisors ?? []), darwinSupervisors = interrupted.flatMap((e) => e.darwinSupervisors ?? []);
27147
27149
  let live = /* @__PURE__ */ new Set();
@@ -27154,11 +27156,19 @@ var NativeJournal = class _NativeJournal {
27154
27156
  }
27155
27157
  for (const original of this.entries.values()) {
27156
27158
  const stranded = original.state === "prepared";
27157
- if (!stranded && !["accepted", "running"].includes(original.state)) continue;
27159
+ const retry = retryUnknown(original);
27160
+ if (!stranded && !["accepted", "running"].includes(original.state) && !retry) continue;
27158
27161
  const e = clone2(original);
27159
27162
  e.state = stranded ? "rejected" : "unknown";
27160
27163
  const stopped2 = !!e.supervisors && (e.supervisors.length === 0 || !!live && e.supervisors.every((pid) => !live.has(pid)));
27161
- if (!stranded && e.workspaceGrantId && e.policyVersion) e.resultCode = stopped2 ? "AGENT_RESTARTED" : "EXECUTION_UNKNOWN";
27164
+ if (retry && !stopped2) continue;
27165
+ if (!stranded && e.workspaceGrantId && e.policyVersion) {
27166
+ e.resultCode = stopped2 ? "AGENT_RESTARTED" : "EXECUTION_UNKNOWN";
27167
+ if (stopped2) {
27168
+ delete e.reportedAt;
27169
+ if (e.result) e.result = { ...e.result, treeTerminated: true };
27170
+ }
27171
+ }
27162
27172
  e.updatedAt = this.now().toISOString();
27163
27173
  const last = e.guardEvents?.at(-1);
27164
27174
  if (last && last.event.phase !== "result") {
@@ -29233,6 +29243,27 @@ async function resolvePosixExecutable(command, searchPath = process.env.PATH ??
29233
29243
  // agent/src/job-supervisor.ts
29234
29244
  import { spawn as spawn4 } from "node:child_process";
29235
29245
  import path16 from "node:path";
29246
+ var supervisorFailureCodes = /* @__PURE__ */ new Set([
29247
+ "SUPERVISOR_PLATFORM_UNSUPPORTED",
29248
+ "INVALID_SUPERVISOR_PATH",
29249
+ "INVALID_SUPERVISOR_ARGS",
29250
+ "INVALID_SUPERVISOR_LIMIT",
29251
+ "SUPERVISOR_INPUT_LIMIT",
29252
+ "SUPERVISOR_CONTROL_CLOSED",
29253
+ "SUPERVISOR_START_FAILED",
29254
+ "SUPERVISOR_DIAGNOSTIC_FAILURE",
29255
+ "SUPERVISOR_PROTOCOL_INVALID",
29256
+ "SUPERVISOR_PROTOCOL_LIMIT",
29257
+ "SUPERVISOR_EXECUTION_UNKNOWN",
29258
+ "SUPERVISOR_DEADLINE_EXCEEDED"
29259
+ ]);
29260
+ var nativeFailureCode = /^(WIN32_[0-9]{1,10}|EXECUTION_OUTCOME_UNKNOWN|INVALID_OR_FAILED_START)$/;
29261
+ function supervisorFailureDiagnostic(error62) {
29262
+ if (!(error62 instanceof Error) || !supervisorFailureCodes.has(error62.message)) return null;
29263
+ const stage = typeof error62.cause === "string" && /^(REQUEST|BRIDGE|CGROUP|EXECUTION|CLEANUP)$/.test(error62.cause) ? error62.cause : void 0;
29264
+ const nativeCode = typeof error62.cause === "string" && nativeFailureCode.test(error62.cause) ? error62.cause : void 0;
29265
+ return { code: error62.message, ...stage ? { stage } : {}, ...nativeCode ? { nativeCode } : {} };
29266
+ }
29236
29267
  function absolute(value) {
29237
29268
  return typeof value === "string" && value.length > 0 && value.length < 32767 && !value.includes("\0") && path16.isAbsolute(value) && path16.resolve(value) === value;
29238
29269
  }
@@ -29316,7 +29347,7 @@ async function runSupervised(helper, request, options = {}) {
29316
29347
  if (pid === null || !Number.isInteger(m.exitCode) || typeof m.timedOut !== "boolean" || typeof m.cancelled !== "boolean" || m.treeTerminated !== true) throw Error();
29317
29348
  outcome = { exitCode: m.exitCode, timedOut: m.timedOut, cancelled: m.cancelled, treeTerminated: true };
29318
29349
  } else if (m.type === "error") {
29319
- fail7("SUPERVISOR_EXECUTION_UNKNOWN", typeof m.stage === "string" && /^(REQUEST|BRIDGE|CGROUP|EXECUTION|CLEANUP)$/.test(m.stage) ? m.stage : void 0);
29350
+ fail7("SUPERVISOR_EXECUTION_UNKNOWN", typeof m.stage === "string" && /^(REQUEST|BRIDGE|CGROUP|EXECUTION|CLEANUP)$/.test(m.stage) ? m.stage : typeof m.code === "string" && nativeFailureCode.test(m.code) ? m.code : void 0);
29320
29351
  return;
29321
29352
  } else throw Error();
29322
29353
  } catch {
@@ -32273,7 +32304,7 @@ var NativeRuntime = class {
32273
32304
  if (!stored.created) {
32274
32305
  if (!journalBinding(stored.entry, binding2)) throw Error("IDEMPOTENCY_CONFLICT");
32275
32306
  if (stored.entry.result) {
32276
- this.send({ type: "result", version: 1, binding: binding2, result: await outboundResult(frame.tool, journalResult(stored.entry.result), binding2, this.optionalTelemetry, this.options.efficiencyLedger) });
32307
+ this.send({ type: "result", version: 1, binding: binding2, result: await outboundResult(frame.tool, journalResult(stored.entry.result, stored.entry.resultCode), binding2, this.optionalTelemetry, this.options.efficiencyLedger) });
32277
32308
  return;
32278
32309
  }
32279
32310
  if (stored.entry.state === "prepared") {
@@ -32372,6 +32403,8 @@ var NativeRuntime = class {
32372
32403
  } else {
32373
32404
  const isCommand = frame.tool.name === "command_run" || frame.tool.name.startsWith("git_") || frame.tool.name === "project_snapshot";
32374
32405
  const uncertain = error62 instanceof Error && error62.message === "GUARD_EVIDENCE_FAILED" || isCommand && !(error62 instanceof NativeToolError);
32406
+ const supervisorFailure = supervisorFailureDiagnostic(error62);
32407
+ if (supervisorFailure) context.stderr.append("\n" + JSON.stringify({ supervisorFailure }) + "\n");
32375
32408
  const output2 = { exitCode: null, timedOut: false, cancelled: abort.signal.aborted, treeTerminated: !uncertain, stdout: context.stdout.toString(), stderr: context.stderr.toString(), stdoutTruncated: context.stdout.truncated, stderrTruncated: context.stderr.truncated, resultCode: uncertain ? "EXECUTION_UNKNOWN" : abort.signal.aborted ? "CANCELLED" : safeCode(error62) };
32376
32409
  try {
32377
32410
  const { resultCode, ...raw } = output2;
@@ -32412,7 +32445,7 @@ var NativeRuntime = class {
32412
32445
  const fresh = await this.options.journal.get(binding2.executionId);
32413
32446
  let result2;
32414
32447
  if (fresh?.result) {
32415
- result2 = this.completedResults.get(binding2.executionId) ?? (context ? await outboundResult(context.tool.call, journalResult(fresh.result), binding2, this.optionalTelemetry, this.options.efficiencyLedger) : journalResult(fresh.result));
32448
+ result2 = this.completedResults.get(binding2.executionId) ?? (context ? await outboundResult(context.tool.call, journalResult(fresh.result, fresh.resultCode), binding2, this.optionalTelemetry, this.options.efficiencyLedger) : journalResult(fresh.result, fresh.resultCode));
32416
32449
  if (frame.action === "output" && this.options.efficiencyLedger) {
32417
32450
  const notice = await this.optionalTelemetry.run(() => this.options.efficiencyLedger.consumeNoticeForExecution?.(binding2.executionId), null);
32418
32451
  if (notice) result2 = { ...result2, efficiencyNotice: notice };
@@ -51358,7 +51391,7 @@ async function restoreContentAudit(input2, output2, key) {
51358
51391
  }
51359
51392
 
51360
51393
  // agent/src/main.ts
51361
- var AGENT_VERSION2 = true ? "0.3.53" : "0.3.2";
51394
+ var AGENT_VERSION2 = true ? "0.3.54" : "0.3.2";
51362
51395
  var NETWORK_PUBLIC_KEY = true ? "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAvmu+81vWtJBQDZNHcAIW\nzCSxpG+R9RBsum2df5mP2cOW+wyUDTpnYquFge1qgI5YYTF96j0xCyXL8B9FeNWs\n939opWNmv53j+CQlS4cEIQhBbZSCu0eC4icsVEzBhvf68MB+E668SOtZBcVTEnyh\n96PTcupxS10rQJBWDinbKBXRC2gvGYeu01rWa/nsrndy4vAYP5t3yQtdOC8e8mr0\n+2Mg2Qhiq+KiTCtDd+L9oXvoLqqJYbzUIveNGha25AWxF1Weblp0gOM87hell5gV\nK7q4ZLUq/wBRGYNmQRdLyV7/WRE1FFPSW21/SBZQ/5aU4UqJU/MjMcrJUrnRKngz\nYKmo0czkxS3N7Q2KVxomgR1AQSuQFKMrboZYKjShADp9RIYUxzs7cYg51Of5PnHh\n6Ax+VevDGfzjMD+yHuyxYZqCtX4OwgolJxz63UQbzKlris+8xb5lLYTbIuz90Pss\nn6HK/F5May25c6oMmS3nh/NsiZopL1OvdtWKTt1L4WlRAgMBAAE=\n-----END PUBLIC KEY-----\n" : "";
51363
51396
  var AI_CONNECTION_SHIPPED = false;
51364
51397
  var QUARANTINE_RETRY_MS = 6e4;