@clawops/cli 1.3.0 → 1.5.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 +136 -0
  2. package/dist/{apply-DLNE2JYZ.js → apply-5RREMN3L.js} +3 -3
  3. package/dist/automation-RULUSJBW.js +0 -0
  4. package/dist/{aws-KQBWY43W.js → aws-FRE2JVAZ.js} +9 -4
  5. package/dist/{azure-4EJFVJZL.js → azure-PVC3AQVC.js} +11 -4
  6. package/dist/bootstrap-G4UZ2FKH.js +0 -0
  7. package/dist/chunk-3QJBNAHW.js +0 -0
  8. package/dist/chunk-4U3LTLWZ.js +0 -0
  9. package/dist/chunk-6ZFIFDBJ.js +0 -0
  10. package/dist/chunk-A2I76FTA.js +0 -0
  11. package/dist/chunk-BOPSG2LI.js +0 -0
  12. package/dist/chunk-CX5SL5HP.js +0 -0
  13. package/dist/{chunk-ZDPBBYYV.js → chunk-IVX62LFO.js} +2 -2
  14. package/dist/chunk-KGXPLI7W.js +0 -0
  15. package/dist/chunk-OIGTOLB3.js +0 -0
  16. package/dist/chunk-R5S6IXBE.js +771 -0
  17. package/dist/{chunk-JDN6PLH2.js → chunk-T5EX55GP.js} +3 -3
  18. package/dist/chunk-YTH4L2GN.js +0 -0
  19. package/dist/{chunk-UDNZUSKA.js → chunk-ZFNPM2WG.js} +1 -1
  20. package/dist/{chunk-JCUZU5BH.js → chunk-ZONXY3C6.js} +2 -2
  21. package/dist/chunk-ZVOEQCNW.js +0 -0
  22. package/dist/cli.js +207 -53
  23. package/dist/{context-M2RMDHX6.js → context-PSGEX2D7.js} +1 -1
  24. package/dist/errors-OK47MQFD.js +0 -0
  25. package/dist/firewall-YYDOWDDP.js +0 -0
  26. package/dist/{gcp-SKURG3L6.js → gcp-BXDTC6EK.js} +60 -17
  27. package/dist/{generate-U7PJ5LRG.js → generate-2QGKYR42.js} +2 -2
  28. package/dist/js-yaml-PTEEG4FO.js +0 -0
  29. package/dist/local-DXBEVZ5C.js +0 -0
  30. package/dist/mcp-apps-KY44ED3Y.js +0 -0
  31. package/dist/mcp-wire-ZWIYMLEW.js +45 -0
  32. package/dist/outputs-DJHBY7EE.js +0 -0
  33. package/dist/overlay-store-ADZPD7EU.js +0 -0
  34. package/dist/{package-AFUTH62F.js → package-QLDA65A3.js} +2 -1
  35. package/dist/pool-FBFHATDG.js +0 -0
  36. package/dist/providers-2OABPW2E.js +0 -0
  37. package/dist/{remote-config-JQ77SRC2.js → remote-config-QF5TT7GU.js} +1 -1
  38. package/dist/secrets-SVZWNAPK.js +0 -0
  39. package/dist/{server-I62UES5V.js → server-LOL2NUJ2.js} +92 -19
  40. package/dist/ssh-IQXNME3D.js +0 -0
  41. package/dist/state-PRBIIN7I.js +0 -0
  42. package/dist/store-SDUR52Z5.js +0 -0
  43. package/dist/validate-T5M5EHSJ.js +0 -0
  44. package/package.json +27 -14
  45. package/dist/chunk-LVIIYY27.js +0 -266
