svamp-cli 0.2.342 → 0.2.356
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/bin/skills/artifact/SKILL.md +19 -5
- package/bin/skills/crew/SKILL.md +62 -13
- package/dist/DefaultTransport-vfp78fug.mjs +47 -0
- package/dist/GeminiTransport-3OkhtFRO.mjs +130 -0
- package/dist/KimiTransport-D8n009Tr.mjs +141 -0
- package/dist/acpAgentConfig-CObOPlA8.mjs +48 -0
- package/dist/acpBackend-UaBD4zL3.mjs +925 -0
- package/dist/{adminCommands-CRTBDZan.mjs → adminCommands-BvsYnRDA.mjs} +2 -18
- package/dist/{agentCommands-BuO988tJ.mjs → agentCommands-D91RcjqQ.mjs} +6 -23
- package/dist/api-BHjyC0Ph.mjs +157 -0
- package/dist/{auth--WS0wezs.mjs → auth-CRz8TsEl.mjs} +1 -22
- package/dist/bootStatus-DqtNgJch.mjs +143 -0
- package/dist/claudeAuth-C0wc1GTM.mjs +291 -0
- package/dist/cli.mjs +2948 -5
- package/dist/codexAppServerBackend-VGsYtbqg.mjs +786 -0
- package/dist/codexProvider-BtxYc5Rj.mjs +68 -0
- package/dist/{commands-DDuGBSsz.mjs → commands-B-yczgz_.mjs} +115 -49
- package/dist/{commands-DU4B-4Gh.mjs → commands-BMeDrpSv.mjs} +55 -25
- package/dist/{commands-DXLOKJOj.mjs → commands-BbmypSgx.mjs} +62 -27
- package/dist/{commands-C0HQiu-S.mjs → commands-BkdbelFo.mjs} +78 -38
- package/dist/{commands-DXM17M6n.mjs → commands-C13-yE2R.mjs} +42 -19
- package/dist/{commands-BKb1g8Gq.mjs → commands-CoOc4qiw.mjs} +20 -30
- package/dist/{commands-BsKgZ5sQ.mjs → commands-DW5RnHZw.mjs} +2 -19
- package/dist/{commands-Cwxy-C5N.mjs → commands-sPvRcG3J.mjs} +10 -32
- package/dist/cron-hHGdb5kU.mjs +132 -0
- package/dist/detectIsolation-CrV8IFDv.mjs +339 -0
- package/dist/envFlag-COOuJ3AH.mjs +11 -0
- package/dist/fileLock-BMPwCrB6.mjs +80 -0
- package/dist/{fleet-BHzlAvnu.mjs → fleet-Ca-UjJNL.mjs} +122 -36
- package/dist/flushExit-C-i6SGjj.mjs +37 -0
- package/dist/friendlyName-1UZcyDhu.mjs +586 -0
- package/dist/{headlessCli-C2gvOpOt.mjs → headlessCli-C8HzQvis.mjs} +3 -21
- package/dist/hookSettings-FFc1pi8j.mjs +10546 -0
- package/dist/{httpServer-Be1Hcddr.mjs → httpServer-BzEDbOGn.mjs} +14 -5
- package/dist/hyphaClient-ybivOjZo.mjs +49 -0
- package/dist/index.mjs +40 -8
- package/dist/instance-CeHz5C8v.mjs +203 -0
- package/dist/kimiProvider-DbxODebR.mjs +69 -0
- package/dist/kimiSetup-NGsoYB5h.mjs +48 -0
- package/dist/loopVerify-DALtTk2V.mjs +444 -0
- package/dist/machineTools-DygM1jXW.mjs +580 -0
- package/dist/model-CUHojegn.mjs +66 -0
- package/dist/{notifyCommands-0aZUwKQK.mjs → notifyCommands-CCUE18Q-.mjs} +3 -18
- package/dist/package-BrsiNutS.mjs +64 -0
- package/dist/pinnedCodex-XW4qvOAe.mjs +11 -0
- package/dist/pinnedNono-5ZHb6328.mjs +15 -0
- package/dist/{rpc-rAQQ1q8t.mjs → rpc-CBkSkzsI.mjs} +38 -6
- package/dist/{rpc-B2Lc2BAB.mjs → rpc-ccY7xvlo.mjs} +33 -22
- package/dist/{run-C7QVfyw4.mjs → run-DCq3aEiF.mjs} +17 -9
- package/dist/run-DDmeV9K3.mjs +9826 -0
- package/dist/sandboxDetect-Cdzsj5TC.mjs +19 -0
- package/dist/{scheduler-CzF4lOe_.mjs → scheduler-BkVJ27Ki.mjs} +38 -6
- package/dist/securityContext-Cm5UTCuD.mjs +218 -0
- package/dist/serveAuth-4M0vwMyj.mjs +460 -0
- package/dist/{serveCommands-EIEqdaVu.mjs → serveCommands-CLhkccJM.mjs} +13 -34
- package/dist/sharingNotificationSync-qGIQ-3yf.mjs +359 -0
- package/dist/{sideband-BoutiRJi.mjs → sideband-68HhGT0i.mjs} +1 -21
- package/dist/store-B4E6NzG6.mjs +356 -0
- package/dist/store-fi0f-ff1.mjs +184 -0
- package/dist/types-57J3Re0n.mjs +17 -0
- package/dist/wantsHelp-6bMOeNUz.mjs +5 -0
- package/dist/wrapCommand-CdNawSaa.mjs +117 -0
- package/package.json +3 -3
- package/dist/cli-B24CmIli.mjs +0 -2780
- package/dist/package-CTbGYaJG.mjs +0 -64
- package/dist/run-CF4kAVPW.mjs +0 -26508
- package/dist/sandboxDetect-DNTcbgWD.mjs +0 -12
|
@@ -1,26 +1,12 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import os from 'node:os';
|
|
4
|
-
import {
|
|
4
|
+
import { c as connectToHypha } from './hyphaClient-ybivOjZo.mjs';
|
|
5
5
|
import { PINNED_CLAUDE_CODE_VERSION } from './pinnedClaudeCode-LCVY4Otm.mjs';
|
|
6
|
-
import '
|
|
7
|
-
import '
|
|
8
|
-
import 'fs';
|
|
9
|
-
import 'path';
|
|
10
|
-
import 'url';
|
|
11
|
-
import 'child_process';
|
|
12
|
-
import 'crypto';
|
|
13
|
-
import 'node:crypto';
|
|
6
|
+
import { P as PINNED_CODEX_VERSION } from './pinnedCodex-XW4qvOAe.mjs';
|
|
7
|
+
import { P as PINNED_NONO_VERSION } from './pinnedNono-5ZHb6328.mjs';
|
|
14
8
|
import 'node:child_process';
|
|
15
|
-
import 'util';
|
|
16
|
-
import 'http';
|
|
17
|
-
import 'net';
|
|
18
|
-
import 'node:events';
|
|
19
|
-
import '@agentclientprotocol/sdk';
|
|
20
9
|
import 'node:util';
|
|
21
|
-
import 'node:readline';
|
|
22
|
-
import 'node:fs/promises';
|
|
23
|
-
import 'yaml';
|
|
24
10
|
|
|
25
11
|
const KIMI_NPM_PACKAGE = "@moonshot-ai/kimi-code";
|
|
26
12
|
const PINNED_KIMI_VERSION = "0.38.0";
|
|
@@ -51,6 +37,26 @@ function readDaemonState() {
|
|
|
51
37
|
function getSelfMachineId() {
|
|
52
38
|
return readDaemonState()?.machineId || null;
|
|
53
39
|
}
|
|
40
|
+
function rowDetail(result) {
|
|
41
|
+
const one = (t) => (t || "").trim().replace(/\s+/g, " ");
|
|
42
|
+
const err = one(result.stderr).slice(-200);
|
|
43
|
+
if (result.exitCode === 124 || /timed out and was killed/i.test(err)) {
|
|
44
|
+
return `TIMED OUT (may have partially completed) \u2014 ${err || "no stderr"}`;
|
|
45
|
+
}
|
|
46
|
+
const last = one((result.stdout || "").trim().split("\n").slice(-1)[0]);
|
|
47
|
+
return last || err || "";
|
|
48
|
+
}
|
|
49
|
+
const INSTALL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
50
|
+
const SAFE_SKILL_NAME = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
51
|
+
const SAFE_VERSION = /^[0-9][0-9a-zA-Z.+-]*$/;
|
|
52
|
+
function assertSafeFleetArg(value, kind, pattern) {
|
|
53
|
+
if (typeof value !== "string" || !pattern.test(value)) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`refusing to fan out: ${kind} ${JSON.stringify(value)} is not a plain ${kind} (expected ${pattern.source}). This string would be interpolated into a shell command run on every machine.`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
54
60
|
function partitionSelf(machines, selfId) {
|
|
55
61
|
if (!selfId) return { targets: machines, skipped: [] };
|
|
56
62
|
return {
|
|
@@ -155,28 +161,44 @@ async function fleetStatus() {
|
|
|
155
161
|
return;
|
|
156
162
|
}
|
|
157
163
|
try {
|
|
158
|
-
printHeader(["MACHINE ID", "LABEL", "CLAUDE", "SVAMP", "STATUS"], [20, 24, 12, 10, 12]);
|
|
164
|
+
printHeader(["MACHINE ID", "LABEL", "CLAUDE", "SVAMP", "NONO", "STATUS"], [20, 24, 12, 10, 14, 12]);
|
|
159
165
|
const rows = await fanOut(machines, async (m) => {
|
|
160
|
-
const [claudeRes, svampRes] = await Promise.all([
|
|
166
|
+
const [claudeRes, svampRes, nonoRes] = await Promise.all([
|
|
161
167
|
m.rpc.bash("claude --version 2>/dev/null || echo unknown").catch(() => null),
|
|
162
|
-
m.rpc.bash("svamp --version 2>/dev/null || echo unknown").catch(() => null)
|
|
168
|
+
m.rpc.bash("svamp --version 2>/dev/null || echo unknown").catch(() => null),
|
|
169
|
+
// Check PATH and the svamp-managed location — installNono writes to the latter,
|
|
170
|
+
// which is not necessarily on the daemon's PATH (see #0-series PATH notes).
|
|
171
|
+
m.rpc.bash("nono --version 2>/dev/null || ~/.svamp/tools/bin/nono --version 2>/dev/null || echo none").catch(() => null)
|
|
163
172
|
]);
|
|
164
173
|
const claude = parseVersionOutput(claudeRes?.stdout);
|
|
165
174
|
const svamp = parseVersionOutput(svampRes?.stdout);
|
|
175
|
+
const nono = parseVersionOutput(nonoRes?.stdout);
|
|
166
176
|
const info = await m.rpc.getMachineInfo();
|
|
167
|
-
return { claude, svamp, status: info.daemonState?.status || "unknown" };
|
|
177
|
+
return { claude, svamp, nono, status: info.daemonState?.status || "unknown" };
|
|
168
178
|
});
|
|
179
|
+
let driftingNono = 0;
|
|
169
180
|
for (const r of rows) {
|
|
170
181
|
const id = truncate(r.machine.machineId, 18).padEnd(20);
|
|
171
182
|
const label = truncate(r.machine.label, 22).padEnd(24);
|
|
172
183
|
const claude = (r.ok ? r.result.claude : "-").padEnd(12);
|
|
173
184
|
const svamp = (r.ok ? r.result.svamp : "-").padEnd(10);
|
|
185
|
+
const nonoRaw = r.ok ? r.result.nono : "-";
|
|
186
|
+
const nonoDrift = r.ok && nonoRaw !== PINNED_NONO_VERSION;
|
|
187
|
+
const nono = (nonoDrift ? `${nonoRaw} !` : nonoRaw).padEnd(14);
|
|
174
188
|
const status = r.ok ? r.result.status : r.error || "fail";
|
|
175
189
|
const color = r.ok && r.result.status === "running" ? "\x1B[32m" : "\x1B[31m";
|
|
176
|
-
console.log(`${id} ${label} ${claude} ${svamp} ${color}${status}\x1B[0m`);
|
|
190
|
+
console.log(`${id} ${label} ${claude} ${svamp} ${nono}${color}${status}\x1B[0m`);
|
|
191
|
+
if (nonoDrift) driftingNono += 1;
|
|
177
192
|
}
|
|
178
193
|
console.log(`
|
|
179
194
|
${machines.length} machine(s).`);
|
|
195
|
+
if (driftingNono > 0) {
|
|
196
|
+
console.log(
|
|
197
|
+
`
|
|
198
|
+
\x1B[33m! ${driftingNono} machine(s) are not on the pinned nono ${PINNED_NONO_VERSION}\x1B[0m \u2014 nono IS the sandbox boundary, and installNono() only runs when the binary is ABSENT, so an
|
|
199
|
+
existing machine never picks up the pin. Reconcile deliberately with: svamp fleet upgrade-nono`
|
|
200
|
+
);
|
|
201
|
+
}
|
|
180
202
|
} finally {
|
|
181
203
|
await server.disconnect();
|
|
182
204
|
}
|
|
@@ -232,8 +254,9 @@ async function fleetUpgradeClaude(opts) {
|
|
|
232
254
|
`);
|
|
233
255
|
try {
|
|
234
256
|
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
257
|
+
assertSafeFleetArg(version, "version", SAFE_VERSION);
|
|
235
258
|
const cmd = `claude install ${version} 2>&1 || claude update 2>&1`;
|
|
236
|
-
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0));
|
|
259
|
+
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0, INSTALL_TIMEOUT_MS));
|
|
237
260
|
let failures = 0;
|
|
238
261
|
for (const r of rows) {
|
|
239
262
|
if (!r.ok) {
|
|
@@ -242,7 +265,7 @@ async function fleetUpgradeClaude(opts) {
|
|
|
242
265
|
continue;
|
|
243
266
|
}
|
|
244
267
|
const ok = r.result.exitCode === 0;
|
|
245
|
-
const detail = (r.result
|
|
268
|
+
const detail = rowDetail(r.result);
|
|
246
269
|
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
247
270
|
if (!ok) failures += 1;
|
|
248
271
|
}
|
|
@@ -269,8 +292,9 @@ async function fleetUpgradeCodex(opts) {
|
|
|
269
292
|
`);
|
|
270
293
|
try {
|
|
271
294
|
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
295
|
+
assertSafeFleetArg(version, "version", SAFE_VERSION);
|
|
272
296
|
const cmd = `bash -lc '${NPM_PREFIX_RESOLVER}; npm install -g $PREFIX_ARG @openai/codex@${version} 2>&1 | tail -5'`;
|
|
273
|
-
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0));
|
|
297
|
+
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0, INSTALL_TIMEOUT_MS));
|
|
274
298
|
let failures = 0;
|
|
275
299
|
for (const r of rows) {
|
|
276
300
|
if (!r.ok) {
|
|
@@ -279,7 +303,7 @@ async function fleetUpgradeCodex(opts) {
|
|
|
279
303
|
continue;
|
|
280
304
|
}
|
|
281
305
|
const ok = r.result.exitCode === 0;
|
|
282
|
-
const detail = (r.result
|
|
306
|
+
const detail = rowDetail(r.result);
|
|
283
307
|
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
284
308
|
if (!ok) failures += 1;
|
|
285
309
|
}
|
|
@@ -290,6 +314,53 @@ ${rows.length - failures}/${rows.length} machines on codex ${version}.`);
|
|
|
290
314
|
await server.disconnect();
|
|
291
315
|
}
|
|
292
316
|
}
|
|
317
|
+
async function fleetUpgradeNono(opts) {
|
|
318
|
+
if (opts?.version && opts.version !== PINNED_NONO_VERSION) {
|
|
319
|
+
console.error(`Refusing to install nono ${opts.version}: this command reconciles the PIN, and the pin is ${PINNED_NONO_VERSION}.`);
|
|
320
|
+
console.error("");
|
|
321
|
+
console.error("nono is the sandbox boundary, so the version that reaches the fleet must be the one");
|
|
322
|
+
console.error("reviewed in a commit \u2014 not one typed at the prompt. To roll a different nono:");
|
|
323
|
+
console.error(` 1. bump PINNED_NONO_VERSION to ${opts.version} in packages/svamp-cli/src/daemon/pinnedNono.ts`);
|
|
324
|
+
console.error(" (this also updates the checksum the installer verifies against)");
|
|
325
|
+
console.error(" 2. land + publish it, then re-run `svamp fleet upgrade-nono` with no -v");
|
|
326
|
+
process.exitCode = 1;
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const version = PINNED_NONO_VERSION;
|
|
330
|
+
const { server, machines } = await discoverMachines();
|
|
331
|
+
if (machines.length === 0) {
|
|
332
|
+
console.log("No machines found.");
|
|
333
|
+
await server.disconnect();
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
console.log(`Reconciling nono to ${version} on ${machines.length} machine(s)...
|
|
337
|
+
`);
|
|
338
|
+
console.log("nono IS the sandbox boundary \u2014 roll it deliberately, and canary one machine first.");
|
|
339
|
+
console.log("No daemon restart needed: the new binary applies to sessions started after this.\n");
|
|
340
|
+
try {
|
|
341
|
+
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
342
|
+
const cmd = `svamp daemon install-nono 2>&1 | tail -5`;
|
|
343
|
+
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0, INSTALL_TIMEOUT_MS));
|
|
344
|
+
let failures = 0;
|
|
345
|
+
for (const r of rows) {
|
|
346
|
+
if (!r.ok) {
|
|
347
|
+
printResultRow(r.machine, "FAIL", r.error || "");
|
|
348
|
+
failures += 1;
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
const ok = r.result.exitCode === 0;
|
|
352
|
+
const detail = rowDetail(r.result);
|
|
353
|
+
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
354
|
+
if (!ok) failures += 1;
|
|
355
|
+
}
|
|
356
|
+
console.log(`
|
|
357
|
+
${rows.length - failures}/${rows.length} machines reconciled to nono ${version}.`);
|
|
358
|
+
console.log("Confirm with: svamp fleet status (the NONO column flags anything off the pin)");
|
|
359
|
+
if (failures > 0) process.exitCode = 1;
|
|
360
|
+
} finally {
|
|
361
|
+
await server.disconnect();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
293
364
|
async function fleetUpgradeKimi(opts) {
|
|
294
365
|
const version = opts?.version || PINNED_KIMI_VERSION;
|
|
295
366
|
const { server, machines } = await discoverMachines();
|
|
@@ -298,6 +369,7 @@ async function fleetUpgradeKimi(opts) {
|
|
|
298
369
|
await server.disconnect();
|
|
299
370
|
return;
|
|
300
371
|
}
|
|
372
|
+
assertSafeFleetArg(version, "version", SAFE_VERSION);
|
|
301
373
|
console.log(`Reconciling Kimi to ${version} on ${machines.length} machine(s)...
|
|
302
374
|
`);
|
|
303
375
|
console.log(`Note: Kimi is a global npm package (${KIMI_NPM_PACKAGE}); machines that never use it can ignore this.`);
|
|
@@ -306,7 +378,7 @@ async function fleetUpgradeKimi(opts) {
|
|
|
306
378
|
try {
|
|
307
379
|
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
308
380
|
const cmd = `bash -lc '${NPM_PREFIX_RESOLVER}; npm install -g $PREFIX_ARG ${KIMI_NPM_PACKAGE}@${version} 2>&1 | tail -5'`;
|
|
309
|
-
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0));
|
|
381
|
+
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0, INSTALL_TIMEOUT_MS));
|
|
310
382
|
let failures = 0;
|
|
311
383
|
for (const r of rows) {
|
|
312
384
|
if (!r.ok) {
|
|
@@ -315,7 +387,7 @@ async function fleetUpgradeKimi(opts) {
|
|
|
315
387
|
continue;
|
|
316
388
|
}
|
|
317
389
|
const ok = r.result.exitCode === 0;
|
|
318
|
-
const detail = (r.result
|
|
390
|
+
const detail = rowDetail(r.result);
|
|
319
391
|
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
320
392
|
if (!ok) failures += 1;
|
|
321
393
|
}
|
|
@@ -346,8 +418,9 @@ async function fleetUpgradeSvamp(opts) {
|
|
|
346
418
|
try {
|
|
347
419
|
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
348
420
|
for (const m of skipped) printResultRow(m, "SKIP", 'self \u2014 restart separately with "svamp daemon restart"');
|
|
421
|
+
assertSafeFleetArg(version, "version", SAFE_VERSION);
|
|
349
422
|
const cmd = `bash -lc '${NPM_PREFIX_RESOLVER}; npm install -g $PREFIX_ARG svamp-cli@${version} 2>&1 | tail -5 && ${restartCmd} 2>&1 | tail -5'`;
|
|
350
|
-
const rows = await fanOut(targets, async (m) => await m.rpc.bash(cmd, void 0));
|
|
423
|
+
const rows = await fanOut(targets, async (m) => await m.rpc.bash(cmd, void 0, INSTALL_TIMEOUT_MS));
|
|
351
424
|
let failures = 0;
|
|
352
425
|
for (const r of rows) {
|
|
353
426
|
if (!r.ok) {
|
|
@@ -356,7 +429,7 @@ async function fleetUpgradeSvamp(opts) {
|
|
|
356
429
|
continue;
|
|
357
430
|
}
|
|
358
431
|
const ok = r.result.exitCode === 0;
|
|
359
|
-
const detail = (r.result
|
|
432
|
+
const detail = rowDetail(r.result);
|
|
360
433
|
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
361
434
|
if (!ok) failures += 1;
|
|
362
435
|
}
|
|
@@ -374,6 +447,15 @@ ${rows.length - failures}/${rows.length} machines updated (new binary installed)
|
|
|
374
447
|
await server.disconnect();
|
|
375
448
|
}
|
|
376
449
|
}
|
|
450
|
+
function fleetDaemonRestartCommand(opts) {
|
|
451
|
+
if (opts?.graceful === false) {
|
|
452
|
+
return `svamp daemon stop --cleanup 2>&1 && svamp daemon start 2>&1`;
|
|
453
|
+
}
|
|
454
|
+
if (opts?.force) {
|
|
455
|
+
return `svamp daemon restart 2>&1`;
|
|
456
|
+
}
|
|
457
|
+
return `svamp daemon restart --when-idle 2>&1`;
|
|
458
|
+
}
|
|
377
459
|
async function fleetDaemonRestart(opts) {
|
|
378
460
|
const { server, machines } = await discoverMachines();
|
|
379
461
|
if (machines.length === 0) {
|
|
@@ -382,9 +464,12 @@ async function fleetDaemonRestart(opts) {
|
|
|
382
464
|
return;
|
|
383
465
|
}
|
|
384
466
|
try {
|
|
467
|
+
const cmd = fleetDaemonRestartCommand(opts);
|
|
468
|
+
const mode = opts?.graceful === false ? "cleanup (hard stop+start)" : opts?.force ? "force (immediate)" : "graceful (restart when idle)";
|
|
469
|
+
console.log(`Restarting daemons on ${machines.length} machine(s) \u2014 ${mode}...
|
|
470
|
+
`);
|
|
385
471
|
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
386
|
-
const
|
|
387
|
-
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0));
|
|
472
|
+
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0, INSTALL_TIMEOUT_MS));
|
|
388
473
|
let failures = 0;
|
|
389
474
|
for (const r of rows) {
|
|
390
475
|
if (!r.ok) {
|
|
@@ -393,7 +478,7 @@ async function fleetDaemonRestart(opts) {
|
|
|
393
478
|
continue;
|
|
394
479
|
}
|
|
395
480
|
const ok = r.result.exitCode === 0;
|
|
396
|
-
const detail = (r.result
|
|
481
|
+
const detail = rowDetail(r.result);
|
|
397
482
|
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
398
483
|
if (!ok) failures += 1;
|
|
399
484
|
}
|
|
@@ -419,8 +504,9 @@ async function fleetPushSkill(name) {
|
|
|
419
504
|
`);
|
|
420
505
|
try {
|
|
421
506
|
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
507
|
+
assertSafeFleetArg(name, "skill name", SAFE_SKILL_NAME);
|
|
422
508
|
const cmd = `svamp skills install ${name} --force 2>&1`;
|
|
423
|
-
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0));
|
|
509
|
+
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0, INSTALL_TIMEOUT_MS));
|
|
424
510
|
let failures = 0;
|
|
425
511
|
for (const r of rows) {
|
|
426
512
|
if (!r.ok) {
|
|
@@ -429,7 +515,7 @@ async function fleetPushSkill(name) {
|
|
|
429
515
|
continue;
|
|
430
516
|
}
|
|
431
517
|
const ok = r.result.exitCode === 0;
|
|
432
|
-
const detail = (r.result
|
|
518
|
+
const detail = rowDetail(r.result);
|
|
433
519
|
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
434
520
|
if (!ok) failures += 1;
|
|
435
521
|
}
|
|
@@ -441,4 +527,4 @@ ${rows.length - failures}/${rows.length} updated.`);
|
|
|
441
527
|
}
|
|
442
528
|
}
|
|
443
529
|
|
|
444
|
-
export { fleetDaemonRestart, fleetExec, fleetPushSkill, fleetStatus, fleetUpgradeClaude, fleetUpgradeCodex, fleetUpgradeKimi, fleetUpgradeSvamp, parseVersionOutput, partitionSelf };
|
|
530
|
+
export { assertSafeFleetArg, fleetDaemonRestart, fleetDaemonRestartCommand, fleetExec, fleetPushSkill, fleetStatus, fleetUpgradeClaude, fleetUpgradeCodex, fleetUpgradeKimi, fleetUpgradeNono, fleetUpgradeSvamp, parseVersionOutput, partitionSelf, rowDetail };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
function flushAndExit(code) {
|
|
2
|
+
return new Promise((resolve) => {
|
|
3
|
+
const streams = [process.stdout, process.stderr];
|
|
4
|
+
let remaining = streams.length;
|
|
5
|
+
const tryExit = () => {
|
|
6
|
+
if (--remaining <= 0) {
|
|
7
|
+
process.exit(code);
|
|
8
|
+
resolve(void 0);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
for (const s of streams) {
|
|
12
|
+
if (s.writableLength) {
|
|
13
|
+
s.write("", () => tryExit());
|
|
14
|
+
} else {
|
|
15
|
+
tryExit();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function flushStdout() {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const streams = [process.stdout, process.stderr];
|
|
23
|
+
let remaining = streams.length;
|
|
24
|
+
const done = () => {
|
|
25
|
+
if (--remaining <= 0) resolve();
|
|
26
|
+
};
|
|
27
|
+
for (const s of streams) {
|
|
28
|
+
if (s.writableLength) {
|
|
29
|
+
s.write("", () => done());
|
|
30
|
+
} else {
|
|
31
|
+
done();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { flushAndExit as a, flushStdout as f };
|