@clawops/cli 2.2.0 → 2.3.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.
Files changed (45) hide show
  1. package/README.md +61 -3
  2. package/dist/{apply-F5SQ2ZOS.js → apply-ODV3NOJJ.js} +9 -9
  3. package/dist/{automation-NBYQ6MFZ.js → automation-VDKLZMJI.js} +1 -1
  4. package/dist/{backup-flows-NDP5JTR3.js → backup-flows-THPX2D7S.js} +1 -1
  5. package/dist/{bootstrap-32TZXVDF.js → bootstrap-L3P5E4D7.js} +2 -2
  6. package/dist/{chunk-PASAVVNS.js → chunk-47CGHUVT.js} +1 -1
  7. package/dist/{chunk-E6BRQK67.js → chunk-4SEFKZRL.js} +1 -1
  8. package/dist/{chunk-PCSX6Y3U.js → chunk-66CUJFXK.js} +2 -2
  9. package/dist/{chunk-55UMO37O.js → chunk-CHPMOE4T.js} +1 -1
  10. package/dist/{chunk-CQOYUWR7.js → chunk-EGGXYZC6.js} +60 -59
  11. package/dist/{chunk-755X5OGS.js → chunk-FGY262WZ.js} +4 -1
  12. package/dist/{chunk-LV7UO5CG.js → chunk-G2ROJXYJ.js} +2 -2
  13. package/dist/{chunk-GFIR2IIJ.js → chunk-GYMAC4MW.js} +47 -28
  14. package/dist/{chunk-66R52R7K.js → chunk-K7OWMI63.js} +14 -8
  15. package/dist/{chunk-OUQVKIIA.js → chunk-PNRFFYOA.js} +14 -14
  16. package/dist/{chunk-AX65JMDZ.js → chunk-PRBDJSWN.js} +12 -9
  17. package/dist/{chunk-4MHDW2NB.js → chunk-QRF4OWG4.js} +1 -1
  18. package/dist/{chunk-AVERNLUY.js → chunk-SQPHNVCF.js} +6 -6
  19. package/dist/{chunk-RDUKRIRC.js → chunk-U3NRKBDW.js} +1 -1
  20. package/dist/cli.js +111 -72
  21. package/dist/{context-EHSLWKSH.js → context-4KTM4DKH.js} +5 -5
  22. package/dist/{flows-6B2I6TRW.js → flows-6YEJGHCK.js} +7 -7
  23. package/dist/{generate-4YYNW3IU.js → generate-OJ5UWTLV.js} +9 -7
  24. package/dist/{harden-UHAOVQMZ.js → harden-7O553IOK.js} +5 -5
  25. package/dist/{init-HOPXDNWY.js → init-RVQ72GZ5.js} +2 -2
  26. package/dist/{mcp-wire-BXF4DJFT.js → mcp-wire-HSGZFOG5.js} +21 -21
  27. package/dist/{migrate-flow-24XA4GZL.js → migrate-flow-4XQUUFMH.js} +2 -2
  28. package/dist/{package-HYGHRX35.js → package-UOWSHBWP.js} +1 -1
  29. package/dist/policy-4FFK7REN.js +42 -0
  30. package/dist/{remote-config-OZYBMBSK.js → remote-config-V2WXIXIF.js} +1 -1
  31. package/dist/{server-E3YA32ND.js → server-YH2JWZ2Q.js} +21 -21
  32. package/dist/setup-policy-OK5PGWP7.js +90 -0
  33. package/dist/{stack-config-ICQ5YHUL.js → stack-config-3E7KWFPI.js} +2 -2
  34. package/dist/{stack-delete-NTIGKWUF.js → stack-delete-SNPMLWMD.js} +2 -2
  35. package/dist/{state-AKZP2S4T.js → state-KG6K5QZC.js} +2 -2
  36. package/dist/{store-YOLQYXMB.js → store-BTQOOIJH.js} +1 -1
  37. package/dist/{tailscale-cutover-V42HO5UM.js → tailscale-cutover-XTMGDM5H.js} +2 -2
  38. package/dist/{validate-DZE6LFEB.js → validate-CRXX7OYF.js} +1 -1
  39. package/package.json +1 -1
  40. package/spec/errors.yaml +5 -3
  41. package/spec/mcp-tools.yaml +4 -3
  42. package/spec/openclaw-2.0.config.schema.json +1 -1
  43. package/dist/{chunk-UAJJEDCJ.js → chunk-AGSNTIYZ.js} +0 -0
  44. package/dist/{chunk-YPVWF7IA.js → chunk-HSGKK3RF.js} +3 -3
  45. package/dist/{ready-IJEUBFVX.js → ready-4H3NNEYQ.js} +3 -3
