@clawops/cli 2.1.3 → 2.2.0
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 +120 -2
- package/dist/agent-activity-25FAWLAI.js +16 -0
- package/dist/{apply-JARPVA5Y.js → apply-F5SQ2ZOS.js} +7 -7
- package/dist/backup-flows-NDP5JTR3.js +29 -0
- package/dist/{bootstrap-3PBVY7MA.js → bootstrap-32TZXVDF.js} +3 -3
- package/dist/bootstrap.sh.tmpl +4 -0
- package/dist/chunk-27335SIH.js +51 -0
- package/dist/{chunk-E4NJSJ54.js → chunk-4PY6PN4G.js} +51 -7
- package/dist/{chunk-PTCVFLZ3.js → chunk-66R52R7K.js} +7 -11
- package/dist/{chunk-7T4CIT7C.js → chunk-AX65JMDZ.js} +15 -15
- package/dist/{chunk-TYHTISI5.js → chunk-CQOYUWR7.js} +610 -104
- package/dist/chunk-E6BRQK67.js +289 -0
- package/dist/chunk-LV7UO5CG.js +82 -0
- package/dist/{chunk-GIEVAGEK.js → chunk-N5ZYUTZS.js} +16 -1
- package/dist/{chunk-CPCO6UJK.js → chunk-OUQVKIIA.js} +368 -30
- package/dist/{chunk-XFN3YDZE.js → chunk-PASAVVNS.js} +1 -1
- package/dist/chunk-PCSX6Y3U.js +297 -0
- package/dist/chunk-POYS3EVQ.js +14 -0
- package/dist/chunk-SX75L2T3.js +46 -0
- package/dist/{chunk-2Z7J3ERQ.js → chunk-TYNMOYVM.js} +1 -1
- package/dist/{chunk-2I7KCMXZ.js → chunk-UAJJEDCJ.js} +2 -2
- package/dist/{chunk-NUDIHZEH.js → chunk-WPZIJONN.js} +14 -12
- package/dist/{chunk-CHNSL3TC.js → chunk-YPVWF7IA.js} +1 -1
- package/dist/{chunk-3OLUJPCB.js → chunk-Z3XLWZWF.js} +1 -1
- package/dist/cli.js +303 -698
- package/dist/conn-M2V5HBPJ.js +9 -0
- package/dist/{context-WOKSKAIA.js → context-EHSLWKSH.js} +2 -2
- package/dist/{docker-3PDO4TS7.js → docker-IKM5GRMC.js} +2 -2
- package/dist/{flows-HGJIA6EL.js → flows-6B2I6TRW.js} +5 -5
- package/dist/{generate-NE54BATS.js → generate-4YYNW3IU.js} +5 -4
- package/dist/{harden-RUOUA5BV.js → harden-UHAOVQMZ.js} +3 -3
- package/dist/{mcp-wire-FIO5DFBY.js → mcp-wire-BXF4DJFT.js} +21 -14
- package/dist/migrate-flow-24XA4GZL.js +25 -0
- package/dist/{package-MF5LPITL.js → package-HYGHRX35.js} +3 -1
- package/dist/{pool-PIIKJ4L2.js → pool-NT4XBSUT.js} +2 -2
- package/dist/{privileged-JFA6LLTV.js → privileged-5Y6O4H7Z.js} +1 -1
- package/dist/{ready-KDNRBNSU.js → ready-IJEUBFVX.js} +2 -2
- package/dist/{remote-config-3HZLUWEA.js → remote-config-OZYBMBSK.js} +3 -3
- package/dist/{runtime-X3KW5TCP.js → runtime-VW53TU2W.js} +5 -1
- package/dist/{server-OXWHBTXK.js → server-E3YA32ND.js} +21 -14
- package/dist/ssh-HOM7GF3M.js +13 -0
- package/dist/stack-delete-NTIGKWUF.js +13 -0
- package/dist/{tailscale-cutover-EKAQSDXP.js → tailscale-cutover-V42HO5UM.js} +1 -1
- package/dist/{validate-JXKN5WD6.js → validate-DZE6LFEB.js} +1 -1
- package/dist/{wait-WO72TRRQ.js → wait-DOUNNJNN.js} +2 -2
- package/package.json +3 -1
- package/spec/mcp-tools.yaml +213 -7
- package/dist/logs-5A7YYA53.js +0 -15
- package/dist/ssh-VAI5DU5M.js +0 -11
- package/dist/upgrade-ULD4KFYC.js +0 -88
- /package/dist/{chunk-NUL5F6YV.js → chunk-SOZ62ZXW.js} +0 -0
package/dist/cli.js
CHANGED
|
@@ -5,39 +5,51 @@ import {
|
|
|
5
5
|
writeAppConfigs
|
|
6
6
|
} from "./chunk-OIGTOLB3.js";
|
|
7
7
|
import {
|
|
8
|
+
AUDIT_CLEAN_MESSAGE,
|
|
9
|
+
AUDIT_FIX_HINT,
|
|
10
|
+
NO_SECRETS_MESSAGE,
|
|
11
|
+
SET_SECRET_HINT,
|
|
12
|
+
auditIssuesHeadline,
|
|
13
|
+
auditSecrets,
|
|
14
|
+
deleteConfirmQuestion,
|
|
15
|
+
deletePreparedSecret,
|
|
16
|
+
dockerRunCmd,
|
|
17
|
+
formatAuditIssue,
|
|
18
|
+
gatewayStatus,
|
|
19
|
+
listSecrets,
|
|
8
20
|
monitor_default,
|
|
9
|
-
|
|
10
|
-
|
|
21
|
+
prepareSecretDelete,
|
|
22
|
+
resolveSecretPath,
|
|
23
|
+
resolveUpdateVersion,
|
|
24
|
+
runDiagnostics,
|
|
25
|
+
secretsDir,
|
|
26
|
+
updateGateway
|
|
27
|
+
} from "./chunk-OUQVKIIA.js";
|
|
11
28
|
import {
|
|
12
29
|
GATEWAY_LOGS_PROBE,
|
|
13
30
|
chooseLogSource,
|
|
14
31
|
containerLogsCommand,
|
|
15
32
|
gatewayLogsCommand
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
33
|
+
} from "./chunk-SOZ62ZXW.js";
|
|
34
|
+
import "./chunk-6ZFIFDBJ.js";
|
|
35
|
+
import "./chunk-Z3XLWZWF.js";
|
|
18
36
|
import {
|
|
19
37
|
execPrivileged,
|
|
20
|
-
execPrivilegedWithInput,
|
|
21
38
|
streamPrivileged
|
|
22
|
-
} from "./chunk-
|
|
23
|
-
import "./chunk-
|
|
39
|
+
} from "./chunk-WPZIJONN.js";
|
|
40
|
+
import "./chunk-YPVWF7IA.js";
|
|
24
41
|
import {
|
|
25
42
|
resolveSpecDir
|
|
26
43
|
} from "./chunk-JW5A7E3X.js";
|
|
27
|
-
import
|
|
28
|
-
interpretProbe,
|
|
29
|
-
probeCommand
|
|
30
|
-
} from "./chunk-LT4XMO5D.js";
|
|
44
|
+
import "./chunk-LT4XMO5D.js";
|
|
31
45
|
import "./chunk-VUFMZEIM.js";
|
|
32
46
|
import {
|
|
33
|
-
CONFIG_FILENAME,
|
|
34
|
-
CONTAINER_UID,
|
|
35
47
|
PUBLISH_INSPECT_CMD,
|
|
36
48
|
STATE_DIR_HOST_LINUX,
|
|
37
49
|
configPathForOS,
|
|
38
50
|
gatewayRunCommand,
|
|
39
51
|
publishForRestart
|
|
40
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-N5ZYUTZS.js";
|
|
41
53
|
import {
|
|
42
54
|
GATEWAY_PORT,
|
|
43
55
|
IMAGE_INSPECT_CMD,
|
|
@@ -67,8 +79,7 @@ import {
|
|
|
67
79
|
} from "./chunk-755X5OGS.js";
|
|
68
80
|
import {
|
|
69
81
|
getConfigDir,
|
|
70
|
-
requireConfig
|
|
71
|
-
setConfig
|
|
82
|
+
requireConfig
|
|
72
83
|
} from "./chunk-GFIR2IIJ.js";
|
|
73
84
|
import {
|
|
74
85
|
ClawopsError,
|
|
@@ -192,7 +203,7 @@ var up_default = defineCommand2({
|
|
|
192
203
|
"publish-gateway": { type: "string", description: 'loopback (default) or all. "all" serves plaintext HTTP \u2014 put TLS in front of it' }
|
|
193
204
|
},
|
|
194
205
|
async run({ args }) {
|
|
195
|
-
const { buildContext } = await import("./context-
|
|
206
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
196
207
|
const { guardOpenclawVersion, defaultOpenclawVersion } = await import("./version-guard-XVYW5WFJ.js");
|
|
197
208
|
const ctx = buildContext(args);
|
|
198
209
|
const requestedVersion = typeof args["openclaw-version"] === "string" ? args["openclaw-version"] : await defaultOpenclawVersion();
|
|
@@ -205,7 +216,7 @@ var up_default = defineCommand2({
|
|
|
205
216
|
);
|
|
206
217
|
}
|
|
207
218
|
const { localOpts } = stackConfig;
|
|
208
|
-
const { localBootstrap } = await import("./bootstrap-
|
|
219
|
+
const { localBootstrap } = await import("./bootstrap-32TZXVDF.js");
|
|
209
220
|
const gatewayPort = parseGatewayPort(args["gateway-port"]);
|
|
210
221
|
const abortController2 = new AbortController();
|
|
211
222
|
process3.on("SIGINT", () => abortController2.abort());
|
|
@@ -245,8 +256,8 @@ var up_default = defineCommand2({
|
|
|
245
256
|
}
|
|
246
257
|
return;
|
|
247
258
|
}
|
|
248
|
-
const { generatePlan } = await import("./generate-
|
|
249
|
-
const { applyPlan } = await import("./apply-
|
|
259
|
+
const { generatePlan } = await import("./generate-4YYNW3IU.js");
|
|
260
|
+
const { applyPlan } = await import("./apply-F5SQ2ZOS.js");
|
|
250
261
|
const { resolveNetworkFlags } = await import("./network-args-PYJRJBYO.js");
|
|
251
262
|
const { detectEgressIp } = await import("./firewall-5VKZ4WBH.js");
|
|
252
263
|
const isDryRun = Boolean(args["dry-run"]);
|
|
@@ -326,9 +337,9 @@ function strArg(value) {
|
|
|
326
337
|
return typeof value === "string" ? value : void 0;
|
|
327
338
|
}
|
|
328
339
|
async function applyLocalConfigOverlay(opts) {
|
|
329
|
-
const { connect } = await import("./ssh-
|
|
340
|
+
const { connect } = await import("./ssh-HOM7GF3M.js");
|
|
330
341
|
const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
|
|
331
|
-
const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-
|
|
342
|
+
const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-OZYBMBSK.js");
|
|
332
343
|
let overlay;
|
|
333
344
|
try {
|
|
334
345
|
overlay = JSON.parse(readFileSync(opts.configPath, "utf-8"));
|
|
@@ -376,7 +387,7 @@ var down_default = defineCommand3({
|
|
|
376
387
|
"dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
|
|
377
388
|
},
|
|
378
389
|
async run({ args }) {
|
|
379
|
-
const { buildContext } = await import("./context-
|
|
390
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
380
391
|
const ctx = buildContext(args);
|
|
381
392
|
if (args["dry-run"]) {
|
|
382
393
|
info(`Dry run \u2014 would destroy stack "${ctx.stackName}"`);
|
|
@@ -440,7 +451,7 @@ var status_default = defineCommand4({
|
|
|
440
451
|
json: { type: "boolean", description: "Emit JSON" }
|
|
441
452
|
},
|
|
442
453
|
async run({ args }) {
|
|
443
|
-
const { buildContext } = await import("./context-
|
|
454
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
444
455
|
const ctx = buildContext(args);
|
|
445
456
|
if (ctx.adapter.name === "local") {
|
|
446
457
|
const state = ctx.localState;
|
|
@@ -540,8 +551,8 @@ var plan_default = defineCommand5({
|
|
|
540
551
|
"private-only": { type: "boolean", description: "Close public SSH and gateway access; reach the stack over its tailnet. Needs `clawops harden --tailscale` first, and checks the tailnet answers before planning" }
|
|
541
552
|
},
|
|
542
553
|
async run({ args }) {
|
|
543
|
-
const { buildContext } = await import("./context-
|
|
544
|
-
const { generatePlan } = await import("./generate-
|
|
554
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
555
|
+
const { generatePlan } = await import("./generate-4YYNW3IU.js");
|
|
545
556
|
const { resolveNetworkFlags } = await import("./network-args-PYJRJBYO.js");
|
|
546
557
|
const { detectEgressIp } = await import("./firewall-5VKZ4WBH.js");
|
|
547
558
|
const ctx = buildContext(args);
|
|
@@ -566,7 +577,7 @@ var plan_default = defineCommand5({
|
|
|
566
577
|
let network = resolved;
|
|
567
578
|
if (args["private-only"]) {
|
|
568
579
|
const { privateOnlyNetwork, assertTailnetReachable } = await import("./private-only-DIA26I2E.js");
|
|
569
|
-
const { probeSsh } = await import("./tailscale-cutover-
|
|
580
|
+
const { probeSsh } = await import("./tailscale-cutover-V42HO5UM.js");
|
|
570
581
|
network = privateOnlyNetwork(flags, resolved, ctx.config.stacks[ctx.stackName]?.tailscale, ctx.stackName);
|
|
571
582
|
await assertTailnetReachable(ctx, (conn) => probeSsh(conn));
|
|
572
583
|
}
|
|
@@ -656,8 +667,8 @@ var apply_default = defineCommand6({
|
|
|
656
667
|
"dry-run": { type: "boolean", description: "Validate plan and show diff without applying" }
|
|
657
668
|
},
|
|
658
669
|
async run({ args }) {
|
|
659
|
-
const { validatePlan } = await import("./validate-
|
|
660
|
-
const { applyPlan } = await import("./apply-
|
|
670
|
+
const { validatePlan } = await import("./validate-DZE6LFEB.js");
|
|
671
|
+
const { applyPlan } = await import("./apply-F5SQ2ZOS.js");
|
|
661
672
|
const planPath = args._?.[0];
|
|
662
673
|
if (!planPath) {
|
|
663
674
|
throw new UsageError("Usage: clawops apply <plan.json>");
|
|
@@ -783,7 +794,7 @@ var destroy_default = defineCommand7({
|
|
|
783
794
|
"dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
|
|
784
795
|
},
|
|
785
796
|
async run({ args }) {
|
|
786
|
-
const { buildContext } = await import("./context-
|
|
797
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
787
798
|
const ctx = buildContext(args);
|
|
788
799
|
if (ctx.adapter.name === "local") {
|
|
789
800
|
throw new UsageError(
|
|
@@ -876,8 +887,8 @@ var ssh_default = defineCommand8({
|
|
|
876
887
|
command: { type: "string", description: "Remote command to run (instead of interactive shell)" }
|
|
877
888
|
},
|
|
878
889
|
async run({ args }) {
|
|
879
|
-
const { buildContext } = await import("./context-
|
|
880
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
890
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
891
|
+
const { acquireSession, drainPool } = await import("./pool-NT4XBSUT.js");
|
|
881
892
|
const ctx = buildContext(args);
|
|
882
893
|
let conn;
|
|
883
894
|
if (ctx.adapter.name === "local") {
|
|
@@ -963,9 +974,9 @@ var tunnel_default = defineCommand9({
|
|
|
963
974
|
"no-open": { type: "boolean", description: "Do not open browser after tunnel is ready" }
|
|
964
975
|
},
|
|
965
976
|
async run({ args }) {
|
|
966
|
-
const { buildContext } = await import("./context-
|
|
977
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
967
978
|
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
968
|
-
const { acquireSession } = await import("./pool-
|
|
979
|
+
const { acquireSession } = await import("./pool-NT4XBSUT.js");
|
|
969
980
|
const ctx = buildContext(args);
|
|
970
981
|
const stack = await ctx.getStack();
|
|
971
982
|
const outputMap = await stack.outputs();
|
|
@@ -1032,25 +1043,10 @@ var logs_default = defineCommand10({
|
|
|
1032
1043
|
json: { type: "boolean", description: "Emit the gateway's structured JSON log lines" }
|
|
1033
1044
|
},
|
|
1034
1045
|
async run({ args }) {
|
|
1035
|
-
const { buildContext } = await import("./context-
|
|
1036
|
-
const {
|
|
1037
|
-
const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
|
|
1046
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
1047
|
+
const { acquireSession, drainPool } = await import("./pool-NT4XBSUT.js");
|
|
1038
1048
|
const ctx = buildContext(args);
|
|
1039
|
-
const
|
|
1040
|
-
const outputMap = await stack.outputs();
|
|
1041
|
-
const outputs = Object.fromEntries(
|
|
1042
|
-
Object.entries(outputMap).map(([k, v]) => [k, v.value])
|
|
1043
|
-
);
|
|
1044
|
-
if (!outputs["publicIp"]) {
|
|
1045
|
-
failure("Stack has no outputs. Run `clawops up` first.");
|
|
1046
|
-
process12.exit(4);
|
|
1047
|
-
}
|
|
1048
|
-
const base = extractBaseOutputs(outputs);
|
|
1049
|
-
const conn = ctx.adapter.getConnectionInfo({
|
|
1050
|
-
...base,
|
|
1051
|
-
privateKeyPath: ctx.config.ssh.keyPath,
|
|
1052
|
-
knownHostsPath: ctx.config.ssh.knownHostsPath
|
|
1053
|
-
});
|
|
1049
|
+
const conn = await connFor(ctx);
|
|
1054
1050
|
const tailLines = typeof args.tail === "string" ? parseInt(args.tail, 10) : 100;
|
|
1055
1051
|
const follow = Boolean(args.follow);
|
|
1056
1052
|
const since = typeof args.since === "string" ? args.since : void 0;
|
|
@@ -1092,12 +1088,33 @@ var logs_default = defineCommand10({
|
|
|
1092
1088
|
}
|
|
1093
1089
|
}
|
|
1094
1090
|
});
|
|
1091
|
+
async function connFor(ctx) {
|
|
1092
|
+
if (ctx.adapter.name === "local") {
|
|
1093
|
+
const { resolveConn } = await import("./conn-M2V5HBPJ.js");
|
|
1094
|
+
return resolveConn(ctx);
|
|
1095
|
+
}
|
|
1096
|
+
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
1097
|
+
const stack = await ctx.getStack();
|
|
1098
|
+
const outputMap = await stack.outputs();
|
|
1099
|
+
const outputs = Object.fromEntries(
|
|
1100
|
+
Object.entries(outputMap).map(([k, v]) => [k, v.value])
|
|
1101
|
+
);
|
|
1102
|
+
if (!outputs["publicIp"]) {
|
|
1103
|
+
failure("Stack has no outputs. Run `clawops up` first.");
|
|
1104
|
+
process12.exit(4);
|
|
1105
|
+
}
|
|
1106
|
+
return ctx.adapter.getConnectionInfo({
|
|
1107
|
+
...extractBaseOutputs(outputs),
|
|
1108
|
+
privateKeyPath: ctx.config.ssh.keyPath,
|
|
1109
|
+
knownHostsPath: ctx.config.ssh.knownHostsPath
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1095
1112
|
|
|
1096
1113
|
// src/cli/commands/config.ts
|
|
1097
1114
|
import { defineCommand as defineCommand11 } from "citty";
|
|
1098
1115
|
import process13 from "process";
|
|
1099
1116
|
var OPENCLAW_CONFIG = configPathForOS("Linux");
|
|
1100
|
-
function
|
|
1117
|
+
function dockerRunCmd2(image) {
|
|
1101
1118
|
return gatewayRunCommand({ image, stateDir: STATE_DIR_HOST_LINUX });
|
|
1102
1119
|
}
|
|
1103
1120
|
function getPath(obj, dotKey) {
|
|
@@ -1138,9 +1155,8 @@ var config_default = defineCommand11({
|
|
|
1138
1155
|
"dry-run": { type: "boolean", description: "Show what would change without writing" }
|
|
1139
1156
|
},
|
|
1140
1157
|
async run({ args }) {
|
|
1141
|
-
const { buildContext } = await import("./context-
|
|
1142
|
-
const {
|
|
1143
|
-
const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
|
|
1158
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
1159
|
+
const { acquireSession, drainPool } = await import("./pool-NT4XBSUT.js");
|
|
1144
1160
|
const [action, key, value] = args._ ?? [];
|
|
1145
1161
|
if (!action || !["get", "set", "unset", "validate"].includes(action)) {
|
|
1146
1162
|
failure("Usage: clawops config <get [key] | set key value | unset key | validate>");
|
|
@@ -1155,17 +1171,8 @@ var config_default = defineCommand11({
|
|
|
1155
1171
|
process13.exit(2);
|
|
1156
1172
|
}
|
|
1157
1173
|
const ctx = buildContext(args);
|
|
1158
|
-
const
|
|
1159
|
-
const
|
|
1160
|
-
const outputs = Object.fromEntries(
|
|
1161
|
-
Object.entries(outputMap).map(([k, v]) => [k, v.value])
|
|
1162
|
-
);
|
|
1163
|
-
const base = extractBaseOutputs(outputs);
|
|
1164
|
-
const conn = ctx.adapter.getConnectionInfo({
|
|
1165
|
-
...base,
|
|
1166
|
-
privateKeyPath: ctx.config.ssh.keyPath,
|
|
1167
|
-
knownHostsPath: ctx.config.ssh.knownHostsPath
|
|
1168
|
-
});
|
|
1174
|
+
const { resolveConn } = await import("./conn-M2V5HBPJ.js");
|
|
1175
|
+
const conn = await resolveConn(ctx);
|
|
1169
1176
|
const abortController = new AbortController();
|
|
1170
1177
|
process13.on("SIGINT", () => abortController.abort());
|
|
1171
1178
|
process13.on("SIGTERM", () => abortController.abort());
|
|
@@ -1228,7 +1235,7 @@ var config_default = defineCommand11({
|
|
|
1228
1235
|
process13.stdout.write(JSON.stringify(cfg, null, 2) + "\n");
|
|
1229
1236
|
return;
|
|
1230
1237
|
}
|
|
1231
|
-
const { atomicWriteConfig } = await import("./remote-config-
|
|
1238
|
+
const { atomicWriteConfig } = await import("./remote-config-OZYBMBSK.js");
|
|
1232
1239
|
try {
|
|
1233
1240
|
await atomicWriteConfig(session, cfg, abortController.signal);
|
|
1234
1241
|
} catch (err) {
|
|
@@ -1244,7 +1251,7 @@ var config_default = defineCommand11({
|
|
|
1244
1251
|
abortController.signal
|
|
1245
1252
|
);
|
|
1246
1253
|
const image = imgResult.stdout.trim();
|
|
1247
|
-
const restartResult = await execPrivileged(session,
|
|
1254
|
+
const restartResult = await execPrivileged(session, dockerRunCmd2(image), abortController.signal);
|
|
1248
1255
|
if (restartResult.code !== 0) {
|
|
1249
1256
|
failure(`Restart failed: ${restartResult.stderr}`);
|
|
1250
1257
|
process13.exit(1);
|
|
@@ -1273,9 +1280,8 @@ var agents_default = defineCommand12({
|
|
|
1273
1280
|
cursor: { type: "string", description: "Continue from a previous `logs` result cursor" }
|
|
1274
1281
|
},
|
|
1275
1282
|
async run({ args }) {
|
|
1276
|
-
const { buildContext } = await import("./context-
|
|
1277
|
-
const {
|
|
1278
|
-
const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
|
|
1283
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
1284
|
+
const { acquireSession, drainPool } = await import("./pool-NT4XBSUT.js");
|
|
1279
1285
|
const [action, name] = args._ ?? [];
|
|
1280
1286
|
if (action === "restart") {
|
|
1281
1287
|
failure(
|
|
@@ -1292,17 +1298,8 @@ var agents_default = defineCommand12({
|
|
|
1292
1298
|
process14.exit(2);
|
|
1293
1299
|
}
|
|
1294
1300
|
const ctx = buildContext(args);
|
|
1295
|
-
const
|
|
1296
|
-
const
|
|
1297
|
-
const outputs = Object.fromEntries(
|
|
1298
|
-
Object.entries(outputMap).map(([k, v]) => [k, v.value])
|
|
1299
|
-
);
|
|
1300
|
-
const base = extractBaseOutputs(outputs);
|
|
1301
|
-
const conn = ctx.adapter.getConnectionInfo({
|
|
1302
|
-
...base,
|
|
1303
|
-
privateKeyPath: ctx.config.ssh.keyPath,
|
|
1304
|
-
knownHostsPath: ctx.config.ssh.knownHostsPath
|
|
1305
|
-
});
|
|
1301
|
+
const { resolveConn } = await import("./conn-M2V5HBPJ.js");
|
|
1302
|
+
const conn = await resolveConn(ctx);
|
|
1306
1303
|
const abortController = new AbortController();
|
|
1307
1304
|
process14.on("SIGINT", () => abortController.abort());
|
|
1308
1305
|
process14.on("SIGTERM", () => abortController.abort());
|
|
@@ -1348,22 +1345,23 @@ var agents_default = defineCommand12({
|
|
|
1348
1345
|
);
|
|
1349
1346
|
}
|
|
1350
1347
|
} else {
|
|
1351
|
-
const {
|
|
1352
|
-
const limit = typeof args.limit === "string" ? parseInt(args.limit, 10) :
|
|
1353
|
-
const result = await
|
|
1348
|
+
const { readAgentActivityRaw, DEFAULT_AGENT_LOG_LIMIT } = await import("./agent-activity-25FAWLAI.js");
|
|
1349
|
+
const limit = typeof args.limit === "string" ? parseInt(args.limit, 10) : DEFAULT_AGENT_LOG_LIMIT;
|
|
1350
|
+
const result = await readAgentActivityRaw(
|
|
1354
1351
|
session,
|
|
1355
|
-
|
|
1352
|
+
{ agentId: name, limit, ...typeof args.cursor === "string" ? { cursor: args.cursor } : {} },
|
|
1356
1353
|
abortController.signal
|
|
1357
1354
|
);
|
|
1358
|
-
if (result.
|
|
1359
|
-
failure(
|
|
1355
|
+
if (!result.ok) {
|
|
1356
|
+
failure(result.error);
|
|
1360
1357
|
process14.exitCode = 1;
|
|
1361
1358
|
return;
|
|
1362
1359
|
}
|
|
1363
1360
|
if (args.json) {
|
|
1364
|
-
process14.stdout.write(result.
|
|
1361
|
+
process14.stdout.write(result.value);
|
|
1365
1362
|
} else {
|
|
1366
|
-
|
|
1363
|
+
const { parseAgentActivity } = await import("./agent-activity-25FAWLAI.js");
|
|
1364
|
+
renderAgentRuns(name, parseAgentActivity(name, result.value));
|
|
1367
1365
|
}
|
|
1368
1366
|
}
|
|
1369
1367
|
} finally {
|
|
@@ -1372,16 +1370,14 @@ var agents_default = defineCommand12({
|
|
|
1372
1370
|
}
|
|
1373
1371
|
}
|
|
1374
1372
|
});
|
|
1375
|
-
function renderAgentRuns(agentId,
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
page = JSON.parse(stdout.trim() || "{}");
|
|
1379
|
-
} catch {
|
|
1380
|
-
failure(`Cannot read activity for "${agentId}": unexpected output: ${stdout.trim().slice(0, 200)}`);
|
|
1373
|
+
function renderAgentRuns(agentId, parsed) {
|
|
1374
|
+
if (!parsed.ok) {
|
|
1375
|
+
failure(parsed.error);
|
|
1381
1376
|
process14.exitCode = 1;
|
|
1382
1377
|
return;
|
|
1383
1378
|
}
|
|
1384
|
-
const
|
|
1379
|
+
const page = parsed.value;
|
|
1380
|
+
const records = page.records;
|
|
1385
1381
|
if (records.length === 0) {
|
|
1386
1382
|
info(`No recorded activity for agent "${agentId}".`);
|
|
1387
1383
|
return;
|
|
@@ -1401,99 +1397,6 @@ function renderAgentRuns(agentId, stdout) {
|
|
|
1401
1397
|
// src/cli/commands/migrate.ts
|
|
1402
1398
|
import { defineCommand as defineCommand13 } from "citty";
|
|
1403
1399
|
import process15 from "process";
|
|
1404
|
-
|
|
1405
|
-
// src/openclaw/migrate.ts
|
|
1406
|
-
async function migrate(steps) {
|
|
1407
|
-
const sourceImage = await steps.inspectSource();
|
|
1408
|
-
if (!sourceImage) {
|
|
1409
|
-
return {
|
|
1410
|
-
kind: "nothing-to-migrate",
|
|
1411
|
-
reason: "No running OpenClaw container was found, so there is no 1.x state to extract. If this deployment was restarted on a clawops release before 2.0, its state was already lost \u2014 clawops mounted none, so every container replacement discarded it. Deploy fresh with `clawops up`."
|
|
1412
|
-
};
|
|
1413
|
-
}
|
|
1414
|
-
const identityBefore = await steps.deviceId();
|
|
1415
|
-
const backup = await steps.backup();
|
|
1416
|
-
if (!backup.ok) {
|
|
1417
|
-
return {
|
|
1418
|
-
kind: "refused",
|
|
1419
|
-
reason: `Refusing to migrate without a verified backup: ${backup.detail}
|
|
1420
|
-
This replaces the running container, and the state it extracts is the only copy.`
|
|
1421
|
-
};
|
|
1422
|
-
}
|
|
1423
|
-
const extracted = await steps.extract();
|
|
1424
|
-
if (!extracted.ok) {
|
|
1425
|
-
return {
|
|
1426
|
-
kind: "failed",
|
|
1427
|
-
reason: "Could not extract state from the running container; it has not been touched.",
|
|
1428
|
-
backupDetail: backup.detail
|
|
1429
|
-
};
|
|
1430
|
-
}
|
|
1431
|
-
await steps.chown();
|
|
1432
|
-
await steps.removeSource();
|
|
1433
|
-
await steps.writeConfig();
|
|
1434
|
-
await steps.start();
|
|
1435
|
-
let restarts = 0;
|
|
1436
|
-
let gate = await steps.gate();
|
|
1437
|
-
if (!gate.ok) {
|
|
1438
|
-
await steps.start();
|
|
1439
|
-
restarts = 1;
|
|
1440
|
-
gate = await steps.gate();
|
|
1441
|
-
}
|
|
1442
|
-
if (!gate.ok) {
|
|
1443
|
-
return {
|
|
1444
|
-
kind: "failed",
|
|
1445
|
-
reason: gate.reason ?? "the gateway did not start after migration",
|
|
1446
|
-
backupDetail: backup.detail
|
|
1447
|
-
};
|
|
1448
|
-
}
|
|
1449
|
-
const identityAfter = await steps.deviceId();
|
|
1450
|
-
const identity = identityBefore === void 0 || identityAfter === void 0 ? "unknown" : identityBefore === identityAfter ? "preserved" : "changed";
|
|
1451
|
-
return { kind: "migrated", entries: extracted.entries, identity, restarts };
|
|
1452
|
-
}
|
|
1453
|
-
function describeMigration(o) {
|
|
1454
|
-
switch (o.kind) {
|
|
1455
|
-
case "migrated": {
|
|
1456
|
-
const lines = [
|
|
1457
|
-
`Migrated to the 2.0 runtime contract. Carried over: ${o.entries.join(", ") || "(nothing)"}.`
|
|
1458
|
-
];
|
|
1459
|
-
if (o.restarts > 0) {
|
|
1460
|
-
lines.push(
|
|
1461
|
-
"The gateway needed a second start to finish its state-schema migration, which is expected for a 1.x database."
|
|
1462
|
-
);
|
|
1463
|
-
}
|
|
1464
|
-
if (o.identity === "preserved") {
|
|
1465
|
-
lines.push("Device identity preserved \u2014 paired devices do not need re-pairing.");
|
|
1466
|
-
} else if (o.identity === "changed") {
|
|
1467
|
-
lines.push(
|
|
1468
|
-
"Device identity CHANGED. Paired devices and nodes must be re-paired \u2014 check `openclaw devices list` on the host for what was paired."
|
|
1469
|
-
);
|
|
1470
|
-
} else {
|
|
1471
|
-
lines.push(
|
|
1472
|
-
"Device identity could not be compared, so pairings may or may not have carried over. Check `openclaw devices list` before relying on them."
|
|
1473
|
-
);
|
|
1474
|
-
}
|
|
1475
|
-
lines.push("Your 1.x config was NOT applied \u2014 it never took effect on 1.x either. Review it");
|
|
1476
|
-
lines.push("and set what you need with `clawops config set`.");
|
|
1477
|
-
return lines.join("\n");
|
|
1478
|
-
}
|
|
1479
|
-
case "nothing-to-migrate":
|
|
1480
|
-
return o.reason;
|
|
1481
|
-
case "refused":
|
|
1482
|
-
return o.reason;
|
|
1483
|
-
case "failed":
|
|
1484
|
-
return `Migration failed: ${o.reason}
|
|
1485
|
-
A verified backup was taken first: ${o.backupDetail}
|
|
1486
|
-
Restore it with \`clawops backup restore --file <archive>\` before retrying.`;
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
|
-
// src/cli/commands/migrate.ts
|
|
1491
|
-
var SYNTHESISED_CONFIG = JSON.stringify({
|
|
1492
|
-
meta: { lastTouchedVersion: "2026.9.2" },
|
|
1493
|
-
gateway: { mode: "local", port: GATEWAY_PORT, auth: { mode: "token" } },
|
|
1494
|
-
models: {},
|
|
1495
|
-
channels: {}
|
|
1496
|
-
});
|
|
1497
1400
|
var migrate_default = defineCommand13({
|
|
1498
1401
|
meta: {
|
|
1499
1402
|
name: "migrate",
|
|
@@ -1505,120 +1408,41 @@ var migrate_default = defineCommand13({
|
|
|
1505
1408
|
yes: { type: "boolean", description: "Skip the confirmation prompt" }
|
|
1506
1409
|
},
|
|
1507
1410
|
async run({ args }) {
|
|
1508
|
-
const {
|
|
1509
|
-
const
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
const requested = typeof args["openclaw-version"] === "string" ? args["openclaw-version"] : void 0;
|
|
1513
|
-
const target = requested ? await guardOpenclawVersion(requested) : await defaultOpenclawVersion();
|
|
1514
|
-
const targetImage = `ghcr.io/openclaw/openclaw:${target}`;
|
|
1515
|
-
const ctx = buildContext(args);
|
|
1516
|
-
const stack = await ctx.getStack();
|
|
1517
|
-
const outputs = Object.fromEntries(
|
|
1518
|
-
Object.entries(await stack.outputs()).map(([k, v]) => [k, v.value])
|
|
1519
|
-
);
|
|
1520
|
-
const conn = ctx.adapter.getConnectionInfo({
|
|
1521
|
-
...extractBaseOutputs(outputs),
|
|
1522
|
-
privateKeyPath: ctx.config.ssh.keyPath,
|
|
1523
|
-
knownHostsPath: ctx.config.ssh.knownHostsPath
|
|
1411
|
+
const { prepareMigration, runMigration, migrationQuestion } = await import("./migrate-flow-24XA4GZL.js");
|
|
1412
|
+
const target = await prepareMigration({
|
|
1413
|
+
stack: typeof args.stack === "string" ? args.stack : void 0,
|
|
1414
|
+
openclawVersion: typeof args["openclaw-version"] === "string" ? args["openclaw-version"] : void 0
|
|
1524
1415
|
});
|
|
1416
|
+
if (!args.yes) {
|
|
1417
|
+
const inquirer = (await import("inquirer")).default;
|
|
1418
|
+
const { confirmed } = await inquirer.prompt([{
|
|
1419
|
+
type: "confirm",
|
|
1420
|
+
name: "confirmed",
|
|
1421
|
+
message: migrationQuestion(target),
|
|
1422
|
+
default: false
|
|
1423
|
+
}]);
|
|
1424
|
+
if (!confirmed) {
|
|
1425
|
+
info("Aborted. Nothing was changed.");
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1525
1429
|
const ac = new AbortController();
|
|
1526
1430
|
process15.on("SIGINT", () => ac.abort());
|
|
1527
|
-
|
|
1528
|
-
host: conn.host,
|
|
1529
|
-
port: conn.port,
|
|
1530
|
-
user: conn.user,
|
|
1531
|
-
privateKeyPath: conn.privateKeyPath,
|
|
1532
|
-
knownHostsPath: conn.knownHostsPath,
|
|
1533
|
-
signal: ac.signal
|
|
1534
|
-
});
|
|
1535
|
-
const spin = spinner("Inspecting the deployment...");
|
|
1536
|
-
const run = (cmd) => execPrivileged(session, cmd, ac.signal);
|
|
1537
|
-
const archive = "/tmp/clawops-premigration.tar.gz";
|
|
1538
|
-
const configPath = `${STATE_DIR_HOST_LINUX}/${CONFIG_FILENAME}`;
|
|
1539
|
-
const steps = {
|
|
1540
|
-
inspectSource: async () => {
|
|
1541
|
-
const r = await run(`docker inspect openclaw --format '{{.Config.Image}}'`);
|
|
1542
|
-
const image = r.stdout.trim();
|
|
1543
|
-
return r.code === 0 && image.includes(":") ? image : void 0;
|
|
1544
|
-
},
|
|
1545
|
-
backup: async () => {
|
|
1546
|
-
spin.text = "Taking a verified backup...";
|
|
1547
|
-
const r = await run(
|
|
1548
|
-
`docker exec openclaw openclaw backup create --output ${archive} --verify --json`
|
|
1549
|
-
);
|
|
1550
|
-
return r.code === 0 ? { ok: true, detail: `${archive} on the host (verified)` } : { ok: false, detail: (r.stderr || r.stdout).slice(0, 200) };
|
|
1551
|
-
},
|
|
1552
|
-
extract: async () => {
|
|
1553
|
-
spin.text = "Extracting state from the running container...";
|
|
1554
|
-
const mk = await run(`mkdir -p ${STATE_DIR_HOST_LINUX}`);
|
|
1555
|
-
if (mk.code !== 0) return { ok: false, entries: [] };
|
|
1556
|
-
const cp = await run(`docker cp openclaw:/home/node/.openclaw/. ${STATE_DIR_HOST_LINUX}/`);
|
|
1557
|
-
if (cp.code !== 0) return { ok: false, entries: [] };
|
|
1558
|
-
const ls = await run(`ls ${STATE_DIR_HOST_LINUX}`);
|
|
1559
|
-
return { ok: true, entries: ls.stdout.trim().split(/\s+/).filter(Boolean) };
|
|
1560
|
-
},
|
|
1561
|
-
chown: async () => {
|
|
1562
|
-
await run(`chown -R ${CONTAINER_UID}:${CONTAINER_UID} ${STATE_DIR_HOST_LINUX}`);
|
|
1563
|
-
},
|
|
1564
|
-
removeSource: async () => {
|
|
1565
|
-
spin.text = "Stopping the 1.x container...";
|
|
1566
|
-
await run("docker stop openclaw 2>/dev/null || true");
|
|
1567
|
-
await run("docker rm openclaw 2>/dev/null || true");
|
|
1568
|
-
},
|
|
1569
|
-
writeConfig: async () => {
|
|
1570
|
-
const b64 = Buffer.from(SYNTHESISED_CONFIG, "utf-8").toString("base64");
|
|
1571
|
-
await run(
|
|
1572
|
-
`echo '${b64}' | base64 -d > ${configPath} && chown ${CONTAINER_UID}:${CONTAINER_UID} ${configPath}`
|
|
1573
|
-
);
|
|
1574
|
-
},
|
|
1575
|
-
start: async () => {
|
|
1576
|
-
spin.text = "Starting the 2.0 gateway...";
|
|
1577
|
-
await run(gatewayRunCommand({ image: targetImage, stateDir: STATE_DIR_HOST_LINUX }));
|
|
1578
|
-
},
|
|
1579
|
-
gate: async () => {
|
|
1580
|
-
spin.text = "Waiting for the gateway to start...";
|
|
1581
|
-
let last;
|
|
1582
|
-
for (let i = 0; i < 15; i++) {
|
|
1583
|
-
if (ac.signal.aborted) return { ok: false, reason: "aborted" };
|
|
1584
|
-
const r = await run(probeCommand("started", GATEWAY_PORT));
|
|
1585
|
-
const v = interpretProbe("started", r.stdout);
|
|
1586
|
-
if (v.ok) return { ok: true };
|
|
1587
|
-
last = v.reason;
|
|
1588
|
-
await new Promise((res) => setTimeout(res, 2e3));
|
|
1589
|
-
}
|
|
1590
|
-
return { ok: false, reason: last ?? "no response" };
|
|
1591
|
-
},
|
|
1592
|
-
deviceId: async () => {
|
|
1593
|
-
const file = await run(
|
|
1594
|
-
`docker exec openclaw sh -c 'cat ~/.openclaw/identity/device.json 2>/dev/null' || cat ${STATE_DIR_HOST_LINUX}/identity/device.json 2>/dev/null || true`
|
|
1595
|
-
);
|
|
1596
|
-
try {
|
|
1597
|
-
const parsed = JSON.parse(file.stdout.trim());
|
|
1598
|
-
return parsed.deviceId;
|
|
1599
|
-
} catch {
|
|
1600
|
-
return void 0;
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
};
|
|
1431
|
+
let spin;
|
|
1604
1432
|
try {
|
|
1605
|
-
const
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
for (const line2 of report.split("\n").slice(1)) {
|
|
1611
|
-
if (/CHANGED|could not be compared/.test(line2)) warn(line2);
|
|
1612
|
-
else info(line2);
|
|
1433
|
+
const result = await runMigration(target, {
|
|
1434
|
+
signal: ac.signal,
|
|
1435
|
+
onStep: (text) => {
|
|
1436
|
+
if (spin) spin.text = text;
|
|
1437
|
+
else spin = spinner(text);
|
|
1613
1438
|
}
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1439
|
+
});
|
|
1440
|
+
spin?.stop();
|
|
1441
|
+
const render2 = { success, info, warn, failure };
|
|
1442
|
+
for (const line2 of result.lines) render2[line2.level](line2.text);
|
|
1443
|
+
if (result.outcome.kind !== "migrated") process15.exit(result.exitCode);
|
|
1619
1444
|
} finally {
|
|
1620
|
-
|
|
1621
|
-
drainPool();
|
|
1445
|
+
spin?.stop();
|
|
1622
1446
|
}
|
|
1623
1447
|
}
|
|
1624
1448
|
});
|
|
@@ -1626,13 +1450,6 @@ var migrate_default = defineCommand13({
|
|
|
1626
1450
|
// src/cli/commands/gateway.ts
|
|
1627
1451
|
import { defineCommand as defineCommand14 } from "citty";
|
|
1628
1452
|
import process16 from "process";
|
|
1629
|
-
function dockerRunCmd2(version, publish = "loopback") {
|
|
1630
|
-
return gatewayRunCommand({
|
|
1631
|
-
image: `ghcr.io/openclaw/openclaw:${version}`,
|
|
1632
|
-
stateDir: STATE_DIR_HOST_LINUX,
|
|
1633
|
-
publish
|
|
1634
|
-
});
|
|
1635
|
-
}
|
|
1636
1453
|
var gateway_default = defineCommand14({
|
|
1637
1454
|
meta: {
|
|
1638
1455
|
name: "gateway",
|
|
@@ -1644,26 +1461,16 @@ var gateway_default = defineCommand14({
|
|
|
1644
1461
|
json: { type: "boolean", description: "Emit JSON (for status)" }
|
|
1645
1462
|
},
|
|
1646
1463
|
async run({ args }) {
|
|
1647
|
-
const { buildContext } = await import("./context-
|
|
1648
|
-
const {
|
|
1649
|
-
const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
|
|
1464
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
1465
|
+
const { acquireSession, drainPool } = await import("./pool-NT4XBSUT.js");
|
|
1650
1466
|
const [action, versionArg] = args._ ?? [];
|
|
1651
1467
|
if (!action || !["status", "restart", "update"].includes(action)) {
|
|
1652
1468
|
failure("Usage: clawops gateway <status | restart | update [version]>");
|
|
1653
1469
|
process16.exit(2);
|
|
1654
1470
|
}
|
|
1655
1471
|
const ctx = buildContext(args);
|
|
1656
|
-
const
|
|
1657
|
-
const
|
|
1658
|
-
const outputs = Object.fromEntries(
|
|
1659
|
-
Object.entries(outputMap).map(([k, v]) => [k, v.value])
|
|
1660
|
-
);
|
|
1661
|
-
const base = extractBaseOutputs(outputs);
|
|
1662
|
-
const conn = ctx.adapter.getConnectionInfo({
|
|
1663
|
-
...base,
|
|
1664
|
-
privateKeyPath: ctx.config.ssh.keyPath,
|
|
1665
|
-
knownHostsPath: ctx.config.ssh.knownHostsPath
|
|
1666
|
-
});
|
|
1472
|
+
const { resolveConn } = await import("./conn-M2V5HBPJ.js");
|
|
1473
|
+
const conn = await resolveConn(ctx);
|
|
1667
1474
|
const abortController = new AbortController();
|
|
1668
1475
|
process16.on("SIGINT", () => abortController.abort());
|
|
1669
1476
|
process16.on("SIGTERM", () => abortController.abort());
|
|
@@ -1677,25 +1484,12 @@ var gateway_default = defineCommand14({
|
|
|
1677
1484
|
});
|
|
1678
1485
|
try {
|
|
1679
1486
|
if (action === "status") {
|
|
1680
|
-
const
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
"openclaw",
|
|
1684
|
-
'{"status":"{{.State.Status}}","started":"{{.State.StartedAt}}","image":"{{.Config.Image}}"}',
|
|
1685
|
-
abortController.signal
|
|
1686
|
-
);
|
|
1687
|
-
let status = { status: "unknown", started: "", image: "" };
|
|
1688
|
-
if (inspected.kind === "ok") {
|
|
1689
|
-
try {
|
|
1690
|
-
status = JSON.parse(inspected.value);
|
|
1691
|
-
} catch {
|
|
1692
|
-
}
|
|
1693
|
-
} else if (inspected.kind === "missing") {
|
|
1694
|
-
status = { status: "not running", started: "", image: "" };
|
|
1695
|
-
} else {
|
|
1696
|
-
failure(`Could not ask docker about the gateway: ${inspected.detail}`);
|
|
1487
|
+
const inspected = await gatewayStatus(session, abortController.signal);
|
|
1488
|
+
if (!inspected.ok) {
|
|
1489
|
+
failure(inspected.error);
|
|
1697
1490
|
process16.exit(1);
|
|
1698
1491
|
}
|
|
1492
|
+
const status = inspected.value;
|
|
1699
1493
|
if (args.json) {
|
|
1700
1494
|
printJson(jsonOk(status));
|
|
1701
1495
|
} else {
|
|
@@ -1723,7 +1517,7 @@ var gateway_default = defineCommand14({
|
|
|
1723
1517
|
const spin = spinner("Restarting gateway...");
|
|
1724
1518
|
const result = await execPrivileged(
|
|
1725
1519
|
session,
|
|
1726
|
-
|
|
1520
|
+
dockerRunCmd(version, publish),
|
|
1727
1521
|
abortController.signal
|
|
1728
1522
|
);
|
|
1729
1523
|
spin.stop();
|
|
@@ -1733,121 +1527,23 @@ var gateway_default = defineCommand14({
|
|
|
1733
1527
|
}
|
|
1734
1528
|
success(`Gateway restarted (${version}).`);
|
|
1735
1529
|
} else {
|
|
1736
|
-
const
|
|
1737
|
-
|
|
1738
|
-
const version =
|
|
1530
|
+
const target = await resolveUpdateVersion(versionArg ?? args.channel);
|
|
1531
|
+
if (!target.ok) throw new UsageError(target.error);
|
|
1532
|
+
const version = target.value;
|
|
1739
1533
|
const spin = spinner(`Updating gateway to ${version}...`);
|
|
1740
|
-
const
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
abortController.signal
|
|
1745
|
-
);
|
|
1746
|
-
if (pullResult.code !== 0) {
|
|
1747
|
-
spin.stop();
|
|
1748
|
-
failure(`Pull failed: ${pullResult.stderr}`);
|
|
1749
|
-
process16.exit(1);
|
|
1750
|
-
}
|
|
1751
|
-
spin.text = "Checking state compatibility...";
|
|
1752
|
-
const {
|
|
1753
|
-
snapshotCommand,
|
|
1754
|
-
snapshotPathFrom,
|
|
1755
|
-
preflightCommand,
|
|
1756
|
-
parsePreflight,
|
|
1757
|
-
judgePreflight
|
|
1758
|
-
} = await import("./upgrade-ULD4KFYC.js");
|
|
1759
|
-
const cur = imageForRestart(
|
|
1760
|
-
(await execPrivileged(session, IMAGE_INSPECT_CMD, abortController.signal)).stdout
|
|
1761
|
-
);
|
|
1762
|
-
const snapRepo = `${STATE_DIR_HOST_LINUX}/snapshots`;
|
|
1763
|
-
const snapOut = await execPrivileged(
|
|
1764
|
-
session,
|
|
1765
|
-
snapshotCommand(cur.ok ? cur.value : targetImage, STATE_DIR_HOST_LINUX, snapRepo),
|
|
1766
|
-
abortController.signal
|
|
1767
|
-
);
|
|
1768
|
-
const snapPath = snapshotPathFrom(snapOut.stdout);
|
|
1769
|
-
if (!snapPath) {
|
|
1770
|
-
spin.stop();
|
|
1771
|
-
failure(
|
|
1772
|
-
"Could not snapshot the state database before upgrading, so neither the compatibility check nor a rollback point is available.\n" + (snapOut.stderr || snapOut.stdout).slice(0, 300)
|
|
1773
|
-
);
|
|
1774
|
-
process16.exit(1);
|
|
1775
|
-
}
|
|
1776
|
-
const pre = await execPrivileged(
|
|
1777
|
-
session,
|
|
1778
|
-
preflightCommand(targetImage, STATE_DIR_HOST_LINUX, `${snapPath}/database.sqlite`),
|
|
1779
|
-
abortController.signal
|
|
1780
|
-
);
|
|
1781
|
-
const report = parsePreflight(pre.stdout);
|
|
1782
|
-
const verdict = report ? judgePreflight(report) : { ok: false, reason: `preflight produced no readable report: ${pre.stderr.slice(0, 200)}` };
|
|
1783
|
-
if (!verdict.ok) {
|
|
1784
|
-
spin.stop();
|
|
1785
|
-
failure(`Refusing to upgrade to ${version}: ${verdict.reason}`);
|
|
1786
|
-
info(`A snapshot of the current state was kept at ${snapPath}.`);
|
|
1787
|
-
process16.exit(1);
|
|
1788
|
-
}
|
|
1789
|
-
if (verdict.ok && verdict.note) info(verdict.note);
|
|
1790
|
-
spin.text = `Updating gateway to ${version}...`;
|
|
1791
|
-
const pubU = await execPrivileged(session, PUBLISH_INSPECT_CMD, abortController.signal);
|
|
1792
|
-
const runResult = await execPrivileged(
|
|
1793
|
-
session,
|
|
1794
|
-
dockerRunCmd2(version, publishForRestart(pubU.stdout)),
|
|
1795
|
-
abortController.signal
|
|
1796
|
-
);
|
|
1797
|
-
if (runResult.code !== 0) {
|
|
1798
|
-
spin.stop();
|
|
1799
|
-
failure(`Start failed: ${runResult.stderr}`);
|
|
1800
|
-
info(`State snapshot from before the upgrade: ${snapPath}`);
|
|
1801
|
-
process16.exit(1);
|
|
1802
|
-
}
|
|
1803
|
-
spin.text = "Waiting for the gateway to start...";
|
|
1804
|
-
const { probeCommand: probeCommand2, interpretProbe: interpretProbe2 } = await import("./health-5CCOXYGG.js");
|
|
1805
|
-
const { repairCommand, describeOutcome } = await import("./upgrade-ULD4KFYC.js");
|
|
1806
|
-
const publish = publishForRestart(pubU.stdout);
|
|
1807
|
-
const gate = async () => {
|
|
1808
|
-
let last;
|
|
1809
|
-
for (let i = 0; i < 15; i++) {
|
|
1810
|
-
if (abortController.signal.aborted) return { ok: false, reason: "aborted" };
|
|
1811
|
-
const r = await execPrivileged(
|
|
1812
|
-
session,
|
|
1813
|
-
probeCommand2("started", GATEWAY_PORT),
|
|
1814
|
-
abortController.signal
|
|
1815
|
-
);
|
|
1816
|
-
const v = interpretProbe2("started", r.stdout);
|
|
1817
|
-
if (v.ok) return { ok: true };
|
|
1818
|
-
last = v.reason;
|
|
1819
|
-
await new Promise((res) => setTimeout(res, 2e3));
|
|
1820
|
-
}
|
|
1821
|
-
return { ok: false, reason: last ?? "no response" };
|
|
1822
|
-
};
|
|
1823
|
-
const { resolveUpgrade } = await import("./upgrade-ULD4KFYC.js");
|
|
1824
|
-
const outcome = await resolveUpgrade(
|
|
1825
|
-
{
|
|
1826
|
-
gate,
|
|
1827
|
-
repair: async () => {
|
|
1828
|
-
spin.text = "Gateway did not start; attempting one-shot repair...";
|
|
1829
|
-
await execPrivileged(
|
|
1830
|
-
session,
|
|
1831
|
-
repairCommand(targetImage, STATE_DIR_HOST_LINUX),
|
|
1832
|
-
abortController.signal
|
|
1833
|
-
);
|
|
1834
|
-
},
|
|
1835
|
-
run: async (v) => {
|
|
1836
|
-
await execPrivileged(session, dockerRunCmd2(v, publish), abortController.signal);
|
|
1837
|
-
}
|
|
1534
|
+
const result = await updateGateway(session, version, {
|
|
1535
|
+
signal: abortController.signal,
|
|
1536
|
+
onProgress: (text) => {
|
|
1537
|
+
spin.text = text;
|
|
1838
1538
|
},
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
previousVersion: cur.ok ? versionOf(cur.value) : void 0,
|
|
1842
|
-
snapshotPath: snapPath
|
|
1843
|
-
}
|
|
1844
|
-
);
|
|
1539
|
+
onNote: (text) => info(text)
|
|
1540
|
+
});
|
|
1845
1541
|
spin.stop();
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
success(message);
|
|
1542
|
+
if (result.ok) {
|
|
1543
|
+
success(result.message);
|
|
1849
1544
|
} else {
|
|
1850
|
-
failure(message);
|
|
1545
|
+
failure(result.message);
|
|
1546
|
+
if (result.hint) info(result.hint);
|
|
1851
1547
|
process16.exit(1);
|
|
1852
1548
|
}
|
|
1853
1549
|
}
|
|
@@ -1860,24 +1556,23 @@ var gateway_default = defineCommand14({
|
|
|
1860
1556
|
|
|
1861
1557
|
// src/cli/commands/backup.ts
|
|
1862
1558
|
import { defineCommand as defineCommand15 } from "citty";
|
|
1863
|
-
import { createWriteStream } from "fs";
|
|
1864
|
-
import { pipeline } from "stream/promises";
|
|
1865
1559
|
import process17 from "process";
|
|
1866
1560
|
var backup_default = defineCommand15({
|
|
1867
1561
|
meta: {
|
|
1868
1562
|
name: "backup",
|
|
1869
|
-
description: "Create an OpenClaw backup
|
|
1563
|
+
description: "Create an OpenClaw backup, or restore one into a staging directory"
|
|
1870
1564
|
},
|
|
1871
1565
|
args: {
|
|
1872
|
-
action: { type: "positional", description: "Action: create
|
|
1566
|
+
action: { type: "positional", description: "Action: create | restore", required: true },
|
|
1873
1567
|
out: { type: "string", description: "[create] Local path to write the backup archive" },
|
|
1874
|
-
file: { type: "string", description: "[restore] Local backup archive
|
|
1568
|
+
file: { type: "string", description: "[restore] Local backup archive to verify and expand on the host" },
|
|
1875
1569
|
stack: { type: "string", description: "Target stack name" },
|
|
1876
|
-
yes: { type: "boolean", description: "[restore] Skip confirmation prompt" }
|
|
1570
|
+
yes: { type: "boolean", description: "[restore] Skip confirmation prompt" },
|
|
1571
|
+
activate: { type: "boolean", description: "[restore] Put the restored state into service: stop the gateway, swap it in, restart, and roll back if it does not come up" }
|
|
1877
1572
|
},
|
|
1878
1573
|
async run({ args }) {
|
|
1879
|
-
const { buildContext } = await import("./context-
|
|
1880
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
1574
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
1575
|
+
const { acquireSession, drainPool } = await import("./pool-NT4XBSUT.js");
|
|
1881
1576
|
const action = args.action;
|
|
1882
1577
|
if (action !== "create" && action !== "restore") {
|
|
1883
1578
|
throw new UsageError(`Unknown action: ${action}. Use "create" or "restore"`);
|
|
@@ -1927,86 +1622,91 @@ var backup_default = defineCommand15({
|
|
|
1927
1622
|
signal: abortController.signal
|
|
1928
1623
|
});
|
|
1929
1624
|
try {
|
|
1625
|
+
const flows = await import("./backup-flows-NDP5JTR3.js");
|
|
1930
1626
|
if (action === "create") {
|
|
1931
|
-
const outPath = typeof args.out === "string" ? args.out :
|
|
1627
|
+
const outPath = typeof args.out === "string" ? args.out : flows.defaultBackupFilename();
|
|
1932
1628
|
info(`Writing backup to ${outPath}...`);
|
|
1933
1629
|
const spin = spinner("Creating backup on remote host...");
|
|
1934
|
-
const
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
spin.stop();
|
|
1942
|
-
throw new Error(`Backup failed on the remote host: ${createResult.stderr.slice(0, 300)}`);
|
|
1943
|
-
}
|
|
1944
|
-
const backupStream = await streamPrivileged(
|
|
1945
|
-
session,
|
|
1946
|
-
`docker exec openclaw cat ${remoteArchive}`,
|
|
1947
|
-
abortController.signal
|
|
1948
|
-
);
|
|
1630
|
+
const created = await flows.createBackup(session, {
|
|
1631
|
+
outPath,
|
|
1632
|
+
signal: abortController.signal,
|
|
1633
|
+
onPhase: (phase) => {
|
|
1634
|
+
if (phase === "downloading") spin.stop();
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1949
1637
|
spin.stop();
|
|
1950
|
-
|
|
1951
|
-
await pipeline(backupStream, fileStream);
|
|
1952
|
-
await execPrivileged(
|
|
1953
|
-
session,
|
|
1954
|
-
`docker exec openclaw rm -f ${remoteArchive}`,
|
|
1955
|
-
abortController.signal
|
|
1956
|
-
);
|
|
1638
|
+
if (!created.ok) throw new Error(created.reason);
|
|
1957
1639
|
success(`Backup saved to ${outPath}`);
|
|
1958
|
-
|
|
1959
|
-
info("secrets and device credentials, unencrypted. Treat it as a credential.");
|
|
1640
|
+
for (const line2 of flows.ARCHIVE_IS_A_CREDENTIAL) info(line2);
|
|
1960
1641
|
} else {
|
|
1961
1642
|
const file = typeof args.file === "string" ? args.file : void 0;
|
|
1962
1643
|
if (!file) {
|
|
1963
1644
|
throw new UsageError("Usage: clawops backup restore --file <archive.tar.gz>");
|
|
1964
1645
|
}
|
|
1965
|
-
|
|
1966
|
-
const
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
);
|
|
1975
|
-
if (
|
|
1976
|
-
|
|
1977
|
-
|
|
1646
|
+
let spin;
|
|
1647
|
+
const staged = await flows.stageRestore(session, {
|
|
1648
|
+
file,
|
|
1649
|
+
signal: abortController.signal,
|
|
1650
|
+
onPhase: (phase) => {
|
|
1651
|
+
if (phase === "uploading") spin = spinner("Uploading archive...");
|
|
1652
|
+
else if (spin) spin.text = "Verifying and restoring to a staging directory...";
|
|
1653
|
+
}
|
|
1654
|
+
});
|
|
1655
|
+
spin?.stop();
|
|
1656
|
+
if (staged.unparsedReport !== void 0) info(staged.unparsedReport);
|
|
1657
|
+
if (!staged.ok) {
|
|
1658
|
+
if (staged.kind === "refused") throw new UsageError(staged.reason);
|
|
1659
|
+
if (staged.kind === "failed") throw new Error(staged.reason);
|
|
1660
|
+
failure(staged.reason);
|
|
1661
|
+
if (staged.stagingOnHost) info(flows.nothingChanged(staged.stagingOnHost));
|
|
1662
|
+
process17.exit(1);
|
|
1978
1663
|
}
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1664
|
+
const { stagingOnHost, stateDir } = staged;
|
|
1665
|
+
success(`Archive verified and expanded to ${stagingOnHost} on the host.`);
|
|
1666
|
+
if (staged.entryCount !== void 0) info(`${staged.entryCount} entries restored.`);
|
|
1667
|
+
for (const w of staged.warnings) warn(w);
|
|
1668
|
+
if (!args.activate) {
|
|
1669
|
+
info("");
|
|
1670
|
+
info("Nothing has been activated. Re-run with --activate to put this state into");
|
|
1671
|
+
info("service, or adopt it by hand:");
|
|
1672
|
+
info(" 1. clawops ssh --command 'sudo docker stop openclaw'");
|
|
1673
|
+
info(` 2. replace the contents of ${stateDir} with those of`);
|
|
1674
|
+
info(` ${staged.statePath}`);
|
|
1675
|
+
info(` (the archive holds ${staged.stateDirInArchive} under payload/posix, not a`);
|
|
1676
|
+
info(" drop-in state directory \u2014 moving the bundle itself stops the gateway)");
|
|
1677
|
+
info(" 3. clawops gateway restart");
|
|
1678
|
+
for (const line2 of flows.PLUGINS_NOT_CARRIED) info(line2);
|
|
1679
|
+
return;
|
|
1993
1680
|
}
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1681
|
+
if (!args.yes) {
|
|
1682
|
+
const { createInterface: createInterface3 } = await import("readline/promises");
|
|
1683
|
+
const rl = createInterface3({ input: process17.stdin, output: process17.stdout });
|
|
1684
|
+
const answer = await rl.question(
|
|
1685
|
+
`Stop the gateway and put this restored state into service? The state it replaces is kept alongside it, and clawops puts it back if the gateway does not come up. [y/N] `
|
|
1686
|
+
);
|
|
1687
|
+
rl.close();
|
|
1688
|
+
if (!answer.toLowerCase().startsWith("y")) {
|
|
1689
|
+
info(`Aborted. The restored state is at ${stagingOnHost}; nothing was changed.`);
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1999
1692
|
}
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
1693
|
+
const activating = spinner("Activating the restored state...");
|
|
1694
|
+
const outcome = await flows.activateStaged(session, staged, {
|
|
1695
|
+
signal: abortController.signal,
|
|
1696
|
+
onPhase: (phase) => {
|
|
1697
|
+
if (phase === "restarting") activating.text = "Restarting the gateway...";
|
|
1698
|
+
else if (phase === "waiting") activating.text = "Waiting for the gateway to answer...";
|
|
1699
|
+
else if (phase === "done") activating.stop();
|
|
1700
|
+
}
|
|
1701
|
+
});
|
|
1702
|
+
activating.stop();
|
|
1703
|
+
if (!outcome.ok) {
|
|
1704
|
+
failure(outcome.reason);
|
|
1705
|
+
for (const line2 of flows.activationFailureDetail(outcome)) info(line2);
|
|
1706
|
+
process17.exit(1);
|
|
1707
|
+
}
|
|
1708
|
+
success(flows.ACTIVATED);
|
|
1709
|
+
for (const line2 of flows.activatedLines(outcome.preserved)) info(line2);
|
|
2010
1710
|
}
|
|
2011
1711
|
} finally {
|
|
2012
1712
|
release();
|
|
@@ -2035,16 +1735,16 @@ var stacks_default = defineCommand16({
|
|
|
2035
1735
|
process18.exit(2);
|
|
2036
1736
|
}
|
|
2037
1737
|
if (action === "list") {
|
|
2038
|
-
const
|
|
2039
|
-
const defaultStack =
|
|
2040
|
-
const rows = Object.entries(
|
|
1738
|
+
const config = requireConfig();
|
|
1739
|
+
const defaultStack = config.defaults.stack;
|
|
1740
|
+
const rows = Object.entries(config.stacks).map(([n, s]) => [
|
|
2041
1741
|
n === defaultStack ? `${n} *` : n,
|
|
2042
1742
|
s.provider,
|
|
2043
1743
|
s.region ?? "\u2014",
|
|
2044
1744
|
s.stateUrl
|
|
2045
1745
|
]);
|
|
2046
1746
|
if (args.json) {
|
|
2047
|
-
const data = Object.entries(
|
|
1747
|
+
const data = Object.entries(config.stacks).map(([n, s]) => ({
|
|
2048
1748
|
name: n,
|
|
2049
1749
|
provider: s.provider,
|
|
2050
1750
|
region: s.region ?? null,
|
|
@@ -2069,49 +1769,17 @@ var stacks_default = defineCommand16({
|
|
|
2069
1769
|
failure("Usage: clawops stacks delete <name>");
|
|
2070
1770
|
process18.exit(2);
|
|
2071
1771
|
}
|
|
2072
|
-
const
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
throw new UsageError(
|
|
2079
|
-
`Cannot delete the only remaining stack "${name}". Add another stack first or run \`clawops destroy\` to tear down resources.`
|
|
2080
|
-
);
|
|
2081
|
-
}
|
|
2082
|
-
if (name === config.defaults.stack && !args.force) {
|
|
2083
|
-
throw new UsageError(
|
|
2084
|
-
`"${name}" is the default stack. Use --force to delete it (clawops will switch the default to another stack).`
|
|
2085
|
-
);
|
|
2086
|
-
}
|
|
2087
|
-
let isDeployed = false;
|
|
2088
|
-
if (!args.force) {
|
|
2089
|
-
try {
|
|
2090
|
-
const { buildContext } = await import("./context-WOKSKAIA.js");
|
|
2091
|
-
const ctx = buildContext({ stack: name });
|
|
2092
|
-
if (ctx.adapter.name === "local") {
|
|
2093
|
-
isDeployed = !!ctx.localState;
|
|
2094
|
-
} else {
|
|
2095
|
-
const stack = await ctx.getStack();
|
|
2096
|
-
const outputMap = await stack.outputs();
|
|
2097
|
-
const outputs = Object.fromEntries(
|
|
2098
|
-
Object.entries(outputMap).map(([k, v]) => [k, v.value])
|
|
2099
|
-
);
|
|
2100
|
-
isDeployed = !!outputs["publicIp"];
|
|
2101
|
-
}
|
|
2102
|
-
} catch {
|
|
2103
|
-
warn(`Could not verify deployment status for "${name}" \u2014 proceeding anyway.`);
|
|
1772
|
+
const { checkStackDelete, deleteStackFromConfig, forgetNotice } = await import("./stack-delete-NTIGKWUF.js");
|
|
1773
|
+
const check = await checkStackDelete(name, { force: !!args.force });
|
|
1774
|
+
if (!check.ok) {
|
|
1775
|
+
if (check.refusal === "deployed") {
|
|
1776
|
+
failure(check.reason);
|
|
1777
|
+
process18.exit(1);
|
|
2104
1778
|
}
|
|
1779
|
+
throw new UsageError(check.reason);
|
|
2105
1780
|
}
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
`Stack "${name}" is still deployed. Run \`clawops down --stack ${name}\` first to destroy cloud resources, or pass --force to remove from registry only.`
|
|
2109
|
-
);
|
|
2110
|
-
process18.exit(1);
|
|
2111
|
-
}
|
|
2112
|
-
warn(
|
|
2113
|
-
`This removes "${name}" from clawops config only. Cloud resources are NOT destroyed. Run \`clawops destroy --stack ` + name + "` first if you want to remove cloud resources."
|
|
2114
|
-
);
|
|
1781
|
+
for (const w of check.warnings) warn(w);
|
|
1782
|
+
warn(forgetNotice(name));
|
|
2115
1783
|
if (!args.yes) {
|
|
2116
1784
|
const confirmed = await confirm(`Delete stack "${name}" from config?`);
|
|
2117
1785
|
if (!confirmed) {
|
|
@@ -2119,18 +1787,9 @@ var stacks_default = defineCommand16({
|
|
|
2119
1787
|
return;
|
|
2120
1788
|
}
|
|
2121
1789
|
}
|
|
2122
|
-
const
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
updated.stacks = newStacks;
|
|
2126
|
-
if (name === config.defaults.stack) {
|
|
2127
|
-
updated.defaults = { ...config.defaults, stack: Object.keys(newStacks)[0] };
|
|
2128
|
-
}
|
|
2129
|
-
setConfig(updated);
|
|
2130
|
-
success(`Stack "${name}" removed from config.`);
|
|
2131
|
-
if (name === config.defaults.stack) {
|
|
2132
|
-
info(`Default stack switched to "${updated.defaults.stack}".`);
|
|
2133
|
-
}
|
|
1790
|
+
const deleted = deleteStackFromConfig(name);
|
|
1791
|
+
success(deleted.message);
|
|
1792
|
+
if (deleted.newDefaultMessage) info(deleted.newDefaultMessage);
|
|
2134
1793
|
}
|
|
2135
1794
|
});
|
|
2136
1795
|
async function confirm(message) {
|
|
@@ -2228,7 +1887,7 @@ var serveCmd = defineCommand18({
|
|
|
2228
1887
|
inspector: { type: "boolean", description: "Enable MCP inspector" }
|
|
2229
1888
|
},
|
|
2230
1889
|
async run({ args }) {
|
|
2231
|
-
const { serveMcp } = await import("./server-
|
|
1890
|
+
const { serveMcp } = await import("./server-E3YA32ND.js");
|
|
2232
1891
|
await serveMcp({
|
|
2233
1892
|
port: args.http ? Number(args.http) : void 0,
|
|
2234
1893
|
bind: args.bind,
|
|
@@ -2306,11 +1965,11 @@ var wireCmd = defineCommand18({
|
|
|
2306
1965
|
rewire: { type: "boolean", description: "Replace an existing clawops entry" }
|
|
2307
1966
|
},
|
|
2308
1967
|
async run({ args }) {
|
|
2309
|
-
const { buildContext } = await import("./context-
|
|
2310
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
1968
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
1969
|
+
const { acquireSession, drainPool } = await import("./pool-NT4XBSUT.js");
|
|
2311
1970
|
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
2312
|
-
const { wireGatewayMcp } = await import("./mcp-wire-
|
|
2313
|
-
const { MCP_HTTP_PORT } = await import("./server-
|
|
1971
|
+
const { wireGatewayMcp } = await import("./mcp-wire-BXF4DJFT.js");
|
|
1972
|
+
const { MCP_HTTP_PORT } = await import("./server-E3YA32ND.js");
|
|
2314
1973
|
const ac = new AbortController();
|
|
2315
1974
|
process20.on("SIGINT", () => {
|
|
2316
1975
|
ac.abort();
|
|
@@ -2910,7 +2569,7 @@ var setup_default = defineCommand19({
|
|
|
2910
2569
|
default: false
|
|
2911
2570
|
}]);
|
|
2912
2571
|
if (applyNow) {
|
|
2913
|
-
const { applyPlan } = await import("./apply-
|
|
2572
|
+
const { applyPlan } = await import("./apply-F5SQ2ZOS.js");
|
|
2914
2573
|
const plan = JSON.parse(readFileSync3(outputPath, "utf-8"));
|
|
2915
2574
|
try {
|
|
2916
2575
|
await applyPlan(plan, {
|
|
@@ -2938,10 +2597,10 @@ To deploy later: clawops apply ${outputPath}`);
|
|
|
2938
2597
|
}
|
|
2939
2598
|
});
|
|
2940
2599
|
async function runLocalDeploy(opts) {
|
|
2941
|
-
const { setConfig
|
|
2942
|
-
const { localBootstrap } = await import("./bootstrap-
|
|
2943
|
-
const { connect } = await import("./ssh-
|
|
2944
|
-
const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-
|
|
2600
|
+
const { setConfig, getConfig, getConfigDir: getConfigDir2 } = await import("./store-YOLQYXMB.js");
|
|
2601
|
+
const { localBootstrap } = await import("./bootstrap-32TZXVDF.js");
|
|
2602
|
+
const { connect } = await import("./ssh-HOM7GF3M.js");
|
|
2603
|
+
const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-OZYBMBSK.js");
|
|
2945
2604
|
const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
|
|
2946
2605
|
const knownHostsPath = path2.join(getConfigDir2(), "known_hosts");
|
|
2947
2606
|
const existing = getConfig();
|
|
@@ -2957,7 +2616,7 @@ async function runLocalDeploy(opts) {
|
|
|
2957
2616
|
stacks: { [opts.stackName]: stackEntry },
|
|
2958
2617
|
ssh: { keyPath: opts.keyPath, knownHostsPath }
|
|
2959
2618
|
};
|
|
2960
|
-
|
|
2619
|
+
setConfig(newConfig);
|
|
2961
2620
|
success(`Deployment "${opts.stackName}" registered (~/.clawops/config.json)`);
|
|
2962
2621
|
await checkDockerPreflight({ host: opts.host, port: opts.port, user: opts.user, keyPath: opts.keyPath, knownHostsPath, signal: opts.signal, inquirer: opts.inquirer });
|
|
2963
2622
|
const STAGES = [
|
|
@@ -3022,7 +2681,7 @@ async function runLocalDeploy(opts) {
|
|
|
3022
2681
|
spin2.fail("Configuration failed");
|
|
3023
2682
|
throw err;
|
|
3024
2683
|
}
|
|
3025
|
-
const { drainPool } = await import("./pool-
|
|
2684
|
+
const { drainPool } = await import("./pool-NT4XBSUT.js");
|
|
3026
2685
|
drainPool();
|
|
3027
2686
|
const tokenPath = path2.join(os.homedir(), ".clawops", "secrets", `GATEWAY_TOKEN_${opts.stackName}`);
|
|
3028
2687
|
const dashboardUrl = `${state.gatewayUrl}?token=${opts.gatewayToken}`;
|
|
@@ -3128,10 +2787,10 @@ async function promptSecret(name, label, envDefault, inquirer) {
|
|
|
3128
2787
|
}]);
|
|
3129
2788
|
mkdirSync(secretsDir2, { recursive: true });
|
|
3130
2789
|
spawnSync("chmod", ["700", secretsDir2], { stdio: "ignore" });
|
|
3131
|
-
const
|
|
3132
|
-
writeFileSync2(
|
|
3133
|
-
success(`Secret saved to ${
|
|
3134
|
-
return { name, source: "file", ref:
|
|
2790
|
+
const secretPath = path2.join(secretsDir2, name);
|
|
2791
|
+
writeFileSync2(secretPath, secretValue.trim(), { encoding: "utf-8", mode: 384 });
|
|
2792
|
+
success(`Secret saved to ${secretPath} (chmod 600)`);
|
|
2793
|
+
return { name, source: "file", ref: secretPath };
|
|
3135
2794
|
}
|
|
3136
2795
|
if (secretSource === "env") {
|
|
3137
2796
|
const { envVar } = await inquirer.prompt([{
|
|
@@ -3160,7 +2819,7 @@ var DOCKER_CHECK_CMD = [
|
|
|
3160
2819
|
"echo NOT_RUNNING"
|
|
3161
2820
|
].join("; ");
|
|
3162
2821
|
async function checkDockerPreflight(opts) {
|
|
3163
|
-
const { acquireSession } = await import("./pool-
|
|
2822
|
+
const { acquireSession } = await import("./pool-NT4XBSUT.js");
|
|
3164
2823
|
const { ProviderError } = await import("./errors-OK47MQFD.js");
|
|
3165
2824
|
const spin = spinner("Checking Docker on target host...");
|
|
3166
2825
|
const timeoutSignal = AbortSignal.timeout(DOCKER_PREFLIGHT_TIMEOUT_MS);
|
|
@@ -3207,7 +2866,7 @@ async function checkDockerPreflight(opts) {
|
|
|
3207
2866
|
var DOCKER_POLL_MS = 3e3;
|
|
3208
2867
|
var DOCKER_TIMEOUT_MS = 9e4;
|
|
3209
2868
|
async function startRemoteDocker(opts, spin) {
|
|
3210
|
-
const { acquireSession } = await import("./pool-
|
|
2869
|
+
const { acquireSession } = await import("./pool-NT4XBSUT.js");
|
|
3211
2870
|
const { ProviderError } = await import("./errors-OK47MQFD.js");
|
|
3212
2871
|
spin.text = "Starting Docker on the remote server...";
|
|
3213
2872
|
const { session, release } = await acquireSession({
|
|
@@ -3412,9 +3071,9 @@ async function maybeWireGatewayMcp(opts) {
|
|
|
3412
3071
|
process21.stdout.write("\n");
|
|
3413
3072
|
const { wireGateway } = await inquirerPromptWire(opts.inquirer);
|
|
3414
3073
|
if (!wireGateway) return;
|
|
3415
|
-
const { connect } = await import("./ssh-
|
|
3074
|
+
const { connect } = await import("./ssh-HOM7GF3M.js");
|
|
3416
3075
|
const { getConfigDir: getConfigDir2 } = await import("./store-YOLQYXMB.js");
|
|
3417
|
-
const { wireGatewayMcp } = await import("./mcp-wire-
|
|
3076
|
+
const { wireGatewayMcp } = await import("./mcp-wire-BXF4DJFT.js");
|
|
3418
3077
|
const knownHostsPath = path2.join(getConfigDir2(), "known_hosts");
|
|
3419
3078
|
const spin = spinner("Wiring gateway MCP client...");
|
|
3420
3079
|
const session = await connect({
|
|
@@ -3533,7 +3192,7 @@ function instanceChoices(provider) {
|
|
|
3533
3192
|
return table[provider] ?? [];
|
|
3534
3193
|
}
|
|
3535
3194
|
async function maybeHarden(opts) {
|
|
3536
|
-
const { MODULE_CATALOG, resolveModules, runHardening, formatHardenSummary } = await import("./harden-
|
|
3195
|
+
const { MODULE_CATALOG, resolveModules, runHardening, formatHardenSummary } = await import("./harden-UHAOVQMZ.js");
|
|
3537
3196
|
const { getConfig } = await import("./store-YOLQYXMB.js");
|
|
3538
3197
|
const config = getConfig();
|
|
3539
3198
|
if (!config) return;
|
|
@@ -3557,7 +3216,7 @@ async function maybeHarden(opts) {
|
|
|
3557
3216
|
const modules = availableModules.filter((m) => selectedIds.includes(m.id));
|
|
3558
3217
|
process21.stdout.write("\nApplying hardening modules...\n\n");
|
|
3559
3218
|
try {
|
|
3560
|
-
const { buildContext } = await import("./context-
|
|
3219
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
3561
3220
|
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
3562
3221
|
const ctx = buildContext({ stack: opts.stackName });
|
|
3563
3222
|
const stackObj = await ctx.getStack();
|
|
@@ -3680,21 +3339,16 @@ async function runAccountPreflight(opts) {
|
|
|
3680
3339
|
|
|
3681
3340
|
// src/cli/commands/secret.ts
|
|
3682
3341
|
import { defineCommand as defineCommand20 } from "citty";
|
|
3683
|
-
import {
|
|
3342
|
+
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
3684
3343
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
3685
|
-
import path3 from "path";
|
|
3686
|
-
import os2 from "os";
|
|
3687
3344
|
import process22 from "process";
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
function listSecretNames() {
|
|
3696
|
-
if (!existsSync2(secretsDir())) return [];
|
|
3697
|
-
return readdirSync(secretsDir()).filter((f) => !f.startsWith("."));
|
|
3345
|
+
function secretPathOrExit(name) {
|
|
3346
|
+
const resolved = resolveSecretPath(name);
|
|
3347
|
+
if (!resolved.ok) {
|
|
3348
|
+
failure(resolved.reason);
|
|
3349
|
+
process22.exit(2);
|
|
3350
|
+
}
|
|
3351
|
+
return resolved.path;
|
|
3698
3352
|
}
|
|
3699
3353
|
var listCmd = defineCommand20({
|
|
3700
3354
|
meta: { name: "list", description: "List all stored secrets and their status" },
|
|
@@ -3702,24 +3356,12 @@ var listCmd = defineCommand20({
|
|
|
3702
3356
|
json: { type: "boolean", description: "Emit JSON" }
|
|
3703
3357
|
},
|
|
3704
3358
|
run({ args }) {
|
|
3705
|
-
const
|
|
3706
|
-
if (
|
|
3707
|
-
info(
|
|
3708
|
-
info(
|
|
3359
|
+
const rows = listSecrets();
|
|
3360
|
+
if (rows.length === 0) {
|
|
3361
|
+
info(NO_SECRETS_MESSAGE);
|
|
3362
|
+
info(SET_SECRET_HINT);
|
|
3709
3363
|
return;
|
|
3710
3364
|
}
|
|
3711
|
-
const rows = names.map((name) => {
|
|
3712
|
-
const p = secretPath(name);
|
|
3713
|
-
try {
|
|
3714
|
-
const stat = statSync(p);
|
|
3715
|
-
const content = readFileSync4(p, "utf-8").trim();
|
|
3716
|
-
const status = content.length > 0 ? "ok" : "empty";
|
|
3717
|
-
const modified = stat.mtime.toISOString().slice(0, 10);
|
|
3718
|
-
return { name, status, source: "file", path: p, modified, resolvable: content.length > 0 };
|
|
3719
|
-
} catch {
|
|
3720
|
-
return { name, status: "unreadable", source: "file", path: p, modified: "\u2014", resolvable: false };
|
|
3721
|
-
}
|
|
3722
|
-
});
|
|
3723
3365
|
if (args.json) {
|
|
3724
3366
|
process22.stdout.write(JSON.stringify(rows, null, 2) + "\n");
|
|
3725
3367
|
return;
|
|
@@ -3744,6 +3386,7 @@ var setCmd = defineCommand20({
|
|
|
3744
3386
|
failure("Usage: clawops secret set <name>");
|
|
3745
3387
|
process22.exit(2);
|
|
3746
3388
|
}
|
|
3389
|
+
const target = secretPathOrExit(name);
|
|
3747
3390
|
const inquirer = (await import("inquirer")).default;
|
|
3748
3391
|
let value;
|
|
3749
3392
|
if (args.value) {
|
|
@@ -3759,8 +3402,8 @@ var setCmd = defineCommand20({
|
|
|
3759
3402
|
}
|
|
3760
3403
|
mkdirSync2(secretsDir(), { recursive: true });
|
|
3761
3404
|
spawnSync2("chmod", ["700", secretsDir()], { stdio: "ignore" });
|
|
3762
|
-
writeFileSync3(
|
|
3763
|
-
success(`Secret "${name}" saved to ${
|
|
3405
|
+
writeFileSync3(target, value.trim(), { encoding: "utf-8", mode: 384 });
|
|
3406
|
+
success(`Secret "${name}" saved to ${target} (chmod 600)`);
|
|
3764
3407
|
info("Run `clawops secret rotate <name>` to propagate it to a running stack.");
|
|
3765
3408
|
}
|
|
3766
3409
|
});
|
|
@@ -3775,23 +3418,18 @@ var deleteCmd = defineCommand20({
|
|
|
3775
3418
|
failure("Usage: clawops secret delete <name>");
|
|
3776
3419
|
process22.exit(2);
|
|
3777
3420
|
}
|
|
3778
|
-
const
|
|
3779
|
-
if (!
|
|
3780
|
-
failure(
|
|
3781
|
-
process22.exit(1);
|
|
3782
|
-
}
|
|
3783
|
-
const { listOverlays } = await import("./overlay-store-ADZPD7EU.js");
|
|
3784
|
-
const referencingStacks = listOverlays().filter((o) => o.secrets.some((s) => s.name === name)).map((o) => o.stackName);
|
|
3785
|
-
if (referencingStacks.length > 0) {
|
|
3786
|
-
warn(`Secret "${name}" is referenced by stack(s): ${referencingStacks.join(", ")}`);
|
|
3787
|
-
warn("Deleting it will leave those stacks with an unresolvable $secret: ref.");
|
|
3421
|
+
const prepared = prepareSecretDelete(name);
|
|
3422
|
+
if (!prepared.ok) {
|
|
3423
|
+
failure(prepared.reason);
|
|
3424
|
+
process22.exit(prepared.kind === "invalid-name" ? 2 : 1);
|
|
3788
3425
|
}
|
|
3426
|
+
for (const line2 of prepared.warnings) warn(line2);
|
|
3789
3427
|
if (!args.yes) {
|
|
3790
3428
|
const inquirer = (await import("inquirer")).default;
|
|
3791
3429
|
const { confirmed } = await inquirer.prompt([{
|
|
3792
3430
|
type: "confirm",
|
|
3793
3431
|
name: "confirmed",
|
|
3794
|
-
message:
|
|
3432
|
+
message: deleteConfirmQuestion(name),
|
|
3795
3433
|
default: false
|
|
3796
3434
|
}]);
|
|
3797
3435
|
if (!confirmed) {
|
|
@@ -3799,8 +3437,7 @@ var deleteCmd = defineCommand20({
|
|
|
3799
3437
|
return;
|
|
3800
3438
|
}
|
|
3801
3439
|
}
|
|
3802
|
-
|
|
3803
|
-
success(`Secret "${name}" deleted.`);
|
|
3440
|
+
success(deletePreparedSecret(prepared));
|
|
3804
3441
|
}
|
|
3805
3442
|
});
|
|
3806
3443
|
var rotateCmd = defineCommand20({
|
|
@@ -3815,6 +3452,7 @@ var rotateCmd = defineCommand20({
|
|
|
3815
3452
|
failure("Usage: clawops secret rotate <name> [--stack <name>]");
|
|
3816
3453
|
process22.exit(2);
|
|
3817
3454
|
}
|
|
3455
|
+
const target = secretPathOrExit(name);
|
|
3818
3456
|
const inquirer = (await import("inquirer")).default;
|
|
3819
3457
|
let value;
|
|
3820
3458
|
if (args.value) {
|
|
@@ -3830,7 +3468,7 @@ var rotateCmd = defineCommand20({
|
|
|
3830
3468
|
}
|
|
3831
3469
|
mkdirSync2(secretsDir(), { recursive: true });
|
|
3832
3470
|
spawnSync2("chmod", ["700", secretsDir()], { stdio: "ignore" });
|
|
3833
|
-
writeFileSync3(
|
|
3471
|
+
writeFileSync3(target, value.trim(), { encoding: "utf-8", mode: 384 });
|
|
3834
3472
|
success(`Secret "${name}" updated.`);
|
|
3835
3473
|
const { getConfig } = await import("./store-YOLQYXMB.js");
|
|
3836
3474
|
const cfg = getConfig();
|
|
@@ -3849,10 +3487,10 @@ var rotateCmd = defineCommand20({
|
|
|
3849
3487
|
}
|
|
3850
3488
|
info(`Re-applying config overlay to stack "${targetStack}"\u2026`);
|
|
3851
3489
|
try {
|
|
3852
|
-
const { buildContext } = await import("./context-
|
|
3853
|
-
const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-
|
|
3490
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
3491
|
+
const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-OZYBMBSK.js");
|
|
3854
3492
|
const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
|
|
3855
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
3493
|
+
const { acquireSession, drainPool } = await import("./pool-NT4XBSUT.js");
|
|
3856
3494
|
const { localStateToConnectionInfo } = await import("./state-AKZP2S4T.js");
|
|
3857
3495
|
const ctx = buildContext({ stack: targetStack });
|
|
3858
3496
|
let conn;
|
|
@@ -3893,53 +3531,20 @@ var auditCmd = defineCommand20({
|
|
|
3893
3531
|
json: { type: "boolean", description: "Emit JSON" }
|
|
3894
3532
|
},
|
|
3895
3533
|
async run({ args }) {
|
|
3896
|
-
const {
|
|
3897
|
-
const overlays = listOverlays();
|
|
3898
|
-
const issues = [];
|
|
3899
|
-
for (const name of listSecretNames()) {
|
|
3900
|
-
const p = secretPath(name);
|
|
3901
|
-
try {
|
|
3902
|
-
const content = readFileSync4(p, "utf-8").trim();
|
|
3903
|
-
if (content.length === 0) {
|
|
3904
|
-
issues.push({ kind: "empty-secret", secret: name, detail: `File exists but is empty: ${p}` });
|
|
3905
|
-
}
|
|
3906
|
-
} catch {
|
|
3907
|
-
issues.push({ kind: "unreadable-secret", secret: name, detail: `Cannot read: ${p}` });
|
|
3908
|
-
}
|
|
3909
|
-
}
|
|
3910
|
-
for (const overlay of overlays) {
|
|
3911
|
-
for (const s of overlay.secrets) {
|
|
3912
|
-
if (s.source === "file") {
|
|
3913
|
-
const ref = s.ref ?? secretPath(s.name);
|
|
3914
|
-
if (!existsSync2(ref)) {
|
|
3915
|
-
issues.push({ kind: "missing-file", stack: overlay.stackName, secret: s.name, detail: `File not found: ${ref}` });
|
|
3916
|
-
}
|
|
3917
|
-
} else if (s.source === "env") {
|
|
3918
|
-
const envVar = s.ref ?? s.name;
|
|
3919
|
-
if (!process22.env[envVar]) {
|
|
3920
|
-
issues.push({ kind: "missing-env", stack: overlay.stackName, secret: s.name, detail: `Env var not set: ${envVar}` });
|
|
3921
|
-
}
|
|
3922
|
-
} else {
|
|
3923
|
-
issues.push({ kind: "cloud-sm-unresolved", stack: overlay.stackName, secret: s.name, detail: `Source "${s.source}" is not auto-resolved \u2014 set manually` });
|
|
3924
|
-
}
|
|
3925
|
-
}
|
|
3926
|
-
}
|
|
3534
|
+
const { issues } = auditSecrets();
|
|
3927
3535
|
if (args.json) {
|
|
3928
3536
|
process22.stdout.write(JSON.stringify({ issues, ok: issues.length === 0 }, null, 2) + "\n");
|
|
3929
3537
|
return;
|
|
3930
3538
|
}
|
|
3931
3539
|
if (issues.length === 0) {
|
|
3932
|
-
success(
|
|
3540
|
+
success(AUDIT_CLEAN_MESSAGE);
|
|
3933
3541
|
return;
|
|
3934
3542
|
}
|
|
3935
|
-
failure(`${issues.length}
|
|
3543
|
+
failure(`${auditIssuesHeadline(issues.length)}
|
|
3936
3544
|
`);
|
|
3937
|
-
for (const issue of issues)
|
|
3938
|
-
const prefix = issue.stack ? `[${issue.stack}] ` : "";
|
|
3939
|
-
warn(`${prefix}${issue.secret}: ${issue.detail}`);
|
|
3940
|
-
}
|
|
3545
|
+
for (const issue of issues) warn(formatAuditIssue(issue));
|
|
3941
3546
|
process22.stdout.write("\n");
|
|
3942
|
-
info(
|
|
3547
|
+
info(AUDIT_FIX_HINT);
|
|
3943
3548
|
}
|
|
3944
3549
|
});
|
|
3945
3550
|
var secret_default = defineCommand20({
|
|
@@ -4036,10 +3641,10 @@ import { accessSync, constants } from "fs";
|
|
|
4036
3641
|
import { execSync as execSync2 } from "child_process";
|
|
4037
3642
|
var ISSUES_URL = `${REPO_URL}/issues/new`;
|
|
4038
3643
|
var BODY_CAP = 2e3;
|
|
4039
|
-
var VERSION = true ? "2.
|
|
3644
|
+
var VERSION = true ? "2.2.0" : "dev";
|
|
4040
3645
|
async function collectContext() {
|
|
4041
3646
|
const nodeVersion = process23.version;
|
|
4042
|
-
const
|
|
3647
|
+
const os2 = `${process23.platform} ${process23.arch}`;
|
|
4043
3648
|
let provider = "unknown";
|
|
4044
3649
|
let stackCount = 0;
|
|
4045
3650
|
let sshKey = "unknown";
|
|
@@ -4066,7 +3671,7 @@ async function collectContext() {
|
|
|
4066
3671
|
return [
|
|
4067
3672
|
`**clawops version:** ${VERSION}`,
|
|
4068
3673
|
`**Node:** ${nodeVersion}`,
|
|
4069
|
-
`**OS:** ${
|
|
3674
|
+
`**OS:** ${os2}`,
|
|
4070
3675
|
`**Provider:** ${provider}`,
|
|
4071
3676
|
`**Stacks:** ${stackCount}`,
|
|
4072
3677
|
`**SSH key:** ${sshKey}`
|
|
@@ -4155,8 +3760,8 @@ var harden_default = defineCommand23({
|
|
|
4155
3760
|
"tailscale-revert": { type: "boolean", description: "Take the host off its tailnet and go back to its public address. A private-only stack must be reopened with a plan first" }
|
|
4156
3761
|
},
|
|
4157
3762
|
async run({ args }) {
|
|
4158
|
-
const { MODULE_CATALOG, resolveModules, runHardening, formatHardenSummary } = await import("./harden-
|
|
4159
|
-
const { buildContext } = await import("./context-
|
|
3763
|
+
const { MODULE_CATALOG, resolveModules, runHardening, formatHardenSummary } = await import("./harden-UHAOVQMZ.js");
|
|
3764
|
+
const { buildContext } = await import("./context-EHSLWKSH.js");
|
|
4160
3765
|
const { getConfig } = await import("./store-YOLQYXMB.js");
|
|
4161
3766
|
if (args.list) {
|
|
4162
3767
|
process24.stdout.write("\nAvailable hardening modules:\n\n");
|
|
@@ -4179,7 +3784,7 @@ var harden_default = defineCommand23({
|
|
|
4179
3784
|
const ctx = buildContext({ stack: args.stack });
|
|
4180
3785
|
const provider = ctx.adapter.name;
|
|
4181
3786
|
if (args["tailscale-revert"]) {
|
|
4182
|
-
const { revertTailnet } = await import("./flows-
|
|
3787
|
+
const { revertTailnet } = await import("./flows-6B2I6TRW.js");
|
|
4183
3788
|
const override = config.stacks[ctx.stackName]?.tailscale;
|
|
4184
3789
|
if (override && args.yes !== true) {
|
|
4185
3790
|
const { createInterface: createInterface3 } = await import("readline/promises");
|
|
@@ -4202,7 +3807,7 @@ var harden_default = defineCommand23({
|
|
|
4202
3807
|
else success(outcome.message);
|
|
4203
3808
|
return;
|
|
4204
3809
|
}
|
|
4205
|
-
const { makeTailscaleModule } = await import("./harden-
|
|
3810
|
+
const { makeTailscaleModule } = await import("./harden-UHAOVQMZ.js");
|
|
4206
3811
|
const forStack = makeTailscaleModule(ctx.stackName);
|
|
4207
3812
|
const resolved = resolveModules(MODULE_CATALOG, args.options, provider).map(
|
|
4208
3813
|
(m) => m.id === "tailscale" ? forStack : m
|
|
@@ -4286,7 +3891,7 @@ var harden_default = defineCommand23({
|
|
|
4286
3891
|
success("Hardening complete.");
|
|
4287
3892
|
}
|
|
4288
3893
|
if (args.tailscale && !args["dry-run"]) {
|
|
4289
|
-
const { cutOverToTailnet } = await import("./flows-
|
|
3894
|
+
const { cutOverToTailnet } = await import("./flows-6B2I6TRW.js");
|
|
4290
3895
|
process24.stdout.write("\nVerifying the tailnet address before using it...\n");
|
|
4291
3896
|
const outcome = await cutOverToTailnet(ctx, conn, config);
|
|
4292
3897
|
if (!outcome.ok) {
|
|
@@ -4323,7 +3928,7 @@ function resolveArgv(argv2, stdinIsTty) {
|
|
|
4323
3928
|
}
|
|
4324
3929
|
|
|
4325
3930
|
// src/cli/index.ts
|
|
4326
|
-
var CLI_VERSION = true ? "2.
|
|
3931
|
+
var CLI_VERSION = true ? "2.2.0" : "dev";
|
|
4327
3932
|
var main = defineCommand24({
|
|
4328
3933
|
meta: {
|
|
4329
3934
|
name: "clawops",
|