local-commander-agent 0.3.46 → 0.3.47
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 +7 -0
- package/bin/localcommander.mjs +17 -0
- package/bin/posix.mjs +18 -0
- package/package.json +4 -4
- package/runtime/JobHost.exe +0 -0
- package/runtime/LocalCommanderAgent.exe +0 -0
- package/runtime/OwnerBridge.exe +0 -0
- package/runtime/agent.mjs +1315 -120
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Change history
|
|
2
2
|
|
|
3
|
+
## 0.3.47 - 2026-10-22
|
|
4
|
+
|
|
5
|
+
- New: screenshots on Linux. Where the screenshot tool is available to your account and the computer has Full Access, it now also works on a Linux desktop (Wayland through the desktop portal or grim, X11 through xwd, import or maim). When capture is not possible the client gets a clear reason, such as no desktop session or no capture tool.
|
|
6
|
+
- New: you can turn screenshots off for this computer. Run `localcommander screenshot off` on Windows, or `npx local-commander-agent screenshot off` on macOS and Linux; `screenshot on` turns them back on and `screenshot status` shows the current setting. No restart is needed.
|
|
7
|
+
- The cabinet now shows whether each computer has Full Access or selected folders only.
|
|
8
|
+
- Includes everything in 0.3.46.
|
|
9
|
+
|
|
3
10
|
## 0.3.46 - 2026-10-22
|
|
4
11
|
|
|
5
12
|
- Simpler setup on macOS and Linux: the approval page opens in your browser by itself, and on a Mac access is one click in a window (Full Access, or Choose Folder). Linux asks one question in the terminal: press Enter for Full Access or type a folder.
|
package/bin/localcommander.mjs
CHANGED
|
@@ -316,6 +316,19 @@ async function auditCommand(runtimeDir, sub) {
|
|
|
316
316
|
}
|
|
317
317
|
fail("ARGUMENT_INVALID");
|
|
318
318
|
}
|
|
319
|
+
// Owner opt-out for take_screenshot under Full Access (#486), on by default. Only this owner-run command changes it (the agent
|
|
320
|
+
// state folder is protected from every file tool); the agent checks it on each capture, so no restart is needed.
|
|
321
|
+
const SCREENSHOT_OFF_FILE = "screenshot-disabled-by-owner";
|
|
322
|
+
async function screenshotCommand(args) {
|
|
323
|
+
const action = args[0] || "status";
|
|
324
|
+
if (args.length > 1 || !["status", "on", "off"].includes(action)) fail("ARGUMENT_INVALID");
|
|
325
|
+
if (!(await readCurrent())) fail("AGENT_NOT_INSTALLED");
|
|
326
|
+
const file = path.join(stateDirectory(), SCREENSHOT_OFF_FILE);
|
|
327
|
+
if (action === "off") await fs.writeFile(file, "", { flag: "wx" }).catch(error => { if (error?.code !== "EEXIST") throw error; });
|
|
328
|
+
if (action === "on") await fs.rm(file, { force: true });
|
|
329
|
+
const off = await fs.lstat(file).then(() => true, error => error?.code !== "ENOENT");
|
|
330
|
+
process.stdout.write(JSON.stringify({ screenshot: off ? "off" : "on" }) + "\n");
|
|
331
|
+
}
|
|
319
332
|
// Public AI-provider domains routed through the tunnel; everything else stays direct. Mirror of
|
|
320
333
|
// packages/connectivity/src/profiles.ts (stable public suffixes).
|
|
321
334
|
const PROXY_PROVIDERS = {
|
|
@@ -793,6 +806,10 @@ async function main() {
|
|
|
793
806
|
if (action === "setup") await restartIfRunning();
|
|
794
807
|
return;
|
|
795
808
|
}
|
|
809
|
+
if (command === "screenshot") {
|
|
810
|
+
await screenshotCommand(args);
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
796
813
|
if (command === "audit") {
|
|
797
814
|
const current = await readCurrent(); if (!current) fail("AGENT_NOT_INSTALLED");
|
|
798
815
|
await auditCommand(current.runtimeDir, args);
|
package/bin/posix.mjs
CHANGED
|
@@ -28,11 +28,29 @@ export function posixHelp() {
|
|
|
28
28
|
].join("\n");
|
|
29
29
|
}
|
|
30
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
|
+
|
|
31
48
|
export async function runPosix(argv, version) {
|
|
32
49
|
const name = PACKAGES[process.platform + "-" + process.arch];
|
|
33
50
|
if (!name) fail(process.platform === "darwin" ? "MACOS_APPLE_SILICON_REQUIRED" : process.platform === "linux" ? "LINUX_X64_OR_ARM64_REQUIRED" : "PLATFORM_UNSUPPORTED");
|
|
34
51
|
const command = argv[0] || "bootstrap", args = argv.slice(1);
|
|
35
52
|
if (command === "-h" || command === "--help" || command === "help") { process.stdout.write(posixHelp()); return; }
|
|
53
|
+
if (command === "screenshot") { await screenshotCommand(args); return; }
|
|
36
54
|
const lifecycle = COMMANDS[command];
|
|
37
55
|
if (!lifecycle) fail("ARGUMENT_INVALID");
|
|
38
56
|
if (lifecycle === "uninstall" ? args.length > 1 || (args.length === 1 && args[0] !== "--purge-state") : args.length) fail("ARGUMENT_INVALID");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-commander-agent",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.47",
|
|
4
4
|
"description": "Computer companion for Local Commander: connect AI clients to local files, approved commands and localhost. Requires https://localcmd.app.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"arm64"
|
|
17
17
|
],
|
|
18
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.
|
|
19
|
+
"local-commander-agent-darwin-arm64": "0.3.47",
|
|
20
|
+
"local-commander-agent-linux-arm64": "0.3.47",
|
|
21
|
+
"local-commander-agent-linux-x64": "0.3.47"
|
|
22
22
|
},
|
|
23
23
|
"engines": {
|
|
24
24
|
"node": ">=20.0.0"
|
package/runtime/JobHost.exe
CHANGED
|
Binary file
|
|
Binary file
|
package/runtime/OwnerBridge.exe
CHANGED
|
Binary file
|