@clawops/cli 1.6.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/dist/cli.js CHANGED
@@ -1,25 +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 {
8
16
  REPO_URL,
9
17
  chalk,
10
18
  failure,
11
19
  info,
12
- monitor_default,
13
20
  printCta,
14
21
  spinner,
15
22
  success,
16
- validateOpenclawConfig,
17
23
  warn
18
- } from "./chunk-C5NDLOK2.js";
19
- import "./chunk-QI75OVJK.js";
20
- import "./chunk-LCKD7L7X.js";
21
- import "./chunk-GJEF6UQA.js";
22
- import "./chunk-ZFNPM2WG.js";
24
+ } from "./chunk-Q7NQY5HV.js";
23
25
  import "./chunk-A2I76FTA.js";
24
26
  import {
25
27
  getConfig,
@@ -33,7 +35,7 @@ import {
33
35
  } from "./chunk-KGXPLI7W.js";
34
36
 
35
37
  // src/cli/index.ts
36
- import { defineCommand as defineCommand22, runMain } from "citty";
38
+ import { defineCommand as defineCommand23, runMain } from "citty";
37
39
 
38
40
  // src/cli/commands/init.ts
39
41
  import { defineCommand } from "citty";
@@ -205,7 +207,7 @@ var up_default = defineCommand2({
205
207
  config: { type: "string", description: "Path to openclaw config overlay JSON (local provider only)" }
206
208
  },
207
209
  async run({ args }) {
208
- const { buildContext } = await import("./context-KPKBOWOP.js");
210
+ const { buildContext } = await import("./context-ALSJMTHE.js");
209
211
  const ctx = buildContext(args);
210
212
  const openclawVersion = typeof args["openclaw-version"] === "string" ? args["openclaw-version"] : "stable";
211
213
  if (ctx.adapter.name === "local") {
@@ -351,7 +353,7 @@ var down_default = defineCommand3({
351
353
  "dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
352
354
  },
353
355
  async run({ args }) {
354
- const { buildContext } = await import("./context-KPKBOWOP.js");
356
+ const { buildContext } = await import("./context-ALSJMTHE.js");
355
357
  const ctx = buildContext(args);
356
358
  if (args["dry-run"]) {
357
359
  info(`Dry run \u2014 would destroy stack "${ctx.stackName}"`);
@@ -415,7 +417,7 @@ var status_default = defineCommand4({
415
417
  json: { type: "boolean", description: "Emit JSON" }
416
418
  },
417
419
  async run({ args }) {
418
- const { buildContext } = await import("./context-KPKBOWOP.js");
420
+ const { buildContext } = await import("./context-ALSJMTHE.js");
419
421
  const ctx = buildContext(args);
420
422
  if (ctx.adapter.name === "local") {
421
423
  const state = ctx.localState;
@@ -487,8 +489,8 @@ var plan_default = defineCommand5({
487
489
  out: { type: "string", description: "Write plan JSON to this absolute path (default: stdout)" }
488
490
  },
489
491
  async run({ args }) {
490
- const { buildContext } = await import("./context-KPKBOWOP.js");
491
- const { generatePlan } = await import("./generate-YV7226Q7.js");
492
+ const { buildContext } = await import("./context-ALSJMTHE.js");
493
+ const { generatePlan } = await import("./generate-ZTD4BVVI.js");
492
494
  const ctx = buildContext(args);
493
495
  if (ctx.adapter.name === "local") {
494
496
  throw new UsageError(
@@ -578,7 +580,7 @@ var apply_default = defineCommand6({
578
580
  },
579
581
  async run({ args }) {
580
582
  const { validatePlan } = await import("./validate-T5M5EHSJ.js");
581
- const { applyPlan } = await import("./apply-SI3JKS4Z.js");
583
+ const { applyPlan } = await import("./apply-BTZFFGAD.js");
582
584
  const planPath = args._?.[0];
583
585
  if (!planPath) {
584
586
  throw new UsageError("Usage: clawops apply <plan.json>");
@@ -694,7 +696,7 @@ var destroy_default = defineCommand7({
694
696
  "dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
695
697
  },
696
698
  async run({ args }) {
697
- const { buildContext } = await import("./context-KPKBOWOP.js");
699
+ const { buildContext } = await import("./context-ALSJMTHE.js");
698
700
  const ctx = buildContext(args);
699
701
  if (ctx.adapter.name === "local") {
700
702
  throw new UsageError(
@@ -761,7 +763,7 @@ var ssh_default = defineCommand8({
761
763
  command: { type: "string", description: "Remote command to run (instead of interactive shell)" }
762
764
  },
763
765
  async run({ args }) {
764
- const { buildContext } = await import("./context-KPKBOWOP.js");
766
+ const { buildContext } = await import("./context-ALSJMTHE.js");
765
767
  const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
766
768
  const ctx = buildContext(args);
767
769
  let conn;
@@ -848,7 +850,7 @@ var tunnel_default = defineCommand9({
848
850
  "no-open": { type: "boolean", description: "Do not open browser after tunnel is ready" }
849
851
  },
850
852
  async run({ args }) {
851
- const { buildContext } = await import("./context-KPKBOWOP.js");
853
+ const { buildContext } = await import("./context-ALSJMTHE.js");
852
854
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
853
855
  const { acquireSession } = await import("./pool-JZGKPP6K.js");
854
856
  const ctx = buildContext(args);
@@ -916,7 +918,7 @@ var logs_default = defineCommand10({
916
918
  since: { type: "string", description: "Show logs since duration (e.g. 5m, 1h)" }
917
919
  },
918
920
  async run({ args }) {
919
- const { buildContext } = await import("./context-KPKBOWOP.js");
921
+ const { buildContext } = await import("./context-ALSJMTHE.js");
920
922
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
921
923
  const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
922
924
  const ctx = buildContext(args);
@@ -1033,7 +1035,7 @@ var config_default = defineCommand11({
1033
1035
  "dry-run": { type: "boolean", description: "Show what would change without writing" }
1034
1036
  },
1035
1037
  async run({ args }) {
1036
- const { buildContext } = await import("./context-KPKBOWOP.js");
1038
+ const { buildContext } = await import("./context-ALSJMTHE.js");
1037
1039
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1038
1040
  const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1039
1041
  const [action, key, value] = args._ ?? [];
@@ -1159,7 +1161,7 @@ var agents_default = defineCommand12({
1159
1161
  json: { type: "boolean", description: "Emit JSON (for list)" }
1160
1162
  },
1161
1163
  async run({ args }) {
1162
- const { buildContext } = await import("./context-KPKBOWOP.js");
1164
+ const { buildContext } = await import("./context-ALSJMTHE.js");
1163
1165
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1164
1166
  const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1165
1167
  const [action, name] = args._ ?? [];
@@ -1263,7 +1265,7 @@ var gateway_default = defineCommand13({
1263
1265
  json: { type: "boolean", description: "Emit JSON (for status)" }
1264
1266
  },
1265
1267
  async run({ args }) {
1266
- const { buildContext } = await import("./context-KPKBOWOP.js");
1268
+ const { buildContext } = await import("./context-ALSJMTHE.js");
1267
1269
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1268
1270
  const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1269
1271
  const [action, versionArg] = args._ ?? [];
@@ -1376,7 +1378,7 @@ var backup_default = defineCommand14({
1376
1378
  yes: { type: "boolean", description: "[restore] Skip confirmation prompt" }
1377
1379
  },
1378
1380
  async run({ args }) {
1379
- const { buildContext } = await import("./context-KPKBOWOP.js");
1381
+ const { buildContext } = await import("./context-ALSJMTHE.js");
1380
1382
  const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1381
1383
  const action = args.action;
1382
1384
  if (action !== "create" && action !== "restore") {
@@ -1549,7 +1551,7 @@ var stacks_default = defineCommand15({
1549
1551
  let isDeployed = false;
1550
1552
  if (!args.force) {
1551
1553
  try {
1552
- const { buildContext } = await import("./context-KPKBOWOP.js");
1554
+ const { buildContext } = await import("./context-ALSJMTHE.js");
1553
1555
  const ctx = buildContext({ stack: name });
1554
1556
  if (ctx.adapter.name === "local") {
1555
1557
  isDeployed = !!ctx.localState;
@@ -1707,7 +1709,7 @@ var doctor_default = defineCommand16({
1707
1709
  info("Remote health skipped \u2014 no config");
1708
1710
  } else {
1709
1711
  try {
1710
- const { buildContext } = await import("./context-KPKBOWOP.js");
1712
+ const { buildContext } = await import("./context-ALSJMTHE.js");
1711
1713
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1712
1714
  const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1713
1715
  const ctx = buildContext({ stack: args.stack });
@@ -1793,6 +1795,44 @@ var doctor_default = defineCommand16({
1793
1795
  }
1794
1796
  }
1795
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
+ }
1796
1836
  process18.stdout.write("\n");
1797
1837
  if (!nodeOk) {
1798
1838
  process18.stdout.write(
@@ -1822,7 +1862,7 @@ var serveCmd = defineCommand17({
1822
1862
  inspector: { type: "boolean", description: "Enable MCP inspector" }
1823
1863
  },
1824
1864
  async run({ args }) {
1825
- const { serveMcp } = await import("./server-3DEZHUWB.js");
1865
+ const { serveMcp } = await import("./server-EXBOOIEP.js");
1826
1866
  await serveMcp({
1827
1867
  port: args.http ? Number(args.http) : void 0,
1828
1868
  bind: args.bind,
@@ -1897,7 +1937,7 @@ var wireCmd = defineCommand17({
1897
1937
  force: { type: "boolean", description: "Apply even if gateway version is below minimum" }
1898
1938
  },
1899
1939
  async run({ args }) {
1900
- const { buildContext } = await import("./context-KPKBOWOP.js");
1940
+ const { buildContext } = await import("./context-ALSJMTHE.js");
1901
1941
  const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1902
1942
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1903
1943
  const { wireGatewayMcp } = await import("./mcp-wire-ZWIYMLEW.js");
@@ -2394,6 +2434,12 @@ var setup_default = defineCommand18({
2394
2434
  signal: ac.signal,
2395
2435
  inquirer
2396
2436
  });
2437
+ await maybeHarden({
2438
+ stackName: stackAnswers.stackName,
2439
+ provider: "local",
2440
+ signal: ac.signal,
2441
+ inquirer
2442
+ });
2397
2443
  } else {
2398
2444
  const { getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
2399
2445
  const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
@@ -2412,7 +2458,7 @@ var setup_default = defineCommand18({
2412
2458
  default: false
2413
2459
  }]);
2414
2460
  if (applyNow) {
2415
- const { applyPlan } = await import("./apply-SI3JKS4Z.js");
2461
+ const { applyPlan } = await import("./apply-BTZFFGAD.js");
2416
2462
  const plan = JSON.parse(readFileSync3(outputPath, "utf-8"));
2417
2463
  try {
2418
2464
  await applyPlan(plan, {
@@ -2426,6 +2472,12 @@ var setup_default = defineCommand18({
2426
2472
  process20.exit(1);
2427
2473
  }
2428
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
+ });
2429
2481
  } else {
2430
2482
  info(`
2431
2483
  To deploy later: clawops apply ${outputPath}`);
@@ -3000,6 +3052,68 @@ function instanceChoices(provider) {
3000
3052
  };
3001
3053
  return table[provider] ?? [];
3002
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
+ }
3003
3117
 
3004
3118
  // src/cli/commands/secret.ts
3005
3119
  import { defineCommand as defineCommand19 } from "citty";
@@ -3172,7 +3286,7 @@ var rotateCmd = defineCommand19({
3172
3286
  }
3173
3287
  info(`Re-applying config overlay to stack "${targetStack}"\u2026`);
3174
3288
  try {
3175
- const { buildContext } = await import("./context-KPKBOWOP.js");
3289
+ const { buildContext } = await import("./context-ALSJMTHE.js");
3176
3290
  const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
3177
3291
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
3178
3292
  const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
@@ -3359,7 +3473,7 @@ import { accessSync as accessSync2, constants as constants2 } from "fs";
3359
3473
  import { execSync as execSync2 } from "child_process";
3360
3474
  var ISSUES_URL = `${REPO_URL}/issues/new`;
3361
3475
  var BODY_CAP = 2e3;
3362
- var VERSION = true ? "1.6.0" : "dev";
3476
+ var VERSION = true ? "1.7.0" : "dev";
3363
3477
  async function collectContext() {
3364
3478
  const nodeVersion = process22.version;
3365
3479
  const os3 = `${process22.platform} ${process22.arch}`;
@@ -3459,26 +3573,147 @@ ${url}
3459
3573
  }
3460
3574
  });
3461
3575
 
3462
- // src/cli/error-handler.ts
3576
+ // src/cli/commands/harden.ts
3577
+ import { defineCommand as defineCommand22 } from "citty";
3463
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";
3464
3699
  function handleError(err) {
3465
3700
  if (err instanceof ClawopsError) {
3466
3701
  failure(err.message);
3467
- process23.exit(err.exitCode);
3702
+ process24.exit(err.exitCode);
3468
3703
  }
3469
3704
  if (err instanceof Error) {
3470
3705
  failure(`Unexpected error: ${err.message}`);
3471
- if (process23.env["DEBUG"]) {
3472
- process23.stderr.write(err.stack ?? "\n");
3706
+ if (process24.env["DEBUG"]) {
3707
+ process24.stderr.write(err.stack ?? "\n");
3473
3708
  }
3474
- process23.exit(1);
3709
+ process24.exit(1);
3475
3710
  }
3476
3711
  failure(`Unknown error: ${String(err)}`);
3477
- process23.exit(1);
3712
+ process24.exit(1);
3478
3713
  }
3479
3714
 
3480
3715
  // src/cli/index.ts
3481
- var main = defineCommand22({
3716
+ var main = defineCommand23({
3482
3717
  meta: {
3483
3718
  name: "clawops",
3484
3719
  description: "Deploy and manage self-hosted OpenClaw instances across clouds",
@@ -3515,7 +3750,8 @@ var main = defineCommand22({
3515
3750
  secret: secret_default,
3516
3751
  monitor: monitor_default,
3517
3752
  help: help_default,
3518
- bug: bug_default
3753
+ bug: bug_default,
3754
+ harden: harden_default
3519
3755
  }
3520
3756
  });
3521
3757
  try {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildContext
4
- } from "./chunk-QI75OVJK.js";
4
+ } from "./chunk-3MFZ7E74.js";
5
5
  import "./chunk-A2I76FTA.js";
6
6
  import "./chunk-CX5SL5HP.js";
7
7
  import "./chunk-KGXPLI7W.js";
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  generatePlan,
4
4
  planId
5
- } from "./chunk-72FF7IK2.js";
5
+ } from "./chunk-7KLLWDBA.js";
6
6
  import "./chunk-YTH4L2GN.js";
7
- import "./chunk-QI75OVJK.js";
7
+ import "./chunk-3MFZ7E74.js";
8
8
  import "./chunk-A2I76FTA.js";
9
9
  import "./chunk-CX5SL5HP.js";
10
10
  import "./chunk-KGXPLI7W.js";