@clawops/cli 2.1.1 → 2.1.3

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.
Files changed (30) hide show
  1. package/README.md +23 -1
  2. package/dist/{apply-HJ5GAKHW.js → apply-JARPVA5Y.js} +8 -8
  3. package/dist/{automation-MKCJ46I6.js → automation-NBYQ6MFZ.js} +1 -1
  4. package/dist/{bootstrap-NN647RCY.js → bootstrap-3PBVY7MA.js} +2 -2
  5. package/dist/{chunk-X56CQ6GB.js → chunk-4MHDW2NB.js} +1 -1
  6. package/dist/{chunk-3Z5TDXCJ.js → chunk-55UMO37O.js} +1 -1
  7. package/dist/chunk-755X5OGS.js +213 -0
  8. package/dist/{chunk-R3DTA35B.js → chunk-7T4CIT7C.js} +6 -6
  9. package/dist/{chunk-QDNFADJI.js → chunk-AVERNLUY.js} +6 -6
  10. package/dist/{chunk-GFUK6KDR.js → chunk-CPCO6UJK.js} +9 -9
  11. package/dist/{chunk-64PONSA5.js → chunk-GFIR2IIJ.js} +3 -1
  12. package/dist/{chunk-YEBFVLOE.js → chunk-PTCVFLZ3.js} +4 -4
  13. package/dist/{chunk-ELU3XQEA.js → chunk-RDUKRIRC.js} +1 -1
  14. package/dist/{chunk-OFTAXLOY.js → chunk-TYHTISI5.js} +239 -159
  15. package/dist/cli.js +127 -274
  16. package/dist/{context-7VI3R6EK.js → context-WOKSKAIA.js} +5 -5
  17. package/dist/{flows-RI7FGHAM.js → flows-HGJIA6EL.js} +7 -7
  18. package/dist/{generate-JNJ63ZYZ.js → generate-NE54BATS.js} +6 -6
  19. package/dist/{harden-3KKCR7BL.js → harden-RUOUA5BV.js} +2 -2
  20. package/dist/init-HOPXDNWY.js +13 -0
  21. package/dist/{mcp-wire-B57DUNOD.js → mcp-wire-FIO5DFBY.js} +11 -11
  22. package/dist/{package-SAUDFQLG.js → package-MF5LPITL.js} +1 -1
  23. package/dist/{server-RHON6QMN.js → server-OXWHBTXK.js} +11 -11
  24. package/dist/{stack-config-LUTS2XAD.js → stack-config-ICQ5YHUL.js} +2 -2
  25. package/dist/{state-AOAYLYY5.js → state-AKZP2S4T.js} +2 -2
  26. package/dist/{store-OVB3DAJR.js → store-YOLQYXMB.js} +1 -1
  27. package/dist/{tailscale-cutover-6YP2QKFM.js → tailscale-cutover-EKAQSDXP.js} +2 -2
  28. package/package.json +1 -1
  29. package/spec/mcp-tools.yaml +69 -28
  30. package/dist/{chunk-BELTQGHT.js → chunk-CHNSL3TC.js} +3 -3
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  monitor_default,
9
9
  runDiagnostics
