@clawops/cli 1.4.0 → 1.6.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 (46) hide show
  1. package/README.md +40 -0
  2. package/dist/{apply-5RREMN3L.js → apply-SI3JKS4Z.js} +2 -2
  3. package/dist/automation-RULUSJBW.js +0 -0
  4. package/dist/{aws-FRE2JVAZ.js → aws-D7Y6LCGK.js} +52 -90
  5. package/dist/{azure-PVC3AQVC.js → azure-JQAMNVHN.js} +15 -56
  6. package/dist/{bootstrap-G4UZ2FKH.js → bootstrap-RY4VOSDJ.js} +2 -2
  7. package/dist/chunk-3QJBNAHW.js +0 -0
  8. package/dist/chunk-6ZFIFDBJ.js +0 -0
  9. package/dist/{chunk-UAA6YOOP.js → chunk-72FF7IK2.js} +2 -2
  10. package/dist/chunk-A2I76FTA.js +0 -0
  11. package/dist/chunk-BOPSG2LI.js +0 -0
  12. package/dist/{chunk-JYQZJMD3.js → chunk-C5NDLOK2.js} +41 -33
  13. package/dist/chunk-CX5SL5HP.js +0 -0
  14. package/dist/{chunk-4U3LTLWZ.js → chunk-GJEF6UQA.js} +1 -0
  15. package/dist/chunk-KGXPLI7W.js +0 -0
  16. package/dist/{chunk-ZVOEQCNW.js → chunk-LCKD7L7X.js} +1 -1
  17. package/dist/chunk-OIGTOLB3.js +0 -0
  18. package/dist/{chunk-ZONXY3C6.js → chunk-QHGFENYR.js} +2 -2
  19. package/dist/{chunk-T5EX55GP.js → chunk-QI75OVJK.js} +3 -3
  20. package/dist/chunk-XKT42M34.js +72 -0
  21. package/dist/chunk-YTH4L2GN.js +0 -0
  22. package/dist/chunk-ZFNPM2WG.js +0 -0
  23. package/dist/cli.js +311 -54
  24. package/dist/{context-PSGEX2D7.js → context-KPKBOWOP.js} +1 -1
  25. package/dist/errors-OK47MQFD.js +0 -0
  26. package/dist/firewall-XQGO7HWK.js +51 -0
  27. package/dist/{gcp-BXDTC6EK.js → gcp-6FT2A45S.js} +14 -63
  28. package/dist/{generate-Z7DBMANX.js → generate-YV7226Q7.js} +2 -2
  29. package/dist/js-yaml-PTEEG4FO.js +0 -0
  30. package/dist/local-DXBEVZ5C.js +0 -0
  31. package/dist/mcp-apps-KY44ED3Y.js +0 -0
  32. package/dist/mcp-wire-ZWIYMLEW.js +45 -0
  33. package/dist/outputs-DJHBY7EE.js +0 -0
  34. package/dist/overlay-store-ADZPD7EU.js +0 -0
  35. package/dist/{package-WAJRGBBM.js → package-EW3FS257.js} +1 -1
  36. package/dist/{pool-FBFHATDG.js → pool-JZGKPP6K.js} +2 -2
  37. package/dist/providers-2OABPW2E.js +0 -0
  38. package/dist/remote-config-QF5TT7GU.js +0 -0
  39. package/dist/secrets-SVZWNAPK.js +0 -0
  40. package/dist/{server-IWLZJ4EU.js → server-3DEZHUWB.js} +9 -9
  41. package/dist/{ssh-IQXNME3D.js → ssh-E2AMBPZY.js} +1 -1
  42. package/dist/state-PRBIIN7I.js +0 -0
  43. package/dist/store-SDUR52Z5.js +0 -0
  44. package/dist/validate-T5M5EHSJ.js +0 -0
  45. package/package.json +26 -14
  46. package/dist/firewall-YYDOWDDP.js +0 -36
package/dist/cli.js CHANGED
@@ -5,18 +5,20 @@ import {
5
5
  writeAppConfigs
6
6
  } from "./chunk-OIGTOLB3.js";
7
7
  import {
8
+ REPO_URL,
8
9
  chalk,
9
10
  failure,
10
11
  info,
11
12
  monitor_default,
13
+ printCta,
12
14
  spinner,
13
15
  success,
14
16
  validateOpenclawConfig,
15
17
  warn
16
- } from "./chunk-JYQZJMD3.js";
17
- import "./chunk-T5EX55GP.js";
18
- import "./chunk-ZVOEQCNW.js";
19
- import "./chunk-4U3LTLWZ.js";
18
+ } from "./chunk-C5NDLOK2.js";
19
+ import "./chunk-QI75OVJK.js";
20
+ import "./chunk-LCKD7L7X.js";
21
+ import "./chunk-GJEF6UQA.js";
20
22
  import "./chunk-ZFNPM2WG.js";