@@ -1,37 +1,36 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  MCP_HTTP_PORT
4
- } from "./chunk-CQOYUWR7.js";
5
- import "./chunk-E6BRQK67.js";
6
- import "./chunk-PCSX6Y3U.js";
7
- import "./chunk-LV7UO5CG.js";
8
- import "./chunk-AX65JMDZ.js";
9
- import "./chunk-SX75L2T3.js";
4
+ } from "./chunk-EGGXYZC6.js";
10
5
  import "./chunk-27335SIH.js";
11
- import "./chunk-66R52R7K.js";
12
- import "./chunk-POYS3EVQ.js";
6
+ import "./chunk-4SEFKZRL.js";
7
+ import "./chunk-66CUJFXK.js";
8
+ import "./chunk-G2ROJXYJ.js";
9
+ import "./chunk-PRBDJSWN.js";
10
+ import "./chunk-SX75L2T3.js";
11
+ import "./chunk-TYNMOYVM.js";
13
12
  import "./chunk-BOPSG2LI.js";
14
13
  import "./chunk-3QJBNAHW.js";
15
- import "./chunk-UAJJEDCJ.js";
16
- import "./chunk-PASAVVNS.js";
17
- import "./chunk-55UMO37O.js";
14
+ import "./chunk-CHPMOE4T.js";
18
15
  import "./chunk-AEEMRFZV.js";
19
- import "./chunk-AVERNLUY.js";
20
- import "./chunk-GAZPPSKU.js";
21
- import "./chunk-TYNMOYVM.js";
16
+ import "./chunk-K7OWMI63.js";
17
+ import "./chunk-POYS3EVQ.js";
22
18
  import "./chunk-4PY6PN4G.js";
23
19
  import "./chunk-MC5ATCXS.js";
24
- import "./chunk-OUQVKIIA.js";
20
+ import "./chunk-GAZPPSKU.js";
21
+ import "./chunk-AGSNTIYZ.js";
22
+ import "./chunk-47CGHUVT.js";
23
+ import "./chunk-SQPHNVCF.js";
24
+ import "./chunk-PNRFFYOA.js";
25
25
  import "./chunk-SOZ62ZXW.js";
26
- import "./chunk-6ZFIFDBJ.js";
27
26
  import "./chunk-Z3XLWZWF.js";
27
+ import "./chunk-6ZFIFDBJ.js";
28
+ import "./chunk-LT4XMO5D.js";
28
29
  import {
29
30
  execPrivileged
30
31
  } from "./chunk-WPZIJONN.js";
31
- import "./chunk-YPVWF7IA.js";
32
32
  import "./chunk-JW5A7E3X.js";
33
- import "./chunk-LT4XMO5D.js";
34
- import "./chunk-VUFMZEIM.js";
33
+ import "./chunk-HSGKK3RF.js";
35
34
  import "./chunk-N5ZYUTZS.js";
36
35
  import "./chunk-VOEJYRIK.js";
37
36
  import "./chunk-EI7CQQ7D.js";
@@ -39,9 +38,10 @@ import "./chunk-FEK7VJAY.js";
39
38
  import "./chunk-RHOWYIWT.js";
40
39
  import "./chunk-Q7NQY5HV.js";
41
40
  import "./chunk-N4WZLWJ4.js";
42
- import "./chunk-RDUKRIRC.js";
43
- import "./chunk-GFIR2IIJ.js";
41
+ import "./chunk-U3NRKBDW.js";
42
+ import "./chunk-GYMAC4MW.js";
44
43
  import "./chunk-KGXPLI7W.js";
44
+ import "./chunk-VUFMZEIM.js";
45
45
 
46
46
  // src/cli/mcp-wire.ts
47
47
  var GATEWAY_MCP_NAME = "clawops";
