@clawops/cli 1.7.8 → 2.0.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 (57) hide show
  1. package/README.md +412 -70
  2. package/dist/{apply-F3KY2HTB.js → apply-AM5HERE7.js} +8 -6
  3. package/dist/{aws-L4RR2LSE.js → aws-AMON7DA7.js} +20 -9
  4. package/dist/{azure-7OXQENQL.js → azure-T4G6OBJQ.js} +19 -8
  5. package/dist/{bootstrap-HL4DNUNG.js → bootstrap-DMRPWJGN.js} +28 -19
  6. package/dist/bootstrap.sh.tmpl +51 -31
  7. package/dist/channels-KBUR42IU.js +53 -0
  8. package/dist/{chunk-DQDAWNGB.js → chunk-3WYA2QDM.js} +1 -1
  9. package/dist/chunk-6TIYVHPX.js +152 -0
  10. package/dist/{chunk-3XK66DKK.js → chunk-AHAAEXWC.js} +41 -0
  11. package/dist/{chunk-QQNKBTYZ.js → chunk-AX74VXTV.js} +292 -94
  12. package/dist/{chunk-C5X375RO.js → chunk-CKSPROD5.js} +59 -15
  13. package/dist/{chunk-UKTP332Z.js → chunk-GAZPPSKU.js} +6 -7
  14. package/dist/{chunk-FNS56UQY.js → chunk-GYV4KNW7.js} +319 -252
  15. package/dist/{chunk-PVUVI35Y.js → chunk-JW5A7E3X.js} +5 -1
  16. package/dist/chunk-LT4XMO5D.js +50 -0
  17. package/dist/{chunk-P5LKWRPL.js → chunk-LU2V3LXA.js} +3 -3
  18. package/dist/chunk-N44K3LHE.js +140 -0
  19. package/dist/chunk-NUDIHZEH.js +55 -0
  20. package/dist/chunk-SBLQH2TJ.js +56 -0
  21. package/dist/chunk-UFRO4H5W.js +228 -0
  22. package/dist/{chunk-RAAONHW3.js → chunk-WHJMKDV7.js} +24 -4
  23. package/dist/chunk-YR3O2I3S.js +101 -0
  24. package/dist/cli.js +866 -577
  25. package/dist/config-validate-K2N6XLDX.js +76 -0
  26. package/dist/{context-5LCUG2QR.js → context-KHKWJJMC.js} +1 -1
  27. package/dist/{firewall-XQGO7HWK.js → firewall-T3NTPZJD.js} +10 -0
  28. package/dist/{gcp-UG6AWPIZ.js → gcp-2JBTD7ZM.js} +19 -8
  29. package/dist/{generate-ELD7QF5Z.js → generate-2XV2GSP2.js} +4 -4
  30. package/dist/{harden-URPXLSVF.js → harden-PCDK3UQ5.js} +48 -11
  31. package/dist/health-5CCOXYGG.js +11 -0
  32. package/dist/logs-P7YCKVF4.js +15 -0
  33. package/dist/{mcp-wire-ZMIVFAUC.js → mcp-wire-BFEY2Y6H.js} +23 -17
  34. package/dist/{package-QYZFN3FP.js → package-3HUW57XH.js} +3 -3
  35. package/dist/plugins-DTST3OER.js +49 -0
  36. package/dist/{pool-QGFQRMGU.js → pool-EX4ZTA5P.js} +2 -2
  37. package/dist/privileged-JFA6LLTV.js +17 -0
  38. package/dist/{remote-config-QDLN4UMG.js → remote-config-Z6IIZR3D.js} +3 -3
  39. package/dist/runtime-LZ7NA53V.js +42 -0
  40. package/dist/{server-FWTOSSZP.js → server-A5AB67GQ.js} +16 -12
  41. package/dist/spec-path-KQOOIQCA.js +9 -0
  42. package/dist/{ssh-CNJNLM3E.js → ssh-B3NZAU4I.js} +1 -1
  43. package/dist/upgrade-ULD4KFYC.js +88 -0
  44. package/dist/validate-BOQRWX4F.js +14 -0
  45. package/dist/{version-guard-VUCNZXQS.js → version-guard-GPSTCPT7.js} +3 -3
  46. package/dist/{versions-2UVAT6PQ.js → versions-W5LRQCAJ.js} +2 -2
  47. package/package.json +3 -3
  48. package/spec/deploy-plan.schema.json +114 -25
  49. package/spec/integrations.yaml +135 -28
  50. package/spec/mcp-tools.yaml +68 -35
  51. package/spec/models.yaml +9 -0
  52. package/spec/openclaw-2.0.config.schema.json +1 -0
  53. package/spec/openclaw-versions.yaml +116 -27
  54. package/dist/chunk-35WVQY3X.js +0 -122
  55. package/dist/chunk-6X45DDGH.js +0 -42
  56. package/dist/chunk-SEZMVVAS.js +0 -156
  57. package/dist/validate-CFQ4FH2T.js +0 -10
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ compareVersions
4
+ } from "./chunk-GAZPPSKU.js";
5
+ import "./chunk-JW5A7E3X.js";
6
+ import "./chunk-EI7CQQ7D.js";
7
+
8
+ // src/openclaw/config-validate.ts
9
+ var cached;
10
+ async function getValidator() {
11
+ if (cached) return cached;
12
+ const [{ default: Ajv }, { default: addFormats }, { readFileSync }, { join }, { resolveSpecDir }] = await Promise.all([
13
+ import("ajv"),
14
+ import("ajv-formats"),
15
+ import("fs"),
16
+ import("path"),
17
+ import("./spec-path-KQOOIQCA.js")
18
+ ]);
19
+ const schema = JSON.parse(
20
+ readFileSync(join(resolveSpecDir(), "openclaw-2.0.config.schema.json"), "utf-8")
21
+ );
22
+ const ajv = new Ajv({ strict: false, allErrors: true });
23
+ addFormats(ajv);
24
+ cached = ajv.compile(schema);
25
+ return cached;
26
+ }
27
+ function isUnknownKey(e) {
28
+ return e.keyword === "additionalProperties";
29
+ }
30
+ function dotPath(instancePath) {
31
+ if (!instancePath) return "(root)";
32
+ return instancePath.slice(1).split("/").map((seg) => seg.replace(/~1/g, "/").replace(/~0/g, "~")).join(".");
33
+ }
34
+ function describe(e) {
35
+ const where = dotPath(e.instancePath);
36
+ if (isUnknownKey(e)) {
37
+ const extra = e.params.additionalProperty;
38
+ return `${where}: unknown key "${extra}"`;
39
+ }
40
+ return `${where}: ${e.message ?? "invalid"}`;
41
+ }
42
+ function deploymentContractErrors(cfg) {
43
+ const errors = [];
44
+ if (cfg === null || typeof cfg !== "object") return errors;
45
+ const gateway = cfg["gateway"];
46
+ const mode = gateway !== null && typeof gateway === "object" ? gateway["mode"] : void 0;
47
+ if (mode === void 0) {
48
+ errors.push(
49
+ 'gateway.mode: required by clawops. OpenClaw treats it as optional only because --allow-unconfigured can bypass the check; clawops does not pass that flag, so a config without gateway.mode exits 78 with "Gateway start blocked". Set it to "local".'
50
+ );
51
+ }
52
+ return errors;
53
+ }
54
+ async function validateConfig(cfg, opts = {}) {
55
+ const validate = await getValidator();
56
+ const contract = deploymentContractErrors(cfg);
57
+ if (validate(cfg)) return { errors: contract, warnings: [] };
58
+ const { openclawVersion, schemaCapturedFrom } = opts;
59
+ const runtimeIsNewer = openclawVersion !== void 0 && schemaCapturedFrom !== void 0 && compareVersions(openclawVersion, schemaCapturedFrom) > 0;
60
+ const errors = [...contract];
61
+ const warnings = [];
62
+ for (const e of validate.errors ?? []) {
63
+ const text = describe(e);
64
+ if (isUnknownKey(e) && runtimeIsNewer) {
65
+ warnings.push(
66
+ `${text} \u2014 not in the schema captured from OpenClaw ${schemaCapturedFrom}; you are deploying ${openclawVersion}, so this may be a newer setting clawops does not know about yet.`
67
+ );
68
+ } else {
69
+ errors.push(text);
70
+ }
71
+ }
72
+ return { errors, warnings };
73
+ }
74
+ export {
75
+ validateConfig
76
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildContext
4
- } from "./chunk-P5LKWRPL.js";
4
+ } from "./chunk-LU2V3LXA.js";
5
5
  import "./chunk-A2I76FTA.js";
