@wrongstack/cli 1.0.3 → 1.0.6

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 (83) hide show
  1. package/dist/{acp-JK4ZQO3R.js → acp-GOQURNC2.js} +128 -43
  2. package/dist/acp-agent-list.d.ts +14 -0
  3. package/dist/acp-hq-telemetry.d.ts +9 -2
  4. package/dist/acp-mcp-servers.d.ts +49 -0
  5. package/dist/acp-server-agent.d.ts +18 -6
  6. package/dist/{auth-XD3GN5RJ.js → auth-WBXXIQUO.js} +3 -3
  7. package/dist/boot/short-circuit-desktop.d.ts +1 -0
  8. package/dist/boot/short-circuit-hq.d.ts +2 -0
  9. package/dist/boot/tool-registry.d.ts +18 -1
  10. package/dist/{chunk-JHPXJRRI.js → chunk-4XCBEUBX.js} +13 -3
  11. package/dist/{chunk-ONOT5OJ2.js → chunk-5A5GCSJC.js} +1 -1
  12. package/dist/chunk-5EA6OTLJ.js +239 -0
  13. package/dist/{chunk-O4A3HHKD.js → chunk-672UXYL3.js} +2 -2
  14. package/dist/{chunk-FPIWTJ2G.js → chunk-6WRKAACA.js} +4 -4
  15. package/dist/chunk-AUQDGU5D.js +32 -0
  16. package/dist/{chunk-VOTTENR5.js → chunk-CDY4D5QK.js} +2 -2
  17. package/dist/{chunk-E6RFXHWD.js → chunk-EK2P53GL.js} +3 -2
  18. package/dist/{chunk-MXEJEYT7.js → chunk-JX6KL7OF.js} +15 -5
  19. package/dist/{chunk-GMY45LO6.js → chunk-KEPABQYT.js} +101 -2
  20. package/dist/{chunk-IMWXXF4J.js → chunk-KNMIBKLV.js} +79 -1
  21. package/dist/{chunk-4NHD5OXJ.js → chunk-NR7BD73C.js} +5 -5
  22. package/dist/{chunk-C2E24IXZ.js → chunk-PQZPHGGD.js} +272 -299
  23. package/dist/chunk-Q7E3BPDU.js +62 -0
  24. package/dist/{chunk-IUEKNHPT.js → chunk-QDQPF4PB.js} +11 -11
  25. package/dist/{chunk-VFCJOWJB.js → chunk-VPS2SJW4.js} +4 -5
  26. package/dist/{chunk-U6KCWRMC.js → chunk-XJ7K67PP.js} +5 -1
  27. package/dist/{cli-context-Q6QP534K.js → cli-context-BYKJDAFF.js} +129 -25
  28. package/dist/{cli-main-JQXCDZEA.js → cli-main-5WZBH3WA.js} +1345 -800
  29. package/dist/{diag-doctor-7LYUYU35.js → diag-doctor-PCER6KHH.js} +2 -2
  30. package/dist/{execution-KH7WJNAX.js → execution-Z6A26EG6.js} +132 -40
  31. package/dist/execution-specialist-trigger.d.ts +28 -0
  32. package/dist/fleet/acp-live-progress.d.ts +19 -0
  33. package/dist/fleet/host-acp-runner-cache.d.ts +3 -1
  34. package/dist/fleet/host-acp.d.ts +14 -2
  35. package/dist/fleet/host.d.ts +1 -0
  36. package/dist/{hq-IG3YRGCO.js → hq-V4PHEETW.js} +127 -8
  37. package/dist/hq-command-controller.d.ts +31 -2
  38. package/dist/hq-server/auth-state.d.ts +6 -0
  39. package/dist/hq-server/auth.d.ts +10 -1
  40. package/dist/hq-server/client-address.d.ts +2 -0
  41. package/dist/hq-server/ip-allowlist.d.ts +16 -0
  42. package/dist/hq-server/preflight.d.ts +1 -0
  43. package/dist/hq-server/routes/auth/common.d.ts +34 -0
  44. package/dist/hq-server/routes/auth/password-routes.d.ts +4 -2
  45. package/dist/hq-server/routes.d.ts +5 -4
  46. package/dist/hq-server/secret-input.d.ts +7 -0
  47. package/dist/hq-server/types.d.ts +21 -2
  48. package/dist/hq-server/upgrade-handler.d.ts +2 -0
  49. package/dist/hq-server/utils.d.ts +6 -0
  50. package/dist/{hq-server-OILU3NPI.js → hq-server-MZ7DV6X7.js} +4 -3
  51. package/dist/hq-server.d.ts +4 -0
  52. package/dist/hq-service-L5INQFM4.js +507 -0
  53. package/dist/hq-service.d.ts +22 -0
  54. package/dist/index.js +9 -6
  55. package/dist/ip-allowlist-NHXO6AKJ.js +9 -0
  56. package/dist/live-settings-input.d.ts +2 -0
  57. package/dist/{mcp-HOMLC4WE.js → mcp-FX7TKPTV.js} +10 -8
  58. package/dist/mcp-serve.d.ts +31 -0
  59. package/dist/{per-subcommand-help-BWBHYVJO.js → per-subcommand-help-DHTYU524.js} +2 -2
  60. package/dist/{plugins-U7KGQAUG.js → plugins-WJLW6ULV.js} +2 -2
  61. package/dist/projects-LMNAGGEU.js +36 -0
  62. package/dist/{proxy-wiring-MGRSKZZB.js → proxy-wiring-K2DORFFL.js} +3 -3
  63. package/dist/short-circuit-flags-KBTYSJTW.js +10 -0
  64. package/dist/slash-commands/acp.d.ts +3 -0
  65. package/dist/slash-commands/command-context.d.ts +22 -0
  66. package/dist/slash-commands/ensemble.d.ts +1 -1
  67. package/dist/slash-commands/profile.d.ts +7 -0
  68. package/dist/subcommands/handlers/hq.d.ts +1 -0
  69. package/dist/subcommands/handlers/projects.d.ts +14 -0
  70. package/dist/{subcommands-CUTGBDKP.js → subcommands-DEYSYHIM.js} +2 -2
  71. package/dist/{version-help-MYKF724O.js → version-help-WXI42PZ3.js} +2 -2
  72. package/dist/{webui-server-QWBUT7BO.js → webui-server-OBV5JYJV.js} +9 -3
  73. package/dist/wiring/cli-slash-commands-setup.d.ts +7 -0
  74. package/dist/wiring/codebase-embeddings.d.ts +2 -2
  75. package/dist/wiring/command-host-state.d.ts +7 -0
  76. package/dist/wiring/pipeline.d.ts +2 -0
  77. package/dist/wiring/provider-runtime-setup.d.ts +1 -1
  78. package/dist/wiring/session-command-handlers.d.ts +2 -1
  79. package/dist/wiring/slash-commands.d.ts +1 -0
  80. package/package.json +28 -28
  81. package/dist/chunk-Q5GTM25S.js +0 -17
  82. package/dist/projects-L6C6XLDY.js +0 -37
  83. package/dist/short-circuit-flags-ZNZX44MC.js +0 -10