@@ -7,10 +7,10 @@ import {
7
7
  migrationSteps,
8
8
  prepareMigration,
9
9
  runMigration
10
- } from "./chunk-E6BRQK67.js";
10
+ } from "./chunk-4SEFKZRL.js";
11
11
  import "./chunk-GAZPPSKU.js";
12
- import "./chunk-JW5A7E3X.js";
13
12
  import "./chunk-LT4XMO5D.js";
13
+ import "./chunk-JW5A7E3X.js";
14
14
  import "./chunk-N5ZYUTZS.js";
15
15
  import "./chunk-VOEJYRIK.js";
16
16
  import "./chunk-EI7CQQ7D.js";
@@ -2,7 +2,7 @@
2
2
 
3
3
  // package.json
4
4
  var name = "@clawops/cli";
5
- var version = "2.2.0";
5
+ var version = "2.3.0";
6
6
  var description = "Deploy self-hosted OpenClaw to AWS, GCP, Azure or a local VM \u2014 a CLI and an MCP server in one.";
7
7
  var keywords = [
8
8
  "openclaw",
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ PolicySchema,
4
+ getConfigDir
5
+ } from "./chunk-GYMAC4MW.js";
6
+ import {
7
+ UsageError
8
+ } from "./chunk-KGXPLI7W.js";
9
+
10
+ // src/config/policy.ts
11
+ import path from "path";
12
+ function configFile() {
13
+ return path.join(getConfigDir(), "config.json");
14
+ }
15
+ async function allowedTypesFor(policy, provider) {
16
+ const entries = policy?.allowedInstanceTypes?.[provider];
17
+ if (!entries) return void 0;
18
+ const { nativeInstanceType } = await import("./generate-OJ5UWTLV.js");
19
+ return [...new Set(await Promise.all(entries.map((e) => nativeInstanceType(provider, e))))];
20
+ }
21
+ async function enforceInstanceType(config, provider, instanceType) {
22
+ const allowed = await allowedTypesFor(config?.policy, provider);
23
+ if (!allowed) return;
24
+ const { nativeInstanceType } = await import("./generate-OJ5UWTLV.js");
25
+ if (allowed.includes(await nativeInstanceType(provider, instanceType))) return;
26
+ throw new UsageError(
27
+ `Instance type "${instanceType}" is not allowed on ${provider} by this machine's spending policy (${configFile()} \u2192 policy.allowedInstanceTypes.${provider}). Allowed: ${allowed.join(", ")}. The operator can change it with \`clawops setup\` or by editing that file.`
28
+ );
29
+ }
30
+ function stackCapRefusal(config, stackName) {
31
+ const max = config?.policy?.maxStacks;
32
+ if (!max || !config) return void 0;
33
+ const names = Object.keys(config.stacks);
34
+ if (names.includes(stackName) || names.length < max) return void 0;
35
+ return `This machine's spending policy allows ${max} stack${max === 1 ? "" : "s"} (${configFile()} \u2192 policy.maxStacks), and ${names.length} exist: ${names.join(", ")}. Remove one with \`clawops stacks delete\` after destroying it, or the operator can raise the cap with \`clawops setup\`.`;
36
+ }
37
+ export {
38
+ PolicySchema,
39
+ allowedTypesFor,
40
+ enforceInstanceType,
41
+ stackCapRefusal
42
+ };
@@ -8,7 +8,7 @@ import {
8
8
  deepMerge,
9
9
  readRemoteConfig,
10
10
  restartGateway
11
- } from "./chunk-UAJJEDCJ.js";
11
+ } from "./chunk-AGSNTIYZ.js";
12
12
  import "./chunk-WPZIJONN.js";
13
13
  import "./chunk-N5ZYUTZS.js";
14
14
  import "./chunk-VOEJYRIK.js";
@@ -5,35 +5,34 @@ import {
5
5
  bearerFrom,
6
6
  isLoopbackBind,
7
7
  serveMcp
8
- } from "./chunk-CQOYUWR7.js";
9
- import "./chunk-E6BRQK67.js";
10
- import "./chunk-PCSX6Y3U.js";
11
- import "./chunk-LV7UO5CG.js";
12
- import "./chunk-AX65JMDZ.js";
13
- import "./chunk-SX75L2T3.js";
8
+ } from "./chunk-EGGXYZC6.js";
14
9
  import "./chunk-27335SIH.js";