6
6
  import "./chunk-CX5SL5HP.js";
7
7
  import "./chunk-KGXPLI7W.js";
@@ -45,7 +45,17 @@ async function detectEgressIp(checkUrl) {
45
45
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
46
46
  }
47
47
  }
48
+ function resolveGatewayIngressCidrs(publishGateway, accessMode, allowedCidrs, portOverride, egressResult) {
49
+ if (publishGateway !== "all") return [];
50
+ return resolveIngressCidrs(accessMode, allowedCidrs, portOverride, egressResult);
51
+ }
52
+ function resolveGatewayPort(raw, fallback) {
53
+ const port = Number(raw);
54
+ return Number.isInteger(port) && port > 0 && port < 65536 ? port : fallback;
55
+ }
48
56
  export {
49
57
  detectEgressIp,
58
+ resolveGatewayIngressCidrs,
59
+ resolveGatewayPort,
50
60
  resolveIngressCidrs
51
61
  };
@@ -1,24 +1,29 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  makeStartupScript
4
- } from "./chunk-C5X375RO.js";
4
+ } from "./chunk-CKSPROD5.js";
5
+ import {
6
+ GATEWAY_PORT
7
+ } from "./chunk-6TIYVHPX.js";
8
+ import "./chunk-EI7CQQ7D.js";
5
9
 
