local-commander-agent 0.3.52 → 0.3.53
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.
- package/CHANGELOG.md +239 -234
- package/README.md +216 -216
- package/bin/command-path.mjs +223 -223
- package/bin/localcommander.mjs +874 -874
- package/bin/monitor-agents.mjs +162 -162
- package/bin/monitor-context.d.mts +7 -7
- package/bin/monitor-context.mjs +65 -65
- package/bin/monitor-mcp.mjs +136 -136
- package/bin/monitor-savings.d.mts +20 -20
- package/bin/monitor-savings.mjs +71 -71
- package/bin/monitor.mjs +530 -530
- package/bin/network-package.mjs +38 -38
- package/bin/posix.mjs +84 -84
- package/package.json +57 -57
- package/runtime/JobHost.exe +0 -0
- package/runtime/LocalCommanderAgent.exe +0 -0
- package/runtime/OwnerBridge.exe +0 -0
- package/runtime/agent.mjs +147 -147
package/bin/network-package.mjs
CHANGED
|
@@ -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.
|
|
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.
|
|
20
|
-
"local-commander-agent-linux-arm64": "0.3.
|
|
21
|
-
"local-commander-agent-linux-x64": "0.3.
|
|
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.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
|
+
}
|
package/runtime/JobHost.exe
CHANGED
|
Binary file
|
|
Binary file
|
package/runtime/OwnerBridge.exe
CHANGED
|
Binary file
|