15
- import "./chunk-66R52R7K.js";
16
- import "./chunk-POYS3EVQ.js";
10
+ import "./chunk-4SEFKZRL.js";
11
+ import "./chunk-66CUJFXK.js";
12
+ import "./chunk-G2ROJXYJ.js";
13
+ import "./chunk-PRBDJSWN.js";
14
+ import "./chunk-SX75L2T3.js";
15
+ import "./chunk-TYNMOYVM.js";
17
16
  import "./chunk-BOPSG2LI.js";
18
17
  import "./chunk-3QJBNAHW.js";
19
- import "./chunk-UAJJEDCJ.js";
20
- import "./chunk-PASAVVNS.js";
21
- import "./chunk-55UMO37O.js";
18
+ import "./chunk-CHPMOE4T.js";
22
19
  import "./chunk-AEEMRFZV.js";
23
- import "./chunk-AVERNLUY.js";
24
- import "./chunk-GAZPPSKU.js";
25
- import "./chunk-TYNMOYVM.js";
20
+ import "./chunk-K7OWMI63.js";
21
+ import "./chunk-POYS3EVQ.js";
26
22
  import "./chunk-4PY6PN4G.js";
27
23
  import "./chunk-MC5ATCXS.js";
28
- import "./chunk-OUQVKIIA.js";
24
+ import "./chunk-GAZPPSKU.js";
25
+ import "./chunk-AGSNTIYZ.js";
26
+ import "./chunk-47CGHUVT.js";
27
+ import "./chunk-SQPHNVCF.js";
28
+ import "./chunk-PNRFFYOA.js";
29
29
  import "./chunk-SOZ62ZXW.js";
30
- import "./chunk-6ZFIFDBJ.js";
31
30
  import "./chunk-Z3XLWZWF.js";
31
+ import "./chunk-6ZFIFDBJ.js";
32
+ import "./chunk-LT4XMO5D.js";
32
33
  import "./chunk-WPZIJONN.js";
33
- import "./chunk-YPVWF7IA.js";
34
34
  import "./chunk-JW5A7E3X.js";
35
- import "./chunk-LT4XMO5D.js";
36
- import "./chunk-VUFMZEIM.js";
35
+ import "./chunk-HSGKK3RF.js";
37
36
  import "./chunk-N5ZYUTZS.js";
38
37
  import "./chunk-VOEJYRIK.js";
39
38
  import "./chunk-EI7CQQ7D.js";
@@ -41,9 +40,10 @@ import "./chunk-FEK7VJAY.js";
41
40
  import "./chunk-RHOWYIWT.js";
42
41
  import "./chunk-Q7NQY5HV.js";
43
42
  import "./chunk-N4WZLWJ4.js";
44
- import "./chunk-RDUKRIRC.js";
45
- import "./chunk-GFIR2IIJ.js";
43
+ import "./chunk-U3NRKBDW.js";
44
+ import "./chunk-GYMAC4MW.js";
46
45
  import "./chunk-KGXPLI7W.js";
