@wrongstack/core 0.313.0 → 0.313.1

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 (182) hide show
  1. package/dist/chronicle/index.js +84 -6391
  2. package/dist/chronicle/project-server.js +84 -4868
  3. package/dist/chunk-2BUUIMQB.js +225 -0
  4. package/dist/chunk-2FK4WTFF.js +207 -0
  5. package/dist/chunk-2FQL4PDC.js +292 -0
  6. package/dist/chunk-2KKODIQU.js +2256 -0
  7. package/dist/chunk-2YU4WVBW.js +134 -0
  8. package/dist/chunk-3E244UDA.js +356 -0
  9. package/dist/chunk-3XPVB7BA.js +135 -0
  10. package/dist/chunk-4LJJYBAU.js +388 -0
  11. package/dist/chunk-4VWO3ZXL.js +342 -0
  12. package/dist/chunk-4XV6IR37.js +187 -0
  13. package/dist/chunk-4ZHTKJHM.js +183 -0
  14. package/dist/chunk-52RTVH4M.js +361 -0
  15. package/dist/chunk-57GEWK5X.js +26 -0
  16. package/dist/chunk-5DSMEVA4.js +931 -0
  17. package/dist/chunk-5RP3QTRL.js +1223 -0
  18. package/dist/chunk-5S437PRC.js +50 -0
  19. package/dist/chunk-5XDUGTKN.js +511 -0
  20. package/dist/chunk-62V2AFVG.js +422 -0
  21. package/dist/chunk-65RDIOR2.js +2470 -0
  22. package/dist/chunk-6AKOTGLM.js +597 -0
  23. package/dist/chunk-7ZHZE5EO.js +28 -0
  24. package/dist/chunk-A455ATZB.js +140 -0
  25. package/dist/chunk-AD7ZFZCS.js +46 -0
  26. package/dist/chunk-AI4LLQ2U.js +856 -0
  27. package/dist/chunk-ASX6AW36.js +789 -0
  28. package/dist/chunk-AT4V4XGI.js +3522 -0
  29. package/dist/chunk-AWNQ6ED6.js +311 -0
  30. package/dist/chunk-B4AMLZPB.js +9 -0
  31. package/dist/chunk-BAKVJLEV.js +417 -0
  32. package/dist/chunk-BJHVULHO.js +55 -0
  33. package/dist/chunk-CB2HFKTP.js +9 -0
  34. package/dist/chunk-CE4ZOCOI.js +1640 -0
  35. package/dist/chunk-CQQL4ZOQ.js +151 -0
  36. package/dist/chunk-DEIQMBD2.js +65 -0
  37. package/dist/chunk-E6I5RXVK.js +58 -0
  38. package/dist/chunk-EFEHDQGY.js +1589 -0
  39. package/dist/chunk-EODDVJBM.js +82 -0
  40. package/dist/chunk-EPC3GZD4.js +308 -0
  41. package/dist/chunk-FAYRX2AD.js +13 -0
  42. package/dist/chunk-FFSX2QDQ.js +362 -0
  43. package/dist/chunk-FHAMQS7Q.js +5856 -0
  44. package/dist/chunk-FIV4IJL7.js +2263 -0
  45. package/dist/chunk-FNXVT7HF.js +52 -0
  46. package/dist/chunk-FSWCWSTS.js +395 -0
  47. package/dist/chunk-FW5LDDMJ.js +16464 -0
  48. package/dist/chunk-FXQLIX3K.js +211 -0
  49. package/dist/chunk-G5AAKEEZ.js +228 -0
  50. package/dist/chunk-G5S3S5ZN.js +38 -0
  51. package/dist/chunk-GAZEWQEZ.js +231 -0
  52. package/dist/chunk-GFJOMSHG.js +125 -0
  53. package/dist/chunk-GFXZTHNI.js +158 -0
  54. package/dist/chunk-GM54GJBU.js +960 -0
  55. package/dist/chunk-GPQ3NJPR.js +900 -0
  56. package/dist/chunk-GTCU6DZ3.js +1 -0
  57. package/dist/chunk-H5E77KUJ.js +15 -0
  58. package/dist/chunk-H72H4XDU.js +1023 -0
  59. package/dist/chunk-HA4ZYA6T.js +178 -0
  60. package/dist/chunk-I45KAW2N.js +5020 -0
  61. package/dist/chunk-IQ35HMQL.js +1396 -0
  62. package/dist/chunk-IYFBFX34.js +86 -0
  63. package/dist/chunk-JJPMWPB6.js +109 -0
  64. package/dist/chunk-JTHKOYWU.js +663 -0
  65. package/dist/chunk-JVGPR3TS.js +365 -0
  66. package/dist/chunk-JVKB2TBL.js +48 -0
  67. package/dist/chunk-JX7VBZDK.js +31 -0
  68. package/dist/chunk-K3G6JBUC.js +5232 -0
  69. package/dist/chunk-K4YUNKU7.js +589 -0
  70. package/dist/chunk-KBZGE6LN.js +710 -0
  71. package/dist/chunk-KDQJCT2J.js +45 -0
  72. package/dist/chunk-KI4L2DUL.js +560 -0
  73. package/dist/chunk-KJ2ZTQSL.js +47 -0
  74. package/dist/chunk-KSJ5UTP7.js +154 -0
  75. package/dist/chunk-LHOA5DWA.js +28 -0
  76. package/dist/chunk-LX5QWLBL.js +27 -0
  77. package/dist/chunk-LZDDLNCZ.js +279 -0
  78. package/dist/chunk-M2WF6AXG.js +115 -0
  79. package/dist/chunk-M7BS2K6U.js +1 -0
  80. package/dist/chunk-NDBIPFNY.js +102 -0
  81. package/dist/chunk-NEMIWEXC.js +1199 -0
  82. package/dist/chunk-NFAYHPRH.js +323 -0
  83. package/dist/chunk-O37BQ65S.js +21 -0
  84. package/dist/chunk-O74MJHXU.js +187 -0
  85. package/dist/chunk-OJZEX73F.js +112 -0
  86. package/dist/chunk-PAAWLLZX.js +74 -0
  87. package/dist/chunk-PFXFQQRT.js +339 -0
  88. package/dist/chunk-PFZO3C6H.js +14 -0
  89. package/dist/chunk-PHH7LD45.js +113 -0
  90. package/dist/chunk-QRTG4XTI.js +188 -0
  91. package/dist/chunk-QVOVMXJR.js +1351 -0
  92. package/dist/chunk-RCQYT2I4.js +757 -0
  93. package/dist/chunk-RD6DEE36.js +1178 -0
  94. package/dist/chunk-RJIZEJ42.js +30 -0
  95. package/dist/chunk-RPOA7IAE.js +150 -0
  96. package/dist/chunk-SN2DQRL6.js +1172 -0
  97. package/dist/chunk-SQJVFEBV.js +41 -0
  98. package/dist/chunk-SQP64RCS.js +5391 -0
  99. package/dist/chunk-SVT4RNTR.js +49 -0
  100. package/dist/chunk-SWUFN7XM.js +43 -0
  101. package/dist/chunk-SXMVYC5H.js +174 -0
  102. package/dist/chunk-SZ6AYUIZ.js +23 -0
  103. package/dist/chunk-T3KGZBU5.js +3171 -0
  104. package/dist/chunk-TBRL2RCC.js +9 -0
  105. package/dist/chunk-TRT2HRWZ.js +18 -0
  106. package/dist/chunk-TYW2GI5I.js +1077 -0
  107. package/dist/chunk-UIWONWVG.js +4959 -0
  108. package/dist/chunk-VB3H5WWB.js +151 -0
  109. package/dist/chunk-W4A6QA3D.js +258 -0
  110. package/dist/chunk-WBPVKEEE.js +227 -0
  111. package/dist/chunk-WEBMSQP2.js +123 -0
  112. package/dist/chunk-WOEZV3Q4.js +333 -0
  113. package/dist/chunk-WQQON3SV.js +473 -0
  114. package/dist/chunk-WQTOVMGV.js +119 -0
  115. package/dist/chunk-WZO23AWO.js +2779 -0
  116. package/dist/chunk-XBDP4QPW.js +7 -0
  117. package/dist/chunk-XEBHSJLT.js +103 -0
  118. package/dist/chunk-XQ2ECNK3.js +1 -0
  119. package/dist/chunk-XQ2XGIBF.js +2086 -0
  120. package/dist/chunk-Y2GE5TSI.js +355 -0
  121. package/dist/chunk-YBUJCZ57.js +351 -0
  122. package/dist/chunk-YNCVSFGF.js +149 -0
  123. package/dist/chunk-YUPMXOGP.js +282 -0
  124. package/dist/chunk-YY6APYUM.js +49 -0
  125. package/dist/chunk-Z2IJUO45.js +691 -0
  126. package/dist/chunk-ZEHUCJHY.js +129 -0
  127. package/dist/chunk-ZYU2YOJ6.js +1496 -0
  128. package/dist/chunk-ZZ4V3WIZ.js +163 -0
  129. package/dist/coordination/agents/index.js +145 -6260
  130. package/dist/coordination/index.js +365 -34324
  131. package/dist/coordination/mailbox-project-server.js +48 -3276
  132. package/dist/coordination/provider-status-tracker.d.ts +4 -0
  133. package/dist/core/agent.d.ts +14 -1
  134. package/dist/core/index.js +267 -12480
  135. package/dist/core/model-ref.js +5 -23
  136. package/dist/core/provider-runner.d.ts +36 -1
  137. package/dist/design/index.js +50 -1087
  138. package/dist/execution/index.d.ts +1 -1
  139. package/dist/execution/index.js +1599 -21888
  140. package/dist/execution/prompt-enhancer.js +16 -535
  141. package/dist/execution/retry-policy.d.ts +31 -1
  142. package/dist/extension/index.js +7 -311
  143. package/dist/goal/index.js +33 -3435
  144. package/dist/hooks/index.js +14 -1138
  145. package/dist/hq/index.js +112 -5139
  146. package/dist/hq/protocol.js +21 -668
  147. package/dist/index.js +1410 -92656
  148. package/dist/infrastructure/index.js +64 -4811
  149. package/dist/kernel/events/provider-events.d.ts +15 -0
  150. package/dist/kernel/index.js +14 -992
  151. package/dist/models/index.js +40 -1117
  152. package/dist/notifications/index.js +3 -108
  153. package/dist/observability/index.js +17 -279
  154. package/dist/plugin/index.js +584 -14835
  155. package/dist/prompts/index.js +14 -948
  156. package/dist/registry/index.js +9 -822
  157. package/dist/registry-R23UBE7H.js +14 -0
  158. package/dist/replay/index.js +6 -84
  159. package/dist/review-finding-store-DKAV3AS6.js +21 -0
  160. package/dist/review-report-store-OWY3EC3N.js +19 -0
  161. package/dist/security/index.js +114 -2202
  162. package/dist/session-catalog/index.js +36 -2103
  163. package/dist/session-catalog/project-server.js +42 -1435
  164. package/dist/skills/index.js +35 -1578
  165. package/dist/storage/index.js +182 -15600
  166. package/dist/tasking/index.js +10 -676
  167. package/dist/tools/index.js +52 -9590
  168. package/dist/types/config/autonomy.d.ts +5 -0
  169. package/dist/types/config/ui.d.ts +1 -1
  170. package/dist/types/errors.d.ts +18 -0
  171. package/dist/types/index.js +121 -1342
  172. package/dist/types/provider-runner.d.ts +8 -0
  173. package/dist/types/session-markers.js +8 -144
  174. package/dist/utils/error.js +3 -4
  175. package/dist/utils/expect-defined.js +3 -9
  176. package/dist/utils/heap-watchdog.js +6 -706
  177. package/dist/utils/index.js +269 -5685
  178. package/dist/utils/sage-output-block.js +5 -42
  179. package/dist/wiring/proxy-rewrite.d.ts +18 -0
  180. package/dist/wiring/proxy-rewrite.js +18 -121
  181. package/dist/worktree/index.js +6 -887
  182. package/package.json +4 -4
