@wrongstack/cli 1.0.28 → 1.0.32

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 (135) hide show
  1. package/data/providers.json +8 -177
  2. package/dist/{acp-M4565YUW.js → acp-EDGUWU7N.js} +4 -7
  3. package/dist/{audit-46YK5DSC.js → audit-KCBTHUQI.js} +1 -1
  4. package/dist/{auth-TE55JF4Z.js → auth-SUHKFFO4.js} +136 -59
  5. package/dist/auth-menu/github-copilot-oauth.d.ts +1 -35
  6. package/dist/auth-menu/index-input.d.ts +3 -0
  7. package/dist/auth-menu/panel-flow-bridge.d.ts +29 -0
  8. package/dist/auth-menu/panel-service.d.ts +3 -34
  9. package/dist/auth-menu/provider-auth-login.d.ts +1 -1
  10. package/dist/auto-discover-providers-QIL34K3U.js +7 -0
  11. package/dist/automation-MCDFCIMV.js +369 -0
  12. package/dist/{bench-GTLPM22B.js → bench-MMZHFHDL.js} +152 -43
  13. package/dist/boot/brain-decision-log.d.ts +1 -1
  14. package/dist/boot/system-prompt-builder.d.ts +1 -1
  15. package/dist/boot/system-prompt-menu.d.ts +11 -2
  16. package/dist/boot/tui-coordinator-setup.d.ts +2 -0
  17. package/dist/boot/tui-startup-output.d.ts +11 -0
  18. package/dist/{boot-auto-thin-6Q56FY3F.js → boot-auto-thin-K2DHHYIW.js} +3 -3
  19. package/dist/{chronicle-UTFETHP6.js → chronicle-PBJS7BN6.js} +5 -3
  20. package/dist/{chunk-EPR42SWM.js → chunk-2EZ2DHOW.js} +60 -7
  21. package/dist/{chunk-7IQWQCBH.js → chunk-3LEFXLAW.js} +39 -39
  22. package/dist/{chunk-WSTVGC2C.js → chunk-4BX2YDTQ.js} +13 -6
  23. package/dist/{chunk-SFBFYIOW.js → chunk-4MDRHMX4.js} +3 -2
  24. package/dist/{chunk-RGFWGUAB.js → chunk-4UWCMBPG.js} +159 -3
  25. package/dist/{chunk-RDGGWMTI.js → chunk-65VNCAF6.js} +2 -22
  26. package/dist/{chunk-WQZW3RDP.js → chunk-7BNBD4PE.js} +2 -2
  27. package/dist/chunk-CFHWIFXL.js +123 -0
  28. package/dist/{chunk-RZ4ZDRYA.js → chunk-DIOODAYM.js} +2 -2
  29. package/dist/{chunk-L2RVEQWO.js → chunk-HHRYIDOW.js} +2 -2
  30. package/dist/chunk-LIZXJHZQ.js +61 -0
  31. package/dist/{chunk-YHYINL47.js → chunk-LKFKO4JW.js} +2 -2
  32. package/dist/{chunk-Q4INH2DG.js → chunk-MPQCHBDJ.js} +2 -1
  33. package/dist/{chunk-2ERX3RPN.js → chunk-P3GRLV47.js} +30 -17
  34. package/dist/{chunk-ZMX5HRLI.js → chunk-P3Q3KMFH.js} +6 -4
  35. package/dist/{chunk-KOEO4CJG.js → chunk-PGNERAZL.js} +4 -4
  36. package/dist/{chunk-ENRYW73H.js → chunk-RQ4UBKYH.js} +81 -10
  37. package/dist/{chunk-X756ZS72.js → chunk-SUDNPYWD.js} +2 -2
  38. package/dist/{chunk-LDCGZJTC.js → chunk-TWSQTQKR.js} +12 -4
  39. package/dist/chunk-TXAFIERF.js +37 -0
  40. package/dist/{chunk-UZ2TMHNH.js → chunk-UKP7H2U4.js} +10 -2
  41. package/dist/{chunk-5JYDKG5B.js → chunk-WHEYHDIE.js} +7 -2
  42. package/dist/{chunk-LBPLTTZ6.js → chunk-WTJDSTYD.js} +4 -4
  43. package/dist/{chunk-L5TD7UIG.js → chunk-WXJH4F6K.js} +7 -7
  44. package/dist/{chunk-IS2PPBQV.js → chunk-X4LW5CZM.js} +8 -4
  45. package/dist/{chunk-BBHWW6LR.js → chunk-YL4KCHZG.js} +18 -6
  46. package/dist/{chunk-LUMETJFO.js → chunk-ZYACRPLN.js} +2 -2
  47. package/dist/{cli-context-O2SHBDFH.js → cli-context-ITHGP2CE.js} +91 -84
  48. package/dist/cli-context.d.ts +3 -1
  49. package/dist/cli-infrastructure.d.ts +33 -0
  50. package/dist/{cli-main-BKG4ZVLN.js → cli-main-TQGLKB6D.js} +3783 -2753
  51. package/dist/config-doctor.d.ts +1 -1
  52. package/dist/{config-transfer-RUWLDCNK.js → config-transfer-UE37X4B5.js} +2 -2
  53. package/dist/{execution-THXWTHYT.js → execution-C2IECWF7.js} +5271 -5118
  54. package/dist/execution-chimera-handlers.d.ts +6 -0
  55. package/dist/execution-session-callbacks.d.ts +36 -0
  56. package/dist/execution-webui.d.ts +3 -0
  57. package/dist/execution.d.ts +1 -1
  58. package/dist/fleet/host-acp-runner.d.ts +15 -0
  59. package/dist/fleet/host-budget.d.ts +13 -0
  60. package/dist/fleet/host-context.d.ts +5 -0
  61. package/dist/fleet/host-explore-companion.d.ts +7 -16
  62. package/dist/fleet/host.d.ts +2 -0
  63. package/dist/fleet/status-broadcast.d.ts +1 -1
  64. package/dist/{hq-44F4OQH2.js → hq-KBFDKTDD.js} +13 -7
  65. package/dist/hq-publisher.d.ts +4 -1
  66. package/dist/hq-server/sage-sync-send.d.ts +5 -0
  67. package/dist/hq-server/server-lifecycle.d.ts +1 -1
  68. package/dist/hq-server/snapshot.d.ts +1 -1
  69. package/dist/{hq-server-UIB24LU6.js → hq-server-AVNKZ2PV.js} +2 -2
  70. package/dist/{hq-service-BMMJAHRT.js → hq-service-FGB7BY2D.js} +3 -3
  71. package/dist/hq-ttl-N4DAIAVX.js +7 -0
  72. package/dist/index.js +126 -10
  73. package/dist/{mailbox-serve-GNGXEQ2R.js → mailbox-serve-S536N66F.js} +4 -3
  74. package/dist/{modeldiag-W7XAE625.js → modeldiag-PQILD7TN.js} +26 -8
  75. package/dist/{per-subcommand-help-QDAQASPZ.js → per-subcommand-help-VKPV3OEY.js} +2 -2
  76. package/dist/{plugin-usage-CIGOOTX3.js → plugin-usage-3TZGROK7.js} +3 -3
  77. package/dist/{plugins-HQTXUD6A.js → plugins-ITH4SLO6.js} +4 -4
  78. package/dist/pre-launch/project-check.d.ts +2 -8
  79. package/dist/pre-launch.d.ts +1 -1
  80. package/dist/{project-manifest-7NSFVBM3.js → project-manifest-FTFDCCTZ.js} +2 -2
  81. package/dist/{project-picker-SVBXMPKX.js → project-picker-NZYJKQQC.js} +3 -3
  82. package/dist/provider-cloud-config.d.ts +4 -0
  83. package/dist/provider-config-utils.d.ts +1 -1
  84. package/dist/{providers-models-5Z2PJTEW.js → providers-models-W57I3QOA.js} +3 -3
  85. package/dist/{remote-GB5VXCCT.js → remote-C74BCNND.js} +5 -5
  86. package/dist/{rewind-JA3ZLCNM.js → rewind-7AULJS7F.js} +7 -5
  87. package/dist/sage-FFKUOCQL.js +475 -0
  88. package/dist/sage-connect.d.ts +62 -0
  89. package/dist/sage-hq-sync.d.ts +8 -0
  90. package/dist/sage-sync-ZMTHB477.js +69 -0
  91. package/dist/sandbox-TYGD6FI2.js +131 -0
  92. package/dist/services/sdd/project-context.d.ts +1 -1
  93. package/dist/{sessions-config-XHLXJ5C3.js → sessions-config-VE26SB56.js} +19 -8
  94. package/dist/short-circuit-flags-6LB3EGF7.js +10 -0
  95. package/dist/slash-commands/openai-quota.d.ts +12 -6
  96. package/dist/slash-commands/sandbox.d.ts +5 -0
  97. package/dist/slash-commands/scout-stats.d.ts +46 -0
  98. package/dist/slash-commands/sdd-inspect-commands.d.ts +9 -0
  99. package/dist/slash-commands/sdd-session-commands.d.ts +19 -0
  100. package/dist/slash-commands/sdd.d.ts +1 -1
  101. package/dist/slash-commands/zai-plan.d.ts +26 -0
  102. package/dist/{standalone-auto-update-TOTRGCSA.js → standalone-auto-update-VQC4GYCM.js} +3 -3
  103. package/dist/{standalone-update-LZO3MNLH.js → standalone-update-HZHDZZOR.js} +2 -2
  104. package/dist/subcommands/handlers/automation-credentials.d.ts +8 -0
  105. package/dist/subcommands/handlers/automation.d.ts +3 -0
  106. package/dist/subcommands/handlers/bench-experiments.d.ts +5 -0
  107. package/dist/subcommands/handlers/helpers.d.ts +1 -1
  108. package/dist/subcommands/handlers/sage-sync.d.ts +4 -0
  109. package/dist/subcommands/handlers/sage.d.ts +5 -0
  110. package/dist/subcommands/handlers/sandbox.d.ts +5 -0
  111. package/dist/{subcommands-SRRB3RAS.js → subcommands-QO7VYTSS.js} +2 -2
  112. package/dist/{tools-skills-GH24UCBY.js → tools-skills-33AI6K6S.js} +2 -2
  113. package/dist/tui-provider-quota-menu.d.ts +5 -0
  114. package/dist/{typesafe-WA5O3KVS.js → typesafe-NHC322W5.js} +27 -8
  115. package/dist/{typesafe-topic-replay-ZILIU3WS.js → typesafe-topic-replay-DB2AYL7V.js} +2 -2
  116. package/dist/{typesafe-triage-replay-FGAW7QM7.js → typesafe-triage-replay-27NDAZ3V.js} +2 -2
  117. package/dist/{update-TDZX4IL2.js → update-J5WHAFPE.js} +3 -3
  118. package/dist/{update-check-J5ZVKS73.js → update-check-VLVT4IV2.js} +2 -2
  119. package/dist/{version-help-XJJQ7YSH.js → version-help-ATOKGMTK.js} +2 -2
  120. package/dist/webui-server/prefs-seeding.d.ts +1 -0
  121. package/dist/webui-server/route-contexts.d.ts +1 -0
  122. package/dist/{webui-server-GCXIO3JY.js → webui-server-GQOVLQS3.js} +79 -40
  123. package/dist/webui-session-retirement.d.ts +10 -0
  124. package/dist/wiring/command-host-state.d.ts +2 -0
  125. package/dist/wiring/director-announcement.d.ts +3 -1
  126. package/dist/wiring/session-establishment.d.ts +10 -8
  127. package/dist/wiring/session-runtime.d.ts +1 -1
  128. package/dist/wiring/session.d.ts +3 -0
  129. package/package.json +30 -29
  130. package/dist/auto-discover-providers-DXR25GTG.js +0 -7
  131. package/dist/chunk-3ZTLPNEQ.js +0 -58
  132. package/dist/chunk-D5GB5MHA.js +0 -87
  133. package/dist/chunk-SIGUWXAA.js +0 -43
  134. package/dist/hq-ttl-VJR65OBJ.js +0 -7
  135. package/dist/short-circuit-flags-BSIPTAPD.js +0 -10
