reasonix 0.36.2 → 0.37.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.
- package/README.md +47 -75
- package/README.zh-CN.md +47 -32
- package/dist/cli/{chat-QSM6JKUA.js → chat-7257YAPG.js} +11 -11
- package/dist/cli/{chunk-DFP4YSVM.js → chunk-6CXT5JRM.js} +17 -2
- package/dist/cli/{chunk-DFP4YSVM.js.map → chunk-6CXT5JRM.js.map} +1 -1
- package/dist/cli/{chunk-G3XNWSFN.js → chunk-6NMWJSES.js} +2 -2
- package/dist/cli/{chunk-MLXUGPJE.js → chunk-GKZJXYMY.js} +79 -1
- package/dist/cli/chunk-GKZJXYMY.js.map +1 -0
- package/dist/cli/{chunk-IPCPEZWQ.js → chunk-JGZKTAOH.js} +2 -2
- package/dist/cli/{chunk-BJ376EN3.js → chunk-JULZ7JTO.js} +3 -3
- package/dist/cli/{chunk-NHV5YGTB.js → chunk-MSKUP6PD.js} +1372 -1012
- package/dist/cli/chunk-MSKUP6PD.js.map +1 -0
- package/dist/cli/{chunk-RNSZYYGB.js → chunk-SEFXUF24.js} +13 -13
- package/dist/cli/chunk-SEFXUF24.js.map +1 -0
- package/dist/cli/{chunk-C5543CRX.js → chunk-VF57YX2M.js} +2 -2
- package/dist/cli/{chunk-K6W64QVE.js → chunk-XOIDSPMQ.js} +27 -7
- package/dist/cli/chunk-XOIDSPMQ.js.map +1 -0
- package/dist/cli/{chunk-4D6TT2IB.js → chunk-YER7WCHF.js} +13 -6
- package/dist/cli/chunk-YER7WCHF.js.map +1 -0
- package/dist/cli/{code-6C5A2CY3.js → code-64EG5IU2.js} +14 -13
- package/dist/cli/code-64EG5IU2.js.map +1 -0
- package/dist/cli/{doctor-DKD34EFD.js → doctor-BW5HSQDW.js} +5 -5
- package/dist/cli/{events-P27CX7LN.js → events-SQXPVV7B.js} +3 -3
- package/dist/cli/index.js +27 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/prompt-KGIUONO3.js +13 -0
- package/dist/cli/{prune-sessions-ERL6B4G5.js → prune-sessions-FCFOYCBP.js} +2 -2
- package/dist/cli/{run-AG4Y45X7.js → run-RWCOA32G.js} +7 -7
- package/dist/cli/{server-GNHR5K3N.js → server-6ZW4TQUP.js} +94 -48
- package/dist/cli/{server-GNHR5K3N.js.map → server-6ZW4TQUP.js.map} +1 -1
- package/dist/cli/{sessions-MHRF3GU4.js → sessions-5ISNWFMU.js} +7 -7
- package/dist/cli/{setup-IIAJXHP4.js → setup-HJG23NKJ.js} +2 -2
- package/dist/cli/{version-7AL4JZ63.js → version-BXAN7Q4V.js} +7 -7
- package/dist/index.d.ts +6 -2
- package/dist/index.js +149 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/chunk-4D6TT2IB.js.map +0 -1
- package/dist/cli/chunk-K6W64QVE.js.map +0 -1
- package/dist/cli/chunk-MLXUGPJE.js.map +0 -1
- package/dist/cli/chunk-NHV5YGTB.js.map +0 -1
- package/dist/cli/chunk-RNSZYYGB.js.map +0 -1
- package/dist/cli/code-6C5A2CY3.js.map +0 -1
- package/dist/cli/prompt-QSEB7HNQ.js +0 -11
- /package/dist/cli/{chat-QSM6JKUA.js.map → chat-7257YAPG.js.map} +0 -0
- /package/dist/cli/{chunk-G3XNWSFN.js.map → chunk-6NMWJSES.js.map} +0 -0
- /package/dist/cli/{chunk-IPCPEZWQ.js.map → chunk-JGZKTAOH.js.map} +0 -0
- /package/dist/cli/{chunk-BJ376EN3.js.map → chunk-JULZ7JTO.js.map} +0 -0
- /package/dist/cli/{chunk-C5543CRX.js.map → chunk-VF57YX2M.js.map} +0 -0
- /package/dist/cli/{doctor-DKD34EFD.js.map → doctor-BW5HSQDW.js.map} +0 -0
- /package/dist/cli/{events-P27CX7LN.js.map → events-SQXPVV7B.js.map} +0 -0
- /package/dist/cli/{prompt-QSEB7HNQ.js.map → prompt-KGIUONO3.js.map} +0 -0
- /package/dist/cli/{prune-sessions-ERL6B4G5.js.map → prune-sessions-FCFOYCBP.js.map} +0 -0
- /package/dist/cli/{run-AG4Y45X7.js.map → run-RWCOA32G.js.map} +0 -0
- /package/dist/cli/{sessions-MHRF3GU4.js.map → sessions-5ISNWFMU.js.map} +0 -0
- /package/dist/cli/{setup-IIAJXHP4.js.map → setup-HJG23NKJ.js.map} +0 -0
- /package/dist/cli/{version-7AL4JZ63.js.map → version-BXAN7Q4V.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/latency.ts","../../src/mcp/registry.ts","../../src/repair/flatten.ts","../../src/tools.ts","../../src/memory/runtime.ts","../../src/context-manager.ts","../../src/core/inflight.ts","../../src/loop/errors.ts","../../src/loop/escalation.ts","../../src/loop/thinking.ts","../../src/loop/messages.ts","../../src/loop/force-summary.ts","../../src/loop/shrink.ts","../../src/loop/healing.ts","../../src/loop/hook-events.ts","../../src/loop/turn-failure-tracker.ts","../../src/repair/scavenge.ts","../../src/repair/storm.ts","../../src/repair/truncation.ts","../../src/repair/index.ts","../../src/loop.ts","../../src/tools/filesystem.ts","../../src/tools/fs/edit.ts","../../src/tools/fs/glob.ts","../../src/tools/fs/search.ts","../../src/tools/memory.ts","../../src/tools/choice.ts","../../src/tools/plan-core.ts","../../src/tools/todo.ts","../../src/tools/web.ts","../../src/at-mentions.ts","../../src/at-mentions-url.ts","../../src/tools/subagent-types.ts","../../src/tools/subagent.ts","../../src/code/edit-blocks.ts"],"sourcesContent":["/** Per-server ring-buffered latency tracker; emits a \"slow\" event on threshold cross only. */\n\nconst SAMPLE_SIZE = 5;\nconst DEFAULT_THRESHOLD_MS = 4000;\n\nexport interface SlowEvent {\n serverName: string;\n p95Ms: number;\n sampleSize: number;\n}\n\nexport interface LatencyTrackerOptions {\n thresholdMs?: number;\n onSlow?: (ev: SlowEvent) => void;\n}\n\nexport class LatencyTracker {\n private samples: number[] = [];\n private wasOverThreshold = false;\n private readonly thresholdMs: number;\n private readonly onSlow?: (ev: SlowEvent) => void;\n\n constructor(\n private readonly serverName: string,\n opts: LatencyTrackerOptions = {},\n ) {\n this.thresholdMs = opts.thresholdMs ?? DEFAULT_THRESHOLD_MS;\n this.onSlow = opts.onSlow;\n }\n\n record(elapsedMs: number): void {\n this.samples.push(elapsedMs);\n if (this.samples.length > SAMPLE_SIZE) this.samples.shift();\n if (this.samples.length < SAMPLE_SIZE) return;\n const p95 = computeP95(this.samples);\n const nowOver = p95 > this.thresholdMs;\n if (nowOver && !this.wasOverThreshold) {\n this.onSlow?.({ serverName: this.serverName, p95Ms: p95, sampleSize: this.samples.length });\n }\n this.wasOverThreshold = nowOver;\n }\n}\n\n/** Plain p95 — sort the buffer and pick the index at floor(N * 0.95). */\nexport function computeP95(samples: readonly number[]): number {\n if (samples.length === 0) return 0;\n const sorted = [...samples].sort((a, b) => a - b);\n const idx = Math.min(sorted.length - 1, Math.floor(sorted.length * 0.95));\n return sorted[idx] ?? 0;\n}\n","import { countTokens } from \"../tokenizer.js\";\nimport { ToolRegistry } from \"../tools.js\";\nimport type { JSONSchema } from \"../types.js\";\nimport type { McpClient } from \"./client.js\";\nimport { LatencyTracker, type SlowEvent } from \"./latency.js\";\nimport type { CallToolResult, McpContentBlock } from \"./types.js\";\n\nexport interface BridgeOptions {\n /** Prefix for tool names — disambiguates collisions when bridging multiple servers. */\n namePrefix?: string;\n /** Registry to populate. Creates a fresh one if omitted. */\n registry?: ToolRegistry;\n /** Auto-flatten deep schemas (Pillar 3). Defaults to the registry's own default (true). */\n autoFlatten?: boolean;\n /** Cap on tool result chars; head+tail truncation. Floor against context-poisoning oversized reads. */\n maxResultChars?: number;\n /** Absent → no `_meta.progressToken` sent and server won't emit progress. */\n onProgress?: (info: {\n toolName: string;\n progress: number;\n total?: number;\n message?: string;\n }) => void;\n /** Server name used to tag latency samples + slow events. Falls through to namePrefix without trailing `_`. */\n serverName?: string;\n /** p95 cutoff in ms before a slow event fires — defaults to 4000. */\n slowThresholdMs?: number;\n /** Fired exactly when the per-server p95 transitions over `slowThresholdMs`. */\n onSlow?: (ev: SlowEvent) => void;\n /** Indirection so reconnect can swap the underlying client without re-registering tools. */\n host?: McpClientHost;\n}\n\n/** Mutable holder so `/mcp reconnect` can swap the underlying client without re-bridging tools. */\nexport interface McpClientHost {\n client: McpClient;\n}\n\nexport const DEFAULT_MAX_RESULT_CHARS = 32_000;\n\n/** ~6% of DeepSeek V3 context. Char cap alone fails on CJK (~1 char/token). */\nexport const DEFAULT_MAX_RESULT_TOKENS = 8_000;\n\nexport interface BridgeResult {\n registry: ToolRegistry;\n /** Names actually registered (may differ from MCP names when a prefix is applied). */\n registeredNames: string[];\n /** Names the server listed but the bridge skipped (e.g. invalid schemas). */\n skipped: Array<{ name: string; reason: string }>;\n}\n\n/** Resolved bridge environment that `registerSingleMcpTool` needs. Stored on summaries so reconnect can append new tools later. */\nexport interface BridgeEnv {\n registry: ToolRegistry;\n host: McpClientHost;\n prefix: string;\n maxResultChars: number;\n tracker: LatencyTracker | null;\n onProgress?: BridgeOptions[\"onProgress\"];\n}\n\n/** Register one MCP tool's bridged closure into the registry. Returns the registered name (or \"\" if skipped). */\nexport function registerSingleMcpTool(\n mcpTool: import(\"./types.js\").McpTool,\n env: BridgeEnv,\n): string {\n if (!mcpTool.name) return \"\";\n const registeredName = `${env.prefix}${mcpTool.name}`;\n env.registry.register({\n name: registeredName,\n description: mcpTool.description ?? \"\",\n parameters: mcpTool.inputSchema as JSONSchema,\n fn: async (args: Record<string, unknown>, ctx) => {\n const t0 = env.tracker ? Date.now() : 0;\n // Resolve client at call time via the host indirection so `/mcp reconnect`\n // can swap a fresh client in without re-bridging tools.\n const live = env.host.client;\n const toolResult = await live.callTool(mcpTool.name, args, {\n onProgress: env.onProgress\n ? (info) => env.onProgress!({ toolName: registeredName, ...info })\n : undefined,\n signal: ctx?.signal,\n });\n if (env.tracker) env.tracker.record(Date.now() - t0);\n return flattenMcpResult(toolResult, { maxChars: env.maxResultChars });\n },\n });\n return registeredName;\n}\n\nexport async function bridgeMcpTools(\n client: McpClient,\n opts: BridgeOptions = {},\n): Promise<BridgeResult & { env: BridgeEnv }> {\n const registry = opts.registry ?? new ToolRegistry({ autoFlatten: opts.autoFlatten });\n const prefix = opts.namePrefix ?? \"\";\n const maxResultChars = opts.maxResultChars ?? DEFAULT_MAX_RESULT_CHARS;\n const result: BridgeResult = { registry, registeredNames: [], skipped: [] };\n\n const serverName = opts.serverName ?? prefix.replace(/_$/, \"\") ?? \"anon\";\n const tracker = opts.onSlow\n ? new LatencyTracker(serverName, { thresholdMs: opts.slowThresholdMs, onSlow: opts.onSlow })\n : null;\n // Synthesize a host on the fly when the caller didn't provide one. Older\n // callers (tests, single-shot non-reconnectable bridges) get the live\n // `client` reference frozen in; reconnect-aware callers pass their own\n // mutable host.\n const host: McpClientHost = opts.host ?? { client };\n const env: BridgeEnv = {\n registry,\n host,\n prefix,\n maxResultChars,\n tracker,\n onProgress: opts.onProgress,\n };\n const listed = await client.listTools();\n for (const mcpTool of listed.tools) {\n if (!mcpTool.name) {\n result.skipped.push({ name: \"?\", reason: \"empty tool name\" });\n continue;\n }\n const registeredName = registerSingleMcpTool(mcpTool, env);\n if (registeredName) result.registeredNames.push(registeredName);\n }\n return { ...result, env };\n}\n\nexport interface FlattenOptions {\n /** Cap the flattened string at this many characters. Default: no cap. */\n maxChars?: number;\n}\n\nexport function flattenMcpResult(result: CallToolResult, opts: FlattenOptions = {}): string {\n const parts = result.content.map(blockToString);\n const joined = parts.join(\"\\n\").trim();\n const prefixed = result.isError ? `ERROR: ${joined || \"(no error message from server)\"}` : joined;\n return opts.maxChars ? truncateForModel(prefixed, opts.maxChars) : prefixed;\n}\n\n/** Head + 1KB tail so error messages at end of stack traces aren't lost. */\nexport function truncateForModel(s: string, maxChars: number): string {\n if (s.length <= maxChars) return s;\n const tailBudget = Math.min(1024, Math.floor(maxChars * 0.1));\n const headBudget = Math.max(0, maxChars - tailBudget);\n const head = s.slice(0, headBudget);\n const tail = s.slice(-tailBudget);\n const dropped = s.length - head.length - tail.length;\n return `${head}\\n\\n[…truncated ${dropped} chars — raise BridgeOptions.maxResultChars, or call the tool with a narrower scope (filter, head, pagination)…]\\n\\n${tail}`;\n}\n\n/** Never tokenizes full input — pathological repetitive text (`AAAA…`) costs 30s+ on the pure-TS BPE port. */\nexport function truncateForModelByTokens(s: string, maxTokens: number): string {\n if (maxTokens <= 0) return \"\";\n // Every token is ≥1 char — if length ≤ budget, tokens ≤ budget.\n if (s.length <= maxTokens) return s;\n // Small enough to tokenize-check without pathological cost: confirm\n // whether we're actually over budget. (Threshold is the char-bound\n // worst case for English/code — ~4 chars/token.)\n if (s.length <= maxTokens * 4) {\n const tokens = countTokens(s);\n if (tokens <= maxTokens) return s;\n }\n\n const markerOverhead = 48; // rough token cost of the truncation marker\n const contentBudget = Math.max(0, maxTokens - markerOverhead);\n const tailBudget = Math.min(256, Math.floor(contentBudget * 0.1));\n const headBudget = Math.max(0, contentBudget - tailBudget);\n\n const head = sizePrefixToTokens(s, headBudget);\n const tail = sizeSuffixToTokens(s, tailBudget);\n const droppedChars = s.length - head.length - tail.length;\n // Estimate dropped tokens from the per-slice char/token ratio we\n // already measured, rather than paying another full-string tokenize.\n // The marker says \"~N tokens\" so the ≤10% slop is visible to readers.\n const headTokens = head ? countTokens(head) : 0;\n const tailTokens = tail ? countTokens(tail) : 0;\n const sampleChars = head.length + tail.length;\n const sampleTokens = headTokens + tailTokens;\n const ratio = sampleChars > 0 ? sampleTokens / sampleChars : 0.3;\n const estTotalTokens = Math.ceil(s.length * ratio);\n const droppedTokens = Math.max(0, estTotalTokens - sampleTokens);\n return `${head}\\n\\n[…truncated ~${droppedTokens} tokens (${droppedChars} chars) — raise BridgeOptions.maxResultTokens, or call the tool with a narrower scope (filter, head, pagination)…]\\n\\n${tail}`;\n}\n\nfunction sizePrefixToTokens(s: string, budget: number): string {\n if (budget <= 0 || s.length === 0) return \"\";\n // Optimistic starting size: assume ~4 chars/token (English/code\n // average). If the content is denser (CJK ~1 char/token), the first\n // tokenize will show we're over and we shrink.\n let size = Math.min(s.length, budget * 4);\n for (let iter = 0; iter < 6; iter++) {\n if (size <= 0) return \"\";\n const slice = s.slice(0, size);\n const count = countTokens(slice);\n if (count <= budget) return slice;\n // Shrink by the overshoot fraction plus a small safety margin.\n const next = Math.floor(size * (budget / count) * 0.95);\n if (next >= size) return s.slice(0, Math.max(0, size - 1));\n size = next;\n }\n return s.slice(0, Math.max(0, size));\n}\n\n/** Slice `s` from the end to the largest suffix that fits `budget` tokens. */\nfunction sizeSuffixToTokens(s: string, budget: number): string {\n if (budget <= 0 || s.length === 0) return \"\";\n let size = Math.min(s.length, budget * 4);\n for (let iter = 0; iter < 6; iter++) {\n if (size <= 0) return \"\";\n const slice = s.slice(-size);\n const count = countTokens(slice);\n if (count <= budget) return slice;\n const next = Math.floor(size * (budget / count) * 0.95);\n if (next >= size) return s.slice(-Math.max(0, size - 1));\n size = next;\n }\n return s.slice(-Math.max(0, size));\n}\n\nfunction blockToString(block: McpContentBlock): string {\n if (block.type === \"text\") return block.text;\n if (block.type === \"image\") return `[image ${block.mimeType}, ${block.data.length} chars base64]`;\n // Unknown block type — preserve for diagnostics.\n return `[unknown block: ${JSON.stringify(block)}]`;\n}\n","/** DeepSeek drops args on schemas >2 levels deep or >10 leaves; flatten to dot-paths and re-nest after dispatch. */\n\nimport type { JSONSchema } from \"../types.js\";\n\nexport interface FlattenDecision {\n shouldFlatten: boolean;\n leafCount: number;\n maxDepth: number;\n}\n\nexport function analyzeSchema(schema: JSONSchema | undefined): FlattenDecision {\n if (!schema) return { shouldFlatten: false, leafCount: 0, maxDepth: 0 };\n let leafCount = 0;\n let maxDepth = 0;\n walk(schema, 0, (depth, isLeaf) => {\n if (isLeaf) leafCount++;\n if (depth > maxDepth) maxDepth = depth;\n });\n return {\n shouldFlatten: leafCount > 10 || maxDepth > 2,\n leafCount,\n maxDepth,\n };\n}\n\nexport function flattenSchema(schema: JSONSchema): JSONSchema {\n const flatProps: Record<string, JSONSchema> = {};\n const required: string[] = [];\n collect(\"\", schema, flatProps, required, true);\n return {\n type: \"object\",\n properties: flatProps,\n required,\n };\n}\n\nexport function nestArguments(flatArgs: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(flatArgs)) {\n setByPath(out, key.split(\".\"), value);\n }\n return out;\n}\n\nfunction walk(\n schema: JSONSchema,\n depth: number,\n visit: (depth: number, isLeaf: boolean) => void,\n): void {\n if (schema.type === \"object\" && schema.properties) {\n for (const child of Object.values(schema.properties)) {\n walk(child, depth + 1, visit);\n }\n return;\n }\n if (schema.type === \"array\" && schema.items) {\n walk(schema.items, depth + 1, visit);\n return;\n }\n visit(depth, true);\n}\n\nfunction collect(\n prefix: string,\n schema: JSONSchema,\n out: Record<string, JSONSchema>,\n required: string[],\n isRootRequired: boolean,\n): void {\n if (schema.type === \"object\" && schema.properties) {\n const requiredSet = new Set(schema.required ?? []);\n for (const [key, child] of Object.entries(schema.properties)) {\n const nextPrefix = prefix ? `${prefix}.${key}` : key;\n const childRequired = isRootRequired && requiredSet.has(key);\n collect(nextPrefix, child, out, required, childRequired);\n }\n return;\n }\n // Treat anything non-object (including arrays) as a leaf for flattening purposes.\n out[prefix] = schema;\n if (isRootRequired) required.push(prefix);\n}\n\nfunction setByPath(target: Record<string, unknown>, path: string[], value: unknown): void {\n let cur: any = target;\n for (let i = 0; i < path.length - 1; i++) {\n const key = path[i]!;\n if (typeof cur[key] !== \"object\" || cur[key] === null) cur[key] = {};\n cur = cur[key];\n }\n cur[path[path.length - 1]!] = value;\n}\n","import type { PauseGate } from \"./core/pause-gate.js\";\nimport { truncateForModel, truncateForModelByTokens } from \"./mcp/registry.js\";\nimport { analyzeSchema, flattenSchema, nestArguments } from \"./repair/flatten.js\";\nimport type { JSONSchema, ToolSpec } from \"./types.js\";\n\nexport interface ToolCallContext {\n signal?: AbortSignal;\n /** Inject a mock PauseGate for tests. When absent, tools use the singleton. */\n confirmationGate?: PauseGate;\n}\n\nexport interface ToolDefinition<A = any, R = any> {\n name: string;\n description?: string;\n parameters?: JSONSchema;\n /** Safe in plan mode — registry refuses non-readonly calls when `planMode` is on. */\n readOnly?: boolean;\n /** Per-args check; takes precedence over `readOnly`. e.g. `run_command` + allowlisted argv. */\n readOnlyCheck?: (args: A) => boolean;\n /** Safe to dispatch concurrently with other parallel-safe calls in the same turn. Default false — opt-in only. */\n parallelSafe?: boolean;\n /** Excluded from repeat-loop storm accounting; use only for cheap, state-inspection tools. */\n stormExempt?: boolean;\n fn: (args: A, ctx?: ToolCallContext) => R | Promise<R>;\n}\n\ninterface InternalTool extends ToolDefinition {\n /** Set when schema is deep (>2 levels) or wide (>10 leaves) — DeepSeek V3/R1 drop args otherwise. */\n flatSchema?: JSONSchema;\n}\n\nexport interface ToolRegistryOptions {\n /** Auto-flatten + re-nest at dispatch; default true. */\n autoFlatten?: boolean;\n}\n\nexport type ToolCallAuditEvent = {\n name: string;\n args: Record<string, unknown>;\n};\n\nexport type ToolCallAuditListener = (event: ToolCallAuditEvent) => void;\n\n/** String return short-circuits dispatch; null/undefined falls through to the tool fn. */\nexport type ToolInterceptor = (\n name: string,\n args: Record<string, unknown>,\n) => string | null | undefined | Promise<string | null | undefined>;\n\n/** Final-stage post-processor — runs on every dispatch return (success and error paths) so callers can append context like a remaining-budget hint. Whatever it returns becomes the dispatch result. */\nexport type ToolResultAugmenter = (\n name: string,\n args: Record<string, unknown>,\n result: string,\n) => string;\n\nexport class ToolRegistry {\n private readonly _tools = new Map<string, InternalTool>();\n private readonly _autoFlatten: boolean;\n private _planMode = false;\n private _interceptor: ToolInterceptor | null = null;\n private _auditListener: ToolCallAuditListener | null = null;\n private _resultAugmenter: ToolResultAugmenter | null = null;\n\n constructor(opts: ToolRegistryOptions = {}) {\n this._autoFlatten = opts.autoFlatten !== false;\n }\n\n /** Enable / disable plan-mode enforcement at dispatch. */\n setPlanMode(on: boolean): void {\n this._planMode = Boolean(on);\n }\n\n /** True when the registry is currently refusing non-readonly calls. */\n get planMode(): boolean {\n return this._planMode;\n }\n\n /** At most one interceptor active; calling twice replaces. */\n setToolInterceptor(fn: ToolInterceptor | null): void {\n this._interceptor = fn;\n }\n\n setAuditListener(fn: ToolCallAuditListener | null): void {\n this._auditListener = fn;\n }\n\n /** Final-stage post-processor; replaces previous augmenter when called twice. Pass null to clear. */\n setResultAugmenter(fn: ToolResultAugmenter | null): void {\n this._resultAugmenter = fn;\n }\n\n register<A, R>(def: ToolDefinition<A, R>): this {\n if (!def.name) throw new Error(\"tool requires a name\");\n const internal: InternalTool = { ...(def as ToolDefinition) };\n if (this._autoFlatten && def.parameters) {\n const decision = analyzeSchema(def.parameters);\n if (decision.shouldFlatten) {\n internal.flatSchema = flattenSchema(def.parameters);\n }\n }\n this._tools.set(def.name, internal);\n return this;\n }\n\n /** Drop a registered tool. Returns true if the name was present. Used by MCP hot-unbridge. */\n unregister(name: string): boolean {\n return this._tools.delete(name);\n }\n\n has(name: string): boolean {\n return this._tools.has(name);\n }\n\n get(name: string): ToolDefinition | undefined {\n return this._tools.get(name);\n }\n\n get size(): number {\n return this._tools.size;\n }\n\n /** True if a registered tool's schema was flattened for the model. */\n wasFlattened(name: string): boolean {\n return Boolean(this._tools.get(name)?.flatSchema);\n }\n\n /** Unknown / unannotated tools default to false — third-party MCP tools must opt in. */\n isParallelSafe(name: string): boolean {\n return this._tools.get(name)?.parallelSafe === true;\n }\n\n specs(): ToolSpec[] {\n return [...this._tools.values()].map((t) => ({\n type: \"function\",\n function: {\n name: t.name,\n description: t.description ?? \"\",\n parameters: t.flatSchema ?? t.parameters ?? { type: \"object\", properties: {} },\n },\n }));\n }\n\n async dispatch(\n name: string,\n argumentsRaw: string | Record<string, unknown>,\n opts: {\n signal?: AbortSignal;\n maxResultChars?: number;\n maxResultTokens?: number;\n /** Inject a mock PauseGate for tests. */\n confirmationGate?: PauseGate;\n } = {},\n ): Promise<string> {\n const tool = this._tools.get(name);\n if (!tool) {\n return JSON.stringify({ error: `unknown tool: ${name}` });\n }\n let args: Record<string, unknown>;\n try {\n args =\n typeof argumentsRaw === \"string\"\n ? argumentsRaw.trim()\n ? (JSON.parse(argumentsRaw) ?? {})\n : {}\n : (argumentsRaw ?? {});\n } catch (err) {\n return JSON.stringify({\n error: `invalid tool arguments JSON: ${(err as Error).message}`,\n });\n }\n\n // Re-nest dot-notation args back to the original shape, but only when\n // (a) we flattened this tool's schema, AND\n // (b) the incoming args actually use dot keys.\n // The second condition handles the case where a model ignores the flat\n // spec and emits nested args anyway — we shouldn't double-process them.\n if (tool.flatSchema && args && typeof args === \"object\" && hasDotKey(args)) {\n args = nestArguments(args);\n }\n\n // Plan-mode enforcement — runs AFTER arg parsing so a tool with a\n // runtime `readOnlyCheck` can inspect the actual args (e.g.\n // `run_command` is read-only iff the command matches its allowlist).\n if (this._planMode && !isReadOnlyCall(tool, args)) {\n return JSON.stringify({\n error: `${name}: unavailable in plan mode — this is a read-only exploration phase. Use read_file / list_directory / search_files / directory_tree / web_search / allowlisted shell commands to investigate. Call submit_plan with your proposed plan when you're ready for the user's review.`,\n rejectedReason: \"plan-mode\",\n });\n }\n\n // Interceptor runs after plan-mode (so a plan-mode refusal still\n // wins) but before the real tool fn. A string return is treated as\n // the full tool result; null / undefined means \"not my concern,\n // fall through.\" Uncaught throws from the interceptor are surfaced\n // through the same error path as a failed tool fn below.\n if (this._interceptor) {\n try {\n const short = await this._interceptor(name, args);\n if (typeof short === \"string\") return short;\n } catch (err) {\n return JSON.stringify({\n error: `${name}: interceptor failed — ${(err as Error).message}`,\n });\n }\n }\n\n let finalResult: string;\n try {\n try {\n this._auditListener?.({ name, args });\n } catch {\n /* audit path must never break tool execution */\n }\n const result = await tool.fn(args, {\n signal: opts.signal,\n confirmationGate: opts.confirmationGate,\n });\n const str = typeof result === \"string\" ? result : JSON.stringify(result);\n // Pre-clip at dispatch so a single fat result can't balloon the\n // log (and disk session file) on its way in. Healing at load time\n // still catches pre-existing oversize entries; this closes the\n // door on new ones.\n //\n // Two caps available: `maxResultTokens` (preferred — bounds the\n // real context footprint, so CJK doesn't slip past at 2× density)\n // and `maxResultChars` (legacy). If both are set, apply both and\n // the tighter one wins; char-only callers keep their old behavior.\n let clipped = str;\n if (opts.maxResultTokens !== undefined) {\n clipped = truncateForModelByTokens(clipped, opts.maxResultTokens);\n }\n if (opts.maxResultChars !== undefined) {\n clipped = truncateForModel(clipped, opts.maxResultChars);\n }\n finalResult = clipped;\n } catch (err) {\n const e = err as Error & { toToolResult?: () => unknown };\n // Errors may opt into a richer tool-result shape by implementing\n // `toToolResult()`. Used by `PlanProposedError` to smuggle the\n // submitted plan text out to the UI without stuffing it into the\n // error message (which the dispatcher truncates at no fixed limit,\n // but keeping payloads structured is cleaner for UI parsing).\n if (typeof e.toToolResult === \"function\") {\n try {\n finalResult = JSON.stringify(e.toToolResult());\n } catch {\n finalResult = JSON.stringify({ error: `${e.name}: ${e.message}` });\n }\n } else {\n finalResult = JSON.stringify({ error: `${e.name}: ${e.message}` });\n }\n }\n\n if (this._resultAugmenter) {\n try {\n return this._resultAugmenter(name, args, finalResult);\n } catch {\n /* augmenter must never break the tool result */\n }\n }\n return finalResult;\n }\n}\n\nfunction isReadOnlyCall(tool: InternalTool, args: Record<string, unknown>): boolean {\n if (tool.readOnlyCheck) {\n try {\n return Boolean(tool.readOnlyCheck(args as never));\n } catch {\n return false;\n }\n }\n return tool.readOnly === true;\n}\n\nfunction hasDotKey(obj: Record<string, unknown>): boolean {\n for (const k of Object.keys(obj)) {\n if (k.includes(\".\")) return true;\n }\n return false;\n}\n","import { createHash } from \"node:crypto\";\nimport type { ChatMessage, ToolSpec } from \"../types.js\";\n\nexport interface ImmutablePrefixOptions {\n system: string;\n toolSpecs?: readonly ToolSpec[];\n fewShots?: readonly ChatMessage[];\n}\n\nexport class ImmutablePrefix {\n readonly system: string;\n /** Each `addTool` costs one cache-miss turn — DeepSeek's prefix cache is keyed by full tool list. */\n private _toolSpecs: ToolSpec[];\n readonly fewShots: readonly ChatMessage[];\n /** Invalidated only via `addTool`; bypassing it leaves cache stale → fingerprint diverges from sent prefix. */\n private _fingerprintCache: string | null = null;\n\n constructor(opts: ImmutablePrefixOptions) {\n this.system = opts.system;\n this._toolSpecs = [...(opts.toolSpecs ?? [])];\n this.fewShots = Object.freeze([...(opts.fewShots ?? [])]);\n }\n\n get toolSpecs(): readonly ToolSpec[] {\n return this._toolSpecs;\n }\n\n toMessages(): ChatMessage[] {\n return [{ role: \"system\", content: this.system }, ...this.fewShots.map((m) => ({ ...m }))];\n }\n\n tools(): ToolSpec[] {\n return this._toolSpecs.map((t) => structuredClone(t) as ToolSpec);\n }\n\n addTool(spec: ToolSpec): boolean {\n const name = spec.function?.name;\n if (!name) return false;\n if (this._toolSpecs.some((t) => t.function?.name === name)) return false;\n this._toolSpecs.push(spec);\n this._fingerprintCache = null;\n return true;\n }\n\n /** Mirror of addTool for MCP hot-unbridge. Same cache-miss cost — prefix changes shape. */\n removeTool(name: string): boolean {\n const idx = this._toolSpecs.findIndex((t) => t.function?.name === name);\n if (idx < 0) return false;\n this._toolSpecs.splice(idx, 1);\n this._fingerprintCache = null;\n return true;\n }\n\n get fingerprint(): string {\n if (this._fingerprintCache !== null) return this._fingerprintCache;\n this._fingerprintCache = this.computeFingerprint();\n return this._fingerprintCache;\n }\n\n /** Dev/test only — throws on cache drift, which always means a non-`addTool` mutation slipped in. */\n verifyFingerprint(): string {\n const fresh = this.computeFingerprint();\n if (this._fingerprintCache !== null && this._fingerprintCache !== fresh) {\n throw new Error(\n `ImmutablePrefix fingerprint drift: cached=${this._fingerprintCache}, fresh=${fresh}. A mutation path bypassed addTool's cache invalidation — DeepSeek will see prefix churn that the TUI / transcript log don't know about.`,\n );\n }\n this._fingerprintCache = fresh;\n return fresh;\n }\n\n private computeFingerprint(): string {\n const blob = JSON.stringify({\n system: this.system,\n tools: this._toolSpecs,\n shots: this.fewShots,\n });\n return createHash(\"sha256\").update(blob).digest(\"hex\").slice(0, 16);\n }\n}\n\nexport class AppendOnlyLog {\n private _entries: ChatMessage[] = [];\n\n append(message: ChatMessage): void {\n if (!message || typeof message !== \"object\" || !(\"role\" in message)) {\n throw new Error(`invalid log entry: ${JSON.stringify(message)}`);\n }\n this._entries.push(message);\n }\n\n extend(messages: ChatMessage[]): void {\n for (const m of messages) this.append(m);\n }\n\n /** The one append-only-breaking path — reserved for `/compact` + recovery. Use `append()` otherwise. */\n compactInPlace(replacement: ChatMessage[]): void {\n this._entries = [...replacement];\n }\n\n get entries(): readonly ChatMessage[] {\n return this._entries;\n }\n\n toMessages(): ChatMessage[] {\n return this._entries.map((e) => ({ ...e }));\n }\n\n get length(): number {\n return this._entries.length;\n }\n}\n\nexport class VolatileScratch {\n reasoning: string | null = null;\n planState: Record<string, unknown> | null = null;\n notes: string[] = [];\n\n reset(): void {\n this.reasoning = null;\n this.planState = null;\n this.notes = [];\n }\n}\n","import type { DeepSeekClient } from \"./client.js\";\nimport { Usage } from \"./client.js\";\nimport { healLoadedMessages } from \"./loop.js\";\nimport { thinkingModeForModel } from \"./loop.js\";\nimport { stripHallucinatedToolMarkup } from \"./loop.js\";\nimport { DEFAULT_MAX_RESULT_CHARS } from \"./mcp/registry.js\";\nimport type { AppendOnlyLog } from \"./memory/runtime.js\";\nimport { rewriteSession } from \"./memory/session.js\";\nimport {\n DEEPSEEK_CONTEXT_TOKENS,\n DEFAULT_CONTEXT_TOKENS,\n type SessionStats,\n} from \"./telemetry/stats.js\";\nimport { estimateConversationTokens, estimateRequestTokens } from \"./tokenizer.js\";\nimport type { ChatMessage } from \"./types.js\";\n\n/** Auto-fold when a turn's response shows promptTokens above this fraction of ctxMax. */\nexport const HISTORY_FOLD_THRESHOLD = 0.5;\n/** Tail budget after a normal fold, as a fraction of ctxMax. */\nexport const HISTORY_FOLD_TAIL_FRACTION = 0.2;\n/** Above this fraction the normal fold's tail budget didn't buy enough headroom — fold harder. */\nexport const HISTORY_FOLD_AGGRESSIVE_THRESHOLD = 0.7;\n/** Tail budget after an aggressive fold — half the normal one, sacrifices recent context for headroom. */\nexport const HISTORY_FOLD_AGGRESSIVE_TAIL_FRACTION = 0.1;\n/** Skip the fold if the head wouldn't shrink the log by at least this fraction. */\nexport const HISTORY_FOLD_MIN_SAVINGS_FRACTION = 0.3;\n/** Above this fraction we exit the turn with a summary instead of folding (defense in depth). */\nexport const FORCE_SUMMARY_THRESHOLD = 0.8;\n/** Local preflight estimate above this fraction trips the emergency in-place compact path. */\nexport const PREFLIGHT_EMERGENCY_THRESHOLD = 0.95;\n/** Prepended to fold summary content so the model knows it's a synthesized recap. */\nexport const HISTORY_FOLD_MARKER =\n \"[CONVERSATION HISTORY SUMMARY — earlier turns folded for context efficiency]\\n\\n\";\n\nexport interface ContextManagerDeps {\n client: DeepSeekClient;\n log: AppendOnlyLog;\n stats: SessionStats;\n sessionName: string | null;\n getAbortSignal: () => AbortSignal;\n getCurrentTurn: () => number;\n}\n\nexport type PostUsageDecisionKind = \"none\" | \"fold\" | \"exit-with-summary\";\n\nexport interface PostUsageDecision {\n kind: PostUsageDecisionKind;\n promptTokens: number;\n ctxMax: number;\n ratio: number;\n /** Token budget for the recent tail when kind === \"fold\"; smaller in the aggressive band. */\n tailBudget?: number;\n /** True when this fold is in the 70-85% band — used in user-facing messaging. */\n aggressive?: boolean;\n}\n\nexport interface PreflightDecision {\n needsAction: boolean;\n estimateTokens: number;\n ctxMax: number;\n}\n\nexport interface FoldResult {\n folded: boolean;\n beforeMessages: number;\n afterMessages: number;\n summaryChars: number;\n}\n\nexport class ContextManager {\n constructor(private deps: ContextManagerDeps) {}\n\n /** Decision after a turn's response — fold, exit with summary, or carry on. */\n decideAfterUsage(\n usage: Usage | null,\n model: string,\n alreadyFoldedThisTurn: boolean,\n ): PostUsageDecision {\n const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model] ?? DEFAULT_CONTEXT_TOKENS;\n if (!usage) return { kind: \"none\", promptTokens: 0, ctxMax, ratio: 0 };\n const ratio = usage.promptTokens / ctxMax;\n const base = { promptTokens: usage.promptTokens, ctxMax, ratio };\n if (ratio > FORCE_SUMMARY_THRESHOLD) {\n return { kind: \"exit-with-summary\", ...base };\n }\n if (alreadyFoldedThisTurn) return { kind: \"none\", ...base };\n if (ratio > HISTORY_FOLD_AGGRESSIVE_THRESHOLD) {\n return {\n kind: \"fold\",\n ...base,\n tailBudget: Math.floor(ctxMax * HISTORY_FOLD_AGGRESSIVE_TAIL_FRACTION),\n aggressive: true,\n };\n }\n if (ratio > HISTORY_FOLD_THRESHOLD) {\n return {\n kind: \"fold\",\n ...base,\n tailBudget: Math.floor(ctxMax * HISTORY_FOLD_TAIL_FRACTION),\n aggressive: false,\n };\n }\n return { kind: \"none\", ...base };\n }\n\n /** Local-side preflight before sending a request — catches oversized payloads early. */\n decidePreflight(\n messages: ChatMessage[],\n toolSpecs: ReadonlyArray<unknown> | undefined | null,\n model: string,\n ): PreflightDecision {\n const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model] ?? DEFAULT_CONTEXT_TOKENS;\n const estimate = estimateRequestTokens(messages, toolSpecs ?? null);\n return {\n needsAction: estimate / ctxMax > PREFLIGHT_EMERGENCY_THRESHOLD,\n estimateTokens: estimate,\n ctxMax,\n };\n }\n\n /** Replace older turns with one summary message; keep tail within keepRecentTokens budget. */\n async fold(model: string, opts?: { keepRecentTokens?: number }): Promise<FoldResult> {\n const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model] ?? DEFAULT_CONTEXT_TOKENS;\n const tailBudget = opts?.keepRecentTokens ?? Math.floor(ctxMax * HISTORY_FOLD_TAIL_FRACTION);\n const all = this.deps.log.toMessages();\n const noop: FoldResult = {\n folded: false,\n beforeMessages: all.length,\n afterMessages: all.length,\n summaryChars: 0,\n };\n if (all.length === 0) return noop;\n\n const tokenCounts = all.map((m) => estimateConversationTokens([m]));\n const totalTokens = tokenCounts.reduce((a, b) => a + b, 0);\n\n let cumTokens = 0;\n let boundary = all.length;\n for (let i = all.length - 1; i >= 0; i--) {\n if (cumTokens + tokenCounts[i]! > tailBudget) break;\n cumTokens += tokenCounts[i]!;\n if (all[i]!.role === \"user\") boundary = i;\n }\n if (boundary <= 0) return noop;\n\n const head = all.slice(0, boundary);\n const tail = all.slice(boundary);\n const headTokens = totalTokens - cumTokens;\n if (headTokens < totalTokens * HISTORY_FOLD_MIN_SAVINGS_FRACTION) return noop;\n\n const summary = await this.summarizeForFold(head);\n if (!summary) return noop;\n\n const summaryMsg: ChatMessage = {\n role: \"assistant\",\n content: HISTORY_FOLD_MARKER + summary,\n };\n const replacement = [summaryMsg, ...tail];\n this.deps.log.compactInPlace(replacement);\n this.persistRewrite(replacement);\n return {\n folded: true,\n beforeMessages: all.length,\n afterMessages: replacement.length,\n summaryChars: summary.length,\n };\n }\n\n /** Drop a trailing in-flight assistant-with-tool_calls before a forced summary. Tail-only mutation; prefix cache safe. */\n trimTrailingToolCalls(): boolean {\n const tail = this.deps.log.entries[this.deps.log.entries.length - 1];\n if (\n !tail ||\n tail.role !== \"assistant\" ||\n !Array.isArray(tail.tool_calls) ||\n tail.tool_calls.length === 0\n ) {\n return false;\n }\n const kept = this.deps.log.entries.slice(0, -1);\n this.deps.log.compactInPlace([...kept]);\n this.persistRewrite([...kept]);\n return true;\n }\n\n private async summarizeForFold(messagesToSummarize: ChatMessage[]): Promise<string> {\n const summaryModel = \"deepseek-v4-flash\";\n const systemPrompt =\n \"You compress conversation history for a coding agent. Output one prose recap that preserves: the user's overall goal, decisions and conclusions reached, files inspected or modified, important tool results still relevant to ongoing work, and any open todos. Skip turn-by-turn play-by-play. No tool calls, no markdown headings, no SEARCH/REPLACE blocks — plain prose only.\";\n const healed = healLoadedMessages(messagesToSummarize, DEFAULT_MAX_RESULT_CHARS).messages;\n const messages: ChatMessage[] = [\n { role: \"system\", content: systemPrompt },\n ...healed,\n {\n role: \"user\",\n content:\n \"Summarize the conversation above as plain prose. This summary replaces the original turns to free context — make it self-contained.\",\n },\n ];\n try {\n const resp = await this.deps.client.chat({\n model: summaryModel,\n messages,\n signal: this.deps.getAbortSignal(),\n thinking: thinkingModeForModel(summaryModel),\n reasoningEffort: \"high\",\n });\n this.deps.stats.record(this.deps.getCurrentTurn(), summaryModel, resp.usage ?? new Usage());\n return stripHallucinatedToolMarkup((resp.content ?? \"\").trim());\n } catch {\n return \"\";\n }\n }\n\n private persistRewrite(messages: ChatMessage[]): void {\n if (!this.deps.sessionName) return;\n try {\n rewriteSession(this.deps.sessionName, messages);\n } catch {\n /* disk full / perms — in-memory mutation still applies */\n }\n }\n}\n","/** Authoritative running-id set — cards derive `running` from `has(id)` instead of trusting end-event delivery. Loop adds on dispatch entry, deletes in `finally` so every exit path cleans up. */\n\nexport type InflightSubscriber = () => void;\n\nexport class InflightSet {\n private readonly _set = new Set<string>();\n private readonly _listeners = new Set<InflightSubscriber>();\n\n add(id: string): void {\n if (this._set.has(id)) return;\n this._set.add(id);\n this._notify();\n }\n\n delete(id: string): void {\n if (this._set.delete(id)) this._notify();\n }\n\n has(id: string): boolean {\n return this._set.has(id);\n }\n\n /** Snapshot for diagnostics / tests; live view, do not mutate. */\n get size(): number {\n return this._set.size;\n }\n\n /** Subscribe to add/delete; returns the unsubscribe function. */\n subscribe(fn: InflightSubscriber): () => void {\n this._listeners.add(fn);\n return () => {\n this._listeners.delete(fn);\n };\n }\n\n /** Drop everything — only use at session reset. Notifies once. */\n clear(): void {\n if (this._set.size === 0) return;\n this._set.clear();\n this._notify();\n }\n\n private _notify(): void {\n for (const fn of this._listeners) {\n try {\n fn();\n } catch {\n /* listener errors must not break the gate */\n }\n }\n }\n}\n","import type { DeepSeekClient } from \"../client.js\";\nimport { t } from \"../i18n/index.js\";\n\nexport interface DeepSeekProbeResult {\n reachable: boolean;\n}\n\nexport function formatLoopError(err: Error, probe?: DeepSeekProbeResult): string {\n const msg = err.message ?? \"\";\n if (msg.includes(\"maximum context length\")) {\n const reqMatch = msg.match(/requested\\s+(\\d+)\\s+tokens/);\n const requested = reqMatch\n ? `${Number(reqMatch[1]).toLocaleString()} tokens`\n : t(\"errors.contextOverflowTooMany\");\n return t(\"errors.contextOverflow\", { requested });\n }\n\n const m = /^DeepSeek (\\d{3}):\\s*([\\s\\S]*)$/.exec(msg);\n if (!m) return msg;\n const status = m[1] ?? \"\";\n const body = m[2] ?? \"\";\n const inner = extractDeepSeekErrorMessage(body);\n\n if (status === \"401\") return t(\"errors.auth401\", { inner });\n if (status === \"402\") return t(\"errors.balance402\", { inner });\n if (status === \"422\") return t(\"errors.badparam422\", { inner });\n if (status === \"400\") return t(\"errors.badrequest400\", { inner });\n if (is5xxStatus(status)) return formatDeepSeek5xx(status, probe);\n return msg;\n}\n\nexport function is5xxError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const m = /^DeepSeek (5\\d{2}):/.exec(err.message ?? \"\");\n return m !== null;\n}\n\nexport async function probeDeepSeekReachable(\n client: DeepSeekClient,\n timeoutMs = 1500,\n): Promise<DeepSeekProbeResult> {\n const balance = await client.getBalance({ signal: AbortSignal.timeout(timeoutMs) });\n return { reachable: balance !== null };\n}\n\nfunction is5xxStatus(status: string): boolean {\n return status === \"500\" || status === \"502\" || status === \"503\" || status === \"504\";\n}\n\nfunction formatDeepSeek5xx(status: string, probe?: DeepSeekProbeResult): string {\n const head = t(\"errors.deepseek5xxHead\", { status });\n const probeNote =\n probe === undefined\n ? \"\"\n : probe.reachable\n ? t(\"errors.deepseek5xxReachable\")\n : t(\"errors.deepseek5xxUnreachable\");\n const action =\n probe?.reachable === false\n ? t(\"errors.deepseek5xxActionNetwork\")\n : t(\"errors.deepseek5xxActionRetry\");\n return `${head}${probeNote}${action}`;\n}\n\nexport function reasonPrefixFor(\n reason: \"budget\" | \"aborted\" | \"context-guard\" | \"stuck\",\n iterCap: number,\n): string {\n if (reason === \"aborted\") return t(\"errors.reasonAborted\");\n if (reason === \"context-guard\") return t(\"errors.reasonContextGuard\");\n if (reason === \"stuck\") return t(\"errors.reasonStuck\");\n return t(\"errors.reasonBudget\", { iterCap });\n}\n\nexport function errorLabelFor(\n reason: \"budget\" | \"aborted\" | \"context-guard\" | \"stuck\",\n iterCap: number,\n): string {\n if (reason === \"aborted\") return t(\"errors.labelAborted\");\n if (reason === \"context-guard\") return t(\"errors.labelContextGuard\");\n if (reason === \"stuck\") return t(\"errors.labelStuck\");\n return t(\"errors.labelBudget\", { iterCap });\n}\n\nfunction extractDeepSeekErrorMessage(body: string): string {\n const trimmed = body.trim();\n if (!trimmed) return t(\"errors.innerNoMessage\");\n try {\n const parsed = JSON.parse(trimmed);\n if (parsed && typeof parsed === \"object\") {\n const obj = parsed as { error?: { message?: unknown }; message?: unknown };\n if (obj.error && typeof obj.error.message === \"string\") return obj.error.message;\n if (typeof obj.message === \"string\") return obj.message;\n }\n } catch {\n /* not JSON — fall through */\n }\n return trimmed;\n}\n","/** Accepts `<<<NEEDS_PRO>>>` or `<<<NEEDS_PRO: reason>>>` (reason trimmed, may be empty). */\nconst NEEDS_PRO_MARKER_PREFIX = \"<<<NEEDS_PRO\";\nconst NEEDS_PRO_MARKER_RE = /^<<<NEEDS_PRO(?::\\s*([^>]*))?>>>/;\n/** Buffer cap before flushing — must fit `<<<NEEDS_PRO: reason>>>` without premature flush. */\nexport const NEEDS_PRO_BUFFER_CHARS = 256;\n\n/** Anchored to lead — mid-text matches are normal content (user asking about the marker). */\nexport function parseEscalationMarker(content: string): { matched: boolean; reason?: string } {\n const m = NEEDS_PRO_MARKER_RE.exec(content.trimStart());\n if (!m) return { matched: false };\n const reason = m[1]?.trim();\n return { matched: true, reason: reason || undefined };\n}\n\n/** Convenience boolean — same gate the streaming path used to call. */\nexport function isEscalationRequest(content: string): boolean {\n return parseEscalationMarker(content).matched;\n}\n\n/** Drives streaming flush — while plausibly partial, keep accumulating; else flush. */\nexport function looksLikePartialEscalationMarker(buf: string): boolean {\n const t = buf.trimStart();\n if (t.length === 0) return true;\n if (t.length <= NEEDS_PRO_MARKER_PREFIX.length) {\n return NEEDS_PRO_MARKER_PREFIX.startsWith(t);\n }\n if (!t.startsWith(NEEDS_PRO_MARKER_PREFIX)) return false;\n const rest = t.slice(NEEDS_PRO_MARKER_PREFIX.length);\n if (rest[0] !== \">\" && rest[0] !== \":\") return false;\n return true;\n}\n","/** True when the model emits reasoning_content and requires it round-tripped on follow-ups. */\nexport function isThinkingModeModel(model: string): boolean {\n if (model.includes(\"reasoner\")) return true;\n if (model === \"deepseek-v4-flash\" || model === \"deepseek-v4-pro\") return true;\n return false;\n}\n\n/** Pins extra_body.thinking.type; `undefined` lets third-party endpoints skip the field. */\nexport function thinkingModeForModel(model: string): \"enabled\" | \"disabled\" | undefined {\n if (model === \"deepseek-chat\") return \"disabled\";\n if (model.includes(\"reasoner\")) return \"enabled\";\n if (model === \"deepseek-v4-flash\" || model === \"deepseek-v4-pro\") return \"enabled\";\n return undefined;\n}\n\n/** Strip hallucinated tool-call envelopes — `tools: undefined` doesn't always force prose. */\nexport function stripHallucinatedToolMarkup(s: string): string {\n let out = s;\n // DeepSeek's DSML envelope (full-width \"|\" is the form R1 emits in practice).\n out = out.replace(/<|DSML|function_calls>[\\s\\S]*?<\\/?|DSML|function_calls>/g, \"\");\n out = out.replace(/<\\|DSML\\|function_calls>[\\s\\S]*?<\\/?\\|DSML\\|function_calls>/g, \"\");\n out = out.replace(/<function_calls>[\\s\\S]*?<\\/function_calls>/g, \"\");\n // Lone unpaired DSML opener left over after R1 truncates mid-call.\n out = out.replace(/<|DSML|[\\s\\S]*$/g, \"\");\n return out.trim();\n}\n","import type { ChatMessage, ToolCall } from \"../types.js\";\nimport { isThinkingModeModel } from \"./thinking.js\";\n\n/** Thinking-mode producer ⇒ reasoning_content MUST be set (even \"\"), or next call 400s. */\nexport function buildAssistantMessage(\n content: string,\n toolCalls: ToolCall[],\n producingModel: string,\n reasoningContent?: string | null,\n): ChatMessage {\n const msg: ChatMessage = { role: \"assistant\", content };\n if (toolCalls.length > 0) msg.tool_calls = toolCalls;\n // V4-era deepseek-chat returns reasoning_content even with thinking.type\n // disabled, and the API rejects round-trips that drop it. Whitelist on\n // model name is too brittle — preserve whenever the producer emitted any.\n if (isThinkingModeModel(producingModel) || (reasoningContent && reasoningContent.length > 0)) {\n msg.reasoning_content = reasoningContent ?? \"\";\n }\n return msg;\n}\n\n/** Abort notices etc — caller passes its current model as the thinking-mode stamp. */\nexport function buildSyntheticAssistantMessage(\n content: string,\n fallbackModel: string,\n): ChatMessage {\n return buildAssistantMessage(content, [], fallbackModel, \"\");\n}\n","import { type DeepSeekClient, Usage } from \"../client.js\";\nimport { t } from \"../i18n/index.js\";\nimport type { TurnStats } from \"../telemetry/stats.js\";\nimport type { ChatMessage } from \"../types.js\";\nimport { errorLabelFor, reasonPrefixFor } from \"./errors.js\";\nimport { buildAssistantMessage } from \"./messages.js\";\nimport { stripHallucinatedToolMarkup, thinkingModeForModel } from \"./thinking.js\";\nimport type { LoopEvent } from \"./types.js\";\n\nexport type ForceSummaryReason = \"budget\" | \"aborted\" | \"context-guard\" | \"stuck\";\n\nexport interface ForceSummaryContext {\n client: DeepSeekClient;\n signal: AbortSignal;\n buildMessages: () => ChatMessage[];\n appendAndPersist: (msg: ChatMessage) => void;\n recordStats: (model: string, usage: Usage) => TurnStats;\n turn: number;\n maxToolIters: number;\n}\n\nexport async function* forceSummaryAfterIterLimit(\n ctx: ForceSummaryContext,\n opts: { reason: ForceSummaryReason } = { reason: \"budget\" },\n): AsyncGenerator<LoopEvent> {\n try {\n // Status bridges the silence — summary call is non-streaming, 30-60s typical.\n yield { turn: ctx.turn, role: \"status\", content: t(\"summary.status\") };\n const messages = ctx.buildMessages();\n // Passing `tools: undefined` was supposed to force a text response,\n // but R1 can still hallucinate tool-call markup (e.g. DSML\n // `<|DSML|function_calls>…`) when primed by prior tool use. An\n // explicit user-role instruction plus post-hoc stripping of known\n // hallucination shapes keeps the user from seeing raw markup.\n messages.push({\n role: \"user\",\n content:\n \"I'm out of tool-call budget for this turn. Summarize in plain prose what you learned from the tool results above. Do NOT emit any tool calls, function-call markup, DSML invocations, or SEARCH/REPLACE edit blocks — they will be silently discarded. Just plain text.\",\n });\n // Pin to flash + effort=high regardless of the main turn's model —\n // pro is 12× overkill for \"paraphrase tool results into prose,\" and\n // budget-exhausted turns are exactly when we don't want to torch the wallet.\n const summaryModel = \"deepseek-v4-flash\";\n const summaryEffort: \"high\" | \"max\" = \"high\";\n const resp = await ctx.client.chat({\n model: summaryModel,\n messages,\n signal: ctx.signal,\n thinking: thinkingModeForModel(summaryModel),\n reasoningEffort: summaryEffort,\n });\n const rawContent = resp.content?.trim() ?? \"\";\n const cleaned = stripHallucinatedToolMarkup(rawContent);\n const summary = cleaned || t(\"summary.hallucinatedFallback\");\n const reasonPrefix = reasonPrefixFor(opts.reason, ctx.maxToolIters);\n const annotated = `${reasonPrefix}\\n\\n${summary}`;\n // Record under the actual model used (flash), so per-turn cost reflects reality.\n const summaryStats = ctx.recordStats(summaryModel, resp.usage ?? new Usage());\n ctx.appendAndPersist(buildAssistantMessage(summary, [], summaryModel, resp.reasoningContent));\n yield {\n turn: ctx.turn,\n role: \"assistant_final\",\n content: annotated,\n stats: summaryStats,\n forcedSummary: true,\n };\n yield { turn: ctx.turn, role: \"done\", content: summary };\n } catch (err) {\n const label = errorLabelFor(opts.reason, ctx.maxToolIters);\n yield {\n turn: ctx.turn,\n role: \"error\",\n content: \"\",\n error: t(\"summary.failedAfterReason\", { label, message: (err as Error).message }),\n };\n yield { turn: ctx.turn, role: \"done\", content: \"\" };\n }\n}\n","import { truncateForModel, truncateForModelByTokens } from \"../mcp/registry.js\";\nimport { countTokens } from \"../tokenizer.js\";\nimport type { ChatMessage } from \"../types.js\";\n\n/** UI progress feedback only — NOT a dispatch gate. */\nexport function looksLikeCompleteJson(s: string): boolean {\n if (!s || !s.trim()) return false;\n try {\n JSON.parse(s);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Tool-role only — truncating user prompts would corrupt authored intent. */\nexport function shrinkOversizedToolResults(\n messages: ChatMessage[],\n maxChars: number,\n): { messages: ChatMessage[]; healedCount: number; healedFrom: number } {\n let healedCount = 0;\n let healedFrom = 0;\n const out = messages.map((msg) => {\n if (msg.role !== \"tool\") return msg;\n const content = typeof msg.content === \"string\" ? msg.content : \"\";\n if (content.length <= maxChars) return msg;\n healedCount += 1;\n healedFrom += content.length;\n return { ...msg, content: truncateForModel(content, maxChars) };\n });\n return { messages: out, healedCount, healedFrom };\n}\n\n/** Token-cap variant — char cap would let CJK slip past at 2× the intended token cost. */\nexport function shrinkOversizedToolResultsByTokens(\n messages: ChatMessage[],\n maxTokens: number,\n): {\n messages: ChatMessage[];\n healedCount: number;\n tokensSaved: number;\n charsSaved: number;\n} {\n let healedCount = 0;\n let tokensSaved = 0;\n let charsSaved = 0;\n const out = messages.map((msg) => {\n if (msg.role !== \"tool\") return msg;\n const content = typeof msg.content === \"string\" ? msg.content : \"\";\n // length ≤ maxTokens ⇒ tokens ≤ maxTokens — skip the per-message tokenize.\n if (content.length <= maxTokens) return msg;\n const beforeTokens = countTokens(content);\n if (beforeTokens <= maxTokens) return msg;\n const truncated = truncateForModelByTokens(content, maxTokens);\n const afterTokens = countTokens(truncated);\n healedCount += 1;\n tokensSaved += Math.max(0, beforeTokens - afterTokens);\n charsSaved += Math.max(0, content.length - truncated.length);\n return { ...msg, content: truncated };\n });\n return { messages: out, healedCount, tokensSaved, charsSaved };\n}\n\n/** Caller must gate on paired tool_calls — in-flight calls would crash mid-turn. */\nexport function shrinkOversizedToolCallArgsByTokens(\n messages: ChatMessage[],\n maxTokens: number,\n): {\n messages: ChatMessage[];\n healedCount: number;\n tokensSaved: number;\n charsSaved: number;\n} {\n let healedCount = 0;\n let tokensSaved = 0;\n let charsSaved = 0;\n const out = messages.map((msg) => {\n if (msg.role !== \"assistant\" || !Array.isArray(msg.tool_calls)) return msg;\n let changed = false;\n const newCalls = msg.tool_calls.map((call) => {\n const args = call.function?.arguments;\n if (typeof args !== \"string\" || args.length <= maxTokens) return call;\n const beforeTokens = countTokens(args);\n if (beforeTokens <= maxTokens) return call;\n const shrunk = shrinkJsonLongStrings(args);\n const afterTokens = countTokens(shrunk);\n // Many-short-strings payloads can come back marginally larger — only swap on real saving.\n if (afterTokens >= beforeTokens) return call;\n changed = true;\n healedCount += 1;\n tokensSaved += beforeTokens - afterTokens;\n charsSaved += args.length - shrunk.length;\n return { ...call, function: { ...call.function, arguments: shrunk } };\n });\n if (!changed) return msg;\n return { ...msg, tool_calls: newCalls };\n });\n return { messages: out, healedCount, tokensSaved, charsSaved };\n}\n\n/** Keeps short keys/values (paths, ids) verbatim; only long string values get a marker. */\nfunction shrinkJsonLongStrings(jsonStr: string): string {\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonStr);\n } catch {\n const head = jsonStr.slice(0, 200);\n return `${head}…[shrunk: ${jsonStr.length} chars, unparsed]`;\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return jsonStr;\n }\n const LONG_THRESHOLD = 300;\n const input = parsed as Record<string, unknown>;\n const output: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(input)) {\n if (typeof v === \"string\" && v.length > LONG_THRESHOLD) {\n const newlines = v.match(/\\n/g)?.length ?? 0;\n output[k] =\n `[…shrunk: ${v.length} chars, ${newlines} lines — tool already responded, see result]`;\n } else {\n output[k] = v;\n }\n }\n return JSON.stringify(output);\n}\n","import type { ChatMessage } from \"../types.js\";\nimport { shrinkOversizedToolResults, shrinkOversizedToolResultsByTokens } from \"./shrink.js\";\nimport { isThinkingModeModel } from \"./thinking.js\";\n\n/** Drops both unpaired assistant.tool_calls and stray tool messages — DeepSeek 400s on either. */\nexport function fixToolCallPairing(messages: ChatMessage[]): {\n messages: ChatMessage[];\n droppedAssistantCalls: number;\n droppedStrayTools: number;\n} {\n const out: ChatMessage[] = [];\n let droppedAssistantCalls = 0;\n let droppedStrayTools = 0;\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!;\n if (msg.role === \"assistant\" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {\n const needed = new Set<string>();\n for (const call of msg.tool_calls) {\n if (call?.id) needed.add(call.id);\n }\n const candidates: ChatMessage[] = [];\n let j = i + 1;\n while (j < messages.length && needed.size > 0) {\n const nxt = messages[j]!;\n if (nxt.role !== \"tool\") break;\n const id = nxt.tool_call_id ?? \"\";\n if (!needed.has(id)) break;\n needed.delete(id);\n candidates.push(nxt);\n j++;\n }\n if (needed.size === 0) {\n out.push(msg);\n for (const r of candidates) out.push(r);\n i = j - 1;\n } else {\n droppedAssistantCalls += 1;\n droppedStrayTools += candidates.length;\n i = j - 1;\n }\n continue;\n }\n if (msg.role === \"tool\") {\n droppedStrayTools += 1;\n continue;\n }\n out.push(msg);\n }\n return { messages: out, droppedAssistantCalls, droppedStrayTools };\n}\n\nexport function healLoadedMessages(\n messages: ChatMessage[],\n maxChars: number,\n): { messages: ChatMessage[]; healedCount: number; healedFrom: number } {\n const shrunk = shrinkOversizedToolResults(messages, maxChars);\n const paired = fixToolCallPairing(shrunk.messages);\n const healedCount = shrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;\n return { messages: paired.messages, healedCount, healedFrom: shrunk.healedFrom };\n}\n\n/** Back-fills \"\" on bare assistant turns; skipped on non-thinking to avoid prefix-cache churn. */\nexport function stampMissingReasoningForThinkingMode(\n messages: ChatMessage[],\n model: string,\n): { messages: ChatMessage[]; stampedCount: number } {\n if (!isThinkingModeModel(model)) {\n return { messages, stampedCount: 0 };\n }\n let stampedCount = 0;\n const out = messages.map((msg) => {\n if (msg.role !== \"assistant\") return msg;\n if (Object.hasOwn(msg, \"reasoning_content\")) return msg;\n stampedCount += 1;\n return { ...msg, reasoning_content: \"\" };\n });\n return { messages: out, stampedCount };\n}\n\n/** Token-cap variant — char cap would let CJK slip past at 2× the intended token cost. */\nexport function healLoadedMessagesByTokens(\n messages: ChatMessage[],\n maxTokens: number,\n): {\n messages: ChatMessage[];\n healedCount: number;\n tokensSaved: number;\n charsSaved: number;\n} {\n const shrunk = shrinkOversizedToolResultsByTokens(messages, maxTokens);\n const paired = fixToolCallPairing(shrunk.messages);\n const healedCount = shrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;\n return {\n messages: paired.messages,\n healedCount,\n tokensSaved: shrunk.tokensSaved,\n charsSaved: shrunk.charsSaved,\n };\n}\n","import { type HookOutcome, formatHookOutcomeMessage } from \"../hooks.js\";\nimport type { LoopEvent } from \"./types.js\";\n\nexport function safeParseToolArgs(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\n/** Format non-pass hook outcomes as `LoopEvent`s of role `warning`. */\nexport function* hookWarnings(outcomes: HookOutcome[], turn: number): Generator<LoopEvent> {\n for (const o of outcomes) {\n if (o.decision === \"pass\") continue;\n yield { turn, role: \"warning\", content: formatHookOutcomeMessage(o) };\n }\n}\n","import type { RepairReport } from \"../repair/index.js\";\n\nexport const FAILURE_ESCALATION_THRESHOLD = 3;\n\nexport class TurnFailureTracker {\n private count = 0;\n private types: Record<string, number> = {};\n\n reset(): void {\n this.count = 0;\n this.types = {};\n }\n\n /** True ONLY on the call where the count crosses FAILURE_ESCALATION_THRESHOLD. */\n noteAndCrossedThreshold(resultJson: string, repair?: RepairReport): boolean {\n const before = this.count;\n const bump = (kind: string, by = 1): void => {\n this.count += by;\n this.types[kind] = (this.types[kind] ?? 0) + by;\n };\n if (resultJson.includes('\"error\"') && resultJson.includes(\"search text not found\")) {\n bump(\"search-mismatch\");\n }\n if (repair) {\n if (repair.scavenged > 0) bump(\"scavenged\", repair.scavenged);\n if (repair.truncationsFixed > 0) bump(\"truncated\", repair.truncationsFixed);\n if (repair.stormsBroken > 0) bump(\"repeat-loop\", repair.stormsBroken);\n }\n return before < FAILURE_ESCALATION_THRESHOLD && this.count >= FAILURE_ESCALATION_THRESHOLD;\n }\n\n formatBreakdown(): string {\n const parts = Object.entries(this.types)\n .filter(([, n]) => n > 0)\n .map(([kind, n]) => `${n}× ${kind}`);\n return parts.length > 0 ? parts.join(\", \") : `${this.count} repair/error signal(s)`;\n }\n}\n","/** R1 sometimes emits tool-call JSON inside reasoning_content and forgets `tool_calls`; recover those calls. */\n\nimport type { ToolCall } from \"../types.js\";\n\nexport interface ScavengeOptions {\n /** Names of tools the model may legitimately call. Other names are ignored. */\n allowedNames: ReadonlySet<string>;\n /** Maximum number of calls to scavenge per pass (defence against runaway). */\n maxCalls?: number;\n}\n\nexport interface ScavengeResult {\n calls: ToolCall[];\n notes: string[];\n}\n\n/** Bounds the regex input — DSML matchers are O(n²) on adversarial input per CodeQL js/polynomial-redos. */\nconst MAX_SCAVENGE_INPUT = 100 * 1024;\n\nexport function scavengeToolCalls(\n reasoningContent: string | null | undefined,\n opts: ScavengeOptions,\n): ScavengeResult {\n if (!reasoningContent) return { calls: [], notes: [] };\n if (reasoningContent.length > MAX_SCAVENGE_INPUT) {\n return {\n calls: [],\n notes: [`scavenge skipped: reasoning_content too large (${reasoningContent.length} chars)`],\n };\n }\n const max = opts.maxCalls ?? 4;\n const notes: string[] = [];\n const out: ToolCall[] = [];\n\n // Pattern A: DSML invoke blocks. R1 sometimes emits tool calls as\n // its chat-template markup in the content channel instead of the\n // proper `tool_calls` field. 0.4.3 stripped these from display;\n // here we actually turn them back into proper ToolCalls so the\n // model's intent isn't lost.\n for (const invoke of iterateDsmlInvokes(reasoningContent)) {\n if (out.length >= max) break;\n if (!opts.allowedNames.has(invoke.name)) continue;\n out.push({\n function: {\n name: invoke.name,\n arguments: JSON.stringify(invoke.args),\n },\n });\n notes.push(`scavenged DSML call: ${invoke.name}`);\n }\n\n // Pattern B: raw JSON objects (the original three shapes). Strip\n // any DSML blocks we already processed so parameter JSON buried\n // inside them doesn't get re-scavenged as a standalone call.\n const nonDsml = stripDsmlBlocks(reasoningContent);\n for (const candidate of iterateJsonObjects(nonDsml)) {\n if (out.length >= max) break;\n const call = coerceToToolCall(candidate, opts.allowedNames);\n if (call) {\n out.push(call);\n notes.push(`scavenged call: ${call.function.name}`);\n }\n }\n return { calls: out, notes };\n}\n\ninterface DsmlInvoke {\n name: string;\n args: Record<string, unknown>;\n}\n\n/** Strips DSML invoke blocks so the raw-JSON scanner doesn't re-scavenge their parameter payloads. */\nfunction stripDsmlBlocks(text: string): string {\n let out = text;\n out = out.replace(/<[||]DSML[||]function_calls>[\\s\\S]*?<\\/?[||]DSML[||]function_calls>/g, \"\");\n out = out.replace(/<[||]DSML[||]invoke\\s+[^>]*>[\\s\\S]*?<\\/[||]DSML[||]invoke>/g, \"\");\n return out;\n}\n\nfunction* iterateDsmlInvokes(text: string): Generator<DsmlInvoke> {\n // `|` (U+FF5C) in practice; `|` (ASCII) as a fallback seen in a\n // minority of builds. `[||]` inside the regex covers both.\n const INVOKE_RE = /<[||]DSML[||]invoke\\s+name=\"([^\"]+)\">([\\s\\S]*?)<\\/[||]DSML[||]invoke>/g;\n for (const match of text.matchAll(INVOKE_RE)) {\n const name = match[1];\n const body = match[2];\n if (!name || body === undefined) continue;\n yield { name, args: parseDsmlParameters(body) };\n }\n}\n\n/** Falls back to literal text when `string=\"false\"` JSON parse fails — never lose the parameter. */\nfunction parseDsmlParameters(body: string): Record<string, unknown> {\n const PARAM_RE =\n /<[||]DSML[||]parameter\\s+name=\"([^\"]+)\"(?:\\s+string=\"(true|false)\")?\\s*>([\\s\\S]*?)<\\/[||]DSML[||]parameter>/g;\n const args: Record<string, unknown> = {};\n for (const m of body.matchAll(PARAM_RE)) {\n const key = m[1];\n const stringFlag = m[2];\n const raw = (m[3] ?? \"\").trim();\n if (!key) continue;\n if (stringFlag === \"false\") {\n try {\n args[key] = JSON.parse(raw);\n continue;\n } catch {\n // Fall through — keep as literal so the information isn't lost.\n }\n }\n args[key] = raw;\n }\n return args;\n}\n\n/** Yield every top-level JSON object substring in `text`. */\nfunction* iterateJsonObjects(text: string): Generator<string> {\n for (let i = 0; i < text.length; i++) {\n if (text[i] !== \"{\") continue;\n let depth = 0;\n let inString = false;\n let escaped = false;\n for (let j = i; j < text.length; j++) {\n const c = text[j]!;\n if (escaped) {\n escaped = false;\n continue;\n }\n if (inString) {\n if (c === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (c === '\"') inString = false;\n continue;\n }\n if (c === '\"') inString = true;\n else if (c === \"{\") depth++;\n else if (c === \"}\") {\n depth--;\n if (depth === 0) {\n yield text.slice(i, j + 1);\n i = j;\n break;\n }\n }\n }\n }\n}\n\nfunction coerceToToolCall(\n candidateJson: string,\n allowedNames: ReadonlySet<string>,\n): ToolCall | null {\n let parsed: any;\n try {\n parsed = JSON.parse(candidateJson);\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== \"object\") return null;\n\n // Pattern 1: { name, arguments }\n if (typeof parsed.name === \"string\" && allowedNames.has(parsed.name)) {\n const args = parsed.arguments;\n return {\n function: {\n name: parsed.name,\n arguments: typeof args === \"string\" ? args : JSON.stringify(args ?? {}),\n },\n };\n }\n\n // Pattern 2: OpenAI-style { type: \"function\", function: { name, arguments } }\n if (\n parsed.type === \"function\" &&\n parsed.function &&\n typeof parsed.function.name === \"string\" &&\n allowedNames.has(parsed.function.name)\n ) {\n const args = parsed.function.arguments;\n return {\n type: \"function\",\n function: {\n name: parsed.function.name,\n arguments: typeof args === \"string\" ? args : JSON.stringify(args ?? {}),\n },\n };\n }\n\n // Pattern 3: { tool_name, tool_args } (R1 free-form variant)\n if (typeof parsed.tool_name === \"string\" && allowedNames.has(parsed.tool_name)) {\n return {\n function: {\n name: parsed.tool_name,\n arguments: JSON.stringify(parsed.tool_args ?? {}),\n },\n };\n }\n\n return null;\n}\n","import type { ToolCall } from \"../types.js\";\n\n/** Mutating calls clear prior read-only entries so a post-edit re-read isn't flagged as repeat. */\nexport type IsMutating = (call: ToolCall) => boolean;\nexport type IsStormExempt = (call: ToolCall) => boolean;\n\ninterface RecentEntry {\n name: string;\n args: string;\n readOnly: boolean;\n}\n\n/** Tracks (name, args) repeats; mutating calls clear prior read-only entries while still counting amongst themselves. */\nexport class StormBreaker {\n private readonly windowSize: number;\n private readonly threshold: number;\n private readonly isMutating: IsMutating | undefined;\n private readonly isStormExempt: IsStormExempt | undefined;\n private readonly recent: RecentEntry[] = [];\n\n constructor(\n windowSize = 6,\n threshold = 3,\n isMutating?: IsMutating,\n isStormExempt?: IsStormExempt,\n ) {\n this.windowSize = windowSize;\n this.threshold = threshold;\n this.isMutating = isMutating;\n this.isStormExempt = isStormExempt;\n }\n\n inspect(call: ToolCall): { suppress: boolean; reason?: string } {\n const name = call.function?.name;\n if (!name) return { suppress: false };\n if (this.isStormExempt?.(call)) return { suppress: false };\n const args = call.function?.arguments ?? \"\";\n const mutating = this.isMutating ? this.isMutating(call) : false;\n const readOnly = !mutating;\n\n if (mutating) {\n // Drop prior read-only entries — the file/shell state just\n // changed, so a verify-read after this should start with a\n // clean slate. Keep mutator entries: 3 identical edits in a row\n // is still a storm (model in a loop).\n for (let i = this.recent.length - 1; i >= 0; i--) {\n if (this.recent[i]!.readOnly) this.recent.splice(i, 1);\n }\n }\n\n const count = this.recent.reduce((n, e) => (e.name === name && e.args === args ? n + 1 : n), 0);\n if (count >= this.threshold - 1) {\n return {\n suppress: true,\n reason: `${name} called with identical args ${count + 1} times — repeat-loop guard tripped`,\n };\n }\n this.recent.push({ name, args, readOnly });\n while (this.recent.length > this.windowSize) this.recent.shift();\n return { suppress: false };\n }\n\n reset(): void {\n this.recent.length = 0;\n }\n}\n","/** Local-only repair (balance braces, close strings, fill nulls); continuation calls belong to the loop, which owns budgets. */\n\nexport interface TruncationRepairResult {\n repaired: string;\n changed: boolean;\n notes: string[];\n}\n\nexport function repairTruncatedJson(input: string): TruncationRepairResult {\n const notes: string[] = [];\n if (!input || !input.trim()) {\n return { repaired: \"{}\", changed: input !== \"{}\", notes: [\"empty input → {}\"] };\n }\n // Fast path: already parseable.\n try {\n JSON.parse(input);\n return { repaired: input, changed: false, notes: [] };\n } catch {\n /* fall through */\n }\n\n const stack: (\"{\" | \"[\" | '\"')[] = [];\n let escaped = false;\n let inString = false;\n let lastSignificant = -1;\n\n for (let i = 0; i < input.length; i++) {\n const c = input[i]!;\n if (!/\\s/.test(c)) lastSignificant = i;\n if (escaped) {\n escaped = false;\n continue;\n }\n if (inString) {\n if (c === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (c === '\"') {\n inString = false;\n stack.pop();\n }\n continue;\n }\n if (c === '\"') {\n inString = true;\n stack.push('\"');\n continue;\n }\n if (c === \"{\" || c === \"[\") stack.push(c);\n else if (c === \"}\" || c === \"]\") stack.pop();\n }\n\n let s = input.slice(0, lastSignificant + 1);\n\n // Trim a trailing comma which would block re-parse.\n if (/,$/.test(s)) {\n s = s.replace(/,$/, \"\");\n notes.push(\"trimmed trailing comma\");\n }\n\n // If we ended on a key without a value: \"foo\": → \"foo\": null\n if (/\"\\s*:\\s*$/.test(s)) {\n s += \" null\";\n notes.push(\"filled dangling key with null\");\n }\n\n // If we ended inside a string, close it.\n if (inString) {\n s += '\"';\n stack.pop();\n notes.push(\"closed unterminated string\");\n }\n\n // Pop remaining open structures in reverse order.\n while (stack.length > 0) {\n const top = stack.pop();\n if (top === \"{\") s += \"}\";\n else if (top === \"[\") s += \"]\";\n else if (top === '\"') s += '\"';\n }\n\n try {\n JSON.parse(s);\n return { repaired: s, changed: true, notes };\n } catch (err) {\n notes.push(`fallback to {}: ${(err as Error).message}`);\n return { repaired: \"{}\", changed: true, notes };\n }\n}\n","/** Pass order: scavenge → truncation → storm. Schema flatten runs at loop construction, not per-turn. */\n\nimport type { ToolCall } from \"../types.js\";\nimport { scavengeToolCalls } from \"./scavenge.js\";\nimport { type IsMutating, type IsStormExempt, StormBreaker } from \"./storm.js\";\nimport { repairTruncatedJson } from \"./truncation.js\";\n\nexport { analyzeSchema, flattenSchema, nestArguments } from \"./flatten.js\";\nexport type { FlattenDecision } from \"./flatten.js\";\nexport { repairTruncatedJson } from \"./truncation.js\";\nexport type { TruncationRepairResult } from \"./truncation.js\";\nexport { scavengeToolCalls } from \"./scavenge.js\";\nexport type { ScavengeOptions, ScavengeResult } from \"./scavenge.js\";\nexport { StormBreaker } from \"./storm.js\";\n\nexport interface RepairReport {\n scavenged: number;\n truncationsFixed: number;\n stormsBroken: number;\n notes: string[];\n}\n\nexport interface ToolCallRepairOptions {\n allowedToolNames: ReadonlySet<string>;\n stormWindow?: number;\n stormThreshold?: number;\n maxScavenge?: number;\n /** Mutating calls clear the storm window so a post-edit verify-read isn't seen as a repeat. */\n isMutating?: IsMutating;\n /** Cheap state-inspection calls that should never trip repeat-loop suppression. */\n isStormExempt?: IsStormExempt;\n}\n\nexport class ToolCallRepair {\n private readonly storm: StormBreaker;\n private readonly opts: ToolCallRepairOptions;\n\n constructor(opts: ToolCallRepairOptions) {\n this.opts = opts;\n this.storm = new StormBreaker(\n opts.stormWindow ?? 6,\n opts.stormThreshold ?? 3,\n opts.isMutating,\n opts.isStormExempt,\n );\n }\n\n /** Called at start of every user turn — fresh intent shouldn't inherit old repetition state. */\n resetStorm(): void {\n this.storm.reset();\n }\n\n process(\n declaredCalls: ToolCall[],\n reasoningContent: string | null,\n content: string | null = null,\n ): { calls: ToolCall[]; report: RepairReport } {\n const report: RepairReport = {\n scavenged: 0,\n truncationsFixed: 0,\n stormsBroken: 0,\n notes: [],\n };\n\n // 1. Scavenge — only add calls whose (name,args) signature is novel.\n // Scan both channels: reasoning (where R1 leaks JSON calls into\n // <think>) AND content (where it emits DSML markup in regular\n // turns). Joined with a newline so the scanners see the blobs as\n // independent bodies. Dedup below keeps us from inflating if the\n // same call shows up in both — first seen wins.\n const combined = [reasoningContent ?? \"\", content ?? \"\"].filter(Boolean).join(\"\\n\");\n const scavenged = scavengeToolCalls(combined || null, {\n allowedNames: this.opts.allowedToolNames,\n maxCalls: this.opts.maxScavenge ?? 4,\n });\n const seenSignatures = new Set(declaredCalls.map(signature));\n const merged = [...declaredCalls];\n for (const sc of scavenged.calls) {\n if (!seenSignatures.has(signature(sc))) {\n merged.push(sc);\n report.scavenged++;\n seenSignatures.add(signature(sc));\n }\n }\n report.notes.push(...scavenged.notes);\n\n // 2. Truncation repair on argument JSON.\n for (const call of merged) {\n const args = call.function?.arguments ?? \"\";\n const r = repairTruncatedJson(args);\n if (r.changed) {\n call.function.arguments = r.repaired;\n report.truncationsFixed++;\n report.notes.push(...r.notes.map((n) => `[${call.function.name}] ${n}`));\n }\n }\n\n // 3. Storm breaker.\n const filtered: ToolCall[] = [];\n for (const call of merged) {\n const verdict = this.storm.inspect(call);\n if (verdict.suppress) {\n report.stormsBroken++;\n if (verdict.reason) report.notes.push(verdict.reason);\n continue;\n }\n filtered.push(call);\n }\n\n return { calls: filtered, report };\n }\n}\n\nfunction signature(call: ToolCall): string {\n return `${call.function?.name ?? \"\"}::${call.function?.arguments ?? \"\"}`;\n}\n","import { type DeepSeekClient, Usage } from \"./client.js\";\nimport type { PauseGate } from \"./core/pause-gate.js\";\nimport { pauseGate as defaultPauseGate } from \"./core/pause-gate.js\";\nimport { type HookPayload, type ResolvedHook, runHooks } from \"./hooks.js\";\nimport {\n DEFAULT_MAX_RESULT_CHARS,\n DEFAULT_MAX_RESULT_TOKENS,\n truncateForModel,\n truncateForModelByTokens,\n} from \"./mcp/registry.js\";\n\nimport { ContextManager } from \"./context-manager.js\";\nimport { InflightSet } from \"./core/inflight.js\";\nimport { t } from \"./i18n/index.js\";\nimport { formatLoopError, is5xxError, probeDeepSeekReachable } from \"./loop/errors.js\";\nimport {\n NEEDS_PRO_BUFFER_CHARS,\n isEscalationRequest,\n looksLikePartialEscalationMarker,\n parseEscalationMarker,\n} from \"./loop/escalation.js\";\nimport { type ForceSummaryContext, forceSummaryAfterIterLimit } from \"./loop/force-summary.js\";\nimport {\n fixToolCallPairing,\n healLoadedMessages,\n healLoadedMessagesByTokens,\n stampMissingReasoningForThinkingMode,\n} from \"./loop/healing.js\";\nimport { hookWarnings, safeParseToolArgs } from \"./loop/hook-events.js\";\nimport { buildAssistantMessage, buildSyntheticAssistantMessage } from \"./loop/messages.js\";\nimport {\n looksLikeCompleteJson,\n shrinkOversizedToolCallArgsByTokens,\n shrinkOversizedToolResults,\n shrinkOversizedToolResultsByTokens,\n} from \"./loop/shrink.js\";\nimport {\n isThinkingModeModel,\n stripHallucinatedToolMarkup,\n thinkingModeForModel,\n} from \"./loop/thinking.js\";\nimport { TurnFailureTracker } from \"./loop/turn-failure-tracker.js\";\nimport type { LoopEvent } from \"./loop/types.js\";\nimport { AppendOnlyLog, type ImmutablePrefix, VolatileScratch } from \"./memory/runtime.js\";\nimport {\n appendSessionMessage,\n loadSessionMessages,\n loadSessionMeta,\n rewriteSession,\n} from \"./memory/session.js\";\nimport { type RepairReport, ToolCallRepair } from \"./repair/index.js\";\nimport { SessionStats, type TurnStats } from \"./telemetry/stats.js\";\nimport { countTokens } from \"./tokenizer.js\";\nimport { ToolRegistry } from \"./tools.js\";\nimport type { ChatMessage, ToolCall } from \"./types.js\";\n\nconst ESCALATION_MODEL = \"deepseek-v4-pro\";\n\nexport {\n fixToolCallPairing,\n formatLoopError,\n healLoadedMessages,\n healLoadedMessagesByTokens,\n isThinkingModeModel,\n looksLikeCompleteJson,\n shrinkOversizedToolCallArgsByTokens,\n shrinkOversizedToolResults,\n shrinkOversizedToolResultsByTokens,\n stampMissingReasoningForThinkingMode,\n stripHallucinatedToolMarkup,\n thinkingModeForModel,\n};\nexport type { EventRole, LoopEvent } from \"./loop/types.js\";\n\nexport interface CacheFirstLoopOptions {\n client: DeepSeekClient;\n prefix: ImmutablePrefix;\n tools?: ToolRegistry;\n model?: string;\n maxToolIters?: number;\n stream?: boolean;\n reasoningEffort?: \"high\" | \"max\";\n autoEscalate?: boolean;\n /** Soft USD cap — warns at 80%, refuses next turn at 100%. Opt-in (default no cap). */\n budgetUsd?: number;\n session?: string;\n /** PreToolUse + PostToolUse only — UserPromptSubmit / Stop live at the App boundary. */\n hooks?: ResolvedHook[];\n /** `cwd` reported to hooks; `reasonix code` sets this to the sandbox root, not shell home. */\n hookCwd?: string;\n /** PauseGate bridge — defaults to singleton, injectable for tests. */\n confirmationGate?: PauseGate;\n}\n\nexport interface ReconfigurableOptions {\n model?: string;\n stream?: boolean;\n /** V4 thinking mode only; deepseek-chat ignores. */\n reasoningEffort?: \"high\" | \"max\";\n /** `false` pins to `model` — kills both NEEDS_PRO marker scavenge and failure-count threshold. */\n autoEscalate?: boolean;\n}\n\nexport class CacheFirstLoop {\n readonly client: DeepSeekClient;\n readonly prefix: ImmutablePrefix;\n readonly tools: ToolRegistry;\n readonly maxToolIters: number;\n readonly log = new AppendOnlyLog();\n readonly scratch = new VolatileScratch();\n readonly stats = new SessionStats();\n readonly repair: ToolCallRepair;\n\n // Mutable via configure() — slash commands in the TUI / library callers tweak\n // these mid-session so users don't have to restart.\n model: string;\n stream: boolean;\n reasoningEffort: \"high\" | \"max\";\n autoEscalate = true;\n budgetUsd: number | null;\n /** One-shot 80% warning latch — cleared by setBudget so a bump re-arms at the new boundary. */\n private _budgetWarned = false;\n sessionName: string | null;\n\n hooks: ResolvedHook[];\n hookCwd: string;\n\n /** PauseGate bridge — defaults to singleton, injectable for tests. */\n readonly confirmationGate: PauseGate;\n\n /** Number of messages that were pre-loaded from the session file. */\n readonly resumedMessageCount: number;\n\n private _turn = 0;\n private _streamPreference: boolean;\n /** Threaded through HTTP + every tool dispatch so Esc cancels in-flight work, not after. */\n private _turnAbort: AbortController = new AbortController();\n /** Authoritative running-id set — UI cards consult this instead of trusting end-event delivery. Insert at dispatch entry, delete in finally. */\n private readonly _inflight = new InflightSet();\n\n private _proArmedForNextTurn = false;\n private _escalateThisTurn = false;\n private readonly _turnFailures = new TurnFailureTracker();\n private _turnSelfCorrected = false;\n private _foldedThisTurn = false;\n private context!: ContextManager;\n\n /** Subscribe API so UI hooks can derive `running` from finally-guaranteed insertions. */\n get inflight(): InflightSet {\n return this._inflight;\n }\n\n get currentTurn(): number {\n return this._turn;\n }\n\n constructor(opts: CacheFirstLoopOptions) {\n this.client = opts.client;\n this.prefix = opts.prefix;\n this.tools = opts.tools ?? new ToolRegistry();\n this.model = opts.model ?? \"deepseek-v4-flash\";\n this.reasoningEffort = opts.reasoningEffort ?? \"max\";\n if (opts.autoEscalate !== undefined) this.autoEscalate = opts.autoEscalate;\n this.budgetUsd =\n typeof opts.budgetUsd === \"number\" && opts.budgetUsd > 0 ? opts.budgetUsd : null;\n // Last-resort backstop — primary stop is the token-context guard inside step().\n this.maxToolIters = opts.maxToolIters ?? 64;\n this.hooks = opts.hooks ?? [];\n this.hookCwd = opts.hookCwd ?? process.cwd();\n this.confirmationGate = opts.confirmationGate ?? defaultPauseGate;\n\n this._streamPreference = opts.stream ?? true;\n this.stream = this._streamPreference;\n\n const allowedNames = new Set([...this.prefix.toolSpecs.map((s) => s.function.name)]);\n // Storm breaker clears its window on mutating calls so read → edit → verify isn't a storm.\n const registry = this.tools;\n const isMutating = (call: ToolCall): boolean => {\n const name = call.function?.name;\n if (!name) return false;\n const def = registry.get(name);\n if (!def) return false;\n if (def.readOnlyCheck) {\n let args: Record<string, unknown> = {};\n try {\n args = JSON.parse(call.function?.arguments ?? \"{}\") ?? {};\n } catch {\n // Malformed args → fall through to the static flag below; the\n // dynamic check would've thrown anyway.\n }\n try {\n if (def.readOnlyCheck(args as never)) return false;\n } catch {\n /* ignore — fall through */\n }\n }\n return def.readOnly !== true;\n };\n const isStormExempt = (call: ToolCall): boolean => {\n const name = call.function?.name;\n if (!name) return false;\n return registry.get(name)?.stormExempt === true;\n };\n this.repair = new ToolCallRepair({\n allowedToolNames: allowedNames,\n isMutating,\n isStormExempt,\n stormThreshold: parsePositiveIntEnv(process.env.REASONIX_STORM_THRESHOLD),\n stormWindow: parsePositiveIntEnv(process.env.REASONIX_STORM_WINDOW),\n });\n\n // Heal-on-load: oversized tool results would 400 the next call before the user types.\n this.sessionName = opts.session ?? null;\n if (this.sessionName) {\n const prior = loadSessionMessages(this.sessionName);\n const shrunk = healLoadedMessagesByTokens(prior, DEFAULT_MAX_RESULT_TOKENS);\n // Thinking-mode sessions: API 400s if any historical assistant turn lacks reasoning_content.\n const stamped = stampMissingReasoningForThinkingMode(shrunk.messages, this.model);\n const messages = stamped.messages;\n const healedCount = shrunk.healedCount + stamped.stampedCount;\n const tokensSaved = shrunk.tokensSaved;\n for (const msg of messages) this.log.append(msg);\n this.resumedMessageCount = messages.length;\n // Carry forward cumulative cost / turn count so the TUI's session\n // total continues across resumes; otherwise each restart resets to $0.\n if (messages.length > 0) {\n const meta = loadSessionMeta(this.sessionName);\n this.stats.seedCarryover({\n totalCostUsd: meta.totalCostUsd,\n turnCount: meta.turnCount,\n cacheHitTokens: meta.cacheHitTokens,\n cacheMissTokens: meta.cacheMissTokens,\n lastPromptTokens: meta.lastPromptTokens,\n });\n }\n if (healedCount > 0) {\n // Persist healed log so the same break isn't re-noticed every restart.\n try {\n rewriteSession(this.sessionName, messages);\n } catch {\n /* disk full / perms — skip, in-memory heal still applies */\n }\n process.stderr.write(\n `▸ session \"${this.sessionName}\": healed ${healedCount} entr${healedCount === 1 ? \"y\" : \"ies\"}${tokensSaved > 0 ? ` (shrunk ${tokensSaved.toLocaleString()} tokens of oversized tool output)` : \" (dropped dangling tool_calls tail)\"}. Rewrote session file.\\n`,\n );\n }\n } else {\n this.resumedMessageCount = 0;\n }\n\n this.context = new ContextManager({\n client: this.client,\n log: this.log,\n stats: this.stats,\n sessionName: this.sessionName,\n getAbortSignal: () => this._turnAbort.signal,\n getCurrentTurn: () => this._turn,\n });\n }\n\n /** Replace older turns with one summary message; keep tail within keepRecentTokens budget. */\n async compactHistory(opts?: { keepRecentTokens?: number }): Promise<{\n folded: boolean;\n beforeMessages: number;\n afterMessages: number;\n summaryChars: number;\n }> {\n return this.context.fold(this.model, opts);\n }\n\n appendAndPersist(message: ChatMessage): void {\n this.log.append(message);\n if (this.sessionName) {\n try {\n appendSessionMessage(this.sessionName, message);\n } catch {\n /* disk full or permission denied shouldn't kill the chat */\n }\n }\n }\n\n /** Swap the just-appended assistant entry — used by self-correction to restore the original tool_calls without dropping reasoning_content. */\n private replaceTailAssistantMessage(message: ChatMessage): void {\n const entries = this.log.entries;\n const tail = entries[entries.length - 1];\n if (!tail || tail.role !== \"assistant\") return;\n const kept = entries.slice(0, -1);\n kept.push(message);\n this.log.compactInPlace(kept);\n if (this.sessionName) {\n try {\n rewriteSession(this.sessionName, kept);\n } catch {\n /* disk issue shouldn't block the in-memory swap */\n }\n }\n }\n\n /** \"New chat\" — drops messages but keeps session + immutable prefix (cache-first invariant). */\n clearLog(): { dropped: number } {\n const dropped = this.log.length;\n this.log.compactInPlace([]);\n if (this.sessionName) {\n try {\n rewriteSession(this.sessionName, []);\n } catch {\n /* disk issue shouldn't block the in-memory clear */\n }\n }\n this.scratch.reset();\n this._inflight.clear();\n return { dropped };\n }\n\n configure(opts: ReconfigurableOptions): void {\n if (opts.model !== undefined) this.model = opts.model;\n if (opts.stream !== undefined) {\n this._streamPreference = opts.stream;\n this.stream = opts.stream;\n }\n if (opts.reasoningEffort !== undefined) this.reasoningEffort = opts.reasoningEffort;\n if (opts.autoEscalate !== undefined) this.autoEscalate = opts.autoEscalate;\n }\n\n /** `null` disables the cap; any change re-arms the 80% warning. */\n setBudget(usd: number | null): void {\n this.budgetUsd = typeof usd === \"number\" && usd > 0 ? usd : null;\n this._budgetWarned = false;\n }\n\n /** Single-turn upgrade consumed at next step() — distinct from `/preset max` (persistent). */\n armProForNextTurn(): void {\n this._proArmedForNextTurn = true;\n }\n /** Cancel `/pro` arming before the next turn starts. */\n disarmPro(): void {\n this._proArmedForNextTurn = false;\n }\n /** UI surface — true while `/pro` is queued but hasn't fired yet. */\n get proArmed(): boolean {\n return this._proArmedForNextTurn;\n }\n /** UI surface — true while the current turn is running on pro (armed or auto-escalated). */\n get escalatedThisTurn(): boolean {\n return this._escalateThisTurn;\n }\n\n /** UI surface — model id of the call about to run (or running) right now, including escalation. */\n get currentCallModel(): string {\n return this.modelForCurrentCall();\n }\n\n private modelForCurrentCall(): string {\n return this._escalateThisTurn ? ESCALATION_MODEL : this.model;\n }\n\n /** Returns true ONLY on the tipping call — caller surfaces a one-shot warning. */\n private noteToolFailureSignal(resultJson: string, repair?: RepairReport): boolean {\n if (!this._turnFailures.noteAndCrossedThreshold(resultJson, repair)) return false;\n if (this._escalateThisTurn || !this.autoEscalate) return false;\n this._escalateThisTurn = true;\n return true;\n }\n\n private async runOneToolCall(\n call: ToolCall,\n signal: AbortSignal,\n ): Promise<{ preWarnings: LoopEvent[]; postWarnings: LoopEvent[]; result: string }> {\n const name = call.function?.name ?? \"\";\n const args = call.function?.arguments ?? \"{}\";\n const parsedArgs = safeParseToolArgs(args);\n this._inflight.add(this.inflightIdFor(call));\n try {\n const preReport = await runHooks({\n hooks: this.hooks,\n payload: {\n event: \"PreToolUse\",\n cwd: this.hookCwd,\n toolName: name,\n toolArgs: parsedArgs,\n },\n });\n const preWarnings = [...hookWarnings(preReport.outcomes, this._turn)];\n\n if (preReport.blocked) {\n const blocking = preReport.outcomes[preReport.outcomes.length - 1];\n const reason = (\n blocking?.stderr ||\n blocking?.stdout ||\n \"blocked by PreToolUse hook\"\n ).trim();\n return {\n preWarnings,\n postWarnings: [],\n result: `[hook block] ${blocking?.hook.command ?? \"<unknown>\"}\\n${reason}`,\n };\n }\n\n const result = await this.tools.dispatch(name, args, {\n signal,\n maxResultTokens: DEFAULT_MAX_RESULT_TOKENS,\n confirmationGate: this.confirmationGate,\n });\n\n const postReport = await runHooks({\n hooks: this.hooks,\n payload: {\n event: \"PostToolUse\",\n cwd: this.hookCwd,\n toolName: name,\n toolArgs: parsedArgs,\n toolResult: result,\n },\n });\n const postWarnings = [...hookWarnings(postReport.outcomes, this._turn)];\n\n return { preWarnings, postWarnings, result };\n } finally {\n this._inflight.delete(this.inflightIdFor(call));\n }\n }\n\n /** Stable per-call id used as the inflight key AND threaded into tool_start / tool events so the UI matches them up. */\n private inflightIdFor(call: ToolCall): string {\n if (call.id) return call.id;\n const fallback = (call as { _inflightFallback?: string })._inflightFallback;\n if (fallback) return fallback;\n const generated = `inflight-${++this._inflightCounter}`;\n (call as { _inflightFallback?: string })._inflightFallback = generated;\n return generated;\n }\n private _inflightCounter = 0;\n\n private buildMessages(pendingUser: string | null): ChatMessage[] {\n // DeepSeek 400s on either unpaired tool_calls or stray tool entries — heal before sending.\n const healed = healLoadedMessages(this.log.toMessages(), DEFAULT_MAX_RESULT_CHARS);\n const msgs: ChatMessage[] = [...this.prefix.toMessages(), ...healed.messages];\n if (pendingUser !== null) msgs.push({ role: \"user\", content: pendingUser });\n return msgs;\n }\n\n abort(): void {\n this._turnAbort.abort();\n }\n\n /** Drop the last user message + everything after; caller re-sends. Persists to session file. */\n retryLastUser(): string | null {\n const entries = this.log.entries;\n let lastUserIdx = -1;\n for (let i = entries.length - 1; i >= 0; i--) {\n if (entries[i]!.role === \"user\") {\n lastUserIdx = i;\n break;\n }\n }\n if (lastUserIdx < 0) return null;\n const raw = entries[lastUserIdx]!.content;\n const userText = typeof raw === \"string\" ? raw : \"\";\n const preserved = entries.slice(0, lastUserIdx).map((m) => ({ ...m }));\n this.log.compactInPlace(preserved);\n if (this.sessionName) {\n try {\n rewriteSession(this.sessionName, preserved);\n } catch {\n /* disk-full / perms — in-memory compaction still applies */\n }\n }\n return userText;\n }\n\n async *step(userInput: string): AsyncGenerator<LoopEvent> {\n // Budget gate runs FIRST, before any per-turn state mutation, so a\n // refusal leaves the loop unchanged and the user can correct the\n // cap and re-issue. Default `null` short-circuits the whole check\n // so the no-budget path is one comparison, no behavior delta.\n if (this.budgetUsd !== null) {\n const spent = this.stats.totalCost;\n if (spent >= this.budgetUsd) {\n yield {\n turn: this._turn,\n role: \"error\",\n content: \"\",\n error: t(\"loop.budgetExhausted\", {\n spent: spent.toFixed(4),\n cap: this.budgetUsd.toFixed(2),\n }),\n };\n return;\n }\n if (!this._budgetWarned && spent >= this.budgetUsd * 0.8) {\n this._budgetWarned = true;\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.budget80Pct\", {\n spent: spent.toFixed(4),\n cap: this.budgetUsd.toFixed(2),\n }),\n };\n }\n }\n this._turn++;\n this.scratch.reset();\n // A fresh user turn is a new intent — don't let StormBreaker's\n // old sliding window of (name, args) signatures keep blocking\n // calls that are now legitimately on-task. The window repopulates\n // naturally as this turn's tool calls flow through.\n this.repair.resetStorm();\n // Per-turn escalation state: reset both flags at turn start, then\n // consume the /pro armed flag into `_escalateThisTurn` (so the\n // armed intent is one-shot — next turn starts fresh on flash\n // unless the user re-arms or mid-turn escalation triggers).\n this._turnFailures.reset();\n this._turnSelfCorrected = false;\n this._escalateThisTurn = false;\n this._foldedThisTurn = false;\n let armedConsumed = false;\n if (this._proArmedForNextTurn) {\n this._escalateThisTurn = true;\n this._proArmedForNextTurn = false;\n armedConsumed = true;\n }\n // Fresh controller for this turn: the prior step's signal has\n // already fired (or stayed clean); either way we don't want its\n // state to bleed into the new turn.\n //\n // Edge case — `loop.abort()` may have been called BEFORE step()\n // ran (race: caller fires abort during async setup, but step()\n // hadn't been awaited yet). Naively reassigning _turnAbort would\n // silently drop that abort. Forward the prior aborted state into\n // the fresh controller so the iter-0 check still bails out. This\n // is load-bearing for subagents: the parent's onParentAbort\n // listener calls childLoop.abort(), which can fire before\n // childLoop.step() has reached the `for await` line below.\n const carryAbort = this._turnAbort.signal.aborted;\n this._turnAbort = new AbortController();\n if (carryAbort) this._turnAbort.abort();\n const signal = this._turnAbort.signal;\n if (armedConsumed) {\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.proArmed\"),\n };\n }\n let pendingUser: string | null = userInput;\n const toolSpecs = this.prefix.tools();\n // 70% of the iter budget is the \"you're getting close\" threshold. We\n // only warn once per step so the user sees a single signal, not a\n // string of identical yellow lines stacked up.\n const warnAt = Math.max(1, Math.floor(this.maxToolIters * 0.7));\n let warnedForIterBudget = false;\n\n for (let iter = 0; iter < this.maxToolIters; iter++) {\n if (signal.aborted) {\n // Esc means \"stop now\" — not \"stop and force another 30-90s\n // reasoner call to produce a summary I didn't ask for\". The\n // user's mental model of cancel is immediate. We emit a\n // synthetic assistant_final (tagged forcedSummary so the\n // code-mode applier ignores it) with a short stopped\n // message, then done. The prior tool outputs are still in\n // the log if the user wants to continue — asking again\n // will hit a warm cache and be cheap.\n //\n // Budget / context-guard still call forceSummaryAfterIterLimit\n // because there the USER didn't choose to stop — we did —\n // and leaving them staring at nothing is worse than one extra\n // call.\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.abortedAtIter\", { iter, cap: this.maxToolIters }),\n };\n const stoppedMsg =\n \"[aborted by user (Esc) — no summary produced. Ask again or /retry when ready; prior tool output is still in the log.]\";\n // Synthetic assistant turn — no real model output exists. For\n // reasoner sessions R1 still demands `reasoning_content` on\n // every assistant message, so we attach an empty-string\n // placeholder to satisfy the validator without inventing\n // reasoning we don't have. V3 gets a plain message as before.\n this.appendAndPersist(buildSyntheticAssistantMessage(stoppedMsg, this.model));\n yield {\n turn: this._turn,\n role: \"assistant_final\",\n content: stoppedMsg,\n forcedSummary: true,\n };\n yield { turn: this._turn, role: \"done\", content: stoppedMsg };\n // Reset to a fresh, non-aborted controller before returning.\n // Without this the carry-abort logic above sees the still-\n // aborted controller on the NEXT step() entry and immediately\n // re-aborts at iter 0, locking the session: every subsequent\n // user message produces \"stopped without producing a summary\"\n // before any work happens. A user-initiated Esc is a discrete\n // event tied to ONE turn; it must not bleed into the next.\n // (The race scenario the carry-abort handles — abort fired in\n // the async window before step() entry — still works: a fresh\n // abort() between turns aborts the new controller below.)\n this._turnAbort = new AbortController();\n return;\n }\n // Bridge the silence between the PREVIOUS iter's tool result and\n // THIS iter's first streaming byte. R1 can spend 20-90s reasoning\n // about tool output before the first delta lands, and prior to\n // this hint the UI had nothing to render. Only emit on iter > 0\n // because iter 0's \"thinking\" phase is already covered by the\n // streaming row / StreamingAssistant's placeholder.\n //\n // Wording is explicit about the two things happening: the tool\n // result IS being uploaded (it's now part of the next prompt) and\n // the model IS thinking. Users were reading \"thinking about the\n // tool result\" as the model-only phase, but the wait also covers\n // the upload round-trip.\n if (iter > 0) {\n yield {\n turn: this._turn,\n role: \"status\",\n content: t(\"loop.toolUploadStatus\"),\n };\n }\n if (!warnedForIterBudget && iter >= warnAt) {\n warnedForIterBudget = true;\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.toolBudgetWarning\", { iter, cap: this.maxToolIters }),\n };\n }\n let messages = this.buildMessages(pendingUser);\n\n // Preflight context check. Local estimate of the outgoing payload\n // catches cases where prior usage didn't warn us (fresh resume, one\n // huge tool result). Above 95% we attempt a fold as a last resort —\n // it costs one summary call but stays cache-friendly. If the fold\n // can't shrink anything, we surface a warning and let the request\n // go (and likely 400) so the user knows to /clear.\n {\n const decision = this.context.decidePreflight(messages, this.prefix.toolSpecs, this.model);\n if (decision.needsAction) {\n const { estimateTokens: estimate, ctxMax } = decision;\n yield {\n turn: this._turn,\n role: \"status\",\n content: t(\"loop.preflightFoldStatus\"),\n };\n const result = await this.context.fold(this.model);\n if (result.folded) {\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.preflightFolded\", {\n estimate: estimate.toLocaleString(),\n ctxMax: ctxMax.toLocaleString(),\n pct: Math.round((estimate / ctxMax) * 100),\n beforeMessages: result.beforeMessages,\n afterMessages: result.afterMessages,\n summaryChars: result.summaryChars,\n }),\n };\n // Rebuild with the folded log so we send the smaller payload.\n messages = this.buildMessages(pendingUser);\n } else {\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.preflightNoFold\", {\n estimate: estimate.toLocaleString(),\n ctxMax: ctxMax.toLocaleString(),\n pct: Math.round((estimate / ctxMax) * 100),\n }),\n };\n }\n }\n }\n\n let assistantContent = \"\";\n let reasoningContent = \"\";\n let toolCalls: ToolCall[] = [];\n let usage: TurnStats[\"usage\"] | null = null;\n\n try {\n if (this.stream) {\n const callBuf: Map<number, ToolCall> = new Map();\n // Indices whose accumulated args have parsed as valid JSON at\n // least once. Purely informational — we don't dispatch until\n // the stream ends (that's the eager-dispatch feature we\n // intentionally punted) but the UI shows \"N ready\" so the\n // user sees progress on long multi-tool turns instead of a\n // stagnant \"building tool call\" spinner.\n const readyIndices = new Set<number>();\n const callModel = this.modelForCurrentCall();\n // Escalation-marker buffer: delay the first few assistant_delta\n // yields so a \"<<<NEEDS_PRO>>>\" lead-in never flashes on-screen\n // before we abort + retry. Only active on flash AND when the\n // user hasn't disabled auto-escalation (the `flash` preset\n // turns this off — model output flows through verbatim, no\n // marker handling). pro never requests its own escalation.\n const bufferForEscalation = this.autoEscalate && callModel !== ESCALATION_MODEL;\n let escalationBuf = \"\";\n let escalationBufFlushed = false;\n for await (const chunk of this.client.stream({\n model: callModel,\n messages,\n tools: toolSpecs.length ? toolSpecs : undefined,\n signal,\n thinking: thinkingModeForModel(callModel),\n reasoningEffort: this.reasoningEffort,\n })) {\n if (chunk.contentDelta) {\n assistantContent += chunk.contentDelta;\n if (bufferForEscalation && !escalationBufFlushed) {\n escalationBuf += chunk.contentDelta;\n // Early exit: marker matches — break and let the\n // post-call retry path take over. No delta was yielded\n // so the user sees nothing flicker.\n if (isEscalationRequest(escalationBuf)) {\n break;\n }\n // Flush once we have enough content to rule out the\n // marker (clearly not a partial match anymore, or past\n // the look-ahead window).\n if (\n escalationBuf.length >= NEEDS_PRO_BUFFER_CHARS ||\n !looksLikePartialEscalationMarker(escalationBuf)\n ) {\n escalationBufFlushed = true;\n yield {\n turn: this._turn,\n role: \"assistant_delta\",\n content: escalationBuf,\n };\n escalationBuf = \"\";\n }\n } else {\n yield {\n turn: this._turn,\n role: \"assistant_delta\",\n content: chunk.contentDelta,\n };\n }\n }\n if (chunk.reasoningDelta) {\n reasoningContent += chunk.reasoningDelta;\n yield {\n turn: this._turn,\n role: \"assistant_delta\",\n content: \"\",\n reasoningDelta: chunk.reasoningDelta,\n };\n }\n if (chunk.toolCallDelta) {\n const d = chunk.toolCallDelta;\n const cur = callBuf.get(d.index) ?? {\n id: d.id,\n type: \"function\" as const,\n function: { name: \"\", arguments: \"\" },\n };\n if (d.id) cur.id = d.id;\n if (d.name) cur.function.name = (cur.function.name ?? \"\") + d.name;\n if (d.argumentsDelta)\n cur.function.arguments = (cur.function.arguments ?? \"\") + d.argumentsDelta;\n callBuf.set(d.index, cur);\n\n // Mark this index \"ready\" once its args first parse as\n // valid JSON. JSON.parse is sub-millisecond on typical\n // tool-call payloads; skip the check once already ready.\n if (\n !readyIndices.has(d.index) &&\n cur.function.name &&\n looksLikeCompleteJson(cur.function.arguments ?? \"\")\n ) {\n readyIndices.add(d.index);\n }\n\n // Skip the id-only opener: name is empty until the next chunk.\n if (cur.function.name) {\n yield {\n turn: this._turn,\n role: \"tool_call_delta\",\n content: \"\",\n toolName: cur.function.name,\n toolCallArgsChars: (cur.function.arguments ?? \"\").length,\n toolCallIndex: d.index,\n toolCallReadyCount: readyIndices.size,\n };\n }\n }\n if (chunk.usage) usage = chunk.usage;\n }\n toolCalls = [...callBuf.values()];\n // Stream ended before the escalation buffer got flushed —\n // either a short response or a partial marker match. If the\n // buffer ISN'T the marker, flush it as the final delta so\n // the user sees it. Marker-match is handled post-call.\n if (bufferForEscalation && !escalationBufFlushed && escalationBuf.length > 0) {\n if (!isEscalationRequest(escalationBuf)) {\n yield {\n turn: this._turn,\n role: \"assistant_delta\",\n content: escalationBuf,\n };\n }\n }\n } else {\n const callModel = this.modelForCurrentCall();\n const resp = await this.client.chat({\n model: callModel,\n messages,\n tools: toolSpecs.length ? toolSpecs : undefined,\n signal,\n thinking: thinkingModeForModel(callModel),\n reasoningEffort: this.reasoningEffort,\n });\n assistantContent = resp.content;\n reasoningContent = resp.reasoningContent ?? \"\";\n toolCalls = resp.toolCalls;\n usage = resp.usage;\n }\n } catch (err) {\n // An aborted signal here is almost always our own doing —\n // either Esc, or App.tsx calling `loop.abort()` to switch to a\n // queued synthetic input (ShellConfirm \"always allow\", PlanConfirm\n // approve, etc.). The DeepSeek client's fetch path translates\n // the abort into a generic `AbortError(\"This operation was\n // aborted\")`, which used to bubble up here and render as a\n // scary red \"error\" row even though nothing actually broke.\n // Treat it as a clean early-exit instead: the next turn (queued\n // synthetic OR user re-prompt) starts immediately and gets to\n // produce its own answer.\n if (signal.aborted) {\n yield { turn: this._turn, role: \"done\", content: \"\" };\n // Reset the controller so the carry-abort check at the top of\n // the NEXT step() doesn't inherit this turn's aborted state.\n // Without this, a queued-submit triggered by App.tsx (e.g.\n // ShellConfirm \"run once\" → loop.abort() + setQueuedSubmit)\n // produces a spurious \"aborted at iter 0/64\" the moment the\n // synthetic message starts processing, locking the session.\n this._turnAbort = new AbortController();\n return;\n }\n const probe = is5xxError(err) ? await probeDeepSeekReachable(this.client) : undefined;\n yield {\n turn: this._turn,\n role: \"error\",\n content: \"\",\n error: formatLoopError(err as Error, probe),\n };\n return;\n }\n\n // Self-reported escalation: the model (flash) emitted the\n // NEEDS_PRO marker as its lead-in. Abort this call's accounting,\n // flip the turn to pro, and re-enter the iter without advancing\n // the counter — next attempt runs on v4-pro with the same\n // messages. Only triggers when the call was on a model OTHER\n // than the escalation model; if the user already configured\n // v4-pro (via /preset max etc.), the marker is taken as a\n // no-op content and passed through verbatim, so there's no\n // infinite-retry loop.\n if (\n this.autoEscalate &&\n this.modelForCurrentCall() !== ESCALATION_MODEL &&\n isEscalationRequest(assistantContent)\n ) {\n const { reason } = parseEscalationMarker(assistantContent);\n this._escalateThisTurn = true;\n const reasonSuffix = reason ? ` — ${reason}` : \"\";\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.flashEscalation\", { model: ESCALATION_MODEL, reasonSuffix }),\n };\n // Reset per-iter state. We don't record stats for the rejected\n // flash call (cost is small — a ~20-token lead-in that we broke\n // out of early on streaming) — recording would attribute a\n // phantom call to the session total.\n assistantContent = \"\";\n reasoningContent = \"\";\n toolCalls = [];\n usage = null;\n // Redo this iter on pro — `iter--` cancels the `iter++` the\n // for loop runs on `continue`.\n iter--;\n continue;\n }\n\n // Attribute under the actual model used (escalated → pro, else\n // this.model) so cost/usage logs reflect reality.\n const turnStats = this.stats.record(\n this._turn,\n this.modelForCurrentCall(),\n usage ?? new Usage(),\n );\n\n // Commit the user turn to the log only on success of the first round-trip.\n if (pendingUser !== null) {\n this.appendAndPersist({ role: \"user\", content: pendingUser });\n pendingUser = null;\n }\n\n this.scratch.reasoning = reasoningContent || null;\n\n const { calls: repairedCalls, report } = this.repair.process(\n toolCalls,\n reasoningContent || null,\n assistantContent || null,\n );\n\n this.appendAndPersist(\n buildAssistantMessage(\n assistantContent,\n repairedCalls,\n this.modelForCurrentCall(),\n reasoningContent,\n ),\n );\n\n yield {\n turn: this._turn,\n role: \"assistant_final\",\n content: assistantContent,\n stats: turnStats,\n repair: report,\n };\n\n // Cost-aware escalation: repair fires (scavenge / truncation /\n // storm) are visible \"model struggled\" signals. Feed them into\n // the turn failure counter — if we hit the threshold, the\n // remainder of this turn's model calls use pro.\n if (this.noteToolFailureSignal(\"\", report)) {\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.autoEscalation\", {\n model: ESCALATION_MODEL,\n breakdown: this._turnFailures.formatBreakdown(),\n fallback: this.model,\n }),\n };\n }\n\n const allSuppressed =\n report.stormsBroken > 0 && repairedCalls.length === 0 && toolCalls.length > 0;\n\n // First all-suppressed storm: rewrite tail with the original tool_calls\n // (so the next prompt shows what was attempted), stub tool responses to\n // keep the API contract, and continue the iter — model gets one shot to\n // self-correct before the loud-warning path takes over.\n if (allSuppressed && !this._turnSelfCorrected) {\n this._turnSelfCorrected = true;\n this.replaceTailAssistantMessage(\n buildAssistantMessage(\n assistantContent,\n toolCalls,\n this.modelForCurrentCall(),\n reasoningContent,\n ),\n );\n for (const call of toolCalls) {\n this.appendAndPersist({\n role: \"tool\",\n tool_call_id: call.id ?? \"\",\n name: call.function?.name ?? \"\",\n content:\n \"[repeat-loop guard] this call was suppressed because it was identical to a previous call in this turn. Earlier results for it are above — try a meaningfully different approach, or stop and answer if you have enough.\",\n });\n }\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.repeatToolCallWarning\"),\n };\n continue;\n }\n\n if (report.stormsBroken > 0) {\n const noteTail = report.notes.length ? ` — ${report.notes[report.notes.length - 1]}` : \"\";\n const phrase = allSuppressed\n ? t(\"loop.stormStuck\")\n : t(\"loop.stormSuppressed\", { count: report.stormsBroken });\n yield {\n turn: this._turn,\n role: \"warning\",\n content: `${phrase}${noteTail}`,\n };\n }\n\n if (repairedCalls.length === 0) {\n if (allSuppressed) {\n yield* forceSummaryAfterIterLimit(this.summaryContext(), { reason: \"stuck\" });\n return;\n }\n yield { turn: this._turn, role: \"done\", content: assistantContent };\n return;\n }\n\n // Context-management decision after each turn's response.\n // ContextManager owns the policy; loop renders the events.\n const decision = this.context.decideAfterUsage(usage, this.model, this._foldedThisTurn);\n if (decision.kind === \"fold\") {\n this._foldedThisTurn = true;\n const before = decision.promptTokens;\n const ctxMax = decision.ctxMax;\n const aggressiveTag = decision.aggressive ? t(\"loop.aggressiveTag\") : \"\";\n yield {\n turn: this._turn,\n role: \"status\",\n content: t(\"loop.compactingHistoryStatus\", { aggressiveTag }),\n };\n const result = await this.compactHistory({ keepRecentTokens: decision.tailBudget });\n if (result.folded) {\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\n decision.aggressive ? \"loop.aggressivelyFoldedHistory\" : \"loop.foldedHistory\",\n {\n before: before.toLocaleString(),\n ctxMax: ctxMax.toLocaleString(),\n pct: Math.round((before / ctxMax) * 100),\n beforeMessages: result.beforeMessages,\n afterMessages: result.afterMessages,\n summaryChars: result.summaryChars,\n },\n ),\n };\n }\n } else if (decision.kind === \"exit-with-summary\") {\n const before = decision.promptTokens;\n const ctxMax = decision.ctxMax;\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.forcingSummary\", {\n before: before.toLocaleString(),\n ctxMax: ctxMax.toLocaleString(),\n pct: Math.round((before / ctxMax) * 100),\n }),\n };\n this.context.trimTrailingToolCalls();\n yield* forceSummaryAfterIterLimit(this.summaryContext(), { reason: \"context-guard\" });\n return;\n }\n\n const dispatchSerial =\n (process.env.REASONIX_TOOL_DISPATCH ?? \"auto\").toLowerCase() === \"serial\";\n const parallelMaxParsed = Number.parseInt(process.env.REASONIX_PARALLEL_MAX ?? \"\", 10);\n const parallelMax =\n Number.isFinite(parallelMaxParsed) && parallelMaxParsed >= 1\n ? Math.min(parallelMaxParsed, 16)\n : 3;\n\n let callIdx = 0;\n while (callIdx < repairedCalls.length) {\n // Group consecutive parallel-safe calls; an unsafe call breaks\n // the chunk and runs alone (serial barrier).\n const chunk: ToolCall[] = [];\n if (!dispatchSerial) {\n while (\n callIdx < repairedCalls.length &&\n chunk.length < parallelMax &&\n this.tools.isParallelSafe(repairedCalls[callIdx]?.function?.name ?? \"\")\n ) {\n chunk.push(repairedCalls[callIdx++]!);\n }\n }\n if (chunk.length === 0) {\n chunk.push(repairedCalls[callIdx++]!);\n }\n\n // tool_start announces every call in the chunk BEFORE any\n // dispatch awaits — TUI shows live indicators for each, and the\n // gap between assistant_final and the first tool_result yield is\n // never silent. Pre-add to the inflight set so the spinner is\n // already correct on the very first card render — runOneToolCall's\n // own add is then idempotent and its finally is the cleanup contract.\n for (const call of chunk) {\n const callId = this.inflightIdFor(call);\n this._inflight.add(callId);\n yield {\n turn: this._turn,\n role: \"tool_start\",\n content: \"\",\n toolName: call.function?.name ?? \"\",\n toolArgs: call.function?.arguments ?? \"{}\",\n callId,\n };\n }\n\n // Race the chunk; collect outcomes in declared order so history\n // append + tool yields are deterministic regardless of which\n // call settles first.\n const settled = await Promise.allSettled(chunk.map((c) => this.runOneToolCall(c, signal)));\n\n for (let k = 0; k < chunk.length; k++) {\n const call = chunk[k]!;\n const name = call.function?.name ?? \"\";\n const args = call.function?.arguments ?? \"{}\";\n const s = settled[k]!;\n\n let result: string;\n let preWarnings: LoopEvent[] = [];\n let postWarnings: LoopEvent[] = [];\n if (s.status === \"fulfilled\") {\n preWarnings = s.value.preWarnings;\n postWarnings = s.value.postWarnings;\n result = s.value.result;\n } else {\n const err = s.reason instanceof Error ? s.reason : new Error(String(s.reason));\n result = JSON.stringify({ error: `${err.name}: ${err.message}` });\n }\n\n for (const w of preWarnings) yield w;\n for (const w of postWarnings) yield w;\n\n this.appendAndPersist({\n role: \"tool\",\n tool_call_id: call.id ?? \"\",\n name,\n content: result,\n });\n\n if (this.noteToolFailureSignal(result)) {\n yield {\n turn: this._turn,\n role: \"warning\",\n content: t(\"loop.autoEscalation\", {\n model: ESCALATION_MODEL,\n breakdown: this._turnFailures.formatBreakdown(),\n fallback: this.model,\n }),\n };\n }\n\n yield {\n turn: this._turn,\n role: \"tool\",\n content: result,\n toolName: name,\n toolArgs: args,\n callId: this.inflightIdFor(call),\n };\n }\n }\n }\n\n // We exhausted the tool-call budget while the model still wanted to\n // call more tools. Rather than stopping silently (which leaves the\n // user staring at a blank prompt), force one final no-tools call so\n // the model must produce a text summary from everything it has\n // already seen.\n yield* forceSummaryAfterIterLimit(this.summaryContext(), { reason: \"budget\" });\n }\n\n private summaryContext(): ForceSummaryContext {\n return {\n client: this.client,\n signal: this._turnAbort.signal,\n buildMessages: () => this.buildMessages(null),\n appendAndPersist: (m) => this.appendAndPersist(m),\n recordStats: (model, usage) => this.stats.record(this._turn, model, usage),\n turn: this._turn,\n maxToolIters: this.maxToolIters,\n };\n }\n\n async run(userInput: string, onEvent?: (ev: LoopEvent) => void): Promise<string> {\n let final = \"\";\n for await (const ev of this.step(userInput)) {\n onEvent?.(ev);\n if (ev.role === \"assistant_final\") final = ev.content;\n if (ev.role === \"done\") break;\n }\n return final;\n }\n}\n\nfunction parsePositiveIntEnv(raw: string | undefined): number | undefined {\n if (!raw) return undefined;\n const n = Number.parseInt(raw, 10);\n return Number.isFinite(n) && n > 0 ? n : undefined;\n}\n","/** Native FS tools — sandbox enforced here, not delegated. `edit_file` takes a single SEARCH/REPLACE string. */\n\nimport { promises as fs } from \"node:fs\";\nimport * as pathMod from \"node:path\";\nimport picomatch from \"picomatch\";\nimport { DEFAULT_INDEX_EXCLUDES } from \"../index/config.js\";\nimport type { ToolRegistry } from \"../tools.js\";\nimport { applyEdit, applyMultiEdit } from \"./fs/edit.js\";\nimport { globFiles } from \"./fs/glob.js\";\nimport { searchContent, searchFiles } from \"./fs/search.js\";\n\nexport { lineDiff } from \"./fs/edit.js\";\n\nexport interface FilesystemToolsOptions {\n /** Absolute directory the tools may read/write. Paths outside this are refused. */\n rootDir: string;\n /** false → register only read-side tools. Default true. */\n allowWriting?: boolean;\n /** Per-read byte cap; floor against OOM on a multi-GB blob. */\n maxReadBytes?: number;\n /** Cap on total bytes from listing/grep tools — bounds tree-as-one-string accidents. */\n maxListBytes?: number;\n}\n\nconst DEFAULT_MAX_READ_BYTES = 2 * 1024 * 1024;\nconst DEFAULT_MAX_LIST_BYTES = 256 * 1024;\n\n/** Auto-preview threshold — files above this force the model to scope (range/head/tail). */\nconst DEFAULT_AUTO_PREVIEW_LINES = 200;\nconst AUTO_PREVIEW_HEAD_LINES = 80;\nconst AUTO_PREVIEW_TAIL_LINES = 40;\nconst OUTLINE_MAX_ENTRIES = 30;\nconst OUTLINE_TAIL_KEEP = 5;\n\ntype OutlineEntry = { line: number; kind: string; name: string };\n\nconst TS_EXPORT_RE =\n /^export\\s+(?:default\\s+)?(?:async\\s+)?(function|class|const|let|var|interface|type|enum)\\s+\\*?\\s*(\\w+)/;\n\nfunction extractTsExportOutline(lines: readonly string[]): OutlineEntry[] {\n const out: OutlineEntry[] = [];\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n if (!line.startsWith(\"export \")) continue;\n const m = TS_EXPORT_RE.exec(line);\n if (!m) continue;\n out.push({ line: i + 1, kind: m[1]!, name: m[2]! });\n }\n return out;\n}\n\nfunction formatOutline(entries: readonly OutlineEntry[]): string {\n const total = entries.length;\n if (total === 0) return \"\";\n const lastEntry = entries[total - 1]!;\n const width = String(lastEntry.line).length;\n const fmt = (e: OutlineEntry) =>\n ` L${String(e.line).padStart(width, \" \")} export ${e.kind} ${e.name}`;\n const header = `[outline: ${total} top-level export${total === 1 ? \"\" : \"s\"}]`;\n if (total <= OUTLINE_MAX_ENTRIES) {\n return [header, ...entries.map(fmt)].join(\"\\n\");\n }\n const headCount = OUTLINE_MAX_ENTRIES - OUTLINE_TAIL_KEEP;\n const headEntries = entries.slice(0, headCount);\n const tailEntries = entries.slice(-OUTLINE_TAIL_KEEP);\n const omitted = total - OUTLINE_MAX_ENTRIES;\n const gapStart = headEntries[headEntries.length - 1]!.line;\n const gapEnd = tailEntries[0]!.line;\n return [\n header,\n ...headEntries.map(fmt),\n ` [… ${omitted} more export${omitted === 1 ? \"\" : \"s\"} between L${gapStart} and L${gapEnd} …]`,\n ...tailEntries.map(fmt),\n ].join(\"\\n\");\n}\n\n/** Skipped unless `include_deps:true` — shared with the semantic indexer via DEFAULT_INDEX_EXCLUDES. */\nconst SKIP_DIR_NAMES: ReadonlySet<string> = new Set(DEFAULT_INDEX_EXCLUDES.dirs);\n\n/** First line of binary defense; NUL-byte sniff is the second (catches mislabeled `.txt`). */\nconst BINARY_EXTENSIONS: ReadonlySet<string> = new Set(DEFAULT_INDEX_EXCLUDES.exts);\n\nexport function displayRel(rootDir: string, full: string): string {\n return pathMod.relative(rootDir, full).replaceAll(\"\\\\\", \"/\");\n}\n\nconst GLOB_METACHARS = /[*?{[]/;\n\n/** Glob via picomatch when metachars present, else case-insensitive substring — keeps `.ts` / `test` callers working. Slash in pattern → match rel-path; otherwise basename. */\nexport function compileNameFilter(\n filter: string | null | undefined,\n): ((name: string, rel: string) => boolean) | null {\n if (!filter) return null;\n if (!GLOB_METACHARS.test(filter)) {\n const needle = filter.toLowerCase();\n return (name) => name.toLowerCase().includes(needle);\n }\n const matchPath = filter.includes(\"/\");\n const isMatch = picomatch(filter, { dot: true, nocase: true });\n return matchPath ? (_n, rel) => isMatch(rel) : (name) => isMatch(name);\n}\n\nfunction isLikelyBinaryByName(name: string): boolean {\n const dot = name.lastIndexOf(\".\");\n if (dot < 0) return false;\n return BINARY_EXTENSIONS.has(name.slice(dot).toLowerCase());\n}\n\nexport function registerFilesystemTools(\n registry: ToolRegistry,\n opts: FilesystemToolsOptions,\n): ToolRegistry {\n const rootDir = pathMod.resolve(opts.rootDir);\n const allowWriting = opts.allowWriting !== false;\n const maxReadBytes = opts.maxReadBytes ?? DEFAULT_MAX_READ_BYTES;\n const maxListBytes = opts.maxListBytes ?? DEFAULT_MAX_LIST_BYTES;\n\n /** Resolve path, enforce it's under rootDir, return absolute. */\n const safePath = (raw: unknown): string => {\n if (typeof raw !== \"string\" || raw.length === 0) {\n throw new Error(\"path must be a non-empty string\");\n }\n // Sandbox-root semantics: a leading POSIX-style `/` (or `\\` on\n // Windows) means \"from the project root\", not \"from the filesystem\n // root\". Models routinely write `path: \"/\"` or `path: \"/src/foo.ts\"`\n // intending the sandbox root — without this normalization,\n // path.resolve interprets `/` as the actual drive root (`F:\\` on\n // Windows, `/` on POSIX) and the escape check rightly rejects it,\n // confusing the model. Strip leading separators so the rest of the\n // resolution treats the input as relative to rootDir. Drive-letter\n // absolutes (`C:\\foo`) and Unix absolutes outside rootDir still\n // get caught by the relative-escape check below.\n let normalized = raw;\n while (normalized.startsWith(\"/\") || normalized.startsWith(\"\\\\\")) {\n normalized = normalized.slice(1);\n }\n if (normalized.length === 0) normalized = \".\";\n const resolved = pathMod.resolve(rootDir, normalized);\n const normRoot = pathMod.resolve(rootDir);\n // Use relative() to catch any `..` segments that escape.\n const rel = pathMod.relative(normRoot, resolved);\n if (rel.startsWith(\"..\") || pathMod.isAbsolute(rel)) {\n throw new Error(\n `path escapes sandbox root (${normRoot}): ${raw} — workspace is pinned at launch; quit and relaunch with \\`reasonix code --dir <path>\\` to work in a different folder`,\n );\n }\n return resolved;\n };\n\n registry.register({\n name: \"read_file\",\n parallelSafe: true,\n description: `Read a file under the sandbox root. To save context, PREFER to scope the read instead of pulling the whole file:\n - head: N → first N lines (imports, public API, small configs)\n - tail: N → last N lines (recently-added code, log tails)\n - range: \"A-B\" → inclusive line range A..B, 1-indexed (e.g. \"120-180\" around an edit site)\nWhen none of these is given AND the file is longer than ${DEFAULT_AUTO_PREVIEW_LINES} lines, the tool auto-returns a head+tail preview with an \"N lines omitted\" marker, plus a top-level export outline (function / class / const / interface / type / enum names with line numbers, capped at ${OUTLINE_MAX_ENTRIES}) so you can pick a smart range without a follow-up grep. If you need the middle, re-call with a range. Prefer search_content to locate a symbol first only when the outline doesn't have what you want — one scoped read beats three full-file reads.`,\n readOnly: true,\n stormExempt: true,\n parameters: {\n type: \"object\",\n properties: {\n path: { type: \"string\", description: \"Path to read (relative to rootDir or absolute).\" },\n head: { type: \"integer\", description: \"If set, return only the first N lines.\" },\n tail: { type: \"integer\", description: \"If set, return only the last N lines.\" },\n range: {\n type: \"string\",\n description:\n 'Inclusive line range like \"50-100\" or \"50-50\". 1-indexed. Takes precedence over head/tail when all three are set. Out-of-range requests clamp to file bounds.',\n },\n },\n required: [\"path\"],\n },\n fn: async (args: { path: string; head?: number; tail?: number; range?: string }) => {\n const abs = safePath(args.path);\n // Open once and reuse the fd so the directory check and the read\n // bind to the same inode — closes the stat→read TOCTOU race.\n const fh = await fs.open(abs, \"r\");\n let raw: Buffer;\n try {\n const stat = await fh.stat();\n if (stat.isDirectory()) {\n throw new Error(`not a file: ${args.path} (it's a directory)`);\n }\n raw = await fh.readFile();\n } finally {\n await fh.close();\n }\n if (raw.length > maxReadBytes) {\n const headBytes = raw.slice(0, maxReadBytes).toString(\"utf8\");\n return `${headBytes}\\n\\n[…truncated ${raw.length - maxReadBytes} bytes — file is ${raw.length} B, cap ${maxReadBytes} B. Retry with head/tail/range for targeted view.]`;\n }\n const text = raw.toString(\"utf8\");\n let lines = text.split(/\\r?\\n/);\n // Most files end with '\\n' which splits into an empty trailing\n // entry; drop it so head/tail/range counts match the user's\n // visible line numbers in an editor.\n if (lines.length > 0 && lines[lines.length - 1] === \"\") lines = lines.slice(0, -1);\n const totalLines = lines.length;\n\n // range wins over head/tail when set — the most precise ask\n // should dominate. Parse \"A-B\" strictly; bad formats fall through\n // to head/tail / auto-preview instead of erroring.\n if (typeof args.range === \"string\" && /^\\d+\\s*-\\s*\\d+$/.test(args.range)) {\n const [rawStart, rawEnd] = args.range.split(\"-\").map((s) => Number.parseInt(s, 10));\n const start = Math.max(1, rawStart ?? 1);\n const end = Math.min(totalLines, Math.max(start, rawEnd ?? totalLines));\n const slice = lines.slice(start - 1, end);\n const label = `[range ${start}-${end} of ${totalLines} lines]`;\n return `${label}\\n${slice.join(\"\\n\")}`;\n }\n if (typeof args.head === \"number\" && args.head > 0) {\n const count = Math.min(args.head, totalLines);\n const slice = lines.slice(0, count);\n const marker =\n count < totalLines\n ? `\\n\\n[…head ${count} of ${totalLines} lines — call again with range / tail for more]`\n : \"\";\n return slice.join(\"\\n\") + marker;\n }\n if (typeof args.tail === \"number\" && args.tail > 0) {\n const count = Math.min(args.tail, totalLines);\n const slice = lines.slice(totalLines - count);\n const marker =\n count < totalLines\n ? `[…tail ${count} of ${totalLines} lines — call again with range / head for more]\\n\\n`\n : \"\";\n return marker + slice.join(\"\\n\");\n }\n\n // No explicit scope + file is small → full content.\n if (totalLines <= DEFAULT_AUTO_PREVIEW_LINES) return lines.join(\"\\n\");\n\n // No explicit scope + file is large → head + tail preview plus\n // a marker telling the model how much it missed and how to get\n // it. This is the single biggest lever on read_file token cost —\n // historically a 500-line file dumped ~4K tokens into the turn\n // even when the model only needed 20 of them.\n const head = lines.slice(0, AUTO_PREVIEW_HEAD_LINES).join(\"\\n\");\n const tail = lines.slice(totalLines - AUTO_PREVIEW_TAIL_LINES).join(\"\\n\");\n const omitted = totalLines - AUTO_PREVIEW_HEAD_LINES - AUTO_PREVIEW_TAIL_LINES;\n const outline = formatOutline(extractTsExportOutline(lines));\n const parts: string[] = [\n `[auto-preview: head ${AUTO_PREVIEW_HEAD_LINES} + tail ${AUTO_PREVIEW_TAIL_LINES} of ${totalLines} lines]`,\n head,\n ];\n if (outline) parts.push(\"\", outline);\n parts.push(\n `\\n[… ${omitted} lines omitted — call read_file again with range:\"A-B\" (1-indexed) or head / tail to get the middle]\\n`,\n tail,\n );\n return parts.join(\"\\n\");\n },\n });\n\n registry.register({\n name: \"list_directory\",\n parallelSafe: true,\n description:\n \"List entries in a directory under the sandbox root. Returns one line per entry, marking directories with a trailing slash. Not recursive — use directory_tree for that.\",\n readOnly: true,\n stormExempt: true,\n parameters: {\n type: \"object\",\n properties: {\n path: { type: \"string\", description: \"Directory to list (default: root).\" },\n },\n },\n fn: async (args: { path?: string }) => {\n const abs = safePath(args.path ?? \".\");\n const entries = await fs.readdir(abs, { withFileTypes: true });\n const lines: string[] = [];\n for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n lines.push(e.isDirectory() ? `${e.name}/` : e.name);\n }\n return lines.join(\"\\n\") || \"(empty directory)\";\n },\n });\n\n registry.register({\n name: \"directory_tree\",\n parallelSafe: true,\n description: `Recursively list entries in a directory. Shows indented tree structure with directories marked '/'. Budget-aware by default:\n - maxDepth defaults to 2 (root + one level). A depth-4 tree on a real repo blew ~5K tokens in one call. If you truly need deeper, pass maxDepth:N explicitly.\n - Skips ${[...SKIP_DIR_NAMES].sort().join(\", \")} unless include_deps:true. Traversing into node_modules / .git / dist is almost always token-waste.\n - Large subtrees (>50 children) auto-collapse to \"[N files, M dirs hidden — list_directory <path> to inspect]\" so one huge folder can't dominate the output.\nPrefer \\`list_directory\\` for a single-level view, \\`search_files\\` to find specific paths, and \\`search_content\\` to find code.`,\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n path: { type: \"string\", description: \"Root of the tree (default: sandbox root).\" },\n maxDepth: {\n type: \"integer\",\n description:\n \"Max recursion depth (default 2). Depth 0 shows only the top-level entries; depth 2 is usually enough to see module structure.\",\n },\n include_deps: {\n type: \"boolean\",\n description:\n \"When true, also traverse node_modules / .git / dist / build / etc. Off by default — most exploration questions are about the user's own code.\",\n },\n },\n },\n fn: async (args: { path?: string; maxDepth?: number; include_deps?: boolean }) => {\n const startAbs = safePath(args.path ?? \".\");\n const maxDepth = typeof args.maxDepth === \"number\" ? args.maxDepth : 2;\n const includeDeps = args.include_deps === true;\n const lines: string[] = [];\n let totalBytes = 0;\n let truncated = false;\n // Per-directory child cap — long fixture / asset folders (200+\n // snapshots) would otherwise dominate; the collapse keeps the\n // overall shape visible. Modest: normal source dirs have <50\n // entries.\n const PER_DIR_CHILD_CAP = 50;\n const walk = async (dir: string, depth: number): Promise<void> => {\n if (truncated) return;\n if (depth > maxDepth) return;\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n entries.sort((a, b) => a.name.localeCompare(b.name));\n let emitted = 0;\n for (const e of entries) {\n if (truncated) return;\n // Dep-skip applies only to DIRECTORIES (a file named\n // \"node_modules\" is fine to list). Anything in the skip set\n // still shows up as a single node with a trailing \" (skipped)\"\n // hint so the model knows the dir exists but wasn't walked.\n const skip = e.isDirectory() && !includeDeps && SKIP_DIR_NAMES.has(e.name);\n if (emitted >= PER_DIR_CHILD_CAP) {\n const remaining = entries.length - emitted;\n let restFiles = 0;\n let restDirs = 0;\n for (const r of entries.slice(emitted)) {\n if (r.isDirectory()) restDirs++;\n else restFiles++;\n }\n const indent = \" \".repeat(depth);\n lines.push(\n `${indent}[… ${remaining} entries hidden (${restDirs} dirs, ${restFiles} files) — list_directory on this path to see all]`,\n );\n return;\n }\n const indent = \" \".repeat(depth);\n const suffix = skip ? \" (skipped — pass include_deps:true to traverse)\" : \"\";\n const line = e.isDirectory() ? `${indent}${e.name}/${suffix}` : `${indent}${e.name}`;\n totalBytes += line.length + 1;\n if (totalBytes > maxListBytes) {\n lines.push(` [… tree truncated at ${maxListBytes} bytes …]`);\n truncated = true;\n return;\n }\n lines.push(line);\n emitted++;\n if (e.isDirectory() && !skip) {\n await walk(pathMod.join(dir, e.name), depth + 1);\n }\n }\n };\n await walk(startAbs, 0);\n return lines.join(\"\\n\") || \"(empty tree)\";\n },\n });\n\n registry.register({\n name: \"search_files\",\n parallelSafe: true,\n description:\n \"Find files whose NAME matches a substring or regex. Case-insensitive. Walks the directory recursively under the sandbox root. Returns one path per line. Skips dependency / VCS / build directories (node_modules, .git, dist, build, .next, target, .venv) by default.\",\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n path: { type: \"string\", description: \"Directory to start the search at (default: root).\" },\n pattern: {\n type: \"string\",\n description: \"Substring (or regex) to match against filenames.\",\n },\n include_deps: {\n type: \"boolean\",\n description:\n \"When true, also walk node_modules / .git / dist / build / etc. Off by default — most filename searches are about the user's own code.\",\n },\n },\n required: [\"pattern\"],\n },\n fn: async (args: { path?: string; pattern: string; include_deps?: boolean }, toolCtx) =>\n searchFiles(\n { rootDir, maxListBytes, skipDirNames: SKIP_DIR_NAMES },\n safePath(args.path ?? \".\"),\n { ...args, signal: toolCtx?.signal },\n ),\n });\n\n registry.register({\n name: \"search_content\",\n parallelSafe: true,\n description:\n \"Recursively grep file CONTENTS for a substring or regex. This is the right tool for 'find all places that call X', 'where is Y referenced', 'what files contain Z'. Different from search_files (which matches FILE NAMES). Returns one match per line in 'path:line: text' format. Per-file hits are capped at 30 (a footer reports any extras); when the byte budget is mostly spent the remaining files switch to a 'rel: N matches' histogram so distribution stays visible instead of one popular file drowning the rest. Pass `summary_only:true` to skip line content entirely and get just the histogram. Skips dependency / VCS / build directories (node_modules, .git, dist, build, .next, target, .venv) and binary files by default.\",\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n pattern: {\n type: \"string\",\n description: \"Substring (or regex) to search file contents for.\",\n },\n path: {\n type: \"string\",\n description: \"Directory to start the search at (default: sandbox root).\",\n },\n glob: {\n type: \"string\",\n description:\n \"Optional filename filter. Real glob when the value contains `*`, `?`, `{`, or `[` — e.g. '*.ts', '**/*.tsx', 'src/**/*.{ts,tsx}'. Plain substring otherwise — e.g. '.ts' (suffix), 'test' (anywhere in the name). Patterns containing `/` match against the path relative to the search root; otherwise just the basename.\",\n },\n case_sensitive: {\n type: \"boolean\",\n description: \"When true, match case exactly. Default false (case-insensitive).\",\n },\n include_deps: {\n type: \"boolean\",\n description:\n \"When true, also search inside node_modules / .git / dist / build / etc. Off by default — most exploration questions are about the user's own code.\",\n },\n context: {\n type: \"integer\",\n description:\n \"Lines of context to show around each match (both before and after). Default 0 (just the matching line). Capped at 20. Output uses ripgrep style: `:` after the line number on the matching line, `-` on context lines, `--` separating non-adjacent windows.\",\n },\n summary_only: {\n type: \"boolean\",\n description:\n \"When true, skip line content and return one 'rel: N matches' line per matching file. Use for 'where does this exist at all' questions before drilling in with a targeted read_file.\",\n },\n },\n required: [\"pattern\"],\n },\n fn: async (\n args: {\n pattern: string;\n path?: string;\n glob?: string;\n case_sensitive?: boolean;\n include_deps?: boolean;\n context?: number;\n summary_only?: boolean;\n },\n toolCtx,\n ) =>\n searchContent(\n {\n rootDir,\n maxListBytes,\n skipDirNames: SKIP_DIR_NAMES,\n isBinaryByName: isLikelyBinaryByName,\n nameMatch: compileNameFilter(typeof args.glob === \"string\" ? args.glob : null),\n },\n safePath(args.path ?? \".\"),\n { ...args, signal: toolCtx?.signal },\n ),\n });\n\n registry.register({\n name: \"glob\",\n parallelSafe: true,\n description:\n \"List files matching a glob pattern, sorted by mtime (most-recently-modified first) by default. Use this for 'what changed lately', 'find all *.test.ts', 'all configs under src/'. Glob syntax matches the cross-tool standard: `*` (any chars in one segment), `**` (any segments), `?` (one char), `{a,b}` (alternation). Pattern matches against the path RELATIVE to the search root (e.g. 'src/**/*.ts' from project root). Skips node_modules / .git / dist / build / etc by default. Default limit 200; raise via `limit` (max 1000). Different from `search_files` (substring on basename) and `search_content` (matches inside file contents).\",\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n pattern: {\n type: \"string\",\n description: \"Glob pattern, e.g. 'src/**/*.ts', '**/*.{md,mdx}', 'tests/*.test.ts'.\",\n },\n path: {\n type: \"string\",\n description:\n \"Base directory to walk (default: sandbox root). The pattern matches relative to this path.\",\n },\n sort_by: {\n type: \"string\",\n enum: [\"mtime\", \"name\"],\n description:\n \"Sort order. 'mtime' (default) shows most-recently-modified first — useful for 'what did I change today'. 'name' is alphabetical.\",\n },\n include_deps: {\n type: \"boolean\",\n description:\n \"When true, also walk node_modules / .git / dist / build / etc. Off by default.\",\n },\n limit: {\n type: \"integer\",\n description: \"Cap on returned matches. Default 200; clamped to [1, 1000].\",\n },\n },\n required: [\"pattern\"],\n },\n fn: async (\n args: {\n pattern: string;\n path?: string;\n sort_by?: \"mtime\" | \"name\";\n include_deps?: boolean;\n limit?: number;\n },\n toolCtx,\n ) =>\n globFiles({ rootDir, skipDirNames: SKIP_DIR_NAMES }, safePath(args.path ?? \".\"), {\n ...args,\n signal: toolCtx?.signal,\n }),\n });\n\n registry.register({\n name: \"get_file_info\",\n parallelSafe: true,\n description:\n \"Stat a path under the sandbox root. Returns type (file|directory|symlink), size in bytes, mtime in ISO-8601.\",\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n path: { type: \"string\" },\n },\n required: [\"path\"],\n },\n fn: async (args: { path: string }) => {\n const abs = safePath(args.path);\n const st = await fs.lstat(abs);\n const type = st.isDirectory() ? \"directory\" : st.isSymbolicLink() ? \"symlink\" : \"file\";\n return JSON.stringify({\n type,\n size: st.size,\n mtime: st.mtime.toISOString(),\n });\n },\n });\n\n if (!allowWriting) return registry;\n\n registry.register({\n name: \"write_file\",\n description:\n \"Create or overwrite a file under the sandbox root with the given content. Parent directories are created as needed.\",\n parameters: {\n type: \"object\",\n properties: {\n path: { type: \"string\" },\n content: { type: \"string\" },\n },\n required: [\"path\", \"content\"],\n },\n fn: async (args: { path: string; content: string }) => {\n const abs = safePath(args.path);\n await fs.mkdir(pathMod.dirname(abs), { recursive: true });\n await fs.writeFile(abs, args.content, \"utf8\");\n return `wrote ${args.content.length} chars to ${displayRel(rootDir, abs)}`;\n },\n });\n\n registry.register({\n name: \"edit_file\",\n description:\n \"Apply a SEARCH/REPLACE edit to an existing file. `search` must match exactly (whitespace sensitive) — no regex. The match must be unique in the file; otherwise the edit is refused to avoid surprise rewrites.\",\n parameters: {\n type: \"object\",\n properties: {\n path: { type: \"string\" },\n search: { type: \"string\", description: \"Exact text to find (must be unique).\" },\n replace: { type: \"string\", description: \"Text to substitute in place of `search`.\" },\n },\n required: [\"path\", \"search\", \"replace\"],\n },\n fn: async (args: { path: string; search: string; replace: string }) =>\n applyEdit(rootDir, safePath(args.path), args),\n });\n\n registry.register({\n name: \"multi_edit\",\n description:\n \"Apply N SEARCH/REPLACE edits across ONE OR MORE files in a single atomic call. Edits run sequentially in array order; for edits that touch the same file, a later edit can match text inserted by an earlier one. If ANY edit fails (search not found, ambiguous match, empty search, file unreadable), NO files are written — atomic at the validation layer. Same per-edit rules as edit_file: `search` is exact text (whitespace sensitive, no regex) and must be unique in its target file at the moment that edit applies. Use this for renames spanning multiple files, cross-file refactors, or any batch where you'd otherwise loop edit_file.\",\n parameters: {\n type: \"object\",\n properties: {\n edits: {\n type: \"array\",\n description: \"Edits to apply in order. Length ≥ 1. Each edit names its own target file.\",\n items: {\n type: \"object\",\n properties: {\n path: {\n type: \"string\",\n description: \"File the edit targets (sandbox-relative or absolute).\",\n },\n search: {\n type: \"string\",\n description: \"Exact text to find (must be unique in the file).\",\n },\n replace: { type: \"string\", description: \"Text to substitute in place of `search`.\" },\n },\n required: [\"path\", \"search\", \"replace\"],\n },\n },\n },\n required: [\"edits\"],\n },\n fn: async (args: { edits: Array<{ path: string; search: string; replace: string }> }) => {\n const resolved = (args.edits ?? []).map((e) => ({\n abs: safePath(e?.path),\n search: e?.search,\n replace: e?.replace,\n }));\n return applyMultiEdit(rootDir, resolved);\n },\n });\n\n registry.register({\n name: \"create_directory\",\n description: \"Create a directory (and any missing parents) under the sandbox root.\",\n parameters: {\n type: \"object\",\n properties: { path: { type: \"string\" } },\n required: [\"path\"],\n },\n fn: async (args: { path: string }) => {\n const abs = safePath(args.path);\n await fs.mkdir(abs, { recursive: true });\n return `created ${displayRel(rootDir, abs)}/`;\n },\n });\n\n registry.register({\n name: \"move_file\",\n description: \"Rename/move a file or directory under the sandbox root.\",\n parameters: {\n type: \"object\",\n properties: {\n source: { type: \"string\" },\n destination: { type: \"string\" },\n },\n required: [\"source\", \"destination\"],\n },\n fn: async (args: { source: string; destination: string }) => {\n const src = safePath(args.source);\n const dst = safePath(args.destination);\n await fs.mkdir(pathMod.dirname(dst), { recursive: true });\n await fs.rename(src, dst);\n return `moved ${displayRel(rootDir, src)} → ${displayRel(rootDir, dst)}`;\n },\n });\n\n return registry;\n}\n","import { promises as fs } from \"node:fs\";\nimport * as pathMod from \"node:path\";\n\nfunction displayRel(rootDir: string, full: string): string {\n return pathMod.relative(rootDir, full).replaceAll(\"\\\\\", \"/\");\n}\n\nexport async function applyEdit(\n rootDir: string,\n abs: string,\n args: { search: string; replace: string },\n): Promise<string> {\n if (args.search.length === 0) {\n throw new Error(\"edit_file: search cannot be empty\");\n }\n const before = await fs.readFile(abs, \"utf8\");\n const le = before.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const adaptedSearch = args.search.replace(/\\r?\\n/g, le);\n const adaptedReplace = args.replace.replace(/\\r?\\n/g, le);\n const firstIdx = before.indexOf(adaptedSearch);\n if (firstIdx < 0) {\n throw new Error(`edit_file: search text not found in ${displayRel(rootDir, abs)}`);\n }\n const nextIdx = before.indexOf(adaptedSearch, firstIdx + 1);\n if (nextIdx >= 0) {\n throw new Error(\n `edit_file: search text appears multiple times in ${displayRel(rootDir, abs)} — include more context to disambiguate`,\n );\n }\n const after =\n before.slice(0, firstIdx) + adaptedReplace + before.slice(firstIdx + adaptedSearch.length);\n await fs.writeFile(abs, after, \"utf8\");\n const rel = displayRel(rootDir, abs);\n const header = `edited ${rel} (${adaptedSearch.length}→${adaptedReplace.length} chars)`;\n const startLine = before.slice(0, firstIdx).split(/\\r?\\n/).length;\n const diff = renderEditDiff(adaptedSearch, adaptedReplace, startLine);\n return `${header}\\n${diff}`;\n}\n\nexport interface MultiEditEntry {\n abs: string;\n search: string;\n replace: string;\n}\n\nexport async function applyMultiEdit(\n rootDir: string,\n edits: ReadonlyArray<MultiEditEntry>,\n): Promise<string> {\n if (edits.length === 0) {\n throw new Error(\"multi_edit: edits must contain at least one entry\");\n }\n type FileState = {\n buf: string;\n le: string;\n hunks: string[];\n deltaChars: number;\n touched: number;\n };\n const filesByPath = new Map<string, FileState>();\n\n for (let i = 0; i < edits.length; i++) {\n const e = edits[i]!;\n if (typeof e.abs !== \"string\" || e.abs.length === 0) {\n throw new Error(`multi_edit: edit #${i + 1} requires a string \\`path\\` (no edits applied)`);\n }\n if (typeof e.search !== \"string\") {\n throw new Error(`multi_edit: edit #${i + 1} requires a string \\`search\\` (no edits applied)`);\n }\n if (typeof e.replace !== \"string\") {\n throw new Error(\n `multi_edit: edit #${i + 1} requires a string \\`replace\\` (no edits applied)`,\n );\n }\n const rel = displayRel(rootDir, e.abs);\n if (e.search.length === 0) {\n throw new Error(\n `multi_edit: edit #${i + 1} (${rel}) search cannot be empty (no edits applied)`,\n );\n }\n let state = filesByPath.get(e.abs);\n if (!state) {\n let before: string;\n try {\n before = await fs.readFile(e.abs, \"utf8\");\n } catch (err) {\n throw new Error(\n `multi_edit: edit #${i + 1} cannot read ${rel}: ${(err as Error).message} (no edits applied)`,\n );\n }\n const le = before.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n state = { buf: before, le, hunks: [], deltaChars: 0, touched: 0 };\n filesByPath.set(e.abs, state);\n }\n const adaptedSearch = e.search.replace(/\\r?\\n/g, state.le);\n const adaptedReplace = e.replace.replace(/\\r?\\n/g, state.le);\n const firstIdx = state.buf.indexOf(adaptedSearch);\n if (firstIdx < 0) {\n throw new Error(\n `multi_edit: edit #${i + 1} search text not found in ${rel} — no edits applied (multi_edit is atomic)`,\n );\n }\n const nextIdx = state.buf.indexOf(adaptedSearch, firstIdx + 1);\n if (nextIdx >= 0) {\n throw new Error(\n `multi_edit: edit #${i + 1} search text appears multiple times in ${rel} — include more context to disambiguate (no edits applied)`,\n );\n }\n const startLine = state.buf.slice(0, firstIdx).split(/\\r?\\n/).length;\n state.buf =\n state.buf.slice(0, firstIdx) +\n adaptedReplace +\n state.buf.slice(firstIdx + adaptedSearch.length);\n state.hunks.push(`# ${rel}\\n${renderEditDiff(adaptedSearch, adaptedReplace, startLine)}`);\n state.deltaChars += adaptedReplace.length - adaptedSearch.length;\n state.touched++;\n }\n\n for (const [abs, state] of filesByPath) {\n await fs.writeFile(abs, state.buf, \"utf8\");\n }\n\n const fileCount = filesByPath.size;\n const editCount = edits.length;\n let totalDelta = 0;\n const allHunks: string[] = [];\n for (const state of filesByPath.values()) {\n totalDelta += state.deltaChars;\n allHunks.push(...state.hunks);\n }\n const sign = totalDelta >= 0 ? \"+\" : \"\";\n const editNoun = editCount === 1 ? \"edit\" : \"edits\";\n const fileNoun = fileCount === 1 ? \"file\" : \"files\";\n const header = `multi_edit: applied ${editCount} ${editNoun} across ${fileCount} ${fileNoun} (${sign}${totalDelta} chars)`;\n return `${header}\\n${allHunks.join(\"\\n\")}`;\n}\n\nfunction renderEditDiff(search: string, replace: string, startLine: number): string {\n const a = search.split(/\\r?\\n/);\n const b = replace.split(/\\r?\\n/);\n const diff = lineDiff(a, b);\n const hunk = `@@ -${startLine},${a.length} +${startLine},${b.length} @@`;\n const body = diff.map((d) => `${d.op === \" \" ? \" \" : d.op} ${d.line}`).join(\"\\n\");\n return `${hunk}\\n${body}`;\n}\n\nexport function lineDiff(\n a: readonly string[],\n b: readonly string[],\n): Array<{ op: \"-\" | \"+\" | \" \"; line: string }> {\n const n = a.length;\n const m = b.length;\n // dp[i][j] = LCS length of a[0..i) and b[0..j).\n const dp: number[][] = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));\n for (let i = 1; i <= n; i++) {\n for (let j = 1; j <= m; j++) {\n if (a[i - 1] === b[j - 1]) dp[i]![j] = dp[i - 1]![j - 1]! + 1;\n else dp[i]![j] = Math.max(dp[i - 1]![j]!, dp[i]![j - 1]!);\n }\n }\n // Backtrack to recover the op sequence.\n const out: Array<{ op: \"-\" | \"+\" | \" \"; line: string }> = [];\n let i = n;\n let j = m;\n while (i > 0 && j > 0) {\n if (a[i - 1] === b[j - 1]) {\n out.unshift({ op: \" \", line: a[i - 1]! });\n i--;\n j--;\n } else if ((dp[i - 1]![j] ?? 0) > (dp[i]![j - 1] ?? 0)) {\n out.unshift({ op: \"-\", line: a[i - 1]! });\n i--;\n } else {\n // Tie-break goes here (strictly less or equal): take the\n // insertion first during backtrack so the final forward order\n // renders removals BEFORE additions for a substitution —\n // matches git-diff convention of `- old / + new`.\n out.unshift({ op: \"+\", line: b[j - 1]! });\n j--;\n }\n }\n while (i > 0) {\n out.unshift({ op: \"-\", line: a[i - 1]! });\n i--;\n }\n while (j > 0) {\n out.unshift({ op: \"+\", line: b[j - 1]! });\n j--;\n }\n return out;\n}\n","import { promises as fs } from \"node:fs\";\nimport * as pathMod from \"node:path\";\nimport picomatch from \"picomatch\";\n\nexport interface GlobContext {\n rootDir: string;\n skipDirNames: ReadonlySet<string>;\n}\n\nfunction displayRel(rootDir: string, full: string): string {\n return pathMod.relative(rootDir, full).replaceAll(\"\\\\\", \"/\");\n}\n\nexport async function globFiles(\n ctx: GlobContext,\n startAbs: string,\n args: {\n pattern: string;\n sort_by?: \"mtime\" | \"name\";\n include_deps?: boolean;\n limit?: number;\n signal?: AbortSignal;\n },\n): Promise<string> {\n if (args.signal?.aborted) {\n throw new DOMException(\"glob aborted by user\", \"AbortError\");\n }\n const includeDeps = args.include_deps === true;\n const sortBy = args.sort_by ?? \"mtime\";\n const limit = Math.max(1, Math.min(1000, Math.floor(args.limit ?? 200)));\n const isMatch = picomatch(args.pattern, { dot: true, nocase: true });\n\n const hits: { rel: string; mtimeMs: number }[] = [];\n\n const walk = async (dir: string): Promise<void> => {\n if (args.signal?.aborted) {\n throw new DOMException(\"glob aborted by user\", \"AbortError\");\n }\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n const full = pathMod.join(dir, e.name);\n if (e.isDirectory()) {\n if (!includeDeps && ctx.skipDirNames.has(e.name)) continue;\n await walk(full);\n continue;\n }\n if (!e.isFile() && !e.isSymbolicLink()) continue;\n const rel = displayRel(ctx.rootDir, full);\n if (!isMatch(rel)) continue;\n let mtimeMs = 0;\n if (sortBy === \"mtime\") {\n try {\n const st = await fs.stat(full);\n mtimeMs = st.mtimeMs;\n } catch {\n continue;\n }\n }\n hits.push({ rel, mtimeMs });\n }\n };\n await walk(startAbs);\n\n if (hits.length === 0) return \"(no matches)\";\n if (sortBy === \"mtime\") hits.sort((a, b) => b.mtimeMs - a.mtimeMs);\n else hits.sort((a, b) => a.rel.localeCompare(b.rel));\n\n const truncated = hits.length > limit;\n const shown = hits.slice(0, limit);\n const lines = shown.map((h) => h.rel);\n if (truncated) {\n lines.push(\n `[… ${hits.length - limit} more matches — refine pattern or raise limit (max 1000) …]`,\n );\n }\n return lines.join(\"\\n\");\n}\n","import { promises as fs } from \"node:fs\";\nimport * as pathMod from \"node:path\";\n\nexport interface SearchContext {\n rootDir: string;\n maxListBytes: number;\n skipDirNames: ReadonlySet<string>;\n isBinaryByName: (name: string) => boolean;\n /** Pre-baked filename→regex/substring matcher; null when no glob filter. */\n nameMatch: ((name: string, rel: string) => boolean) | null;\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) return;\n throw new DOMException(\"search aborted by user\", \"AbortError\");\n}\n\nfunction displayRel(rootDir: string, full: string): string {\n return pathMod.relative(rootDir, full).replaceAll(\"\\\\\", \"/\");\n}\n\nexport async function searchFiles(\n ctx: Pick<SearchContext, \"rootDir\" | \"maxListBytes\" | \"skipDirNames\">,\n startAbs: string,\n args: { pattern: string; include_deps?: boolean; signal?: AbortSignal },\n): Promise<string> {\n throwIfAborted(args.signal);\n const needle = args.pattern.toLowerCase();\n const includeDeps = args.include_deps === true;\n let re: RegExp | null = null;\n try {\n re = new RegExp(args.pattern, \"i\");\n } catch {\n re = null;\n }\n const matches: string[] = [];\n let totalBytes = 0;\n const walk = async (dir: string): Promise<void> => {\n throwIfAborted(args.signal);\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n throwIfAborted(args.signal);\n const full = pathMod.join(dir, e.name);\n const lower = e.name.toLowerCase();\n const hit = re ? re.test(e.name) : lower.includes(needle);\n if (hit) {\n const rel = displayRel(ctx.rootDir, full);\n if (totalBytes + rel.length + 1 > ctx.maxListBytes) {\n matches.push(\"[… search truncated — refine pattern …]\");\n return;\n }\n matches.push(rel);\n totalBytes += rel.length + 1;\n }\n if (e.isDirectory()) {\n if (!includeDeps && ctx.skipDirNames.has(e.name)) continue;\n await walk(full);\n }\n }\n };\n await walk(startAbs);\n return matches.length === 0 ? \"(no matches)\" : matches.join(\"\\n\");\n}\n\n/** Per-file printed-hit cap; beyond this we emit a \"N more matches in this file\" footer. */\nconst MAX_HITS_PER_FILE = 30;\n/** Once printed bytes pass this fraction of the byte budget, remaining files switch to histogram. */\nconst SUMMARY_MODE_TRIGGER_RATIO = 0.8;\n\nexport async function searchContent(\n ctx: SearchContext,\n startAbs: string,\n args: {\n pattern: string;\n case_sensitive?: boolean;\n include_deps?: boolean;\n context?: number;\n /** Skip line content; return only \"rel: N matches\" per file. */\n summary_only?: boolean;\n signal?: AbortSignal;\n },\n): Promise<string> {\n throwIfAborted(args.signal);\n const caseSensitive = args.case_sensitive === true;\n const includeDeps = args.include_deps === true;\n const ctxLines = Math.max(0, Math.min(20, Math.floor(args.context ?? 0)));\n const summaryOnly = args.summary_only === true;\n let re: RegExp | null = null;\n try {\n re = new RegExp(args.pattern, caseSensitive ? \"\" : \"i\");\n } catch {\n re = null;\n }\n const needle = caseSensitive ? args.pattern : args.pattern.toLowerCase();\n const matches: string[] = [];\n let totalBytes = 0;\n let scanned = 0;\n let truncated = false;\n let summaryMode = summaryOnly;\n let summaryNoticeEmitted = false;\n const fileHitCounts = new Map<string, number>();\n\n const pushLine = (out: string): boolean => {\n if (totalBytes + out.length + 1 > ctx.maxListBytes) {\n matches.push(`[… truncated at ${ctx.maxListBytes} bytes — refine pattern or path …]`);\n truncated = true;\n return false;\n }\n matches.push(out);\n totalBytes += out.length + 1;\n return true;\n };\n\n const maybeEnterSummaryMode = (): void => {\n if (summaryMode) return;\n if (totalBytes <= SUMMARY_MODE_TRIGGER_RATIO * ctx.maxListBytes) return;\n summaryMode = true;\n if (!summaryNoticeEmitted) {\n const pct = Math.round((totalBytes / ctx.maxListBytes) * 100);\n pushLine(\n `[switching to summary mode — byte budget at ${pct}%; remaining files will report match counts only]`,\n );\n summaryNoticeEmitted = true;\n }\n };\n\n const walk = async (dir: string): Promise<void> => {\n if (truncated) return;\n throwIfAborted(args.signal);\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (truncated) return;\n throwIfAborted(args.signal);\n if (e.isDirectory()) {\n if (!includeDeps && ctx.skipDirNames.has(e.name)) continue;\n await walk(pathMod.join(dir, e.name));\n continue;\n }\n if (!e.isFile()) continue;\n const full = pathMod.join(dir, e.name);\n if (ctx.nameMatch && !ctx.nameMatch(e.name, displayRel(ctx.rootDir, full))) continue;\n if (ctx.isBinaryByName(e.name)) continue;\n let fh: import(\"node:fs/promises\").FileHandle;\n try {\n fh = await fs.open(full, \"r\");\n } catch {\n continue;\n }\n let raw: Buffer;\n try {\n throwIfAborted(args.signal);\n const st = await fh.stat();\n if (st.size > 2 * 1024 * 1024) {\n await fh.close();\n continue;\n }\n raw = await fh.readFile();\n } catch {\n await fh.close().catch(() => {});\n continue;\n }\n await fh.close();\n throwIfAborted(args.signal);\n const firstNul = raw.indexOf(0);\n if (firstNul !== -1 && firstNul < 8 * 1024) continue;\n const text = raw.toString(\"utf8\");\n const rel = displayRel(ctx.rootDir, full);\n const lines = text.split(/\\r?\\n/);\n const hits: number[] = [];\n for (let li = 0; li < lines.length; li++) {\n throwIfAborted(args.signal);\n const line = lines[li]!;\n const lineForCheck = caseSensitive ? line : line.toLowerCase();\n const hit = re ? re.test(line) : lineForCheck.includes(needle);\n if (hit) hits.push(li);\n }\n scanned++;\n if (hits.length === 0) continue;\n fileHitCounts.set(rel, hits.length);\n\n if (summaryMode) {\n if (!pushLine(`${rel}: ${hits.length} match${hits.length === 1 ? \"\" : \"es\"}`)) return;\n continue;\n }\n\n const printable = Math.min(hits.length, MAX_HITS_PER_FILE);\n const omittedFromFile = hits.length - printable;\n const printableHits = hits.slice(0, printable);\n\n if (ctxLines === 0) {\n for (const li of printableHits) {\n if (truncated) return;\n const line = lines[li]!;\n const display = line.length > 200 ? `${line.slice(0, 200)}…` : line;\n if (!pushLine(`${rel}:${li + 1}: ${display}`)) return;\n }\n } else {\n const hitSet = new Set(printableHits);\n let prevWindowEnd = -2;\n for (const li of printableHits) {\n if (truncated) return;\n const winStart = Math.max(0, li - ctxLines);\n const winEnd = Math.min(lines.length - 1, li + ctxLines);\n if (winStart > prevWindowEnd + 1 && prevWindowEnd >= 0) {\n if (!pushLine(\"--\")) return;\n }\n const realStart = winStart > prevWindowEnd + 1 ? winStart : prevWindowEnd + 1;\n for (let i = realStart; i <= winEnd; i++) {\n const line = lines[i]!;\n const display = line.length > 200 ? `${line.slice(0, 200)}…` : line;\n const sep = hitSet.has(i) ? \":\" : \"-\";\n if (!pushLine(`${rel}:${i + 1}${sep} ${display}`)) return;\n }\n prevWindowEnd = winEnd;\n }\n }\n\n if (omittedFromFile > 0) {\n if (\n !pushLine(\n `[${rel}: ${omittedFromFile} more match${omittedFromFile === 1 ? \"\" : \"es\"} in this file — re-grep with a tighter pattern or use read_file to see them]`,\n )\n )\n return;\n }\n\n maybeEnterSummaryMode();\n }\n };\n await walk(startAbs);\n if (matches.length === 0) {\n return scanned === 0\n ? \"(no files scanned — path empty or all files filtered out)\"\n : `(no matches across ${scanned} file${scanned === 1 ? \"\" : \"s\"})`;\n }\n return matches.join(\"\\n\");\n}\n","/** Writes are eager but the prefix is NOT re-loaded mid-session — keeps prompt-cache stable. */\n\nimport {\n type MemoryScope,\n MemoryStore,\n type MemoryType,\n sanitizeMemoryName,\n} from \"../memory/user.js\";\nimport type { ToolRegistry } from \"../tools.js\";\n\nexport interface MemoryToolsOptions {\n /** Sandbox root for the `project` scope. Omit for chat mode. */\n projectRoot?: string;\n /** Override `~/.reasonix` (tests). */\n homeDir?: string;\n}\n\nexport function registerMemoryTools(\n registry: ToolRegistry,\n opts: MemoryToolsOptions = {},\n): ToolRegistry {\n const store = new MemoryStore({ homeDir: opts.homeDir, projectRoot: opts.projectRoot });\n const hasProject = store.hasProjectScope();\n\n registry.register({\n name: \"remember\",\n description:\n \"Save a memory for future sessions. Use when the user states a preference, corrects your approach, shares a non-obvious fact about this project, or explicitly asks you to remember something. Don't remember transient task state — only things worth recalling next session. The memory is written now but won't re-load into the system prompt until the next `/new` or launch.\",\n parameters: {\n type: \"object\",\n properties: {\n type: {\n type: \"string\",\n enum: [\"user\", \"feedback\", \"project\", \"reference\"],\n description:\n \"'user' = role/skills/prefs; 'feedback' = corrections or confirmed approaches; 'project' = facts/decisions about the current work; 'reference' = pointers to external systems the user uses.\",\n },\n scope: {\n type: \"string\",\n enum: [\"global\", \"project\"],\n description:\n \"'global' = applies across every project (preferences, tooling); 'project' = scoped to the current sandbox (decisions, local facts). Only available in `reasonix code`.\",\n },\n name: {\n type: \"string\",\n description:\n \"filename-safe identifier, 3-40 chars, alnum + _ - . (no path separators, no leading dot).\",\n },\n description: {\n type: \"string\",\n description: \"One-line summary shown in MEMORY.md (under ~150 chars).\",\n },\n content: {\n type: \"string\",\n description:\n \"Full memory body in markdown. For feedback/project types, structure as: rule/fact, then **Why:** line, then **How to apply:** line.\",\n },\n },\n required: [\"type\", \"scope\", \"name\", \"description\", \"content\"],\n },\n fn: async (args: {\n type: MemoryType;\n scope: MemoryScope;\n name: string;\n description: string;\n content: string;\n }) => {\n if (args.scope === \"project\" && !hasProject) {\n return JSON.stringify({\n error:\n \"scope='project' is unavailable in this session (no sandbox root). Retry with scope='global', or ask the user to switch to `reasonix code` for project-scoped memory.\",\n });\n }\n try {\n const path = store.write({\n name: args.name,\n type: args.type,\n scope: args.scope,\n description: args.description,\n body: args.content,\n });\n const key = sanitizeMemoryName(args.name);\n // The return text is load-bearing: it's the ONLY thing keeping\n // the fact visible within the current session, because the\n // prefix isn't re-hashed mid-session (Pillar 1). R1 reads this\n // on its next turn — the wording is deliberately imperative so\n // it doesn't get ignored in favor of explore-first behavior.\n return [\n `✓ REMEMBERED (${args.scope}/${key}): ${args.description}`,\n \"\",\n \"TREAT THIS AS ESTABLISHED FACT for the rest of this session.\",\n \"The user just told you — don't re-explore the filesystem to re-derive it.\",\n `(Saved to ${path}; pins into the system prompt on next /new or launch.)`,\n ].join(\"\\n\");\n } catch (err) {\n return JSON.stringify({ error: `remember failed: ${(err as Error).message}` });\n }\n },\n });\n\n registry.register({\n name: \"forget\",\n description:\n \"Delete a memory file and remove it from MEMORY.md. Use when the user explicitly asks to forget something, or when a previously-remembered fact has become wrong. Irreversible — no tombstone.\",\n parameters: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Memory name (the identifier used in `remember`).\" },\n scope: { type: \"string\", enum: [\"global\", \"project\"] },\n },\n required: [\"name\", \"scope\"],\n },\n fn: async (args: { name: string; scope: MemoryScope }) => {\n if (args.scope === \"project\" && !hasProject) {\n return JSON.stringify({\n error: \"scope='project' is unavailable in this session (no sandbox root).\",\n });\n }\n try {\n const existed = store.delete(args.scope, args.name);\n return existed\n ? `forgot (${args.scope}/${sanitizeMemoryName(args.name)}). Re-load on next /new or launch.`\n : `no such memory: ${args.scope}/${args.name} (nothing to forget).`;\n } catch (err) {\n return JSON.stringify({ error: `forget failed: ${(err as Error).message}` });\n }\n },\n });\n\n registry.register({\n name: \"recall_memory\",\n description:\n \"Read the full body of a memory file when its MEMORY.md one-liner (already in the system prompt) isn't enough detail. Most of the time the index suffices — only call this when the user's question genuinely requires the full context.\",\n readOnly: true,\n parallelSafe: true,\n parameters: {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n scope: { type: \"string\", enum: [\"global\", \"project\"] },\n },\n required: [\"name\", \"scope\"],\n },\n fn: async (args: { name: string; scope: MemoryScope }) => {\n if (args.scope === \"project\" && !hasProject) {\n return JSON.stringify({\n error: \"scope='project' is unavailable in this session (no sandbox root).\",\n });\n }\n try {\n const entry = store.read(args.scope, args.name);\n return [\n `# ${entry.name} (${entry.scope}/${entry.type}, created ${entry.createdAt || \"?\"})`,\n entry.description ? `> ${entry.description}` : \"\",\n \"\",\n entry.body,\n ]\n .filter(Boolean)\n .join(\"\\n\");\n } catch (err) {\n return JSON.stringify({ error: `recall failed: ${(err as Error).message}` });\n }\n },\n });\n\n return registry;\n}\n","/** Branching primitive separate from submit_plan; throws ChoiceRequestedError so the TUI can mount a picker and the model stops. */\n\nimport { pauseGate } from \"../core/pause-gate.js\";\nimport type { ToolRegistry } from \"../tools.js\";\n\nexport interface ChoiceOption {\n id: string;\n title: string;\n summary?: string;\n}\n\nexport class ChoiceRequestedError extends Error {\n readonly question: string;\n readonly options: ChoiceOption[];\n readonly allowCustom: boolean;\n constructor(question: string, options: ChoiceOption[], allowCustom: boolean) {\n super(\n \"ChoiceRequestedError: choice submitted. STOP calling tools now — the TUI has shown the options to the user. Wait for their next message; it will either be 'user picked <id>' (carry on with that branch), 'user answered: <text>' (custom free-form reply; read and proceed), or 'user cancelled the choice' (drop the question and ask what they want instead). Don't call any tools in the meantime.\",\n );\n this.name = \"ChoiceRequestedError\";\n this.question = question;\n this.options = options;\n this.allowCustom = allowCustom;\n }\n\n toToolResult(): {\n error: string;\n question: string;\n options: ChoiceOption[];\n allowCustom: boolean;\n } {\n return {\n error: `${this.name}: ${this.message}`,\n question: this.question,\n options: this.options,\n allowCustom: this.allowCustom,\n };\n }\n}\n\nexport interface ChoiceToolOptions {\n onChoiceRequested?: (question: string, options: ChoiceOption[]) => void;\n}\n\nfunction sanitizeOptions(raw: unknown): ChoiceOption[] {\n if (!Array.isArray(raw)) return [];\n const out: ChoiceOption[] = [];\n const seen = new Set<string>();\n for (const entry of raw) {\n if (!entry || typeof entry !== \"object\") continue;\n const e = entry as Record<string, unknown>;\n const id = typeof e.id === \"string\" ? e.id.trim() : \"\";\n const title = typeof e.title === \"string\" ? e.title.trim() : \"\";\n if (!id || !title) continue;\n if (seen.has(id)) continue;\n seen.add(id);\n const summary = typeof e.summary === \"string\" ? e.summary.trim() || undefined : undefined;\n const opt: ChoiceOption = { id, title };\n if (summary) opt.summary = summary;\n out.push(opt);\n }\n return out;\n}\n\nexport function registerChoiceTool(\n registry: ToolRegistry,\n opts: ChoiceToolOptions = {},\n): ToolRegistry {\n registry.register({\n name: \"ask_choice\",\n description:\n \"Present 2–6 alternatives to the user. The principle: if the user is supposed to pick, the tool picks — you don't enumerate the choices as prose. Prose menus have no picker in this TUI, so the user gets a wall of text to scroll through and a letter to type, strictly worse than the magenta picker this tool renders. Call it whenever (a) the user has asked for options, (b) you've analyzed multiple approaches and the final call is theirs, or (c) it's a preference fork you can't resolve without them. Skip it when one option is clearly best (just do it, or submit_plan) or a free-form text answer fits (ask in prose). Keep option ids short and stable (A/B/C). Each option: title + optional summary. allowCustom=true when their real answer might not fit. Max 6 options — narrow first if more. A one-sentence lead-in before the call is fine; don't repeat the options in it.\",\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n question: {\n type: \"string\",\n description:\n \"The question to put in front of the user. One sentence. Don't repeat the options in the question text — the picker renders them separately.\",\n },\n options: {\n type: \"array\",\n description:\n \"2–4 alternatives. Each needs a stable id and a short title; summary is optional.\",\n items: {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"Short stable id (A, B, C, or option-1).\" },\n title: { type: \"string\", description: \"One-line title shown as the option label.\" },\n summary: {\n type: \"string\",\n description:\n \"Optional. A second dimmed line with more detail. Keep under ~80 chars.\",\n },\n },\n required: [\"id\", \"title\"],\n },\n },\n allowCustom: {\n type: \"boolean\",\n description:\n \"If true, the picker shows a 'Let me type my own answer' escape hatch. Default false. Turn on when the user's real answer might not fit any of your pre-defined options.\",\n },\n },\n required: [\"question\", \"options\"],\n },\n fn: async (args: { question: string; options: unknown; allowCustom?: boolean }, ctx) => {\n const question = (args?.question ?? \"\").trim();\n if (!question) {\n throw new Error(\n \"ask_choice: question is required — write one sentence explaining the decision.\",\n );\n }\n const options = sanitizeOptions(args?.options);\n if (options.length < 2) {\n throw new Error(\n \"ask_choice: need at least 2 well-formed options (each with a non-empty id and title). If you just need a text answer, ask the user in plain assistant text instead.\",\n );\n }\n if (options.length > 6) {\n throw new Error(\n \"ask_choice: too many options (max 6). If you really have this many branches, split into two sequential ask_choice calls or narrow down first.\",\n );\n }\n const allowCustom = args?.allowCustom === true;\n opts.onChoiceRequested?.(question, options);\n // Block until the user picks an option, types custom text, or cancels\n const verdict = await (ctx?.confirmationGate ?? pauseGate).ask({\n kind: \"choice\",\n payload: { question, options, allowCustom },\n });\n if (verdict.type === \"pick\") return `user picked: ${verdict.optionId}`;\n if (verdict.type === \"text\") return `user answered: ${verdict.text}`;\n return \"user cancelled the choice\";\n },\n });\n return registry;\n}\n","import { pauseGate } from \"../core/pause-gate.js\";\nimport type { ToolRegistry } from \"../tools.js\";\nimport { PlanProposedError, PlanRevisionProposedError } from \"./plan-errors.js\";\nimport type { PlanStep, PlanStepRisk, StepCompletion } from \"./plan-types.js\";\n\n// Tool descriptions (teaching prompts for the model). Edit here, not inline.\n\nconst SUBMIT_PLAN_DESCRIPTION =\n \"Submit ONE concrete plan you've already decided on. Use this for tasks that warrant a review gate — multi-file refactors, architecture changes, anything that would be expensive or confusing to undo. Skip it for small fixes (one-line typo, obvious bug with a clear fix) — just make the change. The user will either approve (you then implement it), ask for refinement, or cancel. If the user has already enabled /plan mode, writes are blocked at dispatch and you MUST use this. CRITICAL: do NOT use submit_plan to present alternative routes (A/B/C, option 1/2/3) for the user to pick from — the picker only exposes approve/refine/cancel, so a menu plan strands the user with no way to choose. For branching decisions, call `ask_choice` instead; only call submit_plan once the user has picked a direction and you have a single actionable plan. Write the plan as markdown with a one-line summary, a bulleted list of files to touch and what will change, and any risks or open questions. STRONGLY PREFERRED: pass `steps` — an array of {id, title, action, risk?} — so the UI renders a structured step list above the approval picker and tracks per-step progress. Use risk='high' for steps that touch prod data / break public APIs / are hard to undo; 'med' for non-trivial but reversible (multi-file edits, schema tweaks); 'low' for safe local work. After each step, call `mark_step_complete` so the user sees progress ticks.\";\n\nconst MARK_STEP_COMPLETE_DESCRIPTION =\n \"Mark one step of the approved plan as done. Call this after finishing each step, then immediately continue with the NEXT step — do not stop or wait for the user. The TUI updates the plan card's progress in place. After the FINAL step, write a brief reply summarizing what was done and end the turn. Pass the `stepId` from the plan's steps array, a short `result` (what you did), and optional `notes` for anything surprising (errors, scope changes, follow-ups). This tool doesn't change any files. Don't call it if the plan didn't include structured steps, and don't invent ids that weren't in the original plan.\";\n\nconst REVISE_PLAN_DESCRIPTION =\n \"Surgically replace the REMAINING steps of an in-flight plan. Call this when the user has given feedback at a checkpoint that warrants a structured plan change — skip a step, swap two steps, add a new step, change risk, etc. Pass: `reason` (one sentence why), `remainingSteps` (the new tail of the plan, replacing whatever steps haven't been done yet), and optional `summary` (updated one-line plan summary). Done steps are NEVER touched — keep them out of `remainingSteps`. The TUI shows a diff (removed in red, kept in gray, added in green) and the user accepts or rejects. Don't call this for trivial mid-step adjustments — just keep executing. Don't call submit_plan for revisions either — that resets the whole plan including completed steps. Use submit_plan only when the entire approach has changed; use revise_plan when the tail needs editing.\";\n\n// Reused by both submit_plan and revise_plan — the step list shape is\n// identical, only the outer wrapper differs. Deliberately NOT `as const`:\n// ToolRegistry's JSONSchema type expects mutable arrays.\nconst STEP_ITEM_SCHEMA = {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"Stable id, e.g. step-1.\" },\n title: { type: \"string\", description: \"Short imperative title.\" },\n action: { type: \"string\", description: \"One-sentence description of the concrete action.\" },\n risk: {\n type: \"string\",\n enum: [\"low\", \"med\", \"high\"],\n description:\n \"Self-assessed risk. 'high' = hard-to-undo / touches prod / breaks API; 'med' = non-trivial but reversible; 'low' = safe local work. The UI shows a colored dot per step so the user knows where to focus review. Omit if you're unsure.\",\n },\n },\n required: [\"id\", \"title\", \"action\"],\n};\n\n// Registration options\n\nexport interface PlanToolOptions {\n onPlanSubmitted?: (plan: string, steps?: PlanStep[]) => void;\n onStepCompleted?: (update: StepCompletion) => void;\n onPlanRevisionProposed?: (reason: string, remainingSteps: PlanStep[], summary?: string) => void;\n}\n\n// Arg sanitizers — defensive cleanup shared between submit_plan and revise_plan\n\nfunction sanitizeRisk(raw: unknown): PlanStepRisk | undefined {\n if (raw === \"low\" || raw === \"med\" || raw === \"high\") return raw;\n return undefined;\n}\n\nfunction sanitizeSteps(raw: unknown): PlanStep[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const steps: PlanStep[] = [];\n for (const entry of raw) {\n if (!entry || typeof entry !== \"object\") continue;\n const e = entry as Record<string, unknown>;\n const id = typeof e.id === \"string\" ? e.id.trim() : \"\";\n const title = typeof e.title === \"string\" ? e.title.trim() : \"\";\n const action = typeof e.action === \"string\" ? e.action.trim() : \"\";\n if (!id || !title || !action) continue;\n const step: PlanStep = { id, title, action };\n const risk = sanitizeRisk(e.risk);\n if (risk) step.risk = risk;\n steps.push(step);\n }\n return steps.length > 0 ? steps : undefined;\n}\n\n// Individual tool registrations — one per screen\n\nfunction registerSubmitPlan(registry: ToolRegistry, opts: PlanToolOptions): void {\n registry.register({\n name: \"submit_plan\",\n description: SUBMIT_PLAN_DESCRIPTION,\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n plan: {\n type: \"string\",\n description:\n \"Markdown-formatted plan. Lead with a one-sentence summary. Then a file-by-file breakdown of what you'll change and why. Flag any risks or open questions at the end so the user can weigh in before you start.\",\n },\n steps: {\n type: \"array\",\n description:\n \"Structured step list (strongly recommended). When provided, the UI renders a compact step list above the approval picker AND tracks per-step progress via `mark_step_complete`. Use stable ids (step-1, step-2, ...). Skip only for tiny one-step plans where the markdown body is enough.\",\n items: STEP_ITEM_SCHEMA,\n },\n summary: {\n type: \"string\",\n description:\n \"Optional. One-sentence human-friendly title for the plan, ~80 chars max. Surfaces in the PlanConfirm picker header and in /plans listings ('▸ refactor auth into signed tokens · 2/5 done'). Skip for trivial plans where the first line of the markdown body is already short and clear.\",\n },\n },\n required: [\"plan\"],\n },\n fn: async (args: { plan: string; steps?: unknown; summary?: string }, ctx) => {\n const plan = (args?.plan ?? \"\").trim();\n if (!plan) {\n throw new Error(\"submit_plan: empty plan — write a markdown plan and try again.\");\n }\n const steps = sanitizeSteps(args?.steps);\n const summary =\n typeof args?.summary === \"string\" ? args.summary.trim() || undefined : undefined;\n opts.onPlanSubmitted?.(plan, steps);\n // Block until the user approves, refines, or cancels\n const verdict = await (ctx?.confirmationGate ?? pauseGate).ask({\n kind: \"plan_proposed\",\n payload: { plan, steps, summary },\n });\n const fb = verdict.feedback?.trim();\n if (verdict.type === \"approve\") {\n return fb ? `plan approved. user's additional instructions: ${fb}` : \"plan approved\";\n }\n if (verdict.type === \"refine\") {\n throw new Error(fb ? `user requested refinement: ${fb}` : \"user requested refinement\");\n }\n throw new Error(fb ? `plan cancelled: ${fb}` : \"plan cancelled\");\n },\n });\n}\n\nfunction registerMarkStepComplete(registry: ToolRegistry, opts: PlanToolOptions): void {\n registry.register({\n name: \"mark_step_complete\",\n description: MARK_STEP_COMPLETE_DESCRIPTION,\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n stepId: {\n type: \"string\",\n description:\n \"The id of the step being marked complete. Must match one from submit_plan's steps array.\",\n },\n title: {\n type: \"string\",\n description:\n \"Optional. The step's title, echoed back for the UI. If omitted, the UI falls back to the id.\",\n },\n result: {\n type: \"string\",\n description: \"One-sentence summary of what was done for this step.\",\n },\n notes: {\n type: \"string\",\n description:\n \"Optional. Anything surprising — blockers hit, assumptions revised, follow-ups for later steps.\",\n },\n },\n required: [\"stepId\", \"result\"],\n },\n fn: async (args: { stepId: string; title?: string; result: string; notes?: string }, ctx) => {\n const stepId = (args?.stepId ?? \"\").trim();\n const result = (args?.result ?? \"\").trim();\n if (!stepId) {\n throw new Error(\"mark_step_complete: stepId is required.\");\n }\n if (!result) {\n throw new Error(\n \"mark_step_complete: result is required — say in one sentence what you did.\",\n );\n }\n const title = typeof args?.title === \"string\" ? args.title.trim() || undefined : undefined;\n const notes = typeof args?.notes === \"string\" ? args.notes.trim() || undefined : undefined;\n const update: StepCompletion = { kind: \"step_completed\", stepId, result };\n if (title) update.title = title;\n if (notes) update.notes = notes;\n opts.onStepCompleted?.(update);\n // Block until the user continues, revises, or stops\n const verdict = await (ctx?.confirmationGate ?? pauseGate).ask({\n kind: \"plan_checkpoint\",\n payload: { stepId, title, result, notes },\n });\n if (verdict.type === \"continue\") return JSON.stringify(update);\n if (verdict.type === \"revise\") {\n if (verdict.feedback) return `revision requested: ${verdict.feedback}`;\n throw new Error(\"user requested revision at checkpoint\");\n }\n throw new Error(\"user stopped at checkpoint\");\n },\n });\n}\n\nfunction registerRevisePlan(registry: ToolRegistry, opts: PlanToolOptions): void {\n registry.register({\n name: \"revise_plan\",\n description: REVISE_PLAN_DESCRIPTION,\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n reason: {\n type: \"string\",\n description:\n \"One sentence explaining why you're revising — what the user asked for, what changed your assessment.\",\n },\n remainingSteps: {\n type: \"array\",\n description:\n \"The new tail of the plan — what should run from here on. Each entry: {id, title, action, risk?}. Use stable ids; reuse old ids when a step is just being adjusted, generate new ones for genuinely new steps.\",\n items: STEP_ITEM_SCHEMA,\n },\n summary: {\n type: \"string\",\n description:\n \"Optional. Updated one-line plan summary if the overall framing has shifted.\",\n },\n },\n required: [\"reason\", \"remainingSteps\"],\n },\n fn: async (args: { reason: string; remainingSteps: unknown; summary?: string }, ctx) => {\n const reason = (args?.reason ?? \"\").trim();\n if (!reason) {\n throw new Error(\n \"revise_plan: reason is required — write one sentence explaining the change.\",\n );\n }\n const remainingSteps = sanitizeSteps(args?.remainingSteps);\n if (!remainingSteps || remainingSteps.length === 0) {\n throw new Error(\n \"revise_plan: remainingSteps must be a non-empty array of well-formed steps. If the user wants to STOP rather than continue, don't revise — the picker has its own Stop option.\",\n );\n }\n const summary =\n typeof args?.summary === \"string\" ? args.summary.trim() || undefined : undefined;\n opts.onPlanRevisionProposed?.(reason, remainingSteps, summary);\n // Block until the user accepts, rejects, or cancels the revision\n const verdict = await (ctx?.confirmationGate ?? pauseGate).ask({\n kind: \"plan_revision\",\n payload: { reason, remainingSteps, summary },\n });\n if (verdict.type === \"accepted\") return \"revision accepted\";\n if (verdict.type === \"rejected\") throw new Error(\"revision rejected\");\n throw new Error(\"revision cancelled\");\n },\n });\n}\n\n// Public entry point\n\nexport function registerPlanTool(registry: ToolRegistry, opts: PlanToolOptions = {}): ToolRegistry {\n registerSubmitPlan(registry, opts);\n registerMarkStepComplete(registry, opts);\n registerRevisePlan(registry, opts);\n return registry;\n}\n","import type { ToolRegistry } from \"../tools.js\";\n\nexport type TodoStatus = \"pending\" | \"in_progress\" | \"completed\";\n\nexport interface TodoItem {\n content: string;\n status: TodoStatus;\n activeForm: string;\n}\n\nexport interface TodoToolOptions {\n onTodosUpdated?: (todos: TodoItem[]) => void;\n}\n\nconst DESCRIPTION =\n 'In-session task tracker for multi-step work. NOT a plan — no approval gate, no checkpoint pauses, doesn\\'t touch any files. The tool replaces the entire todo list every call (set semantics, NOT append). Pass the FULL list every time.\\n\\nWhen to use:\\n• The task has 3+ distinct steps and you want to keep them straight as you work.\\n• The user gave you a multi-part request (\"do A, then B, then C\").\\n• You\\'re partway through a long task and want to record where you are so a future you doesn\\'t lose the thread.\\n\\nWhen NOT to use:\\n• One-shot edits, single-question answers, single-tool tasks.\\n• User-facing approval gates → that\\'s `submit_plan`.\\n• Branching choices → that\\'s `ask_choice`.\\n\\nRules:\\n• Exactly ONE todo may have status:\"in_progress\" at a time (or zero — between steps).\\n• Mark a todo \"completed\" the moment it\\'s actually done — don\\'t batch.\\n• Each todo: `content` (imperative, e.g. \"Add tests\"), `activeForm` (gerund shown while running, e.g. \"Adding tests\"), `status`.\\n• Empty `todos:[]` is allowed — it clears the list when work is fully done.';\n\nfunction validateTodos(raw: unknown): TodoItem[] {\n if (!Array.isArray(raw)) {\n throw new Error(\"todo_write: `todos` must be an array\");\n }\n const out: TodoItem[] = [];\n let inProgressCount = 0;\n for (let i = 0; i < raw.length; i++) {\n const entry = raw[i];\n if (!entry || typeof entry !== \"object\") {\n throw new Error(`todo_write: todo #${i + 1} must be an object`);\n }\n const e = entry as Record<string, unknown>;\n const content = typeof e.content === \"string\" ? e.content.trim() : \"\";\n const activeForm = typeof e.activeForm === \"string\" ? e.activeForm.trim() : \"\";\n const status = e.status;\n if (!content) {\n throw new Error(`todo_write: todo #${i + 1} \\`content\\` must be a non-empty string`);\n }\n if (!activeForm) {\n throw new Error(`todo_write: todo #${i + 1} \\`activeForm\\` must be a non-empty string`);\n }\n if (status !== \"pending\" && status !== \"in_progress\" && status !== \"completed\") {\n throw new Error(\n `todo_write: todo #${i + 1} \\`status\\` must be one of pending|in_progress|completed (got ${JSON.stringify(status)})`,\n );\n }\n if (status === \"in_progress\") {\n inProgressCount++;\n if (inProgressCount > 1) {\n throw new Error(\n \"todo_write: at most one todo may be in_progress at a time — mark the previous one completed first\",\n );\n }\n }\n out.push({ content, status, activeForm });\n }\n return out;\n}\n\nfunction renderTodos(todos: TodoItem[]): string {\n if (todos.length === 0) return \"todos cleared (0 items)\";\n let done = 0;\n let inProgress = 0;\n let pending = 0;\n for (const t of todos) {\n if (t.status === \"completed\") done++;\n else if (t.status === \"in_progress\") inProgress++;\n else pending++;\n }\n const header = `todos updated · ${done} done · ${inProgress} in progress · ${pending} pending`;\n const lines = todos.map((t) => {\n if (t.status === \"completed\") return `[x] ${t.content}`;\n if (t.status === \"in_progress\") return `[>] ${t.activeForm}`;\n return `[ ] ${t.content}`;\n });\n return `${header}\\n${lines.join(\"\\n\")}`;\n}\n\nexport function registerTodoTool(registry: ToolRegistry, opts: TodoToolOptions = {}): ToolRegistry {\n registry.register({\n name: \"todo_write\",\n description: DESCRIPTION,\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n todos: {\n type: \"array\",\n description:\n \"The COMPLETE new todo list. Replaces whatever was there before. Pass [] to clear.\",\n items: {\n type: \"object\",\n properties: {\n content: {\n type: \"string\",\n description: 'Imperative step description, e.g. \"Add tests for parser\".',\n },\n status: {\n type: \"string\",\n enum: [\"pending\", \"in_progress\", \"completed\"],\n description: \"Current state. Exactly one item may be in_progress.\",\n },\n activeForm: {\n type: \"string\",\n description: 'Gerund form shown while in_progress, e.g. \"Adding tests for parser\".',\n },\n },\n required: [\"content\", \"status\", \"activeForm\"],\n },\n },\n },\n required: [\"todos\"],\n },\n fn: async (args: { todos: unknown }) => {\n const todos = validateTodos(args?.todos);\n opts.onTodosUpdated?.(todos);\n return renderTodos(todos);\n },\n });\n return registry;\n}\n","/** web_search uses Mojeek (DDG returns anti-bot 202 to unauthenticated POSTs); web_fetch sniffs HTML to text. */\n\nimport { parse as parseHtml } from \"node-html-parser\";\nimport {\n webSearchEndpoint as loadWebSearchEndpoint,\n webSearchEngine as loadWebSearchEngine,\n} from \"../config.js\";\nimport type { ToolRegistry } from \"../tools.js\";\n\nexport interface SearchResult {\n title: string;\n url: string;\n snippet: string;\n}\n\nexport interface PageContent {\n url: string;\n title?: string;\n text: string;\n /** True when the extracted text was clipped to fit the cap. */\n truncated: boolean;\n}\n\nexport interface WebFetchOptions {\n /** Max bytes of extracted text. Defaults to 32_000 to match tool-result cap. */\n maxChars?: number;\n /** Timeout in ms. Defaults to 15_000. */\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\nexport interface WebSearchOptions {\n topK?: number;\n signal?: AbortSignal;\n /** Backend engine: \"mojeek\" (scrapes Mojeek HTML) or \"searxng\" (self-hosted SearXNG JSON API). */\n engine?: \"mojeek\" | \"searxng\";\n /** Base URL for SearXNG. Default http://localhost:8080. */\n endpoint?: string;\n}\n\nconst DEFAULT_FETCH_MAX_CHARS = 32_000;\nconst DEFAULT_FETCH_TIMEOUT_MS = 15_000;\nconst DEFAULT_TOPK = 5;\n/** Bytes cap applied before `resp.text()` — char cap can't fire until the body is fully buffered. */\nconst FETCH_MAX_BYTES = 10 * 1024 * 1024;\n// Real-browser UA. Servers like Mojeek are bot-friendly but still gate\n// obvious scraper UAs; a stock Chrome string avoids the fast-path block.\nconst USER_AGENT =\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\";\nconst MOJEEK_ENDPOINT = \"https://www.mojeek.com/search\";\n\n/** Distinguishes \"truly 0 results\" from \"layout changed / blocked\" so callers can tell. */\nexport async function webSearch(\n query: string,\n opts: WebSearchOptions = {},\n): Promise<SearchResult[]> {\n if (opts.engine === \"searxng\") {\n return searchSearxng(query, opts);\n }\n return searchMojeek(query, opts);\n}\n\nasync function searchMojeek(query: string, opts: WebSearchOptions = {}): Promise<SearchResult[]> {\n const topK = Math.max(1, Math.min(10, opts.topK ?? DEFAULT_TOPK));\n const resp = await fetch(`${MOJEEK_ENDPOINT}?q=${encodeURIComponent(query)}`, {\n headers: {\n \"User-Agent\": USER_AGENT,\n Accept: \"text/html,application/xhtml+xml,application/xml;q=0.9\",\n \"Accept-Language\": \"en-US,en;q=0.9\",\n },\n signal: opts.signal,\n redirect: \"follow\",\n });\n if (!resp.ok) throw new Error(`web_search ${resp.status}`);\n const html = await resp.text();\n const results = parseMojeekResults(html).slice(0, topK);\n if (results.length === 0) {\n if (/no results found|did not match any documents/i.test(html)) return [];\n if (/captcha|verify you are human|access denied|forbidden/i.test(html)) {\n throw new Error(\"web_search: Mojeek anti-bot page — rate-limited or blocked\");\n }\n throw new Error(\n `web_search: 0 results but response doesn't look like a real empty page (${html.length} chars, first 120: ${html.slice(0, 120).replace(/\\s+/g, \" \")})`,\n );\n }\n return results;\n}\n\n/** Parse + validate a SearXNG endpoint. Returns origin (protocol + host). */\nfunction normalizeSearxngEndpoint(raw: string): string {\n let url: URL;\n try {\n url = new URL(raw.includes(\"://\") ? raw : `http://${raw}`);\n } catch {\n throw new Error(`web_search: invalid SearXNG endpoint \"${raw}\"`);\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n throw new Error(`web_search: SearXNG endpoint must be http(s), got ${url.protocol}`);\n }\n return url.origin;\n}\n\nasync function searchSearxng(query: string, opts: WebSearchOptions = {}): Promise<SearchResult[]> {\n const topK = Math.max(1, Math.min(10, opts.topK ?? DEFAULT_TOPK));\n const baseUrl = normalizeSearxngEndpoint(opts.endpoint ?? \"http://localhost:8080\");\n\n // JSON API is often blocked by SearXNG's default limiter; HTML always works.\n const url = `${baseUrl}/search?format=html&q=${encodeURIComponent(query)}`;\n let resp: Response;\n try {\n resp = await fetch(url, {\n headers: {\n \"User-Agent\": USER_AGENT,\n Accept: \"text/html\",\n },\n signal: opts.signal,\n });\n } catch (err) {\n if (err instanceof TypeError && (err as Error).message.includes(\"fetch\")) {\n throw new Error(\n `web_search: Cannot reach SearXNG server at ${opts.endpoint ?? \"http://localhost:8080\"}. Please install SearXNG (https://github.com/searxng/searxng) and start it (e.g. \\`docker run -d -p 8080:8080 searxng/searxng\\`), or switch to the default engine with /search-engine mojeek.`,\n );\n }\n throw err;\n }\n if (!resp.ok) throw new Error(`web_search ${resp.status}`);\n const html = await resp.text();\n const results = parseSearxngHtmlResults(html).slice(0, topK);\n if (results.length === 0) {\n if (/no results found|did not match any documents/i.test(html)) return [];\n throw new Error(\n `web_search: 0 results but SearXNG response doesn't look like an empty results page (${html.length} chars)`,\n );\n }\n return results;\n}\n\n/** Parse SearXNG HTML search results using node-html-parser. */\nexport function parseSearxngHtmlResults(html: string): SearchResult[] {\n const root = parseHtml(html);\n const results: SearchResult[] = [];\n\n // Try <article class=\"result\"> first (default SearXNG theme)\n const articles = root.querySelectorAll(\"article.result, div.result\");\n if (articles.length > 0) {\n for (const article of articles) {\n const link = article.querySelector(\"h3 a, h4 a, a[href^='http']\");\n if (!link) continue;\n const href = link.getAttribute(\"href\");\n if (!href) continue;\n const title = link.textContent.trim();\n if (!title) continue;\n let snippet = \"\";\n for (const p of article.querySelectorAll(\"p\")) {\n const text = p.textContent.trim();\n if (text.length > 10 && !text.includes(title)) {\n snippet = text;\n break;\n }\n }\n if (!snippet) {\n const cs = article.querySelector(\".content, .result-content, [class*='snippet']\");\n if (cs) snippet = cs.textContent.trim();\n }\n results.push({ title, url: href, snippet });\n }\n return results;\n }\n\n // Fallback: <h3><a href> pairs directly\n for (const a of root.querySelectorAll(\"h3 a[href]\")) {\n const href = a.getAttribute(\"href\");\n if (!href || href.startsWith(\"#\")) continue;\n const title = a.textContent.trim();\n if (!title) continue;\n let snippet = \"\";\n const p = a.parentNode?.parentNode?.querySelector(\"p\");\n if (p) snippet = p.textContent.trim();\n results.push({ title, url: href, snippet });\n }\n return results;\n}\n\n/** Title-anchor + snippet-paragraph passes paired positionally — robust to attribute reorder. */\nexport function parseMojeekResults(html: string): SearchResult[] {\n const titles: string[] = [];\n const titleAnchorRe = /<a\\b[^>]*\\bclass=\"title\"[^>]*>[\\s\\S]*?<\\/a>/g;\n let m: RegExpExecArray | null;\n while (true) {\n m = titleAnchorRe.exec(html);\n if (m === null) break;\n titles.push(m[0]);\n }\n\n const snippets: string[] = [];\n const snippetRe = /<p\\b[^>]*\\bclass=\"s\"[^>]*>([\\s\\S]*?)<\\/p>/g;\n while (true) {\n m = snippetRe.exec(html);\n if (m === null) break;\n snippets.push(m[1] ?? \"\");\n }\n\n const hrefRe = /href=\"([^\"]+)\"/;\n const innerRe = /<a\\b[^>]*>([\\s\\S]*?)<\\/a>/;\n const results: SearchResult[] = [];\n for (let i = 0; i < titles.length; i++) {\n const anchor = titles[i]!;\n const hrefMatch = anchor.match(hrefRe);\n const innerMatch = anchor.match(innerRe);\n if (!hrefMatch?.[1]) continue;\n results.push({\n title: decodeHtmlEntities(stripHtml(innerMatch?.[1] ?? \"\")).trim(),\n url: hrefMatch[1],\n snippet: decodeHtmlEntities(stripHtml(snippets[i] ?? \"\"))\n .replace(/\\s+/g, \" \")\n .trim(),\n });\n }\n return results;\n}\n\nexport async function webFetch(url: string, opts: WebFetchOptions = {}): Promise<PageContent> {\n const maxChars = opts.maxChars ?? DEFAULT_FETCH_MAX_CHARS;\n const timeoutMs = opts.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), timeoutMs);\n // Forward the caller's abort too so an Esc during a long fetch is respected.\n const cancel = () => ctl.abort();\n opts.signal?.addEventListener(\"abort\", cancel, { once: true });\n let resp: Response;\n try {\n resp = await fetch(url, {\n headers: { \"User-Agent\": USER_AGENT, Accept: \"text/html,text/plain,*/*\" },\n signal: ctl.signal,\n redirect: \"follow\",\n });\n } finally {\n clearTimeout(timer);\n opts.signal?.removeEventListener(\"abort\", cancel);\n }\n if (!resp.ok) throw new Error(`web_fetch ${resp.status} for ${url}`);\n const contentType = resp.headers.get(\"content-type\") ?? \"\";\n // Pre-check Content-Length when the server provides it. Cheaper to\n // refuse upfront than to start streaming a 1GB ISO.\n const declaredLen = Number(resp.headers.get(\"content-length\") ?? \"\");\n if (Number.isFinite(declaredLen) && declaredLen > FETCH_MAX_BYTES) {\n throw new Error(\n `web_fetch refused: content-length ${declaredLen} bytes exceeds ${FETCH_MAX_BYTES}-byte cap (${url})`,\n );\n }\n const raw = await readBodyCapped(resp, FETCH_MAX_BYTES);\n const title = extractTitle(raw);\n const text = contentType.includes(\"text/html\") ? htmlToText(raw) : raw;\n const truncated = text.length > maxChars;\n const finalText = truncated\n ? `${text.slice(0, maxChars)}\\n\\n[… truncated ${text.length - maxChars} chars …]`\n : text;\n return { url, title, text: finalText, truncated };\n}\n\n/** Streams + caps so chunked responses (or servers lying about Content-Length) can't balloon the heap. */\nasync function readBodyCapped(resp: Response, maxBytes: number): Promise<string> {\n if (!resp.body) return await resp.text();\n const reader = resp.body.getReader();\n const decoder = new TextDecoder(\"utf-8\");\n let total = 0;\n let out = \"\";\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > maxBytes) {\n try {\n await reader.cancel();\n } catch {\n /* already torn down */\n }\n throw new Error(\n `web_fetch refused: response body exceeded ${maxBytes}-byte cap (${total} bytes seen)`,\n );\n }\n out += decoder.decode(value, { stream: true });\n }\n out += decoder.decode();\n } finally {\n try {\n reader.releaseLock();\n } catch {\n /* reader already cancelled / released */\n }\n }\n return out;\n}\n\n/** Hard cap so the per-request HTML budget stays linear-time even on adversarial pages. */\nconst MAX_HTML_INPUT = 5 * 1024 * 1024;\n\nconst STRIP_BLOCK_TAGS = \"script, style, noscript, nav, footer, aside, svg\";\n\n/** Block-level tags that should produce a paragraph break in the extracted text. */\nconst BLOCK_BREAK_TAGS = new Set([\n \"p\",\n \"div\",\n \"br\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"li\",\n \"tr\",\n \"section\",\n \"article\",\n]);\n\nexport function htmlToText(html: string): string {\n const input = html.length > MAX_HTML_INPUT ? html.slice(0, MAX_HTML_INPUT) : html;\n // Real HTML parser — sidesteps the well-known regex anti-patterns\n // (`<X[\\s\\S]*?</X>`, `<[^>]+>`) CodeQL flags as bad-tag-filter and\n // incomplete-multi-character-sanitization.\n const root = parseHtml(input);\n for (const node of root.querySelectorAll(STRIP_BLOCK_TAGS)) node.remove();\n\n const out: string[] = [];\n walkExtract(root, out);\n let s = out.join(\"\");\n s = decodeHtmlEntities(s);\n s = s.replace(/[ \\t]+/g, \" \");\n s = s.replace(/\\n[ \\t]+/g, \"\\n\");\n s = s.replace(/\\n{3,}/g, \"\\n\\n\");\n return s.trim();\n}\n\ninterface WalkableNode {\n nodeType: number;\n rawText?: string;\n text?: string;\n rawTagName?: string;\n childNodes: WalkableNode[];\n}\n\nfunction walkExtract(node: WalkableNode, out: string[]): void {\n // nodeType 3 = TEXT_NODE; 1 = ELEMENT_NODE per node-html-parser.\n if (node.nodeType === 3) {\n out.push(node.rawText ?? node.text ?? \"\");\n return;\n }\n const tag = node.rawTagName?.toLowerCase();\n const isBreak = tag !== undefined && BLOCK_BREAK_TAGS.has(tag);\n if (isBreak) out.push(\"\\n\");\n for (const child of node.childNodes) walkExtract(child, out);\n if (isBreak) out.push(\"\\n\");\n}\n\nfunction stripHtml(s: string): string {\n return parseHtml(s).text;\n}\n\nconst HTML_ENTITIES: Readonly<Record<string, string>> = {\n amp: \"&\",\n lt: \"<\",\n gt: \">\",\n quot: '\"',\n apos: \"'\",\n nbsp: \" \",\n};\n\n/** Single-pass decode — the previous chained `replace`s decoded `&lt;` into `<` because `&` ran before `<`. */\nfunction decodeHtmlEntities(s: string): string {\n return s.replace(/&(#\\d+|#x[0-9a-fA-F]+|\\w+);/g, (raw, name: string) => {\n if (name.startsWith(\"#x\") || name.startsWith(\"#X\")) {\n const code = Number.parseInt(name.slice(2), 16);\n return Number.isFinite(code) ? String.fromCodePoint(code) : raw;\n }\n if (name.startsWith(\"#\")) {\n const code = Number.parseInt(name.slice(1), 10);\n return Number.isFinite(code) ? String.fromCodePoint(code) : raw;\n }\n return HTML_ENTITIES[name.toLowerCase()] ?? raw;\n });\n}\n\nfunction extractTitle(html: string): string | undefined {\n const m = html.match(/<title[^>]*>([\\s\\S]*?)<\\/title>/i);\n if (!m?.[1]) return undefined;\n return m[1].replace(/\\s+/g, \" \").trim() || undefined;\n}\n\nexport interface WebToolsOptions {\n /** Default top-K for `web_search` when the model doesn't specify. */\n defaultTopK?: number;\n /** Byte cap for `web_fetch` extracted text. */\n maxFetchChars?: number;\n /** Backend engine: \"mojeek\" (default, scrapes Mojeek) or \"searxng\" (self-hosted SearXNG). */\n webSearchEngine?: \"mojeek\" | \"searxng\";\n /** Base URL for SearXNG (default http://localhost:8080). */\n webSearchEndpoint?: string;\n}\n\nexport function registerWebTools(registry: ToolRegistry, opts: WebToolsOptions = {}): ToolRegistry {\n const defaultTopK = opts.defaultTopK ?? DEFAULT_TOPK;\n const maxFetchChars = opts.maxFetchChars ?? DEFAULT_FETCH_MAX_CHARS;\n\n registry.register({\n name: \"web_search\",\n description:\n \"Search the public web. Returns ranked results with title, url, and snippet. Call this when the answer's correctness depends on current state — anything that changes over time (events, prices, releases, status of a thing in the real world). Composing such answers from training memory invents stale numbers; search first, then ground the answer in the results. For evergreen / definitional questions you don't need this.\" +\n \" To change the backend, use /web-search-engine mojeek|searxng.\",\n readOnly: true,\n parallelSafe: true,\n parameters: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Natural-language search query.\" },\n topK: {\n type: \"integer\",\n description: `Number of results to return (1..10). Default ${defaultTopK}.`,\n },\n },\n required: [\"query\"],\n },\n fn: async (args: { query: string; topK?: number }, ctx) => {\n const engine = opts.webSearchEngine ?? loadWebSearchEngine();\n const endpoint = opts.webSearchEndpoint ?? loadWebSearchEndpoint();\n const results = await webSearch(args.query, {\n topK: args.topK ?? defaultTopK,\n signal: ctx?.signal,\n engine,\n endpoint,\n });\n return formatSearchResults(args.query, results);\n },\n });\n\n registry.register({\n name: \"web_fetch\",\n description:\n \"Download a URL and return its visible text content (HTML pages get scripts/styles/nav stripped). Truncated at the tool-result cap. Use after web_search when a snippet isn't enough.\",\n readOnly: true,\n parallelSafe: true,\n parameters: {\n type: \"object\",\n properties: {\n url: { type: \"string\", description: \"Absolute http:// or https:// URL.\" },\n },\n required: [\"url\"],\n },\n fn: async (args: { url: string }, ctx) => {\n if (!/^https?:\\/\\//i.test(args.url)) {\n throw new Error(\"web_fetch: url must start with http:// or https://\");\n }\n const page = await webFetch(args.url, { maxChars: maxFetchChars, signal: ctx?.signal });\n const header = page.title ? `${page.title}\\n${page.url}` : page.url;\n return `${header}\\n\\n${page.text}`;\n },\n });\n\n return registry;\n}\n\nexport function formatSearchResults(query: string, results: SearchResult[]): string {\n const lines: string[] = [`query: ${query}`, `\\nresults (${results.length}):`];\n results.forEach((r, i) => {\n lines.push(`\\n${i + 1}. ${r.title}`);\n lines.push(` ${r.url}`);\n if (r.snippet) lines.push(` ${r.snippet}`);\n });\n return lines.join(\"\\n\");\n}\n","/** Expand `@path` mentions inline. Paths must resolve inside rootDir; escapes / oversize get a skip note, not content. */\n\nimport { type Dirent, existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\nimport {\n type GitignoreLayer,\n ignoredByLayers,\n loadGitignoreAt,\n loadGitignoreAtSync,\n} from \"./gitignore.js\";\n\n/** Caps match tool-result dispatch truncation (0.5.2). */\nexport const DEFAULT_AT_MENTION_MAX_BYTES = 64 * 1024;\n\n/** Cap on entries returned for a `@<dir>` listing. ~200 paths × ~50 chars ≈ 10 KB — fits inside DEFAULT_AT_MENTION_MAX_BYTES with room for the rest of the prompt. */\nexport const DEFAULT_AT_DIR_MAX_ENTRIES = 200;\n\n/** Universally-uninteresting build / VCS dirs. Framework-specific dirs (Pods, target, …) live in .gitignore. */\nexport const DEFAULT_PICKER_IGNORE_DIRS: readonly string[] = [\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".next\",\n \"out\",\n \"coverage\",\n \".cache\",\n \".vscode\",\n \".idea\",\n \"target\",\n \".venv\",\n \"venv\",\n \"__pycache__\",\n];\n\nexport interface ListFilesOptions {\n /** Cap the walk once we've collected this many entries. Default 2000. */\n maxResults?: number;\n /** Directory names to skip entirely. Defaults to {@link DEFAULT_PICKER_IGNORE_DIRS}. */\n ignoreDirs?: readonly string[];\n /** Walk nested .gitignores (root + every subdir). Default true. */\n respectGitignore?: boolean;\n}\n\n/** Sync on purpose — fits the TUI's single-turn-per-tick model. Skips dot-DIRS but keeps dotfiles. */\nexport function listFilesSync(root: string, opts: ListFilesOptions = {}): string[] {\n return listFilesWithStatsSync(root, opts).map((e) => e.path);\n}\n\nexport interface FileWithStats {\n /** Relative path with forward-slash separator. */\n path: string;\n /** Modification time (Date.getTime() / ms since epoch). 0 when stat failed. */\n mtimeMs: number;\n}\n\n/** Stat failures kept as `mtimeMs: 0` — entry still appears, sinks to bottom of recency sort. */\nexport function listFilesWithStatsSync(root: string, opts: ListFilesOptions = {}): FileWithStats[] {\n const maxResults = Math.max(1, opts.maxResults ?? 2000);\n const ignoreDirs = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);\n const rootAbs = resolve(root);\n const respectGi = opts.respectGitignore !== false;\n const out: FileWithStats[] = [];\n\n const walk = (dirAbs: string, dirRel: string, layers: readonly GitignoreLayer[]) => {\n if (out.length >= maxResults) return;\n let effectiveLayers = layers;\n if (respectGi) {\n const ig = loadGitignoreAtSync(dirAbs);\n if (ig) effectiveLayers = [...layers, { dirAbs, ig }];\n }\n let entries: Dirent[];\n try {\n entries = readdirSync(dirAbs, { withFileTypes: true });\n } catch {\n return;\n }\n entries.sort((a, b) => a.name.localeCompare(b.name));\n for (const ent of entries) {\n if (out.length >= maxResults) return;\n const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;\n const absPath = join(dirAbs, ent.name);\n if (ent.isDirectory()) {\n if (ent.name.startsWith(\".\") || ignoreDirs.has(ent.name)) continue;\n if (ignoredByLayers(effectiveLayers, absPath, true)) continue;\n walk(absPath, relPath, effectiveLayers);\n } else if (ent.isFile()) {\n if (ignoredByLayers(effectiveLayers, absPath, false)) continue;\n let mtimeMs = 0;\n try {\n mtimeMs = statSync(absPath).mtimeMs;\n } catch {\n /* stat failed (permission / EAGAIN) — keep the entry with mtime=0 */\n }\n out.push({ path: relPath, mtimeMs });\n } else if (ent.isSymbolicLink()) {\n // Dirent.isFile() returns false for symlinks even when they point at\n // regular files — stat the target to recover them. Symlinks-to-dirs\n // are not followed (cycle risk).\n let target: ReturnType<typeof statSync> | null = null;\n try {\n target = statSync(absPath);\n } catch {\n continue;\n }\n if (!target.isFile()) continue;\n if (ignoredByLayers(effectiveLayers, absPath, false)) continue;\n out.push({ path: relPath, mtimeMs: target.mtimeMs });\n }\n }\n };\n\n walk(rootAbs, \"\", []);\n return out;\n}\n\n/** Parallel stat per directory — Windows stat syscalls are 3-5× slower than Linux. */\nexport async function listFilesWithStatsAsync(\n root: string,\n opts: ListFilesOptions = {},\n): Promise<FileWithStats[]> {\n const out: FileWithStats[] = [];\n const maxResults = Math.max(1, opts.maxResults ?? 2000);\n await walkFilesStream(root, {\n ...opts,\n onEntry: (e) => {\n out.push(e);\n return out.length < maxResults;\n },\n });\n return out;\n}\n\nexport interface StreamWalkOptions {\n ignoreDirs?: readonly string[];\n respectGitignore?: boolean;\n signal?: AbortSignal;\n /** Called per file entry. Return false to halt the walk. */\n onEntry: (entry: FileWithStats) => boolean | undefined;\n /** Called periodically with the running file-count. */\n onProgress?: (scanned: number) => void;\n /** Default 100ms — minimum gap between onProgress calls. */\n progressIntervalMs?: number;\n}\n\n/** Cancelable, streaming walker. Drives `listFilesWithStatsAsync` and the picker's search-mode walk. */\nexport async function walkFilesStream(\n root: string,\n opts: StreamWalkOptions,\n): Promise<{ scanned: number; cancelled: boolean }> {\n const ignoreDirs = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);\n const respectGi = opts.respectGitignore !== false;\n const rootAbs = resolve(root);\n const progressGap = Math.max(0, opts.progressIntervalMs ?? 100);\n let scanned = 0;\n let halted = false;\n let lastProgress = 0;\n\n const reportProgress = (force: boolean) => {\n if (!opts.onProgress) return;\n const now = Date.now();\n if (force || now - lastProgress >= progressGap) {\n lastProgress = now;\n opts.onProgress(scanned);\n }\n };\n\n const emit = (entry: FileWithStats) => {\n scanned++;\n if (halted) return;\n if (opts.onEntry(entry) === false) halted = true;\n reportProgress(false);\n };\n\n const walk = async (\n dirAbs: string,\n dirRel: string,\n layers: readonly GitignoreLayer[],\n ): Promise<void> => {\n if (halted || opts.signal?.aborted) return;\n let effectiveLayers = layers;\n if (respectGi) {\n const ig = await loadGitignoreAt(dirAbs);\n if (ig) effectiveLayers = [...layers, { dirAbs, ig }];\n }\n let entries: Dirent[];\n try {\n entries = await readdir(dirAbs, { withFileTypes: true });\n } catch {\n return;\n }\n entries.sort((a, b) => a.name.localeCompare(b.name));\n const fileEnts: Dirent[] = [];\n for (const ent of entries) {\n if (halted || opts.signal?.aborted) break;\n const absPath = join(dirAbs, ent.name);\n if (ent.isDirectory()) {\n if (ent.name.startsWith(\".\") || ignoreDirs.has(ent.name)) continue;\n if (ignoredByLayers(effectiveLayers, absPath, true)) continue;\n if (fileEnts.length > 0) {\n await flushFiles(fileEnts, dirAbs, dirRel, effectiveLayers, emit);\n fileEnts.length = 0;\n if (halted || opts.signal?.aborted) return;\n }\n await walk(absPath, dirRel ? `${dirRel}/${ent.name}` : ent.name, effectiveLayers);\n } else if (ent.isFile() || ent.isSymbolicLink()) {\n fileEnts.push(ent);\n }\n }\n if (fileEnts.length > 0 && !halted && !opts.signal?.aborted) {\n await flushFiles(fileEnts, dirAbs, dirRel, effectiveLayers, emit);\n }\n };\n\n await walk(rootAbs, \"\", []);\n reportProgress(true);\n return { scanned, cancelled: !!opts.signal?.aborted };\n}\n\nasync function flushFiles(\n ents: readonly Dirent[],\n dirAbs: string,\n dirRel: string,\n layers: readonly GitignoreLayer[],\n emit: (e: FileWithStats) => void,\n): Promise<void> {\n const accepted = ents.filter((e) => !ignoredByLayers(layers, join(dirAbs, e.name), false));\n const stats = await Promise.all(\n accepted.map((e) =>\n stat(join(dirAbs, e.name))\n .then((s) => ({ mtimeMs: s.mtimeMs, isFile: s.isFile() }))\n .catch(() => null),\n ),\n );\n for (let i = 0; i < accepted.length; i++) {\n const ent = accepted[i]!;\n const s = stats[i];\n if (ent.isSymbolicLink() && (!s || !s.isFile)) continue;\n emit({\n path: dirRel ? `${dirRel}/${ent.name}` : ent.name,\n mtimeMs: s?.mtimeMs ?? 0,\n });\n }\n}\n\nexport interface DirEntry {\n name: string;\n /** Relative-to-root path (forward slashes). For dirs, no trailing slash. */\n path: string;\n isDir: boolean;\n /** 0 for directories (no stat), real mtime for files. */\n mtimeMs: number;\n}\n\nexport interface ListDirectoryOptions {\n ignoreDirs?: readonly string[];\n respectGitignore?: boolean;\n}\n\n/** One-level browse for the @-picker. Folders first then files, alpha within each group. Resolves outside-root to []. */\nexport async function listDirectory(\n root: string,\n relDir: string,\n opts: ListDirectoryOptions = {},\n): Promise<DirEntry[]> {\n const ignoreDirs = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);\n const respectGi = opts.respectGitignore !== false;\n const rootAbs = resolve(root);\n const dirAbs = resolve(rootAbs, relDir);\n const rel = relative(rootAbs, dirAbs);\n if (rel.startsWith(\"..\") || isAbsolute(rel)) return [];\n\n const layers: GitignoreLayer[] = [];\n if (respectGi) {\n const segs = rel ? rel.split(/[\\\\/]/) : [];\n let cursor = rootAbs;\n const ig = await loadGitignoreAt(cursor);\n if (ig) layers.push({ dirAbs: cursor, ig });\n for (const seg of segs) {\n cursor = join(cursor, seg);\n const igSeg = await loadGitignoreAt(cursor);\n if (igSeg) layers.push({ dirAbs: cursor, ig: igSeg });\n }\n }\n\n let raw: Dirent[];\n try {\n raw = await readdir(dirAbs, { withFileTypes: true });\n } catch {\n return [];\n }\n const dirRel = rel.split(/[\\\\/]/).join(\"/\");\n const dirs: DirEntry[] = [];\n const files: Dirent[] = [];\n for (const ent of raw) {\n const absPath = join(dirAbs, ent.name);\n if (ent.isDirectory()) {\n if (ent.name.startsWith(\".\") || ignoreDirs.has(ent.name)) continue;\n if (ignoredByLayers(layers, absPath, true)) continue;\n dirs.push({\n name: ent.name,\n path: dirRel ? `${dirRel}/${ent.name}` : ent.name,\n isDir: true,\n mtimeMs: 0,\n });\n } else if (ent.isFile() || ent.isSymbolicLink()) {\n if (ignoredByLayers(layers, absPath, false)) continue;\n files.push(ent);\n }\n }\n const stats = await Promise.all(\n files.map((e) =>\n stat(join(dirAbs, e.name))\n .then((s) => ({ mtimeMs: s.mtimeMs, isFile: s.isFile() }))\n .catch(() => null),\n ),\n );\n const fileEntries: DirEntry[] = [];\n for (let i = 0; i < files.length; i++) {\n const ent = files[i]!;\n const s = stats[i];\n if (ent.isSymbolicLink() && (!s || !s.isFile)) continue;\n fileEntries.push({\n name: ent.name,\n path: dirRel ? `${dirRel}/${ent.name}` : ent.name,\n isDir: false,\n mtimeMs: s?.mtimeMs ?? 0,\n });\n }\n dirs.sort((a, b) => a.name.localeCompare(b.name));\n fileEntries.sort((a, b) => a.name.localeCompare(b.name));\n return [...dirs, ...fileEntries];\n}\n\nexport interface ParsedAtQuery {\n /** Directory portion (rel from root, no trailing slash). Empty = root. */\n dir: string;\n /** Filter portion — chars after the last slash. Empty if query ended in `/`. */\n filter: string;\n /** True if the query ended in `/` — caller knows to browse `dir`. */\n trailingSlash: boolean;\n}\n\n/** Split `src/auth/log` → `{dir: \"src/auth\", filter: \"log\"}`; trailing slash sets `trailingSlash` and clears filter. */\nexport function parseAtQuery(query: string): ParsedAtQuery {\n const normalized = query.replace(/\\\\/g, \"/\");\n const trailingSlash = normalized.endsWith(\"/\");\n const trimmed = trailingSlash ? normalized.slice(0, -1) : normalized;\n const lastSlash = trimmed.lastIndexOf(\"/\");\n if (trailingSlash) return { dir: trimmed, filter: \"\", trailingSlash: true };\n if (lastSlash < 0) return { dir: \"\", filter: trimmed, trailingSlash: false };\n return {\n dir: trimmed.slice(0, lastSlash),\n filter: trimmed.slice(lastSlash + 1),\n trailingSlash: false,\n };\n}\n\n/** Trailing-token only, anchored at end-of-input — distinct from `AT_MENTION_PATTERN` which scans all. */\nexport const AT_PICKER_PREFIX = /(?:^|\\s)@([a-zA-Z0-9_./\\\\-]*)$/;\n\nexport function detectAtPicker(input: string): { query: string; atOffset: number } | null {\n const m = AT_PICKER_PREFIX.exec(input);\n if (!m) return null;\n const query = m[1] ?? \"\";\n // `m.index` is the offset of the capture group's SURROUNDING match —\n // which starts at either ^ or the preceding whitespace. The `@`\n // itself is at `end-of-input - query.length - 1`.\n const atOffset = input.length - query.length - 1;\n return { query, atOffset };\n}\n\n/** A candidate accepted by the picker ranker — either a bare path or a path with mtime. */\nexport type PickerCandidate = string | FileWithStats;\n\nexport interface RankPickerOptions {\n /** Upper bound on returned entries. Default 40. */\n limit?: number;\n recentlyUsed?: readonly string[];\n}\n\nexport function rankPickerCandidates(\n files: readonly PickerCandidate[],\n query: string,\n limitOrOpts?: number | RankPickerOptions,\n): string[] {\n const opts: RankPickerOptions =\n typeof limitOrOpts === \"number\" ? { limit: limitOrOpts } : (limitOrOpts ?? {});\n const limit = opts.limit ?? 40;\n const recent = new Set(opts.recentlyUsed ?? []);\n\n const entries: FileWithStats[] = files.map((f) =>\n typeof f === \"string\" ? { path: f, mtimeMs: 0 } : f,\n );\n\n if (!query) {\n // Only re-sort when we actually have signal to sort by. If input\n // is bare strings (mtime = 0 everywhere) AND there's no recent-\n // used list, preserve input order so callers keep their existing\n // layout. Passing FileWithStats or a non-empty recentlyUsed opts\n // you into mtime+recency ranking.\n const anyMtime = entries.some((e) => e.mtimeMs > 0);\n if (!anyMtime && recent.size === 0) {\n return entries.slice(0, limit).map((e) => e.path);\n }\n const sorted = [...entries].sort((a, b) => {\n const aRecent = recent.has(a.path) ? 1 : 0;\n const bRecent = recent.has(b.path) ? 1 : 0;\n if (aRecent !== bRecent) return bRecent - aRecent;\n if (a.mtimeMs !== b.mtimeMs) return b.mtimeMs - a.mtimeMs;\n return a.path.localeCompare(b.path);\n });\n return sorted.slice(0, limit).map((e) => e.path);\n }\n\n const needle = query.toLowerCase();\n const scored: Array<{ path: string; score: number; mtimeMs: number; recent: boolean }> = [];\n for (const e of entries) {\n const lower = e.path.toLowerCase();\n const hit = lower.indexOf(needle);\n if (hit >= 0) {\n const slash = lower.lastIndexOf(\"/\");\n const base = slash >= 0 ? lower.slice(slash + 1) : lower;\n let cls = 2;\n if (base.startsWith(needle)) cls = 0;\n else if (lower.startsWith(needle)) cls = 1;\n scored.push({\n path: e.path,\n score: cls * 10_000 + Math.min(hit, 9999),\n mtimeMs: e.mtimeMs,\n recent: recent.has(e.path),\n });\n continue;\n }\n const fuzzy = fuzzySubseqScore(needle, lower);\n if (fuzzy === null) continue;\n scored.push({\n path: e.path,\n score: 30_000 + fuzzy,\n mtimeMs: e.mtimeMs,\n recent: recent.has(e.path),\n });\n }\n scored.sort((a, b) => {\n if (a.score !== b.score) return a.score - b.score;\n // Tie-break: recently-used, then mtime (newer first).\n if (a.recent !== b.recent) return a.recent ? -1 : 1;\n return b.mtimeMs - a.mtimeMs;\n });\n return scored.slice(0, limit).map((s) => s.path);\n}\n\nfunction fuzzySubseqScore(needle: string, target: string): number | null {\n if (needle.length === 0) return 0;\n const slashIdx = target.lastIndexOf(\"/\");\n const basenameStart = slashIdx >= 0 ? slashIdx + 1 : 0;\n let qi = 0;\n let lastMatchIdx = -2;\n let consecutive = 0;\n let basenameMatches = 0;\n let totalGap = 0;\n for (let ti = 0; ti < target.length && qi < needle.length; ti++) {\n if (target[ti] !== needle[qi]) continue;\n if (ti === lastMatchIdx + 1) consecutive++;\n else if (lastMatchIdx >= 0) totalGap += ti - lastMatchIdx - 1;\n if (ti >= basenameStart) basenameMatches++;\n lastMatchIdx = ti;\n qi++;\n }\n if (qi < needle.length) return null;\n const quality = Math.max(0, totalGap - consecutive * 10 - basenameMatches * 5);\n const lengthPenalty = Math.floor(target.length / 4);\n return quality + lengthPenalty;\n}\n\n/** Word-boundary anchor rejects `@` embedded in emails / social handles; trailing `.` stripped before lookup. */\nexport const AT_MENTION_PATTERN = /(?<=^|\\s)@([a-zA-Z0-9_./\\\\-]+)/g;\n\nexport interface AtMentionExpansion {\n /** The raw `@path` token as it appeared in the text. */\n token: string;\n /** The relative path, as resolved against rootDir. */\n path: string;\n /** True if the content was inlined. False = skipped (reason in `skip`). */\n ok: boolean;\n /** Bytes read (only for ok=true and isDirectory=false). */\n bytes?: number;\n /** True when the mention resolved to a directory (ok=true). Block uses `<directory>` instead of `<file>`. */\n isDirectory?: boolean;\n /** Number of files listed when isDirectory=true. */\n entries?: number;\n /** True iff the directory listing was clipped at maxDirEntries. */\n truncated?: boolean;\n /** Why the mention was skipped. Set when ok=false. */\n skip?: \"missing\" | \"not-file\" | \"too-large\" | \"escape\" | \"read-error\";\n}\n\nexport interface AtMentionOptions {\n /** Max file size in bytes before a mention is skipped. */\n maxBytes?: number;\n /** Cap on entries returned for a `@<dir>` listing. Default {@link DEFAULT_AT_DIR_MAX_ENTRIES}. */\n maxDirEntries?: number;\n fs?: {\n exists: (path: string) => boolean;\n isFile: (path: string) => boolean;\n /** Optional — when omitted, directories are skipped as `not-file`. */\n isDir?: (path: string) => boolean;\n /** Optional — receives the directory's absolute path and the project root, returns relative paths and a truncated flag. */\n listDir?: (\n dirAbs: string,\n root: string,\n max: number,\n ) => { files: string[]; truncated: boolean };\n size: (path: string) => number;\n read: (path: string) => string;\n };\n}\n\nexport function expandAtMentions(\n text: string,\n rootDir: string,\n opts: AtMentionOptions = {},\n): { text: string; expansions: AtMentionExpansion[] } {\n const maxBytes = opts.maxBytes ?? DEFAULT_AT_MENTION_MAX_BYTES;\n const maxDirEntries = Math.max(1, opts.maxDirEntries ?? DEFAULT_AT_DIR_MAX_ENTRIES);\n const fs = opts.fs ?? defaultFs;\n const root = resolve(rootDir);\n // De-dupe by token so `@file.ts` referenced twice inlines once.\n const seen = new Map<string, AtMentionExpansion>();\n const expansions: AtMentionExpansion[] = [];\n const dirListings = new Map<string, string[]>();\n\n for (const match of text.matchAll(AT_MENTION_PATTERN)) {\n const rawPath = match[1] ?? \"\";\n // Strip trailing dot (sentence terminator): `@foo.ts.` → `@foo.ts`.\n // Keep internal dots intact. Manual loop instead of `/\\.+$/` — the\n // regex is O(n²) on dot-heavy non-matches per CodeQL js/polynomial-redos.\n let cleaned = rawPath;\n while (cleaned.endsWith(\".\")) cleaned = cleaned.slice(0, -1);\n // Strip a single trailing slash so `@docs/` and `@docs` resolve identically.\n if (cleaned.endsWith(\"/\") || cleaned.endsWith(\"\\\\\")) cleaned = cleaned.slice(0, -1);\n if (!cleaned) continue;\n const token = `@${cleaned}`;\n if (seen.has(token)) continue;\n\n const expansion = resolveMention(cleaned, root, maxBytes, maxDirEntries, fs, dirListings);\n seen.set(token, expansion);\n expansions.push(expansion);\n }\n\n if (expansions.length === 0) return { text, expansions };\n\n // Build the trailing \"Referenced files\" block. Keep successful\n // inlines and skipped ones (with their reason) so the model sees\n // both what's here and what's missing.\n const blocks: string[] = [];\n for (const ex of expansions) {\n if (ex.ok && ex.isDirectory) {\n const files = dirListings.get(ex.path) ?? [];\n const truncAttr = ex.truncated ? ' truncated=\"true\"' : \"\";\n const body = files.length > 0 ? `\\n${files.join(\"\\n\")}\\n` : \"\\n\";\n blocks.push(\n `<directory path=\"${ex.path}\" entries=\"${ex.entries ?? files.length}\"${truncAttr}>${body}</directory>`,\n );\n } else if (ex.ok) {\n const content = readSafe(root, ex.path, fs);\n blocks.push(`<file path=\"${ex.path}\">\\n${content}\\n</file>`);\n } else {\n blocks.push(`<file path=\"${ex.path}\" skipped=\"${ex.skip}\" />`);\n }\n }\n const augmented = `${text}\\n\\n[Referenced files]\\n${blocks.join(\"\\n\\n\")}`;\n return { text: augmented, expansions };\n}\n\nfunction resolveMention(\n rawPath: string,\n root: string,\n maxBytes: number,\n maxDirEntries: number,\n fs: NonNullable<AtMentionOptions[\"fs\"]>,\n dirListings: Map<string, string[]>,\n): AtMentionExpansion {\n // Reject absolute paths — `@/etc/passwd` should not inline.\n if (isAbsolute(rawPath)) {\n return { token: `@${rawPath}`, path: rawPath, ok: false, skip: \"escape\" };\n }\n const resolved = resolve(root, rawPath);\n // Sandbox escape: after resolution the path must still be inside root.\n const rel = relative(root, resolved);\n if (rel.startsWith(\"..\") || isAbsolute(rel)) {\n return { token: `@${rawPath}`, path: rawPath, ok: false, skip: \"escape\" };\n }\n if (!fs.exists(resolved)) {\n return { token: `@${rawPath}`, path: rawPath, ok: false, skip: \"missing\" };\n }\n if (fs.isFile(resolved)) {\n const size = fs.size(resolved);\n if (size > maxBytes) {\n return { token: `@${rawPath}`, path: rawPath, ok: false, skip: \"too-large\", bytes: size };\n }\n return { token: `@${rawPath}`, path: rawPath, ok: true, bytes: size };\n }\n // Not a file — try the directory branch. listDir is optional; without it,\n // fall back to the legacy not-file skip so test fixtures don't break.\n if (fs.isDir?.(resolved) && fs.listDir) {\n const { files, truncated } = fs.listDir(resolved, root, maxDirEntries);\n dirListings.set(rawPath, files);\n return {\n token: `@${rawPath}`,\n path: rawPath,\n ok: true,\n isDirectory: true,\n entries: files.length,\n truncated,\n };\n }\n return { token: `@${rawPath}`, path: rawPath, ok: false, skip: \"not-file\" };\n}\n\nfunction readSafe(root: string, rawPath: string, fs: NonNullable<AtMentionOptions[\"fs\"]>): string {\n const resolved = resolve(root, rawPath);\n try {\n return fs.read(resolved);\n } catch {\n return \"(read failed)\";\n }\n}\n\nconst defaultFs: NonNullable<AtMentionOptions[\"fs\"]> = {\n exists: (p) => existsSync(p),\n isFile: (p) => {\n try {\n return statSync(p).isFile();\n } catch {\n return false;\n }\n },\n isDir: (p) => {\n try {\n return statSync(p).isDirectory();\n } catch {\n return false;\n }\n },\n listDir: (dirAbs, root, max) => {\n // Walk from project root and filter to entries under dirAbs so the\n // listing inherits the parent .gitignore layers. Walking dirAbs alone\n // would miss the project-root rules above it.\n const dirRel = relative(root, dirAbs).split(/[\\\\/]/).join(\"/\");\n const walkCap = Math.max(max * 4, 5000);\n const all = listFilesSync(root, { maxResults: walkCap });\n const prefix = dirRel ? `${dirRel}/` : \"\";\n const filtered = dirRel ? all.filter((f) => f === dirRel || f.startsWith(prefix)) : all;\n return {\n files: filtered.slice(0, max),\n truncated: filtered.length > max,\n };\n },\n size: (p) => {\n try {\n return statSync(p).size;\n } catch {\n return 0;\n }\n },\n read: (p) => readFileSync(p, \"utf8\"),\n};\n\nexport {\n AT_URL_PATTERN,\n DEFAULT_AT_URL_MAX_CHARS,\n expandAtUrls,\n stripUrlTail,\n} from \"./at-mentions-url.js\";\nexport type { AtUrlExpansion, AtUrlOptions } from \"./at-mentions-url.js\";\n","/** @url mentions — async sibling of @path. Fetches each URL once and inlines under \"Referenced URLs\". */\n\n/** Trailing punctuation stripped separately — URLs legitimately contain `,` `.` `)` in query strings. */\nexport const AT_URL_PATTERN = /(?<=^|\\s)@(https?:\\/\\/\\S+)/g;\n\n/** Default cap on inlined URL body (chars). */\nexport const DEFAULT_AT_URL_MAX_CHARS = 32_000;\n\nexport interface AtUrlExpansion {\n /** The raw `@url` token as it appeared in the text. */\n token: string;\n /** Absolute URL (after trailing-punctuation strip). */\n url: string;\n /** True if content was inlined. False = skipped (reason in `skip`). */\n ok: boolean;\n /** Page title when extractable from `<title>`. */\n title?: string;\n /** Char count of the (post-truncation) inlined body. */\n chars?: number;\n /** True iff the original page exceeded `maxChars` and was clipped. */\n truncated?: boolean;\n /** Why the mention was skipped — set when ok=false. */\n skip?: \"fetch-error\" | \"non-text\" | \"timeout\" | \"blocked\";\n /** Free-form error message attached to skip outcomes. */\n error?: string;\n}\n\nexport interface AtUrlOptions {\n /** Max chars of inlined body per URL. */\n maxChars?: number;\n /** Per-URL fetch timeout in ms. */\n timeoutMs?: number;\n fetcher?: (\n url: string,\n opts: { maxChars?: number; timeoutMs?: number; signal?: AbortSignal },\n ) => Promise<{ url: string; title?: string; text: string; truncated: boolean }>;\n cache?: Map<string, AtUrlExpansion & { body?: string }>;\n /** Forward Esc/abort to the fetcher. */\n signal?: AbortSignal;\n}\n\nexport async function expandAtUrls(\n text: string,\n opts: AtUrlOptions = {},\n): Promise<{ text: string; expansions: AtUrlExpansion[] }> {\n const maxChars = opts.maxChars ?? DEFAULT_AT_URL_MAX_CHARS;\n const fetcher = opts.fetcher;\n if (!fetcher) {\n throw new Error(\"expandAtUrls: fetcher option is required (wire src/tools/web.ts:webFetch)\");\n }\n\n const seen = new Map<string, AtUrlExpansion>();\n const bodies = new Map<string, string>();\n const order: string[] = [];\n\n for (const match of text.matchAll(AT_URL_PATTERN)) {\n const rawUrl = match[1] ?? \"\";\n const url = stripUrlTail(rawUrl);\n if (!url) continue;\n if (seen.has(url)) continue;\n\n const cached = opts.cache?.get(url);\n if (cached) {\n seen.set(url, cached);\n if (cached.body) bodies.set(url, cached.body);\n order.push(url);\n continue;\n }\n\n let expansion: AtUrlExpansion;\n let body = \"\";\n try {\n const page = await fetcher(url, {\n maxChars,\n timeoutMs: opts.timeoutMs,\n signal: opts.signal,\n });\n body = page.text;\n expansion = {\n token: `@${url}`,\n url,\n ok: true,\n title: page.title,\n chars: body.length,\n truncated: page.truncated,\n };\n } catch (err) {\n const message = (err as Error).message ?? String(err);\n let skip: AtUrlExpansion[\"skip\"] = \"fetch-error\";\n if (/aborted|timeout/i.test(message)) skip = \"timeout\";\n else if (/40\\d|forbidden|access denied|captcha/i.test(message)) skip = \"blocked\";\n expansion = {\n token: `@${url}`,\n url,\n ok: false,\n skip,\n error: message,\n };\n }\n seen.set(url, expansion);\n if (body) bodies.set(url, body);\n if (opts.cache) opts.cache.set(url, { ...expansion, body });\n order.push(url);\n }\n\n if (seen.size === 0) return { text, expansions: [] };\n\n const expansions = order.map((u) => seen.get(u)!).filter(Boolean);\n const blocks: string[] = [];\n for (const ex of expansions) {\n if (ex.ok) {\n const titleAttr = ex.title ? ` title=\"${escapeAttr(ex.title)}\"` : \"\";\n const truncTag = ex.truncated ? ' truncated=\"true\"' : \"\";\n const body = bodies.get(ex.url) ?? \"\";\n blocks.push(`<url href=\"${ex.url}\"${titleAttr}${truncTag}>\\n${body}\\n</url>`);\n } else {\n const reasonAttr = ex.skip ?? \"fetch-error\";\n blocks.push(`<url href=\"${ex.url}\" skipped=\"${reasonAttr}\" />`);\n }\n }\n const augmented = `${text}\\n\\n[Referenced URLs]\\n${blocks.join(\"\\n\\n\")}`;\n return { text: augmented, expansions };\n}\n\n/** Only strips `.,;:!?` and unmatched close-brackets — internal path / query punctuation preserved. */\nexport function stripUrlTail(raw: string): string {\n let s = raw;\n while (s.length > 0) {\n const last = s[s.length - 1]!;\n if (\".,;:!?\".includes(last)) {\n s = s.slice(0, -1);\n continue;\n }\n if (\")]}>\".includes(last)) {\n const open = ({ \")\": \"(\", \"]\": \"[\", \"}\": \"{\", \">\": \"<\" } as const)[\n last as \")\" | \"]\" | \"}\" | \">\"\n ];\n if (!s.includes(open)) {\n s = s.slice(0, -1);\n continue;\n }\n }\n break;\n }\n return s;\n}\n\nfunction escapeAttr(s: string): string {\n return s\n .replace(/\"/g, \""\")\n .replace(/[\\r\\n]+/g, \" \")\n .trim();\n}\n","/** Built-in subagent personas — system prompt + iter budget pairs picked via the `type` arg. Skills override at the run_skill level; this is the inline shortcut for parents that don't want to author one. */\n\nimport { NEGATIVE_CLAIM_RULE, TUI_FORMATTING_RULES } from \"../prompt-fragments.js\";\n\nexport type SubagentTypeName = \"explore\" | \"verify\";\n\nexport interface SubagentTypeSpec {\n system: string;\n maxToolIters: number;\n}\n\nconst EXPLORE_SYSTEM = `You are an exploration subagent. Wide-net read-only investigation; return one distilled answer.\n\nHow to operate:\n- Read-only tools only (read_file, search_files, search_content, directory_tree, list_directory, get_file_info).\n- For \"find all places that call / reference / use X\" — use search_content (content grep), NOT search_files (which only matches names).\n- Cast a wide net first to map the territory, then read the 3-10 most relevant files in full. Stop as soon as you can answer.\n- The parent does not see your tool calls — over-exploration is pure waste.\n\nFinal answer:\n- One paragraph or short bullets; lead with the conclusion.\n- Cite file:line ranges when they back the claim.\n- No follow-up offers, no \"let me know if you need more\" — the parent will ask again.\n\n${NEGATIVE_CLAIM_RULE}\n\n${TUI_FORMATTING_RULES}`;\n\nconst VERIFY_SYSTEM = `You are a verify subagent. Narrow check — return YES / NO / INCONCLUSIVE with evidence. Do not expand scope.\n\nHow to operate:\n- Read only what's needed to verify the specific claim. No exploration past the claim.\n- Use search_content / read_file to confirm the exact behavior, type, or call site in question.\n- Cap at 6-8 tool calls. If you can't verify in that, return INCONCLUSIVE plus what's missing.\n\nFinal answer:\n- Lead with VERIFIED / NOT VERIFIED / INCONCLUSIVE.\n- Cite file:line for the evidence.\n- One paragraph or a few bullets. No follow-up offers.\n\n${NEGATIVE_CLAIM_RULE}\n\n${TUI_FORMATTING_RULES}`;\n\nconst TYPES: Record<SubagentTypeName, SubagentTypeSpec> = {\n explore: { system: EXPLORE_SYSTEM, maxToolIters: 20 },\n verify: { system: VERIFY_SYSTEM, maxToolIters: 8 },\n};\n\nexport const SUBAGENT_TYPE_NAMES: readonly SubagentTypeName[] = Object.freeze(\n Object.keys(TYPES) as SubagentTypeName[],\n);\n\nexport function getSubagentType(name: unknown): SubagentTypeSpec | undefined {\n if (typeof name !== \"string\") return undefined;\n return TYPES[name as SubagentTypeName];\n}\n","/** Isolated child loop. Inherits parent registry minus spawn_subagent + submit_plan; no hooks; non-streaming. */\n\nimport { type DeepSeekClient, Usage } from \"../client.js\";\nimport { CacheFirstLoop } from \"../loop.js\";\nimport { applyProjectMemory } from \"../memory/project.js\";\nimport { ImmutablePrefix } from \"../memory/runtime.js\";\nimport {\n ESCALATION_CONTRACT,\n NEGATIVE_CLAIM_RULE,\n TUI_FORMATTING_RULES,\n} from \"../prompt-fragments.js\";\nimport { ToolRegistry } from \"../tools.js\";\nimport { SUBAGENT_TYPE_NAMES, getSubagentType } from \"./subagent-types.js\";\n\n/** Side-channel — subagents run inside a tool-dispatch frame, can't go through parent's `LoopEvent` stream. */\nexport interface SubagentEvent {\n kind: \"start\" | \"progress\" | \"end\" | \"inner\" | \"phase\";\n /** Stable per-spawn id; lets the UI key parallel runs apart instead of overwriting one shared row. */\n runId: string;\n task: string;\n skillName?: string;\n model?: string;\n iter?: number;\n elapsedMs?: number;\n summary?: string;\n error?: string;\n turns?: number;\n costUsd?: number;\n usage?: Usage;\n /** When kind === \"inner\": the raw child loop event. Parent UI translates to a child summary. */\n inner?: import(\"../loop.js\").LoopEvent;\n /** When kind === \"phase\": coarse status verb for the activity row. */\n phase?: \"exploring\" | \"summarising\";\n}\n\nlet runIdCounter = 0;\nfunction nextRunId(): string {\n runIdCounter++;\n return `sub-${runIdCounter.toString(36)}`;\n}\n\nexport interface SubagentSink {\n current: ((ev: SubagentEvent) => void) | null;\n}\n\nexport interface SpawnSubagentOptions {\n client: DeepSeekClient;\n parentRegistry: ToolRegistry;\n system: string;\n task: string;\n model?: string;\n maxToolIters?: number;\n maxResultChars?: number;\n sink?: SubagentSink;\n /** Forwarded into the child loop so parent Esc cancels nested work. */\n parentSignal?: AbortSignal;\n skillName?: string;\n /** Scopes the child registry to these literal tool names; NEVER_INHERITED still wins. Driven by skill `allowed-tools` frontmatter. */\n allowedTools?: readonly string[];\n}\n\nexport interface SubagentResult {\n success: boolean;\n output: string;\n error?: string;\n turns: number;\n toolIters: number;\n elapsedMs: number;\n costUsd: number;\n model: string;\n skillName?: string;\n /** Zero-filled when no API calls landed so consumers always see a valid shape. */\n usage: Usage;\n}\n\nexport interface SubagentToolOptions {\n client: DeepSeekClient;\n defaultSystem?: string;\n projectRoot?: string;\n defaultModel?: string;\n maxToolIters?: number;\n maxResultChars?: number;\n sink?: SubagentSink;\n}\n\nconst DEFAULT_SUBAGENT_SYSTEM = `You are a Reasonix subagent. The parent agent spawned you to handle one focused subtask, then return.\n\nRules:\n- Stay on the task you were given. Do not expand scope.\n- Use tools as needed. You share the parent's sandbox + safety rules.\n- When you're done, your final assistant message is the only thing the parent will see — make it complete and self-contained. No follow-up offers, no questions, no \"let me know if you need more.\"\n- Prefer one clear, distilled answer over a long log of what you tried.\n\n${NEGATIVE_CLAIM_RULE}\n\n${ESCALATION_CONTRACT}\n\n${TUI_FORMATTING_RULES}`;\n\nconst DEFAULT_MAX_RESULT_CHARS = 8000;\nconst DEFAULT_MAX_ITERS = 16;\nconst MIN_MAX_ITERS = 1;\nconst MAX_MAX_ITERS = 32;\n/** Iters-from-cap at which we start appending a remaining-budget hint to tool results. */\nconst BUDGET_WARN_THRESHOLD = 3;\n\nfunction budgetParagraph(maxToolIters: number): string {\n return `Tool budget: you have ${maxToolIters} tool call${maxToolIters === 1 ? \"\" : \"s\"} for this task. The cap is enforced from outside — the call after #${maxToolIters} is refused. Pace yourself: if you can't fully resolve the task within the budget, stop early and return what you have plus what's missing, rather than burning the budget on one branch.`;\n}\n// Subagents default to flash — their work is read-and-synthesize\n// (explore, research), which doesn't need the 12× pro tier. Skill\n// frontmatter `model: deepseek-v4-pro` is the opt-in override for\n// skills that empirically benefit from the stronger model.\nconst DEFAULT_SUBAGENT_MODEL = \"deepseek-v4-flash\";\n// Subagents default to effort=high — less thinking budget than a\n// main turn (which defaults to `max` in the preset). The parent's\n// task arg is already a distilled prompt; explore/research rarely\n// need deep chains of thought, and `high` saves output tokens.\nconst DEFAULT_SUBAGENT_EFFORT: \"high\" | \"max\" = \"high\";\n\nconst SUBAGENT_TOOL_NAME = \"spawn_subagent\";\n/** spawn_subagent excluded → depth=1 hard cap; submit_plan excluded → no picker mid-parent-turn. */\nconst NEVER_INHERITED_TOOLS = new Set<string>([SUBAGENT_TOOL_NAME, \"submit_plan\"]);\n\n/** Errors captured in the result shape, never thrown — caller decides how to surface. */\nexport async function spawnSubagent(opts: SpawnSubagentOptions): Promise<SubagentResult> {\n const model = opts.model ?? DEFAULT_SUBAGENT_MODEL;\n const maxToolIters = opts.maxToolIters ?? DEFAULT_MAX_ITERS;\n const maxResultChars = opts.maxResultChars ?? DEFAULT_MAX_RESULT_CHARS;\n const sink = opts.sink;\n const skillName = opts.skillName;\n\n const startedAt = Date.now();\n const runId = nextRunId();\n const taskPreview = opts.task.length > 30 ? `${opts.task.slice(0, 30)}…` : opts.task;\n sink?.current?.({\n kind: \"start\",\n runId,\n task: taskPreview,\n skillName,\n model,\n iter: 0,\n elapsedMs: 0,\n });\n\n if (opts.allowedTools) {\n const missing = opts.allowedTools.filter((n) => !opts.parentRegistry.has(n));\n if (missing.length > 0) {\n const errorMessage = `subagent allow-list names tool(s) not registered in the parent: ${missing.join(\", \")}. Fix the skill's \\`allowed-tools\\` frontmatter or check spelling.`;\n sink?.current?.({\n kind: \"end\",\n runId,\n task: taskPreview,\n skillName,\n model,\n iter: 0,\n elapsedMs: Date.now() - startedAt,\n error: errorMessage,\n turns: 0,\n costUsd: 0,\n usage: new Usage(),\n });\n return {\n success: false,\n output: \"\",\n error: errorMessage,\n turns: 0,\n toolIters: 0,\n elapsedMs: Date.now() - startedAt,\n costUsd: 0,\n model,\n skillName,\n usage: new Usage(),\n };\n }\n }\n\n const childTools = opts.allowedTools\n ? forkRegistryWithAllowList(\n opts.parentRegistry,\n new Set(opts.allowedTools),\n NEVER_INHERITED_TOOLS,\n )\n : forkRegistryExcluding(opts.parentRegistry, NEVER_INHERITED_TOOLS);\n // Budget telemetry: count dispatches and append a remaining-iters hint\n // when the child is within BUDGET_WARN_THRESHOLD of the cap, so the\n // model can choose to wrap up rather than open another rabbit hole.\n let dispatchCount = 0;\n childTools.setResultAugmenter((_name, _args, result) => {\n dispatchCount++;\n const remaining = maxToolIters - dispatchCount;\n if (remaining <= 0) {\n return `${result}\\n\\n[budget: 0 of ${maxToolIters} tool calls left — finalize NOW; the next tool call will be refused]`;\n }\n if (remaining <= BUDGET_WARN_THRESHOLD) {\n return `${result}\\n\\n[budget: ${remaining} of ${maxToolIters} tool call${remaining === 1 ? \"\" : \"s\"} left — wrap up soon]`;\n }\n return result;\n });\n const childPrefix = new ImmutablePrefix({\n system: `${opts.system}\\n\\n${budgetParagraph(maxToolIters)}`,\n toolSpecs: childTools.specs(),\n });\n const childLoop = new CacheFirstLoop({\n client: opts.client,\n prefix: childPrefix,\n tools: childTools,\n model,\n // Subagents run on a constrained thinking budget by default — the\n // task is already narrow by construction, and `high` cuts output\n // tokens substantially vs `max`.\n reasoningEffort: DEFAULT_SUBAGENT_EFFORT,\n maxToolIters,\n hooks: [],\n // Streaming on so the parent UI can flip the \"summarising\" phase the\n // moment the model starts emitting the final answer (first assistant_delta\n // after the last tool result, before assistant_final lands).\n stream: true,\n });\n\n // Wire parent-abort → child-abort. Two pitfalls we have to handle:\n //\n // 1. `addEventListener(\"abort\", ...)` does NOT fire for a signal\n // that's already aborted (the abort event has already been\n // dispatched once and `once: true` is moot). If the parent\n // aborted between dispatch entry and our listener attach,\n // the listener stays silent forever and the child runs free.\n // → Check `.aborted` synchronously and forward immediately.\n //\n // 2. childLoop.step() reassigns its internal _turnAbort at the\n // top of step(). loop.ts forwards prior aborted state into\n // the fresh controller, so abort() called BEFORE step() runs\n // still kills the new step at iter 0.\n const onParentAbort = () => childLoop.abort();\n if (opts.parentSignal?.aborted) {\n childLoop.abort();\n } else {\n opts.parentSignal?.addEventListener(\"abort\", onParentAbort, { once: true });\n }\n\n let final = \"\";\n let errorMessage: string | undefined;\n let toolIter = 0;\n let summarisingEmitted = false;\n try {\n for await (const ev of childLoop.step(opts.task)) {\n sink?.current?.({ kind: \"inner\", runId, task: taskPreview, skillName, model, inner: ev });\n\n if (ev.role === \"tool\") {\n toolIter++;\n // New tool dispatched — the model went back to deciding, summarising flag resets so the next final-answer delta re-emits.\n summarisingEmitted = false;\n sink?.current?.({\n kind: \"progress\",\n runId,\n task: taskPreview,\n skillName,\n model,\n iter: toolIter,\n elapsedMs: Date.now() - startedAt,\n });\n }\n // First content delta (no concurrent tool_call_delta role) = the\n // model is now writing its final answer, not deciding the next tool.\n if (ev.role === \"assistant_delta\" && !summarisingEmitted && (ev.content ?? \"\").length > 0) {\n summarisingEmitted = true;\n sink?.current?.({\n kind: \"phase\",\n runId,\n task: taskPreview,\n skillName,\n model,\n phase: \"summarising\",\n iter: toolIter,\n elapsedMs: Date.now() - startedAt,\n });\n }\n if (ev.role === \"assistant_final\") {\n if (ev.forcedSummary) {\n errorMessage = ev.content?.trim() || \"subagent ended without producing an answer\";\n } else {\n final = ev.content ?? \"\";\n }\n }\n if (ev.role === \"error\") {\n errorMessage = ev.error ?? \"subagent error\";\n }\n }\n } catch (err) {\n errorMessage = (err as Error).message;\n } finally {\n opts.parentSignal?.removeEventListener(\"abort\", onParentAbort);\n }\n // The loop yields `done` without an `error` event when its API call\n // is aborted mid-flight (intentional UX — see the matching catch in\n // CacheFirstLoop.step). From a SUBAGENT consumer's perspective that\n // still counts as a failure: no answer came back, the parent has\n // nothing to render. Synthesize an error so `success: false` and the\n // UI surfaces the abort instead of returning empty output.\n if (!errorMessage && !final) {\n errorMessage = opts.parentSignal?.aborted\n ? \"subagent aborted before producing an answer\"\n : \"subagent ended without producing an answer\";\n }\n\n const elapsedMs = Date.now() - startedAt;\n const turns = childLoop.stats.turns.length;\n const costUsd = childLoop.stats.totalCost;\n const usage = aggregateChildUsage(childLoop);\n\n const truncated =\n final.length > maxResultChars\n ? `${final.slice(0, maxResultChars)}\\n\\n[…truncated ${final.length - maxResultChars} chars; ask the subagent for a tighter summary if you need more.]`\n : final;\n\n sink?.current?.({\n kind: \"end\",\n runId,\n task: taskPreview,\n skillName,\n model,\n iter: toolIter,\n elapsedMs,\n summary: errorMessage ? undefined : truncated.slice(0, 120),\n error: errorMessage,\n turns,\n costUsd,\n usage,\n });\n\n return {\n success: !errorMessage,\n output: errorMessage ? \"\" : truncated,\n error: errorMessage,\n turns,\n toolIters: toolIter,\n elapsedMs,\n costUsd,\n model,\n skillName,\n usage,\n };\n}\n\n/** Zero-filled when no API calls landed so downstream consumers always see a valid shape. */\nfunction aggregateChildUsage(loop: CacheFirstLoop): Usage {\n const agg = new Usage();\n for (const t of loop.stats.turns) {\n agg.promptTokens += t.usage.promptTokens;\n agg.completionTokens += t.usage.completionTokens;\n agg.totalTokens += t.usage.totalTokens;\n agg.promptCacheHitTokens += t.usage.promptCacheHitTokens;\n agg.promptCacheMissTokens += t.usage.promptCacheMissTokens;\n }\n return agg;\n}\n\nexport function formatSubagentResult(r: SubagentResult): string {\n if (!r.success) {\n return JSON.stringify({\n success: false,\n error: r.error ?? \"unknown subagent error\",\n turns: r.turns,\n tool_iters: r.toolIters,\n elapsed_ms: r.elapsedMs,\n });\n }\n return JSON.stringify({\n success: true,\n output: r.output,\n turns: r.turns,\n tool_iters: r.toolIters,\n elapsed_ms: r.elapsedMs,\n cost_usd: r.costUsd,\n });\n}\n\n/** Library surface only — `reasonix code` uses Skills `runAs: subagent` as the user-facing path. */\nexport function registerSubagentTool(\n parentRegistry: ToolRegistry,\n opts: SubagentToolOptions,\n): ToolRegistry {\n const baseSystem = opts.defaultSystem ?? DEFAULT_SUBAGENT_SYSTEM;\n // Bake project memory into the default once — re-reading on every\n // spawn would (a) make the child prefix unstable when REASONIX.md\n // changes mid-session, defeating cache reuse across multiple\n // subagent calls, and (b) cost a stat() per call. The parent itself\n // also reads memory once at startup; matching that semantics keeps\n // subagent and parent on the same page.\n const defaultSystem = opts.projectRoot\n ? applyProjectMemory(baseSystem, opts.projectRoot)\n : baseSystem;\n const defaultModel = opts.defaultModel ?? DEFAULT_SUBAGENT_MODEL;\n const maxToolIters = opts.maxToolIters ?? DEFAULT_MAX_ITERS;\n const maxResultChars = opts.maxResultChars ?? DEFAULT_MAX_RESULT_CHARS;\n const sink = opts.sink;\n\n parentRegistry.register({\n name: SUBAGENT_TOOL_NAME,\n parallelSafe: true,\n description:\n \"Spawn an isolated subagent to handle a self-contained subtask in a fresh context, returning only its final answer. Use for: deep codebase exploration that would flood the main context, multi-step research where you only need the conclusion, or any focused subtask whose intermediate reasoning the user does not need to see. The subagent inherits all your tools (filesystem, shell, web, MCP, etc.) but runs in its own isolated message log — its tool calls and reasoning never enter your context. Only the final assistant message comes back as this tool's result. Keep tasks focused; the subagent has a stricter iter budget than you do.\",\n parameters: {\n type: \"object\",\n properties: {\n task: {\n type: \"string\",\n description:\n \"The subtask the subagent should perform. Be specific and self-contained — the subagent has none of your conversation context, only what you write here.\",\n },\n system: {\n type: \"string\",\n description:\n \"Optional override for the subagent's system prompt. The default tells it to stay focused and return a concise answer; override only when the subtask needs a specialized persona.\",\n },\n model: {\n type: \"string\",\n enum: [\"deepseek-v4-flash\", \"deepseek-v4-pro\"],\n description:\n \"Which DeepSeek model the subagent runs on. Default is 'deepseek-v4-flash' — cheap and fast, fine for explore/research-style subtasks. Override to 'deepseek-v4-pro' (~12× more expensive) when the subtask genuinely needs the stronger model: cross-file architecture, subtle bug hunts, anything where flash has empirically underperformed.\",\n },\n max_iters: {\n type: \"integer\",\n minimum: MIN_MAX_ITERS,\n maximum: MAX_MAX_ITERS,\n description: `Cap on the subagent's tool-call iterations. Default 16 (or the type's default when 'type' is set). Hard range: ${MIN_MAX_ITERS}-${MAX_MAX_ITERS}; out-of-range values are clamped to the nearest end.`,\n },\n type: {\n type: \"string\",\n enum: [...SUBAGENT_TYPE_NAMES],\n description:\n \"Optional persona shaping the system prompt and default iter budget. 'explore' = wide-net read-only investigation (20-iter budget, returns a distilled answer). 'verify' = narrow yes/no check with evidence (8-iter budget). Omit when supplying your own 'system' prompt or when the default generic persona fits. Caller-supplied 'system' / 'max_iters' override the type's defaults.\",\n },\n },\n required: [\"task\"],\n },\n fn: async (\n args: {\n task?: unknown;\n system?: unknown;\n model?: unknown;\n max_iters?: unknown;\n type?: unknown;\n },\n ctx,\n ) => {\n const task = typeof args.task === \"string\" ? args.task.trim() : \"\";\n if (!task) {\n return JSON.stringify({\n error: \"spawn_subagent requires a non-empty 'task' argument.\",\n });\n }\n const typeSpec = getSubagentType(args.type);\n const system =\n typeof args.system === \"string\" && args.system.trim().length > 0\n ? args.system.trim()\n : (typeSpec?.system ?? defaultSystem);\n const model =\n typeof args.model === \"string\" && args.model.startsWith(\"deepseek-\")\n ? args.model\n : defaultModel;\n const callerIters = clampMaxIters(args.max_iters);\n const result = await spawnSubagent({\n client: opts.client,\n parentRegistry,\n system,\n task,\n model,\n maxToolIters: callerIters ?? typeSpec?.maxToolIters ?? maxToolIters,\n maxResultChars,\n sink,\n parentSignal: ctx?.signal,\n });\n return formatSubagentResult(result);\n },\n });\n\n return parentRegistry;\n}\n\n/** Floats round down; non-finite / wrong-type yields undefined so caller falls back to its default. */\nfunction clampMaxIters(raw: unknown): number | undefined {\n if (typeof raw !== \"number\" || !Number.isFinite(raw)) return undefined;\n const n = Math.floor(raw);\n if (n < MIN_MAX_ITERS) return MIN_MAX_ITERS;\n if (n > MAX_MAX_ITERS) return MAX_MAX_ITERS;\n return n;\n}\n\n/** Plan-mode state propagates — a subagent spawned under `/plan` MUST NOT escape it. */\nexport function forkRegistryExcluding(\n parent: ToolRegistry,\n exclude: ReadonlySet<string>,\n): ToolRegistry {\n const child = new ToolRegistry();\n for (const spec of parent.specs()) {\n const name = spec.function.name;\n if (exclude.has(name)) continue;\n const def = parent.get(name);\n if (!def) continue;\n // Re-register copies the public ToolDefinition fields. The child\n // re-runs auto-flatten analysis on its own, which produces an\n // identical flatSchema for the same input — no surprise.\n child.register(def);\n }\n if (parent.planMode) child.setPlanMode(true);\n return child;\n}\n\n/** alsoExclude wins over allow so NEVER_INHERITED still drops `spawn_subagent` even if a skill allow-list names it. */\nexport function forkRegistryWithAllowList(\n parent: ToolRegistry,\n allow: ReadonlySet<string>,\n alsoExclude: ReadonlySet<string>,\n): ToolRegistry {\n const child = new ToolRegistry();\n for (const spec of parent.specs()) {\n const name = spec.function.name;\n if (!allow.has(name)) continue;\n if (alsoExclude.has(name)) continue;\n const def = parent.get(name);\n if (!def) continue;\n child.register(def);\n }\n if (parent.planMode) child.setPlanMode(true);\n return child;\n}\n","/** SEARCH must match byte-for-byte; empty SEARCH = create new file. No fuzzy match — silent wrong edit beats a missing one. */\n\nimport {\n closeSync,\n existsSync,\n fstatSync,\n ftruncateSync,\n mkdirSync,\n openSync,\n readFileSync,\n readSync,\n unlinkSync,\n writeFileSync,\n writeSync,\n} from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\n\nexport interface EditBlock {\n /** Path as written by the model — relative to rootDir, or absolute. */\n path: string;\n /** Literal text to match in the target file. Empty → create new file. */\n search: string;\n /** Replacement text to write in place of `search`. */\n replace: string;\n /** Char offset in the source message where this block started. */\n offset: number;\n}\n\nexport type ApplyStatus =\n /** Edit landed on disk. */\n | \"applied\"\n /** New file created (SEARCH was empty and file didn't exist). */\n | \"created\"\n /** File exists but SEARCH block wasn't found in its content. */\n | \"not-found\"\n /** File doesn't exist and SEARCH was non-empty (can't create without content). */\n | \"file-missing\"\n /** Path escapes rootDir — refused on safety grounds. */\n | \"path-escape\"\n /** fs write / read threw. */\n | \"error\";\n\nexport interface ApplyResult {\n path: string;\n status: ApplyStatus;\n /** Extra detail (e.g. error message) for logs. */\n message?: string;\n}\n\n// `^` + `m` keeps a JS string containing `<<<<<<< SEARCH` from matching as a real block.\n// `\\n?` makes empty SEARCH/REPLACE bodies legal (new-file / future delete sentinels).\nconst BLOCK_RE = /^(\\S[^\\n]*)\\n<{7} SEARCH\\n([\\s\\S]*?)\\n?={7}\\n([\\s\\S]*?)\\n?>{7} REPLACE/gm;\n\nexport function parseEditBlocks(text: string): EditBlock[] {\n const out: EditBlock[] = [];\n BLOCK_RE.lastIndex = 0;\n let m: RegExpExecArray | null = BLOCK_RE.exec(text);\n while (m !== null) {\n out.push({\n path: m[1]!.trim(),\n search: m[2]!,\n replace: m[3]!,\n offset: m.index,\n });\n m = BLOCK_RE.exec(text);\n }\n return out;\n}\n\nexport function applyEditBlock(block: EditBlock, rootDir: string): ApplyResult {\n const absRoot = resolve(rootDir);\n const absTarget = resolve(absRoot, block.path);\n // Refuse paths that escape rootDir. `resolve` normalizes `..`, so\n // startsWith on the normalized pair is enough.\n if (absTarget !== absRoot && !absTarget.startsWith(`${absRoot}${sep()}`)) {\n return {\n path: block.path,\n status: \"path-escape\",\n message: `resolved path ${absTarget} is outside rootDir ${absRoot}`,\n };\n }\n\n const searchEmpty = block.search.length === 0;\n\n // Branch on intent first so each path makes exactly one `open` call\n // — keeps CodeQL's flow analyser from tripping over a check→use\n // chain across two opens (js/file-system-race).\n if (searchEmpty) {\n try {\n mkdirSync(dirname(absTarget), { recursive: true });\n const fd = openSync(absTarget, \"wx\");\n try {\n writeSync(fd, block.replace);\n } finally {\n closeSync(fd);\n }\n return { path: block.path, status: \"created\" };\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"EEXIST\") {\n return {\n path: block.path,\n status: \"not-found\",\n message: \"empty SEARCH only creates new files — this file already exists\",\n };\n }\n return { path: block.path, status: \"error\", message: e.message };\n }\n }\n\n try {\n // Modify path. ENOENT is reported as `file-missing` so the model\n // knows it needs an empty SEARCH to create the file.\n let fd: number;\n try {\n fd = openSync(absTarget, \"r+\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return {\n path: block.path,\n status: \"file-missing\",\n message: \"file does not exist; to create it, use an empty SEARCH block\",\n };\n }\n throw err;\n }\n\n try {\n const stat = fstatSync(fd);\n const inBuf = Buffer.alloc(stat.size);\n let readBytes = 0;\n while (readBytes < stat.size) {\n const n = readSync(fd, inBuf, readBytes, stat.size - readBytes, readBytes);\n if (n <= 0) break;\n readBytes += n;\n }\n const content = inBuf.toString(\"utf8\", 0, readBytes);\n const le = lineEndingOf(content);\n const adaptedSearch = block.search.replace(/\\r?\\n/g, le);\n const adaptedReplace = block.replace.replace(/\\r?\\n/g, le);\n const idx = content.indexOf(adaptedSearch);\n if (idx === -1) {\n return {\n path: block.path,\n status: \"not-found\",\n message: \"SEARCH text does not match the current file content exactly\",\n };\n }\n // Replace only the first occurrence — if the model needs multiple\n // identical edits it should emit multiple blocks (each anchored by\n // more surrounding context). Auto-expanding to replace-all is a\n // footgun when the same string legitimately appears in several\n // unrelated places.\n const replaced = `${content.slice(0, idx)}${adaptedReplace}${content.slice(idx + adaptedSearch.length)}`;\n // Truncate first so a shorter result doesn't leave stale tail\n // bytes; ftruncate also pads with NUL when the new length is\n // longer, which we then overwrite below.\n const outBuf = Buffer.from(replaced, \"utf8\");\n ftruncateSync(fd, outBuf.length);\n let written = 0;\n while (written < outBuf.length) {\n const n = writeSync(fd, outBuf, written, outBuf.length - written, written);\n if (n <= 0) break;\n written += n;\n }\n return { path: block.path, status: \"applied\" };\n } finally {\n closeSync(fd);\n }\n } catch (err) {\n return { path: block.path, status: \"error\", message: (err as Error).message };\n }\n}\n\nexport function applyEditBlocks(blocks: EditBlock[], rootDir: string): ApplyResult[] {\n return blocks.map((b) => applyEditBlock(b, rootDir));\n}\n\nexport function toWholeFileEditBlock(path: string, content: string, rootDir: string): EditBlock {\n const abs = resolve(rootDir, path);\n let search = \"\";\n if (existsSync(abs)) {\n try {\n search = readFileSync(abs, \"utf8\");\n } catch {\n search = \"\";\n }\n }\n return { path, search, replace: content, offset: 0 };\n}\n\nexport interface EditSnapshot {\n /** Path relative to rootDir, as the block named it. */\n path: string;\n /** `null` = file didn't exist; restore means delete. */\n prevContent: string | null;\n}\n\n/** De-duped by path — one \"before\" snapshot per file even with multiple blocks. */\nexport function snapshotBeforeEdits(blocks: EditBlock[], rootDir: string): EditSnapshot[] {\n const absRoot = resolve(rootDir);\n const seen = new Set<string>();\n const snapshots: EditSnapshot[] = [];\n for (const b of blocks) {\n if (seen.has(b.path)) continue;\n seen.add(b.path);\n const abs = resolve(absRoot, b.path);\n if (!existsSync(abs)) {\n snapshots.push({ path: b.path, prevContent: null });\n continue;\n }\n try {\n snapshots.push({ path: b.path, prevContent: readFileSync(abs, \"utf8\") });\n } catch {\n // Unreadable (permission / binary) — record null so we at least\n // don't pretend the snapshot is authoritative. The restore path\n // will treat null as \"delete on undo\", which is wrong in that\n // case but the file wasn't ours to begin with.\n snapshots.push({ path: b.path, prevContent: null });\n }\n }\n return snapshots;\n}\n\nexport function restoreSnapshots(snapshots: EditSnapshot[], rootDir: string): ApplyResult[] {\n const absRoot = resolve(rootDir);\n return snapshots.map((snap) => {\n const abs = resolve(absRoot, snap.path);\n if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep()}`)) {\n return {\n path: snap.path,\n status: \"path-escape\",\n message: \"snapshot path escapes rootDir — refusing to restore\",\n };\n }\n try {\n if (snap.prevContent === null) {\n if (existsSync(abs)) unlinkSync(abs);\n return {\n path: snap.path,\n status: \"applied\",\n message: \"removed (the edit had created it)\",\n };\n }\n writeFileSync(abs, snap.prevContent, \"utf8\");\n return {\n path: snap.path,\n status: \"applied\",\n message: \"restored to pre-edit content\",\n };\n } catch (err) {\n return { path: snap.path, status: \"error\", message: (err as Error).message };\n }\n });\n}\n\n/** Platform separator — `\\` on Windows, `/` elsewhere. */\nfunction sep(): string {\n return process.platform === \"win32\" ? \"\\\\\" : \"/\";\n}\n\nfunction lineEndingOf(text: string): string {\n return text.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n}\n"],"mappings":"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","names":["t","t","t","decision","fs","pathMod","picomatch","i","j","fs","pathMod","displayRel","walk","fs","pathMod","displayRel","walk","sep","displayRel","picomatch","fs","stat","walk","indent","t","isAbsolute","join","relative","resolve","resolve","walk","join","resolve","walk","join","relative","isAbsolute","fs","DEFAULT_MAX_RESULT_CHARS","DEFAULT_MAX_RESULT_CHARS","errorMessage","costUsd","t","existsSync","readFileSync","dirname","resolve","stat"]}
|