@clawops/cli 1.5.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.
package/dist/cli.js CHANGED
@@ -5,6 +5,7 @@ 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,
@@ -14,10 +15,10 @@ import {
14
15
  success,
15
16
  validateOpenclawConfig,
16
17
  warn
17
- } from "./chunk-R5S6IXBE.js";
18
- import "./chunk-T5EX55GP.js";
19
- import "./chunk-ZVOEQCNW.js";
20
- import "./chunk-4U3LTLWZ.js";
18
+ } from "./chunk-C5NDLOK2.js";
19
+ import "./chunk-QI75OVJK.js";
20
+ import "./chunk-LCKD7L7X.js";
21
+ import "./chunk-GJEF6UQA.js";
21
22
  import "./chunk-ZFNPM2WG.js";
22
23
  import "./chunk-A2I76FTA.js";
23
24
  import {
@@ -32,7 +33,7 @@ import {
32
33
  } from "./chunk-KGXPLI7W.js";
33
34
 
34
35
  // src/cli/index.ts
35
- import { defineCommand as defineCommand21, runMain } from "citty";
36
+ import { defineCommand as defineCommand22, runMain } from "citty";
36
37
 
37
38
  // src/cli/commands/init.ts
38
39
  import { defineCommand } from "citty";
@@ -204,7 +205,7 @@ var up_default = defineCommand2({
204
205
  config: { type: "string", description: "Path to openclaw config overlay JSON (local provider only)" }
205
206
  },
206
207
  async run({ args }) {
207
- const { buildContext } = await import("./context-PSGEX2D7.js");
208
+ const { buildContext } = await import("./context-KPKBOWOP.js");
208
209
  const ctx = buildContext(args);
209
210
  const openclawVersion = typeof args["openclaw-version"] === "string" ? args["openclaw-version"] : "stable";
210
211
  if (ctx.adapter.name === "local") {
@@ -215,7 +216,7 @@ var up_default = defineCommand2({
215
216
  );
216
217
  }
217
218
  const { localOpts } = stackConfig;
218
- const { localBootstrap } = await import("./bootstrap-G4UZ2FKH.js");
219
+ const { localBootstrap } = await import("./bootstrap-RY4VOSDJ.js");
219
220
  const abortController = new AbortController();
220
221
  process3.on("SIGINT", () => abortController.abort());
221
222
  process3.on("SIGTERM", () => abortController.abort());
@@ -308,7 +309,7 @@ var up_default = defineCommand2({
308
309
  }
309
310
  });
310
311
  async function applyLocalConfigOverlay(opts) {
311
- const { connect } = await import("./ssh-IQXNME3D.js");
312
+ const { connect } = await import("./ssh-E2AMBPZY.js");
312
313
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
313
314
  const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
314
315
  let overlay;
@@ -350,7 +351,7 @@ var down_default = defineCommand3({
350
351
  "dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
351
352
  },
352
353
  async run({ args }) {
353
- const { buildContext } = await import("./context-PSGEX2D7.js");
354
+ const { buildContext } = await import("./context-KPKBOWOP.js");
354
355
  const ctx = buildContext(args);
355
356
  if (args["dry-run"]) {
356
357
  info(`Dry run \u2014 would destroy stack "${ctx.stackName}"`);
@@ -414,7 +415,7 @@ var status_default = defineCommand4({
414
415
  json: { type: "boolean", description: "Emit JSON" }
415
416
  },
416
417
  async run({ args }) {
417
- const { buildContext } = await import("./context-PSGEX2D7.js");
418
+ const { buildContext } = await import("./context-KPKBOWOP.js");
418
419
  const ctx = buildContext(args);
419
420
  if (ctx.adapter.name === "local") {
420
421
  const state = ctx.localState;
@@ -486,8 +487,8 @@ var plan_default = defineCommand5({
486
487
  out: { type: "string", description: "Write plan JSON to this absolute path (default: stdout)" }
487
488
  },
488
489
  async run({ args }) {
489
- const { buildContext } = await import("./context-PSGEX2D7.js");
490
- const { generatePlan } = await import("./generate-2QGKYR42.js");
490
+ const { buildContext } = await import("./context-KPKBOWOP.js");
491
+ const { generatePlan } = await import("./generate-YV7226Q7.js");
491
492
  const ctx = buildContext(args);
492
493
  if (ctx.adapter.name === "local") {
493
494
  throw new UsageError(
@@ -577,7 +578,7 @@ var apply_default = defineCommand6({
577
578
  },
578
579
  async run({ args }) {
579
580
  const { validatePlan } = await import("./validate-T5M5EHSJ.js");
580
- const { applyPlan } = await import("./apply-5RREMN3L.js");
581
+ const { applyPlan } = await import("./apply-SI3JKS4Z.js");
581
582
  const planPath = args._?.[0];
582
583
  if (!planPath) {
583
584
  throw new UsageError("Usage: clawops apply <plan.json>");
@@ -693,7 +694,7 @@ var destroy_default = defineCommand7({
693
694
  "dry-run": { type: "boolean", description: "Show what would be destroyed without destroying" }
694
695
  },
695
696
  async run({ args }) {
696
- const { buildContext } = await import("./context-PSGEX2D7.js");
697
+ const { buildContext } = await import("./context-KPKBOWOP.js");
697
698
  const ctx = buildContext(args);
698
699
  if (ctx.adapter.name === "local") {
699
700
  throw new UsageError(
@@ -760,8 +761,8 @@ var ssh_default = defineCommand8({
760
761
  command: { type: "string", description: "Remote command to run (instead of interactive shell)" }
761
762
  },
762
763
  async run({ args }) {
763
- const { buildContext } = await import("./context-PSGEX2D7.js");
764
- 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");
765
766
  const ctx = buildContext(args);
766
767
  let conn;
767
768
  if (ctx.adapter.name === "local") {
@@ -847,9 +848,9 @@ var tunnel_default = defineCommand9({
847
848
  "no-open": { type: "boolean", description: "Do not open browser after tunnel is ready" }
848
849
  },
849
850
  async run({ args }) {
850
- const { buildContext } = await import("./context-PSGEX2D7.js");
851
+ const { buildContext } = await import("./context-KPKBOWOP.js");
851
852
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
852
- const { acquireSession } = await import("./pool-FBFHATDG.js");
853
+ const { acquireSession } = await import("./pool-JZGKPP6K.js");
853
854
  const ctx = buildContext(args);
854
855
  const stack = await ctx.getStack();
855
856
  const outputMap = await stack.outputs();
@@ -915,9 +916,9 @@ var logs_default = defineCommand10({
915
916
  since: { type: "string", description: "Show logs since duration (e.g. 5m, 1h)" }
916
917
  },
917
918
  async run({ args }) {
918
- const { buildContext } = await import("./context-PSGEX2D7.js");
919
+ const { buildContext } = await import("./context-KPKBOWOP.js");
919
920
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
920
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
921
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
921
922
  const ctx = buildContext(args);
922
923
  const stack = await ctx.getStack();
923
924
  const outputMap = await stack.outputs();
@@ -1032,9 +1033,9 @@ var config_default = defineCommand11({
1032
1033
  "dry-run": { type: "boolean", description: "Show what would change without writing" }
1033
1034
  },
1034
1035
  async run({ args }) {
1035
- const { buildContext } = await import("./context-PSGEX2D7.js");
1036
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1036
1037
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1037
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1038
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1038
1039
  const [action, key, value] = args._ ?? [];
1039
1040
  if (!action || !["get", "set", "unset", "validate"].includes(action)) {
1040
1041
  failure("Usage: clawops config <get [key] | set key value | unset key | validate>");
@@ -1158,9 +1159,9 @@ var agents_default = defineCommand12({
1158
1159
  json: { type: "boolean", description: "Emit JSON (for list)" }
1159
1160
  },
1160
1161
  async run({ args }) {
1161
- const { buildContext } = await import("./context-PSGEX2D7.js");
1162
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1162
1163
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1163
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1164
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1164
1165
  const [action, name] = args._ ?? [];
1165
1166
  if (!action || !["list", "restart", "logs"].includes(action)) {
1166
1167
  failure("Usage: clawops agents <list | restart [name] | logs <name>>");
@@ -1262,9 +1263,9 @@ var gateway_default = defineCommand13({
1262
1263
  json: { type: "boolean", description: "Emit JSON (for status)" }
1263
1264
  },
1264
1265
  async run({ args }) {
1265
- const { buildContext } = await import("./context-PSGEX2D7.js");
1266
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1266
1267
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1267
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1268
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1268
1269
  const [action, versionArg] = args._ ?? [];
1269
1270
  if (!action || !["status", "restart", "update"].includes(action)) {
1270
1271
  failure("Usage: clawops gateway <status | restart | update [version]>");
@@ -1375,8 +1376,8 @@ var backup_default = defineCommand14({
1375
1376
  yes: { type: "boolean", description: "[restore] Skip confirmation prompt" }
1376
1377
  },
1377
1378
  async run({ args }) {
1378
- const { buildContext } = await import("./context-PSGEX2D7.js");
1379
- 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");
1380
1381
  const action = args.action;
1381
1382
  if (action !== "create" && action !== "restore") {
1382
1383
  throw new UsageError(`Unknown action: ${action}. Use "create" or "restore"`);
@@ -1548,7 +1549,7 @@ var stacks_default = defineCommand15({
1548
1549
  let isDeployed = false;
1549
1550
  if (!args.force) {
1550
1551
  try {
1551
- const { buildContext } = await import("./context-PSGEX2D7.js");
1552
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1552
1553
  const ctx = buildContext({ stack: name });
1553
1554
  if (ctx.adapter.name === "local") {
1554
1555
  isDeployed = !!ctx.localState;
@@ -1669,9 +1670,9 @@ var doctor_default = defineCommand16({
1669
1670
  info("Credential checks skipped \u2014 no config");
1670
1671
  } else {
1671
1672
  const { getProvider } = await import("./providers-2OABPW2E.js");
1672
- await import("./aws-FRE2JVAZ.js");
1673
- await import("./gcp-BXDTC6EK.js");
1674
- await import("./azure-PVC3AQVC.js");
1673
+ await import("./aws-D7Y6LCGK.js");
1674
+ await import("./gcp-6FT2A45S.js");
1675
+ await import("./azure-JQAMNVHN.js");
1675
1676
  await import("./local-DXBEVZ5C.js");
1676
1677
  const checkedProviders = /* @__PURE__ */ new Set();
1677
1678
  for (const [stackName, stackCfg] of Object.entries(config.stacks)) {
@@ -1706,9 +1707,9 @@ var doctor_default = defineCommand16({
1706
1707
  info("Remote health skipped \u2014 no config");
1707
1708
  } else {
1708
1709
  try {
1709
- const { buildContext } = await import("./context-PSGEX2D7.js");
1710
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1710
1711
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1711
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1712
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1712
1713
  const ctx = buildContext({ stack: args.stack });
1713
1714
  const stack = await ctx.getStack();
1714
1715
  const outputMap = await stack.outputs();
@@ -1793,7 +1794,14 @@ var doctor_default = defineCommand16({
1793
1794
  }
1794
1795
  }
1795
1796
  process18.stdout.write("\n");
1796
- 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
+ }
1797
1805
  }
1798
1806
  });
1799
1807
 
@@ -1814,7 +1822,7 @@ var serveCmd = defineCommand17({
1814
1822
  inspector: { type: "boolean", description: "Enable MCP inspector" }
1815
1823
  },
1816
1824
  async run({ args }) {
1817
- const { serveMcp } = await import("./server-LOL2NUJ2.js");
1825
+ const { serveMcp } = await import("./server-3DEZHUWB.js");
1818
1826
  await serveMcp({
1819
1827
  port: args.http ? Number(args.http) : void 0,
1820
1828
  bind: args.bind,
@@ -1889,8 +1897,8 @@ var wireCmd = defineCommand17({
1889
1897
  force: { type: "boolean", description: "Apply even if gateway version is below minimum" }
1890
1898
  },
1891
1899
  async run({ args }) {
1892
- const { buildContext } = await import("./context-PSGEX2D7.js");
1893
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
1900
+ const { buildContext } = await import("./context-KPKBOWOP.js");
1901
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
1894
1902
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
1895
1903
  const { wireGatewayMcp } = await import("./mcp-wire-ZWIYMLEW.js");
1896
1904
  const ac = new AbortController();
@@ -2404,7 +2412,7 @@ var setup_default = defineCommand18({
2404
2412
  default: false
2405
2413
  }]);
2406
2414
  if (applyNow) {
2407
- const { applyPlan } = await import("./apply-5RREMN3L.js");
2415
+ const { applyPlan } = await import("./apply-SI3JKS4Z.js");
2408
2416
  const plan = JSON.parse(readFileSync3(outputPath, "utf-8"));
2409
2417
  try {
2410
2418
  await applyPlan(plan, {
@@ -2427,8 +2435,8 @@ To deploy later: clawops apply ${outputPath}`);
2427
2435
  });
2428
2436
  async function runLocalDeploy(opts) {
2429
2437
  const { setConfig: setConfig2, getConfig: getConfig2, getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
2430
- const { localBootstrap } = await import("./bootstrap-G4UZ2FKH.js");
2431
- const { connect } = await import("./ssh-IQXNME3D.js");
2438
+ const { localBootstrap } = await import("./bootstrap-RY4VOSDJ.js");
2439
+ const { connect } = await import("./ssh-E2AMBPZY.js");
2432
2440
  const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
2433
2441
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
2434
2442
  const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
@@ -2510,7 +2518,7 @@ async function runLocalDeploy(opts) {
2510
2518
  spin2.fail("Configuration failed");
2511
2519
  throw err;
2512
2520
  }
2513
- const { drainPool } = await import("./pool-FBFHATDG.js");
2521
+ const { drainPool } = await import("./pool-JZGKPP6K.js");
2514
2522
  drainPool();
2515
2523
  const tokenPath = path3.join(os.homedir(), ".clawops", "secrets", `GATEWAY_TOKEN_${opts.stackName}`);
2516
2524
  const dashboardUrl = `${state.gatewayUrl}?token=${opts.gatewayToken}`;
@@ -2648,7 +2656,7 @@ var DOCKER_CHECK_CMD = [
2648
2656
  "echo NOT_RUNNING"
2649
2657
  ].join("; ");
2650
2658
  async function checkDockerPreflight(opts) {
2651
- const { acquireSession } = await import("./pool-FBFHATDG.js");
2659
+ const { acquireSession } = await import("./pool-JZGKPP6K.js");
2652
2660
  const { ProviderError } = await import("./errors-OK47MQFD.js");
2653
2661
  const spin = spinner("Checking Docker on target host...");
2654
2662
  const timeoutSignal = AbortSignal.timeout(DOCKER_PREFLIGHT_TIMEOUT_MS);
@@ -2695,7 +2703,7 @@ async function checkDockerPreflight(opts) {
2695
2703
  var DOCKER_POLL_MS = 3e3;
2696
2704
  var DOCKER_TIMEOUT_MS = 9e4;
2697
2705
  async function startRemoteDocker(opts, spin) {
2698
- const { acquireSession } = await import("./pool-FBFHATDG.js");
2706
+ const { acquireSession } = await import("./pool-JZGKPP6K.js");
2699
2707
  const { ProviderError } = await import("./errors-OK47MQFD.js");
2700
2708
  spin.text = "Starting Docker on the remote server...";
2701
2709
  const { session, release } = await acquireSession({
@@ -2899,7 +2907,7 @@ async function maybeWireGatewayMcp(opts) {
2899
2907
  process20.stdout.write("\n");
2900
2908
  const { wireGateway } = await inquirerPromptWire(opts.inquirer);
2901
2909
  if (!wireGateway) return;
2902
- const { connect } = await import("./ssh-IQXNME3D.js");
2910
+ const { connect } = await import("./ssh-E2AMBPZY.js");
2903
2911
  const { getConfigDir: getConfigDir2 } = await import("./store-SDUR52Z5.js");
2904
2912
  const { wireGatewayMcp } = await import("./mcp-wire-ZWIYMLEW.js");
2905
2913
  const knownHostsPath = path3.join(getConfigDir2(), "known_hosts");
@@ -3164,10 +3172,10 @@ var rotateCmd = defineCommand19({
3164
3172
  }
3165
3173
  info(`Re-applying config overlay to stack "${targetStack}"\u2026`);
3166
3174
  try {
3167
- const { buildContext } = await import("./context-PSGEX2D7.js");
3175
+ const { buildContext } = await import("./context-KPKBOWOP.js");
3168
3176
  const { readRemoteConfig, atomicWriteConfig, restartGateway, deepMerge } = await import("./remote-config-QF5TT7GU.js");
3169
3177
  const { resolveSecrets } = await import("./secrets-SVZWNAPK.js");
3170
- const { acquireSession, drainPool } = await import("./pool-FBFHATDG.js");
3178
+ const { acquireSession, drainPool } = await import("./pool-JZGKPP6K.js");
3171
3179
  const { localStateToConnectionInfo } = await import("./state-PRBIIN7I.js");
3172
3180
  const ctx = buildContext({ stack: targetStack });
3173
3181
  let conn;
@@ -3344,26 +3352,133 @@ ${dim("Run `clawops <command> --help` for command-specific flags.")}
3344
3352
  }
3345
3353
  });
3346
3354
 
3347
- // src/cli/error-handler.ts
3355
+ // src/cli/commands/bug.ts
3356
+ import { defineCommand as defineCommand21 } from "citty";
3348
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}
3457
+ `);
3458
+ }
3459
+ }
3460
+ });
3461
+
3462
+ // src/cli/error-handler.ts
3463
+ import process23 from "process";
3349
3464
  function handleError(err) {
3350
3465
  if (err instanceof ClawopsError) {
3351
3466
  failure(err.message);
3352
- process22.exit(err.exitCode);
3467
+ process23.exit(err.exitCode);
3353
3468
  }
3354
3469
  if (err instanceof Error) {
3355
3470
  failure(`Unexpected error: ${err.message}`);
3356
- if (process22.env["DEBUG"]) {
3357
- process22.stderr.write(err.stack ?? "\n");
3471
+ if (process23.env["DEBUG"]) {
3472
+ process23.stderr.write(err.stack ?? "\n");
3358
3473
  }
3359
- process22.exit(1);
3474
+ process23.exit(1);
3360
3475
  }
3361
3476
  failure(`Unknown error: ${String(err)}`);
3362
- process22.exit(1);
3477
+ process23.exit(1);
3363
3478
  }
3364
3479
 
3365
3480
  // src/cli/index.ts
3366
- var main = defineCommand21({
3481
+ var main = defineCommand22({
3367
3482
  meta: {
3368
3483
  name: "clawops",
3369
3484
  description: "Deploy and manage self-hosted OpenClaw instances across clouds",
@@ -3399,7 +3514,8 @@ var main = defineCommand21({
3399
3514
  setup: setup_default,
3400
3515
  secret: secret_default,
3401
3516
  monitor: monitor_default,
3402
- help: help_default
3517
+ help: help_default,
3518
+ bug: bug_default
3403
3519
  }
3404
3520
  });
3405
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";
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/providers/firewall.ts
4
+ function resolveIngressCidrs(accessMode, allowedCidrs, portOverride, egressResult) {
5
+ if (portOverride.trim()) {
6
+ return portOverride.split(",").map((s) => s.trim()).filter(Boolean);
7
+ }
8
+ switch (accessMode) {
9
+ case "restricted": {
10
+ if (!allowedCidrs.trim()) return [];
11
+ return allowedCidrs.split(",").map((s) => s.trim()).filter(Boolean);
12
+ }
13
+ case "auto": {
14
+ if (!egressResult.ok) {
15
+ throw new Error(
16
+ `accessMode=auto: egress IP detection failed \u2014 ${egressResult.error}. Set allowedCidrs explicitly or use accessMode=restricted.`
17
+ );
18
+ }
19
+ const ip = egressResult.ip.trim();
20
+ if (!ip) {
21
+ throw new Error(
22
+ `accessMode=auto: egress IP detection returned an empty address. Set allowedCidrs explicitly or use accessMode=restricted.`
23
+ );
24
+ }
25
+ return [ip.includes("/") ? ip : `${ip}/32`];
26
+ }
27
+ case "open":
28
+ return ["0.0.0.0/0"];
29
+ default:
30
+ return [];
31
+ }
32
+ }
33
+ async function detectEgressIp(checkUrl) {
34
+ try {
35
+ const res = await fetch(checkUrl, { signal: AbortSignal.timeout(3e3) });
36
+ if (!res.ok) {
37
+ return { ok: false, error: `HTTP ${res.status} from ${checkUrl}` };
38
+ }
39
+ const ip = (await res.text()).trim();
40
+ if (!ip) {
41
+ return { ok: false, error: `empty response from ${checkUrl}` };
42
+ }
43
+ return { ok: true, ip };
44
+ } catch (err) {
45
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
46
+ }
47
+ }
48
+ export {
49
+ detectEgressIp,
50
+ resolveIngressCidrs
51
+ };
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ makeStartupScript
4
+ } from "./chunk-XKT42M34.js";
2
5
 
3
6
  // src/providers/gcp/index.ts
4
7
  import process2 from "process";
@@ -10,7 +13,7 @@ var gcpProgram = async () => {
10
13
  const [pulumi, gcp, { resolveIngressCidrs, detectEgressIp }] = await Promise.all([
11
14
  import("@pulumi/pulumi"),
12
15
  import("@pulumi/gcp"),
13
- import("./firewall-YYDOWDDP.js")
16
+ import("./firewall-XQGO7HWK.js")
14
17
  ]);
15
18
  const cfg = new pulumi.Config();
16
19
  const instanceType = cfg.get("instanceType") ?? "e2-standard-2";
@@ -27,14 +30,14 @@ var gcpProgram = async () => {
27
30
  'Stack config "sshPublicKey" is required for the GCP adapter. Set it with: pulumi config set --stack <name> sshPublicKey "ssh-ed25519 ..."'
28
31
  );
29
32
  }
30
- const detectedIp = accessMode === "auto" ? await detectEgressIp("https://checkip.amazonaws.com") : "";
33
+ const egressResult = accessMode === "auto" ? await detectEgressIp("https://ifconfig.me") : { ok: true, ip: "" };
31
34
  if (accessMode === "open") {
32
35
  process.stderr.write(
33
36
  "[clawops] WARNING: accessMode=open allows 0.0.0.0/0 on SSH and gateway ports. Only use this for development/sandbox stacks.\n"
34
37
  );
35
38
  }
36
- const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, detectedIp);
37
- const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs, detectedIp);
39
+ const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, egressResult);
40
+ const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs, egressResult);
38
41
  const network = new gcp.compute.Network("clawops-network", {
39
42
  autoCreateSubnetworks: false,
40
43
  description: "clawops managed network"
@@ -42,7 +45,7 @@ var gcpProgram = async () => {
42
45
  const subnet = new gcp.compute.Subnetwork("clawops-subnet", {
43
46
  ipCidrRange: "10.0.0.0/24",
44
47
  region,
45
- network: network.id
48
+ network: network.selfLink
46
49
  });
47
50
  if (sshIngressCidrs.length > 0) {
48
51
  new gcp.compute.Firewall("clawops-firewall-ssh", {
@@ -73,8 +76,8 @@ var gcpProgram = async () => {
73
76
  },
74
77
  networkInterfaces: [
75
78
  {
76
- network: network.id,
77
- subnetwork: subnet.id,
79
+ network: network.selfLink,
80
+ subnetwork: subnet.selfLink,
78
81
  accessConfigs: [
79
82
  {
80
83
  natIp: address.address,
@@ -86,7 +89,7 @@ var gcpProgram = async () => {
86
89
  metadata: {
87
90
  // GCP guest agent reads 'ssh-keys' and populates /home/<user>/.ssh/authorized_keys
88
91
  "ssh-keys": `clawops:${sshPublicKey}`,
89
- "startup-script": makeStartupScript(openclawVersion)
92
+ "startup-script": makeStartupScript({ openclawVersion, os: "debian" })
90
93
  },
91
94
  serviceAccount: {
92
95
  scopes: ["https://www.googleapis.com/auth/cloud-platform"]
@@ -103,58 +106,6 @@ var gcpProgram = async () => {
103
106
  provisionedAt: (/* @__PURE__ */ new Date()).toISOString()
104
107
  };
105
108
  };
106
- function makeStartupScript(openclawVersion) {
107
- return `#!/bin/bash
108
- set -euo pipefail
109
-
110
- # Create clawops user with SSH access
111
- id -u clawops &>/dev/null || useradd -m -s /bin/bash clawops
112
- mkdir -p /home/clawops/.ssh
113
- chmod 700 /home/clawops/.ssh
114
-
115
- # Install Docker if not present
116
- if ! command -v docker &>/dev/null; then
117
- apt-get update -q
118
- apt-get install -y -q ca-certificates curl gnupg lsb-release
119
- install -m 0755 -d /etc/apt/keyrings
120
- curl -fsSL https://download.docker.com/linux/debian/gpg \\
121
- | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
122
- chmod a+r /etc/apt/keyrings/docker.gpg
123
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \\
124
- https://download.docker.com/linux/debian $(lsb_release -cs) stable" \\
125
- > /etc/apt/sources.list.d/docker.list
126
- apt-get update -q
127
- apt-get install -y -q docker-ce docker-ce-cli containerd.io
128
- systemctl enable --now docker
129
- fi
130
-
131
- usermod -aG docker clawops
132
-
133
- # Pull OpenClaw image
134
- OPENCLAW_VERSION="${openclawVersion}"
135
- docker pull ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION}
136
-
137
- # Create default openclaw.json if not present
138
- OPENCLAW_CONFIG=/home/clawops/openclaw.json
139
- if [ ! -f "\${OPENCLAW_CONFIG}" ]; then
140
- cat > "\${OPENCLAW_CONFIG}" <<'OPENCLAWJSON'
141
- {"meta":{"lastTouchedVersion":"2026.4"},"gateway":{"port":18789,"auth":{"mode":"token"}},"models":{},"channels":{}}
142
- OPENCLAWJSON
143
- chown clawops:clawops "\${OPENCLAW_CONFIG}"
144
- fi
145
-
146
- # Start OpenClaw container
147
- docker stop openclaw 2>/dev/null || true
148
- docker rm openclaw 2>/dev/null || true
149
- docker run -d \\
150
- --name openclaw \\
151
- --restart unless-stopped \\
152
- -p ${GATEWAY_PORT}:${GATEWAY_PORT} \\
153
- -v "\${OPENCLAW_CONFIG}":/app/config.json:ro \\
154
- ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION} \\
155
- node openclaw.mjs gateway run --allow-unconfigured
156
- `;
157
- }
158
109
 
159
110
  // src/providers/gcp/index.ts
160
111
  var INSTANCE_TYPE_MAP = {
@@ -172,9 +123,9 @@ var gcpAdapter = {
172
123
  },
173
124
  getConnectionInfo(outputs) {
174
125
  return {
175
- host: String(outputs["sshHost"]),
176
- port: Number(outputs["sshPort"]),
177
- user: String(outputs["sshUser"]),
126
+ host: String(outputs["sshHost"] ?? ""),
127
+ port: Number(outputs["sshPort"] ?? 22),
128
+ user: String(outputs["sshUser"] ?? "clawops"),
178
129
  privateKeyPath: String(outputs["privateKeyPath"] ?? ""),
179
130
  knownHostsPath: String(outputs["knownHostsPath"] ?? "")
180
131
  };
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  generatePlan,
4
4
  planId
5
- } from "./chunk-IVX62LFO.js";
5
+ } from "./chunk-72FF7IK2.js";
6
6
  import "./chunk-YTH4L2GN.js";
7
- import "./chunk-T5EX55GP.js";
7
+ import "./chunk-QI75OVJK.js";
8
8
  import "./chunk-A2I76FTA.js";
9
9
  import "./chunk-CX5SL5HP.js";
10
10
  import "./chunk-KGXPLI7W.js";