@clawops/cli 2.1.2 → 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 +2 -0
  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-IQQTB7ER.js → chunk-PTCVFLZ3.js} +4 -4
  13. package/dist/{chunk-ELU3XQEA.js → chunk-RDUKRIRC.js} +1 -1
  14. package/dist/{chunk-T5XCMYAV.js → chunk-TYHTISI5.js} +187 -137
  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-Q2BGVMH7.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-FQOMM7MK.js → mcp-wire-FIO5DFBY.js} +11 -11
  22. package/dist/{package-JFVGCNKU.js → package-MF5LPITL.js} +1 -1
  23. package/dist/{server-B7I6HBQH.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/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@clawops/cli)](https://www.npmjs.com/package/@clawops/cli)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@clawops/cli)](https://www.npmjs.com/package/@clawops/cli)
5
+ [![clawops MCP server – quality and maintenance score on Glama](https://glama.ai/mcp/servers/dfridkin/clawops/badges/score.svg)](https://glama.ai/mcp/servers/dfridkin/clawops)
5
6
 
6
7
  MCP-native infrastructure ops for OpenClaw, with read-only mode, destructive-action confirmation, and audit logs built in.
7
8
 
@@ -362,6 +363,7 @@ Do not bind to a non-loopback address without additional authentication controls
362
363
  | `clawops_config_validate` | cli | Validate the deployed config against the OpenClaw schema |
363
364
  | `clawops_gateway_restart` | cli | Restart the gateway (elicits confirmation) |
364
365
  | `clawops_harden` | cli | Apply hardening modules; join or leave a tailnet (elicits confirmation) |
366
+ | `clawops_init` | cli | Register a stack and write `~/.clawops/config.json` (no cloud resources) |
365
367
  | `clawops_workflow_deploy_app` | workflow | End-to-end deploy: plan → confirm → apply → status |
366
368
  | `clawops_workflow_recover` | workflow | Diagnostic workflow for an unhealthy stack |
367
369
  | `clawops_task_status` | cli | Poll a long-running task |
@@ -1,27 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  applyPlan
4
- } from "./chunk-R3DTA35B.js";
4
+ } from "./chunk-7T4CIT7C.js";
5
5
  import "./chunk-BOPSG2LI.js";
6
6
  import "./chunk-6ZFIFDBJ.js";
7
7
  import "./chunk-2I7KCMXZ.js";
8
- import "./chunk-3Z5TDXCJ.js";
9
- import "./chunk-AEEMRFZV.js";
10
8
  import "./chunk-XFN3YDZE.js";
11
- import "./chunk-QDNFADJI.js";
9
+ import "./chunk-55UMO37O.js";
10
+ import "./chunk-AEEMRFZV.js";
11
+ import "./chunk-AVERNLUY.js";
12
12
  import "./chunk-NUDIHZEH.js";
13
+ import "./chunk-CHNSL3TC.js";
13
14
  import "./chunk-JW5A7E3X.js";
14
- import "./chunk-BELTQGHT.js";
15
+ import "./chunk-VUFMZEIM.js";
15
16
  import "./chunk-GIEVAGEK.js";
16
17
  import "./chunk-VOEJYRIK.js";
17
18
  import "./chunk-EI7CQQ7D.js";
18
19
  import "./chunk-FEK7VJAY.js";
19
20
  import "./chunk-RHOWYIWT.js";
20
21
  import "./chunk-N4WZLWJ4.js";
21
- import "./chunk-ELU3XQEA.js";
22
- import "./chunk-64PONSA5.js";
22
+ import "./chunk-RDUKRIRC.js";
23
+ import "./chunk-GFIR2IIJ.js";
23
24
  import "./chunk-KGXPLI7W.js";
24
- import "./chunk-VUFMZEIM.js";
25
25
  export {
26
26
  applyPlan
27
27
  };
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-V25QRZRB.js";
8
8
  import {
9
9
  getConfigDir
10
- } from "./chunk-64PONSA5.js";
10
+ } from "./chunk-GFIR2IIJ.js";
11
11
  import "./chunk-KGXPLI7W.js";
