@wrongstack/core 0.257.2 → 0.264.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/{agent-bridge-BrxWHEOm.d.ts → agent-bridge-D8sa1vtv.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-US741uBH.d.ts → agent-subagent-runner-c9DLkaas.d.ts} +31 -9
  3. package/dist/{brain-TjEEwSpw.d.ts → brain-O1IdKPaK.d.ts} +59 -2
  4. package/dist/{compactor-C5sT4U7I.d.ts → compactor-BBy0rCtB.d.ts} +1 -1
  5. package/dist/{config-DuAu23zm.d.ts → config-Dz2F3H2K.d.ts} +7 -1
  6. package/dist/{context-CGdgA0q6.d.ts → context-BGSpZNSE.d.ts} +33 -0
  7. package/dist/coordination/index.d.ts +1681 -15
  8. package/dist/coordination/index.js +2826 -405
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +25 -25
  11. package/dist/defaults/index.js +2258 -1433
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/dispatcher-types.d-BBeXBQgS.d.ts +66 -0
  14. package/dist/execution/index.d.ts +15 -15
  15. package/dist/execution/index.js +502 -398
  16. package/dist/execution/index.js.map +1 -1
  17. package/dist/execution/prompt-enhancer.d.ts +2 -2
  18. package/dist/execution/prompt-enhancer.js +7 -1
  19. package/dist/execution/prompt-enhancer.js.map +1 -1
  20. package/dist/extension/index.d.ts +6 -6
  21. package/dist/extension/index.js.map +1 -1
  22. package/dist/{goal-preamble-CznHTZqP.d.ts → goal-preamble-DzjFuN3p.d.ts} +21 -9
  23. package/dist/{goal-store-CV9Yz2X_.d.ts → goal-store-CxWmCGbH.d.ts} +4 -2
  24. package/dist/{index-CC0Mcm05.d.ts → index-CYIQrXVF.d.ts} +8 -8
  25. package/dist/{index-CitPrI3a.d.ts → index-CbLSI66_.d.ts} +5 -5
  26. package/dist/index.d.ts +50 -94
  27. package/dist/index.js +16009 -12406
  28. package/dist/index.js.map +1 -1
  29. package/dist/infrastructure/index.d.ts +6 -6
  30. package/dist/kernel/index.d.ts +9 -9
  31. package/dist/kernel/index.js +6 -1
  32. package/dist/kernel/index.js.map +1 -1
  33. package/dist/{llm-selector-CJ4SyAFE.d.ts → llm-selector-DzxuZnNz.d.ts} +2 -2
  34. package/dist/{mcp-servers-D8YnLaEp.d.ts → mcp-servers-DC4QRPUI.d.ts} +3 -3
  35. package/dist/models/index.d.ts +5 -5
  36. package/dist/models/index.js +6 -1
  37. package/dist/models/index.js.map +1 -1
  38. package/dist/{models-registry-ByZCdFuQ.d.ts → models-registry-B_siPxqN.d.ts} +1 -1
  39. package/dist/{multi-agent-coordinator-DqTUEAeC.d.ts → multi-agent-coordinator-CK5Jdj9K.d.ts} +2 -2
  40. package/dist/{null-fleet-bus-B5mfTJXT.d.ts → null-fleet-bus-DgvD4SCO.d.ts} +13 -8
  41. package/dist/observability/index.d.ts +2 -2
  42. package/dist/observability/index.js +8 -3
  43. package/dist/observability/index.js.map +1 -1
  44. package/dist/{parallel-eternal-engine-C0juOszP.d.ts → parallel-eternal-engine-bK0JQBR_.d.ts} +13 -9
  45. package/dist/{path-resolver-CbkT-RMU.d.ts → path-resolver-BPEDlN38.d.ts} +3 -3
  46. package/dist/{permission-CwBBpCoF.d.ts → permission-4yvGmMRB.d.ts} +1 -1
  47. package/dist/{permission-policy-B8rSu908.d.ts → permission-policy-C6XpsBOy.d.ts} +3 -2
  48. package/dist/{pipeline-JG8XoudC.d.ts → pipeline-CXCeMz8J.d.ts} +58 -3
  49. package/dist/{plan-templates-DPiQMkBz.d.ts → plan-templates-BvzRBkJc.d.ts} +32 -11
  50. package/dist/{provider-runner-hM7EXlLI.d.ts → provider-runner-C5aQpDWE.d.ts} +3 -3
  51. package/dist/{retry-policy-Tg7LXkoK.d.ts → retry-policy-CFhdtRzz.d.ts} +1 -1
  52. package/dist/sdd/index.d.ts +8 -8
  53. package/dist/sdd/index.js +59 -31
  54. package/dist/sdd/index.js.map +1 -1
  55. package/dist/{secret-vault-gxtFZYBt.d.ts → secret-vault-CxiVLbt1.d.ts} +1 -1
  56. package/dist/security/index.d.ts +4 -4
  57. package/dist/security/index.js +238 -204
  58. package/dist/security/index.js.map +1 -1
  59. package/dist/{selector-DWsqVjGf.d.ts → selector-gIuhRTkN.d.ts} +1 -1
  60. package/dist/{session-event-bridge-BAFWdgQ3.d.ts → session-event-bridge-DkvvrpDt.d.ts} +8 -2
  61. package/dist/{session-reader-CqRvaL5v.d.ts → session-reader-KdfVwkKP.d.ts} +1 -1
  62. package/dist/skills/index.js +67 -64
  63. package/dist/skills/index.js.map +1 -1
  64. package/dist/storage/index.d.ts +50 -22
  65. package/dist/storage/index.js +1654 -525
  66. package/dist/storage/index.js.map +1 -1
  67. package/dist/tools/index.d.ts +57 -0
  68. package/dist/tools/index.js +411 -0
  69. package/dist/tools/index.js.map +1 -0
  70. package/dist/types/index.d.ts +19 -19
  71. package/dist/types/index.js +711 -694
  72. package/dist/types/index.js.map +1 -1
  73. package/dist/utils/error.d.ts +7 -0
  74. package/dist/utils/error.js +8 -0
  75. package/dist/utils/error.js.map +1 -0
  76. package/dist/utils/index.d.ts +7 -67
  77. package/dist/utils/index.js +17 -5
  78. package/dist/utils/index.js.map +1 -1
  79. package/package.json +5 -1
  80. package/skills/output-standards/SKILL.md +14 -9
  81. package/skills/output-standards/SKILL.save.md +3 -2
  82. package/dist/package-outdated-watcher-BSgR_kK-.d.ts +0 -581
@@ -1,7 +1,7 @@
1
1
  import { randomBytes, createCipheriv, createDecipheriv, randomUUID } from 'crypto';
2
- import * as fs2 from 'fs';
3
2
  import * as fs from 'fs/promises';
4
3
  import * as path4 from 'path';
4
+ import * as fs2 from 'fs';
5
5
  import * as os from 'os';
6
6
 
7
7
  // src/types/blocks.ts