@@ -1,507 +1,36 @@
1
- // src/models/models-registry.ts
2
- import * as fs from "node:fs/promises";
3
- import * as path2 from "node:path";
4
-
5
- // src/infrastructure/logger.ts
6
- import * as fsp from "node:fs/promises";
7
- import * as path from "node:path";
8
-
9
- // src/utils/term.ts
10
- var hasStdout = () => typeof process !== "undefined" && !!process.stdout;
11
- function isStdoutTTY() {
12
- return hasStdout() && Boolean(process.stdout.isTTY);
13
- }
14
- var activeOutputGuard = null;
15
- function writeTo(s, stream) {
16
- if (!stream || typeof stream.write !== "function") return false;
17
- const guard = activeOutputGuard;
18
- if (!guard) {
19
- stream.write(s);
20
- return true;
21
- }
22
- guard.suspend();
23
- stream.write(s);
24
- guard.resume();
25
- return true;
26
- }
27
- function writeErr(s, stream = process.stderr) {
28
- return writeTo(s, stream);
29
- }
30
- var ESCAPE_TERMINATOR = Object.freeze({
31
- BEL: "\x07",
32
- // OSC 0 / OSC 2 (title)
33
- ST: "\x1B\\"
34
- // DCS / strict OSC
35
- });
36
-
37
- // src/utils/color.ts
38
- var isColorTty = () => {
39
- if (envFlag(process.env.NO_COLOR)) return false;
40
- if (envFlag(process.env.FORCE_COLOR)) return true;
41
- return isStdoutTTY();
42
- };
43
- function envFlag(value) {
44
- if (value === void 0) return false;
45
- if (value.trim() === "") return false;
46
- return !/^(0|false|no|off)$/i.test(value.trim());
47
- }
48
- var COLOR = isColorTty();
49
- var wrap = (open, close) => (s) => COLOR ? `\x1B[${open}m${s}\x1B[${close}m` : s;
50
- var color = {
51
- reset: wrap("0", "0"),
52
- bold: wrap("1", "22"),
53
- dim: wrap("2", "22"),
54
- italic: wrap("3", "23"),
55
- underline: wrap("4", "24"),
56
- red: wrap("31", "39"),
57
- green: wrap("32", "39"),
58
- yellow: wrap("33", "39"),
59
- blue: wrap("34", "39"),
60
- magenta: wrap("35", "39"),
61
- cyan: wrap("36", "39"),
62
- gray: wrap("90", "39"),
63
- amber: wrap("38;5;214", "39"),
64
- pink: wrap("38;5;205", "39"),
65
- bgRed: wrap("41", "49"),
66
- bgGreen: wrap("42", "49")
67
- };
68
-
69
- // src/infrastructure/logger.ts
70
- var LEVEL_RANK = {
71
- error: 0,
72
- warn: 1,
73
- info: 2,
74
- debug: 3,
75
- trace: 4
76
- };
77
- var COLORS = {
78
- error: color.red,
79
- warn: color.yellow,
80
- info: color.cyan,
81
- debug: color.gray,
82
- trace: color.dim
83
- };
84
- var LOG_LEVELS = /* @__PURE__ */ new Set(["error", "warn", "info", "debug", "trace"]);
85
- var LOG_FORMATS = /* @__PURE__ */ new Set(["pretty", "json"]);
86
- var DefaultLogger = class _DefaultLogger {
87
- /** How many file writes between rotation size checks (statSync is not free). */
88
- static ROTATE_CHECK_EVERY = 100;
89
- static MAX_PENDING_FILE_WRITES = 2e3;
90
- static MAX_PENDING_FILE_BYTES = 8 * 1024 * 1024;
91
- level;
92
- file;
93
- bindings;
94
- format;
95
- stderr;
96
- maxFileBytes;
97
- writesSinceRotateCheck = 0;
98
- /**
99
- * Serialized async tail for file writes. Every appendFile (and any
100
- * chained rotation) is awaited through this promise so file I/O
101
- * never overlaps itself — preserving the per-line ordering the
102
- * sync version had, but without blocking the caller thread. Any
103
- * rejection is swallowed (`catch(() => {})`) because logging must
104
- * never crash the host.
105
- *
106
- * Children share the parent's tail: `child.tail === parent.tail`
107
- * for the lifetime of the chain. Read/write access goes through
108
- * `_tail` so that, when a child has been wired to a parent, both
109
- * `enqueueRotate` and `log` always observe the parent's current tail
110
- * rather than a stale snapshot taken at `child()` time.
111
- */
112
- tail = Promise.resolve();
113
- parent = null;
114
- pendingFileWrites = 0;
115
- pendingFileBytes = 0;
116
- get root() {
117
- return this.parent ? this.parent.root : this;
118
- }
119
- /**
120
- * Resolve the current tail. For the root logger this is the field;
121
- * for a child logger we always read through the parent so that a
122
- * child's appends land on the parent's most recent tail, and a
123
- * parent's `flush()` waits for everything the child chained.
124
- */
125
- get _tail() {
126
- return this.parent ? this.parent._tail : this.tail;
127
- }
128
- set _tail(next) {
129
- if (this.parent) this.parent.tail = next;
130
- else this.tail = next;
131
- }
132
- constructor(opts = {}) {
133
- this.level = opts.level ?? parseLogLevel(process.env.WRONGSTACK_LOG_LEVEL);
134
- this.file = opts.file;
135
- this.bindings = opts.bindings ?? {};
136
- this.format = opts.format ?? parseLogFormat(process.env.WRONGSTACK_LOG_FORMAT);
137
- this.stderr = opts.stderr !== false;
138
- this.maxFileBytes = opts.maxFileBytes ?? 10 * 1024 * 1024;
139
- if (this.file) {
140
- const dir = path.dirname(this.file);
141
- this._tail = this._tail.then(async () => {
142
- await fsp.mkdir(dir, { recursive: true });
143
- }).catch(() => void 0);
144
- }
145
- }
146
- error(msg, ctx) {
147
- this.log("error", msg, ctx);
148
- }
149
- warn(msg, ctx) {
150
- this.log("warn", msg, ctx);
151
- }
152
- info(msg, ctx) {
153
- this.log("info", msg, ctx);
154
- }
155
- debug(msg, ctx) {
156
- this.log("debug", msg, ctx);
157
- }
158
- trace(msg, ctx) {
159
- this.log("trace", msg, ctx);
160
- }
161
- child(bindings) {
162
- const child = Object.create(_DefaultLogger.prototype);
163
- child.level = this.level;
164
- child.file = this.file;
165
- child.bindings = { ...this.bindings, ...bindings };
166
- child.format = this.format;
167
- child.stderr = this.stderr;
168
- child.maxFileBytes = this.maxFileBytes;
169
- child.parent = this;
170
- child.writesSinceRotateCheck = this.writesSinceRotateCheck;
171
- return child;
172
- }
173
- /**
174
- * Wait until all queued file writes (and any pending rotation) have
175
- * completed. `log()` is fire-and-forget by design — the caller never
176
- * blocks on disk — so tests, shutdown handlers, and processes that
177
- * need a deterministic "everything is on disk now" guarantee should
178
- * `await logger.flush()` before reading the file or exiting.
179
- */
180
- flush() {
181
- return this._tail;
182
- }
183
- /**
184
- * Size-based rotation: when the file outgrows `maxFileBytes`, rename it to
185
- * `<file>.1` (dropping the previous `.1`) so the live file restarts empty.
186
- * Checked on the first write and every ROTATE_CHECK_EVERY writes after.
187
- * Best-effort: a rename can fail on Windows while another process holds
188
- * the file — the next check retries. Multiple processes appending to the
189
- * same log all run this check; whoever crosses the threshold first wins.
190
- *
191
- * Async: the rotation runs on the file-write tail (so its writes don't
192
- * interleave with the next append), and the caller never blocks on a
193
- * statSync / renameSync syscall on the hot log path.
194
- */
195
- enqueueRotate(file) {
196
- if (this.writesSinceRotateCheck++ % _DefaultLogger.ROTATE_CHECK_EVERY !== 0) return;
197
- this._tail = this._tail.then(async () => {
198
- let st;
199
- try {
200
- st = await fsp.stat(file);
201
- } catch {
202
- return;
203
- }
204
- if (st.size < this.maxFileBytes) return;
205
- try {
206
- await fsp.rm(`${file}.1`, { force: true });
207
- await fsp.rename(file, `${file}.1`);
208
- } catch {
209
- }
210
- }).catch(() => void 0);
211
- }
212
- log(level, msg, ctx) {
213
- const r = LEVEL_RANK[level];
214
- const allowed = LEVEL_RANK[this.level];
215
- if (r > allowed) return;
216
- const ts = (/* @__PURE__ */ new Date()).toISOString();
217
- const entry = { ts, level, msg, ...this.bindings };
218
- if (ctx !== void 0) {
219
- entry.ctx = ctx instanceof Error ? { message: ctx.message, stack: ctx.stack } : ctx;
220
- }
221
- if (this.file) {
222
- const line = `${JSON.stringify(entry)}
223
- `;
224
- const bytes = Buffer.byteLength(line, "utf8");
225
- const root = this.root;
226
- if (root.pendingFileWrites < _DefaultLogger.MAX_PENDING_FILE_WRITES && bytes <= _DefaultLogger.MAX_PENDING_FILE_BYTES && root.pendingFileBytes + bytes <= _DefaultLogger.MAX_PENDING_FILE_BYTES) {
227
- root.pendingFileWrites += 1;
228
- root.pendingFileBytes += bytes;
229
- this.enqueueRotate(this.file);
230
- this._tail = this._tail.then(() => fsp.appendFile(this.file, line, { mode: 384 })).catch(() => void 0).finally(() => {
231
- root.pendingFileWrites = Math.max(0, root.pendingFileWrites - 1);
232
- root.pendingFileBytes = Math.max(0, root.pendingFileBytes - bytes);
233
- });
234
- }
235
- }
236
- if (!this.stderr) return;
237
- if (this.format === "json") {
238
- writeErr(`${JSON.stringify(entry)}
239
- `);
240
- } else {
241
- const head = `${color.dim(ts)} ${COLORS[level](level.toUpperCase().padEnd(5))} ${msg}`;
242
- if (ctx !== void 0) {
243
- writeErr(`${head} ${formatCtx(ctx)}
244
- `);
245
- } else {
246
- writeErr(`${head}
247
- `);
248
- }
249
- }
250
- }
251
- };
252
- function parseLogLevel(raw) {
253
- return raw && LOG_LEVELS.has(raw) ? raw : "info";
254
- }
255
- function parseLogFormat(raw) {
256
- return raw && LOG_FORMATS.has(raw) ? raw : "pretty";
257
- }
258
- function formatCtx(ctx) {
259
- if (ctx instanceof Error) return color.dim(ctx.message);
260
- if (typeof ctx === "string") return color.dim(ctx);
261
- try {
262
- return color.dim(JSON.stringify(ctx));
263
- } catch {
264
- return color.dim(String(ctx));
265
- }
266
- }
267
- var noOpLogger = {
268
- // 'error' is the quietest level the Logger contract offers; the methods
269
- // discard everything regardless, this only matters to level checks.
270
- level: "error",
271
- error: () => {
272
- },
273
- warn: () => {
274
- },
275
- info: () => {
276
- },
277
- debug: () => {
278
- },
279
- trace: () => {
280
- },
281
- child: () => noOpLogger
282
- };
283
-
284
- // src/utils/atomic-write.ts
285
1
  import {
286
- createPersistencePrimitives
287
- } from "@wrongstack/persistence";
288
-
289
- // src/utils/error.ts
290
- function toErrorMessage(err) {
291
- return err instanceof Error ? err.message : String(err);
292
- }
293
-
294
- // src/types/errors.ts
295
- var ERROR_CODES = {
296
- // Provider
297
- PROVIDER_RATE_LIMITED: "PROVIDER_RATE_LIMITED",
298
- PROVIDER_AUTH_FAILED: "PROVIDER_AUTH_FAILED",
299
- PROVIDER_OVERLOADED: "PROVIDER_OVERLOADED",
300
- PROVIDER_INVALID_REQUEST: "PROVIDER_INVALID_REQUEST",
301
- PROVIDER_SERVER_ERROR: "PROVIDER_SERVER_ERROR",
302
- PROVIDER_NETWORK_ERROR: "PROVIDER_NETWORK_ERROR",
303
- PROVIDER_CONTEXT_OVERFLOW: "PROVIDER_CONTEXT_OVERFLOW",
304
- // Tool
305
- TOOL_NOT_FOUND: "TOOL_NOT_FOUND",
306
- TOOL_PERMISSION_DENIED: "TOOL_PERMISSION_DENIED",
307
- TOOL_EXECUTION_FAILED: "TOOL_EXECUTION_FAILED",
308
- TOOL_TIMEOUT: "TOOL_TIMEOUT",
309
- TOOL_INPUT_INVALID: "TOOL_INPUT_INVALID",
310
- // Config
311
- CONFIG_INVALID: "CONFIG_INVALID",
312
- CONFIG_NOT_FOUND: "CONFIG_NOT_FOUND",
313
- CONFIG_PARSE_FAILED: "CONFIG_PARSE_FAILED",
314
- CONFIG_MIGRATION_NEEDED: "CONFIG_MIGRATION_NEEDED",
315
- // Plugin
316
- PLUGIN_LOAD_FAILED: "PLUGIN_LOAD_FAILED",
317
- PLUGIN_API_MISMATCH: "PLUGIN_API_MISMATCH",
318
- PLUGIN_MISSING_DEPENDENCY: "PLUGIN_MISSING_DEPENDENCY",
319
- // Agent
320
- AGENT_ITERATION_LIMIT: "AGENT_ITERATION_LIMIT",
321
- AGENT_CONTEXT_OVERFLOW: "AGENT_CONTEXT_OVERFLOW",
322
- AGENT_ABORTED: "AGENT_ABORTED",
323
- AGENT_RUN_FAILED: "AGENT_RUN_FAILED",
324
- // Session
325
- SESSION_NOT_FOUND: "SESSION_NOT_FOUND",
326
- SESSION_CORRUPTED: "SESSION_CORRUPTED",
327
- SESSION_WRITE_FAILED: "SESSION_WRITE_FAILED",
328
- // Container / Registry
329
- CONTAINER_TOKEN_ALREADY_BOUND: "CONTAINER_TOKEN_ALREADY_BOUND",
330
- CONTAINER_TOKEN_NOT_BOUND: "CONTAINER_TOKEN_NOT_BOUND",
331
- CONTAINER_CIRCULAR_DEPENDENCY: "CONTAINER_CIRCULAR_DEPENDENCY",
332
- REGISTRY_DUPLICATE: "REGISTRY_DUPLICATE",
333
- REGISTRY_NOT_FOUND: "REGISTRY_NOT_FOUND",
334
- REGISTRY_INVALID: "REGISTRY_INVALID",
335
- // File system
336
- FS_READ_FAILED: "FS_READ_FAILED",
337
- FS_WRITE_FAILED: "FS_WRITE_FAILED",
338
- FS_MKDIR_FAILED: "FS_MKDIR_FAILED",
339
- FS_DELETE_FAILED: "FS_DELETE_FAILED",
340
- FS_ATOMIC_WRITE_FAILED: "FS_ATOMIC_WRITE_FAILED",
341
- // SDD (Spec-Driven Development)
342
- SDD_VALIDATION_FAILED: "SDD_VALIDATION_FAILED",
343
- SDD_PARSE_FAILED: "SDD_PARSE_FAILED",
344
- SDD_INVALID_STATE: "SDD_INVALID_STATE",
345
- SDD_NOT_READY: "SDD_NOT_READY",
346
- // General
347
- VALIDATION_ERROR: "VALIDATION_ERROR",
348
- PARSE_FAILED: "PARSE_FAILED",
349
- UNKNOWN: "UNKNOWN"
350
- };
351
- var WrongStackError = class extends Error {
352
- code;
353
- subsystem;
354
- severity;
355
- recoverable;
356
- context;
357
- constructor(opts) {
358
- super(opts.message, { cause: opts.cause });
359
- this.name = "WrongStackError";
360
- this.code = opts.code;
361
- this.subsystem = opts.subsystem;
362
- this.severity = opts.severity ?? "error";
363
- this.recoverable = opts.recoverable ?? false;
364
- this.context = opts.context;
365
- }
366
- /**
367
- * Render a one-line user-facing description.
368
- * Subclasses should override for domain-specific formatting.
369
- */
370
- describe() {
371
- const ctx = this.context ? ` ${formatContext(this.context)}` : "";
372
- return `${this.code}: ${this.message}${ctx}`;
373
- }
374
- };
375
- function formatContext(ctx) {
376
- const parts = Object.entries(ctx).filter(([, v]) => v !== void 0).slice(0, 3).map(([k, v]) => `${k}=${String(v)}`);
377
- return parts.length > 0 ? `[${parts.join(" ")}]` : "";
378
- }
379
- var FsError = class extends WrongStackError {
380
- path;
381
- constructor(opts) {
382
- super({
383
- message: opts.message,
384
- code: opts.code,
385
- subsystem: "fs",
386
- severity: "error",
387
- recoverable: opts.code !== ERROR_CODES.FS_READ_FAILED,
388
- context: { path: opts.path, ...opts.context },
389
- cause: opts.cause
390
- });
391
- this.name = "FsError";
392
- this.path = opts.path;
393
- }
394
- };
395
- var FetchError = class extends WrongStackError {
396
- status;
397
- constructor(opts) {
398
- super({
399
- message: opts.message,
400
- code: ERROR_CODES.VALIDATION_ERROR,
401
- subsystem: "general",
402
- severity: "error",
403
- recoverable: opts.status === 429 || opts.status >= 500,
404
- context: { status: opts.status, ...opts.context },
405
- cause: opts.cause
406
- });
407
- this.name = "FetchError";
408
- this.status = opts.status;
409
- }
410
- };
411
-
412
- // src/utils/atomic-write.ts
413
- var primitives = createPersistencePrimitives({
414
- createLockTimeoutError: ({ targetPath, timeoutMs }) => new FsError({
415
- message: `Timed out waiting for file lock: ${targetPath}`,
416
- code: "FS_ATOMIC_WRITE_FAILED",
417
- path: targetPath,
418
- context: { timeoutMs }
419
- })
420
- });
421
- var atomicWrite = primitives.atomicWrite;
422
- var atomicReplaceWithWriter = primitives.atomicReplaceWithWriter;
423
- var ensureDir = primitives.ensureDir;
424
- var withFileLock = primitives.withFileLock;
425
-
426
- // src/utils/merge-models-payload.ts
427
- var REMOVE_PROVIDERS_KEY = "_removeProviders";
428
- var REMOVE_MODELS_KEY = "_removeModels";
429
- function mergeModelsPayload(base, overlay) {
430
- const removeProviders = Array.isArray(overlay[REMOVE_PROVIDERS_KEY]) ? overlay[REMOVE_PROVIDERS_KEY] : [];
431
- const removeModels = overlay[REMOVE_MODELS_KEY] && typeof overlay[REMOVE_MODELS_KEY] === "object" ? overlay[REMOVE_MODELS_KEY] : {};
432
- const out = {};
433
- for (const [id, provider] of Object.entries(base)) {
434
- out[id] = cloneProvider(provider);
435
- }
436
- for (const [id, ovProvider] of Object.entries(overlay)) {
437
- if (id === REMOVE_PROVIDERS_KEY || id === REMOVE_MODELS_KEY) continue;
438
- const existing = out[id];
439
- out[id] = existing ? mergeProvider(existing, ovProvider) : cloneProvider(ovProvider);
440
- }
441
- for (const providerId of removeProviders) {
442
- delete out[providerId];
443
- }
444
- for (const [providerId, modelIds] of Object.entries(removeModels)) {
445
- const provider = out[providerId];
446
- if (!provider?.models) continue;
447
- for (const modelId of modelIds) {
448
- delete provider.models[modelId];
449
- }
450
- }
451
- return out;
452
- }
453
- function mergeProvider(base, overlay) {
454
- const models = {};
455
- for (const [mid, m] of Object.entries(base.models ?? {})) {
456
- models[mid] = { ...m };
457
- }
458
- for (const [mid, ovModel] of Object.entries(overlay.models ?? {})) {
459
- const existing = models[mid];
460
- models[mid] = existing ? mergeModel(existing, ovModel) : { ...ovModel };
461
- }
462
- return {
463
- ...base,
464
- // Overlay scalar fields win when explicitly provided; otherwise keep base.
465
- ...stripUndefined({
466
- id: overlay.id,
467
- name: overlay.name,
468
- npm: overlay.npm,
469
- api: overlay.api,
470
- env: overlay.env,
471
- doc: overlay.doc
472
- }),
473
- models
474
- };
475
- }
476
- function mergeModel(base, overlay) {
477
- const merged = { ...base, ...overlay };
478
- if (base.limit || overlay.limit) {
479
- merged.limit = { ...base.limit, ...overlay.limit };
480
- }
481
- if (base.cost || overlay.cost) {
482
- merged.cost = { ...base.cost, ...overlay.cost };
483
- }
484
- if (base.modalities || overlay.modalities) {
485
- merged.modalities = { ...base.modalities, ...overlay.modalities };
486
- }
487
- return merged;
488
- }
489
- function cloneProvider(p) {
490
- const models = {};
491
- for (const [mid, m] of Object.entries(p.models ?? {})) {
492
- models[mid] = { ...m };
493
- }
494
- return { ...p, models };
495
- }
496
- function stripUndefined(obj) {
497
- const out = {};
498
- for (const [k, v] of Object.entries(obj)) {
499
- if (v !== void 0) out[k] = v;
500
- }
501
- return out;
502
- }
2
+ LLMSelector
3
+ } from "../chunk-2FQL4PDC.js";
4
+ import {
5
+ noOpLogger
6
+ } from "../chunk-WBPVKEEE.js";
7
+ import {
8
+ DEFAULT_MODES
9
+ } from "../chunk-2FK4WTFF.js";
10
+ import {
11
+ mergeModelsPayload
12
+ } from "../chunk-EODDVJBM.js";
13
+ import {
14
+ FORBIDDEN_PROTO_KEYS
15
+ } from "../chunk-DEIQMBD2.js";
16
+ import "../chunk-5S437PRC.js";
17
+ import "../chunk-4VWO3ZXL.js";
18
+ import "../chunk-FSWCWSTS.js";
19
+ import {
20
+ atomicWrite
21
+ } from "../chunk-7ZHZE5EO.js";
22
+ import "../chunk-O37BQ65S.js";
23
+ import {
24
+ FetchError
25
+ } from "../chunk-WOEZV3Q4.js";
26
+ import {
27
+ toErrorMessage
28
+ } from "../chunk-TBRL2RCC.js";
29
+ import "../chunk-PFZO3C6H.js";
503
30
 
