@dmrlzz/davecode 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +5 -4
  2. package/bin/davecode.js +0 -0
  3. package/dist/{ChatApp-FO5SABXB.js → ChatApp-CJBICQGA.js} +289 -137
  4. package/dist/ChatApp-CJBICQGA.js.map +1 -0
  5. package/dist/{RunnerView-DLVR7C22.js → RunnerView-A7JSPUW5.js} +5 -5
  6. package/dist/account-QWDPJWAA.js +23 -0
  7. package/dist/accounts-IQMR72FC.js +37 -0
  8. package/dist/{budget-RBHCEDPP.js → budget-XANOUVWO.js} +6 -6
  9. package/dist/chat-KDDRNC5V.js +359 -0
  10. package/dist/chat-KDDRNC5V.js.map +1 -0
  11. package/dist/{accounts-MTMGYKEP.js → chunk-44AFJL2X.js} +24 -17
  12. package/dist/chunk-44AFJL2X.js.map +1 -0
  13. package/dist/{chunk-BOLFK3BH.js → chunk-5LKOJBUL.js} +2 -2
  14. package/dist/{chunk-23KTE7IK.js → chunk-AZKACMME.js} +2 -2
  15. package/dist/{chunk-PIIJ3RSI.js → chunk-FYPMA55O.js} +1269 -1265
  16. package/dist/chunk-FYPMA55O.js.map +1 -0
  17. package/dist/{chunk-OYEYNDOO.js → chunk-GE22VBCY.js} +3 -3
  18. package/dist/{chunk-C7FDRA3U.js → chunk-HSBJDV3O.js} +660 -139
  19. package/dist/chunk-HSBJDV3O.js.map +1 -0
  20. package/dist/chunk-JLATEHS7.js +20 -0
  21. package/dist/chunk-JLATEHS7.js.map +1 -0
  22. package/dist/{chunk-VVCXGQMY.js → chunk-MC7RIPL7.js} +17 -8
  23. package/dist/chunk-MC7RIPL7.js.map +1 -0
  24. package/dist/{chunk-MSLLH5XP.js → chunk-PGAJIGUF.js} +4 -4
  25. package/dist/{chunk-OXRMGR72.js → chunk-PGPXE6LF.js} +2 -2
  26. package/dist/chunk-QA3O6RA2.js +81 -0
  27. package/dist/chunk-QA3O6RA2.js.map +1 -0
  28. package/dist/chunk-W7GPBEBZ.js +144 -0
  29. package/dist/chunk-W7GPBEBZ.js.map +1 -0
  30. package/dist/{chunk-IVZHKUCD.js → chunk-WQ7MEWDF.js} +3 -3
  31. package/dist/{config-FRMY5OHG.js → config-YTUPIYZT.js} +5 -5
  32. package/dist/dashboard/assets/Accounts-cq8RLMoI.js +1 -0
  33. package/dist/dashboard/assets/Badge-Z4RBdO9j.js +55 -0
  34. package/dist/dashboard/assets/Callout-w8BTYh4k.js +1 -0
  35. package/dist/dashboard/assets/Field-Cmpgg_1z.js +1 -0
  36. package/dist/dashboard/assets/Goals-Bw02to72.js +1 -0
  37. package/dist/dashboard/assets/Library-DK7mlpRb.js +1 -0
  38. package/dist/dashboard/assets/{Markdown-ClRsddnB.js → Markdown-DCZ4Awcc.js} +8 -8
  39. package/dist/dashboard/assets/Panes-_KTf8pbZ.js +8 -0
  40. package/dist/dashboard/assets/Panes-kHJ-D0s7.css +1 -0
  41. package/dist/dashboard/assets/RoutesPage-QV0oPRW9.js +4 -0
  42. package/dist/dashboard/assets/Runner-CkHBLQl0.js +1 -0
  43. package/dist/dashboard/assets/Settings-BLz2gTBR.js +1 -0
  44. package/dist/dashboard/assets/Switch-DPYlLseH.js +1 -0
  45. package/dist/dashboard/assets/Tasks-BiUQSTpt.js +2 -0
  46. package/dist/dashboard/assets/Traffic-BVfBuC70.js +1 -0
  47. package/dist/dashboard/assets/Workspace-CJTgiiU5.js +1 -0
  48. package/dist/dashboard/assets/arrow-up-DjhzZprp.js +1 -0
  49. package/dist/dashboard/assets/cn-BwE4cei0.js +1 -0
  50. package/dist/dashboard/assets/forms-DVIUAxAc.js +1 -0
  51. package/dist/dashboard/assets/index-BDBa5cb0.js +104 -0
  52. package/dist/dashboard/assets/index-BEmBgsbP.css +2 -0
  53. package/dist/dashboard/assets/task-errors-Daqwi0ue.js +1 -0
  54. package/dist/dashboard/assets/trash-BTuDcSaQ.js +1 -0
  55. package/dist/dashboard/favicon.svg +1 -7
  56. package/dist/dashboard/index.html +4 -4
  57. package/dist/{dist-ZPXEVBEC.js → dist-37VQSHHA.js} +24 -2
  58. package/dist/dist-37VQSHHA.js.map +1 -0
  59. package/dist/{doctor-7RUD4D3A.js → doctor-PYUQRRCB.js} +5 -5
  60. package/dist/{goal-JFRNPBSD.js → goal-SXZUDUCL.js} +5 -5
  61. package/dist/index.js +48 -30
  62. package/dist/index.js.map +1 -1
  63. package/dist/{init-NFYNO3A3.js → init-Z2AFQEEP.js} +6 -6
  64. package/dist/{prompts-L37J72YW.js → prompts-TZ7UC42M.js} +9 -5
  65. package/dist/prompts-TZ7UC42M.js.map +1 -0
  66. package/dist/{run-ARUPXFFB.js → run-AOS7L3RT.js} +10 -10
  67. package/dist/runtime.js +18 -0
  68. package/dist/runtime.js.map +1 -0
  69. package/dist/{start-CFPOVIAR.js → start-CEPXKZUE.js} +5 -5
  70. package/dist/{status-E4EACVE2.js → status-WNJ3GGKU.js} +6 -6
  71. package/dist/status-WNJ3GGKU.js.map +1 -0
  72. package/dist/{tasks-ZIK6BVEX.js → tasks-TFUTUMWB.js} +6 -6
  73. package/package.json +21 -15
  74. package/dist/ChatApp-FO5SABXB.js.map +0 -1
  75. package/dist/accounts-MTMGYKEP.js.map +0 -1
  76. package/dist/chat-ZDXX3N6X.js +0 -95
  77. package/dist/chat-ZDXX3N6X.js.map +0 -1
  78. package/dist/chunk-C7FDRA3U.js.map +0 -1
  79. package/dist/chunk-DYQ56FBT.js +0 -47
  80. package/dist/chunk-DYQ56FBT.js.map +0 -1
  81. package/dist/chunk-PIIJ3RSI.js.map +0 -1
  82. package/dist/chunk-VVCXGQMY.js.map +0 -1
  83. package/dist/dashboard/assets/Accounts-BR3ZfVk4.js +0 -1
  84. package/dist/dashboard/assets/Badge-B-qzNRrZ.js +0 -55
  85. package/dist/dashboard/assets/Callout-B9g_wPDi.js +0 -1
  86. package/dist/dashboard/assets/Field-BfabPEcY.js +0 -1
  87. package/dist/dashboard/assets/Goals-BsV-6m94.js +0 -1
  88. package/dist/dashboard/assets/Library-CEA9P1m-.js +0 -1
  89. package/dist/dashboard/assets/Panel-B9tSgX6l.js +0 -1
  90. package/dist/dashboard/assets/RoutesPage-Dh-BJ3ir.js +0 -4
  91. package/dist/dashboard/assets/Runner-C_e9l5l2.js +0 -1
  92. package/dist/dashboard/assets/Settings-C6Yc1Gjg.js +0 -1
  93. package/dist/dashboard/assets/Switch-CUpOJjUT.js +0 -1
  94. package/dist/dashboard/assets/Tasks-CTku0rR3.js +0 -2
  95. package/dist/dashboard/assets/Traffic-CE6wZSMr.js +0 -1
  96. package/dist/dashboard/assets/Workspace-CxFxvkA6.js +0 -1
  97. package/dist/dashboard/assets/arrow-up-DL3CuFOO.js +0 -1
  98. package/dist/dashboard/assets/forms-D6UIYgC5.js +0 -1
  99. package/dist/dashboard/assets/index-1iH716Xy.css +0 -2
  100. package/dist/dashboard/assets/index-BMWr9EKo.js +0 -104
  101. package/dist/dashboard/assets/task-errors-CE4oEr8H.js +0 -1
  102. package/dist/dashboard/assets/trash-CWqeZ7eg.js +0 -1
  103. package/dist/prompts-L37J72YW.js.map +0 -1
  104. /package/dist/{RunnerView-DLVR7C22.js.map → RunnerView-A7JSPUW5.js.map} +0 -0
  105. /package/dist/{dist-ZPXEVBEC.js.map → account-QWDPJWAA.js.map} +0 -0
  106. /package/dist/{status-E4EACVE2.js.map → accounts-IQMR72FC.js.map} +0 -0
  107. /package/dist/{budget-RBHCEDPP.js.map → budget-XANOUVWO.js.map} +0 -0
  108. /package/dist/{chunk-BOLFK3BH.js.map → chunk-5LKOJBUL.js.map} +0 -0
  109. /package/dist/{chunk-23KTE7IK.js.map → chunk-AZKACMME.js.map} +0 -0
  110. /package/dist/{chunk-OYEYNDOO.js.map → chunk-GE22VBCY.js.map} +0 -0
  111. /package/dist/{chunk-MSLLH5XP.js.map → chunk-PGAJIGUF.js.map} +0 -0
  112. /package/dist/{chunk-OXRMGR72.js.map → chunk-PGPXE6LF.js.map} +0 -0
  113. /package/dist/{chunk-IVZHKUCD.js.map → chunk-WQ7MEWDF.js.map} +0 -0
  114. /package/dist/{config-FRMY5OHG.js.map → config-YTUPIYZT.js.map} +0 -0
  115. /package/dist/{doctor-7RUD4D3A.js.map → doctor-PYUQRRCB.js.map} +0 -0
  116. /package/dist/{goal-JFRNPBSD.js.map → goal-SXZUDUCL.js.map} +0 -0
  117. /package/dist/{init-NFYNO3A3.js.map → init-Z2AFQEEP.js.map} +0 -0
  118. /package/dist/{run-ARUPXFFB.js.map → run-AOS7L3RT.js.map} +0 -0
  119. /package/dist/{start-CFPOVIAR.js.map → start-CEPXKZUE.js.map} +0 -0
  120. /package/dist/{tasks-ZIK6BVEX.js.map → tasks-TFUTUMWB.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/tui/ChatApp.tsx","../src/tui/chat-state.ts","../src/tui/components/InputBox.tsx","../src/tui/editor.ts","../src/tui/components/StatusLine.tsx","../src/tui/components/Transcript.tsx","../src/tui/slash.ts","../src/tui/slash-actions.ts"],"sourcesContent":["import type { Usage } from '@davecode/core';\nimport { Box, Static, useApp, useInput, usePaste, useStdout, useWindowSize } from 'ink';\nimport { useCallback, useEffect, useReducer, useRef, useState } from 'react';\nimport type { Theme } from '../ui/theme';\nimport type { ChatBackend } from './backend';\nimport { chatReducer, initialChatState } from './chat-state';\nimport { InputBox, SlashHints } from './components/InputBox';\nimport { StatusLine } from './components/StatusLine';\nimport { EntryView, StreamingView } from './components/Transcript';\nimport * as ed from './editor';\nimport { completeSlash, parseSlash, slashSuggestions } from './slash';\nimport {\n accountsText,\n helpText,\n modelsText,\n routesText,\n statusText,\n tasksText,\n} from './slash-actions';\nimport { ThemeProvider, useTheme } from './theme-context';\n\nexport interface ChatAppProps {\n backend: ChatBackend;\n theme: Theme;\n model: string;\n version: string;\n /** Health polling interval (tests use a short one). */\n pollMs?: number;\n /** Time source (tests). */\n now?: () => number;\n}\n\nconst PLACEHOLDER = 'Ask anything · / for commands · Shift+Enter or Ctrl+J for a new line';\nconst EXIT_WINDOW_MS = 2000;\n\nfunction errorText(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction Chat({ backend, model, version, pollMs = 10_000, now = Date.now }: ChatAppProps) {\n const theme = useTheme();\n const { exit } = useApp();\n const { write } = useStdout();\n const { columns } = useWindowSize();\n const width = Math.max(20, columns);\n\n const [state, dispatch] = useReducer(chatReducer, model, initialChatState);\n const [editor, setEditor] = useState<ed.EditorState>(ed.emptyEditor);\n const [historyIndex, setHistoryIndex] = useState<number | undefined>();\n const [notice, setNotice] = useState<string | undefined>();\n const [clock, setClock] = useState(now());\n\n const abortRef = useRef<AbortController | undefined>(undefined);\n const exitArmedAt = useRef<number | undefined>(undefined);\n const labels = useRef(new Map<string, string>());\n const stateRef = useRef(state);\n stateRef.current = state;\n\n // --- lifecycle -----------------------------------------------------------\n\n useEffect(() => {\n const where = backend.inProcess ? `${backend.url} (in-process)` : backend.url;\n dispatch({\n type: 'banner',\n text: `${theme.bold(theme.accent('DaveCode'))} ${theme.dim(`v${version}`)}\\n${theme.dim(\n `model ${model} · gateway ${where} · /help for commands`,\n )}`,\n });\n let alive = true;\n const check = async () => {\n const health = await backend.health();\n if (alive) dispatch({ type: 'connection', connection: health ? 'online' : 'offline' });\n };\n void check();\n backend\n .accounts()\n .then((accounts) => {\n for (const a of accounts) labels.current.set(a.id, a.label);\n })\n .catch(() => {});\n const timer = setInterval(() => void check(), pollMs);\n return () => {\n alive = false;\n clearInterval(timer);\n abortRef.current?.abort();\n };\n }, [backend, model, pollMs, theme, version]);\n\n // Elapsed-time display while a reply is streaming.\n useEffect(() => {\n if (!state.streaming) return;\n const timer = setInterval(() => setClock(now()), 250);\n return () => clearInterval(timer);\n }, [state.streaming, now]);\n\n useEffect(() => {\n if (!notice) return;\n const timer = setTimeout(() => setNotice(undefined), EXIT_WINDOW_MS);\n return () => clearTimeout(timer);\n }, [notice]);\n\n // --- actions -------------------------------------------------------------\n\n const refreshQuota = useCallback(\n async (accountId: string) => {\n try {\n const usage = (await backend.usage()).find((u) => u.accountId === accountId);\n const window = usage?.windows['5h'];\n const limited =\n window && (window.tokenLimit !== undefined || window.requestLimit !== undefined);\n dispatch({\n type: 'quota',\n accountId,\n utilization: limited ? window.utilization : undefined,\n });\n } catch {\n // Quota is decoration; ignore failures.\n }\n },\n [backend],\n );\n\n const send = useCallback(\n async (text: string) => {\n dispatch({ type: 'user', text });\n const conversation = [\n ...stateRef.current.conversation,\n { role: 'user' as const, content: text },\n ];\n const controller = new AbortController();\n abortRef.current = controller;\n dispatch({ type: 'stream-start', now: now() });\n let usage: Usage | undefined;\n let accountId: string | undefined;\n try {\n const { meta, chunks } = await backend.stream(\n { model: stateRef.current.model, messages: conversation },\n controller.signal,\n );\n accountId = meta.accountId;\n dispatch({\n type: 'stream-meta',\n failovers: meta.failovers,\n ...(meta.accountId ? { accountId: meta.accountId } : {}),\n ...(meta.provider ? { provider: meta.provider } : {}),\n ...(meta.accountId && labels.current.has(meta.accountId)\n ? { accountLabel: labels.current.get(meta.accountId)! }\n : {}),\n });\n dispatch({ type: 'connection', connection: 'online' });\n for await (const chunk of chunks) {\n if (controller.signal.aborted) break;\n const delta = chunk.choices[0]?.delta?.content;\n if (typeof delta === 'string' && delta) dispatch({ type: 'stream-delta', text: delta });\n if (chunk.usage) usage = chunk.usage;\n }\n dispatch({\n type: 'stream-end',\n now: now(),\n ...(usage ? { usage } : {}),\n ...(controller.signal.aborted ? { cancelled: true } : {}),\n });\n } catch (err) {\n if (controller.signal.aborted) {\n dispatch({ type: 'stream-end', now: now(), cancelled: true });\n } else {\n const status = (err as { status?: number }).status;\n if (status === 0) dispatch({ type: 'connection', connection: 'offline' });\n dispatch({ type: 'stream-end', now: now(), error: errorText(err) });\n }\n } finally {\n if (abortRef.current === controller) abortRef.current = undefined;\n }\n if (accountId) void refreshQuota(accountId);\n },\n [backend, now, refreshQuota],\n );\n\n const runSlash = useCallback(\n async (input: string) => {\n const parsed = parseSlash(input);\n if (parsed.kind === 'unknown') {\n dispatch({\n type: 'error',\n text: `Unknown command /${parsed.name}. Type /help for the list.`,\n });\n return;\n }\n if (parsed.kind !== 'command') return;\n const { command, args } = parsed;\n try {\n switch (command.name) {\n case 'help':\n dispatch({ type: 'info', text: helpText(theme) });\n break;\n case 'exit':\n abortRef.current?.abort();\n exit();\n break;\n case 'clear':\n abortRef.current?.abort();\n write('\\u001b[2J\\u001b[3J\\u001b[H');\n dispatch({ type: 'clear' });\n break;\n case 'model':\n if (args) {\n dispatch({ type: 'set-model', model: args });\n dispatch({ type: 'info', text: `Model set to ${theme.accent(args)}` });\n } else {\n dispatch({\n type: 'info',\n text: await modelsText(theme, backend, stateRef.current.model),\n });\n }\n break;\n case 'route':\n dispatch({ type: 'info', text: await routesText(theme, backend) });\n break;\n case 'accounts': {\n const accounts = await backend.accounts();\n for (const a of accounts) labels.current.set(a.id, a.label);\n dispatch({ type: 'info', text: await accountsText(theme, backend, width - 4) });\n break;\n }\n case 'tasks':\n dispatch({ type: 'info', text: await tasksText(theme, backend, width - 4) });\n break;\n case 'status':\n dispatch({ type: 'info', text: await statusText(theme, backend) });\n break;\n }\n } catch (err) {\n dispatch({ type: 'error', text: `/${command.name} failed: ${errorText(err)}` });\n }\n },\n [backend, exit, theme, width, write],\n );\n\n const submit = useCallback(() => {\n const text = ed.textOf(editor).trim();\n if (!text) return;\n if (parseSlash(text).kind !== 'none') {\n setEditor(ed.emptyEditor);\n setHistoryIndex(undefined);\n void runSlash(text);\n return;\n }\n if (stateRef.current.streaming) {\n setNotice('Wait for the reply, or press Esc to cancel it');\n return;\n }\n setEditor(ed.emptyEditor);\n setHistoryIndex(undefined);\n void send(text);\n }, [editor, runSlash, send]);\n\n // --- keyboard --------------------------------------------------------------\n\n const recall = (direction: -1 | 1) => {\n const { history } = stateRef.current;\n if (history.length === 0) return;\n const current = historyIndex ?? history.length;\n const next = Math.min(history.length, Math.max(0, current + direction));\n setHistoryIndex(next === history.length ? undefined : next);\n setEditor(next === history.length ? ed.emptyEditor : ed.fromText(history[next]!));\n };\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c') {\n const armed =\n exitArmedAt.current !== undefined && now() - exitArmedAt.current < EXIT_WINDOW_MS;\n if (armed) {\n abortRef.current?.abort();\n exit();\n return;\n }\n exitArmedAt.current = now();\n if (stateRef.current.streaming) abortRef.current?.abort();\n else if (editor.chars.length > 0) setEditor(ed.emptyEditor);\n setNotice('Press Ctrl+C again to exit');\n return;\n }\n exitArmedAt.current = undefined;\n\n if (key.escape) {\n if (stateRef.current.streaming) abortRef.current?.abort();\n return;\n }\n // New line: Ctrl+J (LF), Shift/Alt+Enter where the terminal reports it, or \"\\\" + Enter.\n if ((input === '\\n' && !key.return) || (key.ctrl && input === 'j')) {\n setEditor((e) => ed.insert(e, '\\n'));\n return;\n }\n if (key.return) {\n if (key.shift || key.meta) setEditor((e) => ed.insert(e, '\\n'));\n else if (ed.continuesLine(editor)) setEditor((e) => ed.newlineAfterBackslash(e));\n else submit();\n return;\n }\n if (key.tab) {\n const completed = completeSlash(ed.textOf(editor));\n if (completed) setEditor(ed.fromText(completed));\n return;\n }\n if (key.upArrow) {\n const moved = ed.up(editor);\n if (moved) setEditor(moved);\n else recall(-1);\n return;\n }\n if (key.downArrow) {\n const moved = ed.down(editor);\n if (moved) setEditor(moved);\n else if (historyIndex !== undefined) recall(1);\n return;\n }\n if (key.leftArrow) return setEditor(ed.left);\n if (key.rightArrow) return setEditor(ed.right);\n if (key.home || (key.ctrl && input === 'a')) return setEditor(ed.lineStart);\n if (key.end || (key.ctrl && input === 'e')) return setEditor(ed.lineEnd);\n if (key.backspace) return setEditor(ed.backspace);\n if (key.delete) return setEditor(ed.deleteForward);\n if (key.ctrl && input === 'u') return setEditor(ed.killToLineStart);\n if (key.ctrl && input === 'k') return setEditor(ed.killToLineEnd);\n if (key.ctrl && input === 'w') return setEditor(ed.deleteWordBack);\n if (key.ctrl && input === 'l') {\n write('\\u001b[2J\\u001b[H');\n return;\n }\n if (key.ctrl || key.meta || !input) return;\n setEditor((e) => ed.insert(e, input));\n });\n\n usePaste((text) => {\n setEditor((e) => ed.insert(e, text));\n });\n\n // --- render ----------------------------------------------------------------\n\n const suggestions = slashSuggestions(ed.textOf(editor));\n return (\n <Box flexDirection=\"column\" width={width}>\n <Static key={state.epoch} items={state.entries}>\n {(entry) => <EntryView key={entry.id} entry={entry} />}\n </Static>\n {state.streaming ? <StreamingView streaming={state.streaming} now={clock} /> : null}\n <InputBox editor={editor} width={width} placeholder={PLACEHOLDER} />\n <SlashHints commands={suggestions} width={width} />\n <StatusLine\n state={state}\n width={width}\n info={{\n where: backend.inProcess ? `in-process ${new URL(backend.url).port}` : backend.url,\n inProcess: backend.inProcess,\n ...(notice ? { notice } : {}),\n }}\n />\n </Box>\n );\n}\n\n/** The chat TUI. Render with `render(<ChatApp …/>, { exitOnCtrlC: false })`. */\nexport function ChatApp(props: ChatAppProps) {\n return (\n <ThemeProvider theme={props.theme}>\n <Chat {...props} />\n </ThemeProvider>\n );\n}\n","import type { ChatMessage, ProviderKind, Usage } from '@davecode/core';\n\n/** Pure state machine behind the chat TUI (rendering lives in ChatApp). */\n\nexport type EntryKind = 'banner' | 'user' | 'assistant' | 'info' | 'error';\n\nexport interface EntryMeta {\n accountId?: string;\n accountLabel?: string;\n provider?: string;\n model?: string;\n failovers?: number;\n tokens?: number;\n /** Token count is an estimate (the upstream sent no usage). */\n estimated?: boolean;\n latencyMs?: number;\n cancelled?: boolean;\n}\n\nexport interface Entry {\n id: number;\n kind: EntryKind;\n text: string;\n meta?: EntryMeta;\n}\n\nexport type Connection = 'connecting' | 'online' | 'offline';\n\nexport interface StreamingState {\n id: number;\n text: string;\n startedAt: number;\n model: string;\n accountId?: string;\n provider?: string;\n failovers?: number;\n}\n\nexport interface ChatState {\n /** Finalised transcript entries (rendered once, above the live area). */\n entries: Entry[];\n /** The assistant reply being streamed, if any. */\n streaming?: StreamingState;\n /** Messages sent to the gateway on the next turn. */\n conversation: ChatMessage[];\n model: string;\n connection: Connection;\n /** Account that served the last reply. */\n lastAccount?: { id: string; label?: string; provider?: string };\n /** Failover hops of the last reply and across the session. */\n lastFailovers: number;\n totalFailovers: number;\n tokens: { prompt: number; completion: number };\n /** 5h-window utilization of the last account (undefined when unknown or unlimited). */\n quota5h?: number;\n /** Bumped by /clear so the transcript re-mounts. */\n epoch: number;\n /** Submitted inputs, oldest first, for ↑/↓ recall. */\n history: string[];\n nextId: number;\n}\n\nexport type ChatAction =\n | { type: 'banner'; text: string }\n | { type: 'info'; text: string }\n | { type: 'error'; text: string }\n | { type: 'user'; text: string }\n | { type: 'stream-start'; now: number }\n | {\n type: 'stream-meta';\n accountId?: string;\n provider?: ProviderKind | string;\n failovers?: number;\n accountLabel?: string;\n }\n | { type: 'stream-delta'; text: string }\n | {\n type: 'stream-end';\n now: number;\n usage?: Usage;\n cancelled?: boolean;\n error?: string;\n }\n | { type: 'set-model'; model: string }\n | { type: 'connection'; connection: Connection }\n | { type: 'quota'; accountId: string; utilization: number | undefined }\n | { type: 'clear' };\n\nexport function initialChatState(model: string): ChatState {\n return {\n entries: [],\n conversation: [],\n model,\n connection: 'connecting',\n lastFailovers: 0,\n totalFailovers: 0,\n tokens: { prompt: 0, completion: 0 },\n epoch: 0,\n history: [],\n nextId: 1,\n };\n}\n\n/** chars/4, the same fallback the gateway uses when a provider omits usage. */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nfunction push(state: ChatState, kind: EntryKind, text: string, meta?: EntryMeta): ChatState {\n const entry: Entry = { id: state.nextId, kind, text };\n if (meta) entry.meta = meta;\n return { ...state, entries: [...state.entries, entry], nextId: state.nextId + 1 };\n}\n\nexport function chatReducer(state: ChatState, action: ChatAction): ChatState {\n switch (action.type) {\n case 'banner':\n return push(state, 'banner', action.text);\n case 'info':\n return push(state, 'info', action.text);\n case 'error':\n return push(state, 'error', action.text);\n case 'user': {\n const next = push(state, 'user', action.text);\n const history =\n state.history[state.history.length - 1] === action.text\n ? state.history\n : [...state.history, action.text].slice(-200);\n return {\n ...next,\n history,\n conversation: [...state.conversation, { role: 'user', content: action.text }],\n };\n }\n case 'stream-start':\n return {\n ...state,\n streaming: { id: state.nextId, text: '', startedAt: action.now, model: state.model },\n nextId: state.nextId + 1,\n };\n case 'stream-meta': {\n if (!state.streaming) return state;\n const streaming = { ...state.streaming };\n if (action.accountId) streaming.accountId = action.accountId;\n if (action.provider) streaming.provider = action.provider;\n if (action.failovers !== undefined) streaming.failovers = action.failovers;\n const lastAccount = action.accountId\n ? {\n id: action.accountId,\n ...(action.accountLabel ? { label: action.accountLabel } : {}),\n ...(action.provider ? { provider: action.provider } : {}),\n }\n : state.lastAccount;\n return {\n ...state,\n streaming,\n ...(lastAccount ? { lastAccount } : {}),\n ...(action.failovers !== undefined\n ? {\n lastFailovers: action.failovers,\n totalFailovers: state.totalFailovers + action.failovers,\n }\n : {}),\n };\n }\n case 'stream-delta':\n if (!state.streaming) return state;\n return {\n ...state,\n streaming: { ...state.streaming, text: state.streaming.text + action.text },\n };\n case 'stream-end': {\n const live = state.streaming;\n if (!live) return state;\n const prompt =\n action.usage?.prompt_tokens ??\n estimateTokens(\n state.conversation\n .map((m) => (typeof m.content === 'string' ? m.content : ''))\n .join('\\n'),\n );\n const completion = action.usage?.completion_tokens ?? estimateTokens(live.text);\n const meta: EntryMeta = {\n model: live.model,\n latencyMs: action.now - live.startedAt,\n tokens: prompt + completion,\n ...(action.usage ? {} : { estimated: true }),\n ...(live.accountId ? { accountId: live.accountId } : {}),\n ...(state.lastAccount?.id === live.accountId && state.lastAccount?.label\n ? { accountLabel: state.lastAccount.label }\n : {}),\n ...(live.provider ? { provider: live.provider } : {}),\n ...(live.failovers ? { failovers: live.failovers } : {}),\n ...(action.cancelled ? { cancelled: true } : {}),\n };\n let next: ChatState = { ...state };\n delete next.streaming;\n const answered = live.text.length > 0;\n if (answered || action.cancelled) next = push(next, 'assistant', live.text, meta);\n if (action.error) next = push(next, 'error', action.error);\n // Only complete exchanges stay in the conversation the model sees next time; a cancelled\n // or failed turn drops its question too, so roles keep alternating.\n if (answered && !action.cancelled && !action.error) {\n next.conversation = [...next.conversation, { role: 'assistant', content: live.text }];\n } else if (next.conversation[next.conversation.length - 1]?.role === 'user') {\n next.conversation = next.conversation.slice(0, -1);\n }\n if (answered || action.usage) {\n next.tokens = {\n prompt: state.tokens.prompt + prompt,\n completion: state.tokens.completion + completion,\n };\n }\n return next;\n }\n case 'set-model':\n return { ...state, model: action.model };\n case 'connection':\n return state.connection === action.connection\n ? state\n : { ...state, connection: action.connection };\n case 'quota': {\n if (state.lastAccount?.id !== action.accountId) return state;\n const next = { ...state };\n if (action.utilization === undefined) delete next.quota5h;\n else next.quota5h = action.utilization;\n return next;\n }\n case 'clear': {\n const next: ChatState = {\n ...state,\n entries: [],\n conversation: [],\n epoch: state.epoch + 1,\n };\n delete next.streaming;\n return next;\n }\n default:\n return state;\n }\n}\n","import { Box, Text } from 'ink';\nimport { type EditorState, lines, position } from '../editor';\nimport type { SlashCommand } from '../slash';\nimport { useTheme } from '../theme-context';\n\n/** Split a line around the cursor so the cursor cell can be drawn inverted. */\nexport function cursorParts(\n line: string[],\n column: number | undefined,\n): { before: string; at: string; after: string } {\n if (column === undefined) return { before: line.join(''), at: '', after: '' };\n return {\n before: line.slice(0, column).join(''),\n at: line[column] ?? ' ',\n after: line.slice(column + 1).join(''),\n };\n}\n\nexport function InputBox({\n editor,\n width,\n placeholder,\n disabled,\n}: {\n editor: EditorState;\n width: number;\n placeholder: string;\n disabled?: boolean;\n}) {\n const theme = useTheme();\n const all = lines(editor);\n const cursor = position(editor);\n const empty = editor.chars.length === 0;\n return (\n <Box\n borderStyle={theme.unicode ? 'round' : 'classic'}\n borderDimColor={theme.ink.dim}\n flexDirection=\"column\"\n paddingX={1}\n width={width}\n >\n {all.map((line, i) => {\n const parts = cursorParts(line, !disabled && i === cursor.line ? cursor.column : undefined);\n return (\n // biome-ignore lint/suspicious/noArrayIndexKey: lines have no identity beyond position\n <Box key={i}>\n <Box width={2} flexShrink={0}>\n <Text color={i === 0 ? theme.ink.accent : undefined}>\n {i === 0 ? theme.glyph.prompt : ''}\n </Text>\n </Box>\n {empty && i === 0 ? (\n <Text>\n {disabled ? null : <Text inverse> </Text>}\n <Text dimColor={theme.ink.dim}>{placeholder}</Text>\n </Text>\n ) : (\n <Text>\n {parts.before}\n {parts.at ? <Text inverse>{parts.at}</Text> : null}\n {parts.after}\n </Text>\n )}\n </Box>\n );\n })}\n </Box>\n );\n}\n\nexport function SlashHints({ commands, width }: { commands: SlashCommand[]; width: number }) {\n const theme = useTheme();\n if (commands.length === 0) return null;\n const nameWidth =\n Math.max(...commands.map((c) => c.name.length + (c.args ? c.args.length + 1 : 0))) + 3;\n return (\n <Box flexDirection=\"column\" paddingX={2} width={width}>\n {commands.map((c, i) => (\n <Text key={c.name} wrap=\"truncate-end\">\n <Text color={i === 0 ? theme.ink.accent : undefined}>\n {`/${c.name}${c.args ? ` ${c.args}` : ''}`.padEnd(nameWidth)}\n </Text>\n <Text dimColor={theme.ink.dim}>{c.description}</Text>\n </Text>\n ))}\n </Box>\n );\n}\n","/**\n * Pure multiline text-editing model for the chat input. Positions are indexes into the array\n * of code points so emoji and other astral characters move as one unit.\n */\n\nexport interface EditorState {\n /** Code points of the buffer. */\n chars: string[];\n /** Cursor position, 0..chars.length. */\n cursor: number;\n}\n\nexport const emptyEditor: EditorState = { chars: [], cursor: 0 };\n\nexport function fromText(text: string): EditorState {\n const chars = [...text];\n return { chars, cursor: chars.length };\n}\n\nexport function textOf(state: EditorState): string {\n return state.chars.join('');\n}\n\n/** Normalise pasted or typed text: CRLF/CR → LF, tabs → two spaces, other controls dropped. */\nexport function normalizeInput(text: string): string {\n return (\n text\n .replace(/\\r\\n?/g, '\\n')\n .replace(/\\t/g, ' ')\n // biome-ignore lint/suspicious/noControlCharactersInRegex: dropping control characters\n .replace(/[\\u0000-\\u0009\\u000b-\\u001f\\u007f]/g, '')\n );\n}\n\nexport function insert(state: EditorState, text: string): EditorState {\n const add = [...normalizeInput(text)];\n if (add.length === 0) return state;\n const chars = [...state.chars.slice(0, state.cursor), ...add, ...state.chars.slice(state.cursor)];\n return { chars, cursor: state.cursor + add.length };\n}\n\nexport function backspace(state: EditorState): EditorState {\n if (state.cursor === 0) return state;\n const chars = [...state.chars.slice(0, state.cursor - 1), ...state.chars.slice(state.cursor)];\n return { chars, cursor: state.cursor - 1 };\n}\n\nexport function deleteForward(state: EditorState): EditorState {\n if (state.cursor >= state.chars.length) return state;\n const chars = [...state.chars.slice(0, state.cursor), ...state.chars.slice(state.cursor + 1)];\n return { chars, cursor: state.cursor };\n}\n\nexport function left(state: EditorState): EditorState {\n return { ...state, cursor: Math.max(0, state.cursor - 1) };\n}\n\nexport function right(state: EditorState): EditorState {\n return { ...state, cursor: Math.min(state.chars.length, state.cursor + 1) };\n}\n\n/** Line and column of the cursor. */\nexport function position(state: EditorState): { line: number; column: number } {\n let line = 0;\n let column = 0;\n for (let i = 0; i < state.cursor; i++) {\n if (state.chars[i] === '\\n') {\n line++;\n column = 0;\n } else {\n column++;\n }\n }\n return { line, column };\n}\n\nexport function lines(state: EditorState): string[][] {\n const out: string[][] = [[]];\n for (const ch of state.chars) {\n if (ch === '\\n') out.push([]);\n else out[out.length - 1]!.push(ch);\n }\n return out;\n}\n\nfunction offsetOf(all: string[][], line: number, column: number): number {\n let offset = 0;\n for (let i = 0; i < line; i++) offset += all[i]!.length + 1;\n return offset + Math.min(column, all[line]!.length);\n}\n\nexport function lineCount(state: EditorState): number {\n return lines(state).length;\n}\n\n/** Move up one line, keeping the column. Returns `undefined` on the first line. */\nexport function up(state: EditorState): EditorState | undefined {\n const { line, column } = position(state);\n if (line === 0) return undefined;\n return { ...state, cursor: offsetOf(lines(state), line - 1, column) };\n}\n\n/** Move down one line, keeping the column. Returns `undefined` on the last line. */\nexport function down(state: EditorState): EditorState | undefined {\n const all = lines(state);\n const { line, column } = position(state);\n if (line >= all.length - 1) return undefined;\n return { ...state, cursor: offsetOf(all, line + 1, column) };\n}\n\nexport function lineStart(state: EditorState): EditorState {\n const { line } = position(state);\n return { ...state, cursor: offsetOf(lines(state), line, 0) };\n}\n\nexport function lineEnd(state: EditorState): EditorState {\n const all = lines(state);\n const { line } = position(state);\n return { ...state, cursor: offsetOf(all, line, all[line]!.length) };\n}\n\n/** Ctrl+U: delete from the start of the line to the cursor. */\nexport function killToLineStart(state: EditorState): EditorState {\n const start = lineStart(state).cursor;\n if (start === state.cursor) return state;\n return {\n chars: [...state.chars.slice(0, start), ...state.chars.slice(state.cursor)],\n cursor: start,\n };\n}\n\n/** Ctrl+K: delete from the cursor to the end of the line. */\nexport function killToLineEnd(state: EditorState): EditorState {\n const end = lineEnd(state).cursor;\n return {\n chars: [...state.chars.slice(0, state.cursor), ...state.chars.slice(end)],\n cursor: state.cursor,\n };\n}\n\n/** Ctrl+W: delete the word before the cursor (and the spaces after it). */\nexport function deleteWordBack(state: EditorState): EditorState {\n let i = state.cursor;\n while (i > 0 && /[ \\t]/.test(state.chars[i - 1]!)) i--;\n while (i > 0 && !/[\\s]/.test(state.chars[i - 1]!)) i--;\n if (i === state.cursor) return backspace(state);\n return { chars: [...state.chars.slice(0, i), ...state.chars.slice(state.cursor)], cursor: i };\n}\n\n/**\n * Enter at the end of a line that ends with a backslash continues on a new line instead of\n * submitting (the Claude Code convention for terminals that cannot send Shift+Enter).\n */\nexport function continuesLine(state: EditorState): boolean {\n return state.cursor > 0 && state.chars[state.cursor - 1] === '\\\\';\n}\n\nexport function newlineAfterBackslash(state: EditorState): EditorState {\n return insert(backspace(state), '\\n');\n}\n","import { Box, Text } from 'ink';\nimport { bar, formatTokens, levelStyle, percent, visibleWidth } from '../../ui/format';\nimport type { Theme } from '../../ui/theme';\nimport type { ChatState } from '../chat-state';\nimport { useTheme } from '../theme-context';\n\nexport interface StatusInfo {\n /** `in-process :54012` or the gateway URL. */\n where: string;\n inProcess: boolean;\n /** Transient message (e.g. \"Press Ctrl+C again to exit\"). */\n notice?: string;\n}\n\n/**\n * Left: model · account · failovers · tokens · 5h quota. Right: connection.\n * Segments are dropped from the end of the left side until the line fits.\n */\nexport function statusSegments(\n theme: Theme,\n state: ChatState,\n info: StatusInfo,\n width: number,\n): { left: string; right: string } {\n const sep = theme.dim(' · ');\n const left: string[] = [theme.accent(state.model)];\n if (state.lastAccount) {\n const name = state.lastAccount.label ?? state.lastAccount.id;\n left.push(\n `${name}${state.lastAccount.provider ? theme.dim(` (${state.lastAccount.provider})`) : ''}`,\n );\n }\n const failovers =\n state.totalFailovers > 0\n ? theme.warn(`${state.lastFailovers}/${state.totalFailovers} failovers`)\n : theme.dim('0 failovers');\n left.push(failovers);\n const arrows = theme.unicode ? ['↑', '↓'] : ['in', 'out'];\n left.push(\n theme.dim(\n `${formatTokens(state.tokens.prompt)}${arrows[0]} ${formatTokens(state.tokens.completion)}${arrows[1]}`,\n ),\n );\n if (state.quota5h !== undefined) {\n left.push(\n `${theme.dim('5h')} ${bar(theme, state.quota5h, 6)} ${levelStyle(theme, state.quota5h)(percent(state.quota5h))}`,\n );\n }\n\n const dot = theme.glyph.dot;\n let right: string;\n if (info.notice) right = theme.warn(info.notice);\n else if (state.connection === 'online') {\n right = `${theme.ok(dot)} ${theme.dim(info.inProcess ? `${info.where}` : 'connected')}`;\n } else if (state.connection === 'connecting') right = theme.dim(`${dot} connecting`);\n else right = theme.error(`${dot} offline`);\n\n // Drop segments (least important last) until everything fits on one line.\n const priorities = [0, 1, 2, 4, 3];\n let kept = left.map((_, i) => i);\n const render = () => kept.map((i) => left[i]).join(sep);\n while (kept.length > 1 && visibleWidth(render()) + visibleWidth(right) + 2 > width) {\n const drop = [...priorities].reverse().find((p) => kept.includes(p) && p !== 0);\n if (drop === undefined) break;\n kept = kept.filter((i) => i !== drop);\n }\n return { left: render(), right };\n}\n\nexport function StatusLine({\n state,\n info,\n width,\n}: {\n state: ChatState;\n info: StatusInfo;\n width: number;\n}) {\n const theme = useTheme();\n const { left, right } = statusSegments(theme, state, info, width - 2);\n return (\n <Box width={width} justifyContent=\"space-between\" paddingX={1}>\n <Text wrap=\"truncate-end\">{left}</Text>\n <Text wrap=\"truncate-start\">{right}</Text>\n </Box>\n );\n}\n","import { Box, Text } from 'ink';\nimport { formatTokens } from '../../ui/format';\nimport type { Entry, EntryMeta, StreamingState } from '../chat-state';\nimport { useTheme } from '../theme-context';\nimport { Spinner } from './Spinner';\n\n/** `claude-cli · work · 1.2k tok · 830ms · 1 failover` under an assistant reply. */\nexport function metaLine(meta: EntryMeta): string {\n const parts: string[] = [];\n if (meta.accountLabel ?? meta.accountId) {\n parts.push([meta.provider, meta.accountLabel ?? meta.accountId].filter(Boolean).join(' · '));\n }\n if (meta.model) parts.push(meta.model);\n if (meta.tokens !== undefined)\n parts.push(`${meta.estimated ? '~' : ''}${formatTokens(meta.tokens)} tok`);\n if (meta.latencyMs !== undefined) parts.push(`${(meta.latencyMs / 1000).toFixed(1)}s`);\n if (meta.failovers) parts.push(`${meta.failovers} failover${meta.failovers === 1 ? '' : 's'}`);\n if (meta.cancelled) parts.push('cancelled');\n return parts.join(' · ');\n}\n\nfunction Marker({ color, glyph }: { color: string | undefined; glyph: string }) {\n return (\n <Box width={2} flexShrink={0}>\n <Text color={color}>{glyph}</Text>\n </Box>\n );\n}\n\nexport function EntryView({ entry }: { entry: Entry }) {\n const theme = useTheme();\n switch (entry.kind) {\n case 'banner':\n return (\n <Box marginBottom={1}>\n <Text>{entry.text}</Text>\n </Box>\n );\n case 'user':\n return (\n <Box marginBottom={1}>\n <Marker color={theme.ink.accent} glyph={theme.glyph.prompt} />\n <Text dimColor={theme.ink.dim}>{entry.text}</Text>\n </Box>\n );\n case 'assistant':\n return (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Marker color={theme.ink.accent} glyph={theme.glyph.dot} />\n <Text>\n {entry.text || (entry.meta?.cancelled ? '(cancelled before any output)' : '')}\n </Text>\n </Box>\n {entry.meta ? (\n <Box paddingLeft={2}>\n <Text dimColor={theme.ink.dim}>{metaLine(entry.meta)}</Text>\n </Box>\n ) : null}\n </Box>\n );\n case 'error':\n return (\n <Box marginBottom={1}>\n <Marker color={theme.ink.error} glyph={theme.glyph.fail} />\n <Text color={theme.ink.error}>{entry.text}</Text>\n </Box>\n );\n default:\n return (\n <Box marginBottom={1} paddingLeft={2}>\n <Text>{entry.text}</Text>\n </Box>\n );\n }\n}\n\n/** The reply being streamed: spinner until the first token, then the growing text. */\nexport function StreamingView({ streaming, now }: { streaming: StreamingState; now: number }) {\n const theme = useTheme();\n const seconds = Math.max(0, (now - streaming.startedAt) / 1000).toFixed(0);\n return (\n <Box flexDirection=\"column\" marginBottom={1}>\n {streaming.text ? (\n <Box>\n <Marker color={theme.ink.accent} glyph={theme.glyph.dot} />\n <Text>{streaming.text}</Text>\n </Box>\n ) : null}\n <Box paddingLeft={streaming.text ? 2 : 0}>\n <Spinner />\n <Text dimColor={theme.ink.dim}>\n {' '}\n {streaming.text ? 'streaming' : 'thinking'} {seconds}s · esc to cancel\n </Text>\n </Box>\n </Box>\n );\n}\n","/** Slash commands understood by the chat TUI. */\n\nexport type SlashName =\n | 'help'\n | 'model'\n | 'route'\n | 'accounts'\n | 'tasks'\n | 'status'\n | 'clear'\n | 'exit';\n\nexport interface SlashCommand {\n name: SlashName;\n args?: string;\n description: string;\n aliases?: string[];\n}\n\nexport const SLASH_COMMANDS: readonly SlashCommand[] = [\n { name: 'model', args: '[id]', description: 'show models or switch, e.g. /model davecode/auto' },\n { name: 'route', description: 'routes and their failover targets' },\n { name: 'accounts', description: 'accounts with 5h quota usage' },\n { name: 'tasks', description: 'the project task graph' },\n { name: 'status', description: 'gateway health and runner state' },\n { name: 'clear', description: 'clear the transcript and start a new conversation' },\n { name: 'help', description: 'commands and keyboard shortcuts', aliases: ['?'] },\n { name: 'exit', description: 'quit DaveCode', aliases: ['quit', 'q'] },\n];\n\nexport type SlashParse =\n | { kind: 'command'; command: SlashCommand; args: string }\n | { kind: 'unknown'; name: string }\n | { kind: 'none' };\n\n/** `/model gpt-5` → the model command with args `gpt-5`. Text without a leading `/` is a prompt. */\nexport function parseSlash(input: string): SlashParse {\n const text = input.trim();\n if (!text.startsWith('/') || text.startsWith('//')) return { kind: 'none' };\n const [head = '', ...rest] = text.slice(1).split(/\\s+/);\n const name = head.toLowerCase();\n if (!name) return { kind: 'unknown', name: '' };\n const command = SLASH_COMMANDS.find((c) => c.name === name || c.aliases?.includes(name));\n if (!command) return { kind: 'unknown', name };\n return { kind: 'command', command, args: rest.join(' ').trim() };\n}\n\n/** Commands matching what has been typed so far (only while typing the command name). */\nexport function slashSuggestions(input: string): SlashCommand[] {\n if (!input.startsWith('/') || /\\s/.test(input)) return [];\n const prefix = input.slice(1).toLowerCase();\n return SLASH_COMMANDS.filter(\n (c) => c.name.startsWith(prefix) || c.aliases?.some((a) => a.startsWith(prefix) && prefix),\n );\n}\n\n/** Tab completion: the unique (or first) match, with a trailing space when it takes args. */\nexport function completeSlash(input: string): string | undefined {\n const [first] = slashSuggestions(input);\n if (!first) return undefined;\n return `/${first.name}${first.args ? ' ' : ''}`;\n}\n\nexport const KEY_HINTS: ReadonlyArray<[string, string]> = [\n ['Enter', 'send'],\n ['Shift+Enter, Ctrl+J or \\\\ Enter', 'new line'],\n ['↑ / ↓', 'move between lines, then through history'],\n ['Tab', 'complete a slash command'],\n ['Esc', 'cancel the response in flight'],\n ['Ctrl+U / Ctrl+K / Ctrl+W', 'delete to line start / line end / previous word'],\n ['Ctrl+C twice', 'exit'],\n];\n","import { emptyUsage, renderAccounts } from '../commands/status';\nimport { formatTaskTree, summaryLine } from '../lib/task-tree';\nimport { formatDuration, padEnd } from '../ui/format';\nimport type { Theme } from '../ui/theme';\nimport type { ChatBackend } from './backend';\nimport { KEY_HINTS, SLASH_COMMANDS } from './slash';\n\n/** Text produced by the informational slash commands (ANSI-styled, rendered as-is by Ink). */\n\nexport function helpText(theme: Theme): string {\n const width = Math.max(...SLASH_COMMANDS.map((c) => c.name.length + (c.args?.length ?? 0))) + 4;\n const commands = SLASH_COMMANDS.map(\n (c) =>\n `${theme.accent(padEnd(`/${c.name}${c.args ? ` ${c.args}` : ''}`, width))}${theme.dim(c.description)}`,\n );\n const keyWidth = Math.max(...KEY_HINTS.map(([k]) => k.length)) + 2;\n const keys = KEY_HINTS.map(([k, v]) => `${padEnd(k, keyWidth)}${theme.dim(v)}`);\n return [theme.bold('Commands'), ...commands, '', theme.bold('Keys'), ...keys].join('\\n');\n}\n\nexport async function modelsText(theme: Theme, backend: ChatBackend, current: string) {\n const models = await backend.models();\n const ids = models\n .map((m) => m.id)\n .sort((a, b) => {\n const da = a.startsWith('davecode/') ? 0 : 1;\n const db = b.startsWith('davecode/') ? 0 : 1;\n return da - db || a.localeCompare(b);\n });\n if (ids.length === 0)\n return theme.dim('No models yet. Add an account with `davecode accounts add`.');\n const shown = ids.slice(0, 40);\n const lines = shown.map((id) =>\n id === current ? `${theme.accent(theme.glyph.dot)} ${theme.accent(id)}` : ` ${id}`,\n );\n if (ids.length > shown.length) lines.push(theme.dim(` … and ${ids.length - shown.length} more`));\n lines.push('', theme.dim('Switch with /model <id>'));\n return lines.join('\\n');\n}\n\nexport async function routesText(theme: Theme, backend: ChatBackend) {\n const { defaultRoute, routes } = await backend.routes();\n if (routes.length === 0) {\n return [\n `${theme.dim('No routes configured.')} davecode/${defaultRoute} uses every account with a default model.`,\n theme.dim('Define routes under routing.routes in ~/.davecode/config.json.'),\n ].join('\\n');\n }\n const lines: string[] = [];\n for (const route of routes) {\n const mark = route.name === defaultRoute ? theme.dim(' (default)') : '';\n lines.push(\n `${theme.accent(`davecode/${route.name}`)}${mark}${route.description ? theme.dim(` ${route.description}`) : ''}`,\n );\n route.targets.forEach((t, i) => {\n lines.push(\n ` ${theme.dim(`${i + 1}.`)} ${t.provider}/${t.model}${t.accountId ? theme.dim(` @${t.accountId}`) : ''}`,\n );\n });\n }\n return lines.join('\\n');\n}\n\nexport async function accountsText(theme: Theme, backend: ChatBackend, columns: number) {\n const [accounts, usage] = await Promise.all([backend.accounts(), backend.usage()]);\n if (accounts.length === 0)\n return theme.dim('No accounts yet. Add one with `davecode accounts add`.');\n const byId = new Map(usage.map((u) => [u.accountId, u]));\n return renderAccounts(\n theme,\n accounts.map((account) => ({ account, usage: byId.get(account.id) ?? emptyUsage(account.id) })),\n columns,\n ).join('\\n');\n}\n\nexport async function tasksText(theme: Theme, backend: ChatBackend, columns: number) {\n const { project, graph } = await backend.tasks();\n if (!project)\n return theme.dim('No project brain is being served. Start DaveCode inside a repository.');\n if (graph.tasks.length === 0) {\n return theme.dim(`${project.name}: no tasks yet. Add one with \\`davecode tasks add\\`.`);\n }\n return [\n `${theme.bold(project.name)} ${summaryLine(theme, graph)}`,\n '',\n ...formatTaskTree(theme, graph, { width: columns }),\n ].join('\\n');\n}\n\nexport async function statusText(theme: Theme, backend: ChatBackend) {\n const health = await backend.health();\n if (!health) return theme.error(`Gateway at ${backend.url} is not answering.`);\n const runner = await backend.runner().catch(() => undefined);\n const flags = Object.entries(health.experimental)\n .filter(([, on]) => on)\n .map(([k]) => k);\n return [\n `${theme.ok(theme.glyph.dot)} ${backend.url}${backend.inProcess ? theme.dim(' (in-process)') : ''} ${theme.dim(`v${health.version} · up ${formatDuration(health.uptimeSec)}`)}`,\n `${theme.dim('runner')} ${runner ? runner.state : 'unknown'}${runner?.taskId ? theme.dim(` · ${runner.taskId}`) : ''}`,\n `${theme.dim('experimental')} ${flags.length > 0 ? theme.warn(flags.join(', ')) : 'none'}`,\n ].join('\\n');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,SAAS,OAAAA,MAAK,QAAQ,QAAQ,UAAU,UAAU,WAAW,qBAAqB;AAClF,SAAS,aAAa,WAAW,YAAY,QAAQ,gBAAgB;;;ACsF9D,SAAS,iBAAiB,OAA0B;AACzD,SAAO;AAAA,IACL,SAAS,CAAC;AAAA,IACV,cAAc,CAAC;AAAA,IACf;AAAA,IACA,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,QAAQ,EAAE,QAAQ,GAAG,YAAY,EAAE;AAAA,IACnC,OAAO;AAAA,IACP,SAAS,CAAC;AAAA,IACV,QAAQ;AAAA,EACV;AACF;AAGO,SAAS,eAAe,MAAsB;AACnD,SAAO,KAAK,KAAK,KAAK,SAAS,CAAC;AAClC;AAEA,SAAS,KAAK,OAAkB,MAAiB,MAAc,MAA6B;AAC1F,QAAM,QAAe,EAAE,IAAI,MAAM,QAAQ,MAAM,KAAK;AACpD,MAAI,KAAM,OAAM,OAAO;AACvB,SAAO,EAAE,GAAG,OAAO,SAAS,CAAC,GAAG,MAAM,SAAS,KAAK,GAAG,QAAQ,MAAM,SAAS,EAAE;AAClF;AAEO,SAAS,YAAY,OAAkB,QAA+B;AAC3E,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO,KAAK,OAAO,UAAU,OAAO,IAAI;AAAA,IAC1C,KAAK;AACH,aAAO,KAAK,OAAO,QAAQ,OAAO,IAAI;AAAA,IACxC,KAAK;AACH,aAAO,KAAK,OAAO,SAAS,OAAO,IAAI;AAAA,IACzC,KAAK,QAAQ;AACX,YAAM,OAAO,KAAK,OAAO,QAAQ,OAAO,IAAI;AAC5C,YAAM,UACJ,MAAM,QAAQ,MAAM,QAAQ,SAAS,CAAC,MAAM,OAAO,OAC/C,MAAM,UACN,CAAC,GAAG,MAAM,SAAS,OAAO,IAAI,EAAE,MAAM,IAAI;AAChD,aAAO;AAAA,QACL,GAAG;AAAA,QACH;AAAA,QACA,cAAc,CAAC,GAAG,MAAM,cAAc,EAAE,MAAM,QAAQ,SAAS,OAAO,KAAK,CAAC;AAAA,MAC9E;AAAA,IACF;AAAA,IACA,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW,EAAE,IAAI,MAAM,QAAQ,MAAM,IAAI,WAAW,OAAO,KAAK,OAAO,MAAM,MAAM;AAAA,QACnF,QAAQ,MAAM,SAAS;AAAA,MACzB;AAAA,IACF,KAAK,eAAe;AAClB,UAAI,CAAC,MAAM,UAAW,QAAO;AAC7B,YAAM,YAAY,EAAE,GAAG,MAAM,UAAU;AACvC,UAAI,OAAO,UAAW,WAAU,YAAY,OAAO;AACnD,UAAI,OAAO,SAAU,WAAU,WAAW,OAAO;AACjD,UAAI,OAAO,cAAc,OAAW,WAAU,YAAY,OAAO;AACjE,YAAM,cAAc,OAAO,YACvB;AAAA,QACE,IAAI,OAAO;AAAA,QACX,GAAI,OAAO,eAAe,EAAE,OAAO,OAAO,aAAa,IAAI,CAAC;AAAA,QAC5D,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,MACzD,IACA,MAAM;AACV,aAAO;AAAA,QACL,GAAG;AAAA,QACH;AAAA,QACA,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,QACrC,GAAI,OAAO,cAAc,SACrB;AAAA,UACE,eAAe,OAAO;AAAA,UACtB,gBAAgB,MAAM,iBAAiB,OAAO;AAAA,QAChD,IACA,CAAC;AAAA,MACP;AAAA,IACF;AAAA,IACA,KAAK;AACH,UAAI,CAAC,MAAM,UAAW,QAAO;AAC7B,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW,EAAE,GAAG,MAAM,WAAW,MAAM,MAAM,UAAU,OAAO,OAAO,KAAK;AAAA,MAC5E;AAAA,IACF,KAAK,cAAc;AACjB,YAAM,OAAO,MAAM;AACnB,UAAI,CAAC,KAAM,QAAO;AAClB,YAAM,SACJ,OAAO,OAAO,iBACd;AAAA,QACE,MAAM,aACH,IAAI,CAAC,MAAO,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU,EAAG,EAC3D,KAAK,IAAI;AAAA,MACd;AACF,YAAM,aAAa,OAAO,OAAO,qBAAqB,eAAe,KAAK,IAAI;AAC9E,YAAM,OAAkB;AAAA,QACtB,OAAO,KAAK;AAAA,QACZ,WAAW,OAAO,MAAM,KAAK;AAAA,QAC7B,QAAQ,SAAS;AAAA,QACjB,GAAI,OAAO,QAAQ,CAAC,IAAI,EAAE,WAAW,KAAK;AAAA,QAC1C,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,QACtD,GAAI,MAAM,aAAa,OAAO,KAAK,aAAa,MAAM,aAAa,QAC/D,EAAE,cAAc,MAAM,YAAY,MAAM,IACxC,CAAC;AAAA,QACL,GAAI,KAAK,WAAW,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,QACnD,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,QACtD,GAAI,OAAO,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,MAChD;AACA,UAAI,OAAkB,EAAE,GAAG,MAAM;AACjC,aAAO,KAAK;AACZ,YAAM,WAAW,KAAK,KAAK,SAAS;AACpC,UAAI,YAAY,OAAO,UAAW,QAAO,KAAK,MAAM,aAAa,KAAK,MAAM,IAAI;AAChF,UAAI,OAAO,MAAO,QAAO,KAAK,MAAM,SAAS,OAAO,KAAK;AAGzD,UAAI,YAAY,CAAC,OAAO,aAAa,CAAC,OAAO,OAAO;AAClD,aAAK,eAAe,CAAC,GAAG,KAAK,cAAc,EAAE,MAAM,aAAa,SAAS,KAAK,KAAK,CAAC;AAAA,MACtF,WAAW,KAAK,aAAa,KAAK,aAAa,SAAS,CAAC,GAAG,SAAS,QAAQ;AAC3E,aAAK,eAAe,KAAK,aAAa,MAAM,GAAG,EAAE;AAAA,MACnD;AACA,UAAI,YAAY,OAAO,OAAO;AAC5B,aAAK,SAAS;AAAA,UACZ,QAAQ,MAAM,OAAO,SAAS;AAAA,UAC9B,YAAY,MAAM,OAAO,aAAa;AAAA,QACxC;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,OAAO,OAAO,MAAM;AAAA,IACzC,KAAK;AACH,aAAO,MAAM,eAAe,OAAO,aAC/B,QACA,EAAE,GAAG,OAAO,YAAY,OAAO,WAAW;AAAA,IAChD,KAAK,SAAS;AACZ,UAAI,MAAM,aAAa,OAAO,OAAO,UAAW,QAAO;AACvD,YAAM,OAAO,EAAE,GAAG,MAAM;AACxB,UAAI,OAAO,gBAAgB,OAAW,QAAO,KAAK;AAAA,UAC7C,MAAK,UAAU,OAAO;AAC3B,aAAO;AAAA,IACT;AAAA,IACA,KAAK,SAAS;AACZ,YAAM,OAAkB;AAAA,QACtB,GAAG;AAAA,QACH,SAAS,CAAC;AAAA,QACV,cAAc,CAAC;AAAA,QACf,OAAO,MAAM,QAAQ;AAAA,MACvB;AACA,aAAO,KAAK;AACZ,aAAO;AAAA,IACT;AAAA,IACA;AACE,aAAO;AAAA,EACX;AACF;;;ACjPA,SAAS,KAAK,YAAY;;;ACYnB,IAAM,cAA2B,EAAE,OAAO,CAAC,GAAG,QAAQ,EAAE;AAExD,SAAS,SAAS,MAA2B;AAClD,QAAM,QAAQ,CAAC,GAAG,IAAI;AACtB,SAAO,EAAE,OAAO,QAAQ,MAAM,OAAO;AACvC;AAEO,SAAS,OAAO,OAA4B;AACjD,SAAO,MAAM,MAAM,KAAK,EAAE;AAC5B;AAGO,SAAS,eAAe,MAAsB;AACnD,SACE,KACG,QAAQ,UAAU,IAAI,EACtB,QAAQ,OAAO,IAAI,EAEnB,QAAQ,uCAAuC,EAAE;AAExD;AAEO,SAAS,OAAO,OAAoB,MAA2B;AACpE,QAAM,MAAM,CAAC,GAAG,eAAe,IAAI,CAAC;AACpC,MAAI,IAAI,WAAW,EAAG,QAAO;AAC7B,QAAM,QAAQ,CAAC,GAAG,MAAM,MAAM,MAAM,GAAG,MAAM,MAAM,GAAG,GAAG,KAAK,GAAG,MAAM,MAAM,MAAM,MAAM,MAAM,CAAC;AAChG,SAAO,EAAE,OAAO,QAAQ,MAAM,SAAS,IAAI,OAAO;AACpD;AAEO,SAAS,UAAU,OAAiC;AACzD,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,QAAQ,CAAC,GAAG,MAAM,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,GAAG,MAAM,MAAM,MAAM,MAAM,MAAM,CAAC;AAC5F,SAAO,EAAE,OAAO,QAAQ,MAAM,SAAS,EAAE;AAC3C;AAEO,SAAS,cAAc,OAAiC;AAC7D,MAAI,MAAM,UAAU,MAAM,MAAM,OAAQ,QAAO;AAC/C,QAAM,QAAQ,CAAC,GAAG,MAAM,MAAM,MAAM,GAAG,MAAM,MAAM,GAAG,GAAG,MAAM,MAAM,MAAM,MAAM,SAAS,CAAC,CAAC;AAC5F,SAAO,EAAE,OAAO,QAAQ,MAAM,OAAO;AACvC;AAEO,SAAS,KAAK,OAAiC;AACpD,SAAO,EAAE,GAAG,OAAO,QAAQ,KAAK,IAAI,GAAG,MAAM,SAAS,CAAC,EAAE;AAC3D;AAEO,SAAS,MAAM,OAAiC;AACrD,SAAO,EAAE,GAAG,OAAO,QAAQ,KAAK,IAAI,MAAM,MAAM,QAAQ,MAAM,SAAS,CAAC,EAAE;AAC5E;AAGO,SAAS,SAAS,OAAsD;AAC7E,MAAI,OAAO;AACX,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,QAAI,MAAM,MAAM,CAAC,MAAM,MAAM;AAC3B;AACA,eAAS;AAAA,IACX,OAAO;AACL;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,MAAM,OAAO;AACxB;AAEO,SAAS,MAAM,OAAgC;AACpD,QAAM,MAAkB,CAAC,CAAC,CAAC;AAC3B,aAAW,MAAM,MAAM,OAAO;AAC5B,QAAI,OAAO,KAAM,KAAI,KAAK,CAAC,CAAC;AAAA,QACvB,KAAI,IAAI,SAAS,CAAC,EAAG,KAAK,EAAE;AAAA,EACnC;AACA,SAAO;AACT;AAEA,SAAS,SAAS,KAAiB,MAAc,QAAwB;AACvE,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,MAAM,IAAK,WAAU,IAAI,CAAC,EAAG,SAAS;AAC1D,SAAO,SAAS,KAAK,IAAI,QAAQ,IAAI,IAAI,EAAG,MAAM;AACpD;AAOO,SAAS,GAAG,OAA6C;AAC9D,QAAM,EAAE,MAAM,OAAO,IAAI,SAAS,KAAK;AACvC,MAAI,SAAS,EAAG,QAAO;AACvB,SAAO,EAAE,GAAG,OAAO,QAAQ,SAAS,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,EAAE;AACtE;AAGO,SAAS,KAAK,OAA6C;AAChE,QAAM,MAAM,MAAM,KAAK;AACvB,QAAM,EAAE,MAAM,OAAO,IAAI,SAAS,KAAK;AACvC,MAAI,QAAQ,IAAI,SAAS,EAAG,QAAO;AACnC,SAAO,EAAE,GAAG,OAAO,QAAQ,SAAS,KAAK,OAAO,GAAG,MAAM,EAAE;AAC7D;AAEO,SAAS,UAAU,OAAiC;AACzD,QAAM,EAAE,KAAK,IAAI,SAAS,KAAK;AAC/B,SAAO,EAAE,GAAG,OAAO,QAAQ,SAAS,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE;AAC7D;AAEO,SAAS,QAAQ,OAAiC;AACvD,QAAM,MAAM,MAAM,KAAK;AACvB,QAAM,EAAE,KAAK,IAAI,SAAS,KAAK;AAC/B,SAAO,EAAE,GAAG,OAAO,QAAQ,SAAS,KAAK,MAAM,IAAI,IAAI,EAAG,MAAM,EAAE;AACpE;AAGO,SAAS,gBAAgB,OAAiC;AAC/D,QAAM,QAAQ,UAAU,KAAK,EAAE;AAC/B,MAAI,UAAU,MAAM,OAAQ,QAAO;AACnC,SAAO;AAAA,IACL,OAAO,CAAC,GAAG,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,GAAG,MAAM,MAAM,MAAM,MAAM,MAAM,CAAC;AAAA,IAC1E,QAAQ;AAAA,EACV;AACF;AAGO,SAAS,cAAc,OAAiC;AAC7D,QAAM,MAAM,QAAQ,KAAK,EAAE;AAC3B,SAAO;AAAA,IACL,OAAO,CAAC,GAAG,MAAM,MAAM,MAAM,GAAG,MAAM,MAAM,GAAG,GAAG,MAAM,MAAM,MAAM,GAAG,CAAC;AAAA,IACxE,QAAQ,MAAM;AAAA,EAChB;AACF;AAGO,SAAS,eAAe,OAAiC;AAC9D,MAAI,IAAI,MAAM;AACd,SAAO,IAAI,KAAK,QAAQ,KAAK,MAAM,MAAM,IAAI,CAAC,CAAE,EAAG;AACnD,SAAO,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,MAAM,IAAI,CAAC,CAAE,EAAG;AACnD,MAAI,MAAM,MAAM,OAAQ,QAAO,UAAU,KAAK;AAC9C,SAAO,EAAE,OAAO,CAAC,GAAG,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,MAAM,MAAM,MAAM,MAAM,MAAM,CAAC,GAAG,QAAQ,EAAE;AAC9F;AAMO,SAAS,cAAc,OAA6B;AACzD,SAAO,MAAM,SAAS,KAAK,MAAM,MAAM,MAAM,SAAS,CAAC,MAAM;AAC/D;AAEO,SAAS,sBAAsB,OAAiC;AACrE,SAAO,OAAO,UAAU,KAAK,GAAG,IAAI;AACtC;;;ADhHc,cAKA,YALA;AAzCP,SAAS,YACd,MACA,QAC+C;AAC/C,MAAI,WAAW,OAAW,QAAO,EAAE,QAAQ,KAAK,KAAK,EAAE,GAAG,IAAI,IAAI,OAAO,GAAG;AAC5E,SAAO;AAAA,IACL,QAAQ,KAAK,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE;AAAA,IACrC,IAAI,KAAK,MAAM,KAAK;AAAA,IACpB,OAAO,KAAK,MAAM,SAAS,CAAC,EAAE,KAAK,EAAE;AAAA,EACvC;AACF;AAEO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,SAAS;AACvB,QAAM,MAAM,MAAM,MAAM;AACxB,QAAM,SAAS,SAAS,MAAM;AAC9B,QAAM,QAAQ,OAAO,MAAM,WAAW;AACtC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAa,MAAM,UAAU,UAAU;AAAA,MACvC,gBAAgB,MAAM,IAAI;AAAA,MAC1B,eAAc;AAAA,MACd,UAAU;AAAA,MACV;AAAA,MAEC,cAAI,IAAI,CAAC,MAAM,MAAM;AACpB,cAAM,QAAQ,YAAY,MAAM,CAAC,YAAY,MAAM,OAAO,OAAO,OAAO,SAAS,MAAS;AAC1F;AAAA;AAAA,UAEE,qBAAC,OACC;AAAA,gCAAC,OAAI,OAAO,GAAG,YAAY,GACzB,8BAAC,QAAK,OAAO,MAAM,IAAI,MAAM,IAAI,SAAS,QACvC,gBAAM,IAAI,MAAM,MAAM,SAAS,IAClC,GACF;AAAA,YACC,SAAS,MAAM,IACd,qBAAC,QACE;AAAA,yBAAW,OAAO,oBAAC,QAAK,SAAO,MAAC,eAAC;AAAA,cAClC,oBAAC,QAAK,UAAU,MAAM,IAAI,KAAM,uBAAY;AAAA,eAC9C,IAEA,qBAAC,QACE;AAAA,oBAAM;AAAA,cACN,MAAM,KAAK,oBAAC,QAAK,SAAO,MAAE,gBAAM,IAAG,IAAU;AAAA,cAC7C,MAAM;AAAA,eACT;AAAA,eAhBM,CAkBV;AAAA;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH;AAEJ;AAEO,SAAS,WAAW,EAAE,UAAU,MAAM,GAAgD;AAC3F,QAAM,QAAQ,SAAS;AACvB,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,QAAM,YACJ,KAAK,IAAI,GAAG,SAAS,IAAI,CAAC,MAAM,EAAE,KAAK,UAAU,EAAE,OAAO,EAAE,KAAK,SAAS,IAAI,EAAE,CAAC,IAAI;AACvF,SACE,oBAAC,OAAI,eAAc,UAAS,UAAU,GAAG,OACtC,mBAAS,IAAI,CAAC,GAAG,MAChB,qBAAC,QAAkB,MAAK,gBACtB;AAAA,wBAAC,QAAK,OAAO,MAAM,IAAI,MAAM,IAAI,SAAS,QACvC,cAAI,EAAE,IAAI,GAAG,EAAE,OAAO,IAAI,EAAE,IAAI,KAAK,EAAE,GAAG,OAAO,SAAS,GAC7D;AAAA,IACA,oBAAC,QAAK,UAAU,MAAM,IAAI,KAAM,YAAE,aAAY;AAAA,OAJrC,EAAE,IAKb,CACD,GACH;AAEJ;;;AEvFA,SAAS,OAAAC,MAAK,QAAAC,aAAY;AAiFtB,SACE,OAAAC,MADF,QAAAC,aAAA;AA/DG,SAAS,eACd,OACA,OACA,MACA,OACiC;AACjC,QAAM,MAAM,MAAM,IAAI,QAAK;AAC3B,QAAMC,QAAiB,CAAC,MAAM,OAAO,MAAM,KAAK,CAAC;AACjD,MAAI,MAAM,aAAa;AACrB,UAAM,OAAO,MAAM,YAAY,SAAS,MAAM,YAAY;AAC1D,IAAAA,MAAK;AAAA,MACH,GAAG,IAAI,GAAG,MAAM,YAAY,WAAW,MAAM,IAAI,KAAK,MAAM,YAAY,QAAQ,GAAG,IAAI,EAAE;AAAA,IAC3F;AAAA,EACF;AACA,QAAM,YACJ,MAAM,iBAAiB,IACnB,MAAM,KAAK,GAAG,MAAM,aAAa,IAAI,MAAM,cAAc,YAAY,IACrE,MAAM,IAAI,aAAa;AAC7B,EAAAA,MAAK,KAAK,SAAS;AACnB,QAAM,SAAS,MAAM,UAAU,CAAC,UAAK,QAAG,IAAI,CAAC,MAAM,KAAK;AACxD,EAAAA,MAAK;AAAA,IACH,MAAM;AAAA,MACJ,GAAG,aAAa,MAAM,OAAO,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,aAAa,MAAM,OAAO,UAAU,CAAC,GAAG,OAAO,CAAC,CAAC;AAAA,IACvG;AAAA,EACF;AACA,MAAI,MAAM,YAAY,QAAW;AAC/B,IAAAA,MAAK;AAAA,MACH,GAAG,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,MAAM,SAAS,CAAC,CAAC,IAAI,WAAW,OAAO,MAAM,OAAO,EAAE,QAAQ,MAAM,OAAO,CAAC,CAAC;AAAA,IAChH;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,MAAM;AACxB,MAAIC;AACJ,MAAI,KAAK,OAAQ,CAAAA,SAAQ,MAAM,KAAK,KAAK,MAAM;AAAA,WACtC,MAAM,eAAe,UAAU;AACtC,IAAAA,SAAQ,GAAG,MAAM,GAAG,GAAG,CAAC,IAAI,MAAM,IAAI,KAAK,YAAY,GAAG,KAAK,KAAK,KAAK,WAAW,CAAC;AAAA,EACvF,WAAW,MAAM,eAAe,aAAc,CAAAA,SAAQ,MAAM,IAAI,GAAG,GAAG,aAAa;AAAA,MAC9E,CAAAA,SAAQ,MAAM,MAAM,GAAG,GAAG,UAAU;AAGzC,QAAM,aAAa,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC;AACjC,MAAI,OAAOD,MAAK,IAAI,CAAC,GAAG,MAAM,CAAC;AAC/B,QAAM,SAAS,MAAM,KAAK,IAAI,CAAC,MAAMA,MAAK,CAAC,CAAC,EAAE,KAAK,GAAG;AACtD,SAAO,KAAK,SAAS,KAAK,aAAa,OAAO,CAAC,IAAI,aAAaC,MAAK,IAAI,IAAI,OAAO;AAClF,UAAM,OAAO,CAAC,GAAG,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,KAAK,MAAM,CAAC;AAC9E,QAAI,SAAS,OAAW;AACxB,WAAO,KAAK,OAAO,CAAC,MAAM,MAAM,IAAI;AAAA,EACtC;AACA,SAAO,EAAE,MAAM,OAAO,GAAG,OAAAA,OAAM;AACjC;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,QAAQ,SAAS;AACvB,QAAM,EAAE,MAAAD,OAAM,OAAAC,OAAM,IAAI,eAAe,OAAO,OAAO,MAAM,QAAQ,CAAC;AACpE,SACE,gBAAAF,MAACG,MAAA,EAAI,OAAc,gBAAe,iBAAgB,UAAU,GAC1D;AAAA,oBAAAJ,KAACK,OAAA,EAAK,MAAK,gBAAgB,UAAAH,OAAK;AAAA,IAChC,gBAAAF,KAACK,OAAA,EAAK,MAAK,kBAAkB,UAAAF,QAAM;AAAA,KACrC;AAEJ;;;ACtFA,SAAS,OAAAG,MAAK,QAAAC,aAAY;AAwBpB,gBAAAC,MAgBE,QAAAC,aAhBF;AAjBC,SAAS,SAAS,MAAyB;AAChD,QAAM,QAAkB,CAAC;AACzB,MAAI,KAAK,gBAAgB,KAAK,WAAW;AACvC,UAAM,KAAK,CAAC,KAAK,UAAU,KAAK,gBAAgB,KAAK,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK,CAAC;AAAA,EAC7F;AACA,MAAI,KAAK,MAAO,OAAM,KAAK,KAAK,KAAK;AACrC,MAAI,KAAK,WAAW;AAClB,UAAM,KAAK,GAAG,KAAK,YAAY,MAAM,EAAE,GAAG,aAAa,KAAK,MAAM,CAAC,MAAM;AAC3E,MAAI,KAAK,cAAc,OAAW,OAAM,KAAK,IAAI,KAAK,YAAY,KAAM,QAAQ,CAAC,CAAC,GAAG;AACrF,MAAI,KAAK,UAAW,OAAM,KAAK,GAAG,KAAK,SAAS,YAAY,KAAK,cAAc,IAAI,KAAK,GAAG,EAAE;AAC7F,MAAI,KAAK,UAAW,OAAM,KAAK,WAAW;AAC1C,SAAO,MAAM,KAAK,QAAK;AACzB;AAEA,SAAS,OAAO,EAAE,OAAO,MAAM,GAAiD;AAC9E,SACE,gBAAAD,KAACE,MAAA,EAAI,OAAO,GAAG,YAAY,GACzB,0BAAAF,KAACG,OAAA,EAAK,OAAe,iBAAM,GAC7B;AAEJ;AAEO,SAAS,UAAU,EAAE,MAAM,GAAqB;AACrD,QAAM,QAAQ,SAAS;AACvB,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aACE,gBAAAH,KAACE,MAAA,EAAI,cAAc,GACjB,0BAAAF,KAACG,OAAA,EAAM,gBAAM,MAAK,GACpB;AAAA,IAEJ,KAAK;AACH,aACE,gBAAAF,MAACC,MAAA,EAAI,cAAc,GACjB;AAAA,wBAAAF,KAAC,UAAO,OAAO,MAAM,IAAI,QAAQ,OAAO,MAAM,MAAM,QAAQ;AAAA,QAC5D,gBAAAA,KAACG,OAAA,EAAK,UAAU,MAAM,IAAI,KAAM,gBAAM,MAAK;AAAA,SAC7C;AAAA,IAEJ,KAAK;AACH,aACE,gBAAAF,MAACC,MAAA,EAAI,eAAc,UAAS,cAAc,GACxC;AAAA,wBAAAD,MAACC,MAAA,EACC;AAAA,0BAAAF,KAAC,UAAO,OAAO,MAAM,IAAI,QAAQ,OAAO,MAAM,MAAM,KAAK;AAAA,UACzD,gBAAAA,KAACG,OAAA,EACE,gBAAM,SAAS,MAAM,MAAM,YAAY,kCAAkC,KAC5E;AAAA,WACF;AAAA,QACC,MAAM,OACL,gBAAAH,KAACE,MAAA,EAAI,aAAa,GAChB,0BAAAF,KAACG,OAAA,EAAK,UAAU,MAAM,IAAI,KAAM,mBAAS,MAAM,IAAI,GAAE,GACvD,IACE;AAAA,SACN;AAAA,IAEJ,KAAK;AACH,aACE,gBAAAF,MAACC,MAAA,EAAI,cAAc,GACjB;AAAA,wBAAAF,KAAC,UAAO,OAAO,MAAM,IAAI,OAAO,OAAO,MAAM,MAAM,MAAM;AAAA,QACzD,gBAAAA,KAACG,OAAA,EAAK,OAAO,MAAM,IAAI,OAAQ,gBAAM,MAAK;AAAA,SAC5C;AAAA,IAEJ;AACE,aACE,gBAAAH,KAACE,MAAA,EAAI,cAAc,GAAG,aAAa,GACjC,0BAAAF,KAACG,OAAA,EAAM,gBAAM,MAAK,GACpB;AAAA,EAEN;AACF;AAGO,SAAS,cAAc,EAAE,WAAW,IAAI,GAA+C;AAC5F,QAAM,QAAQ,SAAS;AACvB,QAAM,UAAU,KAAK,IAAI,IAAI,MAAM,UAAU,aAAa,GAAI,EAAE,QAAQ,CAAC;AACzE,SACE,gBAAAF,MAACC,MAAA,EAAI,eAAc,UAAS,cAAc,GACvC;AAAA,cAAU,OACT,gBAAAD,MAACC,MAAA,EACC;AAAA,sBAAAF,KAAC,UAAO,OAAO,MAAM,IAAI,QAAQ,OAAO,MAAM,MAAM,KAAK;AAAA,MACzD,gBAAAA,KAACG,OAAA,EAAM,oBAAU,MAAK;AAAA,OACxB,IACE;AAAA,IACJ,gBAAAF,MAACC,MAAA,EAAI,aAAa,UAAU,OAAO,IAAI,GACrC;AAAA,sBAAAF,KAAC,WAAQ;AAAA,MACT,gBAAAC,MAACE,OAAA,EAAK,UAAU,MAAM,IAAI,KACvB;AAAA;AAAA,QACA,UAAU,OAAO,cAAc;AAAA,QAAW;AAAA,QAAE;AAAA,QAAQ;AAAA,SACvD;AAAA,OACF;AAAA,KACF;AAEJ;;;AC/EO,IAAM,iBAA0C;AAAA,EACrD,EAAE,MAAM,SAAS,MAAM,QAAQ,aAAa,mDAAmD;AAAA,EAC/F,EAAE,MAAM,SAAS,aAAa,oCAAoC;AAAA,EAClE,EAAE,MAAM,YAAY,aAAa,+BAA+B;AAAA,EAChE,EAAE,MAAM,SAAS,aAAa,yBAAyB;AAAA,EACvD,EAAE,MAAM,UAAU,aAAa,kCAAkC;AAAA,EACjE,EAAE,MAAM,SAAS,aAAa,oDAAoD;AAAA,EAClF,EAAE,MAAM,QAAQ,aAAa,mCAAmC,SAAS,CAAC,GAAG,EAAE;AAAA,EAC/E,EAAE,MAAM,QAAQ,aAAa,iBAAiB,SAAS,CAAC,QAAQ,GAAG,EAAE;AACvE;AAQO,SAAS,WAAW,OAA2B;AACpD,QAAM,OAAO,MAAM,KAAK;AACxB,MAAI,CAAC,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,IAAI,EAAG,QAAO,EAAE,MAAM,OAAO;AAC1E,QAAM,CAAC,OAAO,IAAI,GAAG,IAAI,IAAI,KAAK,MAAM,CAAC,EAAE,MAAM,KAAK;AACtD,QAAM,OAAO,KAAK,YAAY;AAC9B,MAAI,CAAC,KAAM,QAAO,EAAE,MAAM,WAAW,MAAM,GAAG;AAC9C,QAAM,UAAU,eAAe,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,SAAS,SAAS,IAAI,CAAC;AACvF,MAAI,CAAC,QAAS,QAAO,EAAE,MAAM,WAAW,KAAK;AAC7C,SAAO,EAAE,MAAM,WAAW,SAAS,MAAM,KAAK,KAAK,GAAG,EAAE,KAAK,EAAE;AACjE;AAGO,SAAS,iBAAiB,OAA+B;AAC9D,MAAI,CAAC,MAAM,WAAW,GAAG,KAAK,KAAK,KAAK,KAAK,EAAG,QAAO,CAAC;AACxD,QAAM,SAAS,MAAM,MAAM,CAAC,EAAE,YAAY;AAC1C,SAAO,eAAe;AAAA,IACpB,CAAC,MAAM,EAAE,KAAK,WAAW,MAAM,KAAK,EAAE,SAAS,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM,KAAK,MAAM;AAAA,EAC3F;AACF;AAGO,SAAS,cAAc,OAAmC;AAC/D,QAAM,CAAC,KAAK,IAAI,iBAAiB,KAAK;AACtC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,IAAI,MAAM,IAAI,GAAG,MAAM,OAAO,MAAM,EAAE;AAC/C;AAEO,IAAM,YAA6C;AAAA,EACxD,CAAC,SAAS,MAAM;AAAA,EAChB,CAAC,mCAAmC,UAAU;AAAA,EAC9C,CAAC,mBAAS,0CAA0C;AAAA,EACpD,CAAC,OAAO,0BAA0B;AAAA,EAClC,CAAC,OAAO,+BAA+B;AAAA,EACvC,CAAC,4BAA4B,iDAAiD;AAAA,EAC9E,CAAC,gBAAgB,MAAM;AACzB;;;AC9DO,SAAS,SAAS,OAAsB;AAC7C,QAAM,QAAQ,KAAK,IAAI,GAAG,eAAe,IAAI,CAAC,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,EAAE,CAAC,IAAI;AAC9F,QAAM,WAAW,eAAe;AAAA,IAC9B,CAAC,MACC,GAAG,MAAM,OAAO,OAAO,IAAI,EAAE,IAAI,GAAG,EAAE,OAAO,IAAI,EAAE,IAAI,KAAK,EAAE,IAAI,KAAK,CAAC,CAAC,GAAG,MAAM,IAAI,EAAE,WAAW,CAAC;AAAA,EACxG;AACA,QAAM,WAAW,KAAK,IAAI,GAAG,UAAU,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI;AACjE,QAAM,OAAO,UAAU,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,EAAE;AAC9E,SAAO,CAAC,MAAM,KAAK,UAAU,GAAG,GAAG,UAAU,IAAI,MAAM,KAAK,MAAM,GAAG,GAAG,IAAI,EAAE,KAAK,IAAI;AACzF;AAEA,eAAsB,WAAW,OAAc,SAAsB,SAAiB;AACpF,QAAM,SAAS,MAAM,QAAQ,OAAO;AACpC,QAAM,MAAM,OACT,IAAI,CAAC,MAAM,EAAE,EAAE,EACf,KAAK,CAAC,GAAG,MAAM;AACd,UAAM,KAAK,EAAE,WAAW,WAAW,IAAI,IAAI;AAC3C,UAAM,KAAK,EAAE,WAAW,WAAW,IAAI,IAAI;AAC3C,WAAO,KAAK,MAAM,EAAE,cAAc,CAAC;AAAA,EACrC,CAAC;AACH,MAAI,IAAI,WAAW;AACjB,WAAO,MAAM,IAAI,6DAA6D;AAChF,QAAM,QAAQ,IAAI,MAAM,GAAG,EAAE;AAC7B,QAAMC,SAAQ,MAAM;AAAA,IAAI,CAAC,OACvB,OAAO,UAAU,GAAG,MAAM,OAAO,MAAM,MAAM,GAAG,CAAC,IAAI,MAAM,OAAO,EAAE,CAAC,KAAK,KAAK,EAAE;AAAA,EACnF;AACA,MAAI,IAAI,SAAS,MAAM,OAAQ,CAAAA,OAAM,KAAK,MAAM,IAAI,gBAAW,IAAI,SAAS,MAAM,MAAM,OAAO,CAAC;AAChG,EAAAA,OAAM,KAAK,IAAI,MAAM,IAAI,yBAAyB,CAAC;AACnD,SAAOA,OAAM,KAAK,IAAI;AACxB;AAEA,eAAsB,WAAW,OAAc,SAAsB;AACnE,QAAM,EAAE,cAAc,OAAO,IAAI,MAAM,QAAQ,OAAO;AACtD,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,MACL,GAAG,MAAM,IAAI,uBAAuB,CAAC,aAAa,YAAY;AAAA,MAC9D,MAAM,IAAI,gEAAgE;AAAA,IAC5E,EAAE,KAAK,IAAI;AAAA,EACb;AACA,QAAMA,SAAkB,CAAC;AACzB,aAAW,SAAS,QAAQ;AAC1B,UAAM,OAAO,MAAM,SAAS,eAAe,MAAM,IAAI,YAAY,IAAI;AACrE,IAAAA,OAAM;AAAA,MACJ,GAAG,MAAM,OAAO,YAAY,MAAM,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,MAAM,cAAc,MAAM,IAAI,KAAK,MAAM,WAAW,EAAE,IAAI,EAAE;AAAA,IACjH;AACA,UAAM,QAAQ,QAAQ,CAAC,GAAG,MAAM;AAC9B,MAAAA,OAAM;AAAA,QACJ,KAAK,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,KAAK,GAAG,EAAE,YAAY,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE;AAAA,MACzG;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAOA,OAAM,KAAK,IAAI;AACxB;AAEA,eAAsB,aAAa,OAAc,SAAsB,SAAiB;AACtF,QAAM,CAAC,UAAU,KAAK,IAAI,MAAM,QAAQ,IAAI,CAAC,QAAQ,SAAS,GAAG,QAAQ,MAAM,CAAC,CAAC;AACjF,MAAI,SAAS,WAAW;AACtB,WAAO,MAAM,IAAI,wDAAwD;AAC3E,QAAM,OAAO,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AACvD,SAAO;AAAA,IACL;AAAA,IACA,SAAS,IAAI,CAAC,aAAa,EAAE,SAAS,OAAO,KAAK,IAAI,QAAQ,EAAE,KAAK,WAAW,QAAQ,EAAE,EAAE,EAAE;AAAA,IAC9F;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,eAAsB,UAAU,OAAc,SAAsB,SAAiB;AACnF,QAAM,EAAE,SAAS,MAAM,IAAI,MAAM,QAAQ,MAAM;AAC/C,MAAI,CAAC;AACH,WAAO,MAAM,IAAI,uEAAuE;AAC1F,MAAI,MAAM,MAAM,WAAW,GAAG;AAC5B,WAAO,MAAM,IAAI,GAAG,QAAQ,IAAI,sDAAsD;AAAA,EACxF;AACA,SAAO;AAAA,IACL,GAAG,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,YAAY,OAAO,KAAK,CAAC;AAAA,IACzD;AAAA,IACA,GAAG,eAAe,OAAO,OAAO,EAAE,OAAO,QAAQ,CAAC;AAAA,EACpD,EAAE,KAAK,IAAI;AACb;AAEA,eAAsB,WAAW,OAAc,SAAsB;AACnE,QAAM,SAAS,MAAM,QAAQ,OAAO;AACpC,MAAI,CAAC,OAAQ,QAAO,MAAM,MAAM,cAAc,QAAQ,GAAG,oBAAoB;AAC7E,QAAM,SAAS,MAAM,QAAQ,OAAO,EAAE,MAAM,MAAM,MAAS;AAC3D,QAAM,QAAQ,OAAO,QAAQ,OAAO,YAAY,EAC7C,OAAO,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,EACrB,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AACjB,SAAO;AAAA,IACL,GAAG,MAAM,GAAG,MAAM,MAAM,GAAG,CAAC,IAAI,QAAQ,GAAG,GAAG,QAAQ,YAAY,MAAM,IAAI,eAAe,IAAI,EAAE,KAAK,MAAM,IAAI,IAAI,OAAO,OAAO,YAAS,eAAe,OAAO,SAAS,CAAC,EAAE,CAAC;AAAA,IAC9K,GAAG,MAAM,IAAI,QAAQ,CAAC,UAAU,SAAS,OAAO,QAAQ,SAAS,GAAG,QAAQ,SAAS,MAAM,IAAI,SAAM,OAAO,MAAM,EAAE,IAAI,EAAE;AAAA,IAC1H,GAAG,MAAM,IAAI,cAAc,CAAC,IAAI,MAAM,SAAS,IAAI,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC,IAAI,MAAM;AAAA,EAC1F,EAAE,KAAK,IAAI;AACb;;;APgPI,SAEgB,OAAAC,MAFhB,QAAAC,aAAA;AArTJ,IAAM,cAAc;AACpB,IAAM,iBAAiB;AAEvB,SAAS,UAAU,KAAsB;AACvC,SAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AACxD;AAEA,SAAS,KAAK,EAAE,SAAS,OAAO,SAAS,SAAS,KAAQ,MAAM,KAAK,IAAI,GAAiB;AACxF,QAAM,QAAQ,SAAS;AACvB,QAAM,EAAE,KAAK,IAAI,OAAO;AACxB,QAAM,EAAE,MAAM,IAAI,UAAU;AAC5B,QAAM,EAAE,QAAQ,IAAI,cAAc;AAClC,QAAM,QAAQ,KAAK,IAAI,IAAI,OAAO;AAElC,QAAM,CAAC,OAAO,QAAQ,IAAI,WAAW,aAAa,OAAO,gBAAgB;AACzE,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA4B,WAAW;AACnE,QAAM,CAAC,cAAc,eAAe,IAAI,SAA6B;AACrE,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA6B;AACzD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,IAAI,CAAC;AAExC,QAAM,WAAW,OAAoC,MAAS;AAC9D,QAAM,cAAc,OAA2B,MAAS;AACxD,QAAM,SAAS,OAAO,oBAAI,IAAoB,CAAC;AAC/C,QAAM,WAAW,OAAO,KAAK;AAC7B,WAAS,UAAU;AAInB,YAAU,MAAM;AACd,UAAM,QAAQ,QAAQ,YAAY,GAAG,QAAQ,GAAG,kBAAkB,QAAQ;AAC1E,aAAS;AAAA,MACP,MAAM;AAAA,MACN,MAAM,GAAG,MAAM,KAAK,MAAM,OAAO,UAAU,CAAC,CAAC,IAAI,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;AAAA,EAAK,MAAM;AAAA,QAClF,SAAS,KAAK,iBAAc,KAAK;AAAA,MACnC,CAAC;AAAA,IACH,CAAC;AACD,QAAI,QAAQ;AACZ,UAAM,QAAQ,YAAY;AACxB,YAAM,SAAS,MAAM,QAAQ,OAAO;AACpC,UAAI,MAAO,UAAS,EAAE,MAAM,cAAc,YAAY,SAAS,WAAW,UAAU,CAAC;AAAA,IACvF;AACA,SAAK,MAAM;AACX,YACG,SAAS,EACT,KAAK,CAAC,aAAa;AAClB,iBAAW,KAAK,SAAU,QAAO,QAAQ,IAAI,EAAE,IAAI,EAAE,KAAK;AAAA,IAC5D,CAAC,EACA,MAAM,MAAM;AAAA,IAAC,CAAC;AACjB,UAAM,QAAQ,YAAY,MAAM,KAAK,MAAM,GAAG,MAAM;AACpD,WAAO,MAAM;AACX,cAAQ;AACR,oBAAc,KAAK;AACnB,eAAS,SAAS,MAAM;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,SAAS,OAAO,QAAQ,OAAO,OAAO,CAAC;AAG3C,YAAU,MAAM;AACd,QAAI,CAAC,MAAM,UAAW;AACtB,UAAM,QAAQ,YAAY,MAAM,SAAS,IAAI,CAAC,GAAG,GAAG;AACpD,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,MAAM,WAAW,GAAG,CAAC;AAEzB,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,WAAW,MAAM,UAAU,MAAS,GAAG,cAAc;AACnE,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,MAAM,CAAC;AAIX,QAAM,eAAe;AAAA,IACnB,OAAO,cAAsB;AAC3B,UAAI;AACF,cAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,cAAc,SAAS;AAC3E,cAAM,SAAS,OAAO,QAAQ,IAAI;AAClC,cAAM,UACJ,WAAW,OAAO,eAAe,UAAa,OAAO,iBAAiB;AACxE,iBAAS;AAAA,UACP,MAAM;AAAA,UACN;AAAA,UACA,aAAa,UAAU,OAAO,cAAc;AAAA,QAC9C,CAAC;AAAA,MACH,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,OAAO;AAAA,IACX,OAAO,SAAiB;AACtB,eAAS,EAAE,MAAM,QAAQ,KAAK,CAAC;AAC/B,YAAM,eAAe;AAAA,QACnB,GAAG,SAAS,QAAQ;AAAA,QACpB,EAAE,MAAM,QAAiB,SAAS,KAAK;AAAA,MACzC;AACA,YAAM,aAAa,IAAI,gBAAgB;AACvC,eAAS,UAAU;AACnB,eAAS,EAAE,MAAM,gBAAgB,KAAK,IAAI,EAAE,CAAC;AAC7C,UAAI;AACJ,UAAI;AACJ,UAAI;AACF,cAAM,EAAE,MAAM,OAAO,IAAI,MAAM,QAAQ;AAAA,UACrC,EAAE,OAAO,SAAS,QAAQ,OAAO,UAAU,aAAa;AAAA,UACxD,WAAW;AAAA,QACb;AACA,oBAAY,KAAK;AACjB,iBAAS;AAAA,UACP,MAAM;AAAA,UACN,WAAW,KAAK;AAAA,UAChB,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,UACtD,GAAI,KAAK,WAAW,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,UACnD,GAAI,KAAK,aAAa,OAAO,QAAQ,IAAI,KAAK,SAAS,IACnD,EAAE,cAAc,OAAO,QAAQ,IAAI,KAAK,SAAS,EAAG,IACpD,CAAC;AAAA,QACP,CAAC;AACD,iBAAS,EAAE,MAAM,cAAc,YAAY,SAAS,CAAC;AACrD,yBAAiB,SAAS,QAAQ;AAChC,cAAI,WAAW,OAAO,QAAS;AAC/B,gBAAM,QAAQ,MAAM,QAAQ,CAAC,GAAG,OAAO;AACvC,cAAI,OAAO,UAAU,YAAY,MAAO,UAAS,EAAE,MAAM,gBAAgB,MAAM,MAAM,CAAC;AACtF,cAAI,MAAM,MAAO,SAAQ,MAAM;AAAA,QACjC;AACA,iBAAS;AAAA,UACP,MAAM;AAAA,UACN,KAAK,IAAI;AAAA,UACT,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,UACzB,GAAI,WAAW,OAAO,UAAU,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,QACzD,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,YAAI,WAAW,OAAO,SAAS;AAC7B,mBAAS,EAAE,MAAM,cAAc,KAAK,IAAI,GAAG,WAAW,KAAK,CAAC;AAAA,QAC9D,OAAO;AACL,gBAAM,SAAU,IAA4B;AAC5C,cAAI,WAAW,EAAG,UAAS,EAAE,MAAM,cAAc,YAAY,UAAU,CAAC;AACxE,mBAAS,EAAE,MAAM,cAAc,KAAK,IAAI,GAAG,OAAO,UAAU,GAAG,EAAE,CAAC;AAAA,QACpE;AAAA,MACF,UAAE;AACA,YAAI,SAAS,YAAY,WAAY,UAAS,UAAU;AAAA,MAC1D;AACA,UAAI,UAAW,MAAK,aAAa,SAAS;AAAA,IAC5C;AAAA,IACA,CAAC,SAAS,KAAK,YAAY;AAAA,EAC7B;AAEA,QAAM,WAAW;AAAA,IACf,OAAO,UAAkB;AACvB,YAAM,SAAS,WAAW,KAAK;AAC/B,UAAI,OAAO,SAAS,WAAW;AAC7B,iBAAS;AAAA,UACP,MAAM;AAAA,UACN,MAAM,oBAAoB,OAAO,IAAI;AAAA,QACvC,CAAC;AACD;AAAA,MACF;AACA,UAAI,OAAO,SAAS,UAAW;AAC/B,YAAM,EAAE,SAAS,KAAK,IAAI;AAC1B,UAAI;AACF,gBAAQ,QAAQ,MAAM;AAAA,UACpB,KAAK;AACH,qBAAS,EAAE,MAAM,QAAQ,MAAM,SAAS,KAAK,EAAE,CAAC;AAChD;AAAA,UACF,KAAK;AACH,qBAAS,SAAS,MAAM;AACxB,iBAAK;AACL;AAAA,UACF,KAAK;AACH,qBAAS,SAAS,MAAM;AACxB,kBAAM,sBAA4B;AAClC,qBAAS,EAAE,MAAM,QAAQ,CAAC;AAC1B;AAAA,UACF,KAAK;AACH,gBAAI,MAAM;AACR,uBAAS,EAAE,MAAM,aAAa,OAAO,KAAK,CAAC;AAC3C,uBAAS,EAAE,MAAM,QAAQ,MAAM,gBAAgB,MAAM,OAAO,IAAI,CAAC,GAAG,CAAC;AAAA,YACvE,OAAO;AACL,uBAAS;AAAA,gBACP,MAAM;AAAA,gBACN,MAAM,MAAM,WAAW,OAAO,SAAS,SAAS,QAAQ,KAAK;AAAA,cAC/D,CAAC;AAAA,YACH;AACA;AAAA,UACF,KAAK;AACH,qBAAS,EAAE,MAAM,QAAQ,MAAM,MAAM,WAAW,OAAO,OAAO,EAAE,CAAC;AACjE;AAAA,UACF,KAAK,YAAY;AACf,kBAAM,WAAW,MAAM,QAAQ,SAAS;AACxC,uBAAW,KAAK,SAAU,QAAO,QAAQ,IAAI,EAAE,IAAI,EAAE,KAAK;AAC1D,qBAAS,EAAE,MAAM,QAAQ,MAAM,MAAM,aAAa,OAAO,SAAS,QAAQ,CAAC,EAAE,CAAC;AAC9E;AAAA,UACF;AAAA,UACA,KAAK;AACH,qBAAS,EAAE,MAAM,QAAQ,MAAM,MAAM,UAAU,OAAO,SAAS,QAAQ,CAAC,EAAE,CAAC;AAC3E;AAAA,UACF,KAAK;AACH,qBAAS,EAAE,MAAM,QAAQ,MAAM,MAAM,WAAW,OAAO,OAAO,EAAE,CAAC;AACjE;AAAA,QACJ;AAAA,MACF,SAAS,KAAK;AACZ,iBAAS,EAAE,MAAM,SAAS,MAAM,IAAI,QAAQ,IAAI,YAAY,UAAU,GAAG,CAAC,GAAG,CAAC;AAAA,MAChF;AAAA,IACF;AAAA,IACA,CAAC,SAAS,MAAM,OAAO,OAAO,KAAK;AAAA,EACrC;AAEA,QAAM,SAAS,YAAY,MAAM;AAC/B,UAAM,OAAU,OAAO,MAAM,EAAE,KAAK;AACpC,QAAI,CAAC,KAAM;AACX,QAAI,WAAW,IAAI,EAAE,SAAS,QAAQ;AACpC,gBAAa,WAAW;AACxB,sBAAgB,MAAS;AACzB,WAAK,SAAS,IAAI;AAClB;AAAA,IACF;AACA,QAAI,SAAS,QAAQ,WAAW;AAC9B,gBAAU,+CAA+C;AACzD;AAAA,IACF;AACA,cAAa,WAAW;AACxB,oBAAgB,MAAS;AACzB,SAAK,KAAK,IAAI;AAAA,EAChB,GAAG,CAAC,QAAQ,UAAU,IAAI,CAAC;AAI3B,QAAM,SAAS,CAAC,cAAsB;AACpC,UAAM,EAAE,QAAQ,IAAI,SAAS;AAC7B,QAAI,QAAQ,WAAW,EAAG;AAC1B,UAAM,UAAU,gBAAgB,QAAQ;AACxC,UAAM,OAAO,KAAK,IAAI,QAAQ,QAAQ,KAAK,IAAI,GAAG,UAAU,SAAS,CAAC;AACtE,oBAAgB,SAAS,QAAQ,SAAS,SAAY,IAAI;AAC1D,cAAU,SAAS,QAAQ,SAAY,cAAiB,SAAS,QAAQ,IAAI,CAAE,CAAC;AAAA,EAClF;AAEA,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,QAAQ,UAAU,KAAK;AAC7B,YAAM,QACJ,YAAY,YAAY,UAAa,IAAI,IAAI,YAAY,UAAU;AACrE,UAAI,OAAO;AACT,iBAAS,SAAS,MAAM;AACxB,aAAK;AACL;AAAA,MACF;AACA,kBAAY,UAAU,IAAI;AAC1B,UAAI,SAAS,QAAQ,UAAW,UAAS,SAAS,MAAM;AAAA,eAC/C,OAAO,MAAM,SAAS,EAAG,WAAa,WAAW;AAC1D,gBAAU,4BAA4B;AACtC;AAAA,IACF;AACA,gBAAY,UAAU;AAEtB,QAAI,IAAI,QAAQ;AACd,UAAI,SAAS,QAAQ,UAAW,UAAS,SAAS,MAAM;AACxD;AAAA,IACF;AAEA,QAAK,UAAU,QAAQ,CAAC,IAAI,UAAY,IAAI,QAAQ,UAAU,KAAM;AAClE,gBAAU,CAAC,MAAS,OAAO,GAAG,IAAI,CAAC;AACnC;AAAA,IACF;AACA,QAAI,IAAI,QAAQ;AACd,UAAI,IAAI,SAAS,IAAI,KAAM,WAAU,CAAC,MAAS,OAAO,GAAG,IAAI,CAAC;AAAA,eAClD,cAAc,MAAM,EAAG,WAAU,CAAC,MAAS,sBAAsB,CAAC,CAAC;AAAA,UAC1E,QAAO;AACZ;AAAA,IACF;AACA,QAAI,IAAI,KAAK;AACX,YAAM,YAAY,cAAiB,OAAO,MAAM,CAAC;AACjD,UAAI,UAAW,WAAa,SAAS,SAAS,CAAC;AAC/C;AAAA,IACF;AACA,QAAI,IAAI,SAAS;AACf,YAAM,QAAW,GAAG,MAAM;AAC1B,UAAI,MAAO,WAAU,KAAK;AAAA,UACrB,QAAO,EAAE;AACd;AAAA,IACF;AACA,QAAI,IAAI,WAAW;AACjB,YAAM,QAAW,KAAK,MAAM;AAC5B,UAAI,MAAO,WAAU,KAAK;AAAA,eACjB,iBAAiB,OAAW,QAAO,CAAC;AAC7C;AAAA,IACF;AACA,QAAI,IAAI,UAAW,QAAO,UAAa,IAAI;AAC3C,QAAI,IAAI,WAAY,QAAO,UAAa,KAAK;AAC7C,QAAI,IAAI,QAAS,IAAI,QAAQ,UAAU,IAAM,QAAO,UAAa,SAAS;AAC1E,QAAI,IAAI,OAAQ,IAAI,QAAQ,UAAU,IAAM,QAAO,UAAa,OAAO;AACvE,QAAI,IAAI,UAAW,QAAO,UAAa,SAAS;AAChD,QAAI,IAAI,OAAQ,QAAO,UAAa,aAAa;AACjD,QAAI,IAAI,QAAQ,UAAU,IAAK,QAAO,UAAa,eAAe;AAClE,QAAI,IAAI,QAAQ,UAAU,IAAK,QAAO,UAAa,aAAa;AAChE,QAAI,IAAI,QAAQ,UAAU,IAAK,QAAO,UAAa,cAAc;AACjE,QAAI,IAAI,QAAQ,UAAU,KAAK;AAC7B,YAAM,eAAmB;AACzB;AAAA,IACF;AACA,QAAI,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAO;AACpC,cAAU,CAAC,MAAS,OAAO,GAAG,KAAK,CAAC;AAAA,EACtC,CAAC;AAED,WAAS,CAAC,SAAS;AACjB,cAAU,CAAC,MAAS,OAAO,GAAG,IAAI,CAAC;AAAA,EACrC,CAAC;AAID,QAAM,cAAc,iBAAoB,OAAO,MAAM,CAAC;AACtD,SACE,gBAAAA,MAACC,MAAA,EAAI,eAAc,UAAS,OAC1B;AAAA,oBAAAF,KAAC,UAAyB,OAAO,MAAM,SACpC,WAAC,UAAU,gBAAAA,KAAC,aAAyB,SAAV,MAAM,EAAkB,KADzC,MAAM,KAEnB;AAAA,IACC,MAAM,YAAY,gBAAAA,KAAC,iBAAc,WAAW,MAAM,WAAW,KAAK,OAAO,IAAK;AAAA,IAC/E,gBAAAA,KAAC,YAAS,QAAgB,OAAc,aAAa,aAAa;AAAA,IAClE,gBAAAA,KAAC,cAAW,UAAU,aAAa,OAAc;AAAA,IACjD,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,MAAM;AAAA,UACJ,OAAO,QAAQ,YAAY,cAAc,IAAI,IAAI,QAAQ,GAAG,EAAE,IAAI,KAAK,QAAQ;AAAA,UAC/E,WAAW,QAAQ;AAAA,UACnB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,QAC7B;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAGO,SAAS,QAAQ,OAAqB;AAC3C,SACE,gBAAAA,KAAC,iBAAc,OAAO,MAAM,OAC1B,0BAAAA,KAAC,QAAM,GAAG,OAAO,GACnB;AAEJ;","names":["Box","Box","Text","jsx","jsxs","left","right","Box","Text","Box","Text","jsx","jsxs","Box","Text","lines","jsx","jsxs","Box"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/accounts.ts","../src/lib/account-flow.ts"],"sourcesContent":["import { createInterface } from 'node:readline';\nimport {\n type Account,\n type AccountConnection,\n CLI_LOGINS,\n cliBinaryFor,\n globalPaths,\n loginEnv,\n type ProviderKind,\n SandboxManager,\n type SubscriptionInfo,\n} from '@davecode/core';\nimport { type CliContext, printJson } from '../context';\nimport { CliError, EXIT } from '../errors';\nimport {\n type AddFlags,\n accountFromFlags,\n accountInteractively,\n accountPolicy,\n describeCreate,\n providerInfo,\n} from '../lib/account-flow';\nimport { type AccountsBackend, openAccounts, resolveAccount } from '../lib/accounts-backend';\nimport { type SpawnFn, spawnInteractive, which } from '../lib/proc';\nimport { PromptCancelledError, type Prompter } from '../lib/prompter';\nimport { detectProjectRoot } from '../runtime';\nimport { type Column, table, truncate } from '../ui/format';\nimport type { Theme } from '../ui/theme';\n\nexport interface AccountsDeps {\n /** Override the backend (tests). */\n backend?: AccountsBackend;\n prompter?: Prompter;\n readStdin?: () => Promise<string>;\n spawn?: SpawnFn;\n /** Used by `accounts login --hold` (tests). */\n waitForEnter?: () => Promise<void>;\n}\n\nexport interface BackendFlags {\n /** Write to state.db even if a gateway is running. */\n local?: boolean;\n}\n\nasync function backendFor(\n ctx: CliContext,\n flags: BackendFlags,\n deps: AccountsDeps,\n): Promise<AccountsBackend> {\n if (deps.backend) return deps.backend;\n const projectRoot = await detectProjectRoot(ctx.cwd, ctx.home);\n return openAccounts({\n home: ctx.home,\n env: ctx.env,\n ...(projectRoot ? { projectRoot } : {}),\n ...(flags.local ? { local: true } : {}),\n });\n}\n\nasync function withBackend<T>(\n ctx: CliContext,\n flags: BackendFlags,\n deps: AccountsDeps,\n fn: (backend: AccountsBackend) => Promise<T>,\n): Promise<T> {\n const backend = await backendFor(ctx, flags, deps);\n try {\n return await fn(backend);\n } finally {\n if (!deps.backend) backend.close();\n }\n}\n\nasync function prompterFor(ctx: CliContext, deps: AccountsDeps): Promise<Prompter> {\n if (deps.prompter) return deps.prompter;\n const { createInkPrompter } = await import('../tui/prompts');\n return createInkPrompter({ stdout: ctx.io.stdout, stdin: ctx.io.stdin, theme: ctx.theme });\n}\n\nfunction readAllStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (chunk: string) => {\n data += chunk;\n });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n// ---------------------------------------------------------------------------\n// list\n// ---------------------------------------------------------------------------\n\nfunction statusText(theme: Theme, account: Account): string {\n switch (account.status) {\n case 'active':\n return theme.ok('active');\n case 'cooldown':\n return theme.warn('cooldown');\n case 'error':\n return theme.error('error');\n default:\n return theme.dim('disabled');\n }\n}\n\nfunction detail(account: Account): string {\n const config = account.config;\n const parts: string[] = [];\n if (typeof config.baseUrl === 'string') parts.push(config.baseUrl);\n if (Array.isArray(config.models) && config.models.length > 0) {\n parts.push(config.models.slice(0, 3).join(', ') + (config.models.length > 3 ? ', …' : ''));\n }\n if (typeof config.binaryPath === 'string') parts.push(config.binaryPath);\n return parts.join(' · ');\n}\n\nexport function renderAccountList(theme: Theme, accounts: Account[], columns: number): string[] {\n const cols: Column[] = [\n { header: 'ID' },\n { header: 'LABEL' },\n { header: 'PROVIDER' },\n { header: 'STATUS' },\n { header: 'PRI', align: 'right', drop: 2 },\n { header: 'WEIGHT', align: 'right', drop: 3 },\n { header: 'DETAILS', drop: 4 },\n ];\n const rows = accounts.map((a) => [\n theme.accent(a.id),\n truncate(a.label, 28),\n a.provider,\n statusText(theme, a),\n String(a.priority),\n String(a.weight),\n theme.dim(truncate(detail(a), 40)),\n ]);\n return table(theme, cols, rows, columns);\n}\n\nexport async function accountsList(\n ctx: CliContext,\n flags: BackendFlags = {},\n deps: AccountsDeps = {},\n): Promise<number> {\n return withBackend(ctx, flags, deps, async (backend) => {\n const accounts = await backend.list();\n if (ctx.json) {\n printJson(ctx, { source: backend.kind, accounts });\n return EXIT.ok;\n }\n if (accounts.length === 0) {\n ctx.out(ctx.theme.dim('No accounts yet.'));\n ctx.out(`Add one with ${ctx.theme.accent('davecode accounts add')}.`);\n return EXIT.ok;\n }\n for (const line of renderAccountList(ctx.theme, accounts, ctx.columns)) ctx.out(line);\n ctx.out();\n ctx.out(\n ctx.theme.dim(backend.kind === 'gateway' ? 'source: running gateway' : 'source: local state'),\n );\n return EXIT.ok;\n });\n}\n\n// ---------------------------------------------------------------------------\n// add\n// ---------------------------------------------------------------------------\n\nexport interface AddCommandFlags extends AddFlags, BackendFlags {\n /** Never prompt; everything comes from flags. */\n yes?: boolean;\n /** commander's `--no-login`. */\n login?: boolean;\n}\n\nexport async function accountsAdd(\n ctx: CliContext,\n flags: AddCommandFlags,\n deps: AccountsDeps = {},\n): Promise<number> {\n return withBackend(ctx, flags, deps, async (backend) => {\n const existing = await backend.list();\n const interactive = ctx.interactive && !flags.yes && !flags.secretStdin;\n const { theme, errTheme } = ctx;\n\n let create: Awaited<ReturnType<typeof accountFromFlags>> | undefined;\n if (interactive) {\n try {\n create = await accountInteractively(flags, {\n prompter: await prompterFor(ctx, deps),\n config: backend.config,\n existing,\n say: (line) => ctx.out(line),\n warn: theme.warn,\n });\n } catch (err) {\n if (err instanceof PromptCancelledError) {\n ctx.err(errTheme.dim('Cancelled.'));\n return EXIT.failure;\n }\n throw err;\n }\n if (!create) {\n ctx.err(errTheme.dim('Nothing added.'));\n return EXIT.failure;\n }\n } else {\n create = await accountFromFlags(flags, {\n env: ctx.env,\n readStdin: deps.readStdin ?? readAllStdin,\n });\n const policy = accountPolicy(create.provider, backend.config, existing);\n if (policy.blocked) {\n throw new CliError(policy.blocked.message, { hint: policy.blocked.hint });\n }\n for (const warning of policy.warnings) {\n ctx.err(errTheme.warn(`${errTheme.glyph.warn} ${warning}`));\n }\n if (flags.secret !== undefined) {\n ctx.err(\n errTheme.dim(\n 'Note: --secret is visible in shell history and process lists; prefer --secret-env or --secret-stdin.',\n ),\n );\n }\n }\n\n const account = await backend.create(create);\n if (ctx.json) {\n printJson(ctx, { account });\n return EXIT.ok;\n }\n ctx.out(\n `${theme.ok(theme.glyph.ok)} Added ${theme.bold(account.label)} ${theme.dim(`(${account.id}, ${account.provider})`)}`,\n );\n if (!interactive) {\n for (const line of describeCreate(create)) ctx.out(theme.dim(` ${line}`));\n }\n\n const info = providerInfo(account.provider);\n if (info?.auth === 'cli-login') {\n const loginNow =\n interactive &&\n flags.login !== false &&\n (await (\n await prompterFor(ctx, deps)\n ).confirm(`Log in to ${info.binary} for this account now?`, true));\n if (loginNow) return accountsLogin(ctx, account.id, [], flags, { ...deps, backend });\n ctx.out(\n theme.dim(`Next: log in with ${theme.accent(`davecode accounts login ${account.id}`)}`),\n );\n }\n return EXIT.ok;\n });\n}\n\n// ---------------------------------------------------------------------------\n// remove / enable / disable\n// ---------------------------------------------------------------------------\n\nexport async function accountsRemove(\n ctx: CliContext,\n ref: string,\n flags: BackendFlags & { yes?: boolean },\n deps: AccountsDeps = {},\n): Promise<number> {\n return withBackend(ctx, flags, deps, async (backend) => {\n const account = await resolveAccount(backend, ref);\n if (!flags.yes) {\n if (!ctx.interactive) {\n throw new CliError(`Refusing to remove ${account.id} without confirmation`, {\n hint: 'Pass --yes to remove it non-interactively.',\n });\n }\n const ok = await (await prompterFor(ctx, deps))\n .confirm(`Remove ${account.label} (${account.id}) and its sandbox?`, false)\n .catch((err: unknown) => {\n if (err instanceof PromptCancelledError) return false;\n throw err;\n });\n if (!ok) {\n ctx.err(ctx.errTheme.dim('Nothing removed.'));\n return EXIT.failure;\n }\n }\n await backend.remove(account.id);\n if (ctx.json) printJson(ctx, { removed: account.id });\n else ctx.out(`${ctx.theme.ok(ctx.theme.glyph.ok)} Removed ${account.label} (${account.id})`);\n return EXIT.ok;\n });\n}\n\nexport async function accountsSetEnabled(\n ctx: CliContext,\n ref: string,\n enabled: boolean,\n flags: BackendFlags = {},\n deps: AccountsDeps = {},\n): Promise<number> {\n return withBackend(ctx, flags, deps, async (backend) => {\n const account = await resolveAccount(backend, ref);\n const updated = await backend.update(account.id, { enabled });\n if (ctx.json) printJson(ctx, { account: updated });\n else {\n ctx.out(\n `${ctx.theme.ok(ctx.theme.glyph.ok)} ${updated.label} is now ${enabled ? 'enabled' : 'disabled'} ${ctx.theme.dim(`(${updated.status})`)}`,\n );\n }\n return EXIT.ok;\n });\n}\n\n// ---------------------------------------------------------------------------\n// plan (subscription details)\n// ---------------------------------------------------------------------------\n\nexport interface PlanFlags extends BackendFlags {\n plan?: string;\n paid?: string;\n renews?: string;\n price?: string;\n currency?: string;\n period?: string;\n notes?: string;\n clear?: boolean;\n}\n\nexport function describeSubscription(subscription: SubscriptionInfo | undefined): string {\n if (!subscription) return 'no plan recorded';\n const parts: string[] = [];\n if (subscription.plan) parts.push(subscription.plan);\n if (subscription.price) {\n const { amount, currency, period } = subscription.price;\n parts.push(`${amount} ${currency}/${period}`);\n }\n if (subscription.paidAt) parts.push(`paid ${subscription.paidAt}`);\n if (subscription.renewsAt) parts.push(`renews ${subscription.renewsAt}`);\n if (subscription.notes) parts.push(subscription.notes);\n return parts.length > 0 ? parts.join(' · ') : 'no plan recorded';\n}\n\n/** Merge plan flags into the existing subscription details (validated by the backend). */\nexport function subscriptionFromFlags(\n existing: SubscriptionInfo | undefined,\n flags: PlanFlags,\n): SubscriptionInfo {\n const next: SubscriptionInfo = { ...existing };\n if (flags.plan !== undefined) next.plan = flags.plan;\n if (flags.paid !== undefined) next.paidAt = flags.paid;\n if (flags.renews !== undefined) next.renewsAt = flags.renews;\n if (flags.notes !== undefined) next.notes = flags.notes;\n if (flags.price !== undefined || flags.currency !== undefined || flags.period !== undefined) {\n const amount = flags.price !== undefined ? Number(flags.price) : existing?.price?.amount;\n if (amount === undefined || !Number.isFinite(amount)) {\n throw new CliError('--price needs a number, e.g. --price 20', {\n hint: 'Set the amount with --price, and optionally --currency USD --period month.',\n });\n }\n const period = flags.period ?? existing?.price?.period ?? 'month';\n if (period !== 'month' && period !== 'year') {\n throw new CliError('--period must be \"month\" or \"year\"');\n }\n next.price = { amount, currency: flags.currency ?? existing?.price?.currency ?? 'USD', period };\n }\n return next;\n}\n\nexport async function accountsPlan(\n ctx: CliContext,\n ref: string,\n flags: PlanFlags = {},\n deps: AccountsDeps = {},\n): Promise<number> {\n return withBackend(ctx, flags, deps, async (backend) => {\n const account = await resolveAccount(backend, ref);\n const { theme } = ctx;\n const changes = ['plan', 'paid', 'renews', 'price', 'currency', 'period', 'notes'] as const;\n const editing = flags.clear || changes.some((key) => flags[key] !== undefined);\n if (!editing) {\n if (ctx.json)\n printJson(ctx, { account: account.id, subscription: account.subscription ?? null });\n else ctx.out(`${theme.bold(account.label)}: ${describeSubscription(account.subscription)}`);\n return EXIT.ok;\n }\n const subscription = flags.clear ? null : subscriptionFromFlags(account.subscription, flags);\n const updated = await backend.update(account.id, { subscription });\n if (ctx.json) printJson(ctx, { account: updated });\n else {\n ctx.out(\n `${theme.ok(theme.glyph.ok)} ${updated.label}: ${describeSubscription(updated.subscription)}`,\n );\n }\n return EXIT.ok;\n });\n}\n\n// ---------------------------------------------------------------------------\n// login\n// ---------------------------------------------------------------------------\n\n/** Arguments that start each CLI's own official login flow. */\nexport function loginArgs(provider: ProviderKind): string[] {\n return CLI_LOGINS[provider]?.loginArgs ?? [];\n}\n\nexport interface LoginFlags extends BackendFlags {\n /** Wait for Enter before exiting (used when the dashboard opened this in a new window). */\n hold?: boolean;\n}\n\nfunction waitForEnter(): Promise<void> {\n return new Promise((resolve) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question('Press Enter to close this window.', () => {\n rl.close();\n resolve();\n });\n rl.once('close', resolve);\n });\n}\n\nexport function describeConnection(theme: Theme, connection: AccountConnection): string {\n const label: Record<AccountConnection['status'], string> = {\n connected: theme.ok(`${theme.glyph.ok} connected`),\n not_connected: theme.warn(`${theme.glyph.warn} not connected`),\n unknown: theme.dim('? unknown'),\n };\n return `${label[connection.status]}${connection.detail ? theme.dim(` — ${connection.detail}`) : ''}`;\n}\n\nexport async function accountsLogin(\n ctx: CliContext,\n ref: string,\n extraArgs: string[] = [],\n flags: LoginFlags = {},\n deps: AccountsDeps = {},\n): Promise<number> {\n if (!flags.hold) return runLogin(ctx, ref, extraArgs, flags, deps);\n try {\n return await runLogin(ctx, ref, extraArgs, flags, deps);\n } catch (err) {\n ctx.err(ctx.errTheme.warn(err instanceof Error ? err.message : String(err)));\n return EXIT.failure;\n } finally {\n await (deps.waitForEnter ?? waitForEnter)();\n }\n}\n\nfunction runLogin(\n ctx: CliContext,\n ref: string,\n extraArgs: string[],\n flags: LoginFlags,\n deps: AccountsDeps,\n): Promise<number> {\n return withBackend(ctx, flags, deps, async (backend) => {\n const account = await resolveAccount(backend, ref);\n const spec = CLI_LOGINS[account.provider];\n if (!spec) {\n const info = providerInfo(account.provider);\n throw new CliError(`${account.provider} accounts do not use a CLI login`, {\n hint:\n info?.auth === 'api-key' || info?.auth === 'optional-key'\n ? `Rotate the key with: davecode accounts add … or PATCH /api/accounts/${account.id}`\n : undefined,\n });\n }\n const binary = cliBinaryFor(account) ?? spec.binary;\n const resolved = which(binary, ctx.env);\n if (!resolved) {\n throw new CliError(`Cannot find \\`${binary}\\` on PATH`, { hint: spec.installHint });\n }\n\n const sandboxes = new SandboxManager(globalPaths(ctx.home).sandboxes);\n const dir = sandboxes.prepare(account);\n const isolation = loginEnv(account, sandboxes);\n const env = { ...ctx.env, ...isolation };\n const [variable] = Object.keys(isolation);\n const { theme } = ctx;\n\n ctx.out(\n `${theme.accent(theme.glyph.arrow)} Logging in ${theme.bold(account.label)} ${theme.dim(`(${account.id})`)}`,\n );\n ctx.out(theme.dim(` ${variable}=${dir}`));\n ctx.out(theme.dim(` ${spec.instructions}`));\n ctx.out(theme.dim(' DaveCode never sees your password; the vendor CLI keeps the login.'));\n ctx.out();\n\n const args = extraArgs.length > 0 ? extraArgs : spec.loginArgs;\n const exit = await spawnInteractive(resolved, args, {\n env,\n cwd: dir,\n ...(deps.spawn ? { spawn: deps.spawn } : {}),\n });\n ctx.out();\n if (exit !== 0) {\n ctx.err(ctx.errTheme.warn(`${binary} exited with code ${exit}`));\n return exit;\n }\n if (account.status === 'error' && account.enabled) {\n // A fresh login fixes auth errors; reset the account so the router tries it again.\n await backend.update(account.id, { enabled: true });\n }\n const connection = await backend.connection(account.id).catch(() => undefined);\n if (connection) ctx.out(` ${describeConnection(theme, connection)}`);\n ctx.out(\n `${theme.ok(theme.glyph.ok)} ${account.label} is ready. Its login lives only in ${dir}`,\n );\n return EXIT.ok;\n });\n}\n\nexport interface ConnectFlags extends BackendFlags {\n /** Only report the connection state. */\n check?: boolean;\n}\n\n/**\n * \"Connect subscription\" from the terminal: show the account's connection state and, for\n * CLI-login accounts that are not connected, run the vendor's official login.\n */\nexport async function accountsConnect(\n ctx: CliContext,\n ref: string,\n flags: ConnectFlags = {},\n deps: AccountsDeps = {},\n): Promise<number> {\n const { account, connection } = await withBackend(ctx, flags, deps, async (backend) => {\n const account = await resolveAccount(backend, ref);\n return { account, connection: await backend.connection(account.id) };\n });\n if (ctx.json) {\n printJson(ctx, { connection });\n return connection.status === 'connected' || flags.check ? EXIT.ok : EXIT.failure;\n }\n const { theme } = ctx;\n ctx.out(`${theme.bold(account.label)} ${theme.dim(`(${account.id}, ${account.provider})`)}`);\n ctx.out(` ${describeConnection(theme, connection)}`);\n if (flags.check || connection.status === 'connected') return EXIT.ok;\n if (connection.method === 'api-key') {\n ctx.out(\n theme.dim(\n ` Store a key in the dashboard (Accounts → ${account.label}) or re-add the account with --secret-env.`,\n ),\n );\n return EXIT.failure;\n }\n if (connection.method !== 'cli-login') return EXIT.failure;\n ctx.out();\n return accountsLogin(ctx, account.id, [], flags, deps);\n}\n","import {\n type Account,\n type DaveConfig,\n EXPERIMENTAL_PROVIDER_KINDS,\n type ProviderKind,\n type QuotaLimits,\n SUBSCRIPTION_PROVIDER_KINDS,\n} from '@davecode/core';\nimport { CliError } from '../errors';\nimport type { AccountCreate } from './accounts-backend';\nimport type { Prompter } from './prompter';\n\n// ---------------------------------------------------------------------------\n// Provider catalogue\n// ---------------------------------------------------------------------------\n\nexport type AuthKind = 'api-key' | 'optional-key' | 'cli-login' | 'browser';\n\nexport interface ProviderInfo {\n kind: ProviderKind;\n name: string;\n auth: AuthKind;\n defaultLabel: string;\n /** Default CLI binary for `cli-login` providers. */\n binary?: string;\n}\n\nexport const PROVIDERS: readonly ProviderInfo[] = [\n { kind: 'anthropic', name: 'Anthropic API', auth: 'api-key', defaultLabel: 'Anthropic' },\n { kind: 'openai', name: 'OpenAI API', auth: 'api-key', defaultLabel: 'OpenAI' },\n { kind: 'gemini', name: 'Google Gemini API', auth: 'api-key', defaultLabel: 'Gemini' },\n {\n kind: 'openai-compatible',\n name: 'OpenRouter or another OpenAI-compatible provider',\n auth: 'optional-key',\n defaultLabel: 'OpenRouter',\n },\n {\n kind: 'claude-cli',\n name: 'Claude Code CLI (your Claude login)',\n auth: 'cli-login',\n defaultLabel: 'Claude Code',\n binary: 'claude',\n },\n {\n kind: 'codex-cli',\n name: 'Codex CLI (your ChatGPT/OpenAI login)',\n auth: 'cli-login',\n defaultLabel: 'Codex',\n binary: 'codex',\n },\n {\n kind: 'gemini-cli',\n name: 'Gemini CLI (your Google login)',\n auth: 'cli-login',\n defaultLabel: 'Gemini CLI',\n binary: 'gemini',\n },\n {\n kind: 'gemini-web',\n name: 'Gemini web session (experimental)',\n auth: 'browser',\n defaultLabel: 'Gemini web',\n },\n];\n\nexport function providerInfo(kind: string): ProviderInfo | undefined {\n return PROVIDERS.find((p) => p.kind === kind);\n}\n\nexport const DEFAULT_COMPATIBLE_URL = 'https://openrouter.ai/api/v1';\n\n// ---------------------------------------------------------------------------\n// Terms-of-Service policy\n// ---------------------------------------------------------------------------\n\nexport const GEMINI_WEB_TOS =\n 'gemini-web automates the consumer Gemini web app through a browser profile. This likely ' +\n 'violates Google’s Terms of Service and your account can be rate-limited or suspended.';\n\nexport const ROTATION_TOS =\n 'Rotating several subscription logins of the same provider to get around per-account limits ' +\n 'may violate the provider’s consumer terms; accounts can be rate-limited or suspended.';\n\nexport interface Policy {\n /** The account cannot be added with the current flags. */\n blocked?: { message: string; hint: string };\n /** Shown (and, interactively, confirmed) before adding. */\n warnings: string[];\n}\n\n/** Experimental-flag rules for adding an account of `provider`. */\nexport function accountPolicy(\n provider: ProviderKind,\n config: Pick<DaveConfig, 'experimental'>,\n existing: Pick<Account, 'provider'>[],\n): Policy {\n const warnings: string[] = [];\n if (EXPERIMENTAL_PROVIDER_KINDS.includes(provider)) {\n if (!config.experimental.geminiWeb) {\n return {\n warnings,\n blocked: {\n message: `${provider} is experimental and disabled. ${GEMINI_WEB_TOS}`,\n hint: 'If you accept the risk, set \"experimental\": { \"geminiWeb\": true } in ~/.davecode/config.json (or DAVECODE_EXPERIMENTAL_GEMINI_WEB=1).',\n },\n };\n }\n warnings.push(GEMINI_WEB_TOS);\n }\n const sameProvider = existing.filter((a) => a.provider === provider).length;\n if (SUBSCRIPTION_PROVIDER_KINDS.includes(provider) && sameProvider > 0) {\n if (!config.experimental.multiAccountRotation) {\n return {\n warnings,\n blocked: {\n message: `You already have a ${provider} account. ${ROTATION_TOS}`,\n hint: 'If you accept the risk, set \"experimental\": { \"multiAccountRotation\": true } in ~/.davecode/config.json (or DAVECODE_EXPERIMENTAL_MULTI_ACCOUNT_ROTATION=1).',\n },\n };\n }\n warnings.push(ROTATION_TOS);\n }\n return { warnings };\n}\n\n// ---------------------------------------------------------------------------\n// Flags → AccountCreate\n// ---------------------------------------------------------------------------\n\nexport interface AddFlags {\n provider?: string;\n label?: string;\n priority?: number;\n weight?: number;\n /** Discouraged: visible in shell history and process listings. */\n secret?: string;\n /** Read the secret from this environment variable. */\n secretEnv?: string;\n /** Read the secret from stdin. */\n secretStdin?: boolean;\n baseUrl?: string;\n model?: string[];\n defaultModel?: string;\n binaryPath?: string;\n /** `key=value` quota limits, e.g. `tokens5h=500000`. */\n limit?: string[];\n /** commander's `--disabled`. */\n disabled?: boolean;\n}\n\nconst LIMIT_KEYS = [\n 'tpm',\n 'rpm',\n 'tokens5h',\n 'requests5h',\n 'tokensDaily',\n 'requestsDaily',\n] as const;\n\nexport function parseLimits(pairs: string[] = []): QuotaLimits {\n const limits: QuotaLimits = {};\n for (const pair of pairs) {\n const [rawKey, rawValue] = pair.split('=', 2);\n const key = LIMIT_KEYS.find((k) => k.toLowerCase() === rawKey?.trim().toLowerCase());\n const value = Number(rawValue);\n if (!key) {\n throw new CliError(`Unknown limit ${JSON.stringify(rawKey)}`, {\n hint: `Use one of: ${LIMIT_KEYS.join(', ')} (e.g. --limit tokens5h=500000)`,\n });\n }\n if (!Number.isInteger(value) || value <= 0) {\n throw new CliError(\n `Limit ${key} must be a positive integer, got ${JSON.stringify(rawValue)}`,\n );\n }\n limits[key] = value;\n }\n return limits;\n}\n\nexport function validateUrl(value: string): string | undefined {\n try {\n const url = new URL(value);\n return url.protocol === 'http:' || url.protocol === 'https:'\n ? undefined\n : 'must be an http(s) URL';\n } catch {\n return 'must be a valid URL, e.g. http://localhost:11434/v1';\n }\n}\n\nfunction requireProvider(value: string | undefined): ProviderInfo {\n if (!value) {\n throw new CliError('Missing --provider', {\n hint: `One of: ${PROVIDERS.map((p) => p.kind).join(', ')}`,\n });\n }\n const info = providerInfo(value);\n if (!info) {\n throw new CliError(`Unknown provider ${JSON.stringify(value)}`, {\n hint: `One of: ${PROVIDERS.map((p) => p.kind).join(', ')}`,\n });\n }\n return info;\n}\n\nexport interface SecretSources {\n env: NodeJS.ProcessEnv;\n readStdin: () => Promise<string>;\n}\n\nasync function secretFromFlags(\n flags: AddFlags,\n sources: SecretSources,\n): Promise<string | undefined> {\n const chosen = [flags.secret !== undefined, !!flags.secretEnv, !!flags.secretStdin].filter(\n Boolean,\n );\n if (chosen.length > 1) {\n throw new CliError('Use only one of --secret, --secret-env and --secret-stdin');\n }\n if (flags.secretStdin) {\n const value = (await sources.readStdin()).trim();\n if (!value) throw new CliError('No secret received on stdin');\n return value;\n }\n if (flags.secretEnv) {\n const value = sources.env[flags.secretEnv]?.trim();\n if (!value) throw new CliError(`Environment variable ${flags.secretEnv} is empty or unset`);\n return value;\n }\n const value = flags.secret?.trim();\n return value ? value : undefined;\n}\n\nfunction providerConfig(\n info: ProviderInfo,\n values: { baseUrl?: string; models?: string[]; defaultModel?: string; binaryPath?: string },\n): Record<string, unknown> {\n const config: Record<string, unknown> = {};\n if (values.baseUrl) config.baseUrl = values.baseUrl.replace(/\\/+$/, '');\n if (values.models && values.models.length > 0) config.models = [...new Set(values.models)];\n if (values.defaultModel) config.defaultModel = values.defaultModel;\n if (values.binaryPath && info.auth === 'cli-login') config.binaryPath = values.binaryPath;\n return config;\n}\n\n/** Build an account from flags only (scripts, CI). Never prompts. */\nexport async function accountFromFlags(\n flags: AddFlags,\n sources: SecretSources,\n): Promise<AccountCreate> {\n const info = requireProvider(flags.provider);\n const secret = await secretFromFlags(flags, sources);\n if (info.auth === 'api-key' && !secret) {\n throw new CliError(`${info.name} needs an API key`, {\n hint: 'Pass it with --secret-env <VAR> or pipe it with --secret-stdin.',\n });\n }\n if (secret && (info.auth === 'cli-login' || info.auth === 'browser')) {\n throw new CliError(`${info.kind} accounts do not take a secret`, {\n hint:\n info.auth === 'cli-login'\n ? 'Log in with `davecode accounts login <id>` after adding the account.'\n : 'The browser profile holds the session.',\n });\n }\n if (info.kind === 'openai-compatible') {\n if (!flags.baseUrl) {\n throw new CliError('openai-compatible accounts need --base-url', {\n hint: `e.g. --base-url ${DEFAULT_COMPATIBLE_URL} for OpenRouter`,\n });\n }\n }\n if (flags.baseUrl) {\n const problem = validateUrl(flags.baseUrl);\n if (problem) throw new CliError(`--base-url ${problem}`);\n }\n const create: AccountCreate = {\n provider: info.kind,\n label: flags.label?.trim() || info.defaultLabel,\n config: providerConfig(info, {\n ...(flags.baseUrl ? { baseUrl: flags.baseUrl } : {}),\n ...(flags.model ? { models: flags.model } : {}),\n ...(flags.defaultModel ? { defaultModel: flags.defaultModel } : {}),\n ...(flags.binaryPath ? { binaryPath: flags.binaryPath } : {}),\n }),\n };\n if (flags.priority !== undefined) create.priority = flags.priority;\n if (flags.weight !== undefined) create.weight = flags.weight;\n const limits = parseLimits(flags.limit);\n if (Object.keys(limits).length > 0) create.limits = limits;\n if (flags.disabled) create.enabled = false;\n if (secret) create.secret = secret;\n return create;\n}\n\n// ---------------------------------------------------------------------------\n// Interactive flow\n// ---------------------------------------------------------------------------\n\nexport interface InteractiveDeps {\n prompter: Prompter;\n config: Pick<DaveConfig, 'experimental'>;\n existing: Pick<Account, 'provider' | 'label'>[];\n /** Print a line (warnings, summary). */\n say: (line: string) => void;\n /** Style ToS warnings. */\n warn?: (text: string) => string;\n}\n\nfunction uniqueLabel(base: string, existing: Pick<Account, 'label'>[]): string {\n const taken = new Set(existing.map((a) => a.label.toLowerCase()));\n if (!taken.has(base.toLowerCase())) return base;\n for (let n = 2; ; n++) {\n const candidate = `${base} ${n}`;\n if (!taken.has(candidate.toLowerCase())) return candidate;\n }\n}\n\n/**\n * Ask for whatever the flags did not provide. Returns `undefined` when the user declines a\n * Terms-of-Service warning or the final confirmation.\n */\nexport async function accountInteractively(\n flags: AddFlags,\n deps: InteractiveDeps,\n): Promise<AccountCreate | undefined> {\n const { prompter, say } = deps;\n const warn = deps.warn ?? ((t: string) => t);\n\n const kind = flags.provider\n ? requireProvider(flags.provider).kind\n : await prompter.select(\n 'Provider',\n PROVIDERS.map((p) => ({ value: p.kind, label: p.name, hint: authHint(p.auth) })),\n 'anthropic',\n );\n const info = requireProvider(kind);\n\n const policy = accountPolicy(info.kind, deps.config, deps.existing);\n if (policy.blocked) throw new CliError(policy.blocked.message, { hint: policy.blocked.hint });\n for (const warning of policy.warnings) {\n say(warn(`! ${warning}`));\n if (!(await prompter.confirm('I understand the risk. Continue?', false))) return undefined;\n }\n\n const label =\n flags.label?.trim() ||\n (await prompter.text('Label', {\n initial: uniqueLabel(info.defaultLabel, deps.existing),\n validate: (v) => (v.trim() ? undefined : 'a label is required'),\n }));\n\n const priority =\n flags.priority ??\n Number(\n await prompter.text('Priority (lower is tried first)', {\n initial: '100',\n validate: (v) => (/^\\d+$/.test(v.trim()) ? undefined : 'enter a non-negative integer'),\n }),\n );\n\n let baseUrl = flags.baseUrl;\n let models = flags.model;\n if (info.kind === 'openai-compatible') {\n baseUrl ??= await prompter.text('Base URL', {\n initial: DEFAULT_COMPATIBLE_URL,\n validate: validateUrl,\n });\n if (!models) {\n const answer = await prompter.text('Models (comma-separated, empty to discover)', {\n initial: '',\n });\n models = answer\n .split(',')\n .map((m) => m.trim())\n .filter(Boolean);\n }\n }\n\n let secret: string | undefined;\n if (info.auth === 'api-key' || info.auth === 'optional-key') {\n const optional = info.auth === 'optional-key';\n const answer = await prompter.secret(\n optional ? 'API key (optional, input hidden)' : `${info.name} key (input hidden)`,\n { optional },\n );\n secret = answer.trim() || undefined;\n if (!secret && !optional) throw new CliError(`${info.name} needs an API key`);\n }\n\n const create: AccountCreate = {\n provider: info.kind,\n label: label.trim(),\n priority,\n config: providerConfig(info, {\n ...(baseUrl ? { baseUrl } : {}),\n ...(models ? { models } : {}),\n ...(flags.defaultModel ? { defaultModel: flags.defaultModel } : {}),\n ...(flags.binaryPath ? { binaryPath: flags.binaryPath } : {}),\n }),\n };\n if (flags.weight !== undefined) create.weight = flags.weight;\n const limits = parseLimits(flags.limit);\n if (Object.keys(limits).length > 0) create.limits = limits;\n if (flags.disabled) create.enabled = false;\n if (secret) create.secret = secret;\n\n say('');\n for (const line of describeCreate(create)) say(` ${line}`);\n say('');\n if (!(await prompter.confirm('Add this account?', true))) return undefined;\n return create;\n}\n\nfunction authHint(auth: AuthKind): string {\n switch (auth) {\n case 'api-key':\n return 'API key';\n case 'optional-key':\n return 'base URL, optional key';\n case 'cli-login':\n return 'local CLI login, isolated per account';\n default:\n return 'experimental, ToS risk';\n }\n}\n\n/** Summary lines for an account about to be created. Secrets are shown only as \"set\". */\nexport function describeCreate(create: AccountCreate): string[] {\n const lines = [\n `provider ${create.provider}`,\n `label ${create.label}`,\n `priority ${create.priority ?? 100}`,\n ];\n const config = create.config ?? {};\n if (typeof config.baseUrl === 'string') lines.push(`base URL ${config.baseUrl}`);\n if (Array.isArray(config.models) && config.models.length > 0) {\n lines.push(`models ${config.models.join(', ')}`);\n }\n if (create.limits && Object.keys(create.limits).length > 0) {\n lines.push(\n `limits ${Object.entries(create.limits)\n .map(([k, v]) => `${k}=${v}`)\n .join(' ')}`,\n );\n }\n if (create.secret !== undefined) lines.push('secret set (stored encrypted)');\n return lines;\n}\n"],"mappings":"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","names":["value","account"]}
@@ -1,95 +0,0 @@
1
- import {
2
- GatewayClient,
3
- detectProjectRoot,
4
- findGateway,
5
- startRuntime
6
- } from "./chunk-PIIJ3RSI.js";
7
- import {
8
- CliError,
9
- EXIT
10
- } from "./chunk-7XVXEO7U.js";
11
- import {
12
- VERSION,
13
- loadConfig
14
- } from "./chunk-C7FDRA3U.js";
15
-
16
- // src/commands/chat.ts
17
- import { resolve } from "path";
18
-
19
- // src/tui/backend.ts
20
- function httpBackend(client, inProcess) {
21
- return {
22
- url: client.baseUrl,
23
- inProcess,
24
- health: () => client.health(1500).catch(() => void 0),
25
- stream: (request, signal) => client.chatStream(request, signal),
26
- models: async () => (await client.get("/v1/models")).data,
27
- routes: () => client.get("/api/routes"),
28
- accounts: async () => (await client.get("/api/accounts")).accounts,
29
- usage: async () => (await client.get("/api/usage")).usage,
30
- tasks: () => client.get("/api/tasks"),
31
- runner: async () => (await client.get("/api/runner")).status
32
- };
33
- }
34
-
35
- // src/commands/chat.ts
36
- async function chatCommand(ctx, opts) {
37
- if (!ctx.io.stdin.isTTY || !ctx.io.stdout.isTTY) {
38
- throw new CliError("The chat TUI needs an interactive terminal", {
39
- hint: "For scripts, call the OpenAI-compatible API: POST http://127.0.0.1:4040/v1/chat/completions"
40
- });
41
- }
42
- const projectRoot = opts.project ? resolve(ctx.cwd, opts.project) : await detectProjectRoot(ctx.cwd, ctx.home);
43
- const config = loadConfig({
44
- home: ctx.home,
45
- env: ctx.env,
46
- ...projectRoot ? { projectRoot } : {}
47
- });
48
- let runtime;
49
- let backend;
50
- const running = await findGateway(config);
51
- if (running) {
52
- backend = httpBackend(running.client, false);
53
- } else {
54
- runtime = await startRuntime({
55
- home: ctx.home,
56
- env: ctx.env,
57
- cwd: ctx.cwd,
58
- host: "127.0.0.1",
59
- port: 0,
60
- dashboard: false,
61
- ...projectRoot ? { projectDir: projectRoot } : { noProject: true }
62
- });
63
- const target = config.server.authToken ? { baseUrl: runtime.url, token: config.server.authToken } : { baseUrl: runtime.url };
64
- backend = httpBackend(new GatewayClient(target), true);
65
- }
66
- try {
67
- const [{ render }, { createElement }, { ChatApp }] = await Promise.all([
68
- import("ink"),
69
- import("react"),
70
- import("./ChatApp-FO5SABXB.js")
71
- ]);
72
- const instance = render(
73
- createElement(ChatApp, {
74
- backend,
75
- theme: ctx.theme,
76
- model: opts.model ?? `davecode/${config.routing.defaultRoute}`,
77
- version: VERSION
78
- }),
79
- {
80
- stdout: ctx.io.stdout,
81
- stdin: process.stdin,
82
- exitOnCtrlC: false,
83
- kittyKeyboard: { mode: "auto", flags: ["disambiguateEscapeCodes"] }
84
- }
85
- );
86
- await instance.waitUntilExit();
87
- } finally {
88
- await runtime?.close();
89
- }
90
- return EXIT.ok;
91
- }
92
- export {
93
- chatCommand
94
- };
95
- //# sourceMappingURL=chat-ZDXX3N6X.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/chat.ts","../src/tui/backend.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { loadConfig, VERSION } from '@davecode/core';\nimport { findGateway, GatewayClient } from '../client';\nimport type { CliContext } from '../context';\nimport { CliError, EXIT } from '../errors';\nimport { detectProjectRoot, type Runtime, startRuntime } from '../runtime';\nimport { type ChatBackend, httpBackend } from '../tui/backend';\n\nexport interface ChatOptions {\n model?: string;\n project?: string;\n}\n\n/**\n * Open the chat TUI against the running gateway, or start an in-process gateway on an ephemeral\n * loopback port when none is running (it stops when the TUI exits).\n */\nexport async function chatCommand(ctx: CliContext, opts: ChatOptions): Promise<number> {\n if (!ctx.io.stdin.isTTY || !ctx.io.stdout.isTTY) {\n throw new CliError('The chat TUI needs an interactive terminal', {\n hint: 'For scripts, call the OpenAI-compatible API: POST http://127.0.0.1:4040/v1/chat/completions',\n });\n }\n const projectRoot = opts.project\n ? resolve(ctx.cwd, opts.project)\n : await detectProjectRoot(ctx.cwd, ctx.home);\n const config = loadConfig({\n home: ctx.home,\n env: ctx.env,\n ...(projectRoot ? { projectRoot } : {}),\n });\n\n let runtime: Runtime | undefined;\n let backend: ChatBackend;\n const running = await findGateway(config);\n if (running) {\n backend = httpBackend(running.client, false);\n } else {\n runtime = await startRuntime({\n home: ctx.home,\n env: ctx.env,\n cwd: ctx.cwd,\n host: '127.0.0.1',\n port: 0,\n dashboard: false,\n ...(projectRoot ? { projectDir: projectRoot } : { noProject: true }),\n });\n const target = config.server.authToken\n ? { baseUrl: runtime.url, token: config.server.authToken }\n : { baseUrl: runtime.url };\n backend = httpBackend(new GatewayClient(target), true);\n }\n\n try {\n const [{ render }, { createElement }, { ChatApp }] = await Promise.all([\n import('ink'),\n import('react'),\n import('../tui/ChatApp'),\n ]);\n const instance = render(\n createElement(ChatApp, {\n backend,\n theme: ctx.theme,\n model: opts.model ?? `davecode/${config.routing.defaultRoute}`,\n version: VERSION,\n }),\n {\n stdout: ctx.io.stdout as NodeJS.WriteStream,\n stdin: process.stdin,\n exitOnCtrlC: false,\n kittyKeyboard: { mode: 'auto', flags: ['disambiguateEscapeCodes'] },\n },\n );\n await instance.waitUntilExit();\n } finally {\n await runtime?.close();\n }\n return EXIT.ok;\n}\n","import type {\n Account,\n AccountUsage,\n ChatCompletionChunk,\n ChatRequest,\n ModelInfo,\n Route,\n RunnerStatus,\n TaskGraph,\n} from '@davecode/core';\nimport type { GatewayClient, HealthResponse, StreamMeta } from '../client';\n\n/** What the TUI needs from a gateway. Backed by HTTP in production and by fakes in tests. */\nexport interface ChatBackend {\n /** Base URL, e.g. `http://127.0.0.1:4040`. */\n url: string;\n /** The gateway was started inside this process (no `davecode start` running). */\n inProcess: boolean;\n health(): Promise<HealthResponse | undefined>;\n stream(\n request: ChatRequest,\n signal: AbortSignal,\n ): Promise<{ meta: StreamMeta; chunks: AsyncIterable<ChatCompletionChunk> }>;\n models(): Promise<ModelInfo[]>;\n routes(): Promise<{ defaultRoute: string; routes: Route[] }>;\n accounts(): Promise<Account[]>;\n usage(): Promise<AccountUsage[]>;\n tasks(): Promise<{ project: { root: string; name: string } | null; graph: TaskGraph }>;\n runner(): Promise<RunnerStatus>;\n}\n\nexport function httpBackend(client: GatewayClient, inProcess: boolean): ChatBackend {\n return {\n url: client.baseUrl,\n inProcess,\n health: () => client.health(1500).catch(() => undefined),\n stream: (request, signal) => client.chatStream(request, signal),\n models: async () => (await client.get<{ data: ModelInfo[] }>('/v1/models')).data,\n routes: () => client.get('/api/routes'),\n accounts: async () => (await client.get<{ accounts: Account[] }>('/api/accounts')).accounts,\n usage: async () => (await client.get<{ usage: AccountUsage[] }>('/api/usage')).usage,\n tasks: () => client.get('/api/tasks'),\n runner: async () => (await client.get<{ status: RunnerStatus }>('/api/runner')).status,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA,SAAS,eAAe;;;AC+BjB,SAAS,YAAY,QAAuB,WAAiC;AAClF,SAAO;AAAA,IACL,KAAK,OAAO;AAAA,IACZ;AAAA,IACA,QAAQ,MAAM,OAAO,OAAO,IAAI,EAAE,MAAM,MAAM,MAAS;AAAA,IACvD,QAAQ,CAAC,SAAS,WAAW,OAAO,WAAW,SAAS,MAAM;AAAA,IAC9D,QAAQ,aAAa,MAAM,OAAO,IAA2B,YAAY,GAAG;AAAA,IAC5E,QAAQ,MAAM,OAAO,IAAI,aAAa;AAAA,IACtC,UAAU,aAAa,MAAM,OAAO,IAA6B,eAAe,GAAG;AAAA,IACnF,OAAO,aAAa,MAAM,OAAO,IAA+B,YAAY,GAAG;AAAA,IAC/E,OAAO,MAAM,OAAO,IAAI,YAAY;AAAA,IACpC,QAAQ,aAAa,MAAM,OAAO,IAA8B,aAAa,GAAG;AAAA,EAClF;AACF;;;AD3BA,eAAsB,YAAY,KAAiB,MAAoC;AACrF,MAAI,CAAC,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,GAAG,OAAO,OAAO;AAC/C,UAAM,IAAI,SAAS,8CAA8C;AAAA,MAC/D,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AACA,QAAM,cAAc,KAAK,UACrB,QAAQ,IAAI,KAAK,KAAK,OAAO,IAC7B,MAAM,kBAAkB,IAAI,KAAK,IAAI,IAAI;AAC7C,QAAM,SAAS,WAAW;AAAA,IACxB,MAAM,IAAI;AAAA,IACV,KAAK,IAAI;AAAA,IACT,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,EACvC,CAAC;AAED,MAAI;AACJ,MAAI;AACJ,QAAM,UAAU,MAAM,YAAY,MAAM;AACxC,MAAI,SAAS;AACX,cAAU,YAAY,QAAQ,QAAQ,KAAK;AAAA,EAC7C,OAAO;AACL,cAAU,MAAM,aAAa;AAAA,MAC3B,MAAM,IAAI;AAAA,MACV,KAAK,IAAI;AAAA,MACT,KAAK,IAAI;AAAA,MACT,MAAM;AAAA,MACN,MAAM;AAAA,MACN,WAAW;AAAA,MACX,GAAI,cAAc,EAAE,YAAY,YAAY,IAAI,EAAE,WAAW,KAAK;AAAA,IACpE,CAAC;AACD,UAAM,SAAS,OAAO,OAAO,YACzB,EAAE,SAAS,QAAQ,KAAK,OAAO,OAAO,OAAO,UAAU,IACvD,EAAE,SAAS,QAAQ,IAAI;AAC3B,cAAU,YAAY,IAAI,cAAc,MAAM,GAAG,IAAI;AAAA,EACvD;AAEA,MAAI;AACF,UAAM,CAAC,EAAE,OAAO,GAAG,EAAE,cAAc,GAAG,EAAE,QAAQ,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,MACrE,OAAO,KAAK;AAAA,MACZ,OAAO,OAAO;AAAA,MACd,OAAO,uBAAgB;AAAA,IACzB,CAAC;AACD,UAAM,WAAW;AAAA,MACf,cAAc,SAAS;AAAA,QACrB;AAAA,QACA,OAAO,IAAI;AAAA,QACX,OAAO,KAAK,SAAS,YAAY,OAAO,QAAQ,YAAY;AAAA,QAC5D,SAAS;AAAA,MACX,CAAC;AAAA,MACD;AAAA,QACE,QAAQ,IAAI,GAAG;AAAA,QACf,OAAO,QAAQ;AAAA,QACf,aAAa;AAAA,QACb,eAAe,EAAE,MAAM,QAAQ,OAAO,CAAC,yBAAyB,EAAE;AAAA,MACpE;AAAA,IACF;AACA,UAAM,SAAS,cAAc;AAAA,EAC/B,UAAE;AACA,UAAM,SAAS,MAAM;AAAA,EACvB;AACA,SAAO,KAAK;AACd;","names":[]}