@@ -12,14 +12,14 @@ import {
12
12
  nowIso,
13
13
  resolveActiveApiKey,
14
14
  writeKeysBack
15
- } from "./chunk-LUMETJFO.js";
16
- import {
17
- openBrowser
18
- } from "./chunk-DAKVBMD4.js";
15
+ } from "./chunk-ZYACRPLN.js";
19
16
  import {
20
17
  appendHistory,
21
18
  backupCurrent
22
- } from "./chunk-WSTVGC2C.js";
19
+ } from "./chunk-4BX2YDTQ.js";
20
+ import {
21
+ openBrowser
22
+ } from "./chunk-DAKVBMD4.js";
23
23
 
24
24
  // src/auth-menu/auth-menu-audit.ts
25
25
  import { appendFileSync } from "node:fs";
@@ -177,6 +177,16 @@ import {
177
177
  applyProviderAuthOutcome,
178
178
  createBuiltinProviderAuthRegistry
179
179
  } from "@wrongstack/providers/oauth";
180
+
181
+ // src/auth-menu/helpers.ts
182
+ async function loadProviders(deps) {
183
+ return loadConfigProviders(deps.profileConfigPath, deps.vault, {
184
+ warn: (msg) => deps.renderer.writeWarning(msg),
185
+ profileConfigPath: deps.profileConfigPath
186
+ });
187
+ }
188
+
189
+ // src/auth-menu/provider-auth-login.ts
180
190
  var defaultRegistry;