@@ -0,0 +1,62 @@
1
+
2
+ // src/hq-server/ip-allowlist.ts
3
+ import { BlockList, isIP } from "node:net";
4
+ function normalizeAddress(value) {
5
+ return value.trim().replace(/^\[(.*)\]$/, "$1").replace(/^::ffff:/i, "");
6
+ }
7
+ function addRule(blockList, rawRule) {
8
+ const rule = rawRule.trim();
9
+ if (!rule) throw new TypeError("HQ IP allowlist contains an empty entry.");
10
+ const slash = rule.lastIndexOf("/");
11
+ if (slash === -1) {
12
+ const address2 = normalizeAddress(rule);
13
+ const family2 = isIP(address2);
14
+ if (family2 === 0) {
15
+ throw new TypeError(`Invalid HQ allowlist address: ${rule}`);
16
+ }
17
+ blockList.addAddress(address2, family2 === 4 ? "ipv4" : "ipv6");
18
+ return address2;
19
+ }
20
+ const address = normalizeAddress(rule.slice(0, slash));
21
+ const prefixText = rule.slice(slash + 1);
22
+ const family = isIP(address);
23
+ if (family === 0 || !/^\d+$/.test(prefixText)) {
24
+ throw new TypeError(`Invalid HQ allowlist network: ${rule}`);
25
+ }
26
+ const prefix = Number(prefixText);
27
+ const maximum = family === 4 ? 32 : 128;
28
+ if (!Number.isSafeInteger(prefix) || prefix < 0 || prefix > maximum) {
29
+ throw new TypeError(`Invalid HQ allowlist prefix: ${rule}`);
30
+ }
31
+ blockList.addSubnet(address, prefix, family === 4 ? "ipv4" : "ipv6");
32
+ return `${address}/${prefix}`;
33
+ }
34
+ function createHqIpAllowlist(rules) {
35
+ if (rules === void 0 || rules.length === 0) return void 0;
36
+ const blockList = new BlockList();
37
+ blockList.addSubnet("127.0.0.0", 8, "ipv4");
38
+ blockList.addAddress("::1", "ipv6");
39
+ const entries = [...new Set(rules.map((rule) => addRule(blockList, rule)))];
40
+ return {
41
+ entries,
42
+ allows(address) {
43
+ if (!address) return false;
44
+ const normalized = normalizeAddress(address);
45
+ const family = isIP(normalized);
46
+ if (family === 0) return false;
47
+ return blockList.check(normalized, family === 4 ? "ipv4" : "ipv6");
48
+ }
49
+ };
50
+ }
51
+ function parseHqIpAllowlist(value) {
52
+ if (value === void 0 || value.trim() === "") return void 0;
53
+ const rules = value.split(",").map((entry) => entry.trim());
54
+ createHqIpAllowlist(rules);
55
+ return rules;
56
+ }
57
+
58
+ export {
59
+ createHqIpAllowlist,
60
+ parseHqIpAllowlist
61
+ };
62
+ //# sourceMappingURL=chunk-Q7E3BPDU.js.map
@@ -1,9 +1,9 @@
1
1
 