@@ -14,20 +14,663 @@ function isToolUseBlock(b) {
14
14
  function isToolResultBlock(b) {
15
15
  return b.type === "tool_result";
16
16
  }
17
- function isImageBlock(b) {
18
- return b.type === "image";
17
+ function isImageBlock(b) {
18
+ return b.type === "image";
19
+ }
20
+ function isThinkingBlock(b) {
21
+ return b.type === "thinking";
22
+ }
23
+
24
+ // src/types/messages.ts
25
+ function asBlocks(content) {
26
+ return typeof content === "string" ? [{ type: "text", text: content }] : content;
27
+ }
28
+ function asText(content) {
29
+ if (typeof content === "string") return content;
30
+ return content.filter((b) => b.type === "text").map((b) => b.text).join("");
31
+ }
32
+ async function atomicWrite(targetPath, content, opts = {}) {
33
+ const dir = path4.dirname(targetPath);
34
+ await fs.mkdir(dir, { recursive: true });
35
+ const tmp = path4.join(dir, `.${path4.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
36
+ try {
37
+ if (typeof content === "string") {
38
+ await fs.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
39
+ } else {
40
+ await fs.writeFile(tmp, content, { flag: "wx" });
41
+ }
42
+ try {
43
+ const fh = await fs.open(tmp, "r+");
44
+ try {
45
+ await fh.sync();
46
+ } finally {
47
+ await fh.close();
48
+ }
49
+ } catch {
50
+ }
51
+ let mode;
52
+ try {
53
+ const stat2 = await fs.stat(targetPath);
54
+ mode = stat2.mode & 511;
55
+ } catch {
56
+ mode = opts.mode;
57
+ }
58
+ if (mode !== void 0) {
59
+ await fs.chmod(tmp, mode);
60
+ }
61
+ await renameWithRetry(tmp, targetPath);
62
+ } catch (err) {
63
+ try {
64
+ await fs.unlink(tmp);
65
+ } catch {
66
+ }
67
+ throw err;
68
+ }
69
+ }
70
+ var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
71
+ async function renameWithRetry(from, to) {
72
+ if (process.platform !== "win32") {
73
+ await fs.rename(from, to);
74
+ return;
75
+ }
76
+ const delays = [10, 25, 60, 120, 250];
77
+ let lastErr;
78
+ for (let i = 0; i <= delays.length; i++) {
79
+ try {
80
+ await fs.rename(from, to);
81
+ return;
82
+ } catch (err) {
83
+ lastErr = err;
84
+ const code = err?.code;
85
+ if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
86
+ throw err;
87
+ }
88
+ await new Promise((resolve4) => setTimeout(resolve4, delays[i]));
89
+ }
90
+ }
91
+ throw lastErr;
92
+ }
93
+
94
+ // src/utils/error.ts
95
+ function toErrorMessage(err) {
96
+ return err instanceof Error ? err.message : String(err);
97
+ }
98
+
99
+ // src/utils/term.ts
100
+ var hasStdout = () => typeof process !== "undefined" && !!process.stdout;
101
+ function isStdoutTTY() {
102
+ return hasStdout() && Boolean(process.stdout.isTTY);
103
+ }
104
+ function writeTo(s, stream) {
105
+ if (!stream || typeof stream.write !== "function") return false;
106
+ {
107
+ stream.write(s);
108
+ return true;
109
+ }
110
+ }
111
+ function writeErr(s, stream = process.stderr) {
112
+ return writeTo(s, stream);
113
+ }
114
+
115
+ // src/utils/color.ts
116
+ var isColorTty = () => {
117
+ if (envFlag(process.env.NO_COLOR)) return false;
118
+ if (envFlag(process.env.FORCE_COLOR)) return true;
119
+ return isStdoutTTY();
120
+ };
121
+ function envFlag(value) {
122
+ if (value === void 0) return false;
123
+ if (value.trim() === "") return false;
124
+ return !/^(0|false|no|off)$/i.test(value.trim());
125
+ }
126
+ var COLOR = isColorTty();
127
+ var wrap = (open2, close) => (s) => COLOR ? `\x1B[${open2}m${s}\x1B[${close}m` : s;
128
+ var color = {
129
+ reset: wrap("0", "0"),
130
+ bold: wrap("1", "22"),
131
+ dim: wrap("2", "22"),
132
+ italic: wrap("3", "23"),
133
+ underline: wrap("4", "24"),
134
+ red: wrap("31", "39"),
135
+ green: wrap("32", "39"),
136
+ yellow: wrap("33", "39"),
137
+ blue: wrap("34", "39"),
138
+ magenta: wrap("35", "39"),
139
+ cyan: wrap("36", "39"),
140
+ gray: wrap("90", "39"),
141
+ amber: wrap("38;5;214", "39"),
142
+ pink: wrap("38;5;205", "39"),
143
+ bgRed: wrap("41", "49"),
144
+ bgGreen: wrap("42", "49")
145
+ };
146
+
147
+ // src/utils/string.ts
148
+ function truncate(s, max) {
149
+ return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
150
+ }
151
+
152
+ // src/utils/expect-defined.ts
153
+ function expectDefined(value, label) {
154
+ if (value === null || value === void 0) {
155
+ const err = new Error("Expected value to be defined");
156
+ err.name = "ExpectDefinedError";
157
+ throw err;
158
+ }
159
+ return value;
160
+ }
161
+
162
+ // src/utils/deep-merge.ts
163
+ var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
164
+ "__proto__",
165
+ "constructor",
166
+ "prototype",
167
+ "__defineGetter__",
168
+ "__defineSetter__",
169
+ "__lookupGetter__",
170
+ "__lookupSetter__"
171
+ ]);
172
+ function isPrimitiveArray(a) {
173
+ return a.every((v) => v === null || typeof v !== "object" && typeof v !== "function");
174
+ }
175
+ function deepMerge(base, patch, options = {}) {
176
+ const {
177
+ conflictResolution = "prefer-patch",
178
+ arrayMode = "replace",
179
+ protectProto = true,
180
+ onNonPrimitiveArrayReplace
181
+ } = options;
182
+ if (typeof base !== "object" || base === null) {
183
+ return conflictResolution === "prefer-patch" ? patch : base;
184
+ }
185
+ if (typeof patch !== "object" || patch === null) {
186
+ return conflictResolution === "prefer-patch" ? patch : base;
187
+ }
188
+ if (Array.isArray(base) && Array.isArray(patch)) {
189
+ if (arrayMode === "concat-primitives" && isPrimitiveArray(base) && isPrimitiveArray(patch)) {
190
+ return [.../* @__PURE__ */ new Set([...base, ...patch])];
191
+ }
192
+ return conflictResolution === "prefer-patch" ? patch : base;
193
+ }
194
+ if (Array.isArray(base) || Array.isArray(patch)) {
195
+ return conflictResolution === "prefer-patch" ? patch : base;
196
+ }
197
+ const baseObj = base;
198
+ const patchObj = patch;
199
+ const out = { ...baseObj };
200
+ for (const [k, v] of Object.entries(patchObj)) {
201
+ if (protectProto && FORBIDDEN_PROTO_KEYS.has(k)) continue;
202
+ const existing = out[k];
203
+ if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
204
+ out[k] = deepMerge(existing, v, options);
205
+ } else if (Array.isArray(v) && Array.isArray(existing)) {
206
+ if (onNonPrimitiveArrayReplace && !isPrimitiveArray(v)) {
207
+ onNonPrimitiveArrayReplace(k, existing.length, v.length);
208
+ }
209
+ out[k] = deepMerge(existing, v, options);
210
+ } else if (v !== void 0) {
211
+ if (onNonPrimitiveArrayReplace && Array.isArray(v) && !isPrimitiveArray(v)) {
212
+ const existingLen = Array.isArray(existing) ? existing.length : 0;
213
+ onNonPrimitiveArrayReplace(k, existingLen, v.length);
214
+ }
215
+ out[k] = v;
216
+ }
217
+ }
218
+ return out;
219
+ }
220
+
221
+ // src/utils/tool-output-serializer.ts
222
+ function createToolOutputSerializer(opts = {}) {
223
+ const capBytes = opts.perIterationOutputCapBytes ?? 1e5;
224
+ function serialize(value) {
225
+ if (typeof value === "string") return value;
226
+ if (value === null || value === void 0) return "";
227
+ if (typeof value === "object") {
228
+ if (Array.isArray(value)) return value.map(serialize).join("\n");
229
+ if ("text" in value) {
230
+ const t = value.text;
231
+ return typeof t === "string" ? t : JSON.stringify(value, null, 2);
232
+ }
233
+ try {
234
+ return JSON.stringify(value, null, 2);
235
+ } catch {
236
+ return String(value);
237
+ }
238
+ }
239
+ return String(value);
240
+ }
241
+ function enforceCap(text, remainingBudget) {
242
+ if (remainingBudget <= 0) {
243
+ return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
244
+ }
245
+ const textBytes = Buffer.byteLength(text, "utf8");
246
+ if (textBytes <= remainingBudget) {
247
+ return { text, newBudget: remainingBudget - textBytes };
248
+ }
249
+ const marker = `
250
+ \u2026[truncated ${textBytes - remainingBudget} bytes]\u2026
251
+ `;
252
+ const markerBytes = Buffer.byteLength(marker, "utf8");
253
+ const available = remainingBudget - markerBytes;
254
+ if (available <= 0) {
255
+ return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
256
+ }
257
+ const half = Math.floor(available / 2);
258
+ const first = text.slice(0, half);
259
+ const second = text.slice(text.length - half);
260
+ return { text: `${first}${marker}${second}`, newBudget: 0 };
261
+ }
262
+ return { serialize, enforceCap, capBytes };
263
+ }
264
+
265
+ // src/utils/token-estimate.ts
266
+ var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
267
+ var CALIBRATION_GLOBAL_KEY = "__global__";
268
+ var _cals = /* @__PURE__ */ new Map();
269
+ function calState(key) {
270
+ let state = _cals.get(key);
271
+ if (!state) {
272
+ state = { ratio: 1, count: 0, prevEst: 0 };
273
+ _cals.set(key, state);
274
+ }
275
+ return state;
276
+ }
277
+ var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
278
+ var ESTIMATE_CACHE_MAX_SIZE = 1e4;
279
+ function getCachedEstimate(key, compute) {
280
+ const existing = ESTIMATE_CACHE.get(key);
281
+ if (existing !== void 0) return existing;
282
+ if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
283
+ let evicted = 0;
284
+ const maxEvict = Math.floor(ESTIMATE_CACHE_MAX_SIZE / 4);
285
+ for (const k of ESTIMATE_CACHE.keys()) {
286
+ if (evicted >= maxEvict) break;
287
+ ESTIMATE_CACHE.delete(k);
288
+ evicted++;
289
+ }
290
+ }
291
+ const estimate = compute(key);
292
+ ESTIMATE_CACHE.set(key, estimate);
293
+ return estimate;
294
+ }
295
+ function estimateToolInputTokens(input) {
296
+ if (typeof input === "string") return RoughTokenEstimate(input);
297
+ if (input === null || typeof input !== "object") {
298
+ return RoughTokenEstimate(String(input));
299
+ }
300
+ return getCachedEstimate(JSON.stringify(input), (key) => RoughTokenEstimate(key));
301
+ }
302
+ function estimateToolResultTokens(content) {
303
+ if (typeof content === "string") return RoughTokenEstimate(content);
304
+ return getCachedEstimate(JSON.stringify(content), (key) => RoughTokenEstimate(key));
305
+ }
306
+ function estimateTextTokens(text) {
307
+ return RoughTokenEstimate(text);
308
+ }
309
+ function computeMessageTokens(msg) {
310
+ if (typeof msg.content === "string") return estimateTextTokens(msg.content);
311
+ let total = 0;
312
+ for (const b of msg.content) {
313
+ if (b.type === "text") total += estimateTextTokens(b.text);
314
+ else if (b.type === "tool_use") total += estimateToolInputTokens(b.input);
315
+ else if (b.type === "tool_result") total += estimateToolResultTokens(b.content);
316
+ else total += RoughTokenEstimate(JSON.stringify(b));
317
+ }
318
+ return total;
319
+ }
320
+ function estimateMessageTokens(messages) {
321
+ let total = 0;
322
+ for (const m of messages) {
323
+ if (typeof m._estTokens === "number" && m._estTokens > 0) {
324
+ total += m._estTokens;
325
+ continue;
326
+ }
327
+ total += computeMessageTokens(m);
328
+ }
329
+ return total;
330
+ }
331
+ function estimateToolDefTokens(tool) {
332
+ const cached = tool._estDefTokens;
333
+ if (typeof cached === "number" && cached > 0) return cached;
334
+ return RoughTokenEstimate(tool.name) + RoughTokenEstimate(tool.description ?? "") + RoughTokenEstimate(JSON.stringify(tool.inputSchema));
335
+ }
336
+ function estimateRequestTokens(messages, systemPrompt, tools, calibrationKey = CALIBRATION_GLOBAL_KEY) {
337
+ let messagesTokens = 0;
338
+ if (typeof messages === "string") {
339
+ messagesTokens = RoughTokenEstimate(messages);
340
+ } else if (Array.isArray(messages)) {
341
+ for (const m of messages) {
342
+ if (typeof m === "object" && m !== null && "content" in m) {
343
+ const cached = m._estTokens;
344
+ if (typeof cached === "number" && cached > 0) {
345
+ messagesTokens += cached;
346
+ continue;
347
+ }
348
+ const content = m.content;
349
+ if (typeof content === "string") {
350
+ messagesTokens += RoughTokenEstimate(content);
351
+ } else if (Array.isArray(content)) {
352
+ for (const b of content) {
353
+ if (typeof b === "object" && b !== null) {
354
+ if (b.type === "text") {
355
+ messagesTokens += RoughTokenEstimate(b.text);
356
+ } else {
357
+ messagesTokens += RoughTokenEstimate(JSON.stringify(b));
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }
364
+ }
365
+ let systemTokens = 0;
366
+ if (typeof systemPrompt === "string") {
367
+ systemTokens = RoughTokenEstimate(systemPrompt);
368
+ } else if (Array.isArray(systemPrompt)) {
369
+ for (const b of systemPrompt) {
370
+ if (typeof b === "object" && b !== null && b.type === "text") {
371
+ systemTokens += RoughTokenEstimate(b.text);
372
+ }
373
+ }
374
+ }
375
+ let toolsTokens = 0;
376
+ for (const t of tools) {
377
+ toolsTokens += estimateToolDefTokens(t);
378
+ }
379
+ const total = messagesTokens + systemTokens + toolsTokens;
380
+ calState(calibrationKey).prevEst = total;
381
+ return {
382
+ messages: messagesTokens,
383
+ systemPrompt: systemTokens,
384
+ tools: toolsTokens,
385
+ total
386
+ };
387
+ }
388
+
389
+ // src/utils/message-invariants.ts
390
+ function repairToolUseAdjacency(messages) {
391
+ const removedToolUses = [];
392
+ const removedToolResults = [];
393
+ let removedMessages = 0;
394
+ let changed = false;
395
+ const out = [];
396
+ for (let i = 0; i < messages.length; i++) {
397
+ const original = expectDefined(messages[i]);
398
+ let msg = original;
399
+ if (hasToolUse(msg)) {
400
+ const nextIds = toolResultIds(messages[i + 1]);
401
+ const filtered = mapContent(msg, (blocks) => {
402
+ const next = [];
403
+ for (const block of blocks) {
404
+ if (block.type === "tool_use" && !nextIds.has(block.id)) {
405
+ removedToolUses.push(block.id);
406
+ changed = true;
407
+ continue;
408
+ }
409
+ next.push(block);
410
+ }
411
+ return next;
412
+ });
413
+ msg = filtered ?? msg;
414
+ }
415
+ if (hasToolResult(msg)) {
416
+ const allowed = toolUseIds(out[out.length - 1]);
417
+ const filtered = mapContent(msg, (blocks) => {
418
+ const next = [];
419
+ for (const block of blocks) {
420
+ if (block.type === "tool_result" && !allowed.has(block.tool_use_id)) {
421
+ removedToolResults.push(block.tool_use_id);
422
+ changed = true;
423
+ continue;
424
+ }
425
+ next.push(block);
426
+ }
427
+ return next;
428
+ });
429
+ msg = filtered ?? msg;
430
+ }
431
+ if (isEmptyMessage(msg)) {
432
+ removedMessages++;
433
+ changed = true;
434
+ continue;
435
+ }
436
+ out.push(msg);
437
+ }
438
+ return {
439
+ messages: changed ? out : messages,
440
+ report: { changed, removedToolUses, removedToolResults, removedMessages }
441
+ };
442
+ }
443
+ function hasToolUse(msg) {
444
+ return contentBlocks(msg).some((b) => b.type === "tool_use");
445
+ }
446
+ function hasToolResult(msg) {
447
+ return contentBlocks(msg).some((b) => b.type === "tool_result");
448
+ }
449
+ function toolUseIds(msg) {
450
+ const ids = /* @__PURE__ */ new Set();
451
+ if (!msg || msg.role !== "assistant") return ids;
452
+ for (const block of contentBlocks(msg)) {
453
+ if (block.type === "tool_use") ids.add(block.id);
454
+ }
455
+ return ids;
456
+ }
457
+ function toolResultIds(msg) {
458
+ const ids = /* @__PURE__ */ new Set();
459
+ if (!msg || msg.role !== "user") return ids;
460
+ for (const block of contentBlocks(msg)) {
461
+ if (block.type === "tool_result") ids.add(block.tool_use_id);
462
+ }
463
+ return ids;
464
+ }
465
+ function contentBlocks(msg) {
466
+ return msg && Array.isArray(msg.content) ? msg.content : [];
467
+ }
468
+ function mapContent(msg, fn) {
469
+ if (!Array.isArray(msg.content)) return msg;
470
+ const next = fn(msg.content);
471
+ if (next.length === msg.content.length && next.every((b, idx) => b === msg.content[idx])) {
472
+ return msg;
473
+ }
474
+ return { ...msg, content: next };
475
+ }
476
+ function isEmptyMessage(msg) {
477
+ if (typeof msg.content === "string") return msg.content.trim().length === 0;
478
+ return msg.content.length === 0;
479
+ }
480
+
481
+ // src/utils/json-schema-validate.ts
482
+ function validateAgainstSchema(value, schema) {
483
+ const errors = [];
484
+ walk(value, schema, "", errors);
485
+ return { ok: errors.length === 0, errors };
486
+ }
487
+ function walk(value, schema, path7, errors) {
488
+ if (schema.enum !== void 0) {
489
+ if (!schema.enum.some((e) => deepEqual(e, value))) {
490
+ errors.push({
491
+ path: path7 || "<root>",
492
+ message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
493
+ });
494
+ return;
495
+ }
496
+ }
497
+ if (typeof schema.type === "string") {
498
+ if (!checkType(value, schema.type)) {
499
+ errors.push({
500
+ path: path7 || "<root>",
501
+ message: `expected ${schema.type}, got ${describeType(value)}`
502
+ });
503
+ return;
504
+ }
505
+ }
506
+ if (schema.type === "object" && isPlainObject(value)) {
507
+ const obj = value;
508
+ for (const req of schema.required ?? []) {
509
+ if (!(req in obj)) {
510
+ errors.push({ path: joinPath(path7, req), message: "required property missing" });
511
+ }
512
+ }
513
+ if (schema.properties) {
514
+ for (const [key, subSchema] of Object.entries(schema.properties)) {
515
+ if (key in obj) {
516
+ walk(obj[key], subSchema, joinPath(path7, key), errors);
517
+ }
518
+ }
519
+ }
520
+ }
521
+ if (schema.type === "array" && Array.isArray(value) && schema.items) {
522
+ for (let i = 0; i < value.length; i++) {
523
+ walk(value[i], schema.items, `${path7}[${i}]`, errors);
524
+ }
525
+ }
526
+ }
527
+ function checkType(value, type) {
528
+ switch (type) {
529
+ case "string":
530
+ return typeof value === "string";
531
+ case "number":
532
+ return typeof value === "number" && !Number.isNaN(value);
533
+ case "integer":
534
+ return typeof value === "number" && Number.isInteger(value);
535
+ case "boolean":
536
+ return typeof value === "boolean";
537
+ case "null":
538
+ return value === null;
539
+ case "array":
540
+ return Array.isArray(value);
541
+ case "object":
542
+ return isPlainObject(value);
543
+ default:
544
+ return true;
545
+ }
546
+ }
547
+ function isPlainObject(v) {
548
+ return typeof v === "object" && v !== null && !Array.isArray(v);
549
+ }
550
+ function describeType(v) {
551
+ if (v === null) return "null";
552
+ if (Array.isArray(v)) return "array";
553
+ return typeof v;
554
+ }
555
+ function joinPath(parent, key) {
556
+ if (!parent) return key;
557
+ return `${parent}.${key}`;
558
+ }
559
+ function deepEqual(a, b) {
560
+ if (a === b) return true;
561
+ if (typeof a !== typeof b) return false;
562
+ if (a === null || b === null) return a === b;
563
+ if (Array.isArray(a) && Array.isArray(b)) {
564
+ return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
565
+ }
566
+ if (typeof a === "object" && typeof b === "object") {
567
+ const ak = Object.keys(a);
568
+ const bk = Object.keys(b);
569
+ if (ak.length !== bk.length) return false;
570
+ return ak.every(
571
+ (k) => deepEqual(a[k], b[k])
572
+ );
573
+ }
574
+ return false;
575
+ }
576
+
577
+ // src/utils/regex-guard.ts
578
+ var MAX_PATTERN_LEN = 512;
579
+ var DANGEROUS_PATTERNS = [
580
+ /(\([^)]*[+*][^)]*\))[+*]/,
581
+ // (a+)+, (.*)+, etc
582
+ /(\(\?:[^)]*[+*][^)]*\))[+*]/
583
+ // same, with non-capturing group
584
+ ];
585
+ function compileUserRegex(pattern, flags) {
586
+ if (typeof pattern !== "string") {
587
+ return { ok: false, reason: "pattern must be a string" };
588
+ }
589
+ if (pattern.length === 0) {
590
+ return { ok: false, reason: "pattern is empty" };
591
+ }
592
+ if (pattern.length > MAX_PATTERN_LEN) {
593
+ return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };
594
+ }
595
+ for (const rx of DANGEROUS_PATTERNS) {
596
+ if (rx.test(pattern)) {
597
+ return {
598
+ ok: false,
599
+ reason: "pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers"
600
+ };
601
+ }
602
+ }
603
+ try {
604
+ return { ok: true, regex: new RegExp(pattern, flags) };
605
+ } catch (err) {
606
+ return {
607
+ ok: false,
608
+ reason: err instanceof Error ? err.message : "invalid regex"
609
+ };
610
+ }
611
+ }
612
+
613
+ // src/utils/merge-models-payload.ts
614
+ function mergeModelsPayload(base, overlay) {
615
+ const out = {};
616
+ for (const [id, provider] of Object.entries(base)) {
617
+ out[id] = cloneProvider(provider);
618
+ }
619
+ for (const [id, ovProvider] of Object.entries(overlay)) {
620
+ const existing = out[id];
621
+ out[id] = existing ? mergeProvider(existing, ovProvider) : cloneProvider(ovProvider);
622
+ }
623
+ return out;
624
+ }
625
+ function mergeProvider(base, overlay) {
626
+ const models = {};
627
+ for (const [mid, m] of Object.entries(base.models ?? {})) {
628
+ models[mid] = { ...m };
629
+ }
630
+ for (const [mid, ovModel] of Object.entries(overlay.models ?? {})) {
631
+ const existing = models[mid];
632
+ models[mid] = existing ? mergeModel(existing, ovModel) : { ...ovModel };
633
+ }
634
+ return {
635
+ ...base,
636
+ // Overlay scalar fields win when explicitly provided; otherwise keep base.
637
+ ...stripUndefined({
638
+ id: overlay.id,
639
+ name: overlay.name,
640
+ npm: overlay.npm,
641
+ api: overlay.api,
642
+ env: overlay.env,
643
+ doc: overlay.doc
644
+ }),
645
+ models
646
+ };
19
647
  }
20
- function isThinkingBlock(b) {
21
- return b.type === "thinking";
648
+ function mergeModel(base, overlay) {
649
+ const merged = { ...base, ...overlay };
650
+ if (base.limit || overlay.limit) {
651
+ merged.limit = { ...base.limit, ...overlay.limit };
652
+ }
653
+ if (base.cost || overlay.cost) {
654
+ merged.cost = { ...base.cost, ...overlay.cost };
655
+ }
656
+ if (base.modalities || overlay.modalities) {
657
+ merged.modalities = { ...base.modalities, ...overlay.modalities };
658
+ }
659
+ return merged;
22
660
  }
23
-
24
- // src/types/messages.ts
25
- function asBlocks(content) {
26
- return typeof content === "string" ? [{ type: "text", text: content }] : content;
661
+ function cloneProvider(p) {
662
+ const models = {};
663
+ for (const [mid, m] of Object.entries(p.models ?? {})) {
664
+ models[mid] = { ...m };
665
+ }
666
+ return { ...p, models };
27
667
  }
28
- function asText(content) {
29
- if (typeof content === "string") return content;
30
- return content.filter((b) => b.type === "text").map((b) => b.text).join("");
668
+ function stripUndefined(obj) {
669
+ const out = {};
670
+ for (const [k, v] of Object.entries(obj)) {
671
+ if (v !== void 0) out[k] = v;
672
+ }
673
+ return out;
31
674
  }
32
675
 
33
676
  // src/types/errors.ts
@@ -175,7 +818,7 @@ var AgentError = class extends WrongStackError {
175
818
  };
176
819
  function toWrongStackError(err, code = ERROR_CODES.AGENT_RUN_FAILED) {
177
820
  if (err instanceof WrongStackError) return err;
178
- const message = err instanceof Error ? err.message : String(err);
821
+ const message = toErrorMessage(err);
179
822
  return new AgentError({
180
823
  message,
181
824
  code: code === "UNKNOWN" ? ERROR_CODES.AGENT_RUN_FAILED : code,
@@ -253,11 +896,6 @@ function isSddError(err) {
253
896
  return err instanceof SddError;
254
897
  }
255
898
 
256
- // src/utils/string.ts
257
- function truncate(s, max) {
258
- return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
259
- }
260
-
261
899
  // src/types/provider.ts
262
900
  var ProviderError = class extends WrongStackError {
263
901
  status;
@@ -388,126 +1026,6 @@ var DEFAULT_SESSION_PRUNE_DAYS = 30;
388
1026
 
389
1027
  // src/types/secret-vault.ts
390
1028
  var ENCRYPTED_PREFIX = "enc:v1:";
391
- async function atomicWrite(targetPath, content, opts = {}) {
392
- const dir = path4.dirname(targetPath);
393
- await fs.mkdir(dir, { recursive: true });
394
- const tmp = path4.join(dir, `.${path4.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
395
- try {
396
- if (typeof content === "string") {
397
- await fs.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
398
- } else {
399
- await fs.writeFile(tmp, content, { flag: "wx" });
400
- }
401
- try {
402
- const fh = await fs.open(tmp, "r+");
403
- try {
404
- await fh.sync();
405
- } finally {
406
- await fh.close();
407
- }
408
- } catch {
409
- }
410
- let mode;
411
- try {
412
- const stat2 = await fs.stat(targetPath);
413
- mode = stat2.mode & 511;
414
- } catch {
415
- mode = opts.mode;
416
- }
417
- if (mode !== void 0) {
418
- await fs.chmod(tmp, mode);
419
- }
420
- await renameWithRetry(tmp, targetPath);
421
- } catch (err) {
422
- try {
423
- await fs.unlink(tmp);
424
- } catch {
425
- }
426
- throw err;
427
- }
428
- }
429
- var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
430
- async function renameWithRetry(from, to) {
431
- if (process.platform !== "win32") {
432
- await fs.rename(from, to);
433
- return;
434
- }
435
- const delays = [10, 25, 60, 120, 250];
436
- let lastErr;
437
- for (let i = 0; i <= delays.length; i++) {
438
- try {
439
- await fs.rename(from, to);
440
- return;
441
- } catch (err) {
442
- lastErr = err;
443
- const code = err?.code;
444
- if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
445
- throw err;
446
- }
447
- await new Promise((resolve4) => setTimeout(resolve4, delays[i]));
448
- }
449
- }
450
- throw lastErr;
451
- }
452
-
453
- // src/utils/deep-merge.ts
454
- var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
455
- "__proto__",
456
- "constructor",
457
- "prototype",
458
- "__defineGetter__",
459
- "__defineSetter__",
460
- "__lookupGetter__",
461
- "__lookupSetter__"
462
- ]);
463
- function isPrimitiveArray(a) {
464
- return a.every((v) => v === null || typeof v !== "object" && typeof v !== "function");
465
- }
466
- function deepMerge(base, patch, options = {}) {
467
- const {
468
- conflictResolution = "prefer-patch",
469
- arrayMode = "replace",
470
- protectProto = true,
471
- onNonPrimitiveArrayReplace
472
- } = options;
473
- if (typeof base !== "object" || base === null) {
474
- return conflictResolution === "prefer-patch" ? patch : base;
475
- }
476
- if (typeof patch !== "object" || patch === null) {
477
- return conflictResolution === "prefer-patch" ? patch : base;
478
- }
479
- if (Array.isArray(base) && Array.isArray(patch)) {
480
- if (arrayMode === "concat-primitives" && isPrimitiveArray(base) && isPrimitiveArray(patch)) {
481
- return [.../* @__PURE__ */ new Set([...base, ...patch])];
482
- }
483
- return conflictResolution === "prefer-patch" ? patch : base;
484
- }
485
- if (Array.isArray(base) || Array.isArray(patch)) {
486
- return conflictResolution === "prefer-patch" ? patch : base;
487
- }
488
- const baseObj = base;
489
- const patchObj = patch;
490
- const out = { ...baseObj };
491
- for (const [k, v] of Object.entries(patchObj)) {
492
- if (protectProto && FORBIDDEN_PROTO_KEYS.has(k)) continue;
493
- const existing = out[k];
494
- if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
495
- out[k] = deepMerge(existing, v, options);
496
- } else if (Array.isArray(v) && Array.isArray(existing)) {
497
- if (onNonPrimitiveArrayReplace && !isPrimitiveArray(v)) {
498
- onNonPrimitiveArrayReplace(k, existing.length, v.length);
499
- }
500
- out[k] = deepMerge(existing, v, options);
501
- } else if (v !== void 0) {
502
- if (onNonPrimitiveArrayReplace && Array.isArray(v) && !isPrimitiveArray(v)) {
503
- const existingLen = Array.isArray(existing) ? existing.length : 0;
504
- onNonPrimitiveArrayReplace(k, existingLen, v.length);
505
- }
506
- out[k] = v;
507
- }
508
- }
509
- return out;
510
- }
511
1029
 
512
1030
  // src/security/secret-vault.ts
513
1031
  var KEY_BYTES = 32;
@@ -624,7 +1142,7 @@ var DefaultSecretVault = class {
624
1142
  };
625
1143
  function decryptConfigSecrets(cfg, vault, opts) {
626
1144
  const warn = opts?.warn ?? ((msg) => console.warn(msg));
627
- return walk(cfg, vault, (v, key) => {
1145
+ return walk2(cfg, vault, (v, key) => {
628
1146
  try {
629
1147
  return vault.decrypt(v);
630
1148
  } catch (err) {
@@ -636,20 +1154,20 @@ function decryptConfigSecrets(cfg, vault, opts) {
636
1154
  });
637
1155
  }
638
1156
  function encryptConfigSecrets(cfg, vault, _opts) {
639
- return walk(cfg, vault, (v) => vault.encrypt(v));
1157
+ return walk2(cfg, vault, (v) => vault.encrypt(v));
640
1158
  }
641
- function walk(node, vault, transform) {
1159
+ function walk2(node, vault, transform) {
642
1160
  if (node === null || node === void 0) return node;
643
1161
  if (typeof node !== "object") return node;
644
1162
  if (Array.isArray(node)) {
645
- return node.map((item) => walk(item, vault, transform));
1163
+ return node.map((item) => walk2(item, vault, transform));
646
1164
  }
647
1165
  const out = /* @__PURE__ */ Object.create(null);
648
1166
  for (const [k, v] of Object.entries(node)) {
649
1167
  if (typeof v === "string" && isSecretField(k)) {
650
1168
  out[k] = transform(v, k);
651
1169
  } else if (typeof v === "object" && v !== null) {
652
- out[k] = walk(v, vault, transform);
1170
+ out[k] = walk2(v, vault, transform);
653
1171
  } else {
654
1172
  out[k] = v;
655
1173
  }
@@ -734,74 +1252,24 @@ function windowsAccountName() {
734
1252
  return username;
735
1253
  }
736
1254
  function walkCount(node, vault, counter) {
737
- if (node === null || node === void 0) return node;
738
- if (typeof node !== "object") return node;
739
- if (Array.isArray(node)) {
740
- return node.map((item) => walkCount(item, vault, counter));
741
- }
742
- const out = /* @__PURE__ */ Object.create(null);
743
- for (const [k, v] of Object.entries(node)) {
744
- if (typeof v === "string" && isSecretField(k) && !vault.isEncrypted(v) && v.length > 0) {
745
- out[k] = vault.encrypt(v);
746
- counter.n++;
747
- } else if (typeof v === "object" && v !== null) {
748
- out[k] = walkCount(v, vault, counter);
749
- } else {
750
- out[k] = v;
751
- }
752
- }
753
- return out;
754
- }
755
-
756
- // src/utils/term.ts
757
- var hasStdout = () => typeof process !== "undefined" && !!process.stdout;
758
- function isStdoutTTY() {
759
- return hasStdout() && Boolean(process.stdout.isTTY);
760
- }
761
- function writeTo(s, stream) {
762
- if (!stream || typeof stream.write !== "function") return false;
763
- {
764
- stream.write(s);
765
- return true;
766
- }
767
- }
768
- function writeErr(s, stream = process.stderr) {
769
- return writeTo(s, stream);
770
- }
771
-
772
- // src/utils/color.ts
773
- var isColorTty = () => {
774
- if (envFlag(process.env.NO_COLOR)) return false;
775
- if (envFlag(process.env.FORCE_COLOR)) return true;
776
- return isStdoutTTY();
777
- };
778
- function envFlag(value) {
779
- if (value === void 0) return false;
780
- if (value.trim() === "") return false;
781
- return !/^(0|false|no|off)$/i.test(value.trim());
782
- }
783
- var COLOR = isColorTty();
784
- var wrap = (open2, close) => (s) => COLOR ? `\x1B[${open2}m${s}\x1B[${close}m` : s;
785
- var color = {
786
- reset: wrap("0", "0"),
787
- bold: wrap("1", "22"),
788
- dim: wrap("2", "22"),
789
- italic: wrap("3", "23"),
790
- underline: wrap("4", "24"),
791
- red: wrap("31", "39"),
792
- green: wrap("32", "39"),
793
- yellow: wrap("33", "39"),
794
- blue: wrap("34", "39"),
795
- magenta: wrap("35", "39"),
796
- cyan: wrap("36", "39"),
797
- gray: wrap("90", "39"),
798
- amber: wrap("38;5;214", "39"),
799
- pink: wrap("38;5;205", "39"),
800
- bgRed: wrap("41", "49"),
801
- bgGreen: wrap("42", "49")
802
- };
803
-
804
- // src/infrastructure/logger.ts
1255
+ if (node === null || node === void 0) return node;
1256
+ if (typeof node !== "object") return node;
1257
+ if (Array.isArray(node)) {
1258
+ return node.map((item) => walkCount(item, vault, counter));
1259
+ }
1260
+ const out = /* @__PURE__ */ Object.create(null);
1261
+ for (const [k, v] of Object.entries(node)) {
1262
+ if (typeof v === "string" && isSecretField(k) && !vault.isEncrypted(v) && v.length > 0) {
1263
+ out[k] = vault.encrypt(v);
1264
+ counter.n++;
1265
+ } else if (typeof v === "object" && v !== null) {
1266
+ out[k] = walkCount(v, vault, counter);
1267
+ } else {
1268
+ out[k] = v;
1269
+ }
1270
+ }
1271
+ return out;
1272
+ }
805
1273
  var LEVEL_RANK = {
806
1274
  error: 0,
807
1275
  warn: 1,
@@ -1080,250 +1548,24 @@ function priceFromModel(m) {
1080
1548
  return {
1081
1549
  input: m.cost?.input,
1082
1550
  output: m.cost?.output,
1083
- cacheRead: m.cost?.cache_read,
1084
- cacheWrite: m.cost?.cache_write
1085
- };
1086
- }
1087
- function round4(n) {
1088
- return Math.round(n * 1e4) / 1e4;
1089
- }
1090
-
1091
- // src/types/memory.ts
1092
- var MEMORY_TYPE_LABELS = {
1093
- fact: "Fact",
1094
- decision: "Decision",
1095
- convention: "Convention",
1096
- preference: "Preference",
1097
- reference: "Reference",
1098
- anti_pattern: "Anti-pattern"
1099
- };
1100
-
1101
- // src/utils/token-estimate.ts
1102
- var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
1103
- var CALIBRATION_GLOBAL_KEY = "__global__";
1104
- var _cals = /* @__PURE__ */ new Map();
1105
- function calState(key) {
1106
- let state = _cals.get(key);
1107
- if (!state) {
1108
- state = { ratio: 1, count: 0, prevEst: 0 };
1109
- _cals.set(key, state);
1110
- }
1111
- return state;
1112
- }
1113
- var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
1114
- var ESTIMATE_CACHE_MAX_SIZE = 1e4;
1115
- function getCachedEstimate(key, compute) {
1116
- const existing = ESTIMATE_CACHE.get(key);
1117
- if (existing !== void 0) return existing;
1118
- if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
1119
- let evicted = 0;
1120
- const maxEvict = Math.floor(ESTIMATE_CACHE_MAX_SIZE / 4);
1121
- for (const k of ESTIMATE_CACHE.keys()) {
1122
- if (evicted >= maxEvict) break;
1123
- ESTIMATE_CACHE.delete(k);
1124
- evicted++;
1125
- }
1126
- }
1127
- const estimate = compute(key);
1128
- ESTIMATE_CACHE.set(key, estimate);
1129
- return estimate;
1130
- }
1131
- function estimateToolInputTokens(input) {
1132
- if (typeof input === "string") return RoughTokenEstimate(input);
1133
- if (input === null || typeof input !== "object") {
1134
- return RoughTokenEstimate(String(input));
1135
- }
1136
- return getCachedEstimate(JSON.stringify(input), (key) => RoughTokenEstimate(key));
1137
- }
1138
- function estimateToolResultTokens(content) {
1139
- if (typeof content === "string") return RoughTokenEstimate(content);
1140
- return getCachedEstimate(JSON.stringify(content), (key) => RoughTokenEstimate(key));
1141
- }
1142
- function estimateTextTokens(text) {
1143
- return RoughTokenEstimate(text);
1144
- }
1145
- function computeMessageTokens(msg) {
1146
- if (typeof msg.content === "string") return estimateTextTokens(msg.content);
1147
- let total = 0;
1148
- for (const b of msg.content) {
1149
- if (b.type === "text") total += estimateTextTokens(b.text);
1150
- else if (b.type === "tool_use") total += estimateToolInputTokens(b.input);
1151
- else if (b.type === "tool_result") total += estimateToolResultTokens(b.content);
1152
- else total += RoughTokenEstimate(JSON.stringify(b));
1153
- }
1154
- return total;
1155
- }
1156
- function estimateMessageTokens(messages) {
1157
- let total = 0;
1158
- for (const m of messages) {
1159
- if (typeof m._estTokens === "number" && m._estTokens > 0) {
1160
- total += m._estTokens;
1161
- continue;
1162
- }
1163
- total += computeMessageTokens(m);
1164
- }
1165
- return total;
1166
- }
1167
- function estimateToolDefTokens(tool) {
1168
- const cached = tool._estDefTokens;
1169
- if (typeof cached === "number" && cached > 0) return cached;
1170
- return RoughTokenEstimate(tool.name) + RoughTokenEstimate(tool.description ?? "") + RoughTokenEstimate(JSON.stringify(tool.inputSchema));
1171
- }
1172
- function estimateRequestTokens(messages, systemPrompt, tools, calibrationKey = CALIBRATION_GLOBAL_KEY) {
1173
- let messagesTokens = 0;
1174
- if (typeof messages === "string") {
1175
- messagesTokens = RoughTokenEstimate(messages);
1176
- } else if (Array.isArray(messages)) {
1177
- for (const m of messages) {
1178
- if (typeof m === "object" && m !== null && "content" in m) {
1179
- const cached = m._estTokens;
1180
- if (typeof cached === "number" && cached > 0) {
1181
- messagesTokens += cached;
1182
- continue;
1183
- }
1184
- const content = m.content;
1185
- if (typeof content === "string") {
1186
- messagesTokens += RoughTokenEstimate(content);
1187
- } else if (Array.isArray(content)) {
1188
- for (const b of content) {
1189
- if (typeof b === "object" && b !== null) {
1190
- if (b.type === "text") {
1191
- messagesTokens += RoughTokenEstimate(b.text);
1192
- } else {
1193
- messagesTokens += RoughTokenEstimate(JSON.stringify(b));
1194
- }
1195
- }
1196
- }
1197
- }
1198
- }
1199
- }
1200
- }
1201
- let systemTokens = 0;
1202
- if (typeof systemPrompt === "string") {
1203
- systemTokens = RoughTokenEstimate(systemPrompt);
1204
- } else if (Array.isArray(systemPrompt)) {
1205
- for (const b of systemPrompt) {
1206
- if (typeof b === "object" && b !== null && b.type === "text") {
1207
- systemTokens += RoughTokenEstimate(b.text);
1208
- }
1209
- }
1210
- }
1211
- let toolsTokens = 0;
1212
- for (const t of tools) {
1213
- toolsTokens += estimateToolDefTokens(t);
1214
- }
1215
- const total = messagesTokens + systemTokens + toolsTokens;
1216
- calState(calibrationKey).prevEst = total;
1217
- return {
1218
- messages: messagesTokens,
1219
- systemPrompt: systemTokens,
1220
- tools: toolsTokens,
1221
- total
1222
- };
1223
- }
1224
-
1225
- // src/utils/expect-defined.ts
1226
- function expectDefined(value, label) {
1227
- if (value === null || value === void 0) {
1228
- const err = new Error("Expected value to be defined");
1229
- err.name = "ExpectDefinedError";
1230
- throw err;
1231
- }
1232
- return value;
1233
- }
1234
-
1235
- // src/utils/message-invariants.ts
1236
- function repairToolUseAdjacency(messages) {
1237
- const removedToolUses = [];
1238
- const removedToolResults = [];
1239
- let removedMessages = 0;
1240
- let changed = false;
1241
- const out = [];
1242
- for (let i = 0; i < messages.length; i++) {
1243
- const original = expectDefined(messages[i]);
1244
- let msg = original;
1245
- if (hasToolUse(msg)) {
1246
- const nextIds = toolResultIds(messages[i + 1]);
1247
- const filtered = mapContent(msg, (blocks) => {
1248
- const next = [];
1249
- for (const block of blocks) {
1250
- if (block.type === "tool_use" && !nextIds.has(block.id)) {
1251
- removedToolUses.push(block.id);
1252
- changed = true;
1253
- continue;
1254
- }
1255
- next.push(block);
1256
- }
1257
- return next;
1258
- });
1259
- msg = filtered ?? msg;
1260
- }
1261
- if (hasToolResult(msg)) {
1262
- const allowed = toolUseIds(out[out.length - 1]);
1263
- const filtered = mapContent(msg, (blocks) => {
1264
- const next = [];
1265
- for (const block of blocks) {
1266
- if (block.type === "tool_result" && !allowed.has(block.tool_use_id)) {
1267
- removedToolResults.push(block.tool_use_id);
1268
- changed = true;
1269
- continue;
1270
- }
1271
- next.push(block);
1272
- }
1273
- return next;
1274
- });
1275
- msg = filtered ?? msg;
1276
- }
1277
- if (isEmptyMessage(msg)) {
1278
- removedMessages++;
1279
- changed = true;
1280
- continue;
1281
- }
1282
- out.push(msg);
1283
- }
1284
- return {
1285
- messages: changed ? out : messages,
1286
- report: { changed, removedToolUses, removedToolResults, removedMessages }
1287
- };
1288
- }
1289
- function hasToolUse(msg) {
1290
- return contentBlocks(msg).some((b) => b.type === "tool_use");
1291
- }
1292
- function hasToolResult(msg) {
1293
- return contentBlocks(msg).some((b) => b.type === "tool_result");
1294
- }
1295
- function toolUseIds(msg) {
1296
- const ids = /* @__PURE__ */ new Set();
1297
- if (!msg || msg.role !== "assistant") return ids;
1298
- for (const block of contentBlocks(msg)) {
1299
- if (block.type === "tool_use") ids.add(block.id);
1300
- }
1301
- return ids;
1302
- }
1303
- function toolResultIds(msg) {
1304
- const ids = /* @__PURE__ */ new Set();
1305
- if (!msg || msg.role !== "user") return ids;
1306
- for (const block of contentBlocks(msg)) {
1307
- if (block.type === "tool_result") ids.add(block.tool_use_id);
1308
- }
1309
- return ids;
1310
- }
1311
- function contentBlocks(msg) {
1312
- return msg && Array.isArray(msg.content) ? msg.content : [];
1313
- }
1314
- function mapContent(msg, fn) {
1315
- if (!Array.isArray(msg.content)) return msg;
1316
- const next = fn(msg.content);
1317
- if (next.length === msg.content.length && next.every((b, idx) => b === msg.content[idx])) {
1318
- return msg;
1319
- }
1320
- return { ...msg, content: next };
1551
+ cacheRead: m.cost?.cache_read,
1552
+ cacheWrite: m.cost?.cache_write
1553
+ };
1321
1554
  }
1322
- function isEmptyMessage(msg) {
1323
- if (typeof msg.content === "string") return msg.content.trim().length === 0;
1324
- return msg.content.length === 0;
1555
+ function round4(n) {
1556
+ return Math.round(n * 1e4) / 1e4;
1325
1557
  }
1326
1558
 
1559
+ // src/types/memory.ts
1560
+ var MEMORY_TYPE_LABELS = {
1561
+ fact: "Fact",
1562
+ decision: "Decision",
1563
+ convention: "Convention",
1564
+ preference: "Preference",
1565
+ reference: "Reference",
1566
+ anti_pattern: "Anti-pattern"
1567
+ };
1568
+
1327
1569
  // src/execution/compaction-core.ts
1328
1570
  function emitCompactionMetrics(event, metrics) {
1329
1571
  console.log(
@@ -2091,71 +2333,6 @@ var DefaultSecretScrubber = class {
2091
2333
  return visit(obj);
2092
2334
  }
2093
2335
  };
2094
-
2095
- // src/utils/merge-models-payload.ts
2096
- function mergeModelsPayload(base, overlay) {
2097
- const out = {};
2098
- for (const [id, provider] of Object.entries(base)) {
2099
- out[id] = cloneProvider(provider);
2100
- }
2101
- for (const [id, ovProvider] of Object.entries(overlay)) {
2102
- const existing = out[id];
2103
- out[id] = existing ? mergeProvider(existing, ovProvider) : cloneProvider(ovProvider);
2104
- }
2105
- return out;
2106
- }
2107
- function mergeProvider(base, overlay) {
2108
- const models = {};
2109
- for (const [mid, m] of Object.entries(base.models ?? {})) {
2110
- models[mid] = { ...m };
2111
- }
2112
- for (const [mid, ovModel] of Object.entries(overlay.models ?? {})) {
2113
- const existing = models[mid];
2114
- models[mid] = existing ? mergeModel(existing, ovModel) : { ...ovModel };
2115
- }
2116
- return {
2117
- ...base,
2118
- // Overlay scalar fields win when explicitly provided; otherwise keep base.
2119
- ...stripUndefined({
2120
- id: overlay.id,
2121
- name: overlay.name,
2122
- npm: overlay.npm,
2123
- api: overlay.api,
2124
- env: overlay.env,
2125
- doc: overlay.doc
2126
- }),
2127
- models
2128
- };
2129
- }
2130
- function mergeModel(base, overlay) {
2131
- const merged = { ...base, ...overlay };
2132
- if (base.limit || overlay.limit) {
2133
- merged.limit = { ...base.limit, ...overlay.limit };
2134
- }
2135
- if (base.cost || overlay.cost) {
2136
- merged.cost = { ...base.cost, ...overlay.cost };
2137
- }
2138
- if (base.modalities || overlay.modalities) {
2139
- merged.modalities = { ...base.modalities, ...overlay.modalities };
2140
- }
2141
- return merged;
2142
- }
2143
- function cloneProvider(p) {
2144
- const models = {};
2145
- for (const [mid, m] of Object.entries(p.models ?? {})) {
2146
- models[mid] = { ...m };
2147
- }
2148
- return { ...p, models };
2149
- }
2150
- function stripUndefined(obj) {
2151
- const out = {};
2152
- for (const [k, v] of Object.entries(obj)) {
2153
- if (v !== void 0) out[k] = v;
2154
- }
2155
- return out;
2156
- }
2157
-
2158
- // src/models/models-registry.ts
2159
2336
  var DEFAULT_URL = "https://models.dev/api.json";
2160
2337
  var DEFAULT_TTL_SECONDS = 24 * 3600;
2161
2338
  var DEFAULT_REFRESH_TIMEOUT_MS = 15e3;
@@ -2251,7 +2428,7 @@ var DefaultModelsRegistry = class {
2251
2428
  }
2252
2429
  if (overlayAvailable) {
2253
2430
  console.warn(
2254
- `ModelsRegistry: models.dev unavailable (${err instanceof Error ? err.message : String(err)}); serving curated overlay only.`
2431
+ `ModelsRegistry: models.dev unavailable (${toErrorMessage(err)}); serving curated overlay only.`
2255
2432
  );
2256
2433
  return {};
2257
2434
  }
@@ -3135,144 +3312,6 @@ function getDangerousCapabilities(toolOrCaps) {
3135
3312
  );
3136
3313
  }
3137
3314
 
3138
- // src/utils/json-schema-validate.ts
3139
- function validateAgainstSchema(value, schema) {
3140
- const errors = [];
3141
- walk2(value, schema, "", errors);
3142
- return { ok: errors.length === 0, errors };
3143
- }
3144
- function walk2(value, schema, path7, errors) {
3145
- if (schema.enum !== void 0) {
3146
- if (!schema.enum.some((e) => deepEqual(e, value))) {
3147
- errors.push({
3148
- path: path7 || "<root>",
3149
- message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
3150
- });
3151
- return;
3152
- }
3153
- }
3154
- if (typeof schema.type === "string") {
3155
- if (!checkType(value, schema.type)) {
3156
- errors.push({
3157
- path: path7 || "<root>",
3158
- message: `expected ${schema.type}, got ${describeType(value)}`
3159
- });
3160
- return;
3161
- }
3162
- }
3163
- if (schema.type === "object" && isPlainObject(value)) {
3164
- const obj = value;
3165
- for (const req of schema.required ?? []) {
3166
- if (!(req in obj)) {
3167
- errors.push({ path: joinPath(path7, req), message: "required property missing" });
3168
- }
3169
- }
3170
- if (schema.properties) {
3171
- for (const [key, subSchema] of Object.entries(schema.properties)) {
3172
- if (key in obj) {
3173
- walk2(obj[key], subSchema, joinPath(path7, key), errors);
3174
- }
3175
- }
3176
- }
3177
- }
3178
- if (schema.type === "array" && Array.isArray(value) && schema.items) {
3179
- value.forEach((item, i) => walk2(item, schema.items, `${path7}[${i}]`, errors));
3180
- }
3181
- }
3182
- function checkType(value, type) {
3183
- switch (type) {
3184
- case "string":
3185
- return typeof value === "string";
3186
- case "number":
3187
- return typeof value === "number" && !Number.isNaN(value);
3188
- case "integer":
3189
- return typeof value === "number" && Number.isInteger(value);
3190
- case "boolean":
3191
- return typeof value === "boolean";
3192
- case "null":
3193
- return value === null;
3194
- case "array":
3195
- return Array.isArray(value);
3196
- case "object":
3197
- return isPlainObject(value);
3198
- default:
3199
- return true;
3200
- }
3201
- }
3202
- function isPlainObject(v) {
3203
- return typeof v === "object" && v !== null && !Array.isArray(v);
3204
- }
3205
- function describeType(v) {
3206
- if (v === null) return "null";
3207
- if (Array.isArray(v)) return "array";
3208
- return typeof v;
3209
- }
3210
- function joinPath(parent, key) {
3211
- if (!parent) return key;
3212
- return `${parent}.${key}`;
3213
- }
3214
- function deepEqual(a, b) {
3215
- if (a === b) return true;
3216
- if (typeof a !== typeof b) return false;
3217
- if (a === null || b === null) return a === b;
3218
- if (Array.isArray(a) && Array.isArray(b)) {
3219
- return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
3220
- }
3221
- if (typeof a === "object" && typeof b === "object") {
3222
- const ak = Object.keys(a);
3223
- const bk = Object.keys(b);
3224
- if (ak.length !== bk.length) return false;
3225
- return ak.every(
3226
- (k) => deepEqual(a[k], b[k])
3227
- );
3228
- }
3229
- return false;
3230
- }
3231
-
3232
- // src/utils/tool-output-serializer.ts
3233
- function createToolOutputSerializer(opts = {}) {
3234
- const capBytes = opts.perIterationOutputCapBytes ?? 1e5;
3235
- function serialize(value) {
3236
- if (typeof value === "string") return value;
3237
- if (value === null || value === void 0) return "";
3238
- if (typeof value === "object") {
3239
- if (Array.isArray(value)) return value.map(serialize).join("\n");
3240
- if ("text" in value) {
3241
- const t = value.text;
3242
- return typeof t === "string" ? t : JSON.stringify(value, null, 2);
3243
- }
3244
- try {
3245
- return JSON.stringify(value, null, 2);
3246
- } catch {
3247
- return String(value);
3248
- }
3249
- }
3250
- return String(value);
3251
- }
3252
- function enforceCap(text, remainingBudget) {
3253
- if (remainingBudget <= 0) {
3254
- return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
3255
- }
3256
- const textBytes = Buffer.byteLength(text, "utf8");
3257
- if (textBytes <= remainingBudget) {
3258
- return { text, newBudget: remainingBudget - textBytes };
3259
- }
3260
- const marker = `
3261
- \u2026[truncated ${textBytes - remainingBudget} bytes]\u2026
3262
- `;
3263
- const markerBytes = Buffer.byteLength(marker, "utf8");
3264
- const available = remainingBudget - markerBytes;
3265
- if (available <= 0) {
3266
- return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
3267
- }
3268
- const half = Math.floor(available / 2);
3269
- const first = text.slice(0, half);
3270
- const second = text.slice(text.length - half);
3271
- return { text: `${first}${marker}${second}`, newBudget: 0 };
3272
- }
3273
- return { serialize, enforceCap, capBytes };
3274
- }
3275
-
3276
3315
  // src/execution/tool-executor.ts
3277
3316
  var ToolExecutor = class _ToolExecutor {
3278
3317
  constructor(registry, opts) {
@@ -3436,7 +3475,7 @@ ${post.additionalContext}`;
3436
3475
  );
3437
3476
  return { result, tool, durationMs: Date.now() - start };
3438
3477
  } catch (err) {
3439
- const msg = err instanceof Error ? err.message : String(err);
3478
+ const msg = toErrorMessage(err);
3440
3479
  const scrubbed = this.opts.secretScrubber.scrub(msg);
3441
3480
  this.opts.renderer?.writeToolResult(tool.name, scrubbed, true);
3442
3481
  const result = {
@@ -3457,7 +3496,7 @@ ${post.additionalContext}`;
3457
3496
  try {
3458
3497
  return await runOne(use);
3459
3498
  } catch (err) {
3460
- const msg = err instanceof Error ? err.message : String(err);
3499
+ const msg = toErrorMessage(err);
3461
3500
  const scrubbed = this.opts.secretScrubber.scrub(msg);
3462
3501
  const result = {
3463
3502
  type: "tool_result",
@@ -3873,6 +3912,17 @@ var Context = class {
3873
3912
  agentId;
3874
3913
  /** Human-readable agent name. */
3875
3914
  agentName;
3915
+ /**
3916
+ * Session-level trace ID for correlating storage events with agent
3917
+ * iterations. Stored here and also propagated to `session.traceId`
3918
+ * so storage operations can include it in `storage.*` events.
3919
+ */
3920
+ traceId;
3921
+ /**
3922
+ * When true, tools can access any path on the filesystem.
3923
+ * When false or undefined, tools are restricted to the project root.
3924
+ */
3925
+ allowOutsideProjectRoot;
3876
3926
  /** Callbacks fired when `setWorkingDir()` changes the working directory. */
3877
3927
  _onWorkingDirChanged = [];
3878
3928
  /**
@@ -3908,6 +3958,9 @@ var Context = class {
3908
3958
  this.tools = init.tools ?? [];
3909
3959
  this.agentId = init.agentId ?? "unknown";
3910
3960
  this.agentName = init.agentName ?? "Unknown Agent";
3961
+ this.traceId = init.traceId;
3962
+ this.allowOutsideProjectRoot = init.allowOutsideProjectRoot ?? true;
3963
+ this.session.traceId = init.traceId;
3911
3964
  }
3912
3965
  /**
3913
3966
  * Observable wrapper over the mutable conversation state. Lazy so
@@ -4007,42 +4060,6 @@ var Context = class {
4007
4060
  }
4008
4061
  };
4009
4062
 
4010
- // src/utils/regex-guard.ts
4011
- var MAX_PATTERN_LEN = 512;
4012
- var DANGEROUS_PATTERNS = [
4013
- /(\([^)]*[+*][^)]*\))[+*]/,
4014
- // (a+)+, (.*)+, etc
4015
- /(\(\?:[^)]*[+*][^)]*\))[+*]/
4016
- // same, with non-capturing group
4017
- ];
4018
- function compileUserRegex(pattern, flags) {
4019
- if (typeof pattern !== "string") {
4020
- return { ok: false, reason: "pattern must be a string" };
4021
- }
4022
- if (pattern.length === 0) {
4023
- return { ok: false, reason: "pattern is empty" };
4024
- }
4025
- if (pattern.length > MAX_PATTERN_LEN) {
4026
- return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };
4027
- }
4028
- for (const rx of DANGEROUS_PATTERNS) {
4029
- if (rx.test(pattern)) {
4030
- return {
4031
- ok: false,
4032
- reason: "pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers"
4033
- };
4034
- }
4035
- }
4036
- try {
4037
- return { ok: true, regex: new RegExp(pattern, flags) };
4038
- } catch (err) {
4039
- return {
4040
- ok: false,
4041
- reason: err instanceof Error ? err.message : "invalid regex"
4042
- };
4043
- }
4044
- }
4045
-
4046
4063
  // src/storage/session-reader.ts
4047
4064
  var DefaultSessionReader = class {
4048
4065
  store;