@cryer/star-cli 0.3.13 → 0.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -5
- package/README.zh-CN.md +15 -5
- package/dist/{chunk-6PLZ3FLG.js → chunk-2ISBRSBA.js} +375 -235
- package/dist/chunk-2ISBRSBA.js.map +1 -0
- package/dist/{chunk-QELCMXQX.js → chunk-4HANB3DJ.js} +381 -212
- package/dist/chunk-4HANB3DJ.js.map +1 -0
- package/dist/{chunk-OF42OVM4.js → chunk-54KH4JSO.js} +204 -125
- package/dist/chunk-54KH4JSO.js.map +1 -0
- package/dist/{chunk-RD4S5LKM.js → chunk-CECMCDZG.js} +43 -30
- package/dist/chunk-CECMCDZG.js.map +1 -0
- package/dist/{chunk-MVAMPVTA.js → chunk-KILMI3S5.js} +13 -5
- package/dist/{chunk-MVAMPVTA.js.map → chunk-KILMI3S5.js.map} +1 -1
- package/dist/{chunk-NMB3TNQU.js → chunk-NRLGGA7L.js} +507 -175
- package/dist/chunk-NRLGGA7L.js.map +1 -0
- package/dist/loop-M64D5YII.js +17 -0
- package/dist/main.js +177 -131
- package/dist/main.js.map +1 -1
- package/dist/{provider-EWMUPBLH.js → provider-3Z4B7RMF.js} +2 -2
- package/dist/{repl-ZABBT33D.js → repl-N2H7JDSH.js} +617 -327
- package/dist/repl-N2H7JDSH.js.map +1 -0
- package/dist/{tools-4OLADVDR.js → tools-5RKM7ZI3.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-6PLZ3FLG.js.map +0 -1
- package/dist/chunk-NMB3TNQU.js.map +0 -1
- package/dist/chunk-OF42OVM4.js.map +0 -1
- package/dist/chunk-QELCMXQX.js.map +0 -1
- package/dist/chunk-RD4S5LKM.js.map +0 -1
- package/dist/loop-DWQ5WTPD.js +0 -17
- package/dist/repl-ZABBT33D.js.map +0 -1
- /package/dist/{loop-DWQ5WTPD.js.map → loop-M64D5YII.js.map} +0 -0
- /package/dist/{provider-EWMUPBLH.js.map → provider-3Z4B7RMF.js.map} +0 -0
- /package/dist/{tools-4OLADVDR.js.map → tools-5RKM7ZI3.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/cost.ts","../src/cli/icons.ts","../src/cli/terminal-text.ts","../src/cli/markdown.ts","../src/cli/format.ts","../src/cli/mentions.ts","../src/session/checkpoints.ts","../src/session/store.ts","../src/session/list.ts","../src/cli/system-prompt.ts","../src/session/clear.ts","../src/version.ts"],"sourcesContent":["import type { ModelConfig } from \"../config/schema\";\n\nexport interface TokenUsage {\n promptTokens: number;\n completionTokens: number;\n // Prompt tokens served from the provider cache, a subset of promptTokens\n // (OpenAI / openai-compatible style).\n cachedPromptTokens?: number;\n // Cache-read tokens reported on top of promptTokens (Anthropic style).\n cacheReadInputTokens?: number;\n}\n\nexport function formatDollars(cost: number): string {\n let s = cost.toFixed(4).replace(/0+$/, \"\");\n if (s.endsWith(\".\")) {\n s += \"00\";\n } else if (s.split(\".\")[1]?.length === 1) {\n s += \"0\";\n }\n return s;\n}\n\n// User-facing token counts by magnitude: the raw number below 1K, otherwise\n// K/M with two decimals (842 → \"842\", 532_100 → \"532.10K\", 6_740_000 →\n// \"6.74M\"). Request counts and config values stay raw — this is for tokens.\nexport function formatTokens(n: number): string {\n if (!Number.isFinite(n)) return String(n);\n if (n < 1000) return String(n);\n if (n < 1_000_000) return `${(n / 1000).toFixed(2)}K`;\n return `${(n / 1_000_000).toFixed(2)}M`;\n}\n\n// Compact token count for the status bar's ctx gauge: one decimal, a trailing\n// \".0\" dropped (60_700 → \"60.7K\", 200_000 → \"200K\", 1_000_000 → \"1M\").\nexport function formatTokensCompact(n: number): string {\n if (!Number.isFinite(n)) return String(n);\n if (n < 1000) return String(n);\n const thousands = n < 1_000_000;\n const scaled = thousands ? n / 1000 : n / 1_000_000;\n return `${scaled.toFixed(1).replace(/\\.0$/, \"\")}${thousands ? \"K\" : \"M\"}`;\n}\n\n// Numeric session cost in USD; null when the model has no pricing configured.\n// Cache pricing: OpenAI-style cached tokens are a subset of promptTokens, so\n// the uncached rest bills at promptPrice and the cached share at\n// cacheReadPrice (full promptPrice when no cache price is configured);\n// Anthropic-style cache reads come on top of promptTokens and bill at\n// cacheReadPrice only (unconfigured = unbilled, as before).\nexport function computeCostUsd(usage: TokenUsage, model: ModelConfig | undefined): number | null {\n if (model?.promptPrice === undefined || model.completionPrice === undefined) {\n return null;\n }\n const cached = Math.min(Math.max(usage.cachedPromptTokens ?? 0, 0), usage.promptTokens);\n const promptUsd =\n (usage.promptTokens - cached) * model.promptPrice +\n cached * (model.cacheReadPrice ?? model.promptPrice) +\n (usage.cacheReadInputTokens ?? 0) * (model.cacheReadPrice ?? 0);\n return (promptUsd + usage.completionTokens * model.completionPrice) / 1_000_000;\n}\n\nexport function estimateCost(\n usage: TokenUsage,\n modelName: string,\n model: ModelConfig | undefined,\n): string {\n const cost = computeCostUsd(usage, model);\n if (cost === null) {\n if (model !== undefined) {\n const missing = [\n model.promptPrice === undefined ? \"promptPrice\" : null,\n model.completionPrice === undefined ? \"completionPrice\" : null,\n ].filter((f) => f !== null);\n if (missing.length === 1) {\n return `Estimated cost: unknown (${model.name} is missing ${missing[0]} — both prices are needed)`;\n }\n }\n return `Estimated cost: unknown (no price configured for ${modelName})`;\n }\n const cachePrice =\n model?.cacheReadPrice !== undefined ? `, $${model.cacheReadPrice}/M cache read` : \"\";\n return `Estimated cost: $${formatDollars(cost)} (${model?.name} @ $${model?.promptPrice}/M prompt, $${model?.completionPrice}/M completion${cachePrice})`;\n}\n","// Decorative icons with a terminal-capability fallback.\n//\n// Emoji glyphs are double-width only on terminals with real emoji support.\n// On GBK/CJK consoles and mintty without emoji fonts they render as narrow\n// single-cell fallback glyphs while Ink's width math (string-width) counts\n// them double — a line near the wrap boundary then occupies fewer terminal\n// rows than Ink counted, the frame erase overshoots, and every spinner tick\n// leaves the display scrambled (the \"scroll spam\" regression). Emoji icons\n// are therefore enabled only where the terminal is known to render them\n// double-width; elsewhere a plain single-width symbol set is used.\n// STAR_ICONS=emoji|plain overrides the detection.\n//\n// Plain-set rule: every glyph must have string-width 1, which means no\n// Emoji-property characters at all — string-width counts even text-presentation\n// emoji candidates (✔, ☰, ⚙, ↗…) as width 2. Stick to neutral/ambiguous\n// symbols (✦ ❯ ◦ ▸ ‣ ✧ ✎ ※ ◉ ≡ × § ¶ …).\n\nexport type IconMode = \"emoji\" | \"plain\";\n\nconst EMOJI_TERM_PROGRAMS = new Set([\n \"vscode\",\n \"WezTerm\",\n \"iTerm.app\",\n \"Apple_Terminal\",\n \"ghostty\",\n \"kitty\",\n \"Hyper\",\n \"WarpTerminal\",\n]);\n\nexport function resolveIconMode(env: NodeJS.ProcessEnv = process.env): IconMode {\n const override = env.STAR_ICONS;\n if (override === \"emoji\" || override === \"plain\") return override;\n if (env.WT_SESSION) return \"emoji\"; // Windows Terminal\n if (EMOJI_TERM_PROGRAMS.has(env.TERM_PROGRAM ?? \"\")) return \"emoji\";\n const term = env.TERM ?? \"\";\n if (term.includes(\"kitty\") || term.includes(\"alacritty\")) return \"emoji\";\n return \"plain\";\n}\n\nexport const EMOJI_TOOL_ICONS: Record<string, string> = {\n bash: \"💻\",\n read_file: \"📄\",\n write_file: \"📝\",\n edit_file: \"✏️\",\n glob: \"📂\",\n grep: \"🔍\",\n web_search: \"🔎\",\n web_fetch: \"🌐\",\n todo_write: \"📋\",\n todo_read: \"📋\",\n task_list: \"🧵\",\n task_output: \"🧵\",\n task_kill: \"🛑\",\n subagent: \"🤖\",\n skill: \"✨\",\n remember: \"🧠\",\n};\n\nexport const PLAIN_TOOL_ICONS: Record<string, string> = {\n bash: \"$\",\n read_file: \"≡\",\n write_file: \"+\",\n edit_file: \"✎\",\n glob: \"*\",\n grep: \"/\",\n web_search: \"?\",\n web_fetch: \"⇓\",\n todo_write: \"‣\",\n todo_read: \"‣\",\n task_list: \"¶\",\n task_output: \"¶\",\n task_kill: \"×\",\n subagent: \"◉\",\n skill: \"✧\",\n remember: \"※\",\n};\n\nconst iconMode = resolveIconMode();\n\nexport function toolIcon(name: string): string {\n const map = iconMode === \"emoji\" ? EMOJI_TOOL_ICONS : PLAIN_TOOL_ICONS;\n return map[name] ?? (iconMode === \"emoji\" ? \"🔧\" : \"▸\");\n}\n\n// 💭 / ✧ — thinking spinner label and the collapsed thought summary.\nexport const thinkingIcon = iconMode === \"emoji\" ? \"💭\" : \"✧\";\n\n// 📁 prefix for the status-bar cwd; plain mode keeps the bare path.\nexport const folderIcon = iconMode === \"emoji\" ? \"📁 \" : \"\";\n","// Model/tool-controlled text lands in Ink's live region, where each frame is\n// erased and redrawn based on Ink's own width math. string-width reports \\t\n// as width 0 while real terminals expand it to the next tab stop, and raw\n// control bytes (\\r, ESC, …) move the cursor — both make the on-screen frame\n// taller than Ink counted, so the erase misses lines and every spinner tick\n// leaves a stale duplicate behind (the \"scroll spam\" bug). Normalize such\n// text before it reaches the terminal: tabs become two spaces, all other C0\n// controls except \\n are dropped. Display-only — persisted messages and tool\n// results keep the original bytes.\n// biome-ignore lint/suspicious/noControlCharactersInRegex: matching control characters is the whole point\nconst UNSAFE_CHARS = /[\\x00-\\x09\\x0b-\\x1f\\x7f]/;\n// biome-ignore lint/suspicious/noControlCharactersInRegex: matching control characters is the whole point\nconst CONTROL_CHARS = /[\\x00-\\x08\\x0b-\\x1f\\x7f]/g;\nconst TABS = /\\t/g;\n\nexport function toTerminalSafe(text: string): string {\n if (!UNSAFE_CHARS.test(text)) return text;\n return text.replace(TABS, \" \").replace(CONTROL_CHARS, \"\");\n}\n","// Minimal markdown renderer for terminal output: compiles a markdown subset\n// (headings, bold/italic/strikethrough, inline code, fenced code blocks,\n// links, images, blockquotes, horizontal rules, pipe tables) into an\n// ANSI-styled string suitable for a single Ink <Text> node.\n//\n// `base` is the ANSI SGR code of the surrounding text color (e.g. \"32\" for\n// the green assistant text): every styled span ends with a full reset, so\n// the base must be re-opened after each span or the rest of the line would\n// lose its color.\n//\n// Streaming-safe: unclosed inline markers and fences render as literal text\n// until completed. Width accounting uses display cells (CJK/emoji = 2) so\n// tables stay aligned for CJK content.\n\nconst ESC = \"\\u001B[\";\nconst RESET = `${ESC}0m`;\n\nfunction styled(open: string, text: string, base: string): string {\n const reopen = base ? `${ESC}${base}m` : \"\";\n return `${ESC}${open}m${text}${RESET}${reopen}`;\n}\n\nconst bold = (t: string, b: string) => styled(\"1\", t, b);\nconst dim = (t: string, b: string) => styled(\"2\", t, b);\nconst italic = (t: string, b: string) => styled(\"3\", t, b);\nconst underline = (t: string, b: string) => styled(\"4\", t, b);\nconst strike = (t: string, b: string) => styled(\"9\", t, b);\nconst yellow = (t: string, b: string) => styled(\"33\", t, b);\nconst cyanBold = (t: string, b: string) => styled(\"1;36\", t, b);\n\n// Display width in terminal cells: CJK-wide and emoji ranges count 2,\n// combining marks / ZWJ / variation selectors count 0. Good enough for table\n// alignment; Ink does its own precise width math for wrapping.\nexport function cellWidth(text: string): number {\n let width = 0;\n for (const ch of text) {\n const cp = ch.codePointAt(0) ?? 0;\n if ((cp >= 0x0300 && cp <= 0x036f) || cp === 0x200d || (cp >= 0xfe00 && cp <= 0xfe0f)) {\n continue;\n }\n if (\n (cp >= 0x1100 && cp <= 0x115f) ||\n (cp >= 0x2e80 && cp <= 0x9fff) ||\n (cp >= 0xa000 && cp <= 0xa4cf) ||\n (cp >= 0xac00 && cp <= 0xd7a3) ||\n (cp >= 0xf900 && cp <= 0xfaff) ||\n (cp >= 0xfe30 && cp <= 0xfe4f) ||\n (cp >= 0xff00 && cp <= 0xff60) ||\n (cp >= 0xffe0 && cp <= 0xffe6) ||\n (cp >= 0x1f000 && cp <= 0x1faff) ||\n (cp >= 0x20000 && cp <= 0x3fffd)\n ) {\n width += 2;\n } else {\n width += 1;\n }\n }\n return width;\n}\n\nconst IMAGE_RE = /!\\[([^\\]]*)\\]\\(([^)\\s]+)\\)/g;\nconst LINK_RE = /\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/g;\nconst BOLD_RE = /\\*\\*([^*\\n]+)\\*\\*|__([^_\\n]+)__/g;\nconst STRIKE_RE = /~~([^~\\n]+)~~/g;\nconst STAR_ITALIC_RE = /\\*([^*\\n]+)\\*/g;\n// _emphasis_ only at word boundaries so snake_case stays literal.\nconst UNDERSCORE_ITALIC_RE = /(^|[^\\w])_([^_\\n]+)_(?=[^\\w]|$)/g;\n\n// Inline styles. Code spans are split out first so their contents are never\n// re-parsed for emphasis markers.\nexport function renderInline(text: string, base = \"\"): string {\n return text\n .split(/`([^`\\n]+)`/)\n .map((segment, index) => {\n // Odd segments are code-span contents.\n if (index % 2 === 1) return yellow(segment, base);\n return segment\n .replace(IMAGE_RE, (_m, alt: string) => dim(`[image: ${alt}]`, base))\n .replace(\n LINK_RE,\n (_m, label: string, url: string) => `${underline(label, base)}${dim(` (${url})`, base)}`,\n )\n .replace(BOLD_RE, (_m, star: string, under: string) => bold(star ?? under, base))\n .replace(STRIKE_RE, (_m, t: string) => strike(t, base))\n .replace(STAR_ITALIC_RE, (_m, t: string) => italic(t, base))\n .replace(UNDERSCORE_ITALIC_RE, (_m, pre: string, t: string) => pre + italic(t, base));\n })\n .join(\"\");\n}\n\nconst HEADING_RE = /^#{1,6}\\s+(.*)$/;\nconst HR_RE = /^\\s{0,3}(?:-{3,}|\\*{3,}|_{3,})\\s*$/;\nconst QUOTE_RE = /^\\s{0,3}>\\s?(.*)$/;\nconst FENCE_RE = /^\\s{0,3}(```+|~~~+)/;\nconst TABLE_SEPARATOR_CELL_RE = /^:?-{3,}:?$/;\n\nfunction isTableSeparator(line: string): boolean {\n const cells = splitTableRow(line);\n return (\n cells !== null &&\n cells.length > 0 &&\n cells.every((cell) => TABLE_SEPARATOR_CELL_RE.test(cell.trim()))\n );\n}\n\nfunction splitTableRow(line: string): string[] | null {\n const trimmed = line.trim();\n if (!trimmed.includes(\"|\")) return null;\n const stripped = trimmed.replace(/^\\|/, \"\").replace(/\\|$/, \"\");\n return stripped.split(\"|\").map((cell) => cell.trim());\n}\n\n// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping ANSI is the point\nconst ANSI_RE = /\\u001B\\[[0-9;]*m/g;\n\nconst MIN_COLUMN_WIDTH = 4;\n\n// Wraps a cell to its column width by display cells. Breaks at the last\n// space when there is one, hard-breaks otherwise (CJK text has no spaces).\nfunction wrapCell(text: string, width: number): string[] {\n const lines: string[] = [];\n let current = \"\";\n let currentWidth = 0;\n for (const ch of text) {\n const w = cellWidth(ch);\n if (currentWidth > 0 && currentWidth + w > width) {\n const lastSpace = current.lastIndexOf(\" \");\n if (lastSpace > 0 && ch !== \" \") {\n lines.push(current.slice(0, lastSpace));\n current = current.slice(lastSpace + 1) + ch;\n } else {\n lines.push(current);\n current = ch === \" \" ? \"\" : ch;\n }\n currentWidth = cellWidth(current);\n } else {\n current += ch;\n currentWidth += w;\n }\n }\n if (current.length > 0 || lines.length === 0) lines.push(current);\n return lines;\n}\n\nfunction renderTable(lines: string[], base: string, maxWidth: number): string[] {\n const rows: string[][] = [];\n for (const line of lines) {\n const cells = splitTableRow(line);\n if (cells) rows.push(cells);\n }\n if (rows.length < 2) return lines;\n const columnCount = Math.max(...rows.map((row) => row.length));\n // Natural widths first: columns only shrink when the whole grid would\n // exceed the terminal — then the widest column gives up one cell at a\n // time. Overlong cell text wraps onto extra lines instead of truncating.\n const widths = Array.from({ length: columnCount }, (_, column) =>\n Math.max(1, ...rows.map((row) => cellWidth(row[column] ?? \"\"))),\n );\n // 2 for the indent, 3 per \" │ \" joiner.\n const totalWidth = () =>\n 2 + widths.reduce((sum, width) => sum + width, 0) + 3 * (columnCount - 1);\n while (totalWidth() > maxWidth) {\n const widest = widths.indexOf(Math.max(...widths));\n if (widths[widest] === undefined || widths[widest] <= MIN_COLUMN_WIDTH) break;\n widths[widest] -= 1;\n }\n // Padding is appended after styling so ANSI bytes never skew the alignment,\n // and is measured on the styled text's visible width: renderInline strips\n // markers (backticks, **, link syntax), so the raw cell width would\n // over-pad and push the │ joiners off the grid.\n const joiner = ` ${dim(\"│\", base)} `;\n const formatRow = (row: string[], style: (cell: string) => string): string[] => {\n const wrapped = widths.map((width, column) => wrapCell(row[column] ?? \"\", width));\n const height = Math.max(...wrapped.map((cell) => cell.length));\n const out: string[] = [];\n for (let line = 0; line < height; line++) {\n out.push(\n ` ${widths\n .map((width, column) => {\n const rendered = style(wrapped[column]?.[line] ?? \"\");\n const visible = cellWidth(rendered.replace(ANSI_RE, \"\"));\n return rendered + \" \".repeat(Math.max(0, width - visible));\n })\n .join(joiner)\n .trimEnd()}`,\n );\n }\n return out;\n };\n const separator = dim(` ${widths.map((width) => \"─\".repeat(width)).join(\"─┼─\")}`, base);\n const [header, , ...body] = rows as [string[], string[], ...string[][]];\n return [\n ...formatRow(header, (cell) => bold(cell, base)),\n separator,\n ...body.flatMap((row, index) => {\n const lines = formatRow(row, (cell) => renderInline(cell, base));\n return index < body.length - 1 ? [...lines, separator] : lines;\n }),\n ];\n}\n\n// Longest leading run of lines that ends at a markdown block boundary: not\n// inside a fenced code block, and not inside a run of pipe lines (a table, or\n// a would-be table whose separator is still streaming). The REPL commits\n// streamed text to static history in chunks and each chunk is rendered\n// standalone, so a chunk must never end mid-construct — a table split in two\n// would render its tail as raw pipe text.\nexport function committableLineCount(lines: string[]): number {\n let inFence = false;\n let safe = 0;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n if (FENCE_RE.test(line)) inFence = !inFence;\n const isPipe = line.includes(\"|\");\n // For the last line the next line is still streaming, so assume the worst.\n const nextIsPipe = i + 1 >= lines.length || (lines[i + 1] ?? \"\").includes(\"|\");\n if (!inFence && !(isPipe && nextIsPipe)) safe = i + 1;\n }\n return safe;\n}\n\n// Renders a markdown block into an ANSI-styled string. `base` re-opens the\n// surrounding text color after each styled span (see module docstring).\n// `maxWidth` caps rendered table grids so rows never wrap in the terminal.\nexport function renderMarkdown(text: string, base = \"\", maxWidth = 80): string {\n const lines = text.split(\"\\n\");\n const out: string[] = [];\n let inFence = false;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n if (inFence) {\n if (FENCE_RE.test(line)) {\n inFence = false;\n } else {\n out.push(`${dim(\" ▎\", base)}${line}`);\n }\n continue;\n }\n const fence = FENCE_RE.exec(line);\n if (fence) {\n inFence = true;\n const lang = line\n .trim()\n .slice(fence[1]?.length ?? 0)\n .trim();\n if (lang) out.push(dim(` ▎ ${lang}`, base));\n continue;\n }\n const heading = HEADING_RE.exec(line);\n if (heading) {\n out.push(cyanBold(heading[1] ?? \"\", base));\n continue;\n }\n if (HR_RE.test(line)) {\n out.push(dim(\" ────────\", base));\n continue;\n }\n const quote = QUOTE_RE.exec(line);\n if (quote) {\n out.push(`${dim(\" ▎\", base)}${italic(renderInline(quote[1] ?? \"\", base), base)}`);\n continue;\n }\n // Pipe table: a header row followed by a --- separator row.\n const headerCells = splitTableRow(line);\n if (headerCells && i + 1 < lines.length && isTableSeparator(lines[i + 1] ?? \"\")) {\n const block = [line];\n let j = i + 1;\n while (j < lines.length && splitTableRow(lines[j] ?? \"\") !== null) {\n block.push(lines[j] ?? \"\");\n j += 1;\n }\n out.push(...renderTable(block, base, maxWidth));\n i = j - 1;\n continue;\n }\n out.push(renderInline(line, base));\n }\n return out.join(\"\\n\");\n}\n","import type { StreamErrorInfo } from \"../core/events\";\nimport { type CoreMessage, type StarMessage, coreMessageText } from \"../core/messages\";\nimport type { DisplayMessage } from \"./components/MessageList\";\nimport { toolIcon } from \"./icons\";\nimport { committableLineCount } from \"./markdown\";\nimport { toTerminalSafe } from \"./terminal-text\";\n\n// Re-exported so CLI consumers keep their existing import path; the\n// implementation lives in core/messages.ts, shared with the agent loop.\nexport { coreMessageText };\n\nexport function summarizeArgs(args: unknown, maxLength = 120): string {\n let json: string;\n try {\n json = JSON.stringify(args) ?? String(args);\n } catch {\n json = String(args);\n }\n return json.length > maxLength ? `${json.slice(0, maxLength)}...` : json;\n}\n\nexport function previewLines(text: string, maxLines = 10): { text: string; truncated: boolean } {\n const lines = text.split(\"\\n\");\n if (lines.length <= maxLines) return { text, truncated: false };\n return { text: lines.slice(0, maxLines).join(\"\\n\"), truncated: true };\n}\n\nexport function formatByteCount(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;\n}\n\n// Elapsed-time label for the thinking indicator: seconds while short, then\n// the two largest units (1m5s, 1h2m3s) so long relay waits stay readable.\nexport function formatElapsedSeconds(seconds: number): string {\n const total = Math.max(0, Math.floor(seconds));\n if (total < 60) return `${total}s`;\n const minutes = Math.floor(total / 60);\n const secs = total % 60;\n if (minutes < 60) return `${minutes}m${secs}s`;\n return `${Math.floor(minutes / 60)}h${minutes % 60}m${secs}s`;\n}\n\n// Splits a streaming buffer into a committable head (complete lines) and a\n// remainder, once the buffer holds at least minCompleteLines complete lines.\n// The last line is always kept in the remainder: it may still be growing.\n// The head is further capped at a markdown block boundary (never mid-table\n// or mid-fence) because committed chunks render standalone in static history.\n// Returns null when there is nothing worth committing yet.\nexport function splitCommittableLines(\n text: string,\n minCompleteLines: number,\n): { committed: string; rest: string } | null {\n const lastNewline = text.lastIndexOf(\"\\n\");\n if (lastNewline < 0) return null;\n const complete = text.slice(0, lastNewline);\n const lines = complete.split(\"\\n\");\n const count = committableLineCount(lines);\n if (count < minCompleteLines) return null;\n const committed = lines.slice(0, count).join(\"\\n\");\n return { committed, rest: text.slice(committed.length + 1) };\n}\n\nexport function formatStreamError(error: StreamErrorInfo): string {\n if (error.message.includes(\"Unexpected end of JSON input\")) {\n return `${error.message} (response stream was truncated — try again)`;\n }\n return error.message;\n}\n\n// Accepts plain CoreMessages or StarMessages (the side-band meta survives\n// resume/rewind/compact redraws): a user message injected as a steering\n// prompt renders with the steer color instead of plain user styling.\nexport function buildDisplayMessages(\n messages: readonly (CoreMessage | StarMessage)[],\n): DisplayMessage[] {\n const display: DisplayMessage[] = [];\n let collapsed = 0;\n for (const item of messages) {\n const star: StarMessage = \"role\" in item ? { message: item } : item;\n const message = star.message;\n const steer = star.meta?.synthetic === \"steer\" ? true : undefined;\n if (message.role === \"user\" || message.role === \"assistant\") {\n const content = message.content;\n if (!Array.isArray(content)) {\n const text = coreMessageText(message);\n if (text) {\n // Restored history skips the streaming ingestion path, so escape it\n // here instead (idempotent — live-turn text is already normalized).\n display.push({\n id: display.length,\n role: message.role,\n text: toTerminalSafe(text),\n steer,\n });\n } else {\n collapsed++;\n }\n continue;\n }\n // Tool calls fold in place: each call renders as one dim summary line\n // at its original position (same header shape as the live tool card),\n // so a resumed transcript keeps the order things happened in instead\n // of sinking every call into one trailing count.\n let textParts: string[] = [];\n let represented = false;\n const flushText = () => {\n const text = textParts.join(\" \");\n textParts = [];\n if (!text) return;\n represented = true;\n display.push({\n id: display.length,\n role: message.role,\n text: toTerminalSafe(text),\n steer,\n });\n };\n for (const part of content) {\n if (part.type === \"text\" && \"text\" in part) {\n textParts.push(part.text);\n } else if (part.type === \"tool-call\") {\n flushText();\n represented = true;\n display.push({\n id: display.length,\n role: \"tool\",\n text: toTerminalSafe(\n `${toolIcon(part.toolName)} ${part.toolName} ${summarizeArgs(part.args)}`,\n ),\n dim: true,\n });\n }\n }\n flushText();\n if (!represented) collapsed++;\n } else if (message.role === \"tool\") {\n collapsed++;\n }\n }\n if (collapsed > 0) {\n display.push({\n id: display.length,\n role: \"system\",\n text: `Restored ${collapsed} history message(s) not shown here.`,\n });\n }\n return display;\n}\n","import { readFile, readdir, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { downsampleImageIfNeeded } from \"../core/image-resize\";\nimport type { ImageInput } from \"../core/messages\";\nimport {\n type IgnorePredicate,\n SKIP_DIRS,\n createIgnorePredicate,\n isSensitivePath,\n} from \"../tools/fs/util\";\n\nexport const MAX_MENTION_BYTES = 100 * 1024;\nexport const MAX_IMAGE_BYTES = 5 * 1024 * 1024;\nexport const MAX_DIR_MENTION_ENTRIES = 200;\nexport const MAX_DIR_MENTION_DEPTH = 10;\n// Backstop for the total-entry count: past this the listing reports \"many\n// more entries\" instead of counting a huge tree (e.g. @. in a repo) to the\n// end.\nexport const MAX_DIR_MENTION_TOTAL = 5000;\n\nconst IMAGE_MIME_TYPES: Record<string, string> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n};\n\nexport function imageMimeType(filePath: string): string | null {\n return IMAGE_MIME_TYPES[path.extname(filePath).toLowerCase()] ?? null;\n}\n\n// Reads an image file into a base64 ImageInput, downsampling anything past\n// the dimension cap. Returns null when the path is not a supported image or\n// cannot be read.\nexport async function readImageInput(filePath: string, cwd: string): Promise<ImageInput | null> {\n const mimeType = imageMimeType(filePath);\n if (!mimeType) return null;\n const abs = path.resolve(cwd, filePath);\n const st = await stat(abs).catch(() => null);\n if (!st || !st.isFile() || st.size > MAX_IMAGE_BYTES) return null;\n const buf = await readFile(abs).catch(() => null);\n if (!buf) return null;\n const result = await downsampleImageIfNeeded({\n path: filePath,\n mimeType,\n data: buf.toString(\"base64\"),\n });\n return result.image;\n}\n\nexport interface ParsedMentions {\n cleanText: string;\n mentions: string[];\n}\n\n// CJK ranges cover unified ideographs, Hangul syllables, compatibility\n// ideographs and fullwidth forms so @中文文件名.md mentions parse. Keep in\n// sync with the token charset path-suggest's extractAtToken accepts (\\S).\nconst MENTION_RE =\n /(?<=^|\\s)@([A-Za-z]:[\\\\/][A-Za-z0-9._\\-/\\\\\\u2e80-\\u9fff\\uac00-\\ud7af\\uf900-\\ufaff\\uff00-\\uffef]*|[A-Za-z0-9._\\-/\\\\\\u2e80-\\u9fff\\uac00-\\ud7af\\uf900-\\ufaff\\uff00-\\uffef]+)/g;\n\nexport function parseMentions(text: string): ParsedMentions {\n const mentions: string[] = [];\n const seen = new Set<string>();\n const ranges: Array<[number, number]> = [];\n for (const match of text.matchAll(MENTION_RE)) {\n const mention = match[1];\n const full = match[0];\n if (mention === undefined || full === undefined) continue;\n ranges.push([match.index, match.index + full.length]);\n if (!seen.has(mention)) {\n seen.add(mention);\n mentions.push(mention);\n }\n }\n if (ranges.length === 0) {\n return { cleanText: text, mentions };\n }\n let clean = \"\";\n let last = 0;\n for (const [start, end] of ranges) {\n clean += text.slice(last, start);\n last = end;\n }\n clean += text.slice(last);\n const cleanText = clean\n .replace(/[ \\t]+\\n/g, \"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n return { cleanText, mentions };\n}\n\nexport interface MentionSkip {\n path: string;\n reason: string;\n}\n\nexport interface ResolvedMentions {\n input: string;\n attached: string[];\n skipped: MentionSkip[];\n images: ImageInput[];\n}\n\nfunction isBinaryContent(buf: Buffer): boolean {\n const probe = buf.subarray(0, 8000);\n return probe.includes(0);\n}\n\ninterface DirListState {\n lines: string[];\n shown: number;\n total: number;\n capped: boolean;\n}\n\nasync function listDirEntries(\n dir: string,\n prefix: string,\n depth: number,\n state: DirListState,\n ignore: IgnorePredicate | undefined,\n): Promise<void> {\n if (state.capped) return;\n const entries = await readdir(dir, { withFileTypes: true }).catch(() => null);\n if (!entries) return;\n const visible = entries\n .filter((entry) => entry.isDirectory() || entry.isFile())\n .filter((entry) => !(entry.isDirectory() && SKIP_DIRS.has(entry.name)))\n .filter((entry) => !isSensitivePath(entry.name))\n .filter((entry) => !ignore?.(path.join(dir, entry.name), entry.isDirectory()))\n .sort((a, b) => {\n const dirDiff = Number(b.isDirectory()) - Number(a.isDirectory());\n return dirDiff !== 0 ? dirDiff : a.name.localeCompare(b.name);\n });\n for (let i = 0; i < visible.length; i++) {\n if (state.total >= MAX_DIR_MENTION_TOTAL) {\n state.capped = true;\n return;\n }\n const entry = visible[i];\n if (!entry) continue;\n state.total += 1;\n const last = i === visible.length - 1;\n const isDir = entry.isDirectory();\n if (state.shown < MAX_DIR_MENTION_ENTRIES) {\n state.shown += 1;\n state.lines.push(`${prefix}${last ? \"└── \" : \"├── \"}${entry.name}${isDir ? \"/\" : \"\"}`);\n if (isDir && depth < MAX_DIR_MENTION_DEPTH) {\n await listDirEntries(\n path.join(dir, entry.name),\n `${prefix}${last ? \" \" : \"│ \"}`,\n depth + 1,\n state,\n ignore,\n );\n }\n } else if (isDir && depth < MAX_DIR_MENTION_DEPTH) {\n await listDirEntries(path.join(dir, entry.name), prefix, depth + 1, state, ignore);\n }\n }\n}\n\n// Renders a directory mention as an indented tree block. Returns null when the\n// directory cannot be read at all.\nasync function directoryBlock(\n abs: string,\n mention: string,\n ignore: IgnorePredicate | undefined,\n): Promise<string | null> {\n const display = `${mention.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\")}/`;\n const state: DirListState = { lines: [`${display}`], shown: 0, total: 0, capped: false };\n const probe = await readdir(abs).catch(() => null);\n if (!probe) return null;\n await listDirEntries(abs, \"\", 1, state, ignore);\n if (state.capped) {\n state.lines.push(\"... (truncated, many more entries)\");\n } else if (state.total > state.shown) {\n state.lines.push(\n `... (truncated, ${state.total - state.shown} more entries — use glob/grep tools or mention a subdirectory to see more)`,\n );\n }\n return `--- @${display} (directory) ---\\n${state.lines.join(\"\\n\")}\\n--- end ---`;\n}\n\nexport async function resolveMentions(text: string, cwd: string): Promise<ResolvedMentions> {\n const { cleanText, mentions } = parseMentions(text);\n if (mentions.length === 0) {\n return { input: text, attached: [], skipped: [], images: [] };\n }\n const blocks: string[] = [];\n const attached: string[] = [];\n const skipped: MentionSkip[] = [];\n const images: ImageInput[] = [];\n let ignore: IgnorePredicate | null | undefined;\n for (const mention of mentions) {\n const abs = path.resolve(cwd, mention);\n if (isSensitivePath(abs)) {\n skipped.push({ path: mention, reason: \"sensitive file\" });\n continue;\n }\n const mimeType = imageMimeType(mention);\n if (mimeType) {\n const st = await stat(abs).catch(() => null);\n if (!st || !st.isFile()) {\n skipped.push({ path: mention, reason: st ? \"is a directory\" : \"file not found\" });\n continue;\n }\n if (st.size > MAX_IMAGE_BYTES) {\n skipped.push({ path: mention, reason: \"image too large\" });\n continue;\n }\n const buf = await readFile(abs).catch(() => null);\n if (!buf) {\n skipped.push({ path: mention, reason: \"unreadable\" });\n continue;\n }\n const result = await downsampleImageIfNeeded({\n path: mention,\n mimeType,\n data: buf.toString(\"base64\"),\n });\n attached.push(mention);\n images.push(result.image);\n continue;\n }\n const st = await stat(abs).catch(() => null);\n if (!st) {\n skipped.push({ path: mention, reason: \"file not found\" });\n continue;\n }\n if (st.isDirectory()) {\n if (ignore === undefined) {\n ignore = createIgnorePredicate(cwd) ?? null;\n }\n const block = await directoryBlock(abs, mention, ignore ?? undefined);\n if (!block) {\n skipped.push({ path: mention, reason: \"unreadable\" });\n continue;\n }\n attached.push(mention);\n blocks.push(block);\n continue;\n }\n if (st.size > MAX_MENTION_BYTES) {\n skipped.push({ path: mention, reason: `exceeds ${MAX_MENTION_BYTES / 1024}KB limit` });\n continue;\n }\n const buf = await readFile(abs).catch(() => null);\n if (!buf) {\n skipped.push({ path: mention, reason: \"unreadable\" });\n continue;\n }\n if (isBinaryContent(buf)) {\n skipped.push({ path: mention, reason: \"binary file\" });\n continue;\n }\n attached.push(mention);\n blocks.push(`--- @${mention} ---\\n${buf.toString(\"utf8\")}\\n--- end ---`);\n }\n const input = [cleanText, ...blocks].filter((s) => s.length > 0).join(\"\\n\\n\") || text;\n return { input, attached, skipped, images };\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { FileSnapshot } from \"../tools/fs/snapshots\";\nimport { withTransientFsRetry } from \"./store\";\n\nexport interface CheckpointRecord {\n id: number;\n timestamp: number;\n path: string;\n existed: boolean;\n toolName: string;\n turn: number;\n messageIndex: number;\n owner?: \"root\" | \"subagent\";\n // Set when the original content exceeded the snapshot size cap: no content\n // file exists and reverts must skip the file.\n contentTooLarge?: boolean;\n}\n\nfunction checkpointsDir(sessionDir: string): string {\n return path.join(sessionDir, \"checkpoints\");\n}\n\nfunction indexPath(sessionDir: string): string {\n return path.join(checkpointsDir(sessionDir), \"index.json\");\n}\n\n// Read-modify-write on index.json is serialized per session directory, the\n// same pattern as SessionStore's metaWriteQueue: the root loop and background\n// subagents append checkpoints concurrently, and unprotected read-then-write\n// loses records.\nconst indexWriteQueues = new Map<string, Promise<void>>();\n\nfunction enqueueIndexWrite<T>(sessionDir: string, op: () => Promise<T>): Promise<T> {\n const queued = indexWriteQueues.get(sessionDir) ?? Promise.resolve();\n const run = queued.then(op);\n // The map entry must not outlive the queue it serializes: sessions come and\n // go, and keying by directory would otherwise grow without bound. Only\n // delete when this tail is still the latest — a newer op may have enqueued\n // behind it already.\n const tail = run.then(\n () => {},\n () => {},\n );\n indexWriteQueues.set(sessionDir, tail);\n void tail.then(() => {\n if (indexWriteQueues.get(sessionDir) === tail) indexWriteQueues.delete(sessionDir);\n });\n return run;\n}\n\nlet indexTmpSeq = 0;\n\n// index.json rewrites land atomically (tmp + rename) with the same\n// transient-lock retries as the store's meta writes: a crash mid-writeFile\n// would otherwise corrupt the whole /rewind index.\nasync function writeIndex(sessionDir: string, records: CheckpointRecord[]): Promise<void> {\n const target = indexPath(sessionDir);\n const tmp = `${target}.tmp-${process.pid}-${indexTmpSeq++}`;\n try {\n await withTransientFsRetry(async () => {\n await fs.writeFile(tmp, JSON.stringify(records, null, 2));\n await fs.rename(tmp, target);\n });\n } catch (error) {\n await fs.unlink(tmp).catch(() => {});\n throw error;\n }\n}\n\nexport function checkpointContentPath(sessionDir: string, id: number): string {\n return path.join(checkpointsDir(sessionDir), `${id}.snapshot`);\n}\n\nexport async function listCheckpointRecords(sessionDir: string): Promise<CheckpointRecord[]> {\n let raw: string;\n try {\n raw = await fs.readFile(indexPath(sessionDir), \"utf8\");\n } catch {\n return [];\n }\n try {\n const parsed = JSON.parse(raw) as CheckpointRecord[];\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n // A missing index is normal (no checkpoints yet); a corrupt one means the\n // /rewind history was lost — say so instead of failing silently.\n process.stderr.write(\n `[star-cli] checkpoints index unreadable for session ${path.basename(sessionDir)}, ignoring it\\n`,\n );\n return [];\n }\n}\n\n// Lazily creates the checkpoints directory on first use, mirroring\n// SessionStore's lazy creation — a session without file writes leaves no\n// checkpoints on disk.\nexport async function appendCheckpointRecord(\n sessionDir: string,\n record: CheckpointRecord,\n content: string | Buffer | null,\n): Promise<void> {\n await enqueueIndexWrite(sessionDir, async () => {\n await fs.mkdir(checkpointsDir(sessionDir), { recursive: true, mode: 0o700 });\n if (record.existed && content !== null) {\n // writeFile ignores the encoding for Buffer data, so binary snapshots\n // persist byte-exact; string content stays utf8 as before.\n await fs.writeFile(checkpointContentPath(sessionDir, record.id), content, \"utf8\");\n }\n const records = await listCheckpointRecords(sessionDir);\n records.push(record);\n await writeIndex(sessionDir, records);\n });\n}\n\nexport async function removeCheckpointRecords(sessionDir: string, ids: number[]): Promise<void> {\n if (ids.length === 0) return;\n await enqueueIndexWrite(sessionDir, async () => {\n const drop = new Set(ids);\n const records = await listCheckpointRecords(sessionDir);\n const kept = records.filter((record) => !drop.has(record.id));\n if (kept.length === records.length) return;\n await fs.mkdir(checkpointsDir(sessionDir), { recursive: true, mode: 0o700 });\n await writeIndex(sessionDir, kept);\n for (const id of ids) {\n await fs.rm(checkpointContentPath(sessionDir, id), { force: true });\n }\n });\n}\n\n// Maps persisted records back into snapshots whose content is read lazily\n// from the per-checkpoint content file, for hydrating the in-memory stack\n// after a session resume.\nexport async function loadSessionSnapshots(sessionDir: string): Promise<FileSnapshot[]> {\n const records = await listCheckpointRecords(sessionDir);\n return records.map((record) => ({\n ...record,\n content: null,\n contentFile:\n record.existed && !record.contentTooLarge\n ? checkpointContentPath(sessionDir, record.id)\n : undefined,\n }));\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { StringDecoder } from \"node:string_decoder\";\nimport { sessionsDir } from \"../config/paths\";\nimport type { CoreMessage, MessageMeta, StarMessage } from \"../core/messages\";\nimport {\n type CheckpointRecord,\n appendCheckpointRecord,\n listCheckpointRecords,\n removeCheckpointRecords,\n} from \"./checkpoints\";\n\nexport interface SessionUsage {\n requests: number;\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n // Prompt-cache totals; present only after a provider reports cache fields.\n cachedPromptTokens?: number;\n cacheReadInputTokens?: number;\n}\n\nexport interface DayUsageBucket {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\nexport interface SessionMeta {\n id: string;\n title: string;\n model: string;\n cwd: string;\n createdAt: number;\n updatedAt: number;\n usage?: SessionUsage;\n // Per-day token buckets keyed by local date (YYYY-MM-DD), recorded alongside\n // `usage` from the day this field was introduced; older sessions only have\n // the grand totals in `usage`.\n usageByDay?: Record<string, DayUsageBucket>;\n}\n\nfunction generateId(now: Date): string {\n const pad = (n: number) => String(n).padStart(2, \"0\");\n const stamp =\n `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}` +\n `${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;\n const suffix = Math.random().toString(16).slice(2, 8).padEnd(6, \"0\");\n return `${stamp}-${suffix}`;\n}\n\n// Two processes creating a session in the same second share the timestamp\n// stamp, and a colliding random suffix would merge both sessions into one\n// directory — so an occupied id is redrawn a few times and ultimately widened\n// with a randomUUID segment.\nconst ID_COLLISION_MAX_ATTEMPTS = 5;\n\nfunction generateUniqueId(): string {\n let id = generateId(new Date());\n for (let attempt = 1; existsSync(path.join(sessionsDir(), id)); attempt++) {\n if (attempt >= ID_COLLISION_MAX_ATTEMPTS) {\n const stamp = id.slice(0, id.lastIndexOf(\"-\"));\n return `${stamp}-${randomUUID().replaceAll(\"-\", \"\").slice(0, 12)}`;\n }\n id = generateId(new Date());\n }\n return id;\n}\n\n// Sessions record their owning cwd as a raw string, but on Windows the same\n// directory shows up with different drive-letter casing and trailing\n// separators; comparing raw strings would orphan those sessions from the\n// `star -c` / list filter. win32 comparisons resolve both sides and fold\n// case; POSIX paths are case-sensitive and stay as recorded.\nexport function normalizeCwdForCompare(\n cwd: string,\n platform: NodeJS.Platform = process.platform,\n): string {\n if (platform !== \"win32\") return cwd;\n const resolved = path.win32.resolve(cwd);\n const trimmed = resolved.replace(/[\\\\/]+$/, \"\");\n return (trimmed === \"\" ? resolved : trimmed).toLowerCase();\n}\n\nfunction debugWarn(message: string): void {\n if (process.env.STAR_DEBUG === \"1\") process.stderr.write(`[star-cli] ${message}\\n`);\n}\n\n// Persistent message-write failures surface unconditionally (unlike\n// debugWarn): a dropped append means the line is missing after a resume.\nfunction warn(message: string): void {\n process.stderr.write(`[star-cli] ${message}\\n`);\n}\n\n// Windows antivirus and search indexers briefly lock freshly written files,\n// so a write or rename right after the touch can come back EPERM/EACCES/EBUSY;\n// a few short retries ride out the scan. Shared by meta writes, message\n// appends and history rewrites.\nconst FS_WRITE_MAX_ATTEMPTS = 5;\nconst FS_WRITE_RETRY_DELAY_MS = 25;\n\nfunction isTransientFsError(error: unknown): boolean {\n const code = (error as NodeJS.ErrnoException).code;\n return code === \"EPERM\" || code === \"EACCES\" || code === \"EBUSY\";\n}\n\nexport async function withTransientFsRetry(operation: () => Promise<unknown>): Promise<void> {\n let lastError: unknown;\n for (let attempt = 0; attempt < FS_WRITE_MAX_ATTEMPTS; attempt++) {\n try {\n await operation();\n return;\n } catch (error) {\n lastError = error;\n if (isTransientFsError(error) && attempt + 1 < FS_WRITE_MAX_ATTEMPTS) {\n await new Promise((resolve) =>\n setTimeout(resolve, FS_WRITE_RETRY_DELAY_MS * (attempt + 1)),\n );\n } else {\n break;\n }\n }\n }\n throw lastError;\n}\n\n// Brands the fallback meta returned for a corrupt/unreadable meta.json so\n// writeMeta can refuse to persist it: writing the empty defaults back would\n// wipe the real model/cwd/usage fields still sitting in the damaged file.\nconst FALLBACK_META: unique symbol = Symbol(\"star.fallbackMeta\");\n\nfunction isFallbackMeta(meta: SessionMeta): boolean {\n return (meta as unknown as Record<symbol, unknown>)[FALLBACK_META] === true;\n}\n\n// append() bumps only meta.updatedAt, so those writes are debounced: at most\n// one meta flush per window during a burst plus a trailing flush after it\n// settles (a 30-tool-call turn appends ~60 messages, and each used to land\n// its own atomic tmp+rename meta write). Substantive changes (title, usage,\n// history rewrites, the initial write) still flush immediately.\nconst META_FLUSH_INTERVAL_MS = 2000;\n\n// messages.jsonl is read back in chunks of this size instead of buffering\n// the whole file (a resume used to peak at 3-4x the file size in memory).\nconst MESSAGES_READ_CHUNK_BYTES = 64 * 1024;\n\n// Loop side-band metadata (MessageMeta) persists as an extra key on the\n// message's jsonl row; readers strip it, so older rows without the key and\n// older readers unaware of it both keep working.\nconst STAR_META_KEY = \"__starMeta\";\n\nfunction serializeMessage(star: StarMessage): string {\n if (!star.meta) return JSON.stringify(star.message);\n return JSON.stringify({ ...star.message, [STAR_META_KEY]: star.meta });\n}\n\nfunction parseMessageLine(line: string): StarMessage | null {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n if (parsed !== null && typeof parsed === \"object\" && STAR_META_KEY in parsed) {\n const { [STAR_META_KEY]: meta, ...message } = parsed;\n return { message: message as unknown as CoreMessage, meta: meta as MessageMeta };\n }\n return { message: parsed as unknown as CoreMessage };\n } catch {\n return null;\n }\n}\n\nexport function dayKey(date: Date): string {\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n}\n\nexport class SessionStore {\n readonly id: string;\n readonly dir: string;\n\n private pendingMeta: { cwd: string; model: string; createdAt: number } | null = null;\n private initialized = false;\n private cachedMeta: SessionMeta | null = null;\n private metaTmpSeq = 0;\n private messagesTmpSeq = 0;\n private metaWriteQueue: Promise<void> = Promise.resolve();\n private metaLastFlushAt = 0;\n private metaFlushTimer: NodeJS.Timeout | null = null;\n private metaDirty = false;\n\n private constructor(id: string) {\n this.id = id;\n this.dir = path.join(sessionsDir(), id);\n }\n\n private metaPath(): string {\n return path.join(this.dir, \"meta.json\");\n }\n\n private messagesPath(): string {\n return path.join(this.dir, \"messages.jsonl\");\n }\n\n static async create(cwd: string, model: string): Promise<SessionStore> {\n const store = new SessionStore(generateUniqueId());\n store.pendingMeta = { cwd, model, createdAt: Date.now() };\n return store;\n }\n\n static async open(id: string): Promise<SessionStore | null> {\n const store = new SessionStore(id);\n let raw: string;\n try {\n raw = await fs.readFile(store.metaPath(), \"utf8\");\n } catch {\n return null;\n }\n try {\n const meta = JSON.parse(raw) as SessionMeta;\n if (meta.id !== id) return null;\n } catch {\n // meta.json is corrupt (e.g. truncated write); open anyway and let\n // meta() fall back to defaults so messages stay resumable.\n debugWarn(`session ${id}: corrupt meta.json, using defaults`);\n }\n await store.sweepTmpFiles();\n store.initialized = true;\n return store;\n }\n\n static async list(cwd?: string): Promise<SessionMeta[]> {\n let entries: string[];\n try {\n entries = await fs.readdir(sessionsDir());\n } catch {\n return [];\n }\n const wanted = cwd === undefined ? undefined : normalizeCwdForCompare(cwd);\n const metas = await Promise.all(\n entries.map(async (entry) => {\n try {\n const raw = await fs.readFile(path.join(sessionsDir(), entry, \"meta.json\"), \"utf8\");\n const meta = JSON.parse(raw) as SessionMeta;\n if (\n meta.id === entry &&\n (wanted === undefined || normalizeCwdForCompare(meta.cwd) === wanted)\n ) {\n return meta;\n }\n } catch {\n // 跳过损坏的会话目录\n }\n return null;\n }),\n );\n return metas\n .filter((meta): meta is SessionMeta => meta !== null)\n .sort((a, b) => b.updatedAt - a.updatedAt);\n }\n\n // Meta writes are serialized per instance and land atomically (tmp file +\n // rename) over a cached in-memory meta: the fire-and-forget title/usage\n // writers race the loop's own appends, and a truncated read once turned\n // fallbackMeta's empty defaults into a persisted wipe of model/cwd/usage.\n // A branded fallback meta is never written back for the same reason.\n // A write that still fails after retries is dropped rather than thrown:\n // meta.json is bookkeeping the cached meta rebuilds on the next write,\n // while the conversation itself lives in messages.jsonl — killing the\n // agent turn over a stale updatedAt would be the wrong trade.\n private writeMeta(meta: SessionMeta): Promise<void> {\n if (isFallbackMeta(meta)) return Promise.resolve();\n const tmp = `${this.metaPath()}.tmp-${process.pid}-${this.metaTmpSeq++}`;\n const run = this.metaWriteQueue.then(async () => {\n try {\n await withTransientFsRetry(async () => {\n await fs.writeFile(tmp, JSON.stringify(meta, null, 2));\n await fs.rename(tmp, this.metaPath());\n });\n } catch (error) {\n await fs.unlink(tmp).catch(() => {});\n debugWarn(\n `session ${this.id}: meta write failed (${(error as NodeJS.ErrnoException).code ?? String(error)}), skipping`,\n );\n }\n });\n this.metaWriteQueue = run.catch(() => {});\n return run;\n }\n\n // Debounced flush for append-driven updatedAt bumps. The trailing timer is\n // unref'd so a pending flush never keeps the process alive; close() flushes\n // synchronously on a clean exit, and a hard exit simply drops the trailing\n // bump — meta is bookkeeping.\n private markMetaDirty(): void {\n this.metaDirty = true;\n if (this.metaFlushTimer) return;\n const delay = Math.max(0, META_FLUSH_INTERVAL_MS - (Date.now() - this.metaLastFlushAt));\n if (delay === 0) {\n void this.flushMetaIfDirty();\n return;\n }\n this.metaFlushTimer = setTimeout(() => {\n this.metaFlushTimer = null;\n void this.flushMetaIfDirty();\n }, delay);\n this.metaFlushTimer.unref();\n }\n\n private async flushMetaIfDirty(): Promise<void> {\n if (!this.metaDirty) return;\n await this.flushMetaNow();\n }\n\n // Immediate flush for substantive meta changes; cancels a pending debounced\n // flush, which the write makes redundant either way (it serializes the live\n // cached meta).\n private async flushMetaNow(): Promise<void> {\n if (this.metaFlushTimer) {\n clearTimeout(this.metaFlushTimer);\n this.metaFlushTimer = null;\n }\n this.metaDirty = false;\n this.metaLastFlushAt = Date.now();\n if (this.cachedMeta) await this.writeMeta(this.cachedMeta);\n }\n\n // Flushes a pending debounced meta write and waits for in-flight writes to\n // settle; call when the store is dropped so a clean exit keeps the trailing\n // updatedAt bump.\n async close(): Promise<void> {\n await this.flushMetaIfDirty();\n await this.metaWriteQueue;\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initialized) return;\n const pending = this.pendingMeta;\n if (!pending) {\n this.initialized = true;\n return;\n }\n // Session directories hold file contents (checkpoints); keep them private\n // on shared machines. The mode is a no-op on Windows.\n await fs.mkdir(this.dir, { recursive: true, mode: 0o700 });\n await this.sweepTmpFiles();\n const meta: SessionMeta = {\n id: this.id,\n title: \"\",\n model: pending.model,\n cwd: pending.cwd,\n createdAt: pending.createdAt,\n updatedAt: pending.createdAt,\n };\n await this.writeMeta(meta);\n this.cachedMeta = meta;\n this.metaLastFlushAt = Date.now();\n this.initialized = true;\n }\n\n // Removes tmp orphans left behind by crashed atomic writes (both meta.json\n // and messages.jsonl write tmp file + rename); best-effort, the directory\n // may not even exist yet.\n private async sweepTmpFiles(): Promise<void> {\n let entries: string[];\n try {\n entries = await fs.readdir(this.dir);\n } catch {\n return;\n }\n await Promise.all(\n entries\n .filter(\n (entry) => entry.startsWith(\"meta.json.tmp-\") || entry.startsWith(\"messages.jsonl.tmp-\"),\n )\n .map((entry) => fs.unlink(path.join(this.dir, entry)).catch(() => {})),\n );\n }\n\n async append(message: CoreMessage, meta?: MessageMeta): Promise<void> {\n await this.ensureInitialized();\n // Appends get the same transient-failure retries as meta writes, and a\n // failure that outlasts them degrades to a warning instead of throwing:\n // the agent loop awaits append without a catch, so one AV-locked file\n // must not kill the whole turn. The message still lives in the loop's\n // in-memory history and later appends keep working; only this line is\n // missing from messages.jsonl after a resume.\n try {\n await withTransientFsRetry(() =>\n fs.appendFile(this.messagesPath(), `${serializeMessage({ message, meta })}\\n`),\n );\n } catch (error) {\n warn(\n `session ${this.id}: message append failed (${(error as NodeJS.ErrnoException).code ?? String(error)}), message kept in memory only`,\n );\n }\n const sessionMeta = await this.meta();\n sessionMeta.updatedAt = Date.now();\n this.markMetaDirty();\n }\n\n async replaceMessages(messages: readonly StarMessage[]): Promise<void> {\n await this.ensureInitialized();\n const content = messages.map(serializeMessage).join(\"\\n\");\n // tmp + rename like writeMeta: messages.jsonl is the session's only\n // durable record, and a crash mid-writeFile must not leave it truncated.\n // A rewrite that fails past its retries is dropped with a warning rather\n // than thrown — the previous history stays intact on disk, which is the\n // safer side to land on.\n const tmp = `${this.messagesPath()}.tmp-${process.pid}-${this.messagesTmpSeq++}`;\n try {\n await withTransientFsRetry(async () => {\n await fs.writeFile(tmp, content ? `${content}\\n` : \"\");\n await fs.rename(tmp, this.messagesPath());\n });\n } catch (error) {\n await fs.unlink(tmp).catch(() => {});\n warn(\n `session ${this.id}: history rewrite failed (${(error as NodeJS.ErrnoException).code ?? String(error)}), kept the previous messages.jsonl`,\n );\n }\n const meta = await this.meta();\n meta.updatedAt = Date.now();\n await this.flushMetaNow();\n }\n\n async messages(): Promise<CoreMessage[]> {\n return (await this.starMessages()).map((star) => star.message);\n }\n\n async starMessages(): Promise<StarMessage[]> {\n // Read in fixed-size chunks through a StringDecoder instead of buffering\n // the whole file: a resume used to hold the raw string, the split line\n // array and the parsed objects at once (3-4x the file size at peak). The\n // parsed history is now the only large allocation. Corrupt lines are\n // still skipped; an unreadable file still yields an empty history.\n let handle: fs.FileHandle | null = null;\n try {\n handle = await fs.open(this.messagesPath(), \"r\");\n const messages: StarMessage[] = [];\n const decoder = new StringDecoder(\"utf8\");\n const buffer = Buffer.alloc(MESSAGES_READ_CHUNK_BYTES);\n let tail = \"\";\n const pushLine = (line: string) => {\n const trimmed = line.trim();\n if (!trimmed) return;\n const parsed = parseMessageLine(trimmed);\n if (parsed) {\n messages.push(parsed);\n } else {\n debugWarn(`session ${this.id}: skipping corrupt messages.jsonl line`);\n }\n };\n while (true) {\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, null);\n if (bytesRead === 0) break;\n const chunk = tail + decoder.write(buffer.subarray(0, bytesRead));\n const lines = chunk.split(\"\\n\");\n tail = lines.pop() ?? \"\";\n for (const line of lines) pushLine(line);\n }\n pushLine(tail + decoder.end());\n return messages;\n } catch {\n return [];\n } finally {\n await handle?.close().catch(() => {});\n }\n }\n\n private fallbackMeta(): SessionMeta {\n const now = Date.now();\n const meta: SessionMeta = {\n id: this.id,\n title: \"\",\n model: \"\",\n cwd: \"\",\n createdAt: now,\n updatedAt: now,\n };\n // Non-enumerable, so it neither shows up in JSON.stringify nor spreads.\n Object.defineProperty(meta, FALLBACK_META, { value: true, enumerable: false });\n return meta;\n }\n\n async meta(): Promise<SessionMeta> {\n await this.ensureInitialized();\n if (this.cachedMeta) return this.cachedMeta;\n try {\n const raw = await fs.readFile(this.metaPath(), \"utf8\");\n this.cachedMeta = JSON.parse(raw) as SessionMeta;\n return this.cachedMeta;\n } catch {\n // The fallback is neither cached nor written back: a transient read\n // failure must not turn into a persisted wipe of the real meta.\n debugWarn(`session ${this.id}: unreadable meta.json, using defaults`);\n return this.fallbackMeta();\n }\n }\n\n async setTitle(title: string): Promise<void> {\n await this.ensureInitialized();\n const meta = await this.meta();\n meta.title = title;\n meta.updatedAt = Date.now();\n await this.flushMetaNow();\n }\n\n // /model swaps the live loop mid-session; keep the recorded model in sync\n // or the session list and /usage attribute the whole session to whichever\n // model happened to be active at creation.\n async setModel(model: string): Promise<void> {\n await this.ensureInitialized();\n const meta = await this.meta();\n meta.model = model;\n meta.updatedAt = Date.now();\n await this.flushMetaNow();\n }\n\n async appendCheckpoint(record: CheckpointRecord, content: string | Buffer | null): Promise<void> {\n await this.ensureInitialized();\n await appendCheckpointRecord(this.dir, record, content);\n }\n\n async listCheckpoints(): Promise<CheckpointRecord[]> {\n return listCheckpointRecords(this.dir);\n }\n\n async removeCheckpoints(ids: number[]): Promise<void> {\n await removeCheckpointRecords(this.dir, ids);\n }\n\n async addUsage(delta: {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n cachedPromptTokens?: number;\n cacheReadInputTokens?: number;\n }): Promise<void> {\n await this.ensureInitialized();\n const meta = await this.meta();\n const usage = meta.usage ?? {\n requests: 0,\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n };\n usage.requests += 1;\n usage.promptTokens += delta.promptTokens;\n usage.completionTokens += delta.completionTokens;\n usage.totalTokens += delta.totalTokens;\n if (delta.cachedPromptTokens) {\n usage.cachedPromptTokens = (usage.cachedPromptTokens ?? 0) + delta.cachedPromptTokens;\n }\n if (delta.cacheReadInputTokens) {\n usage.cacheReadInputTokens = (usage.cacheReadInputTokens ?? 0) + delta.cacheReadInputTokens;\n }\n meta.usage = usage;\n const day = dayKey(new Date());\n const byDay = meta.usageByDay ?? {};\n const bucket = byDay[day] ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 };\n bucket.promptTokens += delta.promptTokens;\n bucket.completionTokens += delta.completionTokens;\n bucket.totalTokens += delta.totalTokens;\n byDay[day] = bucket;\n meta.usageByDay = byDay;\n await this.flushMetaNow();\n }\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { sessionsDir } from \"../config/paths\";\nimport type { CoreMessage } from \"../core/messages\";\nimport { type SessionMeta, SessionStore } from \"./store\";\n\nexport interface SessionListEntry {\n meta: SessionMeta;\n messageCount: number;\n}\n\n// Counts newline-terminated records in fixed-size chunks instead of reading\n// the whole file: listSessionEntries runs this for every session, so\n// `star -r` and the /resume picker used to load every full history just for\n// the row's message count. \"\\n\" (0x0A) never appears inside a multi-byte\n// UTF-8 sequence, so a raw byte scan is safe. Lines are written as compact\n// JSON (no raw whitespace), and a blank or whitespace-only fragment is not\n// counted — same semantics as the old readFile + split counter.\nconst COUNT_CHUNK_BYTES = 64 * 1024;\n\nasync function countMessages(id: string): Promise<number> {\n let handle: fs.FileHandle | null = null;\n try {\n handle = await fs.open(path.join(sessionsDir(), id, \"messages.jsonl\"), \"r\");\n const buffer = Buffer.alloc(COUNT_CHUNK_BYTES);\n let count = 0;\n let lineHasContent = false;\n while (true) {\n const { bytesRead } = await handle.read(buffer, 0, COUNT_CHUNK_BYTES, null);\n if (bytesRead === 0) break;\n for (const byte of buffer.subarray(0, bytesRead)) {\n if (byte === 0x0a) {\n if (lineHasContent) count += 1;\n lineHasContent = false;\n } else if (byte !== 0x0d && byte !== 0x20 && byte !== 0x09) {\n lineHasContent = true;\n }\n }\n }\n if (lineHasContent) count += 1;\n return count;\n } catch {\n return 0;\n } finally {\n await handle?.close().catch(() => {});\n }\n}\n\n// Caps how many messages.jsonl files countMessages holds open at once:\n// mapping over every session with Promise.all opens one handle per session\n// concurrently, and a few hundred stored sessions reliably trip EMFILE/EPERM\n// on Windows. Order is preserved — workers claim indices, not slots.\nconst LIST_COUNT_CONCURRENCY = 8;\n\nexport async function listSessionEntries(cwd?: string): Promise<SessionListEntry[]> {\n const metas = await SessionStore.list(cwd);\n const entries: SessionListEntry[] = [];\n let next = 0;\n const worker = async () => {\n while (next < metas.length) {\n const index = next;\n next += 1;\n const meta = metas[index];\n if (!meta) continue;\n entries[index] = { meta, messageCount: await countMessages(meta.id) };\n }\n };\n await Promise.all(\n Array.from({ length: Math.min(LIST_COUNT_CONCURRENCY, metas.length) }, () => worker()),\n );\n return entries;\n}\n\nexport async function findLatestSession(cwd: string): Promise<SessionMeta | null> {\n const [latest] = await SessionStore.list(cwd);\n return latest ?? null;\n}\n\n// Reads only the head of messages.jsonl and extracts the first user message's\n// text, whitespace-collapsed onto one line — the /resume picker needs a\n// preview per session and must not parse every full history for it. The final\n// partial line at the read boundary and any corrupt lines are skipped.\n// Returns null when no user text is found (or the file is unreadable).\nexport async function sessionPreview(id: string, maxBytes = 4096): Promise<string | null> {\n let handle: fs.FileHandle | null = null;\n try {\n handle = await fs.open(path.join(sessionsDir(), id, \"messages.jsonl\"), \"r\");\n const buffer = Buffer.alloc(maxBytes);\n const { bytesRead } = await handle.read(buffer, 0, maxBytes, 0);\n const head = buffer.toString(\"utf8\", 0, bytesRead);\n for (const line of head.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const message = JSON.parse(trimmed) as CoreMessage;\n if (message.role !== \"user\") continue;\n const text =\n typeof message.content === \"string\"\n ? message.content\n : message.content\n .filter((part) => part.type === \"text\")\n .map((part) => (part.type === \"text\" ? part.text : \"\"))\n .join(\" \");\n const collapsed = text.replace(/\\s+/g, \" \").trim();\n if (collapsed) return collapsed;\n } catch {\n // Half line at the read boundary or a corrupt line — keep looking.\n }\n }\n return null;\n } catch {\n return null;\n } finally {\n await handle?.close().catch(() => {});\n }\n}\n\nexport function shortSessionId(id: string): string {\n const dash = id.lastIndexOf(\"-\");\n return dash === -1 ? id : id.slice(dash + 1);\n}\n\nexport async function resolveSessionId(query: string): Promise<string | null> {\n const metas = await SessionStore.list();\n const exact = metas.find((meta) => meta.id === query);\n if (exact) return exact.id;\n const matches = metas.filter(\n (meta) => shortSessionId(meta.id) === query || meta.id.startsWith(query),\n );\n return matches.length === 1 ? (matches[0]?.id ?? null) : null;\n}\n\nexport function relativeTime(timestamp: number): string {\n const diff = Date.now() - timestamp;\n const minutes = Math.floor(diff / 60_000);\n if (minutes < 1) return \"just now\";\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.floor(hours / 24);\n if (days < 30) return `${days}d ago`;\n const months = Math.floor(days / 30);\n if (months < 12) return `${months}mo ago`;\n return `${Math.floor(months / 12)}y ago`;\n}\n\nexport function formatSessionEntries(\n entries: SessionListEntry[],\n options: { showCwd?: boolean } = {},\n): string {\n return entries\n .map(({ meta, messageCount }) => {\n const title = meta.title || \"(untitled)\";\n const base =\n `${shortSessionId(meta.id)} ${title} ` +\n `${messageCount} messages updated ${relativeTime(meta.updatedAt)}`;\n return options.showCwd ? `${base} [${meta.cwd}]` : base;\n })\n .join(\"\\n\");\n}\n","// Base system prompt shared by main.tsx (initial loop) and the REPL's\n// switchModel (rebuilt loop): syncSystemMessage re-derives the prompt from\n// opts.system every turn, so a rebuilt loop without it would silently drop\n// the core instructions whenever AGENTS.md/git/skills context exists.\nexport const SYSTEM_PROMPT = `You are Star CLI, an AI coding agent running in the user's terminal.\nYou help with software engineering tasks: reading, writing and editing code, running shell commands, and managing todos.\nBe concise and direct. Use tools when they help accomplish the task.\nFor any task with two or more steps, start by creating a todo list with todo_write and keep it updated as you progress; only mark an item completed after you have verified its result.\nThe working directory is the user's project root; never touch files outside it without explicit instruction.\nFor conversion, batch-processing, or other scriptable tasks, write a script file into the working directory and run it instead of pasting long inline code into the shell; once the script's output is verified, delete the script unless the user asked to keep it.\nWhen a tool call or command fails, read the error output, work out the cause, and try again with a corrected or alternative approach — never repeat an identical failing call without changing something.\nWhen you add a feature or change behavior, write the unit tests that cover it in the same change, matching the project's test framework, layout, and naming; if the project has no test setup at all, say so instead of silently skipping tests.\nNever consider the task finished until you have verified the result yourself: run the project's full verification — the whole test suite, not only the tests you touched, plus the type check, build, or lint the project defines — and if verification fails or reveals gaps, keep fixing until everything passes; a change that breaks other tests is not done.\nBefore the final verification, sweep your own changes for leftovers: debug prints, commented-out code, half-finished edits.\nDo not end your turn while the task is still incomplete; keep going until it is done or you are genuinely blocked, and if you are blocked, state exactly what is missing.\nWhen you report completion, state the evidence: which checks you ran and that they passed — never claim success you did not observe.\nNever end a reply by announcing what you will do next — either do it now with tool calls, or do not mention it. Narrating future actions is not progress.`;\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { sessionsDir } from \"../config/paths\";\nimport { pruneTreeReposExcept, removeTreeRepo } from \"../snapshot/git-tree\";\nimport { SessionStore } from \"./store\";\n\n// Deletes stored sessions and returns how many were removed. With a cwd only\n// sessions recorded for that directory go (directories with an unreadable\n// meta.json cannot be matched and stay); without it every session directory\n// under sessionsDir is removed. excludeId keeps the caller's live session on\n// disk (the REPL's /clear-sessions must not pull its own store away).\n//\n// Snapshot cleanup rides along: per-file checkpoints live inside the session\n// dir and go with it, while the per-project git-tree repos outlive sessions\n// on purpose (/undo across restarts). Once a project's last session is gone\n// its tree repo is unreachable, so it is removed here too — repos whose\n// project still has a surviving session (e.g. the excluded live one) stay.\n// Deletes a single stored session (the /resume picker's Ctrl+X). Snapshot\n// cleanup matches clearSessions: once the session's project has no sessions\n// left, its git-tree repo is unreachable and removed too.\nexport async function deleteSession(id: string): Promise<void> {\n const meta = (await SessionStore.list()).find((m) => m.id === id);\n await fs.rm(path.join(sessionsDir(), id), { recursive: true, force: true });\n if (meta && (await SessionStore.list(meta.cwd)).length === 0) {\n await removeTreeRepo(meta.cwd);\n }\n}\n\nexport async function clearSessions(cwd?: string, excludeId?: string): Promise<number> {\n if (cwd !== undefined) {\n const metas = await SessionStore.list(cwd);\n let removed = 0;\n for (const meta of metas) {\n if (meta.id === excludeId) continue;\n await fs.rm(path.join(sessionsDir(), meta.id), { recursive: true, force: true });\n removed += 1;\n }\n if ((await SessionStore.list(cwd)).length === 0) {\n await removeTreeRepo(cwd);\n }\n return removed;\n }\n let entries: string[];\n try {\n entries = await fs.readdir(sessionsDir());\n } catch {\n return 0;\n }\n let removed = 0;\n for (const entry of entries) {\n if (entry === excludeId) continue;\n await fs.rm(path.join(sessionsDir(), entry), { recursive: true, force: true });\n removed += 1;\n }\n const survivors = await SessionStore.list();\n await pruneTreeReposExcept(survivors.map((meta) => meta.cwd));\n return removed;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nfunction readPackageVersion(): string {\n try {\n const pkgPath = path.join(path.dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\");\n const pkg: unknown = JSON.parse(fs.readFileSync(pkgPath, \"utf8\"));\n if (typeof pkg === \"object\" && pkg !== null) {\n const version = (pkg as { version?: unknown }).version;\n if (typeof version === \"string\") return version;\n }\n } catch {\n // fall through to placeholder\n }\n return \"0.0.0\";\n}\n\nexport const VERSION = readPackageVersion();\n"],"mappings":"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","names":["lines","st","buf","fs","path","path","path","path","fs","fs","path","fs","path","fs","path","fs","path","removed","fs","path"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tools/fs/edit.ts","../src/tools/fs/glob.ts","../src/tools/fs/grep.ts","../src/tools/fs/outline.ts","../src/tools/fs/read.ts","../src/tools/fs/read-image.ts","../src/tools/fs/write.ts","../src/tools/screenshot.ts","../src/core/screenshot.ts","../src/tools/tasks.ts","../src/tasks/format.ts","../src/tools/web/search.ts","../src/llm/debug.ts","../src/tools/registry.ts","../src/tools/index.ts"],"sourcesContent":["import { readFile, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { Tool } from \"../types\";\nimport {\n MAX_SNAPSHOT_CONTENT_BYTES,\n currentTurnMessageIndex,\n currentTurnSeq,\n nextSnapshotId,\n pushSnapshot,\n} from \"./snapshots\";\nimport { isSensitivePath, realpathForCheck } from \"./util\";\n\n// Same heuristic as read_file: a NUL in the first 8KB marks a binary file.\n// edit_file writes back as UTF-8, so an ASCII old_string that happens to\n// match inside a binary file would corrupt it irreversibly (U+FFFD\n// replacement on undecodable bytes), and snapshots cannot restore it.\nconst BINARY_PROBE_BYTES = 8192;\n\nfunction countOccurrences(haystack: string, needle: string): number {\n let count = 0;\n let idx = haystack.indexOf(needle);\n while (idx !== -1) {\n count += 1;\n idx = haystack.indexOf(needle, idx + needle.length);\n }\n return count;\n}\n\nfunction normalizeEol(text: string): string {\n return text.replace(/\\r\\n/g, \"\\n\");\n}\n\nconst schema = z.object({\n path: z.string().describe(\"File path, absolute or relative to the working directory\"),\n old_string: z.string().min(1).describe(\"Exact text to replace\"),\n new_string: z.string().describe(\"Replacement text\"),\n replace_all: z\n .boolean()\n .optional()\n .describe(\"Replace every occurrence instead of requiring a unique match\"),\n});\n\nexport const editFileTool: Tool<typeof schema> = {\n name: \"edit_file\",\n description:\n \"Replace an exact string in a file. Fails if old_string is not found or matches multiple locations unless replace_all is set. Refuses binary files and files over 5MB.\",\n permission: \"write\",\n parameters: schema,\n async execute(args, ctx) {\n const filePath = path.resolve(ctx.cwd, args.path);\n // Same symlink defense as read_file/write_file: refuse when the resolved\n // target is a sensitive file, in-tool so yolo mode and hooks can't\n // bypass the gate's raw-path name check.\n const resolvedPath = await realpathForCheck(filePath);\n if (isSensitivePath(filePath) || (resolvedPath !== null && isSensitivePath(resolvedPath))) {\n return { content: `Refused to edit sensitive file: ${args.path}`, isError: true };\n }\n let content: string;\n let readMtimeMs: number;\n try {\n const st = await stat(filePath);\n // Past the snapshot content cap /undo keeps only metadata, so an edit\n // would be unrecoverable — refuse instead of writing blind.\n if (st.size > MAX_SNAPSHOT_CONTENT_BYTES) {\n return {\n content: `Refused to edit ${args.path}: file is ${st.size} bytes, over the 5MB limit (edits past it could not be restored by /undo)`,\n isError: true,\n };\n }\n readMtimeMs = st.mtimeMs;\n const buf = await readFile(filePath);\n if (buf.subarray(0, BINARY_PROBE_BYTES).includes(0)) {\n return { content: `Refused to edit binary file: ${args.path}`, isError: true };\n }\n content = buf.toString(\"utf8\");\n } catch (err) {\n return { content: `Failed to read ${args.path}: ${(err as Error).message}`, isError: true };\n }\n // Dual-path matching: exact first. When that finds nothing, retry in an\n // LF-normalized space — read_file strips \\r for display, so on a CRLF\n // file the model can only phrase a multi-line old_string with \\n, which\n // never matches the raw bytes. Uniqueness/replace_all counts are judged\n // in the normalized space; after replacing there, the text is converted\n // back to the original file's dominant line ending before writing.\n let working = content;\n let oldString = args.old_string;\n let newString = args.new_string;\n let restoreEol: ((text: string) => string) | null = null;\n let count = countOccurrences(working, oldString);\n if (count === 0) {\n const normalizedContent = normalizeEol(content);\n const normalizedOld = normalizeEol(oldString);\n const normalizedCount = countOccurrences(normalizedContent, normalizedOld);\n if (normalizedCount > 0) {\n const crlfCount = countOccurrences(content, \"\\r\\n\");\n const loneLfCount = countOccurrences(content.replace(/\\r\\n/g, \"\"), \"\\n\");\n restoreEol =\n crlfCount > 0 && crlfCount >= loneLfCount ? (text) => text.replace(/\\n/g, \"\\r\\n\") : null;\n working = normalizedContent;\n oldString = normalizedOld;\n newString = normalizeEol(newString);\n count = normalizedCount;\n }\n }\n if (count === 0) {\n return { content: `old_string not found in ${args.path}`, isError: true };\n }\n if (count > 1 && !args.replace_all) {\n return {\n content: `old_string matches ${count} locations in ${args.path}; provide more surrounding context or set replace_all`,\n isError: true,\n };\n }\n let updated = args.replace_all\n ? working.split(oldString).join(newString)\n : working.replace(oldString, () => newString);\n if (restoreEol) {\n updated = restoreEol(updated);\n }\n try {\n // Guard against a silent overwrite when the file changed on disk\n // between our read and our write.\n const now = await stat(filePath).catch(() => null);\n if (!now || now.mtimeMs !== readMtimeMs) {\n return {\n content: `Failed to edit ${args.path}: file changed since it was read; re-read and retry`,\n isError: true,\n };\n }\n await writeFile(filePath, updated, \"utf8\");\n } catch (err) {\n return { content: `Failed to write ${args.path}: ${(err as Error).message}`, isError: true };\n }\n const contentTooLarge = Buffer.byteLength(content, \"utf8\") > MAX_SNAPSHOT_CONTENT_BYTES;\n await pushSnapshot({\n id: nextSnapshotId(),\n path: filePath,\n existed: true,\n content: contentTooLarge ? null : content,\n contentTooLarge: contentTooLarge || undefined,\n toolName: \"edit_file\",\n timestamp: Date.now(),\n turn: ctx.snapshotContext?.turn ?? currentTurnSeq(),\n messageIndex: ctx.snapshotContext?.messageIndex ?? currentTurnMessageIndex(),\n owner: ctx.snapshotContext?.owner ?? \"root\",\n });\n return { content: `Edited ${args.path}: ${count} replacement${count > 1 ? \"s\" : \"\"}` };\n },\n};\n","import path from \"node:path\";\nimport { z } from \"zod\";\nimport type { Tool } from \"../types\";\nimport { createIgnorePredicate, matchesGlob, walkFiles } from \"./util\";\n\nconst MAX_RESULTS = 100;\n\nconst GLOB_MAGIC = /[*?[{]/;\n\n// Leading directory segments without glob magic (everything before the final\n// segment, which may name a file) let src/**/*.ts walk <root>/src directly\n// instead of descending the whole tree. Matched paths are re-prefixed before\n// matching and display so output stays relative to the requested root.\nfunction literalDirPrefix(pattern: string): string[] {\n const segments = pattern.replace(/\\\\/g, \"/\").split(\"/\").slice(0, -1);\n const out: string[] = [];\n for (const segment of segments) {\n if (segment === \"\" || GLOB_MAGIC.test(segment)) {\n break;\n }\n out.push(segment);\n }\n return out;\n}\n\nconst schema = z.object({\n pattern: z\n .string()\n .describe(\n \"Glob pattern, e.g. 'src/**/*.ts'. Supports **, *, ?, {a,b} braces and [abc] character classes. A bare pattern like '*.ts' matches basenames recursively.\",\n ),\n path: z.string().optional().describe(\"Directory to search, defaults to the working directory\"),\n});\n\n// A \"..\" segment would walk above the requested root (the literal-prefix\n// optimization resolves it against the search root), escaping the cwd\n// boundary the permission gate enforces on the path argument.\nfunction hasParentSegment(pattern: string): boolean {\n return pattern\n .replace(/\\\\/g, \"/\")\n .split(\"/\")\n .some((segment) => segment === \"..\");\n}\n\nexport const globTool: Tool<typeof schema> = {\n name: \"glob\",\n description:\n \"Find files by glob pattern. Skips node_modules, .git and dist. Follows symlinks that stay inside the working directory. Returns paths sorted by modification time, newest first, up to 100 results.\",\n permission: \"read\",\n parameters: schema,\n async execute(args, ctx) {\n if (hasParentSegment(args.pattern)) {\n return {\n content: `Refused glob pattern with '..' segment: ${args.pattern}`,\n isError: true,\n };\n }\n const root = path.resolve(ctx.cwd, args.path ?? \".\");\n const prefixSegments = literalDirPrefix(args.pattern);\n const walkRoot = prefixSegments.length > 0 ? path.join(root, ...prefixSegments) : root;\n const prefix = prefixSegments.length > 0 ? `${prefixSegments.join(\"/\")}/` : \"\";\n const { files, aborted } = await walkFiles(walkRoot, undefined, {\n ignore: createIgnorePredicate(ctx.cwd),\n signal: ctx.abortSignal,\n symlinkBoundary: ctx.cwd,\n nestedIgnore: true,\n });\n const matched = files\n .filter((f) => matchesGlob(args.pattern, `${prefix}${f.rel}`))\n .sort((a, b) => b.mtimeMs - a.mtimeMs)\n .slice(0, MAX_RESULTS);\n if (matched.length === 0) {\n return {\n content: aborted\n ? `Search interrupted before any files matched pattern: ${args.pattern}`\n : `No files matched pattern: ${args.pattern}`,\n };\n }\n const lines = matched.map((f) => `${prefix}${f.rel}`);\n if (aborted) {\n lines.push(\"... (interrupted: partial results)\");\n }\n return { content: lines.join(\"\\n\") };\n },\n};\n","import { readFile, realpath, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { Tool } from \"../types\";\nimport {\n WALK_CONCURRENCY,\n type WalkedFile,\n createIgnorePredicate,\n isSensitivePath,\n matchesGlob,\n walkFiles,\n} from \"./util\";\n\nconst MAX_MATCHES = 250;\nconst MAX_LINE_CHARS = 500;\nconst MAX_PATTERN_CHARS = 200;\nconst MAX_FILE_BYTES = 5 * 1024 * 1024;\n\n// Very long patterns are usually pasted blobs, and a quantified group is the\n// classic catastrophic-backtracking shape — reject both before they hang the\n// process on a large tree.\nfunction isTooComplexPattern(pattern: string): boolean {\n return (\n pattern.length > MAX_PATTERN_CHARS || /\\)[+*]/.test(pattern) || /\\)\\{\\d+(,\\d*)?\\}/.test(pattern)\n );\n}\n\nconst schema = z.object({\n pattern: z.string().describe(\"Regular expression to search for\"),\n path: z\n .string()\n .optional()\n .describe(\"File or directory to search, defaults to the working directory\"),\n glob: z\n .string()\n .optional()\n .describe(\"Glob pattern to filter which files are searched, e.g. '*.ts'\"),\n ignoreCase: z.boolean().optional().describe(\"Case-insensitive matching\"),\n});\n\nexport const grepTool: Tool<typeof schema> = {\n name: \"grep\",\n description:\n \"Search file contents with a regular expression. Outputs 'file:line:content', up to 250 matches. Skips binary files, files over 5MB, sensitive files, node_modules and .git. Follows symlinks that stay inside the working directory.\",\n permission: \"read\",\n parameters: schema,\n async execute(args, ctx) {\n if (isTooComplexPattern(args.pattern)) {\n return {\n content: `pattern too complex: keep it under ${MAX_PATTERN_CHARS} characters and avoid quantified groups like (a+)+`,\n isError: true,\n };\n }\n let re: RegExp;\n try {\n re = new RegExp(args.pattern, args.ignoreCase ? \"i\" : \"\");\n } catch (err) {\n return { content: `Invalid regular expression: ${(err as Error).message}`, isError: true };\n }\n const root = path.resolve(ctx.cwd, args.path ?? \".\");\n let files: WalkedFile[];\n let interrupted = false;\n try {\n const st = await stat(root);\n if (st.isFile()) {\n // Symlink targets are checked too: a link named notes.txt can point\n // at a sensitive file whose resolved basename is on the blocklist.\n const resolved = await realpath(root).catch(() => null);\n if (isSensitivePath(root) || (resolved !== null && isSensitivePath(resolved))) {\n return {\n content: `Refused to grep sensitive file: ${args.path ?? \".\"}`,\n isError: true,\n };\n }\n files = [{ abs: root, rel: path.basename(root), mtimeMs: st.mtimeMs }];\n } else {\n const walked = await walkFiles(root, undefined, {\n ignore: createIgnorePredicate(ctx.cwd),\n withMtime: false,\n signal: ctx.abortSignal,\n symlinkBoundary: ctx.cwd,\n nestedIgnore: true,\n });\n interrupted = walked.aborted;\n // A link named notes.txt can resolve to a sensitive target inside the\n // cwd; check the resolved path as well as the link path.\n files = walked.files.filter(\n (f) =>\n !isSensitivePath(f.abs) && (f.resolved === undefined || !isSensitivePath(f.resolved)),\n );\n }\n } catch {\n return { content: `Path not found: ${args.path ?? \".\"}`, isError: true };\n }\n if (args.glob) {\n const glob = args.glob;\n files = files.filter((f) => matchesGlob(glob, f.rel));\n }\n // Files are scanned in concurrent chunks; matches are appended in file\n // order so output stays deterministic and the 250-match cut is stable.\n const scanFile = async (file: WalkedFile): Promise<string[] | null> => {\n const st = await stat(file.abs).catch(() => null);\n if (!st) {\n return null;\n }\n if (st.size > MAX_FILE_BYTES) {\n skippedLarge += 1;\n return null;\n }\n let buf: Buffer;\n try {\n buf = await readFile(file.abs);\n } catch {\n return null;\n }\n if (buf.includes(0)) {\n return null;\n }\n const hits: string[] = [];\n const lines = buf.toString(\"utf8\").split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n if (re.test(line)) {\n const shown = line.length > MAX_LINE_CHARS ? `${line.slice(0, MAX_LINE_CHARS)}…` : line;\n hits.push(`${file.rel}:${i + 1}:${shown}`);\n }\n }\n return hits;\n };\n const out: string[] = [];\n let truncated = false;\n let skippedLarge = 0;\n outer: for (let i = 0; i < files.length; i += WALK_CONCURRENCY) {\n if (ctx.abortSignal?.aborted) {\n interrupted = true;\n break;\n }\n const chunk = await Promise.all(\n files.slice(i, i + WALK_CONCURRENCY).map((file) => scanFile(file)),\n );\n for (const hits of chunk) {\n if (!hits) {\n continue;\n }\n for (const hit of hits) {\n out.push(hit);\n if (out.length >= MAX_MATCHES) {\n truncated = true;\n break outer;\n }\n }\n }\n }\n const skippedNote =\n skippedLarge > 0 ? `(skipped ${skippedLarge} file(s) larger than 5MB)` : null;\n if (out.length === 0) {\n return {\n content: `No matches for pattern: ${args.pattern}${skippedNote ? ` ${skippedNote}` : \"\"}${interrupted ? \" (search interrupted)\" : \"\"}`,\n };\n }\n if (truncated) {\n out.push(`... (truncated: more than ${MAX_MATCHES} matches)`);\n } else if (interrupted) {\n out.push(\"... (interrupted: partial results)\");\n }\n if (skippedNote) {\n out.push(`... ${skippedNote}`);\n }\n return { content: out.join(\"\\n\") };\n },\n};\n","import { readFile, realpath, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { Tool } from \"../types\";\nimport {\n WALK_CONCURRENCY,\n type WalkedFile,\n createIgnorePredicate,\n isSensitivePath,\n walkFiles,\n} from \"./util\";\n\nconst MAX_DIR_FILES = 60;\nconst MAX_FILE_BYTES = 2 * 1024 * 1024;\nconst MAX_SYMBOLS_PER_FILE = 150;\nconst MAX_LINE_CHARS = 200;\nconst MAX_OUT_CHARS = 30 * 1024;\n// Nesting is shown through original indentation, capped so deep nesting\n// cannot push the signature out of view.\nconst MAX_INDENT_CHARS = 8;\n\n// Declaration-spotting regexes per language family. This is deliberately a\n// lightweight skeleton extractor, not a parser: it misses some declarations\n// (multi-line signatures, macros) and that is fine — the outline exists so\n// the model can navigate to line ranges cheaply; read_file still owns exact\n// content. Patterns are anchored to declaration shapes (leading modifiers,\n// trailing \"{\"/\";\"/end-of-line) so ordinary calls and control flow don't\n// match, and are tested against the raw line because member rules key on\n// indentation (methods are indented, top-level declarations are not).\nconst KEYWORD_EXCLUSION =\n \"(?!if\\\\b|for\\\\b|while\\\\b|switch\\\\b|catch\\\\b|return\\\\b|else\\\\b|do\\\\b|new\\\\b|throw\\\\b)\";\n\nconst TS_MEMBER_MODIFIERS =\n \"(?:public|private|protected|static|async|readonly|get|set|override|abstract)\";\n\nconst TS_LIKE = [\n /^(?:export\\s+)?(?:default\\s+)?(?:async\\s+)?function\\*?\\s+[\\w$]+/,\n /^(?:export\\s+)?(?:abstract\\s+)?class\\s+[\\w$]+/,\n /^(?:export\\s+)?interface\\s+[\\w$]+/,\n /^(?:export\\s+)?type\\s+[\\w$]+\\s*=/,\n /^(?:export\\s+)?(?:const\\s+)?enum\\s+[\\w$]+/,\n // const handler = (a, b) => / const handler = async (a) => — top level\n // only; locals inside functions are navigation noise.\n /^(?:export\\s+)?(?:const|let|var)\\s+[\\w$]+\\s*=\\s*(?:async\\s*)?(?:\\([^)]*\\)|[\\w$]+)\\s*=>/,\n // Indented class/object members with a body: name<T>(args): ReturnType {\n // — control flow excluded by the keyword lookahead, dotted calls\n // (this.x()) fail the anchored name-then-paren shape.\n new RegExp(\n `^\\\\s+(?:${TS_MEMBER_MODIFIERS}\\\\s+)*${KEYWORD_EXCLUSION}[\\\\w$]+(?:<[^>]*>)?\\\\s*\\\\([^)]*\\\\)\\\\s*(?::\\\\s*[^{}=;]+?)?\\\\s*(?:\\\\{\\\\s*)?\\\\}?\\\\s*$`,\n ),\n // Bodyless signatures (interface members, overloads): only when the\n // parens carry type annotations or an explicit return type follows —\n // otherwise indented calls like clearTimeout(timer); or finalize();\n // would leak into the outline.\n new RegExp(\n `^\\\\s+(?:${TS_MEMBER_MODIFIERS}\\\\s+)*${KEYWORD_EXCLUSION}[\\\\w$]+(?:<[^>]*>)?\\\\s*(?:\\\\([^)]*:[^)]*\\\\)\\\\s*(?::\\\\s*[^{}=;]+?)?|\\\\([^)]*\\\\)\\\\s*:\\\\s*[^{}=;]+?)\\\\s*;\\\\s*$`,\n ),\n];\n\nconst LANGUAGE_PATTERNS: Record<string, RegExp[]> = {\n ts: TS_LIKE,\n python: [/^\\s*(?:async\\s+)?def\\s+\\w+\\s*\\(/, /^\\s*class\\s+\\w+/],\n go: [/^func\\s+(?:\\([^)]*\\)\\s*)?\\w+\\s*\\(/, /^type\\s+\\w+\\s+(?:struct|interface)\\b/],\n rust: [\n /^\\s*(?:pub(?:\\([^)]*\\))?\\s+)?(?:async\\s+)?fn\\s+\\w+/,\n /^\\s*(?:pub\\s+)?(?:struct|enum|trait|union)\\s+\\w+/,\n ],\n jvm: [\n /^\\s*(?:(?:public|private|protected|internal|static|final|abstract|sealed|open|suspend|inline|override|async|partial|virtual|extern)\\s+)*(?:class|interface|enum|struct|record|object)\\s+\\w+/,\n /^\\s*(?:(?:public|private|protected|internal|open|suspend|inline|override)\\s+)*fun\\s+\\w+\\s*\\(/,\n new RegExp(\n `^\\\\s+(?:(?:public|private|protected|internal|static|final|abstract|sealed|open|suspend|inline|override|async|partial|virtual)\\\\s+)*[\\\\w<>[\\\\],.?]+\\\\s+${KEYWORD_EXCLUSION}\\\\w+\\\\s*\\\\([^;{}]*\\\\)\\\\s*(?:\\\\{|;|=>|$)`,\n ),\n ],\n cpp: [\n /^\\s*(?:class|struct|enum|union|namespace)\\s+\\w+/,\n new RegExp(\n `^\\\\s*(?:(?:static|inline|virtual|constexpr|extern|friend|explicit)\\\\s+)*[\\\\w:<>,~*&\\\\s]+?\\\\s+${KEYWORD_EXCLUSION}[\\\\w:~]+\\\\s*\\\\([^;]*\\\\)\\\\s*(?:const\\\\s*)?(?:noexcept\\\\s*)?(?:\\\\{|;|$)`,\n ),\n ],\n ruby: [/^\\s*def\\s+[\\w.=!?]+/, /^\\s*(?:class|module)\\s+[\\w:]+/],\n php: [\n /^\\s*(?:(?:public|private|protected|static|abstract|final)\\s+)*function\\s+\\w+\\s*\\(/,\n /^\\s*(?:(?:abstract|final)\\s+)?(?:class|interface|trait|enum)\\s+\\w+/,\n ],\n shell: [/^\\s*(?:function\\s+)?[\\w.-]+\\s*\\(\\s*\\)\\s*(?:\\{|$)/],\n swift: [\n /^\\s*(?:(?:public|private|internal|open|fileprivate|static|class|override|mutating|final)\\s+)*func\\s+\\w+\\s*\\(/,\n /^\\s*(?:(?:public|private|internal|open|final)\\s+)*(?:class|struct|enum|protocol|extension)\\s+\\w+/,\n ],\n scala: [\n /^\\s*(?:(?:private|protected|override|final|abstract|implicit)\\s+)*def\\s+\\w+\\s*[(\\[]/,\n /^\\s*(?:(?:abstract|final|sealed)\\s+)*(?:class|trait|object)\\s+\\w+/,\n ],\n};\n\nconst EXT_TO_LANGUAGE: Record<string, keyof typeof LANGUAGE_PATTERNS> = {\n ts: \"ts\",\n tsx: \"ts\",\n mts: \"ts\",\n cts: \"ts\",\n js: \"ts\",\n jsx: \"ts\",\n mjs: \"ts\",\n cjs: \"ts\",\n py: \"python\",\n pyi: \"python\",\n go: \"go\",\n rs: \"rust\",\n java: \"jvm\",\n kt: \"jvm\",\n kts: \"jvm\",\n cs: \"jvm\",\n c: \"cpp\",\n h: \"cpp\",\n cc: \"cpp\",\n cpp: \"cpp\",\n cxx: \"cpp\",\n hpp: \"cpp\",\n hh: \"cpp\",\n rb: \"ruby\",\n php: \"php\",\n sh: \"shell\",\n bash: \"shell\",\n zsh: \"shell\",\n swift: \"swift\",\n scala: \"scala\",\n sc: \"scala\",\n};\n\nfunction languageOf(filePath: string): RegExp[] | undefined {\n const name = path.basename(filePath);\n // Minified and machine-generated bundles are declaration soup; outlining\n // a bundled dependency is never useful navigation.\n if (/\\.(min|bundle|generated)\\.[^.]+$/.test(name)) return undefined;\n const ext = name.split(\".\").pop()?.toLowerCase() ?? \"\";\n const lang = EXT_TO_LANGUAGE[ext];\n return lang === undefined ? undefined : LANGUAGE_PATTERNS[lang];\n}\n\ninterface SymbolLine {\n line: number;\n indent: string;\n text: string;\n}\n\nfunction extractSymbols(text: string, patterns: RegExp[]): SymbolLine[] {\n const out: SymbolLine[] = [];\n const lines = text.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const raw = (lines[i] ?? \"\").replace(/\\r$/, \"\");\n const trimmed = raw.trim();\n if (trimmed === \"\") continue;\n if (!patterns.some((re) => re.test(raw))) continue;\n const indent = raw.slice(0, raw.length - raw.trimStart().length).slice(0, MAX_INDENT_CHARS);\n const shown =\n trimmed.length > MAX_LINE_CHARS ? `${trimmed.slice(0, MAX_LINE_CHARS)}…` : trimmed;\n out.push({ line: i + 1, indent, text: shown });\n }\n return out;\n}\n\nasync function outlineFile(\n abs: string,\n): Promise<{ symbols: SymbolLine[]; total: number } | { binary: true } | { unreadable: true }> {\n const st = await stat(abs).catch(() => null);\n if (!st || st.size > MAX_FILE_BYTES) return { unreadable: true };\n const buf = await readFile(abs).catch(() => null);\n if (!buf) return { unreadable: true };\n if (buf.includes(0)) return { binary: true };\n const patterns = languageOf(abs);\n if (!patterns) return { unreadable: true };\n const all = extractSymbols(buf.toString(\"utf8\"), patterns);\n return { symbols: all.slice(0, MAX_SYMBOLS_PER_FILE), total: all.length };\n}\n\nfunction formatSymbols(symbols: SymbolLine[], total: number): string[] {\n const out = symbols.map((s) => `${s.line}\\t${s.indent}${s.text}`);\n if (total > symbols.length) {\n out.push(`... (${total - symbols.length} more declarations)`);\n }\n return out;\n}\n\nconst schema = z.object({\n path: z\n .string()\n .optional()\n .describe(\"Source file or directory to outline (default: the working directory)\"),\n maxFiles: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(`Directory mode: maximum files to include (default ${MAX_DIR_FILES})`),\n});\n\nexport const codeOutlineTool: Tool<typeof schema> = {\n name: \"code_outline\",\n description:\n \"List the declaration skeleton of a source file or directory (functions, classes, methods, types) with line numbers, without reading the bodies. Cheaper than read_file for navigating unfamiliar code: outline first, then read_file the exact line ranges you need. Supports TS/JS, Python, Go, Rust, Java/Kotlin/C#, C/C++, Ruby, PHP, Shell, Swift, Scala.\",\n permission: \"read\",\n parameters: schema,\n async execute(args, ctx) {\n const root = path.resolve(ctx.cwd, args.path ?? \".\");\n const st = await stat(root).catch(() => null);\n if (!st) {\n return { content: `Path not found: ${args.path ?? \".\"}`, isError: true };\n }\n\n if (st.isFile()) {\n // Same refusal as read_file: the raw name and the symlink target both\n // count, so a planted link cannot launder a sensitive basename.\n const resolved = await realpath(root).catch(() => null);\n if (isSensitivePath(root) || (resolved !== null && isSensitivePath(resolved))) {\n return { content: `Refused to outline sensitive file: ${args.path ?? \".\"}`, isError: true };\n }\n if (languageOf(root) === undefined) {\n return {\n content: `No supported source language for: ${args.path ?? \".\"} (supported: TS/JS, Python, Go, Rust, Java/Kotlin/C#, C/C++, Ruby, PHP, Shell, Swift, Scala)`,\n };\n }\n const result = await outlineFile(root);\n if (\"binary\" in result) {\n return { content: `Cannot outline binary file: ${args.path ?? \".\"}`, isError: true };\n }\n if (\"unreadable\" in result) {\n return {\n content: `Cannot outline ${args.path ?? \".\"}: unreadable or larger than 2MB`,\n isError: true,\n };\n }\n if (result.symbols.length === 0) {\n return { content: `(no recognizable declarations in ${args.path ?? \".\"})` };\n }\n return { content: formatSymbols(result.symbols, result.total).join(\"\\n\") };\n }\n\n const walked = await walkFiles(root, undefined, {\n ignore: createIgnorePredicate(ctx.cwd),\n withMtime: false,\n signal: ctx.abortSignal,\n symlinkBoundary: ctx.cwd,\n nestedIgnore: true,\n });\n const candidates = walked.files.filter(\n (f) =>\n languageOf(f.abs) !== undefined &&\n !isSensitivePath(f.abs) &&\n (f.resolved === undefined || !isSensitivePath(f.resolved)),\n );\n const maxFiles = args.maxFiles ?? MAX_DIR_FILES;\n\n const scan = async (\n file: WalkedFile,\n ): Promise<{ rel: string; lines: string[]; chars: number } | null> => {\n const result = await outlineFile(file.abs);\n if (\"symbols\" in result && result.symbols.length > 0) {\n const lines = formatSymbols(result.symbols, result.total);\n const chars = lines.reduce((n, l) => n + l.length + 1, file.rel.length + 2);\n return { rel: file.rel, lines, chars };\n }\n return null;\n };\n\n const out: string[] = [];\n let size = 0;\n let included = 0;\n let hitLimit = false;\n for (let i = 0; i < candidates.length && included < maxFiles; i += WALK_CONCURRENCY) {\n if (ctx.abortSignal?.aborted) break;\n const chunk = await Promise.all(\n candidates.slice(i, i + WALK_CONCURRENCY).map((file) => scan(file)),\n );\n for (const block of chunk) {\n if (!block) continue;\n if (size + block.chars > MAX_OUT_CHARS || included >= maxFiles) {\n hitLimit = true;\n break;\n }\n if (out.length > 0) out.push(\"\");\n out.push(`${block.rel}:`);\n out.push(...block.lines);\n size += block.chars;\n included += 1;\n }\n if (hitLimit) break;\n }\n if (included === 0) {\n return {\n content: `No recognizable declarations under ${args.path ?? \".\"} (${candidates.length} source file(s) scanned)`,\n };\n }\n if (hitLimit) {\n out.push(\"... (truncated: output limit reached, more files not outlined)\");\n } else if (walked.aborted || ctx.abortSignal?.aborted) {\n out.push(\"... (interrupted: partial results)\");\n }\n return { content: out.join(\"\\n\") };\n },\n};\n","import { open, realpath, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { Tool } from \"../types\";\nimport { isSensitivePath } from \"./util\";\n\nconst DEFAULT_LIMIT = 2000;\nconst MAX_CHARS = 100 * 1024;\n// Output is capped at 100KB anyway, so reading past 1MB can never be shown.\nconst MAX_READ_BYTES = 1024 * 1024;\nconst BINARY_PROBE_BYTES = 8192;\n\nfunction decodeUtf16be(buf: Buffer): string {\n const len = buf.length - (buf.length % 2);\n const swapped = Buffer.allocUnsafe(len);\n for (let k = 0; k < len; k += 2) {\n swapped[k] = buf[k + 1] ?? 0;\n swapped[k + 1] = buf[k] ?? 0;\n }\n return swapped.toString(\"utf16le\");\n}\n\n// A UTF-16 BOM means the file is text (its NUL bytes are expected); without a\n// BOM, a NUL in the first 8KB marks a binary file.\nfunction decodeTextBuffer(buf: Buffer): { text: string } | { binary: true } {\n if (buf.length >= 2 && buf[0] === 0xff && buf[1] === 0xfe) {\n return { text: buf.subarray(2).toString(\"utf16le\") };\n }\n if (buf.length >= 2 && buf[0] === 0xfe && buf[1] === 0xff) {\n return { text: decodeUtf16be(buf.subarray(2)) };\n }\n if (buf.subarray(0, BINARY_PROBE_BYTES).includes(0)) {\n return { binary: true };\n }\n return { text: buf.toString(\"utf8\") };\n}\n\nconst schema = z.object({\n path: z.string().describe(\"File path, absolute or relative to the working directory\"),\n offset: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\"1-based line number to start reading from\"),\n limit: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\"Maximum number of lines to read (default 2000)\"),\n});\n\n// Per-tool-instance cache of what was already sent to the model, so a re-read\n// of an unchanged file (same mtime + size) whose requested line range was\n// already returned answers with a one-line note instead of re-billing the\n// full content (aider's read-file dedup). Keyed by realpath when resolvable.\ninterface ReadCacheEntry {\n mtimeMs: number;\n size: number;\n totalLines: number;\n start: number;\n end: number;\n}\nconst READ_CACHE_MAX_ENTRIES = 200;\n\nexport function createReadFileTool(): Tool<typeof schema> {\n const cache = new Map<string, ReadCacheEntry>();\n return {\n name: \"read_file\",\n description:\n \"Read a text file and return its contents with line numbers. Output is truncated to 2000 lines or 100KB by default. Re-reading an unchanged file range returns a short note instead of the content.\",\n permission: \"read\",\n parameters: schema,\n reset: () => cache.clear(),\n async execute(args, ctx) {\n const filePath = path.resolve(ctx.cwd, args.path);\n // Check both the given path and its symlink target: a repo can plant a\n // harmless-looking link (notes.txt -> ~/.ssh/id_rsa) whose resolved name\n // is on the sensitive list. Unresolvable paths keep the raw-path check.\n const resolvedPath = await realpath(filePath).catch(() => null);\n if (isSensitivePath(filePath) || (resolvedPath !== null && isSensitivePath(resolvedPath))) {\n return { content: `Refused to read sensitive file: ${args.path}`, isError: true };\n }\n const st = await stat(filePath).catch(() => null);\n if (!st) {\n return { content: `File not found: ${args.path}`, isError: true };\n }\n if (st.isDirectory()) {\n return { content: `Path is a directory, not a file: ${args.path}`, isError: true };\n }\n const start = args.offset ?? 1;\n const limit = args.limit ?? DEFAULT_LIMIT;\n const cacheKey = resolvedPath ?? filePath;\n const hit = cache.get(cacheKey);\n if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size) {\n const requestedEnd = Math.min(hit.totalLines, start - 1 + limit);\n if (start >= hit.start && requestedEnd <= hit.end && start <= hit.totalLines) {\n return {\n content: `[unchanged since last read: ${args.path} — lines ${start}-${requestedEnd} of ${hit.totalLines} are already in context and the file has not changed]`,\n };\n }\n }\n const bytesToRead = Math.min(st.size, MAX_READ_BYTES);\n const fileCapped = st.size > MAX_READ_BYTES;\n const handle = await open(filePath, \"r\").catch(() => null);\n if (!handle) {\n return { content: `Failed to read ${args.path}`, isError: true };\n }\n let buf: Buffer;\n try {\n const { bytesRead, buffer } = await handle.read(\n Buffer.alloc(bytesToRead),\n 0,\n bytesToRead,\n 0,\n );\n buf = buffer.subarray(0, bytesRead);\n } finally {\n await handle.close().catch(() => {});\n }\n const decoded = decodeTextBuffer(buf);\n if (\"binary\" in decoded) {\n return { content: `Cannot read binary file: ${args.path}`, isError: true };\n }\n const lines = decoded.text.split(\"\\n\");\n const totalDesc = fileCapped ? `at least ${lines.length}` : `${lines.length}`;\n if (start > lines.length) {\n return { content: `(offset ${start} beyond end of file; file has ${totalDesc} lines)` };\n }\n const end = Math.min(lines.length, start - 1 + limit);\n const out: string[] = [];\n let size = 0;\n let truncatedBySize = false;\n for (let i = start - 1; i < end; i++) {\n const line = (lines[i] ?? \"\").replace(/\\r$/, \"\");\n const numbered = `${i + 1}\\t${line}`;\n if (size + numbered.length > MAX_CHARS) {\n truncatedBySize = true;\n break;\n }\n out.push(numbered);\n size += numbered.length;\n }\n const lastShown = start - 1 + out.length;\n if (truncatedBySize) {\n out.push(\n `... (truncated: output exceeds 100KB, showing lines ${start}-${lastShown} of ${totalDesc})`,\n );\n } else if (end < lines.length || fileCapped) {\n out.push(`... (truncated: showing lines ${start}-${end} of ${totalDesc})`);\n }\n if (out.length > 0) {\n if (cache.size >= READ_CACHE_MAX_ENTRIES) cache.clear();\n const prev = hit?.mtimeMs === st.mtimeMs && hit.size === st.size ? hit : undefined;\n cache.set(cacheKey, {\n mtimeMs: st.mtimeMs,\n size: st.size,\n totalLines: lines.length,\n // Extend the remembered range when the new read overlaps or abuts\n // the previous one; disjoint ranges replace it.\n start: prev && start <= prev.end + 1 ? Math.min(prev.start, start) : start,\n end: prev && lastShown >= prev.start - 1 ? Math.max(prev.end, lastShown) : lastShown,\n });\n }\n return { content: out.join(\"\\n\") };\n },\n };\n}\n\n// Shared instance for direct consumers (tests); the tool registry creates a\n// fresh one per agent loop so a subagent's cache never claims content that\n// only the parent's context holds.\nexport const readFileTool = createReadFileTool();\n","import { readFile, realpath, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { probeImageDimensions } from \"../../core/image\";\nimport { downsampleImageIfNeeded } from \"../../core/image-resize\";\nimport type { ImageInput } from \"../../core/messages\";\nimport type { Tool } from \"../types\";\nimport { isSensitivePath } from \"./util\";\n\n// Same ceiling as @-mention image reads (src/cli/mentions.ts).\nconst MAX_IMAGE_BYTES = 5 * 1024 * 1024;\n\nconst IMAGE_MIME_TYPES: Record<string, string> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n};\n\nconst schema = z.object({\n path: z\n .string()\n .describe(\n \"Image file path (png/jpg/jpeg/gif/webp), absolute or relative to the working directory\",\n ),\n});\n\n// Lets the model pull an image into the conversation mid-session (a screenshot\n// the user mentioned, a generated asset, a UI mock). The image itself is not\n// in the text result — the loop attaches it to the history as a user message\n// with image parts (see ToolResult.images), so every protocol sees it the same\n// way as a pasted image.\nexport const readImageTool: Tool<typeof schema> = {\n name: \"read_image\",\n description:\n \"Read an image file (png, jpg, gif, webp) and show it to the model. Use this whenever the user references a screenshot, diagram, or picture file you need to see. Images larger than 2000px are downsampled automatically.\",\n permission: \"read\",\n parameters: schema,\n async execute(args, ctx) {\n if (ctx.visionEnabled === false) {\n return {\n content:\n \"The active model does not support image input (vision = false), so the image was not read. Work from text instead, or ask the user to describe the image.\",\n isError: true,\n };\n }\n const filePath = path.resolve(ctx.cwd, args.path);\n // Same symlink-aware sensitive check as read_file.\n const resolvedPath = await realpath(filePath).catch(() => null);\n if (isSensitivePath(filePath) || (resolvedPath !== null && isSensitivePath(resolvedPath))) {\n return { content: `Refused to read sensitive file: ${args.path}`, isError: true };\n }\n const mimeType = IMAGE_MIME_TYPES[path.extname(filePath).toLowerCase()];\n if (!mimeType) {\n return {\n content: `Not a supported image (png/jpg/jpeg/gif/webp): ${args.path}`,\n isError: true,\n };\n }\n const st = await stat(filePath).catch(() => null);\n if (!st || !st.isFile()) {\n return { content: `File not found: ${args.path}`, isError: true };\n }\n if (st.size > MAX_IMAGE_BYTES) {\n return {\n content: `Image too large (${Math.round(st.size / 1024)}KB > ${MAX_IMAGE_BYTES / 1024}KB): ${args.path}`,\n isError: true,\n };\n }\n const buf = await readFile(filePath).catch(() => null);\n if (!buf || buf.length === 0) {\n return { content: `Failed to read ${args.path}`, isError: true };\n }\n if (!probeImageDimensions(buf)) {\n return {\n content: `File is not a valid image (unrecognized header): ${args.path}`,\n isError: true,\n };\n }\n const downsampled = await downsampleImageIfNeeded({\n path: args.path,\n mimeType,\n data: buf.toString(\"base64\"),\n });\n if (downsampled.oversized && !downsampled.resized) {\n return {\n content: `Image exceeds 2000px and could not be downsampled on this platform: ${args.path}`,\n isError: true,\n };\n }\n const image: ImageInput = downsampled.image;\n const dims = probeImageDimensions(Buffer.from(image.data, \"base64\"));\n const sizeKB = Math.round(image.data.length / 1024);\n const desc = dims ? `${dims.width}x${dims.height}` : \"unknown dimensions\";\n const resizedNote = downsampled.resized ? \" (downsampled to fit 2000px)\" : \"\";\n return {\n content: `Image loaded: ${args.path} (${desc}, ~${sizeKB}KB)${resizedNote}. The image is attached below — look at it now.`,\n images: [image],\n };\n },\n};\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport type { Tool } from \"../types\";\nimport { MAX_SNAPSHOT_CONTENT_BYTES, captureSnapshot, pushSnapshot } from \"./snapshots\";\nimport { isSensitivePath, realpathForCheck } from \"./util\";\n\nconst schema = z.object({\n path: z.string().describe(\"File path, absolute or relative to the working directory\"),\n content: z.string().describe(\"Full content to write to the file\"),\n});\n\nexport const writeFileTool: Tool<typeof schema> = {\n name: \"write_file\",\n description:\n \"Write content to a file, creating parent directories as needed. Overwrites existing files. Refuses content with NUL bytes (binary) or over 5MB.\",\n permission: \"write\",\n parameters: schema,\n async execute(args, ctx) {\n const filePath = path.resolve(ctx.cwd, args.path);\n // Same symlink defense as read_file: a repo can plant a harmless-looking\n // link (config.json -> .env) whose resolved name is on the sensitive\n // list, and the permission gate only name-checks the raw path — so this\n // runs in-tool, unreachable by yolo mode or hooks. Unresolvable (new)\n // paths resolve the parent and re-attach the basename.\n const resolvedPath = await realpathForCheck(filePath);\n if (isSensitivePath(filePath) || (resolvedPath !== null && isSensitivePath(resolvedPath))) {\n return { content: `Refused to write sensitive file: ${args.path}`, isError: true };\n }\n // write_file writes UTF-8 text: NUL bytes mean the model is pushing\n // binary content that would land corrupted, and past the snapshot cap\n // /undo keeps only metadata, so the overwritten file would be\n // unrecoverable — same limits as edit_file.\n if (args.content.includes(\"\\0\")) {\n return {\n content: `Refused to write ${args.path}: content contains NUL bytes (write_file is text-only)`,\n isError: true,\n };\n }\n const bytes = Buffer.byteLength(args.content, \"utf8\");\n if (bytes > MAX_SNAPSHOT_CONTENT_BYTES) {\n return {\n content: `Refused to write ${args.path}: content is ${bytes} bytes, over the 5MB limit (writes past it could not be restored by /undo)`,\n isError: true,\n };\n }\n const snapshot = await captureSnapshot(filePath, \"write_file\", ctx.snapshotContext);\n try {\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, args.content, \"utf8\");\n } catch (err) {\n return { content: `Failed to write ${args.path}: ${(err as Error).message}`, isError: true };\n }\n await pushSnapshot(snapshot);\n return { content: `Wrote ${bytes} bytes to ${args.path}` };\n },\n};\n","import { z } from \"zod\";\nimport { probeImageDimensions } from \"../core/image\";\nimport { type ScreenshotResult, captureScreenshot } from \"../core/screenshot\";\nimport type { Tool } from \"./types\";\n\nconst schema = z.object({});\n\n// Lets the model look at the actual screen mid-session — the visual debugging\n// counterpart of read_image: start a dev server or GUI program, screenshot,\n// then judge the real rendered output instead of guessing from code. The\n// capture function is injectable so tests never touch a real display.\nexport function createScreenshotTool(\n capture: () => Promise<ScreenshotResult> = captureScreenshot,\n): Tool<typeof schema> {\n return {\n name: \"screenshot\",\n description:\n \"Capture a screenshot of the primary display and see it. Use this to check the actual visual result of a running program (web page, GUI) — e.g. after starting a dev server — instead of inferring from code. The capture shows exactly what is visible on screen, including overlapping windows: content hidden behind other windows cannot be seen, so if a specific window matters ask the user to bring it to the front first. Note the capture may include anything else currently on screen.\",\n permission: \"read\",\n parameters: schema,\n async execute(_args, ctx) {\n if (ctx.visionEnabled === false) {\n return {\n content:\n \"The active model does not support image input (vision = false), so no screenshot was taken. Work from text instead, or ask the user to describe what is on screen.\",\n isError: true,\n };\n }\n const result = await capture();\n if (!result.ok) {\n return { content: `Screenshot failed: ${result.error}`, isError: true };\n }\n const image = result.image;\n const dims = probeImageDimensions(Buffer.from(image.data, \"base64\"));\n const sizeKB = Math.round(image.data.length / 1024);\n const desc = dims ? `${dims.width}x${dims.height}` : \"unknown dimensions\";\n return {\n content: `Screenshot captured (${desc}, ~${sizeKB}KB). The image is attached below — look at it now.`,\n images: [image],\n };\n },\n };\n}\n\nexport const screenshotTool = createScreenshotTool();\n","import { execFile } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { readFile, unlink } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { probeImageDimensions } from \"./image\";\nimport { downsampleImageIfNeeded } from \"./image-resize\";\nimport type { ImageInput } from \"./messages\";\n\nexport const SCREENSHOT_TIMEOUT_MS = 20_000;\n\nconst execFileAsync = promisify(execFile);\n\nexport interface ScreenshotCommand {\n command: string;\n args: string[];\n}\n\nexport type ScreenshotResult = { ok: true; image: ImageInput } | { ok: false; error: string };\n\n// Windows capture script: copies the primary screen into a PNG. The position\n// problem on Windows is DPI virtualization — when the process is not truly\n// per-monitor DPI aware, the Bounds Forms reports and the pixels CopyFromScreen\n// reads live in different coordinate spaces, so at 125%/150% scaling the\n// capture comes out offset and wrongly sized. Setting per-monitor-V2 awareness\n// before touching Forms/Drawing makes both sides physical pixels; the call\n// fails harmlessly when the host manifest already pinned awareness (system\n// awareness is still physically correct on the primary display).\nexport function windowsScreenshotScript(outputFile: string): string {\n const output = outputFile.replace(/'/g, \"''\");\n return [\n \"try { Add-Type -MemberDefinition '[DllImport(\\\"user32.dll\\\")] public static extern bool SetProcessDpiAwarenessContext(int v);' -Name Dpi -Namespace StarShot -ErrorAction Stop; [void][StarShot.Dpi]::SetProcessDpiAwarenessContext(-4) } catch { }\",\n \"Add-Type -AssemblyName System.Windows.Forms,System.Drawing\",\n \"$b = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds\",\n \"$bmp = New-Object System.Drawing.Bitmap($b.Width, $b.Height)\",\n \"$g = [System.Drawing.Graphics]::FromImage($bmp)\",\n \"$g.CopyFromScreen($b.Left, $b.Top, 0, 0, $bmp.Size)\",\n `$bmp.Save('${output}', [System.Drawing.Imaging.ImageFormat]::Png)`,\n \"$g.Dispose(); $bmp.Dispose()\",\n ].join(\"; \");\n}\n\n// Platform-native capture command writing a PNG to outputFile, or null when\n// this platform/session cannot take screenshots. Windows/macOS capture the\n// primary display only — one deterministic file and physically exact bounds,\n// even on mixed-DPI multi-monitor setups; Linux tools capture the whole\n// compositor/root window (all monitors composited).\nexport function screenshotPlan(\n platform: NodeJS.Platform,\n outputFile: string,\n env: NodeJS.ProcessEnv = process.env,\n tools: Record<string, boolean> = {},\n): ScreenshotCommand | null {\n if (platform === \"win32\") {\n return {\n command: \"powershell.exe\",\n args: [\"-NoProfile\", \"-NonInteractive\", \"-Command\", windowsScreenshotScript(outputFile)],\n };\n }\n if (platform === \"darwin\") {\n // -x silences the shutter sound; -D 1 pins the main display so a single\n // output file is deterministic no matter how many monitors are attached.\n return { command: \"screencapture\", args: [\"-x\", \"-D\", \"1\", outputFile] };\n }\n if (platform === \"linux\") {\n if (env.WAYLAND_DISPLAY) {\n if (tools.grim) return { command: \"grim\", args: [outputFile] };\n if (tools[\"gnome-screenshot\"]) {\n return { command: \"gnome-screenshot\", args: [\"-f\", outputFile] };\n }\n if (tools.spectacle) {\n return { command: \"spectacle\", args: [\"-b\", \"-n\", \"-o\", outputFile] };\n }\n return null;\n }\n if (env.DISPLAY) {\n if (tools.import) return { command: \"import\", args: [\"-window\", \"root\", outputFile] };\n if (tools.scrot) return { command: \"scrot\", args: [\"--overwrite\", outputFile] };\n if (tools[\"gnome-screenshot\"]) {\n return { command: \"gnome-screenshot\", args: [\"-f\", outputFile] };\n }\n if (tools.spectacle) {\n return { command: \"spectacle\", args: [\"-b\", \"-n\", \"-o\", outputFile] };\n }\n return null;\n }\n return null;\n }\n return null;\n}\n\nexport function noScreenshotToolMessage(\n platform: NodeJS.Platform,\n env: NodeJS.ProcessEnv = process.env,\n): string {\n if (platform === \"linux\") {\n if (!env.WAYLAND_DISPLAY && !env.DISPLAY) {\n return \"no display server (neither DISPLAY nor WAYLAND_DISPLAY is set) — this session is headless (e.g. SSH), there is no screen to capture\";\n }\n return \"no screenshot tool found — install one of: grim or spectacle (Wayland), scrot or ImageMagick's import (X11), or gnome-screenshot\";\n }\n return `screenshots are not supported on this platform (${platform})`;\n}\n\nasync function commandExists(command: string): Promise<boolean> {\n const checker = process.platform === \"win32\" ? \"where\" : \"which\";\n try {\n await execFileAsync(checker, [command], { timeout: SCREENSHOT_TIMEOUT_MS });\n return true;\n } catch {\n return false;\n }\n}\n\nconst LINUX_TOOL_NAMES = [\"grim\", \"gnome-screenshot\", \"spectacle\", \"import\", \"scrot\"];\n\n// Captures the screen into a temp PNG via platform-native tools (no npm image\n// dependency), downsamples past 2000px like read_image, and returns the image\n// for the loop to attach to the history. Failures come back as messages the\n// model can act on instead of exceptions.\nexport async function captureScreenshot(): Promise<ScreenshotResult> {\n const outputFile = path.join(os.tmpdir(), `star-screenshot-${randomUUID()}.png`);\n try {\n const tools: Record<string, boolean> = {};\n if (process.platform === \"linux\") {\n const found = await Promise.all(LINUX_TOOL_NAMES.map(commandExists));\n for (const [i, name] of LINUX_TOOL_NAMES.entries()) {\n tools[name] = found[i] ?? false;\n }\n }\n const plan = screenshotPlan(process.platform, outputFile, process.env, tools);\n if (!plan) {\n return { ok: false, error: noScreenshotToolMessage(process.platform) };\n }\n try {\n await execFileAsync(plan.command, plan.args, { timeout: SCREENSHOT_TIMEOUT_MS });\n } catch (err) {\n const detail = err instanceof Error && err.message ? ` (${err.message})` : \"\";\n return { ok: false, error: `${plan.command} failed to capture the screen${detail}` };\n }\n const buf = await readFile(outputFile).catch(() => null);\n if (!buf || buf.length === 0) {\n return { ok: false, error: `${plan.command} produced no image file` };\n }\n if (!probeImageDimensions(buf)) {\n return { ok: false, error: `${plan.command} produced an unrecognized image file` };\n }\n const downsampled = await downsampleImageIfNeeded({\n path: \"screen\",\n mimeType: \"image/png\",\n data: buf.toString(\"base64\"),\n });\n if (downsampled.oversized && !downsampled.resized) {\n return {\n ok: false,\n error: \"screenshot exceeds 2000px and could not be downsampled on this platform\",\n };\n }\n return { ok: true, image: downsampled.image };\n } finally {\n await unlink(outputFile).catch(() => {});\n }\n}\n","import { z } from \"zod\";\nimport { type AgentTaskSnapshot, defaultAgentTasks } from \"../agent/agent-tasks\";\nimport { formatDuration, formatTaskLine, formatTaskList } from \"../tasks/format\";\nimport { type TaskSnapshot, defaultTaskManager } from \"../tasks/manager\";\nimport { MAX_OUTPUT } from \"./bash\";\nimport type { Tool, ToolContext } from \"./types\";\n\nconst idSchema = z.object({\n id: z.string().describe(\"Task id, e.g. task-1 or agent-1\"),\n});\n\n// Aligns with the foreground bash output cap: keep the tail, note the cut.\nfunction truncateOutput(s: string): string {\n if (s.length <= MAX_OUTPUT) return s;\n return `[... earlier output truncated; showing the last ${MAX_OUTPUT} characters ...]\\n${s.slice(-MAX_OUTPUT)}`;\n}\n\n// Shell tasks are owned by the agent that started them: root sees and\n// controls everything, a subagent only its own tasks — otherwise one\n// subagent could kill the parent's (or a sibling's) background work.\n// Unowned/foreign tasks answer \"Unknown task\" so their existence doesn't\n// leak either. Background subagents (agent-*) always belong to root:\n// subagents can't spawn subagents.\nfunction callerId(ctx: ToolContext): string {\n return ctx.agentId ?? \"root\";\n}\n\nfunction accessibleShellTask(ctx: ToolContext, id: string): TaskSnapshot | undefined {\n const task = defaultTaskManager.get(id);\n if (!task) return undefined;\n const caller = callerId(ctx);\n return caller === \"root\" || task.ownerId === caller ? task : undefined;\n}\n\nfunction formatAgentTaskLine(task: AgentTaskSnapshot): string {\n const duration = formatDuration(task.startedAt, task.endedAt);\n const label = task.description ?? task.prompt.slice(0, 60);\n const status =\n task.status === \"running\" ? `running ${duration}` : `${task.status} after ${duration}`;\n return `${task.id} [${status}] ${label}`;\n}\n\nexport const taskListTool: Tool = {\n name: \"task_list\",\n description: \"List background tasks (shell commands and subagents) with status and runtime.\",\n permission: \"read\",\n parameters: z.object({}),\n execute(_args, ctx) {\n const caller = callerId(ctx);\n const shell = formatTaskList(\n defaultTaskManager.list().filter((t) => caller === \"root\" || t.ownerId === caller),\n );\n const agents = caller === \"root\" ? defaultAgentTasks.list() : [];\n const agentLines =\n agents.length === 0\n ? \"No background subagents.\"\n : `Background subagents:\\n${agents.map(formatAgentTaskLine).join(\"\\n\")}`;\n return Promise.resolve({ content: `${shell}\\n${agentLines}` });\n },\n};\n\nexport const taskOutputTool: Tool<typeof idSchema> = {\n name: \"task_output\",\n description:\n \"Read the current output of a background task (shell command or subagent; works while still running).\",\n permission: \"read\",\n parameters: idSchema,\n execute(args, ctx) {\n const shell = accessibleShellTask(ctx, args.id);\n if (shell) {\n const body = truncateOutput(shell.output.replace(/\\s+$/, \"\") || \"(no output yet)\");\n return Promise.resolve({ content: `${formatTaskLine(shell)}\\n${body}` });\n }\n const agent = callerId(ctx) === \"root\" ? defaultAgentTasks.get(args.id) : undefined;\n if (agent) {\n const body =\n agent.status === \"running\"\n ? \"(still running)\"\n : truncateOutput(agent.result.replace(/\\s+$/, \"\") || \"(no report)\");\n return Promise.resolve({ content: `${formatAgentTaskLine(agent)}\\n${body}` });\n }\n return Promise.resolve({ content: `Unknown task: ${args.id}`, isError: true });\n },\n};\n\nexport const taskKillTool: Tool<typeof idSchema> = {\n name: \"task_kill\",\n description: \"Stop a running background task (shell command process tree or subagent).\",\n permission: \"exec\",\n parameters: idSchema,\n execute(args, ctx) {\n const shell = accessibleShellTask(ctx, args.id);\n const agent = shell || callerId(ctx) !== \"root\" ? undefined : defaultAgentTasks.get(args.id);\n const task = shell ?? agent;\n if (!task) {\n return Promise.resolve({ content: `Unknown task: ${args.id}`, isError: true });\n }\n if (task.status !== \"running\") {\n return Promise.resolve({\n content: `Task ${args.id} is not running (status: ${task.status}).`,\n isError: true,\n });\n }\n if (shell) {\n defaultTaskManager.kill(args.id);\n } else {\n defaultAgentTasks.kill(args.id);\n }\n return Promise.resolve({ content: `Task ${args.id} stopped.` });\n },\n};\n","import type { TaskSnapshot } from \"./manager\";\n\nexport function formatDuration(startedAt: number, endedAt?: number): string {\n const seconds = Math.max(0, Math.round(((endedAt ?? Date.now()) - startedAt) / 1000));\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m${seconds % 60}s`;\n return `${Math.floor(minutes / 60)}h${minutes % 60}m`;\n}\n\nfunction formatStatus(task: TaskSnapshot): string {\n const duration = formatDuration(task.startedAt, task.endedAt);\n if (task.status === \"running\") return `running ${duration}`;\n const exit =\n task.exitCode === null || task.exitCode === undefined ? \"\" : `, exit ${task.exitCode}`;\n return `${task.status}${exit} after ${duration}`;\n}\n\nexport function formatTaskLine(task: TaskSnapshot): string {\n const label = task.description ? `${task.description} (${task.command})` : task.command;\n return `${task.id} [${formatStatus(task)}] ${label}`;\n}\n\nexport function formatTaskList(tasks: TaskSnapshot[]): string {\n if (tasks.length === 0) return \"No background tasks.\";\n return `Background tasks:\\n${tasks.map(formatTaskLine).join(\"\\n\")}`;\n}\n\nexport function formatTaskStarted(task: TaskSnapshot): string {\n const label = task.description ? `${task.description} (${task.command})` : task.command;\n return `Background task ${task.id} started: ${label}`;\n}\n\nexport function formatTaskFinished(task: TaskSnapshot): string {\n const exit =\n task.exitCode === null || task.exitCode === undefined ? \"\" : ` (exit ${task.exitCode})`;\n switch (task.status) {\n case \"completed\":\n return `Background task ${task.id} finished${exit}: ${task.command}`;\n case \"failed\":\n return `Background task ${task.id} failed${exit}: ${task.command}`;\n case \"timed_out\":\n return `Background task ${task.id} timed out: ${task.command}`;\n case \"stopped\":\n return `Background task ${task.id} stopped: ${task.command}`;\n default:\n return `Background task ${task.id}: ${task.command}`;\n }\n}\n","import { z } from \"zod\";\nimport { debugStreamLog } from \"../../llm/debug\";\nimport type { Tool } from \"../types\";\nimport { decodeEntities } from \"./fetch\";\n\nconst TIMEOUT_MS = 15000;\nconst DEFAULT_MAX_RESULTS = 5;\nconst MAX_RESULTS_LIMIT = 10;\nconst USER_AGENT =\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\";\n\nconst schema = z.object({\n query: z.string().min(1).describe(\"The search query\"),\n maxResults: z\n .number()\n .int()\n .min(1)\n .max(MAX_RESULTS_LIMIT)\n .optional()\n .describe(\n `Maximum number of results to return (default ${DEFAULT_MAX_RESULTS}, max ${MAX_RESULTS_LIMIT})`,\n ),\n});\n\nexport interface SearchResult {\n title: string;\n url: string;\n snippet: string;\n}\n\n// A search backend: builds the request URL for a query and parses its HTML\n// into the unified {title, url, snippet} shape. Sources are tried in order;\n// a network error, non-2xx status or zero parsed results falls through to\n// the next one.\ninterface SearchSource {\n name: string;\n buildUrl: (query: string) => string;\n parse: (html: string) => SearchResult[];\n}\n\nfunction stripTags(s: string): string {\n return decodeEntities(s.replace(/<[^>]+>/g, \" \"))\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction normalizeUrl(href: string): string {\n const decoded = decodeEntities(href);\n const uddg = decoded.match(/[?&]uddg=([^&]+)/);\n if (uddg?.[1]) {\n try {\n return decodeURIComponent(uddg[1]);\n } catch {\n return decoded;\n }\n }\n if (decoded.startsWith(\"//\")) {\n return `https:${decoded}`;\n }\n return decoded;\n}\n\nfunction hrefOf(tag: string): string | undefined {\n const match = tag.match(/href\\s*=\\s*\"([^\"]*)\"/i) ?? tag.match(/href\\s*=\\s*'([^']*)'/i);\n return match?.[1];\n}\n\nexport function parseResults(html: string): SearchResult[] {\n const results: SearchResult[] = [];\n const anchorRe = /<a\\b[^>]*\\bclass\\s*=\\s*\"[^\"]*\\bresult__a\\b[^\"]*\"[^>]*>[\\s\\S]*?<\\/a>/gi;\n const anchors = [...html.matchAll(anchorRe)];\n for (const [i, anchor] of anchors.entries()) {\n const full = anchor[0];\n const href = hrefOf(full);\n if (!href) {\n continue;\n }\n const url = normalizeUrl(href);\n const title = stripTags(full.replace(/^<a\\b[^>]*>/i, \"\").replace(/<\\/a>\\s*$/i, \"\"));\n const blockStart = (anchor.index ?? 0) + full.length;\n const blockEnd = i + 1 < anchors.length ? (anchors[i + 1]?.index ?? html.length) : html.length;\n const block = html.slice(blockStart, blockEnd);\n const snippetMatch = block.match(\n /<(?:a|div)\\b[^>]*\\bclass\\s*=\\s*\"[^\"]*\\bresult__snippet\\b[^\"]*\"[^>]*>([\\s\\S]*?)<\\/(?:a|div)>/i,\n );\n const snippet = snippetMatch?.[1] ? stripTags(snippetMatch[1]) : \"\";\n if (title && url) {\n results.push({ title, url, snippet });\n }\n }\n return results;\n}\n\n// lite.duckduckgo.com serves a different (table-based) layout: titles in\n// <a class=\"result-link\">, snippets in the following <td class=\"result-snippet\">.\nexport function parseDdgLiteResults(html: string): SearchResult[] {\n const results: SearchResult[] = [];\n const anchorRe =\n /<a\\b[^>]*\\bclass\\s*=\\s*[\"'][^\"']*\\bresult-link\\b[^\"']*[\"'][^>]*>[\\s\\S]*?<\\/a>/gi;\n const anchors = [...html.matchAll(anchorRe)];\n for (const [i, anchor] of anchors.entries()) {\n const full = anchor[0];\n const href = hrefOf(full);\n if (!href) {\n continue;\n }\n const url = normalizeUrl(href);\n const title = stripTags(full.replace(/^<a\\b[^>]*>/i, \"\").replace(/<\\/a>\\s*$/i, \"\"));\n const blockStart = (anchor.index ?? 0) + full.length;\n const blockEnd = i + 1 < anchors.length ? (anchors[i + 1]?.index ?? html.length) : html.length;\n const block = html.slice(blockStart, blockEnd);\n const snippetMatch = block.match(\n /<td\\b[^>]*\\bclass\\s*=\\s*[\"'][^\"']*\\bresult-snippet\\b[^\"']*[\"'][^>]*>([\\s\\S]*?)<\\/td>/i,\n );\n const snippet = snippetMatch?.[1] ? stripTags(snippetMatch[1]) : \"\";\n if (title && url) {\n results.push({ title, url, snippet });\n }\n }\n return results;\n}\n\n// www.bing.com/search needs no key: results are <li class=\"b_algo\"> blocks\n// with the title link in <h2><a> and the snippet in the block's first <p>.\nexport function parseBingResults(html: string): SearchResult[] {\n const results: SearchResult[] = [];\n const blockRe = /<li\\b[^>]*\\bclass\\s*=\\s*\"[^\"]*\\bb_algo\\b[^\"]*\"[^>]*>/gi;\n const blocks = [...html.matchAll(blockRe)];\n for (const [i, block] of blocks.entries()) {\n const start = block.index ?? 0;\n const end = i + 1 < blocks.length ? (blocks[i + 1]?.index ?? html.length) : html.length;\n const slice = html.slice(start, end);\n const headMatch = slice.match(\n /<h2\\b[^>]*>[\\s\\S]*?<a\\b[^>]*?\\shref\\s*=\\s*\"([^\"]*)\"[^>]*>([\\s\\S]*?)<\\/a>[\\s\\S]*?<\\/h2>/i,\n );\n if (!headMatch) {\n continue;\n }\n const url = decodeEntities(headMatch[1] ?? \"\").trim();\n const title = stripTags(headMatch[2] ?? \"\");\n const snippetMatch = slice.match(/<p\\b[^>]*>([\\s\\S]*?)<\\/p>/i);\n const snippet = snippetMatch?.[1] ? stripTags(snippetMatch[1]) : \"\";\n if (title && /^https?:\\/\\//.test(url)) {\n results.push({ title, url, snippet });\n }\n }\n return results;\n}\n\nconst SEARCH_SOURCES: SearchSource[] = [\n {\n name: \"duckduckgo-html\",\n buildUrl: (query) => `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`,\n parse: parseResults,\n },\n {\n name: \"duckduckgo-lite\",\n buildUrl: (query) => `https://lite.duckduckgo.com/lite/?q=${encodeURIComponent(query)}`,\n parse: parseDdgLiteResults,\n },\n {\n name: \"bing\",\n buildUrl: (query) => `https://www.bing.com/search?q=${encodeURIComponent(query)}`,\n parse: parseBingResults,\n },\n];\n\nexport const webSearchTool: Tool<typeof schema> = {\n name: \"web_search\",\n description:\n \"Search the web and return a numbered list of results with title, URL and snippet. Uses DuckDuckGo with automatic fallback to DuckDuckGo Lite and Bing when a source fails or returns nothing. No API key required. Use web_fetch to read a result's full page.\",\n permission: \"read\",\n parameters: schema,\n async execute(args, ctx) {\n const maxResults = Math.min(args.maxResults ?? DEFAULT_MAX_RESULTS, MAX_RESULTS_LIMIT);\n const failures: string[] = [];\n for (const source of SEARCH_SOURCES) {\n const timeoutSignal = AbortSignal.timeout(TIMEOUT_MS);\n const signal = ctx.abortSignal\n ? AbortSignal.any([timeoutSignal, ctx.abortSignal])\n : timeoutSignal;\n let res: Response;\n try {\n res = await fetch(source.buildUrl(args.query), {\n signal,\n redirect: \"follow\",\n headers: { \"user-agent\": USER_AGENT, accept: \"text/html\" },\n });\n } catch (err) {\n if (ctx.abortSignal?.aborted) {\n return { content: \"ERROR: request aborted\", isError: true };\n }\n const name = err instanceof Error ? err.name : \"\";\n if (timeoutSignal.aborted || name === \"TimeoutError\") {\n failures.push(`${source.name}: search timed out after ${TIMEOUT_MS / 1000}s`);\n } else {\n const message = err instanceof Error ? err.message : String(err);\n failures.push(`${source.name}: search request failed: ${message}`);\n }\n continue;\n }\n if (!res.ok) {\n await res.body?.cancel().catch(() => {});\n failures.push(`${source.name}: HTTP ${res.status} ${res.statusText}`);\n continue;\n }\n let html: string;\n try {\n html = await res.text();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n failures.push(`${source.name}: failed to read search response: ${message}`);\n continue;\n }\n const results = source.parse(html).slice(0, maxResults);\n if (results.length === 0) {\n failures.push(\n `${source.name}: no results found (the response may have been blocked or the page layout changed)`,\n );\n continue;\n }\n debugStreamLog(\"web_search\", {\n source: source.name,\n query: args.query,\n results: results.length,\n failures,\n });\n const lines = results.map(\n (r, i) => `${i + 1}. ${r.title}\\n ${r.url}${r.snippet ? `\\n ${r.snippet}` : \"\"}`,\n );\n return { content: lines.join(\"\\n\") };\n }\n debugStreamLog(\"web_search_failed\", { query: args.query, failures });\n return {\n content: `ERROR: web search failed for \"${args.query}\" — ${failures.join(\"; \")}`,\n isError: true,\n };\n },\n};\n","import { appendFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { starHome } from \"../config/paths\";\n\n// STAR_DEBUG-gated JSONL log of stream internals (~/.star-cli/debug.log):\n// what the provider actually sent — finish reasons, usage, error details —\n// so a misbehaving relay can be diagnosed from the client side. All write\n// failures are silent; logging must never break a turn.\nexport function debugStreamLog(event: string, data?: Record<string, unknown>): void {\n if (!process.env.STAR_DEBUG) return;\n try {\n const line = `${JSON.stringify({ ts: new Date().toISOString(), event, ...data })}\\n`;\n appendFileSync(path.join(starHome(), \"debug.log\"), line);\n } catch {\n // best-effort only\n }\n}\n","import { bashTool } from \"./bash\";\nimport { editFileTool } from \"./fs/edit\";\nimport { globTool } from \"./fs/glob\";\nimport { grepTool } from \"./fs/grep\";\nimport { codeOutlineTool } from \"./fs/outline\";\nimport { createReadFileTool } from \"./fs/read\";\nimport { readImageTool } from \"./fs/read-image\";\nimport { writeFileTool } from \"./fs/write\";\nimport { screenshotTool } from \"./screenshot\";\nimport { taskKillTool, taskListTool, taskOutputTool } from \"./tasks\";\nimport { type TodoStore, createTodoTools, sharedTodoStore } from \"./todo\";\nimport type { Tool } from \"./types\";\nimport { webFetchTool } from \"./web/fetch\";\nimport { webSearchTool } from \"./web/search\";\n\nexport class ToolRegistry {\n private tools = new Map<string, Tool>();\n\n // todoStore defaults to the module-level shared store; subagent loops pass\n // their own instance so a child's todo_write cannot clobber the parent list.\n // Exposed so the agent loop can watch open items for staleness.\n readonly todos: TodoStore;\n\n constructor(todoStore?: TodoStore) {\n this.todos = todoStore ?? sharedTodoStore();\n for (const tool of [\n // Fresh per registry (i.e. per agent loop): the unchanged-since-last-\n // read cache must not leak across loops, whose contexts differ.\n createReadFileTool(),\n readImageTool,\n screenshotTool,\n writeFileTool,\n editFileTool,\n globTool,\n grepTool,\n codeOutlineTool,\n bashTool,\n webFetchTool,\n webSearchTool,\n taskListTool,\n taskOutputTool,\n taskKillTool,\n ...createTodoTools(this.todos),\n ]) {\n this.register(tool);\n }\n }\n\n register(tool: Tool): void {\n this.tools.set(tool.name, tool);\n }\n\n // Drops every tool the predicate rejects. Used to restrict a read-only\n // subagent loop's tool set; the agent loop reads list() lazily per\n // request, so a retain right after loop construction still shapes the\n // first request. The permission gate stays as backstop for anything\n // attempted outside the model's tool map.\n retain(predicate: (tool: Tool) => boolean): void {\n for (const [name, tool] of this.tools) {\n if (!predicate(tool)) this.tools.delete(name);\n }\n }\n\n // Drops per-session volatile tool state after a wholesale history rewrite\n // (compaction, /undo, resume): anything a tool remembers as \"already sent\n // to the model\" may no longer be in the context.\n resetVolatileState(): void {\n for (const tool of this.tools.values()) tool.reset?.();\n }\n\n get(name: string): Tool | undefined {\n return this.tools.get(name);\n }\n\n list(): Tool[] {\n return [...this.tools.values()];\n }\n\n names(): string[] {\n return [...this.tools.keys()];\n }\n}\n","import { ToolRegistry } from \"./registry\";\nimport type { TodoStore } from \"./todo\";\n\nexport { ToolRegistry } from \"./registry\";\nexport { TodoStore, createTodoTools, setTodoPersistGuard } from \"./todo\";\nexport type { TodoItem } from \"./todo\";\nexport type { PermissionLevel, Tool, ToolContext, ToolResult } from \"./types\";\n\n// The registry constructor registers every built-in tool (todo tools\n// included); this helper only forwards the optional per-loop todo store.\nexport function createDefaultRegistry(todoStore?: TodoStore): ToolRegistry {\n return new ToolRegistry(todoStore);\n}\n"],"mappings":"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","names":["path","z","schema","z","path","readFile","stat","path","z","schema","z","path","stat","readFile","readFile","realpath","stat","path","z","MAX_FILE_BYTES","MAX_LINE_CHARS","path","stat","readFile","schema","z","realpath","realpath","stat","path","z","BINARY_PROBE_BYTES","schema","z","path","realpath","stat","readFile","realpath","stat","path","z","schema","z","path","realpath","stat","readFile","writeFile","path","z","schema","z","path","writeFile","z","readFile","path","path","readFile","schema","z","z","z","z","path","path","schema","z"]}
|