10
- } from "./chunk-GFUK6KDR.js";
10
+ } from "./chunk-CPCO6UJK.js";
11
11
  import {
12
12
  GATEWAY_LOGS_PROBE,
13
13
  chooseLogSource,
@@ -20,6 +20,7 @@ import {
20
20
  execPrivilegedWithInput,
21
21
  streamPrivileged
22
22
  } from "./chunk-NUDIHZEH.js";
23
+ import "./chunk-CHNSL3TC.js";
23
24
  import {
24
25
  resolveSpecDir
25
26
  } from "./chunk-JW5A7E3X.js";
@@ -27,7 +28,7 @@ import {
27
28
  interpretProbe,
28
29
  probeCommand
29
30
  } from "./chunk-LT4XMO5D.js";
30
- import "./chunk-BELTQGHT.js";
31
+ import "./chunk-VUFMZEIM.js";
31
32
  import {
32
33
  CONFIG_FILENAME,
33
34
  CONTAINER_UID,
@@ -58,110 +59,29 @@ import {
58
59
  } from "./chunk-Q7NQY5HV.js";
59
60
  import "./chunk-N4WZLWJ4.js";
60
61
  import {
61
- getConfig,
62
+ SUPPORTED_PROVIDERS,
63
+ deriveStateBucket,
64
+ initStack,
65
+ resolveScopeAccount,
66
+ validateStateBucket
67
+ } from "./chunk-755X5OGS.js";
68
+ import {
62
69
  getConfigDir,
63
70
  requireConfig,
64
71
  setConfig
65
- } from "./chunk-64PONSA5.js";
72
+ } from "./chunk-GFIR2IIJ.js";
66
73
  import {
67
74
  ClawopsError,
68
75
  UsageError
69
76
  } from "./chunk-KGXPLI7W.js";
70
- import "./chunk-VUFMZEIM.js";
71
77
 
72
78
  // src/cli/index.ts
73
79
  import { defineCommand as defineCommand24, runMain } from "citty";
74
80
 
75
81
  // src/cli/commands/init.ts
76
82
  import { defineCommand } from "citty";
77
- import { spawnSync } from "child_process";
78
- import { writeFileSync, mkdirSync, existsSync } from "fs";
79
83
  import path from "path";
80
84
  import process2 from "process";
81
-
82
- // src/providers/state-bucket.ts
83
- function deriveStateBucket(provider, scope) {
84
- if (provider === "azure") {
85
- return { ok: true, name: "clawops-state" };
86
- }
87
- if (!scope.account) {
88
- return {
89
- ok: false,
90
- needs: provider === "aws" ? "an AWS account id \u2014 set AWS_PROFILE, or run `aws sso login --profile <name>`" : "a GCP project \u2014 run `gcloud config set project <id>`, or set GOOGLE_CLOUD_PROJECT"
91
- };
92
- }
93
- if (provider === "gcp") return { ok: true, name: `clawops-state-${scope.account}` };
94
- if (!scope.region) return { ok: false, needs: "a region" };
95
- return { ok: true, name: `clawops-state-${scope.account}-${scope.region}` };
96
- }
97
- function stateUrlFor(provider, bucket) {
98
- const verdict = validateStateBucket(provider, bucket);
99
- if (verdict !== true) throw new Error(`Not a usable ${provider} state backend name: ${verdict}`);
100
- const scheme = provider === "aws" ? "s3://" : provider === "gcp" ? "gs://" : "azblob://";
101
- return provider === "azure" ? `${scheme}${bucket}` : `${scheme}${bucket}/clawops`;
102
- }
103
- var IPV4 = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
104
- function validateStateBucket(provider, name) {
105
- const n = name.trim();
106
- if (n === "") return "Required";
107
- if (n !== name) return "No leading or trailing spaces";
108
- if (n.length < 3) return `Too short \u2014 ${labelFor(provider)} names are at least 3 characters`;
109
- const dotted = provider === "gcp" && n.includes(".");
110
- const max = dotted ? 222 : 63;
111
- if (n.length > max) return `Too long \u2014 ${labelFor(provider)} names are at most ${max} characters`;
112
- if (dotted && n.split(".").some((part) => part.length > 63)) {
113
- return "Each dot-separated part of a Cloud Storage name is at most 63 characters";
114
- }
115
- if (n !== n.toLowerCase()) return "Lowercase only";
116
- if (provider === "azure") {
117
- if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(n)) {
118
- return "Letters, digits and single hyphens only, starting and ending with a letter or digit";
119
- }
120
- return true;
121
- }
122
- if (!/^[a-z0-9][a-z0-9._-]*[a-z0-9]$/.test(n)) {
123
- return "Letters, digits, dots, hyphens and underscores only, starting and ending with a letter or digit";
124
- }
125
- if (n.includes("..")) return "No consecutive dots";
126
- if (IPV4.test(n)) return "Cannot be formatted as an IP address";
127
- if (provider === "aws") {
128
- if (n.startsWith("xn--")) return 'Cannot start with "xn--"';
129
- if (n.startsWith("sthree-")) return 'Cannot start with "sthree-"';
130
- if (n.endsWith("-s3alias")) return 'Cannot end with "-s3alias"';
131
- if (n.endsWith("--ol-s3")) return 'Cannot end with "--ol-s3"';
132
- if (n.includes("_")) return "Underscores are not allowed in S3 bucket names";
133
- return true;
134
- }
135
- if (n.startsWith("goog")) return 'Cannot start with "goog"';
136
- if (n.includes("google")) return 'Cannot contain "google"';
137
- return true;
138
- }
139
- function labelFor(provider) {
140
- if (provider === "aws") return "S3 bucket";
141
- if (provider === "gcp") return "Cloud Storage bucket";
142
- return "blob container";
143
- }
144
- async function resolveScopeAccount(provider, signal) {
145
- if (provider === "azure") return void 0;
146
- try {
147
- if (provider === "aws") {
148
- const { callerAccount } = await import("./preflight-TFD4N5ZU.js");
149
- return await callerAccount(signal);
150
- }
151
- const { resolveProjectId } = await import("./preflight-IE2YWBAC.js");
152
- return resolveProjectId();
153
- } catch {
154
- return void 0;
155
- }
156
- }
157
-
158
- // src/cli/commands/init.ts
159
- var SUPPORTED_PROVIDERS = ["gcp", "aws", "azure", "local"];
160
- var PROVIDER_DEFAULTS = {
161
- gcp: { region: "us-central1", credEnv: "GOOGLE_APPLICATION_CREDENTIALS", stateScheme: "gs://" },
162
- aws: { region: "us-east-1", credEnv: "AWS_PROFILE", stateScheme: "s3://" },
163
- azure: { region: "eastus", credEnv: "AZURE_CLIENT_ID", stateScheme: "azblob://" }
164
- };
165
85
  var init_default = defineCommand({
166
86
  meta: {
167
87
  name: "init",
@@ -183,8 +103,6 @@ var init_default = defineCommand({
183
103
  async run({ args }) {
184
104
  const nonInteractive = Boolean(args["non-interactive"]);
185
105
  const providerArg = typeof args.provider === "string" ? args.provider : null;
186
- const stackName = typeof args.stack === "string" ? args.stack : "default";
187
- const forceOverwrite = Boolean(args.force);
188
106
  if (nonInteractive && !providerArg) {
189
107
  throw new UsageError(
190
108
  "--non-interactive requires --provider. Example: clawops init --provider gcp --non-interactive"
@@ -196,107 +114,42 @@ var init_default = defineCommand({
196
114
  `Unsupported provider: ${provider}. Supported: ${SUPPORTED_PROVIDERS.join(", ")}`
197
115
  );
198
116
  }
199
- const existing = getConfig();
200
- if (existing?.stacks[stackName] && !forceOverwrite) {
201
- failure(
202
- `Stack "${stackName}" already exists in ${path.join(getConfigDir(), "config.json")} (${existing.stacks[stackName].stateUrl}). Use --force to overwrite its settings, or pass a different --stack name to add another one.`
203
- );
204
- process2.exit(1);
205
- }
206
- const configDir = getConfigDir();
207
- mkdirSync(configDir, { recursive: true });
208
- const keyPath = typeof args["key-path"] === "string" ? args["key-path"] : path.join(configDir, "id_ed25519");
209
- const knownHostsPath = path.join(configDir, "known_hosts");
210
- if (!existsSync(keyPath)) {
211
- if (typeof args["key-path"] === "string") {
212
- throw new UsageError(`SSH key not found at ${keyPath}`);
213
- }
214
- info("Generating SSH key pair...");
215
- const gen = spawnSync(
216
- "ssh-keygen",
217
- ["-t", "ed25519", "-f", keyPath, "-N", "", "-C", "clawops", "-q"],
218
- { stdio: ["ignore", "pipe", "pipe"] }
219
- );
220
- if (gen.error || gen.status !== 0) {
221
- const reason = gen.error?.message ?? gen.stderr?.toString().trim() ?? `exit ${gen.status}`;
222
- throw new UsageError(
223
- `Could not generate an SSH key: ${reason}
224
- Generate one yourself and point clawops at it:
225
- ssh-keygen -t ed25519 -f ${keyPath} -N '' -C clawops
226
- clawops init --key-path ${keyPath}`
227
- );
117
+ const result = await initStack({
118
+ provider,
119
+ stackName: typeof args.stack === "string" ? args.stack : void 0,
120
+ stateUrl: typeof args.state === "string" ? args.state : void 0,
121
+ region: typeof args.region === "string" ? args.region : void 0,
122
+ force: Boolean(args.force),
123
+ keyPath: typeof args["key-path"] === "string" ? args["key-path"] : void 0,
124
+ host: typeof args.host === "string" ? args.host : void 0,
125
+ sshUser: typeof args["ssh-user"] === "string" ? args["ssh-user"] : void 0,
126
+ sshPort: typeof args["ssh-port"] === "string" ? parseInt(args["ssh-port"], 10) : void 0
127
+ });
128
+ if (!result.ok) {
129
+ if (result.reason.includes("already exists")) {
130
+ failure(result.reason.replace("Pass force", "Use --force"));
131
+ process2.exit(1);
228
132
  }
229
- success(`SSH key pair written to ${keyPath} (and ${keyPath}.pub)`);
230
- } else {
231
- info(`Using existing SSH key at ${keyPath}`);
133
+ throw new UsageError(result.reason);
232
134
  }
233
- if (!existsSync(knownHostsPath)) {
234
- writeFileSync(knownHostsPath, "", "utf-8");
235
- }
236
- let config;
237
- if (provider === "local") {
238
- const host = typeof args.host === "string" ? args.host : "";
239
- if (!host) {
240
- throw new UsageError("--host is required for the local provider");
241
- }
242
- const sshUser = typeof args["ssh-user"] === "string" ? args["ssh-user"] : "root";
243
- const sshPort = typeof args["ssh-port"] === "string" ? parseInt(args["ssh-port"], 10) : 22;
244
- config = merge(existing, stackName, provider, keyPath, knownHostsPath, {
245
- provider,
246
- stateUrl: "file://~/.clawops/state",
247
- credentialsRef: { source: "file", envVars: [] },
248
- localOpts: { host, sshUser, sshPort, sshKeyPath: keyPath }
249
- });
250
- } else {
251
- const defaults = PROVIDER_DEFAULTS[provider];
252
- const region = typeof args.region === "string" ? args.region : defaults.region;
253
- let stateUrl;
254
- if (typeof args.state === "string") {
255
- stateUrl = args.state;
256
- } else {
257
- const account = await resolveScopeAccount(provider);
258
- const derived = deriveStateBucket(provider, { account, region });
259
- if (!derived.ok) {
260
- throw new UsageError(
261
- `Could not name a state backend for ${provider}: clawops needs ${derived.needs}.
262
- Authenticate and run this again, or name the backend yourself:
263
- clawops init --provider ${provider} --state ${defaults.stateScheme}your-bucket/clawops`
264
- );
265
- }
266
- stateUrl = stateUrlFor(provider, derived.name);
267
- }
268
- config = merge(existing, stackName, provider, keyPath, knownHostsPath, {
269
- provider,
270
- stateUrl,
271
- region,
272
- credentialsRef: { source: "env", envVars: [defaults.credEnv] }
273
- });
135
+ if (result.keyGenerated) success(`SSH key pair written to ${result.keyPath} (and ${result.keyPath}.pub)`);
136
+ else info(`Using existing SSH key at ${result.keyPath}`);
137
+ if (result.provider !== "local") {
274
138
  process2.stdout.write("\n");
275
139
  info(
276
- `State backend: ${stateUrl}
277
- clawops doctor --provider ${provider} checks it exists, and clawops setup offers to create it.`
140
+ `State backend: ${result.stateUrl}
141
+ clawops doctor --provider ${result.provider} checks it exists, and clawops setup offers to create it.`
278
142
  );
279
143
  process2.stdout.write("\n");
280
- success(`Provider: ${provider} Region: ${region} Stack: ${stackName}`);
281
- setConfig(config);
282
- success(`Config written to ${path.join(configDir, "config.json")}`);
144
+ success(`Provider: ${result.provider} Region: ${result.region} Stack: ${result.stackName}`);
145
+ success(`Config written to ${path.join(getConfigDir(), "config.json")}`);
283
146
  return;
284
147
  }
285
- setConfig(config);
286
- success(`Config written to ${path.join(configDir, "config.json")}`);
148
+ success(`Config written to ${result.configPath}`);
287
149
  process2.stdout.write("\n");
288
- success(`Provider: ${provider} Stack: ${stackName}`);
150
+ success(`Provider: ${result.provider} Stack: ${result.stackName}`);
289
151
  }
290
152
  });
291
- function merge(existing, stackName, provider, keyPath, knownHostsPath, stack) {
292
- return {
293
- ...existing ?? {},
294
- version: 1,
295
- defaults: { stack: stackName, provider },
296
- stacks: { ...existing?.stacks ?? {}, [stackName]: stack },
297
- ssh: { keyPath, knownHostsPath }
298
- };
299
- }
300
153
 
301
154
  // src/cli/commands/up.ts
302
155
  import { defineCommand as defineCommand2 } from "citty";
@@ -339,7 +192,7 @@ var up_default = defineCommand2({
339
192
  "publish-gateway": { type: "string", description: 'loopback (default) or all. "all" serves plaintext HTTP \u2014 put TLS in front of it' }
340
193
  },
341
194
  async run({ args }) {
342
- const { buildContext } = await import("./context-7VI3R6EK.js");
195
+ const { buildContext } = await import("./context-WOKSKAIA.js");
343
196
  const { guardOpenclawVersion, defaultOpenclawVersion } = await import("./version-guard-XVYW5WFJ.js");
344
197
  const ctx = buildContext(args);
345
198
  const requestedVersion = typeof args["openclaw-version"] === "string" ? args["openclaw-version"] : await defaultOpenclawVersion();
@@ -352,7 +205,7 @@ var up_default = defineCommand2({
352
205
  );
353
206
  }
354
207
  const { localOpts } = stackConfig;
355
- const { localBootstrap } = await import("./bootstrap-NN647RCY.js");
208
+ const { localBootstrap } = await import("./bootstrap-3PBVY7MA.js");
356
209
  const gatewayPort = parseGatewayPort(args["gateway-port"]);
357
210
  const abortController2 = new AbortController();
358
211
  process3.on("SIGINT", () => abortController2.abort());
@@ -392,8 +245,8 @@ var up_default = defineCommand2({
392
245
  }
393
246
  return;
394
247
  }
395
- const { generatePlan } = await import("./generate-JNJ63ZYZ.js");
396
- const { applyPlan } = await import("./apply-HJ5GAKHW.js");
248
+ const { generatePlan } = await import("./generate-NE54BATS.js");
249
+ const { applyPlan } = await import("./apply-JARPVA5Y.js");
397
250
  const { resolveNetworkFlags } = await import("./network-args-PYJRJBYO.js");
398
251
  const { detectEgressIp } = await import("./firewall-5VKZ4WBH.js");
399
252
  const isDryRun = Boolean(args["dry-run"]);
@@ -523,7 +376,7 @@ var down_default = defineCommand3({
523
376
  "dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
524
377
  },
525
378
  async run({ args }) {
526
- const { buildContext } = await import("./context-7VI3R6EK.js");
379
+ const { buildContext } = await import("./context-WOKSKAIA.js");
527
380
  const ctx = buildContext(args);
528
381
  if (args["dry-run"]) {
529
382
  info(`Dry run \u2014 would destroy stack "${ctx.stackName}"`);
@@ -587,7 +440,7 @@ var status_default = defineCommand4({
587
440
  json: { type: "boolean", description: "Emit JSON" }
588
441
  },
589
442
  async run({ args }) {
590
- const { buildContext } = await import("./context-7VI3R6EK.js");
443
+ const { buildContext } = await import("./context-WOKSKAIA.js");
591
444
  const ctx = buildContext(args);
592
445
  if (ctx.adapter.name === "local") {
593
446
  const state = ctx.localState;
@@ -643,7 +496,7 @@ var status_default = defineCommand4({
643
496
  // src/cli/commands/plan.ts
644
497
  import { defineCommand as defineCommand5 } from "citty";
645
498
  import process7 from "process";
646
- import { writeFileSync as writeFileSync2 } from "fs";
499
+ import { writeFileSync } from "fs";
647
500
  import { isAbsolute } from "path";
648
501
  function disruptionWarnings(diff) {
649
502
  const out = [];
@@ -687,8 +540,8 @@ var plan_default = defineCommand5({
687
540
  "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" }
688
541
  },
689
542
  async run({ args }) {
690
- const { buildContext } = await import("./context-7VI3R6EK.js");
691
- const { generatePlan } = await import("./generate-JNJ63ZYZ.js");
543
+ const { buildContext } = await import("./context-WOKSKAIA.js");
544
+ const { generatePlan } = await import("./generate-NE54BATS.js");
692
545
  const { resolveNetworkFlags } = await import("./network-args-PYJRJBYO.js");
693
546
  const { detectEgressIp } = await import("./firewall-5VKZ4WBH.js");
694
547
  const ctx = buildContext(args);
@@ -713,7 +566,7 @@ var plan_default = defineCommand5({
713
566
  let network = resolved;
714
567
  if (args["private-only"]) {
715
568
  const { privateOnlyNetwork, assertTailnetReachable } = await import("./private-only-DIA26I2E.js");
716
- const { probeSsh } = await import("./tailscale-cutover-6YP2QKFM.js");
569
+ const { probeSsh } = await import("./tailscale-cutover-EKAQSDXP.js");
717
570
  network = privateOnlyNetwork(flags, resolved, ctx.config.stacks[ctx.stackName]?.tailscale, ctx.stackName);
718
571
  await assertTailnetReachable(ctx, (conn) => probeSsh(conn));
719
572
  }
@@ -741,7 +594,7 @@ var plan_default = defineCommand5({
741
594
  }
742
595
  const planJson = JSON.stringify(plan, null, 2);
743
596
  if (outPath) {
744
- writeFileSync2(outPath, planJson + "\n", "utf-8");
597
+ writeFileSync(outPath, planJson + "\n", "utf-8");
745
598
  success(`Plan written to ${outPath}`);
746
599
  } else {
747
600
  process7.stdout.write(planJson + "\n");
@@ -804,7 +657,7 @@ var apply_default = defineCommand6({
804
657
  },
805
658
  async run({ args }) {
806
659
  const { validatePlan } = await import("./validate-JXKN5WD6.js");
807
- const { applyPlan } = await import("./apply-HJ5GAKHW.js");
660
+ const { applyPlan } = await import("./apply-JARPVA5Y.js");
808
661
  const planPath = args._?.[0];
809
662
  if (!planPath) {
810
663
  throw new UsageError("Usage: clawops apply <plan.json>");
@@ -930,7 +783,7 @@ var destroy_default = defineCommand7({
930
783
  "dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
931
784
  },
932
785
  async run({ args }) {
933
- const { buildContext } = await import("./context-7VI3R6EK.js");
786
+ const { buildContext } = await import("./context-WOKSKAIA.js");
934
787
  const ctx = buildContext(args);
935
788
  if (ctx.adapter.name === "local") {
936
789
  throw new UsageError(
@@ -1023,7 +876,7 @@ var ssh_default = defineCommand8({
1023
876
  command: { type: "string", description: "Remote command to run (instead of interactive shell)" }
1024
877
  },
1025
878
  async run({ args }) {
1026
- const { buildContext } = await import("./context-7VI3R6EK.js");
879
+ const { buildContext } = await import("./context-WOKSKAIA.js");
1027
880
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
1028
881
  const ctx = buildContext(args);
1029
882
  let conn;
@@ -1110,7 +963,7 @@ var tunnel_default = defineCommand9({
1110
963
  "no-open": { type: "boolean", description: "Do not open browser after tunnel is ready" }
1111
964
  },
1112
965
  async run({ args }) {
1113
- const { buildContext } = await import("./context-7VI3R6EK.js");
966
+ const { buildContext } = await import("./context-WOKSKAIA.js");
1114
967
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1115
968
  const { acquireSession } = await import("./pool-PIIKJ4L2.js");
1116
969
  const ctx = buildContext(args);
@@ -1179,7 +1032,7 @@ var logs_default = defineCommand10({
1179
1032
  json: { type: "boolean", description: "Emit the gateway's structured JSON log lines" }
1180
1033
  },
1181
1034
  async run({ args }) {
1182
- const { buildContext } = await import("./context-7VI3R6EK.js");
1035
+ const { buildContext } = await import("./context-WOKSKAIA.js");
1183
1036
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1184
1037
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
1185
1038
  const ctx = buildContext(args);
@@ -1285,7 +1138,7 @@ var config_default = defineCommand11({
1285
1138
  "dry-run": { type: "boolean", description: "Show what would change without writing" }
1286
1139
  },
1287
1140
  async run({ args }) {
1288
- const { buildContext } = await import("./context-7VI3R6EK.js");
1141
+ const { buildContext } = await import("./context-WOKSKAIA.js");
1289
1142
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1290
1143
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
1291
1144
  const [action, key, value] = args._ ?? [];
@@ -1420,7 +1273,7 @@ var agents_default = defineCommand12({
1420
1273
  cursor: { type: "string", description: "Continue from a previous `logs` result cursor" }
1421
1274
  },
1422
1275
  async run({ args }) {
1423
- const { buildContext } = await import("./context-7VI3R6EK.js");
1276
+ const { buildContext } = await import("./context-WOKSKAIA.js");
1424
1277
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1425
1278
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
1426
1279
  const [action, name] = args._ ?? [];
@@ -1652,7 +1505,7 @@ var migrate_default = defineCommand13({
1652
1505
  yes: { type: "boolean", description: "Skip the confirmation prompt" }
1653
1506
  },
1654
1507
  async run({ args }) {
1655
- const { buildContext } = await import("./context-7VI3R6EK.js");
1508
+ const { buildContext } = await import("./context-WOKSKAIA.js");
1656
1509
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1657
1510
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
1658
1511
  const { guardOpenclawVersion, defaultOpenclawVersion } = await import("./version-guard-XVYW5WFJ.js");
@@ -1791,7 +1644,7 @@ var gateway_default = defineCommand14({
1791
1644
  json: { type: "boolean", description: "Emit JSON (for status)" }
1792
1645
  },
1793
1646
  async run({ args }) {
1794
- const { buildContext } = await import("./context-7VI3R6EK.js");
1647
+ const { buildContext } = await import("./context-WOKSKAIA.js");
1795
1648
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1796
1649
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
1797
1650
  const [action, versionArg] = args._ ?? [];
@@ -2023,7 +1876,7 @@ var backup_default = defineCommand15({
2023
1876
  yes: { type: "boolean", description: "[restore] Skip confirmation prompt" }
2024
1877
  },
2025
1878
  async run({ args }) {
2026
- const { buildContext } = await import("./context-7VI3R6EK.js");
1879
+ const { buildContext } = await import("./context-WOKSKAIA.js");
2027
1880
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
2028
1881
  const action = args.action;
2029
1882
  if (action !== "create" && action !== "restore") {
@@ -2234,7 +2087,7 @@ var stacks_default = defineCommand16({
2234
2087
  let isDeployed = false;
2235
2088
  if (!args.force) {
2236
2089
  try {
2237
- const { buildContext } = await import("./context-7VI3R6EK.js");
2090
+ const { buildContext } = await import("./context-WOKSKAIA.js");
2238
2091
  const ctx = buildContext({ stack: name });
2239
2092
  if (ctx.adapter.name === "local") {
2240
2093
  isDeployed = !!ctx.localState;
@@ -2375,7 +2228,7 @@ var serveCmd = defineCommand18({
2375
2228
  inspector: { type: "boolean", description: "Enable MCP inspector" }
2376
2229
  },
2377
2230
  async run({ args }) {
2378
- const { serveMcp } = await import("./server-RHON6QMN.js");
2231
+ const { serveMcp } = await import("./server-OXWHBTXK.js");
2379
2232
  await serveMcp({
2380
2233
  port: args.http ? Number(args.http) : void 0,
2381
2234
  bind: args.bind,
@@ -2453,11 +2306,11 @@ var wireCmd = defineCommand18({
2453
2306
  rewire: { type: "boolean", description: "Replace an existing clawops entry" }
2454
2307
  },
2455
2308
  async run({ args }) {
2456
- const { buildContext } = await import("./context-7VI3R6EK.js");
2309
+ const { buildContext } = await import("./context-WOKSKAIA.js");
2457
2310
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
2458
2311
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
2459
- const { wireGatewayMcp } = await import("./mcp-wire-B57DUNOD.js");
2460
- const { MCP_HTTP_PORT } = await import("./server-RHON6QMN.js");
2312
+ const { wireGatewayMcp } = await import("./mcp-wire-FIO5DFBY.js");
2313
+ const { MCP_HTTP_PORT } = await import("./server-OXWHBTXK.js");
2461
2314
  const ac = new AbortController();
2462
2315
  process20.on("SIGINT", () => {
2463
2316
  ac.abort();
@@ -2557,8 +2410,8 @@ import { defineCommand as defineCommand19 } from "citty";
2557
2410
  import process21 from "process";
2558
2411
  import os from "os";
2559
2412
  import { randomBytes } from "crypto";
2560
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
2561
- import { execSync, spawnSync as spawnSync2, spawn as spawn2 } from "child_process";
2413
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync, mkdirSync } from "fs";
2414
+ import { execSync, spawnSync, spawn as spawn2 } from "child_process";
2562
2415
  import path2 from "path";
2563
2416
  var setup_default = defineCommand19({
2564
2417
  meta: {
@@ -2617,7 +2470,7 @@ var setup_default = defineCommand19({
2617
2470
  } else {
2618
2471
  provider = "local";
2619
2472
  info("We'll connect to your server over SSH to install and configure OpenClaw.\n");
2620
- if (!existsSync2(localKeyPath)) {
2473
+ if (!existsSync(localKeyPath)) {
2621
2474
  info(`No SSH key found at ${localKeyPath}.`);
2622
2475
  const { genKey } = await inquirer.prompt([{
2623
2476
  type: "confirm",
@@ -2653,7 +2506,7 @@ var setup_default = defineCommand19({
2653
2506
  name: "keyPath",
2654
2507
  message: `SSH private key file: (the key file on your computer used to log in \u2014 e.g. ~/.ssh/id_ed25519)`,
2655
2508
  default: localKeyPath,
2656
- validate: (v) => existsSync2(v.trim()) || `File not found: ${v.trim()}`
2509
+ validate: (v) => existsSync(v.trim()) || `File not found: ${v.trim()}`
2657
2510
  }
2658
2511
  ]);
2659
2512
  localHost = localAnswers.host;
@@ -2875,10 +2728,10 @@ var setup_default = defineCommand19({
2875
2728
  }
2876
2729
  const gatewayToken = randomBytes(24).toString("hex");
2877
2730
  const secretsDir2 = path2.join(os.homedir(), ".clawops", "secrets");
2878
- mkdirSync2(secretsDir2, { recursive: true });
2879
- spawnSync2("chmod", ["700", secretsDir2], { stdio: "ignore" });
2731
+ mkdirSync(secretsDir2, { recursive: true });
2732
+ spawnSync("chmod", ["700", secretsDir2], { stdio: "ignore" });
2880
2733
  const tokenPath = path2.join(secretsDir2, `GATEWAY_TOKEN_${stackAnswers.stackName}`);
2881
- writeFileSync3(tokenPath, gatewayToken, { encoding: "utf-8", mode: 384 });
2734
+ writeFileSync2(tokenPath, gatewayToken, { encoding: "utf-8", mode: 384 });
2882
2735
  const openclawConfigOverlay = {
2883
2736
  models: builtModelConfig,
2884
2737
  gateway: { auth: { mode: "token", token: gatewayToken } }
@@ -2889,7 +2742,7 @@ var setup_default = defineCommand19({
2889
2742
  let outputPath;
2890
2743
  if (provider === "local") {
2891
2744
  outputPath = path2.join(outDir, `openclaw-${stackAnswers.stackName}.json`);
2892
- writeFileSync3(outputPath, JSON.stringify(openclawConfigOverlay, null, 2), "utf-8");
2745
+ writeFileSync2(outputPath, JSON.stringify(openclawConfigOverlay, null, 2), "utf-8");
2893
2746
  process21.stdout.write("\n");
2894
2747
  success(`Config file saved to ${outputPath}`);
2895
2748
  } else {
@@ -2935,7 +2788,7 @@ var setup_default = defineCommand19({
2935
2788
  }
2936
2789
  };
2937
2790
  outputPath = path2.join(outDir, `clawops-${stackAnswers.stackName}-plan.json`);
2938
- writeFileSync3(outputPath, JSON.stringify(plan, null, 2), "utf-8");
2791
+ writeFileSync2(outputPath, JSON.stringify(plan, null, 2), "utf-8");
2939
2792
  process21.stdout.write("\n");
2940
2793
  success(`Deployment plan saved to ${outputPath}`);
2941
2794
  }
@@ -3040,7 +2893,7 @@ var setup_default = defineCommand19({
3040
2893
  inquirer
3041
2894
  });
3042
2895
  } else {
3043
- const { getConfigDir: getConfigDir2 } = await import("./store-OVB3DAJR.js");
2896
+ const { getConfigDir: getConfigDir2 } = await import("./store-YOLQYXMB.js");
3044
2897
  const knownHostsPath = path2.join(getConfigDir2(), "known_hosts");
3045
2898
  process21.stdout.write("\n");
3046
2899
  info("To deploy later, run these two commands:");
@@ -3057,7 +2910,7 @@ var setup_default = defineCommand19({
3057
2910
  default: false
3058
2911
  }]);
3059
2912
  if (applyNow) {
3060
- const { applyPlan } = await import("./apply-HJ5GAKHW.js");
2913
+ const { applyPlan } = await import("./apply-JARPVA5Y.js");
3061
2914
  const plan = JSON.parse(readFileSync3(outputPath, "utf-8"));
3062
2915
  try {
3063
2916
  await applyPlan(plan, {
@@ -3085,13 +2938,13 @@ To deploy later: clawops apply ${outputPath}`);
3085
2938
  }
3086
2939
  });
3087
2940
  async function runLocalDeploy(opts) {
3088
- const { setConfig: setConfig2, getConfig: getConfig2, getConfigDir: getConfigDir2 } = await import("./store-OVB3DAJR.js");
3089
- const { localBootstrap } = await import("./bootstrap-NN647RCY.js");
2941
+ const { setConfig: setConfig2, getConfig, getConfigDir: getConfigDir2 } = await import("./store-YOLQYXMB.js");
2942
+ const { localBootstrap } = await import("./bootstrap-3PBVY7MA.js");
3090
2943
  const { connect } = await import("./ssh-VAI5DU5M.js");
3091
2944
  const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-3HZLUWEA.js");
3092
2945
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
3093
2946
  const knownHostsPath = path2.join(getConfigDir2(), "known_hosts");
3094
- const existing = getConfig2();
2947
+ const existing = getConfig();
3095
2948
  const stackEntry = {
3096
2949
  provider: "local",
3097
2950
  stateUrl: "file://~/.clawops/state",
@@ -3229,7 +3082,7 @@ ${cfg.loginHint}`);
3229
3082
  }]);
3230
3083
  if (runNow) {
3231
3084
  process21.stdout.write("\n");
3232
- const result = spawnSync2(cfg.loginCmd[0], cfg.loginCmd.slice(1), { stdio: "inherit" });
3085
+ const result = spawnSync(cfg.loginCmd[0], cfg.loginCmd.slice(1), { stdio: "inherit" });
3233
3086
  if (result.error) {
3234
3087
  failure(`Could not launch ${cliName} \u2014 is it installed? (${result.error.message})`);
3235
3088
  info(`Install guide: ${cliInstallUrl(provider)}`);
@@ -3273,10 +3126,10 @@ async function promptSecret(name, label, envDefault, inquirer) {
3273
3126
  message: `Paste your ${label}: (input is hidden)`,
3274
3127
  validate: (v) => v.trim() !== "" || "Value cannot be empty"
3275
3128
  }]);
3276
- mkdirSync2(secretsDir2, { recursive: true });
3277
- spawnSync2("chmod", ["700", secretsDir2], { stdio: "ignore" });
3129
+ mkdirSync(secretsDir2, { recursive: true });
3130
+ spawnSync("chmod", ["700", secretsDir2], { stdio: "ignore" });
3278
3131
  const secretPath2 = path2.join(secretsDir2, name);
3279
- writeFileSync3(secretPath2, secretValue.trim(), { encoding: "utf-8", mode: 384 });
3132
+ writeFileSync2(secretPath2, secretValue.trim(), { encoding: "utf-8", mode: 384 });
3280
3133
  success(`Secret saved to ${secretPath2} (chmod 600)`);
3281
3134
  return { name, source: "file", ref: secretPath2 };
3282
3135
  }
@@ -3293,7 +3146,7 @@ async function promptSecret(name, label, envDefault, inquirer) {
3293
3146
  type: "input",
3294
3147
  name: "filePath",
3295
3148
  message: `File path: (full path to the file containing your ${label})`,
3296
- validate: (v) => existsSync2(v.trim()) || `File not found: ${v.trim()}`
3149
+ validate: (v) => existsSync(v.trim()) || `File not found: ${v.trim()}`
3297
3150
  }]);
3298
3151
  return { name, source: "file", ref: filePath };
3299
3152
  }
@@ -3451,7 +3304,7 @@ async function startDockerAndWait(inquirer) {
3451
3304
  await pollUntilDockerReady("Waiting for Docker daemon...");
3452
3305
  } else if (choice === "systemctl") {
3453
3306
  const spin = spinner("Running: sudo systemctl start docker...");
3454
- const res = spawnSync2("sudo", ["systemctl", "start", "docker"], { stdio: "pipe" });
3307
+ const res = spawnSync("sudo", ["systemctl", "start", "docker"], { stdio: "pipe" });
3455
3308
  if (res.status !== 0) {
3456
3309
  spin.fail("systemctl start docker failed.");
3457
3310
  throw new Error("systemctl start docker failed");
@@ -3459,18 +3312,18 @@ async function startDockerAndWait(inquirer) {
3459
3312
  spin.succeed("Docker service started.");
3460
3313
  await pollUntilDockerReady("Waiting for Docker daemon to be reachable...");
3461
3314
  } else if (choice === "desktop") {
3462
- const backendRunning = spawnSync2("pgrep", ["-f", "com.docker.backend"], { stdio: "ignore" }).status === 0;
3315
+ const backendRunning = spawnSync("pgrep", ["-f", "com.docker.backend"], { stdio: "ignore" }).status === 0;
3463
3316
  if (backendRunning) {
3464
3317
  const killSpin = spinner("Docker Desktop is stuck \u2014 force-restarting...");
3465
3318
  for (const pat of ["com.docker.backend", "com.docker.virtualization", "com.docker.build", "Docker Desktop"]) {
3466
- spawnSync2("pkill", ["-9", "-f", pat], { stdio: "ignore" });
3319
+ spawnSync("pkill", ["-9", "-f", pat], { stdio: "ignore" });
3467
3320
  }
3468
3321
  await new Promise((r) => setTimeout(r, 2e3));
3469
3322
  killSpin.succeed("Old Docker processes cleared.");
3470
3323
  }
3471
3324
  const openSpin = spinner("Launching Docker Desktop...");
3472
- let opened = spawnSync2("open", ["-a", "Docker"], { stdio: "ignore" });
3473
- if (opened.status !== 0) opened = spawnSync2("open", ["/Applications/Docker.app"], { stdio: "ignore" });
3325
+ let opened = spawnSync("open", ["-a", "Docker"], { stdio: "ignore" });
3326
+ if (opened.status !== 0) opened = spawnSync("open", ["/Applications/Docker.app"], { stdio: "ignore" });
3474
3327
  if (opened.status !== 0) {
3475
3328
  openSpin.fail("Could not open Docker Desktop \u2014 is it installed in /Applications?");
3476
3329
  throw new Error("Failed to open Docker Desktop");
@@ -3479,7 +3332,7 @@ async function startDockerAndWait(inquirer) {
3479
3332
  await pollUntilDockerReady("Waiting for Docker engine to start...");
3480
3333
  } else if (choice === "colima") {
3481
3334
  const spin = spinner("Running: colima start...");
3482
- const res = spawnSync2("colima", ["start"], { stdio: "pipe" });
3335
+ const res = spawnSync("colima", ["start"], { stdio: "pipe" });
3483
3336
  if (res.status !== 0) {
3484
3337
  spin.fail("colima start failed \u2014 is Colima installed? (brew install colima docker)");
3485
3338
  throw new Error("colima start failed");
@@ -3491,12 +3344,12 @@ async function startDockerAndWait(inquirer) {
3491
3344
  var LOCALHOST_ALIASES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
3492
3345
  async function ensureAuthorizedKey(keyPath, host, inquirer) {
3493
3346
  const pubKeyPath = `${keyPath}.pub`;
3494
- if (!existsSync2(pubKeyPath)) return;
3347
+ if (!existsSync(pubKeyPath)) return;
3495
3348
  const pubKey = readFileSync3(pubKeyPath, "utf-8").trim();
3496
3349
  const isLocal = LOCALHOST_ALIASES.has(host.toLowerCase());
3497
3350
  const authorizedKeysPath = path2.join(os.homedir(), ".ssh", "authorized_keys");
3498
3351
  if (isLocal) {
3499
- const existing = existsSync2(authorizedKeysPath) ? readFileSync3(authorizedKeysPath, "utf-8") : "";
3352
+ const existing = existsSync(authorizedKeysPath) ? readFileSync3(authorizedKeysPath, "utf-8") : "";
3500
3353
  if (existing.includes(pubKey)) {
3501
3354
  success("SSH public key is already in authorized_keys.");
3502
3355
  return;
@@ -3509,10 +3362,10 @@ async function ensureAuthorizedKey(keyPath, host, inquirer) {
3509
3362
  default: true
3510
3363
  }]);
3511
3364
  if (addKey) {
3512
- mkdirSync2(path2.join(os.homedir(), ".ssh"), { recursive: true });
3365
+ mkdirSync(path2.join(os.homedir(), ".ssh"), { recursive: true });
3513
3366
  const entry = existing.endsWith("\n") || existing === "" ? pubKey + "\n" : "\n" + pubKey + "\n";
3514
- writeFileSync3(authorizedKeysPath, existing + entry, { encoding: "utf-8", flag: "a" });
3515
- spawnSync2("chmod", ["600", authorizedKeysPath], { stdio: "ignore" });
3367
+ writeFileSync2(authorizedKeysPath, existing + entry, { encoding: "utf-8", flag: "a" });
3368
+ spawnSync("chmod", ["600", authorizedKeysPath], { stdio: "ignore" });
3516
3369
  success("Public key added to ~/.ssh/authorized_keys.");
3517
3370
  } else {
3518
3371
  info("SSH will likely fail. Add this line to ~/.ssh/authorized_keys manually:");
@@ -3527,8 +3380,8 @@ async function ensureAuthorizedKey(keyPath, host, inquirer) {
3527
3380
  }
3528
3381
  async function generateSshKey() {
3529
3382
  const keyPath = path2.join(os.homedir(), ".ssh", "id_ed25519");
3530
- mkdirSync2(path2.join(os.homedir(), ".ssh"), { recursive: true });
3531
- const result = spawnSync2("ssh-keygen", ["-t", "ed25519", "-f", keyPath, "-N", "", "-C", "clawops"], {
3383
+ mkdirSync(path2.join(os.homedir(), ".ssh"), { recursive: true });
3384
+ const result = spawnSync("ssh-keygen", ["-t", "ed25519", "-f", keyPath, "-N", "", "-C", "clawops"], {
3532
3385
  stdio: ["ignore", "pipe", "pipe"]
3533
3386
  });
3534
3387
  if (result.status !== 0) {
@@ -3543,7 +3396,7 @@ function detectSshKey() {
3543
3396
  const candidates = ["id_ed25519", "id_ecdsa", "id_rsa", "id_dsa"];
3544
3397
  for (const name of candidates) {
3545
3398
  const p = path2.join(os.homedir(), ".ssh", name);
3546
- if (existsSync2(p)) return p;
3399
+ if (existsSync(p)) return p;
3547
3400
  }
3548
3401
  return path2.join(os.homedir(), ".ssh", "id_ed25519");
3549
3402
  }
@@ -3560,8 +3413,8 @@ async function maybeWireGatewayMcp(opts) {
3560
3413
  const { wireGateway } = await inquirerPromptWire(opts.inquirer);
3561
3414
  if (!wireGateway) return;
3562
3415
  const { connect } = await import("./ssh-VAI5DU5M.js");
3563
- const { getConfigDir: getConfigDir2 } = await import("./store-OVB3DAJR.js");
3564
- const { wireGatewayMcp } = await import("./mcp-wire-B57DUNOD.js");
3416
+ const { getConfigDir: getConfigDir2 } = await import("./store-YOLQYXMB.js");
3417
+ const { wireGatewayMcp } = await import("./mcp-wire-FIO5DFBY.js");
3565
3418
  const knownHostsPath = path2.join(getConfigDir2(), "known_hosts");
3566
3419
  const spin = spinner("Wiring gateway MCP client...");
3567
3420
  const session = await connect({
@@ -3680,9 +3533,9 @@ function instanceChoices(provider) {
3680
3533
  return table[provider] ?? [];
3681
3534
  }
3682
3535
  async function maybeHarden(opts) {
3683
- const { MODULE_CATALOG, resolveModules, runHardening, formatHardenSummary } = await import("./harden-3KKCR7BL.js");
3684
- const { getConfig: getConfig2 } = await import("./store-OVB3DAJR.js");
3685
- const config = getConfig2();
3536
+ const { MODULE_CATALOG, resolveModules, runHardening, formatHardenSummary } = await import("./harden-RUOUA5BV.js");
3537
+ const { getConfig } = await import("./store-YOLQYXMB.js");
3538
+ const config = getConfig();
3686
3539
  if (!config) return;
3687
3540
  const availableModules = resolveModules(MODULE_CATALOG, void 0, opts.provider);
3688
3541
  if (availableModules.length === 0) return;
@@ -3704,7 +3557,7 @@ async function maybeHarden(opts) {
3704
3557
  const modules = availableModules.filter((m) => selectedIds.includes(m.id));
3705
3558
  process21.stdout.write("\nApplying hardening modules...\n\n");
3706
3559
  try {
3707
- const { buildContext } = await import("./context-7VI3R6EK.js");
3560
+ const { buildContext } = await import("./context-WOKSKAIA.js");
3708
3561
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
3709
3562
  const ctx = buildContext({ stack: opts.stackName });
3710
3563
  const stackObj = await ctx.getStack();
@@ -3827,8 +3680,8 @@ async function runAccountPreflight(opts) {
3827
3680
 
3828
3681
  // src/cli/commands/secret.ts
3829
3682
  import { defineCommand as defineCommand20 } from "citty";
3830
- import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync4, unlinkSync, mkdirSync as mkdirSync3, statSync } from "fs";
3831
- import { spawnSync as spawnSync3 } from "child_process";
3683
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync3, unlinkSync, mkdirSync as mkdirSync2, statSync } from "fs";
3684
+ import { spawnSync as spawnSync2 } from "child_process";
3832
3685
  import path3 from "path";
3833
3686
  import os2 from "os";
3834
3687
  import process22 from "process";
@@ -3840,7 +3693,7 @@ function secretPath(name) {
3840
3693
  return path3.join(secretsDir(), name);
3841
3694
  }
3842
3695
  function listSecretNames() {
3843
- if (!existsSync3(secretsDir())) return [];
3696
+ if (!existsSync2(secretsDir())) return [];
3844
3697
  return readdirSync(secretsDir()).filter((f) => !f.startsWith("."));
3845
3698
  }
3846
3699
  var listCmd = defineCommand20({
@@ -3904,9 +3757,9 @@ var setCmd = defineCommand20({
3904
3757
  }]);
3905
3758
  value = secretValue;
3906
3759
  }
3907
- mkdirSync3(secretsDir(), { recursive: true });
3908
- spawnSync3("chmod", ["700", secretsDir()], { stdio: "ignore" });
3909
- writeFileSync4(secretPath(name), value.trim(), { encoding: "utf-8", mode: 384 });
3760
+ mkdirSync2(secretsDir(), { recursive: true });
3761
+ spawnSync2("chmod", ["700", secretsDir()], { stdio: "ignore" });
3762
+ writeFileSync3(secretPath(name), value.trim(), { encoding: "utf-8", mode: 384 });
3910
3763
  success(`Secret "${name}" saved to ${secretPath(name)} (chmod 600)`);
3911
3764
  info("Run `clawops secret rotate <name>` to propagate it to a running stack.");
3912
3765
  }
@@ -3923,7 +3776,7 @@ var deleteCmd = defineCommand20({
3923
3776
  process22.exit(2);
3924
3777
  }
3925
3778
  const p = secretPath(name);
3926
- if (!existsSync3(p)) {
3779
+ if (!existsSync2(p)) {
3927
3780
  failure(`Secret "${name}" not found at ${p}`);
3928
3781
  process22.exit(1);
3929
3782
  }
@@ -3975,12 +3828,12 @@ var rotateCmd = defineCommand20({
3975
3828
  }]);
3976
3829
  value = secretValue;
3977
3830
  }
3978
- mkdirSync3(secretsDir(), { recursive: true });
3979
- spawnSync3("chmod", ["700", secretsDir()], { stdio: "ignore" });
3980
- writeFileSync4(secretPath(name), value.trim(), { encoding: "utf-8", mode: 384 });
3831
+ mkdirSync2(secretsDir(), { recursive: true });
3832
+ spawnSync2("chmod", ["700", secretsDir()], { stdio: "ignore" });
3833
+ writeFileSync3(secretPath(name), value.trim(), { encoding: "utf-8", mode: 384 });
3981
3834
  success(`Secret "${name}" updated.`);
3982
- const { getConfig: getConfig2 } = await import("./store-OVB3DAJR.js");
3983
- const cfg = getConfig2();
3835
+ const { getConfig } = await import("./store-YOLQYXMB.js");
3836
+ const cfg = getConfig();
3984
3837
  const targetStack = args.stack ?? cfg?.defaults?.stack;
3985
3838
  if (!targetStack) {
3986
3839
  warn("No stack specified and no default stack in config \u2014 skipping re-apply.");
@@ -3996,11 +3849,11 @@ var rotateCmd = defineCommand20({
3996
3849
  }
3997
3850
  info(`Re-applying config overlay to stack "${targetStack}"\u2026`);
3998
3851
  try {
3999
- const { buildContext } = await import("./context-7VI3R6EK.js");
3852
+ const { buildContext } = await import("./context-WOKSKAIA.js");
4000
3853
  const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-3HZLUWEA.js");
4001
3854
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
4002
3855
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
4003
- const { localStateToConnectionInfo } = await import("./state-AOAYLYY5.js");
3856
+ const { localStateToConnectionInfo } = await import("./state-AKZP2S4T.js");
4004
3857
  const ctx = buildContext({ stack: targetStack });
4005
3858
  let conn;
4006
3859
  if (ctx.adapter.name === "local") {
@@ -4058,7 +3911,7 @@ var auditCmd = defineCommand20({
4058
3911
  for (const s of overlay.secrets) {
4059
3912
  if (s.source === "file") {
4060
3913
  const ref = s.ref ?? secretPath(s.name);
4061
- if (!existsSync3(ref)) {
3914
+ if (!existsSync2(ref)) {
4062
3915
  issues.push({ kind: "missing-file", stack: overlay.stackName, secret: s.name, detail: `File not found: ${ref}` });
4063
3916
  }
4064
3917
  } else if (s.source === "env") {
@@ -4183,7 +4036,7 @@ import { accessSync, constants } from "fs";
4183
4036
  import { execSync as execSync2 } from "child_process";
4184
4037
  var ISSUES_URL = `${REPO_URL}/issues/new`;
4185
4038
  var BODY_CAP = 2e3;
4186
- var VERSION = true ? "2.1.1" : "dev";
4039
+ var VERSION = true ? "2.1.3" : "dev";
4187
4040
  async function collectContext() {
4188
4041
  const nodeVersion = process23.version;
4189
4042
  const os3 = `${process23.platform} ${process23.arch}`;
@@ -4191,8 +4044,8 @@ async function collectContext() {
4191
4044
  let stackCount = 0;
4192
4045
  let sshKey = "unknown";
4193
4046
  try {
4194
- const { getConfig: getConfig2 } = await import("./store-OVB3DAJR.js");
4195
- const config = getConfig2();
4047
+ const { getConfig } = await import("./store-YOLQYXMB.js");
4048
+ const config = getConfig();
4196
4049
  if (config) {
4197
4050
  const stacks = Object.values(config.stacks);
4198
4051
  stackCount = stacks.length;
@@ -4302,9 +4155,9 @@ var harden_default = defineCommand23({
4302
4155
  "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" }
4303
4156
  },
4304
4157
  async run({ args }) {
4305
- const { MODULE_CATALOG, resolveModules, runHardening, formatHardenSummary } = await import("./harden-3KKCR7BL.js");
4306
- const { buildContext } = await import("./context-7VI3R6EK.js");
4307
- const { getConfig: getConfig2 } = await import("./store-OVB3DAJR.js");
4158
+ const { MODULE_CATALOG, resolveModules, runHardening, formatHardenSummary } = await import("./harden-RUOUA5BV.js");
4159
+ const { buildContext } = await import("./context-WOKSKAIA.js");
4160
+ const { getConfig } = await import("./store-YOLQYXMB.js");
4308
4161
  if (args.list) {
4309
4162
  process24.stdout.write("\nAvailable hardening modules:\n\n");
4310
4163
  for (const mod of MODULE_CATALOG) {
@@ -4318,7 +4171,7 @@ var harden_default = defineCommand23({
4318
4171
  process24.stdout.write("\n");
4319
4172
  return;
4320
4173
  }
4321
- const config = getConfig2();
4174
+ const config = getConfig();
4322
4175
  if (!config) {
4323
4176
  failure("No clawops config found. Run `clawops init` first.");
4324
4177
  process24.exit(1);
@@ -4326,7 +4179,7 @@ var harden_default = defineCommand23({
4326
4179
  const ctx = buildContext({ stack: args.stack });
4327
4180
  const provider = ctx.adapter.name;
4328
4181
  if (args["tailscale-revert"]) {
4329
- const { revertTailnet } = await import("./flows-RI7FGHAM.js");
4182
+ const { revertTailnet } = await import("./flows-HGJIA6EL.js");
4330
4183
  const override = config.stacks[ctx.stackName]?.tailscale;
4331
4184
  if (override && args.yes !== true) {
4332
4185
  const { createInterface: createInterface3 } = await import("readline/promises");
@@ -4349,7 +4202,7 @@ var harden_default = defineCommand23({
4349
4202
  else success(outcome.message);
4350
4203
  return;
4351
4204
  }
4352
- const { makeTailscaleModule } = await import("./harden-3KKCR7BL.js");
4205
+ const { makeTailscaleModule } = await import("./harden-RUOUA5BV.js");
4353
4206
  const forStack = makeTailscaleModule(ctx.stackName);
4354
4207
  const resolved = resolveModules(MODULE_CATALOG, args.options, provider).map(
4355
4208
  (m) => m.id === "tailscale" ? forStack : m
@@ -4433,7 +4286,7 @@ var harden_default = defineCommand23({
4433
4286
  success("Hardening complete.");
4434
4287
  }
4435
4288
  if (args.tailscale && !args["dry-run"]) {
4436
- const { cutOverToTailnet } = await import("./flows-RI7FGHAM.js");
4289
+ const { cutOverToTailnet } = await import("./flows-HGJIA6EL.js");
4437
4290
  process24.stdout.write("\nVerifying the tailnet address before using it...\n");
4438
4291
  const outcome = await cutOverToTailnet(ctx, conn, config);
4439
4292
  if (!outcome.ok) {
@@ -4470,7 +4323,7 @@ function resolveArgv(argv2, stdinIsTty) {
4470
4323
  }
4471
4324
 
4472
4325
  // src/cli/index.ts
4473
- var CLI_VERSION = true ? "2.1.1" : "dev";
4326
+ var CLI_VERSION = true ? "2.1.3" : "dev";
4474
4327
  var main = defineCommand24({
4475
4328
  meta: {
4476
4329
  name: "clawops",