181
191
  function providerAuthRegistryFor(deps) {
182
192
  if (deps.providerAuthRegistry) return deps.providerAuthRegistry;
@@ -223,9 +233,11 @@ async function runProviderAuthLogin(deps, strategyId, opts = {}) {
223
233
  Sign in with ${strategy.label}`) + color.dim(` \u2192 ${opts.providerId ?? strategy.providerId}
224
234
  `)
225
235
  );
236
+ const saved = strategy.id === "chatgpt-api" ? (await loadProviders(deps))[opts.providerId ?? strategy.providerId] : void 0;
237
+ const credential = saved?.apiKeys?.find((key) => key.label === saved.activeKey) ?? saved?.apiKeys?.[0];
226
238
  session = await registry.begin(
227
239
  strategy.id,
228
- { modelsRegistry: deps.modelsRegistry },
240
+ { modelsRegistry: deps.modelsRegistry, ...credential ? { credential } : {} },
229
241
  controller.signal
230
242
  );
231
243
  let outcome;
@@ -293,18 +305,18 @@ import { color as color3 } from "@wrongstack/core/utils";
293
305
  import { authProfileAliasError } from "@wrongstack/providers";
294
306
  import { probeLocalLlm } from "@wrongstack/runtime/probe";
295
307
 
296
- // src/auth-menu/helpers.ts
297
- async function loadProviders(deps) {
298
- return loadConfigProviders(deps.profileConfigPath, deps.vault, {
299
- warn: (msg) => deps.renderer.writeWarning(msg),
300
- profileConfigPath: deps.profileConfigPath
301
- });
302
- }
303
-
304
308
  // src/auth-menu/local-presets.ts
305
309
  import { projectLocalProviderPresets } from "@wrongstack/providers/definitions";
306
310
  var LOCAL_LLM_PRESETS = projectLocalProviderPresets();
307
311
 
312
+ // src/auth-menu/index-input.ts
313
+ function parseAuthMenuIndex(raw) {
314
+ const value = raw.trim();
315
+ if (!/^\d+$/.test(value)) return void 0;
316
+ const index = Number(value);
317
+ return Number.isSafeInteger(index) && index > 0 ? index : void 0;
318
+ }
319
+
308
320
  // src/auth-menu/shared.ts
309
321
  import { color as color2 } from "@wrongstack/core/utils";
310
322
  function renderProviderLine(renderer, id, cfg, idx) {
@@ -726,8 +738,8 @@ ${color3.bold("Local LLM servers")} ${color3.dim("\u2014 pick one to pre-fill th
726
738
  ${color3.amber("?")} Pick ${color3.dim(`(1-${LOCAL_LLM_PRESETS.length}, q to quit)`)}: `
727
739
  )).trim().toLowerCase();
728
740
  if (!answer || answer === "q" || answer === "quit") return void 0;