6
10
  // src/providers/gcp/index.ts
7
11
  import process2 from "process";
8
12
 
9
13
  // src/providers/gcp/program.ts
10
- var GATEWAY_PORT = 18789;
11
14
  var SSH_PORT = 22;
12
15
  var gcpProgram = async () => {
13
- const [pulumi, gcp, { resolveIngressCidrs, detectEgressIp }] = await Promise.all([
16
+ const [pulumi, gcp, { resolveIngressCidrs, resolveGatewayIngressCidrs, resolveGatewayPort, detectEgressIp }] = await Promise.all([
14
17
  import("@pulumi/pulumi"),
15
18
  import("@pulumi/gcp"),
16
- import("./firewall-XQGO7HWK.js")
19
+ import("./firewall-T3NTPZJD.js")
17
20
  ]);
18
21
  const cfg = new pulumi.Config();
19
22
  const instanceType = cfg.get("instanceType") ?? "e2-standard-2";
20
23
  const region = cfg.get("region") ?? "us-central1";
21
24
  const openclawVersion = cfg.get("openclawVersion") ?? "latest";
25
+ const publishGateway = cfg.get("publishGateway") === "all" ? "all" : "loopback";
26
+ const gatewayPort = resolveGatewayPort(cfg.get("gatewayPort"), GATEWAY_PORT);
22
27
  const zone = cfg.get("zone") ?? `${region}-a`;
23
28
  const accessMode = cfg.get("accessMode") ?? "restricted";
24
29
  const allowedCidrs = cfg.get("allowedCidrs") ?? "";
@@ -37,7 +42,13 @@ var gcpProgram = async () => {
37
42
  );
38
43
  }
39
44
  const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, egressResult);
40
- const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs, egressResult);
45
+ const gatewayIngressCidrs = resolveGatewayIngressCidrs(
46
+ publishGateway,
47
+ accessMode,
48
+ allowedCidrs,
49
+ gatewayCidrs,
50
+ egressResult
51
+ );
41
52
  const network = new gcp.compute.Network("clawops-network", {
42
53
  autoCreateSubnetworks: false,
43
54
  description: "clawops managed network"
@@ -58,7 +69,7 @@ var gcpProgram = async () => {
58
69
  if (gatewayIngressCidrs.length > 0) {
59
70
  new gcp.compute.Firewall("clawops-firewall-gateway", {
60
71
  network: network.selfLink,
61
- allows: [{ protocol: "tcp", ports: [String(GATEWAY_PORT)] }],
72
+ allows: [{ protocol: "tcp", ports: [String(gatewayPort)] }],
62
73
  sourceRanges: gatewayIngressCidrs,
63
74
  targetTags: ["clawops"]
64
75
  });
@@ -89,7 +100,7 @@ var gcpProgram = async () => {
89
100
  metadata: {
90
101
  // GCP guest agent reads 'ssh-keys' and populates /home/<user>/.ssh/authorized_keys
91
102
  "ssh-keys": `clawops:${sshPublicKey}`,
92
- "startup-script": makeStartupScript({ openclawVersion, os: "debian" })
103
+ "startup-script": makeStartupScript({ openclawVersion, os: "debian", publishGateway, gatewayPort })
93
104
  },
94
105
  serviceAccount: {
95
106
  scopes: ["https://www.googleapis.com/auth/cloud-platform"]
@@ -98,7 +109,7 @@ var gcpProgram = async () => {
98
109
  return {
99
110
  instanceId: instance.id,
100
111
  publicIp: address.address,
101
- gatewayUrl: pulumi.interpolate`https://${address.address}:${GATEWAY_PORT}`,
112
+ gatewayUrl: pulumi.interpolate`https://${address.address}:${gatewayPort}`,
102
113
  sshHost: address.address,
103
114
  sshPort: SSH_PORT,
104
115
  sshUser: "clawops",
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  generatePlan,
4
4
  planId
5
- } from "./chunk-RAAONHW3.js";
6
- import "./chunk-6X45DDGH.js";
7
- import "./chunk-P5LKWRPL.js";
8
- import "./chunk-PVUVI35Y.js";
5
+ } from "./chunk-WHJMKDV7.js";
6
+ import "./chunk-YR3O2I3S.js";
7
+ import "./chunk-LU2V3LXA.js";
8
+ import "./chunk-JW5A7E3X.js";
9
9
  import "./chunk-A2I76FTA.js";
10
10
  import "./chunk-CX5SL5HP.js";
11
11
  import "./chunk-KGXPLI7W.js";
@@ -2,9 +2,16 @@
2
2
  import {
3
3
  acquireSession,
4
4
  drainPool
5
- } from "./chunk-DQDAWNGB.js";
6
- import "./chunk-3XK66DKK.js";
5
+ } from "./chunk-3WYA2QDM.js";
6
+ import "./chunk-AHAAEXWC.js";
7
7
  import "./chunk-KGXPLI7W.js";
8
+ import {
9
+ GATEWAY_PORT,
10
+ PUBLISH_INSPECT_CMD,
11
+ publishForRestart,
12
+ publishedGatewayPort
13
+ } from "./chunk-6TIYVHPX.js";
14
+ import "./chunk-EI7CQQ7D.js";
8
15
 
9
16
  // src/harden/types.ts
10
17
  var SENTINEL_DIR = "/etc/clawops/hardening";
@@ -154,7 +161,11 @@ var sshModule = {
154
161
 
155
162
  // src/harden/modules/ufw.ts
156
163
  var SENTINEL2 = `${SENTINEL_DIR}/ufw.applied`;
157
- var GATEWAY_PORT = 18789;
164
+ async function publishedGateway(exec) {
165
+ const { stdout } = await exec(`${PUBLISH_INSPECT_CMD} 2>/dev/null || true`);
166
+ if (publishForRestart(stdout) !== "all") return { exposed: false };
167
+ return { exposed: true, port: publishedGatewayPort(stdout) };
168
+ }
158
169
  function makeUfwModule(sshPort = 22) {
159
170
  return {
160
171
  id: "ufw",
@@ -176,14 +187,24 @@ function makeUfwModule(sshPort = 22) {
176
187
  return { status: "missing", detail: "UFW installed but not active" };
177
188
  },
178
189
  async apply(exec) {
190
+ const gateway = await publishedGateway(exec);
191
+ const rules = [`ufw allow ${sshPort}/tcp comment "clawops SSH"`];
192
+ let gatewayNote;
193
+ if (!gateway.exposed) {
194
+ gatewayNote = "gateway port not opened (published on 127.0.0.1 \u2014 reach it with `clawops tunnel`)";
195
+ } else if (gateway.port === void 0) {
196
+ gatewayNote = "gateway published on every interface but its port could not be read \u2014 no rule added; run `clawops doctor --stack <name>` and open it yourself if that is intended";
197
+ } else {
198
+ rules.push(`ufw allow ${gateway.port}/tcp comment "OpenClaw gateway"`);
199
+ gatewayNote = `allow ${gateway.port}/tcp`;
200
+ }
179
201
  const script = [
180
202
  `mkdir -p ${SENTINEL_DIR}`,
181
203
  "apt-get install -y -q ufw",
182
204
  "ufw --force reset",
183
205
  "ufw default deny incoming",
184
206
  "ufw default allow outgoing",
185
- `ufw allow ${sshPort}/tcp comment "clawops SSH"`,
186
- `ufw allow ${GATEWAY_PORT}/tcp comment "OpenClaw gateway"`,
207
+ ...rules,
187
208
  "ufw --force enable",
188
209
  `touch ${SENTINEL2}`
189
210
  ].join(" && ");
@@ -191,7 +212,10 @@ function makeUfwModule(sshPort = 22) {
191
212
  if (code !== 0) {
192
213
  throw new Error(`UFW setup failed (exit ${code}): ${stderr.slice(0, 200)}`);
193
214
  }
194
- return { changed: true, detail: `UFW enabled: deny-all in, allow ${sshPort}/tcp + ${GATEWAY_PORT}/tcp` };
215
+ return {
216
+ changed: true,
217
+ detail: `UFW enabled: deny-all in, allow ${sshPort}/tcp; ${gatewayNote}`
218
+ };
195
219
  }
196
220
  };
197
221
  }
@@ -473,7 +497,14 @@ var sysctlModule = {
473
497
  };
474
498
 
475
499
  // src/harden/modules/aws-sg-audit.ts
476
- var EXPECTED_OPEN_PORTS = /* @__PURE__ */ new Set([22, 18789]);
500
+ var WORLD = /* @__PURE__ */ new Set(["0.0.0.0/0"]);
501
+ var WORLD_V6 = /* @__PURE__ */ new Set(["::/0"]);
502
+ var NAMED_PORTS = { 22: "SSH", [GATEWAY_PORT]: "the OpenClaw gateway" };
503
+ function describe(fromPort, toPort) {
504
+ const range = fromPort === toPort ? `port ${fromPort}` : `ports ${fromPort}-${toPort}`;
505
+ const named = NAMED_PORTS[fromPort];
506
+ return named && fromPort === toPort ? `${range} (${named})` : range;
507
+ }
477
508
  var awsSgAuditModule = {
478
509
  id: "aws-sg-audit",
479
510
  label: "AWS SG audit (check-only)",
@@ -492,19 +523,25 @@ var awsSgAuditModule = {
492
523
  for (const rule of sg.IpPermissions ?? []) {
493
524
  const fromPort = rule.FromPort ?? 0;
494
525
  const toPort = rule.ToPort ?? 65535;
526
+ const where = describe(fromPort, toPort);
495
527
  for (const range of rule.IpRanges ?? []) {
496
- if (range.CidrIp === "0.0.0.0/0" && !EXPECTED_OPEN_PORTS.has(fromPort)) {
497
- openRules.push(`port ${fromPort}\u2013${toPort} open to 0.0.0.0/0 in ${sg.GroupId}`);
528
+ if (range.CidrIp && WORLD.has(range.CidrIp)) {
529
+ openRules.push(`${where} open to ${range.CidrIp} in ${sg.GroupId}`);
530
+ }
531
+ }
532
+ for (const range of rule.Ipv6Ranges ?? []) {
533
+ if (range.CidrIpv6 && WORLD_V6.has(range.CidrIpv6)) {
534
+ openRules.push(`${where} open to ${range.CidrIpv6} in ${sg.GroupId}`);
498
535
  }
499
536
  }
500
537
  }
501
538
  }
502
539
  if (openRules.length === 0) {
503
- return { status: "applied", detail: "No unexpected open ingress rules found" };
540
+ return { status: "applied", detail: "No ingress rule admits the whole internet" };
504
541
  }
505
542
  return {
506
543
  status: "drifted",
507
- detail: `Open ingress rules detected: ${openRules.join("; ")}`
544
+ detail: `Ingress open to the internet: ${openRules.join("; ")}`
508
545
  };
509
546
  } catch (err) {
510
547
  return {
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ HEALTH_PATHS,
4
+ interpretProbe,
5
+ probeCommand
6
+ } from "./chunk-LT4XMO5D.js";
7
+ export {
8
+ HEALTH_PATHS,
9
+ interpretProbe,
10
+ probeCommand
11
+ };
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ GATEWAY_LOGS_PROBE,
4
+ agentAuditCommand,
5
+ chooseLogSource,
6
+ containerLogsCommand,
7
+ gatewayLogsCommand
8
+ } from "./chunk-SBLQH2TJ.js";
9
+ export {
10
+ GATEWAY_LOGS_PROBE,
11
+ agentAuditCommand,
12
+ chooseLogSource,
13
+ containerLogsCommand,
14
+ gatewayLogsCommand
15
+ };
@@ -1,24 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  MCP_HTTP_PORT
4
- } from "./chunk-QQNKBTYZ.js";
5
- import "./chunk-35WVQY3X.js";
4
+ } from "./chunk-AX74VXTV.js";
5
+ import "./chunk-UFRO4H5W.js";
6
+ import "./chunk-N44K3LHE.js";
7
+ import "./chunk-3QJBNAHW.js";
8
+ import "./chunk-WHJMKDV7.js";
9
+ import "./chunk-YR3O2I3S.js";
6
10
  import "./chunk-6ZFIFDBJ.js";
11
+ import "./chunk-3WYA2QDM.js";
12
+ import "./chunk-AHAAEXWC.js";
7
13
  import "./chunk-BOPSG2LI.js";
8
- import "./chunk-3QJBNAHW.js";
9
- import "./chunk-RAAONHW3.js";
10
- import "./chunk-6X45DDGH.js";
11
- import "./chunk-FNS56UQY.js";
12
- import "./chunk-DQDAWNGB.js";
13
- import "./chunk-SEZMVVAS.js";
14
- import "./chunk-P5LKWRPL.js";
15
- import "./chunk-EI7CQQ7D.js";
16
- import "./chunk-PVUVI35Y.js";
17
- import "./chunk-3XK66DKK.js";
14
+ import "./chunk-LU2V3LXA.js";
15
+ import "./chunk-GYV4KNW7.js";
16
+ import "./chunk-SBLQH2TJ.js";
17
+ import "./chunk-LT4XMO5D.js";
18
+ import {
19
+ execPrivileged
20
+ } from "./chunk-NUDIHZEH.js";
21
+ import "./chunk-JW5A7E3X.js";
18
22
  import "./chunk-Q7NQY5HV.js";
19
23
  import "./chunk-A2I76FTA.js";
20
24
  import "./chunk-CX5SL5HP.js";
21
25
  import "./chunk-KGXPLI7W.js";
26
+ import "./chunk-6TIYVHPX.js";
27
+ import "./chunk-EI7CQQ7D.js";
22
28
 
23
29
  // src/cli/mcp-wire.ts
24
30
  var GATEWAY_MCP_NAME = "clawops";
@@ -30,17 +36,17 @@ function shellQuote(value) {
30
36
  }
31
37
  var OC = "docker exec openclaw openclaw mcp";
32
38
  async function supportsMcpAdd(session, signal) {
33
- const help = await session.exec(`${OC} add --help`, signal);
39
+ const help = await execPrivileged(session, `${OC} add --help`, signal);
34
40
  return help.code === 0;
35
41
  }
36
42
  async function wireGatewayMcp(session, signal, opts = {}) {
37
43
  const url = opts.url ?? defaultGatewayMcpUrl();
38
44
  if (!await supportsMcpAdd(session, signal)) return { status: "unsupported", url };
39
- const existing = await session.exec(`${OC} show ${GATEWAY_MCP_NAME}`, signal);
45
+ const existing = await execPrivileged(session, `${OC} show ${GATEWAY_MCP_NAME}`, signal);
40
46
  const alreadyWired = existing.code === 0;
41
47
  if (alreadyWired && !opts.rewire) return { status: "exists", url };
42
48
  if (alreadyWired) {
43
- const removed = await session.exec(`${OC} unset ${GATEWAY_MCP_NAME}`, signal);
49
+ const removed = await execPrivileged(session, `${OC} unset ${GATEWAY_MCP_NAME}`, signal);
44
50
  if (removed.code !== 0) {
45
51
  return {
46
52
  status: "probe-failed",
@@ -54,7 +60,7 @@ async function wireGatewayMcp(session, signal, opts = {}) {
54
60
  `--url ${shellQuote(url)}`,
55
61
  ...opts.token ? [`--header ${shellQuote(`Authorization=Bearer ${opts.token}`)}`] : []
56
62
  ].join(" ");
57
- const added = await session.exec(`${OC} add ${GATEWAY_MCP_NAME} ${flags}`, signal);
63
+ const added = await execPrivileged(session, `${OC} add ${GATEWAY_MCP_NAME} ${flags}`, signal);
58
64
  if (added.code !== 0) {
59
65
  return {
60
66
  status: "probe-failed",
@@ -62,7 +68,7 @@ async function wireGatewayMcp(session, signal, opts = {}) {
62
68
  url
63
69
  };
64
70
  }
65
- await session.exec(`${OC} reload`, signal);
71
+ await execPrivileged(session, `${OC} reload`, signal);
66
72
  return { status: "wired", rewired: alreadyWired, url };
67
73
  }
68
74
  export {
@@ -2,7 +2,7 @@
2
2
 
3
3
  // package.json
4
4
  var name = "@clawops/cli";
5
- var version = "1.7.8";
5
+ var version = "2.0.0";
6
6
  var description = "Deploy and manage self-hosted OpenClaw instances across clouds";
7
7
  var type = "module";
8
8
  var bin = {
@@ -35,13 +35,13 @@ var scripts = {
35
35
  test: "vitest run",
36
36
  "test:pulumi": "vitest run tests/providers/aws/program.test.ts tests/providers/azure/program.test.ts",
37
37
  "test:changed": "vitest --changed",
38
- "test:mutation": "node scripts/dev/mutation-check.mjs",
39
38
  "test:integration": "vitest run --config vitest.integration.config.ts",
40
39
  typecheck: "NODE_OPTIONS=--max-old-space-size=4096 tsc --noEmit",
41
40
  lint: "eslint --max-warnings=0 src tests scripts",
42
41
  "gen:schemas": "tsx scripts/gen-schemas.ts",
43
42
  changeset: "changeset",
44
- release: "pnpm build && changeset publish"
43
+ release: "pnpm build && changeset publish",
44
+ "test:mutation": "node scripts/dev/mutation-check.mjs"
45
45
  };
46
46
  var dependencies = {
47
47
  "@aws-sdk/client-cloudwatch-logs": "^3.1063.0",
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/openclaw/plugins.ts
4
+ function providerIdOf(p) {
5
+ return p.configPath?.split(".").pop() ?? p.id;
6
+ }
7
+ function requiredPlugins(cfg, catalog) {
8
+ if (cfg === null || typeof cfg !== "object") return [];
9
+ const models = cfg["models"];
10
+ if (models === null || typeof models !== "object") return [];
11
+ const providers = models["providers"];
12
+ if (providers === null || typeof providers !== "object") return [];
13
+ const configured = new Set(Object.keys(providers));
14
+ const out = [];
15
+ for (const entry of catalog.providers) {
16
+ if (!entry.plugin) continue;
17
+ const id = providerIdOf(entry);
18
+ if (configured.has(id)) {
19
+ out.push({ providerId: id, package: entry.plugin.package, version: entry.plugin.version });
20
+ }
21
+ }
22
+ return out;
23
+ }
24
+ function installCommand(plugin, image, stateDir) {
25
+ return `docker run --rm -v ${stateDir}:/home/node/.openclaw ${image} openclaw plugins install 'clawhub:${plugin.package}@${plugin.version}' --accept-capabilities`;
26
+ }
27
+ function missingProviders(cfg, pluginsListJson) {
28
+ let loaded = /* @__PURE__ */ new Set();
29
+ try {
30
+ const parsed = JSON.parse(pluginsListJson);
31
+ const list = Array.isArray(parsed) ? parsed : parsed.plugins ?? [];
32
+ loaded = new Set(
33
+ list.filter((p) => p.enabled !== false && p.status !== "error").flatMap((p) => p.providerIds ?? [])
34
+ );
35
+ } catch {
36
+ return [];
37
+ }
38
+ if (cfg === null || typeof cfg !== "object") return [];
39
+ const models = cfg["models"];
40
+ if (models === null || typeof models !== "object") return [];
41
+ const providers = models["providers"];
42
+ if (providers === null || typeof providers !== "object") return [];
43
+ return Object.keys(providers).filter((id) => !loaded.has(id));
44
+ }
45
+ export {
46
+ installCommand,
47
+ missingProviders,
48
+ requiredPlugins
49
+ };
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  acquireSession,
4
4
  drainPool
5
- } from "./chunk-DQDAWNGB.js";
6
- import "./chunk-3XK66DKK.js";
5
+ } from "./chunk-3WYA2QDM.js";
6
+ import "./chunk-AHAAEXWC.js";
7
7
  import "./chunk-KGXPLI7W.js";
8
8
  export {
9
9
  acquireSession,
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ execPrivileged,
4
+ execPrivilegedWithInput,
5
+ resetPrivilegeCache,
6
+ shellQuote,
7
+ streamPrivileged,
8
+ sudoWrap
9
+ } from "./chunk-NUDIHZEH.js";
10
+ export {
11
+ execPrivileged,
12
+ execPrivilegedWithInput,
13
+ resetPrivilegeCache,
14
+ shellQuote,
15
+ streamPrivileged,
16
+ sudoWrap
17
+ };
@@ -6,10 +6,11 @@ import {
6
6
  OPENCLAW_TMP,
7
7
  atomicWriteConfig,
8
8
  deepMerge,
9
- normaliseGatewayPort,
10
9
  readRemoteConfig,
11
10
  restartGateway
12
- } from "./chunk-SEZMVVAS.js";
11
+ } from "./chunk-N44K3LHE.js";
12
+ import "./chunk-NUDIHZEH.js";
13
+ import "./chunk-6TIYVHPX.js";
13
14
  import "./chunk-EI7CQQ7D.js";
14
15
  export {
15
16
  OPENCLAW_CONFIG,
@@ -18,7 +19,6 @@ export {
18
19
  OPENCLAW_TMP,
19
20
  atomicWriteConfig,
20
21
  deepMerge,
21
- normaliseGatewayPort,
22
22
  readRemoteConfig,
23
23
  restartGateway
24
24
  };
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ADD_HOST_FLAG,
4
+ CONFIG_FILENAME,
5
+ CONFIG_MOUNT_PATH,
6
+ CONTAINER_UID,
7
+ ENV_FILE_PATH,
8
+ GATEWAY_PORT,
9
+ PUBLISH_INSPECT_CMD,
10
+ SECURITY_FLAGS,
11
+ STATE_DIR_CONTAINER,
12
+ STATE_DIR_HOST_LINUX,
13
+ STATE_DIR_HOST_MACOS,
14
+ SUPERVISOR_ENV,
15
+ configPathForOS,
16
+ gatewayRunArgs,
17
+ gatewayRunCommand,
18
+ publishForRestart,
19
+ publishedGatewayPort,
20
+ stateDirForOS
21
+ } from "./chunk-6TIYVHPX.js";
22
+ import "./chunk-EI7CQQ7D.js";
23
+ export {
24
+ ADD_HOST_FLAG,
25
+ CONFIG_FILENAME,
26
+ CONFIG_MOUNT_PATH,
27
+ CONTAINER_UID,
28
+ ENV_FILE_PATH,
29
+ GATEWAY_PORT,
30
+ PUBLISH_INSPECT_CMD,
31
+ SECURITY_FLAGS,
32
+ STATE_DIR_CONTAINER,
33
+ STATE_DIR_HOST_LINUX,
34
+ STATE_DIR_HOST_MACOS,
35
+ SUPERVISOR_ENV,
36
+ configPathForOS,
37
+ gatewayRunArgs,
38
+ gatewayRunCommand,
39
+ publishForRestart,
40
+ publishedGatewayPort,
41
+ stateDirForOS
42
+ };
@@ -5,24 +5,28 @@ import {
5
5
  bearerFrom,
6
6
  isLoopbackBind,
7
7
  serveMcp
8
- } from "./chunk-QQNKBTYZ.js";
9
- import "./chunk-35WVQY3X.js";
8
+ } from "./chunk-AX74VXTV.js";
9
+ import "./chunk-UFRO4H5W.js";
10
+ import "./chunk-N44K3LHE.js";
11
+ import "./chunk-3QJBNAHW.js";
12
+ import "./chunk-WHJMKDV7.js";
13
+ import "./chunk-YR3O2I3S.js";
10
14
  import "./chunk-6ZFIFDBJ.js";
15
+ import "./chunk-3WYA2QDM.js";
16
+ import "./chunk-AHAAEXWC.js";
11
17
  import "./chunk-BOPSG2LI.js";
12
- import "./chunk-3QJBNAHW.js";
13
- import "./chunk-RAAONHW3.js";
14
- import "./chunk-6X45DDGH.js";
15
- import "./chunk-FNS56UQY.js";
16
- import "./chunk-DQDAWNGB.js";
17
- import "./chunk-SEZMVVAS.js";
18
- import "./chunk-P5LKWRPL.js";
19
- import "./chunk-EI7CQQ7D.js";
20
- import "./chunk-PVUVI35Y.js";
21
- import "./chunk-3XK66DKK.js";
18
+ import "./chunk-LU2V3LXA.js";
19
+ import "./chunk-GYV4KNW7.js";
20
+ import "./chunk-SBLQH2TJ.js";
21
+ import "./chunk-LT4XMO5D.js";
22
+ import "./chunk-NUDIHZEH.js";
23
+ import "./chunk-JW5A7E3X.js";
22
24
  import "./chunk-Q7NQY5HV.js";
23
25
  import "./chunk-A2I76FTA.js";
24
26
  import "./chunk-CX5SL5HP.js";
25
27
  import "./chunk-KGXPLI7W.js";
28
+ import "./chunk-6TIYVHPX.js";
29
+ import "./chunk-EI7CQQ7D.js";
26
30
  export {
27
31
  MCP_HTTP_PORT,
28
32
  authRequirement,
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ _resetSpecDirCache,
4
+ resolveSpecDir
5
+ } from "./chunk-JW5A7E3X.js";
6
+ export {
7
+ _resetSpecDirCache,
8
+ resolveSpecDir
9
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  connect
4
- } from "./chunk-3XK66DKK.js";
4
+ } from "./chunk-AHAAEXWC.js";
5
5
  import "./chunk-KGXPLI7W.js";
6
6
  export {
7
7
  connect