21
23
  import "./chunk-A2I76FTA.js";
22
24
  import {
@@ -31,7 +33,7 @@ import {
31
33
  } from "./chunk-KGXPLI7W.js";
32
34
 
33
35
  // src/cli/index.ts
34
- import { defineCommand as defineCommand21, runMain } from "citty";
36
+ import { defineCommand as defineCommand22, runMain } from "citty";
35
37
 
36
38
  // src/cli/commands/init.ts
37
39
  import { defineCommand } from "citty";
@@ -203,7 +205,7 @@ var up_default = defineCommand2({
203
205
  config: { type: "string", description: "Path to openclaw config overlay JSON (local provider only)" }
204
206
  },
205
207
  async run({ args }) {
206
- const { buildContext } = await import("./context-PSGEX2D7.js");
208
+ const { buildContext } = await import("./context-KPKBOWOP.js");
207
209
  const ctx = buildContext(args);
208
210
  const openclawVersion = typeof args["openclaw-version"] === "string" ? args["openclaw-version"] : "stable";
209
211
  if (ctx.adapter.name === "local") {
@@ -214,7 +216,7 @@ var up_default = defineCommand2({
214
216
  );
215
217
  }
216
218
  const { localOpts } = stackConfig;
217
- const { localBootstrap } = await import("./bootstrap-G4UZ2FKH.js");
219
+ const { localBootstrap } = await import("./bootstrap-RY4VOSDJ.js");
218
220
  const abortController = new AbortController();
219
221
  process3.on("SIGINT", () => abortController.abort());
220
222
  process3.on("SIGTERM", () => abortController.abort());
@@ -307,7 +309,7 @@ var up_default = defineCommand2({
307
309
  }
308
310
  });
309
311
  async function applyLocalConfigOverlay(opts) {
310
- const { connect } = await import("./ssh-IQXNME3D.js");
312
+ const { connect } = await import("./ssh-E2AMBPZY.js");
311
313
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
312
314
  const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
313
315
  let overlay;
@@ -349,7 +351,7 @@ var down_default = defineCommand3({
349
351
  "dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
350
352
  },
351
353
  async run({ args }) {
352
- const { buildContext } = await import("./context-PSGEX2D7.js");
354
+ const { buildContext } = await import("./context-KPKBOWOP.js");
353
355
  const ctx = buildContext(args);
354
356
  if (args["dry-run"]) {
355
357
  info(`Dry run \u2014 would destroy stack "${ctx.stackName}"`);
@@ -413,7 +415,7 @@ var status_default = defineCommand4({
413
415
  json: { type: "boolean", description: "Emit JSON" }
414
416
  },
415
417
  async run({ args }) {
416
- const { buildContext } = await import("./context-PSGEX2D7.js");
418
+ const { buildContext } = await import("./context-KPKBOWOP.js");
417
419
  const ctx = buildContext(args);
418
420
  if (ctx.adapter.name === "local") {
419
421
  const state = ctx.localState;
@@ -485,8 +487,8 @@ var plan_default = defineCommand5({
485
487
  out: { type: "string", description: "Write plan JSON to this absolute path (default: stdout)" }
486
488
  },
487
489
  async run({ args }) {
488
- const { buildContext } = await import("./context-PSGEX2D7.js");
489
- const { generatePlan } = await import("./generate-Z7DBMANX.js");
490
+ const { buildContext } = await import("./context-KPKBOWOP.js");
491
+ const { generatePlan } = await import("./generate-YV7226Q7.js");
490
492
  const ctx = buildContext(args);
491
493
  if (ctx.adapter.name === "local") {
492
494
  throw new UsageError(
@@ -576,7 +578,7 @@ var apply_default = defineCommand6({
576
578
  },
577
579
  async run({ args }) {
578
580
  const { validatePlan } = await import("./validate-T5M5EHSJ.js");
579
- const { applyPlan } = await import("./apply-5RREMN3L.js");
581
+ const { applyPlan } = await import("./apply-SI3JKS4Z.js");
580
582
  const planPath = args._?.[0];
581
583
  if (!planPath) {
582
584
  throw new UsageError("Usage: clawops apply <plan.json>");
@@ -692,7 +694,7 @@ var destroy_default = defineCommand7({
692
694
  "dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
693
695
  },
694
696
  async run({ args }) {
695
- const { buildContext } = await import("./context-PSGEX2D7.js");
697
+ const { buildContext } = await import("./context-KPKBOWOP.js");
696
698
  const ctx = buildContext(args);
697
699
  if (ctx.adapter.name === "local") {
698
700
  throw new UsageError(
@@ -759,8 +761,8 @@ var ssh_default = defineCommand8({
759
761
  command: { type: "string", description: "Remote command to run (instead of interactive shell)" }
760
762
  },
761
763
  async run({ args }) {
762
- const { buildContext } = await import("./context-PSGEX2D7.js");
763
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
764
+ const { buildContext } = await import("./context-KPKBOWOP.js");
765
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
764
766
  const ctx = buildContext(args);
765
767
  let conn;
766
768
  if (ctx.adapter.name === "local") {
@@ -846,9 +848,9 @@ var tunnel_default = defineCommand9({
846
848
  "no-open": { type: "boolean", description: "Do not open browser after tunnel is ready" }
847
849
  },
848
850
  async run({ args }) {
849
- const { buildContext } = await import("./context-PSGEX2D7.js");
851
+ const { buildContext } = await import("./context-KPKBOWOP.js");
850
852
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
851
- const { acquireSession } = await import("./pool-FBFHATDG.js");
853
+ const { acquireSession } = await import("./pool-JZGKPP6K.js");
852
854
  const ctx = buildContext(args);
853
855
  const stack = await ctx.getStack();
854
856
  const outputMap = await stack.outputs();
@@ -914,9 +916,9 @@ var logs_default = defineCommand10({
914
916
  since: { type: "string", description: "Show logs since duration (e.g. 5m, 1h)" }
915
917
  },
916
918
  async run({ args }) {
917
- const { buildContext } = await import("./context-PSGEX2D7.js");
919
+ const { buildContext } = await import("./context-KPKBOWOP.js");
918
920
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
919
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
921
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
920
922
  const ctx = buildContext(args);
921
923
  const stack = await ctx.getStack();
922
924
  const outputMap = await stack.outputs();
@@ -1031,9 +1033,9 @@ var config_default = defineCommand11({
1031
1033
  "dry-run": { type: "boolean", description: "Show what would change without writing" }
1032
1034
  },
1033
1035
  async run({ args }) {
1034
- const { buildContext } = await import("./context-PSGEX2D7.js");
1036
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1035
1037
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1036
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1038
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1037
1039
  const [action, key, value] = args._ ?? [];
1038
1040
  if (!action || !["get", "set", "unset", "validate"].includes(action)) {
1039
1041
  failure("Usage: clawops config <get [key] | set key value | unset key | validate>");
@@ -1157,9 +1159,9 @@ var agents_default = defineCommand12({
1157
1159
  json: { type: "boolean", description: "Emit JSON (for list)" }
1158
1160
  },
1159
1161
  async run({ args }) {
1160
- const { buildContext } = await import("./context-PSGEX2D7.js");
1162
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1161
1163
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1162
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1164
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1163
1165
  const [action, name] = args._ ?? [];
1164
1166
  if (!action || !["list", "restart", "logs"].includes(action)) {
1165
1167
  failure("Usage: clawops agents <list | restart [name] | logs <name>>");
@@ -1261,9 +1263,9 @@ var gateway_default = defineCommand13({
1261
1263
  json: { type: "boolean", description: "Emit JSON (for status)" }
1262
1264
  },
1263
1265
  async run({ args }) {
1264
- const { buildContext } = await import("./context-PSGEX2D7.js");
1266
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1265
1267
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1266
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1268
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1267
1269
  const [action, versionArg] = args._ ?? [];
1268
1270
  if (!action || !["status", "restart", "update"].includes(action)) {
1269
1271
  failure("Usage: clawops gateway <status | restart | update [version]>");
@@ -1374,8 +1376,8 @@ var backup_default = defineCommand14({
1374
1376
  yes: { type: "boolean", description: "[restore] Skip confirmation prompt" }
1375
1377
  },
1376
1378
  async run({ args }) {
1377
- const { buildContext } = await import("./context-PSGEX2D7.js");
1378
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1379
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1380
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1379
1381
  const action = args.action;
1380
1382
  if (action !== "create" && action !== "restore") {
1381
1383
  throw new UsageError(`Unknown action: ${action}. Use "create" or "restore"`);
@@ -1547,7 +1549,7 @@ var stacks_default = defineCommand15({
1547
1549
  let isDeployed = false;
1548
1550
  if (!args.force) {
1549
1551
  try {
1550
- const { buildContext } = await import("./context-PSGEX2D7.js");
1552
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1551
1553
  const ctx = buildContext({ stack: name });
1552
1554
  if (ctx.adapter.name === "local") {
1553
1555
  isDeployed = !!ctx.localState;
@@ -1668,9 +1670,9 @@ var doctor_default = defineCommand16({
1668
1670
  info("Credential checks skipped \u2014 no config");
1669
1671
  } else {
1670
1672
  const { getProvider } = await import("./providers-2OABPW2E.js");
1671
- await import("./aws-FRE2JVAZ.js");
1672
- await import("./gcp-BXDTC6EK.js");
1673
- await import("./azure-PVC3AQVC.js");
1673
+ await import("./aws-D7Y6LCGK.js");
1674
+ await import("./gcp-6FT2A45S.js");
1675
+ await import("./azure-JQAMNVHN.js");
1674
1676
  await import("./local-DXBEVZ5C.js");
1675
1677
  const checkedProviders = /* @__PURE__ */ new Set();
1676
1678
  for (const [stackName, stackCfg] of Object.entries(config.stacks)) {
@@ -1705,9 +1707,9 @@ var doctor_default = defineCommand16({
1705
1707
  info("Remote health skipped \u2014 no config");
1706
1708
  } else {
1707
1709
  try {
1708
- const { buildContext } = await import("./context-PSGEX2D7.js");
1710
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1709
1711
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1710
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1712
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1711
1713
  const ctx = buildContext({ stack: args.stack });
1712
1714
  const stack = await ctx.getStack();
1713
1715
  const outputMap = await stack.outputs();
@@ -1792,7 +1794,14 @@ var doctor_default = defineCommand16({
1792
1794
  }
1793
1795
  }
1794
1796
  process18.stdout.write("\n");
1795
- if (!nodeOk) process18.exit(1);
1797
+ if (!nodeOk) {
1798
+ process18.stdout.write(
1799
+ `Run \`clawops bug\` to open a pre-filled issue at ${REPO_URL}/issues
1800
+
1801
+ `
1802
+ );
1803
+ process18.exit(1);
1804
+ }
1796
1805
  }
1797
1806
  });
1798
1807
 
@@ -1813,7 +1822,7 @@ var serveCmd = defineCommand17({
1813
1822
  inspector: { type: "boolean", description: "Enable MCP inspector" }
1814
1823
  },
1815
1824
  async run({ args }) {
1816
- const { serveMcp } = await import("./server-IWLZJ4EU.js");
1825
+ const { serveMcp } = await import("./server-3DEZHUWB.js");
1817
1826
  await serveMcp({
1818
1827
  port: args.http ? Number(args.http) : void 0,
1819
1828
  bind: args.bind,
@@ -1878,6 +1887,85 @@ var installCmd = defineCommand17({
1878
1887
  }
1879
1888
  }
1880
1889
  });
1890
+ var wireCmd = defineCommand17({
1891
+ meta: {
1892
+ name: "wire",
1893
+ description: "Wire the gateway AI as an MCP client of clawops (WO-28)"
1894
+ },
1895
+ args: {
1896
+ stack: { type: "string", description: "Target stack name" },
1897
+ force: { type: "boolean", description: "Apply even if gateway version is below minimum" }
1898
+ },
1899
+ async run({ args }) {
1900
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1901
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1902
+ const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1903
+ const { wireGatewayMcp } = await import("./mcp-wire-ZWIYMLEW.js");
1904
+ const ac = new AbortController();
1905
+ process19.on("SIGINT", () => {
1906
+ ac.abort();
1907
+ process19.exit(130);
1908
+ });
1909
+ process19.on("SIGTERM", () => {
1910
+ ac.abort();
1911
+ process19.exit(143);
1912
+ });
1913
+ const ctx = buildContext({ stack: args.stack });
1914
+ let conn;
1915
+ if (ctx.adapter.name === "local") {
1916
+ if (!ctx.localState) {
1917
+ failure("Stack is not deployed. Run `clawops up` first.");
1918
+ process19.exit(1);
1919
+ }
1920
+ const ls = ctx.localState;
1921
+ conn = { host: ls.sshHost, port: ls.sshPort, user: ls.sshUser, privateKeyPath: ls.privateKeyPath, knownHostsPath: ls.knownHostsPath };
1922
+ } else {
1923
+ const stack = await ctx.getStack();
1924
+ const outputMap = await stack.outputs();
1925
+ const outputs = Object.fromEntries(
1926
+ Object.entries(outputMap).map(([k, v]) => [k, v.value])
1927
+ );
1928
+ if (!outputs["publicIp"]) {
1929
+ failure("Stack has no outputs. Run `clawops up` first.");
1930
+ process19.exit(1);
1931
+ }
1932
+ const base = extractBaseOutputs(outputs);
1933
+ conn = {
1934
+ host: base.publicIp,
1935
+ port: base.sshPort ?? 22,
1936
+ user: base.sshUser ?? "ubuntu",
1937
+ privateKeyPath: ctx.config.ssh.keyPath,
1938
+ knownHostsPath: ctx.config.ssh.knownHostsPath
1939
+ };
1940
+ }
1941
+ const spin = spinner(`Connecting to ${conn.host}...`);
1942
+ const { session, release } = await acquireSession({ ...conn, signal: ac.signal });
1943
+ try {
1944
+ spin.text = "Reading gateway config...";
1945
+ const result = await wireGatewayMcp(session, ac.signal, { force: Boolean(args.force) });
1946
+ if (result.status === "version-blocked") {
1947
+ spin.fail("Gateway version is too old for MCP client support.");
1948
+ warn(`Gateway version ${result.version} requires at least 2026.4 for MCP client support.`);
1949
+ info("Upgrade OpenClaw and re-run, or bypass with: clawops mcp wire --force");
1950
+ process19.exit(1);
1951
+ }
1952
+ if (result.rewired) {
1953
+ spin.succeed("Re-wiring clawops MCP client \u2014 previous entry replaced.");
1954
+ } else {
1955
+ spin.succeed("Gateway MCP client wired.");
1956
+ }
1957
+ success("The gateway's AI can now run clawops commands.");
1958
+ info('Try asking it: "check if my stack is healthy"');
1959
+ } catch (err) {
1960
+ spin.fail("Failed to wire gateway MCP client.");
1961
+ failure(err instanceof Error ? err.message : String(err));
1962
+ process19.exit(1);
1963
+ } finally {
1964
+ release();
1965
+ drainPool();
1966
+ }
1967
+ }
1968
+ });
1881
1969
  var mcp_default = defineCommand17({
1882
1970
  meta: {
1883
1971
  name: "mcp",
@@ -1886,7 +1974,8 @@ var mcp_default = defineCommand17({
1886
1974
  args: {},
1887
1975
  subCommands: {
1888
1976
  serve: serveCmd,
1889
- install: installCmd
1977
+ install: installCmd,
1978
+ wire: wireCmd
1890
1979
  }
1891
1980
  });
1892
1981
 
@@ -2296,6 +2385,15 @@ var setup_default = defineCommand18({
2296
2385
  signal: ac.signal,
2297
2386
  inquirer
2298
2387
  });
2388
+ await maybeWireGatewayMcp({
2389
+ stackName: stackAnswers.stackName,
2390
+ host: localHost,
2391
+ port: localPort,
2392
+ user: localUser,
2393
+ keyPath: localKeyPath,
2394
+ signal: ac.signal,
2395
+ inquirer
2396
+ });
2299
2397
  } else {
2300
2398
  const { getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
2301
2399
  const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
@@ -2314,7 +2412,7 @@ var setup_default = defineCommand18({
2314
2412
  default: false
2315
2413
  }]);
2316
2414
  if (applyNow) {
2317
- const { applyPlan } = await import("./apply-5RREMN3L.js");
2415
+ const { applyPlan } = await import("./apply-SI3JKS4Z.js");
2318
2416
  const plan = JSON.parse(readFileSync3(outputPath, "utf-8"));
2319
2417
  try {
2320
2418
  await applyPlan(plan, {
@@ -2327,6 +2425,7 @@ var setup_default = defineCommand18({
2327
2425
  failure(err instanceof Error ? err.message : String(err));
2328
2426
  process20.exit(1);
2329
2427
  }
2428
+ await maybeWireGatewayMcpCloud({ stackName: stackAnswers.stackName, signal: ac.signal, inquirer });
2330
2429
  } else {
2331
2430
  info(`
2332
2431
  To deploy later: clawops apply ${outputPath}`);
@@ -2336,8 +2435,8 @@ To deploy later: clawops apply ${outputPath}`);
2336
2435
  });
2337
2436
  async function runLocalDeploy(opts) {
2338
2437
  const { setConfig: setConfig2, getConfig: getConfig2, getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
2339
- const { localBootstrap } = await import("./bootstrap-G4UZ2FKH.js");
2340
- const { connect } = await import("./ssh-IQXNME3D.js");
2438
+ const { localBootstrap } = await import("./bootstrap-RY4VOSDJ.js");
2439
+ const { connect } = await import("./ssh-E2AMBPZY.js");
2341
2440
  const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
2342
2441
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
2343
2442
  const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
@@ -2419,7 +2518,7 @@ async function runLocalDeploy(opts) {
2419
2518
  spin2.fail("Configuration failed");
2420
2519
  throw err;
2421
2520
  }
2422
- const { drainPool } = await import("./pool-FBFHATDG.js");
2521
+ const { drainPool } = await import("./pool-JZGKPP6K.js");
2423
2522
  drainPool();
2424
2523
  const tokenPath = path3.join(os.homedir(), ".clawops", "secrets", `GATEWAY_TOKEN_${opts.stackName}`);
2425
2524
  const dashboardUrl = `${state.gatewayUrl}?token=${opts.gatewayToken}`;
@@ -2431,6 +2530,7 @@ async function runLocalDeploy(opts) {
2431
2530
  info(`Token saved to ${tokenPath}`);
2432
2531
  info(`
2433
2532
  Run clawops doctor --stack ${opts.stackName} to check everything is healthy`);
2533
+ printCta();
2434
2534
  }
2435
2535
  var CLOUD_AUTH = {
2436
2536
  aws: {
@@ -2556,7 +2656,7 @@ var DOCKER_CHECK_CMD = [
2556
2656
  "echo NOT_RUNNING"
2557
2657
  ].join("; ");
2558
2658
  async function checkDockerPreflight(opts) {
2559
- const { acquireSession } = await import("./pool-FBFHATDG.js");
2659
+ const { acquireSession } = await import("./pool-JZGKPP6K.js");
2560
2660
  const { ProviderError } = await import("./errors-OK47MQFD.js");
2561
2661
  const spin = spinner("Checking Docker on target host...");
2562
2662
  const timeoutSignal = AbortSignal.timeout(DOCKER_PREFLIGHT_TIMEOUT_MS);
@@ -2603,7 +2703,7 @@ async function checkDockerPreflight(opts) {
2603
2703
  var DOCKER_POLL_MS = 3e3;
2604
2704
  var DOCKER_TIMEOUT_MS = 9e4;
2605
2705
  async function startRemoteDocker(opts, spin) {
2606
- const { acquireSession } = await import("./pool-FBFHATDG.js");
2706
+ const { acquireSession } = await import("./pool-JZGKPP6K.js");
2607
2707
  const { ProviderError } = await import("./errors-OK47MQFD.js");
2608
2708
  spin.text = "Starting Docker on the remote server...";
2609
2709
  const { session, release } = await acquireSession({
@@ -2803,6 +2903,55 @@ function printMcpSnippet() {
2803
2903
  }
2804
2904
  }, null, 2) + "\n\n");
2805
2905
  }
2906
+ async function maybeWireGatewayMcp(opts) {
2907
+ process20.stdout.write("\n");
2908
+ const { wireGateway } = await inquirerPromptWire(opts.inquirer);
2909
+ if (!wireGateway) return;
2910
+ const { connect } = await import("./ssh-E2AMBPZY.js");
2911
+ const { getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
2912
+ const { wireGatewayMcp } = await import("./mcp-wire-ZWIYMLEW.js");
2913
+ const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
2914
+ const spin = spinner("Wiring gateway MCP client...");
2915
+ const session = await connect({
2916
+ host: opts.host,
2917
+ port: opts.port,
2918
+ user: opts.user,
2919
+ privateKeyPath: opts.keyPath,
2920
+ knownHostsPath,
2921
+ signal: opts.signal
2922
+ });
2923
+ try {
2924
+ const result = await wireGatewayMcp(session, opts.signal ?? AbortSignal.timeout(3e4));
2925
+ if (result.status === "version-blocked") {
2926
+ spin.warn(`Gateway version ${result.version} is too old for MCP client support (requires \u2265 2026.4).`);
2927
+ info("Upgrade OpenClaw and run: clawops mcp wire --stack " + opts.stackName);
2928
+ } else {
2929
+ spin.succeed(result.rewired ? "Gateway MCP client re-wired." : "Gateway MCP client wired.");
2930
+ success("The gateway's AI can now run clawops commands.");
2931
+ info('Try asking it: "check if my stack is healthy"');
2932
+ }
2933
+ } catch (err) {
2934
+ spin.fail("Failed to wire gateway MCP client.");
2935
+ failure(err instanceof Error ? err.message : String(err));
2936
+ info("You can retry later: clawops mcp wire --stack " + opts.stackName);
2937
+ } finally {
2938
+ session.close();
2939
+ }
2940
+ }
2941
+ async function maybeWireGatewayMcpCloud(opts) {
2942
+ process20.stdout.write("\n");
2943
+ const { wireGateway } = await inquirerPromptWire(opts.inquirer);
2944
+ if (!wireGateway) return;
2945
+ info(`Run this after the server is ready: clawops mcp wire --stack ${opts.stackName}`);
2946
+ }
2947
+ async function inquirerPromptWire(inquirer) {
2948
+ return inquirer.prompt([{
2949
+ type: "confirm",
2950
+ name: "wireGateway",
2951
+ message: "Should the OpenClaw gateway's AI also be able to manage this stack? (adds clawops MCP client to gateway)",
2952
+ default: false
2953
+ }]);
2954
+ }
2806
2955
  function loadCatalogs(yaml) {
2807
2956
  const specDir = path3.join(path3.dirname(fileURLToPath(import.meta.url)), "../../../spec");
2808
2957
  try {
@@ -3023,10 +3172,10 @@ var rotateCmd = defineCommand19({
3023
3172
  }
3024
3173
  info(`Re-applying config overlay to stack "${targetStack}"\u2026`);
3025
3174
  try {
3026
- const { buildContext } = await import("./context-PSGEX2D7.js");
3175
+ const { buildContext } = await import("./context-KPKBOWOP.js");
3027
3176
  const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
3028
3177
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
3029
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
3178
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
3030
3179
  const { localStateToConnectionInfo } = await import("./state-PRBIIN7I.js");
3031
3180
  const ctx = buildContext({ stack: targetStack });
3032
3181
  let conn;
@@ -3151,7 +3300,7 @@ var COMMANDS = [
3151
3300
  ["backup", "Create or restore an OpenClaw state backup"],
3152
3301
  ["stacks", "List named stacks and their state"],
3153
3302
  ["doctor", "Check Node version, config, SSH key, provider credentials, and Pulumi home"],
3154
- ["mcp", "MCP server operations (mcp serve | mcp install)"],
3303
+ ["mcp", "MCP server operations (mcp serve | mcp install | mcp wire)"],
3155
3304
  ["secret", "Manage secrets (secret list | set | delete | rotate | audit)"],
3156
3305
  ["monitor", "Live dashboard: gateway health, container status, resource usage, log tail"],
3157
3306
  ["help", "Show this help message"]
@@ -3198,31 +3347,138 @@ ${bold("Global flags:")}
3198
3347
  }
3199
3348
  process.stdout.write(`
3200
3349
  ${dim("Run `clawops <command> --help` for command-specific flags.")}
3350
+ `);
3351
+ printCta();
3352
+ }
3353
+ });
3201
3354
 
3355
+ // src/cli/commands/bug.ts
3356
+ import { defineCommand as defineCommand21 } from "citty";
3357
+ import process22 from "process";
3358
+ import { accessSync as accessSync2, constants as constants2 } from "fs";
3359
+ import { execSync as execSync2 } from "child_process";
3360
+ var ISSUES_URL = `${REPO_URL}/issues/new`;
3361
+ var BODY_CAP = 2e3;
3362
+ var VERSION = true ? "1.6.0" : "dev";
3363
+ async function collectContext() {
3364
+ const nodeVersion = process22.version;
3365
+ const os3 = `${process22.platform} ${process22.arch}`;
3366
+ let provider = "unknown";
3367
+ let stackCount = 0;
3368
+ let sshKey = "unknown";
3369
+ try {
3370
+ const { getConfig: getConfig2 } = await import("./store-SDUR52Z5.js");
3371
+ const config = getConfig2();
3372
+ if (config) {
3373
+ const stacks = Object.values(config.stacks);
3374
+ stackCount = stacks.length;
3375
+ provider = stacks[0]?.provider ?? "none";
3376
+ const keyPath = config.ssh.keyPath.replace(/^~/, process22.env["HOME"] ?? "~");
3377
+ try {
3378
+ accessSync2(keyPath, constants2.R_OK);
3379
+ sshKey = "present";
3380
+ } catch {
3381
+ sshKey = "missing";
3382
+ }
3383
+ } else {
3384
+ provider = "not configured";
3385
+ sshKey = "not configured";
3386
+ }
3387
+ } catch {
3388
+ }
3389
+ return [
3390
+ `**clawops version:** ${VERSION}`,
3391
+ `**Node:** ${nodeVersion}`,
3392
+ `**OS:** ${os3}`,
3393
+ `**Provider:** ${provider}`,
3394
+ `**Stacks:** ${stackCount}`,
3395
+ `**SSH key:** ${sshKey}`
3396
+ ].join("\n");
3397
+ }
3398
+ function buildIssueUrl(title, command, context) {
3399
+ const body = [
3400
+ context,
3401
+ "",
3402
+ "**Description:**",
3403
+ title,
3404
+ "",
3405
+ command ? `**Command:**
3406
+ \`${command}\`` : "",
3407
+ "",
3408
+ "**Steps to reproduce:**",
3409
+ "<!-- Please describe what you did -->\n"
3410
+ ].filter((l) => l !== void 0).join("\n").slice(0, BODY_CAP);
3411
+ const params = new URLSearchParams({ title, body });
3412
+ return `${ISSUES_URL}?${params.toString()}`;
3413
+ }
3414
+ function openBrowser2(url) {
3415
+ try {
3416
+ const cmd = process22.platform === "darwin" ? "open" : "xdg-open";
3417
+ execSync2(`${cmd} "${url}"`, { stdio: "ignore" });
3418
+ return true;
3419
+ } catch {
3420
+ return false;
3421
+ }
3422
+ }
3423
+ var bug_default = defineCommand21({
3424
+ meta: {
3425
+ name: "bug",
3426
+ description: "Open a pre-filled GitHub issue with system context from clawops doctor"
3427
+ },
3428
+ args: {
3429
+ json: { type: "boolean", description: "Emit issue URL as JSON without opening a browser" }
3430
+ },
3431
+ async run({ args }) {
3432
+ const context = await collectContext();
3433
+ let title = "";
3434
+ let command = "";
3435
+ if (!args.json) {
3436
+ const { createInterface: createInterface3 } = await import("readline/promises");
3437
+ const rl = createInterface3({ input: process22.stdin, output: process22.stdout });
3438
+ try {
3439
+ title = (await rl.question("Describe the issue in one line: ")).trim();
3440
+ command = (await rl.question("Which command triggered it? (optional): ")).trim();
3441
+ } finally {
3442
+ rl.close();
3443
+ }
3444
+ }
3445
+ const url = buildIssueUrl(title, command, context);
3446
+ if (args.json) {
3447
+ printJson(jsonOk({ url }));
3448
+ return;
3449
+ }
3450
+ process22.stdout.write("\n");
3451
+ info(`Opening: ${url}`);
3452
+ process22.stdout.write("\n");
3453
+ const opened = openBrowser2(url);
3454
+ if (!opened) {
3455
+ process22.stdout.write(`Open this URL to file the issue:
3456
+ ${url}
3202
3457
  `);
3458
+ }
3203
3459
  }
3204
3460
  });
3205
3461
 
3206
3462
  // src/cli/error-handler.ts
3207
- import process22 from "process";
3463
+ import process23 from "process";
3208
3464
  function handleError(err) {
3209
3465
  if (err instanceof ClawopsError) {
3210
3466
  failure(err.message);
3211
- process22.exit(err.exitCode);
3467
+ process23.exit(err.exitCode);
3212
3468
  }
3213
3469
  if (err instanceof Error) {
3214
3470
  failure(`Unexpected error: ${err.message}`);
3215
- if (process22.env["DEBUG"]) {
3216
- process22.stderr.write(err.stack ?? "\n");
3471
+ if (process23.env["DEBUG"]) {
3472
+ process23.stderr.write(err.stack ?? "\n");
3217
3473
  }
3218
- process22.exit(1);
3474
+ process23.exit(1);
3219
3475
  }
3220
3476
  failure(`Unknown error: ${String(err)}`);
3221
- process22.exit(1);
3477
+ process23.exit(1);
3222
3478
  }
3223
3479
 
3224
3480
  // src/cli/index.ts
3225
- var main = defineCommand21({
3481
+ var main = defineCommand22({
3226
3482
  meta: {
3227
3483
  name: "clawops",
3228
3484
  description: "Deploy and manage self-hosted OpenClaw instances across clouds",
@@ -3258,7 +3514,8 @@ var main = defineCommand21({
3258
3514
  setup: setup_default,
3259
3515
  secret: secret_default,
3260
3516
  monitor: monitor_default,
3261
- help: help_default
3517
+ help: help_default,
3518
+ bug: bug_default
3262
3519
  }
3263
3520
  });
3264
3521
  try {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildContext
4
- } from "./chunk-T5EX55GP.js";
4
+ } from "./chunk-QI75OVJK.js";
5
5
  import "./chunk-A2I76FTA.js";
6
6
  import "./chunk-CX5SL5HP.js";
7
7
  import "./chunk-KGXPLI7W.js";
File without changes