12
12
 
13
13
  // src/pulumi/automation.ts
@@ -14,8 +14,8 @@ import {
14
14
  import "./chunk-EI7CQQ7D.js";
15
15
  import {
16
16
  writeLocalState
17
- } from "./chunk-ELU3XQEA.js";
18
- import "./chunk-64PONSA5.js";
17
+ } from "./chunk-RDUKRIRC.js";
18
+ import "./chunk-GFIR2IIJ.js";
19
19
  import {
20
20
  ProviderError
21
21
  } from "./chunk-KGXPLI7W.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getConfigDir
4
- } from "./chunk-64PONSA5.js";
4
+ } from "./chunk-GFIR2IIJ.js";
5
5
 
6
6
  // src/config/secrets.ts
7
7
  import { readFileSync, existsSync } from "fs";
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-VOEJYRIK.js";
8
8
  import {
9
9
  getConfig
10
- } from "./chunk-64PONSA5.js";
10
+ } from "./chunk-GFIR2IIJ.js";
11
11
  import {
12
12
  UsageError
13
13
  } from "./chunk-KGXPLI7W.js";
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getConfig,
4
+ getConfigDir,
5
+ setConfig
6
+ } from "./chunk-GFIR2IIJ.js";
7
+
8
+ // src/config/init.ts
9
+ import { spawnSync } from "child_process";
10
+ import { writeFileSync, mkdirSync, existsSync } from "fs";
11
+ import path from "path";
12
+
13
+ // src/providers/state-bucket.ts
14
+ function deriveStateBucket(provider, scope) {
15
+ if (provider === "azure") {
16
+ return { ok: true, name: "clawops-state" };
17
+ }
18
+ if (!scope.account) {
19
+ return {
20
+ ok: false,
21
+ 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"
22
+ };
23
+ }
24
+ if (provider === "gcp") return { ok: true, name: `clawops-state-${scope.account}` };
25
+ if (!scope.region) return { ok: false, needs: "a region" };
26
+ return { ok: true, name: `clawops-state-${scope.account}-${scope.region}` };
27
+ }
28
+ function stateUrlFor(provider, bucket) {
29
+ const verdict = validateStateBucket(provider, bucket);
30
+ if (verdict !== true) throw new Error(`Not a usable ${provider} state backend name: ${verdict}`);
31
+ const scheme = provider === "aws" ? "s3://" : provider === "gcp" ? "gs://" : "azblob://";
32
+ return provider === "azure" ? `${scheme}${bucket}` : `${scheme}${bucket}/clawops`;
33
+ }
34
+ var IPV4 = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
35
+ function validateStateBucket(provider, name) {
36
+ const n = name.trim();
37
+ if (n === "") return "Required";
38
+ if (n !== name) return "No leading or trailing spaces";
39
+ if (n.length < 3) return `Too short \u2014 ${labelFor(provider)} names are at least 3 characters`;
40
+ const dotted = provider === "gcp" && n.includes(".");
41
+ const max = dotted ? 222 : 63;
42
+ if (n.length > max) return `Too long \u2014 ${labelFor(provider)} names are at most ${max} characters`;
43
+ if (dotted && n.split(".").some((part) => part.length > 63)) {
44
+ return "Each dot-separated part of a Cloud Storage name is at most 63 characters";
45
+ }
46
+ if (n !== n.toLowerCase()) return "Lowercase only";
47
+ if (provider === "azure") {
48
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(n)) {
49
+ return "Letters, digits and single hyphens only, starting and ending with a letter or digit";
50
+ }
51
+ return true;
52
+ }
53
+ if (!/^[a-z0-9][a-z0-9._-]*[a-z0-9]$/.test(n)) {
54
+ return "Letters, digits, dots, hyphens and underscores only, starting and ending with a letter or digit";
55
+ }
56
+ if (n.includes("..")) return "No consecutive dots";
57
+ if (IPV4.test(n)) return "Cannot be formatted as an IP address";
58
+ if (provider === "aws") {
59
+ if (n.startsWith("xn--")) return 'Cannot start with "xn--"';
60
+ if (n.startsWith("sthree-")) return 'Cannot start with "sthree-"';
61
+ if (n.endsWith("-s3alias")) return 'Cannot end with "-s3alias"';
62
+ if (n.endsWith("--ol-s3")) return 'Cannot end with "--ol-s3"';
63
+ if (n.includes("_")) return "Underscores are not allowed in S3 bucket names";
64
+ return true;
65
+ }
66
+ if (n.startsWith("goog")) return 'Cannot start with "goog"';
67
+ if (n.includes("google")) return 'Cannot contain "google"';
68
+ return true;
69
+ }
70
+ function labelFor(provider) {
71
+ if (provider === "aws") return "S3 bucket";
72
+ if (provider === "gcp") return "Cloud Storage bucket";
73
+ return "blob container";
74
+ }
75
+ async function resolveScopeAccount(provider, signal) {
76
+ if (provider === "azure") return void 0;
77
+ try {
78
+ if (provider === "aws") {
79
+ const { callerAccount } = await import("./preflight-TFD4N5ZU.js");
80
+ return await callerAccount(signal);
81
+ }
82
+ const { resolveProjectId } = await import("./preflight-IE2YWBAC.js");
83
+ return resolveProjectId();
84
+ } catch {
85
+ return void 0;
86
+ }
87
+ }
88
+
89
+ // src/config/init.ts
90
+ var SUPPORTED_PROVIDERS = ["gcp", "aws", "azure", "local"];
91
+ var PROVIDER_DEFAULTS = {
92
+ gcp: { region: "us-central1", credEnv: "GOOGLE_APPLICATION_CREDENTIALS", stateScheme: "gs://" },
93
+ aws: { region: "us-east-1", credEnv: "AWS_PROFILE", stateScheme: "s3://" },
94
+ azure: { region: "eastus", credEnv: "AZURE_CLIENT_ID", stateScheme: "azblob://" }
95
+ };
96
+ async function initStack(opts) {
97
+ const provider = opts.provider;
98
+ if (!SUPPORTED_PROVIDERS.includes(provider)) {
99
+ return {
100
+ ok: false,
101
+ reason: `Unsupported provider: ${provider}. Supported: ${SUPPORTED_PROVIDERS.join(", ")}`
102
+ };
103
+ }
104
+ const stackName = opts.stackName ?? "default";
105
+ const existing = getConfig();
106
+ if (existing?.stacks[stackName] && !opts.force) {
107
+ return {
108
+ ok: false,
109
+ reason: `Stack "${stackName}" already exists in ${path.join(getConfigDir(), "config.json")} (${existing.stacks[stackName].stateUrl}). Pass force to overwrite its settings, or use a different stack name to add another one.`
110
+ };
111
+ }
112
+ const configDir = getConfigDir();
113
+ mkdirSync(configDir, { recursive: true });
114
+ const keyPath = opts.keyPath ?? path.join(configDir, "id_ed25519");
115
+ const knownHostsPath = path.join(configDir, "known_hosts");
116
+ let keyGenerated = false;
117
+ if (!existsSync(keyPath)) {
118
+ if (opts.keyPath) return { ok: false, reason: `SSH key not found at ${keyPath}` };
119
+ const gen = spawnSync(
120
+ "ssh-keygen",
121
+ ["-t", "ed25519", "-f", keyPath, "-N", "", "-C", "clawops", "-q"],
122
+ { stdio: ["ignore", "pipe", "pipe"] }
123
+ );
124
+ if (gen.error || gen.status !== 0) {
125
+ const reason = gen.error?.message ?? gen.stderr?.toString().trim() ?? `exit ${gen.status}`;
126
+ return {
127
+ ok: false,
128
+ reason: `Could not generate an SSH key: ${reason}
129
+ Generate one yourself and point clawops at it:
130
+ ssh-keygen -t ed25519 -f ${keyPath} -N '' -C clawops
131
+ clawops init --key-path ${keyPath}`
132
+ };
133
+ }
134
+ keyGenerated = true;
135
+ }
136
+ if (!existsSync(knownHostsPath)) writeFileSync(knownHostsPath, "", "utf-8");
137
+ if (provider === "local") {
138
+ if (!opts.host) return { ok: false, reason: "host is required for the local provider" };
139
+ const config = merge(existing, stackName, provider, keyPath, knownHostsPath, {
140
+ provider,
141
+ stateUrl: "file://~/.clawops/state",
142
+ credentialsRef: { source: "file", envVars: [] },
143
+ localOpts: {
144
+ host: opts.host,
145
+ sshUser: opts.sshUser ?? "root",
146
+ sshPort: opts.sshPort ?? 22,
147
+ sshKeyPath: keyPath
148
+ }
149
+ });
150
+ setConfig(config);
151
+ return {
152
+ ok: true,
153
+ configPath: path.join(configDir, "config.json"),
154
+ stackName,
155
+ provider,
156
+ stateUrl: "file://~/.clawops/state",
157
+ keyPath,
158
+ keyGenerated
159
+ };
160
+ }
161
+ const defaults = PROVIDER_DEFAULTS[provider];
162
+ const region = opts.region ?? defaults.region;
163
+ let stateUrl;
164
+ if (opts.stateUrl) {
165
+ stateUrl = opts.stateUrl;
166
+ } else {
167
+ const account = await resolveScopeAccount(provider);
168
+ const derived = deriveStateBucket(provider, { account, region });
169
+ if (!derived.ok) {
170
+ return {
171
+ ok: false,
172
+ reason: `Could not name a state backend for ${provider}: clawops needs ${derived.needs}. Authenticate first, or name the backend yourself, e.g. ${defaults.stateScheme}your-bucket/clawops`
173
+ };
174
+ }
175
+ stateUrl = stateUrlFor(provider, derived.name);
176
+ }
177
+ setConfig(
178
+ merge(existing, stackName, provider, keyPath, knownHostsPath, {
179
+ provider,
180
+ stateUrl,
181
+ region,
182
+ credentialsRef: { source: "env", envVars: [defaults.credEnv] }
183
+ })
184
+ );
185
+ return {
186
+ ok: true,
187
+ configPath: path.join(configDir, "config.json"),
188
+ stackName,
189
+ provider,
190
+ stateUrl,
191
+ region,
192
+ keyPath,
193
+ keyGenerated
194
+ };
195
+ }
196
+ function merge(existing, stackName, provider, keyPath, knownHostsPath, stack) {
197
+ return {
198
+ ...existing ?? {},
199
+ version: 1,
200
+ defaults: { stack: stackName, provider },
201
+ stacks: { ...existing?.stacks ?? {}, [stackName]: stack },
202
+ ssh: { keyPath, knownHostsPath }
203
+ };
204
+ }
205
+
206
+ export {
207
+ deriveStateBucket,
208
+ validateStateBucket,
209
+ resolveScopeAccount,
210
+ SUPPORTED_PROVIDERS,
211
+ PROVIDER_DEFAULTS,
212
+ initStack
213
+ };
@@ -11,22 +11,22 @@ import {
11
11
  readRemoteConfig,
12
12
  restartGateway
13
13
  } from "./chunk-2I7KCMXZ.js";
