@clawops/cli 1.5.0 → 1.7.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 +2 -0
- package/dist/{apply-5RREMN3L.js → apply-BTZFFGAD.js} +2 -2
- package/dist/{aws-FRE2JVAZ.js → aws-D7Y6LCGK.js} +52 -90
- package/dist/{azure-PVC3AQVC.js → azure-JQAMNVHN.js} +15 -56
- package/dist/{bootstrap-G4UZ2FKH.js → bootstrap-RY4VOSDJ.js} +2 -2
- package/dist/{chunk-T5EX55GP.js → chunk-3MFZ7E74.js} +3 -3
- package/dist/{chunk-IVX62LFO.js → chunk-7KLLWDBA.js} +2 -2
- package/dist/{chunk-R5S6IXBE.js → chunk-CG3Y7Y2R.js} +41 -71
- package/dist/{chunk-4U3LTLWZ.js → chunk-GJEF6UQA.js} +1 -0
- package/dist/{chunk-ZONXY3C6.js → chunk-ISFHLA4G.js} +4 -4
- package/dist/{chunk-ZVOEQCNW.js → chunk-LCKD7L7X.js} +1 -1
- package/dist/chunk-Q7NQY5HV.js +37 -0
- package/dist/chunk-XKT42M34.js +72 -0
- package/dist/cli.js +410 -58
- package/dist/{context-PSGEX2D7.js → context-ALSJMTHE.js} +1 -1
- package/dist/firewall-XQGO7HWK.js +51 -0
- package/dist/{gcp-BXDTC6EK.js → gcp-6FT2A45S.js} +14 -63
- package/dist/{generate-2QGKYR42.js → generate-ZTD4BVVI.js} +2 -2
- package/dist/harden-BDVYW567.js +748 -0
- package/dist/human-Z44CW7TR.js +21 -0
- package/dist/{package-QLDA65A3.js → package-7WOZMHSO.js} +5 -1
- package/dist/{pool-FBFHATDG.js → pool-JZGKPP6K.js} +2 -2
- package/dist/{server-LOL2NUJ2.js → server-EXBOOIEP.js} +11 -10
- package/dist/{ssh-IQXNME3D.js → ssh-E2AMBPZY.js} +1 -1
- package/package.json +5 -1
- package/dist/firewall-YYDOWDDP.js +0 -36
package/dist/cli.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
monitor_default,
|
|
4
|
+
validateOpenclawConfig
|
|
5
|
+
} from "./chunk-CG3Y7Y2R.js";
|
|
2
6
|
import {
|
|
3
7
|
MCP_APPS,
|
|
4
8
|
buildMcpEntry,
|
|
5
9
|
writeAppConfigs
|
|
6
10
|
} from "./chunk-OIGTOLB3.js";
|
|
11
|
+
import "./chunk-ZFNPM2WG.js";
|
|
12
|
+
import "./chunk-3MFZ7E74.js";
|
|
13
|
+
import "./chunk-LCKD7L7X.js";
|
|
14
|
+
import "./chunk-GJEF6UQA.js";
|
|
7
15
|
import {
|
|
16
|
+
REPO_URL,
|
|
8
17
|
chalk,
|
|
9
18
|
failure,
|
|
10
19
|
info,
|
|
11
|
-
monitor_default,
|
|
12
20
|
printCta,
|
|
13
21
|
spinner,
|
|
14
22
|
success,
|
|
15
|
-
validateOpenclawConfig,
|
|
16
23
|
warn
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-T5EX55GP.js";
|
|
19
|
-
import "./chunk-ZVOEQCNW.js";
|
|
20
|
-
import "./chunk-4U3LTLWZ.js";
|
|
21
|
-
import "./chunk-ZFNPM2WG.js";
|
|
24
|
+
} from "./chunk-Q7NQY5HV.js";
|
|
22
25
|
import "./chunk-A2I76FTA.js";
|
|
23
26
|
import {
|
|
24
27
|
getConfig,
|
|
@@ -32,7 +35,7 @@ import {
|
|
|
32
35
|
} from "./chunk-KGXPLI7W.js";
|
|
33
36
|
|
|
34
37
|
// src/cli/index.ts
|
|
35
|
-
import { defineCommand as
|
|
38
|
+
import { defineCommand as defineCommand23, runMain } from "citty";
|
|
36
39
|
|
|
37
40
|
// src/cli/commands/init.ts
|
|
38
41
|
import { defineCommand } from "citty";
|
|
@@ -204,7 +207,7 @@ var up_default = defineCommand2({
|
|
|
204
207
|
config: { type: "string", description: "Path to openclaw config overlay JSON (local provider only)" }
|
|
205
208
|
},
|
|
206
209
|
async run({ args }) {
|
|
207
|
-
const { buildContext } = await import("./context-
|
|
210
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
208
211
|
const ctx = buildContext(args);
|
|
209
212
|
const openclawVersion = typeof args["openclaw-version"] === "string" ? args["openclaw-version"] : "stable";
|
|
210
213
|
if (ctx.adapter.name === "local") {
|
|
@@ -215,7 +218,7 @@ var up_default = defineCommand2({
|
|
|
215
218
|
);
|
|
216
219
|
}
|
|
217
220
|
const { localOpts } = stackConfig;
|
|
218
|
-
const { localBootstrap } = await import("./bootstrap-
|
|
221
|
+
const { localBootstrap } = await import("./bootstrap-RY4VOSDJ.js");
|
|
219
222
|
const abortController = new AbortController();
|
|
220
223
|
process3.on("SIGINT", () => abortController.abort());
|
|
221
224
|
process3.on("SIGTERM", () => abortController.abort());
|
|
@@ -308,7 +311,7 @@ var up_default = defineCommand2({
|
|
|
308
311
|
}
|
|
309
312
|
});
|
|
310
313
|
async function applyLocalConfigOverlay(opts) {
|
|
311
|
-
const { connect } = await import("./ssh-
|
|
314
|
+
const { connect } = await import("./ssh-E2AMBPZY.js");
|
|
312
315
|
const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
|
|
313
316
|
const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
|
|
314
317
|
let overlay;
|
|
@@ -350,7 +353,7 @@ var down_default = defineCommand3({
|
|
|
350
353
|
"dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
|
|
351
354
|
},
|
|
352
355
|
async run({ args }) {
|
|
353
|
-
const { buildContext } = await import("./context-
|
|
356
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
354
357
|
const ctx = buildContext(args);
|
|
355
358
|
if (args["dry-run"]) {
|
|
356
359
|
info(`Dry run \u2014 would destroy stack "${ctx.stackName}"`);
|
|
@@ -414,7 +417,7 @@ var status_default = defineCommand4({
|
|
|
414
417
|
json: { type: "boolean", description: "Emit JSON" }
|
|
415
418
|
},
|
|
416
419
|
async run({ args }) {
|
|
417
|
-
const { buildContext } = await import("./context-
|
|
420
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
418
421
|
const ctx = buildContext(args);
|
|
419
422
|
if (ctx.adapter.name === "local") {
|
|
420
423
|
const state = ctx.localState;
|
|
@@ -486,8 +489,8 @@ var plan_default = defineCommand5({
|
|
|
486
489
|
out: { type: "string", description: "Write plan JSON to this absolute path (default: stdout)" }
|
|
487
490
|
},
|
|
488
491
|
async run({ args }) {
|
|
489
|
-
const { buildContext } = await import("./context-
|
|
490
|
-
const { generatePlan } = await import("./generate-
|
|
492
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
493
|
+
const { generatePlan } = await import("./generate-ZTD4BVVI.js");
|
|
491
494
|
const ctx = buildContext(args);
|
|
492
495
|
if (ctx.adapter.name === "local") {
|
|
493
496
|
throw new UsageError(
|
|
@@ -577,7 +580,7 @@ var apply_default = defineCommand6({
|
|
|
577
580
|
},
|
|
578
581
|
async run({ args }) {
|
|
579
582
|
const { validatePlan } = await import("./validate-T5M5EHSJ.js");
|
|
580
|
-
const { applyPlan } = await import("./apply-
|
|
583
|
+
const { applyPlan } = await import("./apply-BTZFFGAD.js");
|
|
581
584
|
const planPath = args._?.[0];
|
|
582
585
|
if (!planPath) {
|
|
583
586
|
throw new UsageError("Usage: clawops apply <plan.json>");
|
|
@@ -693,7 +696,7 @@ var destroy_default = defineCommand7({
|
|
|
693
696
|
"dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
|
|
694
697
|
},
|
|
695
698
|
async run({ args }) {
|
|
696
|
-
const { buildContext } = await import("./context-
|
|
699
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
697
700
|
const ctx = buildContext(args);
|
|
698
701
|
if (ctx.adapter.name === "local") {
|
|
699
702
|
throw new UsageError(
|
|
@@ -760,8 +763,8 @@ var ssh_default = defineCommand8({
|
|
|
760
763
|
command: { type: "string", description: "Remote command to run (instead of interactive shell)" }
|
|
761
764
|
},
|
|
762
765
|
async run({ args }) {
|
|
763
|
-
const { buildContext } = await import("./context-
|
|
764
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
766
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
767
|
+
const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
|
|
765
768
|
const ctx = buildContext(args);
|
|
766
769
|
let conn;
|
|
767
770
|
if (ctx.adapter.name === "local") {
|
|
@@ -847,9 +850,9 @@ var tunnel_default = defineCommand9({
|
|
|
847
850
|
"no-open": { type: "boolean", description: "Do not open browser after tunnel is ready" }
|
|
848
851
|
},
|
|
849
852
|
async run({ args }) {
|
|
850
|
-
const { buildContext } = await import("./context-
|
|
853
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
851
854
|
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
852
|
-
const { acquireSession } = await import("./pool-
|
|
855
|
+
const { acquireSession } = await import("./pool-JZGKPP6K.js");
|
|
853
856
|
const ctx = buildContext(args);
|
|
854
857
|
const stack = await ctx.getStack();
|
|
855
858
|
const outputMap = await stack.outputs();
|
|
@@ -915,9 +918,9 @@ var logs_default = defineCommand10({
|
|
|
915
918
|
since: { type: "string", description: "Show logs since duration (e.g. 5m, 1h)" }
|
|
916
919
|
},
|
|
917
920
|
async run({ args }) {
|
|
918
|
-
const { buildContext } = await import("./context-
|
|
921
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
919
922
|
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
920
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
923
|
+
const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
|
|
921
924
|
const ctx = buildContext(args);
|
|
922
925
|
const stack = await ctx.getStack();
|
|
923
926
|
const outputMap = await stack.outputs();
|
|
@@ -1032,9 +1035,9 @@ var config_default = defineCommand11({
|
|
|
1032
1035
|
"dry-run": { type: "boolean", description: "Show what would change without writing" }
|
|
1033
1036
|
},
|
|
1034
1037
|
async run({ args }) {
|
|
1035
|
-
const { buildContext } = await import("./context-
|
|
1038
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
1036
1039
|
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
1037
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
1040
|
+
const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
|
|
1038
1041
|
const [action, key, value] = args._ ?? [];
|
|
1039
1042
|
if (!action || !["get", "set", "unset", "validate"].includes(action)) {
|
|
1040
1043
|
failure("Usage: clawops config <get [key] | set key value | unset key | validate>");
|
|
@@ -1158,9 +1161,9 @@ var agents_default = defineCommand12({
|
|
|
1158
1161
|
json: { type: "boolean", description: "Emit JSON (for list)" }
|
|
1159
1162
|
},
|
|
1160
1163
|
async run({ args }) {
|
|
1161
|
-
const { buildContext } = await import("./context-
|
|
1164
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
1162
1165
|
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
1163
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
1166
|
+
const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
|
|
1164
1167
|
const [action, name] = args._ ?? [];
|
|
1165
1168
|
if (!action || !["list", "restart", "logs"].includes(action)) {
|
|
1166
1169
|
failure("Usage: clawops agents <list | restart [name] | logs <name>>");
|
|
@@ -1262,9 +1265,9 @@ var gateway_default = defineCommand13({
|
|
|
1262
1265
|
json: { type: "boolean", description: "Emit JSON (for status)" }
|
|
1263
1266
|
},
|
|
1264
1267
|
async run({ args }) {
|
|
1265
|
-
const { buildContext } = await import("./context-
|
|
1268
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
1266
1269
|
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
1267
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
1270
|
+
const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
|
|
1268
1271
|
const [action, versionArg] = args._ ?? [];
|
|
1269
1272
|
if (!action || !["status", "restart", "update"].includes(action)) {
|
|
1270
1273
|
failure("Usage: clawops gateway <status | restart | update [version]>");
|
|
@@ -1375,8 +1378,8 @@ var backup_default = defineCommand14({
|
|
|
1375
1378
|
yes: { type: "boolean", description: "[restore] Skip confirmation prompt" }
|
|
1376
1379
|
},
|
|
1377
1380
|
async run({ args }) {
|
|
1378
|
-
const { buildContext } = await import("./context-
|
|
1379
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
1381
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
1382
|
+
const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
|
|
1380
1383
|
const action = args.action;
|
|
1381
1384
|
if (action !== "create" && action !== "restore") {
|
|
1382
1385
|
throw new UsageError(`Unknown action: ${action}. Use "create" or "restore"`);
|
|
@@ -1548,7 +1551,7 @@ var stacks_default = defineCommand15({
|
|
|
1548
1551
|
let isDeployed = false;
|
|
1549
1552
|
if (!args.force) {
|
|
1550
1553
|
try {
|
|
1551
|
-
const { buildContext } = await import("./context-
|
|
1554
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
1552
1555
|
const ctx = buildContext({ stack: name });
|
|
1553
1556
|
if (ctx.adapter.name === "local") {
|
|
1554
1557
|
isDeployed = !!ctx.localState;
|
|
@@ -1669,9 +1672,9 @@ var doctor_default = defineCommand16({
|
|
|
1669
1672
|
info("Credential checks skipped \u2014 no config");
|
|
1670
1673
|
} else {
|
|
1671
1674
|
const { getProvider } = await import("./providers-2OABPW2E.js");
|
|
1672
|
-
await import("./aws-
|
|
1673
|
-
await import("./gcp-
|
|
1674
|
-
await import("./azure-
|
|
1675
|
+
await import("./aws-D7Y6LCGK.js");
|
|
1676
|
+
await import("./gcp-6FT2A45S.js");
|
|
1677
|
+
await import("./azure-JQAMNVHN.js");
|
|
1675
1678
|
await import("./local-DXBEVZ5C.js");
|
|
1676
1679
|
const checkedProviders = /* @__PURE__ */ new Set();
|
|
1677
1680
|
for (const [stackName, stackCfg] of Object.entries(config.stacks)) {
|
|
@@ -1706,9 +1709,9 @@ var doctor_default = defineCommand16({
|
|
|
1706
1709
|
info("Remote health skipped \u2014 no config");
|
|
1707
1710
|
} else {
|
|
1708
1711
|
try {
|
|
1709
|
-
const { buildContext } = await import("./context-
|
|
1712
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
1710
1713
|
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
1711
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
1714
|
+
const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
|
|
1712
1715
|
const ctx = buildContext({ stack: args.stack });
|
|
1713
1716
|
const stack = await ctx.getStack();
|
|
1714
1717
|
const outputMap = await stack.outputs();
|
|
@@ -1792,8 +1795,53 @@ var doctor_default = defineCommand16({
|
|
|
1792
1795
|
}
|
|
1793
1796
|
}
|
|
1794
1797
|
}
|
|
1798
|
+
if (args.stack && config) {
|
|
1799
|
+
process18.stdout.write("\nHardening\n");
|
|
1800
|
+
try {
|
|
1801
|
+
const { MODULE_CATALOG, resolveModules, withRemoteExec } = await import("./harden-BDVYW567.js");
|
|
1802
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
1803
|
+
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
1804
|
+
const ctx = buildContext({ stack: args.stack });
|
|
1805
|
+
const stackObj = await ctx.getStack();
|
|
1806
|
+
const outputMap = await stackObj.outputs();
|
|
1807
|
+
const outputs = Object.fromEntries(
|
|
1808
|
+
Object.entries(outputMap).map(([k, v]) => [k, v.value])
|
|
1809
|
+
);
|
|
1810
|
+
const base = extractBaseOutputs(outputs);
|
|
1811
|
+
const conn = ctx.adapter.getConnectionInfo({
|
|
1812
|
+
...base,
|
|
1813
|
+
privateKeyPath: config.ssh.keyPath,
|
|
1814
|
+
knownHostsPath: config.ssh.knownHostsPath
|
|
1815
|
+
});
|
|
1816
|
+
const hardenAc = new AbortController();
|
|
1817
|
+
process18.on("SIGINT", () => hardenAc.abort());
|
|
1818
|
+
const provider = ctx.adapter.name;
|
|
1819
|
+
const modules = resolveModules(MODULE_CATALOG, void 0, provider);
|
|
1820
|
+
await withRemoteExec(conn, hardenAc.signal, async (exec) => {
|
|
1821
|
+
for (const mod of modules) {
|
|
1822
|
+
const result = await mod.check(exec);
|
|
1823
|
+
if (result.status === "applied") {
|
|
1824
|
+
success(`${mod.label.padEnd(32)} applied`);
|
|
1825
|
+
} else if (result.status === "drifted") {
|
|
1826
|
+
warn(`${mod.label.padEnd(32)} drifted \u2014 ${result.detail}`);
|
|
1827
|
+
} else if (result.status === "missing") {
|
|
1828
|
+
info(`${mod.label.padEnd(32)} not applied \u2014 run \`clawops harden\``);
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
});
|
|
1832
|
+
} catch (err) {
|
|
1833
|
+
failure(`Hardening checks failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1795
1836
|
process18.stdout.write("\n");
|
|
1796
|
-
if (!nodeOk)
|
|
1837
|
+
if (!nodeOk) {
|
|
1838
|
+
process18.stdout.write(
|
|
1839
|
+
`Run \`clawops bug\` to open a pre-filled issue at ${REPO_URL}/issues
|
|
1840
|
+
|
|
1841
|
+
`
|
|
1842
|
+
);
|
|
1843
|
+
process18.exit(1);
|
|
1844
|
+
}
|
|
1797
1845
|
}
|
|
1798
1846
|
});
|
|
1799
1847
|
|
|
@@ -1814,7 +1862,7 @@ var serveCmd = defineCommand17({
|
|
|
1814
1862
|
inspector: { type: "boolean", description: "Enable MCP inspector" }
|
|
1815
1863
|
},
|
|
1816
1864
|
async run({ args }) {
|
|
1817
|
-
const { serveMcp } = await import("./server-
|
|
1865
|
+
const { serveMcp } = await import("./server-EXBOOIEP.js");
|
|
1818
1866
|
await serveMcp({
|
|
1819
1867
|
port: args.http ? Number(args.http) : void 0,
|
|
1820
1868
|
bind: args.bind,
|
|
@@ -1889,8 +1937,8 @@ var wireCmd = defineCommand17({
|
|
|
1889
1937
|
force: { type: "boolean", description: "Apply even if gateway version is below minimum" }
|
|
1890
1938
|
},
|
|
1891
1939
|
async run({ args }) {
|
|
1892
|
-
const { buildContext } = await import("./context-
|
|
1893
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
1940
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
1941
|
+
const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
|
|
1894
1942
|
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
1895
1943
|
const { wireGatewayMcp } = await import("./mcp-wire-ZWIYMLEW.js");
|
|
1896
1944
|
const ac = new AbortController();
|
|
@@ -2386,6 +2434,12 @@ var setup_default = defineCommand18({
|
|
|
2386
2434
|
signal: ac.signal,
|
|
2387
2435
|
inquirer
|
|
2388
2436
|
});
|
|
2437
|
+
await maybeHarden({
|
|
2438
|
+
stackName: stackAnswers.stackName,
|
|
2439
|
+
provider: "local",
|
|
2440
|
+
signal: ac.signal,
|
|
2441
|
+
inquirer
|
|
2442
|
+
});
|
|
2389
2443
|
} else {
|
|
2390
2444
|
const { getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
|
|
2391
2445
|
const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
|
|
@@ -2404,7 +2458,7 @@ var setup_default = defineCommand18({
|
|
|
2404
2458
|
default: false
|
|
2405
2459
|
}]);
|
|
2406
2460
|
if (applyNow) {
|
|
2407
|
-
const { applyPlan } = await import("./apply-
|
|
2461
|
+
const { applyPlan } = await import("./apply-BTZFFGAD.js");
|
|
2408
2462
|
const plan = JSON.parse(readFileSync3(outputPath, "utf-8"));
|
|
2409
2463
|
try {
|
|
2410
2464
|
await applyPlan(plan, {
|
|
@@ -2418,6 +2472,12 @@ var setup_default = defineCommand18({
|
|
|
2418
2472
|
process20.exit(1);
|
|
2419
2473
|
}
|
|
2420
2474
|
await maybeWireGatewayMcpCloud({ stackName: stackAnswers.stackName, signal: ac.signal, inquirer });
|
|
2475
|
+
await maybeHarden({
|
|
2476
|
+
stackName: stackAnswers.stackName,
|
|
2477
|
+
provider,
|
|
2478
|
+
signal: ac.signal,
|
|
2479
|
+
inquirer
|
|
2480
|
+
});
|
|
2421
2481
|
} else {
|
|
2422
2482
|
info(`
|
|
2423
2483
|
To deploy later: clawops apply ${outputPath}`);
|
|
@@ -2427,8 +2487,8 @@ To deploy later: clawops apply ${outputPath}`);
|
|
|
2427
2487
|
});
|
|
2428
2488
|
async function runLocalDeploy(opts) {
|
|
2429
2489
|
const { setConfig: setConfig2, getConfig: getConfig2, getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
|
|
2430
|
-
const { localBootstrap } = await import("./bootstrap-
|
|
2431
|
-
const { connect } = await import("./ssh-
|
|
2490
|
+
const { localBootstrap } = await import("./bootstrap-RY4VOSDJ.js");
|
|
2491
|
+
const { connect } = await import("./ssh-E2AMBPZY.js");
|
|
2432
2492
|
const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
|
|
2433
2493
|
const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
|
|
2434
2494
|
const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
|
|
@@ -2510,7 +2570,7 @@ async function runLocalDeploy(opts) {
|
|
|
2510
2570
|
spin2.fail("Configuration failed");
|
|
2511
2571
|
throw err;
|
|
2512
2572
|
}
|
|
2513
|
-
const { drainPool } = await import("./pool-
|
|
2573
|
+
const { drainPool } = await import("./pool-JZGKPP6K.js");
|
|
2514
2574
|
drainPool();
|
|
2515
2575
|
const tokenPath = path3.join(os.homedir(), ".clawops", "secrets", `GATEWAY_TOKEN_${opts.stackName}`);
|
|
2516
2576
|
const dashboardUrl = `${state.gatewayUrl}?token=${opts.gatewayToken}`;
|
|
@@ -2648,7 +2708,7 @@ var DOCKER_CHECK_CMD = [
|
|
|
2648
2708
|
"echo NOT_RUNNING"
|
|
2649
2709
|
].join("; ");
|
|
2650
2710
|
async function checkDockerPreflight(opts) {
|
|
2651
|
-
const { acquireSession } = await import("./pool-
|
|
2711
|
+
const { acquireSession } = await import("./pool-JZGKPP6K.js");
|
|
2652
2712
|
const { ProviderError } = await import("./errors-OK47MQFD.js");
|
|
2653
2713
|
const spin = spinner("Checking Docker on target host...");
|
|
2654
2714
|
const timeoutSignal = AbortSignal.timeout(DOCKER_PREFLIGHT_TIMEOUT_MS);
|
|
@@ -2695,7 +2755,7 @@ async function checkDockerPreflight(opts) {
|
|
|
2695
2755
|
var DOCKER_POLL_MS = 3e3;
|
|
2696
2756
|
var DOCKER_TIMEOUT_MS = 9e4;
|
|
2697
2757
|
async function startRemoteDocker(opts, spin) {
|
|
2698
|
-
const { acquireSession } = await import("./pool-
|
|
2758
|
+
const { acquireSession } = await import("./pool-JZGKPP6K.js");
|
|
2699
2759
|
const { ProviderError } = await import("./errors-OK47MQFD.js");
|
|
2700
2760
|
spin.text = "Starting Docker on the remote server...";
|
|
2701
2761
|
const { session, release } = await acquireSession({
|
|
@@ -2899,7 +2959,7 @@ async function maybeWireGatewayMcp(opts) {
|
|
|
2899
2959
|
process20.stdout.write("\n");
|
|
2900
2960
|
const { wireGateway } = await inquirerPromptWire(opts.inquirer);
|
|
2901
2961
|
if (!wireGateway) return;
|
|
2902
|
-
const { connect } = await import("./ssh-
|
|
2962
|
+
const { connect } = await import("./ssh-E2AMBPZY.js");
|
|
2903
2963
|
const { getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
|
|
2904
2964
|
const { wireGatewayMcp } = await import("./mcp-wire-ZWIYMLEW.js");
|
|
2905
2965
|
const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
|
|
@@ -2992,6 +3052,68 @@ function instanceChoices(provider) {
|
|
|
2992
3052
|
};
|
|
2993
3053
|
return table[provider] ?? [];
|
|
2994
3054
|
}
|
|
3055
|
+
async function maybeHarden(opts) {
|
|
3056
|
+
const { MODULE_CATALOG, resolveModules, runHardening, formatHardenSummary } = await import("./harden-BDVYW567.js");
|
|
3057
|
+
const { getConfig: getConfig2 } = await import("./store-SDUR52Z5.js");
|
|
3058
|
+
const config = getConfig2();
|
|
3059
|
+
if (!config) return;
|
|
3060
|
+
const availableModules = resolveModules(MODULE_CATALOG, void 0, opts.provider);
|
|
3061
|
+
if (availableModules.length === 0) return;
|
|
3062
|
+
process20.stdout.write("\n");
|
|
3063
|
+
const { selectedIds } = await opts.inquirer.prompt([{
|
|
3064
|
+
type: "checkbox",
|
|
3065
|
+
name: "selectedIds",
|
|
3066
|
+
message: "Apply security hardening? (Space to toggle, Enter to confirm)",
|
|
3067
|
+
choices: availableModules.map((m) => ({
|
|
3068
|
+
name: `${m.label}${m.defaultOn ? "" : " (opt-in)"}`,
|
|
3069
|
+
value: m.id,
|
|
3070
|
+
checked: m.defaultOn
|
|
3071
|
+
}))
|
|
3072
|
+
}]);
|
|
3073
|
+
if (selectedIds.length === 0) {
|
|
3074
|
+
info("Hardening skipped. Run `clawops harden --stack " + opts.stackName + "` later.");
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3077
|
+
const modules = availableModules.filter((m) => selectedIds.includes(m.id));
|
|
3078
|
+
process20.stdout.write("\nApplying hardening modules...\n\n");
|
|
3079
|
+
try {
|
|
3080
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
3081
|
+
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
3082
|
+
const ctx = buildContext({ stack: opts.stackName });
|
|
3083
|
+
const stackObj = await ctx.getStack();
|
|
3084
|
+
const outputMap = await stackObj.outputs();
|
|
3085
|
+
const outputs = Object.fromEntries(
|
|
3086
|
+
Object.entries(outputMap).map(([k, v]) => [k, v.value])
|
|
3087
|
+
);
|
|
3088
|
+
const base = extractBaseOutputs(outputs);
|
|
3089
|
+
const conn = ctx.adapter.getConnectionInfo({
|
|
3090
|
+
...base,
|
|
3091
|
+
privateKeyPath: config.ssh.keyPath,
|
|
3092
|
+
knownHostsPath: config.ssh.knownHostsPath
|
|
3093
|
+
});
|
|
3094
|
+
const { success: ok, failure: fail } = await import("./human-Z44CW7TR.js");
|
|
3095
|
+
const results = await runHardening(conn, {
|
|
3096
|
+
modules,
|
|
3097
|
+
signal: opts.signal,
|
|
3098
|
+
onProgress: (r) => {
|
|
3099
|
+
process20.stdout.write(` \xB7 ${r.module.label}
|
|
3100
|
+
`);
|
|
3101
|
+
}
|
|
3102
|
+
});
|
|
3103
|
+
process20.stdout.write("\n" + formatHardenSummary(results));
|
|
3104
|
+
const errors = results.filter((r) => r.error);
|
|
3105
|
+
if (errors.length > 0) {
|
|
3106
|
+
for (const r of errors) fail(`${r.module.label}: ${r.error}`);
|
|
3107
|
+
info("Some modules failed. Run `clawops harden --stack " + opts.stackName + "` to retry.");
|
|
3108
|
+
} else {
|
|
3109
|
+
ok("Hardening complete.");
|
|
3110
|
+
}
|
|
3111
|
+
} catch (err) {
|
|
3112
|
+
const { failure: fail } = await import("./human-Z44CW7TR.js");
|
|
3113
|
+
fail(`Hardening failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
3114
|
+
info("Run `clawops harden --stack " + opts.stackName + "` to retry.");
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
2995
3117
|
|
|
2996
3118
|
// src/cli/commands/secret.ts
|
|
2997
3119
|
import { defineCommand as defineCommand19 } from "citty";
|
|
@@ -3164,10 +3286,10 @@ var rotateCmd = defineCommand19({
|
|
|
3164
3286
|
}
|
|
3165
3287
|
info(`Re-applying config overlay to stack "${targetStack}"\u2026`);
|
|
3166
3288
|
try {
|
|
3167
|
-
const { buildContext } = await import("./context-
|
|
3289
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
3168
3290
|
const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
|
|
3169
3291
|
const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
|
|
3170
|
-
const { acquireSession, drainPool } = await import("./pool-
|
|
3292
|
+
const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
|
|
3171
3293
|
const { localStateToConnectionInfo } = await import("./state-PRBIIN7I.js");
|
|
3172
3294
|
const ctx = buildContext({ stack: targetStack });
|
|
3173
3295
|
let conn;
|
|
@@ -3344,26 +3466,254 @@ ${dim("Run `clawops <command> --help` for command-specific flags.")}
|
|
|
3344
3466
|
}
|
|
3345
3467
|
});
|
|
3346
3468
|
|
|
3347
|
-
// src/cli/
|
|
3469
|
+
// src/cli/commands/bug.ts
|
|
3470
|
+
import { defineCommand as defineCommand21 } from "citty";
|
|
3348
3471
|
import process22 from "process";
|
|
3472
|
+
import { accessSync as accessSync2, constants as constants2 } from "fs";
|
|
3473
|
+
import { execSync as execSync2 } from "child_process";
|
|
3474
|
+
var ISSUES_URL = `${REPO_URL}/issues/new`;
|
|
3475
|
+
var BODY_CAP = 2e3;
|
|
3476
|
+
var VERSION = true ? "1.7.0" : "dev";
|
|
3477
|
+
async function collectContext() {
|
|
3478
|
+
const nodeVersion = process22.version;
|
|
3479
|
+
const os3 = `${process22.platform} ${process22.arch}`;
|
|
3480
|
+
let provider = "unknown";
|
|
3481
|
+
let stackCount = 0;
|
|
3482
|
+
let sshKey = "unknown";
|
|
3483
|
+
try {
|
|
3484
|
+
const { getConfig: getConfig2 } = await import("./store-SDUR52Z5.js");
|
|
3485
|
+
const config = getConfig2();
|
|
3486
|
+
if (config) {
|
|
3487
|
+
const stacks = Object.values(config.stacks);
|
|
3488
|
+
stackCount = stacks.length;
|
|
3489
|
+
provider = stacks[0]?.provider ?? "none";
|
|
3490
|
+
const keyPath = config.ssh.keyPath.replace(/^~/, process22.env["HOME"] ?? "~");
|
|
3491
|
+
try {
|
|
3492
|
+
accessSync2(keyPath, constants2.R_OK);
|
|
3493
|
+
sshKey = "present";
|
|
3494
|
+
} catch {
|
|
3495
|
+
sshKey = "missing";
|
|
3496
|
+
}
|
|
3497
|
+
} else {
|
|
3498
|
+
provider = "not configured";
|
|
3499
|
+
sshKey = "not configured";
|
|
3500
|
+
}
|
|
3501
|
+
} catch {
|
|
3502
|
+
}
|
|
3503
|
+
return [
|
|
3504
|
+
`**clawops version:** ${VERSION}`,
|
|
3505
|
+
`**Node:** ${nodeVersion}`,
|
|
3506
|
+
`**OS:** ${os3}`,
|
|
3507
|
+
`**Provider:** ${provider}`,
|
|
3508
|
+
`**Stacks:** ${stackCount}`,
|
|
3509
|
+
`**SSH key:** ${sshKey}`
|
|
3510
|
+
].join("\n");
|
|
3511
|
+
}
|
|
3512
|
+
function buildIssueUrl(title, command, context) {
|
|
3513
|
+
const body = [
|
|
3514
|
+
context,
|
|
3515
|
+
"",
|
|
3516
|
+
"**Description:**",
|
|
3517
|
+
title,
|
|
3518
|
+
"",
|
|
3519
|
+
command ? `**Command:**
|
|
3520
|
+
\`${command}\`` : "",
|
|
3521
|
+
"",
|
|
3522
|
+
"**Steps to reproduce:**",
|
|
3523
|
+
"<!-- Please describe what you did -->\n"
|
|
3524
|
+
].filter((l) => l !== void 0).join("\n").slice(0, BODY_CAP);
|
|
3525
|
+
const params = new URLSearchParams({ title, body });
|
|
3526
|
+
return `${ISSUES_URL}?${params.toString()}`;
|
|
3527
|
+
}
|
|
3528
|
+
function openBrowser2(url) {
|
|
3529
|
+
try {
|
|
3530
|
+
const cmd = process22.platform === "darwin" ? "open" : "xdg-open";
|
|
3531
|
+
execSync2(`${cmd} "${url}"`, { stdio: "ignore" });
|
|
3532
|
+
return true;
|
|
3533
|
+
} catch {
|
|
3534
|
+
return false;
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
var bug_default = defineCommand21({
|
|
3538
|
+
meta: {
|
|
3539
|
+
name: "bug",
|
|
3540
|
+
description: "Open a pre-filled GitHub issue with system context from clawops doctor"
|
|
3541
|
+
},
|
|
3542
|
+
args: {
|
|
3543
|
+
json: { type: "boolean", description: "Emit issue URL as JSON without opening a browser" }
|
|
3544
|
+
},
|
|
3545
|
+
async run({ args }) {
|
|
3546
|
+
const context = await collectContext();
|
|
3547
|
+
let title = "";
|
|
3548
|
+
let command = "";
|
|
3549
|
+
if (!args.json) {
|
|
3550
|
+
const { createInterface: createInterface3 } = await import("readline/promises");
|
|
3551
|
+
const rl = createInterface3({ input: process22.stdin, output: process22.stdout });
|
|
3552
|
+
try {
|
|
3553
|
+
title = (await rl.question("Describe the issue in one line: ")).trim();
|
|
3554
|
+
command = (await rl.question("Which command triggered it? (optional): ")).trim();
|
|
3555
|
+
} finally {
|
|
3556
|
+
rl.close();
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
const url = buildIssueUrl(title, command, context);
|
|
3560
|
+
if (args.json) {
|
|
3561
|
+
printJson(jsonOk({ url }));
|
|
3562
|
+
return;
|
|
3563
|
+
}
|
|
3564
|
+
process22.stdout.write("\n");
|
|
3565
|
+
info(`Opening: ${url}`);
|
|
3566
|
+
process22.stdout.write("\n");
|
|
3567
|
+
const opened = openBrowser2(url);
|
|
3568
|
+
if (!opened) {
|
|
3569
|
+
process22.stdout.write(`Open this URL to file the issue:
|
|
3570
|
+
${url}
|
|
3571
|
+
`);
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
});
|
|
3575
|
+
|
|
3576
|
+
// src/cli/commands/harden.ts
|
|
3577
|
+
import { defineCommand as defineCommand22 } from "citty";
|
|
3578
|
+
import process23 from "process";
|
|
3579
|
+
var harden_default = defineCommand22({
|
|
3580
|
+
meta: {
|
|
3581
|
+
name: "harden",
|
|
3582
|
+
description: "Apply security hardening modules to a deployed stack"
|
|
3583
|
+
},
|
|
3584
|
+
args: {
|
|
3585
|
+
stack: { type: "string", description: "Target stack name" },
|
|
3586
|
+
options: { type: "string", description: "Comma-separated module IDs to run (default: all defaultOn modules)" },
|
|
3587
|
+
list: { type: "boolean", description: "List available modules and exit" },
|
|
3588
|
+
"dry-run": { type: "boolean", description: "Check current state without applying changes" },
|
|
3589
|
+
yes: { type: "boolean", description: "Skip confirmation prompt" },
|
|
3590
|
+
json: { type: "boolean", description: "Emit structured JSON output" }
|
|
3591
|
+
},
|
|
3592
|
+
async run({ args }) {
|
|
3593
|
+
const { MODULE_CATALOG, resolveModules, runHardening, formatHardenSummary } = await import("./harden-BDVYW567.js");
|
|
3594
|
+
const { buildContext } = await import("./context-ALSJMTHE.js");
|
|
3595
|
+
const { getConfig: getConfig2 } = await import("./store-SDUR52Z5.js");
|
|
3596
|
+
if (args.list) {
|
|
3597
|
+
process23.stdout.write("\nAvailable hardening modules:\n\n");
|
|
3598
|
+
for (const mod of MODULE_CATALOG) {
|
|
3599
|
+
const on = mod.defaultOn ? chalk.green("ON ") : chalk.dim("off");
|
|
3600
|
+
const providers = mod.providers === "all" ? "all" : mod.providers.join(", ");
|
|
3601
|
+
process23.stdout.write(
|
|
3602
|
+
` ${on} ${mod.id.padEnd(28)} ${mod.label} [${providers}]
|
|
3603
|
+
`
|
|
3604
|
+
);
|
|
3605
|
+
}
|
|
3606
|
+
process23.stdout.write("\n");
|
|
3607
|
+
return;
|
|
3608
|
+
}
|
|
3609
|
+
const config = getConfig2();
|
|
3610
|
+
if (!config) {
|
|
3611
|
+
failure("No clawops config found. Run `clawops init` first.");
|
|
3612
|
+
process23.exit(1);
|
|
3613
|
+
}
|
|
3614
|
+
const ctx = buildContext({ stack: args.stack });
|
|
3615
|
+
const provider = ctx.adapter.name;
|
|
3616
|
+
const modules = resolveModules(MODULE_CATALOG, args.options, provider);
|
|
3617
|
+
if (modules.length === 0) {
|
|
3618
|
+
warn("No modules selected for this provider. Use --options to specify modules or --list to see all.");
|
|
3619
|
+
return;
|
|
3620
|
+
}
|
|
3621
|
+
if (!args.json) {
|
|
3622
|
+
process23.stdout.write("\nModules to run:\n");
|
|
3623
|
+
for (const mod of modules) {
|
|
3624
|
+
const flag = mod.defaultOn ? "" : chalk.yellow(" [opt-in]");
|
|
3625
|
+
process23.stdout.write(` \xB7 ${mod.label}${flag}
|
|
3626
|
+
`);
|
|
3627
|
+
}
|
|
3628
|
+
process23.stdout.write("\n");
|
|
3629
|
+
}
|
|
3630
|
+
if (!args["dry-run"] && !args.yes && !args.json) {
|
|
3631
|
+
const { createInterface: createInterface3 } = await import("readline/promises");
|
|
3632
|
+
const rl = createInterface3({ input: process23.stdin, output: process23.stdout });
|
|
3633
|
+
const answer = await rl.question("Apply these hardening modules? [y/N] ");
|
|
3634
|
+
rl.close();
|
|
3635
|
+
if (!answer.toLowerCase().startsWith("y")) {
|
|
3636
|
+
info("Aborted.");
|
|
3637
|
+
return;
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3640
|
+
const ac = new AbortController();
|
|
3641
|
+
process23.on("SIGINT", () => ac.abort());
|
|
3642
|
+
process23.on("SIGTERM", () => ac.abort());
|
|
3643
|
+
const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
|
|
3644
|
+
const stackObj = await ctx.getStack();
|
|
3645
|
+
const outputMap = await stackObj.outputs();
|
|
3646
|
+
const outputs = Object.fromEntries(
|
|
3647
|
+
Object.entries(outputMap).map(([k, v]) => [k, v.value])
|
|
3648
|
+
);
|
|
3649
|
+
const base = extractBaseOutputs(outputs);
|
|
3650
|
+
const conn = ctx.adapter.getConnectionInfo({
|
|
3651
|
+
...base,
|
|
3652
|
+
privateKeyPath: config.ssh.keyPath,
|
|
3653
|
+
knownHostsPath: config.ssh.knownHostsPath
|
|
3654
|
+
});
|
|
3655
|
+
if (!args.json) {
|
|
3656
|
+
process23.stdout.write(args["dry-run"] ? "Checking hardening state...\n\n" : "Applying hardening...\n\n");
|
|
3657
|
+
}
|
|
3658
|
+
const results = await runHardening(conn, {
|
|
3659
|
+
modules,
|
|
3660
|
+
dryRun: args["dry-run"],
|
|
3661
|
+
signal: ac.signal,
|
|
3662
|
+
onProgress: args.json ? void 0 : (r) => {
|
|
3663
|
+
const icon = r.error ? chalk.red("\u2717") : r.applyResult?.changed ? chalk.green("\u2713") : chalk.dim("\xB7");
|
|
3664
|
+
process23.stdout.write(` ${icon} ${r.module.label}
|
|
3665
|
+
`);
|
|
3666
|
+
}
|
|
3667
|
+
});
|
|
3668
|
+
if (args.json) {
|
|
3669
|
+
printJson(jsonOk({
|
|
3670
|
+
dryRun: args["dry-run"] ?? false,
|
|
3671
|
+
results: results.map((r) => ({
|
|
3672
|
+
id: r.module.id,
|
|
3673
|
+
status: r.checkResult.status,
|
|
3674
|
+
changed: r.applyResult?.changed ?? false,
|
|
3675
|
+
detail: r.applyResult?.detail ?? r.checkResult.detail,
|
|
3676
|
+
error: r.error,
|
|
3677
|
+
durationMs: r.durationMs
|
|
3678
|
+
}))
|
|
3679
|
+
}));
|
|
3680
|
+
return;
|
|
3681
|
+
}
|
|
3682
|
+
process23.stdout.write("\n" + formatHardenSummary(results));
|
|
3683
|
+
const errors = results.filter((r) => r.error);
|
|
3684
|
+
if (errors.length > 0) {
|
|
3685
|
+
process23.stdout.write("\n");
|
|
3686
|
+
for (const r of errors) {
|
|
3687
|
+
failure(`${r.module.label}: ${r.error}`);
|
|
3688
|
+
}
|
|
3689
|
+
process23.exit(1);
|
|
3690
|
+
}
|
|
3691
|
+
if (!args["dry-run"]) {
|
|
3692
|
+
success("Hardening complete.");
|
|
3693
|
+
}
|
|
3694
|
+
}
|
|
3695
|
+
});
|
|
3696
|
+
|
|
3697
|
+
// src/cli/error-handler.ts
|
|
3698
|
+
import process24 from "process";
|
|
3349
3699
|
function handleError(err) {
|
|
3350
3700
|
if (err instanceof ClawopsError) {
|
|
3351
3701
|
failure(err.message);
|
|
3352
|
-
|
|
3702
|
+
process24.exit(err.exitCode);
|
|
3353
3703
|
}
|
|
3354
3704
|
if (err instanceof Error) {
|
|
3355
3705
|
failure(`Unexpected error: ${err.message}`);
|
|
3356
|
-
if (
|
|
3357
|
-
|
|
3706
|
+
if (process24.env["DEBUG"]) {
|
|
3707
|
+
process24.stderr.write(err.stack ?? "\n");
|
|
3358
3708
|
}
|
|
3359
|
-
|
|
3709
|
+
process24.exit(1);
|
|
3360
3710
|
}
|
|
3361
3711
|
failure(`Unknown error: ${String(err)}`);
|
|
3362
|
-
|
|
3712
|
+
process24.exit(1);
|
|
3363
3713
|
}
|
|
3364
3714
|
|
|
3365
3715
|
// src/cli/index.ts
|
|
3366
|
-
var main =
|
|
3716
|
+
var main = defineCommand23({
|
|
3367
3717
|
meta: {
|
|
3368
3718
|
name: "clawops",
|
|
3369
3719
|
description: "Deploy and manage self-hosted OpenClaw instances across clouds",
|
|
@@ -3399,7 +3749,9 @@ var main = defineCommand21({
|
|
|
3399
3749
|
setup: setup_default,
|
|
3400
3750
|
secret: secret_default,
|
|
3401
3751
|
monitor: monitor_default,
|
|
3402
|
-
help: help_default
|
|
3752
|
+
help: help_default,
|
|
3753
|
+
bug: bug_default,
|
|
3754
|
+
harden: harden_default
|
|
3403
3755
|
}
|
|
3404
3756
|
});
|
|
3405
3757
|
try {
|