@24klynx/tui 0.1.2 → 0.1.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["MAX_VISIBLE","MAX_VISIBLE","statusIcon","MAX_VISIBLE","MAX_VISIBLE","MAX_VISIBLE","statusColor","MAX_VISIBLE","MAX_VISIBLE","MAX_VISIBLE","sourceLabel","MAX_VISIBLE","MAX_VISIBLE"],"sources":["../src/theme/theme.ts","../src/renderer/highlight.ts","../src/renderer/emoji.ts","../src/renderer/latex.ts","../src/renderer/markdown.ts","../src/components/ChatLog.ts","../src/renderer/frame-limiter.ts","../src/components/VimStatusBar.ts","../src/components/SuggestionsOverlay.ts","../src/components/InputFooter.ts","../src/components/InputBox.ts","../src/components/StatusBar.ts","../src/components/NotificationCenter.ts","../src/components/PermissionRequest.ts","../src/components/Dialog.ts","../src/components/SessionPicker.ts","../src/components/HelpModal.ts","../src/components/CommandPalette.ts","../src/components/ModelPicker.ts","../src/components/ConfigMenu.ts","../src/components/ThemePicker.ts","../src/components/ConfirmDialog.ts","../src/components/InputPrompt.ts","../src/components/DoctorPanel.ts","../src/components/FilePicker.ts","../src/components/StashPicker.ts","../src/components/DiffViewer.ts","../src/components/SnapshotBrowser.ts","../src/components/TasksPanel.ts","../src/components/SkillPicker.ts","../src/components/McpPanel.ts","../src/components/PluginPanel.ts","../src/components/SkillPanel.ts","../src/components/ContextPanel.ts","../src/components/UsagePanel.ts","../src/screens/WelcomeScreen.ts","../src/hooks/useTerminalSize.ts","../src/hooks/useScroll.ts","../src/views/stack.ts","../src/app.ts","../src/components/ChatView.ts","../src/components/ToolRenderer.ts","../src/components/Mascot.ts","../src/hooks/useInput.ts","../src/renderer/sanitize.ts","../src/keybindings/keybindings.ts","../src/components/ErrorBoundary.ts","../src/components/AlternateScreen.ts"],"sourcesContent":["/**\n * ThemeProvider — semantic color tokens and theme switching.\n *\n * Six built‑in themes: dark, light, catppuccin, monokai, solarized, dracula.\n * Auto mode detects NO_COLOR and COLORTERM to pick a sensible default.\n */\n\nimport type { TuiTheme, ThemeName } from \"../types.js\";\n\n// ── Theme definitions ────────────────────────────────\n\nconst THEMES: Record<ThemeName, TuiTheme> = {\n dark: {\n name: \"dark\",\n colors: {\n background: \"#1a1b26\",\n foreground: \"#c0caf5\",\n border: \"#3b4261\",\n accent: \"#7aa2f7\",\n error: \"#f7768e\",\n warning: \"#e0af68\",\n success: \"#9ece6a\",\n dimmed: \"#565f89\",\n highlight: \"#2f334d\",\n inputBackground: \"#24283b\",\n inputForeground: \"#c0caf5\",\n toolUse: \"#7dcfff\",\n toolResult: \"#9d7cd8\",\n },\n },\n light: {\n name: \"light\",\n colors: {\n background: \"#f5f5f5\",\n foreground: \"#1a1b26\",\n border: \"#d0d0d0\",\n accent: \"#2e6edf\",\n error: \"#d73a49\",\n warning: \"#bf8700\",\n success: \"#22863a\",\n dimmed: \"#8b949e\",\n highlight: \"#e8e8e8\",\n inputBackground: \"#ffffff\",\n inputForeground: \"#1a1b26\",\n toolUse: \"#005cc5\",\n toolResult: \"#6f42c1\",\n },\n },\n catppuccin: {\n name: \"catppuccin\",\n colors: {\n background: \"#1e1e2e\",\n foreground: \"#cdd6f4\",\n border: \"#45475a\",\n accent: \"#89b4fa\",\n error: \"#f38ba8\",\n warning: \"#fab387\",\n success: \"#a6e3a1\",\n dimmed: \"#6c7086\",\n highlight: \"#313244\",\n inputBackground: \"#313244\",\n inputForeground: \"#cdd6f4\",\n toolUse: \"#89dceb\",\n toolResult: \"#cba6f7\",\n },\n },\n monokai: {\n name: \"monokai\",\n colors: {\n background: \"#272822\",\n foreground: \"#f8f8f2\",\n border: \"#49483e\",\n accent: \"#a6e22e\",\n error: \"#f92672\",\n warning: \"#e6db74\",\n success: \"#a6e22e\",\n dimmed: \"#75715e\",\n highlight: \"#3e3d32\",\n inputBackground: \"#3e3d32\",\n inputForeground: \"#f8f8f2\",\n toolUse: \"#66d9ef\",\n toolResult: \"#ae81ff\",\n },\n },\n solarized: {\n name: \"solarized\",\n colors: {\n background: \"#002b36\",\n foreground: \"#839496\",\n border: \"#073642\",\n accent: \"#268bd2\",\n error: \"#dc322f\",\n warning: \"#b58900\",\n success: \"#859900\",\n dimmed: \"#586e75\",\n highlight: \"#073642\",\n inputBackground: \"#073642\",\n inputForeground: \"#839496\",\n toolUse: \"#2aa198\",\n toolResult: \"#6c71c4\",\n },\n },\n dracula: {\n name: \"dracula\",\n colors: {\n background: \"#282a36\",\n foreground: \"#f8f8f2\",\n border: \"#44475a\",\n accent: \"#bd93f9\",\n error: \"#ff5555\",\n warning: \"#ffb86c\",\n success: \"#50fa7b\",\n dimmed: \"#6272a4\",\n highlight: \"#44475a\",\n inputBackground: \"#44475a\",\n inputForeground: \"#f8f8f2\",\n toolUse: \"#8be9fd\",\n toolResult: \"#bd93f9\",\n },\n },\n};\n\n// ── Current theme (mutable singleton) ─────────────────\n\nlet _current: ThemeName = \"dark\";\n\n/** Detect the best default theme from environment variables. */\nfunction detectTheme(): ThemeName {\n if (process.env.NO_COLOR) return \"light\";\n if (process.env.LYNX_THEME && THEMES[process.env.LYNX_THEME as ThemeName]) {\n return process.env.LYNX_THEME as ThemeName;\n }\n return \"dark\";\n}\n\n// ── Public API ───────────────────────────────────────\n\n/** Initialize the theme system. Call once at startup. */\nexport function initTheme(): void {\n _current = detectTheme();\n}\n\n/** Get the current theme. */\nexport function getTheme(): TuiTheme {\n return THEMES[_current];\n}\n\n/** Switch to a different theme. */\nexport function setTheme(name: ThemeName): void {\n if (THEMES[name]) {\n _current = name;\n }\n}\n\n/** Get a specific color from the current theme. */\nexport function color(name: string): string {\n const theme = THEMES[_current];\n return theme.colors[name] ?? theme.colors.foreground;\n}\n\n/** List all available theme names. */\nexport function listThemes(): ThemeName[] {\n return Object.keys(THEMES) as ThemeName[];\n}\n","/**\n * Syntax highlighting — regex-based colourisation for 8 language families.\n *\n * Each language family defines keyword lists, comment patterns, and\n * string/number regexes. The highlighter emits an array of styled spans\n * that can be rendered as Ink Text elements.\n *\n * Design:\n * - Tokenize each line independently (no cross-line state needed for\n * regex-based highlighting).\n * - Comments are detected first (highest priority), then strings,\n * then keywords, then numbers.\n * - Fallback: plain text with no highlighting.\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface HighlightSpan {\n text: string;\n kind: \"keyword\" | \"string\" | \"number\" | \"comment\" | \"type\" | \"plain\";\n}\n\n/** Per-language configuration for the tokenizer. */\ninterface LangConfig {\n /** Words that should be highlighted as keywords (bold). */\n keywords: ReadonlySet<string>;\n /** Words that should be highlighted as types (italic). */\n types?: ReadonlySet<string>;\n /** Regex patterns for single-line comments (applied first). */\n lineComments?: RegExp[];\n /** Block comment delimiters (e.g. `/*` and `*​/` for JS/TS/Go/Rust). */\n blockComment?: { start: string; end: string };\n /** Delimiter pairs for string detection. */\n stringDelimiters?: string[];\n}\n\n// ── Language definitions ──────────────────────────────\n\n/** JavaScript / TypeScript keywords. */\nconst JS_KEYWORDS = new Set([\n \"if\",\n \"else\",\n \"for\",\n \"while\",\n \"do\",\n \"switch\",\n \"case\",\n \"break\",\n \"continue\",\n \"return\",\n \"function\",\n \"const\",\n \"let\",\n \"var\",\n \"import\",\n \"export\",\n \"default\",\n \"from\",\n \"as\",\n \"class\",\n \"interface\",\n \"type\",\n \"enum\",\n \"extends\",\n \"implements\",\n \"abstract\",\n \"async\",\n \"await\",\n \"try\",\n \"catch\",\n \"throw\",\n \"finally\",\n \"new\",\n \"this\",\n \"super\",\n \"true\",\n \"false\",\n \"null\",\n \"undefined\",\n \"void\",\n \"typeof\",\n \"instanceof\",\n \"in\",\n \"of\",\n \"yield\",\n \"debugger\",\n \"delete\",\n \"static\",\n \"private\",\n \"public\",\n \"protected\",\n \"readonly\",\n \"implements\",\n \"namespace\",\n \"module\",\n \"require\",\n \"keyof\",\n \"infer\",\n \"never\",\n \"unknown\",\n]);\n\nconst JS_TYPES = new Set([\n \"string\",\n \"number\",\n \"boolean\",\n \"any\",\n \"void\",\n \"never\",\n \"unknown\",\n \"Array\",\n \"Map\",\n \"Set\",\n \"Promise\",\n \"Object\",\n \"Function\",\n \"Symbol\",\n \"Record\",\n \"Partial\",\n \"Required\",\n \"Pick\",\n \"Omit\",\n \"ReturnType\",\n \"Parameters\",\n]);\n\n/** Python keywords. */\nconst PY_KEYWORDS = new Set([\n \"if\",\n \"elif\",\n \"else\",\n \"for\",\n \"while\",\n \"break\",\n \"continue\",\n \"return\",\n \"yield\",\n \"def\",\n \"class\",\n \"import\",\n \"from\",\n \"as\",\n \"try\",\n \"except\",\n \"finally\",\n \"raise\",\n \"with\",\n \"pass\",\n \"lambda\",\n \"global\",\n \"nonlocal\",\n \"assert\",\n \"del\",\n \"True\",\n \"False\",\n \"None\",\n \"and\",\n \"or\",\n \"not\",\n \"in\",\n \"is\",\n \"async\",\n \"await\",\n \"self\",\n \"cls\",\n]);\n\n/** Go keywords. */\nconst GO_KEYWORDS = new Set([\n \"if\",\n \"else\",\n \"for\",\n \"range\",\n \"switch\",\n \"case\",\n \"default\",\n \"break\",\n \"continue\",\n \"return\",\n \"func\",\n \"var\",\n \"const\",\n \"type\",\n \"import\",\n \"package\",\n \"struct\",\n \"interface\",\n \"map\",\n \"chan\",\n \"go\",\n \"defer\",\n \"select\",\n \"fallthrough\",\n \"goto\",\n \"true\",\n \"false\",\n \"nil\",\n \"iota\",\n \"string\",\n \"int\",\n \"int8\",\n \"int16\",\n \"int32\",\n \"int64\",\n \"uint\",\n \"uint8\",\n \"uint16\",\n \"uint32\",\n \"uint64\",\n \"float32\",\n \"float64\",\n \"bool\",\n \"byte\",\n \"rune\",\n \"error\",\n]);\n\n/** Rust keywords. */\nconst RUST_KEYWORDS = new Set([\n \"if\",\n \"else\",\n \"for\",\n \"while\",\n \"loop\",\n \"match\",\n \"break\",\n \"continue\",\n \"return\",\n \"fn\",\n \"let\",\n \"mut\",\n \"const\",\n \"static\",\n \"type\",\n \"impl\",\n \"trait\",\n \"struct\",\n \"enum\",\n \"use\",\n \"mod\",\n \"pub\",\n \"crate\",\n \"self\",\n \"super\",\n \"extern\",\n \"unsafe\",\n \"where\",\n \"move\",\n \"async\",\n \"await\",\n \"dyn\",\n \"ref\",\n \"true\",\n \"false\",\n \"None\",\n \"Some\",\n \"Ok\",\n \"Err\",\n \"as\",\n \"in\",\n \"if\",\n \"else\",\n \"Self\",\n \"String\",\n \"Vec\",\n \"Option\",\n \"Result\",\n \"Box\",\n \"Rc\",\n \"Arc\",\n \"Cell\",\n \"RefCell\",\n \"i8\",\n \"i16\",\n \"i32\",\n \"i64\",\n \"i128\",\n \"isize\",\n \"u8\",\n \"u16\",\n \"u32\",\n \"u64\",\n \"u128\",\n \"usize\",\n \"f32\",\n \"f64\",\n \"bool\",\n \"char\",\n]);\n\n/** Shell / Bash keywords and built-ins. */\nconst SH_KEYWORDS = new Set([\n \"if\",\n \"then\",\n \"else\",\n \"elif\",\n \"fi\",\n \"for\",\n \"while\",\n \"do\",\n \"done\",\n \"case\",\n \"esac\",\n \"in\",\n \"select\",\n \"until\",\n \"function\",\n \"return\",\n \"exit\",\n \"break\",\n \"continue\",\n \"export\",\n \"local\",\n \"readonly\",\n \"unset\",\n \"declare\",\n \"typeset\",\n \"echo\",\n \"cd\",\n \"ls\",\n \"pwd\",\n \"cat\",\n \"grep\",\n \"sed\",\n \"awk\",\n \"find\",\n \"source\",\n \"test\",\n \"exec\",\n \"eval\",\n \"set\",\n \"shift\",\n \"trap\",\n \"true\",\n \"false\",\n \"yes\",\n \"no\",\n]);\n\n/** SQL keywords. */\nconst SQL_KEYWORDS = new Set([\n \"SELECT\",\n \"FROM\",\n \"WHERE\",\n \"JOIN\",\n \"LEFT\",\n \"RIGHT\",\n \"INNER\",\n \"OUTER\",\n \"ON\",\n \"INSERT\",\n \"INTO\",\n \"VALUES\",\n \"UPDATE\",\n \"SET\",\n \"DELETE\",\n \"CREATE\",\n \"TABLE\",\n \"ALTER\",\n \"DROP\",\n \"INDEX\",\n \"VIEW\",\n \"TRIGGER\",\n \"PROCEDURE\",\n \"FUNCTION\",\n \"AND\",\n \"OR\",\n \"NOT\",\n \"IN\",\n \"LIKE\",\n \"BETWEEN\",\n \"IS\",\n \"NULL\",\n \"AS\",\n \"DISTINCT\",\n \"GROUP\",\n \"BY\",\n \"ORDER\",\n \"HAVING\",\n \"LIMIT\",\n \"OFFSET\",\n \"UNION\",\n \"ALL\",\n \"EXISTS\",\n \"CASE\",\n \"WHEN\",\n \"THEN\",\n \"ELSE\",\n \"END\",\n \"ASC\",\n \"DESC\",\n \"PRIMARY\",\n \"KEY\",\n \"FOREIGN\",\n \"REFERENCES\",\n \"CONSTRAINT\",\n \"INTEGER\",\n \"TEXT\",\n \"VARCHAR\",\n \"BOOLEAN\",\n \"TIMESTAMP\",\n \"REAL\",\n \"BLOB\",\n \"BEGIN\",\n \"COMMIT\",\n \"ROLLBACK\",\n \"TRANSACTION\",\n \"COUNT\",\n \"SUM\",\n \"AVG\",\n \"MAX\",\n \"MIN\",\n \"COALESCE\",\n]);\n\n/** JSON / YAML / XML — no keywords; relies on string/number detection. */\nconst DATA_KEYWORDS = new Set<string>([\"true\", \"false\", \"null\"]);\nconst YAML_KEYWORDS = new Set<string>([\"true\", \"false\", \"null\", \"yes\", \"no\", \"on\", \"off\"]);\n\n/** CSS / SCSS keywords. */\nconst CSS_KEYWORDS = new Set([\n \"color\",\n \"background\",\n \"border\",\n \"margin\",\n \"padding\",\n \"width\",\n \"height\",\n \"display\",\n \"position\",\n \"top\",\n \"right\",\n \"bottom\",\n \"left\",\n \"font\",\n \"text\",\n \"flex\",\n \"grid\",\n \"align\",\n \"justify\",\n \"overflow\",\n \"opacity\",\n \"z-index\",\n \"transform\",\n \"transition\",\n \"animation\",\n \"box-shadow\",\n \"none\",\n \"auto\",\n \"inherit\",\n \"initial\",\n \"unset\",\n \"block\",\n \"inline\",\n \"flex\",\n \"grid\",\n \"absolute\",\n \"relative\",\n \"fixed\",\n \"sticky\",\n \"px\",\n \"em\",\n \"rem\",\n \"vh\",\n \"vw\",\n \"ch\",\n \"%\",\n \"rgb\",\n \"rgba\",\n \"hsl\",\n \"hsla\",\n \"var\",\n]);\n\n// ── Language family lookup ────────────────────────────\n\n/** Alias map: language tag → lookup key. */\nconst LANG_ALIASES: Record<string, string> = {\n js: \"js\",\n javascript: \"js\",\n mjs: \"js\",\n cjs: \"js\",\n ts: \"ts\",\n typescript: \"ts\",\n tsx: \"ts\",\n py: \"py\",\n python: \"py\",\n python3: \"py\",\n go: \"go\",\n golang: \"go\",\n rs: \"rs\",\n rust: \"rs\",\n sh: \"sh\",\n bash: \"sh\",\n shell: \"sh\",\n zsh: \"sh\",\n sql: \"sql\",\n psql: \"sql\",\n json: \"json\",\n yaml: \"yaml\",\n yml: \"yaml\",\n css: \"css\",\n scss: \"css\",\n less: \"css\",\n};\n\n/** Default line‑comment and string patterns per language family. */\nconst BLOCK_COMMENT_C = { start: \"/*\", end: \"*/\" };\n\nconst JS_CONFIG = {\n keywords: JS_KEYWORDS,\n types: JS_TYPES,\n lineComments: [/\\/\\//],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, `'`, \"`\"],\n};\nconst TS_CONFIG = {\n keywords: JS_KEYWORDS,\n types: JS_TYPES,\n lineComments: [/\\/\\//],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, `'`, \"`\"],\n};\nconst PY_CONFIG = { keywords: PY_KEYWORDS, lineComments: [/#/], stringDelimiters: [`\"`, `'`] };\nconst GO_CONFIG = {\n keywords: GO_KEYWORDS,\n lineComments: [/\\/\\//],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, \"`\"],\n};\nconst RS_CONFIG = {\n keywords: RUST_KEYWORDS,\n lineComments: [/\\/\\//],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, `'`],\n};\nconst SH_CONFIG = { keywords: SH_KEYWORDS, lineComments: [/#/], stringDelimiters: [`\"`, `'`] };\nconst SQL_CONFIG = { keywords: SQL_KEYWORDS, lineComments: [/--/], stringDelimiters: [`'`] };\nconst JSON_CONFIG = { keywords: DATA_KEYWORDS, stringDelimiters: [`\"`] };\nconst YAML_CONFIG = { keywords: YAML_KEYWORDS, lineComments: [/#/], stringDelimiters: [`\"`, `'`] };\nconst CSS_CONFIG = {\n keywords: CSS_KEYWORDS,\n lineComments: [/\\/\\//],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, `'`],\n};\nconst FALLBACK_CONFIG = {\n keywords: JS_KEYWORDS,\n lineComments: [new RegExp(\"//\")],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, `'`, \"`\"],\n};\n\nconst LANG_CONFIGS: Record<string, LangConfig> = {\n js: JS_CONFIG,\n ts: TS_CONFIG,\n py: PY_CONFIG,\n go: GO_CONFIG,\n rs: RS_CONFIG,\n sh: SH_CONFIG,\n sql: SQL_CONFIG,\n json: JSON_CONFIG,\n yaml: YAML_CONFIG,\n css: CSS_CONFIG,\n};\n\n/** Resolve a language tag to its highlight config. */\nfunction getLangConfig(language?: string): LangConfig {\n const key = LANG_ALIASES[(language ?? \"\").toLowerCase()];\n return key ? (LANG_CONFIGS[key] ?? FALLBACK_CONFIG) : FALLBACK_CONFIG;\n}\n\n// ── Tokenizer ─────────────────────────────────────────\n\n/**\n * Tokenize a single line of code into highlight spans.\n *\n * Applies the following precedence (highest first):\n * 1. Block comment continuation/termination\n * 2. Line comments (//, #, --)\n * 3. Strings (quoted)\n * 4. Keywords / types (whole-word match)\n * 5. Numbers (integer, float, hex)\n * 6. Plain text\n *\n * @param line — the line to tokenize\n * @param config — language config\n * @param inBlockComment — true if the previous line left an unclosed block comment\n * @returns spans and whether the line ends inside a block comment\n */\nfunction tokenizeLine(\n line: string,\n config: LangConfig,\n inBlockComment?: boolean,\n): { spans: HighlightSpan[]; inBlockComment: boolean } {\n const spans: HighlightSpan[] = [];\n\n // 1. Handle block comment continuation\n const bc = config.blockComment;\n if (bc) {\n if (inBlockComment) {\n // Inside a continuing block comment — look for end marker\n const endIdx = line.indexOf(bc.end);\n if (endIdx >= 0) {\n spans.push({ text: line.slice(0, endIdx + bc.end.length), kind: \"comment\" });\n // Tokenize the rest normally\n const restSpans = tokenizeLine(line.slice(endIdx + bc.end.length), config, false);\n spans.push(...restSpans.spans);\n return { spans, inBlockComment: false };\n }\n // Entire line is comment\n spans.push({ text: line, kind: \"comment\" });\n return { spans, inBlockComment: true };\n }\n\n // Not currently in block comment — check if one starts on this line\n const startIdx = line.indexOf(bc.start);\n if (startIdx >= 0) {\n const endIdx = line.indexOf(bc.end, startIdx + bc.start.length);\n if (endIdx >= 0) {\n // Full block comment on one line\n if (startIdx > 0) {\n spans.push(...tokenizeLineNoComments(line.slice(0, startIdx), config));\n }\n spans.push({ text: line.slice(startIdx, endIdx + bc.end.length), kind: \"comment\" });\n const restSpan = tokenizeLine(line.slice(endIdx + bc.end.length), config, false);\n spans.push(...restSpan.spans);\n return { spans, inBlockComment: false };\n }\n // Block comment starts but doesn't end on this line\n if (startIdx > 0) {\n spans.push(...tokenizeLineNoComments(line.slice(0, startIdx), config));\n }\n spans.push({ text: line.slice(startIdx), kind: \"comment\" });\n return { spans, inBlockComment: true };\n }\n }\n\n // No block comment state — check for line comments\n if (config.lineComments) {\n for (const commentRe of config.lineComments) {\n const match = commentRe.exec(line);\n if (match) {\n const commentStart = match.index;\n if (commentStart > 0) {\n spans.push(...tokenizeLineNoComments(line.slice(0, commentStart), config));\n }\n spans.push({ text: line.slice(commentStart), kind: \"comment\" });\n return { spans, inBlockComment: false };\n }\n }\n }\n\n spans.push(...tokenizeLineNoComments(line, config));\n return { spans, inBlockComment: false };\n}\n\n/**\n * Result of trying to match a word (keyword or type) at the current position.\n * Returns the new spans and the remainder, or null if no word matched.\n */\ninterface WordMatch {\n spans: HighlightSpan[];\n remainder: string;\n}\n\nfunction tryMatchWord(s: string, pos: number, config: LangConfig): WordMatch | null {\n if (!isWordChar(s[pos]!)) return null;\n\n const wordEnd = findWordEnd(s, pos);\n const word = s.slice(pos, wordEnd);\n const lowerWord = word.toLowerCase();\n\n const isKeyword = config.keywords.has(word) || config.keywords.has(lowerWord);\n const isType = config.types && (config.types.has(word) || config.types.has(lowerWord));\n if (!isKeyword && !isType) return null;\n\n const spans: HighlightSpan[] = [];\n if (pos > 0) spans.push({ text: s.slice(0, pos), kind: \"plain\" });\n spans.push({ text: word, kind: isKeyword ? \"keyword\" : \"type\" });\n\n return { spans, remainder: s.slice(wordEnd) };\n}\n\n/** Try to match a number literal at the current position. */\nfunction tryMatchNumberToken(s: string, pos: number): WordMatch | null {\n const char = s[pos]!;\n const isDigit = char >= \"0\" && char <= \"9\";\n const isDecimalDot =\n char === \".\" && pos + 1 < s.length && s[pos + 1]! >= \"0\" && s[pos + 1]! <= \"9\";\n if (!isDigit && !isDecimalDot) return null;\n\n const numEnd = findNumberEnd(s, pos);\n if (numEnd <= pos) return null;\n\n const spans: HighlightSpan[] = [];\n if (pos > 0) spans.push({ text: s.slice(0, pos), kind: \"plain\" });\n spans.push({ text: s.slice(pos, numEnd), kind: \"number\" });\n\n return { spans, remainder: s.slice(numEnd) };\n}\n\n/**\n * Tokenize a line that is known to have no line comments.\n */\nfunction tokenizeLineNoComments(line: string, config: LangConfig): HighlightSpan[] {\n const spans: HighlightSpan[] = [];\n let remaining = line;\n let pos = 0;\n\n while (pos < remaining.length) {\n // String detection (highest priority)\n const strResult = tryMatchString(remaining);\n if (strResult) {\n if (pos > 0) spans.push({ text: remaining.slice(0, pos), kind: \"plain\" });\n spans.push({ text: strResult.matched, kind: \"string\" });\n remaining = strResult.remainder;\n pos = 0;\n continue;\n }\n\n // Keyword / type detection\n const wordMatch = tryMatchWord(remaining, pos, config);\n if (wordMatch) {\n spans.push(...wordMatch.spans);\n remaining = wordMatch.remainder;\n pos = 0;\n continue;\n }\n\n // Number detection\n const numMatch = tryMatchNumberToken(remaining, pos);\n if (numMatch) {\n spans.push(...numMatch.spans);\n remaining = numMatch.remainder;\n pos = 0;\n continue;\n }\n\n pos++;\n }\n\n if (remaining.length > 0) {\n spans.push({ text: remaining, kind: \"plain\" });\n }\n\n return mergeAdjacentSpans(spans);\n}\n\n// ── Tokenizer helpers ─────────────────────────────────\n\nfunction isWordChar(ch: string): boolean {\n return /[a-zA-Z_]/.test(ch);\n}\n\nfunction findWordEnd(s: string, start: number): number {\n let i = start;\n while (i < s.length && /[a-zA-Z0-9_]/.test(s[i]!)) i++;\n return i;\n}\n\nfunction findNumberEnd(s: string, start: number): number {\n let i = start;\n if (s[i] === \"0\" && i + 1 < s.length && (s[i + 1] === \"x\" || s[i + 1] === \"X\")) i += 2;\n while (i < s.length && /[0-9a-fA-F.x]/.test(s[i]!)) i++;\n return i;\n}\n\ninterface StrMatch {\n matched: string;\n remainder: string;\n}\n\nfunction tryMatchString(s: string): StrMatch | null {\n const delimiters = [`\"`, `'`, \"`\"];\n const first = s[0]!;\n if (!delimiters.includes(first)) return null;\n\n let i = 1;\n while (i < s.length) {\n if (s[i] === \"\\\\\") {\n i += 2;\n continue;\n }\n if (s[i] === first) return { matched: s.slice(0, i + 1), remainder: s.slice(i + 1) };\n i++;\n }\n return null;\n}\n\nfunction mergeAdjacentSpans(spans: HighlightSpan[]): HighlightSpan[] {\n if (spans.length <= 1) return spans;\n const merged: HighlightSpan[] = [];\n let cur = spans[0]!;\n for (let i = 1; i < spans.length; i++) {\n const next = spans[i]!;\n if (cur.kind === next.kind) {\n cur = { text: cur.text + next.text, kind: cur.kind };\n } else {\n merged.push(cur);\n cur = next;\n }\n }\n merged.push(cur);\n return merged;\n}\n\n// ── Public API ────────────────────────────────────────\n\n/**\n * Highlight a single line of code, returning styled spans.\n *\n * Uses the language tag to select the right keyword/comment/string\n * patterns. Falls back to JS-style highlighting when unknown.\n */\nexport function highlightCodeLine(line: string, language?: string): HighlightSpan[] {\n const config = getLangConfig(language);\n\n // Trim trailing newline for tokenization\n const clean = line.endsWith(\"\\n\") ? line.slice(0, -1) : line;\n\n if (clean.length === 0) return [{ text: \"\", kind: \"plain\" }];\n\n return tokenizeLine(clean, config).spans;\n}\n\n/**\n * Highlight an entire code block with cross-line block comment tracking.\n *\n * Unlike `highlightCodeLine`, this tracks `/* ... *​/` block comment\n * state across lines for languages that support them (JS, TS, Go, Rust, CSS).\n * Lines inside a multi-line block comment are fully styled as `\"comment\"`.\n */\nexport function highlightCodeBlock(code: string, language?: string): HighlightSpan[][] {\n const config = getLangConfig(language);\n const lines = code.split(\"\\n\");\n const result: HighlightSpan[][] = [];\n let inBlockComment = false;\n\n for (const line of lines) {\n // Trim trailing newline\n const clean = line.endsWith(\"\\n\") ? line.slice(0, -1) : line;\n\n if (clean.length === 0) {\n result.push([{ text: \"\", kind: \"plain\" }]);\n continue;\n }\n\n const { spans, inBlockComment: nextInBlock } = tokenizeLine(clean, config, inBlockComment);\n result.push(spans);\n inBlockComment = nextInBlock;\n }\n\n return result;\n}\n","/**\n * Emoji shortcode renderer — converts :name: patterns to Unicode emoji.\n *\n * Covers ~100 commonly used shortcodes from GitHub/Slack conventions.\n * Unrecognised codes are left as-is so the source remains readable.\n */\n\n/** Map of shortcode (without colons) → Unicode emoji character. */\nconst EMOJI_MAP: Record<string, string> = {\n smile: \"😄\",\n grinning: \"😁\",\n joy: \"😂\",\n rofl: \"🤣\",\n smiley: \"😃\",\n sweat_smile: \"😅\",\n laughing: \"😆\",\n wink: \"😉\",\n blush: \"😊\",\n innocent: \"😇\",\n heart_eyes: \"😍\",\n kissing_heart: \"😘\",\n kissing: \"😗\",\n kissing_closed_eyes: \"😚\",\n stuck_out_tongue: \"😛\",\n stuck_out_tongue_wink: \"😜\",\n stuck_out_tongue_closed_eyes: \"😝\",\n yum: \"😋\",\n relieved: \"😌\",\n satisfied: \"😆\",\n smirk: \"😏\",\n unamused: \"😒\",\n pensive: \"😔\",\n worried: \"😟\",\n confused: \"😕\",\n disappointed: \"😞\",\n cry: \"😢\",\n sob: \"😭\",\n angry: \"😠\",\n rage: \"😡\",\n triumph: \"😤\",\n sleepy: \"😪\",\n tired_face: \"😫\",\n fearful: \"😨\",\n cold_sweat: \"😰\",\n scream: \"😱\",\n astonished: \"😲\",\n flushed: \"😳\",\n dizzy_face: \"😵\",\n mask: \"😷\",\n sunglasses: \"😎\",\n nerd: \"🤓\",\n thinking: \"🤔\",\n neutral_face: \"😐\",\n expressionless: \"😑\",\n no_mouth: \"😶\",\n rolling_eyes: \"🙄\",\n zipper_mouth: \"🤐\",\n hug: \"🤗\",\n clown: \"🤡\",\n lie: \"🤥\",\n nauseated: \"🤢\",\n sneeze: \"🤧\",\n cowboy: \"🤠\",\n // Hand gestures\n \"+1\": \"👍\",\n \"-1\": \"👎\",\n clap: \"👏\",\n wave: \"👋\",\n ok_hand: \"👌\",\n raised_hands: \"🙌\",\n pray: \"🙏\",\n point_up: \"☝️\",\n point_down: \"👇\",\n point_left: \"👈\",\n point_right: \"👉\",\n muscle: \"💪\",\n // Symbols\n heart: \"❤️\",\n broken_heart: \"💔\",\n star: \"⭐\",\n sparkles: \"✨\",\n fire: \"🔥\",\n rocket: \"🚀\",\n tada: \"🎉\",\n check: \"✔️\",\n x: \"✖️\",\n warning: \"⚠️\",\n info: \"ℹ️\",\n question: \"❓\",\n bulb: \"💡\",\n lock: \"🔒\",\n unlock: \"🔓\",\n key: \"🔑\",\n hammer: \"🔨\",\n wrench: \"🔧\",\n gear: \"⚙️\",\n book: \"📖\",\n memo: \"📝\",\n pencil: \"✏️\",\n pin: \"📌\",\n link: \"🔗\",\n eyes: \"👀\",\n // Arrows\n arrow_up: \"⬆️\",\n arrow_down: \"⬇️\",\n arrow_left: \"⬅️\",\n arrow_right: \"➡️\",\n // Tech\n computer: \"💻\",\n bug: \"🐛\",\n robot: \"🤖\",\n package: \"📦\",\n globe: \"🌐\",\n shield: \"🛡️\",\n // Weather / nature\n sun: \"☀️\",\n cloud: \"☁️\",\n rain: \"🌧️\",\n snow: \"❄️\",\n zap: \"⚡\",\n // Misc\n coffee: \"☕\",\n beer: \"🍺\",\n pizza: \"🍕\",\n hourglass: \"⌛\",\n clock: \"🕐\",\n money: \"💰\",\n chart: \"📊\",\n mail: \"✉️\",\n phone: \"📱\",\n calendar: \"📅\",\n};\n\n/** Regex matching an emoji shortcode: :word: or :word_word: */\nconst SHORTCODE_RE = /:([a-zA-Z0-9_+-]+):/g;\n\n/**\n * Replace emoji shortcodes in text with their Unicode equivalents.\n *\n * Example: \"Hello :wave: :smile:\" → \"Hello 👋 😀\"\n * Unrecognised codes are left in place.\n */\nexport function renderEmojiShortcodes(text: string): string {\n return text.replace(SHORTCODE_RE, (_full, name: string) => {\n const emoji = EMOJI_MAP[name];\n return emoji ?? _full;\n });\n}\n","/**\n * LaTeX math → Unicode approximate renderer.\n *\n * Converts inline ($...$) and display ($$...$$) math to their\n * closest Unicode equivalents for terminal rendering. This is\n * NOT a full LaTeX engine — it covers the most common symbols.\n */\n\n// ── Symbol tables ─────────────────────────────────────\n\n/** Greek lowercase letters. */\nconst GREEK_LOWER: Record<string, string> = {\n alpha: \"α\",\n beta: \"β\",\n gamma: \"γ\",\n delta: \"δ\",\n epsilon: \"ε\",\n zeta: \"ζ\",\n eta: \"η\",\n theta: \"θ\",\n iota: \"ι\",\n kappa: \"κ\",\n lambda: \"λ\",\n mu: \"μ\",\n nu: \"ν\",\n xi: \"ξ\",\n pi: \"π\",\n rho: \"ρ\",\n sigma: \"σ\",\n tau: \"τ\",\n upsilon: \"υ\",\n phi: \"φ\",\n chi: \"χ\",\n psi: \"ψ\",\n omega: \"ω\",\n};\n\n/** Greek uppercase letters. */\nconst GREEK_UPPER: Record<string, string> = {\n Gamma: \"Γ\",\n Delta: \"Δ\",\n Theta: \"Θ\",\n Lambda: \"Λ\",\n Xi: \"Ξ\",\n Pi: \"Π\",\n Sigma: \"Σ\",\n Phi: \"Φ\",\n Psi: \"Ψ\",\n Omega: \"Ω\",\n};\n\n/** Common math symbols. */\nconst MATH_SYMBOLS: Record<string, string> = {\n \"\\\\infty\": \"∞\",\n \"\\\\pm\": \"±\",\n \"\\\\mp\": \"∓\",\n \"\\\\times\": \"×\",\n \"\\\\div\": \"÷\",\n \"\\\\cdot\": \"·\",\n \"\\\\leq\": \"≤\",\n \"\\\\geq\": \"≥\",\n \"\\\\neq\": \"≠\",\n \"\\\\approx\": \"≈\",\n \"\\\\equiv\": \"≡\",\n \"\\\\sim\": \"∼\",\n \"\\\\propto\": \"∝\",\n \"\\\\subset\": \"⊂\",\n \"\\\\supset\": \"⊃\",\n \"\\\\subseteq\": \"⊆\",\n \"\\\\supseteq\": \"⊇\",\n \"\\\\in\": \"∈\",\n \"\\\\notin\": \"∉\",\n \"\\\\forall\": \"∀\",\n \"\\\\exists\": \"∃\",\n \"\\\\emptyset\": \"∅\",\n \"\\\\nabla\": \"∇\",\n \"\\\\partial\": \"∂\",\n \"\\\\int\": \"∫\",\n \"\\\\sum\": \"∑\",\n \"\\\\prod\": \"∏\",\n \"\\\\sqrt\": \"√\",\n \"\\\\angle\": \"∠\",\n \"\\\\perp\": \"⊥\",\n \"\\\\parallel\": \"∥\",\n \"\\\\to\": \"→\",\n \"\\\\rightarrow\": \"→\",\n \"\\\\leftarrow\": \"←\",\n \"\\\\uparrow\": \"↑\",\n \"\\\\downarrow\": \"↓\",\n \"\\\\mapsto\": \"↦\",\n \"\\\\Rightarrow\": \"⇒\",\n \"\\\\Leftarrow\": \"⇐\",\n \"\\\\iff\": \"⟺\",\n \"\\\\land\": \"∧\",\n \"\\\\lor\": \"∨\",\n \"\\\\neg\": \"¬\",\n \"\\\\oplus\": \"⊕\",\n \"\\\\otimes\": \"⊗\",\n \"\\\\ldots\": \"…\",\n \"\\\\cdots\": \"⋯\",\n \"\\\\vdots\": \"⋮\",\n \"\\\\ddots\": \"⋱\",\n \"\\\\circ\": \"∘\",\n \"\\\\bullet\": \"•\",\n \"\\\\star\": \"★\",\n \"\\\\triangle\": \"△\",\n \"\\\\square\": \"□\",\n \"\\\\diamond\": \"◇\",\n};\n\n// ── Substitution passes ───────────────────────────────\n\n/**\n * Convert superscript patterns: x^{2} → x², x^{n} → xⁿ.\n * Handles ^ (e.g. x^2 → x², x^{abc} → xᵃᵇᶜ).\n */\nfunction replaceSuperscript(text: string): string {\n const SUPER: Record<string, string> = {\n \"0\": \"⁰\",\n \"1\": \"¹\",\n \"2\": \"²\",\n \"3\": \"³\",\n \"4\": \"⁴\",\n \"5\": \"⁵\",\n \"6\": \"⁶\",\n \"7\": \"⁷\",\n \"8\": \"⁸\",\n \"9\": \"⁹\",\n \"+\": \"⁺\",\n \"-\": \"⁻\",\n \"=\": \"⁼\",\n \"(\": \"⁽\",\n \")\": \"⁾\",\n n: \"ⁿ\",\n i: \"ⁱ\",\n };\n return text\n .replace(/\\^\\{([^}]+)\\}/g, (_, body: string) => [...body].map((c) => SUPER[c] ?? c).join(\"\"))\n .replace(/\\^(\\d)/g, (_, d: string) => SUPER[d] ?? `^${d}`);\n}\n\n/**\n * Convert subscript patterns: x_{i} → xᵢ, x_{10} → x₁₀.\n */\nfunction replaceSubscript(text: string): string {\n const SUB: Record<string, string> = {\n \"0\": \"₀\",\n \"1\": \"₁\",\n \"2\": \"₂\",\n \"3\": \"₃\",\n \"4\": \"₄\",\n \"5\": \"₅\",\n \"6\": \"₆\",\n \"7\": \"₇\",\n \"8\": \"₈\",\n \"9\": \"₉\",\n \"+\": \"₊\",\n \"-\": \"₋\",\n \"=\": \"₌\",\n \"(\": \"₍\",\n \")\": \"₎\",\n i: \"ᵢ\",\n j: \"ⱼ\",\n k: \"ₖ\",\n n: \"ₙ\",\n };\n return text\n .replace(/_\\{([^}]+)\\}/g, (_, body: string) => [...body].map((c) => SUB[c] ?? c).join(\"\"))\n .replace(/_(\\w)/g, (_, c: string) => SUB[c] ?? `_${c}`);\n}\n\n// ── Public API ────────────────────────────────────────\n\n/**\n * Render inline LaTeX ($...$) to Unicode approximations.\n *\n * Handles:\n * - Greek letters (\\\\alpha → α, \\\\Gamma → Γ)\n * - Common symbols (\\\\infty → ∞, \\\\pm → ±, etc.)\n * - Superscript (x^{2} → x²) and subscript (x_{i} → xᵢ)\n * - Fractions (\\\\frac{a}{b} → (a)/(b))\n *\n * Returns the approximate Unicode text, or the original if no\n * patterns matched.\n */\nexport function renderInlineLatex(latex: string): string {\n let result = latex;\n\n // Fractions first — \\\\frac{a}{b} → (a)/(b)\n result = result.replace(/\\\\frac\\{([^}]*)}\\{([^}]*)}/g, \"($1)/($2)\");\n\n // Common math symbols (longest first to avoid partial matches)\n const sortedSymbols = Object.entries(MATH_SYMBOLS).sort((a, b) => b[0].length - a[0].length);\n for (const [cmd, sym] of sortedSymbols) {\n result = result.replaceAll(cmd, sym);\n }\n\n // Greek uppercase\n for (const [name, sym] of Object.entries(GREEK_UPPER)) {\n result = result.replace(`\\\\${name}`, sym);\n }\n\n // Greek lowercase\n for (const [name, sym] of Object.entries(GREEK_LOWER)) {\n result = result.replace(`\\\\${name}`, sym);\n }\n\n // Superscript / subscript\n result = replaceSuperscript(result);\n result = replaceSubscript(result);\n\n return result;\n}\n\n/**\n * Detect if a string looks like a LaTeX math expression.\n *\n * Heuristic: contains a backslash command or a math structure\n * like subscript/superscript braces.\n */\nexport function isLatexInline(text: string): boolean {\n return text.includes(\"\\\\\") || /\\^\\{/.test(text) || /\\{/.test(text);\n}\n","/**\n * Markdown renderer — converts LLM response markdown to Ink‑renderable elements.\n *\n * Handles:\n * — Code blocks (fenced + indented)\n * — Inline: bold, italic, strikethrough, inline code, links\n * — Headings (h1–h6)\n * — Unordered / ordered lists\n * — Blockquotes\n * — Horizontal rules\n * — Diff output (+++/---/@@/+/-)\n *\n * Streaming mode: finds the last stable block boundary,\n * memos the prefix, and only re‑parses the unstable suffix.\n */\n\nimport React, { type ReactNode } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { highlightCodeLine, highlightCodeBlock, type HighlightSpan } from \"./highlight.js\";\nimport { renderEmojiShortcodes } from \"./emoji.js\";\nimport { renderInlineLatex, isLatexInline } from \"./latex.js\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface MarkdownBlock {\n type: \"paragraph\" | \"heading\" | \"code\" | \"list_item\" | \"blockquote\" | \"hr\" | \"diff\" | \"table\";\n /** Heading level (1–6), only for heading blocks. */\n level?: number;\n /** Source text for this block. */\n text: string;\n /** Language tag for fenced code blocks. */\n language?: string;\n /** For ordered list items, the number. */\n listNumber?: number;\n /** For diff blocks, the diff line type. */\n diffLineType?: \"header\" | \"hunk\" | \"add\" | \"remove\" | \"context\";\n /** For task list items, whether the checkbox is checked. */\n checked?: boolean;\n /** Indentation depth for nested list items (0 = top level). */\n indentLevel?: number;\n /** For table blocks, the column headers. */\n tableHeaders?: string[];\n /** For table blocks, the data rows (each row is an array of cell text). */\n tableRows?: string[][];\n /** For table blocks, column alignments. */\n tableAligns?: (\"left\" | \"center\" | \"right\")[];\n}\n\nexport interface RenderOptions {\n /** Max number of blocks to render (limits re‑render cost). */\n maxBlocks?: number;\n /** If true, only parse complete blocks (for streaming). */\n stableOnly?: boolean;\n}\n\n// ── Inline formatting ─────────────────────────────────\n\n/** An inline segment with optional formatting. */\ninterface InlineSegment {\n text: string;\n bold?: boolean;\n italic?: boolean;\n strikethrough?: boolean;\n code?: boolean;\n link?: string;\n}\n\n/**\n * Parse inline markdown formatting within a single line of text.\n * Handles: **bold**, *italic*, ~~strikethrough~~, `code`, [text](url).\n */\nfunction parseInline(text: string): InlineSegment[] {\n const segments: InlineSegment[] = [];\n\n // Regex matches inline formatting tokens in order of precedence\n const pattern = /(\\*\\*(.+?)\\*\\*)|(\\*(.+?)\\*)|(~~(.+?)~~)|(`(.+?)`)|(\\[(.+?)\\]\\((.+?)\\))/g;\n\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n // Text before this match\n if (match.index > lastIndex) {\n segments.push({ text: text.slice(lastIndex, match.index) });\n }\n\n if (match[1]) {\n // **bold**\n segments.push({ text: match[2]!, bold: true });\n } else if (match[3]) {\n // *italic*\n segments.push({ text: match[4]!, italic: true });\n } else if (match[5]) {\n // ~~strikethrough~~\n segments.push({ text: match[6]!, strikethrough: true });\n } else if (match[7]) {\n // `code`\n segments.push({ text: match[8]!, code: true });\n } else if (match[9]) {\n // [text](url)\n segments.push({ text: match[10]!, link: match[11]! });\n }\n\n lastIndex = match.index + match[0].length;\n }\n\n // Remaining text after last match\n if (lastIndex < text.length) {\n segments.push({ text: text.slice(lastIndex) });\n }\n\n // If no formatting was found, return plain text\n if (segments.length === 0) {\n segments.push({ text });\n }\n\n return segments;\n}\n\n/**\n * Render inline segments as Ink Text elements.\n *\n * Each segment becomes a Text element with appropriate formatting.\n * Multiple segments are rendered as siblings within a parent Text.\n */\nexport function renderInline(text: string): ReactNode {\n // Apply emoji shortcode rendering as a safety net\n const rendered = renderEmojiShortcodes(text);\n const segments = parseInline(rendered);\n\n if (segments.length === 1 && !segments[0]!.bold && !segments[0]!.italic && !segments[0]!.code) {\n // Plain text — return as string for efficiency\n return segments[0]!.text;\n }\n\n return segments.map((seg, i) => {\n const props: Record<string, unknown> = { key: `seg-${i}` };\n\n if (seg.bold) props.bold = true;\n if (seg.italic) props.italic = true;\n if (seg.strikethrough) props.strikethrough = true;\n if (seg.code) props.dimColor = true;\n if (seg.link) {\n props.underline = true;\n props.color = \"blue\";\n // Wrap text with OSC 8 hyperlink so terminals that support\n // it can make the link clickable. Fallback: just blue underline.\n if (seg.link && !seg.link.startsWith(\"javascript:\")) {\n return React.createElement(Text, props, wrapOsc8(seg.link, seg.text));\n }\n }\n\n return React.createElement(Text, props, seg.text);\n });\n}\n\n// ── OSC 8 hyperlinks ───────────────────────────────────\n\n/**\n * Wrap text in an OSC 8 hyperlink escape sequence.\n *\n * OSC 8 is supported by most modern terminals (iTerm2, Windows Terminal,\n * VSCode terminal, Kitty, etc.). When the terminal doesn't support it,\n * the escape sequences are ignored and the text renders as plain text.\n *\n * Format: \\x1b]8;;URL\\x1b\\\\TEXT\\x1b]8;;\\x1b\\\\\n */\nfunction wrapOsc8(url: string, text: string): string {\n return `\\x1b]8;;${url}\\x1b\\\\${text}\\x1b]8;;\\x1b\\\\`;\n}\n\n// ── Color helpers ────────────────────────────────────\n\n/** Map a highlight span kind to an Ink color. */\nfunction spanColor(kind: HighlightSpan[\"kind\"]): string | undefined {\n switch (kind) {\n case \"keyword\":\n return \"yellow\";\n case \"string\":\n return \"green\";\n case \"number\":\n return \"magenta\";\n case \"comment\":\n return \"grey\";\n case \"type\":\n return \"cyan\";\n case \"plain\":\n return undefined;\n default:\n return undefined;\n }\n}\n\n/** Render a highlighted line as Ink Text elements. */\nfunction renderHighlightedLine(line: string, lang?: string): ReactNode {\n const spans = highlightCodeLine(line, lang);\n if (spans.length === 0) return \"\";\n\n // Optimize: single plain span → return as string\n if (spans.length === 1 && spans[0]!.kind === \"plain\") {\n return spans[0]!.text;\n }\n\n return spans.map((span, si) => {\n const color = spanColor(span.kind);\n const props: Record<string, unknown> = { key: `hs-${si}` };\n if (span.kind === \"keyword\" || span.kind === \"type\") props.bold = true;\n if (span.kind === \"comment\") props.dimColor = true;\n if (color) props.color = color;\n if (span.text === \"\") return null;\n return React.createElement(Text, props, span.text);\n });\n}\n\n// ── Parsing ──────────────────────────────────────────\n\n// ── Block detection helpers ─────────────────────────\n\n/** Detect the type of a diff line from its prefix. */\nfunction detectDiffLineType(trimmed: string): MarkdownBlock[\"diffLineType\"] {\n if (\n trimmed.startsWith(\"+++ \") ||\n trimmed.startsWith(\"--- \") ||\n trimmed.startsWith(\"diff --git\") ||\n trimmed.startsWith(\"index \")\n ) {\n return \"header\";\n }\n if (trimmed.startsWith(\"@@\")) return \"hunk\";\n if (trimmed.startsWith(\"+\")) return \"add\";\n if (trimmed.startsWith(\"-\")) return \"remove\";\n return \"context\";\n}\n\n/** Detect if a line is part of a diff block (uses prevLine for context). */\nfunction isDiffLine(trimmed: string, prevLine?: string): boolean {\n if (trimmed.startsWith(\"+++ \") || trimmed.startsWith(\"--- \")) return true;\n if (/^@@\\s+-/.test(trimmed)) return true;\n if (\n prevLine &&\n (prevLine.startsWith(\"+++ \") || prevLine.startsWith(\"--- \") || /^@@\\s+-/.test(prevLine))\n ) {\n return trimmed.startsWith(\"+\") || trimmed.startsWith(\"-\");\n }\n return trimmed.startsWith(\"diff --git\") || trimmed.startsWith(\"index \");\n}\n\n/** Try to parse a heading line. Returns null if not a heading. */\nfunction tryParseHeading(trimmed: string): MarkdownBlock | null {\n const match = /^(#{1,6})\\s+(.+)/.exec(trimmed);\n if (!match) return null;\n return { type: \"heading\", level: match[1]!.length, text: match[2]! };\n}\n\n/** Check if a line is a horizontal rule. */\nfunction isHorizontalRule(trimmed: string): boolean {\n return /^(-{3,}|\\*{3,}|_{3,})\\s*$/.test(trimmed);\n}\n\n/** Check if a line is a markdown table row (starts and ends with |). */\nfunction isTableRow(line: string): boolean {\n const trimmed = line.trim();\n return trimmed.startsWith(\"|\") && trimmed.endsWith(\"|\");\n}\n\n/** Check if a line is a table separator row (e.g. |---|---|). */\nfunction isTableSeparator(line: string): boolean {\n return /^\\|[\\s:-]+\\|/.test(line.trim()) && /[\\s:-]+\\|$/.test(line.trim());\n}\n\n/**\n * Parse alignment from a separator cell.\n * Returns \"left\" for :---, \"center\" for :---:, \"right\" for ---:.\n */\nfunction parseAlign(cell: string): \"left\" | \"center\" | \"right\" {\n const trimmed = cell.trim();\n const left = trimmed.startsWith(\":\");\n const right = trimmed.endsWith(\":\");\n if (left && right) return \"center\";\n if (right) return \"right\";\n return \"left\";\n}\n\n/** Parse accumulated table lines into a MarkdownBlock. */\nfunction flushTable(tableLines: string[]): MarkdownBlock | null {\n if (tableLines.length < 2) return null;\n const headerLine = tableLines[0]!;\n const sepLine = tableLines[1]!;\n if (!isTableSeparator(sepLine)) return null;\n\n const headers = splitTableCells(headerLine);\n const sepCells = splitTableCells(sepLine);\n const aligns = sepCells.map(parseAlign);\n\n const rows: string[][] = [];\n for (let r = 2; r < tableLines.length; r++) {\n rows.push(splitTableCells(tableLines[r]!));\n }\n\n return {\n type: \"table\",\n text: tableLines.join(\"\\n\"),\n tableHeaders: headers,\n tableRows: rows,\n tableAligns: aligns,\n };\n}\n\n/** Split a table row like \"| A | B |\" into [\"A\", \"B\"]. */\nfunction splitTableCells(row: string): string[] {\n return row\n .trim()\n .replace(/^\\|/, \"\")\n .replace(/\\|$/, \"\")\n .split(\"|\")\n .map((c) => c.trim());\n}\n\n/** Try to parse a list item. Returns null if not a list item. */\nfunction tryParseListItem(line: string): MarkdownBlock | null {\n const trimmed = line.trim();\n const indent = line.length - line.trimStart().length;\n const indentLevel = Math.floor(indent / 2);\n\n // Task list: - [ ] text or - [x] text\n const taskMatch = /^[-*+]\\s+\\[([ xX])\\]\\s+(.+)/.exec(trimmed);\n if (taskMatch) {\n return {\n type: \"list_item\",\n text: taskMatch[2]!,\n checked: taskMatch[1]!.toLowerCase() === \"x\",\n indentLevel,\n };\n }\n\n if (/^[-*+]\\s+/.test(trimmed)) {\n return {\n type: \"list_item\",\n text: trimmed.replace(/^[-*+]\\s+/, \"\"),\n indentLevel,\n };\n }\n const orderedMatch = /^(\\d+)\\.\\s+(.+)/.exec(trimmed);\n if (orderedMatch) {\n return {\n type: \"list_item\",\n text: orderedMatch[2]!,\n listNumber: Number.parseInt(orderedMatch[1]!, 10),\n indentLevel,\n };\n }\n return null;\n}\n\n// ── Parse state & helpers ───────────────────────────\n\ninterface ParseState {\n inCodeBlock: boolean;\n codeLanguage: string;\n codeLines: string[];\n inBlockquote: boolean;\n quoteLines: string[];\n inDiff: boolean;\n diffLines: MarkdownBlock[];\n paraLines: string[];\n /** Accumulated table lines (raw) being collected. */\n tableLines: string[];\n /** Whether we're inside a table block. */\n inTable: boolean;\n}\n\n/** Flush accumulated paragraph lines as a paragraph block. */\nfunction flushParagraphLines(paraLines: string[], blocks: MarkdownBlock[]): void {\n const text = paraLines.join(\"\\n\").trim();\n if (text) blocks.push({ type: \"paragraph\", text });\n paraLines.length = 0;\n}\n\n/** Flush accumulated code lines as a code block. */\nfunction flushCodeLines(codeLines: string[], blocks: MarkdownBlock[], language: string): void {\n if (codeLines.length > 0) {\n blocks.push({ type: \"code\", text: codeLines.join(\"\\n\"), language: language || undefined });\n codeLines.length = 0;\n }\n}\n\n/** Flush accumulated quote lines as a blockquote. */\nfunction flushQuoteLines(quoteLines: string[], blocks: MarkdownBlock[]): void {\n if (quoteLines.length > 0) {\n blocks.push({ type: \"blockquote\", text: quoteLines.join(\"\\n\") });\n quoteLines.length = 0;\n }\n}\n\n/**\n * Handle code fence toggle, code block content, blockquote start/continue/end.\n * Returns true if the line was consumed (caller should continue the loop).\n */\nfunction tryProcessCodeStructure(\n raw: string,\n trimmed: string,\n state: ParseState,\n blocks: MarkdownBlock[],\n): boolean {\n if (trimmed.startsWith(\"```\")) {\n flushParagraphLines(state.paraLines, blocks);\n flushQuoteLines(state.quoteLines, blocks);\n if (state.inCodeBlock) {\n flushCodeLines(state.codeLines, blocks, state.codeLanguage);\n state.inCodeBlock = false;\n state.codeLanguage = \"\";\n } else {\n state.codeLanguage = trimmed.slice(3).trim();\n state.inCodeBlock = true;\n }\n return true;\n }\n if (state.inCodeBlock) {\n state.codeLines.push(raw);\n return true;\n }\n\n if (trimmed.startsWith(\"> \")) {\n flushParagraphLines(state.paraLines, blocks);\n state.inBlockquote = true;\n state.quoteLines.push(trimmed.slice(2));\n return true;\n }\n if (state.inBlockquote) {\n flushQuoteLines(state.quoteLines, blocks);\n state.inBlockquote = false;\n }\n return false;\n}\n\n/**\n * Handle diff block lines.\n * Returns true if the line was consumed as a diff line.\n */\nfunction tryProcessDiffLine(\n raw: string,\n prevTrimmed: string,\n state: ParseState,\n blocks: MarkdownBlock[],\n): boolean {\n const trimmed = raw.trim();\n const prevCtx = state.inDiff ? prevTrimmed : \"\";\n if (isDiffLine(trimmed, prevCtx)) {\n if (!state.inDiff) flushParagraphLines(state.paraLines, blocks);\n state.inDiff = true;\n state.diffLines.push({ type: \"diff\", text: raw, diffLineType: detectDiffLineType(trimmed) });\n return true;\n }\n if (state.inDiff && trimmed !== \"\" && !isDiffLine(trimmed)) {\n blocks.push(...state.diffLines);\n state.diffLines = [];\n state.inDiff = false;\n }\n return false;\n}\n\n/**\n * Try to parse a single-line block element (heading, HR, list item).\n * Returns true if the line was consumed.\n */\nfunction tryProcessSingleLineBlock(\n trimmed: string,\n state: ParseState,\n blocks: MarkdownBlock[],\n): boolean {\n const heading = tryParseHeading(trimmed);\n if (heading) {\n flushParagraphLines(state.paraLines, blocks);\n blocks.push(heading);\n return true;\n }\n if (isHorizontalRule(trimmed)) {\n flushParagraphLines(state.paraLines, blocks);\n blocks.push({ type: \"hr\", text: \"\" });\n return true;\n }\n const listItem = tryParseListItem(trimmed);\n if (listItem) {\n flushParagraphLines(state.paraLines, blocks);\n blocks.push(listItem);\n return true;\n }\n return false;\n}\n\n/**\n * Process a potential table line. Tables start when we see a header row\n * immediately followed by a separator row.\n *\n * Returns true if the line was consumed as part of a table.\n */\nfunction tryProcessTableLine(\n raw: string,\n idx: number,\n lines: string[],\n state: ParseState,\n blocks: MarkdownBlock[],\n): boolean {\n const trimmed = raw.trim();\n\n // If not a table row and not in a table, skip\n if (!isTableRow(trimmed) && !state.inTable) return false;\n\n if (isTableRow(trimmed)) {\n // Check if next line is a separator — that confirms a table header\n const nextLine = idx + 1 < lines.length ? lines[idx + 1]!.trim() : \"\";\n if (isTableSeparator(nextLine)) {\n // Start a new table: flush prior state\n flushParagraphLines(state.paraLines, blocks);\n if (state.inTable) {\n const flushed = flushTable(state.tableLines);\n if (flushed) blocks.push(flushed);\n state.tableLines = [];\n }\n state.inTable = true;\n state.tableLines.push(raw);\n return true;\n }\n // If we're already in a table, this is a data row\n if (state.inTable) {\n state.tableLines.push(raw);\n return true;\n }\n // Not a table after all — fall through to paragraph\n return false;\n }\n\n // Not a table row but we were in a table — flush and reset\n if (state.inTable && !isTableRow(trimmed)) {\n const flushed = flushTable(state.tableLines);\n if (flushed) blocks.push(flushed);\n state.tableLines = [];\n state.inTable = false;\n }\n return false;\n}\n\n/**\n * Preprocess markdown text before parsing:\n * 1. Replace emoji shortcodes (:smile: → 😀).\n * 2. Convert $$...$$ display LaTeX blocks to Unicode approximations.\n * 3. Convert $...$ inline LaTeX to Unicode approximations.\n */\nfunction preprocessMarkdown(md: string): string {\n // 1. Emoji shortcodes\n let result = renderEmojiShortcodes(md);\n\n // 2. Display LaTeX blocks — $$...$$ on their own lines → Unicode math block\n result = result.replace(/\\$\\$([\\s\\S]*?)\\$\\$/g, (_full: string, body: string) => {\n const approx = renderInlineLatex(body.trim());\n return `\\`\\`\\`math\\n${approx}\\n\\`\\`\\``;\n });\n\n // 3. Inline LaTeX — $...$ → Unicode approximated\n result = result.replace(/\\$([^$\\n]+?)\\$/g, (_full: string, body: string) => {\n if (isLatexInline(body)) return renderInlineLatex(body);\n return _full; // Not a LaTeX expression — leave as-is\n });\n\n return result;\n}\n\n/** Simple line‑by‑line markdown parser. Returns blocks in order. */\nexport function parseMarkdown(md: string, opts: RenderOptions = {}): MarkdownBlock[] {\n const { stableOnly = false } = opts;\n // Preprocess: emoji shortcodes and display LaTeX blocks\n const preprocessed = preprocessMarkdown(md);\n const lines = preprocessed.split(\"\\n\");\n const blocks: MarkdownBlock[] = [];\n\n const state: ParseState = {\n inCodeBlock: false,\n codeLanguage: \"\",\n codeLines: [],\n inBlockquote: false,\n quoteLines: [],\n inDiff: false,\n diffLines: [],\n paraLines: [],\n tableLines: [],\n inTable: false,\n };\n\n for (let i = 0; i < lines.length; i++) {\n const raw = lines[i]!;\n const trimmed = raw.trim();\n\n // Table detection: check before code/diff/single-line blocks since\n // tables can look like regular text to other detectors.\n if (tryProcessTableLine(raw, i, lines, state, blocks)) continue;\n\n if (tryProcessCodeStructure(raw, trimmed, state, blocks)) continue;\n const prevTrimmed = i > 0 ? lines[i - 1]!.trim() : \"\";\n if (tryProcessDiffLine(raw, prevTrimmed, state, blocks)) continue;\n if (tryProcessSingleLineBlock(trimmed, state, blocks)) continue;\n if (trimmed === \"\") {\n flushParagraphLines(state.paraLines, blocks);\n continue;\n }\n\n state.paraLines.push(trimmed);\n }\n\n // Flush any remaining\n if (!(state.inCodeBlock && stableOnly))\n flushCodeLines(state.codeLines, blocks, state.codeLanguage);\n flushQuoteLines(state.quoteLines, blocks);\n if (state.diffLines.length > 0) blocks.push(...state.diffLines);\n if (state.inTable) {\n const flushed = flushTable(state.tableLines);\n if (flushed) blocks.push(flushed);\n }\n flushParagraphLines(state.paraLines, blocks);\n\n return blocks;\n}\n\n/**\n * For streaming text, find the last \"stable\" offset — the position\n * after the last complete block. Everything before this offset can\n * be memoized; only the suffix needs re‑parsing.\n */\nexport function findStableOffset(text: string): number {\n const lastDouble = text.lastIndexOf(\"\\n\\n\");\n if (lastDouble < 0) return 0;\n\n const fenceCount = (text.match(/```/g) ?? []).length;\n if (fenceCount % 2 !== 0) {\n const lastFence = text.lastIndexOf(\"```\");\n if (lastFence > 0) return lastFence;\n return 0;\n }\n\n return lastDouble + 2;\n}\n\n// ── Block renderers ────────────────────────────────\n\n/** Map diff line type to an Ink color string. */\nfunction getDiffColor(diffLineType?: string): string {\n switch (diffLineType) {\n case \"header\":\n return \"grey\";\n case \"hunk\":\n return \"cyan\";\n case \"add\":\n return \"green\";\n case \"remove\":\n return \"red\";\n default:\n return \"white\";\n }\n}\n\n/** Render a heading block. */\nfunction renderHeadingBlock(block: MarkdownBlock, i: number): ReactNode {\n const color = block.level === 1 ? \"cyan\" : block.level === 2 ? \"yellow\" : \"green\";\n return React.createElement(Text, { key: `h-${i}`, bold: true, color }, renderInline(block.text));\n}\n\n/** Render a fenced code block with syntax highlighting (cross‑line comment aware). */\nfunction renderCodeBlock(block: MarkdownBlock, i: number): ReactNode {\n const highlightLines = highlightCodeBlock(block.text, block.language);\n const children: ReactNode[] = [];\n\n if (block.language) {\n children.push(\n React.createElement(Text, { key: \"lang\", bold: true, color: \"cyan\" }, `[${block.language}]`),\n );\n }\n\n for (let li = 0; li < highlightLines.length; li++) {\n const spans = highlightLines[li]!;\n // Optimize: single plain span → render as string\n if (spans.length === 1 && spans[0]!.kind === \"plain\") {\n children.push(React.createElement(Text, { key: `cl-${li}` }, spans[0]!.text));\n continue;\n }\n const spanElements = spans\n .filter((s) => s.text !== \"\")\n .map((span, si) => {\n const color = spanColor(span.kind);\n const props: Record<string, unknown> = { key: `hs-${li}-${si}` };\n if (span.kind === \"keyword\" || span.kind === \"type\") props.bold = true;\n if (span.kind === \"comment\") props.dimColor = true;\n if (color) props.color = color;\n return React.createElement(Text, props, span.text);\n });\n children.push(React.createElement(Text, { key: `cl-${li}` }, ...spanElements));\n }\n\n return React.createElement(\n Box,\n { key: `code-${i}`, flexDirection: \"column\" },\n React.createElement(\n Box,\n {\n borderStyle: \"classic\" as const,\n borderColor: \"grey\" as const,\n paddingX: 1,\n flexDirection: \"column\",\n },\n ...children,\n ),\n );\n}\n\n/** Render a blockquote block. */\nfunction renderBlockquoteBlock(block: MarkdownBlock, i: number): ReactNode {\n return React.createElement(Text, { key: `q-${i}`, color: \"grey\" }, `│ ${block.text}`);\n}\n\n/** Render a list item block, including task list checkbox and indentation. */\nfunction renderListItemBlock(block: MarkdownBlock, i: number): ReactNode {\n const indentPad = block.indentLevel ? \" \".repeat(block.indentLevel) : \"\";\n\n // Task list item\n if (block.checked !== undefined) {\n const checkbox = block.checked ? \"☑\" : \"☐\";\n const color = block.checked ? \"green\" : \"grey\";\n return React.createElement(\n Text,\n { key: `li-${i}` },\n indentPad,\n React.createElement(Text, { color: \"yellow\" }, \"• \"),\n React.createElement(Text, { color }, `${checkbox} `),\n React.createElement(\n Text,\n block.checked ? { strikethrough: true, dimColor: true, color: \"green\" } : {},\n renderInline(block.text),\n ),\n );\n }\n\n // Regular list (ordered or unordered)\n const marker = block.listNumber ? `${block.listNumber}. ` : \"• \";\n return React.createElement(\n Text,\n { key: `li-${i}` },\n indentPad,\n React.createElement(Text, { color: \"yellow\" }, marker),\n React.createElement(Text, { color: \"white\" }, renderInline(block.text)),\n );\n}\n\n/** Render a diff block line. */\nfunction renderDiffBlock(block: MarkdownBlock, i: number): ReactNode {\n return React.createElement(\n Text,\n { key: `d-${i}`, color: getDiffColor(block.diffLineType) },\n block.text,\n );\n}\n\n/** Render a horizontal rule. */\nfunction renderHRBlock(i: number): ReactNode {\n return React.createElement(Text, { key: `hr-${i}`, dimColor: true }, \"────────────────\");\n}\n\n/**\n * Render a table block with aligned columns.\n *\n * Calculates column widths based on content, renders headers in bold,\n * and aligns each cell according to the table's alignment spec.\n */\nfunction renderTableBlock(block: MarkdownBlock, i: number): ReactNode {\n const headers = block.tableHeaders ?? [];\n const rows = block.tableRows ?? [];\n const aligns = block.tableAligns ?? [];\n const allRows = [headers, ...rows];\n\n // Calculate column widths from content\n const colCount = Math.max(headers.length, ...rows.map((r) => r.length), 1);\n const widths: number[] = new Array(colCount).fill(0);\n for (const row of allRows) {\n for (let c = 0; c < colCount; c++) {\n widths[c] = Math.max(widths[c] ?? 0, (row[c] ?? \"\").length);\n }\n }\n\n // Render helper: pad a cell to fit its column width\n function padCell(cell: string, col: number): string {\n const w = widths[col] ?? 0;\n const align = aligns[col] ?? \"left\";\n if (align === \"right\") return cell.padStart(w);\n if (align === \"center\") {\n const left = Math.floor((w - cell.length) / 2);\n return \" \".repeat(left) + cell + \" \".repeat(w - cell.length - left);\n }\n return cell.padEnd(w); // left\n }\n\n const dim = \"grey\";\n const children: ReactNode[] = [];\n\n // Header row\n const headerCells: ReactNode[] = [];\n for (let c = 0; c < colCount; c++) {\n headerCells.push(\n React.createElement(Text, { key: `th-${c}`, bold: true }, padCell(headers[c] ?? \"\", c)),\n );\n if (c < colCount - 1) {\n headerCells.push(React.createElement(Text, { key: `sep-h-${c}`, color: dim }, \" │ \"));\n }\n }\n children.push(React.createElement(Box, { key: \"thead\", flexDirection: \"row\" }, ...headerCells));\n\n // Separator line\n children.push(\n React.createElement(\n Text,\n { key: \"tsep\", color: dim },\n \"─\".repeat(widths.reduce((a, b) => a + b + 3 * (colCount - 1), 0)),\n ),\n );\n\n // Data rows\n for (let r = 0; r < rows.length; r++) {\n const row = rows[r]!;\n const cells: ReactNode[] = [];\n for (let c = 0; c < colCount; c++) {\n cells.push(React.createElement(Text, { key: `td-${r}-${c}` }, padCell(row[c] ?? \"\", c)));\n if (c < colCount - 1) {\n cells.push(React.createElement(Text, { key: `sep-${r}-${c}`, color: dim }, \" │ \"));\n }\n }\n children.push(React.createElement(Box, { key: `tr-${r}`, flexDirection: \"row\" }, ...cells));\n }\n\n return React.createElement(\n Box,\n { key: `table-${i}`, flexDirection: \"column\", paddingY: 1 },\n React.createElement(\n Box,\n {\n borderStyle: \"classic\" as const,\n borderColor: \"grey\" as const,\n paddingX: 1,\n flexDirection: \"column\",\n },\n ...children,\n ),\n );\n}\n\n/** Render a paragraph block with inline formatting. */\nfunction renderParagraphBlock(block: MarkdownBlock, i: number): ReactNode {\n return React.createElement(Text, { key: `p-${i}` }, renderInline(block.text));\n}\n\n/**\n * Render parsed markdown blocks as Ink elements.\n *\n * Uses a Box with flexDirection=\"column\" as the container so that\n * code blocks (which are Box elements with borders) can coexist with\n * text blocks (which are Text elements).\n */\nexport function renderBlocks(blocks: MarkdownBlock[]): ReactNode {\n const elements: ReactNode[] = [];\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]!;\n\n switch (block.type) {\n case \"heading\":\n elements.push(renderHeadingBlock(block, i));\n break;\n case \"code\":\n elements.push(renderCodeBlock(block, i));\n break;\n case \"blockquote\":\n elements.push(renderBlockquoteBlock(block, i));\n break;\n case \"list_item\":\n elements.push(renderListItemBlock(block, i));\n break;\n case \"diff\":\n elements.push(renderDiffBlock(block, i));\n break;\n case \"hr\":\n elements.push(renderHRBlock(i));\n break;\n case \"table\":\n elements.push(renderTableBlock(block, i));\n break;\n default:\n elements.push(renderParagraphBlock(block, i));\n }\n }\n\n if (elements.length === 0) {\n return React.createElement(Text, null, \"\");\n }\n\n return React.createElement(Box, { flexDirection: \"column\" }, ...elements);\n}\n","/**\n * ChatLog — imperative‑handle message transcript.\n *\n * Exposes a ChatLogHandle with 13 methods for the agent loop to\n * drive the UI. Internally uses React useReducer + forwardRef +\n * useImperativeHandle so parent components never touch raw state.\n *\n * Lifecycle:\n * addUser → startAssistant → updateAssistant × N → finalizeAssistant\n * addUser(pending) → commitPendingUser | dropPendingUser\n * addTool → updateToolResult\n *\n * Design rationale (vs FengMing's 35‑method handle):\n * - Single‑threaded agent loop → no runId routing needed\n * - Local process → no gateway reconnect (reconcilePendingUsers)\n * - reserveAssistantSlot folded into startAssistant\n */\n\nimport React, { useReducer, useImperativeHandle, forwardRef, useRef, useState } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\nimport {\n parseMarkdown,\n renderBlocks,\n renderInline,\n findStableOffset,\n} from \"../renderer/markdown.js\";\n\n// ── Types ──────────────────────────────────────────\n\n/** A single entry in the chat transcript. */\nexport interface ChatLogEntry {\n readonly id: string;\n readonly kind: \"system\" | \"user\" | \"assistant\" | \"tool_use\" | \"tool_result\" | \"btw\" | \"thinking\";\n readonly text: string;\n readonly streaming?: boolean;\n readonly pending?: boolean;\n readonly toolName?: string;\n readonly toolCallId?: string;\n readonly toolStartedAt?: number;\n readonly level?: \"info\" | \"warn\" | \"error\";\n /** Duration in ms for thinking entries (shown as \"已思考 X.Xs\"). */\n readonly durationMs?: number;\n readonly timestamp: number;\n}\n\n/** Imperative handle exposed to the parent (agent loop / App). */\nexport interface ChatLogHandle {\n /** Append a system message (info, warning, or error). */\n addSystem(text: string, level?: \"info\" | \"warn\" | \"error\"): void;\n /** Append a user message, optionally marked as pending (optimistic). */\n addUser(text: string, pending?: boolean): void;\n /** Remove the pending marker from the most recent user message. */\n commitPendingUser(): void;\n /** Remove the pending user message entirely. */\n dropPendingUser(): void;\n /** Create (or update) a streaming assistant message. */\n startAssistant(text?: string): void;\n /** Incrementally update the streaming assistant's text. */\n updateAssistant(text: string): void;\n /** Finalize the streaming assistant message — sets streaming=false. */\n finalizeAssistant(text?: string): void;\n /** Remove the streaming assistant message (on error / abort). */\n dropAssistant(): void;\n /** Append a tool‑use entry. */\n addTool(name: string, callId: string): void;\n /** Update the result of a previously added tool‑use entry. */\n updateToolResult(callId: string, result: string): void;\n /** Show a by‑the‑way hint (non‑conversational guidance). */\n showBtw(text: string): void;\n /** Remove the btw message. */\n dismissBtw(): void;\n /** Show a collapsible thinking entry with duration. Default collapsed, Enter toggles. */\n showThinking(text: string, durationMs: number): void;\n /** Remove the thinking message. */\n dismissThinking(): void;\n /** Clear the entire transcript. */\n clearAll(): void;\n /** Return the total number of entries (for scroll calculation). */\n getEntryCount(): number;\n}\n\n/** Props passed to the ChatLog component. */\nexport interface ChatLogProps {\n readonly visibleRange?: { readonly start: number; readonly end: number };\n /** Called when search mode is toggled (so parent can disable InputBox). */\n readonly onSearchActiveChange?: (active: boolean) => void;\n /** Transcript display mode: compact hides timestamps, full shows them + expanded content. */\n readonly transcriptMode?: \"compact\" | \"full\";\n}\n\n// ── State ──────────────────────────────────────────\n\n/** Internal state managed by the ChatLog reducer. */\nexport interface ChatLogState {\n entries: ChatLogEntry[];\n nextId: number;\n}\n\n/** Action discriminated union for the ChatLog reducer. */\nexport type ChatLogAction =\n | { kind: \"ADD_SYSTEM\"; text: string; level?: \"info\" | \"warn\" | \"error\" }\n | { kind: \"ADD_USER\"; text: string; pending?: boolean }\n | { kind: \"COMMIT_PENDING_USER\" }\n | { kind: \"DROP_PENDING_USER\" }\n | { kind: \"START_ASSISTANT\"; text?: string }\n | { kind: \"UPDATE_ASSISTANT\"; text: string }\n | { kind: \"FINALIZE_ASSISTANT\"; text?: string }\n | { kind: \"DROP_ASSISTANT\" }\n | { kind: \"ADD_TOOL\"; name: string; callId: string }\n | { kind: \"UPDATE_TOOL_RESULT\"; callId: string; result: string }\n | { kind: \"SHOW_BTW\"; text: string }\n | { kind: \"DISMISS_BTW\" }\n | { kind: \"SHOW_THINKING\"; text: string; durationMs: number }\n | { kind: \"DISMISS_THINKING\" }\n | { kind: \"CLEAR_ALL\" };\n\nfunction nextId(state: ChatLogState): string {\n return `cl-${state.nextId}`;\n}\n\nfunction entry(\n state: ChatLogState,\n kind: ChatLogEntry[\"kind\"],\n text: string,\n extra?: Partial<ChatLogEntry>,\n): ChatLogEntry {\n return { id: nextId(state), kind, text, timestamp: Date.now(), ...extra };\n}\n\n// ── Reducer action handlers ───────────────────────\n\nfunction reduceAddSystem(\n state: ChatLogState,\n text: string,\n level?: \"info\" | \"warn\" | \"error\",\n): ChatLogState {\n const entries = [...state.entries];\n entries.push(entry(state, \"system\", text, { level: level ?? \"info\" }));\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceAddUser(state: ChatLogState, text: string, pending?: boolean): ChatLogState {\n const entries = [...state.entries];\n entries.push(entry(state, \"user\", text, { pending: pending ?? false }));\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceCommitPendingUser(state: ChatLogState): ChatLogState {\n const entries = [...state.entries];\n for (let i = entries.length - 1; i >= 0; i--) {\n if (entries[i]!.kind === \"user\" && entries[i]!.pending) {\n entries[i] = { ...entries[i]!, pending: false };\n break;\n }\n }\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceDropPendingUser(state: ChatLogState): ChatLogState {\n const entries = [...state.entries];\n const idx = entries.findLastIndex((e) => e.kind === \"user\" && e.pending);\n if (idx !== -1) entries.splice(idx, 1);\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceStartAssistant(state: ChatLogState, text?: string): ChatLogState {\n const entries = [...state.entries];\n const existing = entries.findLastIndex((e) => e.kind === \"assistant\" && e.streaming);\n const newEntry = entry(state, \"assistant\", text ?? \"\", { streaming: true });\n if (existing !== -1) {\n entries[existing] = newEntry;\n return { entries, nextId: state.nextId };\n }\n entries.push(newEntry);\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceUpdateAssistant(state: ChatLogState, text: string): ChatLogState {\n const entries = [...state.entries];\n for (let i = entries.length - 1; i >= 0; i--) {\n if (entries[i]!.kind === \"assistant\" && entries[i]!.streaming) {\n entries[i] = { ...entries[i]!, text: entries[i]!.text + text };\n break;\n }\n }\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceFinalizeAssistant(state: ChatLogState, text?: string): ChatLogState {\n const entries = [...state.entries];\n for (let i = entries.length - 1; i >= 0; i--) {\n if (entries[i]!.kind === \"assistant\" && entries[i]!.streaming) {\n entries[i] = { ...entries[i]!, text: text ?? entries[i]!.text, streaming: false };\n break;\n }\n }\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceDropAssistant(state: ChatLogState): ChatLogState {\n const entries = [...state.entries];\n const idx = entries.findLastIndex((e) => e.kind === \"assistant\" && e.streaming);\n if (idx !== -1) entries.splice(idx, 1);\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceAddTool(state: ChatLogState, name: string, callId: string): ChatLogState {\n const entries = [...state.entries];\n entries.push(\n entry(state, \"tool_use\", name, {\n toolName: name,\n toolCallId: callId,\n toolStartedAt: Date.now(),\n }),\n );\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceUpdateToolResult(state: ChatLogState, callId: string, result: string): ChatLogState {\n const entries = [...state.entries];\n let nextId = state.nextId;\n for (let i = entries.length - 1; i >= 0; i--) {\n const e = entries[i]!;\n if (e.kind === \"tool_use\" && e.toolCallId === callId) {\n const duration = e.toolStartedAt ? ((Date.now() - e.toolStartedAt) / 1000).toFixed(1) : \"?\";\n // Store result text + duration on the tool_use entry for rendering\n entries[i] = {\n ...e,\n text: `${e.toolName ?? \"tool\"} · ${duration}s`,\n };\n // Add compact tool_result entry with the actual result\n entries.push(entry(state, \"tool_result\", result, { toolCallId: callId }));\n nextId++;\n break;\n }\n }\n return { entries, nextId };\n}\n\nfunction reduceShowBtw(state: ChatLogState, text: string): ChatLogState {\n const entries = [...state.entries];\n const existing = entries.findLastIndex((e) => e.kind === \"btw\");\n if (existing !== -1) entries.splice(existing, 1);\n entries.push(entry(state, \"btw\", text));\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceDismissBtw(state: ChatLogState): ChatLogState {\n const entries = [...state.entries];\n const idx = entries.findLastIndex((e) => e.kind === \"btw\");\n if (idx !== -1) entries.splice(idx, 1);\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceShowThinking(state: ChatLogState, text: string, durationMs: number): ChatLogState {\n const entries = [...state.entries];\n entries.push(entry(state, \"thinking\", text, { durationMs }));\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceDismissThinking(state: ChatLogState): ChatLogState {\n const entries = [...state.entries];\n const idx = entries.findLastIndex((e) => e.kind === \"thinking\");\n if (idx !== -1) entries.splice(idx, 1);\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceClearAll(): ChatLogState {\n return { entries: [], nextId: 0 };\n}\n\n/** Pure reducer for ChatLog state — exported for testing. */\nexport function chatLogReducer(state: ChatLogState, action: ChatLogAction): ChatLogState {\n switch (action.kind) {\n case \"ADD_SYSTEM\":\n return reduceAddSystem(state, action.text, action.level);\n case \"ADD_USER\":\n return reduceAddUser(state, action.text, action.pending);\n case \"COMMIT_PENDING_USER\":\n return reduceCommitPendingUser(state);\n case \"DROP_PENDING_USER\":\n return reduceDropPendingUser(state);\n case \"START_ASSISTANT\":\n return reduceStartAssistant(state, action.text);\n case \"UPDATE_ASSISTANT\":\n return reduceUpdateAssistant(state, action.text);\n case \"FINALIZE_ASSISTANT\":\n return reduceFinalizeAssistant(state, action.text);\n case \"DROP_ASSISTANT\":\n return reduceDropAssistant(state);\n case \"ADD_TOOL\":\n return reduceAddTool(state, action.name, action.callId);\n case \"UPDATE_TOOL_RESULT\":\n return reduceUpdateToolResult(state, action.callId, action.result);\n case \"SHOW_BTW\":\n return reduceShowBtw(state, action.text);\n case \"DISMISS_BTW\":\n return reduceDismissBtw(state);\n case \"SHOW_THINKING\":\n return reduceShowThinking(state, action.text, action.durationMs);\n case \"DISMISS_THINKING\":\n return reduceDismissThinking(state);\n case \"CLEAR_ALL\":\n return reduceClearAll();\n }\n}\n\n// ── Constants ──────────────────────────────────────\n\nconst MAX_VISIBLE = 50;\n/** Characters beyond which a tool_result is collapsed by default. */\nconst TOOL_RESULT_COLLAPSE_LEN = 1000;\n\n// ── Component ──────────────────────────────────────\n\n/** ChatLog component — renders the message transcript driven by a handle. */\nexport const ChatLog = forwardRef<ChatLogHandle, ChatLogProps>(function ChatLog(\n { visibleRange, onSearchActiveChange, transcriptMode = \"compact\" },\n ref,\n): React.ReactElement {\n const [state, dispatch] = useReducer(chatLogReducer, { entries: [], nextId: 0 });\n const theme = getTheme();\n\n // Keep a ref to the latest state so useImperativeHandle's stale closure\n // (with [] deps) can still read current values.\n const stateRef = useRef(state);\n stateRef.current = state;\n\n // ── Expand/collapse state ──\n const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set());\n\n // ── Search state ──\n const [searchActive, setSearchActive] = useState(false);\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [searchMatchIdx, setSearchMatchIdx] = useState(0);\n\n // Refs for values read inside useInkInput (stale‑closure safety)\n const searchActiveRef = useRef(searchActive);\n searchActiveRef.current = searchActive;\n const stateForInputRef = useRef(state);\n stateForInputRef.current = state;\n\n /** Toggle search mode and notify parent (so InputBox can be disabled). */\n function setSearchMode(active: boolean): void {\n searchActiveRef.current = active;\n setSearchActive(active);\n if (!active) {\n setSearchQuery(\"\");\n setSearchMatchIdx(0);\n }\n onSearchActiveChange?.(active);\n }\n\n // ── Keyboard ────────────────────────────────────\n useInkInput((input: string, key: Key) => {\n // Ctrl+F → toggle search\n if (key.ctrl && !key.meta && input === \"f\") {\n setSearchMode(!searchActiveRef.current);\n return;\n }\n\n // When search is active, capture all keys for search\n if (searchActiveRef.current) {\n if (key.escape) {\n setSearchMode(false);\n return;\n }\n if (key.backspace || key.delete) {\n setSearchQuery((prev) => prev.slice(0, -1));\n setSearchMatchIdx(0);\n return;\n }\n if (key.upArrow) {\n setSearchMatchIdx((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setSearchMatchIdx((prev) => prev + 1); // clamped in render\n return;\n }\n // Printable character\n if (input && input.length === 1 && !key.ctrl && !key.meta) {\n setSearchQuery((prev) => prev + input);\n setSearchMatchIdx(0);\n return;\n }\n return;\n }\n\n // Ctrl+E → toggle expand/collapse for all tool results\n if (key.ctrl && !key.meta && input === \"e\") {\n const curState = stateForInputRef.current;\n const collapsible = curState.entries.filter(\n (e) => e.kind === \"tool_result\" && e.text.length > TOOL_RESULT_COLLAPSE_LEN,\n );\n if (collapsible.length === 0) return;\n setExpandedIds((prev) => {\n const next = new Set(prev);\n const allExpanded = collapsible.every((e) => next.has(e.id));\n if (allExpanded) {\n for (const e of collapsible) next.delete(e.id);\n } else {\n for (const e of collapsible) next.add(e.id);\n }\n return next;\n });\n return;\n }\n\n // Enter → toggle expand/collapse for the most recent thinking entry\n if (key.return && !key.ctrl && !key.meta) {\n const curState = stateForInputRef.current;\n const thinkingEntry = curState.entries.findLast((e) => e.kind === \"thinking\");\n if (thinkingEntry) {\n setExpandedIds((prev) => {\n const next = new Set(prev);\n if (next.has(thinkingEntry.id)) {\n next.delete(thinkingEntry.id);\n } else {\n next.add(thinkingEntry.id);\n }\n return next;\n });\n return;\n }\n }\n });\n\n useImperativeHandle(\n ref,\n (): ChatLogHandle => ({\n addSystem(text, level) {\n dispatch({ kind: \"ADD_SYSTEM\", text, level });\n },\n addUser(text, pending) {\n dispatch({ kind: \"ADD_USER\", text, pending });\n },\n commitPendingUser() {\n dispatch({ kind: \"COMMIT_PENDING_USER\" });\n },\n dropPendingUser() {\n dispatch({ kind: \"DROP_PENDING_USER\" });\n },\n startAssistant(text) {\n dispatch({ kind: \"START_ASSISTANT\", text });\n },\n updateAssistant(text) {\n dispatch({ kind: \"UPDATE_ASSISTANT\", text });\n },\n finalizeAssistant(text) {\n dispatch({ kind: \"FINALIZE_ASSISTANT\", text });\n },\n dropAssistant() {\n dispatch({ kind: \"DROP_ASSISTANT\" });\n },\n addTool(name, callId) {\n dispatch({ kind: \"ADD_TOOL\", name, callId });\n },\n updateToolResult(callId, result) {\n dispatch({ kind: \"UPDATE_TOOL_RESULT\", callId, result });\n },\n showBtw(text) {\n dispatch({ kind: \"SHOW_BTW\", text });\n },\n dismissBtw() {\n dispatch({ kind: \"DISMISS_BTW\" });\n },\n showThinking(text, durationMs) {\n dispatch({ kind: \"SHOW_THINKING\", text, durationMs });\n },\n dismissThinking() {\n dispatch({ kind: \"DISMISS_THINKING\" });\n },\n clearAll() {\n dispatch({ kind: \"CLEAR_ALL\" });\n },\n getEntryCount() {\n return stateRef.current.entries.length;\n },\n }),\n [],\n );\n\n // Determine which entries to render\n const { entries } = state;\n const windowed = visibleRange\n ? entries.slice(visibleRange.start, visibleRange.end)\n : entries.slice(-MAX_VISIBLE);\n\n if (windowed.length === 0) {\n return React.createElement(\n Box,\n { flexDirection: \"column\", paddingY: 2 },\n // LogoHeader — Lynx brand logo shown on first launch before any messages\n React.createElement(\n Box,\n { flexDirection: \"column\", marginBottom: 1 },\n React.createElement(\n Text,\n { color: theme.colors.accent, bold: true },\n \" ╦ ╦ ═╗ ╦ ═╗ ═╗ ╦\",\n ),\n React.createElement(\n Text,\n { color: theme.colors.accent, bold: true },\n \" ║ ║ ║ ║ ║ ╚╗║\",\n ),\n React.createElement(\n Text,\n { color: theme.colors.accent, bold: true },\n \" ╚═╝ ╩ ═╝ ╩ ═╝ ═╝ ╩\",\n ),\n ),\n React.createElement(\n Text,\n { dimColor: true },\n \" 输入消息开始对话 · /help 查看命令 · Tab 切换模式\",\n ),\n );\n }\n\n // StickyPromptHeader — when scrolled up (not at bottom), show the last user prompt\n const isScrolledUp = visibleRange && visibleRange.end < stateRef.current.entries.length;\n const stickyHeader: React.ReactElement | null = isScrolledUp\n ? React.createElement(\n Box,\n { flexDirection: \"row\", marginBottom: 1 },\n React.createElement(Text, { dimColor: true }, \"↑ 已滚动 · 最后提示: \"),\n React.createElement(\n Text,\n { dimColor: true, bold: true },\n (() => {\n // Find the last user message before the visible range\n for (let i = visibleRange!.end - 1; i >= 0; i--) {\n const entry = stateRef.current.entries[i];\n if (entry?.kind === \"user\") {\n const firstLine = entry.text.split(\"\\n\")[0] ?? \"\";\n return firstLine.length > 60 ? firstLine.slice(0, 57) + \"...\" : firstLine;\n }\n }\n return \"(无)\";\n })(),\n ),\n )\n : null;\n\n // ── Compute search matches ──\n const searchMatches: SearchMatch[] = [];\n if (searchActive && searchQuery) {\n const lower = searchQuery.toLowerCase();\n for (const entry of windowed) {\n let idx = 0;\n const lowerText = entry.text.toLowerCase();\n while ((idx = lowerText.indexOf(lower, idx)) !== -1) {\n searchMatches.push({\n entryId: entry.id,\n start: idx,\n text: entry.text.slice(idx, idx + searchQuery.length),\n });\n idx += lower.length;\n }\n }\n }\n\n // Clamp match index (wraps around on overflow)\n const clampedMatchIdx =\n searchMatches.length > 0\n ? ((searchMatchIdx % searchMatches.length) + searchMatches.length) % searchMatches.length\n : 0;\n\n // Active (highlighted) match entry id\n const activeMatchEntryId =\n searchMatches.length > 0 ? searchMatches[clampedMatchIdx]!.entryId : null;\n\n // ── Render entries ──\n const elements: React.ReactElement[] = [];\n\n for (const entry of windowed) {\n const isExpanded = expandedIds.has(entry.id);\n const entryMatchIndices = searchActive\n ? searchMatches.filter((m) => m.entryId === entry.id).map((m) => m.start)\n : [];\n\n elements.push(\n React.createElement(\n Box,\n {\n key: entry.id,\n flexDirection: \"column\",\n marginBottom: entry.kind === \"btw\" ? 0 : 1,\n },\n // Timestamp row in full transcript mode\n transcriptMode === \"full\"\n ? React.createElement(\n Text,\n { dimColor: true },\n `── ${new Date(entry.timestamp).toLocaleTimeString()} · ${kindLabel(entry.kind)} ──`,\n )\n : null,\n ...renderEntryContent(\n entry,\n isExpanded,\n activeMatchEntryId === entry.id ? clampedMatchIdx : -1,\n entryMatchIndices,\n searchQuery,\n theme,\n ),\n ),\n );\n }\n\n // ── Search bar ──\n const searchBar = searchActive\n ? React.createElement(\n Box,\n { flexDirection: \"row\", paddingTop: 1 },\n React.createElement(Text, { color: theme.colors.accent, bold: true }, \"🔍 \"),\n React.createElement(\n Text,\n null,\n searchQuery || React.createElement(Text, { dimColor: true }, \"输入搜索内容\"),\n ),\n React.createElement(Text, { dimColor: true }, \"█\"),\n searchMatches.length > 0\n ? React.createElement(\n Text,\n { dimColor: true },\n ` ${clampedMatchIdx + 1}/${searchMatches.length}`,\n )\n : searchQuery\n ? React.createElement(Text, { dimColor: true }, \" 无匹配\")\n : React.createElement(Text, { dimColor: true }, \" Esc 关闭\"),\n )\n : null;\n\n return React.createElement(\n Box,\n { flexDirection: \"column\" },\n stickyHeader,\n ...elements,\n searchBar,\n );\n});\n\n// ── Search types ──────────────────────────────────\n\ninterface SearchMatch {\n entryId: string;\n start: number;\n text: string;\n}\n\n// ── Render helpers ─────────────────────────────────\n\nfunction entryColor(entry: ChatLogEntry, colors: Record<string, string>): string | undefined {\n switch (entry.kind) {\n case \"system\":\n return entry.level === \"error\"\n ? colors.error\n : entry.level === \"warn\"\n ? colors.warning\n : colors.dimmed;\n case \"user\":\n return entry.pending ? colors.dimmed : colors.foreground;\n case \"assistant\":\n return entry.streaming ? colors.foreground : colors.foreground;\n case \"tool_use\":\n return colors.info ?? \"yellow\";\n case \"tool_result\":\n return colors.dimmed;\n case \"btw\":\n return colors.accent;\n case \"thinking\":\n return colors.dimmed;\n default:\n return undefined;\n }\n}\n\n/** Map entry kind to a Chinese label for display. */\nfunction kindLabel(kind: ChatLogEntry[\"kind\"]): string {\n switch (kind) {\n case \"system\":\n return \"系统\";\n case \"user\":\n return \"用户\";\n case \"assistant\":\n return \"助手\";\n case \"tool_use\":\n return \"工具调用\";\n case \"tool_result\":\n return \"工具结果\";\n case \"btw\":\n return \"提示\";\n case \"thinking\":\n return \"思考\";\n }\n}\n\nfunction entryPrefix(entry: ChatLogEntry): string {\n switch (entry.kind) {\n case \"system\":\n return entry.level === \"error\" ? \"✘ \" : entry.level === \"warn\" ? \"⚠ \" : \"─ \";\n case \"user\":\n return entry.pending ? \"[发送中] \" : \"> \";\n case \"assistant\":\n return \"\";\n case \"tool_use\":\n return \"\";\n case \"tool_result\":\n return \"\";\n case \"btw\":\n return \"💡 \";\n case \"thinking\":\n return \"💭 \";\n default:\n return \"\";\n }\n}\n\n// ── Per‑entry renderers ───────────────────────────\n\n/**\n * Render the content lines for a single chat entry.\n *\n * Returns an array of React elements suitable as children of a Box.\n * Each entry kind gets its own rendering strategy:\n * - assistant → full markdown (parseMarkdown + renderBlocks)\n * - system → renderInline for formatting\n * - user → renderInline for formatting\n * - tool_use → plain text with prefix\n * - tool_result → renderInline, collapsible beyond TOOL_RESULT_COLLAPSE_LEN\n * - btw → renderInline\n */\nfunction renderEntryContent(\n entry: ChatLogEntry,\n isExpanded: boolean,\n activeMatchGlobalIdx: number,\n entryMatchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n switch (entry.kind) {\n case \"assistant\":\n return renderAssistant(entry, entryMatchIndices, searchQuery, theme);\n case \"system\":\n return renderSystem(entry, entryMatchIndices, searchQuery, theme);\n case \"user\":\n return renderUser(entry, entryMatchIndices, searchQuery, theme);\n case \"tool_use\":\n return renderToolUse(entry, entryMatchIndices, searchQuery, theme);\n case \"tool_result\":\n return renderToolResult(entry, isExpanded, entryMatchIndices, searchQuery, theme);\n case \"btw\":\n return renderBtw(entry, entryMatchIndices, searchQuery, theme);\n case \"thinking\":\n return renderThinking(entry, isExpanded, theme);\n default:\n return [\n React.createElement(\n Text,\n { key: \"text\", color: entryColor(entry, theme.colors) },\n entry.text,\n ),\n ];\n }\n}\n\n// ── Render: assistant (full markdown) ──────────────\n\nfunction renderAssistant(\n entry: ChatLogEntry,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const elements: React.ReactElement[] = [];\n\n if (entry.streaming) {\n // Streaming: render stable portion as markdown, unstable as plain text + cursor\n const stableOffset = findStableOffset(entry.text);\n const stablePart = entry.text.slice(0, stableOffset);\n const unstablePart = entry.text.slice(stableOffset);\n\n if (stablePart) {\n const blocks = parseMarkdown(stablePart);\n elements.push(\n React.createElement(Box, { key: \"stable\", flexDirection: \"column\" }, renderBlocks(blocks)),\n );\n }\n if (unstablePart) {\n elements.push(\n React.createElement(\n Text,\n { key: \"streaming\", color: theme.colors.foreground },\n highlightMatches(unstablePart, matchIndices, searchQuery),\n React.createElement(Text, null, \"▊\"),\n ),\n );\n } else if (!stablePart) {\n // No stable content yet — show cursor on empty\n elements.push(\n React.createElement(Text, { key: \"streaming\", color: theme.colors.foreground }, \"▊\"),\n );\n }\n } else {\n // Finalized: render full markdown\n const blocks = parseMarkdown(entry.text);\n if (blocks.length > 0) {\n elements.push(\n React.createElement(Box, { key: \"md\", flexDirection: \"column\" }, renderBlocks(blocks)),\n );\n }\n }\n\n return elements;\n}\n\n// ── Render: system (inline formatting) ─────────────\n\nfunction renderSystem(\n entry: ChatLogEntry,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const color = entryColor(entry, theme.colors);\n const prefix = entryPrefix(entry);\n const content = highlightMatches(entry.text, matchIndices, searchQuery);\n\n return [\n React.createElement(Text, { key: \"content\", color }, prefix, renderInlineContent(content)),\n ];\n}\n\n// ── Render: user (inline formatting) ───────────────\n\nfunction renderUser(\n entry: ChatLogEntry,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const color = entryColor(entry, theme.colors);\n const prefix = entryPrefix(entry);\n const suffix = entry.pending ? \"…\" : \"\";\n\n return [\n React.createElement(\n Text,\n { key: \"content\", color },\n prefix,\n renderInlineContent(highlightMatches(entry.text, matchIndices, searchQuery)),\n suffix,\n ),\n ];\n}\n\n// ── Render: tool_use (plain text) ──────────────────\n\nfunction renderToolUse(\n entry: ChatLogEntry,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const isDone = entry.toolStartedAt !== undefined && entry.text.includes(\"·\");\n const prefix = isDone ? \"✓ \" : \"✽ \";\n const color = isDone ? theme.colors.success : theme.colors.accent;\n const suffix = isDone ? \"\" : \"…\";\n\n return [\n React.createElement(\n Text,\n { key: \"content\", color },\n prefix,\n highlightMatches(entry.text + suffix, matchIndices, searchQuery),\n ),\n ];\n}\n\n// ── Render: tool_result (inline, collapsible) ──────\n\n/**\n * Collapse multi-line content into a single line for inline display.\n * Replaces consecutive whitespace (including newlines) with a single space.\n */\nfunction collapseWhitespace(text: string): string {\n return text.replace(/\\s+/g, \" \").trim();\n}\n\nfunction renderToolResult(\n entry: ChatLogEntry,\n isExpanded: boolean,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const color = theme.colors.foreground;\n // Always collapse newlines — multi-line JSON would break the terminal layout\n const collapsed = collapseWhitespace(entry.text);\n const isLong = collapsed.length > TOOL_RESULT_COLLAPSE_LEN;\n const elements: React.ReactElement[] = [];\n\n if (isLong && !isExpanded) {\n const truncated = collapsed.slice(0, TOOL_RESULT_COLLAPSE_LEN);\n elements.push(\n React.createElement(\n Text,\n { key: \"content\", color, dimColor: true },\n \" ⎿ \",\n renderInlineContent(highlightMatches(truncated, matchIndices, searchQuery)),\n React.createElement(\n Text,\n { key: \"ellipsis\", dimColor: true },\n `… [+${collapsed.length - TOOL_RESULT_COLLAPSE_LEN} 字符, Ctrl+E 展开]`,\n ),\n ),\n );\n } else {\n elements.push(\n React.createElement(\n Text,\n { key: \"content\", color, dimColor: true },\n \" ⎿ \",\n renderInlineContent(highlightMatches(collapsed, matchIndices, searchQuery)),\n isLong\n ? React.createElement(Text, { key: \"collapse\", dimColor: true }, \" [Ctrl+E 折叠]\")\n : null,\n ),\n );\n }\n\n return elements;\n}\n\n// ── Render: btw (inline formatting) ────────────────\n\nfunction renderBtw(\n entry: ChatLogEntry,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const color = entryColor(entry, theme.colors);\n const prefix = entryPrefix(entry);\n\n return [\n React.createElement(\n Text,\n { key: \"content\", color },\n prefix,\n renderInlineContent(highlightMatches(entry.text, matchIndices, searchQuery)),\n ),\n ];\n}\n\n/**\n * Render a thinking entry — collapsed shows \"已思考 X.Xs · Enter 展开\",\n * expanded shows the full reasoning text.\n */\nfunction renderThinking(\n entry: ChatLogEntry,\n isExpanded: boolean,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const color = entryColor(entry, theme.colors);\n const prefix = entryPrefix(entry);\n const seconds = entry.durationMs != null ? (entry.durationMs / 1000).toFixed(1) : \"?\";\n\n if (isExpanded) {\n // Expanded: show full reasoning text\n const lines = entry.text.trim().split(\"\\n\");\n return lines.map((line, i) =>\n React.createElement(\n Text,\n { key: `think-${i}`, color },\n i === 0 ? `${prefix}已思考 ${seconds}s · Enter 折叠` : prefix,\n line || \" \",\n ),\n );\n }\n\n // Collapsed: show summary only\n return [\n React.createElement(\n Text,\n { key: \"summary\", color, dimColor: true },\n `${prefix}已思考 ${seconds}s · Enter 展开`,\n ),\n ];\n}\n\n// ── Inline formatting + search highlighting ────────\n\n/**\n * Render text with inline markdown formatting.\n *\n * Wraps `renderInline` but handles the case where the input is\n * a mix of plain strings and Ink elements (from search highlighting).\n */\nfunction renderInlineContent(content: React.ReactNode): React.ReactNode {\n if (typeof content === \"string\") {\n return renderInline(content);\n }\n // Already wrapped in elements (from highlightMatches) — return as‑is\n return content;\n}\n\n/**\n * Highlight search query matches in text.\n *\n * When no search is active (matchIndices is empty), returns the plain text.\n * With matches, wraps each match in an inverse‑colored `<Text>` span.\n */\nfunction highlightMatches(text: string, matchIndices: number[], query: string): React.ReactNode {\n if (!query || matchIndices.length === 0) return text;\n\n const len = query.length;\n // Sort and deduplicate match positions\n const sorted = [...new Set(matchIndices)].sort((a, b) => a - b);\n\n const children: React.ReactNode[] = [];\n let cursor = 0;\n\n for (const start of sorted) {\n if (start < cursor) continue; // overlapping match — skip\n // Text before match\n if (start > cursor) {\n children.push(text.slice(cursor, start));\n }\n // Highlighted match\n children.push(\n React.createElement(\n Text,\n { key: `hl-${start}`, inverse: true },\n text.slice(start, start + len),\n ),\n );\n cursor = start + len;\n }\n\n // Trailing text\n if (cursor < text.length) {\n children.push(text.slice(cursor));\n }\n\n // Optimize: if only one child and it's a string, return it directly\n if (children.length === 1 && typeof children[0] === \"string\") {\n return children[0];\n }\n\n return children;\n}\n","/**\n * FrameRateLimiter — throttle Ink re‑renders to ~30 FPS via microtask batching.\n *\n * Ink renders on every state change. For high‑frequency updates (streaming\n * text deltas, tool output), this can cause excessive re‑renders.\n * FrameRateLimiter coalesces state updates within a 16 ms window.\n *\n * Design (§5.9i):\n * - 30 fps throttle (~33 ms frame budget, 16 ms coalesce window)\n * - In‑memory transcript cache for static entries\n * - React.memo on static message blocks\n */\n\n/** Default target frame interval in ms (30 fps ≈ 33 ms). */\nconst DEFAULT_FRAME_MS = 33;\n\n/**\n * Simple frame‑rate limiter.\n *\n * Uses a pending flag and microtask scheduling to ensure\n * callbacks fire at most once per `frameMs` window.\n */\nexport class FrameRateLimiter {\n private lastFrame = 0;\n private pending = false;\n private readonly frameMs: number;\n\n constructor(frameMs: number = DEFAULT_FRAME_MS) {\n this.frameMs = frameMs;\n }\n\n /**\n * Schedule a callback to run on the next available frame.\n *\n * If a callback was already scheduled within the current frame window,\n * the new callback replaces it (last‑writer‑wins semantics).\n */\n schedule(fn: () => void): void {\n const now = Date.now();\n const elapsed = now - this.lastFrame;\n\n if (elapsed >= this.frameMs) {\n // Enough time has passed — run immediately\n this.lastFrame = now;\n this.pending = false;\n fn();\n } else if (!this.pending) {\n // Schedule for the remaining time in the frame\n this.pending = true;\n const delay = this.frameMs - elapsed;\n setTimeout(() => {\n this.lastFrame = Date.now();\n this.pending = false;\n fn();\n }, delay);\n }\n // else: already pending — drop (last‑writer‑wins would need a stored callback)\n }\n\n /** Reset the limiter state. */\n reset(): void {\n this.lastFrame = 0;\n this.pending = false;\n }\n}\n\n/**\n * Create a transcript cache key for stable React.memo comparison.\n *\n * Static messages (non‑streaming, non‑pending) can be memoized\n * since their rendered output never changes.\n */\nexport function transcriptCacheKey(\n entryId: string,\n isStreaming: boolean,\n isPending: boolean,\n): string {\n if (isStreaming || isPending) return `${entryId}:dynamic`;\n return `${entryId}:static`;\n}\n\n/**\n * Default frame rate limiter instance for transcript rendering.\n *\n * Created once per ChatLog mount to throttle streaming updates.\n */\nexport function createFrameRateLimiter(frameMs?: number): FrameRateLimiter {\n return new FrameRateLimiter(frameMs);\n}\n","/**\n * VimStatusBar — 显示当前 Vim 模式和按键提示。\n * 从 InputBox 提取出的独立子组件。\n */\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\n\nexport interface VimStatusBarProps {\n vimEnabled: boolean;\n /** Vim 编辑模式(insert / normal / visual) */\n vimMode: string;\n}\n\nexport function VimStatusBar({\n vimEnabled,\n vimMode,\n}: VimStatusBarProps): React.ReactElement | null {\n if (!vimEnabled) return null;\n const label =\n vimMode === \"insert\" ? \"-- 插入 --\" : vimMode === \"normal\" ? \"-- 普通 --\" : \"-- 可视 --\";\n const color = vimMode === \"insert\" ? \"green\" : vimMode === \"normal\" ? \"yellow\" : \"cyan\";\n return React.createElement(Box, {}, React.createElement(Text, { color }, label));\n}\n","/**\n * SuggestionsOverlay — 自动补全浮层。\n * 绝对定位在输入框上方,显示匹配的补全选项列表。\n * 从 InputBox 提取出的独立子组件。\n */\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\n\nexport interface SuggestionsOverlayProps {\n completions: string[];\n completionIndex: number;\n}\n\nexport function SuggestionsOverlay({\n completions,\n completionIndex,\n}: SuggestionsOverlayProps): React.ReactElement | null {\n if (completions.length === 0) return null;\n return React.createElement(\n Box,\n { flexDirection: \"column\" },\n ...completions.map((item, index) =>\n React.createElement(\n Box,\n { key: item },\n React.createElement(\n Text,\n {\n color: index === completionIndex ? \"cyan\" : undefined,\n inverse: index === completionIndex,\n },\n `${index === completionIndex ? \"> \" : \" \"}${item}`,\n ),\n ),\n ),\n );\n}\n","/**\n * InputFooter — 输入区域底部状态行。\n * 显示 Vim 模式、输入值预览、禁用状态。\n * 从 InputBox 提取出的独立子组件。\n */\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\n\nexport interface InputFooterProps {\n vimEnabled: boolean;\n vimMode: string;\n value: string;\n disabled: boolean;\n}\n\nexport function InputFooter({\n vimEnabled,\n vimMode,\n value,\n disabled,\n}: InputFooterProps): React.ReactElement {\n const children: React.ReactNode[] = [];\n if (vimEnabled) {\n children.push(React.createElement(Text, { key: \"vim\", dimColor: true }, vimMode));\n }\n if (disabled) {\n children.push(React.createElement(Text, { key: \"disabled\", color: \"red\" }, \" 输入已禁用\"));\n }\n if (!disabled && value.length > 0) {\n children.push(\n React.createElement(Text, { key: \"count\", dimColor: true }, ` ${value.length} 字符`),\n );\n }\n return React.createElement(Box, {}, ...children);\n}\n","/**\n * InputBox — multi‑line REPL input with history, autocomplete, and routing.\n *\n * Features:\n * - Multi‑line input (Enter submits, Ctrl+Enter inserts newline)\n * - History navigation (Up/Down, 200 items, deduped, persisted to disk)\n * - Slash command autocomplete (8 suggestions max)\n * - @‑mention file path autocomplete (8 suggestions max)\n * - Submit routing: !bang → shell, / → command, text → message\n * - Full cursor movement: Home/End, Ctrl+A/E/K/W, ←/→\n * - 3‑layer abort counter (tracked in parent)\n *\n * Design:\n * Single useInkInput handler manages all keyboard behaviour.\n * Renders last MAX_VISIBLE_LINES of the input with a ❯ prompt.\n */\n\nimport React, { useState, useRef, useCallback, useEffect } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { readdirSync, statSync, readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { join, relative, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { getTheme } from \"../theme/theme.js\";\nimport { VimStatusBar } from \"./VimStatusBar.js\";\nimport { SuggestionsOverlay } from \"./SuggestionsOverlay.js\";\nimport { InputFooter } from \"./InputFooter.js\";\n\n// ── Constants ──────────────────────────────────\n\nconst MAX_HISTORY = 200;\nconst MAX_VISIBLE_LINES = 5;\n/** Max autocomplete suggestions displayed. */\nconst MAX_COMPLETIONS = 8;\n\n/** Built‑in slash commands for autocomplete. */\nconst SLASH_COMMANDS: string[] = [\n \"/sessions\",\n \"/new\",\n \"/fork\",\n \"/rename\",\n \"/delete\",\n \"/resume\",\n \"/config\",\n \"/settings\",\n \"/doctor\",\n \"/theme\",\n \"/model\",\n \"/compact\",\n \"/help\",\n \"/mcp\",\n \"/plugin\",\n \"/skills\",\n \"/context\",\n \"/usage\",\n \"/tasks\",\n \"/snapshots\",\n \"/stash\",\n \"/diff\",\n];\n\n/** Path to the persisted input history file. */\nconst HISTORY_FILE = join(homedir(), \".lynx\", \"input-history.json\");\n\n// ── File listing (for @‑mention autocomplete) ───\n\n/**\n * Recursively list files in a directory, relative to the workspace root.\n * Returns at most `maxResults` entries. Directories are suffixed with `/`.\n */\nfunction listFilesRecursive(dir: string, workspace: string, maxResults: number): string[] {\n const results: string[] = [];\n const stack: string[] = [dir];\n\n while (stack.length > 0 && results.length < maxResults) {\n const current = stack.pop()!;\n let entries: string[];\n try {\n entries = readdirSync(current);\n } catch {\n continue; // skip unreadable directories\n }\n\n for (const name of entries) {\n if (results.length >= maxResults) break;\n if (name.startsWith(\".\") || name === \"node_modules\") continue;\n\n const fullPath = join(current, name);\n let stat;\n try {\n stat = statSync(fullPath);\n } catch {\n continue;\n }\n\n const relativePath = relative(workspace, fullPath).replace(/\\\\/g, \"/\");\n if (stat.isDirectory()) {\n results.push(relativePath + \"/\");\n stack.push(fullPath);\n } else {\n results.push(relativePath);\n }\n }\n }\n\n return results.sort((a, b) => a.length - b.length);\n}\n\n/**\n * Match file paths for @‑mention autocomplete.\n *\n * `trigger` is the text after `@` (e.g., `\"src/in\"`).\n * Returns matching file paths (prefixed with `@`) relative to the workspace,\n * up to `MAX_COMPLETIONS` entries.\n */\nfunction matchFileCompletions(trigger: string, workspace: string): string[] {\n if (!trigger && trigger !== \"\") return []; // trigger is the empty string when user types just \"@\"\n\n // Determine the base directory for listing\n const normalized = trigger.replace(/\\\\/g, \"/\");\n const lastSlash = normalized.lastIndexOf(\"/\");\n const searchDir = lastSlash >= 0 ? join(workspace, normalized.slice(0, lastSlash)) : workspace;\n const prefix = lastSlash >= 0 ? normalized.slice(lastSlash + 1) : normalized;\n\n const allFiles = listFilesRecursive(searchDir, workspace, 200);\n const lowerPrefix = prefix.toLowerCase();\n\n return allFiles\n .filter((f) => f.toLowerCase().startsWith(lowerPrefix) || f.toLowerCase().includes(lowerPrefix))\n .slice(0, MAX_COMPLETIONS)\n .map((f) => \"@\" + f);\n}\n\n// ── History persistence ─────────────────────────\n\n/** Load persisted input history from disk. Returns empty array on any error. */\nfunction loadPersistedHistory(): string[] {\n try {\n if (!existsSync(HISTORY_FILE)) return [];\n const raw = readFileSync(HISTORY_FILE, \"utf-8\");\n const parsed: unknown = JSON.parse(raw);\n if (Array.isArray(parsed) && parsed.every((e) => typeof e === \"string\")) {\n return parsed.slice(-MAX_HISTORY);\n }\n return [];\n } catch {\n return [];\n }\n}\n\n/** Save input history to disk. */\nfunction savePersistedHistory(history: string[]): void {\n try {\n const dir = dirname(HISTORY_FILE);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(HISTORY_FILE, JSON.stringify(history.slice(-MAX_HISTORY)), \"utf-8\");\n } catch {\n // Best effort — don't crash if write fails\n }\n}\n\n// ── Props ──────────────────────────────────────\n\n/** Vim editing mode. */\nexport type VimMode = \"insert\" | \"normal\" | \"visual\";\n\nexport interface InputBoxProps {\n /** Called when the user submits text. */\n onSubmit: (text: string) => void;\n /** Called on each Ctrl+C press (parent tracks abort count). */\n onAbort: () => void;\n /** Whether input is disabled (e.g. during streaming). */\n disabled: boolean;\n /** Placeholder text shown when input is empty. */\n placeholder?: string;\n /** Called when the user presses Ctrl+S to stash the current input. */\n onStash?: (text: string) => void;\n /** Text to append at cursor position (from FilePicker, @-mention, etc.). */\n appendText?: string;\n /** Called after appendText has been consumed. */\n onAppendTextConsumed?: () => void;\n /** Workspace directory for @‑mention file autocomplete. */\n workspace?: string;\n /** Enable vim‑style editing modes (INSERT/NORMAL/VISUAL). */\n vimMode?: boolean;\n /** Called when vim mode changes (for status display). */\n onVimModeChange?: (mode: VimMode) => void;\n}\n\n// ── Helpers ────────────────────────────────────\n\n/**\n * Match slash‑command prefix for autocomplete.\n * Returns matching commands (up to limit) sorted by length.\n */\nfunction matchCompletions(prefix: string): string[] {\n if (!prefix.startsWith(\"/\")) return [];\n const lower = prefix.toLowerCase();\n return SLASH_COMMANDS.filter((cmd) => cmd.toLowerCase().startsWith(lower))\n .sort((a, b) => a.length - b.length)\n .slice(0, MAX_COMPLETIONS);\n}\n\n/**\n * Find the position of the `@` trigger character preceding the cursor.\n *\n * The trigger is the last `@` that is preceded by a whitespace, start‑of‑string,\n * or another `@`, and is not inside a word boundary (e.g. email addresses).\n * Returns -1 if no valid trigger is found.\n */\nfunction findAtTrigger(value: string, cursor: number): number {\n // Look backward from cursor position for an @ sign\n for (let i = cursor - 1; i >= 0; i--) {\n const ch = value[i];\n if (ch === \"@\") {\n // @ at start of string or preceded by whitespace/punctuation\n if (i === 0 || /\\s/.test(value[i - 1]!) || value[i - 1] === \"@\") {\n return i;\n }\n // @ preceded by a word character → probably an email, skip\n return -1;\n }\n if (ch === \" \" || ch === \"\\n\") {\n // Hit whitespace before finding @ → no trigger\n return -1;\n }\n }\n return -1;\n}\n\n/**\n * Route the submitted text to determine submission type.\n * ! → shell command\n * / → slash command\n * default → chat message\n */\nfunction routeInput(text: string): \"shell\" | \"command\" | \"chat\" {\n if (text.startsWith(\"!\")) return \"shell\";\n if (text.startsWith(\"/\")) return \"command\";\n return \"chat\";\n}\n\n// ── Component ──────────────────────────────────\n\nexport function InputBox({\n onSubmit,\n onAbort,\n disabled,\n placeholder = \"输入消息...\",\n onStash,\n appendText,\n onAppendTextConsumed,\n workspace = process.cwd(),\n vimMode: vimEnabled = false,\n onVimModeChange,\n}: InputBoxProps): React.ReactElement {\n const theme = getTheme();\n\n // ── State ──────────────────────────────────\n\n const [value, setValue] = useState(\"\");\n const [cursor, setCursor] = useState(0);\n const [completions, setCompletions] = useState<string[]>([]);\n const [completionIndex, setCompletionIndex] = useState(0);\n /** Cursor position where the active completion trigger began (-1 = no trigger). */\n const [completionStart, setCompletionStart] = useState(-1);\n\n // Vim mode state\n const [vimMode, setVimMode] = useState<VimMode>(\"insert\");\n const [visualAnchor, setVisualAnchor] = useState(-1); // cursor position where visual mode started\n\n // History (loaded from persisted storage on mount)\n const historyRef = useRef<string[]>(loadPersistedHistory());\n const historyIndexRef = useRef(-1);\n const savedDraftRef = useRef(\"\"); // saved current input when navigating history\n\n // Burst coalescer (merge rapid Enter presses)\n const burstBufferRef = useRef<string[]>([]);\n const burstTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // ── Burst submit ────────────────────────────\n\n const flushBurst = useCallback(() => {\n if (burstTimerRef.current) {\n clearTimeout(burstTimerRef.current);\n burstTimerRef.current = null;\n }\n const lines = burstBufferRef.current;\n burstBufferRef.current = [];\n if (lines.length === 0) return;\n\n if (lines.length === 1) {\n onSubmit(lines[0]!);\n } else {\n onSubmit(lines.join(\"\\n\"));\n }\n }, [onSubmit]);\n\n const submitText = useCallback(\n (text: string) => {\n // Add to history (skip duplicates, cap at MAX_HISTORY)\n const hist = historyRef.current;\n if (hist.length === 0 || hist[hist.length - 1] !== text) {\n hist.push(text);\n if (hist.length > MAX_HISTORY) hist.shift();\n }\n historyIndexRef.current = -1;\n\n // Route check\n const route = routeInput(text);\n\n // Burst coalesce for chat messages\n if (route === \"chat\") {\n burstBufferRef.current.push(text);\n if (burstTimerRef.current) clearTimeout(burstTimerRef.current);\n burstTimerRef.current = setTimeout(flushBurst, 50);\n } else {\n flushBurst(); // flush any pending burst first\n onSubmit(text);\n }\n\n setValue(\"\");\n setCursor(0);\n setCompletions([]);\n setCompletionIndex(0);\n setCompletionStart(-1);\n\n // Persist history to disk\n savePersistedHistory(hist);\n },\n [onSubmit, flushBurst],\n );\n\n // ── Keyboard handler helpers ───────────────\n\n interface Ctx {\n value: string;\n cursor: number;\n completions: string[];\n completionIndex: number;\n completionStart: number;\n setValue: typeof setValue;\n setCursor: typeof setCursor;\n setCompletions: typeof setCompletions;\n setCompletionIndex: typeof setCompletionIndex;\n setCompletionStart: typeof setCompletionStart;\n historyRef: typeof historyRef;\n historyIndexRef: typeof historyIndexRef;\n savedDraftRef: typeof savedDraftRef;\n }\n\n function handleSubmit(input: string, key: Key, ctx: Ctx): boolean {\n if (key.ctrl && input === \"c\") {\n onAbort();\n return true;\n }\n // Ctrl+Enter → insert newline\n if (key.return && key.ctrl) {\n const newValue = ctx.value.slice(0, ctx.cursor) + \"\\n\" + ctx.value.slice(ctx.cursor);\n ctx.setValue(newValue);\n ctx.setCursor(ctx.cursor + 1);\n ctx.setCompletions([]);\n ctx.setCompletionStart(-1);\n return true;\n }\n // Bare Enter → submit\n if (key.return) {\n const trimmed = ctx.value.trim();\n if (trimmed) {\n if (ctx.completions.length > 0 && ctx.completionIndex < ctx.completions.length) {\n const selected = ctx.completions[ctx.completionIndex]!;\n if (ctx.completionStart >= 0 && ctx.completionStart < ctx.value.length) {\n const before = ctx.value.slice(0, ctx.completionStart);\n const after = ctx.value.slice(ctx.cursor);\n ctx.setValue(before + selected + after);\n ctx.setCursor(ctx.completionStart + selected.length);\n } else {\n ctx.setValue(selected);\n ctx.setCursor(selected.length);\n }\n ctx.setCompletions([]);\n ctx.setCompletionIndex(0);\n ctx.setCompletionStart(-1);\n return true;\n }\n submitText(trimmed);\n }\n return true;\n }\n return false;\n }\n\n function handleCompletionKeys(_input: string, key: Key, ctx: Ctx): boolean {\n if (key.tab && ctx.completions.length > 0) {\n const selected = ctx.completions[ctx.completionIndex]!;\n if (ctx.completionStart >= 0 && ctx.completionStart < ctx.value.length) {\n // @‑mention: replace only the trigger region\n const before = ctx.value.slice(0, ctx.completionStart);\n const after = ctx.value.slice(ctx.cursor);\n ctx.setValue(before + selected + after);\n ctx.setCursor(ctx.completionStart + selected.length);\n } else {\n // Slash command: replace entire value\n ctx.setValue(selected);\n ctx.setCursor(selected.length);\n }\n ctx.setCompletions([]);\n ctx.setCompletionIndex(0);\n ctx.setCompletionStart(-1);\n return true;\n }\n if (key.escape) {\n ctx.setCompletions([]);\n ctx.setCompletionIndex(0);\n ctx.setCompletionStart(-1);\n return true;\n }\n return false;\n }\n\n function handleHistoryKeys(key: Key, ctx: Ctx): boolean {\n if (key.upArrow) {\n if (ctx.completions.length > 0) {\n ctx.setCompletionIndex(Math.max(0, ctx.completionIndex - 1));\n return true;\n }\n const hist = ctx.historyRef.current;\n if (hist.length === 0) return true;\n if (ctx.historyIndexRef.current === -1) {\n ctx.savedDraftRef.current = ctx.value;\n }\n const nextIdx = ctx.historyIndexRef.current + 1;\n if (nextIdx < hist.length) {\n ctx.historyIndexRef.current = nextIdx;\n const entry = hist[hist.length - 1 - nextIdx]!;\n ctx.setValue(entry);\n ctx.setCursor(entry.length);\n }\n return true;\n }\n\n if (key.downArrow) {\n if (ctx.completions.length > 0) {\n ctx.setCompletionIndex(Math.min(ctx.completions.length - 1, ctx.completionIndex + 1));\n return true;\n }\n if (ctx.historyIndexRef.current === -1) return true;\n const nextIdx = ctx.historyIndexRef.current - 1;\n if (nextIdx >= 0) {\n ctx.historyIndexRef.current = nextIdx;\n const entry = ctx.historyRef.current[ctx.historyRef.current.length - 1 - nextIdx]!;\n ctx.setValue(entry);\n ctx.setCursor(entry.length);\n } else {\n ctx.historyIndexRef.current = -1;\n ctx.setValue(ctx.savedDraftRef.current);\n ctx.setCursor(ctx.savedDraftRef.current.length);\n }\n return true;\n }\n\n return false;\n }\n\n function handleNavigationKeys(input: string, key: Key, ctx: Ctx): boolean {\n if (handleHistoryKeys(key, ctx)) return true;\n\n if (key.leftArrow) {\n ctx.setCursor(Math.max(0, ctx.cursor - 1));\n return true;\n }\n if (key.rightArrow) {\n ctx.setCursor(Math.min(ctx.value.length, ctx.cursor + 1));\n return true;\n }\n if (key.home || (key.ctrl && input === \"a\")) {\n ctx.setCursor(0);\n return true;\n }\n if (key.end || (key.ctrl && input === \"e\")) {\n ctx.setCursor(ctx.value.length);\n return true;\n }\n\n return false;\n }\n\n function handleEditKeys(input: string, key: Key, ctx: Ctx): boolean {\n if (key.ctrl && input === \"w\") {\n ctx.setValue((prev) => {\n const before = prev.slice(0, ctx.cursor);\n const after = prev.slice(ctx.cursor);\n const wordEnd = before.replace(/\\s*\\S+$/, \"\");\n const deleted = before.length - wordEnd.length;\n ctx.setCursor((c) => c - deleted);\n return wordEnd + after;\n });\n return true;\n }\n\n if (key.ctrl && input === \"k\") {\n ctx.setValue((prev) => prev.slice(0, ctx.cursor));\n return true;\n }\n\n if (key.ctrl && input === \"u\") {\n ctx.setValue((prev) => prev.slice(ctx.cursor));\n ctx.setCursor(0);\n return true;\n }\n\n if (key.backspace || key.delete) {\n if (ctx.cursor > 0) {\n ctx.setValue((prev) => prev.slice(0, ctx.cursor - 1) + prev.slice(ctx.cursor));\n ctx.setCursor((c) => c - 1);\n }\n return true;\n }\n\n return false;\n }\n\n function handleTextInput(input: string, key: Key, ctx: Ctx): boolean {\n if (input && !key.ctrl && !key.meta && input.length > 0) {\n if (/^[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]$/.test(input)) return false;\n\n ctx.setValue((prev) => prev.slice(0, ctx.cursor) + input + prev.slice(ctx.cursor));\n ctx.setCursor((c) => c + input.length);\n\n const newVal = ctx.value.slice(0, ctx.cursor) + input + ctx.value.slice(ctx.cursor);\n const newCursor = ctx.cursor + input.length;\n\n // Slash command autocomplete (value starts with /)\n if (newVal.startsWith(\"/\")) {\n const matches = matchCompletions(newVal);\n ctx.setCompletions(matches);\n ctx.setCompletionIndex(0);\n ctx.setCompletionStart(0);\n return true;\n }\n\n // @‑mention file autocomplete\n // Find the @ trigger preceding the cursor\n const atIdx = findAtTrigger(newVal, newCursor);\n if (atIdx >= 0) {\n const trigger = newVal.slice(atIdx + 1, newCursor);\n if (trigger !== undefined) {\n const matches = matchFileCompletions(trigger, workspace);\n ctx.setCompletions(matches);\n ctx.setCompletionIndex(0);\n ctx.setCompletionStart(atIdx);\n return true;\n }\n }\n\n ctx.setCompletions([]);\n ctx.setCompletionStart(-1);\n return true;\n }\n return false;\n }\n\n // ── Append text from external sources (FilePicker, @-mention, etc.) ──\n\n useEffect(() => {\n if (appendText && appendText.length > 0) {\n setValue((prev) => prev.slice(0, cursor) + appendText + prev.slice(cursor));\n setCursor((c) => c + appendText.length);\n onAppendTextConsumed?.();\n }\n // Only trigger when appendText changes, not on every render\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [appendText]);\n\n // ── Vim mode handler ─────────────────────\n\n /** Handle keys in vim NORMAL mode. Returns true if consumed. */\n const handleVimNormal = useCallback(\n (input: string, key: Key): boolean => {\n // hjkl movement\n if (input === \"h\") {\n setCursor((c) => Math.max(0, c - 1));\n return true;\n }\n if (input === \"l\") {\n setCursor((c) => Math.min(value.length, c + 1));\n return true;\n }\n if (input === \"k\") {\n // Move up one line\n const before = value.slice(0, cursor);\n const prevNewline = before.lastIndexOf(\"\\n\");\n if (prevNewline === -1) {\n setCursor(0);\n return true;\n }\n const prevPrevNewline = before.lastIndexOf(\"\\n\", prevNewline - 1);\n const col = before.length - prevNewline - 1;\n const targetCol = Math.min(col, prevNewline - (prevPrevNewline + 1));\n setCursor((prevPrevNewline === -1 ? 0 : prevPrevNewline + 1) + targetCol);\n return true;\n }\n if (input === \"j\") {\n // Move down one line\n const after = value.slice(cursor);\n const nextNewline = after.indexOf(\"\\n\");\n if (nextNewline === -1) {\n setCursor(value.length);\n return true;\n }\n const col = cursor - (value.slice(0, cursor).lastIndexOf(\"\\n\") + 1);\n const afterNext = after.indexOf(\"\\n\", nextNewline + 1);\n const lineLen =\n afterNext === -1 ? after.length - nextNewline - 1 : afterNext - nextNewline - 1;\n setCursor(cursor + nextNewline + 1 + Math.min(col, lineLen));\n return true;\n }\n // Enter insert mode\n if (input === \"i\") {\n setVimMode(\"insert\");\n onVimModeChange?.(\"insert\");\n return true;\n }\n if (input === \"a\") {\n setCursor((c) => Math.min(value.length, c + 1));\n setVimMode(\"insert\");\n onVimModeChange?.(\"insert\");\n return true;\n }\n if (input === \"I\") {\n const before = value.slice(0, cursor);\n const lineStart = before.lastIndexOf(\"\\n\") + 1;\n setCursor(lineStart);\n setVimMode(\"insert\");\n onVimModeChange?.(\"insert\");\n return true;\n }\n if (input === \"A\") {\n const after = value.slice(cursor);\n const nextNewline = after.indexOf(\"\\n\");\n setCursor(cursor + (nextNewline === -1 ? after.length : nextNewline));\n setVimMode(\"insert\");\n onVimModeChange?.(\"insert\");\n return true;\n }\n if (input === \"o\") {\n const after = value.slice(cursor);\n const nextNewline = after.indexOf(\"\\n\");\n const lineEnd = cursor + (nextNewline === -1 ? after.length : nextNewline);\n setValue((v) => v.slice(0, lineEnd) + \"\\n\" + v.slice(lineEnd));\n setCursor(lineEnd + 1);\n setVimMode(\"insert\");\n onVimModeChange?.(\"insert\");\n return true;\n }\n if (input === \"O\") {\n const before = value.slice(0, cursor);\n const lineStart = before.lastIndexOf(\"\\n\") + 1;\n setValue((v) => v.slice(0, lineStart) + \"\\n\" + v.slice(lineStart));\n setCursor(lineStart);\n setVimMode(\"insert\");\n onVimModeChange?.(\"insert\");\n return true;\n }\n // Delete operations\n if (input === \"x\") {\n setValue((v) => v.slice(0, cursor) + v.slice(cursor + 1));\n if (cursor >= value.length) setCursor((c) => Math.max(0, c - 1));\n return true;\n }\n if (input === \"d\" && !key.ctrl) {\n // For dd (delete line): wait for second 'd' — handled via pending key tracking\n return true;\n }\n // Visual mode\n if (input === \"v\") {\n setVisualAnchor(cursor);\n setVimMode(\"visual\");\n onVimModeChange?.(\"visual\");\n return true;\n }\n // w/b word movement\n if (input === \"w\") {\n const rest = value.slice(cursor);\n const match = rest.match(/[^\\s\\w]*\\w+/);\n if (match) setCursor(cursor + (match.index ?? 0) + match[0].length);\n else setCursor(value.length);\n return true;\n }\n if (input === \"b\") {\n const before = value.slice(0, cursor);\n const match = before.match(/(\\w+)\\W*$/);\n if (match) setCursor(cursor - match[0].length + match[1]!.length);\n else setCursor(before.lastIndexOf(\" \") + 1);\n return true;\n }\n // 0/$ line movement\n if (input === \"0\") {\n setCursor((c) => c - (c - value.slice(0, c).lastIndexOf(\"\\n\") - 1));\n return true;\n }\n // $: move to end of line\n if (key.ctrl && input === \"e\") {\n /* handled by navigation */ return false;\n }\n return false;\n },\n [value, cursor, onVimModeChange],\n );\n\n /** Handle keys in vim VISUAL mode. Returns true if consumed. */\n const handleVimVisual = useCallback(\n (input: string, key: Key): boolean => {\n if (key.escape) {\n setVimMode(\"normal\");\n onVimModeChange?.(\"normal\");\n setVisualAnchor(-1);\n if (visualAnchor >= 0 && visualAnchor < cursor) setCursor(visualAnchor);\n return true;\n }\n // hjkl movement (extends selection)\n if (input === \"h\") {\n setCursor((c) => Math.max(0, c - 1));\n return true;\n }\n if (input === \"l\") {\n setCursor((c) => Math.min(value.length, c + 1));\n return true;\n }\n if (input === \"j\") {\n const after = value.slice(cursor);\n const nextNewline = after.indexOf(\"\\n\");\n if (nextNewline === -1) {\n setCursor(value.length);\n return true;\n }\n setCursor(cursor + nextNewline + 1);\n return true;\n }\n if (input === \"k\") {\n const before = value.slice(0, cursor);\n const prevNewline = before.lastIndexOf(\"\\n\");\n if (prevNewline !== -1) {\n const prevPrev = before.lastIndexOf(\"\\n\", prevNewline - 1);\n setCursor(prevPrev === -1 ? 0 : prevPrev + 1);\n }\n return true;\n }\n // y: yank (copy) selected text\n if (input === \"y\") {\n const start = Math.min(visualAnchor, cursor);\n const end = Math.max(visualAnchor, cursor);\n const selected = value.slice(start, end);\n // Write to clipboard if available (best effort)\n setVimMode(\"normal\");\n onVimModeChange?.(\"normal\");\n setVisualAnchor(-1);\n return true;\n }\n // d: delete selected text\n if (input === \"d\") {\n const start = Math.min(visualAnchor, cursor);\n const end = Math.max(visualAnchor, cursor);\n setValue((v) => v.slice(0, start) + v.slice(end));\n setCursor(start);\n setVimMode(\"normal\");\n onVimModeChange?.(\"normal\");\n setVisualAnchor(-1);\n return true;\n }\n return false;\n },\n [value, cursor, visualAnchor, onVimModeChange],\n );\n\n // ── Main keyboard handler ──────────────────\n\n useInkInput((input: string, key: Key) => {\n if (disabled) return;\n\n // Filter out terminal mouse SGR escape sequences (e.g. [<0;27;3M)\n // that leak through as raw text in terminals with mouse tracking enabled.\n if (input.includes(\"\\x1b[<\") || /^\\[<\\d+;\\d+;\\d+[Mm]/.test(input.trim())) return;\n\n // Ctrl+S → stash current input\n if (key.ctrl && input === \"s\") {\n if (value.trim() && onStash) {\n onStash(value);\n }\n return;\n }\n\n // ── Vim mode handling ─────────────────\n if (vimEnabled) {\n // Escape handling in vim\n if (key.escape) {\n if (vimMode === \"visual\") {\n setVimMode(\"normal\");\n onVimModeChange?.(\"normal\");\n setVisualAnchor(-1);\n return;\n }\n if (vimMode === \"insert\") {\n setVimMode(\"normal\");\n onVimModeChange?.(\"normal\");\n return;\n }\n // In normal mode, Escape clears completions or does nothing\n setCompletions([]);\n return;\n }\n\n if (vimMode === \"normal\") {\n if (handleVimNormal(input, key)) return;\n // Bare Enter / Ctrl+Enter → submit in normal mode\n if (key.return) {\n const trimmed = value.trim();\n if (trimmed) submitText(trimmed);\n return;\n }\n return; // Consume all other keys in normal mode\n }\n\n if (vimMode === \"visual\") {\n if (handleVimVisual(input, key)) return;\n return; // Consume all other keys in visual mode\n }\n\n // INSERT mode: fall through to normal handlers\n }\n\n const ctx: Ctx = {\n value,\n cursor,\n completions,\n completionIndex,\n completionStart,\n setValue,\n setCursor,\n setCompletions,\n setCompletionIndex,\n setCompletionStart,\n historyRef,\n historyIndexRef,\n savedDraftRef,\n };\n\n if (handleSubmit(input, key, ctx)) return;\n if (handleCompletionKeys(input, key, ctx)) return;\n if (handleNavigationKeys(input, key, ctx)) return;\n if (handleEditKeys(input, key, ctx)) return;\n handleTextInput(input, key, ctx);\n });\n\n // ── Render ──────────────────────────────────\n\n // Split value into visible lines (last MAX_VISIBLE_LINES)\n const lines = value.split(\"\\n\");\n const visibleLines = lines.slice(-MAX_VISIBLE_LINES);\n const lineCount = lines.length;\n const hasMore = lineCount > MAX_VISIBLE_LINES;\n\n const isPlaceholder = value === \"\";\n const _displayText = isPlaceholder ? placeholder : value;\n\n // Build rendered lines\n const renderedLines: React.ReactElement[] = [];\n\n if (hasMore) {\n renderedLines.push(\n React.createElement(\n Text,\n { key: \"more\", dimColor: true },\n ` ... (还有 ${lineCount - MAX_VISIBLE_LINES} 行)`,\n ),\n );\n }\n\n for (let i = 0; i < visibleLines.length; i++) {\n const line = visibleLines[i]!;\n const isLast = i === visibleLines.length - 1;\n const prompt = isLast ? \"❯ \" : \" \";\n\n if (isPlaceholder && i === visibleLines.length - 1) {\n renderedLines.push(\n React.createElement(\n Box,\n { key: `line-${i}`, flexDirection: \"row\" },\n React.createElement(Text, { color: theme.colors.accent }, prompt),\n React.createElement(Text, { color: theme.colors.dimmed }, placeholder),\n ),\n );\n } else {\n // Render text with cursor (inverse character at cursor position)\n renderedLines.push(\n React.createElement(\n Box,\n { key: `line-${i}`, flexDirection: \"row\" },\n React.createElement(Text, { color: theme.colors.accent }, prompt),\n renderWithCursor(line, cursor - getCursorOffset(value, i), theme),\n ),\n );\n }\n }\n\n return React.createElement(\n Box,\n { flexDirection: \"column\" },\n // ── Vim status bar ─────────────────────\n React.createElement(VimStatusBar, { vimEnabled, vimMode }),\n\n // ── Input area ──────────────────────────\n React.createElement(\n Box,\n {\n flexDirection: \"column\",\n borderStyle: \"round\",\n borderColor: theme.colors.border,\n paddingX: 1,\n minHeight: 1,\n },\n ...renderedLines,\n ),\n\n // ── Autocomplete popup ──────────────────\n React.createElement(SuggestionsOverlay, { completions, completionIndex }),\n\n // ── Status line ─────────────────────────\n React.createElement(InputFooter, { vimEnabled, vimMode, value, disabled }),\n );\n}\n\n// ── Render helpers ─────────────────────────────\n\n/**\n * Get the cursor offset within a specific line of multi‑line text.\n */\n\n/**\n * Get the cursor offset within a specific line of multi‑line text.\n */\nfunction getCursorOffset(text: string, lineIndex: number): number {\n const lines = text.split(\"\\n\");\n let offset = 0;\n for (let i = 0; i < lineIndex && i < lines.length; i++) {\n offset += lines[i]!.length + 1; // +1 for newline\n }\n return offset;\n}\n\n/**\n * Render a line with cursor highlighting (inverse character).\n */\nfunction renderWithCursor(\n line: string,\n cur: number,\n _theme: ReturnType<typeof getTheme>,\n): React.ReactElement {\n const clamped = Math.max(0, Math.min(cur, line.length));\n\n if (clamped >= line.length) {\n return React.createElement(\n Text,\n {},\n React.createElement(Text, {}, line),\n React.createElement(Text, { inverse: true }, \" \"),\n );\n }\n\n return React.createElement(\n Text,\n {},\n React.createElement(Text, {}, line.slice(0, clamped)),\n React.createElement(Text, { inverse: true }, line[clamped] ?? \" \"),\n React.createElement(Text, {}, line.slice(clamped + 1)),\n );\n}\n","/**\n * StatusBar — bottom‑of‑screen status line.\n *\n * Shows: permission mode, current model, streaming indicator,\n * token count with estimated cost, and the active view name.\n * Compact single‑line layout with budget color coding.\n */\n\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\n\n// ── Props ────────────────────────────────────────────\n\nexport interface StatusBarProps {\n mode: string;\n model: string;\n streaming: boolean;\n viewName: string;\n /** Total tokens consumed in the current session. */\n tokensUsed?: number;\n /** Estimated cost in USD for the current session. */\n costUsd?: number;\n /** Budget maximum USD for color coding. */\n budgetMaxUsd?: number;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** Format a token count as a human-readable string (e.g. \"12.3K\"). */\nfunction formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M`;\n if (tokens >= 1_000) return `${(tokens / 1_000).toFixed(1)}K`;\n return String(tokens);\n}\n\n/** Format a USD cost as a compact string (e.g. \"$0.007\"). */\nfunction formatCost(cost: number): string {\n if (cost >= 1) return `$${cost.toFixed(2)}`;\n if (cost >= 0.01) return `$${cost.toFixed(3)}`;\n return `$${cost.toFixed(4)}`;\n}\n\n/**\n * Determine the color for the cost display based on budget ratio.\n * - < 50% → green\n * - 50–80% → yellow\n * - > 80% → red\n * - no budget → dimmed\n */\nfunction budgetColor(costUsd: number, maxUsd?: number): string | undefined {\n if (maxUsd === undefined || maxUsd <= 0) return undefined;\n const ratio = costUsd / maxUsd;\n if (ratio > 0.8) return \"red\";\n if (ratio > 0.5) return \"yellow\";\n return \"green\";\n}\n\n// ── Public API ───────────────────────────────────────\n\nexport function StatusBar({\n mode,\n model,\n streaming,\n viewName,\n tokensUsed,\n costUsd,\n budgetMaxUsd,\n}: StatusBarProps): React.ReactElement {\n const theme = getTheme();\n const streamIndicator = streaming ? \" ◉\" : \" ○\";\n\n const parts: React.ReactNode[] = [];\n parts.push(`${mode} | ${model}`);\n\n if (tokensUsed !== undefined && tokensUsed > 0) {\n parts.push(`| ${formatTokens(tokensUsed)} 令牌`);\n }\n\n if (costUsd !== undefined && costUsd > 0) {\n const color = budgetColor(costUsd, budgetMaxUsd);\n parts.push(\n React.createElement(\n React.Fragment,\n { key: \"cost\" },\n \"| \",\n React.createElement(Text, { color }, formatCost(costUsd)),\n ),\n );\n }\n\n parts.push(`| ${viewName}${streamIndicator}`);\n\n return React.createElement(\n Box,\n {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n paddingX: 1,\n borderStyle: \"single\",\n borderColor: theme.colors.border,\n },\n React.createElement(\n Text,\n { dimColor: true },\n ...parts.flatMap((p, i) => [i > 0 ? \" \" : \"\", p]),\n ),\n React.createElement(Text, { dimColor: true }, \"Ctrl+C: 中断\"),\n );\n}\n","/**\n * NotificationCenter — single‑line toast bar for transient status messages.\n *\n * Shows between the chat area and the input box. Notifications use a\n * priority‑based queue: only the highest‑priority message is shown, and\n * same‑key notifications replace rather than duplicate.\n *\n * Priority durations:\n * immediate → 5 seconds\n * high → 8 seconds\n * medium → 15 seconds\n * low → 30 seconds\n */\n\nimport React, { useState, useEffect, useCallback, useRef } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\n\n// ── Types ────────────────────────────────────────────\n\nexport type NotificationPriority = \"immediate\" | \"high\" | \"medium\" | \"low\";\n\nexport interface Notification {\n /** Stable key for deduplication (e.g. tool name, permission ID). */\n key: string;\n /** Human‑readable message text. */\n text: string;\n /** Priority determines display duration and ordering. */\n priority: NotificationPriority;\n}\n\ninterface QueuedNotification extends Notification {\n id: string;\n createdAt: number;\n}\n\nexport interface NotificationCenterProps {\n /** Queue of active notifications (oldest first). */\n notifications: Notification[];\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst PRIORITY_DURATION_MS: Record<NotificationPriority, number> = {\n immediate: 5_000,\n high: 8_000,\n medium: 15_000,\n low: 30_000,\n};\n\nconst PRIORITY_ORDER: Record<NotificationPriority, number> = {\n immediate: 0,\n high: 1,\n medium: 2,\n low: 3,\n};\n\n/** Max notifications to keep in the queue. */\nconst MAX_QUEUE = 50;\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * React hook for managing notification state.\n *\n * Call `push(note)` to add a notification. The hook handles\n * deduplication, expiry, and priority ordering.\n *\n * Returns the currently visible notification and a push function.\n */\nexport function useNotifications(): {\n current: QueuedNotification | null;\n push: (note: Notification) => void;\n} {\n const [queue, setQueue] = useState<QueuedNotification[]>([]);\n const timerRef = useRef<NodeJS.Timeout | null>(null);\n const queueRef = useRef(queue);\n queueRef.current = queue;\n\n /** Remove the top notification and advance to the next one. */\n const advance = useCallback(() => {\n setQueue((prev) => prev.slice(1));\n }, []);\n\n /** Push a notification onto the queue. */\n const push = useCallback((note: Notification) => {\n setQueue((prev) => {\n // Replace existing notification with the same key\n const filtered = prev.filter((n) => n.key !== note.key);\n const entry: QueuedNotification = {\n ...note,\n id: `${note.key}-${Date.now()}`,\n createdAt: Date.now(),\n };\n return [...filtered, entry].slice(-MAX_QUEUE);\n });\n }, []);\n\n // Sort queue by priority then by creation time\n const sorted = [...queue].sort((a, b) => {\n const pa = PRIORITY_ORDER[a.priority];\n const pb = PRIORITY_ORDER[b.priority];\n if (pa !== pb) return pa - pb;\n return a.createdAt - b.createdAt;\n });\n\n const current = sorted[0] ?? null;\n\n // Auto‑expire the current notification after its priority duration\n useEffect(() => {\n if (!current) return;\n\n const duration = PRIORITY_DURATION_MS[current.priority];\n timerRef.current = setTimeout(() => {\n advance();\n }, duration);\n\n return () => {\n if (timerRef.current) clearTimeout(timerRef.current);\n };\n }, [current?.id, advance]);\n\n return { current, push };\n}\n\n// ── Component ────────────────────────────────────────\n\n/** Map priority to an Ink color token. */\nfunction priorityColor(priority: NotificationPriority): string {\n switch (priority) {\n case \"immediate\":\n return \"red\";\n case \"high\":\n return \"yellow\";\n case \"medium\":\n return \"green\";\n case \"low\":\n return \"grey\";\n }\n}\n\n/** Single‑line notification renderer. */\nexport function NotificationCenter({\n current,\n}: {\n current: QueuedNotification | null;\n}): React.ReactElement | null {\n const theme = getTheme();\n\n if (!current) return null;\n\n const color = priorityColor(current.priority);\n\n return React.createElement(\n Box,\n {\n paddingX: 1,\n paddingY: 0,\n borderStyle: \"single\",\n borderColor: color,\n },\n React.createElement(Text, { color, bold: true }, current.text),\n );\n}\n","/**\n * PermissionRequest — modal for approving or denying tool calls.\n *\n * Renders the tool name, safety level badge, description, and parameter\n * summary. Supports 4 permission modes with keyboard shortcuts:\n * A → Allow once, D → Deny, L → Always allow, S → Safe mode\n *\n * Design (§5.9f #3):\n * - Inline in ScrollBox area, not an overlay\n * - Safety badge with color coding\n * - Tab to amend, Shift+Tab to cycle permission modes\n * - 60s auto‑deny timeout\n */\n\nimport React, { useEffect, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Safety level determines badge color and severity. */\nexport type SafetyLevel = \"Safe\" | \"WorkspaceSafe\" | \"RequiresApproval\" | \"Dangerous\";\n\n/** Information about a pending permission request. */\nexport interface PermissionRequestData {\n /** Unique request identifier. */\n requestId: string;\n /** Name of the tool being invoked. */\n toolName: string;\n /** Safety level of the tool. */\n safety: SafetyLevel;\n /** Human‑readable description of what the tool will do. */\n description: string;\n /** Optional parameter summary for display. */\n parameters?: Record<string, unknown>;\n}\n\n/** Callback when the user makes a decision. */\nexport type PermissionChoice = \"allow\" | \"deny\" | \"always_allow\";\nexport type PermissionCallback = (requestId: string, choice: PermissionChoice) => void;\n\n/** Props for the PermissionRequest modal. */\nexport interface PermissionRequestProps {\n request: PermissionRequestData;\n onDecide: PermissionCallback;\n onCancel: () => void;\n}\n\n/** Timeout in ms before auto‑deny. */\nconst AUTO_DENY_MS = 60_000;\n\n/** Badge styles per safety level. */\nconst SAFETY_BADGE: Record<SafetyLevel, { label: string; color: string }> = {\n Safe: { label: \"SAFE\", color: \"success\" },\n WorkspaceSafe: { label: \"WORKSPACE\", color: \"foreground\" },\n RequiresApproval: { label: \"APPROVAL\", color: \"warning\" },\n Dangerous: { label: \"DANGER\", color: \"error\" },\n};\n\n/**\n * Permission request dialog.\n *\n * Users navigate with A/D/L keys and can press Escape to cancel.\n * After AUTO_DENY_MS, the dialog auto‑denies.\n */\nexport function PermissionRequest({\n request,\n onDecide,\n onCancel,\n}: PermissionRequestProps): React.ReactElement {\n const theme = getTheme();\n const badge = SAFETY_BADGE[request.safety] ?? SAFETY_BADGE.RequiresApproval;\n const badgeColor = theme.colors[badge.color] ?? theme.colors.warning;\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n const char = input.toLowerCase();\n if (char === \"a\") {\n onDecide(request.requestId, \"allow\");\n return;\n }\n if (char === \"d\") {\n onDecide(request.requestId, \"deny\");\n return;\n }\n if (char === \"l\") {\n onDecide(request.requestId, \"always_allow\");\n return;\n }\n if (key.escape) {\n onCancel();\n return;\n }\n },\n [request.requestId, onDecide, onCancel],\n );\n\n useInkInput(handleKey);\n\n // Auto‑deny timer\n useEffect(() => {\n const timer = setTimeout(() => {\n onDecide(request.requestId, \"deny\");\n }, AUTO_DENY_MS);\n return () => clearTimeout(timer);\n }, [request.requestId, onDecide]);\n\n // Format parameters for display\n const paramLines: string[] = [];\n if (request.parameters) {\n for (const [key, val] of Object.entries(request.parameters)) {\n const str = typeof val === \"string\" ? val : JSON.stringify(val);\n paramLines.push(` ${key}: ${str.slice(0, 80)}`);\n }\n }\n\n return React.createElement(\n Box,\n {\n flexDirection: \"column\",\n borderStyle: \"double\",\n borderColor: badgeColor,\n paddingX: 1,\n paddingY: 1,\n marginY: 1,\n },\n // ── Header: tool name + badge ──────────────\n React.createElement(\n Box,\n { flexDirection: \"row\", justifyContent: \"space-between\" },\n React.createElement(Text, { bold: true }, `🔧 ${request.toolName}`),\n React.createElement(Text, { color: badgeColor, bold: true }, ` ${badge.label} `),\n ),\n\n // ── Description ────────────────────────────\n React.createElement(Box, { marginTop: 1 }, React.createElement(Text, {}, request.description)),\n\n // ── Parameters ─────────────────────────────\n paramLines.length > 0\n ? React.createElement(\n Box,\n { flexDirection: \"column\", marginTop: 1 },\n React.createElement(Text, { dimColor: true }, \"Parameters:\"),\n ...paramLines.map((line, i) =>\n React.createElement(Text, { key: i, dimColor: true }, line),\n ),\n )\n : null,\n\n // ── Actions ────────────────────────────────\n React.createElement(\n Box,\n { flexDirection: \"row\", marginTop: 1, gap: 2 },\n React.createElement(Text, { color: theme.colors.success }, \"[A]llow \"),\n React.createElement(Text, { color: theme.colors.error }, \"[D]eny \"),\n React.createElement(Text, { color: theme.colors.accent }, \"[L] Always Allow\"),\n ),\n\n React.createElement(\n Text,\n { dimColor: true },\n \"Arrow keys to select · Tab to amend · Auto‑deny in 60s\",\n ),\n );\n}\n","/**\n * Dialog — unified modal shell for all Lynx dialogs.\n *\n * Every modal uses this wrapper for consistent look and keyboard behaviour.\n * Renders a double‑bordered overlay with title, subtitle, child content,\n * and bottom input‑guide text.\n *\n * Theme:\n * ┌─ Title ──────────────────────── Esc to close ──┐\n * │ Subtitle │\n * │ │\n * │ {children} │\n * │ │\n * │ Enter to confirm · Esc to cancel │\n * └─────────────────────────────────────────────────┘\n */\n\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Props for the Dialog shell component. */\nexport interface DialogProps {\n /** Modal title shown in the top border. */\n title: string;\n /** Optional accent color for title and border (theme color key). */\n accentColor?: string;\n /** Optional subtitle shown below the title. */\n subtitle?: string;\n /** Bottom hint text (e.g. \"Enter to confirm · Esc to cancel\"). */\n inputGuide?: string;\n /** Width of the dialog in characters. Default: 60. */\n width?: number;\n /** Children rendered as the dialog body. */\n children?: React.ReactNode;\n}\n\n/**\n * Unified dialog wrapper for modals, pickers, and confirmations.\n *\n * All modals in the TUI use this component to ensure visual consistency.\n * The dialog renders as an absolutely positioned overlay with a\n * double‑border style.\n */\nexport function Dialog({\n title,\n accentColor,\n subtitle,\n inputGuide = \"Enter to confirm · Esc to cancel\",\n width = 60,\n children,\n}: DialogProps): React.ReactElement {\n const theme = getTheme();\n const accent = accentColor\n ? (theme.colors[accentColor] ?? theme.colors.accent)\n : theme.colors.accent;\n\n // Build top border line: ┌─ Title ──────────────────── Esc to close ──┐\n const titleText = ` ${title} `;\n const escText = \" Esc to close \";\n const remaining = width - 4 - titleText.length - escText.length; // 4 = \"┌─\" + \"─┐\"\n const filler = remaining > 0 ? \"─\".repeat(remaining) : \"─\";\n\n const topBorder = `┌─${titleText}${filler}${escText}─┐`;\n\n return React.createElement(\n Box,\n {\n position: \"absolute\",\n marginTop: 2,\n marginLeft: 2,\n marginRight: 2,\n marginBottom: 2,\n flexDirection: \"column\",\n borderStyle: \"double\",\n borderColor: accent,\n paddingX: 1,\n },\n // ── Top border with embedded title ─────────\n React.createElement(Text, { color: accent, bold: true }, topBorder),\n\n // ── Subtitle (optional) ───────────────────\n subtitle ? React.createElement(Text, { dimColor: true }, ` ${subtitle}`) : null,\n\n // ── Body ─────────────────────────────────\n React.createElement(Box, { flexDirection: \"column\", marginY: 1, flexGrow: 1 }, children),\n\n // ── Bottom guide ──────────────────────────\n React.createElement(Text, { dimColor: true }, ` ${inputGuide}`),\n\n // ── Bottom border ─────────────────────────\n React.createElement(Text, { color: accent }, `└${\"─\".repeat(width - 2)}┘`),\n );\n}\n","/**\n * SessionPicker — full‑screen session browser and picker.\n *\n * Lists sessions with label, message count, and relative time.\n * Supports text filtering, arrow‑key navigation, Enter to select,\n * and Escape to go back.\n *\n * Design (§5.9f #1):\n * - Search/filter by label substring\n * - Sort tabs: Recent (default) / Relevance / Size\n * - Tree mode for fork groups (Phase 5)\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport type { Session } from \"@24klynx/core\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Sort mode for the session list. */\ntype SortMode = \"recent\" | \"relevance\" | \"size\";\n\n/** Props for the SessionPicker modal. */\nexport interface SessionPickerProps {\n /** All available sessions. */\n sessions: Session[];\n /** Called when the user selects a session (Enter key). */\n onSelect(sessionId: string): void;\n /** Called when the user dismisses the picker (Escape key). */\n onCancel(): void;\n}\n\n/** Maximum number of sessions to display. */\nconst MAX_VISIBLE = 15;\n\n/** Format a relative time string from a Unix‑ms timestamp. */\nfunction formatTime(ts: number): string {\n const sec = Math.floor((Date.now() - ts) / 1000);\n if (sec < 60) return `${sec}秒前`;\n if (sec < 3600) return `${Math.floor(sec / 60)}分钟前`;\n if (sec < 86400) return `${Math.floor(sec / 3600)}小时前`;\n return `${Math.floor(sec / 86400)}天前`;\n}\n\n/** Build fork chains: child sessions indented under their parent. */\nfunction buildForkTree(sessions: Session[]): Array<{ session: Session; depth: number }> {\n const byId = new Map(sessions.map((s) => [s.id, s]));\n const children = new Map<string | undefined, Session[]>();\n for (const s of sessions) {\n const pid = s.parentSessionId ?? \"__root__\";\n let list = children.get(pid);\n if (!list) {\n list = [];\n children.set(pid, list);\n }\n list.push(s);\n }\n\n const result: Array<{ session: Session; depth: number }> = [];\n function walk(pid: string | undefined | \"__root__\", depth: number) {\n const key = pid ?? \"__root__\";\n const kids = children.get(key);\n if (!kids) return;\n kids.sort((a, b) => b.updatedAt - a.updatedAt);\n for (const s of kids) {\n result.push({ session: s, depth: pid === \"__root__\" ? 0 : depth });\n walk(s.id, depth + 1);\n }\n }\n walk(\"__root__\", 0);\n return result;\n}\n\n/** Context passed to {@link sessionPickerHandleKey}. */\nexport interface SessionPickerKeyContext {\n key: {\n return?: boolean;\n escape?: boolean;\n upArrow?: boolean;\n downArrow?: boolean;\n input?: string;\n };\n filter: string;\n setFilter: (f: string) => void;\n selectedIndex: number;\n setSelectedIndex: (i: number) => void;\n maxIndex: number;\n onSelect: () => void;\n onCancel: () => void;\n}\n\n/**\n * Session picker modal.\n *\n * Filters sessions by label substring, displays them in a scrollable\n * list, and handles selection via Enter key.\n */\nexport function SessionPicker({\n sessions: allSessions,\n onSelect,\n onCancel,\n}: SessionPickerProps): React.ReactElement {\n const theme = getTheme();\n const [filter, setFilter] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [sortMode, setSortMode] = useState<SortMode>(\"recent\");\n\n // Build fork tree, then sort by selected mode\n const tree = buildForkTree(allSessions);\n const sorted: Array<{ session: Session; depth: number }> = (() => {\n const copy = [...tree];\n switch (sortMode) {\n case \"recent\":\n copy.sort((a, b) => b.session.updatedAt - a.session.updatedAt);\n break;\n case \"size\":\n copy.sort((a, b) => (b.session.messages?.length ?? 0) - (a.session.messages?.length ?? 0));\n break;\n case \"relevance\":\n // Keep tree order for relevance (parent-child relationships)\n break;\n }\n return copy;\n })();\n\n // Filter by label substring\n const filtered = filter\n ? sorted.filter(({ session: s }) => s.label.toLowerCase().includes(filter.toLowerCase()))\n : sorted;\n\n // Clamp selection\n const maxIndex = Math.max(0, filtered.length - 1);\n const safeIndex = Math.min(selectedIndex, maxIndex);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.return) {\n const selected = filtered[safeIndex];\n if (selected) onSelect(selected.session.id);\n return;\n }\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1));\n return;\n }\n if (key.downArrow) {\n setSelectedIndex(Math.min(maxIndex, selectedIndex + 1));\n return;\n }\n // Tab cycles sort mode\n if (key.tab) {\n setSortMode((prev) => {\n if (prev === \"recent\") return \"relevance\";\n if (prev === \"relevance\") return \"size\";\n return \"recent\";\n });\n setSelectedIndex(0);\n return;\n }\n // Backspace removes last filter char\n if (key.backspace) {\n setFilter((f) => f.slice(0, -1));\n setSelectedIndex(0);\n return;\n }\n // Typing adds to filter\n if (input.length === 1 && !key.ctrl && !key.meta) {\n setFilter((f) => f + input);\n setSelectedIndex(0);\n }\n },\n [filtered, safeIndex, maxIndex, selectedIndex, sortMode, onSelect, onCancel],\n );\n\n useInkInput(handleKey);\n\n /** Chinese label for sort mode tabs. */\n const sortLabel = (mode: SortMode): string => {\n if (mode === \"recent\") return \"最近\";\n if (mode === \"relevance\") return \"关联\";\n return \"大小\";\n };\n\n // ── Sort mode tab bar ──\n const modes: SortMode[] = [\"recent\", \"relevance\", \"size\"];\n const tabNodes = modes.map((mode) => {\n const isActive = mode === sortMode;\n return React.createElement(\n Text,\n { key: mode, color: isActive ? theme.colors.accent : theme.colors.dim, bold: isActive },\n ` ${sortLabel(mode)} `,\n );\n });\n\n // Build session list items with fork tree depth indentation\n const listItems: React.ReactElement[] = [];\n const visible = filtered.slice(0, MAX_VISIBLE);\n\n for (let i = 0; i < visible.length; i++) {\n const entry = visible[i]!;\n const s = entry.session;\n const isSelected = i === safeIndex;\n const cursor = isSelected ? \"❯\" : \" \";\n const indent = \" \".repeat(entry.depth) + (entry.depth > 0 ? \"├─ \" : \"\");\n const count = s.messages?.length ?? 0;\n const time = formatTime(s.updatedAt);\n\n listItems.push(\n React.createElement(\n Box,\n { key: s.id, flexDirection: \"row\" },\n React.createElement(\n Text,\n {\n color: isSelected ? theme.colors.accent : undefined,\n bold: isSelected,\n },\n `${cursor} ${indent}${s.label.padEnd(28 - indent.length)} ${String(count).padStart(4)} 条消息 ${time}`,\n ),\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"会话\",\n subtitle: `排序: ${sortLabel(sortMode)} · 过滤: ${filter || \"(输入关键词)\"}`,\n inputGuide: \"Enter 选择 · Esc 返回 · Tab 切换排序 · ↑↓ 导航 · 打字过滤\",\n accentColor: \"accent\",\n },\n // ── Sort mode tabs ────────────────────────\n React.createElement(Box, { flexDirection: \"row\", marginBottom: 1 }, ...tabNodes),\n // ── Session list ───────────────────────────\n listItems.length > 0\n ? React.createElement(Box, { flexDirection: \"column\" }, ...listItems)\n : React.createElement(Text, { dimColor: true }, \" 未找到会话。\"),\n\n // ── Filter hint ────────────────────────────\n filter\n ? React.createElement(Text, { dimColor: true }, ` ${filtered.length} 个会话匹配 \"${filter}\"`)\n : null,\n );\n}\n\n/**\n * Handle keyboard input for the SessionPicker.\n *\n * Returns true if the key was consumed by the picker.\n */\nexport function sessionPickerHandleKey(ctx: SessionPickerKeyContext): boolean {\n if (ctx.key.return) {\n ctx.onSelect();\n return true;\n }\n\n if (ctx.key.escape) {\n ctx.onCancel();\n return true;\n }\n\n if (ctx.key.upArrow) {\n ctx.setSelectedIndex(Math.max(0, ctx.selectedIndex - 1));\n return true;\n }\n\n if (ctx.key.downArrow) {\n ctx.setSelectedIndex(Math.min(ctx.maxIndex, ctx.selectedIndex + 1));\n return true;\n }\n\n // Text input for filtering\n if (ctx.key.input && ctx.key.input.length === 1) {\n ctx.setFilter(ctx.filter + ctx.key.input);\n ctx.setSelectedIndex(0);\n return true;\n }\n\n return false;\n}\n","/**\n * HelpModal — keyboard shortcut reference.\n *\n * Renders a categorized table of keyboard shortcuts, dynamically\n * generated from the keybindings catalog. Supports text search\n * filtering.\n *\n * Design (§5.9f #4):\n * - Categories: Global, Chat, Permission, Modal\n * - Two‑column layout: key | action\n * - Search filter with real‑time filtering\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** A single shortcut entry. */\ninterface Shortcut {\n keys: string;\n action: string;\n category: string;\n}\n\n/** Built‑in shortcut reference. */\nconst SHORTCUTS: Shortcut[] = [\n { keys: \"Enter\", action: \"发送消息\", category: \"对话\" },\n { keys: \"Ctrl+C\", action: \"中断(三层)\", category: \"全局\" },\n { keys: \"Ctrl+H\", action: \"显示帮助\", category: \"全局\" },\n { keys: \"Ctrl+L\", action: \"模型选择器\", category: \"全局\" },\n { keys: \"Ctrl+K\", action: \"命令面板\", category: \"全局\" },\n { keys: \"Ctrl+S\", action: \"暂存当前输入\", category: \"全局\" },\n { keys: \"Ctrl+F\", action: \"文件选择器\", category: \"对话\" },\n { keys: \"PageUp/PageDown\", action: \"滚动对话历史\", category: \"对话\" },\n { keys: \"Home/End\", action: \"跳到顶部/底部\", category: \"对话\" },\n { keys: \"Up/Down\", action: \"浏览历史(200 条)\", category: \"对话\" },\n { keys: \"Tab\", action: \"接受自动补全\", category: \"对话\" },\n { keys: \"Escape\", action: \"关闭模态框 / 取消\", category: \"模态框\" },\n { keys: \"A/D/L\", action: \"允许/拒绝/始终允许(权限)\", category: \"权限\" },\n { keys: \"Shift+Tab\", action: \"切换权限模式\", category: \"权限\" },\n { keys: \"/\", action: \"斜杠命令 / 技能选择器\", category: \"对话\" },\n { keys: \"!\", action: \"Bang 模式(Shell 命令)\", category: \"对话\" },\n { keys: \"Ctrl+A/E\", action: \"跳到行首/行尾\", category: \"对话\" },\n { keys: \"Ctrl+W\", action: \"删除上一个词\", category: \"对话\" },\n { keys: \"Ctrl+K\", action: \"删除到行尾\", category: \"对话\" },\n];\n\n/** Props for the HelpModal. */\nexport interface HelpModalProps {\n onCancel(): void;\n}\n\n/**\n * Help modal displaying keyboard shortcuts.\n *\n * Categorized display with search filtering.\n */\nexport function HelpModal({ onCancel }: HelpModalProps): React.ReactElement {\n const theme = getTheme();\n const [filter, setFilter] = useState(\"\");\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.backspace) {\n setFilter((f) => f.slice(0, -1));\n return;\n }\n if (input.length === 1 && !key.ctrl && !key.meta) {\n setFilter((f) => f + input);\n }\n },\n [onCancel],\n );\n\n useInkInput(handleKey);\n\n const filtered = filter\n ? SHORTCUTS.filter(\n (s) =>\n s.keys.toLowerCase().includes(filter.toLowerCase()) ||\n s.action.toLowerCase().includes(filter.toLowerCase()) ||\n s.category.toLowerCase().includes(filter.toLowerCase()),\n )\n : SHORTCUTS;\n\n // Group by category\n const categories = new Map<string, Shortcut[]>();\n for (const s of filtered) {\n const list = categories.get(s.category);\n if (list) {\n list.push(s);\n } else {\n categories.set(s.category, [s]);\n }\n }\n\n const rows: React.ReactElement[] = [];\n for (const [category, shortcuts] of categories) {\n rows.push(\n React.createElement(\n Text,\n { key: `cat-${category}`, bold: true, color: theme.colors.accent },\n ` ${category}`,\n ),\n );\n for (const s of shortcuts) {\n const keyDisplay = s.keys.padEnd(22);\n rows.push(\n React.createElement(Text, { key: `${category}-${s.keys}` }, ` ${keyDisplay}${s.action}`),\n );\n }\n // Spacer between categories\n rows.push(React.createElement(Box, { key: `gap-${category}`, height: 1 }));\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"键盘快捷键\",\n subtitle: filter ? `过滤: ${filter}` : undefined,\n inputGuide: \"Escape 关闭 · 输入过滤\",\n accentColor: \"accent\",\n width: 65,\n },\n React.createElement(Box, { flexDirection: \"column\" }, ...rows),\n );\n}\n","/**\n * CommandPalette — fuzzy‑search command picker (Ctrl+K).\n *\n * Lists all available slash commands and actions. Supports\n * real‑time fuzzy filtering, arrow‑key navigation, and\n * Enter to execute.\n *\n * Design (§5.9f #10):\n * - Fuzzy search all available commands\n * - Max 8 items visible\n * - Enter to execute\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** A single command entry in the palette. */\nexport interface CommandEntry {\n name: string;\n description: string;\n}\n\n/** Built‑in commands. Phase 5 expands this with plugin‑registered commands. */\nconst BUILTIN_COMMANDS: CommandEntry[] = [\n { name: \"/sessions\", description: \"列出和管理会话\" },\n { name: \"/new\", description: \"创建新会话\" },\n { name: \"/fork\", description: \"派生当前会话\" },\n { name: \"/rename\", description: \"重命名当前会话\" },\n { name: \"/delete\", description: \"删除会话\" },\n { name: \"/resume\", description: \"恢复上次会话\" },\n { name: \"/config\", description: \"显示配置\" },\n { name: \"/settings\", description: \"打开设置面板\" },\n { name: \"/doctor\", description: \"运行系统诊断\" },\n { name: \"/theme\", description: \"更改颜色主题\" },\n { name: \"/model\", description: \"切换 AI 模型\" },\n { name: \"/compact\", description: \"压缩对话上下文\" },\n { name: \"/help\", description: \"显示键盘快捷键\" },\n { name: \"/mcp\", description: \"管理 MCP 服务器\" },\n { name: \"/plugin\", description: \"管理插件\" },\n { name: \"/skills\", description: \"浏览技能\" },\n { name: \"/context\", description: \"显示上下文用量\" },\n { name: \"/usage\", description: \"显示用量统计\" },\n { name: \"/tasks\", description: \"查看后台任务\" },\n { name: \"/snapshots\", description: \"浏览文件快照\" },\n { name: \"/stash\", description: \"管理暂存输入\" },\n { name: \"/diff\", description: \"查看文件差异\" },\n];\n\n/** Props for the CommandPalette. */\nexport interface CommandPaletteProps {\n /** Called when the user selects a command (Enter key). */\n onSelect(command: string): void;\n /** Called when the user dismisses (Escape key). */\n onCancel(): void;\n /** Additional commands from plugins/extensions. */\n extraCommands?: CommandEntry[];\n}\n\nconst MAX_VISIBLE = 12;\n\n/**\n * Command palette modal.\n *\n * Fuzzy‑filters the command list as the user types and supports\n * arrow‑key navigation with Enter to execute.\n */\nexport function CommandPalette({\n onSelect,\n onCancel,\n extraCommands,\n}: CommandPaletteProps): React.ReactElement {\n const theme = getTheme();\n const [selectedIndex, setSelectedIndex] = useState(0);\n\n const allCommands = [...BUILTIN_COMMANDS, ...(extraCommands ?? [])];\n\n const maxIndex = Math.max(0, allCommands.length - 1);\n const safeIndex = Math.min(selectedIndex, maxIndex);\n const visible = allCommands.slice(0, MAX_VISIBLE);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.return) {\n const cmd = allCommands[safeIndex];\n if (cmd) onSelect(cmd.name);\n return;\n }\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1));\n return;\n }\n if (key.downArrow) {\n setSelectedIndex(Math.min(maxIndex, selectedIndex + 1));\n return;\n }\n },\n [allCommands, safeIndex, maxIndex, selectedIndex, onSelect, onCancel],\n );\n\n useInkInput(handleKey);\n\n const items: React.ReactElement[] = [];\n for (let i = 0; i < visible.length; i++) {\n const cmd = visible[i]!;\n const isSelected = i === safeIndex;\n const prefix = isSelected ? \"❯ \" : \" \";\n const nameDisplay = cmd.name.padEnd(18);\n\n items.push(\n React.createElement(\n Box,\n { key: cmd.name, flexDirection: \"row\" },\n React.createElement(\n Text,\n {\n color: isSelected ? theme.colors.accent : undefined,\n bold: isSelected,\n },\n `${prefix}${nameDisplay}${cmd.description}`,\n ),\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"命令\",\n subtitle: \"输入搜索...\",\n inputGuide: \"Enter 执行 · Esc 关闭 · ↑↓ 导航\",\n accentColor: \"accent\",\n width: 65,\n },\n React.createElement(Box, { flexDirection: \"column\" }, ...items),\n );\n}\n","/**\n * ModelPicker — interactive model selection dialog.\n *\n * Displays available models with search filtering, pricing info,\n * context windows, and output limits.\n * Supports keyboard navigation (Up/Down/Enter/Esc) and setting defaults\n * with the `s` key.\n *\n * Triggered by /model or Ctrl+L.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport type { TuiModelInfo } from \"../types.js\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** Props for the ModelPicker component. */\nexport interface ModelPickerProps {\n /** Available models to display. */\n models: TuiModelInfo[];\n /** Currently selected model ID. */\n currentModel?: string;\n /** Called when the user selects a model. */\n onSelect: (modelId: string) => void;\n /** Called when the user sets a model as default. */\n onSetDefault?: (modelId: string) => void;\n /** Called when the user cancels. */\n onCancel: () => void;\n}\n\n/** Format context window size for display. */\nfunction formatContext(k: number): string {\n return k >= 1000 ? `${Math.round(k / 1000)}K` : `${k}`;\n}\n\n/** Format pricing for display (e.g. \"$0.27/$1.10\"). */\nfunction formatPrice(inputPrice?: number, outputPrice?: number): string {\n if (inputPrice === undefined || outputPrice === undefined) return \"—\";\n return `$${inputPrice}/$${outputPrice}`;\n}\n\n/**\n * Interactive model picker modal with search filtering.\n *\n * Navigation:\n * Type text → filter models by id/label\n * ↑/↓ — move cursor\n * Enter — select and close\n * s — set as default (does not close)\n * Esc — cancel\n */\nexport function ModelPicker({\n models,\n currentModel,\n onSelect,\n onSetDefault,\n onCancel,\n}: ModelPickerProps): React.ReactElement {\n const [filterText, setFilterText] = useState(\"\");\n const [cursor, setCursor] = useState(0);\n\n // Filter models by search text\n const filtered = filterText\n ? models.filter(\n (m) =>\n m.id.toLowerCase().includes(filterText.toLowerCase()) ||\n m.label.toLowerCase().includes(filterText.toLowerCase()),\n )\n : models;\n\n // Clamp cursor when filtered list changes\n const clampedCursor = filtered.length > 0 ? Math.min(cursor, filtered.length - 1) : 0;\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setCursor((prev) => (prev > 0 ? prev - 1 : Math.max(0, filtered.length - 1)));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => (prev < filtered.length - 1 ? prev + 1 : 0));\n return;\n }\n if (key.return) {\n const selected = filtered[clampedCursor];\n if (selected) onSelect(selected.id);\n return;\n }\n if (input === \"s\" && onSetDefault) {\n const selected = filtered[clampedCursor];\n if (selected) onSetDefault(selected.id);\n return;\n }\n if (key.backspace || key.delete) {\n setFilterText((prev) => prev.slice(0, -1));\n setCursor(0);\n return;\n }\n // Printable characters → filter\n if (input && input.length === 1 && !key.ctrl && !key.meta) {\n setFilterText((prev) => prev + input);\n setCursor(0);\n return;\n }\n },\n [filtered, clampedCursor, onSelect, onSetDefault, onCancel],\n );\n\n useInkInput(handleKey);\n\n // ── Render ────────────────────────────────────\n const items: React.ReactNode[] = [];\n\n // Search bar\n items.push(\n React.createElement(\n Box,\n { key: \"search\", flexDirection: \"row\", marginBottom: 1 },\n React.createElement(Text, { dimColor: true }, \"🔍 \"),\n React.createElement(\n Text,\n {},\n filterText || React.createElement(Text, { dimColor: true }, \"输入过滤...\"),\n ),\n React.createElement(Text, { dimColor: true }, \"█\"),\n filterText\n ? React.createElement(Text, { dimColor: true }, ` ${filtered.length}/${models.length}`)\n : null,\n ),\n );\n\n // Model list\n for (let i = 0; i < filtered.length; i++) {\n const model = filtered[i]!;\n const isActive = model.id === currentModel;\n const isCursor = i === clampedCursor;\n const prefix = isCursor ? \"❯\" : \" \";\n const ctxStr = formatContext(model.contextWindow);\n const priceStr = formatPrice(model.inputPrice, model.outputPrice);\n const activeMark = isActive ? \" ✓\" : \"\";\n\n items.push(\n React.createElement(\n Text,\n {\n key: model.id,\n bold: isCursor,\n color: isCursor ? \"cyan\" : isActive ? \"green\" : undefined,\n },\n `${prefix} ${model.id.slice(0, 28).padEnd(30)} ${ctxStr.padStart(6)} 上下文 ${priceStr.padStart(12)}${activeMark}`,\n ),\n );\n }\n\n if (filtered.length === 0) {\n items.push(React.createElement(Text, { key: \"empty\", dimColor: true }, \" 无匹配的模型。\"));\n }\n\n const guide = onSetDefault\n ? \"输入过滤 · ↑↓ 移动 · Enter 选择 · s 设为默认 · Esc 取消\"\n : \"输入过滤 · ↑↓ 移动 · Enter 选择 · Esc 取消\";\n\n return React.createElement(\n Dialog,\n { title: \"选择模型\", accentColor: \"accent\", inputGuide: guide, width: 78 },\n React.createElement(Box, { flexDirection: \"column\", marginY: 1 }, ...items),\n );\n}\n","/**\n * ConfigMenu — settings panel with tabbed categories.\n *\n * Settings are grouped into tabs: General, Models, Permissions, Appearance,\n * Advanced. Boolean settings toggle with Enter; text/number settings open\n * an edit prompt via the onEdit callback.\n *\n * Triggered by /config or /settings.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** A single configurable setting. */\nexport interface ConfigSetting {\n /** Setting key, e.g. \"autoCompact\". */\n key: string;\n /** Human‑readable label. */\n label: string;\n /** Current value. Type determines rendering: boolean → checkbox, string/number → inline display. */\n value: boolean | string | number;\n /** Category tab this setting belongs to. */\n category: string;\n}\n\n/** Tab definitions for the config menu. */\ninterface ConfigTab {\n id: string;\n label: string;\n}\n\nconst TABS: ConfigTab[] = [\n { id: \"general\", label: \"通用\" },\n { id: \"models\", label: \"模型\" },\n { id: \"permissions\", label: \"权限\" },\n { id: \"appearance\", label: \"外观\" },\n { id: \"advanced\", label: \"高级\" },\n];\n\n/** Default settings when no data is provided. */\nconst DEFAULT_SETTINGS: ConfigSetting[] = [\n { key: \"syntaxHighlighting\", label: \"语法高亮\", value: true, category: \"general\" },\n { key: \"autoCollapseTools\", label: \"自动折叠工具\", value: true, category: \"general\" },\n { key: \"showThinking\", label: \"显示思考过程\", value: false, category: \"general\" },\n { key: \"telemetry\", label: \"遥测\", value: true, category: \"general\" },\n { key: \"reduceMotion\", label: \"减少动画\", value: false, category: \"general\" },\n { key: \"vimMode\", label: \"Vim 模式\", value: false, category: \"general\" },\n { key: \"model\", label: \"默认模型\", value: \"deepseek-chat\", category: \"models\" },\n { key: \"autoCompact\", label: \"自动压缩上下文\", value: true, category: \"models\" },\n { key: \"fastMode\", label: \"快速模式\", value: false, category: \"models\" },\n { key: \"streamOutput\", label: \"流式输出\", value: true, category: \"models\" },\n { key: \"promptCache\", label: \"提示缓存\", value: true, category: \"models\" },\n { key: \"maxTokens\", label: \"每轮最大令牌数\", value: 4096, category: \"models\" },\n {\n key: \"yoloMode\",\n label: \"YOLO 模式(跳过所有权限)\",\n value: false,\n category: \"permissions\",\n },\n { key: \"workspaceTrust\", label: \"工作区信任\", value: true, category: \"permissions\" },\n {\n key: \"permissionTimeout\",\n label: \"权限超时(60 秒)\",\n value: true,\n category: \"permissions\",\n },\n { key: \"darkMode\", label: \"深色模式\", value: true, category: \"appearance\" },\n { key: \"compactLayout\", label: \"紧凑布局\", value: false, category: \"appearance\" },\n { key: \"showMascot\", label: \"显示吉祥物\", value: true, category: \"appearance\" },\n {\n key: \"showLineNumbers\",\n label: \"代码中显示行号\",\n value: false,\n category: \"appearance\",\n },\n { key: \"theme\", label: \"主题\", value: \"dark\", category: \"appearance\" },\n { key: \"debugLogging\", label: \"调试日志\", value: false, category: \"advanced\" },\n { key: \"devMode\", label: \"开发者模式\", value: false, category: \"advanced\" },\n {\n key: \"experimentalFeatures\",\n label: \"实验性功能\",\n value: false,\n category: \"advanced\",\n },\n];\n\n/** Props for the ConfigMenu component. */\nexport interface ConfigMenuProps {\n /** Active settings (optional; falls back to defaults). */\n settings?: ConfigSetting[];\n /** Called when a boolean setting is toggled. */\n onToggle: (key: string, value: boolean) => void;\n /** Called when a text/number setting needs editing. valueType helps the handler decide whether to parse as number. */\n onEdit?: (key: string, label: string, currentValue: string, valueType: \"text\" | \"number\") => void;\n /** Called when the user cancels. */\n onCancel: () => void;\n}\n\n/**\n * Detect the setting value type for rendering.\n * boolean → checkbox with toggle\n * string / number → inline value display, Enter to edit\n */\nfunction settingType(value: ConfigSetting[\"value\"]): \"boolean\" | \"text\" | \"number\" {\n if (typeof value === \"boolean\") return \"boolean\";\n if (typeof value === \"number\") return \"number\";\n return \"text\";\n}\n\n/** Format a setting value for display. */\nfunction formatValue(setting: ConfigSetting): string {\n const type = settingType(setting.value);\n if (type === \"boolean\") return setting.value ? \"✓\" : \"○\";\n return String(setting.value);\n}\n\n/**\n * Interactive settings panel with tabbed categories.\n *\n * Navigation:\n * ←/→ — switch tabs\n * ↑/↓ — move cursor\n * Enter — toggle boolean / edit text / edit number\n * Esc — close\n */\nexport function ConfigMenu({\n settings,\n onToggle,\n onEdit,\n onCancel,\n}: ConfigMenuProps): React.ReactElement {\n const items = settings ?? DEFAULT_SETTINGS;\n const [activeTab, setActiveTab] = useState(0);\n const [cursor, setCursor] = useState(0);\n\n const currentTab = TABS[activeTab]!;\n const tabItems = items.filter((s) => s.category === currentTab.id);\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.leftArrow) {\n setActiveTab((prev) => (prev > 0 ? prev - 1 : TABS.length - 1));\n setCursor(0);\n return;\n }\n if (key.rightArrow) {\n setActiveTab((prev) => (prev < TABS.length - 1 ? prev + 1 : 0));\n setCursor(0);\n return;\n }\n if (key.upArrow) {\n setCursor((prev) => (prev > 0 ? prev - 1 : tabItems.length - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => (prev < tabItems.length - 1 ? prev + 1 : 0));\n return;\n }\n if (key.return) {\n const setting = tabItems[cursor];\n if (!setting) return;\n const type = settingType(setting.value);\n if (type === \"boolean\") {\n onToggle(setting.key, !setting.value);\n } else if (onEdit) {\n onEdit(setting.key, setting.label, String(setting.value), type);\n }\n return;\n }\n if (key.escape) {\n onCancel();\n }\n },\n [activeTab, cursor, tabItems, onToggle, onEdit, onCancel],\n );\n\n useInkInput(handleKey);\n\n // ── Render tabs ─────────────────────────────\n const tabElements: React.ReactNode[] = [];\n for (let i = 0; i < TABS.length; i++) {\n const tab = TABS[i]!;\n const isActive = i === activeTab;\n tabElements.push(\n React.createElement(\n Text,\n { key: tab.id, bold: isActive, color: isActive ? \"cyan\" : \"grey\", underline: isActive },\n isActive ? `[${tab.label}]` : ` ${tab.label} `,\n ),\n );\n if (i < TABS.length - 1) {\n tabElements.push(React.createElement(Text, { key: `sep-${i}`, dimColor: true }, \" \"));\n }\n }\n\n // ── Render settings ─────────────────────────\n const settingElements: React.ReactNode[] = [];\n for (let i = 0; i < tabItems.length; i++) {\n const setting = tabItems[i]!;\n const isCursor = i === cursor;\n const prefix = isCursor ? \"❯\" : \" \";\n const type = settingType(setting.value);\n const displayVal = formatValue(setting);\n const editHint = type !== \"boolean\" ? \" [Enter 编辑]\" : \"\";\n\n settingElements.push(\n React.createElement(\n Text,\n { key: setting.key, bold: isCursor, color: isCursor ? \"cyan\" : undefined },\n `${prefix} ${displayVal} ${setting.label}${editHint}`,\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"设置\",\n accentColor: \"accent\",\n inputGuide: \"←→ 切换标签 · ↑↓ 移动 · Enter 切换/编辑 · Esc 关闭\",\n width: 68,\n },\n React.createElement(\n Box,\n { flexDirection: \"column\" },\n React.createElement(Box, { flexDirection: \"row\", marginBottom: 1 }, ...tabElements),\n React.createElement(Box, { flexDirection: \"column\" }, ...settingElements),\n ),\n );\n}\n","/**\n * ThemePicker — interactive theme selection dialog.\n *\n * Displays the six built‑in themes with a live preview swatch.\n * User navigates with arrow keys and presses Enter to apply.\n *\n * Triggered by /theme.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport type { ThemeName } from \"../types.js\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** Theme metadata for the picker. */\ninterface ThemeEntry {\n id: ThemeName;\n label: string;\n description: string;\n}\n\nconst THEME_ENTRIES: ThemeEntry[] = [\n { id: \"dark\", label: \"深色\", description: \"Tokyo Night 风格 — 低对比度,护眼舒适\" },\n { id: \"light\", label: \"浅色\", description: \"GitHub 风格 — 简洁明亮\" },\n { id: \"catppuccin\", label: \"Catppuccin\", description: \"舒缓的柔和色调\" },\n { id: \"monokai\", label: \"Monokai\", description: \"经典鲜艳的语法主题\" },\n { id: \"solarized\", label: \"Solarized\", description: \"为可读性精心调校的色彩\" },\n { id: \"dracula\", label: \"Dracula\", description: \"深紫色 — 戏剧性对比\" },\n];\n\n/** Props for the ThemePicker component. */\nexport interface ThemePickerProps {\n /** Currently active theme name. */\n currentTheme?: ThemeName;\n /** Called when the user selects a theme. */\n onSelect: (themeName: ThemeName) => void;\n /** Called when the user cancels. */\n onCancel: () => void;\n}\n\n/**\n * Interactive theme picker modal.\n *\n * Navigation:\n * ↑/↓ — move cursor\n * Enter — apply theme and close\n * Esc — cancel\n */\nexport function ThemePicker({\n currentTheme,\n onSelect,\n onCancel,\n}: ThemePickerProps): React.ReactElement {\n const [cursor, setCursor] = useState(\n Math.max(\n THEME_ENTRIES.findIndex((t) => t.id === currentTheme),\n 0,\n ),\n );\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.upArrow) {\n setCursor((prev) => (prev > 0 ? prev - 1 : THEME_ENTRIES.length - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => (prev < THEME_ENTRIES.length - 1 ? prev + 1 : 0));\n return;\n }\n if (key.return) {\n const selected = THEME_ENTRIES[cursor];\n if (selected) onSelect(selected.id);\n return;\n }\n if (key.escape) {\n onCancel();\n }\n },\n [cursor, onSelect, onCancel],\n );\n\n useInkInput(handleKey);\n\n const items: React.ReactNode[] = [];\n for (let i = 0; i < THEME_ENTRIES.length; i++) {\n const entry = THEME_ENTRIES[i]!;\n const isActive = entry.id === currentTheme;\n const isCursor = i === cursor;\n const prefix = isCursor ? \"❯\" : \" \";\n const marker = isActive ? \" (当前)\" : \"\";\n\n items.push(\n React.createElement(\n Text,\n {\n key: entry.id,\n bold: isCursor,\n color: isCursor ? \"cyan\" : isActive ? \"green\" : undefined,\n },\n `${prefix} ${entry.label.padEnd(16)} ${entry.description.slice(0, 44)}${marker}`,\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"主题\",\n accentColor: \"accent\",\n inputGuide: \"↑↓ 移动 · Enter 应用 · Esc 取消\",\n width: 72,\n },\n React.createElement(Box, { flexDirection: \"column\", marginY: 1 }, ...items),\n );\n}\n","/**\n * ConfirmDialog — generic yes/no confirmation dialog.\n *\n * Used for dangerous actions (delete session, restore snapshot, force exit).\n * Two options are presented: confirm and cancel. The user navigates with\n * ↑/↓ and confirms with Enter or cancels with Esc.\n *\n * Dangerous keywords in the message are highlighted in red.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** Dangerous keywords to highlight in red. */\nconst DANGER_WORDS = [\n \"delete\",\n \"remove\",\n \"destroy\",\n \"overwrite\",\n \"irreversible\",\n \"cannot be undone\",\n \"删除\",\n \"移除\",\n \"销毁\",\n \"覆盖\",\n \"不可逆\",\n \"无法撤销\",\n];\n\n/** Props for the ConfirmDialog component. */\nexport interface ConfirmDialogProps {\n /** Title shown in the border. */\n title: string;\n /** Body message explaining the action. */\n message: string;\n /** Label for the confirm option. Default: \"Yes\" */\n confirmLabel?: string;\n /** Label for the cancel option. Default: \"No\" */\n cancelLabel?: string;\n /** Called when the user confirms. */\n onConfirm: () => void;\n /** Called when the user cancels. */\n onCancel: () => void;\n}\n\n/** Highlight dangerous words in a message string with red color. */\nfunction renderDangerMessage(message: string): React.ReactNode {\n const lower = message.toLowerCase();\n const parts: React.ReactNode[] = [];\n let lastIndex = 0;\n\n // Find dangerous words and highlight them\n for (const word of DANGER_WORDS) {\n const idx = lower.indexOf(word);\n if (idx >= 0) {\n if (idx > lastIndex) {\n parts.push(\n React.createElement(Text, { key: `text-${lastIndex}` }, message.slice(lastIndex, idx)),\n );\n }\n parts.push(\n React.createElement(\n Text,\n { key: `danger-${idx}`, color: \"red\", bold: true },\n message.slice(idx, idx + word.length),\n ),\n );\n lastIndex = idx + word.length;\n }\n }\n\n if (lastIndex < message.length) {\n parts.push(React.createElement(Text, { key: `text-end` }, message.slice(lastIndex)));\n }\n\n return parts.length > 0\n ? React.createElement(Text, null, ...parts)\n : React.createElement(Text, null, message);\n}\n\n/**\n * Generic confirmation dialog with Yes/No options.\n *\n * Navigation:\n * ↑/↓ — switch between options\n * Enter — confirm current selection\n * Esc — cancel\n */\nexport function ConfirmDialog({\n title,\n message,\n confirmLabel = \"是\",\n cancelLabel = \"否\",\n onConfirm,\n onCancel,\n}: ConfirmDialogProps): React.ReactElement {\n const [selected, setSelected] = useState<\"confirm\" | \"cancel\">(\"cancel\");\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.upArrow || key.downArrow) {\n setSelected((prev) => (prev === \"confirm\" ? \"cancel\" : \"confirm\"));\n return;\n }\n if (key.return) {\n if (selected === \"confirm\") onConfirm();\n else onCancel();\n return;\n }\n if (key.escape) {\n onCancel();\n }\n },\n [selected, onConfirm, onCancel],\n );\n\n useInkInput(handleKey);\n\n return React.createElement(\n Dialog,\n {\n title,\n accentColor: \"error\",\n inputGuide: \"↑↓ 切换 · Enter 确认 · Esc 取消\",\n width: 60,\n },\n React.createElement(\n Box,\n { flexDirection: \"column\", marginY: 1 },\n renderDangerMessage(message),\n React.createElement(\n Box,\n { flexDirection: \"column\", marginTop: 2 },\n React.createElement(\n Text,\n { bold: selected === \"confirm\", color: selected === \"confirm\" ? \"red\" : undefined },\n selected === \"confirm\" ? `❯ ${confirmLabel}` : ` ${confirmLabel}`,\n ),\n React.createElement(\n Text,\n { bold: selected === \"cancel\", color: selected === \"cancel\" ? \"cyan\" : undefined },\n selected === \"cancel\" ? `❯ ${cancelLabel}` : ` ${cancelLabel}`,\n ),\n ),\n ),\n );\n}\n","/**\n * InputPrompt — single‑line text input modal.\n *\n * Used for rename session, set config values, enter search terms, etc.\n * The input field is pre‑filled with the current value and supports\n * basic editing (Backspace, arrow keys, typing).\n *\n * Shared across multiple modals that need text input.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** Props for the InputPrompt component. */\nexport interface InputPromptProps {\n /** Title shown in the border. */\n title: string;\n /** Initial value to pre‑fill the input. */\n initialValue?: string;\n /** Placeholder shown when input is empty. */\n placeholder?: string;\n /** Called when the user confirms with Enter. */\n onConfirm: (value: string) => void;\n /** Called when the user cancels with Esc. */\n onCancel: () => void;\n /** Maximum allowed input length. Default: 100. */\n maxLength?: number;\n}\n\n/**\n * Single‑line text input modal.\n *\n * Key bindings:\n * Enter — confirm and return value\n * Esc — cancel\n * Backspace — delete character before cursor\n * Delete — delete character at cursor\n * ←/→ — move cursor\n * Home/End — jump to start/end\n * Ctrl+A/E — jump to start/end\n * Ctrl+K — delete to end of line\n * Ctrl+W — delete previous word\n */\nexport function InputPrompt({\n title,\n initialValue = \"\",\n placeholder = \"\",\n onConfirm,\n onCancel,\n maxLength = 100,\n}: InputPromptProps): React.ReactElement {\n const [value, setValue] = useState(initialValue);\n const [cursor, setCursor] = useState(initialValue.length);\n\n /** State for the edit buffer. */\n interface EditState {\n value: string;\n cursor: number;\n }\n\n /** Result of an edit operation — null if the key wasn't an edit. */\n type EditResult = EditState | null;\n\n /** Handle deletion keys (Backspace, Delete, Ctrl+K, Ctrl+W). */\n function applyEditOp(input: string, key: Key, state: EditState): EditResult {\n const { value, cursor } = state;\n\n if (key.backspace && cursor > 0) {\n return { value: value.slice(0, cursor - 1) + value.slice(cursor), cursor: cursor - 1 };\n }\n if (key.delete && cursor < value.length) {\n return { value: value.slice(0, cursor) + value.slice(cursor + 1), cursor };\n }\n if (key.ctrl && input === \"k\") {\n return { value: value.slice(0, cursor), cursor };\n }\n if (key.ctrl && input === \"w\") {\n const before = value.slice(0, cursor);\n const match = before.match(/(.*)\\S\\s*$/);\n const newStart = match ? match[1]!.length : 0;\n return { value: value.slice(0, newStart) + value.slice(cursor), cursor: newStart };\n }\n return null;\n }\n\n /** Handle cursor movement keys. Returns new cursor position or -1. */\n function applyCursorMove(input: string, key: Key, state: EditState): number {\n const { value, cursor } = state;\n\n if (key.leftArrow) return Math.max(0, cursor - 1);\n if (key.rightArrow) return Math.min(value.length, cursor + 1);\n if (key.home || (key.ctrl && input === \"a\")) return 0;\n if (key.end || (key.ctrl && input === \"e\")) return value.length;\n return -1;\n }\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.return) {\n onConfirm(value);\n return;\n }\n\n const state: EditState = { value, cursor };\n\n const editResult = applyEditOp(input, key, state);\n if (editResult) {\n setValue(editResult.value);\n setCursor(editResult.cursor);\n return;\n }\n\n const newCursor = applyCursorMove(input, key, state);\n if (newCursor >= 0) {\n setCursor(newCursor);\n return;\n }\n\n // Regular text input\n if (input.length === 1 && value.length < maxLength) {\n setValue((prev) => prev.slice(0, cursor) + input + prev.slice(cursor));\n setCursor((prev) => prev + 1);\n }\n },\n [value, cursor, maxLength, onConfirm, onCancel],\n );\n\n useInkInput(handleKey);\n\n // Render input with cursor\n const beforeCursor = value.slice(0, cursor);\n const atCursor = value[cursor] ?? \" \";\n const afterCursor = value.slice(cursor + 1);\n const displayValue = value || placeholder;\n\n return React.createElement(\n Dialog,\n {\n title,\n accentColor: \"accent\",\n inputGuide: \"Enter 确认 · Esc 取消\",\n width: 60,\n },\n React.createElement(\n Box,\n { flexDirection: \"column\", marginY: 1 },\n React.createElement(\n Text,\n null,\n beforeCursor || (displayValue === placeholder ? \"\" : \"\"),\n React.createElement(Text, { inverse: true }, atCursor),\n afterCursor,\n value.length === 0 && placeholder\n ? React.createElement(Text, { dimColor: true }, ` ${placeholder}`)\n : null,\n ),\n ),\n );\n}\n","/**\n * DoctorPanel — system diagnostics check display.\n *\n * Shows the results of running the `lynx doctor` diagnostics in a\n * formatted modal. Each check item displays a status icon (✓/⚠/✗),\n * label, and optional detail / fix hint.\n *\n * Triggered by /doctor.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** Result of a single diagnostic check. */\nexport interface DoctorCheck {\n /** Human‑readable name of the check. */\n label: string;\n /** Status: \"ok\" = pass, \"warn\" = warning, \"error\" = failed. */\n status: \"ok\" | \"warn\" | \"error\";\n /** Optional detail shown on the same line. */\n detail?: string;\n /** Optional fix hint shown in dimmed text below the check. */\n fixHint?: string;\n}\n\n/** Props for the DoctorPanel component. */\nexport interface DoctorPanelProps {\n /** List of check results to display. */\n checks: DoctorCheck[];\n /** Called when the user cancels (Escape). */\n onCancel: () => void;\n}\n\n/** Icon and color mapping per status. */\nfunction statusIcon(status: DoctorCheck[\"status\"]): { icon: string; color: string } {\n switch (status) {\n case \"ok\":\n return { icon: \"✓\", color: \"green\" };\n case \"warn\":\n return { icon: \"⚠\", color: \"yellow\" };\n case \"error\":\n return { icon: \"✗\", color: \"red\" };\n }\n}\n\n/**\n * System diagnostics panel.\n *\n * Displays each check result with a status icon and optional detail.\n * The Escape key closes the panel (handled by the global handler).\n */\nexport function DoctorPanel({\n checks: initialChecks,\n onCancel,\n}: DoctorPanelProps): React.ReactElement {\n const [checks, setChecks] = useState(initialChecks);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n // 'r' re-runs built-in checks\n if (_input.toLowerCase() === \"r\") {\n setChecks(runBuiltinChecks());\n return;\n }\n },\n [onCancel],\n );\n\n useInkInput(handleKey);\n\n const items: React.ReactNode[] = [];\n\n for (let i = 0; i < checks.length; i++) {\n const check = checks[i]!;\n const { icon, color } = statusIcon(check.status);\n\n items.push(\n React.createElement(\n Box,\n { key: `dr-${i}`, flexDirection: \"column\" },\n React.createElement(\n Box,\n { flexDirection: \"row\" },\n React.createElement(Text, { color }, `${icon} `),\n React.createElement(Text, { bold: check.status === \"error\" }, check.label),\n check.detail ? React.createElement(Text, { dimColor: true }, ` — ${check.detail}`) : null,\n ),\n check.fixHint\n ? React.createElement(Text, { dimColor: true }, ` ${check.fixHint}`)\n : null,\n ),\n );\n }\n\n const okCount = checks.filter((c) => c.status === \"ok\").length;\n const warnCount = checks.filter((c) => c.status === \"warn\").length;\n const errorCount = checks.filter((c) => c.status === \"error\").length;\n\n const subtitle = `${okCount} 通过 · ${warnCount} 警告 · ${errorCount} 错误`;\n\n return React.createElement(\n Dialog,\n {\n title: \"系统诊断\",\n subtitle,\n accentColor: errorCount > 0 ? \"error\" : warnCount > 0 ? \"warning\" : \"success\",\n inputGuide: \"Esc 关闭 · r 重新检查\",\n width: 64,\n },\n React.createElement(Box, { flexDirection: \"column\", marginY: 1 }, ...items),\n );\n}\n\n/**\n * Run built‑in checks synchronously and return results.\n *\n * These checks run within the TUI process and don't require\n * spawning a separate `lynx doctor` subprocess.\n */\nexport function runBuiltinChecks(): DoctorCheck[] {\n const results: DoctorCheck[] = [];\n\n // Node.js version\n const nodeVersion = process.version;\n const nodeMajor = Number.parseInt(nodeVersion.slice(1).split(\".\")[0]!, 10);\n results.push({\n label: \"Node.js\",\n detail: nodeVersion,\n status: nodeMajor >= 18 ? \"ok\" : \"error\",\n fixHint: nodeMajor < 18 ? \"升级到 Node.js 18+\" : undefined,\n });\n\n // Platform\n results.push({\n label: \"平台\",\n detail: `${process.platform} ${process.arch}`,\n status: \"ok\",\n });\n\n // Lynx home directory\n const lynxHome =\n process.env.LYNX_HOME ?? `${process.env.HOME ?? process.env.USERPROFILE ?? \"~\"}/.lynx`;\n results.push({\n label: \"Lynx 目录\",\n detail: lynxHome,\n status: \"ok\",\n });\n\n // Memory usage\n const memMB = Math.round(process.memoryUsage().heapUsed / 1024 / 1024);\n results.push({\n label: \"内存\",\n detail: `${memMB} MB 堆内存`,\n status: memMB < 500 ? \"ok\" : memMB < 900 ? \"warn\" : \"error\",\n fixHint: memMB >= 900 ? \"建议重启或启用自动压缩\" : undefined,\n });\n\n // Uptime\n const uptimeMin = Math.floor(process.uptime() / 60);\n results.push({\n label: \"进程运行时间\",\n detail:\n uptimeMin < 60\n ? `${uptimeMin}分钟`\n : `${Math.floor(uptimeMin / 60)}小时 ${uptimeMin % 60}分钟`,\n status: \"ok\",\n });\n\n return results;\n}\n","/**\n * FilePicker — interactive file selection modal.\n *\n * Walks the workspace directory to collect candidates, then filters\n * in memory as the user types. Supports flat list and tree view modes\n * with git status coloring.\n *\n * Design (§5.9f #2, #10):\n * - Walk workspace (exclude .git, node_modules, dist, build, .venv)\n * - Flat mode: filter by typing, sort by relevance (mtime + match position)\n * - Tree mode: group by directory, expand/collapse with Enter/Tab\n * - Git status colors (M=amber, A=green, D=red, ?=dim)\n * - ↑↓ to navigate, Enter to select file, Esc to cancel\n * - Tab to toggle flat/tree mode\n * - Max 20,000 candidates, max 15 visible\n */\n\nimport React, { useState, useCallback, useMemo } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { readdirSync, statSync } from \"node:fs\";\nimport { join, relative, dirname, basename } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Props for the FilePicker modal. */\nexport interface FilePickerProps {\n /** Workspace root directory to walk. */\n workspace: string;\n /** Called when the user selects a file (Enter). */\n onSelect: (filePath: string) => void;\n /** Called when the user dismisses (Escape). */\n onCancel: () => void;\n /** Initial filter text (e.g. from @-mention). */\n initialFilter?: string;\n}\n\n/** A candidate file entry with metadata for sorting. */\ninterface FileEntry {\n /** Path relative to workspace. */\n path: string;\n /** Modification time (ms since epoch). */\n mtime: number;\n}\n\n/** Directories to skip during traversal. */\nconst SKIP_DIRS = new Set([\n \".git\",\n \"node_modules\",\n \"dist\",\n \"build\",\n \".venv\",\n \"venv\",\n \"__pycache__\",\n \".next\",\n \".nuxt\",\n \"target\",\n \"coverage\",\n \".cache\",\n \".idea\",\n \".vscode\",\n \"out\",\n \".lynx\",\n]);\n\n/** Max candidate files to collect. */\nconst MAX_CANDIDATES = 20_000;\n/** Max visible items in the list. */\nconst MAX_VISIBLE = 15;\n/** Max recursion depth. */\nconst MAX_DEPTH = 20;\n\n/** Git status code → display color mapping. */\nconst GIT_STATUS_LABEL: Record<string, { label: string; color: string }> = {\n M: { label: \"M\", color: \"#e5c07b\" }, // amber — modified\n A: { label: \"A\", color: \"#98c379\" }, // green — added\n D: { label: \"D\", color: \"#e06c75\" }, // red — deleted\n R: { label: \"R\", color: \"#61afef\" }, // blue — renamed\n C: { label: \"C\", color: \"#61afef\" }, // blue — copied\n \"?\": { label: \"?\", color: \"#5c6370\" }, // grey — untracked\n \"!\": { label: \"!\", color: \"#e06c75\" }, // red — ignored\n};\n\n/** Tree node for directory/file hierarchy. */\ninterface TreeNode {\n name: string;\n path: string;\n isDir: boolean;\n children: TreeNode[];\n file?: FileEntry;\n expanded: boolean;\n}\n\n/** Tree display item (flattened for rendering). */\ninterface TreeItem {\n entry: FileEntry;\n depth: number;\n isLast: boolean;\n isDir: boolean;\n expanded: boolean;\n childCount: number;\n}\n\n/**\n * Recursively walk a directory collecting file paths.\n *\n * Stops at MAX_CANDIDATES to prevent memory issues.\n */\nfunction walkFiles(dir: string, workspace: string, candidates: FileEntry[], depth: number): void {\n if (depth > MAX_DEPTH || candidates.length >= MAX_CANDIDATES) return;\n\n let entries: Array<{ name: string; isDirectory(): boolean; isFile(): boolean }>;\n try {\n // HACK: Node.js @types/node resolves Dirent<NonSharedBuffer> in this TS version,\n // but the runtime value has string names. Cast through unknown.\n entries = readdirSync(dir, { withFileTypes: true }) as unknown as typeof entries;\n } catch {\n return; // Permission denied or other error\n }\n\n for (const entry of entries) {\n if (candidates.length >= MAX_CANDIDATES) break;\n if (entry.name.startsWith(\".\") && entry.name !== \".\" && entry.name !== \"..\") {\n // Skip hidden files/dirs except for explicit include patterns\n // (Phase 5: configurable include list)\n if (!entry.name.startsWith(\".env\")) continue;\n }\n\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name)) continue;\n walkFiles(fullPath, workspace, candidates, depth + 1);\n } else if (entry.isFile()) {\n try {\n const st = statSync(fullPath);\n candidates.push({\n path: relative(workspace, fullPath).replace(/\\\\/g, \"/\"),\n mtime: st.mtimeMs,\n });\n } catch {\n // Stat failed, skip\n }\n }\n }\n}\n\n/**\n * Parse `git status --porcelain` and return a map from relative path → status code.\n *\n * Returns empty map if workspace is not a git repo or git is not available.\n */\nfunction buildGitStatusMap(workspace: string): Map<string, string> {\n const statusMap = new Map<string, string>();\n try {\n const output = execSync(\"git -C . status --porcelain\", {\n cwd: workspace,\n encoding: \"utf-8\",\n timeout: 3000,\n });\n for (const line of output.trim().split(\"\\n\")) {\n if (!line) continue;\n // Format: \"XY path\" where X=staging, Y=worktree status\n const status = line.slice(1, 2).trim() || line.slice(0, 1).trim();\n // For renamed files, the path is \"old -> new\"\n let filePath = line.slice(3).trim();\n const arrowIdx = filePath.indexOf(\" -> \");\n if (arrowIdx > 0) filePath = filePath.slice(arrowIdx + 4);\n statusMap.set(filePath.replace(/\\\\/g, \"/\"), status || \"?\");\n }\n } catch {\n // Not a git repo or git not available — return empty map\n }\n return statusMap;\n}\n\n/**\n * Build a tree of directory nodes from flat file entries.\n *\n * Returns root tree node containing all files organized by directory.\n */\nfunction buildFileTree(files: FileEntry[]): TreeNode {\n const root: TreeNode = { name: \"\", path: \"\", isDir: true, children: [], expanded: true };\n\n for (const file of files) {\n const parts = file.path.split(\"/\");\n let current = root;\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]!;\n const isLast = i === parts.length - 1;\n const fullPath = parts.slice(0, i + 1).join(\"/\");\n let child = current.children.find((c) => c.name === part);\n if (!child) {\n child = { name: part, path: fullPath, isDir: !isLast, children: [], expanded: false };\n if (isLast) child.file = file;\n current.children.push(child);\n }\n current = child;\n }\n }\n\n // Recursively sort: directories first, then files; both alphabetically\n function sortNode(node: TreeNode): void {\n node.children.sort((a, b) => {\n if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n for (const child of node.children) sortNode(child);\n }\n sortNode(root);\n return root;\n}\n\n/**\n * Flatten a tree into a list of TreeItems for display, respecting expand/collapse state.\n */\nfunction flattenTree(\n node: TreeNode,\n depth: number,\n expandedDirs: Set<string>,\n result: TreeItem[],\n): void {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i]!;\n const isLast = i === node.children.length - 1;\n if (child.isDir) {\n const isExpanded = expandedDirs.has(child.path);\n result.push({\n entry: { path: child.path + \"/\", mtime: 0 },\n depth,\n isLast,\n isDir: true,\n expanded: isExpanded,\n childCount: child.children.length,\n });\n if (isExpanded) {\n flattenTree(child, depth + 1, expandedDirs, result);\n }\n } else if (child.file) {\n result.push({\n entry: child.file,\n depth,\n isLast,\n isDir: false,\n expanded: false,\n childCount: 0,\n });\n }\n }\n}\n\n/**\n * Match candidates against a filter string.\n *\n * Returns entries whose path contains the filter (case-insensitive),\n * sorted by relevance: exact prefix match > substring at word boundary > general substring,\n * with mtime as tiebreaker (newer files first).\n */\nfunction matchCandidates(candidates: FileEntry[], filter: string): FileEntry[] {\n if (!filter) return candidates.slice(0, MAX_VISIBLE);\n\n const lower = filter.toLowerCase();\n const scored: { entry: FileEntry; score: number }[] = [];\n\n for (const entry of candidates) {\n const pathLower = entry.path.toLowerCase();\n const idx = pathLower.indexOf(lower);\n if (idx === -1) continue;\n\n // Score: higher is better\n let score = 0;\n if (idx === 0) score += 1000;\n else if (pathLower[idx - 1] === \"/\" || pathLower[idx - 1] === \"_\") score += 500;\n // Prefer shorter paths (match closer to filename)\n score += Math.max(0, 200 - idx);\n // Boost by recency (max ~100 points for files modified in last hour)\n const hoursAgo = (Date.now() - entry.mtime) / 3_600_000;\n score += Math.max(0, 100 - hoursAgo * 10);\n\n scored.push({ entry, score });\n }\n\n scored.sort((a, b) => b.score - a.score);\n return scored.slice(0, MAX_VISIBLE).map((s) => s.entry);\n}\n\n/**\n * Interactive file picker modal with flat list and tree view modes.\n *\n * Flat mode: files sorted by relevance. Tree mode: files grouped by\n * directory with expand/collapse. Git status colors indicate modifications.\n */\nexport function FilePicker({\n workspace,\n onSelect,\n onCancel,\n initialFilter = \"\",\n}: FilePickerProps): React.ReactElement {\n const theme = getTheme();\n\n // Walk files and git status once on mount\n const candidates = useMemo<FileEntry[]>(() => {\n const results: FileEntry[] = [];\n walkFiles(workspace, workspace, results, 0);\n results.sort((a, b) => b.mtime - a.mtime);\n return results;\n }, [workspace]);\n\n const gitStatusMap = useMemo(() => buildGitStatusMap(workspace), [workspace]);\n\n // Build tree from candidates (stable reference)\n const fileTree = useMemo(() => buildFileTree(candidates), [candidates]);\n\n const [filter, setFilter] = useState(initialFilter);\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [isTreeMode, setIsTreeMode] = useState(false);\n const [expandedDirs, setExpandedDirs] = useState<Set<string>>(new Set());\n\n // In tree mode: flatten tree; in flat mode: match filter\n const treeItems = useMemo<TreeItem[]>(() => {\n if (!isTreeMode) return [];\n const flat: TreeItem[] = [];\n flattenTree(fileTree, 0, expandedDirs, flat);\n // Apply filter\n if (!filter) return flat;\n const lower = filter.toLowerCase();\n return flat.filter(\n (item) =>\n item.entry.path.toLowerCase().includes(lower) ||\n (item.isDir && item.entry.path.toLowerCase().includes(lower)),\n );\n }, [isTreeMode, fileTree, expandedDirs, filter]);\n\n const flatMatched = useMemo(\n () => (!isTreeMode ? matchCandidates(candidates, filter) : []),\n [isTreeMode, candidates, filter],\n );\n\n const itemCount = isTreeMode ? treeItems.length : flatMatched.length;\n const maxIndex = Math.max(0, itemCount - 1);\n const safeIndex = Math.min(selectedIndex, maxIndex);\n\n // Toggle directory expand/collapse\n const toggleDir = useCallback((dirPath: string) => {\n setExpandedDirs((prev) => {\n const next = new Set(prev);\n if (next.has(dirPath)) next.delete(dirPath);\n else next.add(dirPath);\n return next;\n });\n }, []);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n // Tab toggles flat/tree mode\n if (key.tab) {\n setIsTreeMode((prev) => !prev);\n setSelectedIndex(0);\n return;\n }\n if (key.return) {\n if (isTreeMode) {\n const item = treeItems[safeIndex];\n if (item) {\n if (item.isDir) {\n toggleDir(item.entry.path.replace(/\\/$/, \"\"));\n return;\n }\n onSelect(item.entry.path);\n }\n return;\n }\n const file = flatMatched[safeIndex];\n if (file) onSelect(file.path);\n return;\n }\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1));\n return;\n }\n if (key.downArrow) {\n setSelectedIndex(Math.min(maxIndex, selectedIndex + 1));\n return;\n }\n if (key.backspace) {\n setFilter((f) => f.slice(0, -1));\n setSelectedIndex(0);\n return;\n }\n if (input.length === 1 && !key.ctrl && !key.meta) {\n setFilter((f) => f + input);\n setSelectedIndex(0);\n }\n },\n [\n isTreeMode,\n treeItems,\n flatMatched,\n safeIndex,\n maxIndex,\n selectedIndex,\n toggleDir,\n onSelect,\n onCancel,\n ],\n );\n\n useInkInput(handleKey);\n\n // ── Render helpers ──────────────────────────────\n\n /** Get the display color for a file path based on git status. */\n function gitColor(filePath: string): string | undefined {\n const status = gitStatusMap.get(filePath);\n if (!status) return undefined;\n const entry = GIT_STATUS_LABEL[status];\n return entry?.color;\n }\n\n /** Format a relative time string. */\n function formatTime(ms: number): string {\n const sec = Math.floor((Date.now() - ms) / 1000);\n if (sec < 60) return `${sec}秒前`;\n if (sec < 3600) return `${Math.floor(sec / 60)}分钟前`;\n if (sec < 86400) return `${Math.floor(sec / 3600)}小时前`;\n return `${Math.floor(sec / 86400)}天前`;\n }\n\n /** Draw tree connector lines for a given depth and isLast flags. */\n function treePrefix(depth: number, isLast: boolean): string {\n if (depth === 0) return \"\";\n let prefix = \"\";\n for (let d = 0; d < depth; d++) {\n prefix += \"│ \";\n }\n return prefix.slice(0, -2) + (isLast ? \"└─ \" : \"├─ \");\n }\n\n // ── Render items ──────────────────────────────\n\n const items: React.ReactElement[] = [];\n\n if (isTreeMode) {\n for (let i = 0; i < treeItems.length; i++) {\n const item = treeItems[i]!;\n const isSelected = i === safeIndex;\n const cursor = isSelected ? \"❯\" : \" \";\n const depthPrefix = treePrefix(item.depth, item.isLast);\n\n if (item.isDir) {\n const icon = item.expanded ? \"▼\" : \"▶\";\n const displayPath = item.entry.path.replace(/\\/$/, \"\");\n const dirName = displayPath.includes(\"/\")\n ? displayPath.slice(displayPath.lastIndexOf(\"/\") + 1)\n : displayPath;\n items.push(\n React.createElement(\n Box,\n { key: `dir:${displayPath}`, flexDirection: \"row\" },\n React.createElement(\n Text,\n {\n color: isSelected ? theme.colors.accent : theme.colors.dim,\n bold: isSelected,\n },\n `${cursor} ${depthPrefix}${icon} ${dirName}/ (${item.childCount})`,\n ),\n ),\n );\n } else {\n const filePath = item.entry.path;\n const fileName = filePath.includes(\"/\")\n ? filePath.slice(filePath.lastIndexOf(\"/\") + 1)\n : filePath;\n const statusColor = gitColor(filePath);\n const status = gitStatusMap.get(filePath);\n const statusLabel = status ? ` ${GIT_STATUS_LABEL[status]?.label ?? status}` : \"\";\n\n items.push(\n React.createElement(\n Box,\n { key: filePath, flexDirection: \"row\" },\n React.createElement(\n Text,\n {\n color: isSelected ? theme.colors.accent : undefined,\n bold: isSelected,\n },\n `${cursor} ${depthPrefix}${fileName}`,\n ),\n statusLabel ? React.createElement(Text, { color: statusColor }, statusLabel) : null,\n React.createElement(Text, { dimColor: true }, ` ${formatTime(item.entry.mtime)}`),\n ),\n );\n }\n }\n } else {\n // Flat mode\n for (let i = 0; i < flatMatched.length; i++) {\n const file = flatMatched[i]!;\n const isSelected = i === safeIndex;\n const prefix = isSelected ? \"❯ \" : \" \";\n const statusColor = gitColor(file.path);\n const status = gitStatusMap.get(file.path);\n const statusLabel = status ? ` ${GIT_STATUS_LABEL[status]?.label ?? status}` : \"\";\n\n items.push(\n React.createElement(\n Box,\n { key: file.path, flexDirection: \"row\" },\n React.createElement(\n Text,\n { color: isSelected ? theme.colors.accent : undefined, bold: isSelected },\n `${prefix}${file.path}`,\n ),\n statusLabel ? React.createElement(Text, { color: statusColor }, statusLabel) : null,\n React.createElement(Text, { dimColor: true }, ` ${formatTime(file.mtime)}`),\n ),\n );\n }\n }\n\n const modeLabel = isTreeMode ? \"树形\" : \"列表\";\n\n return React.createElement(\n Dialog,\n {\n title: \"文件\",\n subtitle: `${modeLabel} · 过滤${filter ? `: ${filter}` : \"\"} (${candidates.length} 个文件)`,\n inputGuide: \"Enter 选择 · Esc 关闭 · Tab 切换视图 · ↑↓ 导航 · 打字过滤\",\n accentColor: \"accent\",\n width: 75,\n },\n // ── Mode indicator ──────────────────────\n React.createElement(\n Box,\n { flexDirection: \"row\", marginBottom: 1 },\n React.createElement(\n Text,\n { color: isTreeMode ? theme.colors.accent : theme.colors.dim, bold: isTreeMode },\n \" 树形 \",\n ),\n React.createElement(Text, { dimColor: true }, \" \"),\n React.createElement(\n Text,\n { color: !isTreeMode ? theme.colors.accent : theme.colors.dim, bold: !isTreeMode },\n \" 列表 \",\n ),\n ),\n items.length > 0\n ? React.createElement(Box, { flexDirection: \"column\" }, ...items)\n : React.createElement(\n Text,\n { dimColor: true },\n filter ? ` 无匹配 \"${filter}\" 的文件` : \" 工作区中无文件。\",\n ),\n );\n}\n","/**\n * StashPicker — stashed input browser and restore dialog.\n *\n * Displays previously stashed inputs (LIFO order, newest first)\n * with truncated content previews and timestamps. Users can\n * restore or delete stashed items.\n *\n * Design (§5.9f #15):\n * - LIFO order (newest on top)\n * - Content truncated to 60 chars\n * - ↑↓ to navigate, Enter to restore, Ctrl+D to delete\n * - Max 200 items\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** A single stashed item. */\nexport interface StashEntry {\n /** Unique identifier. */\n id: string;\n /** Truncated content preview. */\n preview: string;\n /** Unix timestamp when stashed. */\n timestamp: number;\n}\n\n/** Props for the StashPicker modal. */\nexport interface StashPickerProps {\n /** Stashed items (newest first). */\n items: StashEntry[];\n /** Called when the user restores an item (Enter). */\n onRestore: (id: string) => void;\n /** Called when the user deletes an item (Ctrl+D). */\n onDelete: (id: string) => void;\n /** Called when the user dismisses (Escape). */\n onCancel: () => void;\n /** Called to stash the current input (Ctrl+S while open is no-op here). */\n}\n\n/** Max visible items. */\nconst MAX_VISIBLE = 12;\n/** Max preview length. */\nconst PREVIEW_LEN = 60;\n\n/**\n * Stash picker modal.\n *\n * Lists stashed inputs with restore and delete actions.\n */\nexport function StashPicker({\n items,\n onRestore,\n onDelete,\n onCancel,\n}: StashPickerProps): React.ReactElement {\n const theme = getTheme();\n const [selectedIndex, setSelectedIndex] = useState(0);\n\n const maxIndex = Math.max(0, items.length - 1);\n const safeIndex = Math.min(selectedIndex, maxIndex);\n const visible = items.slice(0, MAX_VISIBLE);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.return) {\n const item = visible[safeIndex];\n if (item) onRestore(item.id);\n return;\n }\n // Ctrl+D → delete\n if (key.ctrl && input === \"d\") {\n const item = visible[safeIndex];\n if (item) onDelete(item.id);\n return;\n }\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1));\n return;\n }\n if (key.downArrow) {\n setSelectedIndex(Math.min(maxIndex, selectedIndex + 1));\n return;\n }\n },\n [visible, safeIndex, maxIndex, selectedIndex, onRestore, onDelete, onCancel],\n );\n\n useInkInput(handleKey);\n\n // ── Format relative time ──────────────────────\n\n function formatTime(ts: number): string {\n const sec = Math.floor((Date.now() - ts) / 1000);\n if (sec < 60) return \"just now\";\n if (sec < 3600) return `${Math.floor(sec / 60)}m ago`;\n if (sec < 86400) return `${Math.floor(sec / 3600)}h ago`;\n return `${Math.floor(sec / 86400)}d ago`;\n }\n\n // ── Render items ──────────────────────────────\n\n const listItems: React.ReactElement[] = [];\n for (let i = 0; i < visible.length; i++) {\n const item = visible[i]!;\n const isSelected = i === safeIndex;\n const prefix = isSelected ? \"❯ \" : \" \";\n const preview =\n item.preview.length > PREVIEW_LEN ? item.preview.slice(0, PREVIEW_LEN) + \"…\" : item.preview;\n\n listItems.push(\n React.createElement(\n Box,\n { key: item.id, flexDirection: \"row\" },\n React.createElement(\n Text,\n {\n color: isSelected ? theme.colors.accent : undefined,\n bold: isSelected,\n },\n `${prefix}\"${preview}\"`,\n ),\n React.createElement(Text, { dimColor: true }, ` ${formatTime(item.timestamp)}`),\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"Stash\",\n subtitle: `${items.length} stashed item(s)`,\n inputGuide: \"Enter restore · Ctrl+D delete · Esc close · ↑↓ navigate\",\n accentColor: \"accent\",\n width: 70,\n },\n listItems.length > 0\n ? React.createElement(Box, { flexDirection: \"column\" }, ...listItems)\n : React.createElement(Text, { dimColor: true }, \" No stashed items.\"),\n );\n}\n","/**\n * DiffViewer — git diff visualisation triggered by /diff.\n *\n * Displays a file list with git status indicators, then a detailed\n * unified diff view when a file is selected. Data is fetched via\n * the onRequestDiff callback from the CLI bridge layer.\n */\n\nimport React, { useState, useCallback, useEffect } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** A single changed file with diff content. */\nexport interface DiffFile {\n /** Relative file path. */\n path: string;\n /** Git status: M(odified), A(dded), D(eleted), R(enamed). */\n status: string;\n /** Unified diff text. */\n diff: string;\n}\n\n/** Props for the DiffViewer component. */\nexport interface DiffViewerProps {\n /** Async callback that fetches the diff data from git. */\n onRequestDiff?: () => Promise<DiffFile[]>;\n /** Called when the user dismisses the viewer. */\n onCancel: () => void;\n}\n\nconst MAX_VISIBLE = 12;\nconst DIFF_PREVIEW_LINES = 6;\n\n/** Colorise a git status character. */\nfunction statusColor(status: string, theme: ReturnType<typeof getTheme>): string {\n switch (status) {\n case \"M\":\n return theme.colors.warning ?? \"yellow\";\n case \"A\":\n return theme.colors.success ?? \"green\";\n case \"D\":\n return theme.colors.error ?? \"red\";\n case \"R\":\n return theme.colors.accent ?? \"cyan\";\n default:\n return theme.colors.dim ?? \"grey\";\n }\n}\n\n/**\n * Git diff visualisation panel.\n *\n * Two modes:\n * - File list (default): shows changed files with status, preview snippet.\n * - Detail view: full unified diff for the selected file.\n * Arrow keys navigate the file list; Enter opens detail; Escape goes back.\n */\nexport function DiffViewer({ onRequestDiff, onCancel }: DiffViewerProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n\n const [files, setFiles] = useState<DiffFile[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [selectedFile, setSelectedFile] = useState<DiffFile | null>(null);\n const [cursor, setCursor] = useState(0);\n const [diffLines, setDiffLines] = useState<string[]>([]);\n\n const maxIndex = Math.max(0, files.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n // Fetch diff data on mount\n useEffect(() => {\n if (!onRequestDiff) {\n setLoading(false);\n setFiles([]);\n return;\n }\n onRequestDiff()\n .then((data) => {\n setFiles(data);\n setLoading(false);\n })\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n setLoading(false);\n });\n }, [onRequestDiff]);\n\n // Load full diff when a file is selected\n useEffect(() => {\n if (selectedFile) {\n setDiffLines(selectedFile.diff.split(\"\\n\"));\n }\n }, [selectedFile]);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = files.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (selectedFile) {\n // Detail view: only Escape goes back to file list\n if (key.escape) {\n setSelectedFile(null);\n setDiffLines([]);\n }\n return;\n }\n\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n if (key.return && files.length > 0) {\n setSelectedFile(files[safeCursor] ?? null);\n }\n },\n [files, safeCursor, maxIndex, selectedFile],\n );\n\n useInkInput(handleKey);\n\n // ── Detail view — full diff ──────────────────\n\n if (selectedFile) {\n const maxLines = 30;\n const head = diffLines.slice(0, maxLines);\n const truncated = diffLines.length > maxLines;\n const diffNodes = head.map((line, i) => {\n let color = dim;\n if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) color = theme.colors.success ?? \"green\";\n else if (line.startsWith(\"-\") && !line.startsWith(\"---\")) color = theme.colors.error ?? \"red\";\n else if (line.startsWith(\"@@\")) color = theme.colors.accent ?? \"cyan\";\n return React.createElement(Text, { key: i, color }, line);\n });\n if (truncated) {\n diffNodes.push(\n React.createElement(\n Text,\n { key: \"trunc\", color: dim },\n `... 还有 ${diffLines.length - maxLines} 行被截断`,\n ),\n );\n }\n return React.createElement(\n Dialog,\n {\n title: selectedFile.path,\n subtitle: `状态: ${selectedFile.status}`,\n accentColor:\n selectedFile.status === \"D\"\n ? \"error\"\n : selectedFile.status === \"A\"\n ? \"success\"\n : \"warning\",\n inputGuide: \"Esc 返回文件列表\",\n width: 80,\n },\n React.createElement(Box, { flexDirection: \"column\", gap: 0 }, ...diffNodes),\n );\n }\n\n // ── File list view ───────────────────────────\n\n if (loading) {\n return React.createElement(\n Dialog,\n {\n title: \"差异\",\n subtitle: \"读取中...\",\n accentColor: \"dim\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: dim }, \"正在执行 git diff...\"),\n );\n }\n\n if (error) {\n return React.createElement(\n Dialog,\n {\n title: \"差异\",\n subtitle: \"读取失败\",\n accentColor: \"error\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: theme.colors.error }, error),\n );\n }\n\n if (files.length === 0) {\n return React.createElement(\n Dialog,\n { title: \"差异\", subtitle: \"无变更\", accentColor: \"dim\", inputGuide: \"Esc 关闭\", width: 70 },\n React.createElement(Text, { color: dim }, \"工作区无变更。\"),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"差异\",\n subtitle: `${files.length} 个文件变更`,\n accentColor: \"warning\",\n inputGuide: \"↑↓ 导航 · Enter 详细 · Esc 关闭\",\n width: 80,\n },\n ...visible.map((f, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const prefix = isSelected ? \">\" : \" \";\n const sc = statusColor(f.status, theme);\n\n return React.createElement(\n Box,\n { key: f.path, flexDirection: \"column\" },\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color: sc, bold: true }, `[${f.status}]`),\n React.createElement(\n Text,\n { color: isSelected ? theme.colors.accent : undefined },\n f.path,\n ),\n ),\n React.createElement(\n Box,\n { marginLeft: 5 },\n React.createElement(\n Text,\n { color: dim },\n f.diff.split(\"\\n\").slice(0, DIFF_PREVIEW_LINES).join(\"\\n\").substring(0, 60) +\n (f.diff.length > 60 ? \"...\" : \"\"),\n ),\n ),\n );\n }),\n );\n}\n","/**\n * SnapshotBrowser — file snapshot list triggered by /snapshots.\n *\n * Lists all file snapshots with timestamps and labels. Users can\n * browse snapshots and view restore options. Data is fetched via\n * the onRequestSnapshots callback from the CLI bridge layer.\n */\n\nimport React, { useState, useCallback, useEffect } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** A single snapshot record. */\nexport interface SnapshotEntry {\n /** Unique snapshot identifier. */\n id: string;\n /** Unix-ms timestamp when the snapshot was captured. */\n timestamp: number;\n /** Human-readable snapshot label. */\n label: string;\n}\n\n/** Props for the SnapshotBrowser component. */\nexport interface SnapshotBrowserProps {\n /** Async callback that fetches snapshot records. */\n onRequestSnapshots?: () => Promise<SnapshotEntry[]>;\n /** Called when the user dismisses the browser. */\n onCancel: () => void;\n}\n\nconst MAX_VISIBLE = 12;\n\n/** Format a Unix‑ms timestamp to a human‑readable date string. */\nfunction formatTimestamp(ms: number): string {\n const d = new Date(ms);\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;\n}\n\n/**\n * File snapshot browser.\n *\n * Lists all captured snapshots sorted by timestamp (newest first).\n * Arrow keys navigate; currently read‑only (restore support in a future phase).\n */\nexport function SnapshotBrowser({\n onRequestSnapshots,\n onCancel,\n}: SnapshotBrowserProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n\n const [snapshots, setSnapshots] = useState<SnapshotEntry[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [cursor, setCursor] = useState(0);\n\n const maxIndex = Math.max(0, snapshots.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n useEffect(() => {\n if (!onRequestSnapshots) {\n setLoading(false);\n setSnapshots([]);\n return;\n }\n onRequestSnapshots()\n .then((data) => {\n setSnapshots(data);\n setLoading(false);\n })\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n setLoading(false);\n });\n }, [onRequestSnapshots]);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = snapshots.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n },\n [maxIndex],\n );\n\n useInkInput(handleKey);\n\n if (loading) {\n return React.createElement(\n Dialog,\n {\n title: \"快照\",\n subtitle: \"读取中...\",\n accentColor: \"dim\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: dim }, \"正在加载快照列表...\"),\n );\n }\n\n if (error) {\n return React.createElement(\n Dialog,\n {\n title: \"快照\",\n subtitle: \"读取失败\",\n accentColor: \"error\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: theme.colors.error }, error),\n );\n }\n\n if (snapshots.length === 0) {\n return React.createElement(\n Dialog,\n { title: \"快照\", subtitle: \"无快照\", accentColor: \"dim\", inputGuide: \"Esc 关闭\", width: 70 },\n React.createElement(\n Box,\n { flexDirection: \"column\", gap: 1 },\n React.createElement(Text, { color: dim }, \"暂无文件快照。\"),\n React.createElement(\n Text,\n { color: dim },\n \"使用 /stash 暂存输入,或通过 FilePicker 管理文件。\",\n ),\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"快照\",\n subtitle: `${snapshots.length} 个快照`,\n accentColor: \"accent\",\n inputGuide: \"↑↓ 导航 · Esc 关闭\",\n width: 70,\n },\n ...visible.map((snap, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const prefix = isSelected ? \">\" : \" \";\n const timeStr = formatTimestamp(snap.timestamp);\n\n return React.createElement(\n Box,\n { key: snap.id, flexDirection: \"row\", gap: 2 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color: theme.colors.accent, bold: true }, snap.label),\n React.createElement(Text, { color: dim }, \"—\"),\n React.createElement(Text, { color: dim }, timeStr),\n );\n }),\n );\n}\n","/**\n * TasksPanel — background task monitor triggered by /tasks.\n *\n * Displays the status of background tasks: running, queued, done,\n * and failed. Data is fetched via the onRequestTasks callback from\n * the CLI bridge layer.\n */\n\nimport React, { useState, useCallback, useEffect, useRef } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Task status enum. */\nexport type TaskStatus = \"running\" | \"queued\" | \"done\" | \"failed\";\n\n/** A single background task record. */\nexport interface TaskEntry {\n /** Unique task identifier. */\n id: string;\n /** Human-readable task name. */\n name: string;\n /** Current task status. */\n status: TaskStatus;\n /** Error message if status is \"failed\". */\n error?: string;\n}\n\n/** Props for the TasksPanel component. */\nexport interface TasksPanelProps {\n /** Async callback that fetches the current task list. */\n onRequestTasks?: () => Promise<TaskEntry[]>;\n /** Called when the user dismisses the panel. */\n onCancel: () => void;\n}\n\nconst MAX_VISIBLE = 12;\n/** Poll interval for auto‑refreshing the task list (ms). */\nconst POLL_INTERVAL_MS = 2000;\n\n/** Status icon for each task status. */\nfunction statusIcon(status: TaskStatus): string {\n switch (status) {\n case \"running\":\n return \"⟳\";\n case \"queued\":\n return \"○\";\n case \"done\":\n return \"✓\";\n case \"failed\":\n return \"✗\";\n }\n}\n\n/** Colour for each task status. */\nfunction statusColor(status: TaskStatus, theme: ReturnType<typeof getTheme>): string {\n switch (status) {\n case \"running\":\n return theme.colors.accent ?? \"cyan\";\n case \"queued\":\n return theme.colors.dim ?? \"grey\";\n case \"done\":\n return theme.colors.success ?? \"green\";\n case \"failed\":\n return theme.colors.error ?? \"red\";\n }\n}\n\n/** Status label in Chinese. */\nfunction statusLabel(status: TaskStatus): string {\n switch (status) {\n case \"running\":\n return \"运行中\";\n case \"queued\":\n return \"排队中\";\n case \"done\":\n return \"完成\";\n case \"failed\":\n return \"失败\";\n }\n}\n\n/**\n * Background task monitor panel.\n *\n * Auto‑polls the task list every 2 seconds. Shows status icon,\n * task name, and error detail for failed tasks.\n * Press 'r' to manually refresh.\n */\nexport function TasksPanel({ onRequestTasks, onCancel }: TasksPanelProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n\n const [tasks, setTasks] = useState<TaskEntry[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [cursor, setCursor] = useState(0);\n const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const maxIndex = Math.max(0, tasks.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n const fetchTasks = useCallback(() => {\n if (!onRequestTasks) {\n setLoading(false);\n setTasks([]);\n return;\n }\n onRequestTasks()\n .then((data) => {\n setTasks(data);\n setLoading(false);\n })\n .catch((err: unknown) => {\n // Keep previous data on poll errors\n if (loading) setError(err instanceof Error ? err.message : String(err));\n setLoading(false);\n });\n }, [onRequestTasks, loading]);\n\n // Initial fetch + auto‑poll\n useEffect(() => {\n fetchTasks();\n pollRef.current = setInterval(fetchTasks, POLL_INTERVAL_MS);\n return () => {\n if (pollRef.current) clearInterval(pollRef.current);\n };\n }, [fetchTasks]);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = tasks.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n if (input === \"r\") {\n setLoading(true);\n fetchTasks();\n return;\n }\n },\n [maxIndex, fetchTasks],\n );\n\n useInkInput(handleKey);\n\n if (loading) {\n return React.createElement(\n Dialog,\n {\n title: \"任务\",\n subtitle: \"读取中...\",\n accentColor: \"dim\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: dim }, \"正在获取任务状态...\"),\n );\n }\n\n if (error) {\n return React.createElement(\n Dialog,\n {\n title: \"任务\",\n subtitle: \"读取失败\",\n accentColor: \"error\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: theme.colors.error }, error),\n );\n }\n\n if (tasks.length === 0) {\n return React.createElement(\n Dialog,\n {\n title: \"任务\",\n subtitle: \"无后台任务\",\n accentColor: \"dim\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: dim }, \"当前无后台任务运行。\"),\n );\n }\n\n // Compute counts\n const runningCount = tasks.filter((t) => t.status === \"running\").length;\n const queuedCount = tasks.filter((t) => t.status === \"queued\").length;\n const failedCount = tasks.filter((t) => t.status === \"failed\").length;\n\n return React.createElement(\n Dialog,\n {\n title: \"任务\",\n subtitle: `${tasks.length} 个任务 (${runningCount} 运行中, ${queuedCount} 排队, ${failedCount} 失败)`,\n accentColor: failedCount > 0 ? \"error\" : runningCount > 0 ? \"accent\" : \"dim\",\n inputGuide: \"↑↓ 导航 · r 刷新 · Esc 关闭\",\n width: 80,\n },\n ...visible\n .map((task, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const prefix = isSelected ? \">\" : \" \";\n const sc = statusColor(task.status, theme);\n const icon = statusIcon(task.status);\n\n const children: React.ReactElement[] = [\n React.createElement(\n Box,\n { key: `row-${task.id}`, flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color: sc }, `${icon} ${statusLabel(task.status)}`),\n React.createElement(Text, { bold: true }, task.name),\n ),\n ];\n\n if (task.error) {\n children.push(\n React.createElement(\n Box,\n { key: `err-${task.id}`, marginLeft: 5 },\n React.createElement(Text, { color: theme.colors.error }, `错误: ${task.error}`),\n ),\n );\n }\n\n return children;\n })\n .flat(),\n );\n}\n","/**\n * SkillPicker — fuzzy skill search and quick invocation.\n *\n * Triggered by /skill-pick (or programmatically from InputBox when the\n * user types \"/\" followed by a skill name prefix). Performs fuzzy\n * matching against skill names and descriptions.\n *\n * Arrow keys navigate results; Enter invokes the selected skill;\n * Escape dismisses.\n */\n\nimport React, { useState, useCallback, useMemo } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { SkillInfo } from \"../types.js\";\n\n/** Props for the SkillPicker component. */\nexport interface SkillPickerProps {\n /** All available skills (from builtin, user, project). */\n skills: SkillInfo[];\n /** Called when the user selects a skill (Enter). */\n onSelect(skillName: string): void;\n /** Called when the user dismisses (Escape). */\n onCancel(): void;\n}\n\n/** Maximum number of visible results. */\nconst MAX_VISIBLE = 10;\n\n/**\n * Simple fuzzy match — checks whether all characters in the query\n * appear in order within the target string (case‑insensitive).\n */\nfunction fuzzyMatch(query: string, target: string): boolean {\n const q = query.toLowerCase();\n const t = target.toLowerCase();\n let qi = 0;\n for (let ti = 0; ti < t.length && qi < q.length; ti++) {\n if (t[ti] === q[qi]) qi++;\n }\n return qi === q.length;\n}\n\n/** Score a fuzzy match — earlier matches + consecutive matches rank higher. */\nfunction fuzzyScore(query: string, target: string): number {\n const q = query.toLowerCase();\n const t = target.toLowerCase();\n let score = 0;\n let qi = 0;\n let lastMatch = -2;\n for (let ti = 0; ti < t.length && qi < q.length; ti++) {\n if (t[ti] === q[qi]) {\n // Bonus for early matches and consecutive matches\n score += 100 - ti + (ti === lastMatch + 1 ? 50 : 0);\n qi++;\n lastMatch = ti;\n }\n }\n return qi === q.length ? score : 0;\n}\n\n/** Source label in Chinese. */\nfunction sourceLabel(source: SkillInfo[\"source\"]): string {\n switch (source) {\n case \"builtin\":\n return \"内置\";\n case \"user\":\n return \"用户\";\n case \"project\":\n return \"项目\";\n }\n}\n\n/**\n * Fuzzy skill search modal.\n *\n * The user types a query to filter skills. Results are ranked by\n * fuzzy match score. Arrow keys select; Enter invokes; Escape closes.\n */\nexport function SkillPicker({ skills, onSelect, onCancel }: SkillPickerProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n\n const [query, setQuery] = useState(\"\");\n const [cursor, setCursor] = useState(0);\n\n // Filter and rank skills by fuzzy match against name + description\n const ranked = useMemo(() => {\n if (!query.trim()) return [];\n const scored = skills\n .map((s) => ({\n skill: s,\n score: fuzzyScore(query, s.name) * 2 + fuzzyScore(query, s.description),\n }))\n .filter((e) => e.score > 0)\n .sort((a, b) => b.score - a.score);\n return scored;\n }, [skills, query]);\n\n const maxIndex = Math.max(0, ranked.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n const visible = ranked.slice(0, MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n if (key.tab) {\n setCursor((prev) => (prev + 1) % (maxIndex + 1));\n return;\n }\n if (key.return && ranked.length > 0) {\n onSelect(ranked[safeCursor]!.skill.name);\n return;\n }\n // Typing: append to query unless it's a special key\n if (key.backspace || key.delete) {\n setQuery((prev) => prev.slice(0, -1));\n setCursor(0);\n return;\n }\n if (input && input.length === 1 && !key.ctrl && !key.meta) {\n setQuery((prev) => prev + input);\n setCursor(0);\n }\n },\n [ranked, safeCursor, maxIndex, onSelect, onCancel],\n );\n\n useInkInput(handleKey);\n\n const hasQuery = query.trim().length > 0;\n\n return React.createElement(\n Dialog,\n {\n title: \"技能搜索\",\n subtitle: hasQuery ? `${ranked.length} 个匹配` : `${skills.length} 个技能`,\n accentColor: hasQuery && ranked.length > 0 ? \"accent\" : \"dim\",\n inputGuide: hasQuery ? \"↑↓ 导航 · Enter 选择 · Esc 关闭\" : \"输入关键词搜索 · Esc 关闭\",\n width: 70,\n },\n // Search input\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1, marginBottom: 1 },\n React.createElement(Text, { color: dim }, \"/\"),\n React.createElement(\n Text,\n { color: query ? undefined : dim },\n query || (skills.length > 0 ? \"输入技能名搜索...\" : \"暂无可用的技能\"),\n ),\n React.createElement(Text, { color: dim }, \"█\"),\n ),\n // Results list or empty state\n !hasQuery\n ? React.createElement(Text, { color: dim }, \"输入关键词开始搜索。按 Esc 关闭。\")\n : ranked.length === 0\n ? React.createElement(Text, { color: dim }, `未找到匹配 \"${query}\" 的技能。`)\n : visible.map((entry, idx) => {\n const isSelected = idx === safeCursor;\n const prefix = isSelected ? \">\" : \" \";\n const srcLabel = sourceLabel(entry.skill.source);\n\n return React.createElement(\n Box,\n { key: entry.skill.name, flexDirection: \"column\" },\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(\n Text,\n { color: isSelected ? theme.colors.accent : dim },\n prefix,\n ),\n React.createElement(\n Text,\n { color: isSelected ? theme.colors.accent : undefined, bold: true },\n entry.skill.name,\n ),\n React.createElement(Text, { color: dim }, `[${srcLabel}]`),\n ),\n React.createElement(\n Box,\n { marginLeft: 3 },\n React.createElement(Text, { color: dim }, entry.skill.description || \"无描述\"),\n ),\n );\n }),\n );\n}\n","/**\n * McpPanel — MCP server management panel triggered by /mcp.\n *\n * Lists configured MCP servers with connection status, transport type,\n * auth status, tool count, and resource count. Arrow keys navigate,\n * Enter triggers connect/disconnect/reconnect based on current state.\n * Press `d` for detail view, `r` for reconnect.\n *\n * Visual: ● green = connected, ○ dim = disconnected,\n * ◌ yellow = connecting, ✗ red = error\n * 🔒 = authenticated, 🔓 = unauthenticated\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { McpConnectionInfo } from \"../types.js\";\n\n/** Props for the McpPanel component. */\nexport interface McpPanelProps {\n /** List of MCP server connections to display. */\n connections: McpConnectionInfo[];\n /** Called when the user dismisses the panel (Escape). */\n onCancel: () => void;\n /** Called to connect to a server. */\n onConnect?: (serverName: string) => void;\n /** Called to disconnect from a server. */\n onDisconnect?: (serverName: string) => void;\n /** Called to reconnect a failed server. */\n onReconnect?: (serverName: string) => void;\n}\n\n/** Visible items before scrolling. */\nconst MAX_VISIBLE = 12;\n\n/** Transport type display labels. */\nconst TRANSPORT_LABELS: Record<string, string> = {\n stdio: \"stdio\",\n sse: \"SSE\",\n ws: \"WS\",\n inproc: \"inproc\",\n};\n\n/** Status icon and color for each connection state. */\nfunction statusRender(\n status: McpConnectionInfo[\"status\"],\n theme: ReturnType<typeof getTheme>,\n): { icon: string; color: string } {\n switch (status) {\n case \"connected\":\n return { icon: \"●\", color: theme.colors.success ?? \"green\" };\n case \"connecting\":\n return { icon: \"◌\", color: theme.colors.warning ?? \"yellow\" };\n case \"error\":\n return { icon: \"✗\", color: theme.colors.error ?? \"red\" };\n case \"disconnected\":\n default:\n return { icon: \"○\", color: theme.colors.dimmed ?? \"grey\" };\n }\n}\n\n/** Auth status icon. */\nfunction authIcon(authStatus?: string): string {\n if (authStatus === \"authenticated\") return \"🔒\";\n return \"🔓\";\n}\n\n/**\n * Detail view for a single MCP server — shows transport, auth, tools, resources, and errors.\n */\nfunction ServerDetailView({\n server,\n theme,\n}: {\n server: McpConnectionInfo;\n theme: ReturnType<typeof getTheme>;\n}): React.ReactElement {\n const dim = theme.colors.dimmed ?? \"grey\";\n const accent = theme.colors.accent;\n\n return React.createElement(\n Box,\n { flexDirection: \"column\", gap: 1 },\n // Server name + status\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { bold: true, color: accent }, server.name),\n React.createElement(\n Text,\n { color: statusRender(server.status, theme).color },\n `— ${server.detail}`,\n ),\n ),\n // Transport\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: dim }, \"传输:\"),\n React.createElement(Text, {}, server.transport ?? \"未知\"),\n ),\n // Auth status\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: dim }, \"认证:\"),\n React.createElement(\n Text,\n {},\n `${authIcon(server.authStatus)} ${server.authStatus === \"authenticated\" ? \"已认证\" : server.authStatus === \"expired\" ? \"已过期\" : \"未认证\"}`,\n ),\n ),\n // Error detail\n server.status === \"error\"\n ? React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: theme.colors.error ?? \"red\" }, \"错误:\"),\n React.createElement(Text, { color: theme.colors.error ?? \"red\" }, server.detail),\n )\n : null,\n // Tools list\n React.createElement(Text, { bold: true, color: dim }, `工具 (${server.toolCount}):`),\n server.tools && server.tools.length > 0\n ? server.tools.map((tool) =>\n React.createElement(\n Box,\n { key: tool.name, flexDirection: \"row\", gap: 1, marginLeft: 2 },\n React.createElement(Text, { color: accent }, tool.name),\n tool.description\n ? React.createElement(Text, { color: dim }, `— ${tool.description}`)\n : null,\n ),\n )\n : React.createElement(Text, { color: dim, ...{ marginLeft: 2 } }, \"无工具\"),\n // Resources list\n React.createElement(Text, { bold: true, color: dim }, `资源 (${server.resourceCount ?? 0}):`),\n server.resources && server.resources.length > 0\n ? server.resources.map((res) =>\n React.createElement(\n Box,\n { key: res.name, flexDirection: \"row\", gap: 1, marginLeft: 2 },\n React.createElement(Text, { color: accent }, res.name),\n React.createElement(Text, { color: dim }, `— ${res.uri}`),\n ),\n )\n : React.createElement(Text, { color: dim, ...{ marginLeft: 2 } }, \"无资源\"),\n );\n}\n\n/**\n * MCP server management panel.\n *\n * Displays each server's connection state, transport type, auth status,\n * tool count, and resource count. Arrow keys navigate, Enter triggers\n * the appropriate action based on current state. Press `d` for detail view,\n * `r` for reconnect.\n */\nexport function McpPanel({\n connections,\n onCancel,\n onConnect,\n onDisconnect,\n onReconnect,\n}: McpPanelProps): React.ReactElement {\n const theme = getTheme();\n const [cursor, setCursor] = useState(0);\n const [showDetail, setShowDetail] = useState(false);\n const maxIndex = Math.max(0, connections.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = connections.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n // Detail view keybindings\n if (showDetail) {\n if (key.escape || input === \"d\") {\n setShowDetail(false);\n }\n return;\n }\n\n // List view keybindings\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n if (key.return) {\n const server = connections[safeCursor];\n if (!server) return;\n switch (server.status) {\n case \"disconnected\":\n onConnect?.(server.name);\n break;\n case \"error\":\n onReconnect?.(server.name);\n break;\n case \"connected\":\n case \"connecting\":\n onDisconnect?.(server.name);\n break;\n }\n return;\n }\n if (input === \"d\") {\n if (connections[safeCursor]) {\n setShowDetail(true);\n }\n return;\n }\n if (input === \"r\") {\n const server = connections[safeCursor];\n if (server) {\n onReconnect?.(server.name);\n }\n return;\n }\n },\n [connections, safeCursor, maxIndex, onConnect, onDisconnect, onReconnect, onCancel, showDetail],\n );\n\n useInkInput(handleKey);\n\n const accentColor = connections.length > 0 ? \"accent\" : \"dim\";\n const dim = theme.colors.dimmed ?? \"grey\";\n const selectedServer = connections[safeCursor];\n\n // Build the input guide based on current view\n const inputGuide = showDetail\n ? \"d/Esc 返回列表 · Esc 关闭面板\"\n : connections.length > 0\n ? \"↑↓ 导航 · Enter 连接/断开 · r 重连 · d 详情 · Esc 关闭\"\n : \"Esc 关闭\";\n\n return React.createElement(\n Dialog,\n {\n title: \"MCP 服务器\",\n subtitle:\n showDetail && selectedServer\n ? `${selectedServer.name} 详情`\n : `${connections.length} 个服务器`,\n accentColor,\n inputGuide,\n width: 74,\n },\n // Detail view\n showDetail && selectedServer\n ? React.createElement(ServerDetailView, { server: selectedServer, theme })\n : // List view\n connections.length === 0\n ? React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(\n Text,\n { color: dim },\n \"未配置 MCP 服务器。在 ~/.lynx/mcp.json 或项目 .claude/mcp.json 中添加\",\n ),\n )\n : visible.map((conn, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const { icon, color } = statusRender(conn.status, theme);\n const prefix = isSelected ? \">\" : \" \";\n\n return React.createElement(\n Box,\n { key: conn.name, flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color }, icon),\n React.createElement(Text, {}, authIcon(conn.authStatus)),\n React.createElement(Text, { bold: true }, ` ${conn.name}`),\n conn.transport\n ? React.createElement(\n Text,\n { color: dim },\n TRANSPORT_LABELS[conn.transport] ?? conn.transport,\n )\n : null,\n React.createElement(Text, { color: dim }, ` 工具: ${conn.toolCount}`),\n conn.resourceCount !== undefined\n ? React.createElement(Text, { color: dim }, ` 资源: ${conn.resourceCount}`)\n : null,\n React.createElement(Text, { color }, ` — ${conn.detail}`),\n );\n }),\n );\n}\n","/**\n * PluginPanel — plugin management panel triggered by /plugin.\n *\n * Lists installed plugins with version, description, and load state.\n * Arrow keys navigate, Enter toggles load/unload.\n *\n * Visual: ◆ green = loaded, ◇ dim = unloaded\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { PluginInfo } from \"../types.js\";\n\n/** Props for the PluginPanel component. */\nexport interface PluginPanelProps {\n /** List of installed plugins. */\n plugins: PluginInfo[];\n /** Called when the user dismisses the panel (Escape). */\n onCancel: () => void;\n /** Called to load a plugin. */\n onLoad?: (pluginName: string) => void;\n /** Called to unload a plugin. */\n onUnload?: (pluginName: string) => void;\n}\n\nconst MAX_VISIBLE = 12;\n\n/**\n * Plugin management panel.\n *\n * Displays each plugin with its loaded/unloaded state.\n * Enter loads or unloads the selected plugin.\n */\nexport function PluginPanel({\n plugins,\n onCancel,\n onLoad,\n onUnload,\n}: PluginPanelProps): React.ReactElement {\n const theme = getTheme();\n const [cursor, setCursor] = useState(0);\n const maxIndex = Math.max(0, plugins.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = plugins.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const loadedCount = plugins.filter((p) => p.loaded).length;\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n if (key.return) {\n const plugin = plugins[safeCursor];\n if (!plugin) return;\n if (plugin.loaded) {\n onUnload?.(plugin.name);\n } else {\n onLoad?.(plugin.name);\n }\n }\n },\n [plugins, safeCursor, maxIndex, onLoad, onUnload],\n );\n\n useInkInput(handleKey);\n\n const dim = theme.colors.dim ?? \"grey\";\n\n return React.createElement(\n Dialog,\n {\n title: \"插件\",\n subtitle: `${loadedCount} 已加载 / ${plugins.length} 总计`,\n accentColor: plugins.length > 0 ? \"accent\" : \"dim\",\n inputGuide: plugins.length > 0 ? \"↑↓ 导航 · Enter 切换 · Esc 关闭\" : \"Esc 关闭\",\n width: 70,\n },\n plugins.length === 0\n ? React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(\n Text,\n { color: dim },\n \"未安装插件。将插件放入 extensions/ 或通过 lynx plugin install 安装\",\n ),\n )\n : visible.map((plugin, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const icon = plugin.loaded ? \"◆\" : \"◇\";\n const iconColor = plugin.loaded ? (theme.colors.success ?? \"green\") : dim;\n const prefix = isSelected ? \">\" : \" \";\n\n return React.createElement(\n Box,\n {\n key: plugin.name,\n flexDirection: \"column\",\n marginBottom: idx < visible.length - 1 ? 0 : undefined,\n },\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color: iconColor }, icon),\n React.createElement(Text, { bold: true }, ` ${plugin.name}`),\n React.createElement(Text, { color: dim }, `v${plugin.version}`),\n ),\n React.createElement(\n Box,\n { marginLeft: 4 },\n React.createElement(Text, { color: dim }, plugin.description || \"无描述\"),\n ),\n );\n }),\n );\n}\n","/**\n * SkillPanel — skill discovery panel triggered by /skills.\n *\n * Lists all discovered skills (builtin, user, project) with name,\n * description, and source origin. Read-only display — no actions\n * beyond navigation and dismiss.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { SkillInfo } from \"../types.js\";\n\n/** Props for the SkillPanel component. */\nexport interface SkillPanelProps {\n /** List of discovered skills. */\n skills: SkillInfo[];\n /** Called when the user dismisses the panel (Escape). */\n onCancel: () => void;\n}\n\nconst MAX_VISIBLE = 12;\n\n/** Short label for each source origin. */\nfunction sourceLabel(source: SkillInfo[\"source\"]): string {\n switch (source) {\n case \"builtin\":\n return \"内置\";\n case \"user\":\n return \"用户\";\n case \"project\":\n return \"项目\";\n }\n}\n\n/** Color for each source origin. */\nfunction sourceColor(source: SkillInfo[\"source\"], theme: ReturnType<typeof getTheme>): string {\n switch (source) {\n case \"builtin\":\n return theme.colors.accent ?? \"cyan\";\n case \"user\":\n return theme.colors.success ?? \"green\";\n case \"project\":\n return theme.colors.warning ?? \"yellow\";\n }\n}\n\n/**\n * Skill discovery panel.\n *\n * Read-only list of all skills from builtin, user, and project sources.\n * Arrow keys scroll through the list.\n */\nexport function SkillPanel({ skills, onCancel }: SkillPanelProps): React.ReactElement {\n const theme = getTheme();\n const [cursor, setCursor] = useState(0);\n const maxIndex = Math.max(0, skills.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = skills.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n },\n [maxIndex],\n );\n\n useInkInput(handleKey);\n\n const dim = theme.colors.dim ?? \"grey\";\n\n return React.createElement(\n Dialog,\n {\n title: \"技能\",\n subtitle: `发现 ${skills.length} 个技能`,\n accentColor: skills.length > 0 ? \"accent\" : \"dim\",\n inputGuide: skills.length > 0 ? \"↑↓ 导航 · Esc 关闭\" : \"Esc 关闭\",\n width: 70,\n },\n skills.length === 0\n ? React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(\n Text,\n { color: dim },\n \"未发现技能。将技能放入 ~/.lynx/skills/ 或项目 .claude/skills/\",\n ),\n )\n : visible.map((skill, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const prefix = isSelected ? \">\" : \" \";\n const srcColor = sourceColor(skill.source, theme);\n\n return React.createElement(\n Box,\n {\n key: skill.name,\n flexDirection: \"column\",\n },\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color: theme.colors.accent, bold: true }, skill.name),\n React.createElement(Text, { color: dim }, \"—\"),\n React.createElement(Text, { color: srcColor }, `[${sourceLabel(skill.source)}]`),\n ),\n React.createElement(\n Box,\n { marginLeft: 3 },\n React.createElement(Text, { color: dim }, skill.description || \"无描述\"),\n ),\n );\n }),\n );\n}\n","/**\n * ContextPanel — context information panel triggered by /context.\n *\n * Displays the current session's context: session label, model,\n * workspace, memory facts, rules, and skills count.\n * Read-only display with 'r' to refresh.\n */\n\nimport React, { useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { ContextInfo } from \"../types.js\";\n\n/** Props for the ContextPanel component. */\nexport interface ContextPanelProps {\n /** Current context information. */\n contextInfo: ContextInfo;\n /** Called when the user dismisses the panel (Escape). */\n onCancel: () => void;\n}\n\n/** A single label: value row in the context panel. */\nfunction InfoRow({\n label,\n value,\n dim,\n}: {\n label: string;\n value: string;\n dim: string;\n}): React.ReactElement {\n return React.createElement(\n Box,\n { flexDirection: \"row\", gap: 2 },\n React.createElement(Box, { width: 16 }, React.createElement(Text, { color: dim }, label)),\n React.createElement(Text, {}, value),\n );\n}\n\n/**\n * Context information panel.\n *\n * Displays session/model/workspace metadata and loaded resource counts.\n * Press 'r' to request a refresh (the parent handles re-querying contextInfo).\n */\nexport function ContextPanel({ contextInfo, onCancel }: ContextPanelProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n const accent = theme.colors.accent ?? \"cyan\";\n\n const handleKey = useCallback((input: string, key: Key) => {\n // 'r' for refresh — parent re-queries by re-rendering with new contextInfo\n // (no explicit callback needed; the modal re-render is a signal)\n }, []);\n\n useInkInput(handleKey);\n\n return React.createElement(\n Dialog,\n {\n title: \"上下文\",\n subtitle: contextInfo.sessionLabel,\n accentColor: \"accent\",\n inputGuide: \"r 刷新 · Esc 关闭\",\n width: 70,\n },\n React.createElement(\n Box,\n { flexDirection: \"column\", gap: 1, paddingY: 1 },\n // Section: Session\n React.createElement(Text, { bold: true, color: accent }, \"会话\"),\n React.createElement(InfoRow, { label: \"会话\", value: contextInfo.sessionLabel, dim }),\n React.createElement(InfoRow, { label: \"模型\", value: contextInfo.model, dim }),\n React.createElement(InfoRow, { label: \"工作区\", value: contextInfo.workspace, dim }),\n // Separator\n React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(Text, { color: dim }, \"─\".repeat(60)),\n ),\n // Section: Resources\n React.createElement(Text, { bold: true, color: accent }, \"资源\"),\n React.createElement(InfoRow, {\n label: \"记忆条目\",\n value: String(contextInfo.memoryFacts),\n dim,\n }),\n React.createElement(InfoRow, { label: \"规则\", value: String(contextInfo.rules), dim }),\n React.createElement(InfoRow, { label: \"技能\", value: String(contextInfo.skills), dim }),\n ),\n );\n}\n","/**\n * UsagePanel — usage statistics panel triggered by /usage.\n *\n * Displays session token count, estimated cost, budget consumption,\n * turn count, and model pricing. Features a visual budget bar that\n * changes color based on remaining budget.\n *\n * Budget bar colors: green (<50%), yellow (50‑80%), red (>80%),\n * dim (unlimited / no budget set).\n */\n\nimport React, { useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { UsageInfo } from \"../types.js\";\n\n/** Props for the UsagePanel component. */\nexport interface UsagePanelProps {\n /** Current usage statistics. */\n usageInfo: UsageInfo;\n /** Called when the user dismisses the panel (Escape). */\n onCancel: () => void;\n}\n\n/** Budget bar configuration. */\nconst BAR_WIDTH = 40;\nconst BAR_FILLED = \"█\";\nconst BAR_EMPTY = \"░\";\n\n/** A single stat tile in the stats grid. */\nfunction StatTile({\n label,\n value,\n dim,\n accent,\n}: {\n label: string;\n value: string;\n dim: string;\n accent: string;\n}): React.ReactElement {\n return React.createElement(\n Box,\n { flexDirection: \"column\", width: 20 },\n React.createElement(Text, { color: dim }, label),\n React.createElement(Text, { color: accent, bold: true }, value),\n );\n}\n\n/**\n * Usage statistics panel.\n *\n * Shows token usage, cost, budget consumption, turn count, and pricing.\n * The budget bar visualises budget consumption with color-coded thresholds.\n * Read-only; Esc to close.\n */\nexport function UsagePanel({ usageInfo, onCancel }: UsagePanelProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n const accent = theme.colors.accent ?? \"cyan\";\n\n const handleKey = useCallback((input: string, key: Key) => {\n // Read-only, no keyboard actions beyond Escape (handled globally)\n }, []);\n\n useInkInput(handleKey);\n\n // ── Budget bar ────────────────────────────────\n\n const hasBudget = usageInfo.budgetMaxTokens > 0 || usageInfo.budgetMaxUsd > 0;\n const maxUsd = usageInfo.budgetMaxUsd || Infinity;\n const ratio = maxUsd > 0 ? Math.min(usageInfo.costUsd / maxUsd, 1) : 0;\n\n let barColor = theme.colors.success ?? \"green\";\n if (ratio > 0.8) barColor = theme.colors.error ?? \"red\";\n else if (ratio > 0.5) barColor = theme.colors.warning ?? \"yellow\";\n else if (!hasBudget) barColor = dim;\n\n const filledCount = hasBudget ? Math.round(ratio * BAR_WIDTH) : 0;\n const emptyCount = BAR_WIDTH - filledCount;\n const bar = BAR_FILLED.repeat(filledCount) + BAR_EMPTY.repeat(emptyCount);\n\n const percentage = hasBudget ? `${Math.round(ratio * 100)}%` : \"∞\";\n const budgetLabel = hasBudget\n ? `$${usageInfo.costUsd.toFixed(4)} / $${maxUsd.toFixed(2)}`\n : `$${usageInfo.costUsd.toFixed(4)} (unlimited)`;\n\n // ── Stats ─────────────────────────────────────\n\n const tokensFormatted =\n usageInfo.tokensUsed >= 1000\n ? `${(usageInfo.tokensUsed / 1000).toFixed(1)}K`\n : String(usageInfo.tokensUsed);\n\n return React.createElement(\n Dialog,\n {\n title: \"用量\",\n subtitle: `本会话 ${usageInfo.turns} 轮`,\n accentColor: ratio > 0.8 ? \"error\" : ratio > 0.5 ? \"warning\" : \"accent\",\n inputGuide: \"Esc 关闭\",\n width: 68,\n },\n React.createElement(\n Box,\n { flexDirection: \"column\", gap: 1, paddingY: 1 },\n // Budget bar section\n React.createElement(Text, { bold: true, color: dim }, \"预算\"),\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: barColor }, bar),\n React.createElement(Text, { color: barColor }, ` ${percentage}`),\n ),\n React.createElement(Text, { color: dim }, budgetLabel),\n // Separator\n React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(Text, { color: dim }, \"─\".repeat(60)),\n ),\n // Stats grid\n React.createElement(Text, { bold: true, color: dim }, \"统计\"),\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 4, paddingTop: 1 },\n React.createElement(StatTile, {\n label: \"Token 用量\",\n value: tokensFormatted,\n dim,\n accent,\n }),\n React.createElement(StatTile, {\n label: \"费用 (USD)\",\n value: `$${usageInfo.costUsd.toFixed(4)}`,\n dim,\n accent,\n }),\n React.createElement(StatTile, {\n label: \"轮数\",\n value: String(usageInfo.turns),\n dim,\n accent,\n }),\n ),\n // Separator\n React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(Text, { color: dim }, \"─\".repeat(60)),\n ),\n // Pricing info\n React.createElement(Text, { bold: true, color: dim }, \"模型定价\"),\n React.createElement(Text, { color: dim }, usageInfo.modelPricing || \"暂无\"),\n ),\n );\n}\n","/**\n * WelcomeScreen — safety confirmation screen shown before entering the REPL.\n *\n * Rendered after Phase 1 bootstrap completes. The user must explicitly\n * confirm they trust the current workspace before Phase 2 starts.\n *\n * Design (§5.1a):\n * - Unicode box‑drawing border (━)\n * - Workspace path + version display\n * - Context‑aware safety prompt (first visit vs returning)\n * - ↑↓ to switch selection, Enter to confirm, Esc to exit\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Props for the WelcomeScreen component. */\nexport interface WelcomeScreenProps {\n /** Workspace directory path. */\n workspace: string;\n /** Lynx version string. */\n version: string;\n /** Last session info — null on first visit. */\n lastSession?: { label: string; relativeTime: string; sessionCount: number };\n /** Called when the user confirms (trusts the workspace). */\n onConfirm: () => void;\n /** Called when the user exits (does not trust / cancels). */\n onExit: () => void;\n}\n\n/** Safety prompt for first visit to a workspace. */\nconst FIRST_VISIT_PROMPT =\n \"Lynx 可以读取、编辑和执行此工作区中的文件。请确认这是您创建或信任的项目后再继续。\";\n\n/** Index constants for the two options. */\nconst OPTION_TRUST = 0;\nconst OPTION_EXIT = 1;\n\n/**\n * Safety confirmation screen.\n *\n * The user is shown workspace info and must confirm before\n * Lynx starts Phase 2 (loading sessions, MCP, memory, etc.).\n */\nexport function WelcomeScreen({\n workspace,\n version,\n lastSession,\n onConfirm,\n onExit,\n}: WelcomeScreenProps): React.ReactElement {\n const theme = getTheme();\n const accent = theme.colors.accent;\n const [selected, setSelected] = useState(OPTION_TRUST);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.upArrow || key.downArrow) {\n setSelected((prev) => (prev === OPTION_TRUST ? OPTION_EXIT : OPTION_TRUST));\n return;\n }\n if (key.return) {\n if (selected === OPTION_TRUST) onConfirm();\n else onExit();\n return;\n }\n if (key.escape) {\n onExit();\n }\n },\n [selected, onConfirm, onExit],\n );\n\n useInkInput(handleKey);\n\n // ── Safety prompt text ────────────────────────\n\n const promptText = lastSession\n ? `Lynx 可以读取、编辑和执行此工作区中的文件。\\n\\n` +\n `上次会话:${lastSession.label}(${lastSession.relativeTime})\\n` +\n `您在此工作区中有 ${lastSession.sessionCount} 次历史会话。`\n : FIRST_VISIT_PROMPT;\n\n const isTrustSelected = selected === OPTION_TRUST;\n\n return React.createElement(\n Box,\n { flexDirection: \"column\", paddingY: 1 },\n\n // ── Top border ────────────────────────────────\n React.createElement(Text, { dimColor: true }, \"━\".repeat(72)),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Title ─────────────────────────────────────\n React.createElement(Text, { bold: true, color: accent }, \" Lynx\"),\n React.createElement(Text, { dimColor: true }, ` v${version}`),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Workspace ─────────────────────────────────\n React.createElement(\n Text,\n null,\n \" Workspace: \",\n React.createElement(Text, { color: accent }, workspace),\n ),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Safety prompt ─────────────────────────────\n React.createElement(Text, null, ` ${promptText}`),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Options ───────────────────────────────────\n React.createElement(\n Text,\n { color: isTrustSelected ? accent : undefined, bold: isTrustSelected },\n isTrustSelected ? ` ❯ 1. 是,我信任此文件夹` : ` 1. 是,我信任此文件夹`,\n ),\n React.createElement(\n Text,\n {\n color: !isTrustSelected ? accent : undefined,\n bold: !isTrustSelected,\n dimColor: isTrustSelected,\n },\n !isTrustSelected ? ` ❯ 2. 否,退出` : ` 2. 否,退出`,\n ),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Key guide ─────────────────────────────────\n React.createElement(Text, { dimColor: true }, \" Enter 确认 · Esc 取消\"),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Bottom border ─────────────────────────────\n React.createElement(Text, { dimColor: true }, \"━\".repeat(72)),\n );\n}\n","/**\n * useTerminalSize — track stdout dimensions via Ink's useStdout hook.\n *\n * Returns { columns, rows } and updates on terminal resize events.\n */\n\nimport { useState, useEffect } from \"react\";\nimport { useStdout } from \"ink\";\n\nexport interface TerminalSize {\n columns: number;\n rows: number;\n}\n\n/** Default fallback when stdout dimensions are unavailable. */\nconst DEFAULT_SIZE: TerminalSize = { columns: 80, rows: 24 };\n\n/**\n * Hook that returns the current terminal dimensions.\n * Updates when the terminal is resized.\n */\nexport function useTerminalSize(): TerminalSize {\n const { stdout } = useStdout();\n const [size, setSize] = useState<TerminalSize>(() => ({\n columns: stdout?.columns ?? DEFAULT_SIZE.columns,\n rows: stdout?.rows ?? DEFAULT_SIZE.rows,\n }));\n\n useEffect(() => {\n if (!stdout) return;\n\n const onResize = () => {\n setSize({\n columns: stdout.columns ?? DEFAULT_SIZE.columns,\n rows: stdout.rows ?? DEFAULT_SIZE.rows,\n });\n };\n\n stdout.on(\"resize\", onResize);\n return () => {\n stdout.off(\"resize\", onResize);\n };\n }, [stdout]);\n\n return size;\n}\n","/**\n * useScroll — scroll management hook for the ChatLog message area.\n *\n * Manages scroll offset, sticky‑scroll mode, and computes visibleRange\n * for windowed rendering. Exposes jump‑to‑bottom state for the pill UI.\n *\n * Design:\n * - stickyScroll: true → auto‑scroll to bottom on new messages\n * - User presses PageUp → stickyScroll = false, offset increases\n * - User presses PageDown or jumpToBottom() → stickyScroll = true\n * - New messages arrive while stickyScroll → offset resets to 0\n */\n\nimport { useState, useCallback, useRef } from \"react\";\nimport type { Key } from \"ink\";\n\n/** Scroll state returned by useScroll. */\nexport interface ScrollState {\n /** Start index of the visible message range. */\n visibleStart: number;\n /** End index (exclusive) of the visible message range. */\n visibleEnd: number;\n /** Whether the view is auto‑following new messages. */\n stickyScroll: boolean;\n /** How many new messages are below the current viewport (for pill display). */\n unseenCount: number;\n /** Call to jump back to the bottom (resumes auto‑scroll). */\n jumpToBottom(): void;\n /** Handle keyboard input for scroll navigation. */\n handleKey(input: string, key: Key): boolean;\n /** Scroll up by one line (for mouse wheel). */\n scrollUp(): void;\n /** Scroll down by one line (for mouse wheel). */\n scrollDown(): void;\n /** Update the total entry count (call from a ref or interval). */\n setTotalEntries(count: number): void;\n}\n\n/** Options for useScroll. */\nexport interface UseScrollOptions {\n /** Number of visible rows in the chat area (from terminal size). */\n visibleRows: number;\n}\n\n/**\n * React hook that manages scrolling behaviour for the ChatLog.\n *\n * Call `setTotalEntries(getEntryCount())` periodically to keep\n * the hook in sync with the ChatLog's entry list.\n */\nexport function useScroll({ visibleRows }: UseScrollOptions): ScrollState {\n const [scrollOffset, setScrollOffset] = useState(0);\n const [totalEntries, setTotalEntriesRaw] = useState(0);\n const [stickyScroll, setStickyScroll] = useState(true);\n\n // Use ref to avoid stale closure issues in callbacks\n const stickyScrollRef = useRef(stickyScroll);\n stickyScrollRef.current = stickyScroll;\n\n const maxVisible = Math.max(visibleRows - 2, 5); // reserve 2 lines for header/padding\n const visibleEnd = totalEntries - scrollOffset;\n const visibleStart = Math.max(visibleEnd - maxVisible, 0);\n const unseenCount = scrollOffset;\n\n /** Update total entry count from ChatLog, resetting offset if in sticky mode. */\n const setTotalEntries = useCallback((count: number) => {\n setTotalEntriesRaw(count);\n if (stickyScrollRef.current) {\n setScrollOffset(0);\n }\n }, []);\n\n /** Jump to bottom and resume sticky scroll. */\n const jumpToBottom = useCallback(() => {\n setScrollOffset(0);\n setStickyScroll(true);\n }, []);\n\n /** Handle scroll keyboard input. Returns true if the key was consumed. */\n const handleKey = useCallback(\n (input: string, key: Key): boolean => {\n // PageUp / Ctrl+U → scroll up\n if (key.pageUp || (key.ctrl && input === \"u\")) {\n setStickyScroll(false);\n setScrollOffset((prev) => {\n const step = Math.floor(maxVisible / 2);\n const max = Math.max(0, totalEntries - maxVisible);\n return Math.min(prev + step, max);\n });\n return true;\n }\n\n // PageDown / Ctrl+D → scroll down\n if (key.pageDown || (key.ctrl && input === \"d\")) {\n const next = scrollOffset - Math.floor(maxVisible / 2);\n if (next <= 0) {\n jumpToBottom();\n } else {\n setStickyScroll(false);\n setScrollOffset(next);\n }\n return true;\n }\n\n // Home → top of scroll history\n if (key.home) {\n const max = Math.max(0, totalEntries - maxVisible);\n setStickyScroll(false);\n setScrollOffset(max);\n return true;\n }\n\n // End → jump to bottom\n if (key.end) {\n jumpToBottom();\n return true;\n }\n\n return false;\n },\n [scrollOffset, maxVisible, totalEntries, jumpToBottom],\n );\n\n /** Scroll up by one line (mouse wheel up). */\n const scrollUp = useCallback(() => {\n setStickyScroll(false);\n setScrollOffset((prev) => {\n const max = Math.max(0, totalEntries - maxVisible);\n return Math.min(prev + 1, max);\n });\n }, [totalEntries, maxVisible]);\n\n /** Scroll down by one line (mouse wheel down). */\n const scrollDown = useCallback(() => {\n setScrollOffset((prev) => {\n const next = prev - 1;\n if (next <= 0) {\n jumpToBottom();\n return 0;\n }\n setStickyScroll(false);\n return next;\n });\n }, [jumpToBottom]);\n\n return {\n visibleStart,\n visibleEnd,\n stickyScroll,\n unseenCount,\n jumpToBottom,\n handleKey,\n setTotalEntries,\n scrollUp,\n scrollDown,\n };\n}\n","/**\n * ViewStack — immutable view navigation.\n *\n * push → add view on top\n * pop → remove top (at least one view always remains)\n * replace → swap top\n * top → peek at current\n */\n\nimport type { ViewEntry, ViewId, ViewStack } from \"../types.js\";\n\n/** Create a new view stack with an initial view. */\nexport function createViewStack(initial: ViewId = \"chat\"): ViewStack {\n const stack: ViewEntry[] = [{ id: initial }];\n\n return {\n push(view: ViewEntry): void {\n stack.push(view);\n },\n\n pop(): ViewEntry | undefined {\n if (stack.length > 1) {\n return stack.pop();\n }\n return undefined;\n },\n\n replace(view: ViewEntry): void {\n if (stack.length > 0) {\n stack[stack.length - 1] = view;\n } else {\n stack.push(view);\n }\n },\n\n top(): ViewEntry | undefined {\n return stack[stack.length - 1];\n },\n\n toArray(): ViewEntry[] {\n return [...stack];\n },\n };\n}\n","/**\n * App — root Ink component for the Lynx TUI.\n *\n * Wires the imperative ChatLog handle to the streaming backend via\n * TuiCallbacks.onInput(). Drives view navigation through ViewStack\n * and renders modal overlays for the active view.\n *\n * Architecture:\n * User input → handleSubmit → callbacks.onInput(text)\n * → consumes TuiStreamEvent async generator\n * → dispatches to ChatLogHandle methods\n *\n * 3‑layer abort (Ctrl+C):\n * 1 → abort LLM request\n * 2 → abort running tool\n * 3 → process.exit(1)\n */\n\nimport React, { useState, useCallback, useRef, useEffect } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport type { AppProps, ViewEntry, TuiStreamEvent, ThemeName } from \"./types.js\";\nimport { getTheme, setTheme } from \"./theme/theme.js\";\nimport { ChatLog } from \"./components/ChatLog.js\";\nimport type { ChatLogHandle } from \"./components/ChatLog.js\";\nimport { createFrameRateLimiter } from \"./renderer/frame-limiter.js\";\nimport { InputBox } from \"./components/InputBox.js\";\nimport { StatusBar } from \"./components/StatusBar.js\";\nimport { NotificationCenter, useNotifications } from \"./components/NotificationCenter.js\";\nimport { PermissionRequest } from \"./components/PermissionRequest.js\";\nimport type { SafetyLevel } from \"./components/PermissionRequest.js\";\nimport { SessionPicker } from \"./components/SessionPicker.js\";\nimport { HelpModal } from \"./components/HelpModal.js\";\nimport { CommandPalette } from \"./components/CommandPalette.js\";\nimport { ModelPicker } from \"./components/ModelPicker.js\";\nimport { ConfigMenu } from \"./components/ConfigMenu.js\";\nimport { ThemePicker } from \"./components/ThemePicker.js\";\nimport { ConfirmDialog } from \"./components/ConfirmDialog.js\";\nimport { InputPrompt } from \"./components/InputPrompt.js\";\nimport { DoctorPanel, runBuiltinChecks } from \"./components/DoctorPanel.js\";\nimport { FilePicker } from \"./components/FilePicker.js\";\nimport { StashPicker } from \"./components/StashPicker.js\";\nimport type { StashEntry } from \"./components/StashPicker.js\";\nimport { DiffViewer } from \"./components/DiffViewer.js\";\nimport { SnapshotBrowser } from \"./components/SnapshotBrowser.js\";\nimport { TasksPanel } from \"./components/TasksPanel.js\";\nimport { SkillPicker } from \"./components/SkillPicker.js\";\nimport { McpPanel } from \"./components/McpPanel.js\";\nimport { PluginPanel } from \"./components/PluginPanel.js\";\nimport { SkillPanel } from \"./components/SkillPanel.js\";\nimport { ContextPanel } from \"./components/ContextPanel.js\";\nimport { UsagePanel } from \"./components/UsagePanel.js\";\nimport { WelcomeScreen } from \"./screens/WelcomeScreen.js\";\nimport { useTerminalSize } from \"./hooks/useTerminalSize.js\";\nimport { useScroll } from \"./hooks/useScroll.js\";\nimport { createViewStack } from \"./views/stack.js\";\n\n/** Maximum number of consecutive Ctrl+C presses before hard exit. */\nconst MAX_ABORT_LAYERS = 3;\n\n/** Streaming watchdog — how long without a text_delta before warning (ms). */\nconst WATCHDOG_DELAY_MS = 30_000;\n/** Max consecutive watchdog timeouts before declaring the stream stalled. */\nconst WATCHDOG_MAX_TIMEOUTS = 3;\n\n/**\n * Compute a human-readable relative time string from a Unix-ms timestamp.\n *\n * Examples: \"just now\", \"5m ago\", \"3h ago\", \"2d ago\", \"1mo ago\".\n */\nfunction relativeTimeStr(updatedAt: number): string {\n const seconds = Math.floor((Date.now() - updatedAt) / 1000);\n if (seconds < 60) return \"just now\";\n const minutes = Math.floor(seconds / 60);\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 return `${months}mo ago`;\n}\n\n/** Main application component rendered by Ink. */\nexport function App(props: AppProps): React.ReactElement {\n const { callbacks, session, sessions, onPermissionReady } = props;\n const { rows } = useTerminalSize();\n const theme = getTheme();\n\n // ── Welcome screen ────────────────────────────\n // Only show when explicitly requested by the launcher (first visit, safety check).\n // Once the user confirms, welcomeDone flips to true and the screen never reappears.\n\n const showWelcome = props.showWelcome === true;\n const [welcomeDone, setWelcomeDone] = useState(false);\n\n // ── ChatLog handle ────────────────────────────\n\n const chatLogRef = useRef<ChatLogHandle | null>(null);\n\n // ── Scroll state ──────────────────────────────\n\n const chatHeight = Math.max(rows - 6, 6);\n const scroll = useScroll({ visibleRows: chatHeight });\n\n // ── View navigation ───────────────────────────\n\n const viewStackRef = useRef(createViewStack());\n const [currentView, setCurrentView] = useState<ViewEntry>({ id: \"chat\" });\n\n /** Frame rate limiter for throttling scroll sync during streaming. */\n const frameLimiterRef = useRef(createFrameRateLimiter());\n\n /** Sync entry count for scroll calculation (throttled to ~30fps via FrameRateLimiter). */\n const syncScrollEntries = useCallback(() => {\n frameLimiterRef.current.schedule(() => {\n scroll.setTotalEntries(chatLogRef.current?.getEntryCount() ?? 0);\n });\n }, [scroll]);\n\n const pushView = useCallback((view: ViewEntry) => {\n viewStackRef.current.push(view);\n setCurrentView(viewStackRef.current.top()!);\n }, []);\n\n const popView = useCallback(() => {\n viewStackRef.current.pop();\n setCurrentView(viewStackRef.current.top()!);\n }, []);\n\n // ── Streaming state ───────────────────────────\n\n const [streaming, setStreaming] = useState(false);\n const [abortCount, setAbortCount] = useState(0);\n\n // ── Search state (managed here so InputBox can be disabled during search) ─\n const [searchActive, setSearchActive] = useState(false);\n /** Transcript display mode: compact (default) or full (timestamps + expanded content). */\n const [transcriptMode, setTranscriptMode] = useState<\"compact\" | \"full\">(\"compact\");\n\n // ── Budget tracking ───────────────────────────\n const [tokensUsed, setTokensUsed] = useState(0);\n const [costUsd, setCostUsd] = useState(0);\n\n // ── Notification toast system ─────────────────\n const { current: activeNotification, push: pushNotification } = useNotifications();\n\n // ── Streaming watchdog — detects stalled LLM streams ─\n const watchdogTimerRef = useRef<NodeJS.Timeout | null>(null);\n const watchdogTimeoutCountRef = useRef(0);\n\n /** Reset the watchdog — called on each text_delta to indicate the stream is alive. */\n const resetWatchdog = useCallback(() => {\n if (watchdogTimerRef.current) {\n clearTimeout(watchdogTimerRef.current);\n watchdogTimerRef.current = null;\n }\n watchdogTimeoutCountRef.current = 0;\n watchdogTimerRef.current = setTimeout(() => {\n watchdogTimeoutCountRef.current++;\n if (watchdogTimeoutCountRef.current >= WATCHDOG_MAX_TIMEOUTS) {\n chatLogRef.current?.addSystem(\"Stream appears stalled — press Ctrl+C to abort\", \"warn\");\n } else {\n chatLogRef.current?.addSystem(\"Still waiting for response...\", \"info\");\n // Restart for the next interval (resets timeout counter if a delta eventually arrives)\n resetWatchdog();\n }\n }, WATCHDOG_DELAY_MS);\n }, []);\n\n /** Clear the watchdog timer — called when streaming ends. */\n const clearWatchdog = useCallback(() => {\n if (watchdogTimerRef.current) {\n clearTimeout(watchdogTimerRef.current);\n watchdogTimerRef.current = null;\n }\n watchdogTimeoutCountRef.current = 0;\n }, []);\n\n // Force re‑render when theme changes (setTheme mutates the singleton,\n // getTheme() picks it up on next render triggered by this counter).\n const [themeVersion, setThemeVersion] = useState(0);\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- themeVersion above forces re‑render\n void themeVersion;\n\n // ── Permission state ──────────────────────────\n\n const [pendingPermission, setPendingPermission] = useState<{\n requestId: string;\n toolName: string;\n safety: SafetyLevel;\n description: string;\n parameters?: Record<string, unknown>;\n } | null>(null);\n\n // ── Slash command handler ────────────────────\n\n const executeSlashCommand = useCallback(\n (command: string) => {\n popView();\n switch (command) {\n case \"/sessions\":\n case \"/会话\":\n pushView({ id: \"sessions\" });\n break;\n case \"/help\":\n case \"/帮助\":\n pushView({ id: \"help\" });\n break;\n case \"/model\":\n case \"/模型\":\n pushView({ id: \"model\" });\n break;\n case \"/config\":\n case \"/settings\":\n case \"/设置\":\n pushView({ id: \"settings\" });\n break;\n case \"/theme\":\n case \"/主题\":\n pushView({ id: \"theme\" });\n break;\n case \"/doctor\":\n case \"/诊断\":\n pushView({ id: \"doctor\" });\n break;\n case \"/stash\":\n case \"/暂存\":\n pushView({ id: \"stash\" });\n break;\n case \"/files\":\n case \"/文件\":\n pushView({ id: \"file_picker\" });\n break;\n case \"/mcp\":\n pushView({ id: \"mcp\" });\n break;\n case \"/plugin\":\n case \"/插件\":\n pushView({ id: \"plugin\" });\n break;\n case \"/skills\":\n case \"/技能\":\n pushView({ id: \"skills\" });\n break;\n case \"/skill-pick\":\n case \"/技能选择\":\n pushView({ id: \"skill_pick\" });\n break;\n case \"/context\":\n case \"/上下文\":\n pushView({ id: \"context\" });\n break;\n case \"/usage\":\n case \"/用量\":\n pushView({ id: \"usage\" });\n break;\n // ── Session CRUD ──────────────────────────\n case \"/new\":\n case \"/新建\":\n pushView({\n id: \"input_prompt\",\n props: {\n title: \"创建新会话\",\n placeholder: \"请输入会话名称\",\n onConfirm: (label: string) => {\n props.callbacks.onSessionCreate?.(label || \"session\");\n popView();\n },\n },\n });\n break;\n case \"/fork\":\n case \"/分支\":\n pushView({\n id: \"input_prompt\",\n props: {\n title: \"从当前会话创建分支\",\n placeholder: \"请输入分支名称 (可选)\",\n onConfirm: (label: string) => {\n props.callbacks.onSessionFork?.(label || `fork-${session?.label ?? \"session\"}`);\n popView();\n },\n },\n });\n break;\n case \"/rename\":\n case \"/重命名\":\n pushView({\n id: \"input_prompt\",\n props: {\n title: \"重命名会话\",\n placeholder: \"请输入新名称\",\n initialValue: session?.label ?? \"\",\n onConfirm: (newLabel: string) => {\n if (newLabel) props.callbacks.onSessionRename?.(newLabel);\n popView();\n },\n },\n });\n break;\n case \"/delete\":\n case \"/删除\":\n pushView({\n id: \"sessions\",\n props: {\n onSelectOverride: (sessionId: string) => {\n // Push confirm on top of sessions\n pushView({\n id: \"confirm\",\n props: {\n title: \"确认删除\",\n message: `确定要删除会话吗?此操作不可撤销。`,\n onConfirm: () => {\n props.callbacks.onSessionDelete?.(sessionId);\n popView(); // confirm\n popView(); // sessions\n },\n },\n });\n },\n },\n });\n break;\n case \"/resume\":\n case \"/恢复\":\n pushView({\n id: \"sessions\",\n props: {\n onSelectOverride: (sessionId: string) => {\n props.callbacks.onSessionResume?.(sessionId);\n popView();\n },\n },\n });\n break;\n case \"/compact\":\n case \"/压缩\":\n pushView({\n id: \"confirm\",\n props: {\n title: \"压缩上下文\",\n message: \"压缩当前会话的对话上下文?较早的消息将被摘要替换,释放 token 配额。\",\n onConfirm: () => {\n props.callbacks.onSessionCompact?.();\n popView();\n },\n },\n });\n break;\n // ── Tools ──────────────────────────────────\n case \"/diff\":\n case \"/差异\":\n pushView({ id: \"diff\" });\n break;\n case \"/snapshots\":\n case \"/快照\":\n pushView({ id: \"snapshots\" });\n break;\n case \"/tasks\":\n case \"/任务\":\n pushView({ id: \"tasks\" });\n break;\n default:\n chatLogRef.current?.addSystem(`Command \"${command}\" not yet implemented.`, \"warn\");\n }\n },\n [pushView, popView],\n );\n\n // ── Keyboard: global keys ─────────────────────\n\n const handleGlobalKey = useCallback(\n (input: string, key: Key) => {\n if (scroll.handleKey(input, key)) return;\n\n // Escape closes simple modals (views with internal useInput handle their own Escape)\n const selfHandled = new Set([\n \"permission\",\n \"sessions\",\n \"help\",\n \"commands\",\n \"model\",\n \"settings\",\n \"theme\",\n \"confirm\",\n \"input_prompt\",\n \"doctor\",\n \"file_picker\",\n \"stash\",\n \"mcp\",\n \"plugin\",\n \"skills\",\n \"context\",\n \"usage\",\n \"diff\",\n \"snapshots\",\n \"tasks\",\n \"skill_pick\",\n ]);\n if (key.escape && currentView.id !== \"chat\" && !selfHandled.has(currentView.id)) {\n popView();\n }\n\n // Ctrl+G — open external editor\n if (key.ctrl && input === \"g\" && currentView.id === \"chat\") {\n const doExternalEdit = async () => {\n try {\n const result = await callbacks.onOpenExternalEditor?.(\"\");\n if (result) setAppendToInput(result);\n } catch {\n // Editor failed — silently ignore\n }\n };\n doExternalEdit();\n }\n\n // Ctrl+O — toggle transcript mode (compact ↔ full with timestamps)\n if (key.ctrl && input === \"o\" && currentView.id === \"chat\") {\n setTranscriptMode((prev) => (prev === \"compact\" ? \"full\" : \"compact\"));\n }\n },\n [currentView.id, scroll, popView, callbacks],\n );\n\n useInkInput((input: string, key: Key) => {\n // Filter out terminal mouse SGR escape sequences that leak through\n // as raw text when terminal mouse tracking is enabled by Ink.\n if (input.includes(\"\\x1b[<\") || /^\\[<\\d+;\\d+;\\d+[Mm]/.test(input.trim())) return;\n handleGlobalKey(input, key);\n });\n\n // ── Abort handler (3‑layer) ───────────────────\n\n const handleAbort = useCallback(() => {\n const next = abortCount + 1;\n setAbortCount(next);\n\n if (next === 1) {\n callbacks.onAbort();\n chatLogRef.current?.addSystem(\n \"Request aborted (Ctrl+C 1/3). Press again to abort tool.\",\n \"warn\",\n );\n syncScrollEntries();\n } else if (next === 2) {\n chatLogRef.current?.addSystem(\"Tool aborted (Ctrl+C 2/3). Streaming stopped.\", \"error\");\n chatLogRef.current?.dropAssistant();\n setStreaming(false);\n syncScrollEntries();\n } else {\n process.exit(1);\n }\n }, [abortCount, callbacks, syncScrollEntries]);\n\n // ── Stream event processor ────────────────────\n\n /** Process a single TUI stream event, updating ChatLog state. */\n function handleStreamEvent(event: TuiStreamEvent): void {\n const chat = chatLogRef.current;\n if (!chat) return;\n\n if (event.type === \"reasoning_status\") {\n if (event.status === \"started\") {\n chat.addSystem(\"思考中…\", \"info\");\n } else if (event.durationMs != null) {\n chat.showThinking(event.text ?? \"\", event.durationMs);\n }\n } else if (event.type === \"text_delta\") {\n resetWatchdog();\n hasAssistantTextRef.current = true;\n if (!hasAssistantStartedRef.current) {\n chat.commitPendingUser();\n chat.startAssistant(event.text);\n hasAssistantStartedRef.current = true;\n } else {\n chat.updateAssistant(event.text);\n }\n } else if (event.type === \"tool_use\") {\n if (!hasAssistantStartedRef.current) {\n chat.commitPendingUser();\n // Start an empty assistant entry so it can be finalized later\n chat.startAssistant(\"\");\n hasAssistantStartedRef.current = true;\n }\n toolNamesRef.current.push(event.name);\n pushNotification({\n key: `tool-${event.callId}`,\n text: `Running ${event.name}…`,\n priority: \"medium\",\n });\n chat.addTool(event.name, event.callId);\n } else if (event.type === \"tool_result\") {\n pushNotification({\n key: `tool-${event.callId}`,\n text: `${event.content.slice(0, 60)}…`,\n priority: \"low\",\n });\n chat.updateToolResult(event.callId, event.content);\n } else if (event.type === \"tool_recap\") {\n chat.addSystem(event.summary, \"info\");\n } else if (event.type === \"error\") {\n chat.commitPendingUser();\n chat.addSystem(`Error: ${event.message}`, \"error\");\n pushNotification({ key: `err-${Date.now()}`, text: event.message, priority: \"immediate\" });\n } else if (event.type === \"done\") {\n if (hasAssistantStartedRef.current) {\n chat.finalizeAssistant();\n // If tools ran but model produced no text, show which tools completed\n if (!hasAssistantTextRef.current) {\n const names = toolNamesRef.current;\n const unique = [...new Set(names)];\n const fallback =\n unique.length > 0\n ? `${unique.map((n) => `已调用 ${n}`).join(\" · \")} · 已完成 ${names.length} 个工具调用`\n : \"操作完成\";\n chat.addSystem(fallback, \"info\");\n }\n } else {\n chat.dropPendingUser();\n }\n // Accumulate budget from done event\n if (typeof event.totalTokens === \"number\" && event.totalTokens > 0) {\n setTokensUsed((prev) => prev + event.totalTokens!);\n }\n if (typeof event.costUsd === \"number\" && event.costUsd > 0) {\n setCostUsd((prev) => prev + event.costUsd!);\n }\n }\n }\n\n const hasAssistantStartedRef = useRef(false);\n /** Track whether the assistant has produced any visible text (not just tool calls). */\n const hasAssistantTextRef = useRef(false);\n /** Track tool names executed in the current turn for fallback summaries. */\n const toolNamesRef = useRef<string[]>([]);\n\n // ── Submit handler — consumes streaming events ─\n\n const handleSubmit = useCallback(\n async (text: string) => {\n if (text.startsWith(\"/\")) {\n executeSlashCommand(text.trim());\n return;\n }\n\n setAbortCount(0);\n hasAssistantStartedRef.current = false;\n hasAssistantTextRef.current = false;\n toolNamesRef.current = [];\n chatLogRef.current?.addUser(text, true);\n syncScrollEntries();\n setStreaming(true);\n\n try {\n for await (const event of callbacks.onInput(text)) {\n handleStreamEvent(event);\n syncScrollEntries();\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n chatLogRef.current?.commitPendingUser();\n chatLogRef.current?.addSystem(`Stream error: ${message}`, \"error\");\n chatLogRef.current?.dropAssistant();\n syncScrollEntries();\n } finally {\n clearWatchdog();\n setStreaming(false);\n }\n },\n [callbacks, syncScrollEntries, executeSlashCommand, clearWatchdog],\n );\n\n // ── Permission: show in chat area, not overlay ─\n\n const handlePermissionRequest = useCallback(\n (req: { requestId: string; toolName: string; description: string; safety: SafetyLevel }) => {\n setPendingPermission({\n requestId: req.requestId,\n toolName: req.toolName,\n safety: req.safety,\n description: req.description,\n });\n pushView({ id: \"permission\" });\n },\n [pushView],\n );\n\n // ── Stash state ──────────────────────────────\n\n const [stashItems, setStashItems] = useState<StashEntry[]>([]);\n /** Text to append to InputBox (set by FilePicker, StashPicker restore, etc.). */\n const [appendToInput, setAppendToInput] = useState<string | undefined>(undefined);\n\n /** Stash the current input (called via Ctrl+S from InputBox). */\n const stashCurrentInput = useCallback((text: string) => {\n const entry: StashEntry = {\n id: crypto.randomUUID().slice(0, 8),\n preview: text.slice(0, 100),\n timestamp: Date.now(),\n };\n setStashItems((prev) => [entry, ...prev].slice(0, 200));\n }, []);\n\n // Register the permission handler with the CLI bridge on mount\n useEffect(() => {\n onPermissionReady?.(handlePermissionRequest);\n return () => {\n // Unregister on unmount so the bridge doesn't call a stale handler\n onPermissionReady?.(null);\n };\n }, [onPermissionReady, handlePermissionRequest]);\n\n // ── Layout ────────────────────────────────────\n\n const isModal = currentView.id !== \"chat\";\n const hasVisibleRange = scroll.visibleStart < scroll.visibleEnd;\n\n // ── Modal renderers (per‑view functions to keep complexity low) ──\n\n /** Render the permission request modal. */\n function renderPermission(): React.ReactElement {\n return React.createElement(PermissionRequest, {\n request: {\n requestId: pendingPermission!.requestId,\n toolName: pendingPermission!.toolName,\n safety: pendingPermission!.safety,\n description: pendingPermission!.description,\n parameters: pendingPermission!.parameters,\n },\n onDecide: (id, choice) => {\n const approved = choice === \"allow\" || choice === \"always_allow\";\n callbacks.onPermissionReply(id, approved);\n setPendingPermission(null);\n popView();\n },\n onCancel: () => {\n callbacks.onPermissionReply(pendingPermission!.requestId, false);\n setPendingPermission(null);\n popView();\n },\n });\n }\n\n /** Render the session picker modal. */\n function renderSessions(): React.ReactElement {\n const viewProps = currentView.props as\n | { onSelectOverride?: (sessionId: string) => void }\n | undefined;\n return React.createElement(SessionPicker, {\n sessions,\n onSelect:\n viewProps?.onSelectOverride ??\n ((sessionId) => {\n callbacks.onSessionPick(sessionId);\n popView();\n }),\n onCancel: () => popView(),\n });\n }\n\n /** Render the model picker modal. */\n function renderModel(): React.ReactElement {\n return React.createElement(ModelPicker, {\n models: props.models ?? [],\n currentModel: props.currentModel,\n onSelect: (modelId) => {\n props.callbacks.onModelPick?.(modelId);\n popView();\n },\n onSetDefault: props.callbacks.onModelPick\n ? (modelId) => props.callbacks.onModelPick?.(modelId)\n : undefined,\n onCancel: () => popView(),\n });\n }\n\n /** Render the theme picker modal. */\n function renderTheme(): React.ReactElement {\n return React.createElement(ThemePicker, {\n onSelect: (themeName: ThemeName) => {\n setTheme(themeName);\n setThemeVersion((v) => v + 1);\n props.callbacks.onThemeChange?.(themeName);\n popView();\n },\n onCancel: () => popView(),\n });\n }\n\n /** Render the confirm dialog modal. */\n function renderConfirm(): React.ReactElement {\n const confirmProps = currentView.props ?? {};\n return React.createElement(ConfirmDialog, {\n title: (confirmProps.title as string) ?? \"Confirm\",\n message: (confirmProps.message as string) ?? \"Are you sure?\",\n confirmLabel: confirmProps.confirmLabel as string | undefined,\n cancelLabel: confirmProps.cancelLabel as string | undefined,\n onConfirm: () => {\n (confirmProps.onConfirm as (() => void) | undefined)?.();\n popView();\n },\n onCancel: () => popView(),\n });\n }\n\n /** Render the input prompt modal. */\n function renderInputPrompt(): React.ReactElement {\n const promptProps = currentView.props ?? {};\n return React.createElement(InputPrompt, {\n title: (promptProps.title as string) ?? \"Input\",\n initialValue: promptProps.initialValue as string | undefined,\n placeholder: promptProps.placeholder as string | undefined,\n onConfirm: (value) => {\n (promptProps.onConfirm as ((v: string) => void) | undefined)?.(value);\n popView();\n },\n onCancel: () => popView(),\n });\n }\n\n /** Dispatch table for modal views — keeps renderModal complexity at O(1). */\n const modalRenderers: Record<string, () => React.ReactElement> = {\n permission: renderPermission,\n sessions: renderSessions,\n help: () => React.createElement(HelpModal, { onCancel: () => popView() }),\n commands: () =>\n React.createElement(CommandPalette, {\n onSelect: (cmd) => executeSlashCommand(cmd),\n onCancel: () => popView(),\n }),\n model: renderModel,\n settings: () =>\n React.createElement(ConfigMenu, {\n onToggle: (key, value) => {\n props.callbacks.onConfigChange?.(key, value);\n },\n onEdit: (key, label, currentValue, valueType) => {\n pushView({\n id: \"input_prompt\",\n props: {\n title: `Edit: ${label}`,\n initialValue: currentValue,\n placeholder: `Enter new value for ${label}`,\n onConfirm: (newValue: string) => {\n // Parse as number if the original value was a number\n const finalValue =\n valueType === \"number\" && !isNaN(Number(newValue)) ? Number(newValue) : newValue;\n props.callbacks.onConfigChange?.(key, finalValue);\n popView();\n },\n },\n });\n },\n onCancel: () => popView(),\n }),\n theme: renderTheme,\n confirm: renderConfirm,\n doctor: () =>\n React.createElement(DoctorPanel, {\n checks: runBuiltinChecks(),\n onCancel: () => popView(),\n }),\n input_prompt: renderInputPrompt,\n file_picker: () =>\n React.createElement(FilePicker, {\n workspace: session?.workspace ?? process.cwd(),\n onSelect: (filePath) => {\n setAppendToInput(filePath);\n popView();\n },\n onCancel: () => popView(),\n }),\n stash: () =>\n React.createElement(StashPicker, {\n items: stashItems,\n onRestore: (id) => {\n const entry = stashItems.find((e) => e.id === id);\n if (entry) setAppendToInput(entry.preview);\n popView();\n },\n onDelete: (id) => {\n setStashItems((prev) => prev.filter((e) => e.id !== id));\n },\n onCancel: () => popView(),\n }),\n mcp: () =>\n React.createElement(McpPanel, {\n connections: props.mcpConnections ?? [],\n onConnect: (name) => props.callbacks.onMcpConnect?.(name),\n onDisconnect: (name) => props.callbacks.onMcpDisconnect?.(name),\n onReconnect: (name) => props.callbacks.onMcpReconnect?.(name),\n onCancel: () => popView(),\n }),\n plugin: () =>\n React.createElement(PluginPanel, {\n plugins: props.plugins ?? [],\n onLoad: (name) => props.callbacks.onPluginLoad?.(name),\n onUnload: (name) => props.callbacks.onPluginUnload?.(name),\n onCancel: () => popView(),\n }),\n skills: () =>\n React.createElement(SkillPanel, {\n skills: props.skills ?? [],\n onCancel: () => popView(),\n }),\n context: () =>\n React.createElement(ContextPanel, {\n contextInfo: props.contextInfo ?? {\n memoryFacts: 0,\n rules: 0,\n skills: 0,\n model: props.currentModel ?? \"unknown\",\n workspace: session?.workspace ?? process.cwd(),\n sessionLabel: session?.label ?? \"none\",\n },\n onCancel: () => popView(),\n }),\n usage: () =>\n React.createElement(UsagePanel, {\n usageInfo: props.usageInfo ?? {\n tokensUsed,\n costUsd,\n budgetMaxTokens: 0,\n budgetMaxUsd: 0,\n turns: 0,\n modelPricing: props.currentModel ? `${props.currentModel}: N/A` : \"N/A\",\n },\n onCancel: () => popView(),\n }),\n diff: () =>\n React.createElement(DiffViewer, {\n onRequestDiff: callbacks.onRequestDiff,\n onCancel: () => popView(),\n }),\n snapshots: () =>\n React.createElement(SnapshotBrowser, {\n onRequestSnapshots: callbacks.onRequestSnapshots,\n onCancel: () => popView(),\n }),\n tasks: () =>\n React.createElement(TasksPanel, {\n onRequestTasks: callbacks.onRequestTasks,\n onCancel: () => popView(),\n }),\n skill_pick: () =>\n React.createElement(SkillPicker, {\n skills: props.skills ?? [],\n onSelect: (skillName) => {\n chatLogRef.current?.addSystem(`Skill loaded: ${skillName}`, \"info\");\n popView();\n },\n onCancel: () => popView(),\n }),\n };\n\n /** Render the active modal overlay, if any. */\n function renderModal(): React.ReactElement | null {\n if (currentView.id === \"permission\" && !pendingPermission) return null;\n const renderer = modalRenderers[currentView.id];\n return renderer ? renderer() : null;\n }\n\n // ── Render ───────────────────────────────────\n // Note: Ink 6.x requires a single root Box. All code paths\n // below return exactly one root element.\n\n if (showWelcome && !welcomeDone) {\n return React.createElement(WelcomeScreen, {\n workspace: session?.workspace ?? process.cwd(),\n version: \"0.1.0\",\n lastSession: session\n ? {\n label: session.label,\n relativeTime: relativeTimeStr(session.updatedAt),\n sessionCount: sessions.length,\n }\n : undefined,\n onConfirm: () => setWelcomeDone(true),\n onExit: () => process.exit(0),\n });\n }\n\n return React.createElement(\n Box,\n { flexDirection: \"column\", height: rows },\n\n // ── Header ─────────────────────────────────\n React.createElement(\n Box,\n { flexDirection: \"row\", justifyContent: \"space-between\", marginBottom: 1 },\n React.createElement(Text, { bold: true, color: theme.colors.accent }, \"Lynx\"),\n React.createElement(Text, { dimColor: true }, session?.label ?? \"no session\"),\n ),\n\n // ── Chat area ──────────────────────────────\n React.createElement(\n Box,\n { flexDirection: \"column\", height: chatHeight, overflow: \"hidden\" },\n React.createElement(ChatLog, {\n ref: chatLogRef,\n visibleRange: hasVisibleRange\n ? { start: scroll.visibleStart, end: scroll.visibleEnd }\n : undefined,\n onSearchActiveChange: setSearchActive,\n transcriptMode,\n }),\n\n // Jump‑to‑bottom pill\n !scroll.stickyScroll && scroll.unseenCount > 0\n ? React.createElement(\n Box,\n { paddingX: 2, paddingY: 0 },\n React.createElement(\n Text,\n { color: theme.colors.accent, inverse: true },\n ` ↓ ${scroll.unseenCount} new messages — Enter to jump `,\n ),\n )\n : null,\n ),\n\n // ── Notification toast ─────────────────────\n activeNotification\n ? React.createElement(\n Box,\n { paddingX: 1 },\n React.createElement(NotificationCenter, { current: activeNotification }),\n )\n : null,\n\n // ── Input area ─────────────────────────────\n React.createElement(\n Box,\n { flexDirection: \"column\" },\n React.createElement(InputBox, {\n onSubmit: handleSubmit,\n onAbort: handleAbort,\n disabled: streaming || searchActive,\n workspace: session?.workspace,\n placeholder:\n abortCount > 0\n ? `[Abort ${abortCount}/${MAX_ABORT_LAYERS}] Type a message...`\n : \"Type a message...\",\n onStash: stashCurrentInput,\n appendText: appendToInput,\n onAppendTextConsumed: () => setAppendToInput(undefined),\n }),\n ),\n\n // ── Status bar ─────────────────────────────\n React.createElement(StatusBar, {\n mode: abortCount > 0 ? `abort ${abortCount}/${MAX_ABORT_LAYERS}` : \"default\",\n model: props.currentModel ?? \"unknown\",\n streaming,\n viewName: currentView.id,\n tokensUsed,\n costUsd,\n budgetMaxUsd: 10, // default budget cap from AgentConfig\n }),\n\n // ── Modal overlay ──────────────────────────\n isModal ? renderModal() : null,\n );\n}\n","/**\n * ChatView — scrollable message transcript.\n *\n * Renders the session message history as a sequence of\n * text blocks, with speaker labels (User / Assistant)\n * and tool‑use callouts.\n */\n\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { Message } from \"@24klynx/core\";\n\n// ── Props ────────────────────────────────────────────\n\nexport interface ChatViewProps {\n messages: Message[];\n streaming: boolean;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst MAX_VISIBLE_MESSAGES = 50;\n\n// ── Public API ───────────────────────────────────────\n\nexport function ChatView({ messages, streaming }: ChatViewProps): React.ReactElement {\n // Show only the most recent messages\n const visible = messages.slice(-MAX_VISIBLE_MESSAGES);\n\n if (visible.length === 0) {\n return React.createElement(\n Box,\n { flexDirection: \"column\" },\n React.createElement(Text, { dimColor: true }, \"No messages yet. Start a conversation!\"),\n );\n }\n\n const elements: React.ReactElement[] = [];\n\n for (let i = 0; i < visible.length; i++) {\n const msg = visible[i]!;\n const label = msg.role === \"user\" ? \"You\" : \"Lynx\";\n const labelColor = msg.role === \"user\" ? \"green\" : \"blue\";\n\n elements.push(\n React.createElement(\n Box,\n { key: msg.id as string, flexDirection: \"column\", marginBottom: 1 },\n React.createElement(Text, { bold: true, color: labelColor }, `${label}:`),\n // Render each content block\n ...msg.content.map((block, bi) => {\n if (block.type === \"text\") {\n return React.createElement(Text, { key: `${msg.id as string}-${bi}` }, block.text);\n }\n if (block.type === \"tool_use\") {\n return React.createElement(\n Text,\n { key: `${msg.id as string}-${bi}`, color: \"yellow\" },\n `[Tool: ${block.name}]`,\n );\n }\n if (block.type === \"tool_result\") {\n const preview = block.content.slice(0, 200);\n return React.createElement(\n Text,\n { key: `${msg.id as string}-${bi}`, dimColor: true },\n `→ ${preview}${block.content.length > 200 ? \"...\" : \"\"}`,\n );\n }\n if (block.type === \"reasoning\") {\n return React.createElement(\n Text,\n { key: `${msg.id as string}-${bi}`, dimColor: true, italic: true },\n `[thinking] ${block.text.slice(0, 100)}`,\n );\n }\n return React.createElement(Text, { key: `${msg.id as string}-${bi}` }, \"\");\n }),\n ),\n );\n }\n\n // Streaming indicator\n if (streaming) {\n elements.push(\n React.createElement(\n Box,\n { key: \"streaming-indicator\" },\n React.createElement(Text, { dimColor: true }, \"▊\"),\n ),\n );\n }\n\n return React.createElement(Box, { flexDirection: \"column\" }, ...elements);\n}\n","/**\n * ToolRenderer — strategy‑based rendering for tool calls and results.\n *\n * Dispatches to specialized renderers based on the tool name, showing\n * a styled header with the tool icon, name, and relevant context\n * (file path, URL, command, etc.).\n *\n * Design:\n * Each tool category has a dedicated layout with appropriate\n * icons, color coding, and truncation rules.\n */\n\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\n\n/** Props passed to the ToolRenderer. */\nexport interface ToolRendererProps {\n /** Name of the tool being rendered. */\n toolName: string;\n /** Whether this is the tool call (header) or the result. */\n phase: \"call\" | \"result\";\n /** Content to display (command, file path, result text). */\n content: string;\n}\n\n/** Maximum characters before truncation. */\nconst MAX_CONTENT = 2000;\n\n/**\n * ToolRenderer component.\n *\n * Renders tool invocations and results with appropriate icons and colors.\n * Different tool categories get different visual treatments.\n */\nexport function ToolRenderer({ toolName, phase, content }: ToolRendererProps): React.ReactElement {\n const icon = toolIcon(toolName);\n const label = toolLabel(toolName, content);\n const truncated =\n content.length > MAX_CONTENT ? content.slice(0, MAX_CONTENT) + \"\\n [truncated]\" : content;\n\n return React.createElement(\n Box,\n { flexDirection: \"column\", marginBottom: 1 },\n // ── Header ───────────────────────────────\n React.createElement(\n Box,\n { flexDirection: \"row\" },\n React.createElement(Text, { bold: true }, `${icon} ${toolName}`),\n label ? React.createElement(Text, { dimColor: true }, ` — ${label}`) : null,\n ),\n // ── Body ─────────────────────────────────\n phase === \"result\"\n ? React.createElement(\n Text,\n { dimColor: phase === \"result\" },\n phase === \"result\" ? ` → ${truncated}` : truncated,\n )\n : null,\n );\n}\n\n/** Choose an icon based on tool category. */\nfunction toolIcon(name: string): string {\n if (/^(bash|exec|shell|powershell|cmd)$/i.test(name)) return \"💻\";\n if (/^(write|edit|notebook_edit|create_or_update_file|delete_file|move_file)$/i.test(name))\n return \"✏️\";\n if (\n /^(read|grep|glob|search|read_file|read_text_file|read_media_file|read_multiple_files)$/i.test(\n name,\n )\n )\n return \"📄\";\n if (/^(web_fetch|web_search|browser_navigate)$/i.test(name)) return \"🌐\";\n if (/^(agent|task|team_create|team_delete)$/i.test(name)) return \"🤖\";\n if (/^(ask_user|ask_user_question)$/i.test(name)) return \"❓\";\n return \"🔧\";\n}\n\n/** Generate a short label from the tool's first argument (path, URL, command). */\nfunction toolLabel(name: string, content: string): string {\n const firstLine = content.split(\"\\n\")[0] ?? \"\";\n const isRead =\n /^(read|grep|glob|search|read_file|read_text_file|read_media_file|read_multiple_files)$/i.test(\n name,\n );\n const isWrite = /^(write|edit|notebook_edit|create_or_update_file|delete_file|move_file)$/i.test(\n name,\n );\n const isBash = /^(bash|exec|shell|powershell|cmd)$/i.test(name);\n const isWeb = /^(web_fetch|web_search|browser_navigate)$/i.test(name);\n\n if (isBash) {\n // Show truncated command\n return firstLine.length > 60 ? firstLine.slice(0, 57) + \"...\" : firstLine;\n }\n\n if (isRead || isWrite) {\n // Show file path\n return firstLine.length > 50 ? firstLine.slice(0, 47) + \"...\" : firstLine;\n }\n\n if (isWeb) {\n // Show URL\n const url = firstLine.length > 60 ? firstLine.slice(0, 57) + \"...\" : firstLine;\n return url;\n }\n\n return \"\";\n}\n","/**\n * Mascot — animated character that reflects the current agent state.\n *\n * States:\n * idle — waiting for input (slow animation)\n * listen — user is typing (static)\n * think — LLM is reasoning (fast animation)\n * speak — assistant is streaming output\n * error — something went wrong\n *\n * Each state has a set of frames and a rotation interval.\n * Uses a simple setInterval‑based animation.\n */\n\nimport React, { useState, useEffect, useRef } from \"react\";\nimport { Text } from \"ink\";\n\n/** The five mascot states. */\nexport type MascotState = \"idle\" | \"listen\" | \"think\" | \"speak\" | \"error\";\n\n/** Props for the Mascot component. */\nexport interface MascotProps {\n /** Current mascot state. */\n state: MascotState;\n /** Whether animation is enabled (respects reduce‑motion preference). */\n animate?: boolean;\n}\n\n/** Frames and timing per state. */\ninterface StateConfig {\n frames: string[];\n intervalMs: number;\n}\n\nconst STATE_FRAMES: Record<MascotState, StateConfig> = {\n idle: {\n frames: [\"🐱\", \"😺\", \"🐱\", \"😸\"],\n intervalMs: 3000,\n },\n listen: {\n frames: [\"🐱\"],\n intervalMs: Infinity, // No animation\n },\n think: {\n frames: [\"🤔\", \"💭\", \"🤔\", \"💭\"],\n intervalMs: 600,\n },\n speak: {\n frames: [\"😸\", \"🐱\"],\n intervalMs: 400,\n },\n error: {\n frames: [\"🙀\", \"😾\"],\n intervalMs: 500,\n },\n};\n\n/**\n * Animated mascot character.\n *\n * Renders a single emoji that changes based on the current state.\n * Animation is frame‑based with configurable intervals per state.\n */\nexport function Mascot({ state, animate = true }: MascotProps): React.ReactElement {\n const config = STATE_FRAMES[state] ?? STATE_FRAMES.idle;\n const [frameIndex, setFrameIndex] = useState(0);\n const timerRef = useRef<NodeJS.Timeout | null>(null);\n\n useEffect(() => {\n // Reset frame when state changes\n setFrameIndex(0);\n\n if (!animate || config.intervalMs === Infinity) {\n return;\n }\n\n timerRef.current = setInterval(() => {\n setFrameIndex((prev) => (prev + 1) % config.frames.length);\n }, config.intervalMs);\n\n return () => {\n if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n };\n }, [state, animate, config.intervalMs, config.frames.length]);\n\n const frame = config.frames[frameIndex] ?? config.frames[0]!;\n\n return React.createElement(Text, null, frame);\n}\n","/**\n * useInput — bridge between Ink's raw input and the agent's submit callback.\n *\n * Handles 3-parameter handler: (input: string, key: Key, event: InputEvent).\n * Exposes controlled input state and keyboard-aware submission.\n */\n\nimport { useState, useCallback, useRef } from \"react\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface InputState {\n /** Current text in the input box. */\n value: string;\n /** Cursor position within the value. */\n cursor: number;\n /** Whether the input is currently focused. */\n focused: boolean;\n}\n\nexport interface InputActions {\n /** Set the full value. */\n setValue: (value: string) => void;\n /** Clear the input. */\n clear: () => void;\n /** Focus the input. */\n focus: () => void;\n /** Blur the input. */\n blur: () => void;\n /** Submit the current value. Returns the submitted text. */\n submit: () => string;\n /** Insert text at cursor position. */\n insert: (text: string) => void;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Controlled input hook for the main REPL input area.\n *\n * @param onSubmit Called when the user presses Enter with non‑empty input.\n * @param onKey Optional handler for non‑Enter key presses (slash menu, shortcuts, etc.).\n */\nexport function useInput(\n onSubmit: (text: string) => void,\n onKey?: (input: string, key: Key) => void,\n): [InputState, InputActions] {\n const [value, setValue] = useState(\"\");\n const [cursor, setCursor] = useState(0);\n const [focused, setFocused] = useState(true);\n const inputRef = useRef<InputState>({ value: \"\", cursor: 0, focused: true });\n\n // Sync ref with state for the Ink callback\n inputRef.current = { value, cursor, focused };\n\n useInkInput(\n (rawInput: string, key: Key) => {\n if (!inputRef.current.focused) return;\n\n if (key.return) {\n const text = inputRef.current.value.trim();\n if (text) {\n onSubmit(text);\n setValue(\"\");\n setCursor(0);\n }\n return;\n }\n\n if (onKey) {\n onKey(inputRef.current.value, key);\n }\n },\n { isActive: focused },\n );\n\n const actions: InputActions = {\n setValue: useCallback((v: string) => {\n setValue(v);\n setCursor(v.length);\n }, []),\n\n clear: useCallback(() => {\n setValue(\"\");\n setCursor(0);\n }, []),\n\n focus: useCallback(() => {\n setFocused(true);\n }, []),\n\n blur: useCallback(() => {\n setFocused(false);\n }, []),\n\n submit: useCallback((): string => {\n const text = value.trim();\n if (text) {\n onSubmit(text);\n setValue(\"\");\n setCursor(0);\n }\n return text;\n }, [value, onSubmit]),\n\n insert: useCallback(\n (text: string) => {\n setValue((prev) => {\n const pos = cursor;\n return prev.slice(0, pos) + text + prev.slice(pos);\n });\n setCursor((prev) => prev + text.length);\n },\n [cursor],\n ),\n };\n\n return [{ value, cursor, focused }, actions];\n}\n","/**\n * Text sanitization — strip control characters, ANSI escapes, and\n * handle Unicode RTL isolation for safe terminal rendering.\n *\n * All functions are sync and pure — they take a string and return a\n * cleaned version suitable for display.\n */\n\n// ── Constants ────────────────────────────────────────\n\n/** Maximum length of a \"word\" token before insertion of soft breaks. */\nconst LONG_TOKEN_LENGTH = 33;\n\n/** Characters that valid URLs may contain (after the scheme). */\nconst URL_CHARS = /^[a-zA-Z0-9._~:/?#[\\]@!$&'()*+,;=\\-]+$/;\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Strip ANSI escape sequences (CSI, OSC, etc.) from text.\n *\n * Matches: CSI (\\\\x1b[), OSC (\\\\x1b]), and single‑character escapes.\n * Does NOT strip SGR‑only sequences within Ink elements —\n * this is for raw text from tool output or LLM responses.\n */\nexport function stripAnsi(text: string): string {\n // eslint-disable-next-line no-control-regex\n return (\n text\n .replace(/\\x1b\\[[0-9;]*[a-zA-Z]/g, \"\")\n // eslint-disable-next-line no-control-regex\n .replace(/\\x1b\\][^\\x07]*\\x07/g, \"\")\n // eslint-disable-next-line no-control-regex\n .replace(/\\x1b[()][0-9AB]/g, \"\")\n // eslint-disable-next-line no-control-regex\n .replace(/\\x1b[><=]/g, \"\")\n );\n}\n\n/**\n * Strip control characters from text, preserving tab and newline.\n *\n * Removes: NUL, BEL, BS, FF, CR, SO, SI, DLE–US, DEL.\n * Preserves: \\\\t (tab), \\\\n (newline), \\\\r (carriage return).\n */\nexport function stripControlChars(text: string): string {\n return text\n .replace(/\\x00/g, \"\") // NUL\n .replace(/\\x07/g, \"\") // BEL\n .replace(/\\x08/g, \"\") // BS\n .replace(/\\x0c/g, \"\") // FF\n .replace(/\\x0e/g, \"\") // SO\n .replace(/\\x0f/g, \"\") // SI\n .replace(/[\\x10-\\x1a]/g, \"\") // DLE–SUB\n .replace(/\\x1c/g, \"\") // FS\n .replace(/\\x1d/g, \"\") // GS\n .replace(/\\x1e/g, \"\") // RS\n .replace(/\\x1f/g, \"\") // US\n .replace(/\\x7f/g, \"\"); // DEL\n}\n\n/**\n * Wrap RTL (right‑to‑left) text with Unicode bidirectional isolation\n * characters to prevent it from corrupting surrounding LTR layout.\n *\n * RTL scripts detected: Arabic, Hebrew, Syriac, Thaana, N'Ko.\n */\nexport function isolateRtl(text: string): string {\n // Only wrap if RTL characters are present (avoid superfluous marks)\n // eslint-disable-next-line no-misleading-character-class\n if (!/[֐-ࣿיִ-﷿ﹰ-﻾]/.test(text)) return text;\n return `⁨${text}⁩`;\n}\n\n/**\n * Insert soft line‑break opportunities into long \"words\" (tokens) to\n * prevent terminal line overflow. URLs and code blocks are preserved.\n *\n * Tokens longer than {@link LONG_TOKEN_LENGTH} characters are split\n * with zero‑width spaces every 33 characters.\n */\nexport function chunkLongTokens(text: string, maxLen: number = LONG_TOKEN_LENGTH): string {\n // Don't modify text that looks like a code block\n if (text.startsWith(\"```\")) return text;\n\n const words = text.split(/(\\s+)/);\n const result: string[] = [];\n\n for (const word of words) {\n if (word.length <= maxLen) {\n result.push(word);\n continue;\n }\n\n // Preserve URLs\n if (isUrl(word)) {\n result.push(word);\n continue;\n }\n\n // Insert ZWSP every maxLen characters\n const chunks: string[] = [];\n for (let i = 0; i < word.length; i += maxLen) {\n chunks.push(word.slice(i, i + maxLen));\n }\n result.push(chunks.join(\"​\"));\n }\n\n return result.join(\"\");\n}\n\n/**\n * Detect binary content by measuring the ratio of non‑printable\n * characters (excluding common whitespace).\n *\n * If the binary ratio exceeds 50%, returns `\"[binary content]\"`;\n * otherwise returns the original text.\n */\nexport function redactBinaryContent(text: string): string {\n // Short text can't be reliably detected\n if (text.length < 10) return text;\n\n let nonPrintable = 0;\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n // Allow: newline, tab, printable ASCII, and common Unicode\n if (code === 0x0a || code === 0x0d || code === 0x09) continue;\n if (code >= 0x20 && code <= 0x7e) continue;\n if (code >= 0x80) continue; // Non‑ASCII (including CJK)\n nonPrintable++;\n }\n\n const ratio = nonPrintable / text.length;\n if (ratio > 0.5) {\n return \"[binary content]\";\n }\n\n return text;\n}\n\n/**\n * Full sanitization pipeline — applies all sanitizers in order.\n *\n * This is the recommended entry point for cleaning tool output\n * before rendering in the TUI.\n */\nexport function sanitize(text: string): string {\n let cleaned = stripAnsi(text);\n cleaned = stripControlChars(cleaned);\n cleaned = redactBinaryContent(cleaned);\n cleaned = chunkLongTokens(cleaned);\n return cleaned;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\nfunction isUrl(text: string): boolean {\n return /^https?:\\/\\//.test(text) && URL_CHARS.test(text.slice(8));\n}\n","/**\n * Keybindings — catalog of keyboard shortcuts with context‑aware dispatch.\n *\n * Each binding maps a key combination to an action, optionally scoped\n * to a specific view. The dispatcher resolves the binding for the\n * current context and executes it.\n */\n\nimport type { Key } from \"ink\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface KeyBinding {\n /** Human‑readable description shown in the help modal. */\n description: string;\n /** Which views this binding applies to (empty = all views). */\n scopes: string[];\n /** Key matcher function. */\n match: (input: string, key: Key) => boolean;\n /** Action to execute. */\n action: () => void;\n}\n\nexport type KeyBindingCatalog = KeyBinding[];\n\n// ── Built‑in bindings ────────────────────────────────\n\n/**\n * Create the default keybinding catalog.\n *\n * Callers provide concrete actions for each binding.\n * The catalog is stateless — each binding is a closure\n * over the action it should perform.\n */\nexport function createDefaultBindings(actions: {\n abort: () => void;\n help: () => void;\n sessionPicker: () => void;\n clearScreen: () => void;\n scrollUp: () => void;\n scrollDown: () => void;\n}): KeyBindingCatalog {\n return [\n {\n description: \"Abort current operation\",\n scopes: [],\n match: (_input: string, key: Key) => key.ctrl && _input === \"g\",\n // Ctrl+C is handled specially by the input system; this is Ctrl+G\n action: actions.abort,\n },\n {\n description: \"Show help\",\n scopes: [],\n match: (_input: string, key: Key) => key.ctrl && _input === \"h\",\n action: actions.help,\n },\n {\n description: \"Switch session\",\n scopes: [\"chat\"],\n match: (_input: string, key: Key) => key.ctrl && _input === \"s\",\n action: actions.sessionPicker,\n },\n {\n description: \"Clear screen\",\n scopes: [\"chat\"],\n match: (_input: string, key: Key) => key.ctrl && _input === \"l\",\n action: actions.clearScreen,\n },\n {\n description: \"Scroll up\",\n scopes: [\"chat\"],\n match: (_input: string, key: Key) => key.pageUp || (key.ctrl && _input === \"u\"),\n action: actions.scrollUp,\n },\n {\n description: \"Scroll down\",\n scopes: [\"chat\"],\n match: (_input: string, key: Key) => key.pageDown || (key.ctrl && _input === \"d\"),\n action: actions.scrollDown,\n },\n ];\n}\n\n// ── Dispatcher ───────────────────────────────────────\n\n/**\n * Find and execute the first matching keybinding for the current scope.\n *\n * @returns true if a binding matched and was executed.\n */\nexport function dispatchBinding(\n catalog: KeyBindingCatalog,\n scope: string,\n input: string,\n key: Key,\n): boolean {\n for (const binding of catalog) {\n const inScope = binding.scopes.length === 0 || binding.scopes.includes(scope);\n if (inScope && binding.match(input, key)) {\n binding.action();\n return true;\n }\n }\n return false;\n}\n","/**\n * ErrorBoundary — catches rendering errors in the Ink component tree.\n *\n * On error, displays a red error message with the error details and\n * instructions to restart. Prevents the entire TUI from crashing\n * due to a single component error.\n */\n\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\n\n/** Props for the ErrorBoundary. */\nexport interface ErrorBoundaryProps {\n children: React.ReactNode;\n}\n\n/** State tracked by the ErrorBoundary. */\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\n/**\n * React error boundary for Ink components.\n *\n * Catches rendering errors and displays a fallback UI instead of\n * crashing the entire terminal application.\n */\nexport class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n // Log to stderr so it appears in terminal logs\n process.stderr.write(\n `[ErrorBoundary] ${error.message}\\n${error.stack ?? \"\"}\\nComponent stack: ${errorInfo.componentStack ?? \"\"}\\n`,\n );\n }\n\n render(): React.ReactNode {\n if (this.state.hasError) {\n return React.createElement(\n Box,\n {\n flexDirection: \"column\",\n borderStyle: \"round\",\n borderColor: \"red\",\n paddingX: 2,\n paddingY: 1,\n },\n React.createElement(Text, { bold: true, color: \"red\" }, \"✘ Lynx TUI encountered an error\"),\n React.createElement(Text, { dimColor: true }, this.state.error?.message ?? \"Unknown error\"),\n React.createElement(Box, { height: 1 }),\n React.createElement(Text, { dimColor: true }, \"Press Ctrl+C to exit and restart.\"),\n );\n }\n\n return this.props.children;\n }\n}\n","/**\n * AlternateScreen — Ink component wrapping alt‑buffer management.\n *\n * Calls enterFullscreen/exitFullscreen lifecycle hooks when mounted/unmounted.\n * Use this instead of calling terminal-mode utilities directly.\n *\n * Design (§5.9b): componentized alternate screen for fullscreen layout.\n */\n\nimport React, { useEffect } from \"react\";\nimport type { ReactNode } from \"react\";\n\n/** Props for the AlternateScreen wrapper. */\nexport interface AlternateScreenProps {\n /** Children rendered inside the alt buffer. */\n children: ReactNode;\n /** Called when entering fullscreen mode. */\n onEnter(): void;\n /** Called when exiting fullscreen mode. */\n onExit(): void;\n}\n\n/**\n * Wraps children in alternate‑buffer lifecycle management.\n *\n * Calls `onEnter` on mount and `onExit` on unmount,\n * ensuring terminal recovery even on unexpected crashes.\n */\nexport function AlternateScreen({\n children,\n onEnter,\n onExit,\n}: AlternateScreenProps): React.ReactElement {\n useEffect(() => {\n onEnter();\n return () => {\n onExit();\n };\n // Only run on mount/unmount — callbacks are stable references\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return React.createElement(React.Fragment, null, children);\n}\n"],"mappings":";;;;;;;AAWA,MAAM,SAAsC;CAC1C,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;CACA,YAAY;EACV,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;CACA,WAAW;EACT,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;AACF;AAIA,IAAI,WAAsB;;AAG1B,SAAS,cAAyB;CAChC,IAAI,QAAQ,IAAI,UAAU,OAAO;CACjC,IAAI,QAAQ,IAAI,cAAc,OAAO,QAAQ,IAAI,aAC/C,OAAO,QAAQ,IAAI;CAErB,OAAO;AACT;;AAKA,SAAgB,YAAkB;CAChC,WAAW,YAAY;AACzB;;AAGA,SAAgB,WAAqB;CACnC,OAAO,OAAO;AAChB;;AAGA,SAAgB,SAAS,MAAuB;CAC9C,IAAI,OAAO,OACT,WAAW;AAEf;;AAGA,SAAgB,MAAM,MAAsB;CAC1C,MAAM,QAAQ,OAAO;CACrB,OAAO,MAAM,OAAO,SAAS,MAAM,OAAO;AAC5C;;AAGA,SAAgB,aAA0B;CACxC,OAAO,OAAO,KAAK,MAAM;AAC3B;;;;AC5HA,MAAM,cAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,WAAW,IAAI,IAAI;CACvB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,cAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,cAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,gBAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,cAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,eAAe,IAAI,IAAI;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,gBAAgB,IAAI,IAAY;CAAC;CAAQ;CAAS;AAAM,CAAC;AAC/D,MAAM,gBAAgB,IAAI,IAAY;CAAC;CAAQ;CAAS;CAAQ;CAAO;CAAM;CAAM;AAAK,CAAC;;AAGzF,MAAM,eAAe,IAAI,IAAI;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAKD,MAAM,eAAuC;CAC3C,IAAI;CACJ,YAAY;CACZ,KAAK;CACL,KAAK;CACL,IAAI;CACJ,YAAY;CACZ,KAAK;CACL,IAAI;CACJ,QAAQ;CACR,SAAS;CACT,IAAI;CACJ,QAAQ;CACR,IAAI;CACJ,MAAM;CACN,IAAI;CACJ,MAAM;CACN,OAAO;CACP,KAAK;CACL,KAAK;CACL,MAAM;CACN,MAAM;CACN,MAAM;CACN,KAAK;CACL,KAAK;CACL,MAAM;CACN,MAAM;AACR;;AAGA,MAAM,kBAAkB;CAAE,OAAO;CAAM,KAAK;AAAK;AAEjD,MAAM,YAAY;CAChB,UAAU;CACV,OAAO;CACP,cAAc,CAAC,MAAM;CACrB,cAAc;CACd,kBAAkB;EAAC;EAAK;EAAK;CAAG;AAClC;AACA,MAAM,YAAY;CAChB,UAAU;CACV,OAAO;CACP,cAAc,CAAC,MAAM;CACrB,cAAc;CACd,kBAAkB;EAAC;EAAK;EAAK;CAAG;AAClC;AACA,MAAM,YAAY;CAAE,UAAU;CAAa,cAAc,CAAC,GAAG;CAAG,kBAAkB,CAAC,KAAK,GAAG;AAAE;AAC7F,MAAM,YAAY;CAChB,UAAU;CACV,cAAc,CAAC,MAAM;CACrB,cAAc;CACd,kBAAkB,CAAC,KAAK,GAAG;AAC7B;AACA,MAAM,YAAY;CAChB,UAAU;CACV,cAAc,CAAC,MAAM;CACrB,cAAc;CACd,kBAAkB,CAAC,KAAK,GAAG;AAC7B;AACA,MAAM,YAAY;CAAE,UAAU;CAAa,cAAc,CAAC,GAAG;CAAG,kBAAkB,CAAC,KAAK,GAAG;AAAE;AAC7F,MAAM,aAAa;CAAE,UAAU;CAAc,cAAc,CAAC,IAAI;CAAG,kBAAkB,CAAC,GAAG;AAAE;AAC3F,MAAM,cAAc;CAAE,UAAU;CAAe,kBAAkB,CAAC,GAAG;AAAE;AACvE,MAAM,cAAc;CAAE,UAAU;CAAe,cAAc,CAAC,GAAG;CAAG,kBAAkB,CAAC,KAAK,GAAG;AAAE;AACjG,MAAM,aAAa;CACjB,UAAU;CACV,cAAc,CAAC,MAAM;CACrB,cAAc;CACd,kBAAkB,CAAC,KAAK,GAAG;AAC7B;AACA,MAAM,kBAAkB;CACtB,UAAU;CACV,cAAc,iBAAC,IAAI,OAAO,IAAI,CAAC;CAC/B,cAAc;CACd,kBAAkB;EAAC;EAAK;EAAK;CAAG;AAClC;AAEA,MAAM,eAA2C;CAC/C,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,KAAK;CACL,MAAM;CACN,MAAM;CACN,KAAK;AACP;;AAGA,SAAS,cAAc,UAA+B;CACpD,MAAM,MAAM,cAAc,YAAY,GAAA,CAAI,YAAY;CACtD,OAAO,MAAO,aAAa,QAAQ,kBAAmB;AACxD;;;;;;;;;;;;;;;;;AAoBA,SAAS,aACP,MACA,QACA,gBACqD;CACrD,MAAM,QAAyB,CAAC;CAGhC,MAAM,KAAK,OAAO;CAClB,IAAI,IAAI;EACN,IAAI,gBAAgB;GAElB,MAAM,SAAS,KAAK,QAAQ,GAAG,GAAG;GAClC,IAAI,UAAU,GAAG;IACf,MAAM,KAAK;KAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GAAG,IAAI,MAAM;KAAG,MAAM;IAAU,CAAC;IAE3E,MAAM,YAAY,aAAa,KAAK,MAAM,SAAS,GAAG,IAAI,MAAM,GAAG,QAAQ,KAAK;IAChF,MAAM,KAAK,GAAG,UAAU,KAAK;IAC7B,OAAO;KAAE;KAAO,gBAAgB;IAAM;GACxC;GAEA,MAAM,KAAK;IAAE,MAAM;IAAM,MAAM;GAAU,CAAC;GAC1C,OAAO;IAAE;IAAO,gBAAgB;GAAK;EACvC;EAGA,MAAM,WAAW,KAAK,QAAQ,GAAG,KAAK;EACtC,IAAI,YAAY,GAAG;GACjB,MAAM,SAAS,KAAK,QAAQ,GAAG,KAAK,WAAW,GAAG,MAAM,MAAM;GAC9D,IAAI,UAAU,GAAG;IAEf,IAAI,WAAW,GACb,MAAM,KAAK,GAAG,uBAAuB,KAAK,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;IAEvE,MAAM,KAAK;KAAE,MAAM,KAAK,MAAM,UAAU,SAAS,GAAG,IAAI,MAAM;KAAG,MAAM;IAAU,CAAC;IAClF,MAAM,WAAW,aAAa,KAAK,MAAM,SAAS,GAAG,IAAI,MAAM,GAAG,QAAQ,KAAK;IAC/E,MAAM,KAAK,GAAG,SAAS,KAAK;IAC5B,OAAO;KAAE;KAAO,gBAAgB;IAAM;GACxC;GAEA,IAAI,WAAW,GACb,MAAM,KAAK,GAAG,uBAAuB,KAAK,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;GAEvE,MAAM,KAAK;IAAE,MAAM,KAAK,MAAM,QAAQ;IAAG,MAAM;GAAU,CAAC;GAC1D,OAAO;IAAE;IAAO,gBAAgB;GAAK;EACvC;CACF;CAGA,IAAI,OAAO,cACT,KAAK,MAAM,aAAa,OAAO,cAAc;EAC3C,MAAM,QAAQ,UAAU,KAAK,IAAI;EACjC,IAAI,OAAO;GACT,MAAM,eAAe,MAAM;GAC3B,IAAI,eAAe,GACjB,MAAM,KAAK,GAAG,uBAAuB,KAAK,MAAM,GAAG,YAAY,GAAG,MAAM,CAAC;GAE3E,MAAM,KAAK;IAAE,MAAM,KAAK,MAAM,YAAY;IAAG,MAAM;GAAU,CAAC;GAC9D,OAAO;IAAE;IAAO,gBAAgB;GAAM;EACxC;CACF;CAGF,MAAM,KAAK,GAAG,uBAAuB,MAAM,MAAM,CAAC;CAClD,OAAO;EAAE;EAAO,gBAAgB;CAAM;AACxC;AAWA,SAAS,aAAa,GAAW,KAAa,QAAsC;CAClF,IAAI,CAAC,WAAW,EAAE,IAAK,GAAG,OAAO;CAEjC,MAAM,UAAU,YAAY,GAAG,GAAG;CAClC,MAAM,OAAO,EAAE,MAAM,KAAK,OAAO;CACjC,MAAM,YAAY,KAAK,YAAY;CAEnC,MAAM,YAAY,OAAO,SAAS,IAAI,IAAI,KAAK,OAAO,SAAS,IAAI,SAAS;CAC5E,MAAM,SAAS,OAAO,UAAU,OAAO,MAAM,IAAI,IAAI,KAAK,OAAO,MAAM,IAAI,SAAS;CACpF,IAAI,CAAC,aAAa,CAAC,QAAQ,OAAO;CAElC,MAAM,QAAyB,CAAC;CAChC,IAAI,MAAM,GAAG,MAAM,KAAK;EAAE,MAAM,EAAE,MAAM,GAAG,GAAG;EAAG,MAAM;CAAQ,CAAC;CAChE,MAAM,KAAK;EAAE,MAAM;EAAM,MAAM,YAAY,YAAY;CAAO,CAAC;CAE/D,OAAO;EAAE;EAAO,WAAW,EAAE,MAAM,OAAO;CAAE;AAC9C;;AAGA,SAAS,oBAAoB,GAAW,KAA+B;CACrE,MAAM,OAAO,EAAE;CACf,MAAM,UAAU,QAAQ,OAAO,QAAQ;CACvC,MAAM,eACJ,SAAS,OAAO,MAAM,IAAI,EAAE,UAAU,EAAE,MAAM,MAAO,OAAO,EAAE,MAAM,MAAO;CAC7E,IAAI,CAAC,WAAW,CAAC,cAAc,OAAO;CAEtC,MAAM,SAAS,cAAc,GAAG,GAAG;CACnC,IAAI,UAAU,KAAK,OAAO;CAE1B,MAAM,QAAyB,CAAC;CAChC,IAAI,MAAM,GAAG,MAAM,KAAK;EAAE,MAAM,EAAE,MAAM,GAAG,GAAG;EAAG,MAAM;CAAQ,CAAC;CAChE,MAAM,KAAK;EAAE,MAAM,EAAE,MAAM,KAAK,MAAM;EAAG,MAAM;CAAS,CAAC;CAEzD,OAAO;EAAE;EAAO,WAAW,EAAE,MAAM,MAAM;CAAE;AAC7C;;;;AAKA,SAAS,uBAAuB,MAAc,QAAqC;CACjF,MAAM,QAAyB,CAAC;CAChC,IAAI,YAAY;CAChB,IAAI,MAAM;CAEV,OAAO,MAAM,UAAU,QAAQ;EAE7B,MAAM,YAAY,eAAe,SAAS;EAC1C,IAAI,WAAW;GACb,IAAI,MAAM,GAAG,MAAM,KAAK;IAAE,MAAM,UAAU,MAAM,GAAG,GAAG;IAAG,MAAM;GAAQ,CAAC;GACxE,MAAM,KAAK;IAAE,MAAM,UAAU;IAAS,MAAM;GAAS,CAAC;GACtD,YAAY,UAAU;GACtB,MAAM;GACN;EACF;EAGA,MAAM,YAAY,aAAa,WAAW,KAAK,MAAM;EACrD,IAAI,WAAW;GACb,MAAM,KAAK,GAAG,UAAU,KAAK;GAC7B,YAAY,UAAU;GACtB,MAAM;GACN;EACF;EAGA,MAAM,WAAW,oBAAoB,WAAW,GAAG;EACnD,IAAI,UAAU;GACZ,MAAM,KAAK,GAAG,SAAS,KAAK;GAC5B,YAAY,SAAS;GACrB,MAAM;GACN;EACF;EAEA;CACF;CAEA,IAAI,UAAU,SAAS,GACrB,MAAM,KAAK;EAAE,MAAM;EAAW,MAAM;CAAQ,CAAC;CAG/C,OAAO,mBAAmB,KAAK;AACjC;AAIA,SAAS,WAAW,IAAqB;CACvC,OAAO,YAAY,KAAK,EAAE;AAC5B;AAEA,SAAS,YAAY,GAAW,OAAuB;CACrD,IAAI,IAAI;CACR,OAAO,IAAI,EAAE,UAAU,eAAe,KAAK,EAAE,EAAG,GAAG;CACnD,OAAO;AACT;AAEA,SAAS,cAAc,GAAW,OAAuB;CACvD,IAAI,IAAI;CACR,IAAI,EAAE,OAAO,OAAO,IAAI,IAAI,EAAE,WAAW,EAAE,IAAI,OAAO,OAAO,EAAE,IAAI,OAAO,MAAM,KAAK;CACrF,OAAO,IAAI,EAAE,UAAU,gBAAgB,KAAK,EAAE,EAAG,GAAG;CACpD,OAAO;AACT;AAOA,SAAS,eAAe,GAA4B;CAClD,MAAM,aAAa;EAAC;EAAK;EAAK;CAAG;CACjC,MAAM,QAAQ,EAAE;CAChB,IAAI,CAAC,WAAW,SAAS,KAAK,GAAG,OAAO;CAExC,IAAI,IAAI;CACR,OAAO,IAAI,EAAE,QAAQ;EACnB,IAAI,EAAE,OAAO,MAAM;GACjB,KAAK;GACL;EACF;EACA,IAAI,EAAE,OAAO,OAAO,OAAO;GAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;GAAG,WAAW,EAAE,MAAM,IAAI,CAAC;EAAE;EACnF;CACF;CACA,OAAO;AACT;AAEA,SAAS,mBAAmB,OAAyC;CACnE,IAAI,MAAM,UAAU,GAAG,OAAO;CAC9B,MAAM,SAA0B,CAAC;CACjC,IAAI,MAAM,MAAM;CAChB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,OAAO,MAAM;EACnB,IAAI,IAAI,SAAS,KAAK,MACpB,MAAM;GAAE,MAAM,IAAI,OAAO,KAAK;GAAM,MAAM,IAAI;EAAK;OAC9C;GACL,OAAO,KAAK,GAAG;GACf,MAAM;EACR;CACF;CACA,OAAO,KAAK,GAAG;CACf,OAAO;AACT;;;;;;;;AA4BA,SAAgB,mBAAmB,MAAc,UAAsC;CACrF,MAAM,SAAS,cAAc,QAAQ;CACrC,MAAM,QAAQ,KAAK,MAAM,IAAI;CAC7B,MAAM,SAA4B,CAAC;CACnC,IAAI,iBAAiB;CAErB,KAAK,MAAM,QAAQ,OAAO;EAExB,MAAM,QAAQ,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;EAExD,IAAI,MAAM,WAAW,GAAG;GACtB,OAAO,KAAK,CAAC;IAAE,MAAM;IAAI,MAAM;GAAQ,CAAC,CAAC;GACzC;EACF;EAEA,MAAM,EAAE,OAAO,gBAAgB,gBAAgB,aAAa,OAAO,QAAQ,cAAc;EACzF,OAAO,KAAK,KAAK;EACjB,iBAAiB;CACnB;CAEA,OAAO;AACT;;;;;;;;;;AC90BA,MAAM,YAAoC;CACxC,OAAO;CACP,UAAU;CACV,KAAK;CACL,MAAM;CACN,QAAQ;CACR,aAAa;CACb,UAAU;CACV,MAAM;CACN,OAAO;CACP,UAAU;CACV,YAAY;CACZ,eAAe;CACf,SAAS;CACT,qBAAqB;CACrB,kBAAkB;CAClB,uBAAuB;CACvB,8BAA8B;CAC9B,KAAK;CACL,UAAU;CACV,WAAW;CACX,OAAO;CACP,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,cAAc;CACd,KAAK;CACL,KAAK;CACL,OAAO;CACP,MAAM;CACN,SAAS;CACT,QAAQ;CACR,YAAY;CACZ,SAAS;CACT,YAAY;CACZ,QAAQ;CACR,YAAY;CACZ,SAAS;CACT,YAAY;CACZ,MAAM;CACN,YAAY;CACZ,MAAM;CACN,UAAU;CACV,cAAc;CACd,gBAAgB;CAChB,UAAU;CACV,cAAc;CACd,cAAc;CACd,KAAK;CACL,OAAO;CACP,KAAK;CACL,WAAW;CACX,QAAQ;CACR,QAAQ;CAER,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,SAAS;CACT,cAAc;CACd,MAAM;CACN,UAAU;CACV,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,QAAQ;CAER,OAAO;CACP,cAAc;CACd,MAAM;CACN,UAAU;CACV,MAAM;CACN,QAAQ;CACR,MAAM;CACN,OAAO;CACP,GAAG;CACH,SAAS;CACT,MAAM;CACN,UAAU;CACV,MAAM;CACN,MAAM;CACN,QAAQ;CACR,KAAK;CACL,QAAQ;CACR,QAAQ;CACR,MAAM;CACN,MAAM;CACN,MAAM;CACN,QAAQ;CACR,KAAK;CACL,MAAM;CACN,MAAM;CAEN,UAAU;CACV,YAAY;CACZ,YAAY;CACZ,aAAa;CAEb,UAAU;CACV,KAAK;CACL,OAAO;CACP,SAAS;CACT,OAAO;CACP,QAAQ;CAER,KAAK;CACL,OAAO;CACP,MAAM;CACN,MAAM;CACN,KAAK;CAEL,QAAQ;CACR,MAAM;CACN,OAAO;CACP,WAAW;CACX,OAAO;CACP,OAAO;CACP,OAAO;CACP,MAAM;CACN,OAAO;CACP,UAAU;AACZ;;AAGA,MAAM,eAAe;;;;;;;AAQrB,SAAgB,sBAAsB,MAAsB;CAC1D,OAAO,KAAK,QAAQ,eAAe,OAAO,SAAiB;EAEzD,OADc,UAAU,SACR;CAClB,CAAC;AACH;;;;;;;;;;;ACxIA,MAAM,cAAsC;CAC1C,OAAO;CACP,MAAM;CACN,OAAO;CACP,OAAO;CACP,SAAS;CACT,MAAM;CACN,KAAK;CACL,OAAO;CACP,MAAM;CACN,OAAO;CACP,QAAQ;CACR,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,KAAK;CACL,OAAO;CACP,KAAK;CACL,SAAS;CACT,KAAK;CACL,KAAK;CACL,KAAK;CACL,OAAO;AACT;;AAGA,MAAM,cAAsC;CAC1C,OAAO;CACP,OAAO;CACP,OAAO;CACP,QAAQ;CACR,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,KAAK;CACL,KAAK;CACL,OAAO;AACT;;AAGA,MAAM,eAAuC;CAC3C,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,YAAY;CACZ,WAAW;CACX,SAAS;CACT,YAAY;CACZ,YAAY;CACZ,YAAY;CACZ,cAAc;CACd,cAAc;CACd,QAAQ;CACR,WAAW;CACX,YAAY;CACZ,YAAY;CACZ,cAAc;CACd,WAAW;CACX,aAAa;CACb,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,WAAW;CACX,UAAU;CACV,cAAc;CACd,QAAQ;CACR,gBAAgB;CAChB,eAAe;CACf,aAAa;CACb,eAAe;CACf,YAAY;CACZ,gBAAgB;CAChB,eAAe;CACf,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,WAAW;CACX,YAAY;CACZ,WAAW;CACX,WAAW;CACX,WAAW;CACX,WAAW;CACX,UAAU;CACV,YAAY;CACZ,UAAU;CACV,cAAc;CACd,YAAY;CACZ,aAAa;AACf;;;;;AAQA,SAAS,mBAAmB,MAAsB;CAChD,MAAM,QAAgC;EACpC,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,GAAG;EACH,GAAG;CACL;CACA,OAAO,KACJ,QAAQ,mBAAmB,GAAG,SAAiB,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,MAAM,MAAM,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAC5F,QAAQ,YAAY,GAAG,MAAc,MAAM,MAAM,IAAI,GAAG;AAC7D;;;;AAKA,SAAS,iBAAiB,MAAsB;CAC9C,MAAM,MAA8B;EAClC,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;CACL;CACA,OAAO,KACJ,QAAQ,kBAAkB,GAAG,SAAiB,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CACzF,QAAQ,WAAW,GAAG,MAAc,IAAI,MAAM,IAAI,GAAG;AAC1D;;;;;;;;;;;;;AAgBA,SAAgB,kBAAkB,OAAuB;CACvD,IAAI,SAAS;CAGb,SAAS,OAAO,QAAQ,+BAA+B,WAAW;CAGlE,MAAM,gBAAgB,OAAO,QAAQ,YAAY,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,MAAM;CAC3F,KAAK,MAAM,CAAC,KAAK,QAAQ,eACvB,SAAS,OAAO,WAAW,KAAK,GAAG;CAIrC,KAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,WAAW,GAClD,SAAS,OAAO,QAAQ,KAAK,QAAQ,GAAG;CAI1C,KAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,WAAW,GAClD,SAAS,OAAO,QAAQ,KAAK,QAAQ,GAAG;CAI1C,SAAS,mBAAmB,MAAM;CAClC,SAAS,iBAAiB,MAAM;CAEhC,OAAO;AACT;;;;;;;AAQA,SAAgB,cAAc,MAAuB;CACnD,OAAO,KAAK,SAAS,IAAI,KAAK,OAAO,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI;AACnE;;;;;;;;;;;;;;;;;;;;;;ACvJA,SAAS,YAAY,MAA+B;CAClD,MAAM,WAA4B,CAAC;CAGnC,MAAM,UAAU;CAEhB,IAAI,YAAY;CAChB,IAAI;CAEJ,QAAQ,QAAQ,QAAQ,KAAK,IAAI,OAAO,MAAM;EAE5C,IAAI,MAAM,QAAQ,WAChB,SAAS,KAAK,EAAE,MAAM,KAAK,MAAM,WAAW,MAAM,KAAK,EAAE,CAAC;EAG5D,IAAI,MAAM,IAER,SAAS,KAAK;GAAE,MAAM,MAAM;GAAK,MAAM;EAAK,CAAC;OACxC,IAAI,MAAM,IAEf,SAAS,KAAK;GAAE,MAAM,MAAM;GAAK,QAAQ;EAAK,CAAC;OAC1C,IAAI,MAAM,IAEf,SAAS,KAAK;GAAE,MAAM,MAAM;GAAK,eAAe;EAAK,CAAC;OACjD,IAAI,MAAM,IAEf,SAAS,KAAK;GAAE,MAAM,MAAM;GAAK,MAAM;EAAK,CAAC;OACxC,IAAI,MAAM,IAEf,SAAS,KAAK;GAAE,MAAM,MAAM;GAAM,MAAM,MAAM;EAAK,CAAC;EAGtD,YAAY,MAAM,QAAQ,MAAM,EAAE,CAAC;CACrC;CAGA,IAAI,YAAY,KAAK,QACnB,SAAS,KAAK,EAAE,MAAM,KAAK,MAAM,SAAS,EAAE,CAAC;CAI/C,IAAI,SAAS,WAAW,GACtB,SAAS,KAAK,EAAE,KAAK,CAAC;CAGxB,OAAO;AACT;;;;;;;AAQA,SAAgB,aAAa,MAAyB;CAGpD,MAAM,WAAW,YADA,sBAAsB,IACH,CAAC;CAErC,IAAI,SAAS,WAAW,KAAK,CAAC,SAAS,EAAE,CAAE,QAAQ,CAAC,SAAS,EAAE,CAAE,UAAU,CAAC,SAAS,EAAE,CAAE,MAEvF,OAAO,SAAS,EAAE,CAAE;CAGtB,OAAO,SAAS,KAAK,KAAK,MAAM;EAC9B,MAAM,QAAiC,EAAE,KAAK,OAAO,IAAI;EAEzD,IAAI,IAAI,MAAM,MAAM,OAAO;EAC3B,IAAI,IAAI,QAAQ,MAAM,SAAS;EAC/B,IAAI,IAAI,eAAe,MAAM,gBAAgB;EAC7C,IAAI,IAAI,MAAM,MAAM,WAAW;EAC/B,IAAI,IAAI,MAAM;GACZ,MAAM,YAAY;GAClB,MAAM,QAAQ;GAGd,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,WAAW,aAAa,GAChD,OAAO,MAAM,cAAc,MAAM,OAAO,SAAS,IAAI,MAAM,IAAI,IAAI,CAAC;EAExE;EAEA,OAAO,MAAM,cAAc,MAAM,OAAO,IAAI,IAAI;CAClD,CAAC;AACH;;;;;;;;;;AAaA,SAAS,SAAS,KAAa,MAAsB;CACnD,OAAO,WAAW,IAAI,QAAQ,KAAK;AACrC;;AAKA,SAAS,UAAU,MAAiD;CAClE,QAAQ,MAAR;EACE,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,SACH;EACF,SACE;CACJ;AACF;;AA4BA,SAAS,mBAAmB,SAAgD;CAC1E,IACE,QAAQ,WAAW,MAAM,KACzB,QAAQ,WAAW,MAAM,KACzB,QAAQ,WAAW,YAAY,KAC/B,QAAQ,WAAW,QAAQ,GAE3B,OAAO;CAET,IAAI,QAAQ,WAAW,IAAI,GAAG,OAAO;CACrC,IAAI,QAAQ,WAAW,GAAG,GAAG,OAAO;CACpC,IAAI,QAAQ,WAAW,GAAG,GAAG,OAAO;CACpC,OAAO;AACT;;AAGA,SAAS,WAAW,SAAiB,UAA4B;CAC/D,IAAI,QAAQ,WAAW,MAAM,KAAK,QAAQ,WAAW,MAAM,GAAG,OAAO;CACrE,IAAI,UAAU,KAAK,OAAO,GAAG,OAAO;CACpC,IACE,aACC,SAAS,WAAW,MAAM,KAAK,SAAS,WAAW,MAAM,KAAK,UAAU,KAAK,QAAQ,IAEtF,OAAO,QAAQ,WAAW,GAAG,KAAK,QAAQ,WAAW,GAAG;CAE1D,OAAO,QAAQ,WAAW,YAAY,KAAK,QAAQ,WAAW,QAAQ;AACxE;;AAGA,SAAS,gBAAgB,SAAuC;CAC9D,MAAM,QAAQ,mBAAmB,KAAK,OAAO;CAC7C,IAAI,CAAC,OAAO,OAAO;CACnB,OAAO;EAAE,MAAM;EAAW,OAAO,MAAM,EAAE,CAAE;EAAQ,MAAM,MAAM;CAAI;AACrE;;AAGA,SAAS,iBAAiB,SAA0B;CAClD,OAAO,4BAA4B,KAAK,OAAO;AACjD;;AAGA,SAAS,WAAW,MAAuB;CACzC,MAAM,UAAU,KAAK,KAAK;CAC1B,OAAO,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG;AACxD;;AAGA,SAAS,iBAAiB,MAAuB;CAC/C,OAAO,eAAe,KAAK,KAAK,KAAK,CAAC,KAAK,aAAa,KAAK,KAAK,KAAK,CAAC;AAC1E;;;;;AAMA,SAAS,WAAW,MAA2C;CAC7D,MAAM,UAAU,KAAK,KAAK;CAC1B,MAAM,OAAO,QAAQ,WAAW,GAAG;CACnC,MAAM,QAAQ,QAAQ,SAAS,GAAG;CAClC,IAAI,QAAQ,OAAO,OAAO;CAC1B,IAAI,OAAO,OAAO;CAClB,OAAO;AACT;;AAGA,SAAS,WAAW,YAA4C;CAC9D,IAAI,WAAW,SAAS,GAAG,OAAO;CAClC,MAAM,aAAa,WAAW;CAC9B,MAAM,UAAU,WAAW;CAC3B,IAAI,CAAC,iBAAiB,OAAO,GAAG,OAAO;CAEvC,MAAM,UAAU,gBAAgB,UAAU;CAE1C,MAAM,SADW,gBAAgB,OACX,CAAC,CAAC,IAAI,UAAU;CAEtC,MAAM,OAAmB,CAAC;CAC1B,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,QAAQ,KACrC,KAAK,KAAK,gBAAgB,WAAW,EAAG,CAAC;CAG3C,OAAO;EACL,MAAM;EACN,MAAM,WAAW,KAAK,IAAI;EAC1B,cAAc;EACd,WAAW;EACX,aAAa;CACf;AACF;;AAGA,SAAS,gBAAgB,KAAuB;CAC9C,OAAO,IACJ,KAAK,CAAC,CACN,QAAQ,OAAO,EAAE,CAAC,CAClB,QAAQ,OAAO,EAAE,CAAC,CAClB,MAAM,GAAG,CAAC,CACV,KAAK,MAAM,EAAE,KAAK,CAAC;AACxB;;AAGA,SAAS,iBAAiB,MAAoC;CAC5D,MAAM,UAAU,KAAK,KAAK;CAC1B,MAAM,SAAS,KAAK,SAAS,KAAK,UAAU,CAAC,CAAC;CAC9C,MAAM,cAAc,KAAK,MAAM,SAAS,CAAC;CAGzC,MAAM,YAAY,8BAA8B,KAAK,OAAO;CAC5D,IAAI,WACF,OAAO;EACL,MAAM;EACN,MAAM,UAAU;EAChB,SAAS,UAAU,EAAE,CAAE,YAAY,MAAM;EACzC;CACF;CAGF,IAAI,YAAY,KAAK,OAAO,GAC1B,OAAO;EACL,MAAM;EACN,MAAM,QAAQ,QAAQ,aAAa,EAAE;EACrC;CACF;CAEF,MAAM,eAAe,kBAAkB,KAAK,OAAO;CACnD,IAAI,cACF,OAAO;EACL,MAAM;EACN,MAAM,aAAa;EACnB,YAAY,OAAO,SAAS,aAAa,IAAK,EAAE;EAChD;CACF;CAEF,OAAO;AACT;;AAoBA,SAAS,oBAAoB,WAAqB,QAA+B;CAC/E,MAAM,OAAO,UAAU,KAAK,IAAI,CAAC,CAAC,KAAK;CACvC,IAAI,MAAM,OAAO,KAAK;EAAE,MAAM;EAAa;CAAK,CAAC;CACjD,UAAU,SAAS;AACrB;;AAGA,SAAS,eAAe,WAAqB,QAAyB,UAAwB;CAC5F,IAAI,UAAU,SAAS,GAAG;EACxB,OAAO,KAAK;GAAE,MAAM;GAAQ,MAAM,UAAU,KAAK,IAAI;GAAG,UAAU,YAAY,KAAA;EAAU,CAAC;EACzF,UAAU,SAAS;CACrB;AACF;;AAGA,SAAS,gBAAgB,YAAsB,QAA+B;CAC5E,IAAI,WAAW,SAAS,GAAG;EACzB,OAAO,KAAK;GAAE,MAAM;GAAc,MAAM,WAAW,KAAK,IAAI;EAAE,CAAC;EAC/D,WAAW,SAAS;CACtB;AACF;;;;;AAMA,SAAS,wBACP,KACA,SACA,OACA,QACS;CACT,IAAI,QAAQ,WAAW,KAAK,GAAG;EAC7B,oBAAoB,MAAM,WAAW,MAAM;EAC3C,gBAAgB,MAAM,YAAY,MAAM;EACxC,IAAI,MAAM,aAAa;GACrB,eAAe,MAAM,WAAW,QAAQ,MAAM,YAAY;GAC1D,MAAM,cAAc;GACpB,MAAM,eAAe;EACvB,OAAO;GACL,MAAM,eAAe,QAAQ,MAAM,CAAC,CAAC,CAAC,KAAK;GAC3C,MAAM,cAAc;EACtB;EACA,OAAO;CACT;CACA,IAAI,MAAM,aAAa;EACrB,MAAM,UAAU,KAAK,GAAG;EACxB,OAAO;CACT;CAEA,IAAI,QAAQ,WAAW,IAAI,GAAG;EAC5B,oBAAoB,MAAM,WAAW,MAAM;EAC3C,MAAM,eAAe;EACrB,MAAM,WAAW,KAAK,QAAQ,MAAM,CAAC,CAAC;EACtC,OAAO;CACT;CACA,IAAI,MAAM,cAAc;EACtB,gBAAgB,MAAM,YAAY,MAAM;EACxC,MAAM,eAAe;CACvB;CACA,OAAO;AACT;;;;;AAMA,SAAS,mBACP,KACA,aACA,OACA,QACS;CACT,MAAM,UAAU,IAAI,KAAK;CAEzB,IAAI,WAAW,SADC,MAAM,SAAS,cAAc,EACd,GAAG;EAChC,IAAI,CAAC,MAAM,QAAQ,oBAAoB,MAAM,WAAW,MAAM;EAC9D,MAAM,SAAS;EACf,MAAM,UAAU,KAAK;GAAE,MAAM;GAAQ,MAAM;GAAK,cAAc,mBAAmB,OAAO;EAAE,CAAC;EAC3F,OAAO;CACT;CACA,IAAI,MAAM,UAAU,YAAY,MAAM,CAAC,WAAW,OAAO,GAAG;EAC1D,OAAO,KAAK,GAAG,MAAM,SAAS;EAC9B,MAAM,YAAY,CAAC;EACnB,MAAM,SAAS;CACjB;CACA,OAAO;AACT;;;;;AAMA,SAAS,0BACP,SACA,OACA,QACS;CACT,MAAM,UAAU,gBAAgB,OAAO;CACvC,IAAI,SAAS;EACX,oBAAoB,MAAM,WAAW,MAAM;EAC3C,OAAO,KAAK,OAAO;EACnB,OAAO;CACT;CACA,IAAI,iBAAiB,OAAO,GAAG;EAC7B,oBAAoB,MAAM,WAAW,MAAM;EAC3C,OAAO,KAAK;GAAE,MAAM;GAAM,MAAM;EAAG,CAAC;EACpC,OAAO;CACT;CACA,MAAM,WAAW,iBAAiB,OAAO;CACzC,IAAI,UAAU;EACZ,oBAAoB,MAAM,WAAW,MAAM;EAC3C,OAAO,KAAK,QAAQ;EACpB,OAAO;CACT;CACA,OAAO;AACT;;;;;;;AAQA,SAAS,oBACP,KACA,KACA,OACA,OACA,QACS;CACT,MAAM,UAAU,IAAI,KAAK;CAGzB,IAAI,CAAC,WAAW,OAAO,KAAK,CAAC,MAAM,SAAS,OAAO;CAEnD,IAAI,WAAW,OAAO,GAAG;EAGvB,IAAI,iBADa,MAAM,IAAI,MAAM,SAAS,MAAM,MAAM,EAAE,CAAE,KAAK,IAAI,EACtC,GAAG;GAE9B,oBAAoB,MAAM,WAAW,MAAM;GAC3C,IAAI,MAAM,SAAS;IACjB,MAAM,UAAU,WAAW,MAAM,UAAU;IAC3C,IAAI,SAAS,OAAO,KAAK,OAAO;IAChC,MAAM,aAAa,CAAC;GACtB;GACA,MAAM,UAAU;GAChB,MAAM,WAAW,KAAK,GAAG;GACzB,OAAO;EACT;EAEA,IAAI,MAAM,SAAS;GACjB,MAAM,WAAW,KAAK,GAAG;GACzB,OAAO;EACT;EAEA,OAAO;CACT;CAGA,IAAI,MAAM,WAAW,CAAC,WAAW,OAAO,GAAG;EACzC,MAAM,UAAU,WAAW,MAAM,UAAU;EAC3C,IAAI,SAAS,OAAO,KAAK,OAAO;EAChC,MAAM,aAAa,CAAC;EACpB,MAAM,UAAU;CAClB;CACA,OAAO;AACT;;;;;;;AAQA,SAAS,mBAAmB,IAAoB;CAE9C,IAAI,SAAS,sBAAsB,EAAE;CAGrC,SAAS,OAAO,QAAQ,wBAAwB,OAAe,SAAiB;EAE9E,OAAO,eADQ,kBAAkB,KAAK,KAAK,CAChB,EAAE;CAC/B,CAAC;CAGD,SAAS,OAAO,QAAQ,oBAAoB,OAAe,SAAiB;EAC1E,IAAI,cAAc,IAAI,GAAG,OAAO,kBAAkB,IAAI;EACtD,OAAO;CACT,CAAC;CAED,OAAO;AACT;;AAGA,SAAgB,cAAc,IAAY,OAAsB,CAAC,GAAoB;CACnF,MAAM,EAAE,aAAa,UAAU;CAG/B,MAAM,QADe,mBAAmB,EACf,CAAC,CAAC,MAAM,IAAI;CACrC,MAAM,SAA0B,CAAC;CAEjC,MAAM,QAAoB;EACxB,aAAa;EACb,cAAc;EACd,WAAW,CAAC;EACZ,cAAc;EACd,YAAY,CAAC;EACb,QAAQ;EACR,WAAW,CAAC;EACZ,WAAW,CAAC;EACZ,YAAY,CAAC;EACb,SAAS;CACX;CAEA,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,MAAM,MAAM;EAClB,MAAM,UAAU,IAAI,KAAK;EAIzB,IAAI,oBAAoB,KAAK,GAAG,OAAO,OAAO,MAAM,GAAG;EAEvD,IAAI,wBAAwB,KAAK,SAAS,OAAO,MAAM,GAAG;EAE1D,IAAI,mBAAmB,KADH,IAAI,IAAI,MAAM,IAAI,EAAE,CAAE,KAAK,IAAI,IACV,OAAO,MAAM,GAAG;EACzD,IAAI,0BAA0B,SAAS,OAAO,MAAM,GAAG;EACvD,IAAI,YAAY,IAAI;GAClB,oBAAoB,MAAM,WAAW,MAAM;GAC3C;EACF;EAEA,MAAM,UAAU,KAAK,OAAO;CAC9B;CAGA,IAAI,EAAE,MAAM,eAAe,aACzB,eAAe,MAAM,WAAW,QAAQ,MAAM,YAAY;CAC5D,gBAAgB,MAAM,YAAY,MAAM;CACxC,IAAI,MAAM,UAAU,SAAS,GAAG,OAAO,KAAK,GAAG,MAAM,SAAS;CAC9D,IAAI,MAAM,SAAS;EACjB,MAAM,UAAU,WAAW,MAAM,UAAU;EAC3C,IAAI,SAAS,OAAO,KAAK,OAAO;CAClC;CACA,oBAAoB,MAAM,WAAW,MAAM;CAE3C,OAAO;AACT;;;;;;AAOA,SAAgB,iBAAiB,MAAsB;CACrD,MAAM,aAAa,KAAK,YAAY,MAAM;CAC1C,IAAI,aAAa,GAAG,OAAO;CAG3B,KADoB,KAAK,MAAM,MAAM,KAAK,CAAC,EAAA,CAAG,SAC7B,MAAM,GAAG;EACxB,MAAM,YAAY,KAAK,YAAY,KAAK;EACxC,IAAI,YAAY,GAAG,OAAO;EAC1B,OAAO;CACT;CAEA,OAAO,aAAa;AACtB;;AAKA,SAAS,aAAa,cAA+B;CACnD,QAAQ,cAAR;EACE,KAAK,UACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,SACE,OAAO;CACX;AACF;;AAGA,SAAS,mBAAmB,OAAsB,GAAsB;CACtE,MAAM,QAAQ,MAAM,UAAU,IAAI,SAAS,MAAM,UAAU,IAAI,WAAW;CAC1E,OAAO,MAAM,cAAc,MAAM;EAAE,KAAK,KAAK;EAAK,MAAM;EAAM;CAAM,GAAG,aAAa,MAAM,IAAI,CAAC;AACjG;;AAGA,SAAS,gBAAgB,OAAsB,GAAsB;CACnE,MAAM,iBAAiB,mBAAmB,MAAM,MAAM,MAAM,QAAQ;CACpE,MAAM,WAAwB,CAAC;CAE/B,IAAI,MAAM,UACR,SAAS,KACP,MAAM,cAAc,MAAM;EAAE,KAAK;EAAQ,MAAM;EAAM,OAAO;CAAO,GAAG,IAAI,MAAM,SAAS,EAAE,CAC7F;CAGF,KAAK,IAAI,KAAK,GAAG,KAAK,eAAe,QAAQ,MAAM;EACjD,MAAM,QAAQ,eAAe;EAE7B,IAAI,MAAM,WAAW,KAAK,MAAM,EAAE,CAAE,SAAS,SAAS;GACpD,SAAS,KAAK,MAAM,cAAc,MAAM,EAAE,KAAK,MAAM,KAAK,GAAG,MAAM,EAAE,CAAE,IAAI,CAAC;GAC5E;EACF;EACA,MAAM,eAAe,MAClB,QAAQ,MAAM,EAAE,SAAS,EAAE,CAAC,CAC5B,KAAK,MAAM,OAAO;GACjB,MAAM,QAAQ,UAAU,KAAK,IAAI;GACjC,MAAM,QAAiC,EAAE,KAAK,MAAM,GAAG,GAAG,KAAK;GAC/D,IAAI,KAAK,SAAS,aAAa,KAAK,SAAS,QAAQ,MAAM,OAAO;GAClE,IAAI,KAAK,SAAS,WAAW,MAAM,WAAW;GAC9C,IAAI,OAAO,MAAM,QAAQ;GACzB,OAAO,MAAM,cAAc,MAAM,OAAO,KAAK,IAAI;EACnD,CAAC;EACH,SAAS,KAAK,MAAM,cAAc,MAAM,EAAE,KAAK,MAAM,KAAK,GAAG,GAAG,YAAY,CAAC;CAC/E;CAEA,OAAO,MAAM,cACX,KACA;EAAE,KAAK,QAAQ;EAAK,eAAe;CAAS,GAC5C,MAAM,cACJ,KACA;EACE,aAAa;EACb,aAAa;EACb,UAAU;EACV,eAAe;CACjB,GACA,GAAG,QACL,CACF;AACF;;AAGA,SAAS,sBAAsB,OAAsB,GAAsB;CACzE,OAAO,MAAM,cAAc,MAAM;EAAE,KAAK,KAAK;EAAK,OAAO;CAAO,GAAG,KAAK,MAAM,MAAM;AACtF;;AAGA,SAAS,oBAAoB,OAAsB,GAAsB;CACvE,MAAM,YAAY,MAAM,cAAc,KAAK,OAAO,MAAM,WAAW,IAAI;CAGvE,IAAI,MAAM,YAAY,KAAA,GAAW;EAC/B,MAAM,WAAW,MAAM,UAAU,MAAM;EACvC,MAAM,QAAQ,MAAM,UAAU,UAAU;EACxC,OAAO,MAAM,cACX,MACA,EAAE,KAAK,MAAM,IAAI,GACjB,WACA,MAAM,cAAc,MAAM,EAAE,OAAO,SAAS,GAAG,IAAI,GACnD,MAAM,cAAc,MAAM,EAAE,MAAM,GAAG,GAAG,SAAS,EAAE,GACnD,MAAM,cACJ,MACA,MAAM,UAAU;GAAE,eAAe;GAAM,UAAU;GAAM,OAAO;EAAQ,IAAI,CAAC,GAC3E,aAAa,MAAM,IAAI,CACzB,CACF;CACF;CAGA,MAAM,SAAS,MAAM,aAAa,GAAG,MAAM,WAAW,MAAM;CAC5D,OAAO,MAAM,cACX,MACA,EAAE,KAAK,MAAM,IAAI,GACjB,WACA,MAAM,cAAc,MAAM,EAAE,OAAO,SAAS,GAAG,MAAM,GACrD,MAAM,cAAc,MAAM,EAAE,OAAO,QAAQ,GAAG,aAAa,MAAM,IAAI,CAAC,CACxE;AACF;;AAGA,SAAS,gBAAgB,OAAsB,GAAsB;CACnE,OAAO,MAAM,cACX,MACA;EAAE,KAAK,KAAK;EAAK,OAAO,aAAa,MAAM,YAAY;CAAE,GACzD,MAAM,IACR;AACF;;AAGA,SAAS,cAAc,GAAsB;CAC3C,OAAO,MAAM,cAAc,MAAM;EAAE,KAAK,MAAM;EAAK,UAAU;CAAK,GAAG,kBAAkB;AACzF;;;;;;;AAQA,SAAS,iBAAiB,OAAsB,GAAsB;CACpE,MAAM,UAAU,MAAM,gBAAgB,CAAC;CACvC,MAAM,OAAO,MAAM,aAAa,CAAC;CACjC,MAAM,SAAS,MAAM,eAAe,CAAC;CACrC,MAAM,UAAU,CAAC,SAAS,GAAG,IAAI;CAGjC,MAAM,WAAW,KAAK,IAAI,QAAQ,QAAQ,GAAG,KAAK,KAAK,MAAM,EAAE,MAAM,GAAG,CAAC;CACzE,MAAM,SAAmB,IAAI,MAAM,QAAQ,CAAC,CAAC,KAAK,CAAC;CACnD,KAAK,MAAM,OAAO,SAChB,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAC5B,OAAO,KAAK,KAAK,IAAI,OAAO,MAAM,IAAI,IAAI,MAAM,GAAA,CAAI,MAAM;CAK9D,SAAS,QAAQ,MAAc,KAAqB;EAClD,MAAM,IAAI,OAAO,QAAQ;EACzB,MAAM,QAAQ,OAAO,QAAQ;EAC7B,IAAI,UAAU,SAAS,OAAO,KAAK,SAAS,CAAC;EAC7C,IAAI,UAAU,UAAU;GACtB,MAAM,OAAO,KAAK,OAAO,IAAI,KAAK,UAAU,CAAC;GAC7C,OAAO,IAAI,OAAO,IAAI,IAAI,OAAO,IAAI,OAAO,IAAI,KAAK,SAAS,IAAI;EACpE;EACA,OAAO,KAAK,OAAO,CAAC;CACtB;CAEA,MAAM,MAAM;CACZ,MAAM,WAAwB,CAAC;CAG/B,MAAM,cAA2B,CAAC;CAClC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;EACjC,YAAY,KACV,MAAM,cAAc,MAAM;GAAE,KAAK,MAAM;GAAK,MAAM;EAAK,GAAG,QAAQ,QAAQ,MAAM,IAAI,CAAC,CAAC,CACxF;EACA,IAAI,IAAI,WAAW,GACjB,YAAY,KAAK,MAAM,cAAc,MAAM;GAAE,KAAK,SAAS;GAAK,OAAO;EAAI,GAAG,KAAK,CAAC;CAExF;CACA,SAAS,KAAK,MAAM,cAAc,KAAK;EAAE,KAAK;EAAS,eAAe;CAAM,GAAG,GAAG,WAAW,CAAC;CAG9F,SAAS,KACP,MAAM,cACJ,MACA;EAAE,KAAK;EAAQ,OAAO;CAAI,GAC1B,IAAI,OAAO,OAAO,QAAQ,GAAG,MAAM,IAAI,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,CACnE,CACF;CAGA,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;EACjB,MAAM,QAAqB,CAAC;EAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;GACjC,MAAM,KAAK,MAAM,cAAc,MAAM,EAAE,KAAK,MAAM,EAAE,GAAG,IAAI,GAAG,QAAQ,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC;GACvF,IAAI,IAAI,WAAW,GACjB,MAAM,KAAK,MAAM,cAAc,MAAM;IAAE,KAAK,OAAO,EAAE,GAAG;IAAK,OAAO;GAAI,GAAG,KAAK,CAAC;EAErF;EACA,SAAS,KAAK,MAAM,cAAc,KAAK;GAAE,KAAK,MAAM;GAAK,eAAe;EAAM,GAAG,GAAG,KAAK,CAAC;CAC5F;CAEA,OAAO,MAAM,cACX,KACA;EAAE,KAAK,SAAS;EAAK,eAAe;EAAU,UAAU;CAAE,GAC1D,MAAM,cACJ,KACA;EACE,aAAa;EACb,aAAa;EACb,UAAU;EACV,eAAe;CACjB,GACA,GAAG,QACL,CACF;AACF;;AAGA,SAAS,qBAAqB,OAAsB,GAAsB;CACxE,OAAO,MAAM,cAAc,MAAM,EAAE,KAAK,KAAK,IAAI,GAAG,aAAa,MAAM,IAAI,CAAC;AAC9E;;;;;;;;AASA,SAAgB,aAAa,QAAoC;CAC/D,MAAM,WAAwB,CAAC;CAE/B,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,QAAQ,OAAO;EAErB,QAAQ,MAAM,MAAd;GACE,KAAK;IACH,SAAS,KAAK,mBAAmB,OAAO,CAAC,CAAC;IAC1C;GACF,KAAK;IACH,SAAS,KAAK,gBAAgB,OAAO,CAAC,CAAC;IACvC;GACF,KAAK;IACH,SAAS,KAAK,sBAAsB,OAAO,CAAC,CAAC;IAC7C;GACF,KAAK;IACH,SAAS,KAAK,oBAAoB,OAAO,CAAC,CAAC;IAC3C;GACF,KAAK;IACH,SAAS,KAAK,gBAAgB,OAAO,CAAC,CAAC;IACvC;GACF,KAAK;IACH,SAAS,KAAK,cAAc,CAAC,CAAC;IAC9B;GACF,KAAK;IACH,SAAS,KAAK,iBAAiB,OAAO,CAAC,CAAC;IACxC;GACF,SACE,SAAS,KAAK,qBAAqB,OAAO,CAAC,CAAC;EAChD;CACF;CAEA,IAAI,SAAS,WAAW,GACtB,OAAO,MAAM,cAAc,MAAM,MAAM,EAAE;CAG3C,OAAO,MAAM,cAAc,KAAK,EAAE,eAAe,SAAS,GAAG,GAAG,QAAQ;AAC1E;;;;;;;;;;;;;;;;;;;;AC7wBA,SAAS,OAAO,OAA6B;CAC3C,OAAO,MAAM,MAAM;AACrB;AAEA,SAAS,MACP,OACA,MACA,MACA,OACc;CACd,OAAO;EAAE,IAAI,OAAO,KAAK;EAAG;EAAM;EAAM,WAAW,KAAK,IAAI;EAAG,GAAG;CAAM;AAC1E;AAIA,SAAS,gBACP,OACA,MACA,OACc;CACd,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,QAAQ,KAAK,MAAM,OAAO,UAAU,MAAM,EAAE,OAAO,SAAS,OAAO,CAAC,CAAC;CACrE,OAAO;EAAE;EAAS,QAAQ,MAAM,SAAS;CAAE;AAC7C;AAEA,SAAS,cAAc,OAAqB,MAAc,SAAiC;CACzF,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,QAAQ,KAAK,MAAM,OAAO,QAAQ,MAAM,EAAE,SAAS,WAAW,MAAM,CAAC,CAAC;CACtE,OAAO;EAAE;EAAS,QAAQ,MAAM,SAAS;CAAE;AAC7C;AAEA,SAAS,wBAAwB,OAAmC;CAClE,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,KAAK,IAAI,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KACvC,IAAI,QAAQ,EAAE,CAAE,SAAS,UAAU,QAAQ,EAAE,CAAE,SAAS;EACtD,QAAQ,KAAK;GAAE,GAAG,QAAQ;GAAK,SAAS;EAAM;EAC9C;CACF;CAEF,OAAO;EAAE;EAAS,QAAQ,MAAM;CAAO;AACzC;AAEA,SAAS,sBAAsB,OAAmC;CAChE,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,MAAM,MAAM,QAAQ,eAAe,MAAM,EAAE,SAAS,UAAU,EAAE,OAAO;CACvE,IAAI,QAAQ,IAAI,QAAQ,OAAO,KAAK,CAAC;CACrC,OAAO;EAAE;EAAS,QAAQ,MAAM;CAAO;AACzC;AAEA,SAAS,qBAAqB,OAAqB,MAA6B;CAC9E,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,MAAM,WAAW,QAAQ,eAAe,MAAM,EAAE,SAAS,eAAe,EAAE,SAAS;CACnF,MAAM,WAAW,MAAM,OAAO,aAAa,QAAQ,IAAI,EAAE,WAAW,KAAK,CAAC;CAC1E,IAAI,aAAa,IAAI;EACnB,QAAQ,YAAY;EACpB,OAAO;GAAE;GAAS,QAAQ,MAAM;EAAO;CACzC;CACA,QAAQ,KAAK,QAAQ;CACrB,OAAO;EAAE;EAAS,QAAQ,MAAM,SAAS;CAAE;AAC7C;AAEA,SAAS,sBAAsB,OAAqB,MAA4B;CAC9E,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,KAAK,IAAI,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KACvC,IAAI,QAAQ,EAAE,CAAE,SAAS,eAAe,QAAQ,EAAE,CAAE,WAAW;EAC7D,QAAQ,KAAK;GAAE,GAAG,QAAQ;GAAK,MAAM,QAAQ,EAAE,CAAE,OAAO;EAAK;EAC7D;CACF;CAEF,OAAO;EAAE;EAAS,QAAQ,MAAM;CAAO;AACzC;AAEA,SAAS,wBAAwB,OAAqB,MAA6B;CACjF,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,KAAK,IAAI,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KACvC,IAAI,QAAQ,EAAE,CAAE,SAAS,eAAe,QAAQ,EAAE,CAAE,WAAW;EAC7D,QAAQ,KAAK;GAAE,GAAG,QAAQ;GAAK,MAAM,QAAQ,QAAQ,EAAE,CAAE;GAAM,WAAW;EAAM;EAChF;CACF;CAEF,OAAO;EAAE;EAAS,QAAQ,MAAM;CAAO;AACzC;AAEA,SAAS,oBAAoB,OAAmC;CAC9D,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,MAAM,MAAM,QAAQ,eAAe,MAAM,EAAE,SAAS,eAAe,EAAE,SAAS;CAC9E,IAAI,QAAQ,IAAI,QAAQ,OAAO,KAAK,CAAC;CACrC,OAAO;EAAE;EAAS,QAAQ,MAAM;CAAO;AACzC;AAEA,SAAS,cAAc,OAAqB,MAAc,QAA8B;CACtF,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,QAAQ,KACN,MAAM,OAAO,YAAY,MAAM;EAC7B,UAAU;EACV,YAAY;EACZ,eAAe,KAAK,IAAI;CAC1B,CAAC,CACH;CACA,OAAO;EAAE;EAAS,QAAQ,MAAM,SAAS;CAAE;AAC7C;AAEA,SAAS,uBAAuB,OAAqB,QAAgB,QAA8B;CACjG,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,IAAI,SAAS,MAAM;CACnB,KAAK,IAAI,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KAAK;EAC5C,MAAM,IAAI,QAAQ;EAClB,IAAI,EAAE,SAAS,cAAc,EAAE,eAAe,QAAQ;GACpD,MAAM,WAAW,EAAE,kBAAkB,KAAK,IAAI,IAAI,EAAE,iBAAiB,IAAA,CAAM,QAAQ,CAAC,IAAI;GAExF,QAAQ,KAAK;IACX,GAAG;IACH,MAAM,GAAG,EAAE,YAAY,OAAO,KAAK,SAAS;GAC9C;GAEA,QAAQ,KAAK,MAAM,OAAO,eAAe,QAAQ,EAAE,YAAY,OAAO,CAAC,CAAC;GACxE;GACA;EACF;CACF;CACA,OAAO;EAAE;EAAS;CAAO;AAC3B;AAEA,SAAS,cAAc,OAAqB,MAA4B;CACtE,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,MAAM,WAAW,QAAQ,eAAe,MAAM,EAAE,SAAS,KAAK;CAC9D,IAAI,aAAa,IAAI,QAAQ,OAAO,UAAU,CAAC;CAC/C,QAAQ,KAAK,MAAM,OAAO,OAAO,IAAI,CAAC;CACtC,OAAO;EAAE;EAAS,QAAQ,MAAM,SAAS;CAAE;AAC7C;AAEA,SAAS,iBAAiB,OAAmC;CAC3D,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,MAAM,MAAM,QAAQ,eAAe,MAAM,EAAE,SAAS,KAAK;CACzD,IAAI,QAAQ,IAAI,QAAQ,OAAO,KAAK,CAAC;CACrC,OAAO;EAAE;EAAS,QAAQ,MAAM;CAAO;AACzC;AAEA,SAAS,mBAAmB,OAAqB,MAAc,YAAkC;CAC/F,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,QAAQ,KAAK,MAAM,OAAO,YAAY,MAAM,EAAE,WAAW,CAAC,CAAC;CAC3D,OAAO;EAAE;EAAS,QAAQ,MAAM,SAAS;CAAE;AAC7C;AAEA,SAAS,sBAAsB,OAAmC;CAChE,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,MAAM,MAAM,QAAQ,eAAe,MAAM,EAAE,SAAS,UAAU;CAC9D,IAAI,QAAQ,IAAI,QAAQ,OAAO,KAAK,CAAC;CACrC,OAAO;EAAE;EAAS,QAAQ,MAAM;CAAO;AACzC;AAEA,SAAS,iBAA+B;CACtC,OAAO;EAAE,SAAS,CAAC;EAAG,QAAQ;CAAE;AAClC;;AAGA,SAAgB,eAAe,OAAqB,QAAqC;CACvF,QAAQ,OAAO,MAAf;EACE,KAAK,cACH,OAAO,gBAAgB,OAAO,OAAO,MAAM,OAAO,KAAK;EACzD,KAAK,YACH,OAAO,cAAc,OAAO,OAAO,MAAM,OAAO,OAAO;EACzD,KAAK,uBACH,OAAO,wBAAwB,KAAK;EACtC,KAAK,qBACH,OAAO,sBAAsB,KAAK;EACpC,KAAK,mBACH,OAAO,qBAAqB,OAAO,OAAO,IAAI;EAChD,KAAK,oBACH,OAAO,sBAAsB,OAAO,OAAO,IAAI;EACjD,KAAK,sBACH,OAAO,wBAAwB,OAAO,OAAO,IAAI;EACnD,KAAK,kBACH,OAAO,oBAAoB,KAAK;EAClC,KAAK,YACH,OAAO,cAAc,OAAO,OAAO,MAAM,OAAO,MAAM;EACxD,KAAK,sBACH,OAAO,uBAAuB,OAAO,OAAO,QAAQ,OAAO,MAAM;EACnE,KAAK,YACH,OAAO,cAAc,OAAO,OAAO,IAAI;EACzC,KAAK,eACH,OAAO,iBAAiB,KAAK;EAC/B,KAAK,iBACH,OAAO,mBAAmB,OAAO,OAAO,MAAM,OAAO,UAAU;EACjE,KAAK,oBACH,OAAO,sBAAsB,KAAK;EACpC,KAAK,aACH,OAAO,eAAe;CAC1B;AACF;;AAMA,MAAM,2BAA2B;;AAKjC,MAAa,UAAU,WAAwC,SAAS,QACtE,EAAE,cAAc,sBAAsB,iBAAiB,aACvD,KACoB;CACpB,MAAM,CAAC,OAAO,YAAY,WAAW,gBAAgB;EAAE,SAAS,CAAC;EAAG,QAAQ;CAAE,CAAC;CAC/E,MAAM,QAAQ,SAAS;CAIvB,MAAM,WAAW,OAAO,KAAK;CAC7B,SAAS,UAAU;CAGnB,MAAM,CAAC,aAAa,kBAAkB,yBAAsB,IAAI,IAAI,CAAC;CAGrE,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;CACtD,MAAM,CAAC,aAAa,kBAAkB,SAAS,EAAE;CACjD,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,CAAC;CAGtD,MAAM,kBAAkB,OAAO,YAAY;CAC3C,gBAAgB,UAAU;CAC1B,MAAM,mBAAmB,OAAO,KAAK;CACrC,iBAAiB,UAAU;;CAG3B,SAAS,cAAc,QAAuB;EAC5C,gBAAgB,UAAU;EAC1B,gBAAgB,MAAM;EACtB,IAAI,CAAC,QAAQ;GACX,eAAe,EAAE;GACjB,kBAAkB,CAAC;EACrB;EACA,uBAAuB,MAAM;CAC/B;CAGA,YAAa,OAAe,QAAa;EAEvC,IAAI,IAAI,QAAQ,CAAC,IAAI,QAAQ,UAAU,KAAK;GAC1C,cAAc,CAAC,gBAAgB,OAAO;GACtC;EACF;EAGA,IAAI,gBAAgB,SAAS;GAC3B,IAAI,IAAI,QAAQ;IACd,cAAc,KAAK;IACnB;GACF;GACA,IAAI,IAAI,aAAa,IAAI,QAAQ;IAC/B,gBAAgB,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC;IAC1C,kBAAkB,CAAC;IACnB;GACF;GACA,IAAI,IAAI,SAAS;IACf,mBAAmB,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;IACjD;GACF;GACA,IAAI,IAAI,WAAW;IACjB,mBAAmB,SAAS,OAAO,CAAC;IACpC;GACF;GAEA,IAAI,SAAS,MAAM,WAAW,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,MAAM;IACzD,gBAAgB,SAAS,OAAO,KAAK;IACrC,kBAAkB,CAAC;IACnB;GACF;GACA;EACF;EAGA,IAAI,IAAI,QAAQ,CAAC,IAAI,QAAQ,UAAU,KAAK;GAE1C,MAAM,cADW,iBAAiB,QACL,QAAQ,QAClC,MAAM,EAAE,SAAS,iBAAiB,EAAE,KAAK,SAAS,wBACrD;GACA,IAAI,YAAY,WAAW,GAAG;GAC9B,gBAAgB,SAAS;IACvB,MAAM,OAAO,IAAI,IAAI,IAAI;IAEzB,IADoB,YAAY,OAAO,MAAM,KAAK,IAAI,EAAE,EAAE,CAC5C,GACZ,KAAK,MAAM,KAAK,aAAa,KAAK,OAAO,EAAE,EAAE;SAE7C,KAAK,MAAM,KAAK,aAAa,KAAK,IAAI,EAAE,EAAE;IAE5C,OAAO;GACT,CAAC;GACD;EACF;EAGA,IAAI,IAAI,UAAU,CAAC,IAAI,QAAQ,CAAC,IAAI,MAAM;GAExC,MAAM,gBADW,iBAAiB,QACH,QAAQ,UAAU,MAAM,EAAE,SAAS,UAAU;GAC5E,IAAI,eAAe;IACjB,gBAAgB,SAAS;KACvB,MAAM,OAAO,IAAI,IAAI,IAAI;KACzB,IAAI,KAAK,IAAI,cAAc,EAAE,GAC3B,KAAK,OAAO,cAAc,EAAE;UAE5B,KAAK,IAAI,cAAc,EAAE;KAE3B,OAAO;IACT,CAAC;IACD;GACF;EACF;CACF,CAAC;CAED,oBACE,YACsB;EACpB,UAAU,MAAM,OAAO;GACrB,SAAS;IAAE,MAAM;IAAc;IAAM;GAAM,CAAC;EAC9C;EACA,QAAQ,MAAM,SAAS;GACrB,SAAS;IAAE,MAAM;IAAY;IAAM;GAAQ,CAAC;EAC9C;EACA,oBAAoB;GAClB,SAAS,EAAE,MAAM,sBAAsB,CAAC;EAC1C;EACA,kBAAkB;GAChB,SAAS,EAAE,MAAM,oBAAoB,CAAC;EACxC;EACA,eAAe,MAAM;GACnB,SAAS;IAAE,MAAM;IAAmB;GAAK,CAAC;EAC5C;EACA,gBAAgB,MAAM;GACpB,SAAS;IAAE,MAAM;IAAoB;GAAK,CAAC;EAC7C;EACA,kBAAkB,MAAM;GACtB,SAAS;IAAE,MAAM;IAAsB;GAAK,CAAC;EAC/C;EACA,gBAAgB;GACd,SAAS,EAAE,MAAM,iBAAiB,CAAC;EACrC;EACA,QAAQ,MAAM,QAAQ;GACpB,SAAS;IAAE,MAAM;IAAY;IAAM;GAAO,CAAC;EAC7C;EACA,iBAAiB,QAAQ,QAAQ;GAC/B,SAAS;IAAE,MAAM;IAAsB;IAAQ;GAAO,CAAC;EACzD;EACA,QAAQ,MAAM;GACZ,SAAS;IAAE,MAAM;IAAY;GAAK,CAAC;EACrC;EACA,aAAa;GACX,SAAS,EAAE,MAAM,cAAc,CAAC;EAClC;EACA,aAAa,MAAM,YAAY;GAC7B,SAAS;IAAE,MAAM;IAAiB;IAAM;GAAW,CAAC;EACtD;EACA,kBAAkB;GAChB,SAAS,EAAE,MAAM,mBAAmB,CAAC;EACvC;EACA,WAAW;GACT,SAAS,EAAE,MAAM,YAAY,CAAC;EAChC;EACA,gBAAgB;GACd,OAAO,SAAS,QAAQ,QAAQ;EAClC;CACF,IACA,CAAC,CACH;CAGA,MAAM,EAAE,YAAY;CACpB,MAAM,WAAW,eACb,QAAQ,MAAM,aAAa,OAAO,aAAa,GAAG,IAClD,QAAQ,MAAM,GAAY;CAE9B,IAAI,SAAS,WAAW,GACtB,OAAO,MAAM,cACX,KACA;EAAE,eAAe;EAAU,UAAU;CAAE,GAEvC,MAAM,cACJ,KACA;EAAE,eAAe;EAAU,cAAc;CAAE,GAC3C,MAAM,cACJ,MACA;EAAE,OAAO,MAAM,OAAO;EAAQ,MAAM;CAAK,GACzC,sBACF,GACA,MAAM,cACJ,MACA;EAAE,OAAO,MAAM,OAAO;EAAQ,MAAM;CAAK,GACzC,sBACF,GACA,MAAM,cACJ,MACA;EAAE,OAAO,MAAM,OAAO;EAAQ,MAAM;CAAK,GACzC,sBACF,CACF,GACA,MAAM,cACJ,MACA,EAAE,UAAU,KAAK,GACjB,oCACF,CACF;CAKF,MAAM,eADe,gBAAgB,aAAa,MAAM,SAAS,QAAQ,QAAQ,SAE7E,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,cAAc;CAAE,GACxC,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,gBAAgB,GAC9D,MAAM,cACJ,MACA;EAAE,UAAU;EAAM,MAAM;CAAK,UACtB;EAEL,KAAK,IAAI,IAAI,aAAc,MAAM,GAAG,KAAK,GAAG,KAAK;GAC/C,MAAM,QAAQ,SAAS,QAAQ,QAAQ;GACvC,IAAI,OAAO,SAAS,QAAQ;IAC1B,MAAM,YAAY,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM;IAC/C,OAAO,UAAU,SAAS,KAAK,UAAU,MAAM,GAAG,EAAE,IAAI,QAAQ;GAClE;EACF;EACA,OAAO;CACT,EAAA,CAAG,CACL,CACF,IACA;CAGJ,MAAM,gBAA+B,CAAC;CACtC,IAAI,gBAAgB,aAAa;EAC/B,MAAM,QAAQ,YAAY,YAAY;EACtC,KAAK,MAAM,SAAS,UAAU;GAC5B,IAAI,MAAM;GACV,MAAM,YAAY,MAAM,KAAK,YAAY;GACzC,QAAQ,MAAM,UAAU,QAAQ,OAAO,GAAG,OAAO,IAAI;IACnD,cAAc,KAAK;KACjB,SAAS,MAAM;KACf,OAAO;KACP,MAAM,MAAM,KAAK,MAAM,KAAK,MAAM,YAAY,MAAM;IACtD,CAAC;IACD,OAAO,MAAM;GACf;EACF;CACF;CAGA,MAAM,kBACJ,cAAc,SAAS,KACjB,iBAAiB,cAAc,SAAU,cAAc,UAAU,cAAc,SACjF;CAGN,MAAM,qBACJ,cAAc,SAAS,IAAI,cAAc,gBAAgB,CAAE,UAAU;CAGvE,MAAM,WAAiC,CAAC;CAExC,KAAK,MAAM,SAAS,UAAU;EAC5B,MAAM,aAAa,YAAY,IAAI,MAAM,EAAE;EAC3C,MAAM,oBAAoB,eACtB,cAAc,QAAQ,MAAM,EAAE,YAAY,MAAM,EAAE,CAAC,CAAC,KAAK,MAAM,EAAE,KAAK,IACtE,CAAC;EAEL,SAAS,KACP,MAAM,cACJ,KACA;GACE,KAAK,MAAM;GACX,eAAe;GACf,cAAc,MAAM,SAAS,QAAQ,IAAI;EAC3C,GAEA,mBAAmB,SACf,MAAM,cACJ,MACA,EAAE,UAAU,KAAK,GACjB,MAAM,IAAI,KAAK,MAAM,SAAS,CAAC,CAAC,mBAAmB,EAAE,KAAK,UAAU,MAAM,IAAI,EAAE,IAClF,IACA,MACJ,GAAG,mBACD,OACA,YACA,uBAAuB,MAAM,KAAK,kBAAkB,IACpD,mBACA,aACA,KACF,CACF,CACF;CACF;CAGA,MAAM,YAAY,eACd,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,YAAY;CAAE,GACtC,MAAM,cAAc,MAAM;EAAE,OAAO,MAAM,OAAO;EAAQ,MAAM;CAAK,GAAG,KAAK,GAC3E,MAAM,cACJ,MACA,MACA,eAAe,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,QAAQ,CACvE,GACA,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,GAAG,GACjD,cAAc,SAAS,IACnB,MAAM,cACJ,MACA,EAAE,UAAU,KAAK,GACjB,KAAK,kBAAkB,EAAE,GAAG,cAAc,QAC5C,IACA,cACE,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,OAAO,IACrD,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,UAAU,CAChE,IACA;CAEJ,OAAO,MAAM,cACX,KACA,EAAE,eAAe,SAAS,GAC1B,cACA,GAAG,UACH,SACF;AACF,CAAC;AAYD,SAAS,WAAW,OAAqB,QAAoD;CAC3F,QAAQ,MAAM,MAAd;EACE,KAAK,UACH,OAAO,MAAM,UAAU,UACnB,OAAO,QACP,MAAM,UAAU,SACd,OAAO,UACP,OAAO;EACf,KAAK,QACH,OAAO,MAAM,UAAU,OAAO,SAAS,OAAO;EAChD,KAAK,aACH,OAAO,MAAM,YAAY,OAAO,aAAa,OAAO;EACtD,KAAK,YACH,OAAO,OAAO,QAAQ;EACxB,KAAK,eACH,OAAO,OAAO;EAChB,KAAK,OACH,OAAO,OAAO;EAChB,KAAK,YACH,OAAO,OAAO;EAChB,SACE;CACJ;AACF;;AAGA,SAAS,UAAU,MAAoC;CACrD,QAAQ,MAAR;EACE,KAAK,UACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,aACH,OAAO;EACT,KAAK,YACH,OAAO;EACT,KAAK,eACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,YACH,OAAO;CACX;AACF;AAEA,SAAS,YAAY,OAA6B;CAChD,QAAQ,MAAM,MAAd;EACE,KAAK,UACH,OAAO,MAAM,UAAU,UAAU,OAAO,MAAM,UAAU,SAAS,OAAO;EAC1E,KAAK,QACH,OAAO,MAAM,UAAU,WAAW;EACpC,KAAK,aACH,OAAO;EACT,KAAK,YACH,OAAO;EACT,KAAK,eACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,YACH,OAAO;EACT,SACE,OAAO;CACX;AACF;;;;;;;;;;;;;AAgBA,SAAS,mBACP,OACA,YACA,sBACA,mBACA,aACA,OACsB;CACtB,QAAQ,MAAM,MAAd;EACE,KAAK,aACH,OAAO,gBAAgB,OAAO,mBAAmB,aAAa,KAAK;EACrE,KAAK,UACH,OAAO,aAAa,OAAO,mBAAmB,aAAa,KAAK;EAClE,KAAK,QACH,OAAO,WAAW,OAAO,mBAAmB,aAAa,KAAK;EAChE,KAAK,YACH,OAAO,cAAc,OAAO,mBAAmB,aAAa,KAAK;EACnE,KAAK,eACH,OAAO,iBAAiB,OAAO,YAAY,mBAAmB,aAAa,KAAK;EAClF,KAAK,OACH,OAAO,UAAU,OAAO,mBAAmB,aAAa,KAAK;EAC/D,KAAK,YACH,OAAO,eAAe,OAAO,YAAY,KAAK;EAChD,SACE,OAAO,CACL,MAAM,cACJ,MACA;GAAE,KAAK;GAAQ,OAAO,WAAW,OAAO,MAAM,MAAM;EAAE,GACtD,MAAM,IACR,CACF;CACJ;AACF;AAIA,SAAS,gBACP,OACA,cACA,aACA,OACsB;CACtB,MAAM,WAAiC,CAAC;CAExC,IAAI,MAAM,WAAW;EAEnB,MAAM,eAAe,iBAAiB,MAAM,IAAI;EAChD,MAAM,aAAa,MAAM,KAAK,MAAM,GAAG,YAAY;EACnD,MAAM,eAAe,MAAM,KAAK,MAAM,YAAY;EAElD,IAAI,YAAY;GACd,MAAM,SAAS,cAAc,UAAU;GACvC,SAAS,KACP,MAAM,cAAc,KAAK;IAAE,KAAK;IAAU,eAAe;GAAS,GAAG,aAAa,MAAM,CAAC,CAC3F;EACF;EACA,IAAI,cACF,SAAS,KACP,MAAM,cACJ,MACA;GAAE,KAAK;GAAa,OAAO,MAAM,OAAO;EAAW,GACnD,iBAAiB,cAAc,cAAc,WAAW,GACxD,MAAM,cAAc,MAAM,MAAM,GAAG,CACrC,CACF;OACK,IAAI,CAAC,YAEV,SAAS,KACP,MAAM,cAAc,MAAM;GAAE,KAAK;GAAa,OAAO,MAAM,OAAO;EAAW,GAAG,GAAG,CACrF;CAEJ,OAAO;EAEL,MAAM,SAAS,cAAc,MAAM,IAAI;EACvC,IAAI,OAAO,SAAS,GAClB,SAAS,KACP,MAAM,cAAc,KAAK;GAAE,KAAK;GAAM,eAAe;EAAS,GAAG,aAAa,MAAM,CAAC,CACvF;CAEJ;CAEA,OAAO;AACT;AAIA,SAAS,aACP,OACA,cACA,aACA,OACsB;CACtB,MAAM,QAAQ,WAAW,OAAO,MAAM,MAAM;CAC5C,MAAM,SAAS,YAAY,KAAK;CAChC,MAAM,UAAU,iBAAiB,MAAM,MAAM,cAAc,WAAW;CAEtE,OAAO,CACL,MAAM,cAAc,MAAM;EAAE,KAAK;EAAW;CAAM,GAAG,QAAQ,oBAAoB,OAAO,CAAC,CAC3F;AACF;AAIA,SAAS,WACP,OACA,cACA,aACA,OACsB;CACtB,MAAM,QAAQ,WAAW,OAAO,MAAM,MAAM;CAC5C,MAAM,SAAS,YAAY,KAAK;CAChC,MAAM,SAAS,MAAM,UAAU,MAAM;CAErC,OAAO,CACL,MAAM,cACJ,MACA;EAAE,KAAK;EAAW;CAAM,GACxB,QACA,oBAAoB,iBAAiB,MAAM,MAAM,cAAc,WAAW,CAAC,GAC3E,MACF,CACF;AACF;AAIA,SAAS,cACP,OACA,cACA,aACA,OACsB;CACtB,MAAM,SAAS,MAAM,kBAAkB,KAAA,KAAa,MAAM,KAAK,SAAS,GAAG;CAC3E,MAAM,SAAS,SAAS,OAAO;CAC/B,MAAM,QAAQ,SAAS,MAAM,OAAO,UAAU,MAAM,OAAO;CAC3D,MAAM,SAAS,SAAS,KAAK;CAE7B,OAAO,CACL,MAAM,cACJ,MACA;EAAE,KAAK;EAAW;CAAM,GACxB,QACA,iBAAiB,MAAM,OAAO,QAAQ,cAAc,WAAW,CACjE,CACF;AACF;;;;;AAQA,SAAS,mBAAmB,MAAsB;CAChD,OAAO,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;AACxC;AAEA,SAAS,iBACP,OACA,YACA,cACA,aACA,OACsB;CACtB,MAAM,QAAQ,MAAM,OAAO;CAE3B,MAAM,YAAY,mBAAmB,MAAM,IAAI;CAC/C,MAAM,SAAS,UAAU,SAAS;CAClC,MAAM,WAAiC,CAAC;CAExC,IAAI,UAAU,CAAC,YAAY;EACzB,MAAM,YAAY,UAAU,MAAM,GAAG,wBAAwB;EAC7D,SAAS,KACP,MAAM,cACJ,MACA;GAAE,KAAK;GAAW;GAAO,UAAU;EAAK,GACxC,QACA,oBAAoB,iBAAiB,WAAW,cAAc,WAAW,CAAC,GAC1E,MAAM,cACJ,MACA;GAAE,KAAK;GAAY,UAAU;EAAK,GAClC,OAAO,UAAU,SAAS,yBAAyB,gBACrD,CACF,CACF;CACF,OACE,SAAS,KACP,MAAM,cACJ,MACA;EAAE,KAAK;EAAW;EAAO,UAAU;CAAK,GACxC,QACA,oBAAoB,iBAAiB,WAAW,cAAc,WAAW,CAAC,GAC1E,SACI,MAAM,cAAc,MAAM;EAAE,KAAK;EAAY,UAAU;CAAK,GAAG,cAAc,IAC7E,IACN,CACF;CAGF,OAAO;AACT;AAIA,SAAS,UACP,OACA,cACA,aACA,OACsB;CACtB,MAAM,QAAQ,WAAW,OAAO,MAAM,MAAM;CAC5C,MAAM,SAAS,YAAY,KAAK;CAEhC,OAAO,CACL,MAAM,cACJ,MACA;EAAE,KAAK;EAAW;CAAM,GACxB,QACA,oBAAoB,iBAAiB,MAAM,MAAM,cAAc,WAAW,CAAC,CAC7E,CACF;AACF;;;;;AAMA,SAAS,eACP,OACA,YACA,OACsB;CACtB,MAAM,QAAQ,WAAW,OAAO,MAAM,MAAM;CAC5C,MAAM,SAAS,YAAY,KAAK;CAChC,MAAM,UAAU,MAAM,cAAc,QAAQ,MAAM,aAAa,IAAA,CAAM,QAAQ,CAAC,IAAI;CAElF,IAAI,YAGF,OADc,MAAM,KAAK,KAAK,CAAC,CAAC,MAAM,IAC3B,CAAC,CAAC,KAAK,MAAM,MACtB,MAAM,cACJ,MACA;EAAE,KAAK,SAAS;EAAK;CAAM,GAC3B,MAAM,IAAI,GAAG,OAAO,MAAM,QAAQ,gBAAgB,QAClD,QAAQ,GACV,CACF;CAIF,OAAO,CACL,MAAM,cACJ,MACA;EAAE,KAAK;EAAW;EAAO,UAAU;CAAK,GACxC,GAAG,OAAO,MAAM,QAAQ,aAC1B,CACF;AACF;;;;;;;AAUA,SAAS,oBAAoB,SAA2C;CACtE,IAAI,OAAO,YAAY,UACrB,OAAO,aAAa,OAAO;CAG7B,OAAO;AACT;;;;;;;AAQA,SAAS,iBAAiB,MAAc,cAAwB,OAAgC;CAC9F,IAAI,CAAC,SAAS,aAAa,WAAW,GAAG,OAAO;CAEhD,MAAM,MAAM,MAAM;CAElB,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,YAAY,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAE9D,MAAM,WAA8B,CAAC;CACrC,IAAI,SAAS;CAEb,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,QAAQ,QAAQ;EAEpB,IAAI,QAAQ,QACV,SAAS,KAAK,KAAK,MAAM,QAAQ,KAAK,CAAC;EAGzC,SAAS,KACP,MAAM,cACJ,MACA;GAAE,KAAK,MAAM;GAAS,SAAS;EAAK,GACpC,KAAK,MAAM,OAAO,QAAQ,GAAG,CAC/B,CACF;EACA,SAAS,QAAQ;CACnB;CAGA,IAAI,SAAS,KAAK,QAChB,SAAS,KAAK,KAAK,MAAM,MAAM,CAAC;CAIlC,IAAI,SAAS,WAAW,KAAK,OAAO,SAAS,OAAO,UAClD,OAAO,SAAS;CAGlB,OAAO;AACT;;;;;;;;;;;;;;;;AClhCA,MAAM,mBAAmB;;;;;;;AAQzB,IAAa,mBAAb,MAA8B;CAC5B,YAAoB;CACpB,UAAkB;CAClB;CAEA,YAAY,UAAkB,kBAAkB;EAC9C,KAAK,UAAU;CACjB;;;;;;;CAQA,SAAS,IAAsB;EAC7B,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,UAAU,MAAM,KAAK;EAE3B,IAAI,WAAW,KAAK,SAAS;GAE3B,KAAK,YAAY;GACjB,KAAK,UAAU;GACf,GAAG;EACL,OAAO,IAAI,CAAC,KAAK,SAAS;GAExB,KAAK,UAAU;GACf,MAAM,QAAQ,KAAK,UAAU;GAC7B,iBAAiB;IACf,KAAK,YAAY,KAAK,IAAI;IAC1B,KAAK,UAAU;IACf,GAAG;GACL,GAAG,KAAK;EACV;CAEF;;CAGA,QAAc;EACZ,KAAK,YAAY;EACjB,KAAK,UAAU;CACjB;AACF;;;;;;;AAQA,SAAgB,mBACd,SACA,aACA,WACQ;CACR,IAAI,eAAe,WAAW,OAAO,GAAG,QAAQ;CAChD,OAAO,GAAG,QAAQ;AACpB;;;;;;AAOA,SAAgB,uBAAuB,SAAoC;CACzE,OAAO,IAAI,iBAAiB,OAAO;AACrC;;;;;;;AC3EA,SAAgB,aAAa,EAC3B,YACA,WAC+C;CAC/C,IAAI,CAAC,YAAY,OAAO;CACxB,MAAM,QACJ,YAAY,WAAW,aAAa,YAAY,WAAW,aAAa;CAC1E,MAAM,QAAQ,YAAY,WAAW,UAAU,YAAY,WAAW,WAAW;CACjF,OAAO,MAAM,cAAc,KAAK,CAAC,GAAG,MAAM,cAAc,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;AACjF;;;;;;;;ACTA,SAAgB,mBAAmB,EACjC,aACA,mBACqD;CACrD,IAAI,YAAY,WAAW,GAAG,OAAO;CACrC,OAAO,MAAM,cACX,KACA,EAAE,eAAe,SAAS,GAC1B,GAAG,YAAY,KAAK,MAAM,UACxB,MAAM,cACJ,KACA,EAAE,KAAK,KAAK,GACZ,MAAM,cACJ,MACA;EACE,OAAO,UAAU,kBAAkB,SAAS,KAAA;EAC5C,SAAS,UAAU;CACrB,GACA,GAAG,UAAU,kBAAkB,OAAO,OAAO,MAC/C,CACF,CACF,CACF;AACF;;;;;;;;ACrBA,SAAgB,YAAY,EAC1B,YACA,SACA,OACA,YACuC;CACvC,MAAM,WAA8B,CAAC;CACrC,IAAI,YACF,SAAS,KAAK,MAAM,cAAc,MAAM;EAAE,KAAK;EAAO,UAAU;CAAK,GAAG,OAAO,CAAC;CAElF,IAAI,UACF,SAAS,KAAK,MAAM,cAAc,MAAM;EAAE,KAAK;EAAY,OAAO;CAAM,GAAG,QAAQ,CAAC;CAEtF,IAAI,CAAC,YAAY,MAAM,SAAS,GAC9B,SAAS,KACP,MAAM,cAAc,MAAM;EAAE,KAAK;EAAS,UAAU;CAAK,GAAG,IAAI,MAAM,OAAO,IAAI,CACnF;CAEF,OAAO,MAAM,cAAc,KAAK,CAAC,GAAG,GAAG,QAAQ;AACjD;;;;;;;;;;;;;;;;;;;ACHA,MAAM,cAAc;AACpB,MAAM,oBAAoB;;AAE1B,MAAM,kBAAkB;;AAGxB,MAAM,iBAA2B;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAM,eAAe,KAAK,QAAQ,GAAG,SAAS,oBAAoB;;;;;AAQlE,SAAS,mBAAmB,KAAa,WAAmB,YAA8B;CACxF,MAAM,UAAoB,CAAC;CAC3B,MAAM,QAAkB,CAAC,GAAG;CAE5B,OAAO,MAAM,SAAS,KAAK,QAAQ,SAAS,YAAY;EACtD,MAAM,UAAU,MAAM,IAAI;EAC1B,IAAI;EACJ,IAAI;GACF,UAAU,YAAY,OAAO;EAC/B,QAAQ;GACN;EACF;EAEA,KAAK,MAAM,QAAQ,SAAS;GAC1B,IAAI,QAAQ,UAAU,YAAY;GAClC,IAAI,KAAK,WAAW,GAAG,KAAK,SAAS,gBAAgB;GAErD,MAAM,WAAW,KAAK,SAAS,IAAI;GACnC,IAAI;GACJ,IAAI;IACF,OAAO,SAAS,QAAQ;GAC1B,QAAQ;IACN;GACF;GAEA,MAAM,eAAe,SAAS,WAAW,QAAQ,CAAC,CAAC,QAAQ,OAAO,GAAG;GACrE,IAAI,KAAK,YAAY,GAAG;IACtB,QAAQ,KAAK,eAAe,GAAG;IAC/B,MAAM,KAAK,QAAQ;GACrB,OACE,QAAQ,KAAK,YAAY;EAE7B;CACF;CAEA,OAAO,QAAQ,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AACnD;;;;;;;;AASA,SAAS,qBAAqB,SAAiB,WAA6B;CAC1E,IAAI,CAAC,WAAW,YAAY,IAAI,OAAO,CAAC;CAGxC,MAAM,aAAa,QAAQ,QAAQ,OAAO,GAAG;CAC7C,MAAM,YAAY,WAAW,YAAY,GAAG;CAC5C,MAAM,YAAY,aAAa,IAAI,KAAK,WAAW,WAAW,MAAM,GAAG,SAAS,CAAC,IAAI;CACrF,MAAM,SAAS,aAAa,IAAI,WAAW,MAAM,YAAY,CAAC,IAAI;CAElE,MAAM,WAAW,mBAAmB,WAAW,WAAW,GAAG;CAC7D,MAAM,cAAc,OAAO,YAAY;CAEvC,OAAO,SACJ,QAAQ,MAAM,EAAE,YAAY,CAAC,CAAC,WAAW,WAAW,KAAK,EAAE,YAAY,CAAC,CAAC,SAAS,WAAW,CAAC,CAAC,CAC/F,MAAM,GAAG,eAAe,CAAC,CACzB,KAAK,MAAM,MAAM,CAAC;AACvB;;AAKA,SAAS,uBAAiC;CACxC,IAAI;EACF,IAAI,CAAC,WAAW,YAAY,GAAG,OAAO,CAAC;EACvC,MAAM,MAAM,aAAa,cAAc,OAAO;EAC9C,MAAM,SAAkB,KAAK,MAAM,GAAG;EACtC,IAAI,MAAM,QAAQ,MAAM,KAAK,OAAO,OAAO,MAAM,OAAO,MAAM,QAAQ,GACpE,OAAO,OAAO,MAAM,IAAY;EAElC,OAAO,CAAC;CACV,QAAQ;EACN,OAAO,CAAC;CACV;AACF;;AAGA,SAAS,qBAAqB,SAAyB;CACrD,IAAI;EACF,MAAM,MAAM,QAAQ,YAAY;EAChC,IAAI,CAAC,WAAW,GAAG,GAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;EACxD,cAAc,cAAc,KAAK,UAAU,QAAQ,MAAM,IAAY,CAAC,GAAG,OAAO;CAClF,QAAQ,CAER;AACF;;;;;AAoCA,SAAS,iBAAiB,QAA0B;CAClD,IAAI,CAAC,OAAO,WAAW,GAAG,GAAG,OAAO,CAAC;CACrC,MAAM,QAAQ,OAAO,YAAY;CACjC,OAAO,eAAe,QAAQ,QAAQ,IAAI,YAAY,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,CACvE,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CACnC,MAAM,GAAG,eAAe;AAC7B;;;;;;;;AASA,SAAS,cAAc,OAAe,QAAwB;CAE5D,KAAK,IAAI,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK;EACpC,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO,KAAK;GAEd,IAAI,MAAM,KAAK,KAAK,KAAK,MAAM,IAAI,EAAG,KAAK,MAAM,IAAI,OAAO,KAC1D,OAAO;GAGT,OAAO;EACT;EACA,IAAI,OAAO,OAAO,OAAO,MAEvB,OAAO;CAEX;CACA,OAAO;AACT;;;;;;;AAQA,SAAS,WAAW,MAA4C;CAC9D,IAAI,KAAK,WAAW,GAAG,GAAG,OAAO;CACjC,IAAI,KAAK,WAAW,GAAG,GAAG,OAAO;CACjC,OAAO;AACT;AAIA,SAAgB,SAAS,EACvB,UACA,SACA,UACA,cAAc,WACd,SACA,YACA,sBACA,YAAY,QAAQ,IAAI,GACxB,SAAS,aAAa,OACtB,mBACoC;CACpC,MAAM,QAAQ,SAAS;CAIvB,MAAM,CAAC,OAAO,YAAY,SAAS,EAAE;CACrC,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,MAAM,CAAC,aAAa,kBAAkB,SAAmB,CAAC,CAAC;CAC3D,MAAM,CAAC,iBAAiB,sBAAsB,SAAS,CAAC;;CAExD,MAAM,CAAC,iBAAiB,sBAAsB,SAAS,EAAE;CAGzD,MAAM,CAAC,SAAS,cAAc,SAAkB,QAAQ;CACxD,MAAM,CAAC,cAAc,mBAAmB,SAAS,EAAE;CAGnD,MAAM,aAAa,OAAiB,qBAAqB,CAAC;CAC1D,MAAM,kBAAkB,OAAO,EAAE;CACjC,MAAM,gBAAgB,OAAO,EAAE;CAG/B,MAAM,iBAAiB,OAAiB,CAAC,CAAC;CAC1C,MAAM,gBAAgB,OAA6C,IAAI;CAIvE,MAAM,aAAa,kBAAkB;EACnC,IAAI,cAAc,SAAS;GACzB,aAAa,cAAc,OAAO;GAClC,cAAc,UAAU;EAC1B;EACA,MAAM,QAAQ,eAAe;EAC7B,eAAe,UAAU,CAAC;EAC1B,IAAI,MAAM,WAAW,GAAG;EAExB,IAAI,MAAM,WAAW,GACnB,SAAS,MAAM,EAAG;OAElB,SAAS,MAAM,KAAK,IAAI,CAAC;CAE7B,GAAG,CAAC,QAAQ,CAAC;CAEb,MAAM,aAAa,aAChB,SAAiB;EAEhB,MAAM,OAAO,WAAW;EACxB,IAAI,KAAK,WAAW,KAAK,KAAK,KAAK,SAAS,OAAO,MAAM;GACvD,KAAK,KAAK,IAAI;GACd,IAAI,KAAK,SAAS,aAAa,KAAK,MAAM;EAC5C;EACA,gBAAgB,UAAU;EAM1B,IAHc,WAAW,IAGjB,MAAM,QAAQ;GACpB,eAAe,QAAQ,KAAK,IAAI;GAChC,IAAI,cAAc,SAAS,aAAa,cAAc,OAAO;GAC7D,cAAc,UAAU,WAAW,YAAY,EAAE;EACnD,OAAO;GACL,WAAW;GACX,SAAS,IAAI;EACf;EAEA,SAAS,EAAE;EACX,UAAU,CAAC;EACX,eAAe,CAAC,CAAC;EACjB,mBAAmB,CAAC;EACpB,mBAAmB,EAAE;EAGrB,qBAAqB,IAAI;CAC3B,GACA,CAAC,UAAU,UAAU,CACvB;CAoBA,SAAS,aAAa,OAAe,KAAU,KAAmB;EAChE,IAAI,IAAI,QAAQ,UAAU,KAAK;GAC7B,QAAQ;GACR,OAAO;EACT;EAEA,IAAI,IAAI,UAAU,IAAI,MAAM;GAC1B,MAAM,WAAW,IAAI,MAAM,MAAM,GAAG,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,MAAM,IAAI,MAAM;GACnF,IAAI,SAAS,QAAQ;GACrB,IAAI,UAAU,IAAI,SAAS,CAAC;GAC5B,IAAI,eAAe,CAAC,CAAC;GACrB,IAAI,mBAAmB,EAAE;GACzB,OAAO;EACT;EAEA,IAAI,IAAI,QAAQ;GACd,MAAM,UAAU,IAAI,MAAM,KAAK;GAC/B,IAAI,SAAS;IACX,IAAI,IAAI,YAAY,SAAS,KAAK,IAAI,kBAAkB,IAAI,YAAY,QAAQ;KAC9E,MAAM,WAAW,IAAI,YAAY,IAAI;KACrC,IAAI,IAAI,mBAAmB,KAAK,IAAI,kBAAkB,IAAI,MAAM,QAAQ;MACtE,MAAM,SAAS,IAAI,MAAM,MAAM,GAAG,IAAI,eAAe;MACrD,MAAM,QAAQ,IAAI,MAAM,MAAM,IAAI,MAAM;MACxC,IAAI,SAAS,SAAS,WAAW,KAAK;MACtC,IAAI,UAAU,IAAI,kBAAkB,SAAS,MAAM;KACrD,OAAO;MACL,IAAI,SAAS,QAAQ;MACrB,IAAI,UAAU,SAAS,MAAM;KAC/B;KACA,IAAI,eAAe,CAAC,CAAC;KACrB,IAAI,mBAAmB,CAAC;KACxB,IAAI,mBAAmB,EAAE;KACzB,OAAO;IACT;IACA,WAAW,OAAO;GACpB;GACA,OAAO;EACT;EACA,OAAO;CACT;CAEA,SAAS,qBAAqB,QAAgB,KAAU,KAAmB;EACzE,IAAI,IAAI,OAAO,IAAI,YAAY,SAAS,GAAG;GACzC,MAAM,WAAW,IAAI,YAAY,IAAI;GACrC,IAAI,IAAI,mBAAmB,KAAK,IAAI,kBAAkB,IAAI,MAAM,QAAQ;IAEtE,MAAM,SAAS,IAAI,MAAM,MAAM,GAAG,IAAI,eAAe;IACrD,MAAM,QAAQ,IAAI,MAAM,MAAM,IAAI,MAAM;IACxC,IAAI,SAAS,SAAS,WAAW,KAAK;IACtC,IAAI,UAAU,IAAI,kBAAkB,SAAS,MAAM;GACrD,OAAO;IAEL,IAAI,SAAS,QAAQ;IACrB,IAAI,UAAU,SAAS,MAAM;GAC/B;GACA,IAAI,eAAe,CAAC,CAAC;GACrB,IAAI,mBAAmB,CAAC;GACxB,IAAI,mBAAmB,EAAE;GACzB,OAAO;EACT;EACA,IAAI,IAAI,QAAQ;GACd,IAAI,eAAe,CAAC,CAAC;GACrB,IAAI,mBAAmB,CAAC;GACxB,IAAI,mBAAmB,EAAE;GACzB,OAAO;EACT;EACA,OAAO;CACT;CAEA,SAAS,kBAAkB,KAAU,KAAmB;EACtD,IAAI,IAAI,SAAS;GACf,IAAI,IAAI,YAAY,SAAS,GAAG;IAC9B,IAAI,mBAAmB,KAAK,IAAI,GAAG,IAAI,kBAAkB,CAAC,CAAC;IAC3D,OAAO;GACT;GACA,MAAM,OAAO,IAAI,WAAW;GAC5B,IAAI,KAAK,WAAW,GAAG,OAAO;GAC9B,IAAI,IAAI,gBAAgB,YAAY,IAClC,IAAI,cAAc,UAAU,IAAI;GAElC,MAAM,UAAU,IAAI,gBAAgB,UAAU;GAC9C,IAAI,UAAU,KAAK,QAAQ;IACzB,IAAI,gBAAgB,UAAU;IAC9B,MAAM,QAAQ,KAAK,KAAK,SAAS,IAAI;IACrC,IAAI,SAAS,KAAK;IAClB,IAAI,UAAU,MAAM,MAAM;GAC5B;GACA,OAAO;EACT;EAEA,IAAI,IAAI,WAAW;GACjB,IAAI,IAAI,YAAY,SAAS,GAAG;IAC9B,IAAI,mBAAmB,KAAK,IAAI,IAAI,YAAY,SAAS,GAAG,IAAI,kBAAkB,CAAC,CAAC;IACpF,OAAO;GACT;GACA,IAAI,IAAI,gBAAgB,YAAY,IAAI,OAAO;GAC/C,MAAM,UAAU,IAAI,gBAAgB,UAAU;GAC9C,IAAI,WAAW,GAAG;IAChB,IAAI,gBAAgB,UAAU;IAC9B,MAAM,QAAQ,IAAI,WAAW,QAAQ,IAAI,WAAW,QAAQ,SAAS,IAAI;IACzE,IAAI,SAAS,KAAK;IAClB,IAAI,UAAU,MAAM,MAAM;GAC5B,OAAO;IACL,IAAI,gBAAgB,UAAU;IAC9B,IAAI,SAAS,IAAI,cAAc,OAAO;IACtC,IAAI,UAAU,IAAI,cAAc,QAAQ,MAAM;GAChD;GACA,OAAO;EACT;EAEA,OAAO;CACT;CAEA,SAAS,qBAAqB,OAAe,KAAU,KAAmB;EACxE,IAAI,kBAAkB,KAAK,GAAG,GAAG,OAAO;EAExC,IAAI,IAAI,WAAW;GACjB,IAAI,UAAU,KAAK,IAAI,GAAG,IAAI,SAAS,CAAC,CAAC;GACzC,OAAO;EACT;EACA,IAAI,IAAI,YAAY;GAClB,IAAI,UAAU,KAAK,IAAI,IAAI,MAAM,QAAQ,IAAI,SAAS,CAAC,CAAC;GACxD,OAAO;EACT;EACA,IAAI,IAAI,QAAS,IAAI,QAAQ,UAAU,KAAM;GAC3C,IAAI,UAAU,CAAC;GACf,OAAO;EACT;EACA,IAAI,IAAI,OAAQ,IAAI,QAAQ,UAAU,KAAM;GAC1C,IAAI,UAAU,IAAI,MAAM,MAAM;GAC9B,OAAO;EACT;EAEA,OAAO;CACT;CAEA,SAAS,eAAe,OAAe,KAAU,KAAmB;EAClE,IAAI,IAAI,QAAQ,UAAU,KAAK;GAC7B,IAAI,UAAU,SAAS;IACrB,MAAM,SAAS,KAAK,MAAM,GAAG,IAAI,MAAM;IACvC,MAAM,QAAQ,KAAK,MAAM,IAAI,MAAM;IACnC,MAAM,UAAU,OAAO,QAAQ,WAAW,EAAE;IAC5C,MAAM,UAAU,OAAO,SAAS,QAAQ;IACxC,IAAI,WAAW,MAAM,IAAI,OAAO;IAChC,OAAO,UAAU;GACnB,CAAC;GACD,OAAO;EACT;EAEA,IAAI,IAAI,QAAQ,UAAU,KAAK;GAC7B,IAAI,UAAU,SAAS,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC;GAChD,OAAO;EACT;EAEA,IAAI,IAAI,QAAQ,UAAU,KAAK;GAC7B,IAAI,UAAU,SAAS,KAAK,MAAM,IAAI,MAAM,CAAC;GAC7C,IAAI,UAAU,CAAC;GACf,OAAO;EACT;EAEA,IAAI,IAAI,aAAa,IAAI,QAAQ;GAC/B,IAAI,IAAI,SAAS,GAAG;IAClB,IAAI,UAAU,SAAS,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC;IAC7E,IAAI,WAAW,MAAM,IAAI,CAAC;GAC5B;GACA,OAAO;EACT;EAEA,OAAO;CACT;CAEA,SAAS,gBAAgB,OAAe,KAAU,KAAmB;EACnE,IAAI,SAAS,CAAC,IAAI,QAAQ,CAAC,IAAI,QAAQ,MAAM,SAAS,GAAG;GACvD,IAAI,iCAAiC,KAAK,KAAK,GAAG,OAAO;GAEzD,IAAI,UAAU,SAAS,KAAK,MAAM,GAAG,IAAI,MAAM,IAAI,QAAQ,KAAK,MAAM,IAAI,MAAM,CAAC;GACjF,IAAI,WAAW,MAAM,IAAI,MAAM,MAAM;GAErC,MAAM,SAAS,IAAI,MAAM,MAAM,GAAG,IAAI,MAAM,IAAI,QAAQ,IAAI,MAAM,MAAM,IAAI,MAAM;GAClF,MAAM,YAAY,IAAI,SAAS,MAAM;GAGrC,IAAI,OAAO,WAAW,GAAG,GAAG;IAC1B,MAAM,UAAU,iBAAiB,MAAM;IACvC,IAAI,eAAe,OAAO;IAC1B,IAAI,mBAAmB,CAAC;IACxB,IAAI,mBAAmB,CAAC;IACxB,OAAO;GACT;GAIA,MAAM,QAAQ,cAAc,QAAQ,SAAS;GAC7C,IAAI,SAAS,GAAG;IACd,MAAM,UAAU,OAAO,MAAM,QAAQ,GAAG,SAAS;IACjD,IAAI,YAAY,KAAA,GAAW;KACzB,MAAM,UAAU,qBAAqB,SAAS,SAAS;KACvD,IAAI,eAAe,OAAO;KAC1B,IAAI,mBAAmB,CAAC;KACxB,IAAI,mBAAmB,KAAK;KAC5B,OAAO;IACT;GACF;GAEA,IAAI,eAAe,CAAC,CAAC;GACrB,IAAI,mBAAmB,EAAE;GACzB,OAAO;EACT;EACA,OAAO;CACT;CAIA,gBAAgB;EACd,IAAI,cAAc,WAAW,SAAS,GAAG;GACvC,UAAU,SAAS,KAAK,MAAM,GAAG,MAAM,IAAI,aAAa,KAAK,MAAM,MAAM,CAAC;GAC1E,WAAW,MAAM,IAAI,WAAW,MAAM;GACtC,uBAAuB;EACzB;CAGF,GAAG,CAAC,UAAU,CAAC;;CAKf,MAAM,kBAAkB,aACrB,OAAe,QAAsB;EAEpC,IAAI,UAAU,KAAK;GACjB,WAAW,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;GACnC,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GACjB,WAAW,MAAM,KAAK,IAAI,MAAM,QAAQ,IAAI,CAAC,CAAC;GAC9C,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GAEjB,MAAM,SAAS,MAAM,MAAM,GAAG,MAAM;GACpC,MAAM,cAAc,OAAO,YAAY,IAAI;GAC3C,IAAI,gBAAgB,IAAI;IACtB,UAAU,CAAC;IACX,OAAO;GACT;GACA,MAAM,kBAAkB,OAAO,YAAY,MAAM,cAAc,CAAC;GAChE,MAAM,MAAM,OAAO,SAAS,cAAc;GAC1C,MAAM,YAAY,KAAK,IAAI,KAAK,eAAe,kBAAkB,EAAE;GACnE,WAAW,oBAAoB,KAAK,IAAI,kBAAkB,KAAK,SAAS;GACxE,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GAEjB,MAAM,QAAQ,MAAM,MAAM,MAAM;GAChC,MAAM,cAAc,MAAM,QAAQ,IAAI;GACtC,IAAI,gBAAgB,IAAI;IACtB,UAAU,MAAM,MAAM;IACtB,OAAO;GACT;GACA,MAAM,MAAM,UAAU,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,YAAY,IAAI,IAAI;GACjE,MAAM,YAAY,MAAM,QAAQ,MAAM,cAAc,CAAC;GACrD,MAAM,UACJ,cAAc,KAAK,MAAM,SAAS,cAAc,IAAI,YAAY,cAAc;GAChF,UAAU,SAAS,cAAc,IAAI,KAAK,IAAI,KAAK,OAAO,CAAC;GAC3D,OAAO;EACT;EAEA,IAAI,UAAU,KAAK;GACjB,WAAW,QAAQ;GACnB,kBAAkB,QAAQ;GAC1B,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GACjB,WAAW,MAAM,KAAK,IAAI,MAAM,QAAQ,IAAI,CAAC,CAAC;GAC9C,WAAW,QAAQ;GACnB,kBAAkB,QAAQ;GAC1B,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GAGjB,UAFe,MAAM,MAAM,GAAG,MACP,CAAC,CAAC,YAAY,IAAI,IAAI,CAC1B;GACnB,WAAW,QAAQ;GACnB,kBAAkB,QAAQ;GAC1B,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GACjB,MAAM,QAAQ,MAAM,MAAM,MAAM;GAChC,MAAM,cAAc,MAAM,QAAQ,IAAI;GACtC,UAAU,UAAU,gBAAgB,KAAK,MAAM,SAAS,YAAY;GACpE,WAAW,QAAQ;GACnB,kBAAkB,QAAQ;GAC1B,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GACjB,MAAM,QAAQ,MAAM,MAAM,MAAM;GAChC,MAAM,cAAc,MAAM,QAAQ,IAAI;GACtC,MAAM,UAAU,UAAU,gBAAgB,KAAK,MAAM,SAAS;GAC9D,UAAU,MAAM,EAAE,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,MAAM,OAAO,CAAC;GAC7D,UAAU,UAAU,CAAC;GACrB,WAAW,QAAQ;GACnB,kBAAkB,QAAQ;GAC1B,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GAEjB,MAAM,YADS,MAAM,MAAM,GAAG,MACP,CAAC,CAAC,YAAY,IAAI,IAAI;GAC7C,UAAU,MAAM,EAAE,MAAM,GAAG,SAAS,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC;GACjE,UAAU,SAAS;GACnB,WAAW,QAAQ;GACnB,kBAAkB,QAAQ;GAC1B,OAAO;EACT;EAEA,IAAI,UAAU,KAAK;GACjB,UAAU,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,EAAE,MAAM,SAAS,CAAC,CAAC;GACxD,IAAI,UAAU,MAAM,QAAQ,WAAW,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;GAC/D,OAAO;EACT;EACA,IAAI,UAAU,OAAO,CAAC,IAAI,MAExB,OAAO;EAGT,IAAI,UAAU,KAAK;GACjB,gBAAgB,MAAM;GACtB,WAAW,QAAQ;GACnB,kBAAkB,QAAQ;GAC1B,OAAO;EACT;EAEA,IAAI,UAAU,KAAK;GAEjB,MAAM,QADO,MAAM,MAAM,MACR,CAAC,CAAC,MAAM,aAAa;GACtC,IAAI,OAAO,UAAU,UAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC,MAAM;QAC7D,UAAU,MAAM,MAAM;GAC3B,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GACjB,MAAM,SAAS,MAAM,MAAM,GAAG,MAAM;GACpC,MAAM,QAAQ,OAAO,MAAM,WAAW;GACtC,IAAI,OAAO,UAAU,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAE,MAAM;QAC3D,UAAU,OAAO,YAAY,GAAG,IAAI,CAAC;GAC1C,OAAO;EACT;EAEA,IAAI,UAAU,KAAK;GACjB,WAAW,MAAM,KAAK,IAAI,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,IAAI,EAAE;GAClE,OAAO;EACT;EAEA,IAAI,IAAI,QAAQ,UAAU,KACI,OAAO;EAErC,OAAO;CACT,GACA;EAAC;EAAO;EAAQ;CAAe,CACjC;;CAGA,MAAM,kBAAkB,aACrB,OAAe,QAAsB;EACpC,IAAI,IAAI,QAAQ;GACd,WAAW,QAAQ;GACnB,kBAAkB,QAAQ;GAC1B,gBAAgB,EAAE;GAClB,IAAI,gBAAgB,KAAK,eAAe,QAAQ,UAAU,YAAY;GACtE,OAAO;EACT;EAEA,IAAI,UAAU,KAAK;GACjB,WAAW,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;GACnC,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GACjB,WAAW,MAAM,KAAK,IAAI,MAAM,QAAQ,IAAI,CAAC,CAAC;GAC9C,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GAEjB,MAAM,cADQ,MAAM,MAAM,MACF,CAAC,CAAC,QAAQ,IAAI;GACtC,IAAI,gBAAgB,IAAI;IACtB,UAAU,MAAM,MAAM;IACtB,OAAO;GACT;GACA,UAAU,SAAS,cAAc,CAAC;GAClC,OAAO;EACT;EACA,IAAI,UAAU,KAAK;GACjB,MAAM,SAAS,MAAM,MAAM,GAAG,MAAM;GACpC,MAAM,cAAc,OAAO,YAAY,IAAI;GAC3C,IAAI,gBAAgB,IAAI;IACtB,MAAM,WAAW,OAAO,YAAY,MAAM,cAAc,CAAC;IACzD,UAAU,aAAa,KAAK,IAAI,WAAW,CAAC;GAC9C;GACA,OAAO;EACT;EAEA,IAAI,UAAU,KAAK;GACjB,MAAM,QAAQ,KAAK,IAAI,cAAc,MAAM;GAC3C,MAAM,MAAM,KAAK,IAAI,cAAc,MAAM;GACxB,MAAM,MAAM,OAAO,GAAG;GAEvC,WAAW,QAAQ;GACnB,kBAAkB,QAAQ;GAC1B,gBAAgB,EAAE;GAClB,OAAO;EACT;EAEA,IAAI,UAAU,KAAK;GACjB,MAAM,QAAQ,KAAK,IAAI,cAAc,MAAM;GAC3C,MAAM,MAAM,KAAK,IAAI,cAAc,MAAM;GACzC,UAAU,MAAM,EAAE,MAAM,GAAG,KAAK,IAAI,EAAE,MAAM,GAAG,CAAC;GAChD,UAAU,KAAK;GACf,WAAW,QAAQ;GACnB,kBAAkB,QAAQ;GAC1B,gBAAgB,EAAE;GAClB,OAAO;EACT;EACA,OAAO;CACT,GACA;EAAC;EAAO;EAAQ;EAAc;CAAe,CAC/C;CAIA,YAAa,OAAe,QAAa;EACvC,IAAI,UAAU;EAId,IAAI,MAAM,SAAS,QAAQ,KAAK,sBAAsB,KAAK,MAAM,KAAK,CAAC,GAAG;EAG1E,IAAI,IAAI,QAAQ,UAAU,KAAK;GAC7B,IAAI,MAAM,KAAK,KAAK,SAClB,QAAQ,KAAK;GAEf;EACF;EAGA,IAAI,YAAY;GAEd,IAAI,IAAI,QAAQ;IACd,IAAI,YAAY,UAAU;KACxB,WAAW,QAAQ;KACnB,kBAAkB,QAAQ;KAC1B,gBAAgB,EAAE;KAClB;IACF;IACA,IAAI,YAAY,UAAU;KACxB,WAAW,QAAQ;KACnB,kBAAkB,QAAQ;KAC1B;IACF;IAEA,eAAe,CAAC,CAAC;IACjB;GACF;GAEA,IAAI,YAAY,UAAU;IACxB,IAAI,gBAAgB,OAAO,GAAG,GAAG;IAEjC,IAAI,IAAI,QAAQ;KACd,MAAM,UAAU,MAAM,KAAK;KAC3B,IAAI,SAAS,WAAW,OAAO;KAC/B;IACF;IACA;GACF;GAEA,IAAI,YAAY,UAAU;IACxB,IAAI,gBAAgB,OAAO,GAAG,GAAG;IACjC;GACF;EAGF;EAEA,MAAM,MAAW;GACf;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EAEA,IAAI,aAAa,OAAO,KAAK,GAAG,GAAG;EACnC,IAAI,qBAAqB,OAAO,KAAK,GAAG,GAAG;EAC3C,IAAI,qBAAqB,OAAO,KAAK,GAAG,GAAG;EAC3C,IAAI,eAAe,OAAO,KAAK,GAAG,GAAG;EACrC,gBAAgB,OAAO,KAAK,GAAG;CACjC,CAAC;CAKD,MAAM,QAAQ,MAAM,MAAM,IAAI;CAC9B,MAAM,eAAe,MAAM,MAAM,EAAkB;CACnD,MAAM,YAAY,MAAM;CACxB,MAAM,UAAU,YAAY;CAE5B,MAAM,gBAAgB,UAAU;CAIhC,MAAM,gBAAsC,CAAC;CAE7C,IAAI,SACF,cAAc,KACZ,MAAM,cACJ,MACA;EAAE,KAAK;EAAQ,UAAU;CAAK,GAC9B,aAAa,YAAY,kBAAkB,IAC7C,CACF;CAGF,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;EAC5C,MAAM,OAAO,aAAa;EAE1B,MAAM,SADS,MAAM,aAAa,SAAS,IACnB,OAAO;EAE/B,IAAI,iBAAiB,MAAM,aAAa,SAAS,GAC/C,cAAc,KACZ,MAAM,cACJ,KACA;GAAE,KAAK,QAAQ;GAAK,eAAe;EAAM,GACzC,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,OAAO,GAAG,MAAM,GAChE,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,OAAO,GAAG,WAAW,CACvE,CACF;OAGA,cAAc,KACZ,MAAM,cACJ,KACA;GAAE,KAAK,QAAQ;GAAK,eAAe;EAAM,GACzC,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,OAAO,GAAG,MAAM,GAChE,iBAAiB,MAAM,SAAS,gBAAgB,OAAO,CAAC,GAAG,KAAK,CAClE,CACF;CAEJ;CAEA,OAAO,MAAM,cACX,KACA,EAAE,eAAe,SAAS,GAE1B,MAAM,cAAc,cAAc;EAAE;EAAY;CAAQ,CAAC,GAGzD,MAAM,cACJ,KACA;EACE,eAAe;EACf,aAAa;EACb,aAAa,MAAM,OAAO;EAC1B,UAAU;EACV,WAAW;CACb,GACA,GAAG,aACL,GAGA,MAAM,cAAc,oBAAoB;EAAE;EAAa;CAAgB,CAAC,GAGxE,MAAM,cAAc,aAAa;EAAE;EAAY;EAAS;EAAO;CAAS,CAAC,CAC3E;AACF;;;;;;;AAWA,SAAS,gBAAgB,MAAc,WAA2B;CAChE,MAAM,QAAQ,KAAK,MAAM,IAAI;CAC7B,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,IAAI,MAAM,QAAQ,KACjD,UAAU,MAAM,EAAE,CAAE,SAAS;CAE/B,OAAO;AACT;;;;AAKA,SAAS,iBACP,MACA,KACA,QACoB;CACpB,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,CAAC;CAEtD,IAAI,WAAW,KAAK,QAClB,OAAO,MAAM,cACX,MACA,CAAC,GACD,MAAM,cAAc,MAAM,CAAC,GAAG,IAAI,GAClC,MAAM,cAAc,MAAM,EAAE,SAAS,KAAK,GAAG,GAAG,CAClD;CAGF,OAAO,MAAM,cACX,MACA,CAAC,GACD,MAAM,cAAc,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG,OAAO,CAAC,GACpD,MAAM,cAAc,MAAM,EAAE,SAAS,KAAK,GAAG,KAAK,YAAY,GAAG,GACjE,MAAM,cAAc,MAAM,CAAC,GAAG,KAAK,MAAM,UAAU,CAAC,CAAC,CACvD;AACF;;;;;;;;;;;ACn7BA,SAAS,aAAa,QAAwB;CAC5C,IAAI,UAAU,KAAW,OAAO,IAAI,SAAS,IAAA,CAAW,QAAQ,CAAC,EAAE;CACnE,IAAI,UAAU,KAAO,OAAO,IAAI,SAAS,IAAA,CAAO,QAAQ,CAAC,EAAE;CAC3D,OAAO,OAAO,MAAM;AACtB;;AAGA,SAAS,WAAW,MAAsB;CACxC,IAAI,QAAQ,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC;CACxC,IAAI,QAAQ,KAAM,OAAO,IAAI,KAAK,QAAQ,CAAC;CAC3C,OAAO,IAAI,KAAK,QAAQ,CAAC;AAC3B;;;;;;;;AASA,SAAS,YAAY,SAAiB,QAAqC;CACzE,IAAI,WAAW,KAAA,KAAa,UAAU,GAAG,OAAO,KAAA;CAChD,MAAM,QAAQ,UAAU;CACxB,IAAI,QAAQ,IAAK,OAAO;CACxB,IAAI,QAAQ,IAAK,OAAO;CACxB,OAAO;AACT;AAIA,SAAgB,UAAU,EACxB,MACA,OACA,WACA,UACA,YACA,SACA,gBACqC;CACrC,MAAM,QAAQ,SAAS;CACvB,MAAM,kBAAkB,YAAY,OAAO;CAE3C,MAAM,QAA2B,CAAC;CAClC,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO;CAE/B,IAAI,eAAe,KAAA,KAAa,aAAa,GAC3C,MAAM,KAAK,KAAK,aAAa,UAAU,EAAE,IAAI;CAG/C,IAAI,YAAY,KAAA,KAAa,UAAU,GAAG;EACxC,MAAM,QAAQ,YAAY,SAAS,YAAY;EAC/C,MAAM,KACJ,MAAM,cACJ,MAAM,UACN,EAAE,KAAK,OAAO,GACd,MACA,MAAM,cAAc,MAAM,EAAE,MAAM,GAAG,WAAW,OAAO,CAAC,CAC1D,CACF;CACF;CAEA,MAAM,KAAK,KAAK,WAAW,iBAAiB;CAE5C,OAAO,MAAM,cACX,KACA;EACE,eAAe;EACf,gBAAgB;EAChB,UAAU;EACV,aAAa;EACb,aAAa,MAAM,OAAO;CAC5B,GACA,MAAM,cACJ,MACA,EAAE,UAAU,KAAK,GACjB,GAAG,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,IAAI,CAAC,CAAC,CAClD,GACA,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,YAAY,CAC5D;AACF;;;;;;;;;;;;;;;;AClEA,MAAM,uBAA6D;CACjE,WAAW;CACX,MAAM;CACN,QAAQ;CACR,KAAK;AACP;AAEA,MAAM,iBAAuD;CAC3D,WAAW;CACX,MAAM;CACN,QAAQ;CACR,KAAK;AACP;;;;;;;;;AAeA,SAAgB,mBAGd;CACA,MAAM,CAAC,OAAO,YAAY,SAA+B,CAAC,CAAC;CAC3D,MAAM,WAAW,OAA8B,IAAI;CACnD,MAAM,WAAW,OAAO,KAAK;CAC7B,SAAS,UAAU;;CAGnB,MAAM,UAAU,kBAAkB;EAChC,UAAU,SAAS,KAAK,MAAM,CAAC,CAAC;CAClC,GAAG,CAAC,CAAC;;CAGL,MAAM,OAAO,aAAa,SAAuB;EAC/C,UAAU,SAAS;GAEjB,MAAM,WAAW,KAAK,QAAQ,MAAM,EAAE,QAAQ,KAAK,GAAG;GACtD,MAAM,QAA4B;IAChC,GAAG;IACH,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI;IAC5B,WAAW,KAAK,IAAI;GACtB;GACA,OAAO,CAAC,GAAG,UAAU,KAAK,CAAC,CAAC,MAAM,GAAU;EAC9C,CAAC;CACH,GAAG,CAAC,CAAC;CAUL,MAAM,UAPS,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM;EACvC,MAAM,KAAK,eAAe,EAAE;EAC5B,MAAM,KAAK,eAAe,EAAE;EAC5B,IAAI,OAAO,IAAI,OAAO,KAAK;EAC3B,OAAO,EAAE,YAAY,EAAE;CACzB,CAEqB,CAAC,CAAC,MAAM;CAG7B,gBAAgB;EACd,IAAI,CAAC,SAAS;EAEd,MAAM,WAAW,qBAAqB,QAAQ;EAC9C,SAAS,UAAU,iBAAiB;GAClC,QAAQ;EACV,GAAG,QAAQ;EAEX,aAAa;GACX,IAAI,SAAS,SAAS,aAAa,SAAS,OAAO;EACrD;CACF,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC;CAEzB,OAAO;EAAE;EAAS;CAAK;AACzB;;AAKA,SAAS,cAAc,UAAwC;CAC7D,QAAQ,UAAR;EACE,KAAK,aACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,OACH,OAAO;CACX;AACF;;AAGA,SAAgB,mBAAmB,EACjC,WAG4B;CACd,SAAS;CAEvB,IAAI,CAAC,SAAS,OAAO;CAErB,MAAM,QAAQ,cAAc,QAAQ,QAAQ;CAE5C,OAAO,MAAM,cACX,KACA;EACE,UAAU;EACV,UAAU;EACV,aAAa;EACb,aAAa;CACf,GACA,MAAM,cAAc,MAAM;EAAE;EAAO,MAAM;CAAK,GAAG,QAAQ,IAAI,CAC/D;AACF;;;;;;;;;;;;;;;;;AClHA,MAAM,eAAe;;AAGrB,MAAM,eAAsE;CAC1E,MAAM;EAAE,OAAO;EAAQ,OAAO;CAAU;CACxC,eAAe;EAAE,OAAO;EAAa,OAAO;CAAa;CACzD,kBAAkB;EAAE,OAAO;EAAY,OAAO;CAAU;CACxD,WAAW;EAAE,OAAO;EAAU,OAAO;CAAQ;AAC/C;;;;;;;AAQA,SAAgB,kBAAkB,EAChC,SACA,UACA,YAC6C;CAC7C,MAAM,QAAQ,SAAS;CACvB,MAAM,QAAQ,aAAa,QAAQ,WAAW,aAAa;CAC3D,MAAM,aAAa,MAAM,OAAO,MAAM,UAAU,MAAM,OAAO;CA2B7D,WAvBkB,aACf,OAAe,QAAa;EAC3B,MAAM,OAAO,MAAM,YAAY;EAC/B,IAAI,SAAS,KAAK;GAChB,SAAS,QAAQ,WAAW,OAAO;GACnC;EACF;EACA,IAAI,SAAS,KAAK;GAChB,SAAS,QAAQ,WAAW,MAAM;GAClC;EACF;EACA,IAAI,SAAS,KAAK;GAChB,SAAS,QAAQ,WAAW,cAAc;GAC1C;EACF;EACA,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;CACF,GACA;EAAC,QAAQ;EAAW;EAAU;CAAQ,CAGpB,CAAC;CAGrB,gBAAgB;EACd,MAAM,QAAQ,iBAAiB;GAC7B,SAAS,QAAQ,WAAW,MAAM;EACpC,GAAG,YAAY;EACf,aAAa,aAAa,KAAK;CACjC,GAAG,CAAC,QAAQ,WAAW,QAAQ,CAAC;CAGhC,MAAM,aAAuB,CAAC;CAC9B,IAAI,QAAQ,YACV,KAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,QAAQ,UAAU,GAAG;EAC3D,MAAM,MAAM,OAAO,QAAQ,WAAW,MAAM,KAAK,UAAU,GAAG;EAC9D,WAAW,KAAK,KAAK,IAAI,IAAI,IAAI,MAAM,GAAG,EAAE,GAAG;CACjD;CAGF,OAAO,MAAM,cACX,KACA;EACE,eAAe;EACf,aAAa;EACb,aAAa;EACb,UAAU;EACV,UAAU;EACV,SAAS;CACX,GAEA,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,gBAAgB;CAAgB,GACxD,MAAM,cAAc,MAAM,EAAE,MAAM,KAAK,GAAG,MAAM,QAAQ,UAAU,GAClE,MAAM,cAAc,MAAM;EAAE,OAAO;EAAY,MAAM;CAAK,GAAG,IAAI,MAAM,MAAM,EAAE,CACjF,GAGA,MAAM,cAAc,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,cAAc,MAAM,CAAC,GAAG,QAAQ,WAAW,CAAC,GAG7F,WAAW,SAAS,IAChB,MAAM,cACJ,KACA;EAAE,eAAe;EAAU,WAAW;CAAE,GACxC,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,aAAa,GAC3D,GAAG,WAAW,KAAK,MAAM,MACvB,MAAM,cAAc,MAAM;EAAE,KAAK;EAAG,UAAU;CAAK,GAAG,IAAI,CAC5D,CACF,IACA,MAGJ,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,WAAW;EAAG,KAAK;CAAE,GAC7C,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,QAAQ,GAAG,WAAW,GACtE,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,MAAM,GAAG,UAAU,GACnE,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,OAAO,GAAG,kBAAkB,CAC9E,GAEA,MAAM,cACJ,MACA,EAAE,UAAU,KAAK,GACjB,wDACF,CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;AC1HA,SAAgB,OAAO,EACrB,OACA,aACA,UACA,aAAa,oCACb,QAAQ,IACR,YACkC;CAClC,MAAM,QAAQ,SAAS;CACvB,MAAM,SAAS,cACV,MAAM,OAAO,gBAAgB,MAAM,OAAO,SAC3C,MAAM,OAAO;CAGjB,MAAM,YAAY,IAAI,MAAM;CAC5B,MAAM,UAAU;CAChB,MAAM,YAAY,QAAQ,IAAI,UAAU,SAAS;CAGjD,MAAM,YAAY,KAAK,YAFR,YAAY,IAAI,IAAI,OAAO,SAAS,IAAI,MAEX,QAAQ;CAEpD,OAAO,MAAM,cACX,KACA;EACE,UAAU;EACV,WAAW;EACX,YAAY;EACZ,aAAa;EACb,cAAc;EACd,eAAe;EACf,aAAa;EACb,aAAa;EACb,UAAU;CACZ,GAEA,MAAM,cAAc,MAAM;EAAE,OAAO;EAAQ,MAAM;CAAK,GAAG,SAAS,GAGlE,WAAW,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,KAAK,UAAU,IAAI,MAG5E,MAAM,cAAc,KAAK;EAAE,eAAe;EAAU,SAAS;EAAG,UAAU;CAAE,GAAG,QAAQ,GAGvF,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,KAAK,YAAY,GAG/D,MAAM,cAAc,MAAM,EAAE,OAAO,OAAO,GAAG,IAAI,IAAI,OAAO,QAAQ,CAAC,EAAE,EAAE,CAC3E;AACF;;;;;;;;;;;;;;;;AC1DA,MAAMA,iBAAc;;AAGpB,SAAS,WAAW,IAAoB;CACtC,MAAM,MAAM,KAAK,OAAO,KAAK,IAAI,IAAI,MAAM,GAAI;CAC/C,IAAI,MAAM,IAAI,OAAO,GAAG,IAAI;CAC5B,IAAI,MAAM,MAAM,OAAO,GAAG,KAAK,MAAM,MAAM,EAAE,EAAE;CAC/C,IAAI,MAAM,OAAO,OAAO,GAAG,KAAK,MAAM,MAAM,IAAI,EAAE;CAClD,OAAO,GAAG,KAAK,MAAM,MAAM,KAAK,EAAE;AACpC;;AAGA,SAAS,cAAc,UAAiE;CACzE,IAAI,IAAI,SAAS,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;CACnD,MAAM,2BAAW,IAAI,IAAmC;CACxD,KAAK,MAAM,KAAK,UAAU;EACxB,MAAM,MAAM,EAAE,mBAAmB;EACjC,IAAI,OAAO,SAAS,IAAI,GAAG;EAC3B,IAAI,CAAC,MAAM;GACT,OAAO,CAAC;GACR,SAAS,IAAI,KAAK,IAAI;EACxB;EACA,KAAK,KAAK,CAAC;CACb;CAEA,MAAM,SAAqD,CAAC;CAC5D,SAAS,KAAK,KAAsC,OAAe;EACjE,MAAM,MAAM,OAAO;EACnB,MAAM,OAAO,SAAS,IAAI,GAAG;EAC7B,IAAI,CAAC,MAAM;EACX,KAAK,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;EAC7C,KAAK,MAAM,KAAK,MAAM;GACpB,OAAO,KAAK;IAAE,SAAS;IAAG,OAAO,QAAQ,aAAa,IAAI;GAAM,CAAC;GACjE,KAAK,EAAE,IAAI,QAAQ,CAAC;EACtB;CACF;CACA,KAAK,YAAY,CAAC;CAClB,OAAO;AACT;;;;;;;AA0BA,SAAgB,cAAc,EAC5B,UAAU,aACV,UACA,YACyC;CACzC,MAAM,QAAQ,SAAS;CACvB,MAAM,CAAC,QAAQ,aAAa,SAAS,EAAE;CACvC,MAAM,CAAC,eAAe,oBAAoB,SAAS,CAAC;CACpD,MAAM,CAAC,UAAU,eAAe,SAAmB,QAAQ;CAG3D,MAAM,OAAO,cAAc,WAAW;CACtC,MAAM,gBAA4D;EAChE,MAAM,OAAO,CAAC,GAAG,IAAI;EACrB,QAAQ,UAAR;GACE,KAAK;IACH,KAAK,MAAM,GAAG,MAAM,EAAE,QAAQ,YAAY,EAAE,QAAQ,SAAS;IAC7D;GACF,KAAK;IACH,KAAK,MAAM,GAAG,OAAO,EAAE,QAAQ,UAAU,UAAU,MAAM,EAAE,QAAQ,UAAU,UAAU,EAAE;IACzF;GACF,KAAK,aAEH;EACJ;EACA,OAAO;CACT,EAAA,CAAG;CAGH,MAAM,WAAW,SACb,OAAO,QAAQ,EAAE,SAAS,QAAQ,EAAE,MAAM,YAAY,CAAC,CAAC,SAAS,OAAO,YAAY,CAAC,CAAC,IACtF;CAGJ,MAAM,WAAW,KAAK,IAAI,GAAG,SAAS,SAAS,CAAC;CAChD,MAAM,YAAY,KAAK,IAAI,eAAe,QAAQ;CAgDlD,WA5CkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,QAAQ;GACd,MAAM,WAAW,SAAS;GAC1B,IAAI,UAAU,SAAS,SAAS,QAAQ,EAAE;GAC1C;EACF;EACA,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;EACA,IAAI,IAAI,SAAS;GACf,iBAAiB,KAAK,IAAI,GAAG,gBAAgB,CAAC,CAAC;GAC/C;EACF;EACA,IAAI,IAAI,WAAW;GACjB,iBAAiB,KAAK,IAAI,UAAU,gBAAgB,CAAC,CAAC;GACtD;EACF;EAEA,IAAI,IAAI,KAAK;GACX,aAAa,SAAS;IACpB,IAAI,SAAS,UAAU,OAAO;IAC9B,IAAI,SAAS,aAAa,OAAO;IACjC,OAAO;GACT,CAAC;GACD,iBAAiB,CAAC;GAClB;EACF;EAEA,IAAI,IAAI,WAAW;GACjB,WAAW,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC;GAC/B,iBAAiB,CAAC;GAClB;EACF;EAEA,IAAI,MAAM,WAAW,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,MAAM;GAChD,WAAW,MAAM,IAAI,KAAK;GAC1B,iBAAiB,CAAC;EACpB;CACF,GACA;EAAC;EAAU;EAAW;EAAU;EAAe;EAAU;EAAU;CAAQ,CAGzD,CAAC;;CAGrB,MAAM,aAAa,SAA2B;EAC5C,IAAI,SAAS,UAAU,OAAO;EAC9B,IAAI,SAAS,aAAa,OAAO;EACjC,OAAO;CACT;CAIA,MAAM,WAAW;EADU;EAAU;EAAa;CAC7B,CAAC,CAAC,KAAK,SAAS;EACnC,MAAM,WAAW,SAAS;EAC1B,OAAO,MAAM,cACX,MACA;GAAE,KAAK;GAAM,OAAO,WAAW,MAAM,OAAO,SAAS,MAAM,OAAO;GAAK,MAAM;EAAS,GACtF,IAAI,UAAU,IAAI,EAAE,EACtB;CACF,CAAC;CAGD,MAAM,YAAkC,CAAC;CACzC,MAAM,UAAU,SAAS,MAAM,GAAGA,cAAW;CAE7C,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACvC,MAAM,QAAQ,QAAQ;EACtB,MAAM,IAAI,MAAM;EAChB,MAAM,aAAa,MAAM;EACzB,MAAM,SAAS,aAAa,MAAM;EAClC,MAAM,SAAS,KAAK,OAAO,MAAM,KAAK,KAAK,MAAM,QAAQ,IAAI,QAAQ;EACrE,MAAM,QAAQ,EAAE,UAAU,UAAU;EACpC,MAAM,OAAO,WAAW,EAAE,SAAS;EAEnC,UAAU,KACR,MAAM,cACJ,KACA;GAAE,KAAK,EAAE;GAAI,eAAe;EAAM,GAClC,MAAM,cACJ,MACA;GACE,OAAO,aAAa,MAAM,OAAO,SAAS,KAAA;GAC1C,MAAM;EACR,GACA,GAAG,OAAO,GAAG,SAAS,EAAE,MAAM,OAAO,KAAK,OAAO,MAAM,EAAE,GAAG,OAAO,KAAK,CAAC,CAAC,SAAS,CAAC,EAAE,QAAQ,MAChG,CACF,CACF;CACF;CAEA,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,OAAO,UAAU,QAAQ,EAAE,SAAS,UAAU;EACxD,YAAY;EACZ,aAAa;CACf,GAEA,MAAM,cAAc,KAAK;EAAE,eAAe;EAAO,cAAc;CAAE,GAAG,GAAG,QAAQ,GAE/E,UAAU,SAAS,IACf,MAAM,cAAc,KAAK,EAAE,eAAe,SAAS,GAAG,GAAG,SAAS,IAClE,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,UAAU,GAG5D,SACI,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,KAAK,SAAS,OAAO,UAAU,OAAO,EAAE,IACtF,IACN;AACF;;;;;;;;;;;;;;;;AC/NA,MAAM,YAAwB;CAC5B;EAAE,MAAM;EAAS,QAAQ;EAAQ,UAAU;CAAK;CAChD;EAAE,MAAM;EAAU,QAAQ;EAAU,UAAU;CAAK;CACnD;EAAE,MAAM;EAAU,QAAQ;EAAQ,UAAU;CAAK;CACjD;EAAE,MAAM;EAAU,QAAQ;EAAS,UAAU;CAAK;CAClD;EAAE,MAAM;EAAU,QAAQ;EAAQ,UAAU;CAAK;CACjD;EAAE,MAAM;EAAU,QAAQ;EAAU,UAAU;CAAK;CACnD;EAAE,MAAM;EAAU,QAAQ;EAAS,UAAU;CAAK;CAClD;EAAE,MAAM;EAAmB,QAAQ;EAAU,UAAU;CAAK;CAC5D;EAAE,MAAM;EAAY,QAAQ;EAAW,UAAU;CAAK;CACtD;EAAE,MAAM;EAAW,QAAQ;EAAe,UAAU;CAAK;CACzD;EAAE,MAAM;EAAO,QAAQ;EAAU,UAAU;CAAK;CAChD;EAAE,MAAM;EAAU,QAAQ;EAAc,UAAU;CAAM;CACxD;EAAE,MAAM;EAAS,QAAQ;EAAkB,UAAU;CAAK;CAC1D;EAAE,MAAM;EAAa,QAAQ;EAAU,UAAU;CAAK;CACtD;EAAE,MAAM;EAAK,QAAQ;EAAgB,UAAU;CAAK;CACpD;EAAE,MAAM;EAAK,QAAQ;EAAqB,UAAU;CAAK;CACzD;EAAE,MAAM;EAAY,QAAQ;EAAW,UAAU;CAAK;CACtD;EAAE,MAAM;EAAU,QAAQ;EAAU,UAAU;CAAK;CACnD;EAAE,MAAM;EAAU,QAAQ;EAAS,UAAU;CAAK;AACpD;;;;;;AAYA,SAAgB,UAAU,EAAE,YAAgD;CAC1E,MAAM,QAAQ,SAAS;CACvB,MAAM,CAAC,QAAQ,aAAa,SAAS,EAAE;CAqBvC,WAjBkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC;GAC/B;EACF;EACA,IAAI,MAAM,WAAW,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,MAC1C,WAAW,MAAM,IAAI,KAAK;CAE9B,GACA,CAAC,QAAQ,CAGS,CAAC;CAErB,MAAM,WAAW,SACb,UAAU,QACP,MACC,EAAE,KAAK,YAAY,CAAC,CAAC,SAAS,OAAO,YAAY,CAAC,KAClD,EAAE,OAAO,YAAY,CAAC,CAAC,SAAS,OAAO,YAAY,CAAC,KACpD,EAAE,SAAS,YAAY,CAAC,CAAC,SAAS,OAAO,YAAY,CAAC,CAC1D,IACA;CAGJ,MAAM,6BAAa,IAAI,IAAwB;CAC/C,KAAK,MAAM,KAAK,UAAU;EACxB,MAAM,OAAO,WAAW,IAAI,EAAE,QAAQ;EACtC,IAAI,MACF,KAAK,KAAK,CAAC;OAEX,WAAW,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;CAElC;CAEA,MAAM,OAA6B,CAAC;CACpC,KAAK,MAAM,CAAC,UAAU,cAAc,YAAY;EAC9C,KAAK,KACH,MAAM,cACJ,MACA;GAAE,KAAK,OAAO;GAAY,MAAM;GAAM,OAAO,MAAM,OAAO;EAAO,GACjE,KAAK,UACP,CACF;EACA,KAAK,MAAM,KAAK,WAAW;GACzB,MAAM,aAAa,EAAE,KAAK,OAAO,EAAE;GACnC,KAAK,KACH,MAAM,cAAc,MAAM,EAAE,KAAK,GAAG,SAAS,GAAG,EAAE,OAAO,GAAG,OAAO,aAAa,EAAE,QAAQ,CAC5F;EACF;EAEA,KAAK,KAAK,MAAM,cAAc,KAAK;GAAE,KAAK,OAAO;GAAY,QAAQ;EAAE,CAAC,CAAC;CAC3E;CAEA,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,SAAS,OAAO,WAAW,KAAA;EACrC,YAAY;EACZ,aAAa;EACb,OAAO;CACT,GACA,MAAM,cAAc,KAAK,EAAE,eAAe,SAAS,GAAG,GAAG,IAAI,CAC/D;AACF;;;;;;;;;;;;;;;;AC5GA,MAAM,mBAAmC;CACvC;EAAE,MAAM;EAAa,aAAa;CAAU;CAC5C;EAAE,MAAM;EAAQ,aAAa;CAAQ;CACrC;EAAE,MAAM;EAAS,aAAa;CAAS;CACvC;EAAE,MAAM;EAAW,aAAa;CAAU;CAC1C;EAAE,MAAM;EAAW,aAAa;CAAO;CACvC;EAAE,MAAM;EAAW,aAAa;CAAS;CACzC;EAAE,MAAM;EAAW,aAAa;CAAO;CACvC;EAAE,MAAM;EAAa,aAAa;CAAS;CAC3C;EAAE,MAAM;EAAW,aAAa;CAAS;CACzC;EAAE,MAAM;EAAU,aAAa;CAAS;CACxC;EAAE,MAAM;EAAU,aAAa;CAAW;CAC1C;EAAE,MAAM;EAAY,aAAa;CAAU;CAC3C;EAAE,MAAM;EAAS,aAAa;CAAU;CACxC;EAAE,MAAM;EAAQ,aAAa;CAAa;CAC1C;EAAE,MAAM;EAAW,aAAa;CAAO;CACvC;EAAE,MAAM;EAAW,aAAa;CAAO;CACvC;EAAE,MAAM;EAAY,aAAa;CAAU;CAC3C;EAAE,MAAM;EAAU,aAAa;CAAS;CACxC;EAAE,MAAM;EAAU,aAAa;CAAS;CACxC;EAAE,MAAM;EAAc,aAAa;CAAS;CAC5C;EAAE,MAAM;EAAU,aAAa;CAAS;CACxC;EAAE,MAAM;EAAS,aAAa;CAAS;AACzC;AAYA,MAAMC,gBAAc;;;;;;;AAQpB,SAAgB,eAAe,EAC7B,UACA,UACA,iBAC0C;CAC1C,MAAM,QAAQ,SAAS;CACvB,MAAM,CAAC,eAAe,oBAAoB,SAAS,CAAC;CAEpD,MAAM,cAAc,CAAC,GAAG,kBAAkB,GAAI,iBAAiB,CAAC,CAAE;CAElE,MAAM,WAAW,KAAK,IAAI,GAAG,YAAY,SAAS,CAAC;CACnD,MAAM,YAAY,KAAK,IAAI,eAAe,QAAQ;CAClD,MAAM,UAAU,YAAY,MAAM,GAAGA,aAAW;CA2BhD,WAvBkB,aACf,QAAgB,QAAa;EAC5B,IAAI,IAAI,QAAQ;GACd,MAAM,MAAM,YAAY;GACxB,IAAI,KAAK,SAAS,IAAI,IAAI;GAC1B;EACF;EACA,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;EACA,IAAI,IAAI,SAAS;GACf,iBAAiB,KAAK,IAAI,GAAG,gBAAgB,CAAC,CAAC;GAC/C;EACF;EACA,IAAI,IAAI,WAAW;GACjB,iBAAiB,KAAK,IAAI,UAAU,gBAAgB,CAAC,CAAC;GACtD;EACF;CACF,GACA;EAAC;EAAa;EAAW;EAAU;EAAe;EAAU;CAAQ,CAGlD,CAAC;CAErB,MAAM,QAA8B,CAAC;CACrC,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACvC,MAAM,MAAM,QAAQ;EACpB,MAAM,aAAa,MAAM;EACzB,MAAM,SAAS,aAAa,OAAO;EACnC,MAAM,cAAc,IAAI,KAAK,OAAO,EAAE;EAEtC,MAAM,KACJ,MAAM,cACJ,KACA;GAAE,KAAK,IAAI;GAAM,eAAe;EAAM,GACtC,MAAM,cACJ,MACA;GACE,OAAO,aAAa,MAAM,OAAO,SAAS,KAAA;GAC1C,MAAM;EACR,GACA,GAAG,SAAS,cAAc,IAAI,aAChC,CACF,CACF;CACF;CAEA,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU;EACV,YAAY;EACZ,aAAa;EACb,OAAO;CACT,GACA,MAAM,cAAc,KAAK,EAAE,eAAe,SAAS,GAAG,GAAG,KAAK,CAChE;AACF;;;;;;;;;;;;;;AChHA,SAAS,cAAc,GAAmB;CACxC,OAAO,KAAK,MAAO,GAAG,KAAK,MAAM,IAAI,GAAI,EAAE,KAAK,GAAG;AACrD;;AAGA,SAAS,YAAY,YAAqB,aAA8B;CACtE,IAAI,eAAe,KAAA,KAAa,gBAAgB,KAAA,GAAW,OAAO;CAClE,OAAO,IAAI,WAAW,IAAI;AAC5B;;;;;;;;;;;AAYA,SAAgB,YAAY,EAC1B,QACA,cACA,UACA,cACA,YACuC;CACvC,MAAM,CAAC,YAAY,iBAAiB,SAAS,EAAE;CAC/C,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CAGtC,MAAM,WAAW,aACb,OAAO,QACJ,MACC,EAAE,GAAG,YAAY,CAAC,CAAC,SAAS,WAAW,YAAY,CAAC,KACpD,EAAE,MAAM,YAAY,CAAC,CAAC,SAAS,WAAW,YAAY,CAAC,CAC3D,IACA;CAGJ,MAAM,gBAAgB,SAAS,SAAS,IAAI,KAAK,IAAI,QAAQ,SAAS,SAAS,CAAC,IAAI;CAyCpF,WAvCkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;EACA,IAAI,IAAI,SAAS;GACf,WAAW,SAAU,OAAO,IAAI,OAAO,IAAI,KAAK,IAAI,GAAG,SAAS,SAAS,CAAC,CAAE;GAC5E;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,SAAU,OAAO,SAAS,SAAS,IAAI,OAAO,IAAI,CAAE;GAC/D;EACF;EACA,IAAI,IAAI,QAAQ;GACd,MAAM,WAAW,SAAS;GAC1B,IAAI,UAAU,SAAS,SAAS,EAAE;GAClC;EACF;EACA,IAAI,UAAU,OAAO,cAAc;GACjC,MAAM,WAAW,SAAS;GAC1B,IAAI,UAAU,aAAa,SAAS,EAAE;GACtC;EACF;EACA,IAAI,IAAI,aAAa,IAAI,QAAQ;GAC/B,eAAe,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC;GACzC,UAAU,CAAC;GACX;EACF;EAEA,IAAI,SAAS,MAAM,WAAW,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,MAAM;GACzD,eAAe,SAAS,OAAO,KAAK;GACpC,UAAU,CAAC;GACX;EACF;CACF,GACA;EAAC;EAAU;EAAe;EAAU;EAAc;CAAQ,CAGxC,CAAC;CAGrB,MAAM,QAA2B,CAAC;CAGlC,MAAM,KACJ,MAAM,cACJ,KACA;EAAE,KAAK;EAAU,eAAe;EAAO,cAAc;CAAE,GACvD,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,KAAK,GACnD,MAAM,cACJ,MACA,CAAC,GACD,cAAc,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,SAAS,CACvE,GACA,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,GAAG,GACjD,aACI,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,KAAK,SAAS,OAAO,GAAG,OAAO,QAAQ,IACrF,IACN,CACF;CAGA,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,QAAQ,SAAS;EACvB,MAAM,WAAW,MAAM,OAAO;EAC9B,MAAM,WAAW,MAAM;EACvB,MAAM,SAAS,WAAW,MAAM;EAChC,MAAM,SAAS,cAAc,MAAM,aAAa;EAChD,MAAM,WAAW,YAAY,MAAM,YAAY,MAAM,WAAW;EAChE,MAAM,aAAa,WAAW,OAAO;EAErC,MAAM,KACJ,MAAM,cACJ,MACA;GACE,KAAK,MAAM;GACX,MAAM;GACN,OAAO,WAAW,SAAS,WAAW,UAAU,KAAA;EAClD,GACA,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,GAAG,OAAO,SAAS,CAAC,EAAE,QAAQ,SAAS,SAAS,EAAE,IAAI,YACtG,CACF;CACF;CAEA,IAAI,SAAS,WAAW,GACtB,MAAM,KAAK,MAAM,cAAc,MAAM;EAAE,KAAK;EAAS,UAAU;CAAK,GAAG,WAAW,CAAC;CAGrF,MAAM,QAAQ,eACV,8CACA;CAEJ,OAAO,MAAM,cACX,QACA;EAAE,OAAO;EAAQ,aAAa;EAAU,YAAY;EAAO,OAAO;CAAG,GACrE,MAAM,cAAc,KAAK;EAAE,eAAe;EAAU,SAAS;CAAE,GAAG,GAAG,KAAK,CAC5E;AACF;;;;;;;;;;;;AC3IA,MAAM,OAAoB;CACxB;EAAE,IAAI;EAAW,OAAO;CAAK;CAC7B;EAAE,IAAI;EAAU,OAAO;CAAK;CAC5B;EAAE,IAAI;EAAe,OAAO;CAAK;CACjC;EAAE,IAAI;EAAc,OAAO;CAAK;CAChC;EAAE,IAAI;EAAY,OAAO;CAAK;AAChC;;AAGA,MAAM,mBAAoC;CACxC;EAAE,KAAK;EAAsB,OAAO;EAAQ,OAAO;EAAM,UAAU;CAAU;CAC7E;EAAE,KAAK;EAAqB,OAAO;EAAU,OAAO;EAAM,UAAU;CAAU;CAC9E;EAAE,KAAK;EAAgB,OAAO;EAAU,OAAO;EAAO,UAAU;CAAU;CAC1E;EAAE,KAAK;EAAa,OAAO;EAAM,OAAO;EAAM,UAAU;CAAU;CAClE;EAAE,KAAK;EAAgB,OAAO;EAAQ,OAAO;EAAO,UAAU;CAAU;CACxE;EAAE,KAAK;EAAW,OAAO;EAAU,OAAO;EAAO,UAAU;CAAU;CACrE;EAAE,KAAK;EAAS,OAAO;EAAQ,OAAO;EAAiB,UAAU;CAAS;CAC1E;EAAE,KAAK;EAAe,OAAO;EAAW,OAAO;EAAM,UAAU;CAAS;CACxE;EAAE,KAAK;EAAY,OAAO;EAAQ,OAAO;EAAO,UAAU;CAAS;CACnE;EAAE,KAAK;EAAgB,OAAO;EAAQ,OAAO;EAAM,UAAU;CAAS;CACtE;EAAE,KAAK;EAAe,OAAO;EAAQ,OAAO;EAAM,UAAU;CAAS;CACrE;EAAE,KAAK;EAAa,OAAO;EAAW,OAAO;EAAM,UAAU;CAAS;CACtE;EACE,KAAK;EACL,OAAO;EACP,OAAO;EACP,UAAU;CACZ;CACA;EAAE,KAAK;EAAkB,OAAO;EAAS,OAAO;EAAM,UAAU;CAAc;CAC9E;EACE,KAAK;EACL,OAAO;EACP,OAAO;EACP,UAAU;CACZ;CACA;EAAE,KAAK;EAAY,OAAO;EAAQ,OAAO;EAAM,UAAU;CAAa;CACtE;EAAE,KAAK;EAAiB,OAAO;EAAQ,OAAO;EAAO,UAAU;CAAa;CAC5E;EAAE,KAAK;EAAc,OAAO;EAAS,OAAO;EAAM,UAAU;CAAa;CACzE;EACE,KAAK;EACL,OAAO;EACP,OAAO;EACP,UAAU;CACZ;CACA;EAAE,KAAK;EAAS,OAAO;EAAM,OAAO;EAAQ,UAAU;CAAa;CACnE;EAAE,KAAK;EAAgB,OAAO;EAAQ,OAAO;EAAO,UAAU;CAAW;CACzE;EAAE,KAAK;EAAW,OAAO;EAAS,OAAO;EAAO,UAAU;CAAW;CACrE;EACE,KAAK;EACL,OAAO;EACP,OAAO;EACP,UAAU;CACZ;AACF;;;;;;AAmBA,SAAS,YAAY,OAA8D;CACjF,IAAI,OAAO,UAAU,WAAW,OAAO;CACvC,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,OAAO;AACT;;AAGA,SAAS,YAAY,SAAgC;CAEnD,IADa,YAAY,QAAQ,KAC1B,MAAM,WAAW,OAAO,QAAQ,QAAQ,MAAM;CACrD,OAAO,OAAO,QAAQ,KAAK;AAC7B;;;;;;;;;;AAWA,SAAgB,WAAW,EACzB,UACA,UACA,QACA,YACsC;CACtC,MAAM,QAAQ,YAAY;CAC1B,MAAM,CAAC,WAAW,gBAAgB,SAAS,CAAC;CAC5C,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CAEtC,MAAM,aAAa,KAAK;CACxB,MAAM,WAAW,MAAM,QAAQ,MAAM,EAAE,aAAa,WAAW,EAAE;CAwCjE,WAtCkB,aACf,QAAgB,QAAa;EAC5B,IAAI,IAAI,WAAW;GACjB,cAAc,SAAU,OAAO,IAAI,OAAO,IAAI,KAAK,SAAS,CAAE;GAC9D,UAAU,CAAC;GACX;EACF;EACA,IAAI,IAAI,YAAY;GAClB,cAAc,SAAU,OAAO,KAAK,SAAS,IAAI,OAAO,IAAI,CAAE;GAC9D,UAAU,CAAC;GACX;EACF;EACA,IAAI,IAAI,SAAS;GACf,WAAW,SAAU,OAAO,IAAI,OAAO,IAAI,SAAS,SAAS,CAAE;GAC/D;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,SAAU,OAAO,SAAS,SAAS,IAAI,OAAO,IAAI,CAAE;GAC/D;EACF;EACA,IAAI,IAAI,QAAQ;GACd,MAAM,UAAU,SAAS;GACzB,IAAI,CAAC,SAAS;GACd,MAAM,OAAO,YAAY,QAAQ,KAAK;GACtC,IAAI,SAAS,WACX,SAAS,QAAQ,KAAK,CAAC,QAAQ,KAAK;QAC/B,IAAI,QACT,OAAO,QAAQ,KAAK,QAAQ,OAAO,OAAO,QAAQ,KAAK,GAAG,IAAI;GAEhE;EACF;EACA,IAAI,IAAI,QACN,SAAS;CAEb,GACA;EAAC;EAAW;EAAQ;EAAU;EAAU;EAAQ;CAAQ,CAGtC,CAAC;CAGrB,MAAM,cAAiC,CAAC;CACxC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;EACjB,MAAM,WAAW,MAAM;EACvB,YAAY,KACV,MAAM,cACJ,MACA;GAAE,KAAK,IAAI;GAAI,MAAM;GAAU,OAAO,WAAW,SAAS;GAAQ,WAAW;EAAS,GACtF,WAAW,IAAI,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,EAC9C,CACF;EACA,IAAI,IAAI,KAAK,SAAS,GACpB,YAAY,KAAK,MAAM,cAAc,MAAM;GAAE,KAAK,OAAO;GAAK,UAAU;EAAK,GAAG,GAAG,CAAC;CAExF;CAGA,MAAM,kBAAqC,CAAC;CAC5C,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,UAAU,SAAS;EACzB,MAAM,WAAW,MAAM;EACvB,MAAM,SAAS,WAAW,MAAM;EAChC,MAAM,OAAO,YAAY,QAAQ,KAAK;EACtC,MAAM,aAAa,YAAY,OAAO;EACtC,MAAM,WAAW,SAAS,YAAY,gBAAgB;EAEtD,gBAAgB,KACd,MAAM,cACJ,MACA;GAAE,KAAK,QAAQ;GAAK,MAAM;GAAU,OAAO,WAAW,SAAS,KAAA;EAAU,GACzE,GAAG,OAAO,GAAG,WAAW,IAAI,QAAQ,QAAQ,UAC9C,CACF;CACF;CAEA,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cACJ,KACA,EAAE,eAAe,SAAS,GAC1B,MAAM,cAAc,KAAK;EAAE,eAAe;EAAO,cAAc;CAAE,GAAG,GAAG,WAAW,GAClF,MAAM,cAAc,KAAK,EAAE,eAAe,SAAS,GAAG,GAAG,eAAe,CAC1E,CACF;AACF;;;;;;;;;;;ACjNA,MAAM,gBAA8B;CAClC;EAAE,IAAI;EAAQ,OAAO;EAAM,aAAa;CAA6B;CACrE;EAAE,IAAI;EAAS,OAAO;EAAM,aAAa;CAAmB;CAC5D;EAAE,IAAI;EAAc,OAAO;EAAc,aAAa;CAAU;CAChE;EAAE,IAAI;EAAW,OAAO;EAAW,aAAa;CAAY;CAC5D;EAAE,IAAI;EAAa,OAAO;EAAa,aAAa;CAAc;CAClE;EAAE,IAAI;EAAW,OAAO;EAAW,aAAa;CAAc;AAChE;;;;;;;;;AAoBA,SAAgB,YAAY,EAC1B,cACA,UACA,YACuC;CACvC,MAAM,CAAC,QAAQ,aAAa,SAC1B,KAAK,IACH,cAAc,WAAW,MAAM,EAAE,OAAO,YAAY,GACpD,CACF,CACF;CAwBA,WAtBkB,aACf,QAAgB,QAAa;EAC5B,IAAI,IAAI,SAAS;GACf,WAAW,SAAU,OAAO,IAAI,OAAO,IAAI,cAAc,SAAS,CAAE;GACpE;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,SAAU,OAAO,cAAc,SAAS,IAAI,OAAO,IAAI,CAAE;GACpE;EACF;EACA,IAAI,IAAI,QAAQ;GACd,MAAM,WAAW,cAAc;GAC/B,IAAI,UAAU,SAAS,SAAS,EAAE;GAClC;EACF;EACA,IAAI,IAAI,QACN,SAAS;CAEb,GACA;EAAC;EAAQ;EAAU;CAAQ,CAGT,CAAC;CAErB,MAAM,QAA2B,CAAC;CAClC,KAAK,IAAI,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;EAC7C,MAAM,QAAQ,cAAc;EAC5B,MAAM,WAAW,MAAM,OAAO;EAC9B,MAAM,WAAW,MAAM;EACvB,MAAM,SAAS,WAAW,MAAM;EAChC,MAAM,SAAS,WAAW,UAAU;EAEpC,MAAM,KACJ,MAAM,cACJ,MACA;GACE,KAAK,MAAM;GACX,MAAM;GACN,OAAO,WAAW,SAAS,WAAW,UAAU,KAAA;EAClD,GACA,GAAG,OAAO,GAAG,MAAM,MAAM,OAAO,EAAE,EAAE,GAAG,MAAM,YAAY,MAAM,GAAG,EAAE,IAAI,QAC1E,CACF;CACF;CAEA,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cAAc,KAAK;EAAE,eAAe;EAAU,SAAS;CAAE,GAAG,GAAG,KAAK,CAC5E;AACF;;;;;;;;;;;;;ACpGA,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAmBA,SAAS,oBAAoB,SAAkC;CAC7D,MAAM,QAAQ,QAAQ,YAAY;CAClC,MAAM,QAA2B,CAAC;CAClC,IAAI,YAAY;CAGhB,KAAK,MAAM,QAAQ,cAAc;EAC/B,MAAM,MAAM,MAAM,QAAQ,IAAI;EAC9B,IAAI,OAAO,GAAG;GACZ,IAAI,MAAM,WACR,MAAM,KACJ,MAAM,cAAc,MAAM,EAAE,KAAK,QAAQ,YAAY,GAAG,QAAQ,MAAM,WAAW,GAAG,CAAC,CACvF;GAEF,MAAM,KACJ,MAAM,cACJ,MACA;IAAE,KAAK,UAAU;IAAO,OAAO;IAAO,MAAM;GAAK,GACjD,QAAQ,MAAM,KAAK,MAAM,KAAK,MAAM,CACtC,CACF;GACA,YAAY,MAAM,KAAK;EACzB;CACF;CAEA,IAAI,YAAY,QAAQ,QACtB,MAAM,KAAK,MAAM,cAAc,MAAM,EAAE,KAAK,WAAW,GAAG,QAAQ,MAAM,SAAS,CAAC,CAAC;CAGrF,OAAO,MAAM,SAAS,IAClB,MAAM,cAAc,MAAM,MAAM,GAAG,KAAK,IACxC,MAAM,cAAc,MAAM,MAAM,OAAO;AAC7C;;;;;;;;;AAUA,SAAgB,cAAc,EAC5B,OACA,SACA,eAAe,KACf,cAAc,KACd,WACA,YACyC;CACzC,MAAM,CAAC,UAAU,eAAe,SAA+B,QAAQ;CAoBvE,WAlBkB,aACf,QAAgB,QAAa;EAC5B,IAAI,IAAI,WAAW,IAAI,WAAW;GAChC,aAAa,SAAU,SAAS,YAAY,WAAW,SAAU;GACjE;EACF;EACA,IAAI,IAAI,QAAQ;GACd,IAAI,aAAa,WAAW,UAAU;QACjC,SAAS;GACd;EACF;EACA,IAAI,IAAI,QACN,SAAS;CAEb,GACA;EAAC;EAAU;EAAW;CAAQ,CAGZ,CAAC;CAErB,OAAO,MAAM,cACX,QACA;EACE;EACA,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cACJ,KACA;EAAE,eAAe;EAAU,SAAS;CAAE,GACtC,oBAAoB,OAAO,GAC3B,MAAM,cACJ,KACA;EAAE,eAAe;EAAU,WAAW;CAAE,GACxC,MAAM,cACJ,MACA;EAAE,MAAM,aAAa;EAAW,OAAO,aAAa,YAAY,QAAQ,KAAA;CAAU,GAClF,aAAa,YAAY,KAAK,iBAAiB,KAAK,cACtD,GACA,MAAM,cACJ,MACA;EAAE,MAAM,aAAa;EAAU,OAAO,aAAa,WAAW,SAAS,KAAA;CAAU,GACjF,aAAa,WAAW,KAAK,gBAAgB,KAAK,aACpD,CACF,CACF,CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;ACvGA,SAAgB,YAAY,EAC1B,OACA,eAAe,IACf,cAAc,IACd,WACA,UACA,YAAY,OAC2B;CACvC,MAAM,CAAC,OAAO,YAAY,SAAS,YAAY;CAC/C,MAAM,CAAC,QAAQ,aAAa,SAAS,aAAa,MAAM;;CAYxD,SAAS,YAAY,OAAe,KAAU,OAA8B;EAC1E,MAAM,EAAE,OAAO,WAAW;EAE1B,IAAI,IAAI,aAAa,SAAS,GAC5B,OAAO;GAAE,OAAO,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,MAAM,MAAM,MAAM;GAAG,QAAQ,SAAS;EAAE;EAEvF,IAAI,IAAI,UAAU,SAAS,MAAM,QAC/B,OAAO;GAAE,OAAO,MAAM,MAAM,GAAG,MAAM,IAAI,MAAM,MAAM,SAAS,CAAC;GAAG;EAAO;EAE3E,IAAI,IAAI,QAAQ,UAAU,KACxB,OAAO;GAAE,OAAO,MAAM,MAAM,GAAG,MAAM;GAAG;EAAO;EAEjD,IAAI,IAAI,QAAQ,UAAU,KAAK;GAE7B,MAAM,QADS,MAAM,MAAM,GAAG,MACX,CAAC,CAAC,MAAM,YAAY;GACvC,MAAM,WAAW,QAAQ,MAAM,EAAE,CAAE,SAAS;GAC5C,OAAO;IAAE,OAAO,MAAM,MAAM,GAAG,QAAQ,IAAI,MAAM,MAAM,MAAM;IAAG,QAAQ;GAAS;EACnF;EACA,OAAO;CACT;;CAGA,SAAS,gBAAgB,OAAe,KAAU,OAA0B;EAC1E,MAAM,EAAE,OAAO,WAAW;EAE1B,IAAI,IAAI,WAAW,OAAO,KAAK,IAAI,GAAG,SAAS,CAAC;EAChD,IAAI,IAAI,YAAY,OAAO,KAAK,IAAI,MAAM,QAAQ,SAAS,CAAC;EAC5D,IAAI,IAAI,QAAS,IAAI,QAAQ,UAAU,KAAM,OAAO;EACpD,IAAI,IAAI,OAAQ,IAAI,QAAQ,UAAU,KAAM,OAAO,MAAM;EACzD,OAAO;CACT;CAqCA,WAnCkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;EACA,IAAI,IAAI,QAAQ;GACd,UAAU,KAAK;GACf;EACF;EAEA,MAAM,QAAmB;GAAE;GAAO;EAAO;EAEzC,MAAM,aAAa,YAAY,OAAO,KAAK,KAAK;EAChD,IAAI,YAAY;GACd,SAAS,WAAW,KAAK;GACzB,UAAU,WAAW,MAAM;GAC3B;EACF;EAEA,MAAM,YAAY,gBAAgB,OAAO,KAAK,KAAK;EACnD,IAAI,aAAa,GAAG;GAClB,UAAU,SAAS;GACnB;EACF;EAGA,IAAI,MAAM,WAAW,KAAK,MAAM,SAAS,WAAW;GAClD,UAAU,SAAS,KAAK,MAAM,GAAG,MAAM,IAAI,QAAQ,KAAK,MAAM,MAAM,CAAC;GACrE,WAAW,SAAS,OAAO,CAAC;EAC9B;CACF,GACA;EAAC;EAAO;EAAQ;EAAW;EAAW;CAAQ,CAG5B,CAAC;CAGrB,MAAM,eAAe,MAAM,MAAM,GAAG,MAAM;CAC1C,MAAM,WAAW,MAAM,WAAW;CAClC,MAAM,cAAc,MAAM,MAAM,SAAS,CAAC;CAC1C,MAAM,eAAe,SAAS;CAE9B,OAAO,MAAM,cACX,QACA;EACE;EACA,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cACJ,KACA;EAAE,eAAe;EAAU,SAAS;CAAE,GACtC,MAAM,cACJ,MACA,MACA,iBAAiB,iBAAiB,cAAc,KAAK,KACrD,MAAM,cAAc,MAAM,EAAE,SAAS,KAAK,GAAG,QAAQ,GACrD,aACA,MAAM,WAAW,KAAK,cAClB,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,IAAI,aAAa,IAC/D,IACN,CACF,CACF;AACF;;;;;;;;;;;;;AChIA,SAASC,aAAW,QAAgE;CAClF,QAAQ,QAAR;EACE,KAAK,MACH,OAAO;GAAE,MAAM;GAAK,OAAO;EAAQ;EACrC,KAAK,QACH,OAAO;GAAE,MAAM;GAAK,OAAO;EAAS;EACtC,KAAK,SACH,OAAO;GAAE,MAAM;GAAK,OAAO;EAAM;CACrC;AACF;;;;;;;AAQA,SAAgB,YAAY,EAC1B,QAAQ,eACR,YACuC;CACvC,MAAM,CAAC,QAAQ,aAAa,SAAS,aAAa;CAmBlD,WAfkB,aACf,QAAgB,QAAa;EAC5B,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;EAEA,IAAI,OAAO,YAAY,MAAM,KAAK;GAChC,UAAU,iBAAiB,CAAC;GAC5B;EACF;CACF,GACA,CAAC,QAAQ,CAGS,CAAC;CAErB,MAAM,QAA2B,CAAC;CAElC,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,QAAQ,OAAO;EACrB,MAAM,EAAE,MAAM,UAAUA,aAAW,MAAM,MAAM;EAE/C,MAAM,KACJ,MAAM,cACJ,KACA;GAAE,KAAK,MAAM;GAAK,eAAe;EAAS,GAC1C,MAAM,cACJ,KACA,EAAE,eAAe,MAAM,GACvB,MAAM,cAAc,MAAM,EAAE,MAAM,GAAG,GAAG,KAAK,EAAE,GAC/C,MAAM,cAAc,MAAM,EAAE,MAAM,MAAM,WAAW,QAAQ,GAAG,MAAM,KAAK,GACzE,MAAM,SAAS,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,MAAM,MAAM,QAAQ,IAAI,IACvF,GACA,MAAM,UACF,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,QAAQ,MAAM,SAAS,IACrE,IACN,CACF;CACF;CAEA,MAAM,UAAU,OAAO,QAAQ,MAAM,EAAE,WAAW,IAAI,CAAC,CAAC;CACxD,MAAM,YAAY,OAAO,QAAQ,MAAM,EAAE,WAAW,MAAM,CAAC,CAAC;CAC5D,MAAM,aAAa,OAAO,QAAQ,MAAM,EAAE,WAAW,OAAO,CAAC,CAAC;CAE9D,MAAM,WAAW,GAAG,QAAQ,QAAQ,UAAU,QAAQ,WAAW;CAEjE,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP;EACA,aAAa,aAAa,IAAI,UAAU,YAAY,IAAI,YAAY;EACpE,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cAAc,KAAK;EAAE,eAAe;EAAU,SAAS;CAAE,GAAG,GAAG,KAAK,CAC5E;AACF;;;;;;;AAQA,SAAgB,mBAAkC;CAChD,MAAM,UAAyB,CAAC;CAGhC,MAAM,cAAc,QAAQ;CAC5B,MAAM,YAAY,OAAO,SAAS,YAAY,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAK,EAAE;CACzE,QAAQ,KAAK;EACX,OAAO;EACP,QAAQ;EACR,QAAQ,aAAa,KAAK,OAAO;EACjC,SAAS,YAAY,KAAK,oBAAoB,KAAA;CAChD,CAAC;CAGD,QAAQ,KAAK;EACX,OAAO;EACP,QAAQ,GAAG,QAAQ,SAAS,GAAG,QAAQ;EACvC,QAAQ;CACV,CAAC;CAGD,MAAM,WACJ,QAAQ,IAAI,aAAa,GAAG,QAAQ,IAAI,QAAQ,QAAQ,IAAI,eAAe,IAAI;CACjF,QAAQ,KAAK;EACX,OAAO;EACP,QAAQ;EACR,QAAQ;CACV,CAAC;CAGD,MAAM,QAAQ,KAAK,MAAM,QAAQ,YAAY,CAAC,CAAC,WAAW,OAAO,IAAI;CACrE,QAAQ,KAAK;EACX,OAAO;EACP,QAAQ,GAAG,MAAM;EACjB,QAAQ,QAAQ,MAAM,OAAO,QAAQ,MAAM,SAAS;EACpD,SAAS,SAAS,MAAM,gBAAgB,KAAA;CAC1C,CAAC;CAGD,MAAM,YAAY,KAAK,MAAM,QAAQ,OAAO,IAAI,EAAE;CAClD,QAAQ,KAAK;EACX,OAAO;EACP,QACE,YAAY,KACR,GAAG,UAAU,MACb,GAAG,KAAK,MAAM,YAAY,EAAE,EAAE,KAAK,YAAY,GAAG;EACxD,QAAQ;CACV,CAAC;CAED,OAAO;AACT;;;;;;;;;;;;;;;;;;;;AClIA,MAAM,YAAY,IAAI,IAAI;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,iBAAiB;;AAEvB,MAAMC,gBAAc;;AAEpB,MAAM,YAAY;;AAGlB,MAAM,mBAAqE;CACzE,GAAG;EAAE,OAAO;EAAK,OAAO;CAAU;CAClC,GAAG;EAAE,OAAO;EAAK,OAAO;CAAU;CAClC,GAAG;EAAE,OAAO;EAAK,OAAO;CAAU;CAClC,GAAG;EAAE,OAAO;EAAK,OAAO;CAAU;CAClC,GAAG;EAAE,OAAO;EAAK,OAAO;CAAU;CAClC,KAAK;EAAE,OAAO;EAAK,OAAO;CAAU;CACpC,KAAK;EAAE,OAAO;EAAK,OAAO;CAAU;AACtC;;;;;;AA2BA,SAAS,UAAU,KAAa,WAAmB,YAAyB,OAAqB;CAC/F,IAAI,QAAQ,aAAa,WAAW,UAAU,gBAAgB;CAE9D,IAAI;CACJ,IAAI;EAGF,UAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;CACpD,QAAQ;EACN;CACF;CAEA,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,WAAW,UAAU,gBAAgB;EACzC,IAAI,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,SAAS,OAAO,MAAM,SAAS;OAGjE,CAAC,MAAM,KAAK,WAAW,MAAM,GAAG;EAAA;EAGtC,MAAM,WAAW,KAAK,KAAK,MAAM,IAAI;EACrC,IAAI,MAAM,YAAY,GAAG;GACvB,IAAI,UAAU,IAAI,MAAM,IAAI,GAAG;GAC/B,UAAU,UAAU,WAAW,YAAY,QAAQ,CAAC;EACtD,OAAO,IAAI,MAAM,OAAO,GACtB,IAAI;GACF,MAAM,KAAK,SAAS,QAAQ;GAC5B,WAAW,KAAK;IACd,MAAM,SAAS,WAAW,QAAQ,CAAC,CAAC,QAAQ,OAAO,GAAG;IACtD,OAAO,GAAG;GACZ,CAAC;EACH,QAAQ,CAER;CAEJ;AACF;;;;;;AAOA,SAAS,kBAAkB,WAAwC;CACjE,MAAM,4BAAY,IAAI,IAAoB;CAC1C,IAAI;EACF,MAAM,SAAS,SAAS,+BAA+B;GACrD,KAAK;GACL,UAAU;GACV,SAAS;EACX,CAAC;EACD,KAAK,MAAM,QAAQ,OAAO,KAAK,CAAC,CAAC,MAAM,IAAI,GAAG;GAC5C,IAAI,CAAC,MAAM;GAEX,MAAM,SAAS,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK;GAEhE,IAAI,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK;GAClC,MAAM,WAAW,SAAS,QAAQ,MAAM;GACxC,IAAI,WAAW,GAAG,WAAW,SAAS,MAAM,WAAW,CAAC;GACxD,UAAU,IAAI,SAAS,QAAQ,OAAO,GAAG,GAAG,UAAU,GAAG;EAC3D;CACF,QAAQ,CAER;CACA,OAAO;AACT;;;;;;AAOA,SAAS,cAAc,OAA8B;CACnD,MAAM,OAAiB;EAAE,MAAM;EAAI,MAAM;EAAI,OAAO;EAAM,UAAU,CAAC;EAAG,UAAU;CAAK;CAEvF,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,QAAQ,KAAK,KAAK,MAAM,GAAG;EACjC,IAAI,UAAU;EACd,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,MAAM,SAAS,MAAM,MAAM,SAAS;GACpC,MAAM,WAAW,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG;GAC/C,IAAI,QAAQ,QAAQ,SAAS,MAAM,MAAM,EAAE,SAAS,IAAI;GACxD,IAAI,CAAC,OAAO;IACV,QAAQ;KAAE,MAAM;KAAM,MAAM;KAAU,OAAO,CAAC;KAAQ,UAAU,CAAC;KAAG,UAAU;IAAM;IACpF,IAAI,QAAQ,MAAM,OAAO;IACzB,QAAQ,SAAS,KAAK,KAAK;GAC7B;GACA,UAAU;EACZ;CACF;CAGA,SAAS,SAAS,MAAsB;EACtC,KAAK,SAAS,MAAM,GAAG,MAAM;GAC3B,IAAI,EAAE,UAAU,EAAE,OAAO,OAAO,EAAE,QAAQ,KAAK;GAC/C,OAAO,EAAE,KAAK,cAAc,EAAE,IAAI;EACpC,CAAC;EACD,KAAK,MAAM,SAAS,KAAK,UAAU,SAAS,KAAK;CACnD;CACA,SAAS,IAAI;CACb,OAAO;AACT;;;;AAKA,SAAS,YACP,MACA,OACA,cACA,QACM;CACN,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,KAAK;EAC7C,MAAM,QAAQ,KAAK,SAAS;EAC5B,MAAM,SAAS,MAAM,KAAK,SAAS,SAAS;EAC5C,IAAI,MAAM,OAAO;GACf,MAAM,aAAa,aAAa,IAAI,MAAM,IAAI;GAC9C,OAAO,KAAK;IACV,OAAO;KAAE,MAAM,MAAM,OAAO;KAAK,OAAO;IAAE;IAC1C;IACA;IACA,OAAO;IACP,UAAU;IACV,YAAY,MAAM,SAAS;GAC7B,CAAC;GACD,IAAI,YACF,YAAY,OAAO,QAAQ,GAAG,cAAc,MAAM;EAEtD,OAAO,IAAI,MAAM,MACf,OAAO,KAAK;GACV,OAAO,MAAM;GACb;GACA;GACA,OAAO;GACP,UAAU;GACV,YAAY;EACd,CAAC;CAEL;AACF;;;;;;;;AASA,SAAS,gBAAgB,YAAyB,QAA6B;CAC7E,IAAI,CAAC,QAAQ,OAAO,WAAW,MAAM,GAAGA,aAAW;CAEnD,MAAM,QAAQ,OAAO,YAAY;CACjC,MAAM,SAAgD,CAAC;CAEvD,KAAK,MAAM,SAAS,YAAY;EAC9B,MAAM,YAAY,MAAM,KAAK,YAAY;EACzC,MAAM,MAAM,UAAU,QAAQ,KAAK;EACnC,IAAI,QAAQ,IAAI;EAGhB,IAAI,QAAQ;EACZ,IAAI,QAAQ,GAAG,SAAS;OACnB,IAAI,UAAU,MAAM,OAAO,OAAO,UAAU,MAAM,OAAO,KAAK,SAAS;EAE5E,SAAS,KAAK,IAAI,GAAG,MAAM,GAAG;EAE9B,MAAM,YAAY,KAAK,IAAI,IAAI,MAAM,SAAS;EAC9C,SAAS,KAAK,IAAI,GAAG,MAAM,WAAW,EAAE;EAExC,OAAO,KAAK;GAAE;GAAO;EAAM,CAAC;CAC9B;CAEA,OAAO,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;CACvC,OAAO,OAAO,MAAM,GAAGA,aAAW,CAAC,CAAC,KAAK,MAAM,EAAE,KAAK;AACxD;;;;;;;AAQA,SAAgB,WAAW,EACzB,WACA,UACA,UACA,gBAAgB,MACsB;CACtC,MAAM,QAAQ,SAAS;CAGvB,MAAM,aAAa,cAA2B;EAC5C,MAAM,UAAuB,CAAC;EAC9B,UAAU,WAAW,WAAW,SAAS,CAAC;EAC1C,QAAQ,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;EACxC,OAAO;CACT,GAAG,CAAC,SAAS,CAAC;CAEd,MAAM,eAAe,cAAc,kBAAkB,SAAS,GAAG,CAAC,SAAS,CAAC;CAG5E,MAAM,WAAW,cAAc,cAAc,UAAU,GAAG,CAAC,UAAU,CAAC;CAEtE,MAAM,CAAC,QAAQ,aAAa,SAAS,aAAa;CAClD,MAAM,CAAC,eAAe,oBAAoB,SAAS,CAAC;CACpD,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,CAAC,cAAc,mBAAmB,yBAAsB,IAAI,IAAI,CAAC;CAGvE,MAAM,YAAY,cAA0B;EAC1C,IAAI,CAAC,YAAY,OAAO,CAAC;EACzB,MAAM,OAAmB,CAAC;EAC1B,YAAY,UAAU,GAAG,cAAc,IAAI;EAE3C,IAAI,CAAC,QAAQ,OAAO;EACpB,MAAM,QAAQ,OAAO,YAAY;EACjC,OAAO,KAAK,QACT,SACC,KAAK,MAAM,KAAK,YAAY,CAAC,CAAC,SAAS,KAAK,KAC3C,KAAK,SAAS,KAAK,MAAM,KAAK,YAAY,CAAC,CAAC,SAAS,KAAK,CAC/D;CACF,GAAG;EAAC;EAAY;EAAU;EAAc;CAAM,CAAC;CAE/C,MAAM,cAAc,cACX,CAAC,aAAa,gBAAgB,YAAY,MAAM,IAAI,CAAC,GAC5D;EAAC;EAAY;EAAY;CAAM,CACjC;CAEA,MAAM,YAAY,aAAa,UAAU,SAAS,YAAY;CAC9D,MAAM,WAAW,KAAK,IAAI,GAAG,YAAY,CAAC;CAC1C,MAAM,YAAY,KAAK,IAAI,eAAe,QAAQ;CAGlD,MAAM,YAAY,aAAa,YAAoB;EACjD,iBAAiB,SAAS;GACxB,MAAM,OAAO,IAAI,IAAI,IAAI;GACzB,IAAI,KAAK,IAAI,OAAO,GAAG,KAAK,OAAO,OAAO;QACrC,KAAK,IAAI,OAAO;GACrB,OAAO;EACT,CAAC;CACH,GAAG,CAAC,CAAC;CA+DL,WA3DkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;EAEA,IAAI,IAAI,KAAK;GACX,eAAe,SAAS,CAAC,IAAI;GAC7B,iBAAiB,CAAC;GAClB;EACF;EACA,IAAI,IAAI,QAAQ;GACd,IAAI,YAAY;IACd,MAAM,OAAO,UAAU;IACvB,IAAI,MAAM;KACR,IAAI,KAAK,OAAO;MACd,UAAU,KAAK,MAAM,KAAK,QAAQ,OAAO,EAAE,CAAC;MAC5C;KACF;KACA,SAAS,KAAK,MAAM,IAAI;IAC1B;IACA;GACF;GACA,MAAM,OAAO,YAAY;GACzB,IAAI,MAAM,SAAS,KAAK,IAAI;GAC5B;EACF;EACA,IAAI,IAAI,SAAS;GACf,iBAAiB,KAAK,IAAI,GAAG,gBAAgB,CAAC,CAAC;GAC/C;EACF;EACA,IAAI,IAAI,WAAW;GACjB,iBAAiB,KAAK,IAAI,UAAU,gBAAgB,CAAC,CAAC;GACtD;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC;GAC/B,iBAAiB,CAAC;GAClB;EACF;EACA,IAAI,MAAM,WAAW,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,MAAM;GAChD,WAAW,MAAM,IAAI,KAAK;GAC1B,iBAAiB,CAAC;EACpB;CACF,GACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAGkB,CAAC;;CAKrB,SAAS,SAAS,UAAsC;EACtD,MAAM,SAAS,aAAa,IAAI,QAAQ;EACxC,IAAI,CAAC,QAAQ,OAAO,KAAA;EAEpB,OADc,iBAAiB,OACnB,EAAE;CAChB;;CAGA,SAAS,WAAW,IAAoB;EACtC,MAAM,MAAM,KAAK,OAAO,KAAK,IAAI,IAAI,MAAM,GAAI;EAC/C,IAAI,MAAM,IAAI,OAAO,GAAG,IAAI;EAC5B,IAAI,MAAM,MAAM,OAAO,GAAG,KAAK,MAAM,MAAM,EAAE,EAAE;EAC/C,IAAI,MAAM,OAAO,OAAO,GAAG,KAAK,MAAM,MAAM,IAAI,EAAE;EAClD,OAAO,GAAG,KAAK,MAAM,MAAM,KAAK,EAAE;CACpC;;CAGA,SAAS,WAAW,OAAe,QAAyB;EAC1D,IAAI,UAAU,GAAG,OAAO;EACxB,IAAI,SAAS;EACb,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KACzB,UAAU;EAEZ,OAAO,OAAO,MAAM,GAAG,EAAE,KAAK,SAAS,QAAQ;CACjD;CAIA,MAAM,QAA8B,CAAC;CAErC,IAAI,YACF,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;EACzC,MAAM,OAAO,UAAU;EACvB,MAAM,aAAa,MAAM;EACzB,MAAM,SAAS,aAAa,MAAM;EAClC,MAAM,cAAc,WAAW,KAAK,OAAO,KAAK,MAAM;EAEtD,IAAI,KAAK,OAAO;GACd,MAAM,OAAO,KAAK,WAAW,MAAM;GACnC,MAAM,cAAc,KAAK,MAAM,KAAK,QAAQ,OAAO,EAAE;GACrD,MAAM,UAAU,YAAY,SAAS,GAAG,IACpC,YAAY,MAAM,YAAY,YAAY,GAAG,IAAI,CAAC,IAClD;GACJ,MAAM,KACJ,MAAM,cACJ,KACA;IAAE,KAAK,OAAO;IAAe,eAAe;GAAM,GAClD,MAAM,cACJ,MACA;IACE,OAAO,aAAa,MAAM,OAAO,SAAS,MAAM,OAAO;IACvD,MAAM;GACR,GACA,GAAG,OAAO,GAAG,cAAc,KAAK,GAAG,QAAQ,KAAK,KAAK,WAAW,EAClE,CACF,CACF;EACF,OAAO;GACL,MAAM,WAAW,KAAK,MAAM;GAC5B,MAAM,WAAW,SAAS,SAAS,GAAG,IAClC,SAAS,MAAM,SAAS,YAAY,GAAG,IAAI,CAAC,IAC5C;GACJ,MAAM,cAAc,SAAS,QAAQ;GACrC,MAAM,SAAS,aAAa,IAAI,QAAQ;GACxC,MAAM,cAAc,SAAS,IAAI,iBAAiB,OAAO,EAAE,SAAS,WAAW;GAE/E,MAAM,KACJ,MAAM,cACJ,KACA;IAAE,KAAK;IAAU,eAAe;GAAM,GACtC,MAAM,cACJ,MACA;IACE,OAAO,aAAa,MAAM,OAAO,SAAS,KAAA;IAC1C,MAAM;GACR,GACA,GAAG,OAAO,GAAG,cAAc,UAC7B,GACA,cAAc,MAAM,cAAc,MAAM,EAAE,OAAO,YAAY,GAAG,WAAW,IAAI,MAC/E,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,KAAK,WAAW,KAAK,MAAM,KAAK,GAAG,CACnF,CACF;EACF;CACF;MAGA,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;EAC3C,MAAM,OAAO,YAAY;EACzB,MAAM,aAAa,MAAM;EACzB,MAAM,SAAS,aAAa,OAAO;EACnC,MAAM,cAAc,SAAS,KAAK,IAAI;EACtC,MAAM,SAAS,aAAa,IAAI,KAAK,IAAI;EACzC,MAAM,cAAc,SAAS,IAAI,iBAAiB,OAAO,EAAE,SAAS,WAAW;EAE/E,MAAM,KACJ,MAAM,cACJ,KACA;GAAE,KAAK,KAAK;GAAM,eAAe;EAAM,GACvC,MAAM,cACJ,MACA;GAAE,OAAO,aAAa,MAAM,OAAO,SAAS,KAAA;GAAW,MAAM;EAAW,GACxE,GAAG,SAAS,KAAK,MACnB,GACA,cAAc,MAAM,cAAc,MAAM,EAAE,OAAO,YAAY,GAAG,WAAW,IAAI,MAC/E,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,KAAK,WAAW,KAAK,KAAK,GAAG,CAC7E,CACF;CACF;CAGF,MAAM,YAAY,aAAa,OAAO;CAEtC,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,GAAG,UAAU,OAAO,SAAS,KAAK,WAAW,GAAG,IAAI,WAAW,OAAO;EAChF,YAAY;EACZ,aAAa;EACb,OAAO;CACT,GAEA,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,cAAc;CAAE,GACxC,MAAM,cACJ,MACA;EAAE,OAAO,aAAa,MAAM,OAAO,SAAS,MAAM,OAAO;EAAK,MAAM;CAAW,GAC/E,MACF,GACA,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,GAAG,GACjD,MAAM,cACJ,MACA;EAAE,OAAO,CAAC,aAAa,MAAM,OAAO,SAAS,MAAM,OAAO;EAAK,MAAM,CAAC;CAAW,GACjF,MACF,CACF,GACA,MAAM,SAAS,IACX,MAAM,cAAc,KAAK,EAAE,eAAe,SAAS,GAAG,GAAG,KAAK,IAC9D,MAAM,cACJ,MACA,EAAE,UAAU,KAAK,GACjB,SAAS,UAAU,OAAO,SAAS,YACrC,CACN;AACF;;;;;;;;;;;;;;;;;ACvgBA,MAAMC,gBAAc;;AAEpB,MAAM,cAAc;;;;;;AAOpB,SAAgB,YAAY,EAC1B,OACA,WACA,UACA,YACuC;CACvC,MAAM,QAAQ,SAAS;CACvB,MAAM,CAAC,eAAe,oBAAoB,SAAS,CAAC;CAEpD,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM,SAAS,CAAC;CAC7C,MAAM,YAAY,KAAK,IAAI,eAAe,QAAQ;CAClD,MAAM,UAAU,MAAM,MAAM,GAAGA,aAAW;CAiC1C,WA7BkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;EACA,IAAI,IAAI,QAAQ;GACd,MAAM,OAAO,QAAQ;GACrB,IAAI,MAAM,UAAU,KAAK,EAAE;GAC3B;EACF;EAEA,IAAI,IAAI,QAAQ,UAAU,KAAK;GAC7B,MAAM,OAAO,QAAQ;GACrB,IAAI,MAAM,SAAS,KAAK,EAAE;GAC1B;EACF;EACA,IAAI,IAAI,SAAS;GACf,iBAAiB,KAAK,IAAI,GAAG,gBAAgB,CAAC,CAAC;GAC/C;EACF;EACA,IAAI,IAAI,WAAW;GACjB,iBAAiB,KAAK,IAAI,UAAU,gBAAgB,CAAC,CAAC;GACtD;EACF;CACF,GACA;EAAC;EAAS;EAAW;EAAU;EAAe;EAAW;EAAU;CAAQ,CAGzD,CAAC;CAIrB,SAAS,WAAW,IAAoB;EACtC,MAAM,MAAM,KAAK,OAAO,KAAK,IAAI,IAAI,MAAM,GAAI;EAC/C,IAAI,MAAM,IAAI,OAAO;EACrB,IAAI,MAAM,MAAM,OAAO,GAAG,KAAK,MAAM,MAAM,EAAE,EAAE;EAC/C,IAAI,MAAM,OAAO,OAAO,GAAG,KAAK,MAAM,MAAM,IAAI,EAAE;EAClD,OAAO,GAAG,KAAK,MAAM,MAAM,KAAK,EAAE;CACpC;CAIA,MAAM,YAAkC,CAAC;CACzC,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACvC,MAAM,OAAO,QAAQ;EACrB,MAAM,aAAa,MAAM;EACzB,MAAM,SAAS,aAAa,OAAO;EACnC,MAAM,UACJ,KAAK,QAAQ,SAAS,cAAc,KAAK,QAAQ,MAAM,GAAG,WAAW,IAAI,MAAM,KAAK;EAEtF,UAAU,KACR,MAAM,cACJ,KACA;GAAE,KAAK,KAAK;GAAI,eAAe;EAAM,GACrC,MAAM,cACJ,MACA;GACE,OAAO,aAAa,MAAM,OAAO,SAAS,KAAA;GAC1C,MAAM;EACR,GACA,GAAG,OAAO,GAAG,QAAQ,EACvB,GACA,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,KAAK,WAAW,KAAK,SAAS,GAAG,CACjF,CACF;CACF;CAEA,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,GAAG,MAAM,OAAO;EAC1B,YAAY;EACZ,aAAa;EACb,OAAO;CACT,GACA,UAAU,SAAS,IACf,MAAM,cAAc,KAAK,EAAE,eAAe,SAAS,GAAG,GAAG,SAAS,IAClE,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,qBAAqB,CACzE;AACF;;;;;;;;;;ACrHA,MAAMC,gBAAc;AACpB,MAAM,qBAAqB;;AAG3B,SAASC,cAAY,QAAgB,OAA4C;CAC/E,QAAQ,QAAR;EACE,KAAK,KACH,OAAO,MAAM,OAAO,WAAW;EACjC,KAAK,KACH,OAAO,MAAM,OAAO,WAAW;EACjC,KAAK,KACH,OAAO,MAAM,OAAO,SAAS;EAC/B,KAAK,KACH,OAAO,MAAM,OAAO,UAAU;EAChC,SACE,OAAO,MAAM,OAAO,OAAO;CAC/B;AACF;;;;;;;;;AAUA,SAAgB,WAAW,EAAE,eAAe,YAAiD;CAC3F,MAAM,QAAQ,SAAS;CACvB,MAAM,MAAM,MAAM,OAAO,OAAO;CAEhC,MAAM,CAAC,OAAO,YAAY,SAAqB,CAAC,CAAC;CACjD,MAAM,CAAC,SAAS,cAAc,SAAS,IAAI;CAC3C,MAAM,CAAC,OAAO,YAAY,SAAwB,IAAI;CACtD,MAAM,CAAC,cAAc,mBAAmB,SAA0B,IAAI;CACtE,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,MAAM,CAAC,WAAW,gBAAgB,SAAmB,CAAC,CAAC;CAEvD,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM,SAAS,CAAC;CAC7C,MAAM,aAAa,KAAK,IAAI,QAAQ,QAAQ;CAG5C,gBAAgB;EACd,IAAI,CAAC,eAAe;GAClB,WAAW,KAAK;GAChB,SAAS,CAAC,CAAC;GACX;EACF;EACA,cAAc,CAAC,CACZ,MAAM,SAAS;GACd,SAAS,IAAI;GACb,WAAW,KAAK;EAClB,CAAC,CAAC,CACD,OAAO,QAAiB;GACvB,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;GACzD,WAAW,KAAK;EAClB,CAAC;CACL,GAAG,CAAC,aAAa,CAAC;CAGlB,gBAAgB;EACd,IAAI,cACF,aAAa,aAAa,KAAK,MAAM,IAAI,CAAC;CAE9C,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,WAAW,KAAK,IAAI,GAAG,aAAa,KAAK,MAAMD,gBAAc,CAAC,CAAC;CACrE,MAAM,UAAU,MAAM,MAAM,UAAU,WAAWA,aAAW;CA4B5D,WA1BkB,aACf,OAAe,QAAa;EAC3B,IAAI,cAAc;GAEhB,IAAI,IAAI,QAAQ;IACd,gBAAgB,IAAI;IACpB,aAAa,CAAC,CAAC;GACjB;GACA;EACF;EAEA,IAAI,IAAI,SAAS;GACf,WAAW,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;GACzC;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,SAAS,KAAK,IAAI,UAAU,OAAO,CAAC,CAAC;GAChD;EACF;EACA,IAAI,IAAI,UAAU,MAAM,SAAS,GAC/B,gBAAgB,MAAM,eAAe,IAAI;CAE7C,GACA;EAAC;EAAO;EAAY;EAAU;CAAY,CAGxB,CAAC;CAIrB,IAAI,cAAc;EAChB,MAAM,WAAW;EACjB,MAAM,OAAO,UAAU,MAAM,GAAG,QAAQ;EACxC,MAAM,YAAY,UAAU,SAAS;EACrC,MAAM,YAAY,KAAK,KAAK,MAAM,MAAM;GACtC,IAAI,QAAQ;GACZ,IAAI,KAAK,WAAW,GAAG,KAAK,CAAC,KAAK,WAAW,KAAK,GAAG,QAAQ,MAAM,OAAO,WAAW;QAChF,IAAI,KAAK,WAAW,GAAG,KAAK,CAAC,KAAK,WAAW,KAAK,GAAG,QAAQ,MAAM,OAAO,SAAS;QACnF,IAAI,KAAK,WAAW,IAAI,GAAG,QAAQ,MAAM,OAAO,UAAU;GAC/D,OAAO,MAAM,cAAc,MAAM;IAAE,KAAK;IAAG;GAAM,GAAG,IAAI;EAC1D,CAAC;EACD,IAAI,WACF,UAAU,KACR,MAAM,cACJ,MACA;GAAE,KAAK;GAAS,OAAO;EAAI,GAC3B,UAAU,UAAU,SAAS,SAAS,MACxC,CACF;EAEF,OAAO,MAAM,cACX,QACA;GACE,OAAO,aAAa;GACpB,UAAU,OAAO,aAAa;GAC9B,aACE,aAAa,WAAW,MACpB,UACA,aAAa,WAAW,MACtB,YACA;GACR,YAAY;GACZ,OAAO;EACT,GACA,MAAM,cAAc,KAAK;GAAE,eAAe;GAAU,KAAK;EAAE,GAAG,GAAG,SAAS,CAC5E;CACF;CAIA,IAAI,SACF,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU;EACV,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,kBAAkB,CAC9D;CAGF,IAAI,OACF,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU;EACV,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,MAAM,GAAG,KAAK,CAChE;CAGF,IAAI,MAAM,WAAW,GACnB,OAAO,MAAM,cACX,QACA;EAAE,OAAO;EAAM,UAAU;EAAO,aAAa;EAAO,YAAY;EAAU,OAAO;CAAG,GACpF,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,SAAS,CACrD;CAGF,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,GAAG,MAAM,OAAO;EAC1B,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,GAAG,QAAQ,KAAK,GAAG,QAAQ;EAEzB,MAAM,aADY,WAAW,QACI;EACjC,MAAM,SAAS,aAAa,MAAM;EAClC,MAAM,KAAKC,cAAY,EAAE,QAAQ,KAAK;EAEtC,OAAO,MAAM,cACX,KACA;GAAE,KAAK,EAAE;GAAM,eAAe;EAAS,GACvC,MAAM,cACJ,KACA;GAAE,eAAe;GAAO,KAAK;EAAE,GAC/B,MAAM,cAAc,MAAM,EAAE,OAAO,aAAa,MAAM,OAAO,SAAS,IAAI,GAAG,MAAM,GACnF,MAAM,cAAc,MAAM;GAAE,OAAO;GAAI,MAAM;EAAK,GAAG,IAAI,EAAE,OAAO,EAAE,GACpE,MAAM,cACJ,MACA,EAAE,OAAO,aAAa,MAAM,OAAO,SAAS,KAAA,EAAU,GACtD,EAAE,IACJ,CACF,GACA,MAAM,cACJ,KACA,EAAE,YAAY,EAAE,GAChB,MAAM,cACJ,MACA,EAAE,OAAO,IAAI,GACb,EAAE,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG,kBAAkB,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,UAAU,GAAG,EAAE,KACvE,EAAE,KAAK,SAAS,KAAK,QAAQ,GAClC,CACF,CACF;CACF,CAAC,CACH;AACF;;;;;;;;;;ACzNA,MAAMC,gBAAc;;AAGpB,SAAS,gBAAgB,IAAoB;CAC3C,MAAM,IAAI,IAAI,KAAK,EAAE;CACrB,MAAM,OAAO,MAAc,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;CACpD,OAAO,GAAG,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,SAAS,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,CAAC;AACnH;;;;;;;AAQA,SAAgB,gBAAgB,EAC9B,oBACA,YAC2C;CAC3C,MAAM,QAAQ,SAAS;CACvB,MAAM,MAAM,MAAM,OAAO,OAAO;CAEhC,MAAM,CAAC,WAAW,gBAAgB,SAA0B,CAAC,CAAC;CAC9D,MAAM,CAAC,SAAS,cAAc,SAAS,IAAI;CAC3C,MAAM,CAAC,OAAO,YAAY,SAAwB,IAAI;CACtD,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CAEtC,MAAM,WAAW,KAAK,IAAI,GAAG,UAAU,SAAS,CAAC;CACjD,MAAM,aAAa,KAAK,IAAI,QAAQ,QAAQ;CAE5C,gBAAgB;EACd,IAAI,CAAC,oBAAoB;GACvB,WAAW,KAAK;GAChB,aAAa,CAAC,CAAC;GACf;EACF;EACA,mBAAmB,CAAC,CACjB,MAAM,SAAS;GACd,aAAa,IAAI;GACjB,WAAW,KAAK;EAClB,CAAC,CAAC,CACD,OAAO,QAAiB;GACvB,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;GACzD,WAAW,KAAK;EAClB,CAAC;CACL,GAAG,CAAC,kBAAkB,CAAC;CAEvB,MAAM,WAAW,KAAK,IAAI,GAAG,aAAa,KAAK,MAAMA,gBAAc,CAAC,CAAC;CACrE,MAAM,UAAU,UAAU,MAAM,UAAU,WAAWA,aAAW;CAgBhE,WAdkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,SAAS;GACf,WAAW,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;GACzC;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,SAAS,KAAK,IAAI,UAAU,OAAO,CAAC,CAAC;GAChD;EACF;CACF,GACA,CAAC,QAAQ,CAGS,CAAC;CAErB,IAAI,SACF,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU;EACV,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,aAAa,CACzD;CAGF,IAAI,OACF,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU;EACV,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,MAAM,GAAG,KAAK,CAChE;CAGF,IAAI,UAAU,WAAW,GACvB,OAAO,MAAM,cACX,QACA;EAAE,OAAO;EAAM,UAAU;EAAO,aAAa;EAAO,YAAY;EAAU,OAAO;CAAG,GACpF,MAAM,cACJ,KACA;EAAE,eAAe;EAAU,KAAK;CAAE,GAClC,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,SAAS,GACnD,MAAM,cACJ,MACA,EAAE,OAAO,IAAI,GACb,qCACF,CACF,CACF;CAGF,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,GAAG,UAAU,OAAO;EAC9B,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,GAAG,QAAQ,KAAK,MAAM,QAAQ;EAE5B,MAAM,aADY,WAAW,QACI;EACjC,MAAM,SAAS,aAAa,MAAM;EAClC,MAAM,UAAU,gBAAgB,KAAK,SAAS;EAE9C,OAAO,MAAM,cACX,KACA;GAAE,KAAK,KAAK;GAAI,eAAe;GAAO,KAAK;EAAE,GAC7C,MAAM,cAAc,MAAM,EAAE,OAAO,aAAa,MAAM,OAAO,SAAS,IAAI,GAAG,MAAM,GACnF,MAAM,cAAc,MAAM;GAAE,OAAO,MAAM,OAAO;GAAQ,MAAM;EAAK,GAAG,KAAK,KAAK,GAChF,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,GAC7C,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,OAAO,CACnD;CACF,CAAC,CACH;AACF;;;;;;;;;;ACnIA,MAAMC,gBAAc;;AAEpB,MAAM,mBAAmB;;AAGzB,SAAS,WAAW,QAA4B;CAC9C,QAAQ,QAAR;EACE,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,UACH,OAAO;CACX;AACF;;AAGA,SAAS,YAAY,QAAoB,OAA4C;CACnF,QAAQ,QAAR;EACE,KAAK,WACH,OAAO,MAAM,OAAO,UAAU;EAChC,KAAK,UACH,OAAO,MAAM,OAAO,OAAO;EAC7B,KAAK,QACH,OAAO,MAAM,OAAO,WAAW;EACjC,KAAK,UACH,OAAO,MAAM,OAAO,SAAS;CACjC;AACF;;AAGA,SAAS,YAAY,QAA4B;CAC/C,QAAQ,QAAR;EACE,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,UACH,OAAO;CACX;AACF;;;;;;;;AASA,SAAgB,WAAW,EAAE,gBAAgB,YAAiD;CAC5F,MAAM,QAAQ,SAAS;CACvB,MAAM,MAAM,MAAM,OAAO,OAAO;CAEhC,MAAM,CAAC,OAAO,YAAY,SAAsB,CAAC,CAAC;CAClD,MAAM,CAAC,SAAS,cAAc,SAAS,IAAI;CAC3C,MAAM,CAAC,OAAO,YAAY,SAAwB,IAAI;CACtD,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,MAAM,UAAU,OAA8C,IAAI;CAElE,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM,SAAS,CAAC;CAC7C,MAAM,aAAa,KAAK,IAAI,QAAQ,QAAQ;CAE5C,MAAM,aAAa,kBAAkB;EACnC,IAAI,CAAC,gBAAgB;GACnB,WAAW,KAAK;GAChB,SAAS,CAAC,CAAC;GACX;EACF;EACA,eAAe,CAAC,CACb,MAAM,SAAS;GACd,SAAS,IAAI;GACb,WAAW,KAAK;EAClB,CAAC,CAAC,CACD,OAAO,QAAiB;GAEvB,IAAI,SAAS,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;GACtE,WAAW,KAAK;EAClB,CAAC;CACL,GAAG,CAAC,gBAAgB,OAAO,CAAC;CAG5B,gBAAgB;EACd,WAAW;EACX,QAAQ,UAAU,YAAY,YAAY,gBAAgB;EAC1D,aAAa;GACX,IAAI,QAAQ,SAAS,cAAc,QAAQ,OAAO;EACpD;CACF,GAAG,CAAC,UAAU,CAAC;CAEf,MAAM,WAAW,KAAK,IAAI,GAAG,aAAa,KAAK,MAAMA,gBAAc,CAAC,CAAC;CACrE,MAAM,UAAU,MAAM,MAAM,UAAU,WAAWA,aAAW;CAqB5D,WAnBkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,SAAS;GACf,WAAW,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;GACzC;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,SAAS,KAAK,IAAI,UAAU,OAAO,CAAC,CAAC;GAChD;EACF;EACA,IAAI,UAAU,KAAK;GACjB,WAAW,IAAI;GACf,WAAW;GACX;EACF;CACF,GACA,CAAC,UAAU,UAAU,CAGH,CAAC;CAErB,IAAI,SACF,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU;EACV,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,aAAa,CACzD;CAGF,IAAI,OACF,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU;EACV,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,MAAM,GAAG,KAAK,CAChE;CAGF,IAAI,MAAM,WAAW,GACnB,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU;EACV,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,YAAY,CACxD;CAIF,MAAM,eAAe,MAAM,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC,CAAC;CACjE,MAAM,cAAc,MAAM,QAAQ,MAAM,EAAE,WAAW,QAAQ,CAAC,CAAC;CAC/D,MAAM,cAAc,MAAM,QAAQ,MAAM,EAAE,WAAW,QAAQ,CAAC,CAAC;CAE/D,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,GAAG,MAAM,OAAO,QAAQ,aAAa,QAAQ,YAAY,OAAO,YAAY;EACtF,aAAa,cAAc,IAAI,UAAU,eAAe,IAAI,WAAW;EACvE,YAAY;EACZ,OAAO;CACT,GACA,GAAG,QACA,KAAK,MAAM,QAAQ;EAElB,MAAM,aADY,WAAW,QACI;EACjC,MAAM,SAAS,aAAa,MAAM;EAClC,MAAM,KAAK,YAAY,KAAK,QAAQ,KAAK;EACzC,MAAM,OAAO,WAAW,KAAK,MAAM;EAEnC,MAAM,WAAiC,CACrC,MAAM,cACJ,KACA;GAAE,KAAK,OAAO,KAAK;GAAM,eAAe;GAAO,KAAK;EAAE,GACtD,MAAM,cAAc,MAAM,EAAE,OAAO,aAAa,MAAM,OAAO,SAAS,IAAI,GAAG,MAAM,GACnF,MAAM,cAAc,MAAM,EAAE,OAAO,GAAG,GAAG,GAAG,KAAK,GAAG,YAAY,KAAK,MAAM,GAAG,GAC9E,MAAM,cAAc,MAAM,EAAE,MAAM,KAAK,GAAG,KAAK,IAAI,CACrD,CACF;EAEA,IAAI,KAAK,OACP,SAAS,KACP,MAAM,cACJ,KACA;GAAE,KAAK,OAAO,KAAK;GAAM,YAAY;EAAE,GACvC,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,MAAM,GAAG,OAAO,KAAK,OAAO,CAC9E,CACF;EAGF,OAAO;CACT,CAAC,CAAC,CACD,KAAK,CACV;AACF;;;;;;;;;;;;;;ACrNA,MAAMC,gBAAc;;AAiBpB,SAAS,WAAW,OAAe,QAAwB;CACzD,MAAM,IAAI,MAAM,YAAY;CAC5B,MAAM,IAAI,OAAO,YAAY;CAC7B,IAAI,QAAQ;CACZ,IAAI,KAAK;CACT,IAAI,YAAY;CAChB,KAAK,IAAI,KAAK,GAAG,KAAK,EAAE,UAAU,KAAK,EAAE,QAAQ,MAC/C,IAAI,EAAE,QAAQ,EAAE,KAAK;EAEnB,SAAS,MAAM,MAAM,OAAO,YAAY,IAAI,KAAK;EACjD;EACA,YAAY;CACd;CAEF,OAAO,OAAO,EAAE,SAAS,QAAQ;AACnC;;AAGA,SAASC,cAAY,QAAqC;CACxD,QAAQ,QAAR;EACE,KAAK,WACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,WACH,OAAO;CACX;AACF;;;;;;;AAQA,SAAgB,YAAY,EAAE,QAAQ,UAAU,YAAkD;CAChG,MAAM,QAAQ,SAAS;CACvB,MAAM,MAAM,MAAM,OAAO,OAAO;CAEhC,MAAM,CAAC,OAAO,YAAY,SAAS,EAAE;CACrC,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CAGtC,MAAM,SAAS,cAAc;EAC3B,IAAI,CAAC,MAAM,KAAK,GAAG,OAAO,CAAC;EAQ3B,OAPe,OACZ,KAAK,OAAO;GACX,OAAO;GACP,OAAO,WAAW,OAAO,EAAE,IAAI,IAAI,IAAI,WAAW,OAAO,EAAE,WAAW;EACxE,EAAE,CAAC,CACF,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,CAC1B,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAClB;CACd,GAAG,CAAC,QAAQ,KAAK,CAAC;CAElB,MAAM,WAAW,KAAK,IAAI,GAAG,OAAO,SAAS,CAAC;CAC9C,MAAM,aAAa,KAAK,IAAI,QAAQ,QAAQ;CAE5C,MAAM,UAAU,OAAO,MAAM,GAAGD,aAAW;CAsC3C,WApCkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;EACA,IAAI,IAAI,SAAS;GACf,WAAW,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;GACzC;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,SAAS,KAAK,IAAI,UAAU,OAAO,CAAC,CAAC;GAChD;EACF;EACA,IAAI,IAAI,KAAK;GACX,WAAW,UAAU,OAAO,MAAM,WAAW,EAAE;GAC/C;EACF;EACA,IAAI,IAAI,UAAU,OAAO,SAAS,GAAG;GACnC,SAAS,OAAO,WAAW,CAAE,MAAM,IAAI;GACvC;EACF;EAEA,IAAI,IAAI,aAAa,IAAI,QAAQ;GAC/B,UAAU,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC;GACpC,UAAU,CAAC;GACX;EACF;EACA,IAAI,SAAS,MAAM,WAAW,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,MAAM;GACzD,UAAU,SAAS,OAAO,KAAK;GAC/B,UAAU,CAAC;EACb;CACF,GACA;EAAC;EAAQ;EAAY;EAAU;EAAU;CAAQ,CAG/B,CAAC;CAErB,MAAM,WAAW,MAAM,KAAK,CAAC,CAAC,SAAS;CAEvC,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,WAAW,GAAG,OAAO,OAAO,QAAQ,GAAG,OAAO,OAAO;EAC/D,aAAa,YAAY,OAAO,SAAS,IAAI,WAAW;EACxD,YAAY,WAAW,8BAA8B;EACrD,OAAO;CACT,GAEA,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,KAAK;EAAG,cAAc;CAAE,GAChD,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,GAC7C,MAAM,cACJ,MACA,EAAE,OAAO,QAAQ,KAAA,IAAY,IAAI,GACjC,UAAU,OAAO,SAAS,IAAI,eAAe,UAC/C,GACA,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,CAC/C,GAEA,CAAC,WACG,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,qBAAqB,IAC/D,OAAO,WAAW,IAChB,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,UAAU,MAAM,OAAO,IACjE,QAAQ,KAAK,OAAO,QAAQ;EAC1B,MAAM,aAAa,QAAQ;EAC3B,MAAM,SAAS,aAAa,MAAM;EAClC,MAAM,WAAWC,cAAY,MAAM,MAAM,MAAM;EAE/C,OAAO,MAAM,cACX,KACA;GAAE,KAAK,MAAM,MAAM;GAAM,eAAe;EAAS,GACjD,MAAM,cACJ,KACA;GAAE,eAAe;GAAO,KAAK;EAAE,GAC/B,MAAM,cACJ,MACA,EAAE,OAAO,aAAa,MAAM,OAAO,SAAS,IAAI,GAChD,MACF,GACA,MAAM,cACJ,MACA;GAAE,OAAO,aAAa,MAAM,OAAO,SAAS,KAAA;GAAW,MAAM;EAAK,GAClE,MAAM,MAAM,IACd,GACA,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,IAAI,SAAS,EAAE,CAC3D,GACA,MAAM,cACJ,KACA,EAAE,YAAY,EAAE,GAChB,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,MAAM,MAAM,eAAe,KAAK,CAC5E,CACF;CACF,CAAC,CACT;AACF;;;;;;;;;;;;;;;;ACxKA,MAAMC,gBAAc;;AAGpB,MAAM,mBAA2C;CAC/C,OAAO;CACP,KAAK;CACL,IAAI;CACJ,QAAQ;AACV;;AAGA,SAAS,aACP,QACA,OACiC;CACjC,QAAQ,QAAR;EACE,KAAK,aACH,OAAO;GAAE,MAAM;GAAK,OAAO,MAAM,OAAO,WAAW;EAAQ;EAC7D,KAAK,cACH,OAAO;GAAE,MAAM;GAAK,OAAO,MAAM,OAAO,WAAW;EAAS;EAC9D,KAAK,SACH,OAAO;GAAE,MAAM;GAAK,OAAO,MAAM,OAAO,SAAS;EAAM;EAEzD,SACE,OAAO;GAAE,MAAM;GAAK,OAAO,MAAM,OAAO,UAAU;EAAO;CAC7D;AACF;;AAGA,SAAS,SAAS,YAA6B;CAC7C,IAAI,eAAe,iBAAiB,OAAO;CAC3C,OAAO;AACT;;;;AAKA,SAAS,iBAAiB,EACxB,QACA,SAIqB;CACrB,MAAM,MAAM,MAAM,OAAO,UAAU;CACnC,MAAM,SAAS,MAAM,OAAO;CAE5B,OAAO,MAAM,cACX,KACA;EAAE,eAAe;EAAU,KAAK;CAAE,GAElC,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,KAAK;CAAE,GAC/B,MAAM,cAAc,MAAM;EAAE,MAAM;EAAM,OAAO;CAAO,GAAG,OAAO,IAAI,GACpE,MAAM,cACJ,MACA,EAAE,OAAO,aAAa,OAAO,QAAQ,KAAK,CAAC,CAAC,MAAM,GAClD,KAAK,OAAO,QACd,CACF,GAEA,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,KAAK;CAAE,GAC/B,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,KAAK,GAC/C,MAAM,cAAc,MAAM,CAAC,GAAG,OAAO,aAAa,IAAI,CACxD,GAEA,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,KAAK;CAAE,GAC/B,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,KAAK,GAC/C,MAAM,cACJ,MACA,CAAC,GACD,GAAG,SAAS,OAAO,UAAU,EAAE,GAAG,OAAO,eAAe,kBAAkB,QAAQ,OAAO,eAAe,YAAY,QAAQ,OAC9H,CACF,GAEA,OAAO,WAAW,UACd,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,KAAK;CAAE,GAC/B,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,SAAS,MAAM,GAAG,KAAK,GACvE,MAAM,cAAc,MAAM,EAAE,OAAO,MAAM,OAAO,SAAS,MAAM,GAAG,OAAO,MAAM,CACjF,IACA,MAEJ,MAAM,cAAc,MAAM;EAAE,MAAM;EAAM,OAAO;CAAI,GAAG,OAAO,OAAO,UAAU,GAAG,GACjF,OAAO,SAAS,OAAO,MAAM,SAAS,IAClC,OAAO,MAAM,KAAK,SAChB,MAAM,cACJ,KACA;EAAE,KAAK,KAAK;EAAM,eAAe;EAAO,KAAK;EAAG,YAAY;CAAE,GAC9D,MAAM,cAAc,MAAM,EAAE,OAAO,OAAO,GAAG,KAAK,IAAI,GACtD,KAAK,cACD,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,KAAK,KAAK,aAAa,IACjE,IACN,CACF,IACA,MAAM,cAAc,MAAM;EAAE,OAAO;EAAU,YAAY;CAAI,GAAG,KAAK,GAEzE,MAAM,cAAc,MAAM;EAAE,MAAM;EAAM,OAAO;CAAI,GAAG,OAAO,OAAO,iBAAiB,EAAE,GAAG,GAC1F,OAAO,aAAa,OAAO,UAAU,SAAS,IAC1C,OAAO,UAAU,KAAK,QACpB,MAAM,cACJ,KACA;EAAE,KAAK,IAAI;EAAM,eAAe;EAAO,KAAK;EAAG,YAAY;CAAE,GAC7D,MAAM,cAAc,MAAM,EAAE,OAAO,OAAO,GAAG,IAAI,IAAI,GACrD,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,KAAK,IAAI,KAAK,CAC1D,CACF,IACA,MAAM,cAAc,MAAM;EAAE,OAAO;EAAU,YAAY;CAAI,GAAG,KAAK,CAC3E;AACF;;;;;;;;;AAUA,SAAgB,SAAS,EACvB,aACA,UACA,WACA,cACA,eACoC;CACpC,MAAM,QAAQ,SAAS;CACvB,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,WAAW,KAAK,IAAI,GAAG,YAAY,SAAS,CAAC;CACnD,MAAM,aAAa,KAAK,IAAI,QAAQ,QAAQ;CAE5C,MAAM,WAAW,KAAK,IAAI,GAAG,aAAa,KAAK,MAAMA,gBAAc,CAAC,CAAC;CACrE,MAAM,UAAU,YAAY,MAAM,UAAU,WAAWA,aAAW;CA2DlE,WAzDkB,aACf,OAAe,QAAa;EAE3B,IAAI,YAAY;GACd,IAAI,IAAI,UAAU,UAAU,KAC1B,cAAc,KAAK;GAErB;EACF;EAGA,IAAI,IAAI,QAAQ;GACd,SAAS;GACT;EACF;EACA,IAAI,IAAI,SAAS;GACf,WAAW,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;GACzC;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,SAAS,KAAK,IAAI,UAAU,OAAO,CAAC,CAAC;GAChD;EACF;EACA,IAAI,IAAI,QAAQ;GACd,MAAM,SAAS,YAAY;GAC3B,IAAI,CAAC,QAAQ;GACb,QAAQ,OAAO,QAAf;IACE,KAAK;KACH,YAAY,OAAO,IAAI;KACvB;IACF,KAAK;KACH,cAAc,OAAO,IAAI;KACzB;IACF,KAAK;IACL,KAAK;KACH,eAAe,OAAO,IAAI;KAC1B;GACJ;GACA;EACF;EACA,IAAI,UAAU,KAAK;GACjB,IAAI,YAAY,aACd,cAAc,IAAI;GAEpB;EACF;EACA,IAAI,UAAU,KAAK;GACjB,MAAM,SAAS,YAAY;GAC3B,IAAI,QACF,cAAc,OAAO,IAAI;GAE3B;EACF;CACF,GACA;EAAC;EAAa;EAAY;EAAU;EAAW;EAAc;EAAa;EAAU;CAAU,CAG5E,CAAC;CAErB,MAAM,cAAc,YAAY,SAAS,IAAI,WAAW;CACxD,MAAM,MAAM,MAAM,OAAO,UAAU;CACnC,MAAM,iBAAiB,YAAY;CAGnC,MAAM,aAAa,aACf,0BACA,YAAY,SAAS,IACnB,+CACA;CAEN,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UACE,cAAc,iBACV,GAAG,eAAe,KAAK,OACvB,GAAG,YAAY,OAAO;EAC5B;EACA;EACA,OAAO;CACT,GAEA,cAAc,iBACV,MAAM,cAAc,kBAAkB;EAAE,QAAQ;EAAgB;CAAM,CAAC,IAEvE,YAAY,WAAW,IACrB,MAAM,cACJ,KACA,EAAE,UAAU,EAAE,GACd,MAAM,cACJ,MACA,EAAE,OAAO,IAAI,GACb,yDACF,CACF,IACA,QAAQ,KAAK,MAAM,QAAQ;EAEzB,MAAM,aADY,WAAW,QACI;EACjC,MAAM,EAAE,MAAM,UAAU,aAAa,KAAK,QAAQ,KAAK;EACvD,MAAM,SAAS,aAAa,MAAM;EAElC,OAAO,MAAM,cACX,KACA;GAAE,KAAK,KAAK;GAAM,eAAe;GAAO,KAAK;EAAE,GAC/C,MAAM,cAAc,MAAM,EAAE,OAAO,aAAa,MAAM,OAAO,SAAS,IAAI,GAAG,MAAM,GACnF,MAAM,cAAc,MAAM,EAAE,MAAM,GAAG,IAAI,GACzC,MAAM,cAAc,MAAM,CAAC,GAAG,SAAS,KAAK,UAAU,CAAC,GACvD,MAAM,cAAc,MAAM,EAAE,MAAM,KAAK,GAAG,IAAI,KAAK,MAAM,GACzD,KAAK,YACD,MAAM,cACJ,MACA,EAAE,OAAO,IAAI,GACb,iBAAiB,KAAK,cAAc,KAAK,SAC3C,IACA,MACJ,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,QAAQ,KAAK,WAAW,GAClE,KAAK,kBAAkB,KAAA,IACnB,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,QAAQ,KAAK,eAAe,IACtE,MACJ,MAAM,cAAc,MAAM,EAAE,MAAM,GAAG,MAAM,KAAK,QAAQ,CAC1D;CACF,CAAC,CACT;AACF;;;;;;;;;;;AChRA,MAAMC,gBAAc;;;;;;;AAQpB,SAAgB,YAAY,EAC1B,SACA,UACA,QACA,YACuC;CACvC,MAAM,QAAQ,SAAS;CACvB,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,MAAM,WAAW,KAAK,IAAI,GAAG,QAAQ,SAAS,CAAC;CAC/C,MAAM,aAAa,KAAK,IAAI,QAAQ,QAAQ;CAE5C,MAAM,WAAW,KAAK,IAAI,GAAG,aAAa,KAAK,MAAMA,gBAAc,CAAC,CAAC;CACrE,MAAM,UAAU,QAAQ,MAAM,UAAU,WAAWA,aAAW;CAE9D,MAAM,cAAc,QAAQ,QAAQ,MAAM,EAAE,MAAM,CAAC,CAAC;CAyBpD,WAvBkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,SAAS;GACf,WAAW,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;GACzC;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,SAAS,KAAK,IAAI,UAAU,OAAO,CAAC,CAAC;GAChD;EACF;EACA,IAAI,IAAI,QAAQ;GACd,MAAM,SAAS,QAAQ;GACvB,IAAI,CAAC,QAAQ;GACb,IAAI,OAAO,QACT,WAAW,OAAO,IAAI;QAEtB,SAAS,OAAO,IAAI;EAExB;CACF,GACA;EAAC;EAAS;EAAY;EAAU;EAAQ;CAAQ,CAG9B,CAAC;CAErB,MAAM,MAAM,MAAM,OAAO,OAAO;CAEhC,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,GAAG,YAAY,SAAS,QAAQ,OAAO;EACjD,aAAa,QAAQ,SAAS,IAAI,WAAW;EAC7C,YAAY,QAAQ,SAAS,IAAI,8BAA8B;EAC/D,OAAO;CACT,GACA,QAAQ,WAAW,IACf,MAAM,cACJ,KACA,EAAE,UAAU,EAAE,GACd,MAAM,cACJ,MACA,EAAE,OAAO,IAAI,GACb,oDACF,CACF,IACA,QAAQ,KAAK,QAAQ,QAAQ;EAE3B,MAAM,aADY,WAAW,QACI;EACjC,MAAM,OAAO,OAAO,SAAS,MAAM;EACnC,MAAM,YAAY,OAAO,SAAU,MAAM,OAAO,WAAW,UAAW;EACtE,MAAM,SAAS,aAAa,MAAM;EAElC,OAAO,MAAM,cACX,KACA;GACE,KAAK,OAAO;GACZ,eAAe;GACf,cAAc,MAAM,QAAQ,SAAS,IAAI,IAAI,KAAA;EAC/C,GACA,MAAM,cACJ,KACA;GAAE,eAAe;GAAO,KAAK;EAAE,GAC/B,MAAM,cAAc,MAAM,EAAE,OAAO,aAAa,MAAM,OAAO,SAAS,IAAI,GAAG,MAAM,GACnF,MAAM,cAAc,MAAM,EAAE,OAAO,UAAU,GAAG,IAAI,GACpD,MAAM,cAAc,MAAM,EAAE,MAAM,KAAK,GAAG,IAAI,OAAO,MAAM,GAC3D,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,IAAI,OAAO,SAAS,CAChE,GACA,MAAM,cACJ,KACA,EAAE,YAAY,EAAE,GAChB,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,OAAO,eAAe,KAAK,CACvE,CACF;CACF,CAAC,CACP;AACF;;;;;;;;;;ACzGA,MAAM,cAAc;;AAGpB,SAAS,YAAY,QAAqC;CACxD,QAAQ,QAAR;EACE,KAAK,WACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,WACH,OAAO;CACX;AACF;;AAGA,SAAS,YAAY,QAA6B,OAA4C;CAC5F,QAAQ,QAAR;EACE,KAAK,WACH,OAAO,MAAM,OAAO,UAAU;EAChC,KAAK,QACH,OAAO,MAAM,OAAO,WAAW;EACjC,KAAK,WACH,OAAO,MAAM,OAAO,WAAW;CACnC;AACF;;;;;;;AAQA,SAAgB,WAAW,EAAE,QAAQ,YAAiD;CACpF,MAAM,QAAQ,SAAS;CACvB,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,MAAM,WAAW,KAAK,IAAI,GAAG,OAAO,SAAS,CAAC;CAC9C,MAAM,aAAa,KAAK,IAAI,QAAQ,QAAQ;CAE5C,MAAM,WAAW,KAAK,IAAI,GAAG,aAAa,KAAK,MAAM,cAAc,CAAC,CAAC;CACrE,MAAM,UAAU,OAAO,MAAM,UAAU,WAAW,WAAW;CAgB7D,WAdkB,aACf,OAAe,QAAa;EAC3B,IAAI,IAAI,SAAS;GACf,WAAW,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;GACzC;EACF;EACA,IAAI,IAAI,WAAW;GACjB,WAAW,SAAS,KAAK,IAAI,UAAU,OAAO,CAAC,CAAC;GAChD;EACF;CACF,GACA,CAAC,QAAQ,CAGS,CAAC;CAErB,MAAM,MAAM,MAAM,OAAO,OAAO;CAEhC,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,MAAM,OAAO,OAAO;EAC9B,aAAa,OAAO,SAAS,IAAI,WAAW;EAC5C,YAAY,OAAO,SAAS,IAAI,mBAAmB;EACnD,OAAO;CACT,GACA,OAAO,WAAW,IACd,MAAM,cACJ,KACA,EAAE,UAAU,EAAE,GACd,MAAM,cACJ,MACA,EAAE,OAAO,IAAI,GACb,iDACF,CACF,IACA,QAAQ,KAAK,OAAO,QAAQ;EAE1B,MAAM,aADY,WAAW,QACI;EACjC,MAAM,SAAS,aAAa,MAAM;EAClC,MAAM,WAAW,YAAY,MAAM,QAAQ,KAAK;EAEhD,OAAO,MAAM,cACX,KACA;GACE,KAAK,MAAM;GACX,eAAe;EACjB,GACA,MAAM,cACJ,KACA;GAAE,eAAe;GAAO,KAAK;EAAE,GAC/B,MAAM,cAAc,MAAM,EAAE,OAAO,aAAa,MAAM,OAAO,SAAS,IAAI,GAAG,MAAM,GACnF,MAAM,cAAc,MAAM;GAAE,OAAO,MAAM,OAAO;GAAQ,MAAM;EAAK,GAAG,MAAM,IAAI,GAChF,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,GAC7C,MAAM,cAAc,MAAM,EAAE,OAAO,SAAS,GAAG,IAAI,YAAY,MAAM,MAAM,EAAE,EAAE,CACjF,GACA,MAAM,cACJ,KACA,EAAE,YAAY,EAAE,GAChB,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,MAAM,eAAe,KAAK,CACtE,CACF;CACF,CAAC,CACP;AACF;;;;;;;;;;;ACzGA,SAAS,QAAQ,EACf,OACA,OACA,OAKqB;CACrB,OAAO,MAAM,cACX,KACA;EAAE,eAAe;EAAO,KAAK;CAAE,GAC/B,MAAM,cAAc,KAAK,EAAE,OAAO,GAAG,GAAG,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,KAAK,CAAC,GACxF,MAAM,cAAc,MAAM,CAAC,GAAG,KAAK,CACrC;AACF;;;;;;;AAQA,SAAgB,aAAa,EAAE,aAAa,YAAmD;CAC7F,MAAM,QAAQ,SAAS;CACvB,MAAM,MAAM,MAAM,OAAO,OAAO;CAChC,MAAM,SAAS,MAAM,OAAO,UAAU;CAOtC,WALkB,aAAa,OAAe,QAAa,CAG3D,GAAG,CAAC,CAEgB,CAAC;CAErB,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,YAAY;EACtB,aAAa;EACb,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cACJ,KACA;EAAE,eAAe;EAAU,KAAK;EAAG,UAAU;CAAE,GAE/C,MAAM,cAAc,MAAM;EAAE,MAAM;EAAM,OAAO;CAAO,GAAG,IAAI,GAC7D,MAAM,cAAc,SAAS;EAAE,OAAO;EAAM,OAAO,YAAY;EAAc;CAAI,CAAC,GAClF,MAAM,cAAc,SAAS;EAAE,OAAO;EAAM,OAAO,YAAY;EAAO;CAAI,CAAC,GAC3E,MAAM,cAAc,SAAS;EAAE,OAAO;EAAO,OAAO,YAAY;EAAW;CAAI,CAAC,GAEhF,MAAM,cACJ,KACA,EAAE,UAAU,EAAE,GACd,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,IAAI,OAAO,EAAE,CAAC,CAC1D,GAEA,MAAM,cAAc,MAAM;EAAE,MAAM;EAAM,OAAO;CAAO,GAAG,IAAI,GAC7D,MAAM,cAAc,SAAS;EAC3B,OAAO;EACP,OAAO,OAAO,YAAY,WAAW;EACrC;CACF,CAAC,GACD,MAAM,cAAc,SAAS;EAAE,OAAO;EAAM,OAAO,OAAO,YAAY,KAAK;EAAG;CAAI,CAAC,GACnF,MAAM,cAAc,SAAS;EAAE,OAAO;EAAM,OAAO,OAAO,YAAY,MAAM;EAAG;CAAI,CAAC,CACtF,CACF;AACF;;;;;;;;;;;;;;AClEA,MAAM,YAAY;AAClB,MAAM,aAAa;AACnB,MAAM,YAAY;;AAGlB,SAAS,SAAS,EAChB,OACA,OACA,KACA,UAMqB;CACrB,OAAO,MAAM,cACX,KACA;EAAE,eAAe;EAAU,OAAO;CAAG,GACrC,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,KAAK,GAC/C,MAAM,cAAc,MAAM;EAAE,OAAO;EAAQ,MAAM;CAAK,GAAG,KAAK,CAChE;AACF;;;;;;;;AASA,SAAgB,WAAW,EAAE,WAAW,YAAiD;CACvF,MAAM,QAAQ,SAAS;CACvB,MAAM,MAAM,MAAM,OAAO,OAAO;CAChC,MAAM,SAAS,MAAM,OAAO,UAAU;CAMtC,WAJkB,aAAa,OAAe,QAAa,CAE3D,GAAG,CAAC,CAEgB,CAAC;CAIrB,MAAM,YAAY,UAAU,kBAAkB,KAAK,UAAU,eAAe;CAC5E,MAAM,SAAS,UAAU,gBAAgB;CACzC,MAAM,QAAQ,SAAS,IAAI,KAAK,IAAI,UAAU,UAAU,QAAQ,CAAC,IAAI;CAErE,IAAI,WAAW,MAAM,OAAO,WAAW;CACvC,IAAI,QAAQ,IAAK,WAAW,MAAM,OAAO,SAAS;MAC7C,IAAI,QAAQ,IAAK,WAAW,MAAM,OAAO,WAAW;MACpD,IAAI,CAAC,WAAW,WAAW;CAEhC,MAAM,cAAc,YAAY,KAAK,MAAM,QAAQ,SAAS,IAAI;CAChE,MAAM,aAAa,YAAY;CAC/B,MAAM,MAAM,WAAW,OAAO,WAAW,IAAI,UAAU,OAAO,UAAU;CAExE,MAAM,aAAa,YAAY,GAAG,KAAK,MAAM,QAAQ,GAAG,EAAE,KAAK;CAC/D,MAAM,cAAc,YAChB,IAAI,UAAU,QAAQ,QAAQ,CAAC,EAAE,MAAM,OAAO,QAAQ,CAAC,MACvD,IAAI,UAAU,QAAQ,QAAQ,CAAC,EAAE;CAIrC,MAAM,kBACJ,UAAU,cAAc,MACpB,IAAI,UAAU,aAAa,IAAA,CAAM,QAAQ,CAAC,EAAE,KAC5C,OAAO,UAAU,UAAU;CAEjC,OAAO,MAAM,cACX,QACA;EACE,OAAO;EACP,UAAU,OAAO,UAAU,MAAM;EACjC,aAAa,QAAQ,KAAM,UAAU,QAAQ,KAAM,YAAY;EAC/D,YAAY;EACZ,OAAO;CACT,GACA,MAAM,cACJ,KACA;EAAE,eAAe;EAAU,KAAK;EAAG,UAAU;CAAE,GAE/C,MAAM,cAAc,MAAM;EAAE,MAAM;EAAM,OAAO;CAAI,GAAG,IAAI,GAC1D,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,KAAK;CAAE,GAC/B,MAAM,cAAc,MAAM,EAAE,OAAO,SAAS,GAAG,GAAG,GAClD,MAAM,cAAc,MAAM,EAAE,OAAO,SAAS,GAAG,IAAI,YAAY,CACjE,GACA,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,WAAW,GAErD,MAAM,cACJ,KACA,EAAE,UAAU,EAAE,GACd,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,IAAI,OAAO,EAAE,CAAC,CAC1D,GAEA,MAAM,cAAc,MAAM;EAAE,MAAM;EAAM,OAAO;CAAI,GAAG,IAAI,GAC1D,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,KAAK;EAAG,YAAY;CAAE,GAC9C,MAAM,cAAc,UAAU;EAC5B,OAAO;EACP,OAAO;EACP;EACA;CACF,CAAC,GACD,MAAM,cAAc,UAAU;EAC5B,OAAO;EACP,OAAO,IAAI,UAAU,QAAQ,QAAQ,CAAC;EACtC;EACA;CACF,CAAC,GACD,MAAM,cAAc,UAAU;EAC5B,OAAO;EACP,OAAO,OAAO,UAAU,KAAK;EAC7B;EACA;CACF,CAAC,CACH,GAEA,MAAM,cACJ,KACA,EAAE,UAAU,EAAE,GACd,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,IAAI,OAAO,EAAE,CAAC,CAC1D,GAEA,MAAM,cAAc,MAAM;EAAE,MAAM;EAAM,OAAO;CAAI,GAAG,MAAM,GAC5D,MAAM,cAAc,MAAM,EAAE,OAAO,IAAI,GAAG,UAAU,gBAAgB,IAAI,CAC1E,CACF;AACF;;;;;;;;;;;;;;;;AC7HA,MAAM,qBACJ;;AAGF,MAAM,eAAe;AACrB,MAAM,cAAc;;;;;;;AAQpB,SAAgB,cAAc,EAC5B,WACA,SACA,aACA,WACA,UACyC;CAEzC,MAAM,SADQ,SACK,CAAC,CAAC,OAAO;CAC5B,MAAM,CAAC,UAAU,eAAe,SAAS,YAAY;CAsBrD,WAlBkB,aACf,QAAgB,QAAa;EAC5B,IAAI,IAAI,WAAW,IAAI,WAAW;GAChC,aAAa,SAAU,SAAS,eAAe,cAAc,YAAa;GAC1E;EACF;EACA,IAAI,IAAI,QAAQ;GACd,IAAI,aAAa,cAAc,UAAU;QACpC,OAAO;GACZ;EACF;EACA,IAAI,IAAI,QACN,OAAO;CAEX,GACA;EAAC;EAAU;EAAW;CAAM,CAGV,CAAC;CAIrB,MAAM,aAAa,cACf,oCACQ,YAAY,MAAM,GAAG,YAAY,aAAa,cAC1C,YAAY,aAAa,WACrC;CAEJ,MAAM,kBAAkB,aAAa;CAErC,OAAO,MAAM,cACX,KACA;EAAE,eAAe;EAAU,UAAU;CAAE,GAGvC,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,IAAI,OAAO,EAAE,CAAC,GAG5D,MAAM,cAAc,KAAK,EAAE,QAAQ,EAAE,CAAC,GAGtC,MAAM,cAAc,MAAM;EAAE,MAAM;EAAM,OAAO;CAAO,GAAG,QAAQ,GACjE,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,MAAM,SAAS,GAG7D,MAAM,cAAc,KAAK,EAAE,QAAQ,EAAE,CAAC,GAGtC,MAAM,cACJ,MACA,MACA,iBACA,MAAM,cAAc,MAAM,EAAE,OAAO,OAAO,GAAG,SAAS,CACxD,GAGA,MAAM,cAAc,KAAK,EAAE,QAAQ,EAAE,CAAC,GAGtC,MAAM,cAAc,MAAM,MAAM,KAAK,YAAY,GAGjD,MAAM,cAAc,KAAK,EAAE,QAAQ,EAAE,CAAC,GAGtC,MAAM,cACJ,MACA;EAAE,OAAO,kBAAkB,SAAS,KAAA;EAAW,MAAM;CAAgB,GACrE,kBAAkB,qBAAqB,kBACzC,GACA,MAAM,cACJ,MACA;EACE,OAAO,CAAC,kBAAkB,SAAS,KAAA;EACnC,MAAM,CAAC;EACP,UAAU;CACZ,GACA,CAAC,kBAAkB,gBAAgB,aACrC,GAGA,MAAM,cAAc,KAAK,EAAE,QAAQ,EAAE,CAAC,GAGtC,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,qBAAqB,GAGnE,MAAM,cAAc,KAAK,EAAE,QAAQ,EAAE,CAAC,GAGtC,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,IAAI,OAAO,EAAE,CAAC,CAC9D;AACF;;;;;;;;;ACzIA,MAAM,eAA6B;CAAE,SAAS;CAAI,MAAM;AAAG;;;;;AAM3D,SAAgB,kBAAgC;CAC9C,MAAM,EAAE,WAAW,UAAU;CAC7B,MAAM,CAAC,MAAM,WAAW,gBAA8B;EACpD,SAAS,QAAQ,WAAW,aAAa;EACzC,MAAM,QAAQ,QAAQ,aAAa;CACrC,EAAE;CAEF,gBAAgB;EACd,IAAI,CAAC,QAAQ;EAEb,MAAM,iBAAiB;GACrB,QAAQ;IACN,SAAS,OAAO,WAAW,aAAa;IACxC,MAAM,OAAO,QAAQ,aAAa;GACpC,CAAC;EACH;EAEA,OAAO,GAAG,UAAU,QAAQ;EAC5B,aAAa;GACX,OAAO,IAAI,UAAU,QAAQ;EAC/B;CACF,GAAG,CAAC,MAAM,CAAC;CAEX,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;ACKA,SAAgB,UAAU,EAAE,eAA8C;CACxE,MAAM,CAAC,cAAc,mBAAmB,SAAS,CAAC;CAClD,MAAM,CAAC,cAAc,sBAAsB,SAAS,CAAC;CACrD,MAAM,CAAC,cAAc,mBAAmB,SAAS,IAAI;CAGrD,MAAM,kBAAkB,OAAO,YAAY;CAC3C,gBAAgB,UAAU;CAE1B,MAAM,aAAa,KAAK,IAAI,cAAc,GAAG,CAAC;CAC9C,MAAM,aAAa,eAAe;CAClC,MAAM,eAAe,KAAK,IAAI,aAAa,YAAY,CAAC;CACxD,MAAM,cAAc;;CAGpB,MAAM,kBAAkB,aAAa,UAAkB;EACrD,mBAAmB,KAAK;EACxB,IAAI,gBAAgB,SAClB,gBAAgB,CAAC;CAErB,GAAG,CAAC,CAAC;;CAGL,MAAM,eAAe,kBAAkB;EACrC,gBAAgB,CAAC;EACjB,gBAAgB,IAAI;CACtB,GAAG,CAAC,CAAC;CAqEL,OAAO;EACL;EACA;EACA;EACA;EACA;EACA,WAxEgB,aACf,OAAe,QAAsB;GAEpC,IAAI,IAAI,UAAW,IAAI,QAAQ,UAAU,KAAM;IAC7C,gBAAgB,KAAK;IACrB,iBAAiB,SAAS;KACxB,MAAM,OAAO,KAAK,MAAM,aAAa,CAAC;KACtC,MAAM,MAAM,KAAK,IAAI,GAAG,eAAe,UAAU;KACjD,OAAO,KAAK,IAAI,OAAO,MAAM,GAAG;IAClC,CAAC;IACD,OAAO;GACT;GAGA,IAAI,IAAI,YAAa,IAAI,QAAQ,UAAU,KAAM;IAC/C,MAAM,OAAO,eAAe,KAAK,MAAM,aAAa,CAAC;IACrD,IAAI,QAAQ,GACV,aAAa;SACR;KACL,gBAAgB,KAAK;KACrB,gBAAgB,IAAI;IACtB;IACA,OAAO;GACT;GAGA,IAAI,IAAI,MAAM;IACZ,MAAM,MAAM,KAAK,IAAI,GAAG,eAAe,UAAU;IACjD,gBAAgB,KAAK;IACrB,gBAAgB,GAAG;IACnB,OAAO;GACT;GAGA,IAAI,IAAI,KAAK;IACX,aAAa;IACb,OAAO;GACT;GAEA,OAAO;EACT,GACA;GAAC;GAAc;GAAY;GAAc;EAAY,CA+B7C;EACR;EACA,UA7Be,kBAAkB;GACjC,gBAAgB,KAAK;GACrB,iBAAiB,SAAS;IACxB,MAAM,MAAM,KAAK,IAAI,GAAG,eAAe,UAAU;IACjD,OAAO,KAAK,IAAI,OAAO,GAAG,GAAG;GAC/B,CAAC;EACH,GAAG,CAAC,cAAc,UAAU,CAuBnB;EACP,YArBiB,kBAAkB;GACnC,iBAAiB,SAAS;IACxB,MAAM,OAAO,OAAO;IACpB,IAAI,QAAQ,GAAG;KACb,aAAa;KACb,OAAO;IACT;IACA,gBAAgB,KAAK;IACrB,OAAO;GACT,CAAC;EACH,GAAG,CAAC,YAAY,CAWL;CACX;AACF;;;;AChJA,SAAgB,gBAAgB,UAAkB,QAAmB;CACnE,MAAM,QAAqB,CAAC,EAAE,IAAI,QAAQ,CAAC;CAE3C,OAAO;EACL,KAAK,MAAuB;GAC1B,MAAM,KAAK,IAAI;EACjB;EAEA,MAA6B;GAC3B,IAAI,MAAM,SAAS,GACjB,OAAO,MAAM,IAAI;EAGrB;EAEA,QAAQ,MAAuB;GAC7B,IAAI,MAAM,SAAS,GACjB,MAAM,MAAM,SAAS,KAAK;QAE1B,MAAM,KAAK,IAAI;EAEnB;EAEA,MAA6B;GAC3B,OAAO,MAAM,MAAM,SAAS;EAC9B;EAEA,UAAuB;GACrB,OAAO,CAAC,GAAG,KAAK;EAClB;CACF;AACF;;;;;;;;;;;;;;;;;;;;;ACgBA,MAAM,mBAAmB;;AAGzB,MAAM,oBAAoB;;AAE1B,MAAM,wBAAwB;;;;;;AAO9B,SAAS,gBAAgB,WAA2B;CAClD,MAAM,UAAU,KAAK,OAAO,KAAK,IAAI,IAAI,aAAa,GAAI;CAC1D,IAAI,UAAU,IAAI,OAAO;CACzB,MAAM,UAAU,KAAK,MAAM,UAAU,EAAE;CACvC,IAAI,UAAU,IAAI,OAAO,GAAG,QAAQ;CACpC,MAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;CACrC,IAAI,QAAQ,IAAI,OAAO,GAAG,MAAM;CAChC,MAAM,OAAO,KAAK,MAAM,QAAQ,EAAE;CAClC,IAAI,OAAO,IAAI,OAAO,GAAG,KAAK;CAE9B,OAAO,GADQ,KAAK,MAAM,OAAO,EAClB,EAAE;AACnB;;AAGA,SAAgB,IAAI,OAAqC;CACvD,MAAM,EAAE,WAAW,SAAS,UAAU,sBAAsB;CAC5D,MAAM,EAAE,SAAS,gBAAgB;CACjC,MAAM,QAAQ,SAAS;CAMvB,MAAM,cAAc,MAAM,gBAAgB;CAC1C,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CAIpD,MAAM,aAAa,OAA6B,IAAI;CAIpD,MAAM,aAAa,KAAK,IAAI,OAAO,GAAG,CAAC;CACvC,MAAM,SAAS,UAAU,EAAE,aAAa,WAAW,CAAC;CAIpD,MAAM,eAAe,OAAO,gBAAgB,CAAC;CAC7C,MAAM,CAAC,aAAa,kBAAkB,SAAoB,EAAE,IAAI,OAAO,CAAC;;CAGxE,MAAM,kBAAkB,OAAO,uBAAuB,CAAC;;CAGvD,MAAM,oBAAoB,kBAAkB;EAC1C,gBAAgB,QAAQ,eAAe;GACrC,OAAO,gBAAgB,WAAW,SAAS,cAAc,KAAK,CAAC;EACjE,CAAC;CACH,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,WAAW,aAAa,SAAoB;EAChD,aAAa,QAAQ,KAAK,IAAI;EAC9B,eAAe,aAAa,QAAQ,IAAI,CAAE;CAC5C,GAAG,CAAC,CAAC;CAEL,MAAM,UAAU,kBAAkB;EAChC,aAAa,QAAQ,IAAI;EACzB,eAAe,aAAa,QAAQ,IAAI,CAAE;CAC5C,GAAG,CAAC,CAAC;CAIL,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,CAAC,YAAY,iBAAiB,SAAS,CAAC;CAG9C,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;;CAEtD,MAAM,CAAC,gBAAgB,qBAAqB,SAA6B,SAAS;CAGlF,MAAM,CAAC,YAAY,iBAAiB,SAAS,CAAC;CAC9C,MAAM,CAAC,SAAS,cAAc,SAAS,CAAC;CAGxC,MAAM,EAAE,SAAS,oBAAoB,MAAM,qBAAqB,iBAAiB;CAGjF,MAAM,mBAAmB,OAA8B,IAAI;CAC3D,MAAM,0BAA0B,OAAO,CAAC;;CAGxC,MAAM,gBAAgB,kBAAkB;EACtC,IAAI,iBAAiB,SAAS;GAC5B,aAAa,iBAAiB,OAAO;GACrC,iBAAiB,UAAU;EAC7B;EACA,wBAAwB,UAAU;EAClC,iBAAiB,UAAU,iBAAiB;GAC1C,wBAAwB;GACxB,IAAI,wBAAwB,WAAW,uBACrC,WAAW,SAAS,UAAU,kDAAkD,MAAM;QACjF;IACL,WAAW,SAAS,UAAU,iCAAiC,MAAM;IAErE,cAAc;GAChB;EACF,GAAG,iBAAiB;CACtB,GAAG,CAAC,CAAC;;CAGL,MAAM,gBAAgB,kBAAkB;EACtC,IAAI,iBAAiB,SAAS;GAC5B,aAAa,iBAAiB,OAAO;GACrC,iBAAiB,UAAU;EAC7B;EACA,wBAAwB,UAAU;CACpC,GAAG,CAAC,CAAC;CAIL,MAAM,CAAC,cAAc,mBAAmB,SAAS,CAAC;CAMlD,MAAM,CAAC,mBAAmB,wBAAwB,SAMxC,IAAI;CAId,MAAM,sBAAsB,aACzB,YAAoB;EACnB,QAAQ;EACR,QAAQ,SAAR;GACE,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,WAAW,CAAC;IAC3B;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,OAAO,CAAC;IACvB;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,QAAQ,CAAC;IACxB;GACF,KAAK;GACL,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,WAAW,CAAC;IAC3B;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,QAAQ,CAAC;IACxB;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,SAAS,CAAC;IACzB;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,QAAQ,CAAC;IACxB;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,cAAc,CAAC;IAC9B;GACF,KAAK;IACH,SAAS,EAAE,IAAI,MAAM,CAAC;IACtB;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,SAAS,CAAC;IACzB;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,SAAS,CAAC;IACzB;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,aAAa,CAAC;IAC7B;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,UAAU,CAAC;IAC1B;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,QAAQ,CAAC;IACxB;GAEF,KAAK;GACL,KAAK;IACH,SAAS;KACP,IAAI;KACJ,OAAO;MACL,OAAO;MACP,aAAa;MACb,YAAY,UAAkB;OAC5B,MAAM,UAAU,kBAAkB,SAAS,SAAS;OACpD,QAAQ;MACV;KACF;IACF,CAAC;IACD;GACF,KAAK;GACL,KAAK;IACH,SAAS;KACP,IAAI;KACJ,OAAO;MACL,OAAO;MACP,aAAa;MACb,YAAY,UAAkB;OAC5B,MAAM,UAAU,gBAAgB,SAAS,QAAQ,SAAS,SAAS,WAAW;OAC9E,QAAQ;MACV;KACF;IACF,CAAC;IACD;GACF,KAAK;GACL,KAAK;IACH,SAAS;KACP,IAAI;KACJ,OAAO;MACL,OAAO;MACP,aAAa;MACb,cAAc,SAAS,SAAS;MAChC,YAAY,aAAqB;OAC/B,IAAI,UAAU,MAAM,UAAU,kBAAkB,QAAQ;OACxD,QAAQ;MACV;KACF;IACF,CAAC;IACD;GACF,KAAK;GACL,KAAK;IACH,SAAS;KACP,IAAI;KACJ,OAAO,EACL,mBAAmB,cAAsB;MAEvC,SAAS;OACP,IAAI;OACJ,OAAO;QACL,OAAO;QACP,SAAS;QACT,iBAAiB;SACf,MAAM,UAAU,kBAAkB,SAAS;SAC3C,QAAQ;SACR,QAAQ;QACV;OACF;MACF,CAAC;KACH,EACF;IACF,CAAC;IACD;GACF,KAAK;GACL,KAAK;IACH,SAAS;KACP,IAAI;KACJ,OAAO,EACL,mBAAmB,cAAsB;MACvC,MAAM,UAAU,kBAAkB,SAAS;MAC3C,QAAQ;KACV,EACF;IACF,CAAC;IACD;GACF,KAAK;GACL,KAAK;IACH,SAAS;KACP,IAAI;KACJ,OAAO;MACL,OAAO;MACP,SAAS;MACT,iBAAiB;OACf,MAAM,UAAU,mBAAmB;OACnC,QAAQ;MACV;KACF;IACF,CAAC;IACD;GAEF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,OAAO,CAAC;IACvB;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,YAAY,CAAC;IAC5B;GACF,KAAK;GACL,KAAK;IACH,SAAS,EAAE,IAAI,QAAQ,CAAC;IACxB;GACF,SACE,WAAW,SAAS,UAAU,YAAY,QAAQ,yBAAyB,MAAM;EACrF;CACF,GACA,CAAC,UAAU,OAAO,CACpB;CAIA,MAAM,kBAAkB,aACrB,OAAe,QAAa;EAC3B,IAAI,OAAO,UAAU,OAAO,GAAG,GAAG;EAGlC,MAAM,cAAc,IAAI,IAAI;GAC1B;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,CAAC;EACD,IAAI,IAAI,UAAU,YAAY,OAAO,UAAU,CAAC,YAAY,IAAI,YAAY,EAAE,GAC5E,QAAQ;EAIV,IAAI,IAAI,QAAQ,UAAU,OAAO,YAAY,OAAO,QAAQ;GAC1D,MAAM,iBAAiB,YAAY;IACjC,IAAI;KACF,MAAM,SAAS,MAAM,UAAU,uBAAuB,EAAE;KACxD,IAAI,QAAQ,iBAAiB,MAAM;IACrC,QAAQ,CAER;GACF;GACA,eAAe;EACjB;EAGA,IAAI,IAAI,QAAQ,UAAU,OAAO,YAAY,OAAO,QAClD,mBAAmB,SAAU,SAAS,YAAY,SAAS,SAAU;CAEzE,GACA;EAAC,YAAY;EAAI;EAAQ;EAAS;CAAS,CAC7C;CAEA,YAAa,OAAe,QAAa;EAGvC,IAAI,MAAM,SAAS,QAAQ,KAAK,sBAAsB,KAAK,MAAM,KAAK,CAAC,GAAG;EAC1E,gBAAgB,OAAO,GAAG;CAC5B,CAAC;CAID,MAAM,cAAc,kBAAkB;EACpC,MAAM,OAAO,aAAa;EAC1B,cAAc,IAAI;EAElB,IAAI,SAAS,GAAG;GACd,UAAU,QAAQ;GAClB,WAAW,SAAS,UAClB,4DACA,MACF;GACA,kBAAkB;EACpB,OAAO,IAAI,SAAS,GAAG;GACrB,WAAW,SAAS,UAAU,iDAAiD,OAAO;GACtF,WAAW,SAAS,cAAc;GAClC,aAAa,KAAK;GAClB,kBAAkB;EACpB,OACE,QAAQ,KAAK,CAAC;CAElB,GAAG;EAAC;EAAY;EAAW;CAAiB,CAAC;;CAK7C,SAAS,kBAAkB,OAA6B;EACtD,MAAM,OAAO,WAAW;EACxB,IAAI,CAAC,MAAM;EAEX,IAAI,MAAM,SAAS;OACb,MAAM,WAAW,WACnB,KAAK,UAAU,QAAQ,MAAM;QACxB,IAAI,MAAM,cAAc,MAC7B,KAAK,aAAa,MAAM,QAAQ,IAAI,MAAM,UAAU;EAAA,OAEjD,IAAI,MAAM,SAAS,cAAc;GACtC,cAAc;GACd,oBAAoB,UAAU;GAC9B,IAAI,CAAC,uBAAuB,SAAS;IACnC,KAAK,kBAAkB;IACvB,KAAK,eAAe,MAAM,IAAI;IAC9B,uBAAuB,UAAU;GACnC,OACE,KAAK,gBAAgB,MAAM,IAAI;EAEnC,OAAO,IAAI,MAAM,SAAS,YAAY;GACpC,IAAI,CAAC,uBAAuB,SAAS;IACnC,KAAK,kBAAkB;IAEvB,KAAK,eAAe,EAAE;IACtB,uBAAuB,UAAU;GACnC;GACA,aAAa,QAAQ,KAAK,MAAM,IAAI;GACpC,iBAAiB;IACf,KAAK,QAAQ,MAAM;IACnB,MAAM,WAAW,MAAM,KAAK;IAC5B,UAAU;GACZ,CAAC;GACD,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM;EACvC,OAAO,IAAI,MAAM,SAAS,eAAe;GACvC,iBAAiB;IACf,KAAK,QAAQ,MAAM;IACnB,MAAM,GAAG,MAAM,QAAQ,MAAM,GAAG,EAAE,EAAE;IACpC,UAAU;GACZ,CAAC;GACD,KAAK,iBAAiB,MAAM,QAAQ,MAAM,OAAO;EACnD,OAAO,IAAI,MAAM,SAAS,cACxB,KAAK,UAAU,MAAM,SAAS,MAAM;OAC/B,IAAI,MAAM,SAAS,SAAS;GACjC,KAAK,kBAAkB;GACvB,KAAK,UAAU,UAAU,MAAM,WAAW,OAAO;GACjD,iBAAiB;IAAE,KAAK,OAAO,KAAK,IAAI;IAAK,MAAM,MAAM;IAAS,UAAU;GAAY,CAAC;EAC3F,OAAO,IAAI,MAAM,SAAS,QAAQ;GAChC,IAAI,uBAAuB,SAAS;IAClC,KAAK,kBAAkB;IAEvB,IAAI,CAAC,oBAAoB,SAAS;KAChC,MAAM,QAAQ,aAAa;KAC3B,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;KACjC,MAAM,WACJ,OAAO,SAAS,IACZ,GAAG,OAAO,KAAK,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,KAAK,EAAE,SAAS,MAAM,OAAO,UACnE;KACN,KAAK,UAAU,UAAU,MAAM;IACjC;GACF,OACE,KAAK,gBAAgB;GAGvB,IAAI,OAAO,MAAM,gBAAgB,YAAY,MAAM,cAAc,GAC/D,eAAe,SAAS,OAAO,MAAM,WAAY;GAEnD,IAAI,OAAO,MAAM,YAAY,YAAY,MAAM,UAAU,GACvD,YAAY,SAAS,OAAO,MAAM,OAAQ;EAE9C;CACF;CAEA,MAAM,yBAAyB,OAAO,KAAK;;CAE3C,MAAM,sBAAsB,OAAO,KAAK;;CAExC,MAAM,eAAe,OAAiB,CAAC,CAAC;CAIxC,MAAM,eAAe,YACnB,OAAO,SAAiB;EACtB,IAAI,KAAK,WAAW,GAAG,GAAG;GACxB,oBAAoB,KAAK,KAAK,CAAC;GAC/B;EACF;EAEA,cAAc,CAAC;EACf,uBAAuB,UAAU;EACjC,oBAAoB,UAAU;EAC9B,aAAa,UAAU,CAAC;EACxB,WAAW,SAAS,QAAQ,MAAM,IAAI;EACtC,kBAAkB;EAClB,aAAa,IAAI;EAEjB,IAAI;GACF,WAAW,MAAM,SAAS,UAAU,QAAQ,IAAI,GAAG;IACjD,kBAAkB,KAAK;IACvB,kBAAkB;GACpB;EACF,SAAS,KAAK;GACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAC/D,WAAW,SAAS,kBAAkB;GACtC,WAAW,SAAS,UAAU,iBAAiB,WAAW,OAAO;GACjE,WAAW,SAAS,cAAc;GAClC,kBAAkB;EACpB,UAAU;GACR,cAAc;GACd,aAAa,KAAK;EACpB;CACF,GACA;EAAC;EAAW;EAAmB;EAAqB;CAAa,CACnE;CAIA,MAAM,0BAA0B,aAC7B,QAA2F;EAC1F,qBAAqB;GACnB,WAAW,IAAI;GACf,UAAU,IAAI;GACd,QAAQ,IAAI;GACZ,aAAa,IAAI;EACnB,CAAC;EACD,SAAS,EAAE,IAAI,aAAa,CAAC;CAC/B,GACA,CAAC,QAAQ,CACX;CAIA,MAAM,CAAC,YAAY,iBAAiB,SAAuB,CAAC,CAAC;;CAE7D,MAAM,CAAC,eAAe,oBAAoB,SAA6B,KAAA,CAAS;;CAGhF,MAAM,oBAAoB,aAAa,SAAiB;EACtD,MAAM,QAAoB;GACxB,IAAI,OAAO,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC;GAClC,SAAS,KAAK,MAAM,GAAG,GAAG;GAC1B,WAAW,KAAK,IAAI;EACtB;EACA,eAAe,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC;CACxD,GAAG,CAAC,CAAC;CAGL,gBAAgB;EACd,oBAAoB,uBAAuB;EAC3C,aAAa;GAEX,oBAAoB,IAAI;EAC1B;CACF,GAAG,CAAC,mBAAmB,uBAAuB,CAAC;CAI/C,MAAM,UAAU,YAAY,OAAO;CACnC,MAAM,kBAAkB,OAAO,eAAe,OAAO;;CAKrD,SAAS,mBAAuC;EAC9C,OAAO,MAAM,cAAc,mBAAmB;GAC5C,SAAS;IACP,WAAW,kBAAmB;IAC9B,UAAU,kBAAmB;IAC7B,QAAQ,kBAAmB;IAC3B,aAAa,kBAAmB;IAChC,YAAY,kBAAmB;GACjC;GACA,WAAW,IAAI,WAAW;IACxB,MAAM,WAAW,WAAW,WAAW,WAAW;IAClD,UAAU,kBAAkB,IAAI,QAAQ;IACxC,qBAAqB,IAAI;IACzB,QAAQ;GACV;GACA,gBAAgB;IACd,UAAU,kBAAkB,kBAAmB,WAAW,KAAK;IAC/D,qBAAqB,IAAI;IACzB,QAAQ;GACV;EACF,CAAC;CACH;;CAGA,SAAS,iBAAqC;EAC5C,MAAM,YAAY,YAAY;EAG9B,OAAO,MAAM,cAAc,eAAe;GACxC;GACA,UACE,WAAW,sBACT,cAAc;IACd,UAAU,cAAc,SAAS;IACjC,QAAQ;GACV;GACF,gBAAgB,QAAQ;EAC1B,CAAC;CACH;;CAGA,SAAS,cAAkC;EACzC,OAAO,MAAM,cAAc,aAAa;GACtC,QAAQ,MAAM,UAAU,CAAC;GACzB,cAAc,MAAM;GACpB,WAAW,YAAY;IACrB,MAAM,UAAU,cAAc,OAAO;IACrC,QAAQ;GACV;GACA,cAAc,MAAM,UAAU,eACzB,YAAY,MAAM,UAAU,cAAc,OAAO,IAClD,KAAA;GACJ,gBAAgB,QAAQ;EAC1B,CAAC;CACH;;CAGA,SAAS,cAAkC;EACzC,OAAO,MAAM,cAAc,aAAa;GACtC,WAAW,cAAyB;IAClC,SAAS,SAAS;IAClB,iBAAiB,MAAM,IAAI,CAAC;IAC5B,MAAM,UAAU,gBAAgB,SAAS;IACzC,QAAQ;GACV;GACA,gBAAgB,QAAQ;EAC1B,CAAC;CACH;;CAGA,SAAS,gBAAoC;EAC3C,MAAM,eAAe,YAAY,SAAS,CAAC;EAC3C,OAAO,MAAM,cAAc,eAAe;GACxC,OAAQ,aAAa,SAAoB;GACzC,SAAU,aAAa,WAAsB;GAC7C,cAAc,aAAa;GAC3B,aAAa,aAAa;GAC1B,iBAAiB;IACf,aAAc,YAAyC;IACvD,QAAQ;GACV;GACA,gBAAgB,QAAQ;EAC1B,CAAC;CACH;;CAGA,SAAS,oBAAwC;EAC/C,MAAM,cAAc,YAAY,SAAS,CAAC;EAC1C,OAAO,MAAM,cAAc,aAAa;GACtC,OAAQ,YAAY,SAAoB;GACxC,cAAc,YAAY;GAC1B,aAAa,YAAY;GACzB,YAAY,UAAU;IACpB,YAAa,YAAkD,KAAK;IACpE,QAAQ;GACV;GACA,gBAAgB,QAAQ;EAC1B,CAAC;CACH;;CAGA,MAAM,iBAA2D;EAC/D,YAAY;EACZ,UAAU;EACV,YAAY,MAAM,cAAc,WAAW,EAAE,gBAAgB,QAAQ,EAAE,CAAC;EACxE,gBACE,MAAM,cAAc,gBAAgB;GAClC,WAAW,QAAQ,oBAAoB,GAAG;GAC1C,gBAAgB,QAAQ;EAC1B,CAAC;EACH,OAAO;EACP,gBACE,MAAM,cAAc,YAAY;GAC9B,WAAW,KAAK,UAAU;IACxB,MAAM,UAAU,iBAAiB,KAAK,KAAK;GAC7C;GACA,SAAS,KAAK,OAAO,cAAc,cAAc;IAC/C,SAAS;KACP,IAAI;KACJ,OAAO;MACL,OAAO,SAAS;MAChB,cAAc;MACd,aAAa,uBAAuB;MACpC,YAAY,aAAqB;OAE/B,MAAM,aACJ,cAAc,YAAY,CAAC,MAAM,OAAO,QAAQ,CAAC,IAAI,OAAO,QAAQ,IAAI;OAC1E,MAAM,UAAU,iBAAiB,KAAK,UAAU;OAChD,QAAQ;MACV;KACF;IACF,CAAC;GACH;GACA,gBAAgB,QAAQ;EAC1B,CAAC;EACH,OAAO;EACP,SAAS;EACT,cACE,MAAM,cAAc,aAAa;GAC/B,QAAQ,iBAAiB;GACzB,gBAAgB,QAAQ;EAC1B,CAAC;EACH,cAAc;EACd,mBACE,MAAM,cAAc,YAAY;GAC9B,WAAW,SAAS,aAAa,QAAQ,IAAI;GAC7C,WAAW,aAAa;IACtB,iBAAiB,QAAQ;IACzB,QAAQ;GACV;GACA,gBAAgB,QAAQ;EAC1B,CAAC;EACH,aACE,MAAM,cAAc,aAAa;GAC/B,OAAO;GACP,YAAY,OAAO;IACjB,MAAM,QAAQ,WAAW,MAAM,MAAM,EAAE,OAAO,EAAE;IAChD,IAAI,OAAO,iBAAiB,MAAM,OAAO;IACzC,QAAQ;GACV;GACA,WAAW,OAAO;IAChB,eAAe,SAAS,KAAK,QAAQ,MAAM,EAAE,OAAO,EAAE,CAAC;GACzD;GACA,gBAAgB,QAAQ;EAC1B,CAAC;EACH,WACE,MAAM,cAAc,UAAU;GAC5B,aAAa,MAAM,kBAAkB,CAAC;GACtC,YAAY,SAAS,MAAM,UAAU,eAAe,IAAI;GACxD,eAAe,SAAS,MAAM,UAAU,kBAAkB,IAAI;GAC9D,cAAc,SAAS,MAAM,UAAU,iBAAiB,IAAI;GAC5D,gBAAgB,QAAQ;EAC1B,CAAC;EACH,cACE,MAAM,cAAc,aAAa;GAC/B,SAAS,MAAM,WAAW,CAAC;GAC3B,SAAS,SAAS,MAAM,UAAU,eAAe,IAAI;GACrD,WAAW,SAAS,MAAM,UAAU,iBAAiB,IAAI;GACzD,gBAAgB,QAAQ;EAC1B,CAAC;EACH,cACE,MAAM,cAAc,YAAY;GAC9B,QAAQ,MAAM,UAAU,CAAC;GACzB,gBAAgB,QAAQ;EAC1B,CAAC;EACH,eACE,MAAM,cAAc,cAAc;GAChC,aAAa,MAAM,eAAe;IAChC,aAAa;IACb,OAAO;IACP,QAAQ;IACR,OAAO,MAAM,gBAAgB;IAC7B,WAAW,SAAS,aAAa,QAAQ,IAAI;IAC7C,cAAc,SAAS,SAAS;GAClC;GACA,gBAAgB,QAAQ;EAC1B,CAAC;EACH,aACE,MAAM,cAAc,YAAY;GAC9B,WAAW,MAAM,aAAa;IAC5B;IACA;IACA,iBAAiB;IACjB,cAAc;IACd,OAAO;IACP,cAAc,MAAM,eAAe,GAAG,MAAM,aAAa,SAAS;GACpE;GACA,gBAAgB,QAAQ;EAC1B,CAAC;EACH,YACE,MAAM,cAAc,YAAY;GAC9B,eAAe,UAAU;GACzB,gBAAgB,QAAQ;EAC1B,CAAC;EACH,iBACE,MAAM,cAAc,iBAAiB;GACnC,oBAAoB,UAAU;GAC9B,gBAAgB,QAAQ;EAC1B,CAAC;EACH,aACE,MAAM,cAAc,YAAY;GAC9B,gBAAgB,UAAU;GAC1B,gBAAgB,QAAQ;EAC1B,CAAC;EACH,kBACE,MAAM,cAAc,aAAa;GAC/B,QAAQ,MAAM,UAAU,CAAC;GACzB,WAAW,cAAc;IACvB,WAAW,SAAS,UAAU,iBAAiB,aAAa,MAAM;IAClE,QAAQ;GACV;GACA,gBAAgB,QAAQ;EAC1B,CAAC;CACL;;CAGA,SAAS,cAAyC;EAChD,IAAI,YAAY,OAAO,gBAAgB,CAAC,mBAAmB,OAAO;EAClE,MAAM,WAAW,eAAe,YAAY;EAC5C,OAAO,WAAW,SAAS,IAAI;CACjC;CAMA,IAAI,eAAe,CAAC,aAClB,OAAO,MAAM,cAAc,eAAe;EACxC,WAAW,SAAS,aAAa,QAAQ,IAAI;EAC7C,SAAS;EACT,aAAa,UACT;GACE,OAAO,QAAQ;GACf,cAAc,gBAAgB,QAAQ,SAAS;GAC/C,cAAc,SAAS;EACzB,IACA,KAAA;EACJ,iBAAiB,eAAe,IAAI;EACpC,cAAc,QAAQ,KAAK,CAAC;CAC9B,CAAC;CAGH,OAAO,MAAM,cACX,KACA;EAAE,eAAe;EAAU,QAAQ;CAAK,GAGxC,MAAM,cACJ,KACA;EAAE,eAAe;EAAO,gBAAgB;EAAiB,cAAc;CAAE,GACzE,MAAM,cAAc,MAAM;EAAE,MAAM;EAAM,OAAO,MAAM,OAAO;CAAO,GAAG,MAAM,GAC5E,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,SAAS,SAAS,YAAY,CAC9E,GAGA,MAAM,cACJ,KACA;EAAE,eAAe;EAAU,QAAQ;EAAY,UAAU;CAAS,GAClE,MAAM,cAAc,SAAS;EAC3B,KAAK;EACL,cAAc,kBACV;GAAE,OAAO,OAAO;GAAc,KAAK,OAAO;EAAW,IACrD,KAAA;EACJ,sBAAsB;EACtB;CACF,CAAC,GAGD,CAAC,OAAO,gBAAgB,OAAO,cAAc,IACzC,MAAM,cACJ,KACA;EAAE,UAAU;EAAG,UAAU;CAAE,GAC3B,MAAM,cACJ,MACA;EAAE,OAAO,MAAM,OAAO;EAAQ,SAAS;CAAK,GAC5C,MAAM,OAAO,YAAY,+BAC3B,CACF,IACA,IACN,GAGA,qBACI,MAAM,cACJ,KACA,EAAE,UAAU,EAAE,GACd,MAAM,cAAc,oBAAoB,EAAE,SAAS,mBAAmB,CAAC,CACzE,IACA,MAGJ,MAAM,cACJ,KACA,EAAE,eAAe,SAAS,GAC1B,MAAM,cAAc,UAAU;EAC5B,UAAU;EACV,SAAS;EACT,UAAU,aAAa;EACvB,WAAW,SAAS;EACpB,aACE,aAAa,IACT,UAAU,WAAW,GAAG,iBAAiB,uBACzC;EACN,SAAS;EACT,YAAY;EACZ,4BAA4B,iBAAiB,KAAA,CAAS;CACxD,CAAC,CACH,GAGA,MAAM,cAAc,WAAW;EAC7B,MAAM,aAAa,IAAI,SAAS,WAAW,GAAG,qBAAqB;EACnE,OAAO,MAAM,gBAAgB;EAC7B;EACA,UAAU,YAAY;EACtB;EACA;EACA,cAAc;CAChB,CAAC,GAGD,UAAU,YAAY,IAAI,IAC5B;AACF;;;;;;;;;;AC56BA,SAAgB,SAAS,EAAE,UAAU,aAAgD;CAEnF,MAAM,UAAU,SAAS,MAAM,GAAqB;CAEpD,IAAI,QAAQ,WAAW,GACrB,OAAO,MAAM,cACX,KACA,EAAE,eAAe,SAAS,GAC1B,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,wCAAwC,CACxF;CAGF,MAAM,WAAiC,CAAC;CAExC,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACvC,MAAM,MAAM,QAAQ;EACpB,MAAM,QAAQ,IAAI,SAAS,SAAS,QAAQ;EAC5C,MAAM,aAAa,IAAI,SAAS,SAAS,UAAU;EAEnD,SAAS,KACP,MAAM,cACJ,KACA;GAAE,KAAK,IAAI;GAAc,eAAe;GAAU,cAAc;EAAE,GAClE,MAAM,cAAc,MAAM;GAAE,MAAM;GAAM,OAAO;EAAW,GAAG,GAAG,MAAM,EAAE,GAExE,GAAG,IAAI,QAAQ,KAAK,OAAO,OAAO;GAChC,IAAI,MAAM,SAAS,QACjB,OAAO,MAAM,cAAc,MAAM,EAAE,KAAK,GAAG,IAAI,GAAa,GAAG,KAAK,GAAG,MAAM,IAAI;GAEnF,IAAI,MAAM,SAAS,YACjB,OAAO,MAAM,cACX,MACA;IAAE,KAAK,GAAG,IAAI,GAAa,GAAG;IAAM,OAAO;GAAS,GACpD,UAAU,MAAM,KAAK,EACvB;GAEF,IAAI,MAAM,SAAS,eAAe;IAChC,MAAM,UAAU,MAAM,QAAQ,MAAM,GAAG,GAAG;IAC1C,OAAO,MAAM,cACX,MACA;KAAE,KAAK,GAAG,IAAI,GAAa,GAAG;KAAM,UAAU;IAAK,GACnD,KAAK,UAAU,MAAM,QAAQ,SAAS,MAAM,QAAQ,IACtD;GACF;GACA,IAAI,MAAM,SAAS,aACjB,OAAO,MAAM,cACX,MACA;IAAE,KAAK,GAAG,IAAI,GAAa,GAAG;IAAM,UAAU;IAAM,QAAQ;GAAK,GACjE,cAAc,MAAM,KAAK,MAAM,GAAG,GAAG,GACvC;GAEF,OAAO,MAAM,cAAc,MAAM,EAAE,KAAK,GAAG,IAAI,GAAa,GAAG,KAAK,GAAG,EAAE;EAC3E,CAAC,CACH,CACF;CACF;CAGA,IAAI,WACF,SAAS,KACP,MAAM,cACJ,KACA,EAAE,KAAK,sBAAsB,GAC7B,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,GAAG,CACnD,CACF;CAGF,OAAO,MAAM,cAAc,KAAK,EAAE,eAAe,SAAS,GAAG,GAAG,QAAQ;AAC1E;;;;;;;;;;;;;;;ACpEA,MAAM,cAAc;;;;;;;AAQpB,SAAgB,aAAa,EAAE,UAAU,OAAO,WAAkD;CAChG,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,QAAQ,UAAU,UAAU,OAAO;CACzC,MAAM,YACJ,QAAQ,SAAS,cAAc,QAAQ,MAAM,GAAG,WAAW,IAAI,oBAAoB;CAErF,OAAO,MAAM,cACX,KACA;EAAE,eAAe;EAAU,cAAc;CAAE,GAE3C,MAAM,cACJ,KACA,EAAE,eAAe,MAAM,GACvB,MAAM,cAAc,MAAM,EAAE,MAAM,KAAK,GAAG,GAAG,KAAK,GAAG,UAAU,GAC/D,QAAQ,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,MAAM,OAAO,IAAI,IACzE,GAEA,UAAU,WACN,MAAM,cACJ,MACA,EAAE,UAAU,UAAU,SAAS,GAC/B,UAAU,WAAW,OAAO,cAAc,SAC5C,IACA,IACN;AACF;;AAGA,SAAS,SAAS,MAAsB;CACtC,IAAI,sCAAsC,KAAK,IAAI,GAAG,OAAO;CAC7D,IAAI,4EAA4E,KAAK,IAAI,GACvF,OAAO;CACT,IACE,0FAA0F,KACxF,IACF,GAEA,OAAO;CACT,IAAI,6CAA6C,KAAK,IAAI,GAAG,OAAO;CACpE,IAAI,0CAA0C,KAAK,IAAI,GAAG,OAAO;CACjE,IAAI,kCAAkC,KAAK,IAAI,GAAG,OAAO;CACzD,OAAO;AACT;;AAGA,SAAS,UAAU,MAAc,SAAyB;CACxD,MAAM,YAAY,QAAQ,MAAM,IAAI,CAAC,CAAC,MAAM;CAC5C,MAAM,SACJ,0FAA0F,KACxF,IACF;CACF,MAAM,UAAU,4EAA4E,KAC1F,IACF;CACA,MAAM,SAAS,sCAAsC,KAAK,IAAI;CAC9D,MAAM,QAAQ,6CAA6C,KAAK,IAAI;CAEpE,IAAI,QAEF,OAAO,UAAU,SAAS,KAAK,UAAU,MAAM,GAAG,EAAE,IAAI,QAAQ;CAGlE,IAAI,UAAU,SAEZ,OAAO,UAAU,SAAS,KAAK,UAAU,MAAM,GAAG,EAAE,IAAI,QAAQ;CAGlE,IAAI,OAGF,OADY,UAAU,SAAS,KAAK,UAAU,MAAM,GAAG,EAAE,IAAI,QAAQ;CAIvE,OAAO;AACT;;;;;;;;;;;;;;;;AC1EA,MAAM,eAAiD;CACrD,MAAM;EACJ,QAAQ;GAAC;GAAM;GAAM;GAAM;EAAI;EAC/B,YAAY;CACd;CACA,QAAQ;EACN,QAAQ,CAAC,IAAI;EACb,YAAY;CACd;CACA,OAAO;EACL,QAAQ;GAAC;GAAM;GAAM;GAAM;EAAI;EAC/B,YAAY;CACd;CACA,OAAO;EACL,QAAQ,CAAC,MAAM,IAAI;EACnB,YAAY;CACd;CACA,OAAO;EACL,QAAQ,CAAC,MAAM,IAAI;EACnB,YAAY;CACd;AACF;;;;;;;AAQA,SAAgB,OAAO,EAAE,OAAO,UAAU,QAAyC;CACjF,MAAM,SAAS,aAAa,UAAU,aAAa;CACnD,MAAM,CAAC,YAAY,iBAAiB,SAAS,CAAC;CAC9C,MAAM,WAAW,OAA8B,IAAI;CAEnD,gBAAgB;EAEd,cAAc,CAAC;EAEf,IAAI,CAAC,WAAW,OAAO,eAAe,UACpC;EAGF,SAAS,UAAU,kBAAkB;GACnC,eAAe,UAAU,OAAO,KAAK,OAAO,OAAO,MAAM;EAC3D,GAAG,OAAO,UAAU;EAEpB,aAAa;GACX,IAAI,SAAS,SAAS;IACpB,cAAc,SAAS,OAAO;IAC9B,SAAS,UAAU;GACrB;EACF;CACF,GAAG;EAAC;EAAO;EAAS,OAAO;EAAY,OAAO,OAAO;CAAM,CAAC;CAE5D,MAAM,QAAQ,OAAO,OAAO,eAAe,OAAO,OAAO;CAEzD,OAAO,MAAM,cAAc,MAAM,MAAM,KAAK;AAC9C;;;;;;;;;;;;;;;AC9CA,SAAgB,SACd,UACA,OAC4B;CAC5B,MAAM,CAAC,OAAO,YAAY,SAAS,EAAE;CACrC,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,MAAM,CAAC,SAAS,cAAc,SAAS,IAAI;CAC3C,MAAM,WAAW,OAAmB;EAAE,OAAO;EAAI,QAAQ;EAAG,SAAS;CAAK,CAAC;CAG3E,SAAS,UAAU;EAAE;EAAO;EAAQ;CAAQ;CAE5C,YACG,UAAkB,QAAa;EAC9B,IAAI,CAAC,SAAS,QAAQ,SAAS;EAE/B,IAAI,IAAI,QAAQ;GACd,MAAM,OAAO,SAAS,QAAQ,MAAM,KAAK;GACzC,IAAI,MAAM;IACR,SAAS,IAAI;IACb,SAAS,EAAE;IACX,UAAU,CAAC;GACb;GACA;EACF;EAEA,IAAI,OACF,MAAM,SAAS,QAAQ,OAAO,GAAG;CAErC,GACA,EAAE,UAAU,QAAQ,CACtB;CAEA,MAAM,UAAwB;EAC5B,UAAU,aAAa,MAAc;GACnC,SAAS,CAAC;GACV,UAAU,EAAE,MAAM;EACpB,GAAG,CAAC,CAAC;EAEL,OAAO,kBAAkB;GACvB,SAAS,EAAE;GACX,UAAU,CAAC;EACb,GAAG,CAAC,CAAC;EAEL,OAAO,kBAAkB;GACvB,WAAW,IAAI;EACjB,GAAG,CAAC,CAAC;EAEL,MAAM,kBAAkB;GACtB,WAAW,KAAK;EAClB,GAAG,CAAC,CAAC;EAEL,QAAQ,kBAA0B;GAChC,MAAM,OAAO,MAAM,KAAK;GACxB,IAAI,MAAM;IACR,SAAS,IAAI;IACb,SAAS,EAAE;IACX,UAAU,CAAC;GACb;GACA,OAAO;EACT,GAAG,CAAC,OAAO,QAAQ,CAAC;EAEpB,QAAQ,aACL,SAAiB;GAChB,UAAU,SAAS;IACjB,MAAM,MAAM;IACZ,OAAO,KAAK,MAAM,GAAG,GAAG,IAAI,OAAO,KAAK,MAAM,GAAG;GACnD,CAAC;GACD,WAAW,SAAS,OAAO,KAAK,MAAM;EACxC,GACA,CAAC,MAAM,CACT;CACF;CAEA,OAAO,CAAC;EAAE;EAAO;EAAQ;CAAQ,GAAG,OAAO;AAC7C;;;;;;;;;;;AC7GA,MAAM,oBAAoB;;AAG1B,MAAM,YAAY;;;;;;;;AAWlB,SAAgB,UAAU,MAAsB;CAE9C,OACE,KACG,QAAQ,0BAA0B,EAAE,CAAC,CAErC,QAAQ,uBAAuB,EAAE,CAAC,CAElC,QAAQ,oBAAoB,EAAE,CAAC,CAE/B,QAAQ,cAAc,EAAE;AAE/B;;;;;;;AAQA,SAAgB,kBAAkB,MAAsB;CACtD,OAAO,KACJ,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,gBAAgB,EAAE,CAAC,CAC3B,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,SAAS,EAAE;AACxB;;;;;;;AAQA,SAAgB,WAAW,MAAsB;CAG/C,IAAI,CAAC,cAAc,KAAK,IAAI,GAAG,OAAO;CACtC,OAAO,IAAI,KAAK;AAClB;;;;;;;;AASA,SAAgB,gBAAgB,MAAc,SAAiB,mBAA2B;CAExF,IAAI,KAAK,WAAW,KAAK,GAAG,OAAO;CAEnC,MAAM,QAAQ,KAAK,MAAM,OAAO;CAChC,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,UAAU,QAAQ;GACzB,OAAO,KAAK,IAAI;GAChB;EACF;EAGA,IAAI,MAAM,IAAI,GAAG;GACf,OAAO,KAAK,IAAI;GAChB;EACF;EAGA,MAAM,SAAmB,CAAC;EAC1B,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,QACpC,OAAO,KAAK,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC;EAEvC,OAAO,KAAK,OAAO,KAAK,GAAG,CAAC;CAC9B;CAEA,OAAO,OAAO,KAAK,EAAE;AACvB;;;;;;;;AASA,SAAgB,oBAAoB,MAAsB;CAExD,IAAI,KAAK,SAAS,IAAI,OAAO;CAE7B,IAAI,eAAe;CACnB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,OAAO,KAAK,WAAW,CAAC;EAE9B,IAAI,SAAS,MAAQ,SAAS,MAAQ,SAAS,GAAM;EACrD,IAAI,QAAQ,MAAQ,QAAQ,KAAM;EAClC,IAAI,QAAQ,KAAM;EAClB;CACF;CAGA,IADc,eAAe,KAAK,SACtB,IACV,OAAO;CAGT,OAAO;AACT;;;;;;;AAQA,SAAgB,SAAS,MAAsB;CAC7C,IAAI,UAAU,UAAU,IAAI;CAC5B,UAAU,kBAAkB,OAAO;CACnC,UAAU,oBAAoB,OAAO;CACrC,UAAU,gBAAgB,OAAO;CACjC,OAAO;AACT;AAIA,SAAS,MAAM,MAAuB;CACpC,OAAO,eAAe,KAAK,IAAI,KAAK,UAAU,KAAK,KAAK,MAAM,CAAC,CAAC;AAClE;;;;;;;;;;AC5HA,SAAgB,sBAAsB,SAOhB;CACpB,OAAO;EACL;GACE,aAAa;GACb,QAAQ,CAAC;GACT,QAAQ,QAAgB,QAAa,IAAI,QAAQ,WAAW;GAE5D,QAAQ,QAAQ;EAClB;EACA;GACE,aAAa;GACb,QAAQ,CAAC;GACT,QAAQ,QAAgB,QAAa,IAAI,QAAQ,WAAW;GAC5D,QAAQ,QAAQ;EAClB;EACA;GACE,aAAa;GACb,QAAQ,CAAC,MAAM;GACf,QAAQ,QAAgB,QAAa,IAAI,QAAQ,WAAW;GAC5D,QAAQ,QAAQ;EAClB;EACA;GACE,aAAa;GACb,QAAQ,CAAC,MAAM;GACf,QAAQ,QAAgB,QAAa,IAAI,QAAQ,WAAW;GAC5D,QAAQ,QAAQ;EAClB;EACA;GACE,aAAa;GACb,QAAQ,CAAC,MAAM;GACf,QAAQ,QAAgB,QAAa,IAAI,UAAW,IAAI,QAAQ,WAAW;GAC3E,QAAQ,QAAQ;EAClB;EACA;GACE,aAAa;GACb,QAAQ,CAAC,MAAM;GACf,QAAQ,QAAgB,QAAa,IAAI,YAAa,IAAI,QAAQ,WAAW;GAC7E,QAAQ,QAAQ;EAClB;CACF;AACF;;;;;;AASA,SAAgB,gBACd,SACA,OACA,OACA,KACS;CACT,KAAK,MAAM,WAAW,SAEpB,KADgB,QAAQ,OAAO,WAAW,KAAK,QAAQ,OAAO,SAAS,KAAK,MAC7D,QAAQ,MAAM,OAAO,GAAG,GAAG;EACxC,QAAQ,OAAO;EACf,OAAO;CACT;CAEF,OAAO;AACT;;;;;;;;;;;;;;;;AC5EA,IAAa,gBAAb,cAAmC,MAAM,UAAkD;CACzF,YAAY,OAA2B;EACrC,MAAM,KAAK;EACX,KAAK,QAAQ;GAAE,UAAU;GAAO,OAAO;EAAK;CAC9C;CAEA,OAAO,yBAAyB,OAAkC;EAChE,OAAO;GAAE,UAAU;GAAM;EAAM;CACjC;CAEA,kBAAkB,OAAc,WAAkC;EAEhE,QAAQ,OAAO,MACb,mBAAmB,MAAM,QAAQ,IAAI,MAAM,SAAS,GAAG,qBAAqB,UAAU,kBAAkB,GAAG,GAC7G;CACF;CAEA,SAA0B;EACxB,IAAI,KAAK,MAAM,UACb,OAAO,MAAM,cACX,KACA;GACE,eAAe;GACf,aAAa;GACb,aAAa;GACb,UAAU;GACV,UAAU;EACZ,GACA,MAAM,cAAc,MAAM;GAAE,MAAM;GAAM,OAAO;EAAM,GAAG,iCAAiC,GACzF,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,KAAK,MAAM,OAAO,WAAW,eAAe,GAC1F,MAAM,cAAc,KAAK,EAAE,QAAQ,EAAE,CAAC,GACtC,MAAM,cAAc,MAAM,EAAE,UAAU,KAAK,GAAG,mCAAmC,CACnF;EAGF,OAAO,KAAK,MAAM;CACpB;AACF;;;;;;;;;;;;;;;;;ACrCA,SAAgB,gBAAgB,EAC9B,UACA,SACA,UAC2C;CAC3C,gBAAgB;EACd,QAAQ;EACR,aAAa;GACX,OAAO;EACT;CAGF,GAAG,CAAC,CAAC;CAEL,OAAO,MAAM,cAAc,MAAM,UAAU,MAAM,QAAQ;AAC3D"}
1
+ {"version":3,"file":"index.mjs","names":["TOOL_RESULT_COLLAPSE_LEN","MAX_VISIBLE","MAX_VISIBLE","statusIcon","MAX_VISIBLE","MAX_VISIBLE","MAX_VISIBLE","statusColor","MAX_VISIBLE","MAX_VISIBLE","MAX_VISIBLE","sourceLabel","MAX_VISIBLE","MAX_VISIBLE"],"sources":["../src/theme/theme.ts","../src/renderer/highlight.ts","../src/renderer/emoji.ts","../src/renderer/latex.ts","../src/renderer/markdown.ts","../src/components/MessageRow.ts","../src/components/ChatLog.ts","../src/renderer/frame-limiter.ts","../src/components/VimStatusBar.ts","../src/components/SuggestionsOverlay.ts","../src/components/InputFooter.ts","../src/components/input/input-history.ts","../src/components/input/input-completions.ts","../src/components/input/file-completions.ts","../src/components/input/input-keyboard.ts","../src/components/input/useVimInput.ts","../src/components/InputBox.ts","../src/components/StatusBar.ts","../src/components/NotificationCenter.ts","../src/components/PermissionRequest.ts","../src/components/Dialog.ts","../src/components/SessionPicker.ts","../src/components/HelpModal.ts","../src/components/CommandPalette.ts","../src/components/ModelPicker.ts","../src/components/ConfigMenu.ts","../src/components/ThemePicker.ts","../src/components/ConfirmDialog.ts","../src/components/InputPrompt.ts","../src/components/DoctorPanel.ts","../src/components/FilePicker.ts","../src/components/StashPicker.ts","../src/components/DiffViewer.ts","../src/components/SnapshotBrowser.ts","../src/components/TasksPanel.ts","../src/components/SkillPicker.ts","../src/components/GlobalSearchDialog.ts","../src/components/McpPanel.ts","../src/components/PluginPanel.ts","../src/components/SkillPanel.ts","../src/components/ContextPanel.ts","../src/components/UsagePanel.ts","../src/screens/WelcomeScreen.ts","../src/hooks/useTerminalSize.ts","../src/components/ink/ScrollBox.ts","../src/components/FullscreenLayout.ts","../src/hooks/useScroll.ts","../src/views/stack.ts","../src/app.ts","../src/components/ChatView.ts","../src/components/ToolRenderer.ts","../src/components/Mascot.ts","../src/components/ink/Button.ts","../src/components/ink/Link.ts","../src/components/ink/RawAnsi.ts","../src/components/ink/Spinner.ts","../src/components/ink/NoSelect.ts","../src/hooks/useInput.ts","../src/renderer/sanitize.ts","../src/keybindings/keybindings.ts","../src/components/ErrorBoundary.ts","../src/components/AlternateScreen.ts"],"sourcesContent":["/**\n * ThemeProvider — semantic color tokens and theme switching.\n *\n * Six built‑in themes: dark, light, catppuccin, monokai, solarized, dracula.\n * Auto mode detects NO_COLOR and COLORTERM to pick a sensible default.\n */\n\nimport type { TuiTheme, ThemeName } from \"../types.js\";\n\n// ── Theme definitions ────────────────────────────────\n\nconst THEMES: Record<ThemeName, TuiTheme> = {\n dark: {\n name: \"dark\",\n colors: {\n background: \"#1a1b26\",\n foreground: \"#c0caf5\",\n border: \"#3b4261\",\n accent: \"#7aa2f7\",\n error: \"#f7768e\",\n warning: \"#e0af68\",\n success: \"#9ece6a\",\n dimmed: \"#565f89\",\n highlight: \"#2f334d\",\n inputBackground: \"#24283b\",\n inputForeground: \"#c0caf5\",\n toolUse: \"#7dcfff\",\n toolResult: \"#9d7cd8\",\n },\n },\n light: {\n name: \"light\",\n colors: {\n background: \"#f5f5f5\",\n foreground: \"#1a1b26\",\n border: \"#d0d0d0\",\n accent: \"#2e6edf\",\n error: \"#d73a49\",\n warning: \"#bf8700\",\n success: \"#22863a\",\n dimmed: \"#8b949e\",\n highlight: \"#e8e8e8\",\n inputBackground: \"#ffffff\",\n inputForeground: \"#1a1b26\",\n toolUse: \"#005cc5\",\n toolResult: \"#6f42c1\",\n },\n },\n catppuccin: {\n name: \"catppuccin\",\n colors: {\n background: \"#1e1e2e\",\n foreground: \"#cdd6f4\",\n border: \"#45475a\",\n accent: \"#89b4fa\",\n error: \"#f38ba8\",\n warning: \"#fab387\",\n success: \"#a6e3a1\",\n dimmed: \"#6c7086\",\n highlight: \"#313244\",\n inputBackground: \"#313244\",\n inputForeground: \"#cdd6f4\",\n toolUse: \"#89dceb\",\n toolResult: \"#cba6f7\",\n },\n },\n monokai: {\n name: \"monokai\",\n colors: {\n background: \"#272822\",\n foreground: \"#f8f8f2\",\n border: \"#49483e\",\n accent: \"#a6e22e\",\n error: \"#f92672\",\n warning: \"#e6db74\",\n success: \"#a6e22e\",\n dimmed: \"#75715e\",\n highlight: \"#3e3d32\",\n inputBackground: \"#3e3d32\",\n inputForeground: \"#f8f8f2\",\n toolUse: \"#66d9ef\",\n toolResult: \"#ae81ff\",\n },\n },\n solarized: {\n name: \"solarized\",\n colors: {\n background: \"#002b36\",\n foreground: \"#839496\",\n border: \"#073642\",\n accent: \"#268bd2\",\n error: \"#dc322f\",\n warning: \"#b58900\",\n success: \"#859900\",\n dimmed: \"#586e75\",\n highlight: \"#073642\",\n inputBackground: \"#073642\",\n inputForeground: \"#839496\",\n toolUse: \"#2aa198\",\n toolResult: \"#6c71c4\",\n },\n },\n dracula: {\n name: \"dracula\",\n colors: {\n background: \"#282a36\",\n foreground: \"#f8f8f2\",\n border: \"#44475a\",\n accent: \"#bd93f9\",\n error: \"#ff5555\",\n warning: \"#ffb86c\",\n success: \"#50fa7b\",\n dimmed: \"#6272a4\",\n highlight: \"#44475a\",\n inputBackground: \"#44475a\",\n inputForeground: \"#f8f8f2\",\n toolUse: \"#8be9fd\",\n toolResult: \"#bd93f9\",\n },\n },\n};\n\n// ── Current theme (mutable singleton) ─────────────────\n\nlet _current: ThemeName = \"dark\";\n\n/** Detect the best default theme from environment variables. */\nfunction detectTheme(): ThemeName {\n if (process.env.NO_COLOR) return \"light\";\n if (process.env.LYNX_THEME && THEMES[process.env.LYNX_THEME as ThemeName]) {\n return process.env.LYNX_THEME as ThemeName;\n }\n return \"dark\";\n}\n\n// ── Public API ───────────────────────────────────────\n\n/** Initialize the theme system. Call once at startup. */\nexport function initTheme(): void {\n _current = detectTheme();\n}\n\n/** Get the current theme. */\nexport function getTheme(): TuiTheme {\n return THEMES[_current];\n}\n\n/** Switch to a different theme. */\nexport function setTheme(name: ThemeName): void {\n if (THEMES[name]) {\n _current = name;\n }\n}\n\n/** Get a specific color from the current theme. */\nexport function color(name: string): string {\n const theme = THEMES[_current];\n return theme.colors[name] ?? theme.colors.foreground;\n}\n\n/** List all available theme names. */\nexport function listThemes(): ThemeName[] {\n return Object.keys(THEMES) as ThemeName[];\n}\n","/**\n * Syntax highlighting — regex-based colourisation for 8 language families.\n *\n * Each language family defines keyword lists, comment patterns, and\n * string/number regexes. The highlighter emits an array of styled spans\n * that can be rendered as Ink Text elements.\n *\n * Design:\n * - Tokenize each line independently (no cross-line state needed for\n * regex-based highlighting).\n * - Comments are detected first (highest priority), then strings,\n * then keywords, then numbers.\n * - Fallback: plain text with no highlighting.\n */\n\n// ── Types ────────────────────────────────────────────\n\n/** A styled text span — the output unit of the regex-based tokenizer. */\nexport interface HighlightSpan {\n text: string;\n kind: \"keyword\" | \"string\" | \"number\" | \"comment\" | \"type\" | \"plain\";\n}\n\n/** Per-language configuration for the tokenizer. */\ninterface LangConfig {\n /** Words that should be highlighted as keywords (bold). */\n keywords: ReadonlySet<string>;\n /** Words that should be highlighted as types (italic). */\n types?: ReadonlySet<string>;\n /** Regex patterns for single-line comments (applied first). */\n lineComments?: RegExp[];\n /** Block comment delimiters (e.g. `/*` and `*​/` for JS/TS/Go/Rust). */\n blockComment?: { start: string; end: string };\n /** Delimiter pairs for string detection. */\n stringDelimiters?: string[];\n}\n\n// ── Language definitions ──────────────────────────────\n\n/** JavaScript / TypeScript keywords. */\nconst JS_KEYWORDS = new Set([\n \"if\",\n \"else\",\n \"for\",\n \"while\",\n \"do\",\n \"switch\",\n \"case\",\n \"break\",\n \"continue\",\n \"return\",\n \"function\",\n \"const\",\n \"let\",\n \"var\",\n \"import\",\n \"export\",\n \"default\",\n \"from\",\n \"as\",\n \"class\",\n \"interface\",\n \"type\",\n \"enum\",\n \"extends\",\n \"implements\",\n \"abstract\",\n \"async\",\n \"await\",\n \"try\",\n \"catch\",\n \"throw\",\n \"finally\",\n \"new\",\n \"this\",\n \"super\",\n \"true\",\n \"false\",\n \"null\",\n \"undefined\",\n \"void\",\n \"typeof\",\n \"instanceof\",\n \"in\",\n \"of\",\n \"yield\",\n \"debugger\",\n \"delete\",\n \"static\",\n \"private\",\n \"public\",\n \"protected\",\n \"readonly\",\n \"implements\",\n \"namespace\",\n \"module\",\n \"require\",\n \"keyof\",\n \"infer\",\n \"never\",\n \"unknown\",\n]);\n\nconst JS_TYPES = new Set([\n \"string\",\n \"number\",\n \"boolean\",\n \"any\",\n \"void\",\n \"never\",\n \"unknown\",\n \"Array\",\n \"Map\",\n \"Set\",\n \"Promise\",\n \"Object\",\n \"Function\",\n \"Symbol\",\n \"Record\",\n \"Partial\",\n \"Required\",\n \"Pick\",\n \"Omit\",\n \"ReturnType\",\n \"Parameters\",\n]);\n\n/** Python keywords. */\nconst PY_KEYWORDS = new Set([\n \"if\",\n \"elif\",\n \"else\",\n \"for\",\n \"while\",\n \"break\",\n \"continue\",\n \"return\",\n \"yield\",\n \"def\",\n \"class\",\n \"import\",\n \"from\",\n \"as\",\n \"try\",\n \"except\",\n \"finally\",\n \"raise\",\n \"with\",\n \"pass\",\n \"lambda\",\n \"global\",\n \"nonlocal\",\n \"assert\",\n \"del\",\n \"True\",\n \"False\",\n \"None\",\n \"and\",\n \"or\",\n \"not\",\n \"in\",\n \"is\",\n \"async\",\n \"await\",\n \"self\",\n \"cls\",\n]);\n\n/** Go keywords. */\nconst GO_KEYWORDS = new Set([\n \"if\",\n \"else\",\n \"for\",\n \"range\",\n \"switch\",\n \"case\",\n \"default\",\n \"break\",\n \"continue\",\n \"return\",\n \"func\",\n \"var\",\n \"const\",\n \"type\",\n \"import\",\n \"package\",\n \"struct\",\n \"interface\",\n \"map\",\n \"chan\",\n \"go\",\n \"defer\",\n \"select\",\n \"fallthrough\",\n \"goto\",\n \"true\",\n \"false\",\n \"nil\",\n \"iota\",\n \"string\",\n \"int\",\n \"int8\",\n \"int16\",\n \"int32\",\n \"int64\",\n \"uint\",\n \"uint8\",\n \"uint16\",\n \"uint32\",\n \"uint64\",\n \"float32\",\n \"float64\",\n \"bool\",\n \"byte\",\n \"rune\",\n \"error\",\n]);\n\n/** Rust keywords. */\nconst RUST_KEYWORDS = new Set([\n \"if\",\n \"else\",\n \"for\",\n \"while\",\n \"loop\",\n \"match\",\n \"break\",\n \"continue\",\n \"return\",\n \"fn\",\n \"let\",\n \"mut\",\n \"const\",\n \"static\",\n \"type\",\n \"impl\",\n \"trait\",\n \"struct\",\n \"enum\",\n \"use\",\n \"mod\",\n \"pub\",\n \"crate\",\n \"self\",\n \"super\",\n \"extern\",\n \"unsafe\",\n \"where\",\n \"move\",\n \"async\",\n \"await\",\n \"dyn\",\n \"ref\",\n \"true\",\n \"false\",\n \"None\",\n \"Some\",\n \"Ok\",\n \"Err\",\n \"as\",\n \"in\",\n \"if\",\n \"else\",\n \"Self\",\n \"String\",\n \"Vec\",\n \"Option\",\n \"Result\",\n \"Box\",\n \"Rc\",\n \"Arc\",\n \"Cell\",\n \"RefCell\",\n \"i8\",\n \"i16\",\n \"i32\",\n \"i64\",\n \"i128\",\n \"isize\",\n \"u8\",\n \"u16\",\n \"u32\",\n \"u64\",\n \"u128\",\n \"usize\",\n \"f32\",\n \"f64\",\n \"bool\",\n \"char\",\n]);\n\n/** Shell / Bash keywords and built-ins. */\nconst SH_KEYWORDS = new Set([\n \"if\",\n \"then\",\n \"else\",\n \"elif\",\n \"fi\",\n \"for\",\n \"while\",\n \"do\",\n \"done\",\n \"case\",\n \"esac\",\n \"in\",\n \"select\",\n \"until\",\n \"function\",\n \"return\",\n \"exit\",\n \"break\",\n \"continue\",\n \"export\",\n \"local\",\n \"readonly\",\n \"unset\",\n \"declare\",\n \"typeset\",\n \"echo\",\n \"cd\",\n \"ls\",\n \"pwd\",\n \"cat\",\n \"grep\",\n \"sed\",\n \"awk\",\n \"find\",\n \"source\",\n \"test\",\n \"exec\",\n \"eval\",\n \"set\",\n \"shift\",\n \"trap\",\n \"true\",\n \"false\",\n \"yes\",\n \"no\",\n]);\n\n/** SQL keywords. */\nconst SQL_KEYWORDS = new Set([\n \"SELECT\",\n \"FROM\",\n \"WHERE\",\n \"JOIN\",\n \"LEFT\",\n \"RIGHT\",\n \"INNER\",\n \"OUTER\",\n \"ON\",\n \"INSERT\",\n \"INTO\",\n \"VALUES\",\n \"UPDATE\",\n \"SET\",\n \"DELETE\",\n \"CREATE\",\n \"TABLE\",\n \"ALTER\",\n \"DROP\",\n \"INDEX\",\n \"VIEW\",\n \"TRIGGER\",\n \"PROCEDURE\",\n \"FUNCTION\",\n \"AND\",\n \"OR\",\n \"NOT\",\n \"IN\",\n \"LIKE\",\n \"BETWEEN\",\n \"IS\",\n \"NULL\",\n \"AS\",\n \"DISTINCT\",\n \"GROUP\",\n \"BY\",\n \"ORDER\",\n \"HAVING\",\n \"LIMIT\",\n \"OFFSET\",\n \"UNION\",\n \"ALL\",\n \"EXISTS\",\n \"CASE\",\n \"WHEN\",\n \"THEN\",\n \"ELSE\",\n \"END\",\n \"ASC\",\n \"DESC\",\n \"PRIMARY\",\n \"KEY\",\n \"FOREIGN\",\n \"REFERENCES\",\n \"CONSTRAINT\",\n \"INTEGER\",\n \"TEXT\",\n \"VARCHAR\",\n \"BOOLEAN\",\n \"TIMESTAMP\",\n \"REAL\",\n \"BLOB\",\n \"BEGIN\",\n \"COMMIT\",\n \"ROLLBACK\",\n \"TRANSACTION\",\n \"COUNT\",\n \"SUM\",\n \"AVG\",\n \"MAX\",\n \"MIN\",\n \"COALESCE\",\n]);\n\n/** JSON / YAML / XML — no keywords; relies on string/number detection. */\nconst DATA_KEYWORDS = new Set<string>([\"true\", \"false\", \"null\"]);\nconst YAML_KEYWORDS = new Set<string>([\"true\", \"false\", \"null\", \"yes\", \"no\", \"on\", \"off\"]);\n\n/** CSS / SCSS keywords. */\nconst CSS_KEYWORDS = new Set([\n \"color\",\n \"background\",\n \"border\",\n \"margin\",\n \"padding\",\n \"width\",\n \"height\",\n \"display\",\n \"position\",\n \"top\",\n \"right\",\n \"bottom\",\n \"left\",\n \"font\",\n \"text\",\n \"flex\",\n \"grid\",\n \"align\",\n \"justify\",\n \"overflow\",\n \"opacity\",\n \"z-index\",\n \"transform\",\n \"transition\",\n \"animation\",\n \"box-shadow\",\n \"none\",\n \"auto\",\n \"inherit\",\n \"initial\",\n \"unset\",\n \"block\",\n \"inline\",\n \"flex\",\n \"grid\",\n \"absolute\",\n \"relative\",\n \"fixed\",\n \"sticky\",\n \"px\",\n \"em\",\n \"rem\",\n \"vh\",\n \"vw\",\n \"ch\",\n \"%\",\n \"rgb\",\n \"rgba\",\n \"hsl\",\n \"hsla\",\n \"var\",\n]);\n\n// ── Language family lookup ────────────────────────────\n\n/** Alias map: language tag → lookup key. */\nconst LANG_ALIASES: Record<string, string> = {\n js: \"js\",\n javascript: \"js\",\n mjs: \"js\",\n cjs: \"js\",\n ts: \"ts\",\n typescript: \"ts\",\n tsx: \"ts\",\n py: \"py\",\n python: \"py\",\n python3: \"py\",\n go: \"go\",\n golang: \"go\",\n rs: \"rs\",\n rust: \"rs\",\n sh: \"sh\",\n bash: \"sh\",\n shell: \"sh\",\n zsh: \"sh\",\n sql: \"sql\",\n psql: \"sql\",\n json: \"json\",\n yaml: \"yaml\",\n yml: \"yaml\",\n css: \"css\",\n scss: \"css\",\n less: \"css\",\n};\n\n/** Default line‑comment and string patterns per language family. */\nconst BLOCK_COMMENT_C = { start: \"/*\", end: \"*/\" };\n\nconst JS_CONFIG = {\n keywords: JS_KEYWORDS,\n types: JS_TYPES,\n lineComments: [/\\/\\//],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, `'`, \"`\"],\n};\nconst TS_CONFIG = {\n keywords: JS_KEYWORDS,\n types: JS_TYPES,\n lineComments: [/\\/\\//],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, `'`, \"`\"],\n};\nconst PY_CONFIG = { keywords: PY_KEYWORDS, lineComments: [/#/], stringDelimiters: [`\"`, `'`] };\nconst GO_CONFIG = {\n keywords: GO_KEYWORDS,\n lineComments: [/\\/\\//],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, \"`\"],\n};\nconst RS_CONFIG = {\n keywords: RUST_KEYWORDS,\n lineComments: [/\\/\\//],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, `'`],\n};\nconst SH_CONFIG = { keywords: SH_KEYWORDS, lineComments: [/#/], stringDelimiters: [`\"`, `'`] };\nconst SQL_CONFIG = { keywords: SQL_KEYWORDS, lineComments: [/--/], stringDelimiters: [`'`] };\nconst JSON_CONFIG = { keywords: DATA_KEYWORDS, stringDelimiters: [`\"`] };\nconst YAML_CONFIG = { keywords: YAML_KEYWORDS, lineComments: [/#/], stringDelimiters: [`\"`, `'`] };\nconst CSS_CONFIG = {\n keywords: CSS_KEYWORDS,\n lineComments: [/\\/\\//],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, `'`],\n};\nconst FALLBACK_CONFIG = {\n keywords: JS_KEYWORDS,\n lineComments: [new RegExp(\"//\")],\n blockComment: BLOCK_COMMENT_C,\n stringDelimiters: [`\"`, `'`, \"`\"],\n};\n\nconst LANG_CONFIGS: Record<string, LangConfig> = {\n js: JS_CONFIG,\n ts: TS_CONFIG,\n py: PY_CONFIG,\n go: GO_CONFIG,\n rs: RS_CONFIG,\n sh: SH_CONFIG,\n sql: SQL_CONFIG,\n json: JSON_CONFIG,\n yaml: YAML_CONFIG,\n css: CSS_CONFIG,\n};\n\n/** Resolve a language tag to its highlight config. */\nfunction getLangConfig(language?: string): LangConfig {\n const key = LANG_ALIASES[(language ?? \"\").toLowerCase()];\n return key ? (LANG_CONFIGS[key] ?? FALLBACK_CONFIG) : FALLBACK_CONFIG;\n}\n\n// ── Tokenizer ─────────────────────────────────────────\n\n/**\n * Tokenize a single line of code into highlight spans.\n *\n * Applies the following precedence (highest first):\n * 1. Block comment continuation/termination\n * 2. Line comments (//, #, --)\n * 3. Strings (quoted)\n * 4. Keywords / types (whole-word match)\n * 5. Numbers (integer, float, hex)\n * 6. Plain text\n *\n * @param line — the line to tokenize\n * @param config — language config\n * @param inBlockComment — true if the previous line left an unclosed block comment\n * @returns spans and whether the line ends inside a block comment\n */\nfunction tokenizeLine(\n line: string,\n config: LangConfig,\n inBlockComment?: boolean,\n): { spans: HighlightSpan[]; inBlockComment: boolean } {\n const spans: HighlightSpan[] = [];\n\n // 1. Handle block comment continuation\n const bc = config.blockComment;\n if (bc) {\n if (inBlockComment) {\n // Inside a continuing block comment — look for end marker\n const endIdx = line.indexOf(bc.end);\n if (endIdx >= 0) {\n spans.push({ text: line.slice(0, endIdx + bc.end.length), kind: \"comment\" });\n // Tokenize the rest normally\n const restSpans = tokenizeLine(line.slice(endIdx + bc.end.length), config, false);\n spans.push(...restSpans.spans);\n return { spans, inBlockComment: false };\n }\n // Entire line is comment\n spans.push({ text: line, kind: \"comment\" });\n return { spans, inBlockComment: true };\n }\n\n // Not currently in block comment — check if one starts on this line\n const startIdx = line.indexOf(bc.start);\n if (startIdx >= 0) {\n const endIdx = line.indexOf(bc.end, startIdx + bc.start.length);\n if (endIdx >= 0) {\n // Full block comment on one line\n if (startIdx > 0) {\n spans.push(...tokenizeLineNoComments(line.slice(0, startIdx), config));\n }\n spans.push({ text: line.slice(startIdx, endIdx + bc.end.length), kind: \"comment\" });\n const restSpan = tokenizeLine(line.slice(endIdx + bc.end.length), config, false);\n spans.push(...restSpan.spans);\n return { spans, inBlockComment: false };\n }\n // Block comment starts but doesn't end on this line\n if (startIdx > 0) {\n spans.push(...tokenizeLineNoComments(line.slice(0, startIdx), config));\n }\n spans.push({ text: line.slice(startIdx), kind: \"comment\" });\n return { spans, inBlockComment: true };\n }\n }\n\n // No block comment state — check for line comments\n if (config.lineComments) {\n for (const commentRe of config.lineComments) {\n const match = commentRe.exec(line);\n if (match) {\n const commentStart = match.index;\n if (commentStart > 0) {\n spans.push(...tokenizeLineNoComments(line.slice(0, commentStart), config));\n }\n spans.push({ text: line.slice(commentStart), kind: \"comment\" });\n return { spans, inBlockComment: false };\n }\n }\n }\n\n spans.push(...tokenizeLineNoComments(line, config));\n return { spans, inBlockComment: false };\n}\n\n/**\n * Result of trying to match a word (keyword or type) at the current position.\n * Returns the new spans and the remainder, or null if no word matched.\n */\ninterface WordMatch {\n spans: HighlightSpan[];\n remainder: string;\n}\n\nfunction tryMatchWord(s: string, pos: number, config: LangConfig): WordMatch | null {\n if (!isWordChar(s[pos]!)) return null;\n\n const wordEnd = findWordEnd(s, pos);\n const word = s.slice(pos, wordEnd);\n const lowerWord = word.toLowerCase();\n\n const isKeyword = config.keywords.has(word) || config.keywords.has(lowerWord);\n const isType = config.types && (config.types.has(word) || config.types.has(lowerWord));\n if (!isKeyword && !isType) return null;\n\n const spans: HighlightSpan[] = [];\n if (pos > 0) spans.push({ text: s.slice(0, pos), kind: \"plain\" });\n spans.push({ text: word, kind: isKeyword ? \"keyword\" : \"type\" });\n\n return { spans, remainder: s.slice(wordEnd) };\n}\n\n/** Try to match a number literal at the current position. */\nfunction tryMatchNumberToken(s: string, pos: number): WordMatch | null {\n const char = s[pos]!;\n const isDigit = char >= \"0\" && char <= \"9\";\n const isDecimalDot =\n char === \".\" && pos + 1 < s.length && s[pos + 1]! >= \"0\" && s[pos + 1]! <= \"9\";\n if (!isDigit && !isDecimalDot) return null;\n\n const numEnd = findNumberEnd(s, pos);\n if (numEnd <= pos) return null;\n\n const spans: HighlightSpan[] = [];\n if (pos > 0) spans.push({ text: s.slice(0, pos), kind: \"plain\" });\n spans.push({ text: s.slice(pos, numEnd), kind: \"number\" });\n\n return { spans, remainder: s.slice(numEnd) };\n}\n\n/**\n * Tokenize a line that is known to have no line comments.\n */\nfunction tokenizeLineNoComments(line: string, config: LangConfig): HighlightSpan[] {\n const spans: HighlightSpan[] = [];\n let remaining = line;\n let pos = 0;\n\n while (pos < remaining.length) {\n // String detection (highest priority)\n const strResult = tryMatchString(remaining);\n if (strResult) {\n if (pos > 0) spans.push({ text: remaining.slice(0, pos), kind: \"plain\" });\n spans.push({ text: strResult.matched, kind: \"string\" });\n remaining = strResult.remainder;\n pos = 0;\n continue;\n }\n\n // Keyword / type detection\n const wordMatch = tryMatchWord(remaining, pos, config);\n if (wordMatch) {\n spans.push(...wordMatch.spans);\n remaining = wordMatch.remainder;\n pos = 0;\n continue;\n }\n\n // Number detection\n const numMatch = tryMatchNumberToken(remaining, pos);\n if (numMatch) {\n spans.push(...numMatch.spans);\n remaining = numMatch.remainder;\n pos = 0;\n continue;\n }\n\n pos++;\n }\n\n if (remaining.length > 0) {\n spans.push({ text: remaining, kind: \"plain\" });\n }\n\n return mergeAdjacentSpans(spans);\n}\n\n// ── Tokenizer helpers ─────────────────────────────────\n\nfunction isWordChar(ch: string): boolean {\n return /[a-zA-Z_]/.test(ch);\n}\n\nfunction findWordEnd(s: string, start: number): number {\n let i = start;\n while (i < s.length && /[a-zA-Z0-9_]/.test(s[i]!)) i++;\n return i;\n}\n\nfunction findNumberEnd(s: string, start: number): number {\n let i = start;\n if (s[i] === \"0\" && i + 1 < s.length && (s[i + 1] === \"x\" || s[i + 1] === \"X\")) i += 2;\n while (i < s.length && /[0-9a-fA-F.x]/.test(s[i]!)) i++;\n return i;\n}\n\ninterface StrMatch {\n matched: string;\n remainder: string;\n}\n\nfunction tryMatchString(s: string): StrMatch | null {\n const delimiters = [`\"`, `'`, \"`\"];\n const first = s[0]!;\n if (!delimiters.includes(first)) return null;\n\n let i = 1;\n while (i < s.length) {\n if (s[i] === \"\\\\\") {\n i += 2;\n continue;\n }\n if (s[i] === first) return { matched: s.slice(0, i + 1), remainder: s.slice(i + 1) };\n i++;\n }\n return null;\n}\n\nfunction mergeAdjacentSpans(spans: HighlightSpan[]): HighlightSpan[] {\n if (spans.length <= 1) return spans;\n const merged: HighlightSpan[] = [];\n let cur = spans[0]!;\n for (let i = 1; i < spans.length; i++) {\n const next = spans[i]!;\n if (cur.kind === next.kind) {\n cur = { text: cur.text + next.text, kind: cur.kind };\n } else {\n merged.push(cur);\n cur = next;\n }\n }\n merged.push(cur);\n return merged;\n}\n\n// ── Public API ────────────────────────────────────────\n\n/**\n * Highlight a single line of code, returning styled spans.\n *\n * Uses the language tag to select the right keyword/comment/string\n * patterns. Falls back to JS-style highlighting when unknown.\n */\nexport function highlightCodeLine(line: string, language?: string): HighlightSpan[] {\n const config = getLangConfig(language);\n\n // Trim trailing newline for tokenization\n const clean = line.endsWith(\"\\n\") ? line.slice(0, -1) : line;\n\n if (clean.length === 0) return [{ text: \"\", kind: \"plain\" }];\n\n return tokenizeLine(clean, config).spans;\n}\n\n/**\n * Highlight an entire code block with cross-line block comment tracking.\n *\n * Unlike `highlightCodeLine`, this tracks `/* ... *​/` block comment\n * state across lines for languages that support them (JS, TS, Go, Rust, CSS).\n * Lines inside a multi-line block comment are fully styled as `\"comment\"`.\n */\nexport function highlightCodeBlock(code: string, language?: string): HighlightSpan[][] {\n const config = getLangConfig(language);\n const lines = code.split(\"\\n\");\n const result: HighlightSpan[][] = [];\n let inBlockComment = false;\n\n for (const line of lines) {\n // Trim trailing newline\n const clean = line.endsWith(\"\\n\") ? line.slice(0, -1) : line;\n\n if (clean.length === 0) {\n result.push([{ text: \"\", kind: \"plain\" }]);\n continue;\n }\n\n const { spans, inBlockComment: nextInBlock } = tokenizeLine(clean, config, inBlockComment);\n result.push(spans);\n inBlockComment = nextInBlock;\n }\n\n return result;\n}\n","/**\n * Emoji shortcode renderer — converts :name: patterns to Unicode emoji.\n *\n * Covers ~100 commonly used shortcodes from GitHub/Slack conventions.\n * Unrecognised codes are left as-is so the source remains readable.\n */\n\n/** Map of shortcode (without colons) → Unicode emoji character. */\nconst EMOJI_MAP: Record<string, string> = {\n smile: \"😄\",\n grinning: \"😁\",\n joy: \"😂\",\n rofl: \"🤣\",\n smiley: \"😃\",\n sweat_smile: \"😅\",\n laughing: \"😆\",\n wink: \"😉\",\n blush: \"😊\",\n innocent: \"😇\",\n heart_eyes: \"😍\",\n kissing_heart: \"😘\",\n kissing: \"😗\",\n kissing_closed_eyes: \"😚\",\n stuck_out_tongue: \"😛\",\n stuck_out_tongue_wink: \"😜\",\n stuck_out_tongue_closed_eyes: \"😝\",\n yum: \"😋\",\n relieved: \"😌\",\n satisfied: \"😆\",\n smirk: \"😏\",\n unamused: \"😒\",\n pensive: \"😔\",\n worried: \"😟\",\n confused: \"😕\",\n disappointed: \"😞\",\n cry: \"😢\",\n sob: \"😭\",\n angry: \"😠\",\n rage: \"😡\",\n triumph: \"😤\",\n sleepy: \"😪\",\n tired_face: \"😫\",\n fearful: \"😨\",\n cold_sweat: \"😰\",\n scream: \"😱\",\n astonished: \"😲\",\n flushed: \"😳\",\n dizzy_face: \"😵\",\n mask: \"😷\",\n sunglasses: \"😎\",\n nerd: \"🤓\",\n thinking: \"🤔\",\n neutral_face: \"😐\",\n expressionless: \"😑\",\n no_mouth: \"😶\",\n rolling_eyes: \"🙄\",\n zipper_mouth: \"🤐\",\n hug: \"🤗\",\n clown: \"🤡\",\n lie: \"🤥\",\n nauseated: \"🤢\",\n sneeze: \"🤧\",\n cowboy: \"🤠\",\n // Hand gestures\n \"+1\": \"👍\",\n \"-1\": \"👎\",\n clap: \"👏\",\n wave: \"👋\",\n ok_hand: \"👌\",\n raised_hands: \"🙌\",\n pray: \"🙏\",\n point_up: \"☝️\",\n point_down: \"👇\",\n point_left: \"👈\",\n point_right: \"👉\",\n muscle: \"💪\",\n // Symbols\n heart: \"❤️\",\n broken_heart: \"💔\",\n star: \"⭐\",\n sparkles: \"✨\",\n fire: \"🔥\",\n rocket: \"🚀\",\n tada: \"🎉\",\n check: \"✔️\",\n x: \"✖️\",\n warning: \"⚠️\",\n info: \"ℹ️\",\n question: \"❓\",\n bulb: \"💡\",\n lock: \"🔒\",\n unlock: \"🔓\",\n key: \"🔑\",\n hammer: \"🔨\",\n wrench: \"🔧\",\n gear: \"⚙️\",\n book: \"📖\",\n memo: \"📝\",\n pencil: \"✏️\",\n pin: \"📌\",\n link: \"🔗\",\n eyes: \"👀\",\n // Arrows\n arrow_up: \"⬆️\",\n arrow_down: \"⬇️\",\n arrow_left: \"⬅️\",\n arrow_right: \"➡️\",\n // Tech\n computer: \"💻\",\n bug: \"🐛\",\n robot: \"🤖\",\n package: \"📦\",\n globe: \"🌐\",\n shield: \"🛡️\",\n // Weather / nature\n sun: \"☀️\",\n cloud: \"☁️\",\n rain: \"🌧️\",\n snow: \"❄️\",\n zap: \"⚡\",\n // Misc\n coffee: \"☕\",\n beer: \"🍺\",\n pizza: \"🍕\",\n hourglass: \"⌛\",\n clock: \"🕐\",\n money: \"💰\",\n chart: \"📊\",\n mail: \"✉️\",\n phone: \"📱\",\n calendar: \"📅\",\n};\n\n/** Regex matching an emoji shortcode: :word: or :word_word: */\nconst SHORTCODE_RE = /:([a-zA-Z0-9_+-]+):/g;\n\n/**\n * Replace emoji shortcodes in text with their Unicode equivalents.\n *\n * Example: \"Hello :wave: :smile:\" → \"Hello 👋 😀\"\n * Unrecognised codes are left in place.\n */\nexport function renderEmojiShortcodes(text: string): string {\n return text.replace(SHORTCODE_RE, (_full, name: string) => {\n const emoji = EMOJI_MAP[name];\n return emoji ?? _full;\n });\n}\n","/**\n * LaTeX math → Unicode approximate renderer.\n *\n * Converts inline ($...$) and display ($$...$$) math to their\n * closest Unicode equivalents for terminal rendering. This is\n * NOT a full LaTeX engine — it covers the most common symbols.\n */\n\n// ── Symbol tables ─────────────────────────────────────\n\n/** Greek lowercase letters. */\nconst GREEK_LOWER: Record<string, string> = {\n alpha: \"α\",\n beta: \"β\",\n gamma: \"γ\",\n delta: \"δ\",\n epsilon: \"ε\",\n zeta: \"ζ\",\n eta: \"η\",\n theta: \"θ\",\n iota: \"ι\",\n kappa: \"κ\",\n lambda: \"λ\",\n mu: \"μ\",\n nu: \"ν\",\n xi: \"ξ\",\n pi: \"π\",\n rho: \"ρ\",\n sigma: \"σ\",\n tau: \"τ\",\n upsilon: \"υ\",\n phi: \"φ\",\n chi: \"χ\",\n psi: \"ψ\",\n omega: \"ω\",\n};\n\n/** Greek uppercase letters. */\nconst GREEK_UPPER: Record<string, string> = {\n Gamma: \"Γ\",\n Delta: \"Δ\",\n Theta: \"Θ\",\n Lambda: \"Λ\",\n Xi: \"Ξ\",\n Pi: \"Π\",\n Sigma: \"Σ\",\n Phi: \"Φ\",\n Psi: \"Ψ\",\n Omega: \"Ω\",\n};\n\n/** Common math symbols. */\nconst MATH_SYMBOLS: Record<string, string> = {\n \"\\\\infty\": \"∞\",\n \"\\\\pm\": \"±\",\n \"\\\\mp\": \"∓\",\n \"\\\\times\": \"×\",\n \"\\\\div\": \"÷\",\n \"\\\\cdot\": \"·\",\n \"\\\\leq\": \"≤\",\n \"\\\\geq\": \"≥\",\n \"\\\\neq\": \"≠\",\n \"\\\\approx\": \"≈\",\n \"\\\\equiv\": \"≡\",\n \"\\\\sim\": \"∼\",\n \"\\\\propto\": \"∝\",\n \"\\\\subset\": \"⊂\",\n \"\\\\supset\": \"⊃\",\n \"\\\\subseteq\": \"⊆\",\n \"\\\\supseteq\": \"⊇\",\n \"\\\\in\": \"∈\",\n \"\\\\notin\": \"∉\",\n \"\\\\forall\": \"∀\",\n \"\\\\exists\": \"∃\",\n \"\\\\emptyset\": \"∅\",\n \"\\\\nabla\": \"∇\",\n \"\\\\partial\": \"∂\",\n \"\\\\int\": \"∫\",\n \"\\\\sum\": \"∑\",\n \"\\\\prod\": \"∏\",\n \"\\\\sqrt\": \"√\",\n \"\\\\angle\": \"∠\",\n \"\\\\perp\": \"⊥\",\n \"\\\\parallel\": \"∥\",\n \"\\\\to\": \"→\",\n \"\\\\rightarrow\": \"→\",\n \"\\\\leftarrow\": \"←\",\n \"\\\\uparrow\": \"↑\",\n \"\\\\downarrow\": \"↓\",\n \"\\\\mapsto\": \"↦\",\n \"\\\\Rightarrow\": \"⇒\",\n \"\\\\Leftarrow\": \"⇐\",\n \"\\\\iff\": \"⟺\",\n \"\\\\land\": \"∧\",\n \"\\\\lor\": \"∨\",\n \"\\\\neg\": \"¬\",\n \"\\\\oplus\": \"⊕\",\n \"\\\\otimes\": \"⊗\",\n \"\\\\ldots\": \"…\",\n \"\\\\cdots\": \"⋯\",\n \"\\\\vdots\": \"⋮\",\n \"\\\\ddots\": \"⋱\",\n \"\\\\circ\": \"∘\",\n \"\\\\bullet\": \"•\",\n \"\\\\star\": \"★\",\n \"\\\\triangle\": \"△\",\n \"\\\\square\": \"□\",\n \"\\\\diamond\": \"◇\",\n};\n\n// ── Substitution passes ───────────────────────────────\n\n/**\n * Convert superscript patterns: x^{2} → x², x^{n} → xⁿ.\n * Handles ^ (e.g. x^2 → x², x^{abc} → xᵃᵇᶜ).\n */\nfunction replaceSuperscript(text: string): string {\n const SUPER: Record<string, string> = {\n \"0\": \"⁰\",\n \"1\": \"¹\",\n \"2\": \"²\",\n \"3\": \"³\",\n \"4\": \"⁴\",\n \"5\": \"⁵\",\n \"6\": \"⁶\",\n \"7\": \"⁷\",\n \"8\": \"⁸\",\n \"9\": \"⁹\",\n \"+\": \"⁺\",\n \"-\": \"⁻\",\n \"=\": \"⁼\",\n \"(\": \"⁽\",\n \")\": \"⁾\",\n n: \"ⁿ\",\n i: \"ⁱ\",\n };\n return text\n .replace(/\\^\\{([^}]+)\\}/g, (_, body: string) => [...body].map((c) => SUPER[c] ?? c).join(\"\"))\n .replace(/\\^(\\d)/g, (_, d: string) => SUPER[d] ?? `^${d}`);\n}\n\n/**\n * Convert subscript patterns: x_{i} → xᵢ, x_{10} → x₁₀.\n */\nfunction replaceSubscript(text: string): string {\n const SUB: Record<string, string> = {\n \"0\": \"₀\",\n \"1\": \"₁\",\n \"2\": \"₂\",\n \"3\": \"₃\",\n \"4\": \"₄\",\n \"5\": \"₅\",\n \"6\": \"₆\",\n \"7\": \"₇\",\n \"8\": \"₈\",\n \"9\": \"₉\",\n \"+\": \"₊\",\n \"-\": \"₋\",\n \"=\": \"₌\",\n \"(\": \"₍\",\n \")\": \"₎\",\n i: \"ᵢ\",\n j: \"ⱼ\",\n k: \"ₖ\",\n n: \"ₙ\",\n };\n return text\n .replace(/_\\{([^}]+)\\}/g, (_, body: string) => [...body].map((c) => SUB[c] ?? c).join(\"\"))\n .replace(/_(\\w)/g, (_, c: string) => SUB[c] ?? `_${c}`);\n}\n\n// ── Public API ────────────────────────────────────────\n\n/**\n * Render inline LaTeX ($...$) to Unicode approximations.\n *\n * Handles:\n * - Greek letters (\\\\alpha → α, \\\\Gamma → Γ)\n * - Common symbols (\\\\infty → ∞, \\\\pm → ±, etc.)\n * - Superscript (x^{2} → x²) and subscript (x_{i} → xᵢ)\n * - Fractions (\\\\frac{a}{b} → (a)/(b))\n *\n * Returns the approximate Unicode text, or the original if no\n * patterns matched.\n */\n/** Render LaTeX math inline — converts \\\\frac, \\\\sum, superscript, subscript etc. to Unicode approximations. */\nexport function renderInlineLatex(latex: string): string {\n let result = latex;\n\n // Fractions first — \\\\frac{a}{b} → (a)/(b)\n result = result.replace(/\\\\frac\\{([^}]*)}\\{([^}]*)}/g, \"($1)/($2)\");\n\n // Common math symbols (longest first to avoid partial matches)\n const sortedSymbols = Object.entries(MATH_SYMBOLS).sort((a, b) => b[0].length - a[0].length);\n for (const [cmd, sym] of sortedSymbols) {\n result = result.replaceAll(cmd, sym);\n }\n\n // Greek uppercase\n for (const [name, sym] of Object.entries(GREEK_UPPER)) {\n result = result.replace(`\\\\${name}`, sym);\n }\n\n // Greek lowercase\n for (const [name, sym] of Object.entries(GREEK_LOWER)) {\n result = result.replace(`\\\\${name}`, sym);\n }\n\n // Superscript / subscript\n result = replaceSuperscript(result);\n result = replaceSubscript(result);\n\n return result;\n}\n\n/**\n * Detect if a string looks like a LaTeX math expression.\n *\n * Heuristic: contains a backslash command or a math structure\n * like subscript/superscript braces.\n */\nexport function isLatexInline(text: string): boolean {\n return text.includes(\"\\\\\") || /\\^\\{/.test(text) || /\\{/.test(text);\n}\n","/**\n * Markdown renderer — converts LLM response markdown to Ink‑renderable elements.\n *\n * Handles:\n * — Code blocks (fenced + indented)\n * — Inline: bold, italic, strikethrough, inline code, links\n * — Headings (h1–h6)\n * — Unordered / ordered lists\n * — Blockquotes\n * — Horizontal rules\n * — Diff output (+++/---/@@/+/-)\n *\n * Streaming mode: finds the last stable block boundary,\n * memos the prefix, and only re‑parses the unstable suffix.\n */\n\nimport React, { type ReactNode } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { highlightCodeLine, highlightCodeBlock, type HighlightSpan } from \"./highlight.js\";\nimport { renderEmojiShortcodes } from \"./emoji.js\";\nimport { renderInlineLatex, isLatexInline } from \"./latex.js\";\n\n// ── Types ────────────────────────────────────────────\n\n/** Parsed markdown block — the output unit of the streaming-aware markdown parser. */\nexport interface MarkdownBlock {\n type: \"paragraph\" | \"heading\" | \"code\" | \"list_item\" | \"blockquote\" | \"hr\" | \"diff\" | \"table\";\n /** Heading level (1–6), only for heading blocks. */\n level?: number;\n /** Source text for this block. */\n text: string;\n /** Language tag for fenced code blocks. */\n language?: string;\n /** For ordered list items, the number. */\n listNumber?: number;\n /** For diff blocks, the diff line type. */\n diffLineType?: \"header\" | \"hunk\" | \"add\" | \"remove\" | \"context\";\n /** For task list items, whether the checkbox is checked. */\n checked?: boolean;\n /** Indentation depth for nested list items (0 = top level). */\n indentLevel?: number;\n /** For table blocks, the column headers. */\n tableHeaders?: string[];\n /** For table blocks, the data rows (each row is an array of cell text). */\n tableRows?: string[][];\n /** For table blocks, column alignments. */\n tableAligns?: (\"left\" | \"center\" | \"right\")[];\n}\n\n/** Rendering options for the markdown parser — controls block limit and streaming behavior. */\nexport interface RenderOptions {\n /** Max number of blocks to render (limits re‑render cost). */\n maxBlocks?: number;\n /** If true, only parse complete blocks (for streaming). */\n stableOnly?: boolean;\n}\n\n// ── Inline formatting ─────────────────────────────────\n\n/** An inline segment with optional formatting. */\ninterface InlineSegment {\n text: string;\n bold?: boolean;\n italic?: boolean;\n strikethrough?: boolean;\n code?: boolean;\n link?: string;\n}\n\n/**\n * Parse inline markdown formatting within a single line of text.\n * Handles: **bold**, *italic*, ~~strikethrough~~, `code`, [text](url).\n */\nfunction parseInline(text: string): InlineSegment[] {\n const segments: InlineSegment[] = [];\n\n // Regex matches inline formatting tokens in order of precedence\n const pattern = /(\\*\\*(.+?)\\*\\*)|(\\*(.+?)\\*)|(~~(.+?)~~)|(`(.+?)`)|(\\[(.+?)\\]\\((.+?)\\))/g;\n\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n // Text before this match\n if (match.index > lastIndex) {\n segments.push({ text: text.slice(lastIndex, match.index) });\n }\n\n if (match[1]) {\n // **bold**\n segments.push({ text: match[2]!, bold: true });\n } else if (match[3]) {\n // *italic*\n segments.push({ text: match[4]!, italic: true });\n } else if (match[5]) {\n // ~~strikethrough~~\n segments.push({ text: match[6]!, strikethrough: true });\n } else if (match[7]) {\n // `code`\n segments.push({ text: match[8]!, code: true });\n } else if (match[9]) {\n // [text](url)\n segments.push({ text: match[10]!, link: match[11]! });\n }\n\n lastIndex = match.index + match[0].length;\n }\n\n // Remaining text after last match\n if (lastIndex < text.length) {\n segments.push({ text: text.slice(lastIndex) });\n }\n\n // If no formatting was found, return plain text\n if (segments.length === 0) {\n segments.push({ text });\n }\n\n return segments;\n}\n\n/**\n * Render inline segments as Ink Text elements.\n *\n * Each segment becomes a Text element with appropriate formatting.\n * Multiple segments are rendered as siblings within a parent Text.\n */\nexport function renderInline(text: string): ReactNode {\n // Apply emoji shortcode rendering as a safety net\n const rendered = renderEmojiShortcodes(text);\n const segments = parseInline(rendered);\n\n if (segments.length === 1 && !segments[0]!.bold && !segments[0]!.italic && !segments[0]!.code) {\n // Plain text — return as string for efficiency\n return segments[0]!.text;\n }\n\n return segments.map((seg, i) => {\n const props: Record<string, unknown> = { key: `seg-${i}` };\n\n if (seg.bold) props.bold = true;\n if (seg.italic) props.italic = true;\n if (seg.strikethrough) props.strikethrough = true;\n if (seg.code) props.dimColor = true;\n if (seg.link) {\n props.underline = true;\n props.color = \"blue\";\n // Wrap text with OSC 8 hyperlink so terminals that support\n // it can make the link clickable. Fallback: just blue underline.\n if (seg.link && !seg.link.startsWith(\"javascript:\")) {\n return React.createElement(Text, props, wrapOsc8(seg.link, seg.text));\n }\n }\n\n return React.createElement(Text, props, seg.text);\n });\n}\n\n// ── OSC 8 hyperlinks ───────────────────────────────────\n\n/**\n * Wrap text in an OSC 8 hyperlink escape sequence.\n *\n * OSC 8 is supported by most modern terminals (iTerm2, Windows Terminal,\n * VSCode terminal, Kitty, etc.). When the terminal doesn't support it,\n * the escape sequences are ignored and the text renders as plain text.\n *\n * Format: \\x1b]8;;URL\\x1b\\\\TEXT\\x1b]8;;\\x1b\\\\\n */\nfunction wrapOsc8(url: string, text: string): string {\n return `\\x1b]8;;${url}\\x1b\\\\${text}\\x1b]8;;\\x1b\\\\`;\n}\n\n// ── Color helpers ────────────────────────────────────\n\n/** Map a highlight span kind to an Ink color. */\nfunction spanColor(kind: HighlightSpan[\"kind\"]): string | undefined {\n switch (kind) {\n case \"keyword\":\n return \"yellow\";\n case \"string\":\n return \"green\";\n case \"number\":\n return \"magenta\";\n case \"comment\":\n return \"grey\";\n case \"type\":\n return \"cyan\";\n case \"plain\":\n return undefined;\n default:\n return undefined;\n }\n}\n\n/** Render a highlighted line as Ink Text elements. */\nfunction renderHighlightedLine(line: string, lang?: string): ReactNode {\n const spans = highlightCodeLine(line, lang);\n if (spans.length === 0) return \"\";\n\n // Optimize: single plain span → return as string\n if (spans.length === 1 && spans[0]!.kind === \"plain\") {\n return spans[0]!.text;\n }\n\n return spans.map((span, si) => {\n const color = spanColor(span.kind);\n const props: Record<string, unknown> = { key: `hs-${si}` };\n if (span.kind === \"keyword\" || span.kind === \"type\") props.bold = true;\n if (span.kind === \"comment\") props.dimColor = true;\n if (color) props.color = color;\n if (span.text === \"\") return null;\n return React.createElement(Text, props, span.text);\n });\n}\n\n// ── Parsing ──────────────────────────────────────────\n\n// ── Block detection helpers ─────────────────────────\n\n/** Detect the type of a diff line from its prefix. */\nfunction detectDiffLineType(trimmed: string): MarkdownBlock[\"diffLineType\"] {\n if (\n trimmed.startsWith(\"+++ \") ||\n trimmed.startsWith(\"--- \") ||\n trimmed.startsWith(\"diff --git\") ||\n trimmed.startsWith(\"index \")\n ) {\n return \"header\";\n }\n if (trimmed.startsWith(\"@@\")) return \"hunk\";\n if (trimmed.startsWith(\"+\")) return \"add\";\n if (trimmed.startsWith(\"-\")) return \"remove\";\n return \"context\";\n}\n\n/** Detect if a line is part of a diff block (uses prevLine for context). */\nfunction isDiffLine(trimmed: string, prevLine?: string): boolean {\n if (trimmed.startsWith(\"+++ \") || trimmed.startsWith(\"--- \")) return true;\n if (/^@@\\s+-/.test(trimmed)) return true;\n if (\n prevLine &&\n (prevLine.startsWith(\"+++ \") || prevLine.startsWith(\"--- \") || /^@@\\s+-/.test(prevLine))\n ) {\n return trimmed.startsWith(\"+\") || trimmed.startsWith(\"-\");\n }\n return trimmed.startsWith(\"diff --git\") || trimmed.startsWith(\"index \");\n}\n\n/** Try to parse a heading line. Returns null if not a heading. */\nfunction tryParseHeading(trimmed: string): MarkdownBlock | null {\n const match = /^(#{1,6})\\s+(.+)/.exec(trimmed);\n if (!match) return null;\n return { type: \"heading\", level: match[1]!.length, text: match[2]! };\n}\n\n/** Check if a line is a horizontal rule. */\nfunction isHorizontalRule(trimmed: string): boolean {\n return /^(-{3,}|\\*{3,}|_{3,})\\s*$/.test(trimmed);\n}\n\n/** Check if a line is a markdown table row (starts and ends with |). */\nfunction isTableRow(line: string): boolean {\n const trimmed = line.trim();\n return trimmed.startsWith(\"|\") && trimmed.endsWith(\"|\");\n}\n\n/** Check if a line is a table separator row (e.g. |---|---|). */\nfunction isTableSeparator(line: string): boolean {\n return /^\\|[\\s:-]+\\|/.test(line.trim()) && /[\\s:-]+\\|$/.test(line.trim());\n}\n\n/**\n * Parse alignment from a separator cell.\n * Returns \"left\" for :---, \"center\" for :---:, \"right\" for ---:.\n */\nfunction parseAlign(cell: string): \"left\" | \"center\" | \"right\" {\n const trimmed = cell.trim();\n const left = trimmed.startsWith(\":\");\n const right = trimmed.endsWith(\":\");\n if (left && right) return \"center\";\n if (right) return \"right\";\n return \"left\";\n}\n\n/** Parse accumulated table lines into a MarkdownBlock. */\nfunction flushTable(tableLines: string[]): MarkdownBlock | null {\n if (tableLines.length < 2) return null;\n const headerLine = tableLines[0]!;\n const sepLine = tableLines[1]!;\n if (!isTableSeparator(sepLine)) return null;\n\n const headers = splitTableCells(headerLine);\n const sepCells = splitTableCells(sepLine);\n const aligns = sepCells.map(parseAlign);\n\n const rows: string[][] = [];\n for (let r = 2; r < tableLines.length; r++) {\n rows.push(splitTableCells(tableLines[r]!));\n }\n\n return {\n type: \"table\",\n text: tableLines.join(\"\\n\"),\n tableHeaders: headers,\n tableRows: rows,\n tableAligns: aligns,\n };\n}\n\n/** Split a table row like \"| A | B |\" into [\"A\", \"B\"]. */\nfunction splitTableCells(row: string): string[] {\n return row\n .trim()\n .replace(/^\\|/, \"\")\n .replace(/\\|$/, \"\")\n .split(\"|\")\n .map((c) => c.trim());\n}\n\n/** Try to parse a list item. Returns null if not a list item. */\nfunction tryParseListItem(line: string): MarkdownBlock | null {\n const trimmed = line.trim();\n const indent = line.length - line.trimStart().length;\n const indentLevel = Math.floor(indent / 2);\n\n // Task list: - [ ] text or - [x] text\n const taskMatch = /^[-*+]\\s+\\[([ xX])\\]\\s+(.+)/.exec(trimmed);\n if (taskMatch) {\n return {\n type: \"list_item\",\n text: taskMatch[2]!,\n checked: taskMatch[1]!.toLowerCase() === \"x\",\n indentLevel,\n };\n }\n\n if (/^[-*+]\\s+/.test(trimmed)) {\n return {\n type: \"list_item\",\n text: trimmed.replace(/^[-*+]\\s+/, \"\"),\n indentLevel,\n };\n }\n const orderedMatch = /^(\\d+)\\.\\s+(.+)/.exec(trimmed);\n if (orderedMatch) {\n return {\n type: \"list_item\",\n text: orderedMatch[2]!,\n listNumber: Number.parseInt(orderedMatch[1]!, 10),\n indentLevel,\n };\n }\n return null;\n}\n\n// ── Parse state & helpers ───────────────────────────\n\ninterface ParseState {\n inCodeBlock: boolean;\n codeLanguage: string;\n codeLines: string[];\n inBlockquote: boolean;\n quoteLines: string[];\n inDiff: boolean;\n diffLines: MarkdownBlock[];\n paraLines: string[];\n /** Accumulated table lines (raw) being collected. */\n tableLines: string[];\n /** Whether we're inside a table block. */\n inTable: boolean;\n}\n\n/** Flush accumulated paragraph lines as a paragraph block. */\nfunction flushParagraphLines(paraLines: string[], blocks: MarkdownBlock[]): void {\n const text = paraLines.join(\"\\n\").trim();\n if (text) blocks.push({ type: \"paragraph\", text });\n paraLines.length = 0;\n}\n\n/** Flush accumulated code lines as a code block. */\nfunction flushCodeLines(codeLines: string[], blocks: MarkdownBlock[], language: string): void {\n if (codeLines.length > 0) {\n blocks.push({ type: \"code\", text: codeLines.join(\"\\n\"), language: language || undefined });\n codeLines.length = 0;\n }\n}\n\n/** Flush accumulated quote lines as a blockquote. */\nfunction flushQuoteLines(quoteLines: string[], blocks: MarkdownBlock[]): void {\n if (quoteLines.length > 0) {\n blocks.push({ type: \"blockquote\", text: quoteLines.join(\"\\n\") });\n quoteLines.length = 0;\n }\n}\n\n/**\n * Handle code fence toggle, code block content, blockquote start/continue/end.\n * Returns true if the line was consumed (caller should continue the loop).\n */\nfunction tryProcessCodeStructure(\n raw: string,\n trimmed: string,\n state: ParseState,\n blocks: MarkdownBlock[],\n): boolean {\n if (trimmed.startsWith(\"```\")) {\n flushParagraphLines(state.paraLines, blocks);\n flushQuoteLines(state.quoteLines, blocks);\n if (state.inCodeBlock) {\n flushCodeLines(state.codeLines, blocks, state.codeLanguage);\n state.inCodeBlock = false;\n state.codeLanguage = \"\";\n } else {\n state.codeLanguage = trimmed.slice(3).trim();\n state.inCodeBlock = true;\n }\n return true;\n }\n if (state.inCodeBlock) {\n state.codeLines.push(raw);\n return true;\n }\n\n if (trimmed.startsWith(\"> \")) {\n flushParagraphLines(state.paraLines, blocks);\n state.inBlockquote = true;\n state.quoteLines.push(trimmed.slice(2));\n return true;\n }\n if (state.inBlockquote) {\n flushQuoteLines(state.quoteLines, blocks);\n state.inBlockquote = false;\n }\n return false;\n}\n\n/**\n * Handle diff block lines.\n * Returns true if the line was consumed as a diff line.\n */\nfunction tryProcessDiffLine(\n raw: string,\n prevTrimmed: string,\n state: ParseState,\n blocks: MarkdownBlock[],\n): boolean {\n const trimmed = raw.trim();\n const prevCtx = state.inDiff ? prevTrimmed : \"\";\n if (isDiffLine(trimmed, prevCtx)) {\n if (!state.inDiff) flushParagraphLines(state.paraLines, blocks);\n state.inDiff = true;\n state.diffLines.push({ type: \"diff\", text: raw, diffLineType: detectDiffLineType(trimmed) });\n return true;\n }\n if (state.inDiff && trimmed !== \"\" && !isDiffLine(trimmed)) {\n blocks.push(...state.diffLines);\n state.diffLines = [];\n state.inDiff = false;\n }\n return false;\n}\n\n/**\n * Try to parse a single-line block element (heading, HR, list item).\n * Returns true if the line was consumed.\n */\nfunction tryProcessSingleLineBlock(\n trimmed: string,\n state: ParseState,\n blocks: MarkdownBlock[],\n): boolean {\n const heading = tryParseHeading(trimmed);\n if (heading) {\n flushParagraphLines(state.paraLines, blocks);\n blocks.push(heading);\n return true;\n }\n if (isHorizontalRule(trimmed)) {\n flushParagraphLines(state.paraLines, blocks);\n blocks.push({ type: \"hr\", text: \"\" });\n return true;\n }\n const listItem = tryParseListItem(trimmed);\n if (listItem) {\n flushParagraphLines(state.paraLines, blocks);\n blocks.push(listItem);\n return true;\n }\n return false;\n}\n\n/**\n * Process a potential table line. Tables start when we see a header row\n * immediately followed by a separator row.\n *\n * Returns true if the line was consumed as part of a table.\n */\nfunction tryProcessTableLine(\n raw: string,\n idx: number,\n lines: string[],\n state: ParseState,\n blocks: MarkdownBlock[],\n): boolean {\n const trimmed = raw.trim();\n\n // If not a table row and not in a table, skip\n if (!isTableRow(trimmed) && !state.inTable) return false;\n\n if (isTableRow(trimmed)) {\n // Check if next line is a separator — that confirms a table header\n const nextLine = idx + 1 < lines.length ? lines[idx + 1]!.trim() : \"\";\n if (isTableSeparator(nextLine)) {\n // Start a new table: flush prior state\n flushParagraphLines(state.paraLines, blocks);\n if (state.inTable) {\n const flushed = flushTable(state.tableLines);\n if (flushed) blocks.push(flushed);\n state.tableLines = [];\n }\n state.inTable = true;\n state.tableLines.push(raw);\n return true;\n }\n // If we're already in a table, this is a data row\n if (state.inTable) {\n state.tableLines.push(raw);\n return true;\n }\n // Not a table after all — fall through to paragraph\n return false;\n }\n\n // Not a table row but we were in a table — flush and reset\n if (state.inTable && !isTableRow(trimmed)) {\n const flushed = flushTable(state.tableLines);\n if (flushed) blocks.push(flushed);\n state.tableLines = [];\n state.inTable = false;\n }\n return false;\n}\n\n/**\n * Preprocess markdown text before parsing:\n * 1. Replace emoji shortcodes (:smile: → 😀).\n * 2. Convert $$...$$ display LaTeX blocks to Unicode approximations.\n * 3. Convert $...$ inline LaTeX to Unicode approximations.\n */\nfunction preprocessMarkdown(md: string): string {\n // 1. Emoji shortcodes\n let result = renderEmojiShortcodes(md);\n\n // 2. Display LaTeX blocks — $$...$$ on their own lines → Unicode math block\n result = result.replace(/\\$\\$([\\s\\S]*?)\\$\\$/g, (_full: string, body: string) => {\n const approx = renderInlineLatex(body.trim());\n return `\\`\\`\\`math\\n${approx}\\n\\`\\`\\``;\n });\n\n // 3. Inline LaTeX — $...$ → Unicode approximated\n result = result.replace(/\\$([^$\\n]+?)\\$/g, (_full: string, body: string) => {\n if (isLatexInline(body)) return renderInlineLatex(body);\n return _full; // Not a LaTeX expression — leave as-is\n });\n\n return result;\n}\n\n/** Simple line‑by‑line markdown parser. Returns blocks in order. */\nexport function parseMarkdown(md: string, opts: RenderOptions = {}): MarkdownBlock[] {\n const { stableOnly = false } = opts;\n // Preprocess: emoji shortcodes and display LaTeX blocks\n const preprocessed = preprocessMarkdown(md);\n const lines = preprocessed.split(\"\\n\");\n const blocks: MarkdownBlock[] = [];\n\n const state: ParseState = {\n inCodeBlock: false,\n codeLanguage: \"\",\n codeLines: [],\n inBlockquote: false,\n quoteLines: [],\n inDiff: false,\n diffLines: [],\n paraLines: [],\n tableLines: [],\n inTable: false,\n };\n\n for (let i = 0; i < lines.length; i++) {\n const raw = lines[i]!;\n const trimmed = raw.trim();\n\n // Table detection: check before code/diff/single-line blocks since\n // tables can look like regular text to other detectors.\n if (tryProcessTableLine(raw, i, lines, state, blocks)) continue;\n\n if (tryProcessCodeStructure(raw, trimmed, state, blocks)) continue;\n const prevTrimmed = i > 0 ? lines[i - 1]!.trim() : \"\";\n if (tryProcessDiffLine(raw, prevTrimmed, state, blocks)) continue;\n if (tryProcessSingleLineBlock(trimmed, state, blocks)) continue;\n if (trimmed === \"\") {\n flushParagraphLines(state.paraLines, blocks);\n continue;\n }\n\n state.paraLines.push(trimmed);\n }\n\n // Flush any remaining\n if (!(state.inCodeBlock && stableOnly))\n flushCodeLines(state.codeLines, blocks, state.codeLanguage);\n flushQuoteLines(state.quoteLines, blocks);\n if (state.diffLines.length > 0) blocks.push(...state.diffLines);\n if (state.inTable) {\n const flushed = flushTable(state.tableLines);\n if (flushed) blocks.push(flushed);\n }\n flushParagraphLines(state.paraLines, blocks);\n\n return blocks;\n}\n\n/**\n * For streaming text, find the last \"stable\" offset — the position\n * after the last complete block. Everything before this offset can\n * be memoized; only the suffix needs re‑parsing.\n */\nexport function findStableOffset(text: string): number {\n const lastDouble = text.lastIndexOf(\"\\n\\n\");\n if (lastDouble < 0) return 0;\n\n const fenceCount = (text.match(/```/g) ?? []).length;\n if (fenceCount % 2 !== 0) {\n const lastFence = text.lastIndexOf(\"```\");\n if (lastFence > 0) return lastFence;\n return 0;\n }\n\n return lastDouble + 2;\n}\n\n// ── Block renderers ────────────────────────────────\n\n/** Map diff line type to an Ink color string. */\nfunction getDiffColor(diffLineType?: string): string {\n switch (diffLineType) {\n case \"header\":\n return \"grey\";\n case \"hunk\":\n return \"cyan\";\n case \"add\":\n return \"green\";\n case \"remove\":\n return \"red\";\n default:\n return \"white\";\n }\n}\n\n/** Render a heading block. */\nfunction renderHeadingBlock(block: MarkdownBlock, i: number): ReactNode {\n const color = block.level === 1 ? \"cyan\" : block.level === 2 ? \"yellow\" : \"green\";\n return React.createElement(Text, { key: `h-${i}`, bold: true, color }, renderInline(block.text));\n}\n\n/** Render a fenced code block with syntax highlighting (cross‑line comment aware). */\nfunction renderCodeBlock(block: MarkdownBlock, i: number): ReactNode {\n const highlightLines = highlightCodeBlock(block.text, block.language);\n const children: ReactNode[] = [];\n\n if (block.language) {\n children.push(\n React.createElement(Text, { key: \"lang\", bold: true, color: \"cyan\" }, `[${block.language}]`),\n );\n }\n\n for (let li = 0; li < highlightLines.length; li++) {\n const spans = highlightLines[li]!;\n // Optimize: single plain span → render as string\n if (spans.length === 1 && spans[0]!.kind === \"plain\") {\n children.push(React.createElement(Text, { key: `cl-${li}` }, spans[0]!.text));\n continue;\n }\n const spanElements = spans\n .filter((s) => s.text !== \"\")\n .map((span, si) => {\n const color = spanColor(span.kind);\n const props: Record<string, unknown> = { key: `hs-${li}-${si}` };\n if (span.kind === \"keyword\" || span.kind === \"type\") props.bold = true;\n if (span.kind === \"comment\") props.dimColor = true;\n if (color) props.color = color;\n return React.createElement(Text, props, span.text);\n });\n children.push(React.createElement(Text, { key: `cl-${li}` }, ...spanElements));\n }\n\n return React.createElement(\n Box,\n { key: `code-${i}`, flexDirection: \"column\" },\n React.createElement(\n Box,\n {\n borderStyle: \"classic\" as const,\n borderColor: \"grey\" as const,\n paddingX: 1,\n flexDirection: \"column\",\n },\n ...children,\n ),\n );\n}\n\n/** Render a blockquote block. */\nfunction renderBlockquoteBlock(block: MarkdownBlock, i: number): ReactNode {\n return React.createElement(Text, { key: `q-${i}`, color: \"grey\" }, `│ ${block.text}`);\n}\n\n/** Render a list item block, including task list checkbox and indentation. */\nfunction renderListItemBlock(block: MarkdownBlock, i: number): ReactNode {\n const indentPad = block.indentLevel ? \" \".repeat(block.indentLevel) : \"\";\n\n // Task list item\n if (block.checked !== undefined) {\n const checkbox = block.checked ? \"☑\" : \"☐\";\n const color = block.checked ? \"green\" : \"grey\";\n return React.createElement(\n Text,\n { key: `li-${i}` },\n indentPad,\n React.createElement(Text, { color: \"yellow\" }, \"• \"),\n React.createElement(Text, { color }, `${checkbox} `),\n React.createElement(\n Text,\n block.checked ? { strikethrough: true, dimColor: true, color: \"green\" } : {},\n renderInline(block.text),\n ),\n );\n }\n\n // Regular list (ordered or unordered)\n const marker = block.listNumber ? `${block.listNumber}. ` : \"• \";\n return React.createElement(\n Text,\n { key: `li-${i}` },\n indentPad,\n React.createElement(Text, { color: \"yellow\" }, marker),\n React.createElement(Text, { color: \"white\" }, renderInline(block.text)),\n );\n}\n\n/** Render a diff block line. */\nfunction renderDiffBlock(block: MarkdownBlock, i: number): ReactNode {\n return React.createElement(\n Text,\n { key: `d-${i}`, color: getDiffColor(block.diffLineType) },\n block.text,\n );\n}\n\n/** Render a horizontal rule. */\nfunction renderHRBlock(i: number): ReactNode {\n return React.createElement(Text, { key: `hr-${i}`, dimColor: true }, \"────────────────\");\n}\n\n/**\n * Render a table block with aligned columns.\n *\n * Calculates column widths based on content, renders headers in bold,\n * and aligns each cell according to the table's alignment spec.\n */\nfunction renderTableBlock(block: MarkdownBlock, i: number): ReactNode {\n const headers = block.tableHeaders ?? [];\n const rows = block.tableRows ?? [];\n const aligns = block.tableAligns ?? [];\n const allRows = [headers, ...rows];\n\n // Calculate column widths from content\n const colCount = Math.max(headers.length, ...rows.map((r) => r.length), 1);\n const widths: number[] = new Array(colCount).fill(0);\n for (const row of allRows) {\n for (let c = 0; c < colCount; c++) {\n widths[c] = Math.max(widths[c] ?? 0, (row[c] ?? \"\").length);\n }\n }\n\n // Render helper: pad a cell to fit its column width\n function padCell(cell: string, col: number): string {\n const w = widths[col] ?? 0;\n const align = aligns[col] ?? \"left\";\n if (align === \"right\") return cell.padStart(w);\n if (align === \"center\") {\n const left = Math.floor((w - cell.length) / 2);\n return \" \".repeat(left) + cell + \" \".repeat(w - cell.length - left);\n }\n return cell.padEnd(w); // left\n }\n\n const dim = \"grey\";\n const children: ReactNode[] = [];\n\n // Header row\n const headerCells: ReactNode[] = [];\n for (let c = 0; c < colCount; c++) {\n headerCells.push(\n React.createElement(Text, { key: `th-${c}`, bold: true }, padCell(headers[c] ?? \"\", c)),\n );\n if (c < colCount - 1) {\n headerCells.push(React.createElement(Text, { key: `sep-h-${c}`, color: dim }, \" │ \"));\n }\n }\n children.push(React.createElement(Box, { key: \"thead\", flexDirection: \"row\" }, ...headerCells));\n\n // Separator line\n children.push(\n React.createElement(\n Text,\n { key: \"tsep\", color: dim },\n \"─\".repeat(widths.reduce((a, b) => a + b + 3 * (colCount - 1), 0)),\n ),\n );\n\n // Data rows\n for (let r = 0; r < rows.length; r++) {\n const row = rows[r]!;\n const cells: ReactNode[] = [];\n for (let c = 0; c < colCount; c++) {\n cells.push(React.createElement(Text, { key: `td-${r}-${c}` }, padCell(row[c] ?? \"\", c)));\n if (c < colCount - 1) {\n cells.push(React.createElement(Text, { key: `sep-${r}-${c}`, color: dim }, \" │ \"));\n }\n }\n children.push(React.createElement(Box, { key: `tr-${r}`, flexDirection: \"row\" }, ...cells));\n }\n\n return React.createElement(\n Box,\n { key: `table-${i}`, flexDirection: \"column\", paddingY: 1 },\n React.createElement(\n Box,\n {\n borderStyle: \"classic\" as const,\n borderColor: \"grey\" as const,\n paddingX: 1,\n flexDirection: \"column\",\n },\n ...children,\n ),\n );\n}\n\n/** Render a paragraph block with inline formatting. */\nfunction renderParagraphBlock(block: MarkdownBlock, i: number): ReactNode {\n return React.createElement(Text, { key: `p-${i}` }, renderInline(block.text));\n}\n\n/**\n * Render parsed markdown blocks as Ink elements.\n *\n * Uses a Box with flexDirection=\"column\" as the container so that\n * code blocks (which are Box elements with borders) can coexist with\n * text blocks (which are Text elements).\n */\nexport function renderBlocks(blocks: MarkdownBlock[]): ReactNode {\n const elements: ReactNode[] = [];\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]!;\n\n switch (block.type) {\n case \"heading\":\n elements.push(renderHeadingBlock(block, i));\n break;\n case \"code\":\n elements.push(renderCodeBlock(block, i));\n break;\n case \"blockquote\":\n elements.push(renderBlockquoteBlock(block, i));\n break;\n case \"list_item\":\n elements.push(renderListItemBlock(block, i));\n break;\n case \"diff\":\n elements.push(renderDiffBlock(block, i));\n break;\n case \"hr\":\n elements.push(renderHRBlock(i));\n break;\n case \"table\":\n elements.push(renderTableBlock(block, i));\n break;\n default:\n elements.push(renderParagraphBlock(block, i));\n }\n }\n\n if (elements.length === 0) {\n return React.createElement(Text, null, \"\");\n }\n\n return React.createElement(Box, { flexDirection: \"column\" }, ...elements);\n}\n","/**\n * MessageRow — renders a single chat transcript entry with proper visual styling.\n *\n * Three bubble styles aligned to Claude Code:\n * - User: indented right, no prefix, direct style\n * - Assistant: full-width with markdown rendering\n * - System/Tool: dimmed, prefixed, compact\n *\n * Design (§5.4a #1.3.2): extracts per‑entry rendering from ChatLog\n * (was 1058 lines) into a standalone component with proper JSDoc.\n */\n\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\nimport {\n parseMarkdown,\n renderBlocks,\n renderInline,\n findStableOffset,\n} from \"../renderer/markdown.js\";\nimport type { ChatLogEntry } from \"./ChatLog.js\";\n\n// ── Constants ────────────────────────────────────────\n\n/** Characters beyond which a tool_result is collapsed by default. */\nconst TOOL_RESULT_COLLAPSE_LEN = 1000;\n\n// ── Props ─────────────────────────────────────────────\n\n/** Props for the MessageRow component. */\nexport interface MessageRowProps {\n /** The chat entry to render. */\n entry: ChatLogEntry;\n /** Whether this entry's collapsible content is expanded. */\n isExpanded: boolean;\n /** Transcript display mode: compact hides timestamps. */\n transcriptMode?: \"compact\" | \"full\";\n /** Search query string for highlighting (empty → no highlights). */\n searchQuery?: string;\n /** Byte offsets into entry.text where search matches start. */\n matchIndices?: number[];\n}\n\n// ── Component ──────────────────────────────────────────\n\n/**\n * Single message row in the chat transcript.\n *\n * Dispatches to specialized renderers based on `entry.kind`:\n * assistant → full markdown (streaming or finalized)\n * user → right‑aligned bubble\n * system → dimmed prefix line\n * tool_use → status icon + tool name\n * tool_result → collapsible inline result\n * thinking → collapsed/expanded reasoning block\n * btw → accent‑colored hint\n */\n\n/** Single message row in the chat transcript — dispatches to specialized renderers by entry kind. */\nexport function MessageRow({\n entry,\n isExpanded,\n transcriptMode = \"compact\",\n searchQuery = \"\",\n matchIndices = [],\n}: MessageRowProps): React.ReactElement {\n const theme = getTheme();\n\n // ── Timestamp row (full mode only) ────────────\n\n const timestampRow =\n transcriptMode === \"full\"\n ? React.createElement(\n Text,\n { dimColor: true },\n `── ${new Date(entry.timestamp).toLocaleTimeString()} · ${kindLabel(entry.kind)} ──`,\n )\n : null;\n\n // ── Entry content ─────────────────────────────\n\n const content = renderEntryContent(entry, isExpanded, matchIndices, searchQuery, theme);\n\n return React.createElement(\n Box,\n { flexDirection: \"column\", marginBottom: entry.kind === \"btw\" ? 0 : 1 },\n timestampRow,\n ...content,\n );\n}\n\n// ── Entry kind label ─────────────────────────────────\n\n/** Map entry kind to a Chinese label for display. */\nfunction kindLabel(kind: ChatLogEntry[\"kind\"]): string {\n switch (kind) {\n case \"system\":\n return \"系统\";\n case \"user\":\n return \"用户\";\n case \"assistant\":\n return \"助手\";\n case \"tool_use\":\n return \"工具调用\";\n case \"tool_result\":\n return \"工具结果\";\n case \"btw\":\n return \"提示\";\n case \"thinking\":\n return \"思考\";\n }\n}\n\n// ── Color lookup ──────────────────────────────────────\n\nfunction entryColor(entry: ChatLogEntry, colors: Record<string, string>): string | undefined {\n switch (entry.kind) {\n case \"system\":\n return entry.level === \"error\"\n ? colors.error\n : entry.level === \"warn\"\n ? colors.warning\n : colors.dimmed;\n case \"user\":\n return entry.pending ? colors.dimmed : colors.foreground;\n case \"assistant\":\n return colors.foreground;\n case \"tool_use\":\n return colors.info ?? \"yellow\";\n case \"tool_result\":\n return colors.dimmed;\n case \"btw\":\n return colors.accent;\n case \"thinking\":\n return colors.dimmed;\n default:\n return undefined;\n }\n}\n\n// ── Prefix lookup ─────────────────────────────────────\n\nfunction entryPrefix(entry: ChatLogEntry): string {\n switch (entry.kind) {\n case \"system\":\n return entry.level === \"error\" ? \"✘ \" : entry.level === \"warn\" ? \"⚠ \" : \"─ \";\n case \"user\":\n return entry.pending ? \"[发送中] \" : \"> \";\n case \"assistant\":\n return \"\";\n case \"tool_use\":\n return \"\";\n case \"tool_result\":\n return \"\";\n case \"btw\":\n return \"💡 \";\n case \"thinking\":\n return \"💭 \";\n default:\n return \"\";\n }\n}\n\n// ── Per‑entry dispatch ────────────────────────────────\n\nfunction renderEntryContent(\n entry: ChatLogEntry,\n isExpanded: boolean,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n switch (entry.kind) {\n case \"assistant\":\n return renderAssistant(entry, matchIndices, searchQuery, theme);\n case \"system\":\n return renderSystem(entry, matchIndices, searchQuery, theme);\n case \"user\":\n return renderUser(entry, matchIndices, searchQuery, theme);\n case \"tool_use\":\n return renderToolUse(entry, matchIndices, searchQuery, theme);\n case \"tool_result\":\n return renderToolResult(entry, isExpanded, matchIndices, searchQuery, theme);\n case \"btw\":\n return renderBtw(entry, matchIndices, searchQuery, theme);\n case \"thinking\":\n return renderThinking(entry, isExpanded, theme);\n default:\n return [\n React.createElement(\n Text,\n { key: \"text\", color: entryColor(entry, theme.colors) },\n entry.text,\n ),\n ];\n }\n}\n\n// ── Assistant (full markdown) ─────────────────────────\n\nfunction renderAssistant(\n entry: ChatLogEntry,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const elements: React.ReactElement[] = [];\n\n if (entry.streaming) {\n const stableOffset = findStableOffset(entry.text);\n const stablePart = entry.text.slice(0, stableOffset);\n const unstablePart = entry.text.slice(stableOffset);\n\n if (stablePart) {\n const blocks = parseMarkdown(stablePart);\n elements.push(\n React.createElement(Box, { key: \"stable\", flexDirection: \"column\" }, renderBlocks(blocks)),\n );\n }\n if (unstablePart) {\n elements.push(\n React.createElement(\n Text,\n { key: \"streaming\", color: theme.colors.foreground },\n highlightMatches(unstablePart, matchIndices, searchQuery),\n React.createElement(Text, null, \"▊\"),\n ),\n );\n } else if (!stablePart) {\n elements.push(\n React.createElement(Text, { key: \"streaming\", color: theme.colors.foreground }, \"▊\"),\n );\n }\n } else {\n const blocks = parseMarkdown(entry.text);\n if (blocks.length > 0) {\n elements.push(\n React.createElement(Box, { key: \"md\", flexDirection: \"column\" }, renderBlocks(blocks)),\n );\n }\n }\n\n return elements;\n}\n\n// ── System ────────────────────────────────────────────\n\nfunction renderSystem(\n entry: ChatLogEntry,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const color = entryColor(entry, theme.colors);\n const prefix = entryPrefix(entry);\n const content = highlightMatches(entry.text, matchIndices, searchQuery);\n\n return [\n React.createElement(Text, { key: \"content\", color }, prefix, renderInlineContent(content)),\n ];\n}\n\n// ── User ──────────────────────────────────────────────\n\nfunction renderUser(\n entry: ChatLogEntry,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const color = entryColor(entry, theme.colors);\n const prefix = entryPrefix(entry);\n const suffix = entry.pending ? \"…\" : \"\";\n\n return [\n React.createElement(\n Text,\n { key: \"content\", color },\n prefix,\n renderInlineContent(highlightMatches(entry.text, matchIndices, searchQuery)),\n suffix,\n ),\n ];\n}\n\n// ── Tool use ──────────────────────────────────────────\n\nfunction renderToolUse(\n entry: ChatLogEntry,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const isDone = entry.toolStartedAt !== undefined && entry.text.includes(\"·\");\n const prefix = isDone ? \"✓ \" : \"✽ \";\n const color = isDone ? theme.colors.success : theme.colors.accent;\n const suffix = isDone ? \"\" : \"…\";\n\n return [\n React.createElement(\n Text,\n { key: \"content\", color },\n prefix,\n highlightMatches(entry.text + suffix, matchIndices, searchQuery),\n ),\n ];\n}\n\n// ── Tool result (collapsible) ─────────────────────────\n\n/** Collapse multi-line content into a single line. */\nfunction collapseWhitespace(text: string): string {\n return text.replace(/\\s+/g, \" \").trim();\n}\n\nfunction renderToolResult(\n entry: ChatLogEntry,\n isExpanded: boolean,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const color = theme.colors.foreground;\n const collapsed = collapseWhitespace(entry.text);\n const isLong = collapsed.length > TOOL_RESULT_COLLAPSE_LEN;\n const elements: React.ReactElement[] = [];\n\n if (isLong && !isExpanded) {\n const truncated = collapsed.slice(0, TOOL_RESULT_COLLAPSE_LEN);\n elements.push(\n React.createElement(\n Text,\n { key: \"content\", color, dimColor: true },\n \" ⎿ \",\n renderInlineContent(highlightMatches(truncated, matchIndices, searchQuery)),\n React.createElement(\n Text,\n { key: \"ellipsis\", dimColor: true },\n `… [+${collapsed.length - TOOL_RESULT_COLLAPSE_LEN} 字符, Ctrl+E 展开]`,\n ),\n ),\n );\n } else {\n elements.push(\n React.createElement(\n Text,\n { key: \"content\", color, dimColor: true },\n \" ⎿ \",\n renderInlineContent(highlightMatches(collapsed, matchIndices, searchQuery)),\n isLong\n ? React.createElement(Text, { key: \"collapse\", dimColor: true }, \" [Ctrl+E 折叠]\")\n : null,\n ),\n );\n }\n\n return elements;\n}\n\n// ── BTW hint ──────────────────────────────────────────\n\nfunction renderBtw(\n entry: ChatLogEntry,\n matchIndices: number[],\n searchQuery: string,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const color = entryColor(entry, theme.colors);\n const prefix = entryPrefix(entry);\n\n return [\n React.createElement(\n Text,\n { key: \"content\", color },\n prefix,\n renderInlineContent(highlightMatches(entry.text, matchIndices, searchQuery)),\n ),\n ];\n}\n\n// ── Thinking (collapsible reasoning) ──────────────────\n\nfunction renderThinking(\n entry: ChatLogEntry,\n isExpanded: boolean,\n theme: ReturnType<typeof getTheme>,\n): React.ReactElement[] {\n const color = entryColor(entry, theme.colors);\n const prefix = entryPrefix(entry);\n const seconds = entry.durationMs != null ? (entry.durationMs / 1000).toFixed(1) : \"?\";\n\n if (isExpanded) {\n const lines = entry.text.trim().split(\"\\n\");\n return lines.map((line, i) =>\n React.createElement(\n Text,\n { key: `think-${i}`, color },\n i === 0 ? `${prefix}已思考 ${seconds}s · Enter 折叠` : prefix,\n line || \" \",\n ),\n );\n }\n\n return [\n React.createElement(\n Text,\n { key: \"summary\", color, dimColor: true },\n `${prefix}已思考 ${seconds}s · Enter 展开`,\n ),\n ];\n}\n\n// ── Inline formatting + search highlighting ────────────\n\n/** Render text with inline markdown formatting. */\nfunction renderInlineContent(content: React.ReactNode): React.ReactNode {\n if (typeof content === \"string\") {\n return renderInline(content);\n }\n return content;\n}\n\n/**\n * Highlight search query matches in text.\n *\n * Wraps each match in an inverse‑colored `<Text>` span.\n * Returns plain text when no query/matches are active.\n */\nfunction highlightMatches(text: string, matchIndices: number[], query: string): React.ReactNode {\n if (!query || matchIndices.length === 0) return text;\n\n const len = query.length;\n const sorted = [...new Set(matchIndices)].sort((a, b) => a - b);\n\n const children: React.ReactNode[] = [];\n let cursor = 0;\n\n for (const start of sorted) {\n if (start < cursor) continue;\n if (start > cursor) {\n children.push(text.slice(cursor, start));\n }\n children.push(\n React.createElement(\n Text,\n { key: `hl-${start}`, inverse: true },\n text.slice(start, start + len),\n ),\n );\n cursor = start + len;\n }\n\n if (cursor < text.length) {\n children.push(text.slice(cursor));\n }\n\n if (children.length === 1 && typeof children[0] === \"string\") {\n return children[0];\n }\n\n return children;\n}\n","/**\n * ChatLog — imperative‑handle message transcript.\n *\n * Exposes a ChatLogHandle with 13 methods for the agent loop to\n * drive the UI. Internally uses React useReducer + forwardRef +\n * useImperativeHandle so parent components never touch raw state.\n *\n * Lifecycle:\n * addUser → startAssistant → updateAssistant × N → finalizeAssistant\n * addUser(pending) → commitPendingUser | dropPendingUser\n * addTool → updateToolResult\n *\n * Design rationale (vs FengMing's 35‑method handle):\n * - Single‑threaded agent loop → no runId routing needed\n * - Local process → no gateway reconnect (reconcilePendingUsers)\n * - reserveAssistantSlot folded into startAssistant\n */\n\nimport React, { useReducer, useImperativeHandle, forwardRef, useRef, useState } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\nimport { MessageRow } from \"./MessageRow.js\";\n\n// ── Types ──────────────────────────────────────────\n\n/** A single entry in the chat transcript. */\nexport interface ChatLogEntry {\n readonly id: string;\n readonly kind: \"system\" | \"user\" | \"assistant\" | \"tool_use\" | \"tool_result\" | \"btw\" | \"thinking\";\n readonly text: string;\n readonly streaming?: boolean;\n readonly pending?: boolean;\n readonly toolName?: string;\n readonly toolCallId?: string;\n readonly toolStartedAt?: number;\n readonly level?: \"info\" | \"warn\" | \"error\";\n /** Duration in ms for thinking entries (shown as \"已思考 X.Xs\"). */\n readonly durationMs?: number;\n readonly timestamp: number;\n}\n\n/** Imperative handle exposed to the parent (agent loop / App). */\nexport interface ChatLogHandle {\n /** Append a system message (info, warning, or error). */\n addSystem(text: string, level?: \"info\" | \"warn\" | \"error\"): void;\n /** Append a user message, optionally marked as pending (optimistic). */\n addUser(text: string, pending?: boolean): void;\n /** Remove the pending marker from the most recent user message. */\n commitPendingUser(): void;\n /** Remove the pending user message entirely. */\n dropPendingUser(): void;\n /** Create (or update) a streaming assistant message. */\n startAssistant(text?: string): void;\n /** Incrementally update the streaming assistant's text. */\n updateAssistant(text: string): void;\n /** Finalize the streaming assistant message — sets streaming=false. */\n finalizeAssistant(text?: string): void;\n /** Remove the streaming assistant message (on error / abort). */\n dropAssistant(): void;\n /** Append a tool‑use entry. */\n addTool(name: string, callId: string): void;\n /** Update the result of a previously added tool‑use entry. */\n updateToolResult(callId: string, result: string): void;\n /** Show a by‑the‑way hint (non‑conversational guidance). */\n showBtw(text: string): void;\n /** Remove the btw message. */\n dismissBtw(): void;\n /** Show a collapsible thinking entry with duration. Default collapsed, Enter toggles. */\n showThinking(text: string, durationMs: number): void;\n /** Remove the thinking message. */\n dismissThinking(): void;\n /** Clear the entire transcript. */\n clearAll(): void;\n /** Return the total number of entries (for scroll calculation). */\n getEntryCount(): number;\n}\n\n/** Props passed to the ChatLog component. */\nexport interface ChatLogProps {\n readonly visibleRange?: { readonly start: number; readonly end: number };\n /** Called when search mode is toggled (so parent can disable InputBox). */\n readonly onSearchActiveChange?: (active: boolean) => void;\n /** Transcript display mode: compact hides timestamps, full shows them + expanded content. */\n readonly transcriptMode?: \"compact\" | \"full\";\n}\n\n// ── State ──────────────────────────────────────────\n\n/** Internal state managed by the ChatLog reducer. */\nexport interface ChatLogState {\n entries: ChatLogEntry[];\n nextId: number;\n}\n\n/** Action discriminated union for the ChatLog reducer. */\nexport type ChatLogAction =\n | { kind: \"ADD_SYSTEM\"; text: string; level?: \"info\" | \"warn\" | \"error\" }\n | { kind: \"ADD_USER\"; text: string; pending?: boolean }\n | { kind: \"COMMIT_PENDING_USER\" }\n | { kind: \"DROP_PENDING_USER\" }\n | { kind: \"START_ASSISTANT\"; text?: string }\n | { kind: \"UPDATE_ASSISTANT\"; text: string }\n | { kind: \"FINALIZE_ASSISTANT\"; text?: string }\n | { kind: \"DROP_ASSISTANT\" }\n | { kind: \"ADD_TOOL\"; name: string; callId: string }\n | { kind: \"UPDATE_TOOL_RESULT\"; callId: string; result: string }\n | { kind: \"SHOW_BTW\"; text: string }\n | { kind: \"DISMISS_BTW\" }\n | { kind: \"SHOW_THINKING\"; text: string; durationMs: number }\n | { kind: \"DISMISS_THINKING\" }\n | { kind: \"CLEAR_ALL\" };\n\nfunction nextId(state: ChatLogState): string {\n return `cl-${state.nextId}`;\n}\n\nfunction entry(\n state: ChatLogState,\n kind: ChatLogEntry[\"kind\"],\n text: string,\n extra?: Partial<ChatLogEntry>,\n): ChatLogEntry {\n return { id: nextId(state), kind, text, timestamp: Date.now(), ...extra };\n}\n\n// ── Reducer action handlers ───────────────────────\n\nfunction reduceAddSystem(\n state: ChatLogState,\n text: string,\n level?: \"info\" | \"warn\" | \"error\",\n): ChatLogState {\n const entries = [...state.entries];\n entries.push(entry(state, \"system\", text, { level: level ?? \"info\" }));\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceAddUser(state: ChatLogState, text: string, pending?: boolean): ChatLogState {\n const entries = [...state.entries];\n entries.push(entry(state, \"user\", text, { pending: pending ?? false }));\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceCommitPendingUser(state: ChatLogState): ChatLogState {\n const entries = [...state.entries];\n for (let i = entries.length - 1; i >= 0; i--) {\n if (entries[i]!.kind === \"user\" && entries[i]!.pending) {\n entries[i] = { ...entries[i]!, pending: false };\n break;\n }\n }\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceDropPendingUser(state: ChatLogState): ChatLogState {\n const entries = [...state.entries];\n const idx = findLastIndex(entries,(e) => e.kind === \"user\" && e.pending);\n if (idx !== -1) entries.splice(idx, 1);\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceStartAssistant(state: ChatLogState, text?: string): ChatLogState {\n const entries = [...state.entries];\n const existing = findLastIndex(entries,(e) => e.kind === \"assistant\" && e.streaming);\n const newEntry = entry(state, \"assistant\", text ?? \"\", { streaming: true });\n if (existing !== -1) {\n entries[existing] = newEntry;\n return { entries, nextId: state.nextId };\n }\n entries.push(newEntry);\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceUpdateAssistant(state: ChatLogState, text: string): ChatLogState {\n const entries = [...state.entries];\n for (let i = entries.length - 1; i >= 0; i--) {\n if (entries[i]!.kind === \"assistant\" && entries[i]!.streaming) {\n entries[i] = { ...entries[i]!, text: entries[i]!.text + text };\n break;\n }\n }\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceFinalizeAssistant(state: ChatLogState, text?: string): ChatLogState {\n const entries = [...state.entries];\n for (let i = entries.length - 1; i >= 0; i--) {\n if (entries[i]!.kind === \"assistant\" && entries[i]!.streaming) {\n entries[i] = { ...entries[i]!, text: text ?? entries[i]!.text, streaming: false };\n break;\n }\n }\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceDropAssistant(state: ChatLogState): ChatLogState {\n const entries = [...state.entries];\n const idx = findLastIndex(entries,(e) => e.kind === \"assistant\" && e.streaming);\n if (idx !== -1) entries.splice(idx, 1);\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceAddTool(state: ChatLogState, name: string, callId: string): ChatLogState {\n const entries = [...state.entries];\n entries.push(\n entry(state, \"tool_use\", name, {\n toolName: name,\n toolCallId: callId,\n toolStartedAt: Date.now(),\n }),\n );\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceUpdateToolResult(state: ChatLogState, callId: string, result: string): ChatLogState {\n const entries = [...state.entries];\n let nextId = state.nextId;\n for (let i = entries.length - 1; i >= 0; i--) {\n const e = entries[i]!;\n if (e.kind === \"tool_use\" && e.toolCallId === callId) {\n const duration = e.toolStartedAt ? ((Date.now() - e.toolStartedAt) / 1000).toFixed(1) : \"?\";\n // Store result text + duration on the tool_use entry for rendering\n entries[i] = {\n ...e,\n text: `${e.toolName ?? \"tool\"} · ${duration}s`,\n };\n // Add compact tool_result entry with the actual result\n entries.push(entry(state, \"tool_result\", result, { toolCallId: callId }));\n nextId++;\n break;\n }\n }\n return { entries, nextId };\n}\n\nfunction reduceShowBtw(state: ChatLogState, text: string): ChatLogState {\n const entries = [...state.entries];\n const existing = findLastIndex(entries,(e) => e.kind === \"btw\");\n if (existing !== -1) entries.splice(existing, 1);\n entries.push(entry(state, \"btw\", text));\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceDismissBtw(state: ChatLogState): ChatLogState {\n const entries = [...state.entries];\n const idx = findLastIndex(entries,(e) => e.kind === \"btw\");\n if (idx !== -1) entries.splice(idx, 1);\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceShowThinking(state: ChatLogState, text: string, durationMs: number): ChatLogState {\n const entries = [...state.entries];\n entries.push(entry(state, \"thinking\", text, { durationMs }));\n return { entries, nextId: state.nextId + 1 };\n}\n\nfunction reduceDismissThinking(state: ChatLogState): ChatLogState {\n const entries = [...state.entries];\n const idx = findLastIndex(entries,(e) => e.kind === \"thinking\");\n if (idx !== -1) entries.splice(idx, 1);\n return { entries, nextId: state.nextId };\n}\n\nfunction reduceClearAll(): ChatLogState {\n return { entries: [], nextId: 0 };\n}\n\n/** Pure reducer for ChatLog state — exported for testing. */\nexport function chatLogReducer(state: ChatLogState, action: ChatLogAction): ChatLogState {\n switch (action.kind) {\n case \"ADD_SYSTEM\":\n return reduceAddSystem(state, action.text, action.level);\n case \"ADD_USER\":\n return reduceAddUser(state, action.text, action.pending);\n case \"COMMIT_PENDING_USER\":\n return reduceCommitPendingUser(state);\n case \"DROP_PENDING_USER\":\n return reduceDropPendingUser(state);\n case \"START_ASSISTANT\":\n return reduceStartAssistant(state, action.text);\n case \"UPDATE_ASSISTANT\":\n return reduceUpdateAssistant(state, action.text);\n case \"FINALIZE_ASSISTANT\":\n return reduceFinalizeAssistant(state, action.text);\n case \"DROP_ASSISTANT\":\n return reduceDropAssistant(state);\n case \"ADD_TOOL\":\n return reduceAddTool(state, action.name, action.callId);\n case \"UPDATE_TOOL_RESULT\":\n return reduceUpdateToolResult(state, action.callId, action.result);\n case \"SHOW_BTW\":\n return reduceShowBtw(state, action.text);\n case \"DISMISS_BTW\":\n return reduceDismissBtw(state);\n case \"SHOW_THINKING\":\n return reduceShowThinking(state, action.text, action.durationMs);\n case \"DISMISS_THINKING\":\n return reduceDismissThinking(state);\n case \"CLEAR_ALL\":\n return reduceClearAll();\n }\n}\n\n// ── Polyfills ──────────────────────────────────────\n\n/** ES2023 polyfill — find the index of the last element matching a predicate. */\nfunction findLastIndex<T>(arr: readonly T[], pred: (e: T) => unknown): number {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (pred(arr[i]!)) return i;\n }\n return -1;\n}\n\n/** ES2023 polyfill — find the last element matching a predicate. */\nfunction findLast<T>(arr: readonly T[], pred: (e: T) => unknown): T | undefined {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (pred(arr[i]!)) return arr[i];\n }\n return undefined;\n}\n\n// ── Constants ──────────────────────────────────────\n\nconst MAX_VISIBLE = 50;\n/** Characters beyond which a tool_result is collapsed by default. */\nconst TOOL_RESULT_COLLAPSE_LEN = 1000;\n\n// ── Component ──────────────────────────────────────\n\n/** ChatLog component — renders the message transcript driven by a handle. */\nexport const ChatLog = forwardRef<ChatLogHandle, ChatLogProps>(function ChatLog(\n { visibleRange, onSearchActiveChange, transcriptMode = \"compact\" },\n ref,\n): React.ReactElement {\n const [state, dispatch] = useReducer(chatLogReducer, { entries: [], nextId: 0 });\n const theme = getTheme();\n\n // Keep a ref to the latest state so useImperativeHandle's stale closure\n // (with [] deps) can still read current values.\n const stateRef = useRef(state);\n stateRef.current = state;\n\n // ── Expand/collapse state ──\n const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set());\n\n // ── Search state ──\n const [searchActive, setSearchActive] = useState(false);\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [searchMatchIdx, setSearchMatchIdx] = useState(0);\n\n // Refs for values read inside useInkInput (stale‑closure safety)\n const searchActiveRef = useRef(searchActive);\n searchActiveRef.current = searchActive;\n const stateForInputRef = useRef(state);\n stateForInputRef.current = state;\n\n /** Toggle search mode and notify parent (so InputBox can be disabled). */\n function setSearchMode(active: boolean): void {\n searchActiveRef.current = active;\n setSearchActive(active);\n if (!active) {\n setSearchQuery(\"\");\n setSearchMatchIdx(0);\n }\n onSearchActiveChange?.(active);\n }\n\n // ── Keyboard ────────────────────────────────────\n useInkInput((input: string, key: Key) => {\n // Ctrl+F → toggle search\n if (key.ctrl && !key.meta && input === \"f\") {\n setSearchMode(!searchActiveRef.current);\n return;\n }\n\n // When search is active, capture all keys for search\n if (searchActiveRef.current) {\n if (key.escape) {\n setSearchMode(false);\n return;\n }\n if (key.backspace || key.delete) {\n setSearchQuery((prev) => prev.slice(0, -1));\n setSearchMatchIdx(0);\n return;\n }\n if (key.upArrow) {\n setSearchMatchIdx((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setSearchMatchIdx((prev) => prev + 1); // clamped in render\n return;\n }\n // Printable character\n if (input && input.length === 1 && !key.ctrl && !key.meta) {\n setSearchQuery((prev) => prev + input);\n setSearchMatchIdx(0);\n return;\n }\n return;\n }\n\n // Ctrl+E → toggle expand/collapse for all tool results\n if (key.ctrl && !key.meta && input === \"e\") {\n const curState = stateForInputRef.current;\n const collapsible = curState.entries.filter(\n (e) => e.kind === \"tool_result\" && e.text.length > TOOL_RESULT_COLLAPSE_LEN,\n );\n if (collapsible.length === 0) return;\n setExpandedIds((prev) => {\n const next = new Set(prev);\n const allExpanded = collapsible.every((e) => next.has(e.id));\n if (allExpanded) {\n for (const e of collapsible) next.delete(e.id);\n } else {\n for (const e of collapsible) next.add(e.id);\n }\n return next;\n });\n return;\n }\n\n // Enter → toggle expand/collapse for the most recent thinking entry\n if (key.return && !key.ctrl && !key.meta) {\n const curState = stateForInputRef.current;\n const thinkingEntry = findLast(curState.entries,(e) => e.kind === \"thinking\");\n if (thinkingEntry) {\n setExpandedIds((prev) => {\n const next = new Set(prev);\n if (next.has(thinkingEntry.id)) {\n next.delete(thinkingEntry.id);\n } else {\n next.add(thinkingEntry.id);\n }\n return next;\n });\n return;\n }\n }\n });\n\n useImperativeHandle(\n ref,\n (): ChatLogHandle => ({\n addSystem(text, level) {\n dispatch({ kind: \"ADD_SYSTEM\", text, level });\n },\n addUser(text, pending) {\n dispatch({ kind: \"ADD_USER\", text, pending });\n },\n commitPendingUser() {\n dispatch({ kind: \"COMMIT_PENDING_USER\" });\n },\n dropPendingUser() {\n dispatch({ kind: \"DROP_PENDING_USER\" });\n },\n startAssistant(text) {\n dispatch({ kind: \"START_ASSISTANT\", text });\n },\n updateAssistant(text) {\n dispatch({ kind: \"UPDATE_ASSISTANT\", text });\n },\n finalizeAssistant(text) {\n dispatch({ kind: \"FINALIZE_ASSISTANT\", text });\n },\n dropAssistant() {\n dispatch({ kind: \"DROP_ASSISTANT\" });\n },\n addTool(name, callId) {\n dispatch({ kind: \"ADD_TOOL\", name, callId });\n },\n updateToolResult(callId, result) {\n dispatch({ kind: \"UPDATE_TOOL_RESULT\", callId, result });\n },\n showBtw(text) {\n dispatch({ kind: \"SHOW_BTW\", text });\n },\n dismissBtw() {\n dispatch({ kind: \"DISMISS_BTW\" });\n },\n showThinking(text, durationMs) {\n dispatch({ kind: \"SHOW_THINKING\", text, durationMs });\n },\n dismissThinking() {\n dispatch({ kind: \"DISMISS_THINKING\" });\n },\n clearAll() {\n dispatch({ kind: \"CLEAR_ALL\" });\n },\n getEntryCount() {\n return stateRef.current.entries.length;\n },\n }),\n [],\n );\n\n // Determine which entries to render\n const { entries } = state;\n const windowed = visibleRange\n ? entries.slice(visibleRange.start, visibleRange.end)\n : entries.slice(-MAX_VISIBLE);\n\n if (windowed.length === 0) {\n return React.createElement(\n Box,\n { flexDirection: \"column\", paddingY: 2 },\n // LogoHeader — Lynx brand logo shown on first launch before any messages\n React.createElement(\n Box,\n { flexDirection: \"column\", marginBottom: 1 },\n React.createElement(\n Text,\n { color: theme.colors.accent, bold: true },\n \" ╦ ╦ ═╗ ╦ ═╗ ═╗ ╦\",\n ),\n React.createElement(\n Text,\n { color: theme.colors.accent, bold: true },\n \" ║ ║ ║ ║ ║ ╚╗║\",\n ),\n React.createElement(\n Text,\n { color: theme.colors.accent, bold: true },\n \" ╚═╝ ╩ ═╝ ╩ ═╝ ═╝ ╩\",\n ),\n ),\n React.createElement(\n Text,\n { dimColor: true },\n \" 输入消息开始对话 · /help 查看命令 · Tab 切换模式\",\n ),\n );\n }\n\n // StickyPromptHeader — when scrolled up (not at bottom), show the last user prompt\n const isScrolledUp = visibleRange && visibleRange.end < stateRef.current.entries.length;\n const stickyHeader: React.ReactElement | null = isScrolledUp\n ? React.createElement(\n Box,\n { flexDirection: \"row\", marginBottom: 1 },\n React.createElement(Text, { dimColor: true }, \"↑ 已滚动 · 最后提示: \"),\n React.createElement(\n Text,\n { dimColor: true, bold: true },\n (() => {\n // Find the last user message before the visible range\n for (let i = visibleRange!.end - 1; i >= 0; i--) {\n const entry = stateRef.current.entries[i];\n if (entry?.kind === \"user\") {\n const firstLine = entry.text.split(\"\\n\")[0] ?? \"\";\n return firstLine.length > 60 ? firstLine.slice(0, 57) + \"...\" : firstLine;\n }\n }\n return \"(无)\";\n })(),\n ),\n )\n : null;\n\n // ── Compute search matches ──\n const searchMatches: SearchMatch[] = [];\n if (searchActive && searchQuery) {\n const lower = searchQuery.toLowerCase();\n for (const entry of windowed) {\n let idx = 0;\n const lowerText = entry.text.toLowerCase();\n while ((idx = lowerText.indexOf(lower, idx)) !== -1) {\n searchMatches.push({\n entryId: entry.id,\n start: idx,\n text: entry.text.slice(idx, idx + searchQuery.length),\n });\n idx += lower.length;\n }\n }\n }\n\n // Clamp match index (wraps around on overflow)\n const clampedMatchIdx =\n searchMatches.length > 0\n ? ((searchMatchIdx % searchMatches.length) + searchMatches.length) % searchMatches.length\n : 0;\n\n // Active (highlighted) match entry id\n const activeMatchEntryId =\n searchMatches.length > 0 ? searchMatches[clampedMatchIdx]!.entryId : null;\n\n // ── Render entries ──\n const elements: React.ReactElement[] = [];\n\n for (const entry of windowed) {\n const isExpanded = expandedIds.has(entry.id);\n const entryMatchIndices = searchActive\n ? searchMatches.filter((m) => m.entryId === entry.id).map((m) => m.start)\n : [];\n\n elements.push(\n React.createElement(MessageRow, {\n key: entry.id,\n entry,\n isExpanded,\n transcriptMode,\n searchQuery: searchActive ? searchQuery : \"\",\n matchIndices: entryMatchIndices,\n }),\n );\n }\n\n // ── Search bar ──\n const searchBar = searchActive\n ? React.createElement(\n Box,\n { flexDirection: \"row\", paddingTop: 1 },\n React.createElement(Text, { color: theme.colors.accent, bold: true }, \"🔍 \"),\n React.createElement(\n Text,\n null,\n searchQuery || React.createElement(Text, { dimColor: true }, \"输入搜索内容\"),\n ),\n React.createElement(Text, { dimColor: true }, \"█\"),\n searchMatches.length > 0\n ? React.createElement(\n Text,\n { dimColor: true },\n ` ${clampedMatchIdx + 1}/${searchMatches.length}`,\n )\n : searchQuery\n ? React.createElement(Text, { dimColor: true }, \" 无匹配\")\n : React.createElement(Text, { dimColor: true }, \" Esc 关闭\"),\n )\n : null;\n\n return React.createElement(\n Box,\n { flexDirection: \"column\" },\n stickyHeader,\n ...elements,\n searchBar,\n );\n});\n\n// ── Search types ──────────────────────────────────\n\ninterface SearchMatch {\n entryId: string;\n start: number;\n text: string;\n}\n","/**\n * FrameRateLimiter — throttle Ink re‑renders to ~30 FPS via microtask batching.\n *\n * Ink renders on every state change. For high‑frequency updates (streaming\n * text deltas, tool output), this can cause excessive re‑renders.\n * FrameRateLimiter coalesces state updates within a 16 ms window.\n *\n * Design (§5.9i):\n * - 30 fps throttle (~33 ms frame budget, 16 ms coalesce window)\n * - In‑memory transcript cache for static entries\n * - React.memo on static message blocks\n */\n\n/** Default target frame interval in ms (30 fps ≈ 33 ms). */\nconst DEFAULT_FRAME_MS = 33;\n\n/**\n * Simple frame‑rate limiter.\n *\n * Uses a pending flag and microtask scheduling to ensure\n * callbacks fire at most once per `frameMs` window.\n */\nexport class FrameRateLimiter {\n private lastFrame = 0;\n private pending = false;\n private readonly frameMs: number;\n\n constructor(frameMs: number = DEFAULT_FRAME_MS) {\n this.frameMs = frameMs;\n }\n\n /**\n * Schedule a callback to run on the next available frame.\n *\n * If a callback was already scheduled within the current frame window,\n * the new callback replaces it (last‑writer‑wins semantics).\n */\n schedule(fn: () => void): void {\n const now = Date.now();\n const elapsed = now - this.lastFrame;\n\n if (elapsed >= this.frameMs) {\n // Enough time has passed — run immediately\n this.lastFrame = now;\n this.pending = false;\n fn();\n } else if (!this.pending) {\n // Schedule for the remaining time in the frame\n this.pending = true;\n const delay = this.frameMs - elapsed;\n setTimeout(() => {\n this.lastFrame = Date.now();\n this.pending = false;\n fn();\n }, delay);\n }\n // else: already pending — drop (last‑writer‑wins would need a stored callback)\n }\n\n /** Reset the limiter state. */\n reset(): void {\n this.lastFrame = 0;\n this.pending = false;\n }\n}\n\n/**\n * Create a transcript cache key for stable React.memo comparison.\n *\n * Static messages (non‑streaming, non‑pending) can be memoized\n * since their rendered output never changes.\n */\nexport function transcriptCacheKey(\n entryId: string,\n isStreaming: boolean,\n isPending: boolean,\n): string {\n if (isStreaming || isPending) return `${entryId}:dynamic`;\n return `${entryId}:static`;\n}\n\n/**\n * Default frame rate limiter instance for transcript rendering.\n *\n * Created once per ChatLog mount to throttle streaming updates.\n */\nexport function createFrameRateLimiter(frameMs?: number): FrameRateLimiter {\n return new FrameRateLimiter(frameMs);\n}\n","/**\n * VimStatusBar — 显示当前 Vim 模式和按键提示。\n * 从 InputBox 提取出的独立子组件。\n */\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\n\n/** Props for VimStatusBar — whether Vim is enabled and the current editing mode. */\nexport interface VimStatusBarProps {\n vimEnabled: boolean;\n /** Vim 编辑模式(insert / normal / visual) */\n vimMode: string;\n}\n\n/** Displays current Vim mode label with color coding — hidden when vimEnabled is false. */\nexport function VimStatusBar({\n vimEnabled,\n vimMode,\n}: VimStatusBarProps): React.ReactElement | null {\n if (!vimEnabled) return null;\n const label =\n vimMode === \"insert\" ? \"-- 插入 --\" : vimMode === \"normal\" ? \"-- 普通 --\" : \"-- 可视 --\";\n const color = vimMode === \"insert\" ? \"green\" : vimMode === \"normal\" ? \"yellow\" : \"cyan\";\n return React.createElement(Box, {}, React.createElement(Text, { color }, label));\n}\n","/**\n * SuggestionsOverlay — 自动补全浮层。\n * 绝对定位在输入框上方,显示匹配的补全选项列表。\n * 从 InputBox 提取出的独立子组件。\n */\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\n\n/** Props for SuggestionsOverlay — the list of completions and currently selected index. */\nexport interface SuggestionsOverlayProps {\n completions: string[];\n completionIndex: number;\n}\n\n/** Autocomplete overlay — absolutely positioned above the input box with highlighted options. */\nexport function SuggestionsOverlay({\n completions,\n completionIndex,\n}: SuggestionsOverlayProps): React.ReactElement | null {\n if (completions.length === 0) return null;\n return React.createElement(\n Box,\n { flexDirection: \"column\" },\n ...completions.map((item, index) =>\n React.createElement(\n Box,\n { key: item },\n React.createElement(\n Text,\n {\n color: index === completionIndex ? \"cyan\" : undefined,\n inverse: index === completionIndex,\n },\n `${index === completionIndex ? \"> \" : \" \"}${item}`,\n ),\n ),\n ),\n );\n}\n","/**\n * InputFooter — 输入区域底部状态行。\n * 显示 Vim 模式、输入值预览、禁用状态。\n * 从 InputBox 提取出的独立子组件。\n */\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\n\n/** Props for InputFooter — vim mode indicator, current value, and disabled state. */\nexport interface InputFooterProps {\n vimEnabled: boolean;\n vimMode: string;\n value: string;\n disabled: boolean;\n}\n\n/** Input area bottom status line — shows Vim mode, char count, or disabled state. */\nexport function InputFooter({\n vimEnabled,\n vimMode,\n value,\n disabled,\n}: InputFooterProps): React.ReactElement {\n const children: React.ReactNode[] = [];\n if (vimEnabled) {\n children.push(React.createElement(Text, { key: \"vim\", dimColor: true }, vimMode));\n }\n if (disabled) {\n children.push(React.createElement(Text, { key: \"disabled\", color: \"red\" }, \" 输入已禁用\"));\n }\n if (!disabled && value.length > 0) {\n children.push(\n React.createElement(Text, { key: \"count\", dimColor: true }, ` ${value.length} 字符`),\n );\n }\n return React.createElement(Box, {}, ...children);\n}\n","/**\n * Input history persistence — load/save to ~/.lynx/input-history.json.\n *\n * Best-effort I/O: failures are silently swallowed so the REPL\n * never crashes because of a disk error.\n */\n\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\n\n/** Max history entries kept in memory and on disk. */\nexport const MAX_HISTORY = 200;\n\n/** Path to the persisted input history file. */\nexport const HISTORY_FILE = join(homedir(), \".lynx\", \"input-history.json\");\n\n/** Load persisted input history from disk. Returns empty array on any error. */\nexport function loadPersistedHistory(): string[] {\n try {\n if (!existsSync(HISTORY_FILE)) return [];\n const raw = readFileSync(HISTORY_FILE, \"utf-8\");\n const parsed: unknown = JSON.parse(raw);\n if (Array.isArray(parsed) && parsed.every((e) => typeof e === \"string\")) {\n return parsed.slice(-MAX_HISTORY);\n }\n return [];\n } catch {\n return [];\n }\n}\n\n/** Save input history to disk. Does not throw on failure. */\nexport function savePersistedHistory(history: string[]): void {\n try {\n const dir = dirname(HISTORY_FILE);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(HISTORY_FILE, JSON.stringify(history.slice(-MAX_HISTORY)), \"utf-8\");\n } catch {\n // Best effort — don't crash if write fails\n }\n}\n","/**\n * Input completion matching — slash commands and @‑mention triggers.\n */\n\n/** Built‑in slash commands for autocomplete. */\nconst SLASH_COMMANDS: string[] = [\n \"/sessions\",\n \"/new\",\n \"/fork\",\n \"/rename\",\n \"/delete\",\n \"/resume\",\n \"/config\",\n \"/settings\",\n \"/doctor\",\n \"/theme\",\n \"/model\",\n \"/compact\",\n \"/help\",\n \"/mcp\",\n \"/plugin\",\n \"/skills\",\n \"/context\",\n \"/usage\",\n \"/tasks\",\n \"/snapshots\",\n \"/stash\",\n \"/diff\",\n];\n\n/** Match slash commands against a prefix string. */\nexport function matchCompletions(prefix: string): string[] {\n if (!prefix.startsWith(\"/\")) return [];\n const lower = prefix.toLowerCase();\n return SLASH_COMMANDS.filter((cmd) => cmd.toLowerCase().startsWith(lower)).slice(0, 8);\n}\n\n/**\n * Find the `@` trigger position preceding the cursor.\n *\n * Returns the index of `@` in the value, or -1 if no trigger is active.\n * The trigger is only valid if `@` appears at the start of a word\n * (preceded by whitespace or start-of-string).\n */\nexport function findAtTrigger(value: string, cursor: number): number {\n for (let i = cursor - 1; i >= 0; i--) {\n const ch = value[i];\n if (ch === \"@\") {\n if (i === 0 || /\\s/.test(value[i - 1]!)) return i;\n return -1;\n }\n if (/\\s/.test(ch!)) return -1;\n }\n return -1;\n}\n\n/** Determine how to route submitted input. */\nexport function routeInput(text: string): \"shell\" | \"command\" | \"chat\" {\n if (text.startsWith(\"!\")) return \"shell\";\n if (text.startsWith(\"/\")) return \"command\";\n return \"chat\";\n}\n","/**\n * @‑mention file path autocomplete helpers.\n *\n * Walks the workspace to collect file candidates, then filters\n * by the trigger text typed after `@`.\n */\n\nimport { readdirSync, statSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\n\n/** Max autocomplete suggestions displayed. */\nconst MAX_COMPLETIONS = 8;\n\n/**\n * Recursively list files in a directory, relative to the workspace root.\n * Returns at most `maxResults` entries. Directories are suffixed with `/`.\n */\nexport function listFilesRecursive(dir: string, workspace: string, maxResults: number): string[] {\n const results: string[] = [];\n const stack: string[] = [dir];\n\n while (stack.length > 0 && results.length < maxResults) {\n const current = stack.pop()!;\n let entries: string[];\n try {\n entries = readdirSync(current);\n } catch {\n continue; // skip unreadable directories\n }\n\n for (const name of entries) {\n if (results.length >= maxResults) break;\n if (name.startsWith(\".\") || name === \"node_modules\") continue;\n\n const fullPath = join(current, name);\n let entryStat;\n try {\n entryStat = statSync(fullPath);\n } catch {\n continue;\n }\n\n const relativePath = relative(workspace, fullPath).replace(/\\\\/g, \"/\");\n if (entryStat.isDirectory()) {\n results.push(relativePath + \"/\");\n stack.push(fullPath);\n } else {\n results.push(relativePath);\n }\n }\n }\n\n return results.sort((a, b) => a.length - b.length);\n}\n\n/**\n * Match file paths for @‑mention autocomplete.\n *\n * `trigger` is the text after `@` (e.g., `\"src/in\"`).\n * Returns matching file paths (prefixed with `@`) relative to the workspace,\n * up to `MAX_COMPLETIONS` entries.\n */\nexport function matchFileCompletions(trigger: string, workspace: string): string[] {\n if (trigger == null) return []; // trigger is null/undefined — no @-mention to autocomplete\n\n const normalized = trigger.replace(/\\\\/g, \"/\");\n const lastSlash = normalized.lastIndexOf(\"/\");\n const searchDir = lastSlash >= 0 ? join(workspace, normalized.slice(0, lastSlash)) : workspace;\n const prefix = lastSlash >= 0 ? normalized.slice(lastSlash + 1) : normalized;\n\n const allFiles = listFilesRecursive(searchDir, workspace, 200);\n const lowerPrefix = prefix.toLowerCase();\n\n return allFiles\n .filter((f) => f.toLowerCase().startsWith(lowerPrefix) || f.toLowerCase().includes(lowerPrefix))\n .slice(0, MAX_COMPLETIONS)\n .map((f) => \"@\" + f);\n}\n","/**\n * Input keyboard handlers — pure functions that translate key events\n * into state mutations via the Ctx (context) object.\n *\n * Extracted from InputBox to keep the component under 500 lines.\n */\n\nimport type { Key } from \"ink\";\nimport { matchCompletions, findAtTrigger } from \"./input-completions.js\";\nimport { matchFileCompletions } from \"./file-completions.js\";\n\n// ── Ctx — mutable state handle passed to each handler ──\n\n/** Mutable state handle passed to each keyboard handler — mirrors InputBox's state setters. */\nexport interface KeyboardCtx {\n value: string;\n cursor: number;\n completions: string[];\n completionIndex: number;\n completionStart: number;\n setValue: (updater: string | ((prev: string) => string)) => void;\n setCursor: (updater: number | ((prev: number) => number)) => void;\n setCompletions: (updater: string[] | ((prev: string[]) => string[])) => void;\n setCompletionIndex: (updater: number | ((prev: number) => number)) => void;\n setCompletionStart: (updater: number | ((prev: number) => number)) => void;\n historyRef: { current: string[] };\n historyIndexRef: { current: number };\n savedDraftRef: { current: string };\n}\n\n/** Callbacks the keyboard handlers need from the parent component. */\nexport interface KeyboardActions {\n /** Submit text to the chat. */\n submitText: (text: string) => void;\n /** Signal an abort (Ctrl+C). */\n onAbort: () => void;\n}\n\n// ── Handlers ────────────────────────────────────────────\n\n/** Handle Enter / Ctrl+C / Ctrl+Enter. Returns true if consumed. */\nexport function handleSubmit(\n input: string,\n key: Key,\n ctx: KeyboardCtx,\n actions: KeyboardActions,\n): boolean {\n if (key.ctrl && input === \"c\") {\n actions.onAbort();\n return true;\n }\n // Ctrl+Enter → insert newline\n if (key.return && key.ctrl) {\n const newValue = ctx.value.slice(0, ctx.cursor) + \"\\n\" + ctx.value.slice(ctx.cursor);\n ctx.setValue(newValue);\n ctx.setCursor(ctx.cursor + 1);\n ctx.setCompletions([]);\n ctx.setCompletionStart(-1);\n return true;\n }\n // Bare Enter → submit\n if (key.return) {\n const trimmed = ctx.value.trim();\n if (trimmed) {\n if (ctx.completions.length > 0 && ctx.completionIndex < ctx.completions.length) {\n const selected = ctx.completions[ctx.completionIndex]!;\n if (ctx.completionStart >= 0 && ctx.completionStart < ctx.value.length) {\n const before = ctx.value.slice(0, ctx.completionStart);\n const after = ctx.value.slice(ctx.cursor);\n ctx.setValue(before + selected + after);\n ctx.setCursor(ctx.completionStart + selected.length);\n } else {\n ctx.setValue(selected);\n ctx.setCursor(selected.length);\n }\n ctx.setCompletions([]);\n ctx.setCompletionIndex(0);\n ctx.setCompletionStart(-1);\n return true;\n }\n actions.submitText(trimmed);\n }\n return true;\n }\n return false;\n}\n\n/** Handle Tab / Shift+Tab / Escape for completions. */\nexport function handleCompletionKeys(_input: string, key: Key, ctx: KeyboardCtx): boolean {\n // Shift+Tab → cycle completions backwards\n if (key.tab && key.shift && ctx.completions.length > 0) {\n ctx.setCompletionIndex(\n (ctx.completionIndex - 1 + ctx.completions.length) % ctx.completions.length,\n );\n return true;\n }\n if (key.tab && ctx.completions.length > 0) {\n const selected = ctx.completions[ctx.completionIndex]!;\n if (ctx.completionStart >= 0 && ctx.completionStart < ctx.value.length) {\n const before = ctx.value.slice(0, ctx.completionStart);\n const after = ctx.value.slice(ctx.cursor);\n ctx.setValue(before + selected + after);\n ctx.setCursor(ctx.completionStart + selected.length);\n } else {\n ctx.setValue(selected);\n ctx.setCursor(selected.length);\n }\n ctx.setCompletions([]);\n ctx.setCompletionIndex(0);\n ctx.setCompletionStart(-1);\n return true;\n }\n if (key.escape) {\n ctx.setCompletions([]);\n ctx.setCompletionIndex(0);\n ctx.setCompletionStart(-1);\n return true;\n }\n return false;\n}\n\n/** Handle Up/Down arrow for history and completion navigation. */\nexport function handleHistoryKeys(key: Key, ctx: KeyboardCtx): boolean {\n if (key.upArrow) {\n if (ctx.completions.length > 0) {\n ctx.setCompletionIndex(Math.max(0, ctx.completionIndex - 1));\n return true;\n }\n const hist = ctx.historyRef.current;\n if (hist.length === 0) return true;\n if (ctx.historyIndexRef.current === -1) {\n ctx.savedDraftRef.current = ctx.value;\n }\n const nextIdx = ctx.historyIndexRef.current + 1;\n if (nextIdx < hist.length) {\n ctx.historyIndexRef.current = nextIdx;\n const entry = hist[hist.length - 1 - nextIdx]!;\n ctx.setValue(entry);\n ctx.setCursor(entry.length);\n }\n return true;\n }\n if (key.downArrow) {\n if (ctx.completions.length > 0) {\n ctx.setCompletionIndex(Math.min(ctx.completions.length - 1, ctx.completionIndex + 1));\n return true;\n }\n if (ctx.historyIndexRef.current > 0) {\n ctx.historyIndexRef.current--;\n const hist = ctx.historyRef.current;\n const entry = hist[hist.length - 1 - ctx.historyIndexRef.current]!;\n ctx.setValue(entry);\n ctx.setCursor(entry.length);\n } else if (ctx.historyIndexRef.current === 0) {\n ctx.historyIndexRef.current = -1;\n ctx.setValue(ctx.savedDraftRef.current);\n ctx.setCursor(ctx.savedDraftRef.current.length);\n }\n return true;\n }\n return false;\n}\n\n/** Handle Left/Right arrows, Home/End, Ctrl+A/E. */\nexport function handleNavigationKeys(input: string, key: Key, ctx: KeyboardCtx): boolean {\n if (handleHistoryKeys(key, ctx)) return true;\n\n if (key.leftArrow) {\n ctx.setCursor(Math.max(0, ctx.cursor - 1));\n return true;\n }\n if (key.rightArrow) {\n ctx.setCursor(Math.min(ctx.value.length, ctx.cursor + 1));\n return true;\n }\n if (key.home || (key.ctrl && input === \"a\")) {\n ctx.setCursor(0);\n return true;\n }\n if (key.end || (key.ctrl && input === \"e\")) {\n ctx.setCursor(ctx.value.length);\n return true;\n }\n return false;\n}\n\n/** Handle Ctrl+W/K/U and Backspace/Delete. */\nexport function handleEditKeys(_input: string, key: Key, ctx: KeyboardCtx): boolean {\n if (key.ctrl && _input === \"w\") {\n ctx.setValue((prev) => {\n const before = prev.slice(0, ctx.cursor);\n const after = prev.slice(ctx.cursor);\n const wordEnd = before.replace(/\\s*\\S+$/, \"\");\n const deleted = before.length - wordEnd.length;\n ctx.setCursor((c) => c - deleted);\n return wordEnd + after;\n });\n return true;\n }\n\n if (key.ctrl && _input === \"k\") {\n ctx.setValue((prev) => prev.slice(0, ctx.cursor));\n return true;\n }\n\n if (key.ctrl && _input === \"u\") {\n ctx.setValue((prev) => prev.slice(ctx.cursor));\n ctx.setCursor(0);\n return true;\n }\n\n if (key.backspace || key.delete) {\n if (ctx.cursor > 0) {\n ctx.setValue((prev) => prev.slice(0, ctx.cursor - 1) + prev.slice(ctx.cursor));\n ctx.setCursor((c) => c - 1);\n }\n return true;\n }\n\n return false;\n}\n\n/** Handle printable text input and trigger completions. */\nexport function handleTextInput(\n input: string,\n key: Key,\n ctx: KeyboardCtx,\n workspace: string,\n): boolean {\n if (input && !key.ctrl && !key.meta && input.length > 0) {\n if (/^[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]$/.test(input)) return false;\n\n ctx.setValue((prev) => prev.slice(0, ctx.cursor) + input + prev.slice(ctx.cursor));\n ctx.setCursor((c) => c + input.length);\n\n const newVal = ctx.value.slice(0, ctx.cursor) + input + ctx.value.slice(ctx.cursor);\n const newCursor = ctx.cursor + input.length;\n\n // Slash command autocomplete (value starts with /)\n if (newVal.startsWith(\"/\")) {\n const matches = matchCompletions(newVal);\n ctx.setCompletions(matches);\n ctx.setCompletionIndex(0);\n ctx.setCompletionStart(0);\n return true;\n }\n\n // @‑mention file autocomplete\n const atIdx = findAtTrigger(newVal, newCursor);\n if (atIdx >= 0) {\n const trigger = newVal.slice(atIdx + 1, newCursor);\n if (trigger !== undefined) {\n const matches = matchFileCompletions(trigger, workspace);\n ctx.setCompletions(matches);\n ctx.setCompletionIndex(0);\n ctx.setCompletionStart(atIdx);\n return true;\n }\n }\n\n ctx.setCompletions([]);\n ctx.setCompletionStart(-1);\n return true;\n }\n return false;\n}\n","/**\n * useVimInput — Vim-style editing hooks for the multi‑line input.\n *\n * Provides normal‑mode navigation (hjkl/w/b/0/$/i/a/I/A/o/O/x/dd/v)\n * and visual‑mode selection (hjkl/y/d) callbacks.\n */\n\nimport { useCallback } from \"react\";\nimport type { Key } from \"ink\";\nimport type { VimMode } from \"../InputBox.js\";\n\n/** Callbacks the Vim hooks need from the parent. */\nexport interface VimActions {\n setValue: (updater: string | ((prev: string) => string)) => void;\n setCursor: (updater: number | ((prev: number) => number)) => void;\n setVimMode: (mode: VimMode) => void;\n setVisualAnchor: (anchor: number) => void;\n /** Notify parent of mode change. */\n onVimModeChange?: (mode: VimMode) => void;\n}\n\n/**\n * Create a NORMAL‑mode key handler.\n *\n * Returns a function `(input: string, key: Key) => boolean` that the parent\n * calls within its useInkInput dispatch when `vimMode === \"normal\"`.\n */\nexport function useVimNormalHandler(\n value: string,\n cursor: number,\n actions: VimActions,\n): (input: string, key: Key) => boolean {\n return useCallback(\n (input: string, key: Key): boolean => {\n // hjkl movement\n if (input === \"h\") {\n actions.setCursor((c) => Math.max(0, c - 1));\n return true;\n }\n if (input === \"l\") {\n actions.setCursor((c) => Math.min(value.length, c + 1));\n return true;\n }\n if (input === \"k\") {\n const before = value.slice(0, cursor);\n const prevNewline = before.lastIndexOf(\"\\n\");\n if (prevNewline === -1) {\n actions.setCursor(0);\n return true;\n }\n const prevPrevNewline = before.lastIndexOf(\"\\n\", prevNewline - 1);\n const col = before.length - prevNewline - 1;\n const targetCol = Math.min(col, prevNewline - (prevPrevNewline + 1));\n actions.setCursor((prevPrevNewline === -1 ? 0 : prevPrevNewline + 1) + targetCol);\n return true;\n }\n if (input === \"j\") {\n const after = value.slice(cursor);\n const nextNewline = after.indexOf(\"\\n\");\n if (nextNewline === -1) {\n actions.setCursor(value.length);\n return true;\n }\n const col = cursor - (value.slice(0, cursor).lastIndexOf(\"\\n\") + 1);\n const afterNext = after.indexOf(\"\\n\", nextNewline + 1);\n const lineLen =\n afterNext === -1 ? after.length - nextNewline - 1 : afterNext - nextNewline - 1;\n actions.setCursor(cursor + nextNewline + 1 + Math.min(col, lineLen));\n return true;\n }\n // Enter insert mode\n if (input === \"i\") {\n actions.setVimMode(\"insert\");\n actions.onVimModeChange?.(\"insert\");\n return true;\n }\n if (input === \"a\") {\n actions.setCursor((c) => Math.min(value.length, c + 1));\n actions.setVimMode(\"insert\");\n actions.onVimModeChange?.(\"insert\");\n return true;\n }\n if (input === \"I\") {\n const before = value.slice(0, cursor);\n const lineStart = before.lastIndexOf(\"\\n\") + 1;\n actions.setCursor(lineStart);\n actions.setVimMode(\"insert\");\n actions.onVimModeChange?.(\"insert\");\n return true;\n }\n if (input === \"A\") {\n const after = value.slice(cursor);\n const nextNewline = after.indexOf(\"\\n\");\n actions.setCursor(cursor + (nextNewline === -1 ? after.length : nextNewline));\n actions.setVimMode(\"insert\");\n actions.onVimModeChange?.(\"insert\");\n return true;\n }\n if (input === \"o\") {\n const after = value.slice(cursor);\n const nextNewline = after.indexOf(\"\\n\");\n const lineEnd = cursor + (nextNewline === -1 ? after.length : nextNewline);\n actions.setValue((v) => v.slice(0, lineEnd) + \"\\n\" + v.slice(lineEnd));\n actions.setCursor(lineEnd + 1);\n actions.setVimMode(\"insert\");\n actions.onVimModeChange?.(\"insert\");\n return true;\n }\n if (input === \"O\") {\n const before = value.slice(0, cursor);\n const lineStart = before.lastIndexOf(\"\\n\") + 1;\n actions.setValue((v) => v.slice(0, lineStart) + \"\\n\" + v.slice(lineStart));\n actions.setCursor(lineStart);\n actions.setVimMode(\"insert\");\n actions.onVimModeChange?.(\"insert\");\n return true;\n }\n // Delete operations\n if (input === \"x\") {\n actions.setValue((v) => v.slice(0, cursor) + v.slice(cursor + 1));\n if (cursor >= value.length) actions.setCursor((c) => Math.max(0, c - 1));\n return true;\n }\n // dd: delete line — handled via pending key tracking by the parent\n if (input === \"d\" && !key.ctrl) {\n return true;\n }\n // Visual mode\n if (input === \"v\") {\n actions.setVisualAnchor(cursor);\n actions.setVimMode(\"visual\");\n actions.onVimModeChange?.(\"visual\");\n return true;\n }\n // w/b word movement\n if (input === \"w\") {\n const rest = value.slice(cursor);\n const match = rest.match(/[^\\s\\w]*\\w+/);\n if (match) actions.setCursor(cursor + (match.index ?? 0) + match[0].length);\n else actions.setCursor(value.length);\n return true;\n }\n if (input === \"b\") {\n const before = value.slice(0, cursor);\n const match = before.match(/(\\w+)\\W*$/);\n if (match) actions.setCursor(cursor - match[0].length + match[1]!.length);\n else actions.setCursor(before.lastIndexOf(\" \") + 1);\n return true;\n }\n // 0/$ line movement\n if (input === \"0\") {\n actions.setCursor((c) => c - (c - value.slice(0, c).lastIndexOf(\"\\n\") - 1));\n return true;\n }\n return false;\n },\n [value, cursor, actions],\n );\n}\n\n/**\n * Create a VISUAL‑mode key handler.\n *\n * Returns a function `(input: string, key: Key) => boolean` for use\n * when `vimMode === \"visual\"`.\n */\nexport function useVimVisualHandler(\n value: string,\n cursor: number,\n visualAnchor: number,\n actions: VimActions,\n): (input: string, key: Key) => boolean {\n return useCallback(\n (input: string, key: Key): boolean => {\n if (key.escape) {\n actions.setVimMode(\"normal\");\n actions.onVimModeChange?.(\"normal\");\n actions.setVisualAnchor(-1);\n if (visualAnchor >= 0 && visualAnchor < cursor) actions.setCursor(visualAnchor);\n return true;\n }\n // hjkl movement (extends selection)\n if (input === \"h\") {\n actions.setCursor((c) => Math.max(0, c - 1));\n return true;\n }\n if (input === \"l\") {\n actions.setCursor((c) => Math.min(value.length, c + 1));\n return true;\n }\n if (input === \"j\") {\n const after = value.slice(cursor);\n const nextNewline = after.indexOf(\"\\n\");\n if (nextNewline === -1) {\n actions.setCursor(value.length);\n return true;\n }\n actions.setCursor(cursor + nextNewline + 1);\n return true;\n }\n if (input === \"k\") {\n const before = value.slice(0, cursor);\n const prevNewline = before.lastIndexOf(\"\\n\");\n if (prevNewline !== -1) {\n const prevPrev = before.lastIndexOf(\"\\n\", prevNewline - 1);\n actions.setCursor(prevPrev === -1 ? 0 : prevPrev + 1);\n }\n return true;\n }\n // y: yank selection (copy to clipboard — best effort)\n if (input === \"y\") {\n actions.setVimMode(\"normal\");\n actions.onVimModeChange?.(\"normal\");\n actions.setVisualAnchor(-1);\n return true;\n }\n // d: delete selected text\n if (input === \"d\") {\n const start = Math.min(visualAnchor, cursor);\n const end = Math.max(visualAnchor, cursor);\n actions.setValue((v) => v.slice(0, start) + v.slice(end));\n actions.setCursor(start);\n actions.setVimMode(\"normal\");\n actions.onVimModeChange?.(\"normal\");\n actions.setVisualAnchor(-1);\n return true;\n }\n return false;\n },\n [value, cursor, visualAnchor, actions],\n );\n}\n","/**\n * InputBox — multi‑line REPL input with history, autocomplete, and routing.\n *\n * Features:\n * - Multi‑line input (Enter submits, Ctrl+Enter inserts newline)\n * - History navigation (Up/Down, 200 items, deduped, persisted to disk)\n * - Slash command autocomplete (8 suggestions max)\n * - @‑mention file path autocomplete (8 suggestions max)\n * - Submit routing: !bang → shell, / → command, text → message\n * - Full cursor movement: Home/End, Ctrl+A/E/K/W, ←/→\n * - 3‑layer abort counter (tracked in parent)\n *\n * Keyboard handlers extracted to input/input-keyboard.ts.\n * File completion extracted to input/file-completions.ts.\n * History persistence extracted to input/input-history.ts.\n * Vim hooks extracted to input/useVimInput.ts.\n */\n\nimport React, { useState, useRef, useCallback, useEffect } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\nimport { VimStatusBar } from \"./VimStatusBar.js\";\nimport { SuggestionsOverlay } from \"./SuggestionsOverlay.js\";\nimport { InputFooter } from \"./InputFooter.js\";\nimport { loadPersistedHistory, savePersistedHistory, MAX_HISTORY } from \"./input/input-history.js\";\nimport {\n handleSubmit,\n handleCompletionKeys,\n handleNavigationKeys,\n handleEditKeys,\n handleTextInput,\n type KeyboardCtx,\n type KeyboardActions,\n} from \"./input/input-keyboard.js\";\nimport { useVimNormalHandler, useVimVisualHandler, type VimActions } from \"./input/useVimInput.js\";\n\n// ── Constants ──────────────────────────────────\n\nconst MAX_VISIBLE_LINES = 5;\n\n// ── Props ──────────────────────────────────────\n\n/** Vim editing mode. */\nexport type VimMode = \"insert\" | \"normal\" | \"visual\";\n\n/** Props for InputBox — multi-line REPL input with history, autocomplete, and Vim support. */\nexport interface InputBoxProps {\n /** Called when the user submits text. */\n onSubmit: (text: string) => void;\n /** Called on each Ctrl+C press (parent tracks abort count). */\n onAbort: () => void;\n /** Whether input is disabled (e.g. during streaming). */\n disabled: boolean;\n /** Placeholder text shown when input is empty. */\n placeholder?: string;\n /** Called when the user presses Ctrl+S to stash the current input. */\n onStash?: (text: string) => void;\n /** Text to append at cursor position (from FilePicker, @-mention, etc.). */\n appendText?: string;\n /** Called when appendText has been consumed. */\n onAppendTextConsumed?: () => void;\n /** Workspace directory for @‑mention file autocomplete. */\n workspace?: string;\n /** Enable Vim editing mode. */\n vimEnabled?: boolean;\n /** Current Vim mode (for external control). */\n vimMode?: VimMode;\n /** Called when Vim mode changes. */\n onVimModeChange?: (mode: VimMode) => void;\n}\n\n// ── Component ──────────────────────────────────\n\n/** Multi-line REPL input — handles submit routing, history, completions, and Vim editing mode. */\nexport function InputBox({\n onSubmit,\n onAbort,\n disabled,\n placeholder = \"输入消息...\",\n onStash,\n appendText,\n onAppendTextConsumed,\n workspace = process.cwd(),\n vimEnabled = false,\n vimMode: initialVimMode = \"insert\",\n onVimModeChange,\n}: InputBoxProps): React.ReactElement {\n const theme = getTheme();\n\n // ── State ──────────────────────────────────\n\n const [value, setValue] = useState(\"\");\n const [cursor, setCursor] = useState(0);\n const [completions, setCompletions] = useState<string[]>([]);\n const [completionIndex, setCompletionIndex] = useState(0);\n /** Cursor position where the active completion trigger began (-1 = no trigger). */\n const [completionStart, setCompletionStart] = useState(-1);\n\n // Vim mode state\n const [vimMode, setVimMode] = useState<VimMode>(initialVimMode);\n const [visualAnchor, setVisualAnchor] = useState(-1);\n\n // History (loaded from persisted storage on mount)\n const historyRef = useRef<string[]>(loadPersistedHistory());\n const historyIndexRef = useRef(-1);\n const savedDraftRef = useRef(\"\");\n\n // Burst coalescer (merge rapid Enter presses)\n const burstBufferRef = useRef<string[]>([]);\n const burstTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // ── Burst submit ────────────────────────────\n\n const flushBurst = useCallback(() => {\n if (burstTimerRef.current) {\n clearTimeout(burstTimerRef.current);\n burstTimerRef.current = null;\n }\n const lines = burstBufferRef.current;\n burstBufferRef.current = [];\n if (lines.length === 0) return;\n\n if (lines.length === 1) {\n onSubmit(lines[0]!);\n } else {\n onSubmit(lines.join(\"\\n\"));\n }\n }, [onSubmit]);\n\n const submitText = useCallback(\n (text: string) => {\n const hist = historyRef.current;\n if (hist.length === 0 || hist[hist.length - 1] !== text) {\n hist.push(text);\n if (hist.length > MAX_HISTORY) hist.shift();\n }\n historyIndexRef.current = -1;\n\n onSubmit(text);\n\n setValue(\"\");\n setCursor(0);\n setCompletions([]);\n setCompletionIndex(0);\n setCompletionStart(-1);\n\n savePersistedHistory(hist);\n },\n [onSubmit],\n );\n\n // ── Vim hooks ──────────────────────────────\n\n const vimActions: VimActions = {\n setValue,\n setCursor,\n setVimMode,\n setVisualAnchor,\n onVimModeChange,\n };\n\n const handleVimNormal = useVimNormalHandler(value, cursor, vimActions);\n const handleVimVisual = useVimVisualHandler(value, cursor, visualAnchor, vimActions);\n\n // ── Append text from external sources ───────\n\n useEffect(() => {\n if (appendText && appendText.length > 0) {\n setValue((prev) => prev.slice(0, cursor) + appendText + prev.slice(cursor));\n setCursor((c) => c + appendText.length);\n onAppendTextConsumed?.();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [appendText]);\n\n // ── Keyboard actions ───────────────────────\n\n const keyboardActions: KeyboardActions = { submitText, onAbort };\n\n // ── Main keyboard handler ──────────────────\n\n useInkInput((input: string, key: Key) => {\n if (disabled) return;\n\n // Filter out terminal mouse SGR escape sequences\n if (input.includes(\"\\x1b[<\") || /^\\[<\\d+;\\d+;\\d+[Mm]/.test(input.trim())) return;\n\n // Ctrl+S → stash current input\n if (key.ctrl && input === \"s\") {\n if (value.trim() && onStash) {\n onStash(value);\n }\n return;\n }\n\n // ── Vim mode handling ─────────────────\n if (vimEnabled) {\n if (key.escape) {\n if (vimMode === \"visual\") {\n setVimMode(\"normal\");\n onVimModeChange?.(\"normal\");\n setVisualAnchor(-1);\n return;\n }\n if (vimMode === \"insert\") {\n setVimMode(\"normal\");\n onVimModeChange?.(\"normal\");\n return;\n }\n setCompletions([]);\n return;\n }\n\n if (vimMode === \"normal\") {\n if (handleVimNormal(input, key)) return;\n if (key.return) {\n const trimmed = value.trim();\n if (trimmed) submitText(trimmed);\n return;\n }\n return;\n }\n\n if (vimMode === \"visual\") {\n if (handleVimVisual(input, key)) return;\n return;\n }\n }\n\n const ctx: KeyboardCtx = {\n value,\n cursor,\n completions,\n completionIndex,\n completionStart,\n setValue,\n setCursor,\n setCompletions,\n setCompletionIndex,\n setCompletionStart,\n historyRef,\n historyIndexRef,\n savedDraftRef,\n };\n\n if (handleSubmit(input, key, ctx, keyboardActions)) return;\n if (handleCompletionKeys(input, key, ctx)) return;\n if (handleNavigationKeys(input, key, ctx)) return;\n if (handleEditKeys(input, key, ctx)) return;\n handleTextInput(input, key, ctx, workspace);\n });\n\n // ── Render ──────────────────────────────────\n\n const lines = value.split(\"\\n\");\n const visibleLines = lines.slice(-MAX_VISIBLE_LINES);\n const lineCount = lines.length;\n const hasMore = lineCount > MAX_VISIBLE_LINES;\n const isPlaceholder = value === \"\";\n\n const renderedLines: React.ReactElement[] = [];\n\n if (hasMore) {\n renderedLines.push(\n React.createElement(\n Text,\n { key: \"more\", dimColor: true },\n ` ... (还有 ${lineCount - MAX_VISIBLE_LINES} 行)`,\n ),\n );\n }\n\n for (let i = 0; i < visibleLines.length; i++) {\n const line = visibleLines[i]!;\n const isLast = i === visibleLines.length - 1;\n const prompt = isLast ? \"❯ \" : \" \";\n\n if (isPlaceholder && i === visibleLines.length - 1) {\n renderedLines.push(\n React.createElement(\n Box,\n { key: `line-${i}`, flexDirection: \"row\" },\n React.createElement(Text, { color: theme.colors.accent }, prompt),\n React.createElement(Text, { color: theme.colors.dimmed }, placeholder),\n ),\n );\n } else {\n renderedLines.push(\n React.createElement(\n Box,\n { key: `line-${i}`, flexDirection: \"row\" },\n React.createElement(Text, { color: theme.colors.accent }, prompt),\n renderWithCursor(line, cursor - getCursorOffset(value, i), theme),\n ),\n );\n }\n }\n\n return React.createElement(\n Box,\n { flexDirection: \"column\" },\n React.createElement(VimStatusBar, { vimEnabled, vimMode }),\n React.createElement(\n Box,\n {\n flexDirection: \"column\",\n borderStyle: \"round\",\n borderColor: theme.colors.border,\n paddingX: 1,\n minHeight: 1,\n },\n ...renderedLines,\n ),\n React.createElement(SuggestionsOverlay, { completions, completionIndex }),\n React.createElement(InputFooter, { vimEnabled, vimMode, value, disabled }),\n );\n}\n\n// ── Render helpers ─────────────────────────────\n\n/**\n * Get the cursor offset within a specific line of multi‑line text.\n */\nfunction getCursorOffset(text: string, lineIndex: number): number {\n const lines = text.split(\"\\n\");\n let offset = 0;\n for (let i = 0; i < lineIndex && i < lines.length; i++) {\n offset += lines[i]!.length + 1;\n }\n return offset;\n}\n\n/**\n * Render a line with cursor highlighting (inverse character).\n */\nfunction renderWithCursor(\n line: string,\n cur: number,\n _theme: ReturnType<typeof getTheme>,\n): React.ReactElement {\n const clamped = Math.max(0, Math.min(cur, line.length));\n\n if (clamped >= line.length) {\n return React.createElement(\n Text,\n {},\n React.createElement(Text, {}, line),\n React.createElement(Text, { inverse: true }, \" \"),\n );\n }\n\n return React.createElement(\n Text,\n {},\n React.createElement(Text, {}, line.slice(0, clamped)),\n React.createElement(Text, { inverse: true }, line[clamped] ?? \" \"),\n React.createElement(Text, {}, line.slice(clamped + 1)),\n );\n}\n","/**\n * StatusBar — bottom status line with three‑section layout.\n *\n * Aligned to Claude Code's StatusLine:\n * - Left: mode (insert/normal/abort) + current view\n * - Center: model name + streaming indicator + memory\n * - Right: tokens used / cost / budget bar + IDE status\n *\n * Memory indicator: green (<700MB), yellow (700-900MB),\n * red (>900MB) — mirrors Claude Code's heap sampling thresholds.\n *\n * Design (§5.5a #1.5): three‑section status line with color‑coded metrics.\n */\n\nimport React, { useState, useEffect } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\n\n// ── Props ────────────────────────────────────────────\n\n/** Props for StatusBar — mode, model, metrics, and IDE connection status. */\nexport interface StatusBarProps {\n /** Current mode: \"insert\", \"normal\", \"visual\", or \"abort N/3\". */\n mode: string;\n /** Active model identifier. */\n model: string;\n /** Whether the LLM is currently streaming a response. */\n streaming: boolean;\n /** Active view name (chat, sessions, settings, etc.). */\n viewName: string;\n /** Total tokens consumed in the current session. */\n tokensUsed?: number;\n /** Estimated cost in USD for the current session. */\n costUsd?: number;\n /** Budget maximum USD for color coding. */\n budgetMaxUsd?: number;\n /** Whether IDE integration is connected. */\n ideConnected?: boolean;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** Format a token count as a human-readable string (e.g. \"12.3K\"). */\nfunction formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M`;\n if (tokens >= 1_000) return `${(tokens / 1_000).toFixed(1)}K`;\n return String(tokens);\n}\n\n/** Format a USD cost as a compact string (e.g. \"$0.007\"). */\nfunction formatCost(cost: number): string {\n if (cost >= 1) return `$${cost.toFixed(2)}`;\n if (cost >= 0.01) return `$${cost.toFixed(3)}`;\n return `$${cost.toFixed(4)}`;\n}\n\n/**\n * Color‑code the cost display based on budget ratio.\n * - < 50%: normal (within budget)\n * - 50–80%: warning (approaching limit)\n * - > 80%: error (near budget cap)\n */\nfunction budgetColor(costUsd: number, maxUsd?: number): string | undefined {\n if (maxUsd === undefined || maxUsd <= 0) return undefined;\n const ratio = costUsd / maxUsd;\n if (ratio > 0.8) return \"red\";\n if (ratio > 0.5) return \"yellow\";\n return \"green\";\n}\n\n/** Format bytes as human-readable memory size. */\nfunction formatMemory(bytes: number): string {\n const mb = bytes / (1024 * 1024);\n if (mb >= 1000) return `${(mb / 1024).toFixed(1)}GB`;\n return `${Math.round(mb)}MB`;\n}\n\n/**\n * Memory usage color:\n * - < 700MB: dim (normal)\n * - 700–900MB: warning (yellow)\n * - > 900MB: error (red)\n */\nfunction memoryColor(bytes: number): string {\n const mb = bytes / (1024 * 1024);\n if (mb > 900) return \"red\";\n if (mb > 700) return \"yellow\";\n return \"dim\";\n}\n\n// ── Component ────────────────────────────────────────\n\n/** Bottom status line — three-section layout: left (mode+view), center (model+memory), right (tokens+cost+IDE). */\nexport function StatusBar({\n mode,\n model,\n streaming,\n viewName,\n tokensUsed,\n costUsd,\n budgetMaxUsd,\n ideConnected,\n}: StatusBarProps): React.ReactElement {\n const theme = getTheme();\n const streamIcon = streaming ? \"◉\" : \"○\";\n\n // ── Memory usage (polled while streaming) ─────\n\n const [heapUsed, setHeapUsed] = useState(() => process.memoryUsage().heapUsed);\n\n useEffect(() => {\n if (!streaming) {\n setHeapUsed(process.memoryUsage().heapUsed);\n return;\n }\n const id = setInterval(() => {\n setHeapUsed(process.memoryUsage().heapUsed);\n }, 5000);\n return () => clearInterval(id);\n }, [streaming]);\n\n const memColor = memoryColor(heapUsed);\n const memText = formatMemory(heapUsed);\n\n // ── IDE status ─────────────────────────────────\n\n const ideText = ideConnected ? \"IDE\" : \"\";\n\n // ── Budget bar ─────────────────────────────────\n\n let budgetText = \"\";\n let budgetBarColor: string | undefined;\n if (costUsd !== undefined && costUsd > 0) {\n const color = budgetColor(costUsd, budgetMaxUsd);\n budgetText = formatCost(costUsd);\n budgetBarColor = color;\n }\n\n // ── Render ─────────────────────────────────────\n\n return React.createElement(\n Box,\n {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n paddingX: 1,\n borderStyle: \"single\",\n borderColor: theme.colors.border,\n },\n\n // ── Left section ───────────────────────────\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: theme.colors.accent }, mode),\n React.createElement(Text, { dimColor: true }, viewName),\n ),\n\n // ── Center section ─────────────────────────\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { dimColor: true }, model),\n React.createElement(Text, { color: streaming ? theme.colors.accent : undefined }, streamIcon),\n React.createElement(\n Text,\n { dimColor: true, color: memColor !== \"dim\" ? memColor : undefined },\n memText,\n ),\n ),\n\n // ── Right section ───────────────────────────\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n tokensUsed && tokensUsed > 0\n ? React.createElement(Text, { dimColor: true }, formatTokens(tokensUsed))\n : null,\n budgetText ? React.createElement(Text, { color: budgetBarColor }, budgetText) : null,\n budgetMaxUsd && budgetMaxUsd > 0\n ? React.createElement(Text, { dimColor: true }, `/$${budgetMaxUsd.toFixed(0)}`)\n : null,\n ideText\n ? React.createElement(Text, { dimColor: true, color: theme.colors.accent }, ideText)\n : null,\n ),\n );\n}\n","/**\n * NotificationCenter — single‑line toast bar for transient status messages.\n *\n * Shows between the chat area and the input box. Notifications use a\n * priority‑based queue: only the highest‑priority message is shown, and\n * same‑key notifications replace rather than duplicate.\n *\n * Priority durations:\n * immediate → 5 seconds\n * high → 8 seconds\n * medium → 15 seconds\n * low → 30 seconds\n */\n\nimport React, { useState, useEffect, useCallback, useRef } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\n\n// ── Types ────────────────────────────────────────────\n\n/** Priority level for notification display — determines both color and auto-dismiss duration. */\nexport type NotificationPriority = \"immediate\" | \"high\" | \"medium\" | \"low\";\n\n/** A transient status message — key for dedup, text for display, priority for styling. */\nexport interface Notification {\n /** Stable key for deduplication (e.g. tool name, permission ID). */\n key: string;\n /** Human‑readable message text. */\n text: string;\n /** Priority determines display duration and ordering. */\n priority: NotificationPriority;\n}\n\ninterface QueuedNotification extends Notification {\n id: string;\n createdAt: number;\n}\n\n/** Props for the NotificationCenter renderer — the sorted queue of active notifications. */\nexport interface NotificationCenterProps {\n /** Queue of active notifications (oldest first). */\n notifications: Notification[];\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst PRIORITY_DURATION_MS: Record<NotificationPriority, number> = {\n immediate: 5_000,\n high: 8_000,\n medium: 15_000,\n low: 30_000,\n};\n\nconst PRIORITY_ORDER: Record<NotificationPriority, number> = {\n immediate: 0,\n high: 1,\n medium: 2,\n low: 3,\n};\n\n/** Max notifications to keep in the queue. */\nconst MAX_QUEUE = 50;\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * React hook for managing notification state.\n *\n * Call `push(note)` to add a notification. The hook handles\n * deduplication, expiry, and priority ordering.\n *\n * Returns the currently visible notification and a push function.\n */\nexport function useNotifications(): {\n current: QueuedNotification | null;\n push: (note: Notification) => void;\n} {\n const [queue, setQueue] = useState<QueuedNotification[]>([]);\n const timerRef = useRef<NodeJS.Timeout | null>(null);\n const queueRef = useRef(queue);\n queueRef.current = queue;\n\n /** Remove the top notification and advance to the next one. */\n const advance = useCallback(() => {\n setQueue((prev) => prev.slice(1));\n }, []);\n\n /** Push a notification onto the queue. */\n const push = useCallback((note: Notification) => {\n setQueue((prev) => {\n // Replace existing notification with the same key\n const filtered = prev.filter((n) => n.key !== note.key);\n const entry: QueuedNotification = {\n ...note,\n id: `${note.key}-${Date.now()}`,\n createdAt: Date.now(),\n };\n return [...filtered, entry].slice(-MAX_QUEUE);\n });\n }, []);\n\n // Sort queue by priority then by creation time\n const sorted = [...queue].sort((a, b) => {\n const pa = PRIORITY_ORDER[a.priority];\n const pb = PRIORITY_ORDER[b.priority];\n if (pa !== pb) return pa - pb;\n return a.createdAt - b.createdAt;\n });\n\n const current = sorted[0] ?? null;\n\n // Auto‑expire the current notification after its priority duration\n useEffect(() => {\n if (!current) return;\n\n const duration = PRIORITY_DURATION_MS[current.priority];\n timerRef.current = setTimeout(() => {\n advance();\n }, duration);\n\n return () => {\n if (timerRef.current) clearTimeout(timerRef.current);\n };\n }, [current?.id, advance]);\n\n return { current, push };\n}\n\n// ── Component ────────────────────────────────────────\n\n/** Map priority to an Ink color token. */\nfunction priorityColor(priority: NotificationPriority): string {\n switch (priority) {\n case \"immediate\":\n return \"red\";\n case \"high\":\n return \"yellow\";\n case \"medium\":\n return \"green\";\n case \"low\":\n return \"grey\";\n }\n}\n\n/** Single‑line notification renderer. */\nexport function NotificationCenter({\n current,\n}: {\n current: QueuedNotification | null;\n}): React.ReactElement | null {\n const theme = getTheme();\n\n if (!current) return null;\n\n const color = priorityColor(current.priority);\n\n return React.createElement(\n Box,\n {\n paddingX: 1,\n paddingY: 0,\n borderStyle: \"single\",\n borderColor: color,\n },\n React.createElement(Text, { color, bold: true }, current.text),\n );\n}\n","/**\n * PermissionRequest — modal for approving or denying tool calls.\n *\n * Renders the tool name, safety level badge, description, and parameter\n * summary. Supports 4 permission modes with keyboard shortcuts:\n * A → Allow once, D → Deny, L → Always allow, S → Safe mode\n *\n * Design (§5.9f #3):\n * - Inline in ScrollBox area, not an overlay\n * - Safety badge with color coding\n * - Tab to amend, Shift+Tab to cycle permission modes\n * - 60s auto‑deny timeout\n */\n\nimport React, { useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Safety level determines badge color and severity. */\nexport type SafetyLevel = \"Safe\" | \"WorkspaceSafe\" | \"RequiresApproval\" | \"Dangerous\";\n\n/** Information about a pending permission request. */\nexport interface PermissionRequestData {\n /** Unique request identifier. */\n requestId: string;\n /** Name of the tool being invoked. */\n toolName: string;\n /** Safety level of the tool. */\n safety: SafetyLevel;\n /** Human‑readable description of what the tool will do. */\n description: string;\n /** Optional parameter summary for display. */\n parameters?: Record<string, unknown>;\n}\n\n/** Callback when the user makes a decision. */\nexport type PermissionChoice = \"allow\" | \"deny\" | \"always_allow\";\n/** User's permission decision callback — receives request ID and chosen action. */\nexport type PermissionCallback = (requestId: string, choice: PermissionChoice) => void;\n\n/** Props for the PermissionRequest modal. */\nexport interface PermissionRequestProps {\n request: PermissionRequestData;\n onDecide: PermissionCallback;\n onCancel: () => void;\n}\n\n/** Badge styles per safety level. */\nconst SAFETY_BADGE: Record<SafetyLevel, { label: string; color: string }> = {\n Safe: { label: \"SAFE\", color: \"success\" },\n WorkspaceSafe: { label: \"WORKSPACE\", color: \"foreground\" },\n RequiresApproval: { label: \"APPROVAL\", color: \"warning\" },\n Dangerous: { label: \"DANGER\", color: \"error\" },\n};\n\n/**\n * Permission request dialog.\n *\n * Users navigate with A/D/L keys and can press Escape to cancel.\n * After AUTO_DENY_MS, the dialog auto‑denies.\n */\nexport function PermissionRequest({\n request,\n onDecide,\n onCancel,\n}: PermissionRequestProps): React.ReactElement {\n const theme = getTheme();\n const badge = SAFETY_BADGE[request.safety] ?? SAFETY_BADGE.RequiresApproval;\n const badgeColor = theme.colors[badge.color] ?? theme.colors.warning;\n\n // ── Keyboard handler ──────────────────────────\n\n /** Currently highlighted option index (0=Allow, 1=Deny, 2=Always). */\n const [highlighted, setHighlighted] = React.useState(0);\n const OPTIONS = [\"allow\", \"deny\", \"always_allow\"] as const;\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n const char = input.toLowerCase();\n if (char === \"a\") {\n onDecide(request.requestId, \"allow\");\n return;\n }\n if (char === \"d\") {\n onDecide(request.requestId, \"deny\");\n return;\n }\n if (char === \"l\") {\n onDecide(request.requestId, \"always_allow\");\n return;\n }\n if (key.return) {\n onDecide(request.requestId, OPTIONS[highlighted]!);\n return;\n }\n if (key.leftArrow) {\n setHighlighted((prev) => (prev - 1 + OPTIONS.length) % OPTIONS.length);\n return;\n }\n if (key.rightArrow) {\n setHighlighted((prev) => (prev + 1) % OPTIONS.length);\n return;\n }\n if (key.escape) {\n onCancel();\n return;\n }\n },\n [request.requestId, highlighted, onDecide, onCancel],\n );\n\n useInkInput(handleKey);\n\n // Format parameters for display\n const paramLines: string[] = [];\n if (request.parameters) {\n for (const [key, val] of Object.entries(request.parameters)) {\n const str = typeof val === \"string\" ? val : JSON.stringify(val);\n paramLines.push(` ${key}: ${str.slice(0, 80)}`);\n }\n }\n\n return React.createElement(\n Box,\n {\n flexDirection: \"column\",\n borderStyle: \"double\",\n borderColor: badgeColor,\n paddingX: 1,\n paddingY: 1,\n marginY: 1,\n },\n // ── Header: tool name + badge ──────────────\n React.createElement(\n Box,\n { flexDirection: \"row\", justifyContent: \"space-between\" },\n React.createElement(Text, { bold: true }, `🔧 ${request.toolName}`),\n React.createElement(Text, { color: badgeColor, bold: true }, ` ${badge.label} `),\n ),\n\n // ── Description ────────────────────────────\n React.createElement(Box, { marginTop: 1 }, React.createElement(Text, {}, request.description)),\n\n // ── Parameters ─────────────────────────────\n paramLines.length > 0\n ? React.createElement(\n Box,\n { flexDirection: \"column\", marginTop: 1 },\n React.createElement(Text, { dimColor: true }, \"Parameters:\"),\n ...paramLines.map((line, i) =>\n React.createElement(Text, { key: i, dimColor: true }, line),\n ),\n )\n : null,\n\n // ── Actions (with arrow key highlight) ──────\n React.createElement(\n Box,\n { flexDirection: \"row\", marginTop: 1, gap: 2 },\n React.createElement(\n Text,\n highlighted === 0\n ? { bold: true, color: theme.colors.success, inverse: true }\n : { color: theme.colors.success },\n \" Allow \",\n ),\n React.createElement(\n Text,\n highlighted === 1\n ? { bold: true, color: theme.colors.error, inverse: true }\n : { color: theme.colors.error },\n \" Deny \",\n ),\n React.createElement(\n Text,\n highlighted === 2\n ? { bold: true, color: theme.colors.accent, inverse: true }\n : { color: theme.colors.accent },\n \" Always Allow \",\n ),\n ),\n\n React.createElement(\n Text,\n { dimColor: true },\n \"← → to select · Enter to confirm · A/D/L shortcuts · Esc to cancel turn\",\n ),\n );\n}\n","/**\n * Dialog — unified modal shell for all Lynx dialogs.\n *\n * Every modal uses this wrapper for consistent look and keyboard behaviour.\n * Renders a double‑bordered overlay with title, subtitle, child content,\n * and bottom input‑guide text.\n *\n * Theme:\n * ┌─ Title ──────────────────────── Esc to close ──┐\n * │ Subtitle │\n * │ │\n * │ {children} │\n * │ │\n * │ Enter to confirm · Esc to cancel │\n * └─────────────────────────────────────────────────┘\n */\n\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Props for the Dialog shell component. */\nexport interface DialogProps {\n /** Modal title shown in the top border. */\n title: string;\n /** Optional accent color for title and border (theme color key). */\n accentColor?: string;\n /** Optional subtitle shown below the title. */\n subtitle?: string;\n /** Bottom hint text (e.g. \"Enter to confirm · Esc to cancel\"). */\n inputGuide?: string;\n /** Width of the dialog in characters. Default: 60. */\n width?: number;\n /** Children rendered as the dialog body. */\n children?: React.ReactNode;\n}\n\n/**\n * Unified dialog wrapper for modals, pickers, and confirmations.\n *\n * All modals in the TUI use this component to ensure visual consistency.\n * The dialog renders as an absolutely positioned overlay with a\n * double‑border style.\n */\nexport function Dialog({\n title,\n accentColor,\n subtitle,\n inputGuide = \"Enter to confirm · Esc to cancel\",\n width = 60,\n children,\n}: DialogProps): React.ReactElement {\n const theme = getTheme();\n const accent = accentColor\n ? (theme.colors[accentColor] ?? theme.colors.accent)\n : theme.colors.accent;\n\n // Build top border line: ┌─ Title ──────────────────── Esc to close ──┐\n const titleText = ` ${title} `;\n const escText = \" Esc to close \";\n const remaining = width - 4 - titleText.length - escText.length; // 4 = \"┌─\" + \"─┐\"\n const filler = remaining > 0 ? \"─\".repeat(remaining) : \"─\";\n\n const topBorder = `┌─${titleText}${filler}${escText}─┐`;\n\n return React.createElement(\n Box,\n {\n position: \"absolute\",\n marginTop: 2,\n marginLeft: 2,\n marginRight: 2,\n marginBottom: 2,\n flexDirection: \"column\",\n borderStyle: \"double\",\n borderColor: accent,\n paddingX: 1,\n },\n // ── Top border with embedded title ─────────\n React.createElement(Text, { color: accent, bold: true }, topBorder),\n\n // ── Subtitle (optional) ───────────────────\n subtitle ? React.createElement(Text, { dimColor: true }, ` ${subtitle}`) : null,\n\n // ── Body ─────────────────────────────────\n React.createElement(Box, { flexDirection: \"column\", marginY: 1, flexGrow: 1 }, children),\n\n // ── Bottom guide ──────────────────────────\n React.createElement(Text, { dimColor: true }, ` ${inputGuide}`),\n\n // ── Bottom border ─────────────────────────\n React.createElement(Text, { color: accent }, `└${\"─\".repeat(width - 2)}┘`),\n );\n}\n","/**\n * SessionPicker — full‑screen session browser and picker.\n *\n * Lists sessions with label, message count, and relative time.\n * Supports text filtering, arrow‑key navigation, Enter to select,\n * and Escape to go back.\n *\n * Design (§5.9f #1):\n * - Search/filter by label substring\n * - Sort tabs: Recent (default) / Relevance / Size\n * - Tree mode for fork groups (Phase 5)\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport type { Session } from \"@24klynx/core\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Sort mode for the session list. */\ntype SortMode = \"recent\" | \"relevance\" | \"size\";\n\n/** Props for the SessionPicker modal. */\nexport interface SessionPickerProps {\n /** All available sessions. */\n sessions: Session[];\n /** Called when the user selects a session (Enter key). */\n onSelect(sessionId: string): void;\n /** Called when the user dismisses the picker (Escape key). */\n onCancel(): void;\n}\n\n/** Maximum number of sessions to display. */\nconst MAX_VISIBLE = 15;\n\n/** Format a relative time string from a Unix‑ms timestamp. */\nfunction formatTime(ts: number): string {\n const sec = Math.floor((Date.now() - ts) / 1000);\n if (sec < 60) return `${sec}秒前`;\n if (sec < 3600) return `${Math.floor(sec / 60)}分钟前`;\n if (sec < 86400) return `${Math.floor(sec / 3600)}小时前`;\n return `${Math.floor(sec / 86400)}天前`;\n}\n\n/** Build fork chains: child sessions indented under their parent. */\nfunction buildForkTree(sessions: Session[]): Array<{ session: Session; depth: number }> {\n const byId = new Map(sessions.map((s) => [s.id, s]));\n const children = new Map<string | undefined, Session[]>();\n for (const s of sessions) {\n const pid = s.parentSessionId ?? \"__root__\";\n let list = children.get(pid);\n if (!list) {\n list = [];\n children.set(pid, list);\n }\n list.push(s);\n }\n\n const result: Array<{ session: Session; depth: number }> = [];\n function walk(pid: string | undefined | \"__root__\", depth: number) {\n const key = pid ?? \"__root__\";\n const kids = children.get(key);\n if (!kids) return;\n kids.sort((a, b) => b.updatedAt - a.updatedAt);\n for (const s of kids) {\n result.push({ session: s, depth: pid === \"__root__\" ? 0 : depth });\n walk(s.id, depth + 1);\n }\n }\n walk(\"__root__\", 0);\n return result;\n}\n\n/** Context passed to {@link sessionPickerHandleKey}. */\nexport interface SessionPickerKeyContext {\n key: {\n return?: boolean;\n escape?: boolean;\n upArrow?: boolean;\n downArrow?: boolean;\n input?: string;\n };\n filter: string;\n setFilter: (f: string) => void;\n selectedIndex: number;\n setSelectedIndex: (i: number) => void;\n maxIndex: number;\n onSelect: () => void;\n onCancel: () => void;\n}\n\n/**\n * Session picker modal.\n *\n * Filters sessions by label substring, displays them in a scrollable\n * list, and handles selection via Enter key.\n */\nexport function SessionPicker({\n sessions: allSessions,\n onSelect,\n onCancel,\n}: SessionPickerProps): React.ReactElement {\n const theme = getTheme();\n const [filter, setFilter] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [sortMode, setSortMode] = useState<SortMode>(\"recent\");\n\n // Build fork tree, then sort by selected mode\n const tree = buildForkTree(allSessions);\n const sorted: Array<{ session: Session; depth: number }> = (() => {\n const copy = [...tree];\n switch (sortMode) {\n case \"recent\":\n copy.sort((a, b) => b.session.updatedAt - a.session.updatedAt);\n break;\n case \"size\":\n copy.sort((a, b) => (b.session.messages?.length ?? 0) - (a.session.messages?.length ?? 0));\n break;\n case \"relevance\":\n // Keep tree order for relevance (parent-child relationships)\n break;\n }\n return copy;\n })();\n\n // Filter by label substring\n const filtered = filter\n ? sorted.filter(({ session: s }) => s.label.toLowerCase().includes(filter.toLowerCase()))\n : sorted;\n\n // Clamp selection\n const maxIndex = Math.max(0, filtered.length - 1);\n const safeIndex = Math.min(selectedIndex, maxIndex);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.return) {\n const selected = filtered[safeIndex];\n if (selected) onSelect(selected.session.id);\n return;\n }\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1));\n return;\n }\n if (key.downArrow) {\n setSelectedIndex(Math.min(maxIndex, selectedIndex + 1));\n return;\n }\n // Tab cycles sort mode\n if (key.tab) {\n setSortMode((prev) => {\n if (prev === \"recent\") return \"relevance\";\n if (prev === \"relevance\") return \"size\";\n return \"recent\";\n });\n setSelectedIndex(0);\n return;\n }\n // Backspace removes last filter char\n if (key.backspace) {\n setFilter((f) => f.slice(0, -1));\n setSelectedIndex(0);\n return;\n }\n // Typing adds to filter\n if (input.length === 1 && !key.ctrl && !key.meta) {\n setFilter((f) => f + input);\n setSelectedIndex(0);\n }\n },\n [filtered, safeIndex, maxIndex, selectedIndex, sortMode, onSelect, onCancel],\n );\n\n useInkInput(handleKey);\n\n /** Chinese label for sort mode tabs. */\n const sortLabel = (mode: SortMode): string => {\n if (mode === \"recent\") return \"最近\";\n if (mode === \"relevance\") return \"关联\";\n return \"大小\";\n };\n\n // ── Sort mode tab bar ──\n const modes: SortMode[] = [\"recent\", \"relevance\", \"size\"];\n const tabNodes = modes.map((mode) => {\n const isActive = mode === sortMode;\n return React.createElement(\n Text,\n { key: mode, color: isActive ? theme.colors.accent : theme.colors.dim, bold: isActive },\n ` ${sortLabel(mode)} `,\n );\n });\n\n // Build session list items with fork tree depth indentation\n const listItems: React.ReactElement[] = [];\n const visible = filtered.slice(0, MAX_VISIBLE);\n\n for (let i = 0; i < visible.length; i++) {\n const entry = visible[i]!;\n const s = entry.session;\n const isSelected = i === safeIndex;\n const cursor = isSelected ? \"❯\" : \" \";\n const indent = \" \".repeat(entry.depth) + (entry.depth > 0 ? \"├─ \" : \"\");\n const count = s.messages?.length ?? 0;\n const time = formatTime(s.updatedAt);\n\n listItems.push(\n React.createElement(\n Box,\n { key: s.id, flexDirection: \"row\" },\n React.createElement(\n Text,\n {\n color: isSelected ? theme.colors.accent : undefined,\n bold: isSelected,\n },\n `${cursor} ${indent}${s.label.padEnd(28 - indent.length)} ${String(count).padStart(4)} 条消息 ${time}`,\n ),\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"会话\",\n subtitle: `排序: ${sortLabel(sortMode)} · 过滤: ${filter || \"(输入关键词)\"}`,\n inputGuide: \"Enter 选择 · Esc 返回 · Tab 切换排序 · ↑↓ 导航 · 打字过滤\",\n accentColor: \"accent\",\n },\n // ── Sort mode tabs ────────────────────────\n React.createElement(Box, { flexDirection: \"row\", marginBottom: 1 }, ...tabNodes),\n // ── Session list ───────────────────────────\n listItems.length > 0\n ? React.createElement(Box, { flexDirection: \"column\" }, ...listItems)\n : React.createElement(Text, { dimColor: true }, \" 未找到会话。\"),\n\n // ── Filter hint ────────────────────────────\n filter\n ? React.createElement(Text, { dimColor: true }, ` ${filtered.length} 个会话匹配 \"${filter}\"`)\n : null,\n );\n}\n\n/**\n * Handle keyboard input for the SessionPicker.\n *\n * Returns true if the key was consumed by the picker.\n */\nexport function sessionPickerHandleKey(ctx: SessionPickerKeyContext): boolean {\n if (ctx.key.return) {\n ctx.onSelect();\n return true;\n }\n\n if (ctx.key.escape) {\n ctx.onCancel();\n return true;\n }\n\n if (ctx.key.upArrow) {\n ctx.setSelectedIndex(Math.max(0, ctx.selectedIndex - 1));\n return true;\n }\n\n if (ctx.key.downArrow) {\n ctx.setSelectedIndex(Math.min(ctx.maxIndex, ctx.selectedIndex + 1));\n return true;\n }\n\n // Text input for filtering\n if (ctx.key.input && ctx.key.input.length === 1) {\n ctx.setFilter(ctx.filter + ctx.key.input);\n ctx.setSelectedIndex(0);\n return true;\n }\n\n return false;\n}\n","/**\n * HelpModal — keyboard shortcut reference.\n *\n * Renders a categorized table of keyboard shortcuts, dynamically\n * generated from the keybindings catalog. Supports text search\n * filtering.\n *\n * Design (§5.9f #4):\n * - Categories: Global, Chat, Permission, Modal\n * - Two‑column layout: key | action\n * - Search filter with real‑time filtering\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** A single shortcut entry. */\ninterface Shortcut {\n keys: string;\n action: string;\n category: string;\n}\n\n/** Built‑in shortcut reference. */\nconst SHORTCUTS: Shortcut[] = [\n // ── 全局 ──\n { keys: \"Ctrl+C\", action: \"中断(三层)\", category: \"全局\" },\n { keys: \"Ctrl+H\", action: \"显示帮助\", category: \"全局\" },\n { keys: \"Ctrl+L\", action: \"模型选择器\", category: \"全局\" },\n { keys: \"Ctrl+S\", action: \"暂存当前输入\", category: \"全局\" },\n { keys: \"Ctrl+O\", action: \"切换时间戳显示\", category: \"全局\" },\n { keys: \"Ctrl+G\", action: \"外部编辑器\", category: \"全局\" },\n { keys: \"Ctrl+Shift+P\", action: \"命令面板\", category: \"全局\" },\n { keys: \"Ctrl+Shift+F\", action: \"全局文件搜索\", category: \"全局\" },\n // ── 对话 ──\n { keys: \"Enter\", action: \"发送消息\", category: \"对话\" },\n { keys: \"Ctrl+Enter\", action: \"插入换行\", category: \"对话\" },\n { keys: \"Ctrl+F\", action: \"消息内搜索\", category: \"对话\" },\n { keys: \"Ctrl+A/E\", action: \"跳到行首/行尾\", category: \"对话\" },\n { keys: \"Ctrl+W\", action: \"删除上一个词\", category: \"对话\" },\n { keys: \"Ctrl+K\", action: \"删除到行尾\", category: \"对话\" },\n { keys: \"Ctrl+U\", action: \"删除到行首\", category: \"对话\" },\n { keys: \"Tab\", action: \"接受自动补全\", category: \"对话\" },\n { keys: \"Up/Down\", action: \"浏览历史(200 条)\", category: \"对话\" },\n { keys: \"PageUp/PageDown\", action: \"滚动对话历史\", category: \"对话\" },\n { keys: \"Home/End\", action: \"跳到顶部/底部\", category: \"对话\" },\n { keys: \"/\", action: \"斜杠命令\", category: \"对话\" },\n { keys: \"!\", action: \"Bang 模式(Shell 命令)\", category: \"对话\" },\n { keys: \"@\", action: \"文件路径补全\", category: \"对话\" },\n // ── 模态框 ──\n { keys: \"Escape\", action: \"关闭模态框 / 取消\", category: \"模态框\" },\n // ── 权限 ──\n { keys: \"A/D/L\", action: \"允许/拒绝/始终允许\", category: \"权限\" },\n { keys: \"Shift+Tab\", action: \"切换权限模式\", category: \"权限\" },\n];\n\n/** Props for the HelpModal. */\nexport interface HelpModalProps {\n onCancel(): void;\n}\n\n/**\n * Help modal displaying keyboard shortcuts.\n *\n * Categorized display with search filtering.\n */\nexport function HelpModal({ onCancel }: HelpModalProps): React.ReactElement {\n const theme = getTheme();\n const [filter, setFilter] = useState(\"\");\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.backspace) {\n setFilter((f) => f.slice(0, -1));\n return;\n }\n if (input.length === 1 && !key.ctrl && !key.meta) {\n setFilter((f) => f + input);\n }\n },\n [onCancel],\n );\n\n useInkInput(handleKey);\n\n const filtered = filter\n ? SHORTCUTS.filter(\n (s) =>\n s.keys.toLowerCase().includes(filter.toLowerCase()) ||\n s.action.toLowerCase().includes(filter.toLowerCase()) ||\n s.category.toLowerCase().includes(filter.toLowerCase()),\n )\n : SHORTCUTS;\n\n // Group by category\n const categories = new Map<string, Shortcut[]>();\n for (const s of filtered) {\n const list = categories.get(s.category);\n if (list) {\n list.push(s);\n } else {\n categories.set(s.category, [s]);\n }\n }\n\n const rows: React.ReactElement[] = [];\n for (const [category, shortcuts] of categories) {\n rows.push(\n React.createElement(\n Text,\n { key: `cat-${category}`, bold: true, color: theme.colors.accent },\n ` ${category}`,\n ),\n );\n for (const s of shortcuts) {\n const keyDisplay = s.keys.padEnd(22);\n rows.push(\n React.createElement(Text, { key: `${category}-${s.keys}` }, ` ${keyDisplay}${s.action}`),\n );\n }\n // Spacer between categories\n rows.push(React.createElement(Box, { key: `gap-${category}`, height: 1 }));\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"键盘快捷键\",\n subtitle: filter ? `过滤: ${filter}` : undefined,\n inputGuide: \"Escape 关闭 · 输入过滤\",\n accentColor: \"accent\",\n width: 65,\n },\n React.createElement(Box, { flexDirection: \"column\" }, ...rows),\n );\n}\n","/**\n * CommandPalette — fuzzy‑search command picker (Ctrl+K).\n *\n * Lists all available slash commands and actions. Supports\n * real‑time fuzzy filtering, arrow‑key navigation, and\n * Enter to execute.\n *\n * Design (§5.9f #10):\n * - Fuzzy search all available commands\n * - Max 8 items visible\n * - Enter to execute\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** A single command entry in the palette. */\nexport interface CommandEntry {\n name: string;\n description: string;\n}\n\n/** Built‑in commands. Phase 5 expands this with plugin‑registered commands. */\nconst BUILTIN_COMMANDS: CommandEntry[] = [\n { name: \"/sessions\", description: \"列出和管理会话\" },\n { name: \"/new\", description: \"创建新会话\" },\n { name: \"/fork\", description: \"派生当前会话\" },\n { name: \"/rename\", description: \"重命名当前会话\" },\n { name: \"/delete\", description: \"删除会话\" },\n { name: \"/resume\", description: \"恢复上次会话\" },\n { name: \"/config\", description: \"显示配置\" },\n { name: \"/settings\", description: \"打开设置面板\" },\n { name: \"/doctor\", description: \"运行系统诊断\" },\n { name: \"/theme\", description: \"更改颜色主题\" },\n { name: \"/model\", description: \"切换 AI 模型\" },\n { name: \"/compact\", description: \"压缩对话上下文\" },\n { name: \"/help\", description: \"显示键盘快捷键\" },\n { name: \"/mcp\", description: \"管理 MCP 服务器\" },\n { name: \"/plugin\", description: \"管理插件\" },\n { name: \"/skills\", description: \"浏览技能\" },\n { name: \"/context\", description: \"显示上下文用量\" },\n { name: \"/usage\", description: \"显示用量统计\" },\n { name: \"/tasks\", description: \"查看后台任务\" },\n { name: \"/snapshots\", description: \"浏览文件快照\" },\n { name: \"/stash\", description: \"管理暂存输入\" },\n { name: \"/diff\", description: \"查看文件差异\" },\n];\n\n/** Props for the CommandPalette. */\nexport interface CommandPaletteProps {\n /** Called when the user selects a command (Enter key). */\n onSelect(command: string): void;\n /** Called when the user dismisses (Escape key). */\n onCancel(): void;\n /** Additional commands from plugins/extensions. */\n extraCommands?: CommandEntry[];\n}\n\nconst MAX_VISIBLE = 12;\n\n/**\n * Command palette modal.\n *\n * Fuzzy‑filters the command list as the user types and supports\n * arrow‑key navigation with Enter to execute.\n */\nexport function CommandPalette({\n onSelect,\n onCancel,\n extraCommands,\n}: CommandPaletteProps): React.ReactElement {\n const theme = getTheme();\n const [selectedIndex, setSelectedIndex] = useState(0);\n\n const allCommands = [...BUILTIN_COMMANDS, ...(extraCommands ?? [])];\n\n const maxIndex = Math.max(0, allCommands.length - 1);\n const safeIndex = Math.min(selectedIndex, maxIndex);\n const visible = allCommands.slice(0, MAX_VISIBLE);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.return) {\n const cmd = allCommands[safeIndex];\n if (cmd) onSelect(cmd.name);\n return;\n }\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1));\n return;\n }\n if (key.downArrow) {\n setSelectedIndex(Math.min(maxIndex, selectedIndex + 1));\n return;\n }\n },\n [allCommands, safeIndex, maxIndex, selectedIndex, onSelect, onCancel],\n );\n\n useInkInput(handleKey);\n\n const items: React.ReactElement[] = [];\n for (let i = 0; i < visible.length; i++) {\n const cmd = visible[i]!;\n const isSelected = i === safeIndex;\n const prefix = isSelected ? \"❯ \" : \" \";\n const nameDisplay = cmd.name.padEnd(18);\n\n items.push(\n React.createElement(\n Box,\n { key: cmd.name, flexDirection: \"row\" },\n React.createElement(\n Text,\n {\n color: isSelected ? theme.colors.accent : undefined,\n bold: isSelected,\n },\n `${prefix}${nameDisplay}${cmd.description}`,\n ),\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"命令\",\n subtitle: \"输入搜索...\",\n inputGuide: \"Enter 执行 · Esc 关闭 · ↑↓ 导航\",\n accentColor: \"accent\",\n width: 65,\n },\n React.createElement(Box, { flexDirection: \"column\" }, ...items),\n );\n}\n","/**\n * ModelPicker — interactive model selection dialog.\n *\n * Displays available models with search filtering, pricing info,\n * context windows, and output limits.\n * Supports keyboard navigation (Up/Down/Enter/Esc) and setting defaults\n * with the `s` key.\n *\n * Triggered by /model or Ctrl+L.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport type { TuiModelInfo } from \"../types.js\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** Props for the ModelPicker component. */\nexport interface ModelPickerProps {\n /** Available models to display. */\n models: TuiModelInfo[];\n /** Currently selected model ID. */\n currentModel?: string;\n /** Called when the user selects a model. */\n onSelect: (modelId: string) => void;\n /** Called when the user sets a model as default. */\n onSetDefault?: (modelId: string) => void;\n /** Called when the user cancels. */\n onCancel: () => void;\n}\n\n/** Format context window size for display. */\nfunction formatContext(k: number): string {\n return k >= 1000 ? `${Math.round(k / 1000)}K` : `${k}`;\n}\n\n/** Format pricing for display (e.g. \"$0.27/$1.10\"). */\nfunction formatPrice(inputPrice?: number, outputPrice?: number): string {\n if (inputPrice === undefined || outputPrice === undefined) return \"—\";\n return `$${inputPrice}/$${outputPrice}`;\n}\n\n/**\n * Interactive model picker modal with search filtering.\n *\n * Navigation:\n * Type text → filter models by id/label\n * ↑/↓ — move cursor\n * Enter — select and close\n * s — set as default (does not close)\n * Esc — cancel\n */\nexport function ModelPicker({\n models,\n currentModel,\n onSelect,\n onSetDefault,\n onCancel,\n}: ModelPickerProps): React.ReactElement {\n const [filterText, setFilterText] = useState(\"\");\n const [cursor, setCursor] = useState(0);\n\n // Filter models by search text\n const filtered = filterText\n ? models.filter(\n (m) =>\n m.id.toLowerCase().includes(filterText.toLowerCase()) ||\n m.label.toLowerCase().includes(filterText.toLowerCase()),\n )\n : models;\n\n // Clamp cursor when filtered list changes\n const clampedCursor = filtered.length > 0 ? Math.min(cursor, filtered.length - 1) : 0;\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setCursor((prev) => (prev > 0 ? prev - 1 : Math.max(0, filtered.length - 1)));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => (prev < filtered.length - 1 ? prev + 1 : 0));\n return;\n }\n if (key.return) {\n const selected = filtered[clampedCursor];\n if (selected) onSelect(selected.id);\n return;\n }\n if (input === \"s\" && onSetDefault) {\n const selected = filtered[clampedCursor];\n if (selected) onSetDefault(selected.id);\n return;\n }\n if (key.backspace || key.delete) {\n setFilterText((prev) => prev.slice(0, -1));\n setCursor(0);\n return;\n }\n // Printable characters → filter\n if (input && input.length === 1 && !key.ctrl && !key.meta) {\n setFilterText((prev) => prev + input);\n setCursor(0);\n return;\n }\n },\n [filtered, clampedCursor, onSelect, onSetDefault, onCancel],\n );\n\n useInkInput(handleKey);\n\n // ── Render ────────────────────────────────────\n const items: React.ReactNode[] = [];\n\n // Search bar\n items.push(\n React.createElement(\n Box,\n { key: \"search\", flexDirection: \"row\", marginBottom: 1 },\n React.createElement(Text, { dimColor: true }, \"🔍 \"),\n React.createElement(\n Text,\n {},\n filterText || React.createElement(Text, { dimColor: true }, \"输入过滤...\"),\n ),\n React.createElement(Text, { dimColor: true }, \"█\"),\n filterText\n ? React.createElement(Text, { dimColor: true }, ` ${filtered.length}/${models.length}`)\n : null,\n ),\n );\n\n // Model list\n for (let i = 0; i < filtered.length; i++) {\n const model = filtered[i]!;\n const isActive = model.id === currentModel;\n const isCursor = i === clampedCursor;\n const prefix = isCursor ? \"❯\" : \" \";\n const ctxStr = formatContext(model.contextWindow);\n const priceStr = formatPrice(model.inputPrice, model.outputPrice);\n const activeMark = isActive ? \" ✓\" : \"\";\n\n items.push(\n React.createElement(\n Text,\n {\n key: model.id,\n bold: isCursor,\n color: isCursor ? \"cyan\" : isActive ? \"green\" : undefined,\n },\n `${prefix} ${model.id.slice(0, 28).padEnd(30)} ${ctxStr.padStart(6)} 上下文 ${priceStr.padStart(12)}${activeMark}`,\n ),\n );\n }\n\n if (filtered.length === 0) {\n items.push(React.createElement(Text, { key: \"empty\", dimColor: true }, \" 无匹配的模型。\"));\n }\n\n const guide = onSetDefault\n ? \"输入过滤 · ↑↓ 移动 · Enter 选择 · s 设为默认 · Esc 取消\"\n : \"输入过滤 · ↑↓ 移动 · Enter 选择 · Esc 取消\";\n\n return React.createElement(\n Dialog,\n { title: \"选择模型\", accentColor: \"accent\", inputGuide: guide, width: 78 },\n React.createElement(Box, { flexDirection: \"column\", marginY: 1 }, ...items),\n );\n}\n","/**\n * ConfigMenu — settings panel with tabbed categories.\n *\n * Settings are grouped into tabs: General, Models, Permissions, Appearance,\n * Advanced. Boolean settings toggle with Enter; text/number settings open\n * an edit prompt via the onEdit callback.\n *\n * Triggered by /config or /settings.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** A single configurable setting. */\nexport interface ConfigSetting {\n /** Setting key, e.g. \"autoCompact\". */\n key: string;\n /** Human‑readable label. */\n label: string;\n /** Current value. Type determines rendering: boolean → checkbox, string/number → inline display. */\n value: boolean | string | number;\n /** Category tab this setting belongs to. */\n category: string;\n}\n\n/** Tab definitions for the config menu. */\ninterface ConfigTab {\n id: string;\n label: string;\n}\n\nconst TABS: ConfigTab[] = [\n { id: \"general\", label: \"通用\" },\n { id: \"models\", label: \"模型\" },\n { id: \"permissions\", label: \"权限\" },\n { id: \"appearance\", label: \"外观\" },\n { id: \"advanced\", label: \"高级\" },\n];\n\n/** Default settings when no data is provided. */\nconst DEFAULT_SETTINGS: ConfigSetting[] = [\n { key: \"syntaxHighlighting\", label: \"语法高亮\", value: true, category: \"general\" },\n { key: \"autoCollapseTools\", label: \"自动折叠工具\", value: true, category: \"general\" },\n { key: \"showThinking\", label: \"显示思考过程\", value: false, category: \"general\" },\n { key: \"telemetry\", label: \"遥测\", value: true, category: \"general\" },\n { key: \"reduceMotion\", label: \"减少动画\", value: false, category: \"general\" },\n { key: \"vimMode\", label: \"Vim 模式\", value: false, category: \"general\" },\n { key: \"model\", label: \"默认模型\", value: \"deepseek-chat\", category: \"models\" },\n { key: \"autoCompact\", label: \"自动压缩上下文\", value: true, category: \"models\" },\n { key: \"fastMode\", label: \"快速模式\", value: false, category: \"models\" },\n { key: \"streamOutput\", label: \"流式输出\", value: true, category: \"models\" },\n { key: \"promptCache\", label: \"提示缓存\", value: true, category: \"models\" },\n { key: \"maxTokens\", label: \"每轮最大令牌数\", value: 4096, category: \"models\" },\n {\n key: \"yoloMode\",\n label: \"YOLO 模式(跳过所有权限)\",\n value: false,\n category: \"permissions\",\n },\n { key: \"workspaceTrust\", label: \"工作区信任\", value: true, category: \"permissions\" },\n {\n key: \"permissionTimeout\",\n label: \"权限超时(60 秒)\",\n value: true,\n category: \"permissions\",\n },\n { key: \"darkMode\", label: \"深色模式\", value: true, category: \"appearance\" },\n { key: \"compactLayout\", label: \"紧凑布局\", value: false, category: \"appearance\" },\n { key: \"showMascot\", label: \"显示吉祥物\", value: true, category: \"appearance\" },\n {\n key: \"showLineNumbers\",\n label: \"代码中显示行号\",\n value: false,\n category: \"appearance\",\n },\n { key: \"theme\", label: \"主题\", value: \"dark\", category: \"appearance\" },\n { key: \"debugLogging\", label: \"调试日志\", value: false, category: \"advanced\" },\n { key: \"devMode\", label: \"开发者模式\", value: false, category: \"advanced\" },\n {\n key: \"experimentalFeatures\",\n label: \"实验性功能\",\n value: false,\n category: \"advanced\",\n },\n];\n\n/** Props for the ConfigMenu component. */\nexport interface ConfigMenuProps {\n /** Active settings (optional; falls back to defaults). */\n settings?: ConfigSetting[];\n /** Called when a boolean setting is toggled. */\n onToggle: (key: string, value: boolean) => void;\n /** Called when a text/number setting needs editing. valueType helps the handler decide whether to parse as number. */\n onEdit?: (key: string, label: string, currentValue: string, valueType: \"text\" | \"number\") => void;\n /** Called when the user cancels. */\n onCancel: () => void;\n}\n\n/**\n * Detect the setting value type for rendering.\n * boolean → checkbox with toggle\n * string / number → inline value display, Enter to edit\n */\nfunction settingType(value: ConfigSetting[\"value\"]): \"boolean\" | \"text\" | \"number\" {\n if (typeof value === \"boolean\") return \"boolean\";\n if (typeof value === \"number\") return \"number\";\n return \"text\";\n}\n\n/** Format a setting value for display. */\nfunction formatValue(setting: ConfigSetting): string {\n const type = settingType(setting.value);\n if (type === \"boolean\") return setting.value ? \"✓\" : \"○\";\n return String(setting.value);\n}\n\n/**\n * Interactive settings panel with tabbed categories.\n *\n * Navigation:\n * ←/→ — switch tabs\n * ↑/↓ — move cursor\n * Enter — toggle boolean / edit text / edit number\n * Esc — close\n */\nexport function ConfigMenu({\n settings,\n onToggle,\n onEdit,\n onCancel,\n}: ConfigMenuProps): React.ReactElement {\n const items = settings ?? DEFAULT_SETTINGS;\n const [activeTab, setActiveTab] = useState(0);\n const [cursor, setCursor] = useState(0);\n\n const currentTab = TABS[activeTab]!;\n const tabItems = items.filter((s) => s.category === currentTab.id);\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.leftArrow) {\n setActiveTab((prev) => (prev > 0 ? prev - 1 : TABS.length - 1));\n setCursor(0);\n return;\n }\n if (key.rightArrow) {\n setActiveTab((prev) => (prev < TABS.length - 1 ? prev + 1 : 0));\n setCursor(0);\n return;\n }\n if (key.upArrow) {\n setCursor((prev) => (prev > 0 ? prev - 1 : tabItems.length - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => (prev < tabItems.length - 1 ? prev + 1 : 0));\n return;\n }\n if (key.return) {\n const setting = tabItems[cursor];\n if (!setting) return;\n const type = settingType(setting.value);\n if (type === \"boolean\") {\n onToggle(setting.key, !setting.value);\n } else if (onEdit) {\n onEdit(setting.key, setting.label, String(setting.value), type);\n }\n return;\n }\n if (key.escape) {\n onCancel();\n }\n },\n [activeTab, cursor, tabItems, onToggle, onEdit, onCancel],\n );\n\n useInkInput(handleKey);\n\n // ── Render tabs ─────────────────────────────\n const tabElements: React.ReactNode[] = [];\n for (let i = 0; i < TABS.length; i++) {\n const tab = TABS[i]!;\n const isActive = i === activeTab;\n tabElements.push(\n React.createElement(\n Text,\n { key: tab.id, bold: isActive, color: isActive ? \"cyan\" : \"grey\", underline: isActive },\n isActive ? `[${tab.label}]` : ` ${tab.label} `,\n ),\n );\n if (i < TABS.length - 1) {\n tabElements.push(React.createElement(Text, { key: `sep-${i}`, dimColor: true }, \" \"));\n }\n }\n\n // ── Render settings ─────────────────────────\n const settingElements: React.ReactNode[] = [];\n for (let i = 0; i < tabItems.length; i++) {\n const setting = tabItems[i]!;\n const isCursor = i === cursor;\n const prefix = isCursor ? \"❯\" : \" \";\n const type = settingType(setting.value);\n const displayVal = formatValue(setting);\n const editHint = type !== \"boolean\" ? \" [Enter 编辑]\" : \"\";\n\n settingElements.push(\n React.createElement(\n Text,\n { key: setting.key, bold: isCursor, color: isCursor ? \"cyan\" : undefined },\n `${prefix} ${displayVal} ${setting.label}${editHint}`,\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"设置\",\n accentColor: \"accent\",\n inputGuide: \"←→ 切换标签 · ↑↓ 移动 · Enter 切换/编辑 · Esc 关闭\",\n width: 68,\n },\n React.createElement(\n Box,\n { flexDirection: \"column\" },\n React.createElement(Box, { flexDirection: \"row\", marginBottom: 1 }, ...tabElements),\n React.createElement(Box, { flexDirection: \"column\" }, ...settingElements),\n ),\n );\n}\n","/**\n * ThemePicker — interactive theme selection dialog.\n *\n * Displays the six built‑in themes with a live preview swatch.\n * User navigates with arrow keys and presses Enter to apply.\n *\n * Triggered by /theme.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport type { ThemeName } from \"../types.js\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** Theme metadata for the picker. */\ninterface ThemeEntry {\n id: ThemeName;\n label: string;\n description: string;\n}\n\nconst THEME_ENTRIES: ThemeEntry[] = [\n { id: \"dark\", label: \"深色\", description: \"Tokyo Night 风格 — 低对比度,护眼舒适\" },\n { id: \"light\", label: \"浅色\", description: \"GitHub 风格 — 简洁明亮\" },\n { id: \"catppuccin\", label: \"Catppuccin\", description: \"舒缓的柔和色调\" },\n { id: \"monokai\", label: \"Monokai\", description: \"经典鲜艳的语法主题\" },\n { id: \"solarized\", label: \"Solarized\", description: \"为可读性精心调校的色彩\" },\n { id: \"dracula\", label: \"Dracula\", description: \"深紫色 — 戏剧性对比\" },\n];\n\n/** Props for the ThemePicker component. */\nexport interface ThemePickerProps {\n /** Currently active theme name. */\n currentTheme?: ThemeName;\n /** Called when the user selects a theme. */\n onSelect: (themeName: ThemeName) => void;\n /** Called when the user cancels. */\n onCancel: () => void;\n}\n\n/**\n * Interactive theme picker modal.\n *\n * Navigation:\n * ↑/↓ — move cursor\n * Enter — apply theme and close\n * Esc — cancel\n */\nexport function ThemePicker({\n currentTheme,\n onSelect,\n onCancel,\n}: ThemePickerProps): React.ReactElement {\n const [cursor, setCursor] = useState(\n Math.max(\n THEME_ENTRIES.findIndex((t) => t.id === currentTheme),\n 0,\n ),\n );\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.upArrow) {\n setCursor((prev) => (prev > 0 ? prev - 1 : THEME_ENTRIES.length - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => (prev < THEME_ENTRIES.length - 1 ? prev + 1 : 0));\n return;\n }\n if (key.return) {\n const selected = THEME_ENTRIES[cursor];\n if (selected) onSelect(selected.id);\n return;\n }\n if (key.escape) {\n onCancel();\n }\n },\n [cursor, onSelect, onCancel],\n );\n\n useInkInput(handleKey);\n\n const items: React.ReactNode[] = [];\n for (let i = 0; i < THEME_ENTRIES.length; i++) {\n const entry = THEME_ENTRIES[i]!;\n const isActive = entry.id === currentTheme;\n const isCursor = i === cursor;\n const prefix = isCursor ? \"❯\" : \" \";\n const marker = isActive ? \" (当前)\" : \"\";\n\n items.push(\n React.createElement(\n Text,\n {\n key: entry.id,\n bold: isCursor,\n color: isCursor ? \"cyan\" : isActive ? \"green\" : undefined,\n },\n `${prefix} ${entry.label.padEnd(16)} ${entry.description.slice(0, 44)}${marker}`,\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"主题\",\n accentColor: \"accent\",\n inputGuide: \"↑↓ 移动 · Enter 应用 · Esc 取消\",\n width: 72,\n },\n React.createElement(Box, { flexDirection: \"column\", marginY: 1 }, ...items),\n );\n}\n","/**\n * ConfirmDialog — generic yes/no confirmation dialog.\n *\n * Used for dangerous actions (delete session, restore snapshot, force exit).\n * Two options are presented: confirm and cancel. The user navigates with\n * ↑/↓ and confirms with Enter or cancels with Esc.\n *\n * Dangerous keywords in the message are highlighted in red.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** Dangerous keywords to highlight in red. */\nconst DANGER_WORDS = [\n \"delete\",\n \"remove\",\n \"destroy\",\n \"overwrite\",\n \"irreversible\",\n \"cannot be undone\",\n \"删除\",\n \"移除\",\n \"销毁\",\n \"覆盖\",\n \"不可逆\",\n \"无法撤销\",\n];\n\n/** Props for the ConfirmDialog component. */\nexport interface ConfirmDialogProps {\n /** Title shown in the border. */\n title: string;\n /** Body message explaining the action. */\n message: string;\n /** Label for the confirm option. Default: \"Yes\" */\n confirmLabel?: string;\n /** Label for the cancel option. Default: \"No\" */\n cancelLabel?: string;\n /** Called when the user confirms. */\n onConfirm: () => void;\n /** Called when the user cancels. */\n onCancel: () => void;\n}\n\n/** Highlight dangerous words in a message string with red color. */\nfunction renderDangerMessage(message: string): React.ReactNode {\n const lower = message.toLowerCase();\n const parts: React.ReactNode[] = [];\n let lastIndex = 0;\n\n // Find dangerous words and highlight them\n for (const word of DANGER_WORDS) {\n const idx = lower.indexOf(word);\n if (idx >= 0) {\n if (idx > lastIndex) {\n parts.push(\n React.createElement(Text, { key: `text-${lastIndex}` }, message.slice(lastIndex, idx)),\n );\n }\n parts.push(\n React.createElement(\n Text,\n { key: `danger-${idx}`, color: \"red\", bold: true },\n message.slice(idx, idx + word.length),\n ),\n );\n lastIndex = idx + word.length;\n }\n }\n\n if (lastIndex < message.length) {\n parts.push(React.createElement(Text, { key: `text-end` }, message.slice(lastIndex)));\n }\n\n return parts.length > 0\n ? React.createElement(Text, null, ...parts)\n : React.createElement(Text, null, message);\n}\n\n/**\n * Generic confirmation dialog with Yes/No options.\n *\n * Navigation:\n * ↑/↓ — switch between options\n * Enter — confirm current selection\n * Esc — cancel\n */\nexport function ConfirmDialog({\n title,\n message,\n confirmLabel = \"是\",\n cancelLabel = \"否\",\n onConfirm,\n onCancel,\n}: ConfirmDialogProps): React.ReactElement {\n const [selected, setSelected] = useState<\"confirm\" | \"cancel\">(\"cancel\");\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.upArrow || key.downArrow) {\n setSelected((prev) => (prev === \"confirm\" ? \"cancel\" : \"confirm\"));\n return;\n }\n if (key.return) {\n if (selected === \"confirm\") onConfirm();\n else onCancel();\n return;\n }\n if (key.escape) {\n onCancel();\n }\n },\n [selected, onConfirm, onCancel],\n );\n\n useInkInput(handleKey);\n\n return React.createElement(\n Dialog,\n {\n title,\n accentColor: \"error\",\n inputGuide: \"↑↓ 切换 · Enter 确认 · Esc 取消\",\n width: 60,\n },\n React.createElement(\n Box,\n { flexDirection: \"column\", marginY: 1 },\n renderDangerMessage(message),\n React.createElement(\n Box,\n { flexDirection: \"column\", marginTop: 2 },\n React.createElement(\n Text,\n { bold: selected === \"confirm\", color: selected === \"confirm\" ? \"red\" : undefined },\n selected === \"confirm\" ? `❯ ${confirmLabel}` : ` ${confirmLabel}`,\n ),\n React.createElement(\n Text,\n { bold: selected === \"cancel\", color: selected === \"cancel\" ? \"cyan\" : undefined },\n selected === \"cancel\" ? `❯ ${cancelLabel}` : ` ${cancelLabel}`,\n ),\n ),\n ),\n );\n}\n","/**\n * InputPrompt — single‑line text input modal.\n *\n * Used for rename session, set config values, enter search terms, etc.\n * The input field is pre‑filled with the current value and supports\n * basic editing (Backspace, arrow keys, typing).\n *\n * Shared across multiple modals that need text input.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** Props for the InputPrompt component. */\nexport interface InputPromptProps {\n /** Title shown in the border. */\n title: string;\n /** Initial value to pre‑fill the input. */\n initialValue?: string;\n /** Placeholder shown when input is empty. */\n placeholder?: string;\n /** Called when the user confirms with Enter. */\n onConfirm: (value: string) => void;\n /** Called when the user cancels with Esc. */\n onCancel: () => void;\n /** Maximum allowed input length. Default: 100. */\n maxLength?: number;\n}\n\n/**\n * Single‑line text input modal.\n *\n * Key bindings:\n * Enter — confirm and return value\n * Esc — cancel\n * Backspace — delete character before cursor\n * Delete — delete character at cursor\n * ←/→ — move cursor\n * Home/End — jump to start/end\n * Ctrl+A/E — jump to start/end\n * Ctrl+K — delete to end of line\n * Ctrl+W — delete previous word\n */\n/** Modal input prompt component — renders a single-line text input with cursor navigation and keyboard shortcuts. */\nexport function InputPrompt({\n title,\n initialValue = \"\",\n placeholder = \"\",\n onConfirm,\n onCancel,\n maxLength = 100,\n}: InputPromptProps): React.ReactElement {\n const [value, setValue] = useState(initialValue);\n const [cursor, setCursor] = useState(initialValue.length);\n\n /** State for the edit buffer. */\n interface EditState {\n value: string;\n cursor: number;\n }\n\n /** Result of an edit operation — null if the key wasn't an edit. */\n type EditResult = EditState | null;\n\n /** Handle deletion keys (Backspace, Delete, Ctrl+K, Ctrl+W). */\n function applyEditOp(input: string, key: Key, state: EditState): EditResult {\n const { value, cursor } = state;\n\n if (key.backspace && cursor > 0) {\n return { value: value.slice(0, cursor - 1) + value.slice(cursor), cursor: cursor - 1 };\n }\n if (key.delete && cursor < value.length) {\n return { value: value.slice(0, cursor) + value.slice(cursor + 1), cursor };\n }\n if (key.ctrl && input === \"k\") {\n return { value: value.slice(0, cursor), cursor };\n }\n if (key.ctrl && input === \"w\") {\n const before = value.slice(0, cursor);\n const match = before.match(/(.*)\\S\\s*$/);\n const newStart = match ? match[1]!.length : 0;\n return { value: value.slice(0, newStart) + value.slice(cursor), cursor: newStart };\n }\n return null;\n }\n\n /** Handle cursor movement keys. Returns new cursor position or -1. */\n function applyCursorMove(input: string, key: Key, state: EditState): number {\n const { value, cursor } = state;\n\n if (key.leftArrow) return Math.max(0, cursor - 1);\n if (key.rightArrow) return Math.min(value.length, cursor + 1);\n if (key.home || (key.ctrl && input === \"a\")) return 0;\n if (key.end || (key.ctrl && input === \"e\")) return value.length;\n return -1;\n }\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.return) {\n onConfirm(value);\n return;\n }\n\n const state: EditState = { value, cursor };\n\n const editResult = applyEditOp(input, key, state);\n if (editResult) {\n setValue(editResult.value);\n setCursor(editResult.cursor);\n return;\n }\n\n const newCursor = applyCursorMove(input, key, state);\n if (newCursor >= 0) {\n setCursor(newCursor);\n return;\n }\n\n // Regular text input\n if (input.length === 1 && value.length < maxLength) {\n setValue((prev) => prev.slice(0, cursor) + input + prev.slice(cursor));\n setCursor((prev) => prev + 1);\n }\n },\n [value, cursor, maxLength, onConfirm, onCancel],\n );\n\n useInkInput(handleKey);\n\n // Render input with cursor\n const beforeCursor = value.slice(0, cursor);\n const atCursor = value[cursor] ?? \" \";\n const afterCursor = value.slice(cursor + 1);\n const displayValue = value || placeholder;\n\n return React.createElement(\n Dialog,\n {\n title,\n accentColor: \"accent\",\n inputGuide: \"Enter 确认 · Esc 取消\",\n width: 60,\n },\n React.createElement(\n Box,\n { flexDirection: \"column\", marginY: 1 },\n React.createElement(\n Text,\n null,\n beforeCursor || (displayValue === placeholder ? \"\" : \"\"),\n React.createElement(Text, { inverse: true }, atCursor),\n afterCursor,\n value.length === 0 && placeholder\n ? React.createElement(Text, { dimColor: true }, ` ${placeholder}`)\n : null,\n ),\n ),\n );\n}\n","/**\n * DoctorPanel — system diagnostics check display.\n *\n * Shows the results of running the `lynx doctor` diagnostics in a\n * formatted modal. Each check item displays a status icon (✓/⚠/✗),\n * label, and optional detail / fix hint.\n *\n * Triggered by /doctor.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\n\n/** Result of a single diagnostic check. */\nexport interface DoctorCheck {\n /** Human‑readable name of the check. */\n label: string;\n /** Status: \"ok\" = pass, \"warn\" = warning, \"error\" = failed. */\n status: \"ok\" | \"warn\" | \"error\";\n /** Optional detail shown on the same line. */\n detail?: string;\n /** Optional fix hint shown in dimmed text below the check. */\n fixHint?: string;\n}\n\n/** Props for the DoctorPanel component. */\nexport interface DoctorPanelProps {\n /** List of check results to display. */\n checks: DoctorCheck[];\n /** Called when the user cancels (Escape). */\n onCancel: () => void;\n}\n\n/** Icon and color mapping per status. */\nfunction statusIcon(status: DoctorCheck[\"status\"]): { icon: string; color: string } {\n switch (status) {\n case \"ok\":\n return { icon: \"✓\", color: \"green\" };\n case \"warn\":\n return { icon: \"⚠\", color: \"yellow\" };\n case \"error\":\n return { icon: \"✗\", color: \"red\" };\n }\n}\n\n/**\n * System diagnostics panel.\n *\n * Displays each check result with a status icon and optional detail.\n * The Escape key closes the panel (handled by the global handler).\n */\nexport function DoctorPanel({\n checks: initialChecks,\n onCancel,\n}: DoctorPanelProps): React.ReactElement {\n const [checks, setChecks] = useState(initialChecks);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n // 'r' re-runs built-in checks\n if (_input.toLowerCase() === \"r\") {\n setChecks(runBuiltinChecks());\n return;\n }\n },\n [onCancel],\n );\n\n useInkInput(handleKey);\n\n const items: React.ReactNode[] = [];\n\n for (let i = 0; i < checks.length; i++) {\n const check = checks[i]!;\n const { icon, color } = statusIcon(check.status);\n\n items.push(\n React.createElement(\n Box,\n { key: `dr-${i}`, flexDirection: \"column\" },\n React.createElement(\n Box,\n { flexDirection: \"row\" },\n React.createElement(Text, { color }, `${icon} `),\n React.createElement(Text, { bold: check.status === \"error\" }, check.label),\n check.detail ? React.createElement(Text, { dimColor: true }, ` — ${check.detail}`) : null,\n ),\n check.fixHint\n ? React.createElement(Text, { dimColor: true }, ` ${check.fixHint}`)\n : null,\n ),\n );\n }\n\n const okCount = checks.filter((c) => c.status === \"ok\").length;\n const warnCount = checks.filter((c) => c.status === \"warn\").length;\n const errorCount = checks.filter((c) => c.status === \"error\").length;\n\n const subtitle = `${okCount} 通过 · ${warnCount} 警告 · ${errorCount} 错误`;\n\n return React.createElement(\n Dialog,\n {\n title: \"系统诊断\",\n subtitle,\n accentColor: errorCount > 0 ? \"error\" : warnCount > 0 ? \"warning\" : \"success\",\n inputGuide: \"Esc 关闭 · r 重新检查\",\n width: 64,\n },\n React.createElement(Box, { flexDirection: \"column\", marginY: 1 }, ...items),\n );\n}\n\n/**\n * Run built‑in checks synchronously and return results.\n *\n * These checks run within the TUI process and don't require\n * spawning a separate `lynx doctor` subprocess.\n */\nexport function runBuiltinChecks(): DoctorCheck[] {\n const results: DoctorCheck[] = [];\n\n // Node.js version\n const nodeVersion = process.version;\n const nodeMajor = Number.parseInt(nodeVersion.slice(1).split(\".\")[0]!, 10);\n results.push({\n label: \"Node.js\",\n detail: nodeVersion,\n status: nodeMajor >= 18 ? \"ok\" : \"error\",\n fixHint: nodeMajor < 18 ? \"升级到 Node.js 18+\" : undefined,\n });\n\n // Platform\n results.push({\n label: \"平台\",\n detail: `${process.platform} ${process.arch}`,\n status: \"ok\",\n });\n\n // Lynx home directory\n const lynxHome =\n process.env.LYNX_HOME ?? `${process.env.HOME ?? process.env.USERPROFILE ?? \"~\"}/.lynx`;\n results.push({\n label: \"Lynx 目录\",\n detail: lynxHome,\n status: \"ok\",\n });\n\n // Memory usage\n const memMB = Math.round(process.memoryUsage().heapUsed / 1024 / 1024);\n results.push({\n label: \"内存\",\n detail: `${memMB} MB 堆内存`,\n status: memMB < 500 ? \"ok\" : memMB < 900 ? \"warn\" : \"error\",\n fixHint: memMB >= 900 ? \"建议重启或启用自动压缩\" : undefined,\n });\n\n // Uptime\n const uptimeMin = Math.floor(process.uptime() / 60);\n results.push({\n label: \"进程运行时间\",\n detail:\n uptimeMin < 60\n ? `${uptimeMin}分钟`\n : `${Math.floor(uptimeMin / 60)}小时 ${uptimeMin % 60}分钟`,\n status: \"ok\",\n });\n\n return results;\n}\n","/**\n * FilePicker — interactive file selection modal.\n *\n * Walks the workspace directory to collect candidates, then filters\n * in memory as the user types. Supports flat list and tree view modes\n * with git status coloring.\n *\n * Design (§5.9f #2, #10):\n * - Walk workspace (exclude .git, node_modules, dist, build, .venv)\n * - Flat mode: filter by typing, sort by relevance (mtime + match position)\n * - Tree mode: group by directory, expand/collapse with Enter/Tab\n * - Git status colors (M=amber, A=green, D=red, ?=dim)\n * - ↑↓ to navigate, Enter to select file, Esc to cancel\n * - Tab to toggle flat/tree mode\n * - Ctrl+← or Backspace on empty filter = go to parent directory\n * - Breadcrumb showing current directory path\n * - Max 20,000 candidates, max 15 visible\n */\n\nimport React, { useState, useCallback, useMemo } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { readdirSync, statSync } from \"node:fs\";\nimport { join, relative, dirname, basename } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Props for the FilePicker modal. */\nexport interface FilePickerProps {\n /** Workspace root directory to walk. */\n workspace: string;\n /** Called when the user selects a file (Enter). */\n onSelect: (filePath: string) => void;\n /** Called when the user dismisses (Escape). */\n onCancel: () => void;\n /** Initial filter text (e.g. from @-mention). */\n initialFilter?: string;\n}\n\n/** A candidate file entry with metadata for sorting. */\ninterface FileEntry {\n /** Path relative to workspace. */\n path: string;\n /** Modification time (ms since epoch). */\n mtime: number;\n}\n\n/** Directories to skip during traversal. */\nconst SKIP_DIRS = new Set([\n \".git\",\n \"node_modules\",\n \"dist\",\n \"build\",\n \".venv\",\n \"venv\",\n \"__pycache__\",\n \".next\",\n \".nuxt\",\n \"target\",\n \"coverage\",\n \".cache\",\n \".idea\",\n \".vscode\",\n \"out\",\n \".lynx\",\n]);\n\n/** Max candidate files to collect. */\nconst MAX_CANDIDATES = 20_000;\n/** Max visible items in the list. */\nconst MAX_VISIBLE = 15;\n/** Max recursion depth. */\nconst MAX_DEPTH = 20;\n\n/** Git status code → display color mapping. */\nconst GIT_STATUS_LABEL: Record<string, { label: string; color: string }> = {\n M: { label: \"M\", color: \"#e5c07b\" }, // amber — modified\n A: { label: \"A\", color: \"#98c379\" }, // green — added\n D: { label: \"D\", color: \"#e06c75\" }, // red — deleted\n R: { label: \"R\", color: \"#61afef\" }, // blue — renamed\n C: { label: \"C\", color: \"#61afef\" }, // blue — copied\n \"?\": { label: \"?\", color: \"#5c6370\" }, // grey — untracked\n \"!\": { label: \"!\", color: \"#e06c75\" }, // red — ignored\n};\n\n/** Tree node for directory/file hierarchy. */\ninterface TreeNode {\n name: string;\n path: string;\n isDir: boolean;\n children: TreeNode[];\n file?: FileEntry;\n expanded: boolean;\n}\n\n/** Tree display item (flattened for rendering). */\ninterface TreeItem {\n entry: FileEntry;\n depth: number;\n isLast: boolean;\n isDir: boolean;\n expanded: boolean;\n childCount: number;\n}\n\n/**\n * Recursively walk a directory collecting file paths.\n *\n * Stops at MAX_CANDIDATES to prevent memory issues.\n */\nfunction walkFiles(dir: string, workspace: string, candidates: FileEntry[], depth: number): void {\n if (depth > MAX_DEPTH || candidates.length >= MAX_CANDIDATES) return;\n\n let entries: Array<{ name: string; isDirectory(): boolean; isFile(): boolean }>;\n try {\n // HACK: Node.js @types/node resolves Dirent<NonSharedBuffer> in this TS version,\n // but the runtime value has string names. Cast through unknown.\n entries = readdirSync(dir, { withFileTypes: true }) as unknown as typeof entries;\n } catch {\n return; // Permission denied or other error\n }\n\n for (const entry of entries) {\n if (candidates.length >= MAX_CANDIDATES) break;\n if (entry.name.startsWith(\".\") && entry.name !== \".\" && entry.name !== \"..\") {\n // Skip hidden files/dirs except for explicit include patterns\n // (Phase 5: configurable include list)\n if (!entry.name.startsWith(\".env\")) continue;\n }\n\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name)) continue;\n walkFiles(fullPath, workspace, candidates, depth + 1);\n } else if (entry.isFile()) {\n try {\n const st = statSync(fullPath);\n candidates.push({\n path: relative(workspace, fullPath).replace(/\\\\/g, \"/\"),\n mtime: st.mtimeMs,\n });\n } catch {\n // Stat failed, skip\n }\n }\n }\n}\n\n/**\n * Parse `git status --porcelain` and return a map from relative path → status code.\n *\n * Returns empty map if workspace is not a git repo or git is not available.\n */\nfunction buildGitStatusMap(workspace: string): Map<string, string> {\n const statusMap = new Map<string, string>();\n try {\n const output = execSync(\"git status --porcelain\", {\n cwd: workspace,\n encoding: \"utf-8\",\n timeout: 3000,\n });\n for (const line of output.trim().split(\"\\n\")) {\n if (!line) continue;\n // Format: \"XY path\" where X=staging, Y=worktree status\n const status = line.slice(1, 2).trim() || line.slice(0, 1).trim();\n // For renamed files, the path is \"old -> new\"\n let filePath = line.slice(3).trim();\n const arrowIdx = filePath.indexOf(\" -> \");\n if (arrowIdx > 0) filePath = filePath.slice(arrowIdx + 4);\n statusMap.set(filePath.replace(/\\\\/g, \"/\"), status || \"?\");\n }\n } catch {\n // Not a git repo or git not available — return empty map\n }\n return statusMap;\n}\n\n/**\n * Build a tree of directory nodes from flat file entries.\n *\n * Returns root tree node containing all files organized by directory.\n */\nfunction buildFileTree(files: FileEntry[]): TreeNode {\n const root: TreeNode = { name: \"\", path: \"\", isDir: true, children: [], expanded: true };\n\n for (const file of files) {\n const parts = file.path.split(\"/\");\n let current = root;\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]!;\n const isLast = i === parts.length - 1;\n const fullPath = parts.slice(0, i + 1).join(\"/\");\n let child = current.children.find((c) => c.name === part);\n if (!child) {\n child = { name: part, path: fullPath, isDir: !isLast, children: [], expanded: false };\n if (isLast) child.file = file;\n current.children.push(child);\n }\n current = child;\n }\n }\n\n // Recursively sort: directories first, then files; both alphabetically\n function sortNode(node: TreeNode): void {\n node.children.sort((a, b) => {\n if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n for (const child of node.children) sortNode(child);\n }\n sortNode(root);\n return root;\n}\n\n/**\n * Flatten a tree into a list of TreeItems for display, respecting expand/collapse state.\n */\nfunction flattenTree(\n node: TreeNode,\n depth: number,\n expandedDirs: Set<string>,\n result: TreeItem[],\n): void {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i]!;\n const isLast = i === node.children.length - 1;\n if (child.isDir) {\n const isExpanded = expandedDirs.has(child.path);\n result.push({\n entry: { path: child.path + \"/\", mtime: 0 },\n depth,\n isLast,\n isDir: true,\n expanded: isExpanded,\n childCount: child.children.length,\n });\n if (isExpanded) {\n flattenTree(child, depth + 1, expandedDirs, result);\n }\n } else if (child.file) {\n result.push({\n entry: child.file,\n depth,\n isLast,\n isDir: false,\n expanded: false,\n childCount: 0,\n });\n }\n }\n}\n\n/**\n * Match candidates against a filter string.\n *\n * Returns entries whose path contains the filter (case-insensitive),\n * sorted by relevance: exact prefix match > substring at word boundary > general substring,\n * with mtime as tiebreaker (newer files first).\n */\nfunction matchCandidates(candidates: FileEntry[], filter: string): FileEntry[] {\n if (!filter) return candidates.slice(0, MAX_VISIBLE);\n\n const lower = filter.toLowerCase();\n const scored: { entry: FileEntry; score: number }[] = [];\n\n for (const entry of candidates) {\n const pathLower = entry.path.toLowerCase();\n const idx = pathLower.indexOf(lower);\n if (idx === -1) continue;\n\n // Score: higher is better\n let score = 0;\n if (idx === 0) score += 1000;\n else if (pathLower[idx - 1] === \"/\" || pathLower[idx - 1] === \"_\") score += 500;\n // Prefer shorter paths (match closer to filename)\n score += Math.max(0, 200 - idx);\n // Boost by recency (max ~100 points for files modified in last hour)\n const hoursAgo = (Date.now() - entry.mtime) / 3_600_000;\n score += Math.max(0, 100 - hoursAgo * 10);\n\n scored.push({ entry, score });\n }\n\n scored.sort((a, b) => b.score - a.score);\n return scored.slice(0, MAX_VISIBLE).map((s) => s.entry);\n}\n\n/**\n * Interactive file picker modal with flat list and tree view modes.\n *\n * Flat mode: files sorted by relevance. Tree mode: files grouped by\n * directory with expand/collapse. Git status colors indicate modifications.\n */\nexport function FilePicker({\n workspace,\n onSelect,\n onCancel,\n initialFilter = \"\",\n}: FilePickerProps): React.ReactElement {\n const theme = getTheme();\n\n // Walk files and git status once on mount\n const candidates = useMemo<FileEntry[]>(() => {\n const results: FileEntry[] = [];\n walkFiles(workspace, workspace, results, 0);\n results.sort((a, b) => b.mtime - a.mtime);\n return results;\n }, [workspace]);\n\n const gitStatusMap = useMemo(() => buildGitStatusMap(workspace), [workspace]);\n\n // Build tree from candidates (stable reference)\n const fileTree = useMemo(() => buildFileTree(candidates), [candidates]);\n\n const [filter, setFilter] = useState(initialFilter);\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [isTreeMode, setIsTreeMode] = useState(false);\n const [expandedDirs, setExpandedDirs] = useState<Set<string>>(new Set());\n /** Current browsed directory (empty = workspace root, shows all files). */\n const [currentDir, setCurrentDir] = useState(\"\");\n\n // In tree mode: flatten tree; in flat mode: match filter\n const treeItems = useMemo<TreeItem[]>(() => {\n if (!isTreeMode) return [];\n const flat: TreeItem[] = [];\n flattenTree(fileTree, 0, expandedDirs, flat);\n // Apply filter\n if (!filter) return flat;\n const lower = filter.toLowerCase();\n return flat.filter(\n (item) =>\n item.entry.path.toLowerCase().includes(lower) ||\n (item.isDir && item.entry.path.toLowerCase().includes(lower)),\n );\n }, [isTreeMode, fileTree, expandedDirs, filter]);\n\n const flatMatched = useMemo(\n () => (!isTreeMode ? matchCandidates(candidates, filter) : []),\n [isTreeMode, candidates, filter],\n );\n\n /** Flat matches further filtered by current browsed directory. */\n const flatDirFiltered = useMemo(() => {\n if (!currentDir) return flatMatched;\n const prefix = currentDir.endsWith(\"/\") ? currentDir : currentDir + \"/\";\n return flatMatched.filter((f) => f.path.startsWith(prefix));\n }, [flatMatched, currentDir]);\n\n const itemCount = isTreeMode ? treeItems.length : flatDirFiltered.length;\n const maxIndex = Math.max(0, itemCount - 1);\n const safeIndex = Math.min(selectedIndex, maxIndex);\n\n // Toggle directory expand/collapse\n const toggleDir = useCallback((dirPath: string) => {\n setExpandedDirs((prev) => {\n const next = new Set(prev);\n if (next.has(dirPath)) next.delete(dirPath);\n else next.add(dirPath);\n return next;\n });\n }, []);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n // Tab toggles flat/tree mode\n if (key.tab) {\n setIsTreeMode((prev) => !prev);\n setSelectedIndex(0);\n return;\n }\n if (key.return) {\n if (isTreeMode) {\n const item = treeItems[safeIndex];\n if (item) {\n if (item.isDir) {\n toggleDir(item.entry.path.replace(/\\/$/, \"\"));\n return;\n }\n onSelect(item.entry.path);\n }\n return;\n }\n const file = flatDirFiltered[safeIndex];\n if (file) {\n // In flat mode, if the matched entry is a directory prefix match,\n // enter that directory instead of selecting the file.\n onSelect(file.path);\n }\n return;\n }\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1));\n return;\n }\n if (key.downArrow) {\n setSelectedIndex(Math.min(maxIndex, selectedIndex + 1));\n return;\n }\n if (key.backspace) {\n if (filter.length > 0) {\n setFilter((f) => f.slice(0, -1));\n setSelectedIndex(0);\n } else if (!isTreeMode && currentDir) {\n // Go to parent directory\n const parent = currentDir.includes(\"/\")\n ? currentDir.slice(0, currentDir.lastIndexOf(\"/\"))\n : \"\";\n setCurrentDir(parent);\n setSelectedIndex(0);\n }\n return;\n }\n if (input.length === 1 && !key.ctrl && !key.meta) {\n setFilter((f) => f + input);\n setSelectedIndex(0);\n }\n },\n [\n isTreeMode,\n treeItems,\n flatDirFiltered,\n safeIndex,\n maxIndex,\n selectedIndex,\n filter,\n currentDir,\n toggleDir,\n onSelect,\n onCancel,\n ],\n );\n\n useInkInput(handleKey);\n\n // ── Render helpers ──────────────────────────────\n\n /** Get the display color for a file path based on git status. */\n function gitColor(filePath: string): string | undefined {\n const status = gitStatusMap.get(filePath);\n if (!status) return undefined;\n const entry = GIT_STATUS_LABEL[status];\n return entry?.color;\n }\n\n /** Format a relative time string. */\n function formatTime(ms: number): string {\n const sec = Math.floor((Date.now() - ms) / 1000);\n if (sec < 60) return `${sec}秒前`;\n if (sec < 3600) return `${Math.floor(sec / 60)}分钟前`;\n if (sec < 86400) return `${Math.floor(sec / 3600)}小时前`;\n return `${Math.floor(sec / 86400)}天前`;\n }\n\n /** Draw tree connector lines for a given depth and isLast flags. */\n function treePrefix(depth: number, isLast: boolean): string {\n if (depth === 0) return \"\";\n let prefix = \"\";\n for (let d = 0; d < depth; d++) {\n prefix += \"│ \";\n }\n return prefix.slice(0, -2) + (isLast ? \"└─ \" : \"├─ \");\n }\n\n // ── Render items ──────────────────────────────\n\n const items: React.ReactElement[] = [];\n\n if (isTreeMode) {\n for (let i = 0; i < treeItems.length; i++) {\n const item = treeItems[i]!;\n const isSelected = i === safeIndex;\n const cursor = isSelected ? \"❯\" : \" \";\n const depthPrefix = treePrefix(item.depth, item.isLast);\n\n if (item.isDir) {\n const icon = item.expanded ? \"▼\" : \"▶\";\n const displayPath = item.entry.path.replace(/\\/$/, \"\");\n const dirName = displayPath.includes(\"/\")\n ? displayPath.slice(displayPath.lastIndexOf(\"/\") + 1)\n : displayPath;\n items.push(\n React.createElement(\n Box,\n { key: `dir:${displayPath}`, flexDirection: \"row\" },\n React.createElement(\n Text,\n {\n color: isSelected ? theme.colors.accent : theme.colors.dim,\n bold: isSelected,\n },\n `${cursor} ${depthPrefix}${icon} ${dirName}/ (${item.childCount})`,\n ),\n ),\n );\n } else {\n const filePath = item.entry.path;\n const fileName = filePath.includes(\"/\")\n ? filePath.slice(filePath.lastIndexOf(\"/\") + 1)\n : filePath;\n const statusColor = gitColor(filePath);\n const status = gitStatusMap.get(filePath);\n const statusLabel = status ? ` ${GIT_STATUS_LABEL[status]?.label ?? status}` : \"\";\n\n items.push(\n React.createElement(\n Box,\n { key: filePath, flexDirection: \"row\" },\n React.createElement(\n Text,\n {\n color: isSelected ? theme.colors.accent : undefined,\n bold: isSelected,\n },\n `${cursor} ${depthPrefix}${fileName}`,\n ),\n statusLabel ? React.createElement(Text, { color: statusColor }, statusLabel) : null,\n React.createElement(Text, { dimColor: true }, ` ${formatTime(item.entry.mtime)}`),\n ),\n );\n }\n }\n } else {\n // Flat mode\n for (let i = 0; i < flatDirFiltered.length; i++) {\n const file = flatDirFiltered[i]!;\n const isSelected = i === safeIndex;\n const prefix = isSelected ? \"❯ \" : \" \";\n const statusColor = gitColor(file.path);\n const status = gitStatusMap.get(file.path);\n const statusLabel = status ? ` ${GIT_STATUS_LABEL[status]?.label ?? status}` : \"\";\n\n items.push(\n React.createElement(\n Box,\n { key: file.path, flexDirection: \"row\" },\n React.createElement(\n Text,\n { color: isSelected ? theme.colors.accent : undefined, bold: isSelected },\n `${prefix}${file.path}`,\n ),\n statusLabel ? React.createElement(Text, { color: statusColor }, statusLabel) : null,\n React.createElement(Text, { dimColor: true }, ` ${formatTime(file.mtime)}`),\n ),\n );\n }\n }\n\n const modeLabel = isTreeMode ? \"树形\" : \"列表\";\n\n return React.createElement(\n Dialog,\n {\n title: \"文件\",\n subtitle: `${modeLabel} · 过滤${filter ? `: ${filter}` : \"\"} (${candidates.length} 个文件)`,\n inputGuide: \"Enter 选择 · Esc 关闭 · Tab 切换视图 · ↑↓ 导航 · 打字过滤\",\n accentColor: \"accent\",\n width: 75,\n },\n // ── Mode indicator ──────────────────────\n React.createElement(\n Box,\n { flexDirection: \"row\", marginBottom: 1 },\n React.createElement(\n Text,\n { color: isTreeMode ? theme.colors.accent : theme.colors.dim, bold: isTreeMode },\n \" 树形 \",\n ),\n React.createElement(Text, { dimColor: true }, \" \"),\n React.createElement(\n Text,\n { color: !isTreeMode ? theme.colors.accent : theme.colors.dim, bold: !isTreeMode },\n \" 列表 \",\n ),\n ),\n // ── Breadcrumb ────────────────────────\n !isTreeMode && currentDir\n ? React.createElement(\n Box,\n { flexDirection: \"row\", marginBottom: 1 },\n React.createElement(Text, { dimColor: true }, \"📁 \"),\n React.createElement(Text, { color: theme.colors.accent }, currentDir + \"/\"),\n React.createElement(\n Text,\n { dimColor: true },\n ` (${flatDirFiltered.length} 项, 退格返回上级)`,\n ),\n )\n : null,\n items.length > 0\n ? React.createElement(Box, { flexDirection: \"column\" }, ...items)\n : React.createElement(\n Text,\n { dimColor: true },\n filter ? ` 无匹配 \"${filter}\" 的文件` : \" 工作区中无文件。\",\n ),\n );\n}\n","/**\n * StashPicker — stashed input browser and restore dialog.\n *\n * Displays previously stashed inputs (LIFO order, newest first)\n * with truncated content previews and timestamps. Users can\n * restore or delete stashed items.\n *\n * Design (§5.9f #15):\n * - LIFO order (newest on top)\n * - Content truncated to 60 chars\n * - ↑↓ to navigate, Enter to restore, Ctrl+D to delete\n * - Max 200 items\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** A single stashed item. */\nexport interface StashEntry {\n /** Unique identifier. */\n id: string;\n /** Truncated content preview. */\n preview: string;\n /** Unix timestamp when stashed. */\n timestamp: number;\n}\n\n/** Props for the StashPicker modal. */\nexport interface StashPickerProps {\n /** Stashed items (newest first). */\n items: StashEntry[];\n /** Called when the user restores an item (Enter). */\n onRestore: (id: string) => void;\n /** Called when the user deletes an item (Ctrl+D). */\n onDelete: (id: string) => void;\n /** Called when the user dismisses (Escape). */\n onCancel: () => void;\n /** Called to stash the current input (Ctrl+S while open is no-op here). */\n}\n\n/** Max visible items. */\nconst MAX_VISIBLE = 12;\n/** Max preview length. */\nconst PREVIEW_LEN = 60;\n\n/**\n * Stash picker modal.\n *\n * Lists stashed inputs with restore and delete actions.\n */\nexport function StashPicker({\n items,\n onRestore,\n onDelete,\n onCancel,\n}: StashPickerProps): React.ReactElement {\n const theme = getTheme();\n const [selectedIndex, setSelectedIndex] = useState(0);\n\n const maxIndex = Math.max(0, items.length - 1);\n const safeIndex = Math.min(selectedIndex, maxIndex);\n const visible = items.slice(0, MAX_VISIBLE);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.return) {\n const item = visible[safeIndex];\n if (item) onRestore(item.id);\n return;\n }\n // Ctrl+D → delete\n if (key.ctrl && input === \"d\") {\n const item = visible[safeIndex];\n if (item) onDelete(item.id);\n return;\n }\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1));\n return;\n }\n if (key.downArrow) {\n setSelectedIndex(Math.min(maxIndex, selectedIndex + 1));\n return;\n }\n },\n [visible, safeIndex, maxIndex, selectedIndex, onRestore, onDelete, onCancel],\n );\n\n useInkInput(handleKey);\n\n // ── Format relative time ──────────────────────\n\n function formatTime(ts: number): string {\n const sec = Math.floor((Date.now() - ts) / 1000);\n if (sec < 60) return \"just now\";\n if (sec < 3600) return `${Math.floor(sec / 60)}m ago`;\n if (sec < 86400) return `${Math.floor(sec / 3600)}h ago`;\n return `${Math.floor(sec / 86400)}d ago`;\n }\n\n // ── Render items ──────────────────────────────\n\n const listItems: React.ReactElement[] = [];\n for (let i = 0; i < visible.length; i++) {\n const item = visible[i]!;\n const isSelected = i === safeIndex;\n const prefix = isSelected ? \"❯ \" : \" \";\n const preview =\n item.preview.length > PREVIEW_LEN ? item.preview.slice(0, PREVIEW_LEN) + \"…\" : item.preview;\n\n listItems.push(\n React.createElement(\n Box,\n { key: item.id, flexDirection: \"row\" },\n React.createElement(\n Text,\n {\n color: isSelected ? theme.colors.accent : undefined,\n bold: isSelected,\n },\n `${prefix}\"${preview}\"`,\n ),\n React.createElement(Text, { dimColor: true }, ` ${formatTime(item.timestamp)}`),\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"Stash\",\n subtitle: `${items.length} stashed item(s)`,\n inputGuide: \"Enter restore · Ctrl+D delete · Esc close · ↑↓ navigate\",\n accentColor: \"accent\",\n width: 70,\n },\n listItems.length > 0\n ? React.createElement(Box, { flexDirection: \"column\" }, ...listItems)\n : React.createElement(Text, { dimColor: true }, \" No stashed items.\"),\n );\n}\n","/**\n * DiffViewer — git diff visualisation triggered by /diff.\n *\n * Displays a file list with git status indicators, then a detailed\n * unified diff view when a file is selected. Data is fetched via\n * the onRequestDiff callback from the CLI bridge layer.\n */\n\nimport React, { useState, useCallback, useEffect } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** A single changed file with diff content. */\nexport interface DiffFile {\n /** Relative file path. */\n path: string;\n /** Git status: M(odified), A(dded), D(eleted), R(enamed). */\n status: string;\n /** Unified diff text. */\n diff: string;\n}\n\n/** Props for the DiffViewer component. */\nexport interface DiffViewerProps {\n /** Async callback that fetches the diff data from git. */\n onRequestDiff?: () => Promise<DiffFile[]>;\n /** Called when the user dismisses the viewer. */\n onCancel: () => void;\n}\n\nconst MAX_VISIBLE = 12;\nconst DIFF_PREVIEW_LINES = 6;\n\n/** Colorise a git status character. */\nfunction statusColor(status: string, theme: ReturnType<typeof getTheme>): string {\n switch (status) {\n case \"M\":\n return theme.colors.warning ?? \"yellow\";\n case \"A\":\n return theme.colors.success ?? \"green\";\n case \"D\":\n return theme.colors.error ?? \"red\";\n case \"R\":\n return theme.colors.accent ?? \"cyan\";\n default:\n return theme.colors.dim ?? \"grey\";\n }\n}\n\n/**\n * Git diff visualisation panel.\n *\n * Two modes:\n * - File list (default): shows changed files with status, preview snippet.\n * - Detail view: full unified diff for the selected file.\n * Arrow keys navigate the file list; Enter opens detail; Escape goes back.\n */\nexport function DiffViewer({ onRequestDiff, onCancel }: DiffViewerProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n\n const [files, setFiles] = useState<DiffFile[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [selectedFile, setSelectedFile] = useState<DiffFile | null>(null);\n const [cursor, setCursor] = useState(0);\n const [diffLines, setDiffLines] = useState<string[]>([]);\n\n const maxIndex = Math.max(0, files.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n // Fetch diff data on mount\n useEffect(() => {\n if (!onRequestDiff) {\n setLoading(false);\n setFiles([]);\n return;\n }\n onRequestDiff()\n .then((data) => {\n setFiles(data);\n setLoading(false);\n })\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n setLoading(false);\n });\n }, [onRequestDiff]);\n\n // Load full diff when a file is selected\n useEffect(() => {\n if (selectedFile) {\n setDiffLines(selectedFile.diff.split(\"\\n\"));\n }\n }, [selectedFile]);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = files.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (selectedFile) {\n // Detail view: only Escape goes back to file list\n if (key.escape) {\n setSelectedFile(null);\n setDiffLines([]);\n }\n return;\n }\n\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n if (key.return && files.length > 0) {\n setSelectedFile(files[safeCursor] ?? null);\n }\n },\n [files, safeCursor, maxIndex, selectedFile],\n );\n\n useInkInput(handleKey);\n\n // ── Detail view — full diff ──────────────────\n\n if (selectedFile) {\n const maxLines = 30;\n const head = diffLines.slice(0, maxLines);\n const truncated = diffLines.length > maxLines;\n const diffNodes = head.map((line, i) => {\n let color = dim;\n if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) color = theme.colors.success ?? \"green\";\n else if (line.startsWith(\"-\") && !line.startsWith(\"---\")) color = theme.colors.error ?? \"red\";\n else if (line.startsWith(\"@@\")) color = theme.colors.accent ?? \"cyan\";\n return React.createElement(Text, { key: i, color }, line);\n });\n if (truncated) {\n diffNodes.push(\n React.createElement(\n Text,\n { key: \"trunc\", color: dim },\n `... 还有 ${diffLines.length - maxLines} 行被截断`,\n ),\n );\n }\n return React.createElement(\n Dialog,\n {\n title: selectedFile.path,\n subtitle: `状态: ${selectedFile.status}`,\n accentColor:\n selectedFile.status === \"D\"\n ? \"error\"\n : selectedFile.status === \"A\"\n ? \"success\"\n : \"warning\",\n inputGuide: \"Esc 返回文件列表\",\n width: 80,\n },\n React.createElement(Box, { flexDirection: \"column\", gap: 0 }, ...diffNodes),\n );\n }\n\n // ── File list view ───────────────────────────\n\n if (loading) {\n return React.createElement(\n Dialog,\n {\n title: \"差异\",\n subtitle: \"读取中...\",\n accentColor: \"dim\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: dim }, \"正在执行 git diff...\"),\n );\n }\n\n if (error) {\n return React.createElement(\n Dialog,\n {\n title: \"差异\",\n subtitle: \"读取失败\",\n accentColor: \"error\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: theme.colors.error }, error),\n );\n }\n\n if (files.length === 0) {\n return React.createElement(\n Dialog,\n { title: \"差异\", subtitle: \"无变更\", accentColor: \"dim\", inputGuide: \"Esc 关闭\", width: 70 },\n React.createElement(Text, { color: dim }, \"工作区无变更。\"),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"差异\",\n subtitle: `${files.length} 个文件变更`,\n accentColor: \"warning\",\n inputGuide: \"↑↓ 导航 · Enter 详细 · Esc 关闭\",\n width: 80,\n },\n ...visible.map((f, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const prefix = isSelected ? \">\" : \" \";\n const sc = statusColor(f.status, theme);\n\n return React.createElement(\n Box,\n { key: f.path, flexDirection: \"column\" },\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color: sc, bold: true }, `[${f.status}]`),\n React.createElement(\n Text,\n { color: isSelected ? theme.colors.accent : undefined },\n f.path,\n ),\n ),\n React.createElement(\n Box,\n { marginLeft: 5 },\n React.createElement(\n Text,\n { color: dim },\n f.diff.split(\"\\n\").slice(0, DIFF_PREVIEW_LINES).join(\"\\n\").substring(0, 60) +\n (f.diff.length > 60 ? \"...\" : \"\"),\n ),\n ),\n );\n }),\n );\n}\n","/**\n * SnapshotBrowser — file snapshot list triggered by /snapshots.\n *\n * Lists all file snapshots with timestamps and labels. Users can\n * browse snapshots and view restore options. Data is fetched via\n * the onRequestSnapshots callback from the CLI bridge layer.\n */\n\nimport React, { useState, useCallback, useEffect } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** A single snapshot record. */\nexport interface SnapshotEntry {\n /** Unique snapshot identifier. */\n id: string;\n /** Unix-ms timestamp when the snapshot was captured. */\n timestamp: number;\n /** Human-readable snapshot label. */\n label: string;\n}\n\n/** Props for the SnapshotBrowser component. */\nexport interface SnapshotBrowserProps {\n /** Async callback that fetches snapshot records. */\n onRequestSnapshots?: () => Promise<SnapshotEntry[]>;\n /** Called when the user dismisses the browser. */\n onCancel: () => void;\n}\n\nconst MAX_VISIBLE = 12;\n\n/** Format a Unix‑ms timestamp to a human‑readable date string. */\nfunction formatTimestamp(ms: number): string {\n const d = new Date(ms);\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;\n}\n\n/**\n * File snapshot browser.\n *\n * Lists all captured snapshots sorted by timestamp (newest first).\n * Arrow keys navigate; currently read‑only (restore support in a future phase).\n */\nexport function SnapshotBrowser({\n onRequestSnapshots,\n onCancel,\n}: SnapshotBrowserProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n\n const [snapshots, setSnapshots] = useState<SnapshotEntry[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [cursor, setCursor] = useState(0);\n\n const maxIndex = Math.max(0, snapshots.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n useEffect(() => {\n if (!onRequestSnapshots) {\n setLoading(false);\n setSnapshots([]);\n return;\n }\n onRequestSnapshots()\n .then((data) => {\n setSnapshots(data);\n setLoading(false);\n })\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n setLoading(false);\n });\n }, [onRequestSnapshots]);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = snapshots.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n },\n [maxIndex],\n );\n\n useInkInput(handleKey);\n\n if (loading) {\n return React.createElement(\n Dialog,\n {\n title: \"快照\",\n subtitle: \"读取中...\",\n accentColor: \"dim\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: dim }, \"正在加载快照列表...\"),\n );\n }\n\n if (error) {\n return React.createElement(\n Dialog,\n {\n title: \"快照\",\n subtitle: \"读取失败\",\n accentColor: \"error\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: theme.colors.error }, error),\n );\n }\n\n if (snapshots.length === 0) {\n return React.createElement(\n Dialog,\n { title: \"快照\", subtitle: \"无快照\", accentColor: \"dim\", inputGuide: \"Esc 关闭\", width: 70 },\n React.createElement(\n Box,\n { flexDirection: \"column\", gap: 1 },\n React.createElement(Text, { color: dim }, \"暂无文件快照。\"),\n React.createElement(\n Text,\n { color: dim },\n \"使用 /stash 暂存输入,或通过 FilePicker 管理文件。\",\n ),\n ),\n );\n }\n\n return React.createElement(\n Dialog,\n {\n title: \"快照\",\n subtitle: `${snapshots.length} 个快照`,\n accentColor: \"accent\",\n inputGuide: \"↑↓ 导航 · Esc 关闭\",\n width: 70,\n },\n ...visible.map((snap, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const prefix = isSelected ? \">\" : \" \";\n const timeStr = formatTimestamp(snap.timestamp);\n\n return React.createElement(\n Box,\n { key: snap.id, flexDirection: \"row\", gap: 2 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color: theme.colors.accent, bold: true }, snap.label),\n React.createElement(Text, { color: dim }, \"—\"),\n React.createElement(Text, { color: dim }, timeStr),\n );\n }),\n );\n}\n","/**\n * TasksPanel — background task monitor triggered by /tasks.\n *\n * Displays the status of background tasks: running, queued, done,\n * and failed. Data is fetched via the onRequestTasks callback from\n * the CLI bridge layer.\n */\n\nimport React, { useState, useCallback, useEffect, useRef } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Task status enum. */\nexport type TaskStatus = \"running\" | \"queued\" | \"done\" | \"failed\";\n\n/** A single background task record. */\nexport interface TaskEntry {\n /** Unique task identifier. */\n id: string;\n /** Human-readable task name. */\n name: string;\n /** Current task status. */\n status: TaskStatus;\n /** Error message if status is \"failed\". */\n error?: string;\n}\n\n/** Props for the TasksPanel component. */\nexport interface TasksPanelProps {\n /** Async callback that fetches the current task list. */\n onRequestTasks?: () => Promise<TaskEntry[]>;\n /** Called when the user dismisses the panel. */\n onCancel: () => void;\n}\n\nconst MAX_VISIBLE = 12;\n/** Poll interval for auto‑refreshing the task list (ms). */\nconst POLL_INTERVAL_MS = 2000;\n\n/** Status icon for each task status. */\nfunction statusIcon(status: TaskStatus): string {\n switch (status) {\n case \"running\":\n return \"⟳\";\n case \"queued\":\n return \"○\";\n case \"done\":\n return \"✓\";\n case \"failed\":\n return \"✗\";\n }\n}\n\n/** Colour for each task status. */\nfunction statusColor(status: TaskStatus, theme: ReturnType<typeof getTheme>): string {\n switch (status) {\n case \"running\":\n return theme.colors.accent ?? \"cyan\";\n case \"queued\":\n return theme.colors.dim ?? \"grey\";\n case \"done\":\n return theme.colors.success ?? \"green\";\n case \"failed\":\n return theme.colors.error ?? \"red\";\n }\n}\n\n/** Status label in Chinese. */\nfunction statusLabel(status: TaskStatus): string {\n switch (status) {\n case \"running\":\n return \"运行中\";\n case \"queued\":\n return \"排队中\";\n case \"done\":\n return \"完成\";\n case \"failed\":\n return \"失败\";\n }\n}\n\n/**\n * Background task monitor panel.\n *\n * Auto‑polls the task list every 2 seconds. Shows status icon,\n * task name, and error detail for failed tasks.\n * Press 'r' to manually refresh.\n */\nexport function TasksPanel({ onRequestTasks, onCancel }: TasksPanelProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n\n const [tasks, setTasks] = useState<TaskEntry[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [cursor, setCursor] = useState(0);\n const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const maxIndex = Math.max(0, tasks.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n const fetchTasks = useCallback(() => {\n if (!onRequestTasks) {\n setLoading(false);\n setTasks([]);\n return;\n }\n onRequestTasks()\n .then((data) => {\n setTasks(data);\n setLoading(false);\n })\n .catch((err: unknown) => {\n // Keep previous data on poll errors\n if (loading) setError(err instanceof Error ? err.message : String(err));\n setLoading(false);\n });\n }, [onRequestTasks, loading]);\n\n // Initial fetch + auto‑poll\n useEffect(() => {\n fetchTasks();\n pollRef.current = setInterval(fetchTasks, POLL_INTERVAL_MS);\n return () => {\n if (pollRef.current) clearInterval(pollRef.current);\n };\n }, [fetchTasks]);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = tasks.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n if (input === \"r\") {\n setLoading(true);\n fetchTasks();\n return;\n }\n },\n [maxIndex, fetchTasks],\n );\n\n useInkInput(handleKey);\n\n if (loading) {\n return React.createElement(\n Dialog,\n {\n title: \"任务\",\n subtitle: \"读取中...\",\n accentColor: \"dim\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: dim }, \"正在获取任务状态...\"),\n );\n }\n\n if (error) {\n return React.createElement(\n Dialog,\n {\n title: \"任务\",\n subtitle: \"读取失败\",\n accentColor: \"error\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: theme.colors.error }, error),\n );\n }\n\n if (tasks.length === 0) {\n return React.createElement(\n Dialog,\n {\n title: \"任务\",\n subtitle: \"无后台任务\",\n accentColor: \"dim\",\n inputGuide: \"Esc 关闭\",\n width: 70,\n },\n React.createElement(Text, { color: dim }, \"当前无后台任务运行。\"),\n );\n }\n\n // Compute counts\n const runningCount = tasks.filter((t) => t.status === \"running\").length;\n const queuedCount = tasks.filter((t) => t.status === \"queued\").length;\n const failedCount = tasks.filter((t) => t.status === \"failed\").length;\n\n return React.createElement(\n Dialog,\n {\n title: \"任务\",\n subtitle: `${tasks.length} 个任务 (${runningCount} 运行中, ${queuedCount} 排队, ${failedCount} 失败)`,\n accentColor: failedCount > 0 ? \"error\" : runningCount > 0 ? \"accent\" : \"dim\",\n inputGuide: \"↑↓ 导航 · r 刷新 · Esc 关闭\",\n width: 80,\n },\n ...visible\n .map((task, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const prefix = isSelected ? \">\" : \" \";\n const sc = statusColor(task.status, theme);\n const icon = statusIcon(task.status);\n\n const children: React.ReactElement[] = [\n React.createElement(\n Box,\n { key: `row-${task.id}`, flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color: sc }, `${icon} ${statusLabel(task.status)}`),\n React.createElement(Text, { bold: true }, task.name),\n ),\n ];\n\n if (task.error) {\n children.push(\n React.createElement(\n Box,\n { key: `err-${task.id}`, marginLeft: 5 },\n React.createElement(Text, { color: theme.colors.error }, `错误: ${task.error}`),\n ),\n );\n }\n\n return children;\n })\n .flat(),\n );\n}\n","/**\n * SkillPicker — fuzzy skill search and quick invocation.\n *\n * Triggered by /skill-pick (or programmatically from InputBox when the\n * user types \"/\" followed by a skill name prefix). Performs fuzzy\n * matching against skill names and descriptions.\n *\n * Arrow keys navigate results; Enter invokes the selected skill;\n * Escape dismisses.\n */\n\nimport React, { useState, useCallback, useMemo } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { SkillInfo } from \"../types.js\";\n\n/** Props for the SkillPicker component. */\nexport interface SkillPickerProps {\n /** All available skills (from builtin, user, project). */\n skills: SkillInfo[];\n /** Called when the user selects a skill (Enter). */\n onSelect(skillName: string): void;\n /** Called when the user dismisses (Escape). */\n onCancel(): void;\n}\n\n/** Maximum number of visible results. */\nconst MAX_VISIBLE = 10;\n\n/**\n * Simple fuzzy match — checks whether all characters in the query\n * appear in order within the target string (case‑insensitive).\n */\nfunction fuzzyMatch(query: string, target: string): boolean {\n const q = query.toLowerCase();\n const t = target.toLowerCase();\n let qi = 0;\n for (let ti = 0; ti < t.length && qi < q.length; ti++) {\n if (t[ti] === q[qi]) qi++;\n }\n return qi === q.length;\n}\n\n/** Score a fuzzy match — earlier matches + consecutive matches rank higher. */\nfunction fuzzyScore(query: string, target: string): number {\n const q = query.toLowerCase();\n const t = target.toLowerCase();\n let score = 0;\n let qi = 0;\n let lastMatch = -2;\n for (let ti = 0; ti < t.length && qi < q.length; ti++) {\n if (t[ti] === q[qi]) {\n // Bonus for early matches and consecutive matches\n score += 100 - ti + (ti === lastMatch + 1 ? 50 : 0);\n qi++;\n lastMatch = ti;\n }\n }\n return qi === q.length ? score : 0;\n}\n\n/** Source label in Chinese. */\nfunction sourceLabel(source: SkillInfo[\"source\"]): string {\n switch (source) {\n case \"builtin\":\n return \"内置\";\n case \"user\":\n return \"用户\";\n case \"project\":\n return \"项目\";\n }\n}\n\n/**\n * Fuzzy skill search modal.\n *\n * The user types a query to filter skills. Results are ranked by\n * fuzzy match score. Arrow keys select; Enter invokes; Escape closes.\n */\nexport function SkillPicker({ skills, onSelect, onCancel }: SkillPickerProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n\n const [query, setQuery] = useState(\"\");\n const [cursor, setCursor] = useState(0);\n\n // Filter and rank skills by fuzzy match against name + description\n const ranked = useMemo(() => {\n if (!query.trim()) return [];\n const scored = skills\n .map((s) => ({\n skill: s,\n score: fuzzyScore(query, s.name) * 2 + fuzzyScore(query, s.description),\n }))\n .filter((e) => e.score > 0)\n .sort((a, b) => b.score - a.score);\n return scored;\n }, [skills, query]);\n\n const maxIndex = Math.max(0, ranked.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n const visible = ranked.slice(0, MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n if (key.tab) {\n setCursor((prev) => (prev + 1) % (maxIndex + 1));\n return;\n }\n if (key.return && ranked.length > 0) {\n onSelect(ranked[safeCursor]!.skill.name);\n return;\n }\n // Typing: append to query unless it's a special key\n if (key.backspace || key.delete) {\n setQuery((prev) => prev.slice(0, -1));\n setCursor(0);\n return;\n }\n if (input && input.length === 1 && !key.ctrl && !key.meta) {\n setQuery((prev) => prev + input);\n setCursor(0);\n }\n },\n [ranked, safeCursor, maxIndex, onSelect, onCancel],\n );\n\n useInkInput(handleKey);\n\n const hasQuery = query.trim().length > 0;\n\n return React.createElement(\n Dialog,\n {\n title: \"技能搜索\",\n subtitle: hasQuery ? `${ranked.length} 个匹配` : `${skills.length} 个技能`,\n accentColor: hasQuery && ranked.length > 0 ? \"accent\" : \"dim\",\n inputGuide: hasQuery ? \"↑↓ 导航 · Enter 选择 · Esc 关闭\" : \"输入关键词搜索 · Esc 关闭\",\n width: 70,\n },\n // Search input\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1, marginBottom: 1 },\n React.createElement(Text, { color: dim }, \"/\"),\n React.createElement(\n Text,\n { color: query ? undefined : dim },\n query || (skills.length > 0 ? \"输入技能名搜索...\" : \"暂无可用的技能\"),\n ),\n React.createElement(Text, { color: dim }, \"█\"),\n ),\n // Results list or empty state\n !hasQuery\n ? React.createElement(Text, { color: dim }, \"输入关键词开始搜索。按 Esc 关闭。\")\n : ranked.length === 0\n ? React.createElement(Text, { color: dim }, `未找到匹配 \"${query}\" 的技能。`)\n : visible.map((entry, idx) => {\n const isSelected = idx === safeCursor;\n const prefix = isSelected ? \">\" : \" \";\n const srcLabel = sourceLabel(entry.skill.source);\n\n return React.createElement(\n Box,\n { key: entry.skill.name, flexDirection: \"column\" },\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(\n Text,\n { color: isSelected ? theme.colors.accent : dim },\n prefix,\n ),\n React.createElement(\n Text,\n { color: isSelected ? theme.colors.accent : undefined, bold: true },\n entry.skill.name,\n ),\n React.createElement(Text, { color: dim }, `[${srcLabel}]`),\n ),\n React.createElement(\n Box,\n { marginLeft: 3 },\n React.createElement(Text, { color: dim }, entry.skill.description || \"无描述\"),\n ),\n );\n }),\n );\n}\n","/**\n * GlobalSearchDialog — 跨工作区文件内容搜索对话框(Ctrl+Shift+F)。\n *\n * 使用 ripgrep (rg) 进行增量流式搜索,结果按文件:行号去重。\n * 宽终端(≥120 列)在右侧显示预览窗格。\n *\n * Design:\n * - 防抖 150ms,流式递增结果(不替换,避免闪烁)\n * - 最大 500 条结果,单文件最多 10 条\n * - Enter → 插入 file:line 到输入框\n * - Tab → 插入 @file#Lline 到输入框(mention 格式)\n * - ↑↓ 导航, Esc 关闭\n */\n\nimport React, { useState, useRef, useCallback, useEffect } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { resolve, relative } from \"node:path\";\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\n\n// ── Types ──────────────────────────────────────────────\n\n/** Props for GlobalSearchDialog — workspace root plus dismiss/insert callbacks. */\nexport interface GlobalSearchDialogProps {\n /** Workspace root for search. */\n workspace: string;\n /** Called when the dialog is dismissed. */\n onCancel: () => void;\n /** Called with text to insert into the input box. */\n onInsert: (text: string) => void;\n}\n\ninterface SearchMatch {\n file: string;\n line: number;\n text: string;\n}\n\n// ── Constants ──────────────────────────────────────────\n\nconst DEBOUNCE_MS = 150;\nconst MAX_MATCHES_PER_FILE = 10;\nconst MAX_TOTAL_MATCHES = 500;\nconst VISIBLE_RESULTS = 12;\nconst PREVIEW_CONTEXT_LINES = 3;\nconst WIDE_TERMINAL = 120;\n\n// ── Ripgrep parser ─────────────────────────────────────\n\n/** Parse a ripgrep -n --no-heading line: \"path:line:text\". */\nfunction parseRgLine(line: string): SearchMatch | null {\n const m = /^(.*?):(\\d+):(.*)$/.exec(line);\n if (!m) return null;\n const [, file, lineStr, text] = m;\n const lineNum = Number(lineStr);\n if (!file || !Number.isFinite(lineNum)) return null;\n return { file, line: lineNum, text: text ?? \"\" };\n}\n\nfunction matchKey(m: SearchMatch): string {\n return `${m.file}:${m.line}`;\n}\n\n// ── File preview ───────────────────────────────────────\n\n/** Read context lines around a match for preview. */\nfunction readPreview(workspace: string, file: string, targetLine: number): string[] | null {\n try {\n const absolute = resolve(workspace, file);\n if (!existsSync(absolute)) return null;\n const content = readFileSync(absolute, \"utf-8\");\n const lines = content.split(\"\\n\");\n const start = Math.max(0, targetLine - PREVIEW_CONTEXT_LINES - 1);\n const end = Math.min(lines.length, targetLine + PREVIEW_CONTEXT_LINES);\n return lines.slice(start, end).map((l, i) => `${start + i + 1}: ${l}`);\n } catch {\n return null;\n }\n}\n\n// ── Component ──────────────────────────────────────────\n\n/** Cross-workspace file content search dialog — uses ripgrep for incremental streaming results. */\nexport function GlobalSearchDialog({\n workspace,\n onCancel,\n onInsert,\n}: GlobalSearchDialogProps): React.ReactElement {\n const theme = getTheme();\n\n const [query, setQuery] = useState(\"\");\n const [matches, setMatches] = useState<SearchMatch[]>([]);\n const [isSearching, setIsSearching] = useState(false);\n const [truncated, setTruncated] = useState(false);\n const [focusedIndex, setFocusedIndex] = useState(0);\n const [previewLines, setPreviewLines] = useState<string[] | null>(null);\n const [rgError, setRgError] = useState<string | null>(null);\n const rgProcRef = useRef<ChildProcess | null>(null);\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const collectedRef = useRef(0);\n\n // ── Run search ──────────────────────────────\n\n const runSearch = useCallback(\n (q: string) => {\n // Kill previous search\n if (rgProcRef.current) {\n rgProcRef.current.kill();\n rgProcRef.current = null;\n }\n\n if (!q.trim()) {\n setMatches([]);\n setIsSearching(false);\n setTruncated(false);\n setRgError(null);\n collectedRef.current = 0;\n return;\n }\n\n setIsSearching(true);\n setTruncated(false);\n setRgError(null);\n collectedRef.current = 0;\n\n // Client-side filter existing results for narrow-down queries\n const queryLower = q.toLowerCase();\n setMatches((prev) => {\n const filtered = prev.filter((m) => m.text.toLowerCase().includes(queryLower));\n return filtered.length === prev.length ? prev : filtered;\n });\n\n const rg = spawn(\n \"rg\",\n [\"--no-heading\", \"-n\", \"-i\", \"-m\", String(MAX_MATCHES_PER_FILE), \"-F\", \"-e\", q, \".\"],\n {\n cwd: workspace,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n },\n );\n\n rgProcRef.current = rg;\n\n let buffer = \"\";\n rg.stdout.on(\"data\", (chunk: Buffer) => {\n buffer += chunk.toString();\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n const parsed: SearchMatch[] = [];\n for (const line of lines) {\n const m = parseRgLine(line);\n if (!m) continue;\n const rel = relative(workspace, resolve(workspace, m.file));\n parsed.push({\n ...m,\n file: rel.startsWith(\"..\") ? m.file.replace(/\\\\/g, \"/\") : rel.replace(/\\\\/g, \"/\"),\n });\n }\n\n if (parsed.length === 0) return;\n collectedRef.current += parsed.length;\n\n setMatches((prev) => {\n const seen = new Set(prev.map(matchKey));\n const fresh = parsed.filter((p) => !seen.has(matchKey(p)));\n if (fresh.length === 0) return prev;\n const next = prev.concat(fresh);\n return next.length > MAX_TOTAL_MATCHES ? next.slice(0, MAX_TOTAL_MATCHES) : next;\n });\n\n if (collectedRef.current >= MAX_TOTAL_MATCHES) {\n rg.kill();\n setTruncated(true);\n setIsSearching(false);\n }\n });\n\n rg.on(\"close\", () => {\n rgProcRef.current = null;\n if (collectedRef.current === 0) {\n setMatches((prev) => (prev.length ? [] : prev));\n }\n setIsSearching(false);\n });\n\n rg.stderr.on(\"data\", (chunk: Buffer) => {\n const msg = chunk.toString().trim();\n if (msg) {\n setRgError(`ripgrep (rg) 未安装或不可用,请安装后重试。${msg ? ` (${msg.slice(0, 200)})` : \"\"}`);\n }\n });\n },\n [workspace],\n );\n\n // ── Debounced query handler ─────────────────\n\n const handleQueryChange = useCallback(\n (newQuery: string) => {\n setQuery(newQuery);\n if (debounceRef.current) clearTimeout(debounceRef.current);\n debounceRef.current = setTimeout(() => runSearch(newQuery), DEBOUNCE_MS);\n },\n [runSearch],\n );\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (rgProcRef.current) rgProcRef.current.kill();\n if (debounceRef.current) clearTimeout(debounceRef.current);\n };\n }, []);\n\n // ── Preview update ──────────────────────────\n\n useEffect(() => {\n const focused = matches[focusedIndex];\n if (!focused) {\n setPreviewLines(null);\n return;\n }\n const lines = readPreview(workspace, focused.file, focused.line);\n setPreviewLines(lines);\n }, [focusedIndex, matches, workspace]);\n\n // ── Safe index ──────────────────────────────\n\n const safeIndex = Math.min(focusedIndex, Math.max(0, matches.length - 1));\n const previewOnRight = true; // Always show preview for now; could be terminal-width aware\n\n // ── Keyboard handler ────────────────────────\n\n useInkInput((input: string, key: Key) => {\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setFocusedIndex((i) => Math.max(0, i - 1));\n return;\n }\n if (key.downArrow) {\n setFocusedIndex((i) => Math.min(matches.length - 1, i + 1));\n return;\n }\n if (key.return) {\n const focused = matches[safeIndex];\n if (focused) {\n onInsert(`${focused.file}:${focused.line} `);\n }\n return;\n }\n if (key.tab) {\n const focused = matches[safeIndex];\n if (focused) {\n onInsert(`@${focused.file}#L${focused.line} `);\n }\n return;\n }\n if (key.backspace) {\n handleQueryChange(query.slice(0, -1));\n return;\n }\n if (input.length === 1 && !key.ctrl && !key.meta) {\n handleQueryChange(query + input);\n setFocusedIndex(0);\n }\n });\n\n // ── Render helpers ──────────────────────────\n\n const matchLabel = isSearching\n ? `搜索中…`\n : query\n ? `${matches.length}${truncated ? \"+\" : \"\"} 条结果`\n : \"输入关键字开始搜索…\";\n\n const focusedMatch = matches[safeIndex] ?? null;\n\n /** Highlight query in text — returns Text children with the match inverted. */\n function highlightText(text: string, q: string): React.ReactNode {\n if (!q) return text;\n const lowered = text.toLowerCase();\n const qLower = q.toLowerCase();\n const idx = lowered.indexOf(qLower);\n if (idx === -1) return text;\n return [\n text.slice(0, idx),\n React.createElement(Text, { key: \"hl\", inverse: true }, text.slice(idx, idx + q.length)),\n text.slice(idx + q.length),\n ];\n }\n\n /** Truncate path to maxLen chars, keeping basename visible. */\n function truncatePath(path: string, maxLen: number): string {\n if (path.length <= maxLen) return path;\n const sep = \"/\";\n const parts = path.split(sep);\n const base = parts[parts.length - 1] ?? path;\n const dir = parts.slice(0, -1).join(sep);\n const maxDir = maxLen - base.length - 4;\n if (maxDir <= 0) return `…/${base.slice(-(maxLen - 2))}`;\n return dir.slice(0, maxDir) + \"…/\" + base;\n }\n\n // ── Render match list ───────────────────────\n\n const renderListItems: React.ReactElement[] = [];\n for (let i = 0; i < Math.min(matches.length, VISIBLE_RESULTS); i++) {\n const m = matches[i]!;\n const isFocused = i === safeIndex;\n const prefix = isFocused ? \"❯ \" : \" \";\n const color = isFocused ? theme.colors.accent : undefined;\n\n renderListItems.push(\n React.createElement(\n Box,\n { key: matchKey(m), flexDirection: \"row\" },\n React.createElement(\n Text,\n { color },\n prefix,\n React.createElement(Text, { dimColor: !isFocused }, truncatePath(m.file, 30)),\n \":\",\n React.createElement(Text, { color: theme.colors.success }, String(m.line)),\n \" \",\n ),\n React.createElement(Text, { color }, highlightText(m.text.trimStart(), query)),\n ),\n );\n }\n\n // ── Render preview ──────────────────────────\n\n const renderPreview: React.ReactElement[] = [];\n if (focusedMatch && previewLines) {\n renderPreview.push(\n React.createElement(\n Text,\n { key: \"preview-header\", dimColor: true, bold: true },\n `── ${focusedMatch.file}:${focusedMatch.line} ──`,\n ),\n );\n for (let i = 0; i < previewLines.length; i++) {\n const line = previewLines[i]!;\n const isTargetLine = line.startsWith(`${focusedMatch.line}:`);\n renderPreview.push(\n React.createElement(\n Text,\n {\n key: `preview-${i}`,\n color: isTargetLine ? theme.colors.accent : undefined,\n dimColor: !isTargetLine,\n inverse: isTargetLine,\n },\n line,\n ),\n );\n }\n } else if (focusedMatch && previewLines === null) {\n renderPreview.push(\n React.createElement(Text, { key: \"loading\", dimColor: true }, \"加载预览中…\"),\n );\n }\n\n // ── Render ──────────────────────────────────\n\n return React.createElement(\n Dialog,\n {\n title: \"全局搜索\",\n subtitle: matchLabel,\n inputGuide: \"Enter 插入路径 · Tab 插入 @mention · Esc 关闭 · ↑↓ 导航\",\n accentColor: \"accent\",\n width: previewOnRight ? 100 : 70,\n },\n // Search input display\n React.createElement(\n Box,\n { flexDirection: \"row\", marginBottom: 1 },\n React.createElement(Text, { color: theme.colors.accent }, \"🔍 \"),\n React.createElement(Text, { color: theme.colors.foreground }, query || \"输入搜索关键字…\"),\n query ? React.createElement(Text, { inverse: true }, \" \") : null,\n ),\n // rg error banner\n rgError\n ? React.createElement(\n Box,\n { marginBottom: 1 },\n React.createElement(Text, { color: theme.colors.error }, `⚠ ${rgError}`),\n )\n : null,\n // Results list\n matches.length > 0\n ? React.createElement(\n Box,\n {\n flexDirection: previewOnRight ? \"row\" : \"column\",\n gap: 2,\n },\n // Left: match list\n React.createElement(Box, { flexDirection: \"column\", flexGrow: 1 }, ...renderListItems),\n // Right: preview\n previewOnRight && renderPreview.length > 0\n ? React.createElement(\n Box,\n {\n flexDirection: \"column\",\n width: 50,\n borderStyle: \"single\",\n borderColor: theme.colors.border,\n paddingX: 1,\n },\n ...renderPreview,\n )\n : null,\n )\n : React.createElement(\n Text,\n { dimColor: true },\n query ? \" 无结果\" : \" 输入关键字开始搜索文件内容…\",\n ),\n );\n}\n","/**\n * McpPanel — MCP server management panel triggered by /mcp.\n *\n * Lists configured MCP servers with connection status, transport type,\n * auth status, tool count, and resource count. Arrow keys navigate,\n * Enter triggers connect/disconnect/reconnect based on current state.\n * Press `d` for detail view, `r` for reconnect.\n *\n * Visual: ● green = connected, ○ dim = disconnected,\n * ◌ yellow = connecting, ✗ red = error\n * 🔒 = authenticated, 🔓 = unauthenticated\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { McpConnectionInfo } from \"../types.js\";\n\n/** Props for the McpPanel component. */\nexport interface McpPanelProps {\n /** List of MCP server connections to display. */\n connections: McpConnectionInfo[];\n /** Called when the user dismisses the panel (Escape). */\n onCancel: () => void;\n /** Called to connect to a server. */\n onConnect?: (serverName: string) => void;\n /** Called to disconnect from a server. */\n onDisconnect?: (serverName: string) => void;\n /** Called to reconnect a failed server. */\n onReconnect?: (serverName: string) => void;\n}\n\n/** Visible items before scrolling. */\nconst MAX_VISIBLE = 12;\n\n/** Transport type display labels. */\nconst TRANSPORT_LABELS: Record<string, string> = {\n stdio: \"stdio\",\n sse: \"SSE\",\n ws: \"WS\",\n inproc: \"inproc\",\n};\n\n/** Status icon and color for each connection state. */\nfunction statusRender(\n status: McpConnectionInfo[\"status\"],\n theme: ReturnType<typeof getTheme>,\n): { icon: string; color: string } {\n switch (status) {\n case \"connected\":\n return { icon: \"●\", color: theme.colors.success ?? \"green\" };\n case \"connecting\":\n return { icon: \"◌\", color: theme.colors.warning ?? \"yellow\" };\n case \"error\":\n return { icon: \"✗\", color: theme.colors.error ?? \"red\" };\n case \"disconnected\":\n default:\n return { icon: \"○\", color: theme.colors.dimmed ?? \"grey\" };\n }\n}\n\n/** Auth status icon. */\nfunction authIcon(authStatus?: string): string {\n if (authStatus === \"authenticated\") return \"🔒\";\n return \"🔓\";\n}\n\n/**\n * Detail view for a single MCP server — shows transport, auth, tools, resources, and errors.\n */\nfunction ServerDetailView({\n server,\n theme,\n}: {\n server: McpConnectionInfo;\n theme: ReturnType<typeof getTheme>;\n}): React.ReactElement {\n const dim = theme.colors.dimmed ?? \"grey\";\n const accent = theme.colors.accent;\n\n return React.createElement(\n Box,\n { flexDirection: \"column\", gap: 1 },\n // Server name + status\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { bold: true, color: accent }, server.name),\n React.createElement(\n Text,\n { color: statusRender(server.status, theme).color },\n `— ${server.detail}`,\n ),\n ),\n // Transport\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: dim }, \"传输:\"),\n React.createElement(Text, {}, server.transport ?? \"未知\"),\n ),\n // Auth status\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: dim }, \"认证:\"),\n React.createElement(\n Text,\n {},\n `${authIcon(server.authStatus)} ${server.authStatus === \"authenticated\" ? \"已认证\" : server.authStatus === \"expired\" ? \"已过期\" : \"未认证\"}`,\n ),\n ),\n // Error detail\n server.status === \"error\"\n ? React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: theme.colors.error ?? \"red\" }, \"错误:\"),\n React.createElement(Text, { color: theme.colors.error ?? \"red\" }, server.detail),\n )\n : null,\n // Tools list\n React.createElement(Text, { bold: true, color: dim }, `工具 (${server.toolCount}):`),\n server.tools && server.tools.length > 0\n ? server.tools.map((tool) =>\n React.createElement(\n Box,\n { key: tool.name, flexDirection: \"row\", gap: 1, marginLeft: 2 },\n React.createElement(Text, { color: accent }, tool.name),\n tool.description\n ? React.createElement(Text, { color: dim }, `— ${tool.description}`)\n : null,\n ),\n )\n : React.createElement(Text, { color: dim, ...{ marginLeft: 2 } }, \"无工具\"),\n // Resources list\n React.createElement(Text, { bold: true, color: dim }, `资源 (${server.resourceCount ?? 0}):`),\n server.resources && server.resources.length > 0\n ? server.resources.map((res) =>\n React.createElement(\n Box,\n { key: res.name, flexDirection: \"row\", gap: 1, marginLeft: 2 },\n React.createElement(Text, { color: accent }, res.name),\n React.createElement(Text, { color: dim }, `— ${res.uri}`),\n ),\n )\n : React.createElement(Text, { color: dim, ...{ marginLeft: 2 } }, \"无资源\"),\n );\n}\n\n/**\n * MCP server management panel.\n *\n * Displays each server's connection state, transport type, auth status,\n * tool count, and resource count. Arrow keys navigate, Enter triggers\n * the appropriate action based on current state. Press `d` for detail view,\n * `r` for reconnect.\n */\nexport function McpPanel({\n connections,\n onCancel,\n onConnect,\n onDisconnect,\n onReconnect,\n}: McpPanelProps): React.ReactElement {\n const theme = getTheme();\n const [cursor, setCursor] = useState(0);\n const [showDetail, setShowDetail] = useState(false);\n const maxIndex = Math.max(0, connections.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = connections.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n // Detail view keybindings\n if (showDetail) {\n if (key.escape || input === \"d\") {\n setShowDetail(false);\n }\n return;\n }\n\n // List view keybindings\n if (key.escape) {\n onCancel();\n return;\n }\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n if (key.return) {\n const server = connections[safeCursor];\n if (!server) return;\n switch (server.status) {\n case \"disconnected\":\n onConnect?.(server.name);\n break;\n case \"error\":\n onReconnect?.(server.name);\n break;\n case \"connected\":\n case \"connecting\":\n onDisconnect?.(server.name);\n break;\n }\n return;\n }\n if (input === \"d\") {\n if (connections[safeCursor]) {\n setShowDetail(true);\n }\n return;\n }\n if (input === \"r\") {\n const server = connections[safeCursor];\n if (server) {\n onReconnect?.(server.name);\n }\n return;\n }\n },\n [connections, safeCursor, maxIndex, onConnect, onDisconnect, onReconnect, onCancel, showDetail],\n );\n\n useInkInput(handleKey);\n\n const accentColor = connections.length > 0 ? \"accent\" : \"dim\";\n const dim = theme.colors.dimmed ?? \"grey\";\n const selectedServer = connections[safeCursor];\n\n // Build the input guide based on current view\n const inputGuide = showDetail\n ? \"d/Esc 返回列表 · Esc 关闭面板\"\n : connections.length > 0\n ? \"↑↓ 导航 · Enter 连接/断开 · r 重连 · d 详情 · Esc 关闭\"\n : \"Esc 关闭\";\n\n return React.createElement(\n Dialog,\n {\n title: \"MCP 服务器\",\n subtitle:\n showDetail && selectedServer\n ? `${selectedServer.name} 详情`\n : `${connections.length} 个服务器`,\n accentColor,\n inputGuide,\n width: 74,\n },\n // Detail view\n showDetail && selectedServer\n ? React.createElement(ServerDetailView, { server: selectedServer, theme })\n : // List view\n connections.length === 0\n ? React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(\n Text,\n { color: dim },\n \"未配置 MCP 服务器。在 ~/.lynx/mcp.json 或项目 .claude/mcp.json 中添加\",\n ),\n )\n : visible.map((conn, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const { icon, color } = statusRender(conn.status, theme);\n const prefix = isSelected ? \">\" : \" \";\n\n return React.createElement(\n Box,\n { key: conn.name, flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color }, icon),\n React.createElement(Text, {}, authIcon(conn.authStatus)),\n React.createElement(Text, { bold: true }, ` ${conn.name}`),\n conn.transport\n ? React.createElement(\n Text,\n { color: dim },\n TRANSPORT_LABELS[conn.transport] ?? conn.transport,\n )\n : null,\n React.createElement(Text, { color: dim }, ` 工具: ${conn.toolCount}`),\n conn.resourceCount !== undefined\n ? React.createElement(Text, { color: dim }, ` 资源: ${conn.resourceCount}`)\n : null,\n React.createElement(Text, { color }, ` — ${conn.detail}`),\n );\n }),\n );\n}\n","/**\n * PluginPanel — plugin management panel triggered by /plugin.\n *\n * Lists installed plugins with version, description, and load state.\n * Arrow keys navigate, Enter toggles load/unload.\n *\n * Visual: ◆ green = loaded, ◇ dim = unloaded\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { PluginInfo } from \"../types.js\";\n\n/** Props for the PluginPanel component. */\nexport interface PluginPanelProps {\n /** List of installed plugins. */\n plugins: PluginInfo[];\n /** Called when the user dismisses the panel (Escape). */\n onCancel: () => void;\n /** Called to load a plugin. */\n onLoad?: (pluginName: string) => void;\n /** Called to unload a plugin. */\n onUnload?: (pluginName: string) => void;\n}\n\nconst MAX_VISIBLE = 12;\n\n/**\n * Plugin management panel.\n *\n * Displays each plugin with its loaded/unloaded state.\n * Enter loads or unloads the selected plugin.\n */\nexport function PluginPanel({\n plugins,\n onCancel,\n onLoad,\n onUnload,\n}: PluginPanelProps): React.ReactElement {\n const theme = getTheme();\n const [cursor, setCursor] = useState(0);\n const maxIndex = Math.max(0, plugins.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = plugins.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const loadedCount = plugins.filter((p) => p.loaded).length;\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n if (key.return) {\n const plugin = plugins[safeCursor];\n if (!plugin) return;\n if (plugin.loaded) {\n onUnload?.(plugin.name);\n } else {\n onLoad?.(plugin.name);\n }\n }\n },\n [plugins, safeCursor, maxIndex, onLoad, onUnload],\n );\n\n useInkInput(handleKey);\n\n const dim = theme.colors.dim ?? \"grey\";\n\n return React.createElement(\n Dialog,\n {\n title: \"插件\",\n subtitle: `${loadedCount} 已加载 / ${plugins.length} 总计`,\n accentColor: plugins.length > 0 ? \"accent\" : \"dim\",\n inputGuide: plugins.length > 0 ? \"↑↓ 导航 · Enter 切换 · Esc 关闭\" : \"Esc 关闭\",\n width: 70,\n },\n plugins.length === 0\n ? React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(\n Text,\n { color: dim },\n \"未安装插件。将插件放入 extensions/ 或通过 lynx plugin install 安装\",\n ),\n )\n : visible.map((plugin, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const icon = plugin.loaded ? \"◆\" : \"◇\";\n const iconColor = plugin.loaded ? (theme.colors.success ?? \"green\") : dim;\n const prefix = isSelected ? \">\" : \" \";\n\n return React.createElement(\n Box,\n {\n key: plugin.name,\n flexDirection: \"column\",\n marginBottom: idx < visible.length - 1 ? 0 : undefined,\n },\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color: iconColor }, icon),\n React.createElement(Text, { bold: true }, ` ${plugin.name}`),\n React.createElement(Text, { color: dim }, `v${plugin.version}`),\n ),\n React.createElement(\n Box,\n { marginLeft: 4 },\n React.createElement(Text, { color: dim }, plugin.description || \"无描述\"),\n ),\n );\n }),\n );\n}\n","/**\n * SkillPanel — skill discovery panel triggered by /skills.\n *\n * Lists all discovered skills (builtin, user, project) with name,\n * description, and source origin. Read-only display — no actions\n * beyond navigation and dismiss.\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { SkillInfo } from \"../types.js\";\n\n/** Props for the SkillPanel component. */\nexport interface SkillPanelProps {\n /** List of discovered skills. */\n skills: SkillInfo[];\n /** Called when the user dismisses the panel (Escape). */\n onCancel: () => void;\n}\n\nconst MAX_VISIBLE = 12;\n\n/** Short label for each source origin. */\nfunction sourceLabel(source: SkillInfo[\"source\"]): string {\n switch (source) {\n case \"builtin\":\n return \"内置\";\n case \"user\":\n return \"用户\";\n case \"project\":\n return \"项目\";\n }\n}\n\n/** Color for each source origin. */\nfunction sourceColor(source: SkillInfo[\"source\"], theme: ReturnType<typeof getTheme>): string {\n switch (source) {\n case \"builtin\":\n return theme.colors.accent ?? \"cyan\";\n case \"user\":\n return theme.colors.success ?? \"green\";\n case \"project\":\n return theme.colors.warning ?? \"yellow\";\n }\n}\n\n/**\n * Skill discovery panel.\n *\n * Read-only list of all skills from builtin, user, and project sources.\n * Arrow keys scroll through the list.\n */\nexport function SkillPanel({ skills, onCancel }: SkillPanelProps): React.ReactElement {\n const theme = getTheme();\n const [cursor, setCursor] = useState(0);\n const maxIndex = Math.max(0, skills.length - 1);\n const safeCursor = Math.min(cursor, maxIndex);\n\n const startIdx = Math.max(0, safeCursor - Math.floor(MAX_VISIBLE / 2));\n const visible = skills.slice(startIdx, startIdx + MAX_VISIBLE);\n\n const handleKey = useCallback(\n (input: string, key: Key) => {\n if (key.upArrow) {\n setCursor((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow) {\n setCursor((prev) => Math.min(maxIndex, prev + 1));\n return;\n }\n },\n [maxIndex],\n );\n\n useInkInput(handleKey);\n\n const dim = theme.colors.dim ?? \"grey\";\n\n return React.createElement(\n Dialog,\n {\n title: \"技能\",\n subtitle: `发现 ${skills.length} 个技能`,\n accentColor: skills.length > 0 ? \"accent\" : \"dim\",\n inputGuide: skills.length > 0 ? \"↑↓ 导航 · Esc 关闭\" : \"Esc 关闭\",\n width: 70,\n },\n skills.length === 0\n ? React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(\n Text,\n { color: dim },\n \"未发现技能。将技能放入 ~/.lynx/skills/ 或项目 .claude/skills/\",\n ),\n )\n : visible.map((skill, idx) => {\n const globalIdx = startIdx + idx;\n const isSelected = globalIdx === safeCursor;\n const prefix = isSelected ? \">\" : \" \";\n const srcColor = sourceColor(skill.source, theme);\n\n return React.createElement(\n Box,\n {\n key: skill.name,\n flexDirection: \"column\",\n },\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: isSelected ? theme.colors.accent : dim }, prefix),\n React.createElement(Text, { color: theme.colors.accent, bold: true }, skill.name),\n React.createElement(Text, { color: dim }, \"—\"),\n React.createElement(Text, { color: srcColor }, `[${sourceLabel(skill.source)}]`),\n ),\n React.createElement(\n Box,\n { marginLeft: 3 },\n React.createElement(Text, { color: dim }, skill.description || \"无描述\"),\n ),\n );\n }),\n );\n}\n","/**\n * ContextPanel — context information panel triggered by /context.\n *\n * Displays the current session's context: session label, model,\n * workspace, memory facts, rules, and skills count.\n * Read-only display with 'r' to refresh.\n */\n\nimport React, { useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { ContextInfo } from \"../types.js\";\n\n/** Props for the ContextPanel component. */\nexport interface ContextPanelProps {\n /** Current context information. */\n contextInfo: ContextInfo;\n /** Called when the user dismisses the panel (Escape). */\n onCancel: () => void;\n}\n\n/** A single label: value row in the context panel. */\nfunction InfoRow({\n label,\n value,\n dim,\n}: {\n label: string;\n value: string;\n dim: string;\n}): React.ReactElement {\n return React.createElement(\n Box,\n { flexDirection: \"row\", gap: 2 },\n React.createElement(Box, { width: 16 }, React.createElement(Text, { color: dim }, label)),\n React.createElement(Text, {}, value),\n );\n}\n\n/**\n * Context information panel.\n *\n * Displays session/model/workspace metadata and loaded resource counts.\n * Press 'r' to request a refresh (the parent handles re-querying contextInfo).\n */\nexport function ContextPanel({ contextInfo, onCancel }: ContextPanelProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n const accent = theme.colors.accent ?? \"cyan\";\n\n const handleKey = useCallback((input: string, key: Key) => {\n // 'r' for refresh — parent re-queries by re-rendering with new contextInfo\n // (no explicit callback needed; the modal re-render is a signal)\n }, []);\n\n useInkInput(handleKey);\n\n return React.createElement(\n Dialog,\n {\n title: \"上下文\",\n subtitle: contextInfo.sessionLabel,\n accentColor: \"accent\",\n inputGuide: \"r 刷新 · Esc 关闭\",\n width: 70,\n },\n React.createElement(\n Box,\n { flexDirection: \"column\", gap: 1, paddingY: 1 },\n // Section: Session\n React.createElement(Text, { bold: true, color: accent }, \"会话\"),\n React.createElement(InfoRow, { label: \"会话\", value: contextInfo.sessionLabel, dim }),\n React.createElement(InfoRow, { label: \"模型\", value: contextInfo.model, dim }),\n React.createElement(InfoRow, { label: \"工作区\", value: contextInfo.workspace, dim }),\n // Separator\n React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(Text, { color: dim }, \"─\".repeat(60)),\n ),\n // Section: Resources\n React.createElement(Text, { bold: true, color: accent }, \"资源\"),\n React.createElement(InfoRow, {\n label: \"记忆条目\",\n value: String(contextInfo.memoryFacts),\n dim,\n }),\n React.createElement(InfoRow, { label: \"规则\", value: String(contextInfo.rules), dim }),\n React.createElement(InfoRow, { label: \"技能\", value: String(contextInfo.skills), dim }),\n ),\n );\n}\n","/**\n * UsagePanel — usage statistics panel triggered by /usage.\n *\n * Displays session token count, estimated cost, budget consumption,\n * turn count, and model pricing. Features a visual budget bar that\n * changes color based on remaining budget.\n *\n * Budget bar colors: green (<50%), yellow (50‑80%), red (>80%),\n * dim (unlimited / no budget set).\n */\n\nimport React, { useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { Dialog } from \"./Dialog.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { UsageInfo } from \"../types.js\";\n\n/** Props for the UsagePanel component. */\nexport interface UsagePanelProps {\n /** Current usage statistics. */\n usageInfo: UsageInfo;\n /** Called when the user dismisses the panel (Escape). */\n onCancel: () => void;\n}\n\n/** Budget bar configuration. */\nconst BAR_WIDTH = 40;\nconst BAR_FILLED = \"█\";\nconst BAR_EMPTY = \"░\";\n\n/** A single stat tile in the stats grid. */\nfunction StatTile({\n label,\n value,\n dim,\n accent,\n}: {\n label: string;\n value: string;\n dim: string;\n accent: string;\n}): React.ReactElement {\n return React.createElement(\n Box,\n { flexDirection: \"column\", width: 20 },\n React.createElement(Text, { color: dim }, label),\n React.createElement(Text, { color: accent, bold: true }, value),\n );\n}\n\n/**\n * Usage statistics panel.\n *\n * Shows token usage, cost, budget consumption, turn count, and pricing.\n * The budget bar visualises budget consumption with color-coded thresholds.\n * Read-only; Esc to close.\n */\nexport function UsagePanel({ usageInfo, onCancel }: UsagePanelProps): React.ReactElement {\n const theme = getTheme();\n const dim = theme.colors.dim ?? \"grey\";\n const accent = theme.colors.accent ?? \"cyan\";\n\n const handleKey = useCallback((input: string, key: Key) => {\n // Read-only, no keyboard actions beyond Escape (handled globally)\n }, []);\n\n useInkInput(handleKey);\n\n // ── Budget bar ────────────────────────────────\n\n const hasBudget = usageInfo.budgetMaxTokens > 0 || usageInfo.budgetMaxUsd > 0;\n const maxUsd = usageInfo.budgetMaxUsd || Infinity;\n const ratio = maxUsd > 0 ? Math.min(usageInfo.costUsd / maxUsd, 1) : 0;\n\n let barColor = theme.colors.success ?? \"green\";\n if (ratio > 0.8) barColor = theme.colors.error ?? \"red\";\n else if (ratio > 0.5) barColor = theme.colors.warning ?? \"yellow\";\n else if (!hasBudget) barColor = dim;\n\n const filledCount = hasBudget ? Math.round(ratio * BAR_WIDTH) : 0;\n const emptyCount = BAR_WIDTH - filledCount;\n const bar = BAR_FILLED.repeat(filledCount) + BAR_EMPTY.repeat(emptyCount);\n\n const percentage = hasBudget ? `${Math.round(ratio * 100)}%` : \"∞\";\n const budgetLabel = hasBudget\n ? `$${usageInfo.costUsd.toFixed(4)} / $${maxUsd.toFixed(2)}`\n : `$${usageInfo.costUsd.toFixed(4)} (unlimited)`;\n\n // ── Stats ─────────────────────────────────────\n\n const tokensFormatted =\n usageInfo.tokensUsed >= 1000\n ? `${(usageInfo.tokensUsed / 1000).toFixed(1)}K`\n : String(usageInfo.tokensUsed);\n\n return React.createElement(\n Dialog,\n {\n title: \"用量\",\n subtitle: `本会话 ${usageInfo.turns} 轮`,\n accentColor: ratio > 0.8 ? \"error\" : ratio > 0.5 ? \"warning\" : \"accent\",\n inputGuide: \"Esc 关闭\",\n width: 68,\n },\n React.createElement(\n Box,\n { flexDirection: \"column\", gap: 1, paddingY: 1 },\n // Budget bar section\n React.createElement(Text, { bold: true, color: dim }, \"预算\"),\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 1 },\n React.createElement(Text, { color: barColor }, bar),\n React.createElement(Text, { color: barColor }, ` ${percentage}`),\n ),\n React.createElement(Text, { color: dim }, budgetLabel),\n // Separator\n React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(Text, { color: dim }, \"─\".repeat(60)),\n ),\n // Stats grid\n React.createElement(Text, { bold: true, color: dim }, \"统计\"),\n React.createElement(\n Box,\n { flexDirection: \"row\", gap: 4, paddingTop: 1 },\n React.createElement(StatTile, {\n label: \"Token 用量\",\n value: tokensFormatted,\n dim,\n accent,\n }),\n React.createElement(StatTile, {\n label: \"费用 (USD)\",\n value: `$${usageInfo.costUsd.toFixed(4)}`,\n dim,\n accent,\n }),\n React.createElement(StatTile, {\n label: \"轮数\",\n value: String(usageInfo.turns),\n dim,\n accent,\n }),\n ),\n // Separator\n React.createElement(\n Box,\n { paddingY: 1 },\n React.createElement(Text, { color: dim }, \"─\".repeat(60)),\n ),\n // Pricing info\n React.createElement(Text, { bold: true, color: dim }, \"模型定价\"),\n React.createElement(Text, { color: dim }, usageInfo.modelPricing || \"暂无\"),\n ),\n );\n}\n","/**\n * WelcomeScreen — safety confirmation screen shown before entering the REPL.\n *\n * Rendered after Phase 1 bootstrap completes. The user must explicitly\n * confirm they trust the current workspace before Phase 2 starts.\n *\n * Design (§5.1a):\n * - Unicode box‑drawing border (━)\n * - Workspace path + version display\n * - Context‑aware safety prompt (first visit vs returning)\n * - ↑↓ to switch selection, Enter to confirm, Esc to exit\n */\n\nimport React, { useState, useCallback } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport { getTheme } from \"../theme/theme.js\";\n\n/** Props for the WelcomeScreen component. */\nexport interface WelcomeScreenProps {\n /** Workspace directory path. */\n workspace: string;\n /** Lynx version string. */\n version: string;\n /** Last session info — null on first visit. */\n lastSession?: { label: string; relativeTime: string; sessionCount: number };\n /** Called when the user confirms (trusts the workspace). */\n onConfirm: () => void;\n /** Called when the user exits (does not trust / cancels). */\n onExit: () => void;\n}\n\n/** Safety prompt for first visit to a workspace. */\nconst FIRST_VISIT_PROMPT =\n \"Lynx 可以读取、编辑和执行此工作区中的文件。请确认这是您创建或信任的项目后再继续。\";\n\n/** Index constants for the two options. */\nconst OPTION_TRUST = 0;\nconst OPTION_EXIT = 1;\n\n/**\n * Safety confirmation screen.\n *\n * The user is shown workspace info and must confirm before\n * Lynx starts Phase 2 (loading sessions, MCP, memory, etc.).\n */\nexport function WelcomeScreen({\n workspace,\n version,\n lastSession,\n onConfirm,\n onExit,\n}: WelcomeScreenProps): React.ReactElement {\n const theme = getTheme();\n const accent = theme.colors.accent;\n const [selected, setSelected] = useState(OPTION_TRUST);\n\n // ── Keyboard handler ──────────────────────────\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n if (key.upArrow || key.downArrow) {\n setSelected((prev) => (prev === OPTION_TRUST ? OPTION_EXIT : OPTION_TRUST));\n return;\n }\n if (key.return) {\n if (selected === OPTION_TRUST) onConfirm();\n else onExit();\n return;\n }\n if (key.escape) {\n onExit();\n }\n },\n [selected, onConfirm, onExit],\n );\n\n useInkInput(handleKey);\n\n // ── Safety prompt text ────────────────────────\n\n const promptText = lastSession\n ? `Lynx 可以读取、编辑和执行此工作区中的文件。\\n\\n` +\n `上次会话:${lastSession.label}(${lastSession.relativeTime})\\n` +\n `您在此工作区中有 ${lastSession.sessionCount} 次历史会话。`\n : FIRST_VISIT_PROMPT;\n\n const isTrustSelected = selected === OPTION_TRUST;\n\n return React.createElement(\n Box,\n { flexDirection: \"column\", paddingY: 1 },\n\n // ── Top border ────────────────────────────────\n React.createElement(Text, { dimColor: true }, \"━\".repeat(72)),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Title ─────────────────────────────────────\n React.createElement(Text, { bold: true, color: accent }, \" Lynx\"),\n React.createElement(Text, { dimColor: true }, ` v${version}`),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Workspace ─────────────────────────────────\n React.createElement(\n Text,\n null,\n \" Workspace: \",\n React.createElement(Text, { color: accent }, workspace),\n ),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Safety prompt ─────────────────────────────\n React.createElement(Text, null, ` ${promptText}`),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Options ───────────────────────────────────\n React.createElement(\n Text,\n { color: isTrustSelected ? accent : undefined, bold: isTrustSelected },\n isTrustSelected ? ` ❯ 1. 是,我信任此文件夹` : ` 1. 是,我信任此文件夹`,\n ),\n React.createElement(\n Text,\n {\n color: !isTrustSelected ? accent : undefined,\n bold: !isTrustSelected,\n dimColor: isTrustSelected,\n },\n !isTrustSelected ? ` ❯ 2. 否,退出` : ` 2. 否,退出`,\n ),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Key guide ─────────────────────────────────\n React.createElement(Text, { dimColor: true }, \" Enter 确认 · Esc 取消\"),\n\n // Spacer\n React.createElement(Box, { height: 1 }),\n\n // ── Bottom border ─────────────────────────────\n React.createElement(Text, { dimColor: true }, \"━\".repeat(72)),\n );\n}\n","/**\n * useTerminalSize — track stdout dimensions via Ink's useStdout hook.\n *\n * Returns { columns, rows } and updates on terminal resize events.\n */\n\nimport { useState, useEffect } from \"react\";\nimport { useStdout } from \"ink\";\n\n/** Terminal dimensions — columns and rows for layout calculations. */\nexport interface TerminalSize {\n columns: number;\n rows: number;\n}\n\n/** Default fallback when stdout dimensions are unavailable. */\nconst DEFAULT_SIZE: TerminalSize = { columns: 80, rows: 24 };\n\n/**\n * Hook that returns the current terminal dimensions.\n * Updates when the terminal is resized.\n */\nexport function useTerminalSize(): TerminalSize {\n const { stdout } = useStdout();\n const [size, setSize] = useState<TerminalSize>(() => ({\n columns: stdout?.columns ?? DEFAULT_SIZE.columns,\n rows: stdout?.rows ?? DEFAULT_SIZE.rows,\n }));\n\n useEffect(() => {\n if (!stdout) return;\n\n const onResize = () => {\n setSize({\n columns: stdout.columns ?? DEFAULT_SIZE.columns,\n rows: stdout.rows ?? DEFAULT_SIZE.rows,\n });\n };\n\n stdout.on(\"resize\", onResize);\n return () => {\n stdout.off(\"resize\", onResize);\n };\n }, [stdout]);\n\n return size;\n}\n","/**\n * ScrollBox — scrollable container with imperative API and windowed rendering.\n *\n * In standard Ink 6.x there is no native overflow:scroll — terminal output\n * is a linear stream. ScrollBox simulates scrolling by only rendering\n * children that intersect the visible viewport, at the cost of needing\n * child‑height hints.\n *\n * This is the foundation for the ChatLog message list, modal content\n * areas, and any other scrollable region in the TUI.\n *\n * Design (§5.9b #1.6.1): imperative scroll API, sticky‑scroll mode,\n * viewport culling, and subscriber notifications.\n */\n\nimport React, { useState, useCallback, useRef, useImperativeHandle, forwardRef } from \"react\";\nimport { Box, useInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport type { ReactNode } from \"react\";\n\n// ── Imperative handle ────────────────────────────────\n\n/** Imperative API for controlling scroll position. */\nexport interface ScrollBoxHandle {\n /** Scroll to an absolute vertical offset. */\n scrollTo(y: number): void;\n /** Scroll by a relative delta (negative = up, positive = down). */\n scrollBy(dy: number): void;\n /** Scroll to the bottom and re‑enable sticky mode. */\n scrollToBottom(): void;\n /** Get current scroll offset. */\n getScrollTop(): number;\n /** Get total content height (number of logical rows). */\n getScrollHeight(): number;\n /** Whether the viewport is pinned to the bottom. */\n isSticky(): boolean;\n /** Subscribe to imperative scroll changes. Returns unsubscribe fn. */\n subscribe(listener: () => void): () => void;\n}\n\n// ── Props ─────────────────────────────────────────────\n\n/** Props for the ScrollBox component. */\nexport interface ScrollBoxProps {\n /** Children to render inside the scrollable area. */\n children: ReactNode;\n /** Height of the visible viewport in logical rows. */\n height: number;\n /**\n * Total number of logical rows in the content.\n * If a single number, all rows are assumed equal height.\n */\n totalRows: number;\n /** When true, auto‑pins to bottom on content growth. */\n stickyScroll?: boolean;\n /** Called when scroll position changes. */\n onScroll?: (scrollTop: number) => void;\n}\n\n// ── Component ─────────────────────────────────────────\n\n/**\n * Scrollable container with imperative scroll control.\n *\n * Only renders children that intersect [scrollTop, scrollTop + height].\n * Supports keyboard navigation: PageUp/Down, Home/End, arrow keys.\n *\n * Limitations in standard Ink:\n * - No smooth pixel‑level scrolling (Yoga‑based layout)\n * - Children above/below the viewport are not rendered at all\n * - Height must be known ahead of time (no auto‑measurement)\n */\n/** Virtual scrolling container — renders a viewport slice of children with a scroll offset. */\nexport const ScrollBox = forwardRef<ScrollBoxHandle, ScrollBoxProps>(function ScrollBox(\n { children, height, totalRows, stickyScroll: initialSticky = true, onScroll },\n ref,\n): React.ReactElement {\n const [scrollTop, setScrollTop] = useState(0);\n const [stickyScroll, setStickyScroll] = useState(initialSticky);\n\n // Stable refs for use in the imperative handle (avoids stale closures)\n const scrollTopRef = useRef(scrollTop);\n scrollTopRef.current = scrollTop;\n const stickyRef = useRef(stickyScroll);\n stickyRef.current = stickyScroll;\n const listenersRef = useRef(new Set<() => void>());\n\n /** Clamp scrollTop to valid range. */\n const clamp = useCallback(\n (y: number): number => {\n const maxScroll = Math.max(0, totalRows - height);\n return Math.max(0, Math.min(y, maxScroll));\n },\n [totalRows, height],\n );\n\n /** Notify all subscribers of a scroll change. */\n const notify = useCallback(() => {\n for (const listener of listenersRef.current) {\n listener();\n }\n }, []);\n\n /** Update scroll position and notify. */\n const updateScroll = useCallback(\n (y: number, sticky?: boolean) => {\n const clamped = clamp(y);\n scrollTopRef.current = clamped;\n setScrollTop(clamped);\n if (sticky !== undefined) {\n stickyRef.current = sticky;\n setStickyScroll(sticky);\n }\n onScroll?.(clamped);\n notify();\n },\n [clamp, onScroll, notify],\n );\n\n // ── Imperative handle ──────────────────────────\n\n useImperativeHandle(\n ref,\n (): ScrollBoxHandle => ({\n scrollTo(y: number) {\n updateScroll(y, false);\n },\n scrollBy(dy: number) {\n updateScroll(scrollTopRef.current + dy, false);\n },\n scrollToBottom() {\n updateScroll(totalRows - height, true);\n },\n getScrollTop() {\n return scrollTopRef.current;\n },\n getScrollHeight() {\n return totalRows;\n },\n isSticky() {\n return stickyRef.current;\n },\n subscribe(listener: () => void) {\n listenersRef.current.add(listener);\n return () => {\n listenersRef.current.delete(listener);\n };\n },\n }),\n [updateScroll, totalRows, height],\n );\n\n // ── Keyboard navigation ────────────────────────\n\n const handleKey = useCallback(\n (_input: string, key: Key) => {\n const pageStep = Math.max(1, Math.floor(height / 2));\n if (key.pageUp) {\n updateScroll(scrollTopRef.current + pageStep, false);\n } else if (key.pageDown) {\n const next = scrollTopRef.current - pageStep;\n if (next <= 0) {\n updateScroll(0, true);\n } else {\n updateScroll(next, false);\n }\n } else if (key.upArrow) {\n updateScroll(scrollTopRef.current + 1, false);\n } else if (key.downArrow) {\n const next = scrollTopRef.current - 1;\n if (next <= 0) {\n updateScroll(0, true);\n } else {\n updateScroll(next, false);\n }\n } else if (key.home) {\n updateScroll(0, false);\n } else if (key.end) {\n updateScroll(0, true); // bottom = 0 offset from bottom\n }\n },\n [updateScroll, height],\n );\n\n useInput(handleKey);\n\n // ── Viewport culling ───────────────────────────\n\n // Compute which logical child range is visible.\n // Assumes 1:1 child‑to‑row mapping.\n const visibleStart = scrollTop;\n const visibleEnd = Math.min(scrollTop + height, totalRows);\n\n // Only render children that intersect [visibleStart, visibleEnd].\n // Children must be an array for this to work; if a single ReactNode,\n // pass it through as‑is (caller is responsible for height).\n const childArray = React.Children.toArray(children);\n const visibleChildren = childArray.slice(visibleStart, visibleEnd);\n\n // ── Render ─────────────────────────────────────\n\n return React.createElement(\n Box,\n {\n flexDirection: \"column\",\n height,\n overflow: \"hidden\",\n },\n ...visibleChildren,\n );\n});\n","/**\n * FullscreenLayout — three‑slot terminal layout for the Lynx REPL.\n *\n * Mirrors Claude Code's FullscreenLayout API: `header`, `scrollable`,\n * `bottom` props, with an optional `overlay` slot for permission prompts\n * and `modal` for full‑screen dialogs.\n *\n * In fullscreen mode (alt buffer + mouse tracking) the three slots are\n * stacked vertically: header (fixed height) → scrollable (flexGrow)\n * → bottom (fixed height). The scrollable region uses ScrollBox for\n * viewport‑culled rendering with sticky‑scroll support.\n *\n * Design (§5.3a #1.2): three‑slot model with terminal resize adaptation.\n */\n\nimport React, { createContext, useState, useCallback, useRef, useMemo } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useTerminalSize } from \"../hooks/useTerminalSize.js\";\nimport { ScrollBox } from \"./ink/ScrollBox.js\";\nimport type { ScrollBoxHandle } from \"./ink/ScrollBox.js\";\nimport { getTheme } from \"../theme/theme.js\";\nimport type { ReactNode } from \"react\";\n\n// ── Scroll chrome context ──────────────────────────────\n\n/** Entry for the sticky prompt header. */\nexport interface StickyPrompt {\n text: string;\n /** Number of unseen messages (for the pill). */\n newCount: number;\n}\n\n/** Context for scroll‑derived chrome (sticky header, jump‑to‑bottom pill). */\nexport const ScrollChromeContext = createContext<{\n setStickyPrompt: (p: StickyPrompt | null) => void;\n}>({\n setStickyPrompt: () => {},\n});\n\n// ── Props ─────────────────────────────────────────────\n\n/** Props for the FullscreenLayout component. */\nexport interface FullscreenLayoutProps {\n /** Content pinned to the top (header bar: brand, session, model, cost). */\n header?: ReactNode;\n /** Content that scrolls (messages, tool output). */\n scrollable: ReactNode;\n /** Content pinned to the bottom (prompt input, status line). */\n bottom: ReactNode;\n /** Optional overlay rendered inside the scrollable area (permission prompt). */\n overlay?: ReactNode;\n /** Optional absolute‑positioned modal pane (dialogs, pickers). */\n modal?: ReactNode;\n /** Ref to the ScrollBox's imperative handle for keyboard scrolling. */\n scrollRef?: React.RefObject<ScrollBoxHandle | null>;\n /** Force‑hide the jump‑to‑bottom pill. */\n hidePill?: boolean;\n /** Number of unseen messages for the pill. 0 → \"Jump to bottom\". */\n newMessageCount?: number;\n /** Called when the user clicks the pill. */\n onPillClick?: () => void;\n}\n\n// ── Component ──────────────────────────────────────────\n\n/** Default header row height (can be overridden by children). */\nconst HEADER_HEIGHT = 1;\n\n/**\n * Full‑screen terminal layout with three slots.\n *\n * Calculates viewport dimensions from `useTerminalSize` and\n * distributes space: header gets fixed height, scrollable gets\n * the remainder, and bottom gets its natural height.\n *\n * When `modal` is set, it paints over both the scrollable and\n * bottom regions with a dimmed backdrop.\n */\nexport function FullscreenLayout({\n header,\n scrollable,\n bottom,\n overlay,\n modal,\n hidePill,\n newMessageCount,\n onPillClick,\n}: FullscreenLayoutProps): React.ReactElement {\n const { rows, columns } = useTerminalSize();\n const theme = getTheme();\n\n // ── Sticky prompt state ────────────────────────\n\n const [stickyPrompt, setStickyPrompt] = useState<StickyPrompt | null>(null);\n\n /** Stable context value to avoid unnecessary re‑renders. */\n const chromeCtx = useMemo(() => ({ setStickyPrompt }), [setStickyPrompt]);\n\n // ── Scroll pill ────────────────────────────────\n\n const pillText =\n newMessageCount != null && newMessageCount > 0\n ? ` ↓ ${newMessageCount} 条新消息 — Enter 跳转 `\n : \" ↓ 跳转到底部 \";\n\n // ── Layout computation ─────────────────────────\n\n // Estimate bottom section height: InputBox (~3 lines) + StatusLine (~1 line)\n // This is a heuristic; the actual height depends on Ink's layout.\n const bottomEstimate = 5; // InputBox + StatusBar + margin\n const headerHeight = HEADER_HEIGHT;\n const scrollHeight = Math.max(rows - headerHeight - bottomEstimate, 6);\n\n // ── Render ─────────────────────────────────────\n\n return React.createElement(\n ScrollChromeContext.Provider,\n { value: chromeCtx },\n\n React.createElement(\n Box,\n { flexDirection: \"column\", height: rows, width: columns },\n\n // ── Header slot ────────────────────────────\n header ? React.createElement(Box, { height: headerHeight, flexShrink: 0 }, header) : null,\n\n // ── Scrollable slot (body + overlay) ───────\n React.createElement(\n Box,\n { flexDirection: \"column\", flexGrow: 1 },\n\n // Sticky prompt header (shown when scrolled up past messages)\n stickyPrompt\n ? React.createElement(\n Box,\n { paddingX: 1 },\n React.createElement(Text, { dimColor: true }, stickyPrompt.text),\n )\n : null,\n\n React.createElement(\n Box,\n { flexDirection: \"column\", flexGrow: 1, overflow: \"hidden\" },\n scrollable,\n ),\n\n // Overlay inside the scrollable region (permission prompts)\n overlay,\n\n // Jump‑to‑bottom pill (anchored at bottom of scrollable area)\n !hidePill && newMessageCount != null\n ? React.createElement(\n Box,\n { paddingX: 2, paddingY: 0 },\n React.createElement(Text, { color: theme.colors.accent, inverse: true }, pillText),\n )\n : null,\n ),\n\n // ── Bottom slot (input + status) ──────────\n React.createElement(Box, { flexDirection: \"column\", flexShrink: 0 }, bottom),\n\n // ── Modal pane (paints over everything) ────\n modal,\n ),\n );\n}\n","/**\n * useScroll — scroll management hook for the ChatLog message area.\n *\n * Manages scroll offset, sticky‑scroll mode, and computes visibleRange\n * for windowed rendering. Exposes jump‑to‑bottom state for the pill UI.\n *\n * Design:\n * - stickyScroll: true → auto‑scroll to bottom on new messages\n * - User presses PageUp → stickyScroll = false, offset increases\n * - User presses PageDown or jumpToBottom() → stickyScroll = true\n * - New messages arrive while stickyScroll → offset resets to 0\n */\n\nimport { useState, useCallback, useRef } from \"react\";\nimport type { Key } from \"ink\";\n\n/** Scroll state returned by useScroll. */\nexport interface ScrollState {\n /** Start index of the visible message range. */\n visibleStart: number;\n /** End index (exclusive) of the visible message range. */\n visibleEnd: number;\n /** Whether the view is auto‑following new messages. */\n stickyScroll: boolean;\n /** How many new messages are below the current viewport (for pill display). */\n unseenCount: number;\n /** Call to jump back to the bottom (resumes auto‑scroll). */\n jumpToBottom(): void;\n /** Handle keyboard input for scroll navigation. */\n handleKey(input: string, key: Key): boolean;\n /** Scroll up by one line (for mouse wheel). */\n scrollUp(): void;\n /** Scroll down by one line (for mouse wheel). */\n scrollDown(): void;\n /** Update the total entry count (call from a ref or interval). */\n setTotalEntries(count: number): void;\n}\n\n/** Options for useScroll. */\nexport interface UseScrollOptions {\n /** Number of visible rows in the chat area (from terminal size). */\n visibleRows: number;\n}\n\n/**\n * React hook that manages scrolling behaviour for the ChatLog.\n *\n * Call `setTotalEntries(getEntryCount())` periodically to keep\n * the hook in sync with the ChatLog's entry list.\n */\nexport function useScroll({ visibleRows }: UseScrollOptions): ScrollState {\n const [scrollOffset, setScrollOffset] = useState(0);\n const [totalEntries, setTotalEntriesRaw] = useState(0);\n const [stickyScroll, setStickyScroll] = useState(true);\n\n // Use ref to avoid stale closure issues in callbacks\n const stickyScrollRef = useRef(stickyScroll);\n stickyScrollRef.current = stickyScroll;\n\n const maxVisible = Math.max(visibleRows - 2, 5); // reserve 2 lines for header/padding\n const visibleEnd = totalEntries - scrollOffset;\n const visibleStart = Math.max(visibleEnd - maxVisible, 0);\n const unseenCount = scrollOffset;\n\n /** Update total entry count from ChatLog, resetting offset if in sticky mode. */\n const setTotalEntries = useCallback((count: number) => {\n setTotalEntriesRaw(count);\n if (stickyScrollRef.current) {\n setScrollOffset(0);\n }\n }, []);\n\n /** Jump to bottom and resume sticky scroll. */\n const jumpToBottom = useCallback(() => {\n setScrollOffset(0);\n setStickyScroll(true);\n }, []);\n\n /** Handle scroll keyboard input. Returns true if the key was consumed. */\n const handleKey = useCallback(\n (input: string, key: Key): boolean => {\n // PageUp / Ctrl+U → scroll up\n if (key.pageUp || (key.ctrl && input === \"u\")) {\n setStickyScroll(false);\n setScrollOffset((prev) => {\n const step = Math.floor(maxVisible / 2);\n const max = Math.max(0, totalEntries - maxVisible);\n return Math.min(prev + step, max);\n });\n return true;\n }\n\n // PageDown / Ctrl+D → scroll down\n if (key.pageDown || (key.ctrl && input === \"d\")) {\n const next = scrollOffset - Math.floor(maxVisible / 2);\n if (next <= 0) {\n jumpToBottom();\n } else {\n setStickyScroll(false);\n setScrollOffset(next);\n }\n return true;\n }\n\n // Home → top of scroll history\n if (key.home) {\n const max = Math.max(0, totalEntries - maxVisible);\n setStickyScroll(false);\n setScrollOffset(max);\n return true;\n }\n\n // End → jump to bottom\n if (key.end) {\n jumpToBottom();\n return true;\n }\n\n return false;\n },\n [scrollOffset, maxVisible, totalEntries, jumpToBottom],\n );\n\n /** Scroll up by one line (mouse wheel up). */\n const scrollUp = useCallback(() => {\n setStickyScroll(false);\n setScrollOffset((prev) => {\n const max = Math.max(0, totalEntries - maxVisible);\n return Math.min(prev + 1, max);\n });\n }, [totalEntries, maxVisible]);\n\n /** Scroll down by one line (mouse wheel down). */\n const scrollDown = useCallback(() => {\n setScrollOffset((prev) => {\n const next = prev - 1;\n if (next <= 0) {\n jumpToBottom();\n return 0;\n }\n setStickyScroll(false);\n return next;\n });\n }, [jumpToBottom]);\n\n return {\n visibleStart,\n visibleEnd,\n stickyScroll,\n unseenCount,\n jumpToBottom,\n handleKey,\n setTotalEntries,\n scrollUp,\n scrollDown,\n };\n}\n","/**\n * ViewStack — immutable view navigation.\n *\n * push → add view on top\n * pop → remove top (at least one view always remains)\n * replace → swap top\n * top → peek at current\n */\n\nimport type { ViewEntry, ViewId, ViewStack } from \"../types.js\";\n\n/** Create a new view stack with an initial view. */\nexport function createViewStack(initial: ViewId = \"chat\"): ViewStack {\n const stack: ViewEntry[] = [{ id: initial }];\n\n return {\n push(view: ViewEntry): void {\n stack.push(view);\n },\n\n pop(): ViewEntry | undefined {\n if (stack.length > 1) {\n return stack.pop();\n }\n return undefined;\n },\n\n replace(view: ViewEntry): void {\n if (stack.length > 0) {\n stack[stack.length - 1] = view;\n } else {\n stack.push(view);\n }\n },\n\n top(): ViewEntry | undefined {\n return stack[stack.length - 1];\n },\n\n toArray(): ViewEntry[] {\n return [...stack];\n },\n };\n}\n","/**\n * App — root Ink component for the Lynx TUI.\n *\n * Wires the imperative ChatLog handle to the streaming backend via\n * TuiCallbacks.onInput(). Drives view navigation through ViewStack\n * and renders modal overlays for the active view.\n *\n * Architecture:\n * User input → handleSubmit → callbacks.onInput(text)\n * → consumes TuiStreamEvent async generator\n * → dispatches to ChatLogHandle methods\n *\n * 3‑layer abort (Ctrl+C):\n * 1 → abort LLM request\n * 2 → abort running tool\n * 3 → process.exit(1)\n */\n\nimport React, { useState, useReducer, useCallback, useRef, useEffect } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport type { AppProps, ViewEntry, TuiStreamEvent, ThemeName } from \"./types.js\";\nimport { getTheme, setTheme } from \"./theme/theme.js\";\nimport { ChatLog } from \"./components/ChatLog.js\";\nimport type { ChatLogHandle } from \"./components/ChatLog.js\";\nimport { createFrameRateLimiter } from \"./renderer/frame-limiter.js\";\nimport { InputBox } from \"./components/InputBox.js\";\nimport { StatusBar } from \"./components/StatusBar.js\";\nimport { NotificationCenter, useNotifications } from \"./components/NotificationCenter.js\";\nimport { PermissionRequest } from \"./components/PermissionRequest.js\";\nimport type { SafetyLevel } from \"./components/PermissionRequest.js\";\nimport { SessionPicker } from \"./components/SessionPicker.js\";\nimport { HelpModal } from \"./components/HelpModal.js\";\nimport { CommandPalette } from \"./components/CommandPalette.js\";\nimport { ModelPicker } from \"./components/ModelPicker.js\";\nimport { ConfigMenu } from \"./components/ConfigMenu.js\";\nimport { ThemePicker } from \"./components/ThemePicker.js\";\nimport { ConfirmDialog } from \"./components/ConfirmDialog.js\";\nimport { InputPrompt } from \"./components/InputPrompt.js\";\nimport { DoctorPanel, runBuiltinChecks } from \"./components/DoctorPanel.js\";\nimport { FilePicker } from \"./components/FilePicker.js\";\nimport { StashPicker } from \"./components/StashPicker.js\";\nimport type { StashEntry } from \"./components/StashPicker.js\";\nimport { DiffViewer } from \"./components/DiffViewer.js\";\nimport { SnapshotBrowser } from \"./components/SnapshotBrowser.js\";\nimport { TasksPanel } from \"./components/TasksPanel.js\";\nimport { SkillPicker } from \"./components/SkillPicker.js\";\nimport { GlobalSearchDialog } from \"./components/GlobalSearchDialog.js\";\nimport { McpPanel } from \"./components/McpPanel.js\";\nimport { PluginPanel } from \"./components/PluginPanel.js\";\nimport { SkillPanel } from \"./components/SkillPanel.js\";\nimport { ContextPanel } from \"./components/ContextPanel.js\";\nimport { UsagePanel } from \"./components/UsagePanel.js\";\nimport { WelcomeScreen } from \"./screens/WelcomeScreen.js\";\nimport { FullscreenLayout } from \"./components/FullscreenLayout.js\";\nimport { useTerminalSize } from \"./hooks/useTerminalSize.js\";\nimport { useScroll } from \"./hooks/useScroll.js\";\nimport { createViewStack } from \"./views/stack.js\";\n\n/** Maximum number of consecutive Ctrl+C presses before hard exit. */\nconst MAX_ABORT_LAYERS = 3;\n\n/** Streaming watchdog — how long without a text_delta before warning (ms). */\nconst WATCHDOG_DELAY_MS = 30_000;\n/** Max consecutive watchdog timeouts before declaring the stream stalled. */\nconst WATCHDOG_MAX_TIMEOUTS = 3;\n\n/**\n * Compute a human-readable relative time string from a Unix-ms timestamp.\n *\n * Examples: \"just now\", \"5m ago\", \"3h ago\", \"2d ago\", \"1mo ago\".\n */\nfunction relativeTimeStr(updatedAt: number): string {\n const seconds = Math.floor((Date.now() - updatedAt) / 1000);\n if (seconds < 60) return \"just now\";\n const minutes = Math.floor(seconds / 60);\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 return `${months}mo ago`;\n}\n\n/** Main application component rendered by Ink. */\nexport function App(props: AppProps): React.ReactElement {\n const { callbacks, session, sessions, onPermissionReady } = props;\n const { rows } = useTerminalSize();\n const theme = getTheme();\n\n // ── Welcome screen ────────────────────────────\n // Only show when explicitly requested by the launcher (first visit, safety check).\n // Once the user confirms, welcomeDone flips to true and the screen never reappears.\n\n const showWelcome = props.showWelcome === true;\n const [welcomeDone, setWelcomeDone] = useState(false);\n\n // ── ChatLog handle ────────────────────────────\n\n const chatLogRef = useRef<ChatLogHandle | null>(null);\n\n // ── Scroll state ──────────────────────────────\n\n const chatHeight = Math.max(rows - 6, 6);\n const scroll = useScroll({ visibleRows: chatHeight });\n\n // ── View navigation ───────────────────────────\n\n const viewStackRef = useRef(createViewStack());\n const [currentView, setCurrentView] = useState<ViewEntry>({ id: \"chat\" });\n\n /** Frame rate limiter for throttling scroll sync during streaming. */\n const frameLimiterRef = useRef(createFrameRateLimiter());\n\n /** Sync entry count for scroll calculation (throttled to ~30fps via FrameRateLimiter). */\n const syncScrollEntries = useCallback(() => {\n frameLimiterRef.current.schedule(() => {\n scroll.setTotalEntries(chatLogRef.current?.getEntryCount() ?? 0);\n });\n }, [scroll]);\n\n const pushView = useCallback((view: ViewEntry) => {\n viewStackRef.current.push(view);\n setCurrentView(viewStackRef.current.top()!);\n }, []);\n\n const popView = useCallback(() => {\n viewStackRef.current.pop();\n setCurrentView(viewStackRef.current.top()!);\n }, []);\n\n // ── Streaming state ───────────────────────────\n\n const [streaming, setStreaming] = useState(false);\n const [abortCount, setAbortCount] = useState(0);\n\n // ── Search state (managed here so InputBox can be disabled during search) ─\n const [searchActive, setSearchActive] = useState(false);\n /** Transcript display mode: compact (default) or full (timestamps + expanded content). */\n const [transcriptMode, setTranscriptMode] = useState<\"compact\" | \"full\">(\"compact\");\n\n // ── Budget tracking ───────────────────────────\n const [tokensUsed, setTokensUsed] = useState(0);\n const [costUsd, setCostUsd] = useState(0);\n\n // ── Notification toast system ─────────────────\n const { current: activeNotification, push: pushNotification } = useNotifications();\n\n // ── Streaming watchdog — detects stalled LLM streams ─\n const watchdogTimerRef = useRef<NodeJS.Timeout | null>(null);\n const watchdogTimeoutCountRef = useRef(0);\n\n /** Reset the watchdog — called on each text_delta to indicate the stream is alive. */\n const resetWatchdog = useCallback(() => {\n if (watchdogTimerRef.current) {\n clearTimeout(watchdogTimerRef.current);\n watchdogTimerRef.current = null;\n }\n watchdogTimeoutCountRef.current = 0;\n watchdogTimerRef.current = setTimeout(() => {\n watchdogTimeoutCountRef.current++;\n if (watchdogTimeoutCountRef.current >= WATCHDOG_MAX_TIMEOUTS) {\n chatLogRef.current?.addSystem(\"Stream appears stalled — press Ctrl+C to abort\", \"warn\");\n } else {\n chatLogRef.current?.addSystem(\"Still waiting for response...\", \"info\");\n // Restart for the next interval (resets timeout counter if a delta eventually arrives)\n resetWatchdog();\n }\n }, WATCHDOG_DELAY_MS);\n }, []);\n\n /** Clear the watchdog timer — called when streaming ends. */\n const clearWatchdog = useCallback(() => {\n if (watchdogTimerRef.current) {\n clearTimeout(watchdogTimerRef.current);\n watchdogTimerRef.current = null;\n }\n watchdogTimeoutCountRef.current = 0;\n }, []);\n\n // Force re‑render when theme changes (setTheme mutates the singleton,\n // getTheme() picks it up on next render triggered by this counter).\n const [, forceUpdate] = useReducer((x: number) => x + 1, 0);\n\n // ── Permission state ──────────────────────────\n\n const [pendingPermission, setPendingPermission] = useState<{\n requestId: string;\n toolName: string;\n safety: SafetyLevel;\n description: string;\n parameters?: Record<string, unknown>;\n } | null>(null);\n\n // ── Slash command handler ────────────────────\n\n const executeSlashCommand = useCallback(\n (command: string) => {\n popView();\n switch (command) {\n case \"/sessions\":\n case \"/会话\":\n pushView({ id: \"sessions\" });\n break;\n case \"/help\":\n case \"/帮助\":\n pushView({ id: \"help\" });\n break;\n case \"/model\":\n case \"/模型\":\n pushView({ id: \"model\" });\n break;\n case \"/config\":\n case \"/settings\":\n case \"/设置\":\n pushView({ id: \"settings\" });\n break;\n case \"/theme\":\n case \"/主题\":\n pushView({ id: \"theme\" });\n break;\n case \"/doctor\":\n case \"/诊断\":\n pushView({ id: \"doctor\" });\n break;\n case \"/stash\":\n case \"/暂存\":\n pushView({ id: \"stash\" });\n break;\n case \"/files\":\n case \"/文件\":\n pushView({ id: \"file_picker\" });\n break;\n case \"/mcp\":\n pushView({ id: \"mcp\" });\n break;\n case \"/plugin\":\n case \"/插件\":\n pushView({ id: \"plugin\" });\n break;\n case \"/skills\":\n case \"/技能\":\n pushView({ id: \"skills\" });\n break;\n case \"/skill-pick\":\n case \"/技能选择\":\n pushView({ id: \"skill_pick\" });\n break;\n case \"/context\":\n case \"/上下文\":\n pushView({ id: \"context\" });\n break;\n case \"/usage\":\n case \"/用量\":\n pushView({ id: \"usage\" });\n break;\n // ── Session CRUD ──────────────────────────\n case \"/new\":\n case \"/新建\":\n pushView({\n id: \"input_prompt\",\n props: {\n title: \"创建新会话\",\n placeholder: \"请输入会话名称\",\n onConfirm: (label: string) => {\n props.callbacks.onSessionCreate?.(label || \"session\");\n popView();\n },\n },\n });\n break;\n case \"/fork\":\n case \"/分支\":\n pushView({\n id: \"input_prompt\",\n props: {\n title: \"从当前会话创建分支\",\n placeholder: \"请输入分支名称 (可选)\",\n onConfirm: (label: string) => {\n props.callbacks.onSessionFork?.(label || `fork-${session?.label ?? \"session\"}`);\n popView();\n },\n },\n });\n break;\n case \"/rename\":\n case \"/重命名\":\n pushView({\n id: \"input_prompt\",\n props: {\n title: \"重命名会话\",\n placeholder: \"请输入新名称\",\n initialValue: session?.label ?? \"\",\n onConfirm: (newLabel: string) => {\n if (newLabel) props.callbacks.onSessionRename?.(newLabel);\n popView();\n },\n },\n });\n break;\n case \"/delete\":\n case \"/删除\":\n pushView({\n id: \"sessions\",\n props: {\n onSelectOverride: (sessionId: string) => {\n // Push confirm on top of sessions\n pushView({\n id: \"confirm\",\n props: {\n title: \"确认删除\",\n message: `确定要删除会话吗?此操作不可撤销。`,\n onConfirm: () => {\n props.callbacks.onSessionDelete?.(sessionId);\n popView(); // confirm\n popView(); // sessions\n },\n },\n });\n },\n },\n });\n break;\n case \"/resume\":\n case \"/恢复\":\n pushView({\n id: \"sessions\",\n props: {\n onSelectOverride: (sessionId: string) => {\n props.callbacks.onSessionResume?.(sessionId);\n popView();\n },\n },\n });\n break;\n case \"/compact\":\n case \"/压缩\":\n pushView({\n id: \"confirm\",\n props: {\n title: \"压缩上下文\",\n message: \"压缩当前会话的对话上下文?较早的消息将被摘要替换,释放 token 配额。\",\n onConfirm: () => {\n props.callbacks.onSessionCompact?.();\n popView();\n },\n },\n });\n break;\n // ── Tools ──────────────────────────────────\n case \"/diff\":\n case \"/差异\":\n pushView({ id: \"diff\" });\n break;\n case \"/snapshots\":\n case \"/快照\":\n pushView({ id: \"snapshots\" });\n break;\n case \"/tasks\":\n case \"/任务\":\n pushView({ id: \"tasks\" });\n break;\n default:\n chatLogRef.current?.addSystem(`Command \"${command}\" not yet implemented.`, \"warn\");\n }\n },\n [pushView, popView, callbacks],\n );\n\n // ── Keyboard: global keys ─────────────────────\n\n const handleGlobalKey = useCallback(\n (input: string, key: Key) => {\n if (scroll.handleKey(input, key)) return;\n\n // Escape closes simple modals (views with internal useInput handle their own Escape)\n const selfHandled = new Set([\n \"permission\",\n \"sessions\",\n \"help\",\n \"commands\",\n \"model\",\n \"settings\",\n \"theme\",\n \"confirm\",\n \"input_prompt\",\n \"doctor\",\n \"file_picker\",\n \"stash\",\n \"mcp\",\n \"plugin\",\n \"skills\",\n \"context\",\n \"usage\",\n \"diff\",\n \"snapshots\",\n \"tasks\",\n \"skill_pick\",\n \"global_search\",\n ]);\n if (key.escape && currentView.id !== \"chat\" && !selfHandled.has(currentView.id)) {\n popView();\n }\n\n // Ctrl+G — open external editor\n if (key.ctrl && input === \"g\" && currentView.id === \"chat\") {\n const doExternalEdit = async () => {\n try {\n const result = await callbacks.onOpenExternalEditor?.(\"\");\n if (result) setAppendToInput(result);\n } catch {\n // Editor failed — silently ignore\n }\n };\n doExternalEdit();\n }\n\n // Ctrl+O — toggle transcript mode (compact ↔ full with timestamps)\n if (key.ctrl && input === \"o\" && currentView.id === \"chat\") {\n setTranscriptMode((prev) => (prev === \"compact\" ? \"full\" : \"compact\"));\n }\n\n // Ctrl+Shift+P — command palette (VS Code convention)\n if (key.ctrl && key.shift && input === \"p\" && currentView.id === \"chat\") {\n pushView({ id: \"commands\" });\n }\n\n // Ctrl+Shift+F — global search across workspace files\n if (key.ctrl && key.shift && input === \"f\" && currentView.id === \"chat\") {\n pushView({ id: \"global_search\" });\n }\n },\n [currentView.id, scroll, popView, callbacks, pushView],\n );\n\n useInkInput((input: string, key: Key) => {\n // Filter out terminal mouse SGR escape sequences that leak through\n // as raw text when terminal mouse tracking is enabled by Ink.\n if (input.includes(\"\\x1b[<\") || /^\\[<\\d+;\\d+;\\d+[Mm]/.test(input.trim())) return;\n handleGlobalKey(input, key);\n });\n\n // ── Abort handler (3‑layer) ───────────────────\n\n const handleAbort = useCallback(() => {\n const next = abortCount + 1;\n setAbortCount(next);\n\n if (next === 1) {\n callbacks.onAbort();\n chatLogRef.current?.addSystem(\n \"Request aborted (Ctrl+C 1/3). Press again to abort tool.\",\n \"warn\",\n );\n syncScrollEntries();\n } else if (next === 2) {\n chatLogRef.current?.addSystem(\"Tool aborted (Ctrl+C 2/3). Streaming stopped.\", \"error\");\n chatLogRef.current?.dropAssistant();\n setStreaming(false);\n syncScrollEntries();\n } else {\n process.exit(1);\n }\n }, [abortCount, callbacks, syncScrollEntries]);\n\n // ── Stream event processor ────────────────────\n\n /** Process a single TUI stream event, updating ChatLog state. */\n function handleStreamEvent(event: TuiStreamEvent): void {\n const chat = chatLogRef.current;\n if (!chat) return;\n\n if (event.type === \"reasoning_status\") {\n if (event.status === \"started\") {\n chat.addSystem(\"思考中…\", \"info\");\n } else if (event.durationMs != null) {\n chat.showThinking(event.text ?? \"\", event.durationMs);\n }\n } else if (event.type === \"text_delta\") {\n resetWatchdog();\n hasAssistantTextRef.current = true;\n if (!hasAssistantStartedRef.current) {\n chat.commitPendingUser();\n chat.startAssistant(event.text);\n hasAssistantStartedRef.current = true;\n } else {\n chat.updateAssistant(event.text);\n }\n } else if (event.type === \"tool_use\") {\n if (!hasAssistantStartedRef.current) {\n chat.commitPendingUser();\n // Start an empty assistant entry so it can be finalized later\n chat.startAssistant(\"\");\n hasAssistantStartedRef.current = true;\n }\n toolNamesRef.current.push(event.name);\n pushNotification({\n key: `tool-${event.callId}`,\n text: `Running ${event.name}…`,\n priority: \"medium\",\n });\n chat.addTool(event.name, event.callId);\n } else if (event.type === \"tool_result\") {\n pushNotification({\n key: `tool-${event.callId}`,\n text: `${event.content.slice(0, 60)}…`,\n priority: \"low\",\n });\n chat.updateToolResult(event.callId, event.content);\n } else if (event.type === \"tool_recap\") {\n chat.addSystem(event.summary, \"info\");\n } else if (event.type === \"error\") {\n chat.commitPendingUser();\n chat.addSystem(`Error: ${event.message}`, \"error\");\n pushNotification({ key: `err-${Date.now()}`, text: event.message, priority: \"immediate\" });\n } else if (event.type === \"done\") {\n if (hasAssistantStartedRef.current) {\n chat.finalizeAssistant();\n // If tools ran but model produced no text, show which tools completed\n if (!hasAssistantTextRef.current) {\n const names = toolNamesRef.current;\n const unique = [...new Set(names)];\n const fallback =\n unique.length > 0\n ? `${unique.map((n) => `已调用 ${n}`).join(\" · \")} · 已完成 ${names.length} 个工具调用`\n : \"操作完成\";\n chat.addSystem(fallback, \"info\");\n }\n } else {\n chat.dropPendingUser();\n }\n // Accumulate budget from done event\n if (typeof event.totalTokens === \"number\" && event.totalTokens > 0) {\n setTokensUsed((prev) => prev + event.totalTokens!);\n }\n if (typeof event.costUsd === \"number\" && event.costUsd > 0) {\n setCostUsd((prev) => prev + event.costUsd!);\n }\n }\n }\n\n const hasAssistantStartedRef = useRef(false);\n /** Track whether the assistant has produced any visible text (not just tool calls). */\n const hasAssistantTextRef = useRef(false);\n /** Track tool names executed in the current turn for fallback summaries. */\n const toolNamesRef = useRef<string[]>([]);\n\n // ── Submit handler — consumes streaming events ─\n\n const handleSubmit = useCallback(\n async (text: string) => {\n if (text.startsWith(\"/\")) {\n executeSlashCommand(text.trim());\n return;\n }\n\n setAbortCount(0);\n hasAssistantStartedRef.current = false;\n hasAssistantTextRef.current = false;\n toolNamesRef.current = [];\n chatLogRef.current?.addUser(text, true);\n syncScrollEntries();\n setStreaming(true);\n\n try {\n for await (const event of callbacks.onInput(text)) {\n handleStreamEvent(event);\n syncScrollEntries();\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n chatLogRef.current?.commitPendingUser();\n chatLogRef.current?.addSystem(`Stream error: ${message}`, \"error\");\n chatLogRef.current?.dropAssistant();\n syncScrollEntries();\n } finally {\n clearWatchdog();\n setStreaming(false);\n }\n },\n [callbacks, syncScrollEntries, executeSlashCommand, clearWatchdog],\n );\n\n // ── Permission: show in chat area, not overlay ─\n\n const handlePermissionRequest = useCallback(\n (req: { requestId: string; toolName: string; description: string; safety: SafetyLevel }) => {\n setPendingPermission({\n requestId: req.requestId,\n toolName: req.toolName,\n safety: req.safety,\n description: req.description,\n });\n pushView({ id: \"permission\" });\n },\n [pushView],\n );\n\n // ── Stash state ──────────────────────────────\n\n const [stashItems, setStashItems] = useState<StashEntry[]>([]);\n /** Text to append to InputBox (set by FilePicker, StashPicker restore, etc.). */\n const [appendToInput, setAppendToInput] = useState<string | undefined>(undefined);\n\n /** Stash the current input (called via Ctrl+S from InputBox). */\n const stashCurrentInput = useCallback((text: string) => {\n const entry: StashEntry = {\n id: crypto.randomUUID().slice(0, 8),\n preview: text.slice(0, 100),\n timestamp: Date.now(),\n };\n setStashItems((prev) => [entry, ...prev].slice(0, 200));\n }, []);\n\n // Register the permission handler with the CLI bridge on mount\n useEffect(() => {\n onPermissionReady?.(handlePermissionRequest);\n return () => {\n // Unregister on unmount so the bridge doesn't call a stale handler\n onPermissionReady?.(null);\n };\n }, [onPermissionReady, handlePermissionRequest]);\n\n // ── Layout ────────────────────────────────────\n\n const isModal = currentView.id !== \"chat\";\n const hasVisibleRange = scroll.visibleStart < scroll.visibleEnd;\n\n // ── Modal renderers (per‑view functions to keep complexity low) ──\n\n /** Render the permission request modal. */\n function renderPermission(): React.ReactElement {\n return React.createElement(PermissionRequest, {\n request: {\n requestId: pendingPermission!.requestId,\n toolName: pendingPermission!.toolName,\n safety: pendingPermission!.safety,\n description: pendingPermission!.description,\n parameters: pendingPermission!.parameters,\n },\n onDecide: (id, choice) => {\n const approved = choice === \"allow\" || choice === \"always_allow\";\n callbacks.onPermissionReply(id, approved);\n setPendingPermission(null);\n popView();\n },\n onCancel: () => {\n // Abort the entire agent turn rather than just denying this tool.\n // This prevents retry loops when the user is not available to decide.\n callbacks.onAbort();\n setPendingPermission(null);\n popView();\n },\n });\n }\n\n /** Render the session picker modal. */\n function renderSessions(): React.ReactElement {\n const viewProps = currentView.props as\n | { onSelectOverride?: (sessionId: string) => void }\n | undefined;\n return React.createElement(SessionPicker, {\n sessions,\n onSelect:\n viewProps?.onSelectOverride ??\n ((sessionId) => {\n callbacks.onSessionPick(sessionId);\n popView();\n }),\n onCancel: () => popView(),\n });\n }\n\n /** Render the model picker modal. */\n function renderModel(): React.ReactElement {\n return React.createElement(ModelPicker, {\n models: props.models ?? [],\n currentModel: props.currentModel,\n onSelect: (modelId) => {\n props.callbacks.onModelPick?.(modelId);\n popView();\n },\n onSetDefault: props.callbacks.onModelPick\n ? (modelId) => props.callbacks.onModelPick?.(modelId)\n : undefined,\n onCancel: () => popView(),\n });\n }\n\n /** Render the theme picker modal. */\n function renderTheme(): React.ReactElement {\n return React.createElement(ThemePicker, {\n onSelect: (themeName: ThemeName) => {\n setTheme(themeName);\n forceUpdate();\n props.callbacks.onThemeChange?.(themeName);\n popView();\n },\n onCancel: () => popView(),\n });\n }\n\n /** Render the confirm dialog modal. */\n function renderConfirm(): React.ReactElement {\n const confirmProps = currentView.props ?? {};\n return React.createElement(ConfirmDialog, {\n title: (confirmProps.title as string) ?? \"Confirm\",\n message: (confirmProps.message as string) ?? \"Are you sure?\",\n confirmLabel: confirmProps.confirmLabel as string | undefined,\n cancelLabel: confirmProps.cancelLabel as string | undefined,\n onConfirm: () => {\n (confirmProps.onConfirm as (() => void) | undefined)?.();\n popView();\n },\n onCancel: () => popView(),\n });\n }\n\n /** Render the input prompt modal. */\n function renderInputPrompt(): React.ReactElement {\n const promptProps = currentView.props ?? {};\n return React.createElement(InputPrompt, {\n title: (promptProps.title as string) ?? \"Input\",\n initialValue: promptProps.initialValue as string | undefined,\n placeholder: promptProps.placeholder as string | undefined,\n onConfirm: (value) => {\n (promptProps.onConfirm as ((v: string) => void) | undefined)?.(value);\n popView();\n },\n onCancel: () => popView(),\n });\n }\n\n /** Dispatch table for modal views — keeps renderModal complexity at O(1). */\n const modalRenderers: Record<string, () => React.ReactElement> = {\n permission: renderPermission,\n sessions: renderSessions,\n help: () => React.createElement(HelpModal, { onCancel: () => popView() }),\n commands: () =>\n React.createElement(CommandPalette, {\n onSelect: (cmd) => executeSlashCommand(cmd),\n onCancel: () => popView(),\n }),\n model: renderModel,\n settings: () =>\n React.createElement(ConfigMenu, {\n onToggle: (key, value) => {\n props.callbacks.onConfigChange?.(key, value);\n },\n onEdit: (key, label, currentValue, valueType) => {\n pushView({\n id: \"input_prompt\",\n props: {\n title: `Edit: ${label}`,\n initialValue: currentValue,\n placeholder: `Enter new value for ${label}`,\n onConfirm: (newValue: string) => {\n // Parse as number if the original value was a number\n const finalValue =\n valueType === \"number\" && !isNaN(Number(newValue)) ? Number(newValue) : newValue;\n props.callbacks.onConfigChange?.(key, finalValue);\n popView();\n },\n },\n });\n },\n onCancel: () => popView(),\n }),\n theme: renderTheme,\n confirm: renderConfirm,\n doctor: () =>\n React.createElement(DoctorPanel, {\n checks: runBuiltinChecks(),\n onCancel: () => popView(),\n }),\n input_prompt: renderInputPrompt,\n file_picker: () =>\n React.createElement(FilePicker, {\n workspace: session?.workspace ?? process.cwd(),\n onSelect: (filePath) => {\n setAppendToInput(filePath);\n popView();\n },\n onCancel: () => popView(),\n }),\n stash: () =>\n React.createElement(StashPicker, {\n items: stashItems,\n onRestore: (id) => {\n const entry = stashItems.find((e) => e.id === id);\n if (entry) setAppendToInput(entry.preview);\n popView();\n },\n onDelete: (id) => {\n setStashItems((prev) => prev.filter((e) => e.id !== id));\n },\n onCancel: () => popView(),\n }),\n mcp: () =>\n React.createElement(McpPanel, {\n connections: props.mcpConnections ?? [],\n onConnect: (name) => props.callbacks.onMcpConnect?.(name),\n onDisconnect: (name) => props.callbacks.onMcpDisconnect?.(name),\n onReconnect: (name) => props.callbacks.onMcpReconnect?.(name),\n onCancel: () => popView(),\n }),\n plugin: () =>\n React.createElement(PluginPanel, {\n plugins: props.plugins ?? [],\n onLoad: (name) => props.callbacks.onPluginLoad?.(name),\n onUnload: (name) => props.callbacks.onPluginUnload?.(name),\n onCancel: () => popView(),\n }),\n skills: () =>\n React.createElement(SkillPanel, {\n skills: props.skills ?? [],\n onCancel: () => popView(),\n }),\n context: () =>\n React.createElement(ContextPanel, {\n contextInfo: props.contextInfo ?? {\n memoryFacts: 0,\n rules: 0,\n skills: 0,\n model: props.currentModel ?? \"unknown\",\n workspace: session?.workspace ?? process.cwd(),\n sessionLabel: session?.label ?? \"none\",\n },\n onCancel: () => popView(),\n }),\n usage: () =>\n React.createElement(UsagePanel, {\n usageInfo: props.usageInfo ?? {\n tokensUsed,\n costUsd,\n budgetMaxTokens: 0,\n budgetMaxUsd: 0,\n turns: 0,\n modelPricing: props.currentModel ? `${props.currentModel}: N/A` : \"N/A\",\n },\n onCancel: () => popView(),\n }),\n diff: () =>\n React.createElement(DiffViewer, {\n onRequestDiff: callbacks.onRequestDiff,\n onCancel: () => popView(),\n }),\n snapshots: () =>\n React.createElement(SnapshotBrowser, {\n onRequestSnapshots: callbacks.onRequestSnapshots,\n onCancel: () => popView(),\n }),\n tasks: () =>\n React.createElement(TasksPanel, {\n onRequestTasks: callbacks.onRequestTasks,\n onCancel: () => popView(),\n }),\n skill_pick: () =>\n React.createElement(SkillPicker, {\n skills: props.skills ?? [],\n onSelect: (skillName) => {\n chatLogRef.current?.addSystem(`Skill loaded: ${skillName}`, \"info\");\n popView();\n },\n onCancel: () => popView(),\n }),\n global_search: () =>\n React.createElement(GlobalSearchDialog, {\n workspace: session?.workspace ?? process.cwd(),\n onInsert: (text: string) => {\n setAppendToInput(text);\n popView();\n },\n onCancel: () => popView(),\n }),\n };\n\n /** Render the active modal overlay, if any. */\n function renderModal(): React.ReactElement | null {\n if (currentView.id === \"permission\" && !pendingPermission) return null;\n const renderer = modalRenderers[currentView.id];\n return renderer ? renderer() : null;\n }\n\n // ── Render ───────────────────────────────────\n // Note: Ink 6.x requires a single root Box. All code paths\n // below return exactly one root element.\n\n if (showWelcome && !welcomeDone) {\n return React.createElement(WelcomeScreen, {\n workspace: session?.workspace ?? process.cwd(),\n version: props.version,\n lastSession: session\n ? {\n label: session.label,\n relativeTime: relativeTimeStr(session.updatedAt),\n sessionCount: sessions.length,\n }\n : undefined,\n onConfirm: () => setWelcomeDone(true),\n onExit: () => process.exit(0),\n });\n }\n\n // ── Build header ─────────────────────────────\n\n const headerNode = React.createElement(\n Box,\n { flexDirection: \"row\", justifyContent: \"space-between\" },\n // Left: brand + session\n React.createElement(\n Box,\n { flexDirection: \"row\" },\n React.createElement(Text, { bold: true, color: theme.colors.accent }, \"Lynx\"),\n React.createElement(Text, { dimColor: true }, ` · ${session?.label ?? \"no session\"}`),\n ),\n // Right: model + cost\n React.createElement(\n Box,\n { flexDirection: \"row\" },\n React.createElement(Text, { dimColor: true }, props.currentModel ?? \"unknown\"),\n costUsd > 0\n ? React.createElement(Text, { dimColor: true }, ` $${costUsd.toFixed(4)}`)\n : null,\n ),\n );\n\n // ── Build scrollable area ────────────────────\n\n const scrollableNode = React.createElement(\n Box,\n { flexDirection: \"column\" },\n React.createElement(ChatLog, {\n ref: chatLogRef,\n visibleRange: hasVisibleRange\n ? { start: scroll.visibleStart, end: scroll.visibleEnd }\n : undefined,\n onSearchActiveChange: setSearchActive,\n transcriptMode,\n }),\n );\n\n // ── Build overlay (permission prompt) ─────────\n\n const overlayNode =\n currentView.id === \"permission\" && pendingPermission ? renderPermission() : null;\n\n // ── Build bottom (input + status) ────────────\n\n const bottomNode = React.createElement(\n Box,\n { flexDirection: \"column\" },\n\n // Notification toast\n activeNotification\n ? React.createElement(\n Box,\n { paddingX: 1 },\n React.createElement(NotificationCenter, { current: activeNotification }),\n )\n : null,\n\n // Prompt input\n React.createElement(InputBox, {\n onSubmit: handleSubmit,\n onAbort: handleAbort,\n disabled: streaming || searchActive,\n workspace: session?.workspace,\n placeholder:\n abortCount > 0\n ? `[Abort ${abortCount}/${MAX_ABORT_LAYERS}] Type a message...`\n : \"Type a message...\",\n onStash: stashCurrentInput,\n appendText: appendToInput,\n onAppendTextConsumed: () => setAppendToInput(undefined),\n }),\n\n // Status bar\n React.createElement(StatusBar, {\n mode: abortCount > 0 ? `abort ${abortCount}/${MAX_ABORT_LAYERS}` : \"default\",\n model: props.currentModel ?? \"unknown\",\n streaming,\n viewName: currentView.id,\n tokensUsed,\n costUsd,\n budgetMaxUsd: 10,\n }),\n );\n\n // ── Render ───────────────────────────────────\n\n return React.createElement(FullscreenLayout, {\n header: headerNode,\n scrollable: scrollableNode,\n bottom: bottomNode,\n overlay: overlayNode,\n modal: isModal ? renderModal() : null,\n hidePill: scroll.stickyScroll || scroll.unseenCount === 0,\n newMessageCount: scroll.unseenCount,\n onPillClick: () => scroll.jumpToBottom(),\n });\n}\n","/**\n * ChatView — scrollable message transcript.\n *\n * Renders the session message history as a sequence of\n * text blocks, with speaker labels (User / Assistant)\n * and tool‑use callouts.\n */\n\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { Message } from \"@24klynx/core\";\n\n// ── Props ────────────────────────────────────────────\n\n/** Props for ChatView — list of messages to display plus streaming state. */\nexport interface ChatViewProps {\n messages: Message[];\n streaming: boolean;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst MAX_VISIBLE_MESSAGES = 50;\n\n// ── Public API ───────────────────────────────────────\n\n/** Scrollable message transcript — renders the last 50 messages as labeled entries. */\nexport function ChatView({ messages, streaming }: ChatViewProps): React.ReactElement {\n // Show only the most recent messages\n const visible = messages.slice(-MAX_VISIBLE_MESSAGES);\n\n if (visible.length === 0) {\n return React.createElement(\n Box,\n { flexDirection: \"column\" },\n React.createElement(Text, { dimColor: true }, \"No messages yet. Start a conversation!\"),\n );\n }\n\n const elements: React.ReactElement[] = [];\n\n for (let i = 0; i < visible.length; i++) {\n const msg = visible[i]!;\n const label = msg.role === \"user\" ? \"You\" : \"Lynx\";\n const labelColor = msg.role === \"user\" ? \"green\" : \"blue\";\n\n elements.push(\n React.createElement(\n Box,\n { key: msg.id as string, flexDirection: \"column\", marginBottom: 1 },\n React.createElement(Text, { bold: true, color: labelColor }, `${label}:`),\n // Render each content block\n ...msg.content.map((block, bi) => {\n if (block.type === \"text\") {\n return React.createElement(Text, { key: `${msg.id as string}-${bi}` }, block.text);\n }\n if (block.type === \"tool_use\") {\n return React.createElement(\n Text,\n { key: `${msg.id as string}-${bi}`, color: \"yellow\" },\n `[Tool: ${block.name}]`,\n );\n }\n if (block.type === \"tool_result\") {\n const preview = block.content.slice(0, 200);\n return React.createElement(\n Text,\n { key: `${msg.id as string}-${bi}`, dimColor: true },\n `→ ${preview}${block.content.length > 200 ? \"...\" : \"\"}`,\n );\n }\n if (block.type === \"reasoning\") {\n return React.createElement(\n Text,\n { key: `${msg.id as string}-${bi}`, dimColor: true, italic: true },\n `[thinking] ${block.text.slice(0, 100)}`,\n );\n }\n return React.createElement(Text, { key: `${msg.id as string}-${bi}` }, \"\");\n }),\n ),\n );\n }\n\n // Streaming indicator\n if (streaming) {\n elements.push(\n React.createElement(\n Box,\n { key: \"streaming-indicator\" },\n React.createElement(Text, { dimColor: true }, \"▊\"),\n ),\n );\n }\n\n return React.createElement(Box, { flexDirection: \"column\" }, ...elements);\n}\n","/**\n * ToolRenderer — strategy‑based rendering for tool calls and results.\n *\n * Dispatches to specialized renderers based on the tool name, showing\n * a styled header with the tool icon, name, and relevant context\n * (file path, URL, command, etc.).\n *\n * Design:\n * Each tool category has a dedicated layout with appropriate\n * icons, color coding, and truncation rules.\n */\n\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\n\n/** Props passed to the ToolRenderer. */\nexport interface ToolRendererProps {\n /** Name of the tool being rendered. */\n toolName: string;\n /** Whether this is the tool call (header) or the result. */\n phase: \"call\" | \"result\";\n /** Content to display (command, file path, result text). */\n content: string;\n}\n\n/** Maximum characters before truncation. */\nconst MAX_CONTENT = 2000;\n\n/**\n * ToolRenderer component.\n *\n * Renders tool invocations and results with appropriate icons and colors.\n * Different tool categories get different visual treatments.\n */\nexport function ToolRenderer({ toolName, phase, content }: ToolRendererProps): React.ReactElement {\n const icon = toolIcon(toolName);\n const label = toolLabel(toolName, content);\n const truncated =\n content.length > MAX_CONTENT ? content.slice(0, MAX_CONTENT) + \"\\n [truncated]\" : content;\n\n return React.createElement(\n Box,\n { flexDirection: \"column\", marginBottom: 1 },\n // ── Header ───────────────────────────────\n React.createElement(\n Box,\n { flexDirection: \"row\" },\n React.createElement(Text, { bold: true }, `${icon} ${toolName}`),\n label ? React.createElement(Text, { dimColor: true }, ` — ${label}`) : null,\n ),\n // ── Body ─────────────────────────────────\n phase === \"result\"\n ? React.createElement(\n Text,\n { dimColor: phase === \"result\" },\n phase === \"result\" ? ` → ${truncated}` : truncated,\n )\n : null,\n );\n}\n\n/** Choose an icon based on tool category. */\nfunction toolIcon(name: string): string {\n if (/^(bash|exec|shell|powershell|cmd)$/i.test(name)) return \"💻\";\n if (/^(write|edit|notebook_edit|create_or_update_file|delete_file|move_file)$/i.test(name))\n return \"✏️\";\n if (\n /^(read|grep|glob|search|read_file|read_text_file|read_media_file|read_multiple_files)$/i.test(\n name,\n )\n )\n return \"📄\";\n if (/^(web_fetch|web_search|browser_navigate)$/i.test(name)) return \"🌐\";\n if (/^(agent|task|team_create|team_delete)$/i.test(name)) return \"🤖\";\n if (/^(ask_user|ask_user_question)$/i.test(name)) return \"❓\";\n return \"🔧\";\n}\n\n/** Generate a short label from the tool's first argument (path, URL, command). */\nfunction toolLabel(name: string, content: string): string {\n const firstLine = content.split(\"\\n\")[0] ?? \"\";\n const isRead =\n /^(read|grep|glob|search|read_file|read_text_file|read_media_file|read_multiple_files)$/i.test(\n name,\n );\n const isWrite = /^(write|edit|notebook_edit|create_or_update_file|delete_file|move_file)$/i.test(\n name,\n );\n const isBash = /^(bash|exec|shell|powershell|cmd)$/i.test(name);\n const isWeb = /^(web_fetch|web_search|browser_navigate)$/i.test(name);\n\n if (isBash) {\n // Show truncated command\n return firstLine.length > 60 ? firstLine.slice(0, 57) + \"...\" : firstLine;\n }\n\n if (isRead || isWrite) {\n // Show file path\n return firstLine.length > 50 ? firstLine.slice(0, 47) + \"...\" : firstLine;\n }\n\n if (isWeb) {\n // Show URL\n const url = firstLine.length > 60 ? firstLine.slice(0, 57) + \"...\" : firstLine;\n return url;\n }\n\n return \"\";\n}\n","/**\n * Mascot — animated character that reflects the current agent state.\n *\n * States:\n * idle — waiting for input (slow animation)\n * listen — user is typing (static)\n * think — LLM is reasoning (fast animation)\n * speak — assistant is streaming output\n * error — something went wrong\n *\n * Each state has a set of frames and a rotation interval.\n * Uses a simple setInterval‑based animation.\n */\n\nimport React, { useState, useEffect, useRef } from \"react\";\nimport { Text } from \"ink\";\n\n/** The five mascot states. */\nexport type MascotState = \"idle\" | \"listen\" | \"think\" | \"speak\" | \"error\";\n\n/** Props for the Mascot component. */\nexport interface MascotProps {\n /** Current mascot state. */\n state: MascotState;\n /** Whether animation is enabled (respects reduce‑motion preference). */\n animate?: boolean;\n}\n\n/** Frames and timing per state. */\ninterface StateConfig {\n frames: string[];\n intervalMs: number;\n}\n\nconst STATE_FRAMES: Record<MascotState, StateConfig> = {\n idle: {\n frames: [\"🐱\", \"😺\", \"🐱\", \"😸\"],\n intervalMs: 3000,\n },\n listen: {\n frames: [\"🐱\"],\n intervalMs: Infinity, // No animation\n },\n think: {\n frames: [\"🤔\", \"💭\", \"🤔\", \"💭\"],\n intervalMs: 600,\n },\n speak: {\n frames: [\"😸\", \"🐱\"],\n intervalMs: 400,\n },\n error: {\n frames: [\"🙀\", \"😾\"],\n intervalMs: 500,\n },\n};\n\n/**\n * Animated mascot character.\n *\n * Renders a single emoji that changes based on the current state.\n * Animation is frame‑based with configurable intervals per state.\n */\nexport function Mascot({ state, animate = true }: MascotProps): React.ReactElement {\n const config = STATE_FRAMES[state] ?? STATE_FRAMES.idle;\n const [frameIndex, setFrameIndex] = useState(0);\n const timerRef = useRef<NodeJS.Timeout | null>(null);\n\n useEffect(() => {\n // Reset frame when state changes\n setFrameIndex(0);\n\n if (!animate || config.intervalMs === Infinity) {\n return;\n }\n\n timerRef.current = setInterval(() => {\n setFrameIndex((prev) => (prev + 1) % config.frames.length);\n }, config.intervalMs);\n\n return () => {\n if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n };\n }, [state, animate, config.intervalMs, config.frames.length]);\n\n const frame = config.frames[frameIndex] ?? config.frames[0]!;\n\n return React.createElement(Text, null, frame);\n}\n","/**\n * Button — interactive component with keyboard activation and visual states.\n *\n * Activated via Enter, Space, or click. Supports focus/hover/active\n * visual states through a render‑prop pattern. Built on Ink's Box\n * with keyboard event handling via useInput.\n *\n * Design (§5.9b #1.6.2): inverse highlight on active, Enter to trigger.\n * Intentionally unstyled — styling is done by the consumer via render prop.\n */\n\nimport React, { useState, useCallback, useRef } from \"react\";\nimport { Box, useInput } from \"ink\";\nimport type { Key } from \"ink\";\nimport type { ReactNode } from \"react\";\n\n/** Interactive state exposed to the render prop. */\nexport interface ButtonState {\n /** The button currently has keyboard focus. */\n focused: boolean;\n /** The mouse cursor is over the button. */\n hovered: boolean;\n /** The button is being pressed (Enter/Space held or click). */\n active: boolean;\n}\n\n/** Props for the Button component. */\nexport interface ButtonProps {\n /** Called when the button is activated via Enter, Space, or click. */\n onAction: () => void;\n /** Render prop receiving the interactive state. */\n children: (state: ButtonState) => ReactNode;\n /** Tab order index. Default: 0 (in tab order). Set to -1 to skip. */\n tabIndex?: number;\n /** Focus this button on mount. */\n autoFocus?: boolean;\n /** When true, the button processes global keyboard input. Default: false. */\n isFocused?: boolean;\n}\n\n/** Duration of the \"active\" visual flash in milliseconds. */\nconst ACTIVE_FLASH_MS = 100;\n\n/**\n * Interactive button component with keyboard activation.\n *\n * Supports Enter/Space activation, active‑state flash, and a\n * render‑prop pattern so consumers fully control visual styling\n * based on { focused, hovered, active } state.\n */\nexport function Button({ onAction, children, isFocused = false }: ButtonProps): React.ReactElement {\n const [isActive, setIsActive] = useState(false);\n const activeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n /** Handle keyboard activation (Enter / Space). */\n const handleInput = useCallback(\n (input: string, key: Key) => {\n // Only process when focused (global input is always received)\n if (!isFocused) return;\n\n if (key.return || input === \" \") {\n setIsActive(true);\n onAction();\n\n if (activeTimer.current) clearTimeout(activeTimer.current);\n activeTimer.current = setTimeout(() => setIsActive(false), ACTIVE_FLASH_MS);\n }\n },\n [onAction, isFocused],\n );\n\n useInput(handleInput, { isActive: isFocused });\n\n const state: ButtonState = {\n focused: isFocused,\n hovered: false, // Standard Ink has no mouse hover tracking\n active: isActive,\n };\n\n return React.createElement(Box, null, children(state));\n}\n","/**\n * Link — renders a clickable hyperlink in supported terminals.\n *\n * Uses OSC 8 escape sequences when the terminal supports hyperlinks\n * (detected via `supports-hyperlinks`). Falls back to plain text\n * display on terminals without hyperlink support.\n *\n * Design (§5.9b #1.6.3): clickable links via Ctrl+Click or terminal's\n * native hyperlink handling. Supports file://, http://, https://.\n */\n\nimport React from \"react\";\nimport { Text } from \"ink\";\nimport type { ReactNode } from \"react\";\n\n/** Props for the Link component. */\nexport interface LinkProps {\n /** Content to display for the link. Defaults to the URL itself. */\n children?: ReactNode;\n /** Target URL (http://, https://, file://). */\n url: string;\n /** Fallback content when hyperlinks are not supported. */\n fallback?: ReactNode;\n}\n\n/**\n * Detect whether the terminal supports OSC 8 hyperlinks.\n *\n * Checks: iTerm (TERM_PROGRAM), VSCode terminal, Windows Terminal\n * (WT_SESSION), Ghostty (TERM), and Kitty.\n */\nfunction supportsHyperlinks(): boolean {\n const { TERM_PROGRAM, WT_SESSION, TERM } = process.env;\n if (TERM_PROGRAM === \"iTerm.app\") return true;\n if (TERM_PROGRAM === \"vscode\") return true;\n if (WT_SESSION) return true;\n if (TERM === \"xterm-kitty\") return true;\n if (TERM?.startsWith(\"ghostty\")) return true;\n // WezTerm, Konsole 22.04+, foot, rxvt-unicode 9.31+ also support OSC 8\n if (process.env.TERMINAL_EMULATOR === \"JetBrains-JediTerm\") return true;\n return false;\n}\n\n/**\n * Build an OSC 8 hyperlink escape sequence.\n *\n * Format: ESC ] 8 ; <params> ; <url> ST <text> ESC ] 8 ; ; ST\n * Where ST (string terminator) is ESC \\.\n */\nfunction osc8(url: string, text: string): string {\n return `\\x1b]8;;${url}\\x1b\\\\${text}\\x1b]8;;\\x1b\\\\`;\n}\n\n/**\n * Render a clickable link with terminal hyperlink support.\n *\n * On terminals with OSC 8 support, wraps text in hyperlink escape\n * sequences. On unsupported terminals, renders the URL in brackets\n * after the link text (GitHub‑flavored Markdown style).\n */\nexport function Link({ children, url, fallback }: LinkProps): React.ReactElement {\n const content = (children as string) ?? url;\n\n if (supportsHyperlinks()) {\n const linked = osc8(url, content);\n return React.createElement(Text, null, linked);\n }\n\n // Fallback: show text + URL in dim brackets\n const display = fallback ?? `${content} (${url})`;\n return React.createElement(Text, { dimColor: true }, display as string);\n}\n","/**\n * RawAnsi — renders pre‑wrapped ANSI‑escaped text without re‑parsing.\n *\n * Use this when external tools (bash, git diff, compiler output) produce\n * ANSI‑colored output that should be displayed as‑is. Bypasses the\n * React → Yoga → Text serialization roundtrip for performance.\n *\n * In standard Ink 6.x, ANSI SGR codes in Text children are passed through\n * to the terminal output. This component joins pre‑wrapped lines and\n * hands them to Ink's Text, which preserves the escape sequences.\n *\n * Design (§5.9b #1.3.7): renders tool output with native terminal colors.\n */\n\nimport React from \"react\";\nimport { Text } from \"ink\";\n\n/** Props for the RawAnsi component. */\nexport interface RawAnsiProps {\n /**\n * Pre‑rendered ANSI lines. Each element must be exactly one terminal\n * row (already wrapped to the target width) with ANSI escape codes inline.\n */\n lines: string[];\n /** Column width the producer wrapped to. Informational only in standard Ink. */\n width?: number;\n}\n\n/**\n * Render ANSI‑escaped lines directly to terminal output.\n *\n * Joins lines with newlines and renders as a single Text node.\n * In standard Ink, ANSI codes in Text children are preserved in\n * terminal output — no special parsing needed.\n */\nexport function RawAnsi({ lines }: RawAnsiProps): React.ReactElement | null {\n if (lines.length === 0) return null;\n return React.createElement(Text, null, lines.join(\"\\n\"));\n}\n","/**\n * Spinner — animated loading indicator with configurable frame sets.\n *\n * Renders a cycling character animation at a configurable interval.\n * Use for streaming states, tool execution, or any indeterminate wait.\n *\n * Design (§5.9b): 3‑frame cycle, configurable speed, works in both\n * fullscreen and inline contexts.\n */\n\nimport React, { useState, useEffect, useRef } from \"react\";\nimport { Text } from \"ink\";\n\n/** Pre‑built spinner frame sets. */\nexport const SPINNER_FRAMES = {\n dots: [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"],\n line: [\"|\", \"/\", \"-\", \"\\\\\"],\n pulse: [\"█\", \"▓\", \"▒\", \"░\"],\n arrow: [\"←\", \"↖\", \"↑\", \"↗\", \"→\", \"↘\", \"↓\", \"↙\"],\n bounce: [\"⠁\", \"⠂\", \"⠄\", \"⡀\", \"⢀\", \"⠠\", \"⠐\", \"⠈\"],\n} as const;\n\n/** Props for the Spinner component. */\nexport interface SpinnerProps {\n /** Frame set name or custom frame array. Default: \"dots\". */\n frames?: keyof typeof SPINNER_FRAMES | string[];\n /** Interval between frames in milliseconds. Default: 80. */\n intervalMs?: number;\n /** Optional label rendered after the spinner. */\n label?: string;\n /** Color token from the theme. Default: \"spinner\". */\n color?: string;\n}\n\n/**\n * Animated spinner component.\n *\n * Cycles through frames at `intervalMs` speed. Cleans up the\n * interval timer on unmount to prevent memory leaks.\n */\nexport function Spinner({\n frames = \"dots\",\n intervalMs = 80,\n label,\n color,\n}: SpinnerProps): React.ReactElement {\n const frameSet =\n typeof frames === \"string\" ? (SPINNER_FRAMES[frames] ?? SPINNER_FRAMES.dots) : frames;\n const [index, setIndex] = useState(0);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n const id = setInterval(() => {\n if (!mountedRef.current) return;\n setIndex((prev) => (prev + 1) % frameSet.length);\n }, intervalMs);\n return () => {\n mountedRef.current = false;\n clearInterval(id);\n };\n }, [frameSet.length, intervalMs]);\n\n const frame = frameSet[index]!;\n if (label) {\n return React.createElement(Text, color ? { color } : undefined, `${frame} ${label}`);\n }\n return React.createElement(Text, color ? { color } : undefined, frame);\n}\n","/**\n * NoSelect — marks content as non‑selectable during alt‑screen text selection.\n *\n * In standard Ink 6.x (without custom renderer extensions), terminal text\n * selection is handled by the terminal emulator, not Ink. This component\n * is a semantic wrapper: Box with role annotation for accessibility.\n *\n * When Lynx adopts a custom Ink renderer (Tier 5), this component will\n * integrate with the noSelect DOM attribute for true selection exclusion.\n *\n * Design (§5.9b): fences off gutters (line numbers, diff sigils, list\n * bullets) so click‑drag yields clean pasteable content.\n */\n\nimport React from \"react\";\nimport { Box } from \"ink\";\nimport type { ReactNode } from \"react\";\n\n/** Props for the NoSelect wrapper. */\nexport interface NoSelectProps {\n /** Content to mark as non‑selectable. */\n children: ReactNode;\n /**\n * Extend the exclusion zone from column 0 to the right edge.\n * Reserved for future custom‑renderer integration.\n */\n fromLeftEdge?: boolean;\n}\n\n/**\n * Semantic wrapper for non‑selectable content.\n *\n * Currently renders as a plain Box (standard Ink has no selection API).\n * When custom renderer support is added, this will integrate with the\n * noSelect DOM attribute.\n */\nexport function NoSelect({ children }: NoSelectProps): React.ReactElement {\n return React.createElement(Box, null, children);\n}\n","/**\n * useInput — bridge between Ink's raw input and the agent's submit callback.\n *\n * Handles 3-parameter handler: (input: string, key: Key, event: InputEvent).\n * Exposes controlled input state and keyboard-aware submission.\n */\n\nimport { useState, useCallback, useRef } from \"react\";\nimport { useInput as useInkInput } from \"ink\";\nimport type { Key } from \"ink\";\n\n// ── Types ────────────────────────────────────────────\n\n/** Controlled input state — current value, cursor position, and focus status. */\nexport interface InputState {\n /** Current text in the input box. */\n value: string;\n /** Cursor position within the value. */\n cursor: number;\n /** Whether the input is currently focused. */\n focused: boolean;\n}\n\n/** Input mutation actions — set, clear, focus, blur, submit, and insert text. */\nexport interface InputActions {\n /** Set the full value. */\n setValue: (value: string) => void;\n /** Clear the input. */\n clear: () => void;\n /** Focus the input. */\n focus: () => void;\n /** Blur the input. */\n blur: () => void;\n /** Submit the current value. Returns the submitted text. */\n submit: () => string;\n /** Insert text at cursor position. */\n insert: (text: string) => void;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Controlled input hook for the main REPL input area.\n *\n * @param onSubmit Called when the user presses Enter with non‑empty input.\n * @param onKey Optional handler for non‑Enter key presses (slash menu, shortcuts, etc.).\n */\nexport function useInput(\n onSubmit: (text: string) => void,\n onKey?: (input: string, key: Key) => void,\n): [InputState, InputActions] {\n const [value, setValue] = useState(\"\");\n const [cursor, setCursor] = useState(0);\n const [focused, setFocused] = useState(true);\n const inputRef = useRef<InputState>({ value: \"\", cursor: 0, focused: true });\n\n // Sync ref with state for the Ink callback\n inputRef.current = { value, cursor, focused };\n\n useInkInput(\n (rawInput: string, key: Key) => {\n if (!inputRef.current.focused) return;\n\n if (key.return) {\n const text = inputRef.current.value.trim();\n if (text) {\n onSubmit(text);\n setValue(\"\");\n setCursor(0);\n }\n return;\n }\n\n if (onKey) {\n onKey(inputRef.current.value, key);\n }\n },\n { isActive: focused },\n );\n\n const actions: InputActions = {\n setValue: useCallback((v: string) => {\n setValue(v);\n setCursor(v.length);\n }, []),\n\n clear: useCallback(() => {\n setValue(\"\");\n setCursor(0);\n }, []),\n\n focus: useCallback(() => {\n setFocused(true);\n }, []),\n\n blur: useCallback(() => {\n setFocused(false);\n }, []),\n\n submit: useCallback((): string => {\n const text = value.trim();\n if (text) {\n onSubmit(text);\n setValue(\"\");\n setCursor(0);\n }\n return text;\n }, [value, onSubmit]),\n\n insert: useCallback(\n (text: string) => {\n setValue((prev) => {\n const pos = cursor;\n return prev.slice(0, pos) + text + prev.slice(pos);\n });\n setCursor((prev) => prev + text.length);\n },\n [cursor],\n ),\n };\n\n return [{ value, cursor, focused }, actions];\n}\n","/**\n * Text sanitization — strip control characters, ANSI escapes, and\n * handle Unicode RTL isolation for safe terminal rendering.\n *\n * All functions are sync and pure — they take a string and return a\n * cleaned version suitable for display.\n */\n\n// ── Constants ────────────────────────────────────────\n\n/** Maximum length of a \"word\" token before insertion of soft breaks. */\nconst LONG_TOKEN_LENGTH = 33;\n\n/** Characters that valid URLs may contain (after the scheme). */\nconst URL_CHARS = /^[a-zA-Z0-9._~:/?#[\\]@!$&'()*+,;=\\-]+$/;\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Strip ANSI escape sequences (CSI, OSC, etc.) from text.\n *\n * Matches: CSI (\\\\x1b[), OSC (\\\\x1b]), and single‑character escapes.\n * Does NOT strip SGR‑only sequences within Ink elements —\n * this is for raw text from tool output or LLM responses.\n */\nexport function stripAnsi(text: string): string {\n // eslint-disable-next-line no-control-regex\n return (\n text\n .replace(/\\x1b\\[[0-9;]*[a-zA-Z]/g, \"\")\n // eslint-disable-next-line no-control-regex\n .replace(/\\x1b\\][^\\x07]*\\x07/g, \"\")\n // eslint-disable-next-line no-control-regex\n .replace(/\\x1b[()][0-9AB]/g, \"\")\n // eslint-disable-next-line no-control-regex\n .replace(/\\x1b[><=]/g, \"\")\n );\n}\n\n/**\n * Strip control characters from text, preserving tab and newline.\n *\n * Removes: NUL, BEL, BS, FF, CR, SO, SI, DLE–US, DEL.\n * Preserves: \\\\t (tab), \\\\n (newline), \\\\r (carriage return).\n */\nexport function stripControlChars(text: string): string {\n return text\n .replace(/\\x00/g, \"\") // NUL\n .replace(/\\x07/g, \"\") // BEL\n .replace(/\\x08/g, \"\") // BS\n .replace(/\\x0c/g, \"\") // FF\n .replace(/\\x0e/g, \"\") // SO\n .replace(/\\x0f/g, \"\") // SI\n .replace(/[\\x10-\\x1a]/g, \"\") // DLE–SUB\n .replace(/\\x1c/g, \"\") // FS\n .replace(/\\x1d/g, \"\") // GS\n .replace(/\\x1e/g, \"\") // RS\n .replace(/\\x1f/g, \"\") // US\n .replace(/\\x7f/g, \"\"); // DEL\n}\n\n/**\n * Wrap RTL (right‑to‑left) text with Unicode bidirectional isolation\n * characters to prevent it from corrupting surrounding LTR layout.\n *\n * RTL scripts detected: Arabic, Hebrew, Syriac, Thaana, N'Ko.\n */\nexport function isolateRtl(text: string): string {\n // Only wrap if RTL characters are present (avoid superfluous marks)\n // eslint-disable-next-line no-misleading-character-class\n if (!/[֐-ࣿיִ-﷿ﹰ-﻾]/.test(text)) return text;\n return `⁨${text}⁩`;\n}\n\n/**\n * Insert soft line‑break opportunities into long \"words\" (tokens) to\n * prevent terminal line overflow. URLs and code blocks are preserved.\n *\n * Tokens longer than {@link LONG_TOKEN_LENGTH} characters are split\n * with zero‑width spaces every 33 characters.\n */\nexport function chunkLongTokens(text: string, maxLen: number = LONG_TOKEN_LENGTH): string {\n // Don't modify text that looks like a code block\n if (text.startsWith(\"```\")) return text;\n\n const words = text.split(/(\\s+)/);\n const result: string[] = [];\n\n for (const word of words) {\n if (word.length <= maxLen) {\n result.push(word);\n continue;\n }\n\n // Preserve URLs\n if (isUrl(word)) {\n result.push(word);\n continue;\n }\n\n // Insert ZWSP every maxLen characters\n const chunks: string[] = [];\n for (let i = 0; i < word.length; i += maxLen) {\n chunks.push(word.slice(i, i + maxLen));\n }\n result.push(chunks.join(\"​\"));\n }\n\n return result.join(\"\");\n}\n\n/**\n * Detect binary content by measuring the ratio of non‑printable\n * characters (excluding common whitespace).\n *\n * If the binary ratio exceeds 50%, returns `\"[binary content]\"`;\n * otherwise returns the original text.\n */\nexport function redactBinaryContent(text: string): string {\n // Short text can't be reliably detected\n if (text.length < 10) return text;\n\n let nonPrintable = 0;\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n // Allow: newline, tab, printable ASCII, and common Unicode\n if (code === 0x0a || code === 0x0d || code === 0x09) continue;\n if (code >= 0x20 && code <= 0x7e) continue;\n if (code >= 0x80) continue; // Non‑ASCII (including CJK)\n nonPrintable++;\n }\n\n const ratio = nonPrintable / text.length;\n if (ratio > 0.5) {\n return \"[binary content]\";\n }\n\n return text;\n}\n\n/**\n * Full sanitization pipeline — applies all sanitizers in order.\n *\n * This is the recommended entry point for cleaning tool output\n * before rendering in the TUI.\n */\nexport function sanitize(text: string): string {\n let cleaned = stripAnsi(text);\n cleaned = stripControlChars(cleaned);\n cleaned = redactBinaryContent(cleaned);\n cleaned = chunkLongTokens(cleaned);\n return cleaned;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\nfunction isUrl(text: string): boolean {\n return /^https?:\\/\\//.test(text) && URL_CHARS.test(text.slice(8));\n}\n","/**\n * Keybindings — catalog of keyboard shortcuts with context‑aware dispatch.\n *\n * Each binding maps a key combination to an action, optionally scoped\n * to a specific view. The dispatcher resolves the binding for the\n * current context and executes it.\n */\n\nimport type { Key } from \"ink\";\n\n// ── Types ────────────────────────────────────────────\n\n/** Describes a keyboard shortcut — description, scope, key matcher, and callback action. */\nexport interface KeyBinding {\n /** Human‑readable description shown in the help modal. */\n description: string;\n /** Which views this binding applies to (empty = all views). */\n scopes: string[];\n /** Key matcher function. */\n match: (input: string, key: Key) => boolean;\n /** Action to execute. */\n action: () => void;\n}\n\n/** Ordered list of keybindings — each checked for match in the current context scope. */\nexport type KeyBindingCatalog = KeyBinding[];\n\n// ── Built‑in bindings ────────────────────────────────\n\n/**\n * Create the default keybinding catalog.\n *\n * Callers provide concrete actions for each binding.\n * The catalog is stateless — each binding is a closure\n * over the action it should perform.\n */\nexport function createDefaultBindings(actions: {\n abort: () => void;\n help: () => void;\n sessionPicker: () => void;\n clearScreen: () => void;\n scrollUp: () => void;\n scrollDown: () => void;\n}): KeyBindingCatalog {\n return [\n {\n description: \"Abort current operation\",\n scopes: [],\n match: (_input: string, key: Key) => key.ctrl && _input === \"g\",\n // Ctrl+C is handled specially by the input system; this is Ctrl+G\n action: actions.abort,\n },\n {\n description: \"Show help\",\n scopes: [],\n match: (_input: string, key: Key) => key.ctrl && _input === \"h\",\n action: actions.help,\n },\n {\n description: \"Switch session\",\n scopes: [\"chat\"],\n match: (_input: string, key: Key) => key.ctrl && _input === \"s\",\n action: actions.sessionPicker,\n },\n {\n description: \"Clear screen\",\n scopes: [\"chat\"],\n match: (_input: string, key: Key) => key.ctrl && _input === \"l\",\n action: actions.clearScreen,\n },\n {\n description: \"Scroll up\",\n scopes: [\"chat\"],\n match: (_input: string, key: Key) => key.pageUp || (key.ctrl && _input === \"u\"),\n action: actions.scrollUp,\n },\n {\n description: \"Scroll down\",\n scopes: [\"chat\"],\n match: (_input: string, key: Key) => key.pageDown || (key.ctrl && _input === \"d\"),\n action: actions.scrollDown,\n },\n ];\n}\n\n// ── Dispatcher ───────────────────────────────────────\n\n/**\n * Find and execute the first matching keybinding for the current scope.\n *\n * @returns true if a binding matched and was executed.\n */\nexport function dispatchBinding(\n catalog: KeyBindingCatalog,\n scope: string,\n input: string,\n key: Key,\n): boolean {\n for (const binding of catalog) {\n const inScope = binding.scopes.length === 0 || binding.scopes.includes(scope);\n if (inScope && binding.match(input, key)) {\n binding.action();\n return true;\n }\n }\n return false;\n}\n","/**\n * ErrorBoundary — catches rendering errors in the Ink component tree.\n *\n * On error, displays a red error message with the error details and\n * instructions to restart. Prevents the entire TUI from crashing\n * due to a single component error.\n */\n\nimport React from \"react\";\nimport { Box, Text } from \"ink\";\n\n/** Props for the ErrorBoundary. */\nexport interface ErrorBoundaryProps {\n children: React.ReactNode;\n}\n\n/** State tracked by the ErrorBoundary. */\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\n/**\n * React error boundary for Ink components.\n *\n * Catches rendering errors and displays a fallback UI instead of\n * crashing the entire terminal application.\n */\nexport class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n // Log to stderr so it appears in terminal logs\n process.stderr.write(\n `[ErrorBoundary] ${error.message}\\n${error.stack ?? \"\"}\\nComponent stack: ${errorInfo.componentStack ?? \"\"}\\n`,\n );\n }\n\n render(): React.ReactNode {\n if (this.state.hasError) {\n return React.createElement(\n Box,\n {\n flexDirection: \"column\",\n borderStyle: \"round\",\n borderColor: \"red\",\n paddingX: 2,\n paddingY: 1,\n },\n React.createElement(Text, { bold: true, color: \"red\" }, \"✘ Lynx TUI encountered an error\"),\n React.createElement(Text, { dimColor: true }, this.state.error?.message ?? \"Unknown error\"),\n React.createElement(Box, { height: 1 }),\n React.createElement(Text, { dimColor: true }, \"Press Ctrl+C to exit and restart.\"),\n );\n }\n\n return this.props.children;\n }\n}\n","/**\n * AlternateScreen — Ink component wrapping alt‑buffer management.\n *\n * Calls enterFullscreen/exitFullscreen lifecycle hooks when mounted/unmounted.\n * Use this instead of calling terminal-mode utilities directly.\n *\n * Design (§5.9b): componentized alternate screen for fullscreen layout.\n */\n\nimport React, { useEffect } from \"react\";\nimport type { ReactNode } from \"react\";\n\n/** Props for the AlternateScreen wrapper. */\nexport interface AlternateScreenProps {\n /** Children rendered inside the alt buffer. */\n children: ReactNode;\n /** Called when entering fullscreen mode. */\n onEnter(): void;\n /** Called when exiting fullscreen mode. */\n onExit(): void;\n}\n\n/**\n * Wraps children in alternate‑buffer lifecycle management.\n *\n * Calls `onEnter` on mount and `onExit` on unmount,\n * ensuring terminal recovery even on unexpected crashes.\n */\nexport function AlternateScreen({\n children,\n onEnter,\n onExit,\n}: AlternateScreenProps): React.ReactElement {\n useEffect(() => {\n onEnter();\n return () => {\n onExit();\n };\n // Only run on mount/unmount — callbacks are stable references\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return React.createElement(React.Fragment, null, children);\n}\n"],"mappings":";;;;;;;AAWA,MAAM,SAAsC;CAC1C,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;CACA,YAAY;EACV,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;CACA,WAAW;EACT,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,YAAY;GACZ,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,SAAS;GACT,QAAQ;GACR,WAAW;GACX,iBAAiB;GACjB,iBAAiB;GACjB,SAAS;GACT,YAAY;EACd;CACF;AACF;AAIA,IAAI,WAAsB;;AAG1B,SAAS,cAAyB;CAChC,IAAI,QAAQ,IAAI,UAAU,OAAO;CACjC,IAAI,QAAQ,IAAI,cAAc,OAAO,QAAQ,IAAI,aAC/C,OAAO,QAAQ,IAAI;CAErB,OAAO;AACT;;AAKA,SAAgB,YAAkB;CAChC,WAAW,YAAY;AACzB;;AAGA,SAAgB,WAAqB;CACnC,OAAO,OAAO;AAChB;;AAGA,SAAgB,SAAS,MAAuB;CAC9C,IAAI,OAAO,OACT,WAAW;AAEf;;AAGA,SAAgB,MAAM,MAAsB;CAC1C,MAAM,QAAQ,OAAO;CACrB,OAAO,MAAM,OAAO,SAAS,MAAM,OAAO;AAC5C;;AAGA,SAAgB,aAA0B;CACxC,OAAO,OAAO,KAAK,MAAM;AAC3B;;;;AC3HA,MAAM,cAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,WAAW,IAAI,IAAI;CACvB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,cAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,cAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,gBAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,cAAc,IAAI,IAAI;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,eAAe,IAAI,IAAI;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,gBAAgB,IAAI,IAAY;CAAC;CAAQ;CAAS;AAAM,CAAC;AAC/D,MAAM,gBAAgB,IAAI,IAAY;CAAC;CAA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"}