2
2
  // src/subcommands/index.ts
3
3
  var loaders = {
4
- acp: async () => (await import("./acp-JK4ZQO3R.js")).acpCmd,
4
+ acp: async () => (await import("./acp-GOQURNC2.js")).acpCmd,
5
5
  init: async () => (await import("./init-DRMMFG2G.js")).initCmd,
6
- auth: async () => (await import("./auth-XD3GN5RJ.js")).authCmd,
6
+ auth: async () => (await import("./auth-WBXXIQUO.js")).authCmd,
7
7
  update: async () => (await import("./update-5DPB4YD4.js")).updateCmd,
8
8
  sessions: async () => (await import("./sessions-config-UL45XKX7.js")).sessionsCmd,
9
9
  config: async () => (await import("./sessions-config-UL45XKX7.js")).configCmd,
@@ -16,22 +16,22 @@ var loaders = {
16
16
  skills: async () => (await import("./tools-skills-GH24UCBY.js")).skillsCmd,
17
17
  providers: async () => (await import("./providers-models-6MOGAOVK.js")).providersCmd,
18
18
  models: async () => (await import("./providers-models-6MOGAOVK.js")).modelsCmd,
19
- mcp: async () => (await import("./mcp-HOMLC4WE.js")).mcpCmd,
19
+ mcp: async () => (await import("./mcp-FX7TKPTV.js")).mcpCmd,
20
20
  plugin: async () => (await import("./plugin-usage-M6KET4OZ.js")).pluginCmd,
21
21
  plugins: async () => (await import("./plugin-usage-M6KET4OZ.js")).pluginCmd,
22
- diag: async () => (await import("./diag-doctor-7LYUYU35.js")).diagCmd,
23
- doctor: async () => (await import("./diag-doctor-7LYUYU35.js")).doctorCmd,
24
- "proxy-status": async () => (await import("./diag-doctor-7LYUYU35.js")).proxyCmd,
22
+ diag: async () => (await import("./diag-doctor-PCER6KHH.js")).diagCmd,
23
+ doctor: async () => (await import("./diag-doctor-PCER6KHH.js")).doctorCmd,
24
+ "proxy-status": async () => (await import("./diag-doctor-PCER6KHH.js")).proxyCmd,
25
25
  export: async () => (await import("./export-VVRIOWFV.js")).exportCmd,
26
26
  usage: async () => (await import("./plugin-usage-M6KET4OZ.js")).usageCmd,
27
- version: async () => (await import("./version-help-MYKF724O.js")).versionCmd,
28
- help: async () => (await import("./version-help-MYKF724O.js")).helpCmd,
29
- projects: async () => (await import("./projects-L6C6XLDY.js")).projectsCmd,
27
+ version: async () => (await import("./version-help-WXI42PZ3.js")).versionCmd,
28
+ help: async () => (await import("./version-help-WXI42PZ3.js")).helpCmd,
29
+ projects: async () => (await import("./projects-LMNAGGEU.js")).projectsCmd,
30
30
  modeldiag: async () => (await import("./modeldiag-46CMWUNM.js")).modeldiagCmd,
31
31
  quick: async () => (await import("./quick-CNB4Z3HS.js")).quickCmd,
32
32
  bench: async () => (await import("./bench-YBU6BVQP.js")).benchCmd,
33
33
  chronicle: async () => (await import("./chronicle-UTFETHP6.js")).chronicleCmd,
34
- hq: async () => (await import("./hq-IG3YRGCO.js")).hqCmd,
34
+ hq: async () => (await import("./hq-V4PHEETW.js")).hqCmd,
35
35
  mailbox: async () => (await import("./mailbox-serve-X3CR6VFW.js")).mailboxServeCmd,
36
36
  permissions: async () => (await import("./permissions-CFDLXETM.js")).permissionsCmd,
37
37
  project: async () => (await import("./project-AOQI5XTK.js")).projectCmd,
@@ -51,4 +51,4 @@ export {
51
51
  subcommands,
52
52
  subcommandNames
53
53
  };
54
- //# sourceMappingURL=chunk-IUEKNHPT.js.map
54
+ //# sourceMappingURL=chunk-QDQPF4PB.js.map
@@ -74,15 +74,14 @@ function stringifyInput(input) {
74
74
  var PREVIEW_MAX_LINES = 40;
75
75
  var PREVIEW_MAX_CHARS = 8e3;
76
76
  function clipPreview(body, decorate = (l) => l) {
77
- const safe = sanitizeTerminalText2(body);
78
- const { text, truncated } = sanitizeTerminalPreview(body, {
77
+ const { text, truncated, sanitizedLength, sanitizedLines } = sanitizeTerminalPreview(body, {
79
78
  maxLines: PREVIEW_MAX_LINES,
80
79
  maxChars: PREVIEW_MAX_CHARS
81
80
  });
82
81
  const rendered = text.split("\n").map(decorate).join("\n");
83
82
  if (!truncated) return rendered;
84
- const hiddenLines = safe.split("\n").length - text.split("\n").length;
85
- const detail = hiddenLines > 0 ? `${hiddenLines} more line${hiddenLines === 1 ? "" : "s"} not shown` : `${safe.length - text.length} more characters not shown`;
83
+ const hiddenLines = sanitizedLines - text.split("\n").length;
84
+ const detail = hiddenLines > 0 ? `${hiddenLines} more line${hiddenLines === 1 ? "" : "s"} not shown` : `${sanitizedLength - text.length} more characters not shown`;
86
85
  return `${rendered}
87
86
  ${color2.dim(`\u2026 ${detail} \u2014 review the file before approving`)}`;
88
87
  }
@@ -481,4 +480,4 @@ export {
481
480
  detectProjectFacts,
482
481
  renderAgentsTemplate
483
482
  };
484
- //# sourceMappingURL=chunk-VFCJOWJB.js.map
483
+ //# sourceMappingURL=chunk-VPS2SJW4.js.map
@@ -80,6 +80,10 @@ var BUILTIN_PLUGIN_FACTORIES = [
80
80
  const { createAutoReviewPlugin } = await import("@wrongstack/core/plugin");
81
81
  return createAutoReviewPlugin();
82
82
  },
83
+ async () => {
84
+ const { createSpecialistTriggerPlugin } = await import("@wrongstack/core/plugin");
85
+ return createSpecialistTriggerPlugin();
86
+ },
83
87
  async () => {
84
88
  const { createSkillsPlugin } = await import("@wrongstack/core/plugin");
85
89
  return createSkillsPlugin();
@@ -263,4 +267,4 @@ export {
263
267
  BUILTIN_PLUGIN_FACTORIES,
264
268
  setupPlugins
265
269
  };
266
- //# sourceMappingURL=chunk-U6KCWRMC.js.map
270
+ //# sourceMappingURL=chunk-XJ7K67PP.js.map
@@ -5,33 +5,41 @@ import {
5
5
  makePromptDelegate,
6
6
  renderAgentsTemplate,
7
7
  renderDiff
8
- } from "./chunk-VFCJOWJB.js";
8
+ } from "./chunk-VPS2SJW4.js";
9
9
  import {
10
10
  theme as theme2
11
11
  } from "./chunk-QD544J2B.js";
12
- import {
13
- parseWebuiSessionChildOptions,
14
- writeWebuiSessionChildError
15
- } from "./chunk-GPPRNAKW.js";
16
12
  import {
17
13
  fmtTok,
18
14
  patchConfig
19
15
  } from "./chunk-EWKESL4L.js";
16
+ import {
17
+ parseWebuiSessionChildOptions,
18
+ writeWebuiSessionChildError
19
+ } from "./chunk-GPPRNAKW.js";
20
20
  import {
21
21
  subcommands
22
- } from "./chunk-IUEKNHPT.js";
22
+ } from "./chunk-QDQPF4PB.js";
23
23
  import {
24
24
  renderDeepHelp,
25
25
  renderFocusedHelp
26
- } from "./chunk-MXEJEYT7.js";
26
+ } from "./chunk-JX6KL7OF.js";
27
27
  import {
28
28
  handleHelpVersionShortCircuit
29
- } from "./chunk-4NHD5OXJ.js";
29
+ } from "./chunk-NR7BD73C.js";
30
30
  import {
31
31
  DEFAULT_PORT
32
- } from "./chunk-C2E24IXZ.js";
32
+ } from "./chunk-PQZPHGGD.js";
33
33
  import "./chunk-HXJYHAR4.js";
34
- import "./chunk-Q5GTM25S.js";
34
+ import {
35
+ resolveHqPasswordInput
36
+ } from "./chunk-AUQDGU5D.js";
37
+ import {
38
+ normalizeHqPublicOrigin
39
+ } from "./chunk-5EA6OTLJ.js";
40
+ import {
41
+ parseHqIpAllowlist
42
+ } from "./chunk-Q7E3BPDU.js";
35
43
  import {
36
44
  discoverAndMergeProviders
37
45
  } from "./chunk-D5GB5MHA.js";
@@ -39,8 +47,8 @@ import {
39
47
  applyNodeEnvDefault,
40
48
  applySessionShellDefault,
41
49
  runPreflight
42
- } from "./chunk-O4A3HHKD.js";
43
- import "./chunk-FPIWTJ2G.js";
50
+ } from "./chunk-672UXYL3.js";
51
+ import "./chunk-6WRKAACA.js";
44
52
  import {
45
53
  CLI_VERSION
46
54
  } from "./chunk-XJXDOF63.js";
