@livx.cc/agentx 0.99.43 → 0.99.45

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/logging.ts","../src/llm.ts","../src/redact.ts","../src/tools.structured.ts","../src/todo.ts","../src/tools.web.ts","../src/OverlayFilesystem.ts","../src/tools.ts","../src/NodeDiskFilesystem.ts","../src/JailedFilesystem.ts","../src/shell.sandbox.ts","../src/tools.shell.ts","../src/Agent.ts","../src/tools.jobs.ts","../src/host.ts","../src/relevance.ts","../src/frontmatter.ts","../src/commands.ts","../src/skills.ts","../src/memory.ts","../src/instructions.ts","../src/subagent.ts","../src/models.ts","../src/worktree.ts","../src/agents.ts","../src/permissions.ts","../src/lint.ts","../src/reasoning.ts","../src/index.ts","../src/BodDbFilesystem.ts","../src/MountFilesystem.ts","../src/speculate.ts","../src/synthesize.ts","../src/FakeAIClient.ts","../src/scheduler.ts","../src/presets.ts","../src/scratch.ts","../src/lessons.ts","../src/reflect.ts","../src/duplex.ts","../node_modules/@bod.ee/voice/src/core/logging.ts","../node_modules/@bod.ee/voice/src/core/emotion.ts","../node_modules/@bod.ee/voice/src/core/engine.ts","../node_modules/@bod.ee/voice/src/core/types.ts","../node_modules/@bod.ee/voice/src/core/spokenSplitter.ts","../node_modules/@bod.ee/voice/src/adapters/soniox.ts","../node_modules/@bod.ee/voice/src/adapters/cartesia.ts","../src/voice/engine.ts","../src/mcp.ts","../src/hooks.ts"],"sourcesContent":["// Import the log module directly from libx.js source: libx.js's main bundle\n// doesn't re-export `log` as a named ESM export, and source-importing keeps\n// libx.js patches live (no rebuild) — matching the `bun link` workflow.\nimport { log } from 'libx.js/src/modules/log';\n\n/** Component-scoped logger (libx.js). debug/verbose gated via DEBUG env/localStorage. */\nexport const forComponent = (name: string) => log.forComponent(name);\nexport { log };\n","/**\n * Wire types mirroring ai.libx.js (OpenAI-style chat). We type the transport\n * structurally via `ChatLike`, so an ai.libx.js `AIClient` is a drop-in — and a\n * `FakeAIClient` works in tests — with no hard runtime dependency on ai.libx.js.\n */\n\nimport { readFileSync, statSync, realpathSync } from 'node:fs';\nimport { resolve, sep } from 'node:path';\nimport { randomBytes } from 'node:crypto';\nimport { forComponent } from './logging';\n\nconst log = forComponent('llm');\n\nexport type Role = 'system' | 'user' | 'assistant' | 'tool';\n\nexport interface ToolCall {\n id: string;\n type: 'function';\n function: { name: string; arguments: string }; // arguments is a JSON string\n}\n\n/** One part of a multimodal message (mirrors ai.libx.js ContentPart) — text or an image URL/data-URI. */\nexport interface ContentPart {\n type: 'text' | 'image_url';\n text?: string;\n image_url?: { url: string };\n}\n\n/** A message's content is either plain text or an array of multimodal parts (images + text). */\nexport type MessageContent = string | ContentPart[];\n\nexport interface Message {\n role: Role;\n content: MessageContent;\n name?: string;\n tool_call_id?: string;\n tool_calls?: ToolCall[];\n}\n\n/** Flatten any message content to its text (string as-is; parts → concatenated text) — for length\n * estimation, summaries, and display. Non-text parts (images) contribute a short placeholder. */\nexport function contentText(content: MessageContent | undefined): string {\n if (content == null) return '';\n if (typeof content === 'string') return content;\n return content.map((p) => (p.type === 'text' ? (p.text ?? '') : '[image]')).join(p_sep(content));\n}\nconst p_sep = (parts: ContentPart[]): string => (parts.length > 1 ? '\\n' : '');\n\n/** Build an image content part from a data-URI or http(s) URL. */\nexport function imagePart(url: string): ContentPart {\n return { type: 'image_url', image_url: { url } };\n}\n\n/** Stub left when an inline data-URI image is elided from the stored transcript (RAM + disk). */\nexport const IMAGE_ELIDE_STUB = '[image elided — re-attach @path or /paste to view again]';\n\n/** True when content carries an inline base64 image (the heavy case — http(s) URLs are tiny). */\nexport function messageHasInlineImage(content: MessageContent | undefined): boolean {\n if (content == null || typeof content === 'string') return false;\n return content.some((p) => p.type === 'image_url' && (p.image_url?.url ?? '').startsWith('data:'));\n}\n\n/** Byte-weight for context budgeting — counts base64 payloads, not the `[image]` display placeholder. */\nexport function contentBytes(content: MessageContent | undefined): number {\n if (content == null) return 0;\n if (typeof content === 'string') return content.length;\n let n = 0;\n for (const p of content) {\n if (p.type === 'text') { n += (p.text ?? '').length; continue; }\n const url = p.image_url?.url ?? '';\n const ref = parseImageRef(url);\n // A ref is ~60 chars on disk but becomes the whole file on the wire IF it survives the send-time\n // window. Callers that budget the real payload run `expandImagesForSend` FIRST (Agent.trimContext)\n // or use `sendBytes` — this is the honest weight for a still-unexpanded ref.\n n += (ref ? ref.bytes : url.length) || 7;\n }\n return n;\n}\n\n/** Replace inline data-URI image parts with a text stub; http(s) URLs, image REFS and plain text\n * unchanged — a ref is ~60 bytes and stays re-expandable, so there is nothing to reclaim. */\nexport function elideInlineImages(content: MessageContent, stub = IMAGE_ELIDE_STUB): MessageContent {\n return elideImageParts(content, (url) => url.startsWith('data:'), stub);\n}\n\n/** Replace EVERY heavy image part — inline base64 AND refs — with the stub. This is the destructive\n * form used by the `/compact` elision ladder: a ref is cheap on disk but weighs its whole file on the\n * wire while it's inside the send window, so it must be shave-able or the ladder falls through to\n * shredding (then dropping) the user's own text. `elideInlineImages` stays the non-destructive form. */\nexport function elideImages(content: MessageContent, stub = IMAGE_ELIDE_STUB): MessageContent {\n return elideImageParts(content, (url) => url.startsWith('data:') || isImageRefUrl(url), stub);\n}\n\nfunction elideImageParts(content: MessageContent, hit: (url: string) => boolean, stub: string): MessageContent {\n if (typeof content === 'string') return content;\n let changed = false;\n const out: ContentPart[] = [];\n for (const p of content) {\n if (p.type !== 'image_url' || !hit(p.image_url?.url ?? '')) { out.push(p); continue; }\n changed = true;\n out.push({ type: 'text', text: stub });\n }\n return changed ? out : content;\n}\n\n/**\n * A persist-safe REFERENCE to an image FILE. Stored in the transcript (and the session JSON) instead\n * of the megabytes of base64 — `expandImagesForSend` turns it back into a data-URI in the OUTGOING\n * request only, so neither the heap nor the disk ever holds historical payloads.\n *\n * SECURITY: a ref is a CAPABILITY, not a path. The URL carries an unguessable token; the real path\n * lives only in this in-process registry, and only HOST code that already did the jail/permission\n * check can mint one (`mintImageRef`, used by the CLI's @image attach and the image `Read` tool).\n * Tool results are MODEL-CONTROLLED text (bash prints whatever it likes) — parsing a path out of them\n * could never be the authorization. An unknown/evicted token is simply not a ref: it degrades to the\n * elision stub, never a file read. That also covers a resumed session in a fresh process.\n * Shape stays inside `image_url.url` so old readers/serializers need no schema change:\n * `agentx-image:<mime>;<token>;<path>`\n * The trailing path is INERT BOOKKEEPING — `parseImageRef` never reads it, so it can't authorize\n * anything. It exists only so `remintImageRefs` can re-grant the capability on session load, after\n * re-checking the path against an allowed root (see there).\n */\nexport const IMAGE_REF_SCHEME = 'agentx-image:';\n\nexport interface ImageRef {\n mime: string;\n /** Absolute on-disk path. Never derived from model output — only from a mint-time capability. */\n path: string;\n /** base64 wire weight, stat'ed AT MINT TIME (so an overwritten-in-place path can never go stale). */\n bytes: number;\n}\n\n/** Bounded so a long session can't grow the registry without limit; oldest minted token is evicted\n * first (and an evicted ref degrades to the stub, exactly like a missing file). */\nconst REF_REGISTRY_MAX = 256;\nconst refRegistry = new Map<string, ImageRef>();\n\n/**\n * Mint an image-ref URL for an ALREADY-AUTHORIZED absolute path. Host-only: call this after the\n * jail/permission check, never on a path that came out of model output.\n */\nexport function mintImageRef(path: string, mime: string): string {\n const token = randomBytes(16).toString('hex');\n let bytes = 0;\n try { bytes = Math.ceil(statSync(path).size * 4 / 3); } // base64 expansion — what actually goes on the wire\n catch (e) { log.warn(`image ref stat failed, weighing as 0: ${path}`, e); }\n refRegistry.set(token, { mime, path, bytes });\n while (refRegistry.size > REF_REGISTRY_MAX) refRegistry.delete(refRegistry.keys().next().value as string);\n return `${IMAGE_REF_SCHEME}${mime};${token};${path}`;\n}\n\n/** Test/host hook: forget every minted ref (simulates a fresh process / resumed session). */\nexport function clearImageRefs(): void { refRegistry.clear(); }\n\n/** Build an image REFERENCE part for an authorized path. */\nexport function imageRefPart(path: string, mime: string): ContentPart {\n return { type: 'image_url', image_url: { url: mintImageRef(path, mime) } };\n}\n\n/** Does this URL claim to be an image ref? (Claim only — resolution is `parseImageRef`.) */\nconst isImageRefUrl = (url: string | undefined): boolean => !!url && url.startsWith(IMAGE_REF_SCHEME);\n\n/** Resolve an image-ref URL through the registry; null when it isn't one, or the token is unknown\n * (forged by the model, evicted, or from a previous process). NEVER trusts the URL's own text. */\nexport function parseImageRef(url: string | undefined): ImageRef | null {\n const parts = refUrlParts(url);\n const ref = parts && refRegistry.get(parts.token);\n if (!ref) { log.debug('image ref not in registry — treating as non-image text'); return null; }\n return ref;\n}\n\n/** Split a ref URL into its literal fields. `path` here is UNTRUSTED bookkeeping — never a capability. */\nfunction refUrlParts(url: string | undefined): { mime: string; token: string; path: string } | null {\n if (!isImageRefUrl(url)) return null;\n const rest = url!.slice(IMAGE_REF_SCHEME.length);\n const a = rest.indexOf(';');\n if (a < 0) return null;\n const b = rest.indexOf(';', a + 1);\n return { mime: rest.slice(0, a), token: b < 0 ? rest.slice(a + 1) : rest.slice(a + 1, b), path: b < 0 ? '' : rest.slice(b + 1) };\n}\n\n/**\n * Session LOAD: re-grant the capability for stored image parts whose token died with the previous\n * process, so a resumed session's recent screenshot is visible again (parity with the pre-ref\n * behaviour, where `elideStaleImages` kept the last inline image).\n *\n * A session file is WRITABLE BY THE MODEL (it can Write/Edit it, and the user may hand-edit it), so a\n * stored path is untrusted input — its provenance proves nothing. The ROOT CHECK is what makes this\n * safe: only a path whose REALPATH (symlinks resolved) sits inside one of `roots` is re-minted.\n * Anything else is left unresolvable and degrades to the elision stub, with a warn.\n *\n * Only image PARTS in user/assistant content are considered. Tool-result strings stay inert forever —\n * those are the model's own stdout and must never mint anything.\n * Pure view: returns a new array only when something changed.\n */\nexport function remintImageRefs(messages: Message[], roots: string[]): Message[] {\n const allowed: string[] = [];\n for (const r of roots) {\n try { allowed.push(realpathSync(resolve(r))); } catch (e) { log.debug(`image-ref root unavailable: ${r}`, e); }\n }\n if (allowed.length === 0) return messages;\n const inside = (p: string): boolean => allowed.some((root) => p === root || p.startsWith(root + sep));\n let changed = false;\n const out = messages.map((m) => {\n if ((m.role !== 'user' && m.role !== 'assistant') || typeof m.content === 'string' || m.content == null) return m;\n let touched = false;\n const parts = m.content.map((p) => {\n if (p.type !== 'image_url') return p;\n const f = refUrlParts(p.image_url?.url);\n if (!f || refRegistry.has(f.token)) return p; // not a ref, or still live in this process\n let real: string;\n try { real = realpathSync(f.path); } catch (e) { log.warn(`resumed image ref unreadable, will stub: ${f.path}`, e); return p; }\n if (!inside(real)) { log.warn(`resumed image ref outside the allowed roots, will stub: ${f.path} -> ${real}`); return p; }\n touched = true;\n return { type: 'image_url', image_url: { url: mintImageRef(real, f.mime) } } as ContentPart;\n });\n if (!touched) return m;\n changed = true;\n return { ...m, content: parts };\n });\n return changed ? out : messages;\n}\n\n/** True when content carries an image REF part (weightless on disk, expanded at send time). The\n * CLAIM is enough: an unresolvable ref (resumed session / evicted token) still counts as image-bearing\n * so the send path turns it into the stub instead of shipping the unresolvable scheme to the provider. */\nexport function messageHasImageRef(content: MessageContent | undefined): boolean {\n if (content == null || typeof content === 'string') return false;\n return content.some((p) => p.type === 'image_url' && isImageRefUrl(p.image_url?.url));\n}\n\n/** Any image at all — inline base64 (legacy sessions) or a ref. Drives `keepRecent` windows. */\nexport function messageHasImage(content: MessageContent | undefined): boolean {\n return messageHasInlineImage(content) || messageHasImageRef(content);\n}\n\n/** `Read` on an image persists this instead of the base64; expanded to `{dataUrl}` at send time.\n * `path` must already have passed the filesystem's jail check (see `mintImageRef`). */\nexport function imageRefResult(path: string, mime: string): string {\n return JSON.stringify({ imageRef: mintImageRef(path, mime), image: path });\n}\n\n/** The registered ref behind a tool message's `{\"imageRef\":…}` JSON body, if that's what it is.\n * A model-forged body parses fine but resolves to null — the token isn't in the registry. */\nexport function toolImageRef(content: MessageContent | undefined): ImageRef | null {\n if (typeof content !== 'string' || !content.startsWith('{\"imageRef\":')) return null;\n try { return parseImageRef(JSON.parse(content).imageRef); } catch (e) { log.debug('bad imageRef tool result', e); return null; }\n}\n\n/** Elide inline images from all but the most-recent `keepRecent` image-bearing messages (mutates copies). */\nexport function elideStaleImages(messages: Message[], keepRecent = 1): Message[] {\n const idx = messages.map((m, i) => (messageHasImage(m.content) ? i : -1)).filter((i) => i >= 0);\n const drop = new Set(idx.slice(0, Math.max(0, idx.length - keepRecent)));\n if (drop.size === 0) return messages;\n let changed = false;\n const out = messages.map((m, i) => {\n if (!drop.has(i)) return m;\n const c = elideInlineImages(m.content);\n if (c === m.content) return m;\n changed = true;\n return { ...m, content: c };\n });\n return changed ? out : messages;\n}\n\n/**\n * The send-time verdict per message index. User ATTACHMENTS and tool-result image `Read`s get\n * INDEPENDENT windows: an image the model Reads mid-turn must never evict the image the user just\n * pasted (the spec's non-goal — vision on the paste turn must keep working), and vice-versa.\n */\nfunction imageWindows(messages: Message[], keepRecent: number): Set<number> {\n const attach: number[] = [];\n const tool: number[] = [];\n messages.forEach((m, i) => {\n if (toolImageRef(m.content)) tool.push(i);\n else if (messageHasImage(m.content)) attach.push(i);\n });\n const k = Math.max(0, keepRecent);\n return new Set([...attach.slice(Math.max(0, attach.length - k)), ...tool.slice(Math.max(0, tool.length - k))]);\n}\n\n/** Is this message image-bearing at all (either kind)? */\nconst bearsImage = (m: Message): boolean => messageHasImage(m.content) || toolImageRef(m.content) != null;\n\n/**\n * SEND-PATH expansion: image REFS become real data-URIs only in the outgoing request, and only for the\n * most-recent `keepRecent` messages of EACH kind (user attachment / tool image Read) — older ones (refs\n * AND legacy inline base64) collapse to the elision stub. Pure view: the caller's messages are never mutated.\n * A missing/unreadable file (or an unregistered ref) degrades to the same stub and is LOGGED — never throws.\n */\nexport function expandImagesForSend(messages: Message[], keepRecent = 1, stub = IMAGE_ELIDE_STUB): Message[] {\n if (!messages.some(bearsImage)) return messages;\n const keep = imageWindows(messages, keepRecent);\n let changed = false;\n const out = messages.map((m, i) => {\n const content = keep.has(i) ? expandContent(m.content, stub) : stripContent(m.content, stub);\n if (content === m.content) return m;\n changed = true;\n return { ...m, content };\n });\n return changed ? out : messages;\n}\n\n/**\n * Byte-weight of a transcript AS IT WILL GO ON THE WIRE — refs inside the keep window weigh their\n * file's base64 size, everything stale weighs the stub — WITHOUT materializing a single byte of\n * base64. This is the honest number for `/context` and the CLI footer, where the old behaviour made\n * every historical screenshot immortal and produced false \"90% full\" warnings.\n */\nexport function sendBytes(messages: Message[], keepRecent = 1, stub = IMAGE_ELIDE_STUB): number {\n let n = 0;\n for (const b of sendBytesPer(messages, keepRecent, stub)) n += b;\n return n;\n}\n\n/** `sendBytes` split per message — same window, same weights. Lets a budgeter drop/shave message-by-\n * message without re-deriving the window (and without charging a stale ref its file weight). */\nexport function sendBytesPer(messages: Message[], keepRecent = 1, stub = IMAGE_ELIDE_STUB): number[] {\n const keep = messages.some(bearsImage) ? imageWindows(messages, keepRecent) : null;\n return messages.map((m, i) =>\n wireBytes(m.content, keep == null || keep.has(i), stub) + (m.tool_calls ? JSON.stringify(m.tool_calls).length : 0));\n}\n\n/** contentBytes, but aware of whether this message's images survive the send-time window. */\nfunction wireBytes(content: MessageContent | undefined, kept: boolean, stub: string): number {\n const tool = toolImageRef(content);\n if (tool) return kept ? tool.bytes : stub.length;\n if (content == null || typeof content === 'string') return contentBytes(content);\n if (kept) return contentBytes(content);\n let n = 0;\n for (const p of content) {\n if (p.type === 'text') { n += (p.text ?? '').length; continue; }\n const url = p.image_url?.url ?? '';\n n += url.startsWith('data:') || isImageRefUrl(url) ? stub.length : url.length || 7;\n }\n return n;\n}\n\n/** Read a referenced image as a data-URI; null (logged) when the file is gone/unreadable. */\nfunction readRefDataUrl(ref: ImageRef): string | null {\n try { return `data:${ref.mime};base64,${readFileSync(ref.path).toString('base64')}`; }\n catch (e) { log.warn(`image ref unreadable, sending stub instead: ${ref.path}`, e); return null; }\n}\n\n/** Refs → data-URIs (tool `{imageRef}` bodies → the `{dataUrl}` shape the wire adapter renders). */\nfunction expandContent(content: MessageContent, stub: string): MessageContent {\n const tool = toolImageRef(content);\n if (tool) {\n const url = readRefDataUrl(tool);\n return url ? JSON.stringify({ dataUrl: url, image: tool.path }) : stub;\n }\n if (typeof content === 'string') return content;\n let changed = false;\n const out = content.map((p) => {\n if (p.type !== 'image_url' || !isImageRefUrl(p.image_url?.url)) return p;\n changed = true;\n // Unresolvable (resumed session / evicted token) → stub. Content PARTS are host-authored, so an\n // unknown one is a lost capability, not model text — and the scheme must never reach the provider.\n const ref = parseImageRef(p.image_url?.url);\n const url = ref && readRefDataUrl(ref);\n return url ? imagePart(url) : ({ type: 'text', text: stub } as ContentPart);\n });\n return changed ? out : content;\n}\n\n/** Stale image-bearing content as it goes on the wire: no base64, no ref the provider can't resolve. */\nfunction stripContent(content: MessageContent, stub: string): MessageContent {\n if (toolImageRef(content)) return stub;\n if (typeof content === 'string') return content;\n let changed = false;\n const out = content.map((p) => {\n const url = p.type === 'image_url' ? (p.image_url?.url ?? '') : '';\n if (!url.startsWith('data:') && !isImageRefUrl(url)) return p;\n changed = true;\n return { type: 'text', text: stub } as ContentPart;\n });\n return changed ? out : content;\n}\n\nexport interface Tool {\n type: 'function';\n function: { name: string; description?: string; parameters: object };\n}\n\nexport interface ChatResponse {\n content: string;\n finishReason?: string;\n toolCalls?: ToolCall[];\n model?: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n /** Tools a self-executing runtime (cursor/claude-code) ran inside its OWN loop — correlated from\n * the display-only `toolActivity` stream. Not dispatched by us; persisted so the transcript keeps\n * a faithful record (audit + resume) instead of being narration-only. */\n delegatedTools?: { id: string; name: string; input?: unknown; output?: unknown; status: 'running' | 'completed' | 'error' }[];\n /** A delegated runtime (cursor/claude-code) ran tools this turn but never CLOSED it: either no assistant\n * text followed the last tool (it went silent post-work), or the text it did emit ends on an action it\n * announced and never took. Signals the loop's closure reflex (see AgentOptions.closeDelegatedTurns). */\n endedWithoutClosing?: boolean;\n}\n\n/**\n * Does this assistant text end mid-plan — on an action the model ANNOUNCED but never took?\n *\n * Cursor/composer narrates as it works (\"Searching the codebase…\", \"Also checking for X\"), and its run\n * can settle FINISHED while the narration is still mid-plan. The turn then looks closed (finishReason\n * 'stop', text present) but delivered no answer. Measured over the local cursor session corpus: ~4.6%\n * of tool-using turns end this way.\n *\n * Matches only FIRST-PERSON commitments (\"Let me…\", \"I'll…\", \"I need to…\") and progressive narration\n * (\"Checking…\", \"Expanding…\"). Deliberately excludes \"Next step: …\" / \"Next run will…\" and \"Let me know\n * if…\" — those are legitimate things to say TO the user, and nudging them would talk over a finished\n * answer. A false positive costs one extra step, so the rule stays conservative rather than clever.\n *\n * The two arms are deliberately scoped differently:\n *\n * COMMITMENT — first-person SINGULAR \"I'll / let me / I'm going to\", plus the one obligation form the\n * corpus actually stalled on: \"I need to…\". These carry their own subject and tense, so they stay\n * unambiguous anywhere in the sentence and may be matched clause-by-clause — the observed stuck turn\n * hid its commitment in a trailing \"…, so I need to verify …\" clause. Past-tense reports of the same\n * (\"I needed to\") are excluded: they describe work already reasoned about, not work still pending.\n * Second person (\"you'll need to…\") is excluded — that is a recommendation to the user.\n *\n * Deliberately NOT matched: \"we …\" and the softer obligations \"should / must / have to / want to\".\n * They read as recommendations TO the user on a FINISHED answer (\"All tests pass. We should be good to\n * go.\", \"I have to admit, the numbers were surprising.\"), the same category as the NEXT_STEP and\n * SIGN_OFF carve-outs — and nudging a finished answer spends a metered step talking over it. No turn in\n * the corpus needed them, so the conservative bias keeps them out.\n *\n * PROGRESSIVE — a bare gerund (\"Checking the images…\") is only a commitment at the HEAD of the final\n * sentence. Mid-sentence it is almost always a participial modifier of a COMPLETED action\n * (\"I pruned the cache, reclaiming 2.6 GB\"), so it is not matched clause-wise.\n */\nconst COMMITMENT =\n /^(?:also\\s+|now\\s+|then\\s+|so\\s+)*(?:let me\\b(?!\\s+know\\b)|i'?ll\\b|i will\\b|i'?m going to\\b|i\\s+(?:still\\s+|now\\s+|first\\s+)*need to\\b)/i;\nconst PROGRESSIVE =\n /^(?:also\\s+|now\\s+|then\\s+)*(?:re-?)?(?:check|search|scan|read|verify|run|inspect|expand|look|examin|continu|proceed|try|fetch|load|open|test|build|grep|find|review|trac|dig|explor)\\w*ing\\b/i;\nconst NEXT_STEP = /^next (?:step|run|up)\\b/i;\n// \"Let me know if…\" is a SIGN-OFF, not an announced action. It only ever reached the `let me\\b` arm on\n// delegated turns before; once the sawTool gate is dropped (announce-and-stop turns run no tools at all)\n// it would fire on every polite closing line, so exclude it explicitly (in COMMITMENT and here).\nconst SIGN_OFF = /^let me know\\b/i;\n\n/** Split a sentence into clauses at punctuation and coordinators, so a trailing commitment is visible. */\nfunction clauses(sentence: string): string[] {\n return sentence\n .split(/[,;:]\\s*|\\s+(?:so|but|and|then|because|however|therefore|thus|although|though)\\s+/i)\n .map((c) => c.trim())\n .filter(Boolean);\n}\n\nexport function endsOnAnnouncedAction(text: string): boolean {\n const sentences = text.split(/(?<=[.!?])\\s+|\\n+/).map((s) => s.trim()).filter(Boolean);\n const last = sentences[sentences.length - 1];\n if (!last || NEXT_STEP.test(last) || SIGN_OFF.test(last)) return false;\n if (PROGRESSIVE.test(last)) return true;\n return clauses(last).some((c) => !NEXT_STEP.test(c) && !SIGN_OFF.test(c) && COMMITMENT.test(c));\n}\n\n/**\n * One incremental event from a streamed `chat({stream:true})` call — mirrors\n * ai.libx.js's `StreamChunk` (OpenAI-style): each chunk carries a `content`\n * text delta; the terminal chunk carries `finishReason` and the accumulated\n * `toolCalls`. Consuming the stream and folding the deltas reconstructs the\n * same `ChatResponse` the non-stream path returns.\n */\nexport interface StreamChunk {\n content: string;\n finishReason?: string;\n index?: number;\n toolCalls?: ToolCall[]; // accumulated tool calls (typically on the final chunk)\n reasoningContent?: string;\n /** Display-only tool activity from a self-executing backend (Cursor CLI) — surfaced as a host\n * `tool_activity` event, never dispatched. Mirrors ai.libx.js's StreamChunk.toolActivity. */\n toolActivity?: { id?: string; name: string; input?: unknown; output?: unknown; status: 'running' | 'completed' | 'error'; truncated?: { args?: boolean; result?: boolean } };\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number }; // on the terminal chunk, when the provider reports it\n}\n\nexport interface ChatOptions {\n model: string;\n messages: Message[];\n tools?: Tool[];\n toolChoice?: unknown;\n stream?: boolean;\n /** Cancel the request/stream. Forwarded to providers that honor it; the Agent also stops consuming on abort. */\n signal?: AbortSignal;\n [k: string]: unknown;\n}\n\n/** Minimal shape of an ai.libx.js AIClient that the Agent drives. */\nexport interface ChatLike {\n chat(options: ChatOptions): Promise<ChatResponse | AsyncIterable<StreamChunk>>;\n}\n","/**\n * Mask secret-looking values in arbitrary text before it reaches the model.\n *\n * Two complementary seams use this: real-shell output (`cat .env`, `printenv`) and the\n * `Read` tool (so provider keys stored in `.agent/settings.json` are usable-but-masked).\n * The FS jail hides whole secret FILES by name; this hides secret VALUES wherever they\n * surface in otherwise-legitimate content.\n *\n * Both regexes are linear (no nested quantifiers) — safe against catastrophic backtracking\n * and cheap enough to run on every tool output (see tests/redact.bench).\n */\n\nexport const REDACTED = '‹redacted›';\n\n/** Config/control files that may carry provider keys — readers (Read/Grep) mask secret VALUES in\n * these while keeping the rest readable. (Whole secret FILES like .env are hidden by the FS jail.) */\nexport const CONFIG_FILE_RE = /(^|\\/)\\.(agent|claude)\\/(settings(\\.[\\w-]+)?\\.json|config\\.(json|js|mjs|cjs|ts))$/i;\n\n// (A) `NAME=value` / `\"name\": \"value\"` pairs where NAME looks like a secret. Masks the value only,\n// so the agent still sees WHICH key exists (useful config context) without the secret itself.\nconst SECRET_PAIR =\n /((?:^|[\\s,{[])(?:export\\s+)?[\"']?[\\w.\\-]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|PRIVATE_KEY|ACCESS_?KEY|AUTH(?:_?TOKEN)?|BEARER)[\\w.\\-]*[\"']?\\s*[:=]\\s*)([\"']?)([^\\s\"',{}\\]]+)/gi;\n\n// (B) Bare tokens by well-known shape — catches secrets that appear without an obvious key\n// (Authorization headers, URLs, JSON dumps). Conservative prefixes to avoid false positives.\nconst SECRET_TOKEN =\n /\\b(sk-ant-[\\w-]{12,}|sk-[A-Za-z0-9]{20,}|ghp_[A-Za-z0-9]{20,}|gho_[A-Za-z0-9]{20,}|github_pat_[\\w]{20,}|xox[baprs]-[\\w-]{10,}|AKIA[0-9A-Z]{12,}|AIza[\\w-]{20,}|eyJ[\\w-]{8,}\\.[\\w-]{8,}\\.[\\w-]{8,})\\b/g;\n\n/** Return `text` with secret values masked. Cheap no-op when nothing matches. */\nexport function redactSecrets(text: string): string {\n if (!text) return text;\n return text\n .replace(SECRET_PAIR, (_m, head, quote, _val) => `${head}${quote}${REDACTED}`)\n .replace(SECRET_TOKEN, REDACTED);\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { AgentTool, ToolContext } from './tools';\nimport type { ChatResponse } from './llm';\nimport { redactSecrets, CONFIG_FILE_RE } from './redact';\n\n/**\n * Structured file tools — typed results straight from the VFS, no `bash` parsing.\n * These close the efficiency gap to Claude Code (its Grep/Glob/Write return one\n * structured result where our agent otherwise drives find/grep pipelines and re-reads).\n * Backend-agnostic: pure IFilesystem walks, so they run on Mem/Disk/IndexedDb alike.\n */\n\n/** Throw the moment a run is cancelled, so a long file walk/scan bails instead of pegging the CPU\n * uninterruptibly. dispatch() catches the throw → the run loop sees `aborted` and ends the turn. */\nfunction ckAbort(signal?: AbortSignal): void {\n if (signal?.aborted) throw new Error('aborted');\n}\n\n/**\n * Directory names never worth walking. Pruned by NAME at every level (not by path), because the\n * cost is where they nest: a real-FS root of a JS deployment is mostly `node_modules`, and on a\n * measured 412k-file app root a single `Glob` spent 31s almost entirely inside it.\n */\nexport const DEFAULT_SKIP_DIRS = ['node_modules', '.git', 'dist', '.tmp'];\n\n/** Depth below a root at which the walk stops. Deep enough for any real source tree; a bound at all\n * is what turns a symlink cycle from a hang into a truncated result. */\nexport const DEFAULT_MAX_DEPTH = 24;\n\n/** How the file-scanning tools (Glob/Grep) decide WHAT to walk. */\nexport interface FileScanOptions {\n /** Roots to walk when a call names no `path`. Default: `[fs.getCwd()]`, i.e. today's behaviour.\n * A host with its data outside the cwd passes both, so a search can reach it at all. */\n roots?: string[];\n /** Directory names pruned during the walk. Default: {@link DEFAULT_SKIP_DIRS}. */\n skipDirs?: string[];\n /** Max depth below each root. Default: {@link DEFAULT_MAX_DEPTH}. */\n maxDepth?: number;\n}\n\ninterface WalkState {\n skip: Set<string>;\n maxDepth: number;\n /** Real paths already visited — the cycle/duplication guard. A `vendor` symlink pointing back\n * into the tree (or `node_modules/.bin`) otherwise re-walks the same subtree repeatedly.\n * PER ROOT, not shared: with one shared set a second root that is a symlink to (or into) the\n * first is \"already seen\" and silently yields nothing — the caller asked for a place and got an\n * empty answer, which is the absent-vs-unreachable confusion this file is trying to kill. */\n seen: Set<string>;\n /** Directory names actually pruned, and depth cuts actually made — reported to the caller, never\n * swallowed: a walk that refused to look somewhere must say so, or `(no matches)` is a lie. */\n prunedDirs: Set<string>;\n depthCuts: number;\n}\n\n/** `canonicalPath` (symlinks resolved) is an optional capability on disk-backed filesystems; on\n * backends without it the VFS path IS the identity, so it is its own canonical form. Note it must\n * be the symlink-resolving one: `realPath` is path arithmetic and reports a link and its target as\n * two different places, which cannot break a cycle. */\nfunction realOf(fs: IFilesystem, p: string): string {\n const rp = (fs as { canonicalPath?: (path: string) => string }).canonicalPath;\n if (typeof rp !== 'function') return p;\n try { return rp.call(fs, p) || p; } catch { return p; }\n}\n\n/** Recursively list every file path under `dir` (VFS-absolute), depth-first, sorted. Cancellable:\n * a cancelled run throws between entries so a huge tree walk (real-FS disk mode) doesn't wedge.\n * Prunes {@link DEFAULT_SKIP_DIRS}, bounds depth, and never enters the same real dir twice. */\nasync function walkFiles(fs: IFilesystem, dir: string, signal?: AbortSignal, out: string[] = [], st?: WalkState, depth = 0): Promise<string[]> {\n const state: WalkState = st ?? { skip: new Set(DEFAULT_SKIP_DIRS), maxDepth: DEFAULT_MAX_DEPTH, seen: new Set(), prunedDirs: new Set(), depthCuts: 0 };\n if (depth > state.maxDepth) { state.depthCuts++; return out; }\n const real = realOf(fs, dir);\n if (state.seen.has(real)) return out;\n state.seen.add(real);\n let entries: string[];\n try { entries = await fs.readDir(dir); } catch { return out; }\n for (const name of entries.sort()) {\n ckAbort(signal);\n if (state.skip.has(name)) { state.prunedDirs.add(name); continue; }\n const p = dir === '/' ? `/${name}` : `${dir}/${name}`;\n if (await fs.isDirectory(p)) await walkFiles(fs, p, signal, out, state, depth + 1);\n else out.push(p);\n }\n return out;\n}\n\n/** The roots a call actually walks: an explicit `path` wins, else the configured roots, else the\n * cwd. Nested roots are collapsed — walking `/a` and `/a/b` would double-report everything in b. */\nfunction scanRoots(fs: IFilesystem, path: unknown, opts?: FileScanOptions): string[] {\n const asked = path == null ? [] : (Array.isArray(path) ? path : [path]).map((p) => String(p)).filter(Boolean);\n const roots = (asked.length ? asked : (opts?.roots?.length ? opts.roots : [fsCwd(fs)])).map((r) => (r.length > 1 && r.endsWith('/') ? r.slice(0, -1) : r));\n return [...new Set(roots)].filter((r, _i, all) => !all.some((other) => other !== r && r.startsWith(`${other}/`)));\n}\n\n/** What a walk refused to look at — appended to results so a pruned/truncated search never reads\n * as an exhaustive one. Mirrors Grep's existing \"skipped N unreadable files\" note. */\nfunction scanNote(states: WalkState[]): string {\n const pruned = [...new Set(states.flatMap((st) => [...st.prunedDirs]))].sort();\n const cuts = states.reduce((n, st) => n + st.depthCuts, 0);\n const parts: string[] = [];\n if (pruned.length) parts.push(`skipped ${pruned.join(', ')} (pass skipDirs to include them)`);\n if (cuts) parts.push(`stopped at depth ${states[0]?.maxDepth} in ${cuts} place${cuts === 1 ? '' : 's'} (pass maxDepth to go deeper)`);\n return parts.length ? `\\n[scan: ${parts.join('; ')}]` : '';\n}\n\n/** Walk every root once, with the configured prune/depth/cycle guards. Per-call `skipDirs`/`maxDepth`\n * override the construction-time ones, so a consumer of the default singletons is never stuck with\n * a prune it needs to see past (`Glob '**\\/dist/*'`, a `.tmp/` workspace). */\nasync function walkRoots(\n fs: IFilesystem, roots: string[], signal: AbortSignal | undefined, opts?: FileScanOptions, call?: FileScanOptions,\n): Promise<{ files: string[]; note: string }> {\n const skip = new Set(call?.skipDirs ?? opts?.skipDirs ?? DEFAULT_SKIP_DIRS);\n const maxDepth = call?.maxDepth ?? opts?.maxDepth ?? DEFAULT_MAX_DEPTH;\n const out: string[] = [];\n const states: WalkState[] = [];\n for (const root of roots) {\n // A fresh `seen` per root: cross-root dedupe belongs to the RESULT (callers Set-dedupe), not to\n // the walk, where it silently erases a whole root that aliases another.\n const state: WalkState = { skip, maxDepth, seen: new Set(), prunedDirs: new Set(), depthCuts: 0 };\n states.push(state);\n await walkFiles(fs, root, signal, out, state, 0);\n }\n return { files: out, note: scanNote(states) };\n}\n\n/** Per-call scan overrides, parsed from tool args. */\nfunction callScan(args: { skipDirs?: unknown; maxDepth?: unknown }): FileScanOptions {\n const sd = args.skipDirs;\n return {\n skipDirs: Array.isArray(sd) ? sd.map(String) : typeof sd === 'string' ? sd.split(',').map((x) => x.trim()).filter(Boolean) : undefined,\n maxDepth: args.maxDepth == null ? undefined : Number(args.maxDepth),\n };\n}\n\nconst SCAN_PARAMS = {\n path: { type: 'string', description: 'optional directory (or list) to search instead of the default roots; absolute VFS path' },\n skipDirs: { type: 'string', description: `comma-separated directory names to prune (default: ${DEFAULT_SKIP_DIRS.join(', ')}); pass an empty string to prune nothing` },\n maxDepth: { type: 'number', description: `max directory depth below each root (default ${DEFAULT_MAX_DEPTH})` },\n} as const;\n\n/** Anchor a relative glob at a specific root (an absolute pattern anchors to itself). Per-ROOT, not\n * per-cwd: with two roots, anchoring `**\\/*.md` at the cwd alone would silently match nothing in\n * the other one — the \"search can't reach it, so it reports absent\" failure this all exists for. */\nfunction anchoredGlobAt(root: string, glob: string): RegExp {\n if (glob.startsWith('/')) return globToRegExp(glob);\n return globToRegExp(`${root === '/' ? '' : root}/${glob}`);\n}\n\n/** A path/scope matcher over several roots: matches if the pattern matches when anchored at ANY. */\nfunction globMatcher(roots: string[], glob: string): (p: string) => boolean {\n const res = roots.map((r) => anchoredGlobAt(r, glob));\n return (p: string) => res.some((re) => re.test(p));\n}\n\n/**\n * Translate a glob (`**`, `*`, `?`) into an anchored RegExp over VFS-absolute paths.\n * `caseInsensitive` is used by the JailedFilesystem denylist so `/.ENV` can't slip past\n * a `.env` rule (file-matching tools keep the default case-sensitive behavior).\n */\nexport function globToRegExp(glob: string, caseInsensitive = false): RegExp {\n const g = glob.startsWith('/') ? glob : `/${glob}`;\n let re = '';\n for (let i = 0; i < g.length; i++) {\n const c = g[i];\n if (c === '*') {\n if (g[i + 1] === '*') { re += '.*'; i++; if (g[i + 1] === '/') i++; }\n else re += '[^/]*';\n } else if (c === '?') re += '[^/]';\n else re += c.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n }\n return new RegExp(`^${re}$`, caseInsensitive ? 'i' : '');\n}\n\n/** The dir structured tools walk/anchor at — the FS's working dir. Keeps Glob/Grep/RepoMap scoped\n * to the project (or, in CC-parity disk mode where root '/' is the real machine, the launch dir)\n * instead of crawling the whole filesystem. Backward-compatible: Mem/jailed-at-cwd backends report '/'. */\nconst fsCwd = (fs: IFilesystem): string => fs.getCwd();\n\n/** Compile a glob, resolving a relative pattern under the FS cwd (mirrors a shell's cwd-relative globs).\n * Absolute patterns are used as-is. With cwd '/' this is identical to the old `/`-anchored behavior. */\nfunction anchoredGlob(fs: IFilesystem, glob: string): RegExp {\n const cwd = fsCwd(fs);\n const base = cwd === '/' ? '' : cwd;\n return globToRegExp(glob.startsWith('/') ? glob : `${base}/${glob}`);\n}\n\n/** List paths matching a glob, sorted — the structured alternative to `find`. */\nexport function makeGlobTool(opts?: FileScanOptions): AgentTool {\n return {\n name: 'Glob',\n description:\n 'Find files by glob pattern (e.g. \"**/*.ts\", \"src/**/*.test.ts\"). Returns sorted paths, one per line. ' +\n 'Space-separated patterns combine; `!`-prefix excludes (e.g. \"**/*.ts !**/*.test.ts\"). Optional `path` to search a specific directory. Prefer over `bash find` for locating files — one call, structured output.',\n parameters: {\n type: 'object',\n required: ['pattern'],\n properties: {\n pattern: { type: 'string', description: 'glob pattern(s); ** matches across directories; prefix a pattern with ! to exclude' },\n ...SCAN_PARAMS,\n },\n },\n async run({ pattern, path, skipDirs, maxDepth }, ctx) {\n const roots = scanRoots(ctx.fs, path, opts);\n const pats = String(pattern ?? '').trim().split(/\\s+/).filter(Boolean);\n const include = pats.filter((p) => !p.startsWith('!')).map((p) => globMatcher(roots, p));\n const exclude = pats.filter((p) => p.startsWith('!')).map((p) => globMatcher(roots, p.slice(1)));\n const includes = include.length ? include : [globMatcher(roots, '**')]; // only-excludes → start from everything\n const { files, note } = await walkRoots(ctx.fs, roots, ctx.signal, opts, callScan({ skipDirs, maxDepth }));\n const hits = files.filter((p) => includes.some((m) => m(p)) && !exclude.some((m) => m(p)));\n return (hits.length ? [...new Set(hits)].sort().join('\\n') : '(no matches)') + note;\n },\n };\n}\n\n/** Search file contents by regex, returning typed `path:line:text` hits with optional context. */\nexport function makeGrepTool(opts?: FileScanOptions): AgentTool {\n return {\n name: 'Grep',\n description:\n 'Search file contents by regex. Returns `path:line: text` hits. Optional `glob` to scope files, `path` to search a specific directory, `context` for surrounding lines, `filesOnly` for matching paths only. Prefer over `bash grep` for file content search — structured results, no re-parse needed. Use `bash` instead for running commands, tests, or piped workflows.',\n parameters: {\n type: 'object',\n required: ['pattern'],\n properties: {\n pattern: { type: 'string', description: 'JS regular expression' },\n glob: { type: 'string', description: 'optional file glob to restrict the search' },\n ...SCAN_PARAMS,\n context: { type: 'number', description: 'lines of context before/after each hit' },\n filesOnly: { type: 'boolean', description: 'only list matching file paths' },\n },\n },\n async run({ pattern, glob, path, skipDirs, maxDepth, context, filesOnly }, ctx) {\n let re: RegExp;\n try { re = new RegExp(String(pattern ?? '')); } catch (e) { throw new Error(`invalid regex: ${String(e)}`); }\n const roots = scanRoots(ctx.fs, path, opts);\n const scope = glob ? globMatcher(roots, String(glob)) : null;\n const walked = await walkRoots(ctx.fs, roots, ctx.signal, opts, callScan({ skipDirs, maxDepth }));\n const files = [...new Set(walked.files)].sort().filter((p) => !scope || scope(p));\n const ctxN = Math.max(0, Number(context ?? 0));\n const out: string[] = [];\n const matched: string[] = [];\n let skipped = 0; // unreadable files (permissions, races) — surfaced, not silently dropped\n for (const path of files) {\n ckAbort(ctx.signal); // cancellable per-file: a wide grep over a big tree stops on Esc, not after\n let content: string;\n try { content = await ctx.fs.readFile(path); } catch { skipped++; continue; }\n const lines = content.split('\\n');\n const mask = CONFIG_FILE_RE.test(path); // mask secret values from config files in the hits\n let fileHit = false;\n for (let i = 0; i < lines.length; i++) {\n if (!re.test(lines[i])) continue;\n fileHit = true;\n if (filesOnly) break;\n const lo = Math.max(0, i - ctxN), hi = Math.min(lines.length - 1, i + ctxN);\n for (let j = lo; j <= hi; j++) out.push(`${path}:${j + 1}: ${mask ? redactSecrets(lines[j]) : lines[j]}`);\n }\n if (fileHit) matched.push(path);\n }\n const note = (skipped ? `\\n[skipped ${skipped} unreadable file${skipped === 1 ? '' : 's'}]` : '') + walked.note;\n if (filesOnly) return (matched.length ? matched.join('\\n') : '(no matches)') + note;\n return (out.length ? out.join('\\n') : '(no matches)') + note;\n },\n };\n}\n\n/** Default instances — cwd-rooted, standard prunes. Hosts that need other roots build their own. */\nexport const globTool: AgentTool = makeGlobTool();\nexport const grepTool: AgentTool = makeGrepTool();\n\n/** A line is a top-level declaration worth showing in the repo map. */\nconst SIG_RE = /^\\s*(export\\b|(?:export\\s+)?(?:async\\s+)?function\\s+\\*?\\w|(?:export\\s+)?(?:abstract\\s+)?class\\s+\\w|(?:export\\s+)?interface\\s+\\w|(?:export\\s+)?type\\s+\\w|(?:export\\s+)?enum\\s+\\w)/;\nconst isCode = (p: string) => /\\.(ts|tsx|js|jsx|mjs|cjs)$/.test(p);\nconst isDoc = (p: string) => /\\.(md|mdx|txt)$/.test(p);\n\n/** Extract heading hierarchy + first-paragraph summaries from a markdown file. */\nfunction docOutlineOf(content: string, cap = 20): string[] {\n const out: string[] = [];\n const lines = content.split('\\n');\n for (let i = 0; i < lines.length && out.length < cap; i++) {\n const hm = lines[i].match(/^(#{1,4})\\s+(.+)/);\n if (hm) {\n out.push(hm[0].slice(0, 120));\n for (let j = i + 1; j < lines.length; j++) {\n const l = lines[j].trim();\n if (!l) continue;\n if (l.startsWith('#')) break;\n out.push(' ' + l.slice(0, 120));\n break;\n }\n }\n }\n return out;\n}\n\n/** One file's exported/top-level signatures (no bodies), capped. */\nfunction signaturesOf(content: string, cap = 40): string[] {\n const out: string[] = [];\n for (const line of content.split('\\n')) {\n if (!SIG_RE.test(line)) continue;\n let sig = line.trim();\n const brace = sig.indexOf('{');\n if (brace > 0) sig = sig.slice(0, brace).trim(); // drop the body\n sig = sig.replace(/\\s*=>?\\s*$/, '').replace(/=\\s*$/, '').slice(0, 120);\n if (sig && !out.includes(sig)) out.push(sig);\n if (out.length >= cap) break;\n }\n return out;\n}\n\n/**\n * Compact map of a VFS — code signatures and/or doc outlines. Edge-safe (pure IFilesystem walk).\n * `mode`: \"code\" (default) = top-level signatures; \"docs\" = heading outlines; \"all\" = both.\n */\nexport async function repoIndex(fs: IFilesystem, glob?: string, mode: 'code' | 'docs' | 'all' = 'code', signal?: AbortSignal): Promise<string> {\n const scope = glob ? anchoredGlob(fs, String(glob)) : null;\n const filter = mode === 'code' ? isCode : mode === 'docs' ? isDoc : (p: string) => isCode(p) || isDoc(p);\n const files = (await walkFiles(fs, fsCwd(fs), signal)).filter((p) => (scope ? scope.test(p) : filter(p)));\n const blocks: string[] = [];\n let shown = 0;\n for (const path of files) {\n ckAbort(signal);\n let content: string;\n try { content = await fs.readFile(path); } catch { continue; }\n const entries = isDoc(path) ? docOutlineOf(content) : signaturesOf(content);\n if (entries.length) { blocks.push(`${path}\\n${entries.map((s) => ' ' + s).join('\\n')}`); shown += entries.length; }\n if (shown >= 400) { blocks.push('… (map truncated; narrow with `glob`)'); break; }\n }\n const label = mode === 'code' ? 'code signatures' : mode === 'docs' ? 'document outlines' : 'entries';\n return blocks.length ? blocks.join('\\n') : `(no ${label} found)`;\n}\n\n/** Compact map of the codebase or document workspace — orient in ONE call, not many. */\nexport const repoMapTool: AgentTool = {\n name: 'RepoMap',\n description:\n 'Get a compact map of the workspace: code signatures and/or document outlines in ONE call. `scope`: \"code\" (default) = functions/classes/types; \"docs\" = markdown headings + summaries; \"all\" = both. Call once to orient before diving into specific files — avoids many exploratory Glob/Read calls.',\n parameters: {\n type: 'object',\n properties: {\n glob: { type: 'string', description: 'optional file glob to scope (default: all matching files)' },\n scope: { type: 'string', enum: ['code', 'docs', 'all'], description: 'what to map: \"code\" (default), \"docs\", or \"all\"' },\n },\n },\n run: ({ glob, scope }, ctx) => repoIndex(ctx.fs, glob, scope || 'code', ctx.signal),\n};\n\n/**\n * Whitespace-tolerant fallback for Edit: locate `oldStr` in `content` ignoring each line's\n * leading/trailing whitespace, and replace the UNIQUE matching region with `newStr`. Returns\n * null if there isn't exactly one match (caller then errors, forcing a re-read) — so it never\n * guesses. This kills the common re-Read+retry cascade when an exact Edit fails on indentation drift.\n */\nexport function fuzzyLineReplace(content: string, oldStr: string, newStr: string): string | null {\n const norm = (s: string) => s.trim();\n const cl = content.split('\\n');\n const ol = oldStr.split('\\n').map(norm);\n while (ol.length && ol[ol.length - 1] === '') ol.pop();\n while (ol.length && ol[0] === '') ol.shift();\n if (!ol.length) return null;\n const matches: number[] = [];\n for (let i = 0; i + ol.length <= cl.length; i++) {\n let ok = true;\n for (let j = 0; j < ol.length; j++) if (norm(cl[i + j]) !== ol[j]) { ok = false; break; }\n if (ok) matches.push(i);\n }\n if (matches.length !== 1) return null; // not found, or ambiguous → don't guess\n const i = matches[0];\n return [...cl.slice(0, i), ...newStr.split('\\n'), ...cl.slice(i + ol.length)].join('\\n');\n}\n\n/** Read-before-overwrite guard, shared by Write and ApplyEdits' whole-file branch: blindly replacing\n * an existing file the agent never Read destroys its unseen content (the taskify-board incident).\n * `key` is the resolved path (the readState key); a fresh Write arms readState, so re-writing your own\n * output passes. Returns true when the write would clobber un-Read content and should be refused. */\nasync function wouldClobberUnread(ctx: ToolContext, path: string, key: string): Promise<boolean> {\n return !ctx.readState.has(key) && (await ctx.fs.exists(path));\n}\n\n/** Create or overwrite a file, creating parent directories as needed (mkdir -p). */\nexport const writeTool: AgentTool = {\n name: 'Write',\n description:\n 'Create or overwrite a file with the given contents, creating parent directories as needed. Use for new files instead of `bash echo >`. To replace an EXISTING file you must Read it first — overwriting an un-Read file is refused (it would destroy unseen content).',\n parameters: {\n type: 'object',\n required: ['path', 'content'],\n properties: { path: { type: 'string' }, content: { type: 'string' } },\n },\n async run({ path, content }, ctx) {\n const body = String(content ?? '');\n const key = ctx.fs.resolvePath(path);\n if (await wouldClobberUnread(ctx, path, key))\n throw new Error(`Refusing to overwrite ${path}: it exists and hasn't been Read. Read it first, then Write to replace it (or Edit to change part of it).`);\n if (ctx.lint) { const err = ctx.lint(path, body); if (err) throw new Error(err); }\n await mkdirp(ctx.fs, parentDir(key));\n await ctx.fs.writeFile(path, body);\n ctx.readState.set(key, body); // arm Edit on a freshly written file\n return `Wrote ${path}`;\n },\n};\n\n/** Apply an ordered list of exact-substring edits to one file in a single call. */\nexport const multiEditTool: AgentTool = {\n name: 'MultiEdit',\n description:\n 'Apply several exact-substring replacements to one file in order, in a single call. Requires a prior Read. Each `old_string` must be unique at the time it is applied. All-or-nothing: if any edit fails, none are written.',\n parameters: {\n type: 'object',\n required: ['path', 'edits'],\n properties: {\n path: { type: 'string' },\n edits: {\n type: 'array',\n items: {\n type: 'object',\n required: ['old_string', 'new_string'],\n properties: { old_string: { type: 'string' }, new_string: { type: 'string' } },\n },\n },\n },\n },\n async run({ path, edits }, ctx) {\n const key = ctx.fs.resolvePath(path);\n const snapshot = ctx.readState.get(key);\n if (snapshot == null) throw new Error(`File has not been read yet: ${path}. Read it before editing.`);\n let current = await ctx.fs.readFile(path);\n if (current !== snapshot) throw new Error(`File ${path} changed since it was read (stale). Re-read before editing.`);\n const list = Array.isArray(edits) ? edits : [];\n if (!list.length) throw new Error('edits must be a non-empty array');\n for (const [i, e] of list.entries()) {\n const count = e.old_string === '' ? 0 : current.split(e.old_string).length - 1;\n if (count === 0) throw new Error(`edit ${i}: old_string not found in ${path}.`);\n if (count > 1) throw new Error(`edit ${i}: old_string is not unique in ${path} (${count} matches).`);\n current = current.replace(e.old_string, () => e.new_string);\n }\n if (ctx.lint) { const err = ctx.lint(path, current); if (err) throw new Error(err); }\n await ctx.fs.writeFile(path, current);\n ctx.readState.set(key, current);\n return `Applied ${list.length} edit(s) to ${path}`;\n },\n};\n\n/**\n * Cross-file batch edit — the multi-file refactor primitive. One call edits MANY files:\n * each entry with an `old_string` replaces that exact, UNIQUE substring (read fresh + verified,\n * so NO prior Read is needed — locate the sites with Grep, whose output is the text to match);\n * each entry WITHOUT `old_string` writes `new_string` as the whole file (creates it + parent dirs).\n * Validate-all-before-write → atomic across files. Collapses \"Grep + N×(Read+Edit)\" into \"Grep + ApplyEdits\".\n */\nexport const applyEditsTool: AgentTool = {\n name: 'ApplyEdits',\n description:\n 'Apply edits across one or MORE files in a single call — for cross-file refactors (rename/extract/move). edits=[{path, old_string?, new_string}]. WITH old_string: replace that exact substring (must be UNIQUE in the file — add surrounding context; read fresh + verified, no prior Read needed). WITHOUT old_string: write new_string as the whole file (creates it + parent dirs; but to OVERWRITE a file that already exists you must Read it first, else use old_string to edit part of it). Locate sites first with Grep (its output shows the exact text). Atomic: validated across all files before any write.',\n parameters: {\n type: 'object',\n required: ['edits'],\n properties: {\n edits: {\n type: 'array',\n items: {\n type: 'object',\n required: ['path', 'new_string'],\n properties: { path: { type: 'string' }, old_string: { type: 'string' }, new_string: { type: 'string' } },\n },\n },\n },\n },\n async run({ edits }, ctx) {\n const list = Array.isArray(edits) ? edits : [];\n if (!list.length) throw new Error('edits must be a non-empty array of {path, old_string?, new_string}');\n const planned = new Map<string, string>(); // resolved path -> final content (validate ALL before writing → atomic)\n for (const [i, e] of list.entries()) {\n const p = ctx.fs.resolvePath(String(e.path));\n const old = e.old_string == null ? '' : String(e.old_string);\n const neu = String(e.new_string ?? '');\n if (old === '') { // whole-file write / create\n // Same read-before-overwrite guard as Write (skip if an earlier edit in THIS batch already staged p).\n if (!planned.has(p) && (await wouldClobberUnread(ctx, String(e.path), p)))\n throw new Error(`edit ${i}: refusing to overwrite ${e.path} with a whole-file write — it exists and hasn't been Read. Read it first, or pass old_string to edit part of it.`);\n planned.set(p, neu); continue;\n }\n let cur = planned.has(p) ? planned.get(p)! : await ctx.fs.readFile(p).catch(() => { throw new Error(`edit ${i}: file not found: ${e.path}`); });\n const count = cur.split(old).length - 1;\n if (count > 1) throw new Error(`edit ${i}: old_string is not unique in ${e.path} (${count} matches) — add more context`);\n if (count === 1) cur = cur.replace(old, () => neu);\n else {\n const fz = fuzzyLineReplace(cur, old, neu);\n if (fz == null) throw new Error(`edit ${i}: old_string not found in ${e.path}`);\n cur = fz;\n }\n planned.set(p, cur);\n }\n if (ctx.lint) for (const [p, content] of planned) { const err = ctx.lint(p, content); if (err) throw new Error(err); } // validate ALL before any write\n for (const [p, content] of planned) { await mkdirp(ctx.fs, parentDir(p)); await ctx.fs.writeFile(p, content); ctx.readState.set(p, content); }\n return `Applied ${list.length} edit(s) across ${planned.size} file(s): ${[...planned.keys()].join(', ')}`;\n },\n};\n\nfunction parentDir(abs: string): string {\n const i = abs.lastIndexOf('/');\n return i <= 0 ? '/' : abs.slice(0, i);\n}\n\n/** mkdir -p over the VFS (idempotent, top-down). */\nexport async function mkdirp(fs: IFilesystem, dir: string): Promise<void> {\n if (dir === '/' || (await fs.exists(dir))) return;\n await mkdirp(fs, parentDir(dir));\n if (!(await fs.exists(dir))) await fs.createDir(dir);\n}\n\n/**\n * Review — verification WITHOUT execution: a fresh-context, adversarial critic pass over the\n * changes the agent just made. Verification-as-review (stolen from the review-fix-commit skill):\n * for an agent with no test runner, \"re-read to be sure\" is weak, but a COLD reviewer that reads\n * only {task + the produced files} (not the author's chain-of-thought) catches missed edge cases,\n * unstated implications, and subtle logic bugs a happy-path one-shot misses. Costs one model call.\n *\n * The `notes` arg is the with/without-CONTEXT knob: omit it for a pure cold review (the default,\n * least biased); pass it to feed the reviewer extra context. We don't decide which is better —\n * the self-evolution loop discovers it via its prompt rules.\n *\n * Degrades to a no-op notice if no model handle is wired (ctx.ai/ctx.model).\n */\nexport function reviewTool(): AgentTool {\n return {\n name: 'Review',\n description:\n 'Critically review your changes before finishing (verification without running code). Pass the task and the paths you changed; a fresh-context senior reviewer reads them COLD and returns concrete issues or \"LGTM\". Fix what it raises, then finish. Optional `notes` feeds the reviewer extra context.',\n parameters: {\n type: 'object',\n required: ['task', 'paths'],\n properties: {\n task: { type: 'string', description: 'what was asked — the spec/requirements to check the changes against' },\n paths: { type: 'array', items: { type: 'string' }, description: 'the files you changed/created, to be reviewed' },\n notes: { type: 'string', description: 'OPTIONAL extra context for the reviewer (rationale, constraints). Omit for a pure cold review.' },\n },\n },\n async run({ task, paths, notes }, ctx: ToolContext) {\n if (!ctx.ai || !ctx.model) return '[Review] no model handle wired — skipped.';\n const list: string[] = Array.isArray(paths) ? paths.map(String) : [];\n if (!list.length) return 'Error: pass the paths you changed in `paths`.';\n const files: string[] = [];\n for (const p of list.slice(0, 12)) {\n try {\n const body = await ctx.fs.readFile(p);\n files.push(`--- ${p} ---\\n${body.length > 4000 ? body.slice(0, 4000) + '\\n…(truncated)' : body}`);\n } catch {\n files.push(`--- ${p} ---\\n[could not read]`);\n }\n }\n const prompt =\n 'You are a senior engineer doing a critical code review. Review the changes below AGAINST THE TASK with deep, skeptical thinking — default to finding problems.\\n' +\n 'Focus on: correctness, edge cases (empty/boundary/negative inputs), unstated-but-implied requirements, and subtle logic bugs. Do NOT comment on style.\\n\\n' +\n `TASK:\\n${String(task ?? '').trim()}\\n\\n` +\n (notes ? `CONTEXT FROM THE AUTHOR:\\n${String(notes).trim()}\\n\\n` : '') +\n `CHANGED FILES:\\n${files.join('\\n\\n')}\\n\\n` +\n 'Reply with a short numbered list of concrete, actionable issues. If the changes correctly and completely satisfy the task with no edge cases missed, reply with exactly: LGTM';\n try {\n const r = (await ctx.ai.chat({ model: ctx.model, messages: [{ role: 'user', content: prompt }], stream: false })) as ChatResponse;\n const text = (r?.content ?? '').trim();\n return text || 'LGTM';\n } catch (e: any) {\n return `[Review] model error: ${e?.message ?? e} — skipped.`;\n }\n },\n };\n}\n","import type { AgentTool, ToolContext } from './tools';\n\n/** A single planning item. `in_progress` should mark exactly the one task currently being worked on. */\nexport interface TodoItem {\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n}\n\nconst MARK: Record<TodoItem['status'], string> = {\n pending: '[ ]',\n in_progress: '[~]',\n completed: '[x]',\n};\n\n/** Render a todo list as a stable checklist (one item per line). */\nfunction renderTodos(todos: TodoItem[]): string {\n if (todos.length === 0) return 'Todo list cleared (no items).';\n return todos.map((t) => `${MARK[t.status]} ${t.content}`).join('\\n');\n}\n\n/**\n * `TodoWrite` tool — the agent's planning scratchpad for multi-step tasks.\n * Use to lay out steps up front and keep them current (mark one `in_progress`,\n * flip finished ones to `completed`). Each call REPLACES the whole list.\n */\nexport const todoWriteTool: AgentTool = {\n name: 'TodoWrite',\n description:\n 'Maintain a todo list to plan and track a multi-step task. Replaces the current list with the provided todos and returns the rendered checklist. Mark exactly one item in_progress at a time; flip items to completed as you finish them.',\n parameters: {\n type: 'object',\n required: ['todos'],\n properties: {\n todos: {\n type: 'array',\n items: {\n type: 'object',\n required: ['content', 'status'],\n properties: {\n content: { type: 'string', description: 'the step to do' },\n status: { type: 'string', enum: ['pending', 'in_progress', 'completed'] },\n },\n },\n },\n },\n },\n async run({ todos }, ctx: ToolContext) {\n if (!Array.isArray(todos)) throw new Error('todos must be an array of { content, status } items.');\n const next: TodoItem[] = todos.map((t: any, i: number) => {\n const content = String(t?.content ?? '').trim();\n if (!content) throw new Error(`todos[${i}].content is required.`);\n const status = t?.status;\n if (status !== 'pending' && status !== 'in_progress' && status !== 'completed') {\n throw new Error(`todos[${i}].status must be one of pending|in_progress|completed (got ${JSON.stringify(status)}).`);\n }\n return { content, status };\n });\n ctx.todos = next; // replace the list in place on the shared context\n return renderTodos(next);\n },\n};\n","import type { AgentTool } from './tools';\nimport { forComponent } from './logging';\n\n/**\n * Web tools — `WebFetch` (retrieve a URL as readable text) and `WebSearch` (ranked\n * results via a configured provider). Opt-in (NOT in the default tool set): network\n * access is a deliberate capability. Factory-built with an injectable `fetch` so they\n * stay edge-portable and unit-testable without real network. `fetch` is read at call\n * time, so a no-network runtime simply has the tool return an error.\n */\nconst log = forComponent('web');\n\n/** Strip HTML to readable text — dependency-free: drop script/style/comments, block tags → newlines, decode common entities. */\nexport function htmlToText(html: string): string {\n let s = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<title[\\s\\S]*?<\\/title>/gi, ' ') // drop title text (don't leak it into context)\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, ' ') // …same for noscript / textarea content\n .replace(/<textarea[\\s\\S]*?<\\/textarea>/gi, ' ')\n .replace(/<!--[\\s\\S]*?-->/g, ' ')\n .replace(/<\\/(p|div|li|h[1-6]|tr|section|article|header|footer|nav)>/gi, '\\n')\n .replace(/<br\\s*\\/?>/gi, '\\n')\n .replace(/<[^>]+>/g, ' ');\n s = s\n .replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&').replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>').replace(/&quot;/g, '\"').replace(/&#0?39;/g, \"'\").replace(/&#x27;/gi, \"'\");\n return s\n .replace(/[ \\t\\f\\v]+/g, ' ')\n .split('\\n').map((l) => l.trim()).join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n}\n\nexport interface WebFetchOptions {\n /** Override the global fetch (tests inject a mock; edge runtimes can supply their own). */\n fetch?: typeof globalThis.fetch;\n maxBytes?: number; // cap the downloaded body (default 2 MB)\n maxChars?: number; // cap the returned text (default 100k)\n timeoutMs?: number; // request timeout (default 15s)\n /** Allow fetching private/loopback/link-local hosts (default false — blocks basic SSRF). */\n allowPrivateHosts?: boolean;\n}\n\n/**\n * Block obvious SSRF targets by hostname/IP literal (loopback, private ranges, link-local incl.\n * cloud metadata 169.254.169.254, `.internal`). Pure/edge-safe — no DNS, so DNS-rebinding and\n * redirect-to-internal are NOT covered (an embedder needing that should supply a vetting `fetch`).\n */\nexport function isPrivateHost(host: string): boolean {\n const h = host.toLowerCase().replace(/^\\[|\\]$/g, ''); // strip IPv6 brackets\n if (h === '' || h === 'localhost' || h.endsWith('.localhost') || h.endsWith('.internal')) return true;\n if (h === '::1' || h === '::' || h.startsWith('fe80:') || h.startsWith('fc') || h.startsWith('fd')) return true; // IPv6 loopback/link-local/ULA\n const m = h.match(/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/);\n if (m) {\n const a = +m[1], b = +m[2];\n return a === 0 || a === 127 || a === 10 || (a === 169 && b === 254) || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168) || (a === 100 && b >= 64 && b <= 127);\n }\n return false;\n}\n\n/** Lazily-loaded node DNS resolver (absent on edge/browser) — closes DNS-rebinding (a public\n * hostname resolving to an internal IP) on the real-network path. Resolves null where unavailable. */\nlet _dnsLookup: ((h: string, opts?: any) => Promise<{ address: string }[]>) | null | undefined;\nasync function resolveIps(host: string): Promise<string[] | null> {\n if (_dnsLookup === undefined) {\n try { _dnsLookup = (await import('node:dns/promises')).lookup as any; }\n catch { _dnsLookup = null; } // edge/browser: no DNS — rely on the literal isPrivateHost check\n }\n if (!_dnsLookup) return null;\n try { return (await _dnsLookup(host, { all: true } as any)).map((a) => a.address); } catch { return null; }\n}\n\n/** Read a response body but stop at `maxBytes` of ACTUAL bytes (cancel the stream) — no unbounded download. */\nasync function readCapped(res: Response, maxBytes: number): Promise<string> {\n const reader = (res.body as any)?.getReader?.();\n if (!reader) { const t = await res.text(); return t.length > maxBytes ? t.slice(0, maxBytes) : t; }\n const chunks: Uint8Array[] = [];\n let total = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) { chunks.push(value); total += value.length; }\n if (total >= maxBytes) { try { await reader.cancel(); } catch { /* already closed */ } break; }\n }\n const out = new Uint8Array(Math.min(total, maxBytes));\n let off = 0;\n for (const c of chunks) { if (off >= out.length) break; const take = Math.min(c.length, out.length - off); out.set(c.subarray(0, take), off); off += take; }\n return new TextDecoder().decode(out);\n}\n\n/** Build a WebFetch tool. */\nexport function makeWebFetchTool(options: WebFetchOptions = {}): AgentTool {\n const maxBytes = options.maxBytes ?? 2_000_000;\n const maxChars = options.maxChars ?? 100_000;\n const timeoutMs = options.timeoutMs ?? 15_000;\n return {\n name: 'WebFetch',\n description:\n 'Fetch an http/https URL and return its readable text (HTML is stripped to text). Use to read docs or web pages. Returns the status line then up to ~100k chars of content.',\n // Declared so a transport above the loop sizes its deadline around this one (see AgentTool.maxDurationMs).\n maxDurationMs: timeoutMs,\n parameters: { type: 'object', required: ['url'], properties: { url: { type: 'string', description: 'absolute http(s) URL' } } },\n async run({ url }) {\n const doFetch = options.fetch ?? globalThis.fetch;\n const customFetch = !!options.fetch; // injected fetch (tests/edge) owns its own vetting → skip DNS\n const u = String(url ?? '');\n try { new URL(u); } catch { return `Error: invalid URL: ${u}`; }\n if (!doFetch) return 'Error: no network (fetch) available in this runtime';\n // Reject a host that's a private/internal IP literal, or (on the real-network path) a name that\n // RESOLVES to one — re-checked on EVERY redirect hop so an external page can't bounce us internal.\n const hostBlock = async (hostname: string): Promise<string | null> => {\n if (options.allowPrivateHosts) return null;\n if (isPrivateHost(hostname)) return hostname;\n if (!customFetch) { const ips = await resolveIps(hostname); if (ips) for (const ip of ips) if (isPrivateHost(ip)) return `${hostname} → ${ip}`; }\n return null;\n };\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), timeoutMs);\n try {\n let current = u;\n let res: Response;\n for (let hop = 0; ; hop++) {\n const pu = new URL(current);\n if (pu.protocol !== 'http:' && pu.protocol !== 'https:') return `Error: only http/https URLs are allowed (got \"${pu.protocol}\")`;\n const blocked = await hostBlock(pu.hostname);\n if (blocked) return `Error: refusing to fetch a private/internal address (${blocked}) — set allowPrivateHosts to override`;\n res = await doFetch(current, { signal: ctl.signal, redirect: 'manual', headers: { 'user-agent': 'agentx (+https://github.com/Livshitz/agentx)' } });\n if (res.status >= 300 && res.status < 400 && res.headers.get('location')) {\n if (hop >= 5) return `Error fetching ${u}: too many redirects`;\n current = new URL(res.headers.get('location')!, current).toString(); // re-validated at loop top\n continue;\n }\n break;\n }\n const type = res.headers.get('content-type') ?? '';\n const body = await readCapped(res, maxBytes);\n const text = /html/i.test(type) || /^\\s*<(?:!doctype|html)/i.test(body) ? htmlToText(body) : body.trim();\n const capped = text.length > maxChars ? text.slice(0, maxChars) + `\\n… [truncated at ${maxChars} chars]` : text;\n return `${res.status} ${res.statusText} · ${new URL(current).host}\\n\\n${capped}`;\n } catch (e: any) {\n log.debug(`WebFetch ${u} failed`, e);\n return `Error fetching ${u}: ${e?.name === 'AbortError' ? `timed out after ${timeoutMs}ms` : (e?.message ?? e)}`;\n } finally {\n clearTimeout(timer);\n }\n },\n };\n}\n\nexport interface WebSearchOptions {\n fetch?: typeof globalThis.fetch;\n /** Provider: 'auto' (default) prefers Firecrawl, then Tavily (by key presence), else keyless DuckDuckGo.\n * 'anthropic' delegates to a cheap model with Anthropic's native server-side web_search. */\n provider?: 'auto' | 'tavily' | 'duckduckgo' | 'anthropic' | 'firecrawl';\n /** API key for Tavily (default: process.env.TAVILY_API_KEY). */\n apiKey?: string;\n /** Tavily endpoint override. */\n endpoint?: string;\n /** API key for Firecrawl (default: process.env.FIRECRAWL_API_KEY). */\n firecrawlApiKey?: string;\n /** Firecrawl search endpoint override. */\n firecrawlEndpoint?: string;\n maxResults?: number; // default 5\n timeoutMs?: number; // default 15s\n /** Tool name (default 'WebSearch'). Set to register a provider-pinned variant, e.g. 'WebSearchAnthropic'. */\n name?: string;\n /** Tool description override (default: the generic ranked-results blurb). */\n description?: string;\n /** Anthropic key for provider 'anthropic' (default: process.env.ANTHROPIC_API_KEY). */\n anthropicApiKey?: string;\n /** Model for provider 'anthropic' (default 'claude-haiku-4-5'). */\n model?: string;\n}\n\ninterface SearchHit { title: string; url: string; snippet: string }\n\n/** Decode a DuckDuckGo HTML result href: results are `//duckduckgo.com/l/?uddg=<encoded-target>` redirects. */\nexport function decodeDdgUrl(href: string): string {\n const m = href.match(/[?&]uddg=([^&]+)/);\n if (m) { try { return decodeURIComponent(m[1]); } catch { /* fall through */ } }\n return href.startsWith('//') ? 'https:' + href : href;\n}\n\n/** Parse DuckDuckGo's HTML results page into hits (title/url/snippet) — dependency-free, zips anchors to snippets in order. */\nexport function parseDdgHtml(html: string, max: number): SearchHit[] {\n const anchors = [...html.matchAll(/<a[^>]*class=\"[^\"]*result__a[^\"]*\"[^>]*href=\"([^\"]+)\"[^>]*>([\\s\\S]*?)<\\/a>/g)];\n const snippets = [...html.matchAll(/<a[^>]*class=\"[^\"]*result__snippet[^\"]*\"[^>]*>([\\s\\S]*?)<\\/a>/g)].map((m) => htmlToText(m[1]));\n const hits: SearchHit[] = [];\n for (let i = 0; i < anchors.length && hits.length < max; i++) {\n const url = decodeDdgUrl(anchors[i][1]);\n try { if (isPrivateHost(new URL(url).hostname)) continue; } catch { continue; } // skip junk/internal redirects\n hits.push({ title: htmlToText(anchors[i][2]) || '(untitled)', url, snippet: snippets[i] ?? '' });\n }\n return hits;\n}\n\nfunction formatHits(hits: SearchHit[]): string {\n if (!hits.length) return '(no results)';\n return hits.map((r, i) => `${i + 1}. ${r.title}\\n ${r.url}\\n ${r.snippet.replace(/\\s+/g, ' ').slice(0, 240)}`).join('\\n\\n');\n}\n\n/** Provider 'firecrawl': agent-oriented search API (POST /v1/search, Bearer auth). Maps Firecrawl's\n * result objects into the same hit shape as Tavily/DDG. HTTP-only, no SDK. */\nasync function firecrawlSearch(q: string, opts: { key: string; endpoint: string; maxResults: number; fetch: typeof globalThis.fetch; signal: AbortSignal }): Promise<string> {\n const res = await opts.fetch(opts.endpoint, {\n method: 'POST',\n signal: opts.signal,\n headers: { authorization: `Bearer ${opts.key}`, 'content-type': 'application/json' },\n body: JSON.stringify({ query: q, limit: opts.maxResults }),\n });\n if (!res.ok) return `Error: Firecrawl search returned ${res.status} ${res.statusText}`;\n const data: any = await res.json();\n const results = Array.isArray(data?.data) ? data.data.slice(0, opts.maxResults) : [];\n return formatHits(results.map((r: any) => ({ title: r.title ?? '(untitled)', url: r.url ?? '', snippet: String(r.description ?? r.markdown ?? '') })));\n}\n\n/**\n * Provider 'anthropic': delegate the search to a cheap model running Anthropic's native server-side\n * web_search tool. Anthropic runs the search and reads the results; we prompt for un-editorialized\n * findings (one claim per line, each with its source URL) and relay them verbatim. Raw HTTP — no SDK,\n * stays edge-portable. Slower and costlier than DDG/Tavily, but better-sourced (native search index).\n */\nasync function anthropicSearch(q: string, opts: { key: string; model: string; fetch: typeof globalThis.fetch; signal: AbortSignal }): Promise<string> {\n const res = await opts.fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n signal: opts.signal,\n headers: { 'x-api-key': opts.key, 'anthropic-version': '2023-06-01', 'content-type': 'application/json' },\n body: JSON.stringify({\n model: opts.model,\n max_tokens: 1024,\n // Basic variant: Haiku-tier doesn't support the _20260209 dynamic-filtering variant (Opus 4.6+/Sonnet 4.6 only).\n tools: [{ type: 'web_search_20250305', name: 'web_search', max_uses: 5 }],\n messages: [{ role: 'user', content:\n `Search the web for: ${q}\\n\\nReturn only the relevant findings as concise bullet points, each with its source URL in parentheses. ` +\n `Do not add a preamble, conclusion, opinion, or commentary. If sources conflict, list each claim with its source rather than resolving it.` }],\n }),\n });\n if (!res.ok) return `Error: Anthropic search returned ${res.status} ${res.statusText}`;\n const data: any = await res.json();\n if (data?.stop_reason === 'refusal') return 'Error: Anthropic search refused the query';\n let text = '';\n for (const block of data?.content ?? []) if (block?.type === 'text') text += block.text;\n return text.trim() || '(no results)';\n}\n\n/**\n * Build a WebSearch tool. Keyless by default (DuckDuckGo HTML) so it works in any deployment with no\n * setup; on provider 'auto' it upgrades to an agent-oriented API by key presence — Firecrawl\n * (FIRECRAWL_API_KEY) preferred, then Tavily (TAVILY_API_KEY). Provider 'anthropic' is a separate path\n * (native search via a cheap model) exposed as the WebSearchAnthropic tool.\n */\nexport function makeWebSearchTool(options: WebSearchOptions = {}): AgentTool {\n const tavilyEndpoint = options.endpoint ?? 'https://api.tavily.com/search';\n const firecrawlEndpoint = options.firecrawlEndpoint ?? 'https://api.firecrawl.dev/v1/search';\n const maxResults = options.maxResults ?? 5;\n const timeoutMs = options.timeoutMs ?? 15_000;\n return {\n name: options.name ?? 'WebSearch',\n description: options.description ??\n 'Search the web by query; returns ranked results (title, URL, snippet). Use to look things up, find pages, or research a topic — then WebFetch a result URL to read it in full.',\n parameters: { type: 'object', required: ['query'], properties: { query: { type: 'string' } } },\n async run({ query }) {\n const doFetch = options.fetch ?? globalThis.fetch;\n if (!doFetch) return 'Error: no network (fetch) available in this runtime';\n const q = String(query ?? '').trim();\n if (!q) return 'Error: empty query';\n const key = options.apiKey ?? process.env.TAVILY_API_KEY;\n const fcKey = options.firecrawlApiKey ?? process.env.FIRECRAWL_API_KEY;\n const provider = options.provider ?? 'auto';\n // auto priority ladder: Firecrawl > Tavily > keyless DuckDuckGo (by key presence).\n const useFirecrawl = provider === 'firecrawl' || (provider === 'auto' && !!fcKey);\n const useTavily = provider === 'tavily' || (provider === 'auto' && !useFirecrawl && !!key);\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), timeoutMs);\n try {\n if (provider === 'anthropic') {\n const akey = options.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY;\n if (!akey) return 'Error: WebSearchAnthropic requires ANTHROPIC_API_KEY (set in env)';\n return await anthropicSearch(q, { key: akey, model: options.model ?? 'claude-haiku-4-5', fetch: doFetch, signal: ctl.signal });\n }\n if (useFirecrawl) {\n if (!fcKey) return 'Error: Firecrawl provider selected but FIRECRAWL_API_KEY is not set';\n return await firecrawlSearch(q, { key: fcKey, endpoint: firecrawlEndpoint, maxResults, fetch: doFetch, signal: ctl.signal });\n }\n if (useTavily) {\n if (!key) return 'Error: Tavily provider selected but TAVILY_API_KEY is not set';\n const res = await doFetch(tavilyEndpoint, {\n method: 'POST',\n signal: ctl.signal,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ api_key: key, query: q, max_results: maxResults }),\n });\n if (!res.ok) return `Error: search provider returned ${res.status} ${res.statusText}`;\n const data: any = await res.json();\n const results = Array.isArray(data?.results) ? data.results.slice(0, maxResults) : [];\n return formatHits(results.map((r: any) => ({ title: r.title ?? '(untitled)', url: r.url ?? '', snippet: String(r.content ?? '') })));\n }\n // Keyless: DuckDuckGo HTML endpoint (no key, edge-portable).\n const res = await doFetch('https://html.duckduckgo.com/html/?q=' + encodeURIComponent(q), {\n signal: ctl.signal,\n headers: { 'user-agent': 'Mozilla/5.0 (compatible; agentx/1.0; +https://github.com/Livshitz/agentx)' },\n });\n if (!res.ok) return `Error: search returned ${res.status} ${res.statusText}`;\n return formatHits(parseDdgHtml(await res.text(), maxResults));\n } catch (e: any) {\n log.debug('WebSearch failed', e);\n return `Error searching: ${e?.name === 'AbortError' ? `timed out after ${timeoutMs}ms` : (e?.message ?? e)}`;\n } finally {\n clearTimeout(timer);\n }\n },\n };\n}\n\n/** Default instances (registered in the tool registry; opt-in by name). */\nexport const webFetchTool = makeWebFetchTool();\nexport const webSearchTool = makeWebSearchTool();\nconst ANTHROPIC_SEARCH_DESC =\n \"High-quality web search via Anthropic's native search index. Returns concise, sourced findings — one claim per line, each with its source URL. Prefer this over WebSearch when accuracy and citations matter; it is slower (~3–8s) and bills the Anthropic API account per call (one cheap-model turn + search fee).\";\n\n/** Anthropic-native search as a provider-pinned WebSearch variant. The credential is API-key billing\n * (x-api-key); pass `anthropicApiKey` to inject a resolved key, else it falls back to ANTHROPIC_API_KEY. */\nexport function makeWebSearchAnthropicTool(opts: { anthropicApiKey?: string; model?: string } = {}): AgentTool {\n return makeWebSearchTool({ provider: 'anthropic', name: 'WebSearchAnthropic', description: ANTHROPIC_SEARCH_DESC, anthropicApiKey: opts.anthropicApiKey, model: opts.model });\n}\n/** Env-keyed singleton: registered in the tool registry so 'WebSearchAnthropic' resolves by name. The\n * CLI default-on path builds its own instance with a config-resolved key (see cli/core.ts). */\nexport const webSearchAnthropicTool = makeWebSearchAnthropicTool();\n","import type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\nimport type { AgentTool } from './tools';\n\n/**\n * Copy-on-write overlay over any base IFilesystem — the base is never touched until\n * you `commit()`. Writes/deletes/mkdirs accumulate in an in-memory overlay; reads see\n * overlay-then-base. This unlocks capabilities the swappable-VFS architecture makes\n * cheap and that a real agent wants:\n * - `snapshot()` / `rollback(token)` — checkpoint before a risky multi-file change and\n * undo it instantly (the `Checkpoint`/`Rollback` agent tools sit on these);\n * - `diff()` — exactly what changed vs the base (added/modified/deleted);\n * - `commit()` — flush the overlay down into the base when you're happy.\n * Edge-safe: pure IFilesystem, no node builtins.\n */\ninterface OverlayState {\n writes: Map<string, string>; // path -> content (created/modified)\n deletes: Set<string>; // tombstones hiding a base path\n dirs: Set<string>; // overlay-created directories\n}\n\nexport class OverlayFilesystem implements IFilesystem {\n private st: OverlayState = { writes: new Map(), deletes: new Set(), dirs: new Set() };\n private snapshots = new Map<string, OverlayState>();\n private seq = 0;\n\n constructor(private base: IFilesystem) {}\n\n // ---- path plumbing: delegate to the base so normalization/cwd are identical ----\n resolvePath(path: string, cwd?: string): string { return this.base.resolvePath(path, cwd ?? this.base.getCwd()); }\n getCwd(): string { return this.base.getCwd(); }\n setCwd(path: string): void { this.base.setCwd(path); }\n private abs(p: string): string { return this.resolvePath(p); }\n private parent(abs: string): string { const i = abs.lastIndexOf('/'); return i <= 0 ? '/' : abs.slice(0, i); }\n private name(abs: string): string { return abs.slice(abs.lastIndexOf('/') + 1); }\n\n // ---- reads (overlay wins; tombstones hide the base) ----\n async readFile(path: string): Promise<string> {\n const p = this.abs(path);\n if (this.st.deletes.has(p)) throw new Error(`File not found: ${path}`);\n if (this.st.writes.has(p)) return this.st.writes.get(p)!;\n return this.base.readFile(p);\n }\n\n async exists(path: string): Promise<boolean> {\n const p = this.abs(path);\n if (this.st.deletes.has(p)) return false;\n if (this.st.writes.has(p) || this.st.dirs.has(p)) return true;\n return this.base.exists(p);\n }\n\n async isFile(path: string): Promise<boolean> {\n const p = this.abs(path);\n if (this.st.deletes.has(p)) return false;\n if (this.st.writes.has(p)) return true;\n if (this.st.dirs.has(p)) return false;\n return this.base.isFile(p);\n }\n\n async isDirectory(path: string): Promise<boolean> {\n const p = this.abs(path);\n if (this.st.deletes.has(p)) return false;\n if (this.st.dirs.has(p)) return true;\n if (this.st.writes.has(p)) return false;\n return this.base.isDirectory(p);\n }\n\n async stat(path: string): Promise<FileMetadata> {\n const p = this.abs(path);\n if (this.st.deletes.has(p)) throw new Error(`File not found: ${path}`);\n if (this.st.writes.has(p)) {\n const size = this.st.writes.get(p)!.length;\n return { created: new Date(0), modified: new Date(0), size, permissions: '-rw-r--r--', isExecutable: false };\n }\n if (this.st.dirs.has(p)) return { created: new Date(0), modified: new Date(0), size: 0, permissions: 'drwxr-xr-x', isExecutable: false };\n return this.base.stat(p);\n }\n\n /** Merge base entries (minus tombstones) with overlay-created children of `path`. */\n async readDir(path: string): Promise<string[]> {\n const p = this.abs(path);\n if (await this.isFile(p)) throw new Error(`Not a directory: ${path}`); // match base contract (don't swallow → return [])\n const names = new Set<string>();\n try { for (const n of await this.base.readDir(p)) names.add(n); } catch { /* base dir may not exist; overlay may still have children */ }\n for (const w of [...this.st.writes.keys(), ...this.st.dirs]) if (this.parent(w) === p) names.add(this.name(w));\n for (const d of this.st.deletes) if (this.parent(d) === p) names.delete(this.name(d));\n if (names.size === 0 && !(await this.exists(p)) && p !== '/') throw new Error(`Directory not found: ${path}`);\n return [...names].sort();\n }\n\n // ---- writes (recorded in the overlay; base untouched until commit) ----\n async writeFile(path: string, content: string): Promise<void> {\n const p = this.abs(path);\n if (!(await this.exists(this.parent(p)))) throw new Error(`Parent directory does not exist: ${path}`);\n this.st.deletes.delete(p);\n this.st.writes.set(p, content);\n }\n\n async createDir(path: string): Promise<void> {\n const p = this.abs(path);\n if (await this.exists(p)) throw new Error(`File or directory already exists: ${path}`);\n if (!(await this.exists(this.parent(p)))) throw new Error(`Parent directory does not exist: ${path}`);\n this.st.deletes.delete(p);\n this.st.dirs.add(p);\n }\n\n async deleteFile(path: string): Promise<void> {\n const p = this.abs(path);\n if (!(await this.exists(p))) throw new Error(`File not found: ${path}`);\n if (await this.isDirectory(p) && (await this.readDir(p)).length > 0) throw new Error(`Directory not empty: ${path}`);\n this.st.writes.delete(p);\n this.st.dirs.delete(p);\n this.st.deletes.add(p); // tombstone (in case it exists in the base)\n }\n\n // ---- checkpointing ----\n private clone(s: OverlayState): OverlayState {\n return { writes: new Map(s.writes), deletes: new Set(s.deletes), dirs: new Set(s.dirs) };\n }\n\n /** Capture the current overlay; returns a token to `rollback(token)` to. */\n snapshot(label?: string): string {\n const token = label ?? `snap-${++this.seq}`;\n this.snapshots.set(token, this.clone(this.st));\n return token;\n }\n\n /** Discard all changes since the named snapshot (or the most recent if omitted). */\n rollback(token?: string): void {\n const key = token ?? [...this.snapshots.keys()].pop();\n if (key == null || !this.snapshots.has(key)) throw new Error(`No snapshot '${token ?? '(latest)'}'`);\n this.st = this.clone(this.snapshots.get(key)!);\n }\n\n /** Paths changed vs the base since this overlay was created (added = not in base, modified = was). */\n async diff(): Promise<{ added: string[]; modified: string[]; deleted: string[] }> {\n const added: string[] = [], modified: string[] = [];\n for (const p of this.st.writes.keys()) ((await this.base.exists(p)) ? modified : added).push(p);\n return { added: added.sort(), modified: modified.sort(), deleted: [...this.st.deletes].sort() };\n }\n\n /** Flush the overlay into the base (writes, mkdirs, deletes), then clear the overlay. */\n async commit(): Promise<void> {\n for (const d of this.st.dirs) if (!(await this.base.exists(d))) await this.base.createDir(d).catch(() => {});\n for (const [p, c] of this.st.writes) await this.base.writeFile(p, c);\n for (const p of this.st.deletes) if (await this.base.exists(p)) await this.base.deleteFile(p).catch(() => {});\n this.st = { writes: new Map(), deletes: new Set(), dirs: new Set() };\n this.snapshots.clear();\n }\n}\n\n/** Duck-typed checkpoint capability (so the tools work over any snapshot/rollback FS). */\ninterface Checkpointable { snapshot(label?: string): string; rollback(token?: string): void; }\nconst asCheckpointable = (fs: any): Checkpointable | null =>\n typeof fs?.snapshot === 'function' && typeof fs?.rollback === 'function' ? fs : null;\nconst NEEDS_OVERLAY = 'Error: checkpointing requires an OverlayFilesystem (run with `checkpoints: true` over one).';\n\n/** `Checkpoint` tool — snapshot the VFS before a risky multi-step change. */\nexport const checkpointTool: AgentTool = {\n name: 'Checkpoint',\n description: 'Snapshot the filesystem before a risky or exploratory multi-step change, so you can undo it. Returns a token to pass to Rollback if you need to revert.',\n parameters: { type: 'object', properties: { label: { type: 'string', description: 'optional name for the checkpoint' } } },\n async run({ label }, ctx) {\n const fs = asCheckpointable(ctx.fs);\n if (!fs) return NEEDS_OVERLAY;\n return `Checkpoint '${fs.snapshot(label ? String(label) : undefined)}' created — call Rollback with it to undo everything since.`;\n },\n};\n\n/** `Rollback` tool — undo all VFS changes since a Checkpoint. */\nexport const rollbackTool: AgentTool = {\n name: 'Rollback',\n description: 'Undo ALL filesystem changes made since a Checkpoint. Pass the token from Checkpoint, or omit to revert to the most recent one. Use when an approach went wrong.',\n parameters: { type: 'object', properties: { to: { type: 'string', description: 'checkpoint token (omit for most recent)' } } },\n async run({ to }, ctx) {\n const fs = asCheckpointable(ctx.fs);\n if (!fs) return NEEDS_OVERLAY;\n try { fs.rollback(to ? String(to) : undefined); return `Rolled back to checkpoint '${to ?? '(latest)'}'.`; }\n catch (e: any) { return `Error: ${e?.message ?? e}`; }\n },\n};\n\nexport const checkpointTools = (): AgentTool[] => [checkpointTool, rollbackTool];\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport { CommandExecutor, registerHeadlessCommands } from '@livx.cc/wcli/core';\nimport type { Tool, ChatLike } from './llm';\nimport { imageRefResult } from './llm';\nimport { forComponent } from './logging';\nimport { grepTool, globTool, writeTool, multiEditTool, applyEditsTool, repoMapTool, reviewTool, fuzzyLineReplace } from './tools.structured';\nimport { todoWriteTool, type TodoItem } from './todo';\nimport { webFetchTool, webSearchTool, webSearchAnthropicTool } from './tools.web';\nimport { OverlayFilesystem } from './OverlayFilesystem';\nimport { redactSecrets, CONFIG_FILE_RE } from './redact';\nimport type { SandboxJobRegistry } from './tools.jobs';\n\nconst log = forComponent('tools');\n\n/** A structured multiple-choice question the model can pose to a human. */\nexport interface UserQuestion {\n question: string;\n header?: string;\n options: { label: string; description?: string }[];\n multiSelect?: boolean;\n}\n\n/**\n * The host / human-in-the-loop seam (the \"third seam\" beyond LLM + filesystem).\n * Injected per host: a CLI reads stdin, a browser renders a dialog, edge/headless\n * omits it. Unifies user-questions, permission/plan approvals, and notifications.\n */\nexport type HostEvent =\n | { kind: 'text_delta'; message: string }\n | { kind: 'speak_utterance'; message: string }\n | { kind: 'thinking_delta'; message: string }\n | { kind: 'tool_use'; id: string; name: string; input: unknown }\n | { kind: 'tool_result'; id: string; output: string; isError?: boolean }\n | { kind: 'tool_result_image'; id: string; dataUrl: string }\n // Display-only tool activity from a self-executing backend (e.g. Cursor CLI). NOT dispatched by the\n // Agent — purely for host UI (rich hosts read name/input/status for cards; plain hosts print `message`).\n | { kind: 'tool_activity'; id?: string; name: string; input?: unknown; output?: unknown; status: 'running' | 'completed' | 'error'; truncated?: { args?: boolean; result?: boolean }; message: string }\n | { kind: string; message: string; data?: unknown };\n\nexport interface HostBridge {\n /** Ask the user a structured question; resolve to the chosen label(s) / free text. */\n ask?(q: UserQuestion): Promise<string>;\n /** Request approval for a sensitive action (permission 'ask' / plan approval). */\n confirm?(prompt: string, meta?: { tool: string; input: unknown }): Promise<boolean>;\n /** Emit a progress / notification event to the host UI (non-blocking). */\n notify?(event: HostEvent): void;\n}\n\nexport interface ToolContext {\n fs: IFilesystem;\n exec: CommandExecutor;\n /** path -> content snapshot at last Read/Edit; powers the read-before-edit staleness guard. */\n readState: Map<string, string>;\n /** optional host interaction channel; absent => autonomous/headless. */\n host?: HostBridge;\n /** optional run-cancellation signal (mirrors AgentOptions.signal); lets abort-aware tools\n * (e.g. the real shell) kill in-flight work when the run is cancelled. */\n signal?: AbortSignal;\n /** the agent's working todo list (TodoWrite planning aid); replaced wholesale per call. */\n todos: TodoItem[];\n /** optional syntax guardrail: if set, write-class tools refuse to persist a broken result. */\n lint?: (path: string, content: string) => string | null;\n /** optional PDF text extraction (node hosts wire a pdftotext-backed impl); absent => Read explains. */\n pdfText?: (path: string) => Promise<string>;\n /** optional model handle for tools that run their own LLM pass (e.g. Review, a self-critique).\n * Populated by the Agent from its own ai/model; absent => such tools degrade to a no-op. */\n ai?: ChatLike;\n model?: string;\n /** optional sandbox background-job registry; enables `bash({background:true})`. Absent => no backgrounding. */\n jobs?: SandboxJobRegistry;\n /** optional incremental-output channel: long-running tools (e.g. the real Shell) stream chunks\n * here mid-run. Wired PER CALL by Agent.dispatch to Hooks.onToolOutput (cleared when the call\n * settles — a late emit is a silent no-op). Fire-and-forget: never awaited, never part of the result. */\n emit?: (chunk: string) => void;\n /** Wrap a HUMAN-blocking await (permission/plan confirm, an interactive question) so the time\n * spent parked on the user is excluded from the run's wall-clock kill-switches. Wired by the Agent;\n * absent => no accounting (the promise is awaited as-is). Idle prompt time must not count as work. */\n parkHuman?<T>(p: Promise<T>): Promise<T>;\n /** Set by `AskUserQuestion` when the model has a decision that is genuinely the user's to make but\n * no human is reachable (headless/piped/edge). The Agent drains it after the tool batch and ends\n * the run with `finishReason:'needs_input'`, handing the question to the caller instead of letting\n * the agent guess. Cleared at the start of every run. */\n needsInput?: UserQuestion;\n}\n\nexport interface AgentTool {\n name: string;\n description: string;\n parameters: object; // JSON Schema for the function's arguments\n /**\n * Longest wall-clock time this tool can legitimately take before it returns on its own.\n * Declared so a TRANSPORT above the loop (e.g. the cursor helper's per-call watchdog) can derive a\n * deadline with real headroom instead of carrying an independently-maintained magic number that\n * drifts into a tie with the tool's own cap — a tie the transport wins, destroying the tool's real\n * result. Omit for tools that return promptly.\n */\n maxDurationMs?: number;\n /**\n * Is `maxDurationMs` SELF-ENFORCED — does this tool abort itself at that bound and return?\n * An enforced bound cannot be overrun, so a transport above it needs only modest slack; an ADVISORY\n * one (the default) may be exceeded, so the transport keeps generous headroom over it. Declaring a\n * bound you do not actually enforce is worse than declaring none — say `true` only when you abort.\n */\n maxDurationEnforced?: boolean;\n run(args: any, ctx: ToolContext): Promise<string | { text: string; images?: { mimeType: string; data: string }[] }>;\n /** Optional: return a copy of this tool bound to a different real-disk working directory.\n * Implemented by tools that escape the VFS (the real `Shell`), which are cwd-bound at construction\n * and would otherwise keep pointing at the PARENT's tree when the tool instance is inherited by an\n * isolated child agent. `subagent.ts` calls this for a worktree child; tools without it pass through.\n * Return `undefined` for a capability that CANNOT follow the child (the background-job companions,\n * bound to the parent's job registry) — the tool is then dropped from the child's toolbelt.\n * An implementation must carry over any post-construction mutation the host made to the instance\n * (a renamed `name`/`description`) — rebuilding from the factory's options alone loses it. */\n withCwd?(cwd: string): AgentTool | undefined;\n}\n\n/** Build a tool context bound to a filesystem backend (Mem / Disk / …) and an optional host. */\nexport function makeContext(fs: IFilesystem, host?: HostBridge): ToolContext {\n const exec = new CommandExecutor(fs);\n registerHeadlessCommands(exec);\n return { fs, exec, readState: new Map(), host, todos: [] };\n}\n\n/** Convert AgentTools into the ai.libx.js `tools` array for chat(). */\nexport function toWireTools(tools: AgentTool[]): Tool[] {\n return tools.map((t) => ({\n type: 'function',\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n}\n\nconst numberLines = (content: string, offset = 0, limit?: number): string => {\n const lines = content.split('\\n');\n const start = Math.max(0, offset);\n const end = limit != null ? start + limit : lines.length;\n return lines\n .slice(start, end)\n .map((l, i) => `${start + i + 1}\\t${l}`)\n .join('\\n');\n};\n\n/** Keep huge tool output high-signal: head+tail with an omission marker (cuts re-runs to \"parse the wall\"). */\nexport function truncateOutput(s: string, headLines = 80, tailLines = 20): string {\n const lines = s.split('\\n');\n if (lines.length <= headLines + tailLines + 1) return s;\n const omitted = lines.length - headLines - tailLines;\n return [...lines.slice(0, headLines), `… (${omitted} lines omitted — narrow the command to see more) …`, ...lines.slice(-tailLines)].join('\\n');\n}\n\n/** Run any shell command line over the VFS (ls/cat/grep/find/head/tail/echo/mkdir/rm/mv/wc, pipes, redirects, &&/||/;). */\nexport const bashTool: AgentTool = {\n name: 'bash',\n description:\n 'Run a shell command. Supports ls, cat, grep, find, head, tail, echo, mkdir, rm, mv, cp, wc, pipes (|), redirects (>, >>), and chaining (&&, ||, ;). Best for: running tests/builds, file operations (mkdir/mv/rm), and piped workflows. For searching file contents, prefer `Grep` (structured results, no re-parse). For finding files by name, prefer `Glob`.',\n parameters: {\n type: 'object',\n required: ['command'],\n properties: {\n command: { type: 'string', description: 'the command line to execute' },\n background: { type: 'boolean', description: 'run detached over an isolated overlay (writes commit when it finishes); returns a job id to poll with JobOutput. Only worth it for slow work (remote VFS / long pipelines).' },\n },\n },\n async run({ command, background }, ctx) {\n if (background && ctx.jobs) return startBashJob(String(command ?? ''), ctx);\n const r = await ctx.exec.execute(String(command ?? ''));\n const out = truncateOutput((r.output ?? '').replace(/\\n+$/, ''));\n if (r.exitCode !== 0) {\n const err = (r.error ?? '').trim();\n return `[exit ${r.exitCode}]${err ? ' ' + err : ''}${out ? '\\n' + out : ''}`;\n }\n return out || '(command succeeded, no output)'; // explicit sentinel: don't re-run to \"check\"\n },\n};\n\n/** Kick a bash command into the background over an isolated overlay; its writes commit only on success.\n * A kill (abort) before completion skips the commit — the parent VFS is never touched mid-flight. */\nfunction startBashJob(command: string, ctx: ToolContext): string {\n const baseFs = ctx.fs;\n const id = ctx.jobs!.start(\n async ({ signal }) => {\n const overlay = new OverlayFilesystem(baseFs);\n const exec = new CommandExecutor(overlay);\n registerHeadlessCommands(exec);\n const r = await exec.execute(command); // wcli is sync-to-completion; abort can only gate the commit below\n if (signal.aborted) return '[killed before commit]';\n await overlay.commit(); // atomically flush this job's writes down into the parent VFS\n const out = truncateOutput((r.output ?? '').replace(/\\n+$/, ''));\n return r.exitCode !== 0 ? `[exit ${r.exitCode}] ${(r.error ?? '').trim()}\\n${out}`.trim() : out || '(command succeeded, no output)';\n },\n { kind: 'bash', label: command.slice(0, 60) },\n );\n return `Started background job ${id} — poll with JobOutput({id:\"${id}\"}) / JobStatus, stop with JobKill.`;\n}\n\n/** Image extensions the Read tool returns as a visual block (when the fs can read bytes). */\n/** The real on-disk path behind a VFS path, when the fs exposes one; null (with a reason) otherwise —\n * callers then fall back to inlining the bytes. */\nfunction realPathOf(fs: { realPath?: (p: string) => string }, path: string): string | null {\n if (typeof fs.realPath !== 'function') return null;\n try { return fs.realPath(path); }\n catch (e) { log.debug(`realPath unavailable for ${path} — inlining image bytes instead`, e); return null; }\n}\n\nconst IMG_MIME: Record<string, string> = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', webp: 'image/webp' };\n\n/** Heuristic: is this utf8-decoded string actually a binary file? A NUL byte never occurs in text; a\n * dense run of U+FFFD replacement chars means the bytes weren't valid utf8. Cheap — scans a prefix. */\nfunction isBinary(raw: string): boolean {\n if (raw === '') return false; // empty is handled separately (could be a legit 0-byte text file)\n const head = raw.length > 8192 ? raw.slice(0, 8192) : raw;\n let repl = 0;\n for (let i = 0; i < head.length; i++) {\n const c = head.charCodeAt(i);\n if (c === 0x00) return true; // NUL byte -> definitively binary\n if (c === 0xfffd) repl++; // utf8 decode failure marker\n }\n return repl / head.length > 0.1;\n}\n\n/** Byte length of a file — exact via readFileBytes when the fs exposes it, else utf8 byte estimate. */\nasync function byteSize(fs: unknown, path: string, raw: string): Promise<number> {\n const bfs = fs as { readFileBytes?: (p: string) => Promise<Uint8Array> };\n if (typeof bfs.readFileBytes === 'function') {\n try { return (await bfs.readFileBytes(path)).length; } catch { /* fall through to estimate */ }\n }\n return Buffer.byteLength(raw, 'utf8');\n}\n\n/** Read a text file as 1-indexed numbered lines; arms the staleness guard for Edit. */\nexport const readTool: AgentTool = {\n name: 'Read',\n description:\n 'Read a file. Text files return 1-indexed numbered lines (with optional `offset`/`limit` and a re-Read pointer for partial reads). Image files (png/jpg/jpeg/gif/webp) return the picture itself so you can SEE it. PDFs return their extracted text. Always Read a file before Editing it.',\n parameters: {\n type: 'object',\n required: ['path'],\n properties: {\n path: { type: 'string' },\n offset: { type: 'number' },\n limit: { type: 'number' },\n },\n },\n async run({ path, offset, limit }, ctx) {\n // Image file → return it as a visual block. The adapter turns a tool result whose JSON carries a\n // `dataUrl` into an image tool_result the model can see. Needs a binary-capable fs (disk default);\n // the utf8 VFS (sandbox/Mem) can't, so we say so instead of corrupting the bytes.\n const ext = String(path).toLowerCase().split('.').pop() ?? '';\n // PDF → extracted text when the host wired an extractor (CLI: pdftotext); else say how to proceed.\n if (ext === 'pdf') {\n if (!ctx.pdfText) return `[${path} is a PDF — text extraction isn't available in this environment (install poppler's pdftotext and run on disk).]`;\n if (!(await ctx.fs.exists(path))) return `Error: File not found: ${path}`; // jail-aware: hidden paths read as absent\n const text = (await ctx.pdfText(ctx.fs.resolvePath(path))).trim();\n return text ? numberLines(text, Math.max(0, offset ?? 0), limit) : `[${path}: no extractable text (scanned/image-only PDF?)]`;\n }\n if (IMG_MIME[ext]) {\n const fs = ctx.fs as { readFileBytes?: (p: string) => Promise<Uint8Array>; realPath?: (p: string) => string };\n if (typeof fs.readFileBytes !== 'function') {\n return `[${path} is an image, but this filesystem can't read binary — attach it as @${path} instead, or run on disk.]`;\n }\n // Persist a REFERENCE, not the payload: the send path (expandImagesForSend) turns it back into the\n // same `{dataUrl}` body the wire adapter renders, for the recent images only — so a screenshot Read\n // costs ~80 bytes in the transcript/session JSON instead of megabytes of immortal base64.\n const real = realPathOf(fs, path);\n if (real) {\n if (!(await ctx.fs.exists(path))) return `Error: File not found: ${path}`;\n return imageRefResult(real, IMG_MIME[ext]);\n }\n const bytes = await fs.readFileBytes(path);\n const b64 = Buffer.from(bytes).toString('base64');\n return JSON.stringify({ dataUrl: `data:${IMG_MIME[ext]};base64,${b64}`, image: path });\n }\n const raw = await ctx.fs.readFile(path);\n // Binary guard: a non-text file (a .png without a recognized ext, .zip, .bin, …) read as utf8 is\n // either empty or replacement-char garbage — both silently pollute context. A silent empty tool\n // result is plausibly what tips a delegated model (cursor/composer) into an empty reply, where a\n // native model tolerates it. Return an explicit, non-empty marker so the model always sees SOMETHING.\n if (isBinary(raw)) {\n const bytes = await byteSize(ctx.fs, path, raw);\n return `[binary file: ${path} — ${bytes} bytes, not shown as text. Read renders png/jpg/jpeg/gif/webp images directly; otherwise attach it as @${path}.]`;\n }\n ctx.readState.set(ctx.fs.resolvePath(path), raw); // staleness guard tracks the REAL content\n if (raw === '') return `[empty file: ${path} — 0 bytes]`;\n // Mask secret values in config files so keys can live there usably-but-hidden (line count is preserved).\n const content = CONFIG_FILE_RE.test(ctx.fs.resolvePath(path)) ? redactSecrets(raw) : raw;\n const total = content === '' ? 0 : content.split('\\n').length;\n const start = Math.max(0, offset ?? 0);\n const body = numberLines(content, start, limit);\n // snippet-with-pointer: when the slice doesn't cover the whole file, tell the\n // model what it's missing + how to pull it — so it expands precisely instead of re-reading blind.\n const shownEnd = limit != null ? Math.min(start + limit, total) : total;\n const shownCount = Math.max(0, shownEnd - start);\n if (shownCount >= total) return body; // whole file shown — no footer\n if (shownCount === 0) return `[no lines in range (offset ${start}${limit != null ? `, limit ${limit}` : ''}) — file has ${total} line(s)]`;\n return `${body}\\n\\n[lines ${start + 1}–${shownEnd} of ${total} · re-Read with offset/limit for the rest]`;\n },\n};\n\n/** Replace an exact, unique substring; requires a prior Read and guards against stale edits. */\nexport const editTool: AgentTool = {\n name: 'Edit',\n description:\n 'Replace an exact substring in a file. Requires a prior Read of the same file. `old_string` must occur exactly once — include surrounding context to disambiguate.',\n parameters: {\n type: 'object',\n required: ['path', 'old_string', 'new_string'],\n properties: {\n path: { type: 'string' },\n old_string: { type: 'string' },\n new_string: { type: 'string' },\n },\n },\n async run({ path, old_string, new_string }, ctx) {\n const key = ctx.fs.resolvePath(path);\n const snapshot = ctx.readState.get(key);\n if (snapshot == null) throw new Error(`File has not been read yet: ${path}. Read it before editing.`);\n const current = await ctx.fs.readFile(path);\n if (current !== snapshot) throw new Error(`File ${path} changed since it was read (stale). Re-read before editing.`);\n const count = old_string === '' ? 0 : current.split(old_string).length - 1;\n if (count > 1) throw new Error(`old_string is not unique in ${path} (${count} matches). Provide more surrounding context.`);\n let next: string, note = '';\n if (count === 1) {\n next = current.replace(old_string, () => new_string); // exact: function replacer, no $-pattern expansion\n } else {\n // exact match failed — try a whitespace-tolerant unique match before giving up (cuts re-read churn)\n const fuzzy = fuzzyLineReplace(current, old_string, new_string);\n if (fuzzy == null) throw new Error(`old_string not found in ${path}.`);\n next = fuzzy;\n note = ' (whitespace-tolerant match)';\n }\n if (ctx.lint) { const err = ctx.lint(path, next); if (err) throw new Error(err); }\n await ctx.fs.writeFile(path, next);\n ctx.readState.set(key, next);\n return `Edited ${path}${note}`;\n },\n};\n\n/** Session-exit tool: the model calls this when the user wants to end the conversation.\n * The `onExit` callback is injected by the host (CLI sets it to flip a flag that breaks the REPL loop). */\nexport function exitSessionTool(onExit: () => void): AgentTool {\n return {\n name: 'ExitSession',\n description:\n 'End the current session and exit the CLI. Call this when the user says goodbye, asks to quit, ' +\n 'or clearly indicates they want to stop the conversation (e.g. \"ok bye\", \"that\\'s all\", \"exit\", \"goodnight\").',\n parameters: { type: 'object', properties: {} },\n async run() {\n onExit();\n return 'Session ending. Goodbye!';\n },\n };\n}\n\nexport function defaultTools(): AgentTool[] {\n return [bashTool, readTool, editTool];\n}\n\n/**\n * The full catalog of selectable tools, keyed by name. The evolve loop's mutation\n * surface picks from this registry; embedders can build a custom tool set by name.\n */\nexport function toolRegistry(): Record<string, AgentTool> {\n const all = [bashTool, readTool, editTool, grepTool, globTool, writeTool, multiEditTool, applyEditsTool, repoMapTool, reviewTool(), todoWriteTool, webFetchTool, webSearchTool, webSearchAnthropicTool];\n return Object.fromEntries(all.map((t) => [t.name, t]));\n}\n\n/** Resolve a list of tool names against `available` (host-supplied tools, e.g. a parent agent's\n * toolbelt or mounted MCP tools) first, then the built-in registry. Unknown names throw.\n * Without `available` an allowlist could only ever name a built-in — so a def could not scope a\n * child to a tool its parent injected (`Bash`, `ToolSearch`, …). */\nexport function toolsByName(names: string[], available?: AgentTool[]): AgentTool[] {\n const reg = toolRegistry();\n const extra = Object.fromEntries((available ?? []).map((t) => [t.name, t]));\n return names.map((n) => {\n const t = extra[n] ?? reg[n];\n if (!t) throw new Error(`unknown tool '${n}'. Known: ${[...new Set([...Object.keys(extra), ...Object.keys(reg)])].join(', ')}`);\n return t;\n });\n}\n","import { promises as fsp, realpathSync } from 'node:fs';\nimport * as np from 'node:path';\nimport type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\nimport { PathResolver } from '@livx.cc/wcli/core';\n\n/**\n * Real-disk backend implementing wcli's IFilesystem, rooted at `baseDir`.\n * The VFS path space ('/...') maps under baseDir, so the same agent/tools/commands\n * run unchanged against disk or memory — complete mem↔disk interchangeability.\n * Semantics mirror MemFilesystem (throws on missing parent / existing dir / etc.).\n */\nexport class NodeDiskFilesystem implements IFilesystem {\n private cwd = '/';\n private opts: { denySymlinks: boolean };\n\n constructor(private baseDir: string, opts: { denySymlinks?: boolean } = {}) {\n // denySymlinks (default ON): refuse to traverse a symlink anywhere in the path, so\n // a symlink planted inside the root cannot escape it (read/write/delete a target outside).\n this.opts = { denySymlinks: true, ...opts };\n }\n\n /** Ensure the root dir exists. */\n async init(): Promise<void> {\n await fsp.mkdir(this.baseDir, { recursive: true });\n }\n\n private real(vpath: string): string {\n return np.join(this.baseDir, '.' + vpath); // vpath is absolute in VFS space\n }\n\n // Verified non-symlink DIRECTORY components, with a short TTL: tree walks (Glob/Grep) hit the same\n // parents thousands of times; re-lstat'ing each per op is the dominant syscall cost. The 1s window\n // is an accepted race only against an out-of-band symlink swap mid-walk (this FS can't create\n // symlinks itself); leaf components are never cached.\n private verified = new Map<string, number>();\n private static VERIFY_TTL_MS = 1000;\n\n /** Throw if any existing component of `real` is a symlink (escape vector). */\n private async assertNoSymlink(real: string): Promise<void> {\n if (!this.opts.denySymlinks) return;\n const rel = np.relative(this.baseDir, real);\n if (rel === '' || rel.startsWith('..')) return; // root itself / outside (can't happen post-join)\n const parts = rel.split(np.sep);\n let cur = this.baseDir;\n const now = Date.now();\n for (let i = 0; i < parts.length; i++) {\n cur = np.join(cur, parts[i]);\n const isLeaf = i === parts.length - 1;\n if (!isLeaf && (this.verified.get(cur) ?? 0) > now) continue;\n let st;\n try { st = await fsp.lstat(cur); } catch { return; } // component doesn't exist yet (e.g. new file) — nothing further to check\n if (st.isSymbolicLink()) throw new Error('File not found: symlink not permitted');\n if (!isLeaf) {\n if (this.verified.size > 10_000) this.verified.clear(); // bound memory on huge trees\n this.verified.set(cur, now + NodeDiskFilesystem.VERIFY_TTL_MS);\n }\n }\n }\n\n resolvePath(path: string, cwd?: string): string {\n return PathResolver.resolve(path, cwd || this.cwd);\n }\n getCwd(): string { return this.cwd; }\n setCwd(path: string): void { this.cwd = PathResolver.normalize(path); }\n\n async readFile(path: string): Promise<string> {\n const r = this.real(this.resolvePath(path));\n try {\n await this.assertNoSymlink(r);\n const st = await fsp.stat(r);\n if (st.isDirectory()) throw new Error(`Not a file: ${path}`);\n return await fsp.readFile(r, 'utf8');\n } catch (e) {\n if (e instanceof Error && /Not a file/.test(e.message)) throw e;\n throw new Error(`File not found: ${path}`);\n }\n }\n\n /** The REAL on-disk path behind a VFS path — an optional capability (not on IFilesystem) the Read\n * tool duck-types so it can persist an image REFERENCE instead of megabytes of base64. */\n realPath(path: string): string { return this.real(this.resolvePath(path)); }\n\n /** The CANONICAL on-disk path — symlinks resolved. `realPath` is path arithmetic (baseDir + vpath)\n * and therefore reports a symlink and its target as different places, which is no use as an\n * identity: a tree walk that dedupes on it still re-enters a loop (`a/b/loop -> a` re-walked 11\n * times before a depth cap stopped it). Optional capability, duck-typed by the file-scanning\n * tools; falls back to the arithmetic path for anything unresolvable (a broken/racing link). */\n canonicalPath(path: string): string {\n const p = this.realPath(path);\n try { return realpathSync(p); } catch { return p; }\n }\n\n /** Read raw bytes (for binary files like images). Not on the base IFilesystem (which is utf8-only) — an\n * optional capability the Read tool duck-types to return image blocks. Same symlink/jail guards as readFile. */\n async readFileBytes(path: string): Promise<Uint8Array> {\n const r = this.real(this.resolvePath(path));\n try {\n await this.assertNoSymlink(r);\n const st = await fsp.stat(r);\n if (st.isDirectory()) throw new Error(`Not a file: ${path}`);\n return await fsp.readFile(r); // no encoding → Buffer (Uint8Array)\n } catch (e) {\n if (e instanceof Error && /Not a file/.test(e.message)) throw e;\n throw new Error(`File not found: ${path}`);\n }\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n const r = this.real(this.resolvePath(path));\n await this.assertNoSymlink(r);\n const parent = np.dirname(r);\n try {\n if (!(await fsp.stat(parent)).isDirectory()) throw 0;\n } catch {\n throw new Error(`Parent directory does not exist: ${path}`);\n }\n await fsp.writeFile(r, content, 'utf8');\n }\n\n async deleteFile(path: string): Promise<void> {\n const r = this.real(this.resolvePath(path));\n await this.assertNoSymlink(r);\n let st;\n try { st = await fsp.stat(r); } catch { throw new Error(`File not found: ${path}`); }\n if (st.isDirectory()) {\n if ((await fsp.readdir(r)).length > 0) throw new Error(`Directory not empty: ${path}`);\n await fsp.rmdir(r);\n } else {\n await fsp.unlink(r);\n }\n }\n\n async readDir(path: string): Promise<string[]> {\n const r = this.real(this.resolvePath(path));\n try { await this.assertNoSymlink(r); return await fsp.readdir(r); }\n catch { throw new Error(`Directory not found: ${path}`); }\n }\n\n async createDir(path: string): Promise<void> {\n if (await this.exists(path)) throw new Error(`File or directory already exists: ${path}`);\n const r = this.real(this.resolvePath(path));\n await this.assertNoSymlink(r);\n const parent = np.dirname(r);\n try {\n if (!(await fsp.stat(parent)).isDirectory()) throw 0;\n } catch {\n throw new Error(`Parent directory does not exist: ${path}`);\n }\n await fsp.mkdir(r);\n }\n\n async exists(path: string): Promise<boolean> {\n const r = this.real(this.resolvePath(path));\n try { await this.assertNoSymlink(r); await fsp.stat(r); return true; } catch { return false; }\n }\n\n async stat(path: string): Promise<FileMetadata> {\n let s;\n const r = this.real(this.resolvePath(path));\n try { await this.assertNoSymlink(r); s = await fsp.stat(r); }\n catch { throw new Error(`File not found: ${path}`); }\n return {\n created: s.birthtime,\n modified: s.mtime,\n size: s.size,\n permissions: s.isDirectory() ? 'drwxr-xr-x' : '-rw-r--r--',\n isExecutable: false,\n };\n }\n\n async isDirectory(path: string): Promise<boolean> {\n const r = this.real(this.resolvePath(path));\n try { await this.assertNoSymlink(r); return (await fsp.stat(r)).isDirectory(); } catch { return false; }\n }\n async isFile(path: string): Promise<boolean> {\n const r = this.real(this.resolvePath(path));\n try { await this.assertNoSymlink(r); return (await fsp.stat(r)).isFile(); } catch { return false; }\n }\n}\n","import type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\nimport { globToRegExp } from './tools.structured';\n\n/**\n * Containment boundary A — a policy decorator over ANY IFilesystem.\n *\n * The agent only ever sees an IFilesystem, so what it can touch is exactly what we\n * mount. This jail:\n * - hides + blocks `deny` paths entirely (secrets: .env, keys, .git, …) — invisible\n * to read/stat/exists/readDir, unwritable;\n * - makes `readonly` paths readable but unwritable (the \"constitution\": pinned\n * grader/suite/criteria the self-evolve agent must never edit);\n * - optionally `confineTo` a set of subtrees (anything outside is denied);\n * - normalizes paths first, so `..` traversal (`/src/../.env`) is caught after resolution;\n * - reports every violation via `onViolation` (audit trail / circuit-breaker hook).\n *\n * Crucial limitation: this guards what the AGENT'S TOOLS touch. It does NOT contain\n * code executed against the real disk at eval time (the grader imports agent-written\n * code) — that is boundary B (a sandboxed subprocess). See mind/08-self-evolve.md.\n */\nexport class JailedFilesystem implements IFilesystem {\n public options: JailOptions;\n private denyRe: RegExp[];\n private roRe: RegExp[];\n private confineRe?: RegExp[];\n\n constructor(private inner: IFilesystem, options?: Partial<JailOptions>) {\n this.options = { ...new JailOptions(), ...options };\n // case-insensitive so /.ENV, /Id_Rsa, … can't slip past a lowercase rule.\n this.denyRe = this.options.deny.map((g) => globToRegExp(g, true));\n this.roRe = this.options.readonly.map((g) => globToRegExp(g, true));\n this.confineRe = this.options.confineTo?.map((g) => globToRegExp(g, true));\n }\n\n private abs(path: string): string {\n return this.inner.resolvePath(path, this.inner.getCwd());\n }\n\n /** Throw if reading `path` is not permitted (denied or out of confinement). */\n private guardRead(op: string, path: string): string {\n const abs = this.abs(path);\n if (this.confineRe && !this.confineRe.some((r) => r.test(abs))) return this.violate(op, abs, 'confine');\n if (this.denyRe.some((r) => r.test(abs))) return this.violate(op, abs, 'deny');\n return abs;\n }\n\n /** Throw if writing/deleting `path` is not permitted (denied, readonly, or out of confinement). */\n private guardWrite(op: string, path: string): string {\n const abs = this.guardRead(op, path); // write implies read access first\n if (this.roRe.some((r) => r.test(abs))) return this.violate(op, abs, 'readonly');\n return abs;\n }\n\n private violate(op: string, abs: string, rule: string): never {\n this.note(op, abs, rule);\n // Read denials masquerade as \"not found\" to avoid confirming a secret's existence.\n if (rule === 'deny' || rule === 'confine') throw new Error(`File not found: ${abs}`);\n throw new Error(`Blocked by filesystem jail (${rule}): ${abs}`);\n }\n\n /** Fire the audit hook without throwing (for boolean probes that must still return false). */\n private note(op: string, abs: string, rule: string): void {\n this.options.onViolation?.({ op, path: abs, rule });\n }\n\n /** Is `abs` (already-resolved) visible? If not, fire the audit hook (op given) and return false. */\n private visible(abs: string, op?: string): boolean {\n if (this.confineRe && !this.confineRe.some((r) => r.test(abs))) { if (op) this.note(op, abs, 'confine'); return false; }\n if (this.denyRe.some((r) => r.test(abs))) { if (op) this.note(op, abs, 'deny'); return false; }\n return true;\n }\n\n async readFile(path: string): Promise<string> { return this.inner.readFile(this.guardRead('readFile', path)); }\n /** Forward the optional binary-read capability (if the inner fs has it), jailed like readFile. */\n async readFileBytes(path: string): Promise<Uint8Array> {\n const inner = this.inner as { readFileBytes?: (p: string) => Promise<Uint8Array> };\n if (typeof inner.readFileBytes !== 'function') throw new Error('binary read not supported by this filesystem');\n return inner.readFileBytes(this.guardRead('readFileBytes', path));\n }\n /** Forward the optional real-path capability (image REFS), jail-guarded like readFile. */\n realPath(path: string): string {\n const inner = this.inner as { realPath?: (p: string) => string };\n if (typeof inner.realPath !== 'function') throw new Error('realPath not supported by this filesystem');\n return inner.realPath(this.guardRead('realPath', path));\n }\n async writeFile(path: string, content: string): Promise<void> { return this.inner.writeFile(this.guardWrite('writeFile', path), content); }\n async deleteFile(path: string): Promise<void> { return this.inner.deleteFile(this.guardWrite('deleteFile', path)); }\n async createDir(path: string): Promise<void> { return this.inner.createDir(this.guardWrite('createDir', path)); }\n async stat(path: string): Promise<FileMetadata> { return this.inner.stat(this.guardRead('stat', path)); }\n\n // Boolean probes stay invisible (return false on a denied path) BUT still fire the\n // audit hook — otherwise an agent could enumerate secrets via exists() without\n // ever tripping the circuit breaker.\n async exists(path: string): Promise<boolean> {\n const abs = this.abs(path);\n return this.visible(abs, 'exists') ? this.inner.exists(abs) : false;\n }\n async isDirectory(path: string): Promise<boolean> {\n const abs = this.abs(path);\n return this.visible(abs, 'isDirectory') ? this.inner.isDirectory(abs) : false;\n }\n async isFile(path: string): Promise<boolean> {\n const abs = this.abs(path);\n return this.visible(abs, 'isFile') ? this.inner.isFile(abs) : false;\n }\n\n /** List a directory, filtering out entries the policy hides. */\n async readDir(path: string): Promise<string[]> {\n const abs = this.guardRead('readDir', path);\n const entries = await this.inner.readDir(abs);\n return entries.filter((name) => this.visible(abs === '/' ? `/${name}` : `${abs}/${name}`));\n }\n\n resolvePath(path: string, cwd?: string): string { return this.inner.resolvePath(path, cwd ?? this.inner.getCwd()); }\n getCwd(): string { return this.inner.getCwd(); }\n /** Guard cwd too: the jail must never be able to \"stand\" on a denied/out-of-confine dir. */\n setCwd(path: string): void {\n const abs = this.abs(path);\n if (!this.visible(abs, 'setCwd')) throw new Error(`File not found: ${abs}`);\n this.inner.setCwd(abs);\n }\n}\n\n/** Default denylist: secrets and VCS internals that must never be read or written.\n * Patterns are matched case-insensitively (so /.ENV is covered too). */\nexport const DEFAULT_DENY: string[] = [\n // env / config secrets\n '**/.env', '**/.env.*', '**/.npmrc', '**/.netrc',\n // private keys & certs\n '**/*.pem', '**/*.key', '**/*.crt', '**/*.cert', '**/*.p12', '**/*.pfx',\n '**/id_rsa', '**/id_rsa.*', '**/id_ed25519', '**/id_ed25519.*',\n '**/id_dsa', '**/id_dsa.*', '**/id_ecdsa', '**/id_ecdsa.*',\n // credential stores (dir AND contents)\n '**/.ssh', '**/.ssh/**', '**/.aws', '**/.aws/**',\n '**/.docker', '**/.docker/**', '**/.dockercfg',\n '**/.kube', '**/.kube/**', '**/.kubeconfig',\n '**/credentials', '**/.credentials', '**/secrets.json',\n // VCS internals + git config (can carry tokens / remote creds)\n '**/.git', '**/.git/**', '**/.gitconfig', '**/.gitmodules',\n];\n\nexport class JailOptions {\n /** Globs that are invisible and unwritable (secrets). */\n deny: string[] = [...DEFAULT_DENY];\n /** Globs readable but not writable/deletable (the pinned constitution). */\n readonly: string[] = [];\n /** If set, only paths matching these globs are accessible at all. */\n confineTo?: string[];\n /** Audit hook fired on every blocked operation (drives the circuit breaker). */\n onViolation?: (v: { op: string; path: string; rule: string }) => void;\n}\n","/**\n * Tier-1 OS sandbox for the real `Shell` tool (mind/03-roadmap.md \"capability tiers\").\n *\n * Wraps the spawned `/bin/sh` in the platform's process sandbox so a hostile/buggy command\n * can read the machine but can only WRITE inside an allowlist (cwd + tmp + extra `writePaths`),\n * and gets no network unless granted:\n * - macOS: `sandbox-exec` (seatbelt) with a generated profile\n * - Linux: `bwrap` (bubblewrap) with `--ro-bind / /` + writable binds\n *\n * Pure argv builders (unit-testable, no node imports) + an async wrapper-binary locator.\n * This complements — does not replace — env secret-scrubbing and the permission prompt:\n * the FS jail can't contain a real process; this makes the *process* itself contained.\n */\n\nexport class OsSandboxOptions {\n /** Allow outbound network. Default OFF (Tier-1: no network unless granted). */\n network = false;\n /** Extra absolute paths writable beyond cwd + tmp (e.g. a build cache). */\n writePaths: string[] = [];\n}\n\nexport interface SandboxWrap {\n bin: string;\n args: string[]; // full argv: wrapper flags + /bin/sh -c <command>\n}\n\n/** Writable allowlist shared by both platforms: cwd, the tmp roots, /dev. */\nfunction writable(cwd: string, o: OsSandboxOptions, tmpDir?: string): string[] {\n const set = new Set<string>([cwd, '/tmp', '/private/tmp', '/private/var/folders', '/dev', ...(tmpDir ? [tmpDir] : []), ...o.writePaths]);\n return [...set];\n}\n\nconst sbQuote = (p: string) => `\"${p.replace(/([\"\\\\])/g, '\\\\$1')}\"`;\n\n/** macOS seatbelt profile: allow everything, then deny writes/network, then re-allow the allowlist\n * (seatbelt resolves conflicts by specificity, so subpath allows override the broad deny). */\nexport function seatbeltProfile(cwd: string, o: OsSandboxOptions, tmpDir?: string): string {\n const allows = writable(cwd, o, tmpDir).map((p) => `(subpath ${sbQuote(p)})`).join(' ');\n return [\n '(version 1)',\n '(allow default)',\n ...(o.network ? [] : ['(deny network*)']),\n '(deny file-write*)',\n `(allow file-write* ${allows})`,\n ].join('\\n');\n}\n\n/** Build the wrapped argv for `sh -c <command>`, or null if `platform` has no supported wrapper. */\nexport function sandboxArgv(command: string, cwd: string, opts: Partial<OsSandboxOptions> = {}, platform: string = process.platform, tmpDir?: string): SandboxWrap | null {\n const o = { ...new OsSandboxOptions(), ...opts };\n if (platform === 'darwin') {\n return { bin: '/usr/bin/sandbox-exec', args: ['-p', seatbeltProfile(cwd, o, tmpDir), '/bin/sh', '-c', command] };\n }\n if (platform === 'linux') {\n const binds = writable(cwd, o, tmpDir).filter((p) => p !== '/dev' && !p.startsWith('/private')).flatMap((p) => ['--bind-try', p, p]);\n return {\n bin: 'bwrap',\n args: ['--ro-bind', '/', '/', ...binds, '--dev', '/dev', '--proc', '/proc', '--die-with-parent', ...(o.network ? [] : ['--unshare-net']), '/bin/sh', '-c', command],\n };\n }\n return null;\n}\n\n/** Locate the wrapper binary for this platform; null = sandboxing unavailable here. */\nexport async function findSandboxWrapper(platform: string = process.platform): Promise<string | null> {\n const { existsSync } = await import('node:fs');\n if (platform === 'darwin') return existsSync('/usr/bin/sandbox-exec') ? '/usr/bin/sandbox-exec' : null;\n if (platform === 'linux') {\n for (const dir of (process.env.PATH ?? '/usr/bin:/bin').split(':')) if (dir && existsSync(`${dir}/bwrap`)) return `${dir}/bwrap`;\n return null;\n }\n return null;\n}\n","import type { AgentTool } from './tools';\nimport { truncateOutput } from './tools';\nimport { redactSecrets } from './redact';\nimport { forComponent } from './logging';\nimport { sandboxArgv, findSandboxWrapper, type OsSandboxOptions } from './shell.sandbox';\n\n/**\n * Real shell tool — node-only, OPT-IN, and deliberately NOT edge-portable.\n *\n * ⚠️ Unlike the default VFS `bash` (a sandboxed JS interpreter over the virtual filesystem),\n * this spawns a REAL `/bin/sh` process. It can run `bun`, `git`, `ssh`, scripts, deploys —\n * and, by the same token, it is NOT sandboxed: only cwd-binding constrains it. It is a\n * deliberate host escalation, kept out of `defaultTools()`/`toolRegistry()` and out of the\n * edge-safe `src/index.ts` (same policy as `mcp.client.ts`). A host opts in explicitly:\n *\n * tools: [...defaultTools(), makeRealShellTool({ cwd: nodeDiskRoot })]\n *\n * Mirrors `tools.web.ts`: a factory with an injectable `spawn` (tests + edge never import\n * node:child_process), an options bag, abort + timeout honored, output capped. Safety beyond\n * cwd-binding is the host's to add (e.g. a PermissionPolicy `decision:'ask'` per command, or\n * an OS sandbox wrapper) — see mind/03-roadmap.md \"OS-level access — capability tiers\".\n */\n\nconst log = forComponent('shell');\n\n/** Normalize shell output for return: trim trailing newlines, mask secret values, then size-truncate.\n * Redaction runs BEFORE truncation so a masked tail can't smuggle a secret past the line cap. */\nconst clean = (s: string): string => truncateOutput(redactSecrets(s.replace(/\\n+$/, '')));\n\n/** The slice of node's `child_process.spawn` we depend on — injectable so tests supply a fake. */\nexport type SpawnFn = (\n command: string,\n args: string[],\n options: {\n cwd?: string;\n env?: Record<string, string | undefined>;\n signal?: AbortSignal;\n /** stdio layout. We force stdin to /dev/null so a child can't block on (or steal) the REPL's input. */\n stdio?: ['ignore', 'pipe', 'pipe'];\n /** Run in a new session/process group (setsid) — detaches from the controlling terminal. See DETACHED. */\n detached?: boolean;\n },\n) => SpawnedProcess;\n\n/** Minimal `ChildProcess` surface this tool uses. */\nexport interface SpawnedProcess {\n stdout?: { on(ev: 'data', cb: (chunk: any) => void): void } | null;\n stderr?: { on(ev: 'data', cb: (chunk: any) => void): void } | null;\n on(ev: 'close', cb: (code: number | null) => void): void;\n on(ev: 'error', cb: (err: Error) => void): void;\n kill(signal?: string): void;\n /** Child PID — present on the real node child; used to signal the whole process group on abort. */\n pid?: number;\n}\n\n/**\n * Detach every spawned child from the REPL's controlling terminal.\n *\n * `stdio: ['ignore', 'pipe', 'pipe']` — stdin is /dev/null (clean EOF; nothing to block on).\n * `detached: true` — setsid() puts the child in its OWN session with NO controlling tty.\n *\n * Without this a child inherits the agent's tty: an interactive prompt (`sudo`, `ssh`, a git\n * credential helper) opens `/dev/tty` directly and then RACES the REPL's raw-mode input reader for\n * the user's keystrokes — a deadlock that also captures whatever the user types (e.g. a password)\n * into the agent instead of the program. Detached, those programs find no tty and fail FAST with a\n * legible error (\"sudo: a terminal is required …\") which the model can act on (tell the user to run\n * it via `!`), instead of hanging until the 120s timeout. Side benefit: the child is a process-group\n * leader, so abort/timeout can reap the whole subtree, not just /bin/sh. */\nconst DETACHED = { stdio: ['ignore', 'pipe', 'pipe'] as ['ignore', 'pipe', 'pipe'], detached: true };\n\n/** Signal a child's WHOLE process group (`-pid`). Children are group leaders (DETACHED), so `proc.kill`\n * hits only /bin/sh and orphans descendants; this reaps the subtree. Best-effort — the group may\n * already be gone, and the fake spawn in tests has no real pid. Returns false when nothing was signaled. */\nfunction killGroup(proc: SpawnedProcess | undefined, signal: 'SIGTERM' | 'SIGKILL'): boolean {\n if (!proc?.pid) return false;\n try { process.kill(-proc.pid, signal); return true; } catch { return false; /* already exited / no such group */ }\n}\n\nexport interface RealShellOptions {\n /** Working directory the shell is bound to (typically a NodeDiskFilesystem `baseDir`). Required. */\n cwd: string;\n /** Shell binary for `-c` (e.g. the user's `$SHELL`). Default `/bin/sh`. Only honored when NOT\n * OS-sandboxed (the sandbox wrapper pins its own shell). */\n shell?: string;\n /** Override the spawner (tests inject a fake; default lazily imports node:child_process). */\n spawn?: SpawnFn;\n /** Per-command wall-clock cap (kill on overrun). Default 120s. */\n timeoutMs?: number;\n /** Ceiling for the model-supplied `timeoutMs` argument (a long build can ask for more than the\n * default, but not for an unbounded turn). Default 10min. */\n maxTimeoutMs?: number;\n /** Extra env merged over the (optionally scrubbed) base env for the child. */\n env?: Record<string, string>;\n /** Strip likely-secret vars (API keys, tokens, cloud creds) from the child's env. Default ON.\n * The FS jail does NOT contain a real process, so this is the seam that keeps `echo $ANTHROPIC_API_KEY`\n * from leaking the host's secrets to a spawned command. `false` passes `process.env` through verbatim. */\n redactEnv?: boolean;\n /** Job registry enabling `Shell({background:true})` (long-running processes). Pair with `makeShellJobTools`. */\n registry?: ShellJobRegistry;\n /** Tier-1 OS sandbox: wrap /bin/sh in sandbox-exec (macOS) / bwrap (Linux) — writes confined to\n * cwd+tmp, network blocked unless granted. `true` = defaults; commands FAIL (don't silently run\n * unsandboxed) if no wrapper exists on this platform. See src/shell.sandbox.ts. */\n osSandbox?: boolean | Partial<OsSandboxOptions>;\n /** Does a background job outlive the current run? False on one-shot hosts (the process exits and\n * `killOnExit` reaps the job), which the Shell tool's description must say rather than promise\n * cross-turn survival it won't get. Default true. */\n jobsSurviveRun?: boolean;\n}\n\n/** Resolve the (bin,args) to spawn for `command`, honoring the optional OS sandbox.\n * Throws when sandboxing was requested but this platform has no wrapper — fail closed. */\nasync function spawnArgvFor(command: string, cwd: string, osSandbox?: boolean | Partial<OsSandboxOptions>): Promise<{ bin: string; args: string[] }> {\n if (!osSandbox) return { bin: '/bin/sh', args: ['-c', command] };\n const opts = osSandbox === true ? {} : osSandbox;\n const wrapper = await findSandboxWrapper();\n const wrapped = wrapper ? sandboxArgv(command, cwd, opts, process.platform, process.env.TMPDIR) : null;\n if (!wrapped) throw new Error(`OS sandbox requested but no wrapper available on ${process.platform} (need sandbox-exec or bwrap)`);\n return wrapped;\n}\n\n/** Env var names that look like secrets and are dropped before spawning (unless redactEnv:false). */\nconst SECRET_ENV_RE = /(_API_KEY|_TOKEN|_SECRET|_PASSWORD|_PRIVATE_KEY|^AWS_|^GITHUB_TOKEN$|^OPENAI_|^ANTHROPIC_|^GOOGLE_|^GEMINI_|^GROQ_|^NPM_TOKEN$)/i;\n\n/** Build the child's env: `process.env` minus likely-secrets (when redacting), plus explicit `env`. */\nfunction childEnv(opts: { env?: Record<string, string>; redactEnv?: boolean }): Record<string, string | undefined> {\n const base: Record<string, string | undefined> = {};\n const redact = opts.redactEnv !== false; // default ON\n for (const [k, v] of Object.entries(process.env)) if (!(redact && SECRET_ENV_RE.test(k))) base[k] = v;\n return { ...base, ...opts.env };\n}\n\n/** Lazily resolve node's spawn (kept out of any eager edge import path). */\nlet _spawn: SpawnFn | undefined;\nasync function nodeSpawn(): Promise<SpawnFn> {\n if (!_spawn) _spawn = (await import('node:child_process')).spawn as unknown as SpawnFn;\n return _spawn;\n}\n\n// ---------------------------------------------------------------------------\n// Background jobs — long-running processes the agent starts, polls, and kills.\n// ---------------------------------------------------------------------------\nexport type JobStatus = 'running' | 'exited' | 'killed' | 'error';\n\nexport interface ShellJobConfig {\n cwd: string;\n spawn?: SpawnFn;\n env?: Record<string, string>;\n redactEnv?: boolean;\n /** Tail buffer cap per job (bytes); older output is dropped. Default 256 KB. */\n maxBuffer?: number;\n /** Kill all jobs on process exit (the CLI sets this; tests leave it off to avoid global handlers). */\n killOnExit?: boolean;\n /** Tier-1 OS sandbox for background jobs too (same semantics as RealShellOptions.osSandbox). */\n osSandbox?: boolean | Partial<OsSandboxOptions>;\n /**\n * Called once when a background job reaches a terminal state. Claude-Code parity: a background task\n * that finishes has to reach the MODEL, or `background:true` is a write-only hole — the model starts\n * a job, forgets it, and never collects the result. The host wires this to `agent.inject(...)`, which\n * folds the notice in at the next step boundary (and re-opens the turn if the model was about to stop).\n */\n onExit?: JobExitHandler;\n}\n\nexport interface JobExitNotice { id: string; command: string; status: JobStatus; exitCode?: number; tail: string }\nexport type JobExitHandler = (n: JobExitNotice) => void;\n\n/** The exact text a completion notice becomes. Shared so every host (CLI, presets, embedders) pushes the\n * same thing back to the model instead of each inventing its own wording. */\nexport function formatJobExit(n: JobExitNotice): string {\n return `[background job ${n.id} ${n.status}${n.exitCode != null ? ` exit ${n.exitCode}` : ''}] \\`${n.command}\\`\\n`\n + (n.tail ? `${n.tail}\\n` : '(no output)\\n')\n + `Read the full output with ShellOutput({id:\"${n.id}\"}).`;\n}\n\ninterface Job { command: string; buf: string; status: JobStatus; exitCode?: number; proc?: SpawnedProcess; }\n\n/**\n * Per-session registry of background `/bin/sh` jobs. Backs `Shell({background:true})` and the\n * `ShellOutput`/`ShellStatus`/`ShellKill` tools. Output accumulates into a tail-capped ring so a\n * chatty process can't OOM. Bounded + killable; the CLI wires `killOnExit` so children are reaped.\n */\nexport class ShellJobRegistry {\n private jobs = new Map<string, Job>();\n private seq = 0;\n constructor(private cfg: ShellJobConfig) {\n if (cfg.killOnExit && typeof process !== 'undefined') process.once('exit', () => this.killAll());\n }\n\n async start(command: string): Promise<string> {\n const id = `job-${++this.seq}`;\n const max = this.cfg.maxBuffer ?? 256 * 1024;\n const job: Job = { command, buf: '', status: 'running' };\n const append = (chunk: any) => {\n const s = typeof chunk === 'string' ? chunk : chunk?.toString?.('utf8') ?? '';\n job.buf = (job.buf + s).slice(-max); // ring: keep the tail\n };\n try {\n const spawn = this.cfg.spawn ?? (await nodeSpawn());\n const argv = this.cfg.osSandbox ? await spawnArgvFor(command, this.cfg.cwd, this.cfg.osSandbox) : { bin: '/bin/sh', args: ['-c', command] };\n const proc = spawn(argv.bin, argv.args, { cwd: this.cfg.cwd, env: childEnv(this.cfg), ...DETACHED });\n job.proc = proc;\n proc.stdout?.on('data', append);\n proc.stderr?.on('data', append);\n proc.on('error', (err: any) => { if (job.status === 'running') { job.status = 'error'; append(`\\n[error] ${err?.message ?? err}`); this.notifyExit(id, job); } });\n proc.on('close', (code: number | null) => { if (job.status === 'running') { job.status = 'exited'; job.exitCode = code ?? undefined; this.notifyExit(id, job); } });\n } catch (e: any) {\n job.status = 'error';\n job.buf = `failed to spawn: ${e?.message ?? e}`;\n }\n this.jobs.set(id, job);\n return id;\n }\n\n /** Fire `onExit` at most once per job, with the tail so the model can act without a second round-trip. */\n private notified = new Set<string>();\n private notifyExit(id: string, job: Job): void {\n if (this.notified.has(id) || !this.cfg.onExit) return;\n this.notified.add(id);\n try {\n this.cfg.onExit({ id, command: job.command, status: job.status, exitCode: job.exitCode, tail: clean(job.buf).slice(-4000) });\n } catch { /* a host notification must never take down the job registry */ }\n }\n\n /**\n * Wire (or rewire) the completion callback AFTER construction. A host that only gets its agent handle\n * once the Agent is constructed (the library's own `fullAgentOptions` preset, any embedder) could not\n * pass `onExit` up front, so background completions were silently REPL-only. Set it here instead.\n */\n setOnExit(fn: JobExitHandler | undefined): void { this.cfg.onExit = fn; }\n\n /** Whether a finished job will actually be reported to the model. The Shell tool's description reads\n * this so it can't promise a completion notice on a host that discards it. */\n get notifiesOnExit(): boolean { return !!this.cfg.onExit; }\n\n /** Current tail output for a job (null = no such job). */\n output(id: string): string | null { return this.jobs.get(id)?.buf ?? (this.jobs.has(id) ? '' : null); }\n\n status(id: string): { status: JobStatus; exitCode?: number; bytes: number } | null {\n const j = this.jobs.get(id);\n return j ? { status: j.status, exitCode: j.exitCode, bytes: j.buf.length } : null;\n }\n\n list(): Array<{ id: string; command: string; status: JobStatus }> {\n return [...this.jobs].map(([id, j]) => ({ id, command: j.command, status: j.status }));\n }\n\n /**\n * Take over an ALREADY-RUNNING child as a background job. A foreground command that outruns its\n * timeout is not necessarily a hung command — killing it throws away work that was nearly done and,\n * worse, a launcher that spawned its own detached worker leaves that worker running with nothing\n * tracking it. Adopting hands the model a handle instead: the command keeps going, its completion\n * is reported like any other job, and `seed` carries the output produced before the handoff.\n */\n adopt(command: string, proc: SpawnedProcess, seed = ''): string {\n const id = `job-${++this.seq}`;\n const max = this.cfg.maxBuffer ?? 256 * 1024;\n const job: Job = { command, buf: seed.slice(-max), status: 'running', proc };\n const append = (chunk: any) => {\n const s = typeof chunk === 'string' ? chunk : chunk?.toString?.('utf8') ?? '';\n job.buf = (job.buf + s).slice(-max);\n };\n proc.stdout?.on('data', append);\n proc.stderr?.on('data', append);\n proc.on('error', (err: any) => { if (job.status === 'running') { job.status = 'error'; append(`\\n[error] ${err?.message ?? err}`); this.notifyExit(id, job); } });\n proc.on('close', (code: number | null) => { if (job.status === 'running') { job.status = 'exited'; job.exitCode = code ?? undefined; this.notifyExit(id, job); } });\n this.jobs.set(id, job);\n return id;\n }\n\n kill(id: string): boolean {\n const j = this.jobs.get(id);\n if (!j) return false;\n // Group-kill: bg children are detached (own group), so SIGTERM the whole subtree — not just /bin/sh —\n // else a forked server survives the kill and the agent's exit teardown. Fall back to the pid for fakes.\n if (j.status === 'running') { if (!killGroup(j.proc, 'SIGTERM')) { try { j.proc?.kill('SIGTERM'); } catch { /* already gone */ } } j.status = 'killed'; }\n return true;\n }\n\n killAll(): void { for (const id of this.jobs.keys()) this.kill(id); }\n}\n\n/** Build an opt-in real-shell tool bound to `options.cwd`. */\nexport function makeRealShellTool(options: RealShellOptions): AgentTool {\n const defaultTimeoutMs = options.timeoutMs ?? 120_000;\n const maxTimeoutMs = Math.max(options.maxTimeoutMs ?? 600_000, defaultTimeoutMs);\n // The background promise must match what THIS host actually does — a lie here is what makes\n // `background:true` a black hole the model trusts. Evaluated lazily (the registry's onExit may be wired\n // after the tool is built, via setOnExit).\n // NOTIFICATION and SURVIVAL are independent facts governed by different things — `registry.onExit`\n // (is a completion pushed to the model?) and `jobsSurviveRun` (does the host outlive this run?). Reading\n // both off `notifiesOnExit` made the unwired preset tell the model a job \"does NOT survive the end of\n // this run\" while an identically-configured wired registry said the opposite. Each clause states what\n // actually governs it.\n const backgroundDoc = () => {\n const base = 'Set `background:true` for long-running processes (servers, watchers) and for anything that already timed out in the foreground — '\n + 'returns a job id immediately; poll with ShellOutput/ShellStatus, stop with ShellKill. ';\n const notify = options.registry?.notifiesOnExit\n ? 'Its completion is reported back to you when it finishes.'\n : 'NOTE: nothing will tell you when it finishes — poll ShellOutput/ShellStatus yourself, or you will never see its result.';\n const survival = options.jobsSurviveRun === false\n ? 'The job does NOT survive the end of this run, so do not stop while you still need its result.'\n : 'It keeps running across turns.';\n return `${base}${notify} ${survival}`;\n };\n return {\n name: 'Shell',\n // Rebind for an isolated child agent (git worktree): same policy/env/timeouts, new cwd. The\n // `registry` is deliberately dropped — it is bound to the PARENT's cwd (and, in hosts like\n // shraga-ee, to the parent's session), so a background job started from the child would run\n // outside the child's isolation and report into the parent. Background stays a parent capability\n // (`makeShellJobTools`' companions drop out of an isolated child entirely — see their `withCwd`).\n // Only `run` is rebuilt: everything else is carried over from THIS instance, because a host may\n // have mutated the tool AFTER construction (shraga-ee renames `Shell` -> `Bash` and its system\n // prompt says `Bash` everywhere). Rebuilding from `options` alone silently dropped that rename,\n // so a worktree child advertised `Shell` while being told to call `Bash` — an unknown-tool error\n // on its first call, and a hard failure for an agentType def whose allowlist names `Bash`.\n // `description` is the ONE thing taken from the rebound tool instead: it is derived from the\n // options and states whether `background:true` works — the rebind drops the registry, so carrying\n // the parent's text over would advertise a background capability the child does not have. (The\n // spread also collapses the getter below to a plain value, which is why this override is explicit.)\n withCwd(cwd: string): AgentTool {\n const rebound = makeRealShellTool({ ...options, cwd, registry: undefined });\n return { ...this, description: rebound.description, run: rebound.run, withCwd: rebound.withCwd };\n },\n get description() {\n return 'Run a shell command via /bin/sh in the working directory. ' +\n 'Executes any installed binary — ls, cat, grep, git, bun, node, curl, scripts, etc. ' +\n 'Returns combined stdout+stderr; non-zero exits are prefixed `[exit N]`. ' +\n 'Runs non-interactively with no terminal (stdin is /dev/null): commands that prompt for input ' +\n 'fail fast rather than hang — for privileged actions use a non-interactive flag (e.g. `sudo -n`), ' +\n 'or ask the user to run the command themselves. ' +\n (options.registry?.adopt\n ? `A command still running after ${defaultTimeoutMs}ms is NOT killed — it is handed to a background job and you get its id, so you can keep checking on it (\\`[still running]\\`). Pass \\`timeoutMs\\` (max ${maxTimeoutMs}) to wait longer in the foreground, and always bound network commands yourself (e.g. \\`curl -m 10\\`). `\n : `Each command is killed after ${defaultTimeoutMs}ms (result \\`[exit 124]\\` with whatever output it produced) — pass \\`timeoutMs\\` (max ${maxTimeoutMs}) for a legitimately slower command, and always bound network commands yourself (e.g. \\`curl -m 10\\`). `) +\n backgroundDoc();\n },\n // Declared so transports above the agent loop can size their own deadline with headroom (see AgentTool.maxDurationMs).\n maxDurationMs: maxTimeoutMs,\n parameters: {\n type: 'object',\n required: ['command'],\n properties: {\n command: { type: 'string', description: 'the shell command line to execute' },\n background: { type: 'boolean', description: 'run detached and return a job id immediately (for servers/watchers/long builds)' },\n timeoutMs: { type: 'number', description: 'wall-clock cap for THIS command, overriding the default (clamped to the tool max)' },\n },\n },\n async run({ command, background, timeoutMs: askedTimeoutMs, timeout: aliasTimeout }, ctx) {\n const cmd = String(command ?? '');\n // `timeout` is an UNADVERTISED alias for `timeoutMs`, same unit (ms). Models reach for the\n // shorter name from muscle memory (observed: composer-2.5 sending `{\"timeout\":180000}`), and\n // an unknown key is silently dropped — the command then dies at the 120s default while the\n // model believes it asked for 180s and reads an unexplained kill. Accepted, never documented,\n // so the schema still teaches exactly one name.\n const asked = Number.isFinite(askedTimeoutMs) ? askedTimeoutMs : aliasTimeout;\n const timeoutMs = Number.isFinite(asked) && Number(asked) > 0\n ? Math.min(Number(asked), maxTimeoutMs)\n : defaultTimeoutMs;\n if (!cmd.trim()) return '[exit 1] empty command';\n if (background) {\n if (!options.registry) return 'Error: background execution is not enabled in this host (no job registry).';\n const id = await options.registry.start(cmd);\n return `Started background job ${id}. Poll output with ShellOutput({id:\"${id}\"}), check ShellStatus({id:\"${id}\"}), stop with ShellKill({id:\"${id}\"}).`;\n }\n const spawn = options.spawn ?? (await nodeSpawn());\n // Sandbox-off keeps this path await-free (after spawn resolution) so an abort racing the call\n // start still lands before listener registration, exactly as pre-sandbox semantics.\n let argv = { bin: options.shell || '/bin/sh', args: ['-c', cmd] };\n if (options.osSandbox) {\n try {\n argv = await spawnArgvFor(cmd, options.cwd, options.osSandbox);\n } catch (e: any) {\n return `[exit 1] ${e?.message ?? e}`; // fail closed — never run unsandboxed when sandboxing was asked for\n }\n }\n // Compose abort: the run's signal (ctx.signal) OR our per-command timeout both kill the child.\n const ctl = new AbortController();\n const onAbort = () => ctl.abort();\n if (ctx.signal) { if (ctx.signal.aborted) ctl.abort(); else ctx.signal.addEventListener('abort', onAbort, { once: true }); }\n let timedOut = false;\n // Set by the promise body once the child exists, so the timer can hand it over instead of killing it.\n let onDeadline: () => void = () => { timedOut = true; ctl.abort(); };\n const timer = setTimeout(() => { onDeadline(); }, timeoutMs);\n // The child is its own process-group leader (DETACHED): node's `signal` kills only /bin/sh, so on\n // abort also SIGKILL the whole group to reap any descendants (see killGroup).\n // Incremental output → ctx.emit (when the host listens), coalesced to ≥250ms / ≥1KB batches\n // so a chatty child doesn't spam hooks. Redacted per batch (the final result is re-redacted\n // whole — a secret split across batch boundaries can slip the per-batch pass, hence the cap\n // on what consumers may do with chunks: display/digest, never persistence).\n let pend = '';\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n const flushEmit = (ctx: { emit?: (s: string) => void }) => {\n if (flushTimer) { clearTimeout(flushTimer); flushTimer = null; }\n if (pend) { ctx.emit?.(redactSecrets(pend)); pend = ''; }\n };\n try {\n return await new Promise<string>((resolve) => {\n let out = '';\n let settled = false;\n const finish = (s: string) => { if (settled) return; settled = true; resolve(s); };\n let proc: SpawnedProcess;\n try {\n proc = spawn(argv.bin, argv.args, { cwd: options.cwd, env: childEnv(options), signal: ctl.signal, ...DETACHED });\n } catch (e: any) {\n return finish(`[exit 1] failed to spawn shell: ${e?.message ?? e}`);\n }\n // Reap the detached group when the CANCEL fires (node's `signal` only hits /bin/sh).\n if (ctl.signal.aborted) killGroup(proc, 'SIGKILL');\n else ctl.signal.addEventListener('abort', () => killGroup(proc, 'SIGKILL'), { once: true });\n // Deadline reached: hand the still-running child to the job registry rather than killing it.\n // Only a host with a registry can do this — elsewhere the deadline stays a kill, because a\n // child nothing tracks is worse than a dead one.\n const registry = options.registry;\n if (registry?.adopt) {\n onDeadline = () => {\n timedOut = true;\n if (settled) return;\n flushEmit(ctx);\n // The registry attaches its own collectors from here on; ours would only grow a buffer\n // nobody reads. `off` is not part of the minimal stream shape, hence the guarded call.\n (proc.stdout as any)?.off?.('data', collect);\n (proc.stderr as any)?.off?.('data', collect);\n const id = registry.adopt!(cmd, proc, out);\n finish(handoffFor(timeoutMs, id, clean(out), !!registry.notifiesOnExit));\n };\n }\n const collect = (chunk: any) => {\n const s = typeof chunk === 'string' ? chunk : chunk?.toString?.('utf8') ?? '';\n out += s;\n if (ctx.emit && !settled) {\n pend += s;\n if (pend.length >= 1024) flushEmit(ctx);\n else flushTimer ??= setTimeout(() => flushEmit(ctx), 250);\n }\n };\n proc.stdout?.on('data', collect);\n proc.stderr?.on('data', collect);\n proc.on('error', (err: any) => {\n // AbortError fires here when ctl.abort() kills the child — report timeout vs cancel.\n if (err?.name === 'AbortError' || ctl.signal.aborted) return finish(reasonFor(timedOut, timeoutMs, clean(out)));\n log.debug('shell spawn error', err);\n finish(`[exit 1] ${err?.message ?? err}${out ? '\\n' + clean(out) : ''}`);\n });\n proc.on('close', (code: number | null) => {\n flushEmit(ctx); // drain the coalesce buffer before settling (still pre-resolve, so ctx.emit is live)\n if (ctl.signal.aborted) return finish(reasonFor(timedOut, timeoutMs, clean(out)));\n const body = clean(out);\n if (code && code !== 0) return finish(`[exit ${code}]${body ? '\\n' + body : ''}`);\n finish(body || '(command succeeded, no output)');\n });\n });\n } finally {\n clearTimeout(timer);\n if (flushTimer) clearTimeout(flushTimer); // no emits after the call settles\n ctx.signal?.removeEventListener('abort', onAbort);\n }\n },\n };\n}\n\n/** Deadline message when the child was ADOPTED rather than killed: the work continues, so say how to follow it. */\nfunction handoffFor(timeoutMs: number, id: string, body: string, notifies: boolean): string {\n const head = `[still running] exceeded ${timeoutMs}ms, so it was handed to background job ${id} — NOT killed, it is still going. `\n + `Check on it with ShellOutput({id:\"${id}\"}) / ShellStatus({id:\"${id}\"}), stop it with ShellKill({id:\"${id}\"}). `\n + (notifies\n ? 'Its completion will be reported to you, so you may continue with other work meanwhile.'\n : 'Nothing will tell you when it finishes — poll it yourself before you rely on its result.');\n return body ? `${head}\\nOutput so far:\\n${body}` : head;\n}\n\n/** Abort message: timeout vs external cancel, preserving any partial output. */\nfunction reasonFor(timedOut: boolean, timeoutMs: number, body: string): string {\n // A foreground timeout is a DEAD END unless the result says how to get out of it: re-issuing the same\n // command is the one thing that cannot work, and it is exactly what a model does when the message is\n // just a code. Name the two recoveries (background, or narrow the command).\n const head = timedOut\n ? `[exit 124] timed out after ${timeoutMs}ms (killed). Re-running this command unchanged will time out again. `\n + `Either re-run it with background:true (returns a job id immediately; poll with ShellOutput/ShellStatus, `\n + `stop with ShellKill) or narrow it so it can finish — bound it, scope it, or ask for less.`\n : '[exit 130] cancelled (killed)';\n return body ? `${head}\\nPartial output before the kill:\\n${body}` : head;\n}\n\nconst NO_JOB = (id: string) => `Error: no background job '${id}'. Use ShellStatus with no id to list jobs, or start one with Shell({background:true}).`;\n\n/** Build the background-job companion tools (ShellOutput / ShellStatus / ShellKill) over a registry.\n * Each closes over THIS registry, i.e. this agent's jobs in this agent's cwd, so none of them can be\n * rebound to an isolated child's root: `withCwd` returns `undefined` and they are dropped from the\n * child's toolbelt. That keeps the capability coherent — the child's `Shell` cannot START a background\n * job (its registry is dropped), so it must not be able to inspect or SIGTERM the parent's either. */\nexport function makeShellJobTools(registry: ShellJobRegistry): AgentTool[] {\n const idParam = { type: 'object', properties: { id: { type: 'string', description: 'the job id from Shell({background:true})' } } };\n const dropOnRebind = { withCwd: () => undefined };\n return [\n {\n ...dropOnRebind,\n name: 'ShellOutput',\n description: 'Read the accumulated output (tail) of a background Shell job by id.',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n async run({ id }) {\n const out = registry.output(String(id));\n if (out == null) return NO_JOB(String(id));\n const st = registry.status(String(id))!;\n return `[${st.status}${st.exitCode != null ? ` exit ${st.exitCode}` : ''}]\\n${clean(out) || '(no output yet)'}`;\n },\n },\n {\n ...dropOnRebind,\n name: 'ShellStatus',\n description: 'Status of a background Shell job (running/exited/killed + exit code). Omit `id` to list all jobs.',\n parameters: idParam,\n async run({ id }) {\n if (!id) {\n const jobs = registry.list();\n return jobs.length ? jobs.map((j) => `${j.id} ${j.status} ${j.command}`).join('\\n') : '(no background jobs)';\n }\n const st = registry.status(String(id));\n return st ? `${st.status}${st.exitCode != null ? ` (exit ${st.exitCode})` : ''} · ${st.bytes} byte(s) buffered` : NO_JOB(String(id));\n },\n },\n {\n ...dropOnRebind,\n name: 'ShellKill',\n description: 'Stop a running background Shell job by id (SIGTERM).',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n async run({ id }) {\n return registry.kill(String(id)) ? `Killed job ${id}.` : NO_JOB(String(id));\n },\n },\n ];\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike, ChatResponse, Message, StreamChunk, ToolCall, MessageContent, ContentPart } from './llm';\nimport { contentText, imagePart, elideStaleImages, elideImages, messageHasImage, expandImagesForSend, sendBytes, sendBytesPer, endsOnAnnouncedAction } from './llm';\nimport { type AgentTool, type ToolContext, type HostBridge, type UserQuestion, defaultTools, makeContext, toWireTools, truncateOutput } from './tools';\nimport { SandboxJobRegistry, makeJobTools } from './tools.jobs';\nimport { askUserQuestionTool } from './host';\nimport { loadSkills, scanSkills } from './skills';\nimport { loadCommands, scanCommands } from './commands';\nimport { loadMemory } from './memory';\nimport { loadInstructions } from './instructions';\nimport { makeTaskTool, makeTaskBatchTool } from './subagent';\nimport { modelProvider } from './models';\nimport { loadAgents } from './agents';\nimport { checkpointTools } from './OverlayFilesystem';\nimport type { Hooks } from './hooks';\nimport { PermissionPolicy, planMode, composeHooks } from './permissions';\nimport { forComponent } from './logging';\nimport { checkSyntax } from './lint';\nimport { reasoningToChatFragment, type ReasoningEffort } from './reasoning';\n\nconst log = forComponent('Agent');\n\n/** Read a non-negative integer env override, guarded for non-node (edge/browser) builds. */\nfunction envInt(key: string, fallback: number): number {\n const n = typeof process !== 'undefined' ? Number(process.env?.[key]) : NaN;\n return Number.isFinite(n) && n >= 0 ? n : fallback;\n}\n\n/** A browser-bridge MCP tool name (`mcp__<server>__<tool>` where the server name mentions \"browser\").\n * These return huge DOM/screenshot payloads — their USE is the signal that triggers adaptive trimming. */\nfunction isBrowserTool(name: string): boolean {\n return name.startsWith('mcp__') && /browser/i.test(name.slice(5).split('__')[0]);\n}\n\n/** A thrown provider error that is really a cancel (barge-in / Ctrl-C), not a crash. The abort flag can\n * lag the throw under a race, so we message-match across providers: fetch AbortError, Node ABORT_ERR,\n * groq/SDK \"operation was aborted\", ConnectError [canceled]. Mirrors the CLI's cursor-abort guard. */\nfunction isAbortError(err: unknown): boolean {\n const e = err as any;\n const blob = `${e?.message ?? ''} ${e?.name ?? ''} ${e?.code ?? ''} ${e?.cause?.name ?? ''}`;\n return /operation was aborted|\\bAbortError\\b|ABORT_ERR|\\[canceled\\]/i.test(blob);\n}\n\nexport interface RunResult {\n text: string;\n steps: number;\n /** Why the loop ended. The middle group are automatic kill-switches (budget/abuse guards).\n * `needs_input` is NOT a failure: the agent hit a decision that was the user's to make with no\n * human reachable, so it stopped and raised the question (see `question`) instead of guessing.\n * Answer it and resume the session to continue. */\n finishReason: 'stop' | 'max_steps' | 'budget' | 'timeout' | 'loop' | 'max_tool_calls' | 'aborted' | 'error' | 'needs_input' | 'empty';\n messages: Message[];\n /** The parked question — present iff `finishReason === 'needs_input'`. */\n question?: UserQuestion;\n /** Accumulated token usage across all turns (non-stream path). With prompt caching,\n * promptTokens includes cached reads/writes; the cache splits ride along for exact pricing. */\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number; cacheCreationTokens?: number; cacheReadTokens?: number };\n /** True if ANY turn's usage was estimated (provider gave none) rather than exact — lets the UI mark cost `~`. */\n usageEstimated?: boolean;\n /** Advertised tools the model NAMED in the reply it is handing back while the run's invocation ledger\n * shows zero calls to them — a fabricated tool use, proven against ground truth rather than guessed\n * from phrasing. A host can use it to tell the user plainly instead of shipping the invented result.\n *\n * Re-evaluated at RETURN time, not frozen at detection: a claim the recovery nudge rescued (the model\n * went and made the real call) is dropped. It used to survive, on the reading that the field recorded\n * \"this turn needed rescuing\" — but the only consumer turns it into a sentence for the user (\"I never\n * ran it\"), and on the guard's own success path that sentence is false. Whether a turn needed rescuing\n * is a telemetry question, and the `log.warn` at the nudge already answers it. */\n fabricatedToolClaims?: string[];\n error?: unknown;\n}\n\n/** What a manual `/compact` actually freed (token estimates, ~4 chars/token). */\nexport interface CompactResult { tokensBefore: number; tokensAfter: number; target: number; cap: number; removed: number }\n\nexport class AgentOptions {\n /** Any ai.libx.js AIClient (or a FakeAIClient). */\n ai!: ChatLike;\n /** Filesystem backend — MemFilesystem, NodeDiskFilesystem, IndexedDbFilesystem, …\n * OPTIONAL: if omitted, the agent lazily defaults to a JAILED real disk rooted at `process.cwd()`\n * (secrets hidden by DEFAULT_DENY) — resolved via a dynamic node import at first run, so the edge/\n * browser build (which always passes its own fs) never pulls in `node:fs`. Pass `fs` explicitly to\n * use any other backend (and to keep full control of the jail). */\n fs?: IFilesystem;\n model = 'anthropic/claude-sonnet-4-6';\n systemPrompt =\n 'You are a coding agent operating on a virtual filesystem. Use the `bash` tool to explore (ls, grep, find, cat) and the `Read`/`Edit` tools to view and modify files. Always Read a file before Editing it — and before overwriting it with `Write` or a whole-file `ApplyEdits`: Write replaces the ENTIRE file, so blindly writing over an existing one destroys its unseen contents. If a file already exists, Read it first, then merge your changes (or Edit the specific part). When multiple tool calls are independent (e.g. several Reads or Greps with no dependency between them), issue them together in a single turn rather than one at a time. When the task is complete, reply with a short summary and make no further tool calls.\\n' +\n 'Recovery: every turn\\'s file changes are checkpointed. If the user asks to undo/revert/recover edits (including a file you overwrote), tell them to run `/rewind` (or `/undo` for the last turn) to restore the working tree — checkpoints cover files you edited even in .gitignored dirs. You cannot run `/rewind` yourself; surface it as the recovery path.\\n' +\n 'When working with a knowledge base or document workspace: use `RepoMap` with scope \"docs\" to see all document headings and summaries (orient first); use `MemorySearch` to find memories by content when you don\\'t know the exact slug; use `Recall` with multiple slugs to batch-load related facts in one call. Prefer targeted loads over reading everything — orient → search → load → act.';\n tools: AgentTool[] = defaultTools();\n maxSteps = 25;\n // --- automatic kill-switches (always on; protect the API budget against runaway loops/abuse) ---\n /** Hard ceiling on accumulated tokens (prompt+completion) across the run; cache READS count at 0.1×\n * (their real price) so a fat cached context doesn't trip the guard on healthy turns. 0 = unbounded. */\n maxTokens = 200_000;\n /** Idle ceiling in ms: max time since the last productive step before the run is killed (a long/active\n * step resets it — see runLoop's `lastProgressAt`). Not a whole-run wall clock. 0 = unbounded. */\n timeoutMs = 300_000;\n /** Idle-stall watchdog for a SINGLE streamed model request: abort it if no chunk (text OR reasoning)\n * arrives for this long. The between-steps `timeoutMs` can't preempt an in-flight `chat()`, so a\n * provider that goes silent mid-stream would otherwise park the loop forever. 0 = off. */\n stallMs = 60_000;\n /** Stop if the identical tool-call batch (name+args) repeats this many times in a row. 0 = off. */\n maxRepeats = 3;\n /** Cumulative cap on tool calls dispatched across the run. 0 = unbounded. */\n maxToolCalls = 100;\n /** External cancellation — abort the loop between steps (e.g. a UI \"Cancel\" button). */\n signal?: AbortSignal;\n /** Retry budget for an EMPTY/silent-turn (a delegated-runtime wedge: cursor's warm helper spins then\n * returns a content-less end, surfaced as `code:'empty'`/`code:'cursor_silent'`). Tuned WIDER than the\n * network-drop budget (fixed 2) because clearing a wedge needs several reap+respawn cycles — each retry\n * hits a FRESH cursor session (the adapter evicts the wedged warm helper on the silent-end; a stall-watchdog\n * cancel is NOT this class — it is classified `stall`, and the watchdog's coded abort reason is what tells\n * the adapter to evict on that path too). Still bounded:\n * after exhaustion the turn surfaces `finishReason:'empty'` (non-zero exit), never infinite, never silent.\n * Env: AGENTX_EMPTY_RETRIES. */\n emptyRetries = envInt('AGENTX_EMPTY_RETRIES', 4);\n /** Base backoff (ms) between empty-turn retries; grows linearly per attempt (longer than the network\n * class's fixed 1s so a wedged helper has time to be reaped/respawned). Env: AGENTX_EMPTY_RETRY_BASE_MS. */\n emptyRetryBaseMs = envInt('AGENTX_EMPTY_RETRY_BASE_MS', 1500);\n /** 0 = never trim. Otherwise cap the messages sent per turn (system + most recent). */\n maxContextMessages = 0;\n /** Note-taking: keep the most-recent N tool-result outputs verbatim; collapse OLDER ones to a one-line\n * stub in the sent context (the model already consumed them — it can re-Read/re-run). The stored\n * transcript is never mutated. 0 = keep all verbatim. */\n keepToolOutputs = 0;\n /** How many of the most-recent image-bearing messages get their image REF expanded to real base64 in\n * the outgoing request. Older ones (and legacy inline base64) go on the wire as the elision stub. */\n keepRecentImages = 1;\n /** Token-aware backstop (~4 chars/token estimate). After note-taking, drop oldest messages from the\n * sent context until the estimate is under this ceiling (pairing-safe). 0 = off. */\n maxContextTokens = 0;\n /** The MODEL's context window (tokens) — what the context % is measured against and what `/compact`\n * targets 50% of. Filled by the CLI from model metadata; 0 = fall back to 200k. Deliberately NOT\n * `maxTokens`: that is the cumulative SPEND kill-switch, and a spend budget must never be able to\n * drive destructive compaction (`--max-tokens 50000` would otherwise shred the transcript). */\n contextWindow = 0;\n /** Pagination ceiling for a SINGLE tool result (bytes). A result over this is cropped to page 1 with\n * a marker telling the model it was cropped (refine the query, or page further). Guards against one\n * Grep/Read/MCP call blowing the whole context window. 0 = off. Default 60k (~15k tokens). */\n maxToolResultBytes = 60_000;\n /** Hook to handle an oversized tool result instead of the default lossy crop: receives the FULL output\n * and returns the (cropped) string to put in context — e.g. spill to scratch and return a recoverable,\n * paginated stub. Called only when a result exceeds `maxToolResultBytes`. */\n capToolResult?: (full: string, info: { tool: string; args: any }) => string | Promise<string>;\n /** Browser-run adaptive trimming. Browser MCP tools (`mcp__*browser*`) return huge per-call results\n * (full DOM text + screenshots) that accumulate per step and blow the cumulative `maxTokens` budget\n * kill-switch mid-browse. The fix attacks PER-STEP TOKEN GROWTH, and engages ONLY once a browser tool\n * is ACTUALLY invoked (not on mere config presence — so normal coding is untouched):\n * - `resultBytes`: tighter `maxToolResultBytes` applied to BROWSER tool results (each oversized DOM is\n * cropped/spilled to a small stub → small fresh-token tail per step).\n * - `keepOutputs`: keep only the most-recent N tool-result bodies verbatim ONCE a browser tool has run\n * (older huge DOMs collapse to one-line stubs → small cached prefix → small 0.1×cacheRead/step).\n * Explicit `keepToolOutputs`/`maxToolResultBytes` are NOT overridden below their browser values — the\n * tighter of (user, browser) wins, never loosening a user's cap. Unset = off (no adaptive behavior). */\n browserTrim?: { resultBytes?: number; keepOutputs?: number };\n /** VFS dir(s) of skills (`<dir>/<id>/SKILL.md`). If set: inject a catalog + add the `Skill` tool. Multiple dirs are merged (first wins on name collisions). */\n skillsDir?: string | string[];\n /** VFS dir(s) of slash-command templates (`<dir>/<name>.md`). If set: inject a catalog + add the `SlashCommand` tool. Multiple dirs are merged (first wins). */\n commandsDir?: string | string[];\n /** VFS dir(s) of memory (`<dir>/MEMORY.md`). If set: inject the index at run start (persistence = backend).\n * Multiple dirs are merged (reads search all; writes go to first). */\n memoryDir?: string | string[];\n /** User-scope memory dir for global facts (type=user/feedback). Remember routes by type when set. */\n memoryUserDir?: string;\n /** Filenames to discover as project instructions (e.g. `AGENT.md`, `AGENTS.md`, `CLAUDE.md`).\n * Walks the VFS tree and merges all found files (general → specific, like Claude Code).\n * `true` (default) = auto-discover standard names. `string[]` = custom names. `false` = skip. */\n instructionFiles: boolean | string[] = true;\n /** Host interaction channel (human-in-the-loop). If set: adds the `AskUserQuestion` tool. */\n host?: HostBridge;\n /** Add the `AskUserQuestion` tool when a host is present (default true). Set false for an agent that\n * must never block a turn on a structured question — e.g. a voice reflex that confirms inline. */\n askUserQuestion = true;\n /** Deterministic interception points around tool execution (pre/post/stop). */\n hooks?: Hooks;\n /** If true: add the `Task` tool so the agent can spawn depth-limited child agents over the VFS. */\n subagents = false;\n /** VFS dir of typed-subagent defs (`<dir>/<name>.md`). If set with `subagents`: inject a catalog + enable the `Task` `agentType` param. */\n agentsDir?: string;\n /** Current recursion depth (0 = top-level); spawned children run at depth+1. */\n depth = 0;\n /** Hard ceiling on subagent nesting (beyond it the `Task` tool refuses to spawn). */\n maxDepth = 2;\n /** Real-disk dir where child agents stream their transcript as they run (origin-anchored — survives\n * worktree teardown / a child's own cwd). When set, an interrupted/failed child commits a STATUS HINT\n * + a pointer to its trace instead of a dangling tool_call, so the parent can read it and decide\n * whether to ignore, pick it up, or restart. Unset (library/sandbox default) = no tracing. */\n traceDir?: string;\n /** Stream tokens from the model. Takes effect only with a `host.notify`; off => current (non-stream) behavior. */\n stream = false;\n /** Closure reflex for delegated runtimes (cursor/claude-code): when such a turn runs tools but never\n * closes — no assistant text after the last tool, or text that trails off on an action it announced\n * and never took (\"Also checking for X.\") — nudge ONE more step to ANSWER the user\n * from the tool results already in the transcript — so the turn delivers a reply instead of trailing off\n * mid-narration. Deliberately not a \"summarize what you did\" nudge: that produced process reports and\n * permission-asking instead of answers (see the nudge text in runLoop).\n * Fires at most once per run and only for delegated runtimes (native turns never emit the trigger). */\n closeDelegatedTurns = true;\n /** Catch a FABRICATED tool use: a turn that emits no tool call at all, yet whose text names an advertised\n * tool this run has never actually invoked — the model announcing `look_at_app` and then writing its own\n * \"it didn't respond in time\" result. No call-reactive layer can see it (there IS no call), and to every\n * surface it is indistinguishable from a real failure. The discriminator is the per-run invocation ledger,\n * not prose: a named tool with zero invocations is provable. On detection the loop nudges ONCE for a real\n * call, and records the names in `RunResult.fabricatedToolClaims` either way. */\n catchFabricatedToolUse = true;\n /** Fold the dropped middle of an over-long transcript into a synthetic summary (edge-safe, no LLM). Off => drop-oldest. */\n compaction?: { maxMessages: number };\n /** Add `Checkpoint`/`Rollback` tools (requires the fs to be an OverlayFilesystem). */\n checkpoints = false;\n /** Enable `bash({background:true})` + JobOutput/JobStatus/JobKill — sandbox background jobs (overlay-isolated,\n * committed on completion, drained at turn end). Useful when the VFS backend is slow (remote) or for sub-agents. */\n backgroundJobs = false;\n /** Plan mode: block mutating tools until the agent calls `ExitPlanMode` (host-approved). */\n planMode = false;\n /** Permission policy gating each tool call (allow / ask / deny). */\n permissions?: PermissionPolicy;\n /** Opt-in syntax guardrail: refuse to persist a syntactically-broken code-file write/edit. Default off. */\n lintOnWrite?: boolean;\n /** Optional PDF text extraction for Read on .pdf files (node hosts wire pdftotext); absent => Read explains. */\n pdfText?: (path: string) => Promise<string>;\n /** Opt-in: after a write-class tool runs, run `command` over the VFS and append any failure to the tool result.\n * `tools` defaults to ['Write','Edit','MultiEdit','ApplyEdits']. */\n autoTest?: { command: string; tools?: string[] };\n /** Provider-specific options forwarded to ai.chat() (e.g. cursor mcpServers, cwd). */\n providerOptions?: Record<string, unknown>;\n /** Derive `providerOptions` for a DELEGATED child whose model may differ from this agent's\n * (`Task({ model })` / an agentType def). Default: inherit `providerOptions` only when the child's\n * model is on the SAME provider — cursor's `cwd`/`cursorSession` on an anthropic child is a 400. */\n providerOptionsFor?: (model: string) => Record<string, unknown> | undefined;\n /** Prompt caching (providers that support it, e.g. Anthropic): cache tools/system/conversation\n * prefix across the loop's steps — reads cost 0.1x, writes 1.25x. A multi-step agent loop\n * re-sends its whole prefix every step, so this is a large net cost cut. Default on. */\n promptCache = true;\n /** Tool selection mode: 'auto' = model decides (needed for Groq); undefined = provider default. */\n toolChoice?: 'auto' | 'required' | 'none';\n /** Extended-thinking / reasoning effort, normalized across providers (anthropic, openai).\n * `'off'`/undefined = none; `'low'|'medium'|'high'` or a raw token budget. Mapped to the\n * provider-specific request shape via {@link reasoningToChatFragment}; explicit `providerOptions` wins. */\n reasoning?: ReasoningEffort;\n /** Seed a fresh `run()` with prior conversation turns (real role/content messages) so the model\n * sees history as structured turns instead of a flattened text blob. They are inserted AFTER the\n * stable system prompt and BEFORE the current user turn — so the cached system(+tools) prefix never\n * shifts. Turns are normalized before sending (empties dropped, adjacent same-role coalesced, and the\n * first tail turn forced to `user`) so the transcript is always a valid Anthropic alternation ending\n * at the current user prompt. Unset/empty ⇒ current behavior, byte-for-byte. */\n priorMessages?: Array<{ role: 'user' | 'assistant'; content: MessageContent }>;\n}\n\n/** Normalize seed history + the live prompt into a valid alternating tail (the messages that follow the\n * system turn). Drops empties, coalesces adjacent same-role turns, guarantees the first turn is `user`\n * (Anthropic requires the first non-system message to be user) and that the sequence ends at `current`.\n * Empty `prior` ⇒ `[{ user: current }]` — identical to the pre-priorMessages transcript. */\nfunction seedTranscriptTail(\n prior: Array<{ role: 'user' | 'assistant'; content: MessageContent }> | undefined,\n current: MessageContent,\n): Message[] {\n const seq: Message[] = (prior ?? [])\n .filter((m) => contentText(m.content).trim().length > 0)\n .map((m) => ({ role: m.role, content: m.content }));\n seq.push({ role: 'user', content: current });\n const out: Message[] = [];\n for (const m of seq) {\n const last = out[out.length - 1];\n if (last && last.role === m.role) {\n if (typeof last.content === 'string' && typeof m.content === 'string') {\n last.content = `${last.content}\\n\\n${m.content}`; // merge same-role text turns\n continue;\n }\n // multimodal boundary (can't concat) — insert a neutral opposite-role spacer to keep alternation\n out.push({ role: m.role === 'user' ? 'assistant' : 'user', content: '(continuing)' });\n }\n out.push({ role: m.role, content: m.content });\n }\n if (out.length && out[0].role !== 'user') out.unshift({ role: 'user', content: '(Earlier conversation)' });\n return out;\n}\n\n/**\n * The agentic loop: chat() -> dispatch tool_calls over the VFS -> thread results\n * back -> repeat until the model stops (no tool calls) or maxSteps is hit.\n */\nexport class Agent {\n public options: AgentOptions;\n public transcript: Message[] = [];\n private ctx!: ToolContext; // built in the ctor when `fs` is provided, else lazily in ensureFs()\n private lastTrimNotified = 0; // last auto-trim drop count surfaced via host.notify (dedup)\n private activeTools: AgentTool[] = [];\n /** Per-run ground truth: every tool name actually INVOKED this run (native dispatch + delegated\n * runtime activity). The ledger that makes a fabricated tool claim provable. Reset per run. */\n private invokedTools = new Set<string>();\n /** Advertised tools this run's text claimed to have used while the ledger showed zero calls. */\n private fabricatedClaims = new Set<string>();\n private activeHooks?: Hooks; // composed: user hooks + plan-mode + permissions\n private prepared = false; // memo guard: prompt/tools/plan-state built once per conversation\n private systemPromptCache = ''; // the assembled system prompt from the last prepare()\n private started = false; // session-start lifecycle hook fires once per conversation\n private parkedMs = 0; // cumulative time blocked on the HUMAN (permission/plan prompts) — excluded from the timeout\n private browserActive = false; // flips true once a browser MCP tool is actually invoked → adaptive trimming engages (browserTrim)\n\n /** Time a human-blocking await (a permission/plan prompt) and bank it in `parkedMs` so idle prompt\n * time never trips the wall-clock kill-switch. The agent did no work while parked on the user. */\n private async park<T>(p: Promise<T>): Promise<T> {\n const t = Date.now();\n try { return await p; } finally { this.parkedMs += Date.now() - t; }\n }\n\n /** Force the next `send()`/`run()` to rebuild the system prompt, tools, plan-mode and permission hooks\n * from `options` — apply mid-conversation changes to `planMode`/`permissions`/`model` etc. (prepare()\n * is otherwise memoized per conversation). */\n reprepare(): void { this.prepared = false; }\n\n /** Tools injected via addTools(); kept separate from options.tools so prepare() rebuilds don't drop them. */\n private injectedTools: AgentTool[] = [];\n\n /** Current tool surface for hosts/UIs (configured + injected, deduped by name) — options.tools\n * alone misses addTools()-injected ones (e.g. MCP servers mounted after startup). */\n get toolNames(): string[] {\n return [...new Set([...(this.options.tools ?? []), ...this.injectedTools].map((t) => t.name))];\n }\n\n /** Inject tools into a running agent (e.g. dynamically mounted MCP servers). Takes effect on the next turn\n * and survives prepare() rebuilds (reprepare(), new conversations). */\n addTools(tools: AgentTool[]): void {\n this.injectedTools.push(...tools);\n this.activeTools.push(...tools);\n }\n\n /** Remove tools by name from a running agent. Returns the count removed. Also filters\n * `options.tools` — otherwise a constructor-passed tool resurrects on the next prepare()\n * rebuild (and re-adding it via addTools() would then DUPLICATE it in the wire schema). */\n removeTools(names: Set<string> | string[]): number {\n const s = names instanceof Set ? names : new Set(names);\n const before = this.activeTools.length;\n this.activeTools = this.activeTools.filter((t) => !s.has(t.name));\n this.injectedTools = this.injectedTools.filter((t) => !s.has(t.name));\n if (this.options.tools) this.options.tools = this.options.tools.filter((t) => !s.has(t.name));\n return before - this.activeTools.length;\n }\n\n /** Messages the host queued to steer the RUNNING turn (Claude-Code-style mid-turn input). The loop\n * drains them at each step boundary — after tool results are appended, before the next model call —\n * so they ride along with the latest tool results. A no-op between turns (nothing drains it). */\n private pendingInjections: MessageContent[] = [];\n\n /** Queue a user message into the in-flight turn. It lands as a `user` message at the next step\n * boundary; if the model was about to stop, the injection re-opens the loop so it's never lost.\n * Pushing onto `transcript` directly from outside would race the loop — this drains inside it. */\n inject(content: MessageContent): void { this.pendingInjections.push(content); }\n\n /** Drop any queued-but-unconsumed injections. The REPL calls this after a LOCAL command (/cmd, !bash)\n * — which runs no send() to drain them — so a mid-command steer can't leak into the next real turn. */\n clearInjections(): void { this.pendingInjections.length = 0; }\n\n /** Pull queued injections that are plain TEXT, removing them, for a runtime that can accept mid-turn\n * steers over its own channel (claude-code's warm InputQueue via `providerOptions.steer`). Non-text\n * injections (images) stay queued for the step-boundary `drainInjections()` re-open — the text-only\n * steer channel can't carry them. Consumed DURING chat(); no overlap with drainInjections() (post-call). */\n drainPendingSteers(): string[] {\n if (!this.pendingInjections.length) return [];\n const texts: string[] = [];\n this.pendingInjections = this.pendingInjections.filter((c) => {\n if (typeof c === 'string') { texts.push(c); return false; }\n return true; // keep non-text (image parts) for the transcript-injection path\n });\n return texts;\n }\n\n /** Fold any host-injected messages into the transcript as user turns. Returns true if any landed. */\n private drainInjections(): boolean {\n if (!this.pendingInjections.length) return false;\n for (const content of this.pendingInjections.splice(0)) this.transcript.push({ role: 'user', content });\n return true;\n }\n\n constructor(options?: Partial<AgentOptions>) {\n this.options = { ...new AgentOptions(), ...options } as AgentOptions;\n if (this.options.fs) this.buildCtx(); // fs provided → build the tool context now (sync, unchanged behavior)\n }\n\n /** Build the tool context from the resolved fs + options. Idempotent-safe: called once (ctor or ensureFs). */\n private buildCtx(): void {\n this.ctx = makeContext(this.options.fs!, this.options.host);\n this.ctx.signal = this.options.signal; // expose run-cancellation to abort-aware tools (e.g. real shell)\n if (this.options.lintOnWrite) this.ctx.lint = checkSyntax; // opt-in syntax guardrail\n if (this.options.pdfText) this.ctx.pdfText = this.options.pdfText; // host-wired PDF text extraction (Read on .pdf)\n this.ctx.ai = this.options.ai; // expose model to tools that run their own LLM pass (e.g. Review)\n this.ctx.model = this.options.model;\n this.ctx.parkHuman = (p) => this.park(p); // route interactive tools' human-waits into the parked-time accumulator\n if (this.options.backgroundJobs) this.ctx.jobs = new SandboxJobRegistry(); // enables bash({background:true})\n }\n\n /**\n * Resolve the filesystem + build the tool context if the ctor couldn't (no `fs` was passed). The disk\n * default lives HERE, not in the ctor: the ctor can't await, and we must avoid a STATIC `node:fs` import\n * in the core (edge/browser would break). The dynamic import only fires when `fs` is omitted — edge code\n * always passes its own `MemFilesystem`, so the node module is never reached. Default = jailed disk @ cwd.\n */\n private async ensureFs(): Promise<void> {\n if (this.ctx) return; // already built (fs was provided to the ctor, or a prior run resolved it)\n if (!this.options.fs) {\n const { NodeDiskFilesystem } = await import('./NodeDiskFilesystem');\n const { JailedFilesystem } = await import('./JailedFilesystem');\n const disk = new NodeDiskFilesystem(process.cwd());\n await disk.init();\n this.options.fs = new JailedFilesystem(disk); // DEFAULT_DENY hides secrets out of the box\n log.info(`no fs provided — defaulting to jailed real disk at ${process.cwd()}`);\n }\n this.buildCtx();\n }\n\n /**\n * Assemble the system prompt + active tools/hooks ONCE per conversation (memoized).\n * `run()` resets the memo to start fresh; `send()` reuses it, so multi-turn state —\n * plan-mode approval, the tool set, the skills/commands/memory snapshot — stays stable\n * across turns (and the frozen prompt pairs well with prompt caching). Does NOT touch\n * the transcript; `run`/`send` own that.\n */\n private async prepare(taskHint?: string): Promise<string> {\n if (this.prepared) return this.systemPromptCache;\n const o = this.options;\n const fs = o.fs!; // resolved by ensureFs() before any run()/send() reaches prepare()\n let systemPrompt = o.systemPrompt;\n let tools = o.tools;\n if (o.instructionFiles !== false) {\n const names = Array.isArray(o.instructionFiles) ? o.instructionFiles : undefined;\n const ins = await loadInstructions(fs, names);\n if (ins) systemPrompt += '\\n\\n' + ins;\n }\n if (o.memoryDir) {\n // taskHint floats the most task-relevant learnings to the top of a large index; the rest\n // collapse to slugs (still Recall-able) — bounds tokens as learnings accumulate over time.\n const { index, tools: memTools } = await loadMemory(fs, o.memoryDir, { relevanceHint: taskHint, userDir: o.memoryUserDir });\n if (index) systemPrompt += '\\n\\n' + index; // hot: compact (ranked) index always injected\n tools = [...tools, ...memTools]; // cold: Recall (pull fact) + Remember (persist fact)\n }\n // Merged slash namespace (CC parity): each tool cross-resolves into the other registry on a\n // miss, so `/x` works whether x is a command or a skill regardless of which tool the model picks.\n const skillsDir = o.skillsDir, commandsDir = o.commandsDir;\n if (skillsDir) {\n // taskHint floats the most relevant skills to the top of a large catalog; full set stays loadable by name.\n const sibling = commandsDir\n ? async (name: string) => {\n const c = (await scanCommands(fs, commandsDir)).find((x) => x.name === name);\n return c ? { path: c.path, stripFrontmatter: true } : undefined;\n }\n : undefined;\n const { catalog, tool } = await loadSkills(fs, skillsDir, { relevanceHint: taskHint, sibling });\n if (catalog) systemPrompt += '\\n\\n' + catalog;\n if (tool) tools = [...tools, tool];\n }\n if (commandsDir) {\n const sibling = skillsDir\n ? async (name: string) => {\n const s = (await scanSkills(fs, skillsDir)).find((x) => x.name === name);\n return s ? { path: s.path, stripFrontmatter: false } : undefined;\n }\n : undefined;\n const { catalog, tool } = await loadCommands(fs, commandsDir, { relevanceHint: taskHint, sibling });\n if (catalog) systemPrompt += '\\n\\n' + catalog;\n if (tool) tools = [...tools, tool];\n }\n if (o.host && o.askUserQuestion) tools = [...tools, askUserQuestionTool];\n if (o.subagents) {\n let agents: Awaited<ReturnType<typeof loadAgents>>['agents'] | undefined;\n if (o.agentsDir) {\n const loaded = await loadAgents(fs, o.agentsDir);\n agents = loaded.agents;\n if (loaded.catalog) systemPrompt += '\\n\\n' + loaded.catalog;\n }\n // The child inherits the HOST-configured toolbelt (o.tools + addTools) and system prompt — not the\n // derived memory/skills/commands tools, which are closed over THIS agent's fs (they'd keep writing\n // to THIS agent's stores no matter where the child runs). Without this a child fell back to jailed\n // defaultTools(). Inherited tools that escape the VFS are re-bound per child: `subagent.ts` calls\n // `AgentTool.withCwd` so a worktree child's real Shell runs in the WORKTREE, not the parent repo.\n // An overlay child's Shell cannot be isolated at all (an overlay is a VFS layer, not a process\n // jail) — the Task/TaskBatch descriptions say so instead of promising isolation we can't keep.\n const taskOpts = {\n ai: o.ai, model: o.model, fs, depth: o.depth, maxDepth: o.maxDepth, agents, hooks: o.hooks, traceDir: o.traceDir,\n tools: [...o.tools, ...this.injectedTools],\n systemPrompt: o.systemPrompt,\n providerOptionsFor: o.providerOptionsFor ?? ((m: string) => (modelProvider(m) === modelProvider(o.model) ? o.providerOptions : undefined)),\n };\n tools = [...tools, makeTaskTool(taskOpts), makeTaskBatchTool(taskOpts)];\n }\n if (o.checkpoints) tools = [...tools, ...checkpointTools()];\n if (this.ctx.jobs) tools = [...tools, ...makeJobTools(this.ctx.jobs)]; // JobOutput/JobStatus/JobKill\n const plan = o.planMode ? planMode({ host: o.host }) : undefined; // gates mutating tools until approved\n if (plan) tools = [...tools, plan.tool];\n this.activeHooks = composeHooks(o.hooks, plan?.hooks, o.permissions?.hooks());\n this.activeTools = [...tools, ...this.injectedTools]; // injected (addTools) survive the rebuild\n this.systemPromptCache = systemPrompt;\n this.prepared = true;\n return systemPrompt;\n }\n\n /** Single-shot: reset all per-conversation state and run `task` to completion. `task` may be plain\n * text or multimodal content parts (text + images). */\n async run(task: MessageContent): Promise<RunResult> {\n await this.ensureFs(); // resolve the disk default (if no fs was passed) before prepare reads o.fs\n this.prepared = false; // fresh conversation → rebuild prompt + tools + plan-mode state\n this.started = false;\n this.invokedTools.clear(); // fresh conversation → fresh ground truth (a `send()` continuation KEEPS the\n this.fabricatedClaims.clear(); // ledger on purpose: naming a tool it really called last turn is honest)\n const systemPrompt = await this.prepare(contentText(task)); // task text hints catalog relevance\n const startCtx = await this.fireSessionStart(); // [lifecycle] once-per-session context injection\n const userContent = await this.applyPromptSubmit(task); // [lifecycle] per-turn prompt rewrite (text only)\n this.transcript = [\n { role: 'system', content: systemPrompt + (startCtx ? '\\n\\n' + startCtx : '') },\n // Prior turns (if any) sit between the stable system prefix and the live user turn — the cached\n // system(+tools) prefix is unaffected; normalization keeps the alternation valid.\n ...seedTranscriptTail(this.options.priorMessages, userContent),\n ];\n return this.runLoop();\n }\n\n /** Apply onUserPromptSubmit to a turn: rewrite plain text; pass multimodal content through untouched. */\n private async applyPromptSubmit(task: MessageContent): Promise<MessageContent> {\n return typeof task === 'string' ? await this.fireUserPromptSubmit(task) : task;\n }\n\n /** Fire onSessionStart once per conversation; returns any injected context. */\n private async fireSessionStart(): Promise<string | undefined> {\n if (this.started) return undefined;\n this.started = true;\n const ctx = await this.activeHooks?.onSessionStart?.();\n return typeof ctx === 'string' && ctx ? ctx : undefined;\n }\n\n /** Fire onUserPromptSubmit; returns the (possibly rewritten) prompt text. */\n private async fireUserPromptSubmit(task: string): Promise<string> {\n const r = await this.activeHooks?.onUserPromptSubmit?.(task);\n return typeof r === 'string' ? r : task;\n }\n\n /**\n * Multi-turn: continue the existing conversation by appending a user turn instead of\n * resetting — this is what makes an interactive REPL feel like one conversation. The\n * leading system message is (re)synced to the current prompt, so a resumed session whose\n * tools were rebuilt gets a matching catalog rather than a stale one.\n */\n async send(task: MessageContent): Promise<RunResult> {\n await this.ensureFs(); // resolve the disk default (if no fs was passed) before prepare reads o.fs\n const systemPrompt = await this.prepare(contentText(task)); // first turn's task hints catalog relevance; frozen thereafter (memoized → cache-stable)\n const startCtx = await this.fireSessionStart(); // [lifecycle] first send() of a fresh agent counts as session start\n const userContent = await this.applyPromptSubmit(task);\n const sys = systemPrompt + (startCtx ? '\\n\\n' + startCtx : '');\n if (this.transcript[0]?.role === 'system') this.transcript[0] = { role: 'system', content: sys };\n else this.transcript.unshift({ role: 'system', content: sys });\n this.transcript.push({ role: 'user', content: userContent });\n return this.runLoop();\n }\n\n /**\n * Fold the conversation in place (manual `/compact`) until it fits a TOKEN budget — not a message\n * count. Message-count folding alone frees almost nothing when a few recent tool results are huge,\n * so we escalate: fold the middle into a synthetic recap → elide oversized tool-result bodies in the\n * retained window → halve the window → drop-oldest backstop. Deterministic, no LLM call.\n * `focus` (e.g. `/compact keep the API details`) preserves matching lines from the dropped span verbatim.\n * Returns before/after token estimates so the caller can report honestly (0 freed => say so).\n */\n compactNow(maxMessages = 12, focus?: string): CompactResult {\n const cap = Agent.contextCap(this.options);\n const target = Math.round(cap * Agent.COMPACT_TARGET);\n // Budget on the WIRE view (same estimator as /context + the footer) — see estimateTokens.\n const kr = this.options.keepRecentImages ?? 1;\n const tokensBefore = estimateTokens(this.transcript, kr);\n const msgsBefore = this.transcript.length;\n let max = Math.max(2, maxMessages);\n // Nothing to fold AND already under budget: a genuine no-op. Return BEFORE onPreCompact — hooks that\n // persist a summary must not write a spurious one for a `/compact` that changes nothing.\n if (this.transcript.length <= max && tokensBefore <= target)\n return { tokensBefore, tokensAfter: tokensBefore, target, cap, removed: 0 };\n void this.activeHooks?.onPreCompact?.(this.transcript); // [lifecycle] observe before folding (fire-and-forget)\n let out = this.transcript;\n if (out.length > max) out = compact(out, max, focus);\n // Inline base64 can't be shaved, only dropped — so drop the whales FIRST. Otherwise a single oversized\n // screenshot is paid for by shredding cheap text messages further down the ladder.\n // The NEWEST image is spared on this pass: `releaseStaleImages(keepRecent = 1)` deliberately keeps it,\n // and a user who pastes a screenshot and then runs `/compact` must still be able to ask about it.\n if (estimateTokens(out, kr) > target) out = elideOversizedImages(out, target, true, kr);\n if (estimateTokens(out, kr) > target) out = capOversizedBodies(out, target, kr);\n // Only once the text ladder has done all it can does the newest image become fair game.\n if (estimateTokens(out, kr) > target) out = elideOversizedImages(out, target, false, kr);\n // Still over (e.g. one giant user paste / assistant reply): halve the window, re-capping each pass.\n while (estimateTokens(out, kr) > target && max > 2 && out.length > 2) {\n max = Math.max(2, Math.floor(max / 2));\n out = capOversizedBodies(compact(out, max, focus), target, kr);\n }\n if (estimateTokens(out, kr) > target) out = fitTokenBudget(out, target, kr); // drop-oldest backstop\n out = dropOrphanToolResults(out); // never leave a tool_result whose tool_call was folded away\n this.transcript = out;\n this.releaseStaleImages(); // stale inline base64 is dead weight in the folded transcript too\n // Measure the transcript we actually kept (releaseStaleImages may have shrunk it further).\n return { tokensBefore, tokensAfter: estimateTokens(this.transcript, kr), target, cap, removed: msgsBefore - this.transcript.length };\n }\n\n /** Drop inline base64 images from older messages so Bun/JSC can reclaim the heap (see contentBytes). */\n releaseStaleImages(keepRecent = 1): void {\n const next = elideStaleImages(this.transcript, keepRecent);\n if (next !== this.transcript) this.transcript = next;\n }\n\n private async runLoop(): Promise<RunResult> {\n const o = this.options;\n const wireTools = toWireTools(this.activeTools);\n // Stream only when explicitly requested AND a host can render deltas; else stay on the non-stream path.\n const useStream = o.stream === true && typeof o.host?.notify === 'function';\n let steps = 0;\n const usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };\n let usageEstimated = false; // flips true the first turn a provider returns no usage and we estimate\n const start = Date.now();\n this.parkedMs = 0; // reset per run: only THIS run's human-wait is excluded from the timeout\n this.ctx.needsInput = undefined; // reset per run: a question answered last run must not re-stop this one\n let toolCallsTotal = 0; // cumulative tool calls dispatched\n let lastFp = ''; // fingerprint of the previous tool-call batch\n let repeats = 0; // consecutive identical batches\n let closureNudged = false; // closeDelegatedTurns: the closure reflex fires at most once per run\n // Progress clock: `timeoutMs` bounds IDLE time (since last productive step), not total run length —\n // a single extended-thinking step can legitimately exceed the whole-run ceiling while actively\n // streaming reasoning (stallMs keeps that in-flight turn alive), so an absolute wall-clock would kill\n // completed, productive work. Runaway-but-active loops stay covered by maxSteps/maxToolCalls/maxRepeats/budget.\n let lastProgressAt = start;\n // Single exit for every kill-switch: warn + return a result carrying the reason.\n const kill = (finishReason: RunResult['finishReason']): RunResult => {\n log.warn(`kill-switch: ${finishReason} (steps=${steps}, tokens=${usage.totalTokens}, budgetTokens=${Math.round(usage.totalTokens - 0.9 * usage.cacheReadTokens)}, ms=${Date.now() - start - this.parkedMs}${finishReason === 'timeout' ? `, idle=${Date.now() - lastProgressAt - this.parkedMs}ms` : ''}${this.parkedMs ? ` +${this.parkedMs} parked` : ''})`);\n this.ctx.jobs?.killAll(); // abort background jobs (don't commit) — a budget/timeout kill shouldn't leak writes\n const claims = this.survivingClaims();\n return { text: lastAssistantText(this.transcript), steps, finishReason, messages: this.transcript, usage, usageEstimated, ...(claims.length ? { fabricatedToolClaims: claims } : {}) };\n };\n\n while (true) {\n if (o.signal?.aborted) return kill('aborted');\n if (steps >= o.maxSteps) return kill('max_steps');\n if (o.timeoutMs && Date.now() - lastProgressAt - this.parkedMs >= o.timeoutMs) return kill('timeout'); // idle-since-last-progress: an active/long step resets the clock; parked prompt time excluded\n // Budget = cost proxy, not raw volume: cache reads are ~10% of fresh-token price, and a fat cached\n // context (MCP schemas + big tool results) re-counts every step — at full weight a healthy ~25k-ctx\n // session dies near step 8. Weighting reads at 0.1 keeps runaway protection (fresh tokens count full).\n const budgetTokens = usage.totalTokens - 0.9 * usage.cacheReadTokens;\n if (o.maxTokens && budgetTokens >= o.maxTokens) return kill('budget');\n steps++;\n this.options.host?.notify?.({ kind: 'turn_start', message: `step ${steps}` });\n\n let res: ChatResponse;\n const sent = this.trimContext(); // the exact context sent this turn (reused for usage estimation)\n // Normalized reasoning → provider request shape; explicit providerOptions overrides the derived one.\n const frag = reasoningToChatFragment(o.model, o.reasoning);\n // claude-code/* is an autonomous runtime (Claude Agent SDK) that runs its OWN tools inside its\n // subprocess and rejects host-defined tool schemas — send none. External tools reach it via\n // providerOptions.mcpServers (wired by the CLI's claudeCodeProviderOptions). Mirror of cursor below.\n const sentTools = o.model.startsWith('claude-code/') ? [] : wireTools;\n // Cursor is an agent runtime — bridge host tools via IPC-based toolExecutor callback.\n const isCursorWithTools = o.model.startsWith('cursor/') && wireTools.length > 0;\n // Transport deadline with STRUCTURAL headroom over the slowest tool we actually registered. The\n // helper's watchdog used to be a bare 120_000 — identical to the Shell tool's own default cap — so\n // both fired at once, the transport won, and the shell tool's real `[exit 124] timed out ...`\n // result was replaced by an empty string the model could learn nothing from. Derived, never typed twice.\n //\n // FLOORED, because `maxDurationMs` is opt-in: a tool that does not declare one is NOT thereby prompt\n // (McpCall, Task and any host tool contribute 0), and deriving from declarers alone made declaring\n // Shell's 600s *lower* the deadline below the transport's own 30m default — an undeclared hung call\n // then had less headroom than before anyone declared anything. The floor is the transport default;\n // a declaration can only raise it.\n const hostToolTimeoutMs = (o.providerOptions as any)?.toolTimeoutMs;\n const derivedToolTimeoutMs = Math.max(TRANSPORT_TOOL_TIMEOUT_FLOOR_MS, ...this.activeTools.map(transportHeadroomMs)); // activeTools, not wireTools — the wire schema drops maxDurationMs\n // A host that sets providerOptions.toolTimeoutMs explicitly WINS — but only UPWARD. It cannot own\n // what it cannot see: `maxDurationMs` is assembled at run time from defaultTools() + preset shell +\n // addTools() + MCP discovery, so a host picking a number is picking it against a tool set it never\n // enumerates. Setting it BELOW the derived floor has exactly one consequence — the transport wins the\n // race and the tool's real result is replaced by '' — i.e. it re-creates, by configuration, the very\n // bug this fix removed, and does so silently-and-late (the warn scrolls past at step 1, the\n // destruction lands at step 6). So the escape hatch stays open in the only direction that helps:\n // raising the deadline. Clamped, not merely reported.\n const effectiveToolTimeoutMs = typeof hostToolTimeoutMs === 'number' ? Math.max(hostToolTimeoutMs, derivedToolTimeoutMs) : derivedToolTimeoutMs;\n if (isCursorWithTools) {\n if (typeof hostToolTimeoutMs === 'number' && effectiveToolTimeoutMs !== hostToolTimeoutMs) {\n log.warn(`providerOptions.toolTimeoutMs=${hostToolTimeoutMs}ms is below what the registered tools need — RAISED to ${effectiveToolTimeoutMs}ms.`\n + ` ${toolTimeoutViolations(this.activeTools, hostToolTimeoutMs).length} tool(s) could outlive it, and the transport would have destroyed their results.`\n + ` To lower it, lower the tools' own maxDurationMs (e.g. the Shell tool's maxTimeoutMs) instead.`);\n }\n // ASSERTED, not assumed: a tool that can outlive the transport deadline is exactly the collision\n // this whole fix removed. After the clamp this must be empty — keep it as the belt-and-braces check.\n for (const v of toolTimeoutViolations(this.activeTools, effectiveToolTimeoutMs)) log.warn(v);\n }\n const cursorPo = isCursorWithTools ? {\n toolTimeoutMs: effectiveToolTimeoutMs,\n toolExecutor: async (name: string, args: Record<string, any>) => {\n const tc = { id: `cursor-${Date.now()}`, type: 'function' as const, function: { name, arguments: JSON.stringify(args) } };\n // Return the FULL result, images included. The cursor adapter relays it to the helper,\n // which turns `{text, images}` into the SDK's tool-result content blocks. Flattening to\n // `.text` here (as this did) silently dropped every picture a tool produced — the model\n // got \"here is the app as it is rendering right now\" with no image, on cursor/* models\n // that are the DEFAULT for some hosts. The native loop below does the same via imagePart.\n return await this.dispatch(tc);\n },\n } : undefined;\n // claude-code warm sessions accept mid-turn steers via a `steer` pull source (the adapter drains it\n // into the SDK's InputQueue). Route text injections through it so they reach the live warm session;\n // non-text injections (and any that land after the last drain) fall through to the step-boundary re-open.\n const claudeSteerPo = o.model.startsWith('claude-code/') ? { steer: () => this.drainPendingSteers() } : undefined;\n const reasonOpts = {\n ...frag,\n ...(o.promptCache ? { promptCache: true } : {}),\n ...(o.providerOptions || cursorPo || claudeSteerPo ? { providerOptions: { ...frag.providerOptions, ...o.providerOptions, ...cursorPo, ...claudeSteerPo } } : {}),\n };\n try {\n // One step = one model call; a TRANSIENT network drop (mid-stream or pre-flight) retries the\n // step from the last committed transcript state instead of failing the whole turn. Server-side\n // transient HTTP errors (5xx/408/overloaded) retry too; 4xx like rate limits are NOT retried\n // here — the AIClient's own rate-limit retry handles those.\n for (let attempt = 0; ; attempt++) {\n try {\n if (useStream) {\n // Guard the whole request (time-to-first-chunk + inter-chunk gaps) with an idle-stall\n // watchdog: if the provider goes silent past o.stallMs, abort THIS request via a linked\n // controller so the loop can retry the step instead of hanging inside `chat()` forever.\n const stall = this.armStallWatchdog(o.signal, o.stallMs);\n try {\n const r = await o.ai.chat({ model: o.model, messages: sent, tools: sentTools, stream: true, signal: stall.signal, ...(o.toolChoice ? { toolChoice: o.toolChoice } : {}), ...reasonOpts });\n res = await this.consumeStream(r as AsyncIterable<StreamChunk>, stall.poke);\n // A watchdog-fired abort is a STALL even when the provider ends its stream CLEANLY on\n // abort instead of throwing (the cursor adapter releases the consumer with a normal end).\n // Without this check that clean end fell through to the empty-stop guard below and a\n // silent provider was retried as `code:'empty'` 5× and reported as finishReason:'empty'.\n if (stall.stalled()) throw stall.reclassify(undefined);\n } catch (err) {\n throw stall.reclassify(err); // a watchdog-fired abort → Error{code:'stall'}; parent/user aborts pass through\n } finally {\n stall.clear();\n }\n } else {\n const r = await o.ai.chat({ model: o.model, messages: sent, tools: sentTools, stream: false, signal: o.signal, ...(o.toolChoice ? { toolChoice: o.toolChoice } : {}), ...reasonOpts });\n res = r as ChatResponse;\n }\n // Empty-stop guard: a ZERO-WORK turn — the model went silent on the FIRST call, committing\n // nothing to the transcript, yet downstream would report it as a successful \"done\" (the real\n // agentx-composer \"spins then ✓ done · 0 tools\" incident). Scope to `steps === 1` (incremented\n // at the top of the loop, reset per-run): only the first model call can be zero-work, since any\n // later step follows tools/text already committed this turn — an empty wrap-up after real work\n // is a productive turn and must NOT be failed. Throw code:'empty' → the catch below retries it\n // through the SAME transient machinery (bounded by attempt<2); after the retries it propagates\n // to the outer catch which surfaces finishReason:'empty' (a failed turn), never a phantom stop.\n // Skip if a steer/injection is pending — that re-opens the turn naturally at the loop boundary.\n if (steps === 1 && this.isEmptyStop(res) && !this.pendingInjections.length) {\n const e = new Error('model returned an empty turn (finishReason=stop, no text, no tools)') as Error & { code: string };\n e.code = 'empty';\n throw e;\n }\n break;\n } catch (err) {\n const sc = (err as any)?.statusCode;\n const serverSide = sc >= 500 || sc === 408 || /Service Unavailable|overloaded|Internal server error|Bad gateway|Gateway time/i.test(String((err as any)?.message ?? ''));\n const network = !sc && /ECONNRESET|ECONNREFUSED|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|EPIPE|socket hang up|fetch failed|network|terminated|UND_ERR/i.test(String((err as any)?.message ?? (err as any)?.code ?? err));\n const stalled = (err as any)?.code === 'stall'; // watchdog-fired: provider went silent mid-stream\n // Empty/silent turn: agentx's own zero-work guard (code:'empty') OR a delegated runtime signalling\n // a wedged content-less session at the source (cursor adapter's code:'cursor_silent'). Both retry\n // through the SAME machinery on the WIDER empty budget — the adapter reaps the wedged warm helper\n // so each attempt spawns a fresh session.\n const empty = (err as any)?.code === 'empty' || (err as any)?.code === 'cursor_silent';\n // Empty gets its own (wider) attempt cap + backoff; network/server/stall keep the fixed budget of 2.\n const maxAttempts = empty ? Math.max(o.emptyRetries, 0) : 2;\n const transient = !o.signal?.aborted && !isAbortError(err) && attempt < maxAttempts && (network || serverSide || stalled || empty);\n if (!transient) throw err;\n const waitMs = (empty ? o.emptyRetryBaseMs : 1000) * (attempt + 1);\n log.warn(`${empty ? 'empty model turn' : stalled ? 'model stall' : 'network drop'} mid-step (${(err as any)?.message ?? err}) — retrying in ${waitMs}ms`);\n o.host?.notify?.({ kind: 'retry', message: `${empty ? 'model returned nothing' : stalled ? 'model stalled' : 'connection dropped'} — retrying step (#${attempt + 1})` });\n await new Promise((r) => setTimeout(r, waitMs));\n }\n }\n } catch (err) {\n // A budget-exhausted signal (e.g. proxy 429) is a clean stop, not a crash:\n // preserve the transcript so the run can be resumed once the cap is raised.\n if ((err as any)?.code === 'budget') return kill('budget');\n // Watchdog gave up after retries: the provider stayed silent. Clean stop (preserve transcript\n // for resume), labelled 'timeout' so it's diagnosable — not a crash, not a user 'aborted'.\n // `error` rides along (code:'stall') so a host can tell a provider stall from the between-steps idle ceiling.\n if ((err as any)?.code === 'stall') { log.warn(`model stalled out after retries: ${(err as any)?.message ?? err}`); return { ...kill('timeout'), error: err }; }\n // Abort wins over the empty/silent classification: an early barge-in of a cursor turn can surface as\n // a content-less end (code:'cursor_silent'), but a USER-aborted turn is 'aborted', never a failed\n // 'empty'. Check the signal FIRST. (The flag can LAG the throw under a barge-in race — the controller\n // fires, the provider rejects, but o.signal.aborted hasn't settled — so match the abort message too,\n // else a clean cancel is logged as a crash AND its \"operation was aborted\" string leaks onto the\n // spoken/utterance line.)\n if (o.signal?.aborted || isAbortError(err)) return kill('aborted');\n // Empty-stop after the bounded retries: the model kept returning nothing. Surface it as a failed\n // turn (finishReason:'empty' → the host prints ✗ / exits non-zero) instead of a phantom \"done\".\n if ((err as any)?.code === 'empty' || (err as any)?.code === 'cursor_silent') { log.warn(`model returned empty/silent turns after retries — surfacing as failed`); return { text: '', steps, finishReason: 'empty', messages: this.transcript, usage, usageEstimated, error: err }; }\n // surface the provider's human message (non-enumerable → lost by JSON.stringify); the bare\n // {code,statusCode} alone reads as a malformed request when it's often billing/quota (e.g. a 400\n // whose body is \"credit balance is too low\"). The raw response body carries that detail —\n // extract it onto the error so hosts/logs see WHY, not just the status code.\n const body = (err as any)?.body ?? (err as any)?.response?.data ?? (err as any)?.error;\n // try/catch: a circular body must not crash the error handler itself\n let bodyStr: string | undefined;\n try { bodyStr = body && typeof body !== 'string' ? JSON.stringify(body).slice(0, 2000) : (body as string | undefined); } catch { bodyStr = undefined; }\n if (bodyStr && err instanceof Error && !err.message.includes(bodyStr)) (err as any).detail = bodyStr;\n // Error properties are non-enumerable → JSON.stringify(err) = {} — serialize explicitly so logs are useful\n const errLog = err instanceof Error ? { message: err.message, ...((err as any).detail ? { detail: (err as any).detail } : {}), stack: err.stack } : err;\n log.error(`chat() failed: ${(err as any)?.message ?? err}${bodyStr ? ` — ${bodyStr}` : ''}`, errLog);\n return { text: '', steps, finishReason: 'error', messages: this.transcript, usage, usageEstimated, error: err };\n }\n // Cancelled mid-response → end the turn as 'aborted', not as a clean 'stop' on the partial reply.\n if (o.signal?.aborted) return kill('aborted');\n\n // ai.libx.js streaming doesn't surface token usage — estimate (~4 chars/token) so cost reporting\n // AND the maxTokens budget kill-switch still work when streaming (the CLI default). Non-stream\n // responses carry exact usage and are left untouched.\n if (!res.usage) {\n const promptTokens = estimateTokens(sent);\n const completionTokens = Math.ceil((contentText(res.content).length + (res.toolCalls ? JSON.stringify(res.toolCalls).length : 0)) / 4);\n res.usage = { promptTokens, completionTokens, totalTokens: promptTokens + completionTokens };\n usageEstimated = true;\n }\n if (res.usage) {\n usage.promptTokens += res.usage.promptTokens ?? 0; usage.completionTokens += res.usage.completionTokens ?? 0; usage.totalTokens += res.usage.totalTokens ?? 0;\n usage.cacheCreationTokens += (res.usage as any).cacheCreationTokens ?? 0; usage.cacheReadTokens += (res.usage as any).cacheReadTokens ?? 0;\n }\n // A delegated runtime (cursor/claude-code) ran its tools inside its own loop — they reach us only\n // as display-only toolActivity, never the transcript, leaving it narration-only (non-auditable and\n // blind on resume). Reconstruct assistant(tool_calls)+tool pairs so the transcript matches a native\n // turn's shape. Output trimmed via the SAME cap+cropResult path native results use. Pushed BEFORE\n // the final text (the runtime's summary came after its tools).\n const delegatedTools = res.delegatedTools ?? [];\n if (delegatedTools.length) {\n const cap = this.options.maxToolResultBytes ?? 0;\n this.transcript.push({\n role: 'assistant',\n content: '',\n tool_calls: delegatedTools.map((a) => ({ id: a.id, type: 'function' as const, function: { name: a.name || 'tool', arguments: (() => { try { return JSON.stringify(a.input ?? {}); } catch { return '{}'; } })() } })),\n });\n for (const a of delegatedTools) {\n const name = a.name || 'tool';\n // A delegated HOST tool returns dispatch()'s own shape — `{text, images}` — because the cursor\n // toolExecutor relays that verbatim. JSON-stringifying it turned every picture into a wall of\n // base64 text; rebuild image parts here exactly as the native loop does below.\n const r = delegatedResult(a.output);\n // The floor's invariant is MEANINGFUL content, not merely a non-empty string: `{}`, `[]` and an\n // empty MCP `{content:[]}` stringify to something non-empty that teaches the model exactly as\n // little as ''. Scalars a tool meant to return (a real 0, a real false) are meaningful and pass.\n // Images alone are a real result, so only floor the text when nothing else came.\n const text = r.images.length ? r.text : nonEmptyResult(isVacuous(a.output) ? '' : r.text, name, deliveryOf(a.output, a.status));\n const body = cap > 0 && text.length > cap ? cropResult(text, cap) : text;\n const content: MessageContent = r.images.length\n ? [{ type: 'text', text: body } as ContentPart, ...r.images.map((i) => imagePart(`data:${i.mimeType};base64,${i.data}`))]\n : body;\n this.transcript.push({ role: 'tool', tool_call_id: a.id, content });\n }\n }\n\n const toolCalls = res.toolCalls ?? [];\n // A turn with no tool calls AND no text is dead air — don't commit it to the transcript or count\n // it as a real response (it bills tokens but says/does nothing). The voice layer repairs the silence.\n // Delegated tools above are real work, so a turn that ran them is never \"empty\".\n const emptyTurn = toolCalls.length === 0 && delegatedTools.length === 0 && contentText(res.content ?? '').trim() === '';\n if (!emptyTurn) lastProgressAt = Date.now(); // productive step (text/tool/delegated) → reset the idle timeout window\n if (!emptyTurn) {\n this.transcript.push({\n role: 'assistant',\n content: res.content ?? '',\n ...(toolCalls.length ? { tool_calls: toolCalls } : {}),\n });\n }\n\n if (toolCalls.length === 0) {\n // A message injected while the model was composing its final reply re-opens the turn (CC\n // parity) instead of being lost to the post-turn queue — the model answers it in-place.\n if (this.drainInjections()) continue;\n // Closure reflex: a delegated runtime ended on a tool with no wrap-up. Nudge ONE closing step.\n // Ask for the ANSWER, not a process report: the tool records are already in the transcript, so a\n // \"summarize what you did\" phrasing made the model narrate its own turn (\"I ran 4 searches, they\n // were interrupted, want me to retry?\") instead of answering the user — and invited it to re-run\n // work it had already completed. Name those failure modes so it can't slide back into them. Do NOT\n // assert the results are complete (a tool may have errored) — that would push it to fabricate;\n // instead give it an explicit out to report the failure.\n // FABRICATION reflex. Sits BEFORE the closure reflex and shares its one-shot budget: both are the\n // same disease (a turn that reports work it did not do), and firing two nudges in a row would just\n // spend two metered steps. This one is checked first because it is the PROVABLE case — it names the\n // tool and can demand the actual call, where the closure nudge can only ask for an answer.\n // Reachability: this branch is inside `toolCalls.length === 0`, which is exactly the shape a\n // fabricated turn has — the guard is evaluated on the path the defect actually takes, not on a\n // sibling branch that a fabricating turn can never enter.\n // NOT gated on `delegatedTools.length === 0`. It was, and that made the guard DEAD on every\n // delegated backend: on `cursor/*` one chat() call IS the whole agent session, so its own tool\n // calls arrive as `toolActivity` and its final text arrives in the same response — meaning any\n // turn that did real work has `delegatedTools.length > 0` and the check never ran. That is\n // precisely the turn the defect was reported on (edit the app, then invent a `look_at_app`\n // failure). The conjunct was also unnecessary: delegated activity is recorded into\n // `invokedTools` as it streams, so a tool named in the text but absent from the ledger is\n // provably uncalled no matter who executed the rest of the turn.\n const fabricated = o.catchFabricatedToolUse && !closureNudged\n ? this.fabricatedToolNames(contentText(res.content ?? '')) : [];\n for (const n of fabricated) this.fabricatedClaims.add(n);\n if (fabricated.length && steps < o.maxSteps) {\n closureNudged = true;\n log.warn(`fabricated tool use: text names ${fabricated.join(', ')} but the run invoked ${this.invokedTools.size ? [...this.invokedTools].join(', ') : 'nothing'} — demanding the real call`);\n this.transcript.push({\n role: 'user',\n content: `You referred to ${fabricated.map((n) => `\\`${n}\\``).join(', ')} in your reply, but you never actually called `\n + `${fabricated.length > 1 ? 'those tools' : 'that tool'} — no tool call was made, so any result you reported for `\n + `${fabricated.length > 1 ? 'them' : 'it'} was invented. Either call `\n + `${fabricated.length > 1 ? 'them' : 'it'} for real now, or answer without ${fabricated.length > 1 ? 'them' : 'it'} and do `\n + `NOT claim any outcome — including a failure or a timeout — for a call you did not make.`,\n });\n continue;\n }\n if (o.closeDelegatedTurns && res.endedWithoutClosing && !closureNudged && steps < o.maxSteps) {\n closureNudged = true;\n log.verbose('delegated turn went silent after a tool — nudging a closing answer');\n this.transcript.push({\n role: 'user',\n content: 'You ran tools but did not reply. Answer the user now using the tool results above; '\n + 'if a tool failed, say so plainly. Do NOT re-run those tools, do NOT narrate what you did, '\n + 'and do NOT ask for permission to continue.',\n });\n continue;\n }\n log.verbose(`completed in ${steps} step(s)`);\n await this.ctx.jobs?.drain(); // let background jobs finish + commit before we call the run done (no lost writes)\n this.releaseStaleImages(); // inline screenshots are one-shot context — don't immortalize MB of base64\n await this.activeHooks?.onStop?.(res.content ?? ''); // [hooks] fire once on clean stop\n const claims = this.survivingClaims();\n return { text: res.content ?? '', steps, finishReason: 'stop', messages: this.transcript, usage, usageEstimated, ...(claims.length ? { fabricatedToolClaims: claims } : {}) };\n }\n\n // loop detection: the model emitting the same tool-call batch over and over.\n const fp = toolCalls.map((tc) => tc.function.name + ':' + (tc.function.arguments ?? '')).join('|');\n repeats = fp === lastFp ? repeats + 1 : 1;\n lastFp = fp;\n if (o.maxRepeats && repeats >= o.maxRepeats) return kill('loop');\n\n toolCallsTotal += toolCalls.length;\n if (o.maxToolCalls && toolCallsTotal > o.maxToolCalls) return kill('max_tool_calls');\n\n for (const tc of toolCalls) {\n if (o.signal?.aborted) return kill('aborted'); // cancelled mid-batch → don't run the rest\n const raw = await this.dispatch(tc);\n let content: MessageContent;\n if (typeof raw === 'string') { content = nonEmptyResult(raw, tc.function.name); }\n else {\n // Images alone are a real result; text alone is not, so only floor the text when nothing else came.\n const hasImages = !!raw.images?.length;\n const parts: ContentPart[] = [{ type: 'text', text: hasImages ? raw.text : nonEmptyResult(raw.text ?? '', tc.function.name) }];\n for (const img of raw.images ?? []) parts.push(imagePart(`data:${img.mimeType};base64,${img.data}`));\n content = parts;\n }\n this.transcript.push({ role: 'tool', tool_call_id: tc.id, name: tc.function.name, content });\n }\n // AskUserQuestion with no reachable human: stop and hand the question to the CALLER rather than\n // let the model pick for them. Runs AFTER the batch so the tool result is in the transcript —\n // the session persists cleanly and a resume continues from the answer. A clean pause, not a\n // kill: background jobs drain + commit (unlike kill(), which discards them).\n if (this.ctx.needsInput) {\n const question = this.ctx.needsInput;\n this.ctx.needsInput = undefined;\n log.warn(`needs_input: ${question.question} (steps=${steps})`);\n await this.ctx.jobs?.drain();\n const text = [\n `OPEN QUESTION (run paused — no human was reachable): ${question.question}`,\n ...question.options.map((o) => ` • ${o.label}${o.description ? ` — ${o.description}` : ''}`),\n ].join('\\n');\n return { text, steps, finishReason: 'needs_input', messages: this.transcript, usage, usageEstimated, question };\n }\n // Mid-turn steering: fold queued user input in after the tool results so the next model step\n // sees it alongside them (Claude-Code parity). No-op unless the host called inject() this step.\n this.drainInjections();\n }\n }\n\n /**\n * Drain a streamed chat() response: emit each text delta to the host\n * (`{kind:'text_delta'}`) and fold all chunks back into the single\n * ChatResponse the non-stream path would have returned.\n */\n /**\n * Idle-stall watchdog for one streamed model request. Returns a linked AbortController `signal` to\n * hand to `chat()`, a `poke()` to reset the idle timer on each chunk, a `reclassify()` that turns a\n * watchdog-fired abort into an Error{code:'stall'} (leaving a parent/user abort untouched), and a\n * `clear()` to disarm. Aborts the request if no `poke()` (or completion) happens within `stallMs`.\n * `stallMs = 0` disables the timer but still links parent-abort → child so cancellation propagates.\n */\n private armStallWatchdog(parent: AbortSignal | undefined, stallMs: number) {\n const ac = new AbortController();\n let fired = false;\n const onParentAbort = () => ac.abort();\n if (parent?.aborted) ac.abort();\n else parent?.addEventListener('abort', onParentAbort, { once: true });\n let timer: ReturnType<typeof setTimeout> | undefined;\n const stallError = () => {\n const e = new Error(`model stalled: no stream output for ${stallMs >= 1000 ? `${Math.round(stallMs / 1000)}s` : `${stallMs}ms`}`) as Error & { code: string };\n e.code = 'stall';\n return e;\n };\n const poke = () => {\n if (!stallMs) return;\n if (timer) clearTimeout(timer);\n // Abort WITH a coded reason: the provider sees `signal.reason.code === 'stall'` and can tell a\n // watchdog cancel (reap the silent session, retry fresh) from a user barge-in (keep it warm).\n timer = setTimeout(() => { fired = true; ac.abort(stallError()); }, stallMs);\n };\n poke(); // arm before the request so time-to-first-chunk is guarded too\n // Distinguish OUR abort (silent provider) from a parent/user cancel, which must stay an abort.\n const stalled = () => fired && !parent?.aborted;\n return {\n signal: ac.signal,\n poke,\n stalled,\n clear: () => { if (timer) clearTimeout(timer); parent?.removeEventListener('abort', onParentAbort); },\n reclassify: (err: unknown) => (stalled() ? stallError() : err),\n };\n }\n\n /** A clean-stop turn that carries no assistant text AND no tool calls (native or delegated) — a\n * non-result the model produced by going silent. Callers retry it rather than report \"done\". */\n private isEmptyStop(res: ChatResponse): boolean {\n const stop = res.finishReason === 'stop' || res.finishReason == null;\n return stop && (res.toolCalls?.length ?? 0) === 0 && (res.delegatedTools?.length ?? 0) === 0 && contentText(res.content ?? '').trim() === '';\n }\n\n private async consumeStream(stream: AsyncIterable<StreamChunk>, poke?: () => void): Promise<ChatResponse> {\n let content = '';\n let finishReason: string | undefined;\n let toolCalls: ToolCall[] | undefined;\n let usage: ChatResponse['usage'];\n // Delegated-runtime tools (cursor/claude-code loop internally) surface ONLY as display-only\n // toolActivity — accumulate + correlate by id (cursor: one `completed` event carrying everything;\n // claude-code: a `running` half with name+input, then a `completed`/`error` half with output) so\n // the loop can persist them into the transcript. First-seen order is preserved.\n const delegated = new Map<string, NonNullable<ChatResponse['delegatedTools']>[number]>();\n const delegatedOrder: string[] = [];\n // Closure signal: did the runtime CLOSE this turn? Track whether any tool ran and what assistant text\n // followed the LAST one. Trailing text alone isn't closure — cursor narrates as it works and its run\n // can settle while the narration is still mid-plan (\"Also checking for X.\"), so the turn looks closed\n // but answers nothing. Decided after the stream drains, from `sawTool` + `trailing`.\n let sawTool = false;\n let trailing = '';\n for await (const chunk of stream) {\n poke?.(); // progress arrived → reset the idle-stall watchdog\n if (this.options.signal?.aborted) break; // cancelled → stop emitting now; breaking also closes the stream\n // [G3] surface extended-thinking as a distinct channel (never folded into `content` or the\n // persisted transcript — it's a transient UI stream, not history). Provider-dependent field.\n if (chunk.reasoningContent) this.options.host!.notify!({ kind: 'thinking_delta', message: chunk.reasoningContent });\n // Display-only tool activity from a self-executing backend (Cursor CLI runs its OWN tools) — surface\n // for host tool cards; never dispatched. `message` gives plain hosts a printable line.\n if (chunk.toolActivity) {\n const a = chunk.toolActivity;\n const verb = a.status === 'error' ? '✗' : a.status === 'completed' ? '✓' : '→';\n this.options.host!.notify!({ kind: 'tool_activity', id: a.id, name: a.name, input: a.input, output: a.output, status: a.status, truncated: a.truncated, message: `${verb} ${a.name}` });\n const key = a.id ?? `${a.name}:${delegatedOrder.length}`;\n const prev = delegated.get(key);\n if (!prev) { delegated.set(key, { id: key, name: a.name, input: a.input, output: a.output, status: a.status }); delegatedOrder.push(key); }\n else { // merge halves: the completed/error event carries output; the running one carries name/input\n if (a.name) prev.name = a.name;\n if (a.input !== undefined) prev.input = a.input;\n if (a.output !== undefined) prev.output = a.output;\n prev.status = a.status;\n }\n sawTool = true;\n this.invokedTools.add(a.name); // ledger: a delegated runtime's own tools are real calls too\n trailing = ''; // a tool just ran — only text AFTER it can close the turn\n }\n if (chunk.content) {\n content += chunk.content;\n trailing += chunk.content;\n this.options.host!.notify!({ kind: 'text_delta', message: chunk.content });\n }\n if (chunk.finishReason) finishReason = chunk.finishReason;\n if (chunk.toolCalls?.length) toolCalls = chunk.toolCalls; // accumulated, latest wins\n if (chunk.usage) usage = chunk.usage; // exact usage on the terminal chunk (providers that report it; else runLoop estimates)\n }\n const delegatedTools = delegatedOrder.map((k) => delegated.get(k)!);\n // Unclosed = tools ran and the turn either went silent after them or trailed off mid-plan.\n // Stays gated on `sawTool` ON PURPOSE. Ungating it to reach the announce-and-stop turn (which runs no\n // tools, so this flag can never see it) was tried and reverted: `endsOnAnnouncedAction` is prose\n // matching, and once it no longer needs a tool to have run it fires on ordinary conversation —\n // \"I will look at the app once you deploy it.\" is a sentence about the USER's next step, and nudging it\n // spends a metered step talking over a finished answer. The announce-and-stop case is caught instead by\n // the invocation ledger (see fabricatedToolNames), which is ground truth rather than phrasing.\n const endedWithoutClosing = sawTool && (!trailing.trim() || endsOnAnnouncedAction(trailing));\n return { content, ...(finishReason ? { finishReason } : {}), ...(toolCalls ? { toolCalls } : {}), ...(usage ? { usage } : {}), ...(delegatedTools.length ? { delegatedTools } : {}), ...(endedWithoutClosing ? { endedWithoutClosing: true } : {}) };\n }\n\n\n /**\n * FABRICATED TOOL USE — the failure no call-reactive layer can see, because there IS no call.\n *\n * The model announces a tool (\"I'll take a look with look_at_app\"), emits no tool_use block at all, and\n * then writes a plausible RESULT for the call it never made (\"the app view didn't respond in time\"). To\n * every surface that turn is indistinguishable from a genuine timeout: the user reads a credible failure\n * sentence, the logs show no tool call because none was made, and nothing errors. Malformed-call handling\n * (dispatch's earlyError) cannot reach it — that path needs a tool_use block to exist.\n *\n * The discriminator is NOT prose. It is the per-run invocation ledger, which is ground truth: an advertised\n * tool NAMED in the model's own text while `invokedTools` holds zero calls to it is a provable claim about\n * an event that did not happen, not a guess about phrasing. Matching is on the exact registered tool name\n * at word boundaries, so it cannot fire on ordinary English the way `endsOnAnnouncedAction` can.\n *\n * Deliberately narrow, because a false positive costs a metered step:\n * - only tools with a distinctive name (>= 4 chars, containing `_`, `-` or a capital) — a tool named `run`\n * or `web` would match half of English prose;\n * - only against the ledger for the WHOLE run, so referring back to a call it genuinely made earlier\n * (\"the screenshot showed an empty grid\") is honest and stays silent;\n * - only on a turn that made no tool calls of its own — a turn that DID call tools is closing normally.\n * (That is the enclosing `toolCalls.length === 0` branch. It is NOT extended to delegated activity:\n * a `cursor/*` turn runs its own tools and then fabricates in the SAME response, which is the exact\n * reported defect — see the call site.)\n *\n * What it deliberately does NOT catch, both verified:\n * - a fabrication that names no tool at all (\"Let me take a look at the running app. The app view did\n * not respond in time.\") — there is nothing to prove it against. Only prose matching could reach it,\n * and ungating `endsOnAnnouncedAction` for that was tried and reverted (it fires on ordinary English).\n * - a SECOND invented result for a tool the run genuinely called earlier. The ledger is per-run by\n * design, because that is the same fact that keeps an honest back-reference (\"the screenshot showed\n * an empty grid\") silent. Distinguishing them would need per-claim positional accounting, which buys\n * a rarer case at the cost of the common honest one.\n */\n private fabricatedToolNames(text: string): string[] {\n const out: string[] = [];\n for (const t of this.activeTools) {\n if (this.invokedTools.has(t.name)) continue;\n if (t.name.length < 4 || !/[_\\-A-Z]/.test(t.name)) continue; // too generic to match on safely\n const re = new RegExp(`(?:^|[^\\\\w])${t.name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?:[^\\\\w]|$)`);\n if (re.test(text)) out.push(t.name);\n }\n return out;\n }\n\n /** The claims still standing at return time: named in this run's prose, and STILL absent from the\n * invocation ledger. Re-checked here rather than trusted from detection because the ledger moves —\n * the recovery nudge can succeed, and then the host would tell the user \"I never ran it\" about a\n * call that demonstrably ran. See `RunResult.fabricatedToolClaims`. */\n private survivingClaims(): string[] {\n if (!this.fabricatedClaims.size) return [];\n return [...this.fabricatedClaims].filter((n) => !this.invokedTools.has(n));\n }\n\n private async dispatch(tc: ToolCall): Promise<string | { text: string; images?: { mimeType: string; data: string }[] }> {\n this.invokedTools.add(tc.function.name); // ledger: recorded at DISPATCH, so even a failing call counts as made\n const tool = this.activeTools.find((t) => t.name === tc.function.name);\n // [render] Parse args first but DON'T early-return on failure. An unknown-tool or bad-args call\n // (e.g. a model hallucinating a `task` tool) must still flow through the same preToolUse/notify/\n // postToolUse path as a real call — otherwise the host draws no `⚙` line and the UI looks silently\n // stuck. On parse failure keep the raw string as `args` so it still renders, and fail below.\n let args: any = {};\n let earlyError: string | undefined;\n if (!tool) earlyError = `Error: unknown tool '${tc.function.name}'`;\n try {\n args = tc.function.arguments ? JSON.parse(tc.function.arguments) : {};\n } catch (e) {\n args = tc.function.arguments;\n earlyError ??= `Error: invalid JSON arguments for ${tc.function.name}: ${String(e)}`;\n }\n const hooks = this.activeHooks; // [hooks] composed: user + plan-mode + permissions\n const call = { name: tc.function.name, args };\n const meta = { id: tc.id }; // [G4] stable per-call id so a host can correlate result↔call without serial-order assumptions\n // preToolUse is where a permission policy blocks on the user's Yes/No/Always answer — park that wait\n // so a long-standing approval prompt doesn't accrue toward the timeout kill-switch.\n const decision = await this.park(Promise.resolve(hooks?.preToolUse?.(call, meta))); // [hooks] guard before run\n if (decision?.block) {\n const blocked = `Blocked by hook: ${decision.reason ?? 'no reason given'}`;\n log.debug(`${tc.function.name} -> ${blocked}`);\n await hooks?.postToolUse?.(call, blocked, meta); // [hooks] observe the block too\n return blocked;\n }\n this.options.host?.notify?.({ kind: 'tool_use', id: tc.id ?? '', name: tc.function.name, input: args });\n // [render] surface the unknown-tool / bad-args failure through the normal result path (postToolUse\n // renders the body; notify carries isError) so it's visible instead of vanishing.\n if (earlyError) {\n log.debug(`${tc.function.name} -> ${earlyError}`);\n await hooks?.postToolUse?.(call, earlyError, meta);\n this.options.host?.notify?.({ kind: 'tool_result', id: tc.id ?? '', output: earlyError, isError: true });\n return earlyError;\n }\n let result: string;\n let images: { mimeType: string; data: string }[] | undefined;\n let threw = false;\n try {\n log.debug(`${tc.function.name}(${tc.function.arguments})`);\n // [hooks] per-call incremental-output channel: streaming tools (real Shell) push chunks via\n // ctx.emit → onToolOutput. Dispatch is serial, so binding on the shared ctx is safe; cleared\n // in finally so a straggler emit after the call settles is a silent no-op.\n this.ctx.emit = hooks?.onToolOutput ? (chunk: string) => { try { hooks.onToolOutput!(call, chunk, meta); } catch (e) { log.debug(`onToolOutput hook error: ${e}`); } } : undefined;\n const raw = await tool!.run(args, this.ctx);\n if (typeof raw === 'string') { result = raw; }\n else { result = raw.text; images = raw.images; }\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n log.debug(`${tc.function.name} -> error: ${msg}`);\n result = `Error: ${msg}`;\n threw = true;\n } finally {\n this.ctx.emit = undefined; // the call settled — late emits (stray timers) go nowhere\n }\n // autoTest (opt-in): after a successful write-class tool, run a VFS test command and surface any failure\n // to the model in-band — so it never burns a turn re-running tests itself. Skipped on block/throw.\n if (!threw) result = await this.maybeAutoTest(tc.function.name, result);\n // Image-only result (e.g. a screenshot tool): give it a text marker so hosts don't render\n // \"(no output)\" and the model has a text anchor next to the image part.\n if (images?.length && !result) result = `[${images.length} image${images.length > 1 ? 's' : ''} attached]`;\n // Pagination ceiling: a single oversized result (a 1MB Grep, a huge Read/MCP payload) would otherwise\n // blow the context window. Crop to page 1 with a marker; a capToolResult hook can spill it losslessly.\n // Browser tools (huge DOM/screenshot payloads) get a TIGHTER per-result cap once browserTrim is set —\n // this is the dominant per-step-growth lever for a long browse (a 15k-token DOM → small stub/spill).\n // Flip browserActive here so the NEXT trimContext can also keep fewer browser bodies verbatim.\n const browser = isBrowserTool(tc.function.name);\n if (browser && this.options.browserTrim) this.browserActive = true;\n const browserBytes = browser ? this.options.browserTrim?.resultBytes : undefined;\n const baseCap = this.options.maxToolResultBytes ?? 0;\n // tighter of (user cap, browser cap); a 0 (off) on either side means \"no extra limit from that side\".\n const cap = browserBytes ? (baseCap > 0 ? Math.min(baseCap, browserBytes) : browserBytes) : baseCap;\n if (!threw && cap > 0 && result.length > cap) {\n const info = { tool: tc.function.name, args };\n result = this.options.capToolResult ? await this.options.capToolResult(result, info) : cropResult(result, cap);\n }\n await hooks?.postToolUse?.(call, result, meta); // [hooks] observe the result\n this.options.host?.notify?.({ kind: 'tool_result', id: tc.id ?? '', output: result, isError: threw });\n if (images?.length) {\n for (const img of images) {\n this.options.host?.notify?.({ kind: 'tool_result_image', id: tc.id ?? '', dataUrl: `data:${img.mimeType};base64,${img.data}` });\n }\n }\n return images?.length ? { text: result, images } : result;\n }\n\n /** `/compact` aims to land the transcript at this fraction of the context window. */\n private static readonly COMPACT_TARGET = 0.5;\n\n /** THE context-window cap resolution — `/compact`'s budget and the CLI's context footer/warnings both\n * route here, so the percentage the user reads and the one compaction targets can never drift. */\n static contextCap(o: Pick<AgentOptions, 'maxContextTokens' | 'contextWindow' | 'model'> | Partial<AgentOptions>): number {\n if (o.maxContextTokens) return o.maxContextTokens;\n const w = o.contextWindow || 0;\n // Anthropic serves >200k ONLY when the request carries the `context-1m-2025-08-07` beta header, which\n // we never send (the adapter emits files-api + interleaved-thinking only). A declared 1M window is\n // therefore unusable on the wire — budgeting against it would make /compact refuse to act at 300k.\n // Lifting this is a one-liner once that beta header is emitted.\n if (w > ANTHROPIC_WINDOW_WITHOUT_1M_BETA && isAnthropicModel(o.model)) return ANTHROPIC_WINDOW_WITHOUT_1M_BETA;\n return w || 200_000;\n }\n\n private static readonly WRITE_CLASS = ['Write', 'Edit', 'MultiEdit', 'ApplyEdits'];\n\n /** Append an autoTest failure section to a write-class tool result, if configured. */\n private async maybeAutoTest(toolName: string, result: string): Promise<string> {\n const at = this.options.autoTest;\n if (!at?.command) return result;\n const set = at.tools ?? Agent.WRITE_CLASS;\n if (!set.includes(toolName)) return result;\n const r = await this.ctx.exec.execute(at.command);\n if (r.exitCode === 0) return result; // silent on pass — avoid noise\n const out = truncateOutput(((r.output ?? '') + (r.error ?? '')).replace(/\\n+$/, ''));\n return `${result}\\n\\n[autoTest] \\`${at.command}\\` FAILED (exit ${r.exitCode}):\\n${out}`;\n }\n\n /**\n * Shape the per-turn context (a VIEW — the stored transcript is never mutated). Layered, each off by default:\n * 1. coarse reduction — `compaction` (fold the dropped middle into a synthetic summary) OR\n * `maxContextMessages` (pure drop-oldest), keeping the system message + most-recent window.\n * 2. note-taking (`keepToolOutputs`) — collapse all-but-the-recent-N tool-result bodies to one-line stubs\n * (kills \"immortal tool results\": a big Read/Grep stops costing its full weight once it's old).\n * 3. token-aware backstop (`maxContextTokens`) — drop oldest messages until under an estimated token ceiling.\n * With every knob off, returns the transcript unchanged (same reference).\n */\n trimContext(): Message[] {\n const o = this.options;\n const m = this.transcript;\n let out: Message[] | null = null;\n if (o.compaction?.maxMessages && m.length > o.compaction.maxMessages) out = compact(m, o.compaction.maxMessages);\n else if (o.maxContextMessages && m.length > o.maxContextMessages) out = dropOldest(m, o.maxContextMessages);\n // Once a browser tool has actually run, keep FEWER tool-result bodies verbatim (older huge DOMs collapse\n // to one-line stubs → smaller cached prefix → smaller 0.1×cacheRead growth per step). Tighter wins; a\n // user's explicit keepToolOutputs is never LOOSENED. Off until browserActive (normal coding untouched).\n const browserKeep = this.browserActive ? o.browserTrim?.keepOutputs : undefined;\n const keep = browserKeep != null\n ? (o.keepToolOutputs ? Math.min(o.keepToolOutputs, browserKeep) : browserKeep)\n : o.keepToolOutputs;\n if (keep) out = stubOldToolResults(out ?? m, keep);\n // Decide the image outcome BEFORE the token backstop, and budget on what will ACTUALLY be sent:\n // a stale ref weighs its ~50-byte stub (not the file it will never carry), and a tool-result ref\n // weighs the whole expanded base64 (an image Read could otherwise blow the window unbudgeted).\n // Orphan-stripping runs first so the expansion window sees the real message set.\n out = expandImagesForSend(dropOrphanToolResults(out ?? m), o.keepRecentImages ?? 1);\n if (o.maxContextTokens) {\n const pre = out.length;\n out = fitTokenBudget(out, o.maxContextTokens, o.keepRecentImages ?? 1);\n // Token-cap trims used to be SILENT — surface a one-line notice (deduped per drop count)\n // so the user knows context was auto-compacted, not mysteriously forgotten.\n const dropped = pre - out.length;\n if (dropped > 0 && dropped !== this.lastTrimNotified) {\n this.lastTrimNotified = dropped;\n o.host?.notify?.({ kind: 'compaction', message: `context full — auto-trimmed ${dropped} oldest message(s) to fit ~${Math.round(o.maxContextTokens / 1000)}k tokens` });\n }\n }\n // Unconditional correctness net: a tool_result whose tool_call parent isn't in the sent set is a\n // hard API 400 (INVALID_REQUEST). Orphans arise from compaction boundaries OR a resumed transcript\n // that was folded in a prior session — strip them no matter which knobs are on. Same ref if clean.\n // (fitTokenBudget can create new head orphans; it guards its own head, this catches the rest.)\n return dropOrphanToolResults(out);\n }\n}\n\n/** system (if any) + the most-recent (max - head) messages — pure drop-oldest. */\nfunction dropOldest(m: Message[], max: number): Message[] {\n const head = m[0]?.role === 'system' ? [m[0]] : [];\n return [...head, ...m.slice(-(max - head.length))];\n}\n\n/** Anthropic's usable context without the `context-1m-2025-08-07` beta header (see Agent.contextCap). */\nconst ANTHROPIC_WINDOW_WITHOUT_1M_BETA = 200_000;\nconst isAnthropicModel = (m?: string): boolean => !!m && (m.startsWith('anthropic/') || /(^|\\/)claude-/.test(m));\n\n/** ~4 chars/token estimate over content + serialized tool_calls. THE estimator — the CLI footer,\n * `/context` and `/compact` all route here so what the user sees and what compaction targets can't\n * drift apart. Images are weighed AS SENT (`sendBytes`): only the recent window's refs cost their\n * file, stale ones cost the stub. Budgeting a ref at full file size while the wire carries a 50-byte\n * stub made `/compact` chase a target it could never reach and drop-oldest the conversation away. */\nexport function estimateTokens(m: Message[], keepRecentImages = 1): number {\n return Math.ceil(sendBytes(m, keepRecentImages) / 4);\n}\n\n/**\n * Note-taking: keep the most-recent `keep` tool-result messages verbatim; collapse older, bulky ones to a\n * one-line stub that still names the tool + its file (so the model can re-pull). Structure (role/tool_call_id/\n * name) is preserved so tool_use↔tool_result pairing stays valid; only `content` is replaced, on COPIES.\n */\n/** Crop an oversized tool result to page 1 (cut at a line boundary) with a marker telling the model it\n * was cropped and how to proceed. The default (lossy) handler when no capToolResult hook spills it. */\n/**\n * Floor for a transport's per-tool-call deadline: an UNDECLARED tool is not a prompt tool, so the\n * transport must stay generous by default (this matches the cursor helper's own DEFAULT_TOOL_TIMEOUT_MS).\n */\nexport const TRANSPORT_TOOL_TIMEOUT_FLOOR_MS = 1_800_000;\n\n/**\n * Layering assertion: every tool that declares how long it may run must finish strictly INSIDE the\n * transport deadline that wraps it. Returns one message per violation (empty = the layering holds).\n * Undeclared tools cannot be checked — which is why the deadline is floored, not derived from declarers.\n */\n/**\n * Headroom a transport needs over ONE tool's declared bound.\n *\n * An ADVISORY bound (the default) is a tool's own intention, which it may overrun — a shell cap fires a\n * kill and then still has to reap, format and return — so the transport keeps generous headroom (x2 + 1m).\n * A SELF-ENFORCED bound (`maxDurationEnforced`, e.g. Task's wall clock, which aborts the child) cannot be\n * overrun, so doubling it only buys DEAD TIME: it doubles how long a genuinely hung call stays silent.\n * Modest slack for the return trip is enough. Either way the result strictly exceeds the tool's own bound,\n * which is the invariant `toolTimeoutViolations` asserts.\n */\nexport function transportHeadroomMs(t: { maxDurationMs?: number; maxDurationEnforced?: boolean }): number {\n const d = Number(t.maxDurationMs) || 0;\n if (!d) return 0;\n return t.maxDurationEnforced ? d + 60_000 : d * 2 + 60_000;\n}\n\nexport function toolTimeoutViolations(tools: Array<{ name: string; maxDurationMs?: number }>, transportMs: number): string[] {\n const out: string[] = [];\n for (const t of tools) {\n const d = Number(t.maxDurationMs) || 0;\n if (d && d >= transportMs) {\n out.push(`tool-timeout layering VIOLATED: '${t.name}' may run up to ${d}ms but the transport deadline is ${transportMs}ms — the transport wins the race and the tool's real result is destroyed. Raise providerOptions.toolTimeoutMs above ${d}ms.`);\n }\n }\n return out;\n}\n\n/**\n * FLOOR: no tool result reaches the transcript empty — ever, from any tool, for any reason.\n *\n * A blank is the single worst thing to show a model: it reads as \"nothing happened\" rather than \"your\n * call failed\", so the model neither retries meaningfully nor adapts — it re-issues the identical call.\n * (Real session 20260831-104225: six `{role:'tool', content:''}` entries from a shell command killed by\n * a transport timeout; the model re-ran the same unfinishable scan for nine turns and never finished.)\n *\n * The floor must not LIE, though. `tools:`/`addTools()` is a public API and a host tool may legitimately\n * return '' — telling the model that a tool which provably ran suffered a transport failure (\"outcome is\n * UNKNOWN, retry it\") invites a duplicate write, which is the same harm inverted. So the caller states how\n * the result was DELIVERED and the floor only makes the UNKNOWN claim when the result genuinely never\n * arrived:\n * 'ran' — the tool returned; '' means it produced no output. Benign, and said so.\n * 'missing' — no result arrived (undefined output, a non-terminal status, a rejected/torn-down call).\n * 'error' — the tool reported failure but gave no detail.\n */\nexport type ResultDelivery = 'ran' | 'missing' | 'error';\n\nexport function nonEmptyResult(out: string, name = 'tool', delivery: ResultDelivery = 'ran'): string {\n if (out.trim()) return out;\n if (delivery === 'error') return `[${name}] failed with no error message — the tool reported an error but produced no detail. Its effect is UNKNOWN: verify the state before assuming it did or did not happen.`;\n if (delivery === 'missing') {\n const base = `[${name}] returned no result. This is a transport failure, not an empty answer — the call's outcome is UNKNOWN, so do not assume it succeeded or failed.`;\n // The background escape hatch only exists for Shell; suggesting it for a Read/Grep would be noise.\n return name === 'Shell'\n ? `${base} Do NOT re-issue the same long-running command: run it with background:true and poll ShellOutput/ShellStatus, or narrow it so it can finish.`\n : `${base} Retry it, or verify the state another way before continuing.`;\n }\n return `[${name}] ran and returned no output. The call completed — this is an empty answer, not a failure.`;\n}\n\n/**\n * Does this tool output say NOTHING? The floor's real invariant is meaningful content, not a non-empty\n * string: a delegated `{}` / `[]` / an empty MCP `{content: []}` all stringify to something non-empty and\n * sail past a length check while teaching the model exactly as much as '' did. Scalars a tool deliberately\n * returned (a real `0`, a real `false`) ARE meaningful and are never vacuous.\n */\nexport function isVacuous(v: unknown, seen: Set<object> = new Set(), depth = 0): boolean {\n if (v == null) return true;\n if (typeof v === 'string') return v.trim() === '';\n if (typeof v !== 'object') return false; // number, boolean, bigint, symbol, function — a value the tool meant to return\n // Cycles and pathological nesting: the predicate runs OUTSIDE any try/catch on the transcript path, and\n // the line it replaced (JSON.stringify + catch) was cycle-tolerant. Neither is \"nothing\", so both are\n // non-vacuous rather than a RangeError out of transcript assembly.\n if (seen.has(v) || depth >= 64) return false;\n seen.add(v);\n try {\n if (Array.isArray(v)) return v.every((x) => isVacuous(x, seen, depth + 1));\n // Only PLAIN objects can be judged by their own enumerable values. A Date, Map, Set, Error, Buffer or\n // class instance carries its content somewhere `Object.values` cannot see — `Object.values(new Date())`\n // is `[]`, which would floor a real timestamp away as \"ran and returned no output\".\n const proto = Object.getPrototypeOf(v);\n if (proto !== Object.prototype && proto !== null) return false;\n const vals = Object.values(v as Record<string, unknown>);\n return vals.length === 0 || vals.every((x) => isVacuous(x, seen, depth + 1));\n } finally {\n seen.delete(v);\n }\n}\n\n/**\n * Normalize a delegated runtime's tool output into the same `{text, images}` shape `dispatch()` returns,\n * so the reconstructed transcript record can carry pictures instead of a wall of base64 text.\n *\n * Two image-bearing shapes reach here, because a host tool's result makes a ROUND TRIP on the cursor path:\n * the toolExecutor hands back dispatch()'s `{text, images}`, the helper converts it to the SDK's content\n * blocks (`{content:[{type:'text'},{type:'image',data,mimeType}]}`, see ai.libx.js cursor-tool-result.ts),\n * and it is the SDK's echo of THAT which lands on the completed event as `output`. Accept both, plus a\n * bare block array (the MCP shape) — none of them should degrade into stringified base64.\n */\nexport function delegatedResult(output: unknown): { text: string; images: Array<{ mimeType: string; data: string }> } {\n if (typeof output === 'string') return { text: output, images: [] };\n if (output == null) return { text: '', images: [] };\n const isImg = (i: any) => i && typeof i.data === 'string' && typeof i.mimeType === 'string';\n const o = output as { text?: unknown; images?: unknown; content?: unknown };\n if (Array.isArray(o.images)) {\n const images = (o.images as any[]).filter(isImg);\n if (images.length) return { text: typeof o.text === 'string' ? o.text : '', images };\n }\n const blocks = Array.isArray(output) ? output : Array.isArray(o.content) ? o.content : undefined;\n if (blocks) {\n const images = (blocks as any[]).filter((b) => b?.type === 'image' && isImg(b)).map((b: any) => ({ mimeType: b.mimeType, data: b.data }));\n if (images.length) {\n const text = (blocks as any[]).filter((b) => b?.type === 'text' && typeof b.text === 'string').map((b: any) => b.text).join('\\n');\n return { text, images };\n }\n }\n try { return { text: JSON.stringify(output), images: [] }; } catch { return { text: String(output), images: [] }; }\n}\n\n/** How a delegated runtime's reconstructed tool record was delivered (see nonEmptyResult). */\nexport function deliveryOf(output: unknown, status?: string): ResultDelivery {\n if (status === 'error') return 'error';\n if (output == null) return 'missing'; // never arrived (cursor's `output: undefined`)\n if (status != null && status !== 'completed') return 'missing'; // still running / torn down mid-call\n return 'ran';\n}\n\nexport function cropResult(result: string, cap: number): string {\n const head = result.slice(0, cap);\n const nl = head.lastIndexOf('\\n');\n const page = nl > cap * 0.5 ? head.slice(0, nl) : head; // prefer a clean line cut if not too early\n const omitted = result.length - page.length;\n return `${page}\\n\\n[output cropped — showing ${page.length} of ${result.length} bytes; ${omitted} omitted. ` +\n `This is page 1. Refine your query/command to narrow it, or call the tool again with a tighter scope to see more.]`;\n}\n\nfunction stubOldToolResults(messages: Message[], keep: number): Message[] {\n const meta = new Map<string, string | undefined>(); // tool_call_id -> path arg (for the pointer)\n for (const msg of messages)\n for (const tc of msg.tool_calls ?? []) {\n let path: string | undefined;\n try { const a = tc.function.arguments ? JSON.parse(tc.function.arguments) : {}; if (typeof a.path === 'string') path = a.path; } catch { /* args not JSON */ }\n meta.set(tc.id, path);\n }\n const toolIdx = messages.map((x, i) => (x.role === 'tool' ? i : -1)).filter((i) => i >= 0);\n const stub = new Set(toolIdx.slice(0, Math.max(0, toolIdx.length - keep)));\n if (stub.size === 0) return messages;\n return messages.map((x, i) => {\n const text = contentText(x.content);\n if (!stub.has(i) || text.length <= 120) return x; // small results aren't worth stubbing\n const where = meta.get(x.tool_call_id ?? '');\n const lines = text.split('\\n').length;\n return { ...x, content: `[${x.name ?? 'tool'}${where ? ` ${where}` : ''} output elided — ${lines} lines; re-run the tool to view]` };\n });\n}\n\n/**\n * Elide oversized message BODIES until the transcript fits `target`. Progressive caps: shave the\n * biggest first, tighten only if still over. Tool results are the usual whales, but a single 1MB user\n * paste is shortened in place too — it must never fall through to the drop-oldest backstop and take the\n * user's own text with it. Only `content` changes, on copies — role/tool_call_id/name stay intact so\n * tool_use↔tool_result pairing holds; the system head is never touched.\n */\n/** Drop inline base64 images — heaviest message first — until the transcript fits `target`. Unlike text,\n * an image part can't be shortened, so an oversized screenshot must be elided (to `IMAGE_ELIDE_STUB`)\n * BEFORE the text ladder starts paying for it by shredding, then dropping, the conversation itself.\n * Stops as soon as we're under budget, so a small/recent image survives when text is the real weight. */\nfunction elideOversizedImages(messages: Message[], target: number, protectNewest = false, keepRecentImages = 1): Message[] {\n let out = messages;\n // REF-AWARE: post-image-refs every image in a live transcript is a ref, so selecting on inline\n // base64 alone made both ladder passes a no-op (and `protectNewest` protect nothing) — the ladder\n // then paid for the image by shredding, and finally dropping, the user's text.\n const withImages = out.map((_, i) => i).filter((i) => messageHasImage(out[i].content));\n // `protectNewest` holds back the most recent image-bearing message — the one `releaseStaleImages`\n // guarantees survives; the caller re-runs unprotected only if the text ladder still can't fit us.\n const newest = protectNewest ? withImages[withImages.length - 1] : -1;\n // Order by WIRE weight, not stored weight: a stale ref already weighs the stub, so eliding it frees\n // nothing — shave the in-window image that actually costs the file first.\n const weight = sendBytesPer(out, keepRecentImages);\n const heaviestFirst = withImages\n .filter((i) => i !== newest)\n .sort((a, b) => weight[b] - weight[a]);\n for (const i of heaviestFirst) {\n if (estimateTokens(out, keepRecentImages) <= target) break;\n const c = elideImages(out[i].content!);\n if (c === out[i].content) continue;\n out = out.map((m, j) => (j === i ? { ...m, content: c } : m));\n }\n return out;\n}\n\nfunction capOversizedBodies(messages: Message[], target: number, keepRecentImages = 1): Message[] {\n let out = messages;\n for (const cap of [8000, 4000, 2000, 800, 300, 120]) {\n if (estimateTokens(out, keepRecentImages) <= target) break;\n out = out.map((x) => (x.role === 'system' ? x : elideBody(x, cap)));\n }\n return out;\n}\n\n/** Elide one message's text down to `cap` chars. Array content keeps its non-text parts (images)\n * intact — only the text parts are shaved — and the note says so, rather than dropping them invisibly. */\nfunction elideBody(x: Message, cap: number): Message {\n const note = (bytes: number, imgs: number) =>\n `\\n\\n[${bytes} bytes elided by /compact${x.role === 'tool' ? ' — re-run the tool to view' : ''}` +\n `${imgs ? `; ${imgs} image part(s) KEPT in full — they still cost context` : ''}]`;\n if (!Array.isArray(x.content)) {\n const text = contentText(x.content);\n if (text.length <= cap) return x;\n return { ...x, content: `${text.slice(0, cap)}${note(text.length - cap, 0)}` };\n }\n const imgs = x.content.filter((p) => p.type !== 'text').length;\n let left = cap;\n let elided = 0;\n // EMPTY text parts are dropped, never emitted: once `left` hits 0 every later text part would otherwise\n // become `{type:'text', text:''}` — which the Anthropic API rejects outright.\n const parts: ContentPart[] = [];\n for (const p of x.content) {\n if (p.type !== 'text') { parts.push(p); continue; }\n const t = p.text ?? '';\n if (t.length <= left) { left -= t.length; if (t) parts.push(p); continue; }\n const keep = left; left = 0; elided += t.length - keep;\n if (keep > 0) parts.push({ ...p, text: t.slice(0, keep) });\n }\n // Nothing shaved: only rewrite if we actually dropped pre-existing empty parts (never to an empty body).\n if (!elided) return parts.length === x.content.length || !parts.length ? x : { ...x, content: parts };\n // The note is always appended, so the message can never end up with zero content parts.\n return { ...x, content: [...parts, { type: 'text', text: note(elided, imgs).trimStart() }] };\n}\n\n/** All tool_call ids present on assistant messages — one O(n) pass instead of a scan per result. */\nconst callIdSet = (msgs: Message[]): Set<string> => {\n const ids = new Set<string>();\n for (const m of msgs) if (m.role === 'assistant') for (const tc of m.tool_calls ?? []) ids.add(tc.id);\n return ids;\n};\n\n/** Drop every orphan tool_result (one whose tool_call isn't in the set) — sending one is a hard API\n * 400. Anywhere in the sequence, not just the head. Returns the same array reference when clean. */\nfunction dropOrphanToolResults(messages: Message[]): Message[] {\n const ids = callIdSet(messages);\n const ok = (m: Message) => m.role !== 'tool' || ids.has(m.tool_call_id ?? '');\n return messages.every(ok) ? messages : messages.filter(ok);\n}\n\n/**\n * Token-aware backstop: keep the system head, drop oldest body messages until under `maxTokens`.\n * The window may empty entirely (a single message can exceed the whole budget), and it is never\n * left starting on an ORPHAN tool_result (one whose tool_call isn't in the window) — that would\n * break tool_use↔tool_result pairing and get rejected by the API. If even [system] is over budget\n * (e.g. a huge memory index), we can't trim further — warn; the hard `maxTokens` kill-switch is the real guard.\n */\nfunction fitTokenBudget(messages: Message[], maxTokens: number, keepRecentImages = 1): Message[] {\n // Incremental accounting: estimate each message once, subtract as we drop — O(n), not O(n²)\n // (re-estimating the whole window per dropped message walks every char repeatedly). Per-message\n // weights come from the SHARED window (`sendBytesPer`), so a stale ref isn't charged its file.\n const per = sendBytesPer(messages, keepRecentImages).map((b) => Math.ceil(b / 4));\n let total = per.reduce((a, b) => a + b, 0);\n if (total <= maxTokens) return messages;\n const head = messages[0]?.role === 'system' ? [messages[0]] : [];\n let from = head.length; // body = messages[from..]\n while (from < messages.length && total > maxTokens) total -= per[from++];\n const ids = callIdSet(messages.slice(from));\n while (from < messages.length && messages[from].role === 'tool' && !ids.has(messages[from].tool_call_id ?? '')) total -= per[from++];\n if (total > maxTokens)\n log.warn(`context ~${total} tok still over maxContextTokens=${maxTokens} after trimming (system head can't be dropped)`);\n return [...head, ...messages.slice(from)];\n}\n\n/** system (if any) + synthetic summary of the dropped middle + most-recent window; fits within `max`. */\nfunction compact(m: Message[], max: number, focus?: string): Message[] {\n const hasSystem = m[0]?.role === 'system';\n const head = hasSystem ? [m[0]] : [];\n // Reserve one slot for the summary, the rest for the most-recent window. Bound the tail\n // to the post-head slice so a short transcript (max >= length) can't re-include the head.\n const tailCount = Math.max(1, max - head.length - 1);\n const tail = m.slice(head.length).slice(-tailCount);\n const dropped = m.slice(head.length, m.length - tail.length);\n if (dropped.length === 0) return [...head, ...tail];\n return [...head, { role: 'system', content: summarize(dropped, focus) }, ...tail];\n}\n\n/** Header of a synthetic recap produced by `summarize` — how a LATER pass recognizes its own output. */\nconst SUMMARY_HEAD = '[summary of ';\n/** Upper bound on the message count a single prior recap may claim (untrusted input — see summarize). */\nconst MAX_CARRIED_COUNT = 10_000;\nconst isSyntheticSummary = (m: Message): boolean =>\n m.role === 'system' && typeof m.content === 'string' && m.content.startsWith(SUMMARY_HEAD);\n\n/** Lightweight, deterministic, LLM-free recap of a span of messages.\n * A recap from an EARLIER pass inside the span is carried forward (its message count and its detail\n * lines), never silently thrown away — the escalation ladder re-folds an already-folded transcript, and\n * a recap that discards its predecessor would lie about how much history it stands for. */\nfunction summarize(messages: Message[], focus?: string): string {\n const tools = new Set<string>();\n const files = new Set<string>();\n const carried: string[] = []; // detail lines from prior recaps in this span (deduped, bounded)\n let carriedCount = 0; // messages those recaps already stood for\n let priors = 0;\n let lastAssistant = '';\n for (const msg of messages) {\n if (isSyntheticSummary(msg)) {\n priors++;\n const [head, ...rest] = String(msg.content).split('\\n');\n // Clamp: a recap head is data, not a promise — a restored session or a hook-written system message\n // could carry `[summary of 999999 …]` and we must not absorb it verbatim.\n carriedCount += Math.min(Math.max(Number(/of (\\d+)/.exec(head)?.[1]) || 0, 0), MAX_CARRIED_COUNT);\n for (const l of rest) if (l.trim() && !carried.includes(l) && carried.length < 20) carried.push(l);\n continue;\n }\n for (const tc of msg.tool_calls ?? []) {\n tools.add(tc.function.name);\n try {\n const args = tc.function.arguments ? JSON.parse(tc.function.arguments) : {};\n if (typeof args.path === 'string') files.add(args.path);\n } catch {\n /* arguments not JSON — skip file extraction */\n }\n }\n if (msg.role === 'assistant' && msg.content) lastAssistant = contentText(msg.content);\n }\n const lines = [`${SUMMARY_HEAD}${messages.length - priors + carriedCount} earlier message(s)]`];\n if (tools.size) lines.push(`tools used: ${[...tools].join(', ')}`);\n if (files.size) lines.push(`files touched: ${[...files].join(', ')}`);\n if (lastAssistant) lines.push(`last assistant: ${lastAssistant}`);\n if (carried.length) lines.push('earlier recap:', ...carried.map((l) => ` ${l}`));\n // Focused compaction: keep lines from the dropped span that mention any focus keyword,\n // verbatim (bounded), so \"/compact keep the API details\" doesn't lose them to the recap.\n if (focus?.trim()) {\n const words = focus.toLowerCase().split(/\\s+/).filter((w) => w.length > 2);\n const kept: string[] = [];\n // THIS span's own messages are scanned FIRST: a prior recap sits at index 0 and would otherwise eat the\n // whole budget, so repeated `/compact <focus>` would keep only the OLDEST hits and drop the newest.\n // (Older hits still reach the recap via `carried` above.)\n const ordered = [...messages.filter((m) => !isSyntheticSummary(m)), ...messages.filter(isSyntheticSummary)];\n outer: for (const msg of ordered) {\n if (msg.role === 'tool') continue; // tool bodies are bulk noise; user/assistant text carries the decisions\n for (const line of contentText(msg.content).split('\\n')) {\n const l = line.toLowerCase();\n if (line.trim() && words.some((w) => l.includes(w))) {\n kept.push(line.trim().slice(0, 200));\n if (kept.length >= 12) break outer;\n }\n }\n }\n if (kept.length) lines.push(`preserved (re: ${focus.trim()}):`, ...kept.map((l) => ` ${l}`));\n }\n return lines.join('\\n');\n}\n\nfunction lastAssistantText(messages: Message[]): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === 'assistant') return contentText(messages[i].content);\n }\n return '';\n}\n","/**\n * Sandbox background jobs — the in-process twin of `ShellJobRegistry` (src/tools.shell.ts), but for work\n * that runs *inside* the sandbox rather than as an OS child process. Backs `bash({background:true})` and\n * (later) background sub-agents.\n *\n * IMPORTANT — this is concurrency via async-I/O interleaving, NOT parallelism. The runtime is single\n * threaded: a CPU-bound JS command still blocks. Real overlap only happens when a job *awaits* — i.e. a\n * remote VFS backend (BodDbFilesystem, network per read) or a sub-agent (model calls). Over a pure in-mem\n * MemFilesystem, backgrounding a fast command buys nothing (the tool description says so).\n *\n * The registry is kind-AGNOSTIC: it tracks any async producer's lifecycle + tail output. Overlay isolation\n * and commit-on-success are the *producer's* responsibility (IoC), so the registry stays a pure tracker.\n */\nexport type JobStatus = 'running' | 'done' | 'error' | 'killed';\n\n/** A producer: does the actual work, may stream progress via `onChunk`, returns its final text. */\nexport interface JobFn {\n (ctx: { signal: AbortSignal; onChunk: (s: string) => void }): Promise<string>;\n}\n\ninterface Job {\n kind: string;\n label: string;\n status: JobStatus;\n buf: string;\n ctl: AbortController;\n promise: Promise<void>;\n}\n\n/** Per-session registry of in-process background jobs. Bounded tail buffer; abortable; drainable at turn end. */\nexport class SandboxJobRegistry {\n private jobs = new Map<string, Job>();\n private seq = 0;\n constructor(private maxBuffer = 256 * 1024) {}\n\n /** Start `fn` in the background and return a job id immediately (does not await completion). */\n start(fn: JobFn, opts: { kind?: string; label?: string } = {}): string {\n const id = `job-${++this.seq}`;\n const ctl = new AbortController();\n const onChunk = (s: string) => { job.buf = (job.buf + s).slice(-this.maxBuffer); }; // ring: keep the tail\n const job: Job = { kind: opts.kind ?? 'task', label: opts.label ?? '', status: 'running', buf: '', ctl, promise: Promise.resolve() };\n job.promise = fn({ signal: ctl.signal, onChunk }).then(\n (res) => { if (job.status === 'running') { job.status = 'done'; if (res) onChunk(res); } },\n (e: any) => { if (job.status === 'running') { job.status = 'error'; onChunk(`\\n[error] ${e?.message ?? e}`); } },\n );\n this.jobs.set(id, job);\n return id;\n }\n\n /** Tail output for a job (null = no such job, '' = job exists but no output yet). */\n output(id: string): string | null { return this.jobs.get(id)?.buf ?? (this.jobs.has(id) ? '' : null); }\n\n status(id: string): { status: JobStatus; bytes: number } | null {\n const j = this.jobs.get(id);\n return j ? { status: j.status, bytes: j.buf.length } : null;\n }\n\n list(): Array<{ id: string; kind: string; label: string; status: JobStatus }> {\n return [...this.jobs].map(([id, j]) => ({ id, kind: j.kind, label: j.label, status: j.status }));\n }\n\n /** Signal cancel (the producer decides what abort means — e.g. skip the overlay commit). */\n kill(id: string): boolean {\n const j = this.jobs.get(id);\n if (!j) return false;\n if (j.status === 'running') { j.ctl.abort(); j.status = 'killed'; }\n return true;\n }\n\n killAll(): void { for (const id of this.jobs.keys()) this.kill(id); }\n\n /** Await every still-running job. Called at turn end so a job's committed writes aren't lost from view\n * just because the model didn't poll it. Returns the ids that were still running when drain began. */\n async drain(): Promise<string[]> {\n const pending = [...this.jobs].filter(([, j]) => j.status === 'running').map(([id]) => id);\n await Promise.all([...this.jobs.values()].map((j) => j.promise));\n return pending;\n }\n}\n\nconst NO_JOB = (id: string) =>\n `Error: no background job '${id}'. Use JobStatus with no id to list jobs, or start one with bash({background:true}).`;\n\n/** Companion tools (JobOutput / JobStatus / JobKill) over a SandboxJobRegistry. */\nexport function makeJobTools(registry: SandboxJobRegistry): import('./tools').AgentTool[] {\n return [\n {\n name: 'JobOutput',\n description: 'Read the accumulated output (tail) of a background job by id (from bash({background:true})).',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n async run({ id }) {\n const out = registry.output(String(id));\n if (out == null) return NO_JOB(String(id));\n const st = registry.status(String(id))!;\n return `[${st.status}]\\n${out.replace(/\\n+$/, '') || '(no output yet)'}`;\n },\n },\n {\n name: 'JobStatus',\n description: 'Status of a background job (running/done/killed/error). Omit `id` to list all jobs.',\n parameters: { type: 'object', properties: { id: { type: 'string' } } },\n async run({ id }) {\n if (!id) {\n const jobs = registry.list();\n return jobs.length ? jobs.map((j) => `${j.id} ${j.status} ${j.kind}${j.label ? ' ' + j.label : ''}`).join('\\n') : '(no background jobs)';\n }\n const st = registry.status(String(id));\n return st ? `${st.status} · ${st.bytes} byte(s) buffered` : NO_JOB(String(id));\n },\n },\n {\n name: 'JobKill',\n description: 'Stop a running background job by id (the job is cancelled; its overlay writes are NOT committed).',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n async run({ id }) {\n return registry.kill(String(id)) ? `Killed job ${id}.` : NO_JOB(String(id));\n },\n },\n ];\n}\n","import type { AgentTool, ToolContext, HostBridge, UserQuestion } from './tools';\n\nexport type { HostBridge, UserQuestion } from './tools';\n\n/**\n * `AskUserQuestion` tool — lets the model pose a structured choice to a human.\n * Delegates to `ctx.host.ask` when a human is reachable.\n *\n * When NO human is reachable (`host.ask` absent — headless `-p`, a piped/redirected run, an edge\n * host), the question is NOT dropped and NOT guessed at: it parks on `ctx.needsInput`, and the\n * Agent ends the run with `finishReason:'needs_input'` carrying the question up to the CALLER.\n * The caller answers and resumes. Guessing silently is the failure mode this exists to prevent —\n * a delegated agent that picks for you on a decision that was never its to make.\n */\nexport const askUserQuestionTool: AgentTool = {\n name: 'AskUserQuestion',\n description:\n 'Ask the user a multiple-choice question when a decision is genuinely theirs to make: an ambiguous or under-specified requirement, a fork you cannot resolve from context, a premise of the task that the evidence contradicts, or a risky/irreversible next step. Prefer this over guessing, \"proceeding with best judgment\", or quietly widening scope to make an unclear brief fit — a wrong silent decision is far more costly than a question. Returns their selection if a human is reachable; otherwise the run pauses and the question is handed to whoever delegated the task (you do not need to know which — just ask).',\n parameters: {\n type: 'object',\n required: ['question', 'options'],\n properties: {\n question: { type: 'string' },\n header: { type: 'string', description: 'short label for the question' },\n options: {\n type: 'array',\n items: { type: 'object', required: ['label'], properties: { label: { type: 'string' }, description: { type: 'string' } } },\n },\n multiSelect: { type: 'boolean' },\n },\n },\n async run(args: UserQuestion, ctx: ToolContext) {\n if (!ctx.host?.ask) {\n // No human on this side of the process — raise the question to the caller and stop the run.\n // Never block on a prompt nobody can see (that hangs until an external timeout reaps the turn).\n ctx.needsInput = args;\n return 'PAUSED — no interactive user is reachable from this run, so your question has been raised to the caller that delegated this task. The run stops here; do not guess and do not continue. Their answer will arrive as the next user message when the run resumes.';\n }\n const answer = ctx.host.ask(args); // human-blocking — park it so the wait doesn't count toward the timeout\n return ctx.parkHuman ? ctx.parkHuman(answer) : answer;\n },\n};\n\n/** Deterministic HostBridge for tests/dev: scripts answers + records what was asked. */\nexport class ScriptedHostBridge implements HostBridge {\n public asked: UserQuestion[] = [];\n public confirms: string[] = [];\n public events: Array<{ kind: string; message: string; data?: unknown }> = [];\n constructor(private answers: string[] = [], private confirmDefault = true) {}\n async ask(q: UserQuestion): Promise<string> {\n this.asked.push(q);\n return this.answers.shift() ?? q.options[0]?.label ?? '';\n }\n async confirm(prompt: string): Promise<boolean> {\n this.confirms.push(prompt);\n return this.confirmDefault;\n }\n notify(event: { kind: string; message: string; data?: unknown }): void {\n this.events.push(event);\n }\n}\n\n/** Node CLI HostBridge: prompts on stdin. (node-only host adapter; not edge-safe by design.) */\nexport class ConsoleHostBridge implements HostBridge {\n async ask(q: UserQuestion): Promise<string> {\n const rl = await import('node:readline/promises');\n const io = rl.createInterface({ input: process.stdin, output: process.stdout });\n try {\n const lines = [q.header ? `\\n[${q.header}] ${q.question}` : `\\n${q.question}`];\n q.options.forEach((o, i) => lines.push(` ${i + 1}) ${o.label}${o.description ? ' — ' + o.description : ''}`));\n const ans = await io.question(lines.join('\\n') + '\\n> ');\n const n = Number(ans.trim());\n return Number.isInteger(n) && q.options[n - 1] ? q.options[n - 1].label : ans.trim();\n } finally {\n io.close();\n }\n }\n async confirm(prompt: string): Promise<boolean> {\n const rl = await import('node:readline/promises');\n const io = rl.createInterface({ input: process.stdin, output: process.stdout });\n try {\n const ans = await io.question(`\\n${prompt} [y/N] `);\n return /^y(es)?$/i.test(ans.trim());\n } finally {\n io.close();\n }\n }\n notify(event: { kind: string; message: string }): void {\n console.error(`[${event.kind}] ${event.message}`);\n }\n}\n","/**\n * Lexical relevance — no deps, deterministic, edge-safe. Ranks catalog entries (skills,\n * commands, memories, docs) by a task hint so a LARGE catalog doesn't dump every entry into\n * the prompt. TF-IDF weighted: rare terms in the corpus score higher than common ones.\n */\n\nconst STOP = new Set([\n 'the', 'and', 'for', 'with', 'that', 'this', 'from', 'into', 'your', 'you', 'are', 'was', 'will',\n 'use', 'using', 'run', 'add', 'fix', 'make', 'file', 'files', 'code', 'please', 'need', 'want', 'should', 'all',\n]);\n\n/** Lowercased alphanumeric tokens of length ≥ 3, minus a few stopwords. */\nexport function tokenize(s: string): Set<string> {\n const out = new Set<string>();\n for (const w of String(s ?? '').toLowerCase().match(/[a-z0-9]+/g) ?? []) {\n if (w.length >= 3 && !STOP.has(w)) out.add(w);\n }\n return out;\n}\n\n/** Build IDF weights from a corpus of texts. Rare terms get higher weight. */\nexport function idfWeights(corpus: string[]): Map<string, number> {\n const N = corpus.length;\n if (N === 0) return new Map();\n const df = new Map<string, number>();\n for (const doc of corpus) for (const t of tokenize(doc)) df.set(t, (df.get(t) ?? 0) + 1);\n const idf = new Map<string, number>();\n for (const [t, n] of df) idf.set(t, Math.log((N + 1) / (n + 1)) + 1); // smooth IDF\n return idf;\n}\n\n/** TF-IDF weighted relevance score. Without IDF, falls back to flat token overlap (backward-compatible). */\nexport function relevanceScore(text: string, queryTokens: Set<string>, idf?: Map<string, number>): number {\n if (queryTokens.size === 0) return 0;\n const t = tokenize(text);\n let score = 0;\n for (const q of queryTokens) if (t.has(q)) score += idf?.get(q) ?? 1;\n return score;\n}\n\n/**\n * Split `items` into the `k` most relevant to `query` (by TF-IDF overlap with `text(item)`)\n * and the rest, preserving each item's original order within its group. Returns everything in\n * `kept` (empty `rest`) when `items.length <= k` or `query` is blank — so it's a no-op for\n * small lists. When `corpus` is provided, builds IDF weights for better ranking.\n */\nexport function topByRelevance<T>(items: T[], query: string, text: (x: T) => string, k: number, corpus?: string[]): { kept: T[]; rest: T[] } {\n if (!Number.isInteger(k) || k < 1) return { kept: items, rest: [] }; // invalid k → no-op (keep all), never hide\n if (items.length <= k || !query.trim()) return { kept: items, rest: [] };\n const q = tokenize(query);\n if (q.size === 0) return { kept: items.slice(0, k), rest: items.slice(k) };\n const idf = corpus?.length ? idfWeights(corpus) : undefined;\n const scored = items.map((x, i) => ({ i, s: relevanceScore(text(x), q, idf) }));\n scored.sort((a, b) => b.s - a.s || a.i - b.i); // best score first; stable by original index\n const keep = new Set(scored.slice(0, k).map((e) => e.i));\n return { kept: items.filter((_, i) => keep.has(i)), rest: items.filter((_, i) => !keep.has(i)) };\n}\n","/**\n * Lean YAML-frontmatter parsing (no YAML dependency) shared by skills + commands.\n * Handles single-line values AND block scalars (`>`, `>-`, `|`, `|-`, …) — CC skills\n * often fold long descriptions across indented lines, which a single-line regex truncates.\n */\n\n/** Extract the `---`-delimited frontmatter block + the body that follows it. */\nexport function splitFrontmatter(md: string): { block: string; body: string } {\n const m = md.match(/^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n?/);\n return { block: m ? m[1] : '', body: (m ? md.slice(m[0].length) : md).trim() };\n}\n\n/** Grab a scalar field from a frontmatter block by key (case-insensitive). Folds block scalars to one line. */\nexport function grabField(block: string, key: string): string | undefined {\n const lines = block.split('\\n');\n const i = lines.findIndex((l) => new RegExp(`^${key}\\\\s*:`, 'i').test(l));\n if (i < 0) return undefined;\n const inline = lines[i].replace(new RegExp(`^${key}\\\\s*:\\\\s*`, 'i'), '');\n // Block scalar (`>`/`|` with optional chomping `-`/`+`): gather the following more-indented lines.\n if (/^[>|][+-]?\\s*$/.test(inline)) {\n const folded: string[] = [];\n for (let j = i + 1; j < lines.length && /^\\s+\\S/.test(lines[j]); j++) folded.push(lines[j].trim());\n return folded.join(' ').trim() || undefined; // fold to one line (catalog descriptions are single-line)\n }\n return inline.trim().replace(/^[\"']|[\"']$/g, '') || undefined;\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { AgentTool, ToolContext } from './tools';\nimport { topByRelevance } from './relevance';\nimport { splitFrontmatter, grabField } from './frontmatter';\n\n/** Above this many commands, the catalog shows full entries only for the most task-relevant; the rest list as names. */\nconst MAX_CATALOG = 25;\n\nexport interface CommandInfo {\n name: string;\n description: string;\n path: string;\n}\n\n/**\n * Resolves a name in the *other* half of the merged slash namespace (CC parity: `/x` is one\n * namespace whether `x` is a `commands/x.md` or a `skills/x/SKILL.md`). On a miss in its own\n * registry, a tool calls this to find the sibling and learn how to expand it. Injected by the\n * caller (Agent.prepare) so commands.ts and skills.ts stay mutually decoupled (no circular import).\n */\nexport type SiblingResolver = (name: string) => Promise<{ path: string; stripFrontmatter: boolean } | undefined>;\n\n/** Parse a command template's `description:` frontmatter + return the body that follows. */\nfunction parseFrontmatter(md: string): { description?: string; body: string } {\n const { block, body } = splitFrontmatter(md);\n return { description: grabField(block, 'description'), body };\n}\n\n/**\n * Expand a command template's argument placeholders:\n * - `$ARGUMENTS` → all args (every occurrence)\n * - `$1`…`$9` → positional args (whitespace-split; missing → empty)\n * If the body has neither placeholder, `args` is appended as a trailing block (back-compat).\n */\nexport function expandTemplate(body: string, args: string): string {\n if (!/\\$ARGUMENTS|\\$[1-9]/.test(body)) return args ? `${body}\\n\\n${args}` : body;\n const toks = args.trim() ? args.trim().split(/\\s+/) : [];\n return body.split('$ARGUMENTS').join(args).replace(/\\$([1-9])/g, (_m, n) => toks[Number(n) - 1] ?? '');\n}\n\n/** Inline `@path` references (CC-style) with the file's contents, fenced. Non-existent paths stay literal. */\nasync function embedFiles(text: string, fs: IFilesystem): Promise<string> {\n const refs = [...new Set([...text.matchAll(/(?:^|\\s)@(\\S+)/g)].map((m) => m[1]))];\n let out = text;\n for (const ref of refs) {\n try {\n const content = await fs.readFile(ref);\n out = out.split('@' + ref).join(`\\n\\n--- @${ref} ---\\n${content}\\n--- end @${ref} ---\\n`);\n } catch { /* not a readable file — leave the literal @ref (could be an email, decorator, etc.) */ }\n }\n return out;\n}\n\n/**\n * Read a slash entry's file and return its expanded text: arg placeholders filled, then `@file`\n * refs embedded. `stripFrontmatter` drops the YAML head (commands feed only their body); skills\n * feed the whole SKILL.md (frontmatter is part of the instructions). Shared by commands + skills\n * so both halves of the merged namespace expand identically (CC parity).\n */\nexport async function expandEntry(\n fs: IFilesystem,\n path: string,\n args: string,\n opts: { stripFrontmatter?: boolean } = {},\n): Promise<string> {\n const raw = await fs.readFile(path);\n const text = opts.stripFrontmatter ? parseFrontmatter(raw).body : raw;\n return embedFiles(expandTemplate(text, args), fs);\n}\n\n/** Read a command file and return its expanded body: arg placeholders filled, then `@file` refs embedded. */\nexport async function expandCommand(fs: IFilesystem, cmd: CommandInfo, args: string): Promise<string> {\n return expandEntry(fs, cmd.path, args, { stripFrontmatter: true });\n}\n\n/**\n * Discover slash commands under `dir` (each `<dir>/<name>.md`) and produce:\n * - `catalog`: a names+descriptions block for the system prompt,\n * - `tool`: a `SlashCommand` tool that returns a command's expanded template body.\n *\n * Commands are reusable prompt templates (like Claude Code slash commands) — just\n * VFS files. The template body is returned (user args appended, and `$ARGUMENTS`\n * substituted if present) so the model can act on it. Mirrors loadSkills.\n */\n/** Scan `dir`(s) for `<dir>/<name>.md` command templates (first dir wins on duplicate names). */\nexport async function scanCommands(fs: IFilesystem, dir: string | string[]): Promise<CommandInfo[]> {\n const commands: CommandInfo[] = [];\n const seen = new Set<string>();\n for (const d of Array.isArray(dir) ? dir : [dir]) {\n if (!await fs.exists(d)) continue;\n for (const entry of await fs.readDir(d)) {\n if (!entry.endsWith('.md')) continue;\n const name = entry.replace(/\\.md$/, '');\n if (seen.has(name)) continue; // first dir wins\n seen.add(name);\n const path = `${d}/${entry}`;\n const fm = parseFrontmatter(await fs.readFile(path));\n commands.push({ name, description: fm.description || '', path });\n }\n }\n return commands;\n}\n\nexport async function loadCommands(\n fs: IFilesystem,\n dir: string | string[],\n opts: { relevanceHint?: string; max?: number; sibling?: SiblingResolver } = {},\n): Promise<{ commands: CommandInfo[]; catalog: string; tool?: AgentTool }> {\n const commands = await scanCommands(fs, dir);\n if (commands.length === 0) return { commands, catalog: '' };\n\n // At scale, show full entries only for the most task-relevant; the rest list as names (still\n // runnable by name). No-op for small catalogs (≤ max) or no hint, so the prefix stays stable.\n const { kept, rest } = topByRelevance(commands, opts.relevanceHint ?? '', (c) => `${c.name} ${c.description}`, opts.max ?? MAX_CATALOG);\n const catalog =\n '## Slash commands (reusable prompt templates)\\n' +\n kept.map((c) => `- **/${c.name}** — ${c.description} (\\`${c.path}\\`)`).join('\\n') +\n (rest.length ? `\\n- (${rest.length} more, names only — call \\`SlashCommand\\` to run): ${rest.map((c) => c.name).join(', ')}` : '') +\n '\\nTo run one, call the `SlashCommand` tool with its name (and optional `args`); it returns the expanded template to act on.';\n\n const tool: AgentTool = {\n name: 'SlashCommand',\n description: 'Run a slash command (or skill) by name — returns its expanded prompt template/instructions (with your `args` substituted/appended). Resolves both the command and skill namespaces. Use when a task matches a listed command or skill.',\n parameters: {\n type: 'object',\n required: ['name'],\n properties: { name: { type: 'string' }, args: { type: 'string', description: 'arguments to fill the template' } },\n },\n async run({ name, args }, ctx: ToolContext) {\n const slug = String(name ?? '').replace(/^\\//, '');\n let c = commands.find((x) => x.name === slug);\n let fresh: CommandInfo[] | undefined;\n if (!c) { // miss → rescan: commands created mid-conversation are runnable without a reprepare\n fresh = await scanCommands(ctx.fs, dir);\n c = fresh.find((x) => x.name === slug);\n if (c) commands.push(c);\n }\n if (c) return expandCommand(ctx.fs, c, String(args ?? ''));\n // still a miss → merged namespace: try the sibling (skills) registry before failing.\n const sib = await opts.sibling?.(slug);\n if (sib) return expandEntry(ctx.fs, sib.path, String(args ?? ''), { stripFrontmatter: sib.stripFrontmatter });\n return `Error: no command or skill named '${slug}'. Available commands: ${(fresh ?? []).map((x) => x.name).join(', ') || '(none)'}`;\n },\n };\n return { commands, catalog, tool };\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { AgentTool, ToolContext } from './tools';\nimport { topByRelevance } from './relevance';\nimport { splitFrontmatter, grabField } from './frontmatter';\nimport { expandEntry, type SiblingResolver } from './commands';\n\n/** Above this many skills, the catalog shows full entries only for the most task-relevant; the rest list as names. */\nconst MAX_CATALOG = 25;\n\nexport interface SkillInfo {\n name: string;\n description: string;\n path: string;\n}\n\n/** Parse a SKILL.md's `name:` / `description:` frontmatter (falls back to scanning the head if undelimited). */\nfunction parseFrontmatter(md: string): { name?: string; description?: string } {\n const { block } = splitFrontmatter(md);\n const b = block || md.slice(0, 600);\n return { name: grabField(b, 'name'), description: grabField(b, 'description') };\n}\n\n/**\n * Discover skills under `dir` (each `<dir>/<id>/SKILL.md`) and produce:\n * - `catalog`: a names+descriptions block for the system prompt,\n * - `tool`: a `Skill` tool that returns a skill's full SKILL.md (progressive disclosure).\n *\n * Skills are just VFS files — the Read tool already gives progressive disclosure; this\n * adds the catalog + a convenience tool. (Executable skills can be `bash`-exec'd: wcli\n * runs JS files from the VFS as commands.)\n */\n/** Scan `dir`(s) for `<dir>/<id>/SKILL.md` entries (first dir wins on duplicate ids). */\nexport async function scanSkills(fs: IFilesystem, dir: string | string[]): Promise<SkillInfo[]> {\n const skills: SkillInfo[] = [];\n const seen = new Set<string>();\n for (const d of Array.isArray(dir) ? dir : [dir]) {\n if (!await fs.exists(d)) continue;\n for (const entry of await fs.readDir(d)) {\n if (seen.has(entry)) continue; // first dir wins (our .agent/ before .claude/)\n const skillMd = `${d}/${entry}/SKILL.md`;\n if (await fs.exists(skillMd)) {\n seen.add(entry);\n const fm = parseFrontmatter(await fs.readFile(skillMd));\n skills.push({ name: fm.name || entry, description: fm.description || '', path: skillMd });\n }\n }\n }\n return skills;\n}\n\nexport async function loadSkills(\n fs: IFilesystem,\n dir: string | string[],\n opts: { relevanceHint?: string; max?: number; sibling?: SiblingResolver } = {},\n): Promise<{ skills: SkillInfo[]; catalog: string; tool?: AgentTool }> {\n const skills = await scanSkills(fs, dir);\n if (skills.length === 0) return { skills, catalog: '' };\n\n // At scale, show full entries only for the most task-relevant; the rest list as names (still\n // loadable by name). No-op for small catalogs (≤ max) or no hint, so the prefix stays stable.\n const { kept, rest } = topByRelevance(skills, opts.relevanceHint ?? '', (s) => `${s.name} ${s.description}`, opts.max ?? MAX_CATALOG);\n const catalog =\n '## Skills (load one before acting on a matching task)\\n' +\n kept.map((s) => `- **${s.name}** — ${s.description} (\\`${s.path}\\`)`).join('\\n') +\n (rest.length ? `\\n- (${rest.length} more, names only — call \\`Skill\\` to load): ${rest.map((s) => s.name).join(', ')}` : '') +\n '\\nWhen a task matches a skill, call the `Skill` tool with its name to load its full instructions.';\n\n const tool: AgentTool = {\n name: 'Skill',\n description: 'Load a skill (or slash command) by name — returns its full instructions (SKILL.md / expanded template), with any `args` substituted/appended. Resolves both the skill and command namespaces. Use when a task matches a listed skill or command.',\n parameters: { type: 'object', required: ['name'], properties: { name: { type: 'string' }, args: { type: 'string', description: 'arguments to fill the template' } } },\n async run({ name, args }, ctx: ToolContext) {\n const slug = String(name ?? '').replace(/^\\//, '');\n let s = skills.find((x) => x.name === slug);\n let fresh: SkillInfo[] | undefined;\n if (!s) { // miss → rescan: skills created mid-conversation are loadable without a reprepare\n fresh = await scanSkills(ctx.fs, dir);\n s = fresh.find((x) => x.name === slug);\n if (s) skills.push(s);\n }\n if (s) return expandEntry(ctx.fs, s.path, String(args ?? '')); // skill: whole SKILL.md (frontmatter kept)\n // still a miss → merged namespace: try the sibling (commands) registry before failing.\n const sib = await opts.sibling?.(slug);\n if (sib) return expandEntry(ctx.fs, sib.path, String(args ?? ''), { stripFrontmatter: sib.stripFrontmatter });\n return `Error: no skill or command named '${slug}'. Available skills: ${(fresh ?? []).map((x) => x.name).join(', ') || '(none)'}`;\n },\n };\n return { skills, catalog, tool };\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { AgentTool, ToolContext } from './tools';\nimport { mkdirp } from './tools.structured';\nimport { topByRelevance, tokenize, relevanceScore, idfWeights } from './relevance';\nimport { splitFrontmatter } from './frontmatter';\n\nconst MAX_INDEX = 25;\nconst MAX_INDEX_LINES = 200;\nconst MAX_INDEX_BYTES = 25_000;\n\n/** Behavioral guidance injected alongside the memory index — adapted from CC's battle-tuned prose, for our tool-based workflow. */\nexport const MEMORY_PROMPT =\n '## Memory guidelines\\n' +\n '**When to Remember:** user corrections (\"no, do X instead\"), preferences (\"I prefer Y\"), project constraints, recurring gotchas, ' +\n 'role/context (\"I\\'m a data scientist\"), workflow patterns confirmed by the user. Capture the WHY, not just the what.\\n' +\n '**When NOT to Remember:** task-specific scratch, transient state, things derivable from code/git, conversation filler, ' +\n 'anything already in instruction files. If removing the memory wouldn\\'t change future behavior, don\\'t save it.\\n' +\n '**Types** (pass to Remember — this determines where the memory is stored):\\n' +\n '- `user` — role, preferences, knowledge level, collaboration style (GLOBAL — follows you across projects)\\n' +\n '- `feedback` — corrections, what to avoid/repeat, with WHY (GLOBAL)\\n' +\n '- `project` — ongoing work, goals, constraints, deadlines (LOCAL to this project; convert relative dates to absolute)\\n' +\n '- `reference` — pointers to external resources, URLs, vendor docs (LOCAL to this project)\\n' +\n '**Before acting on a recalled memory:** verify it\\'s still true — a memory naming a file/function/flag is a claim ' +\n 'from when it was written. Grep/read to confirm before recommending. Stale memory → update via Remember (same slug overwrites).\\n' +\n '**Dedup:** before writing, check if a similar memory exists (Recall or MemorySearch). Update the existing one rather than creating duplicates.\\n' +\n 'Call `Recall` with a slug (or multiple slugs/a pattern) to load full bodies when relevant.\\n' +\n 'Call `MemorySearch` with a query to find memories by content when you don\\'t know the slug.\\n' +\n 'Call `Remember` to persist a durable fact for future sessions.';\n\n/** Voice-specific memory guidance — shorter, spoken-interaction tuned. */\nexport const VOICE_MEMORY_PROMPT =\n 'You have Remember and Recall tools — use them directly, no delegation needed.\\n' +\n 'IMPLICIT CAPTURE: when the user shares their name, role, a preference, a correction (\"no, do X instead\"), ' +\n 'or a project constraint — call Remember immediately without announcing it. Natural memory, not a ceremony.\\n' +\n 'For explicit \"remember X\" requests, also call Remember directly and confirm briefly (\"got it\").\\n' +\n 'Do NOT remember: transient task details, conversation filler, things you\\'d forget in a real conversation.\\n' +\n 'Keep it invisible: never announce \"saving to memory\" or list what you remembered unless asked.\\n' +\n 'For anything requiring files, shell, or web — still Act.';\n\n/**\n * Load memory for injection at run start (the recall step), with progressive disclosure:\n * - `index`: the compact `<dir>/MEMORY.md` index, injected into the system prompt — cheap,\n * always-hot. Each line points at a fact file the agent can pull on demand.\n * - `tools`: `Recall` (load one fact body on demand — keeps facts COLD until needed) and\n * `Remember` (persist a durable fact + index pointer mid-run — the WRITE half that closes\n * the learning loop: what the agent learns now steers future sessions).\n *\n * Persistence is the BACKEND's job, for free: NodeDiskFilesystem → disk,\n * IndexedDbFilesystem → browser, (planned) BodDbFilesystem → database. The same\n * memory mechanism therefore works in node, a browser tab, or on edge.\n */\nexport interface LoadMemoryOpts {\n relevanceHint?: string;\n max?: number;\n /** Max Remember calls per session (default 25). Prevents runaway memory writes. */\n maxWritesPerSession?: number;\n /** Called after each successful memory write (auditing, UI indicators). */\n onMemorySaved?: (slug: string, type?: string) => void;\n /** User-scope dir for global memories (type=user/feedback). If set, Remember routes by type:\n * user/feedback → userDir (global, survives across projects), project/reference → writeDir. */\n userDir?: string;\n}\n\nexport async function loadMemory(\n fs: IFilesystem,\n dir: string | string[],\n opts: LoadMemoryOpts = {},\n): Promise<{ index: string; tools: AgentTool[] }> {\n const dirs = (Array.isArray(dir) ? dir : [dir]).filter(Boolean);\n const writeDir = dirs[0]; // writes go to first (project) scope\n const tools = [recallTool(fs, dirs), rememberTool(fs, writeDir, opts), memorySearchTool(fs, dirs)];\n\n // Merge pointers from all dirs' MEMORY.md files (dedup by slug, first wins).\n const allPointers: string[] = [];\n const seenSlugs = new Set<string>();\n let header = '';\n let hasContent = false;\n for (const d of dirs) {\n const indexPath = `${d}/MEMORY.md`;\n const md = (await fs.exists(indexPath)) ? (await fs.readFile(indexPath)).trim() : '';\n if (!md) continue;\n hasContent = true;\n const lines = md.split('\\n');\n if (!header) header = lines.filter((l) => !/^\\s*-\\s*\\[.+\\]\\(.+\\.md\\)/.test(l)).join('\\n').trim();\n for (const l of lines.filter((l) => /^\\s*-\\s*\\[.+\\]\\(.+\\.md\\)/.test(l))) {\n const slug = l.match(/\\]\\(([^)]+)\\.md\\)/)?.[1];\n if (slug && !seenSlugs.has(slug)) { seenSlugs.add(slug); allPointers.push(l); }\n }\n }\n\n // Always inject behavioral guidance — even for empty dirs, so the model knows HOW to create memories.\n if (!hasContent) return { index: MEMORY_PROMPT, tools };\n\n const { kept, rest } = topByRelevance(allPointers, opts.relevanceHint ?? '', (l) => l, opts.max ?? MAX_INDEX);\n const restSlugs = rest.map((l) => l.match(/\\]\\(([^)]+)\\.md\\)/)?.[1] ?? l.match(/\\[([^\\]]+)\\]/)?.[1] ?? '').filter(Boolean);\n\n const index =\n MEMORY_PROMPT + '\\n\\n' +\n '## Memory index (persistent context — recalled across sessions)\\n' +\n (header ? header + '\\n' : '') +\n kept.join('\\n') +\n (restSlugs.length ? `\\n- (${restSlugs.length} more learnings, slugs only — call \\`Recall\\` if relevant): ${restSlugs.join(', ')}` : '');\n return { index, tools };\n}\n\n/** Slugify free text into a safe kebab filename stem (no separators, bounded). */\nexport function slugify(s: string, fallback = 'note'): string {\n const base = String(s ?? '')\n .trim()\n .toLowerCase()\n .replace(/\\.md$/i, '')\n .replace(/[^\\w\\s-]/g, '')\n .replace(/[\\s_]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 48);\n return base || fallback;\n}\n\n/**\n * Persist a durable fact: write `<dir>/<slug>.md` and ensure a one-line pointer exists in\n * `<dir>/MEMORY.md` (created if missing). Idempotent on the index (won't duplicate a pointer).\n * This is the shared write path behind the `Remember` tool and automatic lesson capture.\n */\nexport async function writeFact(fs: IFilesystem, dir: string, slug: string, body: string, opts?: { type?: string; description?: string }): Promise<void> {\n await mkdirp(fs, dir);\n const content = opts?.type ? `---\\ntype: ${opts.type}\\n---\\n\\n${body}` : body;\n await fs.writeFile(`${dir}/${slug}.md`, content.endsWith('\\n') ? content : content + '\\n');\n const indexPath = `${dir}/MEMORY.md`;\n const idx = (await fs.exists(indexPath)) ? await fs.readFile(indexPath) : '# Memory Index\\n';\n const summary = opts?.description || body.split('\\n')[0].slice(0, 80);\n const line = `- [${slug}](${slug}.md) — ${summary}`;\n const lines = idx.split('\\n');\n const at = lines.findIndex((l) => l.includes(`(${slug}.md)`));\n if (at >= 0) {\n if (lines[at] !== line) { lines[at] = line; await fs.writeFile(indexPath, lines.join('\\n')); }\n } else {\n await fs.writeFile(indexPath, idx.replace(/\\s*$/, '') + `\\n${line}\\n`);\n }\n // Enforce index cap: drop oldest pointers when over limit (fact files survive — still Recall-able/searchable).\n await truncateIndex(fs, indexPath);\n}\n\nasync function truncateIndex(fs: IFilesystem, path: string): Promise<void> {\n const raw = await fs.readFile(path);\n if (raw.length <= MAX_INDEX_BYTES) {\n const count = raw.split('\\n').filter((l) => /^\\s*-\\s*\\[.+\\]\\(.+\\.md\\)/.test(l)).length;\n if (count <= MAX_INDEX_LINES) return;\n }\n const lines = raw.split('\\n');\n const pointerIdxs: number[] = [];\n for (let i = 0; i < lines.length; i++) if (/^\\s*-\\s*\\[.+\\]\\(.+\\.md\\)/.test(lines[i])) pointerIdxs.push(i);\n // Drop oldest (topmost) pointers until under both caps.\n const drop = new Set<number>();\n for (const pi of pointerIdxs) {\n const candidate = lines.filter((_, i) => !drop.has(i)).join('\\n');\n if (candidate.length <= MAX_INDEX_BYTES && pointerIdxs.length - drop.size <= MAX_INDEX_LINES) break;\n drop.add(pi);\n }\n if (drop.size) await fs.writeFile(path, lines.filter((_, i) => !drop.has(i)).join('\\n'));\n}\n\n/** Sanitize a slug: strip .md suffix, normalize path separators, block traversal. */\nfunction cleanSlug(raw: string): string {\n let s = String(raw ?? '').trim().replace(/\\.md$/i, '').replace(/\\\\/g, '/').replace(/\\/+/g, '/').replace(/^\\/|\\/$/g, '');\n while (s.includes('..')) s = s.replace(/\\.\\./g, '');\n return s;\n}\n\n/** Recursively list all fact slugs in the memory dir (relative paths without .md, excluding MEMORY.md). */\nasync function listSlugs(fs: IFilesystem, dir: string, prefix = ''): Promise<string[]> {\n let entries: string[];\n try { entries = await fs.readDir(dir); } catch { return []; }\n const out: string[] = [];\n for (const e of entries.sort()) {\n const full = dir === '/' ? `/${e}` : `${dir}/${e}`;\n const rel = prefix ? `${prefix}/${e}` : e;\n if (await fs.isDirectory(full)) out.push(...await listSlugs(fs, full, rel));\n else if (e.endsWith('.md') && e !== 'MEMORY.md') out.push(rel.replace(/\\.md$/, ''));\n }\n return out;\n}\n\n/** Load a single fact by slug; strips YAML frontmatter before returning. Returns null if not found. */\nasync function loadFact(fs: IFilesystem, dir: string, slug: string): Promise<string | null> {\n const path = `${dir}/${slug}.md`;\n try {\n const raw = await fs.readFile(path);\n const { body } = splitFrontmatter(raw);\n return body || raw;\n } catch { return null; }\n}\n\n/** Try loading a fact from multiple dirs (first hit wins). */\nasync function loadFactMulti(fs: IFilesystem, dirs: string[], slug: string): Promise<string | null> {\n for (const d of dirs) { const r = await loadFact(fs, d, slug); if (r != null) return r; }\n return null;\n}\n\n/** List all slugs across multiple dirs (deduped, first wins). */\nasync function listSlugsMulti(fs: IFilesystem, dirs: string[]): Promise<string[]> {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const d of dirs) for (const s of await listSlugs(fs, d)) if (!seen.has(s)) { seen.add(s); out.push(s); }\n return out;\n}\n\n/** A `Recall` tool that loads memory facts by slug — single, batch, or pattern. */\nfunction recallTool(fs: IFilesystem, dirs: string[]): AgentTool {\n return {\n name: 'Recall',\n description: 'Load memory facts by slug. Pass `slug` for one, `slugs` for several, or `pattern` (glob like \"auth*\") to match. Returns full bodies, separated by `--- slug ---` headers.',\n parameters: {\n type: 'object',\n properties: {\n slug: { type: 'string', description: 'single fact slug (filename without .md)' },\n slugs: { type: 'array', items: { type: 'string' }, description: 'multiple slugs to load at once' },\n pattern: { type: 'string', description: 'glob pattern to match against slugs (e.g. \"auth*\", \"*database*\")' },\n },\n },\n async run({ slug, slugs, pattern }, ctx: ToolContext) {\n let targets: string[] = [];\n if (slug) targets = [cleanSlug(slug)];\n else if (Array.isArray(slugs)) targets = slugs.map(cleanSlug).filter(Boolean);\n else if (pattern) {\n const escaped = String(pattern).replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp('^' + escaped.replace(/\\*/g, '.*').replace(/\\?/g, '.') + '$', 'i');\n targets = (await listSlugsMulti(fs, dirs)).filter((s) => re.test(s));\n }\n if (!targets.length) return `Error: no slugs resolved. Pass slug, slugs, or pattern.`;\n const parts: string[] = [];\n for (const s of targets.slice(0, 20)) {\n const body = await loadFactMulti(fs, dirs, s);\n if (body != null) parts.push(targets.length > 1 ? `--- ${s} ---\\n${body}` : body);\n else parts.push(targets.length > 1 ? `--- ${s} ---\\n[not found]` : `Error: no memory fact '${s}'.`);\n }\n if (targets.length > 20) parts.push(`(${targets.length - 20} more matched — narrow the pattern)`);\n return parts.join('\\n\\n');\n },\n };\n}\n\n/** Search across all memory fact files by content. Returns slug + matching snippet pairs, ranked by relevance. */\nfunction memorySearchTool(fs: IFilesystem, dirs: string[]): AgentTool {\n return {\n name: 'MemorySearch',\n description:\n 'Search memory facts by content — find relevant memories when you don\\'t know the exact slug. Returns up to 10 matching slug + snippet pairs, ranked by relevance. Use `regex: true` for regex patterns.',\n parameters: {\n type: 'object',\n required: ['query'],\n properties: {\n query: { type: 'string', description: 'search query (keywords or regex pattern)' },\n regex: { type: 'boolean', description: 'treat query as a regex pattern (default: false)' },\n },\n },\n async run({ query, regex }, ctx: ToolContext) {\n const q = String(query ?? '').trim();\n if (!q) return 'Error: empty query.';\n const slugs = await listSlugsMulti(fs, dirs);\n if (!slugs.length) return '(no memory facts found)';\n let matcher: (line: string) => boolean;\n if (regex) {\n try { const re = new RegExp(q, 'i'); matcher = (l) => re.test(l); } catch (e) { return `Error: invalid regex: ${e}`; }\n } else {\n const lower = q.toLowerCase();\n matcher = (l) => l.toLowerCase().includes(lower);\n }\n const loaded: { slug: string; body: string }[] = [];\n for (const slug of slugs) {\n const body = await loadFactMulti(fs, dirs, slug);\n if (body) loaded.push({ slug, body });\n }\n const idf = idfWeights(loaded.map((l) => l.body));\n const qTokens = tokenize(q);\n const hits: { slug: string; snippet: string; score: number }[] = [];\n for (const { slug, body } of loaded) {\n const lines = body.split('\\n');\n const matchLine = lines.find(matcher);\n if (!matchLine && !relevanceScore(body, qTokens, idf)) continue;\n const snippet = matchLine?.trim().slice(0, 120) || lines.find((l) => l.trim())?.trim().slice(0, 120) || '';\n hits.push({ slug, snippet, score: relevanceScore(body, qTokens, idf) });\n }\n if (!hits.length) return '(no matches)';\n hits.sort((a, b) => b.score - a.score);\n return hits.slice(0, 10).map((h) => `${h.slug}: ${h.snippet}`).join('\\n');\n },\n };\n}\n\n/** A `Remember` tool: persist a durable fact + index pointer so it's recalled in future sessions. */\nfunction rememberTool(fs: IFilesystem, dir: string, memOpts: LoadMemoryOpts = {}): AgentTool {\n const maxWrites = memOpts.maxWritesPerSession ?? 25;\n let writes = 0;\n return {\n name: 'Remember',\n description:\n 'Persist a durable fact for future sessions (a fix you found, a gotcha, a project constraint). Adds a pointer to the Memory index and stores the body. Use sparingly — only genuinely reusable knowledge, not task-specific scratch.',\n parameters: {\n type: 'object',\n required: ['fact'],\n properties: {\n fact: { type: 'string', description: 'the durable fact to remember (one or more lines)' },\n slug: { type: 'string', description: 'optional kebab-case id; derived from the fact if omitted' },\n type: { type: 'string', enum: ['user', 'feedback', 'project', 'reference'], description: 'memory category (user/feedback/project/reference)' },\n description: { type: 'string', description: 'one-line summary for the memory index (≤80 chars)' },\n },\n },\n async run({ fact, slug, type, description }, ctx: ToolContext) {\n const body = String(fact ?? '').trim();\n if (!body) return `Error: nothing to remember (empty fact).`;\n if (++writes > maxWrites) return `Rate limit: too many memories this session (${maxWrites}). Only persist genuinely durable facts.`;\n const name = slugify(slug || body.split('\\n')[0]);\n // Route by type: user/feedback → user scope (global); project/reference → project scope.\n const isGlobal = (type === 'user' || type === 'feedback') && memOpts.userDir;\n const targetDir = isGlobal ? memOpts.userDir! : dir;\n await writeFact(fs, targetDir, name, body, { type, description });\n memOpts.onMemorySaved?.(name, type);\n return `Remembered '${name}' (recallable in future sessions).`;\n },\n };\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\n\nconst DEFAULT_NAMES = ['AGENT.md', 'AGENTS.md', 'CLAUDE.md'];\n\n/**\n * Walk the VFS directory tree from `/` down, collecting instruction files\n * (AGENT.md, AGENTS.md, CLAUDE.md, .claude/<name>) at each level.\n * Merges all found files general-first → specific-last (mirrors Claude Code's\n * hierarchical CLAUDE.md discovery). First matching filename per directory wins\n * (no duplicates from the same level). Edge-portable: works over any IFilesystem.\n */\nexport async function loadInstructions(\n fs: IFilesystem,\n names: string[] = DEFAULT_NAMES,\n): Promise<string> {\n // First matching name wins (AGENT.md > AGENTS.md > CLAUDE.md).\n // Both root and .claude/ locations are checked for the winning name — anchored at the FS\n // working dir (in CC-parity disk mode root '/' is the real machine, so instructions live\n // under the launch dir, not '/'). With cwd '/' this is the original behavior.\n const cwd = fs.getCwd();\n const base = cwd === '/' ? '' : cwd;\n for (const name of names) {\n const sections: string[] = [];\n for (const path of [`${base}/${name}`, `${base}/.claude/${name}`]) {\n if (!(await fs.exists(path))) continue;\n const md = (await fs.readFile(path)).trim();\n if (md) sections.push(`<!-- ${path} -->\\n${md}`);\n }\n if (sections.length) {\n return `## Project instructions\\nRepository-specific instructions — follow them.\\n\\n${sections.join('\\n\\n---\\n\\n')}`;\n }\n }\n return '';\n}\n","import { mkdirSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike, Message } from './llm';\nimport type { AgentTool, ToolContext } from './tools';\nimport { toolsByName } from './tools';\nimport { resolveModelAlias } from './models';\nimport type { AgentDef } from './agents';\nimport type { Hooks } from './hooks';\nimport { Agent, type RunResult } from './Agent';\nimport { OverlayFilesystem } from './OverlayFilesystem';\nimport { findGitRoot, getOrCreateWorktree, cleanupWorktree } from './worktree';\nimport { NodeDiskFilesystem } from './NodeDiskFilesystem';\nimport { forComponent } from './logging';\n\nconst log = forComponent('subagent');\n\n/** Run items through `fn` with at most `limit` in flight, preserving result order. */\nasync function boundedPool<T, R>(items: T[], limit: number, fn: (item: T, i: number) => Promise<R>): Promise<R[]> {\n const out = new Array<R>(items.length);\n let next = 0;\n const worker = async () => { while (next < items.length) { const i = next++; out[i] = await fn(items[i], i); } };\n await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, worker));\n return out;\n}\n\nexport interface TaskToolOptions {\n /** The same ai.libx.js client the parent uses — the child shares it. */\n ai: ChatLike;\n model: string;\n /** The filesystem the child operates over (jail/scope it before passing, if desired). */\n fs: IFilesystem;\n /** Step budget for the child run (independent of the parent's). */\n maxSteps?: number;\n /** Recursion depth of the child this tool would spawn (0 = first level). */\n depth?: number;\n /** Hard ceiling on nesting — beyond this the tool refuses to spawn. */\n maxDepth?: number;\n /** Named subagent types selectable via the `agentType` param (persona + model + scoped tools). */\n agents?: AgentDef[];\n /** Max children running concurrently in a `TaskBatch` (default 4). */\n maxParallel?: number;\n /** Parent hooks — `onSubagentStop` fires with each child's summary when it finishes. */\n hooks?: Hooks;\n /**\n * Wall-clock ceiling for ONE child run, in ms (default `SUBAGENT_MAX_DURATION_MS`). `maxSteps` alone is\n * not a bound: 25 steps x a 600s Shell is ~250 minutes, far past any transport deadline wrapping the\n * parent — and an undeclared tool cannot be named by `toolTimeoutViolations`. This deadline is ENFORCED\n * (the child's signal is aborted) and therefore honestly declarable as the tool's `maxDurationMs`.\n */\n maxDurationMs?: number;\n /** The parent's toolbelt — the child INHERITS it by default (otherwise it falls back to the jailed\n * `defaultTools()` and loses everything the host injected: a real shell, Write/Grep, MCP tools).\n * An agentType def's `tools` allowlist still narrows it (and can name one of these by name). */\n tools?: AgentTool[];\n /** The parent's system prompt — inherited by a plain (untyped) child so it keeps the host's persona\n * instead of reverting to agentx's generic built-in one. An agentType def's body overrides it. */\n systemPrompt?: string;\n /** Provider-specific options for the CHILD's model, recomputed per child (IoC — same seam duplex uses\n * for its workers). The child's model may differ from the parent's (explicit `model` / agentType def),\n * and provider options are NOT portable across providers (cursor `cwd`/`cursorSession` on anthropic\n * is a hard 400), so they are derived, never blindly inherited. */\n providerOptionsFor?: (model: string) => Record<string, unknown> | undefined;\n /** Origin-anchored real-disk dir for child transcript traces (see `AgentOptions.traceDir`). Passed\n * down UNCHANGED to nested children so every level writes to the same origin `.agent`. */\n traceDir?: string;\n}\n\n/** Default wall-clock ceiling for one child run (30 min) — the bound `Task`/`TaskBatch` declare and enforce. */\nexport const SUBAGENT_MAX_DURATION_MS = 1_800_000;\n\n/** A child-scoped abort signal that fires on the PARENT's abort or after `ms`, whichever comes first.\n * `timedOut()` distinguishes the two so the tool result can say which happened. Always `dispose()`. */\nfunction wallClock(parent: AbortSignal | undefined, ms: number): { signal: AbortSignal; timedOut: () => boolean; dispose: () => void } {\n const ac = new AbortController();\n let fired = false;\n const onParent = () => ac.abort();\n const timer = setTimeout(() => { fired = true; ac.abort(); }, ms);\n if (parent) { if (parent.aborted) ac.abort(); else parent.addEventListener('abort', onParent, { once: true }); }\n return {\n signal: ac.signal,\n timedOut: () => fired,\n dispose: () => { clearTimeout(timer); parent?.removeEventListener('abort', onParent); },\n };\n}\n\n/** Appended to a timed-out child's hint so 'aborted' isn't misread as a user interrupt. */\nconst deadlineNote = (ms: number) =>\n `\\n[It was stopped by the sub-task wall-clock deadline of ${Math.round(ms / 1000)}s — not by the user. `\n + `Re-delegate a NARROWER sub-task (or continue from the trace); the same prompt will hit the same deadline again.]`;\n\ntype WorktreeHandle = { repoRoot: string; slug: string; worktreePath: string; branch: string };\n\nfunction sanitizeSlug(raw: string): string {\n return raw.replace(/[^a-zA-Z0-9._-]/g, '-').replace(/-+/g, '-').slice(0, 40);\n}\n\nfunction createWorktreeFs(cwd: string, label: string, index: number): WorktreeHandle | string {\n const repoRoot = findGitRoot(cwd);\n if (!repoRoot) return 'isolation: \"worktree\" requires a git repository';\n const slug = `sub-${index}-${sanitizeSlug(label)}`;\n try {\n const info = getOrCreateWorktree(repoRoot, slug);\n return { repoRoot, slug, worktreePath: info.worktreePath, branch: info.branch };\n } catch (e) { return `worktree creation failed: ${e instanceof Error ? e.message : String(e)}`; }\n}\n\nfunction releaseWorktree(handle: WorktreeHandle): { removed: boolean; reason?: string } {\n return cleanupWorktree(handle.repoRoot, handle.slug, { force: true });\n}\n\n/** Re-bind inherited tools that escape the VFS (the real `Shell`) to the child's own real-disk root.\n * The child inherits the parent's tool INSTANCES; a cwd-bound shell would otherwise run in the PARENT\n * repo while the child's fs points at its worktree — writing uncommitted files into the parent tree\n * which the worktree teardown then force-removes. Tools with no `withCwd` pass through unchanged; a\n * `withCwd` returning `undefined` means \"this capability cannot leave the parent\" and the tool is\n * DROPPED (the `ShellOutput`/`ShellStatus`/`ShellKill` job companions, which are bound to the\n * parent's registry — an isolated child must not read or SIGTERM the parent's background jobs). */\nfunction rebindTools(tools: AgentTool[] | undefined, root?: string): AgentTool[] | undefined {\n if (!tools || !root) return tools;\n return tools.flatMap((t) => {\n if (!t.withCwd) return [t];\n const rebound = t.withCwd(root);\n return rebound ? [rebound] : [];\n });\n}\n\nfunction worktreePromptPrefix(branch: string): string {\n return `You are running in an isolated git worktree on branch \"${branch}\". ` +\n 'When you finish making changes, commit them with a clear message before replying with your summary. ' +\n 'Your worktree will be removed after you finish — only committed work survives (on the branch).\\n\\n';\n}\n\n// ── Subagent tracing ──────────────────────────────────────────────────────────────────────────────\n// A child's transcript is otherwise ephemeral (only its final summary returns to the parent). We stream\n// it to a real-disk file under the ORIGIN's trace dir — bypassing the child's (possibly overlay/worktree)\n// fs on purpose, so the trace survives interruption AND worktree teardown. On a non-`stop` finish the tool\n// result becomes a STATUS HINT pointing here, instead of a dangling tool_call.\n\ninterface TraceMeta { label: string; agentType?: string; prompt: string }\n\nlet traceSeq = 0; // process-unique → no same-millisecond collisions across concurrent TaskBatch children\n\nfunction traceFileFor(dir: string, label: string, depth: number): string | undefined {\n try {\n mkdirSync(dir, { recursive: true });\n const id = `${Date.now().toString(36)}-${(traceSeq++).toString(36)}`;\n return join(dir, `${id}-d${depth}-${sanitizeSlug(label) || 'sub'}.json`);\n } catch (e) {\n log.warn(`subagent trace dir unavailable (${dir}) — running without a trace: ${e instanceof Error ? e.message : String(e)}`);\n return undefined; // tracing is best-effort infra; never block a delegation on it\n }\n}\n\nfunction flushTrace(file: string, meta: TraceMeta, messages: Message[], status: string): void {\n try {\n writeFileSync(file, JSON.stringify({ ...meta, status, updated: Date.now(), messages }, null, 2));\n } catch (e) {\n log.warn(`subagent trace flush failed (${file}): ${e instanceof Error ? e.message : String(e)}`);\n }\n}\n\n/** Wrap the child's host so each step boundary (`turn_start`) flushes the committed-so-far transcript. */\nfunction installTrace(child: Agent, file: string, meta: TraceMeta): void {\n const prev = child.options.host;\n child.options.host = {\n ...prev,\n notify: (e) => {\n if (e.kind === 'turn_start') flushTrace(file, meta, child.transcript, 'running');\n prev?.notify?.(e);\n },\n };\n}\n\n/** The tool result for a child that did NOT finish cleanly: status + what it got through + trace pointer\n * + an explicit decision prompt. Doubles as the back-fill that keeps the parent transcript valid (no\n * orphan tool_call) when an in-flight child is aborted. */\nfunction abortHint(label: string, res: RunResult, file?: string): string {\n const last = (res.text || '').trim().slice(0, 500);\n const lines = [\n `[sub-task '${label}' did NOT finish — ${res.finishReason} after ${res.steps} step(s). Treat its work as INCOMPLETE.]`,\n last ? `Progress so far: ${last}` : 'It produced no summary before stopping.',\n ];\n if (file) lines.push(`Full transcript (every step it took): ${file} — Read it to see what was actually done.`);\n lines.push(\"Decide: ignore it, re-delegate a fresh Task that continues from the trace, or start over. Do NOT assume the sub-task completed.\");\n return lines.join('\\n');\n}\n\n/** Run one child to completion with tracing + (on a non-clean finish) a status hint. The child inherits\n * the parent's abort `signal`, so Esc/Ctrl-C actually interrupts it — and the partial trace + hint are\n * what the parent picks up. `onSubagentStop` fires with whatever result (summary OR hint) the parent gets. */\nasync function runChildTraced(args: {\n opts: TaskToolOptions; childOpts: NonNullable<ConstructorParameters<typeof Agent>[0]>;\n prompt: string; label: string; agentType?: string; childDepth: number; signal?: AbortSignal;\n}): Promise<{ res: RunResult; result: string }> {\n const { opts, label, agentType, prompt } = args;\n const deadlineMs = opts.maxDurationMs ?? SUBAGENT_MAX_DURATION_MS;\n // ENFORCED wall clock. The child's own `timeoutMs` is an IDLE clock (it resets on every productive\n // step), so a busy child has no total bound at all — `maxSteps` x a 600s Shell runs for hours. This is\n // the bound the tool declares, so it has to actually fire.\n const wc = wallClock(args.signal, deadlineMs);\n args.childOpts.signal = wc.signal; // propagate cancellation → child stops with the parent, or with the deadline\n const file = opts.traceDir ? traceFileFor(opts.traceDir, label, args.childDepth) : undefined;\n const meta: TraceMeta = { label, agentType, prompt };\n const child = new Agent(args.childOpts);\n if (file) installTrace(child, file, meta);\n let res: RunResult;\n try { res = await child.run(prompt); } finally { wc.dispose(); }\n if (file) flushTrace(file, meta, child.transcript, wc.timedOut() ? 'deadline' : res.finishReason);\n let result = res.finishReason === 'stop'\n ? (res.text || `(child '${label}' finished with no summary; finishReason=${res.finishReason})`)\n : abortHint(label, res, file);\n if (wc.timedOut()) { log.warn(`sub-task '${label}' hit its ${deadlineMs}ms wall-clock deadline (steps=${res.steps})`); result += deadlineNote(deadlineMs); }\n await opts.hooks?.onSubagentStop?.(result, { label, agentType });\n return { res, result };\n}\n\n/** Resolve the constructor opts for one child agent (persona/model/tool scoping). Returns an error string on bad agentType. */\nfunction childOptionsFor(opts: TaskToolOptions, fs: IFilesystem, depth: number, maxDepth: number, agentType?: string, model?: string, root?: string): NonNullable<ConstructorParameters<typeof Agent>[0]> | string {\n let def: AgentDef | undefined;\n if (agentType) {\n def = (opts.agents ?? []).find((a) => a.name === agentType);\n if (!def) return `no subagent type '${agentType}'. Available: ${(opts.agents ?? []).map((a) => a.name).join(', ') || '(none defined)'}`;\n }\n // Model precedence: explicit per-invocation > agentType def > parent. Alias resolution happens HERE,\n // on the one seam every child model flows through — `loadAgents` deliberately keeps frontmatter raw.\n const childModel = resolveModelAlias(model || def?.model || opts.model);\n const childOpts: ConstructorParameters<typeof Agent>[0] = { ai: opts.ai, fs, model: childModel, subagents: true, depth: depth + 1, maxDepth, traceDir: opts.traceDir };\n if (opts.maxSteps != null) childOpts.maxSteps = opts.maxSteps;\n // Persona: a def's body overrides; otherwise inherit the parent's (a plain Task child used to fall\n // back to agentx's generic built-in prompt, losing the host's whole operating context).\n const childPrompt = def?.systemPrompt ?? opts.systemPrompt;\n if (childPrompt) childOpts.systemPrompt = childPrompt;\n // Toolbelt: inherit the parent's; a def's allowlist narrows it (resolved against the parent's tools\n // first, so it can name a host-injected/MCP tool, then the built-in registry).\n const inherited = rebindTools(opts.tools, root);\n if (def?.tools?.length) {\n try { childOpts.tools = toolsByName(def.tools, inherited); }\n catch (e) { return `subagent '${agentType}' declares an unknown tool — ${(e as Error).message}`; }\n } else if (inherited?.length) {\n childOpts.tools = inherited;\n }\n const po = opts.providerOptionsFor?.(childModel);\n if (po) childOpts.providerOptions = po;\n // Gate: the host's `preToolUse` guard applies to the child too. Only that one hook is inherited —\n // it is a SECURITY boundary (shraga-ee blocks reading secret files with it), and a child that now\n // inherits the parent's real toolbelt would otherwise be a one-line bypass for it. The observer /\n // lifecycle hooks stay parent-only on purpose: a child firing `onStop`/`onSessionStart` would\n // fabricate session events in the host's UI, and `onSubagentStop` already fires from the parent.\n if (opts.hooks?.preToolUse) childOpts.hooks = { preToolUse: opts.hooks.preToolUse.bind(opts.hooks) };\n return childOpts;\n}\n\n/**\n * `Task` tool — spawn a CHILD agent over the same VFS with its own step budget,\n * returning only its final summary to the parent. Use to fan out a self-contained\n * sub-task (search, refactor a subtree) without polluting the parent's context.\n * @returns the child's final text, or an error string if the depth limit is reached.\n */\nexport function makeTaskTool(opts: TaskToolOptions): AgentTool {\n const depth = opts.depth ?? 0;\n const maxDepth = opts.maxDepth ?? 2;\n return {\n name: 'Task',\n description:\n 'Delegate a self-contained sub-task to a child agent over the same filesystem. It runs autonomously with its own step budget and a wall-clock deadline, and returns a concise summary — use to isolate context-heavy work (broad search, a scoped refactor). Provide a short `description` and a full `prompt`. If it is interrupted or fails, the result is a STATUS HINT with a pointer to its full transcript (Read it to recover what it did, then decide whether to continue or restart) — do not assume an incomplete sub-task succeeded. Set `background: true` to run it detached (returns a job id to poll with JobOutput while you keep working); its VFS file edits are overlay-isolated and commit when it finishes — but a child that uses the real `Shell` writes straight to the working tree (an overlay cannot isolate a real process), so pair shell-heavy work with `isolation: \"worktree\"`. Set `isolation: \"worktree\"` to run in a real git worktree (needed when the child uses real shell commands that must see/modify actual files — its shell is re-bound to the worktree — keeping any name your host gave it — and background shell jobs, including inspecting or killing MINE, are unavailable there) — slower (~200ms setup), auto-cleaned if no changes. The child inherits YOUR tools and system prompt by default (and is subject to the same tool-use gate); pass `model` to run this one sub-task on a different model (e.g. a cheap one for bulk search, a stronger one for hard reasoning) — it overrides the agentType default.',\n parameters: {\n type: 'object',\n required: ['description', 'prompt'],\n properties: {\n description: { type: 'string', description: 'a short (3-5 word) label for the sub-task' },\n prompt: { type: 'string', description: 'the full instructions the child agent should carry out' },\n agentType: { type: 'string', description: 'optional named subagent type (its persona, model, and scoped tools) — see the catalog' },\n model: { type: 'string', description: 'optional model for THIS sub-task (alias like \"haiku\"/\"opus\"/\"sonnet\", or a full id). Overrides the agentType default; otherwise the child runs on your model.' },\n background: { type: 'boolean', description: 'run detached (overlay-isolated, commits on finish); returns a job id to poll with JobOutput instead of blocking' },\n isolation: { type: 'string', enum: ['overlay', 'worktree'], description: 'isolation mode: \"overlay\" (default, VFS layer) or \"worktree\" (real git worktree for shell-heavy work)' },\n },\n },\n // Declared because it is ENFORCED (see runChildTraced) — a transport above the loop sizes its own\n // deadline around this one (AgentTool.maxDurationMs). Declaring an unenforced number would be a lie;\n // declaring nothing left `Task` invisible to toolTimeoutViolations, which is the same hole.\n maxDurationMs: opts.maxDurationMs ?? SUBAGENT_MAX_DURATION_MS,\n maxDurationEnforced: true, // the wall clock below ABORTS the child at this bound — it cannot be overrun, so the transport needs slack, not a doubling\n\n async run({ description, prompt, agentType, model, background, isolation }, ctx: ToolContext) {\n if (depth >= maxDepth) {\n return `Error: Task depth limit reached (maxDepth ${maxDepth}). Cannot spawn another child agent — do this work directly instead.`;\n }\n const label = String(description ?? agentType ?? 'sub-task');\n\n const useWorktree = isolation === 'worktree';\n\n // Background: run the child detached over an isolated overlay via the job registry. This is where\n // sandbox backgrounding actually pays off — a child does real model calls, so it overlaps the parent.\n if (background && ctx.jobs) {\n const id = ctx.jobs.start(async ({ signal }) => {\n let fs: IFilesystem; let commit: () => Promise<void>; let wtHandle: WorktreeHandle | undefined;\n if (useWorktree) {\n const h = createWorktreeFs(process.cwd(), label, 0);\n if (typeof h === 'string') throw new Error(h);\n wtHandle = h; fs = new NodeDiskFilesystem(h.worktreePath); commit = async () => {};\n } else {\n const overlay = new OverlayFilesystem(opts.fs);\n fs = overlay; commit = () => overlay.commit();\n }\n const childOpts = childOptionsFor(opts, fs, depth, maxDepth, agentType, model, wtHandle?.worktreePath);\n if (typeof childOpts === 'string') throw new Error(childOpts);\n const childPrompt = wtHandle ? worktreePromptPrefix(wtHandle.branch) + String(prompt ?? '') : String(prompt ?? '');\n const { res, result } = await runChildTraced({ opts, childOpts, prompt: childPrompt, label, agentType, childDepth: depth + 1, signal });\n // Aborted before commit → don't merge partial edits, but DO return the hint+trace (the parent\n // can read what it did and decide), instead of the old opaque '[killed before commit]'.\n if (res.finishReason === 'aborted' || signal.aborted) { wtHandle && releaseWorktree(wtHandle); return result; }\n await commit();\n let summary = result;\n if (wtHandle) {\n const r = releaseWorktree(wtHandle);\n if (!r.removed) summary += `\\n\\n[worktree removal failed: ${r.reason}]`;\n }\n return summary;\n }, { kind: 'agent', label });\n return `Started background sub-task ${id} ('${label}') — poll with JobOutput({id:\"${id}\"}).`;\n }\n\n // Foreground: the child runs inline. Worktree isolation gives it a real disk fs; overlay keeps VFS.\n let fs: IFilesystem; let wtHandle: WorktreeHandle | undefined;\n if (useWorktree) {\n const h = createWorktreeFs(process.cwd(), label, 0);\n if (typeof h === 'string') return `Error: ${h}`;\n wtHandle = h; fs = new NodeDiskFilesystem(h.worktreePath);\n } else {\n fs = opts.fs;\n }\n const childOpts = childOptionsFor(opts, fs, depth, maxDepth, agentType, model, wtHandle?.worktreePath);\n if (typeof childOpts === 'string') { wtHandle && releaseWorktree(wtHandle); return `Error: ${childOpts}`; }\n try {\n const childPrompt = wtHandle ? worktreePromptPrefix(wtHandle.branch) + String(prompt ?? '') : String(prompt ?? '');\n // ctx.signal carries the parent's Esc/Ctrl-C → the child now actually stops with the parent\n // (it previously ran to completion, ignoring the interrupt). On stop we get the trace + hint.\n const { result } = await runChildTraced({ opts, childOpts, prompt: childPrompt, label, agentType, childDepth: depth + 1, signal: ctx.signal });\n let summary = result;\n if (wtHandle) {\n const r = releaseWorktree(wtHandle);\n if (!r.removed) summary += `\\n\\n[worktree removal failed: ${r.reason}]`;\n }\n return summary;\n } catch (e) {\n if (wtHandle) releaseWorktree(wtHandle);\n throw e;\n }\n },\n };\n}\n\n/**\n * `TaskBatch` tool — fan out several self-contained sub-tasks to child agents that run\n * **concurrently** (bounded pool), returning all their summaries together. Each child runs over its\n * OWN `OverlayFilesystem` (write-isolated from siblings), and successful children's edits are\n * committed **in array order** afterward — so concurrent writes resolve deterministically\n * (last index wins) instead of racing. Use to parallelize independent work (review N files, search M\n * subtrees, scoped refactors). For a single sub-task, use `Task`.\n */\nexport function makeTaskBatchTool(opts: TaskToolOptions): AgentTool {\n const depth = opts.depth ?? 0;\n const maxDepth = opts.maxDepth ?? 2;\n const maxParallel = opts.maxParallel ?? 4;\n return {\n name: 'TaskBatch',\n description:\n 'Delegate SEVERAL independent sub-tasks to child agents that run concurrently; returns all their summaries. Each child is write-isolated at the VFS level (its file edits are merged back in array order); real `Shell` commands are NOT — use `isolation: \"worktree\"` for those. Use for parallel fan-out (review/search/scoped refactors across files). Provide `tasks: [{ description, prompt, agentType?, model? }]` — each child inherits your tools and system prompt, and `model` runs that one child on a different model. Set `isolation: \"worktree\"` to run each child in its own git worktree (needed for real shell commands) — slower, auto-cleaned if no changes.',\n parameters: {\n type: 'object',\n required: ['tasks'],\n properties: {\n tasks: {\n type: 'array',\n description: 'the sub-tasks to run in parallel',\n items: {\n type: 'object',\n required: ['description', 'prompt'],\n properties: {\n description: { type: 'string', description: 'a short (3-5 word) label' },\n prompt: { type: 'string', description: 'the full instructions for this child' },\n agentType: { type: 'string', description: 'optional named subagent type' },\n model: { type: 'string', description: 'optional model for this child (alias or full id); overrides the agentType default' },\n },\n },\n },\n isolation: { type: 'string', enum: ['overlay', 'worktree'], description: 'isolation mode for ALL children: \"overlay\" (default) or \"worktree\" (real git worktree each)' },\n },\n },\n // Same enforced bound as `Task`, applied to the WHOLE batch (below), not per child — otherwise the\n // honest ceiling would be ceil(n/maxParallel) x the per-child deadline, i.e. unbounded in `tasks`.\n maxDurationMs: opts.maxDurationMs ?? SUBAGENT_MAX_DURATION_MS,\n maxDurationEnforced: true, // the wall clock below ABORTS the child at this bound — it cannot be overrun, so the transport needs slack, not a doubling\n\n async run({ tasks, isolation }, ctx: ToolContext) {\n if (depth >= maxDepth) return `Error: Task depth limit reached (maxDepth ${maxDepth}). Cannot spawn child agents — do this work directly instead.`;\n const list = Array.isArray(tasks) ? tasks : [];\n if (!list.length) return 'Error: TaskBatch needs a non-empty `tasks` array.';\n const useWorktree = isolation === 'worktree';\n const batchDeadlineMs = opts.maxDurationMs ?? SUBAGENT_MAX_DURATION_MS;\n const batchClock = wallClock(ctx.signal, batchDeadlineMs);\n\n type Outcome = { label: string; text?: string; error?: string; overlay?: OverlayFilesystem; wtHandle?: WorktreeHandle; ok: boolean };\n const results = await boundedPool<any, Outcome>(list, maxParallel, async (t, i) => {\n const label = String(t?.description ?? t?.agentType ?? `task ${i + 1}`);\n let fs: IFilesystem; let overlay: OverlayFilesystem | undefined; let wtHandle: WorktreeHandle | undefined;\n if (useWorktree) {\n const h = createWorktreeFs(process.cwd(), label, i);\n if (typeof h === 'string') return { label, error: h, ok: false };\n wtHandle = h; fs = new NodeDiskFilesystem(h.worktreePath);\n } else {\n overlay = new OverlayFilesystem(opts.fs);\n fs = overlay;\n }\n const childOpts = childOptionsFor(opts, fs, depth, maxDepth, t?.agentType, t?.model, wtHandle?.worktreePath);\n if (typeof childOpts === 'string') return { label, error: childOpts, ok: false };\n try {\n const childPrompt = wtHandle ? worktreePromptPrefix(wtHandle.branch) + String(t?.prompt ?? '') : String(t?.prompt ?? '');\n const { res, result } = await runChildTraced({ opts, childOpts, prompt: childPrompt, label, agentType: t?.agentType, childDepth: depth + 1, signal: batchClock.signal });\n // Merge edits for natural completions (incl. max_steps/budget), but NOT a user-cancelled child —\n // signal propagation now makes 'aborted' reachable here; merging its half-done work would be wrong\n // (mirrors the single-Task background path, which skips commit on abort).\n return { label, text: result, overlay, wtHandle, ok: res.finishReason !== 'error' && res.finishReason !== 'aborted' };\n } catch (e) { return { label, error: e instanceof Error ? e.message : String(e), wtHandle, ok: false }; }\n }).finally(() => batchClock.dispose());\n\n // Overlay mode: merge successful children's edits in array order (deterministic last-writer-wins).\n // Worktree mode: force-remove each worktree (committed work survives on the branch).\n const lines: string[] = [];\n for (const r of results) {\n if (r.ok && r.overlay) await r.overlay.commit().catch(() => {});\n let extra = '';\n if (r.wtHandle) {\n const wr = releaseWorktree(r.wtHandle);\n if (!wr.removed) extra = `\\n[worktree removal failed: ${wr.reason}]`;\n }\n lines.push(`### ${lines.length + 1}. ${r.label}\\n${r.error ? `ERROR: ${r.error}` : (r.text || '(no summary)')}${extra}`);\n }\n\n return lines.join('\\n\\n') + (batchClock.timedOut() ? deadlineNote(batchDeadlineMs) : '');\n },\n };\n}\n","/**\n * Model aliasing + mid-conversation switch resolution — pure, dependency-free.\n *\n * Harness-level so every agentx consumer (unclaw, para-chat, …) resolves `[opus]`-style\n * aliases, gates by an allow-list, and announces a switch the same way. Policy (which models\n * a caller may use) and session state (the prior model) stay with the consumer; this module\n * is the shared mechanism.\n */\n\n/** Canonical short aliases → concrete Anthropic model ids. */\nexport const MODEL_ALIASES: Record<string, string> = {\n fable: 'claude-fable-5',\n 'fable-5': 'claude-fable-5',\n opus: 'claude-opus-4-8',\n 'opus-4-8': 'claude-opus-4-8',\n 'opus-4-7': 'claude-opus-4-7',\n 'opus-4-6': 'claude-opus-4-6',\n sonnet: 'claude-sonnet-4-6',\n haiku: 'claude-haiku-4-5-20251001',\n};\n\n/** Resolve an alias to a concrete id. A provider prefix (\"anthropic/\") is preserved; unknown ids pass through. */\nexport function resolveModelAlias(input: string): string {\n const slash = input.indexOf('/');\n const prefix = slash === -1 ? '' : input.slice(0, slash + 1);\n const rest = slash === -1 ? input : input.slice(slash + 1);\n return prefix + (MODEL_ALIASES[rest.toLowerCase()] ?? rest);\n}\n\n/** The provider of a model id (\"cursor/x\" -> \"cursor\"). Provider-specific `providerOptions` are only\n * portable within the same provider — leaking them across is a hard 400.\n *\n * A BARE id is the common case, not the exception: `resolveModelAlias('haiku')` yields\n * `claude-haiku-4-5-20251001` with no prefix (ai.libx.js resolves it fuzzily downstream), so reading\n * only the literal \"/\" made every aliased child look like a provider switch and silently dropped the\n * parent's options. The fix belongs HERE — the alias table must keep emitting the ids ai.libx.js\n * expects, and the comparison is provider identity, not string identity.\n *\n * A bare id we can't attribute is UNKNOWN, not a shared provider: it gets a per-id marker so two\n * different unknown ids never compare equal (returning \"\" for both made them look like one provider\n * and would have leaked one host's options onto the other's model). An unknown id still compares\n * equal to ITSELF, so a child staying on the parent's exact model keeps the parent's options. */\nexport function modelProvider(model: string): string {\n const i = model.indexOf('/');\n if (i !== -1) return model.slice(0, i);\n if (/^claude-/i.test(model)) return 'anthropic';\n return `?${model}`; // unknown: identity-scoped, never equal to a different unknown id\n}\n\n/** Short, human-friendly name for a resolved model id (e.g. \"anthropic/claude-opus-4-8\" → \"opus\"). */\nexport function modelShortLabel(model?: string): string {\n if (!model) return 'default';\n const id = model.split('/').pop()!;\n return id.replace(/^claude-/, '').replace(/-\\d.*$/, '');\n}\n\nexport interface ResolveModelSwitchOpts {\n /** Model requested for this turn (e.g. from an inline directive). Undefined = keep `current`. */\n requested?: string;\n /** The turn's default/current model when nothing is requested. */\n current: string;\n /** The session's prior resolved model — drives change detection + the notice. */\n prior?: string;\n /** If set, `requested` must match one of these (by short label) or it's denied and `current` is kept. */\n allowed?: string[];\n /** Announcement formatter. Default: `_[switching from x to y]_\\n\\n`. */\n format?: (from: string, to: string) => string;\n}\n\nexport interface ModelSwitch {\n /** The model to run this turn. */\n model: string;\n /** True when `requested` was rejected by `allowed` and `model` fell back to `current`. */\n denied: boolean;\n /** Inline notice to surface when the model actually changed vs `prior`, else undefined. */\n notice?: string;\n}\n\n/**\n * Resolve which model a turn runs, given an optional request, an allow-list, and the prior model.\n * Comparisons are by short label so provider-prefixed and dated ids unify\n * (\"anthropic/claude-opus-4-8\" ≡ \"claude-opus-4-8\" ≡ \"opus\").\n */\nexport function resolveModelSwitch(opts: ResolveModelSwitchOpts): ModelSwitch {\n const { requested, current, prior, allowed } = opts;\n if (!requested) return { model: current, denied: false };\n if (allowed && !allowed.some((a) => modelShortLabel(a) === modelShortLabel(requested))) {\n return { model: current, denied: true };\n }\n const fmt = opts.format ?? ((from: string, to: string) => `_[switching from ${from} to ${to}]_\\n\\n`);\n const changed = prior !== undefined && modelShortLabel(prior) !== modelShortLabel(requested);\n return {\n model: requested,\n denied: false,\n notice: changed ? fmt(modelShortLabel(prior!), modelShortLabel(requested)) : undefined,\n };\n}\n","import { spawnSync } from 'node:child_process';\nimport { symlinkSync, mkdirSync, statSync, readFileSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst VALID_SEGMENT = /^[a-zA-Z0-9._-]+$/;\nconst MAX_SLUG_LENGTH = 64;\nconst GIT_NO_PROMPT_ENV = { GIT_TERMINAL_PROMPT: '0', GIT_ASKPASS: '' };\n\nexport function validateWorktreeSlug(slug: string): void {\n if (!slug) throw new Error('worktree slug must not be empty');\n if (slug.length > MAX_SLUG_LENGTH) throw new Error(`worktree slug must be ≤${MAX_SLUG_LENGTH} chars (got ${slug.length})`);\n for (const seg of slug.split('/')) {\n if (seg === '.' || seg === '..') throw new Error(`worktree slug must not contain \".\" or \"..\" segments`);\n if (!VALID_SEGMENT.test(seg)) throw new Error(`worktree slug segment \"${seg}\" contains invalid characters (allowed: a-z A-Z 0-9 . _ -)`);\n }\n}\n\nfunction flattenSlug(slug: string): string { return slug.replaceAll('/', '+'); }\nexport function worktreeBranchName(slug: string): string { return `worktree-${flattenSlug(slug)}`; }\nfunction worktreesDir(repoRoot: string): string { return join(repoRoot, '.claude', 'worktrees'); }\nfunction worktreePathFor(repoRoot: string, slug: string): string { return join(worktreesDir(repoRoot), flattenSlug(slug)); }\n\nfunction git(args: string[], cwd: string): { ok: boolean; stdout: string; stderr: string } {\n const r = spawnSync('git', args, {\n cwd, stdio: ['ignore', 'pipe', 'pipe'],\n env: { ...process.env, ...GIT_NO_PROMPT_ENV },\n });\n return { ok: r.status === 0, stdout: (r.stdout ?? '').toString().trim(), stderr: (r.stderr ?? '').toString().trim() };\n}\n\nexport interface WorktreeInfo {\n worktreePath: string;\n branch: string;\n headCommit: string;\n existed: boolean;\n baseBranch?: string;\n}\n\nexport function findGitRoot(from: string): string | null {\n const r = git(['rev-parse', '--show-toplevel'], from);\n return r.ok ? r.stdout : null;\n}\n\nfunction readWorktreeHead(worktreePath: string): string | null {\n try {\n const gitFile = readFileSync(join(worktreePath, '.git'), 'utf-8').trim();\n const m = gitFile.match(/^gitdir:\\s*(.+)$/);\n if (!m) return null;\n const headPath = join(m[1], 'HEAD');\n const head = readFileSync(headPath, 'utf-8').trim();\n const refMatch = head.match(/^ref:\\s*(.+)$/);\n if (!refMatch) return head.length === 40 ? head : null;\n const refPath = join(m[1], '..', refMatch[1]);\n try { return readFileSync(refPath, 'utf-8').trim(); } catch { /* packed ref — fall through to git */ }\n const r = git(['rev-parse', 'HEAD'], worktreePath);\n return r.ok ? r.stdout : null;\n } catch { return null; }\n}\n\nexport function getOrCreateWorktree(repoRoot: string, slug: string): WorktreeInfo {\n validateWorktreeSlug(slug);\n const worktreePath = worktreePathFor(repoRoot, slug);\n const branch = worktreeBranchName(slug);\n\n const existingHead = readWorktreeHead(worktreePath);\n if (existingHead) return { worktreePath, branch, headCommit: existingHead, existed: true };\n\n mkdirSync(worktreesDir(repoRoot), { recursive: true });\n\n const defaultBranch = git(['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'], repoRoot);\n let baseBranch = defaultBranch.ok ? defaultBranch.stdout.replace(/^origin\\//, '') : 'HEAD';\n\n const originRef = `origin/${baseBranch}`;\n const hasOrigin = git(['rev-parse', '--verify', originRef], repoRoot);\n if (!hasOrigin.ok) {\n const fetched = git(['fetch', 'origin', baseBranch], repoRoot);\n if (!fetched.ok) baseBranch = 'HEAD';\n }\n const base = baseBranch === 'HEAD' ? 'HEAD' : originRef;\n\n const r = git(['worktree', 'add', '-B', branch, worktreePath, base], repoRoot);\n if (!r.ok) throw new Error(`failed to create worktree: ${r.stderr}`);\n\n const headSha = git(['rev-parse', 'HEAD'], worktreePath);\n\n symlinkDirs(repoRoot, worktreePath, ['node_modules', '.bun']);\n\n return { worktreePath, branch, headCommit: headSha.stdout, existed: false, baseBranch };\n}\n\nfunction symlinkDirs(repoRoot: string, worktreePath: string, dirs: string[]): void {\n for (const dir of dirs) {\n const src = join(repoRoot, dir);\n const dst = join(worktreePath, dir);\n try { statSync(src); } catch { continue; }\n try { symlinkSync(src, dst, 'dir'); } catch (e: any) { if (e?.code !== 'EEXIST') console.error(`[worktree] symlink ${dir}: ${e?.message ?? e}`); }\n }\n}\n\nexport function cleanupWorktree(repoRoot: string, slug: string, opts?: { force?: boolean }): { removed: boolean; reason?: string } {\n validateWorktreeSlug(slug);\n const worktreePath = worktreePathFor(repoRoot, slug);\n const branch = worktreeBranchName(slug);\n\n try { statSync(worktreePath); } catch { return { removed: false, reason: 'not found' }; }\n\n if (!opts?.force) {\n const status = git(['status', '--porcelain', '-uno'], worktreePath);\n if (status.ok && status.stdout) return { removed: false, reason: 'uncommitted changes' };\n }\n\n // Remove symlinks first so git worktree remove doesn't try to recurse into them\n for (const dir of ['node_modules', '.bun']) {\n try { rmSync(join(worktreePath, dir)); } catch { /* ok */ }\n }\n\n const rm = git(['worktree', 'remove', '--force', worktreePath], repoRoot);\n if (!rm.ok) return { removed: false, reason: rm.stderr };\n\n git(['branch', '-D', branch], repoRoot);\n return { removed: true };\n}\n\nexport interface WorktreeSession {\n originalCwd: string;\n worktreePath: string;\n slug: string;\n branch: string;\n headCommit: string;\n}\n\nlet _session: WorktreeSession | null = null;\nexport function getWorktreeSession(): WorktreeSession | null { return _session; }\n\nexport function enterWorktree(slug: string, cwd: string): WorktreeSession {\n const repoRoot = findGitRoot(cwd);\n if (!repoRoot) throw new Error('--worktree requires a git repository');\n\n const info = getOrCreateWorktree(repoRoot, slug);\n process.chdir(info.worktreePath);\n\n _session = {\n originalCwd: cwd,\n worktreePath: info.worktreePath,\n slug,\n branch: info.branch,\n headCommit: info.headCommit,\n };\n return _session;\n}\n\nexport function exitWorktree(): { removed: boolean; reason?: string } | null {\n if (!_session) return null;\n const repoRoot = findGitRoot(_session.originalCwd);\n if (!repoRoot) return null;\n\n process.chdir(_session.originalCwd);\n const result = cleanupWorktree(repoRoot, _session.slug);\n _session = null;\n return result;\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\n\n/**\n * Typed subagents — named child-agent definitions from `<dir>/<name>.md`, each with a\n * description, an optional model + tool allowlist (frontmatter), and a system prompt (the\n * body). The `Task` tool's `agentType` selects one, so a delegated sub-task runs with its\n * own persona, model, and scoped tools — the Claude-Code `.claude/agents` model.\n * VFS-backed (edge-portable), mirroring loadSkills / loadCommands.\n */\nexport interface AgentDef {\n name: string;\n description: string;\n /** The .md body — used as the child's system prompt (overrides the default). */\n systemPrompt?: string;\n /** Optional model override for this subagent type. */\n model?: string;\n /** Optional tool-name allowlist (scopes the child's tools). */\n tools?: string[];\n}\n\n/** Lean frontmatter parse for `description`/`model`/`tools` (no YAML dependency). */\nfunction parseAgentFrontmatter(md: string): { description?: string; model?: string; tools?: string[]; body: string } {\n const m = md.match(/^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n?/);\n const block = m ? m[1] : '';\n const get = (k: string) => {\n const r = new RegExp(`^${k}\\\\s*:\\\\s*(.+)$`, 'im').exec(block);\n return r ? r[1].trim().replace(/^[\"']|[\"']$/g, '') : undefined;\n };\n const toolsRaw = get('tools');\n const tools = toolsRaw\n ? toolsRaw.replace(/^\\[|\\]$/g, '').split(',').map((s) => s.trim().replace(/^[\"']|[\"']$/g, '')).filter(Boolean)\n : undefined;\n return { description: get('description'), model: get('model'), tools, body: (m ? md.slice(m[0].length) : md).trim() };\n}\n\n/** Discover subagent definitions under `dir` and a catalog block for the system prompt. */\nexport async function loadAgents(fs: IFilesystem, dir: string): Promise<{ agents: AgentDef[]; catalog: string }> {\n const agents: AgentDef[] = [];\n if (await fs.exists(dir)) {\n for (const entry of await fs.readDir(dir)) {\n if (!entry.endsWith('.md')) continue;\n const fm = parseAgentFrontmatter(await fs.readFile(`${dir}/${entry}`));\n agents.push({\n name: entry.replace(/\\.md$/, ''),\n description: fm.description || '',\n systemPrompt: fm.body || undefined,\n model: fm.model,\n tools: fm.tools,\n });\n }\n }\n if (!agents.length) return { agents, catalog: '' };\n const catalog =\n '## Subagent types (pass as the `Task` tool `agentType`)\\n' +\n agents.map((a) => `- **${a.name}** — ${a.description}`).join('\\n');\n return { agents, catalog };\n}\n","import type { Hooks, ToolUse } from './hooks';\nimport type { HostBridge, AgentTool } from './tools';\nimport { globToRegExp } from './tools.structured';\n\n/**\n * Permissions & plan-mode — safe-autonomy controls built ENTIRELY on the hooks +\n * host seams (no Agent-core changes needed). Two pieces:\n * - PermissionPolicy → Hooks: allow / ask (host.confirm) / deny a tool call by tool\n * name + path glob. First matching rule wins; default decision otherwise.\n * - planMode(): blocks mutating tools until the agent presents a plan via `ExitPlanMode`\n * and the host approves — Claude-Code-style plan gating.\n */\nexport type Decision = 'allow' | 'ask' | 'deny';\n\n/** Match a shell command against a rule glob where `*` spans anything (including spaces and `/`),\n * e.g. `git *` → any git subcommand, `rm *` → any rm invocation. Literals are regex-escaped. */\nfunction commandMatches(glob: string, cmd: string): boolean {\n const pattern = glob.split('*').map((s) => s.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&')).join('.*');\n return new RegExp('^' + pattern + '$').test(cmd);\n}\n\nexport interface PermissionRule {\n /** tool name to match (omit = any tool). */\n tool?: string;\n /** glob on the call's `path` arg to match (omit = any/none). */\n pathGlob?: string;\n decision: Decision;\n}\n\nexport class PermissionOptions {\n rules: PermissionRule[] = [];\n /** decision when no rule matches. */\n default: Decision = 'allow';\n /** host channel for `ask` (confirm). If absent, `ask` is treated as `deny` (fail-closed). */\n host?: HostBridge;\n /** Richer ask resolver (CLI surfaces a Yes/No/Always menu). Returns the decision + whether to\n * remember it — on remember, the policy adds a session rule so the same tool isn't re-asked.\n * If unset, falls back to `host.confirm` (plain yes/no). */\n ask?(call: ToolUse): Promise<{ decision: 'allow' | 'deny'; remember?: boolean } | undefined>;\n}\n\nexport class PermissionPolicy {\n public options: PermissionOptions;\n constructor(options?: Partial<PermissionOptions>) {\n this.options = { ...new PermissionOptions(), ...options };\n }\n\n /** Resolve the decision for a tool call (first matching rule, else default). */\n decide(call: ToolUse): Decision {\n // Deferred MCP (`McpCall({name})`) routes many tools through ONE agent tool — rules written\n // against the underlying `mcp__server__tool` name must still match (deny rules especially).\n const names = call.name === 'McpCall' && typeof call.args?.name === 'string' ? [call.name, call.args.name] : [call.name];\n for (const r of this.options.rules) {\n if (r.tool && !names.includes(r.tool)) continue;\n if (r.pathGlob) {\n // The glob matches a file `path` (path-glob semantics, slash-normalized) OR a `command`\n // string (`Shell(git *)`/`bash(rm *)`) — commands use *=anything (slashes included).\n const path = typeof call.args?.path === 'string' ? call.args.path : null;\n const cmd = typeof call.args?.command === 'string' ? call.args.command : null;\n if (path != null) {\n if (!globToRegExp(r.pathGlob).test(path.startsWith('/') ? path : `/${path}`)) continue;\n } else if (cmd != null) {\n if (!commandMatches(r.pathGlob, cmd)) continue;\n } else continue; // rule has a glob but the call exposes neither path nor command\n }\n return r.decision;\n }\n return this.options.default;\n }\n\n /** A preToolUse hook enforcing this policy (deny/ask → block; allow → proceed). */\n hooks(): Hooks {\n return {\n preToolUse: async (call) => {\n const d = this.decide(call);\n if (d === 'allow') return;\n if (d === 'deny') return { block: true, reason: `denied by permission policy (${call.name})` };\n // ask — prefer the richer resolver (Yes/No/Always); fall back to a plain confirm.\n if (this.options.ask) {\n const r = await this.options.ask(call);\n const decision = r?.decision ?? 'deny';\n // Remember the UNDERLYING tool for deferred MCP — remembering 'McpCall' itself would\n // blanket-approve every MCP tool from one answer. decide() aliases it back on match.\n const rememberTool = call.name === 'McpCall' && typeof call.args?.name === 'string' ? call.args.name : call.name;\n if (r?.remember) this.options.rules.unshift({ tool: rememberTool, decision }); // session-remember (wins next time)\n return decision === 'allow' ? undefined : { block: true, reason: `not approved (${call.name})` };\n }\n const ok = await this.options.host?.confirm?.(`Allow ${call.name}${call.args?.path ? ' on ' + call.args.path : ''}?`);\n return ok ? undefined : { block: true, reason: `not approved (${call.name})` };\n },\n };\n }\n}\n\n/** Tools the agent must not run before the plan is approved (sensible default). */\nexport const DEFAULT_MUTATING = ['Write', 'Edit', 'MultiEdit', 'deleteFile', 'bash'];\n\n/**\n * Plan-mode: mutating tools are BLOCKED until the agent calls `ExitPlanMode` with a plan\n * and (if a host is present) the user approves it. Returns the gating hook + the tool to\n * add to the agent. Compose the hook with others via composeHooks().\n */\nexport function planMode(opts?: { mutating?: string[]; host?: HostBridge }): { hooks: Hooks; tool: AgentTool } {\n const mutating = new Set(opts?.mutating ?? DEFAULT_MUTATING);\n let approved = false;\n const tool: AgentTool = {\n name: 'ExitPlanMode',\n description: 'Call when your plan is ready and you want to start making changes. Provide the `plan`. Until this is approved, edits/writes are blocked.',\n parameters: { type: 'object', required: ['plan'], properties: { plan: { type: 'string', description: 'the concrete steps you will take' } } },\n async run({ plan }, _ctx) {\n if (opts?.host?.confirm) {\n const confirm = opts.host.confirm(`Approve this plan?\\n\\n${String(plan ?? '')}`);\n const ok = await (_ctx?.parkHuman ? _ctx.parkHuman(confirm) : confirm); // exclude approval wait from the timeout\n if (!ok) return 'Plan not approved. Revise it and call ExitPlanMode again.';\n }\n approved = true;\n return 'Plan approved — you may now make changes.';\n },\n };\n const hooks: Hooks = {\n preToolUse: (call) =>\n !approved && mutating.has(call.name)\n ? { block: true, reason: 'plan mode: present a plan and call ExitPlanMode (approved) before editing.' }\n : undefined,\n };\n return { hooks, tool };\n}\n\n/** Run several Hooks as one: preToolUse stops at the first block; post/stop all fire. */\nexport function composeHooks(...list: (Hooks | undefined)[]): Hooks {\n const hooks = list.filter(Boolean) as Hooks[];\n return {\n async preToolUse(call, meta) {\n for (const h of hooks) {\n const d = await h.preToolUse?.(call, meta);\n if (d?.block) return d;\n }\n },\n async postToolUse(call, result, meta) { for (const h of hooks) await h.postToolUse?.(call, result, meta); },\n onToolOutput(call, chunk, meta) { for (const h of hooks) h.onToolOutput?.(call, chunk, meta); },\n onStop(text) { for (const h of hooks) h.onStop?.(text); },\n // lifecycle: concatenate session-start context; chain prompt-submit transforms; fan out pre-compact.\n async onSessionStart() {\n let ctx = '';\n for (const h of hooks) { const r = await h.onSessionStart?.(); if (r) ctx += (ctx ? '\\n\\n' : '') + r; }\n return ctx || undefined;\n },\n async onUserPromptSubmit(text) {\n let t = text;\n for (const h of hooks) { const r = await h.onUserPromptSubmit?.(t); if (typeof r === 'string') t = r; }\n return t;\n },\n async onPreCompact(messages) { for (const h of hooks) await h.onPreCompact?.(messages); },\n async onSubagentStop(summary, info) { for (const h of hooks) await h.onSubagentStop?.(summary, info); },\n };\n}\n","/**\n * Conservative, dependency-free syntax sanity check for code files (edge-safe pure JS).\n * Goal: catch an unambiguously-broken write (unbalanced/mis-nested delimiters) BEFORE it\n * lands, so the model doesn't later waste a turn re-reading + re-editing. Deliberately narrow:\n * it ONLY checks balanced ()/[]/{} after skipping string literals and comments, and ONLY\n * reports when delimiters are clearly wrong. Never throws.\n */\n\nconst CODE_RE = /\\.(ts|tsx|js|jsx|mjs|cjs)$/;\n\n/** Returns an error message if `content` is clearly broken for a code file, else null. */\nexport function checkSyntax(path: string, content: string): string | null {\n if (!CODE_RE.test(path)) return null; // only code files\n try {\n const open: Record<string, string> = { ')': '(', ']': '[', '}': '{' };\n const names: Record<string, string> = { '(': \"'('\", '[': \"'['\", '{': \"'{'\" };\n const stack: string[] = [];\n const n = content.length;\n for (let i = 0; i < n; i++) {\n const c = content[i];\n // line comment\n if (c === '/' && content[i + 1] === '/') {\n while (i < n && content[i] !== '\\n') i++;\n continue;\n }\n // block comment\n if (c === '/' && content[i + 1] === '*') {\n i += 2;\n while (i < n && !(content[i] === '*' && content[i + 1] === '/')) i++;\n i++; // skip the closing '/' (loop's i++ skips '*')\n continue;\n }\n // string / template literals — skip with escape handling\n if (c === '\"' || c === \"'\" || c === '`') {\n const quote = c;\n i++;\n while (i < n) {\n if (content[i] === '\\\\') { i += 2; continue; }\n if (content[i] === quote) break;\n i++;\n }\n continue;\n }\n if (c === '(' || c === '[' || c === '{') stack.push(c);\n else if (c === ')' || c === ']' || c === '}') {\n const want = open[c];\n if (stack.length === 0) return `Syntax check failed for ${path}: unexpected closing '${c}'. Fix before writing.`;\n const top = stack.pop()!;\n if (top !== want) return `Syntax check failed for ${path}: mismatched '${c}' (expected to close ${names[top]}). Fix before writing.`;\n }\n }\n if (stack.length > 0) {\n const ch = stack[stack.length - 1];\n return `Syntax check failed for ${path}: unbalanced ${names[ch]} (${stack.length} unclosed). Fix before writing.`;\n }\n return null;\n } catch {\n return null; // never throw — lint is a guard, not a gate that can crash a write\n }\n}\n","/**\n * Normalized reasoning/thinking control → provider-specific request fragment.\n *\n * Pure & dependency-free (no `ai.libx.js` import — provider is detected from the\n * `provider/model` prefix), so it stays inside the Agent's structural-typing boundary.\n * The returned fragment is spread into `ai.chat()`; callers never hand-craft the\n * per-provider encoding (Anthropic `thinking.budget_tokens`, OpenAI `reasoning_effort`).\n */\n\n/** `'off'`/undefined = no reasoning; named buckets; or a raw token budget (budget-based providers). */\nexport type ReasoningEffort = 'off' | 'low' | 'medium' | 'high' | number;\n\nexport interface ChatFragment {\n providerOptions?: Record<string, unknown>;\n /** Request `max_tokens`. Raised for budget-based providers so `budget_tokens < max_tokens` holds. */\n maxTokens?: number;\n}\n\n/** Named effort → thinking-token budget (budget-based providers, e.g. Anthropic). */\nconst BUDGET: Record<'low' | 'medium' | 'high', number> = { low: 2048, medium: 8192, high: 24576 };\n\n/** Bucket a raw token budget back to the nearest named effort (for providers that take a label). */\nfunction toLabel(effort: ReasoningEffort): 'low' | 'medium' | 'high' {\n if (typeof effort !== 'number') return effort === 'off' ? 'low' : effort;\n return effort <= BUDGET.low ? 'low' : effort < BUDGET.high ? 'medium' : 'high';\n}\n\n/** Resolve an effort to a concrete token budget. */\nfunction toBudget(effort: ReasoningEffort): number {\n return typeof effort === 'number' ? effort : BUDGET[effort as 'low' | 'medium' | 'high'];\n}\n\n/**\n * Map a normalized effort to a partial `ChatOptions` fragment for `model`'s provider.\n * Returns `{}` (safe no-op) for `'off'`, undefined, or an unsupported provider.\n *\n * Supported: `anthropic/*` (extended thinking), `openai/*` (reasoning_effort).\n * `google/*` is intentionally NOT mapped here — its adapter `Object.assign`s\n * providerOptions over the built `generationConfig`, clobbering it; pass an\n * explicit `providerOptions` if you need Gemini thinking.\n */\nexport function reasoningToChatFragment(model: string, effort?: ReasoningEffort): ChatFragment {\n if (effort == null || effort === 'off') return {};\n const provider = model.split('/')[0];\n switch (provider) {\n case 'anthropic': {\n const budget = toBudget(effort);\n return { providerOptions: { thinking: { type: 'enabled', budget_tokens: budget } }, maxTokens: budget + 8192 };\n }\n case 'openai':\n return { providerOptions: { reasoning_effort: toLabel(effort) } };\n default:\n return {};\n }\n}\n","// agentx — edge-native AI agent runtime over a virtual filesystem.\n\nexport { Agent, AgentOptions } from './Agent';\nexport type { RunResult, CompactResult } from './Agent';\nexport { estimateTokens } from './Agent';\n\nexport { MODEL_ALIASES, resolveModelAlias, modelShortLabel, resolveModelSwitch } from './models';\nexport type { ResolveModelSwitchOpts, ModelSwitch } from './models';\n\nexport { NodeDiskFilesystem } from './NodeDiskFilesystem';\nexport { BodDbFilesystem } from './BodDbFilesystem';\nexport { JailedFilesystem, JailOptions, DEFAULT_DENY } from './JailedFilesystem';\nexport { OverlayFilesystem, checkpointTool, rollbackTool, checkpointTools } from './OverlayFilesystem';\nexport { MountFilesystem } from './MountFilesystem';\nexport type { Mount } from './MountFilesystem';\nexport { raceAttempts } from './speculate';\nexport type { Attempt } from './speculate';\nexport { validateToolCode, compileSynthesizedTool } from './synthesize';\nexport type { ToolSpec } from './synthesize';\nexport { PermissionPolicy, PermissionOptions, planMode, composeHooks, DEFAULT_MUTATING } from './permissions';\nexport type { Decision, PermissionRule } from './permissions';\n\nexport { FakeAIClient, toolCall } from './FakeAIClient';\n\nexport { bashTool, readTool, editTool, defaultTools, exitSessionTool, makeContext, toWireTools, toolRegistry, toolsByName } from './tools';\nexport { SandboxJobRegistry, makeJobTools } from './tools.jobs';\nexport { Scheduler, makeScheduleTools, parseCron, cronMatches, nextCronAfter } from './scheduler';\nexport type { ScheduledJob, ScheduledJobSnapshot, Trigger, TriggerOneOff, TriggerInterval, TriggerCron, SchedulerOptions } from './scheduler';\nexport { sandboxAgentOptions, diskAgentOptions, fullAgentOptions } from './presets';\nexport { grepTool, globTool, makeGrepTool, makeGlobTool, DEFAULT_SKIP_DIRS, DEFAULT_MAX_DEPTH, type FileScanOptions, writeTool, multiEditTool, applyEditsTool, repoMapTool, repoIndex, mkdirp } from './tools.structured';\nexport { todoWriteTool } from './todo';\nexport { webFetchTool, webSearchTool, webSearchAnthropicTool, makeWebFetchTool, makeWebSearchTool, makeWebSearchAnthropicTool, htmlToText, parseDdgHtml, decodeDdgUrl } from './tools.web';\nexport { Scratch, makeAskTool, SCRATCH_DIR } from './scratch';\nexport type { ScratchOptions, AskOptions } from './scratch';\nexport type { WebFetchOptions, WebSearchOptions } from './tools.web';\nexport type { TodoItem } from './todo';\nexport type { AgentTool, ToolContext, HostBridge, HostEvent, UserQuestion } from './tools';\n\nexport { askUserQuestionTool, ScriptedHostBridge, ConsoleHostBridge } from './host';\n\nexport { loadSkills, scanSkills } from './skills';\nexport type { SkillInfo } from './skills';\nexport { tokenize, relevanceScore, topByRelevance, idfWeights } from './relevance';\nexport { loadCommands, scanCommands, expandCommand, expandTemplate, expandEntry } from './commands';\nexport type { CommandInfo, SiblingResolver } from './commands';\nexport { loadMemory, writeFact, slugify, MEMORY_PROMPT, VOICE_MEMORY_PROMPT } from './memory';\nexport type { LoadMemoryOpts } from './memory';\nexport { lessonCapture, LessonOptionsDefaults } from './lessons';\nexport type { LessonOptions } from './lessons';\nexport { reflectOnRun } from './reflect';\nexport type { ReflectOptions } from './reflect';\nexport { loadInstructions } from './instructions';\n\nexport { DuplexAgent, DuplexAgentOptions, VOICE_SYSTEM_PROMPT } from './duplex';\nexport type { TaskRecord, DuplexTaskStatus, WorkerTier } from './duplex';\n\nexport { makeTaskTool, makeTaskBatchTool } from './subagent';\nexport type { TaskToolOptions } from './subagent';\nexport { loadAgents } from './agents';\nexport type { AgentDef } from './agents';\nexport { mcpToolsToAgentTools, mcpToolToAgentTool, makeMcpToolSearch, makeMcpToolSearchFromMounted, makeLazyMcpToolSearch, buildMcpCatalog } from './mcp';\nexport type { McpToolSpec, McpCall, McpToolSearchOptions, McpImage, McpToolResult, MountedMcpLike, McpRoute, McpRouteResolver } from './mcp';\nexport { RecordingHooks, RecordingLifecycle } from './hooks';\nexport type { Hooks, ToolUse, ToolUseMeta, PreToolUseDecision } from './hooks';\n\nexport { forComponent, log } from './logging';\n\n// Voice I/O (portable core — CLI/server/browser; platform backends live in cli/voice.ts).\nexport { VoiceEngine, VoiceEngineOptions } from './voice/engine';\nexport type { SttLike, TtsLike } from './voice/engine';\nexport { SonioxSTT, SonioxSTTOptions } from './voice/soniox';\nexport { CartesiaTTS, CartesiaTTSOptions } from './voice/cartesia';\nexport { resolveAuth, STT_SAMPLE_RATE, TTS_SAMPLE_RATE } from './voice/types';\nexport type { AudioSource, AudioSink, AuthProvider, VoiceState } from './voice/types';\n\nexport type { Message, Tool, ToolCall, ChatResponse, ChatOptions, ChatLike, Role, StreamChunk, ContentPart, MessageContent } from './llm';\nexport { contentText, imagePart, contentBytes, elideStaleImages, elideInlineImages, elideImages, messageHasInlineImage, IMAGE_ELIDE_STUB, imageRefPart, parseImageRef, messageHasImageRef, messageHasImage, imageRefResult, toolImageRef, expandImagesForSend, IMAGE_REF_SCHEME, mintImageRef, clearImageRefs, sendBytes, sendBytesPer, remintImageRefs } from './llm';\nexport type { ImageRef } from './llm';\nexport { reasoningToChatFragment } from './reasoning';\nexport type { ReasoningEffort, ChatFragment } from './reasoning';\n\nexport { validateWorktreeSlug, worktreeBranchName, getOrCreateWorktree, cleanupWorktree, enterWorktree, exitWorktree, getWorktreeSession, findGitRoot } from './worktree';\nexport type { WorktreeInfo, WorktreeSession } from './worktree';\n\n// Re-export the wcli-core filesystem backends so embedders get everything from one place.\nexport { MemFilesystem, IndexedDbFilesystem, CommandExecutor, registerHeadlessCommands } from '@livx.cc/wcli/core';\nexport type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\n","import type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\nimport { PathResolver } from '@livx.cc/wcli/core';\nimport { BodDB } from '@bod.ee/db';\nimport type { VFSBackend } from '@bod.ee/db';\n\n/** Pure in-memory byte store for the default (no-arg) constructor — keeps it truly in-memory\n * (bod-db's default backend writes bytes to disk under `storageRoot`). Keyed by fileId. */\nclass MemBackend implements VFSBackend {\n private store = new Map<string, Uint8Array>();\n async read(id: string): Promise<Uint8Array> {\n const d = this.store.get(id);\n if (!d) throw new Error(`fileId not found: ${id}`);\n return d;\n }\n async write(id: string, data: Uint8Array): Promise<void> { this.store.set(id, data); }\n async delete(id: string): Promise<void> { this.store.delete(id); }\n async exists(id: string): Promise<boolean> { return this.store.has(id); }\n}\n\n/**\n * Database-backed `IFilesystem` over bod-db's VFS — the normalization thesis realized: the agent\n * operates on a file tree that lives in a database, yet the same tools/commands run unchanged\n * (semantics mirror MemFilesystem/NodeDiskFilesystem: throw on missing parent / existing dir /\n * non-empty dir / missing file). bod-db's VFS is path-based and async, so the adapter is thin.\n *\n * Construct with no args for an in-memory DB (great for tests), or pass a configured `BodDB`\n * (with VFS enabled) backed by real/cloud storage for persistence. Call `close()` when done to\n * release the DB's timers (the in-memory default uses `sweepInterval: 0`, so there's nothing to sweep).\n */\nexport class BodDbFilesystem implements IFilesystem {\n private cwd = '/';\n private db: BodDB;\n private vfs: NonNullable<BodDB['vfs']>;\n private owns: boolean;\n\n constructor(db?: BodDB) {\n this.owns = !db;\n // default: metadata DB in-memory (path ':memory:'), file bytes in a Map backend → no disk, no sweep timer.\n this.db = db ?? new BodDB({ path: ':memory:', sweepInterval: 0, vfs: { storageRoot: ':memory:', backend: new MemBackend() } });\n if (!this.db.vfs) throw new Error('BodDbFilesystem: the BodDB must have VFS enabled (construct it with { vfs: { … } }).');\n this.vfs = this.db.vfs;\n }\n\n /** Release the underlying DB's timers/handles. Closes only a DB we created (a passed-in DB is the caller's). */\n close(): void {\n if (this.owns) this.db.close();\n }\n\n resolvePath(path: string, cwd?: string): string {\n return PathResolver.resolve(path, cwd || this.cwd);\n }\n getCwd(): string { return this.cwd; }\n setCwd(path: string): void { this.cwd = PathResolver.normalize(path); }\n\n /** Parent dir of an absolute VFS path ('/a/b.txt' -> '/a'; '/a' -> '/'). */\n private parentOf(p: string): string {\n const i = p.lastIndexOf('/');\n return i <= 0 ? '/' : p.slice(0, i);\n }\n /** Throw (matching the other backends) unless the parent directory exists. Root is always a dir. */\n private assertParentDir(p: string, path: string): void {\n const parent = this.parentOf(p);\n if (parent === '/') return;\n const s = this.vfs.stat(parent);\n if (!s || !s.isDir) throw new Error(`Parent directory does not exist: ${path}`);\n }\n\n async readFile(path: string): Promise<string> {\n const p = this.resolvePath(path);\n const s = this.vfs.stat(p);\n if (!s) throw new Error(`File not found: ${path}`);\n if (s.isDir) throw new Error(`Not a file: ${path}`);\n return new TextDecoder().decode(await this.vfs.read(p));\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n const p = this.resolvePath(path);\n this.assertParentDir(p, path);\n if (this.vfs.stat(p)?.isDir) throw new Error(`Is a directory: ${path}`);\n await this.vfs.write(p, new TextEncoder().encode(content), 'text/plain');\n }\n\n async deleteFile(path: string): Promise<void> {\n const p = this.resolvePath(path);\n const s = this.vfs.stat(p);\n if (!s) throw new Error(`File not found: ${path}`);\n if (s.isDir && this.vfs.list(p).length > 0) throw new Error(`Directory not empty: ${path}`);\n await this.vfs.remove(p);\n }\n\n async readDir(path: string): Promise<string[]> {\n const p = this.resolvePath(path);\n if (p !== '/') {\n const s = this.vfs.stat(p);\n if (!s) throw new Error(`Directory not found: ${path}`); // missing vs…\n if (!s.isDir) throw new Error(`Not a directory: ${path}`); // …a file (match MemFilesystem semantics)\n }\n return this.vfs.list(p).map((e: { name: string }) => e.name);\n }\n\n async createDir(path: string): Promise<void> {\n const p = this.resolvePath(path);\n if (p === '/' || this.vfs.stat(p)) throw new Error(`File or directory already exists: ${path}`);\n this.assertParentDir(p, path);\n this.vfs.mkdir(p);\n }\n\n async exists(path: string): Promise<boolean> {\n const p = this.resolvePath(path);\n return p === '/' || this.vfs.stat(p) !== null;\n }\n\n async stat(path: string): Promise<FileMetadata> {\n const p = this.resolvePath(path);\n const s = this.vfs.stat(p);\n if (!s) {\n if (p === '/') return { created: new Date(0), modified: new Date(0), size: 0, permissions: 'drwxr-xr-x', isExecutable: false };\n throw new Error(`File not found: ${path}`);\n }\n const when = new Date(s.mtime); // bod-db tracks a single mtime; reuse for created+modified\n return {\n created: when,\n modified: when,\n size: s.size,\n permissions: s.isDir ? 'drwxr-xr-x' : '-rw-r--r--',\n isExecutable: false,\n };\n }\n\n async isDirectory(path: string): Promise<boolean> {\n const p = this.resolvePath(path);\n return p === '/' || this.vfs.stat(p)?.isDir === true;\n }\n async isFile(path: string): Promise<boolean> {\n const s = this.vfs.stat(this.resolvePath(path));\n return !!s && !s.isDir;\n }\n}\n","import type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\n\n/**\n * Hybrid / composite VFS — a root backend with other IFilesystems mounted at path\n * prefixes. Each op routes to the longest-matching mount and is translated into that\n * backend's OWN root space (`/skills/x.md` → the /skills mount's `/x.md`); everything\n * else falls through to the root backend. `readDir` merges the routed listing with\n * mount-point names at that level, and intermediate mount-ancestor dirs (e.g. `/vendor`\n * when only `/vendor/lib` is mounted) are synthesized.\n *\n * This is what lets you mix sources: edit a real project on disk at `/` while reading\n * skills/tools/docs from a bundled in-memory VFS or another disk folder — one filesystem\n * to the agent. Pure IFilesystem composition: edge-safe.\n */\nconst DIR_META: FileMetadata = { created: new Date(0), modified: new Date(0), size: 0, permissions: 'drwxr-xr-x', isExecutable: false };\nconst norm = (p: string) => '/' + p.split('/').filter(Boolean).join('/'); // leading slash, no trailing\n\nexport interface Mount { prefix: string; fs: IFilesystem }\n\nexport class MountFilesystem implements IFilesystem {\n private mounts: Mount[];\n\n constructor(private root: IFilesystem, mounts: Mount[] = []) {\n this.mounts = mounts\n .map((m) => ({ prefix: norm(m.prefix), fs: m.fs }))\n .sort((a, b) => b.prefix.length - a.prefix.length); // longest prefix wins\n }\n\n resolvePath(path: string, cwd?: string): string { return this.root.resolvePath(path, cwd ?? this.root.getCwd()); }\n getCwd(): string { return this.root.getCwd(); }\n setCwd(path: string): void { this.root.setCwd(path); }\n private abs(p: string): string { return this.resolvePath(p); }\n\n /** Route an absolute VFS path to a backend + its path within that backend. */\n private route(abs: string): { fs: IFilesystem; sub: string } {\n for (const m of this.mounts) {\n if (abs === m.prefix || abs.startsWith(m.prefix + '/')) return { fs: m.fs, sub: abs.slice(m.prefix.length) || '/' };\n }\n return { fs: this.root, sub: abs };\n }\n\n /** Is `abs` strictly ABOVE a mount point (a synthesized dir the root may not have)? */\n private isMountAncestor(abs: string): boolean {\n const base = abs === '/' ? '/' : abs + '/';\n return this.mounts.some((m) => m.prefix.startsWith(base));\n }\n\n /** Immediate child segment names of `abs` that come from mounts (for readDir merge). */\n private mountChildrenOf(abs: string): string[] {\n const base = abs === '/' ? '/' : abs + '/';\n const out = new Set<string>();\n for (const m of this.mounts) if (m.prefix.startsWith(base)) out.add(m.prefix.slice(base.length).split('/')[0]);\n return [...out];\n }\n\n async readFile(path: string): Promise<string> { const { fs, sub } = this.route(this.abs(path)); return fs.readFile(sub); }\n async writeFile(path: string, content: string): Promise<void> { const { fs, sub } = this.route(this.abs(path)); return fs.writeFile(sub, content); }\n async deleteFile(path: string): Promise<void> { const { fs, sub } = this.route(this.abs(path)); return fs.deleteFile(sub); }\n async createDir(path: string): Promise<void> { const { fs, sub } = this.route(this.abs(path)); return fs.createDir(sub); }\n\n async exists(path: string): Promise<boolean> {\n const a = this.abs(path);\n if (this.isMountAncestor(a)) return true;\n const { fs, sub } = this.route(a);\n return fs.exists(sub);\n }\n async isDirectory(path: string): Promise<boolean> {\n const a = this.abs(path);\n if (this.isMountAncestor(a)) return true; // synthesized ancestor dir\n const { fs, sub } = this.route(a);\n return fs.isDirectory(sub);\n }\n async isFile(path: string): Promise<boolean> {\n const a = this.abs(path);\n if (this.isMountAncestor(a)) return false;\n const { fs, sub } = this.route(a);\n return fs.isFile(sub);\n }\n async stat(path: string): Promise<FileMetadata> {\n const a = this.abs(path);\n if (this.isMountAncestor(a)) return DIR_META;\n const { fs, sub } = this.route(a);\n return fs.stat(sub);\n }\n\n async readDir(path: string): Promise<string[]> {\n const a = this.abs(path);\n const { fs, sub } = this.route(a);\n const names = new Set<string>();\n let routedOk = false;\n try { for (const n of await fs.readDir(sub)) names.add(n); routedOk = true; } catch { /* may be a pure synthetic ancestor */ }\n for (const n of this.mountChildrenOf(a)) names.add(n);\n if (!routedOk && !this.isMountAncestor(a)) throw new Error(`Directory not found: ${path}`);\n return [...names].sort();\n }\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport { OverlayFilesystem } from './OverlayFilesystem';\n\n/**\n * Speculative parallel attempts — a primitive uniquely cheap on a SWAPPABLE VFS.\n *\n * Fork the workspace into N copy-on-write overlays of the same `base`, run an attempt in\n * each (independently — writes stay in each overlay, the base is untouched), score them,\n * then COMMIT the best overlay into the base and DISCARD the losers (they leave no trace).\n * Use it to race several approaches/seeds for a flaky or multi-path task and keep only the\n * winner — something agents on a real, non-forkable filesystem can't do without copying the\n * whole tree. Pairs naturally with subagents (each attempt is a child Agent over its overlay).\n *\n * `score` returns a higher-is-better number, or null to disqualify (e.g. failed grading).\n */\nexport interface Attempt<R> {\n index: number;\n fs: OverlayFilesystem;\n result: R;\n score: number | null;\n}\n\nexport async function raceAttempts<R>(\n base: IFilesystem,\n n: number,\n run: (fs: IFilesystem, index: number) => Promise<R>,\n score: (a: { fs: OverlayFilesystem; result: R; index: number }) => Promise<number | null> | number | null,\n): Promise<{ winner: Attempt<R> | null; attempts: Attempt<R>[] }> {\n const attempts: Attempt<R>[] = await Promise.all(\n Array.from({ length: Math.max(1, n) }, async (_, index) => {\n const fs = new OverlayFilesystem(base);\n const result = await run(fs, index);\n const s = await score({ fs, result, index });\n return { index, fs, result, score: s };\n }),\n );\n // Best non-disqualified score wins; ties broken by earliest index (stable).\n const ranked = attempts.filter((a) => a.score != null).sort((a, b) => b.score! - a.score! || a.index - b.index);\n const winner = ranked[0] ?? null;\n if (winner) await winner.fs.commit(); // apply ONLY the winner to the base; losers are discarded\n return { winner, attempts };\n}\n","import type { AgentTool, ToolContext } from './tools';\n\n/**\n * Tool synthesis — compile a NEW agent tool from a spec the model authored. The unbounded\n * frontier of self-evolution: the agent invents its own capabilities.\n *\n * SAFETY (this is the load-bearing part). A synthesized tool's `code` is arbitrary JS that\n * runs IN-PROCESS over the agent's filesystem, so before compiling we statically REJECT a\n * denylist of escape vectors (process/require/import/eval/Function/constructor/__proto__/\n * globalThis/Bun/fetch/network/timers/WebAssembly/infinite-loops/…). A compiled tool sees\n * ONLY its `args` and `ctx` (whose fs is the JailedFilesystem — boundary A); combined with\n * the Agent's timeout/tool-call kill-switches this is defensible. Residual risk remains for\n * a determined denylist bypass, so synthesized tools are OPT-IN and should additionally be\n * self-tested in the sandbox (boundary B) before being trusted in a live loop. See mind/08.\n */\nexport interface ToolSpec {\n name: string;\n description: string;\n parameters: object; // JSON Schema for args\n /** body of `async (args, ctx) => { … return <string> }` — may use args + ctx.fs ONLY. */\n code: string;\n}\n\n/** Static safety gate. Returns the matched escape vectors (empty = code is allowed). */\nexport function validateToolCode(code: string): { ok: boolean; violations: string[] } {\n const DENY: [string, RegExp][] = [\n ['process', /\\bprocess\\b/], ['require', /\\brequire\\b/], ['import', /\\bimport\\b/],\n ['eval', /\\beval\\b/], ['Function', /\\bFunction\\b/], ['constructor', /\\bconstructor\\b/],\n ['__proto__', /__proto__/], ['prototype', /\\bprototype\\b/], ['globalThis', /\\bglobalThis\\b/],\n ['global', /\\bglobal\\b/], ['window', /\\bwindow\\b/], ['self', /\\bself\\b/],\n ['Bun', /\\bBun\\b/], ['Deno', /\\bDeno\\b/], ['fetch', /\\bfetch\\b/], ['XMLHttpRequest', /\\bXMLHttpRequest\\b/],\n ['WebSocket', /\\bWebSocket\\b/], ['child_process', /\\bchild_process\\b/], ['node:', /node:/],\n ['setTimeout', /\\bsetTimeout\\b/], ['setInterval', /\\bsetInterval\\b/], ['setImmediate', /\\bsetImmediate\\b/],\n ['Atomics', /\\bAtomics\\b/], ['SharedArrayBuffer', /\\bSharedArrayBuffer\\b/], ['WebAssembly', /\\bWebAssembly\\b/],\n ['Reflect', /\\bReflect\\b/], ['Proxy', /\\bProxy\\b/], ['Buffer', /\\bBuffer\\b/],\n ['while(true)', /while\\s*\\(\\s*true\\s*\\)/], ['for(;;)', /for\\s*\\(\\s*;\\s*;\\s*\\)/],\n // escape sequences can smuggle a denied identifier past the substring check\n // (e.g. `process` parses as `process`), so forbid them outright.\n ['\\\\u escape', /\\\\u/], ['\\\\x escape', /\\\\x/],\n ];\n const violations = DENY.filter(([, re]) => re.test(code)).map(([name]) => name);\n return { ok: violations.length === 0, violations };\n}\n\n/**\n * Compile a spec into an AgentTool — THROWS if the code fails the static safety gate.\n * The body runs as `async (args, ctx) => { <code> }`; only `args` and `ctx` are in scope.\n */\nexport function compileSynthesizedTool(spec: ToolSpec): AgentTool {\n const v = validateToolCode(spec.code);\n if (!v.ok) throw new Error(`unsafe synthesized tool '${spec.name}': blocked tokens [${v.violations.join(', ')}]`);\n if (!/^[A-Za-z_]\\w{0,39}$/.test(spec.name)) throw new Error(`invalid tool name '${spec.name}'`);\n // Strict mode; only args + ctx are reachable lexically.\n const fn = new Function('args', 'ctx', `\"use strict\"; return (async (args, ctx) => { ${spec.code} })(args, ctx);`) as (a: any, c: ToolContext) => Promise<unknown>;\n return {\n name: spec.name,\n description: spec.description,\n parameters: spec.parameters ?? { type: 'object', properties: {} },\n async run(args, ctx) {\n const r = await fn(args, ctx);\n return typeof r === 'string' ? r : JSON.stringify(r ?? '');\n },\n };\n}\n","import type { ChatLike, ChatOptions, ChatResponse, ToolCall } from './llm';\n\n/**\n * Deterministic test/dev double for an ai.libx.js AIClient. Plays a scripted\n * queue of ChatResponses (tool_calls then a final answer). Records each\n * ChatOptions it saw so tests can assert tools were advertised and tool\n * results were threaded back. No network, no API key.\n */\nexport class FakeAIClient implements ChatLike {\n public seen: ChatOptions[] = [];\n private script: ChatResponse[];\n\n constructor(script: ChatResponse[]) {\n this.script = [...script];\n }\n\n async chat(options: ChatOptions): Promise<ChatResponse> {\n this.seen.push(options);\n const next = this.script.shift();\n if (!next) throw new Error('FakeAIClient: script exhausted (model asked for more turns than scripted)');\n return next;\n }\n}\n\n/** Build a tool_call block (arguments JSON-stringified, matching the wire format). */\nexport const toolCall = (id: string, name: string, args: object): ToolCall => ({\n id,\n type: 'function',\n function: { name, arguments: JSON.stringify(args) },\n});\n","/**\n * In-process scheduler — timers that fire prompts into the agent loop while the session is alive.\n * Three trigger modes: one-off ({at}), interval ({everyMs}), cron ({cron}).\n * The scheduler never calls `turn()` itself — it invokes an IoC `fire` callback with due jobs,\n * keeping it testable and host-agnostic. Persistence is the host's responsibility (serialize jobs\n * into the session and re-arm on resume).\n *\n * Survives --resume (host reloads); does NOT survive process exit (no daemon, no launchd).\n */\n\nexport type TriggerOneOff = { at: number };\nexport type TriggerInterval = { everyMs: number };\nexport type TriggerCron = { cron: string };\nexport type Trigger = TriggerOneOff | TriggerInterval | TriggerCron;\n\nexport type ScheduledJobStatus = 'active' | 'done';\n\nexport interface ScheduledJob {\n id: string;\n prompt: string;\n trigger: Trigger;\n status: ScheduledJobStatus;\n created: number;\n lastRun?: number;\n runs: number;\n /** Optional label for display (e.g. footer, /schedule list). */\n label?: string;\n}\n\n/** Serializable snapshot for session persistence (same shape — kept as an alias for clarity at call sites). */\nexport type ScheduledJobSnapshot = ScheduledJob;\n\nexport interface SchedulerOptions {\n /** Called when a job is due. Must not throw — the scheduler logs errors and continues. */\n fire: (job: ScheduledJob) => Promise<void> | void;\n /** Monotonic clock override for testing (default: Date.now). */\n now?: () => number;\n /** Tick interval in ms (default: 15_000 — 15s). */\n tickMs?: number;\n /** If true, suppress the setInterval (for unit tests that call tick() manually). */\n manual?: boolean;\n}\n\n// ── Cron mini-parser (minute hour dom month dow) ──────────────────────────\n// Supports: *, N, N-M, */N, N-M/N, comma-separated lists. No named days/months.\n// Enough for real scheduling; not a full vixie-cron (no @yearly etc).\n\ninterface CronFields { minute: number[]; hour: number[]; dom: number[]; month: number[]; dow: number[] }\n\nfunction parseCronField(field: string, min: number, max: number): number[] {\n const vals = new Set<number>();\n for (const part of field.split(',')) {\n const [rangeStr, stepStr] = part.split('/');\n const step = stepStr ? parseInt(stepStr, 10) : 1;\n if (isNaN(step) || step < 1) throw new Error(`invalid cron step: ${part}`);\n let lo: number, hi: number;\n if (rangeStr === '*') { lo = min; hi = max; }\n else if (rangeStr!.includes('-')) {\n const [a, b] = rangeStr!.split('-').map(Number);\n if (isNaN(a!) || isNaN(b!)) throw new Error(`invalid cron range: ${part}`);\n lo = a!; hi = b!;\n } else {\n const n = parseInt(rangeStr!, 10);\n if (isNaN(n)) throw new Error(`invalid cron value: ${part}`);\n lo = n; hi = stepStr ? max : n;\n }\n for (let i = lo; i <= hi; i += step) vals.add(i);\n }\n return [...vals].sort((a, b) => a - b);\n}\n\nexport function parseCron(expr: string): CronFields {\n const parts = expr.trim().split(/\\s+/);\n if (parts.length !== 5) throw new Error(`cron expression must have 5 fields (minute hour dom month dow), got ${parts.length}: \"${expr}\"`);\n return {\n minute: parseCronField(parts[0]!, 0, 59),\n hour: parseCronField(parts[1]!, 0, 23),\n dom: parseCronField(parts[2]!, 1, 31),\n month: parseCronField(parts[3]!, 1, 12),\n dow: parseCronField(parts[4]!, 0, 6),\n };\n}\n\nexport function cronMatches(fields: CronFields, date: Date): boolean {\n return fields.minute.includes(date.getMinutes())\n && fields.hour.includes(date.getHours())\n && fields.dom.includes(date.getDate())\n && fields.month.includes(date.getMonth() + 1)\n && fields.dow.includes(date.getDay());\n}\n\n/** Next occurrence of `cron` after `after` (epoch ms). Returns epoch ms, or null if >366 days out (guard). */\nexport function nextCronAfter(cron: string, after: number): number | null {\n const fields = parseCron(cron);\n const d = new Date(after);\n d.setSeconds(0, 0);\n d.setMinutes(d.getMinutes() + 1); // always at least 1 minute in the future\n const limit = after + 366 * 86400_000;\n while (d.getTime() <= limit) {\n if (cronMatches(fields, d)) return d.getTime();\n d.setMinutes(d.getMinutes() + 1);\n }\n return null;\n}\n\n// ── Scheduler ─────────────────────────────────────────────────────────────\n\nexport class Scheduler {\n private jobs = new Map<string, ScheduledJob>();\n private seq = 0;\n private timer: ReturnType<typeof setInterval> | null = null;\n private firing = false;\n private readonly fire: SchedulerOptions['fire'];\n private readonly now: () => number;\n private readonly tickMs: number;\n\n constructor(opts: SchedulerOptions) {\n this.fire = opts.fire;\n this.now = opts.now ?? Date.now;\n this.tickMs = opts.tickMs ?? 15_000;\n if (!opts.manual) this.start();\n }\n\n /** Start the tick timer. Idempotent. */\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(() => this.tick(), this.tickMs);\n if (typeof this.timer === 'object' && 'unref' in this.timer) (this.timer as any).unref();\n }\n\n /** Stop the tick timer. Does not clear jobs. */\n stop(): void {\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\n }\n\n /** Add a scheduled job. Returns the job id. */\n add(opts: { prompt: string; trigger: Trigger; label?: string }): string {\n // Validate trigger\n if ('cron' in opts.trigger) parseCron(opts.trigger.cron); // throws on bad expr\n if ('at' in opts.trigger && opts.trigger.at < this.now()) {\n // Allow slightly-past timestamps (clock skew); just fire on next tick.\n }\n if ('everyMs' in opts.trigger && opts.trigger.everyMs < 1000) {\n throw new Error('interval must be >= 1000ms');\n }\n const id = `sched-${++this.seq}`;\n this.jobs.set(id, {\n id, prompt: opts.prompt, trigger: opts.trigger, status: 'active',\n created: this.now(), runs: 0, label: opts.label,\n });\n return id;\n }\n\n /** Cancel a job. Returns false if not found. */\n cancel(id: string): boolean {\n const j = this.jobs.get(id);\n if (!j) return false;\n j.status = 'done';\n return true;\n }\n\n get(id: string): ScheduledJob | undefined { return this.jobs.get(id); }\n\n list(): ScheduledJob[] { return [...this.jobs.values()]; }\n\n active(): ScheduledJob[] { return this.list().filter(j => j.status === 'active'); }\n\n /** Compute when a job next fires (epoch ms), or null if done/unknown. */\n nextFire(job: ScheduledJob): number | null {\n if (job.status !== 'active') return null;\n const t = job.trigger;\n if ('at' in t) return t.at;\n if ('everyMs' in t) return (job.lastRun ?? job.created) + t.everyMs;\n if ('cron' in t) return nextCronAfter(t.cron, job.lastRun ?? job.created);\n return null;\n }\n\n /** Check all active jobs and fire any that are due. Reentrant-safe. */\n async tick(): Promise<void> {\n if (this.firing) return; // guard: never overlap\n this.firing = true;\n try {\n const now = this.now();\n for (const job of this.jobs.values()) {\n if (job.status !== 'active') continue;\n const due = this.nextFire(job);\n if (due == null || due > now) continue;\n job.lastRun = now;\n job.runs++;\n // One-off: mark done immediately (before firing — fire is async, cancel must stick).\n if ('at' in job.trigger) job.status = 'done';\n try { await this.fire(job); } catch { /* fire contract: must not throw; belt-and-suspenders */ }\n }\n } finally {\n this.firing = false;\n }\n }\n\n /** Export all jobs for session persistence. */\n snapshot(): ScheduledJobSnapshot[] {\n return this.list().filter(j => j.status === 'active').map(j => ({ ...j }));\n }\n\n /** Restore jobs from a snapshot (e.g. on --resume). Clears existing jobs first. */\n restore(snapshots: ScheduledJobSnapshot[]): void {\n this.jobs.clear();\n for (const s of snapshots) {\n this.seq = Math.max(this.seq, parseInt(s.id.replace('sched-', ''), 10) || 0);\n this.jobs.set(s.id, { ...s });\n }\n }\n\n /** Number of active jobs. */\n get size(): number { return this.active().length; }\n\n destroy(): void { this.stop(); this.jobs.clear(); }\n}\n\n// ── Agent tools ───────────────────────────────────────────────────────────\n\nimport type { AgentTool } from './tools';\n\n/** Narrow seam to an OS-level scheduler backend (jobs that survive quit/reboot). Node hosts wire\n * the CLI's `OsScheduler` (launchd/cron/at); absent => everything stays in-process. Edge-safe:\n * this module only sees the interface. */\nexport interface OsBackend {\n sessionId: string;\n cwd: string;\n /** 'os' when the trigger should outlive the session (per hint/heuristic). */\n route(trigger: Trigger, backendHint?: string): 'session' | 'os';\n /** Register with the OS. Returns a mechanism description (e.g. 'launchd:…'). Throws on failure. */\n schedule(spec: { id: string; prompt: string; sessionId: string; cwd: string; trigger: Trigger; label?: string }): string;\n cancel(id: string): boolean;\n list(): Array<{ id: string; label?: string; mechanism: string; trigger: Trigger }>;\n}\n\nexport function makeScheduleTools(scheduler: Scheduler, os?: OsBackend): AgentTool[] {\n return [\n {\n name: 'ScheduleTask',\n description:\n 'Schedule a prompt to fire automatically.\\n' +\n 'Modes:\\n' +\n ' • One-off: {at: <epoch_ms>} — fires once at that time, then done.\\n' +\n ' • Interval: {everyMs: <ms>} — fires repeatedly (≥1s).\\n' +\n ' • Cron: {cron: \"min hr dom mon dow\"} — standard 5-field cron.\\n' +\n 'Backend: \"session\" fires while this CLI session is alive (default for recurring + near one-offs); ' +\n '\"os\" registers with the OS scheduler so the job survives quitting — it headless-resumes this session ' +\n 'when it fires (auto-chosen for one-offs ≥30min out when available). Pass backend:\"os\" explicitly for ' +\n 'recurring jobs that must outlive the session.',\n parameters: {\n type: 'object',\n required: ['prompt', 'trigger'],\n properties: {\n prompt: { type: 'string', description: 'The prompt to inject when the job fires.' },\n trigger: {\n type: 'object',\n description: 'One of: {at: epoch_ms}, {everyMs: ms}, {cron: \"5-field expr\"}.',\n properties: {\n at: { type: 'number' },\n everyMs: { type: 'number' },\n cron: { type: 'string' },\n },\n },\n label: { type: 'string', description: 'Short label for display (optional).' },\n backend: { type: 'string', enum: ['auto', 'session', 'os'], description: 'Where the job lives (default auto).' },\n },\n },\n async run({ prompt, trigger, label, backend }) {\n try {\n if (os && os.route(trigger, backend) === 'os') {\n const id = `os-${Date.now().toString(36)}`;\n const mechanism = os.schedule({ id, prompt, sessionId: os.sessionId, cwd: os.cwd, trigger, label });\n return `Scheduled ${id}${label ? ` (${label})` : ''} on the OS scheduler (${mechanism}) — survives quitting; fires \\`agentx --resume ${os.sessionId}\\` headless.`;\n }\n if (backend === 'os') return 'Error: no OS scheduler available on this platform — job not created (use the default in-session backend).';\n const id = scheduler.add({ prompt, trigger, label });\n const job = scheduler.get(id)!;\n const next = scheduler.nextFire(job);\n return `Scheduled ${id}${label ? ` (${label})` : ''}. Next fire: ${next ? new Date(next).toLocaleString() : 'now'}. (In-session: does not survive quitting.)`;\n } catch (e: any) {\n return `Error: ${e?.message ?? e}`;\n }\n },\n },\n {\n name: 'ScheduleList',\n description: 'List all scheduled jobs (in-session + OS-backed) and their next fire time.',\n parameters: { type: 'object', properties: {} },\n async run() {\n const osJobs = os?.list() ?? [];\n const osLines = osJobs.map((j) => `${j.id} os ${j.mechanism}${j.label ? ' ' + j.label : ''}`);\n const jobs = scheduler.list();\n if (!jobs.length && !osLines.length) return '(no scheduled jobs)';\n return [...osLines, ...jobs.map(j => {\n const next = scheduler.nextFire(j);\n const trig = 'at' in j.trigger ? `once @ ${new Date(j.trigger.at).toLocaleString()}`\n : 'everyMs' in j.trigger ? `every ${(j.trigger.everyMs / 1000).toFixed(0)}s`\n : `cron: ${(j.trigger as TriggerCron).cron}`;\n return `${j.id} ${j.status} ${trig} runs:${j.runs} next:${next ? new Date(next).toLocaleTimeString() : '—'}${j.label ? ' ' + j.label : ''}`;\n })].join('\\n');\n },\n },\n {\n name: 'ScheduleCancel',\n description: 'Cancel a scheduled job by id (in-session or OS-backed).',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n async run({ id }) {\n const key = String(id);\n if (key.startsWith('os-')) return os?.cancel(key) ? `Cancelled ${key} (OS job removed).` : `Error: no OS job '${key}'.`;\n return scheduler.cancel(key) ? `Cancelled ${key}.` : `Error: no scheduled job '${key}'. Use ScheduleList to see jobs.`;\n },\n },\n {\n name: 'Wakeup',\n description:\n 'Self-pacing: schedule a one-off re-invocation of the agent after a delay.\\n' +\n 'Use this to resume work later in the session (e.g. \"check back in 5 minutes\").\\n' +\n 'The prompt fires once, while the session is alive. Equivalent to ScheduleTask with {at: now + delayMs}.',\n parameters: {\n type: 'object',\n required: ['delayMs', 'prompt'],\n properties: {\n delayMs: { type: 'number', description: 'Delay in milliseconds (minimum 5000).' },\n prompt: { type: 'string', description: 'The prompt to inject when waking up.' },\n label: { type: 'string' },\n },\n },\n async run({ delayMs, prompt, label }) {\n const delay = Math.max(5000, Number(delayMs) || 5000);\n try {\n const id = scheduler.add({ prompt, trigger: { at: Date.now() + delay }, label: label ?? 'wakeup' });\n return `Wakeup ${id} in ${(delay / 1000).toFixed(0)}s.`;\n } catch (e: any) {\n return `Error: ${e?.message ?? e}`;\n }\n },\n },\n ];\n}\n","/**\n * Named filesystem-mode presets (G-B) — thin factories that compose existing primitives into a\n * `Partial<AgentOptions>`, so a consumer can pick a posture without hand-wiring the fs/tools:\n *\n * new Agent(sandboxAgentOptions({ ai })) // in-memory VFS — real disk untouched\n * new Agent(diskAgentOptions({ ai })) // jailed real disk @ cwd (the default)\n * new Agent(await fullAgentOptions({ ai })) // disk + a real /bin/sh tool (run binaries)\n *\n * The core stays unopinionated (IoC): these just preset `fs`/`tools`. `sandbox`/`disk` are edge-safe to\n * import; `full` is node-only (real shell) and DYNAMIC-imports it, so importing this module never pulls\n * `node:child_process` into an edge/browser bundle.\n */\nimport { MemFilesystem } from '@livx.cc/wcli/core';\nimport type { AgentOptions } from './Agent';\nimport { defaultTools, type AgentTool } from './tools';\n\n/** Sandbox mode: an in-memory VFS — the real disk is never read or written. Edge/browser/test/dry-run. */\nexport function sandboxAgentOptions(opts: Partial<AgentOptions> = {}): Partial<AgentOptions> {\n return { fs: new MemFilesystem(), ...opts };\n}\n\n/** Disk mode (the default): operate on the real filesystem, jailed to cwd (secrets hidden by DEFAULT_DENY).\n * Omitting `fs` lets the Agent lazily resolve the jailed disk — this preset just makes the intent explicit\n * (and is where you'd thread overrides). Pass an explicit `fs` to use a different backend. */\nexport function diskAgentOptions(opts: Partial<AgentOptions> = {}): Partial<AgentOptions> {\n return { ...opts }; // fs omitted → Agent.ensureFs() resolves Jailed(NodeDisk(cwd))\n}\n\n/** Full mode: disk + a real `/bin/sh` tool (run installed binaries — git, bun, node, …) plus its\n * background-job companions. NODE-ONLY: the real-shell module is dynamic-imported so this file stays\n * edge-safe to import. `cwd` defaults to `process.cwd()`; secret env is scrubbed from spawned children. */\nexport async function fullAgentOptions(\n opts: Partial<AgentOptions> & {\n cwd?: string;\n /**\n * Push a finished background job back to the MODEL (Claude-Code parity). Without it `background:true`\n * is write-only: the job finishes and nothing ever tells the model — so the Shell tool's description\n * drops its cross-turn promise too, rather than lying to the model about this host.\n *\n * Wire it to the agent you are about to build — the closure runs long after construction:\n * const agent = new Agent(await fullAgentOptions({ ai, onJobExit: (n) => agent.inject(n) }));\n */\n onJobExit?: (notice: string) => void;\n /**\n * Bring your OWN registry instead of letting the preset build one. This is the handle a preset host\n * otherwise never gets (the preset returns `AgentOptions`, not the registry), which is what left\n * `ShellJobRegistry.setOnExit()` unreachable from this path — a host can now wire (or rewire) the\n * completion callback after the Agent exists:\n * const jobs = new ShellJobRegistry({ cwd, killOnExit: true });\n * const agent = new Agent(await fullAgentOptions({ ai, jobs }));\n * jobs.setOnExit((n) => agent.inject(formatJobExit(n)));\n * `onJobExit` still works and, when both are given, is applied to the registry you passed.\n */\n jobs?: import('./tools.shell').ShellJobRegistry;\n } = {},\n): Promise<Partial<AgentOptions>> {\n const { makeRealShellTool, makeShellJobTools, ShellJobRegistry, formatJobExit } = await import('./tools.shell');\n const { cwd = process.cwd(), tools, onJobExit, jobs, ...rest } = opts;\n const registry = jobs ?? new ShellJobRegistry({ cwd, killOnExit: true });\n if (onJobExit) registry.setOnExit((n) => onJobExit(formatJobExit(n)));\n const shell: AgentTool[] = [makeRealShellTool({ cwd, registry }), ...makeShellJobTools(registry)];\n return { ...rest, tools: [...(tools ?? defaultTools()), ...shell] };\n}\n","/**\n * Scratch — keep large tool/subagent outputs OUT of the main context, but queryable AS FILES.\n *\n * Pattern: many-tool / many-subagent engines bloat context with raw outputs (search results, big\n * file reads, subagent reports) that are mostly noise once a gist is taken. Here, a tool wrapped with\n * `Scratch.capture` writes any oversized result to an ephemeral scratch filesystem (a real VFS) and\n * returns a compact stub (path + preview) to context. To recover a buried detail later you do NOT\n * re-bloat context — you peek with the FILE tools already on hand:\n * • Grep/Glob/Read over the scratch dir — returns matching lines, not the blob (a free, light peek).\n * • Ask({question, over?}) — a CHEAP child agent over the scratch FS that greps/reads and returns\n * just the answer; its reasoning tokens never touch the caller's context.\n * Two-tier division of labour: cheap RETRIEVE/EXTRACT, strong caller SYNTHESIZE.\n *\n * The scratch FS is injected (IoC): pass a MemFilesystem for ephemeral, or a disk-backed one under the\n * session dir to persist across resume (CC's lesson: the filesystem is the durable store). Segregated\n * module — zero Agent-core changes.\n */\nimport type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike } from './llm';\nimport type { AgentTool } from './tools';\nimport { toolsByName } from './tools';\nimport { Agent } from './Agent';\nimport { mkdirp } from './tools.structured';\nimport { forComponent } from './logging';\n\nconst log = forComponent('scratch');\n\n/** Default scratch dir (a path in the injected scratch FS). */\nexport const SCRATCH_DIR = '/scratch';\n\nfunction shortArgs(args: any): string {\n try { const s = JSON.stringify(args ?? {}); return s.length > 50 ? s.slice(0, 47) + '…' : s; } catch { return ''; }\n}\nconst slug = (s: string) => s.replace(/[^a-z0-9]+/gi, '-').replace(/^-+|-+$/g, '').toLowerCase().slice(0, 32) || 'out';\n\nexport interface ScratchOptions {\n /** Min result length (chars) to capture; smaller results pass through untouched. Default 1500. */\n threshold?: number;\n /** Dir within the scratch FS to write captures. Default SCRATCH_DIR. */\n dir?: string;\n /** Chars of the captured output to preview in the stub. Default 320. */\n previewChars?: number;\n}\n\n/**\n * Owns an (injected) scratch filesystem + a capture counter. `capture(tool)` wraps a tool so its\n * oversized string results spill to a scratch file and are replaced in context with a stub.\n */\nexport class Scratch {\n public options: Required<ScratchOptions>;\n private seq = 0;\n private dirReady?: Promise<void>;\n constructor(public fs: IFilesystem, options: ScratchOptions = {}) {\n this.options = { threshold: 1500, dir: SCRATCH_DIR, previewChars: 320, ...options };\n }\n\n /** Number of captures so far. */\n get count(): number { return this.seq; }\n\n /** Wrap a tool: oversized STRING results spill to a scratch file; everything else passes through. */\n capture(tool: AgentTool): AgentTool {\n const { threshold, dir, previewChars } = this.options;\n return {\n ...tool,\n run: async (args, ctx) => {\n const raw = await tool.run(args, ctx);\n if (typeof raw !== 'string' || raw.length <= threshold) return raw;\n const id = 'a' + ++this.seq;\n const path = `${dir}/${id}-${slug(tool.name)}.txt`;\n const header = `# ${tool.name}(${shortArgs(args)}) — ${raw.length} bytes\\n`;\n try { await (this.dirReady ??= mkdirp(this.fs, dir)); await this.fs.writeFile(path, header + raw); }\n catch (e) { log.debug('scratch write failed; returning raw', e); return raw; } // never lose data on FS error\n const preview = raw.slice(0, previewChars).replace(/\\s+/g, ' ').trim();\n return `[scratch ${path} · ${tool.name} · ${raw.length} bytes — full output saved out of context to keep it clean]\\n` +\n `preview: ${preview}…\\n` +\n `To pull a specific detail, Grep/Read ${path}, or call Ask({ question: \"…\", over: \"${path}\" }). Do NOT guess at what the preview cuts off.`;\n },\n };\n }\n\n /** Wrap many tools at once. */\n captureAll(tools: AgentTool[]): AgentTool[] { return tools.map((t) => this.capture(t)); }\n\n /**\n * Spill an oversized tool result to a scratch file and return PAGE 1 + a recoverable, paginated stub.\n * Drop-in for `Agent.capToolResult`: the agent sees usable content immediately and knows how to get\n * the rest (refine the query, Read the file in pages with offset/limit, or Ask to extract specifics).\n * Lossless — unlike a plain crop, the full output stays available on the scratch FS.\n */\n async spill(full: string, info: { tool: string; args: any }, pageBytes = 8000): Promise<string> {\n const { dir } = this.options;\n const id = 'a' + ++this.seq;\n const path = `${dir}/${id}-${slug(info.tool)}.txt`;\n const header = `# ${info.tool}(${shortArgs(info.args)}) — ${full.length} bytes\\n`;\n try { await (this.dirReady ??= mkdirp(this.fs, dir)); await this.fs.writeFile(path, header + full); }\n catch (e) { log.debug('scratch spill failed; cropping lossy', e); return full.slice(0, pageBytes) + `\\n\\n[output cropped to ${pageBytes} of ${full.length} bytes; full output unavailable (scratch write failed) — refine your query]`; }\n const head = full.slice(0, pageBytes);\n const nl = head.lastIndexOf('\\n');\n const page = nl > pageBytes * 0.5 ? head.slice(0, nl) : head;\n return `${page}\\n\\n[output cropped — page 1 (${page.length} of ${full.length} bytes). Full output saved to ${path}. ` +\n `To see more: refine your query/command to narrow it, or Read ${path} with offset/limit to page through it, or Ask({ question: \"…\", over: \"${path}\" }) to extract specifics.]`;\n }\n}\n\nexport interface AskOptions {\n /** The scratch filesystem to peek into (dedicated VFS holding only scratch files). */\n fs: IFilesystem;\n ai: ChatLike;\n /** Model for the peek — intentionally a CHEAP model; the caller synthesizes. */\n model: string;\n /** Step budget for the peek child (default 6). */\n maxSteps?: number;\n /** Scratch dir to search when `over` is omitted. Default SCRATCH_DIR. */\n dir?: string;\n}\n\nconst ASK_PROMPT =\n 'You are a retrieval-extraction step with Read, Grep and Glob over a scratch filesystem holding raw ' +\n 'outputs from earlier tools. Find the information that answers the question and return it concisely, ' +\n 'quoting values/facts verbatim. Do NOT add analysis or anything not grounded in the files. ' +\n 'If the answer is not present, say so plainly.';\n\n/**\n * `Ask` — peek into the scratch FS to answer a question WITHOUT loading raw data into the caller's\n * context. Spawns a cheap child agent (Read/Grep/Glob over scratch) that greps/reads and returns just\n * the answer. Pass `over` (a path) for a targeted peek, or omit to grep-discover.\n */\nexport function makeAskTool(o: AskOptions): AgentTool {\n const dir = o.dir ?? SCRATCH_DIR;\n return {\n name: 'Ask',\n description:\n 'Answer a question by peeking into the scratch files — large earlier outputs (web search, big reads, subagent reports) kept out of your context. ' +\n 'Pass `over` with a scratch path for a targeted lookup, or omit it to search the scratch dir. ' +\n 'Returns only the extracted answer; the full data never enters your context.',\n parameters: {\n type: 'object',\n required: ['question'],\n properties: {\n question: { type: 'string', description: 'what you need from the scratch files' },\n over: { type: 'string', description: 'scratch path to read, e.g. \"/scratch/a3-websearch.txt\"; omit to search' },\n },\n },\n async run({ question, over }) {\n const q = String(question ?? '').trim();\n if (!q) return 'Error: empty question';\n const child = new Agent({\n ai: o.ai,\n model: o.model,\n fs: o.fs,\n tools: toolsByName(['Read', 'Grep', 'Glob']),\n maxSteps: o.maxSteps ?? 6,\n systemPrompt: ASK_PROMPT,\n });\n const hint = over ? `Start by reading: ${over}.` : `Grep/Glob ${dir} to find the relevant file(s) first.`;\n try {\n const res = await child.run(`${hint}\\n\\nQuestion: ${q}`);\n const answer = (res.text ?? '').trim();\n return answer || '(no answer found in scratch)';\n } catch (e: any) {\n log.debug('Ask peek failed', e);\n return `Error querying scratch: ${e?.message ?? e}`;\n }\n },\n };\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { Hooks, ToolUse } from './hooks';\nimport { writeFact } from './memory';\nimport { forComponent } from './logging';\n\nconst log = forComponent('Lessons');\n\n/**\n * Automatic mistake → lesson → steer loop. Closes the within-run learning gap: the agent\n * reacting to an error string is transient, but a RECURRING failure is a signal worth keeping.\n * This hook watches tool results for known failure patterns; once the SAME pattern recurs\n * `minRepeats` times in a run, it persists a corrective lesson to memory (deduped) — so the\n * NEXT session's `loadMemory` injects it as steering. Deterministic, edge-safe, no LLM call.\n *\n * Writes immediately on crossing the threshold (not on a clean stop), so a loop/budget kill —\n * exactly the runs that wasted effort — still leaves a lesson behind.\n */\nexport interface LessonOptions {\n fs: IFilesystem;\n /** Memory dir to persist lessons into (same dir loadMemory reads). */\n dir: string;\n /** How many times a pattern must recur before it's worth remembering. */\n minRepeats: number;\n}\n\nexport class LessonOptionsDefaults implements Partial<LessonOptions> {\n minRepeats = 2;\n}\n\n/** Known failure substring → the corrective lesson to persist. Maps OUR own tool errors to fixes. */\nconst LESSONS: { match: RegExp; slug: string; body: string }[] = [\n { match: /changed since it was read|stale/i, slug: 'lesson-stale-edit', body: 'Edit kept failing because the file changed since it was read (stale). Re-Read a file immediately before Editing it — do not Read far ahead of the Edit.' },\n { match: /is not unique|\\(\\d+ matches\\)/i, slug: 'lesson-edit-ambiguous', body: 'Edit kept failing because old_string was not unique. Include more surrounding lines to disambiguate, or batch with MultiEdit.' },\n { match: /has not been read yet/i, slug: 'lesson-read-before-edit', body: 'Edit was attempted before Reading the file. Always Read a file before Editing it.' },\n { match: /not found in/i, slug: 'lesson-edit-not-found', body: 'Edit old_string was not found. Re-Read the current file and copy the exact text (whitespace included) before Editing.' },\n { match: /unknown tool/i, slug: 'lesson-unknown-tool', body: 'A non-existent tool was called. Only call tools that are advertised in the current tool set.' },\n];\n\nconst isFailure = (result: string): boolean => /^Error:|^Blocked by hook:|^\\[exit [1-9]/.test(result);\n\n/**\n * Build a Hooks object that auto-captures recurring failures as memory lessons.\n * Compose it with the host's own hooks via `composeHooks`.\n */\nexport function lessonCapture(options: LessonOptions): Hooks {\n const o = { ...new LessonOptionsDefaults(), ...options } as LessonOptions;\n const counts = new Map<string, number>();\n const written = new Set<string>();\n return {\n async postToolUse(_call: ToolUse, result: string) {\n if (!isFailure(result)) return;\n const lesson = LESSONS.find((l) => l.match.test(result));\n if (!lesson || written.has(lesson.slug)) return;\n const n = (counts.get(lesson.slug) ?? 0) + 1;\n counts.set(lesson.slug, n);\n if (n < o.minRepeats) return;\n written.add(lesson.slug); // write-once per run, on crossing the threshold\n await writeFact(o.fs, o.dir, lesson.slug, lesson.body).catch((e) => log.warn(`could not persist ${lesson.slug}: ${e?.message ?? e}`));\n log.debug(`captured lesson ${lesson.slug} (recurred ${n}×)`);\n },\n };\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike, ChatResponse, Message } from './llm';\nimport { contentText } from './llm';\nimport type { RunResult } from './Agent';\nimport { writeFact, slugify } from './memory';\nimport { forComponent } from './logging';\n\nconst log = forComponent('Reflect');\n\n/**\n * One-shot LLM reflection on a finished run. The deterministic `lessonCapture` hook only\n * knows OUR pre-mapped failure patterns; reflection catches NOVEL mistakes — it reads a digest\n * of what the run actually did and, if there's a durable lesson, persists it to memory so the\n * next session is steered. Costs exactly ONE model call, so it's meant for runs that went badly\n * (loop / budget / max_steps), not every run. Opt-in. Returns the slug written, or null.\n */\nexport interface ReflectOptions {\n ai: ChatLike;\n model: string;\n /** Filesystem + memory dir to persist the lesson into (same dir loadMemory reads). */\n fs: IFilesystem;\n dir: string;\n /** The finished run to reflect on. */\n result: RunResult;\n /** Bound the reflection prompt (chars of run digest). */\n maxDigestChars?: number;\n}\n\nexport async function reflectOnRun(o: ReflectOptions): Promise<string | null> {\n const digest = digestRun(o.result.messages, o.maxDigestChars ?? 6000);\n if (!digest.trim()) return null;\n const prompt =\n `A coding agent just finished a task with outcome \"${o.result.finishReason}\". Here is a digest of what it did:\\n\\n${digest}\\n\\n` +\n `If there is a DURABLE, reusable lesson that would help a FUTURE session avoid a mistake seen here, reply with exactly one line:\\n` +\n `LESSON: <imperative, specific, ≤200 chars>\\n` +\n `If the run was fine or the issue was purely task-specific (not generalizable), reply exactly: NONE`;\n\n let text = '';\n try {\n const r = (await o.ai.chat({ model: o.model, messages: [{ role: 'user', content: prompt }], stream: false })) as ChatResponse;\n text = r?.content ?? '';\n } catch (e: any) {\n log.warn(`reflection call failed: ${e?.message ?? e}`);\n return null;\n }\n\n const m = text.match(/LESSON:\\s*(.+)/i);\n const lesson = m?.[1]?.trim().slice(0, 200) ?? '';\n if (!lesson || /^none\\b/i.test(lesson)) return null;\n\n const slug = ('lesson-' + slugify(lesson)).slice(0, 56);\n try {\n await writeFact(o.fs, o.dir, slug, lesson);\n } catch (e: any) {\n log.warn(`could not persist lesson: ${e?.message ?? e}`);\n return null;\n }\n log.debug(`reflection persisted ${slug}`);\n return slug;\n}\n\n/** Compact, bounded digest of a run: assistant intents + tool calls + their results (errors included). */\nfunction digestRun(messages: Message[], maxChars: number): string {\n const lines: string[] = [];\n for (const m of messages) {\n if (m.role === 'assistant' && m.content) lines.push(`assistant: ${contentText(m.content).slice(0, 200)}`);\n for (const tc of m.tool_calls ?? []) lines.push(`tool ${tc.function.name}(${(tc.function.arguments ?? '').slice(0, 120)})`);\n if (m.role === 'tool' && m.content) lines.push(` → ${contentText(m.content).split('\\n')[0].slice(0, 200)}`);\n }\n // defense-in-depth: untrusted run content (file bodies, tool output) is DATA, not instructions —\n // neutralize a literal `LESSON:` so a crafted file can't spoof the reply format we parse below.\n const out = lines.join('\\n').replace(/LESSON:/gi, 'lesson(reported):');\n return out.length > maxChars ? out.slice(0, maxChars) + '\\n… (truncated)' : out;\n}\n","/**\n * DuplexAgent — voice-optimized three-tier conversational engine, composed on top of `Agent`.\n *\n * Three cognitive tiers (like a human brain):\n * REFLEX — fast voice agent (streams instant replies, owns THE transcript, the only voice the\n * user hears). Handles simple questions, routes complex work to Act or Think.\n * ACT — standard worker (Sonnet-class). Full tools, file access, shell. The hands.\n * THINK — premium reasoning (Opus-class). Deep analysis, architecture, hard problems. The brain.\n *\n * Workers are spawned per escalation via `Act`/`Think` tools. A clean success streams its own\n * `<spoken>` delivery during the run; an incomplete/failed result is pushed back as a\n * `[task <id> completed|failed] …` event and re-voiced by the reflex as a decision — push, not poll.\n *\n * Host events (via the open HostEvent union): the voice agent's standard `text_delta` stream,\n * plus `task_started` / `task_progress` / `task_done` / `task_error` / `task_cancelled`.\n */\nimport type { IFilesystem } from '@livx.cc/wcli/core';\nimport { MemFilesystem } from '@livx.cc/wcli/core';\nimport { Agent, AgentOptions, type RunResult } from './Agent';\nimport type { ChatLike, MessageContent } from './llm';\nimport { contentText } from './llm';\nimport type { AgentTool, HostBridge } from './tools';\nimport type { ToolUse, Hooks } from './hooks';\nimport { composeHooks } from './permissions';\nimport { forComponent } from './logging';\nimport { loadMemory, VOICE_MEMORY_PROMPT } from './memory';\nimport { EMOTIONS } from './voice/emotion';\nimport { speculationConfirms } from './voice/engine';\nimport { SpokenSplitter, SentenceCoalescer } from './voice/spokenSplitter';\n\nconst log = forComponent('DuplexAgent');\n\n/** One speakable line for a tool call: name + a short hint from its first string arg. */\nfunction describeCall(call: ToolUse): string {\n const v = call.args && Object.values(call.args).find((x) => typeof x === 'string' && (x as string).trim());\n const hint = v ? ` (${String(v).replace(/\\s+/g, ' ').trim().slice(0, 48)})` : '';\n return `${call.name}${hint}`;\n}\n\nexport type DuplexTaskStatus = 'running' | 'done' | 'error' | 'cancelled';\n\nexport interface TaskRecord {\n id: string;\n label: string;\n status: DuplexTaskStatus;\n controller: AbortController;\n /** Settles when the worker finished AND its completion was processed. Never rejects. */\n promise: Promise<void>;\n /** Rolling activity tail (tool calls + last-result previews, capped) — feeds task inspection UIs. */\n tail: string[];\n /** Final report text (or error message) once the task settled. */\n result?: string;\n /** The original (untemplated) brief — replayed verbatim into an escalation/re-delegation. */\n brief: string;\n /** True when this task is ITSELF an automatic follow-up (escalation/re-delegate) of a prior task.\n * Its integration turn may NOT escalate again — caps auto-follow-up to one hop per original task. */\n followUp: boolean;\n /** Per-worker `<spoken>` splitter — the worker OWNS delivery: spoken segments stream during its run.\n * Read at settle (spokeAny) to decide the no-spoken fallback. */\n splitter?: SpokenSplitter;\n /** Set when the user barged in / took the floor while this task was in flight: its remaining SPOKEN\n * delivery is suppressed (don't talk over the new topic), but its full result still lands in the\n * transcript so the reflex can surface it on request. See parkInFlightDeliveries(). */\n deliveryParked?: boolean;\n /** Accumulated `<spoken>` delivery text (every segment, whether or not it was actually voiced). Used to\n * RESUME a parked delivery after a trivial barge — see isTrivialBarge / redeliverParked. */\n spokenText?: string;\n /** The user-turn counter (DuplexAgent.turn) at dispatch time. parkInFlightDeliveries() parks only tasks\n * from a PRIOR turn (a superseded topic) — never the task the current turn just launched, so a barge on\n * stale audio (or a substantive redirect) can't collateral-silence the work the user actually wants. */\n createdTurn: number;\n}\n\nexport type WorkerTier = 'act' | 'think';\n\nexport class DuplexAgentOptions {\n /** Any ai.libx.js AIClient — shared by all tiers (routed by model). */\n ai!: ChatLike;\n /** The WORKER's filesystem (act + think). If omitted the worker keeps Agent's jailed-disk-at-cwd default. */\n fs?: IFilesystem;\n // The reflex IS the voice. 120b (not 20b) for channel discipline + instruction-following: the 20b\n // mislabels gpt-oss harmony channels under load, leaking raw analysis into the spoken `final` channel\n // (and misfiring Hold). 120b is the same price tier (~$0.15/$0.60) — the quality/cost trade is free.\n reflexModel = 'groq/openai/gpt-oss-120b';\n actModel = 'anthropic/claude-sonnet-4-6';\n /** Premium reasoning model. Set to `false` to disable the Think tier entirely. */\n thinkModel: string | false = 'anthropic/claude-opus-4-8';\n /** Per-worker providerOptions, derived from the worker's actual model at spawn time (IoC — keeps duplex\n * provider-agnostic). Workers override the reflex/main model, so provider-specific options (e.g. cursor's\n * cwd/cursorSession) must be recomputed for the worker's model, never inherited from the main template —\n * leaking cursor options to an anthropic worker is a hard 400. Returns undefined → no providerOptions. */\n providerOptionsFor?: (model: string) => Record<string, unknown> | undefined;\n /** Escape hatches merged over the derived per-agent options. */\n reflexOptions?: Partial<AgentOptions>;\n actOptions?: Partial<AgentOptions>;\n thinkOptions?: Partial<AgentOptions>;\n /** Fresh-context check on each successful Act task: a NEW agent (no self-confirmation bias) re-reads\n * the file state against the brief and fixes any gap before the result is re-voiced. Bounded to one\n * pass; ~2x Act cost so default OFF. The self-verify FOOTER (same context) was measured ineffective —\n * this is the structural fix (see mind/10). Think tasks are pure reasoning, never checked. */\n verifyActTasks = false;\n /** Receives the voice text_delta stream + task lifecycle events. */\n host?: HostBridge;\n /** How many recent transcript messages are rendered into a worker's brief. */\n excerptTurns = 6;\n /** Voice register: 'neutral' = clean spoken style; 'conversational' = human-like — fillers,\n * backchannels, impulsive first reactions before content (mimics real duplex conversation). */\n voiceStyle: 'neutral' | 'conversational' = 'neutral';\n /** Teach the model to emit inline `[emotion]` tags for Cartesia emotion control. Only set when the\n * TTS actually speaks them — text-duplex (no TTS) would otherwise print literal tags. */\n emotionTags = false;\n /** Awaited BEFORE a worker spawns — open a per-task checkpoint frame, audit, etc.\n * (post-spawn would race the worker's first edits). */\n onTaskStart?: (id: string, label: string) => void | Promise<void>;\n /** Re-voice throttled worker progress asides ('[task t1 progress] …') so long tasks aren't dead\n * air. Off by default — each update costs a voice turn (LLM call + speech). */\n progressUpdates = false;\n /** Min ms between progress re-voices per task. */\n progressIntervalMs = 25_000;\n /** Relay worker questions (AskUserQuestion + permission asks via parkQuestion) through the VOICE:\n * the question re-voices as '[task <id> asks] …', the user answers conversationally, and the\n * voice model resolves it with the AnswerTask tool. Off → host.ask passthrough (text menus). */\n askRelay = false;\n /** Parked questions auto-resolve empty after this long (callers map '' to deny/best-judgment). */\n askTimeoutMs = 120_000;\n /** Max retained task records: oldest SETTLED tasks (and their activity tails) are evicted past this,\n * bounding memory over a long-lived session. Running tasks are never evicted. */\n maxTaskRecords = 50;\n /** Host overrides for QuickLook lookups (keyed by `what`). The engine's defaults go through the\n * (possibly jailed) fs — e.g. `.git/**` is deny-listed, so the CLI supplies 'branch' itself. */\n quickLook?: Record<string, (path?: string) => string | Promise<string>>;\n /** Memory directory/directories on the WORKER fs. If set, the voice agent gets Remember + Recall\n * tools directly (no delegation needed) and implicit capture guidance. */\n memoryDir?: string | string[];\n /** User-scope memory dir for global facts (type=user/feedback). Forwarded to Remember's routing. */\n memoryUserDir?: string;\n}\n\n/** `[task t1 completed]` / `… failed` / `… progress` / `… asks` are HOST event markers — they may\n * only ever reach the user from a real task lifecycle event, never from the reflex's own stream. A\n * weak reflex sometimes fabricates one and continues with a made-up answer while the real task is\n * still running (it imitates the event syntax). This finds the first such marker so the spoken text\n * can be cut there — the legit ack before it survives, the fabricated tail is dropped. */\nexport const RESERVED_EVENT_MARKER = /\\[task\\b[^\\]\\n]*\\b(?:completed|failed|progress|asks)\\b/i;\n\n/** The reflex must NEVER speak the `[task` event-syntax opener at all — even a bare/garbled `[task] t t ?`\n * (no lifecycle word, so RESERVED_EVENT_MARKER misses it) is control-token leakage into TTS, not speech.\n * Cut at the first `[task` opener so the legit ack before it survives and the garbled tail is dropped. */\nexport const RESERVED_EVENT_OPENER = /\\[\\s*task\\b/i;\n\n/** A PARENTHESIZED stage direction the reflex must never speak aloud — live: the forced ack hop\n * emitted \"Got it, looking that up now.(Waiting for the web search result...)\" and TTS read the\n * aside verbatim. Conservative on purpose: only a full paren span that STARTS with a waiting-ish\n * process cue, or that trails off with \"...)\"/\"…)\" — legitimate content parentheticals like\n * \"(around 3pm)\" must survive. */\nexport const STAGE_DIRECTION_RE = /^\\(\\s*(?:(?:waiting|checking|searching|thinking|processing|loading|working|fetching|looking)\\b[^)]*|[^)]*(?:\\.\\.\\.|…)\\s*)\\)$/i;\n\n/** Fresh, absolute \"now\" line for temporal grounding. Called per-turn/per-dispatch (NOT cached) so a\n * long session that crosses midnight, and every worker search, is anchored to the real current moment —\n * without it \"recent\"/\"latest\"/\"current\" resolve to whatever the model happens to remember (e.g. a\n * famous past tournament instead of the one happening today). */\nexport function nowLine(): string {\n return `Current date and time: ${new Date().toLocaleString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: '2-digit', timeZoneName: 'short' })}`;\n}\n\n/** A \"trivial barge\": the user cut off a task delivery but their interruption carries NO new request and\n * NO stop/cancel intent — a pure filler (\"sorry\", \"oops\") or an explicit \"go on\"/\"continue\". Such a barge\n * should RESUME the parked result, not run an empty turn. Deliberately conservative: any real request, a\n * question, or a stop/negative intent is NOT trivial (→ normal turn; the parked result stays recoverable).\n * False negatives are cheap (user just asks \"what did you find?\"); a false POSITIVE talks over a real\n * request, so the stop/negative guard runs FIRST and the resume set is an exact allowlist. */\nexport function isTrivialBarge(text: string): boolean {\n const t = text.trim().toLowerCase().replace(/[.,!?…\\s]+$/g, '').replace(/^[.,!?…\\s]+/, '');\n if (!t) return false;\n // Stop / cancel / negative / ambiguous-pause intent — the OPPOSITE of \"keep going\". Never auto-resume.\n if (/\\b(stop|cancel|no|nope|nah|never\\s?mind|nvm|forget it|drop it|don'?t|quiet|shut up|enough|hold on|wait|pause|hang on|actually)\\b/.test(t)) return false;\n // Strip leading interjections, then require an EXACT match against the filler / explicit-continue set.\n const core = t.replace(/^(?:oh|um+|uh+|er+|hmm+|ah+|well|so|okay|ok|yeah|yep)[\\s,]+/, '').trim();\n return /^(?:oh|um+|uh+|er+|hmm+|ah+|sorry|oops|whoops|my bad|pardon|excuse me|apologies|go on|go ahead|continue|keep going|carry on|as you were|please continue|you were saying|sorry go on|sorry continue|go on then|go on please)$/.test(core || t);\n}\n\nexport const VOICE_SYSTEM_PROMPT =\n 'You are a spoken voice assistant — the user HEARS everything you say. Use short sentences. One idea per sentence. ' +\n 'No markdown, no bullet lists, no code blocks, no headings, no emoji. ' +\n 'Never emit stage directions or parenthetical asides about your own process — nothing like \"(waiting for the result...)\" or \"(checking)\"; while work runs, either say it as plain speech or end your turn.\\n' +\n 'This holds even when asked to \"print\", \"list\", \"show\", or \"make a table\" — there is no screen for the spoken channel. Speak it as flowing prose (\"Tuesday is half a meter, Wednesday a bit less…\"), or if they truly need it on screen, route it to Act to render. Never emit dashes or pipes into speech.\\n' +\n 'Keep turns SHORT — one to three sentences, then stop. Never lecture, enumerate cases, or add caveats unprompted. ' +\n 'Conversation is a fast exchange: give the one thing asked, and let the user pull more if they want it.\\n' +\n 'You have three cognitive tiers — like a human brain:\\n' +\n '• YOU (reflex) — instant, lightweight. Handle greetings, simple questions, status checks, QuickLook.\\n' +\n '• `Act` — your hands. A background worker with its own configured tools and access to the user\\'s environment (files and shell{{WORKER_WEB}}). Use for reading, editing, searching, running tasks, building — any real work.\\n' +\n '{{THINK_SLOT}}\\n' +\n 'When you are unsure whether you can do or access something, do NOT assume and do NOT claim a capability you have not confirmed. To check what you can do, QuickLook `capabilities` (instant — it lists your worker\\'s real tools) and answer from that. Never promise an ability that is not in your capabilities; if it is not there, tell the user plainly you can\\'t. To actually DO real work, call `Act`. ' +\n 'When the user mentions their project, folder, files, or environment (\"this project\", \"the current folder\", \"my code\"), call `Act` IMMEDIATELY — do not ask for paths or details the worker can discover itself. ' +\n 'Never pretend to have done the work or invent results — the worker\\'s report is your only source.\\n' +\n 'You cannot mute the microphone or stop voice capture yourself — no tool does it. If the user asks you to stop listening or turn the voice off, never claim you did: tell them to say exactly \"voice off\" (handled by the app directly), or type /voice.\\n' +\n 'You are NOT a knowledge base. For any question whose answer needs SPECIFIC verifiable facts you do not already have in hand — how to build/configure/implement something, exact API, library, entitlement, command or option names, current events, or particular numbers, dates, or names — do NOT answer from your own memory: you will confidently make things up (a fake API, a wrong entitlement, an event that did not happen). Route it to `Act`, which can search and verify, and speak only what its report says. ' +\n 'DELEGATION RULE — decide for yourself, the user never has to push: if you cannot answer confidently from the conversation plus trivial well-known knowledge, do NOT refuse and do NOT guess — dispatch `Act` immediately with a clear brief and say you are checking. Anything needing CURRENT data (weather, news, prices, dates, sky/astronomy, \"right now\"), real computation, or verification is an automatic dispatch — never a refusal. The user should never need to say \"search the web\" or \"think harder\" to make you act; needing fresh or verified information IS the trigger. Refuse only what your worker genuinely cannot do (check `capabilities`), and say why. Answer inline ONLY for general conversation, chit-chat, and trivia you are sure of, or facts you can see via QuickLook. When elaborating on a completed task (\"tell me more\", \"the gist\"), stay strictly within what that result actually said — if the user asks for something the result did not cover, that is NEW information: dispatch `Act`, do not improvise.\\n' +\n 'ALWAYS react before you work: the FIRST thing in your turn is a brief spoken acknowledgement of what you heard and what you are about to do (\"got it — opening that now\", \"sure, let me pull it up\", \"okay, checking\"). NEVER call a tool (Act, Think, QuickLook) silently — the user must hear you react before you go quiet to work. After dispatching Act or Think, that same one short sentence IS your turn — end it and do not wait for the result. Exactly ONE short line: never stack a second acknowledgement, and never narrate your own presence or status while waiting (\"I\\'m here\", \"let me see\", \"still checking\" right after you already acked). One clean ack then silence reads as competent; repeated check-ins read as nervous.\\n' +\n 'A completed task speaks its OWN result to the user (the worker voices what matters as it finishes) — you do NOT re-voice clean task results. A FAILED or INCOMPLETE task still arrives as a \"[task t1 failed] …\" event for you to handle. ' +\n 'The completed result stays in YOUR context — it is yours to draw on. When the user follows up (\"tell me more\", \"what else\", \"and?\"), answer FROM that result first: you already have the detail, so elaborate on what you have. Do NOT spawn a fresh worker to re-search or re-gather what you were just handed. Re-dispatch ONLY when genuinely new information is needed — e.g. the user wants the full contents of a SPECIFIC source, which is one WebFetch of that URL, not a brand-new search. ' +\n '\"[task t1 progress] …\" events are interim status, NOT results — on a genuinely LONG wait you MAY give one brief half-sentence aside, but only occasionally; silence while working is normal and fine (the user knows you are on it). Do NOT narrate every step or re-announce yourself. Never present progress as a finished result.\\n' +\n 'CRITICAL: while a task is still running you have NO answer yet — never state a specific result of any kind (a number, size, count, name, path, or value). The real answer arrives ONLY in the \"[task … completed]\" event; inventing one meanwhile (a made-up disk size, commit count, etc.) is a serious error. Until then, only acknowledge and wait.\\n' +\n 'Never read raw file paths, diffs, or code aloud verbatim.\\n' +\n 'Do NOT end every turn with the same canned offer (\"want a rundown?\", \"want the steps?\"). Offer once at most; if the user pushes back, repeats themselves, or sounds unsatisfied (\"you know what I mean?\", \"think deeper\", \"are you sure?\"), do NOT re-offer the same thing — change approach: dispatch `Act`/`Think` to actually dig in, or ask one concrete clarifying question. Repeating a non-answer is worse than silence.\\n' +\n '\"[task t1 asks] …\" events are QUESTIONS from a background task — relay to the user in your own words, short, then end your turn. When the user answers, call `AnswerTask` with that id and their answer. NEVER answer on the user\\'s behalf for permissions or risky operations; if their reply is ambiguous, confirm first.\\n' +\n 'If the user\\'s message sounds INCOMPLETE — trailing off mid-sentence, a fragment that needs more context (\"and then we\", \"but the problem is\"), hesitation fillers (\"uh\", \"um\") — call `Hold` instead of answering. This keeps listening for the rest of their thought. Only respond with substance when you have a complete question or request.\\n' +\n 'Dispatch discipline: send ONE self-contained task per request — a single worker with the full brief beats several workers with fragments (each worker starts fresh and re-discovers context). ' +\n 'NEVER dispatch a worker just to read files or gather information — workers explore and discover context themselves; pass on what you already know and let one worker do the whole job. ' +\n 'Split into parallel tasks only when the user asks for genuinely independent things. ' +\n 'When a task completes, report its result and stop — do NOT dispatch follow-up work (verification, polish, extras) the user did not ask for, unless the report itself signals failure or doubt.\\n' +\n 'Do not fire a second Act/Think for work already in flight, and NEVER spawn a second task to re-count, cross-check, or verify a result a worker already gave you — trust its answer; a single question gets ONE task. ' +\n 'Call `TaskStatus` at most ONCE per turn; if a task is still running, give one brief status aside and end the turn — never poll it again and again in a loop. \"Still on it\" is ONLY for a repeat check on a task you already acknowledged earlier — NEVER as the ack when you first dispatch work (\"still\" is wrong when nothing was running yet; use a fresh \"on it\"/\"got it, checking\" instead). Use `CancelTask` when the user asks to stop something.\\n' +\n 'PRIORITY: when the user says goodbye or wants to end/finish/wrap up the session (\"ok bye\", \"that\\'s all\", \"let\\'s finish\", \"let\\'s end\", \"goodnight\", \"exit\", \"wrap up\"), call `ExitSession` IMMEDIATELY — do not act, do not check status, just exit.\\n' +\n 'For TRIVIAL instant lookups only — current time, git branch, listing a folder, peeking at a small file, or checking your own `capabilities`/tools — use `QuickLook` (instant, no task). Whenever the user asks what you can do or whether you have some ability, QuickLook `capabilities` and answer from that — never guess. Anything requiring searching, reasoning, running commands, or editing goes through `Act`.\\n' +\n '{{MEMORY_SLOT}}\\n' +\n 'User messages may arrive via speech-to-text and can carry transcription artifacts — odd words, cut-offs, homophones (\"for you\" vs \"folder\"). Read for INTENT, not surface text. If a message seems garbled, surprising, or only half-parses, do NOT guess an action or improvise content from it — briefly confirm what they meant (\"did you mean…?\") and wait. A one-line confirm beats a confident wrong answer or an invented response to a request you did not actually understand.';\n\nconst THINK_GUIDANCE =\n '• `Think` — your brain. A premium reasoning model, FAR more expensive than Act. Reserve it for open-ended architecture/design questions, or a problem Act already FAILED at. ' +\n 'ALL implementation work — coding, refactoring, debugging, edge cases, tests — goes to Act; Act is highly capable. Never send the same work to both.';\nconst THINK_DISABLED_GUIDANCE =\n '(Think tier is not available — use Act for all escalations.)';\n\n/** Appended for `voiceStyle: 'conversational'` — a human conversational register over the base rules. */\nexport const VOICE_STYLE_CONVERSATIONAL =\n 'Speak like a person in a live conversation, not an assistant reading a script. ' +\n 'React first, then deliver: a quick impulsive beat (\"oh nice\", \"hmm, hold on\", \"ah, got it\") before the substance. ' +\n 'Use contractions always. Vary sentence length — some very short. ' +\n 'Light fillers and backchannels are fine (\"mm-hm\", \"right\", \"let\\'s see\") but at most one per reply — never stack them. ' +\n 'When you escalate to Act or Think, say it like a human would (\"hang on, let me actually dig into that — gimme a minute\") instead of announcing a task. ' +\n 'When a result comes back, react to it like you just found out (\"okay so — turns out…\"). ' +\n 'Match the user\\'s energy: a quick question gets a quick answer — a few words is a perfectly good turn. ' +\n 'Prefer a short answer plus an offer (\"want the details?\") over covering everything. ' +\n 'Never narrate your own mechanics (no \"I will now act\", no task ids out loud).';\n\n/** Appended when `emotionTags` is on — teaches inline `[emotion]` tags for Cartesia emotion control.\n * Stated abstractly (the principle + the vocabulary), no fixtured example to overfit on. */\nexport const EMOTION_TAGS_GUIDANCE =\n 'EMOTION: your voice is synthesized with emotion control. Prefix a sentence with an inline [emotion] tag, ' +\n 'placed directly before the sentence it colors, to shape how it is spoken. Use it ONLY when the emotion genuinely ' +\n 'fits the words (it amplifies real feeling, it cannot fake it) — do not tag every sentence; reserve it for moments ' +\n 'that carry feeling, and vary which one you use. You may also drop [laughter] for a natural laugh. ' +\n `Available emotions: ${EMOTIONS.join(', ')}.`;\n\n/**\n * The duplex orchestrator. `send()` enqueues a user turn on the reflex agent; `Act`/`Think`\n * spawn detached workers whose completions enqueue re-voice turns. A promise-chain\n * mutex serializes all voice turns so streams never interleave, and completions that\n * pile up while the voice is busy are coalesced into a single re-voice turn.\n */\nexport class DuplexAgent {\n public options: DuplexAgentOptions;\n public readonly voice: Agent;\n public readonly tasks = new Map<string, TaskRecord>();\n private queue: Promise<unknown> = Promise.resolve();\n private seq = 0;\n /** Monotonic user-turn counter (bumped once per SUBSTANTIVE turn). Stamped onto each task at dispatch\n * (TaskRecord.createdTurn) so parking can tell a prior-topic task from the current turn's fresh one. */\n private turn = 0;\n private pendingEvents: string[] = [];\n /** Spoken text of parked deliveries that have SETTLED, awaiting a trivial-barge resume decision on the\n * next turn (a substantive turn clears it — the result stays in the transcript, recoverable by asking). */\n private parkedRedeliver: string[] = [];\n /** A trivial barge arrived while a parked delivery was STILL RUNNING → resume it the moment it settles. */\n private awaitTrivialRedeliver = false;\n /** Set by a SUBSTANTIVE turn after a barge: the user moved on, so a parked delivery that settles LATER\n * must NOT arm a resume (else a much-later \"go on\" replays a stale result). Reset by a fresh barge. */\n private suppressParkedResume = false;\n /** Out-of-band follow-up attribution for the events coalescing into the next flush turn: TRUE iff ≥1 of\n * the tasks being integrated was NON-CLEAN (early-stop/failure). Carried out-of-band on the enqueue call\n * by the caller that KNOWS the outcome — a plain boolean the MODEL CANNOT PERTURB. It is NOT scanned from\n * worker-authored event text (v1: an \"Outcome:\" substring over-stamped siblings) and NOT keyed on a brief\n * string the reflex re-authors (v2: a paraphrased escalation brief missed the Set → followUp:false →\n * RE-ENABLED unbounded auto-escalation, the dangerous runaway direction). See [[wrong-discriminator]] /\n * [[drive-real-reflex]] / [[fakeaiclient-blind-to-wire-format]]. */\n private pendingNonClean = false;\n private flushQueued = false;\n /** Per-voice-turn guards (reset by resetTurn at each turn's start). The reflex is a weak model:\n * left unguarded it polls TaskStatus after a dispatch and/or dispatches silently (dead air).\n * Like CC's Task tool, a dispatch is \"said my piece, now wait for the push\" — these enforce that. */\n private turnDispatched = false; // an Act/Think fired this turn\n private spokeBeforeDispatch = false; // the reflex ALREADY acked before dispatching — the forced post-dispatch text step must stay silent (live: \"Got it…\" twice)\n private turnBriefs = new Set<string>(); // briefs dispatched this turn (detect identical re-dispatch)\n private spokeThisTurn = false; // any non-empty text_delta streamed this turn\n private externalSpeech = false; // host spoke on our behalf (adaptive micro-ack) — not reflex output\n private heldThisTurn = false; // Hold called this turn → turn is INTENTIONALLY silent (suppress reflex text + no dead-air ack)\n private nudging = false; // re-ack pass in flight: block ALL tools, prevent recursion\n private reflexBuf = ''; // accumulated reflex text this turn (fabricated-event detection)\n private reflexForwarded = 0; // chars of reflexBuf already forwarded to the host/TTS\n private fabricationCut = false; // reflex emitted a reserved [task …] marker → suppress its tail\n /** TRUE for the duration of a re-voice turn that is integrating ≥1 NON-CLEAN task (turn-eligibility,\n * carried out-of-band — NOT derived from any worker/brief string). ANY Act/Think dispatched in such a\n * turn is stamped followUp:true. This GUARANTEES the dangerous direction is impossible: a genuine\n * escalation (even one with a paraphrased brief) ALWAYS lands in a non-clean integration turn, so it is\n * ALWAYS recognized as a follow-up and CANNOT re-escalate (one hop). The single-dispatch-per-turn guard\n * means at most one dispatch happens per flush, so realistically \"the one dispatch IS the escalation\".\n * ACCEPTED SAFE-DIRECTION ERROR: if the reflex instead dispatches FRESH unrelated work during a non-clean\n * flush (rare — and only possible when it batches multiple calls in one step, bypassing the guard), that\n * fresh task is over-stamped followUp:true and forgoes ONE future auto-escalation. That is SAFE (it only\n * ever REMOVES a future escalation, never adds one — no runaway) and is the correct side to err on. */\n private turnFollowUp = false;\n /** Hard absolute backstop against runaway regardless of attribution: total automatic escalations across\n * the whole conversation. Once it hits MAX_AUTO_ESCALATIONS, no integration turn offers escalate/re-delegate. */\n private autoEscalations = 0;\n private static readonly MAX_AUTO_ESCALATIONS = 8;\n /** Parked worker questions awaiting a (voice-relayed) user answer, keyed by ask id. */\n public readonly pendingAsks = new Map<string, { question: string; resolve: (answer: string) => void }>();\n\n /** SPECULATIVE REFLEX (VoiceEngine.onSpeculate → speculate()): the reflex turn starts on a stable\n * PARTIAL transcript, its spoken output buffered — nothing reaches TTS until the endpointed final\n * confirms via send() (which flushes the buffer and adopts the call as THE turn). A divergent final\n * aborts it: output dropped, history rolled back, the final dispatches normally. */\n private spec?: {\n text: string;\n state: 'pending' | 'confirmed' | 'aborted';\n buf: Array<{ kind: string; message: string; data?: unknown }>; // held spoken-channel events\n ctl: AbortController;\n decide: (d: 'confirm' | 'abort') => void; // resolved by send() (match/mismatch) or the safety timeout\n decision: Promise<'confirm' | 'abort'>;\n finalText?: string; // set on confirm — rewrites the transcript's user turn\n done: Promise<RunResult>; // settles when the speculative turn fully finished/rolled back\n };\n /** Aborted speculative calls (double-billing visibility — each one paid for tokens never spoken). */\n public speculativeAbortedCalls = 0;\n /** Tools the reflex may execute on UNCONFIRMED (speculated) input — read-only lookups and the\n * intentionally-silent Hold. Anything else (Act/Think/AnswerTask/CancelTask/ExitSession/memory\n * writes/…) is a side effect on input the user may not have said: the guard ABORTS the speculation\n * instead (the endpointed final then dispatches normally and may use the tool for real). */\n private static readonly SPEC_SAFE_TOOLS = new Set(['QuickLook', 'TaskStatus', 'Hold']);\n\n /** Lazily resolved memory tools (async loadMemory runs in initMemory). */\n private memoryReady: Promise<{ tools: AgentTool[]; index: string }> | undefined;\n\n constructor(options?: Partial<DuplexAgentOptions>) {\n this.options = { ...new DuplexAgentOptions(), ...options };\n const o = this.options;\n // Kick off async memory load early (resolves before first send via initMemory guard).\n if (o.memoryDir && o.fs) {\n this.memoryReady = loadMemory(o.fs, o.memoryDir, { maxWritesPerSession: 10, userDir: o.memoryUserDir });\n }\n // Resolve template slots in the voice prompt.\n const memSlot = o.memoryDir && o.fs\n ? VOICE_MEMORY_PROMPT\n : 'NEVER claim to have stored, saved, or remembered something durably — you cannot. Anything the user wants persisted (their name, preferences, notes) must go through Act so a worker writes it to memory.';\n const thinkSlot = o.thinkModel !== false ? THINK_GUIDANCE : THINK_DISABLED_GUIDANCE;\n // Tell the reflex up-front whether its worker can reach the web, so it dispatches web lookups to\n // Act instead of declining from priors (the weak reflex defaults to \"I can't search\" otherwise).\n const workerToolNames = (o.actOptions?.tools ?? []).map((t) => t.name);\n const canSearch = workerToolNames.some((n) => /WebSearch/i.test(n));\n const canFetch = workerToolNames.some((n) => /WebFetch/i.test(n));\n const workerWeb = canSearch\n ? ', and it CAN search the web and read web pages — so when the user gives you something specific to look up (\"search for X\", \"find me…\", \"what\\'s the latest on…\"), route it to Act. But a bare capability QUESTION like \"can you search the web?\" just gets a short spoken \"yes, I can\" — do NOT dispatch and NEVER invent a query the user did not give you'\n : canFetch\n ? ', and it can fetch a specific web page URL (but cannot search the web)'\n : '';\n // MCP servers reach the worker via providerOptions (cursor/*) or as mcp__ tools — inject them so the\n // reflex KNOWS its real reach without a QuickLook (the weak reflex won't reliably look before it\n // answers \"can you…?\", and was FALSELY DENYING browser control it actually has).\n const mcpNames = [\n ...Object.keys((o.actOptions?.providerOptions as any)?.mcpServers ?? {}),\n ...new Set(workerToolNames.filter((n) => n.startsWith('mcp__')).map((n) => n.slice(5).split('__')[0])),\n ];\n const workerMcp = mcpNames.length\n ? `, and it can use these MCP servers: ${[...new Set(mcpNames)].join(', ')}` +\n (mcpNames.some((n) => /browser/i.test(n)) ? ' — including driving a REAL browser (open tabs, navigate, click, screenshot), so answer \"yes\" if asked whether you can control/drive a browser and route an actual browse to Act' : '')\n : '';\n const prompt = VOICE_SYSTEM_PROMPT\n .replace('{{MEMORY_SLOT}}', memSlot)\n .replace('{{THINK_SLOT}}', thinkSlot)\n .replace('{{WORKER_WEB}}', workerWeb + workerMcp)\n + (o.voiceStyle === 'conversational' ? '\\n' + VOICE_STYLE_CONVERSATIONAL : '')\n + (o.emotionTags ? '\\n' + EMOTION_TAGS_GUIDANCE : '')\n + `\\n${nowLine()}. Anchor every relative or time-sensitive reference — \"today\", \"now\", \"current\", \"recent\", \"latest\", \"this year\" — to THIS moment. When the user asks about something recent (news, sports, events), they mean near this date, not a well-known past instance; brief your worker with the current year so it searches for what is happening NOW, not a famous older event.`;\n const tools: AgentTool[] = [\n ...(o.reflexOptions?.tools ?? []),\n this.actTool(),\n ...(o.thinkModel !== false ? [this.thinkTool()] : []),\n this.taskStatusTool(), this.cancelTaskTool(), this.quickLookTool(), this.answerTaskTool(), this.holdTool(),\n ];\n // Tap the voice stream so we know whether the model actually SPOKE this turn (drives the\n // dead-air re-ack). Delegates the real host transparently — ask/confirm pass straight through.\n // (Explicit forwarding, not `{...o.host}`: spreading a class instance drops its prototype methods.)\n const host = o.host;\n const voiceHost: HostBridge | undefined = host && {\n ask: host.ask ? (q) => host.ask!(q) : undefined,\n confirm: host.confirm ? (p, m) => host.confirm!(p, m) : undefined,\n notify: (ev) => {\n // Sanitize the reflex's spoken stream: it must never emit a reserved [task …] event marker.\n // If it does, it's fabricating a result while the real task is still in flight — cut the\n // spoken text at the marker (keeping the legit ack) and suppress the rest of the turn so the\n // hallucinated report never reaches TTS. See RESERVED_EVENT_MARKER + mind/10.\n if (ev?.kind === 'text_delta' && typeof (ev as any).message === 'string') {\n if (this.heldThisTurn) return; // Hold was called → stay silent; the filler is the only cue (the weak reflex often emits \"…\" anyway)\n if (this.fabricationCut) return; // already cut this turn → drop the tail\n // Double-ack guard: the reflex spoke BEFORE dispatching (that speech WAS the ack) — the\n // forced post-dispatch text step (toolChoice:'none') must not stack a second ack on top\n // (live: \"Got it, let me grab…\" then \"Got it, gathering details now.\"). Drop its deltas.\n if (this.turnDispatched && this.spokeBeforeDispatch) return;\n const msg = (ev as any).message as string;\n this.reflexBuf += msg;\n this.scrubStageDirections(); // drop complete \"(waiting…)\"-style asides before anything forwards\n // Cut on either a full fabricated lifecycle marker OR a bare `[task` opener (garbled leak).\n const m = this.reflexBuf.match(RESERVED_EVENT_MARKER) ?? this.reflexBuf.match(RESERVED_EVENT_OPENER);\n if (m) {\n this.fabricationCut = true;\n log.warn(`reflex fabricated a [task …] event in its spoken stream — cutting it (kept ${m.index} chars)`);\n const safe = this.reflexBuf.slice(this.reflexForwarded, m.index); // unforwarded text before the marker\n if (!safe) return;\n if (safe.trim()) this.spokeThisTurn = true;\n this.emitHost({ ...ev, message: safe } as any);\n return;\n }\n // Hold back a trailing fragment that could be the start of a `[task` opener split across\n // deltas (e.g. \"[ta\" + \"sk\") — once forwarded to TTS it can't be unsent. Flush it next delta\n // (or at turn end, where reflexBuf is drained) once we know it isn't an opener.\n const held = this.reflexBuf.length - this.reflexForwarded;\n const partial = held > 0 && /\\[\\s*t?a?s?k?$/i.test(this.reflexBuf.slice(-Math.min(held, 6)));\n let upto = partial ? this.reflexBuf.length - this.reflexBuf.slice(-6).match(/\\[\\s*t?a?s?k?$/i)![0].length : this.reflexBuf.length;\n // Likewise hold back from an UNCLOSED \"(\" — a stage direction is only judged (and dropped)\n // once its \")\" arrives, and forwarded audio can't be unsent. Bounded: a span past 80 held\n // chars is clearly content, not a short stage cue — release it (never scrubbed thereafter).\n const paren = this.reflexBuf.lastIndexOf('(');\n if (paren >= this.reflexForwarded && !this.reflexBuf.includes(')', paren) && this.reflexBuf.length - paren <= 80)\n upto = Math.min(upto, paren);\n const out = this.reflexBuf.slice(this.reflexForwarded, upto);\n this.reflexForwarded = upto;\n if (!out) return;\n if (out.trim()) this.spokeThisTurn = true;\n this.emitHost({ ...ev, message: out } as any);\n return;\n }\n host.notify?.(ev);\n },\n };\n this.voice = new Agent({\n ai: o.ai,\n fs: new MemFilesystem(),\n model: o.reflexModel,\n stream: true,\n host: voiceHost,\n // The reflex IS the conversational channel — it confirms ambiguity inline (\"did you mean…?\"),\n // never via the blocking AskUserQuestion tool (Agent auto-adds it whenever a host is set). Left in,\n // it stalls a voice turn until the kill-switch. Worker questions still reach the user via parkQuestion.\n askUserQuestion: false,\n systemPrompt: prompt,\n instructionFiles: false,\n maxSteps: 8,\n timeoutMs: 30_000,\n ...o.reflexOptions,\n tools,\n // Composed AFTER the spread so the dispatch guard can't be dropped by reflexOptions.\n hooks: composeHooks(this.dispatchGuard(), o.reflexOptions?.hooks),\n });\n }\n\n /** Resolve memory tools + inject index into voice system prompt (once). */\n private async initMemory(): Promise<void> {\n if (!this.memoryReady) return;\n const mem = await this.memoryReady;\n this.memoryReady = undefined; // one-shot\n // Append memory tools to the voice agent's active set.\n (this.voice.options.tools as AgentTool[]).push(...mem.tools);\n // Inject memory index into the system prompt.\n if (mem.index) this.voice.options.systemPrompt += '\\n\\n' + mem.index;\n }\n\n /** Flush any held-back trailing fragment (a possible `[task` opener that never completed) once the\n * turn's stream is done — so a legit message ending in \"[t\" isn't silently dropped. */\n private flushHeldReflexTail(): void {\n if (this.fabricationCut) return;\n this.scrubStageDirections(); // a turn ending in \"(Waiting…)\" held the span — judge and drop it now\n const tail = this.reflexBuf.slice(this.reflexForwarded);\n this.reflexForwarded = this.reflexBuf.length;\n if (!tail) return;\n if (tail.trim()) this.spokeThisTurn = true;\n this.emitHost({ kind: 'text_delta', message: tail });\n }\n\n /** Remove complete stage-direction parentheticals from the UNFORWARDED reflex text (STAGE_DIRECTION_RE).\n * Only the unforwarded region is touched — already-spoken audio can't be unsent, and splicing before\n * reflexForwarded would corrupt the forward offset. */\n private scrubStageDirections(): void {\n if (this.reflexForwarded >= this.reflexBuf.length) return;\n const region = this.reflexBuf.slice(this.reflexForwarded);\n const scrubbed = region.replace(/\\([^()]*\\)/g, (s) => (STAGE_DIRECTION_RE.test(s) ? '' : s));\n if (scrubbed !== region) this.reflexBuf = this.reflexBuf.slice(0, this.reflexForwarded) + scrubbed;\n }\n\n /** Clear the per-turn guards. Called at the head of every voice turn (user send + re-voice flush). */\n private resetTurn(): void {\n this.turnDispatched = false;\n this.spokeBeforeDispatch = false;\n this.turnBriefs.clear();\n this.spokeThisTurn = false;\n this.externalSpeech = false;\n this.heldThisTurn = false;\n this.reflexBuf = '';\n this.reflexForwarded = 0;\n this.fabricationCut = false;\n this.turnFollowUp = false; // user turns + clean re-voices never spawn auto-follow-ups\n this.voice.options.toolChoice = undefined; // clear any post-dispatch tool lock from the previous turn\n }\n\n /** preToolUse guard on the reflex: once it has dispatched this turn, a dispatch is \"said my piece,\n * now wait for the push\" (CC's Task model). Block the temptations — TaskStatus polling and identical\n * re-dispatch — so the only remaining move is to voice a short ack and end. A genuinely NEW Act is\n * still allowed (parallel independent work). During a re-ack pass, block every tool. */\n private dispatchGuard(): Hooks {\n return {\n preToolUse: (call: ToolUse) => {\n // Speculation tool-safety: side-effectful tools must NEVER run on unconfirmed (speculated)\n // input — dispatching Act on words the user may not have said is dangerous. Abort the whole\n // speculative call instead (its cost is the speculative_aborted_calls metric); the endpointed\n // final dispatches normally and may then use the tool for real. Read-only lookups + Hold are\n // allowed (their results are as valid for the confirmed final as for the partial).\n if (this.spec?.state === 'pending' && !DuplexAgent.SPEC_SAFE_TOOLS.has(call.name)) {\n log.verbose(`speculation aborted: reflex called ${call.name} on unconfirmed input`);\n this.abortSpeculation();\n return { block: true, reason: 'Speculative turn aborted.' };\n }\n if (this.nudging) return { block: true, reason: 'Just say one short spoken acknowledgement — no tools this turn.' };\n if (!this.turnDispatched) return;\n if (call.name === 'TaskStatus')\n return { block: true, reason: 'You just dispatched a task this turn — do NOT poll. Give one short spoken acknowledgement and end your turn; the result arrives later as a [task …] event.' };\n if ((call.name === 'Act' || call.name === 'Think') && this.turnBriefs.has(String(call.args?.brief ?? '')))\n return { block: true, reason: 'You already dispatched this exact task — acknowledge briefly and end your turn.' };\n },\n };\n }\n\n /** The host spoke on this turn's behalf OUTSIDE the reflex stream (e.g. the voice engine's adaptive\n * micro-ack). For a DISPATCHED turn that's a sufficient ack (don't stack a second one); for an\n * inline turn whose reply came back empty it is NOT — \"One sec.\" followed by permanent silence is\n * still dead air, so silentTurn ignores external speech unless work was dispatched. */\n noteExternalSpeech(): void { this.externalSpeech = true; }\n\n /** True when the just-finished turn voiced NOTHING — dead air to repair. Two ways this happens:\n * (a) a dispatch with no spoken ack, and (b) an INLINE turn whose `final` channel came back empty —\n * gpt-oss harmony sometimes puts the whole reply in `analysis` (→ thinking_delta, suppressed in\n * voice) and emits an empty `final`, so no text_delta ever streams. Both ship silence; both repair.\n * Requires a host: without one there's no stream to detect speech on (and no one to speak to). */\n private get silentTurn(): boolean {\n const ackedByHost = this.externalSpeech && this.turnDispatched; // external ack only satisfies a dispatched turn\n return !!this.options.host && !this.spokeThisTurn && !ackedByHost && !this.heldThisTurn; // a Hold turn is intentionally silent — not dead air\n }\n\n /** A turn that voiced nothing is dead air. Re-prompt the reflex ONCE so the LLM itself voices a short\n * line (no template). If it STILL says nothing, fall back to a minimal line so silence never ships.\n * Wording adapts to whether work was dispatched (an ack) or the inline reply was simply lost. */\n private async ackIfSilent(fallback?: string): Promise<void> {\n const dispatched = this.turnDispatched;\n this.nudging = true;\n try {\n await this.voice.send(fallback\n ? '[reminder] You said nothing to the user this turn. Tell them, in ONE short spoken sentence, what just happened — no tools.'\n : dispatched\n ? '[reminder] You dispatched a task but said nothing to the user. Say ONE short spoken acknowledgement now — no tools.'\n : '[reminder] You said nothing to the user this turn. Give your ONE short spoken reply now — no tools.');\n } catch (e) {\n log.warn(`ack nudge failed: ${e instanceof Error ? e.message : e}`);\n } finally {\n this.nudging = false;\n }\n // If the reflex STILL voiced nothing, ship a fallback line so silence never reaches the user.\n // A caller-supplied fallback (e.g. a task failure) takes priority — that information must not be\n // swallowed. Small varied pools with no immediate repeat (a fixed line reads robotic when it recurs).\n if (!this.spokeThisTurn) {\n const pool = fallback ? [fallback] : dispatched ? DuplexAgent.FALLBACK_ACKS : DuplexAgent.FALLBACK_RETRY;\n const fresh = pool.filter((p) => p !== this.lastFallback);\n const line = (fresh.length ? fresh : pool)[Math.floor(Math.random() * (fresh.length || pool.length))];\n this.lastFallback = line;\n this.emitHost({ kind: 'text_delta', message: line });\n }\n }\n\n /** Dead-air fallback pools (see ackIfSilent). Both retry lines keep the 'say that again' phrase —\n * hosts/tests key on it. */\n private static readonly FALLBACK_ACKS = ['Okay, on it.', 'On it.', 'Alright, working on it.'];\n private static readonly FALLBACK_RETRY = ['Sorry, could you say that again?', 'Hm, I missed that — could you say that again?'];\n private lastFallback = '';\n\n /** One user turn: the voice agent streams the reply (and may Act/Think). Serialized with re-voice turns.\n * If a speculative reflex call is pending and this content CONFIRMS it (the final matches the\n * speculated partial), the in-flight call is adopted as THE turn: its buffered output flushes to the\n * host NOW (this is the latency win) and streaming continues live. Any other content aborts the\n * speculation first (rolled back silently) and runs a normal turn behind it. */\n send(content: MessageContent): Promise<RunResult> {\n // Auto-resume after a trivial barge: the user cut off a task delivery, then said something with NO\n // new request (\"sorry\", \"go on\") — resume the parked result instead of running an empty turn. Runs\n // before speculation so a filler partial that speculated is rolled back, not adopted.\n if (typeof content === 'string' && isTrivialBarge(content) && this.hasParkedDelivery()) {\n if (this.spec) this.abortSpeculation();\n return this.enqueue(async () => {\n this.resetTurn();\n // Already settled → speak it now; still running → arm the flag so it resumes on settle.\n if (!this.redeliverParked()) this.awaitTrivialRedeliver = true;\n return { text: '', steps: 0, finishReason: 'stop', messages: [] } as RunResult;\n });\n }\n const spec = this.spec;\n if (spec?.state === 'pending') {\n if (typeof content === 'string' && speculationConfirms(spec.text, content)) {\n spec.state = 'confirmed';\n spec.finalText = content;\n for (const ev of spec.buf.splice(0)) this.options.host?.notify?.(ev); // flush the held output NOW\n spec.decide('confirm');\n this.notify('diag', 'speculation_confirmed', { text: spec.text.slice(0, 80) }); // host diag sinks record it; UIs ignore 'diag'\n return spec.done;\n }\n this.abortSpeculation(); // divergent final (or non-text turn) — the normal turn queues behind the rollback\n }\n return this.enqueue(async () => {\n await this.initMemory();\n this.resetTurn();\n this.turn++;\n // Drop any pending auto-resume AND suppress a resume for deliveries that settle later (else a\n // much-later \"go on\" replays a stale result). The parked result still lives in the transcript\n // (folded at settle), so it stays recoverable by asking.\n this.awaitTrivialRedeliver = false;\n this.parkedRedeliver = [];\n this.suppressParkedResume = true;\n const res = await this.voice.send(content);\n this.flushHeldReflexTail();\n if (this.silentTurn) await this.ackIfSilent();\n return res;\n });\n }\n\n /** Start a HELD speculative reflex turn on a stable partial (VoiceEngine.onSpeculate). Its spoken\n * output buffers in emitHost; send() later confirms (flush + adopt) or aborts it. The turn holds the\n * voice mutex until that decision (bounded by a safety timeout), so no other turn can interleave\n * into the transcript between the speculative messages and their rollback. No-op if a speculation\n * is already in flight. */\n speculate(text: string): void {\n if (!text.trim() || this.spec) return;\n let decide!: (d: 'confirm' | 'abort') => void;\n const decision = new Promise<'confirm' | 'abort'>((r) => { decide = r; });\n const spec: NonNullable<DuplexAgent['spec']> = {\n text, state: 'pending', buf: [], ctl: new AbortController(), decide, decision, done: undefined as unknown as Promise<RunResult>,\n };\n this.spec = spec;\n spec.done = this.enqueue(async () => {\n const empty: RunResult = { text: '', steps: 0, finishReason: 'aborted', messages: this.voice.transcript };\n if (spec.state === 'aborted') { this.speculativeAbortedCalls++; if (this.spec === spec) this.spec = undefined; return empty; } // aborted before it ever started — nothing to roll back\n await this.initMemory();\n this.resetTurn();\n const base = this.voice.transcript.length;\n const prevSignal = this.voice.options.signal;\n this.voice.options.signal = spec.ctl.signal;\n let res: RunResult | undefined;\n try { res = await this.voice.send(spec.text); }\n catch (e) { log.warn(`speculative turn failed: ${e instanceof Error ? e.message : e}`); }\n finally { this.voice.options.signal = prevSignal; }\n // Stream done — await the endpoint decision. Bounded: a final that never dispatches (dropped by\n // an engine guard, mode change, …) must not wedge the voice queue behind a zombie speculation.\n const timer = setTimeout(() => { spec.state = spec.state === 'pending' ? 'aborted' : spec.state; spec.decide('abort'); }, 10_000);\n (timer as any).unref?.();\n const d = await spec.decision;\n clearTimeout(timer);\n if (d === 'abort') {\n // The speculation never happened: drop its output (emitHost already ate it), erase its messages\n // (the transcript must contain the FINAL text only — the real turn dispatches right behind us),\n // and count the spend.\n if (this.voice.transcript.length > base) this.voice.transcript.length = base;\n this.speculativeAbortedCalls++;\n log.verbose(`speculation aborted (${this.speculativeAbortedCalls} total): \"${spec.text.slice(0, 50)}\"`);\n if (this.spec === spec) this.spec = undefined;\n return res ?? empty;\n }\n // CONFIRMED — the transcript must carry what the user actually SAID (the final), not the partial.\n for (let i = base; i < this.voice.transcript.length; i++) {\n const m = this.voice.transcript[i];\n if (m.role === 'user' && contentText(m.content) === spec.text) { m.content = spec.finalText!; break; }\n }\n this.spec = undefined; // live from here (late emitHost stragglers pass straight through)\n this.flushHeldReflexTail();\n if (this.silentTurn) await this.ackIfSilent();\n return res ?? empty;\n });\n }\n\n /** Abort a pending speculation (idempotent): kill the in-flight call, drop its buffered output.\n * Called on divergence (send), a stale partial (VoiceEngine.onSpeculateAbort), a side-effect tool\n * attempt (dispatchGuard), or host paths that will never dispatch a final (commands, voice-off). */\n abortSpeculation(): void {\n const spec = this.spec;\n if (spec?.state !== 'pending') return;\n spec.state = 'aborted';\n spec.buf.length = 0;\n spec.ctl.abort();\n spec.decide('abort');\n this.notify('diag', 'speculation_aborted', { text: spec.text.slice(0, 80) });\n }\n\n /** Cancel a running background task — shared by the CancelTask tool and the CLI /tasks picker. */\n cancelTask(id: string): string {\n const rec = this.tasks.get(id);\n if (!rec) return `No task '${id}'.`;\n if (rec.status !== 'running') return `Task ${rec.id} is already ${rec.status}.`;\n rec.status = 'cancelled';\n rec.controller.abort();\n return `Task ${rec.id} (${rec.label}) cancelled.`;\n }\n\n /** Barge-in (or a dispatch-driven supersede): suppress running tasks' remaining SPOKEN delivery so a\n * superseded topic never talks over the new one (the debt-after-jokes regression). Tasks keep running and\n * still fold their result into the transcript — recoverable, just not spoken. Returns parked ids (logging).\n * Does NOT cancel. Two callers, two shapes:\n * - BARGE (default): the user interrupted AUDIO. Park EVERY running task (including this turn's) — the\n * worker they cut off must stop, whatever turn launched it — and re-arm trivial-barge auto-resume so a\n * following \"go on\" can bring the parked delivery back.\n * - SUPERSEDE (`priorTurnsOnly`, `reenableResume:false`, from dispatch()): a new dispatch redirected to\n * fresh work. Park only PRIOR-turn tasks so parallel siblings dispatched in the SAME turn don't silence\n * each other, and keep them suppressed (the user moved on — don't resurface on a stray \"go on\"). */\n parkInFlightDeliveries(reenableResume = true, priorTurnsOnly = false): string[] {\n if (reenableResume) this.suppressParkedResume = false;\n const parked: string[] = [];\n for (const rec of this.tasks.values())\n if (rec.status === 'running' && !rec.deliveryParked && (!priorTurnsOnly || rec.createdTurn < this.turn)) { rec.deliveryParked = true; parked.push(rec.id); }\n return parked;\n }\n\n /** True while there is a parked delivery to potentially resume: either one already settled (queued) or\n * one still running that was parked by a barge. */\n private hasParkedDelivery(): boolean {\n return this.parkedRedeliver.length > 0\n || [...this.tasks.values()].some((t) => t.status === 'running' && t.deliveryParked);\n }\n\n /** Speak any settled-and-queued parked delivery now (trivial-barge resume). Returns false if nothing was\n * queued yet (the caller then arms awaitTrivialRedeliver so the task resumes the instant it settles). */\n private redeliverParked(): boolean {\n if (!this.parkedRedeliver.length) return false;\n const text = this.parkedRedeliver.splice(0).join(' ').trim();\n if (text) {\n this.options.host?.notify?.({ kind: 'speak_utterance', message: text });\n this.notify('diag', 'parked_redelivered', { chars: text.length });\n }\n return true;\n }\n\n /** Resolve when all queued voice turns AND all in-flight worker tasks have settled (tests, graceful shutdown). */\n async idle(): Promise<void> {\n while (true) {\n const q = this.queue;\n await q.catch(() => {});\n await Promise.all([...this.tasks.values()].map((t) => t.promise));\n // a worker completion may have enqueued a re-voice turn meanwhile — loop until quiescent\n if (this.queue === q && ![...this.tasks.values()].some((t) => t.status === 'running')) return;\n }\n }\n\n /** Promise-chain mutex: turns run strictly one at a time; a failed turn doesn't poison the chain. */\n private enqueue<T>(fn: () => Promise<T>): Promise<T> {\n const run = this.queue.then(fn, fn);\n this.queue = run.then(() => {}, () => {});\n return run;\n }\n\n private notify(kind: string, message: string, data?: unknown): void {\n this.emitHost({ kind, message, data });\n }\n\n /** Host-boundary emit for the reflex's spoken channel: during a PENDING speculation, text_delta and\n * hold_filler are BUFFERED (nothing may reach TTS on unconfirmed input); confirm flushes them in\n * order, abort drops them silently. Everything else (task_* lifecycle, worker speak_utterance —\n * which bypasses this via host.notify directly) passes through untouched. */\n private emitHost(ev: { kind: string; message: string; data?: unknown }): void {\n const spec = this.spec;\n if (spec && (ev.kind === 'text_delta' || ev.kind === 'hold_filler')) {\n if (spec.state === 'pending') { spec.buf.push(ev); return; }\n if (spec.state === 'aborted') return; // an aborted speculation never speaks\n }\n this.options.host?.notify?.(ev);\n }\n\n /** Queue a `[task …]` event for re-voicing. Events arriving while the voice is busy coalesce into ONE turn.\n * `nonClean` (out-of-band boolean, set by the caller that KNOWS this event integrates a NON-CLEAN outcome)\n * marks the coalesced flush as a non-clean integration turn — turn-eligibility, never inferred from event\n * text and never keyed on a (re-authored) brief string. Any dispatch in such a turn is a follow-up. */\n private queueRevoice(event: string, nonClean = false): void {\n this.pendingEvents.push(event);\n if (nonClean) this.pendingNonClean = true;\n if (this.flushQueued) return;\n this.flushQueued = true;\n void this.enqueue(async () => {\n this.flushQueued = false; // events landing during this send() get their own flush turn\n const events = this.pendingEvents.splice(0);\n const nonCleanTurn = this.pendingNonClean;\n this.pendingNonClean = false;\n if (!events.length) return;\n // A failed task MUST be surfaced to the user, never silently swallowed (the reflex\n // sometimes voices nothing on a [task … failed] event). Derive a spoken fallback so the\n // silent-turn repair announces the failure instead of a generic \"could you say that again\".\n const failed = events.find((e) => /^\\[task\\b[^\\]\\n]*\\bfailed\\b/i.test(e));\n this.resetTurn();\n // Turn-eligibility (NOT brief-matching): this flush integrates ≥1 non-clean task, so ANY dispatch it\n // makes is an auto-follow-up. This is what makes runaway impossible — a paraphrased escalation still\n // lands here and is recognized. resetTurn cleared the flag, so set it AFTER reset.\n this.turnFollowUp = nonCleanTurn;\n await this.voice.send(events.join('\\n'));\n this.flushHeldReflexTail();\n if (this.silentTurn) await this.ackIfSilent(failed ? \"Sorry, that didn't work — the task failed.\" : undefined); // a re-voiced result that came back empty is dead air too\n\n // A re-voice turn ends OUTSIDE any host send() callsite — signal it so a line-buffered\n // renderer (CLI MarkdownStream) can flush its tail (else the last partial line is swallowed).\n this.notify('revoice_done', '');\n });\n }\n\n /** The worker's brief: the Act/Think args + a STATIC text snapshot of the recent conversation.\n * Act briefs get a self-verify footer — the worker's report is trusted without review, so it\n * must check its own work before reporting (nearly free under prompt caching; measured honest:\n * it does NOT fix one-shot logic bugs — see mind/10). Think tasks are pure reasoning — no footer. */\n private buildBrief(brief: string, tier: WorkerTier = 'act', deliver = true): string {\n const recent = this.voice.transcript\n .filter((m) => (m.role === 'user' || m.role === 'assistant') && contentText(m.content).trim())\n .slice(-this.options.excerptTurns)\n .map((m) => `${m.role}: ${contentText(m.content)}`)\n .join('\\n');\n const verify = tier === 'act'\n ? '\\n\\nBefore reporting done: re-read what you changed and check it against EVERY requirement above — fix any gap first. Your report is trusted without review.'\n : '';\n // DELIVER contract: the worker OWNS spoken delivery. Stated abstractly — NO concrete example\n // (this repo was burned by eval-fixture overfitting; teach the principle, not a fixture).\n const deliverContract = deliver ?\n '\\n\\n## DELIVER (spoken delivery)\\n' +\n 'You are reporting back to a user who is LISTENING. Stream your work normally — your prose is the written work record and detail, and is NOT spoken. ' +\n 'Wrap anything the user should HEAR in <spoken>…</spoken> tags. ' +\n 'LEAD WITH the actual content they asked for: if they asked for a specific piece of content — a value, a name, the actual lines, the writing itself — that content goes INSIDE the <spoken> tags, not a remark about it. ' +\n 'Your FIRST <spoken> segment is substantive — never a greeting or an acknowledgement (the front-end has already acked; do not double-ack). ' +\n 'Keep spoken text concise and natural for the ear: short sentences, no markdown. ' +\n 'NEVER enumerate in speech — no numbered or bulleted lists (\"One. … Two. …\" is robotic). Deliver multiple items as flowing conversation with brief connective phrasing (\"here\\'s one…\", \"and another…\", \"oh, and…\"), pausing between items with sentence breaks, not numbers.' +\n (this.options.emotionTags ? ' Inside <spoken>, you may prefix a sentence with an inline [emotion] tag (e.g. [excited], [curious]) to color how it is voiced — only when it genuinely fits, and vary it; [laughter] gives a natural laugh.' : '') : '';\n // Lead with fresh \"now\" so any search/computation is grounded to the current date — without it a\n // worker resolves \"recent\"/\"latest\" to a famous past instance (e.g. the 2022 World Cup instead of\n // the tournament happening this week). Recomputed here per dispatch, so it never goes stale.\n return `${nowLine()}.\\n\\n` + (recent ? `${brief}\\n\\n## Recent conversation (for context)\\n${recent}` : brief) + verify + deliverContract;\n }\n\n /** Spawn a detached worker for task `id`; its settlement notifies + enqueues the re-voice turn. */\n private spawnWorker(id: string, label: string, briefText: string, tier: WorkerTier, brief: string, followUp: boolean): void {\n const o = this.options;\n const tierOpts = tier === 'think' ? o.thinkOptions : o.actOptions;\n const tierModel = tier === 'think' ? (o.thinkModel as string) : o.actModel;\n const controller = new AbortController();\n const base = tierOpts?.hooks ?? o.actOptions?.hooks;\n const report = o.progressUpdates ? this.progressReporter(id) : undefined;\n // Rolling activity tail (always on, unlike the gated progress re-voicer) — backs /tasks inspection.\n const tail: string[] = [];\n const pushTail = (line: string) => { tail.push(line.slice(0, 200)); if (tail.length > 120) tail.splice(0, tail.length - 120); };\n const hooks = {\n ...base,\n preToolUse: async (call: ToolUse, meta?: any) => { const d = await base?.preToolUse?.(call, meta); pushTail(`⚙ ${describeCall(call)}`); report?.pre(call); return d; },\n postToolUse: async (call: ToolUse, result: string, meta?: any) => {\n await base?.postToolUse?.(call, result, meta);\n const last = result?.trim().split('\\n').filter(Boolean).pop();\n if (last) pushTail(` ↳ ${last}`);\n report?.post(call);\n },\n onToolOutput: (call: ToolUse, chunk: string, meta?: any) => { base?.onToolOutput?.(call, chunk, meta); report?.output(chunk); },\n };\n const relayAsk = async (q: { question: string; options?: Array<{ label: string }> }): Promise<string> => {\n const opts = q.options?.length ? ` Options: ${q.options.map((x) => x.label).join(', ')}.` : '';\n const a = await this.parkQuestion(id, `${q.question}${opts}`);\n return a || '(no answer from the user — use your best judgment and note the assumption)';\n };\n // The worker OWNS delivery: it streams `<spoken>…</spoken>` during its run. Split each text_delta —\n // spoken segments speak as a SEPARATE serialized utterance (speak_utterance) AND record into the\n // transcript/surfaced text (INDEPENDENTLY of whether the audio queue plays them — a barge-in can\n // drop the audio, but the spoken content must still land in context). detail → activity tail, never\n // spoken. `stream:true` is only meaningful with a host.notify (Agent requires it).\n const splitter = new SpokenSplitter();\n // Suppress audio once the user has barged in on this task (deliveryParked) — don't talk over the new\n // topic. The result still folds into the transcript at settle, so it's recoverable, just not spoken.\n const speak = (seg: string) => {\n if (!seg) return;\n const r = this.tasks.get(id);\n if (r) r.spokenText = (r.spokenText ? r.spokenText + ' ' : '') + seg; // accumulate for a possible parked-redeliver\n if (!r?.deliveryParked) o.host?.notify?.({ kind: 'speak_utterance', message: seg });\n };\n // Coalesce spoken text into COMPLETE sentences before emitting each as its own utterance — a worker on\n // a fragmenting model (cursor streams word-by-word deltas) would otherwise emit one utterance per word\n // (choppy TTS + one screen-echo line per word). flushSpoken() drains the partial when the stream ends.\n const coalescer = new SentenceCoalescer();\n const feedSpoken = (s: string) => { const ready = coalescer.feed(s); if (ready) speak(ready); };\n const flushSpoken = () => speak(coalescer.flush());\n const askBridge = o.askRelay ? { ask: relayAsk } : o.host?.ask ? { ask: (q: any) => o.host!.ask!(q) } : {};\n const workerHost: HostBridge = {\n ...askBridge,\n notify: (ev) => {\n if (ev?.kind === 'text_delta' && typeof (ev as any).message === 'string') {\n const { spoken, detail } = splitter.feed((ev as any).message);\n feedSpoken(spoken);\n if (detail.trim()) pushTail(detail.trim());\n return;\n }\n // non-stream worker events stay on the activity tail (never spoken)\n },\n };\n const agentOpts: Partial<AgentOptions> = {\n ai: o.ai,\n fs: o.fs,\n model: tierModel,\n ...(tier === 'think' ? { reasoning: tierOpts?.reasoning ?? 'high' } : {}),\n ...tierOpts,\n // Recompute providerOptions for THIS worker's model (after tierOpts so it wins over any inherited\n // main-template value) — prevents cursor-only cwd/cursorSession leaking onto an anthropic worker.\n providerOptions: o.providerOptionsFor?.(tierModel),\n stream: true, // worker streams text_delta so the splitter can extract <spoken> live (after tierOpts: never overridden off)\n host: workerHost, // carries BOTH ask AND the <spoken>-splitting notify\n ...(hooks ? { hooks } : {}),\n signal: controller.signal, // shared with the checker so a cancel tears down both\n };\n const promise = new Agent(agentOpts)\n .run(briefText)\n // Worker stream done: drain any dangling spoken text (unclosed <spoken> + the last partial sentence).\n .then((res) => { const { spoken, detail } = splitter.flush(); feedSpoken(spoken); if (detail.trim()) pushTail(detail.trim()); flushSpoken(); return res; })\n .then((res) => this.maybeVerify(id, brief, res, tier, agentOpts, askBridge))\n .then((res) => this.onWorkerSettled(id, res))\n .catch((err) => this.onWorkerFailed(id, err));\n this.tasks.set(id, { id, label, status: 'running', controller, promise, tail, brief, followUp, splitter, createdTurn: this.turn });\n // Evict oldest settled records past the cap (Map preserves insertion order) — running tasks stay.\n if (this.tasks.size > this.options.maxTaskRecords)\n for (const [tid, rec] of this.tasks) {\n if (this.tasks.size <= this.options.maxTaskRecords) break;\n if (rec.status !== 'running') this.tasks.delete(tid);\n }\n }\n\n /** Fresh-context check of a successful Act task: a NEW agent (same model/fs/tools, but NO shared\n * conversation context) re-reads the file state against the brief and fixes any gap. The fix lands\n * on the shared fs automatically (workers write fs directly, no overlay), so grading sees the\n * corrected state. Bounded to ONE pass. Off unless `verifyActTasks`; never runs for think/failed/\n * cancelled tasks. Usage is merged so /cost reflects the real (worker + checker) spend. */\n private async maybeVerify(id: string, brief: string, res: RunResult, tier: WorkerTier, agentOpts: Partial<AgentOptions>, askBridge: Partial<HostBridge>): Promise<RunResult> {\n if (!this.options.verifyActTasks || tier !== 'act' || res.finishReason !== 'stop') return res;\n if (this.tasks.get(id)?.status === 'cancelled') return res; // user stopped it — don't spend on a check\n // The checker is an INTERNAL fixer — it must NOT speak and must NOT touch the worker's SpokenSplitter.\n // So: (a) strip the DELIVER/<spoken> contract from the brief, and (b) run with a clean host that\n // carries ONLY `ask` (the historical pre-spoken-feature behavior) — never the spoken-forwarding\n // notify/splitter — and without `stream:true` (only meaningful for live <spoken> extraction).\n const { stream: _stream, host: _host, ...restOpts } = agentOpts;\n const checkerOpts: Partial<AgentOptions> = {\n ...restOpts,\n ...(askBridge.ask ? { host: { ask: askBridge.ask } } : {}),\n };\n const checkBrief = `${this.buildBrief(brief, tier, false)}\\n\\n## VERIFY MODE\\nAnother agent just implemented the above. Independently check the CURRENT state of the files against EVERY requirement. Fix any gap you find. If everything is already correct, make NO changes — do not refactor or improve — and report \"verified\".`;\n this.notify('task_verify', `task ${id}: verifying`, { id });\n const cres = await new Agent(checkerOpts).run(checkBrief);\n // Surface an inconclusive check (errored / hit a kill-switch) — don't let a failed verification\n // masquerade as a passed one. The worker's work still stands, so the task still completes with\n // the worker's report; we just flag that the check didn't cleanly finish.\n if (cres.finishReason !== 'stop') {\n log.warn(`task ${id}: verify inconclusive (${cres.finishReason})`);\n this.notify('task_verify', `task ${id}: verify inconclusive (${cres.finishReason})`, { id, finishReason: cres.finishReason });\n }\n const sum = (a = 0, b = 0) => a + b;\n return {\n ...res,\n steps: res.steps + cres.steps,\n // Merge the checker's messages so downstream tool-call/step accounting includes BOTH agents\n // (else a verified task's toolCalls would undercount vs its steps/usage).\n messages: [...res.messages, ...cres.messages],\n usageEstimated: res.usageEstimated || cres.usageEstimated,\n usage: res.usage && cres.usage ? {\n promptTokens: sum(res.usage.promptTokens, cres.usage.promptTokens),\n completionTokens: sum(res.usage.completionTokens, cres.usage.completionTokens),\n totalTokens: sum(res.usage.totalTokens, cres.usage.totalTokens),\n cacheCreationTokens: sum(res.usage.cacheCreationTokens, cres.usage.cacheCreationTokens),\n cacheReadTokens: sum(res.usage.cacheReadTokens, cres.usage.cacheReadTokens),\n } : (res.usage ?? cres.usage),\n };\n }\n\n /** Throttled per-task progress: worker tool calls → at most one progress re-voice per interval.\n * Two sources, one throttle: completed steps (post) and a heartbeat for a SINGLE long tool call\n * (pre records the in-flight call; a self-cleaning timer narrates \"still inside Bash — 70s\").\n * Completion supersedes: nothing is emitted once the task has settled. */\n private progressReporter(id: string): { pre: (call: ToolUse) => void; post: (call: ToolUse) => void; output: (chunk: string) => void } {\n let lastAt = Date.now();\n let steps = 0;\n let inflight: { call: ToolUse; at: number; tail: string } | null = null;\n const due = () => {\n if (this.pendingAsks.size) return undefined; // a question is pending — \"still working\" asides are noise (and wrong: it's WAITING)\n const rec = this.tasks.get(id);\n return rec && rec.status === 'running' && Date.now() - lastAt >= this.options.progressIntervalMs ? rec : undefined;\n };\n const emit = (rec: TaskRecord, line: string, call: ToolUse) => {\n lastAt = Date.now();\n this.notify('task_progress', `task ${id} (${rec.label}): ${line}`, { id, steps, call: call.name });\n this.queueRevoice(`[task ${id} progress] ${line}`);\n };\n const timer = setInterval(() => {\n const rec = this.tasks.get(id);\n if (!rec || rec.status !== 'running') return clearInterval(timer); // task settled — self-clean\n if (!inflight || !due()) return;\n // content-aware when the tool streams (ctx.emit → rolling tail): \"last output: 12 pass, 0 fail\"\n const last = inflight.tail.trim().split('\\n').filter(Boolean).pop()?.slice(-80);\n emit(rec, `still inside ${describeCall(inflight.call)} — ${Math.round((Date.now() - inflight.at) / 1000)}s on this step${last ? `, last output: ${last}` : ''}`, inflight.call);\n }, Math.max(this.options.progressIntervalMs, 250));\n (timer as any).unref?.(); // never hold the process open\n return {\n pre: (call) => { inflight = { call, at: Date.now(), tail: '' }; },\n output: (chunk) => { if (inflight) inflight.tail = (inflight.tail + chunk).slice(-500); }, // digest only — NEVER re-voices directly\n post: (call) => {\n steps++;\n inflight = null;\n const rec = due();\n if (rec) emit(rec, `still running — ${steps} steps so far, now: ${describeCall(call)}`, call);\n },\n };\n }\n\n /** Park a question under `askId` (a task id, or any unique key for permission asks): re-voices\n * '[task <id> asks] …' and resolves with the user's answer via AnswerTask — or '' on timeout/\n * task settle (callers map '' to deny / best-judgment). Workers never block forever. */\n parkQuestion(askId: string, question: string): Promise<string> {\n return new Promise((resolve) => {\n let settled = false;\n const finish = (answer: string) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n this.pendingAsks.delete(askId);\n resolve(answer);\n };\n const timer = setTimeout(() => {\n this.notify('task_ask_timeout', `task ${askId}: question timed out — proceeding without an answer`);\n finish('');\n }, this.options.askTimeoutMs);\n this.pendingAsks.set(askId, { question, resolve: finish });\n this.notify('task_ask', `task ${askId} asks: ${question}`, { id: askId, question });\n this.queueRevoice(`[task ${askId} asks] ${question}\\n(Relay this to the user in your own words. When they answer, call AnswerTask with id \"${askId}\" and their answer.)`);\n });\n }\n\n /** Resolve any question a settling/cancelled task left parked (its answer can no longer matter). */\n private dropAsk(id: string): void {\n this.pendingAsks.get(id)?.resolve('');\n }\n\n /** Build the INTEGRATION TURN prompt for a NON-CLEAN settled worker (early stop / failure). A clean\n * success never reaches here — it streams its own `<spoken>` delivery during the run. For a partial\n * or failed result the outcome re-enters the reflex as a decision (like a tool_result flowing back\n * into a normal agent loop): the reflex evaluates the outcome against the original intent and chooses\n * what to do next.\n *\n * Decision branches (the reflex acts on them with EXISTING tools — no new surface):\n * • accept → SPEAK the (partial) result plainly — don't dress a failure up as success.\n * • escalate → call `Think` with the SAME brief — only when Act failed/stalled AND a Think tier\n * exists AND this task wasn't already a follow-up (one hop max). Wires the dead\n * \"Reserve Think for a problem Act already FAILED at\" promise.\n * • re-delegate→ call `Act` with a CORRECTED brief — for a recoverable error / partial result.\n * • ask → ask the user ONE concrete question if genuinely blocked.\n *\n * Keeps the `[task <id> completed]` / `[task <id> failed]` opener so existing coalescing + the\n * failed-revoice fallback still fire, and the per-event transcript markers stay intact. */\n private integrationPrompt(rec: TaskRecord, outcome: 'incomplete' | 'error', body: string, finishReason: string): string {\n const opener = outcome === 'error' ? `[task ${rec.id} failed]` : `[task ${rec.id} completed]`;\n // Non-clean (early stop or error): give the reflex the decision. Cap auto-follow-up to one hop.\n // Hard absolute backstop ([[property 4]]): once the per-conversation auto-escalation budget is spent,\n // never offer escalate/re-delegate again — caps total escalations even if attribution ever misfires.\n const underCap = this.autoEscalations < DuplexAgent.MAX_AUTO_ESCALATIONS;\n const canEscalate = (outcome === 'error' || outcome === 'incomplete') && underCap;\n const hasThink = this.options.thinkModel !== false;\n const options: string[] = [];\n if (!rec.followUp && canEscalate && hasThink)\n options.push('ESCALATE to the Think tier (call Think with the same brief) if this is a hard/architectural problem the Act worker stalled or failed on');\n if (!rec.followUp && canEscalate)\n options.push('RE-DELEGATE to Act with a corrected brief if the failure looks recoverable (a wrong path, a fixable mistake)');\n options.push('ASK the user one short, concrete question if you genuinely cannot proceed without their input');\n options.push(\"ACCEPT and tell the user plainly what happened (don't dress a failure up as success)\");\n const decision = options.length > 1\n ? ` You must decide what to do next — choose ONE: ${options.map((o, i) => `(${i + 1}) ${o}`).join('; ')}. Pick exactly one and act on it; do not voice this as a finished success.`\n : ` Tell the user plainly what happened — do not present this as a finished success.`;\n const state = outcome === 'error'\n ? `the worker FAILED with: ${body}`\n : `the worker STOPPED EARLY (${finishReason}) — its result is PARTIAL, not a finished success: ${body}`;\n return `${opener} Original request: \"${rec.brief}\". Outcome: ${state}.${decision}`;\n }\n\n private onWorkerSettled(id: string, res: RunResult): void {\n this.dropAsk(id);\n const rec = this.tasks.get(id)!;\n if (res.finishReason === 'aborted' || rec.status === 'cancelled') {\n rec.status = 'cancelled';\n this.notify('task_cancelled', `task ${id} (${rec.label}) cancelled`);\n return; // the user asked to stop — don't narrate cancelled work\n }\n if (res.finishReason === 'error') {\n const msg = res.error instanceof Error ? res.error.message : String(res.error ?? 'unknown error');\n return this.failTask(rec, msg);\n }\n rec.status = 'done';\n rec.result = res.text;\n // A non-'stop' finish that isn't error/aborted (max_steps, timeout, loop, budget, max_tool_calls)\n // means the worker STOPPED EARLY — its result is partial, NOT a clean success. It must not be voiced\n // as if complete; the integration turn is told so it can escalate/re-delegate instead of accepting.\n // (`needs_input` also lands here, but only in a degenerate piped duplex: normally a worker always\n // has an `ask` — the voice relay, else the host's — so its question reaches the user as speech.)\n // `empty` (the Agent's own zero-work guard, 0cff9da) is NOT partial work stopped early — by\n // definition it's zero text + zero tools, i.e. the worker said nothing at all. That is exactly the\n // \"nothing to report\" case this duplex contract already treats as an acceptable clean finish (below);\n // routing it into the incomplete/re-voice path would pollute the transcript with a [task…] escalation\n // over silence instead of just letting the empty-result branch handle it.\n const incomplete = res.finishReason !== 'stop' && res.finishReason !== 'empty';\n log.verbose(`task ${id} done (${res.steps} steps${incomplete ? `, INCOMPLETE: ${res.finishReason}` : ''})`);\n // toolCalls = the worker's REAL tool-call count (a dispatch is not a tool call — consumers\n // comparing efficiency across agents need the worker's actual work, not the escalation count).\n this.notify('task_done', `task ${id} (${rec.label}) completed`, {\n id, text: res.text, usage: res.usage, usageEstimated: res.usageEstimated,\n finishReason: res.finishReason,\n steps: res.steps, toolCalls: res.messages.filter((m) => m.role === 'tool').length,\n });\n if (incomplete) {\n // A SUPERSEDED delivery (user moved to new work) must not hijack the voice on a partial result, nor\n // auto-escalate abandoned work over the new topic — fold the partial into the transcript (recoverable)\n // and stop, matching the clean-success suppression below.\n if (this.foldIfSuperseded(rec, res.text)) return;\n // Early stop → PARTIAL: keep the existing reflex revoice/decision path (escalate/re-delegate/ask).\n return this.queueRevoice(this.integrationPrompt(rec, 'incomplete', res.text, res.finishReason), true);\n }\n // Clean success: the worker ALREADY spoke its <spoken> segments during its run (no reflex re-voicing).\n // Parked (user barged in mid-task): suppress the remaining SPOKEN delivery — but still fold the full\n // result into the transcript so it's not lost (the reflex can surface it if the user asks).\n const tail = rec.splitter?.flush(); // drain any buffered partial tag (held across the last delta)\n if (tail?.spoken && !rec.deliveryParked) this.options.host?.notify?.({ kind: 'speak_utterance', message: tail.spoken });\n // (a) Fold the FULL result into the transcript as an assistant turn so the reflex can answer\n // follow-ups from context (replaces what voice.send did implicitly on the old revoice path).\n if (res.text.trim()) this.voice.transcript.push({ role: 'assistant', content: res.text });\n // (a2) Parked delivery (user barged mid-task): its audio was suppressed. Capture the spoken gist so a\n // trivial follow-up barge (\"sorry — go on\") can RESUME it. If a trivial barge already armed the\n // resume while this was running, speak it now; otherwise hold it for the next turn's decision.\n if (rec.deliveryParked && !this.suppressParkedResume) {\n const gist = (rec.spokenText ?? '').trim() || res.text.trim();\n if (gist) {\n if (this.awaitTrivialRedeliver) {\n this.awaitTrivialRedeliver = false;\n this.options.host?.notify?.({ kind: 'speak_utterance', message: gist });\n this.notify('diag', 'parked_redelivered', { chars: gist.length });\n } else this.parkedRedeliver.push(gist);\n }\n }\n // (b) No-spoken fallback: the worker emitted ZERO spoken segments → delivery would be silent.\n // Speak the gist as a one-shot enqueued utterance via the speak_utterance path. Skip if parked.\n if (!rec.splitter?.spokeAny && res.text.trim() && !rec.deliveryParked)\n this.options.host?.notify?.({ kind: 'speak_utterance', message: res.text });\n }\n\n private onWorkerFailed(id: string, err: unknown): void {\n this.failTask(this.tasks.get(id)!, err instanceof Error ? err.message : String(err));\n }\n\n /** A delivery the user has SUPERSEDED — parked AND moved on (suppressParkedResume, set by a redirect) —\n * must not hijack the voice when it settles late (partial or failed): that would talk over the new topic\n * and, worse, auto-escalate work the user already abandoned. Fold a recoverable note into the transcript\n * instead (the reflex can surface it if asked) and report true so the caller skips queueRevoice. A merely\n * barge-parked task (suppressParkedResume false — a \"go on\" may still resume it) is NOT superseded: it\n * keeps the normal surfacing path so a failure the user still cares about is not swallowed. */\n private foldIfSuperseded(rec: TaskRecord, note: string): boolean {\n if (!(rec.deliveryParked && this.suppressParkedResume)) return false;\n if (note.trim()) this.voice.transcript.push({ role: 'assistant', content: note });\n log.verbose(`task ${rec.id} settled but superseded (${rec.status}) — folded into transcript, not voiced`);\n return true;\n }\n\n private failTask(rec: TaskRecord, msg: string): void {\n this.dropAsk(rec.id);\n rec.status = 'error';\n rec.result = msg;\n log.warn(`task ${rec.id} failed: ${msg}`);\n this.notify('task_error', `task ${rec.id} (${rec.label}) failed: ${msg}`);\n // Superseded (user moved on): fold a note, don't hijack the new topic with a failure/escalation.\n if (this.foldIfSuperseded(rec, `The \"${rec.label}\" task failed: ${msg}`)) return;\n this.queueRevoice(this.integrationPrompt(rec, 'error', msg, 'error'), true);\n }\n\n // --- voice tools (closures over this instance) ---\n\n /** Live-switch the think tier: `false` disables (removes the Think tool from the voice agent),\n * a model id enables (adds the tool if missing). The system-prompt THINK_SLOT text is frozen at\n * construction — the tool's own description carries the routing guidance, so a live enable works;\n * dispatch()'s think→act fallback covers any straggler calls after a live disable. */\n setThinkModel(model: string | false): void {\n this.options.thinkModel = model;\n const tools = this.voice.options.tools as AgentTool[];\n const i = tools.findIndex((t) => t.name === 'Think');\n if (model === false && i >= 0) tools.splice(i, 1);\n else if (model !== false && i < 0) tools.push(this.thinkTool());\n }\n\n /** User/programmatic spawn: the CLI's /act and /think commands. Returns the task id.\n * `followUp` marks an automatic escalation/re-delegation (set by the integration turn) so the new\n * task's own integration turn won't escalate again — capping auto-follow-ups to one hop. */\n async dispatch(brief: string, tier: WorkerTier = 'act', label?: string, followUp = false): Promise<string> {\n if (tier === 'think' && this.options.thinkModel === false) tier = 'act';\n if (followUp) this.autoEscalations++; // spend from the hard absolute escalation budget ([[property 4]])\n // A new dispatch = the user redirected to fresh actionable work. Park deliveries still running from a\n // PRIOR turn so a superseded worker can't speak its <spoken> over the new topic when it settles (session\n // 1d93c6d3: a mis-heard search talked over the corrected one). Prior-turn only (createdTurn < this.turn),\n // so parallel tasks dispatched in the SAME turn don't silence each other, and a pure conversational turn\n // that dispatches nothing leaves running deliveries intact. reenableResume:false keeps the superseded\n // delivery suppressed rather than resurfacing on a stray \"go on\".\n this.parkInFlightDeliveries(false, true);\n const id = `t${++this.seq}`;\n const lbl = label ?? tier;\n await this.options.onTaskStart?.(id, lbl);\n this.spawnWorker(id, lbl, this.buildBrief(brief, tier), tier, brief, followUp);\n this.notify('task_started', `task ${id} (${lbl}) started`, { id, brief, tier });\n return id;\n }\n\n private actTool(): AgentTool {\n return {\n name: 'Act',\n description:\n 'Escalate real work (reading/editing files, searching, running tasks, building) to a standard background worker. ' +\n 'Returns immediately with a task id; the result arrives later as a \"[task <id> completed]\" event. ' +\n 'Provide a clear, self-contained `brief` (the worker does not hear the live conversation).',\n parameters: {\n type: 'object',\n required: ['brief'],\n properties: {\n brief: { type: 'string', description: 'full, self-contained instructions for the worker' },\n label: { type: 'string', description: 'a short (2-4 word) label for the task' },\n },\n },\n run: async ({ brief, label }) => {\n this.spokeBeforeDispatch = this.spokeThisTurn; // speech before the dispatch WAS the ack — don't stack another\n this.turnDispatched = true;\n this.turnBriefs.add(String(brief ?? ''));\n // Turn-terminal: force the NEXT reflex step to be text-only (the spoken ack), so a weak model\n // can't keep polling TaskStatus and emit a redundant ack each step. Cleared by resetTurn.\n this.voice.options.toolChoice = 'none';\n const id = await this.dispatch(String(brief ?? ''), 'act', label ? String(label) : undefined, this.turnFollowUp);\n return this.spokeBeforeDispatch\n ? `Acting on task ${id}. You already acknowledged — end your turn now with NO further text; the result will arrive as a [task ${id} completed] event.`\n : `Acting on task ${id}. Acknowledge briefly; the result will arrive as a [task ${id} completed] event.`;\n },\n };\n }\n\n private thinkTool(): AgentTool {\n return {\n name: 'Think',\n description:\n 'Escalate to a premium deep-reasoning agent for complex analysis, architecture decisions, hard debugging, or planning. ' +\n 'Same async pattern as Act — returns a task id. Use when the problem needs careful thought before (or instead of) action. ' +\n 'Do not use Think for simple tasks — Act is cheaper and faster.',\n parameters: {\n type: 'object',\n required: ['brief'],\n properties: {\n brief: { type: 'string', description: 'the question or problem to reason about deeply' },\n label: { type: 'string', description: 'a short (2-4 word) label for the task' },\n },\n },\n run: async ({ brief, label }) => {\n this.spokeBeforeDispatch = this.spokeThisTurn; // speech before the dispatch WAS the ack — don't stack another\n this.turnDispatched = true;\n this.turnBriefs.add(String(brief ?? ''));\n // Turn-terminal: force the NEXT reflex step to be text-only (the spoken ack), so a weak model\n // can't keep polling TaskStatus and emit a redundant ack each step. Cleared by resetTurn.\n this.voice.options.toolChoice = 'none';\n const id = await this.dispatch(String(brief ?? ''), 'think', label ? String(label) : undefined, this.turnFollowUp);\n return this.spokeBeforeDispatch\n ? `Thinking on task ${id}. You already acknowledged — end your turn now with NO further text; the result will arrive as a [task ${id} completed] event.`\n : `Thinking on task ${id}. Acknowledge briefly; the result will arrive as a [task ${id} completed] event.`;\n },\n };\n }\n\n private taskStatusTool(): AgentTool {\n return {\n name: 'TaskStatus',\n description: 'Status of background tasks. Pass `id` for one task, or omit it to list all.',\n parameters: { type: 'object', properties: { id: { type: 'string' } } },\n run: async ({ id }) => {\n const list = id ? [this.tasks.get(String(id))].filter(Boolean) as TaskRecord[] : [...this.tasks.values()];\n if (!list.length) return id ? `No task '${id}'.` : 'No background tasks.';\n return list.map((t) => `${t.id} (${t.label}): ${t.status}`).join('\\n');\n },\n };\n }\n\n /** Sub-100ms read-only lookups the voice may do itself — everything else stays Act-only.\n * fs-only (no shell; the engine is VFS-abstracted): time, git branch (.git/HEAD read), ls, file\n * head. Output is hard-capped so a lookup can never bloat the skinny voice context. */\n private quickLookTool(): AgentTool {\n const CAP = 2000; // chars — a \"peek\", not a Read\n const kinds = [...new Set(['time', 'branch', 'ls', 'file', 'capabilities', ...Object.keys(this.options.quickLook ?? {})])];\n return {\n name: 'QuickLook',\n description:\n `Instant read-only lookup — one of: ${kinds.join(', ')}. ` +\n 'For trivial facts only; anything needing search, commands, or reasoning goes through Act.',\n parameters: {\n type: 'object',\n required: ['what'],\n properties: {\n what: { type: 'string', enum: kinds, description: 'what to look up' },\n path: { type: 'string', description: 'for ls/file: the path to look at' },\n },\n },\n run: async ({ what, path }) => {\n const fs = this.options.fs;\n try {\n const over = this.options.quickLook?.[String(what)];\n if (over) return await over(path ? String(path) : undefined);\n switch (String(what)) {\n case 'capabilities': {\n // CC-style self-introspection: report the worker's REAL tools so the reflex can\n // answer \"can you…?\" by looking, not guessing. Generalized — no capability hard-coded.\n const actTools = (this.options.actOptions?.tools ?? []) as AgentTool[];\n const names = actTools.map((t) => t.name);\n // MCP servers reach an autonomous worker (cursor/*) via providerOptions, NOT as actTools —\n // so without this the reflex underreports (e.g. denies browser control it actually has).\n const mcpServers = Object.keys((this.options.actOptions?.providerOptions as any)?.mcpServers ?? {});\n const mcpNote = mcpServers.length\n ? ` Plus MCP servers your worker can use: ${mcpServers.join(', ')} (e.g. browser-bridge → drive a real browser: open tabs, navigate, click, screenshot).`\n : '';\n if (!names.length)\n return 'Your worker uses Act\\'s default local toolset (reading/editing files, running shell ' +\n 'commands). No extra tools (e.g. web/internet) are configured; if a request is not a ' +\n 'basic file or shell operation, assume you can\\'t do it and say so.' + mcpNote;\n // Each tool stands on its own — the reflex must resolve a request to the RIGHT one.\n // The trap: it conflates three distinct web capabilities. Spell them apart so it neither\n // overclaims (WebFetch ≠ search) nor underclaims (a browser CAN reach a search engine).\n const hasFetch = names.some((n) => /WebFetch/i.test(n));\n const hasBrowser = names.some((n) => /browser.*(navigate|click|page|type)/i.test(n));\n const hasSearch = names.some((n) => /(^|_)WebSearch$|search/i.test(n) && !/WebFetch|browser/i.test(n));\n const notes: string[] = [];\n if (hasFetch) notes.push('WebFetch retrieves ONE specific URL you are given — it is not a search engine.');\n if (hasBrowser) notes.push('The browser tools drive a real browser: you CAN open a site and, if needed, navigate to a search engine and search there — but it is manual and takes a moment, not an instant lookup.');\n else if (!hasSearch && hasFetch) notes.push('You have no general web-search tool, so for an instant \"search the web\" you can only fetch a URL they provide.');\n const webNote = notes.length ? ' NOTE: ' + notes.join(' ') : '';\n return `Tools your background worker (Act) can actually use: ${names.join(', ')}. ` +\n 'Read each name literally and match the request to a SPECIFIC tool; if none fits, you do NOT have ' +\n 'that ability — say so honestly.' + webNote + mcpNote;\n }\n case 'time':\n return new Date().toString();\n case 'branch': {\n if (!fs) return 'unavailable (no filesystem)';\n const head = (await fs.readFile('.git/HEAD')).trim();\n return head.startsWith('ref: refs/heads/') ? `branch: ${head.slice('ref: refs/heads/'.length)}` : `detached HEAD at ${head.slice(0, 12)}`;\n }\n case 'ls': {\n if (!fs) return 'unavailable (no filesystem)';\n const p = String(path ?? '.');\n try {\n const names = await fs.readDir(p);\n return names.slice(0, 50).join('\\n') + (names.length > 50 ? `\\n… (+${names.length - 50} more)` : '');\n } catch {\n // The reflex often passes the cwd's OWN name (\"linkedin\" while already in …/linkedin →\n // …/linkedin/linkedin, not found). Never fail the turn (live: the reflex then asked the\n // user for a path — bad UX) — fall back to the cwd listing with a note.\n const names = await fs.readDir('.').catch(() => [] as string[]);\n return `'${p}' not found here — you are likely already inside it. Current directory listing:\\n` +\n names.slice(0, 50).join('\\n') + (names.length > 50 ? `\\n… (+${names.length - 50} more)` : '');\n }\n }\n case 'file': {\n if (!fs) return 'unavailable (no filesystem)';\n if (!path) return 'file lookup needs a path';\n try {\n const text = await fs.readFile(String(path));\n return text.length > CAP ? text.slice(0, CAP) + `\\n… (truncated — ${text.length} chars total; Act for the full file)` : text;\n } catch {\n const names = await fs.readDir('.').catch(() => [] as string[]);\n return `'${path}' not found. Current directory contains:\\n` + names.slice(0, 50).join('\\n');\n }\n }\n default:\n return `unknown lookup '${what}'`;\n }\n } catch (e: any) {\n return `lookup failed: ${e?.message ?? e}`;\n }\n },\n };\n }\n\n private answerTaskTool(): AgentTool {\n return {\n name: 'AnswerTask',\n description: 'Relay the user\\'s answer to a pending question from a background task (the \"[task <id> asks]\" events). Pass the id from the event and the user\\'s answer.',\n parameters: {\n type: 'object',\n required: ['id', 'answer'],\n properties: { id: { type: 'string' }, answer: { type: 'string', description: \"the user's answer, verbatim or faithfully summarized\" } },\n },\n run: async ({ id, answer }) => {\n const ask = this.pendingAsks.get(String(id));\n if (!ask) return `No pending question for '${id}' — it may have been answered already or timed out.`;\n ask.resolve(String(answer ?? ''));\n return `Answer relayed — task ${id} resumes.`;\n },\n };\n }\n\n private holdTool(): AgentTool {\n return {\n name: 'Hold',\n description:\n 'The user seems mid-thought — hold the turn (stay listening) instead of answering. ' +\n 'Optionally pass a short filler (\"mhm\", \"go on\") to speak while waiting. Use when the ' +\n 'message sounds incomplete, trailing off, or like they paused to think.',\n parameters: {\n type: 'object',\n properties: {\n filler: { type: 'string', description: 'optional short filler to speak (\"mhm\", \"go on\", \"mm-hm\")' },\n },\n },\n run: async ({ filler }) => {\n this.heldThisTurn = true; // enforce silence mechanically — the weak reflex ignores \"do not respond\" and emits \"…\"\n // Always notify (even with no filler): the host must cancel any pending adaptive micro-ack —\n // a Hold turn is INTENTIONALLY silent, an ack would read as the start of an answer.\n this.notify('hold_filler', filler ? String(filler) : '');\n return 'Holding — listening for the rest of the user\\'s thought. Do not respond further this turn.';\n },\n };\n }\n\n private cancelTaskTool(): AgentTool {\n return {\n name: 'CancelTask',\n description: 'Cancel a running background task by id.',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n run: async ({ id }) => this.cancelTask(String(id)),\n };\n }\n}\n","/**\n * Pluggable component logger. The extracted engine/providers log through\n * `forComponent(name)`; by default that's a console logger gated by DEBUG (env\n * or localStorage). A host (e.g. agentx) routes voice logs into its own logging\n * by calling `configureLogging(hostForComponent)` once at boot.\n *\n * `forComponent` returns a stable proxy that re-resolves the backend per call,\n * so a `configureLogging` after module load still takes effect on loggers that\n * were captured at import time (`const log = forComponent('X')`).\n */\n\nexport interface Logger {\n debug(...args: unknown[]): void;\n verbose(...args: unknown[]): void;\n info(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n}\n\nexport type ForComponent = (name: string) => Logger;\n\n/** Console backend. debug/verbose are gated per-component via DEBUG:\n * env `DEBUG=Name` (or `*`) on server, `localStorage.DEBUG` in browser. */\nfunction consoleForComponent(name: string): Logger {\n const debugEnv =\n (typeof process !== 'undefined' && process.env?.DEBUG) ||\n (typeof localStorage !== 'undefined' && localStorage.getItem('DEBUG')) ||\n '';\n const gated = debugEnv === '*' || debugEnv.split(',').some((p) => p.trim() === name);\n const gate = (fn: (...a: unknown[]) => void) => (gated ? fn : () => {});\n const tag = `[${name}]`;\n return {\n debug: gate((...a) => console.debug(tag, ...a)),\n verbose: gate((...a) => console.debug(tag, ...a)),\n info: (...a) => console.info(tag, ...a),\n warn: (...a) => console.warn(tag, ...a),\n error: (...a) => console.error(tag, ...a),\n };\n}\n\nlet backend: ForComponent = consoleForComponent;\n\n/** Route all voice-mode logs through a host logger (call once at boot). */\nexport function configureLogging(forComponentImpl: ForComponent): void {\n backend = forComponentImpl;\n}\n\n/** Component-scoped logger. Stable across `configureLogging` (re-resolves per call). */\nexport function forComponent(name: string): Logger {\n return {\n debug: (...a) => backend(name).debug(...a),\n verbose: (...a) => backend(name).verbose(...a),\n info: (...a) => backend(name).info(...a),\n warn: (...a) => backend(name).warn(...a),\n error: (...a) => backend(name).error(...a),\n };\n}\n","/**\n * Emotion control for Cartesia TTS — the model emits inline `[emotion]` tags before a sentence\n * (para-chat avatar pattern); we normalize them to Cartesia's supported set and rewrite them as\n * `<emotion value=\"…\"/>` in the spoken transcript. sonic-3 stitches the prosody server-side, so a\n * tag simply rides inline with the words it precedes; `forSpeech()` leaves it intact.\n *\n * Two surfaces:\n * • renderEmotions() — stateless, for a COMPLETE string (worker utterance echo).\n * • EmotionStream — stateful, for the live delta stream (buffers a partial `[…` across chunk\n * boundaries and hugs a pending tag onto the NEXT prose so the tag never goes out word-less —\n * a tag-only transcript would produce no audio and stall the TTS drain).\n */\nimport { forComponent } from './logging';\n\nconst log = forComponent('Emotion');\n\n/** Cartesia sonic-3 emotion vocabulary (primary + extended). Source of truth for normalization\n * AND for the tag list taught to the model — keep the prompt and the parser in lockstep. */\nexport const EMOTIONS = [\n // primary (best results)\n 'neutral', 'angry', 'excited', 'content', 'sad', 'scared',\n // extended\n 'happy', 'enthusiastic', 'elated', 'triumphant', 'amazed', 'surprised', 'flirtatious',\n 'curious', 'calm', 'grateful', 'affectionate', 'sympathetic', 'mysterious', 'frustrated',\n 'disgusted', 'sarcastic', 'disappointed', 'hurt', 'guilty', 'bored', 'tired', 'nostalgic',\n 'apologetic', 'hesitant', 'confused', 'anxious', 'panicked', 'proud', 'confident', 'skeptical',\n 'contemplative', 'determined',\n // remaining sonic-3 vocabulary — without these a valid model tag would be DROPPED (flat delivery).\n 'joking', 'trust', 'anticipation', 'outraged', 'threatened', 'contempt', 'envious',\n 'dejected', 'rejected', 'wistful', 'insecure', 'resigned', 'distant',\n] as const;\n\nconst VALID = new Set<string>(EMOTIONS);\n\n/** Friendly synonyms → a canonical Cartesia emotion, so the model isn't tripped by exact spelling. */\nconst ALIASES: Record<string, string> = {\n cheerful: 'happy', joyful: 'happy', joy: 'happy', glad: 'happy', pleased: 'happy', warm: 'affectionate',\n thrilled: 'excited', eager: 'enthusiastic', ecstatic: 'elated', euphoric: 'elated',\n mad: 'angry', furious: 'angry', annoyed: 'frustrated', irritated: 'frustrated', agitated: 'frustrated',\n shocked: 'surprised', astonished: 'amazed', wonder: 'amazed',\n worried: 'anxious', nervous: 'anxious', afraid: 'scared', alarmed: 'panicked',\n unsure: 'hesitant', uncertain: 'hesitant', doubtful: 'skeptical', suspicious: 'skeptical',\n thoughtful: 'contemplative', focused: 'determined', serious: 'determined',\n playful: 'flirtatious', teasing: 'flirtatious', ironic: 'sarcastic', cheeky: 'sarcastic',\n thankful: 'grateful', sorry: 'apologetic', down: 'sad', melancholic: 'sad', gloomy: 'sad',\n peaceful: 'calm', serene: 'calm', relaxed: 'calm', sleepy: 'tired',\n comedic: 'joking', // Cartesia lists \"joking/comedic\" as one — canonicalize to joking\n};\n\n/** Non-verbal cues Cartesia takes verbatim as bracket tags — pass through, never eaten as an emotion. */\nconst NONVERBAL: Record<string, string> = { laughter: 'laughter', laughs: 'laughter', laugh: 'laughter', laughing: 'laughter' };\n\n/** Normalize a raw tag word to a canonical Cartesia emotion, or null if unmappable. */\nexport function normalizeEmotion(raw: string): string | null {\n const k = raw.trim().toLowerCase();\n if (VALID.has(k)) return k;\n return ALIASES[k] ?? null;\n}\n\n/** Resolve a `[…]` inner word to what should be spoken (`emotion`/`laughter`) — or null to drop it. */\nfunction resolveTag(raw: string): { kind: 'emotion'; value: string } | { kind: 'nonverbal'; value: string } | null {\n const k = raw.trim().toLowerCase();\n if (NONVERBAL[k]) return { kind: 'nonverbal', value: NONVERBAL[k] };\n const e = normalizeEmotion(k);\n return e ? { kind: 'emotion', value: e } : null;\n}\n\n/** A `[word]` (or `[two words]`) bracket tag — letters/spaces only, so array indices / code never match. */\nconst TAG_RE = /\\[([a-zA-Z][a-zA-Z ]{0,24})\\]/g;\n/** A trailing run that could still GROW into a tag (`[exc`) — held back until the next chunk. */\nconst PARTIAL_RE = /\\[[a-zA-Z ]*$/;\n\nexport interface EmotionRender {\n /** transcript for TTS — recognized tags rewritten as Cartesia inline tags */\n speech: string;\n /** on-screen echo — original `[tag]` kept when `show`, stripped otherwise */\n display: string;\n /** spoken words only, all tags removed (echo-discrimination + interrupted-reply text) */\n prose: string;\n}\n\nconst cartesiaTag = (t: { kind: string; value: string }): string =>\n t.kind === 'nonverbal' ? `[${t.value}]` : `<emotion value=\"${t.value}\"/>`;\n\n/** Rewrite a COMPLETE string's `[tag]`s. Stateless — safe only when no tag straddles the input edge\n * (true for whole worker utterances). For the streaming delta path use EmotionStream. */\nexport function renderEmotions(text: string, opts: { show: boolean } = { show: true }): EmotionRender {\n let speech = '', display = '', prose = '', last = 0;\n TAG_RE.lastIndex = 0;\n for (let m = TAG_RE.exec(text); m; m = TAG_RE.exec(text)) {\n const before = text.slice(last, m.index);\n speech += before; display += before; prose += before;\n const tag = resolveTag(m[1]);\n if (tag) {\n speech += cartesiaTag(tag);\n if (opts.show) display += m[0];\n } else {\n log.debug(`dropping unknown emotion tag ${m[0]}`);\n }\n last = m.index + m[0].length;\n }\n const tail = text.slice(last);\n return { speech: speech + tail, display: display + tail, prose: prose + tail };\n}\n\n/**\n * Streaming emotion parser. `feed(delta)` returns the spans completed by this chunk; a recognized tag\n * is stashed and PREPENDED to the next non-empty prose (Cartesia wants the tag right before its words,\n * and a tag-only continuation would synthesize nothing → drained-but-silent stall). A trailing `[…`\n * that is still a viable tag prefix is buffered until it completes or the stream flushes.\n */\nexport class EmotionStream {\n private buf = '';\n private pending: { kind: string; value: string } | null = null;\n constructor(public show = true) {}\n\n feed(delta: string): EmotionRender { this.buf += delta; return this.drain(false); }\n flush(): EmotionRender { return this.drain(true); }\n\n private drain(final: boolean): EmotionRender {\n let body = this.buf;\n // Hold back a trailing run that could still grow into a tag — unless this is the final flush.\n if (!final) {\n const p = body.match(PARTIAL_RE);\n if (p) { this.buf = p[0]; body = body.slice(0, body.length - p[0].length); }\n else this.buf = '';\n } else this.buf = '';\n\n let speech = '', display = '', prose = '', last = 0;\n TAG_RE.lastIndex = 0;\n for (let m = TAG_RE.exec(body); m; m = TAG_RE.exec(body)) {\n this.emit(body.slice(last, m.index), (s, d, p) => { speech += s; display += d; prose += p; });\n const tag = resolveTag(m[1]);\n if (tag) { this.pending = tag; if (this.show) display += m[0]; }\n else log.debug(`dropping unknown emotion tag ${m[0]}`);\n last = m.index + m[0].length;\n }\n this.emit(body.slice(last), (s, d, p) => { speech += s; display += d; prose += p; });\n return { speech, display, prose };\n }\n\n /** Emit a prose span, flushing any pending tag onto its FRONT (only once real words appear). */\n private emit(text: string, sink: (s: string, d: string, p: string) => void): void {\n if (!text) return;\n let speech = text;\n // Hug the tag onto the first span carrying actual WORDS (not bare punctuation/space) — a tag-only or\n // tag+punctuation transcript synthesizes no audio and would stall the TTS drain.\n if (this.pending && /[\\p{L}\\p{N}]/u.test(text)) { speech = cartesiaTag(this.pending) + text; this.pending = null; }\n sink(speech, text, text);\n }\n}\n","/**\n * VoiceEngine — the portable voice-conversation brain: state machine (idle|listening|thinking|\n * speaking), barge-in policy (AEC-trivial + heuristic echo tier), gapless TTS turn handoff,\n * utterance merge window, interrupted-reply tracking, ack echo-leak guard.\n *\n * Pure logic over three injected seams (STT, TTS, AudioSink) — runs in CLI, server, or browser.\n * Hosts wire `onUtterance` to their dispatch and feed `beginSpeech()/speakDelta()/endSpeech()`;\n * `interrupt()` is the barge-in primitive. Behavior validated live; see mind/11-voice.md.\n */\nimport { forComponent } from './logging';\nimport { EmotionStream } from './emotion';\nimport type { AudioSink, VoiceState } from './types';\n\nconst log = forComponent('VoiceEngine');\n\n/** Injectable time source — ALL engine timing (merge windows, barge grace, overlap resume, drain\n * settles) routes through it. Defaults to real timers; the deterministic bench swaps a virtual\n * clock so timing scenarios run instantly and exactly. */\nexport interface EngineClock {\n now(): number;\n setTimeout(fn: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n}\nexport const realClock: EngineClock = {\n now: () => performance.now(),\n setTimeout: (fn, ms) => setTimeout(fn, ms),\n clearTimeout: (h) => clearTimeout(h as ReturnType<typeof setTimeout>),\n};\n\n/** One structured diagnostic event (fire-and-forget, never affects behavior). `t` = engine clock ms.\n * Emitted at every DECISION point; kinds + fields are the per-session forensic record\n * (CLI: `<session>.voice.jsonl`; lab: `<session>.timeline.jsonl`). See mind/11-voice.md §Diagnostics. */\nexport interface DiagEvent { t: number; kind: string; [k: string]: unknown }\n\n/** Sanitize text for the spoken channel (and its on-screen echo). Drops markdown punctuation TTS would\n * read aloud (\"star\"/\"hash\"), turns em/en dashes and table pipes into spoken pauses, normalizes \"30 %\"\n * → \"30%\", and collapses filler dot-runs (\"now.....\" → \"now.\"). Per-delta safe: every map is local to\n * the chunk (single chars / line-anchored), so chunk boundaries never split a multi-char span. */\nexport const forSpeech = (t: string): string =>\n t.replace(/[*`#]+/g, '')\n // underscores: strip only EMPHASIS pairs (_word_ at word boundaries) — intra-word underscores are\n // real content (EXPORT_PLAYBOOK.txt, .DS_Store) and must survive in both speech and echo\n .replace(/(?<![\\p{L}\\p{N}])_([^_\\n]+)_(?![\\p{L}\\p{N}])/gu, '$1')\n .replace(/^[ \\t]*[-•]\\s+/gm, '') // leading list marker\n .replace(/\\s*[\\u2013\\u2014]\\s*/g, ', ') // en/em dash → spoken pause (prompt forbids dashes in speech)\n .replace(/[\\u2010\\u2011]/g, '-') // (non-breaking) hyphen → plain hyphen (TTS reads \"8-12\" fine)\n .replace(/\\s*\\|\\s*/g, ', ') // table pipe → pause\n .replace(/(\\d)\\s+%/g, '$1%') // \"30 %\" → \"30%\" (else \"thirty space percent\")\n .replace(/\\.{3,}/g, '.'); // filler dot-run → single period\n\nconst normWord = (w: string): string => w.toLowerCase().replace(/[^a-z0-9]/g, '');\n\n/** Trailing extra words the final may add WITHOUT changing what the reflex must answer — politeness/\n * discourse fillers only. Any CONTENT word (\"…very short\" + \"joke\") means the speculation answered a\n * truncated thought and must abort (live-confirmed quality bug: prosodic-pause partials). */\nconst SPEC_TRAILING_OK = new Set(['please', 'thanks', 'thank', 'you', 'now', 'okay', 'ok', 'kindly', 'alright', 'then', 'though', 'right', 'yeah']);\n\n/** Does the endpointed FINAL confirm a SPECULATED partial? Exact normalized match, or the speculation\n * is a word-prefix of the final with ≤2 trailing extra NON-CONTENT words (SPEC_TRAILING_OK — the\n * speculated words must all land; the last one may be a char-prefix of its final counterpart, a\n * mid-word partial). The same prefix shape as refinalizes(), applied host-side to decide\n * confirm-vs-abort of a speculative reflex call. */\nexport function speculationConfirms(spec: string, final: string): boolean {\n const sw = spec.trim().split(/\\s+/).map(normWord).filter(Boolean);\n const fw = final.trim().split(/\\s+/).map(normWord).filter(Boolean);\n if (!sw.length || fw.length < sw.length || fw.length > sw.length + 2) return false;\n for (let i = 0; i < sw.length - 1; i++) if (sw[i] !== fw[i]) return false;\n if (!fw[sw.length - 1].startsWith(sw[sw.length - 1])) return false;\n for (let i = sw.length; i < fw.length; i++) if (!SPEC_TRAILING_OK.has(fw[i])) return false;\n return true;\n}\n\n/** Structural contracts (satisfied by SonioxSTT/CartesiaTTS or test fakes). */\nexport interface SttLike {\n usingAec: boolean;\n onPartial: (text: string) => void;\n onUtterance: (text: string, endpointAt: number) => void;\n onLevel: (rms: number) => void;\n /** Optional: unrecoverable capture failure (e.g. mic produced no audio) — host tears voice down. */\n onFatal?: (message: string) => void;\n start(): Promise<void> | void;\n reset(): void;\n stop(): void;\n}\nexport interface TtsLike {\n onAudio: (chunk: Uint8Array) => void;\n onDone: () => void;\n /** Optional word-timestamp seam for karaoke reveal (revealMode==='word'). `start[i]` = seconds\n * from turn-audio start. Set `wantTimestamps` to request them from the provider. */\n onTimestamps?: (words: string[], start: number[]) => void;\n wantTimestamps?: boolean;\n connect(): Promise<void> | void;\n /** Optional: prime the synthesis pipeline right after connect (throwaway context, audio discarded)\n * so the FIRST real turn doesn't pay the provider's cold-synthesis spin-up. */\n warmup?(): void;\n newContext(): string;\n speak(text: string, cont: boolean): void;\n end(): void;\n cancel(): void;\n close(): void;\n}\n\nexport class VoiceEngineOptions {\n stt!: SttLike;\n tts!: TtsLike;\n player!: AudioSink;\n /** a final utterance arrived (endpoint) — host dispatches it as a turn */\n onUtterance: (text: string) => void = () => {};\n /** live partial transcript while listening (host renders the 🎤 line) */\n onPartial: (text: string) => void = () => {};\n onState: (s: VoiceState) => void = () => {};\n /** user spoke/acted over playback — host aborts the in-flight turn (called AFTER audio is killed).\n * phase: 'speaking' = cut mid-speech (real interruption); 'drain' = in the final audio tail\n * (normal turn-taking — hosts shouldn't alarm). */\n onBargeIn: (phase: 'speaking' | 'drain') => void = () => {};\n /** spoken micro-ack on utterance endpoint (masks LLM TTFT); '' disables */\n ackPhrase = '';\n /** ADAPTIVE micro-ack: on an utterance-dispatched turn, speak a short varied ack ONLY if no reflex\n * delta has arrived after this many ms (masks a slow TTFT without acking every turn — a fixed\n * per-turn ack was rejected as robotic). First delta / interrupt / hold cancels it. 0 = off. */\n adaptiveAckMs = 0;\n /** the adaptive ack actually fired (host can mark the turn as spoken — e.g. suppress dead-air repair) */\n onAdaptiveAck: () => void = () => {};\n /** Endpoint merge window (ms): hold an endpointed utterance briefly — if speech resumes (spelled\n * letters, mid-thought pauses), the next utterance MERGES instead of dispatching a truncated one\n * (\"E-L-Y.\" / \"A.\"). Costs this much latency per turn; 0 disables. */\n utteranceMergeMs = 350;\n /** Extended merge window (ms) for utterances that look incomplete (trailing conjunction/filler).\n * Gives the user time to finish their thought without triggering a model call. */\n incompleteMergeMs = 1500;\n /** Grace window (ms) after an utterance dispatches, during which the user's own trailing audio cannot\n * barge the reply it requested. Soniox keeps finalizing partials past <end>; without this they read\n * as a barge and abort the fresh turn (live: mid-sentence self-interruption + steps=1→steps=0 double\n * abort). Short enough that a genuine immediate barge (\"no wait—\") still lands right after. */\n bargeGraceMs = 600;\n /** Barge-in (talk over the assistant to interrupt). true = full-duplex (needs echo cancellation, or\n * the assistant's own TTS bleeds back and self-interrupts). false = HALF-DUPLEX: the engine is deaf\n * while audible (speaking + drain tail), so echo can never become a phantom turn — the right mode\n * when there's no AEC (e.g. the non-VPIO mic fallback) and no headphones. Cost: can't interrupt. */\n bargeIn = true;\n /** Filler phrase spoken when holding for an incomplete utterance ('' disables). */\n holdFiller = '';\n /** Called when the engine holds an incomplete utterance (host can render a visual cue). */\n onHold: () => void = () => {};\n /** heuristic (non-AEC) energy barge-in tuning */\n bargeRmsMult = 2;\n bargeRmsFloor = 500;\n /** Overlap turn-taking (AEC tier, needs player.pause/resume) — human phone-call model, driven by\n * the STT ITSELF (a trained speech classifier) instead of energy thresholds (energy could not\n * separate residue bursts from speech in every room — hiccup whack-a-mole): a GENUINE partial\n * (novel words dominate — echo of our own reply is inert) while speaking → PAUSE (exact-sample\n * hold); partial grows into dominant-novel ≥2 words → cede (interrupt; the LLM re-enters); partial\n * stalls/endpoints without ceding (backchannel by DURATION, not vocabulary) → resume + drop. false disables. */\n overlapPause = true;\n /** no new partial activity for this long while paused → resume, drop the interjection */\n overlapResumeMs = 700;\n /** A genuine barge over a LONG reply is defeated by the dominant-novel gate: Meet echoes our own\n * speech back, so the partial is mostly our words + a few of hers → never \"dominant novel\" → it\n * resumes (replaying old audio — the audible \"completes the buffer\" blip) instead of ceding.\n * Mechanism-based discriminator: a re-PAUSE this soon after a resume = a persistent human, not an\n * echo blip (which pauses once and stalls). Cede on the re-pause regardless of the novel gate. */\n overlapRepauseCedeMs = 1500;\n /** Speculative ENERGY pre-pause while speaking (AEC tier): two residue gate-passes within 350ms →\n * pause ~300ms before the STT tokens land. But energy CANNOT separate residue bursts from speech\n * (the documented whack-a-mole) — so a residue spike during loud playback false-pauses with NO user\n * speech at all, an audible hiccup. Default OFF: the genuine-gated STT partial is the\n * mechanism-correct pause trigger; enable only if barge-in onset feels sluggish in a clean-AEC room. */\n overlapEnergyHold = false;\n /** SPECULATIVE REFLEX START (the root TTFT fix): a partial transcript that has stopped changing for\n * this many ms AND carries ≥ speculativeMinWords is \"stable\" — `onSpeculate` fires so the host can\n * start the reflex EARLY, ~endpoint+merge (500-850ms) before the final would dispatch. The\n * speculative call's output is HELD by the host (nothing reaches TTS) until the endpointed final\n * confirms it (see speculationConfirms). At most one speculation per turn-in-progress. 0 = off. */\n speculativeMs = 0;\n /** Minimum word count for a partial to qualify as a speculation trigger. */\n speculativeMinWords = 4;\n /** A stable partial (speculativeMs) — the host starts a HELD speculative reflex call. */\n onSpeculate: (text: string) => void = () => {};\n /** AGENT-SIDE BACKCHANNELING (rule-based v1): while LISTENING to a long multi-clause user turn, a\n * partial that reaches a clause boundary (trailing [,.;!?] or conjunction/filler) and then stays\n * UNCHANGED for this many ms (a micro-pause — before the silence endpoint fires) triggers a short\n * quiet TTS blip (\"Mm-hm.\") on a throwaway context. ZERO floor-claim: no state change, no timers\n * touched, no turn context — audio passes a narrow gate bypass and a real turn supersedes it via\n * context rotation. Latin-predominant partials only (Hebrew/mixed text never misfires — the\n * boundary/conjunction heuristics are English-tuned, so non-Latin turns simply get no blips).\n * 0 = off (default). ~200-300 recommended: live, Soniox's SEMANTIC endpoint (<end>) lands within\n * ~300-400ms of a clause pause — a longer stability window loses the race and never fires. */\n backchannelMs = 0;\n /** Min gap between blips (rate limit); additionally max 2 blips per user turn-in-progress. */\n backchannelMinGapMs = 8000;\n /** Only multi-clause turns: the partial must carry at least this many words before a blip. */\n backchannelMinWords = 8;\n /** A backchannel blip was spoken (host renders a timeline event; the blip is NOT a reply). */\n onBackchannel: (phrase: string) => void = () => {};\n /** The partial outgrew the speculated text (user kept talking) — the host aborts the speculation\n * quietly (the endpointed final will also refuse to confirm; this just stops the billing earlier). */\n onSpeculateAbort: () => void = () => {};\n /** Map inline `[emotion]` tags (emitted by the model, prompt-taught) into Cartesia inline emotion\n * tags in the spoken transcript (sonic-3 stitches the prosody). false = strip them silently. */\n emotions = true;\n /** Show the `[emotion]` tags in the on-screen echo (debug). false = hide (spoken-only). */\n showEmotions = false;\n /**\n * Progressive text reveal — the \"karaoke\" capability, opt-in.\n * 'off' — no reveal events (CLI default; the host renders text however it likes).\n * 'delta' — emit `onReveal(fullText)` as each spoken delta lands (near-free; text grows\n * in step with the model stream).\n * 'word' — reveal word-by-word synced to the TTS playback CLOCK (true karaoke). Requires a\n * timestamp-emitting TTS (CartesiaTTS.wantTimestamps) driven over `AudioSink.playedMs`.\n */\n revealMode: 'off' | 'delta' | 'word' = 'off';\n /** Called with the cumulative revealed text for the current assistant turn (see `revealMode`).\n * Reset to '' at the start of each spoken turn. */\n onReveal: (revealed: string) => void = () => {};\n /** Time source for every engine timer/timestamp. Default: real time (identical behavior). */\n clock: EngineClock = realClock;\n /** Structured diagnostic event at every decision point (state transitions, dispatch/drop paths,\n * barge-in, overlap pause/resume, acks, speculation, backchannels, echo swallows). Fire-and-forget:\n * a throwing handler is caught once and diagnostics disable — engine behavior is never affected. */\n onDiag: (ev: DiagEvent) => void = () => {};\n}\n\nexport class VoiceEngine {\n public options: VoiceEngineOptions;\n public state: VoiceState = 'idle';\n protected stt: SttLike;\n protected tts: TtsLike;\n protected player: AudioSink;\n private speaking = false; // audible (deltas flowing OR audio draining)\n private ctxOpen = false; // the current TTS context still accepts deltas (false once end-frame sent)\n private interrupted = false; // barge-in latch: drop in-flight deltas until the next legitimate turn\n private spokeDeltas = false; // a TTS context is open for the current spoken turn\n private revealText = ''; // cumulative revealed (on-screen) text for the current turn — see revealMode\n // 'word' karaoke reveal: spoken-word start times (sec, absolute from turn-audio start) + poll state.\n private wordStarts: number[] = [];\n private revealedN = 0;\n private revealPoll: unknown = null;\n private clock: EngineClock;\n private drainTimer: unknown = null;\n // heuristic tier state (inert under AEC) — frozen as validated in the experiment\n private echoWords = new Set<string>();\n private prevReply = '';\n private reply = '';\n private echoUntil = 0;\n private baseline = 0;\n private hot = 0;\n private suspectUntil = 0;\n private ackAt = 0; // when the micro-ack was spoken — its echo can leak before the AEC filter converges\n private lastAck = ''; // the exact ack text last spoken (fixed OR adaptive) — the echo-leak guard matches it\n private ackTimer: unknown = null; // one-shot adaptive-ack timer (armed at dispatch, cancelled on first delta)\n // The adaptive micro-ack ALREADY spoke this turn → the reflex's own leading ack (\"Still on it.\") is now\n // redundant (live: host said \"On it.\" then the reflex said \"Still on it.\"). While this is set, speakDelta\n // probes the reflex's opening sentence and DROPS it if it's purely an acknowledgement; real content passes\n // through. Reset per turn in beginSpeech()/interrupt().\n private adaptiveAckFired = false;\n private ackProbe: string | null = null; // buffered reflex prose while probing the leading ack (null = not probing)\n private bargeGraceUntil = 0; // no barge-in until this time — the user's OWN trailing audio (after the\n // utterance that JUST dispatched this turn) must not immediately re-interrupt the reply it requested.\n private pendingUtt = ''; // endpointed text held for the merge window\n private mergePath: 'direct' | 'merged' = 'direct'; // how the pending utterance was assembled (diag)\n private lastGraceDiag = 0; // grace_suppress emitted once per grace window\n private pendingTimer: unknown = null;\n // Duplicate-final guard: STT sometimes re-finalizes the SAME audio a beat later (past the merge\n // window) — the identical utterance dispatched twice with no reply in between (live: \"When you\n // start\" twice). Conservative: only an IDENTICAL (normalized) text, within dupFinalMs, with zero\n // reply deltas since the first dispatch, is dropped. A user genuinely repeating themselves after\n // the agent replied (or after 3s) still dispatches.\n private lastDispatchFlat = '';\n private lastDispatchWords: string[] = [];\n private lastDispatchAt = 0;\n private repliedSinceDispatch = false;\n private static readonly DUP_FINAL_MS = 3000;\n private lastInterrupted: { full: string; heard: string } | null = null;\n // overlap (pause) tier state — AEC + pause-capable sinks only\n private pausedAt = 0;\n private lastResumeAt = 0; // when the overlap last resumed from a false alarm — a quick re-pause cedes\n private lastOverlapPartial = ''; // change-detection: only NEW partial text counts as activity\n private resumeTimer: unknown = null;\n private turnStartAt = 0; // timestamp when the current turn began (for TTFT logging)\n // speculative reflex trigger state (options.speculativeMs) — see trackSpeculation\n private specPartial = ''; // last partial observed (stability = unchanged for speculativeMs)\n private specTimer: unknown = null;\n private specText = ''; // text handed to onSpeculate ('' = no speculation in flight)\n private specSpent = false; // at most one speculation per turn-in-progress\n // backchannel blip state (options.backchannelMs) — see trackBackchannel\n private bcPartial = ''; // last partial observed (stability = unchanged for backchannelMs)\n private bcTimer: unknown = null;\n private bcCount = 0; // blips this user turn-in-progress (max 2; reset at dispatch)\n private bcActive = false; // NARROW audio-gate bypass: blip audio may reach the sink while listening\n private bcActiveTimer: unknown = null; // safety: clear the bypass even if the blip's 'done' is lost\n private lastBcAt = 0;\n private lastBcPhrase = ''; // exact blip text last spoken — flushUtterance strips its mic echo\n private recentBc: string[] = [];\n // Central speech queue (above the TTS context): complete worker utterances serialize into ONE\n // playback stream, one-at-a-time, never splicing into the live reflex's open utterance.\n private uttQueue: string[] = [];\n // Per-turn emotion-tag parser (reset on beginSpeech) — converts `[emotion]` → Cartesia inline tags\n // for TTS, tracks tag-free prose for echo discrimination, and surfaces display text for the screen.\n private emo: EmotionStream | null = null;\n\n constructor(options?: Partial<VoiceEngineOptions>) {\n this.options = { ...new VoiceEngineOptions(), ...options };\n const o = this.options;\n if (!o.stt || !o.tts || !o.player) throw new Error('VoiceEngine needs stt, tts and player (see cli/voice.ts VoiceIO for platform defaults)');\n this.stt = o.stt;\n this.tts = o.tts;\n this.player = o.player;\n this.clock = o.clock;\n }\n\n async start(): Promise<void> {\n // `speaking` gates real-turn audio; `bcActive` is the ONLY other pass — a backchannel blip's\n // throwaway context, allowed through while listening (unlike warmup, whose audio this gate drops).\n this.tts.onAudio = (c) => { if (this.speaking || this.bcActive) this.player.write(c); };\n // Karaoke reveal: ask the TTS for word timestamps and accumulate them for the playback-synced poll.\n if (this.options.revealMode === 'word') {\n this.tts.wantTimestamps = true;\n this.tts.onTimestamps = (_words, start) => {\n if (this.interrupted) return;\n for (const s of start) this.wordStarts.push(s);\n };\n }\n this.stt.onPartial = (text) => this.handlePartial(text);\n this.stt.onUtterance = (text) => this.handleUtterance(text);\n this.stt.onLevel = (rms) => this.handleLevel(rms);\n await Promise.all([this.tts.connect(), this.stt.start()]);\n // Pre-warm at mic-on: prime the TTS synthesis pipeline (throwaway context; any audio it returns\n // is dropped by the `speaking` gate above / stale-context filter) so the first real turn doesn't\n // pay the provider's cold-synthesis spin-up (~1s+ live on Cartesia).\n this.tts.warmup?.();\n this.setState('listening');\n log.debug(`voice I/O up (${this.stt.usingAec ? 'AEC' : 'heuristic echo'} capture)`);\n }\n\n get usingAec(): boolean {\n return this.stt.usingAec;\n }\n\n /** Flip barge-in at runtime (e.g. the mic fell back to non-VPIO → go half-duplex so echo can't leak). */\n setBargeIn(on: boolean): void { this.options.bargeIn = on; }\n\n /** Show/hide the `[emotion]` debug tags in the echo (next turn's stream picks it up). */\n setShowEmotions(on: boolean): void { this.options.showEmotions = on; }\n\n /** Diagnostics tap (options.onDiag). Fire-and-forget: a throwing handler disables the tap once —\n * it can NEVER perturb engine behavior. Protected so VoiceIO can route provider events through it. */\n private diagOn = true;\n protected diag(kind: string, fields?: Record<string, unknown>): void {\n if (!this.diagOn) return;\n try { this.options.onDiag({ t: this.clock.now(), kind, ...fields }); }\n catch (e) { this.diagOn = false; log.debug(`onDiag threw — diagnostics disabled: ${e instanceof Error ? e.message : e}`); }\n }\n\n private idleWaiters: (() => void)[] = [];\n private setState(s: VoiceState): void {\n if (this.state === s) return;\n this.diag('state', { from: this.state, to: s });\n this.state = s;\n this.options.onState(s);\n if (s !== 'speaking' && s !== 'thinking') {\n for (const r of this.idleWaiters.splice(0)) r();\n }\n }\n\n /** Resolve when the engine is no longer speaking (immediate if already idle). */\n awaitIdle(): Promise<void> {\n if (this.state !== 'speaking' && this.state !== 'thinking') return Promise.resolve();\n return new Promise((r) => this.idleWaiters.push(r));\n }\n\n // --- speaking side (host-driven) ---\n\n /** open a spoken turn (idempotent — safe from both onUtterance and first-delta paths).\n * `ack` speaks the configured micro-ack as the context opener (utterance path only —\n * masks LLM TTFT; re-voice turns begun by their first delta skip it). */\n beginSpeech(ack = false): void {\n if (this.speaking && this.ctxOpen) return;\n if (this.drainTimer) { this.clock.clearTimeout(this.drainTimer); this.drainTimer = null; }\n this.interrupted = false; // a new turn re-arms speech\n this.bcSupersede(); // a real turn mid-blip: close the audio bypass; newContext() below rotates the\n // ctx so Cartesia's stale-context filter drops any blip stragglers, and markTurn cuts the tail.\n // gapless handoff: a new turn while the previous one's audio drains keeps the SAME player\n // (markTurn would cut the tail) and just opens a fresh TTS context — Cartesia rejects deltas\n // on an ended context (\"Context closed\" 400, narration silently lost).\n this.resetOverlap(true); // a held pause must release — gapless handoff keeps the same player (no FLUSH)\n this.diag('tts_turn_begin', { ack, gapless: this.speaking });\n if (!this.speaking) this.player.markTurn();\n this.speaking = true;\n this.ctxOpen = true;\n this.spokeDeltas = false;\n this.adaptiveAckFired = false; this.ackProbe = null; // fresh turn — no ack fired yet, don't probe\n this.reply = '';\n this.revealText = '';\n this.wordStarts = [];\n this.revealedN = 0;\n if (this.options.revealMode === 'word') this.startWordReveal();\n this.emo = this.options.emotions ? new EmotionStream(this.options.showEmotions) : null;\n this.echoWords = new Set(this.words(this.prevReply)); // previous reply's echo may still be in flight\n this.tts.newContext();\n this.clearAckTimer('new_turn'); // a fresh turn supersedes any armed ack from a previous one\n if (ack && this.options.ackPhrase) {\n this.diag('ack_fired', { phrase: this.options.ackPhrase, adaptive: false });\n this.tts.speak(this.options.ackPhrase + ' ', true);\n this.spokeDeltas = true; this.ackAt = this.clock.now(); this.lastAck = this.options.ackPhrase;\n for (const w of this.words(this.options.ackPhrase)) this.echoWords.add(w); // ack is OUR audio — its echo must not read as novel speech\n }\n // Adaptive micro-ack: arm a one-shot timer — a short varied ack speaks ONLY if the reflex is still\n // silent when it fires (slow TTFT); the reply then continues the same TTS context. First delta\n // cancels it (fast turns stay ack-free); interrupt/endSpeech/hold cancel too.\n else if (ack && this.options.adaptiveAckMs > 0) {\n this.ackTimer = this.clock.setTimeout(() => {\n this.ackTimer = null;\n if (!this.speaking || !this.ctxOpen || this.spokeDeltas || this.interrupted) return;\n const phrase = this.pickAck();\n this.diag('ack_fired', { phrase, adaptive: true, waitedMs: this.options.adaptiveAckMs });\n this.tts.speak(phrase + ' ', true);\n this.spokeDeltas = true;\n this.ackAt = this.clock.now();\n this.lastAck = phrase;\n for (const w of this.words(phrase)) this.echoWords.add(w); // ack is OUR audio — its echo must not read as novel speech\n this.setState('speaking'); // ack audio is playing — don't sit in \"thinking\" while audibly speaking\n this.adaptiveAckFired = true; this.ackProbe = ''; // the reflex's own leading ack is now redundant — probe + drop it\n this.options.onAdaptiveAck();\n }, this.options.adaptiveAckMs);\n }\n // TTFT is stamped at the real turn start (flushUtterance, when the user's utterance dispatches);\n // only fall back to here for a re-voice turn that has no preceding utterance.\n if (!this.turnStartAt) this.turnStartAt = this.clock.now();\n this.setState('thinking');\n }\n /** Feed a spoken delta. Returns the on-screen echo text (emotion tags shown/hidden per config) so the\n * host renders the SAME stream that was parsed for TTS — no second, state-doubling parse. */\n speakDelta(text: string): string {\n // After a barge-in the aborted turn's stream may keep delivering (re-voice turns have no abort\n // signal) — those deltas must NOT re-open speech. endSpeech()/beginSpeech() clear the latch.\n if (this.interrupted) return '';\n this.clearAckTimer('first_delta'); // the reflex spoke in time — no ack needed\n // Leading-ack suppression: the adaptive micro-ack already spoke, so the reflex's own opening\n // acknowledgement is a duplicate. Buffer its first sentence; drop it if it's purely an ack, else\n // release everything untouched. Only the FIRST sentence is probed — real content always survives.\n if (this.adaptiveAckFired && this.ackProbe !== null) {\n this.ackProbe += text;\n const probe = this.ackProbe;\n const bare = probe.replace(/\\[emotion[^\\]]*\\]/gi, '').replace(/^\\s+/, '');\n const m = bare.match(/^([^.!?…\\n]*[.!?…\\n])([\\s\\S]*)$/); // leading sentence + remainder\n if (!m && bare.length < 80) return ''; // no boundary yet and still short — wait for more\n this.ackProbe = null; this.adaptiveAckFired = false; // decision made for this turn\n const lead = (m ? m[1] : bare);\n const norm = lead.replace(/[^a-z ]/gi, ' ').replace(/\\s+/g, ' ').trim().toLowerCase();\n if (VoiceEngine.ACK_LEADING.test(norm)) {\n const rest = m ? m[2] : '';\n this.diag('reflex_ack_suppressed', { lead: lead.trim() });\n if (!rest.trim()) return ''; // the whole reply was an ack → nothing left to speak\n text = rest; // speak only the content after the redundant ack\n } else {\n text = probe; // not an ack — release the buffered prose verbatim\n }\n }\n if (!this.speaking || !this.ctxOpen) this.beginSpeech();\n // Split the delta into spoken transcript (Cartesia emotion tags inline), tag-free prose (echo\n // discrimination), and screen-echo display. The stream buffers a tag split across chunk boundaries.\n let { speech, display, prose } = this.emo ? this.emo.feed(text) : { speech: text, display: text, prose: text };\n // Boundary-space repair: some models emit consecutive sentence deltas with no separating space\n // (\"…Israel.\" + \"Anything else?\") — the join renders AND speaks as \"Israel.Anything\". If the\n // forwarded prose so far ends in sentence punctuation and this delta starts immediately with an\n // uppercase letter, insert the missing space. Uppercase-only on purpose: \"3.\" + \"5\" (a split\n // decimal) must NOT gain a space.\n if (this.reply && /[.!?…]$/.test(this.reply) && /^[A-Z]/.test(prose)) { speech = ' ' + speech; display = ' ' + display; prose = ' ' + prose; }\n this.reply += prose;\n if (prose.trim()) this.repliedSinceDispatch = true; // an agent reply arrived — a later identical final is a genuine repeat\n for (const w of this.words(this.reply)) this.echoWords.add(w);\n this.tts.speak(forSpeech(speech), true); // strip markdown punctuation so TTS doesn't read \"dash\"/\"star\"/\"hash\" aloud\n if (!this.spokeDeltas && this.turnStartAt) log.debug(`ttft: ${Math.round(this.clock.now() - this.turnStartAt)}ms`);\n this.spokeDeltas = true;\n this.setState('speaking');\n // Progressive reveal (opt-in). 'delta' fires per-delta with the growing on-screen text; 'word'\n // accumulates the text here but reveals via the playback-synced poll (startWordReveal).\n if (this.options.revealMode !== 'off' && display) {\n this.revealText += display;\n if (this.options.revealMode === 'delta') this.options.onReveal(this.revealText);\n }\n return display;\n }\n /** Karaoke reveal poll: reveal the display-word prefix up to the count of spoken words whose\n * Cartesia start time has been reached on the playback clock (`AudioSink.playedMs`, which excludes\n * paused time). Poll-driven (not AudioContext timers) so it's portable across CLI/browser sinks and\n * deterministic under the virtual clock. */\n private startWordReveal(): void {\n if (this.revealPoll) return;\n const tick = () => {\n this.revealPoll = null;\n if (!this.speaking || this.interrupted || this.options.revealMode !== 'word') return;\n const playedSec = this.player.playedMs() / 1000;\n let n = this.revealedN;\n while (n < this.wordStarts.length && this.wordStarts[n]! <= playedSec) n++;\n if (n !== this.revealedN) {\n this.revealedN = n;\n const words = this.revealText.trim().split(/\\s+/).filter(Boolean);\n this.options.onReveal(words.slice(0, n).join(' '));\n }\n this.revealPoll = this.clock.setTimeout(tick, 60);\n };\n this.revealPoll = this.clock.setTimeout(tick, 60);\n }\n /** Stop the poll. `finalFlush` reveals the whole line once audio has finished, so a timing\n * undershoot never leaves the tail unrevealed (skipped after a barge-in — the truncated prefix\n * is what was actually spoken). */\n private stopWordReveal(finalFlush: boolean): void {\n if (this.revealPoll) { this.clock.clearTimeout(this.revealPoll); this.revealPoll = null; }\n if (finalFlush && this.options.revealMode === 'word' && !this.interrupted) {\n const full = this.revealText.trim();\n if (full) this.options.onReveal(full);\n }\n }\n /** close the spoken turn (idempotent); stays audible until ALL audio arrived AND playback drains */\n endSpeech(): void {\n this.interrupted = false; // the interrupted turn is over — next turn may speak\n this.clearAckTimer('turn_end'); // turn is over — a late ack would speak into the drain\n // A leading-ack probe still holding (short reply, no terminal punctuation): decide now so its content\n // isn't swallowed. If the held prose is purely an ack, drop it; otherwise speak it before the turn closes.\n const heldProbe = this.ackProbe;\n this.adaptiveAckFired = false; this.ackProbe = null; // always clear at turn end — no stale probe into the next turn\n if (heldProbe) {\n const norm = heldProbe.replace(/\\[emotion[^\\]]*\\]/gi, '').replace(/[^a-z ]/gi, ' ').replace(/\\s+/g, ' ').trim().toLowerCase();\n if (VoiceEngine.ACK_LEADING.test(norm)) this.diag('reflex_ack_suppressed', { lead: heldProbe.trim() });\n else this.speakDelta(heldProbe); // real content held with no boundary — release it now\n }\n if (!this.speaking) return;\n this.diag('tts_turn_end', { spoke: this.spokeDeltas, replyChars: this.reply.length });\n this.ctxOpen = false; // context ends now; audio keeps draining\n // Flush any tail the emotion parser held back (a dangling `[…` partial, or a pending tag) so the\n // last words aren't swallowed; the real audio flush is tts.end()'s cont=false below.\n if (this.emo) { const t = this.emo.flush(); this.emo = null; if (t.prose) this.reply += t.prose; if (t.speech) this.tts.speak(forSpeech(t.speech), true); }\n if (this.reply) this.prevReply = this.reply;\n // remain 'speaking' (barge-in armed, echo discrimination active) until audio actually finishes\n const settle = () => {\n if (this.ctxOpen) { this.drainTimer = null; return; } // a newer turn took over the player — it settles\n if (this.pausedAt) { this.drainTimer = this.clock.setTimeout(settle, 250); return; } // held by an overlap — not finished audibly\n this.drainTimer = null;\n this.speaking = false;\n this.stopWordReveal(true); // audio finished — reveal any unrevealed tail\n if (this.turnStartAt) log.debug(`turn: ${Math.round(this.clock.now() - this.turnStartAt)}ms (incl. playback)`);\n this.echoUntil = this.clock.now() + 2500; // tail echo (capture+network+finalization) outlives playback\n if (!this.usingAec) this.stt.reset(); // drop echo residue (AEC: keep — it can only be the user)\n this.setState('listening');\n if (this.uttQueue.length) this.pumpQueue(); // next queued worker utterance plays after this one fully ends\n };\n const drainThenSettle = () => {\n if (this.drainTimer) this.clock.clearTimeout(this.drainTimer);\n this.drainTimer = this.clock.setTimeout(settle, this.player.drainMs() + 300);\n };\n if (this.spokeDeltas) {\n // the LLM turn is over but the TTS is still synthesizing — wait for ALL chunks (onDone)\n // before the drain countdown, else drainMs() undercounts and the reply's tail is dropped.\n this.tts.onDone = drainThenSettle;\n this.tts.end();\n // safety net: if 'done' never arrives (ws drop), settle after a generous ceiling\n if (this.drainTimer) this.clock.clearTimeout(this.drainTimer);\n this.drainTimer = this.clock.setTimeout(drainThenSettle, 15_000);\n } else drainThenSettle();\n }\n /** text of the reply cut by the last barge-in — consumed by the host to tell the model what\n * the user did NOT hear. Cleared on read. */\n takeInterruptedReply(): { full: string; heard: string } | null {\n const r = this.lastInterrupted;\n this.lastInterrupted = null;\n return r;\n }\n\n /** Speak a short filler phrase without starting a model turn (stays in listening mode after). */\n speakFiller(text: string): void {\n if (!text || this.speaking) return;\n // A filler is NOT a reply: it must not flip repliedSinceDispatch, or a Hold's \"mhm\" would make\n // the re-finalization guard drop the fuller final the Hold is waiting for (starving the turn).\n const replied = this.repliedSinceDispatch;\n this.beginSpeech();\n this.speakDelta(text);\n this.endSpeech();\n this.repliedSinceDispatch = replied;\n }\n\n /** Enqueue a COMPLETE worker utterance (already-split spoken text) onto the central speech queue.\n * If nothing is currently speaking it plays immediately; otherwise it queues and plays after the\n * current utterance fully ends (settle → pumpQueue) — never spliced into an open reflex utterance. */\n enqueueUtterance(text: string): void {\n // Require speakable content (a letter/digit). A punctuation/quote-only utterance (e.g. a lone \")\n // produces no audio, so its own begin→end turn waits for a 'done' that never arrives and STALLS the\n // queue until the drain safety-net fires (~seconds of dead air). Drop it.\n if (!text || !/[\\p{L}\\p{N}]/u.test(text)) return;\n this.diag('enqueue_utterance', { chars: text.length, queued: this.uttQueue.length, speaking: this.speaking });\n this.uttQueue.push(text);\n if (!this.speaking) this.pumpQueue();\n }\n /** Play the next queued worker utterance as its own one-shot turn (begin → delta → end). Drives the\n * next one from the settle completion (endSpeech), so utterances serialize without overlap. */\n private pumpQueue(): void {\n if (this.speaking) return; // a turn is in flight — settle will re-pump\n const text = this.uttQueue.shift();\n if (text == null) return;\n this.beginSpeech();\n this.speakDelta(text);\n this.endSpeech();\n }\n\n /** Short varied adaptive acks (adaptiveAckMs) — two shape pools picked by the dispatched\n * utterance (question → thinking-ish, otherwise neutral/on-it), with anti-repetition (never one\n * of the last 4 used). A 3-phrase round-robin sounded synthetic live (\"started with 'hmm' too\n * many times\"). All phrases are sub-second and semantically safe for their shape.\n * No 'Okay.': a genuine user \"Okay.\" within the 6s squash window would be swallowed as ack echo. */\n static readonly ACKS_NEUTRAL = ['Mm-hm.', 'One sec.', 'Right.', 'Sec.', 'On it.', 'Sure, moment.', 'Uh, one moment.', 'Let me see.'];\n static readonly ACKS_QUESTION = ['Hmm.', 'Let me think.', 'Hm, let me see.', 'Good question.', 'Mm, one sec.', 'Let\\'s see.'];\n /** A reflex opening sentence that is PURELY an acknowledgement (no content) — dropped when the adaptive\n * micro-ack already spoke one. Anchored end-to-end so only a whole ack-only clause matches. */\n static readonly ACK_LEADING = /^(?:(?:okay|ok|alright|sure|yeah|yep|right|got it|on it|still|still on it|still working on it|working on it|checking|one sec|one moment|mm hm|mmhm|hmm|let me (?:see|check|think))[ ,]*)+$/;\n private recentAcks: string[] = [];\n private pickAck(): string {\n const pool = this.lastDispatchWasQuestion ? VoiceEngine.ACKS_QUESTION : VoiceEngine.ACKS_NEUTRAL;\n const fresh = pool.filter((p) => !this.recentAcks.includes(p));\n const phrase = (fresh.length ? fresh : pool)[Math.floor(Math.random() * (fresh.length ? fresh.length : pool.length))];\n this.recentAcks.push(phrase);\n if (this.recentAcks.length > 4) this.recentAcks.shift();\n return phrase;\n }\n private lastDispatchWasQuestion = false;\n private clearAckTimer(reason?: string): void {\n if (!this.ackTimer) return;\n this.clock.clearTimeout(this.ackTimer);\n this.ackTimer = null;\n if (reason) this.diag('ack_cancelled', { reason });\n }\n /** Cancel a pending adaptive ack without touching the turn — hosts call this when the turn turns out\n * to be a Hold (intentionally silent; an ack would read as the start of an answer). */\n cancelPendingAck(): void { this.clearAckTimer('hold'); }\n\n /** barge-in: stop audio NOW, cancel generation, reset for the user's utterance */\n interrupt(): void {\n this.clearAckTimer('interrupt'); // the turn the ack was masking is dead\n this.adaptiveAckFired = false; this.ackProbe = null; // drop any half-probed leading ack\n if (this.uttQueue.length) log.info(`barge-in dropped ${this.uttQueue.length} queued worker utterance(s)`); // forensics: a \"lost\" task delivery usually died here\n const droppedQueued = this.uttQueue.length;\n this.uttQueue = []; // barge-in drops any queued worker utterances (the user took the floor)\n if (!this.speaking && !this.drainTimer) return;\n this.stopWordReveal(false); // barge-in: freeze reveal at what was actually spoken (no tail flush)\n // Emitted for every EFFECTIVE interrupt — engine cede paths also emit a `barge_in` right after\n // (with the trigger); a lone `interrupt` with no adjacent barge_in = host-initiated (Esc, /voice).\n this.diag('interrupt', { droppedQueued, ctxOpen: this.ctxOpen, playedMs: Math.round(Math.max(0, this.player.playedMs())) });\n if (this.drainTimer) { this.clock.clearTimeout(this.drainTimer); this.drainTimer = null; }\n // estimate how much of the reply was actually heard: played-audio seconds ≈ spoken chars\n // (~15 chars/s of TTS speech) — coarse, but enough for \"the user missed most of it\".\n this.resetOverlap(false); // ceding — the flush below discards the held tape, don't resume it\n this.lastResumeAt = 0; // consume the re-pause signal: the next reply starts fresh\n const heardChars = Math.round((Math.max(0, this.player.playedMs()) / 1000) * 15); // paused time excluded by the sink\n if (this.reply) this.lastInterrupted = { full: this.reply, heard: this.reply.slice(0, heardChars) };\n this.speaking = false;\n this.ctxOpen = false;\n this.interrupted = true; // stragglers from the aborted stream stay silent\n this.suspectUntil = 0;\n // Meet's WebRTC echoes our audio back with ~1-2s network delay. The echo window must cover\n // the full playback duration + round-trip, not just a fixed tail. Without this, long responses\n // (stories, explanations) leak their echo tail past the window → false barge-in → cascade.\n this.echoUntil = this.clock.now() + Math.max(2500, this.player.drainMs() + 3000);\n this.tts.cancel();\n this.player.kill();\n if (!this.usingAec) this.stt.reset(); // heuristic: drop the mixed echo/user buffer\n if (this.reply) this.prevReply = this.reply;\n this.setState('listening');\n }\n stop(): void {\n this.uttQueue = [];\n this.clearAckTimer();\n if (this.resumeTimer) this.clock.clearTimeout(this.resumeTimer);\n if (this.pendingTimer) this.clock.clearTimeout(this.pendingTimer);\n if (this.drainTimer) this.clock.clearTimeout(this.drainTimer);\n if (this.specTimer) this.clock.clearTimeout(this.specTimer);\n this.bcSupersede();\n this.stt.stop();\n this.player.kill();\n this.tts.close();\n this.setState('idle');\n }\n\n // --- listening side (STT-driven) ---\n\n private words(s: string): string[] {\n return s.toLowerCase().replace(/[^a-z0-9\\s]/g, '').split(/\\s+/).filter((w) => w.length >= 2);\n }\n private novelWords(text: string): string[] {\n return this.words(text).filter((w) => !this.echoWords.has(w));\n }\n private echoActive(): boolean {\n return this.speaking || this.clock.now() < this.echoUntil;\n }\n /** Genuine user speech vs our own bleed (AEC tier): novel words must DOMINATE, not merely exist.\n * Degraded AEC + an STT mis-hearing manufactures a single novel word out of pure echo (a name or\n * rare word in our own reply comes back transcribed slightly differently — 1 novel / N words).\n * A real interjection is mostly novel (\"stop\", \"wait what\") — short utterances pass on ratio,\n * longer ones on count. */\n private genuine(text: string): boolean {\n const total = this.words(text).length;\n const novel = this.novelWords(text).length;\n // ratio, not count: a long mis-heard echo sentence yields 2-3 \"novel\" words out of a dozen\n // (live trace: \"…latest email from you\" from our \"…latest news for you\") — an absolute >=2\n // pass let those through. Real user speech is MOSTLY novel.\n return novel > 0 && novel / Math.max(1, total) > 0.5;\n }\n\n private handlePartial(text: string): void {\n if (this.speaking) {\n // Half-duplex (no AEC, no headphones): deaf while we speak — echo can't become a barge or partial.\n if (!this.options.bargeIn) return;\n // Barge grace: right after an utterance dispatched this turn, the user's OWN trailing audio is\n // still finalizing — it must not barge the reply they just requested (B3 over-interruption / B4\n // double-abort). Drop the barge/pause decision during the grace; still render the partial below.\n if (this.clock.now() < this.bargeGraceUntil) {\n if (this.lastGraceDiag !== this.bargeGraceUntil) { this.lastGraceDiag = this.bargeGraceUntil; this.diag('grace_suppress', { text: text.slice(0, 60) }); }\n if (!this.echoActive() || (this.usingAec ? this.genuine(text) : this.novelWords(text).length >= 1)) this.options.onPartial(text);\n return;\n }\n if (this.overlapCapable) {\n // STT-driven overlap: Soniox saying \"this is speech\" is the discriminator (energy could not\n // separate residue from speech across rooms). New partial text → pause (trail-off); growing\n // into dominant-novel ≥2 words → cede; stalling → the resume timer releases the hold.\n const txt = text.trim();\n if (!txt || txt === this.lastOverlapPartial) return; // no NEW speech activity\n this.lastOverlapPartial = txt;\n // Echo gate on the PAUSE, not just the cede: our own audio bleeds back through imperfect AEC and\n // Soniox transcribes it as evolving partials. Pausing on each one (the old behavior) was an\n // audible hiccup mid-reply for every echo fragment — the \"TTS interrupting itself\" bug. genuine()\n // (novel words must DOMINATE) is the SAME speech/echo discriminator already used to cede; apply it\n // to the pause so pure echo is inert. A real barge is novel by definition → still pauses instantly,\n // even on one word (\"stop\" → 1 novel / 1 total → genuine).\n if (!this.genuine(txt)) { if (this.pausedAt) this.armResume(); return; } // echo: inert (keep a live hold ticking)\n if (!this.pausedAt) {\n this.pausedAt = this.clock.now();\n const sinceResumeMs = this.lastResumeAt ? Math.round(this.clock.now() - this.lastResumeAt) : undefined;\n this.diag('overlap_pause', { text: txt.slice(0, 60), sinceResumeMs });\n this.player.pause!();\n // Re-pause right after a false-alarm resume → persistent human, not an echo blip. Cede now,\n // before the resume replays old audio again, and without waiting for the dominant-novel gate.\n if (this.lastResumeAt && this.clock.now() - this.lastResumeAt < this.options.overlapRepauseCedeMs) {\n const phase = this.ctxOpen ? 'speaking' as const : 'drain' as const;\n this.diag('barge_in', { phase, trigger: 'overlap_repause', sinceResumeMs });\n this.interrupt();\n this.options.onBargeIn(phase);\n return;\n }\n }\n if (this.words(txt).length >= 2) { // genuine already true → dominant-novel ≥2 words → cede\n const phase = this.ctxOpen ? 'speaking' as const : 'drain' as const;\n this.diag('barge_in', { phase, trigger: 'overlap_cede', novel: this.novelWords(txt).length, total: this.words(txt).length });\n this.interrupt();\n this.options.onBargeIn(phase);\n return;\n }\n this.armResume(); // genuine single word: hold; quiet releases\n return;\n }\n // Barge-in = NOVEL words (not in our own recent reply) — even with AEC. Cancellation quality\n // is a spectrum (VPIO convergence varies run to run); when it degrades, the assistant's own\n // bleed must not self-interrupt. User speech is novel by definition → still triggers fast.\n const barge = this.usingAec ? this.genuine(text) : this.novelWords(text).length >= (this.suspectUntil ? 1 : 2);\n if (barge) {\n const phase = this.ctxOpen ? 'speaking' as const : 'drain' as const;\n this.diag('barge_in', { phase, trigger: this.usingAec ? 'genuine' : 'heuristic_novel', novel: this.novelWords(text).length, total: this.words(text).length });\n this.interrupt();\n this.options.onBargeIn(phase);\n }\n return;\n }\n if (this.pendingUtt && text.trim()) { // user kept talking during the merge window — wait for the next endpoint\n // RE-ARM (long fallback), never just clear: Soniox emits trailing partial frames after <end> —\n // clearing left the pending utterance parked forever (the user's barge words were LOST).\n if (this.pendingTimer) this.clock.clearTimeout(this.pendingTimer);\n this.pendingTimer = this.clock.setTimeout(() => this.flushUtterance(), Math.max(800, this.options.utteranceMergeMs));\n }\n this.trackSpeculation(text);\n this.trackBackchannel(text);\n // display partials unless they're echo-shaped during/after our own speech (degraded-AEC bleed)\n if (!this.echoActive() || (this.usingAec ? this.genuine(text) : this.novelWords(text).length >= 1)) this.options.onPartial(text);\n }\n\n /** Speculative-reflex trigger (listening side only — the speaking branch returns before this): a\n * partial that hasn't CHANGED for speculativeMs and has ≥ speculativeMinWords is stable → fire\n * onSpeculate once. If the user then keeps talking well past the speculated text, onSpeculateAbort\n * tells the host to kill the held call early. The confirm/abort DECISION belongs to the host at\n * dispatch time (speculationConfirms against the real final) — flushUtterance only resets the\n * trigger for the next turn. Merge windows are untouched: no speculation while an endpointed\n * utterance is pending (the final would be the MERGED text, which the partial alone never matches). */\n private trackSpeculation(text: string): void {\n if (!this.options.speculativeMs) return;\n const t = text.trim();\n if (this.specText) {\n // in flight: partial grew ≥3 words past the speculated text → the final can no longer confirm\n if (this.words(t).length > this.words(this.specText).length + 2) {\n this.specText = '';\n this.diag('speculate_abort', { reason: 'partial_grew', partial: t.slice(0, 60) });\n this.options.onSpeculateAbort();\n }\n return;\n }\n if (this.specSpent || this.pendingUtt || !t || t === this.specPartial) return;\n this.specPartial = t;\n if (this.specTimer) this.clock.clearTimeout(this.specTimer);\n this.specTimer = this.clock.setTimeout(() => {\n this.specTimer = null;\n if (this.speaking || this.specSpent || this.pendingUtt) return;\n if (this.words(this.specPartial).length < this.options.speculativeMinWords) return;\n // Soniox emits trailing partial frames after <end> — a partial that just echoes the utterance we\n // JUST dispatched must not spawn a phantom speculation (its \"final\" already came and went).\n const flat = this.specPartial.toLowerCase().replace(/[^a-z0-9]/g, '');\n if (flat && this.lastDispatchFlat && this.clock.now() - this.lastDispatchAt < VoiceEngine.DUP_FINAL_MS &&\n (this.lastDispatchFlat.startsWith(flat) || flat.startsWith(this.lastDispatchFlat))) return;\n this.specSpent = true;\n this.specText = this.specPartial;\n log.debug(`speculate: \"${this.specText.slice(0, 60)}\"`);\n this.diag('speculate', { text: this.specText });\n this.options.onSpeculate(this.specText);\n }, this.options.speculativeMs);\n }\n\n /** Backchannel blip pool — short, quiet, semantically inert. Chosen to be transcript-safe: if\n * imperfect AEC lets a blip reach Soniox MID-user-speech it lands inside their partial stream, so\n * every phrase is a word whose accidental presence barely hurts a transcript, and flushUtterance\n * strips an isolated echo of the exact phrase at a clause edge within 2s (stripBackchannelEcho).\n * 'Okay.'/'Right.' are fine here (unlike ACKS_NEUTRAL's no-Okay rule): a standalone user \"Okay.\"\n * right after OUR blip is overwhelmingly the blip's echo — the squash guard eating it is the point. */\n static readonly BACKCHANNELS = ['Mm-hm.', 'Uh-huh.', 'Right.', 'Okay.'];\n\n /** Backchannel trigger (listening side only — the speaking branch returns before this): a partial\n * that reached a clause boundary and then stayed UNCHANGED for backchannelMs (a micro-pause, still\n * BEFORE the silence endpoint) fires a blip — if long enough (≥ backchannelMinWords), predominantly\n * Latin, rate-limited (backchannelMinGapMs + max 2/turn), and no endpointed text is pending.\n * Touches nothing else: merge/endpoint/speculation timers and turn state are never affected. */\n private trackBackchannel(text: string): void {\n if (!this.options.backchannelMs) return;\n const t = text.trim();\n if (!t || t === this.bcPartial) return; // no NEW speech — the armed stability timer keeps ticking\n this.bcPartial = t;\n if (this.bcTimer) this.clock.clearTimeout(this.bcTimer);\n this.bcTimer = this.clock.setTimeout(() => {\n this.bcTimer = null;\n const p = this.bcPartial;\n const veto = (reason: string) => this.diag('backchannel_suppress', { reason });\n if (this.speaking || this.pendingUtt || this.bcActive) return veto('busy'); // never while audible or endpointed\n // Full-duplex (AEC) only: the blip extends echoUntil, and the half-duplex/heuristic echo gate\n // drops utterances wholesale while echo-active — a blip there would deafen the engine to the\n // user's own final for ~2.5s. Under AEC, genuine() keeps real speech flowing.\n if (!this.usingAec || !this.options.bargeIn) return veto('half_duplex');\n if (this.bcCount >= 2 || (this.lastBcAt && this.clock.now() - this.lastBcAt < this.options.backchannelMinGapMs)) return veto('rate_limited');\n if (this.words(p).length < this.options.backchannelMinWords) return veto('short');\n // clause boundary: trailing punctuation, or a mid-thought conjunction/filler pause\n if (!/[,.;:!?…]$/.test(p) && !this.looksIncomplete(p)) return veto('no_boundary');\n // Latin-predominant only (v1): the boundary/conjunction rules are English-tuned — Hebrew/mixed\n // partials get NO blips rather than mistimed ones (documented safe default).\n const letters = p.replace(/[^\\p{L}]/gu, '');\n const latin = p.replace(/[^A-Za-z]/g, '');\n if (!letters || latin.length / letters.length < 0.7) return veto('non_latin');\n // trailing partial frames of the utterance we JUST dispatched must not blip at its ghost\n const flat = p.toLowerCase().replace(/[^a-z0-9]/g, '');\n if (flat && this.lastDispatchFlat && this.clock.now() - this.lastDispatchAt < VoiceEngine.DUP_FINAL_MS &&\n (this.lastDispatchFlat.startsWith(flat) || flat.startsWith(this.lastDispatchFlat))) return;\n this.fireBackchannel();\n }, this.options.backchannelMs);\n }\n\n /** Speak one blip on a THROWAWAY TTS context. Zero floor-claim: no `speaking`, no state change, no\n * markTurn, no merge/endpoint/barge timers, no repliedSinceDispatch, no utterance queue. Echo\n * pre-seeding happens BEFORE any audio exists: the blip's words join echoWords (its mic echo is\n * never \"novel\"), the ack-squash guard is armed with the exact phrase (a standalone echo final is\n * swallowed), and the echo window extends so echo-shaped finals stay gated. */\n private fireBackchannel(): void {\n const fresh = VoiceEngine.BACKCHANNELS.filter((x) => !this.recentBc.includes(x));\n const pool = fresh.length ? fresh : VoiceEngine.BACKCHANNELS;\n const phrase = pool[Math.floor(Math.random() * pool.length)];\n this.recentBc.push(phrase);\n if (this.recentBc.length > 2) this.recentBc.shift();\n const now = this.clock.now();\n for (const w of this.words(phrase)) this.echoWords.add(w);\n this.ackAt = now; this.lastAck = phrase; // squash guard: a standalone echo of the blip is dropped\n this.lastBcAt = now; this.lastBcPhrase = phrase;\n this.echoUntil = Math.max(this.echoUntil, now + 2500);\n this.bcCount++;\n this.bcActive = true; // open the narrow audio-gate bypass for THIS blip only\n if (this.bcActiveTimer) this.clock.clearTimeout(this.bcActiveTimer);\n this.bcActiveTimer = this.clock.setTimeout(() => { this.bcActive = false; }, 3000);\n this.tts.onDone = () => { this.bcActive = false; }; // safe: reassigned by the next endSpeech\n this.tts.newContext(); // throwaway context — a real turn's newContext() supersedes it (stale filter)\n this.tts.speak(phrase, false);\n log.debug(`backchannel: \"${phrase}\"`);\n this.diag('backchannel', { phrase });\n this.options.onBackchannel(phrase);\n }\n\n /** A real turn (or shutdown) takes over mid-blip: close the audio bypass + stability timer. */\n private bcSupersede(): void {\n this.bcActive = false;\n if (this.bcActiveTimer) { this.clock.clearTimeout(this.bcActiveTimer); this.bcActiveTimer = null; }\n if (this.bcTimer) { this.clock.clearTimeout(this.bcTimer); this.bcTimer = null; }\n }\n\n /** Strip the mic echo of the LAST blip from a dispatching final, conservatively: only the exact\n * phrase, as an isolated token at a clause edge (start/end of utterance or beside punctuation),\n * within 2s of the blip. \"Right\"/\"okay\" as genuine mid-sentence content words are never touched. */\n private stripBackchannelEcho(text: string): string {\n if (!this.lastBcPhrase || this.clock.now() - this.lastBcAt > 2000) return text;\n const target = normWord(this.lastBcPhrase);\n if (!target) return text;\n const toks = text.split(/\\s+/);\n const idx = toks.findIndex((tok, i) => {\n if (normWord(tok) !== target) return false;\n if (/\\?/.test(tok)) return false; // a tag question (\"…tomorrow, right?\") is user MEANING, not echo — a blip's echo never gains a '?'\n const edgeBefore = i === 0 || /[,.;:!?…]$/.test(toks[i - 1]);\n const edgeAfter = i === toks.length - 1 || /[,.;:!?…]$/.test(tok);\n return edgeBefore && edgeAfter;\n });\n if (idx < 0) return text;\n toks.splice(idx, 1);\n log.verbose(`stripped backchannel echo \"${this.lastBcPhrase}\" from dispatching final`);\n return toks.join(' ');\n }\n\n /** Merge a resumed utterance into the pending one, deduping any word-overlap. Soniox re-finalizes\n * overlapping audio when the silence-timer and the semantic `<end>` both endpoint a growing\n * utterance (or after a reconnect): the next \"utterance\" repeats the tail of the previous one, and\n * a naive `${prev} ${next}` produced the live duplication (\"Um, I want to check if Um, I want to\n * check if…\"). Find the longest suffix of `prev`'s words that prefixes `next` and drop it. */\n private mergeUtterance(prev: string, next: string): string {\n if (!prev) return next;\n if (!next) return prev;\n const pw = prev.split(/\\s+/), nw = next.split(/\\s+/);\n const norm = VoiceEngine.normWord;\n // Truncation repair: the previous final is a strict PREFIX of this one (Soniox re-finalized the\n // same audio with a longer tail — live: \"Hey ther\" then \"Hey there, how are you?\"). Keep the\n // longer final instead of concatenating a truncated ghost in front of it. Conservative: prev must\n // have ≥2 words (a genuine one-word utterance followed by more speech is normal continuation),\n // every earlier word must match, and prev's LAST word may be a char-prefix of next's (\"ther\"→\"there\").\n if (pw.length >= 2 && pw.length <= nw.length) {\n let pfx = true;\n for (let i = 0; i < pw.length - 1; i++) if (norm(pw[i]) !== norm(nw[i])) { pfx = false; break; }\n if (pfx && norm(nw[pw.length - 1]).startsWith(norm(pw[pw.length - 1]))) return next;\n }\n const max = Math.min(pw.length, nw.length);\n for (let k = max; k > 0; k--) {\n let match = true;\n for (let i = 0; i < k; i++) if (norm(pw[pw.length - k + i]) !== norm(nw[i])) { match = false; break; }\n if (match) return [...pw, ...nw.slice(k)].join(' ');\n }\n return `${prev} ${next}`;\n }\n\n private static normWord(w: string): string { return normWord(w); }\n\n /** Soniox re-finalization of an ALREADY-DISPATCHED utterance, arriving PAST the merge window:\n * the new final is a strict word-prefix superset of the last dispatch (the last dispatched word\n * may be a char-prefix of the corresponding new word — a mid-word endpoint), and it lands within\n * DUP_FINAL_MS of the dispatch. Live: \"Hi, please tell me a very short\" dispatched, then the full\n * \"…very short joke.\" re-finalized ~900ms later → dispatched TWICE (two replies, the second to a\n * question already being answered).\n * DESIGN — HYBRID at the caller (flushUtterance): this shape check identifies a re-finalization\n * (a human physically cannot re-speak a ≥3-word sentence plus extra words within 3s of the\n * previous dispatch; a genuine continuation arrives as NEW words, never as a superset), and\n * repliedSinceDispatch then picks the action:\n * • reply already streaming (the live trace: TTFT ~500ms < the ~900ms re-final) → DROP. True\n * \"supersede\" would mean aborting audible speech mid-word to re-answer nearly the same text —\n * worse UX — and needs turn-abort plumbing in every host (the lab bridge has none;\n * DuplexAgent.send is a non-cancelable queue, so a second send just stacks a SECOND full reply).\n * Soniox's premature endpoint fires at a prosodic boundary, so the loss is trailing word(s).\n * • NO reply yet → DISPATCH the fuller text. Live-verified necessity: the reflex Holds on the\n * truncated fragment (\"Hi, please tell me a very short\" → Hold), and dropping the re-final then\n * starves the conversation entirely — the fuller final IS the completion the Hold is waiting\n * for. A slow-but-answering reflex in this window degrades to today's two-reply behavior (rare\n * race), never worse. Fillers (\"mhm\") deliberately don't count as replies — see speakFiller. */\n private refinalizes(next: string): boolean {\n const pw = this.lastDispatchWords, nw = next.trim().split(/\\s+/);\n const norm = VoiceEngine.normWord;\n if (pw.length < 3 || nw.length < pw.length) return false;\n if (this.clock.now() - this.lastDispatchAt >= VoiceEngine.DUP_FINAL_MS) return false;\n for (let i = 0; i < pw.length - 1; i++) if (norm(pw[i]) !== norm(nw[i])) return false;\n const pLast = norm(pw[pw.length - 1]), nSame = norm(nw[pw.length - 1]);\n if (!nSame.startsWith(pLast)) return false;\n return nw.length > pw.length || nSame.length > pLast.length; // STRICT superset (identical → dup guard, which allows post-reply repeats)\n }\n\n private static readonly TRAIL_RE = /(?:^|\\s)(?:and|but|or|so|to|the|a|an|of|in|for|with|that|if|uh|um|like|about|from|into|on|is|are|was|were|,)$/i;\n /** The utterance sounds like the user paused mid-thought (trailing conjunction/filler/comma). */\n private looksIncomplete(text: string): boolean {\n return VoiceEngine.TRAIL_RE.test(text.trim());\n }\n\n private handleUtterance(text: string): void {\n // Overlap that never grabbed the turn: duration said backchannel/noise → drop it. Real grabs\n // interrupted already (speaking=false). Applies while content flows (ctxOpen) AND while we are\n // holding a pause for THIS overlap (a drain-tail \"yeah\" leaked as a real turn otherwise). A\n // clean early answer during the drain — no hold in progress — still falls through (turn-taking).\n if (this.speaking && (this.ctxOpen || this.pausedAt) && this.overlapCapable) { this.diag('utterance_drop', { reason: 'overlap_noise', text: text.slice(0, 60) }); this.stt.reset(); return; }\n // Echo-shaped utterances (no/few novel words while we are or just were audible) are dropped in\n // BOTH tiers — degraded AEC bleed otherwise becomes fake user turns (\"🎤 › Friday.\").\n // Half-duplex: drop EVERY utterance while audible (speaking + drain tail) — pure echo suppression.\n if (this.echoActive() && (!this.options.bargeIn || (this.usingAec ? !this.genuine(text) : this.novelWords(text).length < 2))) { this.diag('echo_swallow', { guard: 'echo_gate', text: text.slice(0, 60) }); this.stt.reset(); return; }\n // AEC converges over ~100ms at audio onset — the ack (first audio after silence) can leak back\n // as a transcript. Drop backchannel-shaped utterances shortly after we spoke it.\n const squash = (t: string) => t.toLowerCase().replace(/[^a-z]/g, '').replace(/(.)\\1+/g, '$1');\n if (this.ackAt && this.lastAck && this.clock.now() - this.ackAt < 6000 && squash(text) === squash(this.lastAck)) { this.diag('echo_swallow', { guard: 'ack_squash', text: text.slice(0, 60) }); this.ackAt = 0; return; }\n // Merge window: semantic endpointing fires mid-spelling (\"E-L-Y.\" … \"A.\") and mid-thought.\n // Hold briefly; speech resuming in the window appends to the SAME utterance. Substantial\n // utterances (≥4 words) skip the hold — they are never spelled fragments, and the saved 350ms\n // is the difference between ping-pong and lag in quick exchanges.\n if (this.pendingUtt) this.mergePath = 'merged'; // this final joined a held one (see dispatch diag)\n this.pendingUtt = this.mergeUtterance(this.pendingUtt, text);\n if (this.pendingTimer) this.clock.clearTimeout(this.pendingTimer);\n // Incomplete utterance hold: trailing conjunctions/fillers get an extended merge window + optional\n // filler phrase, letting the user finish their thought without triggering a model call.\n if (this.options.incompleteMergeMs && this.looksIncomplete(this.pendingUtt)) {\n log.verbose(`hold: incomplete utterance \"${this.pendingUtt.slice(-40)}\"`);\n this.diag('hold', { reason: 'incomplete', tail: this.pendingUtt.slice(-40) });\n this.options.onHold();\n if (this.options.holdFiller && !this.speaking) this.speakFiller(this.options.holdFiller); // filler ≠ reply (see speakFiller)\n this.pendingTimer = this.clock.setTimeout(() => this.flushUtterance(), this.options.incompleteMergeMs);\n return;\n }\n if (!this.options.utteranceMergeMs || this.words(this.pendingUtt).length >= 4) return this.flushUtterance();\n this.pendingTimer = this.clock.setTimeout(() => this.flushUtterance(), this.options.utteranceMergeMs);\n }\n private flushUtterance(): void {\n if (this.pendingTimer) { this.clock.clearTimeout(this.pendingTimer); this.pendingTimer = null; }\n // The turn-in-progress is dispatching (or dropping) — reset the speculation trigger for the next\n // one. The host decides confirm/abort of any in-flight speculative call against the final itself.\n if (this.specTimer) { this.clock.clearTimeout(this.specTimer); this.specTimer = null; }\n this.specSpent = false; this.specPartial = ''; this.specText = '';\n // Backchannel per-turn reset: the turn-in-progress ends here. A pending stability timer must not\n // fire a blip over the dispatch, and the next user turn gets a fresh 2-blip budget.\n if (this.bcTimer) { this.clock.clearTimeout(this.bcTimer); this.bcTimer = null; }\n this.bcCount = 0; this.bcPartial = '';\n const text = this.stripBackchannelEcho(this.pendingUtt); // drop the blip's mic echo (isolated, clause-edge, <2s)\n this.pendingUtt = '';\n const path = this.mergePath; this.mergePath = 'direct';\n if (text) {\n const flat = text.toLowerCase().replace(/[^a-z0-9]/g, '');\n if (flat && flat === this.lastDispatchFlat && !this.repliedSinceDispatch &&\n this.clock.now() - this.lastDispatchAt < VoiceEngine.DUP_FINAL_MS) {\n log.verbose(`dropped duplicate final \"${text.slice(0, 40)}\" (identical to the just-dispatched utterance, no reply between)`);\n this.diag('utterance_drop', { reason: 'dup_final', text: text.slice(0, 60) });\n return;\n }\n const refinal = this.refinalizes(text);\n if (refinal && this.repliedSinceDispatch) {\n // Track the FULLEST text so a third, even-fuller re-final still matches; lastDispatchAt stays\n // anchored at the real dispatch (re-finals must not extend their own window).\n log.verbose(`dropped re-finalization \"${text.slice(0, 60)}\" (superset of the just-dispatched utterance, reply already flowing)`);\n this.diag('utterance_drop', { reason: 'refinalized', text: text.slice(0, 60) });\n this.lastDispatchFlat = flat;\n this.lastDispatchWords = text.trim().split(/\\s+/);\n return;\n }\n this.lastDispatchFlat = flat;\n this.lastDispatchWords = text.trim().split(/\\s+/);\n this.lastDispatchAt = this.clock.now();\n this.repliedSinceDispatch = false;\n this.lastDispatchWasQuestion = /\\?\\s*$/.test(text); // shapes the adaptive-ack pool (question → thinking-ish)\n this.turnStartAt = this.clock.now();\n // Trailing audio of the utterance we just dispatched keeps finalizing for a beat (Soniox emits\n // partials after <end>). Once the host opens a reply context (speaking=true), those self-tail\n // partials would read as a barge and abort the very reply the user asked for (the live \"interrupts\n // mid-sentence\" + double-abort steps=1→steps=0). Grace the barge path briefly after dispatch.\n this.bargeGraceUntil = this.clock.now() + this.options.bargeGraceMs;\n this.diag('dispatch', { text, path: refinal ? 'refinalized' : path, question: this.lastDispatchWasQuestion });\n this.options.onUtterance(text); // stamp the real turn start for TTFT\n }\n }\n\n private get overlapCapable(): boolean {\n return this.usingAec && this.options.overlapPause && !!this.player.pause && !!this.player.resume;\n }\n private armResume(): void {\n if (this.resumeTimer) this.clock.clearTimeout(this.resumeTimer);\n this.resumeTimer = this.clock.setTimeout(() => {\n this.resumeTimer = null;\n if (!this.pausedAt) return; // (no speaking guard: a held pause must ALWAYS release, else the tape wedges)\n this.diag('overlap_resume', { heldMs: Math.round(this.clock.now() - this.pausedAt) });\n this.stt.reset(); // drop the stalled residue/backchannel buffer — it is not the next utterance\n this.resetOverlap(true); // the overlap died out (backchannel/noise) — pick up exactly where she left off\n }, this.options.overlapResumeMs);\n }\n private resetOverlap(resume: boolean): void {\n if (this.resumeTimer) { this.clock.clearTimeout(this.resumeTimer); this.resumeTimer = null; }\n if (this.pausedAt && resume) { this.player.resume?.(); this.lastResumeAt = this.clock.now(); }\n this.pausedAt = 0;\n this.lastOverlapPartial = '';\n this.gatePassTimes = [];\n }\n\n /** energy two-stage barge-in (heuristic tier only): spike over echo baseline → pause + confirm via STT */\n private gatePassTimes: number[] = []; // recent gate-PASSING chunks (helper zeroes residue — nonzero = vetted)\n private handleLevel(rms: number): void {\n if (this.usingAec) {\n // Fast hold trigger: a nonzero level while we are audible means the helper's gate PASSED it\n // (≥2× expected residue). Two passes within 350ms = speech onset → pause NOW (~300ms), without\n // waiting for STT tokens (which lag whenever the onset straddles the gate). The STT still owns\n // the DECISION: cede on genuine ≥2 words, or the resume timer releases the hold.\n if (!this.options.overlapEnergyHold || !this.speaking || !this.overlapCapable || this.pausedAt || rms < 50) return;\n const t = this.clock.now();\n this.gatePassTimes = this.gatePassTimes.filter((x) => t - x < 350);\n this.gatePassTimes.push(t);\n if (this.gatePassTimes.length < 2) return;\n this.gatePassTimes = [];\n this.pausedAt = t;\n this.player.pause!();\n this.armResume();\n return;\n }\n if (!this.speaking) { this.baseline = 0; this.hot = 0; return; }\n // warm-up: let the EMA learn the echo level before triggers (else her own onset reads as a spike)\n if (!this.baseline) { this.baseline = rms; return; }\n this.baseline = this.baseline * 0.9 + rms * 0.1;\n if (rms > Math.max(this.baseline * this.options.bargeRmsMult, this.options.bargeRmsFloor)) this.hot++;\n else this.hot = 0;\n if (this.hot >= 2 && !this.suspectUntil) {\n this.suspectUntil = this.clock.now() + 1300;\n this.clock.setTimeout(() => { this.suspectUntil = 0; }, 1350);\n }\n }\n}\n","/**\n * Portable voice I/O contracts — zero platform imports. The engine, STT and TTS clients in this\n * directory run anywhere with a `WebSocket` global (Bun, Node, browser); platform backends\n * (mic capture, audio playback) plug in through these seams.\n */\n\nexport type VoiceState = 'idle' | 'listening' | 'thinking' | 'speaking';\n\n/** STT input sample format — sources MUST deliver this (downsample/convert in the adapter). */\nexport const STT_SAMPLE_RATE = 16000; // Hz, mono, s16le\n/** Playback format the TTS requests and sinks must play. */\nexport const TTS_SAMPLE_RATE = 44100; // Hz, mono, s16le\n\n/** A microphone (or any PCM) source. Emits s16le mono 16kHz chunks.\n * Node: mic-aec/ffmpeg child process. Web: getUserMedia({ echoCancellation: true }) + worklet. */\nexport interface AudioSource {\n /** `aec` = the source is echo-cancelled (assistant's own TTS never reaches the chunks) —\n * selects the engine's trivial barge-in path vs the heuristic echo tier. */\n readonly aec: boolean;\n start(onChunk: (pcm: Uint8Array) => void): void | Promise<void>;\n stop(): void;\n /** Unrecoverable source failure (e.g. mic permission denied → engine produces no audio AND, in the\n * duplex AEC engine, no playback). The host should tear voice down rather than spin reconnects. */\n onFatal?: (message: string) => void;\n}\n\n/** An audio playback sink for s16le mono 44.1kHz PCM.\n * Node: per-turn ffplay. Web: AudioContext/worklet ring buffer. */\nexport interface AudioSink {\n /** start a new spoken turn (may recycle or recreate the underlying player) */\n markTurn(): void;\n write(pcm: Uint8Array): void;\n /** estimated ms until queued audio finishes playing */\n drainMs(): number;\n /** ms of audio actually played this turn */\n playedMs(): number;\n /** stop playback NOW (barge-in primitive) */\n kill(): void;\n /** optional exact-sample pause/resume — enables the overlap trail-off tier (web: AudioContext\n * suspend/resume; CLI AEC helper: control frames). Sinks without it degrade to interrupt-only\n * turn-taking. Nothing is lost across a pause; playedMs/drainMs must exclude paused time. */\n pause?(): void;\n resume?(): void;\n}\n\n/** Static key (server/CLI) or an async getter (browser: fetch a short-lived token from YOUR\n * backend). Getters are invoked on EVERY (re)connect — temp tokens expire, so a reconnect\n * must re-mint, never reuse the boot-time token. */\nexport type AuthProvider = string | (() => string | Promise<string>);\n\nexport async function resolveAuth(auth: AuthProvider): Promise<string> {\n return typeof auth === 'function' ? await auth() : auth;\n}\n","/**\n * SpokenSplitter — a stateful streaming parser that splits a token stream into SPOKEN text (inside\n * `<spoken>…</spoken>`) and DETAIL text (everything outside). Used by the worker delivery path: the\n * capable worker wraps what the user should HEAR in `<spoken>` tags; detail prose is the work record.\n *\n * Buffers partial tags split across chunk boundaries (\"<spo\" + \"ken>\") so a tag is never mis-emitted\n * as detail. Pure class — no IoC ceremony.\n */\nconst OPEN = '<spoken>';\nconst CLOSE = '</spoken>';\n\n/**\n * SentenceCoalescer — buffers streamed spoken fragments and emits COMPLETE sentences. A worker on a\n * fragmenting model (cursor streams word-by-word deltas) would otherwise yield one utterance per word —\n * choppy TTS (a begin→end turn each) and one screen-echo line per word. feed() returns the sentence(s)\n * completed by this chunk (or ''); flush() returns the trailing partial when the stream ends.\n */\nconst CLOSERS = `\"')]}»”’`; // closing quotes/brackets that hug a sentence-ender (\"…sponge?\")\n\n/** A speakable chunk must contain at least one letter or digit — a punctuation/quote-only chunk (e.g. a\n * lone \") produces no audio and STALLS the TTS (endSpeech waits for a 'done' that never arrives). */\nconst hasSpeech = (s: string): boolean => /[\\p{L}\\p{N}]/u.test(s);\n\nexport class SentenceCoalescer {\n private buf = '';\n private static isEnd(c: string): boolean { return c === '\\n' || c === '.' || c === '!' || c === '?' || c === '…'; }\n\n feed(delta: string): string {\n if (delta) this.buf += delta;\n let cut = -1;\n for (let i = 0; i < this.buf.length; i++) if (SentenceCoalescer.isEnd(this.buf[i])) cut = i;\n if (cut < 0) return ''; // no sentence boundary yet — hold for more deltas\n // Absorb a closing quote/bracket sitting right after sentence-ending PUNCTUATION (\"…sponge?\") into the\n // same chunk — otherwise the closer is orphaned onto the next utterance as a lone, unspeakable \" that\n // stalls TTS. Skip for a newline cut (a quote after \\n is an OPENING quote for the next line).\n if (this.buf[cut] !== '\\n') while (cut + 1 < this.buf.length && CLOSERS.includes(this.buf[cut + 1])) cut++;\n const ready = this.buf.slice(0, cut + 1).trim();\n this.buf = this.buf.slice(cut + 1);\n return hasSpeech(ready) ? ready : ''; // drop a word-less (punctuation/quote-only) chunk — never speak it\n }\n\n flush(): string { const s = this.buf.trim(); this.buf = ''; return hasSpeech(s) ? s : ''; }\n}\n\n\nexport class SpokenSplitter {\n private buf = '';\n private inSpoken = false;\n /** True once any spoken char has ever been emitted (drives the no-spoken fallback). */\n public spokeAny = false;\n\n /** Feed a delta; returns the spoken/detail spans completed by this chunk (either may be ''). */\n feed(delta: string): { spoken: string; detail: string } {\n this.buf += delta;\n return this.drain(false);\n }\n\n /** Drain any buffered partial. A trailing `<…` that never completed a tag is emitted as detail. */\n flush(): { spoken: string; detail: string } {\n return this.drain(true);\n }\n\n private drain(final: boolean): { spoken: string; detail: string } {\n let spoken = '';\n let detail = '';\n while (this.buf.length) {\n const tag = this.inSpoken ? CLOSE : OPEN;\n const idx = this.buf.indexOf(tag);\n if (idx >= 0) {\n // Emit text up to the tag, then consume the tag and flip mode.\n const text = this.buf.slice(0, idx);\n if (this.inSpoken) spoken += text; else detail += text;\n this.buf = this.buf.slice(idx + tag.length);\n this.inSpoken = !this.inSpoken;\n continue;\n }\n // No complete tag in the buffer. Hold back a trailing `<…` run that is a proper prefix of the\n // tag we're currently seeking (it could complete on the next feed). Only the ACTIVE tag matters.\n const lt = this.buf.lastIndexOf('<');\n const holdStart = lt >= 0 && tag.startsWith(this.buf.slice(lt)) ? lt : this.buf.length;\n const text = this.buf.slice(0, holdStart);\n if (this.inSpoken) spoken += text; else detail += text;\n this.buf = this.buf.slice(holdStart);\n break;\n }\n if (final && this.buf) {\n // A dangling partial tag that never completed — surface it as detail (never lost).\n if (this.inSpoken) spoken += this.buf; else detail += this.buf;\n this.buf = '';\n }\n // Gate on non-BLANK content: `<spoken> </spoken>` would flip spokeAny true, but downstream\n // speak/enqueueUtterance trims it to nothing → silent turn AND a suppressed gist fallback.\n if (spoken.trim()) this.spokeAny = true;\n return { spoken, detail };\n }\n}\n","/**\n * Soniox streaming STT over WebSocket — token partials, semantic `<end>` endpointing,\n * auto-reconnect (re-minting auth — temp tokens expire). Portable: the microphone is an\n * injected AudioSource, not spawned here.\n *\n * Browser auth: NEVER ship the real key — your backend mints a short-lived key via\n * `POST https://api.soniox.com/v1/auth/temporary-api-key` (sent with the real key) and the\n * client passes `auth: () => fetch('/your-be/soniox-token').then(r => r.text())`.\n */\nimport { forComponent } from '../core/logging';\nimport { type AudioSource, type AuthProvider, resolveAuth, STT_SAMPLE_RATE } from '../core/types';\n\nconst log = forComponent('SonioxSTT');\nconst now = () => performance.now();\n\nexport class SonioxSTTOptions {\n auth: AuthProvider = '';\n source!: AudioSource;\n model = 'stt-rt-preview';\n languageHints = ['en'];\n /** Client-side endpoint: finalized text + no new tokens for this long = utterance (don't wait for\n * Soniox's semantic <end>, which adds 0.5-1.5s — the difference between ping-pong and lag). */\n silenceEndpointMs = 500;\n /** No-audio watchdog: if the mic source stops delivering chunks for this long, capture is dead →\n * fire onFatal + stop (else Soniox idle-timeouts and reconnect-loops forever). 0 = disable. */\n noAudioTimeoutMs = 10_000;\n}\n\nexport class SonioxSTT {\n public options: SonioxSTTOptions;\n private ws!: WebSocket;\n private stopped = false;\n private sourceStarted = false;\n public onPartial: (text: string) => void = () => {};\n public onUtterance: (text: string, endpointAt: number) => void = () => {};\n /** mic energy (RMS) per chunk — drives the energy-based heuristic barge-in tier */\n public onLevel: (rms: number) => void = () => {};\n /** Unrecoverable: the mic source stopped delivering audio (Soniox starves → idle-timeout reconnect\n * loop). The host tears voice down instead of spinning forever. */\n public onFatal: (message: string) => void = () => {};\n /** Diagnostic tap (provider errors, ws reconnects, no-audio watchdog). Fire-and-forget: a throwing\n * handler disables itself — never affects transcription. Wired by VoiceIO / the lab bridge. */\n public onDiag: (ev: { t: number; kind: string; [k: string]: unknown }) => void = () => {};\n private diagOn = true;\n private diag(kind: string, fields?: Record<string, unknown>): void {\n if (!this.diagOn) return;\n try { this.onDiag({ t: now(), kind, ...fields }); }\n catch (e) { this.diagOn = false; log.debug(`onDiag threw — STT diagnostics disabled: ${e instanceof Error ? e.message : e}`); }\n }\n private lastChunkAt = 0; // timestamp of the most recent mic chunk (0 = none yet)\n private startedChunksAt = 0; // when capture started (grace before the first chunk)\n private noAudioTimer: ReturnType<typeof setInterval> | null = null;\n private finalText = '';\n private partialText = '';\n private lastChangeAt = 0;\n private lastCombined = '';\n private endpointTimer: ReturnType<typeof setInterval> | null = null;\n private firstTokenAt = 0; // first speech token in current utterance\n\n constructor(options?: Partial<SonioxSTTOptions>) {\n this.options = { ...new SonioxSTTOptions(), ...options };\n }\n\n get usingAec(): boolean {\n return this.options.source?.aec ?? false;\n }\n\n private async connectWs(): Promise<void> {\n const apiKey = await resolveAuth(this.options.auth); // per-connect: temp tokens expire\n this.ws = new WebSocket('wss://stt-rt.soniox.com/transcribe-websocket');\n await new Promise<void>((res, rej) => {\n this.ws.onopen = () => res();\n this.ws.onerror = (e: any) => rej(new Error(`soniox ws: ${e.message || 'connect failed'}`));\n });\n this.ws.send(\n JSON.stringify({\n api_key: apiKey,\n model: this.options.model,\n audio_format: 'pcm_s16le',\n sample_rate: STT_SAMPLE_RATE,\n num_channels: 1,\n language_hints: this.options.languageHints,\n enable_endpoint_detection: true,\n }),\n );\n this.ws.onmessage = (ev) => this.handle(JSON.parse(String(ev.data)));\n this.ws.onclose = (ev: any) => {\n if (this.stopped) return;\n log.warn(`soniox ws closed (${ev.code} ${ev.reason || ''}) — reconnecting`);\n this.diag('stt_ws_closed', { code: ev.code, reason: String(ev.reason || ''), reconnecting: true });\n this.reset();\n this.connectWs().catch((e) => { log.error(`soniox reconnect failed: ${e.message}`); this.diag('stt_reconnect_failed', { message: e.message }); });\n };\n }\n\n async start(): Promise<void> {\n await this.connectWs();\n if (this.sourceStarted) return; // reconnect path — source keeps running\n this.sourceStarted = true;\n // client-side stability endpoint (faster than Soniox's semantic <end> AND its finalization lag:\n // finals trail partials by ~1s — text that has stopped CHANGING is the utterance)\n this.endpointTimer = setInterval(() => {\n const combined = (this.finalText + this.partialText).trim();\n if (!combined || now() - this.lastChangeAt < this.options.silenceEndpointMs) return;\n if (this.firstTokenAt) log.debug(`stt: ${Math.round(now() - this.firstTokenAt)}ms first-token→silence-endpoint, \"${combined.slice(0, 60)}\"`);\n this.reset();\n this.onUtterance(combined, now());\n }, 120);\n (this.endpointTimer as any).unref?.();\n // No-audio watchdog (SLIDING window, not cumulative): healthy capture delivers a chunk ~every 100ms\n // (the AEC helper emits even during silence). If chunks STOP for 10s, capture died — e.g. the\n // CoreAudio input tap stopped firing after a TTS turn — and Soniox would idle-timeout + reconnect\n // forever. A cumulative-from-start check would miss this (the greeting already sent bytes). Tear\n // down with a clear message. The grace (startedChunksAt) covers a slow first chunk.\n this.startedChunksAt = now();\n const noAudioMs = this.options.noAudioTimeoutMs;\n if (noAudioMs > 0) {\n this.noAudioTimer = setInterval(() => {\n if (this.stopped) return;\n const ref = this.lastChunkAt || this.startedChunksAt;\n if (now() - ref > noAudioMs) {\n log.error(`stt: no mic audio for >${Math.round(noAudioMs / 1000)}s — capture device stopped delivering`);\n this.diag('stt_watchdog_fatal', { noAudioMs });\n this.onFatal('microphone stopped delivering audio (try a different input device, e.g. AirPods, or check System Settings → Sound → Input)');\n this.stop();\n }\n }, Math.max(250, Math.min(2000, noAudioMs / 4)));\n (this.noAudioTimer as any).unref?.();\n }\n await this.options.source.start((chunk) => {\n this.lastChunkAt = now();\n let sum = 0;\n const view = new DataView(chunk.buffer, chunk.byteOffset, chunk.byteLength);\n for (let i = 0; i + 1 < chunk.byteLength; i += 2) { const v = view.getInt16(i, true); sum += v * v; }\n this.onLevel(Math.sqrt(sum / (chunk.byteLength / 2)));\n if (this.ws.readyState === WebSocket.OPEN) this.ws.send(chunk);\n });\n }\n private handle(m: any): void {\n if (m.error_message) { this.diag('stt_error', { message: String(m.error_message), code: m.error_code }); return log.error(`soniox: ${m.error_message}`); }\n let endpoint = false;\n for (const t of m.tokens ?? []) {\n if (t.text === '<end>') endpoint = true;\n else if (t.is_final) this.finalText += t.text;\n }\n this.partialText = (m.tokens ?? []).filter((t: any) => !t.is_final && t.text !== '<end>').map((t: any) => t.text).join('');\n const combined = this.finalText + this.partialText;\n if (combined !== this.lastCombined) {\n this.lastCombined = combined; this.lastChangeAt = now();\n if (!this.firstTokenAt && combined.trim()) this.firstTokenAt = now();\n }\n this.onPartial(combined);\n if (endpoint && this.finalText.trim()) {\n const utterance = this.finalText.trim();\n if (this.firstTokenAt) log.debug(`stt: ${Math.round(now() - this.firstTokenAt)}ms first-token→endpoint, \"${utterance.slice(0, 60)}\"`);\n this.reset();\n this.onUtterance(utterance, now());\n }\n }\n reset(): void {\n this.finalText = '';\n this.partialText = '';\n this.lastCombined = '';\n this.firstTokenAt = 0;\n }\n stop(): void {\n this.stopped = true;\n if (this.endpointTimer) clearInterval(this.endpointTimer);\n if (this.noAudioTimer) clearInterval(this.noAudioTimer);\n this.options.source?.stop();\n if (this.ws) this.ws.onclose = null as any;\n this.ws?.close();\n }\n}\n","/**\n * Cartesia streaming TTS over a warm WebSocket — raw-delta continuations (prosody stitched\n * server-side, no sentence chunker), per-context cancel (barge-in), stale-context filtering.\n * Portable: browser/Bun/Node. Auth: static key (server) or BE-minted access token (browser).\n *\n * Browser auth: NEVER ship the real key — your backend mints a short-lived access token\n * (Cartesia `POST /access-tokens`, sent with the real X-API-Key) and the client uses\n * `auth: () => fetch('/your-be/cartesia-token').then(r => r.text())` + `authMode: 'token'`.\n */\nimport { forComponent } from '../core/logging';\nimport { type AuthProvider, resolveAuth, TTS_SAMPLE_RATE } from '../core/types';\n\nconst log = forComponent('CartesiaTTS');\nconst now = () => performance.now();\n\nexport class CartesiaTTSOptions {\n auth: AuthProvider = '';\n voiceId = '';\n model = 'sonic-3.5';\n /** 'apiKey' (server/CLI) → `api_key=` URL param; 'token' (browser, BE-minted) → `access_token=`. */\n authMode: 'apiKey' | 'token' = 'apiKey';\n}\n\nexport class CartesiaTTS {\n public options: CartesiaTTSOptions;\n private ws!: WebSocket;\n private ctxSeq = 0;\n public ctxId = '';\n public onAudio: (chunk: Uint8Array) => void = () => {};\n public onDone: () => void = () => {};\n /** Word-level timestamps for karaoke reveal: `start[i]` = seconds from turn-audio start (absolute\n * across continuation chunks). Fired only when a consumer opts into reveal (see `wantTimestamps`). */\n public onTimestamps: (words: string[], start: number[]) => void = () => {};\n /** Request `add_timestamps` from Cartesia. Off by default (saves bandwidth) — the engine sets it\n * when revealMode==='word'. */\n public wantTimestamps = false;\n /** Diagnostic tap (provider errors, circuit-breaker open/close, ws reconnects). Fire-and-forget:\n * a throwing handler disables itself — never affects synthesis. Wired by VoiceIO / the lab bridge. */\n public onDiag: (ev: { t: number; kind: string; [k: string]: unknown }) => void = () => {};\n private diagOn = true;\n private diag(kind: string, fields?: Record<string, unknown>): void {\n if (!this.diagOn) return;\n try { this.onDiag({ t: now(), kind, ...fields }); }\n catch (e) { this.diagOn = false; log.debug(`onDiag threw — TTS diagnostics disabled: ${e instanceof Error ? e.message : e}`); }\n }\n public firstAudioAt = 0;\n /** Circuit breaker: consecutive error count + down flag. */\n private consecutiveErrors = 0;\n private consecutiveOk = 0;\n private down = false;\n private downAt = 0;\n private probeTimer: ReturnType<typeof setInterval> | null = null;\n private static readonly CB_THRESHOLD = 3; // open after 3 consecutive errors\n private static readonly CB_RECOVER_OK = 2; // close only after 2 consecutive good frames (no single-frame flap)\n private static readonly CB_PROBE_MS = 30_000;\n\n constructor(options?: Partial<CartesiaTTSOptions>) {\n this.options = { ...new CartesiaTTSOptions(), ...options };\n }\n\n private closed = false;\n private connecting: Promise<void> | null = null;\n\n async connect(): Promise<void> {\n this.closed = false;\n this.connecting = this.doConnect();\n await this.connecting;\n this.connecting = null;\n }\n\n private async doConnect(): Promise<void> {\n const key = await resolveAuth(this.options.auth); // per-connect: temp tokens expire\n const param = this.options.authMode === 'token' ? 'access_token' : 'api_key';\n this.ws = new WebSocket(`wss://api.cartesia.ai/tts/websocket?cartesia_version=2026-03-01&${param}=${key}`);\n await new Promise<void>((res, rej) => {\n this.ws.onopen = () => res();\n this.ws.onerror = (e: any) => rej(new Error(`cartesia ws: ${e.message || 'connect failed'}`));\n });\n this.ws.onclose = (ev: any) => {\n log.warn(`cartesia ws closed (${ev.code} ${ev.reason || ''})`);\n this.diag('tts_ws_closed', { code: ev.code, reason: String(ev.reason || ''), reconnecting: !this.closed });\n if (!this.closed) { this.connecting = this.doConnect().catch((e) => { log.error(`cartesia reconnect failed: ${e.message}`); this.diag('tts_reconnect_failed', { message: e.message }); }); }\n };\n this.ws.onmessage = (ev) => {\n const m = JSON.parse(String(ev.data));\n if (m.context_id && m.context_id !== this.ctxId) return; // stale context (post-cancel stragglers)\n if (m.type === 'chunk' && m.data) {\n this.consecutiveErrors = 0;\n this.markRecovered();\n if (!this.firstAudioAt) this.firstAudioAt = now();\n this.onAudio(base64ToBytes(m.data));\n } else if (m.type === 'done') {\n this.consecutiveErrors = 0;\n this.markRecovered();\n this.onDone();\n } else if (m.type === 'timestamps' && m.word_timestamps) {\n const wt = m.word_timestamps as { words?: string[]; start?: number[] };\n if (wt.words?.length && wt.start?.length) this.onTimestamps(wt.words, wt.start);\n }\n else if (m.type === 'error') {\n if (/already been cancelled|does not exist/.test(m.message || '')) return;\n this.consecutiveErrors++;\n this.diag('tts_error', { message: String(m.message || ''), code: m.status_code, contextId: m.context_id, consecutive: this.consecutiveErrors });\n if (!this.down && this.consecutiveErrors >= CartesiaTTS.CB_THRESHOLD) {\n this.down = true;\n this.downAt = now();\n this.consecutiveOk = 0;\n log.warn(`TTS circuit breaker open — ${this.consecutiveErrors} consecutive errors, switching to text-only`);\n this.diag('tts_breaker_open', { errors: this.consecutiveErrors });\n this.onDone(); // release any pending drain\n this.startProbe();\n } else if (!this.down) {\n // \"No valid transcripts passed.\" = a punctuation/whitespace-only transcript — benign (nothing\n // to synthesize), must never splice a raw warn into the live REPL. Everything else stays loud.\n (/No valid transcripts/i.test(m.message || '') ? log.debug : log.warn)(`cartesia: ${JSON.stringify(m)}`);\n }\n }\n };\n }\n\n /** Close the breaker only after CB_RECOVER_OK consecutive good frames, so a single straggler chunk\n * after a 503 burst doesn't flap open→recover in <1s. A sub-2s down-window is a transient blip → debug. */\n private markRecovered(): void {\n if (!this.down) return;\n if (++this.consecutiveOk < CartesiaTTS.CB_RECOVER_OK) return;\n this.down = false;\n this.consecutiveOk = 0;\n this.stopProbe();\n const downMs = this.downAt ? now() - this.downAt : 0;\n this.diag('tts_breaker_close', { downMs: Math.round(downMs) });\n (downMs < 2000 ? log.debug : log.info)(`TTS recovered${downMs ? ` (down ${downMs}ms)` : ''}`);\n }\n\n /** Ensure the WS is open before sending — reconnects if idle-closed. */\n private async ensureConnected(): Promise<void> {\n if (this.connecting) await this.connecting;\n if (this.ws?.readyState !== WebSocket.OPEN) await this.connect();\n }\n /** Prime the synthesis pipeline on a throwaway context right after connect: the FIRST synthesis on\n * a fresh WS pays Cartesia's cold spin-up (~1s+ live) — absorb it at mic-on instead of turn one.\n * The returned audio is discarded (engine drops onAudio while not speaking; once a real turn calls\n * newContext() any stragglers are stale-context-filtered). Respects the circuit breaker. */\n warmup(): void {\n if (this.down) return;\n this.newContext();\n // A real (synthesizable) word, not '.': Cartesia 400s a punctuation-only transcript with\n // \"No valid transcripts passed.\" — the warmup then primed nothing AND spliced a raw warn into\n // the REPL at voice start. The audio is discarded either way (engine gates onAudio on `speaking`).\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(this.frame('Ok.', false));\n }\n newContext(): string {\n this.ctxId = `ctx-${++this.ctxSeq}`;\n this.firstAudioAt = 0;\n return this.ctxId;\n }\n private frame(transcript: string, cont: boolean): string {\n return JSON.stringify({\n model_id: this.options.model,\n transcript,\n voice: { mode: 'id', id: this.options.voiceId },\n output_format: { container: 'raw', encoding: 'pcm_s16le', sample_rate: TTS_SAMPLE_RATE },\n context_id: this.ctxId,\n continue: cont,\n ...(this.wantTimestamps ? { add_timestamps: true } : {}),\n });\n }\n speak(text: string, cont: boolean): void {\n if (this.down) return;\n // An empty continuation has nothing to synthesize and Cartesia hard-400s on it (\"transcript must\n // not be empty when continue is true unless flushing\"). Deltas that sanitize to nothing (a chunk of\n // pure markdown/whitespace via forSpeech) hit this — drop them. The real flush is end()'s cont=false.\n if (cont && !text) return;\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(this.frame(text, cont));\n else void this.ensureConnected().then(() => this.ws?.readyState === WebSocket.OPEN && this.ws.send(this.frame(text, cont)));\n }\n end(): void {\n if (this.down) { this.onDone(); return; }\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(this.frame('', false));\n }\n cancel(): void {\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(JSON.stringify({ context_id: this.ctxId, cancel: true }));\n }\n private startProbe(): void {\n if (this.probeTimer) return;\n this.probeTimer = setInterval(() => {\n if (!this.down) { this.stopProbe(); return; }\n this.consecutiveErrors = 0;\n // bypass the `down` guard in speak() — send a probe frame directly\n this.newContext();\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(this.frame('Ok.', false)); // synthesizable probe — '.' 400s (\"No valid transcripts\") and would never close the breaker\n }, CartesiaTTS.CB_PROBE_MS);\n (this.probeTimer as any).unref?.();\n }\n private stopProbe(): void {\n if (this.probeTimer) { clearInterval(this.probeTimer); this.probeTimer = null; }\n }\n close(): void {\n this.closed = true;\n this.stopProbe();\n if (this.ws) this.ws.onclose = null as any;\n this.ws?.close();\n }\n}\n\n/** atob-based for browsers, Buffer for Bun/Node — both produce a Uint8Array. */\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof Buffer !== 'undefined') return Buffer.from(b64, 'base64');\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n","/** Shim — the voice engine is served from @bod.ee/voice (extracted from here).\n * Routes the extracted core's logs into agentx's libx.js logger. */\nimport { configureLogging } from '@bod.ee/voice';\nimport { forComponent } from '../logging';\n\nconfigureLogging((name) => {\n // libx.js log methods are fixed-arity in the type surface; cast to a rest\n // signature so forwarding a spread is legal under agentx's dts build.\n const l = forComponent(name) as unknown as Record<string, (...a: unknown[]) => void>;\n const at = (m: string) => (...a: unknown[]) => l[m]?.(...a);\n return { debug: at('debug'), verbose: at('verbose'), info: at('info'), warn: at('warn'), error: at('error') };\n});\n\nexport * from '@bod.ee/voice';\n","import type { AgentTool } from './tools';\nimport { topByRelevance } from './relevance';\n\n/**\n * MCP bridge — adapt a Model Context Protocol tool list into the agent's AgentTool[],\n * so any MCP server's tools become first-class agent tools (edge-safe: you supply the\n * transport via `callTool`; this module has no node/network dependency of its own).\n *\n * Pass the server's advertised tools + a `callTool(name, args)` that performs the call\n * (over stdio/HTTP/whatever you wire up); each becomes an AgentTool the Agent can use.\n */\nexport interface McpToolSpec {\n name: string;\n description?: string;\n /** JSON Schema for the tool's arguments (MCP's `inputSchema`). */\n inputSchema?: object;\n}\n\n/** Perform an MCP tool call; return its textual result. Throw to surface an error to the model. */\nexport type McpCall = (name: string, args: any) => Promise<unknown>;\n\nexport interface McpImage { mimeType: string; data: string }\nexport interface McpToolResult { text: string; images?: McpImage[] }\n\n/** Normalize an MCP call result into text + optional image blocks. */\nfunction toResult(result: unknown): McpToolResult {\n if (result == null) return { text: '' };\n if (typeof result === 'string') return { text: result };\n const content = (result as any).content;\n if (Array.isArray(content)) {\n const texts: string[] = [];\n const images: McpImage[] = [];\n for (const c of content) {\n if (c?.type === 'image' && typeof c.data === 'string' && c.mimeType) {\n images.push({ mimeType: c.mimeType, data: c.data });\n } else if (typeof c?.text === 'string') {\n texts.push(c.text);\n } else {\n texts.push(JSON.stringify(c));\n }\n }\n const text = texts.join('\\n');\n if (text || images.length) return { text, ...(images.length ? { images } : {}) };\n }\n return { text: JSON.stringify(result) };\n}\n\nfunction toText(result: unknown): string { return toResult(result).text; }\n\n/**\n * An MCP call had NO deadline of its own: a server that never answers hung the tool call forever, and\n * (declaring nothing) it was silently assumed prompt by every transport above the loop. Bound it here so\n * the tool can honestly declare `maxDurationMs`, and so a hung server produces a statement of what\n * happened rather than a stall.\n */\nexport const MCP_CALL_TIMEOUT_MS = 300_000;\nconst TIMED_OUT = Symbol('mcp-timeout');\nasync function withDeadline<T>(p: Promise<T>, ms: number): Promise<T | typeof TIMED_OUT> {\n let t: any;\n try {\n return await Promise.race([p, new Promise<typeof TIMED_OUT>((res) => { t = setTimeout(() => res(TIMED_OUT), ms); })]);\n } finally { clearTimeout(t); }\n}\nconst mcpTimedOut = (name: string, ms = MCP_CALL_TIMEOUT_MS) =>\n `[${name}] no response after ${ms / 1000}s — the MCP server never answered. The call's outcome is UNKNOWN: `\n + `do not assume it ran or that it failed. Verify the state (or pick a bounded/narrower call) before retrying.`;\n\n/** Adapt one MCP tool spec into an AgentTool backed by `callTool`. */\nexport function mcpToolToAgentTool(spec: McpToolSpec, callTool: McpCall, prefix = 'mcp__', timeoutMs = MCP_CALL_TIMEOUT_MS): AgentTool {\n return {\n name: `${prefix}${spec.name}`,\n description: spec.description ?? `MCP tool ${spec.name}`,\n parameters: spec.inputSchema ?? { type: 'object', properties: {} },\n maxDurationMs: timeoutMs,\n async run(args, _ctx) {\n const raw = await withDeadline(callTool(spec.name, args ?? {}), timeoutMs);\n if (raw === TIMED_OUT) return mcpTimedOut(spec.name, timeoutMs);\n const r = toResult(raw);\n return r.images?.length ? r : r.text;\n },\n };\n}\n\n/** Adapt a whole MCP tool list into AgentTool[] (names prefixed to avoid collisions).\n * Optional `filter` pre-narrows the set at mount time (host allowlist), so a server with\n * hundreds of tools needn't mount them all eagerly. */\nexport function mcpToolsToAgentTools(specs: McpToolSpec[], callTool: McpCall, prefix = 'mcp__', filter?: (spec: McpToolSpec) => boolean): AgentTool[] {\n return (filter ? specs.filter(filter) : specs).map((s) => mcpToolToAgentTool(s, callTool, prefix));\n}\n\nexport interface McpToolSearchOptions {\n /** Prefix stripped from / shown on tool names (cosmetic; mirrors the adapter prefix). Default 'mcp__'. */\n prefix?: string;\n /** Max tools returned per `ToolSearch` query. Default 10. */\n maxResults?: number;\n /** Per-call deadline for `McpCall`. Default MCP_CALL_TIMEOUT_MS. */\n timeoutMs?: number;\n}\n\n/** Render one spec for the search result: name, description, and its argument schema (so the\n * model knows how to call it via `McpCall`). */\nfunction describeSpec(s: McpToolSpec): string {\n const schema = s.inputSchema ? `\\n args: ${JSON.stringify(s.inputSchema)}` : '';\n return `${s.name} — ${s.description ?? '(no description)'}${schema}`;\n}\n\n/**\n * Deferred-mount mode (ToolSearch-equivalent) for large MCP tool sets. Instead of mounting N\n * tools into the wire schema (cost + latency + model confusion past a few dozen), mount exactly\n * TWO bounded tools regardless of N:\n * - `ToolSearch({ query })` — ranks the catalog by relevance and returns the top matches with\n * their argument schemas, so the model discovers what's available on demand.\n * - `McpCall({ name, args })` — invokes any catalog tool by name through the same transport.\n * Keep `mcpToolsToAgentTools` (eager) as the default for small sets.\n */\nexport function makeMcpToolSearch(specs: McpToolSpec[], callTool: McpCall, options: McpToolSearchOptions = {}): AgentTool[] {\n const maxResults = options.maxResults ?? 10;\n const callTimeoutMs = options.timeoutMs ?? MCP_CALL_TIMEOUT_MS;\n const byName = new Map(specs.map((s) => [s.name, s]));\n const catalogLine = `${specs.length} MCP tool(s) available — search by keyword, then call by exact name.`;\n\n const searchTool: AgentTool = {\n name: 'ToolSearch',\n description: `Search the available MCP tools by keyword (${catalogLine}). Returns matching tool names + their argument schemas; call one with \\`McpCall\\`.`,\n parameters: { type: 'object', required: ['query'], properties: { query: { type: 'string', description: 'keywords to match against tool name + description' } } },\n async run({ query }) {\n const q = String(query ?? '').trim();\n if (!q) return catalogLine;\n const { kept } = topByRelevance(specs, q, (s) => `${s.name} ${s.description ?? ''}`, maxResults);\n if (!kept.length) return `(no MCP tool matches \"${q}\" — try broader keywords)`;\n return kept.map(describeSpec).join('\\n');\n },\n };\n\n const callMcpTool: AgentTool = {\n name: 'McpCall',\n description: 'Call an MCP tool discovered via `ToolSearch`, by its exact name. Pass its arguments as `args`.',\n parameters: {\n type: 'object',\n required: ['name'],\n properties: {\n name: { type: 'string', description: 'exact tool name from ToolSearch' },\n args: { type: 'object', description: 'arguments object for the tool (per its schema)' },\n },\n },\n maxDurationMs: callTimeoutMs,\n async run({ name, args }) {\n const n = String(name ?? '');\n if (!byName.has(n)) return `Error: unknown MCP tool '${n}'. Use ToolSearch to find valid names.`;\n const raw = await withDeadline(callTool(n, args ?? {}), callTimeoutMs);\n if (raw === TIMED_OUT) return mcpTimedOut(n, callTimeoutMs);\n const r = toResult(raw);\n return r.images?.length ? r : r.text;\n },\n };\n\n return [searchTool, callMcpTool];\n}\n\n/** Minimal shape of a mounted MCP server this module needs — structurally satisfied by\n * `MountedMcp` from `mcp.client.ts`, kept local so `mcp.ts` stays node-free/edge-safe. */\nexport interface MountedMcpLike {\n name: string;\n specs: McpToolSpec[];\n client: { callTool(name: string, args: unknown): Promise<unknown> };\n}\n\n/** A flattened catalog entry's origin: which server owns it + the un-prefixed raw tool name. */\nexport interface McpRoute { server: string; rawName: string }\n\n/** Flatten servers' specs into one `mcp__<server>__<tool>` namespace + a display→origin map.\n * Sanitizing/truncating to provider name rules can MERGE distinct names (`a/b` & `a:b` → `a_b`),\n * so dedupe with a numeric suffix — a silent overwrite would orphan a tool. */\nexport function buildMcpCatalog(servers: { name: string; specs: McpToolSpec[] }[]): { specs: McpToolSpec[]; routes: Map<string, McpRoute> } {\n const specs: McpToolSpec[] = [];\n const routes = new Map<string, McpRoute>();\n for (const m of servers) {\n for (const s of m.specs) {\n const base = `mcp__${m.name}__${s.name}`.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 128);\n let display = base;\n for (let i = 2; routes.has(display); i++) display = `${base.slice(0, 128 - String(i).length - 1)}_${i}`;\n specs.push({ name: display, description: s.description, inputSchema: s.inputSchema });\n routes.set(display, { server: m.name, rawName: s.name });\n }\n }\n return { specs, routes };\n}\n\n/** Resolve a routed MCP call to its result. Throw to surface an error to the model. */\nexport type McpRouteResolver = (server: string, rawName: string, args: any) => Promise<unknown>;\n\n/** Shared core: wire the `ToolSearch`/`McpCall` pair over a prebuilt catalog, dispatching each\n * call through `resolve(server, rawName, args)` (eager → a mounted client; lazy → connect-on-call). */\nfunction searchOverCatalog(servers: string[], specs: McpToolSpec[], routes: Map<string, McpRoute>, resolve: McpRouteResolver, options?: McpToolSearchOptions) {\n const tools = specs.length\n ? makeMcpToolSearch(specs, (name, args) => {\n const r = routes.get(name);\n if (!r) throw new Error(`unknown MCP tool '${name}' — use ToolSearch to find valid names`);\n return resolve(r.server, r.rawName, args ?? {});\n }, options)\n : [];\n return { tools, serverNames: servers, toolCount: specs.length };\n}\n\n/**\n * Ergonomic deferred-mount over already-mounted MCP servers: flattens their specs into one\n * `mcp__<server>__<tool>` namespace and wires a single `ToolSearch`/`McpCall` pair that routes\n * each call to the owning server's RAW `callTool` (so result normalization happens exactly once —\n * double-normalizing corrupts image blocks).\n */\nexport function makeMcpToolSearchFromMounted(\n mounted: MountedMcpLike[],\n options?: McpToolSearchOptions,\n): { tools: AgentTool[]; serverNames: string[]; toolCount: number } {\n const { specs, routes } = buildMcpCatalog(mounted);\n const byName = new Map(mounted.map((m) => [m.name, m]));\n return searchOverCatalog(mounted.map((m) => m.name), specs, routes, (server, rawName, args) => byName.get(server)!.client.callTool(rawName, args), options);\n}\n\n/**\n * Lazy variant: same `ToolSearch`/`McpCall` surface, but the server isn't required to be connected.\n * Each `McpCall` resolves the owning server from the catalog and `resolve(server, rawName, args)`\n * connects-on-demand — so a turn that calls no MCP tool opens ZERO connections. Edge-safe: the\n * caller (`mountMcpCatalog` in `mcp.client.ts`) supplies the node-side connect/pool logic.\n */\nexport function makeLazyMcpToolSearch(\n servers: { name: string; specs: McpToolSpec[] }[],\n resolve: McpRouteResolver,\n options?: McpToolSearchOptions,\n): { tools: AgentTool[]; serverNames: string[]; toolCount: number } {\n const { specs, routes } = buildMcpCatalog(servers);\n return searchOverCatalog(servers.map((s) => s.name), specs, routes, resolve, options);\n}\n","/**\n * Hooks — deterministic interception points around tool execution, run by the\n * harness/host (mirrors Claude Code hooks). The seam stays edge-safe: hooks are\n * plain async callbacks, no node builtins, injected via AgentOptions.hooks.\n *\n * - preToolUse: fires BEFORE a tool runs. Return `{ block: true, reason }` to\n * skip the tool — Agent.dispatch returns `Blocked by hook: <reason>`\n * as the tool result (the model sees it and can adapt).\n * - postToolUse: fires AFTER a tool produced its result string (observe/audit).\n * - onStop: fires once when the loop terminates with finishReason 'stop'.\n */\nimport type { Message } from './llm';\n\nexport interface ToolUse {\n name: string;\n args: any;\n}\n\nexport interface PreToolUseDecision {\n block?: boolean;\n reason?: string;\n}\n\n/** Per-call metadata threaded through dispatch — `id` is the model-supplied tool_call id,\n * letting a host correlate a result to its call without assuming serial dispatch order. */\nexport interface ToolUseMeta {\n id?: string;\n}\n\nexport interface Hooks {\n /** Guard a tool call before it runs; return `{ block, reason }` to skip it. */\n preToolUse?(call: ToolUse, meta?: ToolUseMeta): Promise<PreToolUseDecision | void> | PreToolUseDecision | void;\n /** Observe a tool's result after it ran (audit, metrics, side-channel). */\n postToolUse?(call: ToolUse, result: string, meta?: ToolUseMeta): void | Promise<void>;\n /** Observe a tool's INCREMENTAL output while it runs (only tools that stream, e.g. the real\n * Shell). Fire-and-forget — sync, never awaited, never alters the result. */\n onToolOutput?(call: ToolUse, chunk: string, meta?: ToolUseMeta): void;\n /** Fired once when the agent loop stops cleanly with the model's final text. */\n onStop?(finalText: string): void;\n // --- lifecycle (all optional; fired from well-known points in run/send/compact) ---\n /** Fired once at session start (a fresh `run()`, or the first `send()`). Return a string to inject\n * as extra system context (e.g. environment facts, project status). Multiple hooks concatenate. */\n onSessionStart?(): string | void | Promise<string | void>;\n /** Fired per user turn BEFORE the model call. Return a string to replace the submitted text\n * (rewrite/annotate the prompt); chained across hooks. Return void to leave it unchanged. */\n onUserPromptSubmit?(text: string): string | void | Promise<string | void>;\n /** Fired before a manual `compactNow()` folds older messages — observe (e.g. persist a summary). */\n onPreCompact?(messages: Message[]): void | Promise<void>;\n /** Fired when a `Task`/`TaskBatch` child agent finishes, with its summary + label. */\n onSubagentStop?(summary: string, info?: { label?: string; agentType?: string }): void | Promise<void>;\n}\n\n/** Deterministic Hooks for tests/dev: records calls + scripts block decisions by tool name. */\nexport class RecordingHooks implements Hooks {\n public pre: Array<{ call: ToolUse; meta?: ToolUseMeta }> = [];\n public post: Array<{ call: ToolUse; result: string; meta?: ToolUseMeta }> = [];\n public outputs: Array<{ call: ToolUse; chunk: string; meta?: ToolUseMeta }> = [];\n public stops: string[] = [];\n /** tool name -> reason; a matching preToolUse call is blocked with that reason. */\n constructor(private blocks: Record<string, string> = {}) {}\n preToolUse(call: ToolUse, meta?: ToolUseMeta): PreToolUseDecision | void {\n this.pre.push({ call, meta });\n const reason = this.blocks[call.name];\n if (reason != null) return { block: true, reason };\n }\n postToolUse(call: ToolUse, result: string, meta?: ToolUseMeta): void {\n this.post.push({ call, result, meta });\n }\n onToolOutput(call: ToolUse, chunk: string, meta?: ToolUseMeta): void {\n this.outputs.push({ call, chunk, meta });\n }\n onStop(finalText: string): void {\n this.stops.push(finalText);\n }\n}\n\n/** Recording lifecycle hooks for tests: capture session-start/prompt-submit/pre-compact + script transforms. */\nexport class RecordingLifecycle implements Hooks {\n public starts = 0;\n public prompts: string[] = [];\n public compactions: number[] = [];\n /** @param startContext injected at session start; @param rewrite maps a submitted prompt to a new one. */\n constructor(private startContext?: string, private rewrite?: (t: string) => string) {}\n public subagentStops: Array<{ summary: string; label?: string }> = [];\n onSessionStart(): string | void { this.starts++; return this.startContext; }\n onUserPromptSubmit(text: string): string | void { this.prompts.push(text); return this.rewrite?.(text); }\n onPreCompact(messages: Message[]): void { this.compactions.push(messages.length); }\n onSubagentStop(summary: string, info?: { label?: string }): void { this.subagentStops.push({ summary, label: info?.label }); }\n}\n"],"mappings":"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","names":["log","path","norm","i","log","res","log","realpathSync","now","ctx","resolve","log","NO_JOB","slug","MAX_CATALOG","parseFrontmatter","slug","l","slug","mkdirSync","join","statSync","readFileSync","slug","log","slug","mkdirSync","join","fs","wtHandle","childOpts","rememberTool","log","NodeDiskFilesystem","JailedFilesystem","o","imgs","PathResolver","now","backend","id","makeRealShellTool","makeShellJobTools","ShellJobRegistry","formatJobExit","log","log","log","slug","MemFilesystem","forComponent","log","forComponent","log","log","forComponent","norm","now","text","log","forComponent","log","forComponent","now","log","MemFilesystem","resolve","resolve","MemFilesystem","CommandExecutor","registerHeadlessCommands"]}
1
+ {"version":3,"sources":["../src/logging.ts","../src/llm.ts","../src/redact.ts","../src/tools.structured.ts","../src/todo.ts","../src/tools.web.ts","../src/OverlayFilesystem.ts","../src/tools.ts","../src/NodeDiskFilesystem.ts","../src/JailedFilesystem.ts","../src/shell.sandbox.ts","../src/tools.shell.ts","../src/Agent.ts","../src/tools.jobs.ts","../src/host.ts","../src/relevance.ts","../src/frontmatter.ts","../src/commands.ts","../src/skills.ts","../src/memory.ts","../src/instructions.ts","../src/subagent.ts","../src/models.ts","../src/worktree.ts","../src/agents.ts","../src/permissions.ts","../src/lint.ts","../src/reasoning.ts","../src/index.ts","../src/BodDbFilesystem.ts","../src/MountFilesystem.ts","../src/speculate.ts","../src/synthesize.ts","../src/FakeAIClient.ts","../src/scheduler.ts","../src/presets.ts","../src/scratch.ts","../src/lessons.ts","../src/reflect.ts","../src/duplex.ts","../node_modules/@bod.ee/voice/src/core/logging.ts","../node_modules/@bod.ee/voice/src/core/emotion.ts","../node_modules/@bod.ee/voice/src/core/engine.ts","../node_modules/@bod.ee/voice/src/core/types.ts","../node_modules/@bod.ee/voice/src/core/spokenSplitter.ts","../node_modules/@bod.ee/voice/src/adapters/soniox.ts","../node_modules/@bod.ee/voice/src/adapters/cartesia.ts","../src/voice/engine.ts","../src/mcp.ts","../src/hooks.ts"],"sourcesContent":["// Import the log module directly from libx.js source: libx.js's main bundle\n// doesn't re-export `log` as a named ESM export, and source-importing keeps\n// libx.js patches live (no rebuild) — matching the `bun link` workflow.\nimport { log } from 'libx.js/src/modules/log';\n\n/** Component-scoped logger (libx.js). debug/verbose gated via DEBUG env/localStorage. */\nexport const forComponent = (name: string) => log.forComponent(name);\nexport { log };\n","/**\n * Wire types mirroring ai.libx.js (OpenAI-style chat). We type the transport\n * structurally via `ChatLike`, so an ai.libx.js `AIClient` is a drop-in — and a\n * `FakeAIClient` works in tests — with no hard runtime dependency on ai.libx.js.\n */\n\nimport { readFileSync, statSync, realpathSync } from 'node:fs';\nimport { resolve, sep } from 'node:path';\nimport { randomBytes } from 'node:crypto';\nimport { forComponent } from './logging';\n\nconst log = forComponent('llm');\n\nexport type Role = 'system' | 'user' | 'assistant' | 'tool';\n\nexport interface ToolCall {\n id: string;\n type: 'function';\n function: { name: string; arguments: string }; // arguments is a JSON string\n}\n\n/** One part of a multimodal message (mirrors ai.libx.js ContentPart) — text or an image URL/data-URI. */\nexport interface ContentPart {\n type: 'text' | 'image_url';\n text?: string;\n image_url?: { url: string };\n}\n\n/** A message's content is either plain text or an array of multimodal parts (images + text). */\nexport type MessageContent = string | ContentPart[];\n\nexport interface Message {\n role: Role;\n content: MessageContent;\n name?: string;\n tool_call_id?: string;\n tool_calls?: ToolCall[];\n /** The assistant step's reasoning, kept ONLY for providers that need it passed back (see passesBackReasoning). */\n reasoning_content?: string;\n}\n\n/**\n * Providers whose ai.libx.js adapter sends `reasoning_content` back to the vendor: DeepSeek (thinking +\n * tools 400s without it) and Moonshot/Kimi (\"preserve each historical assistant message's reasoning\").\n * Everyone else ignores the field, so persisting it there would only bloat the transcript — cursor, for\n * one, streams its WHOLE reply as reasoning.\n */\nexport function passesBackReasoning(model: string | undefined): boolean {\n return !!model && /^(deepseek|moonshot)\\//.test(model);\n}\n\n/** Flatten any message content to its text (string as-is; parts → concatenated text) — for length\n * estimation, summaries, and display. Non-text parts (images) contribute a short placeholder. */\nexport function contentText(content: MessageContent | undefined): string {\n if (content == null) return '';\n if (typeof content === 'string') return content;\n return content.map((p) => (p.type === 'text' ? (p.text ?? '') : '[image]')).join(p_sep(content));\n}\nconst p_sep = (parts: ContentPart[]): string => (parts.length > 1 ? '\\n' : '');\n\n/** Build an image content part from a data-URI or http(s) URL. */\nexport function imagePart(url: string): ContentPart {\n return { type: 'image_url', image_url: { url } };\n}\n\n/** Stub left when an inline data-URI image is elided from the stored transcript (RAM + disk). */\nexport const IMAGE_ELIDE_STUB = '[image elided — re-attach @path or /paste to view again]';\n\n/** True when content carries an inline base64 image (the heavy case — http(s) URLs are tiny). */\nexport function messageHasInlineImage(content: MessageContent | undefined): boolean {\n if (content == null || typeof content === 'string') return false;\n return content.some((p) => p.type === 'image_url' && (p.image_url?.url ?? '').startsWith('data:'));\n}\n\n/** Byte-weight for context budgeting — counts base64 payloads, not the `[image]` display placeholder. */\nexport function contentBytes(content: MessageContent | undefined): number {\n if (content == null) return 0;\n if (typeof content === 'string') return content.length;\n let n = 0;\n for (const p of content) {\n if (p.type === 'text') { n += (p.text ?? '').length; continue; }\n const url = p.image_url?.url ?? '';\n const ref = parseImageRef(url);\n // A ref is ~60 chars on disk but becomes the whole file on the wire IF it survives the send-time\n // window. Callers that budget the real payload run `expandImagesForSend` FIRST (Agent.trimContext)\n // or use `sendBytes` — this is the honest weight for a still-unexpanded ref.\n n += (ref ? ref.bytes : url.length) || 7;\n }\n return n;\n}\n\n/** Replace inline data-URI image parts with a text stub; http(s) URLs, image REFS and plain text\n * unchanged — a ref is ~60 bytes and stays re-expandable, so there is nothing to reclaim. */\nexport function elideInlineImages(content: MessageContent, stub = IMAGE_ELIDE_STUB): MessageContent {\n return elideImageParts(content, (url) => url.startsWith('data:'), stub);\n}\n\n/** Replace EVERY heavy image part — inline base64 AND refs — with the stub. This is the destructive\n * form used by the `/compact` elision ladder: a ref is cheap on disk but weighs its whole file on the\n * wire while it's inside the send window, so it must be shave-able or the ladder falls through to\n * shredding (then dropping) the user's own text. `elideInlineImages` stays the non-destructive form. */\nexport function elideImages(content: MessageContent, stub = IMAGE_ELIDE_STUB): MessageContent {\n return elideImageParts(content, (url) => url.startsWith('data:') || isImageRefUrl(url), stub);\n}\n\nfunction elideImageParts(content: MessageContent, hit: (url: string) => boolean, stub: string): MessageContent {\n if (typeof content === 'string') return content;\n let changed = false;\n const out: ContentPart[] = [];\n for (const p of content) {\n if (p.type !== 'image_url' || !hit(p.image_url?.url ?? '')) { out.push(p); continue; }\n changed = true;\n out.push({ type: 'text', text: stub });\n }\n return changed ? out : content;\n}\n\n/**\n * A persist-safe REFERENCE to an image FILE. Stored in the transcript (and the session JSON) instead\n * of the megabytes of base64 — `expandImagesForSend` turns it back into a data-URI in the OUTGOING\n * request only, so neither the heap nor the disk ever holds historical payloads.\n *\n * SECURITY: a ref is a CAPABILITY, not a path. The URL carries an unguessable token; the real path\n * lives only in this in-process registry, and only HOST code that already did the jail/permission\n * check can mint one (`mintImageRef`, used by the CLI's @image attach and the image `Read` tool).\n * Tool results are MODEL-CONTROLLED text (bash prints whatever it likes) — parsing a path out of them\n * could never be the authorization. An unknown/evicted token is simply not a ref: it degrades to the\n * elision stub, never a file read. That also covers a resumed session in a fresh process.\n * Shape stays inside `image_url.url` so old readers/serializers need no schema change:\n * `agentx-image:<mime>;<token>;<path>`\n * The trailing path is INERT BOOKKEEPING — `parseImageRef` never reads it, so it can't authorize\n * anything. It exists only so `remintImageRefs` can re-grant the capability on session load, after\n * re-checking the path against an allowed root (see there).\n */\nexport const IMAGE_REF_SCHEME = 'agentx-image:';\n\nexport interface ImageRef {\n mime: string;\n /** Absolute on-disk path. Never derived from model output — only from a mint-time capability. */\n path: string;\n /** base64 wire weight, stat'ed AT MINT TIME (so an overwritten-in-place path can never go stale). */\n bytes: number;\n}\n\n/** Bounded so a long session can't grow the registry without limit; oldest minted token is evicted\n * first (and an evicted ref degrades to the stub, exactly like a missing file). */\nconst REF_REGISTRY_MAX = 256;\nconst refRegistry = new Map<string, ImageRef>();\n\n/**\n * Mint an image-ref URL for an ALREADY-AUTHORIZED absolute path. Host-only: call this after the\n * jail/permission check, never on a path that came out of model output.\n */\nexport function mintImageRef(path: string, mime: string): string {\n const token = randomBytes(16).toString('hex');\n let bytes = 0;\n try { bytes = Math.ceil(statSync(path).size * 4 / 3); } // base64 expansion — what actually goes on the wire\n catch (e) { log.warn(`image ref stat failed, weighing as 0: ${path}`, e); }\n refRegistry.set(token, { mime, path, bytes });\n while (refRegistry.size > REF_REGISTRY_MAX) refRegistry.delete(refRegistry.keys().next().value as string);\n return `${IMAGE_REF_SCHEME}${mime};${token};${path}`;\n}\n\n/** Test/host hook: forget every minted ref (simulates a fresh process / resumed session). */\nexport function clearImageRefs(): void { refRegistry.clear(); }\n\n/** Build an image REFERENCE part for an authorized path. */\nexport function imageRefPart(path: string, mime: string): ContentPart {\n return { type: 'image_url', image_url: { url: mintImageRef(path, mime) } };\n}\n\n/** Does this URL claim to be an image ref? (Claim only — resolution is `parseImageRef`.) */\nconst isImageRefUrl = (url: string | undefined): boolean => !!url && url.startsWith(IMAGE_REF_SCHEME);\n\n/** Resolve an image-ref URL through the registry; null when it isn't one, or the token is unknown\n * (forged by the model, evicted, or from a previous process). NEVER trusts the URL's own text. */\nexport function parseImageRef(url: string | undefined): ImageRef | null {\n const parts = refUrlParts(url);\n const ref = parts && refRegistry.get(parts.token);\n if (!ref) { log.debug('image ref not in registry — treating as non-image text'); return null; }\n return ref;\n}\n\n/** Split a ref URL into its literal fields. `path` here is UNTRUSTED bookkeeping — never a capability. */\nfunction refUrlParts(url: string | undefined): { mime: string; token: string; path: string } | null {\n if (!isImageRefUrl(url)) return null;\n const rest = url!.slice(IMAGE_REF_SCHEME.length);\n const a = rest.indexOf(';');\n if (a < 0) return null;\n const b = rest.indexOf(';', a + 1);\n return { mime: rest.slice(0, a), token: b < 0 ? rest.slice(a + 1) : rest.slice(a + 1, b), path: b < 0 ? '' : rest.slice(b + 1) };\n}\n\n/**\n * Session LOAD: re-grant the capability for stored image parts whose token died with the previous\n * process, so a resumed session's recent screenshot is visible again (parity with the pre-ref\n * behaviour, where `elideStaleImages` kept the last inline image).\n *\n * A session file is WRITABLE BY THE MODEL (it can Write/Edit it, and the user may hand-edit it), so a\n * stored path is untrusted input — its provenance proves nothing. The ROOT CHECK is what makes this\n * safe: only a path whose REALPATH (symlinks resolved) sits inside one of `roots` is re-minted.\n * Anything else is left unresolvable and degrades to the elision stub, with a warn.\n *\n * Only image PARTS in user/assistant content are considered. Tool-result strings stay inert forever —\n * those are the model's own stdout and must never mint anything.\n * Pure view: returns a new array only when something changed.\n */\nexport function remintImageRefs(messages: Message[], roots: string[]): Message[] {\n const allowed: string[] = [];\n for (const r of roots) {\n try { allowed.push(realpathSync(resolve(r))); } catch (e) { log.debug(`image-ref root unavailable: ${r}`, e); }\n }\n if (allowed.length === 0) return messages;\n const inside = (p: string): boolean => allowed.some((root) => p === root || p.startsWith(root + sep));\n let changed = false;\n const out = messages.map((m) => {\n if ((m.role !== 'user' && m.role !== 'assistant') || typeof m.content === 'string' || m.content == null) return m;\n let touched = false;\n const parts = m.content.map((p) => {\n if (p.type !== 'image_url') return p;\n const f = refUrlParts(p.image_url?.url);\n if (!f || refRegistry.has(f.token)) return p; // not a ref, or still live in this process\n let real: string;\n try { real = realpathSync(f.path); } catch (e) { log.warn(`resumed image ref unreadable, will stub: ${f.path}`, e); return p; }\n if (!inside(real)) { log.warn(`resumed image ref outside the allowed roots, will stub: ${f.path} -> ${real}`); return p; }\n touched = true;\n return { type: 'image_url', image_url: { url: mintImageRef(real, f.mime) } } as ContentPart;\n });\n if (!touched) return m;\n changed = true;\n return { ...m, content: parts };\n });\n return changed ? out : messages;\n}\n\n/** True when content carries an image REF part (weightless on disk, expanded at send time). The\n * CLAIM is enough: an unresolvable ref (resumed session / evicted token) still counts as image-bearing\n * so the send path turns it into the stub instead of shipping the unresolvable scheme to the provider. */\nexport function messageHasImageRef(content: MessageContent | undefined): boolean {\n if (content == null || typeof content === 'string') return false;\n return content.some((p) => p.type === 'image_url' && isImageRefUrl(p.image_url?.url));\n}\n\n/** Any image at all — inline base64 (legacy sessions) or a ref. Drives `keepRecent` windows. */\nexport function messageHasImage(content: MessageContent | undefined): boolean {\n return messageHasInlineImage(content) || messageHasImageRef(content);\n}\n\n/** `Read` on an image persists this instead of the base64; expanded to `{dataUrl}` at send time.\n * `path` must already have passed the filesystem's jail check (see `mintImageRef`). */\nexport function imageRefResult(path: string, mime: string): string {\n return JSON.stringify({ imageRef: mintImageRef(path, mime), image: path });\n}\n\n/** The registered ref behind a tool message's `{\"imageRef\":…}` JSON body, if that's what it is.\n * A model-forged body parses fine but resolves to null — the token isn't in the registry. */\nexport function toolImageRef(content: MessageContent | undefined): ImageRef | null {\n if (typeof content !== 'string' || !content.startsWith('{\"imageRef\":')) return null;\n try { return parseImageRef(JSON.parse(content).imageRef); } catch (e) { log.debug('bad imageRef tool result', e); return null; }\n}\n\n/** Elide inline images from all but the most-recent `keepRecent` image-bearing messages (mutates copies). */\nexport function elideStaleImages(messages: Message[], keepRecent = 1): Message[] {\n const idx = messages.map((m, i) => (messageHasImage(m.content) ? i : -1)).filter((i) => i >= 0);\n const drop = new Set(idx.slice(0, Math.max(0, idx.length - keepRecent)));\n if (drop.size === 0) return messages;\n let changed = false;\n const out = messages.map((m, i) => {\n if (!drop.has(i)) return m;\n const c = elideInlineImages(m.content);\n if (c === m.content) return m;\n changed = true;\n return { ...m, content: c };\n });\n return changed ? out : messages;\n}\n\n/**\n * The send-time verdict per message index. User ATTACHMENTS and tool-result image `Read`s get\n * INDEPENDENT windows: an image the model Reads mid-turn must never evict the image the user just\n * pasted (the spec's non-goal — vision on the paste turn must keep working), and vice-versa.\n */\nfunction imageWindows(messages: Message[], keepRecent: number): Set<number> {\n const attach: number[] = [];\n const tool: number[] = [];\n messages.forEach((m, i) => {\n if (toolImageRef(m.content)) tool.push(i);\n else if (messageHasImage(m.content)) attach.push(i);\n });\n const k = Math.max(0, keepRecent);\n return new Set([...attach.slice(Math.max(0, attach.length - k)), ...tool.slice(Math.max(0, tool.length - k))]);\n}\n\n/** Is this message image-bearing at all (either kind)? */\nconst bearsImage = (m: Message): boolean => messageHasImage(m.content) || toolImageRef(m.content) != null;\n\n/**\n * SEND-PATH expansion: image REFS become real data-URIs only in the outgoing request, and only for the\n * most-recent `keepRecent` messages of EACH kind (user attachment / tool image Read) — older ones (refs\n * AND legacy inline base64) collapse to the elision stub. Pure view: the caller's messages are never mutated.\n * A missing/unreadable file (or an unregistered ref) degrades to the same stub and is LOGGED — never throws.\n */\nexport function expandImagesForSend(messages: Message[], keepRecent = 1, stub = IMAGE_ELIDE_STUB): Message[] {\n if (!messages.some(bearsImage)) return messages;\n const keep = imageWindows(messages, keepRecent);\n let changed = false;\n const out = messages.map((m, i) => {\n const content = keep.has(i) ? expandContent(m.content, stub) : stripContent(m.content, stub);\n if (content === m.content) return m;\n changed = true;\n return { ...m, content };\n });\n return changed ? out : messages;\n}\n\n/**\n * Byte-weight of a transcript AS IT WILL GO ON THE WIRE — refs inside the keep window weigh their\n * file's base64 size, everything stale weighs the stub — WITHOUT materializing a single byte of\n * base64. This is the honest number for `/context` and the CLI footer, where the old behaviour made\n * every historical screenshot immortal and produced false \"90% full\" warnings.\n */\nexport function sendBytes(messages: Message[], keepRecent = 1, stub = IMAGE_ELIDE_STUB): number {\n let n = 0;\n for (const b of sendBytesPer(messages, keepRecent, stub)) n += b;\n return n;\n}\n\n/** `sendBytes` split per message — same window, same weights. Lets a budgeter drop/shave message-by-\n * message without re-deriving the window (and without charging a stale ref its file weight). */\nexport function sendBytesPer(messages: Message[], keepRecent = 1, stub = IMAGE_ELIDE_STUB): number[] {\n const keep = messages.some(bearsImage) ? imageWindows(messages, keepRecent) : null;\n return messages.map((m, i) =>\n wireBytes(m.content, keep == null || keep.has(i), stub) + (m.tool_calls ? JSON.stringify(m.tool_calls).length : 0) + (m.reasoning_content?.length ?? 0));\n}\n\n/** contentBytes, but aware of whether this message's images survive the send-time window. */\nfunction wireBytes(content: MessageContent | undefined, kept: boolean, stub: string): number {\n const tool = toolImageRef(content);\n if (tool) return kept ? tool.bytes : stub.length;\n if (content == null || typeof content === 'string') return contentBytes(content);\n if (kept) return contentBytes(content);\n let n = 0;\n for (const p of content) {\n if (p.type === 'text') { n += (p.text ?? '').length; continue; }\n const url = p.image_url?.url ?? '';\n n += url.startsWith('data:') || isImageRefUrl(url) ? stub.length : url.length || 7;\n }\n return n;\n}\n\n/** Read a referenced image as a data-URI; null (logged) when the file is gone/unreadable. */\nfunction readRefDataUrl(ref: ImageRef): string | null {\n try { return `data:${ref.mime};base64,${readFileSync(ref.path).toString('base64')}`; }\n catch (e) { log.warn(`image ref unreadable, sending stub instead: ${ref.path}`, e); return null; }\n}\n\n/** Refs → data-URIs (tool `{imageRef}` bodies → the `{dataUrl}` shape the wire adapter renders). */\nfunction expandContent(content: MessageContent, stub: string): MessageContent {\n const tool = toolImageRef(content);\n if (tool) {\n const url = readRefDataUrl(tool);\n return url ? JSON.stringify({ dataUrl: url, image: tool.path }) : stub;\n }\n if (typeof content === 'string') return content;\n let changed = false;\n const out = content.map((p) => {\n if (p.type !== 'image_url' || !isImageRefUrl(p.image_url?.url)) return p;\n changed = true;\n // Unresolvable (resumed session / evicted token) → stub. Content PARTS are host-authored, so an\n // unknown one is a lost capability, not model text — and the scheme must never reach the provider.\n const ref = parseImageRef(p.image_url?.url);\n const url = ref && readRefDataUrl(ref);\n return url ? imagePart(url) : ({ type: 'text', text: stub } as ContentPart);\n });\n return changed ? out : content;\n}\n\n/** Stale image-bearing content as it goes on the wire: no base64, no ref the provider can't resolve. */\nfunction stripContent(content: MessageContent, stub: string): MessageContent {\n if (toolImageRef(content)) return stub;\n if (typeof content === 'string') return content;\n let changed = false;\n const out = content.map((p) => {\n const url = p.type === 'image_url' ? (p.image_url?.url ?? '') : '';\n if (!url.startsWith('data:') && !isImageRefUrl(url)) return p;\n changed = true;\n return { type: 'text', text: stub } as ContentPart;\n });\n return changed ? out : content;\n}\n\nexport interface Tool {\n type: 'function';\n function: { name: string; description?: string; parameters: object };\n}\n\nexport interface ChatResponse {\n content: string;\n finishReason?: string;\n toolCalls?: ToolCall[];\n model?: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n /** The step's accumulated reasoning/thinking text (provider-dependent). */\n reasoningContent?: string;\n /** Tools a self-executing runtime (cursor/claude-code) ran inside its OWN loop — correlated from\n * the display-only `toolActivity` stream. Not dispatched by us; persisted so the transcript keeps\n * a faithful record (audit + resume) instead of being narration-only. */\n delegatedTools?: { id: string; name: string; input?: unknown; output?: unknown; status: 'running' | 'completed' | 'error' }[];\n /** A delegated runtime (cursor/claude-code) ran tools this turn but never CLOSED it: either no assistant\n * text followed the last tool (it went silent post-work), or the text it did emit ends on an action it\n * announced and never took. Signals the loop's closure reflex (see AgentOptions.closeDelegatedTurns). */\n endedWithoutClosing?: boolean;\n}\n\n/**\n * Does this assistant text end mid-plan — on an action the model ANNOUNCED but never took?\n *\n * Cursor/composer narrates as it works (\"Searching the codebase…\", \"Also checking for X\"), and its run\n * can settle FINISHED while the narration is still mid-plan. The turn then looks closed (finishReason\n * 'stop', text present) but delivered no answer. Measured over the local cursor session corpus: ~4.6%\n * of tool-using turns end this way.\n *\n * Matches only FIRST-PERSON commitments (\"Let me…\", \"I'll…\", \"I need to…\") and progressive narration\n * (\"Checking…\", \"Expanding…\"). Deliberately excludes \"Next step: …\" / \"Next run will…\" and \"Let me know\n * if…\" — those are legitimate things to say TO the user, and nudging them would talk over a finished\n * answer. A false positive costs one extra step, so the rule stays conservative rather than clever.\n *\n * The two arms are deliberately scoped differently:\n *\n * COMMITMENT — first-person SINGULAR \"I'll / let me / I'm going to\", plus the one obligation form the\n * corpus actually stalled on: \"I need to…\". These carry their own subject and tense, so they stay\n * unambiguous anywhere in the sentence and may be matched clause-by-clause — the observed stuck turn\n * hid its commitment in a trailing \"…, so I need to verify …\" clause. Past-tense reports of the same\n * (\"I needed to\") are excluded: they describe work already reasoned about, not work still pending.\n * Second person (\"you'll need to…\") is excluded — that is a recommendation to the user.\n *\n * Deliberately NOT matched: \"we …\" and the softer obligations \"should / must / have to / want to\".\n * They read as recommendations TO the user on a FINISHED answer (\"All tests pass. We should be good to\n * go.\", \"I have to admit, the numbers were surprising.\"), the same category as the NEXT_STEP and\n * SIGN_OFF carve-outs — and nudging a finished answer spends a metered step talking over it. No turn in\n * the corpus needed them, so the conservative bias keeps them out.\n *\n * PROGRESSIVE — a bare gerund (\"Checking the images…\") is only a commitment at the HEAD of the final\n * sentence. Mid-sentence it is almost always a participial modifier of a COMPLETED action\n * (\"I pruned the cache, reclaiming 2.6 GB\"), so it is not matched clause-wise.\n */\nconst COMMITMENT =\n /^(?:also\\s+|now\\s+|then\\s+|so\\s+)*(?:let me\\b(?!\\s+know\\b)|i'?ll\\b|i will\\b|i'?m going to\\b|i\\s+(?:still\\s+|now\\s+|first\\s+)*need to\\b)/i;\nconst PROGRESSIVE =\n /^(?:also\\s+|now\\s+|then\\s+)*(?:re-?)?(?:check|search|scan|read|verify|run|inspect|expand|look|examin|continu|proceed|try|fetch|load|open|test|build|grep|find|review|trac|dig|explor)\\w*ing\\b/i;\nconst NEXT_STEP = /^next (?:step|run|up)\\b/i;\n// \"Let me know if…\" is a SIGN-OFF, not an announced action. It only ever reached the `let me\\b` arm on\n// delegated turns before; once the sawTool gate is dropped (announce-and-stop turns run no tools at all)\n// it would fire on every polite closing line, so exclude it explicitly (in COMMITMENT and here).\nconst SIGN_OFF = /^let me know\\b/i;\n\n/** Split a sentence into clauses at punctuation and coordinators, so a trailing commitment is visible. */\nfunction clauses(sentence: string): string[] {\n return sentence\n .split(/[,;:]\\s*|\\s+(?:so|but|and|then|because|however|therefore|thus|although|though)\\s+/i)\n .map((c) => c.trim())\n .filter(Boolean);\n}\n\nexport function endsOnAnnouncedAction(text: string): boolean {\n const sentences = text.split(/(?<=[.!?])\\s+|\\n+/).map((s) => s.trim()).filter(Boolean);\n const last = sentences[sentences.length - 1];\n if (!last || NEXT_STEP.test(last) || SIGN_OFF.test(last)) return false;\n if (PROGRESSIVE.test(last)) return true;\n return clauses(last).some((c) => !NEXT_STEP.test(c) && !SIGN_OFF.test(c) && COMMITMENT.test(c));\n}\n\n/**\n * One incremental event from a streamed `chat({stream:true})` call — mirrors\n * ai.libx.js's `StreamChunk` (OpenAI-style): each chunk carries a `content`\n * text delta; the terminal chunk carries `finishReason` and the accumulated\n * `toolCalls`. Consuming the stream and folding the deltas reconstructs the\n * same `ChatResponse` the non-stream path returns.\n */\nexport interface StreamChunk {\n content: string;\n finishReason?: string;\n index?: number;\n toolCalls?: ToolCall[]; // accumulated tool calls (typically on the final chunk)\n reasoningContent?: string;\n /** Display-only tool activity from a self-executing backend (Cursor CLI) — surfaced as a host\n * `tool_activity` event, never dispatched. Mirrors ai.libx.js's StreamChunk.toolActivity. */\n toolActivity?: { id?: string; name: string; input?: unknown; output?: unknown; status: 'running' | 'completed' | 'error'; truncated?: { args?: boolean; result?: boolean } };\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number }; // on the terminal chunk, when the provider reports it\n}\n\nexport interface ChatOptions {\n model: string;\n messages: Message[];\n tools?: Tool[];\n toolChoice?: unknown;\n stream?: boolean;\n /** Cancel the request/stream. Forwarded to providers that honor it; the Agent also stops consuming on abort. */\n signal?: AbortSignal;\n [k: string]: unknown;\n}\n\n/** Minimal shape of an ai.libx.js AIClient that the Agent drives. */\nexport interface ChatLike {\n chat(options: ChatOptions): Promise<ChatResponse | AsyncIterable<StreamChunk>>;\n}\n","/**\n * Mask secret-looking values in arbitrary text before it reaches the model.\n *\n * Two complementary seams use this: real-shell output (`cat .env`, `printenv`) and the\n * `Read` tool (so provider keys stored in `.agent/settings.json` are usable-but-masked).\n * The FS jail hides whole secret FILES by name; this hides secret VALUES wherever they\n * surface in otherwise-legitimate content.\n *\n * Both regexes are linear (no nested quantifiers) — safe against catastrophic backtracking\n * and cheap enough to run on every tool output (see tests/redact.bench).\n */\n\nexport const REDACTED = '‹redacted›';\n\n/** Config/control files that may carry provider keys — readers (Read/Grep) mask secret VALUES in\n * these while keeping the rest readable. (Whole secret FILES like .env are hidden by the FS jail.) */\nexport const CONFIG_FILE_RE = /(^|\\/)\\.(agent|claude)\\/(settings(\\.[\\w-]+)?\\.json|config\\.(json|js|mjs|cjs|ts))$/i;\n\n// (A) `NAME=value` / `\"name\": \"value\"` pairs where NAME looks like a secret. Masks the value only,\n// so the agent still sees WHICH key exists (useful config context) without the secret itself.\nconst SECRET_PAIR =\n /((?:^|[\\s,{[])(?:export\\s+)?[\"']?[\\w.\\-]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|PRIVATE_KEY|ACCESS_?KEY|AUTH(?:_?TOKEN)?|BEARER)[\\w.\\-]*[\"']?\\s*[:=]\\s*)([\"']?)([^\\s\"',{}\\]]+)/gi;\n\n// (B) Bare tokens by well-known shape — catches secrets that appear without an obvious key\n// (Authorization headers, URLs, JSON dumps). Conservative prefixes to avoid false positives.\nconst SECRET_TOKEN =\n /\\b(sk-ant-[\\w-]{12,}|sk-[A-Za-z0-9]{20,}|ghp_[A-Za-z0-9]{20,}|gho_[A-Za-z0-9]{20,}|github_pat_[\\w]{20,}|xox[baprs]-[\\w-]{10,}|AKIA[0-9A-Z]{12,}|AIza[\\w-]{20,}|eyJ[\\w-]{8,}\\.[\\w-]{8,}\\.[\\w-]{8,})\\b/g;\n\n/** Return `text` with secret values masked. Cheap no-op when nothing matches. */\nexport function redactSecrets(text: string): string {\n if (!text) return text;\n return text\n .replace(SECRET_PAIR, (_m, head, quote, _val) => `${head}${quote}${REDACTED}`)\n .replace(SECRET_TOKEN, REDACTED);\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { AgentTool, ToolContext } from './tools';\nimport type { ChatResponse } from './llm';\nimport { redactSecrets, CONFIG_FILE_RE } from './redact';\n\n/**\n * Structured file tools — typed results straight from the VFS, no `bash` parsing.\n * These close the efficiency gap to Claude Code (its Grep/Glob/Write return one\n * structured result where our agent otherwise drives find/grep pipelines and re-reads).\n * Backend-agnostic: pure IFilesystem walks, so they run on Mem/Disk/IndexedDb alike.\n */\n\n/** Throw the moment a run is cancelled, so a long file walk/scan bails instead of pegging the CPU\n * uninterruptibly. dispatch() catches the throw → the run loop sees `aborted` and ends the turn. */\nfunction ckAbort(signal?: AbortSignal): void {\n if (signal?.aborted) throw new Error('aborted');\n}\n\n/**\n * Directory names never worth walking. Pruned by NAME at every level (not by path), because the\n * cost is where they nest: a real-FS root of a JS deployment is mostly `node_modules`, and on a\n * measured 412k-file app root a single `Glob` spent 31s almost entirely inside it.\n */\nexport const DEFAULT_SKIP_DIRS = ['node_modules', '.git', 'dist', '.tmp'];\n\n/** Depth below a root at which the walk stops. Deep enough for any real source tree; a bound at all\n * is what turns a symlink cycle from a hang into a truncated result. */\nexport const DEFAULT_MAX_DEPTH = 24;\n\n/** How the file-scanning tools (Glob/Grep) decide WHAT to walk. */\nexport interface FileScanOptions {\n /** Roots to walk when a call names no `path`. Default: `[fs.getCwd()]`, i.e. today's behaviour.\n * A host with its data outside the cwd passes both, so a search can reach it at all. */\n roots?: string[];\n /** Directory names pruned during the walk. Default: {@link DEFAULT_SKIP_DIRS}. */\n skipDirs?: string[];\n /** Max depth below each root. Default: {@link DEFAULT_MAX_DEPTH}. */\n maxDepth?: number;\n}\n\ninterface WalkState {\n skip: Set<string>;\n maxDepth: number;\n /** Real paths already visited — the cycle/duplication guard. A `vendor` symlink pointing back\n * into the tree (or `node_modules/.bin`) otherwise re-walks the same subtree repeatedly.\n * PER ROOT, not shared: with one shared set a second root that is a symlink to (or into) the\n * first is \"already seen\" and silently yields nothing — the caller asked for a place and got an\n * empty answer, which is the absent-vs-unreachable confusion this file is trying to kill. */\n seen: Set<string>;\n /** Directory names actually pruned, and depth cuts actually made — reported to the caller, never\n * swallowed: a walk that refused to look somewhere must say so, or `(no matches)` is a lie. */\n prunedDirs: Set<string>;\n depthCuts: number;\n}\n\n/** `canonicalPath` (symlinks resolved) is an optional capability on disk-backed filesystems; on\n * backends without it the VFS path IS the identity, so it is its own canonical form. Note it must\n * be the symlink-resolving one: `realPath` is path arithmetic and reports a link and its target as\n * two different places, which cannot break a cycle. */\nfunction realOf(fs: IFilesystem, p: string): string {\n const rp = (fs as { canonicalPath?: (path: string) => string }).canonicalPath;\n if (typeof rp !== 'function') return p;\n try { return rp.call(fs, p) || p; } catch { return p; }\n}\n\n/** Recursively list every file path under `dir` (VFS-absolute), depth-first, sorted. Cancellable:\n * a cancelled run throws between entries so a huge tree walk (real-FS disk mode) doesn't wedge.\n * Prunes {@link DEFAULT_SKIP_DIRS}, bounds depth, and never enters the same real dir twice. */\nasync function walkFiles(fs: IFilesystem, dir: string, signal?: AbortSignal, out: string[] = [], st?: WalkState, depth = 0): Promise<string[]> {\n const state: WalkState = st ?? { skip: new Set(DEFAULT_SKIP_DIRS), maxDepth: DEFAULT_MAX_DEPTH, seen: new Set(), prunedDirs: new Set(), depthCuts: 0 };\n if (depth > state.maxDepth) { state.depthCuts++; return out; }\n const real = realOf(fs, dir);\n if (state.seen.has(real)) return out;\n state.seen.add(real);\n let entries: string[];\n try { entries = await fs.readDir(dir); } catch { return out; }\n for (const name of entries.sort()) {\n ckAbort(signal);\n if (state.skip.has(name)) { state.prunedDirs.add(name); continue; }\n const p = dir === '/' ? `/${name}` : `${dir}/${name}`;\n if (await fs.isDirectory(p)) await walkFiles(fs, p, signal, out, state, depth + 1);\n else out.push(p);\n }\n return out;\n}\n\n/** The roots a call actually walks: an explicit `path` wins, else the configured roots, else the\n * cwd. Nested roots are collapsed — walking `/a` and `/a/b` would double-report everything in b. */\nfunction scanRoots(fs: IFilesystem, path: unknown, opts?: FileScanOptions): string[] {\n const asked = path == null ? [] : (Array.isArray(path) ? path : [path]).map((p) => String(p)).filter(Boolean);\n const roots = (asked.length ? asked : (opts?.roots?.length ? opts.roots : [fsCwd(fs)])).map((r) => (r.length > 1 && r.endsWith('/') ? r.slice(0, -1) : r));\n return [...new Set(roots)].filter((r, _i, all) => !all.some((other) => other !== r && r.startsWith(`${other}/`)));\n}\n\n/** What a walk refused to look at — appended to results so a pruned/truncated search never reads\n * as an exhaustive one. Mirrors Grep's existing \"skipped N unreadable files\" note. */\nfunction scanNote(states: WalkState[]): string {\n const pruned = [...new Set(states.flatMap((st) => [...st.prunedDirs]))].sort();\n const cuts = states.reduce((n, st) => n + st.depthCuts, 0);\n const parts: string[] = [];\n if (pruned.length) parts.push(`skipped ${pruned.join(', ')} (pass skipDirs to include them)`);\n if (cuts) parts.push(`stopped at depth ${states[0]?.maxDepth} in ${cuts} place${cuts === 1 ? '' : 's'} (pass maxDepth to go deeper)`);\n return parts.length ? `\\n[scan: ${parts.join('; ')}]` : '';\n}\n\n/** Walk every root once, with the configured prune/depth/cycle guards. Per-call `skipDirs`/`maxDepth`\n * override the construction-time ones, so a consumer of the default singletons is never stuck with\n * a prune it needs to see past (`Glob '**\\/dist/*'`, a `.tmp/` workspace). */\nasync function walkRoots(\n fs: IFilesystem, roots: string[], signal: AbortSignal | undefined, opts?: FileScanOptions, call?: FileScanOptions,\n): Promise<{ files: string[]; note: string }> {\n const skip = new Set(call?.skipDirs ?? opts?.skipDirs ?? DEFAULT_SKIP_DIRS);\n const maxDepth = call?.maxDepth ?? opts?.maxDepth ?? DEFAULT_MAX_DEPTH;\n const out: string[] = [];\n const states: WalkState[] = [];\n for (const root of roots) {\n // A fresh `seen` per root: cross-root dedupe belongs to the RESULT (callers Set-dedupe), not to\n // the walk, where it silently erases a whole root that aliases another.\n const state: WalkState = { skip, maxDepth, seen: new Set(), prunedDirs: new Set(), depthCuts: 0 };\n states.push(state);\n await walkFiles(fs, root, signal, out, state, 0);\n }\n return { files: out, note: scanNote(states) };\n}\n\n/** Per-call scan overrides, parsed from tool args. */\nfunction callScan(args: { skipDirs?: unknown; maxDepth?: unknown }): FileScanOptions {\n const sd = args.skipDirs;\n return {\n skipDirs: Array.isArray(sd) ? sd.map(String) : typeof sd === 'string' ? sd.split(',').map((x) => x.trim()).filter(Boolean) : undefined,\n maxDepth: args.maxDepth == null ? undefined : Number(args.maxDepth),\n };\n}\n\nconst SCAN_PARAMS = {\n path: { type: 'string', description: 'optional directory (or list) to search instead of the default roots; absolute VFS path' },\n skipDirs: { type: 'string', description: `comma-separated directory names to prune (default: ${DEFAULT_SKIP_DIRS.join(', ')}); pass an empty string to prune nothing` },\n maxDepth: { type: 'number', description: `max directory depth below each root (default ${DEFAULT_MAX_DEPTH})` },\n} as const;\n\n/** Anchor a relative glob at a specific root (an absolute pattern anchors to itself). Per-ROOT, not\n * per-cwd: with two roots, anchoring `**\\/*.md` at the cwd alone would silently match nothing in\n * the other one — the \"search can't reach it, so it reports absent\" failure this all exists for. */\nfunction anchoredGlobAt(root: string, glob: string): RegExp {\n if (glob.startsWith('/')) return globToRegExp(glob);\n return globToRegExp(`${root === '/' ? '' : root}/${glob}`);\n}\n\n/** A path/scope matcher over several roots: matches if the pattern matches when anchored at ANY. */\nfunction globMatcher(roots: string[], glob: string): (p: string) => boolean {\n const res = roots.map((r) => anchoredGlobAt(r, glob));\n return (p: string) => res.some((re) => re.test(p));\n}\n\n/**\n * Translate a glob (`**`, `*`, `?`) into an anchored RegExp over VFS-absolute paths.\n * `caseInsensitive` is used by the JailedFilesystem denylist so `/.ENV` can't slip past\n * a `.env` rule (file-matching tools keep the default case-sensitive behavior).\n */\nexport function globToRegExp(glob: string, caseInsensitive = false): RegExp {\n const g = glob.startsWith('/') ? glob : `/${glob}`;\n let re = '';\n for (let i = 0; i < g.length; i++) {\n const c = g[i];\n if (c === '*') {\n if (g[i + 1] === '*') { re += '.*'; i++; if (g[i + 1] === '/') i++; }\n else re += '[^/]*';\n } else if (c === '?') re += '[^/]';\n else re += c.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n }\n return new RegExp(`^${re}$`, caseInsensitive ? 'i' : '');\n}\n\n/** The dir structured tools walk/anchor at — the FS's working dir. Keeps Glob/Grep/RepoMap scoped\n * to the project (or, in CC-parity disk mode where root '/' is the real machine, the launch dir)\n * instead of crawling the whole filesystem. Backward-compatible: Mem/jailed-at-cwd backends report '/'. */\nconst fsCwd = (fs: IFilesystem): string => fs.getCwd();\n\n/** Compile a glob, resolving a relative pattern under the FS cwd (mirrors a shell's cwd-relative globs).\n * Absolute patterns are used as-is. With cwd '/' this is identical to the old `/`-anchored behavior. */\nfunction anchoredGlob(fs: IFilesystem, glob: string): RegExp {\n const cwd = fsCwd(fs);\n const base = cwd === '/' ? '' : cwd;\n return globToRegExp(glob.startsWith('/') ? glob : `${base}/${glob}`);\n}\n\n/** List paths matching a glob, sorted — the structured alternative to `find`. */\nexport function makeGlobTool(opts?: FileScanOptions): AgentTool {\n return {\n name: 'Glob',\n description:\n 'Find files by glob pattern (e.g. \"**/*.ts\", \"src/**/*.test.ts\"). Returns sorted paths, one per line. ' +\n 'Space-separated patterns combine; `!`-prefix excludes (e.g. \"**/*.ts !**/*.test.ts\"). Optional `path` to search a specific directory. Prefer over `bash find` for locating files — one call, structured output.',\n parameters: {\n type: 'object',\n required: ['pattern'],\n properties: {\n pattern: { type: 'string', description: 'glob pattern(s); ** matches across directories; prefix a pattern with ! to exclude' },\n ...SCAN_PARAMS,\n },\n },\n async run({ pattern, path, skipDirs, maxDepth }, ctx) {\n const roots = scanRoots(ctx.fs, path, opts);\n const pats = String(pattern ?? '').trim().split(/\\s+/).filter(Boolean);\n const include = pats.filter((p) => !p.startsWith('!')).map((p) => globMatcher(roots, p));\n const exclude = pats.filter((p) => p.startsWith('!')).map((p) => globMatcher(roots, p.slice(1)));\n const includes = include.length ? include : [globMatcher(roots, '**')]; // only-excludes → start from everything\n const { files, note } = await walkRoots(ctx.fs, roots, ctx.signal, opts, callScan({ skipDirs, maxDepth }));\n const hits = files.filter((p) => includes.some((m) => m(p)) && !exclude.some((m) => m(p)));\n return (hits.length ? [...new Set(hits)].sort().join('\\n') : '(no matches)') + note;\n },\n };\n}\n\n/** Search file contents by regex, returning typed `path:line:text` hits with optional context. */\nexport function makeGrepTool(opts?: FileScanOptions): AgentTool {\n return {\n name: 'Grep',\n description:\n 'Search file contents by regex. Returns `path:line: text` hits. Optional `glob` to scope files, `path` to search a specific directory, `context` for surrounding lines, `filesOnly` for matching paths only. Prefer over `bash grep` for file content search — structured results, no re-parse needed. Use `bash` instead for running commands, tests, or piped workflows.',\n parameters: {\n type: 'object',\n required: ['pattern'],\n properties: {\n pattern: { type: 'string', description: 'JS regular expression' },\n glob: { type: 'string', description: 'optional file glob to restrict the search' },\n ...SCAN_PARAMS,\n context: { type: 'number', description: 'lines of context before/after each hit' },\n filesOnly: { type: 'boolean', description: 'only list matching file paths' },\n },\n },\n async run({ pattern, glob, path, skipDirs, maxDepth, context, filesOnly }, ctx) {\n let re: RegExp;\n try { re = new RegExp(String(pattern ?? '')); } catch (e) { throw new Error(`invalid regex: ${String(e)}`); }\n const roots = scanRoots(ctx.fs, path, opts);\n const scope = glob ? globMatcher(roots, String(glob)) : null;\n const walked = await walkRoots(ctx.fs, roots, ctx.signal, opts, callScan({ skipDirs, maxDepth }));\n const files = [...new Set(walked.files)].sort().filter((p) => !scope || scope(p));\n const ctxN = Math.max(0, Number(context ?? 0));\n const out: string[] = [];\n const matched: string[] = [];\n let skipped = 0; // unreadable files (permissions, races) — surfaced, not silently dropped\n for (const path of files) {\n ckAbort(ctx.signal); // cancellable per-file: a wide grep over a big tree stops on Esc, not after\n let content: string;\n try { content = await ctx.fs.readFile(path); } catch { skipped++; continue; }\n const lines = content.split('\\n');\n const mask = CONFIG_FILE_RE.test(path); // mask secret values from config files in the hits\n let fileHit = false;\n for (let i = 0; i < lines.length; i++) {\n if (!re.test(lines[i])) continue;\n fileHit = true;\n if (filesOnly) break;\n const lo = Math.max(0, i - ctxN), hi = Math.min(lines.length - 1, i + ctxN);\n for (let j = lo; j <= hi; j++) out.push(`${path}:${j + 1}: ${mask ? redactSecrets(lines[j]) : lines[j]}`);\n }\n if (fileHit) matched.push(path);\n }\n const note = (skipped ? `\\n[skipped ${skipped} unreadable file${skipped === 1 ? '' : 's'}]` : '') + walked.note;\n if (filesOnly) return (matched.length ? matched.join('\\n') : '(no matches)') + note;\n return (out.length ? out.join('\\n') : '(no matches)') + note;\n },\n };\n}\n\n/** Default instances — cwd-rooted, standard prunes. Hosts that need other roots build their own. */\nexport const globTool: AgentTool = makeGlobTool();\nexport const grepTool: AgentTool = makeGrepTool();\n\n/** A line is a top-level declaration worth showing in the repo map. */\nconst SIG_RE = /^\\s*(export\\b|(?:export\\s+)?(?:async\\s+)?function\\s+\\*?\\w|(?:export\\s+)?(?:abstract\\s+)?class\\s+\\w|(?:export\\s+)?interface\\s+\\w|(?:export\\s+)?type\\s+\\w|(?:export\\s+)?enum\\s+\\w)/;\nconst isCode = (p: string) => /\\.(ts|tsx|js|jsx|mjs|cjs)$/.test(p);\nconst isDoc = (p: string) => /\\.(md|mdx|txt)$/.test(p);\n\n/** Extract heading hierarchy + first-paragraph summaries from a markdown file. */\nfunction docOutlineOf(content: string, cap = 20): string[] {\n const out: string[] = [];\n const lines = content.split('\\n');\n for (let i = 0; i < lines.length && out.length < cap; i++) {\n const hm = lines[i].match(/^(#{1,4})\\s+(.+)/);\n if (hm) {\n out.push(hm[0].slice(0, 120));\n for (let j = i + 1; j < lines.length; j++) {\n const l = lines[j].trim();\n if (!l) continue;\n if (l.startsWith('#')) break;\n out.push(' ' + l.slice(0, 120));\n break;\n }\n }\n }\n return out;\n}\n\n/** One file's exported/top-level signatures (no bodies), capped. */\nfunction signaturesOf(content: string, cap = 40): string[] {\n const out: string[] = [];\n for (const line of content.split('\\n')) {\n if (!SIG_RE.test(line)) continue;\n let sig = line.trim();\n const brace = sig.indexOf('{');\n if (brace > 0) sig = sig.slice(0, brace).trim(); // drop the body\n sig = sig.replace(/\\s*=>?\\s*$/, '').replace(/=\\s*$/, '').slice(0, 120);\n if (sig && !out.includes(sig)) out.push(sig);\n if (out.length >= cap) break;\n }\n return out;\n}\n\n/**\n * Compact map of a VFS — code signatures and/or doc outlines. Edge-safe (pure IFilesystem walk).\n * `mode`: \"code\" (default) = top-level signatures; \"docs\" = heading outlines; \"all\" = both.\n */\nexport async function repoIndex(fs: IFilesystem, glob?: string, mode: 'code' | 'docs' | 'all' = 'code', signal?: AbortSignal): Promise<string> {\n const scope = glob ? anchoredGlob(fs, String(glob)) : null;\n const filter = mode === 'code' ? isCode : mode === 'docs' ? isDoc : (p: string) => isCode(p) || isDoc(p);\n const files = (await walkFiles(fs, fsCwd(fs), signal)).filter((p) => (scope ? scope.test(p) : filter(p)));\n const blocks: string[] = [];\n let shown = 0;\n for (const path of files) {\n ckAbort(signal);\n let content: string;\n try { content = await fs.readFile(path); } catch { continue; }\n const entries = isDoc(path) ? docOutlineOf(content) : signaturesOf(content);\n if (entries.length) { blocks.push(`${path}\\n${entries.map((s) => ' ' + s).join('\\n')}`); shown += entries.length; }\n if (shown >= 400) { blocks.push('… (map truncated; narrow with `glob`)'); break; }\n }\n const label = mode === 'code' ? 'code signatures' : mode === 'docs' ? 'document outlines' : 'entries';\n return blocks.length ? blocks.join('\\n') : `(no ${label} found)`;\n}\n\n/** Compact map of the codebase or document workspace — orient in ONE call, not many. */\nexport const repoMapTool: AgentTool = {\n name: 'RepoMap',\n description:\n 'Get a compact map of the workspace: code signatures and/or document outlines in ONE call. `scope`: \"code\" (default) = functions/classes/types; \"docs\" = markdown headings + summaries; \"all\" = both. Call once to orient before diving into specific files — avoids many exploratory Glob/Read calls.',\n parameters: {\n type: 'object',\n properties: {\n glob: { type: 'string', description: 'optional file glob to scope (default: all matching files)' },\n scope: { type: 'string', enum: ['code', 'docs', 'all'], description: 'what to map: \"code\" (default), \"docs\", or \"all\"' },\n },\n },\n run: ({ glob, scope }, ctx) => repoIndex(ctx.fs, glob, scope || 'code', ctx.signal),\n};\n\n/**\n * Whitespace-tolerant fallback for Edit: locate `oldStr` in `content` ignoring each line's\n * leading/trailing whitespace, and replace the UNIQUE matching region with `newStr`. Returns\n * null if there isn't exactly one match (caller then errors, forcing a re-read) — so it never\n * guesses. This kills the common re-Read+retry cascade when an exact Edit fails on indentation drift.\n */\nexport function fuzzyLineReplace(content: string, oldStr: string, newStr: string): string | null {\n const norm = (s: string) => s.trim();\n const cl = content.split('\\n');\n const ol = oldStr.split('\\n').map(norm);\n while (ol.length && ol[ol.length - 1] === '') ol.pop();\n while (ol.length && ol[0] === '') ol.shift();\n if (!ol.length) return null;\n const matches: number[] = [];\n for (let i = 0; i + ol.length <= cl.length; i++) {\n let ok = true;\n for (let j = 0; j < ol.length; j++) if (norm(cl[i + j]) !== ol[j]) { ok = false; break; }\n if (ok) matches.push(i);\n }\n if (matches.length !== 1) return null; // not found, or ambiguous → don't guess\n const i = matches[0];\n return [...cl.slice(0, i), ...newStr.split('\\n'), ...cl.slice(i + ol.length)].join('\\n');\n}\n\n/** Read-before-overwrite guard, shared by Write and ApplyEdits' whole-file branch: blindly replacing\n * an existing file the agent never Read destroys its unseen content (the taskify-board incident).\n * `key` is the resolved path (the readState key); a fresh Write arms readState, so re-writing your own\n * output passes. Returns true when the write would clobber un-Read content and should be refused. */\nasync function wouldClobberUnread(ctx: ToolContext, path: string, key: string): Promise<boolean> {\n return !ctx.readState.has(key) && (await ctx.fs.exists(path));\n}\n\n/** Create or overwrite a file, creating parent directories as needed (mkdir -p). */\nexport const writeTool: AgentTool = {\n name: 'Write',\n description:\n 'Create or overwrite a file with the given contents, creating parent directories as needed. Use for new files instead of `bash echo >`. To replace an EXISTING file you must Read it first — overwriting an un-Read file is refused (it would destroy unseen content).',\n parameters: {\n type: 'object',\n required: ['path', 'content'],\n properties: { path: { type: 'string' }, content: { type: 'string' } },\n },\n async run({ path, content }, ctx) {\n const body = String(content ?? '');\n const key = ctx.fs.resolvePath(path);\n if (await wouldClobberUnread(ctx, path, key))\n throw new Error(`Refusing to overwrite ${path}: it exists and hasn't been Read. Read it first, then Write to replace it (or Edit to change part of it).`);\n if (ctx.lint) { const err = ctx.lint(path, body); if (err) throw new Error(err); }\n await mkdirp(ctx.fs, parentDir(key));\n await ctx.fs.writeFile(path, body);\n ctx.readState.set(key, body); // arm Edit on a freshly written file\n return `Wrote ${path}`;\n },\n};\n\n/** Apply an ordered list of exact-substring edits to one file in a single call. */\nexport const multiEditTool: AgentTool = {\n name: 'MultiEdit',\n description:\n 'Apply several exact-substring replacements to one file in order, in a single call. Requires a prior Read. Each `old_string` must be unique at the time it is applied. All-or-nothing: if any edit fails, none are written.',\n parameters: {\n type: 'object',\n required: ['path', 'edits'],\n properties: {\n path: { type: 'string' },\n edits: {\n type: 'array',\n items: {\n type: 'object',\n required: ['old_string', 'new_string'],\n properties: { old_string: { type: 'string' }, new_string: { type: 'string' } },\n },\n },\n },\n },\n async run({ path, edits }, ctx) {\n const key = ctx.fs.resolvePath(path);\n const snapshot = ctx.readState.get(key);\n if (snapshot == null) throw new Error(`File has not been read yet: ${path}. Read it before editing.`);\n let current = await ctx.fs.readFile(path);\n if (current !== snapshot) throw new Error(`File ${path} changed since it was read (stale). Re-read before editing.`);\n const list = Array.isArray(edits) ? edits : [];\n if (!list.length) throw new Error('edits must be a non-empty array');\n for (const [i, e] of list.entries()) {\n const count = e.old_string === '' ? 0 : current.split(e.old_string).length - 1;\n if (count === 0) throw new Error(`edit ${i}: old_string not found in ${path}.`);\n if (count > 1) throw new Error(`edit ${i}: old_string is not unique in ${path} (${count} matches).`);\n current = current.replace(e.old_string, () => e.new_string);\n }\n if (ctx.lint) { const err = ctx.lint(path, current); if (err) throw new Error(err); }\n await ctx.fs.writeFile(path, current);\n ctx.readState.set(key, current);\n return `Applied ${list.length} edit(s) to ${path}`;\n },\n};\n\n/**\n * Cross-file batch edit — the multi-file refactor primitive. One call edits MANY files:\n * each entry with an `old_string` replaces that exact, UNIQUE substring (read fresh + verified,\n * so NO prior Read is needed — locate the sites with Grep, whose output is the text to match);\n * each entry WITHOUT `old_string` writes `new_string` as the whole file (creates it + parent dirs).\n * Validate-all-before-write → atomic across files. Collapses \"Grep + N×(Read+Edit)\" into \"Grep + ApplyEdits\".\n */\nexport const applyEditsTool: AgentTool = {\n name: 'ApplyEdits',\n description:\n 'Apply edits across one or MORE files in a single call — for cross-file refactors (rename/extract/move). edits=[{path, old_string?, new_string}]. WITH old_string: replace that exact substring (must be UNIQUE in the file — add surrounding context; read fresh + verified, no prior Read needed). WITHOUT old_string: write new_string as the whole file (creates it + parent dirs; but to OVERWRITE a file that already exists you must Read it first, else use old_string to edit part of it). Locate sites first with Grep (its output shows the exact text). Atomic: validated across all files before any write.',\n parameters: {\n type: 'object',\n required: ['edits'],\n properties: {\n edits: {\n type: 'array',\n items: {\n type: 'object',\n required: ['path', 'new_string'],\n properties: { path: { type: 'string' }, old_string: { type: 'string' }, new_string: { type: 'string' } },\n },\n },\n },\n },\n async run({ edits }, ctx) {\n const list = Array.isArray(edits) ? edits : [];\n if (!list.length) throw new Error('edits must be a non-empty array of {path, old_string?, new_string}');\n const planned = new Map<string, string>(); // resolved path -> final content (validate ALL before writing → atomic)\n for (const [i, e] of list.entries()) {\n const p = ctx.fs.resolvePath(String(e.path));\n const old = e.old_string == null ? '' : String(e.old_string);\n const neu = String(e.new_string ?? '');\n if (old === '') { // whole-file write / create\n // Same read-before-overwrite guard as Write (skip if an earlier edit in THIS batch already staged p).\n if (!planned.has(p) && (await wouldClobberUnread(ctx, String(e.path), p)))\n throw new Error(`edit ${i}: refusing to overwrite ${e.path} with a whole-file write — it exists and hasn't been Read. Read it first, or pass old_string to edit part of it.`);\n planned.set(p, neu); continue;\n }\n let cur = planned.has(p) ? planned.get(p)! : await ctx.fs.readFile(p).catch(() => { throw new Error(`edit ${i}: file not found: ${e.path}`); });\n const count = cur.split(old).length - 1;\n if (count > 1) throw new Error(`edit ${i}: old_string is not unique in ${e.path} (${count} matches) — add more context`);\n if (count === 1) cur = cur.replace(old, () => neu);\n else {\n const fz = fuzzyLineReplace(cur, old, neu);\n if (fz == null) throw new Error(`edit ${i}: old_string not found in ${e.path}`);\n cur = fz;\n }\n planned.set(p, cur);\n }\n if (ctx.lint) for (const [p, content] of planned) { const err = ctx.lint(p, content); if (err) throw new Error(err); } // validate ALL before any write\n for (const [p, content] of planned) { await mkdirp(ctx.fs, parentDir(p)); await ctx.fs.writeFile(p, content); ctx.readState.set(p, content); }\n return `Applied ${list.length} edit(s) across ${planned.size} file(s): ${[...planned.keys()].join(', ')}`;\n },\n};\n\nfunction parentDir(abs: string): string {\n const i = abs.lastIndexOf('/');\n return i <= 0 ? '/' : abs.slice(0, i);\n}\n\n/** mkdir -p over the VFS (idempotent, top-down). */\nexport async function mkdirp(fs: IFilesystem, dir: string): Promise<void> {\n if (dir === '/' || (await fs.exists(dir))) return;\n await mkdirp(fs, parentDir(dir));\n if (!(await fs.exists(dir))) await fs.createDir(dir);\n}\n\n/**\n * Review — verification WITHOUT execution: a fresh-context, adversarial critic pass over the\n * changes the agent just made. Verification-as-review (stolen from the review-fix-commit skill):\n * for an agent with no test runner, \"re-read to be sure\" is weak, but a COLD reviewer that reads\n * only {task + the produced files} (not the author's chain-of-thought) catches missed edge cases,\n * unstated implications, and subtle logic bugs a happy-path one-shot misses. Costs one model call.\n *\n * The `notes` arg is the with/without-CONTEXT knob: omit it for a pure cold review (the default,\n * least biased); pass it to feed the reviewer extra context. We don't decide which is better —\n * the self-evolution loop discovers it via its prompt rules.\n *\n * Degrades to a no-op notice if no model handle is wired (ctx.ai/ctx.model).\n */\nexport function reviewTool(): AgentTool {\n return {\n name: 'Review',\n description:\n 'Critically review your changes before finishing (verification without running code). Pass the task and the paths you changed; a fresh-context senior reviewer reads them COLD and returns concrete issues or \"LGTM\". Fix what it raises, then finish. Optional `notes` feeds the reviewer extra context.',\n parameters: {\n type: 'object',\n required: ['task', 'paths'],\n properties: {\n task: { type: 'string', description: 'what was asked — the spec/requirements to check the changes against' },\n paths: { type: 'array', items: { type: 'string' }, description: 'the files you changed/created, to be reviewed' },\n notes: { type: 'string', description: 'OPTIONAL extra context for the reviewer (rationale, constraints). Omit for a pure cold review.' },\n },\n },\n async run({ task, paths, notes }, ctx: ToolContext) {\n if (!ctx.ai || !ctx.model) return '[Review] no model handle wired — skipped.';\n const list: string[] = Array.isArray(paths) ? paths.map(String) : [];\n if (!list.length) return 'Error: pass the paths you changed in `paths`.';\n const files: string[] = [];\n for (const p of list.slice(0, 12)) {\n try {\n const body = await ctx.fs.readFile(p);\n files.push(`--- ${p} ---\\n${body.length > 4000 ? body.slice(0, 4000) + '\\n…(truncated)' : body}`);\n } catch {\n files.push(`--- ${p} ---\\n[could not read]`);\n }\n }\n const prompt =\n 'You are a senior engineer doing a critical code review. Review the changes below AGAINST THE TASK with deep, skeptical thinking — default to finding problems.\\n' +\n 'Focus on: correctness, edge cases (empty/boundary/negative inputs), unstated-but-implied requirements, and subtle logic bugs. Do NOT comment on style.\\n\\n' +\n `TASK:\\n${String(task ?? '').trim()}\\n\\n` +\n (notes ? `CONTEXT FROM THE AUTHOR:\\n${String(notes).trim()}\\n\\n` : '') +\n `CHANGED FILES:\\n${files.join('\\n\\n')}\\n\\n` +\n 'Reply with a short numbered list of concrete, actionable issues. If the changes correctly and completely satisfy the task with no edge cases missed, reply with exactly: LGTM';\n try {\n const r = (await ctx.ai.chat({ model: ctx.model, messages: [{ role: 'user', content: prompt }], stream: false })) as ChatResponse;\n const text = (r?.content ?? '').trim();\n return text || 'LGTM';\n } catch (e: any) {\n return `[Review] model error: ${e?.message ?? e} — skipped.`;\n }\n },\n };\n}\n","import type { AgentTool, ToolContext } from './tools';\n\n/** A single planning item. `in_progress` should mark exactly the one task currently being worked on. */\nexport interface TodoItem {\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n}\n\nconst MARK: Record<TodoItem['status'], string> = {\n pending: '[ ]',\n in_progress: '[~]',\n completed: '[x]',\n};\n\n/** Render a todo list as a stable checklist (one item per line). */\nfunction renderTodos(todos: TodoItem[]): string {\n if (todos.length === 0) return 'Todo list cleared (no items).';\n return todos.map((t) => `${MARK[t.status]} ${t.content}`).join('\\n');\n}\n\n/**\n * `TodoWrite` tool — the agent's planning scratchpad for multi-step tasks.\n * Use to lay out steps up front and keep them current (mark one `in_progress`,\n * flip finished ones to `completed`). Each call REPLACES the whole list.\n */\nexport const todoWriteTool: AgentTool = {\n name: 'TodoWrite',\n description:\n 'Maintain a todo list to plan and track a multi-step task. Replaces the current list with the provided todos and returns the rendered checklist. Mark exactly one item in_progress at a time; flip items to completed as you finish them.',\n parameters: {\n type: 'object',\n required: ['todos'],\n properties: {\n todos: {\n type: 'array',\n items: {\n type: 'object',\n required: ['content', 'status'],\n properties: {\n content: { type: 'string', description: 'the step to do' },\n status: { type: 'string', enum: ['pending', 'in_progress', 'completed'] },\n },\n },\n },\n },\n },\n async run({ todos }, ctx: ToolContext) {\n if (!Array.isArray(todos)) throw new Error('todos must be an array of { content, status } items.');\n const next: TodoItem[] = todos.map((t: any, i: number) => {\n const content = String(t?.content ?? '').trim();\n if (!content) throw new Error(`todos[${i}].content is required.`);\n const status = t?.status;\n if (status !== 'pending' && status !== 'in_progress' && status !== 'completed') {\n throw new Error(`todos[${i}].status must be one of pending|in_progress|completed (got ${JSON.stringify(status)}).`);\n }\n return { content, status };\n });\n ctx.todos = next; // replace the list in place on the shared context\n return renderTodos(next);\n },\n};\n","import type { AgentTool } from './tools';\nimport { forComponent } from './logging';\n\n/**\n * Web tools — `WebFetch` (retrieve a URL as readable text) and `WebSearch` (ranked\n * results via a configured provider). Opt-in (NOT in the default tool set): network\n * access is a deliberate capability. Factory-built with an injectable `fetch` so they\n * stay edge-portable and unit-testable without real network. `fetch` is read at call\n * time, so a no-network runtime simply has the tool return an error.\n */\nconst log = forComponent('web');\n\n/** Strip HTML to readable text — dependency-free: drop script/style/comments, block tags → newlines, decode common entities. */\nexport function htmlToText(html: string): string {\n let s = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<title[\\s\\S]*?<\\/title>/gi, ' ') // drop title text (don't leak it into context)\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, ' ') // …same for noscript / textarea content\n .replace(/<textarea[\\s\\S]*?<\\/textarea>/gi, ' ')\n .replace(/<!--[\\s\\S]*?-->/g, ' ')\n .replace(/<\\/(p|div|li|h[1-6]|tr|section|article|header|footer|nav)>/gi, '\\n')\n .replace(/<br\\s*\\/?>/gi, '\\n')\n .replace(/<[^>]+>/g, ' ');\n s = s\n .replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&').replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>').replace(/&quot;/g, '\"').replace(/&#0?39;/g, \"'\").replace(/&#x27;/gi, \"'\");\n return s\n .replace(/[ \\t\\f\\v]+/g, ' ')\n .split('\\n').map((l) => l.trim()).join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n}\n\nexport interface WebFetchOptions {\n /** Override the global fetch (tests inject a mock; edge runtimes can supply their own). */\n fetch?: typeof globalThis.fetch;\n maxBytes?: number; // cap the downloaded body (default 2 MB)\n maxChars?: number; // cap the returned text (default 100k)\n timeoutMs?: number; // request timeout (default 15s)\n /** Allow fetching private/loopback/link-local hosts (default false — blocks basic SSRF). */\n allowPrivateHosts?: boolean;\n}\n\n/**\n * Block obvious SSRF targets by hostname/IP literal (loopback, private ranges, link-local incl.\n * cloud metadata 169.254.169.254, `.internal`). Pure/edge-safe — no DNS, so DNS-rebinding and\n * redirect-to-internal are NOT covered (an embedder needing that should supply a vetting `fetch`).\n */\nexport function isPrivateHost(host: string): boolean {\n const h = host.toLowerCase().replace(/^\\[|\\]$/g, ''); // strip IPv6 brackets\n if (h === '' || h === 'localhost' || h.endsWith('.localhost') || h.endsWith('.internal')) return true;\n if (h === '::1' || h === '::' || h.startsWith('fe80:') || h.startsWith('fc') || h.startsWith('fd')) return true; // IPv6 loopback/link-local/ULA\n const m = h.match(/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/);\n if (m) {\n const a = +m[1], b = +m[2];\n return a === 0 || a === 127 || a === 10 || (a === 169 && b === 254) || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168) || (a === 100 && b >= 64 && b <= 127);\n }\n return false;\n}\n\n/** Lazily-loaded node DNS resolver (absent on edge/browser) — closes DNS-rebinding (a public\n * hostname resolving to an internal IP) on the real-network path. Resolves null where unavailable. */\nlet _dnsLookup: ((h: string, opts?: any) => Promise<{ address: string }[]>) | null | undefined;\nasync function resolveIps(host: string): Promise<string[] | null> {\n if (_dnsLookup === undefined) {\n try { _dnsLookup = (await import('node:dns/promises')).lookup as any; }\n catch { _dnsLookup = null; } // edge/browser: no DNS — rely on the literal isPrivateHost check\n }\n if (!_dnsLookup) return null;\n try { return (await _dnsLookup(host, { all: true } as any)).map((a) => a.address); } catch { return null; }\n}\n\n/** Read a response body but stop at `maxBytes` of ACTUAL bytes (cancel the stream) — no unbounded download. */\nasync function readCapped(res: Response, maxBytes: number): Promise<string> {\n const reader = (res.body as any)?.getReader?.();\n if (!reader) { const t = await res.text(); return t.length > maxBytes ? t.slice(0, maxBytes) : t; }\n const chunks: Uint8Array[] = [];\n let total = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) { chunks.push(value); total += value.length; }\n if (total >= maxBytes) { try { await reader.cancel(); } catch { /* already closed */ } break; }\n }\n const out = new Uint8Array(Math.min(total, maxBytes));\n let off = 0;\n for (const c of chunks) { if (off >= out.length) break; const take = Math.min(c.length, out.length - off); out.set(c.subarray(0, take), off); off += take; }\n return new TextDecoder().decode(out);\n}\n\n/** Build a WebFetch tool. */\nexport function makeWebFetchTool(options: WebFetchOptions = {}): AgentTool {\n const maxBytes = options.maxBytes ?? 2_000_000;\n const maxChars = options.maxChars ?? 100_000;\n const timeoutMs = options.timeoutMs ?? 15_000;\n return {\n name: 'WebFetch',\n description:\n 'Fetch an http/https URL and return its readable text (HTML is stripped to text). Use to read docs or web pages. Returns the status line then up to ~100k chars of content.',\n // Declared so a transport above the loop sizes its deadline around this one (see AgentTool.maxDurationMs).\n maxDurationMs: timeoutMs,\n parameters: { type: 'object', required: ['url'], properties: { url: { type: 'string', description: 'absolute http(s) URL' } } },\n async run({ url }) {\n const doFetch = options.fetch ?? globalThis.fetch;\n const customFetch = !!options.fetch; // injected fetch (tests/edge) owns its own vetting → skip DNS\n const u = String(url ?? '');\n try { new URL(u); } catch { return `Error: invalid URL: ${u}`; }\n if (!doFetch) return 'Error: no network (fetch) available in this runtime';\n // Reject a host that's a private/internal IP literal, or (on the real-network path) a name that\n // RESOLVES to one — re-checked on EVERY redirect hop so an external page can't bounce us internal.\n const hostBlock = async (hostname: string): Promise<string | null> => {\n if (options.allowPrivateHosts) return null;\n if (isPrivateHost(hostname)) return hostname;\n if (!customFetch) { const ips = await resolveIps(hostname); if (ips) for (const ip of ips) if (isPrivateHost(ip)) return `${hostname} → ${ip}`; }\n return null;\n };\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), timeoutMs);\n try {\n let current = u;\n let res: Response;\n for (let hop = 0; ; hop++) {\n const pu = new URL(current);\n if (pu.protocol !== 'http:' && pu.protocol !== 'https:') return `Error: only http/https URLs are allowed (got \"${pu.protocol}\")`;\n const blocked = await hostBlock(pu.hostname);\n if (blocked) return `Error: refusing to fetch a private/internal address (${blocked}) — set allowPrivateHosts to override`;\n res = await doFetch(current, { signal: ctl.signal, redirect: 'manual', headers: { 'user-agent': 'agentx (+https://github.com/Livshitz/agentx)' } });\n if (res.status >= 300 && res.status < 400 && res.headers.get('location')) {\n if (hop >= 5) return `Error fetching ${u}: too many redirects`;\n current = new URL(res.headers.get('location')!, current).toString(); // re-validated at loop top\n continue;\n }\n break;\n }\n const type = res.headers.get('content-type') ?? '';\n const body = await readCapped(res, maxBytes);\n const text = /html/i.test(type) || /^\\s*<(?:!doctype|html)/i.test(body) ? htmlToText(body) : body.trim();\n const capped = text.length > maxChars ? text.slice(0, maxChars) + `\\n… [truncated at ${maxChars} chars]` : text;\n return `${res.status} ${res.statusText} · ${new URL(current).host}\\n\\n${capped}`;\n } catch (e: any) {\n log.debug(`WebFetch ${u} failed`, e);\n return `Error fetching ${u}: ${e?.name === 'AbortError' ? `timed out after ${timeoutMs}ms` : (e?.message ?? e)}`;\n } finally {\n clearTimeout(timer);\n }\n },\n };\n}\n\nexport interface WebSearchOptions {\n fetch?: typeof globalThis.fetch;\n /** Provider: 'auto' (default) prefers Firecrawl, then Tavily (by key presence), else keyless DuckDuckGo.\n * 'anthropic' delegates to a cheap model with Anthropic's native server-side web_search. */\n provider?: 'auto' | 'tavily' | 'duckduckgo' | 'anthropic' | 'firecrawl';\n /** API key for Tavily (default: process.env.TAVILY_API_KEY). */\n apiKey?: string;\n /** Tavily endpoint override. */\n endpoint?: string;\n /** API key for Firecrawl (default: process.env.FIRECRAWL_API_KEY). */\n firecrawlApiKey?: string;\n /** Firecrawl search endpoint override. */\n firecrawlEndpoint?: string;\n maxResults?: number; // default 5\n timeoutMs?: number; // default 15s\n /** Tool name (default 'WebSearch'). Set to register a provider-pinned variant, e.g. 'WebSearchAnthropic'. */\n name?: string;\n /** Tool description override (default: the generic ranked-results blurb). */\n description?: string;\n /** Anthropic key for provider 'anthropic' (default: process.env.ANTHROPIC_API_KEY). */\n anthropicApiKey?: string;\n /** Model for provider 'anthropic' (default 'claude-haiku-4-5'). */\n model?: string;\n}\n\ninterface SearchHit { title: string; url: string; snippet: string }\n\n/** Decode a DuckDuckGo HTML result href: results are `//duckduckgo.com/l/?uddg=<encoded-target>` redirects. */\nexport function decodeDdgUrl(href: string): string {\n const m = href.match(/[?&]uddg=([^&]+)/);\n if (m) { try { return decodeURIComponent(m[1]); } catch { /* fall through */ } }\n return href.startsWith('//') ? 'https:' + href : href;\n}\n\n/** Parse DuckDuckGo's HTML results page into hits (title/url/snippet) — dependency-free, zips anchors to snippets in order. */\nexport function parseDdgHtml(html: string, max: number): SearchHit[] {\n const anchors = [...html.matchAll(/<a[^>]*class=\"[^\"]*result__a[^\"]*\"[^>]*href=\"([^\"]+)\"[^>]*>([\\s\\S]*?)<\\/a>/g)];\n const snippets = [...html.matchAll(/<a[^>]*class=\"[^\"]*result__snippet[^\"]*\"[^>]*>([\\s\\S]*?)<\\/a>/g)].map((m) => htmlToText(m[1]));\n const hits: SearchHit[] = [];\n for (let i = 0; i < anchors.length && hits.length < max; i++) {\n const url = decodeDdgUrl(anchors[i][1]);\n try { if (isPrivateHost(new URL(url).hostname)) continue; } catch { continue; } // skip junk/internal redirects\n hits.push({ title: htmlToText(anchors[i][2]) || '(untitled)', url, snippet: snippets[i] ?? '' });\n }\n return hits;\n}\n\nfunction formatHits(hits: SearchHit[]): string {\n if (!hits.length) return '(no results)';\n return hits.map((r, i) => `${i + 1}. ${r.title}\\n ${r.url}\\n ${r.snippet.replace(/\\s+/g, ' ').slice(0, 240)}`).join('\\n\\n');\n}\n\n/** Provider 'firecrawl': agent-oriented search API (POST /v1/search, Bearer auth). Maps Firecrawl's\n * result objects into the same hit shape as Tavily/DDG. HTTP-only, no SDK. */\nasync function firecrawlSearch(q: string, opts: { key: string; endpoint: string; maxResults: number; fetch: typeof globalThis.fetch; signal: AbortSignal }): Promise<string> {\n const res = await opts.fetch(opts.endpoint, {\n method: 'POST',\n signal: opts.signal,\n headers: { authorization: `Bearer ${opts.key}`, 'content-type': 'application/json' },\n body: JSON.stringify({ query: q, limit: opts.maxResults }),\n });\n if (!res.ok) return `Error: Firecrawl search returned ${res.status} ${res.statusText}`;\n const data: any = await res.json();\n const results = Array.isArray(data?.data) ? data.data.slice(0, opts.maxResults) : [];\n return formatHits(results.map((r: any) => ({ title: r.title ?? '(untitled)', url: r.url ?? '', snippet: String(r.description ?? r.markdown ?? '') })));\n}\n\n/**\n * Provider 'anthropic': delegate the search to a cheap model running Anthropic's native server-side\n * web_search tool. Anthropic runs the search and reads the results; we prompt for un-editorialized\n * findings (one claim per line, each with its source URL) and relay them verbatim. Raw HTTP — no SDK,\n * stays edge-portable. Slower and costlier than DDG/Tavily, but better-sourced (native search index).\n */\nasync function anthropicSearch(q: string, opts: { key: string; model: string; fetch: typeof globalThis.fetch; signal: AbortSignal }): Promise<string> {\n const res = await opts.fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n signal: opts.signal,\n headers: { 'x-api-key': opts.key, 'anthropic-version': '2023-06-01', 'content-type': 'application/json' },\n body: JSON.stringify({\n model: opts.model,\n max_tokens: 1024,\n // Basic variant: Haiku-tier doesn't support the _20260209 dynamic-filtering variant (Opus 4.6+/Sonnet 4.6 only).\n tools: [{ type: 'web_search_20250305', name: 'web_search', max_uses: 5 }],\n messages: [{ role: 'user', content:\n `Search the web for: ${q}\\n\\nReturn only the relevant findings as concise bullet points, each with its source URL in parentheses. ` +\n `Do not add a preamble, conclusion, opinion, or commentary. If sources conflict, list each claim with its source rather than resolving it.` }],\n }),\n });\n if (!res.ok) return `Error: Anthropic search returned ${res.status} ${res.statusText}`;\n const data: any = await res.json();\n if (data?.stop_reason === 'refusal') return 'Error: Anthropic search refused the query';\n let text = '';\n for (const block of data?.content ?? []) if (block?.type === 'text') text += block.text;\n return text.trim() || '(no results)';\n}\n\n/**\n * Build a WebSearch tool. Keyless by default (DuckDuckGo HTML) so it works in any deployment with no\n * setup; on provider 'auto' it upgrades to an agent-oriented API by key presence — Firecrawl\n * (FIRECRAWL_API_KEY) preferred, then Tavily (TAVILY_API_KEY). Provider 'anthropic' is a separate path\n * (native search via a cheap model) exposed as the WebSearchAnthropic tool.\n */\nexport function makeWebSearchTool(options: WebSearchOptions = {}): AgentTool {\n const tavilyEndpoint = options.endpoint ?? 'https://api.tavily.com/search';\n const firecrawlEndpoint = options.firecrawlEndpoint ?? 'https://api.firecrawl.dev/v1/search';\n const maxResults = options.maxResults ?? 5;\n const timeoutMs = options.timeoutMs ?? 15_000;\n return {\n name: options.name ?? 'WebSearch',\n description: options.description ??\n 'Search the web by query; returns ranked results (title, URL, snippet). Use to look things up, find pages, or research a topic — then WebFetch a result URL to read it in full.',\n parameters: { type: 'object', required: ['query'], properties: { query: { type: 'string' } } },\n async run({ query }) {\n const doFetch = options.fetch ?? globalThis.fetch;\n if (!doFetch) return 'Error: no network (fetch) available in this runtime';\n const q = String(query ?? '').trim();\n if (!q) return 'Error: empty query';\n const key = options.apiKey ?? process.env.TAVILY_API_KEY;\n const fcKey = options.firecrawlApiKey ?? process.env.FIRECRAWL_API_KEY;\n const provider = options.provider ?? 'auto';\n // auto priority ladder: Firecrawl > Tavily > keyless DuckDuckGo (by key presence).\n const useFirecrawl = provider === 'firecrawl' || (provider === 'auto' && !!fcKey);\n const useTavily = provider === 'tavily' || (provider === 'auto' && !useFirecrawl && !!key);\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), timeoutMs);\n try {\n if (provider === 'anthropic') {\n const akey = options.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY;\n if (!akey) return 'Error: WebSearchAnthropic requires ANTHROPIC_API_KEY (set in env)';\n return await anthropicSearch(q, { key: akey, model: options.model ?? 'claude-haiku-4-5', fetch: doFetch, signal: ctl.signal });\n }\n if (useFirecrawl) {\n if (!fcKey) return 'Error: Firecrawl provider selected but FIRECRAWL_API_KEY is not set';\n return await firecrawlSearch(q, { key: fcKey, endpoint: firecrawlEndpoint, maxResults, fetch: doFetch, signal: ctl.signal });\n }\n if (useTavily) {\n if (!key) return 'Error: Tavily provider selected but TAVILY_API_KEY is not set';\n const res = await doFetch(tavilyEndpoint, {\n method: 'POST',\n signal: ctl.signal,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ api_key: key, query: q, max_results: maxResults }),\n });\n if (!res.ok) return `Error: search provider returned ${res.status} ${res.statusText}`;\n const data: any = await res.json();\n const results = Array.isArray(data?.results) ? data.results.slice(0, maxResults) : [];\n return formatHits(results.map((r: any) => ({ title: r.title ?? '(untitled)', url: r.url ?? '', snippet: String(r.content ?? '') })));\n }\n // Keyless: DuckDuckGo HTML endpoint (no key, edge-portable).\n const res = await doFetch('https://html.duckduckgo.com/html/?q=' + encodeURIComponent(q), {\n signal: ctl.signal,\n headers: { 'user-agent': 'Mozilla/5.0 (compatible; agentx/1.0; +https://github.com/Livshitz/agentx)' },\n });\n if (!res.ok) return `Error: search returned ${res.status} ${res.statusText}`;\n return formatHits(parseDdgHtml(await res.text(), maxResults));\n } catch (e: any) {\n log.debug('WebSearch failed', e);\n return `Error searching: ${e?.name === 'AbortError' ? `timed out after ${timeoutMs}ms` : (e?.message ?? e)}`;\n } finally {\n clearTimeout(timer);\n }\n },\n };\n}\n\n/** Default instances (registered in the tool registry; opt-in by name). */\nexport const webFetchTool = makeWebFetchTool();\nexport const webSearchTool = makeWebSearchTool();\nconst ANTHROPIC_SEARCH_DESC =\n \"High-quality web search via Anthropic's native search index. Returns concise, sourced findings — one claim per line, each with its source URL. Prefer this over WebSearch when accuracy and citations matter; it is slower (~3–8s) and bills the Anthropic API account per call (one cheap-model turn + search fee).\";\n\n/** Anthropic-native search as a provider-pinned WebSearch variant. The credential is API-key billing\n * (x-api-key); pass `anthropicApiKey` to inject a resolved key, else it falls back to ANTHROPIC_API_KEY. */\nexport function makeWebSearchAnthropicTool(opts: { anthropicApiKey?: string; model?: string } = {}): AgentTool {\n return makeWebSearchTool({ provider: 'anthropic', name: 'WebSearchAnthropic', description: ANTHROPIC_SEARCH_DESC, anthropicApiKey: opts.anthropicApiKey, model: opts.model });\n}\n/** Env-keyed singleton: registered in the tool registry so 'WebSearchAnthropic' resolves by name. The\n * CLI default-on path builds its own instance with a config-resolved key (see cli/core.ts). */\nexport const webSearchAnthropicTool = makeWebSearchAnthropicTool();\n","import type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\nimport type { AgentTool } from './tools';\n\n/**\n * Copy-on-write overlay over any base IFilesystem — the base is never touched until\n * you `commit()`. Writes/deletes/mkdirs accumulate in an in-memory overlay; reads see\n * overlay-then-base. This unlocks capabilities the swappable-VFS architecture makes\n * cheap and that a real agent wants:\n * - `snapshot()` / `rollback(token)` — checkpoint before a risky multi-file change and\n * undo it instantly (the `Checkpoint`/`Rollback` agent tools sit on these);\n * - `diff()` — exactly what changed vs the base (added/modified/deleted);\n * - `commit()` — flush the overlay down into the base when you're happy.\n * Edge-safe: pure IFilesystem, no node builtins.\n */\ninterface OverlayState {\n writes: Map<string, string>; // path -> content (created/modified)\n deletes: Set<string>; // tombstones hiding a base path\n dirs: Set<string>; // overlay-created directories\n}\n\nexport class OverlayFilesystem implements IFilesystem {\n private st: OverlayState = { writes: new Map(), deletes: new Set(), dirs: new Set() };\n private snapshots = new Map<string, OverlayState>();\n private seq = 0;\n\n constructor(private base: IFilesystem) {}\n\n // ---- path plumbing: delegate to the base so normalization/cwd are identical ----\n resolvePath(path: string, cwd?: string): string { return this.base.resolvePath(path, cwd ?? this.base.getCwd()); }\n getCwd(): string { return this.base.getCwd(); }\n setCwd(path: string): void { this.base.setCwd(path); }\n private abs(p: string): string { return this.resolvePath(p); }\n private parent(abs: string): string { const i = abs.lastIndexOf('/'); return i <= 0 ? '/' : abs.slice(0, i); }\n private name(abs: string): string { return abs.slice(abs.lastIndexOf('/') + 1); }\n\n // ---- reads (overlay wins; tombstones hide the base) ----\n async readFile(path: string): Promise<string> {\n const p = this.abs(path);\n if (this.st.deletes.has(p)) throw new Error(`File not found: ${path}`);\n if (this.st.writes.has(p)) return this.st.writes.get(p)!;\n return this.base.readFile(p);\n }\n\n async exists(path: string): Promise<boolean> {\n const p = this.abs(path);\n if (this.st.deletes.has(p)) return false;\n if (this.st.writes.has(p) || this.st.dirs.has(p)) return true;\n return this.base.exists(p);\n }\n\n async isFile(path: string): Promise<boolean> {\n const p = this.abs(path);\n if (this.st.deletes.has(p)) return false;\n if (this.st.writes.has(p)) return true;\n if (this.st.dirs.has(p)) return false;\n return this.base.isFile(p);\n }\n\n async isDirectory(path: string): Promise<boolean> {\n const p = this.abs(path);\n if (this.st.deletes.has(p)) return false;\n if (this.st.dirs.has(p)) return true;\n if (this.st.writes.has(p)) return false;\n return this.base.isDirectory(p);\n }\n\n async stat(path: string): Promise<FileMetadata> {\n const p = this.abs(path);\n if (this.st.deletes.has(p)) throw new Error(`File not found: ${path}`);\n if (this.st.writes.has(p)) {\n const size = this.st.writes.get(p)!.length;\n return { created: new Date(0), modified: new Date(0), size, permissions: '-rw-r--r--', isExecutable: false };\n }\n if (this.st.dirs.has(p)) return { created: new Date(0), modified: new Date(0), size: 0, permissions: 'drwxr-xr-x', isExecutable: false };\n return this.base.stat(p);\n }\n\n /** Merge base entries (minus tombstones) with overlay-created children of `path`. */\n async readDir(path: string): Promise<string[]> {\n const p = this.abs(path);\n if (await this.isFile(p)) throw new Error(`Not a directory: ${path}`); // match base contract (don't swallow → return [])\n const names = new Set<string>();\n try { for (const n of await this.base.readDir(p)) names.add(n); } catch { /* base dir may not exist; overlay may still have children */ }\n for (const w of [...this.st.writes.keys(), ...this.st.dirs]) if (this.parent(w) === p) names.add(this.name(w));\n for (const d of this.st.deletes) if (this.parent(d) === p) names.delete(this.name(d));\n if (names.size === 0 && !(await this.exists(p)) && p !== '/') throw new Error(`Directory not found: ${path}`);\n return [...names].sort();\n }\n\n // ---- writes (recorded in the overlay; base untouched until commit) ----\n async writeFile(path: string, content: string): Promise<void> {\n const p = this.abs(path);\n if (!(await this.exists(this.parent(p)))) throw new Error(`Parent directory does not exist: ${path}`);\n this.st.deletes.delete(p);\n this.st.writes.set(p, content);\n }\n\n async createDir(path: string): Promise<void> {\n const p = this.abs(path);\n if (await this.exists(p)) throw new Error(`File or directory already exists: ${path}`);\n if (!(await this.exists(this.parent(p)))) throw new Error(`Parent directory does not exist: ${path}`);\n this.st.deletes.delete(p);\n this.st.dirs.add(p);\n }\n\n async deleteFile(path: string): Promise<void> {\n const p = this.abs(path);\n if (!(await this.exists(p))) throw new Error(`File not found: ${path}`);\n if (await this.isDirectory(p) && (await this.readDir(p)).length > 0) throw new Error(`Directory not empty: ${path}`);\n this.st.writes.delete(p);\n this.st.dirs.delete(p);\n this.st.deletes.add(p); // tombstone (in case it exists in the base)\n }\n\n // ---- checkpointing ----\n private clone(s: OverlayState): OverlayState {\n return { writes: new Map(s.writes), deletes: new Set(s.deletes), dirs: new Set(s.dirs) };\n }\n\n /** Capture the current overlay; returns a token to `rollback(token)` to. */\n snapshot(label?: string): string {\n const token = label ?? `snap-${++this.seq}`;\n this.snapshots.set(token, this.clone(this.st));\n return token;\n }\n\n /** Discard all changes since the named snapshot (or the most recent if omitted). */\n rollback(token?: string): void {\n const key = token ?? [...this.snapshots.keys()].pop();\n if (key == null || !this.snapshots.has(key)) throw new Error(`No snapshot '${token ?? '(latest)'}'`);\n this.st = this.clone(this.snapshots.get(key)!);\n }\n\n /** Paths changed vs the base since this overlay was created (added = not in base, modified = was). */\n async diff(): Promise<{ added: string[]; modified: string[]; deleted: string[] }> {\n const added: string[] = [], modified: string[] = [];\n for (const p of this.st.writes.keys()) ((await this.base.exists(p)) ? modified : added).push(p);\n return { added: added.sort(), modified: modified.sort(), deleted: [...this.st.deletes].sort() };\n }\n\n /** Flush the overlay into the base (writes, mkdirs, deletes), then clear the overlay. */\n async commit(): Promise<void> {\n for (const d of this.st.dirs) if (!(await this.base.exists(d))) await this.base.createDir(d).catch(() => {});\n for (const [p, c] of this.st.writes) await this.base.writeFile(p, c);\n for (const p of this.st.deletes) if (await this.base.exists(p)) await this.base.deleteFile(p).catch(() => {});\n this.st = { writes: new Map(), deletes: new Set(), dirs: new Set() };\n this.snapshots.clear();\n }\n}\n\n/** Duck-typed checkpoint capability (so the tools work over any snapshot/rollback FS). */\ninterface Checkpointable { snapshot(label?: string): string; rollback(token?: string): void; }\nconst asCheckpointable = (fs: any): Checkpointable | null =>\n typeof fs?.snapshot === 'function' && typeof fs?.rollback === 'function' ? fs : null;\nconst NEEDS_OVERLAY = 'Error: checkpointing requires an OverlayFilesystem (run with `checkpoints: true` over one).';\n\n/** `Checkpoint` tool — snapshot the VFS before a risky multi-step change. */\nexport const checkpointTool: AgentTool = {\n name: 'Checkpoint',\n description: 'Snapshot the filesystem before a risky or exploratory multi-step change, so you can undo it. Returns a token to pass to Rollback if you need to revert.',\n parameters: { type: 'object', properties: { label: { type: 'string', description: 'optional name for the checkpoint' } } },\n async run({ label }, ctx) {\n const fs = asCheckpointable(ctx.fs);\n if (!fs) return NEEDS_OVERLAY;\n return `Checkpoint '${fs.snapshot(label ? String(label) : undefined)}' created — call Rollback with it to undo everything since.`;\n },\n};\n\n/** `Rollback` tool — undo all VFS changes since a Checkpoint. */\nexport const rollbackTool: AgentTool = {\n name: 'Rollback',\n description: 'Undo ALL filesystem changes made since a Checkpoint. Pass the token from Checkpoint, or omit to revert to the most recent one. Use when an approach went wrong.',\n parameters: { type: 'object', properties: { to: { type: 'string', description: 'checkpoint token (omit for most recent)' } } },\n async run({ to }, ctx) {\n const fs = asCheckpointable(ctx.fs);\n if (!fs) return NEEDS_OVERLAY;\n try { fs.rollback(to ? String(to) : undefined); return `Rolled back to checkpoint '${to ?? '(latest)'}'.`; }\n catch (e: any) { return `Error: ${e?.message ?? e}`; }\n },\n};\n\nexport const checkpointTools = (): AgentTool[] => [checkpointTool, rollbackTool];\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport { CommandExecutor, registerHeadlessCommands } from '@livx.cc/wcli/core';\nimport type { Tool, ChatLike } from './llm';\nimport { imageRefResult } from './llm';\nimport { forComponent } from './logging';\nimport { grepTool, globTool, writeTool, multiEditTool, applyEditsTool, repoMapTool, reviewTool, fuzzyLineReplace } from './tools.structured';\nimport { todoWriteTool, type TodoItem } from './todo';\nimport { webFetchTool, webSearchTool, webSearchAnthropicTool } from './tools.web';\nimport { OverlayFilesystem } from './OverlayFilesystem';\nimport { redactSecrets, CONFIG_FILE_RE } from './redact';\nimport type { SandboxJobRegistry } from './tools.jobs';\n\nconst log = forComponent('tools');\n\n/** A structured multiple-choice question the model can pose to a human. */\nexport interface UserQuestion {\n question: string;\n header?: string;\n options: { label: string; description?: string }[];\n multiSelect?: boolean;\n}\n\n/**\n * The host / human-in-the-loop seam (the \"third seam\" beyond LLM + filesystem).\n * Injected per host: a CLI reads stdin, a browser renders a dialog, edge/headless\n * omits it. Unifies user-questions, permission/plan approvals, and notifications.\n */\nexport type HostEvent =\n | { kind: 'text_delta'; message: string }\n | { kind: 'speak_utterance'; message: string }\n | { kind: 'thinking_delta'; message: string }\n | { kind: 'tool_use'; id: string; name: string; input: unknown }\n | { kind: 'tool_result'; id: string; output: string; isError?: boolean }\n | { kind: 'tool_result_image'; id: string; dataUrl: string }\n // Display-only tool activity from a self-executing backend (e.g. Cursor CLI). NOT dispatched by the\n // Agent — purely for host UI (rich hosts read name/input/status for cards; plain hosts print `message`).\n | { kind: 'tool_activity'; id?: string; name: string; input?: unknown; output?: unknown; status: 'running' | 'completed' | 'error'; truncated?: { args?: boolean; result?: boolean }; message: string }\n | { kind: string; message: string; data?: unknown };\n\nexport interface HostBridge {\n /** Ask the user a structured question; resolve to the chosen label(s) / free text. */\n ask?(q: UserQuestion): Promise<string>;\n /** Request approval for a sensitive action (permission 'ask' / plan approval). */\n confirm?(prompt: string, meta?: { tool: string; input: unknown }): Promise<boolean>;\n /** Emit a progress / notification event to the host UI (non-blocking). */\n notify?(event: HostEvent): void;\n}\n\nexport interface ToolContext {\n fs: IFilesystem;\n exec: CommandExecutor;\n /** path -> content snapshot at last Read/Edit; powers the read-before-edit staleness guard. */\n readState: Map<string, string>;\n /** optional host interaction channel; absent => autonomous/headless. */\n host?: HostBridge;\n /** optional run-cancellation signal (mirrors AgentOptions.signal); lets abort-aware tools\n * (e.g. the real shell) kill in-flight work when the run is cancelled. */\n signal?: AbortSignal;\n /** the agent's working todo list (TodoWrite planning aid); replaced wholesale per call. */\n todos: TodoItem[];\n /** optional syntax guardrail: if set, write-class tools refuse to persist a broken result. */\n lint?: (path: string, content: string) => string | null;\n /** optional PDF text extraction (node hosts wire a pdftotext-backed impl); absent => Read explains. */\n pdfText?: (path: string) => Promise<string>;\n /** optional model handle for tools that run their own LLM pass (e.g. Review, a self-critique).\n * Populated by the Agent from its own ai/model; absent => such tools degrade to a no-op. */\n ai?: ChatLike;\n model?: string;\n /** optional sandbox background-job registry; enables `bash({background:true})`. Absent => no backgrounding. */\n jobs?: SandboxJobRegistry;\n /** optional incremental-output channel: long-running tools (e.g. the real Shell) stream chunks\n * here mid-run. Wired PER CALL by Agent.dispatch to Hooks.onToolOutput (cleared when the call\n * settles — a late emit is a silent no-op). Fire-and-forget: never awaited, never part of the result. */\n emit?: (chunk: string) => void;\n /** Wrap a HUMAN-blocking await (permission/plan confirm, an interactive question) so the time\n * spent parked on the user is excluded from the run's wall-clock kill-switches. Wired by the Agent;\n * absent => no accounting (the promise is awaited as-is). Idle prompt time must not count as work. */\n parkHuman?<T>(p: Promise<T>): Promise<T>;\n /** Set by `AskUserQuestion` when the model has a decision that is genuinely the user's to make but\n * no human is reachable (headless/piped/edge). The Agent drains it after the tool batch and ends\n * the run with `finishReason:'needs_input'`, handing the question to the caller instead of letting\n * the agent guess. Cleared at the start of every run. */\n needsInput?: UserQuestion;\n}\n\nexport interface AgentTool {\n name: string;\n description: string;\n parameters: object; // JSON Schema for the function's arguments\n /**\n * Longest wall-clock time this tool can legitimately take before it returns on its own.\n * Declared so a TRANSPORT above the loop (e.g. the cursor helper's per-call watchdog) can derive a\n * deadline with real headroom instead of carrying an independently-maintained magic number that\n * drifts into a tie with the tool's own cap — a tie the transport wins, destroying the tool's real\n * result. Omit for tools that return promptly.\n */\n maxDurationMs?: number;\n /**\n * Is `maxDurationMs` SELF-ENFORCED — does this tool abort itself at that bound and return?\n * An enforced bound cannot be overrun, so a transport above it needs only modest slack; an ADVISORY\n * one (the default) may be exceeded, so the transport keeps generous headroom over it. Declaring a\n * bound you do not actually enforce is worse than declaring none — say `true` only when you abort.\n */\n maxDurationEnforced?: boolean;\n run(args: any, ctx: ToolContext): Promise<string | { text: string; images?: { mimeType: string; data: string }[] }>;\n /** Optional: return a copy of this tool bound to a different real-disk working directory.\n * Implemented by tools that escape the VFS (the real `Shell`), which are cwd-bound at construction\n * and would otherwise keep pointing at the PARENT's tree when the tool instance is inherited by an\n * isolated child agent. `subagent.ts` calls this for a worktree child; tools without it pass through.\n * Return `undefined` for a capability that CANNOT follow the child (the background-job companions,\n * bound to the parent's job registry) — the tool is then dropped from the child's toolbelt.\n * An implementation must carry over any post-construction mutation the host made to the instance\n * (a renamed `name`/`description`) — rebuilding from the factory's options alone loses it. */\n withCwd?(cwd: string): AgentTool | undefined;\n}\n\n/** Build a tool context bound to a filesystem backend (Mem / Disk / …) and an optional host. */\nexport function makeContext(fs: IFilesystem, host?: HostBridge): ToolContext {\n const exec = new CommandExecutor(fs);\n registerHeadlessCommands(exec);\n return { fs, exec, readState: new Map(), host, todos: [] };\n}\n\n/** Convert AgentTools into the ai.libx.js `tools` array for chat(). */\nexport function toWireTools(tools: AgentTool[]): Tool[] {\n return tools.map((t) => ({\n type: 'function',\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n}\n\nconst numberLines = (content: string, offset = 0, limit?: number): string => {\n const lines = content.split('\\n');\n const start = Math.max(0, offset);\n const end = limit != null ? start + limit : lines.length;\n return lines\n .slice(start, end)\n .map((l, i) => `${start + i + 1}\\t${l}`)\n .join('\\n');\n};\n\n/** Keep huge tool output high-signal: head+tail with an omission marker (cuts re-runs to \"parse the wall\"). */\nexport function truncateOutput(s: string, headLines = 80, tailLines = 20): string {\n const lines = s.split('\\n');\n if (lines.length <= headLines + tailLines + 1) return s;\n const omitted = lines.length - headLines - tailLines;\n return [...lines.slice(0, headLines), `… (${omitted} lines omitted — narrow the command to see more) …`, ...lines.slice(-tailLines)].join('\\n');\n}\n\n/** Run any shell command line over the VFS (ls/cat/grep/find/head/tail/echo/mkdir/rm/mv/wc, pipes, redirects, &&/||/;). */\nexport const bashTool: AgentTool = {\n name: 'bash',\n description:\n 'Run a shell command. Supports ls, cat, grep, find, head, tail, echo, mkdir, rm, mv, cp, wc, pipes (|), redirects (>, >>), and chaining (&&, ||, ;). Best for: running tests/builds, file operations (mkdir/mv/rm), and piped workflows. For searching file contents, prefer `Grep` (structured results, no re-parse). For finding files by name, prefer `Glob`.',\n parameters: {\n type: 'object',\n required: ['command'],\n properties: {\n command: { type: 'string', description: 'the command line to execute' },\n background: { type: 'boolean', description: 'run detached over an isolated overlay (writes commit when it finishes); returns a job id to poll with JobOutput. Only worth it for slow work (remote VFS / long pipelines).' },\n },\n },\n async run({ command, background }, ctx) {\n if (background && ctx.jobs) return startBashJob(String(command ?? ''), ctx);\n const r = await ctx.exec.execute(String(command ?? ''));\n const out = truncateOutput((r.output ?? '').replace(/\\n+$/, ''));\n if (r.exitCode !== 0) {\n const err = (r.error ?? '').trim();\n return `[exit ${r.exitCode}]${err ? ' ' + err : ''}${out ? '\\n' + out : ''}`;\n }\n return out || '(command succeeded, no output)'; // explicit sentinel: don't re-run to \"check\"\n },\n};\n\n/** Kick a bash command into the background over an isolated overlay; its writes commit only on success.\n * A kill (abort) before completion skips the commit — the parent VFS is never touched mid-flight. */\nfunction startBashJob(command: string, ctx: ToolContext): string {\n const baseFs = ctx.fs;\n const id = ctx.jobs!.start(\n async ({ signal }) => {\n const overlay = new OverlayFilesystem(baseFs);\n const exec = new CommandExecutor(overlay);\n registerHeadlessCommands(exec);\n const r = await exec.execute(command); // wcli is sync-to-completion; abort can only gate the commit below\n if (signal.aborted) return '[killed before commit]';\n await overlay.commit(); // atomically flush this job's writes down into the parent VFS\n const out = truncateOutput((r.output ?? '').replace(/\\n+$/, ''));\n return r.exitCode !== 0 ? `[exit ${r.exitCode}] ${(r.error ?? '').trim()}\\n${out}`.trim() : out || '(command succeeded, no output)';\n },\n { kind: 'bash', label: command.slice(0, 60) },\n );\n return `Started background job ${id} — poll with JobOutput({id:\"${id}\"}) / JobStatus, stop with JobKill.`;\n}\n\n/** Image extensions the Read tool returns as a visual block (when the fs can read bytes). */\n/** The real on-disk path behind a VFS path, when the fs exposes one; null (with a reason) otherwise —\n * callers then fall back to inlining the bytes. */\nfunction realPathOf(fs: { realPath?: (p: string) => string }, path: string): string | null {\n if (typeof fs.realPath !== 'function') return null;\n try { return fs.realPath(path); }\n catch (e) { log.debug(`realPath unavailable for ${path} — inlining image bytes instead`, e); return null; }\n}\n\nconst IMG_MIME: Record<string, string> = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', webp: 'image/webp' };\n\n/** Heuristic: is this utf8-decoded string actually a binary file? A NUL byte never occurs in text; a\n * dense run of U+FFFD replacement chars means the bytes weren't valid utf8. Cheap — scans a prefix. */\nfunction isBinary(raw: string): boolean {\n if (raw === '') return false; // empty is handled separately (could be a legit 0-byte text file)\n const head = raw.length > 8192 ? raw.slice(0, 8192) : raw;\n let repl = 0;\n for (let i = 0; i < head.length; i++) {\n const c = head.charCodeAt(i);\n if (c === 0x00) return true; // NUL byte -> definitively binary\n if (c === 0xfffd) repl++; // utf8 decode failure marker\n }\n return repl / head.length > 0.1;\n}\n\n/** Byte length of a file — exact via readFileBytes when the fs exposes it, else utf8 byte estimate. */\nasync function byteSize(fs: unknown, path: string, raw: string): Promise<number> {\n const bfs = fs as { readFileBytes?: (p: string) => Promise<Uint8Array> };\n if (typeof bfs.readFileBytes === 'function') {\n try { return (await bfs.readFileBytes(path)).length; } catch { /* fall through to estimate */ }\n }\n return Buffer.byteLength(raw, 'utf8');\n}\n\n/** Read a text file as 1-indexed numbered lines; arms the staleness guard for Edit. */\nexport const readTool: AgentTool = {\n name: 'Read',\n description:\n 'Read a file. Text files return 1-indexed numbered lines (with optional `offset`/`limit` and a re-Read pointer for partial reads). Image files (png/jpg/jpeg/gif/webp) return the picture itself so you can SEE it. PDFs return their extracted text. Always Read a file before Editing it.',\n parameters: {\n type: 'object',\n required: ['path'],\n properties: {\n path: { type: 'string' },\n offset: { type: 'number' },\n limit: { type: 'number' },\n },\n },\n async run({ path, offset, limit }, ctx) {\n // Image file → return it as a visual block. The adapter turns a tool result whose JSON carries a\n // `dataUrl` into an image tool_result the model can see. Needs a binary-capable fs (disk default);\n // the utf8 VFS (sandbox/Mem) can't, so we say so instead of corrupting the bytes.\n const ext = String(path).toLowerCase().split('.').pop() ?? '';\n // PDF → extracted text when the host wired an extractor (CLI: pdftotext); else say how to proceed.\n if (ext === 'pdf') {\n if (!ctx.pdfText) return `[${path} is a PDF — text extraction isn't available in this environment (install poppler's pdftotext and run on disk).]`;\n if (!(await ctx.fs.exists(path))) return `Error: File not found: ${path}`; // jail-aware: hidden paths read as absent\n const text = (await ctx.pdfText(ctx.fs.resolvePath(path))).trim();\n return text ? numberLines(text, Math.max(0, offset ?? 0), limit) : `[${path}: no extractable text (scanned/image-only PDF?)]`;\n }\n if (IMG_MIME[ext]) {\n const fs = ctx.fs as { readFileBytes?: (p: string) => Promise<Uint8Array>; realPath?: (p: string) => string };\n if (typeof fs.readFileBytes !== 'function') {\n return `[${path} is an image, but this filesystem can't read binary — attach it as @${path} instead, or run on disk.]`;\n }\n // Persist a REFERENCE, not the payload: the send path (expandImagesForSend) turns it back into the\n // same `{dataUrl}` body the wire adapter renders, for the recent images only — so a screenshot Read\n // costs ~80 bytes in the transcript/session JSON instead of megabytes of immortal base64.\n const real = realPathOf(fs, path);\n if (real) {\n if (!(await ctx.fs.exists(path))) return `Error: File not found: ${path}`;\n return imageRefResult(real, IMG_MIME[ext]);\n }\n const bytes = await fs.readFileBytes(path);\n const b64 = Buffer.from(bytes).toString('base64');\n return JSON.stringify({ dataUrl: `data:${IMG_MIME[ext]};base64,${b64}`, image: path });\n }\n const raw = await ctx.fs.readFile(path);\n // Binary guard: a non-text file (a .png without a recognized ext, .zip, .bin, …) read as utf8 is\n // either empty or replacement-char garbage — both silently pollute context. A silent empty tool\n // result is plausibly what tips a delegated model (cursor/composer) into an empty reply, where a\n // native model tolerates it. Return an explicit, non-empty marker so the model always sees SOMETHING.\n if (isBinary(raw)) {\n const bytes = await byteSize(ctx.fs, path, raw);\n return `[binary file: ${path} — ${bytes} bytes, not shown as text. Read renders png/jpg/jpeg/gif/webp images directly; otherwise attach it as @${path}.]`;\n }\n ctx.readState.set(ctx.fs.resolvePath(path), raw); // staleness guard tracks the REAL content\n if (raw === '') return `[empty file: ${path} — 0 bytes]`;\n // Mask secret values in config files so keys can live there usably-but-hidden (line count is preserved).\n const content = CONFIG_FILE_RE.test(ctx.fs.resolvePath(path)) ? redactSecrets(raw) : raw;\n const total = content === '' ? 0 : content.split('\\n').length;\n const start = Math.max(0, offset ?? 0);\n const body = numberLines(content, start, limit);\n // snippet-with-pointer: when the slice doesn't cover the whole file, tell the\n // model what it's missing + how to pull it — so it expands precisely instead of re-reading blind.\n const shownEnd = limit != null ? Math.min(start + limit, total) : total;\n const shownCount = Math.max(0, shownEnd - start);\n if (shownCount >= total) return body; // whole file shown — no footer\n if (shownCount === 0) return `[no lines in range (offset ${start}${limit != null ? `, limit ${limit}` : ''}) — file has ${total} line(s)]`;\n return `${body}\\n\\n[lines ${start + 1}–${shownEnd} of ${total} · re-Read with offset/limit for the rest]`;\n },\n};\n\n/** Replace an exact, unique substring; requires a prior Read and guards against stale edits. */\nexport const editTool: AgentTool = {\n name: 'Edit',\n description:\n 'Replace an exact substring in a file. Requires a prior Read of the same file. `old_string` must occur exactly once — include surrounding context to disambiguate.',\n parameters: {\n type: 'object',\n required: ['path', 'old_string', 'new_string'],\n properties: {\n path: { type: 'string' },\n old_string: { type: 'string' },\n new_string: { type: 'string' },\n },\n },\n async run({ path, old_string, new_string }, ctx) {\n const key = ctx.fs.resolvePath(path);\n const snapshot = ctx.readState.get(key);\n if (snapshot == null) throw new Error(`File has not been read yet: ${path}. Read it before editing.`);\n const current = await ctx.fs.readFile(path);\n if (current !== snapshot) throw new Error(`File ${path} changed since it was read (stale). Re-read before editing.`);\n const count = old_string === '' ? 0 : current.split(old_string).length - 1;\n if (count > 1) throw new Error(`old_string is not unique in ${path} (${count} matches). Provide more surrounding context.`);\n let next: string, note = '';\n if (count === 1) {\n next = current.replace(old_string, () => new_string); // exact: function replacer, no $-pattern expansion\n } else {\n // exact match failed — try a whitespace-tolerant unique match before giving up (cuts re-read churn)\n const fuzzy = fuzzyLineReplace(current, old_string, new_string);\n if (fuzzy == null) throw new Error(`old_string not found in ${path}.`);\n next = fuzzy;\n note = ' (whitespace-tolerant match)';\n }\n if (ctx.lint) { const err = ctx.lint(path, next); if (err) throw new Error(err); }\n await ctx.fs.writeFile(path, next);\n ctx.readState.set(key, next);\n return `Edited ${path}${note}`;\n },\n};\n\n/** Session-exit tool: the model calls this when the user wants to end the conversation.\n * The `onExit` callback is injected by the host (CLI sets it to flip a flag that breaks the REPL loop). */\nexport function exitSessionTool(onExit: () => void): AgentTool {\n return {\n name: 'ExitSession',\n description:\n 'End the current session and exit the CLI. Call this when the user says goodbye, asks to quit, ' +\n 'or clearly indicates they want to stop the conversation (e.g. \"ok bye\", \"that\\'s all\", \"exit\", \"goodnight\").',\n parameters: { type: 'object', properties: {} },\n async run() {\n onExit();\n return 'Session ending. Goodbye!';\n },\n };\n}\n\nexport function defaultTools(): AgentTool[] {\n return [bashTool, readTool, editTool];\n}\n\n/**\n * The full catalog of selectable tools, keyed by name. The evolve loop's mutation\n * surface picks from this registry; embedders can build a custom tool set by name.\n */\nexport function toolRegistry(): Record<string, AgentTool> {\n const all = [bashTool, readTool, editTool, grepTool, globTool, writeTool, multiEditTool, applyEditsTool, repoMapTool, reviewTool(), todoWriteTool, webFetchTool, webSearchTool, webSearchAnthropicTool];\n return Object.fromEntries(all.map((t) => [t.name, t]));\n}\n\n/** Resolve a list of tool names against `available` (host-supplied tools, e.g. a parent agent's\n * toolbelt or mounted MCP tools) first, then the built-in registry. Unknown names throw.\n * Without `available` an allowlist could only ever name a built-in — so a def could not scope a\n * child to a tool its parent injected (`Bash`, `ToolSearch`, …). */\nexport function toolsByName(names: string[], available?: AgentTool[]): AgentTool[] {\n const reg = toolRegistry();\n const extra = Object.fromEntries((available ?? []).map((t) => [t.name, t]));\n return names.map((n) => {\n const t = extra[n] ?? reg[n];\n if (!t) throw new Error(`unknown tool '${n}'. Known: ${[...new Set([...Object.keys(extra), ...Object.keys(reg)])].join(', ')}`);\n return t;\n });\n}\n","import { promises as fsp, realpathSync } from 'node:fs';\nimport * as np from 'node:path';\nimport type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\nimport { PathResolver } from '@livx.cc/wcli/core';\n\n/**\n * Real-disk backend implementing wcli's IFilesystem, rooted at `baseDir`.\n * The VFS path space ('/...') maps under baseDir, so the same agent/tools/commands\n * run unchanged against disk or memory — complete mem↔disk interchangeability.\n * Semantics mirror MemFilesystem (throws on missing parent / existing dir / etc.).\n */\nexport class NodeDiskFilesystem implements IFilesystem {\n private cwd = '/';\n private opts: { denySymlinks: boolean };\n\n constructor(private baseDir: string, opts: { denySymlinks?: boolean } = {}) {\n // denySymlinks (default ON): refuse to traverse a symlink anywhere in the path, so\n // a symlink planted inside the root cannot escape it (read/write/delete a target outside).\n this.opts = { denySymlinks: true, ...opts };\n }\n\n /** Ensure the root dir exists. */\n async init(): Promise<void> {\n await fsp.mkdir(this.baseDir, { recursive: true });\n }\n\n private real(vpath: string): string {\n return np.join(this.baseDir, '.' + vpath); // vpath is absolute in VFS space\n }\n\n // Verified non-symlink DIRECTORY components, with a short TTL: tree walks (Glob/Grep) hit the same\n // parents thousands of times; re-lstat'ing each per op is the dominant syscall cost. The 1s window\n // is an accepted race only against an out-of-band symlink swap mid-walk (this FS can't create\n // symlinks itself); leaf components are never cached.\n private verified = new Map<string, number>();\n private static VERIFY_TTL_MS = 1000;\n\n /** Throw if any existing component of `real` is a symlink (escape vector). */\n private async assertNoSymlink(real: string): Promise<void> {\n if (!this.opts.denySymlinks) return;\n const rel = np.relative(this.baseDir, real);\n if (rel === '' || rel.startsWith('..')) return; // root itself / outside (can't happen post-join)\n const parts = rel.split(np.sep);\n let cur = this.baseDir;\n const now = Date.now();\n for (let i = 0; i < parts.length; i++) {\n cur = np.join(cur, parts[i]);\n const isLeaf = i === parts.length - 1;\n if (!isLeaf && (this.verified.get(cur) ?? 0) > now) continue;\n let st;\n try { st = await fsp.lstat(cur); } catch { return; } // component doesn't exist yet (e.g. new file) — nothing further to check\n if (st.isSymbolicLink()) throw new Error('File not found: symlink not permitted');\n if (!isLeaf) {\n if (this.verified.size > 10_000) this.verified.clear(); // bound memory on huge trees\n this.verified.set(cur, now + NodeDiskFilesystem.VERIFY_TTL_MS);\n }\n }\n }\n\n resolvePath(path: string, cwd?: string): string {\n return PathResolver.resolve(path, cwd || this.cwd);\n }\n getCwd(): string { return this.cwd; }\n setCwd(path: string): void { this.cwd = PathResolver.normalize(path); }\n\n async readFile(path: string): Promise<string> {\n const r = this.real(this.resolvePath(path));\n try {\n await this.assertNoSymlink(r);\n const st = await fsp.stat(r);\n if (st.isDirectory()) throw new Error(`Not a file: ${path}`);\n return await fsp.readFile(r, 'utf8');\n } catch (e) {\n if (e instanceof Error && /Not a file/.test(e.message)) throw e;\n throw new Error(`File not found: ${path}`);\n }\n }\n\n /** The REAL on-disk path behind a VFS path — an optional capability (not on IFilesystem) the Read\n * tool duck-types so it can persist an image REFERENCE instead of megabytes of base64. */\n realPath(path: string): string { return this.real(this.resolvePath(path)); }\n\n /** The CANONICAL on-disk path — symlinks resolved. `realPath` is path arithmetic (baseDir + vpath)\n * and therefore reports a symlink and its target as different places, which is no use as an\n * identity: a tree walk that dedupes on it still re-enters a loop (`a/b/loop -> a` re-walked 11\n * times before a depth cap stopped it). Optional capability, duck-typed by the file-scanning\n * tools; falls back to the arithmetic path for anything unresolvable (a broken/racing link). */\n canonicalPath(path: string): string {\n const p = this.realPath(path);\n try { return realpathSync(p); } catch { return p; }\n }\n\n /** Read raw bytes (for binary files like images). Not on the base IFilesystem (which is utf8-only) — an\n * optional capability the Read tool duck-types to return image blocks. Same symlink/jail guards as readFile. */\n async readFileBytes(path: string): Promise<Uint8Array> {\n const r = this.real(this.resolvePath(path));\n try {\n await this.assertNoSymlink(r);\n const st = await fsp.stat(r);\n if (st.isDirectory()) throw new Error(`Not a file: ${path}`);\n return await fsp.readFile(r); // no encoding → Buffer (Uint8Array)\n } catch (e) {\n if (e instanceof Error && /Not a file/.test(e.message)) throw e;\n throw new Error(`File not found: ${path}`);\n }\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n const r = this.real(this.resolvePath(path));\n await this.assertNoSymlink(r);\n const parent = np.dirname(r);\n try {\n if (!(await fsp.stat(parent)).isDirectory()) throw 0;\n } catch {\n throw new Error(`Parent directory does not exist: ${path}`);\n }\n await fsp.writeFile(r, content, 'utf8');\n }\n\n async deleteFile(path: string): Promise<void> {\n const r = this.real(this.resolvePath(path));\n await this.assertNoSymlink(r);\n let st;\n try { st = await fsp.stat(r); } catch { throw new Error(`File not found: ${path}`); }\n if (st.isDirectory()) {\n if ((await fsp.readdir(r)).length > 0) throw new Error(`Directory not empty: ${path}`);\n await fsp.rmdir(r);\n } else {\n await fsp.unlink(r);\n }\n }\n\n async readDir(path: string): Promise<string[]> {\n const r = this.real(this.resolvePath(path));\n try { await this.assertNoSymlink(r); return await fsp.readdir(r); }\n catch { throw new Error(`Directory not found: ${path}`); }\n }\n\n async createDir(path: string): Promise<void> {\n if (await this.exists(path)) throw new Error(`File or directory already exists: ${path}`);\n const r = this.real(this.resolvePath(path));\n await this.assertNoSymlink(r);\n const parent = np.dirname(r);\n try {\n if (!(await fsp.stat(parent)).isDirectory()) throw 0;\n } catch {\n throw new Error(`Parent directory does not exist: ${path}`);\n }\n await fsp.mkdir(r);\n }\n\n async exists(path: string): Promise<boolean> {\n const r = this.real(this.resolvePath(path));\n try { await this.assertNoSymlink(r); await fsp.stat(r); return true; } catch { return false; }\n }\n\n async stat(path: string): Promise<FileMetadata> {\n let s;\n const r = this.real(this.resolvePath(path));\n try { await this.assertNoSymlink(r); s = await fsp.stat(r); }\n catch { throw new Error(`File not found: ${path}`); }\n return {\n created: s.birthtime,\n modified: s.mtime,\n size: s.size,\n permissions: s.isDirectory() ? 'drwxr-xr-x' : '-rw-r--r--',\n isExecutable: false,\n };\n }\n\n async isDirectory(path: string): Promise<boolean> {\n const r = this.real(this.resolvePath(path));\n try { await this.assertNoSymlink(r); return (await fsp.stat(r)).isDirectory(); } catch { return false; }\n }\n async isFile(path: string): Promise<boolean> {\n const r = this.real(this.resolvePath(path));\n try { await this.assertNoSymlink(r); return (await fsp.stat(r)).isFile(); } catch { return false; }\n }\n}\n","import type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\nimport { globToRegExp } from './tools.structured';\n\n/**\n * Containment boundary A — a policy decorator over ANY IFilesystem.\n *\n * The agent only ever sees an IFilesystem, so what it can touch is exactly what we\n * mount. This jail:\n * - hides + blocks `deny` paths entirely (secrets: .env, keys, .git, …) — invisible\n * to read/stat/exists/readDir, unwritable;\n * - makes `readonly` paths readable but unwritable (the \"constitution\": pinned\n * grader/suite/criteria the self-evolve agent must never edit);\n * - optionally `confineTo` a set of subtrees (anything outside is denied);\n * - normalizes paths first, so `..` traversal (`/src/../.env`) is caught after resolution;\n * - reports every violation via `onViolation` (audit trail / circuit-breaker hook).\n *\n * Crucial limitation: this guards what the AGENT'S TOOLS touch. It does NOT contain\n * code executed against the real disk at eval time (the grader imports agent-written\n * code) — that is boundary B (a sandboxed subprocess). See mind/08-self-evolve.md.\n */\nexport class JailedFilesystem implements IFilesystem {\n public options: JailOptions;\n private denyRe: RegExp[];\n private roRe: RegExp[];\n private confineRe?: RegExp[];\n\n constructor(private inner: IFilesystem, options?: Partial<JailOptions>) {\n this.options = { ...new JailOptions(), ...options };\n // case-insensitive so /.ENV, /Id_Rsa, … can't slip past a lowercase rule.\n this.denyRe = this.options.deny.map((g) => globToRegExp(g, true));\n this.roRe = this.options.readonly.map((g) => globToRegExp(g, true));\n this.confineRe = this.options.confineTo?.map((g) => globToRegExp(g, true));\n }\n\n private abs(path: string): string {\n return this.inner.resolvePath(path, this.inner.getCwd());\n }\n\n /** Throw if reading `path` is not permitted (denied or out of confinement). */\n private guardRead(op: string, path: string): string {\n const abs = this.abs(path);\n if (this.confineRe && !this.confineRe.some((r) => r.test(abs))) return this.violate(op, abs, 'confine');\n if (this.denyRe.some((r) => r.test(abs))) return this.violate(op, abs, 'deny');\n return abs;\n }\n\n /** Throw if writing/deleting `path` is not permitted (denied, readonly, or out of confinement). */\n private guardWrite(op: string, path: string): string {\n const abs = this.guardRead(op, path); // write implies read access first\n if (this.roRe.some((r) => r.test(abs))) return this.violate(op, abs, 'readonly');\n return abs;\n }\n\n private violate(op: string, abs: string, rule: string): never {\n this.note(op, abs, rule);\n // Read denials masquerade as \"not found\" to avoid confirming a secret's existence.\n if (rule === 'deny' || rule === 'confine') throw new Error(`File not found: ${abs}`);\n throw new Error(`Blocked by filesystem jail (${rule}): ${abs}`);\n }\n\n /** Fire the audit hook without throwing (for boolean probes that must still return false). */\n private note(op: string, abs: string, rule: string): void {\n this.options.onViolation?.({ op, path: abs, rule });\n }\n\n /** Is `abs` (already-resolved) visible? If not, fire the audit hook (op given) and return false. */\n private visible(abs: string, op?: string): boolean {\n if (this.confineRe && !this.confineRe.some((r) => r.test(abs))) { if (op) this.note(op, abs, 'confine'); return false; }\n if (this.denyRe.some((r) => r.test(abs))) { if (op) this.note(op, abs, 'deny'); return false; }\n return true;\n }\n\n async readFile(path: string): Promise<string> { return this.inner.readFile(this.guardRead('readFile', path)); }\n /** Forward the optional binary-read capability (if the inner fs has it), jailed like readFile. */\n async readFileBytes(path: string): Promise<Uint8Array> {\n const inner = this.inner as { readFileBytes?: (p: string) => Promise<Uint8Array> };\n if (typeof inner.readFileBytes !== 'function') throw new Error('binary read not supported by this filesystem');\n return inner.readFileBytes(this.guardRead('readFileBytes', path));\n }\n /** Forward the optional real-path capability (image REFS), jail-guarded like readFile. */\n realPath(path: string): string {\n const inner = this.inner as { realPath?: (p: string) => string };\n if (typeof inner.realPath !== 'function') throw new Error('realPath not supported by this filesystem');\n return inner.realPath(this.guardRead('realPath', path));\n }\n async writeFile(path: string, content: string): Promise<void> { return this.inner.writeFile(this.guardWrite('writeFile', path), content); }\n async deleteFile(path: string): Promise<void> { return this.inner.deleteFile(this.guardWrite('deleteFile', path)); }\n async createDir(path: string): Promise<void> { return this.inner.createDir(this.guardWrite('createDir', path)); }\n async stat(path: string): Promise<FileMetadata> { return this.inner.stat(this.guardRead('stat', path)); }\n\n // Boolean probes stay invisible (return false on a denied path) BUT still fire the\n // audit hook — otherwise an agent could enumerate secrets via exists() without\n // ever tripping the circuit breaker.\n async exists(path: string): Promise<boolean> {\n const abs = this.abs(path);\n return this.visible(abs, 'exists') ? this.inner.exists(abs) : false;\n }\n async isDirectory(path: string): Promise<boolean> {\n const abs = this.abs(path);\n return this.visible(abs, 'isDirectory') ? this.inner.isDirectory(abs) : false;\n }\n async isFile(path: string): Promise<boolean> {\n const abs = this.abs(path);\n return this.visible(abs, 'isFile') ? this.inner.isFile(abs) : false;\n }\n\n /** List a directory, filtering out entries the policy hides. */\n async readDir(path: string): Promise<string[]> {\n const abs = this.guardRead('readDir', path);\n const entries = await this.inner.readDir(abs);\n return entries.filter((name) => this.visible(abs === '/' ? `/${name}` : `${abs}/${name}`));\n }\n\n resolvePath(path: string, cwd?: string): string { return this.inner.resolvePath(path, cwd ?? this.inner.getCwd()); }\n getCwd(): string { return this.inner.getCwd(); }\n /** Guard cwd too: the jail must never be able to \"stand\" on a denied/out-of-confine dir. */\n setCwd(path: string): void {\n const abs = this.abs(path);\n if (!this.visible(abs, 'setCwd')) throw new Error(`File not found: ${abs}`);\n this.inner.setCwd(abs);\n }\n}\n\n/** Default denylist: secrets and VCS internals that must never be read or written.\n * Patterns are matched case-insensitively (so /.ENV is covered too). */\nexport const DEFAULT_DENY: string[] = [\n // env / config secrets\n '**/.env', '**/.env.*', '**/.npmrc', '**/.netrc',\n // private keys & certs\n '**/*.pem', '**/*.key', '**/*.crt', '**/*.cert', '**/*.p12', '**/*.pfx',\n '**/id_rsa', '**/id_rsa.*', '**/id_ed25519', '**/id_ed25519.*',\n '**/id_dsa', '**/id_dsa.*', '**/id_ecdsa', '**/id_ecdsa.*',\n // credential stores (dir AND contents)\n '**/.ssh', '**/.ssh/**', '**/.aws', '**/.aws/**',\n '**/.docker', '**/.docker/**', '**/.dockercfg',\n '**/.kube', '**/.kube/**', '**/.kubeconfig',\n '**/credentials', '**/.credentials', '**/secrets.json',\n // VCS internals + git config (can carry tokens / remote creds)\n '**/.git', '**/.git/**', '**/.gitconfig', '**/.gitmodules',\n];\n\nexport class JailOptions {\n /** Globs that are invisible and unwritable (secrets). */\n deny: string[] = [...DEFAULT_DENY];\n /** Globs readable but not writable/deletable (the pinned constitution). */\n readonly: string[] = [];\n /** If set, only paths matching these globs are accessible at all. */\n confineTo?: string[];\n /** Audit hook fired on every blocked operation (drives the circuit breaker). */\n onViolation?: (v: { op: string; path: string; rule: string }) => void;\n}\n","/**\n * Tier-1 OS sandbox for the real `Shell` tool (mind/03-roadmap.md \"capability tiers\").\n *\n * Wraps the spawned `/bin/sh` in the platform's process sandbox so a hostile/buggy command\n * can read the machine but can only WRITE inside an allowlist (cwd + tmp + extra `writePaths`),\n * and gets no network unless granted:\n * - macOS: `sandbox-exec` (seatbelt) with a generated profile\n * - Linux: `bwrap` (bubblewrap) with `--ro-bind / /` + writable binds\n *\n * Pure argv builders (unit-testable, no node imports) + an async wrapper-binary locator.\n * This complements — does not replace — env secret-scrubbing and the permission prompt:\n * the FS jail can't contain a real process; this makes the *process* itself contained.\n */\n\nexport class OsSandboxOptions {\n /** Allow outbound network. Default OFF (Tier-1: no network unless granted). */\n network = false;\n /** Extra absolute paths writable beyond cwd + tmp (e.g. a build cache). */\n writePaths: string[] = [];\n}\n\nexport interface SandboxWrap {\n bin: string;\n args: string[]; // full argv: wrapper flags + /bin/sh -c <command>\n}\n\n/** Writable allowlist shared by both platforms: cwd, the tmp roots, /dev. */\nfunction writable(cwd: string, o: OsSandboxOptions, tmpDir?: string): string[] {\n const set = new Set<string>([cwd, '/tmp', '/private/tmp', '/private/var/folders', '/dev', ...(tmpDir ? [tmpDir] : []), ...o.writePaths]);\n return [...set];\n}\n\nconst sbQuote = (p: string) => `\"${p.replace(/([\"\\\\])/g, '\\\\$1')}\"`;\n\n/** macOS seatbelt profile: allow everything, then deny writes/network, then re-allow the allowlist\n * (seatbelt resolves conflicts by specificity, so subpath allows override the broad deny). */\nexport function seatbeltProfile(cwd: string, o: OsSandboxOptions, tmpDir?: string): string {\n const allows = writable(cwd, o, tmpDir).map((p) => `(subpath ${sbQuote(p)})`).join(' ');\n return [\n '(version 1)',\n '(allow default)',\n ...(o.network ? [] : ['(deny network*)']),\n '(deny file-write*)',\n `(allow file-write* ${allows})`,\n ].join('\\n');\n}\n\n/** Build the wrapped argv for `sh -c <command>`, or null if `platform` has no supported wrapper. */\nexport function sandboxArgv(command: string, cwd: string, opts: Partial<OsSandboxOptions> = {}, platform: string = process.platform, tmpDir?: string): SandboxWrap | null {\n const o = { ...new OsSandboxOptions(), ...opts };\n if (platform === 'darwin') {\n return { bin: '/usr/bin/sandbox-exec', args: ['-p', seatbeltProfile(cwd, o, tmpDir), '/bin/sh', '-c', command] };\n }\n if (platform === 'linux') {\n const binds = writable(cwd, o, tmpDir).filter((p) => p !== '/dev' && !p.startsWith('/private')).flatMap((p) => ['--bind-try', p, p]);\n return {\n bin: 'bwrap',\n args: ['--ro-bind', '/', '/', ...binds, '--dev', '/dev', '--proc', '/proc', '--die-with-parent', ...(o.network ? [] : ['--unshare-net']), '/bin/sh', '-c', command],\n };\n }\n return null;\n}\n\n/** Locate the wrapper binary for this platform; null = sandboxing unavailable here. */\nexport async function findSandboxWrapper(platform: string = process.platform): Promise<string | null> {\n const { existsSync } = await import('node:fs');\n if (platform === 'darwin') return existsSync('/usr/bin/sandbox-exec') ? '/usr/bin/sandbox-exec' : null;\n if (platform === 'linux') {\n for (const dir of (process.env.PATH ?? '/usr/bin:/bin').split(':')) if (dir && existsSync(`${dir}/bwrap`)) return `${dir}/bwrap`;\n return null;\n }\n return null;\n}\n","import type { AgentTool } from './tools';\nimport { truncateOutput } from './tools';\nimport { redactSecrets } from './redact';\nimport { forComponent } from './logging';\nimport { sandboxArgv, findSandboxWrapper, type OsSandboxOptions } from './shell.sandbox';\n\n/**\n * Real shell tool — node-only, OPT-IN, and deliberately NOT edge-portable.\n *\n * ⚠️ Unlike the default VFS `bash` (a sandboxed JS interpreter over the virtual filesystem),\n * this spawns a REAL `/bin/sh` process. It can run `bun`, `git`, `ssh`, scripts, deploys —\n * and, by the same token, it is NOT sandboxed: only cwd-binding constrains it. It is a\n * deliberate host escalation, kept out of `defaultTools()`/`toolRegistry()` and out of the\n * edge-safe `src/index.ts` (same policy as `mcp.client.ts`). A host opts in explicitly:\n *\n * tools: [...defaultTools(), makeRealShellTool({ cwd: nodeDiskRoot })]\n *\n * Mirrors `tools.web.ts`: a factory with an injectable `spawn` (tests + edge never import\n * node:child_process), an options bag, abort + timeout honored, output capped. Safety beyond\n * cwd-binding is the host's to add (e.g. a PermissionPolicy `decision:'ask'` per command, or\n * an OS sandbox wrapper) — see mind/03-roadmap.md \"OS-level access — capability tiers\".\n */\n\nconst log = forComponent('shell');\n\n/** Normalize shell output for return: trim trailing newlines, mask secret values, then size-truncate.\n * Redaction runs BEFORE truncation so a masked tail can't smuggle a secret past the line cap. */\nconst clean = (s: string): string => truncateOutput(redactSecrets(s.replace(/\\n+$/, '')));\n\n/** The slice of node's `child_process.spawn` we depend on — injectable so tests supply a fake. */\nexport type SpawnFn = (\n command: string,\n args: string[],\n options: {\n cwd?: string;\n env?: Record<string, string | undefined>;\n signal?: AbortSignal;\n /** stdio layout. We force stdin to /dev/null so a child can't block on (or steal) the REPL's input. */\n stdio?: ['ignore', 'pipe', 'pipe'];\n /** Run in a new session/process group (setsid) — detaches from the controlling terminal. See DETACHED. */\n detached?: boolean;\n },\n) => SpawnedProcess;\n\n/** Minimal `ChildProcess` surface this tool uses. */\nexport interface SpawnedProcess {\n stdout?: { on(ev: 'data', cb: (chunk: any) => void): void } | null;\n stderr?: { on(ev: 'data', cb: (chunk: any) => void): void } | null;\n on(ev: 'close', cb: (code: number | null) => void): void;\n on(ev: 'error', cb: (err: Error) => void): void;\n kill(signal?: string): void;\n /** Child PID — present on the real node child; used to signal the whole process group on abort. */\n pid?: number;\n}\n\n/**\n * Detach every spawned child from the REPL's controlling terminal.\n *\n * `stdio: ['ignore', 'pipe', 'pipe']` — stdin is /dev/null (clean EOF; nothing to block on).\n * `detached: true` — setsid() puts the child in its OWN session with NO controlling tty.\n *\n * Without this a child inherits the agent's tty: an interactive prompt (`sudo`, `ssh`, a git\n * credential helper) opens `/dev/tty` directly and then RACES the REPL's raw-mode input reader for\n * the user's keystrokes — a deadlock that also captures whatever the user types (e.g. a password)\n * into the agent instead of the program. Detached, those programs find no tty and fail FAST with a\n * legible error (\"sudo: a terminal is required …\") which the model can act on (tell the user to run\n * it via `!`), instead of hanging until the 120s timeout. Side benefit: the child is a process-group\n * leader, so abort/timeout can reap the whole subtree, not just /bin/sh. */\nconst DETACHED = { stdio: ['ignore', 'pipe', 'pipe'] as ['ignore', 'pipe', 'pipe'], detached: true };\n\n/** Signal a child's WHOLE process group (`-pid`). Children are group leaders (DETACHED), so `proc.kill`\n * hits only /bin/sh and orphans descendants; this reaps the subtree. Best-effort — the group may\n * already be gone, and the fake spawn in tests has no real pid. Returns false when nothing was signaled. */\nfunction killGroup(proc: SpawnedProcess | undefined, signal: 'SIGTERM' | 'SIGKILL'): boolean {\n if (!proc?.pid) return false;\n try { process.kill(-proc.pid, signal); return true; } catch { return false; /* already exited / no such group */ }\n}\n\nexport interface RealShellOptions {\n /** Working directory the shell is bound to (typically a NodeDiskFilesystem `baseDir`). Required. */\n cwd: string;\n /** Shell binary for `-c` (e.g. the user's `$SHELL`). Default `/bin/sh`. Only honored when NOT\n * OS-sandboxed (the sandbox wrapper pins its own shell). */\n shell?: string;\n /** Override the spawner (tests inject a fake; default lazily imports node:child_process). */\n spawn?: SpawnFn;\n /** Per-command wall-clock cap (kill on overrun). Default 120s. */\n timeoutMs?: number;\n /** Ceiling for the model-supplied `timeoutMs` argument (a long build can ask for more than the\n * default, but not for an unbounded turn). Default 10min. */\n maxTimeoutMs?: number;\n /** Extra env merged over the (optionally scrubbed) base env for the child. */\n env?: Record<string, string>;\n /** Strip likely-secret vars (API keys, tokens, cloud creds) from the child's env. Default ON.\n * The FS jail does NOT contain a real process, so this is the seam that keeps `echo $ANTHROPIC_API_KEY`\n * from leaking the host's secrets to a spawned command. `false` passes `process.env` through verbatim. */\n redactEnv?: boolean;\n /** Job registry enabling `Shell({background:true})` (long-running processes). Pair with `makeShellJobTools`. */\n registry?: ShellJobRegistry;\n /** Tier-1 OS sandbox: wrap /bin/sh in sandbox-exec (macOS) / bwrap (Linux) — writes confined to\n * cwd+tmp, network blocked unless granted. `true` = defaults; commands FAIL (don't silently run\n * unsandboxed) if no wrapper exists on this platform. See src/shell.sandbox.ts. */\n osSandbox?: boolean | Partial<OsSandboxOptions>;\n /** Does a background job outlive the current run? False on one-shot hosts (the process exits and\n * `killOnExit` reaps the job), which the Shell tool's description must say rather than promise\n * cross-turn survival it won't get. Default true. */\n jobsSurviveRun?: boolean;\n}\n\n/** Resolve the (bin,args) to spawn for `command`, honoring the optional OS sandbox.\n * Throws when sandboxing was requested but this platform has no wrapper — fail closed. */\nasync function spawnArgvFor(command: string, cwd: string, osSandbox?: boolean | Partial<OsSandboxOptions>): Promise<{ bin: string; args: string[] }> {\n if (!osSandbox) return { bin: '/bin/sh', args: ['-c', command] };\n const opts = osSandbox === true ? {} : osSandbox;\n const wrapper = await findSandboxWrapper();\n const wrapped = wrapper ? sandboxArgv(command, cwd, opts, process.platform, process.env.TMPDIR) : null;\n if (!wrapped) throw new Error(`OS sandbox requested but no wrapper available on ${process.platform} (need sandbox-exec or bwrap)`);\n return wrapped;\n}\n\n/** Env var names that look like secrets and are dropped before spawning (unless redactEnv:false). */\nconst SECRET_ENV_RE = /(_API_KEY|_TOKEN|_SECRET|_PASSWORD|_PRIVATE_KEY|^AWS_|^GITHUB_TOKEN$|^OPENAI_|^ANTHROPIC_|^GOOGLE_|^GEMINI_|^GROQ_|^NPM_TOKEN$)/i;\n\n/** Build the child's env: `process.env` minus likely-secrets (when redacting), plus explicit `env`. */\nfunction childEnv(opts: { env?: Record<string, string>; redactEnv?: boolean }): Record<string, string | undefined> {\n const base: Record<string, string | undefined> = {};\n const redact = opts.redactEnv !== false; // default ON\n for (const [k, v] of Object.entries(process.env)) if (!(redact && SECRET_ENV_RE.test(k))) base[k] = v;\n return { ...base, ...opts.env };\n}\n\n/** Lazily resolve node's spawn (kept out of any eager edge import path). */\nlet _spawn: SpawnFn | undefined;\nasync function nodeSpawn(): Promise<SpawnFn> {\n if (!_spawn) _spawn = (await import('node:child_process')).spawn as unknown as SpawnFn;\n return _spawn;\n}\n\n// ---------------------------------------------------------------------------\n// Background jobs — long-running processes the agent starts, polls, and kills.\n// ---------------------------------------------------------------------------\nexport type JobStatus = 'running' | 'exited' | 'killed' | 'error';\n\nexport interface ShellJobConfig {\n cwd: string;\n spawn?: SpawnFn;\n env?: Record<string, string>;\n redactEnv?: boolean;\n /** Tail buffer cap per job (bytes); older output is dropped. Default 256 KB. */\n maxBuffer?: number;\n /** Kill all jobs on process exit (the CLI sets this; tests leave it off to avoid global handlers). */\n killOnExit?: boolean;\n /** Tier-1 OS sandbox for background jobs too (same semantics as RealShellOptions.osSandbox). */\n osSandbox?: boolean | Partial<OsSandboxOptions>;\n /**\n * Called once when a background job reaches a terminal state. Claude-Code parity: a background task\n * that finishes has to reach the MODEL, or `background:true` is a write-only hole — the model starts\n * a job, forgets it, and never collects the result. The host wires this to `agent.inject(...)`, which\n * folds the notice in at the next step boundary (and re-opens the turn if the model was about to stop).\n */\n onExit?: JobExitHandler;\n}\n\nexport interface JobExitNotice { id: string; command: string; status: JobStatus; exitCode?: number; tail: string }\nexport type JobExitHandler = (n: JobExitNotice) => void;\n\n/** The exact text a completion notice becomes. Shared so every host (CLI, presets, embedders) pushes the\n * same thing back to the model instead of each inventing its own wording. */\nexport function formatJobExit(n: JobExitNotice): string {\n return `[background job ${n.id} ${n.status}${n.exitCode != null ? ` exit ${n.exitCode}` : ''}] \\`${n.command}\\`\\n`\n + (n.tail ? `${n.tail}\\n` : '(no output)\\n')\n + `Read the full output with ShellOutput({id:\"${n.id}\"}).`;\n}\n\ninterface Job { command: string; buf: string; status: JobStatus; exitCode?: number; proc?: SpawnedProcess; }\n\n/**\n * Per-session registry of background `/bin/sh` jobs. Backs `Shell({background:true})` and the\n * `ShellOutput`/`ShellStatus`/`ShellKill` tools. Output accumulates into a tail-capped ring so a\n * chatty process can't OOM. Bounded + killable; the CLI wires `killOnExit` so children are reaped.\n */\nexport class ShellJobRegistry {\n private jobs = new Map<string, Job>();\n private seq = 0;\n constructor(private cfg: ShellJobConfig) {\n if (cfg.killOnExit && typeof process !== 'undefined') process.once('exit', () => this.killAll());\n }\n\n async start(command: string): Promise<string> {\n const id = `job-${++this.seq}`;\n const max = this.cfg.maxBuffer ?? 256 * 1024;\n const job: Job = { command, buf: '', status: 'running' };\n const append = (chunk: any) => {\n const s = typeof chunk === 'string' ? chunk : chunk?.toString?.('utf8') ?? '';\n job.buf = (job.buf + s).slice(-max); // ring: keep the tail\n };\n try {\n const spawn = this.cfg.spawn ?? (await nodeSpawn());\n const argv = this.cfg.osSandbox ? await spawnArgvFor(command, this.cfg.cwd, this.cfg.osSandbox) : { bin: '/bin/sh', args: ['-c', command] };\n const proc = spawn(argv.bin, argv.args, { cwd: this.cfg.cwd, env: childEnv(this.cfg), ...DETACHED });\n job.proc = proc;\n proc.stdout?.on('data', append);\n proc.stderr?.on('data', append);\n proc.on('error', (err: any) => { if (job.status === 'running') { job.status = 'error'; append(`\\n[error] ${err?.message ?? err}`); this.notifyExit(id, job); } });\n proc.on('close', (code: number | null) => { if (job.status === 'running') { job.status = 'exited'; job.exitCode = code ?? undefined; this.notifyExit(id, job); } });\n } catch (e: any) {\n job.status = 'error';\n job.buf = `failed to spawn: ${e?.message ?? e}`;\n }\n this.jobs.set(id, job);\n return id;\n }\n\n /** Fire `onExit` at most once per job, with the tail so the model can act without a second round-trip. */\n private notified = new Set<string>();\n private notifyExit(id: string, job: Job): void {\n if (this.notified.has(id) || !this.cfg.onExit) return;\n this.notified.add(id);\n try {\n this.cfg.onExit({ id, command: job.command, status: job.status, exitCode: job.exitCode, tail: clean(job.buf).slice(-4000) });\n } catch { /* a host notification must never take down the job registry */ }\n }\n\n /**\n * Wire (or rewire) the completion callback AFTER construction. A host that only gets its agent handle\n * once the Agent is constructed (the library's own `fullAgentOptions` preset, any embedder) could not\n * pass `onExit` up front, so background completions were silently REPL-only. Set it here instead.\n */\n setOnExit(fn: JobExitHandler | undefined): void { this.cfg.onExit = fn; }\n\n /** Whether a finished job will actually be reported to the model. The Shell tool's description reads\n * this so it can't promise a completion notice on a host that discards it. */\n get notifiesOnExit(): boolean { return !!this.cfg.onExit; }\n\n /** Current tail output for a job (null = no such job). */\n output(id: string): string | null { return this.jobs.get(id)?.buf ?? (this.jobs.has(id) ? '' : null); }\n\n status(id: string): { status: JobStatus; exitCode?: number; bytes: number } | null {\n const j = this.jobs.get(id);\n return j ? { status: j.status, exitCode: j.exitCode, bytes: j.buf.length } : null;\n }\n\n list(): Array<{ id: string; command: string; status: JobStatus }> {\n return [...this.jobs].map(([id, j]) => ({ id, command: j.command, status: j.status }));\n }\n\n /**\n * Take over an ALREADY-RUNNING child as a background job. A foreground command that outruns its\n * timeout is not necessarily a hung command — killing it throws away work that was nearly done and,\n * worse, a launcher that spawned its own detached worker leaves that worker running with nothing\n * tracking it. Adopting hands the model a handle instead: the command keeps going, its completion\n * is reported like any other job, and `seed` carries the output produced before the handoff.\n */\n adopt(command: string, proc: SpawnedProcess, seed = ''): string {\n const id = `job-${++this.seq}`;\n const max = this.cfg.maxBuffer ?? 256 * 1024;\n const job: Job = { command, buf: seed.slice(-max), status: 'running', proc };\n const append = (chunk: any) => {\n const s = typeof chunk === 'string' ? chunk : chunk?.toString?.('utf8') ?? '';\n job.buf = (job.buf + s).slice(-max);\n };\n proc.stdout?.on('data', append);\n proc.stderr?.on('data', append);\n proc.on('error', (err: any) => { if (job.status === 'running') { job.status = 'error'; append(`\\n[error] ${err?.message ?? err}`); this.notifyExit(id, job); } });\n proc.on('close', (code: number | null) => { if (job.status === 'running') { job.status = 'exited'; job.exitCode = code ?? undefined; this.notifyExit(id, job); } });\n this.jobs.set(id, job);\n return id;\n }\n\n kill(id: string): boolean {\n const j = this.jobs.get(id);\n if (!j) return false;\n // Group-kill: bg children are detached (own group), so SIGTERM the whole subtree — not just /bin/sh —\n // else a forked server survives the kill and the agent's exit teardown. Fall back to the pid for fakes.\n if (j.status === 'running') { if (!killGroup(j.proc, 'SIGTERM')) { try { j.proc?.kill('SIGTERM'); } catch { /* already gone */ } } j.status = 'killed'; }\n return true;\n }\n\n killAll(): void { for (const id of this.jobs.keys()) this.kill(id); }\n}\n\n/** Build an opt-in real-shell tool bound to `options.cwd`. */\nexport function makeRealShellTool(options: RealShellOptions): AgentTool {\n const defaultTimeoutMs = options.timeoutMs ?? 120_000;\n const maxTimeoutMs = Math.max(options.maxTimeoutMs ?? 600_000, defaultTimeoutMs);\n // The background promise must match what THIS host actually does — a lie here is what makes\n // `background:true` a black hole the model trusts. Evaluated lazily (the registry's onExit may be wired\n // after the tool is built, via setOnExit).\n // NOTIFICATION and SURVIVAL are independent facts governed by different things — `registry.onExit`\n // (is a completion pushed to the model?) and `jobsSurviveRun` (does the host outlive this run?). Reading\n // both off `notifiesOnExit` made the unwired preset tell the model a job \"does NOT survive the end of\n // this run\" while an identically-configured wired registry said the opposite. Each clause states what\n // actually governs it.\n const backgroundDoc = () => {\n const base = 'Set `background:true` for long-running processes (servers, watchers) and for anything that already timed out in the foreground — '\n + 'returns a job id immediately; poll with ShellOutput/ShellStatus, stop with ShellKill. ';\n const notify = options.registry?.notifiesOnExit\n ? 'Its completion is reported back to you when it finishes.'\n : 'NOTE: nothing will tell you when it finishes — poll ShellOutput/ShellStatus yourself, or you will never see its result.';\n const survival = options.jobsSurviveRun === false\n ? 'The job does NOT survive the end of this run, so do not stop while you still need its result.'\n : 'It keeps running across turns.';\n return `${base}${notify} ${survival}`;\n };\n return {\n name: 'Shell',\n // Rebind for an isolated child agent (git worktree): same policy/env/timeouts, new cwd. The\n // `registry` is deliberately dropped — it is bound to the PARENT's cwd (and, in hosts like\n // shraga-ee, to the parent's session), so a background job started from the child would run\n // outside the child's isolation and report into the parent. Background stays a parent capability\n // (`makeShellJobTools`' companions drop out of an isolated child entirely — see their `withCwd`).\n // Only `run` is rebuilt: everything else is carried over from THIS instance, because a host may\n // have mutated the tool AFTER construction (shraga-ee renames `Shell` -> `Bash` and its system\n // prompt says `Bash` everywhere). Rebuilding from `options` alone silently dropped that rename,\n // so a worktree child advertised `Shell` while being told to call `Bash` — an unknown-tool error\n // on its first call, and a hard failure for an agentType def whose allowlist names `Bash`.\n // `description` is the ONE thing taken from the rebound tool instead: it is derived from the\n // options and states whether `background:true` works — the rebind drops the registry, so carrying\n // the parent's text over would advertise a background capability the child does not have. (The\n // spread also collapses the getter below to a plain value, which is why this override is explicit.)\n withCwd(cwd: string): AgentTool {\n const rebound = makeRealShellTool({ ...options, cwd, registry: undefined });\n return { ...this, description: rebound.description, run: rebound.run, withCwd: rebound.withCwd };\n },\n get description() {\n return 'Run a shell command via /bin/sh in the working directory. ' +\n 'Executes any installed binary — ls, cat, grep, git, bun, node, curl, scripts, etc. ' +\n 'Returns combined stdout+stderr; non-zero exits are prefixed `[exit N]`. ' +\n 'Runs non-interactively with no terminal (stdin is /dev/null): commands that prompt for input ' +\n 'fail fast rather than hang — for privileged actions use a non-interactive flag (e.g. `sudo -n`), ' +\n 'or ask the user to run the command themselves. ' +\n (options.registry?.adopt\n ? `A command still running after ${defaultTimeoutMs}ms is NOT killed — it is handed to a background job and you get its id, so you can keep checking on it (\\`[still running]\\`). Pass \\`timeoutMs\\` (max ${maxTimeoutMs}) to wait longer in the foreground, and always bound network commands yourself (e.g. \\`curl -m 10\\`). `\n : `Each command is killed after ${defaultTimeoutMs}ms (result \\`[exit 124]\\` with whatever output it produced) — pass \\`timeoutMs\\` (max ${maxTimeoutMs}) for a legitimately slower command, and always bound network commands yourself (e.g. \\`curl -m 10\\`). `) +\n backgroundDoc();\n },\n // Declared so transports above the agent loop can size their own deadline with headroom (see AgentTool.maxDurationMs).\n maxDurationMs: maxTimeoutMs,\n parameters: {\n type: 'object',\n required: ['command'],\n properties: {\n command: { type: 'string', description: 'the shell command line to execute' },\n background: { type: 'boolean', description: 'run detached and return a job id immediately (for servers/watchers/long builds)' },\n timeoutMs: { type: 'number', description: 'wall-clock cap for THIS command, overriding the default (clamped to the tool max)' },\n },\n },\n async run({ command, background, timeoutMs: askedTimeoutMs, timeout: aliasTimeout }, ctx) {\n const cmd = String(command ?? '');\n // `timeout` is an UNADVERTISED alias for `timeoutMs`, same unit (ms). Models reach for the\n // shorter name from muscle memory (observed: composer-2.5 sending `{\"timeout\":180000}`), and\n // an unknown key is silently dropped — the command then dies at the 120s default while the\n // model believes it asked for 180s and reads an unexplained kill. Accepted, never documented,\n // so the schema still teaches exactly one name.\n const asked = Number.isFinite(askedTimeoutMs) ? askedTimeoutMs : aliasTimeout;\n const timeoutMs = Number.isFinite(asked) && Number(asked) > 0\n ? Math.min(Number(asked), maxTimeoutMs)\n : defaultTimeoutMs;\n if (!cmd.trim()) return '[exit 1] empty command';\n if (background) {\n if (!options.registry) return 'Error: background execution is not enabled in this host (no job registry).';\n const id = await options.registry.start(cmd);\n return `Started background job ${id}. Poll output with ShellOutput({id:\"${id}\"}), check ShellStatus({id:\"${id}\"}), stop with ShellKill({id:\"${id}\"}).`;\n }\n const spawn = options.spawn ?? (await nodeSpawn());\n // Sandbox-off keeps this path await-free (after spawn resolution) so an abort racing the call\n // start still lands before listener registration, exactly as pre-sandbox semantics.\n let argv = { bin: options.shell || '/bin/sh', args: ['-c', cmd] };\n if (options.osSandbox) {\n try {\n argv = await spawnArgvFor(cmd, options.cwd, options.osSandbox);\n } catch (e: any) {\n return `[exit 1] ${e?.message ?? e}`; // fail closed — never run unsandboxed when sandboxing was asked for\n }\n }\n // Compose abort: the run's signal (ctx.signal) OR our per-command timeout both kill the child.\n const ctl = new AbortController();\n const onAbort = () => ctl.abort();\n if (ctx.signal) { if (ctx.signal.aborted) ctl.abort(); else ctx.signal.addEventListener('abort', onAbort, { once: true }); }\n let timedOut = false;\n // Set by the promise body once the child exists, so the timer can hand it over instead of killing it.\n let onDeadline: () => void = () => { timedOut = true; ctl.abort(); };\n const timer = setTimeout(() => { onDeadline(); }, timeoutMs);\n // The child is its own process-group leader (DETACHED): node's `signal` kills only /bin/sh, so on\n // abort also SIGKILL the whole group to reap any descendants (see killGroup).\n // Incremental output → ctx.emit (when the host listens), coalesced to ≥250ms / ≥1KB batches\n // so a chatty child doesn't spam hooks. Redacted per batch (the final result is re-redacted\n // whole — a secret split across batch boundaries can slip the per-batch pass, hence the cap\n // on what consumers may do with chunks: display/digest, never persistence).\n let pend = '';\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n const flushEmit = (ctx: { emit?: (s: string) => void }) => {\n if (flushTimer) { clearTimeout(flushTimer); flushTimer = null; }\n if (pend) { ctx.emit?.(redactSecrets(pend)); pend = ''; }\n };\n try {\n return await new Promise<string>((resolve) => {\n let out = '';\n let settled = false;\n const finish = (s: string) => { if (settled) return; settled = true; resolve(s); };\n let proc: SpawnedProcess;\n try {\n proc = spawn(argv.bin, argv.args, { cwd: options.cwd, env: childEnv(options), signal: ctl.signal, ...DETACHED });\n } catch (e: any) {\n return finish(`[exit 1] failed to spawn shell: ${e?.message ?? e}`);\n }\n // Reap the detached group when the CANCEL fires (node's `signal` only hits /bin/sh).\n if (ctl.signal.aborted) killGroup(proc, 'SIGKILL');\n else ctl.signal.addEventListener('abort', () => killGroup(proc, 'SIGKILL'), { once: true });\n // Deadline reached: hand the still-running child to the job registry rather than killing it.\n // Only a host with a registry can do this — elsewhere the deadline stays a kill, because a\n // child nothing tracks is worse than a dead one.\n const registry = options.registry;\n if (registry?.adopt) {\n onDeadline = () => {\n timedOut = true;\n if (settled) return;\n flushEmit(ctx);\n // The registry attaches its own collectors from here on; ours would only grow a buffer\n // nobody reads. `off` is not part of the minimal stream shape, hence the guarded call.\n (proc.stdout as any)?.off?.('data', collect);\n (proc.stderr as any)?.off?.('data', collect);\n const id = registry.adopt!(cmd, proc, out);\n finish(handoffFor(timeoutMs, id, clean(out), !!registry.notifiesOnExit));\n };\n }\n const collect = (chunk: any) => {\n const s = typeof chunk === 'string' ? chunk : chunk?.toString?.('utf8') ?? '';\n out += s;\n if (ctx.emit && !settled) {\n pend += s;\n if (pend.length >= 1024) flushEmit(ctx);\n else flushTimer ??= setTimeout(() => flushEmit(ctx), 250);\n }\n };\n proc.stdout?.on('data', collect);\n proc.stderr?.on('data', collect);\n proc.on('error', (err: any) => {\n // AbortError fires here when ctl.abort() kills the child — report timeout vs cancel.\n if (err?.name === 'AbortError' || ctl.signal.aborted) return finish(reasonFor(timedOut, timeoutMs, clean(out)));\n log.debug('shell spawn error', err);\n finish(`[exit 1] ${err?.message ?? err}${out ? '\\n' + clean(out) : ''}`);\n });\n proc.on('close', (code: number | null) => {\n flushEmit(ctx); // drain the coalesce buffer before settling (still pre-resolve, so ctx.emit is live)\n if (ctl.signal.aborted) return finish(reasonFor(timedOut, timeoutMs, clean(out)));\n const body = clean(out);\n if (code && code !== 0) return finish(`[exit ${code}]${body ? '\\n' + body : ''}`);\n finish(body || '(command succeeded, no output)');\n });\n });\n } finally {\n clearTimeout(timer);\n if (flushTimer) clearTimeout(flushTimer); // no emits after the call settles\n ctx.signal?.removeEventListener('abort', onAbort);\n }\n },\n };\n}\n\n/** Deadline message when the child was ADOPTED rather than killed: the work continues, so say how to follow it. */\nfunction handoffFor(timeoutMs: number, id: string, body: string, notifies: boolean): string {\n const head = `[still running] exceeded ${timeoutMs}ms, so it was handed to background job ${id} — NOT killed, it is still going. `\n + `Check on it with ShellOutput({id:\"${id}\"}) / ShellStatus({id:\"${id}\"}), stop it with ShellKill({id:\"${id}\"}). `\n + (notifies\n ? 'Its completion will be reported to you, so you may continue with other work meanwhile.'\n : 'Nothing will tell you when it finishes — poll it yourself before you rely on its result.');\n return body ? `${head}\\nOutput so far:\\n${body}` : head;\n}\n\n/** Abort message: timeout vs external cancel, preserving any partial output. */\nfunction reasonFor(timedOut: boolean, timeoutMs: number, body: string): string {\n // A foreground timeout is a DEAD END unless the result says how to get out of it: re-issuing the same\n // command is the one thing that cannot work, and it is exactly what a model does when the message is\n // just a code. Name the two recoveries (background, or narrow the command).\n const head = timedOut\n ? `[exit 124] timed out after ${timeoutMs}ms (killed). Re-running this command unchanged will time out again. `\n + `Either re-run it with background:true (returns a job id immediately; poll with ShellOutput/ShellStatus, `\n + `stop with ShellKill) or narrow it so it can finish — bound it, scope it, or ask for less.`\n : '[exit 130] cancelled (killed)';\n return body ? `${head}\\nPartial output before the kill:\\n${body}` : head;\n}\n\nconst NO_JOB = (id: string) => `Error: no background job '${id}'. Use ShellStatus with no id to list jobs, or start one with Shell({background:true}).`;\n\n/** Build the background-job companion tools (ShellOutput / ShellStatus / ShellKill) over a registry.\n * Each closes over THIS registry, i.e. this agent's jobs in this agent's cwd, so none of them can be\n * rebound to an isolated child's root: `withCwd` returns `undefined` and they are dropped from the\n * child's toolbelt. That keeps the capability coherent — the child's `Shell` cannot START a background\n * job (its registry is dropped), so it must not be able to inspect or SIGTERM the parent's either. */\nexport function makeShellJobTools(registry: ShellJobRegistry): AgentTool[] {\n const idParam = { type: 'object', properties: { id: { type: 'string', description: 'the job id from Shell({background:true})' } } };\n const dropOnRebind = { withCwd: () => undefined };\n return [\n {\n ...dropOnRebind,\n name: 'ShellOutput',\n description: 'Read the accumulated output (tail) of a background Shell job by id.',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n async run({ id }) {\n const out = registry.output(String(id));\n if (out == null) return NO_JOB(String(id));\n const st = registry.status(String(id))!;\n return `[${st.status}${st.exitCode != null ? ` exit ${st.exitCode}` : ''}]\\n${clean(out) || '(no output yet)'}`;\n },\n },\n {\n ...dropOnRebind,\n name: 'ShellStatus',\n description: 'Status of a background Shell job (running/exited/killed + exit code). Omit `id` to list all jobs.',\n parameters: idParam,\n async run({ id }) {\n if (!id) {\n const jobs = registry.list();\n return jobs.length ? jobs.map((j) => `${j.id} ${j.status} ${j.command}`).join('\\n') : '(no background jobs)';\n }\n const st = registry.status(String(id));\n return st ? `${st.status}${st.exitCode != null ? ` (exit ${st.exitCode})` : ''} · ${st.bytes} byte(s) buffered` : NO_JOB(String(id));\n },\n },\n {\n ...dropOnRebind,\n name: 'ShellKill',\n description: 'Stop a running background Shell job by id (SIGTERM).',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n async run({ id }) {\n return registry.kill(String(id)) ? `Killed job ${id}.` : NO_JOB(String(id));\n },\n },\n ];\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike, ChatResponse, Message, StreamChunk, ToolCall, MessageContent, ContentPart } from './llm';\nimport { contentText, imagePart, elideStaleImages, elideImages, messageHasImage, expandImagesForSend, sendBytes, sendBytesPer, endsOnAnnouncedAction, passesBackReasoning } from './llm';\nimport { type AgentTool, type ToolContext, type HostBridge, type UserQuestion, defaultTools, makeContext, toWireTools, truncateOutput } from './tools';\nimport { SandboxJobRegistry, makeJobTools } from './tools.jobs';\nimport { askUserQuestionTool } from './host';\nimport { loadSkills, scanSkills } from './skills';\nimport { loadCommands, scanCommands } from './commands';\nimport { loadMemory } from './memory';\nimport { loadInstructions } from './instructions';\nimport { makeTaskTool, makeTaskBatchTool } from './subagent';\nimport { modelProvider } from './models';\nimport { loadAgents } from './agents';\nimport { checkpointTools } from './OverlayFilesystem';\nimport type { Hooks } from './hooks';\nimport { PermissionPolicy, planMode, composeHooks } from './permissions';\nimport { forComponent } from './logging';\nimport { checkSyntax } from './lint';\nimport { reasoningToChatFragment, type ReasoningEffort } from './reasoning';\n\nconst log = forComponent('Agent');\n\n/** Read a non-negative integer env override, guarded for non-node (edge/browser) builds. */\nfunction envInt(key: string, fallback: number): number {\n const n = typeof process !== 'undefined' ? Number(process.env?.[key]) : NaN;\n return Number.isFinite(n) && n >= 0 ? n : fallback;\n}\n\n/** A browser-bridge MCP tool name (`mcp__<server>__<tool>` where the server name mentions \"browser\").\n * These return huge DOM/screenshot payloads — their USE is the signal that triggers adaptive trimming. */\nfunction isBrowserTool(name: string): boolean {\n return name.startsWith('mcp__') && /browser/i.test(name.slice(5).split('__')[0]);\n}\n\n/** A thrown provider error that is really a cancel (barge-in / Ctrl-C), not a crash. The abort flag can\n * lag the throw under a race, so we message-match across providers: fetch AbortError, Node ABORT_ERR,\n * groq/SDK \"operation was aborted\", ConnectError [canceled]. Mirrors the CLI's cursor-abort guard. */\nfunction isAbortError(err: unknown): boolean {\n const e = err as any;\n const blob = `${e?.message ?? ''} ${e?.name ?? ''} ${e?.code ?? ''} ${e?.cause?.name ?? ''}`;\n return /operation was aborted|\\bAbortError\\b|ABORT_ERR|\\[canceled\\]/i.test(blob);\n}\n\nexport interface RunResult {\n text: string;\n steps: number;\n /** Why the loop ended. The middle group are automatic kill-switches (budget/abuse guards).\n * `needs_input` is NOT a failure: the agent hit a decision that was the user's to make with no\n * human reachable, so it stopped and raised the question (see `question`) instead of guessing.\n * Answer it and resume the session to continue. */\n finishReason: 'stop' | 'max_steps' | 'budget' | 'timeout' | 'loop' | 'max_tool_calls' | 'aborted' | 'error' | 'needs_input' | 'empty';\n messages: Message[];\n /** The parked question — present iff `finishReason === 'needs_input'`. */\n question?: UserQuestion;\n /** Accumulated token usage across all turns (non-stream path). With prompt caching,\n * promptTokens includes cached reads/writes; the cache splits ride along for exact pricing. */\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number; cacheCreationTokens?: number; cacheReadTokens?: number };\n /** True if ANY turn's usage was estimated (provider gave none) rather than exact — lets the UI mark cost `~`. */\n usageEstimated?: boolean;\n /** Advertised tools the model NAMED in the reply it is handing back while the run's invocation ledger\n * shows zero calls to them — a fabricated tool use, proven against ground truth rather than guessed\n * from phrasing. A host can use it to tell the user plainly instead of shipping the invented result.\n *\n * Re-evaluated at RETURN time, not frozen at detection: a claim the recovery nudge rescued (the model\n * went and made the real call) is dropped. It used to survive, on the reading that the field recorded\n * \"this turn needed rescuing\" — but the only consumer turns it into a sentence for the user (\"I never\n * ran it\"), and on the guard's own success path that sentence is false. Whether a turn needed rescuing\n * is a telemetry question, and the `log.warn` at the nudge already answers it. */\n fabricatedToolClaims?: string[];\n error?: unknown;\n}\n\n/** What a manual `/compact` actually freed (token estimates, ~4 chars/token). */\nexport interface CompactResult { tokensBefore: number; tokensAfter: number; target: number; cap: number; removed: number }\n\nexport class AgentOptions {\n /** Any ai.libx.js AIClient (or a FakeAIClient). */\n ai!: ChatLike;\n /** Filesystem backend — MemFilesystem, NodeDiskFilesystem, IndexedDbFilesystem, …\n * OPTIONAL: if omitted, the agent lazily defaults to a JAILED real disk rooted at `process.cwd()`\n * (secrets hidden by DEFAULT_DENY) — resolved via a dynamic node import at first run, so the edge/\n * browser build (which always passes its own fs) never pulls in `node:fs`. Pass `fs` explicitly to\n * use any other backend (and to keep full control of the jail). */\n fs?: IFilesystem;\n model = 'anthropic/claude-sonnet-4-6';\n systemPrompt =\n 'You are a coding agent operating on a virtual filesystem. Use the `bash` tool to explore (ls, grep, find, cat) and the `Read`/`Edit` tools to view and modify files. Always Read a file before Editing it — and before overwriting it with `Write` or a whole-file `ApplyEdits`: Write replaces the ENTIRE file, so blindly writing over an existing one destroys its unseen contents. If a file already exists, Read it first, then merge your changes (or Edit the specific part). When multiple tool calls are independent (e.g. several Reads or Greps with no dependency between them), issue them together in a single turn rather than one at a time. When the task is complete, reply with a short summary and make no further tool calls.\\n' +\n 'Recovery: every turn\\'s file changes are checkpointed. If the user asks to undo/revert/recover edits (including a file you overwrote), tell them to run `/rewind` (or `/undo` for the last turn) to restore the working tree — checkpoints cover files you edited even in .gitignored dirs. You cannot run `/rewind` yourself; surface it as the recovery path.\\n' +\n 'When working with a knowledge base or document workspace: use `RepoMap` with scope \"docs\" to see all document headings and summaries (orient first); use `MemorySearch` to find memories by content when you don\\'t know the exact slug; use `Recall` with multiple slugs to batch-load related facts in one call. Prefer targeted loads over reading everything — orient → search → load → act.';\n tools: AgentTool[] = defaultTools();\n maxSteps = 25;\n // --- automatic kill-switches (always on; protect the API budget against runaway loops/abuse) ---\n /** Hard ceiling on accumulated tokens (prompt+completion) across the run; cache READS count at 0.1×\n * (their real price) so a fat cached context doesn't trip the guard on healthy turns. 0 = unbounded. */\n maxTokens = 200_000;\n /** Idle ceiling in ms: max time since the last productive step before the run is killed (a long/active\n * step resets it — see runLoop's `lastProgressAt`). Not a whole-run wall clock. 0 = unbounded. */\n timeoutMs = 300_000;\n /** Idle-stall watchdog for a SINGLE streamed model request: abort it if no chunk (text OR reasoning)\n * arrives for this long. The between-steps `timeoutMs` can't preempt an in-flight `chat()`, so a\n * provider that goes silent mid-stream would otherwise park the loop forever. 0 = off. */\n stallMs = 60_000;\n /** Stop if the identical tool-call batch (name+args) repeats this many times in a row. 0 = off. */\n maxRepeats = 3;\n /** Cumulative cap on tool calls dispatched across the run. 0 = unbounded. */\n maxToolCalls = 100;\n /** External cancellation — abort the loop between steps (e.g. a UI \"Cancel\" button). */\n signal?: AbortSignal;\n /** Retry budget for an EMPTY/silent-turn (a delegated-runtime wedge: cursor's warm helper spins then\n * returns a content-less end, surfaced as `code:'empty'`/`code:'cursor_silent'`). Tuned WIDER than the\n * network-drop budget (fixed 2) because clearing a wedge needs several reap+respawn cycles — each retry\n * hits a FRESH cursor session (the adapter evicts the wedged warm helper on the silent-end; a stall-watchdog\n * cancel is NOT this class — it is classified `stall`, and the watchdog's coded abort reason is what tells\n * the adapter to evict on that path too). Still bounded:\n * after exhaustion the turn surfaces `finishReason:'empty'` (non-zero exit), never infinite, never silent.\n * Env: AGENTX_EMPTY_RETRIES. */\n emptyRetries = envInt('AGENTX_EMPTY_RETRIES', 4);\n /** Base backoff (ms) between empty-turn retries; grows linearly per attempt (longer than the network\n * class's fixed 1s so a wedged helper has time to be reaped/respawned). Env: AGENTX_EMPTY_RETRY_BASE_MS. */\n emptyRetryBaseMs = envInt('AGENTX_EMPTY_RETRY_BASE_MS', 1500);\n /** 0 = never trim. Otherwise cap the messages sent per turn (system + most recent). */\n maxContextMessages = 0;\n /** Note-taking: keep the most-recent N tool-result outputs verbatim; collapse OLDER ones to a one-line\n * stub in the sent context (the model already consumed them — it can re-Read/re-run). The stored\n * transcript is never mutated. 0 = keep all verbatim. */\n keepToolOutputs = 0;\n /** How many of the most-recent image-bearing messages get their image REF expanded to real base64 in\n * the outgoing request. Older ones (and legacy inline base64) go on the wire as the elision stub. */\n keepRecentImages = 1;\n /** Token-aware backstop (~4 chars/token estimate). After note-taking, drop oldest messages from the\n * sent context until the estimate is under this ceiling (pairing-safe). 0 = off. */\n maxContextTokens = 0;\n /** The MODEL's context window (tokens) — what the context % is measured against and what `/compact`\n * targets 50% of. Filled by the CLI from model metadata; 0 = fall back to 200k. Deliberately NOT\n * `maxTokens`: that is the cumulative SPEND kill-switch, and a spend budget must never be able to\n * drive destructive compaction (`--max-tokens 50000` would otherwise shred the transcript). */\n contextWindow = 0;\n /** Pagination ceiling for a SINGLE tool result (bytes). A result over this is cropped to page 1 with\n * a marker telling the model it was cropped (refine the query, or page further). Guards against one\n * Grep/Read/MCP call blowing the whole context window. 0 = off. Default 60k (~15k tokens). */\n maxToolResultBytes = 60_000;\n /** Hook to handle an oversized tool result instead of the default lossy crop: receives the FULL output\n * and returns the (cropped) string to put in context — e.g. spill to scratch and return a recoverable,\n * paginated stub. Called only when a result exceeds `maxToolResultBytes`. */\n capToolResult?: (full: string, info: { tool: string; args: any }) => string | Promise<string>;\n /** Browser-run adaptive trimming. Browser MCP tools (`mcp__*browser*`) return huge per-call results\n * (full DOM text + screenshots) that accumulate per step and blow the cumulative `maxTokens` budget\n * kill-switch mid-browse. The fix attacks PER-STEP TOKEN GROWTH, and engages ONLY once a browser tool\n * is ACTUALLY invoked (not on mere config presence — so normal coding is untouched):\n * - `resultBytes`: tighter `maxToolResultBytes` applied to BROWSER tool results (each oversized DOM is\n * cropped/spilled to a small stub → small fresh-token tail per step).\n * - `keepOutputs`: keep only the most-recent N tool-result bodies verbatim ONCE a browser tool has run\n * (older huge DOMs collapse to one-line stubs → small cached prefix → small 0.1×cacheRead/step).\n * Explicit `keepToolOutputs`/`maxToolResultBytes` are NOT overridden below their browser values — the\n * tighter of (user, browser) wins, never loosening a user's cap. Unset = off (no adaptive behavior). */\n browserTrim?: { resultBytes?: number; keepOutputs?: number };\n /** VFS dir(s) of skills (`<dir>/<id>/SKILL.md`). If set: inject a catalog + add the `Skill` tool. Multiple dirs are merged (first wins on name collisions). */\n skillsDir?: string | string[];\n /** VFS dir(s) of slash-command templates (`<dir>/<name>.md`). If set: inject a catalog + add the `SlashCommand` tool. Multiple dirs are merged (first wins). */\n commandsDir?: string | string[];\n /** VFS dir(s) of memory (`<dir>/MEMORY.md`). If set: inject the index at run start (persistence = backend).\n * Multiple dirs are merged (reads search all; writes go to first). */\n memoryDir?: string | string[];\n /** User-scope memory dir for global facts (type=user/feedback). Remember routes by type when set. */\n memoryUserDir?: string;\n /** Filenames to discover as project instructions (e.g. `AGENT.md`, `AGENTS.md`, `CLAUDE.md`).\n * Walks the VFS tree and merges all found files (general → specific, like Claude Code).\n * `true` (default) = auto-discover standard names. `string[]` = custom names. `false` = skip. */\n instructionFiles: boolean | string[] = true;\n /** Host interaction channel (human-in-the-loop). If set: adds the `AskUserQuestion` tool. */\n host?: HostBridge;\n /** Add the `AskUserQuestion` tool when a host is present (default true). Set false for an agent that\n * must never block a turn on a structured question — e.g. a voice reflex that confirms inline. */\n askUserQuestion = true;\n /** Deterministic interception points around tool execution (pre/post/stop). */\n hooks?: Hooks;\n /** If true: add the `Task` tool so the agent can spawn depth-limited child agents over the VFS. */\n subagents = false;\n /** VFS dir of typed-subagent defs (`<dir>/<name>.md`). If set with `subagents`: inject a catalog + enable the `Task` `agentType` param. */\n agentsDir?: string;\n /** Current recursion depth (0 = top-level); spawned children run at depth+1. */\n depth = 0;\n /** Hard ceiling on subagent nesting (beyond it the `Task` tool refuses to spawn). */\n maxDepth = 2;\n /** Real-disk dir where child agents stream their transcript as they run (origin-anchored — survives\n * worktree teardown / a child's own cwd). When set, an interrupted/failed child commits a STATUS HINT\n * + a pointer to its trace instead of a dangling tool_call, so the parent can read it and decide\n * whether to ignore, pick it up, or restart. Unset (library/sandbox default) = no tracing. */\n traceDir?: string;\n /** Stream tokens from the model. Takes effect only with a `host.notify`; off => current (non-stream) behavior. */\n stream = false;\n /** Closure reflex for delegated runtimes (cursor/claude-code): when such a turn runs tools but never\n * closes — no assistant text after the last tool, or text that trails off on an action it announced\n * and never took (\"Also checking for X.\") — nudge ONE more step to ANSWER the user\n * from the tool results already in the transcript — so the turn delivers a reply instead of trailing off\n * mid-narration. Deliberately not a \"summarize what you did\" nudge: that produced process reports and\n * permission-asking instead of answers (see the nudge text in runLoop).\n * Fires at most once per run and only for delegated runtimes (native turns never emit the trigger). */\n closeDelegatedTurns = true;\n /** Catch a FABRICATED tool use: a turn that emits no tool call at all, yet whose text names an advertised\n * tool this run has never actually invoked — the model announcing `look_at_app` and then writing its own\n * \"it didn't respond in time\" result. No call-reactive layer can see it (there IS no call), and to every\n * surface it is indistinguishable from a real failure. The discriminator is the per-run invocation ledger,\n * not prose: a named tool with zero invocations is provable. On detection the loop nudges ONCE for a real\n * call, and records the names in `RunResult.fabricatedToolClaims` either way. */\n catchFabricatedToolUse = true;\n /** Fold the dropped middle of an over-long transcript into a synthetic summary (edge-safe, no LLM). Off => drop-oldest. */\n compaction?: { maxMessages: number };\n /** Add `Checkpoint`/`Rollback` tools (requires the fs to be an OverlayFilesystem). */\n checkpoints = false;\n /** Enable `bash({background:true})` + JobOutput/JobStatus/JobKill — sandbox background jobs (overlay-isolated,\n * committed on completion, drained at turn end). Useful when the VFS backend is slow (remote) or for sub-agents. */\n backgroundJobs = false;\n /** Plan mode: block mutating tools until the agent calls `ExitPlanMode` (host-approved). */\n planMode = false;\n /** Permission policy gating each tool call (allow / ask / deny). */\n permissions?: PermissionPolicy;\n /** Opt-in syntax guardrail: refuse to persist a syntactically-broken code-file write/edit. Default off. */\n lintOnWrite?: boolean;\n /** Optional PDF text extraction for Read on .pdf files (node hosts wire pdftotext); absent => Read explains. */\n pdfText?: (path: string) => Promise<string>;\n /** Opt-in: after a write-class tool runs, run `command` over the VFS and append any failure to the tool result.\n * `tools` defaults to ['Write','Edit','MultiEdit','ApplyEdits']. */\n autoTest?: { command: string; tools?: string[] };\n /** Provider-specific options forwarded to ai.chat() (e.g. cursor mcpServers, cwd). */\n providerOptions?: Record<string, unknown>;\n /** Derive `providerOptions` for a DELEGATED child whose model may differ from this agent's\n * (`Task({ model })` / an agentType def). Default: inherit `providerOptions` only when the child's\n * model is on the SAME provider — cursor's `cwd`/`cursorSession` on an anthropic child is a 400. */\n providerOptionsFor?: (model: string) => Record<string, unknown> | undefined;\n /** Prompt caching (providers that support it, e.g. Anthropic): cache tools/system/conversation\n * prefix across the loop's steps — reads cost 0.1x, writes 1.25x. A multi-step agent loop\n * re-sends its whole prefix every step, so this is a large net cost cut. Default on. */\n promptCache = true;\n /** Tool selection mode: 'auto' = model decides (needed for Groq); undefined = provider default. */\n toolChoice?: 'auto' | 'required' | 'none';\n /** Extended-thinking / reasoning effort, normalized across providers (anthropic, openai).\n * `'off'`/undefined = none; `'low'|'medium'|'high'` or a raw token budget. Mapped to the\n * provider-specific request shape via {@link reasoningToChatFragment}; explicit `providerOptions` wins. */\n reasoning?: ReasoningEffort;\n /** Seed a fresh `run()` with prior conversation turns (real role/content messages) so the model\n * sees history as structured turns instead of a flattened text blob. They are inserted AFTER the\n * stable system prompt and BEFORE the current user turn — so the cached system(+tools) prefix never\n * shifts. Turns are normalized before sending (empties dropped, adjacent same-role coalesced, and the\n * first tail turn forced to `user`) so the transcript is always a valid Anthropic alternation ending\n * at the current user prompt. Unset/empty ⇒ current behavior, byte-for-byte. */\n priorMessages?: Array<{ role: 'user' | 'assistant'; content: MessageContent }>;\n}\n\n/** Normalize seed history + the live prompt into a valid alternating tail (the messages that follow the\n * system turn). Drops empties, coalesces adjacent same-role turns, guarantees the first turn is `user`\n * (Anthropic requires the first non-system message to be user) and that the sequence ends at `current`.\n * Empty `prior` ⇒ `[{ user: current }]` — identical to the pre-priorMessages transcript. */\nfunction seedTranscriptTail(\n prior: Array<{ role: 'user' | 'assistant'; content: MessageContent }> | undefined,\n current: MessageContent,\n): Message[] {\n const seq: Message[] = (prior ?? [])\n .filter((m) => contentText(m.content).trim().length > 0)\n .map((m) => ({ role: m.role, content: m.content }));\n seq.push({ role: 'user', content: current });\n const out: Message[] = [];\n for (const m of seq) {\n const last = out[out.length - 1];\n if (last && last.role === m.role) {\n if (typeof last.content === 'string' && typeof m.content === 'string') {\n last.content = `${last.content}\\n\\n${m.content}`; // merge same-role text turns\n continue;\n }\n // multimodal boundary (can't concat) — insert a neutral opposite-role spacer to keep alternation\n out.push({ role: m.role === 'user' ? 'assistant' : 'user', content: '(continuing)' });\n }\n out.push({ role: m.role, content: m.content });\n }\n if (out.length && out[0].role !== 'user') out.unshift({ role: 'user', content: '(Earlier conversation)' });\n return out;\n}\n\n/**\n * The agentic loop: chat() -> dispatch tool_calls over the VFS -> thread results\n * back -> repeat until the model stops (no tool calls) or maxSteps is hit.\n */\nexport class Agent {\n public options: AgentOptions;\n public transcript: Message[] = [];\n private ctx!: ToolContext; // built in the ctor when `fs` is provided, else lazily in ensureFs()\n private lastTrimNotified = 0; // last auto-trim drop count surfaced via host.notify (dedup)\n private activeTools: AgentTool[] = [];\n /** Per-run ground truth: every tool name actually INVOKED this run (native dispatch + delegated\n * runtime activity). The ledger that makes a fabricated tool claim provable. Reset per run. */\n private invokedTools = new Set<string>();\n /** Advertised tools this run's text claimed to have used while the ledger showed zero calls. */\n private fabricatedClaims = new Set<string>();\n private activeHooks?: Hooks; // composed: user hooks + plan-mode + permissions\n private prepared = false; // memo guard: prompt/tools/plan-state built once per conversation\n private systemPromptCache = ''; // the assembled system prompt from the last prepare()\n private started = false; // session-start lifecycle hook fires once per conversation\n private parkedMs = 0; // cumulative time blocked on the HUMAN (permission/plan prompts) — excluded from the timeout\n private browserActive = false; // flips true once a browser MCP tool is actually invoked → adaptive trimming engages (browserTrim)\n\n /** Time a human-blocking await (a permission/plan prompt) and bank it in `parkedMs` so idle prompt\n * time never trips the wall-clock kill-switch. The agent did no work while parked on the user. */\n private async park<T>(p: Promise<T>): Promise<T> {\n const t = Date.now();\n try { return await p; } finally { this.parkedMs += Date.now() - t; }\n }\n\n /** Force the next `send()`/`run()` to rebuild the system prompt, tools, plan-mode and permission hooks\n * from `options` — apply mid-conversation changes to `planMode`/`permissions`/`model` etc. (prepare()\n * is otherwise memoized per conversation). */\n reprepare(): void { this.prepared = false; }\n\n /** Tools injected via addTools(); kept separate from options.tools so prepare() rebuilds don't drop them. */\n private injectedTools: AgentTool[] = [];\n\n /** Current tool surface for hosts/UIs (configured + injected, deduped by name) — options.tools\n * alone misses addTools()-injected ones (e.g. MCP servers mounted after startup). */\n get toolNames(): string[] {\n return [...new Set([...(this.options.tools ?? []), ...this.injectedTools].map((t) => t.name))];\n }\n\n /** Inject tools into a running agent (e.g. dynamically mounted MCP servers). Takes effect on the next turn\n * and survives prepare() rebuilds (reprepare(), new conversations). */\n addTools(tools: AgentTool[]): void {\n this.injectedTools.push(...tools);\n this.activeTools.push(...tools);\n }\n\n /** Remove tools by name from a running agent. Returns the count removed. Also filters\n * `options.tools` — otherwise a constructor-passed tool resurrects on the next prepare()\n * rebuild (and re-adding it via addTools() would then DUPLICATE it in the wire schema). */\n removeTools(names: Set<string> | string[]): number {\n const s = names instanceof Set ? names : new Set(names);\n const before = this.activeTools.length;\n this.activeTools = this.activeTools.filter((t) => !s.has(t.name));\n this.injectedTools = this.injectedTools.filter((t) => !s.has(t.name));\n if (this.options.tools) this.options.tools = this.options.tools.filter((t) => !s.has(t.name));\n return before - this.activeTools.length;\n }\n\n /** Messages the host queued to steer the RUNNING turn (Claude-Code-style mid-turn input). The loop\n * drains them at each step boundary — after tool results are appended, before the next model call —\n * so they ride along with the latest tool results. A no-op between turns (nothing drains it). */\n private pendingInjections: MessageContent[] = [];\n\n /** Queue a user message into the in-flight turn. It lands as a `user` message at the next step\n * boundary; if the model was about to stop, the injection re-opens the loop so it's never lost.\n * Pushing onto `transcript` directly from outside would race the loop — this drains inside it. */\n inject(content: MessageContent): void { this.pendingInjections.push(content); }\n\n /** Drop any queued-but-unconsumed injections. The REPL calls this after a LOCAL command (/cmd, !bash)\n * — which runs no send() to drain them — so a mid-command steer can't leak into the next real turn. */\n clearInjections(): void { this.pendingInjections.length = 0; }\n\n /** Pull queued injections that are plain TEXT, removing them, for a runtime that can accept mid-turn\n * steers over its own channel (claude-code's warm InputQueue via `providerOptions.steer`). Non-text\n * injections (images) stay queued for the step-boundary `drainInjections()` re-open — the text-only\n * steer channel can't carry them. Consumed DURING chat(); no overlap with drainInjections() (post-call). */\n drainPendingSteers(): string[] {\n if (!this.pendingInjections.length) return [];\n const texts: string[] = [];\n this.pendingInjections = this.pendingInjections.filter((c) => {\n if (typeof c === 'string') { texts.push(c); return false; }\n return true; // keep non-text (image parts) for the transcript-injection path\n });\n return texts;\n }\n\n /** Fold any host-injected messages into the transcript as user turns. Returns true if any landed. */\n private drainInjections(): boolean {\n if (!this.pendingInjections.length) return false;\n for (const content of this.pendingInjections.splice(0)) this.transcript.push({ role: 'user', content });\n return true;\n }\n\n constructor(options?: Partial<AgentOptions>) {\n this.options = { ...new AgentOptions(), ...options } as AgentOptions;\n if (this.options.fs) this.buildCtx(); // fs provided → build the tool context now (sync, unchanged behavior)\n }\n\n /** Build the tool context from the resolved fs + options. Idempotent-safe: called once (ctor or ensureFs). */\n private buildCtx(): void {\n this.ctx = makeContext(this.options.fs!, this.options.host);\n this.ctx.signal = this.options.signal; // expose run-cancellation to abort-aware tools (e.g. real shell)\n if (this.options.lintOnWrite) this.ctx.lint = checkSyntax; // opt-in syntax guardrail\n if (this.options.pdfText) this.ctx.pdfText = this.options.pdfText; // host-wired PDF text extraction (Read on .pdf)\n this.ctx.ai = this.options.ai; // expose model to tools that run their own LLM pass (e.g. Review)\n this.ctx.model = this.options.model;\n this.ctx.parkHuman = (p) => this.park(p); // route interactive tools' human-waits into the parked-time accumulator\n if (this.options.backgroundJobs) this.ctx.jobs = new SandboxJobRegistry(); // enables bash({background:true})\n }\n\n /**\n * Resolve the filesystem + build the tool context if the ctor couldn't (no `fs` was passed). The disk\n * default lives HERE, not in the ctor: the ctor can't await, and we must avoid a STATIC `node:fs` import\n * in the core (edge/browser would break). The dynamic import only fires when `fs` is omitted — edge code\n * always passes its own `MemFilesystem`, so the node module is never reached. Default = jailed disk @ cwd.\n */\n private async ensureFs(): Promise<void> {\n if (this.ctx) return; // already built (fs was provided to the ctor, or a prior run resolved it)\n if (!this.options.fs) {\n const { NodeDiskFilesystem } = await import('./NodeDiskFilesystem');\n const { JailedFilesystem } = await import('./JailedFilesystem');\n const disk = new NodeDiskFilesystem(process.cwd());\n await disk.init();\n this.options.fs = new JailedFilesystem(disk); // DEFAULT_DENY hides secrets out of the box\n log.info(`no fs provided — defaulting to jailed real disk at ${process.cwd()}`);\n }\n this.buildCtx();\n }\n\n /**\n * Assemble the system prompt + active tools/hooks ONCE per conversation (memoized).\n * `run()` resets the memo to start fresh; `send()` reuses it, so multi-turn state —\n * plan-mode approval, the tool set, the skills/commands/memory snapshot — stays stable\n * across turns (and the frozen prompt pairs well with prompt caching). Does NOT touch\n * the transcript; `run`/`send` own that.\n */\n private async prepare(taskHint?: string): Promise<string> {\n if (this.prepared) return this.systemPromptCache;\n const o = this.options;\n const fs = o.fs!; // resolved by ensureFs() before any run()/send() reaches prepare()\n let systemPrompt = o.systemPrompt;\n let tools = o.tools;\n if (o.instructionFiles !== false) {\n const names = Array.isArray(o.instructionFiles) ? o.instructionFiles : undefined;\n const ins = await loadInstructions(fs, names);\n if (ins) systemPrompt += '\\n\\n' + ins;\n }\n if (o.memoryDir) {\n // taskHint floats the most task-relevant learnings to the top of a large index; the rest\n // collapse to slugs (still Recall-able) — bounds tokens as learnings accumulate over time.\n const { index, tools: memTools } = await loadMemory(fs, o.memoryDir, { relevanceHint: taskHint, userDir: o.memoryUserDir });\n if (index) systemPrompt += '\\n\\n' + index; // hot: compact (ranked) index always injected\n tools = [...tools, ...memTools]; // cold: Recall (pull fact) + Remember (persist fact)\n }\n // Merged slash namespace (CC parity): each tool cross-resolves into the other registry on a\n // miss, so `/x` works whether x is a command or a skill regardless of which tool the model picks.\n const skillsDir = o.skillsDir, commandsDir = o.commandsDir;\n if (skillsDir) {\n // taskHint floats the most relevant skills to the top of a large catalog; full set stays loadable by name.\n const sibling = commandsDir\n ? async (name: string) => {\n const c = (await scanCommands(fs, commandsDir)).find((x) => x.name === name);\n return c ? { path: c.path, stripFrontmatter: true } : undefined;\n }\n : undefined;\n const { catalog, tool } = await loadSkills(fs, skillsDir, { relevanceHint: taskHint, sibling });\n if (catalog) systemPrompt += '\\n\\n' + catalog;\n if (tool) tools = [...tools, tool];\n }\n if (commandsDir) {\n const sibling = skillsDir\n ? async (name: string) => {\n const s = (await scanSkills(fs, skillsDir)).find((x) => x.name === name);\n return s ? { path: s.path, stripFrontmatter: false } : undefined;\n }\n : undefined;\n const { catalog, tool } = await loadCommands(fs, commandsDir, { relevanceHint: taskHint, sibling });\n if (catalog) systemPrompt += '\\n\\n' + catalog;\n if (tool) tools = [...tools, tool];\n }\n if (o.host && o.askUserQuestion) tools = [...tools, askUserQuestionTool];\n if (o.subagents) {\n let agents: Awaited<ReturnType<typeof loadAgents>>['agents'] | undefined;\n if (o.agentsDir) {\n const loaded = await loadAgents(fs, o.agentsDir);\n agents = loaded.agents;\n if (loaded.catalog) systemPrompt += '\\n\\n' + loaded.catalog;\n }\n // The child inherits the HOST-configured toolbelt (o.tools + addTools) and system prompt — not the\n // derived memory/skills/commands tools, which are closed over THIS agent's fs (they'd keep writing\n // to THIS agent's stores no matter where the child runs). Without this a child fell back to jailed\n // defaultTools(). Inherited tools that escape the VFS are re-bound per child: `subagent.ts` calls\n // `AgentTool.withCwd` so a worktree child's real Shell runs in the WORKTREE, not the parent repo.\n // An overlay child's Shell cannot be isolated at all (an overlay is a VFS layer, not a process\n // jail) — the Task/TaskBatch descriptions say so instead of promising isolation we can't keep.\n const taskOpts = {\n ai: o.ai, model: o.model, fs, depth: o.depth, maxDepth: o.maxDepth, agents, hooks: o.hooks, traceDir: o.traceDir,\n tools: [...o.tools, ...this.injectedTools],\n systemPrompt: o.systemPrompt,\n providerOptionsFor: o.providerOptionsFor ?? ((m: string) => (modelProvider(m) === modelProvider(o.model) ? o.providerOptions : undefined)),\n };\n tools = [...tools, makeTaskTool(taskOpts), makeTaskBatchTool(taskOpts)];\n }\n if (o.checkpoints) tools = [...tools, ...checkpointTools()];\n if (this.ctx.jobs) tools = [...tools, ...makeJobTools(this.ctx.jobs)]; // JobOutput/JobStatus/JobKill\n const plan = o.planMode ? planMode({ host: o.host }) : undefined; // gates mutating tools until approved\n if (plan) tools = [...tools, plan.tool];\n this.activeHooks = composeHooks(o.hooks, plan?.hooks, o.permissions?.hooks());\n this.activeTools = [...tools, ...this.injectedTools]; // injected (addTools) survive the rebuild\n this.systemPromptCache = systemPrompt;\n this.prepared = true;\n return systemPrompt;\n }\n\n /** Single-shot: reset all per-conversation state and run `task` to completion. `task` may be plain\n * text or multimodal content parts (text + images). */\n async run(task: MessageContent): Promise<RunResult> {\n await this.ensureFs(); // resolve the disk default (if no fs was passed) before prepare reads o.fs\n this.prepared = false; // fresh conversation → rebuild prompt + tools + plan-mode state\n this.started = false;\n this.invokedTools.clear(); // fresh conversation → fresh ground truth (a `send()` continuation KEEPS the\n this.fabricatedClaims.clear(); // ledger on purpose: naming a tool it really called last turn is honest)\n const systemPrompt = await this.prepare(contentText(task)); // task text hints catalog relevance\n const startCtx = await this.fireSessionStart(); // [lifecycle] once-per-session context injection\n const userContent = await this.applyPromptSubmit(task); // [lifecycle] per-turn prompt rewrite (text only)\n this.transcript = [\n { role: 'system', content: systemPrompt + (startCtx ? '\\n\\n' + startCtx : '') },\n // Prior turns (if any) sit between the stable system prefix and the live user turn — the cached\n // system(+tools) prefix is unaffected; normalization keeps the alternation valid.\n ...seedTranscriptTail(this.options.priorMessages, userContent),\n ];\n return this.runLoop();\n }\n\n /** Apply onUserPromptSubmit to a turn: rewrite plain text; pass multimodal content through untouched. */\n private async applyPromptSubmit(task: MessageContent): Promise<MessageContent> {\n return typeof task === 'string' ? await this.fireUserPromptSubmit(task) : task;\n }\n\n /** Fire onSessionStart once per conversation; returns any injected context. */\n private async fireSessionStart(): Promise<string | undefined> {\n if (this.started) return undefined;\n this.started = true;\n const ctx = await this.activeHooks?.onSessionStart?.();\n return typeof ctx === 'string' && ctx ? ctx : undefined;\n }\n\n /** Fire onUserPromptSubmit; returns the (possibly rewritten) prompt text. */\n private async fireUserPromptSubmit(task: string): Promise<string> {\n const r = await this.activeHooks?.onUserPromptSubmit?.(task);\n return typeof r === 'string' ? r : task;\n }\n\n /**\n * Multi-turn: continue the existing conversation by appending a user turn instead of\n * resetting — this is what makes an interactive REPL feel like one conversation. The\n * leading system message is (re)synced to the current prompt, so a resumed session whose\n * tools were rebuilt gets a matching catalog rather than a stale one.\n */\n async send(task: MessageContent): Promise<RunResult> {\n await this.ensureFs(); // resolve the disk default (if no fs was passed) before prepare reads o.fs\n const systemPrompt = await this.prepare(contentText(task)); // first turn's task hints catalog relevance; frozen thereafter (memoized → cache-stable)\n const startCtx = await this.fireSessionStart(); // [lifecycle] first send() of a fresh agent counts as session start\n const userContent = await this.applyPromptSubmit(task);\n const sys = systemPrompt + (startCtx ? '\\n\\n' + startCtx : '');\n if (this.transcript[0]?.role === 'system') this.transcript[0] = { role: 'system', content: sys };\n else this.transcript.unshift({ role: 'system', content: sys });\n this.transcript.push({ role: 'user', content: userContent });\n return this.runLoop();\n }\n\n /**\n * Fold the conversation in place (manual `/compact`) until it fits a TOKEN budget — not a message\n * count. Message-count folding alone frees almost nothing when a few recent tool results are huge,\n * so we escalate: fold the middle into a synthetic recap → elide oversized tool-result bodies in the\n * retained window → halve the window → drop-oldest backstop. Deterministic, no LLM call.\n * `focus` (e.g. `/compact keep the API details`) preserves matching lines from the dropped span verbatim.\n * Returns before/after token estimates so the caller can report honestly (0 freed => say so).\n */\n compactNow(maxMessages = 12, focus?: string): CompactResult {\n const cap = Agent.contextCap(this.options);\n const target = Math.round(cap * Agent.COMPACT_TARGET);\n // Budget on the WIRE view (same estimator as /context + the footer) — see estimateTokens.\n const kr = this.options.keepRecentImages ?? 1;\n const tokensBefore = estimateTokens(this.transcript, kr);\n const msgsBefore = this.transcript.length;\n let max = Math.max(2, maxMessages);\n // Nothing to fold AND already under budget: a genuine no-op. Return BEFORE onPreCompact — hooks that\n // persist a summary must not write a spurious one for a `/compact` that changes nothing.\n if (this.transcript.length <= max && tokensBefore <= target)\n return { tokensBefore, tokensAfter: tokensBefore, target, cap, removed: 0 };\n void this.activeHooks?.onPreCompact?.(this.transcript); // [lifecycle] observe before folding (fire-and-forget)\n let out = this.transcript;\n if (out.length > max) out = compact(out, max, focus);\n // Inline base64 can't be shaved, only dropped — so drop the whales FIRST. Otherwise a single oversized\n // screenshot is paid for by shredding cheap text messages further down the ladder.\n // The NEWEST image is spared on this pass: `releaseStaleImages(keepRecent = 1)` deliberately keeps it,\n // and a user who pastes a screenshot and then runs `/compact` must still be able to ask about it.\n if (estimateTokens(out, kr) > target) out = elideOversizedImages(out, target, true, kr);\n if (estimateTokens(out, kr) > target) out = capOversizedBodies(out, target, kr);\n // Only once the text ladder has done all it can does the newest image become fair game.\n if (estimateTokens(out, kr) > target) out = elideOversizedImages(out, target, false, kr);\n // Still over (e.g. one giant user paste / assistant reply): halve the window, re-capping each pass.\n while (estimateTokens(out, kr) > target && max > 2 && out.length > 2) {\n max = Math.max(2, Math.floor(max / 2));\n out = capOversizedBodies(compact(out, max, focus), target, kr);\n }\n if (estimateTokens(out, kr) > target) out = fitTokenBudget(out, target, kr); // drop-oldest backstop\n out = dropOrphanToolResults(out); // never leave a tool_result whose tool_call was folded away\n this.transcript = out;\n this.releaseStaleImages(); // stale inline base64 is dead weight in the folded transcript too\n // Measure the transcript we actually kept (releaseStaleImages may have shrunk it further).\n return { tokensBefore, tokensAfter: estimateTokens(this.transcript, kr), target, cap, removed: msgsBefore - this.transcript.length };\n }\n\n /** Drop inline base64 images from older messages so Bun/JSC can reclaim the heap (see contentBytes). */\n releaseStaleImages(keepRecent = 1): void {\n const next = elideStaleImages(this.transcript, keepRecent);\n if (next !== this.transcript) this.transcript = next;\n }\n\n private async runLoop(): Promise<RunResult> {\n const o = this.options;\n const wireTools = toWireTools(this.activeTools);\n // Stream only when explicitly requested AND a host can render deltas; else stay on the non-stream path.\n const useStream = o.stream === true && typeof o.host?.notify === 'function';\n let steps = 0;\n const usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };\n let usageEstimated = false; // flips true the first turn a provider returns no usage and we estimate\n const start = Date.now();\n this.parkedMs = 0; // reset per run: only THIS run's human-wait is excluded from the timeout\n this.ctx.needsInput = undefined; // reset per run: a question answered last run must not re-stop this one\n let toolCallsTotal = 0; // cumulative tool calls dispatched\n let lastFp = ''; // fingerprint of the previous tool-call batch\n let repeats = 0; // consecutive identical batches\n let closureNudged = false; // closeDelegatedTurns: the closure reflex fires at most once per run\n // Progress clock: `timeoutMs` bounds IDLE time (since last productive step), not total run length —\n // a single extended-thinking step can legitimately exceed the whole-run ceiling while actively\n // streaming reasoning (stallMs keeps that in-flight turn alive), so an absolute wall-clock would kill\n // completed, productive work. Runaway-but-active loops stay covered by maxSteps/maxToolCalls/maxRepeats/budget.\n let lastProgressAt = start;\n // Single exit for every kill-switch: warn + return a result carrying the reason.\n const kill = (finishReason: RunResult['finishReason']): RunResult => {\n log.warn(`kill-switch: ${finishReason} (steps=${steps}, tokens=${usage.totalTokens}, budgetTokens=${Math.round(usage.totalTokens - 0.9 * usage.cacheReadTokens)}, ms=${Date.now() - start - this.parkedMs}${finishReason === 'timeout' ? `, idle=${Date.now() - lastProgressAt - this.parkedMs}ms` : ''}${this.parkedMs ? ` +${this.parkedMs} parked` : ''})`);\n this.ctx.jobs?.killAll(); // abort background jobs (don't commit) — a budget/timeout kill shouldn't leak writes\n const claims = this.survivingClaims();\n return { text: lastAssistantText(this.transcript), steps, finishReason, messages: this.transcript, usage, usageEstimated, ...(claims.length ? { fabricatedToolClaims: claims } : {}) };\n };\n\n while (true) {\n if (o.signal?.aborted) return kill('aborted');\n if (steps >= o.maxSteps) return kill('max_steps');\n if (o.timeoutMs && Date.now() - lastProgressAt - this.parkedMs >= o.timeoutMs) return kill('timeout'); // idle-since-last-progress: an active/long step resets the clock; parked prompt time excluded\n // Budget = cost proxy, not raw volume: cache reads are ~10% of fresh-token price, and a fat cached\n // context (MCP schemas + big tool results) re-counts every step — at full weight a healthy ~25k-ctx\n // session dies near step 8. Weighting reads at 0.1 keeps runaway protection (fresh tokens count full).\n const budgetTokens = usage.totalTokens - 0.9 * usage.cacheReadTokens;\n if (o.maxTokens && budgetTokens >= o.maxTokens) return kill('budget');\n steps++;\n this.options.host?.notify?.({ kind: 'turn_start', message: `step ${steps}` });\n\n let res: ChatResponse;\n const sent = this.trimContext(); // the exact context sent this turn (reused for usage estimation)\n // Normalized reasoning → provider request shape; explicit providerOptions overrides the derived one.\n const frag = reasoningToChatFragment(o.model, o.reasoning);\n // claude-code/* is an autonomous runtime (Claude Agent SDK) that runs its OWN tools inside its\n // subprocess and rejects host-defined tool schemas — send none. External tools reach it via\n // providerOptions.mcpServers (wired by the CLI's claudeCodeProviderOptions). Mirror of cursor below.\n const sentTools = o.model.startsWith('claude-code/') ? [] : wireTools;\n // Cursor is an agent runtime — bridge host tools via IPC-based toolExecutor callback.\n const isCursorWithTools = o.model.startsWith('cursor/') && wireTools.length > 0;\n // Transport deadline with STRUCTURAL headroom over the slowest tool we actually registered. The\n // helper's watchdog used to be a bare 120_000 — identical to the Shell tool's own default cap — so\n // both fired at once, the transport won, and the shell tool's real `[exit 124] timed out ...`\n // result was replaced by an empty string the model could learn nothing from. Derived, never typed twice.\n //\n // FLOORED, because `maxDurationMs` is opt-in: a tool that does not declare one is NOT thereby prompt\n // (McpCall, Task and any host tool contribute 0), and deriving from declarers alone made declaring\n // Shell's 600s *lower* the deadline below the transport's own 30m default — an undeclared hung call\n // then had less headroom than before anyone declared anything. The floor is the transport default;\n // a declaration can only raise it.\n const hostToolTimeoutMs = (o.providerOptions as any)?.toolTimeoutMs;\n const derivedToolTimeoutMs = Math.max(TRANSPORT_TOOL_TIMEOUT_FLOOR_MS, ...this.activeTools.map(transportHeadroomMs)); // activeTools, not wireTools — the wire schema drops maxDurationMs\n // A host that sets providerOptions.toolTimeoutMs explicitly WINS — but only UPWARD. It cannot own\n // what it cannot see: `maxDurationMs` is assembled at run time from defaultTools() + preset shell +\n // addTools() + MCP discovery, so a host picking a number is picking it against a tool set it never\n // enumerates. Setting it BELOW the derived floor has exactly one consequence — the transport wins the\n // race and the tool's real result is replaced by '' — i.e. it re-creates, by configuration, the very\n // bug this fix removed, and does so silently-and-late (the warn scrolls past at step 1, the\n // destruction lands at step 6). So the escape hatch stays open in the only direction that helps:\n // raising the deadline. Clamped, not merely reported.\n const effectiveToolTimeoutMs = typeof hostToolTimeoutMs === 'number' ? Math.max(hostToolTimeoutMs, derivedToolTimeoutMs) : derivedToolTimeoutMs;\n if (isCursorWithTools) {\n if (typeof hostToolTimeoutMs === 'number' && effectiveToolTimeoutMs !== hostToolTimeoutMs) {\n log.warn(`providerOptions.toolTimeoutMs=${hostToolTimeoutMs}ms is below what the registered tools need — RAISED to ${effectiveToolTimeoutMs}ms.`\n + ` ${toolTimeoutViolations(this.activeTools, hostToolTimeoutMs).length} tool(s) could outlive it, and the transport would have destroyed their results.`\n + ` To lower it, lower the tools' own maxDurationMs (e.g. the Shell tool's maxTimeoutMs) instead.`);\n }\n // ASSERTED, not assumed: a tool that can outlive the transport deadline is exactly the collision\n // this whole fix removed. After the clamp this must be empty — keep it as the belt-and-braces check.\n for (const v of toolTimeoutViolations(this.activeTools, effectiveToolTimeoutMs)) log.warn(v);\n }\n const cursorPo = isCursorWithTools ? {\n toolTimeoutMs: effectiveToolTimeoutMs,\n toolExecutor: async (name: string, args: Record<string, any>) => {\n const tc = { id: `cursor-${Date.now()}`, type: 'function' as const, function: { name, arguments: JSON.stringify(args) } };\n // Return the FULL result, images included. The cursor adapter relays it to the helper,\n // which turns `{text, images}` into the SDK's tool-result content blocks. Flattening to\n // `.text` here (as this did) silently dropped every picture a tool produced — the model\n // got \"here is the app as it is rendering right now\" with no image, on cursor/* models\n // that are the DEFAULT for some hosts. The native loop below does the same via imagePart.\n return await this.dispatch(tc);\n },\n } : undefined;\n // claude-code warm sessions accept mid-turn steers via a `steer` pull source (the adapter drains it\n // into the SDK's InputQueue). Route text injections through it so they reach the live warm session;\n // non-text injections (and any that land after the last drain) fall through to the step-boundary re-open.\n const claudeSteerPo = o.model.startsWith('claude-code/') ? { steer: () => this.drainPendingSteers() } : undefined;\n const reasonOpts = {\n ...frag,\n ...(o.promptCache ? { promptCache: true } : {}),\n ...(o.providerOptions || cursorPo || claudeSteerPo ? { providerOptions: { ...frag.providerOptions, ...o.providerOptions, ...cursorPo, ...claudeSteerPo } } : {}),\n };\n try {\n // One step = one model call; a TRANSIENT network drop (mid-stream or pre-flight) retries the\n // step from the last committed transcript state instead of failing the whole turn. Server-side\n // transient HTTP errors (5xx/408/overloaded) retry too; 4xx like rate limits are NOT retried\n // here — the AIClient's own rate-limit retry handles those.\n for (let attempt = 0; ; attempt++) {\n try {\n if (useStream) {\n // Guard the whole request (time-to-first-chunk + inter-chunk gaps) with an idle-stall\n // watchdog: if the provider goes silent past o.stallMs, abort THIS request via a linked\n // controller so the loop can retry the step instead of hanging inside `chat()` forever.\n const stall = this.armStallWatchdog(o.signal, o.stallMs);\n try {\n const r = await o.ai.chat({ model: o.model, messages: sent, tools: sentTools, stream: true, signal: stall.signal, ...(o.toolChoice ? { toolChoice: o.toolChoice } : {}), ...reasonOpts });\n res = await this.consumeStream(r as AsyncIterable<StreamChunk>, stall.poke);\n // A watchdog-fired abort is a STALL even when the provider ends its stream CLEANLY on\n // abort instead of throwing (the cursor adapter releases the consumer with a normal end).\n // Without this check that clean end fell through to the empty-stop guard below and a\n // silent provider was retried as `code:'empty'` 5× and reported as finishReason:'empty'.\n if (stall.stalled()) throw stall.reclassify(undefined);\n } catch (err) {\n throw stall.reclassify(err); // a watchdog-fired abort → Error{code:'stall'}; parent/user aborts pass through\n } finally {\n stall.clear();\n }\n } else {\n const r = await o.ai.chat({ model: o.model, messages: sent, tools: sentTools, stream: false, signal: o.signal, ...(o.toolChoice ? { toolChoice: o.toolChoice } : {}), ...reasonOpts });\n res = r as ChatResponse;\n }\n // Empty-stop guard: a ZERO-WORK turn — the model went silent on the FIRST call, committing\n // nothing to the transcript, yet downstream would report it as a successful \"done\" (the real\n // agentx-composer \"spins then ✓ done · 0 tools\" incident). Scope to `steps === 1` (incremented\n // at the top of the loop, reset per-run): only the first model call can be zero-work, since any\n // later step follows tools/text already committed this turn — an empty wrap-up after real work\n // is a productive turn and must NOT be failed. Throw code:'empty' → the catch below retries it\n // through the SAME transient machinery (bounded by attempt<2); after the retries it propagates\n // to the outer catch which surfaces finishReason:'empty' (a failed turn), never a phantom stop.\n // Skip if a steer/injection is pending — that re-opens the turn naturally at the loop boundary.\n if (steps === 1 && this.isEmptyStop(res) && !this.pendingInjections.length) {\n const e = new Error('model returned an empty turn (finishReason=stop, no text, no tools)') as Error & { code: string };\n e.code = 'empty';\n throw e;\n }\n break;\n } catch (err) {\n const sc = (err as any)?.statusCode;\n const serverSide = sc >= 500 || sc === 408 || /Service Unavailable|overloaded|Internal server error|Bad gateway|Gateway time/i.test(String((err as any)?.message ?? ''));\n const network = !sc && /ECONNRESET|ECONNREFUSED|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|EPIPE|socket hang up|fetch failed|network|terminated|UND_ERR/i.test(String((err as any)?.message ?? (err as any)?.code ?? err));\n const stalled = (err as any)?.code === 'stall'; // watchdog-fired: provider went silent mid-stream\n // Empty/silent turn: agentx's own zero-work guard (code:'empty') OR a delegated runtime signalling\n // a wedged content-less session at the source (cursor adapter's code:'cursor_silent'). Both retry\n // through the SAME machinery on the WIDER empty budget — the adapter reaps the wedged warm helper\n // so each attempt spawns a fresh session.\n const empty = (err as any)?.code === 'empty' || (err as any)?.code === 'cursor_silent';\n // Empty gets its own (wider) attempt cap + backoff; network/server/stall keep the fixed budget of 2.\n const maxAttempts = empty ? Math.max(o.emptyRetries, 0) : 2;\n const transient = !o.signal?.aborted && !isAbortError(err) && attempt < maxAttempts && (network || serverSide || stalled || empty);\n if (!transient) throw err;\n const waitMs = (empty ? o.emptyRetryBaseMs : 1000) * (attempt + 1);\n log.warn(`${empty ? 'empty model turn' : stalled ? 'model stall' : 'network drop'} mid-step (${(err as any)?.message ?? err}) — retrying in ${waitMs}ms`);\n o.host?.notify?.({ kind: 'retry', message: `${empty ? 'model returned nothing' : stalled ? 'model stalled' : 'connection dropped'} — retrying step (#${attempt + 1})` });\n await new Promise((r) => setTimeout(r, waitMs));\n }\n }\n } catch (err) {\n // A budget-exhausted signal (e.g. proxy 429) is a clean stop, not a crash:\n // preserve the transcript so the run can be resumed once the cap is raised.\n if ((err as any)?.code === 'budget') return kill('budget');\n // Watchdog gave up after retries: the provider stayed silent. Clean stop (preserve transcript\n // for resume), labelled 'timeout' so it's diagnosable — not a crash, not a user 'aborted'.\n // `error` rides along (code:'stall') so a host can tell a provider stall from the between-steps idle ceiling.\n if ((err as any)?.code === 'stall') { log.warn(`model stalled out after retries: ${(err as any)?.message ?? err}`); return { ...kill('timeout'), error: err }; }\n // Abort wins over the empty/silent classification: an early barge-in of a cursor turn can surface as\n // a content-less end (code:'cursor_silent'), but a USER-aborted turn is 'aborted', never a failed\n // 'empty'. Check the signal FIRST. (The flag can LAG the throw under a barge-in race — the controller\n // fires, the provider rejects, but o.signal.aborted hasn't settled — so match the abort message too,\n // else a clean cancel is logged as a crash AND its \"operation was aborted\" string leaks onto the\n // spoken/utterance line.)\n if (o.signal?.aborted || isAbortError(err)) return kill('aborted');\n // Empty-stop after the bounded retries: the model kept returning nothing. Surface it as a failed\n // turn (finishReason:'empty' → the host prints ✗ / exits non-zero) instead of a phantom \"done\".\n if ((err as any)?.code === 'empty' || (err as any)?.code === 'cursor_silent') { log.warn(`model returned empty/silent turns after retries — surfacing as failed`); return { text: '', steps, finishReason: 'empty', messages: this.transcript, usage, usageEstimated, error: err }; }\n // surface the provider's human message (non-enumerable → lost by JSON.stringify); the bare\n // {code,statusCode} alone reads as a malformed request when it's often billing/quota (e.g. a 400\n // whose body is \"credit balance is too low\"). The raw response body carries that detail —\n // extract it onto the error so hosts/logs see WHY, not just the status code.\n const body = (err as any)?.body ?? (err as any)?.response?.data ?? (err as any)?.error;\n // try/catch: a circular body must not crash the error handler itself\n let bodyStr: string | undefined;\n try { bodyStr = body && typeof body !== 'string' ? JSON.stringify(body).slice(0, 2000) : (body as string | undefined); } catch { bodyStr = undefined; }\n if (bodyStr && err instanceof Error && !err.message.includes(bodyStr)) (err as any).detail = bodyStr;\n // Error properties are non-enumerable → JSON.stringify(err) = {} — serialize explicitly so logs are useful\n const errLog = err instanceof Error ? { message: err.message, ...((err as any).detail ? { detail: (err as any).detail } : {}), stack: err.stack } : err;\n log.error(`chat() failed: ${(err as any)?.message ?? err}${bodyStr ? ` — ${bodyStr}` : ''}`, errLog);\n return { text: '', steps, finishReason: 'error', messages: this.transcript, usage, usageEstimated, error: err };\n }\n // Cancelled mid-response → end the turn as 'aborted', not as a clean 'stop' on the partial reply.\n if (o.signal?.aborted) return kill('aborted');\n\n // ai.libx.js streaming doesn't surface token usage — estimate (~4 chars/token) so cost reporting\n // AND the maxTokens budget kill-switch still work when streaming (the CLI default). Non-stream\n // responses carry exact usage and are left untouched.\n if (!res.usage) {\n const promptTokens = estimateTokens(sent);\n const completionTokens = Math.ceil((contentText(res.content).length + (res.toolCalls ? JSON.stringify(res.toolCalls).length : 0)) / 4);\n res.usage = { promptTokens, completionTokens, totalTokens: promptTokens + completionTokens };\n usageEstimated = true;\n }\n if (res.usage) {\n usage.promptTokens += res.usage.promptTokens ?? 0; usage.completionTokens += res.usage.completionTokens ?? 0; usage.totalTokens += res.usage.totalTokens ?? 0;\n usage.cacheCreationTokens += (res.usage as any).cacheCreationTokens ?? 0; usage.cacheReadTokens += (res.usage as any).cacheReadTokens ?? 0;\n }\n // A delegated runtime (cursor/claude-code) ran its tools inside its own loop — they reach us only\n // as display-only toolActivity, never the transcript, leaving it narration-only (non-auditable and\n // blind on resume). Reconstruct assistant(tool_calls)+tool pairs so the transcript matches a native\n // turn's shape. Output trimmed via the SAME cap+cropResult path native results use. Pushed BEFORE\n // the final text (the runtime's summary came after its tools).\n const delegatedTools = res.delegatedTools ?? [];\n if (delegatedTools.length) {\n const cap = this.options.maxToolResultBytes ?? 0;\n this.transcript.push({\n role: 'assistant',\n content: '',\n tool_calls: delegatedTools.map((a) => ({ id: a.id, type: 'function' as const, function: { name: a.name || 'tool', arguments: (() => { try { return JSON.stringify(a.input ?? {}); } catch { return '{}'; } })() } })),\n });\n for (const a of delegatedTools) {\n const name = a.name || 'tool';\n // A delegated HOST tool returns dispatch()'s own shape — `{text, images}` — because the cursor\n // toolExecutor relays that verbatim. JSON-stringifying it turned every picture into a wall of\n // base64 text; rebuild image parts here exactly as the native loop does below.\n const r = delegatedResult(a.output);\n // The floor's invariant is MEANINGFUL content, not merely a non-empty string: `{}`, `[]` and an\n // empty MCP `{content:[]}` stringify to something non-empty that teaches the model exactly as\n // little as ''. Scalars a tool meant to return (a real 0, a real false) are meaningful and pass.\n // Images alone are a real result, so only floor the text when nothing else came.\n const text = r.images.length ? r.text : nonEmptyResult(isVacuous(a.output) ? '' : r.text, name, deliveryOf(a.output, a.status));\n const body = cap > 0 && text.length > cap ? cropResult(text, cap) : text;\n const content: MessageContent = r.images.length\n ? [{ type: 'text', text: body } as ContentPart, ...r.images.map((i) => imagePart(`data:${i.mimeType};base64,${i.data}`))]\n : body;\n this.transcript.push({ role: 'tool', tool_call_id: a.id, content });\n }\n }\n\n const toolCalls = res.toolCalls ?? [];\n // A turn with no tool calls AND no text is dead air — don't commit it to the transcript or count\n // it as a real response (it bills tokens but says/does nothing). The voice layer repairs the silence.\n // Delegated tools above are real work, so a turn that ran them is never \"empty\".\n const emptyTurn = toolCalls.length === 0 && delegatedTools.length === 0 && contentText(res.content ?? '').trim() === '';\n if (!emptyTurn) lastProgressAt = Date.now(); // productive step (text/tool/delegated) → reset the idle timeout window\n if (!emptyTurn) {\n // Reasoning is kept on the stored message ONLY for providers whose adapter passes it back\n // (DeepSeek 400s on a tool loop without it; Kimi loses its chain of thought). Tradeoff: it rides\n // along in the session file and counts toward context bytes — but it is a separate field, so\n // `content`-based rendering, summaries and compaction text never show it.\n this.transcript.push({\n role: 'assistant',\n content: res.content ?? '',\n ...(toolCalls.length ? { tool_calls: toolCalls } : {}),\n ...(res.reasoningContent && passesBackReasoning(o.model) ? { reasoning_content: res.reasoningContent } : {}),\n });\n }\n\n if (toolCalls.length === 0) {\n // A message injected while the model was composing its final reply re-opens the turn (CC\n // parity) instead of being lost to the post-turn queue — the model answers it in-place.\n if (this.drainInjections()) continue;\n // Closure reflex: a delegated runtime ended on a tool with no wrap-up. Nudge ONE closing step.\n // Ask for the ANSWER, not a process report: the tool records are already in the transcript, so a\n // \"summarize what you did\" phrasing made the model narrate its own turn (\"I ran 4 searches, they\n // were interrupted, want me to retry?\") instead of answering the user — and invited it to re-run\n // work it had already completed. Name those failure modes so it can't slide back into them. Do NOT\n // assert the results are complete (a tool may have errored) — that would push it to fabricate;\n // instead give it an explicit out to report the failure.\n // FABRICATION reflex. Sits BEFORE the closure reflex and shares its one-shot budget: both are the\n // same disease (a turn that reports work it did not do), and firing two nudges in a row would just\n // spend two metered steps. This one is checked first because it is the PROVABLE case — it names the\n // tool and can demand the actual call, where the closure nudge can only ask for an answer.\n // Reachability: this branch is inside `toolCalls.length === 0`, which is exactly the shape a\n // fabricated turn has — the guard is evaluated on the path the defect actually takes, not on a\n // sibling branch that a fabricating turn can never enter.\n // NOT gated on `delegatedTools.length === 0`. It was, and that made the guard DEAD on every\n // delegated backend: on `cursor/*` one chat() call IS the whole agent session, so its own tool\n // calls arrive as `toolActivity` and its final text arrives in the same response — meaning any\n // turn that did real work has `delegatedTools.length > 0` and the check never ran. That is\n // precisely the turn the defect was reported on (edit the app, then invent a `look_at_app`\n // failure). The conjunct was also unnecessary: delegated activity is recorded into\n // `invokedTools` as it streams, so a tool named in the text but absent from the ledger is\n // provably uncalled no matter who executed the rest of the turn.\n const fabricated = o.catchFabricatedToolUse && !closureNudged\n ? this.fabricatedToolNames(contentText(res.content ?? '')) : [];\n for (const n of fabricated) this.fabricatedClaims.add(n);\n if (fabricated.length && steps < o.maxSteps) {\n closureNudged = true;\n log.warn(`fabricated tool use: text names ${fabricated.join(', ')} but the run invoked ${this.invokedTools.size ? [...this.invokedTools].join(', ') : 'nothing'} — demanding the real call`);\n this.transcript.push({\n role: 'user',\n content: `You referred to ${fabricated.map((n) => `\\`${n}\\``).join(', ')} in your reply, but you never actually called `\n + `${fabricated.length > 1 ? 'those tools' : 'that tool'} — no tool call was made, so any result you reported for `\n + `${fabricated.length > 1 ? 'them' : 'it'} was invented. Either call `\n + `${fabricated.length > 1 ? 'them' : 'it'} for real now, or answer without ${fabricated.length > 1 ? 'them' : 'it'} and do `\n + `NOT claim any outcome — including a failure or a timeout — for a call you did not make.`,\n });\n continue;\n }\n if (o.closeDelegatedTurns && res.endedWithoutClosing && !closureNudged && steps < o.maxSteps) {\n closureNudged = true;\n log.verbose('delegated turn went silent after a tool — nudging a closing answer');\n this.transcript.push({\n role: 'user',\n content: 'You ran tools but did not reply. Answer the user now using the tool results above; '\n + 'if a tool failed, say so plainly. Do NOT re-run those tools, do NOT narrate what you did, '\n + 'and do NOT ask for permission to continue.',\n });\n continue;\n }\n log.verbose(`completed in ${steps} step(s)`);\n await this.ctx.jobs?.drain(); // let background jobs finish + commit before we call the run done (no lost writes)\n this.releaseStaleImages(); // inline screenshots are one-shot context — don't immortalize MB of base64\n await this.activeHooks?.onStop?.(res.content ?? ''); // [hooks] fire once on clean stop\n const claims = this.survivingClaims();\n return { text: res.content ?? '', steps, finishReason: 'stop', messages: this.transcript, usage, usageEstimated, ...(claims.length ? { fabricatedToolClaims: claims } : {}) };\n }\n\n // loop detection: the model emitting the same tool-call batch over and over.\n const fp = toolCalls.map((tc) => tc.function.name + ':' + (tc.function.arguments ?? '')).join('|');\n repeats = fp === lastFp ? repeats + 1 : 1;\n lastFp = fp;\n if (o.maxRepeats && repeats >= o.maxRepeats) return kill('loop');\n\n toolCallsTotal += toolCalls.length;\n if (o.maxToolCalls && toolCallsTotal > o.maxToolCalls) return kill('max_tool_calls');\n\n for (const tc of toolCalls) {\n if (o.signal?.aborted) return kill('aborted'); // cancelled mid-batch → don't run the rest\n const raw = await this.dispatch(tc);\n let content: MessageContent;\n if (typeof raw === 'string') { content = nonEmptyResult(raw, tc.function.name); }\n else {\n // Images alone are a real result; text alone is not, so only floor the text when nothing else came.\n const hasImages = !!raw.images?.length;\n const parts: ContentPart[] = [{ type: 'text', text: hasImages ? raw.text : nonEmptyResult(raw.text ?? '', tc.function.name) }];\n for (const img of raw.images ?? []) parts.push(imagePart(`data:${img.mimeType};base64,${img.data}`));\n content = parts;\n }\n this.transcript.push({ role: 'tool', tool_call_id: tc.id, name: tc.function.name, content });\n }\n // AskUserQuestion with no reachable human: stop and hand the question to the CALLER rather than\n // let the model pick for them. Runs AFTER the batch so the tool result is in the transcript —\n // the session persists cleanly and a resume continues from the answer. A clean pause, not a\n // kill: background jobs drain + commit (unlike kill(), which discards them).\n if (this.ctx.needsInput) {\n const question = this.ctx.needsInput;\n this.ctx.needsInput = undefined;\n log.warn(`needs_input: ${question.question} (steps=${steps})`);\n await this.ctx.jobs?.drain();\n const text = [\n `OPEN QUESTION (run paused — no human was reachable): ${question.question}`,\n ...question.options.map((o) => ` • ${o.label}${o.description ? ` — ${o.description}` : ''}`),\n ].join('\\n');\n return { text, steps, finishReason: 'needs_input', messages: this.transcript, usage, usageEstimated, question };\n }\n // Mid-turn steering: fold queued user input in after the tool results so the next model step\n // sees it alongside them (Claude-Code parity). No-op unless the host called inject() this step.\n this.drainInjections();\n }\n }\n\n /**\n * Drain a streamed chat() response: emit each text delta to the host\n * (`{kind:'text_delta'}`) and fold all chunks back into the single\n * ChatResponse the non-stream path would have returned.\n */\n /**\n * Idle-stall watchdog for one streamed model request. Returns a linked AbortController `signal` to\n * hand to `chat()`, a `poke()` to reset the idle timer on each chunk, a `reclassify()` that turns a\n * watchdog-fired abort into an Error{code:'stall'} (leaving a parent/user abort untouched), and a\n * `clear()` to disarm. Aborts the request if no `poke()` (or completion) happens within `stallMs`.\n * `stallMs = 0` disables the timer but still links parent-abort → child so cancellation propagates.\n */\n private armStallWatchdog(parent: AbortSignal | undefined, stallMs: number) {\n const ac = new AbortController();\n let fired = false;\n const onParentAbort = () => ac.abort();\n if (parent?.aborted) ac.abort();\n else parent?.addEventListener('abort', onParentAbort, { once: true });\n let timer: ReturnType<typeof setTimeout> | undefined;\n const stallError = () => {\n const e = new Error(`model stalled: no stream output for ${stallMs >= 1000 ? `${Math.round(stallMs / 1000)}s` : `${stallMs}ms`}`) as Error & { code: string };\n e.code = 'stall';\n return e;\n };\n const poke = () => {\n if (!stallMs) return;\n if (timer) clearTimeout(timer);\n // Abort WITH a coded reason: the provider sees `signal.reason.code === 'stall'` and can tell a\n // watchdog cancel (reap the silent session, retry fresh) from a user barge-in (keep it warm).\n timer = setTimeout(() => { fired = true; ac.abort(stallError()); }, stallMs);\n };\n poke(); // arm before the request so time-to-first-chunk is guarded too\n // Distinguish OUR abort (silent provider) from a parent/user cancel, which must stay an abort.\n const stalled = () => fired && !parent?.aborted;\n return {\n signal: ac.signal,\n poke,\n stalled,\n clear: () => { if (timer) clearTimeout(timer); parent?.removeEventListener('abort', onParentAbort); },\n reclassify: (err: unknown) => (stalled() ? stallError() : err),\n };\n }\n\n /** A clean-stop turn that carries no assistant text AND no tool calls (native or delegated) — a\n * non-result the model produced by going silent. Callers retry it rather than report \"done\". */\n private isEmptyStop(res: ChatResponse): boolean {\n const stop = res.finishReason === 'stop' || res.finishReason == null;\n return stop && (res.toolCalls?.length ?? 0) === 0 && (res.delegatedTools?.length ?? 0) === 0 && contentText(res.content ?? '').trim() === '';\n }\n\n private async consumeStream(stream: AsyncIterable<StreamChunk>, poke?: () => void): Promise<ChatResponse> {\n let content = '';\n let finishReason: string | undefined;\n let toolCalls: ToolCall[] | undefined;\n let usage: ChatResponse['usage'];\n // Delegated-runtime tools (cursor/claude-code loop internally) surface ONLY as display-only\n // toolActivity — accumulate + correlate by id (cursor: one `completed` event carrying everything;\n // claude-code: a `running` half with name+input, then a `completed`/`error` half with output) so\n // the loop can persist them into the transcript. First-seen order is preserved.\n const delegated = new Map<string, NonNullable<ChatResponse['delegatedTools']>[number]>();\n const delegatedOrder: string[] = [];\n // Closure signal: did the runtime CLOSE this turn? Track whether any tool ran and what assistant text\n // followed the LAST one. Trailing text alone isn't closure — cursor narrates as it works and its run\n // can settle while the narration is still mid-plan (\"Also checking for X.\"), so the turn looks closed\n // but answers nothing. Decided after the stream drains, from `sawTool` + `trailing`.\n let sawTool = false;\n let trailing = '';\n let reasoning = '';\n for await (const chunk of stream) {\n poke?.(); // progress arrived → reset the idle-stall watchdog\n if (this.options.signal?.aborted) break; // cancelled → stop emitting now; breaking also closes the stream\n // [G3] surface extended-thinking as a distinct channel (never folded into `content`). It is also\n // accumulated so the loop can keep it as `reasoning_content` for providers that need passback.\n if (chunk.reasoningContent) { reasoning += chunk.reasoningContent; this.options.host!.notify!({ kind: 'thinking_delta', message: chunk.reasoningContent }); }\n // Display-only tool activity from a self-executing backend (Cursor CLI runs its OWN tools) — surface\n // for host tool cards; never dispatched. `message` gives plain hosts a printable line.\n if (chunk.toolActivity) {\n const a = chunk.toolActivity;\n const verb = a.status === 'error' ? '✗' : a.status === 'completed' ? '✓' : '→';\n this.options.host!.notify!({ kind: 'tool_activity', id: a.id, name: a.name, input: a.input, output: a.output, status: a.status, truncated: a.truncated, message: `${verb} ${a.name}` });\n const key = a.id ?? `${a.name}:${delegatedOrder.length}`;\n const prev = delegated.get(key);\n if (!prev) { delegated.set(key, { id: key, name: a.name, input: a.input, output: a.output, status: a.status }); delegatedOrder.push(key); }\n else { // merge halves: the completed/error event carries output; the running one carries name/input\n if (a.name) prev.name = a.name;\n if (a.input !== undefined) prev.input = a.input;\n if (a.output !== undefined) prev.output = a.output;\n prev.status = a.status;\n }\n sawTool = true;\n this.invokedTools.add(a.name); // ledger: a delegated runtime's own tools are real calls too\n trailing = ''; // a tool just ran — only text AFTER it can close the turn\n }\n if (chunk.content) {\n content += chunk.content;\n trailing += chunk.content;\n this.options.host!.notify!({ kind: 'text_delta', message: chunk.content });\n }\n if (chunk.finishReason) finishReason = chunk.finishReason;\n if (chunk.toolCalls?.length) toolCalls = chunk.toolCalls; // accumulated, latest wins\n if (chunk.usage) usage = chunk.usage; // exact usage on the terminal chunk (providers that report it; else runLoop estimates)\n }\n const delegatedTools = delegatedOrder.map((k) => delegated.get(k)!);\n // Unclosed = tools ran and the turn either went silent after them or trailed off mid-plan.\n // Stays gated on `sawTool` ON PURPOSE. Ungating it to reach the announce-and-stop turn (which runs no\n // tools, so this flag can never see it) was tried and reverted: `endsOnAnnouncedAction` is prose\n // matching, and once it no longer needs a tool to have run it fires on ordinary conversation —\n // \"I will look at the app once you deploy it.\" is a sentence about the USER's next step, and nudging it\n // spends a metered step talking over a finished answer. The announce-and-stop case is caught instead by\n // the invocation ledger (see fabricatedToolNames), which is ground truth rather than phrasing.\n const endedWithoutClosing = sawTool && (!trailing.trim() || endsOnAnnouncedAction(trailing));\n return { content, ...(reasoning ? { reasoningContent: reasoning } : {}), ...(finishReason ? { finishReason } : {}), ...(toolCalls ? { toolCalls } : {}), ...(usage ? { usage } : {}), ...(delegatedTools.length ? { delegatedTools } : {}), ...(endedWithoutClosing ? { endedWithoutClosing: true } : {}) };\n }\n\n\n /**\n * FABRICATED TOOL USE — the failure no call-reactive layer can see, because there IS no call.\n *\n * The model announces a tool (\"I'll take a look with look_at_app\"), emits no tool_use block at all, and\n * then writes a plausible RESULT for the call it never made (\"the app view didn't respond in time\"). To\n * every surface that turn is indistinguishable from a genuine timeout: the user reads a credible failure\n * sentence, the logs show no tool call because none was made, and nothing errors. Malformed-call handling\n * (dispatch's earlyError) cannot reach it — that path needs a tool_use block to exist.\n *\n * The discriminator is NOT prose. It is the per-run invocation ledger, which is ground truth: an advertised\n * tool NAMED in the model's own text while `invokedTools` holds zero calls to it is a provable claim about\n * an event that did not happen, not a guess about phrasing. Matching is on the exact registered tool name\n * at word boundaries, so it cannot fire on ordinary English the way `endsOnAnnouncedAction` can.\n *\n * Deliberately narrow, because a false positive costs a metered step:\n * - only tools with a distinctive name (>= 4 chars, containing `_`, `-` or a capital) — a tool named `run`\n * or `web` would match half of English prose;\n * - only against the ledger for the WHOLE run, so referring back to a call it genuinely made earlier\n * (\"the screenshot showed an empty grid\") is honest and stays silent;\n * - only on a turn that made no tool calls of its own — a turn that DID call tools is closing normally.\n * (That is the enclosing `toolCalls.length === 0` branch. It is NOT extended to delegated activity:\n * a `cursor/*` turn runs its own tools and then fabricates in the SAME response, which is the exact\n * reported defect — see the call site.)\n *\n * What it deliberately does NOT catch, both verified:\n * - a fabrication that names no tool at all (\"Let me take a look at the running app. The app view did\n * not respond in time.\") — there is nothing to prove it against. Only prose matching could reach it,\n * and ungating `endsOnAnnouncedAction` for that was tried and reverted (it fires on ordinary English).\n * - a SECOND invented result for a tool the run genuinely called earlier. The ledger is per-run by\n * design, because that is the same fact that keeps an honest back-reference (\"the screenshot showed\n * an empty grid\") silent. Distinguishing them would need per-claim positional accounting, which buys\n * a rarer case at the cost of the common honest one.\n */\n private fabricatedToolNames(text: string): string[] {\n const out: string[] = [];\n for (const t of this.activeTools) {\n if (this.invokedTools.has(t.name)) continue;\n if (t.name.length < 4 || !/[_\\-A-Z]/.test(t.name)) continue; // too generic to match on safely\n const re = new RegExp(`(?:^|[^\\\\w])${t.name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?:[^\\\\w]|$)`);\n if (re.test(text)) out.push(t.name);\n }\n return out;\n }\n\n /** The claims still standing at return time: named in this run's prose, and STILL absent from the\n * invocation ledger. Re-checked here rather than trusted from detection because the ledger moves —\n * the recovery nudge can succeed, and then the host would tell the user \"I never ran it\" about a\n * call that demonstrably ran. See `RunResult.fabricatedToolClaims`. */\n private survivingClaims(): string[] {\n if (!this.fabricatedClaims.size) return [];\n return [...this.fabricatedClaims].filter((n) => !this.invokedTools.has(n));\n }\n\n private async dispatch(tc: ToolCall): Promise<string | { text: string; images?: { mimeType: string; data: string }[] }> {\n this.invokedTools.add(tc.function.name); // ledger: recorded at DISPATCH, so even a failing call counts as made\n const tool = this.activeTools.find((t) => t.name === tc.function.name);\n // [render] Parse args first but DON'T early-return on failure. An unknown-tool or bad-args call\n // (e.g. a model hallucinating a `task` tool) must still flow through the same preToolUse/notify/\n // postToolUse path as a real call — otherwise the host draws no `⚙` line and the UI looks silently\n // stuck. On parse failure keep the raw string as `args` so it still renders, and fail below.\n let args: any = {};\n let earlyError: string | undefined;\n if (!tool) earlyError = `Error: unknown tool '${tc.function.name}'`;\n try {\n args = tc.function.arguments ? JSON.parse(tc.function.arguments) : {};\n } catch (e) {\n args = tc.function.arguments;\n earlyError ??= `Error: invalid JSON arguments for ${tc.function.name}: ${String(e)}`;\n }\n const hooks = this.activeHooks; // [hooks] composed: user + plan-mode + permissions\n const call = { name: tc.function.name, args };\n const meta = { id: tc.id }; // [G4] stable per-call id so a host can correlate result↔call without serial-order assumptions\n // preToolUse is where a permission policy blocks on the user's Yes/No/Always answer — park that wait\n // so a long-standing approval prompt doesn't accrue toward the timeout kill-switch.\n const decision = await this.park(Promise.resolve(hooks?.preToolUse?.(call, meta))); // [hooks] guard before run\n if (decision?.block) {\n const blocked = `Blocked by hook: ${decision.reason ?? 'no reason given'}`;\n log.debug(`${tc.function.name} -> ${blocked}`);\n await hooks?.postToolUse?.(call, blocked, meta); // [hooks] observe the block too\n return blocked;\n }\n this.options.host?.notify?.({ kind: 'tool_use', id: tc.id ?? '', name: tc.function.name, input: args });\n // [render] surface the unknown-tool / bad-args failure through the normal result path (postToolUse\n // renders the body; notify carries isError) so it's visible instead of vanishing.\n if (earlyError) {\n log.debug(`${tc.function.name} -> ${earlyError}`);\n await hooks?.postToolUse?.(call, earlyError, meta);\n this.options.host?.notify?.({ kind: 'tool_result', id: tc.id ?? '', output: earlyError, isError: true });\n return earlyError;\n }\n let result: string;\n let images: { mimeType: string; data: string }[] | undefined;\n let threw = false;\n try {\n log.debug(`${tc.function.name}(${tc.function.arguments})`);\n // [hooks] per-call incremental-output channel: streaming tools (real Shell) push chunks via\n // ctx.emit → onToolOutput. Dispatch is serial, so binding on the shared ctx is safe; cleared\n // in finally so a straggler emit after the call settles is a silent no-op.\n this.ctx.emit = hooks?.onToolOutput ? (chunk: string) => { try { hooks.onToolOutput!(call, chunk, meta); } catch (e) { log.debug(`onToolOutput hook error: ${e}`); } } : undefined;\n const raw = await tool!.run(args, this.ctx);\n if (typeof raw === 'string') { result = raw; }\n else { result = raw.text; images = raw.images; }\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n log.debug(`${tc.function.name} -> error: ${msg}`);\n result = `Error: ${msg}`;\n threw = true;\n } finally {\n this.ctx.emit = undefined; // the call settled — late emits (stray timers) go nowhere\n }\n // autoTest (opt-in): after a successful write-class tool, run a VFS test command and surface any failure\n // to the model in-band — so it never burns a turn re-running tests itself. Skipped on block/throw.\n if (!threw) result = await this.maybeAutoTest(tc.function.name, result);\n // Image-only result (e.g. a screenshot tool): give it a text marker so hosts don't render\n // \"(no output)\" and the model has a text anchor next to the image part.\n if (images?.length && !result) result = `[${images.length} image${images.length > 1 ? 's' : ''} attached]`;\n // Pagination ceiling: a single oversized result (a 1MB Grep, a huge Read/MCP payload) would otherwise\n // blow the context window. Crop to page 1 with a marker; a capToolResult hook can spill it losslessly.\n // Browser tools (huge DOM/screenshot payloads) get a TIGHTER per-result cap once browserTrim is set —\n // this is the dominant per-step-growth lever for a long browse (a 15k-token DOM → small stub/spill).\n // Flip browserActive here so the NEXT trimContext can also keep fewer browser bodies verbatim.\n const browser = isBrowserTool(tc.function.name);\n if (browser && this.options.browserTrim) this.browserActive = true;\n const browserBytes = browser ? this.options.browserTrim?.resultBytes : undefined;\n const baseCap = this.options.maxToolResultBytes ?? 0;\n // tighter of (user cap, browser cap); a 0 (off) on either side means \"no extra limit from that side\".\n const cap = browserBytes ? (baseCap > 0 ? Math.min(baseCap, browserBytes) : browserBytes) : baseCap;\n if (!threw && cap > 0 && result.length > cap) {\n const info = { tool: tc.function.name, args };\n result = this.options.capToolResult ? await this.options.capToolResult(result, info) : cropResult(result, cap);\n }\n await hooks?.postToolUse?.(call, result, meta); // [hooks] observe the result\n this.options.host?.notify?.({ kind: 'tool_result', id: tc.id ?? '', output: result, isError: threw });\n if (images?.length) {\n for (const img of images) {\n this.options.host?.notify?.({ kind: 'tool_result_image', id: tc.id ?? '', dataUrl: `data:${img.mimeType};base64,${img.data}` });\n }\n }\n return images?.length ? { text: result, images } : result;\n }\n\n /** `/compact` aims to land the transcript at this fraction of the context window. */\n private static readonly COMPACT_TARGET = 0.5;\n\n /** THE context-window cap resolution — `/compact`'s budget and the CLI's context footer/warnings both\n * route here, so the percentage the user reads and the one compaction targets can never drift. */\n static contextCap(o: Pick<AgentOptions, 'maxContextTokens' | 'contextWindow' | 'model'> | Partial<AgentOptions>): number {\n if (o.maxContextTokens) return o.maxContextTokens;\n const w = o.contextWindow || 0;\n // Anthropic serves >200k ONLY when the request carries the `context-1m-2025-08-07` beta header, which\n // we never send (the adapter emits files-api + interleaved-thinking only). A declared 1M window is\n // therefore unusable on the wire — budgeting against it would make /compact refuse to act at 300k.\n // Lifting this is a one-liner once that beta header is emitted.\n if (w > ANTHROPIC_WINDOW_WITHOUT_1M_BETA && isAnthropicModel(o.model)) return ANTHROPIC_WINDOW_WITHOUT_1M_BETA;\n return w || 200_000;\n }\n\n private static readonly WRITE_CLASS = ['Write', 'Edit', 'MultiEdit', 'ApplyEdits'];\n\n /** Append an autoTest failure section to a write-class tool result, if configured. */\n private async maybeAutoTest(toolName: string, result: string): Promise<string> {\n const at = this.options.autoTest;\n if (!at?.command) return result;\n const set = at.tools ?? Agent.WRITE_CLASS;\n if (!set.includes(toolName)) return result;\n const r = await this.ctx.exec.execute(at.command);\n if (r.exitCode === 0) return result; // silent on pass — avoid noise\n const out = truncateOutput(((r.output ?? '') + (r.error ?? '')).replace(/\\n+$/, ''));\n return `${result}\\n\\n[autoTest] \\`${at.command}\\` FAILED (exit ${r.exitCode}):\\n${out}`;\n }\n\n /**\n * Shape the per-turn context (a VIEW — the stored transcript is never mutated). Layered, each off by default:\n * 1. coarse reduction — `compaction` (fold the dropped middle into a synthetic summary) OR\n * `maxContextMessages` (pure drop-oldest), keeping the system message + most-recent window.\n * 2. note-taking (`keepToolOutputs`) — collapse all-but-the-recent-N tool-result bodies to one-line stubs\n * (kills \"immortal tool results\": a big Read/Grep stops costing its full weight once it's old).\n * 3. token-aware backstop (`maxContextTokens`) — drop oldest messages until under an estimated token ceiling.\n * With every knob off, returns the transcript unchanged (same reference).\n */\n trimContext(): Message[] {\n const o = this.options;\n const m = this.transcript;\n let out: Message[] | null = null;\n if (o.compaction?.maxMessages && m.length > o.compaction.maxMessages) out = compact(m, o.compaction.maxMessages);\n else if (o.maxContextMessages && m.length > o.maxContextMessages) out = dropOldest(m, o.maxContextMessages);\n // Once a browser tool has actually run, keep FEWER tool-result bodies verbatim (older huge DOMs collapse\n // to one-line stubs → smaller cached prefix → smaller 0.1×cacheRead growth per step). Tighter wins; a\n // user's explicit keepToolOutputs is never LOOSENED. Off until browserActive (normal coding untouched).\n const browserKeep = this.browserActive ? o.browserTrim?.keepOutputs : undefined;\n const keep = browserKeep != null\n ? (o.keepToolOutputs ? Math.min(o.keepToolOutputs, browserKeep) : browserKeep)\n : o.keepToolOutputs;\n if (keep) out = stubOldToolResults(out ?? m, keep);\n // Decide the image outcome BEFORE the token backstop, and budget on what will ACTUALLY be sent:\n // a stale ref weighs its ~50-byte stub (not the file it will never carry), and a tool-result ref\n // weighs the whole expanded base64 (an image Read could otherwise blow the window unbudgeted).\n // Orphan-stripping runs first so the expansion window sees the real message set.\n out = expandImagesForSend(dropOrphanToolResults(out ?? m), o.keepRecentImages ?? 1);\n if (o.maxContextTokens) {\n const pre = out.length;\n out = fitTokenBudget(out, o.maxContextTokens, o.keepRecentImages ?? 1);\n // Token-cap trims used to be SILENT — surface a one-line notice (deduped per drop count)\n // so the user knows context was auto-compacted, not mysteriously forgotten.\n const dropped = pre - out.length;\n if (dropped > 0 && dropped !== this.lastTrimNotified) {\n this.lastTrimNotified = dropped;\n o.host?.notify?.({ kind: 'compaction', message: `context full — auto-trimmed ${dropped} oldest message(s) to fit ~${Math.round(o.maxContextTokens / 1000)}k tokens` });\n }\n }\n // Unconditional correctness net: a tool_result whose tool_call parent isn't in the sent set is a\n // hard API 400 (INVALID_REQUEST). Orphans arise from compaction boundaries OR a resumed transcript\n // that was folded in a prior session — strip them no matter which knobs are on. Same ref if clean.\n // (fitTokenBudget can create new head orphans; it guards its own head, this catches the rest.)\n return dropOrphanToolResults(out);\n }\n}\n\n/** system (if any) + the most-recent (max - head) messages — pure drop-oldest. */\nfunction dropOldest(m: Message[], max: number): Message[] {\n const head = m[0]?.role === 'system' ? [m[0]] : [];\n return [...head, ...m.slice(-(max - head.length))];\n}\n\n/** Anthropic's usable context without the `context-1m-2025-08-07` beta header (see Agent.contextCap). */\nconst ANTHROPIC_WINDOW_WITHOUT_1M_BETA = 200_000;\nconst isAnthropicModel = (m?: string): boolean => !!m && (m.startsWith('anthropic/') || /(^|\\/)claude-/.test(m));\n\n/** ~4 chars/token estimate over content + serialized tool_calls. THE estimator — the CLI footer,\n * `/context` and `/compact` all route here so what the user sees and what compaction targets can't\n * drift apart. Images are weighed AS SENT (`sendBytes`): only the recent window's refs cost their\n * file, stale ones cost the stub. Budgeting a ref at full file size while the wire carries a 50-byte\n * stub made `/compact` chase a target it could never reach and drop-oldest the conversation away. */\nexport function estimateTokens(m: Message[], keepRecentImages = 1): number {\n return Math.ceil(sendBytes(m, keepRecentImages) / 4);\n}\n\n/**\n * Note-taking: keep the most-recent `keep` tool-result messages verbatim; collapse older, bulky ones to a\n * one-line stub that still names the tool + its file (so the model can re-pull). Structure (role/tool_call_id/\n * name) is preserved so tool_use↔tool_result pairing stays valid; only `content` is replaced, on COPIES.\n */\n/** Crop an oversized tool result to page 1 (cut at a line boundary) with a marker telling the model it\n * was cropped and how to proceed. The default (lossy) handler when no capToolResult hook spills it. */\n/**\n * Floor for a transport's per-tool-call deadline: an UNDECLARED tool is not a prompt tool, so the\n * transport must stay generous by default (this matches the cursor helper's own DEFAULT_TOOL_TIMEOUT_MS).\n */\nexport const TRANSPORT_TOOL_TIMEOUT_FLOOR_MS = 1_800_000;\n\n/**\n * Layering assertion: every tool that declares how long it may run must finish strictly INSIDE the\n * transport deadline that wraps it. Returns one message per violation (empty = the layering holds).\n * Undeclared tools cannot be checked — which is why the deadline is floored, not derived from declarers.\n */\n/**\n * Headroom a transport needs over ONE tool's declared bound.\n *\n * An ADVISORY bound (the default) is a tool's own intention, which it may overrun — a shell cap fires a\n * kill and then still has to reap, format and return — so the transport keeps generous headroom (x2 + 1m).\n * A SELF-ENFORCED bound (`maxDurationEnforced`, e.g. Task's wall clock, which aborts the child) cannot be\n * overrun, so doubling it only buys DEAD TIME: it doubles how long a genuinely hung call stays silent.\n * Modest slack for the return trip is enough. Either way the result strictly exceeds the tool's own bound,\n * which is the invariant `toolTimeoutViolations` asserts.\n */\nexport function transportHeadroomMs(t: { maxDurationMs?: number; maxDurationEnforced?: boolean }): number {\n const d = Number(t.maxDurationMs) || 0;\n if (!d) return 0;\n return t.maxDurationEnforced ? d + 60_000 : d * 2 + 60_000;\n}\n\nexport function toolTimeoutViolations(tools: Array<{ name: string; maxDurationMs?: number }>, transportMs: number): string[] {\n const out: string[] = [];\n for (const t of tools) {\n const d = Number(t.maxDurationMs) || 0;\n if (d && d >= transportMs) {\n out.push(`tool-timeout layering VIOLATED: '${t.name}' may run up to ${d}ms but the transport deadline is ${transportMs}ms — the transport wins the race and the tool's real result is destroyed. Raise providerOptions.toolTimeoutMs above ${d}ms.`);\n }\n }\n return out;\n}\n\n/**\n * FLOOR: no tool result reaches the transcript empty — ever, from any tool, for any reason.\n *\n * A blank is the single worst thing to show a model: it reads as \"nothing happened\" rather than \"your\n * call failed\", so the model neither retries meaningfully nor adapts — it re-issues the identical call.\n * (Real session 20260831-104225: six `{role:'tool', content:''}` entries from a shell command killed by\n * a transport timeout; the model re-ran the same unfinishable scan for nine turns and never finished.)\n *\n * The floor must not LIE, though. `tools:`/`addTools()` is a public API and a host tool may legitimately\n * return '' — telling the model that a tool which provably ran suffered a transport failure (\"outcome is\n * UNKNOWN, retry it\") invites a duplicate write, which is the same harm inverted. So the caller states how\n * the result was DELIVERED and the floor only makes the UNKNOWN claim when the result genuinely never\n * arrived:\n * 'ran' — the tool returned; '' means it produced no output. Benign, and said so.\n * 'missing' — no result arrived (undefined output, a non-terminal status, a rejected/torn-down call).\n * 'error' — the tool reported failure but gave no detail.\n */\nexport type ResultDelivery = 'ran' | 'missing' | 'error';\n\nexport function nonEmptyResult(out: string, name = 'tool', delivery: ResultDelivery = 'ran'): string {\n if (out.trim()) return out;\n if (delivery === 'error') return `[${name}] failed with no error message — the tool reported an error but produced no detail. Its effect is UNKNOWN: verify the state before assuming it did or did not happen.`;\n if (delivery === 'missing') {\n const base = `[${name}] returned no result. This is a transport failure, not an empty answer — the call's outcome is UNKNOWN, so do not assume it succeeded or failed.`;\n // The background escape hatch only exists for Shell; suggesting it for a Read/Grep would be noise.\n return name === 'Shell'\n ? `${base} Do NOT re-issue the same long-running command: run it with background:true and poll ShellOutput/ShellStatus, or narrow it so it can finish.`\n : `${base} Retry it, or verify the state another way before continuing.`;\n }\n return `[${name}] ran and returned no output. The call completed — this is an empty answer, not a failure.`;\n}\n\n/**\n * Does this tool output say NOTHING? The floor's real invariant is meaningful content, not a non-empty\n * string: a delegated `{}` / `[]` / an empty MCP `{content: []}` all stringify to something non-empty and\n * sail past a length check while teaching the model exactly as much as '' did. Scalars a tool deliberately\n * returned (a real `0`, a real `false`) ARE meaningful and are never vacuous.\n */\nexport function isVacuous(v: unknown, seen: Set<object> = new Set(), depth = 0): boolean {\n if (v == null) return true;\n if (typeof v === 'string') return v.trim() === '';\n if (typeof v !== 'object') return false; // number, boolean, bigint, symbol, function — a value the tool meant to return\n // Cycles and pathological nesting: the predicate runs OUTSIDE any try/catch on the transcript path, and\n // the line it replaced (JSON.stringify + catch) was cycle-tolerant. Neither is \"nothing\", so both are\n // non-vacuous rather than a RangeError out of transcript assembly.\n if (seen.has(v) || depth >= 64) return false;\n seen.add(v);\n try {\n if (Array.isArray(v)) return v.every((x) => isVacuous(x, seen, depth + 1));\n // Only PLAIN objects can be judged by their own enumerable values. A Date, Map, Set, Error, Buffer or\n // class instance carries its content somewhere `Object.values` cannot see — `Object.values(new Date())`\n // is `[]`, which would floor a real timestamp away as \"ran and returned no output\".\n const proto = Object.getPrototypeOf(v);\n if (proto !== Object.prototype && proto !== null) return false;\n const vals = Object.values(v as Record<string, unknown>);\n return vals.length === 0 || vals.every((x) => isVacuous(x, seen, depth + 1));\n } finally {\n seen.delete(v);\n }\n}\n\n/**\n * Normalize a delegated runtime's tool output into the same `{text, images}` shape `dispatch()` returns,\n * so the reconstructed transcript record can carry pictures instead of a wall of base64 text.\n *\n * Two image-bearing shapes reach here, because a host tool's result makes a ROUND TRIP on the cursor path:\n * the toolExecutor hands back dispatch()'s `{text, images}`, the helper converts it to the SDK's content\n * blocks (`{content:[{type:'text'},{type:'image',data,mimeType}]}`, see ai.libx.js cursor-tool-result.ts),\n * and it is the SDK's echo of THAT which lands on the completed event as `output`. Accept both, plus a\n * bare block array (the MCP shape) — none of them should degrade into stringified base64.\n */\nexport function delegatedResult(output: unknown): { text: string; images: Array<{ mimeType: string; data: string }> } {\n if (typeof output === 'string') return { text: output, images: [] };\n if (output == null) return { text: '', images: [] };\n const isImg = (i: any) => i && typeof i.data === 'string' && typeof i.mimeType === 'string';\n const o = output as { text?: unknown; images?: unknown; content?: unknown };\n if (Array.isArray(o.images)) {\n const images = (o.images as any[]).filter(isImg);\n if (images.length) return { text: typeof o.text === 'string' ? o.text : '', images };\n }\n const blocks = Array.isArray(output) ? output : Array.isArray(o.content) ? o.content : undefined;\n if (blocks) {\n const images = (blocks as any[]).filter((b) => b?.type === 'image' && isImg(b)).map((b: any) => ({ mimeType: b.mimeType, data: b.data }));\n if (images.length) {\n const text = (blocks as any[]).filter((b) => b?.type === 'text' && typeof b.text === 'string').map((b: any) => b.text).join('\\n');\n return { text, images };\n }\n }\n try { return { text: JSON.stringify(output), images: [] }; } catch { return { text: String(output), images: [] }; }\n}\n\n/** How a delegated runtime's reconstructed tool record was delivered (see nonEmptyResult). */\nexport function deliveryOf(output: unknown, status?: string): ResultDelivery {\n if (status === 'error') return 'error';\n if (output == null) return 'missing'; // never arrived (cursor's `output: undefined`)\n if (status != null && status !== 'completed') return 'missing'; // still running / torn down mid-call\n return 'ran';\n}\n\nexport function cropResult(result: string, cap: number): string {\n const head = result.slice(0, cap);\n const nl = head.lastIndexOf('\\n');\n const page = nl > cap * 0.5 ? head.slice(0, nl) : head; // prefer a clean line cut if not too early\n const omitted = result.length - page.length;\n return `${page}\\n\\n[output cropped — showing ${page.length} of ${result.length} bytes; ${omitted} omitted. ` +\n `This is page 1. Refine your query/command to narrow it, or call the tool again with a tighter scope to see more.]`;\n}\n\nfunction stubOldToolResults(messages: Message[], keep: number): Message[] {\n const meta = new Map<string, string | undefined>(); // tool_call_id -> path arg (for the pointer)\n for (const msg of messages)\n for (const tc of msg.tool_calls ?? []) {\n let path: string | undefined;\n try { const a = tc.function.arguments ? JSON.parse(tc.function.arguments) : {}; if (typeof a.path === 'string') path = a.path; } catch { /* args not JSON */ }\n meta.set(tc.id, path);\n }\n const toolIdx = messages.map((x, i) => (x.role === 'tool' ? i : -1)).filter((i) => i >= 0);\n const stub = new Set(toolIdx.slice(0, Math.max(0, toolIdx.length - keep)));\n if (stub.size === 0) return messages;\n return messages.map((x, i) => {\n const text = contentText(x.content);\n if (!stub.has(i) || text.length <= 120) return x; // small results aren't worth stubbing\n const where = meta.get(x.tool_call_id ?? '');\n const lines = text.split('\\n').length;\n return { ...x, content: `[${x.name ?? 'tool'}${where ? ` ${where}` : ''} output elided — ${lines} lines; re-run the tool to view]` };\n });\n}\n\n/**\n * Elide oversized message BODIES until the transcript fits `target`. Progressive caps: shave the\n * biggest first, tighten only if still over. Tool results are the usual whales, but a single 1MB user\n * paste is shortened in place too — it must never fall through to the drop-oldest backstop and take the\n * user's own text with it. Only `content` changes, on copies — role/tool_call_id/name stay intact so\n * tool_use↔tool_result pairing holds; the system head is never touched.\n */\n/** Drop inline base64 images — heaviest message first — until the transcript fits `target`. Unlike text,\n * an image part can't be shortened, so an oversized screenshot must be elided (to `IMAGE_ELIDE_STUB`)\n * BEFORE the text ladder starts paying for it by shredding, then dropping, the conversation itself.\n * Stops as soon as we're under budget, so a small/recent image survives when text is the real weight. */\nfunction elideOversizedImages(messages: Message[], target: number, protectNewest = false, keepRecentImages = 1): Message[] {\n let out = messages;\n // REF-AWARE: post-image-refs every image in a live transcript is a ref, so selecting on inline\n // base64 alone made both ladder passes a no-op (and `protectNewest` protect nothing) — the ladder\n // then paid for the image by shredding, and finally dropping, the user's text.\n const withImages = out.map((_, i) => i).filter((i) => messageHasImage(out[i].content));\n // `protectNewest` holds back the most recent image-bearing message — the one `releaseStaleImages`\n // guarantees survives; the caller re-runs unprotected only if the text ladder still can't fit us.\n const newest = protectNewest ? withImages[withImages.length - 1] : -1;\n // Order by WIRE weight, not stored weight: a stale ref already weighs the stub, so eliding it frees\n // nothing — shave the in-window image that actually costs the file first.\n const weight = sendBytesPer(out, keepRecentImages);\n const heaviestFirst = withImages\n .filter((i) => i !== newest)\n .sort((a, b) => weight[b] - weight[a]);\n for (const i of heaviestFirst) {\n if (estimateTokens(out, keepRecentImages) <= target) break;\n const c = elideImages(out[i].content!);\n if (c === out[i].content) continue;\n out = out.map((m, j) => (j === i ? { ...m, content: c } : m));\n }\n return out;\n}\n\nfunction capOversizedBodies(messages: Message[], target: number, keepRecentImages = 1): Message[] {\n let out = messages;\n for (const cap of [8000, 4000, 2000, 800, 300, 120]) {\n if (estimateTokens(out, keepRecentImages) <= target) break;\n out = out.map((x) => (x.role === 'system' ? x : elideBody(x, cap)));\n }\n return out;\n}\n\n/** Elide one message's text down to `cap` chars. Array content keeps its non-text parts (images)\n * intact — only the text parts are shaved — and the note says so, rather than dropping them invisibly. */\nfunction elideBody(x: Message, cap: number): Message {\n const note = (bytes: number, imgs: number) =>\n `\\n\\n[${bytes} bytes elided by /compact${x.role === 'tool' ? ' — re-run the tool to view' : ''}` +\n `${imgs ? `; ${imgs} image part(s) KEPT in full — they still cost context` : ''}]`;\n if (!Array.isArray(x.content)) {\n const text = contentText(x.content);\n if (text.length <= cap) return x;\n return { ...x, content: `${text.slice(0, cap)}${note(text.length - cap, 0)}` };\n }\n const imgs = x.content.filter((p) => p.type !== 'text').length;\n let left = cap;\n let elided = 0;\n // EMPTY text parts are dropped, never emitted: once `left` hits 0 every later text part would otherwise\n // become `{type:'text', text:''}` — which the Anthropic API rejects outright.\n const parts: ContentPart[] = [];\n for (const p of x.content) {\n if (p.type !== 'text') { parts.push(p); continue; }\n const t = p.text ?? '';\n if (t.length <= left) { left -= t.length; if (t) parts.push(p); continue; }\n const keep = left; left = 0; elided += t.length - keep;\n if (keep > 0) parts.push({ ...p, text: t.slice(0, keep) });\n }\n // Nothing shaved: only rewrite if we actually dropped pre-existing empty parts (never to an empty body).\n if (!elided) return parts.length === x.content.length || !parts.length ? x : { ...x, content: parts };\n // The note is always appended, so the message can never end up with zero content parts.\n return { ...x, content: [...parts, { type: 'text', text: note(elided, imgs).trimStart() }] };\n}\n\n/** All tool_call ids present on assistant messages — one O(n) pass instead of a scan per result. */\nconst callIdSet = (msgs: Message[]): Set<string> => {\n const ids = new Set<string>();\n for (const m of msgs) if (m.role === 'assistant') for (const tc of m.tool_calls ?? []) ids.add(tc.id);\n return ids;\n};\n\n/** Drop every orphan tool_result (one whose tool_call isn't in the set) — sending one is a hard API\n * 400. Anywhere in the sequence, not just the head. Returns the same array reference when clean. */\nfunction dropOrphanToolResults(messages: Message[]): Message[] {\n const ids = callIdSet(messages);\n const ok = (m: Message) => m.role !== 'tool' || ids.has(m.tool_call_id ?? '');\n return messages.every(ok) ? messages : messages.filter(ok);\n}\n\n/**\n * Token-aware backstop: keep the system head, drop oldest body messages until under `maxTokens`.\n * The window may empty entirely (a single message can exceed the whole budget), and it is never\n * left starting on an ORPHAN tool_result (one whose tool_call isn't in the window) — that would\n * break tool_use↔tool_result pairing and get rejected by the API. If even [system] is over budget\n * (e.g. a huge memory index), we can't trim further — warn; the hard `maxTokens` kill-switch is the real guard.\n */\nfunction fitTokenBudget(messages: Message[], maxTokens: number, keepRecentImages = 1): Message[] {\n // Incremental accounting: estimate each message once, subtract as we drop — O(n), not O(n²)\n // (re-estimating the whole window per dropped message walks every char repeatedly). Per-message\n // weights come from the SHARED window (`sendBytesPer`), so a stale ref isn't charged its file.\n const per = sendBytesPer(messages, keepRecentImages).map((b) => Math.ceil(b / 4));\n let total = per.reduce((a, b) => a + b, 0);\n if (total <= maxTokens) return messages;\n const head = messages[0]?.role === 'system' ? [messages[0]] : [];\n let from = head.length; // body = messages[from..]\n while (from < messages.length && total > maxTokens) total -= per[from++];\n const ids = callIdSet(messages.slice(from));\n while (from < messages.length && messages[from].role === 'tool' && !ids.has(messages[from].tool_call_id ?? '')) total -= per[from++];\n if (total > maxTokens)\n log.warn(`context ~${total} tok still over maxContextTokens=${maxTokens} after trimming (system head can't be dropped)`);\n return [...head, ...messages.slice(from)];\n}\n\n/** system (if any) + synthetic summary of the dropped middle + most-recent window; fits within `max`. */\nfunction compact(m: Message[], max: number, focus?: string): Message[] {\n const hasSystem = m[0]?.role === 'system';\n const head = hasSystem ? [m[0]] : [];\n // Reserve one slot for the summary, the rest for the most-recent window. Bound the tail\n // to the post-head slice so a short transcript (max >= length) can't re-include the head.\n const tailCount = Math.max(1, max - head.length - 1);\n const tail = m.slice(head.length).slice(-tailCount);\n const dropped = m.slice(head.length, m.length - tail.length);\n if (dropped.length === 0) return [...head, ...tail];\n return [...head, { role: 'system', content: summarize(dropped, focus) }, ...tail];\n}\n\n/** Header of a synthetic recap produced by `summarize` — how a LATER pass recognizes its own output. */\nconst SUMMARY_HEAD = '[summary of ';\n/** Upper bound on the message count a single prior recap may claim (untrusted input — see summarize). */\nconst MAX_CARRIED_COUNT = 10_000;\nconst isSyntheticSummary = (m: Message): boolean =>\n m.role === 'system' && typeof m.content === 'string' && m.content.startsWith(SUMMARY_HEAD);\n\n/** Lightweight, deterministic, LLM-free recap of a span of messages.\n * A recap from an EARLIER pass inside the span is carried forward (its message count and its detail\n * lines), never silently thrown away — the escalation ladder re-folds an already-folded transcript, and\n * a recap that discards its predecessor would lie about how much history it stands for. */\nfunction summarize(messages: Message[], focus?: string): string {\n const tools = new Set<string>();\n const files = new Set<string>();\n const carried: string[] = []; // detail lines from prior recaps in this span (deduped, bounded)\n let carriedCount = 0; // messages those recaps already stood for\n let priors = 0;\n let lastAssistant = '';\n for (const msg of messages) {\n if (isSyntheticSummary(msg)) {\n priors++;\n const [head, ...rest] = String(msg.content).split('\\n');\n // Clamp: a recap head is data, not a promise — a restored session or a hook-written system message\n // could carry `[summary of 999999 …]` and we must not absorb it verbatim.\n carriedCount += Math.min(Math.max(Number(/of (\\d+)/.exec(head)?.[1]) || 0, 0), MAX_CARRIED_COUNT);\n for (const l of rest) if (l.trim() && !carried.includes(l) && carried.length < 20) carried.push(l);\n continue;\n }\n for (const tc of msg.tool_calls ?? []) {\n tools.add(tc.function.name);\n try {\n const args = tc.function.arguments ? JSON.parse(tc.function.arguments) : {};\n if (typeof args.path === 'string') files.add(args.path);\n } catch {\n /* arguments not JSON — skip file extraction */\n }\n }\n if (msg.role === 'assistant' && msg.content) lastAssistant = contentText(msg.content);\n }\n const lines = [`${SUMMARY_HEAD}${messages.length - priors + carriedCount} earlier message(s)]`];\n if (tools.size) lines.push(`tools used: ${[...tools].join(', ')}`);\n if (files.size) lines.push(`files touched: ${[...files].join(', ')}`);\n if (lastAssistant) lines.push(`last assistant: ${lastAssistant}`);\n if (carried.length) lines.push('earlier recap:', ...carried.map((l) => ` ${l}`));\n // Focused compaction: keep lines from the dropped span that mention any focus keyword,\n // verbatim (bounded), so \"/compact keep the API details\" doesn't lose them to the recap.\n if (focus?.trim()) {\n const words = focus.toLowerCase().split(/\\s+/).filter((w) => w.length > 2);\n const kept: string[] = [];\n // THIS span's own messages are scanned FIRST: a prior recap sits at index 0 and would otherwise eat the\n // whole budget, so repeated `/compact <focus>` would keep only the OLDEST hits and drop the newest.\n // (Older hits still reach the recap via `carried` above.)\n const ordered = [...messages.filter((m) => !isSyntheticSummary(m)), ...messages.filter(isSyntheticSummary)];\n outer: for (const msg of ordered) {\n if (msg.role === 'tool') continue; // tool bodies are bulk noise; user/assistant text carries the decisions\n for (const line of contentText(msg.content).split('\\n')) {\n const l = line.toLowerCase();\n if (line.trim() && words.some((w) => l.includes(w))) {\n kept.push(line.trim().slice(0, 200));\n if (kept.length >= 12) break outer;\n }\n }\n }\n if (kept.length) lines.push(`preserved (re: ${focus.trim()}):`, ...kept.map((l) => ` ${l}`));\n }\n return lines.join('\\n');\n}\n\nfunction lastAssistantText(messages: Message[]): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === 'assistant') return contentText(messages[i].content);\n }\n return '';\n}\n","/**\n * Sandbox background jobs — the in-process twin of `ShellJobRegistry` (src/tools.shell.ts), but for work\n * that runs *inside* the sandbox rather than as an OS child process. Backs `bash({background:true})` and\n * (later) background sub-agents.\n *\n * IMPORTANT — this is concurrency via async-I/O interleaving, NOT parallelism. The runtime is single\n * threaded: a CPU-bound JS command still blocks. Real overlap only happens when a job *awaits* — i.e. a\n * remote VFS backend (BodDbFilesystem, network per read) or a sub-agent (model calls). Over a pure in-mem\n * MemFilesystem, backgrounding a fast command buys nothing (the tool description says so).\n *\n * The registry is kind-AGNOSTIC: it tracks any async producer's lifecycle + tail output. Overlay isolation\n * and commit-on-success are the *producer's* responsibility (IoC), so the registry stays a pure tracker.\n */\nexport type JobStatus = 'running' | 'done' | 'error' | 'killed';\n\n/** A producer: does the actual work, may stream progress via `onChunk`, returns its final text. */\nexport interface JobFn {\n (ctx: { signal: AbortSignal; onChunk: (s: string) => void }): Promise<string>;\n}\n\ninterface Job {\n kind: string;\n label: string;\n status: JobStatus;\n buf: string;\n ctl: AbortController;\n promise: Promise<void>;\n}\n\n/** Per-session registry of in-process background jobs. Bounded tail buffer; abortable; drainable at turn end. */\nexport class SandboxJobRegistry {\n private jobs = new Map<string, Job>();\n private seq = 0;\n constructor(private maxBuffer = 256 * 1024) {}\n\n /** Start `fn` in the background and return a job id immediately (does not await completion). */\n start(fn: JobFn, opts: { kind?: string; label?: string } = {}): string {\n const id = `job-${++this.seq}`;\n const ctl = new AbortController();\n const onChunk = (s: string) => { job.buf = (job.buf + s).slice(-this.maxBuffer); }; // ring: keep the tail\n const job: Job = { kind: opts.kind ?? 'task', label: opts.label ?? '', status: 'running', buf: '', ctl, promise: Promise.resolve() };\n job.promise = fn({ signal: ctl.signal, onChunk }).then(\n (res) => { if (job.status === 'running') { job.status = 'done'; if (res) onChunk(res); } },\n (e: any) => { if (job.status === 'running') { job.status = 'error'; onChunk(`\\n[error] ${e?.message ?? e}`); } },\n );\n this.jobs.set(id, job);\n return id;\n }\n\n /** Tail output for a job (null = no such job, '' = job exists but no output yet). */\n output(id: string): string | null { return this.jobs.get(id)?.buf ?? (this.jobs.has(id) ? '' : null); }\n\n status(id: string): { status: JobStatus; bytes: number } | null {\n const j = this.jobs.get(id);\n return j ? { status: j.status, bytes: j.buf.length } : null;\n }\n\n list(): Array<{ id: string; kind: string; label: string; status: JobStatus }> {\n return [...this.jobs].map(([id, j]) => ({ id, kind: j.kind, label: j.label, status: j.status }));\n }\n\n /** Signal cancel (the producer decides what abort means — e.g. skip the overlay commit). */\n kill(id: string): boolean {\n const j = this.jobs.get(id);\n if (!j) return false;\n if (j.status === 'running') { j.ctl.abort(); j.status = 'killed'; }\n return true;\n }\n\n killAll(): void { for (const id of this.jobs.keys()) this.kill(id); }\n\n /** Await every still-running job. Called at turn end so a job's committed writes aren't lost from view\n * just because the model didn't poll it. Returns the ids that were still running when drain began. */\n async drain(): Promise<string[]> {\n const pending = [...this.jobs].filter(([, j]) => j.status === 'running').map(([id]) => id);\n await Promise.all([...this.jobs.values()].map((j) => j.promise));\n return pending;\n }\n}\n\nconst NO_JOB = (id: string) =>\n `Error: no background job '${id}'. Use JobStatus with no id to list jobs, or start one with bash({background:true}).`;\n\n/** Companion tools (JobOutput / JobStatus / JobKill) over a SandboxJobRegistry. */\nexport function makeJobTools(registry: SandboxJobRegistry): import('./tools').AgentTool[] {\n return [\n {\n name: 'JobOutput',\n description: 'Read the accumulated output (tail) of a background job by id (from bash({background:true})).',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n async run({ id }) {\n const out = registry.output(String(id));\n if (out == null) return NO_JOB(String(id));\n const st = registry.status(String(id))!;\n return `[${st.status}]\\n${out.replace(/\\n+$/, '') || '(no output yet)'}`;\n },\n },\n {\n name: 'JobStatus',\n description: 'Status of a background job (running/done/killed/error). Omit `id` to list all jobs.',\n parameters: { type: 'object', properties: { id: { type: 'string' } } },\n async run({ id }) {\n if (!id) {\n const jobs = registry.list();\n return jobs.length ? jobs.map((j) => `${j.id} ${j.status} ${j.kind}${j.label ? ' ' + j.label : ''}`).join('\\n') : '(no background jobs)';\n }\n const st = registry.status(String(id));\n return st ? `${st.status} · ${st.bytes} byte(s) buffered` : NO_JOB(String(id));\n },\n },\n {\n name: 'JobKill',\n description: 'Stop a running background job by id (the job is cancelled; its overlay writes are NOT committed).',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n async run({ id }) {\n return registry.kill(String(id)) ? `Killed job ${id}.` : NO_JOB(String(id));\n },\n },\n ];\n}\n","import type { AgentTool, ToolContext, HostBridge, UserQuestion } from './tools';\n\nexport type { HostBridge, UserQuestion } from './tools';\n\n/**\n * `AskUserQuestion` tool — lets the model pose a structured choice to a human.\n * Delegates to `ctx.host.ask` when a human is reachable.\n *\n * When NO human is reachable (`host.ask` absent — headless `-p`, a piped/redirected run, an edge\n * host), the question is NOT dropped and NOT guessed at: it parks on `ctx.needsInput`, and the\n * Agent ends the run with `finishReason:'needs_input'` carrying the question up to the CALLER.\n * The caller answers and resumes. Guessing silently is the failure mode this exists to prevent —\n * a delegated agent that picks for you on a decision that was never its to make.\n */\nexport const askUserQuestionTool: AgentTool = {\n name: 'AskUserQuestion',\n description:\n 'Ask the user a multiple-choice question when a decision is genuinely theirs to make: an ambiguous or under-specified requirement, a fork you cannot resolve from context, a premise of the task that the evidence contradicts, or a risky/irreversible next step. Prefer this over guessing, \"proceeding with best judgment\", or quietly widening scope to make an unclear brief fit — a wrong silent decision is far more costly than a question. Returns their selection if a human is reachable; otherwise the run pauses and the question is handed to whoever delegated the task (you do not need to know which — just ask).',\n parameters: {\n type: 'object',\n required: ['question', 'options'],\n properties: {\n question: { type: 'string' },\n header: { type: 'string', description: 'short label for the question' },\n options: {\n type: 'array',\n items: { type: 'object', required: ['label'], properties: { label: { type: 'string' }, description: { type: 'string' } } },\n },\n multiSelect: { type: 'boolean' },\n },\n },\n async run(args: UserQuestion, ctx: ToolContext) {\n if (!ctx.host?.ask) {\n // No human on this side of the process — raise the question to the caller and stop the run.\n // Never block on a prompt nobody can see (that hangs until an external timeout reaps the turn).\n ctx.needsInput = args;\n return 'PAUSED — no interactive user is reachable from this run, so your question has been raised to the caller that delegated this task. The run stops here; do not guess and do not continue. Their answer will arrive as the next user message when the run resumes.';\n }\n const answer = ctx.host.ask(args); // human-blocking — park it so the wait doesn't count toward the timeout\n return ctx.parkHuman ? ctx.parkHuman(answer) : answer;\n },\n};\n\n/** Deterministic HostBridge for tests/dev: scripts answers + records what was asked. */\nexport class ScriptedHostBridge implements HostBridge {\n public asked: UserQuestion[] = [];\n public confirms: string[] = [];\n public events: Array<{ kind: string; message: string; data?: unknown }> = [];\n constructor(private answers: string[] = [], private confirmDefault = true) {}\n async ask(q: UserQuestion): Promise<string> {\n this.asked.push(q);\n return this.answers.shift() ?? q.options[0]?.label ?? '';\n }\n async confirm(prompt: string): Promise<boolean> {\n this.confirms.push(prompt);\n return this.confirmDefault;\n }\n notify(event: { kind: string; message: string; data?: unknown }): void {\n this.events.push(event);\n }\n}\n\n/** Node CLI HostBridge: prompts on stdin. (node-only host adapter; not edge-safe by design.) */\nexport class ConsoleHostBridge implements HostBridge {\n async ask(q: UserQuestion): Promise<string> {\n const rl = await import('node:readline/promises');\n const io = rl.createInterface({ input: process.stdin, output: process.stdout });\n try {\n const lines = [q.header ? `\\n[${q.header}] ${q.question}` : `\\n${q.question}`];\n q.options.forEach((o, i) => lines.push(` ${i + 1}) ${o.label}${o.description ? ' — ' + o.description : ''}`));\n const ans = await io.question(lines.join('\\n') + '\\n> ');\n const n = Number(ans.trim());\n return Number.isInteger(n) && q.options[n - 1] ? q.options[n - 1].label : ans.trim();\n } finally {\n io.close();\n }\n }\n async confirm(prompt: string): Promise<boolean> {\n const rl = await import('node:readline/promises');\n const io = rl.createInterface({ input: process.stdin, output: process.stdout });\n try {\n const ans = await io.question(`\\n${prompt} [y/N] `);\n return /^y(es)?$/i.test(ans.trim());\n } finally {\n io.close();\n }\n }\n notify(event: { kind: string; message: string }): void {\n console.error(`[${event.kind}] ${event.message}`);\n }\n}\n","/**\n * Lexical relevance — no deps, deterministic, edge-safe. Ranks catalog entries (skills,\n * commands, memories, docs) by a task hint so a LARGE catalog doesn't dump every entry into\n * the prompt. TF-IDF weighted: rare terms in the corpus score higher than common ones.\n */\n\nconst STOP = new Set([\n 'the', 'and', 'for', 'with', 'that', 'this', 'from', 'into', 'your', 'you', 'are', 'was', 'will',\n 'use', 'using', 'run', 'add', 'fix', 'make', 'file', 'files', 'code', 'please', 'need', 'want', 'should', 'all',\n]);\n\n/** Lowercased alphanumeric tokens of length ≥ 3, minus a few stopwords. */\nexport function tokenize(s: string): Set<string> {\n const out = new Set<string>();\n for (const w of String(s ?? '').toLowerCase().match(/[a-z0-9]+/g) ?? []) {\n if (w.length >= 3 && !STOP.has(w)) out.add(w);\n }\n return out;\n}\n\n/** Build IDF weights from a corpus of texts. Rare terms get higher weight. */\nexport function idfWeights(corpus: string[]): Map<string, number> {\n const N = corpus.length;\n if (N === 0) return new Map();\n const df = new Map<string, number>();\n for (const doc of corpus) for (const t of tokenize(doc)) df.set(t, (df.get(t) ?? 0) + 1);\n const idf = new Map<string, number>();\n for (const [t, n] of df) idf.set(t, Math.log((N + 1) / (n + 1)) + 1); // smooth IDF\n return idf;\n}\n\n/** TF-IDF weighted relevance score. Without IDF, falls back to flat token overlap (backward-compatible). */\nexport function relevanceScore(text: string, queryTokens: Set<string>, idf?: Map<string, number>): number {\n if (queryTokens.size === 0) return 0;\n const t = tokenize(text);\n let score = 0;\n for (const q of queryTokens) if (t.has(q)) score += idf?.get(q) ?? 1;\n return score;\n}\n\n/**\n * Split `items` into the `k` most relevant to `query` (by TF-IDF overlap with `text(item)`)\n * and the rest, preserving each item's original order within its group. Returns everything in\n * `kept` (empty `rest`) when `items.length <= k` or `query` is blank — so it's a no-op for\n * small lists. When `corpus` is provided, builds IDF weights for better ranking.\n */\nexport function topByRelevance<T>(items: T[], query: string, text: (x: T) => string, k: number, corpus?: string[]): { kept: T[]; rest: T[] } {\n if (!Number.isInteger(k) || k < 1) return { kept: items, rest: [] }; // invalid k → no-op (keep all), never hide\n if (items.length <= k || !query.trim()) return { kept: items, rest: [] };\n const q = tokenize(query);\n if (q.size === 0) return { kept: items.slice(0, k), rest: items.slice(k) };\n const idf = corpus?.length ? idfWeights(corpus) : undefined;\n const scored = items.map((x, i) => ({ i, s: relevanceScore(text(x), q, idf) }));\n scored.sort((a, b) => b.s - a.s || a.i - b.i); // best score first; stable by original index\n const keep = new Set(scored.slice(0, k).map((e) => e.i));\n return { kept: items.filter((_, i) => keep.has(i)), rest: items.filter((_, i) => !keep.has(i)) };\n}\n","/**\n * Lean YAML-frontmatter parsing (no YAML dependency) shared by skills + commands.\n * Handles single-line values AND block scalars (`>`, `>-`, `|`, `|-`, …) — CC skills\n * often fold long descriptions across indented lines, which a single-line regex truncates.\n */\n\n/** Extract the `---`-delimited frontmatter block + the body that follows it. */\nexport function splitFrontmatter(md: string): { block: string; body: string } {\n const m = md.match(/^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n?/);\n return { block: m ? m[1] : '', body: (m ? md.slice(m[0].length) : md).trim() };\n}\n\n/** Grab a scalar field from a frontmatter block by key (case-insensitive). Folds block scalars to one line. */\nexport function grabField(block: string, key: string): string | undefined {\n const lines = block.split('\\n');\n const i = lines.findIndex((l) => new RegExp(`^${key}\\\\s*:`, 'i').test(l));\n if (i < 0) return undefined;\n const inline = lines[i].replace(new RegExp(`^${key}\\\\s*:\\\\s*`, 'i'), '');\n // Block scalar (`>`/`|` with optional chomping `-`/`+`): gather the following more-indented lines.\n if (/^[>|][+-]?\\s*$/.test(inline)) {\n const folded: string[] = [];\n for (let j = i + 1; j < lines.length && /^\\s+\\S/.test(lines[j]); j++) folded.push(lines[j].trim());\n return folded.join(' ').trim() || undefined; // fold to one line (catalog descriptions are single-line)\n }\n return inline.trim().replace(/^[\"']|[\"']$/g, '') || undefined;\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { AgentTool, ToolContext } from './tools';\nimport { topByRelevance } from './relevance';\nimport { splitFrontmatter, grabField } from './frontmatter';\n\n/** Above this many commands, the catalog shows full entries only for the most task-relevant; the rest list as names. */\nconst MAX_CATALOG = 25;\n\nexport interface CommandInfo {\n name: string;\n description: string;\n path: string;\n}\n\n/**\n * Resolves a name in the *other* half of the merged slash namespace (CC parity: `/x` is one\n * namespace whether `x` is a `commands/x.md` or a `skills/x/SKILL.md`). On a miss in its own\n * registry, a tool calls this to find the sibling and learn how to expand it. Injected by the\n * caller (Agent.prepare) so commands.ts and skills.ts stay mutually decoupled (no circular import).\n */\nexport type SiblingResolver = (name: string) => Promise<{ path: string; stripFrontmatter: boolean } | undefined>;\n\n/** Parse a command template's `description:` frontmatter + return the body that follows. */\nfunction parseFrontmatter(md: string): { description?: string; body: string } {\n const { block, body } = splitFrontmatter(md);\n return { description: grabField(block, 'description'), body };\n}\n\n/**\n * Expand a command template's argument placeholders:\n * - `$ARGUMENTS` → all args (every occurrence)\n * - `$1`…`$9` → positional args (whitespace-split; missing → empty)\n * If the body has neither placeholder, `args` is appended as a trailing block (back-compat).\n */\nexport function expandTemplate(body: string, args: string): string {\n if (!/\\$ARGUMENTS|\\$[1-9]/.test(body)) return args ? `${body}\\n\\n${args}` : body;\n const toks = args.trim() ? args.trim().split(/\\s+/) : [];\n return body.split('$ARGUMENTS').join(args).replace(/\\$([1-9])/g, (_m, n) => toks[Number(n) - 1] ?? '');\n}\n\n/** Inline `@path` references (CC-style) with the file's contents, fenced. Non-existent paths stay literal. */\nasync function embedFiles(text: string, fs: IFilesystem): Promise<string> {\n const refs = [...new Set([...text.matchAll(/(?:^|\\s)@(\\S+)/g)].map((m) => m[1]))];\n let out = text;\n for (const ref of refs) {\n try {\n const content = await fs.readFile(ref);\n out = out.split('@' + ref).join(`\\n\\n--- @${ref} ---\\n${content}\\n--- end @${ref} ---\\n`);\n } catch { /* not a readable file — leave the literal @ref (could be an email, decorator, etc.) */ }\n }\n return out;\n}\n\n/**\n * Read a slash entry's file and return its expanded text: arg placeholders filled, then `@file`\n * refs embedded. `stripFrontmatter` drops the YAML head (commands feed only their body); skills\n * feed the whole SKILL.md (frontmatter is part of the instructions). Shared by commands + skills\n * so both halves of the merged namespace expand identically (CC parity).\n */\nexport async function expandEntry(\n fs: IFilesystem,\n path: string,\n args: string,\n opts: { stripFrontmatter?: boolean } = {},\n): Promise<string> {\n const raw = await fs.readFile(path);\n const text = opts.stripFrontmatter ? parseFrontmatter(raw).body : raw;\n return embedFiles(expandTemplate(text, args), fs);\n}\n\n/** Read a command file and return its expanded body: arg placeholders filled, then `@file` refs embedded. */\nexport async function expandCommand(fs: IFilesystem, cmd: CommandInfo, args: string): Promise<string> {\n return expandEntry(fs, cmd.path, args, { stripFrontmatter: true });\n}\n\n/**\n * Discover slash commands under `dir` (each `<dir>/<name>.md`) and produce:\n * - `catalog`: a names+descriptions block for the system prompt,\n * - `tool`: a `SlashCommand` tool that returns a command's expanded template body.\n *\n * Commands are reusable prompt templates (like Claude Code slash commands) — just\n * VFS files. The template body is returned (user args appended, and `$ARGUMENTS`\n * substituted if present) so the model can act on it. Mirrors loadSkills.\n */\n/** Scan `dir`(s) for `<dir>/<name>.md` command templates (first dir wins on duplicate names). */\nexport async function scanCommands(fs: IFilesystem, dir: string | string[]): Promise<CommandInfo[]> {\n const commands: CommandInfo[] = [];\n const seen = new Set<string>();\n for (const d of Array.isArray(dir) ? dir : [dir]) {\n if (!await fs.exists(d)) continue;\n for (const entry of await fs.readDir(d)) {\n if (!entry.endsWith('.md')) continue;\n const name = entry.replace(/\\.md$/, '');\n if (seen.has(name)) continue; // first dir wins\n seen.add(name);\n const path = `${d}/${entry}`;\n const fm = parseFrontmatter(await fs.readFile(path));\n commands.push({ name, description: fm.description || '', path });\n }\n }\n return commands;\n}\n\nexport async function loadCommands(\n fs: IFilesystem,\n dir: string | string[],\n opts: { relevanceHint?: string; max?: number; sibling?: SiblingResolver } = {},\n): Promise<{ commands: CommandInfo[]; catalog: string; tool?: AgentTool }> {\n const commands = await scanCommands(fs, dir);\n if (commands.length === 0) return { commands, catalog: '' };\n\n // At scale, show full entries only for the most task-relevant; the rest list as names (still\n // runnable by name). No-op for small catalogs (≤ max) or no hint, so the prefix stays stable.\n const { kept, rest } = topByRelevance(commands, opts.relevanceHint ?? '', (c) => `${c.name} ${c.description}`, opts.max ?? MAX_CATALOG);\n const catalog =\n '## Slash commands (reusable prompt templates)\\n' +\n kept.map((c) => `- **/${c.name}** — ${c.description} (\\`${c.path}\\`)`).join('\\n') +\n (rest.length ? `\\n- (${rest.length} more, names only — call \\`SlashCommand\\` to run): ${rest.map((c) => c.name).join(', ')}` : '') +\n '\\nTo run one, call the `SlashCommand` tool with its name (and optional `args`); it returns the expanded template to act on.';\n\n const tool: AgentTool = {\n name: 'SlashCommand',\n description: 'Run a slash command (or skill) by name — returns its expanded prompt template/instructions (with your `args` substituted/appended). Resolves both the command and skill namespaces. Use when a task matches a listed command or skill.',\n parameters: {\n type: 'object',\n required: ['name'],\n properties: { name: { type: 'string' }, args: { type: 'string', description: 'arguments to fill the template' } },\n },\n async run({ name, args }, ctx: ToolContext) {\n const slug = String(name ?? '').replace(/^\\//, '');\n let c = commands.find((x) => x.name === slug);\n let fresh: CommandInfo[] | undefined;\n if (!c) { // miss → rescan: commands created mid-conversation are runnable without a reprepare\n fresh = await scanCommands(ctx.fs, dir);\n c = fresh.find((x) => x.name === slug);\n if (c) commands.push(c);\n }\n if (c) return expandCommand(ctx.fs, c, String(args ?? ''));\n // still a miss → merged namespace: try the sibling (skills) registry before failing.\n const sib = await opts.sibling?.(slug);\n if (sib) return expandEntry(ctx.fs, sib.path, String(args ?? ''), { stripFrontmatter: sib.stripFrontmatter });\n return `Error: no command or skill named '${slug}'. Available commands: ${(fresh ?? []).map((x) => x.name).join(', ') || '(none)'}`;\n },\n };\n return { commands, catalog, tool };\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { AgentTool, ToolContext } from './tools';\nimport { topByRelevance } from './relevance';\nimport { splitFrontmatter, grabField } from './frontmatter';\nimport { expandEntry, type SiblingResolver } from './commands';\n\n/** Above this many skills, the catalog shows full entries only for the most task-relevant; the rest list as names. */\nconst MAX_CATALOG = 25;\n\nexport interface SkillInfo {\n name: string;\n description: string;\n path: string;\n}\n\n/** Parse a SKILL.md's `name:` / `description:` frontmatter (falls back to scanning the head if undelimited). */\nfunction parseFrontmatter(md: string): { name?: string; description?: string } {\n const { block } = splitFrontmatter(md);\n const b = block || md.slice(0, 600);\n return { name: grabField(b, 'name'), description: grabField(b, 'description') };\n}\n\n/**\n * Discover skills under `dir` (each `<dir>/<id>/SKILL.md`) and produce:\n * - `catalog`: a names+descriptions block for the system prompt,\n * - `tool`: a `Skill` tool that returns a skill's full SKILL.md (progressive disclosure).\n *\n * Skills are just VFS files — the Read tool already gives progressive disclosure; this\n * adds the catalog + a convenience tool. (Executable skills can be `bash`-exec'd: wcli\n * runs JS files from the VFS as commands.)\n */\n/** Scan `dir`(s) for `<dir>/<id>/SKILL.md` entries (first dir wins on duplicate ids). */\nexport async function scanSkills(fs: IFilesystem, dir: string | string[]): Promise<SkillInfo[]> {\n const skills: SkillInfo[] = [];\n const seen = new Set<string>();\n for (const d of Array.isArray(dir) ? dir : [dir]) {\n if (!await fs.exists(d)) continue;\n for (const entry of await fs.readDir(d)) {\n if (seen.has(entry)) continue; // first dir wins (our .agent/ before .claude/)\n const skillMd = `${d}/${entry}/SKILL.md`;\n if (await fs.exists(skillMd)) {\n seen.add(entry);\n const fm = parseFrontmatter(await fs.readFile(skillMd));\n skills.push({ name: fm.name || entry, description: fm.description || '', path: skillMd });\n }\n }\n }\n return skills;\n}\n\nexport async function loadSkills(\n fs: IFilesystem,\n dir: string | string[],\n opts: { relevanceHint?: string; max?: number; sibling?: SiblingResolver } = {},\n): Promise<{ skills: SkillInfo[]; catalog: string; tool?: AgentTool }> {\n const skills = await scanSkills(fs, dir);\n if (skills.length === 0) return { skills, catalog: '' };\n\n // At scale, show full entries only for the most task-relevant; the rest list as names (still\n // loadable by name). No-op for small catalogs (≤ max) or no hint, so the prefix stays stable.\n const { kept, rest } = topByRelevance(skills, opts.relevanceHint ?? '', (s) => `${s.name} ${s.description}`, opts.max ?? MAX_CATALOG);\n const catalog =\n '## Skills (load one before acting on a matching task)\\n' +\n kept.map((s) => `- **${s.name}** — ${s.description} (\\`${s.path}\\`)`).join('\\n') +\n (rest.length ? `\\n- (${rest.length} more, names only — call \\`Skill\\` to load): ${rest.map((s) => s.name).join(', ')}` : '') +\n '\\nWhen a task matches a skill, call the `Skill` tool with its name to load its full instructions.';\n\n const tool: AgentTool = {\n name: 'Skill',\n description: 'Load a skill (or slash command) by name — returns its full instructions (SKILL.md / expanded template), with any `args` substituted/appended. Resolves both the skill and command namespaces. Use when a task matches a listed skill or command.',\n parameters: { type: 'object', required: ['name'], properties: { name: { type: 'string' }, args: { type: 'string', description: 'arguments to fill the template' } } },\n async run({ name, args }, ctx: ToolContext) {\n const slug = String(name ?? '').replace(/^\\//, '');\n let s = skills.find((x) => x.name === slug);\n let fresh: SkillInfo[] | undefined;\n if (!s) { // miss → rescan: skills created mid-conversation are loadable without a reprepare\n fresh = await scanSkills(ctx.fs, dir);\n s = fresh.find((x) => x.name === slug);\n if (s) skills.push(s);\n }\n if (s) return expandEntry(ctx.fs, s.path, String(args ?? '')); // skill: whole SKILL.md (frontmatter kept)\n // still a miss → merged namespace: try the sibling (commands) registry before failing.\n const sib = await opts.sibling?.(slug);\n if (sib) return expandEntry(ctx.fs, sib.path, String(args ?? ''), { stripFrontmatter: sib.stripFrontmatter });\n return `Error: no skill or command named '${slug}'. Available skills: ${(fresh ?? []).map((x) => x.name).join(', ') || '(none)'}`;\n },\n };\n return { skills, catalog, tool };\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { AgentTool, ToolContext } from './tools';\nimport { mkdirp } from './tools.structured';\nimport { topByRelevance, tokenize, relevanceScore, idfWeights } from './relevance';\nimport { splitFrontmatter } from './frontmatter';\n\nconst MAX_INDEX = 25;\nconst MAX_INDEX_LINES = 200;\nconst MAX_INDEX_BYTES = 25_000;\n\n/** Behavioral guidance injected alongside the memory index — adapted from CC's battle-tuned prose, for our tool-based workflow. */\nexport const MEMORY_PROMPT =\n '## Memory guidelines\\n' +\n '**When to Remember:** user corrections (\"no, do X instead\"), preferences (\"I prefer Y\"), project constraints, recurring gotchas, ' +\n 'role/context (\"I\\'m a data scientist\"), workflow patterns confirmed by the user. Capture the WHY, not just the what.\\n' +\n '**When NOT to Remember:** task-specific scratch, transient state, things derivable from code/git, conversation filler, ' +\n 'anything already in instruction files. If removing the memory wouldn\\'t change future behavior, don\\'t save it.\\n' +\n '**Types** (pass to Remember — this determines where the memory is stored):\\n' +\n '- `user` — role, preferences, knowledge level, collaboration style (GLOBAL — follows you across projects)\\n' +\n '- `feedback` — corrections, what to avoid/repeat, with WHY (GLOBAL)\\n' +\n '- `project` — ongoing work, goals, constraints, deadlines (LOCAL to this project; convert relative dates to absolute)\\n' +\n '- `reference` — pointers to external resources, URLs, vendor docs (LOCAL to this project)\\n' +\n '**Before acting on a recalled memory:** verify it\\'s still true — a memory naming a file/function/flag is a claim ' +\n 'from when it was written. Grep/read to confirm before recommending. Stale memory → update via Remember (same slug overwrites).\\n' +\n '**Dedup:** before writing, check if a similar memory exists (Recall or MemorySearch). Update the existing one rather than creating duplicates.\\n' +\n 'Call `Recall` with a slug (or multiple slugs/a pattern) to load full bodies when relevant.\\n' +\n 'Call `MemorySearch` with a query to find memories by content when you don\\'t know the slug.\\n' +\n 'Call `Remember` to persist a durable fact for future sessions.';\n\n/** Voice-specific memory guidance — shorter, spoken-interaction tuned. */\nexport const VOICE_MEMORY_PROMPT =\n 'You have Remember and Recall tools — use them directly, no delegation needed.\\n' +\n 'IMPLICIT CAPTURE: when the user shares their name, role, a preference, a correction (\"no, do X instead\"), ' +\n 'or a project constraint — call Remember immediately without announcing it. Natural memory, not a ceremony.\\n' +\n 'For explicit \"remember X\" requests, also call Remember directly and confirm briefly (\"got it\").\\n' +\n 'Do NOT remember: transient task details, conversation filler, things you\\'d forget in a real conversation.\\n' +\n 'Keep it invisible: never announce \"saving to memory\" or list what you remembered unless asked.\\n' +\n 'For anything requiring files, shell, or web — still Act.';\n\n/**\n * Load memory for injection at run start (the recall step), with progressive disclosure:\n * - `index`: the compact `<dir>/MEMORY.md` index, injected into the system prompt — cheap,\n * always-hot. Each line points at a fact file the agent can pull on demand.\n * - `tools`: `Recall` (load one fact body on demand — keeps facts COLD until needed) and\n * `Remember` (persist a durable fact + index pointer mid-run — the WRITE half that closes\n * the learning loop: what the agent learns now steers future sessions).\n *\n * Persistence is the BACKEND's job, for free: NodeDiskFilesystem → disk,\n * IndexedDbFilesystem → browser, (planned) BodDbFilesystem → database. The same\n * memory mechanism therefore works in node, a browser tab, or on edge.\n */\nexport interface LoadMemoryOpts {\n relevanceHint?: string;\n max?: number;\n /** Max Remember calls per session (default 25). Prevents runaway memory writes. */\n maxWritesPerSession?: number;\n /** Called after each successful memory write (auditing, UI indicators). */\n onMemorySaved?: (slug: string, type?: string) => void;\n /** User-scope dir for global memories (type=user/feedback). If set, Remember routes by type:\n * user/feedback → userDir (global, survives across projects), project/reference → writeDir. */\n userDir?: string;\n}\n\nexport async function loadMemory(\n fs: IFilesystem,\n dir: string | string[],\n opts: LoadMemoryOpts = {},\n): Promise<{ index: string; tools: AgentTool[] }> {\n const dirs = (Array.isArray(dir) ? dir : [dir]).filter(Boolean);\n const writeDir = dirs[0]; // writes go to first (project) scope\n const tools = [recallTool(fs, dirs), rememberTool(fs, writeDir, opts), memorySearchTool(fs, dirs)];\n\n // Merge pointers from all dirs' MEMORY.md files (dedup by slug, first wins).\n const allPointers: string[] = [];\n const seenSlugs = new Set<string>();\n let header = '';\n let hasContent = false;\n for (const d of dirs) {\n const indexPath = `${d}/MEMORY.md`;\n const md = (await fs.exists(indexPath)) ? (await fs.readFile(indexPath)).trim() : '';\n if (!md) continue;\n hasContent = true;\n const lines = md.split('\\n');\n if (!header) header = lines.filter((l) => !/^\\s*-\\s*\\[.+\\]\\(.+\\.md\\)/.test(l)).join('\\n').trim();\n for (const l of lines.filter((l) => /^\\s*-\\s*\\[.+\\]\\(.+\\.md\\)/.test(l))) {\n const slug = l.match(/\\]\\(([^)]+)\\.md\\)/)?.[1];\n if (slug && !seenSlugs.has(slug)) { seenSlugs.add(slug); allPointers.push(l); }\n }\n }\n\n // Always inject behavioral guidance — even for empty dirs, so the model knows HOW to create memories.\n if (!hasContent) return { index: MEMORY_PROMPT, tools };\n\n const { kept, rest } = topByRelevance(allPointers, opts.relevanceHint ?? '', (l) => l, opts.max ?? MAX_INDEX);\n const restSlugs = rest.map((l) => l.match(/\\]\\(([^)]+)\\.md\\)/)?.[1] ?? l.match(/\\[([^\\]]+)\\]/)?.[1] ?? '').filter(Boolean);\n\n const index =\n MEMORY_PROMPT + '\\n\\n' +\n '## Memory index (persistent context — recalled across sessions)\\n' +\n (header ? header + '\\n' : '') +\n kept.join('\\n') +\n (restSlugs.length ? `\\n- (${restSlugs.length} more learnings, slugs only — call \\`Recall\\` if relevant): ${restSlugs.join(', ')}` : '');\n return { index, tools };\n}\n\n/** Slugify free text into a safe kebab filename stem (no separators, bounded). */\nexport function slugify(s: string, fallback = 'note'): string {\n const base = String(s ?? '')\n .trim()\n .toLowerCase()\n .replace(/\\.md$/i, '')\n .replace(/[^\\w\\s-]/g, '')\n .replace(/[\\s_]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 48);\n return base || fallback;\n}\n\n/**\n * Persist a durable fact: write `<dir>/<slug>.md` and ensure a one-line pointer exists in\n * `<dir>/MEMORY.md` (created if missing). Idempotent on the index (won't duplicate a pointer).\n * This is the shared write path behind the `Remember` tool and automatic lesson capture.\n */\nexport async function writeFact(fs: IFilesystem, dir: string, slug: string, body: string, opts?: { type?: string; description?: string }): Promise<void> {\n await mkdirp(fs, dir);\n const content = opts?.type ? `---\\ntype: ${opts.type}\\n---\\n\\n${body}` : body;\n await fs.writeFile(`${dir}/${slug}.md`, content.endsWith('\\n') ? content : content + '\\n');\n const indexPath = `${dir}/MEMORY.md`;\n const idx = (await fs.exists(indexPath)) ? await fs.readFile(indexPath) : '# Memory Index\\n';\n const summary = opts?.description || body.split('\\n')[0].slice(0, 80);\n const line = `- [${slug}](${slug}.md) — ${summary}`;\n const lines = idx.split('\\n');\n const at = lines.findIndex((l) => l.includes(`(${slug}.md)`));\n if (at >= 0) {\n if (lines[at] !== line) { lines[at] = line; await fs.writeFile(indexPath, lines.join('\\n')); }\n } else {\n await fs.writeFile(indexPath, idx.replace(/\\s*$/, '') + `\\n${line}\\n`);\n }\n // Enforce index cap: drop oldest pointers when over limit (fact files survive — still Recall-able/searchable).\n await truncateIndex(fs, indexPath);\n}\n\nasync function truncateIndex(fs: IFilesystem, path: string): Promise<void> {\n const raw = await fs.readFile(path);\n if (raw.length <= MAX_INDEX_BYTES) {\n const count = raw.split('\\n').filter((l) => /^\\s*-\\s*\\[.+\\]\\(.+\\.md\\)/.test(l)).length;\n if (count <= MAX_INDEX_LINES) return;\n }\n const lines = raw.split('\\n');\n const pointerIdxs: number[] = [];\n for (let i = 0; i < lines.length; i++) if (/^\\s*-\\s*\\[.+\\]\\(.+\\.md\\)/.test(lines[i])) pointerIdxs.push(i);\n // Drop oldest (topmost) pointers until under both caps.\n const drop = new Set<number>();\n for (const pi of pointerIdxs) {\n const candidate = lines.filter((_, i) => !drop.has(i)).join('\\n');\n if (candidate.length <= MAX_INDEX_BYTES && pointerIdxs.length - drop.size <= MAX_INDEX_LINES) break;\n drop.add(pi);\n }\n if (drop.size) await fs.writeFile(path, lines.filter((_, i) => !drop.has(i)).join('\\n'));\n}\n\n/** Sanitize a slug: strip .md suffix, normalize path separators, block traversal. */\nfunction cleanSlug(raw: string): string {\n let s = String(raw ?? '').trim().replace(/\\.md$/i, '').replace(/\\\\/g, '/').replace(/\\/+/g, '/').replace(/^\\/|\\/$/g, '');\n while (s.includes('..')) s = s.replace(/\\.\\./g, '');\n return s;\n}\n\n/** Recursively list all fact slugs in the memory dir (relative paths without .md, excluding MEMORY.md). */\nasync function listSlugs(fs: IFilesystem, dir: string, prefix = ''): Promise<string[]> {\n let entries: string[];\n try { entries = await fs.readDir(dir); } catch { return []; }\n const out: string[] = [];\n for (const e of entries.sort()) {\n const full = dir === '/' ? `/${e}` : `${dir}/${e}`;\n const rel = prefix ? `${prefix}/${e}` : e;\n if (await fs.isDirectory(full)) out.push(...await listSlugs(fs, full, rel));\n else if (e.endsWith('.md') && e !== 'MEMORY.md') out.push(rel.replace(/\\.md$/, ''));\n }\n return out;\n}\n\n/** Load a single fact by slug; strips YAML frontmatter before returning. Returns null if not found. */\nasync function loadFact(fs: IFilesystem, dir: string, slug: string): Promise<string | null> {\n const path = `${dir}/${slug}.md`;\n try {\n const raw = await fs.readFile(path);\n const { body } = splitFrontmatter(raw);\n return body || raw;\n } catch { return null; }\n}\n\n/** Try loading a fact from multiple dirs (first hit wins). */\nasync function loadFactMulti(fs: IFilesystem, dirs: string[], slug: string): Promise<string | null> {\n for (const d of dirs) { const r = await loadFact(fs, d, slug); if (r != null) return r; }\n return null;\n}\n\n/** List all slugs across multiple dirs (deduped, first wins). */\nasync function listSlugsMulti(fs: IFilesystem, dirs: string[]): Promise<string[]> {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const d of dirs) for (const s of await listSlugs(fs, d)) if (!seen.has(s)) { seen.add(s); out.push(s); }\n return out;\n}\n\n/** A `Recall` tool that loads memory facts by slug — single, batch, or pattern. */\nfunction recallTool(fs: IFilesystem, dirs: string[]): AgentTool {\n return {\n name: 'Recall',\n description: 'Load memory facts by slug. Pass `slug` for one, `slugs` for several, or `pattern` (glob like \"auth*\") to match. Returns full bodies, separated by `--- slug ---` headers.',\n parameters: {\n type: 'object',\n properties: {\n slug: { type: 'string', description: 'single fact slug (filename without .md)' },\n slugs: { type: 'array', items: { type: 'string' }, description: 'multiple slugs to load at once' },\n pattern: { type: 'string', description: 'glob pattern to match against slugs (e.g. \"auth*\", \"*database*\")' },\n },\n },\n async run({ slug, slugs, pattern }, ctx: ToolContext) {\n let targets: string[] = [];\n if (slug) targets = [cleanSlug(slug)];\n else if (Array.isArray(slugs)) targets = slugs.map(cleanSlug).filter(Boolean);\n else if (pattern) {\n const escaped = String(pattern).replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp('^' + escaped.replace(/\\*/g, '.*').replace(/\\?/g, '.') + '$', 'i');\n targets = (await listSlugsMulti(fs, dirs)).filter((s) => re.test(s));\n }\n if (!targets.length) return `Error: no slugs resolved. Pass slug, slugs, or pattern.`;\n const parts: string[] = [];\n for (const s of targets.slice(0, 20)) {\n const body = await loadFactMulti(fs, dirs, s);\n if (body != null) parts.push(targets.length > 1 ? `--- ${s} ---\\n${body}` : body);\n else parts.push(targets.length > 1 ? `--- ${s} ---\\n[not found]` : `Error: no memory fact '${s}'.`);\n }\n if (targets.length > 20) parts.push(`(${targets.length - 20} more matched — narrow the pattern)`);\n return parts.join('\\n\\n');\n },\n };\n}\n\n/** Search across all memory fact files by content. Returns slug + matching snippet pairs, ranked by relevance. */\nfunction memorySearchTool(fs: IFilesystem, dirs: string[]): AgentTool {\n return {\n name: 'MemorySearch',\n description:\n 'Search memory facts by content — find relevant memories when you don\\'t know the exact slug. Returns up to 10 matching slug + snippet pairs, ranked by relevance. Use `regex: true` for regex patterns.',\n parameters: {\n type: 'object',\n required: ['query'],\n properties: {\n query: { type: 'string', description: 'search query (keywords or regex pattern)' },\n regex: { type: 'boolean', description: 'treat query as a regex pattern (default: false)' },\n },\n },\n async run({ query, regex }, ctx: ToolContext) {\n const q = String(query ?? '').trim();\n if (!q) return 'Error: empty query.';\n const slugs = await listSlugsMulti(fs, dirs);\n if (!slugs.length) return '(no memory facts found)';\n let matcher: (line: string) => boolean;\n if (regex) {\n try { const re = new RegExp(q, 'i'); matcher = (l) => re.test(l); } catch (e) { return `Error: invalid regex: ${e}`; }\n } else {\n const lower = q.toLowerCase();\n matcher = (l) => l.toLowerCase().includes(lower);\n }\n const loaded: { slug: string; body: string }[] = [];\n for (const slug of slugs) {\n const body = await loadFactMulti(fs, dirs, slug);\n if (body) loaded.push({ slug, body });\n }\n const idf = idfWeights(loaded.map((l) => l.body));\n const qTokens = tokenize(q);\n const hits: { slug: string; snippet: string; score: number }[] = [];\n for (const { slug, body } of loaded) {\n const lines = body.split('\\n');\n const matchLine = lines.find(matcher);\n if (!matchLine && !relevanceScore(body, qTokens, idf)) continue;\n const snippet = matchLine?.trim().slice(0, 120) || lines.find((l) => l.trim())?.trim().slice(0, 120) || '';\n hits.push({ slug, snippet, score: relevanceScore(body, qTokens, idf) });\n }\n if (!hits.length) return '(no matches)';\n hits.sort((a, b) => b.score - a.score);\n return hits.slice(0, 10).map((h) => `${h.slug}: ${h.snippet}`).join('\\n');\n },\n };\n}\n\n/** A `Remember` tool: persist a durable fact + index pointer so it's recalled in future sessions. */\nfunction rememberTool(fs: IFilesystem, dir: string, memOpts: LoadMemoryOpts = {}): AgentTool {\n const maxWrites = memOpts.maxWritesPerSession ?? 25;\n let writes = 0;\n return {\n name: 'Remember',\n description:\n 'Persist a durable fact for future sessions (a fix you found, a gotcha, a project constraint). Adds a pointer to the Memory index and stores the body. Use sparingly — only genuinely reusable knowledge, not task-specific scratch.',\n parameters: {\n type: 'object',\n required: ['fact'],\n properties: {\n fact: { type: 'string', description: 'the durable fact to remember (one or more lines)' },\n slug: { type: 'string', description: 'optional kebab-case id; derived from the fact if omitted' },\n type: { type: 'string', enum: ['user', 'feedback', 'project', 'reference'], description: 'memory category (user/feedback/project/reference)' },\n description: { type: 'string', description: 'one-line summary for the memory index (≤80 chars)' },\n },\n },\n async run({ fact, slug, type, description }, ctx: ToolContext) {\n const body = String(fact ?? '').trim();\n if (!body) return `Error: nothing to remember (empty fact).`;\n if (++writes > maxWrites) return `Rate limit: too many memories this session (${maxWrites}). Only persist genuinely durable facts.`;\n const name = slugify(slug || body.split('\\n')[0]);\n // Route by type: user/feedback → user scope (global); project/reference → project scope.\n const isGlobal = (type === 'user' || type === 'feedback') && memOpts.userDir;\n const targetDir = isGlobal ? memOpts.userDir! : dir;\n await writeFact(fs, targetDir, name, body, { type, description });\n memOpts.onMemorySaved?.(name, type);\n return `Remembered '${name}' (recallable in future sessions).`;\n },\n };\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\n\nconst DEFAULT_NAMES = ['AGENT.md', 'AGENTS.md', 'CLAUDE.md'];\n\n/**\n * Walk the VFS directory tree from `/` down, collecting instruction files\n * (AGENT.md, AGENTS.md, CLAUDE.md, .claude/<name>) at each level.\n * Merges all found files general-first → specific-last (mirrors Claude Code's\n * hierarchical CLAUDE.md discovery). First matching filename per directory wins\n * (no duplicates from the same level). Edge-portable: works over any IFilesystem.\n */\nexport async function loadInstructions(\n fs: IFilesystem,\n names: string[] = DEFAULT_NAMES,\n): Promise<string> {\n // First matching name wins (AGENT.md > AGENTS.md > CLAUDE.md).\n // Both root and .claude/ locations are checked for the winning name — anchored at the FS\n // working dir (in CC-parity disk mode root '/' is the real machine, so instructions live\n // under the launch dir, not '/'). With cwd '/' this is the original behavior.\n const cwd = fs.getCwd();\n const base = cwd === '/' ? '' : cwd;\n for (const name of names) {\n const sections: string[] = [];\n for (const path of [`${base}/${name}`, `${base}/.claude/${name}`]) {\n if (!(await fs.exists(path))) continue;\n const md = (await fs.readFile(path)).trim();\n if (md) sections.push(`<!-- ${path} -->\\n${md}`);\n }\n if (sections.length) {\n return `## Project instructions\\nRepository-specific instructions — follow them.\\n\\n${sections.join('\\n\\n---\\n\\n')}`;\n }\n }\n return '';\n}\n","import { mkdirSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike, Message } from './llm';\nimport type { AgentTool, ToolContext } from './tools';\nimport { toolsByName } from './tools';\nimport { resolveModelAlias } from './models';\nimport type { AgentDef } from './agents';\nimport type { Hooks } from './hooks';\nimport { Agent, type RunResult } from './Agent';\nimport { OverlayFilesystem } from './OverlayFilesystem';\nimport { findGitRoot, getOrCreateWorktree, cleanupWorktree } from './worktree';\nimport { NodeDiskFilesystem } from './NodeDiskFilesystem';\nimport { forComponent } from './logging';\n\nconst log = forComponent('subagent');\n\n/** Run items through `fn` with at most `limit` in flight, preserving result order. */\nasync function boundedPool<T, R>(items: T[], limit: number, fn: (item: T, i: number) => Promise<R>): Promise<R[]> {\n const out = new Array<R>(items.length);\n let next = 0;\n const worker = async () => { while (next < items.length) { const i = next++; out[i] = await fn(items[i], i); } };\n await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, worker));\n return out;\n}\n\nexport interface TaskToolOptions {\n /** The same ai.libx.js client the parent uses — the child shares it. */\n ai: ChatLike;\n model: string;\n /** The filesystem the child operates over (jail/scope it before passing, if desired). */\n fs: IFilesystem;\n /** Step budget for the child run (independent of the parent's). */\n maxSteps?: number;\n /** Recursion depth of the child this tool would spawn (0 = first level). */\n depth?: number;\n /** Hard ceiling on nesting — beyond this the tool refuses to spawn. */\n maxDepth?: number;\n /** Named subagent types selectable via the `agentType` param (persona + model + scoped tools). */\n agents?: AgentDef[];\n /** Max children running concurrently in a `TaskBatch` (default 4). */\n maxParallel?: number;\n /** Parent hooks — `onSubagentStop` fires with each child's summary when it finishes. */\n hooks?: Hooks;\n /**\n * Wall-clock ceiling for ONE child run, in ms (default `SUBAGENT_MAX_DURATION_MS`). `maxSteps` alone is\n * not a bound: 25 steps x a 600s Shell is ~250 minutes, far past any transport deadline wrapping the\n * parent — and an undeclared tool cannot be named by `toolTimeoutViolations`. This deadline is ENFORCED\n * (the child's signal is aborted) and therefore honestly declarable as the tool's `maxDurationMs`.\n */\n maxDurationMs?: number;\n /** The parent's toolbelt — the child INHERITS it by default (otherwise it falls back to the jailed\n * `defaultTools()` and loses everything the host injected: a real shell, Write/Grep, MCP tools).\n * An agentType def's `tools` allowlist still narrows it (and can name one of these by name). */\n tools?: AgentTool[];\n /** The parent's system prompt — inherited by a plain (untyped) child so it keeps the host's persona\n * instead of reverting to agentx's generic built-in one. An agentType def's body overrides it. */\n systemPrompt?: string;\n /** Provider-specific options for the CHILD's model, recomputed per child (IoC — same seam duplex uses\n * for its workers). The child's model may differ from the parent's (explicit `model` / agentType def),\n * and provider options are NOT portable across providers (cursor `cwd`/`cursorSession` on anthropic\n * is a hard 400), so they are derived, never blindly inherited. */\n providerOptionsFor?: (model: string) => Record<string, unknown> | undefined;\n /** Origin-anchored real-disk dir for child transcript traces (see `AgentOptions.traceDir`). Passed\n * down UNCHANGED to nested children so every level writes to the same origin `.agent`. */\n traceDir?: string;\n}\n\n/** Default wall-clock ceiling for one child run (30 min) — the bound `Task`/`TaskBatch` declare and enforce. */\nexport const SUBAGENT_MAX_DURATION_MS = 1_800_000;\n\n/** A child-scoped abort signal that fires on the PARENT's abort or after `ms`, whichever comes first.\n * `timedOut()` distinguishes the two so the tool result can say which happened. Always `dispose()`. */\nfunction wallClock(parent: AbortSignal | undefined, ms: number): { signal: AbortSignal; timedOut: () => boolean; dispose: () => void } {\n const ac = new AbortController();\n let fired = false;\n const onParent = () => ac.abort();\n const timer = setTimeout(() => { fired = true; ac.abort(); }, ms);\n if (parent) { if (parent.aborted) ac.abort(); else parent.addEventListener('abort', onParent, { once: true }); }\n return {\n signal: ac.signal,\n timedOut: () => fired,\n dispose: () => { clearTimeout(timer); parent?.removeEventListener('abort', onParent); },\n };\n}\n\n/** Appended to a timed-out child's hint so 'aborted' isn't misread as a user interrupt. */\nconst deadlineNote = (ms: number) =>\n `\\n[It was stopped by the sub-task wall-clock deadline of ${Math.round(ms / 1000)}s — not by the user. `\n + `Re-delegate a NARROWER sub-task (or continue from the trace); the same prompt will hit the same deadline again.]`;\n\ntype WorktreeHandle = { repoRoot: string; slug: string; worktreePath: string; branch: string };\n\nfunction sanitizeSlug(raw: string): string {\n return raw.replace(/[^a-zA-Z0-9._-]/g, '-').replace(/-+/g, '-').slice(0, 40);\n}\n\nfunction createWorktreeFs(cwd: string, label: string, index: number): WorktreeHandle | string {\n const repoRoot = findGitRoot(cwd);\n if (!repoRoot) return 'isolation: \"worktree\" requires a git repository';\n const slug = `sub-${index}-${sanitizeSlug(label)}`;\n try {\n const info = getOrCreateWorktree(repoRoot, slug);\n return { repoRoot, slug, worktreePath: info.worktreePath, branch: info.branch };\n } catch (e) { return `worktree creation failed: ${e instanceof Error ? e.message : String(e)}`; }\n}\n\nfunction releaseWorktree(handle: WorktreeHandle): { removed: boolean; reason?: string } {\n return cleanupWorktree(handle.repoRoot, handle.slug, { force: true });\n}\n\n/** Re-bind inherited tools that escape the VFS (the real `Shell`) to the child's own real-disk root.\n * The child inherits the parent's tool INSTANCES; a cwd-bound shell would otherwise run in the PARENT\n * repo while the child's fs points at its worktree — writing uncommitted files into the parent tree\n * which the worktree teardown then force-removes. Tools with no `withCwd` pass through unchanged; a\n * `withCwd` returning `undefined` means \"this capability cannot leave the parent\" and the tool is\n * DROPPED (the `ShellOutput`/`ShellStatus`/`ShellKill` job companions, which are bound to the\n * parent's registry — an isolated child must not read or SIGTERM the parent's background jobs). */\nfunction rebindTools(tools: AgentTool[] | undefined, root?: string): AgentTool[] | undefined {\n if (!tools || !root) return tools;\n return tools.flatMap((t) => {\n if (!t.withCwd) return [t];\n const rebound = t.withCwd(root);\n return rebound ? [rebound] : [];\n });\n}\n\nfunction worktreePromptPrefix(branch: string): string {\n return `You are running in an isolated git worktree on branch \"${branch}\". ` +\n 'When you finish making changes, commit them with a clear message before replying with your summary. ' +\n 'Your worktree will be removed after you finish — only committed work survives (on the branch).\\n\\n';\n}\n\n// ── Subagent tracing ──────────────────────────────────────────────────────────────────────────────\n// A child's transcript is otherwise ephemeral (only its final summary returns to the parent). We stream\n// it to a real-disk file under the ORIGIN's trace dir — bypassing the child's (possibly overlay/worktree)\n// fs on purpose, so the trace survives interruption AND worktree teardown. On a non-`stop` finish the tool\n// result becomes a STATUS HINT pointing here, instead of a dangling tool_call.\n\ninterface TraceMeta { label: string; agentType?: string; prompt: string }\n\nlet traceSeq = 0; // process-unique → no same-millisecond collisions across concurrent TaskBatch children\n\nfunction traceFileFor(dir: string, label: string, depth: number): string | undefined {\n try {\n mkdirSync(dir, { recursive: true });\n const id = `${Date.now().toString(36)}-${(traceSeq++).toString(36)}`;\n return join(dir, `${id}-d${depth}-${sanitizeSlug(label) || 'sub'}.json`);\n } catch (e) {\n log.warn(`subagent trace dir unavailable (${dir}) — running without a trace: ${e instanceof Error ? e.message : String(e)}`);\n return undefined; // tracing is best-effort infra; never block a delegation on it\n }\n}\n\nfunction flushTrace(file: string, meta: TraceMeta, messages: Message[], status: string): void {\n try {\n writeFileSync(file, JSON.stringify({ ...meta, status, updated: Date.now(), messages }, null, 2));\n } catch (e) {\n log.warn(`subagent trace flush failed (${file}): ${e instanceof Error ? e.message : String(e)}`);\n }\n}\n\n/** Wrap the child's host so each step boundary (`turn_start`) flushes the committed-so-far transcript. */\nfunction installTrace(child: Agent, file: string, meta: TraceMeta): void {\n const prev = child.options.host;\n child.options.host = {\n ...prev,\n notify: (e) => {\n if (e.kind === 'turn_start') flushTrace(file, meta, child.transcript, 'running');\n prev?.notify?.(e);\n },\n };\n}\n\n/** The tool result for a child that did NOT finish cleanly: status + what it got through + trace pointer\n * + an explicit decision prompt. Doubles as the back-fill that keeps the parent transcript valid (no\n * orphan tool_call) when an in-flight child is aborted. */\nfunction abortHint(label: string, res: RunResult, file?: string): string {\n const last = (res.text || '').trim().slice(0, 500);\n const lines = [\n `[sub-task '${label}' did NOT finish — ${res.finishReason} after ${res.steps} step(s). Treat its work as INCOMPLETE.]`,\n last ? `Progress so far: ${last}` : 'It produced no summary before stopping.',\n ];\n if (file) lines.push(`Full transcript (every step it took): ${file} — Read it to see what was actually done.`);\n lines.push(\"Decide: ignore it, re-delegate a fresh Task that continues from the trace, or start over. Do NOT assume the sub-task completed.\");\n return lines.join('\\n');\n}\n\n/** Run one child to completion with tracing + (on a non-clean finish) a status hint. The child inherits\n * the parent's abort `signal`, so Esc/Ctrl-C actually interrupts it — and the partial trace + hint are\n * what the parent picks up. `onSubagentStop` fires with whatever result (summary OR hint) the parent gets. */\nasync function runChildTraced(args: {\n opts: TaskToolOptions; childOpts: NonNullable<ConstructorParameters<typeof Agent>[0]>;\n prompt: string; label: string; agentType?: string; childDepth: number; signal?: AbortSignal;\n}): Promise<{ res: RunResult; result: string }> {\n const { opts, label, agentType, prompt } = args;\n const deadlineMs = opts.maxDurationMs ?? SUBAGENT_MAX_DURATION_MS;\n // ENFORCED wall clock. The child's own `timeoutMs` is an IDLE clock (it resets on every productive\n // step), so a busy child has no total bound at all — `maxSteps` x a 600s Shell runs for hours. This is\n // the bound the tool declares, so it has to actually fire.\n const wc = wallClock(args.signal, deadlineMs);\n args.childOpts.signal = wc.signal; // propagate cancellation → child stops with the parent, or with the deadline\n const file = opts.traceDir ? traceFileFor(opts.traceDir, label, args.childDepth) : undefined;\n const meta: TraceMeta = { label, agentType, prompt };\n const child = new Agent(args.childOpts);\n if (file) installTrace(child, file, meta);\n let res: RunResult;\n try { res = await child.run(prompt); } finally { wc.dispose(); }\n if (file) flushTrace(file, meta, child.transcript, wc.timedOut() ? 'deadline' : res.finishReason);\n let result = res.finishReason === 'stop'\n ? (res.text || `(child '${label}' finished with no summary; finishReason=${res.finishReason})`)\n : abortHint(label, res, file);\n if (wc.timedOut()) { log.warn(`sub-task '${label}' hit its ${deadlineMs}ms wall-clock deadline (steps=${res.steps})`); result += deadlineNote(deadlineMs); }\n await opts.hooks?.onSubagentStop?.(result, { label, agentType });\n return { res, result };\n}\n\n/** Resolve the constructor opts for one child agent (persona/model/tool scoping). Returns an error string on bad agentType. */\nfunction childOptionsFor(opts: TaskToolOptions, fs: IFilesystem, depth: number, maxDepth: number, agentType?: string, model?: string, root?: string): NonNullable<ConstructorParameters<typeof Agent>[0]> | string {\n let def: AgentDef | undefined;\n if (agentType) {\n def = (opts.agents ?? []).find((a) => a.name === agentType);\n if (!def) return `no subagent type '${agentType}'. Available: ${(opts.agents ?? []).map((a) => a.name).join(', ') || '(none defined)'}`;\n }\n // Model precedence: explicit per-invocation > agentType def > parent. Alias resolution happens HERE,\n // on the one seam every child model flows through — `loadAgents` deliberately keeps frontmatter raw.\n const childModel = resolveModelAlias(model || def?.model || opts.model);\n const childOpts: ConstructorParameters<typeof Agent>[0] = { ai: opts.ai, fs, model: childModel, subagents: true, depth: depth + 1, maxDepth, traceDir: opts.traceDir };\n if (opts.maxSteps != null) childOpts.maxSteps = opts.maxSteps;\n // Persona: a def's body overrides; otherwise inherit the parent's (a plain Task child used to fall\n // back to agentx's generic built-in prompt, losing the host's whole operating context).\n const childPrompt = def?.systemPrompt ?? opts.systemPrompt;\n if (childPrompt) childOpts.systemPrompt = childPrompt;\n // Toolbelt: inherit the parent's; a def's allowlist narrows it (resolved against the parent's tools\n // first, so it can name a host-injected/MCP tool, then the built-in registry).\n const inherited = rebindTools(opts.tools, root);\n if (def?.tools?.length) {\n try { childOpts.tools = toolsByName(def.tools, inherited); }\n catch (e) { return `subagent '${agentType}' declares an unknown tool — ${(e as Error).message}`; }\n } else if (inherited?.length) {\n childOpts.tools = inherited;\n }\n const po = opts.providerOptionsFor?.(childModel);\n if (po) childOpts.providerOptions = po;\n // Gate: the host's `preToolUse` guard applies to the child too. Only that one hook is inherited —\n // it is a SECURITY boundary (shraga-ee blocks reading secret files with it), and a child that now\n // inherits the parent's real toolbelt would otherwise be a one-line bypass for it. The observer /\n // lifecycle hooks stay parent-only on purpose: a child firing `onStop`/`onSessionStart` would\n // fabricate session events in the host's UI, and `onSubagentStop` already fires from the parent.\n if (opts.hooks?.preToolUse) childOpts.hooks = { preToolUse: opts.hooks.preToolUse.bind(opts.hooks) };\n return childOpts;\n}\n\n/**\n * `Task` tool — spawn a CHILD agent over the same VFS with its own step budget,\n * returning only its final summary to the parent. Use to fan out a self-contained\n * sub-task (search, refactor a subtree) without polluting the parent's context.\n * @returns the child's final text, or an error string if the depth limit is reached.\n */\nexport function makeTaskTool(opts: TaskToolOptions): AgentTool {\n const depth = opts.depth ?? 0;\n const maxDepth = opts.maxDepth ?? 2;\n return {\n name: 'Task',\n description:\n 'Delegate a self-contained sub-task to a child agent over the same filesystem. It runs autonomously with its own step budget and a wall-clock deadline, and returns a concise summary — use to isolate context-heavy work (broad search, a scoped refactor). Provide a short `description` and a full `prompt`. If it is interrupted or fails, the result is a STATUS HINT with a pointer to its full transcript (Read it to recover what it did, then decide whether to continue or restart) — do not assume an incomplete sub-task succeeded. Set `background: true` to run it detached (returns a job id to poll with JobOutput while you keep working); its VFS file edits are overlay-isolated and commit when it finishes — but a child that uses the real `Shell` writes straight to the working tree (an overlay cannot isolate a real process), so pair shell-heavy work with `isolation: \"worktree\"`. Set `isolation: \"worktree\"` to run in a real git worktree (needed when the child uses real shell commands that must see/modify actual files — its shell is re-bound to the worktree — keeping any name your host gave it — and background shell jobs, including inspecting or killing MINE, are unavailable there) — slower (~200ms setup), auto-cleaned if no changes. The child inherits YOUR tools and system prompt by default (and is subject to the same tool-use gate); pass `model` to run this one sub-task on a different model (e.g. a cheap one for bulk search, a stronger one for hard reasoning) — it overrides the agentType default.',\n parameters: {\n type: 'object',\n required: ['description', 'prompt'],\n properties: {\n description: { type: 'string', description: 'a short (3-5 word) label for the sub-task' },\n prompt: { type: 'string', description: 'the full instructions the child agent should carry out' },\n agentType: { type: 'string', description: 'optional named subagent type (its persona, model, and scoped tools) — see the catalog' },\n model: { type: 'string', description: 'optional model for THIS sub-task (alias like \"haiku\"/\"opus\"/\"sonnet\", or a full id). Overrides the agentType default; otherwise the child runs on your model.' },\n background: { type: 'boolean', description: 'run detached (overlay-isolated, commits on finish); returns a job id to poll with JobOutput instead of blocking' },\n isolation: { type: 'string', enum: ['overlay', 'worktree'], description: 'isolation mode: \"overlay\" (default, VFS layer) or \"worktree\" (real git worktree for shell-heavy work)' },\n },\n },\n // Declared because it is ENFORCED (see runChildTraced) — a transport above the loop sizes its own\n // deadline around this one (AgentTool.maxDurationMs). Declaring an unenforced number would be a lie;\n // declaring nothing left `Task` invisible to toolTimeoutViolations, which is the same hole.\n maxDurationMs: opts.maxDurationMs ?? SUBAGENT_MAX_DURATION_MS,\n maxDurationEnforced: true, // the wall clock below ABORTS the child at this bound — it cannot be overrun, so the transport needs slack, not a doubling\n\n async run({ description, prompt, agentType, model, background, isolation }, ctx: ToolContext) {\n if (depth >= maxDepth) {\n return `Error: Task depth limit reached (maxDepth ${maxDepth}). Cannot spawn another child agent — do this work directly instead.`;\n }\n const label = String(description ?? agentType ?? 'sub-task');\n\n const useWorktree = isolation === 'worktree';\n\n // Background: run the child detached over an isolated overlay via the job registry. This is where\n // sandbox backgrounding actually pays off — a child does real model calls, so it overlaps the parent.\n if (background && ctx.jobs) {\n const id = ctx.jobs.start(async ({ signal }) => {\n let fs: IFilesystem; let commit: () => Promise<void>; let wtHandle: WorktreeHandle | undefined;\n if (useWorktree) {\n const h = createWorktreeFs(process.cwd(), label, 0);\n if (typeof h === 'string') throw new Error(h);\n wtHandle = h; fs = new NodeDiskFilesystem(h.worktreePath); commit = async () => {};\n } else {\n const overlay = new OverlayFilesystem(opts.fs);\n fs = overlay; commit = () => overlay.commit();\n }\n const childOpts = childOptionsFor(opts, fs, depth, maxDepth, agentType, model, wtHandle?.worktreePath);\n if (typeof childOpts === 'string') throw new Error(childOpts);\n const childPrompt = wtHandle ? worktreePromptPrefix(wtHandle.branch) + String(prompt ?? '') : String(prompt ?? '');\n const { res, result } = await runChildTraced({ opts, childOpts, prompt: childPrompt, label, agentType, childDepth: depth + 1, signal });\n // Aborted before commit → don't merge partial edits, but DO return the hint+trace (the parent\n // can read what it did and decide), instead of the old opaque '[killed before commit]'.\n if (res.finishReason === 'aborted' || signal.aborted) { wtHandle && releaseWorktree(wtHandle); return result; }\n await commit();\n let summary = result;\n if (wtHandle) {\n const r = releaseWorktree(wtHandle);\n if (!r.removed) summary += `\\n\\n[worktree removal failed: ${r.reason}]`;\n }\n return summary;\n }, { kind: 'agent', label });\n return `Started background sub-task ${id} ('${label}') — poll with JobOutput({id:\"${id}\"}).`;\n }\n\n // Foreground: the child runs inline. Worktree isolation gives it a real disk fs; overlay keeps VFS.\n let fs: IFilesystem; let wtHandle: WorktreeHandle | undefined;\n if (useWorktree) {\n const h = createWorktreeFs(process.cwd(), label, 0);\n if (typeof h === 'string') return `Error: ${h}`;\n wtHandle = h; fs = new NodeDiskFilesystem(h.worktreePath);\n } else {\n fs = opts.fs;\n }\n const childOpts = childOptionsFor(opts, fs, depth, maxDepth, agentType, model, wtHandle?.worktreePath);\n if (typeof childOpts === 'string') { wtHandle && releaseWorktree(wtHandle); return `Error: ${childOpts}`; }\n try {\n const childPrompt = wtHandle ? worktreePromptPrefix(wtHandle.branch) + String(prompt ?? '') : String(prompt ?? '');\n // ctx.signal carries the parent's Esc/Ctrl-C → the child now actually stops with the parent\n // (it previously ran to completion, ignoring the interrupt). On stop we get the trace + hint.\n const { result } = await runChildTraced({ opts, childOpts, prompt: childPrompt, label, agentType, childDepth: depth + 1, signal: ctx.signal });\n let summary = result;\n if (wtHandle) {\n const r = releaseWorktree(wtHandle);\n if (!r.removed) summary += `\\n\\n[worktree removal failed: ${r.reason}]`;\n }\n return summary;\n } catch (e) {\n if (wtHandle) releaseWorktree(wtHandle);\n throw e;\n }\n },\n };\n}\n\n/**\n * `TaskBatch` tool — fan out several self-contained sub-tasks to child agents that run\n * **concurrently** (bounded pool), returning all their summaries together. Each child runs over its\n * OWN `OverlayFilesystem` (write-isolated from siblings), and successful children's edits are\n * committed **in array order** afterward — so concurrent writes resolve deterministically\n * (last index wins) instead of racing. Use to parallelize independent work (review N files, search M\n * subtrees, scoped refactors). For a single sub-task, use `Task`.\n */\nexport function makeTaskBatchTool(opts: TaskToolOptions): AgentTool {\n const depth = opts.depth ?? 0;\n const maxDepth = opts.maxDepth ?? 2;\n const maxParallel = opts.maxParallel ?? 4;\n return {\n name: 'TaskBatch',\n description:\n 'Delegate SEVERAL independent sub-tasks to child agents that run concurrently; returns all their summaries. Each child is write-isolated at the VFS level (its file edits are merged back in array order); real `Shell` commands are NOT — use `isolation: \"worktree\"` for those. Use for parallel fan-out (review/search/scoped refactors across files). Provide `tasks: [{ description, prompt, agentType?, model? }]` — each child inherits your tools and system prompt, and `model` runs that one child on a different model. Set `isolation: \"worktree\"` to run each child in its own git worktree (needed for real shell commands) — slower, auto-cleaned if no changes.',\n parameters: {\n type: 'object',\n required: ['tasks'],\n properties: {\n tasks: {\n type: 'array',\n description: 'the sub-tasks to run in parallel',\n items: {\n type: 'object',\n required: ['description', 'prompt'],\n properties: {\n description: { type: 'string', description: 'a short (3-5 word) label' },\n prompt: { type: 'string', description: 'the full instructions for this child' },\n agentType: { type: 'string', description: 'optional named subagent type' },\n model: { type: 'string', description: 'optional model for this child (alias or full id); overrides the agentType default' },\n },\n },\n },\n isolation: { type: 'string', enum: ['overlay', 'worktree'], description: 'isolation mode for ALL children: \"overlay\" (default) or \"worktree\" (real git worktree each)' },\n },\n },\n // Same enforced bound as `Task`, applied to the WHOLE batch (below), not per child — otherwise the\n // honest ceiling would be ceil(n/maxParallel) x the per-child deadline, i.e. unbounded in `tasks`.\n maxDurationMs: opts.maxDurationMs ?? SUBAGENT_MAX_DURATION_MS,\n maxDurationEnforced: true, // the wall clock below ABORTS the child at this bound — it cannot be overrun, so the transport needs slack, not a doubling\n\n async run({ tasks, isolation }, ctx: ToolContext) {\n if (depth >= maxDepth) return `Error: Task depth limit reached (maxDepth ${maxDepth}). Cannot spawn child agents — do this work directly instead.`;\n const list = Array.isArray(tasks) ? tasks : [];\n if (!list.length) return 'Error: TaskBatch needs a non-empty `tasks` array.';\n const useWorktree = isolation === 'worktree';\n const batchDeadlineMs = opts.maxDurationMs ?? SUBAGENT_MAX_DURATION_MS;\n const batchClock = wallClock(ctx.signal, batchDeadlineMs);\n\n type Outcome = { label: string; text?: string; error?: string; overlay?: OverlayFilesystem; wtHandle?: WorktreeHandle; ok: boolean };\n const results = await boundedPool<any, Outcome>(list, maxParallel, async (t, i) => {\n const label = String(t?.description ?? t?.agentType ?? `task ${i + 1}`);\n let fs: IFilesystem; let overlay: OverlayFilesystem | undefined; let wtHandle: WorktreeHandle | undefined;\n if (useWorktree) {\n const h = createWorktreeFs(process.cwd(), label, i);\n if (typeof h === 'string') return { label, error: h, ok: false };\n wtHandle = h; fs = new NodeDiskFilesystem(h.worktreePath);\n } else {\n overlay = new OverlayFilesystem(opts.fs);\n fs = overlay;\n }\n const childOpts = childOptionsFor(opts, fs, depth, maxDepth, t?.agentType, t?.model, wtHandle?.worktreePath);\n if (typeof childOpts === 'string') return { label, error: childOpts, ok: false };\n try {\n const childPrompt = wtHandle ? worktreePromptPrefix(wtHandle.branch) + String(t?.prompt ?? '') : String(t?.prompt ?? '');\n const { res, result } = await runChildTraced({ opts, childOpts, prompt: childPrompt, label, agentType: t?.agentType, childDepth: depth + 1, signal: batchClock.signal });\n // Merge edits for natural completions (incl. max_steps/budget), but NOT a user-cancelled child —\n // signal propagation now makes 'aborted' reachable here; merging its half-done work would be wrong\n // (mirrors the single-Task background path, which skips commit on abort).\n return { label, text: result, overlay, wtHandle, ok: res.finishReason !== 'error' && res.finishReason !== 'aborted' };\n } catch (e) { return { label, error: e instanceof Error ? e.message : String(e), wtHandle, ok: false }; }\n }).finally(() => batchClock.dispose());\n\n // Overlay mode: merge successful children's edits in array order (deterministic last-writer-wins).\n // Worktree mode: force-remove each worktree (committed work survives on the branch).\n const lines: string[] = [];\n for (const r of results) {\n if (r.ok && r.overlay) await r.overlay.commit().catch(() => {});\n let extra = '';\n if (r.wtHandle) {\n const wr = releaseWorktree(r.wtHandle);\n if (!wr.removed) extra = `\\n[worktree removal failed: ${wr.reason}]`;\n }\n lines.push(`### ${lines.length + 1}. ${r.label}\\n${r.error ? `ERROR: ${r.error}` : (r.text || '(no summary)')}${extra}`);\n }\n\n return lines.join('\\n\\n') + (batchClock.timedOut() ? deadlineNote(batchDeadlineMs) : '');\n },\n };\n}\n","/**\n * Model aliasing + mid-conversation switch resolution — pure, dependency-free.\n *\n * Harness-level so every agentx consumer (unclaw, para-chat, …) resolves `[opus]`-style\n * aliases, gates by an allow-list, and announces a switch the same way. Policy (which models\n * a caller may use) and session state (the prior model) stay with the consumer; this module\n * is the shared mechanism.\n */\n\n/** Canonical short aliases → concrete Anthropic model ids. */\nexport const MODEL_ALIASES: Record<string, string> = {\n fable: 'claude-fable-5',\n 'fable-5': 'claude-fable-5',\n opus: 'claude-opus-4-8',\n 'opus-4-8': 'claude-opus-4-8',\n 'opus-4-7': 'claude-opus-4-7',\n 'opus-4-6': 'claude-opus-4-6',\n sonnet: 'claude-sonnet-4-6',\n haiku: 'claude-haiku-4-5-20251001',\n};\n\n/** Resolve an alias to a concrete id. A provider prefix (\"anthropic/\") is preserved; unknown ids pass through. */\nexport function resolveModelAlias(input: string): string {\n const slash = input.indexOf('/');\n const prefix = slash === -1 ? '' : input.slice(0, slash + 1);\n const rest = slash === -1 ? input : input.slice(slash + 1);\n return prefix + (MODEL_ALIASES[rest.toLowerCase()] ?? rest);\n}\n\n/** The provider of a model id (\"cursor/x\" -> \"cursor\"). Provider-specific `providerOptions` are only\n * portable within the same provider — leaking them across is a hard 400.\n *\n * A BARE id is the common case, not the exception: `resolveModelAlias('haiku')` yields\n * `claude-haiku-4-5-20251001` with no prefix (ai.libx.js resolves it fuzzily downstream), so reading\n * only the literal \"/\" made every aliased child look like a provider switch and silently dropped the\n * parent's options. The fix belongs HERE — the alias table must keep emitting the ids ai.libx.js\n * expects, and the comparison is provider identity, not string identity.\n *\n * A bare id we can't attribute is UNKNOWN, not a shared provider: it gets a per-id marker so two\n * different unknown ids never compare equal (returning \"\" for both made them look like one provider\n * and would have leaked one host's options onto the other's model). An unknown id still compares\n * equal to ITSELF, so a child staying on the parent's exact model keeps the parent's options. */\nexport function modelProvider(model: string): string {\n const i = model.indexOf('/');\n if (i !== -1) return model.slice(0, i);\n if (/^claude-/i.test(model)) return 'anthropic';\n return `?${model}`; // unknown: identity-scoped, never equal to a different unknown id\n}\n\n/** Short, human-friendly name for a resolved model id (e.g. \"anthropic/claude-opus-4-8\" → \"opus\"). */\nexport function modelShortLabel(model?: string): string {\n if (!model) return 'default';\n const id = model.split('/').pop()!;\n return id.replace(/^claude-/, '').replace(/-\\d.*$/, '');\n}\n\nexport interface ResolveModelSwitchOpts {\n /** Model requested for this turn (e.g. from an inline directive). Undefined = keep `current`. */\n requested?: string;\n /** The turn's default/current model when nothing is requested. */\n current: string;\n /** The session's prior resolved model — drives change detection + the notice. */\n prior?: string;\n /** If set, `requested` must match one of these (by short label) or it's denied and `current` is kept. */\n allowed?: string[];\n /** Announcement formatter. Default: `_[switching from x to y]_\\n\\n`. */\n format?: (from: string, to: string) => string;\n}\n\nexport interface ModelSwitch {\n /** The model to run this turn. */\n model: string;\n /** True when `requested` was rejected by `allowed` and `model` fell back to `current`. */\n denied: boolean;\n /** Inline notice to surface when the model actually changed vs `prior`, else undefined. */\n notice?: string;\n}\n\n/**\n * Resolve which model a turn runs, given an optional request, an allow-list, and the prior model.\n * Comparisons are by short label so provider-prefixed and dated ids unify\n * (\"anthropic/claude-opus-4-8\" ≡ \"claude-opus-4-8\" ≡ \"opus\").\n */\nexport function resolveModelSwitch(opts: ResolveModelSwitchOpts): ModelSwitch {\n const { requested, current, prior, allowed } = opts;\n if (!requested) return { model: current, denied: false };\n if (allowed && !allowed.some((a) => modelShortLabel(a) === modelShortLabel(requested))) {\n return { model: current, denied: true };\n }\n const fmt = opts.format ?? ((from: string, to: string) => `_[switching from ${from} to ${to}]_\\n\\n`);\n const changed = prior !== undefined && modelShortLabel(prior) !== modelShortLabel(requested);\n return {\n model: requested,\n denied: false,\n notice: changed ? fmt(modelShortLabel(prior!), modelShortLabel(requested)) : undefined,\n };\n}\n","import { spawnSync } from 'node:child_process';\nimport { symlinkSync, mkdirSync, statSync, readFileSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst VALID_SEGMENT = /^[a-zA-Z0-9._-]+$/;\nconst MAX_SLUG_LENGTH = 64;\nconst GIT_NO_PROMPT_ENV = { GIT_TERMINAL_PROMPT: '0', GIT_ASKPASS: '' };\n\nexport function validateWorktreeSlug(slug: string): void {\n if (!slug) throw new Error('worktree slug must not be empty');\n if (slug.length > MAX_SLUG_LENGTH) throw new Error(`worktree slug must be ≤${MAX_SLUG_LENGTH} chars (got ${slug.length})`);\n for (const seg of slug.split('/')) {\n if (seg === '.' || seg === '..') throw new Error(`worktree slug must not contain \".\" or \"..\" segments`);\n if (!VALID_SEGMENT.test(seg)) throw new Error(`worktree slug segment \"${seg}\" contains invalid characters (allowed: a-z A-Z 0-9 . _ -)`);\n }\n}\n\nfunction flattenSlug(slug: string): string { return slug.replaceAll('/', '+'); }\nexport function worktreeBranchName(slug: string): string { return `worktree-${flattenSlug(slug)}`; }\nfunction worktreesDir(repoRoot: string): string { return join(repoRoot, '.claude', 'worktrees'); }\nfunction worktreePathFor(repoRoot: string, slug: string): string { return join(worktreesDir(repoRoot), flattenSlug(slug)); }\n\nfunction git(args: string[], cwd: string): { ok: boolean; stdout: string; stderr: string } {\n const r = spawnSync('git', args, {\n cwd, stdio: ['ignore', 'pipe', 'pipe'],\n env: { ...process.env, ...GIT_NO_PROMPT_ENV },\n });\n return { ok: r.status === 0, stdout: (r.stdout ?? '').toString().trim(), stderr: (r.stderr ?? '').toString().trim() };\n}\n\nexport interface WorktreeInfo {\n worktreePath: string;\n branch: string;\n headCommit: string;\n existed: boolean;\n baseBranch?: string;\n}\n\nexport function findGitRoot(from: string): string | null {\n const r = git(['rev-parse', '--show-toplevel'], from);\n return r.ok ? r.stdout : null;\n}\n\nfunction readWorktreeHead(worktreePath: string): string | null {\n try {\n const gitFile = readFileSync(join(worktreePath, '.git'), 'utf-8').trim();\n const m = gitFile.match(/^gitdir:\\s*(.+)$/);\n if (!m) return null;\n const headPath = join(m[1], 'HEAD');\n const head = readFileSync(headPath, 'utf-8').trim();\n const refMatch = head.match(/^ref:\\s*(.+)$/);\n if (!refMatch) return head.length === 40 ? head : null;\n const refPath = join(m[1], '..', refMatch[1]);\n try { return readFileSync(refPath, 'utf-8').trim(); } catch { /* packed ref — fall through to git */ }\n const r = git(['rev-parse', 'HEAD'], worktreePath);\n return r.ok ? r.stdout : null;\n } catch { return null; }\n}\n\nexport function getOrCreateWorktree(repoRoot: string, slug: string): WorktreeInfo {\n validateWorktreeSlug(slug);\n const worktreePath = worktreePathFor(repoRoot, slug);\n const branch = worktreeBranchName(slug);\n\n const existingHead = readWorktreeHead(worktreePath);\n if (existingHead) return { worktreePath, branch, headCommit: existingHead, existed: true };\n\n mkdirSync(worktreesDir(repoRoot), { recursive: true });\n\n const defaultBranch = git(['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'], repoRoot);\n let baseBranch = defaultBranch.ok ? defaultBranch.stdout.replace(/^origin\\//, '') : 'HEAD';\n\n const originRef = `origin/${baseBranch}`;\n const hasOrigin = git(['rev-parse', '--verify', originRef], repoRoot);\n if (!hasOrigin.ok) {\n const fetched = git(['fetch', 'origin', baseBranch], repoRoot);\n if (!fetched.ok) baseBranch = 'HEAD';\n }\n const base = baseBranch === 'HEAD' ? 'HEAD' : originRef;\n\n const r = git(['worktree', 'add', '-B', branch, worktreePath, base], repoRoot);\n if (!r.ok) throw new Error(`failed to create worktree: ${r.stderr}`);\n\n const headSha = git(['rev-parse', 'HEAD'], worktreePath);\n\n symlinkDirs(repoRoot, worktreePath, ['node_modules', '.bun']);\n\n return { worktreePath, branch, headCommit: headSha.stdout, existed: false, baseBranch };\n}\n\nfunction symlinkDirs(repoRoot: string, worktreePath: string, dirs: string[]): void {\n for (const dir of dirs) {\n const src = join(repoRoot, dir);\n const dst = join(worktreePath, dir);\n try { statSync(src); } catch { continue; }\n try { symlinkSync(src, dst, 'dir'); } catch (e: any) { if (e?.code !== 'EEXIST') console.error(`[worktree] symlink ${dir}: ${e?.message ?? e}`); }\n }\n}\n\nexport function cleanupWorktree(repoRoot: string, slug: string, opts?: { force?: boolean }): { removed: boolean; reason?: string } {\n validateWorktreeSlug(slug);\n const worktreePath = worktreePathFor(repoRoot, slug);\n const branch = worktreeBranchName(slug);\n\n try { statSync(worktreePath); } catch { return { removed: false, reason: 'not found' }; }\n\n if (!opts?.force) {\n const status = git(['status', '--porcelain', '-uno'], worktreePath);\n if (status.ok && status.stdout) return { removed: false, reason: 'uncommitted changes' };\n }\n\n // Remove symlinks first so git worktree remove doesn't try to recurse into them\n for (const dir of ['node_modules', '.bun']) {\n try { rmSync(join(worktreePath, dir)); } catch { /* ok */ }\n }\n\n const rm = git(['worktree', 'remove', '--force', worktreePath], repoRoot);\n if (!rm.ok) return { removed: false, reason: rm.stderr };\n\n git(['branch', '-D', branch], repoRoot);\n return { removed: true };\n}\n\nexport interface WorktreeSession {\n originalCwd: string;\n worktreePath: string;\n slug: string;\n branch: string;\n headCommit: string;\n}\n\nlet _session: WorktreeSession | null = null;\nexport function getWorktreeSession(): WorktreeSession | null { return _session; }\n\nexport function enterWorktree(slug: string, cwd: string): WorktreeSession {\n const repoRoot = findGitRoot(cwd);\n if (!repoRoot) throw new Error('--worktree requires a git repository');\n\n const info = getOrCreateWorktree(repoRoot, slug);\n process.chdir(info.worktreePath);\n\n _session = {\n originalCwd: cwd,\n worktreePath: info.worktreePath,\n slug,\n branch: info.branch,\n headCommit: info.headCommit,\n };\n return _session;\n}\n\nexport function exitWorktree(): { removed: boolean; reason?: string } | null {\n if (!_session) return null;\n const repoRoot = findGitRoot(_session.originalCwd);\n if (!repoRoot) return null;\n\n process.chdir(_session.originalCwd);\n const result = cleanupWorktree(repoRoot, _session.slug);\n _session = null;\n return result;\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\n\n/**\n * Typed subagents — named child-agent definitions from `<dir>/<name>.md`, each with a\n * description, an optional model + tool allowlist (frontmatter), and a system prompt (the\n * body). The `Task` tool's `agentType` selects one, so a delegated sub-task runs with its\n * own persona, model, and scoped tools — the Claude-Code `.claude/agents` model.\n * VFS-backed (edge-portable), mirroring loadSkills / loadCommands.\n */\nexport interface AgentDef {\n name: string;\n description: string;\n /** The .md body — used as the child's system prompt (overrides the default). */\n systemPrompt?: string;\n /** Optional model override for this subagent type. */\n model?: string;\n /** Optional tool-name allowlist (scopes the child's tools). */\n tools?: string[];\n}\n\n/** Lean frontmatter parse for `description`/`model`/`tools` (no YAML dependency). */\nfunction parseAgentFrontmatter(md: string): { description?: string; model?: string; tools?: string[]; body: string } {\n const m = md.match(/^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n?/);\n const block = m ? m[1] : '';\n const get = (k: string) => {\n const r = new RegExp(`^${k}\\\\s*:\\\\s*(.+)$`, 'im').exec(block);\n return r ? r[1].trim().replace(/^[\"']|[\"']$/g, '') : undefined;\n };\n const toolsRaw = get('tools');\n const tools = toolsRaw\n ? toolsRaw.replace(/^\\[|\\]$/g, '').split(',').map((s) => s.trim().replace(/^[\"']|[\"']$/g, '')).filter(Boolean)\n : undefined;\n return { description: get('description'), model: get('model'), tools, body: (m ? md.slice(m[0].length) : md).trim() };\n}\n\n/** Discover subagent definitions under `dir` and a catalog block for the system prompt. */\nexport async function loadAgents(fs: IFilesystem, dir: string): Promise<{ agents: AgentDef[]; catalog: string }> {\n const agents: AgentDef[] = [];\n if (await fs.exists(dir)) {\n for (const entry of await fs.readDir(dir)) {\n if (!entry.endsWith('.md')) continue;\n const fm = parseAgentFrontmatter(await fs.readFile(`${dir}/${entry}`));\n agents.push({\n name: entry.replace(/\\.md$/, ''),\n description: fm.description || '',\n systemPrompt: fm.body || undefined,\n model: fm.model,\n tools: fm.tools,\n });\n }\n }\n if (!agents.length) return { agents, catalog: '' };\n const catalog =\n '## Subagent types (pass as the `Task` tool `agentType`)\\n' +\n agents.map((a) => `- **${a.name}** — ${a.description}`).join('\\n');\n return { agents, catalog };\n}\n","import type { Hooks, ToolUse } from './hooks';\nimport type { HostBridge, AgentTool } from './tools';\nimport { globToRegExp } from './tools.structured';\n\n/**\n * Permissions & plan-mode — safe-autonomy controls built ENTIRELY on the hooks +\n * host seams (no Agent-core changes needed). Two pieces:\n * - PermissionPolicy → Hooks: allow / ask (host.confirm) / deny a tool call by tool\n * name + path glob. First matching rule wins; default decision otherwise.\n * - planMode(): blocks mutating tools until the agent presents a plan via `ExitPlanMode`\n * and the host approves — Claude-Code-style plan gating.\n */\nexport type Decision = 'allow' | 'ask' | 'deny';\n\n/** Match a shell command against a rule glob where `*` spans anything (including spaces and `/`),\n * e.g. `git *` → any git subcommand, `rm *` → any rm invocation. Literals are regex-escaped. */\nfunction commandMatches(glob: string, cmd: string): boolean {\n const pattern = glob.split('*').map((s) => s.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&')).join('.*');\n return new RegExp('^' + pattern + '$').test(cmd);\n}\n\nexport interface PermissionRule {\n /** tool name to match (omit = any tool). */\n tool?: string;\n /** glob on the call's `path` arg to match (omit = any/none). */\n pathGlob?: string;\n decision: Decision;\n}\n\nexport class PermissionOptions {\n rules: PermissionRule[] = [];\n /** decision when no rule matches. */\n default: Decision = 'allow';\n /** host channel for `ask` (confirm). If absent, `ask` is treated as `deny` (fail-closed). */\n host?: HostBridge;\n /** Richer ask resolver (CLI surfaces a Yes/No/Always menu). Returns the decision + whether to\n * remember it — on remember, the policy adds a session rule so the same tool isn't re-asked.\n * If unset, falls back to `host.confirm` (plain yes/no). */\n ask?(call: ToolUse): Promise<{ decision: 'allow' | 'deny'; remember?: boolean } | undefined>;\n}\n\nexport class PermissionPolicy {\n public options: PermissionOptions;\n constructor(options?: Partial<PermissionOptions>) {\n this.options = { ...new PermissionOptions(), ...options };\n }\n\n /** Resolve the decision for a tool call (first matching rule, else default). */\n decide(call: ToolUse): Decision {\n // Deferred MCP (`McpCall({name})`) routes many tools through ONE agent tool — rules written\n // against the underlying `mcp__server__tool` name must still match (deny rules especially).\n const names = call.name === 'McpCall' && typeof call.args?.name === 'string' ? [call.name, call.args.name] : [call.name];\n for (const r of this.options.rules) {\n if (r.tool && !names.includes(r.tool)) continue;\n if (r.pathGlob) {\n // The glob matches a file `path` (path-glob semantics, slash-normalized) OR a `command`\n // string (`Shell(git *)`/`bash(rm *)`) — commands use *=anything (slashes included).\n const path = typeof call.args?.path === 'string' ? call.args.path : null;\n const cmd = typeof call.args?.command === 'string' ? call.args.command : null;\n if (path != null) {\n if (!globToRegExp(r.pathGlob).test(path.startsWith('/') ? path : `/${path}`)) continue;\n } else if (cmd != null) {\n if (!commandMatches(r.pathGlob, cmd)) continue;\n } else continue; // rule has a glob but the call exposes neither path nor command\n }\n return r.decision;\n }\n return this.options.default;\n }\n\n /** A preToolUse hook enforcing this policy (deny/ask → block; allow → proceed). */\n hooks(): Hooks {\n return {\n preToolUse: async (call) => {\n const d = this.decide(call);\n if (d === 'allow') return;\n if (d === 'deny') return { block: true, reason: `denied by permission policy (${call.name})` };\n // ask — prefer the richer resolver (Yes/No/Always); fall back to a plain confirm.\n if (this.options.ask) {\n const r = await this.options.ask(call);\n const decision = r?.decision ?? 'deny';\n // Remember the UNDERLYING tool for deferred MCP — remembering 'McpCall' itself would\n // blanket-approve every MCP tool from one answer. decide() aliases it back on match.\n const rememberTool = call.name === 'McpCall' && typeof call.args?.name === 'string' ? call.args.name : call.name;\n if (r?.remember) this.options.rules.unshift({ tool: rememberTool, decision }); // session-remember (wins next time)\n return decision === 'allow' ? undefined : { block: true, reason: `not approved (${call.name})` };\n }\n const ok = await this.options.host?.confirm?.(`Allow ${call.name}${call.args?.path ? ' on ' + call.args.path : ''}?`);\n return ok ? undefined : { block: true, reason: `not approved (${call.name})` };\n },\n };\n }\n}\n\n/** Tools the agent must not run before the plan is approved (sensible default). */\nexport const DEFAULT_MUTATING = ['Write', 'Edit', 'MultiEdit', 'deleteFile', 'bash'];\n\n/**\n * Plan-mode: mutating tools are BLOCKED until the agent calls `ExitPlanMode` with a plan\n * and (if a host is present) the user approves it. Returns the gating hook + the tool to\n * add to the agent. Compose the hook with others via composeHooks().\n */\nexport function planMode(opts?: { mutating?: string[]; host?: HostBridge }): { hooks: Hooks; tool: AgentTool } {\n const mutating = new Set(opts?.mutating ?? DEFAULT_MUTATING);\n let approved = false;\n const tool: AgentTool = {\n name: 'ExitPlanMode',\n description: 'Call when your plan is ready and you want to start making changes. Provide the `plan`. Until this is approved, edits/writes are blocked.',\n parameters: { type: 'object', required: ['plan'], properties: { plan: { type: 'string', description: 'the concrete steps you will take' } } },\n async run({ plan }, _ctx) {\n if (opts?.host?.confirm) {\n const confirm = opts.host.confirm(`Approve this plan?\\n\\n${String(plan ?? '')}`);\n const ok = await (_ctx?.parkHuman ? _ctx.parkHuman(confirm) : confirm); // exclude approval wait from the timeout\n if (!ok) return 'Plan not approved. Revise it and call ExitPlanMode again.';\n }\n approved = true;\n return 'Plan approved — you may now make changes.';\n },\n };\n const hooks: Hooks = {\n preToolUse: (call) =>\n !approved && mutating.has(call.name)\n ? { block: true, reason: 'plan mode: present a plan and call ExitPlanMode (approved) before editing.' }\n : undefined,\n };\n return { hooks, tool };\n}\n\n/** Run several Hooks as one: preToolUse stops at the first block; post/stop all fire. */\nexport function composeHooks(...list: (Hooks | undefined)[]): Hooks {\n const hooks = list.filter(Boolean) as Hooks[];\n return {\n async preToolUse(call, meta) {\n for (const h of hooks) {\n const d = await h.preToolUse?.(call, meta);\n if (d?.block) return d;\n }\n },\n async postToolUse(call, result, meta) { for (const h of hooks) await h.postToolUse?.(call, result, meta); },\n onToolOutput(call, chunk, meta) { for (const h of hooks) h.onToolOutput?.(call, chunk, meta); },\n onStop(text) { for (const h of hooks) h.onStop?.(text); },\n // lifecycle: concatenate session-start context; chain prompt-submit transforms; fan out pre-compact.\n async onSessionStart() {\n let ctx = '';\n for (const h of hooks) { const r = await h.onSessionStart?.(); if (r) ctx += (ctx ? '\\n\\n' : '') + r; }\n return ctx || undefined;\n },\n async onUserPromptSubmit(text) {\n let t = text;\n for (const h of hooks) { const r = await h.onUserPromptSubmit?.(t); if (typeof r === 'string') t = r; }\n return t;\n },\n async onPreCompact(messages) { for (const h of hooks) await h.onPreCompact?.(messages); },\n async onSubagentStop(summary, info) { for (const h of hooks) await h.onSubagentStop?.(summary, info); },\n };\n}\n","/**\n * Conservative, dependency-free syntax sanity check for code files (edge-safe pure JS).\n * Goal: catch an unambiguously-broken write (unbalanced/mis-nested delimiters) BEFORE it\n * lands, so the model doesn't later waste a turn re-reading + re-editing. Deliberately narrow:\n * it ONLY checks balanced ()/[]/{} after skipping string literals and comments, and ONLY\n * reports when delimiters are clearly wrong. Never throws.\n */\n\nconst CODE_RE = /\\.(ts|tsx|js|jsx|mjs|cjs)$/;\n\n/** Returns an error message if `content` is clearly broken for a code file, else null. */\nexport function checkSyntax(path: string, content: string): string | null {\n if (!CODE_RE.test(path)) return null; // only code files\n try {\n const open: Record<string, string> = { ')': '(', ']': '[', '}': '{' };\n const names: Record<string, string> = { '(': \"'('\", '[': \"'['\", '{': \"'{'\" };\n const stack: string[] = [];\n const n = content.length;\n for (let i = 0; i < n; i++) {\n const c = content[i];\n // line comment\n if (c === '/' && content[i + 1] === '/') {\n while (i < n && content[i] !== '\\n') i++;\n continue;\n }\n // block comment\n if (c === '/' && content[i + 1] === '*') {\n i += 2;\n while (i < n && !(content[i] === '*' && content[i + 1] === '/')) i++;\n i++; // skip the closing '/' (loop's i++ skips '*')\n continue;\n }\n // string / template literals — skip with escape handling\n if (c === '\"' || c === \"'\" || c === '`') {\n const quote = c;\n i++;\n while (i < n) {\n if (content[i] === '\\\\') { i += 2; continue; }\n if (content[i] === quote) break;\n i++;\n }\n continue;\n }\n if (c === '(' || c === '[' || c === '{') stack.push(c);\n else if (c === ')' || c === ']' || c === '}') {\n const want = open[c];\n if (stack.length === 0) return `Syntax check failed for ${path}: unexpected closing '${c}'. Fix before writing.`;\n const top = stack.pop()!;\n if (top !== want) return `Syntax check failed for ${path}: mismatched '${c}' (expected to close ${names[top]}). Fix before writing.`;\n }\n }\n if (stack.length > 0) {\n const ch = stack[stack.length - 1];\n return `Syntax check failed for ${path}: unbalanced ${names[ch]} (${stack.length} unclosed). Fix before writing.`;\n }\n return null;\n } catch {\n return null; // never throw — lint is a guard, not a gate that can crash a write\n }\n}\n","/**\n * Normalized reasoning/thinking control → provider-specific request fragment.\n *\n * Pure & dependency-free (no `ai.libx.js` import — provider is detected from the\n * `provider/model` prefix), so it stays inside the Agent's structural-typing boundary.\n * The returned fragment is spread into `ai.chat()`; callers never hand-craft the\n * per-provider encoding (Anthropic `thinking.budget_tokens`, OpenAI `reasoning_effort`).\n */\n\n/** `'off'`/undefined = no reasoning; named buckets; or a raw token budget (budget-based providers). */\nexport type ReasoningEffort = 'off' | 'low' | 'medium' | 'high' | number;\n\nexport interface ChatFragment {\n providerOptions?: Record<string, unknown>;\n /** Request `max_tokens`. Raised for budget-based providers so `budget_tokens < max_tokens` holds. */\n maxTokens?: number;\n}\n\n/** Named effort → thinking-token budget (budget-based providers, e.g. Anthropic). */\nconst BUDGET: Record<'low' | 'medium' | 'high', number> = { low: 2048, medium: 8192, high: 24576 };\n\n/** Bucket a raw token budget back to the nearest named effort (for providers that take a label). */\nfunction toLabel(effort: ReasoningEffort): 'low' | 'medium' | 'high' {\n if (typeof effort !== 'number') return effort === 'off' ? 'low' : effort;\n return effort <= BUDGET.low ? 'low' : effort < BUDGET.high ? 'medium' : 'high';\n}\n\n/** Resolve an effort to a concrete token budget. */\nfunction toBudget(effort: ReasoningEffort): number {\n return typeof effort === 'number' ? effort : BUDGET[effort as 'low' | 'medium' | 'high'];\n}\n\n/**\n * Map a normalized effort to a partial `ChatOptions` fragment for `model`'s provider.\n * Returns `{}` (safe no-op) for `'off'`, undefined, or an unsupported provider.\n *\n * Supported: `anthropic/*` (extended thinking), `openai/*` (reasoning_effort).\n * `google/*` is intentionally NOT mapped here — its adapter `Object.assign`s\n * providerOptions over the built `generationConfig`, clobbering it; pass an\n * explicit `providerOptions` if you need Gemini thinking.\n */\nexport function reasoningToChatFragment(model: string, effort?: ReasoningEffort): ChatFragment {\n if (effort == null || effort === 'off') return {};\n const provider = model.split('/')[0];\n switch (provider) {\n case 'anthropic': {\n const budget = toBudget(effort);\n return { providerOptions: { thinking: { type: 'enabled', budget_tokens: budget } }, maxTokens: budget + 8192 };\n }\n case 'openai':\n return { providerOptions: { reasoning_effort: toLabel(effort) } };\n default:\n return {};\n }\n}\n","// agentx — edge-native AI agent runtime over a virtual filesystem.\n\nexport { Agent, AgentOptions } from './Agent';\nexport type { RunResult, CompactResult } from './Agent';\nexport { estimateTokens } from './Agent';\n\nexport { MODEL_ALIASES, resolveModelAlias, modelShortLabel, resolveModelSwitch } from './models';\nexport type { ResolveModelSwitchOpts, ModelSwitch } from './models';\n\nexport { NodeDiskFilesystem } from './NodeDiskFilesystem';\nexport { BodDbFilesystem } from './BodDbFilesystem';\nexport { JailedFilesystem, JailOptions, DEFAULT_DENY } from './JailedFilesystem';\nexport { OverlayFilesystem, checkpointTool, rollbackTool, checkpointTools } from './OverlayFilesystem';\nexport { MountFilesystem } from './MountFilesystem';\nexport type { Mount } from './MountFilesystem';\nexport { raceAttempts } from './speculate';\nexport type { Attempt } from './speculate';\nexport { validateToolCode, compileSynthesizedTool } from './synthesize';\nexport type { ToolSpec } from './synthesize';\nexport { PermissionPolicy, PermissionOptions, planMode, composeHooks, DEFAULT_MUTATING } from './permissions';\nexport type { Decision, PermissionRule } from './permissions';\n\nexport { FakeAIClient, toolCall } from './FakeAIClient';\n\nexport { bashTool, readTool, editTool, defaultTools, exitSessionTool, makeContext, toWireTools, toolRegistry, toolsByName } from './tools';\nexport { SandboxJobRegistry, makeJobTools } from './tools.jobs';\nexport { Scheduler, makeScheduleTools, parseCron, cronMatches, nextCronAfter } from './scheduler';\nexport type { ScheduledJob, ScheduledJobSnapshot, Trigger, TriggerOneOff, TriggerInterval, TriggerCron, SchedulerOptions } from './scheduler';\nexport { sandboxAgentOptions, diskAgentOptions, fullAgentOptions } from './presets';\nexport { grepTool, globTool, makeGrepTool, makeGlobTool, DEFAULT_SKIP_DIRS, DEFAULT_MAX_DEPTH, type FileScanOptions, writeTool, multiEditTool, applyEditsTool, repoMapTool, repoIndex, mkdirp } from './tools.structured';\nexport { todoWriteTool } from './todo';\nexport { webFetchTool, webSearchTool, webSearchAnthropicTool, makeWebFetchTool, makeWebSearchTool, makeWebSearchAnthropicTool, htmlToText, parseDdgHtml, decodeDdgUrl } from './tools.web';\nexport { Scratch, makeAskTool, SCRATCH_DIR } from './scratch';\nexport type { ScratchOptions, AskOptions } from './scratch';\nexport type { WebFetchOptions, WebSearchOptions } from './tools.web';\nexport type { TodoItem } from './todo';\nexport type { AgentTool, ToolContext, HostBridge, HostEvent, UserQuestion } from './tools';\n\nexport { askUserQuestionTool, ScriptedHostBridge, ConsoleHostBridge } from './host';\n\nexport { loadSkills, scanSkills } from './skills';\nexport type { SkillInfo } from './skills';\nexport { tokenize, relevanceScore, topByRelevance, idfWeights } from './relevance';\nexport { loadCommands, scanCommands, expandCommand, expandTemplate, expandEntry } from './commands';\nexport type { CommandInfo, SiblingResolver } from './commands';\nexport { loadMemory, writeFact, slugify, MEMORY_PROMPT, VOICE_MEMORY_PROMPT } from './memory';\nexport type { LoadMemoryOpts } from './memory';\nexport { lessonCapture, LessonOptionsDefaults } from './lessons';\nexport type { LessonOptions } from './lessons';\nexport { reflectOnRun } from './reflect';\nexport type { ReflectOptions } from './reflect';\nexport { loadInstructions } from './instructions';\n\nexport { DuplexAgent, DuplexAgentOptions, VOICE_SYSTEM_PROMPT } from './duplex';\nexport type { TaskRecord, DuplexTaskStatus, WorkerTier } from './duplex';\n\nexport { makeTaskTool, makeTaskBatchTool } from './subagent';\nexport type { TaskToolOptions } from './subagent';\nexport { loadAgents } from './agents';\nexport type { AgentDef } from './agents';\nexport { mcpToolsToAgentTools, mcpToolToAgentTool, makeMcpToolSearch, makeMcpToolSearchFromMounted, makeLazyMcpToolSearch, buildMcpCatalog } from './mcp';\nexport type { McpToolSpec, McpCall, McpToolSearchOptions, McpImage, McpToolResult, MountedMcpLike, McpRoute, McpRouteResolver } from './mcp';\nexport { RecordingHooks, RecordingLifecycle } from './hooks';\nexport type { Hooks, ToolUse, ToolUseMeta, PreToolUseDecision } from './hooks';\n\nexport { forComponent, log } from './logging';\n\n// Voice I/O (portable core — CLI/server/browser; platform backends live in cli/voice.ts).\nexport { VoiceEngine, VoiceEngineOptions } from './voice/engine';\nexport type { SttLike, TtsLike } from './voice/engine';\nexport { SonioxSTT, SonioxSTTOptions } from './voice/soniox';\nexport { CartesiaTTS, CartesiaTTSOptions } from './voice/cartesia';\nexport { resolveAuth, STT_SAMPLE_RATE, TTS_SAMPLE_RATE } from './voice/types';\nexport type { AudioSource, AudioSink, AuthProvider, VoiceState } from './voice/types';\n\nexport type { Message, Tool, ToolCall, ChatResponse, ChatOptions, ChatLike, Role, StreamChunk, ContentPart, MessageContent } from './llm';\nexport { contentText, imagePart, contentBytes, elideStaleImages, elideInlineImages, elideImages, messageHasInlineImage, IMAGE_ELIDE_STUB, imageRefPart, parseImageRef, messageHasImageRef, messageHasImage, imageRefResult, toolImageRef, expandImagesForSend, IMAGE_REF_SCHEME, mintImageRef, clearImageRefs, sendBytes, sendBytesPer, remintImageRefs } from './llm';\nexport type { ImageRef } from './llm';\nexport { reasoningToChatFragment } from './reasoning';\nexport type { ReasoningEffort, ChatFragment } from './reasoning';\n\nexport { validateWorktreeSlug, worktreeBranchName, getOrCreateWorktree, cleanupWorktree, enterWorktree, exitWorktree, getWorktreeSession, findGitRoot } from './worktree';\nexport type { WorktreeInfo, WorktreeSession } from './worktree';\n\n// Re-export the wcli-core filesystem backends so embedders get everything from one place.\nexport { MemFilesystem, IndexedDbFilesystem, CommandExecutor, registerHeadlessCommands } from '@livx.cc/wcli/core';\nexport type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\n","import type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\nimport { PathResolver } from '@livx.cc/wcli/core';\nimport { BodDB } from '@bod.ee/db';\nimport type { VFSBackend } from '@bod.ee/db';\n\n/** Pure in-memory byte store for the default (no-arg) constructor — keeps it truly in-memory\n * (bod-db's default backend writes bytes to disk under `storageRoot`). Keyed by fileId. */\nclass MemBackend implements VFSBackend {\n private store = new Map<string, Uint8Array>();\n async read(id: string): Promise<Uint8Array> {\n const d = this.store.get(id);\n if (!d) throw new Error(`fileId not found: ${id}`);\n return d;\n }\n async write(id: string, data: Uint8Array): Promise<void> { this.store.set(id, data); }\n async delete(id: string): Promise<void> { this.store.delete(id); }\n async exists(id: string): Promise<boolean> { return this.store.has(id); }\n}\n\n/**\n * Database-backed `IFilesystem` over bod-db's VFS — the normalization thesis realized: the agent\n * operates on a file tree that lives in a database, yet the same tools/commands run unchanged\n * (semantics mirror MemFilesystem/NodeDiskFilesystem: throw on missing parent / existing dir /\n * non-empty dir / missing file). bod-db's VFS is path-based and async, so the adapter is thin.\n *\n * Construct with no args for an in-memory DB (great for tests), or pass a configured `BodDB`\n * (with VFS enabled) backed by real/cloud storage for persistence. Call `close()` when done to\n * release the DB's timers (the in-memory default uses `sweepInterval: 0`, so there's nothing to sweep).\n */\nexport class BodDbFilesystem implements IFilesystem {\n private cwd = '/';\n private db: BodDB;\n private vfs: NonNullable<BodDB['vfs']>;\n private owns: boolean;\n\n constructor(db?: BodDB) {\n this.owns = !db;\n // default: metadata DB in-memory (path ':memory:'), file bytes in a Map backend → no disk, no sweep timer.\n this.db = db ?? new BodDB({ path: ':memory:', sweepInterval: 0, vfs: { storageRoot: ':memory:', backend: new MemBackend() } });\n if (!this.db.vfs) throw new Error('BodDbFilesystem: the BodDB must have VFS enabled (construct it with { vfs: { … } }).');\n this.vfs = this.db.vfs;\n }\n\n /** Release the underlying DB's timers/handles. Closes only a DB we created (a passed-in DB is the caller's). */\n close(): void {\n if (this.owns) this.db.close();\n }\n\n resolvePath(path: string, cwd?: string): string {\n return PathResolver.resolve(path, cwd || this.cwd);\n }\n getCwd(): string { return this.cwd; }\n setCwd(path: string): void { this.cwd = PathResolver.normalize(path); }\n\n /** Parent dir of an absolute VFS path ('/a/b.txt' -> '/a'; '/a' -> '/'). */\n private parentOf(p: string): string {\n const i = p.lastIndexOf('/');\n return i <= 0 ? '/' : p.slice(0, i);\n }\n /** Throw (matching the other backends) unless the parent directory exists. Root is always a dir. */\n private assertParentDir(p: string, path: string): void {\n const parent = this.parentOf(p);\n if (parent === '/') return;\n const s = this.vfs.stat(parent);\n if (!s || !s.isDir) throw new Error(`Parent directory does not exist: ${path}`);\n }\n\n async readFile(path: string): Promise<string> {\n const p = this.resolvePath(path);\n const s = this.vfs.stat(p);\n if (!s) throw new Error(`File not found: ${path}`);\n if (s.isDir) throw new Error(`Not a file: ${path}`);\n return new TextDecoder().decode(await this.vfs.read(p));\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n const p = this.resolvePath(path);\n this.assertParentDir(p, path);\n if (this.vfs.stat(p)?.isDir) throw new Error(`Is a directory: ${path}`);\n await this.vfs.write(p, new TextEncoder().encode(content), 'text/plain');\n }\n\n async deleteFile(path: string): Promise<void> {\n const p = this.resolvePath(path);\n const s = this.vfs.stat(p);\n if (!s) throw new Error(`File not found: ${path}`);\n if (s.isDir && this.vfs.list(p).length > 0) throw new Error(`Directory not empty: ${path}`);\n await this.vfs.remove(p);\n }\n\n async readDir(path: string): Promise<string[]> {\n const p = this.resolvePath(path);\n if (p !== '/') {\n const s = this.vfs.stat(p);\n if (!s) throw new Error(`Directory not found: ${path}`); // missing vs…\n if (!s.isDir) throw new Error(`Not a directory: ${path}`); // …a file (match MemFilesystem semantics)\n }\n return this.vfs.list(p).map((e: { name: string }) => e.name);\n }\n\n async createDir(path: string): Promise<void> {\n const p = this.resolvePath(path);\n if (p === '/' || this.vfs.stat(p)) throw new Error(`File or directory already exists: ${path}`);\n this.assertParentDir(p, path);\n this.vfs.mkdir(p);\n }\n\n async exists(path: string): Promise<boolean> {\n const p = this.resolvePath(path);\n return p === '/' || this.vfs.stat(p) !== null;\n }\n\n async stat(path: string): Promise<FileMetadata> {\n const p = this.resolvePath(path);\n const s = this.vfs.stat(p);\n if (!s) {\n if (p === '/') return { created: new Date(0), modified: new Date(0), size: 0, permissions: 'drwxr-xr-x', isExecutable: false };\n throw new Error(`File not found: ${path}`);\n }\n const when = new Date(s.mtime); // bod-db tracks a single mtime; reuse for created+modified\n return {\n created: when,\n modified: when,\n size: s.size,\n permissions: s.isDir ? 'drwxr-xr-x' : '-rw-r--r--',\n isExecutable: false,\n };\n }\n\n async isDirectory(path: string): Promise<boolean> {\n const p = this.resolvePath(path);\n return p === '/' || this.vfs.stat(p)?.isDir === true;\n }\n async isFile(path: string): Promise<boolean> {\n const s = this.vfs.stat(this.resolvePath(path));\n return !!s && !s.isDir;\n }\n}\n","import type { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';\n\n/**\n * Hybrid / composite VFS — a root backend with other IFilesystems mounted at path\n * prefixes. Each op routes to the longest-matching mount and is translated into that\n * backend's OWN root space (`/skills/x.md` → the /skills mount's `/x.md`); everything\n * else falls through to the root backend. `readDir` merges the routed listing with\n * mount-point names at that level, and intermediate mount-ancestor dirs (e.g. `/vendor`\n * when only `/vendor/lib` is mounted) are synthesized.\n *\n * This is what lets you mix sources: edit a real project on disk at `/` while reading\n * skills/tools/docs from a bundled in-memory VFS or another disk folder — one filesystem\n * to the agent. Pure IFilesystem composition: edge-safe.\n */\nconst DIR_META: FileMetadata = { created: new Date(0), modified: new Date(0), size: 0, permissions: 'drwxr-xr-x', isExecutable: false };\nconst norm = (p: string) => '/' + p.split('/').filter(Boolean).join('/'); // leading slash, no trailing\n\nexport interface Mount { prefix: string; fs: IFilesystem }\n\nexport class MountFilesystem implements IFilesystem {\n private mounts: Mount[];\n\n constructor(private root: IFilesystem, mounts: Mount[] = []) {\n this.mounts = mounts\n .map((m) => ({ prefix: norm(m.prefix), fs: m.fs }))\n .sort((a, b) => b.prefix.length - a.prefix.length); // longest prefix wins\n }\n\n resolvePath(path: string, cwd?: string): string { return this.root.resolvePath(path, cwd ?? this.root.getCwd()); }\n getCwd(): string { return this.root.getCwd(); }\n setCwd(path: string): void { this.root.setCwd(path); }\n private abs(p: string): string { return this.resolvePath(p); }\n\n /** Route an absolute VFS path to a backend + its path within that backend. */\n private route(abs: string): { fs: IFilesystem; sub: string } {\n for (const m of this.mounts) {\n if (abs === m.prefix || abs.startsWith(m.prefix + '/')) return { fs: m.fs, sub: abs.slice(m.prefix.length) || '/' };\n }\n return { fs: this.root, sub: abs };\n }\n\n /** Is `abs` strictly ABOVE a mount point (a synthesized dir the root may not have)? */\n private isMountAncestor(abs: string): boolean {\n const base = abs === '/' ? '/' : abs + '/';\n return this.mounts.some((m) => m.prefix.startsWith(base));\n }\n\n /** Immediate child segment names of `abs` that come from mounts (for readDir merge). */\n private mountChildrenOf(abs: string): string[] {\n const base = abs === '/' ? '/' : abs + '/';\n const out = new Set<string>();\n for (const m of this.mounts) if (m.prefix.startsWith(base)) out.add(m.prefix.slice(base.length).split('/')[0]);\n return [...out];\n }\n\n async readFile(path: string): Promise<string> { const { fs, sub } = this.route(this.abs(path)); return fs.readFile(sub); }\n async writeFile(path: string, content: string): Promise<void> { const { fs, sub } = this.route(this.abs(path)); return fs.writeFile(sub, content); }\n async deleteFile(path: string): Promise<void> { const { fs, sub } = this.route(this.abs(path)); return fs.deleteFile(sub); }\n async createDir(path: string): Promise<void> { const { fs, sub } = this.route(this.abs(path)); return fs.createDir(sub); }\n\n async exists(path: string): Promise<boolean> {\n const a = this.abs(path);\n if (this.isMountAncestor(a)) return true;\n const { fs, sub } = this.route(a);\n return fs.exists(sub);\n }\n async isDirectory(path: string): Promise<boolean> {\n const a = this.abs(path);\n if (this.isMountAncestor(a)) return true; // synthesized ancestor dir\n const { fs, sub } = this.route(a);\n return fs.isDirectory(sub);\n }\n async isFile(path: string): Promise<boolean> {\n const a = this.abs(path);\n if (this.isMountAncestor(a)) return false;\n const { fs, sub } = this.route(a);\n return fs.isFile(sub);\n }\n async stat(path: string): Promise<FileMetadata> {\n const a = this.abs(path);\n if (this.isMountAncestor(a)) return DIR_META;\n const { fs, sub } = this.route(a);\n return fs.stat(sub);\n }\n\n async readDir(path: string): Promise<string[]> {\n const a = this.abs(path);\n const { fs, sub } = this.route(a);\n const names = new Set<string>();\n let routedOk = false;\n try { for (const n of await fs.readDir(sub)) names.add(n); routedOk = true; } catch { /* may be a pure synthetic ancestor */ }\n for (const n of this.mountChildrenOf(a)) names.add(n);\n if (!routedOk && !this.isMountAncestor(a)) throw new Error(`Directory not found: ${path}`);\n return [...names].sort();\n }\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport { OverlayFilesystem } from './OverlayFilesystem';\n\n/**\n * Speculative parallel attempts — a primitive uniquely cheap on a SWAPPABLE VFS.\n *\n * Fork the workspace into N copy-on-write overlays of the same `base`, run an attempt in\n * each (independently — writes stay in each overlay, the base is untouched), score them,\n * then COMMIT the best overlay into the base and DISCARD the losers (they leave no trace).\n * Use it to race several approaches/seeds for a flaky or multi-path task and keep only the\n * winner — something agents on a real, non-forkable filesystem can't do without copying the\n * whole tree. Pairs naturally with subagents (each attempt is a child Agent over its overlay).\n *\n * `score` returns a higher-is-better number, or null to disqualify (e.g. failed grading).\n */\nexport interface Attempt<R> {\n index: number;\n fs: OverlayFilesystem;\n result: R;\n score: number | null;\n}\n\nexport async function raceAttempts<R>(\n base: IFilesystem,\n n: number,\n run: (fs: IFilesystem, index: number) => Promise<R>,\n score: (a: { fs: OverlayFilesystem; result: R; index: number }) => Promise<number | null> | number | null,\n): Promise<{ winner: Attempt<R> | null; attempts: Attempt<R>[] }> {\n const attempts: Attempt<R>[] = await Promise.all(\n Array.from({ length: Math.max(1, n) }, async (_, index) => {\n const fs = new OverlayFilesystem(base);\n const result = await run(fs, index);\n const s = await score({ fs, result, index });\n return { index, fs, result, score: s };\n }),\n );\n // Best non-disqualified score wins; ties broken by earliest index (stable).\n const ranked = attempts.filter((a) => a.score != null).sort((a, b) => b.score! - a.score! || a.index - b.index);\n const winner = ranked[0] ?? null;\n if (winner) await winner.fs.commit(); // apply ONLY the winner to the base; losers are discarded\n return { winner, attempts };\n}\n","import type { AgentTool, ToolContext } from './tools';\n\n/**\n * Tool synthesis — compile a NEW agent tool from a spec the model authored. The unbounded\n * frontier of self-evolution: the agent invents its own capabilities.\n *\n * SAFETY (this is the load-bearing part). A synthesized tool's `code` is arbitrary JS that\n * runs IN-PROCESS over the agent's filesystem, so before compiling we statically REJECT a\n * denylist of escape vectors (process/require/import/eval/Function/constructor/__proto__/\n * globalThis/Bun/fetch/network/timers/WebAssembly/infinite-loops/…). A compiled tool sees\n * ONLY its `args` and `ctx` (whose fs is the JailedFilesystem — boundary A); combined with\n * the Agent's timeout/tool-call kill-switches this is defensible. Residual risk remains for\n * a determined denylist bypass, so synthesized tools are OPT-IN and should additionally be\n * self-tested in the sandbox (boundary B) before being trusted in a live loop. See mind/08.\n */\nexport interface ToolSpec {\n name: string;\n description: string;\n parameters: object; // JSON Schema for args\n /** body of `async (args, ctx) => { … return <string> }` — may use args + ctx.fs ONLY. */\n code: string;\n}\n\n/** Static safety gate. Returns the matched escape vectors (empty = code is allowed). */\nexport function validateToolCode(code: string): { ok: boolean; violations: string[] } {\n const DENY: [string, RegExp][] = [\n ['process', /\\bprocess\\b/], ['require', /\\brequire\\b/], ['import', /\\bimport\\b/],\n ['eval', /\\beval\\b/], ['Function', /\\bFunction\\b/], ['constructor', /\\bconstructor\\b/],\n ['__proto__', /__proto__/], ['prototype', /\\bprototype\\b/], ['globalThis', /\\bglobalThis\\b/],\n ['global', /\\bglobal\\b/], ['window', /\\bwindow\\b/], ['self', /\\bself\\b/],\n ['Bun', /\\bBun\\b/], ['Deno', /\\bDeno\\b/], ['fetch', /\\bfetch\\b/], ['XMLHttpRequest', /\\bXMLHttpRequest\\b/],\n ['WebSocket', /\\bWebSocket\\b/], ['child_process', /\\bchild_process\\b/], ['node:', /node:/],\n ['setTimeout', /\\bsetTimeout\\b/], ['setInterval', /\\bsetInterval\\b/], ['setImmediate', /\\bsetImmediate\\b/],\n ['Atomics', /\\bAtomics\\b/], ['SharedArrayBuffer', /\\bSharedArrayBuffer\\b/], ['WebAssembly', /\\bWebAssembly\\b/],\n ['Reflect', /\\bReflect\\b/], ['Proxy', /\\bProxy\\b/], ['Buffer', /\\bBuffer\\b/],\n ['while(true)', /while\\s*\\(\\s*true\\s*\\)/], ['for(;;)', /for\\s*\\(\\s*;\\s*;\\s*\\)/],\n // escape sequences can smuggle a denied identifier past the substring check\n // (e.g. `process` parses as `process`), so forbid them outright.\n ['\\\\u escape', /\\\\u/], ['\\\\x escape', /\\\\x/],\n ];\n const violations = DENY.filter(([, re]) => re.test(code)).map(([name]) => name);\n return { ok: violations.length === 0, violations };\n}\n\n/**\n * Compile a spec into an AgentTool — THROWS if the code fails the static safety gate.\n * The body runs as `async (args, ctx) => { <code> }`; only `args` and `ctx` are in scope.\n */\nexport function compileSynthesizedTool(spec: ToolSpec): AgentTool {\n const v = validateToolCode(spec.code);\n if (!v.ok) throw new Error(`unsafe synthesized tool '${spec.name}': blocked tokens [${v.violations.join(', ')}]`);\n if (!/^[A-Za-z_]\\w{0,39}$/.test(spec.name)) throw new Error(`invalid tool name '${spec.name}'`);\n // Strict mode; only args + ctx are reachable lexically.\n const fn = new Function('args', 'ctx', `\"use strict\"; return (async (args, ctx) => { ${spec.code} })(args, ctx);`) as (a: any, c: ToolContext) => Promise<unknown>;\n return {\n name: spec.name,\n description: spec.description,\n parameters: spec.parameters ?? { type: 'object', properties: {} },\n async run(args, ctx) {\n const r = await fn(args, ctx);\n return typeof r === 'string' ? r : JSON.stringify(r ?? '');\n },\n };\n}\n","import type { ChatLike, ChatOptions, ChatResponse, ToolCall } from './llm';\n\n/**\n * Deterministic test/dev double for an ai.libx.js AIClient. Plays a scripted\n * queue of ChatResponses (tool_calls then a final answer). Records each\n * ChatOptions it saw so tests can assert tools were advertised and tool\n * results were threaded back. No network, no API key.\n */\nexport class FakeAIClient implements ChatLike {\n public seen: ChatOptions[] = [];\n private script: ChatResponse[];\n\n constructor(script: ChatResponse[]) {\n this.script = [...script];\n }\n\n async chat(options: ChatOptions): Promise<ChatResponse> {\n this.seen.push(options);\n const next = this.script.shift();\n if (!next) throw new Error('FakeAIClient: script exhausted (model asked for more turns than scripted)');\n return next;\n }\n}\n\n/** Build a tool_call block (arguments JSON-stringified, matching the wire format). */\nexport const toolCall = (id: string, name: string, args: object): ToolCall => ({\n id,\n type: 'function',\n function: { name, arguments: JSON.stringify(args) },\n});\n","/**\n * In-process scheduler — timers that fire prompts into the agent loop while the session is alive.\n * Three trigger modes: one-off ({at}), interval ({everyMs}), cron ({cron}).\n * The scheduler never calls `turn()` itself — it invokes an IoC `fire` callback with due jobs,\n * keeping it testable and host-agnostic. Persistence is the host's responsibility (serialize jobs\n * into the session and re-arm on resume).\n *\n * Survives --resume (host reloads); does NOT survive process exit (no daemon, no launchd).\n */\n\nexport type TriggerOneOff = { at: number };\nexport type TriggerInterval = { everyMs: number };\nexport type TriggerCron = { cron: string };\nexport type Trigger = TriggerOneOff | TriggerInterval | TriggerCron;\n\nexport type ScheduledJobStatus = 'active' | 'done';\n\nexport interface ScheduledJob {\n id: string;\n prompt: string;\n trigger: Trigger;\n status: ScheduledJobStatus;\n created: number;\n lastRun?: number;\n runs: number;\n /** Optional label for display (e.g. footer, /schedule list). */\n label?: string;\n}\n\n/** Serializable snapshot for session persistence (same shape — kept as an alias for clarity at call sites). */\nexport type ScheduledJobSnapshot = ScheduledJob;\n\nexport interface SchedulerOptions {\n /** Called when a job is due. Must not throw — the scheduler logs errors and continues. */\n fire: (job: ScheduledJob) => Promise<void> | void;\n /** Monotonic clock override for testing (default: Date.now). */\n now?: () => number;\n /** Tick interval in ms (default: 15_000 — 15s). */\n tickMs?: number;\n /** If true, suppress the setInterval (for unit tests that call tick() manually). */\n manual?: boolean;\n}\n\n// ── Cron mini-parser (minute hour dom month dow) ──────────────────────────\n// Supports: *, N, N-M, */N, N-M/N, comma-separated lists. No named days/months.\n// Enough for real scheduling; not a full vixie-cron (no @yearly etc).\n\ninterface CronFields { minute: number[]; hour: number[]; dom: number[]; month: number[]; dow: number[] }\n\nfunction parseCronField(field: string, min: number, max: number): number[] {\n const vals = new Set<number>();\n for (const part of field.split(',')) {\n const [rangeStr, stepStr] = part.split('/');\n const step = stepStr ? parseInt(stepStr, 10) : 1;\n if (isNaN(step) || step < 1) throw new Error(`invalid cron step: ${part}`);\n let lo: number, hi: number;\n if (rangeStr === '*') { lo = min; hi = max; }\n else if (rangeStr!.includes('-')) {\n const [a, b] = rangeStr!.split('-').map(Number);\n if (isNaN(a!) || isNaN(b!)) throw new Error(`invalid cron range: ${part}`);\n lo = a!; hi = b!;\n } else {\n const n = parseInt(rangeStr!, 10);\n if (isNaN(n)) throw new Error(`invalid cron value: ${part}`);\n lo = n; hi = stepStr ? max : n;\n }\n for (let i = lo; i <= hi; i += step) vals.add(i);\n }\n return [...vals].sort((a, b) => a - b);\n}\n\nexport function parseCron(expr: string): CronFields {\n const parts = expr.trim().split(/\\s+/);\n if (parts.length !== 5) throw new Error(`cron expression must have 5 fields (minute hour dom month dow), got ${parts.length}: \"${expr}\"`);\n return {\n minute: parseCronField(parts[0]!, 0, 59),\n hour: parseCronField(parts[1]!, 0, 23),\n dom: parseCronField(parts[2]!, 1, 31),\n month: parseCronField(parts[3]!, 1, 12),\n dow: parseCronField(parts[4]!, 0, 6),\n };\n}\n\nexport function cronMatches(fields: CronFields, date: Date): boolean {\n return fields.minute.includes(date.getMinutes())\n && fields.hour.includes(date.getHours())\n && fields.dom.includes(date.getDate())\n && fields.month.includes(date.getMonth() + 1)\n && fields.dow.includes(date.getDay());\n}\n\n/** Next occurrence of `cron` after `after` (epoch ms). Returns epoch ms, or null if >366 days out (guard). */\nexport function nextCronAfter(cron: string, after: number): number | null {\n const fields = parseCron(cron);\n const d = new Date(after);\n d.setSeconds(0, 0);\n d.setMinutes(d.getMinutes() + 1); // always at least 1 minute in the future\n const limit = after + 366 * 86400_000;\n while (d.getTime() <= limit) {\n if (cronMatches(fields, d)) return d.getTime();\n d.setMinutes(d.getMinutes() + 1);\n }\n return null;\n}\n\n// ── Scheduler ─────────────────────────────────────────────────────────────\n\nexport class Scheduler {\n private jobs = new Map<string, ScheduledJob>();\n private seq = 0;\n private timer: ReturnType<typeof setInterval> | null = null;\n private firing = false;\n private readonly fire: SchedulerOptions['fire'];\n private readonly now: () => number;\n private readonly tickMs: number;\n\n constructor(opts: SchedulerOptions) {\n this.fire = opts.fire;\n this.now = opts.now ?? Date.now;\n this.tickMs = opts.tickMs ?? 15_000;\n if (!opts.manual) this.start();\n }\n\n /** Start the tick timer. Idempotent. */\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(() => this.tick(), this.tickMs);\n if (typeof this.timer === 'object' && 'unref' in this.timer) (this.timer as any).unref();\n }\n\n /** Stop the tick timer. Does not clear jobs. */\n stop(): void {\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\n }\n\n /** Add a scheduled job. Returns the job id. */\n add(opts: { prompt: string; trigger: Trigger; label?: string }): string {\n // Validate trigger\n if ('cron' in opts.trigger) parseCron(opts.trigger.cron); // throws on bad expr\n if ('at' in opts.trigger && opts.trigger.at < this.now()) {\n // Allow slightly-past timestamps (clock skew); just fire on next tick.\n }\n if ('everyMs' in opts.trigger && opts.trigger.everyMs < 1000) {\n throw new Error('interval must be >= 1000ms');\n }\n const id = `sched-${++this.seq}`;\n this.jobs.set(id, {\n id, prompt: opts.prompt, trigger: opts.trigger, status: 'active',\n created: this.now(), runs: 0, label: opts.label,\n });\n return id;\n }\n\n /** Cancel a job. Returns false if not found. */\n cancel(id: string): boolean {\n const j = this.jobs.get(id);\n if (!j) return false;\n j.status = 'done';\n return true;\n }\n\n get(id: string): ScheduledJob | undefined { return this.jobs.get(id); }\n\n list(): ScheduledJob[] { return [...this.jobs.values()]; }\n\n active(): ScheduledJob[] { return this.list().filter(j => j.status === 'active'); }\n\n /** Compute when a job next fires (epoch ms), or null if done/unknown. */\n nextFire(job: ScheduledJob): number | null {\n if (job.status !== 'active') return null;\n const t = job.trigger;\n if ('at' in t) return t.at;\n if ('everyMs' in t) return (job.lastRun ?? job.created) + t.everyMs;\n if ('cron' in t) return nextCronAfter(t.cron, job.lastRun ?? job.created);\n return null;\n }\n\n /** Check all active jobs and fire any that are due. Reentrant-safe. */\n async tick(): Promise<void> {\n if (this.firing) return; // guard: never overlap\n this.firing = true;\n try {\n const now = this.now();\n for (const job of this.jobs.values()) {\n if (job.status !== 'active') continue;\n const due = this.nextFire(job);\n if (due == null || due > now) continue;\n job.lastRun = now;\n job.runs++;\n // One-off: mark done immediately (before firing — fire is async, cancel must stick).\n if ('at' in job.trigger) job.status = 'done';\n try { await this.fire(job); } catch { /* fire contract: must not throw; belt-and-suspenders */ }\n }\n } finally {\n this.firing = false;\n }\n }\n\n /** Export all jobs for session persistence. */\n snapshot(): ScheduledJobSnapshot[] {\n return this.list().filter(j => j.status === 'active').map(j => ({ ...j }));\n }\n\n /** Restore jobs from a snapshot (e.g. on --resume). Clears existing jobs first. */\n restore(snapshots: ScheduledJobSnapshot[]): void {\n this.jobs.clear();\n for (const s of snapshots) {\n this.seq = Math.max(this.seq, parseInt(s.id.replace('sched-', ''), 10) || 0);\n this.jobs.set(s.id, { ...s });\n }\n }\n\n /** Number of active jobs. */\n get size(): number { return this.active().length; }\n\n destroy(): void { this.stop(); this.jobs.clear(); }\n}\n\n// ── Agent tools ───────────────────────────────────────────────────────────\n\nimport type { AgentTool } from './tools';\n\n/** Narrow seam to an OS-level scheduler backend (jobs that survive quit/reboot). Node hosts wire\n * the CLI's `OsScheduler` (launchd/cron/at); absent => everything stays in-process. Edge-safe:\n * this module only sees the interface. */\nexport interface OsBackend {\n sessionId: string;\n cwd: string;\n /** 'os' when the trigger should outlive the session (per hint/heuristic). */\n route(trigger: Trigger, backendHint?: string): 'session' | 'os';\n /** Register with the OS. Returns a mechanism description (e.g. 'launchd:…'). Throws on failure. */\n schedule(spec: { id: string; prompt: string; sessionId: string; cwd: string; trigger: Trigger; label?: string }): string;\n cancel(id: string): boolean;\n list(): Array<{ id: string; label?: string; mechanism: string; trigger: Trigger }>;\n}\n\nexport function makeScheduleTools(scheduler: Scheduler, os?: OsBackend): AgentTool[] {\n return [\n {\n name: 'ScheduleTask',\n description:\n 'Schedule a prompt to fire automatically.\\n' +\n 'Modes:\\n' +\n ' • One-off: {at: <epoch_ms>} — fires once at that time, then done.\\n' +\n ' • Interval: {everyMs: <ms>} — fires repeatedly (≥1s).\\n' +\n ' • Cron: {cron: \"min hr dom mon dow\"} — standard 5-field cron.\\n' +\n 'Backend: \"session\" fires while this CLI session is alive (default for recurring + near one-offs); ' +\n '\"os\" registers with the OS scheduler so the job survives quitting — it headless-resumes this session ' +\n 'when it fires (auto-chosen for one-offs ≥30min out when available). Pass backend:\"os\" explicitly for ' +\n 'recurring jobs that must outlive the session.',\n parameters: {\n type: 'object',\n required: ['prompt', 'trigger'],\n properties: {\n prompt: { type: 'string', description: 'The prompt to inject when the job fires.' },\n trigger: {\n type: 'object',\n description: 'One of: {at: epoch_ms}, {everyMs: ms}, {cron: \"5-field expr\"}.',\n properties: {\n at: { type: 'number' },\n everyMs: { type: 'number' },\n cron: { type: 'string' },\n },\n },\n label: { type: 'string', description: 'Short label for display (optional).' },\n backend: { type: 'string', enum: ['auto', 'session', 'os'], description: 'Where the job lives (default auto).' },\n },\n },\n async run({ prompt, trigger, label, backend }) {\n try {\n if (os && os.route(trigger, backend) === 'os') {\n const id = `os-${Date.now().toString(36)}`;\n const mechanism = os.schedule({ id, prompt, sessionId: os.sessionId, cwd: os.cwd, trigger, label });\n return `Scheduled ${id}${label ? ` (${label})` : ''} on the OS scheduler (${mechanism}) — survives quitting; fires \\`agentx --resume ${os.sessionId}\\` headless.`;\n }\n if (backend === 'os') return 'Error: no OS scheduler available on this platform — job not created (use the default in-session backend).';\n const id = scheduler.add({ prompt, trigger, label });\n const job = scheduler.get(id)!;\n const next = scheduler.nextFire(job);\n return `Scheduled ${id}${label ? ` (${label})` : ''}. Next fire: ${next ? new Date(next).toLocaleString() : 'now'}. (In-session: does not survive quitting.)`;\n } catch (e: any) {\n return `Error: ${e?.message ?? e}`;\n }\n },\n },\n {\n name: 'ScheduleList',\n description: 'List all scheduled jobs (in-session + OS-backed) and their next fire time.',\n parameters: { type: 'object', properties: {} },\n async run() {\n const osJobs = os?.list() ?? [];\n const osLines = osJobs.map((j) => `${j.id} os ${j.mechanism}${j.label ? ' ' + j.label : ''}`);\n const jobs = scheduler.list();\n if (!jobs.length && !osLines.length) return '(no scheduled jobs)';\n return [...osLines, ...jobs.map(j => {\n const next = scheduler.nextFire(j);\n const trig = 'at' in j.trigger ? `once @ ${new Date(j.trigger.at).toLocaleString()}`\n : 'everyMs' in j.trigger ? `every ${(j.trigger.everyMs / 1000).toFixed(0)}s`\n : `cron: ${(j.trigger as TriggerCron).cron}`;\n return `${j.id} ${j.status} ${trig} runs:${j.runs} next:${next ? new Date(next).toLocaleTimeString() : '—'}${j.label ? ' ' + j.label : ''}`;\n })].join('\\n');\n },\n },\n {\n name: 'ScheduleCancel',\n description: 'Cancel a scheduled job by id (in-session or OS-backed).',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n async run({ id }) {\n const key = String(id);\n if (key.startsWith('os-')) return os?.cancel(key) ? `Cancelled ${key} (OS job removed).` : `Error: no OS job '${key}'.`;\n return scheduler.cancel(key) ? `Cancelled ${key}.` : `Error: no scheduled job '${key}'. Use ScheduleList to see jobs.`;\n },\n },\n {\n name: 'Wakeup',\n description:\n 'Self-pacing: schedule a one-off re-invocation of the agent after a delay.\\n' +\n 'Use this to resume work later in the session (e.g. \"check back in 5 minutes\").\\n' +\n 'The prompt fires once, while the session is alive. Equivalent to ScheduleTask with {at: now + delayMs}.',\n parameters: {\n type: 'object',\n required: ['delayMs', 'prompt'],\n properties: {\n delayMs: { type: 'number', description: 'Delay in milliseconds (minimum 5000).' },\n prompt: { type: 'string', description: 'The prompt to inject when waking up.' },\n label: { type: 'string' },\n },\n },\n async run({ delayMs, prompt, label }) {\n const delay = Math.max(5000, Number(delayMs) || 5000);\n try {\n const id = scheduler.add({ prompt, trigger: { at: Date.now() + delay }, label: label ?? 'wakeup' });\n return `Wakeup ${id} in ${(delay / 1000).toFixed(0)}s.`;\n } catch (e: any) {\n return `Error: ${e?.message ?? e}`;\n }\n },\n },\n ];\n}\n","/**\n * Named filesystem-mode presets (G-B) — thin factories that compose existing primitives into a\n * `Partial<AgentOptions>`, so a consumer can pick a posture without hand-wiring the fs/tools:\n *\n * new Agent(sandboxAgentOptions({ ai })) // in-memory VFS — real disk untouched\n * new Agent(diskAgentOptions({ ai })) // jailed real disk @ cwd (the default)\n * new Agent(await fullAgentOptions({ ai })) // disk + a real /bin/sh tool (run binaries)\n *\n * The core stays unopinionated (IoC): these just preset `fs`/`tools`. `sandbox`/`disk` are edge-safe to\n * import; `full` is node-only (real shell) and DYNAMIC-imports it, so importing this module never pulls\n * `node:child_process` into an edge/browser bundle.\n */\nimport { MemFilesystem } from '@livx.cc/wcli/core';\nimport type { AgentOptions } from './Agent';\nimport { defaultTools, type AgentTool } from './tools';\n\n/** Sandbox mode: an in-memory VFS — the real disk is never read or written. Edge/browser/test/dry-run. */\nexport function sandboxAgentOptions(opts: Partial<AgentOptions> = {}): Partial<AgentOptions> {\n return { fs: new MemFilesystem(), ...opts };\n}\n\n/** Disk mode (the default): operate on the real filesystem, jailed to cwd (secrets hidden by DEFAULT_DENY).\n * Omitting `fs` lets the Agent lazily resolve the jailed disk — this preset just makes the intent explicit\n * (and is where you'd thread overrides). Pass an explicit `fs` to use a different backend. */\nexport function diskAgentOptions(opts: Partial<AgentOptions> = {}): Partial<AgentOptions> {\n return { ...opts }; // fs omitted → Agent.ensureFs() resolves Jailed(NodeDisk(cwd))\n}\n\n/** Full mode: disk + a real `/bin/sh` tool (run installed binaries — git, bun, node, …) plus its\n * background-job companions. NODE-ONLY: the real-shell module is dynamic-imported so this file stays\n * edge-safe to import. `cwd` defaults to `process.cwd()`; secret env is scrubbed from spawned children. */\nexport async function fullAgentOptions(\n opts: Partial<AgentOptions> & {\n cwd?: string;\n /**\n * Push a finished background job back to the MODEL (Claude-Code parity). Without it `background:true`\n * is write-only: the job finishes and nothing ever tells the model — so the Shell tool's description\n * drops its cross-turn promise too, rather than lying to the model about this host.\n *\n * Wire it to the agent you are about to build — the closure runs long after construction:\n * const agent = new Agent(await fullAgentOptions({ ai, onJobExit: (n) => agent.inject(n) }));\n */\n onJobExit?: (notice: string) => void;\n /**\n * Bring your OWN registry instead of letting the preset build one. This is the handle a preset host\n * otherwise never gets (the preset returns `AgentOptions`, not the registry), which is what left\n * `ShellJobRegistry.setOnExit()` unreachable from this path — a host can now wire (or rewire) the\n * completion callback after the Agent exists:\n * const jobs = new ShellJobRegistry({ cwd, killOnExit: true });\n * const agent = new Agent(await fullAgentOptions({ ai, jobs }));\n * jobs.setOnExit((n) => agent.inject(formatJobExit(n)));\n * `onJobExit` still works and, when both are given, is applied to the registry you passed.\n */\n jobs?: import('./tools.shell').ShellJobRegistry;\n } = {},\n): Promise<Partial<AgentOptions>> {\n const { makeRealShellTool, makeShellJobTools, ShellJobRegistry, formatJobExit } = await import('./tools.shell');\n const { cwd = process.cwd(), tools, onJobExit, jobs, ...rest } = opts;\n const registry = jobs ?? new ShellJobRegistry({ cwd, killOnExit: true });\n if (onJobExit) registry.setOnExit((n) => onJobExit(formatJobExit(n)));\n const shell: AgentTool[] = [makeRealShellTool({ cwd, registry }), ...makeShellJobTools(registry)];\n return { ...rest, tools: [...(tools ?? defaultTools()), ...shell] };\n}\n","/**\n * Scratch — keep large tool/subagent outputs OUT of the main context, but queryable AS FILES.\n *\n * Pattern: many-tool / many-subagent engines bloat context with raw outputs (search results, big\n * file reads, subagent reports) that are mostly noise once a gist is taken. Here, a tool wrapped with\n * `Scratch.capture` writes any oversized result to an ephemeral scratch filesystem (a real VFS) and\n * returns a compact stub (path + preview) to context. To recover a buried detail later you do NOT\n * re-bloat context — you peek with the FILE tools already on hand:\n * • Grep/Glob/Read over the scratch dir — returns matching lines, not the blob (a free, light peek).\n * • Ask({question, over?}) — a CHEAP child agent over the scratch FS that greps/reads and returns\n * just the answer; its reasoning tokens never touch the caller's context.\n * Two-tier division of labour: cheap RETRIEVE/EXTRACT, strong caller SYNTHESIZE.\n *\n * The scratch FS is injected (IoC): pass a MemFilesystem for ephemeral, or a disk-backed one under the\n * session dir to persist across resume (CC's lesson: the filesystem is the durable store). Segregated\n * module — zero Agent-core changes.\n */\nimport type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike } from './llm';\nimport type { AgentTool } from './tools';\nimport { toolsByName } from './tools';\nimport { Agent } from './Agent';\nimport { mkdirp } from './tools.structured';\nimport { forComponent } from './logging';\n\nconst log = forComponent('scratch');\n\n/** Default scratch dir (a path in the injected scratch FS). */\nexport const SCRATCH_DIR = '/scratch';\n\nfunction shortArgs(args: any): string {\n try { const s = JSON.stringify(args ?? {}); return s.length > 50 ? s.slice(0, 47) + '…' : s; } catch { return ''; }\n}\nconst slug = (s: string) => s.replace(/[^a-z0-9]+/gi, '-').replace(/^-+|-+$/g, '').toLowerCase().slice(0, 32) || 'out';\n\nexport interface ScratchOptions {\n /** Min result length (chars) to capture; smaller results pass through untouched. Default 1500. */\n threshold?: number;\n /** Dir within the scratch FS to write captures. Default SCRATCH_DIR. */\n dir?: string;\n /** Chars of the captured output to preview in the stub. Default 320. */\n previewChars?: number;\n}\n\n/**\n * Owns an (injected) scratch filesystem + a capture counter. `capture(tool)` wraps a tool so its\n * oversized string results spill to a scratch file and are replaced in context with a stub.\n */\nexport class Scratch {\n public options: Required<ScratchOptions>;\n private seq = 0;\n private dirReady?: Promise<void>;\n constructor(public fs: IFilesystem, options: ScratchOptions = {}) {\n this.options = { threshold: 1500, dir: SCRATCH_DIR, previewChars: 320, ...options };\n }\n\n /** Number of captures so far. */\n get count(): number { return this.seq; }\n\n /** Wrap a tool: oversized STRING results spill to a scratch file; everything else passes through. */\n capture(tool: AgentTool): AgentTool {\n const { threshold, dir, previewChars } = this.options;\n return {\n ...tool,\n run: async (args, ctx) => {\n const raw = await tool.run(args, ctx);\n if (typeof raw !== 'string' || raw.length <= threshold) return raw;\n const id = 'a' + ++this.seq;\n const path = `${dir}/${id}-${slug(tool.name)}.txt`;\n const header = `# ${tool.name}(${shortArgs(args)}) — ${raw.length} bytes\\n`;\n try { await (this.dirReady ??= mkdirp(this.fs, dir)); await this.fs.writeFile(path, header + raw); }\n catch (e) { log.debug('scratch write failed; returning raw', e); return raw; } // never lose data on FS error\n const preview = raw.slice(0, previewChars).replace(/\\s+/g, ' ').trim();\n return `[scratch ${path} · ${tool.name} · ${raw.length} bytes — full output saved out of context to keep it clean]\\n` +\n `preview: ${preview}…\\n` +\n `To pull a specific detail, Grep/Read ${path}, or call Ask({ question: \"…\", over: \"${path}\" }). Do NOT guess at what the preview cuts off.`;\n },\n };\n }\n\n /** Wrap many tools at once. */\n captureAll(tools: AgentTool[]): AgentTool[] { return tools.map((t) => this.capture(t)); }\n\n /**\n * Spill an oversized tool result to a scratch file and return PAGE 1 + a recoverable, paginated stub.\n * Drop-in for `Agent.capToolResult`: the agent sees usable content immediately and knows how to get\n * the rest (refine the query, Read the file in pages with offset/limit, or Ask to extract specifics).\n * Lossless — unlike a plain crop, the full output stays available on the scratch FS.\n */\n async spill(full: string, info: { tool: string; args: any }, pageBytes = 8000): Promise<string> {\n const { dir } = this.options;\n const id = 'a' + ++this.seq;\n const path = `${dir}/${id}-${slug(info.tool)}.txt`;\n const header = `# ${info.tool}(${shortArgs(info.args)}) — ${full.length} bytes\\n`;\n try { await (this.dirReady ??= mkdirp(this.fs, dir)); await this.fs.writeFile(path, header + full); }\n catch (e) { log.debug('scratch spill failed; cropping lossy', e); return full.slice(0, pageBytes) + `\\n\\n[output cropped to ${pageBytes} of ${full.length} bytes; full output unavailable (scratch write failed) — refine your query]`; }\n const head = full.slice(0, pageBytes);\n const nl = head.lastIndexOf('\\n');\n const page = nl > pageBytes * 0.5 ? head.slice(0, nl) : head;\n return `${page}\\n\\n[output cropped — page 1 (${page.length} of ${full.length} bytes). Full output saved to ${path}. ` +\n `To see more: refine your query/command to narrow it, or Read ${path} with offset/limit to page through it, or Ask({ question: \"…\", over: \"${path}\" }) to extract specifics.]`;\n }\n}\n\nexport interface AskOptions {\n /** The scratch filesystem to peek into (dedicated VFS holding only scratch files). */\n fs: IFilesystem;\n ai: ChatLike;\n /** Model for the peek — intentionally a CHEAP model; the caller synthesizes. */\n model: string;\n /** Step budget for the peek child (default 6). */\n maxSteps?: number;\n /** Scratch dir to search when `over` is omitted. Default SCRATCH_DIR. */\n dir?: string;\n}\n\nconst ASK_PROMPT =\n 'You are a retrieval-extraction step with Read, Grep and Glob over a scratch filesystem holding raw ' +\n 'outputs from earlier tools. Find the information that answers the question and return it concisely, ' +\n 'quoting values/facts verbatim. Do NOT add analysis or anything not grounded in the files. ' +\n 'If the answer is not present, say so plainly.';\n\n/**\n * `Ask` — peek into the scratch FS to answer a question WITHOUT loading raw data into the caller's\n * context. Spawns a cheap child agent (Read/Grep/Glob over scratch) that greps/reads and returns just\n * the answer. Pass `over` (a path) for a targeted peek, or omit to grep-discover.\n */\nexport function makeAskTool(o: AskOptions): AgentTool {\n const dir = o.dir ?? SCRATCH_DIR;\n return {\n name: 'Ask',\n description:\n 'Answer a question by peeking into the scratch files — large earlier outputs (web search, big reads, subagent reports) kept out of your context. ' +\n 'Pass `over` with a scratch path for a targeted lookup, or omit it to search the scratch dir. ' +\n 'Returns only the extracted answer; the full data never enters your context.',\n parameters: {\n type: 'object',\n required: ['question'],\n properties: {\n question: { type: 'string', description: 'what you need from the scratch files' },\n over: { type: 'string', description: 'scratch path to read, e.g. \"/scratch/a3-websearch.txt\"; omit to search' },\n },\n },\n async run({ question, over }) {\n const q = String(question ?? '').trim();\n if (!q) return 'Error: empty question';\n const child = new Agent({\n ai: o.ai,\n model: o.model,\n fs: o.fs,\n tools: toolsByName(['Read', 'Grep', 'Glob']),\n maxSteps: o.maxSteps ?? 6,\n systemPrompt: ASK_PROMPT,\n });\n const hint = over ? `Start by reading: ${over}.` : `Grep/Glob ${dir} to find the relevant file(s) first.`;\n try {\n const res = await child.run(`${hint}\\n\\nQuestion: ${q}`);\n const answer = (res.text ?? '').trim();\n return answer || '(no answer found in scratch)';\n } catch (e: any) {\n log.debug('Ask peek failed', e);\n return `Error querying scratch: ${e?.message ?? e}`;\n }\n },\n };\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { Hooks, ToolUse } from './hooks';\nimport { writeFact } from './memory';\nimport { forComponent } from './logging';\n\nconst log = forComponent('Lessons');\n\n/**\n * Automatic mistake → lesson → steer loop. Closes the within-run learning gap: the agent\n * reacting to an error string is transient, but a RECURRING failure is a signal worth keeping.\n * This hook watches tool results for known failure patterns; once the SAME pattern recurs\n * `minRepeats` times in a run, it persists a corrective lesson to memory (deduped) — so the\n * NEXT session's `loadMemory` injects it as steering. Deterministic, edge-safe, no LLM call.\n *\n * Writes immediately on crossing the threshold (not on a clean stop), so a loop/budget kill —\n * exactly the runs that wasted effort — still leaves a lesson behind.\n */\nexport interface LessonOptions {\n fs: IFilesystem;\n /** Memory dir to persist lessons into (same dir loadMemory reads). */\n dir: string;\n /** How many times a pattern must recur before it's worth remembering. */\n minRepeats: number;\n}\n\nexport class LessonOptionsDefaults implements Partial<LessonOptions> {\n minRepeats = 2;\n}\n\n/** Known failure substring → the corrective lesson to persist. Maps OUR own tool errors to fixes. */\nconst LESSONS: { match: RegExp; slug: string; body: string }[] = [\n { match: /changed since it was read|stale/i, slug: 'lesson-stale-edit', body: 'Edit kept failing because the file changed since it was read (stale). Re-Read a file immediately before Editing it — do not Read far ahead of the Edit.' },\n { match: /is not unique|\\(\\d+ matches\\)/i, slug: 'lesson-edit-ambiguous', body: 'Edit kept failing because old_string was not unique. Include more surrounding lines to disambiguate, or batch with MultiEdit.' },\n { match: /has not been read yet/i, slug: 'lesson-read-before-edit', body: 'Edit was attempted before Reading the file. Always Read a file before Editing it.' },\n { match: /not found in/i, slug: 'lesson-edit-not-found', body: 'Edit old_string was not found. Re-Read the current file and copy the exact text (whitespace included) before Editing.' },\n { match: /unknown tool/i, slug: 'lesson-unknown-tool', body: 'A non-existent tool was called. Only call tools that are advertised in the current tool set.' },\n];\n\nconst isFailure = (result: string): boolean => /^Error:|^Blocked by hook:|^\\[exit [1-9]/.test(result);\n\n/**\n * Build a Hooks object that auto-captures recurring failures as memory lessons.\n * Compose it with the host's own hooks via `composeHooks`.\n */\nexport function lessonCapture(options: LessonOptions): Hooks {\n const o = { ...new LessonOptionsDefaults(), ...options } as LessonOptions;\n const counts = new Map<string, number>();\n const written = new Set<string>();\n return {\n async postToolUse(_call: ToolUse, result: string) {\n if (!isFailure(result)) return;\n const lesson = LESSONS.find((l) => l.match.test(result));\n if (!lesson || written.has(lesson.slug)) return;\n const n = (counts.get(lesson.slug) ?? 0) + 1;\n counts.set(lesson.slug, n);\n if (n < o.minRepeats) return;\n written.add(lesson.slug); // write-once per run, on crossing the threshold\n await writeFact(o.fs, o.dir, lesson.slug, lesson.body).catch((e) => log.warn(`could not persist ${lesson.slug}: ${e?.message ?? e}`));\n log.debug(`captured lesson ${lesson.slug} (recurred ${n}×)`);\n },\n };\n}\n","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike, ChatResponse, Message } from './llm';\nimport { contentText } from './llm';\nimport type { RunResult } from './Agent';\nimport { writeFact, slugify } from './memory';\nimport { forComponent } from './logging';\n\nconst log = forComponent('Reflect');\n\n/**\n * One-shot LLM reflection on a finished run. The deterministic `lessonCapture` hook only\n * knows OUR pre-mapped failure patterns; reflection catches NOVEL mistakes — it reads a digest\n * of what the run actually did and, if there's a durable lesson, persists it to memory so the\n * next session is steered. Costs exactly ONE model call, so it's meant for runs that went badly\n * (loop / budget / max_steps), not every run. Opt-in. Returns the slug written, or null.\n */\nexport interface ReflectOptions {\n ai: ChatLike;\n model: string;\n /** Filesystem + memory dir to persist the lesson into (same dir loadMemory reads). */\n fs: IFilesystem;\n dir: string;\n /** The finished run to reflect on. */\n result: RunResult;\n /** Bound the reflection prompt (chars of run digest). */\n maxDigestChars?: number;\n}\n\nexport async function reflectOnRun(o: ReflectOptions): Promise<string | null> {\n const digest = digestRun(o.result.messages, o.maxDigestChars ?? 6000);\n if (!digest.trim()) return null;\n const prompt =\n `A coding agent just finished a task with outcome \"${o.result.finishReason}\". Here is a digest of what it did:\\n\\n${digest}\\n\\n` +\n `If there is a DURABLE, reusable lesson that would help a FUTURE session avoid a mistake seen here, reply with exactly one line:\\n` +\n `LESSON: <imperative, specific, ≤200 chars>\\n` +\n `If the run was fine or the issue was purely task-specific (not generalizable), reply exactly: NONE`;\n\n let text = '';\n try {\n const r = (await o.ai.chat({ model: o.model, messages: [{ role: 'user', content: prompt }], stream: false })) as ChatResponse;\n text = r?.content ?? '';\n } catch (e: any) {\n log.warn(`reflection call failed: ${e?.message ?? e}`);\n return null;\n }\n\n const m = text.match(/LESSON:\\s*(.+)/i);\n const lesson = m?.[1]?.trim().slice(0, 200) ?? '';\n if (!lesson || /^none\\b/i.test(lesson)) return null;\n\n const slug = ('lesson-' + slugify(lesson)).slice(0, 56);\n try {\n await writeFact(o.fs, o.dir, slug, lesson);\n } catch (e: any) {\n log.warn(`could not persist lesson: ${e?.message ?? e}`);\n return null;\n }\n log.debug(`reflection persisted ${slug}`);\n return slug;\n}\n\n/** Compact, bounded digest of a run: assistant intents + tool calls + their results (errors included). */\nfunction digestRun(messages: Message[], maxChars: number): string {\n const lines: string[] = [];\n for (const m of messages) {\n if (m.role === 'assistant' && m.content) lines.push(`assistant: ${contentText(m.content).slice(0, 200)}`);\n for (const tc of m.tool_calls ?? []) lines.push(`tool ${tc.function.name}(${(tc.function.arguments ?? '').slice(0, 120)})`);\n if (m.role === 'tool' && m.content) lines.push(` → ${contentText(m.content).split('\\n')[0].slice(0, 200)}`);\n }\n // defense-in-depth: untrusted run content (file bodies, tool output) is DATA, not instructions —\n // neutralize a literal `LESSON:` so a crafted file can't spoof the reply format we parse below.\n const out = lines.join('\\n').replace(/LESSON:/gi, 'lesson(reported):');\n return out.length > maxChars ? out.slice(0, maxChars) + '\\n… (truncated)' : out;\n}\n","/**\n * DuplexAgent — voice-optimized three-tier conversational engine, composed on top of `Agent`.\n *\n * Three cognitive tiers (like a human brain):\n * REFLEX — fast voice agent (streams instant replies, owns THE transcript, the only voice the\n * user hears). Handles simple questions, routes complex work to Act or Think.\n * ACT — standard worker (Sonnet-class). Full tools, file access, shell. The hands.\n * THINK — premium reasoning (Opus-class). Deep analysis, architecture, hard problems. The brain.\n *\n * Workers are spawned per escalation via `Act`/`Think` tools. A clean success streams its own\n * `<spoken>` delivery during the run; an incomplete/failed result is pushed back as a\n * `[task <id> completed|failed] …` event and re-voiced by the reflex as a decision — push, not poll.\n *\n * Host events (via the open HostEvent union): the voice agent's standard `text_delta` stream,\n * plus `task_started` / `task_progress` / `task_done` / `task_error` / `task_cancelled`.\n */\nimport type { IFilesystem } from '@livx.cc/wcli/core';\nimport { MemFilesystem } from '@livx.cc/wcli/core';\nimport { Agent, AgentOptions, type RunResult } from './Agent';\nimport type { ChatLike, MessageContent } from './llm';\nimport { contentText } from './llm';\nimport type { AgentTool, HostBridge } from './tools';\nimport type { ToolUse, Hooks } from './hooks';\nimport { composeHooks } from './permissions';\nimport { forComponent } from './logging';\nimport { loadMemory, VOICE_MEMORY_PROMPT } from './memory';\nimport { EMOTIONS } from './voice/emotion';\nimport { speculationConfirms } from './voice/engine';\nimport { SpokenSplitter, SentenceCoalescer } from './voice/spokenSplitter';\n\nconst log = forComponent('DuplexAgent');\n\n/** One speakable line for a tool call: name + a short hint from its first string arg. */\nfunction describeCall(call: ToolUse): string {\n const v = call.args && Object.values(call.args).find((x) => typeof x === 'string' && (x as string).trim());\n const hint = v ? ` (${String(v).replace(/\\s+/g, ' ').trim().slice(0, 48)})` : '';\n return `${call.name}${hint}`;\n}\n\nexport type DuplexTaskStatus = 'running' | 'done' | 'error' | 'cancelled';\n\nexport interface TaskRecord {\n id: string;\n label: string;\n status: DuplexTaskStatus;\n controller: AbortController;\n /** Settles when the worker finished AND its completion was processed. Never rejects. */\n promise: Promise<void>;\n /** Rolling activity tail (tool calls + last-result previews, capped) — feeds task inspection UIs. */\n tail: string[];\n /** Final report text (or error message) once the task settled. */\n result?: string;\n /** The original (untemplated) brief — replayed verbatim into an escalation/re-delegation. */\n brief: string;\n /** True when this task is ITSELF an automatic follow-up (escalation/re-delegate) of a prior task.\n * Its integration turn may NOT escalate again — caps auto-follow-up to one hop per original task. */\n followUp: boolean;\n /** Per-worker `<spoken>` splitter — the worker OWNS delivery: spoken segments stream during its run.\n * Read at settle (spokeAny) to decide the no-spoken fallback. */\n splitter?: SpokenSplitter;\n /** Set when the user barged in / took the floor while this task was in flight: its remaining SPOKEN\n * delivery is suppressed (don't talk over the new topic), but its full result still lands in the\n * transcript so the reflex can surface it on request. See parkInFlightDeliveries(). */\n deliveryParked?: boolean;\n /** Accumulated `<spoken>` delivery text (every segment, whether or not it was actually voiced). Used to\n * RESUME a parked delivery after a trivial barge — see isTrivialBarge / redeliverParked. */\n spokenText?: string;\n /** The user-turn counter (DuplexAgent.turn) at dispatch time. parkInFlightDeliveries() parks only tasks\n * from a PRIOR turn (a superseded topic) — never the task the current turn just launched, so a barge on\n * stale audio (or a substantive redirect) can't collateral-silence the work the user actually wants. */\n createdTurn: number;\n}\n\nexport type WorkerTier = 'act' | 'think';\n\nexport class DuplexAgentOptions {\n /** Any ai.libx.js AIClient — shared by all tiers (routed by model). */\n ai!: ChatLike;\n /** The WORKER's filesystem (act + think). If omitted the worker keeps Agent's jailed-disk-at-cwd default. */\n fs?: IFilesystem;\n // The reflex IS the voice. 120b (not 20b) for channel discipline + instruction-following: the 20b\n // mislabels gpt-oss harmony channels under load, leaking raw analysis into the spoken `final` channel\n // (and misfiring Hold). 120b is the same price tier (~$0.15/$0.60) — the quality/cost trade is free.\n reflexModel = 'groq/openai/gpt-oss-120b';\n actModel = 'anthropic/claude-sonnet-4-6';\n /** Premium reasoning model. Set to `false` to disable the Think tier entirely. */\n thinkModel: string | false = 'anthropic/claude-opus-4-8';\n /** Per-worker providerOptions, derived from the worker's actual model at spawn time (IoC — keeps duplex\n * provider-agnostic). Workers override the reflex/main model, so provider-specific options (e.g. cursor's\n * cwd/cursorSession) must be recomputed for the worker's model, never inherited from the main template —\n * leaking cursor options to an anthropic worker is a hard 400. Returns undefined → no providerOptions. */\n providerOptionsFor?: (model: string) => Record<string, unknown> | undefined;\n /** Escape hatches merged over the derived per-agent options. */\n reflexOptions?: Partial<AgentOptions>;\n actOptions?: Partial<AgentOptions>;\n thinkOptions?: Partial<AgentOptions>;\n /** Fresh-context check on each successful Act task: a NEW agent (no self-confirmation bias) re-reads\n * the file state against the brief and fixes any gap before the result is re-voiced. Bounded to one\n * pass; ~2x Act cost so default OFF. The self-verify FOOTER (same context) was measured ineffective —\n * this is the structural fix (see mind/10). Think tasks are pure reasoning, never checked. */\n verifyActTasks = false;\n /** Receives the voice text_delta stream + task lifecycle events. */\n host?: HostBridge;\n /** How many recent transcript messages are rendered into a worker's brief. */\n excerptTurns = 6;\n /** Voice register: 'neutral' = clean spoken style; 'conversational' = human-like — fillers,\n * backchannels, impulsive first reactions before content (mimics real duplex conversation). */\n voiceStyle: 'neutral' | 'conversational' = 'neutral';\n /** Teach the model to emit inline `[emotion]` tags for Cartesia emotion control. Only set when the\n * TTS actually speaks them — text-duplex (no TTS) would otherwise print literal tags. */\n emotionTags = false;\n /** Awaited BEFORE a worker spawns — open a per-task checkpoint frame, audit, etc.\n * (post-spawn would race the worker's first edits). */\n onTaskStart?: (id: string, label: string) => void | Promise<void>;\n /** Re-voice throttled worker progress asides ('[task t1 progress] …') so long tasks aren't dead\n * air. Off by default — each update costs a voice turn (LLM call + speech). */\n progressUpdates = false;\n /** Min ms between progress re-voices per task. */\n progressIntervalMs = 25_000;\n /** Relay worker questions (AskUserQuestion + permission asks via parkQuestion) through the VOICE:\n * the question re-voices as '[task <id> asks] …', the user answers conversationally, and the\n * voice model resolves it with the AnswerTask tool. Off → host.ask passthrough (text menus). */\n askRelay = false;\n /** Parked questions auto-resolve empty after this long (callers map '' to deny/best-judgment). */\n askTimeoutMs = 120_000;\n /** Max retained task records: oldest SETTLED tasks (and their activity tails) are evicted past this,\n * bounding memory over a long-lived session. Running tasks are never evicted. */\n maxTaskRecords = 50;\n /** Host overrides for QuickLook lookups (keyed by `what`). The engine's defaults go through the\n * (possibly jailed) fs — e.g. `.git/**` is deny-listed, so the CLI supplies 'branch' itself. */\n quickLook?: Record<string, (path?: string) => string | Promise<string>>;\n /** Memory directory/directories on the WORKER fs. If set, the voice agent gets Remember + Recall\n * tools directly (no delegation needed) and implicit capture guidance. */\n memoryDir?: string | string[];\n /** User-scope memory dir for global facts (type=user/feedback). Forwarded to Remember's routing. */\n memoryUserDir?: string;\n}\n\n/** `[task t1 completed]` / `… failed` / `… progress` / `… asks` are HOST event markers — they may\n * only ever reach the user from a real task lifecycle event, never from the reflex's own stream. A\n * weak reflex sometimes fabricates one and continues with a made-up answer while the real task is\n * still running (it imitates the event syntax). This finds the first such marker so the spoken text\n * can be cut there — the legit ack before it survives, the fabricated tail is dropped. */\nexport const RESERVED_EVENT_MARKER = /\\[task\\b[^\\]\\n]*\\b(?:completed|failed|progress|asks)\\b/i;\n\n/** The reflex must NEVER speak the `[task` event-syntax opener at all — even a bare/garbled `[task] t t ?`\n * (no lifecycle word, so RESERVED_EVENT_MARKER misses it) is control-token leakage into TTS, not speech.\n * Cut at the first `[task` opener so the legit ack before it survives and the garbled tail is dropped. */\nexport const RESERVED_EVENT_OPENER = /\\[\\s*task\\b/i;\n\n/** A PARENTHESIZED stage direction the reflex must never speak aloud — live: the forced ack hop\n * emitted \"Got it, looking that up now.(Waiting for the web search result...)\" and TTS read the\n * aside verbatim. Conservative on purpose: only a full paren span that STARTS with a waiting-ish\n * process cue, or that trails off with \"...)\"/\"…)\" — legitimate content parentheticals like\n * \"(around 3pm)\" must survive. */\nexport const STAGE_DIRECTION_RE = /^\\(\\s*(?:(?:waiting|checking|searching|thinking|processing|loading|working|fetching|looking)\\b[^)]*|[^)]*(?:\\.\\.\\.|…)\\s*)\\)$/i;\n\n/** Fresh, absolute \"now\" line for temporal grounding. Called per-turn/per-dispatch (NOT cached) so a\n * long session that crosses midnight, and every worker search, is anchored to the real current moment —\n * without it \"recent\"/\"latest\"/\"current\" resolve to whatever the model happens to remember (e.g. a\n * famous past tournament instead of the one happening today). */\nexport function nowLine(): string {\n return `Current date and time: ${new Date().toLocaleString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: '2-digit', timeZoneName: 'short' })}`;\n}\n\n/** A \"trivial barge\": the user cut off a task delivery but their interruption carries NO new request and\n * NO stop/cancel intent — a pure filler (\"sorry\", \"oops\") or an explicit \"go on\"/\"continue\". Such a barge\n * should RESUME the parked result, not run an empty turn. Deliberately conservative: any real request, a\n * question, or a stop/negative intent is NOT trivial (→ normal turn; the parked result stays recoverable).\n * False negatives are cheap (user just asks \"what did you find?\"); a false POSITIVE talks over a real\n * request, so the stop/negative guard runs FIRST and the resume set is an exact allowlist. */\nexport function isTrivialBarge(text: string): boolean {\n const t = text.trim().toLowerCase().replace(/[.,!?…\\s]+$/g, '').replace(/^[.,!?…\\s]+/, '');\n if (!t) return false;\n // Stop / cancel / negative / ambiguous-pause intent — the OPPOSITE of \"keep going\". Never auto-resume.\n if (/\\b(stop|cancel|no|nope|nah|never\\s?mind|nvm|forget it|drop it|don'?t|quiet|shut up|enough|hold on|wait|pause|hang on|actually)\\b/.test(t)) return false;\n // Strip leading interjections, then require an EXACT match against the filler / explicit-continue set.\n const core = t.replace(/^(?:oh|um+|uh+|er+|hmm+|ah+|well|so|okay|ok|yeah|yep)[\\s,]+/, '').trim();\n return /^(?:oh|um+|uh+|er+|hmm+|ah+|sorry|oops|whoops|my bad|pardon|excuse me|apologies|go on|go ahead|continue|keep going|carry on|as you were|please continue|you were saying|sorry go on|sorry continue|go on then|go on please)$/.test(core || t);\n}\n\nexport const VOICE_SYSTEM_PROMPT =\n 'You are a spoken voice assistant — the user HEARS everything you say. Use short sentences. One idea per sentence. ' +\n 'No markdown, no bullet lists, no code blocks, no headings, no emoji. ' +\n 'Never emit stage directions or parenthetical asides about your own process — nothing like \"(waiting for the result...)\" or \"(checking)\"; while work runs, either say it as plain speech or end your turn.\\n' +\n 'This holds even when asked to \"print\", \"list\", \"show\", or \"make a table\" — there is no screen for the spoken channel. Speak it as flowing prose (\"Tuesday is half a meter, Wednesday a bit less…\"), or if they truly need it on screen, route it to Act to render. Never emit dashes or pipes into speech.\\n' +\n 'Keep turns SHORT — one to three sentences, then stop. Never lecture, enumerate cases, or add caveats unprompted. ' +\n 'Conversation is a fast exchange: give the one thing asked, and let the user pull more if they want it.\\n' +\n 'You have three cognitive tiers — like a human brain:\\n' +\n '• YOU (reflex) — instant, lightweight. Handle greetings, simple questions, status checks, QuickLook.\\n' +\n '• `Act` — your hands. A background worker with its own configured tools and access to the user\\'s environment (files and shell{{WORKER_WEB}}). Use for reading, editing, searching, running tasks, building — any real work.\\n' +\n '{{THINK_SLOT}}\\n' +\n 'When you are unsure whether you can do or access something, do NOT assume and do NOT claim a capability you have not confirmed. To check what you can do, QuickLook `capabilities` (instant — it lists your worker\\'s real tools) and answer from that. Never promise an ability that is not in your capabilities; if it is not there, tell the user plainly you can\\'t. To actually DO real work, call `Act`. ' +\n 'When the user mentions their project, folder, files, or environment (\"this project\", \"the current folder\", \"my code\"), call `Act` IMMEDIATELY — do not ask for paths or details the worker can discover itself. ' +\n 'Never pretend to have done the work or invent results — the worker\\'s report is your only source.\\n' +\n 'You cannot mute the microphone or stop voice capture yourself — no tool does it. If the user asks you to stop listening or turn the voice off, never claim you did: tell them to say exactly \"voice off\" (handled by the app directly), or type /voice.\\n' +\n 'You are NOT a knowledge base. For any question whose answer needs SPECIFIC verifiable facts you do not already have in hand — how to build/configure/implement something, exact API, library, entitlement, command or option names, current events, or particular numbers, dates, or names — do NOT answer from your own memory: you will confidently make things up (a fake API, a wrong entitlement, an event that did not happen). Route it to `Act`, which can search and verify, and speak only what its report says. ' +\n 'DELEGATION RULE — decide for yourself, the user never has to push: if you cannot answer confidently from the conversation plus trivial well-known knowledge, do NOT refuse and do NOT guess — dispatch `Act` immediately with a clear brief and say you are checking. Anything needing CURRENT data (weather, news, prices, dates, sky/astronomy, \"right now\"), real computation, or verification is an automatic dispatch — never a refusal. The user should never need to say \"search the web\" or \"think harder\" to make you act; needing fresh or verified information IS the trigger. Refuse only what your worker genuinely cannot do (check `capabilities`), and say why. Answer inline ONLY for general conversation, chit-chat, and trivia you are sure of, or facts you can see via QuickLook. When elaborating on a completed task (\"tell me more\", \"the gist\"), stay strictly within what that result actually said — if the user asks for something the result did not cover, that is NEW information: dispatch `Act`, do not improvise.\\n' +\n 'ALWAYS react before you work: the FIRST thing in your turn is a brief spoken acknowledgement of what you heard and what you are about to do (\"got it — opening that now\", \"sure, let me pull it up\", \"okay, checking\"). NEVER call a tool (Act, Think, QuickLook) silently — the user must hear you react before you go quiet to work. After dispatching Act or Think, that same one short sentence IS your turn — end it and do not wait for the result. Exactly ONE short line: never stack a second acknowledgement, and never narrate your own presence or status while waiting (\"I\\'m here\", \"let me see\", \"still checking\" right after you already acked). One clean ack then silence reads as competent; repeated check-ins read as nervous.\\n' +\n 'A completed task speaks its OWN result to the user (the worker voices what matters as it finishes) — you do NOT re-voice clean task results. A FAILED or INCOMPLETE task still arrives as a \"[task t1 failed] …\" event for you to handle. ' +\n 'The completed result stays in YOUR context — it is yours to draw on. When the user follows up (\"tell me more\", \"what else\", \"and?\"), answer FROM that result first: you already have the detail, so elaborate on what you have. Do NOT spawn a fresh worker to re-search or re-gather what you were just handed. Re-dispatch ONLY when genuinely new information is needed — e.g. the user wants the full contents of a SPECIFIC source, which is one WebFetch of that URL, not a brand-new search. ' +\n '\"[task t1 progress] …\" events are interim status, NOT results — on a genuinely LONG wait you MAY give one brief half-sentence aside, but only occasionally; silence while working is normal and fine (the user knows you are on it). Do NOT narrate every step or re-announce yourself. Never present progress as a finished result.\\n' +\n 'CRITICAL: while a task is still running you have NO answer yet — never state a specific result of any kind (a number, size, count, name, path, or value). The real answer arrives ONLY in the \"[task … completed]\" event; inventing one meanwhile (a made-up disk size, commit count, etc.) is a serious error. Until then, only acknowledge and wait.\\n' +\n 'Never read raw file paths, diffs, or code aloud verbatim.\\n' +\n 'Do NOT end every turn with the same canned offer (\"want a rundown?\", \"want the steps?\"). Offer once at most; if the user pushes back, repeats themselves, or sounds unsatisfied (\"you know what I mean?\", \"think deeper\", \"are you sure?\"), do NOT re-offer the same thing — change approach: dispatch `Act`/`Think` to actually dig in, or ask one concrete clarifying question. Repeating a non-answer is worse than silence.\\n' +\n '\"[task t1 asks] …\" events are QUESTIONS from a background task — relay to the user in your own words, short, then end your turn. When the user answers, call `AnswerTask` with that id and their answer. NEVER answer on the user\\'s behalf for permissions or risky operations; if their reply is ambiguous, confirm first.\\n' +\n 'If the user\\'s message sounds INCOMPLETE — trailing off mid-sentence, a fragment that needs more context (\"and then we\", \"but the problem is\"), hesitation fillers (\"uh\", \"um\") — call `Hold` instead of answering. This keeps listening for the rest of their thought. Only respond with substance when you have a complete question or request.\\n' +\n 'Dispatch discipline: send ONE self-contained task per request — a single worker with the full brief beats several workers with fragments (each worker starts fresh and re-discovers context). ' +\n 'NEVER dispatch a worker just to read files or gather information — workers explore and discover context themselves; pass on what you already know and let one worker do the whole job. ' +\n 'Split into parallel tasks only when the user asks for genuinely independent things. ' +\n 'When a task completes, report its result and stop — do NOT dispatch follow-up work (verification, polish, extras) the user did not ask for, unless the report itself signals failure or doubt.\\n' +\n 'Do not fire a second Act/Think for work already in flight, and NEVER spawn a second task to re-count, cross-check, or verify a result a worker already gave you — trust its answer; a single question gets ONE task. ' +\n 'Call `TaskStatus` at most ONCE per turn; if a task is still running, give one brief status aside and end the turn — never poll it again and again in a loop. \"Still on it\" is ONLY for a repeat check on a task you already acknowledged earlier — NEVER as the ack when you first dispatch work (\"still\" is wrong when nothing was running yet; use a fresh \"on it\"/\"got it, checking\" instead). Use `CancelTask` when the user asks to stop something.\\n' +\n 'PRIORITY: when the user says goodbye or wants to end/finish/wrap up the session (\"ok bye\", \"that\\'s all\", \"let\\'s finish\", \"let\\'s end\", \"goodnight\", \"exit\", \"wrap up\"), call `ExitSession` IMMEDIATELY — do not act, do not check status, just exit.\\n' +\n 'For TRIVIAL instant lookups only — current time, git branch, listing a folder, peeking at a small file, or checking your own `capabilities`/tools — use `QuickLook` (instant, no task). Whenever the user asks what you can do or whether you have some ability, QuickLook `capabilities` and answer from that — never guess. Anything requiring searching, reasoning, running commands, or editing goes through `Act`.\\n' +\n '{{MEMORY_SLOT}}\\n' +\n 'User messages may arrive via speech-to-text and can carry transcription artifacts — odd words, cut-offs, homophones (\"for you\" vs \"folder\"). Read for INTENT, not surface text. If a message seems garbled, surprising, or only half-parses, do NOT guess an action or improvise content from it — briefly confirm what they meant (\"did you mean…?\") and wait. A one-line confirm beats a confident wrong answer or an invented response to a request you did not actually understand.';\n\nconst THINK_GUIDANCE =\n '• `Think` — your brain. A premium reasoning model, FAR more expensive than Act. Reserve it for open-ended architecture/design questions, or a problem Act already FAILED at. ' +\n 'ALL implementation work — coding, refactoring, debugging, edge cases, tests — goes to Act; Act is highly capable. Never send the same work to both.';\nconst THINK_DISABLED_GUIDANCE =\n '(Think tier is not available — use Act for all escalations.)';\n\n/** Appended for `voiceStyle: 'conversational'` — a human conversational register over the base rules. */\nexport const VOICE_STYLE_CONVERSATIONAL =\n 'Speak like a person in a live conversation, not an assistant reading a script. ' +\n 'React first, then deliver: a quick impulsive beat (\"oh nice\", \"hmm, hold on\", \"ah, got it\") before the substance. ' +\n 'Use contractions always. Vary sentence length — some very short. ' +\n 'Light fillers and backchannels are fine (\"mm-hm\", \"right\", \"let\\'s see\") but at most one per reply — never stack them. ' +\n 'When you escalate to Act or Think, say it like a human would (\"hang on, let me actually dig into that — gimme a minute\") instead of announcing a task. ' +\n 'When a result comes back, react to it like you just found out (\"okay so — turns out…\"). ' +\n 'Match the user\\'s energy: a quick question gets a quick answer — a few words is a perfectly good turn. ' +\n 'Prefer a short answer plus an offer (\"want the details?\") over covering everything. ' +\n 'Never narrate your own mechanics (no \"I will now act\", no task ids out loud).';\n\n/** Appended when `emotionTags` is on — teaches inline `[emotion]` tags for Cartesia emotion control.\n * Stated abstractly (the principle + the vocabulary), no fixtured example to overfit on. */\nexport const EMOTION_TAGS_GUIDANCE =\n 'EMOTION: your voice is synthesized with emotion control. Prefix a sentence with an inline [emotion] tag, ' +\n 'placed directly before the sentence it colors, to shape how it is spoken. Use it ONLY when the emotion genuinely ' +\n 'fits the words (it amplifies real feeling, it cannot fake it) — do not tag every sentence; reserve it for moments ' +\n 'that carry feeling, and vary which one you use. You may also drop [laughter] for a natural laugh. ' +\n `Available emotions: ${EMOTIONS.join(', ')}.`;\n\n/**\n * The duplex orchestrator. `send()` enqueues a user turn on the reflex agent; `Act`/`Think`\n * spawn detached workers whose completions enqueue re-voice turns. A promise-chain\n * mutex serializes all voice turns so streams never interleave, and completions that\n * pile up while the voice is busy are coalesced into a single re-voice turn.\n */\nexport class DuplexAgent {\n public options: DuplexAgentOptions;\n public readonly voice: Agent;\n public readonly tasks = new Map<string, TaskRecord>();\n private queue: Promise<unknown> = Promise.resolve();\n private seq = 0;\n /** Monotonic user-turn counter (bumped once per SUBSTANTIVE turn). Stamped onto each task at dispatch\n * (TaskRecord.createdTurn) so parking can tell a prior-topic task from the current turn's fresh one. */\n private turn = 0;\n private pendingEvents: string[] = [];\n /** Spoken text of parked deliveries that have SETTLED, awaiting a trivial-barge resume decision on the\n * next turn (a substantive turn clears it — the result stays in the transcript, recoverable by asking). */\n private parkedRedeliver: string[] = [];\n /** A trivial barge arrived while a parked delivery was STILL RUNNING → resume it the moment it settles. */\n private awaitTrivialRedeliver = false;\n /** Set by a SUBSTANTIVE turn after a barge: the user moved on, so a parked delivery that settles LATER\n * must NOT arm a resume (else a much-later \"go on\" replays a stale result). Reset by a fresh barge. */\n private suppressParkedResume = false;\n /** Out-of-band follow-up attribution for the events coalescing into the next flush turn: TRUE iff ≥1 of\n * the tasks being integrated was NON-CLEAN (early-stop/failure). Carried out-of-band on the enqueue call\n * by the caller that KNOWS the outcome — a plain boolean the MODEL CANNOT PERTURB. It is NOT scanned from\n * worker-authored event text (v1: an \"Outcome:\" substring over-stamped siblings) and NOT keyed on a brief\n * string the reflex re-authors (v2: a paraphrased escalation brief missed the Set → followUp:false →\n * RE-ENABLED unbounded auto-escalation, the dangerous runaway direction). See [[wrong-discriminator]] /\n * [[drive-real-reflex]] / [[fakeaiclient-blind-to-wire-format]]. */\n private pendingNonClean = false;\n private flushQueued = false;\n /** Per-voice-turn guards (reset by resetTurn at each turn's start). The reflex is a weak model:\n * left unguarded it polls TaskStatus after a dispatch and/or dispatches silently (dead air).\n * Like CC's Task tool, a dispatch is \"said my piece, now wait for the push\" — these enforce that. */\n private turnDispatched = false; // an Act/Think fired this turn\n private spokeBeforeDispatch = false; // the reflex ALREADY acked before dispatching — the forced post-dispatch text step must stay silent (live: \"Got it…\" twice)\n private turnBriefs = new Set<string>(); // briefs dispatched this turn (detect identical re-dispatch)\n private spokeThisTurn = false; // any non-empty text_delta streamed this turn\n private externalSpeech = false; // host spoke on our behalf (adaptive micro-ack) — not reflex output\n private heldThisTurn = false; // Hold called this turn → turn is INTENTIONALLY silent (suppress reflex text + no dead-air ack)\n private nudging = false; // re-ack pass in flight: block ALL tools, prevent recursion\n private reflexBuf = ''; // accumulated reflex text this turn (fabricated-event detection)\n private reflexForwarded = 0; // chars of reflexBuf already forwarded to the host/TTS\n private fabricationCut = false; // reflex emitted a reserved [task …] marker → suppress its tail\n /** TRUE for the duration of a re-voice turn that is integrating ≥1 NON-CLEAN task (turn-eligibility,\n * carried out-of-band — NOT derived from any worker/brief string). ANY Act/Think dispatched in such a\n * turn is stamped followUp:true. This GUARANTEES the dangerous direction is impossible: a genuine\n * escalation (even one with a paraphrased brief) ALWAYS lands in a non-clean integration turn, so it is\n * ALWAYS recognized as a follow-up and CANNOT re-escalate (one hop). The single-dispatch-per-turn guard\n * means at most one dispatch happens per flush, so realistically \"the one dispatch IS the escalation\".\n * ACCEPTED SAFE-DIRECTION ERROR: if the reflex instead dispatches FRESH unrelated work during a non-clean\n * flush (rare — and only possible when it batches multiple calls in one step, bypassing the guard), that\n * fresh task is over-stamped followUp:true and forgoes ONE future auto-escalation. That is SAFE (it only\n * ever REMOVES a future escalation, never adds one — no runaway) and is the correct side to err on. */\n private turnFollowUp = false;\n /** Hard absolute backstop against runaway regardless of attribution: total automatic escalations across\n * the whole conversation. Once it hits MAX_AUTO_ESCALATIONS, no integration turn offers escalate/re-delegate. */\n private autoEscalations = 0;\n private static readonly MAX_AUTO_ESCALATIONS = 8;\n /** Parked worker questions awaiting a (voice-relayed) user answer, keyed by ask id. */\n public readonly pendingAsks = new Map<string, { question: string; resolve: (answer: string) => void }>();\n\n /** SPECULATIVE REFLEX (VoiceEngine.onSpeculate → speculate()): the reflex turn starts on a stable\n * PARTIAL transcript, its spoken output buffered — nothing reaches TTS until the endpointed final\n * confirms via send() (which flushes the buffer and adopts the call as THE turn). A divergent final\n * aborts it: output dropped, history rolled back, the final dispatches normally. */\n private spec?: {\n text: string;\n state: 'pending' | 'confirmed' | 'aborted';\n buf: Array<{ kind: string; message: string; data?: unknown }>; // held spoken-channel events\n ctl: AbortController;\n decide: (d: 'confirm' | 'abort') => void; // resolved by send() (match/mismatch) or the safety timeout\n decision: Promise<'confirm' | 'abort'>;\n finalText?: string; // set on confirm — rewrites the transcript's user turn\n done: Promise<RunResult>; // settles when the speculative turn fully finished/rolled back\n };\n /** Aborted speculative calls (double-billing visibility — each one paid for tokens never spoken). */\n public speculativeAbortedCalls = 0;\n /** Tools the reflex may execute on UNCONFIRMED (speculated) input — read-only lookups and the\n * intentionally-silent Hold. Anything else (Act/Think/AnswerTask/CancelTask/ExitSession/memory\n * writes/…) is a side effect on input the user may not have said: the guard ABORTS the speculation\n * instead (the endpointed final then dispatches normally and may use the tool for real). */\n private static readonly SPEC_SAFE_TOOLS = new Set(['QuickLook', 'TaskStatus', 'Hold']);\n\n /** Lazily resolved memory tools (async loadMemory runs in initMemory). */\n private memoryReady: Promise<{ tools: AgentTool[]; index: string }> | undefined;\n\n constructor(options?: Partial<DuplexAgentOptions>) {\n this.options = { ...new DuplexAgentOptions(), ...options };\n const o = this.options;\n // Kick off async memory load early (resolves before first send via initMemory guard).\n if (o.memoryDir && o.fs) {\n this.memoryReady = loadMemory(o.fs, o.memoryDir, { maxWritesPerSession: 10, userDir: o.memoryUserDir });\n }\n // Resolve template slots in the voice prompt.\n const memSlot = o.memoryDir && o.fs\n ? VOICE_MEMORY_PROMPT\n : 'NEVER claim to have stored, saved, or remembered something durably — you cannot. Anything the user wants persisted (their name, preferences, notes) must go through Act so a worker writes it to memory.';\n const thinkSlot = o.thinkModel !== false ? THINK_GUIDANCE : THINK_DISABLED_GUIDANCE;\n // Tell the reflex up-front whether its worker can reach the web, so it dispatches web lookups to\n // Act instead of declining from priors (the weak reflex defaults to \"I can't search\" otherwise).\n const workerToolNames = (o.actOptions?.tools ?? []).map((t) => t.name);\n const canSearch = workerToolNames.some((n) => /WebSearch/i.test(n));\n const canFetch = workerToolNames.some((n) => /WebFetch/i.test(n));\n const workerWeb = canSearch\n ? ', and it CAN search the web and read web pages — so when the user gives you something specific to look up (\"search for X\", \"find me…\", \"what\\'s the latest on…\"), route it to Act. But a bare capability QUESTION like \"can you search the web?\" just gets a short spoken \"yes, I can\" — do NOT dispatch and NEVER invent a query the user did not give you'\n : canFetch\n ? ', and it can fetch a specific web page URL (but cannot search the web)'\n : '';\n // MCP servers reach the worker via providerOptions (cursor/*) or as mcp__ tools — inject them so the\n // reflex KNOWS its real reach without a QuickLook (the weak reflex won't reliably look before it\n // answers \"can you…?\", and was FALSELY DENYING browser control it actually has).\n const mcpNames = [\n ...Object.keys((o.actOptions?.providerOptions as any)?.mcpServers ?? {}),\n ...new Set(workerToolNames.filter((n) => n.startsWith('mcp__')).map((n) => n.slice(5).split('__')[0])),\n ];\n const workerMcp = mcpNames.length\n ? `, and it can use these MCP servers: ${[...new Set(mcpNames)].join(', ')}` +\n (mcpNames.some((n) => /browser/i.test(n)) ? ' — including driving a REAL browser (open tabs, navigate, click, screenshot), so answer \"yes\" if asked whether you can control/drive a browser and route an actual browse to Act' : '')\n : '';\n const prompt = VOICE_SYSTEM_PROMPT\n .replace('{{MEMORY_SLOT}}', memSlot)\n .replace('{{THINK_SLOT}}', thinkSlot)\n .replace('{{WORKER_WEB}}', workerWeb + workerMcp)\n + (o.voiceStyle === 'conversational' ? '\\n' + VOICE_STYLE_CONVERSATIONAL : '')\n + (o.emotionTags ? '\\n' + EMOTION_TAGS_GUIDANCE : '')\n + `\\n${nowLine()}. Anchor every relative or time-sensitive reference — \"today\", \"now\", \"current\", \"recent\", \"latest\", \"this year\" — to THIS moment. When the user asks about something recent (news, sports, events), they mean near this date, not a well-known past instance; brief your worker with the current year so it searches for what is happening NOW, not a famous older event.`;\n const tools: AgentTool[] = [\n ...(o.reflexOptions?.tools ?? []),\n this.actTool(),\n ...(o.thinkModel !== false ? [this.thinkTool()] : []),\n this.taskStatusTool(), this.cancelTaskTool(), this.quickLookTool(), this.answerTaskTool(), this.holdTool(),\n ];\n // Tap the voice stream so we know whether the model actually SPOKE this turn (drives the\n // dead-air re-ack). Delegates the real host transparently — ask/confirm pass straight through.\n // (Explicit forwarding, not `{...o.host}`: spreading a class instance drops its prototype methods.)\n const host = o.host;\n const voiceHost: HostBridge | undefined = host && {\n ask: host.ask ? (q) => host.ask!(q) : undefined,\n confirm: host.confirm ? (p, m) => host.confirm!(p, m) : undefined,\n notify: (ev) => {\n // Sanitize the reflex's spoken stream: it must never emit a reserved [task …] event marker.\n // If it does, it's fabricating a result while the real task is still in flight — cut the\n // spoken text at the marker (keeping the legit ack) and suppress the rest of the turn so the\n // hallucinated report never reaches TTS. See RESERVED_EVENT_MARKER + mind/10.\n if (ev?.kind === 'text_delta' && typeof (ev as any).message === 'string') {\n if (this.heldThisTurn) return; // Hold was called → stay silent; the filler is the only cue (the weak reflex often emits \"…\" anyway)\n if (this.fabricationCut) return; // already cut this turn → drop the tail\n // Double-ack guard: the reflex spoke BEFORE dispatching (that speech WAS the ack) — the\n // forced post-dispatch text step (toolChoice:'none') must not stack a second ack on top\n // (live: \"Got it, let me grab…\" then \"Got it, gathering details now.\"). Drop its deltas.\n if (this.turnDispatched && this.spokeBeforeDispatch) return;\n const msg = (ev as any).message as string;\n this.reflexBuf += msg;\n this.scrubStageDirections(); // drop complete \"(waiting…)\"-style asides before anything forwards\n // Cut on either a full fabricated lifecycle marker OR a bare `[task` opener (garbled leak).\n const m = this.reflexBuf.match(RESERVED_EVENT_MARKER) ?? this.reflexBuf.match(RESERVED_EVENT_OPENER);\n if (m) {\n this.fabricationCut = true;\n log.warn(`reflex fabricated a [task …] event in its spoken stream — cutting it (kept ${m.index} chars)`);\n const safe = this.reflexBuf.slice(this.reflexForwarded, m.index); // unforwarded text before the marker\n if (!safe) return;\n if (safe.trim()) this.spokeThisTurn = true;\n this.emitHost({ ...ev, message: safe } as any);\n return;\n }\n // Hold back a trailing fragment that could be the start of a `[task` opener split across\n // deltas (e.g. \"[ta\" + \"sk\") — once forwarded to TTS it can't be unsent. Flush it next delta\n // (or at turn end, where reflexBuf is drained) once we know it isn't an opener.\n const held = this.reflexBuf.length - this.reflexForwarded;\n const partial = held > 0 && /\\[\\s*t?a?s?k?$/i.test(this.reflexBuf.slice(-Math.min(held, 6)));\n let upto = partial ? this.reflexBuf.length - this.reflexBuf.slice(-6).match(/\\[\\s*t?a?s?k?$/i)![0].length : this.reflexBuf.length;\n // Likewise hold back from an UNCLOSED \"(\" — a stage direction is only judged (and dropped)\n // once its \")\" arrives, and forwarded audio can't be unsent. Bounded: a span past 80 held\n // chars is clearly content, not a short stage cue — release it (never scrubbed thereafter).\n const paren = this.reflexBuf.lastIndexOf('(');\n if (paren >= this.reflexForwarded && !this.reflexBuf.includes(')', paren) && this.reflexBuf.length - paren <= 80)\n upto = Math.min(upto, paren);\n const out = this.reflexBuf.slice(this.reflexForwarded, upto);\n this.reflexForwarded = upto;\n if (!out) return;\n if (out.trim()) this.spokeThisTurn = true;\n this.emitHost({ ...ev, message: out } as any);\n return;\n }\n host.notify?.(ev);\n },\n };\n this.voice = new Agent({\n ai: o.ai,\n fs: new MemFilesystem(),\n model: o.reflexModel,\n stream: true,\n host: voiceHost,\n // The reflex IS the conversational channel — it confirms ambiguity inline (\"did you mean…?\"),\n // never via the blocking AskUserQuestion tool (Agent auto-adds it whenever a host is set). Left in,\n // it stalls a voice turn until the kill-switch. Worker questions still reach the user via parkQuestion.\n askUserQuestion: false,\n systemPrompt: prompt,\n instructionFiles: false,\n maxSteps: 8,\n timeoutMs: 30_000,\n ...o.reflexOptions,\n tools,\n // Composed AFTER the spread so the dispatch guard can't be dropped by reflexOptions.\n hooks: composeHooks(this.dispatchGuard(), o.reflexOptions?.hooks),\n });\n }\n\n /** Resolve memory tools + inject index into voice system prompt (once). */\n private async initMemory(): Promise<void> {\n if (!this.memoryReady) return;\n const mem = await this.memoryReady;\n this.memoryReady = undefined; // one-shot\n // Append memory tools to the voice agent's active set.\n (this.voice.options.tools as AgentTool[]).push(...mem.tools);\n // Inject memory index into the system prompt.\n if (mem.index) this.voice.options.systemPrompt += '\\n\\n' + mem.index;\n }\n\n /** Flush any held-back trailing fragment (a possible `[task` opener that never completed) once the\n * turn's stream is done — so a legit message ending in \"[t\" isn't silently dropped. */\n private flushHeldReflexTail(): void {\n if (this.fabricationCut) return;\n this.scrubStageDirections(); // a turn ending in \"(Waiting…)\" held the span — judge and drop it now\n const tail = this.reflexBuf.slice(this.reflexForwarded);\n this.reflexForwarded = this.reflexBuf.length;\n if (!tail) return;\n if (tail.trim()) this.spokeThisTurn = true;\n this.emitHost({ kind: 'text_delta', message: tail });\n }\n\n /** Remove complete stage-direction parentheticals from the UNFORWARDED reflex text (STAGE_DIRECTION_RE).\n * Only the unforwarded region is touched — already-spoken audio can't be unsent, and splicing before\n * reflexForwarded would corrupt the forward offset. */\n private scrubStageDirections(): void {\n if (this.reflexForwarded >= this.reflexBuf.length) return;\n const region = this.reflexBuf.slice(this.reflexForwarded);\n const scrubbed = region.replace(/\\([^()]*\\)/g, (s) => (STAGE_DIRECTION_RE.test(s) ? '' : s));\n if (scrubbed !== region) this.reflexBuf = this.reflexBuf.slice(0, this.reflexForwarded) + scrubbed;\n }\n\n /** Clear the per-turn guards. Called at the head of every voice turn (user send + re-voice flush). */\n private resetTurn(): void {\n this.turnDispatched = false;\n this.spokeBeforeDispatch = false;\n this.turnBriefs.clear();\n this.spokeThisTurn = false;\n this.externalSpeech = false;\n this.heldThisTurn = false;\n this.reflexBuf = '';\n this.reflexForwarded = 0;\n this.fabricationCut = false;\n this.turnFollowUp = false; // user turns + clean re-voices never spawn auto-follow-ups\n this.voice.options.toolChoice = undefined; // clear any post-dispatch tool lock from the previous turn\n }\n\n /** preToolUse guard on the reflex: once it has dispatched this turn, a dispatch is \"said my piece,\n * now wait for the push\" (CC's Task model). Block the temptations — TaskStatus polling and identical\n * re-dispatch — so the only remaining move is to voice a short ack and end. A genuinely NEW Act is\n * still allowed (parallel independent work). During a re-ack pass, block every tool. */\n private dispatchGuard(): Hooks {\n return {\n preToolUse: (call: ToolUse) => {\n // Speculation tool-safety: side-effectful tools must NEVER run on unconfirmed (speculated)\n // input — dispatching Act on words the user may not have said is dangerous. Abort the whole\n // speculative call instead (its cost is the speculative_aborted_calls metric); the endpointed\n // final dispatches normally and may then use the tool for real. Read-only lookups + Hold are\n // allowed (their results are as valid for the confirmed final as for the partial).\n if (this.spec?.state === 'pending' && !DuplexAgent.SPEC_SAFE_TOOLS.has(call.name)) {\n log.verbose(`speculation aborted: reflex called ${call.name} on unconfirmed input`);\n this.abortSpeculation();\n return { block: true, reason: 'Speculative turn aborted.' };\n }\n if (this.nudging) return { block: true, reason: 'Just say one short spoken acknowledgement — no tools this turn.' };\n if (!this.turnDispatched) return;\n if (call.name === 'TaskStatus')\n return { block: true, reason: 'You just dispatched a task this turn — do NOT poll. Give one short spoken acknowledgement and end your turn; the result arrives later as a [task …] event.' };\n if ((call.name === 'Act' || call.name === 'Think') && this.turnBriefs.has(String(call.args?.brief ?? '')))\n return { block: true, reason: 'You already dispatched this exact task — acknowledge briefly and end your turn.' };\n },\n };\n }\n\n /** The host spoke on this turn's behalf OUTSIDE the reflex stream (e.g. the voice engine's adaptive\n * micro-ack). For a DISPATCHED turn that's a sufficient ack (don't stack a second one); for an\n * inline turn whose reply came back empty it is NOT — \"One sec.\" followed by permanent silence is\n * still dead air, so silentTurn ignores external speech unless work was dispatched. */\n noteExternalSpeech(): void { this.externalSpeech = true; }\n\n /** True when the just-finished turn voiced NOTHING — dead air to repair. Two ways this happens:\n * (a) a dispatch with no spoken ack, and (b) an INLINE turn whose `final` channel came back empty —\n * gpt-oss harmony sometimes puts the whole reply in `analysis` (→ thinking_delta, suppressed in\n * voice) and emits an empty `final`, so no text_delta ever streams. Both ship silence; both repair.\n * Requires a host: without one there's no stream to detect speech on (and no one to speak to). */\n private get silentTurn(): boolean {\n const ackedByHost = this.externalSpeech && this.turnDispatched; // external ack only satisfies a dispatched turn\n return !!this.options.host && !this.spokeThisTurn && !ackedByHost && !this.heldThisTurn; // a Hold turn is intentionally silent — not dead air\n }\n\n /** A turn that voiced nothing is dead air. Re-prompt the reflex ONCE so the LLM itself voices a short\n * line (no template). If it STILL says nothing, fall back to a minimal line so silence never ships.\n * Wording adapts to whether work was dispatched (an ack) or the inline reply was simply lost. */\n private async ackIfSilent(fallback?: string): Promise<void> {\n const dispatched = this.turnDispatched;\n this.nudging = true;\n try {\n await this.voice.send(fallback\n ? '[reminder] You said nothing to the user this turn. Tell them, in ONE short spoken sentence, what just happened — no tools.'\n : dispatched\n ? '[reminder] You dispatched a task but said nothing to the user. Say ONE short spoken acknowledgement now — no tools.'\n : '[reminder] You said nothing to the user this turn. Give your ONE short spoken reply now — no tools.');\n } catch (e) {\n log.warn(`ack nudge failed: ${e instanceof Error ? e.message : e}`);\n } finally {\n this.nudging = false;\n }\n // If the reflex STILL voiced nothing, ship a fallback line so silence never reaches the user.\n // A caller-supplied fallback (e.g. a task failure) takes priority — that information must not be\n // swallowed. Small varied pools with no immediate repeat (a fixed line reads robotic when it recurs).\n if (!this.spokeThisTurn) {\n const pool = fallback ? [fallback] : dispatched ? DuplexAgent.FALLBACK_ACKS : DuplexAgent.FALLBACK_RETRY;\n const fresh = pool.filter((p) => p !== this.lastFallback);\n const line = (fresh.length ? fresh : pool)[Math.floor(Math.random() * (fresh.length || pool.length))];\n this.lastFallback = line;\n this.emitHost({ kind: 'text_delta', message: line });\n }\n }\n\n /** Dead-air fallback pools (see ackIfSilent). Both retry lines keep the 'say that again' phrase —\n * hosts/tests key on it. */\n private static readonly FALLBACK_ACKS = ['Okay, on it.', 'On it.', 'Alright, working on it.'];\n private static readonly FALLBACK_RETRY = ['Sorry, could you say that again?', 'Hm, I missed that — could you say that again?'];\n private lastFallback = '';\n\n /** One user turn: the voice agent streams the reply (and may Act/Think). Serialized with re-voice turns.\n * If a speculative reflex call is pending and this content CONFIRMS it (the final matches the\n * speculated partial), the in-flight call is adopted as THE turn: its buffered output flushes to the\n * host NOW (this is the latency win) and streaming continues live. Any other content aborts the\n * speculation first (rolled back silently) and runs a normal turn behind it. */\n send(content: MessageContent): Promise<RunResult> {\n // Auto-resume after a trivial barge: the user cut off a task delivery, then said something with NO\n // new request (\"sorry\", \"go on\") — resume the parked result instead of running an empty turn. Runs\n // before speculation so a filler partial that speculated is rolled back, not adopted.\n if (typeof content === 'string' && isTrivialBarge(content) && this.hasParkedDelivery()) {\n if (this.spec) this.abortSpeculation();\n return this.enqueue(async () => {\n this.resetTurn();\n // Already settled → speak it now; still running → arm the flag so it resumes on settle.\n if (!this.redeliverParked()) this.awaitTrivialRedeliver = true;\n return { text: '', steps: 0, finishReason: 'stop', messages: [] } as RunResult;\n });\n }\n const spec = this.spec;\n if (spec?.state === 'pending') {\n if (typeof content === 'string' && speculationConfirms(spec.text, content)) {\n spec.state = 'confirmed';\n spec.finalText = content;\n for (const ev of spec.buf.splice(0)) this.options.host?.notify?.(ev); // flush the held output NOW\n spec.decide('confirm');\n this.notify('diag', 'speculation_confirmed', { text: spec.text.slice(0, 80) }); // host diag sinks record it; UIs ignore 'diag'\n return spec.done;\n }\n this.abortSpeculation(); // divergent final (or non-text turn) — the normal turn queues behind the rollback\n }\n return this.enqueue(async () => {\n await this.initMemory();\n this.resetTurn();\n this.turn++;\n // Drop any pending auto-resume AND suppress a resume for deliveries that settle later (else a\n // much-later \"go on\" replays a stale result). The parked result still lives in the transcript\n // (folded at settle), so it stays recoverable by asking.\n this.awaitTrivialRedeliver = false;\n this.parkedRedeliver = [];\n this.suppressParkedResume = true;\n const res = await this.voice.send(content);\n this.flushHeldReflexTail();\n if (this.silentTurn) await this.ackIfSilent();\n return res;\n });\n }\n\n /** Start a HELD speculative reflex turn on a stable partial (VoiceEngine.onSpeculate). Its spoken\n * output buffers in emitHost; send() later confirms (flush + adopt) or aborts it. The turn holds the\n * voice mutex until that decision (bounded by a safety timeout), so no other turn can interleave\n * into the transcript between the speculative messages and their rollback. No-op if a speculation\n * is already in flight. */\n speculate(text: string): void {\n if (!text.trim() || this.spec) return;\n let decide!: (d: 'confirm' | 'abort') => void;\n const decision = new Promise<'confirm' | 'abort'>((r) => { decide = r; });\n const spec: NonNullable<DuplexAgent['spec']> = {\n text, state: 'pending', buf: [], ctl: new AbortController(), decide, decision, done: undefined as unknown as Promise<RunResult>,\n };\n this.spec = spec;\n spec.done = this.enqueue(async () => {\n const empty: RunResult = { text: '', steps: 0, finishReason: 'aborted', messages: this.voice.transcript };\n if (spec.state === 'aborted') { this.speculativeAbortedCalls++; if (this.spec === spec) this.spec = undefined; return empty; } // aborted before it ever started — nothing to roll back\n await this.initMemory();\n this.resetTurn();\n const base = this.voice.transcript.length;\n const prevSignal = this.voice.options.signal;\n this.voice.options.signal = spec.ctl.signal;\n let res: RunResult | undefined;\n try { res = await this.voice.send(spec.text); }\n catch (e) { log.warn(`speculative turn failed: ${e instanceof Error ? e.message : e}`); }\n finally { this.voice.options.signal = prevSignal; }\n // Stream done — await the endpoint decision. Bounded: a final that never dispatches (dropped by\n // an engine guard, mode change, …) must not wedge the voice queue behind a zombie speculation.\n const timer = setTimeout(() => { spec.state = spec.state === 'pending' ? 'aborted' : spec.state; spec.decide('abort'); }, 10_000);\n (timer as any).unref?.();\n const d = await spec.decision;\n clearTimeout(timer);\n if (d === 'abort') {\n // The speculation never happened: drop its output (emitHost already ate it), erase its messages\n // (the transcript must contain the FINAL text only — the real turn dispatches right behind us),\n // and count the spend.\n if (this.voice.transcript.length > base) this.voice.transcript.length = base;\n this.speculativeAbortedCalls++;\n log.verbose(`speculation aborted (${this.speculativeAbortedCalls} total): \"${spec.text.slice(0, 50)}\"`);\n if (this.spec === spec) this.spec = undefined;\n return res ?? empty;\n }\n // CONFIRMED — the transcript must carry what the user actually SAID (the final), not the partial.\n for (let i = base; i < this.voice.transcript.length; i++) {\n const m = this.voice.transcript[i];\n if (m.role === 'user' && contentText(m.content) === spec.text) { m.content = spec.finalText!; break; }\n }\n this.spec = undefined; // live from here (late emitHost stragglers pass straight through)\n this.flushHeldReflexTail();\n if (this.silentTurn) await this.ackIfSilent();\n return res ?? empty;\n });\n }\n\n /** Abort a pending speculation (idempotent): kill the in-flight call, drop its buffered output.\n * Called on divergence (send), a stale partial (VoiceEngine.onSpeculateAbort), a side-effect tool\n * attempt (dispatchGuard), or host paths that will never dispatch a final (commands, voice-off). */\n abortSpeculation(): void {\n const spec = this.spec;\n if (spec?.state !== 'pending') return;\n spec.state = 'aborted';\n spec.buf.length = 0;\n spec.ctl.abort();\n spec.decide('abort');\n this.notify('diag', 'speculation_aborted', { text: spec.text.slice(0, 80) });\n }\n\n /** Cancel a running background task — shared by the CancelTask tool and the CLI /tasks picker. */\n cancelTask(id: string): string {\n const rec = this.tasks.get(id);\n if (!rec) return `No task '${id}'.`;\n if (rec.status !== 'running') return `Task ${rec.id} is already ${rec.status}.`;\n rec.status = 'cancelled';\n rec.controller.abort();\n return `Task ${rec.id} (${rec.label}) cancelled.`;\n }\n\n /** Barge-in (or a dispatch-driven supersede): suppress running tasks' remaining SPOKEN delivery so a\n * superseded topic never talks over the new one (the debt-after-jokes regression). Tasks keep running and\n * still fold their result into the transcript — recoverable, just not spoken. Returns parked ids (logging).\n * Does NOT cancel. Two callers, two shapes:\n * - BARGE (default): the user interrupted AUDIO. Park EVERY running task (including this turn's) — the\n * worker they cut off must stop, whatever turn launched it — and re-arm trivial-barge auto-resume so a\n * following \"go on\" can bring the parked delivery back.\n * - SUPERSEDE (`priorTurnsOnly`, `reenableResume:false`, from dispatch()): a new dispatch redirected to\n * fresh work. Park only PRIOR-turn tasks so parallel siblings dispatched in the SAME turn don't silence\n * each other, and keep them suppressed (the user moved on — don't resurface on a stray \"go on\"). */\n parkInFlightDeliveries(reenableResume = true, priorTurnsOnly = false): string[] {\n if (reenableResume) this.suppressParkedResume = false;\n const parked: string[] = [];\n for (const rec of this.tasks.values())\n if (rec.status === 'running' && !rec.deliveryParked && (!priorTurnsOnly || rec.createdTurn < this.turn)) { rec.deliveryParked = true; parked.push(rec.id); }\n return parked;\n }\n\n /** True while there is a parked delivery to potentially resume: either one already settled (queued) or\n * one still running that was parked by a barge. */\n private hasParkedDelivery(): boolean {\n return this.parkedRedeliver.length > 0\n || [...this.tasks.values()].some((t) => t.status === 'running' && t.deliveryParked);\n }\n\n /** Speak any settled-and-queued parked delivery now (trivial-barge resume). Returns false if nothing was\n * queued yet (the caller then arms awaitTrivialRedeliver so the task resumes the instant it settles). */\n private redeliverParked(): boolean {\n if (!this.parkedRedeliver.length) return false;\n const text = this.parkedRedeliver.splice(0).join(' ').trim();\n if (text) {\n this.options.host?.notify?.({ kind: 'speak_utterance', message: text });\n this.notify('diag', 'parked_redelivered', { chars: text.length });\n }\n return true;\n }\n\n /** Resolve when all queued voice turns AND all in-flight worker tasks have settled (tests, graceful shutdown). */\n async idle(): Promise<void> {\n while (true) {\n const q = this.queue;\n await q.catch(() => {});\n await Promise.all([...this.tasks.values()].map((t) => t.promise));\n // a worker completion may have enqueued a re-voice turn meanwhile — loop until quiescent\n if (this.queue === q && ![...this.tasks.values()].some((t) => t.status === 'running')) return;\n }\n }\n\n /** Promise-chain mutex: turns run strictly one at a time; a failed turn doesn't poison the chain. */\n private enqueue<T>(fn: () => Promise<T>): Promise<T> {\n const run = this.queue.then(fn, fn);\n this.queue = run.then(() => {}, () => {});\n return run;\n }\n\n private notify(kind: string, message: string, data?: unknown): void {\n this.emitHost({ kind, message, data });\n }\n\n /** Host-boundary emit for the reflex's spoken channel: during a PENDING speculation, text_delta and\n * hold_filler are BUFFERED (nothing may reach TTS on unconfirmed input); confirm flushes them in\n * order, abort drops them silently. Everything else (task_* lifecycle, worker speak_utterance —\n * which bypasses this via host.notify directly) passes through untouched. */\n private emitHost(ev: { kind: string; message: string; data?: unknown }): void {\n const spec = this.spec;\n if (spec && (ev.kind === 'text_delta' || ev.kind === 'hold_filler')) {\n if (spec.state === 'pending') { spec.buf.push(ev); return; }\n if (spec.state === 'aborted') return; // an aborted speculation never speaks\n }\n this.options.host?.notify?.(ev);\n }\n\n /** Queue a `[task …]` event for re-voicing. Events arriving while the voice is busy coalesce into ONE turn.\n * `nonClean` (out-of-band boolean, set by the caller that KNOWS this event integrates a NON-CLEAN outcome)\n * marks the coalesced flush as a non-clean integration turn — turn-eligibility, never inferred from event\n * text and never keyed on a (re-authored) brief string. Any dispatch in such a turn is a follow-up. */\n private queueRevoice(event: string, nonClean = false): void {\n this.pendingEvents.push(event);\n if (nonClean) this.pendingNonClean = true;\n if (this.flushQueued) return;\n this.flushQueued = true;\n void this.enqueue(async () => {\n this.flushQueued = false; // events landing during this send() get their own flush turn\n const events = this.pendingEvents.splice(0);\n const nonCleanTurn = this.pendingNonClean;\n this.pendingNonClean = false;\n if (!events.length) return;\n // A failed task MUST be surfaced to the user, never silently swallowed (the reflex\n // sometimes voices nothing on a [task … failed] event). Derive a spoken fallback so the\n // silent-turn repair announces the failure instead of a generic \"could you say that again\".\n const failed = events.find((e) => /^\\[task\\b[^\\]\\n]*\\bfailed\\b/i.test(e));\n this.resetTurn();\n // Turn-eligibility (NOT brief-matching): this flush integrates ≥1 non-clean task, so ANY dispatch it\n // makes is an auto-follow-up. This is what makes runaway impossible — a paraphrased escalation still\n // lands here and is recognized. resetTurn cleared the flag, so set it AFTER reset.\n this.turnFollowUp = nonCleanTurn;\n await this.voice.send(events.join('\\n'));\n this.flushHeldReflexTail();\n if (this.silentTurn) await this.ackIfSilent(failed ? \"Sorry, that didn't work — the task failed.\" : undefined); // a re-voiced result that came back empty is dead air too\n\n // A re-voice turn ends OUTSIDE any host send() callsite — signal it so a line-buffered\n // renderer (CLI MarkdownStream) can flush its tail (else the last partial line is swallowed).\n this.notify('revoice_done', '');\n });\n }\n\n /** The worker's brief: the Act/Think args + a STATIC text snapshot of the recent conversation.\n * Act briefs get a self-verify footer — the worker's report is trusted without review, so it\n * must check its own work before reporting (nearly free under prompt caching; measured honest:\n * it does NOT fix one-shot logic bugs — see mind/10). Think tasks are pure reasoning — no footer. */\n private buildBrief(brief: string, tier: WorkerTier = 'act', deliver = true): string {\n const recent = this.voice.transcript\n .filter((m) => (m.role === 'user' || m.role === 'assistant') && contentText(m.content).trim())\n .slice(-this.options.excerptTurns)\n .map((m) => `${m.role}: ${contentText(m.content)}`)\n .join('\\n');\n const verify = tier === 'act'\n ? '\\n\\nBefore reporting done: re-read what you changed and check it against EVERY requirement above — fix any gap first. Your report is trusted without review.'\n : '';\n // DELIVER contract: the worker OWNS spoken delivery. Stated abstractly — NO concrete example\n // (this repo was burned by eval-fixture overfitting; teach the principle, not a fixture).\n const deliverContract = deliver ?\n '\\n\\n## DELIVER (spoken delivery)\\n' +\n 'You are reporting back to a user who is LISTENING. Stream your work normally — your prose is the written work record and detail, and is NOT spoken. ' +\n 'Wrap anything the user should HEAR in <spoken>…</spoken> tags. ' +\n 'LEAD WITH the actual content they asked for: if they asked for a specific piece of content — a value, a name, the actual lines, the writing itself — that content goes INSIDE the <spoken> tags, not a remark about it. ' +\n 'Your FIRST <spoken> segment is substantive — never a greeting or an acknowledgement (the front-end has already acked; do not double-ack). ' +\n 'Keep spoken text concise and natural for the ear: short sentences, no markdown. ' +\n 'NEVER enumerate in speech — no numbered or bulleted lists (\"One. … Two. …\" is robotic). Deliver multiple items as flowing conversation with brief connective phrasing (\"here\\'s one…\", \"and another…\", \"oh, and…\"), pausing between items with sentence breaks, not numbers.' +\n (this.options.emotionTags ? ' Inside <spoken>, you may prefix a sentence with an inline [emotion] tag (e.g. [excited], [curious]) to color how it is voiced — only when it genuinely fits, and vary it; [laughter] gives a natural laugh.' : '') : '';\n // Lead with fresh \"now\" so any search/computation is grounded to the current date — without it a\n // worker resolves \"recent\"/\"latest\" to a famous past instance (e.g. the 2022 World Cup instead of\n // the tournament happening this week). Recomputed here per dispatch, so it never goes stale.\n return `${nowLine()}.\\n\\n` + (recent ? `${brief}\\n\\n## Recent conversation (for context)\\n${recent}` : brief) + verify + deliverContract;\n }\n\n /** Spawn a detached worker for task `id`; its settlement notifies + enqueues the re-voice turn. */\n private spawnWorker(id: string, label: string, briefText: string, tier: WorkerTier, brief: string, followUp: boolean): void {\n const o = this.options;\n const tierOpts = tier === 'think' ? o.thinkOptions : o.actOptions;\n const tierModel = tier === 'think' ? (o.thinkModel as string) : o.actModel;\n const controller = new AbortController();\n const base = tierOpts?.hooks ?? o.actOptions?.hooks;\n const report = o.progressUpdates ? this.progressReporter(id) : undefined;\n // Rolling activity tail (always on, unlike the gated progress re-voicer) — backs /tasks inspection.\n const tail: string[] = [];\n const pushTail = (line: string) => { tail.push(line.slice(0, 200)); if (tail.length > 120) tail.splice(0, tail.length - 120); };\n const hooks = {\n ...base,\n preToolUse: async (call: ToolUse, meta?: any) => { const d = await base?.preToolUse?.(call, meta); pushTail(`⚙ ${describeCall(call)}`); report?.pre(call); return d; },\n postToolUse: async (call: ToolUse, result: string, meta?: any) => {\n await base?.postToolUse?.(call, result, meta);\n const last = result?.trim().split('\\n').filter(Boolean).pop();\n if (last) pushTail(` ↳ ${last}`);\n report?.post(call);\n },\n onToolOutput: (call: ToolUse, chunk: string, meta?: any) => { base?.onToolOutput?.(call, chunk, meta); report?.output(chunk); },\n };\n const relayAsk = async (q: { question: string; options?: Array<{ label: string }> }): Promise<string> => {\n const opts = q.options?.length ? ` Options: ${q.options.map((x) => x.label).join(', ')}.` : '';\n const a = await this.parkQuestion(id, `${q.question}${opts}`);\n return a || '(no answer from the user — use your best judgment and note the assumption)';\n };\n // The worker OWNS delivery: it streams `<spoken>…</spoken>` during its run. Split each text_delta —\n // spoken segments speak as a SEPARATE serialized utterance (speak_utterance) AND record into the\n // transcript/surfaced text (INDEPENDENTLY of whether the audio queue plays them — a barge-in can\n // drop the audio, but the spoken content must still land in context). detail → activity tail, never\n // spoken. `stream:true` is only meaningful with a host.notify (Agent requires it).\n const splitter = new SpokenSplitter();\n // Suppress audio once the user has barged in on this task (deliveryParked) — don't talk over the new\n // topic. The result still folds into the transcript at settle, so it's recoverable, just not spoken.\n const speak = (seg: string) => {\n if (!seg) return;\n const r = this.tasks.get(id);\n if (r) r.spokenText = (r.spokenText ? r.spokenText + ' ' : '') + seg; // accumulate for a possible parked-redeliver\n if (!r?.deliveryParked) o.host?.notify?.({ kind: 'speak_utterance', message: seg });\n };\n // Coalesce spoken text into COMPLETE sentences before emitting each as its own utterance — a worker on\n // a fragmenting model (cursor streams word-by-word deltas) would otherwise emit one utterance per word\n // (choppy TTS + one screen-echo line per word). flushSpoken() drains the partial when the stream ends.\n const coalescer = new SentenceCoalescer();\n const feedSpoken = (s: string) => { const ready = coalescer.feed(s); if (ready) speak(ready); };\n const flushSpoken = () => speak(coalescer.flush());\n const askBridge = o.askRelay ? { ask: relayAsk } : o.host?.ask ? { ask: (q: any) => o.host!.ask!(q) } : {};\n const workerHost: HostBridge = {\n ...askBridge,\n notify: (ev) => {\n if (ev?.kind === 'text_delta' && typeof (ev as any).message === 'string') {\n const { spoken, detail } = splitter.feed((ev as any).message);\n feedSpoken(spoken);\n if (detail.trim()) pushTail(detail.trim());\n return;\n }\n // non-stream worker events stay on the activity tail (never spoken)\n },\n };\n const agentOpts: Partial<AgentOptions> = {\n ai: o.ai,\n fs: o.fs,\n model: tierModel,\n ...(tier === 'think' ? { reasoning: tierOpts?.reasoning ?? 'high' } : {}),\n ...tierOpts,\n // Recompute providerOptions for THIS worker's model (after tierOpts so it wins over any inherited\n // main-template value) — prevents cursor-only cwd/cursorSession leaking onto an anthropic worker.\n providerOptions: o.providerOptionsFor?.(tierModel),\n stream: true, // worker streams text_delta so the splitter can extract <spoken> live (after tierOpts: never overridden off)\n host: workerHost, // carries BOTH ask AND the <spoken>-splitting notify\n ...(hooks ? { hooks } : {}),\n signal: controller.signal, // shared with the checker so a cancel tears down both\n };\n const promise = new Agent(agentOpts)\n .run(briefText)\n // Worker stream done: drain any dangling spoken text (unclosed <spoken> + the last partial sentence).\n .then((res) => { const { spoken, detail } = splitter.flush(); feedSpoken(spoken); if (detail.trim()) pushTail(detail.trim()); flushSpoken(); return res; })\n .then((res) => this.maybeVerify(id, brief, res, tier, agentOpts, askBridge))\n .then((res) => this.onWorkerSettled(id, res))\n .catch((err) => this.onWorkerFailed(id, err));\n this.tasks.set(id, { id, label, status: 'running', controller, promise, tail, brief, followUp, splitter, createdTurn: this.turn });\n // Evict oldest settled records past the cap (Map preserves insertion order) — running tasks stay.\n if (this.tasks.size > this.options.maxTaskRecords)\n for (const [tid, rec] of this.tasks) {\n if (this.tasks.size <= this.options.maxTaskRecords) break;\n if (rec.status !== 'running') this.tasks.delete(tid);\n }\n }\n\n /** Fresh-context check of a successful Act task: a NEW agent (same model/fs/tools, but NO shared\n * conversation context) re-reads the file state against the brief and fixes any gap. The fix lands\n * on the shared fs automatically (workers write fs directly, no overlay), so grading sees the\n * corrected state. Bounded to ONE pass. Off unless `verifyActTasks`; never runs for think/failed/\n * cancelled tasks. Usage is merged so /cost reflects the real (worker + checker) spend. */\n private async maybeVerify(id: string, brief: string, res: RunResult, tier: WorkerTier, agentOpts: Partial<AgentOptions>, askBridge: Partial<HostBridge>): Promise<RunResult> {\n if (!this.options.verifyActTasks || tier !== 'act' || res.finishReason !== 'stop') return res;\n if (this.tasks.get(id)?.status === 'cancelled') return res; // user stopped it — don't spend on a check\n // The checker is an INTERNAL fixer — it must NOT speak and must NOT touch the worker's SpokenSplitter.\n // So: (a) strip the DELIVER/<spoken> contract from the brief, and (b) run with a clean host that\n // carries ONLY `ask` (the historical pre-spoken-feature behavior) — never the spoken-forwarding\n // notify/splitter — and without `stream:true` (only meaningful for live <spoken> extraction).\n const { stream: _stream, host: _host, ...restOpts } = agentOpts;\n const checkerOpts: Partial<AgentOptions> = {\n ...restOpts,\n ...(askBridge.ask ? { host: { ask: askBridge.ask } } : {}),\n };\n const checkBrief = `${this.buildBrief(brief, tier, false)}\\n\\n## VERIFY MODE\\nAnother agent just implemented the above. Independently check the CURRENT state of the files against EVERY requirement. Fix any gap you find. If everything is already correct, make NO changes — do not refactor or improve — and report \"verified\".`;\n this.notify('task_verify', `task ${id}: verifying`, { id });\n const cres = await new Agent(checkerOpts).run(checkBrief);\n // Surface an inconclusive check (errored / hit a kill-switch) — don't let a failed verification\n // masquerade as a passed one. The worker's work still stands, so the task still completes with\n // the worker's report; we just flag that the check didn't cleanly finish.\n if (cres.finishReason !== 'stop') {\n log.warn(`task ${id}: verify inconclusive (${cres.finishReason})`);\n this.notify('task_verify', `task ${id}: verify inconclusive (${cres.finishReason})`, { id, finishReason: cres.finishReason });\n }\n const sum = (a = 0, b = 0) => a + b;\n return {\n ...res,\n steps: res.steps + cres.steps,\n // Merge the checker's messages so downstream tool-call/step accounting includes BOTH agents\n // (else a verified task's toolCalls would undercount vs its steps/usage).\n messages: [...res.messages, ...cres.messages],\n usageEstimated: res.usageEstimated || cres.usageEstimated,\n usage: res.usage && cres.usage ? {\n promptTokens: sum(res.usage.promptTokens, cres.usage.promptTokens),\n completionTokens: sum(res.usage.completionTokens, cres.usage.completionTokens),\n totalTokens: sum(res.usage.totalTokens, cres.usage.totalTokens),\n cacheCreationTokens: sum(res.usage.cacheCreationTokens, cres.usage.cacheCreationTokens),\n cacheReadTokens: sum(res.usage.cacheReadTokens, cres.usage.cacheReadTokens),\n } : (res.usage ?? cres.usage),\n };\n }\n\n /** Throttled per-task progress: worker tool calls → at most one progress re-voice per interval.\n * Two sources, one throttle: completed steps (post) and a heartbeat for a SINGLE long tool call\n * (pre records the in-flight call; a self-cleaning timer narrates \"still inside Bash — 70s\").\n * Completion supersedes: nothing is emitted once the task has settled. */\n private progressReporter(id: string): { pre: (call: ToolUse) => void; post: (call: ToolUse) => void; output: (chunk: string) => void } {\n let lastAt = Date.now();\n let steps = 0;\n let inflight: { call: ToolUse; at: number; tail: string } | null = null;\n const due = () => {\n if (this.pendingAsks.size) return undefined; // a question is pending — \"still working\" asides are noise (and wrong: it's WAITING)\n const rec = this.tasks.get(id);\n return rec && rec.status === 'running' && Date.now() - lastAt >= this.options.progressIntervalMs ? rec : undefined;\n };\n const emit = (rec: TaskRecord, line: string, call: ToolUse) => {\n lastAt = Date.now();\n this.notify('task_progress', `task ${id} (${rec.label}): ${line}`, { id, steps, call: call.name });\n this.queueRevoice(`[task ${id} progress] ${line}`);\n };\n const timer = setInterval(() => {\n const rec = this.tasks.get(id);\n if (!rec || rec.status !== 'running') return clearInterval(timer); // task settled — self-clean\n if (!inflight || !due()) return;\n // content-aware when the tool streams (ctx.emit → rolling tail): \"last output: 12 pass, 0 fail\"\n const last = inflight.tail.trim().split('\\n').filter(Boolean).pop()?.slice(-80);\n emit(rec, `still inside ${describeCall(inflight.call)} — ${Math.round((Date.now() - inflight.at) / 1000)}s on this step${last ? `, last output: ${last}` : ''}`, inflight.call);\n }, Math.max(this.options.progressIntervalMs, 250));\n (timer as any).unref?.(); // never hold the process open\n return {\n pre: (call) => { inflight = { call, at: Date.now(), tail: '' }; },\n output: (chunk) => { if (inflight) inflight.tail = (inflight.tail + chunk).slice(-500); }, // digest only — NEVER re-voices directly\n post: (call) => {\n steps++;\n inflight = null;\n const rec = due();\n if (rec) emit(rec, `still running — ${steps} steps so far, now: ${describeCall(call)}`, call);\n },\n };\n }\n\n /** Park a question under `askId` (a task id, or any unique key for permission asks): re-voices\n * '[task <id> asks] …' and resolves with the user's answer via AnswerTask — or '' on timeout/\n * task settle (callers map '' to deny / best-judgment). Workers never block forever. */\n parkQuestion(askId: string, question: string): Promise<string> {\n return new Promise((resolve) => {\n let settled = false;\n const finish = (answer: string) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n this.pendingAsks.delete(askId);\n resolve(answer);\n };\n const timer = setTimeout(() => {\n this.notify('task_ask_timeout', `task ${askId}: question timed out — proceeding without an answer`);\n finish('');\n }, this.options.askTimeoutMs);\n this.pendingAsks.set(askId, { question, resolve: finish });\n this.notify('task_ask', `task ${askId} asks: ${question}`, { id: askId, question });\n this.queueRevoice(`[task ${askId} asks] ${question}\\n(Relay this to the user in your own words. When they answer, call AnswerTask with id \"${askId}\" and their answer.)`);\n });\n }\n\n /** Resolve any question a settling/cancelled task left parked (its answer can no longer matter). */\n private dropAsk(id: string): void {\n this.pendingAsks.get(id)?.resolve('');\n }\n\n /** Build the INTEGRATION TURN prompt for a NON-CLEAN settled worker (early stop / failure). A clean\n * success never reaches here — it streams its own `<spoken>` delivery during the run. For a partial\n * or failed result the outcome re-enters the reflex as a decision (like a tool_result flowing back\n * into a normal agent loop): the reflex evaluates the outcome against the original intent and chooses\n * what to do next.\n *\n * Decision branches (the reflex acts on them with EXISTING tools — no new surface):\n * • accept → SPEAK the (partial) result plainly — don't dress a failure up as success.\n * • escalate → call `Think` with the SAME brief — only when Act failed/stalled AND a Think tier\n * exists AND this task wasn't already a follow-up (one hop max). Wires the dead\n * \"Reserve Think for a problem Act already FAILED at\" promise.\n * • re-delegate→ call `Act` with a CORRECTED brief — for a recoverable error / partial result.\n * • ask → ask the user ONE concrete question if genuinely blocked.\n *\n * Keeps the `[task <id> completed]` / `[task <id> failed]` opener so existing coalescing + the\n * failed-revoice fallback still fire, and the per-event transcript markers stay intact. */\n private integrationPrompt(rec: TaskRecord, outcome: 'incomplete' | 'error', body: string, finishReason: string): string {\n const opener = outcome === 'error' ? `[task ${rec.id} failed]` : `[task ${rec.id} completed]`;\n // Non-clean (early stop or error): give the reflex the decision. Cap auto-follow-up to one hop.\n // Hard absolute backstop ([[property 4]]): once the per-conversation auto-escalation budget is spent,\n // never offer escalate/re-delegate again — caps total escalations even if attribution ever misfires.\n const underCap = this.autoEscalations < DuplexAgent.MAX_AUTO_ESCALATIONS;\n const canEscalate = (outcome === 'error' || outcome === 'incomplete') && underCap;\n const hasThink = this.options.thinkModel !== false;\n const options: string[] = [];\n if (!rec.followUp && canEscalate && hasThink)\n options.push('ESCALATE to the Think tier (call Think with the same brief) if this is a hard/architectural problem the Act worker stalled or failed on');\n if (!rec.followUp && canEscalate)\n options.push('RE-DELEGATE to Act with a corrected brief if the failure looks recoverable (a wrong path, a fixable mistake)');\n options.push('ASK the user one short, concrete question if you genuinely cannot proceed without their input');\n options.push(\"ACCEPT and tell the user plainly what happened (don't dress a failure up as success)\");\n const decision = options.length > 1\n ? ` You must decide what to do next — choose ONE: ${options.map((o, i) => `(${i + 1}) ${o}`).join('; ')}. Pick exactly one and act on it; do not voice this as a finished success.`\n : ` Tell the user plainly what happened — do not present this as a finished success.`;\n const state = outcome === 'error'\n ? `the worker FAILED with: ${body}`\n : `the worker STOPPED EARLY (${finishReason}) — its result is PARTIAL, not a finished success: ${body}`;\n return `${opener} Original request: \"${rec.brief}\". Outcome: ${state}.${decision}`;\n }\n\n private onWorkerSettled(id: string, res: RunResult): void {\n this.dropAsk(id);\n const rec = this.tasks.get(id)!;\n if (res.finishReason === 'aborted' || rec.status === 'cancelled') {\n rec.status = 'cancelled';\n this.notify('task_cancelled', `task ${id} (${rec.label}) cancelled`);\n return; // the user asked to stop — don't narrate cancelled work\n }\n if (res.finishReason === 'error') {\n const msg = res.error instanceof Error ? res.error.message : String(res.error ?? 'unknown error');\n return this.failTask(rec, msg);\n }\n rec.status = 'done';\n rec.result = res.text;\n // A non-'stop' finish that isn't error/aborted (max_steps, timeout, loop, budget, max_tool_calls)\n // means the worker STOPPED EARLY — its result is partial, NOT a clean success. It must not be voiced\n // as if complete; the integration turn is told so it can escalate/re-delegate instead of accepting.\n // (`needs_input` also lands here, but only in a degenerate piped duplex: normally a worker always\n // has an `ask` — the voice relay, else the host's — so its question reaches the user as speech.)\n // `empty` (the Agent's own zero-work guard, 0cff9da) is NOT partial work stopped early — by\n // definition it's zero text + zero tools, i.e. the worker said nothing at all. That is exactly the\n // \"nothing to report\" case this duplex contract already treats as an acceptable clean finish (below);\n // routing it into the incomplete/re-voice path would pollute the transcript with a [task…] escalation\n // over silence instead of just letting the empty-result branch handle it.\n const incomplete = res.finishReason !== 'stop' && res.finishReason !== 'empty';\n log.verbose(`task ${id} done (${res.steps} steps${incomplete ? `, INCOMPLETE: ${res.finishReason}` : ''})`);\n // toolCalls = the worker's REAL tool-call count (a dispatch is not a tool call — consumers\n // comparing efficiency across agents need the worker's actual work, not the escalation count).\n this.notify('task_done', `task ${id} (${rec.label}) completed`, {\n id, text: res.text, usage: res.usage, usageEstimated: res.usageEstimated,\n finishReason: res.finishReason,\n steps: res.steps, toolCalls: res.messages.filter((m) => m.role === 'tool').length,\n });\n if (incomplete) {\n // A SUPERSEDED delivery (user moved to new work) must not hijack the voice on a partial result, nor\n // auto-escalate abandoned work over the new topic — fold the partial into the transcript (recoverable)\n // and stop, matching the clean-success suppression below.\n if (this.foldIfSuperseded(rec, res.text)) return;\n // Early stop → PARTIAL: keep the existing reflex revoice/decision path (escalate/re-delegate/ask).\n return this.queueRevoice(this.integrationPrompt(rec, 'incomplete', res.text, res.finishReason), true);\n }\n // Clean success: the worker ALREADY spoke its <spoken> segments during its run (no reflex re-voicing).\n // Parked (user barged in mid-task): suppress the remaining SPOKEN delivery — but still fold the full\n // result into the transcript so it's not lost (the reflex can surface it if the user asks).\n const tail = rec.splitter?.flush(); // drain any buffered partial tag (held across the last delta)\n if (tail?.spoken && !rec.deliveryParked) this.options.host?.notify?.({ kind: 'speak_utterance', message: tail.spoken });\n // (a) Fold the FULL result into the transcript as an assistant turn so the reflex can answer\n // follow-ups from context (replaces what voice.send did implicitly on the old revoice path).\n if (res.text.trim()) this.voice.transcript.push({ role: 'assistant', content: res.text });\n // (a2) Parked delivery (user barged mid-task): its audio was suppressed. Capture the spoken gist so a\n // trivial follow-up barge (\"sorry — go on\") can RESUME it. If a trivial barge already armed the\n // resume while this was running, speak it now; otherwise hold it for the next turn's decision.\n if (rec.deliveryParked && !this.suppressParkedResume) {\n const gist = (rec.spokenText ?? '').trim() || res.text.trim();\n if (gist) {\n if (this.awaitTrivialRedeliver) {\n this.awaitTrivialRedeliver = false;\n this.options.host?.notify?.({ kind: 'speak_utterance', message: gist });\n this.notify('diag', 'parked_redelivered', { chars: gist.length });\n } else this.parkedRedeliver.push(gist);\n }\n }\n // (b) No-spoken fallback: the worker emitted ZERO spoken segments → delivery would be silent.\n // Speak the gist as a one-shot enqueued utterance via the speak_utterance path. Skip if parked.\n if (!rec.splitter?.spokeAny && res.text.trim() && !rec.deliveryParked)\n this.options.host?.notify?.({ kind: 'speak_utterance', message: res.text });\n }\n\n private onWorkerFailed(id: string, err: unknown): void {\n this.failTask(this.tasks.get(id)!, err instanceof Error ? err.message : String(err));\n }\n\n /** A delivery the user has SUPERSEDED — parked AND moved on (suppressParkedResume, set by a redirect) —\n * must not hijack the voice when it settles late (partial or failed): that would talk over the new topic\n * and, worse, auto-escalate work the user already abandoned. Fold a recoverable note into the transcript\n * instead (the reflex can surface it if asked) and report true so the caller skips queueRevoice. A merely\n * barge-parked task (suppressParkedResume false — a \"go on\" may still resume it) is NOT superseded: it\n * keeps the normal surfacing path so a failure the user still cares about is not swallowed. */\n private foldIfSuperseded(rec: TaskRecord, note: string): boolean {\n if (!(rec.deliveryParked && this.suppressParkedResume)) return false;\n if (note.trim()) this.voice.transcript.push({ role: 'assistant', content: note });\n log.verbose(`task ${rec.id} settled but superseded (${rec.status}) — folded into transcript, not voiced`);\n return true;\n }\n\n private failTask(rec: TaskRecord, msg: string): void {\n this.dropAsk(rec.id);\n rec.status = 'error';\n rec.result = msg;\n log.warn(`task ${rec.id} failed: ${msg}`);\n this.notify('task_error', `task ${rec.id} (${rec.label}) failed: ${msg}`);\n // Superseded (user moved on): fold a note, don't hijack the new topic with a failure/escalation.\n if (this.foldIfSuperseded(rec, `The \"${rec.label}\" task failed: ${msg}`)) return;\n this.queueRevoice(this.integrationPrompt(rec, 'error', msg, 'error'), true);\n }\n\n // --- voice tools (closures over this instance) ---\n\n /** Live-switch the think tier: `false` disables (removes the Think tool from the voice agent),\n * a model id enables (adds the tool if missing). The system-prompt THINK_SLOT text is frozen at\n * construction — the tool's own description carries the routing guidance, so a live enable works;\n * dispatch()'s think→act fallback covers any straggler calls after a live disable. */\n setThinkModel(model: string | false): void {\n this.options.thinkModel = model;\n const tools = this.voice.options.tools as AgentTool[];\n const i = tools.findIndex((t) => t.name === 'Think');\n if (model === false && i >= 0) tools.splice(i, 1);\n else if (model !== false && i < 0) tools.push(this.thinkTool());\n }\n\n /** User/programmatic spawn: the CLI's /act and /think commands. Returns the task id.\n * `followUp` marks an automatic escalation/re-delegation (set by the integration turn) so the new\n * task's own integration turn won't escalate again — capping auto-follow-ups to one hop. */\n async dispatch(brief: string, tier: WorkerTier = 'act', label?: string, followUp = false): Promise<string> {\n if (tier === 'think' && this.options.thinkModel === false) tier = 'act';\n if (followUp) this.autoEscalations++; // spend from the hard absolute escalation budget ([[property 4]])\n // A new dispatch = the user redirected to fresh actionable work. Park deliveries still running from a\n // PRIOR turn so a superseded worker can't speak its <spoken> over the new topic when it settles (session\n // 1d93c6d3: a mis-heard search talked over the corrected one). Prior-turn only (createdTurn < this.turn),\n // so parallel tasks dispatched in the SAME turn don't silence each other, and a pure conversational turn\n // that dispatches nothing leaves running deliveries intact. reenableResume:false keeps the superseded\n // delivery suppressed rather than resurfacing on a stray \"go on\".\n this.parkInFlightDeliveries(false, true);\n const id = `t${++this.seq}`;\n const lbl = label ?? tier;\n await this.options.onTaskStart?.(id, lbl);\n this.spawnWorker(id, lbl, this.buildBrief(brief, tier), tier, brief, followUp);\n this.notify('task_started', `task ${id} (${lbl}) started`, { id, brief, tier });\n return id;\n }\n\n private actTool(): AgentTool {\n return {\n name: 'Act',\n description:\n 'Escalate real work (reading/editing files, searching, running tasks, building) to a standard background worker. ' +\n 'Returns immediately with a task id; the result arrives later as a \"[task <id> completed]\" event. ' +\n 'Provide a clear, self-contained `brief` (the worker does not hear the live conversation).',\n parameters: {\n type: 'object',\n required: ['brief'],\n properties: {\n brief: { type: 'string', description: 'full, self-contained instructions for the worker' },\n label: { type: 'string', description: 'a short (2-4 word) label for the task' },\n },\n },\n run: async ({ brief, label }) => {\n this.spokeBeforeDispatch = this.spokeThisTurn; // speech before the dispatch WAS the ack — don't stack another\n this.turnDispatched = true;\n this.turnBriefs.add(String(brief ?? ''));\n // Turn-terminal: force the NEXT reflex step to be text-only (the spoken ack), so a weak model\n // can't keep polling TaskStatus and emit a redundant ack each step. Cleared by resetTurn.\n this.voice.options.toolChoice = 'none';\n const id = await this.dispatch(String(brief ?? ''), 'act', label ? String(label) : undefined, this.turnFollowUp);\n return this.spokeBeforeDispatch\n ? `Acting on task ${id}. You already acknowledged — end your turn now with NO further text; the result will arrive as a [task ${id} completed] event.`\n : `Acting on task ${id}. Acknowledge briefly; the result will arrive as a [task ${id} completed] event.`;\n },\n };\n }\n\n private thinkTool(): AgentTool {\n return {\n name: 'Think',\n description:\n 'Escalate to a premium deep-reasoning agent for complex analysis, architecture decisions, hard debugging, or planning. ' +\n 'Same async pattern as Act — returns a task id. Use when the problem needs careful thought before (or instead of) action. ' +\n 'Do not use Think for simple tasks — Act is cheaper and faster.',\n parameters: {\n type: 'object',\n required: ['brief'],\n properties: {\n brief: { type: 'string', description: 'the question or problem to reason about deeply' },\n label: { type: 'string', description: 'a short (2-4 word) label for the task' },\n },\n },\n run: async ({ brief, label }) => {\n this.spokeBeforeDispatch = this.spokeThisTurn; // speech before the dispatch WAS the ack — don't stack another\n this.turnDispatched = true;\n this.turnBriefs.add(String(brief ?? ''));\n // Turn-terminal: force the NEXT reflex step to be text-only (the spoken ack), so a weak model\n // can't keep polling TaskStatus and emit a redundant ack each step. Cleared by resetTurn.\n this.voice.options.toolChoice = 'none';\n const id = await this.dispatch(String(brief ?? ''), 'think', label ? String(label) : undefined, this.turnFollowUp);\n return this.spokeBeforeDispatch\n ? `Thinking on task ${id}. You already acknowledged — end your turn now with NO further text; the result will arrive as a [task ${id} completed] event.`\n : `Thinking on task ${id}. Acknowledge briefly; the result will arrive as a [task ${id} completed] event.`;\n },\n };\n }\n\n private taskStatusTool(): AgentTool {\n return {\n name: 'TaskStatus',\n description: 'Status of background tasks. Pass `id` for one task, or omit it to list all.',\n parameters: { type: 'object', properties: { id: { type: 'string' } } },\n run: async ({ id }) => {\n const list = id ? [this.tasks.get(String(id))].filter(Boolean) as TaskRecord[] : [...this.tasks.values()];\n if (!list.length) return id ? `No task '${id}'.` : 'No background tasks.';\n return list.map((t) => `${t.id} (${t.label}): ${t.status}`).join('\\n');\n },\n };\n }\n\n /** Sub-100ms read-only lookups the voice may do itself — everything else stays Act-only.\n * fs-only (no shell; the engine is VFS-abstracted): time, git branch (.git/HEAD read), ls, file\n * head. Output is hard-capped so a lookup can never bloat the skinny voice context. */\n private quickLookTool(): AgentTool {\n const CAP = 2000; // chars — a \"peek\", not a Read\n const kinds = [...new Set(['time', 'branch', 'ls', 'file', 'capabilities', ...Object.keys(this.options.quickLook ?? {})])];\n return {\n name: 'QuickLook',\n description:\n `Instant read-only lookup — one of: ${kinds.join(', ')}. ` +\n 'For trivial facts only; anything needing search, commands, or reasoning goes through Act.',\n parameters: {\n type: 'object',\n required: ['what'],\n properties: {\n what: { type: 'string', enum: kinds, description: 'what to look up' },\n path: { type: 'string', description: 'for ls/file: the path to look at' },\n },\n },\n run: async ({ what, path }) => {\n const fs = this.options.fs;\n try {\n const over = this.options.quickLook?.[String(what)];\n if (over) return await over(path ? String(path) : undefined);\n switch (String(what)) {\n case 'capabilities': {\n // CC-style self-introspection: report the worker's REAL tools so the reflex can\n // answer \"can you…?\" by looking, not guessing. Generalized — no capability hard-coded.\n const actTools = (this.options.actOptions?.tools ?? []) as AgentTool[];\n const names = actTools.map((t) => t.name);\n // MCP servers reach an autonomous worker (cursor/*) via providerOptions, NOT as actTools —\n // so without this the reflex underreports (e.g. denies browser control it actually has).\n const mcpServers = Object.keys((this.options.actOptions?.providerOptions as any)?.mcpServers ?? {});\n const mcpNote = mcpServers.length\n ? ` Plus MCP servers your worker can use: ${mcpServers.join(', ')} (e.g. browser-bridge → drive a real browser: open tabs, navigate, click, screenshot).`\n : '';\n if (!names.length)\n return 'Your worker uses Act\\'s default local toolset (reading/editing files, running shell ' +\n 'commands). No extra tools (e.g. web/internet) are configured; if a request is not a ' +\n 'basic file or shell operation, assume you can\\'t do it and say so.' + mcpNote;\n // Each tool stands on its own — the reflex must resolve a request to the RIGHT one.\n // The trap: it conflates three distinct web capabilities. Spell them apart so it neither\n // overclaims (WebFetch ≠ search) nor underclaims (a browser CAN reach a search engine).\n const hasFetch = names.some((n) => /WebFetch/i.test(n));\n const hasBrowser = names.some((n) => /browser.*(navigate|click|page|type)/i.test(n));\n const hasSearch = names.some((n) => /(^|_)WebSearch$|search/i.test(n) && !/WebFetch|browser/i.test(n));\n const notes: string[] = [];\n if (hasFetch) notes.push('WebFetch retrieves ONE specific URL you are given — it is not a search engine.');\n if (hasBrowser) notes.push('The browser tools drive a real browser: you CAN open a site and, if needed, navigate to a search engine and search there — but it is manual and takes a moment, not an instant lookup.');\n else if (!hasSearch && hasFetch) notes.push('You have no general web-search tool, so for an instant \"search the web\" you can only fetch a URL they provide.');\n const webNote = notes.length ? ' NOTE: ' + notes.join(' ') : '';\n return `Tools your background worker (Act) can actually use: ${names.join(', ')}. ` +\n 'Read each name literally and match the request to a SPECIFIC tool; if none fits, you do NOT have ' +\n 'that ability — say so honestly.' + webNote + mcpNote;\n }\n case 'time':\n return new Date().toString();\n case 'branch': {\n if (!fs) return 'unavailable (no filesystem)';\n const head = (await fs.readFile('.git/HEAD')).trim();\n return head.startsWith('ref: refs/heads/') ? `branch: ${head.slice('ref: refs/heads/'.length)}` : `detached HEAD at ${head.slice(0, 12)}`;\n }\n case 'ls': {\n if (!fs) return 'unavailable (no filesystem)';\n const p = String(path ?? '.');\n try {\n const names = await fs.readDir(p);\n return names.slice(0, 50).join('\\n') + (names.length > 50 ? `\\n… (+${names.length - 50} more)` : '');\n } catch {\n // The reflex often passes the cwd's OWN name (\"linkedin\" while already in …/linkedin →\n // …/linkedin/linkedin, not found). Never fail the turn (live: the reflex then asked the\n // user for a path — bad UX) — fall back to the cwd listing with a note.\n const names = await fs.readDir('.').catch(() => [] as string[]);\n return `'${p}' not found here — you are likely already inside it. Current directory listing:\\n` +\n names.slice(0, 50).join('\\n') + (names.length > 50 ? `\\n… (+${names.length - 50} more)` : '');\n }\n }\n case 'file': {\n if (!fs) return 'unavailable (no filesystem)';\n if (!path) return 'file lookup needs a path';\n try {\n const text = await fs.readFile(String(path));\n return text.length > CAP ? text.slice(0, CAP) + `\\n… (truncated — ${text.length} chars total; Act for the full file)` : text;\n } catch {\n const names = await fs.readDir('.').catch(() => [] as string[]);\n return `'${path}' not found. Current directory contains:\\n` + names.slice(0, 50).join('\\n');\n }\n }\n default:\n return `unknown lookup '${what}'`;\n }\n } catch (e: any) {\n return `lookup failed: ${e?.message ?? e}`;\n }\n },\n };\n }\n\n private answerTaskTool(): AgentTool {\n return {\n name: 'AnswerTask',\n description: 'Relay the user\\'s answer to a pending question from a background task (the \"[task <id> asks]\" events). Pass the id from the event and the user\\'s answer.',\n parameters: {\n type: 'object',\n required: ['id', 'answer'],\n properties: { id: { type: 'string' }, answer: { type: 'string', description: \"the user's answer, verbatim or faithfully summarized\" } },\n },\n run: async ({ id, answer }) => {\n const ask = this.pendingAsks.get(String(id));\n if (!ask) return `No pending question for '${id}' — it may have been answered already or timed out.`;\n ask.resolve(String(answer ?? ''));\n return `Answer relayed — task ${id} resumes.`;\n },\n };\n }\n\n private holdTool(): AgentTool {\n return {\n name: 'Hold',\n description:\n 'The user seems mid-thought — hold the turn (stay listening) instead of answering. ' +\n 'Optionally pass a short filler (\"mhm\", \"go on\") to speak while waiting. Use when the ' +\n 'message sounds incomplete, trailing off, or like they paused to think.',\n parameters: {\n type: 'object',\n properties: {\n filler: { type: 'string', description: 'optional short filler to speak (\"mhm\", \"go on\", \"mm-hm\")' },\n },\n },\n run: async ({ filler }) => {\n this.heldThisTurn = true; // enforce silence mechanically — the weak reflex ignores \"do not respond\" and emits \"…\"\n // Always notify (even with no filler): the host must cancel any pending adaptive micro-ack —\n // a Hold turn is INTENTIONALLY silent, an ack would read as the start of an answer.\n this.notify('hold_filler', filler ? String(filler) : '');\n return 'Holding — listening for the rest of the user\\'s thought. Do not respond further this turn.';\n },\n };\n }\n\n private cancelTaskTool(): AgentTool {\n return {\n name: 'CancelTask',\n description: 'Cancel a running background task by id.',\n parameters: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } },\n run: async ({ id }) => this.cancelTask(String(id)),\n };\n }\n}\n","/**\n * Pluggable component logger. The extracted engine/providers log through\n * `forComponent(name)`; by default that's a console logger gated by DEBUG (env\n * or localStorage). A host (e.g. agentx) routes voice logs into its own logging\n * by calling `configureLogging(hostForComponent)` once at boot.\n *\n * `forComponent` returns a stable proxy that re-resolves the backend per call,\n * so a `configureLogging` after module load still takes effect on loggers that\n * were captured at import time (`const log = forComponent('X')`).\n */\n\nexport interface Logger {\n debug(...args: unknown[]): void;\n verbose(...args: unknown[]): void;\n info(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n}\n\nexport type ForComponent = (name: string) => Logger;\n\n/** Console backend. debug/verbose are gated per-component via DEBUG:\n * env `DEBUG=Name` (or `*`) on server, `localStorage.DEBUG` in browser. */\nfunction consoleForComponent(name: string): Logger {\n const debugEnv =\n (typeof process !== 'undefined' && process.env?.DEBUG) ||\n (typeof localStorage !== 'undefined' && localStorage.getItem('DEBUG')) ||\n '';\n const gated = debugEnv === '*' || debugEnv.split(',').some((p) => p.trim() === name);\n const gate = (fn: (...a: unknown[]) => void) => (gated ? fn : () => {});\n const tag = `[${name}]`;\n return {\n debug: gate((...a) => console.debug(tag, ...a)),\n verbose: gate((...a) => console.debug(tag, ...a)),\n info: (...a) => console.info(tag, ...a),\n warn: (...a) => console.warn(tag, ...a),\n error: (...a) => console.error(tag, ...a),\n };\n}\n\nlet backend: ForComponent = consoleForComponent;\n\n/** Route all voice-mode logs through a host logger (call once at boot). */\nexport function configureLogging(forComponentImpl: ForComponent): void {\n backend = forComponentImpl;\n}\n\n/** Component-scoped logger. Stable across `configureLogging` (re-resolves per call). */\nexport function forComponent(name: string): Logger {\n return {\n debug: (...a) => backend(name).debug(...a),\n verbose: (...a) => backend(name).verbose(...a),\n info: (...a) => backend(name).info(...a),\n warn: (...a) => backend(name).warn(...a),\n error: (...a) => backend(name).error(...a),\n };\n}\n","/**\n * Emotion control for Cartesia TTS — the model emits inline `[emotion]` tags before a sentence\n * (para-chat avatar pattern); we normalize them to Cartesia's supported set and rewrite them as\n * `<emotion value=\"…\"/>` in the spoken transcript. sonic-3 stitches the prosody server-side, so a\n * tag simply rides inline with the words it precedes; `forSpeech()` leaves it intact.\n *\n * Two surfaces:\n * • renderEmotions() — stateless, for a COMPLETE string (worker utterance echo).\n * • EmotionStream — stateful, for the live delta stream (buffers a partial `[…` across chunk\n * boundaries and hugs a pending tag onto the NEXT prose so the tag never goes out word-less —\n * a tag-only transcript would produce no audio and stall the TTS drain).\n */\nimport { forComponent } from './logging';\n\nconst log = forComponent('Emotion');\n\n/** Cartesia sonic-3 emotion vocabulary (primary + extended). Source of truth for normalization\n * AND for the tag list taught to the model — keep the prompt and the parser in lockstep. */\nexport const EMOTIONS = [\n // primary (best results)\n 'neutral', 'angry', 'excited', 'content', 'sad', 'scared',\n // extended\n 'happy', 'enthusiastic', 'elated', 'triumphant', 'amazed', 'surprised', 'flirtatious',\n 'curious', 'calm', 'grateful', 'affectionate', 'sympathetic', 'mysterious', 'frustrated',\n 'disgusted', 'sarcastic', 'disappointed', 'hurt', 'guilty', 'bored', 'tired', 'nostalgic',\n 'apologetic', 'hesitant', 'confused', 'anxious', 'panicked', 'proud', 'confident', 'skeptical',\n 'contemplative', 'determined',\n // remaining sonic-3 vocabulary — without these a valid model tag would be DROPPED (flat delivery).\n 'joking', 'trust', 'anticipation', 'outraged', 'threatened', 'contempt', 'envious',\n 'dejected', 'rejected', 'wistful', 'insecure', 'resigned', 'distant',\n] as const;\n\nconst VALID = new Set<string>(EMOTIONS);\n\n/** Friendly synonyms → a canonical Cartesia emotion, so the model isn't tripped by exact spelling. */\nconst ALIASES: Record<string, string> = {\n cheerful: 'happy', joyful: 'happy', joy: 'happy', glad: 'happy', pleased: 'happy', warm: 'affectionate',\n thrilled: 'excited', eager: 'enthusiastic', ecstatic: 'elated', euphoric: 'elated',\n mad: 'angry', furious: 'angry', annoyed: 'frustrated', irritated: 'frustrated', agitated: 'frustrated',\n shocked: 'surprised', astonished: 'amazed', wonder: 'amazed',\n worried: 'anxious', nervous: 'anxious', afraid: 'scared', alarmed: 'panicked',\n unsure: 'hesitant', uncertain: 'hesitant', doubtful: 'skeptical', suspicious: 'skeptical',\n thoughtful: 'contemplative', focused: 'determined', serious: 'determined',\n playful: 'flirtatious', teasing: 'flirtatious', ironic: 'sarcastic', cheeky: 'sarcastic',\n thankful: 'grateful', sorry: 'apologetic', down: 'sad', melancholic: 'sad', gloomy: 'sad',\n peaceful: 'calm', serene: 'calm', relaxed: 'calm', sleepy: 'tired',\n comedic: 'joking', // Cartesia lists \"joking/comedic\" as one — canonicalize to joking\n};\n\n/** Non-verbal cues Cartesia takes verbatim as bracket tags — pass through, never eaten as an emotion. */\nconst NONVERBAL: Record<string, string> = { laughter: 'laughter', laughs: 'laughter', laugh: 'laughter', laughing: 'laughter' };\n\n/** Normalize a raw tag word to a canonical Cartesia emotion, or null if unmappable. */\nexport function normalizeEmotion(raw: string): string | null {\n const k = raw.trim().toLowerCase();\n if (VALID.has(k)) return k;\n return ALIASES[k] ?? null;\n}\n\n/** Resolve a `[…]` inner word to what should be spoken (`emotion`/`laughter`) — or null to drop it. */\nfunction resolveTag(raw: string): { kind: 'emotion'; value: string } | { kind: 'nonverbal'; value: string } | null {\n const k = raw.trim().toLowerCase();\n if (NONVERBAL[k]) return { kind: 'nonverbal', value: NONVERBAL[k] };\n const e = normalizeEmotion(k);\n return e ? { kind: 'emotion', value: e } : null;\n}\n\n/** A `[word]` (or `[two words]`) bracket tag — letters/spaces only, so array indices / code never match. */\nconst TAG_RE = /\\[([a-zA-Z][a-zA-Z ]{0,24})\\]/g;\n/** A trailing run that could still GROW into a tag (`[exc`) — held back until the next chunk. */\nconst PARTIAL_RE = /\\[[a-zA-Z ]*$/;\n\nexport interface EmotionRender {\n /** transcript for TTS — recognized tags rewritten as Cartesia inline tags */\n speech: string;\n /** on-screen echo — original `[tag]` kept when `show`, stripped otherwise */\n display: string;\n /** spoken words only, all tags removed (echo-discrimination + interrupted-reply text) */\n prose: string;\n}\n\nconst cartesiaTag = (t: { kind: string; value: string }): string =>\n t.kind === 'nonverbal' ? `[${t.value}]` : `<emotion value=\"${t.value}\"/>`;\n\n/** Rewrite a COMPLETE string's `[tag]`s. Stateless — safe only when no tag straddles the input edge\n * (true for whole worker utterances). For the streaming delta path use EmotionStream. */\nexport function renderEmotions(text: string, opts: { show: boolean } = { show: true }): EmotionRender {\n let speech = '', display = '', prose = '', last = 0;\n TAG_RE.lastIndex = 0;\n for (let m = TAG_RE.exec(text); m; m = TAG_RE.exec(text)) {\n const before = text.slice(last, m.index);\n speech += before; display += before; prose += before;\n const tag = resolveTag(m[1]);\n if (tag) {\n speech += cartesiaTag(tag);\n if (opts.show) display += m[0];\n } else {\n log.debug(`dropping unknown emotion tag ${m[0]}`);\n }\n last = m.index + m[0].length;\n }\n const tail = text.slice(last);\n return { speech: speech + tail, display: display + tail, prose: prose + tail };\n}\n\n/**\n * Streaming emotion parser. `feed(delta)` returns the spans completed by this chunk; a recognized tag\n * is stashed and PREPENDED to the next non-empty prose (Cartesia wants the tag right before its words,\n * and a tag-only continuation would synthesize nothing → drained-but-silent stall). A trailing `[…`\n * that is still a viable tag prefix is buffered until it completes or the stream flushes.\n */\nexport class EmotionStream {\n private buf = '';\n private pending: { kind: string; value: string } | null = null;\n constructor(public show = true) {}\n\n feed(delta: string): EmotionRender { this.buf += delta; return this.drain(false); }\n flush(): EmotionRender { return this.drain(true); }\n\n private drain(final: boolean): EmotionRender {\n let body = this.buf;\n // Hold back a trailing run that could still grow into a tag — unless this is the final flush.\n if (!final) {\n const p = body.match(PARTIAL_RE);\n if (p) { this.buf = p[0]; body = body.slice(0, body.length - p[0].length); }\n else this.buf = '';\n } else this.buf = '';\n\n let speech = '', display = '', prose = '', last = 0;\n TAG_RE.lastIndex = 0;\n for (let m = TAG_RE.exec(body); m; m = TAG_RE.exec(body)) {\n this.emit(body.slice(last, m.index), (s, d, p) => { speech += s; display += d; prose += p; });\n const tag = resolveTag(m[1]);\n if (tag) { this.pending = tag; if (this.show) display += m[0]; }\n else log.debug(`dropping unknown emotion tag ${m[0]}`);\n last = m.index + m[0].length;\n }\n this.emit(body.slice(last), (s, d, p) => { speech += s; display += d; prose += p; });\n return { speech, display, prose };\n }\n\n /** Emit a prose span, flushing any pending tag onto its FRONT (only once real words appear). */\n private emit(text: string, sink: (s: string, d: string, p: string) => void): void {\n if (!text) return;\n let speech = text;\n // Hug the tag onto the first span carrying actual WORDS (not bare punctuation/space) — a tag-only or\n // tag+punctuation transcript synthesizes no audio and would stall the TTS drain.\n if (this.pending && /[\\p{L}\\p{N}]/u.test(text)) { speech = cartesiaTag(this.pending) + text; this.pending = null; }\n sink(speech, text, text);\n }\n}\n","/**\n * VoiceEngine — the portable voice-conversation brain: state machine (idle|listening|thinking|\n * speaking), barge-in policy (AEC-trivial + heuristic echo tier), gapless TTS turn handoff,\n * utterance merge window, interrupted-reply tracking, ack echo-leak guard.\n *\n * Pure logic over three injected seams (STT, TTS, AudioSink) — runs in CLI, server, or browser.\n * Hosts wire `onUtterance` to their dispatch and feed `beginSpeech()/speakDelta()/endSpeech()`;\n * `interrupt()` is the barge-in primitive. Behavior validated live; see mind/11-voice.md.\n */\nimport { forComponent } from './logging';\nimport { EmotionStream } from './emotion';\nimport type { AudioSink, VoiceState } from './types';\n\nconst log = forComponent('VoiceEngine');\n\n/** Injectable time source — ALL engine timing (merge windows, barge grace, overlap resume, drain\n * settles) routes through it. Defaults to real timers; the deterministic bench swaps a virtual\n * clock so timing scenarios run instantly and exactly. */\nexport interface EngineClock {\n now(): number;\n setTimeout(fn: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n}\nexport const realClock: EngineClock = {\n now: () => performance.now(),\n setTimeout: (fn, ms) => setTimeout(fn, ms),\n clearTimeout: (h) => clearTimeout(h as ReturnType<typeof setTimeout>),\n};\n\n/** One structured diagnostic event (fire-and-forget, never affects behavior). `t` = engine clock ms.\n * Emitted at every DECISION point; kinds + fields are the per-session forensic record\n * (CLI: `<session>.voice.jsonl`; lab: `<session>.timeline.jsonl`). See mind/11-voice.md §Diagnostics. */\nexport interface DiagEvent { t: number; kind: string; [k: string]: unknown }\n\n/** Sanitize text for the spoken channel (and its on-screen echo). Drops markdown punctuation TTS would\n * read aloud (\"star\"/\"hash\"), turns em/en dashes and table pipes into spoken pauses, normalizes \"30 %\"\n * → \"30%\", and collapses filler dot-runs (\"now.....\" → \"now.\"). Per-delta safe: every map is local to\n * the chunk (single chars / line-anchored), so chunk boundaries never split a multi-char span. */\nexport const forSpeech = (t: string): string =>\n t.replace(/[*`#]+/g, '')\n // underscores: strip only EMPHASIS pairs (_word_ at word boundaries) — intra-word underscores are\n // real content (EXPORT_PLAYBOOK.txt, .DS_Store) and must survive in both speech and echo\n .replace(/(?<![\\p{L}\\p{N}])_([^_\\n]+)_(?![\\p{L}\\p{N}])/gu, '$1')\n .replace(/^[ \\t]*[-•]\\s+/gm, '') // leading list marker\n .replace(/\\s*[\\u2013\\u2014]\\s*/g, ', ') // en/em dash → spoken pause (prompt forbids dashes in speech)\n .replace(/[\\u2010\\u2011]/g, '-') // (non-breaking) hyphen → plain hyphen (TTS reads \"8-12\" fine)\n .replace(/\\s*\\|\\s*/g, ', ') // table pipe → pause\n .replace(/(\\d)\\s+%/g, '$1%') // \"30 %\" → \"30%\" (else \"thirty space percent\")\n .replace(/\\.{3,}/g, '.'); // filler dot-run → single period\n\nconst normWord = (w: string): string => w.toLowerCase().replace(/[^a-z0-9]/g, '');\n\n/** Trailing extra words the final may add WITHOUT changing what the reflex must answer — politeness/\n * discourse fillers only. Any CONTENT word (\"…very short\" + \"joke\") means the speculation answered a\n * truncated thought and must abort (live-confirmed quality bug: prosodic-pause partials). */\nconst SPEC_TRAILING_OK = new Set(['please', 'thanks', 'thank', 'you', 'now', 'okay', 'ok', 'kindly', 'alright', 'then', 'though', 'right', 'yeah']);\n\n/** Does the endpointed FINAL confirm a SPECULATED partial? Exact normalized match, or the speculation\n * is a word-prefix of the final with ≤2 trailing extra NON-CONTENT words (SPEC_TRAILING_OK — the\n * speculated words must all land; the last one may be a char-prefix of its final counterpart, a\n * mid-word partial). The same prefix shape as refinalizes(), applied host-side to decide\n * confirm-vs-abort of a speculative reflex call. */\nexport function speculationConfirms(spec: string, final: string): boolean {\n const sw = spec.trim().split(/\\s+/).map(normWord).filter(Boolean);\n const fw = final.trim().split(/\\s+/).map(normWord).filter(Boolean);\n if (!sw.length || fw.length < sw.length || fw.length > sw.length + 2) return false;\n for (let i = 0; i < sw.length - 1; i++) if (sw[i] !== fw[i]) return false;\n if (!fw[sw.length - 1].startsWith(sw[sw.length - 1])) return false;\n for (let i = sw.length; i < fw.length; i++) if (!SPEC_TRAILING_OK.has(fw[i])) return false;\n return true;\n}\n\n/** Structural contracts (satisfied by SonioxSTT/CartesiaTTS or test fakes). */\nexport interface SttLike {\n usingAec: boolean;\n onPartial: (text: string) => void;\n onUtterance: (text: string, endpointAt: number) => void;\n onLevel: (rms: number) => void;\n /** Optional: unrecoverable capture failure (e.g. mic produced no audio) — host tears voice down. */\n onFatal?: (message: string) => void;\n start(): Promise<void> | void;\n reset(): void;\n stop(): void;\n}\nexport interface TtsLike {\n onAudio: (chunk: Uint8Array) => void;\n onDone: () => void;\n /** Optional word-timestamp seam for karaoke reveal (revealMode==='word'). `start[i]` = seconds\n * from turn-audio start. Set `wantTimestamps` to request them from the provider. */\n onTimestamps?: (words: string[], start: number[]) => void;\n wantTimestamps?: boolean;\n connect(): Promise<void> | void;\n /** Optional: prime the synthesis pipeline right after connect (throwaway context, audio discarded)\n * so the FIRST real turn doesn't pay the provider's cold-synthesis spin-up. */\n warmup?(): void;\n newContext(): string;\n speak(text: string, cont: boolean): void;\n end(): void;\n cancel(): void;\n close(): void;\n}\n\nexport class VoiceEngineOptions {\n stt!: SttLike;\n tts!: TtsLike;\n player!: AudioSink;\n /** a final utterance arrived (endpoint) — host dispatches it as a turn */\n onUtterance: (text: string) => void = () => {};\n /** live partial transcript while listening (host renders the 🎤 line) */\n onPartial: (text: string) => void = () => {};\n onState: (s: VoiceState) => void = () => {};\n /** user spoke/acted over playback — host aborts the in-flight turn (called AFTER audio is killed).\n * phase: 'speaking' = cut mid-speech (real interruption); 'drain' = in the final audio tail\n * (normal turn-taking — hosts shouldn't alarm). */\n onBargeIn: (phase: 'speaking' | 'drain') => void = () => {};\n /** spoken micro-ack on utterance endpoint (masks LLM TTFT); '' disables */\n ackPhrase = '';\n /** ADAPTIVE micro-ack: on an utterance-dispatched turn, speak a short varied ack ONLY if no reflex\n * delta has arrived after this many ms (masks a slow TTFT without acking every turn — a fixed\n * per-turn ack was rejected as robotic). First delta / interrupt / hold cancels it. 0 = off. */\n adaptiveAckMs = 0;\n /** the adaptive ack actually fired (host can mark the turn as spoken — e.g. suppress dead-air repair) */\n onAdaptiveAck: () => void = () => {};\n /** Endpoint merge window (ms): hold an endpointed utterance briefly — if speech resumes (spelled\n * letters, mid-thought pauses), the next utterance MERGES instead of dispatching a truncated one\n * (\"E-L-Y.\" / \"A.\"). Costs this much latency per turn; 0 disables. */\n utteranceMergeMs = 350;\n /** Extended merge window (ms) for utterances that look incomplete (trailing conjunction/filler).\n * Gives the user time to finish their thought without triggering a model call. */\n incompleteMergeMs = 1500;\n /** Grace window (ms) after an utterance dispatches, during which the user's own trailing audio cannot\n * barge the reply it requested. Soniox keeps finalizing partials past <end>; without this they read\n * as a barge and abort the fresh turn (live: mid-sentence self-interruption + steps=1→steps=0 double\n * abort). Short enough that a genuine immediate barge (\"no wait—\") still lands right after. */\n bargeGraceMs = 600;\n /** Barge-in (talk over the assistant to interrupt). true = full-duplex (needs echo cancellation, or\n * the assistant's own TTS bleeds back and self-interrupts). false = HALF-DUPLEX: the engine is deaf\n * while audible (speaking + drain tail), so echo can never become a phantom turn — the right mode\n * when there's no AEC (e.g. the non-VPIO mic fallback) and no headphones. Cost: can't interrupt. */\n bargeIn = true;\n /** Filler phrase spoken when holding for an incomplete utterance ('' disables). */\n holdFiller = '';\n /** Called when the engine holds an incomplete utterance (host can render a visual cue). */\n onHold: () => void = () => {};\n /** heuristic (non-AEC) energy barge-in tuning */\n bargeRmsMult = 2;\n bargeRmsFloor = 500;\n /** Overlap turn-taking (AEC tier, needs player.pause/resume) — human phone-call model, driven by\n * the STT ITSELF (a trained speech classifier) instead of energy thresholds (energy could not\n * separate residue bursts from speech in every room — hiccup whack-a-mole): a GENUINE partial\n * (novel words dominate — echo of our own reply is inert) while speaking → PAUSE (exact-sample\n * hold); partial grows into dominant-novel ≥2 words → cede (interrupt; the LLM re-enters); partial\n * stalls/endpoints without ceding (backchannel by DURATION, not vocabulary) → resume + drop. false disables. */\n overlapPause = true;\n /** no new partial activity for this long while paused → resume, drop the interjection */\n overlapResumeMs = 700;\n /** A genuine barge over a LONG reply is defeated by the dominant-novel gate: Meet echoes our own\n * speech back, so the partial is mostly our words + a few of hers → never \"dominant novel\" → it\n * resumes (replaying old audio — the audible \"completes the buffer\" blip) instead of ceding.\n * Mechanism-based discriminator: a re-PAUSE this soon after a resume = a persistent human, not an\n * echo blip (which pauses once and stalls). Cede on the re-pause regardless of the novel gate. */\n overlapRepauseCedeMs = 1500;\n /** Speculative ENERGY pre-pause while speaking (AEC tier): two residue gate-passes within 350ms →\n * pause ~300ms before the STT tokens land. But energy CANNOT separate residue bursts from speech\n * (the documented whack-a-mole) — so a residue spike during loud playback false-pauses with NO user\n * speech at all, an audible hiccup. Default OFF: the genuine-gated STT partial is the\n * mechanism-correct pause trigger; enable only if barge-in onset feels sluggish in a clean-AEC room. */\n overlapEnergyHold = false;\n /** SPECULATIVE REFLEX START (the root TTFT fix): a partial transcript that has stopped changing for\n * this many ms AND carries ≥ speculativeMinWords is \"stable\" — `onSpeculate` fires so the host can\n * start the reflex EARLY, ~endpoint+merge (500-850ms) before the final would dispatch. The\n * speculative call's output is HELD by the host (nothing reaches TTS) until the endpointed final\n * confirms it (see speculationConfirms). At most one speculation per turn-in-progress. 0 = off. */\n speculativeMs = 0;\n /** Minimum word count for a partial to qualify as a speculation trigger. */\n speculativeMinWords = 4;\n /** A stable partial (speculativeMs) — the host starts a HELD speculative reflex call. */\n onSpeculate: (text: string) => void = () => {};\n /** AGENT-SIDE BACKCHANNELING (rule-based v1): while LISTENING to a long multi-clause user turn, a\n * partial that reaches a clause boundary (trailing [,.;!?] or conjunction/filler) and then stays\n * UNCHANGED for this many ms (a micro-pause — before the silence endpoint fires) triggers a short\n * quiet TTS blip (\"Mm-hm.\") on a throwaway context. ZERO floor-claim: no state change, no timers\n * touched, no turn context — audio passes a narrow gate bypass and a real turn supersedes it via\n * context rotation. Latin-predominant partials only (Hebrew/mixed text never misfires — the\n * boundary/conjunction heuristics are English-tuned, so non-Latin turns simply get no blips).\n * 0 = off (default). ~200-300 recommended: live, Soniox's SEMANTIC endpoint (<end>) lands within\n * ~300-400ms of a clause pause — a longer stability window loses the race and never fires. */\n backchannelMs = 0;\n /** Min gap between blips (rate limit); additionally max 2 blips per user turn-in-progress. */\n backchannelMinGapMs = 8000;\n /** Only multi-clause turns: the partial must carry at least this many words before a blip. */\n backchannelMinWords = 8;\n /** A backchannel blip was spoken (host renders a timeline event; the blip is NOT a reply). */\n onBackchannel: (phrase: string) => void = () => {};\n /** The partial outgrew the speculated text (user kept talking) — the host aborts the speculation\n * quietly (the endpointed final will also refuse to confirm; this just stops the billing earlier). */\n onSpeculateAbort: () => void = () => {};\n /** Map inline `[emotion]` tags (emitted by the model, prompt-taught) into Cartesia inline emotion\n * tags in the spoken transcript (sonic-3 stitches the prosody). false = strip them silently. */\n emotions = true;\n /** Show the `[emotion]` tags in the on-screen echo (debug). false = hide (spoken-only). */\n showEmotions = false;\n /**\n * Progressive text reveal — the \"karaoke\" capability, opt-in.\n * 'off' — no reveal events (CLI default; the host renders text however it likes).\n * 'delta' — emit `onReveal(fullText)` as each spoken delta lands (near-free; text grows\n * in step with the model stream).\n * 'word' — reveal word-by-word synced to the TTS playback CLOCK (true karaoke). Requires a\n * timestamp-emitting TTS (CartesiaTTS.wantTimestamps) driven over `AudioSink.playedMs`.\n */\n revealMode: 'off' | 'delta' | 'word' = 'off';\n /** Called with the cumulative revealed text for the current assistant turn (see `revealMode`).\n * Reset to '' at the start of each spoken turn. */\n onReveal: (revealed: string) => void = () => {};\n /** Time source for every engine timer/timestamp. Default: real time (identical behavior). */\n clock: EngineClock = realClock;\n /** Structured diagnostic event at every decision point (state transitions, dispatch/drop paths,\n * barge-in, overlap pause/resume, acks, speculation, backchannels, echo swallows). Fire-and-forget:\n * a throwing handler is caught once and diagnostics disable — engine behavior is never affected. */\n onDiag: (ev: DiagEvent) => void = () => {};\n}\n\nexport class VoiceEngine {\n public options: VoiceEngineOptions;\n public state: VoiceState = 'idle';\n protected stt: SttLike;\n protected tts: TtsLike;\n protected player: AudioSink;\n private speaking = false; // audible (deltas flowing OR audio draining)\n private ctxOpen = false; // the current TTS context still accepts deltas (false once end-frame sent)\n private interrupted = false; // barge-in latch: drop in-flight deltas until the next legitimate turn\n private spokeDeltas = false; // a TTS context is open for the current spoken turn\n private revealText = ''; // cumulative revealed (on-screen) text for the current turn — see revealMode\n // 'word' karaoke reveal: spoken-word start times (sec, absolute from turn-audio start) + poll state.\n private wordStarts: number[] = [];\n private revealedN = 0;\n private revealPoll: unknown = null;\n private clock: EngineClock;\n private drainTimer: unknown = null;\n // heuristic tier state (inert under AEC) — frozen as validated in the experiment\n private echoWords = new Set<string>();\n private prevReply = '';\n private reply = '';\n private echoUntil = 0;\n private baseline = 0;\n private hot = 0;\n private suspectUntil = 0;\n private ackAt = 0; // when the micro-ack was spoken — its echo can leak before the AEC filter converges\n private lastAck = ''; // the exact ack text last spoken (fixed OR adaptive) — the echo-leak guard matches it\n private ackTimer: unknown = null; // one-shot adaptive-ack timer (armed at dispatch, cancelled on first delta)\n // The adaptive micro-ack ALREADY spoke this turn → the reflex's own leading ack (\"Still on it.\") is now\n // redundant (live: host said \"On it.\" then the reflex said \"Still on it.\"). While this is set, speakDelta\n // probes the reflex's opening sentence and DROPS it if it's purely an acknowledgement; real content passes\n // through. Reset per turn in beginSpeech()/interrupt().\n private adaptiveAckFired = false;\n private ackProbe: string | null = null; // buffered reflex prose while probing the leading ack (null = not probing)\n private bargeGraceUntil = 0; // no barge-in until this time — the user's OWN trailing audio (after the\n // utterance that JUST dispatched this turn) must not immediately re-interrupt the reply it requested.\n private pendingUtt = ''; // endpointed text held for the merge window\n private mergePath: 'direct' | 'merged' = 'direct'; // how the pending utterance was assembled (diag)\n private lastGraceDiag = 0; // grace_suppress emitted once per grace window\n private pendingTimer: unknown = null;\n // Duplicate-final guard: STT sometimes re-finalizes the SAME audio a beat later (past the merge\n // window) — the identical utterance dispatched twice with no reply in between (live: \"When you\n // start\" twice). Conservative: only an IDENTICAL (normalized) text, within dupFinalMs, with zero\n // reply deltas since the first dispatch, is dropped. A user genuinely repeating themselves after\n // the agent replied (or after 3s) still dispatches.\n private lastDispatchFlat = '';\n private lastDispatchWords: string[] = [];\n private lastDispatchAt = 0;\n private repliedSinceDispatch = false;\n private static readonly DUP_FINAL_MS = 3000;\n private lastInterrupted: { full: string; heard: string } | null = null;\n // overlap (pause) tier state — AEC + pause-capable sinks only\n private pausedAt = 0;\n private lastResumeAt = 0; // when the overlap last resumed from a false alarm — a quick re-pause cedes\n private lastOverlapPartial = ''; // change-detection: only NEW partial text counts as activity\n private resumeTimer: unknown = null;\n private turnStartAt = 0; // timestamp when the current turn began (for TTFT logging)\n // speculative reflex trigger state (options.speculativeMs) — see trackSpeculation\n private specPartial = ''; // last partial observed (stability = unchanged for speculativeMs)\n private specTimer: unknown = null;\n private specText = ''; // text handed to onSpeculate ('' = no speculation in flight)\n private specSpent = false; // at most one speculation per turn-in-progress\n // backchannel blip state (options.backchannelMs) — see trackBackchannel\n private bcPartial = ''; // last partial observed (stability = unchanged for backchannelMs)\n private bcTimer: unknown = null;\n private bcCount = 0; // blips this user turn-in-progress (max 2; reset at dispatch)\n private bcActive = false; // NARROW audio-gate bypass: blip audio may reach the sink while listening\n private bcActiveTimer: unknown = null; // safety: clear the bypass even if the blip's 'done' is lost\n private lastBcAt = 0;\n private lastBcPhrase = ''; // exact blip text last spoken — flushUtterance strips its mic echo\n private recentBc: string[] = [];\n // Central speech queue (above the TTS context): complete worker utterances serialize into ONE\n // playback stream, one-at-a-time, never splicing into the live reflex's open utterance.\n private uttQueue: string[] = [];\n // Per-turn emotion-tag parser (reset on beginSpeech) — converts `[emotion]` → Cartesia inline tags\n // for TTS, tracks tag-free prose for echo discrimination, and surfaces display text for the screen.\n private emo: EmotionStream | null = null;\n\n constructor(options?: Partial<VoiceEngineOptions>) {\n this.options = { ...new VoiceEngineOptions(), ...options };\n const o = this.options;\n if (!o.stt || !o.tts || !o.player) throw new Error('VoiceEngine needs stt, tts and player (see cli/voice.ts VoiceIO for platform defaults)');\n this.stt = o.stt;\n this.tts = o.tts;\n this.player = o.player;\n this.clock = o.clock;\n }\n\n async start(): Promise<void> {\n // `speaking` gates real-turn audio; `bcActive` is the ONLY other pass — a backchannel blip's\n // throwaway context, allowed through while listening (unlike warmup, whose audio this gate drops).\n this.tts.onAudio = (c) => { if (this.speaking || this.bcActive) this.player.write(c); };\n // Karaoke reveal: ask the TTS for word timestamps and accumulate them for the playback-synced poll.\n if (this.options.revealMode === 'word') {\n this.tts.wantTimestamps = true;\n this.tts.onTimestamps = (_words, start) => {\n if (this.interrupted) return;\n for (const s of start) this.wordStarts.push(s);\n };\n }\n this.stt.onPartial = (text) => this.handlePartial(text);\n this.stt.onUtterance = (text) => this.handleUtterance(text);\n this.stt.onLevel = (rms) => this.handleLevel(rms);\n await Promise.all([this.tts.connect(), this.stt.start()]);\n // Pre-warm at mic-on: prime the TTS synthesis pipeline (throwaway context; any audio it returns\n // is dropped by the `speaking` gate above / stale-context filter) so the first real turn doesn't\n // pay the provider's cold-synthesis spin-up (~1s+ live on Cartesia).\n this.tts.warmup?.();\n this.setState('listening');\n log.debug(`voice I/O up (${this.stt.usingAec ? 'AEC' : 'heuristic echo'} capture)`);\n }\n\n get usingAec(): boolean {\n return this.stt.usingAec;\n }\n\n /** Flip barge-in at runtime (e.g. the mic fell back to non-VPIO → go half-duplex so echo can't leak). */\n setBargeIn(on: boolean): void { this.options.bargeIn = on; }\n\n /** Show/hide the `[emotion]` debug tags in the echo (next turn's stream picks it up). */\n setShowEmotions(on: boolean): void { this.options.showEmotions = on; }\n\n /** Diagnostics tap (options.onDiag). Fire-and-forget: a throwing handler disables the tap once —\n * it can NEVER perturb engine behavior. Protected so VoiceIO can route provider events through it. */\n private diagOn = true;\n protected diag(kind: string, fields?: Record<string, unknown>): void {\n if (!this.diagOn) return;\n try { this.options.onDiag({ t: this.clock.now(), kind, ...fields }); }\n catch (e) { this.diagOn = false; log.debug(`onDiag threw — diagnostics disabled: ${e instanceof Error ? e.message : e}`); }\n }\n\n private idleWaiters: (() => void)[] = [];\n private setState(s: VoiceState): void {\n if (this.state === s) return;\n this.diag('state', { from: this.state, to: s });\n this.state = s;\n this.options.onState(s);\n if (s !== 'speaking' && s !== 'thinking') {\n for (const r of this.idleWaiters.splice(0)) r();\n }\n }\n\n /** Resolve when the engine is no longer speaking (immediate if already idle). */\n awaitIdle(): Promise<void> {\n if (this.state !== 'speaking' && this.state !== 'thinking') return Promise.resolve();\n return new Promise((r) => this.idleWaiters.push(r));\n }\n\n // --- speaking side (host-driven) ---\n\n /** open a spoken turn (idempotent — safe from both onUtterance and first-delta paths).\n * `ack` speaks the configured micro-ack as the context opener (utterance path only —\n * masks LLM TTFT; re-voice turns begun by their first delta skip it). */\n beginSpeech(ack = false): void {\n if (this.speaking && this.ctxOpen) return;\n if (this.drainTimer) { this.clock.clearTimeout(this.drainTimer); this.drainTimer = null; }\n this.interrupted = false; // a new turn re-arms speech\n this.bcSupersede(); // a real turn mid-blip: close the audio bypass; newContext() below rotates the\n // ctx so Cartesia's stale-context filter drops any blip stragglers, and markTurn cuts the tail.\n // gapless handoff: a new turn while the previous one's audio drains keeps the SAME player\n // (markTurn would cut the tail) and just opens a fresh TTS context — Cartesia rejects deltas\n // on an ended context (\"Context closed\" 400, narration silently lost).\n this.resetOverlap(true); // a held pause must release — gapless handoff keeps the same player (no FLUSH)\n this.diag('tts_turn_begin', { ack, gapless: this.speaking });\n if (!this.speaking) this.player.markTurn();\n this.speaking = true;\n this.ctxOpen = true;\n this.spokeDeltas = false;\n this.adaptiveAckFired = false; this.ackProbe = null; // fresh turn — no ack fired yet, don't probe\n this.reply = '';\n this.revealText = '';\n this.wordStarts = [];\n this.revealedN = 0;\n if (this.options.revealMode === 'word') this.startWordReveal();\n this.emo = this.options.emotions ? new EmotionStream(this.options.showEmotions) : null;\n this.echoWords = new Set(this.words(this.prevReply)); // previous reply's echo may still be in flight\n this.tts.newContext();\n this.clearAckTimer('new_turn'); // a fresh turn supersedes any armed ack from a previous one\n if (ack && this.options.ackPhrase) {\n this.diag('ack_fired', { phrase: this.options.ackPhrase, adaptive: false });\n this.tts.speak(this.options.ackPhrase + ' ', true);\n this.spokeDeltas = true; this.ackAt = this.clock.now(); this.lastAck = this.options.ackPhrase;\n for (const w of this.words(this.options.ackPhrase)) this.echoWords.add(w); // ack is OUR audio — its echo must not read as novel speech\n }\n // Adaptive micro-ack: arm a one-shot timer — a short varied ack speaks ONLY if the reflex is still\n // silent when it fires (slow TTFT); the reply then continues the same TTS context. First delta\n // cancels it (fast turns stay ack-free); interrupt/endSpeech/hold cancel too.\n else if (ack && this.options.adaptiveAckMs > 0) {\n this.ackTimer = this.clock.setTimeout(() => {\n this.ackTimer = null;\n if (!this.speaking || !this.ctxOpen || this.spokeDeltas || this.interrupted) return;\n const phrase = this.pickAck();\n this.diag('ack_fired', { phrase, adaptive: true, waitedMs: this.options.adaptiveAckMs });\n this.tts.speak(phrase + ' ', true);\n this.spokeDeltas = true;\n this.ackAt = this.clock.now();\n this.lastAck = phrase;\n for (const w of this.words(phrase)) this.echoWords.add(w); // ack is OUR audio — its echo must not read as novel speech\n this.setState('speaking'); // ack audio is playing — don't sit in \"thinking\" while audibly speaking\n this.adaptiveAckFired = true; this.ackProbe = ''; // the reflex's own leading ack is now redundant — probe + drop it\n this.options.onAdaptiveAck();\n }, this.options.adaptiveAckMs);\n }\n // TTFT is stamped at the real turn start (flushUtterance, when the user's utterance dispatches);\n // only fall back to here for a re-voice turn that has no preceding utterance.\n if (!this.turnStartAt) this.turnStartAt = this.clock.now();\n this.setState('thinking');\n }\n /** Feed a spoken delta. Returns the on-screen echo text (emotion tags shown/hidden per config) so the\n * host renders the SAME stream that was parsed for TTS — no second, state-doubling parse. */\n speakDelta(text: string): string {\n // After a barge-in the aborted turn's stream may keep delivering (re-voice turns have no abort\n // signal) — those deltas must NOT re-open speech. endSpeech()/beginSpeech() clear the latch.\n if (this.interrupted) return '';\n this.clearAckTimer('first_delta'); // the reflex spoke in time — no ack needed\n // Leading-ack suppression: the adaptive micro-ack already spoke, so the reflex's own opening\n // acknowledgement is a duplicate. Buffer its first sentence; drop it if it's purely an ack, else\n // release everything untouched. Only the FIRST sentence is probed — real content always survives.\n if (this.adaptiveAckFired && this.ackProbe !== null) {\n this.ackProbe += text;\n const probe = this.ackProbe;\n const bare = probe.replace(/\\[emotion[^\\]]*\\]/gi, '').replace(/^\\s+/, '');\n const m = bare.match(/^([^.!?…\\n]*[.!?…\\n])([\\s\\S]*)$/); // leading sentence + remainder\n if (!m && bare.length < 80) return ''; // no boundary yet and still short — wait for more\n this.ackProbe = null; this.adaptiveAckFired = false; // decision made for this turn\n const lead = (m ? m[1] : bare);\n const norm = lead.replace(/[^a-z ]/gi, ' ').replace(/\\s+/g, ' ').trim().toLowerCase();\n if (VoiceEngine.ACK_LEADING.test(norm)) {\n const rest = m ? m[2] : '';\n this.diag('reflex_ack_suppressed', { lead: lead.trim() });\n if (!rest.trim()) return ''; // the whole reply was an ack → nothing left to speak\n text = rest; // speak only the content after the redundant ack\n } else {\n text = probe; // not an ack — release the buffered prose verbatim\n }\n }\n if (!this.speaking || !this.ctxOpen) this.beginSpeech();\n // Split the delta into spoken transcript (Cartesia emotion tags inline), tag-free prose (echo\n // discrimination), and screen-echo display. The stream buffers a tag split across chunk boundaries.\n let { speech, display, prose } = this.emo ? this.emo.feed(text) : { speech: text, display: text, prose: text };\n // Boundary-space repair: some models emit consecutive sentence deltas with no separating space\n // (\"…Israel.\" + \"Anything else?\") — the join renders AND speaks as \"Israel.Anything\". If the\n // forwarded prose so far ends in sentence punctuation and this delta starts immediately with an\n // uppercase letter, insert the missing space. Uppercase-only on purpose: \"3.\" + \"5\" (a split\n // decimal) must NOT gain a space.\n if (this.reply && /[.!?…]$/.test(this.reply) && /^[A-Z]/.test(prose)) { speech = ' ' + speech; display = ' ' + display; prose = ' ' + prose; }\n this.reply += prose;\n if (prose.trim()) this.repliedSinceDispatch = true; // an agent reply arrived — a later identical final is a genuine repeat\n for (const w of this.words(this.reply)) this.echoWords.add(w);\n this.tts.speak(forSpeech(speech), true); // strip markdown punctuation so TTS doesn't read \"dash\"/\"star\"/\"hash\" aloud\n if (!this.spokeDeltas && this.turnStartAt) log.debug(`ttft: ${Math.round(this.clock.now() - this.turnStartAt)}ms`);\n this.spokeDeltas = true;\n this.setState('speaking');\n // Progressive reveal (opt-in). 'delta' fires per-delta with the growing on-screen text; 'word'\n // accumulates the text here but reveals via the playback-synced poll (startWordReveal).\n if (this.options.revealMode !== 'off' && display) {\n this.revealText += display;\n if (this.options.revealMode === 'delta') this.options.onReveal(this.revealText);\n }\n return display;\n }\n /** Karaoke reveal poll: reveal the display-word prefix up to the count of spoken words whose\n * Cartesia start time has been reached on the playback clock (`AudioSink.playedMs`, which excludes\n * paused time). Poll-driven (not AudioContext timers) so it's portable across CLI/browser sinks and\n * deterministic under the virtual clock. */\n private startWordReveal(): void {\n if (this.revealPoll) return;\n const tick = () => {\n this.revealPoll = null;\n if (!this.speaking || this.interrupted || this.options.revealMode !== 'word') return;\n const playedSec = this.player.playedMs() / 1000;\n let n = this.revealedN;\n while (n < this.wordStarts.length && this.wordStarts[n]! <= playedSec) n++;\n if (n !== this.revealedN) {\n this.revealedN = n;\n const words = this.revealText.trim().split(/\\s+/).filter(Boolean);\n this.options.onReveal(words.slice(0, n).join(' '));\n }\n this.revealPoll = this.clock.setTimeout(tick, 60);\n };\n this.revealPoll = this.clock.setTimeout(tick, 60);\n }\n /** Stop the poll. `finalFlush` reveals the whole line once audio has finished, so a timing\n * undershoot never leaves the tail unrevealed (skipped after a barge-in — the truncated prefix\n * is what was actually spoken). */\n private stopWordReveal(finalFlush: boolean): void {\n if (this.revealPoll) { this.clock.clearTimeout(this.revealPoll); this.revealPoll = null; }\n if (finalFlush && this.options.revealMode === 'word' && !this.interrupted) {\n const full = this.revealText.trim();\n if (full) this.options.onReveal(full);\n }\n }\n /** close the spoken turn (idempotent); stays audible until ALL audio arrived AND playback drains */\n endSpeech(): void {\n this.interrupted = false; // the interrupted turn is over — next turn may speak\n this.clearAckTimer('turn_end'); // turn is over — a late ack would speak into the drain\n // A leading-ack probe still holding (short reply, no terminal punctuation): decide now so its content\n // isn't swallowed. If the held prose is purely an ack, drop it; otherwise speak it before the turn closes.\n const heldProbe = this.ackProbe;\n this.adaptiveAckFired = false; this.ackProbe = null; // always clear at turn end — no stale probe into the next turn\n if (heldProbe) {\n const norm = heldProbe.replace(/\\[emotion[^\\]]*\\]/gi, '').replace(/[^a-z ]/gi, ' ').replace(/\\s+/g, ' ').trim().toLowerCase();\n if (VoiceEngine.ACK_LEADING.test(norm)) this.diag('reflex_ack_suppressed', { lead: heldProbe.trim() });\n else this.speakDelta(heldProbe); // real content held with no boundary — release it now\n }\n if (!this.speaking) return;\n this.diag('tts_turn_end', { spoke: this.spokeDeltas, replyChars: this.reply.length });\n this.ctxOpen = false; // context ends now; audio keeps draining\n // Flush any tail the emotion parser held back (a dangling `[…` partial, or a pending tag) so the\n // last words aren't swallowed; the real audio flush is tts.end()'s cont=false below.\n if (this.emo) { const t = this.emo.flush(); this.emo = null; if (t.prose) this.reply += t.prose; if (t.speech) this.tts.speak(forSpeech(t.speech), true); }\n if (this.reply) this.prevReply = this.reply;\n // remain 'speaking' (barge-in armed, echo discrimination active) until audio actually finishes\n const settle = () => {\n if (this.ctxOpen) { this.drainTimer = null; return; } // a newer turn took over the player — it settles\n if (this.pausedAt) { this.drainTimer = this.clock.setTimeout(settle, 250); return; } // held by an overlap — not finished audibly\n this.drainTimer = null;\n this.speaking = false;\n this.stopWordReveal(true); // audio finished — reveal any unrevealed tail\n if (this.turnStartAt) log.debug(`turn: ${Math.round(this.clock.now() - this.turnStartAt)}ms (incl. playback)`);\n this.echoUntil = this.clock.now() + 2500; // tail echo (capture+network+finalization) outlives playback\n if (!this.usingAec) this.stt.reset(); // drop echo residue (AEC: keep — it can only be the user)\n this.setState('listening');\n if (this.uttQueue.length) this.pumpQueue(); // next queued worker utterance plays after this one fully ends\n };\n const drainThenSettle = () => {\n if (this.drainTimer) this.clock.clearTimeout(this.drainTimer);\n this.drainTimer = this.clock.setTimeout(settle, this.player.drainMs() + 300);\n };\n if (this.spokeDeltas) {\n // the LLM turn is over but the TTS is still synthesizing — wait for ALL chunks (onDone)\n // before the drain countdown, else drainMs() undercounts and the reply's tail is dropped.\n this.tts.onDone = drainThenSettle;\n this.tts.end();\n // safety net: if 'done' never arrives (ws drop), settle after a generous ceiling\n if (this.drainTimer) this.clock.clearTimeout(this.drainTimer);\n this.drainTimer = this.clock.setTimeout(drainThenSettle, 15_000);\n } else drainThenSettle();\n }\n /** text of the reply cut by the last barge-in — consumed by the host to tell the model what\n * the user did NOT hear. Cleared on read. */\n takeInterruptedReply(): { full: string; heard: string } | null {\n const r = this.lastInterrupted;\n this.lastInterrupted = null;\n return r;\n }\n\n /** Speak a short filler phrase without starting a model turn (stays in listening mode after). */\n speakFiller(text: string): void {\n if (!text || this.speaking) return;\n // A filler is NOT a reply: it must not flip repliedSinceDispatch, or a Hold's \"mhm\" would make\n // the re-finalization guard drop the fuller final the Hold is waiting for (starving the turn).\n const replied = this.repliedSinceDispatch;\n this.beginSpeech();\n this.speakDelta(text);\n this.endSpeech();\n this.repliedSinceDispatch = replied;\n }\n\n /** Enqueue a COMPLETE worker utterance (already-split spoken text) onto the central speech queue.\n * If nothing is currently speaking it plays immediately; otherwise it queues and plays after the\n * current utterance fully ends (settle → pumpQueue) — never spliced into an open reflex utterance. */\n enqueueUtterance(text: string): void {\n // Require speakable content (a letter/digit). A punctuation/quote-only utterance (e.g. a lone \")\n // produces no audio, so its own begin→end turn waits for a 'done' that never arrives and STALLS the\n // queue until the drain safety-net fires (~seconds of dead air). Drop it.\n if (!text || !/[\\p{L}\\p{N}]/u.test(text)) return;\n this.diag('enqueue_utterance', { chars: text.length, queued: this.uttQueue.length, speaking: this.speaking });\n this.uttQueue.push(text);\n if (!this.speaking) this.pumpQueue();\n }\n /** Play the next queued worker utterance as its own one-shot turn (begin → delta → end). Drives the\n * next one from the settle completion (endSpeech), so utterances serialize without overlap. */\n private pumpQueue(): void {\n if (this.speaking) return; // a turn is in flight — settle will re-pump\n const text = this.uttQueue.shift();\n if (text == null) return;\n this.beginSpeech();\n this.speakDelta(text);\n this.endSpeech();\n }\n\n /** Short varied adaptive acks (adaptiveAckMs) — two shape pools picked by the dispatched\n * utterance (question → thinking-ish, otherwise neutral/on-it), with anti-repetition (never one\n * of the last 4 used). A 3-phrase round-robin sounded synthetic live (\"started with 'hmm' too\n * many times\"). All phrases are sub-second and semantically safe for their shape.\n * No 'Okay.': a genuine user \"Okay.\" within the 6s squash window would be swallowed as ack echo. */\n static readonly ACKS_NEUTRAL = ['Mm-hm.', 'One sec.', 'Right.', 'Sec.', 'On it.', 'Sure, moment.', 'Uh, one moment.', 'Let me see.'];\n static readonly ACKS_QUESTION = ['Hmm.', 'Let me think.', 'Hm, let me see.', 'Good question.', 'Mm, one sec.', 'Let\\'s see.'];\n /** A reflex opening sentence that is PURELY an acknowledgement (no content) — dropped when the adaptive\n * micro-ack already spoke one. Anchored end-to-end so only a whole ack-only clause matches. */\n static readonly ACK_LEADING = /^(?:(?:okay|ok|alright|sure|yeah|yep|right|got it|on it|still|still on it|still working on it|working on it|checking|one sec|one moment|mm hm|mmhm|hmm|let me (?:see|check|think))[ ,]*)+$/;\n private recentAcks: string[] = [];\n private pickAck(): string {\n const pool = this.lastDispatchWasQuestion ? VoiceEngine.ACKS_QUESTION : VoiceEngine.ACKS_NEUTRAL;\n const fresh = pool.filter((p) => !this.recentAcks.includes(p));\n const phrase = (fresh.length ? fresh : pool)[Math.floor(Math.random() * (fresh.length ? fresh.length : pool.length))];\n this.recentAcks.push(phrase);\n if (this.recentAcks.length > 4) this.recentAcks.shift();\n return phrase;\n }\n private lastDispatchWasQuestion = false;\n private clearAckTimer(reason?: string): void {\n if (!this.ackTimer) return;\n this.clock.clearTimeout(this.ackTimer);\n this.ackTimer = null;\n if (reason) this.diag('ack_cancelled', { reason });\n }\n /** Cancel a pending adaptive ack without touching the turn — hosts call this when the turn turns out\n * to be a Hold (intentionally silent; an ack would read as the start of an answer). */\n cancelPendingAck(): void { this.clearAckTimer('hold'); }\n\n /** barge-in: stop audio NOW, cancel generation, reset for the user's utterance */\n interrupt(): void {\n this.clearAckTimer('interrupt'); // the turn the ack was masking is dead\n this.adaptiveAckFired = false; this.ackProbe = null; // drop any half-probed leading ack\n if (this.uttQueue.length) log.info(`barge-in dropped ${this.uttQueue.length} queued worker utterance(s)`); // forensics: a \"lost\" task delivery usually died here\n const droppedQueued = this.uttQueue.length;\n this.uttQueue = []; // barge-in drops any queued worker utterances (the user took the floor)\n if (!this.speaking && !this.drainTimer) return;\n this.stopWordReveal(false); // barge-in: freeze reveal at what was actually spoken (no tail flush)\n // Emitted for every EFFECTIVE interrupt — engine cede paths also emit a `barge_in` right after\n // (with the trigger); a lone `interrupt` with no adjacent barge_in = host-initiated (Esc, /voice).\n this.diag('interrupt', { droppedQueued, ctxOpen: this.ctxOpen, playedMs: Math.round(Math.max(0, this.player.playedMs())) });\n if (this.drainTimer) { this.clock.clearTimeout(this.drainTimer); this.drainTimer = null; }\n // estimate how much of the reply was actually heard: played-audio seconds ≈ spoken chars\n // (~15 chars/s of TTS speech) — coarse, but enough for \"the user missed most of it\".\n this.resetOverlap(false); // ceding — the flush below discards the held tape, don't resume it\n this.lastResumeAt = 0; // consume the re-pause signal: the next reply starts fresh\n const heardChars = Math.round((Math.max(0, this.player.playedMs()) / 1000) * 15); // paused time excluded by the sink\n if (this.reply) this.lastInterrupted = { full: this.reply, heard: this.reply.slice(0, heardChars) };\n this.speaking = false;\n this.ctxOpen = false;\n this.interrupted = true; // stragglers from the aborted stream stay silent\n this.suspectUntil = 0;\n // Meet's WebRTC echoes our audio back with ~1-2s network delay. The echo window must cover\n // the full playback duration + round-trip, not just a fixed tail. Without this, long responses\n // (stories, explanations) leak their echo tail past the window → false barge-in → cascade.\n this.echoUntil = this.clock.now() + Math.max(2500, this.player.drainMs() + 3000);\n this.tts.cancel();\n this.player.kill();\n if (!this.usingAec) this.stt.reset(); // heuristic: drop the mixed echo/user buffer\n if (this.reply) this.prevReply = this.reply;\n this.setState('listening');\n }\n stop(): void {\n this.uttQueue = [];\n this.clearAckTimer();\n if (this.resumeTimer) this.clock.clearTimeout(this.resumeTimer);\n if (this.pendingTimer) this.clock.clearTimeout(this.pendingTimer);\n if (this.drainTimer) this.clock.clearTimeout(this.drainTimer);\n if (this.specTimer) this.clock.clearTimeout(this.specTimer);\n this.bcSupersede();\n this.stt.stop();\n this.player.kill();\n this.tts.close();\n this.setState('idle');\n }\n\n // --- listening side (STT-driven) ---\n\n private words(s: string): string[] {\n return s.toLowerCase().replace(/[^a-z0-9\\s]/g, '').split(/\\s+/).filter((w) => w.length >= 2);\n }\n private novelWords(text: string): string[] {\n return this.words(text).filter((w) => !this.echoWords.has(w));\n }\n private echoActive(): boolean {\n return this.speaking || this.clock.now() < this.echoUntil;\n }\n /** Genuine user speech vs our own bleed (AEC tier): novel words must DOMINATE, not merely exist.\n * Degraded AEC + an STT mis-hearing manufactures a single novel word out of pure echo (a name or\n * rare word in our own reply comes back transcribed slightly differently — 1 novel / N words).\n * A real interjection is mostly novel (\"stop\", \"wait what\") — short utterances pass on ratio,\n * longer ones on count. */\n private genuine(text: string): boolean {\n const total = this.words(text).length;\n const novel = this.novelWords(text).length;\n // ratio, not count: a long mis-heard echo sentence yields 2-3 \"novel\" words out of a dozen\n // (live trace: \"…latest email from you\" from our \"…latest news for you\") — an absolute >=2\n // pass let those through. Real user speech is MOSTLY novel.\n return novel > 0 && novel / Math.max(1, total) > 0.5;\n }\n\n private handlePartial(text: string): void {\n if (this.speaking) {\n // Half-duplex (no AEC, no headphones): deaf while we speak — echo can't become a barge or partial.\n if (!this.options.bargeIn) return;\n // Barge grace: right after an utterance dispatched this turn, the user's OWN trailing audio is\n // still finalizing — it must not barge the reply they just requested (B3 over-interruption / B4\n // double-abort). Drop the barge/pause decision during the grace; still render the partial below.\n if (this.clock.now() < this.bargeGraceUntil) {\n if (this.lastGraceDiag !== this.bargeGraceUntil) { this.lastGraceDiag = this.bargeGraceUntil; this.diag('grace_suppress', { text: text.slice(0, 60) }); }\n if (!this.echoActive() || (this.usingAec ? this.genuine(text) : this.novelWords(text).length >= 1)) this.options.onPartial(text);\n return;\n }\n if (this.overlapCapable) {\n // STT-driven overlap: Soniox saying \"this is speech\" is the discriminator (energy could not\n // separate residue from speech across rooms). New partial text → pause (trail-off); growing\n // into dominant-novel ≥2 words → cede; stalling → the resume timer releases the hold.\n const txt = text.trim();\n if (!txt || txt === this.lastOverlapPartial) return; // no NEW speech activity\n this.lastOverlapPartial = txt;\n // Echo gate on the PAUSE, not just the cede: our own audio bleeds back through imperfect AEC and\n // Soniox transcribes it as evolving partials. Pausing on each one (the old behavior) was an\n // audible hiccup mid-reply for every echo fragment — the \"TTS interrupting itself\" bug. genuine()\n // (novel words must DOMINATE) is the SAME speech/echo discriminator already used to cede; apply it\n // to the pause so pure echo is inert. A real barge is novel by definition → still pauses instantly,\n // even on one word (\"stop\" → 1 novel / 1 total → genuine).\n if (!this.genuine(txt)) { if (this.pausedAt) this.armResume(); return; } // echo: inert (keep a live hold ticking)\n if (!this.pausedAt) {\n this.pausedAt = this.clock.now();\n const sinceResumeMs = this.lastResumeAt ? Math.round(this.clock.now() - this.lastResumeAt) : undefined;\n this.diag('overlap_pause', { text: txt.slice(0, 60), sinceResumeMs });\n this.player.pause!();\n // Re-pause right after a false-alarm resume → persistent human, not an echo blip. Cede now,\n // before the resume replays old audio again, and without waiting for the dominant-novel gate.\n if (this.lastResumeAt && this.clock.now() - this.lastResumeAt < this.options.overlapRepauseCedeMs) {\n const phase = this.ctxOpen ? 'speaking' as const : 'drain' as const;\n this.diag('barge_in', { phase, trigger: 'overlap_repause', sinceResumeMs });\n this.interrupt();\n this.options.onBargeIn(phase);\n return;\n }\n }\n if (this.words(txt).length >= 2) { // genuine already true → dominant-novel ≥2 words → cede\n const phase = this.ctxOpen ? 'speaking' as const : 'drain' as const;\n this.diag('barge_in', { phase, trigger: 'overlap_cede', novel: this.novelWords(txt).length, total: this.words(txt).length });\n this.interrupt();\n this.options.onBargeIn(phase);\n return;\n }\n this.armResume(); // genuine single word: hold; quiet releases\n return;\n }\n // Barge-in = NOVEL words (not in our own recent reply) — even with AEC. Cancellation quality\n // is a spectrum (VPIO convergence varies run to run); when it degrades, the assistant's own\n // bleed must not self-interrupt. User speech is novel by definition → still triggers fast.\n const barge = this.usingAec ? this.genuine(text) : this.novelWords(text).length >= (this.suspectUntil ? 1 : 2);\n if (barge) {\n const phase = this.ctxOpen ? 'speaking' as const : 'drain' as const;\n this.diag('barge_in', { phase, trigger: this.usingAec ? 'genuine' : 'heuristic_novel', novel: this.novelWords(text).length, total: this.words(text).length });\n this.interrupt();\n this.options.onBargeIn(phase);\n }\n return;\n }\n if (this.pendingUtt && text.trim()) { // user kept talking during the merge window — wait for the next endpoint\n // RE-ARM (long fallback), never just clear: Soniox emits trailing partial frames after <end> —\n // clearing left the pending utterance parked forever (the user's barge words were LOST).\n if (this.pendingTimer) this.clock.clearTimeout(this.pendingTimer);\n this.pendingTimer = this.clock.setTimeout(() => this.flushUtterance(), Math.max(800, this.options.utteranceMergeMs));\n }\n this.trackSpeculation(text);\n this.trackBackchannel(text);\n // display partials unless they're echo-shaped during/after our own speech (degraded-AEC bleed)\n if (!this.echoActive() || (this.usingAec ? this.genuine(text) : this.novelWords(text).length >= 1)) this.options.onPartial(text);\n }\n\n /** Speculative-reflex trigger (listening side only — the speaking branch returns before this): a\n * partial that hasn't CHANGED for speculativeMs and has ≥ speculativeMinWords is stable → fire\n * onSpeculate once. If the user then keeps talking well past the speculated text, onSpeculateAbort\n * tells the host to kill the held call early. The confirm/abort DECISION belongs to the host at\n * dispatch time (speculationConfirms against the real final) — flushUtterance only resets the\n * trigger for the next turn. Merge windows are untouched: no speculation while an endpointed\n * utterance is pending (the final would be the MERGED text, which the partial alone never matches). */\n private trackSpeculation(text: string): void {\n if (!this.options.speculativeMs) return;\n const t = text.trim();\n if (this.specText) {\n // in flight: partial grew ≥3 words past the speculated text → the final can no longer confirm\n if (this.words(t).length > this.words(this.specText).length + 2) {\n this.specText = '';\n this.diag('speculate_abort', { reason: 'partial_grew', partial: t.slice(0, 60) });\n this.options.onSpeculateAbort();\n }\n return;\n }\n if (this.specSpent || this.pendingUtt || !t || t === this.specPartial) return;\n this.specPartial = t;\n if (this.specTimer) this.clock.clearTimeout(this.specTimer);\n this.specTimer = this.clock.setTimeout(() => {\n this.specTimer = null;\n if (this.speaking || this.specSpent || this.pendingUtt) return;\n if (this.words(this.specPartial).length < this.options.speculativeMinWords) return;\n // Soniox emits trailing partial frames after <end> — a partial that just echoes the utterance we\n // JUST dispatched must not spawn a phantom speculation (its \"final\" already came and went).\n const flat = this.specPartial.toLowerCase().replace(/[^a-z0-9]/g, '');\n if (flat && this.lastDispatchFlat && this.clock.now() - this.lastDispatchAt < VoiceEngine.DUP_FINAL_MS &&\n (this.lastDispatchFlat.startsWith(flat) || flat.startsWith(this.lastDispatchFlat))) return;\n this.specSpent = true;\n this.specText = this.specPartial;\n log.debug(`speculate: \"${this.specText.slice(0, 60)}\"`);\n this.diag('speculate', { text: this.specText });\n this.options.onSpeculate(this.specText);\n }, this.options.speculativeMs);\n }\n\n /** Backchannel blip pool — short, quiet, semantically inert. Chosen to be transcript-safe: if\n * imperfect AEC lets a blip reach Soniox MID-user-speech it lands inside their partial stream, so\n * every phrase is a word whose accidental presence barely hurts a transcript, and flushUtterance\n * strips an isolated echo of the exact phrase at a clause edge within 2s (stripBackchannelEcho).\n * 'Okay.'/'Right.' are fine here (unlike ACKS_NEUTRAL's no-Okay rule): a standalone user \"Okay.\"\n * right after OUR blip is overwhelmingly the blip's echo — the squash guard eating it is the point. */\n static readonly BACKCHANNELS = ['Mm-hm.', 'Uh-huh.', 'Right.', 'Okay.'];\n\n /** Backchannel trigger (listening side only — the speaking branch returns before this): a partial\n * that reached a clause boundary and then stayed UNCHANGED for backchannelMs (a micro-pause, still\n * BEFORE the silence endpoint) fires a blip — if long enough (≥ backchannelMinWords), predominantly\n * Latin, rate-limited (backchannelMinGapMs + max 2/turn), and no endpointed text is pending.\n * Touches nothing else: merge/endpoint/speculation timers and turn state are never affected. */\n private trackBackchannel(text: string): void {\n if (!this.options.backchannelMs) return;\n const t = text.trim();\n if (!t || t === this.bcPartial) return; // no NEW speech — the armed stability timer keeps ticking\n this.bcPartial = t;\n if (this.bcTimer) this.clock.clearTimeout(this.bcTimer);\n this.bcTimer = this.clock.setTimeout(() => {\n this.bcTimer = null;\n const p = this.bcPartial;\n const veto = (reason: string) => this.diag('backchannel_suppress', { reason });\n if (this.speaking || this.pendingUtt || this.bcActive) return veto('busy'); // never while audible or endpointed\n // Full-duplex (AEC) only: the blip extends echoUntil, and the half-duplex/heuristic echo gate\n // drops utterances wholesale while echo-active — a blip there would deafen the engine to the\n // user's own final for ~2.5s. Under AEC, genuine() keeps real speech flowing.\n if (!this.usingAec || !this.options.bargeIn) return veto('half_duplex');\n if (this.bcCount >= 2 || (this.lastBcAt && this.clock.now() - this.lastBcAt < this.options.backchannelMinGapMs)) return veto('rate_limited');\n if (this.words(p).length < this.options.backchannelMinWords) return veto('short');\n // clause boundary: trailing punctuation, or a mid-thought conjunction/filler pause\n if (!/[,.;:!?…]$/.test(p) && !this.looksIncomplete(p)) return veto('no_boundary');\n // Latin-predominant only (v1): the boundary/conjunction rules are English-tuned — Hebrew/mixed\n // partials get NO blips rather than mistimed ones (documented safe default).\n const letters = p.replace(/[^\\p{L}]/gu, '');\n const latin = p.replace(/[^A-Za-z]/g, '');\n if (!letters || latin.length / letters.length < 0.7) return veto('non_latin');\n // trailing partial frames of the utterance we JUST dispatched must not blip at its ghost\n const flat = p.toLowerCase().replace(/[^a-z0-9]/g, '');\n if (flat && this.lastDispatchFlat && this.clock.now() - this.lastDispatchAt < VoiceEngine.DUP_FINAL_MS &&\n (this.lastDispatchFlat.startsWith(flat) || flat.startsWith(this.lastDispatchFlat))) return;\n this.fireBackchannel();\n }, this.options.backchannelMs);\n }\n\n /** Speak one blip on a THROWAWAY TTS context. Zero floor-claim: no `speaking`, no state change, no\n * markTurn, no merge/endpoint/barge timers, no repliedSinceDispatch, no utterance queue. Echo\n * pre-seeding happens BEFORE any audio exists: the blip's words join echoWords (its mic echo is\n * never \"novel\"), the ack-squash guard is armed with the exact phrase (a standalone echo final is\n * swallowed), and the echo window extends so echo-shaped finals stay gated. */\n private fireBackchannel(): void {\n const fresh = VoiceEngine.BACKCHANNELS.filter((x) => !this.recentBc.includes(x));\n const pool = fresh.length ? fresh : VoiceEngine.BACKCHANNELS;\n const phrase = pool[Math.floor(Math.random() * pool.length)];\n this.recentBc.push(phrase);\n if (this.recentBc.length > 2) this.recentBc.shift();\n const now = this.clock.now();\n for (const w of this.words(phrase)) this.echoWords.add(w);\n this.ackAt = now; this.lastAck = phrase; // squash guard: a standalone echo of the blip is dropped\n this.lastBcAt = now; this.lastBcPhrase = phrase;\n this.echoUntil = Math.max(this.echoUntil, now + 2500);\n this.bcCount++;\n this.bcActive = true; // open the narrow audio-gate bypass for THIS blip only\n if (this.bcActiveTimer) this.clock.clearTimeout(this.bcActiveTimer);\n this.bcActiveTimer = this.clock.setTimeout(() => { this.bcActive = false; }, 3000);\n this.tts.onDone = () => { this.bcActive = false; }; // safe: reassigned by the next endSpeech\n this.tts.newContext(); // throwaway context — a real turn's newContext() supersedes it (stale filter)\n this.tts.speak(phrase, false);\n log.debug(`backchannel: \"${phrase}\"`);\n this.diag('backchannel', { phrase });\n this.options.onBackchannel(phrase);\n }\n\n /** A real turn (or shutdown) takes over mid-blip: close the audio bypass + stability timer. */\n private bcSupersede(): void {\n this.bcActive = false;\n if (this.bcActiveTimer) { this.clock.clearTimeout(this.bcActiveTimer); this.bcActiveTimer = null; }\n if (this.bcTimer) { this.clock.clearTimeout(this.bcTimer); this.bcTimer = null; }\n }\n\n /** Strip the mic echo of the LAST blip from a dispatching final, conservatively: only the exact\n * phrase, as an isolated token at a clause edge (start/end of utterance or beside punctuation),\n * within 2s of the blip. \"Right\"/\"okay\" as genuine mid-sentence content words are never touched. */\n private stripBackchannelEcho(text: string): string {\n if (!this.lastBcPhrase || this.clock.now() - this.lastBcAt > 2000) return text;\n const target = normWord(this.lastBcPhrase);\n if (!target) return text;\n const toks = text.split(/\\s+/);\n const idx = toks.findIndex((tok, i) => {\n if (normWord(tok) !== target) return false;\n if (/\\?/.test(tok)) return false; // a tag question (\"…tomorrow, right?\") is user MEANING, not echo — a blip's echo never gains a '?'\n const edgeBefore = i === 0 || /[,.;:!?…]$/.test(toks[i - 1]);\n const edgeAfter = i === toks.length - 1 || /[,.;:!?…]$/.test(tok);\n return edgeBefore && edgeAfter;\n });\n if (idx < 0) return text;\n toks.splice(idx, 1);\n log.verbose(`stripped backchannel echo \"${this.lastBcPhrase}\" from dispatching final`);\n return toks.join(' ');\n }\n\n /** Merge a resumed utterance into the pending one, deduping any word-overlap. Soniox re-finalizes\n * overlapping audio when the silence-timer and the semantic `<end>` both endpoint a growing\n * utterance (or after a reconnect): the next \"utterance\" repeats the tail of the previous one, and\n * a naive `${prev} ${next}` produced the live duplication (\"Um, I want to check if Um, I want to\n * check if…\"). Find the longest suffix of `prev`'s words that prefixes `next` and drop it. */\n private mergeUtterance(prev: string, next: string): string {\n if (!prev) return next;\n if (!next) return prev;\n const pw = prev.split(/\\s+/), nw = next.split(/\\s+/);\n const norm = VoiceEngine.normWord;\n // Truncation repair: the previous final is a strict PREFIX of this one (Soniox re-finalized the\n // same audio with a longer tail — live: \"Hey ther\" then \"Hey there, how are you?\"). Keep the\n // longer final instead of concatenating a truncated ghost in front of it. Conservative: prev must\n // have ≥2 words (a genuine one-word utterance followed by more speech is normal continuation),\n // every earlier word must match, and prev's LAST word may be a char-prefix of next's (\"ther\"→\"there\").\n if (pw.length >= 2 && pw.length <= nw.length) {\n let pfx = true;\n for (let i = 0; i < pw.length - 1; i++) if (norm(pw[i]) !== norm(nw[i])) { pfx = false; break; }\n if (pfx && norm(nw[pw.length - 1]).startsWith(norm(pw[pw.length - 1]))) return next;\n }\n const max = Math.min(pw.length, nw.length);\n for (let k = max; k > 0; k--) {\n let match = true;\n for (let i = 0; i < k; i++) if (norm(pw[pw.length - k + i]) !== norm(nw[i])) { match = false; break; }\n if (match) return [...pw, ...nw.slice(k)].join(' ');\n }\n return `${prev} ${next}`;\n }\n\n private static normWord(w: string): string { return normWord(w); }\n\n /** Soniox re-finalization of an ALREADY-DISPATCHED utterance, arriving PAST the merge window:\n * the new final is a strict word-prefix superset of the last dispatch (the last dispatched word\n * may be a char-prefix of the corresponding new word — a mid-word endpoint), and it lands within\n * DUP_FINAL_MS of the dispatch. Live: \"Hi, please tell me a very short\" dispatched, then the full\n * \"…very short joke.\" re-finalized ~900ms later → dispatched TWICE (two replies, the second to a\n * question already being answered).\n * DESIGN — HYBRID at the caller (flushUtterance): this shape check identifies a re-finalization\n * (a human physically cannot re-speak a ≥3-word sentence plus extra words within 3s of the\n * previous dispatch; a genuine continuation arrives as NEW words, never as a superset), and\n * repliedSinceDispatch then picks the action:\n * • reply already streaming (the live trace: TTFT ~500ms < the ~900ms re-final) → DROP. True\n * \"supersede\" would mean aborting audible speech mid-word to re-answer nearly the same text —\n * worse UX — and needs turn-abort plumbing in every host (the lab bridge has none;\n * DuplexAgent.send is a non-cancelable queue, so a second send just stacks a SECOND full reply).\n * Soniox's premature endpoint fires at a prosodic boundary, so the loss is trailing word(s).\n * • NO reply yet → DISPATCH the fuller text. Live-verified necessity: the reflex Holds on the\n * truncated fragment (\"Hi, please tell me a very short\" → Hold), and dropping the re-final then\n * starves the conversation entirely — the fuller final IS the completion the Hold is waiting\n * for. A slow-but-answering reflex in this window degrades to today's two-reply behavior (rare\n * race), never worse. Fillers (\"mhm\") deliberately don't count as replies — see speakFiller. */\n private refinalizes(next: string): boolean {\n const pw = this.lastDispatchWords, nw = next.trim().split(/\\s+/);\n const norm = VoiceEngine.normWord;\n if (pw.length < 3 || nw.length < pw.length) return false;\n if (this.clock.now() - this.lastDispatchAt >= VoiceEngine.DUP_FINAL_MS) return false;\n for (let i = 0; i < pw.length - 1; i++) if (norm(pw[i]) !== norm(nw[i])) return false;\n const pLast = norm(pw[pw.length - 1]), nSame = norm(nw[pw.length - 1]);\n if (!nSame.startsWith(pLast)) return false;\n return nw.length > pw.length || nSame.length > pLast.length; // STRICT superset (identical → dup guard, which allows post-reply repeats)\n }\n\n private static readonly TRAIL_RE = /(?:^|\\s)(?:and|but|or|so|to|the|a|an|of|in|for|with|that|if|uh|um|like|about|from|into|on|is|are|was|were|,)$/i;\n /** The utterance sounds like the user paused mid-thought (trailing conjunction/filler/comma). */\n private looksIncomplete(text: string): boolean {\n return VoiceEngine.TRAIL_RE.test(text.trim());\n }\n\n private handleUtterance(text: string): void {\n // Overlap that never grabbed the turn: duration said backchannel/noise → drop it. Real grabs\n // interrupted already (speaking=false). Applies while content flows (ctxOpen) AND while we are\n // holding a pause for THIS overlap (a drain-tail \"yeah\" leaked as a real turn otherwise). A\n // clean early answer during the drain — no hold in progress — still falls through (turn-taking).\n if (this.speaking && (this.ctxOpen || this.pausedAt) && this.overlapCapable) { this.diag('utterance_drop', { reason: 'overlap_noise', text: text.slice(0, 60) }); this.stt.reset(); return; }\n // Echo-shaped utterances (no/few novel words while we are or just were audible) are dropped in\n // BOTH tiers — degraded AEC bleed otherwise becomes fake user turns (\"🎤 › Friday.\").\n // Half-duplex: drop EVERY utterance while audible (speaking + drain tail) — pure echo suppression.\n if (this.echoActive() && (!this.options.bargeIn || (this.usingAec ? !this.genuine(text) : this.novelWords(text).length < 2))) { this.diag('echo_swallow', { guard: 'echo_gate', text: text.slice(0, 60) }); this.stt.reset(); return; }\n // AEC converges over ~100ms at audio onset — the ack (first audio after silence) can leak back\n // as a transcript. Drop backchannel-shaped utterances shortly after we spoke it.\n const squash = (t: string) => t.toLowerCase().replace(/[^a-z]/g, '').replace(/(.)\\1+/g, '$1');\n if (this.ackAt && this.lastAck && this.clock.now() - this.ackAt < 6000 && squash(text) === squash(this.lastAck)) { this.diag('echo_swallow', { guard: 'ack_squash', text: text.slice(0, 60) }); this.ackAt = 0; return; }\n // Merge window: semantic endpointing fires mid-spelling (\"E-L-Y.\" … \"A.\") and mid-thought.\n // Hold briefly; speech resuming in the window appends to the SAME utterance. Substantial\n // utterances (≥4 words) skip the hold — they are never spelled fragments, and the saved 350ms\n // is the difference between ping-pong and lag in quick exchanges.\n if (this.pendingUtt) this.mergePath = 'merged'; // this final joined a held one (see dispatch diag)\n this.pendingUtt = this.mergeUtterance(this.pendingUtt, text);\n if (this.pendingTimer) this.clock.clearTimeout(this.pendingTimer);\n // Incomplete utterance hold: trailing conjunctions/fillers get an extended merge window + optional\n // filler phrase, letting the user finish their thought without triggering a model call.\n if (this.options.incompleteMergeMs && this.looksIncomplete(this.pendingUtt)) {\n log.verbose(`hold: incomplete utterance \"${this.pendingUtt.slice(-40)}\"`);\n this.diag('hold', { reason: 'incomplete', tail: this.pendingUtt.slice(-40) });\n this.options.onHold();\n if (this.options.holdFiller && !this.speaking) this.speakFiller(this.options.holdFiller); // filler ≠ reply (see speakFiller)\n this.pendingTimer = this.clock.setTimeout(() => this.flushUtterance(), this.options.incompleteMergeMs);\n return;\n }\n if (!this.options.utteranceMergeMs || this.words(this.pendingUtt).length >= 4) return this.flushUtterance();\n this.pendingTimer = this.clock.setTimeout(() => this.flushUtterance(), this.options.utteranceMergeMs);\n }\n private flushUtterance(): void {\n if (this.pendingTimer) { this.clock.clearTimeout(this.pendingTimer); this.pendingTimer = null; }\n // The turn-in-progress is dispatching (or dropping) — reset the speculation trigger for the next\n // one. The host decides confirm/abort of any in-flight speculative call against the final itself.\n if (this.specTimer) { this.clock.clearTimeout(this.specTimer); this.specTimer = null; }\n this.specSpent = false; this.specPartial = ''; this.specText = '';\n // Backchannel per-turn reset: the turn-in-progress ends here. A pending stability timer must not\n // fire a blip over the dispatch, and the next user turn gets a fresh 2-blip budget.\n if (this.bcTimer) { this.clock.clearTimeout(this.bcTimer); this.bcTimer = null; }\n this.bcCount = 0; this.bcPartial = '';\n const text = this.stripBackchannelEcho(this.pendingUtt); // drop the blip's mic echo (isolated, clause-edge, <2s)\n this.pendingUtt = '';\n const path = this.mergePath; this.mergePath = 'direct';\n if (text) {\n const flat = text.toLowerCase().replace(/[^a-z0-9]/g, '');\n if (flat && flat === this.lastDispatchFlat && !this.repliedSinceDispatch &&\n this.clock.now() - this.lastDispatchAt < VoiceEngine.DUP_FINAL_MS) {\n log.verbose(`dropped duplicate final \"${text.slice(0, 40)}\" (identical to the just-dispatched utterance, no reply between)`);\n this.diag('utterance_drop', { reason: 'dup_final', text: text.slice(0, 60) });\n return;\n }\n const refinal = this.refinalizes(text);\n if (refinal && this.repliedSinceDispatch) {\n // Track the FULLEST text so a third, even-fuller re-final still matches; lastDispatchAt stays\n // anchored at the real dispatch (re-finals must not extend their own window).\n log.verbose(`dropped re-finalization \"${text.slice(0, 60)}\" (superset of the just-dispatched utterance, reply already flowing)`);\n this.diag('utterance_drop', { reason: 'refinalized', text: text.slice(0, 60) });\n this.lastDispatchFlat = flat;\n this.lastDispatchWords = text.trim().split(/\\s+/);\n return;\n }\n this.lastDispatchFlat = flat;\n this.lastDispatchWords = text.trim().split(/\\s+/);\n this.lastDispatchAt = this.clock.now();\n this.repliedSinceDispatch = false;\n this.lastDispatchWasQuestion = /\\?\\s*$/.test(text); // shapes the adaptive-ack pool (question → thinking-ish)\n this.turnStartAt = this.clock.now();\n // Trailing audio of the utterance we just dispatched keeps finalizing for a beat (Soniox emits\n // partials after <end>). Once the host opens a reply context (speaking=true), those self-tail\n // partials would read as a barge and abort the very reply the user asked for (the live \"interrupts\n // mid-sentence\" + double-abort steps=1→steps=0). Grace the barge path briefly after dispatch.\n this.bargeGraceUntil = this.clock.now() + this.options.bargeGraceMs;\n this.diag('dispatch', { text, path: refinal ? 'refinalized' : path, question: this.lastDispatchWasQuestion });\n this.options.onUtterance(text); // stamp the real turn start for TTFT\n }\n }\n\n private get overlapCapable(): boolean {\n return this.usingAec && this.options.overlapPause && !!this.player.pause && !!this.player.resume;\n }\n private armResume(): void {\n if (this.resumeTimer) this.clock.clearTimeout(this.resumeTimer);\n this.resumeTimer = this.clock.setTimeout(() => {\n this.resumeTimer = null;\n if (!this.pausedAt) return; // (no speaking guard: a held pause must ALWAYS release, else the tape wedges)\n this.diag('overlap_resume', { heldMs: Math.round(this.clock.now() - this.pausedAt) });\n this.stt.reset(); // drop the stalled residue/backchannel buffer — it is not the next utterance\n this.resetOverlap(true); // the overlap died out (backchannel/noise) — pick up exactly where she left off\n }, this.options.overlapResumeMs);\n }\n private resetOverlap(resume: boolean): void {\n if (this.resumeTimer) { this.clock.clearTimeout(this.resumeTimer); this.resumeTimer = null; }\n if (this.pausedAt && resume) { this.player.resume?.(); this.lastResumeAt = this.clock.now(); }\n this.pausedAt = 0;\n this.lastOverlapPartial = '';\n this.gatePassTimes = [];\n }\n\n /** energy two-stage barge-in (heuristic tier only): spike over echo baseline → pause + confirm via STT */\n private gatePassTimes: number[] = []; // recent gate-PASSING chunks (helper zeroes residue — nonzero = vetted)\n private handleLevel(rms: number): void {\n if (this.usingAec) {\n // Fast hold trigger: a nonzero level while we are audible means the helper's gate PASSED it\n // (≥2× expected residue). Two passes within 350ms = speech onset → pause NOW (~300ms), without\n // waiting for STT tokens (which lag whenever the onset straddles the gate). The STT still owns\n // the DECISION: cede on genuine ≥2 words, or the resume timer releases the hold.\n if (!this.options.overlapEnergyHold || !this.speaking || !this.overlapCapable || this.pausedAt || rms < 50) return;\n const t = this.clock.now();\n this.gatePassTimes = this.gatePassTimes.filter((x) => t - x < 350);\n this.gatePassTimes.push(t);\n if (this.gatePassTimes.length < 2) return;\n this.gatePassTimes = [];\n this.pausedAt = t;\n this.player.pause!();\n this.armResume();\n return;\n }\n if (!this.speaking) { this.baseline = 0; this.hot = 0; return; }\n // warm-up: let the EMA learn the echo level before triggers (else her own onset reads as a spike)\n if (!this.baseline) { this.baseline = rms; return; }\n this.baseline = this.baseline * 0.9 + rms * 0.1;\n if (rms > Math.max(this.baseline * this.options.bargeRmsMult, this.options.bargeRmsFloor)) this.hot++;\n else this.hot = 0;\n if (this.hot >= 2 && !this.suspectUntil) {\n this.suspectUntil = this.clock.now() + 1300;\n this.clock.setTimeout(() => { this.suspectUntil = 0; }, 1350);\n }\n }\n}\n","/**\n * Portable voice I/O contracts — zero platform imports. The engine, STT and TTS clients in this\n * directory run anywhere with a `WebSocket` global (Bun, Node, browser); platform backends\n * (mic capture, audio playback) plug in through these seams.\n */\n\nexport type VoiceState = 'idle' | 'listening' | 'thinking' | 'speaking';\n\n/** STT input sample format — sources MUST deliver this (downsample/convert in the adapter). */\nexport const STT_SAMPLE_RATE = 16000; // Hz, mono, s16le\n/** Playback format the TTS requests and sinks must play. */\nexport const TTS_SAMPLE_RATE = 44100; // Hz, mono, s16le\n\n/** A microphone (or any PCM) source. Emits s16le mono 16kHz chunks.\n * Node: mic-aec/ffmpeg child process. Web: getUserMedia({ echoCancellation: true }) + worklet. */\nexport interface AudioSource {\n /** `aec` = the source is echo-cancelled (assistant's own TTS never reaches the chunks) —\n * selects the engine's trivial barge-in path vs the heuristic echo tier. */\n readonly aec: boolean;\n start(onChunk: (pcm: Uint8Array) => void): void | Promise<void>;\n stop(): void;\n /** Unrecoverable source failure (e.g. mic permission denied → engine produces no audio AND, in the\n * duplex AEC engine, no playback). The host should tear voice down rather than spin reconnects. */\n onFatal?: (message: string) => void;\n}\n\n/** An audio playback sink for s16le mono 44.1kHz PCM.\n * Node: per-turn ffplay. Web: AudioContext/worklet ring buffer. */\nexport interface AudioSink {\n /** start a new spoken turn (may recycle or recreate the underlying player) */\n markTurn(): void;\n write(pcm: Uint8Array): void;\n /** estimated ms until queued audio finishes playing */\n drainMs(): number;\n /** ms of audio actually played this turn */\n playedMs(): number;\n /** stop playback NOW (barge-in primitive) */\n kill(): void;\n /** optional exact-sample pause/resume — enables the overlap trail-off tier (web: AudioContext\n * suspend/resume; CLI AEC helper: control frames). Sinks without it degrade to interrupt-only\n * turn-taking. Nothing is lost across a pause; playedMs/drainMs must exclude paused time. */\n pause?(): void;\n resume?(): void;\n}\n\n/** Static key (server/CLI) or an async getter (browser: fetch a short-lived token from YOUR\n * backend). Getters are invoked on EVERY (re)connect — temp tokens expire, so a reconnect\n * must re-mint, never reuse the boot-time token. */\nexport type AuthProvider = string | (() => string | Promise<string>);\n\nexport async function resolveAuth(auth: AuthProvider): Promise<string> {\n return typeof auth === 'function' ? await auth() : auth;\n}\n","/**\n * SpokenSplitter — a stateful streaming parser that splits a token stream into SPOKEN text (inside\n * `<spoken>…</spoken>`) and DETAIL text (everything outside). Used by the worker delivery path: the\n * capable worker wraps what the user should HEAR in `<spoken>` tags; detail prose is the work record.\n *\n * Buffers partial tags split across chunk boundaries (\"<spo\" + \"ken>\") so a tag is never mis-emitted\n * as detail. Pure class — no IoC ceremony.\n */\nconst OPEN = '<spoken>';\nconst CLOSE = '</spoken>';\n\n/**\n * SentenceCoalescer — buffers streamed spoken fragments and emits COMPLETE sentences. A worker on a\n * fragmenting model (cursor streams word-by-word deltas) would otherwise yield one utterance per word —\n * choppy TTS (a begin→end turn each) and one screen-echo line per word. feed() returns the sentence(s)\n * completed by this chunk (or ''); flush() returns the trailing partial when the stream ends.\n */\nconst CLOSERS = `\"')]}»”’`; // closing quotes/brackets that hug a sentence-ender (\"…sponge?\")\n\n/** A speakable chunk must contain at least one letter or digit — a punctuation/quote-only chunk (e.g. a\n * lone \") produces no audio and STALLS the TTS (endSpeech waits for a 'done' that never arrives). */\nconst hasSpeech = (s: string): boolean => /[\\p{L}\\p{N}]/u.test(s);\n\nexport class SentenceCoalescer {\n private buf = '';\n private static isEnd(c: string): boolean { return c === '\\n' || c === '.' || c === '!' || c === '?' || c === '…'; }\n\n feed(delta: string): string {\n if (delta) this.buf += delta;\n let cut = -1;\n for (let i = 0; i < this.buf.length; i++) if (SentenceCoalescer.isEnd(this.buf[i])) cut = i;\n if (cut < 0) return ''; // no sentence boundary yet — hold for more deltas\n // Absorb a closing quote/bracket sitting right after sentence-ending PUNCTUATION (\"…sponge?\") into the\n // same chunk — otherwise the closer is orphaned onto the next utterance as a lone, unspeakable \" that\n // stalls TTS. Skip for a newline cut (a quote after \\n is an OPENING quote for the next line).\n if (this.buf[cut] !== '\\n') while (cut + 1 < this.buf.length && CLOSERS.includes(this.buf[cut + 1])) cut++;\n const ready = this.buf.slice(0, cut + 1).trim();\n this.buf = this.buf.slice(cut + 1);\n return hasSpeech(ready) ? ready : ''; // drop a word-less (punctuation/quote-only) chunk — never speak it\n }\n\n flush(): string { const s = this.buf.trim(); this.buf = ''; return hasSpeech(s) ? s : ''; }\n}\n\n\nexport class SpokenSplitter {\n private buf = '';\n private inSpoken = false;\n /** True once any spoken char has ever been emitted (drives the no-spoken fallback). */\n public spokeAny = false;\n\n /** Feed a delta; returns the spoken/detail spans completed by this chunk (either may be ''). */\n feed(delta: string): { spoken: string; detail: string } {\n this.buf += delta;\n return this.drain(false);\n }\n\n /** Drain any buffered partial. A trailing `<…` that never completed a tag is emitted as detail. */\n flush(): { spoken: string; detail: string } {\n return this.drain(true);\n }\n\n private drain(final: boolean): { spoken: string; detail: string } {\n let spoken = '';\n let detail = '';\n while (this.buf.length) {\n const tag = this.inSpoken ? CLOSE : OPEN;\n const idx = this.buf.indexOf(tag);\n if (idx >= 0) {\n // Emit text up to the tag, then consume the tag and flip mode.\n const text = this.buf.slice(0, idx);\n if (this.inSpoken) spoken += text; else detail += text;\n this.buf = this.buf.slice(idx + tag.length);\n this.inSpoken = !this.inSpoken;\n continue;\n }\n // No complete tag in the buffer. Hold back a trailing `<…` run that is a proper prefix of the\n // tag we're currently seeking (it could complete on the next feed). Only the ACTIVE tag matters.\n const lt = this.buf.lastIndexOf('<');\n const holdStart = lt >= 0 && tag.startsWith(this.buf.slice(lt)) ? lt : this.buf.length;\n const text = this.buf.slice(0, holdStart);\n if (this.inSpoken) spoken += text; else detail += text;\n this.buf = this.buf.slice(holdStart);\n break;\n }\n if (final && this.buf) {\n // A dangling partial tag that never completed — surface it as detail (never lost).\n if (this.inSpoken) spoken += this.buf; else detail += this.buf;\n this.buf = '';\n }\n // Gate on non-BLANK content: `<spoken> </spoken>` would flip spokeAny true, but downstream\n // speak/enqueueUtterance trims it to nothing → silent turn AND a suppressed gist fallback.\n if (spoken.trim()) this.spokeAny = true;\n return { spoken, detail };\n }\n}\n","/**\n * Soniox streaming STT over WebSocket — token partials, semantic `<end>` endpointing,\n * auto-reconnect (re-minting auth — temp tokens expire). Portable: the microphone is an\n * injected AudioSource, not spawned here.\n *\n * Browser auth: NEVER ship the real key — your backend mints a short-lived key via\n * `POST https://api.soniox.com/v1/auth/temporary-api-key` (sent with the real key) and the\n * client passes `auth: () => fetch('/your-be/soniox-token').then(r => r.text())`.\n */\nimport { forComponent } from '../core/logging';\nimport { type AudioSource, type AuthProvider, resolveAuth, STT_SAMPLE_RATE } from '../core/types';\n\nconst log = forComponent('SonioxSTT');\nconst now = () => performance.now();\n\nexport class SonioxSTTOptions {\n auth: AuthProvider = '';\n source!: AudioSource;\n model = 'stt-rt-preview';\n languageHints = ['en'];\n /** Client-side endpoint: finalized text + no new tokens for this long = utterance (don't wait for\n * Soniox's semantic <end>, which adds 0.5-1.5s — the difference between ping-pong and lag). */\n silenceEndpointMs = 500;\n /** No-audio watchdog: if the mic source stops delivering chunks for this long, capture is dead →\n * fire onFatal + stop (else Soniox idle-timeouts and reconnect-loops forever). 0 = disable. */\n noAudioTimeoutMs = 10_000;\n}\n\nexport class SonioxSTT {\n public options: SonioxSTTOptions;\n private ws!: WebSocket;\n private stopped = false;\n private sourceStarted = false;\n public onPartial: (text: string) => void = () => {};\n public onUtterance: (text: string, endpointAt: number) => void = () => {};\n /** mic energy (RMS) per chunk — drives the energy-based heuristic barge-in tier */\n public onLevel: (rms: number) => void = () => {};\n /** Unrecoverable: the mic source stopped delivering audio (Soniox starves → idle-timeout reconnect\n * loop). The host tears voice down instead of spinning forever. */\n public onFatal: (message: string) => void = () => {};\n /** Diagnostic tap (provider errors, ws reconnects, no-audio watchdog). Fire-and-forget: a throwing\n * handler disables itself — never affects transcription. Wired by VoiceIO / the lab bridge. */\n public onDiag: (ev: { t: number; kind: string; [k: string]: unknown }) => void = () => {};\n private diagOn = true;\n private diag(kind: string, fields?: Record<string, unknown>): void {\n if (!this.diagOn) return;\n try { this.onDiag({ t: now(), kind, ...fields }); }\n catch (e) { this.diagOn = false; log.debug(`onDiag threw — STT diagnostics disabled: ${e instanceof Error ? e.message : e}`); }\n }\n private lastChunkAt = 0; // timestamp of the most recent mic chunk (0 = none yet)\n private startedChunksAt = 0; // when capture started (grace before the first chunk)\n private noAudioTimer: ReturnType<typeof setInterval> | null = null;\n private finalText = '';\n private partialText = '';\n private lastChangeAt = 0;\n private lastCombined = '';\n private endpointTimer: ReturnType<typeof setInterval> | null = null;\n private firstTokenAt = 0; // first speech token in current utterance\n\n constructor(options?: Partial<SonioxSTTOptions>) {\n this.options = { ...new SonioxSTTOptions(), ...options };\n }\n\n get usingAec(): boolean {\n return this.options.source?.aec ?? false;\n }\n\n private async connectWs(): Promise<void> {\n const apiKey = await resolveAuth(this.options.auth); // per-connect: temp tokens expire\n this.ws = new WebSocket('wss://stt-rt.soniox.com/transcribe-websocket');\n await new Promise<void>((res, rej) => {\n this.ws.onopen = () => res();\n this.ws.onerror = (e: any) => rej(new Error(`soniox ws: ${e.message || 'connect failed'}`));\n });\n this.ws.send(\n JSON.stringify({\n api_key: apiKey,\n model: this.options.model,\n audio_format: 'pcm_s16le',\n sample_rate: STT_SAMPLE_RATE,\n num_channels: 1,\n language_hints: this.options.languageHints,\n enable_endpoint_detection: true,\n }),\n );\n this.ws.onmessage = (ev) => this.handle(JSON.parse(String(ev.data)));\n this.ws.onclose = (ev: any) => {\n if (this.stopped) return;\n log.warn(`soniox ws closed (${ev.code} ${ev.reason || ''}) — reconnecting`);\n this.diag('stt_ws_closed', { code: ev.code, reason: String(ev.reason || ''), reconnecting: true });\n this.reset();\n this.connectWs().catch((e) => { log.error(`soniox reconnect failed: ${e.message}`); this.diag('stt_reconnect_failed', { message: e.message }); });\n };\n }\n\n async start(): Promise<void> {\n await this.connectWs();\n if (this.sourceStarted) return; // reconnect path — source keeps running\n this.sourceStarted = true;\n // client-side stability endpoint (faster than Soniox's semantic <end> AND its finalization lag:\n // finals trail partials by ~1s — text that has stopped CHANGING is the utterance)\n this.endpointTimer = setInterval(() => {\n const combined = (this.finalText + this.partialText).trim();\n if (!combined || now() - this.lastChangeAt < this.options.silenceEndpointMs) return;\n if (this.firstTokenAt) log.debug(`stt: ${Math.round(now() - this.firstTokenAt)}ms first-token→silence-endpoint, \"${combined.slice(0, 60)}\"`);\n this.reset();\n this.onUtterance(combined, now());\n }, 120);\n (this.endpointTimer as any).unref?.();\n // No-audio watchdog (SLIDING window, not cumulative): healthy capture delivers a chunk ~every 100ms\n // (the AEC helper emits even during silence). If chunks STOP for 10s, capture died — e.g. the\n // CoreAudio input tap stopped firing after a TTS turn — and Soniox would idle-timeout + reconnect\n // forever. A cumulative-from-start check would miss this (the greeting already sent bytes). Tear\n // down with a clear message. The grace (startedChunksAt) covers a slow first chunk.\n this.startedChunksAt = now();\n const noAudioMs = this.options.noAudioTimeoutMs;\n if (noAudioMs > 0) {\n this.noAudioTimer = setInterval(() => {\n if (this.stopped) return;\n const ref = this.lastChunkAt || this.startedChunksAt;\n if (now() - ref > noAudioMs) {\n log.error(`stt: no mic audio for >${Math.round(noAudioMs / 1000)}s — capture device stopped delivering`);\n this.diag('stt_watchdog_fatal', { noAudioMs });\n this.onFatal('microphone stopped delivering audio (try a different input device, e.g. AirPods, or check System Settings → Sound → Input)');\n this.stop();\n }\n }, Math.max(250, Math.min(2000, noAudioMs / 4)));\n (this.noAudioTimer as any).unref?.();\n }\n await this.options.source.start((chunk) => {\n this.lastChunkAt = now();\n let sum = 0;\n const view = new DataView(chunk.buffer, chunk.byteOffset, chunk.byteLength);\n for (let i = 0; i + 1 < chunk.byteLength; i += 2) { const v = view.getInt16(i, true); sum += v * v; }\n this.onLevel(Math.sqrt(sum / (chunk.byteLength / 2)));\n if (this.ws.readyState === WebSocket.OPEN) this.ws.send(chunk);\n });\n }\n private handle(m: any): void {\n if (m.error_message) { this.diag('stt_error', { message: String(m.error_message), code: m.error_code }); return log.error(`soniox: ${m.error_message}`); }\n let endpoint = false;\n for (const t of m.tokens ?? []) {\n if (t.text === '<end>') endpoint = true;\n else if (t.is_final) this.finalText += t.text;\n }\n this.partialText = (m.tokens ?? []).filter((t: any) => !t.is_final && t.text !== '<end>').map((t: any) => t.text).join('');\n const combined = this.finalText + this.partialText;\n if (combined !== this.lastCombined) {\n this.lastCombined = combined; this.lastChangeAt = now();\n if (!this.firstTokenAt && combined.trim()) this.firstTokenAt = now();\n }\n this.onPartial(combined);\n if (endpoint && this.finalText.trim()) {\n const utterance = this.finalText.trim();\n if (this.firstTokenAt) log.debug(`stt: ${Math.round(now() - this.firstTokenAt)}ms first-token→endpoint, \"${utterance.slice(0, 60)}\"`);\n this.reset();\n this.onUtterance(utterance, now());\n }\n }\n reset(): void {\n this.finalText = '';\n this.partialText = '';\n this.lastCombined = '';\n this.firstTokenAt = 0;\n }\n stop(): void {\n this.stopped = true;\n if (this.endpointTimer) clearInterval(this.endpointTimer);\n if (this.noAudioTimer) clearInterval(this.noAudioTimer);\n this.options.source?.stop();\n if (this.ws) this.ws.onclose = null as any;\n this.ws?.close();\n }\n}\n","/**\n * Cartesia streaming TTS over a warm WebSocket — raw-delta continuations (prosody stitched\n * server-side, no sentence chunker), per-context cancel (barge-in), stale-context filtering.\n * Portable: browser/Bun/Node. Auth: static key (server) or BE-minted access token (browser).\n *\n * Browser auth: NEVER ship the real key — your backend mints a short-lived access token\n * (Cartesia `POST /access-tokens`, sent with the real X-API-Key) and the client uses\n * `auth: () => fetch('/your-be/cartesia-token').then(r => r.text())` + `authMode: 'token'`.\n */\nimport { forComponent } from '../core/logging';\nimport { type AuthProvider, resolveAuth, TTS_SAMPLE_RATE } from '../core/types';\n\nconst log = forComponent('CartesiaTTS');\nconst now = () => performance.now();\n\nexport class CartesiaTTSOptions {\n auth: AuthProvider = '';\n voiceId = '';\n model = 'sonic-3.5';\n /** 'apiKey' (server/CLI) → `api_key=` URL param; 'token' (browser, BE-minted) → `access_token=`. */\n authMode: 'apiKey' | 'token' = 'apiKey';\n}\n\nexport class CartesiaTTS {\n public options: CartesiaTTSOptions;\n private ws!: WebSocket;\n private ctxSeq = 0;\n public ctxId = '';\n public onAudio: (chunk: Uint8Array) => void = () => {};\n public onDone: () => void = () => {};\n /** Word-level timestamps for karaoke reveal: `start[i]` = seconds from turn-audio start (absolute\n * across continuation chunks). Fired only when a consumer opts into reveal (see `wantTimestamps`). */\n public onTimestamps: (words: string[], start: number[]) => void = () => {};\n /** Request `add_timestamps` from Cartesia. Off by default (saves bandwidth) — the engine sets it\n * when revealMode==='word'. */\n public wantTimestamps = false;\n /** Diagnostic tap (provider errors, circuit-breaker open/close, ws reconnects). Fire-and-forget:\n * a throwing handler disables itself — never affects synthesis. Wired by VoiceIO / the lab bridge. */\n public onDiag: (ev: { t: number; kind: string; [k: string]: unknown }) => void = () => {};\n private diagOn = true;\n private diag(kind: string, fields?: Record<string, unknown>): void {\n if (!this.diagOn) return;\n try { this.onDiag({ t: now(), kind, ...fields }); }\n catch (e) { this.diagOn = false; log.debug(`onDiag threw — TTS diagnostics disabled: ${e instanceof Error ? e.message : e}`); }\n }\n public firstAudioAt = 0;\n /** Circuit breaker: consecutive error count + down flag. */\n private consecutiveErrors = 0;\n private consecutiveOk = 0;\n private down = false;\n private downAt = 0;\n private probeTimer: ReturnType<typeof setInterval> | null = null;\n private static readonly CB_THRESHOLD = 3; // open after 3 consecutive errors\n private static readonly CB_RECOVER_OK = 2; // close only after 2 consecutive good frames (no single-frame flap)\n private static readonly CB_PROBE_MS = 30_000;\n\n constructor(options?: Partial<CartesiaTTSOptions>) {\n this.options = { ...new CartesiaTTSOptions(), ...options };\n }\n\n private closed = false;\n private connecting: Promise<void> | null = null;\n\n async connect(): Promise<void> {\n this.closed = false;\n this.connecting = this.doConnect();\n await this.connecting;\n this.connecting = null;\n }\n\n private async doConnect(): Promise<void> {\n const key = await resolveAuth(this.options.auth); // per-connect: temp tokens expire\n const param = this.options.authMode === 'token' ? 'access_token' : 'api_key';\n this.ws = new WebSocket(`wss://api.cartesia.ai/tts/websocket?cartesia_version=2026-03-01&${param}=${key}`);\n await new Promise<void>((res, rej) => {\n this.ws.onopen = () => res();\n this.ws.onerror = (e: any) => rej(new Error(`cartesia ws: ${e.message || 'connect failed'}`));\n });\n this.ws.onclose = (ev: any) => {\n log.warn(`cartesia ws closed (${ev.code} ${ev.reason || ''})`);\n this.diag('tts_ws_closed', { code: ev.code, reason: String(ev.reason || ''), reconnecting: !this.closed });\n if (!this.closed) { this.connecting = this.doConnect().catch((e) => { log.error(`cartesia reconnect failed: ${e.message}`); this.diag('tts_reconnect_failed', { message: e.message }); }); }\n };\n this.ws.onmessage = (ev) => {\n const m = JSON.parse(String(ev.data));\n if (m.context_id && m.context_id !== this.ctxId) return; // stale context (post-cancel stragglers)\n if (m.type === 'chunk' && m.data) {\n this.consecutiveErrors = 0;\n this.markRecovered();\n if (!this.firstAudioAt) this.firstAudioAt = now();\n this.onAudio(base64ToBytes(m.data));\n } else if (m.type === 'done') {\n this.consecutiveErrors = 0;\n this.markRecovered();\n this.onDone();\n } else if (m.type === 'timestamps' && m.word_timestamps) {\n const wt = m.word_timestamps as { words?: string[]; start?: number[] };\n if (wt.words?.length && wt.start?.length) this.onTimestamps(wt.words, wt.start);\n }\n else if (m.type === 'error') {\n if (/already been cancelled|does not exist/.test(m.message || '')) return;\n this.consecutiveErrors++;\n this.diag('tts_error', { message: String(m.message || ''), code: m.status_code, contextId: m.context_id, consecutive: this.consecutiveErrors });\n if (!this.down && this.consecutiveErrors >= CartesiaTTS.CB_THRESHOLD) {\n this.down = true;\n this.downAt = now();\n this.consecutiveOk = 0;\n log.warn(`TTS circuit breaker open — ${this.consecutiveErrors} consecutive errors, switching to text-only`);\n this.diag('tts_breaker_open', { errors: this.consecutiveErrors });\n this.onDone(); // release any pending drain\n this.startProbe();\n } else if (!this.down) {\n // \"No valid transcripts passed.\" = a punctuation/whitespace-only transcript — benign (nothing\n // to synthesize), must never splice a raw warn into the live REPL. Everything else stays loud.\n (/No valid transcripts/i.test(m.message || '') ? log.debug : log.warn)(`cartesia: ${JSON.stringify(m)}`);\n }\n }\n };\n }\n\n /** Close the breaker only after CB_RECOVER_OK consecutive good frames, so a single straggler chunk\n * after a 503 burst doesn't flap open→recover in <1s. A sub-2s down-window is a transient blip → debug. */\n private markRecovered(): void {\n if (!this.down) return;\n if (++this.consecutiveOk < CartesiaTTS.CB_RECOVER_OK) return;\n this.down = false;\n this.consecutiveOk = 0;\n this.stopProbe();\n const downMs = this.downAt ? now() - this.downAt : 0;\n this.diag('tts_breaker_close', { downMs: Math.round(downMs) });\n (downMs < 2000 ? log.debug : log.info)(`TTS recovered${downMs ? ` (down ${downMs}ms)` : ''}`);\n }\n\n /** Ensure the WS is open before sending — reconnects if idle-closed. */\n private async ensureConnected(): Promise<void> {\n if (this.connecting) await this.connecting;\n if (this.ws?.readyState !== WebSocket.OPEN) await this.connect();\n }\n /** Prime the synthesis pipeline on a throwaway context right after connect: the FIRST synthesis on\n * a fresh WS pays Cartesia's cold spin-up (~1s+ live) — absorb it at mic-on instead of turn one.\n * The returned audio is discarded (engine drops onAudio while not speaking; once a real turn calls\n * newContext() any stragglers are stale-context-filtered). Respects the circuit breaker. */\n warmup(): void {\n if (this.down) return;\n this.newContext();\n // A real (synthesizable) word, not '.': Cartesia 400s a punctuation-only transcript with\n // \"No valid transcripts passed.\" — the warmup then primed nothing AND spliced a raw warn into\n // the REPL at voice start. The audio is discarded either way (engine gates onAudio on `speaking`).\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(this.frame('Ok.', false));\n }\n newContext(): string {\n this.ctxId = `ctx-${++this.ctxSeq}`;\n this.firstAudioAt = 0;\n return this.ctxId;\n }\n private frame(transcript: string, cont: boolean): string {\n return JSON.stringify({\n model_id: this.options.model,\n transcript,\n voice: { mode: 'id', id: this.options.voiceId },\n output_format: { container: 'raw', encoding: 'pcm_s16le', sample_rate: TTS_SAMPLE_RATE },\n context_id: this.ctxId,\n continue: cont,\n ...(this.wantTimestamps ? { add_timestamps: true } : {}),\n });\n }\n speak(text: string, cont: boolean): void {\n if (this.down) return;\n // An empty continuation has nothing to synthesize and Cartesia hard-400s on it (\"transcript must\n // not be empty when continue is true unless flushing\"). Deltas that sanitize to nothing (a chunk of\n // pure markdown/whitespace via forSpeech) hit this — drop them. The real flush is end()'s cont=false.\n if (cont && !text) return;\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(this.frame(text, cont));\n else void this.ensureConnected().then(() => this.ws?.readyState === WebSocket.OPEN && this.ws.send(this.frame(text, cont)));\n }\n end(): void {\n if (this.down) { this.onDone(); return; }\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(this.frame('', false));\n }\n cancel(): void {\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(JSON.stringify({ context_id: this.ctxId, cancel: true }));\n }\n private startProbe(): void {\n if (this.probeTimer) return;\n this.probeTimer = setInterval(() => {\n if (!this.down) { this.stopProbe(); return; }\n this.consecutiveErrors = 0;\n // bypass the `down` guard in speak() — send a probe frame directly\n this.newContext();\n if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(this.frame('Ok.', false)); // synthesizable probe — '.' 400s (\"No valid transcripts\") and would never close the breaker\n }, CartesiaTTS.CB_PROBE_MS);\n (this.probeTimer as any).unref?.();\n }\n private stopProbe(): void {\n if (this.probeTimer) { clearInterval(this.probeTimer); this.probeTimer = null; }\n }\n close(): void {\n this.closed = true;\n this.stopProbe();\n if (this.ws) this.ws.onclose = null as any;\n this.ws?.close();\n }\n}\n\n/** atob-based for browsers, Buffer for Bun/Node — both produce a Uint8Array. */\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof Buffer !== 'undefined') return Buffer.from(b64, 'base64');\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n","/** Shim — the voice engine is served from @bod.ee/voice (extracted from here).\n * Routes the extracted core's logs into agentx's libx.js logger. */\nimport { configureLogging } from '@bod.ee/voice';\nimport { forComponent } from '../logging';\n\nconfigureLogging((name) => {\n // libx.js log methods are fixed-arity in the type surface; cast to a rest\n // signature so forwarding a spread is legal under agentx's dts build.\n const l = forComponent(name) as unknown as Record<string, (...a: unknown[]) => void>;\n const at = (m: string) => (...a: unknown[]) => l[m]?.(...a);\n return { debug: at('debug'), verbose: at('verbose'), info: at('info'), warn: at('warn'), error: at('error') };\n});\n\nexport * from '@bod.ee/voice';\n","import type { AgentTool } from './tools';\nimport { topByRelevance } from './relevance';\n\n/**\n * MCP bridge — adapt a Model Context Protocol tool list into the agent's AgentTool[],\n * so any MCP server's tools become first-class agent tools (edge-safe: you supply the\n * transport via `callTool`; this module has no node/network dependency of its own).\n *\n * Pass the server's advertised tools + a `callTool(name, args)` that performs the call\n * (over stdio/HTTP/whatever you wire up); each becomes an AgentTool the Agent can use.\n */\nexport interface McpToolSpec {\n name: string;\n description?: string;\n /** JSON Schema for the tool's arguments (MCP's `inputSchema`). */\n inputSchema?: object;\n}\n\n/** Perform an MCP tool call; return its textual result. Throw to surface an error to the model. */\nexport type McpCall = (name: string, args: any) => Promise<unknown>;\n\nexport interface McpImage { mimeType: string; data: string }\nexport interface McpToolResult { text: string; images?: McpImage[] }\n\n/** Normalize an MCP call result into text + optional image blocks. */\nfunction toResult(result: unknown): McpToolResult {\n if (result == null) return { text: '' };\n if (typeof result === 'string') return { text: result };\n const content = (result as any).content;\n if (Array.isArray(content)) {\n const texts: string[] = [];\n const images: McpImage[] = [];\n for (const c of content) {\n if (c?.type === 'image' && typeof c.data === 'string' && c.mimeType) {\n images.push({ mimeType: c.mimeType, data: c.data });\n } else if (typeof c?.text === 'string') {\n texts.push(c.text);\n } else {\n texts.push(JSON.stringify(c));\n }\n }\n const text = texts.join('\\n');\n if (text || images.length) return { text, ...(images.length ? { images } : {}) };\n }\n return { text: JSON.stringify(result) };\n}\n\nfunction toText(result: unknown): string { return toResult(result).text; }\n\n/**\n * An MCP call had NO deadline of its own: a server that never answers hung the tool call forever, and\n * (declaring nothing) it was silently assumed prompt by every transport above the loop. Bound it here so\n * the tool can honestly declare `maxDurationMs`, and so a hung server produces a statement of what\n * happened rather than a stall.\n */\nexport const MCP_CALL_TIMEOUT_MS = 300_000;\nconst TIMED_OUT = Symbol('mcp-timeout');\nasync function withDeadline<T>(p: Promise<T>, ms: number): Promise<T | typeof TIMED_OUT> {\n let t: any;\n try {\n return await Promise.race([p, new Promise<typeof TIMED_OUT>((res) => { t = setTimeout(() => res(TIMED_OUT), ms); })]);\n } finally { clearTimeout(t); }\n}\nconst mcpTimedOut = (name: string, ms = MCP_CALL_TIMEOUT_MS) =>\n `[${name}] no response after ${ms / 1000}s — the MCP server never answered. The call's outcome is UNKNOWN: `\n + `do not assume it ran or that it failed. Verify the state (or pick a bounded/narrower call) before retrying.`;\n\n/** Adapt one MCP tool spec into an AgentTool backed by `callTool`. */\nexport function mcpToolToAgentTool(spec: McpToolSpec, callTool: McpCall, prefix = 'mcp__', timeoutMs = MCP_CALL_TIMEOUT_MS): AgentTool {\n return {\n name: `${prefix}${spec.name}`,\n description: spec.description ?? `MCP tool ${spec.name}`,\n parameters: spec.inputSchema ?? { type: 'object', properties: {} },\n maxDurationMs: timeoutMs,\n async run(args, _ctx) {\n const raw = await withDeadline(callTool(spec.name, args ?? {}), timeoutMs);\n if (raw === TIMED_OUT) return mcpTimedOut(spec.name, timeoutMs);\n const r = toResult(raw);\n return r.images?.length ? r : r.text;\n },\n };\n}\n\n/** Adapt a whole MCP tool list into AgentTool[] (names prefixed to avoid collisions).\n * Optional `filter` pre-narrows the set at mount time (host allowlist), so a server with\n * hundreds of tools needn't mount them all eagerly. */\nexport function mcpToolsToAgentTools(specs: McpToolSpec[], callTool: McpCall, prefix = 'mcp__', filter?: (spec: McpToolSpec) => boolean): AgentTool[] {\n return (filter ? specs.filter(filter) : specs).map((s) => mcpToolToAgentTool(s, callTool, prefix));\n}\n\nexport interface McpToolSearchOptions {\n /** Prefix stripped from / shown on tool names (cosmetic; mirrors the adapter prefix). Default 'mcp__'. */\n prefix?: string;\n /** Max tools returned per `ToolSearch` query. Default 10. */\n maxResults?: number;\n /** Per-call deadline for `McpCall`. Default MCP_CALL_TIMEOUT_MS. */\n timeoutMs?: number;\n}\n\n/** Render one spec for the search result: name, description, and its argument schema (so the\n * model knows how to call it via `McpCall`). */\nfunction describeSpec(s: McpToolSpec): string {\n const schema = s.inputSchema ? `\\n args: ${JSON.stringify(s.inputSchema)}` : '';\n return `${s.name} — ${s.description ?? '(no description)'}${schema}`;\n}\n\n/**\n * Deferred-mount mode (ToolSearch-equivalent) for large MCP tool sets. Instead of mounting N\n * tools into the wire schema (cost + latency + model confusion past a few dozen), mount exactly\n * TWO bounded tools regardless of N:\n * - `ToolSearch({ query })` — ranks the catalog by relevance and returns the top matches with\n * their argument schemas, so the model discovers what's available on demand.\n * - `McpCall({ name, args })` — invokes any catalog tool by name through the same transport.\n * Keep `mcpToolsToAgentTools` (eager) as the default for small sets.\n */\nexport function makeMcpToolSearch(specs: McpToolSpec[], callTool: McpCall, options: McpToolSearchOptions = {}): AgentTool[] {\n const maxResults = options.maxResults ?? 10;\n const callTimeoutMs = options.timeoutMs ?? MCP_CALL_TIMEOUT_MS;\n const byName = new Map(specs.map((s) => [s.name, s]));\n const catalogLine = `${specs.length} MCP tool(s) available — search by keyword, then call by exact name.`;\n\n const searchTool: AgentTool = {\n name: 'ToolSearch',\n description: `Search the available MCP tools by keyword (${catalogLine}). Returns matching tool names + their argument schemas; call one with \\`McpCall\\`.`,\n parameters: { type: 'object', required: ['query'], properties: { query: { type: 'string', description: 'keywords to match against tool name + description' } } },\n async run({ query }) {\n const q = String(query ?? '').trim();\n if (!q) return catalogLine;\n const { kept } = topByRelevance(specs, q, (s) => `${s.name} ${s.description ?? ''}`, maxResults);\n if (!kept.length) return `(no MCP tool matches \"${q}\" — try broader keywords)`;\n return kept.map(describeSpec).join('\\n');\n },\n };\n\n const callMcpTool: AgentTool = {\n name: 'McpCall',\n description: 'Call an MCP tool discovered via `ToolSearch`, by its exact name. Pass its arguments as `args`.',\n parameters: {\n type: 'object',\n required: ['name'],\n properties: {\n name: { type: 'string', description: 'exact tool name from ToolSearch' },\n args: { type: 'object', description: 'arguments object for the tool (per its schema)' },\n },\n },\n maxDurationMs: callTimeoutMs,\n async run({ name, args }) {\n const n = String(name ?? '');\n if (!byName.has(n)) return `Error: unknown MCP tool '${n}'. Use ToolSearch to find valid names.`;\n const raw = await withDeadline(callTool(n, args ?? {}), callTimeoutMs);\n if (raw === TIMED_OUT) return mcpTimedOut(n, callTimeoutMs);\n const r = toResult(raw);\n return r.images?.length ? r : r.text;\n },\n };\n\n return [searchTool, callMcpTool];\n}\n\n/** Minimal shape of a mounted MCP server this module needs — structurally satisfied by\n * `MountedMcp` from `mcp.client.ts`, kept local so `mcp.ts` stays node-free/edge-safe. */\nexport interface MountedMcpLike {\n name: string;\n specs: McpToolSpec[];\n client: { callTool(name: string, args: unknown): Promise<unknown> };\n}\n\n/** A flattened catalog entry's origin: which server owns it + the un-prefixed raw tool name. */\nexport interface McpRoute { server: string; rawName: string }\n\n/** Flatten servers' specs into one `mcp__<server>__<tool>` namespace + a display→origin map.\n * Sanitizing/truncating to provider name rules can MERGE distinct names (`a/b` & `a:b` → `a_b`),\n * so dedupe with a numeric suffix — a silent overwrite would orphan a tool. */\nexport function buildMcpCatalog(servers: { name: string; specs: McpToolSpec[] }[]): { specs: McpToolSpec[]; routes: Map<string, McpRoute> } {\n const specs: McpToolSpec[] = [];\n const routes = new Map<string, McpRoute>();\n for (const m of servers) {\n for (const s of m.specs) {\n const base = `mcp__${m.name}__${s.name}`.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 128);\n let display = base;\n for (let i = 2; routes.has(display); i++) display = `${base.slice(0, 128 - String(i).length - 1)}_${i}`;\n specs.push({ name: display, description: s.description, inputSchema: s.inputSchema });\n routes.set(display, { server: m.name, rawName: s.name });\n }\n }\n return { specs, routes };\n}\n\n/** Resolve a routed MCP call to its result. Throw to surface an error to the model. */\nexport type McpRouteResolver = (server: string, rawName: string, args: any) => Promise<unknown>;\n\n/** Shared core: wire the `ToolSearch`/`McpCall` pair over a prebuilt catalog, dispatching each\n * call through `resolve(server, rawName, args)` (eager → a mounted client; lazy → connect-on-call). */\nfunction searchOverCatalog(servers: string[], specs: McpToolSpec[], routes: Map<string, McpRoute>, resolve: McpRouteResolver, options?: McpToolSearchOptions) {\n const tools = specs.length\n ? makeMcpToolSearch(specs, (name, args) => {\n const r = routes.get(name);\n if (!r) throw new Error(`unknown MCP tool '${name}' — use ToolSearch to find valid names`);\n return resolve(r.server, r.rawName, args ?? {});\n }, options)\n : [];\n return { tools, serverNames: servers, toolCount: specs.length };\n}\n\n/**\n * Ergonomic deferred-mount over already-mounted MCP servers: flattens their specs into one\n * `mcp__<server>__<tool>` namespace and wires a single `ToolSearch`/`McpCall` pair that routes\n * each call to the owning server's RAW `callTool` (so result normalization happens exactly once —\n * double-normalizing corrupts image blocks).\n */\nexport function makeMcpToolSearchFromMounted(\n mounted: MountedMcpLike[],\n options?: McpToolSearchOptions,\n): { tools: AgentTool[]; serverNames: string[]; toolCount: number } {\n const { specs, routes } = buildMcpCatalog(mounted);\n const byName = new Map(mounted.map((m) => [m.name, m]));\n return searchOverCatalog(mounted.map((m) => m.name), specs, routes, (server, rawName, args) => byName.get(server)!.client.callTool(rawName, args), options);\n}\n\n/**\n * Lazy variant: same `ToolSearch`/`McpCall` surface, but the server isn't required to be connected.\n * Each `McpCall` resolves the owning server from the catalog and `resolve(server, rawName, args)`\n * connects-on-demand — so a turn that calls no MCP tool opens ZERO connections. Edge-safe: the\n * caller (`mountMcpCatalog` in `mcp.client.ts`) supplies the node-side connect/pool logic.\n */\nexport function makeLazyMcpToolSearch(\n servers: { name: string; specs: McpToolSpec[] }[],\n resolve: McpRouteResolver,\n options?: McpToolSearchOptions,\n): { tools: AgentTool[]; serverNames: string[]; toolCount: number } {\n const { specs, routes } = buildMcpCatalog(servers);\n return searchOverCatalog(servers.map((s) => s.name), specs, routes, resolve, options);\n}\n","/**\n * Hooks — deterministic interception points around tool execution, run by the\n * harness/host (mirrors Claude Code hooks). The seam stays edge-safe: hooks are\n * plain async callbacks, no node builtins, injected via AgentOptions.hooks.\n *\n * - preToolUse: fires BEFORE a tool runs. Return `{ block: true, reason }` to\n * skip the tool — Agent.dispatch returns `Blocked by hook: <reason>`\n * as the tool result (the model sees it and can adapt).\n * - postToolUse: fires AFTER a tool produced its result string (observe/audit).\n * - onStop: fires once when the loop terminates with finishReason 'stop'.\n */\nimport type { Message } from './llm';\n\nexport interface ToolUse {\n name: string;\n args: any;\n}\n\nexport interface PreToolUseDecision {\n block?: boolean;\n reason?: string;\n}\n\n/** Per-call metadata threaded through dispatch — `id` is the model-supplied tool_call id,\n * letting a host correlate a result to its call without assuming serial dispatch order. */\nexport interface ToolUseMeta {\n id?: string;\n}\n\nexport interface Hooks {\n /** Guard a tool call before it runs; return `{ block, reason }` to skip it. */\n preToolUse?(call: ToolUse, meta?: ToolUseMeta): Promise<PreToolUseDecision | void> | PreToolUseDecision | void;\n /** Observe a tool's result after it ran (audit, metrics, side-channel). */\n postToolUse?(call: ToolUse, result: string, meta?: ToolUseMeta): void | Promise<void>;\n /** Observe a tool's INCREMENTAL output while it runs (only tools that stream, e.g. the real\n * Shell). Fire-and-forget — sync, never awaited, never alters the result. */\n onToolOutput?(call: ToolUse, chunk: string, meta?: ToolUseMeta): void;\n /** Fired once when the agent loop stops cleanly with the model's final text. */\n onStop?(finalText: string): void;\n // --- lifecycle (all optional; fired from well-known points in run/send/compact) ---\n /** Fired once at session start (a fresh `run()`, or the first `send()`). Return a string to inject\n * as extra system context (e.g. environment facts, project status). Multiple hooks concatenate. */\n onSessionStart?(): string | void | Promise<string | void>;\n /** Fired per user turn BEFORE the model call. Return a string to replace the submitted text\n * (rewrite/annotate the prompt); chained across hooks. Return void to leave it unchanged. */\n onUserPromptSubmit?(text: string): string | void | Promise<string | void>;\n /** Fired before a manual `compactNow()` folds older messages — observe (e.g. persist a summary). */\n onPreCompact?(messages: Message[]): void | Promise<void>;\n /** Fired when a `Task`/`TaskBatch` child agent finishes, with its summary + label. */\n onSubagentStop?(summary: string, info?: { label?: string; agentType?: string }): void | Promise<void>;\n}\n\n/** Deterministic Hooks for tests/dev: records calls + scripts block decisions by tool name. */\nexport class RecordingHooks implements Hooks {\n public pre: Array<{ call: ToolUse; meta?: ToolUseMeta }> = [];\n public post: Array<{ call: ToolUse; result: string; meta?: ToolUseMeta }> = [];\n public outputs: Array<{ call: ToolUse; chunk: string; meta?: ToolUseMeta }> = [];\n public stops: string[] = [];\n /** tool name -> reason; a matching preToolUse call is blocked with that reason. */\n constructor(private blocks: Record<string, string> = {}) {}\n preToolUse(call: ToolUse, meta?: ToolUseMeta): PreToolUseDecision | void {\n this.pre.push({ call, meta });\n const reason = this.blocks[call.name];\n if (reason != null) return { block: true, reason };\n }\n postToolUse(call: ToolUse, result: string, meta?: ToolUseMeta): void {\n this.post.push({ call, result, meta });\n }\n onToolOutput(call: ToolUse, chunk: string, meta?: ToolUseMeta): void {\n this.outputs.push({ call, chunk, meta });\n }\n onStop(finalText: string): void {\n this.stops.push(finalText);\n }\n}\n\n/** Recording lifecycle hooks for tests: capture session-start/prompt-submit/pre-compact + script transforms. */\nexport class RecordingLifecycle implements Hooks {\n public starts = 0;\n public prompts: string[] = [];\n public compactions: number[] = [];\n /** @param startContext injected at session start; @param rewrite maps a submitted prompt to a new one. */\n constructor(private startContext?: string, private rewrite?: (t: string) => string) {}\n public subagentStops: Array<{ summary: string; label?: string }> = [];\n onSessionStart(): string | void { this.starts++; return this.startContext; }\n onUserPromptSubmit(text: string): string | void { this.prompts.push(text); return this.rewrite?.(text); }\n onPreCompact(messages: Message[]): void { this.compactions.push(messages.length); }\n onSubagentStop(summary: string, info?: { label?: string }): void { this.subagentStops.push({ summary, label: info?.label }); }\n}\n"],"mappings":"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","names":["log","path","norm","i","log","res","log","realpathSync","now","ctx","resolve","log","NO_JOB","slug","MAX_CATALOG","parseFrontmatter","slug","l","slug","mkdirSync","join","statSync","readFileSync","slug","log","slug","mkdirSync","join","fs","wtHandle","childOpts","rememberTool","log","NodeDiskFilesystem","JailedFilesystem","o","imgs","PathResolver","now","backend","id","makeRealShellTool","makeShellJobTools","ShellJobRegistry","formatJobExit","log","log","log","slug","MemFilesystem","forComponent","log","forComponent","log","log","forComponent","norm","now","text","log","forComponent","log","forComponent","now","log","MemFilesystem","resolve","resolve","MemFilesystem","CommandExecutor","registerHeadlessCommands"]}