46
+ import "./chunk-VUFMZEIM.js";
47
47
  export {
48
48
  MCP_HTTP_PORT,
49
49
  authRequirement,
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/setup-policy.ts
4
+ async function allowedChoices(provider, choices, policy) {
5
+ const { allowedTypesFor } = await import("./policy-4FFK7REN.js");
6
+ const allowed = await allowedTypesFor(policy, provider);
7
+ if (!allowed) return choices;
8
+ const { nativeInstanceType } = await import("./generate-OJ5UWTLV.js");
9
+ const kept = [];
10
+ for (const c of choices) {
11
+ if (allowed.includes(await nativeInstanceType(provider, c.value))) kept.push(c);
12
+ }
13
+ const offered = new Set(await Promise.all(kept.map((c) => nativeInstanceType(provider, c.value))));
14
+ for (const t of allowed) if (!offered.has(t)) kept.push({ name: `${t} (allowed by policy)`, value: t });
15
+ return kept;
16
+ }
17
+ function describe(provider, policy) {
18
+ const sizes = policy?.allowedInstanceTypes?.[provider];
19
+ const cap = policy?.maxStacks;
20
+ return `Server sizes on ${provider}: ${sizes ? sizes.join(", ") : "any"}. Deployments: ${cap ? `at most ${cap}` : "no limit"}.`;
21
+ }
22
+ async function promptSpendingPolicy(opts) {
23
+ const { provider, choices, current, stackCount, inquirer } = opts;
24
+ const { change } = await inquirer.prompt([{
25
+ type: "confirm",
26
+ name: "change",
27
+ message: `Spending limits \u2014 ${describe(provider ?? "this machine", current)} Change them? (they apply to every deploy from this machine, by any tool)`,
28
+ default: false
29
+ }]);
30
+ if (!change) return void 0;
31
+ const next = { ...current ?? {} };
32
+ if (provider && choices.length > 0) {
33
+ const currentSizes = current?.allowedInstanceTypes?.[provider];
34
+ const { sizes } = await inquirer.prompt([{
35
+ type: "checkbox",
36
+ name: "sizes",
37
+ message: `Server sizes clawops may deploy on ${provider}: (space to toggle; all checked = no limit)`,
38
+ choices: choices.map((c) => ({
39
+ ...c,
40
+ checked: currentSizes ? currentSizes.includes(c.value) : true
41
+ })),
42
+ // A checkbox answer is the array of checked values, whatever the shim's signature says.
43
+ validate: (v) => Array.isArray(v) && v.length > 0 || "Allow at least one size."
44
+ }]);
45
+ const all = sizes.length === choices.length;
46
+ const rest = { ...next.allowedInstanceTypes ?? {} };
47
+ if (all) delete rest[provider];
48
+ else rest[provider] = sizes;
49
+ if (Object.keys(rest).length > 0) next.allowedInstanceTypes = rest;
50
+ else delete next.allowedInstanceTypes;
51
+ }
52
+ const { maxStacks } = await inquirer.prompt([{
53
+ type: "input",
54
+ name: "maxStacks",
55
+ message: "Most deployments clawops may manage: (a number, or leave blank for no limit)",
56
+ default: current?.maxStacks ? String(current.maxStacks) : "",
57
+ validate: (v) => v.trim() === "" || /^\d+$/.test(v.trim()) && Number(v) > 0 || "A whole number above 0, or blank."
58
+ }]);
59
+ if (maxStacks.trim() === "") delete next.maxStacks;
60
+ else {
61
+ next.maxStacks = Number(maxStacks);
62
+ if (next.maxStacks <= stackCount) {
63
+ process.stderr.write(
64
+ `[clawops] note: ${stackCount} deployment${stackCount === 1 ? " exists" : "s exist"} already, so new ones will be refused until some are removed.
65
+ `
66
+ );
67
+ }
68
+ }
69
+ return next;
70
+ }
71
+ async function savePolicy(policy) {
72
+ const { getConfig, setConfig } = await import("./store-BTQOOIJH.js");
73
+ const config = getConfig();
74
+ if (!config) return false;
75
+ const { allowedInstanceTypes, maxStacks } = policy;
76
+ const cleaned = {
77
+ ...allowedInstanceTypes && Object.keys(allowedInstanceTypes).length > 0 ? { allowedInstanceTypes } : {},
78
+ ...maxStacks ? { maxStacks } : {}
79
+ };
80
+ const next = { ...config };
81
+ if (Object.keys(cleaned).length > 0) next.policy = cleaned;
82
+ else delete next.policy;
83
+ setConfig(next);
84
+ return true;
85
+ }
86
+ export {
87
+ allowedChoices,
88
+ promptSpendingPolicy,
89
+ savePolicy
90
+ };
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  writeStackConfig
4
- } from "./chunk-55UMO37O.js";
4
+ } from "./chunk-CHPMOE4T.js";
5
5
  import "./chunk-AEEMRFZV.js";
6
6
  import "./chunk-VOEJYRIK.js";
7
7
  import "./chunk-EI7CQQ7D.js";
8
- import "./chunk-GFIR2IIJ.js";
8
+ import "./chunk-GYMAC4MW.js";
9
9
  import "./chunk-KGXPLI7W.js";
10
10
  export {
11
11
  writeStackConfig
@@ -3,8 +3,8 @@ import {
3
3
  checkStackDelete,
4
4
  deleteStackFromConfig,
5
5
  forgetNotice
6
- } from "./chunk-LV7UO5CG.js";
7
- import "./chunk-GFIR2IIJ.js";
6
+ } from "./chunk-G2ROJXYJ.js";
7
+ import "./chunk-GYMAC4MW.js";
8
8
  import "./chunk-KGXPLI7W.js";