14
- import {
15
- writeStackConfig
16
- } from "./chunk-3Z5TDXCJ.js";
17
14
  import {
18
15
  validatePlan
19
16
  } from "./chunk-XFN3YDZE.js";
17
+ import {
18
+ writeStackConfig
19
+ } from "./chunk-55UMO37O.js";
20
20
  import {
21
21
  buildContext
22
- } from "./chunk-QDNFADJI.js";
22
+ } from "./chunk-AVERNLUY.js";
23
23
  import {
24
24
  GATEWAY_PORT
25
25
  } from "./chunk-VOEJYRIK.js";
26
26
  import {
27
27
  getConfig,
28
28
  setConfig
29
- } from "./chunk-64PONSA5.js";
29
+ } from "./chunk-GFIR2IIJ.js";
30
30
  import {
31
31
  UsageError
32
32
  } from "./chunk-KGXPLI7W.js";
@@ -54,7 +54,7 @@ ${validation.errors.join("\n")}`
54
54
  });
55
55
  const stack = await ctx.getStack();
56
56
  const { guardPrivateOnlyApply } = await import("./private-only-DIA26I2E.js");
57
- const { probeSsh } = await import("./tailscale-cutover-6YP2QKFM.js");
57
+ const { probeSsh } = await import("./tailscale-cutover-EKAQSDXP.js");
58
58
  await guardPrivateOnlyApply(plan, ctx, opts?.probeTailnet ?? ((conn2) => probeSsh(conn2, opts?.signal)));
59
59
  await writeStackConfig(stack, plan);
60
60
  if (plan.metadata.stackVersion !== void 0) {
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ getProvider
4
+ } from "./chunk-VUFMZEIM.js";
2
5
  import {
3
6
  readLocalState
4
- } from "./chunk-ELU3XQEA.js";
7
+ } from "./chunk-RDUKRIRC.js";
5
8
  import {
6
9
  getConfigDir,
7
10
  requireConfig
8
- } from "./chunk-64PONSA5.js";
11
+ } from "./chunk-GFIR2IIJ.js";
9
12
  import {
10
13
  UsageError
11
14
  } from "./chunk-KGXPLI7W.js";
12
- import {
13
- getProvider
14
- } from "./chunk-VUFMZEIM.js";
15
15
 
16
16
  // src/cli/context.ts
17
17
  function buildContext(args) {
@@ -41,7 +41,7 @@ function buildContext(args) {
41
41
  `Stack "${stackName}" not found in config. Run \`clawops init\` or use \`--stack\` to specify a different stack.`
