@wrongstack/core 0.264.0 → 0.267.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 (90) hide show
  1. package/dist/{agent-bridge-D8sa1vtv.d.ts → agent-bridge-STJ3JwwK.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-c9DLkaas.d.ts → agent-subagent-runner-CzPGP3jA.d.ts} +131 -11
  3. package/dist/{brain-O1IdKPaK.d.ts → brain-Cdg77tVN.d.ts} +103 -2
  4. package/dist/{compactor-BBy0rCtB.d.ts → compactor-iMZ84CXq.d.ts} +19 -1
  5. package/dist/{config-Dz2F3H2K.d.ts → config-Du3pYYln.d.ts} +132 -13
  6. package/dist/{context-BGSpZNSE.d.ts → context-dT5Ueund.d.ts} +90 -12
  7. package/dist/coordination/index.d.ts +78 -22
  8. package/dist/coordination/index.js +695 -273
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/{default-config-CXsDvOmP.d.ts → default-config-B0cj-Hry.d.ts} +11 -1
  11. package/dist/defaults/index.d.ts +28 -28
  12. package/dist/defaults/index.js +2327 -965
  13. package/dist/defaults/index.js.map +1 -1
  14. package/dist/execution/index.d.ts +16 -16
  15. package/dist/execution/index.js +1500 -371
  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 +1 -1
  19. package/dist/execution/prompt-enhancer.js.map +1 -1
  20. package/dist/extension/index.d.ts +6 -6
  21. package/dist/{goal-preamble-DzjFuN3p.d.ts → goal-preamble-SulMTowG.d.ts} +33 -12
  22. package/dist/{goal-store-CxWmCGbH.d.ts → goal-store-CABDwdFE.d.ts} +1 -1
  23. package/dist/{index-CbLSI66_.d.ts → index-Bms0m4oy.d.ts} +5 -5
  24. package/dist/{index-CYIQrXVF.d.ts → index-DtCVWel4.d.ts} +8 -8
  25. package/dist/index-IEuxQd-E.d.ts +82 -0
  26. package/dist/index.d.ts +261 -57
  27. package/dist/index.js +4799 -2212
  28. package/dist/index.js.map +1 -1
  29. package/dist/infrastructure/index.d.ts +6 -6
  30. package/dist/infrastructure/index.js +84 -9
  31. package/dist/infrastructure/index.js.map +1 -1
  32. package/dist/kernel/index.d.ts +9 -9
  33. package/dist/kernel/index.js +1 -1
  34. package/dist/kernel/index.js.map +1 -1
  35. package/dist/{mcp-servers-DC4QRPUI.d.ts → mcp-servers-C2cBTxUR.d.ts} +3 -3
  36. package/dist/models/index.d.ts +5 -5
  37. package/dist/models/index.js +104 -31
  38. package/dist/models/index.js.map +1 -1
  39. package/dist/{models-registry-B_siPxqN.d.ts → models-registry-BqGZNJQ-.d.ts} +1 -1
  40. package/dist/{multi-agent-coordinator-CK5Jdj9K.d.ts → multi-agent-coordinator-B8R43uPz.d.ts} +1 -1
  41. package/dist/{null-fleet-bus-DgvD4SCO.d.ts → null-fleet-bus-CnXa5oTH.d.ts} +14 -9
  42. package/dist/observability/index.d.ts +2 -2
  43. package/dist/{parallel-eternal-engine-bK0JQBR_.d.ts → parallel-eternal-engine-DdNnw9BQ.d.ts} +11 -9
  44. package/dist/{path-resolver-BPEDlN38.d.ts → path-resolver-COIMLCQL.d.ts} +3 -3
  45. package/dist/{permission-4yvGmMRB.d.ts → permission-B75JAi3-.d.ts} +1 -1
  46. package/dist/{permission-policy-C6XpsBOy.d.ts → permission-policy-DlR9eJAM.d.ts} +2 -2
  47. package/dist/{pipeline-CXCeMz8J.d.ts → pipeline-BfD2k1rT.d.ts} +3 -3
  48. package/dist/{plan-templates-BvzRBkJc.d.ts → plan-templates-DSIKCXZN.d.ts} +32 -8
  49. package/dist/provider-model-resolve-BNRsNuJx.d.ts +107 -0
  50. package/dist/{provider-runner-C5aQpDWE.d.ts → provider-runner-CX7iIvox.d.ts} +3 -3
  51. package/dist/{retry-policy-CFhdtRzz.d.ts → retry-policy-BilV1ujH.d.ts} +1 -1
  52. package/dist/sdd/index.d.ts +8 -8
  53. package/dist/sdd/index.js +286 -105
  54. package/dist/sdd/index.js.map +1 -1
  55. package/dist/secret-vault-BAKpgFw_.d.ts +57 -0
  56. package/dist/{secret-vault-CxiVLbt1.d.ts → secret-vault-gkvEZZfE.d.ts} +43 -4
  57. package/dist/security/index.d.ts +6 -68
  58. package/dist/security/index.js +296 -95
  59. package/dist/security/index.js.map +1 -1
  60. package/dist/{selector-gIuhRTkN.d.ts → selector-Bc7eWtT3.d.ts} +1 -1
  61. package/dist/{session-event-bridge-DkvvrpDt.d.ts → session-event-bridge-D-araDEz.d.ts} +1 -1
  62. package/dist/{session-reader-KdfVwkKP.d.ts → session-reader-D7Dapswh.d.ts} +1 -1
  63. package/dist/storage/index.d.ts +112 -15
  64. package/dist/storage/index.js +491 -156
  65. package/dist/storage/index.js.map +1 -1
  66. package/dist/tools/index.d.ts +4 -2
  67. package/dist/tools/index.js.map +1 -1
  68. package/dist/types/index.d.ts +21 -21
  69. package/dist/types/index.js +1523 -450
  70. package/dist/types/index.js.map +1 -1
  71. package/dist/utils/index.d.ts +455 -407
  72. package/dist/utils/index.js +2191 -1203
  73. package/dist/utils/index.js.map +1 -1
  74. package/dist/{wstack-paths-CJjEwPXn.d.ts → wstack-paths-hOpNLmvf.d.ts} +2 -0
  75. package/package.json +1 -1
  76. package/skills/api-design/SKILL.md +1 -1
  77. package/skills/audit-log/SKILL.md +6 -6
  78. package/skills/bug-hunter/SKILL.md +5 -5
  79. package/skills/chimera/SKILL.md +4 -4
  80. package/skills/docker-deploy/SKILL.md +1 -1
  81. package/skills/git-flow/SKILL.md +3 -3
  82. package/skills/multi-agent/SKILL.md +3 -3
  83. package/skills/node-modern/SKILL.md +1 -0
  84. package/skills/observability/SKILL.md +2 -2
  85. package/skills/output-standards/SKILL.md +51 -28
  86. package/skills/refactor-planner/SKILL.md +3 -3
  87. package/skills/security-scanner/SKILL.md +4 -3
  88. package/skills/tech-stack/SKILL.md +1 -2
  89. package/dist/llm-selector-DzxuZnNz.d.ts +0 -58
  90. package/dist/secret-vault-BJDY28ev.d.ts +0 -25
