@zswarm/core 0.2.0 → 0.2.2
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/README.md +4 -4
- package/dist/host/cli.js +1 -1
- package/dist/host/relay.js +2 -0
- package/dist/host/services.d.ts +7 -6
- package/dist/host/services.js +28 -20
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ the CLI flags, and the CLI help, so they cannot drift.
|
|
|
10
10
|
npm install @zswarm/core
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
From a checkout of this repo:
|
|
13
|
+
From a checkout of this repo (build first with `pnpm build`):
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
npm install ./packages/core
|
|
@@ -36,11 +36,11 @@ SSH LocalForward and calls `probeServe` before ops (including before reuse);
|
|
|
36
36
|
pass a `serveTunnels` manager if the caller (MCP) should reuse it. Omitting
|
|
37
37
|
the SSH port leaves `Port` to OpenSSH instead of forcing 22. `tcp://` also
|
|
38
38
|
names a private Tailscale Serve frontend over a loopback backend; see
|
|
39
|
-
[Tailscale crew](
|
|
39
|
+
[Tailscale crew](https://github.com/brandonkramer/zswarm/blob/master/docs/tailscale.md).
|
|
40
40
|
|
|
41
|
-
Spawn lifecycle, body files, guarded keys, status tabs and routing context: [crew operations](
|
|
41
|
+
Spawn lifecycle, body files, guarded keys, status tabs and routing context: [crew operations](https://github.com/brandonkramer/zswarm/blob/master/docs/crew-operations.md).
|
|
42
42
|
|
|
43
|
-
Ops, env, and the event bus: the [zswarm README](
|
|
43
|
+
Ops, env, and the event bus: the [zswarm README](https://github.com/brandonkramer/zswarm#readme).
|
|
44
44
|
|
|
45
45
|
## License
|
|
46
46
|
|
package/dist/host/cli.js
CHANGED
|
@@ -183,7 +183,7 @@ const COMMANDS = {
|
|
|
183
183
|
"zswarm host install --ssh DEST [--sudo] [--prefix /usr/local/lib/zswarm] [--bin-dir /usr/local/bin]",
|
|
184
184
|
" [--node V] [--zellij V] [--zswarm V] Node.js, zswarm and Zellij on a Linux/macOS host",
|
|
185
185
|
"zswarm host install --script [same options] print the script (run it as: sh -s -- <args printed on stderr>)",
|
|
186
|
-
"zswarm host doctor
|
|
186
|
+
"zswarm host doctor (--ssh DEST | --serve TARGET) [--session S] tools, disk, services, serve, session, panes",
|
|
187
187
|
].join("\n"),
|
|
188
188
|
run: host,
|
|
189
189
|
},
|
package/dist/host/relay.js
CHANGED
|
@@ -293,6 +293,7 @@ export function launchRelay(dir, env = process.env) {
|
|
|
293
293
|
"submit", "-l", label, "-o", log, "-e", log, "--",
|
|
294
294
|
"/usr/bin/env", `PATH=${env.PATH ?? "/usr/bin:/bin"}`, `HOME=${env.HOME ?? ""}`,
|
|
295
295
|
...(env.ZSWARM_STATE_DIR ? [`ZSWARM_STATE_DIR=${env.ZSWARM_STATE_DIR}`] : []),
|
|
296
|
+
...(env.ZSWARM_RELAY_DELAYS ? [`ZSWARM_RELAY_DELAYS=${env.ZSWARM_RELAY_DELAYS}`] : []),
|
|
296
297
|
`ZSWARM_RELAY_LABEL=${label}`, ...argv,
|
|
297
298
|
], { encoding: "utf8" });
|
|
298
299
|
if (res.status !== 0)
|
|
@@ -304,6 +305,7 @@ export function launchRelay(dir, env = process.env) {
|
|
|
304
305
|
const res = spawnSync("systemd-run", ["--user", "--collect", "--quiet", `--unit=${unit}`,
|
|
305
306
|
`--setenv=PATH=${env.PATH ?? "/usr/bin:/bin"}`,
|
|
306
307
|
...(env.ZSWARM_STATE_DIR ? [`--setenv=ZSWARM_STATE_DIR=${env.ZSWARM_STATE_DIR}`] : []),
|
|
308
|
+
...(env.ZSWARM_RELAY_DELAYS ? [`--setenv=ZSWARM_RELAY_DELAYS=${env.ZSWARM_RELAY_DELAYS}`] : []),
|
|
307
309
|
...argv], { encoding: "utf8" });
|
|
308
310
|
if (res.status === 0)
|
|
309
311
|
return `systemd unit ${unit}`;
|
package/dist/host/services.d.ts
CHANGED
|
@@ -66,14 +66,15 @@ export declare const defaultRunner: Runner;
|
|
|
66
66
|
/** The account services are installed for: the current user, or `runAs` when root. */
|
|
67
67
|
export declare function serviceAccount(runAs?: string, run?: Runner): ServiceAccount;
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
69
|
+
* The argv prefix that runs a command as the account: `runuser` on Linux,
|
|
70
|
+
* `sudo -u` on macOS. Root writes into the account's home through it, so the
|
|
71
71
|
* kernel refuses what the account itself could not do (a symlink it planted
|
|
72
|
-
* towards a root-owned file, say) and new files are the account's own.
|
|
73
|
-
*
|
|
72
|
+
* towards a root-owned file, say) and new files are the account's own. (Not
|
|
73
|
+
* seteuid in this process: Node disables it on Linux while io_uring may be
|
|
74
|
+
* enabled, CVE-2024-22017.)
|
|
74
75
|
*/
|
|
75
|
-
export declare function
|
|
76
|
-
/** Write a file in the account's home as the account (see
|
|
76
|
+
export declare function accountArgv(account: ServiceAccount): string[];
|
|
77
|
+
/** Write a file in the account's home as the account (see accountArgv). */
|
|
77
78
|
export declare function writeAccountFile(account: ServiceAccount, path: string, text: string | Buffer, mode: number): void;
|
|
78
79
|
export declare function systemdUnitName(name: string, kind: ServiceKind): string;
|
|
79
80
|
export declare function systemdUnits(spec: ServiceSpec): Array<{
|
package/dist/host/services.js
CHANGED
|
@@ -38,33 +38,38 @@ export function serviceAccount(runAs, run = defaultRunner) {
|
|
|
38
38
|
throw new ZellijError("usage", `cannot find the home of ${target}`);
|
|
39
39
|
return { platform, user: target, uid: id("-u"), gid: id("-g"), home, foreign: true };
|
|
40
40
|
}
|
|
41
|
+
/** Root installing for another account (`--run-as`). */
|
|
42
|
+
function installingFor(account) {
|
|
43
|
+
return account.foreign && typeof process.geteuid === "function" && process.geteuid() === 0;
|
|
44
|
+
}
|
|
41
45
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
46
|
+
* The argv prefix that runs a command as the account: `runuser` on Linux,
|
|
47
|
+
* `sudo -u` on macOS. Root writes into the account's home through it, so the
|
|
44
48
|
* kernel refuses what the account itself could not do (a symlink it planted
|
|
45
|
-
* towards a root-owned file, say) and new files are the account's own.
|
|
46
|
-
*
|
|
49
|
+
* towards a root-owned file, say) and new files are the account's own. (Not
|
|
50
|
+
* seteuid in this process: Node disables it on Linux while io_uring may be
|
|
51
|
+
* enabled, CVE-2024-22017.)
|
|
47
52
|
*/
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
process.seteuid(0);
|
|
59
|
-
process.setegid(0);
|
|
53
|
+
export function accountArgv(account) {
|
|
54
|
+
return account.platform === "linux"
|
|
55
|
+
? ["runuser", "-u", account.user, "--"]
|
|
56
|
+
: ["sudo", "-n", "-u", account.user, "-H", "--"];
|
|
57
|
+
}
|
|
58
|
+
function runAsAccount(account, argv, input) {
|
|
59
|
+
const [cmd, ...rest] = [...accountArgv(account), ...argv];
|
|
60
|
+
const res = spawnSync(cmd, rest, { input, encoding: "utf8" });
|
|
61
|
+
if (res.status !== 0) {
|
|
62
|
+
throw new ZellijError("failed", `${argv[0]} as ${account.user} failed: ${(res.stderr || res.error?.message || "").trim().slice(0, 300)}`);
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
|
-
/** Write a file in the account's home as the account (see
|
|
65
|
+
/** Write a file in the account's home as the account (see accountArgv). */
|
|
63
66
|
export function writeAccountFile(account, path, text, mode) {
|
|
64
|
-
|
|
67
|
+
if (!installingFor(account)) {
|
|
65
68
|
writeFileSync(path, text, { mode });
|
|
66
69
|
chmodSync(path, mode);
|
|
67
|
-
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
runAsAccount(account, ["sh", "-c", 'umask 077 && cat > "$1" && chmod "$2" "$1"', "sh", path, mode.toString(8)], text);
|
|
68
73
|
}
|
|
69
74
|
function realFs(account) {
|
|
70
75
|
return {
|
|
@@ -319,7 +324,10 @@ export function ensureAccountDir(account, dir, mode = 0o700) {
|
|
|
319
324
|
for (let d = dir; d && d !== "/" && !existsSync(d); d = d.slice(0, d.lastIndexOf("/")) || "/")
|
|
320
325
|
missing.unshift(d);
|
|
321
326
|
for (const d of missing) {
|
|
322
|
-
|
|
327
|
+
if (installingFor(account))
|
|
328
|
+
runAsAccount(account, ["mkdir", "-m", mode.toString(8), d]);
|
|
329
|
+
else
|
|
330
|
+
mkdirSync(d, { mode });
|
|
323
331
|
}
|
|
324
332
|
}
|
|
325
333
|
/** Write a mode-600 file for the account, creating its directory (700) as needed. */
|
package/dist/index.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export { cliUsage, mcpInputSchema, parseCliArgv, MCP_TOOL_DESCRIPTION, OP_NAMES,
|
|
|
32
32
|
export { HOST_COMMANDS, hostUsage, parseHostArgs, runHostCommand } from "./host/cli.js";
|
|
33
33
|
export { findPython, runSlot, slotScriptPath } from "./host/slot.js";
|
|
34
34
|
export { installServeService, serveServiceName, serveServiceSpec, serveTokenFromEnv, serveTokenPath, uninstallServeService, SERVE_AWAIT_SESSION_ENV, SERVE_TOKEN_FILE_ENV, type ServeServiceInput, } from "./host/serve-service.js";
|
|
35
|
-
export {
|
|
35
|
+
export { accountArgv, installServices, launchdLabel, launchdPlist, removeServices, serviceAccount, serviceStates, systemdUnitName, systemdUnits, writeAccountFile, type Runner, type ServiceAccount, type ServiceHost, type ServiceKind, type ServiceSpec, type ServiceState, } from "./host/services.js";
|
|
36
36
|
export { crewCheck, crewDir, crewDown, crewServiceSpecs, crewStart, crewStatus, crewUp, firstLayoutPane, parseEnvFile, CREW_UNIT_ENV, CREW_WATCH_SEC, type CrewDeps, type CrewUpInput, } from "./host/crew.js";
|
|
37
37
|
export { deliverMessage, doneLines, fillMessage, freshDoneLine, launchRelay, prepareRelay, pruneRelays, relayLoop, relaysDir, runRelayDir, scrubRelayToken, startRelay, waitForRelay, type RelayConfig, type RelayDeps, type RelayStartInput, type RelayStatus, } from "./host/relay.js";
|
|
38
38
|
export { hostChecks, hostDoctor, hostInstall, hostInstallArgs, hostScriptPath, parseHostReport, type HostCheck, type HostDoctorInput, type HostInstallInput, type SshRunner, } from "./host/host.js";
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@ export { cliUsage, mcpInputSchema, parseCliArgv, MCP_TOOL_DESCRIPTION, OP_NAMES,
|
|
|
30
30
|
export { HOST_COMMANDS, hostUsage, parseHostArgs, runHostCommand } from "./host/cli.js";
|
|
31
31
|
export { findPython, runSlot, slotScriptPath } from "./host/slot.js";
|
|
32
32
|
export { installServeService, serveServiceName, serveServiceSpec, serveTokenFromEnv, serveTokenPath, uninstallServeService, SERVE_AWAIT_SESSION_ENV, SERVE_TOKEN_FILE_ENV, } from "./host/serve-service.js";
|
|
33
|
-
export {
|
|
33
|
+
export { accountArgv, installServices, launchdLabel, launchdPlist, removeServices, serviceAccount, serviceStates, systemdUnitName, systemdUnits, writeAccountFile, } from "./host/services.js";
|
|
34
34
|
export { crewCheck, crewDir, crewDown, crewServiceSpecs, crewStart, crewStatus, crewUp, firstLayoutPane, parseEnvFile, CREW_UNIT_ENV, CREW_WATCH_SEC, } from "./host/crew.js";
|
|
35
35
|
export { deliverMessage, doneLines, fillMessage, freshDoneLine, launchRelay, prepareRelay, pruneRelays, relayLoop, relaysDir, runRelayDir, scrubRelayToken, startRelay, waitForRelay, } from "./host/relay.js";
|
|
36
36
|
export { hostChecks, hostDoctor, hostInstall, hostInstallArgs, hostScriptPath, parseHostReport, } from "./host/host.js";
|