504
31
  // src/models/models-registry.ts
32
+ import * as fs from "node:fs/promises";
33
+ import * as path from "node:path";
505
34
  var DEFAULT_URL = "https://models.dev/api.json";
506
35
  var ENV_URL_KEY = "WRONGSTACK_MODELS_DEV_URL";
507
36
  var DEFAULT_TTL_SECONDS = 3 * 3600;
@@ -578,7 +107,7 @@ var DefaultModelsRegistry = class {
578
107
  this.overlay = opts.overlay;
579
108
  this.overlayUrl = opts.overlayUrl;
580
109
  this.overlayFile = opts.overlayFile;
581
- this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path2.join(path2.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
110
+ this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path.join(path.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
582
111
  this.logger = opts.logger ?? noOpLogger;
583
112
  }
584
113
  async load(opts = {}) {
@@ -853,7 +382,7 @@ var DefaultModelsRegistry = class {
853
382
  }
854
383
  /** Used by `wstack models refresh` to expose where the cache lives. */
855
384
  cacheLocation() {
856
- return path2.resolve(this.cacheFile);
385
+ return path.resolve(this.cacheFile);
857
386
  }
858
387
  };
859
388
  var REASONING_EFFORTS = /* @__PURE__ */ new Set([
@@ -923,212 +452,7 @@ function looksLikeModelsPayload(value, requireModels) {
923
452
 
924
453
  // src/models/mode-store.ts
925
454
  import * as fs2 from "node:fs/promises";
926
- import * as path4 from "node:path";
927
-
928
- // src/types/mode-prompts.ts
929
- import { readFileSync, statSync } from "node:fs";
930
- import * as path3 from "node:path";
931
- import { fileURLToPath } from "node:url";
932
- function modePrompt(id) {
933
- for (const dir of modePromptDirCandidates()) {
934
- try {
935
- return readFileSync(path3.join(dir, `${id}.md`), "utf8").trimEnd();
936
- } catch {
937
- }
938
- }
939
- return "";
940
- }
941
- function modePromptDirCandidates() {
942
- const here = path3.dirname(fileURLToPath(import.meta.url));
943
- const candidates = [
944
- path3.resolve(here, "../../instructions/modes"),
945
- path3.resolve(here, "../instructions/modes"),
946
- path3.resolve(here, "instructions/modes")
947
- ];
948
- return candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));
949
- }
950
- function isDirectory(candidate) {
951
- try {
952
- return statSync(candidate).isDirectory();
953
- } catch {
954
- return false;
955
- }
956
- }
957
-
958
- // src/types/mode.ts
959
- var DEFAULT_MODES = [
960
- {
961
- id: "default",
962
- name: "Default",
963
- description: "Balanced general-purpose mode; use when no special token/coverage trade-off is needed",
964
- prompt: "",
965
- tags: ["general", "balanced"]
966
- },
967
- {
968
- id: "brief",
969
- name: "Brief",
970
- description: "Ultra-compact responses for low-context, high-speed work",
971
- prompt: modePrompt("brief"),
972
- tags: ["lite", "fast", "concise", "token-saving"],
973
- toolPreferences: ["read", "edit", "bash"],
974
- suggestedSkills: []
975
- },
976
- {
977
- id: "review-lite",
978
- name: "Review Lite",
979
- description: "Token-saving code review: changed files only, top correctness/security risks",
980
- prompt: modePrompt("review-lite"),
981
- tags: ["lite", "review", "quality", "token-saving"],
982
- toolPreferences: ["git", "diff", "read", "grep"],
983
- suggestedSkills: ["bug-hunter", "typescript-strict"]
984
- },
985
- {
986
- id: "audit-lite",
987
- name: "Audit Lite",
988
- description: "Token-saving security triage for a small diff or named file",
989
- prompt: modePrompt("audit-lite"),
990
- tags: ["lite", "security", "audit", "token-saving"],
991
- toolPreferences: ["grep", "read", "git"],
992
- suggestedSkills: ["security-scanner"]
993
- },
994
- {
995
- id: "plan-lite",
996
- name: "Plan Lite",
997
- description: "Token-saving planning: 3-6 actionable steps, minimal design debate",
998
- prompt: modePrompt("plan-lite"),
999
- tags: ["lite", "planning", "architecture", "token-saving"],
1000
- toolPreferences: ["tree", "glob", "read", "grep"],
1001
- suggestedSkills: ["refactor-planner"]
1002
- },
1003
- {
1004
- id: "debug-lite",
1005
- name: "Debug Lite",
1006
- description: "Token-saving bug triage: one hypothesis, nearest evidence, narrow check",
1007
- prompt: modePrompt("debug-lite"),
1008
- tags: ["lite", "debug", "triage", "token-saving"],
1009
- toolPreferences: ["read", "grep", "test", "logs"],
1010
- suggestedSkills: ["bug-hunter"]
1011
- },
1012
- {
1013
- id: "test-lite",
1014
- name: "Test Lite",
1015
- description: "Token-saving tests: one focused regression or narrow verification target",
1016
- prompt: modePrompt("test-lite"),
1017
- tags: ["lite", "testing", "qa", "token-saving"],
1018
- toolPreferences: ["test", "read", "grep"],
1019
- suggestedSkills: ["testing"]
1020
- },
1021
- {
1022
- id: "refactor-lite",
1023
- name: "Refactor Lite",
1024
- description: "Token-saving cleanup: small scoped behavior-preserving changes",
1025
- prompt: modePrompt("refactor-lite"),
1026
- tags: ["lite", "refactor", "token-saving"],
1027
- toolPreferences: ["read", "edit", "test"],
1028
- suggestedSkills: ["typescript-strict"]
1029
- },
1030
- {
1031
- id: "research-lite",
1032
- name: "Research Lite",
1033
- description: "Token-saving web research: one search, one authoritative fetch, short answer",
1034
- prompt: modePrompt("research-lite"),
1035
- tags: ["lite", "research", "web", "token-saving"],
1036
- toolPreferences: ["search", "fetch"],
1037
- suggestedSkills: ["research-web"]
1038
- },
1039
- {
1040
- id: "code-reviewer",
1041
- name: "Review Deep",
1042
- description: "Comprehensive code review across contracts, edge cases, lifecycle, errors, concurrency",
1043
- prompt: modePrompt("code-reviewer"),
1044
- tags: ["deep", "review", "quality", "security"],
1045
- toolPreferences: ["read", "grep", "git", "diff", "test"],
1046
- suggestedSkills: ["bug-hunter", "security-scanner", "typescript-strict", "testing"]
1047
- },
1048
- {
1049
- id: "code-auditor",
1050
- name: "Audit Deep",
1051
- description: "Comprehensive security audit with category coverage and exploitability notes",
1052
- prompt: modePrompt("code-auditor"),
1053
- tags: ["deep", "security", "audit", "compliance"],
1054
- toolPreferences: ["grep", "read", "audit", "bash"],
1055
- suggestedSkills: ["security-scanner", "bug-hunter", "audit-log"]
1056
- },
1057
- {
1058
- id: "architect",
1059
- name: "Architecture Deep",
1060
- description: "Comprehensive architecture and cross-module contract analysis",
1061
- prompt: modePrompt("architect"),
1062
- tags: ["deep", "architecture", "design", "scalability"],
1063
- toolPreferences: ["read", "glob", "tree", "diff"],
1064
- suggestedSkills: ["api-design", "refactor-planner", "node-modern", "docker-deploy"]
1065
- },
1066
- {
1067
- id: "debugger",
1068
- name: "Debug Deep",
1069
- description: "Comprehensive root-cause analysis with traces, logs, assumptions, and verification",
1070
- prompt: modePrompt("debugger"),
1071
- tags: ["deep", "debug", "investigation", "error-resolution"],
1072
- toolPreferences: ["read", "grep", "bash", "logs", "test"],
1073
- suggestedSkills: ["bug-hunter", "audit-log", "observability"]
1074
- },
1075
- {
1076
- id: "tester",
1077
- name: "Test Deep",
1078
- description: "Comprehensive QA mode for coverage, boundaries, isolation, and integration gaps",
1079
- prompt: modePrompt("tester"),
1080
- tags: ["deep", "testing", "qa", "quality"],
1081
- toolPreferences: ["read", "grep", "test", "bash"],
1082
- suggestedSkills: ["testing", "bug-hunter", "typescript-strict"]
1083
- },
1084
- {
1085
- id: "devops",
1086
- name: "DevOps Deep",
1087
- description: "Comprehensive infrastructure, deployment, observability, and operations review",
1088
- prompt: modePrompt("devops"),
1089
- tags: ["deep", "devops", "infrastructure", "operations"],
1090
- toolPreferences: ["read", "bash", "grep", "logs", "git"],
1091
- suggestedSkills: ["docker-deploy", "observability", "security-scanner"]
1092
- },
1093
- {
1094
- id: "refactorer",
1095
- name: "Refactor Deep",
1096
- description: "Comprehensive modernization/refactor mode with contracts and verification discipline",
1097
- prompt: modePrompt("refactorer"),
1098
- tags: ["deep", "refactor", "modernization", "improvement"],
1099
- toolPreferences: ["read", "edit", "test", "git", "grep"],
1100
- suggestedSkills: ["refactor-planner", "typescript-strict", "node-modern", "testing"]
1101
- },
1102
- {
1103
- id: "ui-design",
1104
- name: "UI Design Deep",
1105
- description: "Comprehensive design-first frontend/mobile UI work with kit, tokens, and accessibility",
1106
- prompt: modePrompt("ui-design"),
1107
- tags: ["deep", "ui", "frontend", "mobile", "design"],
1108
- toolPreferences: ["design", "write", "edit", "read", "scaffold"],
1109
- suggestedSkills: ["react-modern"]
1110
- },
1111
- {
1112
- id: "teach",
1113
- name: "Teach Deep",
1114
- description: "Mentor mode with explanations, mental models, trade-offs, and takeaways",
1115
- prompt: modePrompt("teach"),
1116
- tags: ["deep", "teaching", "mentor", "learning"],
1117
- toolPreferences: ["read", "edit", "explain"],
1118
- suggestedSkills: ["prompt-engineering", "skill-creator", "node-modern", "typescript-strict"]
1119
- },
1120
- {
1121
- id: "research-web",
1122
- name: "Research Deep",
1123
- description: "Comprehensive current-data research with cross-checking and reusable findings",
1124
- prompt: modePrompt("research-web"),
1125
- tags: ["deep", "research", "web", "current-data", "up-to-date"],
1126
- toolPreferences: ["search", "fetch", "context_manager"],
1127
- suggestedSkills: ["research-web", "tech-stack", "node-modern", "security-scanner", "react-modern"]
1128
- }
1129
- ];
1130
-
1131
- // src/models/mode-store.ts
455
+ import * as path2 from "node:path";
1132
456
  var DefaultModeStore = class {
1133
457
  activeModeId = null;
1134
458
  modes;
@@ -1175,7 +499,7 @@ var DefaultModeStore = class {
1175
499
  }
1176
500
  async loadActiveMode() {
1177
501
  try {
1178
- const configPath = path4.join(this.configDir, "mode.json");
502
+ const configPath = path2.join(this.configDir, "mode.json");
1179
503
  const content = await fs2.readFile(configPath, "utf8");
1180
504
  const data = JSON.parse(content);
1181
505
  this.activeModeId = data.activeMode ?? null;
@@ -1186,7 +510,7 @@ var DefaultModeStore = class {
1186
510
  async saveActiveMode() {
1187
511
  try {
1188
512
  await fs2.mkdir(this.configDir, { recursive: true });
1189
- const configPath = path4.join(this.configDir, "mode.json");
513
+ const configPath = path2.join(this.configDir, "mode.json");
1190
514
  await atomicWrite(
1191
515
  configPath,
1192
516
  JSON.stringify({ activeMode: this.activeModeId }, null, 2)
@@ -1201,11 +525,11 @@ async function loadProjectModes(modesDir) {
1201
525
  const entries = await fs2.readdir(modesDir);
1202
526
  for (const entry of entries) {
1203
527
  if (!entry.endsWith(".md") && !entry.endsWith(".txt")) continue;
1204
- const filePath = path4.join(modesDir, entry);
1205
- const stat3 = await fs2.stat(filePath);
1206
- if (!stat3.isFile()) continue;
528
+ const filePath = path2.join(modesDir, entry);
529
+ const stat2 = await fs2.stat(filePath);
530
+ if (!stat2.isFile()) continue;
1207
531
  const content = await fs2.readFile(filePath, "utf8");
1208
- const id = path4.basename(entry, path4.extname(entry));
532
+ const id = path2.basename(entry, path2.extname(entry));
1209
533
  modes.push({
1210
534
  id,
1211
535
  name: id.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
@@ -1221,7 +545,7 @@ async function loadProjectModes(modesDir) {
1221
545
  async function loadUserModes(modesDir) {
1222
546
  const modes = [];
1223
547
  try {
1224
- const manifestPath = path4.join(modesDir, "modes.json");
548
+ const manifestPath = path2.join(modesDir, "modes.json");
1225
549
  const content = await fs2.readFile(manifestPath, "utf8");
1226
550
  const manifest = JSON.parse(content);
1227
551
  for (const mode of manifest.modes) {
@@ -1232,394 +556,6 @@ async function loadUserModes(modesDir) {
1232
556
  return modes;
1233
557
  }
1234
558
 
1235
- // src/utils/expect-defined.ts
1236
- function expectDefined(value, label) {
1237
- if (value === null || value === void 0) {
1238
- const err = new Error(label ? `Expected ${label} to be defined` : "Expected value to be defined");
1239
- err.name = "ExpectDefinedError";
1240
- throw err;
1241
- }
1242
- return value;
1243
- }
1244
-
1245
- // src/utils/token-estimate.ts
1246
- var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
1247
- var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
1248
- var _estimateCacheOrder = [];
1249
- var ESTIMATE_CACHE_MAX_SIZE = 5e4;
1250
- function estimateCacheKey(source) {
1251
- let h = 5381;
1252
- for (let i = 0; i < source.length; i++) {
1253
- h = (h << 5) + h + source.charCodeAt(i) | 0;
1254
- }
1255
- return `${source.length}:${h >>> 0}`;
1256
- }
1257
- function getCachedEstimate(source, compute) {
1258
- const key = estimateCacheKey(source);
1259
- const existing = ESTIMATE_CACHE.get(key);
1260
- if (existing !== void 0) return existing;
1261
- if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
1262
- while (ESTIMATE_CACHE.size > Math.floor(ESTIMATE_CACHE_MAX_SIZE / 2)) {
1263
- const oldest = _estimateCacheOrder.shift();
1264
- if (oldest !== void 0) ESTIMATE_CACHE.delete(oldest);
1265
- }
1266
- }
1267
- const estimate = compute(source);
1268
- ESTIMATE_CACHE.set(key, estimate);
1269
- _estimateCacheOrder.push(key);
1270
- return estimate;
1271
- }
1272
- function estimateToolInputTokens(input) {
1273
- if (typeof input === "string") return RoughTokenEstimate(input);
1274
- if (input === null || typeof input !== "object") {
1275
- return RoughTokenEstimate(String(input));
1276
- }
1277
- return getCachedEstimate(JSON.stringify(input), (key) => RoughTokenEstimate(key));
1278
- }
1279
- function estimateToolResultTokens(content) {
1280
- if (typeof content === "string") return RoughTokenEstimate(content);
1281
- return getCachedEstimate(JSON.stringify(content), (key) => RoughTokenEstimate(key));
1282
- }
1283
- function estimateTextTokens(text) {
1284
- return RoughTokenEstimate(text);
1285
- }
1286
- function computeMessageTokens(msg) {
1287
- if (typeof msg.content === "string") return estimateTextTokens(msg.content);
1288
- let total = 0;
1289
- for (const b of msg.content) {
1290
- if (b.type === "text") total += estimateTextTokens(b.text);
1291
- else if (b.type === "tool_use") total += estimateToolInputTokens(b.input);
1292
- else if (b.type === "tool_result") total += estimateToolResultTokens(b.content);
1293
- else total += RoughTokenEstimate(JSON.stringify(b));
1294
- }
1295
- return total;
1296
- }
1297
- function estimateMessageTokens(messages) {
1298
- let total = 0;
1299
- for (const m of messages) {
1300
- if (typeof m._estTokens === "number" && m._estTokens > 0) {
1301
- total += m._estTokens;
1302
- continue;
1303
- }
1304
- total += computeMessageTokens(m);
1305
- }
1306
- return total;
1307
- }
1308
-
1309
- // src/types/blocks.ts
1310
- function isTextBlock(b) {
1311
- return b.type === "text";
1312
- }
1313
-
1314
- // src/utils/compaction-preview.ts
1315
- var PATH_HINT_PATTERN = /(?:(?:[A-Za-z]:)?[./\\]?[\w@.-]+(?:[\\/][\w@(). -]+)+\.[A-Za-z0-9]{1,12})/g;
1316
- var PATH_BACKSLASH_PATTERN = /\\/g;
1317
- var PATH_TRIM_PATTERN = /^["'`]+|["'`),;:]+$/g;
1318
- var ERROR_LINE_PATTERN = /\b(error|exception|failed|failure|fatal|panic|timeout|denied|enoent|eacces|eperm)\b/i;
1319
- var NEWLINE_SPLIT_PATTERN = /\r?\n/;
1320
- var WHITESPACE_COLLAPSE_PATTERN = /\s+/g;
1321
- function buildCompactionPreview(message, maxChars = 600) {
1322
- if (maxChars <= 0) return "";
1323
- if (typeof message.content === "string") {
1324
- return truncatePreview(message.content, maxChars);
1325
- }
1326
- const parts = [];
1327
- for (const block of message.content) {
1328
- if (isTextBlock(block)) {
1329
- const text = truncatePreview(block.text, maxChars);
1330
- if (text) parts.push(text);
1331
- continue;
1332
- }
1333
- if (block.type === "tool_use") {
1334
- const input = truncatePreview(safePreviewString(block.input), 220);
1335
- parts.push(`[tool_use: ${block.name}${input ? `; input=${input}` : ""}]`);
1336
- continue;
1337
- }
1338
- if (block.type === "tool_result") {
1339
- const raw = safePreviewString(block.content);
1340
- const details = [block.is_error ? "error" : "ok"];
1341
- if (block.name) details.push(`tool=${block.name}`);
1342
- const files = extractPathHints(raw).slice(0, 5);
1343
- if (files.length > 0) details.push(`files=${files.join(", ")}`);
1344
- const error = firstErrorLine(raw);
1345
- if (error) details.push(`error=${error}`);
1346
- const sample = truncatePreview(raw, 260);
1347
- if (sample) details.push(`sample=${sample}`);
1348
- parts.push(`[tool_result: ${details.join("; ")}]`);
1349
- continue;
1350
- }
1351
- parts.push(`[${block.type}]`);
1352
- }
1353
- return truncatePreview(parts.join(" "), maxChars);
1354
- }
1355
- function safePreviewString(value) {
1356
- if (typeof value === "string") return value;
1357
- try {
1358
- return JSON.stringify(value);
1359
- } catch {
1360
- return String(value);
1361
- }
1362
- }
1363
- function truncatePreview(value, maxChars) {
1364
- const compact = value.replace(WHITESPACE_COLLAPSE_PATTERN, " ").trim();
1365
- if (compact.length <= maxChars) return compact;
1366
- return `${compact.slice(0, Math.max(0, maxChars - 1))}\u2026`;
1367
- }
1368
- function extractPathHints(content) {
1369
- const text = safePreviewString(content);
1370
- const out = /* @__PURE__ */ new Set();
1371
- for (const match of text.matchAll(PATH_HINT_PATTERN)) {
1372
- const clean = match[0]?.replace(PATH_BACKSLASH_PATTERN, "/").replace(PATH_TRIM_PATTERN, "");
1373
- if (clean) out.add(clean);
1374
- }
1375
- return [...out];
1376
- }
1377
- function firstErrorLine(content) {
1378
- const text = safePreviewString(content);
1379
- for (const line of text.split(NEWLINE_SPLIT_PATTERN)) {
1380
- if (!ERROR_LINE_PATTERN.test(line)) continue;
1381
- const trimmed = line.replace(WHITESPACE_COLLAPSE_PATTERN, " ").trim();
1382
- if (trimmed) return truncatePreview(trimmed, 220);
1383
- }
1384
- return void 0;
1385
- }
1386
-
1387
- // src/utils/instruction-file.ts
1388
- import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
1389
- import * as path5 from "node:path";
1390
- import { fileURLToPath as fileURLToPath2 } from "node:url";
1391
- var textCache = /* @__PURE__ */ new Map();
1392
- var rootCandidates;
1393
- function readBundledInstructionText(relativePath) {
1394
- const cached = textCache.get(relativePath);
1395
- if (cached !== void 0) return cached;
1396
- let resolved = "";
1397
- for (const root of instructionRootCandidates()) {
1398
- try {
1399
- resolved = readFileSync2(path5.join(root, relativePath), "utf8").trimEnd();
1400
- break;
1401
- } catch {
1402
- }
1403
- }
1404
- textCache.set(relativePath, resolved);
1405
- return resolved;
1406
- }
1407
- function instructionRootCandidates() {
1408
- if (rootCandidates !== void 0) return rootCandidates;
1409
- const here = path5.dirname(fileURLToPath2(import.meta.url));
1410
- const candidates = [
1411
- path5.resolve(here, "../../instructions"),
1412
- path5.resolve(here, "../instructions"),
1413
- path5.resolve(here, "instructions")
1414
- ];
1415
- rootCandidates = candidates.sort((a, b) => Number(!isDirectory2(a)) - Number(!isDirectory2(b)));
1416
- return rootCandidates;
1417
- }
1418
- function isDirectory2(candidate) {
1419
- try {
1420
- return statSync2(candidate).isDirectory();
1421
- } catch {
1422
- return false;
1423
- }
1424
- }
1425
-
1426
- // src/models/llm-selector.ts
1427
- var DEFAULT_SYSTEM_PROMPT = readBundledInstructionText("llm/llm-selector.md");
1428
- function formatMessages(messages, maxTokens = 2048) {
1429
- const previewChars = Math.max(
1430
- 120,
1431
- Math.min(600, Math.floor(maxTokens * 3.2 / Math.max(1, messages.length)))
1432
- );
1433
- const lines = [];
1434
- for (let i = 0; i < messages.length; i++) {
1435
- const m = expectDefined(messages[i]);
1436
- const role = m.role.padEnd(10, " ");
1437
- const line = `[${i}][${role}]: ${buildCompactionPreview(m, previewChars)}`;
1438
- lines.push({ index: i, text: line, tokens: estimateTextTokens(line) });
1439
- }
1440
- const total = lines.reduce((sum, line) => sum + line.tokens, 0);
1441
- if (total <= maxTokens) return lines.map((line) => line.text).join("\n");
1442
- const recentCount = Math.min(8, lines.length);
1443
- const recentStart = lines.length - recentCount;
1444
- const tail = [];
1445
- let usedTokens = 0;
1446
- for (let i = lines.length - 1; i >= recentStart; i--) {
1447
- const line = expectDefined(lines[i]);
1448
- if (tail.length >= 2 && usedTokens + line.tokens > Math.floor(maxTokens * 0.45)) continue;
1449
- tail.unshift(line);
1450
- usedTokens += line.tokens;
1451
- }
1452
- const head = [];
1453
- for (let i = 0; i < recentStart; i++) {
1454
- const line = expectDefined(lines[i]);
1455
- if (usedTokens + line.tokens > maxTokens) break;
1456
- head.push(line);
1457
- usedTokens += line.tokens;
1458
- }
1459
- const omitted = Math.max(0, recentStart - head.length);
1460
- const marker = omitted > 0 ? [`[\u2026 ${omitted} middle message(s) omitted from selector preview \u2026]`] : [];
1461
- return [...head.map((line) => line.text), ...marker, ...tail.map((line) => line.text)].join("\n");
1462
- }
1463
- var LLMSelector = class {
1464
- provider;
1465
- model;
1466
- maxContextTokens;
1467
- systemPrompt;
1468
- maxOutputTokens;
1469
- oneShotOrchestrator;
1470
- logger;
1471
- constructor(opts) {
1472
- this.provider = opts.provider;
1473
- this.model = opts.model ?? "unknown";
1474
- this.logger = opts.logger ?? noOpLogger;
1475
- if (this.model === "unknown" && (process.env["NODE_ENV"] === "development" || process.env["WRONGSTACK_DEBUG"] === "1")) {
1476
- this.logger.warn(
1477
- "[LLMSelector] model not set \u2014 selector will use the provider default. Set `model` explicitly in LLMSelectorOptions to silence this warning."
1478
- );
1479
- }
1480
- this.maxContextTokens = opts.maxContextTokens ?? 4e4;
1481
- this.systemPrompt = opts.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
1482
- this.maxOutputTokens = opts.maxOutputTokens ?? 1024;
1483
- this.oneShotOrchestrator = opts.oneShotOrchestrator;
1484
- }
1485
- async select(messages, maxToKeep) {
1486
- const effectiveBudget = Math.min(maxToKeep, this.maxContextTokens);
1487
- const totalTokens = estimateMessageTokens(messages);
1488
- const systemText = `${this.systemPrompt}
1489
-
1490
- Conversation (${messages.length} messages, ~${totalTokens} tokens, budget: ${effectiveBudget}):
1491
- `;
1492
- const systemTokens = estimateTextTokens(systemText);
1493
- const historyBudget = Math.max(512, effectiveBudget - systemTokens - this.maxOutputTokens);
1494
- const historyText = formatMessages(messages, historyBudget);
1495
- const budgetInstruction = totalTokens > effectiveBudget ? `
1496
-
1497
- IMPORTANT: Total conversation (${totalTokens} tokens) exceeds budget (${effectiveBudget}). You MUST collapse enough to fit. Prefer collapsing older/lower-importance ranges.` : "";
1498
- const req = {
1499
- model: this.model,
1500
- system: [{ type: "text", text: systemText + budgetInstruction }],
1501
- messages: [{ role: "user", content: historyText }],
1502
- maxTokens: this.maxOutputTokens
1503
- };
1504
- let raw;
1505
- const ac = new AbortController();
1506
- try {
1507
- if (this.oneShotOrchestrator) {
1508
- const result = await this.oneShotOrchestrator.call({
1509
- system: systemText + budgetInstruction,
1510
- userPrompt: historyText,
1511
- maxTokens: this.maxOutputTokens,
1512
- timeoutMs: 3e4
1513
- });
1514
- if (result.error) throw new Error(result.error);
1515
- raw = result.text;
1516
- } else {
1517
- const timeoutSignal = AbortSignal.timeout(3e4);
1518
- const res = await this.provider.complete(req, {
1519
- signal: AbortSignal.any([ac.signal, timeoutSignal])
1520
- });
1521
- const textBlocks = res.content.filter(isTextBlock);
1522
- raw = textBlocks.map((b) => b.text).join("\n").trim();
1523
- }
1524
- } catch (err) {
1525
- if (err instanceof Error) {
1526
- this.logger.warn(`selector call failed, using recency fallback: ${err.message}`, {
1527
- event: "llm_selector.call_failed"
1528
- });
1529
- }
1530
- return this.fallbackSelect(messages, effectiveBudget);
1531
- } finally {
1532
- ac.abort();
1533
- }
1534
- return this.parseSelectorOutput(raw, messages);
1535
- }
1536
- fallbackSelect(messages, budget) {
1537
- const toKeep = [];
1538
- const toCollapse = [];
1539
- let tokenCount = 0;
1540
- let startIdx = 0;
1541
- for (let i = messages.length - 1; i >= 0; i--) {
1542
- const m = expectDefined(messages[i]);
1543
- const cost = estimateMessageTokens([m]);
1544
- if (tokenCount + cost <= budget) {
1545
- tokenCount += cost;
1546
- } else {
1547
- startIdx = i + 1;
1548
- break;
1549
- }
1550
- }
1551
- if (startIdx > 0) {
1552
- toCollapse.push({ from: 0, to: startIdx - 1 });
1553
- }
1554
- toKeep.push({ from: startIdx, to: messages.length - 1, importance: "high" });
1555
- return {
1556
- kept: toKeep,
1557
- collapsed: toCollapse,
1558
- reasoning: `Fallback: kept last ${messages.length - startIdx} messages within ${budget} token budget`
1559
- };
1560
- }
1561
- /**
1562
- * Parse and validate the raw LLM output into a SelectorResult.
1563
- * Falls back to recency-based selection if the LLM output is malformed,
1564
- * out-of-bounds, or internally inconsistent.
1565
- */
1566
- parseSelectorOutput(raw, messages) {
1567
- const messageCount = messages.length;
1568
- if (messageCount === 0) {
1569
- return { kept: [], collapsed: [], reasoning: "empty session" };
1570
- }
1571
- const jsonStart = raw.indexOf("{");
1572
- const jsonEnd = raw.lastIndexOf("}");
1573
- if (jsonStart === -1 || jsonEnd === -1) {
1574
- return this.fallbackSelect(messages, this.maxContextTokens);
1575
- }
1576
- let parsed;
1577
- try {
1578
- parsed = JSON.parse(raw.slice(jsonStart, jsonEnd + 1));
1579
- } catch {
1580
- return this.fallbackSelect(messages, this.maxContextTokens);
1581
- }
1582
- const obj = parsed;
1583
- const keptRaw = obj.kept ?? [];
1584
- const collapsedRaw = obj.collapsed ?? [];
1585
- const kept = [];
1586
- for (const k of keptRaw) {
1587
- if (typeof k.from !== "number" || typeof k.to !== "number" || k.from < 0 || k.to >= messageCount || k.from > k.to) {
1588
- return this.fallbackSelect(messages, this.maxContextTokens);
1589
- }
1590
- kept.push({
1591
- from: k.from,
1592
- to: k.to,
1593
- importance: k.importance ?? "medium"
1594
- });
1595
- }
1596
- const collapsed = [];
1597
- for (const c of collapsedRaw) {
1598
- if (typeof c.from !== "number" || typeof c.to !== "number" || c.from < 0 || c.to >= messageCount || c.from > c.to) {
1599
- return this.fallbackSelect(messages, this.maxContextTokens);
1600
- }
1601
- collapsed.push({ from: c.from, to: c.to, summary: c.summary });
1602
- }
1603
- const allRanges = [...kept, ...collapsed];
1604
- for (let i = 0; i < allRanges.length; i++) {
1605
- const a = allRanges[i];
1606
- if (!a) continue;
1607
- for (let j = i + 1; j < allRanges.length; j++) {
1608
- const b = allRanges[j];
1609
- if (!b) continue;
1610
- if (a.from <= b.to && a.to >= b.from) {
1611
- return this.fallbackSelect(messages, this.maxContextTokens);
1612
- }
1613
- }
1614
- }
1615
- return {
1616
- kept,
1617
- collapsed,
1618
- reasoning: typeof obj.reasoning === "string" ? obj.reasoning : ""
1619
- };
1620
- }
1621
- };
1622
-
1623
559
  // src/models/codex-catalog.ts
1624
560
  var CODEX_MODELS = [
1625
561
  {
@@ -1813,19 +749,6 @@ function alibabaTokenPlanModelMeta(id) {
1813
749
 
1814
750
  // src/models/models-dev-schema.ts
1815
751
  import { z } from "zod";
1816
-
1817
- // src/utils/deep-merge.ts
1818
- var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
1819
- "__proto__",
1820
- "constructor",
1821
- "prototype",
1822
- "__defineGetter__",
1823
- "__defineSetter__",
1824
- "__lookupGetter__",
1825
- "__lookupSetter__"
1826
- ]);
1827
-
1828
- // src/models/models-dev-schema.ts
1829
752
  var MODELS_DEV_MODALITY_VALUES = ["text", "image", "audio", "video", "pdf"];
1830
753
  var REASONING_EFFORT_LITERALS = [
1831
754
  "none",