@@ -1,25 +1,352 @@
1
- import { s as TodoItem, M as Message, J as JSONSchema } from '../context-BGSpZNSE.js';
2
- export { T as TaskItem, c as computeTaskItemProgress, f as formatTaskList, a as formatTaskProgress } from '../task-format-vGOIftmK.js';
3
- export { a as WstackPathOptions, W as WstackPaths, p as projectHash, b as projectSlug, r as resolveWstackPaths, w as wstackGlobalRoot } from '../wstack-paths-CJjEwPXn.js';
4
- export { expectDefined } from './expect-defined.js';
5
- export { toErrorMessage } from './error.js';
6
- import { a as ModelsDevPayload, t as CustomModelDefinition } from '../config-Dz2F3H2K.js';
1
+ import { C as Context, w as ContextEvidenceState, k as ToolOutputMetadata, J as JSONSchema, M as Message, t as TodoItem } from '../context-dT5Ueund.js';
7
2
  export { H as HttpDispatcher, a as HttpsAgentAsDispatcher } from '../dispatcher-types.d-BBeXBQgS.js';
3
+ export { toErrorMessage } from './error.js';
4
+ export { expectDefined } from './expect-defined.js';
5
+ import { v as CustomModelDefinition, a as ModelsDevPayload } from '../config-Du3pYYln.js';
6
+ export { T as TaskItem, c as computeTaskItemProgress, f as formatTaskList, a as formatTaskProgress } from '../task-format-vGOIftmK.js';
7
+ export { a as WstackPathOptions, W as WstackPaths, p as projectHash, b as projectSlug, r as resolveWstackPaths, w as wstackGlobalRoot } from '../wstack-paths-hOpNLmvf.js';
8
8
  export { a as TaskPriority, b as TaskStatus, T as TaskType } from '../task-graph-u1q9Jkyk.js';
9
9
  import 'node:https';
10
10
  import 'undici';
11
11
 
