@wrongstack/core 0.260.0 → 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 (80) hide show
  1. package/dist/{agent-bridge-BbskZ7HH.d.ts → agent-bridge-D8sa1vtv.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-BNIGZx18.d.ts → agent-subagent-runner-c9DLkaas.d.ts} +11 -9
  3. package/dist/{brain-C2yDd7Lw.d.ts → brain-O1IdKPaK.d.ts} +2 -2
  4. package/dist/{compactor-t0R_AIt_.d.ts → compactor-BBy0rCtB.d.ts} +1 -1
  5. package/dist/{config-FG6As4H5.d.ts → config-Dz2F3H2K.d.ts} +7 -1
  6. package/dist/{context-JFOVvu6z.d.ts → context-BGSpZNSE.d.ts} +11 -0
  7. package/dist/coordination/index.d.ts +1681 -15
  8. package/dist/coordination/index.js +2648 -388
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +25 -25
  11. package/dist/defaults/index.js +1414 -1387
  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 +410 -388
  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-B1IXJtLX.d.ts → goal-preamble-DzjFuN3p.d.ts} +21 -9
  23. package/dist/{goal-store-CPXz6Mml.d.ts → goal-store-CxWmCGbH.d.ts} +1 -1
  24. package/dist/{index-CebbJB94.d.ts → index-CYIQrXVF.d.ts} +8 -8
  25. package/dist/{index-BPcg4N3M.d.ts → index-CbLSI66_.d.ts} +5 -5
  26. package/dist/index.d.ts +45 -91
  27. package/dist/index.js +14976 -12551
  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-DXxI2tlu.d.ts → llm-selector-DzxuZnNz.d.ts} +2 -2
  34. package/dist/{mcp-servers-OwNHo43-.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-Djlmq4uB.d.ts → models-registry-B_siPxqN.d.ts} +1 -1
  39. package/dist/{multi-agent-coordinator-CEmrSCMJ.d.ts → multi-agent-coordinator-CK5Jdj9K.d.ts} +2 -2
  40. package/dist/{null-fleet-bus-DT92xqgJ.d.ts → null-fleet-bus-DgvD4SCO.d.ts} +6 -6
  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-0SItuq5r.d.ts → parallel-eternal-engine-bK0JQBR_.d.ts} +9 -9
  45. package/dist/{path-resolver-DKBh6Jlo.d.ts → path-resolver-BPEDlN38.d.ts} +3 -3
  46. package/dist/{permission-BJ7eO9Vl.d.ts → permission-4yvGmMRB.d.ts} +1 -1
  47. package/dist/{permission-policy-DEXOfnpm.d.ts → permission-policy-C6XpsBOy.d.ts} +2 -2
  48. package/dist/{pipeline-zflkI2dp.d.ts → pipeline-CXCeMz8J.d.ts} +58 -3
  49. package/dist/{plan-templates-BFXyRkEK.d.ts → plan-templates-BvzRBkJc.d.ts} +5 -5
  50. package/dist/{provider-runner-BC-uywtT.d.ts → provider-runner-C5aQpDWE.d.ts} +3 -3
  51. package/dist/{retry-policy-Cavrzmtk.d.ts → retry-policy-CFhdtRzz.d.ts} +1 -1
  52. package/dist/sdd/index.d.ts +8 -8
  53. package/dist/sdd/index.js +39 -29
  54. package/dist/sdd/index.js.map +1 -1
  55. package/dist/{secret-vault-CDvDYXWX.d.ts → secret-vault-CxiVLbt1.d.ts} +1 -1
  56. package/dist/security/index.d.ts +4 -4
  57. package/dist/security/index.js +208 -203
  58. package/dist/security/index.js.map +1 -1
  59. package/dist/{selector-B7AivHsu.d.ts → selector-gIuhRTkN.d.ts} +1 -1
  60. package/dist/{session-event-bridge-BmIDxdJd.d.ts → session-event-bridge-DkvvrpDt.d.ts} +8 -2
  61. package/dist/{session-reader-DtofsB-2.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 +31 -12
  65. package/dist/storage/index.js +441 -360
  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 +703 -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/dist/package-outdated-watcher-C70ag2G9.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
  }
@@ -736,72 +1254,22 @@ function windowsAccountName() {
736
1254
  function walkCount(node, vault, counter) {
737
1255
  if (node === null || node === void 0) return node;
738
1256
  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
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,
@@ -1078,252 +1546,26 @@ var DefaultTokenCounter = class {
1078
1546
  };
1079
1547
  function priceFromModel(m) {
1080
1548
  return {
1081
- input: m.cost?.input,
1082
- 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 };
1549
+ input: m.cost?.input,
1550
+ output: m.cost?.output,
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",
@@ -3879,6 +3918,11 @@ var Context = class {
3879
3918
  * so storage operations can include it in `storage.*` events.
3880
3919
  */
3881
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;
3882
3926
  /** Callbacks fired when `setWorkingDir()` changes the working directory. */
3883
3927
  _onWorkingDirChanged = [];
3884
3928
  /**
@@ -3915,6 +3959,7 @@ var Context = class {
3915
3959
  this.agentId = init.agentId ?? "unknown";
3916
3960
  this.agentName = init.agentName ?? "Unknown Agent";
3917
3961
  this.traceId = init.traceId;
3962
+ this.allowOutsideProjectRoot = init.allowOutsideProjectRoot ?? true;
3918
3963
  this.session.traceId = init.traceId;
3919
3964
  }
3920
3965
  /**
@@ -4015,42 +4060,6 @@ var Context = class {
4015
4060
  }
4016
4061
  };
4017
4062
 
4018
- // src/utils/regex-guard.ts
4019
- var MAX_PATTERN_LEN = 512;
4020
- var DANGEROUS_PATTERNS = [
4021
- /(\([^)]*[+*][^)]*\))[+*]/,
4022
- // (a+)+, (.*)+, etc
4023
- /(\(\?:[^)]*[+*][^)]*\))[+*]/
4024
- // same, with non-capturing group
4025
- ];
4026
- function compileUserRegex(pattern, flags) {
4027
- if (typeof pattern !== "string") {
4028
- return { ok: false, reason: "pattern must be a string" };
4029
- }
4030
- if (pattern.length === 0) {
4031
- return { ok: false, reason: "pattern is empty" };
4032
- }
4033
- if (pattern.length > MAX_PATTERN_LEN) {
4034
- return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };
4035
- }
4036
- for (const rx of DANGEROUS_PATTERNS) {
4037
- if (rx.test(pattern)) {
4038
- return {
4039
- ok: false,
4040
- reason: "pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers"
4041
- };
4042
- }
4043
- }
4044
- try {
4045
- return { ok: true, regex: new RegExp(pattern, flags) };
4046
- } catch (err) {
4047
- return {
4048
- ok: false,
4049
- reason: err instanceof Error ? err.message : "invalid regex"
4050
- };
4051
- }
4052
- }
4053
-
4054
4063
  // src/storage/session-reader.ts
4055
4064
  var DefaultSessionReader = class {
4056
4065
  store;