agent.libx.js 0.94.24 → 0.94.25

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/redact.ts","../src/tools.structured.ts","../src/todo.ts","../src/logging.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/llm.ts","../src/Agent.ts","../src/tools.jobs.ts","../src/host.ts","../src/relevance.ts","../src/frontmatter.ts","../src/skills.ts","../src/commands.ts","../src/memory.ts","../src/instructions.ts","../src/subagent.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","../src/mcp.ts","../src/hooks.ts","../src/voice/engine.ts","../src/voice/soniox.ts","../src/voice/types.ts","../src/voice/cartesia.ts"],"sourcesContent":["/**\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/** 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. */\nasync function walkFiles(fs: IFilesystem, dir: string, signal?: AbortSignal, out: string[] = []): Promise<string[]> {\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 const p = dir === '/' ? `/${name}` : `${dir}/${name}`;\n if (await fs.isDirectory(p)) await walkFiles(fs, p, signal, out);\n else out.push(p);\n }\n return out;\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 const globTool: AgentTool = {\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\"). Prefer over `bash find` for locating files — one call, structured output.',\n parameters: {\n type: 'object',\n required: ['pattern'],\n properties: { pattern: { type: 'string', description: 'glob pattern(s); ** matches across directories; prefix a pattern with ! to exclude' } },\n },\n async run({ pattern }, ctx) {\n const pats = String(pattern ?? '').trim().split(/\\s+/).filter(Boolean);\n const include = pats.filter((p) => !p.startsWith('!')).map((p) => anchoredGlob(ctx.fs, p));\n const exclude = pats.filter((p) => p.startsWith('!')).map((p) => anchoredGlob(ctx.fs, p.slice(1)));\n const includes = include.length ? include : [anchoredGlob(ctx.fs, '**')]; // only-excludes → start from everything\n const hits = (await walkFiles(ctx.fs, fsCwd(ctx.fs), ctx.signal)).filter(\n (p) => includes.some((re) => re.test(p)) && !exclude.some((re) => re.test(p)),\n );\n return hits.length ? hits.join('\\n') : '(no matches)';\n },\n};\n\n/** Search file contents by regex, returning typed `path:line:text` hits with optional context. */\nexport const grepTool: AgentTool = {\n name: 'Grep',\n description:\n 'Search file contents by regex. Returns `path:line: text` hits. Optional `glob` to scope files, `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 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, 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 scope = glob ? anchoredGlob(ctx.fs, String(glob)) : null;\n const files = (await walkFiles(ctx.fs, fsCwd(ctx.fs), ctx.signal)).filter((p) => !scope || scope.test(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'}]` : '';\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/** 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/** 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 >`.',\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 if (ctx.lint) { const err = ctx.lint(path, body); if (err) throw new Error(err); }\n await mkdirp(ctx.fs, parentDir(ctx.fs.resolvePath(path)));\n await ctx.fs.writeFile(path, body);\n ctx.readState.set(ctx.fs.resolvePath(path), 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). 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 === '') { planned.set(p, neu); continue; } // whole-file write / create\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 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","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 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/agent.libx.js)' } });\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) uses Tavily if an API key is present, else keyless DuckDuckGo. */\n provider?: 'auto' | 'tavily' | 'duckduckgo';\n /** API key for Tavily (default: process.env.TAVILY_API_KEY). */\n apiKey?: string;\n /** Tavily endpoint override. */\n endpoint?: string;\n maxResults?: number; // default 5\n timeoutMs?: number; // default 15s\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/**\n * Build a WebSearch tool. Keyless by default (DuckDuckGo HTML) so it works in any deployment with\n * no setup; auto-upgrades to Tavily (better, agent-oriented results) when TAVILY_API_KEY is present.\n */\nexport function makeWebSearchTool(options: WebSearchOptions = {}): AgentTool {\n const tavilyEndpoint = options.endpoint ?? 'https://api.tavily.com/search';\n const maxResults = options.maxResults ?? 5;\n const timeoutMs = options.timeoutMs ?? 15_000;\n return {\n name: 'WebSearch',\n 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 provider = options.provider ?? 'auto';\n const useTavily = provider === 'tavily' || (provider === 'auto' && !!key);\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), timeoutMs);\n try {\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/agent.libx.js)' },\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();\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 { grepTool, globTool, writeTool, multiEditTool, applyEditsTool, repoMapTool, reviewTool, fuzzyLineReplace } from './tools.structured';\nimport { todoWriteTool, type TodoItem } from './todo';\nimport { webFetchTool, webSearchTool } from './tools.web';\nimport { OverlayFilesystem } from './OverlayFilesystem';\nimport { redactSecrets, CONFIG_FILE_RE } from './redact';\nimport type { SandboxJobRegistry } from './tools.jobs';\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: '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 | { 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}\n\nexport interface AgentTool {\n name: string;\n description: string;\n parameters: object; // JSON Schema for the function's arguments\n run(args: any, ctx: ToolContext): Promise<string | { text: string; images?: { mimeType: string; data: string }[] }>;\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). */\nconst IMG_MIME: Record<string, string> = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', webp: 'image/webp' };\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> };\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 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 ctx.readState.set(ctx.fs.resolvePath(path), raw); // staleness guard tracks the REAL content\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];\n return Object.fromEntries(all.map((t) => [t.name, t]));\n}\n\n/** Resolve a list of tool names against the registry (unknown names throw). */\nexport function toolsByName(names: string[]): AgentTool[] {\n const reg = toolRegistry();\n return names.map((n) => {\n const t = reg[n];\n if (!t) throw new Error(`unknown tool '${n}'. Known: ${Object.keys(reg).join(', ')}`);\n return t;\n });\n}\n","import { promises as fsp } 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 /** 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 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: { cwd?: string; env?: Record<string, string | undefined>; signal?: AbortSignal },\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}\n\nexport interface RealShellOptions {\n /** Working directory the shell is bound to (typically a NodeDiskFilesystem `baseDir`). Required. */\n cwd: 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 /** 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}\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\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) });\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}`); } });\n proc.on('close', (code: number | null) => { if (job.status === 'running') { job.status = 'exited'; job.exitCode = code ?? undefined; } });\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 /** 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 kill(id: string): boolean {\n const j = this.jobs.get(id);\n if (!j) return false;\n if (j.status === 'running') { 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 timeoutMs = options.timeoutMs ?? 120_000;\n return {\n name: 'Shell',\n description:\n '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 'Set `background:true` for long-running processes (servers, watchers) — returns a job id immediately; poll with ShellOutput, stop with ShellKill.',\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 },\n },\n async run({ command, background }, ctx) {\n const cmd = String(command ?? '');\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: '/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 const timer = setTimeout(() => { timedOut = true; ctl.abort(); }, timeoutMs);\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 });\n } catch (e: any) {\n return finish(`[exit 1] failed to spawn shell: ${e?.message ?? e}`);\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/** Abort message: timeout vs external cancel, preserving any partial output. */\nfunction reasonFor(timedOut: boolean, timeoutMs: number, body: string): string {\n const head = timedOut ? `[exit 124] timed out after ${timeoutMs}ms (killed)` : '[exit 130] cancelled (killed)';\n return body ? `${head}\\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. */\nexport function makeShellJobTools(registry: ShellJobRegistry): AgentTool[] {\n const idParam = { type: 'object', properties: { id: { type: 'string', description: 'the job id from Shell({background:true})' } } };\n return [\n {\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 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 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","/**\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\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\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}\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 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","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike, ChatResponse, Message, StreamChunk, ToolCall, MessageContent, ContentPart } from './llm';\nimport { contentText, imagePart } from './llm';\nimport { type AgentTool, type ToolContext, type HostBridge, defaultTools, makeContext, toWireTools, truncateOutput } from './tools';\nimport { SandboxJobRegistry, makeJobTools } from './tools.jobs';\nimport { askUserQuestionTool } from './host';\nimport { loadSkills } from './skills';\nimport { loadCommands } from './commands';\nimport { loadMemory } from './memory';\nimport { loadInstructions } from './instructions';\nimport { makeTaskTool, makeTaskBatchTool } from './subagent';\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/** 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 finishReason: 'stop' | 'max_steps' | 'budget' | 'timeout' | 'loop' | 'max_tool_calls' | 'aborted' | 'error';\n messages: Message[];\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 error?: unknown;\n}\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. 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 '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 /** Wall-clock ceiling in ms for the whole run. 0 = unbounded. */\n timeoutMs = 120_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 /** 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 /** 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 /** 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 /** 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 /** Stream tokens from the model. Takes effect only with a `host.notify`; off => current (non-stream) behavior. */\n stream = false;\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 /** 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}\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 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\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 /** 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. */\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 return before - this.activeTools.length;\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 if (o.skillsDir) {\n // taskHint floats the most relevant skills to the top of a large catalog; full set stays loadable by name.\n const { catalog, tool } = await loadSkills(fs, o.skillsDir, { relevanceHint: taskHint });\n if (catalog) systemPrompt += '\\n\\n' + catalog;\n if (tool) tools = [...tools, tool];\n }\n if (o.commandsDir) {\n const { catalog, tool } = await loadCommands(fs, o.commandsDir, { relevanceHint: taskHint });\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 const taskOpts = { ai: o.ai, model: o.model, fs, depth: o.depth, maxDepth: o.maxDepth, agents, hooks: o.hooks };\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 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 { role: 'user', content: 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`): keep the system message + the\n * most-recent window, summarizing the dropped middle (deterministic, no LLM call).\n * No-op when the transcript already fits. Returns the number of messages removed.\n * `focus` (e.g. from `/compact keep the API details`) preserves matching lines from the\n * dropped span verbatim in the summary, instead of losing them to the generic recap.\n */\n compactNow(maxMessages = 12, focus?: string): number {\n const max = Math.max(2, maxMessages);\n if (this.transcript.length <= max) return 0;\n void this.activeHooks?.onPreCompact?.(this.transcript); // [lifecycle] observe before folding (fire-and-forget)\n const before = this.transcript.length;\n this.transcript = compact(this.transcript, max, focus);\n return before - this.transcript.length;\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 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 // 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}${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 return { text: lastAssistantText(this.transcript), steps, finishReason, messages: this.transcript, usage, usageEstimated };\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() - start - this.parkedMs >= o.timeoutMs) return kill('timeout'); // active wall-clock: idle 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 // Cursor is an agent runtime — bridge host tools via IPC-based toolExecutor callback.\n const isCursorWithTools = o.model.startsWith('cursor/') && wireTools.length > 0;\n const cursorPo = isCursorWithTools ? {\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 const raw = await this.dispatch(tc);\n return typeof raw === 'string' ? raw : raw.text;\n },\n } : undefined;\n const reasonOpts = {\n ...frag,\n ...(o.promptCache ? { promptCache: true } : {}),\n ...(o.providerOptions || cursorPo ? { providerOptions: { ...frag.providerOptions, ...o.providerOptions, ...cursorPo } } : {}),\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 const r = await o.ai.chat({ model: o.model, messages: sent, tools: wireTools, stream: true, signal: o.signal, ...(o.toolChoice ? { toolChoice: o.toolChoice } : {}), ...reasonOpts });\n res = await this.consumeStream(r as AsyncIterable<StreamChunk>);\n } else {\n const r = await o.ai.chat({ model: o.model, messages: sent, tools: wireTools, stream: false, signal: o.signal, ...(o.toolChoice ? { toolChoice: o.toolChoice } : {}), ...reasonOpts });\n res = r as ChatResponse;\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 transient = !o.signal?.aborted && !isAbortError(err) && attempt < 2 && (network || serverSide);\n if (!transient) throw err;\n const waitMs = 1000 * (attempt + 1);\n log.warn(`network drop mid-step (${(err as any)?.message ?? err}) — retrying in ${waitMs}ms`);\n o.host?.notify?.({ kind: 'retry', message: `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 // An aborted fetch surfaces as a thrown provider error. The signal flag can LAG the throw under\n // a barge-in race (the controller fires, the provider rejects, but o.signal.aborted hasn't\n // settled yet), so match the provider's abort message too — else a clean cancel is logged as a\n // crash AND its \"operation was aborted\" string leaks onto the spoken/utterance line.\n if (o.signal?.aborted || isAbortError(err)) return kill('aborted');\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 log.error(`chat() failed: ${(err as any)?.message ?? err}${bodyStr ? ` — ${bodyStr}` : ''}`, err);\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 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 const emptyTurn = toolCalls.length === 0 && contentText(res.content ?? '').trim() === '';\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 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 await this.activeHooks?.onStop?.(res.content ?? ''); // [hooks] fire once on clean stop\n return { text: res.content ?? '', steps, finishReason: 'stop', messages: this.transcript, usage, usageEstimated };\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 = raw; }\n else {\n const parts: ContentPart[] = [{ type: 'text', text: raw.text }];\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 }\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 private async consumeStream(stream: AsyncIterable<StreamChunk>): Promise<ChatResponse> {\n let content = '';\n let finishReason: string | undefined;\n let toolCalls: ToolCall[] | undefined;\n let usage: ChatResponse['usage'];\n for await (const chunk of stream) {\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 if (chunk.content) {\n content += 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 return { content, ...(finishReason ? { finishReason } : {}), ...(toolCalls ? { toolCalls } : {}), ...(usage ? { usage } : {}) };\n }\n\n private async dispatch(tc: ToolCall): Promise<string | { text: string; images?: { mimeType: string; data: string }[] }> {\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 const cap = this.options.maxToolResultBytes ?? 0;\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 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 if (o.keepToolOutputs) out = stubOldToolResults(out ?? m, o.keepToolOutputs);\n if (o.maxContextTokens) {\n const pre = (out ?? m).length;\n out = fitTokenBudget(out ?? m, o.maxContextTokens);\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 return dropOrphanToolResults(out ?? m);\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/** ~4 chars/token estimate over content + serialized tool_calls. */\nfunction estimateTokens(m: Message[]): number {\n let chars = 0;\n for (const x of m) chars += contentText(x.content).length + (x.tool_calls ? JSON.stringify(x.tool_calls).length : 0);\n return Math.ceil(chars / 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. */\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/** 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): 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).\n const per = messages.map((x) => estimateTokens([x]));\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/** Lightweight, deterministic, LLM-free recap of a span of messages. */\nfunction summarize(messages: Message[], focus?: string): string {\n const tools = new Set<string>();\n const files = new Set<string>();\n let lastAssistant = '';\n for (const msg of messages) {\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 of ${messages.length} 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 // 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 outer: for (const msg of messages) {\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`. Registered only when a HostBridge is provided\n * (autonomous runs don't see it), so it never dead-ends a headless agent.\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 (ambiguous requirement, a fork you cannot resolve from context). Returns their selection.',\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 const fallback = args.options?.[0]?.label ?? '';\n return `No interactive user is available — proceed using your best judgment.${fallback ? ` (Closest default: \"${fallback}\")` : ''}`;\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 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 } = {},\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 by name — returns its full instructions (SKILL.md). Use when a task matches a listed skill.',\n parameters: { type: 'object', required: ['name'], properties: { name: { type: 'string' } } },\n async run({ name }, ctx: ToolContext) {\n let s = skills.find((x) => x.name === name);\n if (!s) { // miss → rescan: skills created mid-conversation are loadable without a reprepare\n const fresh = await scanSkills(ctx.fs, dir);\n s = fresh.find((x) => x.name === name);\n if (!s) return `Error: no skill named '${name}'. Available: ${fresh.map((x) => x.name).join(', ')}`;\n skills.push(s);\n }\n return ctx.fs.readFile(s.path);\n },\n };\n return { skills, 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';\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/** 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/** 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 const { body } = parseFrontmatter(await fs.readFile(cmd.path));\n return embedFiles(expandTemplate(body, args), fs);\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 } = {},\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 by name — returns its expanded prompt template (with your `args` substituted/appended). Use when a task matches a listed command.',\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 if (!c) { // miss → rescan: commands created mid-conversation are runnable without a reprepare\n const fresh = await scanCommands(ctx.fs, dir);\n c = fresh.find((x) => x.name === slug);\n if (!c) return `Error: no command named '${slug}'. Available: ${fresh.map((x) => x.name).join(', ')}`;\n commands.push(c);\n }\n return expandCommand(ctx.fs, c, String(args ?? ''));\n },\n };\n return { commands, 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 type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike } from './llm';\nimport type { AgentTool, ToolContext } from './tools';\nimport { toolsByName } from './tools';\nimport type { AgentDef } from './agents';\nimport type { Hooks } from './hooks';\nimport { Agent } from './Agent';\nimport { OverlayFilesystem } from './OverlayFilesystem';\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\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): 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 const childOpts: ConstructorParameters<typeof Agent>[0] = { ai: opts.ai, fs, model: def?.model ?? opts.model, subagents: true, depth: depth + 1, maxDepth };\n if (opts.maxSteps != null) childOpts.maxSteps = opts.maxSteps;\n if (def?.systemPrompt) childOpts.systemPrompt = def.systemPrompt;\n if (def?.tools?.length) {\n try { childOpts.tools = toolsByName(def.tools); }\n catch (e) { return `subagent '${agentType}' declares an unknown tool — ${(e as Error).message}`; }\n }\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 returns a concise summary — use to isolate context-heavy work (broad search, a scoped refactor). Provide a short `description` and a full `prompt`. Set `background: true` to run it detached (returns a job id to poll with JobOutput while you keep working); its file edits are overlay-isolated and commit when it finishes.',\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 background: { type: 'boolean', description: 'run detached (overlay-isolated, commits on finish); returns a job id to poll with JobOutput instead of blocking' },\n },\n },\n async run({ description, prompt, agentType, background }, 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 // 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 const overlay = new OverlayFilesystem(opts.fs); // write-isolation: parent VFS untouched until commit\n const childOpts = childOptionsFor(opts, overlay, depth, maxDepth, agentType);\n if (typeof childOpts === 'string') throw new Error(childOpts);\n childOpts!.signal = signal; // killing the job aborts the child's run loop\n const res = await new Agent(childOpts).run(String(prompt ?? ''));\n if (signal.aborted) return '[killed before commit]';\n await overlay.commit(); // flush the child's edits down into the parent VFS\n const summary = res.text || `(child '${label}' finished with no summary; finishReason=${res.finishReason})`;\n await opts.hooks?.onSubagentStop?.(summary, { label, agentType });\n return summary;\n }, { kind: 'agent', label });\n return `Started background sub-task ${id} ('${label}') — poll with JobOutput({id:\"${id}\"}).`;\n }\n\n // The child gets subagents enabled but one level deeper, so it can recurse\n // up to maxDepth; at the ceiling its own Task tool refuses (see guard above).\n const childOpts = childOptionsFor(opts, opts.fs, depth, maxDepth, agentType);\n if (typeof childOpts === 'string') return `Error: ${childOpts}`;\n const child = new Agent(childOpts);\n const res = await child.run(String(prompt ?? ''));\n const summary = res.text || `(child agent finished '${label}' with no summary; finishReason=${res.finishReason})`;\n await opts.hooks?.onSubagentStop?.(summary, { label, agentType });\n return summary;\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 (its file edits are merged back in array order). Use for parallel fan-out (review/search/scoped refactors across files). Provide `tasks: [{ description, prompt, agentType? }]`.',\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 },\n },\n },\n },\n },\n async run({ tasks }, _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\n type Outcome = { label: string; text?: string; error?: string; overlay?: OverlayFilesystem; 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 const overlay = new OverlayFilesystem(opts.fs); // write-isolation: siblings can't see each other's edits\n const childOpts = childOptionsFor(opts, overlay, depth, maxDepth, t?.agentType);\n if (typeof childOpts === 'string') return { label, error: childOpts, ok: false };\n try {\n const res = await new Agent(childOpts).run(String(t?.prompt ?? ''));\n await opts.hooks?.onSubagentStop?.(res.text, { label, agentType: t?.agentType });\n return { label, text: res.text, overlay, ok: res.finishReason !== 'error' };\n } catch (e) { return { label, error: e instanceof Error ? e.message : String(e), ok: false }; }\n });\n\n // Merge successful children's edits into the shared fs, in array order (deterministic last-writer-wins).\n for (const r of results) if (r.ok && r.overlay) await r.overlay.commit().catch(() => {});\n\n return results\n .map((r, i) => `### ${i + 1}. ${r.label}\\n${r.error ? `ERROR: ${r.error}` : (r.text || '(no summary)')}`)\n .join('\\n\\n');\n },\n };\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 for (const r of this.options.rules) {\n if (r.tool && r.tool !== call.name) 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 if (r?.remember) this.options.rules.unshift({ tool: call.name, 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","// agent.libx.js — edge-native AI agent runtime over a virtual filesystem.\n\nexport { Agent, AgentOptions } from './Agent';\nexport type { RunResult } from './Agent';\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, writeTool, multiEditTool, applyEditsTool, repoMapTool, repoIndex, mkdirp } from './tools.structured';\nexport { todoWriteTool } from './todo';\nexport { webFetchTool, webSearchTool, makeWebFetchTool, makeWebSearchTool, 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 } from './commands';\nexport type { CommandInfo } 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 } from './llm';\nexport { reasoningToChatFragment } from './reasoning';\nexport type { ReasoningEffort, ChatFragment } from './reasoning';\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(opts: Partial<AgentOptions> & { cwd?: string } = {}): Promise<Partial<AgentOptions>> {\n const { makeRealShellTool, makeShellJobTools, ShellJobRegistry } = await import('./tools.shell');\n const { cwd = process.cwd(), tools, ...rest } = opts;\n const registry = new ShellJobRegistry({ cwd, killOnExit: true });\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. Results are pushed back as\n * `[task <id> completed] …` events and re-voiced by the reflex — 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';\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}\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 /** 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\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' +\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 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. 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.\\n' +\n 'Results arrive later as events like \"[task t1 completed] …\" or \"[task t1 failed] …\". When one arrives, speak the USEFUL gist in one or two short sentences — the actual answer the user wanted (the headline finding, the key numbers), not the thinnest possible \"it\\'s done\". A forecast → say it\\'s calm AND that it\\'s good for swimming but not surf; a count → say the number. Be brief, but do not drop the substance. ' +\n 'If the result is a LIST (search results, multiple files/matches), the user CANNOT see it — there is no screen and no numbered menu to point at. Speak the gist: say what you found and name the top one or two by NAME (the source, not \"the first one\" or a number), then ask plainly if they want more. Never ask them to \"pick which one\" or reference items by position. ' +\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 — give at most a half-sentence aside (\"still on it — running tests now\") and end your turn. 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, just say \"still on it\" and end the turn — never poll it again and again in a loop. 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 or surprising, briefly confirm what they meant (\"did you mean…?\") instead of answering the literal words.';\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/**\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 private pendingEvents: string[] = [];\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 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 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 /** 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 /** 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 + `\\nToday's date: ${new Date().toDateString()}.`;\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.fabricationCut) return; // already cut this turn → drop the tail\n const msg = (ev as any).message as string;\n this.reflexBuf += msg;\n const m = this.reflexBuf.match(RESERVED_EVENT_MARKER);\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 host.notify?.({ ...ev, message: safe } as any);\n return;\n }\n this.reflexForwarded = this.reflexBuf.length;\n if (msg.trim()) this.spokeThisTurn = true;\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 /** 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.turnBriefs.clear();\n this.spokeThisTurn = false;\n this.reflexBuf = '';\n this.reflexForwarded = 0;\n this.fabricationCut = false;\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 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 /** True when the just-finished turn dispatched a task but voiced nothing — dead air to repair.\n * Requires a host: without one there's no stream to detect speech on (and no one to speak to). */\n private get silentDispatch(): boolean {\n return !!this.options.host && this.turnDispatched && !this.spokeThisTurn;\n }\n\n /** A dispatch with no spoken text is dead air. Re-prompt the reflex ONCE so the LLM itself voices a\n * short ack (no template). If it STILL says nothing, fall back to a minimal line so silence never ships. */\n private async ackIfSilent(): Promise<void> {\n this.nudging = true;\n try {\n await this.voice.send('[reminder] You dispatched a task but said nothing to the user. Say ONE short spoken acknowledgement 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 (!this.spokeThisTurn) this.options.host?.notify?.({ kind: 'text_delta', message: 'Okay, on it.' });\n }\n\n /** One user turn: the voice agent streams the reply (and may Act/Think). Serialized with re-voice turns. */\n send(content: MessageContent): Promise<RunResult> {\n return this.enqueue(async () => {\n await this.initMemory();\n this.resetTurn();\n const res = await this.voice.send(content);\n if (this.silentDispatch) await this.ackIfSilent();\n return res;\n });\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 /** 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.options.host?.notify?.({ kind, message, data });\n }\n\n /** Queue a `[task …]` event for re-voicing. Events arriving while the voice is busy coalesce into ONE turn. */\n private queueRevoice(event: string): void {\n this.pendingEvents.push(event);\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 if (!events.length) return;\n this.resetTurn();\n await this.voice.send(events.join('\\n'));\n if (this.silentDispatch) await this.ackIfSilent();\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'): 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 return (recent ? `${brief}\\n\\n## Recent conversation (for context)\\n${recent}` : brief) + verify;\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 = 'act'): 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 const workerHost: HostBridge | undefined = o.askRelay ? { ask: relayAsk } : o.host?.ask ? { ask: (q) => o.host!.ask!(q) } : undefined;\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 ...(workerHost ? { host: workerHost } : {}),\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 .then((res) => this.maybeVerify(id, briefText, res, tier, agentOpts))\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 });\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, briefText: string, res: RunResult, tier: WorkerTier, agentOpts: Partial<AgentOptions>): 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 const checkBrief = `${briefText}\\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(agentOpts).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 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 log.verbose(`task ${id} done (${res.steps} steps)`);\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 steps: res.steps, toolCalls: res.messages.filter((m) => m.role === 'tool').length,\n });\n this.queueRevoice(`[task ${id} completed] ${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 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 this.queueRevoice(`[task ${rec.id} failed] ${msg}`);\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 async dispatch(brief: string, tier: WorkerTier = 'act', label?: string): Promise<string> {\n if (tier === 'think' && this.options.thinkModel === false) tier = 'act';\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);\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.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);\n return `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.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);\n return `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 names = await fs.readDir(String(path ?? '.'));\n return names.slice(0, 50).join('\\n') + (names.length > 50 ? `\\n… (+${names.length - 50} more)` : '');\n }\n case 'file': {\n if (!fs) return 'unavailable (no filesystem)';\n if (!path) return 'file lookup needs a path';\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 }\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 if (filler) this.notify('hold_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","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/** Adapt one MCP tool spec into an AgentTool backed by `callTool`. */\nexport function mcpToolToAgentTool(spec: McpToolSpec, callTool: McpCall, prefix = 'mcp__'): AgentTool {\n return {\n name: `${prefix}${spec.name}`,\n description: spec.description ?? `MCP tool ${spec.name}`,\n parameters: spec.inputSchema ?? { type: 'object', properties: {} },\n async run(args, _ctx) {\n const r = toResult(await callTool(spec.name, args ?? {}));\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}\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 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 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 r = toResult(await callTool(n, args ?? {}));\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","/**\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 type { AudioSink, VoiceState } from './types';\n\nconst log = forComponent('VoiceEngine');\nconst now = () => performance.now();\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 .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\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 start(): Promise<void> | void;\n reset(): void;\n stop(): void;\n}\nexport interface TtsLike {\n onAudio: (chunk: Uint8Array) => void;\n onDone: () => void;\n connect(): Promise<void> | 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 /** 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 /** 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): partial text while\n * speaking → PAUSE (exact-sample hold); partial grows into dominant-novel ≥2 words → cede\n * (interrupt; the LLM re-enters); partial stalls/endpoints without ceding (backchannel by\n * 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}\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 drainTimer: ReturnType<typeof setTimeout> | null = 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 pendingUtt = ''; // endpointed text held for the merge window\n private pendingTimer: ReturnType<typeof setTimeout> | null = null;\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: ReturnType<typeof setTimeout> | null = null;\n private turnStartAt = 0; // timestamp when the current turn began (for TTFT logging)\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 }\n\n async start(): Promise<void> {\n this.tts.onAudio = (c) => { if (this.speaking) this.player.write(c); };\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 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 private idleWaiters: (() => void)[] = [];\n private setState(s: VoiceState): void {\n if (this.state === s) return;\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) { clearTimeout(this.drainTimer); this.drainTimer = null; }\n this.interrupted = false; // a new turn re-arms speech\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 if (!this.speaking) this.player.markTurn();\n this.speaking = true;\n this.ctxOpen = true;\n this.spokeDeltas = false;\n this.reply = '';\n this.echoWords = new Set(this.words(this.prevReply)); // previous reply's echo may still be in flight\n this.tts.newContext();\n if (ack && this.options.ackPhrase) { this.tts.speak(this.options.ackPhrase + ' ', true); this.spokeDeltas = true; this.ackAt = now(); }\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 = now();\n this.setState('thinking');\n }\n speakDelta(text: string): void {\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 if (!this.speaking || !this.ctxOpen) this.beginSpeech();\n this.reply += text;\n for (const w of this.words(this.reply)) this.echoWords.add(w);\n this.tts.speak(forSpeech(text), true); // strip markdown punctuation so TTS doesn't read \"dash\"/\"star\"/\"hash\" aloud\n if (!this.spokeDeltas && this.turnStartAt) log.debug(`ttft: ${Math.round(now() - this.turnStartAt)}ms`);\n this.spokeDeltas = true;\n this.setState('speaking');\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 if (!this.speaking) return;\n this.ctxOpen = false; // context ends now; audio keeps draining\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 = setTimeout(settle, 250); return; } // held by an overlap — not finished audibly\n this.drainTimer = null;\n this.speaking = false;\n if (this.turnStartAt) log.debug(`turn: ${Math.round(now() - this.turnStartAt)}ms (incl. playback)`);\n this.echoUntil = 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 };\n const drainThenSettle = () => {\n if (this.drainTimer) clearTimeout(this.drainTimer);\n this.drainTimer = 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) clearTimeout(this.drainTimer);\n this.drainTimer = 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 this.beginSpeech();\n this.speakDelta(text);\n this.endSpeech();\n }\n\n /** barge-in: stop audio NOW, cancel generation, reset for the user's utterance */\n interrupt(): void {\n if (!this.speaking && !this.drainTimer) return;\n if (this.drainTimer) { 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 = 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 if (this.resumeTimer) clearTimeout(this.resumeTimer);\n if (this.pendingTimer) clearTimeout(this.pendingTimer);\n if (this.drainTimer) clearTimeout(this.drainTimer);\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 || 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 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 if (!this.pausedAt) {\n this.pausedAt = now();\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 && now() - this.lastResumeAt < this.options.overlapRepauseCedeMs) {\n this.interrupt();\n this.options.onBargeIn(this.ctxOpen ? 'speaking' : 'drain');\n return;\n }\n }\n if (this.genuine(txt) && this.words(txt).length >= 2) {\n const phase = this.ctxOpen ? 'speaking' as const : 'drain' as const;\n this.interrupt();\n this.options.onBargeIn(phase);\n return;\n }\n this.armResume(); // single word / not-yet-genuine: 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.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) clearTimeout(this.pendingTimer);\n this.pendingTimer = setTimeout(() => this.flushUtterance(), Math.max(800, this.options.utteranceMergeMs));\n }\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 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.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 if (this.echoActive() && (this.usingAec ? !this.genuine(text) : this.novelWords(text).length < 2)) { 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 && now() - this.ackAt < 6000 && squash(text) === squash(this.options.ackPhrase)) { 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 this.pendingUtt = this.pendingUtt ? `${this.pendingUtt} ${text}` : text;\n if (this.pendingTimer) 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.options.onHold();\n if (this.options.holdFiller && !this.speaking) {\n this.beginSpeech();\n this.speakDelta(this.options.holdFiller);\n this.endSpeech();\n }\n this.pendingTimer = 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 = setTimeout(() => this.flushUtterance(), this.options.utteranceMergeMs);\n }\n private flushUtterance(): void {\n if (this.pendingTimer) { clearTimeout(this.pendingTimer); this.pendingTimer = null; }\n const text = this.pendingUtt;\n this.pendingUtt = '';\n if (text) { this.turnStartAt = now(); this.options.onUtterance(text); } // stamp the real turn start for TTFT\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) clearTimeout(this.resumeTimer);\n this.resumeTimer = 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.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) { clearTimeout(this.resumeTimer); this.resumeTimer = null; }\n if (this.pausedAt && resume) { this.player.resume?.(); this.lastResumeAt = 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.speaking || !this.overlapCapable || this.pausedAt || rms < 50) return;\n const t = 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 = now() + 1300;\n setTimeout(() => { this.suspectUntil = 0; }, 1350);\n }\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 '../logging';\nimport { type AudioSource, type AuthProvider, resolveAuth, STT_SAMPLE_RATE } from './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}\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 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.reset();\n this.connectWs().catch((e) => log.error(`soniox reconnect failed: ${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 await this.options.source.start((chunk) => {\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) 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 this.options.source?.stop();\n if (this.ws) this.ws.onclose = null as any;\n this.ws?.close();\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}\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 * 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 '../logging';\nimport { type AuthProvider, resolveAuth, TTS_SAMPLE_RATE } from './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 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 if (!this.closed) { this.connecting = this.doConnect().catch((e) => log.error(`cartesia reconnect failed: ${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 }\n else if (m.type === 'error') {\n if (/already been cancelled|does not exist/.test(m.message || '')) return;\n 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.onDone(); // release any pending drain\n this.startProbe();\n } else if (!this.down) {\n 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 (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 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 });\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('.', false));\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"],"mappings":"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","names":["norm","i","log","res","now","ctx","log","NO_JOB","MAX_CATALOG","parseFrontmatter","slug","l","slug","childOpts","res","summary","log","NodeDiskFilesystem","JailedFilesystem","PathResolver","now","id","makeRealShellTool","makeShellJobTools","ShellJobRegistry","log","log","log","slug","MemFilesystem","log","MemFilesystem","log","log","now","log","now","MemFilesystem","CommandExecutor","registerHeadlessCommands"]}
1
+ {"version":3,"sources":["../src/redact.ts","../src/tools.structured.ts","../src/todo.ts","../src/logging.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/llm.ts","../src/Agent.ts","../src/tools.jobs.ts","../src/host.ts","../src/relevance.ts","../src/frontmatter.ts","../src/skills.ts","../src/commands.ts","../src/memory.ts","../src/instructions.ts","../src/subagent.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","../src/mcp.ts","../src/hooks.ts","../src/voice/engine.ts","../src/voice/soniox.ts","../src/voice/types.ts","../src/voice/cartesia.ts"],"sourcesContent":["/**\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/** 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. */\nasync function walkFiles(fs: IFilesystem, dir: string, signal?: AbortSignal, out: string[] = []): Promise<string[]> {\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 const p = dir === '/' ? `/${name}` : `${dir}/${name}`;\n if (await fs.isDirectory(p)) await walkFiles(fs, p, signal, out);\n else out.push(p);\n }\n return out;\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 const globTool: AgentTool = {\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\"). Prefer over `bash find` for locating files — one call, structured output.',\n parameters: {\n type: 'object',\n required: ['pattern'],\n properties: { pattern: { type: 'string', description: 'glob pattern(s); ** matches across directories; prefix a pattern with ! to exclude' } },\n },\n async run({ pattern }, ctx) {\n const pats = String(pattern ?? '').trim().split(/\\s+/).filter(Boolean);\n const include = pats.filter((p) => !p.startsWith('!')).map((p) => anchoredGlob(ctx.fs, p));\n const exclude = pats.filter((p) => p.startsWith('!')).map((p) => anchoredGlob(ctx.fs, p.slice(1)));\n const includes = include.length ? include : [anchoredGlob(ctx.fs, '**')]; // only-excludes → start from everything\n const hits = (await walkFiles(ctx.fs, fsCwd(ctx.fs), ctx.signal)).filter(\n (p) => includes.some((re) => re.test(p)) && !exclude.some((re) => re.test(p)),\n );\n return hits.length ? hits.join('\\n') : '(no matches)';\n },\n};\n\n/** Search file contents by regex, returning typed `path:line:text` hits with optional context. */\nexport const grepTool: AgentTool = {\n name: 'Grep',\n description:\n 'Search file contents by regex. Returns `path:line: text` hits. Optional `glob` to scope files, `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 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, 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 scope = glob ? anchoredGlob(ctx.fs, String(glob)) : null;\n const files = (await walkFiles(ctx.fs, fsCwd(ctx.fs), ctx.signal)).filter((p) => !scope || scope.test(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'}]` : '';\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/** 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/** 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 >`.',\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 if (ctx.lint) { const err = ctx.lint(path, body); if (err) throw new Error(err); }\n await mkdirp(ctx.fs, parentDir(ctx.fs.resolvePath(path)));\n await ctx.fs.writeFile(path, body);\n ctx.readState.set(ctx.fs.resolvePath(path), 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). 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 === '') { planned.set(p, neu); continue; } // whole-file write / create\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 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","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 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/agent.libx.js)' } });\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) uses Tavily if an API key is present, else keyless DuckDuckGo. */\n provider?: 'auto' | 'tavily' | 'duckduckgo';\n /** API key for Tavily (default: process.env.TAVILY_API_KEY). */\n apiKey?: string;\n /** Tavily endpoint override. */\n endpoint?: string;\n maxResults?: number; // default 5\n timeoutMs?: number; // default 15s\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/**\n * Build a WebSearch tool. Keyless by default (DuckDuckGo HTML) so it works in any deployment with\n * no setup; auto-upgrades to Tavily (better, agent-oriented results) when TAVILY_API_KEY is present.\n */\nexport function makeWebSearchTool(options: WebSearchOptions = {}): AgentTool {\n const tavilyEndpoint = options.endpoint ?? 'https://api.tavily.com/search';\n const maxResults = options.maxResults ?? 5;\n const timeoutMs = options.timeoutMs ?? 15_000;\n return {\n name: 'WebSearch',\n 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 provider = options.provider ?? 'auto';\n const useTavily = provider === 'tavily' || (provider === 'auto' && !!key);\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), timeoutMs);\n try {\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/agent.libx.js)' },\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();\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 { grepTool, globTool, writeTool, multiEditTool, applyEditsTool, repoMapTool, reviewTool, fuzzyLineReplace } from './tools.structured';\nimport { todoWriteTool, type TodoItem } from './todo';\nimport { webFetchTool, webSearchTool } from './tools.web';\nimport { OverlayFilesystem } from './OverlayFilesystem';\nimport { redactSecrets, CONFIG_FILE_RE } from './redact';\nimport type { SandboxJobRegistry } from './tools.jobs';\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: '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 | { 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}\n\nexport interface AgentTool {\n name: string;\n description: string;\n parameters: object; // JSON Schema for the function's arguments\n run(args: any, ctx: ToolContext): Promise<string | { text: string; images?: { mimeType: string; data: string }[] }>;\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). */\nconst IMG_MIME: Record<string, string> = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', webp: 'image/webp' };\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> };\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 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 ctx.readState.set(ctx.fs.resolvePath(path), raw); // staleness guard tracks the REAL content\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];\n return Object.fromEntries(all.map((t) => [t.name, t]));\n}\n\n/** Resolve a list of tool names against the registry (unknown names throw). */\nexport function toolsByName(names: string[]): AgentTool[] {\n const reg = toolRegistry();\n return names.map((n) => {\n const t = reg[n];\n if (!t) throw new Error(`unknown tool '${n}'. Known: ${Object.keys(reg).join(', ')}`);\n return t;\n });\n}\n","import { promises as fsp } 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 /** 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 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 /** 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 /** 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}\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\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}`); } });\n proc.on('close', (code: number | null) => { if (job.status === 'running') { job.status = 'exited'; job.exitCode = code ?? undefined; } });\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 /** 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 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 timeoutMs = options.timeoutMs ?? 120_000;\n return {\n name: 'Shell',\n description:\n '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 'Set `background:true` for long-running processes (servers, watchers) — returns a job id immediately; poll with ShellOutput, stop with ShellKill.',\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 },\n },\n async run({ command, background }, ctx) {\n const cmd = String(command ?? '');\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: '/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 const timer = setTimeout(() => { timedOut = true; ctl.abort(); }, 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 timeout/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 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/** Abort message: timeout vs external cancel, preserving any partial output. */\nfunction reasonFor(timedOut: boolean, timeoutMs: number, body: string): string {\n const head = timedOut ? `[exit 124] timed out after ${timeoutMs}ms (killed)` : '[exit 130] cancelled (killed)';\n return body ? `${head}\\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. */\nexport function makeShellJobTools(registry: ShellJobRegistry): AgentTool[] {\n const idParam = { type: 'object', properties: { id: { type: 'string', description: 'the job id from Shell({background:true})' } } };\n return [\n {\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 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 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","/**\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\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\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}\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 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","import type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike, ChatResponse, Message, StreamChunk, ToolCall, MessageContent, ContentPart } from './llm';\nimport { contentText, imagePart } from './llm';\nimport { type AgentTool, type ToolContext, type HostBridge, defaultTools, makeContext, toWireTools, truncateOutput } from './tools';\nimport { SandboxJobRegistry, makeJobTools } from './tools.jobs';\nimport { askUserQuestionTool } from './host';\nimport { loadSkills } from './skills';\nimport { loadCommands } from './commands';\nimport { loadMemory } from './memory';\nimport { loadInstructions } from './instructions';\nimport { makeTaskTool, makeTaskBatchTool } from './subagent';\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/** 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 finishReason: 'stop' | 'max_steps' | 'budget' | 'timeout' | 'loop' | 'max_tool_calls' | 'aborted' | 'error';\n messages: Message[];\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 error?: unknown;\n}\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. 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 '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 /** Wall-clock ceiling in ms for the whole run. 0 = unbounded. */\n timeoutMs = 120_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 /** 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 /** 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 /** 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 /** 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 /** Stream tokens from the model. Takes effect only with a `host.notify`; off => current (non-stream) behavior. */\n stream = false;\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 /** 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}\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 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\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 /** 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. */\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 return before - this.activeTools.length;\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 if (o.skillsDir) {\n // taskHint floats the most relevant skills to the top of a large catalog; full set stays loadable by name.\n const { catalog, tool } = await loadSkills(fs, o.skillsDir, { relevanceHint: taskHint });\n if (catalog) systemPrompt += '\\n\\n' + catalog;\n if (tool) tools = [...tools, tool];\n }\n if (o.commandsDir) {\n const { catalog, tool } = await loadCommands(fs, o.commandsDir, { relevanceHint: taskHint });\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 const taskOpts = { ai: o.ai, model: o.model, fs, depth: o.depth, maxDepth: o.maxDepth, agents, hooks: o.hooks };\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 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 { role: 'user', content: 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`): keep the system message + the\n * most-recent window, summarizing the dropped middle (deterministic, no LLM call).\n * No-op when the transcript already fits. Returns the number of messages removed.\n * `focus` (e.g. from `/compact keep the API details`) preserves matching lines from the\n * dropped span verbatim in the summary, instead of losing them to the generic recap.\n */\n compactNow(maxMessages = 12, focus?: string): number {\n const max = Math.max(2, maxMessages);\n if (this.transcript.length <= max) return 0;\n void this.activeHooks?.onPreCompact?.(this.transcript); // [lifecycle] observe before folding (fire-and-forget)\n const before = this.transcript.length;\n this.transcript = compact(this.transcript, max, focus);\n return before - this.transcript.length;\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 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 // 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}${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 return { text: lastAssistantText(this.transcript), steps, finishReason, messages: this.transcript, usage, usageEstimated };\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() - start - this.parkedMs >= o.timeoutMs) return kill('timeout'); // active wall-clock: idle 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 // Cursor is an agent runtime — bridge host tools via IPC-based toolExecutor callback.\n const isCursorWithTools = o.model.startsWith('cursor/') && wireTools.length > 0;\n const cursorPo = isCursorWithTools ? {\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 const raw = await this.dispatch(tc);\n return typeof raw === 'string' ? raw : raw.text;\n },\n } : undefined;\n const reasonOpts = {\n ...frag,\n ...(o.promptCache ? { promptCache: true } : {}),\n ...(o.providerOptions || cursorPo ? { providerOptions: { ...frag.providerOptions, ...o.providerOptions, ...cursorPo } } : {}),\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 const r = await o.ai.chat({ model: o.model, messages: sent, tools: wireTools, stream: true, signal: o.signal, ...(o.toolChoice ? { toolChoice: o.toolChoice } : {}), ...reasonOpts });\n res = await this.consumeStream(r as AsyncIterable<StreamChunk>);\n } else {\n const r = await o.ai.chat({ model: o.model, messages: sent, tools: wireTools, stream: false, signal: o.signal, ...(o.toolChoice ? { toolChoice: o.toolChoice } : {}), ...reasonOpts });\n res = r as ChatResponse;\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 transient = !o.signal?.aborted && !isAbortError(err) && attempt < 2 && (network || serverSide);\n if (!transient) throw err;\n const waitMs = 1000 * (attempt + 1);\n log.warn(`network drop mid-step (${(err as any)?.message ?? err}) — retrying in ${waitMs}ms`);\n o.host?.notify?.({ kind: 'retry', message: `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 // An aborted fetch surfaces as a thrown provider error. The signal flag can LAG the throw under\n // a barge-in race (the controller fires, the provider rejects, but o.signal.aborted hasn't\n // settled yet), so match the provider's abort message too — else a clean cancel is logged as a\n // crash AND its \"operation was aborted\" string leaks onto the spoken/utterance line.\n if (o.signal?.aborted || isAbortError(err)) return kill('aborted');\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 log.error(`chat() failed: ${(err as any)?.message ?? err}${bodyStr ? ` — ${bodyStr}` : ''}`, err);\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 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 const emptyTurn = toolCalls.length === 0 && contentText(res.content ?? '').trim() === '';\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 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 await this.activeHooks?.onStop?.(res.content ?? ''); // [hooks] fire once on clean stop\n return { text: res.content ?? '', steps, finishReason: 'stop', messages: this.transcript, usage, usageEstimated };\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 = raw; }\n else {\n const parts: ContentPart[] = [{ type: 'text', text: raw.text }];\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 }\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 private async consumeStream(stream: AsyncIterable<StreamChunk>): Promise<ChatResponse> {\n let content = '';\n let finishReason: string | undefined;\n let toolCalls: ToolCall[] | undefined;\n let usage: ChatResponse['usage'];\n for await (const chunk of stream) {\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 if (chunk.content) {\n content += 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 return { content, ...(finishReason ? { finishReason } : {}), ...(toolCalls ? { toolCalls } : {}), ...(usage ? { usage } : {}) };\n }\n\n private async dispatch(tc: ToolCall): Promise<string | { text: string; images?: { mimeType: string; data: string }[] }> {\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 const cap = this.options.maxToolResultBytes ?? 0;\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 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 if (o.keepToolOutputs) out = stubOldToolResults(out ?? m, o.keepToolOutputs);\n if (o.maxContextTokens) {\n const pre = (out ?? m).length;\n out = fitTokenBudget(out ?? m, o.maxContextTokens);\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 return dropOrphanToolResults(out ?? m);\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/** ~4 chars/token estimate over content + serialized tool_calls. */\nfunction estimateTokens(m: Message[]): number {\n let chars = 0;\n for (const x of m) chars += contentText(x.content).length + (x.tool_calls ? JSON.stringify(x.tool_calls).length : 0);\n return Math.ceil(chars / 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. */\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/** 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): 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).\n const per = messages.map((x) => estimateTokens([x]));\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/** Lightweight, deterministic, LLM-free recap of a span of messages. */\nfunction summarize(messages: Message[], focus?: string): string {\n const tools = new Set<string>();\n const files = new Set<string>();\n let lastAssistant = '';\n for (const msg of messages) {\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 of ${messages.length} 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 // 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 outer: for (const msg of messages) {\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`. Registered only when a HostBridge is provided\n * (autonomous runs don't see it), so it never dead-ends a headless agent.\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 (ambiguous requirement, a fork you cannot resolve from context). Returns their selection.',\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 const fallback = args.options?.[0]?.label ?? '';\n return `No interactive user is available — proceed using your best judgment.${fallback ? ` (Closest default: \"${fallback}\")` : ''}`;\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 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 } = {},\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 by name — returns its full instructions (SKILL.md). Use when a task matches a listed skill.',\n parameters: { type: 'object', required: ['name'], properties: { name: { type: 'string' } } },\n async run({ name }, ctx: ToolContext) {\n let s = skills.find((x) => x.name === name);\n if (!s) { // miss → rescan: skills created mid-conversation are loadable without a reprepare\n const fresh = await scanSkills(ctx.fs, dir);\n s = fresh.find((x) => x.name === name);\n if (!s) return `Error: no skill named '${name}'. Available: ${fresh.map((x) => x.name).join(', ')}`;\n skills.push(s);\n }\n return ctx.fs.readFile(s.path);\n },\n };\n return { skills, 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';\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/** 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/** 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 const { body } = parseFrontmatter(await fs.readFile(cmd.path));\n return embedFiles(expandTemplate(body, args), fs);\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 } = {},\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 by name — returns its expanded prompt template (with your `args` substituted/appended). Use when a task matches a listed command.',\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 if (!c) { // miss → rescan: commands created mid-conversation are runnable without a reprepare\n const fresh = await scanCommands(ctx.fs, dir);\n c = fresh.find((x) => x.name === slug);\n if (!c) return `Error: no command named '${slug}'. Available: ${fresh.map((x) => x.name).join(', ')}`;\n commands.push(c);\n }\n return expandCommand(ctx.fs, c, String(args ?? ''));\n },\n };\n return { commands, 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 type { IFilesystem } from '@livx.cc/wcli/core';\nimport type { ChatLike } from './llm';\nimport type { AgentTool, ToolContext } from './tools';\nimport { toolsByName } from './tools';\nimport type { AgentDef } from './agents';\nimport type { Hooks } from './hooks';\nimport { Agent } from './Agent';\nimport { OverlayFilesystem } from './OverlayFilesystem';\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\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): 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 const childOpts: ConstructorParameters<typeof Agent>[0] = { ai: opts.ai, fs, model: def?.model ?? opts.model, subagents: true, depth: depth + 1, maxDepth };\n if (opts.maxSteps != null) childOpts.maxSteps = opts.maxSteps;\n if (def?.systemPrompt) childOpts.systemPrompt = def.systemPrompt;\n if (def?.tools?.length) {\n try { childOpts.tools = toolsByName(def.tools); }\n catch (e) { return `subagent '${agentType}' declares an unknown tool — ${(e as Error).message}`; }\n }\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 returns a concise summary — use to isolate context-heavy work (broad search, a scoped refactor). Provide a short `description` and a full `prompt`. Set `background: true` to run it detached (returns a job id to poll with JobOutput while you keep working); its file edits are overlay-isolated and commit when it finishes.',\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 background: { type: 'boolean', description: 'run detached (overlay-isolated, commits on finish); returns a job id to poll with JobOutput instead of blocking' },\n },\n },\n async run({ description, prompt, agentType, background }, 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 // 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 const overlay = new OverlayFilesystem(opts.fs); // write-isolation: parent VFS untouched until commit\n const childOpts = childOptionsFor(opts, overlay, depth, maxDepth, agentType);\n if (typeof childOpts === 'string') throw new Error(childOpts);\n childOpts!.signal = signal; // killing the job aborts the child's run loop\n const res = await new Agent(childOpts).run(String(prompt ?? ''));\n if (signal.aborted) return '[killed before commit]';\n await overlay.commit(); // flush the child's edits down into the parent VFS\n const summary = res.text || `(child '${label}' finished with no summary; finishReason=${res.finishReason})`;\n await opts.hooks?.onSubagentStop?.(summary, { label, agentType });\n return summary;\n }, { kind: 'agent', label });\n return `Started background sub-task ${id} ('${label}') — poll with JobOutput({id:\"${id}\"}).`;\n }\n\n // The child gets subagents enabled but one level deeper, so it can recurse\n // up to maxDepth; at the ceiling its own Task tool refuses (see guard above).\n const childOpts = childOptionsFor(opts, opts.fs, depth, maxDepth, agentType);\n if (typeof childOpts === 'string') return `Error: ${childOpts}`;\n const child = new Agent(childOpts);\n const res = await child.run(String(prompt ?? ''));\n const summary = res.text || `(child agent finished '${label}' with no summary; finishReason=${res.finishReason})`;\n await opts.hooks?.onSubagentStop?.(summary, { label, agentType });\n return summary;\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 (its file edits are merged back in array order). Use for parallel fan-out (review/search/scoped refactors across files). Provide `tasks: [{ description, prompt, agentType? }]`.',\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 },\n },\n },\n },\n },\n async run({ tasks }, _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\n type Outcome = { label: string; text?: string; error?: string; overlay?: OverlayFilesystem; 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 const overlay = new OverlayFilesystem(opts.fs); // write-isolation: siblings can't see each other's edits\n const childOpts = childOptionsFor(opts, overlay, depth, maxDepth, t?.agentType);\n if (typeof childOpts === 'string') return { label, error: childOpts, ok: false };\n try {\n const res = await new Agent(childOpts).run(String(t?.prompt ?? ''));\n await opts.hooks?.onSubagentStop?.(res.text, { label, agentType: t?.agentType });\n return { label, text: res.text, overlay, ok: res.finishReason !== 'error' };\n } catch (e) { return { label, error: e instanceof Error ? e.message : String(e), ok: false }; }\n });\n\n // Merge successful children's edits into the shared fs, in array order (deterministic last-writer-wins).\n for (const r of results) if (r.ok && r.overlay) await r.overlay.commit().catch(() => {});\n\n return results\n .map((r, i) => `### ${i + 1}. ${r.label}\\n${r.error ? `ERROR: ${r.error}` : (r.text || '(no summary)')}`)\n .join('\\n\\n');\n },\n };\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 for (const r of this.options.rules) {\n if (r.tool && r.tool !== call.name) 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 if (r?.remember) this.options.rules.unshift({ tool: call.name, 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","// agent.libx.js — edge-native AI agent runtime over a virtual filesystem.\n\nexport { Agent, AgentOptions } from './Agent';\nexport type { RunResult } from './Agent';\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, writeTool, multiEditTool, applyEditsTool, repoMapTool, repoIndex, mkdirp } from './tools.structured';\nexport { todoWriteTool } from './todo';\nexport { webFetchTool, webSearchTool, makeWebFetchTool, makeWebSearchTool, 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 } from './commands';\nexport type { CommandInfo } 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 } from './llm';\nexport { reasoningToChatFragment } from './reasoning';\nexport type { ReasoningEffort, ChatFragment } from './reasoning';\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(opts: Partial<AgentOptions> & { cwd?: string } = {}): Promise<Partial<AgentOptions>> {\n const { makeRealShellTool, makeShellJobTools, ShellJobRegistry } = await import('./tools.shell');\n const { cwd = process.cwd(), tools, ...rest } = opts;\n const registry = new ShellJobRegistry({ cwd, killOnExit: true });\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. Results are pushed back as\n * `[task <id> completed] …` events and re-voiced by the reflex — 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';\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}\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 /** 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\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' +\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 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. 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.\\n' +\n 'Results arrive later as events like \"[task t1 completed] …\" or \"[task t1 failed] …\". When one arrives, speak the USEFUL gist in one or two short sentences — the actual answer the user wanted (the headline finding, the key numbers), not the thinnest possible \"it\\'s done\". A forecast → say it\\'s calm AND that it\\'s good for swimming but not surf; a count → say the number. Be brief, but do not drop the substance. ' +\n 'If the result is a LIST (search results, multiple files/matches), the user CANNOT see it — there is no screen and no numbered menu to point at. Speak the gist: say what you found and name the top one or two by NAME (the source, not \"the first one\" or a number), then ask plainly if they want more. Never ask them to \"pick which one\" or reference items by position. ' +\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 — give at most a half-sentence aside (\"still on it — running tests now\") and end your turn. 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, just say \"still on it\" and end the turn — never poll it again and again in a loop. 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 or surprising, briefly confirm what they meant (\"did you mean…?\") instead of answering the literal words.';\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/**\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 private pendingEvents: string[] = [];\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 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 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 /** 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 /** 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 + `\\nToday's date: ${new Date().toDateString()}.`;\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.fabricationCut) return; // already cut this turn → drop the tail\n const msg = (ev as any).message as string;\n this.reflexBuf += msg;\n const m = this.reflexBuf.match(RESERVED_EVENT_MARKER);\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 host.notify?.({ ...ev, message: safe } as any);\n return;\n }\n this.reflexForwarded = this.reflexBuf.length;\n if (msg.trim()) this.spokeThisTurn = true;\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 /** 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.turnBriefs.clear();\n this.spokeThisTurn = false;\n this.reflexBuf = '';\n this.reflexForwarded = 0;\n this.fabricationCut = false;\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 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 /** True when the just-finished turn dispatched a task but voiced nothing — dead air to repair.\n * Requires a host: without one there's no stream to detect speech on (and no one to speak to). */\n private get silentDispatch(): boolean {\n return !!this.options.host && this.turnDispatched && !this.spokeThisTurn;\n }\n\n /** A dispatch with no spoken text is dead air. Re-prompt the reflex ONCE so the LLM itself voices a\n * short ack (no template). If it STILL says nothing, fall back to a minimal line so silence never ships. */\n private async ackIfSilent(): Promise<void> {\n this.nudging = true;\n try {\n await this.voice.send('[reminder] You dispatched a task but said nothing to the user. Say ONE short spoken acknowledgement 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 (!this.spokeThisTurn) this.options.host?.notify?.({ kind: 'text_delta', message: 'Okay, on it.' });\n }\n\n /** One user turn: the voice agent streams the reply (and may Act/Think). Serialized with re-voice turns. */\n send(content: MessageContent): Promise<RunResult> {\n return this.enqueue(async () => {\n await this.initMemory();\n this.resetTurn();\n const res = await this.voice.send(content);\n if (this.silentDispatch) await this.ackIfSilent();\n return res;\n });\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 /** 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.options.host?.notify?.({ kind, message, data });\n }\n\n /** Queue a `[task …]` event for re-voicing. Events arriving while the voice is busy coalesce into ONE turn. */\n private queueRevoice(event: string): void {\n this.pendingEvents.push(event);\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 if (!events.length) return;\n this.resetTurn();\n await this.voice.send(events.join('\\n'));\n if (this.silentDispatch) await this.ackIfSilent();\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'): 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 return (recent ? `${brief}\\n\\n## Recent conversation (for context)\\n${recent}` : brief) + verify;\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 = 'act'): 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 const workerHost: HostBridge | undefined = o.askRelay ? { ask: relayAsk } : o.host?.ask ? { ask: (q) => o.host!.ask!(q) } : undefined;\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 ...(workerHost ? { host: workerHost } : {}),\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 .then((res) => this.maybeVerify(id, briefText, res, tier, agentOpts))\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 });\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, briefText: string, res: RunResult, tier: WorkerTier, agentOpts: Partial<AgentOptions>): 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 const checkBrief = `${briefText}\\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(agentOpts).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 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 log.verbose(`task ${id} done (${res.steps} steps)`);\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 steps: res.steps, toolCalls: res.messages.filter((m) => m.role === 'tool').length,\n });\n this.queueRevoice(`[task ${id} completed] ${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 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 this.queueRevoice(`[task ${rec.id} failed] ${msg}`);\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 async dispatch(brief: string, tier: WorkerTier = 'act', label?: string): Promise<string> {\n if (tier === 'think' && this.options.thinkModel === false) tier = 'act';\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);\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.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);\n return `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.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);\n return `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 names = await fs.readDir(String(path ?? '.'));\n return names.slice(0, 50).join('\\n') + (names.length > 50 ? `\\n… (+${names.length - 50} more)` : '');\n }\n case 'file': {\n if (!fs) return 'unavailable (no filesystem)';\n if (!path) return 'file lookup needs a path';\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 }\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 if (filler) this.notify('hold_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","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/** Adapt one MCP tool spec into an AgentTool backed by `callTool`. */\nexport function mcpToolToAgentTool(spec: McpToolSpec, callTool: McpCall, prefix = 'mcp__'): AgentTool {\n return {\n name: `${prefix}${spec.name}`,\n description: spec.description ?? `MCP tool ${spec.name}`,\n parameters: spec.inputSchema ?? { type: 'object', properties: {} },\n async run(args, _ctx) {\n const r = toResult(await callTool(spec.name, args ?? {}));\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}\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 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 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 r = toResult(await callTool(n, args ?? {}));\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","/**\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 type { AudioSink, VoiceState } from './types';\n\nconst log = forComponent('VoiceEngine');\nconst now = () => performance.now();\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 .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\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 start(): Promise<void> | void;\n reset(): void;\n stop(): void;\n}\nexport interface TtsLike {\n onAudio: (chunk: Uint8Array) => void;\n onDone: () => void;\n connect(): Promise<void> | 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 /** 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 /** 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): partial text while\n * speaking → PAUSE (exact-sample hold); partial grows into dominant-novel ≥2 words → cede\n * (interrupt; the LLM re-enters); partial stalls/endpoints without ceding (backchannel by\n * 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}\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 drainTimer: ReturnType<typeof setTimeout> | null = 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 pendingUtt = ''; // endpointed text held for the merge window\n private pendingTimer: ReturnType<typeof setTimeout> | null = null;\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: ReturnType<typeof setTimeout> | null = null;\n private turnStartAt = 0; // timestamp when the current turn began (for TTFT logging)\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 }\n\n async start(): Promise<void> {\n this.tts.onAudio = (c) => { if (this.speaking) this.player.write(c); };\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 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 private idleWaiters: (() => void)[] = [];\n private setState(s: VoiceState): void {\n if (this.state === s) return;\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) { clearTimeout(this.drainTimer); this.drainTimer = null; }\n this.interrupted = false; // a new turn re-arms speech\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 if (!this.speaking) this.player.markTurn();\n this.speaking = true;\n this.ctxOpen = true;\n this.spokeDeltas = false;\n this.reply = '';\n this.echoWords = new Set(this.words(this.prevReply)); // previous reply's echo may still be in flight\n this.tts.newContext();\n if (ack && this.options.ackPhrase) { this.tts.speak(this.options.ackPhrase + ' ', true); this.spokeDeltas = true; this.ackAt = now(); }\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 = now();\n this.setState('thinking');\n }\n speakDelta(text: string): void {\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 if (!this.speaking || !this.ctxOpen) this.beginSpeech();\n this.reply += text;\n for (const w of this.words(this.reply)) this.echoWords.add(w);\n this.tts.speak(forSpeech(text), true); // strip markdown punctuation so TTS doesn't read \"dash\"/\"star\"/\"hash\" aloud\n if (!this.spokeDeltas && this.turnStartAt) log.debug(`ttft: ${Math.round(now() - this.turnStartAt)}ms`);\n this.spokeDeltas = true;\n this.setState('speaking');\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 if (!this.speaking) return;\n this.ctxOpen = false; // context ends now; audio keeps draining\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 = setTimeout(settle, 250); return; } // held by an overlap — not finished audibly\n this.drainTimer = null;\n this.speaking = false;\n if (this.turnStartAt) log.debug(`turn: ${Math.round(now() - this.turnStartAt)}ms (incl. playback)`);\n this.echoUntil = 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 };\n const drainThenSettle = () => {\n if (this.drainTimer) clearTimeout(this.drainTimer);\n this.drainTimer = 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) clearTimeout(this.drainTimer);\n this.drainTimer = 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 this.beginSpeech();\n this.speakDelta(text);\n this.endSpeech();\n }\n\n /** barge-in: stop audio NOW, cancel generation, reset for the user's utterance */\n interrupt(): void {\n if (!this.speaking && !this.drainTimer) return;\n if (this.drainTimer) { 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 = 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 if (this.resumeTimer) clearTimeout(this.resumeTimer);\n if (this.pendingTimer) clearTimeout(this.pendingTimer);\n if (this.drainTimer) clearTimeout(this.drainTimer);\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 || 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 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 if (!this.pausedAt) {\n this.pausedAt = now();\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 && now() - this.lastResumeAt < this.options.overlapRepauseCedeMs) {\n this.interrupt();\n this.options.onBargeIn(this.ctxOpen ? 'speaking' : 'drain');\n return;\n }\n }\n if (this.genuine(txt) && this.words(txt).length >= 2) {\n const phase = this.ctxOpen ? 'speaking' as const : 'drain' as const;\n this.interrupt();\n this.options.onBargeIn(phase);\n return;\n }\n this.armResume(); // single word / not-yet-genuine: 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.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) clearTimeout(this.pendingTimer);\n this.pendingTimer = setTimeout(() => this.flushUtterance(), Math.max(800, this.options.utteranceMergeMs));\n }\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 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.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 if (this.echoActive() && (this.usingAec ? !this.genuine(text) : this.novelWords(text).length < 2)) { 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 && now() - this.ackAt < 6000 && squash(text) === squash(this.options.ackPhrase)) { 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 this.pendingUtt = this.pendingUtt ? `${this.pendingUtt} ${text}` : text;\n if (this.pendingTimer) 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.options.onHold();\n if (this.options.holdFiller && !this.speaking) {\n this.beginSpeech();\n this.speakDelta(this.options.holdFiller);\n this.endSpeech();\n }\n this.pendingTimer = 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 = setTimeout(() => this.flushUtterance(), this.options.utteranceMergeMs);\n }\n private flushUtterance(): void {\n if (this.pendingTimer) { clearTimeout(this.pendingTimer); this.pendingTimer = null; }\n const text = this.pendingUtt;\n this.pendingUtt = '';\n if (text) { this.turnStartAt = now(); this.options.onUtterance(text); } // stamp the real turn start for TTFT\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) clearTimeout(this.resumeTimer);\n this.resumeTimer = 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.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) { clearTimeout(this.resumeTimer); this.resumeTimer = null; }\n if (this.pausedAt && resume) { this.player.resume?.(); this.lastResumeAt = 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.speaking || !this.overlapCapable || this.pausedAt || rms < 50) return;\n const t = 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 = now() + 1300;\n setTimeout(() => { this.suspectUntil = 0; }, 1350);\n }\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 '../logging';\nimport { type AudioSource, type AuthProvider, resolveAuth, STT_SAMPLE_RATE } from './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}\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 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.reset();\n this.connectWs().catch((e) => log.error(`soniox reconnect failed: ${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 await this.options.source.start((chunk) => {\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) 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 this.options.source?.stop();\n if (this.ws) this.ws.onclose = null as any;\n this.ws?.close();\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}\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 * 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 '../logging';\nimport { type AuthProvider, resolveAuth, TTS_SAMPLE_RATE } from './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 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 if (!this.closed) { this.connecting = this.doConnect().catch((e) => log.error(`cartesia reconnect failed: ${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 }\n else if (m.type === 'error') {\n if (/already been cancelled|does not exist/.test(m.message || '')) return;\n 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.onDone(); // release any pending drain\n this.startProbe();\n } else if (!this.down) {\n 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 (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 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 });\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('.', false));\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"],"mappings":"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","names":["norm","i","log","res","now","ctx","log","NO_JOB","MAX_CATALOG","parseFrontmatter","slug","l","slug","childOpts","res","summary","log","NodeDiskFilesystem","JailedFilesystem","PathResolver","now","id","makeRealShellTool","makeShellJobTools","ShellJobRegistry","log","log","log","slug","MemFilesystem","log","MemFilesystem","log","log","now","log","now","MemFilesystem","CommandExecutor","registerHeadlessCommands"]}