9
9
  export {
10
10
  checkStackDelete,
@@ -5,8 +5,8 @@ import {
5
5
  stateDir,
6
6
  statePath,
7
7
  writeLocalState
8
- } from "./chunk-RDUKRIRC.js";
9
- import "./chunk-GFIR2IIJ.js";
8
+ } from "./chunk-U3NRKBDW.js";
9
+ import "./chunk-GYMAC4MW.js";
10
10
  import "./chunk-KGXPLI7W.js";
11
11
  export {
12
12
  localStateToConnectionInfo,
@@ -5,7 +5,7 @@ import {
5
5
  getConfigPath,
6
6
  requireConfig,
7
7
  setConfig
8
- } from "./chunk-GFIR2IIJ.js";
8
+ } from "./chunk-GYMAC4MW.js";
9
9
  import "./chunk-KGXPLI7W.js";
10
10
  export {
11
11
  getConfig,
@@ -3,13 +3,13 @@ import {
3
3
  isTailscaleIpv4,
4
4
  parseStatus,
5
5
  rootPrefix
6
- } from "./chunk-4MHDW2NB.js";
6
+ } from "./chunk-QRF4OWG4.js";
7
7
  import {
8
8
  formatKnownHostsLine,
9
9
  keyTypeFromBlob,
10
10
  verifyAgainstKnownHosts
11
11
  } from "./chunk-MC5ATCXS.js";
12
- import "./chunk-GFIR2IIJ.js";
12
+ import "./chunk-GYMAC4MW.js";
13
13
  import "./chunk-KGXPLI7W.js";
14
14
 
15
15
  // src/harden/tailscale-cutover.ts
@@ -4,7 +4,7 @@ import {
4
4
  validatePlan,
5
5
  validatePlanConfig,
6
6
  validatePlanNetwork
7
- } from "./chunk-PASAVVNS.js";
7
+ } from "./chunk-47CGHUVT.js";
8
8
  import "./chunk-JW5A7E3X.js";
9
9
  export {
10
10
  assertValidPlan,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawops/cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Deploy self-hosted OpenClaw to AWS, GCP, Azure or a local VM — a CLI and an MCP server in one.",
5
5
  "keywords": [
6
6
  "openclaw",
package/spec/errors.yaml CHANGED
@@ -1,6 +1,7 @@
1
1
  # Error Taxonomy — machine-readable companion to ADR 0005.
2
- # Used by `pnpm gen:schemas` to emit src/errors/_generated.ts.
3
- # Update via PR; CI verifies generated file matches.
2
+ # Nothing is generated from this file. src/errors/index.ts is hand-written, and
3
+ # tests/spec/errors.test.ts fails when the two disagree on a class or its exit code.
4
+ # Change both in the same PR.
4
5
 
5
6
  version: 1
6
7
 
@@ -150,7 +151,8 @@ taxonomy:
150
151
  suggestedAction: "Operation cancelled by user."
151
152
 
152
153
  # Sensitive field patterns for redaction (R21).
153
- # Used by both pino logger config and src/mcp/audit.ts.
154
+ # Enforced by src/mcp/audit.ts, whose SENSITIVE_KEYS must cover every pattern here;
155
+ # tests/spec/errors.test.ts checks that it does.
154
156
  redaction:
155
157
  patterns:
156
158
  - authorization
@@ -836,9 +836,10 @@ tools:
836
836
  - name: clawops_workflow_recover
837
837
  toolset: [workflow, read]
838
838
  description: |
839
- Diagnostic workflow for an unhealthy stack. Internally: status check →
840
- gateway logs → agent logs → systemd service status → produces a structured
841
- diagnostic report with suggested remediation.
839
+ Diagnostic workflow for an unhealthy stack. Internally: what is deployed
840
+ (clawops_status) → the stack's failed health checks (clawops_doctor) → the
841
+ gateway's last 50 log lines (clawops_logs_tail) → a report with next steps that
842
+ name the tool for each kind of failure. Changes nothing.
842
843
 
843
844
  Use when: the user reports any "not working" symptom and you don't know
844
845
  where to start. Best entry point for troubleshooting.