42
42
  );
43
43
  }
44
- const { getOrCreateStack } = await import("./automation-MKCJ46I6.js");
44
+ const { getOrCreateStack } = await import("./automation-NBYQ6MFZ.js");
45
45
  stackCache = await getOrCreateStack({
46
46
  stack: stackName,
47
47
  stateUrl: stackConfig.stateUrl,
@@ -146,8 +146,8 @@ function renderSnapshot(snap, opts) {
146
146
  return lines.join("\n");
147
147
  }
148
148
  async function probeEntries() {
149
- const { buildContext } = await import("./context-7VI3R6EK.js");
150
- const { getConfig } = await import("./store-OVB3DAJR.js");
149
+ const { buildContext } = await import("./context-WOKSKAIA.js");
150
+ const { getConfig } = await import("./store-YOLQYXMB.js");
151
151
  const config = getConfig();
152
152
  if (!config) return [];
153
153
  return Promise.all(
@@ -215,7 +215,7 @@ function renderMenu(entries, selectedIdx, showAll, noColor, confirmDelete) {
215
215
  return lines.join("\n");
216
216
  }
217
217
  async function deleteFromRegistry(name) {
218
- const { requireConfig, setConfig } = await import("./store-OVB3DAJR.js");
218
+ const { requireConfig, setConfig } = await import("./store-YOLQYXMB.js");
219
219
  const config = requireConfig();
220
220
  const newStacks = { ...config.stacks };
221
221
  delete newStacks[name];
@@ -373,7 +373,7 @@ var monitor_default = defineCommand({
373
373
  const tailLines = Math.max(1, parseInt(String(args.tail ?? "10"), 10) || 10);
374
374
  const isTTY = Boolean(process.stdout.isTTY);
375
375
  const noColor = Boolean(args["no-color"]) || !isTTY;
376
- const { buildContext } = await import("./context-7VI3R6EK.js");
376
+ const { buildContext } = await import("./context-WOKSKAIA.js");
377
377
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
378
378
  const ac = new AbortController();
379
379
  process.on("SIGINT", () => ac.abort());
@@ -508,7 +508,7 @@ import { accessSync, mkdirSync, readFileSync, constants } from "fs";
508
508
  import ssh2 from "ssh2";
509
509
  import path from "path";
510
510
  async function runDiagnostics(opts = {}, deps = {}) {
511
- const { getConfig, getConfigDir } = await import("./store-OVB3DAJR.js");
511
+ const { getConfig, getConfigDir } = await import("./store-YOLQYXMB.js");
512
512
  const config = getConfig();
513
513
  const sections = [];
514
514
  sections.push({ title: "Runtime", checks: await runtimeChecks(getConfigDir()) });
@@ -808,8 +808,8 @@ async function deployedVersionCheck(image, deployedVersion) {
808
808
  }
809
809
  async function hardeningChecks(conn, stack, signal) {
810
810
  try {
811
- const { MODULE_CATALOG, resolveModules, withRemoteExec } = await import("./harden-3KKCR7BL.js");
812
- const { buildContext } = await import("./context-7VI3R6EK.js");
811
+ const { MODULE_CATALOG, resolveModules, withRemoteExec } = await import("./harden-RUOUA5BV.js");
812
+ const { buildContext } = await import("./context-WOKSKAIA.js");
813
813
  const provider = buildContext({ stack }).adapter.name;
814
814
  const modules = resolveModules(MODULE_CATALOG, void 0, provider);
815
815
  const checks = [];
@@ -831,8 +831,8 @@ async function hardeningChecks(conn, stack, signal) {
831
831
  }
832
832
  }
833
833
  async function defaultOpenSession(stack, signal) {
834
- const { getConfig } = await import("./store-OVB3DAJR.js");
835
- const { buildContext } = await import("./context-7VI3R6EK.js");
834
+ const { getConfig } = await import("./store-YOLQYXMB.js");
835
+ const { buildContext } = await import("./context-WOKSKAIA.js");
836
836
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
837
837
  const { acquireSession } = await import("./pool-PIIKJ4L2.js");
838
838
  const config = getConfig();
@@ -76,7 +76,9 @@ function getConfig() {
76
76
  function requireConfig() {
77
77
  const cfg = getConfig();
78
78
  if (!cfg) {
79
- throw new UsageError("No config found. Run `clawops init` first.");
79
+ throw new UsageError(
80
+ `No clawops config at ${getConfigPath()}. Create one with \`clawops init\` in a terminal, or by calling the clawops_init tool. Either way it registers a stack \u2014 a provider and a state backend \u2014 and generates an SSH key; nothing is provisioned and nothing is charged.`
81
+ );
80
82
  }
81
83
  return cfg;
82
84
  }
@@ -5,10 +5,10 @@ import {
5
5
  import {
6
6
  buildContext,
7
7
  loadAdapterModule
8
- } from "./chunk-QDNFADJI.js";
8
+ } from "./chunk-AVERNLUY.js";
9
9
  import {
10
10
  getConfig
11
- } from "./chunk-64PONSA5.js";
11
+ } from "./chunk-GFIR2IIJ.js";
12
12
  import {
13
13
  StateError,
14
14
  UsageError
@@ -71,7 +71,7 @@ async function generatePlan(intent, _opts) {
71
71
  "plan/apply is not supported for the local provider. Use `clawops up` directly."
72
72
  );
73
73
  }
74
- const { version } = await import("./package-JFVGCNKU.js");
74
+ const { version } = await import("./package-MF5LPITL.js");
75
75
  const config = getConfig();
76
76
  const instanceType = await resolveInstanceType(intent);
77
77
  const { guardOpenclawVersion, defaultOpenclawVersion } = await import("./version-guard-XVYW5WFJ.js");
@@ -123,7 +123,7 @@ A plan is only as good as the state it was computed against, so this is not a pl
123
123
  );
124
124
  }
125
125
  try {
126
- const { writeStackConfig } = await import("./stack-config-LUTS2XAD.js");
126
+ const { writeStackConfig } = await import("./stack-config-ICQ5YHUL.js");
127
127
  await writeStackConfig(stack, plan);
128
128
  const outputLines = [];
129
129
  const preview = await stack.preview({
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getConfigDir
4
- } from "./chunk-64PONSA5.js";
4
+ } from "./chunk-GFIR2IIJ.js";
5
5
 
6
6
  // src/providers/local/state.ts
7
7
  import { readFileSync, writeFileSync, mkdirSync, renameSync } from "fs";