@@ -55,7 +63,7 @@ import {
55
63
  runPicker,
56
64
  saveToGlobalConfig,
57
65
  theme
58
- } from "./chunk-ONOT5OJ2.js";
66
+ } from "./chunk-5A5GCSJC.js";
59
67
  import "./chunk-2VMJ3E5Z.js";
60
68
  import "./chunk-B4JLSXZB.js";
61
69
  import {
@@ -67,7 +75,7 @@ import {
67
75
  } from "./chunk-YMXXOOFN.js";
68
76
  import {
69
77
  parseArgs
70
- } from "./chunk-E6RFXHWD.js";
78
+ } from "./chunk-EK2P53GL.js";
71
79
  import "./chunk-DAKVBMD4.js";
72
80
  import {
73
81
  mutateConfigProviders,
@@ -706,6 +714,10 @@ function stripDesktopLauncherArgs(argv) {
706
714
  }
707
715
  return out;
708
716
  }
717
+ function selectDesktopLauncherExecutable(execPath, runningUnderBun, nodeOverride) {
718
+ if (!runningUnderBun) return execPath;
719
+ return nodeOverride?.trim() || "node";
720
+ }
709
721
  async function handleDesktopShortCircuit(flags, argv) {
710
722
  if (flags["desktop"] !== true) return null;
711
723
  return launchDesktop(stripDesktopLauncherArgs(argv));
@@ -732,7 +744,12 @@ async function launchDesktop(args) {
732
744
  return 1;
733
745
  }
734
746
  return await new Promise((resolve2) => {
735
- const child = spawn(process.execPath, [launcherPath, ...args], {
747
+ const executable = selectDesktopLauncherExecutable(
748
+ process.execPath,
749
+ typeof globalThis.Bun !== "undefined",
750
+ process.env["NODE"]
751
+ );
752
+ const child = spawn(executable, [launcherPath, ...args], {
736
753
  stdio: "inherit",
737
754
  env: process.env,
738
755
  windowsHide: false
@@ -760,9 +777,13 @@ import {
760
777
  resolveHqDataDir
761
778
  } from "@wrongstack/core/hq";
762
779
  import { color as color3, isPidAlive } from "@wrongstack/core/utils";
780
+ function isReusedContainerPid(markerPid, containerMode, currentPid = process.pid) {
781
+ return containerMode === "1" && markerPid === currentPid;
782
+ }
763
783
  async function isHqAlreadyRunning(dataDir) {
764
784
  const marker = readHqRuntimeFileSync(dataDir);
765
785
  if (!marker) return null;
786
+ if (isReusedContainerPid(marker.pid, process.env.WRONGSTACK_HQ_CONTAINER)) return null;
766
787
  if (marker.pid && isPidAlive(marker.pid)) return marker;
767
788
  return null;
768
789
  }
@@ -784,12 +805,31 @@ async function isPortInUse(host, port) {
784
805
  }
785
806
  async function handleHqShortCircuit(flags) {
786
807
  if (flags["hq"] !== true) return null;
787
- const { startHqServer } = await import("./hq-server-OILU3NPI.js");
808
+ const { startHqServer } = await import("./hq-server-MZ7DV6X7.js");
788
809
  const tunnelRequested = flags["tunnel"] === true;
789
- const host = typeof flags["host"] === "string" ? flags["host"] : tunnelRequested ? "127.0.0.1" : HQ_CLI_DEFAULT_HOST2;
790
- if (tunnelRequested && !isLoopbackHost(host)) {
810
+ const rawPublicUrl = typeof flags["hq-public-url"] === "string" ? flags["hq-public-url"] : process.env.WRONGSTACK_HQ_PUBLIC_URL;
811
+ let publicOrigin;
812
+ if (rawPublicUrl !== void 0 && rawPublicUrl.trim() !== "") {
813
+ try {
814
+ publicOrigin = normalizeHqPublicOrigin(rawPublicUrl);
815
+ } catch (cause) {
816
+ process.stderr.write(
817
+ `${color3.red("\u2717")} ${cause instanceof Error ? cause.message : String(cause)}
818
+ `
819
+ );
820
+ return 1;
821
+ }
822
+ }
823
+ if (tunnelRequested && publicOrigin !== void 0) {
824
+ process.stderr.write(`${color3.red("\u2717")} Use either --tunnel or --hq-public-url, not both.
825
+ `);
826
+ return 1;
827
+ }
828
+ const externallyPublished = tunnelRequested || publicOrigin !== void 0;
829
+ const host = typeof flags["host"] === "string" ? flags["host"] : externallyPublished ? "127.0.0.1" : HQ_CLI_DEFAULT_HOST2;
830
+ if (externallyPublished && !isLoopbackHost(host)) {
791
831
  process.stderr.write(
792
- `${color3.red("\u2717")} --tunnel requires a loopback origin. Remove --host or use --host 127.0.0.1.
832
+ `${color3.red("\u2717")} Public HQ publishing requires a loopback bind. Remove --host or use --host 127.0.0.1.
793
833
  `
794
834
  );
795
835
  return 1;
@@ -806,12 +846,51 @@ async function handleHqShortCircuit(flags) {
806
846
  }
807
847
  } else port = DEFAULT_PORT;
808
848
  const dataDir = typeof flags["data-dir"] === "string" ? flags["data-dir"] : void 0;
809
- const password = typeof flags["password"] === "string" ? flags["password"] : process.env.WRONGSTACK_HQ_PASSWORD;
849
+ let password;
850
+ try {
851
+ password = await resolveHqPasswordInput({
852
+ ...typeof flags["password"] === "string" ? { explicitPassword: flags["password"] } : {}
853
+ });
854
+ } catch (cause) {
855
+ process.stderr.write(
856
+ `${color3.red("\u2717")} ${cause instanceof Error ? cause.message : String(cause)}
857
+ `
858
+ );
859
+ return 1;
860
+ }
861
+ const bootstrapPasswordOnly = /^(?:1|true)$/i.test(
862
+ process.env.WRONGSTACK_HQ_BOOTSTRAP_PASSWORD_ONLY?.trim() ?? ""
863
+ );
864
+ let ipAllowlist;
865
+ try {
866
+ ipAllowlist = parseHqIpAllowlist(
867
+ typeof flags["hq-allowlist"] === "string" ? flags["hq-allowlist"] : process.env.WRONGSTACK_HQ_ALLOWLIST
868
+ );
869
+ } catch (cause) {
870
+ process.stderr.write(
871
+ `${color3.red("\u2717")} ${cause instanceof Error ? cause.message : String(cause)}
872
+ `
873
+ );
874
+ return 1;
875
+ }
810
876
  if (password !== void 0 && password.length < 8) {
811
877
  process.stderr.write(`${color3.red("\u2717")} HQ password must be at least 8 characters.
812
878
  `);
813
879
  return 1;
814
880
  }
881
+ const rawTrustedProxyHops = typeof flags["hq-trusted-proxy-hops"] === "string" ? flags["hq-trusted-proxy-hops"] : process.env.WRONGSTACK_HQ_TRUSTED_PROXY_HOPS;
882
+ let trustedProxyHops;
883
+ if (rawTrustedProxyHops !== void 0 && rawTrustedProxyHops.trim() !== "") {
884
+ const parsed = Number.parseInt(rawTrustedProxyHops, 10);
885
+ if (!Number.isFinite(parsed) || parsed < 0 || String(parsed) !== rawTrustedProxyHops.trim()) {
886
+ process.stderr.write(
887
+ `${color3.red("\u2717")} --hq-trusted-proxy-hops must be a non-negative integer.
888
+ `
889
+ );
890
+ return 1;
891
+ }
892
+ trustedProxyHops = parsed;
893
+ }
815
894
  const userProvidedPort = typeof flags["port"] === "string" && flags["port"].trim() !== "" || port !== DEFAULT_PORT;
816
895
  const resolvedDataDir = dataDir ?? resolveHqDataDir();
817
896
  const existing = await isHqAlreadyRunning(resolvedDataDir);
@@ -849,11 +928,14 @@ async function handleHqShortCircuit(flags) {
849
928
  strictPort: flags["strict-port"] === true,
850
929
  exactPort: userProvidedPort,
851
930
  allowInsecureOpen: flags["insecure-open"] === true,
852
- secureCookies: tunnelRequested,
853
- requireBrowserAuth: tunnelRequested,
931
+ secureCookies: externallyPublished,
932
+ requireBrowserAuth: externallyPublished,
854
933
  ...dataDir !== void 0 ? { dataDir } : {},
855
934
  ...password !== void 0 ? { password } : {},
856
- ...tokenTtlMs !== void 0 ? { tokenTtlMs } : {}
935
+ ...bootstrapPasswordOnly ? { bootstrapPasswordOnly: true } : {},
936
+ ...tokenTtlMs !== void 0 ? { tokenTtlMs } : {},
937
+ ...trustedProxyHops !== void 0 ? { trustedProxyHops } : {},
938
+ ...ipAllowlist !== void 0 ? { ipAllowlist } : {}
857
939
  });
858
940
  } catch (err) {
859
941
  const msg = err instanceof Error ? err.message : String(err);
@@ -868,8 +950,24 @@ async function handleHqShortCircuit(flags) {
868
950
  }
869
951
  return 1;
870
952
  }
953
+ if (publicOrigin !== void 0) {
954
+ if (handle.firstRunSetup?.passwordMode !== true) {
955
+ await handle.close();
956
+ process.stderr.write(
957
+ `${color3.red("\u2717")} Persistent public HQ requires password mode. Set WRONGSTACK_HQ_PASSWORD and retry.
958
+ `
959
+ );
960
+ return 1;
961
+ }
962
+ handle.trustPublicOrigin(publicOrigin);
963
+ process.stdout.write(`
964
+ ${color3.green("Persistent HQ origin ready:")} ${publicOrigin}/
965
+ `);
966
+ process.stdout.write(`${color3.green("Mobile:")} ${publicOrigin}/mobile
967
+ `);
968
+ }
871
969
  let tunnel;
872
- let browserUrl = handle.firstRunSetup?.browserUrl ?? `http://${handle.host}:${handle.port}`;
970
+ let browserUrl = publicOrigin ?? handle.firstRunSetup?.browserUrl ?? `http://${handle.host}:${handle.port}`;
873
971
  if (tunnelRequested) {
874
972
  if (handle.firstRunSetup !== void 0 && !handle.firstRunSetup.browserTokenMode && !handle.firstRunSetup.passwordMode) {
875
973
  await handle.close();
@@ -894,6 +992,12 @@ async function handleHqShortCircuit(flags) {
894
992
  );
895
993
  process.stdout.write(`
896
994
  ${color3.green("Cloudflare Quick Tunnel ready:")} ${browserUrl}
995
+ `);
996
+ const tunnelMobileUrl = new URL(tunnel.url);
997
+ tunnelMobileUrl.pathname = "/mobile";
998
+ tunnelMobileUrl.search = "";
999
+ tunnelMobileUrl.hash = "";
1000
+ process.stdout.write(`${color3.green("Mobile:")} ${tunnelMobileUrl.toString()}
897
1001
  `);
898
1002
  process.stdout.write(
899
1003
  `${color3.dim("Temporary development URL; DNS may need a few seconds, it changes on restart and ends when HQ stops.")}
@@ -3128,4 +3232,4 @@ async function initializeCli(argv) {
3128
3232
  export {
3129
3233
  initializeCli
3130
3234
  };
3131
- //# sourceMappingURL=cli-context-Q6QP534K.js.map
3235
+ //# sourceMappingURL=cli-context-BYKJDAFF.js.map