729
- const num = Number.parseInt(answer, 10);
730
- if (!Number.isNaN(num) && num >= 1 && num <= LOCAL_LLM_PRESETS.length) {
741
+ const num = parseAuthMenuIndex(answer);
742
+ if (num !== void 0 && num <= LOCAL_LLM_PRESETS.length) {
731
743
  return LOCAL_LLM_PRESETS[num - 1];
732
744
  }
733
745
  const byId = LOCAL_LLM_PRESETS.find((p) => p.id === answer);
@@ -1926,6 +1938,7 @@ export {
1926
1938
  providerAuthStrategiesFor,
1927
1939
  runProviderAuthLogin,
1928
1940
  LOCAL_LLM_PRESETS,
1941
+ parseAuthMenuIndex,
1929
1942
  runAuthLocal,
1930
1943
  resolveOAuthKind,
1931
1944
  runOAuthLoginKind,
@@ -1944,4 +1957,4 @@ export {
1944
1957
  addCustomProvider,
1945
1958
  addKeyForProvider
1946
1959
  };
1947
- //# sourceMappingURL=chunk-2ERX3RPN.js.map
1960
+ //# sourceMappingURL=chunk-P3GRLV47.js.map
@@ -33,14 +33,16 @@ function boolFlag(flags, names) {
33
33
  }
34
34
  function parsePositiveInteger(value, label) {
35
35
  if (value === void 0) throw new Error(`${label} is required`);
36
- const parsed = Number.parseInt(value, 10);
37
- if (!Number.isInteger(parsed) || parsed <= 0)
36
+ const trimmed = value.trim();
37
+ const parsed = /^\d+$/.test(trimmed) ? Number(trimmed) : Number.NaN;
38
+ if (!Number.isSafeInteger(parsed) || parsed <= 0)
38
39
  throw new Error(`${label} must be a positive integer`);
39
40
  return parsed;
40
41
  }
41
42
  function parsePort(value) {
42
43
  if (value === void 0) return void 0;
43
- const parsed = Number.parseInt(value, 10);
44
+ const trimmed = value.trim();
45
+ const parsed = /^\d+$/.test(trimmed) ? Number(trimmed) : Number.NaN;
44
46
  if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) {
45
47
  throw new Error("--port must be a port between 1 and 65535");
46
48
  }
@@ -125,4 +127,4 @@ export {
125
127
  writeWebuiSessionChildReady,
126
128
  writeWebuiSessionChildError
127
129
  };
128
- //# sourceMappingURL=chunk-ZMX5HRLI.js.map
130
+ //# sourceMappingURL=chunk-P3Q3KMFH.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-U3SS4NRH.js";
4
4
  import {
5
5
  checkForUpdate
6
- } from "./chunk-RZ4ZDRYA.js";
6
+ } from "./chunk-DIOODAYM.js";
7
7
 
8
8
  // src/subcommands/handlers/update.ts
9
9
  import { spawn } from "node:child_process";
@@ -80,8 +80,8 @@ async function runUpdateCommand(args, deps) {
80
80
  }
81
81
  if (isStandaloneBinary()) {
82
82
  const [{ updateStandaloneBinary }, { standaloneUpdater }, { STANDALONE_TARGET }] = await Promise.all([
83
- import("./standalone-update-LZO3MNLH.js"),
84
- import("./standalone-auto-update-TOTRGCSA.js"),
83
+ import("./standalone-update-HZHDZZOR.js"),
84
+ import("./standalone-auto-update-VQC4GYCM.js"),
85
85
  import("./version-JB2UAV2A.js")
86
86
  ]);
87
87
  const updater = standaloneUpdater({
@@ -406,4 +406,4 @@ export {
406
406
  detectUpdatePackageManager,
407
407
  detectUpdatePackageName
408
408
  };
409
- //# sourceMappingURL=chunk-KOEO4CJG.js.map
409
+ //# sourceMappingURL=chunk-PGNERAZL.js.map
@@ -1689,7 +1689,7 @@ import { WebSocket } from "ws";
1689
1689
  var HQ_SNAPSHOT_BROADCAST_DEBOUNCE_MS = 100;
1690
1690
  var HQ_SNAPSHOT_PERSIST_MIN_INTERVAL_MS = 3e3;
1691
1691
  var HQ_BROWSER_MAX_BUFFERED_BYTES = 32 * 1024 * 1024;
1692
- function sendGuarded(ws, data) {
1692
+ function sendGuarded(ws, data, callback) {
1693
1693
  if (ws.readyState !== WebSocket.OPEN) return false;
1694
1694
  const buffered = Number.isFinite(ws.bufferedAmount) ? ws.bufferedAmount : 0;
1695
1695
  if (buffered + Buffer.byteLength(data, "utf8") > HQ_BROWSER_MAX_BUFFERED_BYTES) {
@@ -1704,7 +1704,8 @@ function sendGuarded(ws, data) {
1704
1704
  return false;
1705
1705
  }
1706
1706
  try {
1707
- ws.send(data);
1707
+ if (callback) ws.send(data, callback);
1708
+ else ws.send(data);
1708
1709
  return true;
1709
1710
  } catch {
1710
1711
  return false;
@@ -2888,8 +2889,8 @@ async function handleApiAgentMessages(req, res, match, agentMessages) {
2888
2889
  // src/hq-server/routes/system-handlers.ts
2889
2890
  async function handleApiSystemUpdate(res) {
2890
2891
  const [{ checkForUpdate }, { detectUpdatePackageName }] = await Promise.all([
2891
- import("./update-check-J5ZVKS73.js"),
2892
- import("./update-TDZX4IL2.js")
2892
+ import("./update-check-VLVT4IV2.js"),
2893
+ import("./update-J5WHAFPE.js")
2893
2894
  ]);
2894
2895
  const packageName = detectUpdatePackageName();
2895
2896
  const info = await checkForUpdate({ packageName });
@@ -3770,7 +3771,8 @@ function createHqServerShutdown(params) {
3770
3771
  params.persistence.eventLog.drain(),
3771
3772
  params.persistence.snapshotStore.drain(),
3772
3773
  params.persistence.timeseries.drain(),
3773
- params.persistence.kanban.drain()
3774
+ params.persistence.kanban.drain(),
3775
+ params.persistence.sage?.drain()
3774
3776
  ]).then(() => clearHqRuntimeMarker(params.dataDir, params.hqUrl)).catch(() => void 0).finally(() => res());
3775
3777
  });
3776
3778
  });
@@ -3849,16 +3851,56 @@ import {
3849
3851
  tightenHqRedactionPolicy as tightenHqRedactionPolicy2,
3850
3852
  tokenHasCapability as tokenHasCapability3
3851
3853
  } from "@wrongstack/core/hq";
3854
+ import { toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
3852
3855
  import { WebSocket as WebSocket3 } from "ws";
3853
3856
 
3857
+ // src/hq-server/sage-sync-send.ts
3858
+ import { chunkHqSageRecords } from "@wrongstack/core/hq";
3859
+ async function sendSageSnapshot(ws, snapshot) {
3860
+ for (const part of chunkHqSageRecords(snapshot.projectId, snapshot.records)) {
3861
+ const delivered = await new Promise((resolve) => {
3862
+ let settled = false;
3863
+ const finish = (ok) => {
3864
+ if (settled) return;
3865
+ settled = true;
3866
+ clearTimeout(timer);
3867
+ ws.removeListener("close", onClose);
3868
+ resolve(ok);
3869
+ };
3870
+ const onClose = () => finish(false);
3871
+ const timer = setTimeout(() => {
3872
+ finish(false);
3873
+ try {
3874
+ ws.terminate();
3875
+ } catch {
3876
+ }
3877
+ }, 1e4);
3878
+ timer.unref?.();
3879
+ ws.once("close", onClose);
3880
+ const accepted = sendGuarded(
3881
+ ws,
3882
+ JSON.stringify({ type: "hq.sage_snapshot", payload: part }),
3883
+ (error) => finish(!error)
3884
+ );
3885
+ if (!accepted) finish(false);
3886
+ });
3887
+ if (!delivered) return false;
3888
+ }
3889
+ return true;
3890
+ }
3891
+
3854
3892
  // src/hq-server/ws-client-events.ts
3855
3893
  import {
3894
+ chunkHqSageRecords as chunkHqSageRecords2,
3856
3895
  HQ_TRANSCRIPT_TEXT_CAP,
3896
+ isHqSageSnapshotPayload,
3897
+ MAX_HQ_SAGE_RECORD_BYTES,
3857
3898
  parseHqEventPayload,
3858
3899
  redactHqEvent,
3859
3900
  tightenHqRedactionPolicy,
3860
3901
  tokenHasCapability as tokenHasCapability2
3861
3902
  } from "@wrongstack/core/hq";
3903
+ import { toErrorMessage } from "@wrongstack/core/utils";
3862
3904
  function fanoutKanbanDelta(message, clients, _browsers, projectId) {
3863
3905
  let clientsNotified = 0;
3864
3906
  for (const peer of clients.values()) {
@@ -3908,12 +3950,33 @@ function handleIncomingClientEvent(ws, incomingEvent, clients, browsers, auth, s
3908
3950
  // Chat-transcript events carry full turns — the generic 500-char
3909
3951
  // summary cap would truncate them a second time after the
3910
3952
  // publisher already applied the transcript cap.
3911
- ...incomingEvent.type === "session.transcript" || incomingEvent.type === "agent.message" ? { maxSummaryLength: HQ_TRANSCRIPT_TEXT_CAP } : {}
3953
+ ...incomingEvent.type === "sage.snapshot" ? { maxSummaryLength: MAX_HQ_SAGE_RECORD_BYTES } : incomingEvent.type === "session.transcript" || incomingEvent.type === "agent.message" ? { maxSummaryLength: HQ_TRANSCRIPT_TEXT_CAP } : {}
3912
3954
  }
3913
3955
  ).value;
3914
3956
  if (event.type === "client.heartbeat") {
3915
3957
  return;
3916
3958
  }
3959
+ if (event.type === "sage.snapshot") {
3960
+ const payload = event.payload;
3961
+ if (!isHqSageSnapshotPayload(payload) || payload.projectId !== client.projectId || !persistence?.sage)
3962
+ return;
3963
+ void persistence.sage.merge(payload).then((merged) => {
3964
+ for (const part of chunkHqSageRecords2(client.projectId, merged.records)) {
3965
+ fanoutKanbanDelta(
3966
+ JSON.stringify({ type: "hq.sage_snapshot", payload: part }),
3967
+ clients,
3968
+ browsers,
3969
+ client.projectId
3970
+ );
3971
+ }
3972
+ }).catch(
3973
+ (error) => process.stderr.write(
3974
+ `${JSON.stringify({ level: "warn", event: "hq.sage_sync_failed", projectId: client.projectId, message: toErrorMessage(error) })}
3975
+ `
3976
+ )
3977
+ );
3978
+ return;
3979
+ }
3917
3980
  if (event.type === "kanban.snapshot") {
3918
3981
  const payload = event.payload;
3919
3982
  if (payload.projectId !== client.projectId || persistence === void 0) return;
@@ -3934,7 +3997,7 @@ function handleIncomingClientEvent(ws, incomingEvent, clients, browsers, auth, s
3934
3997
  JSON.stringify({
3935
3998
  level: "warn",
3936
3999
  event: "hq.kanban_merge_failed",
3937
- message: error instanceof Error ? error.message : String(error),
4000
+ message: toErrorMessage(error),
3938
4001
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
3939
4002
  })
3940
4003
  );
@@ -4343,7 +4406,7 @@ function handleBrowser(ws, snapshotBroadcaster, browsers, eventLog) {
4343
4406
  JSON.stringify({
4344
4407
  level: "warn",
4345
4408
  event: "hq.browser_socket_error",
4346
- message: err instanceof Error ? err.message : String(err),
4409
+ message: toErrorMessage2(err),
4347
4410
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
4348
4411
  })
4349
4412
  );
@@ -4424,7 +4487,7 @@ function handleClient(ws, clients, browsers, eventLog, auth, snapshotBroadcaster
4424
4487
  JSON.stringify({
4425
4488
  level: "warn",
4426
4489
  event: "hq.client_socket_error",
4427
- message: err instanceof Error ? err.message : String(err),
4490
+ message: toErrorMessage2(err),
4428
4491
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
4429
4492
  })
4430
4493
  );
@@ -4525,6 +4588,14 @@ function handleClient(ws, clients, browsers, eventLog, auth, snapshotBroadcaster
4525
4588
  sendGuarded(ws, JSON.stringify({ type: "hq.kanban_snapshot", payload: p }));
4526
4589
  }).catch(() => void 0);
4527
4590
  }
4591
+ if (persistence?.sage !== void 0) {
4592
+ void persistence.sage.load(client.projectId).then((snapshot) => sendSageSnapshot(ws, snapshot)).catch(
4593
+ (error) => process.stderr.write(
4594
+ `${JSON.stringify({ level: "warn", event: "hq.sage_restore_failed", projectId: client.projectId, message: toErrorMessage2(error) })}
4595
+ `
4596
+ )
4597
+ );
4598
+ }
4528
4599
  const event = redactHqEvent2(
4529
4600
  {
4530
4601
  id: randomUUID5(),
@@ -5296,4 +5367,4 @@ export {
5296
5367
  startHqServer,
5297
5368
  HqInsecureExposureError2 as HqInsecureExposureError
5298
5369
  };
5299
- //# sourceMappingURL=chunk-ENRYW73H.js.map
5370
+ //# sourceMappingURL=chunk-RQ4UBKYH.js.map
@@ -66,7 +66,7 @@ async function downloadReleaseAssetToFile(url, file, options) {
66
66
  throw new Error(`download ${url} is too large`);
67
67
  }
68
68
  hash.update(value);
69
- await out.write(value);
69
+ await out.writeFile(value);
70
70
  }
71
71
  } finally {
72
72
  reader.releaseLock();
@@ -326,4 +326,4 @@ export {
326
326
  installExecutableFrom,
327
327
  updateStandaloneBinary
328
328
  };
329
- //# sourceMappingURL=chunk-X756ZS72.js.map
329
+ //# sourceMappingURL=chunk-SUDNPYWD.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  mutateConfigProviders
3
- } from "./chunk-LUMETJFO.js";
3
+ } from "./chunk-ZYACRPLN.js";
4
4
  import {
5
5
  activeProfileConfigPath
6
6
  } from "./chunk-YMXXOOFN.js";
@@ -8,13 +8,22 @@ import {
8
8
  // src/wiring/provider-persisters.ts
9
9
  import {
10
10
  applyProviderOAuthRefresh,
11
+ createSubscriptionRefreshTransaction,
11
12
  matchesActiveProviderCredential,
13
+ setAccountQuotaReporting,
12
14
  setOAuthTokenPersister,
13
- setProviderModelPersister
15
+ setProviderModelPersister,
16
+ setSubscriptionRefreshTransaction
14
17
  } from "@wrongstack/providers";
15
18
  import { applyProviderOAuthRefresh as applyProviderOAuthRefresh2 } from "@wrongstack/providers";
16
19
  function installProviderPersisters(args) {
17
20
  const profileConfigPath = activeProfileConfigPath(args.paths, args.config);
21
+ setAccountQuotaReporting(true);
22
+ setSubscriptionRefreshTransaction(
23
+ createSubscriptionRefreshTransaction(
24
+ (mutator) => mutateConfigProviders(profileConfigPath, args.vault, mutator)
25
+ )
26
+ );
18
27
  setOAuthTokenPersister((providerId, creds, source) => {
19
28
  void mutateConfigProviders(profileConfigPath, args.vault, (all) => {
20
29
  const p = all[providerId];
@@ -27,7 +36,6 @@ function installProviderPersisters(args) {
27
36
  );
28
37
  });
29
38
  setProviderModelPersister((providerId, models, source) => {
30
- if (models.length === 0) return;
31
39
  void mutateConfigProviders(profileConfigPath, args.vault, (all) => {
32
40
  const p = all[providerId];
33
41
  if (!p) return;
@@ -43,4 +51,4 @@ export {
43
51
  installProviderPersisters,
44
52
  applyProviderOAuthRefresh2 as applyProviderOAuthRefresh
45
53
  };
46
- //# sourceMappingURL=chunk-LDCGZJTC.js.map
54
+ //# sourceMappingURL=chunk-TWSQTQKR.js.map
@@ -0,0 +1,37 @@
1
+ import {
2
+ loadConfigProviders,
3
+ mutateConfigProviders
4
+ } from "./chunk-ZYACRPLN.js";
5
+
6
+ // src/provider-cloud-config.ts
7
+ import {
8
+ cloudFieldsForProvider,
9
+ parseNativeCloudSettings
10
+ } from "@wrongstack/core/cloud-provider";
11
+ async function providerCloudConfig(id, updates, configPath, vault) {
12
+ if (!/^[\w.-]{1,128}$/.test(id) || ["__proto__", "constructor", "prototype"].includes(id))
13
+ throw new Error("Invalid provider id");
14
+ if (updates === void 0) {
15
+ const providers = await loadConfigProviders(configPath, vault);
16
+ if (!Object.hasOwn(providers, id)) throw new Error("Saved provider not found");
17
+ return parseNativeCloudSettings(providers[id]?.cloud ?? {});
18
+ }
19
+ let saved = {};
20
+ await mutateConfigProviders(configPath, vault, (providers) => {
21
+ if (!Object.hasOwn(providers, id)) throw new Error("Saved provider not found");
22
+ const provider = providers[id];
23
+ const fields = cloudFieldsForProvider(provider.type || id);
24
+ if (!fields.length) throw new Error("This provider has no native cloud routing settings");
25
+ const parsed = updates === null ? {} : parseNativeCloudSettings(updates);
26
+ if (Object.keys(parsed).some((field) => !fields.includes(field)))
27
+ throw new Error("Cloud setting does not apply to this provider");
28
+ saved = updates === null ? {} : parseNativeCloudSettings({ ...provider.cloud, ...updates });
29
+ provider.cloud = saved;
30
+ });
31
+ return saved;
32
+ }
33
+
34
+ export {
35
+ providerCloudConfig
36
+ };
37
+ //# sourceMappingURL=chunk-TXAFIERF.js.map
@@ -8,6 +8,7 @@ var TTL_UNIT_MS = {
8
8
  d: 864e5,
9
9
  w: 6048e5
10
10
  };
11
+ var MAX_SAFE_TTL_MS = 864e13;
11
12
  function parseTokenTtlValue(raw) {
12
13
  const trimmed = raw.trim();
13
14
  if (trimmed.length === 0) {
@@ -18,6 +19,9 @@ function parseTokenTtlValue(raw) {
18
19
  if (!Number.isFinite(ms) || ms <= 0) {
19
20
  return { error: `TTL value must be positive (got ${raw})` };
20
21
  }
22
+ if (!Number.isSafeInteger(ms) || ms > MAX_SAFE_TTL_MS) {
23
+ return { error: `TTL value exceeds maximum safe duration (got ${raw})` };
24
+ }
21
25
  return { value: ms };
22
26
  }
23
27
  const match = /^(?<value>\d+)(?<unit>ms|s|m|h|d|w)$/i.exec(trimmed);
@@ -28,7 +32,11 @@ function parseTokenTtlValue(raw) {
28
32
  if (!Number.isFinite(value) || value <= 0 || multiplier === void 0) {
29
33
  return { error: `TTL value must be positive with a valid unit (got ${raw})` };
30
34
  }
31
- return { value: value * multiplier };
35
+ const totalMs = value * multiplier;
36
+ if (!Number.isSafeInteger(value) || !Number.isSafeInteger(totalMs) || totalMs > MAX_SAFE_TTL_MS) {
37
+ return { error: `TTL value exceeds maximum safe duration (got ${raw})` };
38
+ }
39
+ return { value: totalMs };
32
40
  }
33
41
  return {
34
42
  error: `TTL must be a positive integer (milliseconds) or <number><unit> where unit is one of ms, s, m, h, d, w (got ${raw})`
@@ -38,4 +46,4 @@ function parseTokenTtlValue(raw) {
38
46
  export {
39
47
  parseTokenTtlValue
40
48
  };
41
- //# sourceMappingURL=chunk-UZ2TMHNH.js.map
49
+ //# sourceMappingURL=chunk-UKP7H2U4.js.map
@@ -56,6 +56,11 @@ var helpCmd = async (_args, deps) => {
56
56
  ["wstack config-export | config-import", "Move behaviour settings via ./wstack-config.json"],
57
57
  ["wstack mcp", "MCP servers: list, add, remove, serve"],
58
58
  ["wstack import-claude-code", "Import MCP servers from Claude Code (preview; --apply)"],
59
+ [
60
+ "wstack sage connect",
61
+ "SAGE memory in Claude Code, Codex, Cursor, Antigravity (MCP + skill)"
62
+ ],
63
+ ["wstack sage sync", "Keep project SAGE memory synchronized through HQ"],
59
64
  ["wstack plugin", "Plugins: list, install, enable, disable, remove"],
60
65
  ["wstack tools | skills", "List registered tools / discovered skills"],
61
66
  ["wstack typesafe", "TypeSafe account: status, login, test"],
@@ -78,7 +83,7 @@ var helpCmd = async (_args, deps) => {
78
83
  ["--provider <id> --model <id>", "Provider and model for this run"],
79
84
  ["--fallback-model <a,b,...>", "Models to fall back to when the primary is unavailable"],
80
85
  ["--effort <level>", "Reasoning effort: none|minimal|low|medium|high|xhigh|max"],
81
- ["--system-prompt lite|pro|default", "Bundled system-prompt variant"],
86
+ ["--system-prompt lite|pro|scout|default", "Bundled system-prompt variant"],
82
87
  [
83
88
  "--append-system-prompt <text> | --append-system-prompt-file <path>",
84
89
  "Add instructions to the host agent prompt for this run"
@@ -151,4 +156,4 @@ export {
151
156
  versionCmd,
152
157
  helpCmd
153
158
  };
154
- //# sourceMappingURL=chunk-5JYDKG5B.js.map
159
+ //# sourceMappingURL=chunk-WHEYHDIE.js.map
@@ -23,8 +23,8 @@ var APPLIED_FMT = `
23
23
  `;
24
24
  async function printStandaloneUpdateNotice(info, config) {
25
25
  const [{ autoUpdateEnabled, standaloneUpdater, takeAppliedUpdate }, { isNewer }, version] = await Promise.all([
26
- import("./standalone-auto-update-TOTRGCSA.js"),
27
- import("./update-check-J5ZVKS73.js"),
26
+ import("./standalone-auto-update-VQC4GYCM.js"),
27
+ import("./update-check-VLVT4IV2.js"),
28
28
  import("./version-JB2UAV2A.js")
29
29
  ]);
30
30
  const applied = takeAppliedUpdate();
@@ -47,7 +47,7 @@ async function printUpdateNotice(initialUpdateInfo, config) {
47
47
  const ac = new AbortController();
48
48
  const timer = setTimeout(() => ac.abort(), 2e3);
49
49
  try {
50
- const { checkForUpdate } = await import("./update-check-J5ZVKS73.js");
50
+ const { checkForUpdate } = await import("./update-check-VLVT4IV2.js");
51
51
  info = await checkForUpdate(ac.signal);
52
52
  } catch {
53
53
  } finally {
@@ -102,4 +102,4 @@ export {
102
102
  applySessionShellDefault,
103
103
  runPreflight
104
104
  };
105
- //# sourceMappingURL=chunk-LBPLTTZ6.js.map
105
+ //# sourceMappingURL=chunk-WTJDSTYD.js.map
@@ -1,10 +1,10 @@
1
+ import {
2
+ parseArgs
3
+ } from "./chunk-MPQCHBDJ.js";
1
4
  import {
2
5
  helpCmd,
3
6
  versionCmd
4
- } from "./chunk-5JYDKG5B.js";
5
- import {
6
- parseArgs
7
- } from "./chunk-Q4INH2DG.js";
7
+ } from "./chunk-WHEYHDIE.js";
8
8
 
9
9
  // src/boot/short-circuit-flags.ts
10
10
  async function handleHelpVersionShortCircuit(argv) {
@@ -22,11 +22,11 @@ async function handleHelpVersionShortCircuit(argv) {
22
22
  }
23
23
  if (earlyFlags["help"] === true) {
24
24
  if (positional.length > 0) {
25
- const { subcommandNames } = await import("./subcommands-SRRB3RAS.js");
25
+ const { subcommandNames } = await import("./subcommands-QO7VYTSS.js");
26
26
  if (subcommandNames.includes(positional[0])) {
27
27
  const first = positional[0];
28
28
  const deep = positional[1];
29
- const { renderDeepHelp, renderFocusedHelp } = await import("./per-subcommand-help-QDAQASPZ.js");
29
+ const { renderDeepHelp, renderFocusedHelp } = await import("./per-subcommand-help-VKPV3OEY.js");
30
30
  if (deep && renderDeepHelp(`${first}:${deep}`, stubRenderer)) {
31
31
  return 0;
32
32
  }
@@ -43,4 +43,4 @@ async function handleHelpVersionShortCircuit(argv) {
43
43
  export {
44
44
  handleHelpVersionShortCircuit
45
45
  };
46
- //# sourceMappingURL=chunk-L5TD7UIG.js.map
46
+ //# sourceMappingURL=chunk-WXJH4F6K.js.map
@@ -4,7 +4,12 @@ import { createHash } from "node:crypto";
4
4
  import * as fs from "node:fs/promises";
5
5
  import * as path from "node:path";
6
6
  import { ConfigError } from "@wrongstack/core/types";
7
- import { readProjectIdentity, withFileLock, wstackGlobalRoot } from "@wrongstack/core/utils";
7
+ import {
8
+ atomicWrite,
9
+ readProjectIdentity,
10
+ withFileLock,
11
+ wstackGlobalRoot
12
+ } from "@wrongstack/core/utils";
8
13
  function projectsJsonPath(globalConfigPath) {
9
14
  const base = globalConfigPath ? path.dirname(globalConfigPath) : wstackGlobalRoot();
10
15
  return path.join(base, "projects.json");
@@ -44,8 +49,7 @@ async function loadManifest(globalConfigPath) {
44
49
  }
45
50
  async function saveManifest(manifest, globalConfigPath) {
46
51
  const file = projectsJsonPath(globalConfigPath);
47
- await fs.mkdir(path.dirname(file), { recursive: true });
48
- await fs.writeFile(file, JSON.stringify(manifest, null, 2), "utf8");
52
+ await atomicWrite(file, JSON.stringify(manifest, null, 2), { encoding: "utf8" });
49
53
  }
50
54
  function generateSlug(root) {
51
55
  const base = path.basename(root).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "project";
@@ -116,4 +120,4 @@ export {
116
120
  ensureProjectDataDir,
117
121
  touchProjectInManifest
118
122
  };
119
- //# sourceMappingURL=chunk-IS2PPBQV.js.map
123
+ //# sourceMappingURL=chunk-X4LW5CZM.js.map
@@ -83,7 +83,10 @@ var MODEL_PROFILES = [
83
83
  ];
84
84
  function fmtTokens(n) {
85
85
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
86
- if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
86
+ if (n >= 1e3) {
87
+ const k = (n / 1e3).toFixed(1);
88
+ return Number(k) < 1e3 ? `${k}k` : `${(n / 1e6).toFixed(1)}M`;
89
+ }
87
90
  return String(n);
88
91
  }
89
92
  function fmtMs(ms) {
@@ -322,7 +325,16 @@ async function runModeldiagEval(args, deps, providers, config, hasKey) {
322
325
  const providerFilter = providersValue ? providersValue.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
323
326
  const maxEq = evalArgs.find((a) => a.startsWith("--max="));
324
327
  const maxValue = maxEq?.replace("--max=", "") ?? (typeof deps.flags?.["max"] === "string" ? deps.flags["max"] : void 0);
325
- const maxModels = maxValue ? Math.max(1, parseInt(maxValue, 10) || 2) : 2;
328
+ let maxModels = 2;
329
+ if (maxValue !== void 0) {
330
+ const rawMax = maxValue.trim();
331
+ const parsedMax = /^\d+$/.test(rawMax) ? Number(rawMax) : Number.NaN;
332
+ if (!Number.isSafeInteger(parsedMax) || parsedMax < 1) {
333
+ writeLine(`${color2.amber(`Invalid --max value "${maxValue}". Use a positive integer.`)}`);
334
+ return 1;
335
+ }
336
+ maxModels = parsedMax;
337
+ }
326
338
  const quick = evalArgs.includes("--quick") || deps.flags?.["quick"] === true || deps.flags?.["quick"] === "true";
327
339
  const modelsPerCat = quick ? 1 : maxModels;
328
340
  const roleFilter = evalArgs.find((a) => !a.startsWith("--"));
@@ -369,9 +381,9 @@ ${color2.dim('Enter numbers or provider IDs (comma-separated, or "all"):')}
369
381
  } else {
370
382
  targetProviderIds = [];
371
383
  for (const part of selected.split(",").map((s) => s.trim())) {
372
- const idx = parseInt(part, 10);
373
- if (idx >= 1 && idx <= keyedProviderIds.length) {
374
- const pid = keyedProviderIds[idx - 1];
384
+ const index = /^\d+$/.test(part) ? Number(part) : Number.NaN;
385
+ if (Number.isSafeInteger(index) && index >= 1 && index <= keyedProviderIds.length) {
386
+ const pid = keyedProviderIds[index - 1];
375
387
  if (!targetProviderIds.includes(pid)) targetProviderIds.push(pid);
376
388
  } else if (keyedProviderIds.includes(part)) {
377
389
  if (!targetProviderIds.includes(part)) targetProviderIds.push(part);
@@ -546,4 +558,4 @@ export {
546
558
  createProviderForId,
547
559
  runModeldiagEval
548
560
  };
549
- //# sourceMappingURL=chunk-BBHWW6LR.js.map
561
+ //# sourceMappingURL=chunk-YL4KCHZG.js.map
@@ -140,7 +140,7 @@ async function mutateConfigProviders(configPath, vault, mutator, profileConfigPa
140
140
  decrypted["model"],
141
141
  typeof decrypted["provider"] === "string" ? providers[decrypted["provider"]] : void 0
142
142
  ]);
143
- mutator(providers, decrypted);
143
+ await mutator(providers, decrypted);
144
144
  for (const id of previousProviderIds) {
145
145
  if (!Object.hasOwn(providers, id)) removeProviderFallbackReferences(decrypted, id);
146
146
  }
@@ -168,4 +168,4 @@ export {
168
168
  mutateConfigProviders,
169
169
  nowIso
170
170
  };
171
- //# sourceMappingURL=chunk-LUMETJFO.js.map
171
+ //# sourceMappingURL=chunk-ZYACRPLN.js.map