@buildaharness/aielia 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +97 -19
  2. package/dist/action-approval-service.d.ts +34 -2
  3. package/dist/action-record.d.ts +13 -0
  4. package/dist/activity-log.d.ts +4 -0
  5. package/dist/agent-loop.d.ts +83 -1
  6. package/dist/assistant-session.d.ts +20 -1
  7. package/dist/assistant-types.d.ts +3 -1
  8. package/dist/assistant.d.ts +32 -0
  9. package/dist/{bin-CjKpxDxl.js → bin-C_hgDdSf.js} +369 -219
  10. package/dist/bin-C_hgDdSf.js.map +1 -0
  11. package/dist/cli-config.d.ts +3 -0
  12. package/dist/cli-session.d.ts +5 -4
  13. package/dist/cli.d.ts +9 -0
  14. package/dist/cli.js +1 -1
  15. package/dist/config.d.ts +3 -1
  16. package/dist/debug-log.d.ts +10 -1
  17. package/dist/email.d.ts +5 -3
  18. package/dist/file-tools-mcp-server.mjs +155 -30
  19. package/dist/file-tools.d.ts +2 -0
  20. package/dist/git-exclude.d.ts +9 -0
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +127 -126
  23. package/dist/ink-select-prompt.d.ts +2 -0
  24. package/dist/ink-test-render.d.ts +2 -0
  25. package/dist/memory-service.d.ts +8 -0
  26. package/dist/next-step-proposer.d.ts +7 -0
  27. package/dist/plan-drafting-service.d.ts +3 -0
  28. package/dist/plan-store.d.ts +5 -0
  29. package/dist/{provider-setup-LFsaTkpf.js → provider-setup-wX2IBw2X.js} +2183 -919
  30. package/dist/provider-setup-wX2IBw2X.js.map +1 -0
  31. package/dist/reply-audit.d.ts +67 -0
  32. package/dist/side-call-policy.d.ts +30 -0
  33. package/dist/tool-step.d.ts +6 -0
  34. package/dist/trace-events.d.ts +1 -1
  35. package/dist/trust-tagging.d.ts +2 -0
  36. package/dist/{tui-app-BLR-PRFp.js → tui-app-C0J6HRzv.js} +127 -26
  37. package/dist/tui-app-C0J6HRzv.js.map +1 -0
  38. package/dist/tui-app.d.ts +35 -0
  39. package/dist/tui-mode-flag.d.ts +1 -1
  40. package/dist/turn-abort.d.ts +18 -0
  41. package/dist/turn-intent-classifier.d.ts +8 -0
  42. package/dist/turn-interpreter.d.ts +2 -0
  43. package/dist/version.d.ts +1 -1
  44. package/package.json +3 -3
  45. package/dist/bin-CjKpxDxl.js.map +0 -1
  46. package/dist/provider-setup-LFsaTkpf.js.map +0 -1
  47. package/dist/tui-app-BLR-PRFp.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"tui-app-BLR-PRFp.js","sources":["../src/tui-output-capture.ts","../src/tui-input.tsx","../src/ink-select-prompt.tsx","../src/plan-viz/plan-nav.ts","../src/plan-viz/plan-viewport.ts","../src/plan-viz/plan-detail-lines.ts","../src/PlanGraphPane.tsx","../src/markdown-line.tsx","../src/tui-app.tsx"],"sourcesContent":["import { format } from 'node:util'\n\n/**\n * One classified write, mirroring the three writer patterns `cli.ts` already uses (see that\n * file's `writeProgress`/`clearProgress`, `writeToolStep`, `writeToken`) — not a new convention,\n * just naming what's already there so Phase 3's Ink shell can route each kind to the right\n * region (transient status line, transient streamed-reply buffer, permanent scrollback).\n */\nexport type CaptureEvent =\n | {\n /** `writeProgress`'s `\\r`-overwritten step counter, or `clearProgress`'s blank-out of it. */\n type: 'progress'\n /** The current progress text with the `\\r` control character and `padEnd` filler removed — `''` once cleared. */\n text: string\n }\n | {\n /** `writeToken`'s raw incremental streamed characters — no trailing newline until the turn ends. */\n type: 'token'\n text: string\n }\n | {\n /** A `console.log`/`console.error` call, or any write that completes with a trailing newline — one or more committed, permanently-scrolled lines. */\n type: 'line'\n lines: string[]\n /** Which global function produced this — `'stderr'` only for `console.error`, everything else (`console.log`, raw `process.stdout.write`) is `'stdout'`. Lets a consumer (Phase 3's `EventLogBridge`) style error output distinctly without guessing from content. */\n stream: 'stdout' | 'stderr'\n }\n\n/**\n * Classifies a single already-formatted write exactly the way the three writer patterns in\n * `cli.ts` are told apart from each other (see this file's `CaptureEvent` doc comment): a\n * leading `\\r` means progress, a trailing `\\n` means one or more committed lines, and everything\n * else (streamed reply tokens — the only writer left that produces neither) is a token.\n */\nfunction classify(raw: string, stream: 'stdout' | 'stderr'): CaptureEvent {\n if (raw.startsWith('\\r')) {\n // `padEnd`'s filler spaces exist only to overwrite a longer previous line on a real\n // terminal — Ink re-renders the whole frame every time, so that artifact would just show up\n // as trailing whitespace with no purpose. `clearProgress`'s `\\r${spaces}\\r` collapses to ''.\n return { type: 'progress', text: raw.replace(/\\r/g, '').trimEnd() }\n }\n if (raw.endsWith('\\n')) {\n // Drop only the one trailing empty element `split` produces because the string itself ends\n // in '\\n' — any other blank lines in the middle (e.g. a call site's own leading/trailing\n // '\\n' for spacing) are real committed blank lines, not a split artifact.\n return { type: 'line', lines: raw.slice(0, -1).split('\\n'), stream }\n }\n return { type: 'token', text: raw }\n}\n\ntype StdoutWrite = typeof process.stdout.write\n\n/**\n * Monkey-patches `console.log`, `console.error`, and `process.stdout.write` for the duration of\n * the interactive Ink session, classifying every write via {@link classify} and routing it to\n * `onEvent` instead of the real terminal — Ink owns the frame once this is active (Decision 1:\n * every command handler still calls the same global functions unmodified). Returns a restore\n * function that puts the originals back; call it on exit and in every test's `afterEach`.\n */\nexport function startCapture(onEvent: (event: CaptureEvent) => void): () => void {\n const originalLog = console.log\n const originalError = console.error\n const originalWrite = process.stdout.write\n\n const makeCaptureConsole = (stream: 'stdout' | 'stderr') => (...args: unknown[]): void => {\n onEvent(classify(`${format(...(args as [unknown, ...unknown[]]))}\\n`, stream))\n }\n console.log = makeCaptureConsole('stdout')\n console.error = makeCaptureConsole('stderr')\n\n const captureWrite: StdoutWrite = ((chunk: unknown, ...rest: unknown[]): boolean => {\n onEvent(classify(typeof chunk === 'string' ? chunk : String(chunk), 'stdout'))\n // Honor process.stdout.write's real contract (an optional trailing callback) even though no\n // call site in cli.ts currently passes one — costs nothing and avoids a silent hang for any\n // future one that does.\n const callback = rest.find((arg): arg is () => void => typeof arg === 'function')\n callback?.()\n return true\n }) as StdoutWrite\n process.stdout.write = captureWrite\n\n return () => {\n console.log = originalLog\n console.error = originalError\n process.stdout.write = originalWrite\n }\n}\n","import { useRef, useState } from 'react'\nimport { Box, Text, useInput, usePaste, useWindowSize } from 'ink'\n\n/** @default 5 — the plan's own \"grows up to 5 rows, then scrolls internally\" number. */\nconst DEFAULT_MAX_ROWS = 5\n/** Round border (1 col each side) + paddingX (1 col each side) eaten out of the terminal width before wrapping text. */\nconst BOX_CHROME_WIDTH = 4\n\n/**\n * One word-wrapped visual row of the draft. `wraps: true` means the next row is a continuation\n * of the same logical (`\\n`-delimited) line — no real newline between `end` and the next row's\n * `start` — which is what lets {@link offsetToRowCol} tell a wrap boundary (cursor snaps to the\n * start of the next row) apart from a real end-of-line (cursor stays put at this row's end).\n */\nexport interface DraftRow {\n text: string\n start: number\n end: number\n wraps: boolean\n}\n\n/**\n * Splits `value` into visual rows at `\\n` boundaries and, within each logical line, at every\n * `columns`-wide chunk — plain character wrapping (not word-boundary wrapping): a real terminal\n * hard-wraps by character when a row overflows, so this matches what the terminal will actually\n * show rather than reflowing at word boundaries the way a GUI text area would.\n */\nexport function wrapDraftIntoRows(value: string, columns: number): DraftRow[] {\n const width = Math.max(1, columns)\n const rows: DraftRow[] = []\n const logicalLines = value.split('\\n')\n let offset = 0\n logicalLines.forEach((line, li) => {\n if (line.length === 0) {\n rows.push({ text: '', start: offset, end: offset, wraps: false })\n } else {\n for (let i = 0; i < line.length; i += width) {\n const text = line.slice(i, i + width)\n const start = offset + i\n const end = start + text.length\n rows.push({ text, start, end, wraps: end < offset + line.length })\n }\n }\n offset += line.length\n if (li < logicalLines.length - 1) offset += 1 // the '\\n' itself\n })\n return rows\n}\n\n/** Maps a character offset into `value` to its (row, col) among `rows` — see {@link DraftRow.wraps} for the wrap-vs-newline distinction this leans on. */\nexport function offsetToRowCol(rows: DraftRow[], cursor: number): { row: number; col: number } {\n for (let r = 0; r < rows.length; r++) {\n const row = rows[r]!\n if (cursor < row.end) return { row: r, col: cursor - row.start }\n if (cursor === row.end && !row.wraps) return { row: r, col: cursor - row.start }\n }\n const last = rows[rows.length - 1]\n return last ? { row: rows.length - 1, col: last.text.length } : { row: 0, col: 0 }\n}\n\n/** Inverse of {@link offsetToRowCol}, clamping both row and column into range — used to preserve column when moving the cursor a visual row up/down. */\nexport function rowColToOffset(rows: DraftRow[], row: number, col: number): number {\n const clampedRow = Math.max(0, Math.min(row, rows.length - 1))\n const target = rows[clampedRow]\n if (!target) return 0\n return target.start + Math.max(0, Math.min(col, target.text.length))\n}\n\n/** Home = start of the current logical (`\\n`-delimited) line, not the current visual row. */\nexport function homeOffset(value: string, cursor: number): number {\n return value.lastIndexOf('\\n', cursor - 1) + 1\n}\n\n/** End = end of the current logical (`\\n`-delimited) line, not the current visual row. */\nexport function endOffset(value: string, cursor: number): number {\n const idx = value.indexOf('\\n', cursor)\n return idx === -1 ? value.length : idx\n}\n\n/**\n * Keeps the cursor's row inside a `maxRows`-tall window, scrolling the minimum amount needed —\n * matches an ordinary scrolling textarea rather than re-centering on every keystroke.\n */\nexport function computeViewportStart(prevStart: number, cursorRow: number, totalRows: number, maxRows: number): number {\n if (totalRows <= maxRows) return 0\n let start = prevStart\n if (cursorRow < start) start = cursorRow\n if (cursorRow > start + maxRows - 1) start = cursorRow - maxRows + 1\n return Math.max(0, Math.min(start, totalRows - maxRows))\n}\n\nexport interface TuiInputProps {\n /** Question text for a pending askYesNo/askLine prompt (Decision 1's override seam) — undefined means ordinary chat mode. Shown as a label above the box, since it's real information (the question being asked), unlike chat mode's old static \"you\" label, which was dropped in favor of a placeholder inside the box (see `placeholder` below). */\n promptLabel?: string\n /** Faint placeholder shown inside the (empty) box in chat mode, replacing the old \"you\" label above it. */\n placeholder?: string\n /** Called when Enter submits a non-empty draft in chat mode. Also appended to in-session history. */\n onSubmitChat: (line: string) => void\n /** Called when Enter resolves a pending prompt (promptLabel set). Not added to chat history. */\n onSubmitPrompt: (line: string) => void\n /** Terminal width; defaults to the live width from Ink's useWindowSize. Pass explicitly for a deterministic wrap width in tests. */\n columns?: number\n /** Max input box height in rows before internal scrolling kicks in. */\n maxRows?: number\n isActive?: boolean\n}\n\nexport function TuiInput(props: TuiInputProps): React.JSX.Element {\n const { promptLabel, placeholder = 'Type your message here', onSubmitChat, onSubmitPrompt, maxRows = DEFAULT_MAX_ROWS, isActive = true } = props\n\n const [value, setValue] = useState('')\n const [cursor, setCursor] = useState(0)\n const [history, setHistory] = useState<string[]>([])\n const [historyIndex, setHistoryIndex] = useState<number | null>(null)\n const [pendingDraft, setPendingDraft] = useState('')\n\n const windowSize = useWindowSize()\n const terminalColumns = props.columns ?? windowSize.columns\n const wrapWidth = Math.max(1, terminalColumns - BOX_CHROME_WIDTH)\n\n const rows = wrapDraftIntoRows(value, wrapWidth)\n const { row: cursorRow, col: cursorCol } = offsetToRowCol(rows, cursor)\n\n // Mutated during render, not via setState — this is a derived scroll cache keyed off the\n // current row layout/cursor, not independent state, so it doesn't need its own re-render.\n const viewportStartRef = useRef(0)\n viewportStartRef.current = computeViewportStart(viewportStartRef.current, cursorRow, rows.length, maxRows)\n const viewportStart = viewportStartRef.current\n\n function insertText(text: string): void {\n setValue(value.slice(0, cursor) + text + value.slice(cursor))\n setCursor(cursor + text.length)\n }\n\n function handleReturn(): void {\n if (cursor > 0 && value[cursor - 1] === '\\\\') {\n // Trailing-backslash convention: swap it for a literal newline instead of submitting.\n setValue(value.slice(0, cursor - 1) + '\\n' + value.slice(cursor))\n return\n }\n if (value.length === 0) return\n const submitted = value\n if (promptLabel !== undefined) {\n onSubmitPrompt(submitted)\n } else {\n onSubmitChat(submitted)\n setHistory([...history, submitted])\n }\n setValue('')\n setCursor(0)\n setHistoryIndex(null)\n setPendingDraft('')\n }\n\n function recallHistory(index: number): void {\n const entry = history[index]!\n setHistoryIndex(index)\n setValue(entry)\n setCursor(entry.length)\n }\n\n function handleUp(): void {\n if (cursorRow > 0) {\n setCursor(rowColToOffset(rows, cursorRow - 1, cursorCol))\n return\n }\n if (promptLabel !== undefined || history.length === 0) return\n if (historyIndex === null) {\n setPendingDraft(value)\n recallHistory(history.length - 1)\n return\n }\n if (historyIndex > 0) recallHistory(historyIndex - 1)\n }\n\n function handleDown(): void {\n if (cursorRow < rows.length - 1) {\n setCursor(rowColToOffset(rows, cursorRow + 1, cursorCol))\n return\n }\n if (promptLabel !== undefined || historyIndex === null) return\n if (historyIndex < history.length - 1) {\n recallHistory(historyIndex + 1)\n return\n }\n setHistoryIndex(null)\n setValue(pendingDraft)\n setCursor(pendingDraft.length)\n }\n\n usePaste(\n (text) => {\n insertText(text.replace(/\\r\\n?/g, '\\n'))\n },\n { isActive },\n )\n\n useInput(\n (input, key) => {\n if (key.upArrow) return handleUp()\n if (key.downArrow) return handleDown()\n if (key.leftArrow) return setCursor(Math.max(0, cursor - 1))\n if (key.rightArrow) return setCursor(Math.min(value.length, cursor + 1))\n if (key.home) return setCursor(homeOffset(value, cursor))\n if (key.end) return setCursor(endOffset(value, cursor))\n if (key.backspace) {\n if (cursor === 0) return\n setValue(value.slice(0, cursor - 1) + value.slice(cursor))\n setCursor(cursor - 1)\n return\n }\n if (key.delete) {\n setValue(value.slice(0, cursor) + value.slice(cursor + 1))\n return\n }\n if (key.return) return handleReturn()\n if (key.ctrl || key.meta || key.tab || key.escape || key.pageUp || key.pageDown) return\n if (input.length > 0) insertText(input)\n },\n { isActive },\n )\n\n const visibleRows = rows.slice(viewportStart, viewportStart + maxRows)\n\n return (\n <Box flexDirection=\"column\">\n {promptLabel !== undefined && (\n <Text bold color=\"yellow\">\n {promptLabel}\n </Text>\n )}\n <Box borderStyle=\"round\" borderColor={promptLabel !== undefined ? 'yellow' : 'cyan'} flexDirection=\"column\" paddingX={1}>\n {promptLabel === undefined && value.length === 0 ? (\n <Text dimColor>{placeholder}</Text>\n ) : (\n visibleRows.map((row, i) => {\n const absoluteRow = viewportStart + i\n if (absoluteRow !== cursorRow) {\n return <Text key={absoluteRow}>{row.text.length > 0 ? row.text : ' '}</Text>\n }\n const before = row.text.slice(0, cursorCol)\n const atCursor = row.text[cursorCol] ?? ' '\n const after = row.text.slice(cursorCol + 1)\n return (\n <Text key={absoluteRow}>\n {before}\n <Text inverse>{atCursor}</Text>\n {after}\n </Text>\n )\n })\n )}\n </Box>\n </Box>\n )\n}\n","import { useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport type { SelectOption } from './cli.js'\n\nexport interface SelectPromptProps {\n /** The question text, rendered the same bold-yellow way `TuiInput`'s own `promptLabel` renders a pending askYesNo/askLine question. */\n question: string\n /** Rendered in order, top to bottom — the highlighted (arrow-key-selected) option starts at index 0. Each option's `key` also doubles as its single-keystroke shortcut. */\n options: SelectOption[]\n /** Called once, with the chosen option's `key` — either Enter on the highlighted row, or a direct keystroke matching an option's `key`. */\n onSubmit: (key: string) => void\n isActive?: boolean\n}\n\n/**\n * Phase 7 of the internal plan: an arrow-key + numbered/shortcut-key\n * selector, replacing free-text `y`/`N` typed into the same box used for chat (the report's\n * finding — Codex/Claude Code both use a dedicated selector for this). Deliberately a standalone\n * component rather than a mode bolted onto `TuiInput`: `TuiInput` is a general-purpose free-text\n * editor (word-wrap, cursor movement, history recall) that has no notion of a fixed option list,\n * and grafting one on would tangle two unrelated input models together for no shared benefit — the\n * two components share only the surrounding visual grammar (bold label above a round-bordered\n * box), which each renders independently.\n */\nexport function SelectPrompt(props: SelectPromptProps): React.JSX.Element {\n const { question, options, onSubmit, isActive = true } = props\n const [highlighted, setHighlighted] = useState(0)\n\n useInput(\n (input, key) => {\n if (key.upArrow) {\n setHighlighted((h) => (h - 1 + options.length) % options.length)\n return\n }\n if (key.downArrow) {\n setHighlighted((h) => (h + 1) % options.length)\n return\n }\n if (key.return) {\n onSubmit(options[highlighted]!.key)\n return\n }\n // A direct shortcut keystroke (e.g. 'y'/'a'/'n') submits immediately without needing Enter\n // first — matches Codex/Claude Code's own selector, where the per-option key is a shortcut,\n // not just a label.\n const matched = options.find((option) => option.key.toLowerCase() === input.toLowerCase())\n if (matched) onSubmit(matched.key)\n },\n { isActive },\n )\n\n return (\n <Box flexDirection=\"column\">\n <Text bold color=\"yellow\">\n {question}\n </Text>\n <Box borderStyle=\"round\" borderColor=\"yellow\" flexDirection=\"column\" paddingX={1}>\n {options.map((option, i) => (\n <Text key={option.key} inverse={i === highlighted}>\n {i === highlighted ? '› ' : ' '}[{option.key}] {option.label}\n </Text>\n ))}\n </Box>\n </Box>\n )\n}\n","import type { Box, VizNode } from './types.js'\n\n/**\n * Keyboard navigation over the plan graph (section 5.4). Same behaviour as `referenceNavigator` in\n * testkit/nav-oracles.ts (copied: production code does not import the kit); a differential test keeps them equal.\n * Pure: no I/O. Read-only: it only moves a selection.\n */\n\nexport type NavKey = 'up' | 'down' | 'left' | 'right' | 'tab' | 'shiftTab'\n\nexport interface NavModel {\n ids: string[]\n taskOrder: string[]\n /** Box centre x and top y; rank is decided by y (equal y = same rank). */\n x: Record<string, number>\n y: Record<string, number>\n deps: Record<string, string[]>\n dependents: Record<string, string[]>\n}\n\nexport interface NavState {\n cur: string\n lastKey?: NavKey\n /** For a repeated vertical key: the node the cycling started from. */\n lastFrom?: string\n k: number\n}\n\nexport interface Navigator {\n start(model: NavModel, id: string): NavState\n press(model: NavModel, state: NavState, key: NavKey): NavState\n}\n\nexport function navModelFrom(nodes: readonly VizNode[], boxes: readonly Box[]): NavModel {\n const byId = new Map(boxes.map((b) => [b.id, b]))\n const ids = nodes.map((n) => n.id).filter((id) => byId.has(id))\n const dependents: Record<string, string[]> = Object.fromEntries(ids.map((id) => [id, []]))\n for (const n of nodes) if (byId.has(n.id)) for (const d of n.deps) if (dependents[d]) dependents[d].push(n.id)\n return {\n ids,\n taskOrder: ids,\n x: Object.fromEntries(ids.map((id) => [id, byId.get(id)!.x + byId.get(id)!.w / 2])),\n y: Object.fromEntries(ids.map((id) => [id, byId.get(id)!.y])),\n deps: Object.fromEntries(nodes.map((n) => [n.id, n.deps.filter((d) => byId.has(d))])),\n dependents,\n }\n}\n\nconst cmp = (a: string, b: string): number => (a < b ? -1 : a > b ? 1 : 0)\nconst byX = (m: NavModel, ids: readonly string[]): string[] => [...ids].sort((a, b) => m.x[a] - m.x[b] || cmp(a, b))\n\nexport const planNavigator: Navigator = {\n start: (_m, id) => ({ cur: id, k: 0 }),\n press(m, st, key) {\n if (key === 'tab' || key === 'shiftTab') {\n const n = m.taskOrder.length\n if (!n) return st\n const i = m.taskOrder.indexOf(st.cur)\n return { cur: m.taskOrder[(i + (key === 'tab' ? 1 : -1) + n) % n], k: 0 }\n }\n if (key === 'up' || key === 'down') {\n const origin = st.lastKey === key && st.lastFrom !== undefined ? st.lastFrom : st.cur\n const cands = byX(m, (key === 'up' ? m.deps[origin] : m.dependents[origin]) ?? [])\n if (!cands.length) return st\n const nearest = [...cands].sort((a, b) => Math.abs(m.x[a] - m.x[origin]) - Math.abs(m.x[b] - m.x[origin]) || cmp(a, b))[0]\n const k = st.lastKey === key ? (st.k + 1) % cands.length : 0\n return { cur: cands[(cands.indexOf(nearest) + k) % cands.length], lastKey: key, lastFrom: origin, k }\n }\n const rank = byX(m, m.ids.filter((id) => m.y[id] === m.y[st.cur]))\n const i = rank.indexOf(st.cur)\n if (i < 0) return st\n return { cur: rank[(i + (key === 'left' ? -1 : 1) + rank.length) % rank.length], lastKey: key, k: 0 }\n },\n}\n","import type { Box } from './types.js'\n\nexport interface Viewport {\n left: number\n top: number\n width: number\n height: number\n}\n\n/**\n * Keeps the selected box fully visible when it fits, never leaves the diagram and never exceeds the terminal.\n * Scrolls the minimum amount from the previous viewport so the picture does not jump while navigating.\n * Same behaviour as `followSelection` in testkit/nav-oracles.ts (copied: production code does not import the kit).\n */\nexport function followSelection(prev: Viewport, box: Box, grid: { width: number; height: number }, term: { cols: number; rows: number }): Viewport {\n const width = Math.min(term.cols, grid.width)\n const height = Math.min(term.rows, grid.height)\n const fit = (start: number, size: number, bStart: number, bSize: number, total: number): number => {\n let s = start\n if (bStart < s) s = bStart\n if (bStart + bSize > s + size) s = bStart + bSize - size\n return Math.max(0, Math.min(s, total - size))\n }\n return { width, height, left: fit(prev.left, width, box.x, box.w, grid.width), top: fit(prev.top, height, box.y, box.h, grid.height) }\n}\n\n/** Which edges of the diagram lie beyond the viewport, for scroll indicators. */\nexport function scrollIndicators(v: Viewport, grid: { width: number; height: number }): { up: boolean; down: boolean; left: boolean; right: boolean } {\n return { up: v.top > 0, down: v.top + v.height < grid.height, left: v.left > 0, right: v.left + v.width < grid.width }\n}\n","import type { VizNode } from './types.js'\n\nconst STATUS_WORD: Record<VizNode['status'], string> = {\n pending: 'pending', ready: 'ready to run', running: 'running', done: 'done', failed: 'failed',\n awaiting_user: 'waiting for you', awaiting_input: 'blocked, waiting for input', cancelled: 'cancelled',\n}\n\n/** Wraps `text` to `width` columns on spaces; a word longer than the width is hard-split. */\nfunction wrap(text: string, width: number): string[] {\n const out: string[] = []\n let line = ''\n for (const word of text.split(/\\s+/).filter(Boolean)) {\n let w = word\n while (w.length > width) {\n if (line) { out.push(line); line = '' }\n out.push(w.slice(0, width)); w = w.slice(width)\n }\n if (!line) line = w\n else if (line.length + 1 + w.length <= width) line += ` ${w}`\n else { out.push(line); line = w }\n }\n if (line) out.push(line)\n return out\n}\n\n/** The detail drawer's text for one node: full (unshortened) label, status, dependencies and dependents. Pure. */\nexport function planDetailLines(nodes: readonly VizNode[], id: string | undefined, width: number): string[] {\n const node = nodes.find((n) => n.id === id)\n if (!node) return ['No task selected.']\n const w = Math.max(10, width)\n const name = (i: string): string => nodes.find((n) => n.id === i)?.id ?? i\n const dependents = nodes.filter((n) => n.deps.includes(node.id)).map((n) => n.id)\n return [\n ...wrap(node.id, w),\n '',\n ...wrap(node.label, w),\n '',\n `Status: ${STATUS_WORD[node.status] ?? node.status}`,\n ...wrap(`Depends on: ${node.deps.length ? node.deps.map(name).join(', ') : 'nothing'}`, w),\n ...wrap(`Needed by: ${dependents.length ? dependents.join(', ') : 'nothing'}`, w),\n ]\n}\n","import { useMemo, useRef, useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { renderPlan, toLines } from './plan-viz/plan-raster.js'\nimport { navModelFrom, planNavigator, type NavKey, type NavState } from './plan-viz/plan-nav.js'\nimport { followSelection, scrollIndicators, type Viewport } from './plan-viz/plan-viewport.js'\nimport { planDetailLines } from './plan-viz/plan-detail-lines.js'\nimport type { VizNode } from './plan-viz/types.js'\n\n/** Width at which the detail drawer docks to the right instead of being toggled. */\nexport const DRAWER_DOCK_COLUMNS = 120\nconst DRAWER_WIDTH = 36\n\nexport interface PlanGraphPaneProps {\n nodes: readonly VizNode[]\n columns: number\n rows: number\n /** False while an approval prompt owns the keyboard: the pane stays drawn but ignores keys. */\n active?: boolean\n color?: boolean\n ascii?: boolean\n onClose: () => void\n}\n\n/**\n * Read-only plan graph pane (plans/plan_visualization_plan.html, R2). Keys: arrows (or [ ]) move along edges and ranks, j/k and PgUp/PgDn scroll the detail drawer,\n * Tab/Shift+Tab walk task order, Enter or d toggles the detail drawer below 120 columns, q or Esc closes.\n * No key edits anything: the plan changes only through the approval gate.\n */\nexport function PlanGraphPane({ nodes, columns, rows, active = true, color = true, ascii = false, onClose }: PlanGraphPaneProps): React.JSX.Element {\n const docked = columns >= DRAWER_DOCK_COLUMNS\n const [drawerOpen, setDrawerOpen] = useState(false)\n const showDrawer = docked || drawerOpen\n const graphCols = showDrawer ? Math.max(20, columns - DRAWER_WIDTH - 1) : columns\n const graphRows = Math.max(3, rows - 2)\n\n const [nav, setNav] = useState<NavState | undefined>(undefined)\n const lastIndex = useRef(0)\n const viewport = useRef<Viewport>({ left: 0, top: 0, width: 0, height: 0 })\n\n // Layout is independent of the selection (boxes never move), so the model comes from an unselected render.\n const base = useMemo(() => renderPlan(nodes, { maxCols: graphCols, ascii, color: false }), [nodes, graphCols, ascii])\n const model = useMemo(() => (base.ok ? navModelFrom(nodes, base.boxes) : undefined), [nodes, base])\n\n // The selection survives updates; if its node disappeared, fall back to the node now at the same position (clamped).\n let selectedId: string | undefined\n if (model && model.ids.length) {\n if (nav && model.ids.includes(nav.cur)) selectedId = nav.cur\n else selectedId = model.taskOrder[Math.min(lastIndex.current, model.taskOrder.length - 1)]\n }\n if (model && selectedId) lastIndex.current = model.taskOrder.indexOf(selectedId)\n\n // Drawer scrolling: the offset belongs to one selected node, so selecting another starts it back at the top.\n const detail = useMemo(() => planDetailLines(nodes, selectedId, DRAWER_WIDTH - 2), [nodes, selectedId])\n const [scroll, setScroll] = useState<{ id: string | undefined; offset: number }>({ id: undefined, offset: 0 })\n const drawerRows = graphRows\n const maxScroll = Math.max(0, detail.length - drawerRows)\n const drawerOffset = scroll.id === selectedId ? Math.min(scroll.offset, maxScroll) : 0\n const scrollDrawer = (delta: number): void => setScroll({ id: selectedId, offset: Math.max(0, Math.min(maxScroll, drawerOffset + delta)) })\n\n useInput(\n (input, key) => {\n if (key.escape || input === 'q') return onClose()\n if (key.return || input === 'd') return setDrawerOpen((open) => !open)\n if (showDrawer) {\n if (input === 'j') return scrollDrawer(1)\n if (input === 'k') return scrollDrawer(-1)\n if (key.pageDown) return scrollDrawer(drawerRows)\n if (key.pageUp) return scrollDrawer(-drawerRows)\n }\n if (!model || !selectedId) return\n // [ and ] are kept from the git view as aliases of up/down (repeat to cycle the other dependencies/dependents).\n const k: NavKey | undefined = key.upArrow || input === '[' ? 'up' : key.downArrow || input === ']' ? 'down' : key.leftArrow ? 'left' : key.rightArrow ? 'right' : key.tab ? (key.shift ? 'shiftTab' : 'tab') : undefined\n if (!k) return\n const from: NavState = nav && nav.cur === selectedId ? nav : planNavigator.start(model, selectedId)\n setNav(planNavigator.press(model, from, k))\n },\n { isActive: active },\n )\n\n if (!base.ok || !model) {\n return (\n <Box flexDirection=\"column\" height={rows}>\n <Text>Plan graph unavailable: {base.ok ? 'nothing to draw' : base.message}</Text>\n <Text dimColor>q / Esc closes</Text>\n </Box>\n )\n }\n\n const r = renderPlan(nodes, { maxCols: graphCols, ascii, color, selectedId })\n if (!r.ok) return <Text>Plan graph unavailable: {r.message}</Text>\n const box = r.boxes.find((b) => b.id === selectedId)\n const vp = box ? followSelection(viewport.current, box, r, { cols: graphCols, rows: graphRows }) : { left: 0, top: 0, width: Math.min(graphCols, r.width), height: Math.min(graphRows, r.height) }\n viewport.current = vp\n const lines = toLines(r.cells, r.styles, [vp.top, vp.top + vp.height], [vp.left, vp.left + vp.width])\n const more = scrollIndicators(vp, r)\n const arrows = `${more.up ? '↑' : ' '}${more.down ? '↓' : ' '}${more.left ? '←' : ' '}${more.right ? '→' : ' '}`\n const done = nodes.filter((n) => n.status === 'done').length\n\n return (\n <Box flexDirection=\"column\" height={rows}>\n <Text bold>\n {`Plan graph — ${done}/${nodes.length} done `}<Text dimColor>{arrows}</Text>\n </Text>\n <Box flexDirection=\"row\" flexGrow={1}>\n <Box flexDirection=\"column\" width={graphCols}>\n {lines.map((line, i) => (\n <Text key={i} wrap=\"truncate\">{line.length ? line : ' '}</Text>\n ))}\n </Box>\n {showDrawer && (\n <Box flexDirection=\"column\" width={DRAWER_WIDTH + 1} paddingLeft={1} borderStyle=\"single\" borderTop={false} borderBottom={false} borderRight={false}>\n {detail.slice(drawerOffset, drawerOffset + drawerRows).map((line, i) => (\n <Text key={i} wrap=\"truncate\">{line.length ? line : ' '}</Text>\n ))}\n </Box>\n )}\n </Box>\n <Text dimColor>{docked ? '↑↓←→ move · Tab next · j/k PgUp/PgDn scroll details · q close' : '↑↓←→ move · Tab next · Enter details · q close'}</Text>\n </Box>\n )\n}\n","import { Text } from 'ink'\nimport { DIFF_INDENT } from './diff-format.js'\n\n/**\n * Minimal inline/line-level markdown rendering for the TUI's committed scrollback — not a full\n * CommonMark parser, just the subset the live terminal comparison\n * (`reports/cli_appearance_comparison_2026-09-17.md`) actually caught printing as literal\n * characters in a real plan-mode reply: `## Headers`, `- [ ]`/`- [x]` checkboxes, `**bold**`, and\n * `` `code spans` ``. Each `LogLine.text` here is already exactly one already-split line (see\n * `EventLogBridge.handleEvent`'s `displayText.split('\\n')`), so this operates line-at-a-time —\n * no cross-line constructs (fenced code blocks, tables, nested lists) are attempted.\n *\n * Phase 5 follow-up: a write/edit confirmation's diff (`diff-format.ts`'s `formatWriteDiff`) is\n * plain, uncolored text — it's an ordinary assistant-reply string consumed by both the plain\n * readline CLI and this TUI, so `diff-format.ts` can't embed ANSI itself (see its own\n * `DIFF_INDENT` comment). Recognized here the same way headers/checkboxes are: by shape, not by a\n * `LogLine.kind` of its own.\n */\n\nconst HEADER_RE = /^(#{1,6})\\s+(.*)$/\nconst CHECKBOX_RE = /^(\\s*[-*]\\s)\\[([ xX])\\]\\s+(.*)$/\n// diff-format.ts's gutter format: a right-aligned line number, a separator space, then the\n// unified-diff sign character (`+`/`-`/a plain space for context) immediately against content.\nconst DIFF_LINE_RE = /^(\\s*\\d+) ([+\\- ])(.*)$/\nconst INLINE_TOKEN_RE = /\\*\\*(.+?)\\*\\*|`([^`]+)`/g\n// Mirrors the user side's own \"you>\"/\"> \" convention (readline's prompt, the persistent\n// approval-record line) with a marker on the assistant's side too, on ordinary prose lines only —\n// a header/checkbox/diff line already carries its own leading glyph, and doubling up would read\n// as two markers stacked on one line.\nconst ASSISTANT_BULLET = '- '\n\n/**\n * Recognizes one line of `diff-format.ts`'s output by shape: `DIFF_INDENT` followed by a\n * right-aligned line number and a unified-diff sign character. That combination — a fixed\n * two-space indent no ordinary assistant prose produces, paired with a line-number gutter no\n * markdown construct produces — doesn't occur in natural writing (a markdown bullet is always\n * `- text`, dash *then* a space with no number in front, which `CHECKBOX_RE`/plain rendering\n * already own), so this can't misfire on a real bullet list. Context lines (sign is a plain\n * space) are recognized too, with `color: undefined` — they still need to short-circuit\n * `renderMarkdownLine`'s plain-text fallback below (which would otherwise prepend `ASSISTANT_BULLET`\n * to them as if they were ordinary prose), they just aren't colored the way a real diff tool\n * doesn't color its context lines either.\n */\nexport function matchDiffLine(text: string): { content: string; color: 'green' | 'red' | undefined } | undefined {\n if (!text.startsWith(DIFF_INDENT)) return undefined\n const rest = text.slice(DIFF_INDENT.length)\n const match = DIFF_LINE_RE.exec(rest)\n if (!match) return undefined\n const sign = match[2]\n return { content: rest, color: sign === '+' ? 'green' : sign === '-' ? 'red' : undefined }\n}\n\n/**\n * Renders one line as colored diff content if `matchDiffLine` recognizes it, otherwise\n * `undefined` so the caller falls back to its own plain/markdown rendering. Used by\n * `renderMarkdownLine` below (the `'assistant'`-kind, post-write confirmation) and by\n * `tui-app.tsx`'s `'system'`-kind branch (the pre-approval preview) — the two `LogLine` kinds a\n * `formatWriteDiff()` string actually reaches, per `classifyLineKind`.\n */\nexport function renderDiffLine(text: string, key: React.Key): React.JSX.Element | undefined {\n const diffLine = matchDiffLine(text)\n if (!diffLine) return undefined\n return (\n <Text key={key} color={diffLine.color}>\n {DIFF_INDENT}\n {diffLine.content}\n </Text>\n )\n}\n\nconst NEEDS_APPROVAL_RE = /^(\\[needs approval[^\\]]*\\])(.*)$/\n\n/**\n * Colors the `[needs approval — write/shell command/…]`/`[needs approval — HIGH/…]` tag\n * `cli.ts` prints ahead of every approval prompt (see its own `console.log` call sites) yellow —\n * the same \"worth your attention\" color `StatusLine`'s own `⚠`-prefixed indicators already use —\n * leaving the reason text after it in the default color. This line is `'system'`-classified (see\n * `classifyLineKind`), not `'assistant'`, so it's checked from `tui-app.tsx`'s own `'system'`\n * branch rather than from `renderMarkdownLine`.\n */\nexport function renderNeedsApprovalLine(text: string, key: React.Key): React.JSX.Element | undefined {\n const match = NEEDS_APPROVAL_RE.exec(text)\n if (!match) return undefined\n return (\n <Text key={key}>\n <Text color=\"yellow\">{match[1]}</Text>\n {match[2]}\n </Text>\n )\n}\n\n/** Splits a line's text on `**bold**`/`` `code` `` tokens into plain strings and styled `<Text>` spans, preserving order. */\nfunction renderInlineSegments(text: string): React.ReactNode[] {\n const segments: React.ReactNode[] = []\n let lastIndex = 0\n let key = 0\n INLINE_TOKEN_RE.lastIndex = 0\n let match: RegExpExecArray | null\n while ((match = INLINE_TOKEN_RE.exec(text)) !== null) {\n if (match.index > lastIndex) segments.push(text.slice(lastIndex, match.index))\n if (match[1] !== undefined) {\n segments.push(\n <Text key={key++} bold>\n {match[1]}\n </Text>,\n )\n } else if (match[2] !== undefined) {\n segments.push(\n <Text key={key++} color=\"cyan\">\n {match[2]}\n </Text>,\n )\n }\n lastIndex = INLINE_TOKEN_RE.lastIndex\n }\n if (lastIndex < text.length || segments.length === 0) segments.push(text.slice(lastIndex))\n return segments\n}\n\n/**\n * Renders one committed line of assistant/system text, recognizing a leading `#`/`##`/… header or\n * `- [ ]`/`- [x]` checkbox before falling back to plain inline-styled text. `key` is the React key\n * for the returned element (the caller already has a per-line index from `<Static>`'s own render\n * prop — see `tui-app.tsx`'s `LogLineText`). `continuation` is `LogLine.continuation` — true for\n * every line of a multi-line reply after the first, which suppresses `ASSISTANT_BULLET` (the\n * marker belongs once at the front of the whole message, not on every wrapped line).\n */\nexport function renderMarkdownLine(text: string, key: React.Key, continuation = false): React.JSX.Element {\n const diffElement = renderDiffLine(text, key)\n if (diffElement) return diffElement\n const headerMatch = HEADER_RE.exec(text)\n if (headerMatch) {\n return (\n <Text key={key} bold underline>\n {renderInlineSegments(headerMatch[2]!)}\n </Text>\n )\n }\n const checkboxMatch = CHECKBOX_RE.exec(text)\n if (checkboxMatch) {\n const checked = checkboxMatch[2]!.toLowerCase() === 'x'\n return (\n <Text key={key}>\n {checkboxMatch[1]}\n {checked ? '☑' : '☐'} {renderInlineSegments(checkboxMatch[3]!)}\n </Text>\n )\n }\n // Blank lines (paragraph breaks within a multi-line reply) stay bare — a lone \"- \" with\n // nothing after it would read as a stray bullet, not a paragraph break.\n if (text.length === 0) return <Text key={key}> </Text>\n return (\n <Text key={key}>\n {continuation ? '' : ASSISTANT_BULLET}\n {renderInlineSegments(text)}\n </Text>\n )\n}\n","import { Readable, Writable } from 'node:stream'\nimport { useCallback, useEffect, useRef, useState, useSyncExternalStore } from 'react'\nimport { Box, Static, Text, render as inkRender, useInput, useWindowSize } from 'ink'\nimport { runCli, type CliInstance, type RunCliOptions, type SelectOption } from './cli.js'\nimport { startCapture, type CaptureEvent } from './tui-output-capture.js'\nimport { TuiInput } from './tui-input.js'\nimport { SelectPrompt } from './ink-select-prompt.js'\nimport { ICONS, PLAN_LINE_PREFIX } from './cli-icons.js'\nimport { PlanGraphPane } from './PlanGraphPane.js'\nimport type { VizNode } from './plan-viz/types.js'\nimport { renderMarkdownLine, renderDiffLine, renderNeedsApprovalLine } from './markdown-line.js'\n\n// \"Indent everything coming from the assistant\" — a uniform left margin on every assistant-reply\n// line, separate from (and additive with) formatWriteDiff()'s own DIFF_INDENT baked into diff\n// content: a diff line already starts with two of its own spaces, so wrapping it in this padding\n// too makes it sit visibly deeper than plain prose in the same reply — \"the code\" (diff/code\n// content) reads as more indented than ordinary text without a separate, parallel indent scheme.\nconst ASSISTANT_INDENT_WIDTH = 2\n\n/**\n * A minimal pub/sub store, one per piece of state the Ink tree needs — deliberately not React\n * state, because the values that drive it arrive from outside React entirely: `startCapture`\n * (Phase 1) calls its `onEvent` callback synchronously from a monkey-patched `console.log`/\n * `process.stdout.write`, and `askYesNo`/`askLine` (Decision 1's override seam) are plain\n * functions handed to `runCli()` before any component has mounted. `useSyncExternalStore` is the\n * React-correct way to subscribe a component to state that's mutated from outside React's own\n * render cycle, without the chicken-and-egg problem of needing a `setState` that only exists\n * after the first render.\n */\ninterface Store<T> {\n subscribe: (listener: () => void) => () => void\n getSnapshot: () => T\n}\n\nfunction useStore<T>(store: Store<T>): T {\n return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot)\n}\n\n/**\n * Which visual style a committed scrollback line gets (this task's ask: \"different formats for\n * user text vs aielia response vs tool call details\"). `'margin'` is a blank spacer line between\n * turns, not a real writer's output — kept as its own kind rather than reusing `'system'` so\n * rendering never has to guess a blank line's intent from empty text alone.\n */\nexport type LineKind = 'user' | 'assistant' | 'tool' | 'error' | 'system' | 'margin' | 'plan' | 'approval'\n\nexport interface LogLine {\n text: string\n kind: LineKind\n /**\n * True for every split line of a multi-line assistant reply after the first one (see\n * `handleEvent`'s own `displayText.split('\\n')`) — `markdown-line.tsx`'s `ASSISTANT_BULLET`\n * belongs once at the front of the whole message, not on every wrapped line (found live: a\n * two-line write confirmation, \"Wrote X.\"/\"apple\", rendered as two separate bulleted lines\n * instead of one statement). Unset (falsy) for a single-line reply or any other kind, so the\n * bullet still shows by default wherever this flag isn't threaded through.\n */\n continuation?: boolean\n}\n\nexport interface TuiLogState {\n /** Every permanently-committed scrollback line, oldest first — fed straight into `<Static>`. */\n lines: LogLine[]\n /** `writeProgress`'s current `\\r`-overwritten line — shown in the transient region, never committed. */\n progressText: string\n /** `writeToken`'s not-yet-newline-terminated streamed reply text — shown in the transient region until the next committed-line event closes it out. */\n transientText: string\n /**\n * True from `beginTurn()` (called right after a chat line or a resolved approval/clarification\n * prompt is submitted) until the first `CaptureEvent` of that turn actually lands. Covers the\n * gap the comparison report flagged — \"nothing shows between hitting enter and the first\n * output\" — that neither `progressText` nor `transientText` can, since both start empty and\n * only a genuine harness event ever populates them.\n */\n waitingForOutput: boolean\n}\n\nconst EMPTY_LOG: TuiLogState = { lines: [], progressText: '', transientText: '', waitingForOutput: false }\n\n/** `writeToolStep`'s own indent+glyph (see cli.ts's `toolStepIcon`/cli-icons.ts) — matched after trimming so a `'line'` event's kind survives cli.ts adding/removing leading whitespace. Three possible glyphs since cli-icons.ts distinguishes a routine tool step, one that's itself proposing a state-changing action, and one `tool-policy.ts` denied before it executed — all three still classify as the same `'tool'` LineKind here, just with a different leading icon. */\nconst TOOL_STEP_PREFIXES = [ICONS.toolStep, ICONS.proposalStep, ICONS.deniedStep]\n/** cli.ts hardcodes this literal label for every assistant-reply write, streamed or not (`writeToken`'s opening write and the non-streaming `console.log` fallback both start with it) — see this class's `handleEvent` doc comment for why streaming state alone isn't a reliable-enough signal on its own. */\nconst ASSISTANT_REPLY_PREFIX = 'Aielia>'\n\n/** Classifies one already-merged, already-stream-tagged committed block into a `LineKind` — shared by every resulting split line, since a multi-line reply/tool/system block reads as one unit, not a mix of styles line to line. */\nfunction classifyLineKind(mergedText: string, streamedReplyWasOpen: boolean, stream: 'stdout' | 'stderr'): LineKind {\n if (stream === 'stderr') return 'error'\n if (mergedText.trimStart().startsWith(PLAN_LINE_PREFIX)) return 'plan'\n // Streaming state alone would miss the non-streaming `console.log('\\nAielia>…')` fallback path\n // (harness_d2's non-one-loop path) that never opens a `'token'` stream at all — checked first\n // since it's the more specific, unambiguous signal when it does apply.\n if (streamedReplyWasOpen || mergedText.trimStart().startsWith(ASSISTANT_REPLY_PREFIX)) return 'assistant'\n if (TOOL_STEP_PREFIXES.some((prefix) => mergedText.trimStart().startsWith(prefix))) return 'tool'\n return 'system'\n}\n\n/** Strips {@link PLAN_LINE_PREFIX} the same way `stripAssistantLabel` strips `ASSISTANT_REPLY_PREFIX` — the marker exists only for `classifyLineKind` to match on, never shown. */\nfunction stripPlanLabel(text: string): string {\n return text.replace(new RegExp(`^\\\\s*${PLAN_LINE_PREFIX}\\\\s*`), '')\n}\n\n/**\n * Strips cli.ts's hardcoded \"Aielia>\" reply label (plus a leading blank-line artifact — the\n * streaming path's opening write is literally `'\\nAielia> '`, and `\\s*` below eats that leading\n * `\\n` along with the label) so the assistant's reply displays as just its own text, no label —\n * explicit feedback that spelling out \"you\"/\"Aielia\" wasn't wanted (see `LogLineText`'s doc\n * comment for the full styling rationale). Applied to already-classified `'assistant'` text only;\n * never called on anything else, so it can't accidentally eat real reply content that happens to\n * start the same way.\n */\nfunction stripAssistantLabel(text: string): string {\n return text.replace(/^\\s*Aielia>\\s?/, '')\n}\n\n/**\n * Classifies and accumulates `CaptureEvent`s (Phase 1) into the three regions Phase 3's layout\n * needs: permanent scrollback, the transient progress line, and the transient in-progress\n * streamed reply. A `'line'` event closes out whatever streamed-token text is currently pending\n * (see `cli.ts`'s `writeToken`/`handleTurn`: a streamed reply is one or more raw `'token'` writes\n * followed by exactly one final `'line'` write for the trailing hint text) — merging the two\n * before committing is what turns \"Hi the|re!\\n\\n\" (streamed \"Hi the\" + committed \"re!\\n\\n\") into\n * one correct committed line instead of two garbled ones.\n */\nexport class EventLogBridge implements Store<TuiLogState> {\n private lines: LogLine[] = []\n private progressText = ''\n private transientText = ''\n private waitingForOutput = false\n private snapshot: TuiLogState = EMPTY_LOG\n private listeners = new Set<() => void>()\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n getSnapshot = (): TuiLogState => this.snapshot\n\n private commit(): void {\n this.snapshot = { lines: this.lines, progressText: this.progressText, transientText: this.transientText, waitingForOutput: this.waitingForOutput }\n for (const listener of this.listeners) listener()\n }\n\n /** Marks the start of a turn's wait for its first output (see `TuiLogState.waitingForOutput`'s doc comment) — called by `TuiApp` right after a chat line or resolved prompt answer is submitted. */\n beginTurn(): void {\n this.waitingForOutput = true\n this.commit()\n }\n\n /**\n * A blank spacer line (\"some margins between different conversations\", later extended to \"at\n * least one line spacing between the user and system messages\") — called from three places in\n * `handleSubmitChat` (never from a resolved approval/clarification prompt answer, which stays\n * visually grouped with the turn it belongs to): once before a new turn's echo (separating it\n * from the previous turn's reply) and once right after it (separating the echo from whatever\n * system/tool/assistant output follows). A no-op on an empty log or if the last line is already\n * a margin, so calling it from both of those spots back-to-back across turns can't stack blank\n * lines — the \"before next turn\" and \"after this turn\" calls collapse into the same one line.\n */\n pushTurnMargin(): void {\n const last = this.lines[this.lines.length - 1]\n if (!last || last.kind === 'margin') return\n this.lines = [...this.lines, { text: '', kind: 'margin' }]\n this.commit()\n }\n\n /** Records a line the user just submitted (chat or a resolved prompt answer) into permanent scrollback — mirrors a real terminal's own line-echo, which the inert (non-TTY) input stream this shell uses never produces on its own. `prefix` is `''` for an ordinary chat line (no \"you>\" label — see `LogLineText`'s doc comment, kind `'user'`) and `'> '` for a resolved prompt answer (kind `'approval'`, its own box color — see `LogLineText` — distinct from a real chat message even though both are the user's own input), which keeps its prefix since it's answering a question printed just above it, not identifying whose turn it is. */\n pushEchoLine(prefix: string, text: string): void {\n this.lines = [...this.lines, { text: `${prefix}${text}`, kind: prefix === '' ? 'user' : 'approval' }]\n this.commit()\n }\n\n handleEvent(event: CaptureEvent): void {\n // Any real event closes the \"waiting for first output\" gap — a spinner covering it makes no\n // sense once the turn has actually started producing something.\n this.waitingForOutput = false\n if (event.type === 'progress') {\n this.progressText = event.text\n this.commit()\n return\n }\n if (event.type === 'token') {\n this.transientText += event.text\n this.commit()\n return\n }\n const streamedReplyWasOpen = this.transientText.length > 0\n const merged = this.transientText + event.lines.join('\\n')\n const kind = classifyLineKind(merged, streamedReplyWasOpen, event.stream)\n const displayText = kind === 'assistant' ? stripAssistantLabel(merged) : kind === 'plan' ? stripPlanLabel(merged) : merged\n // 'plan' stays one un-split LogLine (see PlanBox's doc comment) — every other kind splits\n // per-line since their own rendering (plain/dim/red text, or per-line markdown) doesn't need\n // the whole block intact the way a single bordered box does.\n this.lines =\n kind === 'plan'\n ? [...this.lines, { text: displayText, kind }]\n : // continuation is only meaningful (and only set) for 'assistant' — every other kind's\n // LogLine stays a bare { text, kind } so existing exact-shape equality checks elsewhere\n // (classifyLineKind's own test coverage) don't have to account for an unused field.\n [...this.lines, ...displayText.split('\\n').map((text, i) => (kind === 'assistant' ? { text, kind, continuation: i > 0 } : { text, kind }))]\n this.transientText = ''\n // Any committed line means the progress indicator that was describing the still-in-flight\n // turn is now stale — cli.ts's own clearProgress() deliberately skips itself once a reply has\n // streamed (real-terminal reasoning: clearing would \\r back onto the tail of the just-printed\n // reply and blank it — see handleTurn's `if (!streamedAnyTokens) clearProgress()` comment).\n // That reasoning doesn't apply here: the TUI's progress line lives in its own state-driven\n // transient region, decoupled from real cursor position, so nothing needs to \"not corrupt\" —\n // it just needs to stop displaying a step counter for a turn that has already finished.\n // Clearing on every commit is safe even when cli.ts's own clearProgress() *did* already fire\n // (writeToolStep's case): progressText is already '' then, so this is a no-op.\n this.progressText = ''\n this.commit()\n // A blank line after the assistant's own reply, mirroring the one already pushed after the\n // user's echo (pushTurnMargin's own no-op-on-consecutive-margin guard means this and the next\n // turn's pre-echo pushTurnMargin() call collapse into the same single line, never stacking).\n if (kind === 'assistant') this.pushTurnMargin()\n }\n}\n\nexport type PendingPrompt = { question: string; options?: SelectOption[] } | undefined\n\n/**\n * Bridges `runCli()`'s `askYesNo`/`askLine`/`askSelect` override seam (Decision 1, extended by\n * Phase 7 for the structured selector) to Ink: each call parks a resolver and exposes the pending\n * question (and, for `askSelect`, its option list) to the component tree via `getSnapshot()`,\n * instead of the original `rl.question`-based implementation. `TuiInput`'s own `promptLabel` prop\n * (Phase 2) renders a plain-text pending question; `TuiApp` (below) renders `SelectPrompt` instead\n * whenever `pending.options` is set — this class only needs to supply the question (and options)\n * and resolve the answer, the same way for either shape.\n */\nexport class PromptBridge implements Store<PendingPrompt> {\n private pending: PendingPrompt\n private resolve: ((answer: string) => void) | undefined\n private listeners = new Set<() => void>()\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n getSnapshot = (): PendingPrompt => this.pending\n\n private ask(question: string, options?: SelectOption[]): Promise<string> {\n return new Promise((resolve) => {\n this.pending = { question, options }\n this.resolve = resolve\n for (const listener of this.listeners) listener()\n })\n }\n\n /** Matches `RunCliOptions.askYesNo`'s exact parsing convention (`answer.trim().toLowerCase().startsWith('y')`) — same fail-closed shape, just answered via the Ink prompt instead of `rl.question`. */\n askYesNo = (question: string): Promise<boolean> => this.ask(question).then((answer) => answer.trim().toLowerCase().startsWith('y'))\n\n askLine = (question: string): Promise<string> => this.ask(question)\n\n /** Matches `RunCliOptions.askSelect`'s contract exactly — resolves with the chosen `SelectOption.key`, answered via `SelectPrompt` instead of `rl.question`. */\n askSelect = (question: string, options: SelectOption[]): Promise<string> => this.ask(question, options)\n\n submit(answer: string): void {\n const resolve = this.resolve\n this.pending = undefined\n this.resolve = undefined\n for (const listener of this.listeners) listener()\n resolve?.(answer)\n }\n}\n\n/** The status line's short indicator list (Phase 3 step 5) — polled from `CliInstance.getStatusIndicators()` after every dispatched line, since plan/spend-cap state only changes as a side effect of a turn. */\nexport class StatusBridge implements Store<string[]> {\n private indicators: string[] = []\n private listeners = new Set<() => void>()\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n getSnapshot = (): string[] => this.indicators\n\n set(indicators: string[]): void {\n this.indicators = indicators\n for (const listener of this.listeners) listener()\n }\n}\n\n/** Escape sequences for the terminal's alternate screen. */\nconst ALT_SCREEN_ON = '\\x1b[?1049h'\nconst ALT_SCREEN_OFF = '\\x1b[?1049l'\n/** Pause between the empty frame and the screen switch (verified in the S2 probe) so Ink's last chat frame is erased before the switch. */\nconst ALT_SCREEN_SETTLE_MS = 80\n/** At most one pane re-render per interval, however fast progress updates arrive. */\nconst PLAN_GRAPH_MIN_RENDER_MS = 100\n\nexport interface PlanGraphView {\n /** 'chat': normal UI. 'blank': the empty frame bracketing a screen switch. 'pane': the full-screen plan graph. */\n mode: 'chat' | 'blank' | 'pane'\n nodes: VizNode[]\n}\n\n/**\n * State for the full-screen plan graph pane (read-only; plans/plan_visualization_plan.html, R2). Same pub/sub shape as\n * `StatusBridge`. `writeRaw` must be the UNPATCHED stdout write so `startCapture` never turns the screen-switch escape\n * sequences into log lines. Opening/closing brackets the switch with an empty Ink frame: empty frame, wait, switch, pane.\n */\nexport class PlanGraphBridge implements Store<PlanGraphView> {\n private view: PlanGraphView = { mode: 'chat', nodes: [] }\n private listeners = new Set<() => void>()\n private timer: ReturnType<typeof setTimeout> | undefined\n private pendingNodes: VizNode[] | undefined\n private transition: Promise<void> = Promise.resolve()\n\n constructor(private readonly writeRaw: (chunk: string) => void, private readonly settleMs = ALT_SCREEN_SETTLE_MS, private readonly minRenderMs = PLAN_GRAPH_MIN_RENDER_MS) {}\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n getSnapshot = (): PlanGraphView => this.view\n\n isOpen(): boolean {\n return this.view.mode !== 'chat'\n }\n\n private set(view: PlanGraphView): void {\n this.view = view\n for (const listener of this.listeners) listener()\n }\n\n private sleep(): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, this.settleMs))\n }\n\n open(nodes: VizNode[]): Promise<void> {\n this.transition = this.transition.then(async () => {\n if (this.view.mode !== 'chat') {\n this.update(nodes)\n return\n }\n this.set({ mode: 'blank', nodes })\n await this.sleep()\n this.writeRaw(ALT_SCREEN_ON)\n this.set({ mode: 'pane', nodes: this.pendingNodes ?? nodes })\n this.pendingNodes = undefined\n })\n return this.transition\n }\n\n close(): Promise<void> {\n this.transition = this.transition.then(async () => {\n if (this.view.mode === 'chat') return\n this.clearTimer()\n this.set({ mode: 'blank', nodes: this.view.nodes })\n await this.sleep()\n this.writeRaw(ALT_SCREEN_OFF)\n this.set({ mode: 'chat', nodes: [] })\n })\n return this.transition\n }\n\n /** Synchronous leave for process exit: restores the main screen without waiting. */\n restore(): void {\n this.clearTimer()\n if (this.view.mode === 'pane') this.writeRaw(ALT_SCREEN_OFF)\n this.view = { mode: 'chat', nodes: [] }\n }\n\n /** Throttled node update: the first goes through at once, later ones coalesce to the newest within `minRenderMs`. Identical content is ignored. */\n update(nodes: VizNode[]): void {\n if (this.view.mode === 'chat') return\n if (this.view.mode === 'blank') {\n this.pendingNodes = nodes\n return\n }\n if (this.timer) {\n this.pendingNodes = nodes\n return\n }\n this.apply(nodes)\n this.timer = setTimeout(() => this.flush(), this.minRenderMs)\n }\n\n private apply(nodes: VizNode[]): void {\n if (this.view.mode !== 'pane' || JSON.stringify(nodes) === JSON.stringify(this.view.nodes)) return\n this.set({ mode: 'pane', nodes })\n }\n\n private flush(): void {\n this.timer = undefined\n const next = this.pendingNodes\n this.pendingNodes = undefined\n if (next) {\n this.apply(next)\n this.timer = setTimeout(() => this.flush(), this.minRenderMs)\n }\n }\n\n private clearTimer(): void {\n if (this.timer) clearTimeout(this.timer)\n this.timer = undefined\n this.pendingNodes = undefined\n }\n}\n\n/** Stand-in store for when no plan graph bridge is wired: always the chat view. */\nconst NO_PLAN_GRAPH: Store<PlanGraphView> = { subscribe: () => () => {}, getSnapshot: (() => { const v: PlanGraphView = { mode: 'chat', nodes: [] }; return () => v })() }\n\nexport interface TuiAppProps {\n eventLog: EventLogBridge\n prompt: PromptBridge\n status: StatusBridge\n /** Optional: absent means the plan graph pane can never open (flag-off wiring). */\n planGraph?: PlanGraphBridge\n onSubmitChat: (line: string) => void\n onExit: () => void\n /** Overrides the live terminal width for tests — same seam `TuiInput` already accepts. */\n columns?: number\n}\n\n/**\n * One committed scrollback line, styled by `LineKind` (this task's ask: \"different formats for\n * user text vs aielia response vs tool call details\"). Several earlier versions are worth\n * recording since they were each explicit feedback, not guesses: (1) colored 'user'/'assistant'\n * cyan/green — rejected as arbitrary; (2) dropped color for bold-only-on-the-label-line —\n * rejected in favor of dropping the \"you>\"/\"Aielia>\" labels themselves entirely (see\n * `stripAssistantLabel` — the label text no longer exists in `'assistant'`-kind text at all, and\n * `'user'`-kind text is pushed with no prefix in chat mode — `EventLogBridge.pushEchoLine`'s doc\n * comment); (3) a dark gray foreground, then (4) a dark gray *background* highlight band instead\n * (through three shades — plain 'gray', then near-black, then a midpoint — before the whole\n * background-band approach was set aside); (5) **current**: a bordered `<Box>` around the user's\n * own text, echoing `TuiInput`'s own box chrome (round border, `paddingX={1}`) but in a muted gray\n * border instead of the live input box's cyan, so a past message reads as \"the same kind of\n * thing, already said\" rather than \"still being typed.\" Ink's `Box` fills the parent's width by\n * default (no explicit `width` set, same as `TuiInput`'s own box), so this box's border\n * automatically spans the same width as the live input box below it with no manual padding\n * needed. Position — the old label used to carry — is now conveyed by `pushTurnMargin`'s\n * blank-line spacing instead. `'tool'`/`'error'` still use dim/red respectively — not what the\n * feedback was about (a functional error signal, not a stylistic user/assistant split). A\n * `'margin'` line renders a bare blank row (a real space, not empty — Ink/terminal rows with\n * truly empty text can collapse to zero width, the same reasoning `TuiInput` already applies to\n * its own empty draft rows).\n */\n/**\n * `width` is passed explicitly (from `TuiApp`'s own `columns ?? windowSize.columns`, the same\n * value the separator and `TuiInput`'s box use) rather than relying on `Box`'s usual\n * fill-parent-width default — confirmed live that a `<Static>` item's `Box` sizes to its content\n * instead of stretching, unlike a `Box` in the main persistent tree (`TuiInput`'s own), so without\n * this every message box shrink-wrapped to its own text length instead of matching the input box.\n */\nfunction UserMessageBox({ text, width, borderColor = 'gray' }: { text: string; width: number; borderColor?: string }): React.JSX.Element {\n return (\n <Box borderStyle=\"round\" borderColor={borderColor} flexDirection=\"column\" paddingX={1} width={width}>\n {text.split('\\n').map((line, i) => (\n <Text key={i}>{line.length > 0 ? line : ' '}</Text>\n ))}\n </Box>\n )\n}\n\n/**\n * Phase 6 of the CLI formatting plan (\"distinct plan-mode UI\") — a dedicated bordered widget for\n * `cli.ts`'s `printPlan()` status block, the same \"one box around the whole multi-line text\"\n * pattern {@link UserMessageBox} already uses (see `EventLogBridge.handleEvent`'s `kind === 'plan'`\n * branch, which — unlike every other kind — pushes the whole block as one un-split `LogLine` so\n * this component receives it intact instead of one already-split line at a time). Cyan border\n * distinguishes it from the user box's gray without introducing a new color for its own sake — cyan\n * is `TuiInput`'s own live-input border color, so a plan box reads as \"structured, awaiting your\n * attention\" the same way the input box does. The header line (`Plan: … % complete`, always first —\n * see `formatPlanProgress`/`printPlan`) is bolded for a lightweight title, without the separate\n * \"Updated Plan\" banner line Codex uses, since `formatPlanProgress`'s own first line already serves\n * that purpose and a second title would be redundant.\n */\nfunction PlanBox({ text, width }: { text: string; width: number }): React.JSX.Element {\n return (\n <Box borderStyle=\"round\" borderColor=\"cyan\" flexDirection=\"column\" paddingX={1} width={width}>\n {text.split('\\n').map((line, i) => (\n <Text key={i} bold={i === 0}>{line.length > 0 ? line : ' '}</Text>\n ))}\n </Box>\n )\n}\n\nfunction LogLineText({ line, width }: { line: LogLine; width: number }): React.JSX.Element {\n switch (line.kind) {\n case 'user':\n return <UserMessageBox text={line.text} width={width} />\n // A resolved approval/clarification-prompt answer (pushEchoLine's '> ' prefix case) — same\n // box shape as a real chat message, but a distinct light-green border (was reusing 'user''s\n // gray, indistinguishable from an actual message the person typed) so a permission decision\n // reads as its own kind of record, not \"something I said.\"\n case 'approval':\n return <UserMessageBox text={line.text} width={width} borderColor=\"greenBright\" />\n // Basic markdown (headers, `- [ ]`/`- [x]` checkboxes, **bold**, `code`) rendered for the\n // assistant's own reply text only (see markdown-line.tsx) — system output (banner, /help,\n // /status, etc.) is left as plain text since it's already deterministic, controlled prose\n // with no markdown of its own to render.\n case 'assistant':\n return (\n <Box paddingLeft={ASSISTANT_INDENT_WIDTH}>\n {renderMarkdownLine(line.text, 0, line.continuation)}\n </Box>\n )\n case 'plan':\n return <PlanBox text={line.text} width={width} />\n case 'system':\n // The pre-approval write/edit preview (\"[needs approval — write] Proposes writing to\n // X:\\n<diff>\") is system-classified, not assistant-classified — this is the other\n // LogLine kind a formatWriteDiff() string reaches (see renderDiffLine's own doc comment).\n // Checked before renderNeedsApprovalLine since the two can never both match the same line\n // (a diff line never starts with the literal \"[needs approval\" tag) — order is arbitrary.\n return renderDiffLine(line.text, 0) ?? renderNeedsApprovalLine(line.text, 0) ?? <Text>{line.text}</Text>\n case 'tool':\n return <Text dimColor>{line.text}</Text>\n case 'error':\n return <Text color=\"red\">{line.text}</Text>\n case 'margin':\n return <Text> </Text>\n }\n}\n\n/** Braille frames for {@link Spinner} — the same cycle `cli-spinner`/`ora`'s default `dots` style uses, hand-rolled here since no spinner dependency exists in this package (Ink-native, no new dependency, matching this phase's other items). */\nconst SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']\n/** How often the spinner advances a frame — fast enough to read as \"alive,\" slow enough not to flood a redraw-on-every-frame terminal. */\nconst SPINNER_INTERVAL_MS = 80\n\n/**\n * A minimal thinking/loading indicator for the gap between hitting Enter and the first real\n * output (report finding: \"nothing shows... no spinner, no status line, unlike Pi/Codex\") — shown\n * only while `TuiLogState.waitingForOutput` is true and cleared automatically the instant any real\n * `CaptureEvent` lands (see `EventLogBridge.handleEvent`), so it can never linger over genuine\n * progress/streamed output.\n */\nfunction Spinner(): React.JSX.Element {\n const [frame, setFrame] = useState(0)\n useEffect(() => {\n const id = setInterval(() => setFrame((f) => (f + 1) % SPINNER_FRAMES.length), SPINNER_INTERVAL_MS)\n return () => clearInterval(id)\n }, [])\n return (\n <Text dimColor>\n {SPINNER_FRAMES[frame]} Thinking…\n </Text>\n )\n}\n\n/** The reserved status line (Phase 3 step 5) — each indicator its own `<Text>` so a `⚠`-prefixed warning (currently only the dangerouslySkipPermissions notice) can stand out in yellow while the rest stay dim, without string-parsing a single joined line. */\nfunction StatusLine({ indicators }: { indicators: string[] }): React.JSX.Element {\n return (\n <Text>\n {indicators.map((indicator, index) => (\n <Text key={indicator}>\n {index > 0 ? ' ' : ''}\n <Text color={indicator.startsWith('⚠') ? 'yellow' : undefined} dimColor={!indicator.startsWith('⚠')}>\n {indicator}\n </Text>\n </Text>\n ))}\n </Text>\n )\n}\n\n/**\n * The top-level Ink app (Phase 3): a `<Static>` scrollback of every committed line, a transient\n * region for the in-progress progress line/streamed reply, a one-row separator, the Phase 2\n * multiline input box pinned to the bottom, and a reserved status line under that. Composition\n * only — command parsing/dispatch stays entirely inside `cli.ts`'s `dispatchLine()` (Decision 1),\n * and this component never re-implements it.\n */\nexport function TuiApp(props: TuiAppProps): React.JSX.Element {\n const { eventLog, prompt, status, planGraph, onSubmitChat, onExit, columns } = props\n const log = useStore(eventLog)\n const pending = useStore(prompt)\n const statusIndicators = useStore(status)\n const windowSize = useWindowSize()\n const width = columns ?? windowSize.columns\n const graphView = useStore(planGraph ?? NO_PLAN_GRAPH)\n // While the pane (or its screen-switch frame) is up, no new scrollback may print: Static output would land on the alternate screen.\n const frozenLines = useRef(0)\n if (graphView.mode === 'chat') frozenLines.current = log.lines.length\n\n // Always active, regardless of chat-vs-prompt mode — Ctrl+C must exit either way, unlike\n // TuiInput's own useInput, which deliberately ignores every ctrl/meta/tab/escape key (its\n // job is draft editing, not process control).\n useInput((input, key) => {\n if (key.ctrl && input === 'c') onExit()\n })\n\n const handleSubmitChat = useCallback(\n (line: string) => {\n // Only a genuine new chat turn gets blank margins around it — a resolved\n // approval/clarification prompt answer (handleSubmitPrompt below) stays visually grouped\n // with the turn it belongs to, not treated as a turn of its own. No \"you>\" prefix (see\n // `LogLineText`'s doc comment) — the gray shading plus these margins on both sides do the\n // job the label used to.\n eventLog.pushTurnMargin()\n eventLog.pushEchoLine('', line)\n eventLog.pushTurnMargin()\n eventLog.beginTurn()\n onSubmitChat(line)\n },\n [eventLog, onSubmitChat],\n )\n\n const handleSubmitPrompt = useCallback(\n (line: string) => {\n // Commit the question alongside its answer (Phase 2) — `pending.question` only lives in\n // `PromptBridge` state and disappears the instant `prompt.submit()` clears it below, so\n // without this the resolved prompt (e.g. \"Run this command? (y/N)\") would vanish from\n // scrollback entirely, leaving only the bare answer echo with no context for what it\n // answered. Falls back to the bare answer if `pending` is somehow already cleared (Enter\n // fired with no promptLabel), which shouldn't happen since `TuiInput` only calls\n // `onSubmitPrompt` when `promptLabel` is set.\n // `.trimEnd()` — every real `askYesNo`/`askLine` question text ends with a trailing space\n // (e.g. `'Proceed? (y/N) '`), a holdover from the old `rl.question()` flow where the answer\n // was typed inline right after it; here it'd otherwise double up with the arrow's own\n // leading space.\n // For an `askSelect` answer, `line` is the chosen option's raw `key` (e.g. `'a'`) — look up\n // its `label` so the persistent record reads \"Proceed? → Yes, don't ask again this session\"\n // rather than the bare, less legible key.\n const displayAnswer = pending?.options?.find((option) => option.key === line)?.label ?? line\n eventLog.pushEchoLine('> ', pending?.question !== undefined ? `${pending.question.trimEnd()} → ${displayAnswer}` : line)\n eventLog.beginTurn()\n prompt.submit(line)\n },\n [eventLog, prompt, pending],\n )\n\n const closePane = useCallback(() => {\n void planGraph?.close()\n }, [planGraph])\n\n const hasTransient = log.progressText.length > 0 || log.transientText.length > 0\n const showSpinner = log.waitingForOutput && !hasTransient\n\n const staticItems = graphView.mode === 'chat' ? log.lines : log.lines.slice(0, frozenLines.current)\n // One row short of the viewport on purpose: Ink treats a frame as fullscreen at height >= rows, and leaving fullscreen emits\n // clearTerminal (which includes ESC[3J, erasing the user's scrollback). Never reaching that height keeps close lossless.\n const paneRows = Math.max(3, (windowSize.rows ?? 24) - 1)\n if (graphView.mode !== 'chat') {\n // An approval prompt takes priority: the pane stays drawn but stops reading keys, and the prompt is shown below it.\n const promptRows = pending ? Math.min(10, Math.floor(paneRows / 2)) : 0\n return (\n <Box flexDirection=\"column\">\n <Static items={staticItems}>{(line, index) => <LogLineText key={index} line={line} width={width} />}</Static>\n {graphView.mode === 'pane' && (\n <PlanGraphPane nodes={graphView.nodes} columns={width} rows={paneRows - promptRows} active={!pending} color={!process.env.NO_COLOR} onClose={closePane} />\n )}\n {graphView.mode === 'pane' && pending?.options && <SelectPrompt question={pending.question} options={pending.options} onSubmit={handleSubmitPrompt} />}\n {graphView.mode === 'pane' && pending && !pending.options && (\n <TuiInput promptLabel={pending.question} onSubmitChat={handleSubmitChat} onSubmitPrompt={handleSubmitPrompt} columns={columns} />\n )}\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\">\n <Static items={staticItems}>{(line, index) => <LogLineText key={index} line={line} width={width} />}</Static>\n {showSpinner && <Spinner />}\n {hasTransient && (\n <Box flexDirection=\"column\">\n {log.progressText.length > 0 && <Text dimColor>{log.progressText}</Text>}\n {log.transientText.length > 0 && <Text>{stripAssistantLabel(log.transientText)}</Text>}\n </Box>\n )}\n <Text dimColor>{'─'.repeat(Math.max(1, width))}</Text>\n {pending?.options ? (\n <SelectPrompt question={pending.question} options={pending.options} onSubmit={handleSubmitPrompt} />\n ) : (\n <TuiInput\n promptLabel={pending?.question}\n onSubmitChat={handleSubmitChat}\n onSubmitPrompt={handleSubmitPrompt}\n columns={columns}\n />\n )}\n <StatusLine indicators={statusIndicators} />\n </Box>\n )\n}\n\n/**\n * `startCapture` (Phase 1) monkey-patches the *global* `process.stdout.write` so it can intercept\n * `cli.ts`'s ~108 existing call sites without touching each one (Decision 1) — but Ink itself also\n * paints every frame through that same global `process.stdout.write` by default. Left unpatched,\n * Ink's own frame writes would loop back through `startCapture`'s `onEvent` into\n * `EventLogBridge.handleEvent`/`commit()`, which notifies the very `TuiApp` subscribers that\n * caused the frame in the first place — triggering another render, another write, another event,\n * forever, until React's update-depth guard throws `Maximum update depth exceeded`. This wraps the\n * *real* `process.stdout` in a `Proxy` that resolves every property normally (so `columns`,\n * `isTTY`, `on('resize', …)` etc. all still hit the genuine stream, preserving correct `this`\n * binding for its internal EventEmitter state) except `write`, which is pinned to the pristine\n * function captured *before* `startCapture` ran — so Ink paints the real terminal directly and\n * never re-enters the capture/bridge loop.\n */\nfunction createUnpatchedStdout(originalWrite: NodeJS.WriteStream['write']): NodeJS.WriteStream {\n return new Proxy(process.stdout, {\n get(target, prop, receiver) {\n if (prop === 'write') return originalWrite.bind(target)\n const value = Reflect.get(target, prop, receiver)\n return typeof value === 'function' ? value.bind(target) : value\n },\n })\n}\n\n/**\n * Inert stand-ins for `RunCliOptions.input`/`.output`: the Ink shell drives every chat line\n * through `CliInstance.dispatchLine()` and every approval/clarification prompt through\n * `PromptBridge` (Decision 1's override seam), so `runCli()`'s own internal `readline` interface\n * never needs to read real keystrokes or write real prompts — Ink owns the real terminal\n * exclusively (raw mode for keystrokes, direct ANSI writes for frames). Leaving `runCli()`'s\n * `createInterface({ input: process.stdin, output: process.stdout })` default in place here\n * would fight Ink for both: `readline` auto-enables terminal/raw mode whenever its `output` is a\n * TTY, which would race Ink's own `setRawMode` calls on the same `stdin`. Neither stream declares\n * `isTTY`, so `createInterface`'s terminal-mode auto-detection (`Boolean(output.isTTY)`) comes\n * out false and it never tries.\n */\nfunction createInertStreams(): { input: NodeJS.ReadableStream; output: NodeJS.WritableStream } {\n const input = new Readable({ read: () => {} })\n const output = new Writable({\n write: (_chunk, _encoding, callback) => callback(),\n })\n return { input, output }\n}\n\nexport type RunTuiAppOptions = Omit<RunCliOptions, 'askYesNo' | 'askLine' | 'askSelect'>\n\n/**\n * Constructs `runCli()` wired to this file's Ink shell (Phase 4 calls this once, behind the\n * `tuiMode` rollout flag) and renders it. Resolves once the user exits (Ctrl+C — see `TuiApp`'s\n * `onExit`), after the same graceful-exit steps `cli.ts`'s own `rl.on('SIGINT', ...)` handler\n * performs: restore the captured `console`/`process.stdout`, close the underlying `CliInstance`,\n * then exit the process.\n */\nexport async function runTuiApp(options: RunTuiAppOptions = {}): Promise<void> {\n const eventLog = new EventLogBridge()\n const prompt = new PromptBridge()\n const status = new StatusBridge()\n\n // Captured before startCapture patches process.stdout.write — this is the pristine function\n // Ink itself will paint frames through (see createUnpatchedStdout's doc comment above).\n const originalWrite = process.stdout.write.bind(process.stdout)\n\n // Started before runCli() is ever called — runCli() itself prints the startup banner\n // (backend, capabilities, undo-log carryover) via plain console.log, which must land in the\n // Static scrollback like everything else, not leak to the real terminal underneath Ink's frame.\n const restoreCapture = startCapture((event) => eventLog.handleEvent(event))\n // Screen-switch escapes go through the unpatched write, never the captured one (see PlanGraphBridge).\n const planGraph = new PlanGraphBridge((chunk) => void originalWrite(chunk))\n let instanceRef: CliInstance | undefined\n\n let instance: CliInstance\n try {\n const inert = createInertStreams()\n instance = await runCli({\n ...options,\n openPlanGraph: (nodes) => void planGraph.open(nodes),\n onPlanProgress: (tasks) => {\n if (planGraph.isOpen()) void instanceRef?.getPlanGraphNodes(tasks).then((nodes) => nodes && planGraph.update(nodes))\n },\n input: options.input ?? inert.input,\n output: options.output ?? inert.output,\n askYesNo: prompt.askYesNo,\n askLine: prompt.askLine,\n askSelect: prompt.askSelect,\n })\n } catch (err) {\n restoreCapture()\n throw err\n }\n\n instanceRef = instance\n const refreshStatus = async (): Promise<void> => {\n status.set(await instance.getStatusIndicators())\n if (planGraph.isOpen()) {\n const nodes = await instance.getPlanGraphNodes()\n if (nodes) planGraph.update(nodes)\n }\n }\n await refreshStatus()\n\n const handleSubmitChat = (line: string): void => {\n void instance.dispatchLine(line).then(refreshStatus)\n }\n\n let exiting = false\n const exit = (): void => {\n if (exiting) return\n exiting = true\n planGraph.restore()\n restoreCapture()\n instance.close()\n app.unmount()\n process.exit(0)\n }\n\n const app = inkRender(<TuiApp eventLog={eventLog} prompt={prompt} status={status} planGraph={planGraph} onSubmitChat={handleSubmitChat} onExit={exit} />, {\n // Phase 1's startCapture already routes every console.log/process.stdout.write call into\n // eventLog — ink's own patchConsole would double-intercept the same calls with a competing\n // mechanism (writing them above its own Static area independently), not compose with it.\n patchConsole: false,\n exitOnCtrlC: false,\n // Bypass startCapture's patched process.stdout.write for Ink's own frame painting — see\n // createUnpatchedStdout's doc comment for why leaving this as the default (real\n // process.stdout, whose .write is the patched one) causes an infinite render loop.\n stdout: createUnpatchedStdout(originalWrite),\n })\n\n await app.waitUntilExit()\n}\n"],"names":["i","inkRender"],"mappings":"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"}