@24klynx/tui 0.1.0 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -8
package/dist/index.mjs.map
CHANGED
|
@@ -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 \"@lynx/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 \"@lynx/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;CAA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"}
|
|
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"}
|