@@ -56,17 +56,17 @@ function makeProviderProxy(name) {
56
56
  if (resolved) return resolved;
57
57
  switch (name) {
58
58
  case "gcp": {
59
- const mod = await import("./gcp-SKURG3L6.js");
59
+ const mod = await import("./gcp-BXDTC6EK.js");
60
60
  resolved = mod.default;
61
61
  return resolved;
62
62
  }
63
63
  case "aws": {
64
- const mod = await import("./aws-KQBWY43W.js");
64
+ const mod = await import("./aws-FRE2JVAZ.js");
65
65
  resolved = mod.default;
66
66
  return resolved;
67
67
  }
68
68
  case "azure": {
69
- const mod = await import("./azure-4EJFVJZL.js");
69
+ const mod = await import("./azure-PVC3AQVC.js");
70
70
  resolved = mod.default;
71
71
  return resolved;
72
72
  }
File without changes
@@ -20,7 +20,7 @@ async function execWithFallbackSudo(session, cmd, signal) {
20
20
  async function readRemoteConfig(session, signal) {
21
21
  const os = await detectOS(session, signal);
22
22
  const configPath = configPathForOS(os);
23
- const result = await session.exec(`cat ${configPath}`, signal);
23
+ const result = os === "Darwin" ? await session.exec(`cat ${configPath}`, signal) : await execWithFallbackSudo(session, `cat ${configPath}`, signal);
24
24
  if (result.code !== 0) {
25
25
  throw new Error(`Cannot read ${configPath}: ${result.stderr}`);
26
26
  }
@@ -10,13 +10,13 @@ import {
10
10
  } from "./chunk-BOPSG2LI.js";
11
11
  import {
12
12
  buildContext
13
- } from "./chunk-JDN6PLH2.js";
13
+ } from "./chunk-T5EX55GP.js";
14
14
  import {
15
15
  atomicWriteConfig,
16
16
  deepMerge,
17
17
  readRemoteConfig,
18
18
  restartGateway
19
- } from "./chunk-UDNZUSKA.js";
19
+ } from "./chunk-ZFNPM2WG.js";
20
20
  import {
21
21
  UsageError
22
22
  } from "./chunk-KGXPLI7W.js";
File without changes
package/dist/cli.js CHANGED
@@ -5,12 +5,20 @@ import {
5
5
  writeAppConfigs
6
6
  } from "./chunk-OIGTOLB3.js";
7
7
  import {
8
- validateOpenclawConfig
9
- } from "./chunk-LVIIYY27.js";
10
- import "./chunk-JDN6PLH2.js";
8
+ chalk,
9
+ failure,
10
+ info,
11
+ monitor_default,
12
+ printCta,
13
+ spinner,
14
+ success,
15
+ validateOpenclawConfig,
16
+ warn
17
+ } from "./chunk-R5S6IXBE.js";
18
+ import "./chunk-T5EX55GP.js";
11
19
  import "./chunk-ZVOEQCNW.js";
12
20
  import "./chunk-4U3LTLWZ.js";
13
- import "./chunk-UDNZUSKA.js";
21
+ import "./chunk-ZFNPM2WG.js";
14
22
  import "./chunk-A2I76FTA.js";
15
23
  import {
16
24
  getConfig,
@@ -32,27 +40,6 @@ import { generateKeyPairSync } from "crypto";
32
40
  import { writeFileSync, mkdirSync, existsSync } from "fs";
33
41
  import path from "path";
34
42
  import process2 from "process";
35
-
36
- // src/output/human.ts
37
- import chalk from "chalk";
38
- import ora from "ora";
39
- function success(msg) {
40
- console.log(chalk.green("\u2713") + " " + msg);
41
- }
42
- function failure(msg) {
43
- console.error(chalk.red("\u2717") + " " + msg);
44
- }
45
- function warn(msg) {
46
- console.warn(chalk.yellow("\u26A0") + " " + msg);
47
- }
48
- function info(msg) {
49
- console.log(chalk.blue("\u2139") + " " + msg);
50
- }
51
- function spinner(text) {
52
- return ora(text).start();
53
- }
54
-
55
- // src/cli/commands/init.ts
56
43
  var SUPPORTED_PROVIDERS = ["gcp", "aws", "azure", "local"];
57
44
  var PROVIDER_DEFAULTS = {
58
45
  gcp: { region: "us-central1", credEnv: "GOOGLE_APPLICATION_CREDENTIALS", stateScheme: "gs://" },
@@ -217,7 +204,7 @@ var up_default = defineCommand2({
217
204
  config: { type: "string", description: "Path to openclaw config overlay JSON (local provider only)" }
218
205
  },
219
206
  async run({ args }) {
220
- const { buildContext } = await import("./context-M2RMDHX6.js");
207
+ const { buildContext } = await import("./context-PSGEX2D7.js");
221
208
  const ctx = buildContext(args);
222
209
  const openclawVersion = typeof args["openclaw-version"] === "string" ? args["openclaw-version"] : "stable";
223
210
  if (ctx.adapter.name === "local") {
@@ -323,7 +310,7 @@ var up_default = defineCommand2({
323
310
  async function applyLocalConfigOverlay(opts) {
324
311
  const { connect } = await import("./ssh-IQXNME3D.js");
325
312
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
326
- const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-JQ77SRC2.js");
313
+ const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
327
314
  let overlay;
328
315
  try {
329
316
  overlay = JSON.parse(readFileSync(opts.configPath, "utf-8"));
@@ -363,7 +350,7 @@ var down_default = defineCommand3({
363
350
  "dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
364
351
  },
365
352
  async run({ args }) {
366
- const { buildContext } = await import("./context-M2RMDHX6.js");
353
+ const { buildContext } = await import("./context-PSGEX2D7.js");
367
354
  const ctx = buildContext(args);
368
355
  if (args["dry-run"]) {
369
356
  info(`Dry run \u2014 would destroy stack "${ctx.stackName}"`);
@@ -427,7 +414,7 @@ var status_default = defineCommand4({
427
414
  json: { type: "boolean", description: "Emit JSON" }
428
415
  },
429
416
  async run({ args }) {
430
- const { buildContext } = await import("./context-M2RMDHX6.js");
417
+ const { buildContext } = await import("./context-PSGEX2D7.js");
431
418
  const ctx = buildContext(args);
432
419
  if (ctx.adapter.name === "local") {
433
420
  const state = ctx.localState;
@@ -499,8 +486,8 @@ var plan_default = defineCommand5({
499
486
  out: { type: "string", description: "Write plan JSON to this absolute path (default: stdout)" }
500
487
  },
501
488
  async run({ args }) {
502
- const { buildContext } = await import("./context-M2RMDHX6.js");
503
- const { generatePlan } = await import("./generate-U7PJ5LRG.js");
489
+ const { buildContext } = await import("./context-PSGEX2D7.js");
490
+ const { generatePlan } = await import("./generate-2QGKYR42.js");
504
491
  const ctx = buildContext(args);
505
492
  if (ctx.adapter.name === "local") {
506
493
  throw new UsageError(
@@ -590,7 +577,7 @@ var apply_default = defineCommand6({
590
577
  },
591
578
  async run({ args }) {
592
579
  const { validatePlan } = await import("./validate-T5M5EHSJ.js");
593
- const { applyPlan } = await import("./apply-DLNE2JYZ.js");
580
+ const { applyPlan } = await import("./apply-5RREMN3L.js");
594
581
  const planPath = args._?.[0];
595
582
  if (!planPath) {
596
583
  throw new UsageError("Usage: clawops apply <plan.json>");
@@ -706,7 +693,7 @@ var destroy_default = defineCommand7({
706
693
  "dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
707
694
  },
708
695
  async run({ args }) {
709
- const { buildContext } = await import("./context-M2RMDHX6.js");
696
+ const { buildContext } = await import("./context-PSGEX2D7.js");
710
697
  const ctx = buildContext(args);
711
698
  if (ctx.adapter.name === "local") {
712
699
  throw new UsageError(
@@ -773,7 +760,7 @@ var ssh_default = defineCommand8({
773
760
  command: { type: "string", description: "Remote command to run (instead of interactive shell)" }
774
761
  },
775
762
  async run({ args }) {
776
- const { buildContext } = await import("./context-M2RMDHX6.js");
763
+ const { buildContext } = await import("./context-PSGEX2D7.js");
777
764
  const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
778
765
  const ctx = buildContext(args);
779
766
  let conn;
@@ -860,7 +847,7 @@ var tunnel_default = defineCommand9({
860
847
  "no-open": { type: "boolean", description: "Do not open browser after tunnel is ready" }
861
848
  },
862
849
  async run({ args }) {
863
- const { buildContext } = await import("./context-M2RMDHX6.js");
850
+ const { buildContext } = await import("./context-PSGEX2D7.js");
864
851
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
865
852
  const { acquireSession } = await import("./pool-FBFHATDG.js");
866
853
  const ctx = buildContext(args);
@@ -928,7 +915,7 @@ var logs_default = defineCommand10({
928
915
  since: { type: "string", description: "Show logs since duration (e.g. 5m, 1h)" }
929
916
  },
930
917
  async run({ args }) {
931
- const { buildContext } = await import("./context-M2RMDHX6.js");
918
+ const { buildContext } = await import("./context-PSGEX2D7.js");
932
919
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
933
920
  const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
934
921
  const ctx = buildContext(args);
@@ -1045,7 +1032,7 @@ var config_default = defineCommand11({
1045
1032
  "dry-run": { type: "boolean", description: "Show what would change without writing" }
1046
1033
  },
1047
1034
  async run({ args }) {
1048
- const { buildContext } = await import("./context-M2RMDHX6.js");
1035
+ const { buildContext } = await import("./context-PSGEX2D7.js");
1049
1036
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1050
1037
  const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1051
1038
  const [action, key, value] = args._ ?? [];
@@ -1171,7 +1158,7 @@ var agents_default = defineCommand12({
1171
1158
  json: { type: "boolean", description: "Emit JSON (for list)" }
1172
1159
  },
1173
1160
  async run({ args }) {
1174
- const { buildContext } = await import("./context-M2RMDHX6.js");
1161
+ const { buildContext } = await import("./context-PSGEX2D7.js");
1175
1162
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1176
1163
  const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1177
1164
  const [action, name] = args._ ?? [];
@@ -1275,7 +1262,7 @@ var gateway_default = defineCommand13({
1275
1262
  json: { type: "boolean", description: "Emit JSON (for status)" }
1276
1263
  },
1277
1264
  async run({ args }) {
1278
- const { buildContext } = await import("./context-M2RMDHX6.js");
1265
+ const { buildContext } = await import("./context-PSGEX2D7.js");
1279
1266
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1280
1267
  const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1281
1268
  const [action, versionArg] = args._ ?? [];
@@ -1388,7 +1375,7 @@ var backup_default = defineCommand14({
1388
1375
  yes: { type: "boolean", description: "[restore] Skip confirmation prompt" }
1389
1376
  },
1390
1377
  async run({ args }) {
1391
- const { buildContext } = await import("./context-M2RMDHX6.js");
1378
+ const { buildContext } = await import("./context-PSGEX2D7.js");
1392
1379
  const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1393
1380
  const action = args.action;
1394
1381
  if (action !== "create" && action !== "restore") {
@@ -1500,7 +1487,7 @@ var stacks_default = defineCommand15({
1500
1487
  args: {
1501
1488
  json: { type: "boolean", description: "Emit JSON (for list)" },
1502
1489
  yes: { type: "boolean", description: "Skip confirmation prompt on delete" },
1503
- force: { type: "boolean", description: "Allow deleting the default stack" }
1490
+ force: { type: "boolean", description: "Skip safety checks (allow deleting default or still-deployed stacks)" }
1504
1491
  },
1505
1492
  async run({ args }) {
1506
1493
  const [action, name] = args._ ?? [];
@@ -1558,6 +1545,31 @@ var stacks_default = defineCommand15({
1558
1545
  `"${name}" is the default stack. Use --force to delete it (clawops will switch the default to another stack).`
1559
1546
  );
1560
1547
  }
1548
+ let isDeployed = false;
1549
+ if (!args.force) {
1550
+ try {
1551
+ const { buildContext } = await import("./context-PSGEX2D7.js");
1552
+ const ctx = buildContext({ stack: name });
1553
+ if (ctx.adapter.name === "local") {
1554
+ isDeployed = !!ctx.localState;
1555
+ } else {
1556
+ const stack = await ctx.getStack();
1557
+ const outputMap = await stack.outputs();
1558
+ const outputs = Object.fromEntries(
1559
+ Object.entries(outputMap).map(([k, v]) => [k, v.value])
1560
+ );
1561
+ isDeployed = !!outputs["publicIp"];
1562
+ }
1563
+ } catch {
1564
+ warn(`Could not verify deployment status for "${name}" \u2014 proceeding anyway.`);
1565
+ }
1566
+ }
1567
+ if (isDeployed) {
1568
+ failure(
1569
+ `Stack "${name}" is still deployed. Run \`clawops down --stack ${name}\` first to destroy cloud resources, or pass --force to remove from registry only.`
1570
+ );
1571
+ process17.exit(1);
1572
+ }
1561
1573
  warn(
1562
1574
  `This removes "${name}" from clawops config only. Cloud resources are NOT destroyed. Run \`clawops destroy --stack ` + name + "` first if you want to remove cloud resources."
1563
1575
  );
@@ -1657,9 +1669,9 @@ var doctor_default = defineCommand16({
1657
1669
  info("Credential checks skipped \u2014 no config");
1658
1670
  } else {
1659
1671
  const { getProvider } = await import("./providers-2OABPW2E.js");
1660
- await import("./aws-KQBWY43W.js");
1661
- await import("./gcp-SKURG3L6.js");
1662
- await import("./azure-4EJFVJZL.js");
1672
+ await import("./aws-FRE2JVAZ.js");
1673
+ await import("./gcp-BXDTC6EK.js");
1674
+ await import("./azure-PVC3AQVC.js");
1663
1675
  await import("./local-DXBEVZ5C.js");
1664
1676
  const checkedProviders = /* @__PURE__ */ new Set();
1665
1677
  for (const [stackName, stackCfg] of Object.entries(config.stacks)) {
@@ -1694,7 +1706,7 @@ var doctor_default = defineCommand16({
1694
1706
  info("Remote health skipped \u2014 no config");
1695
1707
  } else {
1696
1708
  try {
1697
- const { buildContext } = await import("./context-M2RMDHX6.js");
1709
+ const { buildContext } = await import("./context-PSGEX2D7.js");
1698
1710
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1699
1711
  const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1700
1712
  const ctx = buildContext({ stack: args.stack });
@@ -1802,7 +1814,7 @@ var serveCmd = defineCommand17({
1802
1814
  inspector: { type: "boolean", description: "Enable MCP inspector" }
1803
1815
  },
1804
1816
  async run({ args }) {
1805
- const { serveMcp } = await import("./server-I62UES5V.js");
1817
+ const { serveMcp } = await import("./server-LOL2NUJ2.js");
1806
1818
  await serveMcp({
1807
1819
  port: args.http ? Number(args.http) : void 0,
1808
1820
  bind: args.bind,
@@ -1867,6 +1879,85 @@ var installCmd = defineCommand17({
1867
1879
  }
1868
1880
  }
1869
1881
  });
1882
+ var wireCmd = defineCommand17({
1883
+ meta: {
1884
+ name: "wire",
1885
+ description: "Wire the gateway AI as an MCP client of clawops (WO-28)"
1886
+ },
1887
+ args: {
1888
+ stack: { type: "string", description: "Target stack name" },
1889
+ force: { type: "boolean", description: "Apply even if gateway version is below minimum" }
1890
+ },
1891
+ async run({ args }) {
1892
+ const { buildContext } = await import("./context-PSGEX2D7.js");
1893
+ const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1894
+ const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1895
+ const { wireGatewayMcp } = await import("./mcp-wire-ZWIYMLEW.js");
1896
+ const ac = new AbortController();
1897
+ process19.on("SIGINT", () => {
1898
+ ac.abort();
1899
+ process19.exit(130);
1900
+ });
1901
+ process19.on("SIGTERM", () => {
1902
+ ac.abort();
1903
+ process19.exit(143);
1904
+ });
1905
+ const ctx = buildContext({ stack: args.stack });
1906
+ let conn;
1907
+ if (ctx.adapter.name === "local") {
1908
+ if (!ctx.localState) {
1909
+ failure("Stack is not deployed. Run `clawops up` first.");
1910
+ process19.exit(1);
1911
+ }
1912
+ const ls = ctx.localState;
1913
+ conn = { host: ls.sshHost, port: ls.sshPort, user: ls.sshUser, privateKeyPath: ls.privateKeyPath, knownHostsPath: ls.knownHostsPath };
1914
+ } else {
1915
+ const stack = await ctx.getStack();
1916
+ const outputMap = await stack.outputs();
1917
+ const outputs = Object.fromEntries(
1918
+ Object.entries(outputMap).map(([k, v]) => [k, v.value])
1919
+ );
1920
+ if (!outputs["publicIp"]) {
1921
+ failure("Stack has no outputs. Run `clawops up` first.");
1922
+ process19.exit(1);
1923
+ }
1924
+ const base = extractBaseOutputs(outputs);
1925
+ conn = {
1926
+ host: base.publicIp,
1927
+ port: base.sshPort ?? 22,
1928
+ user: base.sshUser ?? "ubuntu",
1929
+ privateKeyPath: ctx.config.ssh.keyPath,
1930
+ knownHostsPath: ctx.config.ssh.knownHostsPath
1931
+ };
1932
+ }
1933
+ const spin = spinner(`Connecting to ${conn.host}...`);
1934
+ const { session, release } = await acquireSession({ ...conn, signal: ac.signal });
1935
+ try {
1936
+ spin.text = "Reading gateway config...";
1937
+ const result = await wireGatewayMcp(session, ac.signal, { force: Boolean(args.force) });
1938
+ if (result.status === "version-blocked") {
1939
+ spin.fail("Gateway version is too old for MCP client support.");
1940
+ warn(`Gateway version ${result.version} requires at least 2026.4 for MCP client support.`);
1941
+ info("Upgrade OpenClaw and re-run, or bypass with: clawops mcp wire --force");
1942
+ process19.exit(1);
1943
+ }
1944
+ if (result.rewired) {
1945
+ spin.succeed("Re-wiring clawops MCP client \u2014 previous entry replaced.");
1946
+ } else {
1947
+ spin.succeed("Gateway MCP client wired.");
1948
+ }
1949
+ success("The gateway's AI can now run clawops commands.");
1950
+ info('Try asking it: "check if my stack is healthy"');
1951
+ } catch (err) {
1952
+ spin.fail("Failed to wire gateway MCP client.");
1953
+ failure(err instanceof Error ? err.message : String(err));
1954
+ process19.exit(1);
1955
+ } finally {
1956
+ release();
1957
+ drainPool();
1958
+ }
1959
+ }
1960
+ });
1870
1961
  var mcp_default = defineCommand17({
1871
1962
  meta: {
1872
1963
  name: "mcp",
@@ -1875,7 +1966,8 @@ var mcp_default = defineCommand17({
1875
1966
  args: {},
1876
1967
  subCommands: {
1877
1968
  serve: serveCmd,
1878
- install: installCmd
1969
+ install: installCmd,
1970
+ wire: wireCmd
1879
1971
  }
1880
1972
  });
1881
1973
 
@@ -2285,6 +2377,15 @@ var setup_default = defineCommand18({
2285
2377
  signal: ac.signal,
2286
2378
  inquirer
2287
2379
  });
2380
+ await maybeWireGatewayMcp({
2381
+ stackName: stackAnswers.stackName,
2382
+ host: localHost,
2383
+ port: localPort,
2384
+ user: localUser,
2385
+ keyPath: localKeyPath,
2386
+ signal: ac.signal,
2387
+ inquirer
2388
+ });
2288
2389
  } else {
2289
2390
  const { getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
2290
2391
  const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
@@ -2303,7 +2404,7 @@ var setup_default = defineCommand18({
2303
2404
  default: false
2304
2405
  }]);
2305
2406
  if (applyNow) {
2306
- const { applyPlan } = await import("./apply-DLNE2JYZ.js");
2407
+ const { applyPlan } = await import("./apply-5RREMN3L.js");
2307
2408
  const plan = JSON.parse(readFileSync3(outputPath, "utf-8"));
2308
2409
  try {
2309
2410
  await applyPlan(plan, {
@@ -2316,6 +2417,7 @@ var setup_default = defineCommand18({
2316
2417
  failure(err instanceof Error ? err.message : String(err));
2317
2418
  process20.exit(1);
2318
2419
  }
2420
+ await maybeWireGatewayMcpCloud({ stackName: stackAnswers.stackName, signal: ac.signal, inquirer });
2319
2421
  } else {
2320
2422
  info(`
2321
2423
  To deploy later: clawops apply ${outputPath}`);
@@ -2327,7 +2429,7 @@ async function runLocalDeploy(opts) {
2327
2429
  const { setConfig: setConfig2, getConfig: getConfig2, getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
2328
2430
  const { localBootstrap } = await import("./bootstrap-G4UZ2FKH.js");
2329
2431
  const { connect } = await import("./ssh-IQXNME3D.js");
2330
- const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-JQ77SRC2.js");
2432
+ const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
2331
2433
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
2332
2434
  const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
2333
2435
  const existing = getConfig2();
@@ -2420,6 +2522,7 @@ async function runLocalDeploy(opts) {
2420
2522
  info(`Token saved to ${tokenPath}`);
2421
2523
  info(`
2422
2524
  Run clawops doctor --stack ${opts.stackName} to check everything is healthy`);
2525
+ printCta();
2423
2526
  }
2424
2527
  var CLOUD_AUTH = {
2425
2528
  aws: {
@@ -2792,6 +2895,55 @@ function printMcpSnippet() {
2792
2895
  }
2793
2896
  }, null, 2) + "\n\n");
2794
2897
  }
2898
+ async function maybeWireGatewayMcp(opts) {
2899
+ process20.stdout.write("\n");
2900
+ const { wireGateway } = await inquirerPromptWire(opts.inquirer);
2901
+ if (!wireGateway) return;
2902
+ const { connect } = await import("./ssh-IQXNME3D.js");
2903
+ const { getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
2904
+ const { wireGatewayMcp } = await import("./mcp-wire-ZWIYMLEW.js");
2905
+ const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
2906
+ const spin = spinner("Wiring gateway MCP client...");
2907
+ const session = await connect({
2908
+ host: opts.host,
2909
+ port: opts.port,
2910
+ user: opts.user,
2911
+ privateKeyPath: opts.keyPath,
2912
+ knownHostsPath,
2913
+ signal: opts.signal
2914
+ });
2915
+ try {
2916
+ const result = await wireGatewayMcp(session, opts.signal ?? AbortSignal.timeout(3e4));
2917
+ if (result.status === "version-blocked") {
2918
+ spin.warn(`Gateway version ${result.version} is too old for MCP client support (requires \u2265 2026.4).`);
2919
+ info("Upgrade OpenClaw and run: clawops mcp wire --stack " + opts.stackName);
2920
+ } else {
2921
+ spin.succeed(result.rewired ? "Gateway MCP client re-wired." : "Gateway MCP client wired.");
2922
+ success("The gateway's AI can now run clawops commands.");
2923
+ info('Try asking it: "check if my stack is healthy"');
2924
+ }
2925
+ } catch (err) {
2926
+ spin.fail("Failed to wire gateway MCP client.");
2927
+ failure(err instanceof Error ? err.message : String(err));
2928
+ info("You can retry later: clawops mcp wire --stack " + opts.stackName);
2929
+ } finally {
2930
+ session.close();
2931
+ }
2932
+ }
2933
+ async function maybeWireGatewayMcpCloud(opts) {
2934
+ process20.stdout.write("\n");
2935
+ const { wireGateway } = await inquirerPromptWire(opts.inquirer);
2936
+ if (!wireGateway) return;
2937
+ info(`Run this after the server is ready: clawops mcp wire --stack ${opts.stackName}`);
2938
+ }
2939
+ async function inquirerPromptWire(inquirer) {
2940
+ return inquirer.prompt([{
2941
+ type: "confirm",
2942
+ name: "wireGateway",
2943
+ message: "Should the OpenClaw gateway's AI also be able to manage this stack? (adds clawops MCP client to gateway)",
2944
+ default: false
2945
+ }]);
2946
+ }
2795
2947
  function loadCatalogs(yaml) {
2796
2948
  const specDir = path3.join(path3.dirname(fileURLToPath(import.meta.url)), "../../../spec");
2797
2949
  try {
@@ -3012,8 +3164,8 @@ var rotateCmd = defineCommand19({
3012
3164
  }
3013
3165
  info(`Re-applying config overlay to stack "${targetStack}"\u2026`);
3014
3166
  try {
3015
- const { buildContext } = await import("./context-M2RMDHX6.js");
3016
- const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-JQ77SRC2.js");
3167
+ const { buildContext } = await import("./context-PSGEX2D7.js");
3168
+ const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
3017
3169
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
3018
3170
  const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
3019
3171
  const { localStateToConnectionInfo } = await import("./state-PRBIIN7I.js");
@@ -3140,8 +3292,9 @@ var COMMANDS = [
3140
3292
  ["backup", "Create or restore an OpenClaw state backup"],
3141
3293
  ["stacks", "List named stacks and their state"],
3142
3294
  ["doctor", "Check Node version, config, SSH key, provider credentials, and Pulumi home"],
3143
- ["mcp", "MCP server operations (mcp serve | mcp install)"],
3295
+ ["mcp", "MCP server operations (mcp serve | mcp install | mcp wire)"],
3144
3296
  ["secret", "Manage secrets (secret list | set | delete | rotate | audit)"],
3297
+ ["monitor", "Live dashboard: gateway health, container status, resource usage, log tail"],
3145
3298
  ["help", "Show this help message"]
3146
3299
  ];
3147
3300
  var GLOBAL_FLAGS = [
@@ -3186,8 +3339,8 @@ ${bold("Global flags:")}
3186
3339
  }
3187
3340
  process.stdout.write(`
3188
3341
  ${dim("Run `clawops <command> --help` for command-specific flags.")}
3189
-
3190
3342
  `);
3343
+ printCta();
3191
3344
  }
3192
3345
  });
3193
3346
 
@@ -3245,6 +3398,7 @@ var main = defineCommand21({
3245
3398
  mcp: mcp_default,
3246
3399
  setup: setup_default,
3247
3400
  secret: secret_default,
3401
+ monitor: monitor_default,
3248
3402
  help: help_default
3249
3403
  }
3250
3404
  });
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildContext
4
- } from "./chunk-JDN6PLH2.js";
4
+ } from "./chunk-T5EX55GP.js";
5
5
  import "./chunk-A2I76FTA.js";
6
6
  import "./chunk-CX5SL5HP.js";
7
7
  import "./chunk-KGXPLI7W.js";
File without changes
File without changes