12
- interface AtomicWriteOptions {
13
- mode?: number | undefined;
14
- encoding?: BufferEncoding | undefined;
12
+ /**
13
+ * Exhaustiveness check for discriminated union switches.
14
+ * Place in the `default` branch of a switch over a union type
15
+ * to get a compile-time error when a new variant is added.
16
+ *
17
+ * @example
18
+ * switch (block.type) {
19
+ * case 'text': return renderText(block);
20
+ * case 'tool_use': return renderToolUse(block);
21
+ * default: return assertNever(block);
22
+ * }
23
+ */
24
+ declare function assertNever(x: never, message?: string): never;
25
+
26
+ interface AtomicWriteOptions {
27
+ mode?: number | undefined;
28
+ encoding?: BufferEncoding | undefined;
29
+ }
30
+ interface FileLockOptions {
31
+ timeoutMs?: number | undefined;
32
+ staleMs?: number | undefined;
33
+ }
34
+ declare function atomicWrite(targetPath: string, content: string | Uint8Array, opts?: AtomicWriteOptions): Promise<void>;
35
+ declare function ensureDir(dir: string): Promise<void>;
36
+ declare function withFileLock<T>(targetPath: string, fn: () => Promise<T>, opts?: FileLockOptions): Promise<T>;
37
+
38
+ /**
39
+ * Build a sanitized child-process environment.
40
+ *
41
+ * The bash/exec tools and MCP stdio transports execute LLM-generated or
42
+ * configured commands. The parent process carries provider API keys
43
+ * (ANTHROPIC_API_KEY, OPENAI_API_KEY, ...), VCS tokens (GITHUB_TOKEN),
44
+ * and cloud credentials. Forwarding those to a child is an exfiltration
45
+ * vector even with `permission: 'confirm'` — a compromised MCP server
46
+ * or a cleverly composed shell pipeline can leak secrets.
47
+ *
48
+ * Strategy: copy a small, explicit allowlist of variables that real builds
49
+ * need, then copy anything else that does NOT look secret-bearing. This
50
+ * preserves user-friendly behavior (locale, terminal, npm config) while
51
+ * blocking the obvious leak channels.
52
+ *
53
+ * Override with `WRONGSTACK_CHILD_ENV_PASSTHROUGH=1` to forward the full
54
+ * parent environment unchanged (opt-in for advanced users who understand
55
+ * the risk).
56
+ */
57
+ interface BuildChildEnvOptions {
58
+ /** Session ID to inject as WRONGSTACK_SESSION_ID. */
59
+ sessionId?: string | undefined;
60
+ /** Additional env vars to merge (takes priority over filtered parent env). */
61
+ extra?: NodeJS.ProcessEnv | undefined;
62
+ }
63
+ /**
64
+ * Build a filtered child-process environment suitable for bash, exec, and
65
+ * MCP server subprocesses. Strips API keys, tokens, and other credentials
66
+ * while preserving system/tooling variables.
67
+ */
68
+ declare function buildChildEnv(optsOrSessionId?: BuildChildEnvOptions | string): NodeJS.ProcessEnv;
69
+
70
+ declare const color: {
71
+ reset: (s: string) => string;
72
+ bold: (s: string) => string;
73
+ dim: (s: string) => string;
74
+ italic: (s: string) => string;
75
+ underline: (s: string) => string;
76
+ red: (s: string) => string;
77
+ green: (s: string) => string;
78
+ yellow: (s: string) => string;
79
+ blue: (s: string) => string;
80
+ magenta: (s: string) => string;
81
+ cyan: (s: string) => string;
82
+ gray: (s: string) => string;
83
+ amber: (s: string) => string;
84
+ pink: (s: string) => string;
85
+ bgRed: (s: string) => string;
86
+ bgGreen: (s: string) => string;
87
+ };
88
+ declare function stripAnsi(s: string): string;
89
+
90
+ declare function createContextEvidenceState(): ContextEvidenceState;
91
+ interface RecordToolOutputEvidenceInput {
92
+ toolUseId: string;
93
+ toolName: string;
94
+ input: unknown;
95
+ content: string;
96
+ ok: boolean;
97
+ outputBytes?: number | undefined;
98
+ outputTokens?: number | undefined;
99
+ outputLines?: number | undefined;
100
+ }
101
+ declare function recordUserIntentEvidence(ctx: Context, text: string): void;
102
+ declare function recordToolOutputEvidence(ctx: Context, input: RecordToolOutputEvidenceInput): ToolOutputMetadata;
103
+ declare function markAssistantReferencedEvidence(ctx: Context, text: string): void;
104
+ declare function buildContextEvidenceDigest(ctx: Context): string;
105
+ declare function repeatedReadPressure(ctx: Context): number;
106
+
107
+ /**
108
+ * Deep merge utility — safely merges nested objects with configurable
109
+ * conflict resolution, array merging, and prototype-pollution guarding.
110
+ *
111
+ * Used by:
112
+ * - config-loader (config layer merging with primitive-array concatenation)
113
+ * - secret-vault (config patching)
114
+ * - json-path (json_merge tool with prefer-base / prefer-patch semantics)
115
+ *
116
+ * @module utils/deep-merge
117
+ */
118
+ declare const FORBIDDEN_PROTO_KEYS: Set<string>;
119
+ /** True when every element is a primitive or null (no nested objects/arrays). */
120
+ declare function isPrimitiveArray(a: unknown[]): boolean;
121
+ interface DeepMergeOptions {
122
+ /**
123
+ * Which side wins on collision for scalars and arrays.
124
+ *
125
+ * - `'prefer-patch'` (default): patch value replaces base value.
126
+ * - `'prefer-base'`: base value is kept, patch value is ignored.
127
+ */
128
+ conflictResolution?: 'prefer-base' | 'prefer-patch';
129
+ /**
130
+ * How to handle array values.
131
+ *
132
+ * - `'replace'` (default): patch array replaces base array entirely.
133
+ * - `'concat-primitives'`: when both values are primitive arrays,
134
+ * they are concatenated and deduped (via Set). Non-primitive
135
+ * arrays still replace the base wholesale.
136
+ */
137
+ arrayMode?: 'replace' | 'concat-primitives';
138
+ /**
139
+ * Skip prototype-pollution keys (`__proto__`, `constructor`, etc.).
140
+ * Enabled by default. Only disable when you control both inputs
141
+ * and the keyset (e.g. when merging trusted JSON schemas).
142
+ */
143
+ protectProto?: boolean;
144
+ /**
145
+ * Optional callback fired when a non-primitive (object) array is
146
+ * replaced wholesale (only relevant with `arrayMode: 'concat-primitives'`).
147
+ * Receives the key name, existing array length, and patch array length.
148
+ * Used by config-loader for debug logging.
149
+ */
150
+ onNonPrimitiveArrayReplace?: (key: string, existingLen: number, patchLen: number) => void;
151
+ }
152
+ /**
153
+ * Recursively merge `patch` into `base`, returning a new object.
154
+ *
155
+ * - Nested plain objects are merged recursively.
156
+ * - Arrays are handled per `options.arrayMode`.
157
+ * - Scalar collisions are resolved per `options.conflictResolution`.
158
+ * - `null` and non-object values in `patch` replace the base value
159
+ * (unless `conflictResolution` is `'prefer-base'`).
160
+ * - Keys in `base` that are absent from `patch` are preserved.
161
+ * - `FORBIDDEN_PROTO_KEYS` are skipped in the patch (unless
162
+ * `options.protectProto` is set to `false`).
163
+ *
164
+ * The function is generic over `T extends Record<string, unknown>` for
165
+ * callers that pass typed config objects, but the runtime signature
166
+ * also accepts `unknown` inputs (used by the json-path plugin).
167
+ */
168
+ declare function deepMerge<T extends Record<string, unknown>>(base: T, patch: Record<string, unknown>, options?: DeepMergeOptions): T;
169
+ declare function deepMerge(base: unknown, patch: unknown, options?: DeepMergeOptions): unknown;
170
+
171
+ /**
172
+ * Myers diff with unified-format output. No external dependencies.
173
+ * Operates on arrays of lines (newline-terminated or stripped).
174
+ */
175
+ interface UnifiedDiffOptions {
176
+ context?: number | undefined;
177
+ fromFile?: string | undefined;
178
+ toFile?: string | undefined;
179
+ }
180
+ declare function unifiedDiff(oldText: string, newText: string, opts?: UnifiedDiffOptions): string;
181
+
182
+ /**
183
+ * Resolve `pattern` to the set of concrete file paths it matches.
184
+ * Literal paths (no glob chars) are returned as-is.
185
+ *
186
+ * @example
187
+ * await expandGlob('src/**\/*.ts') // → ['src/a.ts', 'src/b/c.ts', ...]
188
+ * await expandGlob('foo.txt') // → ['foo.txt']
189
+ */
190
+ declare function expandGlob(pattern: string): Promise<string[]>;
191
+
192
+ declare function compileGlob(pattern: string): RegExp;
193
+ declare function matchGlob(pattern: string, input: string): boolean;
194
+ declare function matchAny(patterns: string[], input: string): boolean;
195
+
196
+ /**
197
+ * Shared IP-address guards for SSRF protection.
198
+ *
199
+ * Exported so `fetch.ts` (tools), `web-search/index.ts` (plugins), and any
200
+ * other package that needs to validate IPs can all consume the same logic.
201
+ * Any future additions (e.g. extra CIDR blocks) need only be made here.
202
+ */
203
+ /**
204
+ * True if `addr` is in a private / loopback / link-local / reserved / CGNAT /
205
+ * multicast range. `net.isIP` is called by the caller first so `addr` is
206
+ * guaranteed to be a canonical dotted-quad at this point.
207
+ */
208
+ declare function isPrivateIPv4(addr: string): boolean;
209
+ /**
210
+ * True if `raw` (an IPv6 literal, already lowercased) is loopback / unique-local /
211
+ * link-local / unspecified / IPv4-mapped-private.
212
+ */
213
+ declare function isPrivateIPv6(raw: string): boolean;
214
+ /**
215
+ * Expand an IPv6 string into exactly 8 16-bit numbers. Handles `::` compression.
216
+ * Returns null on malformed input — caller should treat that as "block".
217
+ */
218
+ declare function expandIPv6(addr: string): number[] | null;
219
+ /**
220
+ * Convenience: throw if `hostname` resolves to a private / loopback IP.
221
+ * Use as a pre-flight check before opening a socket.
222
+ *
223
+ * ⚠️ This is not sufficient alone — connections must also use a pinned
224
+ * dispatcher (so the OS re-uses the already-resolved address) or the same
225
+ * check must be applied after every redirect hop. See `guardedLookup` in
226
+ * `fetch.ts` for the connection-level enforcement.
227
+ */
228
+ declare function assertNotPrivateHost(hostname: string): Promise<void>;
229
+
230
+ /**
231
+ * Attempt to close an incomplete JSON object string by auto-closing braces
232
+ * and completing any unclosed double-quoted string values.
233
+ *
234
+ * Strategy:
235
+ * 1. Compute origOpen from the ORIGINAL input (how many braces are unclosed).
236
+ * 2. Add that many closing braces. If result is now valid JSON → return it.
237
+ * 3. If still invalid: trim trailing whitespace, strip trailing backslash.
238
+ * 4. Walk backwards to detect an unclosed string value.
239
+ * - Quote followed by `:` → key-name, skip
240
+ * - Quote followed by `,` `}` or end-of-string → toggle in/out of string
241
+ * 5. If we end INSIDE a string (unclosed opening `"`), append `"` + origOpen `}`.
242
+ *
243
+ * Known limitations:
244
+ * - Strings whose content ends with a `"` character cannot be repaired
245
+ * (algorithm can't distinguish content-`"` from string-terminator `"`).
246
+ * - Input ending in bare `:` (incomplete value expression) can't be meaningfully repaired.
247
+ * - Bare `{` returns unchanged.
248
+ * - If origOpen=0 (braces balanced) but string is unclosed, repair is skipped
249
+ * (the input would be valid JSON per JSON.parse, so it's returned as-is).
250
+ */
251
+ declare function completePartialObject(s: string): string;
252
+
253
+ /**
254
+ * Minimal JSON Schema validator — covers the subset needed for plugin
255
+ * configSchema validation and tool inputSchema sanity checks. Intentionally
256
+ * small (~80 lines, zero deps) and tolerant: unknown keywords are ignored so
257
+ * authors can mix in non-standard extensions without breaking validation.
258
+ *
259
+ * NOT for full JSON Schema 2020-12 conformance. If a plugin needs $ref,
260
+ * conditional schemas, format validation, or anything else exotic, it should
261
+ * bring its own ajv-based validator and call this only for the cheap path.
262
+ */
263
+
264
+ interface ValidationError {
265
+ path: string;
266
+ message: string;
267
+ }
268
+ interface ValidationResult {
269
+ ok: boolean;
270
+ errors: ValidationError[];
271
+ }
272
+ declare function validateAgainstSchema(value: unknown, schema: JSONSchema): ValidationResult;
273
+
274
+ /**
275
+ * Merge per-provider `customModels` into top-level `configModels`.
276
+ *
277
+ * Keys present in `configModels` always win over `providerCustomModels`
278
+ * when the same model id appears in both places. This lets the user
279
+ * override provider-attached definitions from the top-level config.
280
+ *
281
+ * Pure: never mutates its inputs.
282
+ */
283
+ declare function mergeCustomModelDefs(providerCustomModels: Record<string, CustomModelDefinition> | undefined, configModels: Record<string, CustomModelDefinition> | undefined): Record<string, CustomModelDefinition> | undefined;
284
+
285
+ /**
286
+ * Deep-merge a curated `overlay` payload on top of a `base` payload (both in
287
+ * the models.dev `api.json` shape). The overlay always wins: it can add
288
+ * providers/models the base lacks and override fields the base gets wrong.
289
+ *
290
+ * Precedence rules:
291
+ * - Provider present in both → scalar fields (`name`, `npm`, `api`, `env`,
292
+ * `doc`) come from the overlay when set; `models` maps merge by model id.
293
+ * - Provider only in the overlay → added wholesale.
294
+ * - Model present in both → overlay model fields override base model fields
295
+ * (`{ ...base, ...overlay }`), with the nested `limit` / `cost` /
296
+ * `modalities` objects merged one level deeper so an overlay can fix just
297
+ * `limit.context` without restating the rest of the model.
298
+ * - Model only in the overlay → added.
299
+ *
300
+ * Pure: never mutates its inputs.
301
+ */
302
+ declare function mergeModelsPayload(base: ModelsDevPayload, overlay: ModelsDevPayload): ModelsDevPayload;
303
+
304
+ interface MessageRepairReport {
305
+ changed: boolean;
306
+ removedToolUses: string[];
307
+ removedToolResults: string[];
308
+ removedMessages: number;
309
+ }
310
+ interface MessageRepairResult {
311
+ messages: Message[];
312
+ report: MessageRepairReport;
313
+ }
314
+ /**
315
+ * Repair provider-level tool-call adjacency invariants.
316
+ *
317
+ * Anthropic requires every assistant `tool_use` block to have a matching
318
+ * `tool_result` block in the immediately following user message. Manual
319
+ * context surgery (summary/prune) can cut through the middle of such an
320
+ * exchange. This function removes only the now-orphaned protocol blocks,
321
+ * preserving surrounding text/images/thinking blocks where possible.
322
+ */
323
+ declare function repairToolUseAdjacency(messages: Message[]): MessageRepairResult;
324
+
325
+ type NewlineStyle = 'lf' | 'crlf' | 'cr';
326
+ declare function detectNewlineStyle(text: string): NewlineStyle;
327
+ declare function toStyle(text: string, style: NewlineStyle): string;
328
+ declare function normalizeToLf(text: string): string;
329
+
330
+ /**
331
+ * Compile a user-supplied regex with conservative bounds against ReDoS.
332
+ *
333
+ * Duplicated from @wrongstack/tools/_regex.ts to avoid a circular
334
+ * dependency (tools depends on core, not vice versa). Keep both copies
335
+ * in sync if the heuristics change.
336
+ *
337
+ * V8's regex engine is backtracking-based and cannot interrupt a
338
+ * synchronous match — a pattern like `(a+)+$` against a sufficiently
339
+ * long line will pin a worker for seconds.
340
+ */
341
+ interface CompileResult {
342
+ ok: true;
343
+ regex: RegExp;
15
344
  }
16
- interface FileLockOptions {
17
- timeoutMs?: number | undefined;
18
- staleMs?: number | undefined;
345
+ interface CompileFail {
346
+ ok: false;
347
+ reason: string;
19
348
  }
20
- declare function atomicWrite(targetPath: string, content: string | Uint8Array, opts?: AtomicWriteOptions): Promise<void>;
21
- declare function ensureDir(dir: string): Promise<void>;
22
- declare function withFileLock<T>(targetPath: string, fn: () => Promise<T>, opts?: FileLockOptions): Promise<T>;
349
+ declare function compileUserRegex(pattern: string, flags: string): CompileResult | CompileFail;
23
350
 
24
351
  interface SafeParseResult<T> {
25
352
  ok: boolean;
@@ -40,30 +367,19 @@ declare function safeStringify(value: unknown, pretty?: boolean): string;
40
367
  */
41
368
  declare function sanitizeJsonString(s: string): string | null;
42
369
 
43
- type NewlineStyle = 'lf' | 'crlf' | 'cr';
44
- declare function detectNewlineStyle(text: string): NewlineStyle;
45
- declare function toStyle(text: string, style: NewlineStyle): string;
46
- declare function normalizeToLf(text: string): string;
370
+ /** Resolve a promise after `ms` milliseconds. Prefer this over raw
371
+ * `setTimeout` wrappers so all delay sites use a single implementation
372
+ * and an abortable variant can be introduced without a codebase-wide hunt. */
373
+ declare function sleep(ms: number): Promise<void>;
47
374
 
48
- declare const color: {
49
- reset: (s: string) => string;
50
- bold: (s: string) => string;
51
- dim: (s: string) => string;
52
- italic: (s: string) => string;
53
- underline: (s: string) => string;
54
- red: (s: string) => string;
55
- green: (s: string) => string;
56
- yellow: (s: string) => string;
57
- blue: (s: string) => string;
58
- magenta: (s: string) => string;
59
- cyan: (s: string) => string;
60
- gray: (s: string) => string;
61
- amber: (s: string) => string;
62
- pink: (s: string) => string;
63
- bgRed: (s: string) => string;
64
- bgGreen: (s: string) => string;
65
- };
66
- declare function stripAnsi(s: string): string;
375
+ /**
376
+ * String utilities shared across the WrongStack codebase.
377
+ */
378
+ /**
379
+ * Truncate a string to at most `max` characters, appending an ellipsis if it
380
+ * was longer. Returns the original string unchanged when it fits.
381
+ */
382
+ declare function truncate(s: string, max: number): string;
67
383
 
68
384
  /**
69
385
  * TTY detection helpers — the single source of truth for "is this process
@@ -141,233 +457,77 @@ declare function setRawMode(input: NodeJS.ReadStream, mode: boolean): boolean;
141
457
  * When no prompt is active the guard is `null` and writes pass straight
142
458
  * through — so agent-turn output (spinner, renderer) is untouched.
143
459
  */
144
- interface OutputLineGuard {
145
- /** Clear the current input row right before an out-of-band write. */
146
- suspend(): void;
147
- /** Repaint the prompt + in-progress draft right after the write. */
148
- resume(): void;
149
- }
150
- /**
151
- * Register (or clear, with `null`) the guard that brackets out-of-band
152
- * writes. Installed by {@link writeOut}/{@link writeErr} consumers — in
153
- * practice the CLI's readline input reader — only while a prompt is live.
154
- * Idempotent; the most recent caller wins.
155
- */
156
- declare function setOutputLineGuard(guard: OutputLineGuard | null): void;
157
- /**
158
- * Write `s` to `stream` (defaults to `process.stdout`). Returns `false`
159
- * when the stream is missing or doesn't expose `write` so callers can
160
- * degrade silently under hostile host environments (closed pipe, mock
161
- * injects `null`, test replaces the stream with a stub).
162
- *
163
- * Why a helper:
164
- * 1. **Single seam for output capture in tests** — stub `writeOut` once
165
- * and assert on what the rest of the codebase intended to print,
166
- * without spying on `process.stdout.write` (which is brittle and
167
- * leaks across parallel test files).
168
- * 2. **Stream swap without grep** — routing the CLI's output to a
169
- * logger or `out.log` becomes a one-line change at process boot.
170
- * 3. **Defensive default** — closes the "what if `process.stdout` is
171
- * `null`" gap that currently exists at ~50 call sites that just
172
- * call `process.stdout.write(s)` and crash on certain Windows
173
- * redirect invocations.
174
- *
175
- * Call-site migration is staged: this commit introduces the helper, a
176
- * follow-up commit replaces the 50+ `process.stdout.write(...)` sites
177
- * with `writeOut(...)`. Until that migration lands, both forms coexist
178
- * and `writeOut` is the preferred form for new code.
179
- */
180
- declare function writeOut(s: string, stream?: NodeJS.WriteStream): boolean;
181
- /**
182
- * Symmetric partner of `writeOut` for the standard error stream. Same shape,
183
- * same defensive contract, same single-seam-for-tests story — just defaults to
184
- * `process.stderr` instead of `process.stdout`.
185
- *
186
- * Use this in code paths that emit error/diagnostic/warning text. Keeping
187
- * these two helpers split (rather than a single `writeTo(s, stream)`) means
188
- * the call site reads as a clear intent signal: "I am writing an error" vs.
189
- * "I am writing a result" — which matters for callers that decide between
190
- * stdout/stderr routing (e.g. `--quiet` flags, log-level filtering,
191
- * structured-log rewriters that fork on stream).
192
- *
193
- * Stderr writes from the core logger (see `infrastructure/logger.ts`) and from
194
- * the TUI guard (see `tui/run-tui.ts`) used to call `process.stderr.write`
195
- * directly. Routing them through this helper lets tests stub the stream at
196
- * one boundary and lets future logging middleware (e.g. a JSON-line rewriter)
197
- * swap the destination for the entire process in one place.
198
- */
199
- declare function writeErr(s: string, stream?: NodeJS.WriteStream): boolean;
200
-
201
- /**
202
- * Canonical text rendering of the live todo list, shared by the CLI's
203
- * `/todos` slash command and the TUI's auto-echo (which prints the same
204
- * snapshot to chat history each time the `todo` tool mutates the list).
205
- *
206
- * Layout: a header line with the `done/total done` count, then one row
207
- * per item — `[ ]` pending, `[~]` in-progress, `[x]` completed. In-
208
- * progress rows prefer `activeForm` ("Building the project") over the
209
- * imperative `content` ("Build the project") when present.
210
- *
211
- * Returned as a single newline-joined string so callers can hand it
212
- * straight to a history dispatcher or stdout.
213
- */
214
- declare function formatTodosList(todos: TodoItem[]): string;
215
-
216
- /**
217
- * String utilities shared across the WrongStack codebase.
218
- */
219
- /**
220
- * Truncate a string to at most `max` characters, appending an ellipsis if it
221
- * was longer. Returns the original string unchanged when it fits.
222
- */
223
- declare function truncate(s: string, max: number): string;
224
-
225
- declare function compileGlob(pattern: string): RegExp;
226
- declare function matchGlob(pattern: string, input: string): boolean;
227
- declare function matchAny(patterns: string[], input: string): boolean;
228
-
229
- /**
230
- * Myers diff with unified-format output. No external dependencies.
231
- * Operates on arrays of lines (newline-terminated or stripped).
232
- */
233
- interface UnifiedDiffOptions {
234
- context?: number | undefined;
235
- fromFile?: string | undefined;
236
- toFile?: string | undefined;
237
- }
238
- declare function unifiedDiff(oldText: string, newText: string, opts?: UnifiedDiffOptions): string;
239
-
240
- /**
241
- * Build a sanitized child-process environment.
242
- *
243
- * The bash/exec tools and MCP stdio transports execute LLM-generated or
244
- * configured commands. The parent process carries provider API keys
245
- * (ANTHROPIC_API_KEY, OPENAI_API_KEY, ...), VCS tokens (GITHUB_TOKEN),
246
- * and cloud credentials. Forwarding those to a child is an exfiltration
247
- * vector even with `permission: 'confirm'` — a compromised MCP server
248
- * or a cleverly composed shell pipeline can leak secrets.
249
- *
250
- * Strategy: copy a small, explicit allowlist of variables that real builds
251
- * need, then copy anything else that does NOT look secret-bearing. This
252
- * preserves user-friendly behavior (locale, terminal, npm config) while
253
- * blocking the obvious leak channels.
254
- *
255
- * Override with `WRONGSTACK_CHILD_ENV_PASSTHROUGH=1` to forward the full
256
- * parent environment unchanged (opt-in for advanced users who understand
257
- * the risk).
258
- */
259
- interface BuildChildEnvOptions {
260
- /** Session ID to inject as WRONGSTACK_SESSION_ID. */
261
- sessionId?: string | undefined;
262
- /** Additional env vars to merge (takes priority over filtered parent env). */
263
- extra?: NodeJS.ProcessEnv | undefined;
264
- }
265
- /**
266
- * Build a filtered child-process environment suitable for bash, exec, and
267
- * MCP server subprocesses. Strips API keys, tokens, and other credentials
268
- * while preserving system/tooling variables.
269
- */
270
- declare function buildChildEnv(optsOrSessionId?: BuildChildEnvOptions | string): NodeJS.ProcessEnv;
271
-
272
- /** Resolve a promise after `ms` milliseconds. Prefer this over raw
273
- * `setTimeout` wrappers so all delay sites use a single implementation
274
- * and an abortable variant can be introduced without a codebase-wide hunt. */
275
- declare function sleep(ms: number): Promise<void>;
276
-
277
- /**
278
- * Exhaustiveness check for discriminated union switches.
279
- * Place in the `default` branch of a switch over a union type
280
- * to get a compile-time error when a new variant is added.
281
- *
282
- * @example
283
- * switch (block.type) {
284
- * case 'text': return renderText(block);
285
- * case 'tool_use': return renderToolUse(block);
286
- * default: return assertNever(block);
287
- * }
288
- */
289
- declare function assertNever(x: never, message?: string): never;
290
-
291
- /**
292
- * Deep merge utility — safely merges nested objects with configurable
293
- * conflict resolution, array merging, and prototype-pollution guarding.
294
- *
295
- * Used by:
296
- * - config-loader (config layer merging with primitive-array concatenation)
297
- * - secret-vault (config patching)
298
- * - json-path (json_merge tool with prefer-base / prefer-patch semantics)
299
- *
300
- * @module utils/deep-merge
301
- */
302
- declare const FORBIDDEN_PROTO_KEYS: Set<string>;
303
- /** True when every element is a primitive or null (no nested objects/arrays). */
304
- declare function isPrimitiveArray(a: unknown[]): boolean;
305
- interface DeepMergeOptions {
306
- /**
307
- * Which side wins on collision for scalars and arrays.
308
- *
309
- * - `'prefer-patch'` (default): patch value replaces base value.
310
- * - `'prefer-base'`: base value is kept, patch value is ignored.
311
- */
312
- conflictResolution?: 'prefer-base' | 'prefer-patch';
313
- /**
314
- * How to handle array values.
315
- *
316
- * - `'replace'` (default): patch array replaces base array entirely.
317
- * - `'concat-primitives'`: when both values are primitive arrays,
318
- * they are concatenated and deduped (via Set). Non-primitive
319
- * arrays still replace the base wholesale.
320
- */
321
- arrayMode?: 'replace' | 'concat-primitives';
322
- /**
323
- * Skip prototype-pollution keys (`__proto__`, `constructor`, etc.).
324
- * Enabled by default. Only disable when you control both inputs
325
- * and the keyset (e.g. when merging trusted JSON schemas).
326
- */
327
- protectProto?: boolean;
328
- /**
329
- * Optional callback fired when a non-primitive (object) array is
330
- * replaced wholesale (only relevant with `arrayMode: 'concat-primitives'`).
331
- * Receives the key name, existing array length, and patch array length.
332
- * Used by config-loader for debug logging.
333
- */
334
- onNonPrimitiveArrayReplace?: (key: string, existingLen: number, patchLen: number) => void;
460
+ interface OutputLineGuard {
461
+ /** Clear the current input row right before an out-of-band write. */
462
+ suspend(): void;
463
+ /** Repaint the prompt + in-progress draft right after the write. */
464
+ resume(): void;
335
465
  }
336
466
  /**
337
- * Recursively merge `patch` into `base`, returning a new object.
467
+ * Register (or clear, with `null`) the guard that brackets out-of-band
468
+ * writes. Installed by {@link writeOut}/{@link writeErr} consumers — in
469
+ * practice the CLI's readline input reader — only while a prompt is live.
470
+ * Idempotent; the most recent caller wins.
471
+ */
472
+ declare function setOutputLineGuard(guard: OutputLineGuard | null): void;
473
+ /**
474
+ * Write `s` to `stream` (defaults to `process.stdout`). Returns `false`
475
+ * when the stream is missing or doesn't expose `write` so callers can
476
+ * degrade silently under hostile host environments (closed pipe, mock
477
+ * injects `null`, test replaces the stream with a stub).
338
478
  *
339
- * - Nested plain objects are merged recursively.
340
- * - Arrays are handled per `options.arrayMode`.
341
- * - Scalar collisions are resolved per `options.conflictResolution`.
342
- * - `null` and non-object values in `patch` replace the base value
343
- * (unless `conflictResolution` is `'prefer-base'`).
344
- * - Keys in `base` that are absent from `patch` are preserved.
345
- * - `FORBIDDEN_PROTO_KEYS` are skipped in the patch (unless
346
- * `options.protectProto` is set to `false`).
479
+ * Why a helper:
480
+ * 1. **Single seam for output capture in tests** — stub `writeOut` once
481
+ * and assert on what the rest of the codebase intended to print,
482
+ * without spying on `process.stdout.write` (which is brittle and
483
+ * leaks across parallel test files).
484
+ * 2. **Stream swap without grep** routing the CLI's output to a
485
+ * logger or `out.log` becomes a one-line change at process boot.
486
+ * 3. **Defensive default** closes the "what if `process.stdout` is
487
+ * `null`" gap that currently exists at ~50 call sites that just
488
+ * call `process.stdout.write(s)` and crash on certain Windows
489
+ * redirect invocations.
347
490
  *
348
- * The function is generic over `T extends Record<string, unknown>` for
349
- * callers that pass typed config objects, but the runtime signature
350
- * also accepts `unknown` inputs (used by the json-path plugin).
491
+ * Call-site migration is staged: this commit introduces the helper, a
492
+ * follow-up commit replaces the 50+ `process.stdout.write(...)` sites
493
+ * with `writeOut(...)`. Until that migration lands, both forms coexist
494
+ * and `writeOut` is the preferred form for new code.
351
495
  */
352
- declare function deepMerge<T extends Record<string, unknown>>(base: T, patch: Record<string, unknown>, options?: DeepMergeOptions): T;
353
- declare function deepMerge(base: unknown, patch: unknown, options?: DeepMergeOptions): unknown;
496
+ declare function writeOut(s: string, stream?: NodeJS.WriteStream): boolean;
497
+ /**
498
+ * Symmetric partner of `writeOut` for the standard error stream. Same shape,
499
+ * same defensive contract, same single-seam-for-tests story — just defaults to
500
+ * `process.stderr` instead of `process.stdout`.
501
+ *
502
+ * Use this in code paths that emit error/diagnostic/warning text. Keeping
503
+ * these two helpers split (rather than a single `writeTo(s, stream)`) means
504
+ * the call site reads as a clear intent signal: "I am writing an error" vs.
505
+ * "I am writing a result" — which matters for callers that decide between
506
+ * stdout/stderr routing (e.g. `--quiet` flags, log-level filtering,
507
+ * structured-log rewriters that fork on stream).
508
+ *
509
+ * Stderr writes from the core logger (see `infrastructure/logger.ts`) and from
510
+ * the TUI guard (see `tui/run-tui.ts`) used to call `process.stderr.write`
511
+ * directly. Routing them through this helper lets tests stub the stream at
512
+ * one boundary and lets future logging middleware (e.g. a JSON-line rewriter)
513
+ * swap the destination for the entire process in one place.
514
+ */
515
+ declare function writeErr(s: string, stream?: NodeJS.WriteStream): boolean;
354
516
 
355
517
  /**
356
- * Tool output serialization utilities.
357
- * Extracted from Agent.executeTools to allow reuse and consistent output handling.
518
+ * Canonical text rendering of the live todo list, shared by the CLI's
519
+ * `/todos` slash command and the TUI's auto-echo (which prints the same
520
+ * snapshot to chat history each time the `todo` tool mutates the list).
521
+ *
522
+ * Layout: a header line with the `done/total done` count, then one row
523
+ * per item — `[ ]` pending, `[~]` in-progress, `[x]` completed. In-
524
+ * progress rows prefer `activeForm` ("Building the project") over the
525
+ * imperative `content` ("Build the project") when present.
526
+ *
527
+ * Returned as a single newline-joined string so callers can hand it
528
+ * straight to a history dispatcher or stdout.
358
529
  */
359
- interface ToolOutputSerializerOptions {
360
- perIterationOutputCapBytes?: number | undefined;
361
- estimator?: ((text: string) => number) | undefined;
362
- }
363
- declare function createToolOutputSerializer(opts?: ToolOutputSerializerOptions): {
364
- serialize: (value: unknown) => string;
365
- enforceCap: (text: string, remainingBudget: number) => {
366
- text: string;
367
- newBudget: number;
368
- };
369
- capBytes: number;
370
- };
530
+ declare function formatTodosList(todos: TodoItem[]): string;
371
531
 
372
532
  /**
373
533
  * Estimate tokens for a tool_use block input.
@@ -480,164 +640,52 @@ declare function estimateRequestTokensCalibrated(messages: unknown, systemPrompt
480
640
  */
481
641
  declare function resetCalibration(calibrationKey?: string): void;
482
642
 
483
- interface MessageRepairReport {
484
- changed: boolean;
485
- removedToolUses: string[];
486
- removedToolResults: string[];
487
- removedMessages: number;
488
- }
489
- interface MessageRepairResult {
490
- messages: Message[];
491
- report: MessageRepairReport;
492
- }
493
- /**
494
- * Repair provider-level tool-call adjacency invariants.
495
- *
496
- * Anthropic requires every assistant `tool_use` block to have a matching
497
- * `tool_result` block in the immediately following user message. Manual
498
- * context surgery (summary/prune) can cut through the middle of such an
499
- * exchange. This function removes only the now-orphaned protocol blocks,
500
- * preserving surrounding text/images/thinking blocks where possible.
501
- */
502
- declare function repairToolUseAdjacency(messages: Message[]): MessageRepairResult;
503
-
504
643
  /**
505
- * Minimal JSON Schema validator — covers the subset needed for plugin
506
- * configSchema validation and tool inputSchema sanity checks. Intentionally
507
- * small (~80 lines, zero deps) and tolerant: unknown keywords are ignored so
508
- * authors can mix in non-standard extensions without breaking validation.
509
- *
510
- * NOT for full JSON Schema 2020-12 conformance. If a plugin needs $ref,
511
- * conditional schemas, format validation, or anything else exotic, it should
512
- * bring its own ajv-based validator and call this only for the cheap path.
644
+ * Tool output serialization utilities.
645
+ * Extracted from Agent.executeTools to allow reuse and consistent output handling.
513
646
  */
514
-
515
- interface ValidationError {
516
- path: string;
517
- message: string;
647
+ interface ToolOutputSerializerOptions {
648
+ perIterationOutputCapBytes?: number | undefined;
649
+ estimator?: ((text: string) => number) | undefined;
518
650
  }
519
- interface ValidationResult {
520
- ok: boolean;
521
- errors: ValidationError[];
651
+ interface ToolOutputSerializeContext {
652
+ toolName?: string | undefined;
653
+ input?: unknown;
522
654
  }
523
- declare function validateAgainstSchema(value: unknown, schema: JSONSchema): ValidationResult;
655
+ declare function createToolOutputSerializer(opts?: ToolOutputSerializerOptions): {
656
+ serialize: (value: unknown, context?: ToolOutputSerializeContext) => string;
657
+ enforceCap: (text: string, remainingBudget: number) => {
658
+ text: string;
659
+ newBudget: number;
660
+ };
661
+ capBytes: number;
662
+ };
524
663
 
525
- /**
526
- * Compile a user-supplied regex with conservative bounds against ReDoS.
527
- *
528
- * Duplicated from @wrongstack/tools/_regex.ts to avoid a circular
529
- * dependency (tools depends on core, not vice versa). Keep both copies
530
- * in sync if the heuristics change.
531
- *
532
- * V8's regex engine is backtracking-based and cannot interrupt a
533
- * synchronous match — a pattern like `(a+)+$` against a sufficiently
534
- * long line will pin a worker for seconds.
535
- */
536
- interface CompileResult {
537
- ok: true;
538
- regex: RegExp;
664
+ interface ToolWireDefinitionLike {
665
+ name: string;
666
+ description?: string | undefined;
667
+ inputSchema: unknown;
539
668
  }
540
- interface CompileFail {
541
- ok: false;
542
- reason: string;
669
+ interface CompactToolDefinitionForWireOptions {
670
+ /** Top-level tool description budget. */
671
+ descriptionMaxChars?: number | undefined;
672
+ /** Per-JSON-Schema `description` annotation budget. */
673
+ schemaDescriptionMaxChars?: number | undefined;
674
+ }
675
+ interface CompactWireToolDefinition {
676
+ name: string;
677
+ description: string;
678
+ inputSchema: Record<string, unknown>;
543
679
  }
544
- declare function compileUserRegex(pattern: string, flags: string): CompileResult | CompileFail;
545
-
546
- /**
547
- * Resolve `pattern` to the set of concrete file paths it matches.
548
- * Literal paths (no glob chars) are returned as-is.
549
- *
550
- * @example
551
- * await expandGlob('src/**\/*.ts') // → ['src/a.ts', 'src/b/c.ts', ...]
552
- * await expandGlob('foo.txt') // → ['foo.txt']
553
- */
554
- declare function expandGlob(pattern: string): Promise<string[]>;
555
-
556
- /**
557
- * Attempt to close an incomplete JSON object string by auto-closing braces
558
- * and completing any unclosed double-quoted string values.
559
- *
560
- * Strategy:
561
- * 1. Compute origOpen from the ORIGINAL input (how many braces are unclosed).
562
- * 2. Add that many closing braces. If result is now valid JSON → return it.
563
- * 3. If still invalid: trim trailing whitespace, strip trailing backslash.
564
- * 4. Walk backwards to detect an unclosed string value.
565
- * - Quote followed by `:` → key-name, skip
566
- * - Quote followed by `,` `}` or end-of-string → toggle in/out of string
567
- * 5. If we end INSIDE a string (unclosed opening `"`), append `"` + origOpen `}`.
568
- *
569
- * Known limitations:
570
- * - Strings whose content ends with a `"` character cannot be repaired
571
- * (algorithm can't distinguish content-`"` from string-terminator `"`).
572
- * - Input ending in bare `:` (incomplete value expression) can't be meaningfully repaired.
573
- * - Bare `{` returns unchanged.
574
- * - If origOpen=0 (braces balanced) but string is unclosed, repair is skipped
575
- * (the input would be valid JSON per JSON.parse, so it's returned as-is).
576
- */
577
- declare function completePartialObject(s: string): string;
578
-
579
- /**
580
- * Deep-merge a curated `overlay` payload on top of a `base` payload (both in
581
- * the models.dev `api.json` shape). The overlay always wins: it can add
582
- * providers/models the base lacks and override fields the base gets wrong.
583
- *
584
- * Precedence rules:
585
- * - Provider present in both → scalar fields (`name`, `npm`, `api`, `env`,
586
- * `doc`) come from the overlay when set; `models` maps merge by model id.
587
- * - Provider only in the overlay → added wholesale.
588
- * - Model present in both → overlay model fields override base model fields
589
- * (`{ ...base, ...overlay }`), with the nested `limit` / `cost` /
590
- * `modalities` objects merged one level deeper so an overlay can fix just
591
- * `limit.context` without restating the rest of the model.
592
- * - Model only in the overlay → added.
593
- *
594
- * Pure: never mutates its inputs.
595
- */
596
- declare function mergeModelsPayload(base: ModelsDevPayload, overlay: ModelsDevPayload): ModelsDevPayload;
597
-
598
- /**
599
- * Merge per-provider `customModels` into top-level `configModels`.
600
- *
601
- * Keys present in `configModels` always win over `providerCustomModels`
602
- * when the same model id appears in both places. This lets the user
603
- * override provider-attached definitions from the top-level config.
604
- *
605
- * Pure: never mutates its inputs.
606
- */
607
- declare function mergeCustomModelDefs(providerCustomModels: Record<string, CustomModelDefinition> | undefined, configModels: Record<string, CustomModelDefinition> | undefined): Record<string, CustomModelDefinition> | undefined;
608
-
609
- /**
610
- * Shared IP-address guards for SSRF protection.
611
- *
612
- * Exported so `fetch.ts` (tools), `web-search/index.ts` (plugins), and any
613
- * other package that needs to validate IPs can all consume the same logic.
614
- * Any future additions (e.g. extra CIDR blocks) need only be made here.
615
- */
616
- /**
617
- * True if `addr` is in a private / loopback / link-local / reserved / CGNAT /
618
- * multicast range. `net.isIP` is called by the caller first so `addr` is
619
- * guaranteed to be a canonical dotted-quad at this point.
620
- */
621
- declare function isPrivateIPv4(addr: string): boolean;
622
- /**
623
- * True if `raw` (an IPv6 literal, already lowercased) is loopback / unique-local /
624
- * link-local / unspecified / IPv4-mapped-private.
625
- */
626
- declare function isPrivateIPv6(raw: string): boolean;
627
- /**
628
- * Expand an IPv6 string into exactly 8 16-bit numbers. Handles `::` compression.
629
- * Returns null on malformed input — caller should treat that as "block".
630
- */
631
- declare function expandIPv6(addr: string): number[] | null;
632
680
  /**
633
- * Convenience: throw if `hostname` resolves to a private / loopback IP.
634
- * Use as a pre-flight check before opening a socket.
681
+ * Return the provider-wire version of a tool definition.
635
682
  *
636
- * ⚠️ This is not sufficient alone connections must also use a pinned
637
- * dispatcher (so the OS re-uses the already-resolved address) or the same
638
- * check must be applied after every redirect hop. See `guardedLookup` in
639
- * `fetch.ts` for the connection-level enforcement.
683
+ * Tool schemas remain structurally intact: validation keywords, property
684
+ * names, required fields, enum values, and nested shapes are preserved. The
685
+ * only reduction is on human prose annotations (`description`), which are the
686
+ * largest repeated cost in provider tool declarations.
640
687
  */
641
- declare function assertNotPrivateHost(hostname: string): Promise<void>;
688
+ declare function compactToolDefinitionForWire(tool: ToolWireDefinitionLike, opts?: CompactToolDefinitionForWireOptions): CompactWireToolDefinition;
689
+ declare function compactSchemaDescriptions(schema: unknown, maxDescriptionChars?: number): Record<string, unknown>;
642
690
 
643
- export { type AtomicWriteOptions, type BuildChildEnvOptions, type CompileFail, type CompileResult, type DeepMergeOptions, FORBIDDEN_PROTO_KEYS, type FileLockOptions, type MessageRepairReport, type MessageRepairResult, type NewlineStyle, type OutputLineGuard, type RequestTokenBreakdown, type SafeParseResult, type ToolOutputSerializerOptions, type UnifiedDiffOptions, type ValidationError, type ValidationResult, assertNever, assertNotPrivateHost, atomicWrite, buildChildEnv, color, compileGlob, compileUserRegex, completePartialObject, computeMessageTokens, createToolOutputSerializer, deepMerge, detectNewlineStyle, ensureDir, estimateMessageTokens, estimateRequestTokens, estimateRequestTokensCalibrated, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, expandGlob, expandIPv6, formatTodosList, getCalibrationState, getTermSize, isInteractive, isPrimitiveArray, isPrivateIPv4, isPrivateIPv6, isStdinTTY, isStdoutTTY, matchAny, matchGlob, mergeCustomModelDefs, mergeModelsPayload, normalizeToLf, onResize, recordActualUsage, repairToolUseAdjacency, resetCalibration, safeParse, safeStringify, sanitizeJsonString, setOutputLineGuard, setRawMode, sleep, stripAnsi, toStyle, truncate, unifiedDiff, validateAgainstSchema, withFileLock, writeErr, writeOut };
691
+ export { type AtomicWriteOptions, type BuildChildEnvOptions, type CompactToolDefinitionForWireOptions, type CompactWireToolDefinition, type CompileFail, type CompileResult, type DeepMergeOptions, FORBIDDEN_PROTO_KEYS, type FileLockOptions, type MessageRepairReport, type MessageRepairResult, type NewlineStyle, type OutputLineGuard, type RecordToolOutputEvidenceInput, type RequestTokenBreakdown, type SafeParseResult, type ToolOutputSerializerOptions, type ToolWireDefinitionLike, type UnifiedDiffOptions, type ValidationError, type ValidationResult, assertNever, assertNotPrivateHost, atomicWrite, buildChildEnv, buildContextEvidenceDigest, color, compactSchemaDescriptions, compactToolDefinitionForWire, compileGlob, compileUserRegex, completePartialObject, computeMessageTokens, createContextEvidenceState, createToolOutputSerializer, deepMerge, detectNewlineStyle, ensureDir, estimateMessageTokens, estimateRequestTokens, estimateRequestTokensCalibrated, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, expandGlob, expandIPv6, formatTodosList, getCalibrationState, getTermSize, isInteractive, isPrimitiveArray, isPrivateIPv4, isPrivateIPv6, isStdinTTY, isStdoutTTY, markAssistantReferencedEvidence, matchAny, matchGlob, mergeCustomModelDefs, mergeModelsPayload, normalizeToLf, onResize, recordActualUsage, recordToolOutputEvidence, recordUserIntentEvidence, repairToolUseAdjacency, repeatedReadPressure, resetCalibration, safeParse, safeStringify, sanitizeJsonString, setOutputLineGuard, setRawMode, sleep, stripAnsi, toStyle, truncate, unifiedDiff, validateAgainstSchema, withFileLock, writeErr, writeOut };