@scopebond/agent 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/allowance-sender.js +10 -4
- package/dist/allowance-sender.js.map +1 -1
- package/dist/autostart.js +1 -1
- package/dist/autostart.js.map +1 -1
- package/dist/ipc.d.ts +3 -2
- package/dist/ipc.d.ts.map +1 -1
- package/dist/ipc.js +4 -2
- package/dist/ipc.js.map +1 -1
- package/dist/log-file.js.map +1 -1
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +1 -0
- package/dist/prompt.js.map +1 -1
- package/dist/selfcheck.js.map +1 -1
- package/dist/setup.js +1 -1
- package/dist/setup.js.map +1 -1
- package/package.json +4 -4
package/dist/allowance-sender.js
CHANGED
|
@@ -37,7 +37,7 @@ export async function sendAllowancesAndRequests(dir, connection, fetchImpl = fet
|
|
|
37
37
|
for (const a of readAllowances(dir)) {
|
|
38
38
|
if (a.created_by !== "person" || a.sent_at)
|
|
39
39
|
continue;
|
|
40
|
-
const
|
|
40
|
+
const record = without(a, "sent_at", "uses");
|
|
41
41
|
const outcome = await post("/v1/allowances", record, ALLOWANCE_DOMAIN);
|
|
42
42
|
if (outcome !== "later")
|
|
43
43
|
allowanceOutcomes.set(a.id, outcome);
|
|
@@ -50,8 +50,7 @@ export async function sendAllowancesAndRequests(dir, connection, fetchImpl = fet
|
|
|
50
50
|
return a;
|
|
51
51
|
if (outcome === "sent") {
|
|
52
52
|
sent.allowances += 1;
|
|
53
|
-
|
|
54
|
-
return { ...rest, sent_at: at };
|
|
53
|
+
return { ...without(a, "reason"), sent_at: at };
|
|
55
54
|
} // the workspace keeps the text
|
|
56
55
|
return { ...a, sent_at: at };
|
|
57
56
|
}), now);
|
|
@@ -60,7 +59,7 @@ export async function sendAllowancesAndRequests(dir, connection, fetchImpl = fet
|
|
|
60
59
|
for (const r of readRequests(dir)) {
|
|
61
60
|
if (r.sent_at)
|
|
62
61
|
continue;
|
|
63
|
-
const
|
|
62
|
+
const record = without(r, "sent_at");
|
|
64
63
|
const outcome = await post("/v1/requests", record, REQUEST_DOMAIN);
|
|
65
64
|
if (outcome !== "later")
|
|
66
65
|
requestOutcomes.set(r.id, outcome);
|
|
@@ -77,4 +76,11 @@ export async function sendAllowancesAndRequests(dir, connection, fetchImpl = fet
|
|
|
77
76
|
}
|
|
78
77
|
return sent;
|
|
79
78
|
}
|
|
79
|
+
/** A copy of `value` without the named fields. */
|
|
80
|
+
function without(value, ...keys) {
|
|
81
|
+
const copy = { ...value };
|
|
82
|
+
for (const key of keys)
|
|
83
|
+
delete copy[key];
|
|
84
|
+
return copy;
|
|
85
|
+
}
|
|
80
86
|
//# sourceMappingURL=allowance-sender.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"allowance-sender.js","sourceRoot":"","sources":["../src/allowance-sender.ts"],"names":[],"mappings":"AAAA,4HAA4H;AAC5H,2HAA2H;AAC3H,yHAAyH;AACzH,6HAA6H;AAC7H,6HAA6H;AAC7H,6HAA6H;AAE7H,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAuB,MAAM,iBAAiB,CAAC;AAEpH,MAAM,CAAC,MAAM,gBAAgB,GAAG,0BAA0B,CAAC;AAC3D,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,GAAW,EAAE,UAAsD,EAAE,YAA0B,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACpK,MAAM,IAAI,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,gEAAgE;IACvG,MAAM,EAAE,QAAQ,EAAE,GAAG,oBAAoB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,KAAK,EAAE,IAAY,EAAE,MAA+B,EAAE,MAAc,EAAyC,EAAE;QAC1H,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YACvG,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;gBACpE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;gBACtE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,UAAU,CAAC,UAAU,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC9H,CAAC,CAAC;YACH,IAAI,GAAG,CAAC,EAAE;gBAAE,OAAO,MAAM,CAAC;YAC1B,OAAO,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;QACxE,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,OAAO,CAAC;QAAC,CAAC;IAC7B,CAAC,CAAC;IAEF,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAA8B,CAAC;IAChE,KAAK,MAAM,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC,CAAC,UAAU,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO;YAAE,SAAS;QACrD,MAAM,
|
|
1
|
+
{"version":3,"file":"allowance-sender.js","sourceRoot":"","sources":["../src/allowance-sender.ts"],"names":[],"mappings":"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","sourcesContent":["// D144 (SB411): the agent tells the workspace about allowances a person made on this computer and the requests they sent to\n// an admin. Each record is signed by the key this computer enrolled with (the same key that countersigns its receipts), so\n// the workspace can show it was made here. Sent once; one the workspace refuses for good (400) is not sent again; one it\n// could not take (offline, 5xx) waits for the next cycle. A workspace without these calls (404) leaves them on the computer.\n// Each signature covers a domain line and the canonical record, so neither can pass as a receipt signed by the same key. The\n// files are re-read before each write and only what this send changed is applied, so a hook writing meanwhile loses nothing.\n\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { canonical } from \"@scopebond/gateway\";\nimport { loadOrCreateAttester } from \"@scopebond/gateway/node\";\nimport { readAllowances, readRequests, writeAllowances, writeRequests, type HookConnection } from \"@scopebond/hook\";\n\nexport const ALLOWANCE_DOMAIN = \"scopebond:allowance/v1\\n\";\nexport const REQUEST_DOMAIN = \"scopebond:request/v1\\n\";\n\nexport async function sendAllowancesAndRequests(dir: string, connection: Pick<HookConnection, \"url\" | \"credential\">, fetchImpl: typeof fetch = fetch, now = Date.now()): Promise<{ allowances: number; requests: number }> {\n const sent = { allowances: 0, requests: 0 };\n const keyFile = join(dir, \"attester.key\");\n if (!existsSync(keyFile)) return sent; // never makes a key: an unenrolled computer has nothing to send\n const { attester } = loadOrCreateAttester({ file: keyFile });\n const post = async (path: string, record: Record<string, unknown>, domain: string): Promise<\"sent\" | \"refused\" | \"later\"> => {\n try {\n const body = { record, kid: attester.kid, signature: await attester.sign(domain + canonical(record)) };\n const res = await fetchImpl(new URL(path, connection.url).toString(), {\n method: \"POST\", redirect: \"error\", signal: AbortSignal.timeout(10_000),\n headers: { authorization: `Bearer ${connection.credential}`, \"content-type\": \"application/json\" }, body: JSON.stringify(body),\n });\n if (res.ok) return \"sent\";\n return res.status === 400 || res.status === 409 ? \"refused\" : \"later\";\n } catch { return \"later\"; }\n };\n\n const at = new Date(now).toISOString();\n const allowanceOutcomes = new Map<string, \"sent\" | \"refused\">();\n for (const a of readAllowances(dir)) {\n if (a.created_by !== \"person\" || a.sent_at) continue;\n const record = without(a, \"sent_at\", \"uses\");\n const outcome = await post(\"/v1/allowances\", record, ALLOWANCE_DOMAIN);\n if (outcome !== \"later\") allowanceOutcomes.set(a.id, outcome);\n }\n if (allowanceOutcomes.size) {\n // Applied to the file as it is now (the hook may have counted a use or added an allowance while this was sending).\n writeAllowances(dir, readAllowances(dir).map((a) => {\n const outcome = allowanceOutcomes.get(a.id);\n if (!outcome || a.sent_at) return a;\n if (outcome === \"sent\") { sent.allowances += 1; return { ...without(a, \"reason\"), sent_at: at }; } // the workspace keeps the text\n return { ...a, sent_at: at };\n }), now);\n }\n\n const requestOutcomes = new Map<string, \"sent\" | \"refused\">();\n for (const r of readRequests(dir)) {\n if (r.sent_at) continue;\n const record = without(r, \"sent_at\");\n const outcome = await post(\"/v1/requests\", record, REQUEST_DOMAIN);\n if (outcome !== \"later\") requestOutcomes.set(r.id, outcome);\n }\n if (requestOutcomes.size) {\n writeRequests(dir, readRequests(dir).map((r) => {\n const outcome = requestOutcomes.get(r.id);\n if (!outcome || r.sent_at) return r;\n if (outcome === \"sent\") sent.requests += 1;\n return { ...r, sent_at: at };\n }), now);\n }\n return sent;\n}\n\n/** A copy of `value` without the named fields. */\nfunction without<T extends object, K extends keyof T>(value: T, ...keys: K[]): Omit<T, K> {\n const copy = { ...value };\n for (const key of keys) delete copy[key];\n return copy;\n}\n"]}
|
package/dist/autostart.js
CHANGED
|
@@ -312,7 +312,7 @@ export function autostartHealth(scopebondHome, platform = process.platform, tray
|
|
|
312
312
|
: { on, ok: false, detail: "the Scopebond tray does not start with sign-in (turn on Start with Windows in its menu, or run: scopebond-agent.exe autostart on)" };
|
|
313
313
|
}
|
|
314
314
|
const paths = autostartPaths();
|
|
315
|
-
let on
|
|
315
|
+
let on;
|
|
316
316
|
if (platform === "win32") {
|
|
317
317
|
try {
|
|
318
318
|
execFileSync("reg", ["query", RUN_KEY, "/v", RUN_VALUE], { stdio: "ignore" });
|
package/dist/autostart.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autostart.js","sourceRoot":"","sources":["../src/autostart.ts"],"names":[],"mappings":"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","sourcesContent":["// Start the agent when the person signs in to the computer, per user, with no administrator\n// rights: a Run entry on Windows, a LaunchAgent on macOS, a systemd user unit on Linux.\n//\n// Each of them starts a small launcher script in the Scopebond home, not Node directly. The\n// launcher finds Node and the agent when it runs (the recorded paths first, then the system's),\n// so upgrading Node or switching versions never leaves an autostart entry pointing at nothing.\n// On Windows it runs under `conhost --headless`, so no window opens at sign-in.\n\nimport { execFileSync, spawn } from \"node:child_process\";\nimport { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, win32 } from \"node:path\";\nimport { isSingleExecutable } from \"@scopebond/hook\";\nimport { nativeTrayPath } from \"./native-update.js\";\n\nexport const LABEL = \"com.scopebond.agent\";\nconst RUN_KEY = \"HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\";\nconst RUN_VALUE = \"ScopebondAgent\";\n\nconst xml = (s: string) => s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\nconst noQuotes = (s: string) => s.replace(/\"/g, \"\");\n\n/** The agent's log, which the agent writes itself (`SCOPEBOND_AGENT_LOG`) when a Windows launcher or a handover starts it. */\nexport const AGENT_LOG_ENV = \"SCOPEBOND_AGENT_LOG\";\n\n/** Written into every Windows launcher this version makes. A launcher without it redirects the agent's output into\n * agent.log itself, which keeps a replacement agent from starting (see `spawnReplacement`). */\nexport const LAUNCHER_MARK = \"rem Scopebond Agent launcher 2:\";\n\n/** Whether a launcher's text is this version's (an older one is rewritten once no agent runs under it). */\nexport function launcherIsCurrent(text: string, platform: NodeJS.Platform = process.platform): boolean {\n return platform !== \"win32\" || text.includes(LAUNCHER_MARK);\n}\n\nexport function launcherPath(home: string, platform: NodeJS.Platform = process.platform): string {\n return join(home, platform === \"win32\" ? \"agent-launch.cmd\" : \"agent-launch.sh\");\n}\n\n/** The Windows launcher. With `cli` empty, `node` is the single executable: it is started as it is, with no Node to find. */\nexport function windowsLauncher(node: string, cli: string, logFile: string): string {\n const log = `\"%~dp0${win32.basename(noQuotes(logFile))}\"`;\n const single = cli === \"\";\n return [\n \"@echo off\",\n // cmd.exe reads a batch file in the console code page: switch to UTF-8 first, so a profile folder\n // with non-ASCII letters in the paths below reads as written.\n \"chcp 65001 >nul\",\n `${LAUNCHER_MARK} finds Node and the agent each time, so a Node upgrade never stops it.`,\n \"setlocal\",\n // The agent writes its own log. A `>> agent.log` here would hold the file shared for reading only, the old agent's\n // children inherit that handle, and a replacement started during an update could then never open it: cmd skips the\n // whole command line when a redirect fails. The log sits beside this launcher; %~dp0 keeps it right whatever the folder is called.\n `set \"${AGENT_LOG_ENV}=%~dp0${win32.basename(noQuotes(logFile))}\"`,\n `set \"NODE=${noQuotes(node)}\"`,\n ...(single ? [`if not exist \"%NODE%\" exit /b 1`] : [\n `if not exist \"%NODE%\" set \"NODE=\"`,\n `if not defined NODE for /f \"delims=\" %%i in ('where node 2^>nul') do if not defined NODE set \"NODE=%%i\"`,\n `set \"CLI=${noQuotes(cli)}\"`,\n `if not exist \"%CLI%\" for /f \"delims=\" %%i in ('npm.cmd root -g 2^>nul') do set \"CLI=%%i\\\\@scopebond\\\\agent\\\\dist\\\\cli.js\"`,\n `if not defined NODE exit /b 1`,\n ]),\n // Restart on failure, as launchd (KeepAlive) and systemd (Restart=on-failure) do: a crash restarts the agent after\n // 30 seconds, up to 50 times; a clean exit (stop, autostart off, an update handing over) ends the launcher.\n \"set /a TRIES=0\",\n \":run\",\n // (call) sets the error level to 1 first, so a command that never ran counts as a failure, not a clean stop.\n \"(call)\",\n single ? `\"%NODE%\" run >nul 2>&1` : `\"%NODE%\" --disable-warning=ExperimentalWarning \"%CLI%\" run >nul 2>&1`,\n `set \"CODE=%ERRORLEVEL%\"`,\n // An update's handover names the agent to wait for; a restart after a crash has nothing to wait for.\n `set \"SCOPEBOND_AGENT_AFTER_PID=\"`,\n \"if %CODE% EQU 0 exit /b 0\",\n \"set /a TRIES+=1\",\n `echo %DATE% %TIME% the agent stopped with exit code %CODE%; restarting in 30 seconds (attempt %TRIES% of 50) >> ${log}`,\n \"if %TRIES% GEQ 50 exit /b 1\",\n // ping waits without a console to read from (timeout.exe refuses to run under a headless console).\n \"ping -n 31 127.0.0.1 >nul\",\n \"goto run\",\n \"\",\n ].join(\"\\r\\n\");\n}\n\n/** The macOS/Linux launcher. With `cli` empty, `node` is the single executable, started as it is. */\nexport function posixLauncher(node: string, cli: string): string {\n const q = (s: string) => `'${s.replace(/'/g, \"'\\\\''\")}'`;\n if (cli === \"\") return `#!/bin/sh\n# Scopebond Agent launcher: the single executable.\nexec ${q(node)} run\n`;\n return `#!/bin/sh\n# Scopebond Agent launcher: finds Node and the agent each time, so a Node upgrade never stops it.\nNODE=${q(node)}\nif [ ! -x \"$NODE\" ]; then\n [ -s \"$HOME/.nvm/nvm.sh\" ] && . \"$HOME/.nvm/nvm.sh\" >/dev/null 2>&1\n NODE=\"$(command -v node 2>/dev/null)\"\n for candidate in /opt/homebrew/bin/node /usr/local/bin/node /usr/bin/node; do\n [ -n \"$NODE\" ] && break\n [ -x \"$candidate\" ] && NODE=\"$candidate\"\n done\nfi\nCLI=${q(cli)}\n[ -f \"$CLI\" ] || CLI=\"$(npm root -g 2>/dev/null)/@scopebond/agent/dist/cli.js\"\n[ -n \"$NODE\" ] || exit 1\nexec \"$NODE\" --disable-warning=ExperimentalWarning \"$CLI\" run\n`;\n}\n\n/** The Run value: the launcher under a headless console host, so nothing appears on screen. */\n/** `cmd /s /c \"\"<launcher>\"\"`: cmd drops only the outer quotes and runs the quoted path as it is, so a\n * profile folder with a space and a `(`, `)` or `&` (\"John (Work)\") still starts the launcher. */\nconst cmdRun = (launcher: string) => `/d /s /c \"\"${noQuotes(launcher)}\"\"`;\n\nexport function windowsRunCommand(launcher: string): string {\n return `conhost.exe --headless cmd.exe ${cmdRun(launcher)}`;\n}\n\nexport function macLaunchAgent(launcher: string, logFile: string): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key><string>${LABEL}</string>\n <key>ProgramArguments</key>\n <array><string>/bin/sh</string><string>${xml(launcher)}</string></array>\n <key>RunAtLoad</key><true/>\n <key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>\n <key>StandardOutPath</key><string>${xml(logFile)}</string>\n <key>StandardErrorPath</key><string>${xml(logFile)}</string>\n</dict>\n</plist>\n`;\n}\n\nexport function linuxUserUnit(launcher: string): string {\n const q = (s: string) => `\"${s.replace(/([\"\\\\])/g, \"\\\\$1\")}\"`;\n return `[Unit]\nDescription=Scopebond Agent (delivers this computer's records to its Scopebond workspace)\nAfter=network-online.target\n\n[Service]\nExecStart=/bin/sh ${q(launcher)}\nRestart=on-failure\nRestartSec=30\n\n[Install]\nWantedBy=default.target\n`;\n}\n\nexport function autostartPaths(home = homedir()) {\n return {\n macPlist: join(home, \"Library\", \"LaunchAgents\", `${LABEL}.plist`),\n linuxUnit: join(home, \".config\", \"systemd\", \"user\", \"scopebond-agent.service\"),\n };\n}\n\n/** Rewrite an older Windows launcher as this version's, keeping autostart as it is. Only safe once no cmd.exe runs the old\n * one (cmd reads a batch file line by line from where it left off): the handover calls it after the old agent has exited.\n * Returns whether it rewrote one. */\nexport function refreshLauncher(scopebondHome: string, cli: string, node = process.execPath, platform = process.platform): boolean {\n const launcher = launcherPath(scopebondHome, platform);\n let text: string;\n try { text = readFileSync(launcher, \"utf8\"); } catch { return false; }\n if (launcherIsCurrent(text, platform)) return false;\n writeLauncher(scopebondHome, node, cli, platform);\n return true;\n}\n\nfunction writeLauncher(scopebondHome: string, node: string, cli: string, platform: NodeJS.Platform): string {\n // The single executable is both Node and the agent: the launcher starts it with `run`.\n if (isSingleExecutable()) { node = process.execPath; cli = \"\"; }\n mkdirSync(scopebondHome, { recursive: true });\n const launcher = launcherPath(scopebondHome, platform);\n const log = join(scopebondHome, \"agent.log\");\n writeFileSync(launcher, platform === \"win32\" ? windowsLauncher(node, cli, log) : posixLauncher(node, cli), { mode: 0o700 });\n if (platform !== \"win32\") chmodSync(launcher, 0o700);\n return launcher;\n}\n\n/** The ways to start the agent now on Windows, in order: the launcher under a headless console (no window,\n * as sign-in does), then the launcher through cmd.exe with its window hidden, for a session where the\n * headless console host does not start (seen on Windows Server). macOS and Linux start it themselves\n * when autostart is turned on (RunAtLoad, enable --now). */\nexport function startCommands(launcher: string, platform: NodeJS.Platform = process.platform): Array<[string, string[]]> {\n if (platform !== \"win32\") return [];\n // Passed verbatim (startNow sets windowsVerbatimArguments): Node's own quoting follows other rules than cmd's.\n return [[\"conhost.exe\", [\"--headless\", \"cmd.exe\", cmdRun(launcher)]], [\"cmd.exe\", [cmdRun(launcher)]]];\n}\n\n// The signed Windows install with its native tray (`scopebond-tray.exe` beside the agent): the installer adds a Run value\n// `Scopebond` that starts the tray, and the tray starts the agent and keeps it running. Autostart then means that value,\n// not the launcher's `ScopebondAgent`, which would start a second agent (refused by its lock) at every sign-in.\n\n/** Runs `reg.exe` with these arguments; whether it succeeded. Tests pass their own. */\nexport type RegRunner = (args: string[]) => boolean;\nconst runReg: RegRunner = (args) => {\n try { execFileSync(\"reg\", args, { stdio: \"ignore\", windowsHide: true }); return true; } catch { return false; }\n};\nexport const TRAY_RUN_VALUE = \"Scopebond\";\nconst MACHINE_RUN_KEY = \"HKLM\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\";\nconst trayFor = (platform: NodeJS.Platform) => (platform === \"win32\" ? nativeTrayPath() : null);\n/** The tray's Run value set for every user (an install with ALLUSERS=1): only whoever installed it changes it. */\nconst trayForEveryone = (reg: RegRunner) => reg([\"query\", MACHINE_RUN_KEY, \"/v\", TRAY_RUN_VALUE]);\n\n/** The launcher's Run value is not used beside the native tray. Whether there was one to remove. */\nexport function retireLauncherRunValue(reg: RegRunner = runReg): boolean {\n return reg([\"query\", RUN_KEY, \"/v\", RUN_VALUE]) && reg([\"delete\", RUN_KEY, \"/v\", RUN_VALUE, \"/f\"]);\n}\n\n/** Start the agent now with the `attempt`-th way (0 first), detached from this terminal. Returns whether it tried one.\n * Beside the native tray, the one way is to start the tray (it starts the agent; a second tray gives way to the first). */\nexport function startNow(scopebondHome: string, platform = process.platform, attempt = 0, tray: string | null = trayFor(platform)): boolean {\n if (tray) {\n if (attempt > 0) return false;\n try {\n const child = spawn(tray, [], { detached: true, stdio: \"ignore\", windowsHide: true });\n child.on(\"error\", () => { /* the next sign-in starts it */ });\n child.unref();\n return true;\n } catch { return false; }\n }\n const launcher = launcherPath(scopebondHome, platform);\n const command = startCommands(launcher, platform)[attempt];\n if (!command || !existsSync(launcher)) return false;\n try {\n const child = spawn(command[0], command[1], { detached: true, stdio: \"ignore\", windowsHide: true, windowsVerbatimArguments: true });\n child.on(\"error\", () => { /* the next way, or the next sign-in */ });\n child.unref();\n return true;\n } catch { return false; }\n}\n\n/** Turn autostart on for this user. Returns a one-line description of what changed. */\nexport function enableAutostart(scopebondHome: string, cli: string, node = process.execPath, platform = process.platform, tray: string | null = trayFor(platform), reg: RegRunner = runReg): string {\n if (tray) {\n retireLauncherRunValue(reg);\n if (trayForEveryone(reg)) return \"the Scopebond tray starts for every user of this computer and keeps the agent running\";\n if (!reg([\"add\", RUN_KEY, \"/v\", TRAY_RUN_VALUE, \"/t\", \"REG_SZ\", \"/d\", `\"${noQuotes(tray)}\"`, \"/f\"])) throw new Error(`could not add ${TRAY_RUN_VALUE} to ${RUN_KEY}`);\n return `added ${TRAY_RUN_VALUE} to ${RUN_KEY}: the Scopebond tray starts with your sign-in and keeps the agent running`;\n }\n const launcher = writeLauncher(scopebondHome, node, cli, platform);\n const paths = autostartPaths();\n if (platform === \"win32\") {\n execFileSync(\"reg\", [\"add\", RUN_KEY, \"/v\", RUN_VALUE, \"/t\", \"REG_SZ\", \"/d\", windowsRunCommand(launcher), \"/f\"], { stdio: \"ignore\" });\n return `added ${RUN_VALUE} to ${RUN_KEY} (launcher ${launcher})`;\n }\n if (platform === \"darwin\") {\n mkdirSync(dirname(paths.macPlist), { recursive: true });\n writeFileSync(paths.macPlist, macLaunchAgent(launcher, join(scopebondHome, \"agent.log\")));\n try { execFileSync(\"launchctl\", [\"load\", \"-w\", paths.macPlist], { stdio: \"ignore\" }); } catch { /* loads at next sign-in */ }\n return `wrote ${paths.macPlist}`;\n }\n mkdirSync(dirname(paths.linuxUnit), { recursive: true });\n writeFileSync(paths.linuxUnit, linuxUserUnit(launcher));\n try { execFileSync(\"systemctl\", [\"--user\", \"daemon-reload\"], { stdio: \"ignore\" }); execFileSync(\"systemctl\", [\"--user\", \"enable\", \"--now\", \"scopebond-agent.service\"], { stdio: \"ignore\" }); }\n catch { return `wrote ${paths.linuxUnit} (enable it with: systemctl --user enable --now scopebond-agent)`; }\n return `wrote and enabled ${paths.linuxUnit}`;\n}\n\nexport function disableAutostart(scopebondHome: string, platform = process.platform, tray: string | null = trayFor(platform), reg: RegRunner = runReg): string {\n const paths = autostartPaths();\n rmSync(launcherPath(scopebondHome, platform), { force: true });\n if (tray) {\n const launcherValue = retireLauncherRunValue(reg);\n const trayValue = reg([\"query\", RUN_KEY, \"/v\", TRAY_RUN_VALUE]) && reg([\"delete\", RUN_KEY, \"/v\", TRAY_RUN_VALUE, \"/f\"]);\n if (trayValue || launcherValue) return `removed ${trayValue ? TRAY_RUN_VALUE : RUN_VALUE} from ${RUN_KEY}`;\n return trayForEveryone(reg) ? \"Scopebond starts for every user of this computer; whoever installed it changes that\" : \"autostart was not on\";\n }\n if (platform === \"win32\") {\n try { execFileSync(\"reg\", [\"delete\", RUN_KEY, \"/v\", RUN_VALUE, \"/f\"], { stdio: \"ignore\" }); } catch { return \"autostart was not on\"; }\n return `removed ${RUN_VALUE} from ${RUN_KEY}`;\n }\n if (platform === \"darwin\") {\n if (!existsSync(paths.macPlist)) return \"autostart was not on\";\n try { execFileSync(\"launchctl\", [\"unload\", \"-w\", paths.macPlist], { stdio: \"ignore\" }); } catch { /* not loaded */ }\n rmSync(paths.macPlist, { force: true });\n return `removed ${paths.macPlist}`;\n }\n if (!existsSync(paths.linuxUnit)) return \"autostart was not on\";\n try { execFileSync(\"systemctl\", [\"--user\", \"disable\", \"--now\", \"scopebond-agent.service\"], { stdio: \"ignore\" }); } catch { /* not enabled */ }\n rmSync(paths.linuxUnit, { force: true });\n return `removed ${paths.linuxUnit}`;\n}\n\n/** Whether autostart is on and its launcher can start the agent now. */\nexport function autostartHealth(scopebondHome: string, platform = process.platform, tray: string | null = trayFor(platform), reg: RegRunner = runReg): { on: boolean; ok: boolean; detail: string } {\n if (tray) {\n const on = reg([\"query\", RUN_KEY, \"/v\", TRAY_RUN_VALUE]) || trayForEveryone(reg);\n return on\n ? { on, ok: true, detail: \"starts with sign-in (the Scopebond tray keeps the agent running)\" }\n : { on, ok: false, detail: \"the Scopebond tray does not start with sign-in (turn on Start with Windows in its menu, or run: scopebond-agent.exe autostart on)\" };\n }\n const paths = autostartPaths();\n let on = false;\n if (platform === \"win32\") {\n try { execFileSync(\"reg\", [\"query\", RUN_KEY, \"/v\", RUN_VALUE], { stdio: \"ignore\" }); on = true; } catch { on = false; }\n } else on = existsSync(platform === \"darwin\" ? paths.macPlist : paths.linuxUnit);\n // The fix as the person types it: PowerShell blocks the plain scopebond-agent script shim.\n const fix = `${platform === \"win32\" ? \"scopebond-agent.cmd\" : \"scopebond-agent\"} autostart on`;\n if (!on) return { on, ok: false, detail: `the agent does not start with sign-in (run: ${fix})` };\n if (!existsSync(launcherPath(scopebondHome, platform))) return { on, ok: false, detail: `the autostart launcher is missing (run: ${fix})` };\n return { on, ok: true, detail: \"starts with sign-in\" };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"autostart.js","sourceRoot":"","sources":["../src/autostart.ts"],"names":[],"mappings":"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","sourcesContent":["// Start the agent when the person signs in to the computer, per user, with no administrator\n// rights: a Run entry on Windows, a LaunchAgent on macOS, a systemd user unit on Linux.\n//\n// Each of them starts a small launcher script in the Scopebond home, not Node directly. The\n// launcher finds Node and the agent when it runs (the recorded paths first, then the system's),\n// so upgrading Node or switching versions never leaves an autostart entry pointing at nothing.\n// On Windows it runs under `conhost --headless`, so no window opens at sign-in.\n\nimport { execFileSync, spawn } from \"node:child_process\";\nimport { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, win32 } from \"node:path\";\nimport { isSingleExecutable } from \"@scopebond/hook\";\nimport { nativeTrayPath } from \"./native-update.js\";\n\nexport const LABEL = \"com.scopebond.agent\";\nconst RUN_KEY = \"HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\";\nconst RUN_VALUE = \"ScopebondAgent\";\n\nconst xml = (s: string) => s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\nconst noQuotes = (s: string) => s.replace(/\"/g, \"\");\n\n/** The agent's log, which the agent writes itself (`SCOPEBOND_AGENT_LOG`) when a Windows launcher or a handover starts it. */\nexport const AGENT_LOG_ENV = \"SCOPEBOND_AGENT_LOG\";\n\n/** Written into every Windows launcher this version makes. A launcher without it redirects the agent's output into\n * agent.log itself, which keeps a replacement agent from starting (see `spawnReplacement`). */\nexport const LAUNCHER_MARK = \"rem Scopebond Agent launcher 2:\";\n\n/** Whether a launcher's text is this version's (an older one is rewritten once no agent runs under it). */\nexport function launcherIsCurrent(text: string, platform: NodeJS.Platform = process.platform): boolean {\n return platform !== \"win32\" || text.includes(LAUNCHER_MARK);\n}\n\nexport function launcherPath(home: string, platform: NodeJS.Platform = process.platform): string {\n return join(home, platform === \"win32\" ? \"agent-launch.cmd\" : \"agent-launch.sh\");\n}\n\n/** The Windows launcher. With `cli` empty, `node` is the single executable: it is started as it is, with no Node to find. */\nexport function windowsLauncher(node: string, cli: string, logFile: string): string {\n const log = `\"%~dp0${win32.basename(noQuotes(logFile))}\"`;\n const single = cli === \"\";\n return [\n \"@echo off\",\n // cmd.exe reads a batch file in the console code page: switch to UTF-8 first, so a profile folder\n // with non-ASCII letters in the paths below reads as written.\n \"chcp 65001 >nul\",\n `${LAUNCHER_MARK} finds Node and the agent each time, so a Node upgrade never stops it.`,\n \"setlocal\",\n // The agent writes its own log. A `>> agent.log` here would hold the file shared for reading only, the old agent's\n // children inherit that handle, and a replacement started during an update could then never open it: cmd skips the\n // whole command line when a redirect fails. The log sits beside this launcher; %~dp0 keeps it right whatever the folder is called.\n `set \"${AGENT_LOG_ENV}=%~dp0${win32.basename(noQuotes(logFile))}\"`,\n `set \"NODE=${noQuotes(node)}\"`,\n ...(single ? [`if not exist \"%NODE%\" exit /b 1`] : [\n `if not exist \"%NODE%\" set \"NODE=\"`,\n `if not defined NODE for /f \"delims=\" %%i in ('where node 2^>nul') do if not defined NODE set \"NODE=%%i\"`,\n `set \"CLI=${noQuotes(cli)}\"`,\n `if not exist \"%CLI%\" for /f \"delims=\" %%i in ('npm.cmd root -g 2^>nul') do set \"CLI=%%i\\\\@scopebond\\\\agent\\\\dist\\\\cli.js\"`,\n `if not defined NODE exit /b 1`,\n ]),\n // Restart on failure, as launchd (KeepAlive) and systemd (Restart=on-failure) do: a crash restarts the agent after\n // 30 seconds, up to 50 times; a clean exit (stop, autostart off, an update handing over) ends the launcher.\n \"set /a TRIES=0\",\n \":run\",\n // (call) sets the error level to 1 first, so a command that never ran counts as a failure, not a clean stop.\n \"(call)\",\n single ? `\"%NODE%\" run >nul 2>&1` : `\"%NODE%\" --disable-warning=ExperimentalWarning \"%CLI%\" run >nul 2>&1`,\n `set \"CODE=%ERRORLEVEL%\"`,\n // An update's handover names the agent to wait for; a restart after a crash has nothing to wait for.\n `set \"SCOPEBOND_AGENT_AFTER_PID=\"`,\n \"if %CODE% EQU 0 exit /b 0\",\n \"set /a TRIES+=1\",\n `echo %DATE% %TIME% the agent stopped with exit code %CODE%; restarting in 30 seconds (attempt %TRIES% of 50) >> ${log}`,\n \"if %TRIES% GEQ 50 exit /b 1\",\n // ping waits without a console to read from (timeout.exe refuses to run under a headless console).\n \"ping -n 31 127.0.0.1 >nul\",\n \"goto run\",\n \"\",\n ].join(\"\\r\\n\");\n}\n\n/** The macOS/Linux launcher. With `cli` empty, `node` is the single executable, started as it is. */\nexport function posixLauncher(node: string, cli: string): string {\n const q = (s: string) => `'${s.replace(/'/g, \"'\\\\''\")}'`;\n if (cli === \"\") return `#!/bin/sh\n# Scopebond Agent launcher: the single executable.\nexec ${q(node)} run\n`;\n return `#!/bin/sh\n# Scopebond Agent launcher: finds Node and the agent each time, so a Node upgrade never stops it.\nNODE=${q(node)}\nif [ ! -x \"$NODE\" ]; then\n [ -s \"$HOME/.nvm/nvm.sh\" ] && . \"$HOME/.nvm/nvm.sh\" >/dev/null 2>&1\n NODE=\"$(command -v node 2>/dev/null)\"\n for candidate in /opt/homebrew/bin/node /usr/local/bin/node /usr/bin/node; do\n [ -n \"$NODE\" ] && break\n [ -x \"$candidate\" ] && NODE=\"$candidate\"\n done\nfi\nCLI=${q(cli)}\n[ -f \"$CLI\" ] || CLI=\"$(npm root -g 2>/dev/null)/@scopebond/agent/dist/cli.js\"\n[ -n \"$NODE\" ] || exit 1\nexec \"$NODE\" --disable-warning=ExperimentalWarning \"$CLI\" run\n`;\n}\n\n/** The Run value: the launcher under a headless console host, so nothing appears on screen. */\n/** `cmd /s /c \"\"<launcher>\"\"`: cmd drops only the outer quotes and runs the quoted path as it is, so a\n * profile folder with a space and a `(`, `)` or `&` (\"John (Work)\") still starts the launcher. */\nconst cmdRun = (launcher: string) => `/d /s /c \"\"${noQuotes(launcher)}\"\"`;\n\nexport function windowsRunCommand(launcher: string): string {\n return `conhost.exe --headless cmd.exe ${cmdRun(launcher)}`;\n}\n\nexport function macLaunchAgent(launcher: string, logFile: string): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key><string>${LABEL}</string>\n <key>ProgramArguments</key>\n <array><string>/bin/sh</string><string>${xml(launcher)}</string></array>\n <key>RunAtLoad</key><true/>\n <key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>\n <key>StandardOutPath</key><string>${xml(logFile)}</string>\n <key>StandardErrorPath</key><string>${xml(logFile)}</string>\n</dict>\n</plist>\n`;\n}\n\nexport function linuxUserUnit(launcher: string): string {\n const q = (s: string) => `\"${s.replace(/([\"\\\\])/g, \"\\\\$1\")}\"`;\n return `[Unit]\nDescription=Scopebond Agent (delivers this computer's records to its Scopebond workspace)\nAfter=network-online.target\n\n[Service]\nExecStart=/bin/sh ${q(launcher)}\nRestart=on-failure\nRestartSec=30\n\n[Install]\nWantedBy=default.target\n`;\n}\n\nexport function autostartPaths(home = homedir()) {\n return {\n macPlist: join(home, \"Library\", \"LaunchAgents\", `${LABEL}.plist`),\n linuxUnit: join(home, \".config\", \"systemd\", \"user\", \"scopebond-agent.service\"),\n };\n}\n\n/** Rewrite an older Windows launcher as this version's, keeping autostart as it is. Only safe once no cmd.exe runs the old\n * one (cmd reads a batch file line by line from where it left off): the handover calls it after the old agent has exited.\n * Returns whether it rewrote one. */\nexport function refreshLauncher(scopebondHome: string, cli: string, node = process.execPath, platform = process.platform): boolean {\n const launcher = launcherPath(scopebondHome, platform);\n let text: string;\n try { text = readFileSync(launcher, \"utf8\"); } catch { return false; }\n if (launcherIsCurrent(text, platform)) return false;\n writeLauncher(scopebondHome, node, cli, platform);\n return true;\n}\n\nfunction writeLauncher(scopebondHome: string, node: string, cli: string, platform: NodeJS.Platform): string {\n // The single executable is both Node and the agent: the launcher starts it with `run`.\n if (isSingleExecutable()) { node = process.execPath; cli = \"\"; }\n mkdirSync(scopebondHome, { recursive: true });\n const launcher = launcherPath(scopebondHome, platform);\n const log = join(scopebondHome, \"agent.log\");\n writeFileSync(launcher, platform === \"win32\" ? windowsLauncher(node, cli, log) : posixLauncher(node, cli), { mode: 0o700 });\n if (platform !== \"win32\") chmodSync(launcher, 0o700);\n return launcher;\n}\n\n/** The ways to start the agent now on Windows, in order: the launcher under a headless console (no window,\n * as sign-in does), then the launcher through cmd.exe with its window hidden, for a session where the\n * headless console host does not start (seen on Windows Server). macOS and Linux start it themselves\n * when autostart is turned on (RunAtLoad, enable --now). */\nexport function startCommands(launcher: string, platform: NodeJS.Platform = process.platform): Array<[string, string[]]> {\n if (platform !== \"win32\") return [];\n // Passed verbatim (startNow sets windowsVerbatimArguments): Node's own quoting follows other rules than cmd's.\n return [[\"conhost.exe\", [\"--headless\", \"cmd.exe\", cmdRun(launcher)]], [\"cmd.exe\", [cmdRun(launcher)]]];\n}\n\n// The signed Windows install with its native tray (`scopebond-tray.exe` beside the agent): the installer adds a Run value\n// `Scopebond` that starts the tray, and the tray starts the agent and keeps it running. Autostart then means that value,\n// not the launcher's `ScopebondAgent`, which would start a second agent (refused by its lock) at every sign-in.\n\n/** Runs `reg.exe` with these arguments; whether it succeeded. Tests pass their own. */\nexport type RegRunner = (args: string[]) => boolean;\nconst runReg: RegRunner = (args) => {\n try { execFileSync(\"reg\", args, { stdio: \"ignore\", windowsHide: true }); return true; } catch { return false; }\n};\nexport const TRAY_RUN_VALUE = \"Scopebond\";\nconst MACHINE_RUN_KEY = \"HKLM\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\";\nconst trayFor = (platform: NodeJS.Platform) => (platform === \"win32\" ? nativeTrayPath() : null);\n/** The tray's Run value set for every user (an install with ALLUSERS=1): only whoever installed it changes it. */\nconst trayForEveryone = (reg: RegRunner) => reg([\"query\", MACHINE_RUN_KEY, \"/v\", TRAY_RUN_VALUE]);\n\n/** The launcher's Run value is not used beside the native tray. Whether there was one to remove. */\nexport function retireLauncherRunValue(reg: RegRunner = runReg): boolean {\n return reg([\"query\", RUN_KEY, \"/v\", RUN_VALUE]) && reg([\"delete\", RUN_KEY, \"/v\", RUN_VALUE, \"/f\"]);\n}\n\n/** Start the agent now with the `attempt`-th way (0 first), detached from this terminal. Returns whether it tried one.\n * Beside the native tray, the one way is to start the tray (it starts the agent; a second tray gives way to the first). */\nexport function startNow(scopebondHome: string, platform = process.platform, attempt = 0, tray: string | null = trayFor(platform)): boolean {\n if (tray) {\n if (attempt > 0) return false;\n try {\n const child = spawn(tray, [], { detached: true, stdio: \"ignore\", windowsHide: true });\n child.on(\"error\", () => { /* the next sign-in starts it */ });\n child.unref();\n return true;\n } catch { return false; }\n }\n const launcher = launcherPath(scopebondHome, platform);\n const command = startCommands(launcher, platform)[attempt];\n if (!command || !existsSync(launcher)) return false;\n try {\n const child = spawn(command[0], command[1], { detached: true, stdio: \"ignore\", windowsHide: true, windowsVerbatimArguments: true });\n child.on(\"error\", () => { /* the next way, or the next sign-in */ });\n child.unref();\n return true;\n } catch { return false; }\n}\n\n/** Turn autostart on for this user. Returns a one-line description of what changed. */\nexport function enableAutostart(scopebondHome: string, cli: string, node = process.execPath, platform = process.platform, tray: string | null = trayFor(platform), reg: RegRunner = runReg): string {\n if (tray) {\n retireLauncherRunValue(reg);\n if (trayForEveryone(reg)) return \"the Scopebond tray starts for every user of this computer and keeps the agent running\";\n if (!reg([\"add\", RUN_KEY, \"/v\", TRAY_RUN_VALUE, \"/t\", \"REG_SZ\", \"/d\", `\"${noQuotes(tray)}\"`, \"/f\"])) throw new Error(`could not add ${TRAY_RUN_VALUE} to ${RUN_KEY}`);\n return `added ${TRAY_RUN_VALUE} to ${RUN_KEY}: the Scopebond tray starts with your sign-in and keeps the agent running`;\n }\n const launcher = writeLauncher(scopebondHome, node, cli, platform);\n const paths = autostartPaths();\n if (platform === \"win32\") {\n execFileSync(\"reg\", [\"add\", RUN_KEY, \"/v\", RUN_VALUE, \"/t\", \"REG_SZ\", \"/d\", windowsRunCommand(launcher), \"/f\"], { stdio: \"ignore\" });\n return `added ${RUN_VALUE} to ${RUN_KEY} (launcher ${launcher})`;\n }\n if (platform === \"darwin\") {\n mkdirSync(dirname(paths.macPlist), { recursive: true });\n writeFileSync(paths.macPlist, macLaunchAgent(launcher, join(scopebondHome, \"agent.log\")));\n try { execFileSync(\"launchctl\", [\"load\", \"-w\", paths.macPlist], { stdio: \"ignore\" }); } catch { /* loads at next sign-in */ }\n return `wrote ${paths.macPlist}`;\n }\n mkdirSync(dirname(paths.linuxUnit), { recursive: true });\n writeFileSync(paths.linuxUnit, linuxUserUnit(launcher));\n try { execFileSync(\"systemctl\", [\"--user\", \"daemon-reload\"], { stdio: \"ignore\" }); execFileSync(\"systemctl\", [\"--user\", \"enable\", \"--now\", \"scopebond-agent.service\"], { stdio: \"ignore\" }); }\n catch { return `wrote ${paths.linuxUnit} (enable it with: systemctl --user enable --now scopebond-agent)`; }\n return `wrote and enabled ${paths.linuxUnit}`;\n}\n\nexport function disableAutostart(scopebondHome: string, platform = process.platform, tray: string | null = trayFor(platform), reg: RegRunner = runReg): string {\n const paths = autostartPaths();\n rmSync(launcherPath(scopebondHome, platform), { force: true });\n if (tray) {\n const launcherValue = retireLauncherRunValue(reg);\n const trayValue = reg([\"query\", RUN_KEY, \"/v\", TRAY_RUN_VALUE]) && reg([\"delete\", RUN_KEY, \"/v\", TRAY_RUN_VALUE, \"/f\"]);\n if (trayValue || launcherValue) return `removed ${trayValue ? TRAY_RUN_VALUE : RUN_VALUE} from ${RUN_KEY}`;\n return trayForEveryone(reg) ? \"Scopebond starts for every user of this computer; whoever installed it changes that\" : \"autostart was not on\";\n }\n if (platform === \"win32\") {\n try { execFileSync(\"reg\", [\"delete\", RUN_KEY, \"/v\", RUN_VALUE, \"/f\"], { stdio: \"ignore\" }); } catch { return \"autostart was not on\"; }\n return `removed ${RUN_VALUE} from ${RUN_KEY}`;\n }\n if (platform === \"darwin\") {\n if (!existsSync(paths.macPlist)) return \"autostart was not on\";\n try { execFileSync(\"launchctl\", [\"unload\", \"-w\", paths.macPlist], { stdio: \"ignore\" }); } catch { /* not loaded */ }\n rmSync(paths.macPlist, { force: true });\n return `removed ${paths.macPlist}`;\n }\n if (!existsSync(paths.linuxUnit)) return \"autostart was not on\";\n try { execFileSync(\"systemctl\", [\"--user\", \"disable\", \"--now\", \"scopebond-agent.service\"], { stdio: \"ignore\" }); } catch { /* not enabled */ }\n rmSync(paths.linuxUnit, { force: true });\n return `removed ${paths.linuxUnit}`;\n}\n\n/** Whether autostart is on and its launcher can start the agent now. */\nexport function autostartHealth(scopebondHome: string, platform = process.platform, tray: string | null = trayFor(platform), reg: RegRunner = runReg): { on: boolean; ok: boolean; detail: string } {\n if (tray) {\n const on = reg([\"query\", RUN_KEY, \"/v\", TRAY_RUN_VALUE]) || trayForEveryone(reg);\n return on\n ? { on, ok: true, detail: \"starts with sign-in (the Scopebond tray keeps the agent running)\" }\n : { on, ok: false, detail: \"the Scopebond tray does not start with sign-in (turn on Start with Windows in its menu, or run: scopebond-agent.exe autostart on)\" };\n }\n const paths = autostartPaths();\n let on: boolean;\n if (platform === \"win32\") {\n try { execFileSync(\"reg\", [\"query\", RUN_KEY, \"/v\", RUN_VALUE], { stdio: \"ignore\" }); on = true; } catch { on = false; }\n } else on = existsSync(platform === \"darwin\" ? paths.macPlist : paths.linuxUnit);\n // The fix as the person types it: PowerShell blocks the plain scopebond-agent script shim.\n const fix = `${platform === \"win32\" ? \"scopebond-agent.cmd\" : \"scopebond-agent\"} autostart on`;\n if (!on) return { on, ok: false, detail: `the agent does not start with sign-in (run: ${fix})` };\n if (!existsSync(launcherPath(scopebondHome, platform))) return { on, ok: false, detail: `the autostart launcher is missing (run: ${fix})` };\n return { on, ok: true, detail: \"starts with sign-in\" };\n}\n"]}
|
package/dist/ipc.d.ts
CHANGED
|
@@ -14,7 +14,8 @@ export interface AgentEndpoint {
|
|
|
14
14
|
* first. Elsewhere: `run/agent.sock` in the Scopebond home (folder 0700), or a private folder under the temporary folder
|
|
15
15
|
* when that path is longer than a Unix socket path may be. */
|
|
16
16
|
export declare function localSocketPath(dir: string, platform?: NodeJS.Platform, random?: string): string;
|
|
17
|
-
|
|
17
|
+
/** Returns the answer, or a promise of it. */
|
|
18
|
+
export type Handler = (body: unknown) => unknown;
|
|
18
19
|
export declare function readEndpoint(dir: string): AgentEndpoint | null;
|
|
19
20
|
/** Start the control server. `routes` maps "METHOD /path" to a handler. `loopback`: also listen on 127.0.0.1 (default:
|
|
20
21
|
* unless SCOPEBOND_AGENT_LOOPBACK=0); it is used anyway when the pipe or socket could not be made, or nothing could reach
|
|
@@ -27,5 +28,5 @@ export declare function startControl(dir: string, version: string, routes: Recor
|
|
|
27
28
|
close(): Promise<void>;
|
|
28
29
|
}>;
|
|
29
30
|
/** Call a running agent, over its pipe or socket when it has one. Returns null when no agent answers. */
|
|
30
|
-
export declare function callAgent(dir: string, method: "GET" | "POST", path: string, body?: unknown, timeoutMs?: number): Promise<unknown
|
|
31
|
+
export declare function callAgent(dir: string, method: "GET" | "POST", path: string, body?: unknown, timeoutMs?: number): Promise<unknown>;
|
|
31
32
|
//# sourceMappingURL=ipc.d.ts.map
|
package/dist/ipc.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ipc.d.ts","sourceRoot":"","sources":["../src/ipc.ts"],"names":[],"mappings":"AAQA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAOjG,eAAO,MAAM,UAAU,eAAe,CAAC;AACvC,eAAO,MAAM,YAAY,4BAA4B,CAAC;AAEtD,8GAA8G;AAC9G,MAAM,WAAW,aAAa;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAExI;;+DAE+D;AAC/D,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAAE,MAAM,SAAkC,GAAG,MAAM,CAK3I;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC
|
|
1
|
+
{"version":3,"file":"ipc.d.ts","sourceRoot":"","sources":["../src/ipc.ts"],"names":[],"mappings":"AAQA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAOjG,eAAO,MAAM,UAAU,eAAe,CAAC;AACvC,eAAO,MAAM,YAAY,4BAA4B,CAAC;AAEtD,8GAA8G;AAC9G,MAAM,WAAW,aAAa;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAExI;;+DAE+D;AAC/D,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAAE,MAAM,SAAkC,GAAG,MAAM,CAK3I;AAED,8CAA8C;AAC9C,MAAM,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;AAEjD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAI9D;AAED;;iBAEiB;AACjB,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAC;IAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAqDpN;AAED,yGAAyG;AACzG,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,SAAS,SAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAetI"}
|
package/dist/ipc.js
CHANGED
|
@@ -62,9 +62,11 @@ export async function startControl(dir, version, routes, options = {}) {
|
|
|
62
62
|
send(500, { error: error.message.slice(0, 200) });
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
|
+
// A caller that drops the connection mid-body rejects the read; that ends the request, never the agent.
|
|
66
|
+
const listener = (req, res) => { handle(req, res).catch(() => { res.destroy(); }); };
|
|
65
67
|
// The pipe or socket first. A Unix socket's folder is created for this user only, and the socket itself is too.
|
|
66
68
|
const socketPath = localSocketPath(dir);
|
|
67
|
-
const local = createServer(
|
|
69
|
+
const local = createServer(listener);
|
|
68
70
|
let socket = socketPath;
|
|
69
71
|
try {
|
|
70
72
|
if (process.platform !== "win32") {
|
|
@@ -82,7 +84,7 @@ export async function startControl(dir, version, routes, options = {}) {
|
|
|
82
84
|
// Loopback where something still needs it (the PowerShell tray, older hooks), unless turned off; always when the pipe
|
|
83
85
|
// could not be made.
|
|
84
86
|
const loopback = (options.loopback ?? process.env.SCOPEBOND_AGENT_LOOPBACK !== "0") || socket === null;
|
|
85
|
-
const server = createServer(
|
|
87
|
+
const server = createServer(listener);
|
|
86
88
|
if (loopback)
|
|
87
89
|
await new Promise((resolve, reject) => { server.once("error", reject); server.listen(0, "127.0.0.1", () => resolve()); });
|
|
88
90
|
const address = loopback ? server.address() : null;
|
package/dist/ipc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ipc.js","sourceRoot":"","sources":["../src/ipc.ts"],"names":[],"mappings":"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","sourcesContent":["// The agent's local control channel: HTTP with a random token, over a named pipe on Windows (a random name) or a Unix\n// socket in a folder only this user can open. npm installs also listen on 127.0.0.1 at a random port, because the\n// PowerShell tray and hooks before the pipe use it (SCOPEBOND_AGENT_LOOPBACK=0 turns it off); the signed install with the\n// native tray does not (its tray and its hook use the pipe). The pipe or socket, the port, the token and the process id\n// are written to agent.json in the Scopebond home, which is how the CLI, the hook's override window and the tray find it.\n// A loopback port can be reached by any program on the computer; the pipe's name and the socket's folder cannot be found\n// or opened by another user. Every request must carry the token either way.\n\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { randomBytes, timingSafeEqual } from \"node:crypto\";\nimport { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { requestOverSocket } from \"@scopebond/hook\";\n\nexport const AGENT_FILE = \"agent.json\";\nexport const TOKEN_HEADER = \"x-scopebond-agent-token\";\n\n/** `socket`: the named pipe or Unix socket (absent from agents before it); `port`: 0 when loopback is off. */\nexport interface AgentEndpoint { port: number; socket?: string | null; token: string; pid: number; started_at: number; version: string }\n\n/** Where this start's pipe or socket goes. Windows: a pipe whose name is random, so no other user can guess it or claim it\n * first. Elsewhere: `run/agent.sock` in the Scopebond home (folder 0700), or a private folder under the temporary folder\n * when that path is longer than a Unix socket path may be. */\nexport function localSocketPath(dir: string, platform: NodeJS.Platform = process.platform, random = randomBytes(16).toString(\"hex\")): string {\n if (platform === \"win32\") return `\\\\\\\\.\\\\pipe\\\\scopebond-agent-${random}`;\n const inHome = join(dir, \"run\", \"agent.sock\");\n if (Buffer.byteLength(inHome) <= 100) return inHome;\n return join(mkdtempSync(join(tmpdir(), \"scopebond-\")), \"agent.sock\");\n}\n\nexport type Handler = (body: unknown) => Promise<unknown> | unknown;\n\nexport function readEndpoint(dir: string): AgentEndpoint | null {\n const file = join(dir, AGENT_FILE);\n if (!existsSync(file)) return null;\n try { return JSON.parse(readFileSync(file, \"utf8\")) as AgentEndpoint; } catch { return null; }\n}\n\n/** Start the control server. `routes` maps \"METHOD /path\" to a handler. `loopback`: also listen on 127.0.0.1 (default:\n * unless SCOPEBOND_AGENT_LOOPBACK=0); it is used anyway when the pipe or socket could not be made, or nothing could reach\n * the agent. */\nexport async function startControl(dir: string, version: string, routes: Record<string, Handler>, options: { loopback?: boolean } = {}): Promise<{ server: Server; endpoint: AgentEndpoint; close(): Promise<void> }> {\n const token = randomBytes(24).toString(\"base64url\");\n const expected = Buffer.from(token);\n const handle = async (req: IncomingMessage, res: ServerResponse) => {\n const send = (status: number, body: unknown) => { res.writeHead(status, { \"content-type\": \"application/json; charset=utf-8\", \"cache-control\": \"no-store\" }); res.end(JSON.stringify(body)); };\n const offered = Buffer.from(String(req.headers[TOKEN_HEADER] ?? \"\"));\n if (offered.length !== expected.length || !timingSafeEqual(offered, expected)) return send(401, { error: \"unauthorized\" });\n const handler = routes[`${req.method} ${(req.url ?? \"/\").split(\"?\")[0]}`];\n if (!handler) return send(404, { error: \"not found\" });\n let raw = \"\";\n for await (const chunk of req) { raw += chunk; if (raw.length > 64 * 1024) return send(413, { error: \"too large\" }); }\n try { send(200, await handler(raw ? JSON.parse(raw) : null)); }\n catch (error) { send(500, { error: (error as Error).message.slice(0, 200) }); }\n };\n // The pipe or socket first. A Unix socket's folder is created for this user only, and the socket itself is too.\n const socketPath = localSocketPath(dir);\n const local = createServer(handle);\n let socket: string | null = socketPath;\n try {\n if (process.platform !== \"win32\") {\n mkdirSync(join(socketPath, \"..\"), { recursive: true, mode: 0o700 });\n chmodSync(join(socketPath, \"..\"), 0o700);\n rmSync(socketPath, { force: true });\n }\n await new Promise<void>((resolve, reject) => { local.once(\"error\", reject); local.listen(socketPath, () => resolve()); });\n if (process.platform !== \"win32\") chmodSync(socketPath, 0o600);\n } catch { socket = null; }\n // Loopback where something still needs it (the PowerShell tray, older hooks), unless turned off; always when the pipe\n // could not be made.\n const loopback = (options.loopback ?? process.env.SCOPEBOND_AGENT_LOOPBACK !== \"0\") || socket === null;\n const server = createServer(handle);\n if (loopback) await new Promise<void>((resolve, reject) => { server.once(\"error\", reject); server.listen(0, \"127.0.0.1\", () => resolve()); });\n const address = loopback ? server.address() : null;\n const port = typeof address === \"object\" && address ? address.port : 0;\n const endpoint: AgentEndpoint = { port, socket, token, pid: process.pid, started_at: Date.now(), version };\n const file = join(dir, AGENT_FILE);\n const temp = `${file}.${process.pid}.tmp`;\n writeFileSync(temp, JSON.stringify(endpoint, null, 2) + \"\\n\", { mode: 0o600 });\n renameSync(temp, file);\n return {\n server, endpoint,\n close: () => new Promise<void>((resolve) => {\n let open = (loopback ? 1 : 0) + (socket ? 1 : 0);\n const done = () => { if (--open <= 0) resolve(); };\n if (open === 0) resolve();\n if (loopback) server.close(done);\n if (socket) local.close(() => { if (process.platform !== \"win32\") rmSync(socketPath, { force: true }); done(); });\n // Only remove the file if it is still ours (a newer agent may have replaced it).\n try { if (readEndpoint(dir)?.pid === process.pid) rmSync(file, { force: true }); } catch { /* best effort */ }\n }),\n };\n}\n\n/** Call a running agent, over its pipe or socket when it has one. Returns null when no agent answers. */\nexport async function callAgent(dir: string, method: \"GET\" | \"POST\", path: string, body?: unknown, timeoutMs = 5_000): Promise<unknown | null> {\n const endpoint = readEndpoint(dir);\n if (!endpoint) return null;\n if (typeof endpoint.socket === \"string\" && endpoint.socket) {\n const answer = await requestOverSocket(endpoint.socket, method, path, { [TOKEN_HEADER]: endpoint.token }, body, timeoutMs);\n if (answer) return answer.status >= 200 && answer.status < 300 ? answer.body : null;\n if (!endpoint.port) return null;\n }\n try {\n const res = await fetch(`http://127.0.0.1:${endpoint.port}${path}`, {\n method, headers: { [TOKEN_HEADER]: endpoint.token, ...(body !== undefined ? { \"content-type\": \"application/json\" } : {}) },\n body: body !== undefined ? JSON.stringify(body) : undefined, signal: AbortSignal.timeout(timeoutMs),\n });\n return res.ok ? await res.json() : null;\n } catch { return null; }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ipc.js","sourceRoot":"","sources":["../src/ipc.ts"],"names":[],"mappings":"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","sourcesContent":["// The agent's local control channel: HTTP with a random token, over a named pipe on Windows (a random name) or a Unix\n// socket in a folder only this user can open. npm installs also listen on 127.0.0.1 at a random port, because the\n// PowerShell tray and hooks before the pipe use it (SCOPEBOND_AGENT_LOOPBACK=0 turns it off); the signed install with the\n// native tray does not (its tray and its hook use the pipe). The pipe or socket, the port, the token and the process id\n// are written to agent.json in the Scopebond home, which is how the CLI, the hook's override window and the tray find it.\n// A loopback port can be reached by any program on the computer; the pipe's name and the socket's folder cannot be found\n// or opened by another user. Every request must carry the token either way.\n\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { randomBytes, timingSafeEqual } from \"node:crypto\";\nimport { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { requestOverSocket } from \"@scopebond/hook\";\n\nexport const AGENT_FILE = \"agent.json\";\nexport const TOKEN_HEADER = \"x-scopebond-agent-token\";\n\n/** `socket`: the named pipe or Unix socket (absent from agents before it); `port`: 0 when loopback is off. */\nexport interface AgentEndpoint { port: number; socket?: string | null; token: string; pid: number; started_at: number; version: string }\n\n/** Where this start's pipe or socket goes. Windows: a pipe whose name is random, so no other user can guess it or claim it\n * first. Elsewhere: `run/agent.sock` in the Scopebond home (folder 0700), or a private folder under the temporary folder\n * when that path is longer than a Unix socket path may be. */\nexport function localSocketPath(dir: string, platform: NodeJS.Platform = process.platform, random = randomBytes(16).toString(\"hex\")): string {\n if (platform === \"win32\") return `\\\\\\\\.\\\\pipe\\\\scopebond-agent-${random}`;\n const inHome = join(dir, \"run\", \"agent.sock\");\n if (Buffer.byteLength(inHome) <= 100) return inHome;\n return join(mkdtempSync(join(tmpdir(), \"scopebond-\")), \"agent.sock\");\n}\n\n/** Returns the answer, or a promise of it. */\nexport type Handler = (body: unknown) => unknown;\n\nexport function readEndpoint(dir: string): AgentEndpoint | null {\n const file = join(dir, AGENT_FILE);\n if (!existsSync(file)) return null;\n try { return JSON.parse(readFileSync(file, \"utf8\")) as AgentEndpoint; } catch { return null; }\n}\n\n/** Start the control server. `routes` maps \"METHOD /path\" to a handler. `loopback`: also listen on 127.0.0.1 (default:\n * unless SCOPEBOND_AGENT_LOOPBACK=0); it is used anyway when the pipe or socket could not be made, or nothing could reach\n * the agent. */\nexport async function startControl(dir: string, version: string, routes: Record<string, Handler>, options: { loopback?: boolean } = {}): Promise<{ server: Server; endpoint: AgentEndpoint; close(): Promise<void> }> {\n const token = randomBytes(24).toString(\"base64url\");\n const expected = Buffer.from(token);\n const handle = async (req: IncomingMessage, res: ServerResponse) => {\n const send = (status: number, body: unknown) => { res.writeHead(status, { \"content-type\": \"application/json; charset=utf-8\", \"cache-control\": \"no-store\" }); res.end(JSON.stringify(body)); };\n const offered = Buffer.from(String(req.headers[TOKEN_HEADER] ?? \"\"));\n if (offered.length !== expected.length || !timingSafeEqual(offered, expected)) return send(401, { error: \"unauthorized\" });\n const handler = routes[`${req.method} ${(req.url ?? \"/\").split(\"?\")[0]}`];\n if (!handler) return send(404, { error: \"not found\" });\n let raw = \"\";\n for await (const chunk of req) { raw += chunk; if (raw.length > 64 * 1024) return send(413, { error: \"too large\" }); }\n try { send(200, await handler(raw ? JSON.parse(raw) : null)); }\n catch (error) { send(500, { error: (error as Error).message.slice(0, 200) }); }\n };\n // A caller that drops the connection mid-body rejects the read; that ends the request, never the agent.\n const listener = (req: IncomingMessage, res: ServerResponse) => { handle(req, res).catch(() => { res.destroy(); }); };\n // The pipe or socket first. A Unix socket's folder is created for this user only, and the socket itself is too.\n const socketPath = localSocketPath(dir);\n const local = createServer(listener);\n let socket: string | null = socketPath;\n try {\n if (process.platform !== \"win32\") {\n mkdirSync(join(socketPath, \"..\"), { recursive: true, mode: 0o700 });\n chmodSync(join(socketPath, \"..\"), 0o700);\n rmSync(socketPath, { force: true });\n }\n await new Promise<void>((resolve, reject) => { local.once(\"error\", reject); local.listen(socketPath, () => resolve()); });\n if (process.platform !== \"win32\") chmodSync(socketPath, 0o600);\n } catch { socket = null; }\n // Loopback where something still needs it (the PowerShell tray, older hooks), unless turned off; always when the pipe\n // could not be made.\n const loopback = (options.loopback ?? process.env.SCOPEBOND_AGENT_LOOPBACK !== \"0\") || socket === null;\n const server = createServer(listener);\n if (loopback) await new Promise<void>((resolve, reject) => { server.once(\"error\", reject); server.listen(0, \"127.0.0.1\", () => resolve()); });\n const address = loopback ? server.address() : null;\n const port = typeof address === \"object\" && address ? address.port : 0;\n const endpoint: AgentEndpoint = { port, socket, token, pid: process.pid, started_at: Date.now(), version };\n const file = join(dir, AGENT_FILE);\n const temp = `${file}.${process.pid}.tmp`;\n writeFileSync(temp, JSON.stringify(endpoint, null, 2) + \"\\n\", { mode: 0o600 });\n renameSync(temp, file);\n return {\n server, endpoint,\n close: () => new Promise<void>((resolve) => {\n let open = (loopback ? 1 : 0) + (socket ? 1 : 0);\n const done = () => { if (--open <= 0) resolve(); };\n if (open === 0) resolve();\n if (loopback) server.close(done);\n if (socket) local.close(() => { if (process.platform !== \"win32\") rmSync(socketPath, { force: true }); done(); });\n // Only remove the file if it is still ours (a newer agent may have replaced it).\n try { if (readEndpoint(dir)?.pid === process.pid) rmSync(file, { force: true }); } catch { /* best effort */ }\n }),\n };\n}\n\n/** Call a running agent, over its pipe or socket when it has one. Returns null when no agent answers. */\nexport async function callAgent(dir: string, method: \"GET\" | \"POST\", path: string, body?: unknown, timeoutMs = 5_000): Promise<unknown> {\n const endpoint = readEndpoint(dir);\n if (!endpoint) return null;\n if (typeof endpoint.socket === \"string\" && endpoint.socket) {\n const answer = await requestOverSocket(endpoint.socket, method, path, { [TOKEN_HEADER]: endpoint.token }, body, timeoutMs);\n if (answer) return answer.status >= 200 && answer.status < 300 ? answer.body : null;\n if (!endpoint.port) return null;\n }\n try {\n const res = await fetch(`http://127.0.0.1:${endpoint.port}${path}`, {\n method, headers: { [TOKEN_HEADER]: endpoint.token, ...(body !== undefined ? { \"content-type\": \"application/json\" } : {}) },\n body: body !== undefined ? JSON.stringify(body) : undefined, signal: AbortSignal.timeout(timeoutMs),\n });\n return res.ok ? await res.json() : null;\n } catch { return null; }\n}\n"]}
|
package/dist/log-file.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-file.js","sourceRoot":"","sources":["../src/log-file.ts"],"names":[],"mappings":"AAAA,sHAAsH;AACtH,yHAAyH;AACzH,uHAAuH;AACvH,kEAAkE;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C;mHACmH;AACnH,MAAM,CAAC,MAAM,YAAY,GAAG,oBAAoB,CAAC;AAEjD,2GAA2G;AAC3G,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,CAAC,IAAyB,EAAE,EAAE;QAC3C,IAAI,CAAC;YAAC,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAAC,CAAC;QACnC,MAAM,CAAC;YAAC,IAAI,CAAC;gBAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,2DAA2D,CAAC,CAAC;QAAC,CAAC;IACzH,CAAC,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACtD,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,IAAyB,EAAE,QAAkB,EAAE,QAAkB,EAAE,EAAE;YACpF,MAAM,CAAC,IAAI,CAAC,CAAC;YACb,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;YAClE,IAAI,OAAO,IAAI,KAAK,UAAU;gBAAE,cAAc,CAAC,GAAG,EAAE,CAAE,IAAmB,EAAE,CAAC,CAAC;YAC7E,OAAO,IAAI,CAAC;QACd,CAAC,
|
|
1
|
+
{"version":3,"file":"log-file.js","sourceRoot":"","sources":["../src/log-file.ts"],"names":[],"mappings":"AAAA,sHAAsH;AACtH,yHAAyH;AACzH,uHAAuH;AACvH,kEAAkE;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C;mHACmH;AACnH,MAAM,CAAC,MAAM,YAAY,GAAG,oBAAoB,CAAC;AAEjD,2GAA2G;AAC3G,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,CAAC,IAAyB,EAAE,EAAE;QAC3C,IAAI,CAAC;YAAC,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAAC,CAAC;QACnC,MAAM,CAAC;YAAC,IAAI,CAAC;gBAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,2DAA2D,CAAC,CAAC;QAAC,CAAC;IACzH,CAAC,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACtD,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,IAAyB,EAAE,QAAkB,EAAE,QAAkB,EAAE,EAAE;YACpF,MAAM,CAAC,IAAI,CAAC,CAAC;YACb,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;YAClE,IAAI,OAAO,IAAI,KAAK,UAAU;gBAAE,cAAc,CAAC,GAAG,EAAE,CAAE,IAAmB,EAAE,CAAC,CAAC;YAC7E,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IACD,qHAAqH;IACrH,sCAAsC;IACtC,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE;QACxC,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,mCAAmC,KAAK,EAAE,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["// The agent's own log. A launcher redirecting the agent's output into the log would hold the file open for as long as\n// the agent runs, shared for reading only on Windows, and every child of the agent would inherit that handle. Writing it\n// here instead opens the file for each line, shared for reading and writing, so two agents (an old one handing over to\n// its update) can both write to it and no handle outlives a line.\n\nimport { appendFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\n/** Where lines go while the log itself cannot be opened: an agent started by an older launcher's agent inherits that\n * launcher's handle on agent.log, which keeps everyone else from writing it until the computer signs in again. */\nexport const FALLBACK_LOG = \"agent-handover.log\";\n\n/** Send everything this process writes to stdout and stderr, and an error that would end it, to `file`. */\nexport function writeOutputTo(file: string): void {\n const fallback = join(dirname(file), FALLBACK_LOG);\n const append = (data: string | Uint8Array) => {\n try { appendFileSync(file, data); }\n catch { try { appendFileSync(fallback, data); } catch { /* nowhere to write: the line is lost, the agent runs on */ } }\n };\n for (const stream of [process.stdout, process.stderr]) {\n stream.write = ((data: string | Uint8Array, encoding?: unknown, callback?: unknown) => {\n append(data);\n const done = typeof encoding === \"function\" ? encoding : callback;\n if (typeof done === \"function\") queueMicrotask(() => (done as () => void)());\n return true;\n });\n }\n // Node prints a fatal error straight to the console, which is nul here: note it in the log, then exit as Node would,\n // so the launcher restarts the agent.\n process.on(\"uncaughtException\", (error) => {\n append(`${new Date().toISOString()} the agent stopped on an error: ${error?.stack ?? String(error)}\\n`);\n process.exit(1);\n });\n}\n"]}
|
package/dist/prompt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,qGAAqG;IACrG,IAAI,EAAE,UAAU,GAAG,KAAK,CAAC;IACzB,6HAA6H;IAC7H,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC9E;AACD,MAAM,WAAW,cAAc;IAAG,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,aAAa,GAAG,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAA;CAAE;AAC5J,MAAM,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,gBAAgB,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,qGAAqG;IACrG,IAAI,EAAE,UAAU,GAAG,KAAK,CAAC;IACzB,6HAA6H;IAC7H,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC9E;AACD,MAAM,WAAW,cAAc;IAAG,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,aAAa,GAAG,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAA;CAAE;AAC5J,MAAM,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,gBAAgB,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAM/E,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAmBnE;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAIxD;AAiBD,uGAAuG;AACvG,wBAAgB,aAAa,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAmDzD;AAoDD,iHAAiH;AACjH,eAAO,MAAM,cAAc,EAAE,QAQ5B,CAAC;AAEF,uHAAuH;AACvH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAQvD"}
|
package/dist/prompt.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { userInfo } from "node:os";
|
|
7
7
|
const ID = /^[A-Za-z0-9._:-]{16,200}$/;
|
|
8
|
+
// eslint-disable-next-line no-control-regex -- deliberately replaces control characters in text shown in the window
|
|
8
9
|
const clip = (v, max) => (typeof v === "string" ? v.replace(/[\u0000-\u001f\u007f]/g, " ").slice(0, max) : "");
|
|
9
10
|
/** Check a request from the local channel. Anything malformed is refused before a window opens. */
|
|
10
11
|
export function parseQuestion(raw) {
|
package/dist/prompt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"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","sourcesContent":["// The Scopebond window: asks the person at the computer whether to allow one action a workspace rule blocks, with a reason.\n// It is shown by this resident agent with the operating system's own tools (Windows PowerShell with Windows Forms, macOS\n// osascript, Linux zenity), never by the coding agent, and the answer comes only from the window. Text reaches each tool as\n// data (base64 for PowerShell, arguments for osascript and zenity), never spliced into code.\n\nimport { spawn } from \"node:child_process\";\nimport { userInfo } from \"node:os\";\n\nexport interface OverrideQuestion {\n action_id: string;\n rule: string;\n title: string;\n summary: string;\n reason_min: number;\n lasts: string;\n timeout_ms: number;\n /** D144: override = \"Block, person may allow\"; ask = \"Block, person may ask\" (only Ask an admin). */\n mode: \"override\" | \"ask\";\n /** Which choices the workspace allows: allow (once), fifteen (for 15 minutes), always (an allowance), ask (Ask an admin). */\n offers: { allow: boolean; always: boolean; ask: boolean; fifteen?: boolean };\n}\nexport interface OverrideAnswer { decision: \"allow\" | \"deny\" | \"unavailable\" | \"ask\"; reason?: string; os_user?: string; lasts?: \"once\" | \"15m\" | \"always\" }\nexport type Prompter = (question: OverrideQuestion) => Promise<OverrideAnswer>;\n\nconst ID = /^[A-Za-z0-9._:-]{16,200}$/;\nconst clip = (v: unknown, max: number) => (typeof v === \"string\" ? v.replace(/[\\u0000-\\u001f\\u007f]/g, \" \").slice(0, max) : \"\");\n\n/** Check a request from the local channel. Anything malformed is refused before a window opens. */\nexport function parseQuestion(raw: unknown): OverrideQuestion | null {\n if (!raw || typeof raw !== \"object\") return null;\n const r = raw as Record<string, unknown>;\n if (typeof r.action_id !== \"string\" || !ID.test(r.action_id) || typeof r.rule !== \"string\" || !/^[a-z0-9-]{1,64}$/.test(r.rule)) return null;\n const reasonMin = Number(r.reason_min);\n const timeout = Number(r.timeout_ms);\n if (!Number.isInteger(reasonMin) || reasonMin < 10 || reasonMin > 200) return null;\n const mode = r.mode === \"ask\" ? \"ask\" : \"override\";\n const o = (r.offers && typeof r.offers === \"object\" ? r.offers : {}) as Record<string, unknown>;\n // A hook before D144 sends no offers: the window offers \"Allow once\", as it always did.\n const offers = r.offers === undefined ? { allow: true, always: false, ask: false }\n : { allow: mode === \"override\" && o.allow === true, always: mode === \"override\" && o.always === true, ask: o.ask === true,\n // A hook that does not say offers 15 minutes wherever it offers \"always\" (both came with allowances).\n fifteen: mode === \"override\" && (o.fifteen === true || (o.fifteen === undefined && o.always === true)) };\n return {\n action_id: r.action_id, rule: r.rule, title: clip(r.title, 120) || r.rule, summary: clip(r.summary, 200), reason_min: reasonMin,\n lasts: clip(r.lasts, 80) || \"this action only\", timeout_ms: Number.isFinite(timeout) ? Math.min(Math.max(timeout, 5_000), 55_000) : 45_000,\n mode, offers,\n };\n}\n\nexport function questionText(q: OverrideQuestion): string {\n const head = `Scopebond blocked this. Your workspace's rule \"${q.title}\" blocked this action:\\n\\n${q.summary}\\n\\n`;\n if (!q.offers.allow) return `${head}You may ask an admin to allow it. Say why, in at least ${q.reason_min} characters. The action stays blocked until an admin answers; your name, the reason and the action are recorded in your workspace.`;\n return `${head}You may allow it. Say why, in at least ${q.reason_min} characters. Your name, the reason and the action are recorded in your workspace.`;\n}\n\nfunction run(command: string, args: string[], timeoutMs: number): Promise<{ code: number | null; stdout: string }> {\n return new Promise((resolve) => {\n let stdout = \"\";\n let child;\n try { child = spawn(command, args, { windowsHide: false, stdio: [\"ignore\", \"pipe\", \"ignore\"] }); }\n catch { resolve({ code: null, stdout: \"\" }); return; }\n const timer = setTimeout(() => { child.kill(); resolve({ code: null, stdout }); }, timeoutMs + 3_000);\n child.stdout?.on(\"data\", (d) => { stdout += d; });\n child.on(\"error\", () => { clearTimeout(timer); resolve({ code: null, stdout: \"\" }); });\n child.on(\"close\", (code) => { clearTimeout(timer); resolve({ code, stdout }); });\n });\n}\n\nconst b64 = (s: string) => Buffer.from(s, \"utf8\").toString(\"base64\");\n\n/** Windows: a small topmost form from Windows' own signed PowerShell. Closes itself at the timeout. */\nexport function windowsScript(q: OverrideQuestion): string {\n return `\n$ErrorActionPreference = 'Stop'\nAdd-Type -AssemblyName System.Windows.Forms\nAdd-Type -AssemblyName System.Drawing\nfunction T($s) { [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($s)) }\n$min = ${q.reason_min}\n$f = New-Object Windows.Forms.Form\n$f.Text = 'Scopebond'\n$f.TopMost = $true\n$f.StartPosition = 'CenterScreen'\n$f.FormBorderStyle = 'FixedDialog'\n$f.MaximizeBox = $false\n$f.MinimizeBox = $false\n$f.ClientSize = New-Object Drawing.Size(640, 250)\n$l = New-Object Windows.Forms.Label\n$l.Text = (T '${b64(questionText(q))}')\n$l.SetBounds(12, 10, 616, 130)\n$r = New-Object Windows.Forms.TextBox\n$r.SetBounds(12, 145, 616, 24)\n$script:answer = 'deny'\n$script:lasts = 'once'\n$needReason = @()\n$x = 628\nfunction Btn($label, $width, $decision, $lasts, $needs) {\n $b = New-Object Windows.Forms.Button\n $b.Text = (T $label)\n $script:x0 = $x - $width\n $b.SetBounds($x - $width, 200, $width, 30)\n $b.Add_Click({ $script:answer = $decision; $script:lasts = $lasts; $f.Close() }.GetNewClosure())\n if ($needs) { $b.Enabled = $false; $script:needReason += $b }\n $f.Controls.Add($b)\n $b\n}\n$d = Btn '${b64(\"Don't allow\")}' 100 'deny' 'once' $false; $x -= 108\n${q.offers.ask ? `[void](Btn '${b64(\"Ask an admin\")}' 110 'ask' 'once' $true); $x -= 118` : \"\"}\n${q.offers.always ? `[void](Btn '${b64(\"Always allow this here…\")}' 150 'allow' 'always' $true); $x -= 158` : \"\"}\n${q.offers.allow && q.offers.fifteen ? `[void](Btn '${b64(\"Allow for 15 min\")}' 120 'allow' '15m' $true); $x -= 128; ` : \"\"}${q.offers.allow ? `[void](Btn '${b64(\"Allow once\")}' 92 'allow' 'once' $true)` : \"\"}\n$r.Add_TextChanged({ foreach ($b in $script:needReason) { $b.Enabled = ($r.Text.Trim().Length -ge $min) } })\n$f.AcceptButton = $d\n$f.CancelButton = $d\n$f.Controls.AddRange(@($l, $r))\n$t = New-Object Windows.Forms.Timer\n$t.Interval = ${q.timeout_ms}\n$t.Add_Tick({ $t.Stop(); $f.Close() })\n$t.Start()\n$f.Add_Shown({ $f.Activate(); $r.Focus() })\n[void]$f.ShowDialog()\n$out = @{ decision = $script:answer; lasts = $script:lasts; reason = $(if ($script:answer -ne 'deny') { $r.Text.Trim() } else { '' }) }\n[Console]::Out.Write((ConvertTo-Json $out -Compress))\n`;\n}\n\nasync function promptWindows(q: OverrideQuestion): Promise<OverrideAnswer> {\n const encoded = Buffer.from(windowsScript(q), \"utf16le\").toString(\"base64\");\n const { code, stdout } = await run(\"powershell.exe\", [\"-NoProfile\", \"-NonInteractive\", \"-STA\", \"-WindowStyle\", \"Hidden\", \"-EncodedCommand\", encoded], q.timeout_ms);\n if (code !== 0) return { decision: \"unavailable\" };\n try {\n const parsed = JSON.parse(stdout.trim()) as { decision?: string; reason?: string; lasts?: string };\n const lasts = parsed.lasts === \"15m\" || parsed.lasts === \"always\" ? parsed.lasts : \"once\";\n if (parsed.decision === \"allow\" && q.offers.allow && (lasts !== \"always\" || q.offers.always) && (lasts !== \"15m\" || q.offers.fifteen)) return { decision: \"allow\", reason: String(parsed.reason ?? \"\"), lasts };\n if (parsed.decision === \"ask\" && q.offers.ask) return { decision: \"ask\", reason: String(parsed.reason ?? \"\") };\n return { decision: \"deny\" };\n } catch { return { decision: \"unavailable\" }; }\n}\n\nconst MAC_SCRIPT = [\n \"on run argv\",\n \"set q to item 1 of argv\",\n \"set secs to (item 2 of argv) as integer\",\n \"set r to display dialog q default answer \\\"\\\" with title \\\"Scopebond\\\" buttons {\\\"Don't allow\\\", \\\"Allow once\\\"} default button \\\"Don't allow\\\" cancel button \\\"Don't allow\\\" giving up after secs\",\n \"if gave up of r then return \\\"timeout\\\"\",\n \"return \\\"allow\\\" & linefeed & (text returned of r)\",\n \"end run\",\n];\n\nasync function promptMac(q: OverrideQuestion): Promise<OverrideAnswer> {\n // macOS dialogs take three buttons: \"Allow once\" where allowing is offered, otherwise \"Ask an admin\".\n const asking = !q.offers.allow && q.offers.ask;\n if (!q.offers.allow && !asking) return { decision: \"unavailable\" };\n const script = asking ? MAC_SCRIPT.map((line) => line.replace(/Allow once/g, \"Ask an admin\").replace('return \"allow\"', 'return \"ask\"')) : MAC_SCRIPT;\n const args = script.flatMap((line) => [\"-e\", line]);\n const { code, stdout } = await run(\"osascript\", [...args, questionText(q), String(Math.round(q.timeout_ms / 1000))], q.timeout_ms);\n if (code === null) return { decision: \"unavailable\" };\n if (code !== 0) return { decision: \"deny\" }; // \"Don't allow\" is the cancel button\n const [first, ...rest] = stdout.replace(/\\r?\\n$/, \"\").split(\"\\n\");\n if (first === \"ask\") return { decision: \"ask\", reason: rest.join(\"\\n\") };\n return first === \"allow\" ? { decision: \"allow\", reason: rest.join(\"\\n\"), lasts: \"once\" } : { decision: \"deny\" };\n}\n\nasync function promptLinux(q: OverrideQuestion): Promise<OverrideAnswer> {\n const asking = !q.offers.allow && q.offers.ask;\n if (!q.offers.allow && !asking) return { decision: \"unavailable\" };\n const { code, stdout } = await run(\"zenity\", [\n \"--entry\", \"--title=Scopebond\", `--text=${questionText(q)}`, `--ok-label=${asking ? \"Ask an admin\" : \"Allow once\"}`, \"--cancel-label=Don't allow\",\n `--timeout=${Math.round(q.timeout_ms / 1000)}`,\n ], q.timeout_ms);\n if (code === null) return { decision: \"unavailable\" };\n if (code === 0) return asking ? { decision: \"ask\", reason: stdout.replace(/\\r?\\n$/, \"\") } : { decision: \"allow\", reason: stdout.replace(/\\r?\\n$/, \"\"), lasts: \"once\" };\n // 1: Don't allow; 5: timed out; anything else (no display, not installed): no window.\n return code === 1 || code === 5 ? { decision: \"deny\" } : { decision: \"unavailable\" };\n}\n\n/** The window for this operating system. A reason shorter than the workspace accepts is refused here as well. */\nexport const systemPrompter: Prompter = async (q) => {\n const answer = process.platform === \"win32\" ? await promptWindows(q) : process.platform === \"darwin\" ? await promptMac(q) : await promptLinux(q);\n if (answer.decision !== \"allow\" && answer.decision !== \"ask\") return answer;\n const reason = (answer.reason ?? \"\").trim();\n if (reason.length < q.reason_min) return { decision: \"deny\" };\n let os_user: string | undefined;\n try { os_user = userInfo().username; } catch { /* not known */ }\n return { ...answer, reason: reason.slice(0, 500), ...(os_user ? { os_user } : {}) };\n};\n\n/** One window at a time: a second request waits for the first, and gives up as no answer if it would wait too long. */\nexport function serialized(prompter: Prompter): Prompter {\n let chain: Promise<unknown> = Promise.resolve();\n return (q) => {\n const queuedAt = Date.now();\n const next = chain.then(() => (Date.now() - queuedAt > q.timeout_ms ? { decision: \"unavailable\" as const } : prompter(q)));\n chain = next.catch(() => undefined);\n return next;\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"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","sourcesContent":["// The Scopebond window: asks the person at the computer whether to allow one action a workspace rule blocks, with a reason.\n// It is shown by this resident agent with the operating system's own tools (Windows PowerShell with Windows Forms, macOS\n// osascript, Linux zenity), never by the coding agent, and the answer comes only from the window. Text reaches each tool as\n// data (base64 for PowerShell, arguments for osascript and zenity), never spliced into code.\n\nimport { spawn } from \"node:child_process\";\nimport { userInfo } from \"node:os\";\n\nexport interface OverrideQuestion {\n action_id: string;\n rule: string;\n title: string;\n summary: string;\n reason_min: number;\n lasts: string;\n timeout_ms: number;\n /** D144: override = \"Block, person may allow\"; ask = \"Block, person may ask\" (only Ask an admin). */\n mode: \"override\" | \"ask\";\n /** Which choices the workspace allows: allow (once), fifteen (for 15 minutes), always (an allowance), ask (Ask an admin). */\n offers: { allow: boolean; always: boolean; ask: boolean; fifteen?: boolean };\n}\nexport interface OverrideAnswer { decision: \"allow\" | \"deny\" | \"unavailable\" | \"ask\"; reason?: string; os_user?: string; lasts?: \"once\" | \"15m\" | \"always\" }\nexport type Prompter = (question: OverrideQuestion) => Promise<OverrideAnswer>;\n\nconst ID = /^[A-Za-z0-9._:-]{16,200}$/;\n// eslint-disable-next-line no-control-regex -- deliberately replaces control characters in text shown in the window\nconst clip = (v: unknown, max: number) => (typeof v === \"string\" ? v.replace(/[\\u0000-\\u001f\\u007f]/g, \" \").slice(0, max) : \"\");\n\n/** Check a request from the local channel. Anything malformed is refused before a window opens. */\nexport function parseQuestion(raw: unknown): OverrideQuestion | null {\n if (!raw || typeof raw !== \"object\") return null;\n const r = raw as Record<string, unknown>;\n if (typeof r.action_id !== \"string\" || !ID.test(r.action_id) || typeof r.rule !== \"string\" || !/^[a-z0-9-]{1,64}$/.test(r.rule)) return null;\n const reasonMin = Number(r.reason_min);\n const timeout = Number(r.timeout_ms);\n if (!Number.isInteger(reasonMin) || reasonMin < 10 || reasonMin > 200) return null;\n const mode = r.mode === \"ask\" ? \"ask\" : \"override\";\n const o = (r.offers && typeof r.offers === \"object\" ? r.offers : {}) as Record<string, unknown>;\n // A hook before D144 sends no offers: the window offers \"Allow once\", as it always did.\n const offers = r.offers === undefined ? { allow: true, always: false, ask: false }\n : { allow: mode === \"override\" && o.allow === true, always: mode === \"override\" && o.always === true, ask: o.ask === true,\n // A hook that does not say offers 15 minutes wherever it offers \"always\" (both came with allowances).\n fifteen: mode === \"override\" && (o.fifteen === true || (o.fifteen === undefined && o.always === true)) };\n return {\n action_id: r.action_id, rule: r.rule, title: clip(r.title, 120) || r.rule, summary: clip(r.summary, 200), reason_min: reasonMin,\n lasts: clip(r.lasts, 80) || \"this action only\", timeout_ms: Number.isFinite(timeout) ? Math.min(Math.max(timeout, 5_000), 55_000) : 45_000,\n mode, offers,\n };\n}\n\nexport function questionText(q: OverrideQuestion): string {\n const head = `Scopebond blocked this. Your workspace's rule \"${q.title}\" blocked this action:\\n\\n${q.summary}\\n\\n`;\n if (!q.offers.allow) return `${head}You may ask an admin to allow it. Say why, in at least ${q.reason_min} characters. The action stays blocked until an admin answers; your name, the reason and the action are recorded in your workspace.`;\n return `${head}You may allow it. Say why, in at least ${q.reason_min} characters. Your name, the reason and the action are recorded in your workspace.`;\n}\n\nfunction run(command: string, args: string[], timeoutMs: number): Promise<{ code: number | null; stdout: string }> {\n return new Promise((resolve) => {\n let stdout = \"\";\n let child;\n try { child = spawn(command, args, { windowsHide: false, stdio: [\"ignore\", \"pipe\", \"ignore\"] }); }\n catch { resolve({ code: null, stdout: \"\" }); return; }\n const timer = setTimeout(() => { child.kill(); resolve({ code: null, stdout }); }, timeoutMs + 3_000);\n child.stdout?.on(\"data\", (d) => { stdout += d; });\n child.on(\"error\", () => { clearTimeout(timer); resolve({ code: null, stdout: \"\" }); });\n child.on(\"close\", (code) => { clearTimeout(timer); resolve({ code, stdout }); });\n });\n}\n\nconst b64 = (s: string) => Buffer.from(s, \"utf8\").toString(\"base64\");\n\n/** Windows: a small topmost form from Windows' own signed PowerShell. Closes itself at the timeout. */\nexport function windowsScript(q: OverrideQuestion): string {\n return `\n$ErrorActionPreference = 'Stop'\nAdd-Type -AssemblyName System.Windows.Forms\nAdd-Type -AssemblyName System.Drawing\nfunction T($s) { [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($s)) }\n$min = ${q.reason_min}\n$f = New-Object Windows.Forms.Form\n$f.Text = 'Scopebond'\n$f.TopMost = $true\n$f.StartPosition = 'CenterScreen'\n$f.FormBorderStyle = 'FixedDialog'\n$f.MaximizeBox = $false\n$f.MinimizeBox = $false\n$f.ClientSize = New-Object Drawing.Size(640, 250)\n$l = New-Object Windows.Forms.Label\n$l.Text = (T '${b64(questionText(q))}')\n$l.SetBounds(12, 10, 616, 130)\n$r = New-Object Windows.Forms.TextBox\n$r.SetBounds(12, 145, 616, 24)\n$script:answer = 'deny'\n$script:lasts = 'once'\n$needReason = @()\n$x = 628\nfunction Btn($label, $width, $decision, $lasts, $needs) {\n $b = New-Object Windows.Forms.Button\n $b.Text = (T $label)\n $script:x0 = $x - $width\n $b.SetBounds($x - $width, 200, $width, 30)\n $b.Add_Click({ $script:answer = $decision; $script:lasts = $lasts; $f.Close() }.GetNewClosure())\n if ($needs) { $b.Enabled = $false; $script:needReason += $b }\n $f.Controls.Add($b)\n $b\n}\n$d = Btn '${b64(\"Don't allow\")}' 100 'deny' 'once' $false; $x -= 108\n${q.offers.ask ? `[void](Btn '${b64(\"Ask an admin\")}' 110 'ask' 'once' $true); $x -= 118` : \"\"}\n${q.offers.always ? `[void](Btn '${b64(\"Always allow this here…\")}' 150 'allow' 'always' $true); $x -= 158` : \"\"}\n${q.offers.allow && q.offers.fifteen ? `[void](Btn '${b64(\"Allow for 15 min\")}' 120 'allow' '15m' $true); $x -= 128; ` : \"\"}${q.offers.allow ? `[void](Btn '${b64(\"Allow once\")}' 92 'allow' 'once' $true)` : \"\"}\n$r.Add_TextChanged({ foreach ($b in $script:needReason) { $b.Enabled = ($r.Text.Trim().Length -ge $min) } })\n$f.AcceptButton = $d\n$f.CancelButton = $d\n$f.Controls.AddRange(@($l, $r))\n$t = New-Object Windows.Forms.Timer\n$t.Interval = ${q.timeout_ms}\n$t.Add_Tick({ $t.Stop(); $f.Close() })\n$t.Start()\n$f.Add_Shown({ $f.Activate(); $r.Focus() })\n[void]$f.ShowDialog()\n$out = @{ decision = $script:answer; lasts = $script:lasts; reason = $(if ($script:answer -ne 'deny') { $r.Text.Trim() } else { '' }) }\n[Console]::Out.Write((ConvertTo-Json $out -Compress))\n`;\n}\n\nasync function promptWindows(q: OverrideQuestion): Promise<OverrideAnswer> {\n const encoded = Buffer.from(windowsScript(q), \"utf16le\").toString(\"base64\");\n const { code, stdout } = await run(\"powershell.exe\", [\"-NoProfile\", \"-NonInteractive\", \"-STA\", \"-WindowStyle\", \"Hidden\", \"-EncodedCommand\", encoded], q.timeout_ms);\n if (code !== 0) return { decision: \"unavailable\" };\n try {\n const parsed = JSON.parse(stdout.trim()) as { decision?: string; reason?: string; lasts?: string };\n const lasts = parsed.lasts === \"15m\" || parsed.lasts === \"always\" ? parsed.lasts : \"once\";\n if (parsed.decision === \"allow\" && q.offers.allow && (lasts !== \"always\" || q.offers.always) && (lasts !== \"15m\" || q.offers.fifteen)) return { decision: \"allow\", reason: String(parsed.reason ?? \"\"), lasts };\n if (parsed.decision === \"ask\" && q.offers.ask) return { decision: \"ask\", reason: String(parsed.reason ?? \"\") };\n return { decision: \"deny\" };\n } catch { return { decision: \"unavailable\" }; }\n}\n\nconst MAC_SCRIPT = [\n \"on run argv\",\n \"set q to item 1 of argv\",\n \"set secs to (item 2 of argv) as integer\",\n \"set r to display dialog q default answer \\\"\\\" with title \\\"Scopebond\\\" buttons {\\\"Don't allow\\\", \\\"Allow once\\\"} default button \\\"Don't allow\\\" cancel button \\\"Don't allow\\\" giving up after secs\",\n \"if gave up of r then return \\\"timeout\\\"\",\n \"return \\\"allow\\\" & linefeed & (text returned of r)\",\n \"end run\",\n];\n\nasync function promptMac(q: OverrideQuestion): Promise<OverrideAnswer> {\n // macOS dialogs take three buttons: \"Allow once\" where allowing is offered, otherwise \"Ask an admin\".\n const asking = !q.offers.allow && q.offers.ask;\n if (!q.offers.allow && !asking) return { decision: \"unavailable\" };\n const script = asking ? MAC_SCRIPT.map((line) => line.replace(/Allow once/g, \"Ask an admin\").replace('return \"allow\"', 'return \"ask\"')) : MAC_SCRIPT;\n const args = script.flatMap((line) => [\"-e\", line]);\n const { code, stdout } = await run(\"osascript\", [...args, questionText(q), String(Math.round(q.timeout_ms / 1000))], q.timeout_ms);\n if (code === null) return { decision: \"unavailable\" };\n if (code !== 0) return { decision: \"deny\" }; // \"Don't allow\" is the cancel button\n const [first, ...rest] = stdout.replace(/\\r?\\n$/, \"\").split(\"\\n\");\n if (first === \"ask\") return { decision: \"ask\", reason: rest.join(\"\\n\") };\n return first === \"allow\" ? { decision: \"allow\", reason: rest.join(\"\\n\"), lasts: \"once\" } : { decision: \"deny\" };\n}\n\nasync function promptLinux(q: OverrideQuestion): Promise<OverrideAnswer> {\n const asking = !q.offers.allow && q.offers.ask;\n if (!q.offers.allow && !asking) return { decision: \"unavailable\" };\n const { code, stdout } = await run(\"zenity\", [\n \"--entry\", \"--title=Scopebond\", `--text=${questionText(q)}`, `--ok-label=${asking ? \"Ask an admin\" : \"Allow once\"}`, \"--cancel-label=Don't allow\",\n `--timeout=${Math.round(q.timeout_ms / 1000)}`,\n ], q.timeout_ms);\n if (code === null) return { decision: \"unavailable\" };\n if (code === 0) return asking ? { decision: \"ask\", reason: stdout.replace(/\\r?\\n$/, \"\") } : { decision: \"allow\", reason: stdout.replace(/\\r?\\n$/, \"\"), lasts: \"once\" };\n // 1: Don't allow; 5: timed out; anything else (no display, not installed): no window.\n return code === 1 || code === 5 ? { decision: \"deny\" } : { decision: \"unavailable\" };\n}\n\n/** The window for this operating system. A reason shorter than the workspace accepts is refused here as well. */\nexport const systemPrompter: Prompter = async (q) => {\n const answer = process.platform === \"win32\" ? await promptWindows(q) : process.platform === \"darwin\" ? await promptMac(q) : await promptLinux(q);\n if (answer.decision !== \"allow\" && answer.decision !== \"ask\") return answer;\n const reason = (answer.reason ?? \"\").trim();\n if (reason.length < q.reason_min) return { decision: \"deny\" };\n let os_user: string | undefined;\n try { os_user = userInfo().username; } catch { /* not known */ }\n return { ...answer, reason: reason.slice(0, 500), ...(os_user ? { os_user } : {}) };\n};\n\n/** One window at a time: a second request waits for the first, and gives up as no answer if it would wait too long. */\nexport function serialized(prompter: Prompter): Prompter {\n let chain: Promise<unknown> = Promise.resolve();\n return (q) => {\n const queuedAt = Date.now();\n const next = chain.then(() => (Date.now() - queuedAt > q.timeout_ms ? { decision: \"unavailable\" as const } : prompter(q)));\n chain = next.catch(() => undefined);\n return next;\n };\n}\n"]}
|
package/dist/selfcheck.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selfcheck.js","sourceRoot":"","sources":["../src/selfcheck.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,mGAAmG;AACnG,gGAAgG;AAChG,qGAAqG;AAErG,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EACL,sBAAsB,EAAE,cAAc,EAAE,mBAAmB,EAAE,WAAW,EAAE,sBAAsB,EAAE,WAAW,EAAE,iBAAiB,EAAE,eAAe,GAElJ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIjD,MAAM,UAAU,cAAc,CAAC,YAAoB,EAAE,SAAiB,EAAE,GAAW;IACjF,OAAO,SAAS,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,CAAC,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;AAC1H,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,UAA0B,EAAE,SAAoB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACzG,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9H,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,2CAA2C,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9I,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,+BAA+B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACzK,oHAAoH;IACpH,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAChF,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,yDAAyD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,uBAAuB,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACvR,MAAM,SAAS,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1G,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,IAAI,MAAM,KAAK,IAAI,IAAI,GAAG,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC9E,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,4BAA4B,IAAI,IAAI,CAAC,MAAO,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACjN,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACpF,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,0BAA0B,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,sBAAsB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACjK,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EAAE,UAA0B,EAAE,SAAoB,EAAE,YAAoB,EACnF,UAA0E,EAAE;IAE5E,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3G,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrD,MAAM,EAAE,QAAQ,EAAE,GAAG,oBAAoB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7D,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,aAAa,EAAE,UAAU,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;IAC5G,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,gBAAgB,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;YACnG,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;YAC3F,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,UAAU,CAAC,UAAU,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YACjG,uHAAuH;YACvH,yFAAyF;YACzF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,CAAC;SACxI,CAAC,CAAC;QACH,oHAAoH;QACpH,gDAAgD;QAChD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAAC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAAC,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,CAAC;QACvK,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,kBAAkB,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;QAC/G,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAuE,CAAC;QACnG,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC;IACzI,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,0BAA2B,KAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACvI,CAAC;AACH,CAAC","sourcesContent":["// The daily end-to-end self-check (SB347). The agent checks this computer's side (the hook entry\n// is present and starts, autostart works, nothing is stuck, the connection is not about to lapse),\n// then signs the day with the key it enrolled with and sends everything to the workspace, which\n// verifies the signature. A pass means the whole path works, end to end; a failure names what broke.\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { canonical } from \"@scopebond/gateway\";\nimport { loadOrCreateAttester } from \"@scopebond/gateway/node\";\nimport {\n configuredHookCommands, duplicateHooks, hookCommandResolves, hookVersion, isScopebondHookCommand, queueStatus, readDeliveryState, userHarnessFile,\n type Harness, type HookConnection,\n} from \"@scopebond/hook\";\nimport { autostartHealth } from \"./autostart.js\";\nimport { installKind } from \"./native-update.js\";\n\nexport interface SelfCheckItem { id: string; ok: boolean; detail?: string }\n\nexport function selfCheckProof(credentialId: string, gatewayId: string, day: string): string {\n return canonical({ type: \"scopebond:self-check\", version: 1, credential_id: credentialId, gateway_id: gatewayId, day });\n}\n\nexport function localChecks(dir: string, connection: HookConnection, harnesses: Harness[], now = Date.now()): SelfCheckItem[] {\n const checks: SelfCheckItem[] = [];\n const entries = harnesses.flatMap((h) => configuredHookCommands(userHarnessFile(h)).filter((c) => isScopebondHookCommand(c)));\n checks.push({ id: \"hook_entry\", ok: entries.length > 0, ...(entries.length ? {} : { detail: \"no agent setting holds the Scopebond hook\" }) });\n const broken = entries.filter((c) => !hookCommandResolves(c));\n checks.push({ id: \"hook_starts\", ok: entries.length > 0 && broken.length === 0, ...(broken.length ? { detail: `${broken.length} hook command(s) cannot start` } : {}) });\n // SB302: the hook twice in the user settings, or an enabled plugin beside them, signs and sends every action twice.\n const dupes = harnesses.flatMap((h) => duplicateHooks(h, homedir()) ? [h] : []);\n checks.push({ id: \"hook_duplicates\", ok: dupes.length === 0, ...(dupes.length ? { detail: `the Scopebond hook runs more than once per action for ${dupes.join(\", \")} (fix: ${process.platform === \"win32\" ? \"npx.cmd\" : \"npx\"} -y @scopebond/hook@${hookVersion()} dedupe)` } : {}) });\n const autostart = autostartHealth(dir);\n checks.push({ id: \"autostart\", ok: autostart.ok, ...(autostart.ok ? {} : { detail: autostart.detail }) });\n const { pending, oldest } = queueStatus(dir);\n const state = readDeliveryState(dir);\n const stuck = pending > 0 && oldest !== null && now - oldest > 60 * 60 * 1000;\n checks.push({ id: \"queue\", ok: !stuck, ...(stuck ? { detail: `${pending} record(s) waiting since ${new Date(oldest!).toISOString()}${state.last_error ? ` (${state.last_error.slice(0, 120)})` : \"\"}` } : {}) });\n const expires = Date.parse(connection.expires_at ?? \"\");\n const lapsing = Number.isFinite(expires) && expires - now < 7 * 24 * 60 * 60 * 1000;\n checks.push({ id: \"credential\", ok: !lapsing, ...(lapsing ? { detail: `the connection expires ${new Date(expires).toISOString()} and was not renewed` } : {}) });\n return checks;\n}\n\nexport async function runSelfCheck(\n dir: string, connection: HookConnection, harnesses: Harness[], agentVersion: string,\n options: { fetchImpl?: typeof fetch; now?: number; timeoutMs?: number } = {},\n): Promise<{ ok: boolean; signature_verified: boolean; failed: string[]; checks: SelfCheckItem[] } | null> {\n const now = options.now ?? Date.now();\n const checks = localChecks(dir, connection, harnesses, now);\n const keyFile = join(dir, \"attester.key\");\n if (!existsSync(keyFile)) return { ok: false, signature_verified: false, failed: [\"signing_key\"], checks };\n const day = new Date(now).toISOString().slice(0, 10);\n const { attester } = loadOrCreateAttester({ file: keyFile });\n const signature = await attester.sign(selfCheckProof(connection.credential_id, connection.gateway_id, day));\n try {\n const res = await (options.fetchImpl ?? fetch)(new URL(\"/v1/self-check\", connection.url).toString(), {\n method: \"POST\", redirect: \"error\", signal: AbortSignal.timeout(options.timeoutMs ?? 10_000),\n headers: { authorization: `Bearer ${connection.credential}`, \"content-type\": \"application/json\" },\n // install_kind: how this agent was installed (npm, per-user or per-machine signed installer), so the workspace can say\n // how the computer updates and is removed. A workspace that does not read it ignores it.\n body: JSON.stringify({ signature, day, checks, hook_version: hookVersion(), agent_version: agentVersion, install_kind: installKind() }),\n });\n // A workspace that does not offer the self-check yet answers 404: the computer's own checks still count; the signed\n // workspace part is simply not available there.\n if (res.status === 404) { const failed = checks.filter((c) => !c.ok).map((c) => c.id); return { ok: failed.length === 0, signature_verified: false, failed, checks }; }\n if (!res.ok) return { ok: false, signature_verified: false, failed: [`workspace_http_${res.status}`], checks };\n const body = await res.json() as { ok?: boolean; signature_verified?: boolean; failed?: string[] };\n return { ok: !!body.ok, signature_verified: !!body.signature_verified, failed: Array.isArray(body.failed) ? body.failed : [], checks };\n } catch (error) {\n return { ok: false, signature_verified: false, failed: [`workspace_unreachable: ${(error as Error).message.slice(0, 80)}`], checks };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"selfcheck.js","sourceRoot":"","sources":["../src/selfcheck.ts"],"names":[],"mappings":"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","sourcesContent":["// The daily end-to-end self-check (SB347). The agent checks this computer's side (the hook entry\n// is present and starts, autostart works, nothing is stuck, the connection is not about to lapse),\n// then signs the day with the key it enrolled with and sends everything to the workspace, which\n// verifies the signature. A pass means the whole path works, end to end; a failure names what broke.\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { canonical } from \"@scopebond/gateway\";\nimport { loadOrCreateAttester } from \"@scopebond/gateway/node\";\nimport {\n configuredHookCommands, duplicateHooks, hookCommandResolves, hookVersion, isScopebondHookCommand, queueStatus, readDeliveryState, userHarnessFile,\n type Harness, type HookConnection,\n} from \"@scopebond/hook\";\nimport { autostartHealth } from \"./autostart.js\";\nimport { installKind } from \"./native-update.js\";\n\nexport interface SelfCheckItem { id: string; ok: boolean; detail?: string }\n\nexport function selfCheckProof(credentialId: string, gatewayId: string, day: string): string {\n return canonical({ type: \"scopebond:self-check\", version: 1, credential_id: credentialId, gateway_id: gatewayId, day });\n}\n\nexport function localChecks(dir: string, connection: HookConnection, harnesses: Harness[], now = Date.now()): SelfCheckItem[] {\n const checks: SelfCheckItem[] = [];\n const entries = harnesses.flatMap((h) => configuredHookCommands(userHarnessFile(h)).filter((c) => isScopebondHookCommand(c)));\n checks.push({ id: \"hook_entry\", ok: entries.length > 0, ...(entries.length ? {} : { detail: \"no agent setting holds the Scopebond hook\" }) });\n const broken = entries.filter((c) => !hookCommandResolves(c));\n checks.push({ id: \"hook_starts\", ok: entries.length > 0 && broken.length === 0, ...(broken.length ? { detail: `${broken.length} hook command(s) cannot start` } : {}) });\n // SB302: the hook twice in the user settings, or an enabled plugin beside them, signs and sends every action twice.\n const dupes = harnesses.flatMap((h) => duplicateHooks(h, homedir()) ? [h] : []);\n checks.push({ id: \"hook_duplicates\", ok: dupes.length === 0, ...(dupes.length ? { detail: `the Scopebond hook runs more than once per action for ${dupes.join(\", \")} (fix: ${process.platform === \"win32\" ? \"npx.cmd\" : \"npx\"} -y @scopebond/hook@${hookVersion()} dedupe)` } : {}) });\n const autostart = autostartHealth(dir);\n checks.push({ id: \"autostart\", ok: autostart.ok, ...(autostart.ok ? {} : { detail: autostart.detail }) });\n const { pending, oldest } = queueStatus(dir);\n const state = readDeliveryState(dir);\n const stuck = pending > 0 && oldest !== null && now - oldest > 60 * 60 * 1000;\n checks.push({ id: \"queue\", ok: !stuck, ...(stuck ? { detail: `${pending} record(s) waiting since ${new Date(oldest).toISOString()}${state.last_error ? ` (${state.last_error.slice(0, 120)})` : \"\"}` } : {}) });\n const expires = Date.parse(connection.expires_at ?? \"\");\n const lapsing = Number.isFinite(expires) && expires - now < 7 * 24 * 60 * 60 * 1000;\n checks.push({ id: \"credential\", ok: !lapsing, ...(lapsing ? { detail: `the connection expires ${new Date(expires).toISOString()} and was not renewed` } : {}) });\n return checks;\n}\n\nexport async function runSelfCheck(\n dir: string, connection: HookConnection, harnesses: Harness[], agentVersion: string,\n options: { fetchImpl?: typeof fetch; now?: number; timeoutMs?: number } = {},\n): Promise<{ ok: boolean; signature_verified: boolean; failed: string[]; checks: SelfCheckItem[] } | null> {\n const now = options.now ?? Date.now();\n const checks = localChecks(dir, connection, harnesses, now);\n const keyFile = join(dir, \"attester.key\");\n if (!existsSync(keyFile)) return { ok: false, signature_verified: false, failed: [\"signing_key\"], checks };\n const day = new Date(now).toISOString().slice(0, 10);\n const { attester } = loadOrCreateAttester({ file: keyFile });\n const signature = await attester.sign(selfCheckProof(connection.credential_id, connection.gateway_id, day));\n try {\n const res = await (options.fetchImpl ?? fetch)(new URL(\"/v1/self-check\", connection.url).toString(), {\n method: \"POST\", redirect: \"error\", signal: AbortSignal.timeout(options.timeoutMs ?? 10_000),\n headers: { authorization: `Bearer ${connection.credential}`, \"content-type\": \"application/json\" },\n // install_kind: how this agent was installed (npm, per-user or per-machine signed installer), so the workspace can say\n // how the computer updates and is removed. A workspace that does not read it ignores it.\n body: JSON.stringify({ signature, day, checks, hook_version: hookVersion(), agent_version: agentVersion, install_kind: installKind() }),\n });\n // A workspace that does not offer the self-check yet answers 404: the computer's own checks still count; the signed\n // workspace part is simply not available there.\n if (res.status === 404) { const failed = checks.filter((c) => !c.ok).map((c) => c.id); return { ok: failed.length === 0, signature_verified: false, failed, checks }; }\n if (!res.ok) return { ok: false, signature_verified: false, failed: [`workspace_http_${res.status}`], checks };\n const body = await res.json() as { ok?: boolean; signature_verified?: boolean; failed?: string[] };\n return { ok: !!body.ok, signature_verified: !!body.signature_verified, failed: Array.isArray(body.failed) ? body.failed : [], checks };\n } catch (error) {\n return { ok: false, signature_verified: false, failed: [`workspace_unreachable: ${(error as Error).message.slice(0, 80)}`], checks };\n }\n}\n"]}
|
package/dist/setup.js
CHANGED
package/dist/setup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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","sourcesContent":["// `scopebond-agent setup <workspace-url>`: one command from nothing to a connected computer.\n// It checks Node, signs this person in with a code (which puts the hook in the user-level agent\n// settings), installs the agent for this user so autostart has a stable path, turns autostart on\n// and ends with `status`. Run again, it repairs what is missing and duplicates nothing: an\n// existing connection to the same workspace is kept, the same agent version is not reinstalled,\n// and the hook entry and autostart are put back only where they are gone.\n\nimport { spawn, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { hookSelfCommand, isSingleExecutable, loadConnection, nodeTooOldLines, readDeliveryState, type Harness } from \"@scopebond/hook\";\nimport { agentCliPath, agentSelfCommand } from \"./self.js\";\nimport { autostartHealth, enableAutostart, startNow } from \"./autostart.js\";\nimport { writeAppsEntry } from \"./apps-entry.js\";\nimport { installKind } from \"./native-update.js\";\nimport { callAgent } from \"./ipc.js\";\nimport { compareVersions, npmEnvironment, npmInstallArgs, ownNpm } from \"./update.js\";\nimport { repairHookEntries } from \"./service.js\";\n\nexport type SetupStep = \"login\" | \"install_agent\" | \"autostart\";\n\nexport interface SetupState {\n /** The workspace origin this computer's user-level connection points at, if any. */\n connectedTo: string | null;\n /** The workspace refused that connection's credential (it must sign in again). */\n credentialRefused: boolean;\n /** The agent version installed for this user with npm, if any. */\n installedVersion: string | null;\n /** Autostart is on and its launcher exists. */\n autostartOk: boolean;\n}\n\n/** What a setup run has to do, given what is already true. Pure, so a second run is provably a no-op\n * (or a repair) rather than a second sign-in or install. */\nexport function setupPlan(state: SetupState, origin: string, version: string, relogin = false): SetupStep[] {\n const steps: SetupStep[] = [];\n if (relogin || state.connectedTo !== origin || state.credentialRefused) steps.push(\"login\");\n const install = state.installedVersion === null || compareVersions(state.installedVersion, version) < 0;\n if (install) steps.push(\"install_agent\");\n if (install || !state.autostartOk) steps.push(\"autostart\");\n return steps;\n}\n\nexport function nodeSupported(version = process.versions.node): boolean {\n const [major, minor] = version.split(\".\").map(Number);\n return major > 22 || (major === 22 && minor >= 13);\n}\n\n/** The folder npm puts global commands in: the prefix itself on Windows, <prefix>/bin elsewhere. */\nexport function globalBinDir(prefix: string, platform: NodeJS.Platform = process.platform): string {\n return platform === \"win32\" ? prefix : join(prefix, \"bin\");\n}\n\n/** Whether `dir` is on PATH (case-insensitive on Windows, ignoring a trailing separator). */\nexport function onPath(dir: string, pathEnv = process.env.PATH ?? process.env.Path ?? \"\", platform: NodeJS.Platform = process.platform): boolean {\n const norm = (p: string) => {\n let t = p.trim();\n while (t.endsWith(\"/\") || t.endsWith(\"\\\\\")) t = t.slice(0, -1); // a loop, not a regex: PATH entries are untrusted input\n return platform === \"win32\" ? t.toLowerCase().replace(/\\//g, \"\\\\\") : t;\n };\n const target = norm(dir);\n return pathEnv.split(platform === \"win32\" ? \";\" : \":\").some((p) => p && norm(p) === target);\n}\n\n/** The PowerShell line that adds a folder to this user's PATH for new windows. */\nexport function addToPathCommand(dir: string): string {\n return `[Environment]::SetEnvironmentVariable(\"Path\", [Environment]::GetEnvironmentVariable(\"Path\", \"User\") + \";${dir}\", \"User\")`;\n}\n\nfunction npm(args: string[], env?: NodeJS.ProcessEnv): { ok: boolean; out: string } {\n const win = process.platform === \"win32\";\n // This Node's own npm, without a shell; otherwise npm on PATH (a .cmd on Windows, started through a shell, each argument quoted).\n const own = ownNpm();\n const r = own\n ? spawnSync(own[0], [...own[1], ...args], { encoding: \"utf8\", windowsHide: true, timeout: 5 * 60_000, env })\n : spawnSync(win ? \"npm.cmd\" : \"npm\", win ? args.map((a) => `\"${a}\"`) : args, { encoding: \"utf8\", shell: win, windowsHide: true, timeout: 5 * 60_000, env });\n return { ok: r.status === 0, out: `${r.stdout ?? \"\"}${r.stderr ?? \"\"}` };\n}\n\nfunction globalAgent(): { prefix: string | null; cli: string | null; version: string | null } {\n const prefix = npm([\"prefix\", \"-g\"]);\n const root = npm([\"root\", \"-g\"]);\n if (!root.ok) return { prefix: null, cli: null, version: null };\n const dir = join(root.out.trim().split(/\\r?\\n/).pop() ?? \"\", \"@scopebond\", \"agent\");\n const cli = join(dir, \"dist\", \"cli.js\");\n let version: string | null = null;\n try { version = (JSON.parse(readFileSync(join(dir, \"package.json\"), \"utf8\")) as { version?: string }).version ?? null; } catch { /* not installed */ }\n return { prefix: prefix.ok ? prefix.out.trim().split(/\\r?\\n/).pop() ?? null : null, cli: existsSync(cli) ? cli : null, version };\n}\n\n\n/** Where the agent setup works with: the signed single executable is already installed (its own version, no npm asked),\n * otherwise the copy in npm's global folder, if any. */\nexport function agentOnThisComputer(single: boolean, version: string, fromNpm: () => { prefix: string | null; cli: string | null; version: string | null } = globalAgent, self = agentCliPath): { prefix: string | null; cli: string | null; version: string | null } {\n return single ? { prefix: null, cli: self(), version } : fromNpm();\n}\n\nexport interface SetupOptions { dir: string; origin: string; harness: Harness; relogin: boolean; version: string; me: string }\n\nexport async function runSetup(o: SetupOptions): Promise<number> {\n const say = (line: string) => console.log(line);\n if (!nodeSupported()) { for (const line of nodeTooOldLines(process.versions.node)) console.error(line); return 1; }\n const connection = loadConnection(o.dir);\n let connectedTo: string | null = null;\n try { connectedTo = connection ? new URL(connection.url).origin : null; } catch { connectedTo = null; }\n // The signed installer put the agent (one executable with the hook) in place: nothing to install with npm, and no Node\n // or npm need be on this computer. Autostart then starts this executable itself.\n const single = isSingleExecutable();\n const global = agentOnThisComputer(single, o.version);\n const state: SetupState = {\n connectedTo,\n credentialRefused: readDeliveryState(o.dir).invalid_since != null,\n installedVersion: global.version,\n autostartOk: autostartHealth(o.dir).ok,\n };\n const steps = setupPlan(state, o.origin, o.version, o.relogin);\n say(`Setting up Scopebond for this user (${steps.length ? steps.join(\", \").replace(/_/g, \" \") : \"nothing missing\"}).`);\n\n // 1. Sign in with a code. The hook's own login prints the link and code and waits for approval.\n if (steps.includes(\"login\")) {\n const flag = o.harness === \"claude\" ? \"--claude\" : `--${o.harness}`;\n // From the home folder, so a project's own setup in the current folder can never take the sign-in;\n // and a failed sign-in names this setup command, which also installs and starts the agent.\n const harnessFlag = o.harness === \"claude\" ? \"\" : ` --${o.harness}`;\n const again = single\n ? `\"${process.execPath}\" setup ${o.origin}${harnessFlag}`\n : `${process.platform === \"win32\" ? \"npx.cmd\" : \"npx\"} -y @scopebond/agent@${o.version} setup ${o.origin}${harnessFlag}`;\n const [program, args] = hookSelfCommand([\"login\", o.origin, flag]);\n const r = spawnSync(program, args, { stdio: \"inherit\", cwd: homedir(), env: { ...process.env, SCOPEBOND_HOME: o.dir, SCOPEBOND_RETRY_COMMAND: again } });\n if (r.status !== 0) { console.error(\"Setup stopped: the sign-in did not finish. Run the same command again for a new code.\"); return 1; }\n } else {\n say(`✓ Already connected to ${o.origin} (to sign in again anyway, add --relogin).`);\n for (const fixed of repairHookEntries()) say(`✓ Put the Scopebond hook back in ${fixed.file}`);\n }\n\n // 2. The agent, installed for this user so autostart points at a path npm will not clear.\n let cli = global.cli;\n if (steps.includes(\"install_agent\")) {\n const spec = process.env.SCOPEBOND_AGENT_INSTALL_SPEC || `@scopebond/agent@${o.version}`;\n say(`Installing the Scopebond Agent for this user: ${process.platform === \"win32\" ? \"npm.cmd\" : \"npm\"} install -g ${spec}`);\n // Package scripts off and the public registry pinned, as the agent's own updates do.\n const installed = npm(npmInstallArgs(spec), npmEnvironment());\n if (!installed.ok) { console.error(`Setup stopped: npm could not install the agent.\\n${installed.out.slice(-1500)}`); return 1; }\n cli = globalAgent().cli;\n if (!cli) { console.error(\"Setup stopped: npm reported success but the agent is not in npm's global folder.\"); return 1; }\n } else say(single ? `✓ The Scopebond Agent ${global.version} is installed (signed installer).` : `✓ The Scopebond Agent ${global.version} is installed for this user.`);\n const bin = global.prefix ? globalBinDir(global.prefix) : null;\n if (bin && !onPath(bin)) {\n say(`Note: npm's global folder ${bin} is not on PATH, so new terminals will not find ${o.me}.`);\n say(process.platform === \"win32\"\n ? ` Add it for your user in PowerShell, then open a new window: ${addToPathCommand(bin)}\n (or: Start, \"Edit environment variables for your account\", Path, New)`\n : ` Add it to PATH in your shell profile: export PATH=\"${bin}:$PATH\"`);\n }\n\n // 3. Autostart, and the agent running now.\n if (steps.includes(\"autostart\") && cli) {\n say(enableAutostart(o.dir, cli));\n } else say(\"✓ The agent already starts with your sign-in.\");\n // Listed in Settings -> Apps, so it can be removed there like any other app (refreshed each run: the version moves).\n if (cli && process.platform === \"win32\" && installKind() === \"npm\") {\n try { const listed = writeAppsEntry(o.dir, { version: globalAgent().version ?? o.version, cli }); if (listed) say(`✓ ${listed}`); }\n catch (error) { say(`Note: could not list Scopebond in Settings -> Apps (${(error as Error).message}).`); }\n }\n if (cli && !await callAgent(o.dir, \"GET\", \"/status\", undefined, 2_000)) {\n const up = async (tries: number) => {\n for (let i = 0; i < tries; i++) { if (await callAgent(o.dir, \"GET\", \"/status\", undefined, 1_000)) return true; await new Promise((r) => setTimeout(r, 500)); }\n return false;\n };\n if (process.platform === \"win32\") {\n // The headless console first; where it does not start, the launcher through a hidden cmd.exe.\n if (!(startNow(o.dir, \"win32\", 0) && await up(12))) { startNow(o.dir, \"win32\", 1); await up(18); }\n } else {\n // No systemd user session (a container, WSL without systemd): run it detached until the next sign-in.\n if (!await up(10) && process.platform === \"linux\") {\n const [program, args] = single ? agentSelfCommand([\"run\"]) : [process.execPath, [cli, \"run\"]];\n spawn(program, args, { detached: true, stdio: \"ignore\", env: { ...process.env, SCOPEBOND_HOME: o.dir } }).unref();\n }\n await up(20);\n }\n }\n\n // 4. Status, from the installed agent.\n say(\"\");\n const [statusProgram, statusArgs] = single ? agentSelfCommand([\"status\"]) : [process.execPath, [cli ?? process.argv[1], \"status\"]];\n const status = spawnSync(statusProgram, statusArgs, { stdio: \"inherit\", env: { ...process.env, SCOPEBOND_HOME: o.dir } });\n return status.status === 0 ? 0 : 1;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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","sourcesContent":["// `scopebond-agent setup <workspace-url>`: one command from nothing to a connected computer.\n// It checks Node, signs this person in with a code (which puts the hook in the user-level agent\n// settings), installs the agent for this user so autostart has a stable path, turns autostart on\n// and ends with `status`. Run again, it repairs what is missing and duplicates nothing: an\n// existing connection to the same workspace is kept, the same agent version is not reinstalled,\n// and the hook entry and autostart are put back only where they are gone.\n\nimport { spawn, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { hookSelfCommand, isSingleExecutable, loadConnection, nodeTooOldLines, readDeliveryState, type Harness } from \"@scopebond/hook\";\nimport { agentCliPath, agentSelfCommand } from \"./self.js\";\nimport { autostartHealth, enableAutostart, startNow } from \"./autostart.js\";\nimport { writeAppsEntry } from \"./apps-entry.js\";\nimport { installKind } from \"./native-update.js\";\nimport { callAgent } from \"./ipc.js\";\nimport { compareVersions, npmEnvironment, npmInstallArgs, ownNpm } from \"./update.js\";\nimport { repairHookEntries } from \"./service.js\";\n\nexport type SetupStep = \"login\" | \"install_agent\" | \"autostart\";\n\nexport interface SetupState {\n /** The workspace origin this computer's user-level connection points at, if any. */\n connectedTo: string | null;\n /** The workspace refused that connection's credential (it must sign in again). */\n credentialRefused: boolean;\n /** The agent version installed for this user with npm, if any. */\n installedVersion: string | null;\n /** Autostart is on and its launcher exists. */\n autostartOk: boolean;\n}\n\n/** What a setup run has to do, given what is already true. Pure, so a second run is provably a no-op\n * (or a repair) rather than a second sign-in or install. */\nexport function setupPlan(state: SetupState, origin: string, version: string, relogin = false): SetupStep[] {\n const steps: SetupStep[] = [];\n if (relogin || state.connectedTo !== origin || state.credentialRefused) steps.push(\"login\");\n const install = state.installedVersion === null || compareVersions(state.installedVersion, version) < 0;\n if (install) steps.push(\"install_agent\");\n if (install || !state.autostartOk) steps.push(\"autostart\");\n return steps;\n}\n\nexport function nodeSupported(version = process.versions.node): boolean {\n const [major, minor] = version.split(\".\").map(Number);\n return major > 22 || (major === 22 && minor >= 13);\n}\n\n/** The folder npm puts global commands in: the prefix itself on Windows, <prefix>/bin elsewhere. */\nexport function globalBinDir(prefix: string, platform: NodeJS.Platform = process.platform): string {\n return platform === \"win32\" ? prefix : join(prefix, \"bin\");\n}\n\n/** Whether `dir` is on PATH (case-insensitive on Windows, ignoring a trailing separator). */\nexport function onPath(dir: string, pathEnv = process.env.PATH ?? process.env.Path ?? \"\", platform: NodeJS.Platform = process.platform): boolean {\n const norm = (p: string) => {\n let t = p.trim();\n while (t.endsWith(\"/\") || t.endsWith(\"\\\\\")) t = t.slice(0, -1); // a loop, not a regex: PATH entries are untrusted input\n return platform === \"win32\" ? t.toLowerCase().replace(/\\//g, \"\\\\\") : t;\n };\n const target = norm(dir);\n return pathEnv.split(platform === \"win32\" ? \";\" : \":\").some((p) => p && norm(p) === target);\n}\n\n/** The PowerShell line that adds a folder to this user's PATH for new windows. */\nexport function addToPathCommand(dir: string): string {\n return `[Environment]::SetEnvironmentVariable(\"Path\", [Environment]::GetEnvironmentVariable(\"Path\", \"User\") + \";${dir}\", \"User\")`;\n}\n\nfunction npm(args: string[], env?: NodeJS.ProcessEnv): { ok: boolean; out: string } {\n const win = process.platform === \"win32\";\n // This Node's own npm, without a shell; otherwise npm on PATH (a .cmd on Windows, started through a shell, each argument quoted).\n const own = ownNpm();\n const r = own\n ? spawnSync(own[0], [...own[1], ...args], { encoding: \"utf8\", windowsHide: true, timeout: 5 * 60_000, env })\n : spawnSync(win ? \"npm.cmd\" : \"npm\", win ? args.map((a) => `\"${a}\"`) : args, { encoding: \"utf8\", shell: win, windowsHide: true, timeout: 5 * 60_000, env });\n return { ok: r.status === 0, out: `${r.stdout ?? \"\"}${r.stderr ?? \"\"}` };\n}\n\nfunction globalAgent(): { prefix: string | null; cli: string | null; version: string | null } {\n const prefix = npm([\"prefix\", \"-g\"]);\n const root = npm([\"root\", \"-g\"]);\n if (!root.ok) return { prefix: null, cli: null, version: null };\n const dir = join(root.out.trim().split(/\\r?\\n/).pop() ?? \"\", \"@scopebond\", \"agent\");\n const cli = join(dir, \"dist\", \"cli.js\");\n let version: string | null = null;\n try { version = (JSON.parse(readFileSync(join(dir, \"package.json\"), \"utf8\")) as { version?: string }).version ?? null; } catch { /* not installed */ }\n return { prefix: prefix.ok ? prefix.out.trim().split(/\\r?\\n/).pop() ?? null : null, cli: existsSync(cli) ? cli : null, version };\n}\n\n\n/** Where the agent setup works with: the signed single executable is already installed (its own version, no npm asked),\n * otherwise the copy in npm's global folder, if any. */\nexport function agentOnThisComputer(single: boolean, version: string, fromNpm: () => { prefix: string | null; cli: string | null; version: string | null } = globalAgent, self = agentCliPath): { prefix: string | null; cli: string | null; version: string | null } {\n return single ? { prefix: null, cli: self(), version } : fromNpm();\n}\n\nexport interface SetupOptions { dir: string; origin: string; harness: Harness; relogin: boolean; version: string; me: string }\n\nexport async function runSetup(o: SetupOptions): Promise<number> {\n const say = (line: string) => console.log(line);\n if (!nodeSupported()) { for (const line of nodeTooOldLines(process.versions.node)) console.error(line); return 1; }\n const connection = loadConnection(o.dir);\n let connectedTo: string | null;\n try { connectedTo = connection ? new URL(connection.url).origin : null; } catch { connectedTo = null; }\n // The signed installer put the agent (one executable with the hook) in place: nothing to install with npm, and no Node\n // or npm need be on this computer. Autostart then starts this executable itself.\n const single = isSingleExecutable();\n const global = agentOnThisComputer(single, o.version);\n const state: SetupState = {\n connectedTo,\n credentialRefused: readDeliveryState(o.dir).invalid_since != null,\n installedVersion: global.version,\n autostartOk: autostartHealth(o.dir).ok,\n };\n const steps = setupPlan(state, o.origin, o.version, o.relogin);\n say(`Setting up Scopebond for this user (${steps.length ? steps.join(\", \").replace(/_/g, \" \") : \"nothing missing\"}).`);\n\n // 1. Sign in with a code. The hook's own login prints the link and code and waits for approval.\n if (steps.includes(\"login\")) {\n const flag = o.harness === \"claude\" ? \"--claude\" : `--${o.harness}`;\n // From the home folder, so a project's own setup in the current folder can never take the sign-in;\n // and a failed sign-in names this setup command, which also installs and starts the agent.\n const harnessFlag = o.harness === \"claude\" ? \"\" : ` --${o.harness}`;\n const again = single\n ? `\"${process.execPath}\" setup ${o.origin}${harnessFlag}`\n : `${process.platform === \"win32\" ? \"npx.cmd\" : \"npx\"} -y @scopebond/agent@${o.version} setup ${o.origin}${harnessFlag}`;\n const [program, args] = hookSelfCommand([\"login\", o.origin, flag]);\n const r = spawnSync(program, args, { stdio: \"inherit\", cwd: homedir(), env: { ...process.env, SCOPEBOND_HOME: o.dir, SCOPEBOND_RETRY_COMMAND: again } });\n if (r.status !== 0) { console.error(\"Setup stopped: the sign-in did not finish. Run the same command again for a new code.\"); return 1; }\n } else {\n say(`✓ Already connected to ${o.origin} (to sign in again anyway, add --relogin).`);\n for (const fixed of repairHookEntries()) say(`✓ Put the Scopebond hook back in ${fixed.file}`);\n }\n\n // 2. The agent, installed for this user so autostart points at a path npm will not clear.\n let cli = global.cli;\n if (steps.includes(\"install_agent\")) {\n const spec = process.env.SCOPEBOND_AGENT_INSTALL_SPEC || `@scopebond/agent@${o.version}`;\n say(`Installing the Scopebond Agent for this user: ${process.platform === \"win32\" ? \"npm.cmd\" : \"npm\"} install -g ${spec}`);\n // Package scripts off and the public registry pinned, as the agent's own updates do.\n const installed = npm(npmInstallArgs(spec), npmEnvironment());\n if (!installed.ok) { console.error(`Setup stopped: npm could not install the agent.\\n${installed.out.slice(-1500)}`); return 1; }\n cli = globalAgent().cli;\n if (!cli) { console.error(\"Setup stopped: npm reported success but the agent is not in npm's global folder.\"); return 1; }\n } else say(single ? `✓ The Scopebond Agent ${global.version} is installed (signed installer).` : `✓ The Scopebond Agent ${global.version} is installed for this user.`);\n const bin = global.prefix ? globalBinDir(global.prefix) : null;\n if (bin && !onPath(bin)) {\n say(`Note: npm's global folder ${bin} is not on PATH, so new terminals will not find ${o.me}.`);\n say(process.platform === \"win32\"\n ? ` Add it for your user in PowerShell, then open a new window: ${addToPathCommand(bin)}\n (or: Start, \"Edit environment variables for your account\", Path, New)`\n : ` Add it to PATH in your shell profile: export PATH=\"${bin}:$PATH\"`);\n }\n\n // 3. Autostart, and the agent running now.\n if (steps.includes(\"autostart\") && cli) {\n say(enableAutostart(o.dir, cli));\n } else say(\"✓ The agent already starts with your sign-in.\");\n // Listed in Settings -> Apps, so it can be removed there like any other app (refreshed each run: the version moves).\n if (cli && process.platform === \"win32\" && installKind() === \"npm\") {\n try { const listed = writeAppsEntry(o.dir, { version: globalAgent().version ?? o.version, cli }); if (listed) say(`✓ ${listed}`); }\n catch (error) { say(`Note: could not list Scopebond in Settings -> Apps (${(error as Error).message}).`); }\n }\n if (cli && !await callAgent(o.dir, \"GET\", \"/status\", undefined, 2_000)) {\n const up = async (tries: number) => {\n for (let i = 0; i < tries; i++) { if (await callAgent(o.dir, \"GET\", \"/status\", undefined, 1_000)) return true; await new Promise((r) => setTimeout(r, 500)); }\n return false;\n };\n if (process.platform === \"win32\") {\n // The headless console first; where it does not start, the launcher through a hidden cmd.exe.\n if (!(startNow(o.dir, \"win32\", 0) && await up(12))) { startNow(o.dir, \"win32\", 1); await up(18); }\n } else {\n // No systemd user session (a container, WSL without systemd): run it detached until the next sign-in.\n if (!await up(10) && process.platform === \"linux\") {\n const [program, args] = single ? agentSelfCommand([\"run\"]) : [process.execPath, [cli, \"run\"]];\n spawn(program, args, { detached: true, stdio: \"ignore\", env: { ...process.env, SCOPEBOND_HOME: o.dir } }).unref();\n }\n await up(20);\n }\n }\n\n // 4. Status, from the installed agent.\n say(\"\");\n const [statusProgram, statusArgs] = single ? agentSelfCommand([\"status\"]) : [process.execPath, [cli ?? process.argv[1], \"status\"]];\n const status = spawnSync(statusProgram, statusArgs, { stdio: \"inherit\", env: { ...process.env, SCOPEBOND_HOME: o.dir } });\n return status.status === 0 ? 0 : 1;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scopebond/agent",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Free, open-source Scopebond Agent companion: deliver queued records, maintain rules and connections, and report computer health to the separate proprietary Scopebond Cloud workspace.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Avouro LLC",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"dist"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@scopebond/
|
|
43
|
-
"@scopebond/
|
|
44
|
-
"@scopebond/
|
|
42
|
+
"@scopebond/gateway": "0.17.5",
|
|
43
|
+
"@scopebond/sdk": "0.1.7",
|
|
44
|
+
"@scopebond/hook": "0.21.7"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"access": "public"
|