@butlerw/vellum 0.1.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 (446) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +411 -0
  3. package/__fixtures__/responses/code-generation.json +42 -0
  4. package/__fixtures__/responses/error-response.json +20 -0
  5. package/__fixtures__/responses/hello-world.json +32 -0
  6. package/dist/auth-6MCXESOH.js +26 -0
  7. package/dist/chunk-SECXJGWA.js +597 -0
  8. package/dist/index.js +34023 -0
  9. package/package.json +67 -0
  10. package/src/__tests__/commands.e2e.test.ts +728 -0
  11. package/src/__tests__/credentials.test.ts +713 -0
  12. package/src/__tests__/mode-e2e.test.ts +391 -0
  13. package/src/__tests__/tui-integration.test.tsx +1271 -0
  14. package/src/agents/__tests__/task-persistence.test.ts +235 -0
  15. package/src/agents/commands/delegate.ts +240 -0
  16. package/src/agents/commands/index.ts +10 -0
  17. package/src/agents/commands/resume.ts +335 -0
  18. package/src/agents/index.ts +29 -0
  19. package/src/agents/task-persistence.ts +272 -0
  20. package/src/agents/task-resumption.ts +242 -0
  21. package/src/app.tsx +4737 -0
  22. package/src/commands/__tests__/.gitkeep +1 -0
  23. package/src/commands/__tests__/agents.test.ts +606 -0
  24. package/src/commands/__tests__/auth.test.ts +626 -0
  25. package/src/commands/__tests__/autocomplete.test.ts +683 -0
  26. package/src/commands/__tests__/batch.test.ts +287 -0
  27. package/src/commands/__tests__/chain-pipe-parser.test.ts +654 -0
  28. package/src/commands/__tests__/completion.test.ts +238 -0
  29. package/src/commands/__tests__/core.test.ts +363 -0
  30. package/src/commands/__tests__/executor.test.ts +496 -0
  31. package/src/commands/__tests__/exit-codes.test.ts +220 -0
  32. package/src/commands/__tests__/init.test.ts +243 -0
  33. package/src/commands/__tests__/language.test.ts +353 -0
  34. package/src/commands/__tests__/mode-cli.test.ts +667 -0
  35. package/src/commands/__tests__/model.test.ts +277 -0
  36. package/src/commands/__tests__/parser.test.ts +493 -0
  37. package/src/commands/__tests__/performance.bench.ts +380 -0
  38. package/src/commands/__tests__/registry.test.ts +534 -0
  39. package/src/commands/__tests__/resume.test.ts +449 -0
  40. package/src/commands/__tests__/security.test.ts +845 -0
  41. package/src/commands/__tests__/stream-json.test.ts +372 -0
  42. package/src/commands/__tests__/user-commands.test.ts +597 -0
  43. package/src/commands/adapters.ts +267 -0
  44. package/src/commands/agent.ts +395 -0
  45. package/src/commands/agents/generate.ts +506 -0
  46. package/src/commands/agents/index.ts +272 -0
  47. package/src/commands/agents/show.ts +271 -0
  48. package/src/commands/agents/validate.ts +387 -0
  49. package/src/commands/auth.ts +883 -0
  50. package/src/commands/autocomplete.ts +480 -0
  51. package/src/commands/batch/command.ts +388 -0
  52. package/src/commands/batch/executor.ts +361 -0
  53. package/src/commands/batch/index.ts +12 -0
  54. package/src/commands/commit.ts +235 -0
  55. package/src/commands/completion/index.ts +371 -0
  56. package/src/commands/condense.ts +191 -0
  57. package/src/commands/config.ts +344 -0
  58. package/src/commands/context-provider.ts +173 -0
  59. package/src/commands/copy.ts +329 -0
  60. package/src/commands/core/clear.ts +38 -0
  61. package/src/commands/core/exit.ts +43 -0
  62. package/src/commands/core/help.ts +354 -0
  63. package/src/commands/core/index.ts +15 -0
  64. package/src/commands/cost.ts +179 -0
  65. package/src/commands/credentials.tsx +618 -0
  66. package/src/commands/custom-agents/__tests__/custom-agents.test.ts +709 -0
  67. package/src/commands/custom-agents/create.ts +377 -0
  68. package/src/commands/custom-agents/export.ts +135 -0
  69. package/src/commands/custom-agents/import.ts +199 -0
  70. package/src/commands/custom-agents/index.ts +372 -0
  71. package/src/commands/custom-agents/info.ts +318 -0
  72. package/src/commands/custom-agents/list.ts +267 -0
  73. package/src/commands/custom-agents/validate.ts +388 -0
  74. package/src/commands/diff-mode.ts +241 -0
  75. package/src/commands/env.ts +53 -0
  76. package/src/commands/executor.ts +579 -0
  77. package/src/commands/exit-codes.ts +202 -0
  78. package/src/commands/index.ts +701 -0
  79. package/src/commands/init/index.ts +15 -0
  80. package/src/commands/init/prompts.ts +366 -0
  81. package/src/commands/init/templates/commands-readme.md +80 -0
  82. package/src/commands/init/templates/example-command.md +79 -0
  83. package/src/commands/init/templates/example-skill.md +168 -0
  84. package/src/commands/init/templates/example-workflow.md +101 -0
  85. package/src/commands/init/templates/prompts-readme.md +52 -0
  86. package/src/commands/init/templates/rules-readme.md +63 -0
  87. package/src/commands/init/templates/skills-readme.md +83 -0
  88. package/src/commands/init/templates/workflows-readme.md +94 -0
  89. package/src/commands/init.ts +391 -0
  90. package/src/commands/install.ts +90 -0
  91. package/src/commands/language.ts +191 -0
  92. package/src/commands/loaders/.gitkeep +1 -0
  93. package/src/commands/lsp.ts +199 -0
  94. package/src/commands/markdown-commands.ts +253 -0
  95. package/src/commands/mcp.ts +588 -0
  96. package/src/commands/memory/export.ts +341 -0
  97. package/src/commands/memory/index.ts +148 -0
  98. package/src/commands/memory/list.ts +261 -0
  99. package/src/commands/memory/search.ts +346 -0
  100. package/src/commands/memory/utils.ts +15 -0
  101. package/src/commands/metrics.ts +75 -0
  102. package/src/commands/migrate/index.ts +16 -0
  103. package/src/commands/migrate/prompts.ts +477 -0
  104. package/src/commands/mode.ts +331 -0
  105. package/src/commands/model.ts +298 -0
  106. package/src/commands/onboard.ts +205 -0
  107. package/src/commands/open.ts +169 -0
  108. package/src/commands/output/stream-json.ts +373 -0
  109. package/src/commands/parser/chain-parser.ts +370 -0
  110. package/src/commands/parser/index.ts +29 -0
  111. package/src/commands/parser/pipe-parser.ts +480 -0
  112. package/src/commands/parser.ts +588 -0
  113. package/src/commands/persistence.ts +355 -0
  114. package/src/commands/progress.ts +18 -0
  115. package/src/commands/prompt/index.ts +17 -0
  116. package/src/commands/prompt/validate.ts +621 -0
  117. package/src/commands/prompt-priority.ts +401 -0
  118. package/src/commands/registry.ts +374 -0
  119. package/src/commands/sandbox/index.ts +131 -0
  120. package/src/commands/security/index.ts +21 -0
  121. package/src/commands/security/input-sanitizer.ts +168 -0
  122. package/src/commands/security/permission-checker.ts +456 -0
  123. package/src/commands/security/sensitive-data.ts +350 -0
  124. package/src/commands/session/delete.ts +38 -0
  125. package/src/commands/session/export.ts +39 -0
  126. package/src/commands/session/index.ts +26 -0
  127. package/src/commands/session/list.ts +26 -0
  128. package/src/commands/session/resume.ts +562 -0
  129. package/src/commands/session/search.ts +434 -0
  130. package/src/commands/session/show.ts +26 -0
  131. package/src/commands/settings.ts +368 -0
  132. package/src/commands/setup.ts +23 -0
  133. package/src/commands/shell/index.ts +16 -0
  134. package/src/commands/shell/setup.ts +422 -0
  135. package/src/commands/shell-init.ts +50 -0
  136. package/src/commands/shell-integration/index.ts +194 -0
  137. package/src/commands/skill.ts +1220 -0
  138. package/src/commands/spec.ts +558 -0
  139. package/src/commands/status.ts +246 -0
  140. package/src/commands/theme.ts +211 -0
  141. package/src/commands/think.ts +551 -0
  142. package/src/commands/trust.ts +211 -0
  143. package/src/commands/tutorial.ts +522 -0
  144. package/src/commands/types.ts +512 -0
  145. package/src/commands/update.ts +274 -0
  146. package/src/commands/usage.ts +213 -0
  147. package/src/commands/user-commands.ts +630 -0
  148. package/src/commands/utils.ts +142 -0
  149. package/src/commands/vim.ts +152 -0
  150. package/src/commands/workflow.ts +257 -0
  151. package/src/components/header.tsx +25 -0
  152. package/src/components/input.tsx +25 -0
  153. package/src/components/message-list.tsx +32 -0
  154. package/src/components/status-bar.tsx +23 -0
  155. package/src/index.tsx +614 -0
  156. package/src/onboarding/__tests__/tutorial.test.ts +740 -0
  157. package/src/onboarding/index.ts +69 -0
  158. package/src/onboarding/tips/index.ts +9 -0
  159. package/src/onboarding/tips/tip-engine.ts +459 -0
  160. package/src/onboarding/tutorial/index.ts +88 -0
  161. package/src/onboarding/tutorial/lessons/basics.ts +151 -0
  162. package/src/onboarding/tutorial/lessons/index.ts +151 -0
  163. package/src/onboarding/tutorial/lessons/modes.ts +230 -0
  164. package/src/onboarding/tutorial/lessons/tools.ts +172 -0
  165. package/src/onboarding/tutorial/progress-tracker.ts +350 -0
  166. package/src/onboarding/tutorial/storage.ts +249 -0
  167. package/src/onboarding/tutorial/tutorial-system.ts +462 -0
  168. package/src/onboarding/tutorial/types.ts +310 -0
  169. package/src/orchestrator-singleton.ts +129 -0
  170. package/src/shutdown.ts +33 -0
  171. package/src/test/e2e/assertions.ts +267 -0
  172. package/src/test/e2e/fixtures.ts +204 -0
  173. package/src/test/e2e/harness.ts +575 -0
  174. package/src/test/e2e/index.ts +57 -0
  175. package/src/test/e2e/types.ts +228 -0
  176. package/src/test/fixtures/__tests__/fake-response-loader.test.ts +314 -0
  177. package/src/test/fixtures/fake-response-loader.ts +314 -0
  178. package/src/test/fixtures/index.ts +20 -0
  179. package/src/tui/__tests__/mcp-panel.test.tsx +82 -0
  180. package/src/tui/__tests__/mcp-wiring.test.tsx +78 -0
  181. package/src/tui/__tests__/mode-components.test.tsx +395 -0
  182. package/src/tui/__tests__/permission-ask-flow.test.tsx +138 -0
  183. package/src/tui/__tests__/sidebar-panel-data.test.tsx +148 -0
  184. package/src/tui/__tests__/tools-panel-hotkeys.test.tsx +41 -0
  185. package/src/tui/adapters/agent-adapter.ts +1008 -0
  186. package/src/tui/adapters/index.ts +48 -0
  187. package/src/tui/adapters/message-adapter.ts +315 -0
  188. package/src/tui/adapters/persistence-bridge.ts +331 -0
  189. package/src/tui/adapters/session-adapter.ts +419 -0
  190. package/src/tui/buffered-stdout.ts +223 -0
  191. package/src/tui/components/AgentProgress.tsx +424 -0
  192. package/src/tui/components/Banner/AsciiArt.ts +160 -0
  193. package/src/tui/components/Banner/Banner.tsx +355 -0
  194. package/src/tui/components/Banner/ShimmerContext.tsx +131 -0
  195. package/src/tui/components/Banner/ShimmerText.tsx +193 -0
  196. package/src/tui/components/Banner/TypeWriterGradient.tsx +321 -0
  197. package/src/tui/components/Banner/index.ts +61 -0
  198. package/src/tui/components/Banner/useShimmer.ts +241 -0
  199. package/src/tui/components/ChatView.tsx +11 -0
  200. package/src/tui/components/Checkpoint/CheckpointDiffView.tsx +371 -0
  201. package/src/tui/components/Checkpoint/SnapshotCheckpointPanel.tsx +440 -0
  202. package/src/tui/components/Checkpoint/index.ts +19 -0
  203. package/src/tui/components/CostDisplay.tsx +226 -0
  204. package/src/tui/components/InitErrorBanner.tsx +122 -0
  205. package/src/tui/components/Input/Autocomplete.tsx +603 -0
  206. package/src/tui/components/Input/EnhancedCommandInput.tsx +471 -0
  207. package/src/tui/components/Input/HighlightedText.tsx +236 -0
  208. package/src/tui/components/Input/MentionAutocomplete.tsx +375 -0
  209. package/src/tui/components/Input/TextInput.tsx +1002 -0
  210. package/src/tui/components/Input/__tests__/Autocomplete.test.tsx +374 -0
  211. package/src/tui/components/Input/__tests__/TextInput.test.tsx +241 -0
  212. package/src/tui/components/Input/__tests__/highlight.test.ts +219 -0
  213. package/src/tui/components/Input/__tests__/slash-command-utils.test.ts +104 -0
  214. package/src/tui/components/Input/highlight.ts +362 -0
  215. package/src/tui/components/Input/index.ts +36 -0
  216. package/src/tui/components/Input/slash-command-utils.ts +135 -0
  217. package/src/tui/components/Layout.tsx +432 -0
  218. package/src/tui/components/McpPanel.tsx +137 -0
  219. package/src/tui/components/MemoryPanel.tsx +448 -0
  220. package/src/tui/components/Messages/CodeBlock.tsx +527 -0
  221. package/src/tui/components/Messages/DiffView.tsx +679 -0
  222. package/src/tui/components/Messages/ImageReference.tsx +89 -0
  223. package/src/tui/components/Messages/MarkdownBlock.tsx +228 -0
  224. package/src/tui/components/Messages/MarkdownRenderer.tsx +498 -0
  225. package/src/tui/components/Messages/MessageBubble.tsx +270 -0
  226. package/src/tui/components/Messages/MessageList.tsx +1719 -0
  227. package/src/tui/components/Messages/StreamingText.tsx +216 -0
  228. package/src/tui/components/Messages/ThinkingBlock.tsx +408 -0
  229. package/src/tui/components/Messages/ToolResultPreview.tsx +243 -0
  230. package/src/tui/components/Messages/__tests__/CodeBlock.test.tsx +296 -0
  231. package/src/tui/components/Messages/__tests__/DiffView.test.tsx +239 -0
  232. package/src/tui/components/Messages/__tests__/MarkdownRenderer.test.tsx +303 -0
  233. package/src/tui/components/Messages/__tests__/MessageBubble.test.tsx +268 -0
  234. package/src/tui/components/Messages/__tests__/MessageList.test.tsx +324 -0
  235. package/src/tui/components/Messages/__tests__/StreamingText.test.tsx +215 -0
  236. package/src/tui/components/Messages/index.ts +25 -0
  237. package/src/tui/components/ModeIndicator.tsx +177 -0
  238. package/src/tui/components/ModeSelector.tsx +216 -0
  239. package/src/tui/components/ModelSelector.tsx +339 -0
  240. package/src/tui/components/OnboardingWizard.tsx +670 -0
  241. package/src/tui/components/PhaseProgressIndicator.tsx +270 -0
  242. package/src/tui/components/RateLimitIndicator.tsx +82 -0
  243. package/src/tui/components/ScreenReaderLayout.tsx +295 -0
  244. package/src/tui/components/SettingsPanel.tsx +643 -0
  245. package/src/tui/components/Sidebar/SystemStatusPanel.tsx +284 -0
  246. package/src/tui/components/Sidebar/index.ts +9 -0
  247. package/src/tui/components/Status/ModelStatusBar.tsx +270 -0
  248. package/src/tui/components/Status/index.ts +12 -0
  249. package/src/tui/components/StatusBar/AgentModeIndicator.tsx +257 -0
  250. package/src/tui/components/StatusBar/ContextProgress.tsx +167 -0
  251. package/src/tui/components/StatusBar/FileChangesIndicator.tsx +62 -0
  252. package/src/tui/components/StatusBar/GitIndicator.tsx +89 -0
  253. package/src/tui/components/StatusBar/HeaderBar.tsx +126 -0
  254. package/src/tui/components/StatusBar/ModelIndicator.tsx +157 -0
  255. package/src/tui/components/StatusBar/PersistenceStatusIndicator.tsx +210 -0
  256. package/src/tui/components/StatusBar/ResilienceIndicator.tsx +106 -0
  257. package/src/tui/components/StatusBar/SandboxIndicator.tsx +167 -0
  258. package/src/tui/components/StatusBar/StatusBar.tsx +368 -0
  259. package/src/tui/components/StatusBar/ThinkingModeIndicator.tsx +170 -0
  260. package/src/tui/components/StatusBar/TokenBreakdown.tsx +246 -0
  261. package/src/tui/components/StatusBar/TokenCounter.tsx +135 -0
  262. package/src/tui/components/StatusBar/TrustModeIndicator.tsx +130 -0
  263. package/src/tui/components/StatusBar/WorkspaceIndicator.tsx +86 -0
  264. package/src/tui/components/StatusBar/__tests__/AgentModeIndicator.test.tsx +193 -0
  265. package/src/tui/components/StatusBar/__tests__/StatusBar.test.tsx +729 -0
  266. package/src/tui/components/StatusBar/index.ts +60 -0
  267. package/src/tui/components/TipBanner.tsx +115 -0
  268. package/src/tui/components/TodoItem.tsx +208 -0
  269. package/src/tui/components/TodoPanel.tsx +455 -0
  270. package/src/tui/components/Tools/ApprovalQueue.tsx +407 -0
  271. package/src/tui/components/Tools/OptionSelector.tsx +160 -0
  272. package/src/tui/components/Tools/PermissionDialog.tsx +286 -0
  273. package/src/tui/components/Tools/ToolParams.tsx +483 -0
  274. package/src/tui/components/Tools/ToolsPanel.tsx +178 -0
  275. package/src/tui/components/Tools/__tests__/PermissionDialog.test.tsx +510 -0
  276. package/src/tui/components/Tools/__tests__/ToolParams.test.tsx +432 -0
  277. package/src/tui/components/Tools/index.ts +21 -0
  278. package/src/tui/components/TrustPrompt.tsx +279 -0
  279. package/src/tui/components/UpdateBanner.tsx +166 -0
  280. package/src/tui/components/VimModeIndicator.tsx +112 -0
  281. package/src/tui/components/backtrack/BacktrackControls.tsx +402 -0
  282. package/src/tui/components/backtrack/index.ts +13 -0
  283. package/src/tui/components/common/AutoApprovalStatus.tsx +251 -0
  284. package/src/tui/components/common/CostWarning.tsx +294 -0
  285. package/src/tui/components/common/DynamicShortcutHints.tsx +209 -0
  286. package/src/tui/components/common/EnhancedLoadingIndicator.tsx +305 -0
  287. package/src/tui/components/common/ErrorBoundary.tsx +140 -0
  288. package/src/tui/components/common/GradientText.tsx +224 -0
  289. package/src/tui/components/common/HotkeyHelpModal.tsx +193 -0
  290. package/src/tui/components/common/HotkeyHints.tsx +70 -0
  291. package/src/tui/components/common/MaxSizedBox.tsx +354 -0
  292. package/src/tui/components/common/NewMessagesBadge.tsx +65 -0
  293. package/src/tui/components/common/ProtectedFileLegend.tsx +89 -0
  294. package/src/tui/components/common/ScrollIndicator.tsx +160 -0
  295. package/src/tui/components/common/Spinner.tsx +342 -0
  296. package/src/tui/components/common/StreamingIndicator.tsx +316 -0
  297. package/src/tui/components/common/VirtualizedList/VirtualizedList.tsx +428 -0
  298. package/src/tui/components/common/VirtualizedList/hooks/index.ts +19 -0
  299. package/src/tui/components/common/VirtualizedList/hooks/useBatchedScroll.ts +64 -0
  300. package/src/tui/components/common/VirtualizedList/hooks/useScrollAnchor.ts +290 -0
  301. package/src/tui/components/common/VirtualizedList/hooks/useVirtualization.ts +340 -0
  302. package/src/tui/components/common/VirtualizedList/index.ts +30 -0
  303. package/src/tui/components/common/VirtualizedList/types.ts +107 -0
  304. package/src/tui/components/common/__tests__/NewMessagesBadge.test.tsx +74 -0
  305. package/src/tui/components/common/__tests__/ScrollIndicator.test.tsx +193 -0
  306. package/src/tui/components/common/index.ts +110 -0
  307. package/src/tui/components/index.ts +79 -0
  308. package/src/tui/components/session/CheckpointPanel.tsx +323 -0
  309. package/src/tui/components/session/RollbackDialog.tsx +169 -0
  310. package/src/tui/components/session/SessionItem.tsx +136 -0
  311. package/src/tui/components/session/SessionListPanel.tsx +252 -0
  312. package/src/tui/components/session/SessionPicker.tsx +449 -0
  313. package/src/tui/components/session/SessionPreview.tsx +240 -0
  314. package/src/tui/components/session/__tests__/session.test.tsx +408 -0
  315. package/src/tui/components/session/index.ts +28 -0
  316. package/src/tui/components/session/types.ts +116 -0
  317. package/src/tui/components/theme/__tests__/tokens.test.ts +471 -0
  318. package/src/tui/components/theme/index.ts +227 -0
  319. package/src/tui/components/theme/tokens.ts +484 -0
  320. package/src/tui/config/defaults.ts +134 -0
  321. package/src/tui/config/index.ts +17 -0
  322. package/src/tui/context/AnimationContext.tsx +284 -0
  323. package/src/tui/context/AppContext.tsx +349 -0
  324. package/src/tui/context/BracketedPasteContext.tsx +372 -0
  325. package/src/tui/context/LspContext.tsx +192 -0
  326. package/src/tui/context/McpContext.tsx +325 -0
  327. package/src/tui/context/MessagesContext.tsx +870 -0
  328. package/src/tui/context/OverflowContext.tsx +213 -0
  329. package/src/tui/context/RateLimitContext.tsx +108 -0
  330. package/src/tui/context/ResilienceContext.tsx +275 -0
  331. package/src/tui/context/RootProvider.tsx +136 -0
  332. package/src/tui/context/ScrollContext.tsx +331 -0
  333. package/src/tui/context/ToolsContext.tsx +702 -0
  334. package/src/tui/context/__tests__/BracketedPasteContext.test.tsx +416 -0
  335. package/src/tui/context/index.ts +140 -0
  336. package/src/tui/enterprise-integration.ts +282 -0
  337. package/src/tui/hooks/__tests__/useBacktrack.test.tsx +138 -0
  338. package/src/tui/hooks/__tests__/useBracketedPaste.test.tsx +222 -0
  339. package/src/tui/hooks/__tests__/useCopyMode.test.tsx +336 -0
  340. package/src/tui/hooks/__tests__/useHotkeys.ctrl-input.test.tsx +96 -0
  341. package/src/tui/hooks/__tests__/useHotkeys.test.tsx +454 -0
  342. package/src/tui/hooks/__tests__/useInputHistory.test.tsx +660 -0
  343. package/src/tui/hooks/__tests__/useLineBuffer.test.ts +295 -0
  344. package/src/tui/hooks/__tests__/useModeController.test.ts +137 -0
  345. package/src/tui/hooks/__tests__/useModeShortcuts.test.tsx +142 -0
  346. package/src/tui/hooks/__tests__/useScrollController.test.ts +464 -0
  347. package/src/tui/hooks/__tests__/useVim.test.tsx +531 -0
  348. package/src/tui/hooks/index.ts +252 -0
  349. package/src/tui/hooks/useAgentLoop.ts +712 -0
  350. package/src/tui/hooks/useAlternateBuffer.ts +398 -0
  351. package/src/tui/hooks/useAnimatedScrollbar.ts +241 -0
  352. package/src/tui/hooks/useBacktrack.ts +443 -0
  353. package/src/tui/hooks/useBracketedPaste.ts +104 -0
  354. package/src/tui/hooks/useCollapsible.ts +240 -0
  355. package/src/tui/hooks/useCopyMode.ts +382 -0
  356. package/src/tui/hooks/useCostSummary.ts +75 -0
  357. package/src/tui/hooks/useDesktopNotification.ts +414 -0
  358. package/src/tui/hooks/useDiffMode.ts +44 -0
  359. package/src/tui/hooks/useFileChangeStats.ts +110 -0
  360. package/src/tui/hooks/useFileSuggestions.ts +284 -0
  361. package/src/tui/hooks/useFlickerDetector.ts +250 -0
  362. package/src/tui/hooks/useGitStatus.ts +200 -0
  363. package/src/tui/hooks/useHotkeys.ts +579 -0
  364. package/src/tui/hooks/useImagePaste.ts +114 -0
  365. package/src/tui/hooks/useInputHighlight.ts +145 -0
  366. package/src/tui/hooks/useInputHistory.ts +246 -0
  367. package/src/tui/hooks/useKeyboardScroll.ts +209 -0
  368. package/src/tui/hooks/useLineBuffer.ts +356 -0
  369. package/src/tui/hooks/useMentionAutocomplete.ts +235 -0
  370. package/src/tui/hooks/useModeController.ts +167 -0
  371. package/src/tui/hooks/useModeShortcuts.ts +196 -0
  372. package/src/tui/hooks/usePermissionHandler.ts +146 -0
  373. package/src/tui/hooks/usePersistence.ts +480 -0
  374. package/src/tui/hooks/usePersistenceShortcuts.ts +225 -0
  375. package/src/tui/hooks/usePlaceholderRotation.ts +143 -0
  376. package/src/tui/hooks/useProviderStatus.ts +270 -0
  377. package/src/tui/hooks/useRateLimitStatus.ts +90 -0
  378. package/src/tui/hooks/useScreenReader.ts +315 -0
  379. package/src/tui/hooks/useScrollController.ts +450 -0
  380. package/src/tui/hooks/useScrollEventBatcher.ts +185 -0
  381. package/src/tui/hooks/useSidebarPanelData.ts +115 -0
  382. package/src/tui/hooks/useSmoothScroll.ts +202 -0
  383. package/src/tui/hooks/useSnapshots.ts +300 -0
  384. package/src/tui/hooks/useStateAndRef.ts +50 -0
  385. package/src/tui/hooks/useTerminalSize.ts +206 -0
  386. package/src/tui/hooks/useToolApprovalController.ts +91 -0
  387. package/src/tui/hooks/useVim.ts +334 -0
  388. package/src/tui/hooks/useWorkspace.ts +56 -0
  389. package/src/tui/i18n/__tests__/init.test.ts +278 -0
  390. package/src/tui/i18n/__tests__/language-config.test.ts +199 -0
  391. package/src/tui/i18n/__tests__/locale-detection.test.ts +250 -0
  392. package/src/tui/i18n/__tests__/settings-integration.test.ts +262 -0
  393. package/src/tui/i18n/index.ts +72 -0
  394. package/src/tui/i18n/init.ts +131 -0
  395. package/src/tui/i18n/language-config.ts +106 -0
  396. package/src/tui/i18n/locale-detection.ts +173 -0
  397. package/src/tui/i18n/settings-integration.ts +557 -0
  398. package/src/tui/i18n/tui-namespace.ts +538 -0
  399. package/src/tui/i18n/types.ts +312 -0
  400. package/src/tui/index.ts +43 -0
  401. package/src/tui/lsp-integration.ts +409 -0
  402. package/src/tui/metrics-integration.ts +366 -0
  403. package/src/tui/plugins.ts +383 -0
  404. package/src/tui/resilience.ts +342 -0
  405. package/src/tui/sandbox-integration.ts +317 -0
  406. package/src/tui/services/clipboard.ts +348 -0
  407. package/src/tui/services/fuzzy-search.ts +441 -0
  408. package/src/tui/services/index.ts +72 -0
  409. package/src/tui/services/markdown-renderer.ts +565 -0
  410. package/src/tui/services/open-external.ts +247 -0
  411. package/src/tui/services/syntax-highlighter.ts +483 -0
  412. package/src/tui/slash-commands.ts +12 -0
  413. package/src/tui/theme/index.ts +15 -0
  414. package/src/tui/theme/provider.tsx +206 -0
  415. package/src/tui/tip-integration.ts +300 -0
  416. package/src/tui/types/__tests__/ink-extended.test.ts +121 -0
  417. package/src/tui/types/ink-extended.ts +87 -0
  418. package/src/tui/utils/__tests__/bracketedPaste.test.ts +231 -0
  419. package/src/tui/utils/__tests__/heightEstimator.test.ts +157 -0
  420. package/src/tui/utils/__tests__/text-width.test.ts +158 -0
  421. package/src/tui/utils/__tests__/textSanitizer.test.ts +266 -0
  422. package/src/tui/utils/__tests__/ui-sizing.test.ts +169 -0
  423. package/src/tui/utils/bracketedPaste.ts +107 -0
  424. package/src/tui/utils/cursor-manager.ts +131 -0
  425. package/src/tui/utils/detectTerminal.ts +596 -0
  426. package/src/tui/utils/findLastSafeSplitPoint.ts +92 -0
  427. package/src/tui/utils/heightEstimator.ts +198 -0
  428. package/src/tui/utils/index.ts +91 -0
  429. package/src/tui/utils/isNarrowWidth.ts +52 -0
  430. package/src/tui/utils/stdoutGuard.ts +90 -0
  431. package/src/tui/utils/synchronized-update.ts +70 -0
  432. package/src/tui/utils/text-width.ts +225 -0
  433. package/src/tui/utils/textSanitizer.ts +225 -0
  434. package/src/tui/utils/textUtils.ts +114 -0
  435. package/src/tui/utils/ui-sizing.ts +192 -0
  436. package/src/tui-blessed/app.ts +160 -0
  437. package/src/tui-blessed/index.ts +2 -0
  438. package/src/tui-blessed/neo-blessed.d.ts +6 -0
  439. package/src/tui-blessed/test.ts +21 -0
  440. package/src/tui-blessed/types.ts +14 -0
  441. package/src/utils/icons.ts +130 -0
  442. package/src/utils/index.ts +33 -0
  443. package/src/utils/resume-hint.ts +86 -0
  444. package/src/version.ts +1 -0
  445. package/tsconfig.json +8 -0
  446. package/vitest.config.ts +35 -0
@@ -0,0 +1,402 @@
1
+ /**
2
+ * BacktrackControls Component (T058)
3
+ *
4
+ * UI component for displaying and controlling conversation backtracking.
5
+ * Shows undo/redo status, current branch, and branch selector.
6
+ *
7
+ * @module tui/components/backtrack/BacktrackControls
8
+ */
9
+
10
+ import { Box, Text, useInput } from "ink";
11
+ import type React from "react";
12
+ import { memo, useCallback, useState } from "react";
13
+ import type { BacktrackState, Branch } from "../../hooks/useBacktrack.js";
14
+ import { useTUITranslation } from "../../i18n/index.js";
15
+ import { useTheme } from "../../theme/index.js";
16
+
17
+ // =============================================================================
18
+ // Types
19
+ // =============================================================================
20
+
21
+ /**
22
+ * Props for the BacktrackControls component.
23
+ */
24
+ export interface BacktrackControlsProps {
25
+ /** Current backtrack state */
26
+ readonly backtrackState: BacktrackState;
27
+ /** Available branches */
28
+ readonly branches: ReadonlyArray<Branch<unknown>>;
29
+ /** Handler for undo action */
30
+ readonly onUndo: () => void;
31
+ /** Handler for redo action */
32
+ readonly onRedo: () => void;
33
+ /** Handler for creating a new branch */
34
+ readonly onCreateBranch: () => void;
35
+ /** Handler for switching branches */
36
+ readonly onSwitchBranch: (branchId: string) => void;
37
+ /** Whether the component is focused for input */
38
+ readonly isFocused?: boolean;
39
+ /** Whether to show in compact mode */
40
+ readonly compact?: boolean;
41
+ /** Whether to show keyboard hints */
42
+ readonly showHints?: boolean;
43
+ }
44
+
45
+ /**
46
+ * Props for the BranchSelector sub-component.
47
+ */
48
+ interface BranchSelectorProps {
49
+ readonly branches: ReadonlyArray<Branch<unknown>>;
50
+ readonly currentBranch: string;
51
+ readonly onSelect: (branchId: string) => void;
52
+ readonly onClose: () => void;
53
+ readonly isFocused: boolean;
54
+ }
55
+
56
+ // =============================================================================
57
+ // Sub-Components
58
+ // =============================================================================
59
+
60
+ /**
61
+ * Branch selector popup for choosing between branches.
62
+ */
63
+ function BranchSelector({
64
+ branches,
65
+ currentBranch,
66
+ onSelect,
67
+ onClose,
68
+ isFocused,
69
+ }: BranchSelectorProps): React.JSX.Element {
70
+ const { theme } = useTheme();
71
+ const { t } = useTUITranslation();
72
+ const [selectedIndex, setSelectedIndex] = useState(() => {
73
+ const index = branches.findIndex((b) => b.name === currentBranch);
74
+ return index >= 0 ? index : 0;
75
+ });
76
+
77
+ useInput(
78
+ (input, key) => {
79
+ if (!isFocused) return;
80
+
81
+ if (key.upArrow || input === "k") {
82
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
83
+ } else if (key.downArrow || input === "j") {
84
+ setSelectedIndex((prev) => Math.min(branches.length - 1, prev + 1));
85
+ } else if (key.return) {
86
+ const branch = branches[selectedIndex];
87
+ if (branch) {
88
+ onSelect(branch.id);
89
+ }
90
+ onClose();
91
+ } else if (key.escape || input === "q") {
92
+ onClose();
93
+ }
94
+ },
95
+ { isActive: isFocused }
96
+ );
97
+
98
+ return (
99
+ <Box flexDirection="column" borderStyle="single" borderColor={theme.colors.muted} paddingX={1}>
100
+ <Text bold color={theme.colors.primary}>
101
+ {t("backtrack.selectBranch")}
102
+ </Text>
103
+ <Box marginTop={1} flexDirection="column">
104
+ {branches.map((branch, index) => {
105
+ const isSelected = index === selectedIndex;
106
+ const isCurrent = branch.name === currentBranch;
107
+
108
+ return (
109
+ <Box key={branch.id}>
110
+ <Text color={isSelected ? theme.colors.primary : undefined} inverse={isSelected}>
111
+ {isSelected ? "▸ " : " "}
112
+ {branch.name}
113
+ {isCurrent ? ` ${t("backtrack.current")}` : ""}
114
+ </Text>
115
+ </Box>
116
+ );
117
+ })}
118
+ </Box>
119
+ <Box marginTop={1}>
120
+ <Text dimColor>{t("backtrack.keybindings")}</Text>
121
+ </Box>
122
+ </Box>
123
+ );
124
+ }
125
+
126
+ /**
127
+ * Status indicator showing undo/redo availability.
128
+ */
129
+ function StatusIndicator({
130
+ canUndo,
131
+ canRedo,
132
+ compact,
133
+ t,
134
+ }: {
135
+ canUndo: boolean;
136
+ canRedo: boolean;
137
+ compact: boolean;
138
+ t: (key: string) => string;
139
+ }): React.JSX.Element {
140
+ const { theme } = useTheme();
141
+
142
+ if (compact) {
143
+ return (
144
+ <Box>
145
+ <Text color={canUndo ? theme.colors.success : theme.colors.muted}>◀</Text>
146
+ <Text color={canRedo ? theme.colors.success : theme.colors.muted}>▶</Text>
147
+ </Box>
148
+ );
149
+ }
150
+
151
+ return (
152
+ <Box gap={1}>
153
+ <Text color={canUndo ? theme.colors.success : theme.colors.muted}>
154
+ {"[<]"} {t("backtrack.undo")} {canUndo ? "+" : "x"}
155
+ </Text>
156
+ <Text color={canRedo ? theme.colors.success : theme.colors.muted}>
157
+ {"[>]"} {t("backtrack.redo")} {canRedo ? "+" : "x"}
158
+ </Text>
159
+ </Box>
160
+ );
161
+ }
162
+
163
+ /**
164
+ * Branch indicator showing current branch and fork count.
165
+ */
166
+ function BranchIndicator({
167
+ currentBranch,
168
+ forkCount,
169
+ compact,
170
+ t,
171
+ }: {
172
+ currentBranch: string;
173
+ forkCount: number;
174
+ compact: boolean;
175
+ onClick?: () => void;
176
+ t: (key: string) => string;
177
+ }): React.JSX.Element {
178
+ const { theme } = useTheme();
179
+
180
+ if (compact) {
181
+ return (
182
+ <Box>
183
+ <Text color={theme.colors.info}>⎇{forkCount > 0 ? `+${forkCount}` : ""}</Text>
184
+ </Box>
185
+ );
186
+ }
187
+
188
+ return (
189
+ <Box gap={1}>
190
+ <Text color={theme.colors.info}>⎇ {currentBranch}</Text>
191
+ {forkCount > 0 && (
192
+ <Text dimColor>
193
+ ({forkCount} {forkCount !== 1 ? t("backtrack.forks") : t("backtrack.fork")})
194
+ </Text>
195
+ )}
196
+ </Box>
197
+ );
198
+ }
199
+
200
+ /**
201
+ * History position indicator.
202
+ */
203
+ function HistoryIndicator({
204
+ currentIndex,
205
+ historyLength,
206
+ }: {
207
+ currentIndex: number;
208
+ historyLength: number;
209
+ }): React.JSX.Element {
210
+ const position = currentIndex + 1;
211
+
212
+ return (
213
+ <Text dimColor>
214
+ [{position}/{historyLength}]
215
+ </Text>
216
+ );
217
+ }
218
+
219
+ // =============================================================================
220
+ // Main Component
221
+ // =============================================================================
222
+
223
+ /**
224
+ * BacktrackControls displays undo/redo status and branch management UI.
225
+ *
226
+ * Features:
227
+ * - Visual indicators for undo/redo availability
228
+ * - Current branch display with fork count
229
+ * - Branch selector popup (Ctrl+B to toggle)
230
+ * - History position indicator
231
+ * - Keyboard shortcuts: Ctrl+Z (undo), Ctrl+Y (redo), Ctrl+B (branch)
232
+ *
233
+ * @example
234
+ * ```tsx
235
+ * const {
236
+ * backtrackState,
237
+ * branches,
238
+ * undo,
239
+ * redo,
240
+ * createBranch,
241
+ * switchBranch,
242
+ * } = useBacktrack({ initialState: messages });
243
+ *
244
+ * <BacktrackControls
245
+ * backtrackState={backtrackState}
246
+ * branches={branches}
247
+ * onUndo={undo}
248
+ * onRedo={redo}
249
+ * onCreateBranch={() => createBranch()}
250
+ * onSwitchBranch={switchBranch}
251
+ * isFocused={true}
252
+ * showHints={true}
253
+ * />
254
+ * ```
255
+ */
256
+ export const BacktrackControls = memo(function BacktrackControls({
257
+ backtrackState,
258
+ branches,
259
+ onUndo,
260
+ onRedo,
261
+ onCreateBranch,
262
+ onSwitchBranch,
263
+ isFocused = false,
264
+ compact = false,
265
+ showHints = true,
266
+ }: BacktrackControlsProps): React.JSX.Element {
267
+ const { t } = useTUITranslation();
268
+ const [showBranchSelector, setShowBranchSelector] = useState(false);
269
+
270
+ const { canUndo, canRedo, forkCount, currentBranch, currentIndex, historyLength } =
271
+ backtrackState;
272
+
273
+ // Handle keyboard input
274
+ useInput(
275
+ (input, key) => {
276
+ if (!isFocused || showBranchSelector) return;
277
+
278
+ // Ctrl+Z for undo
279
+ if (key.ctrl && input === "z") {
280
+ onUndo();
281
+ return;
282
+ }
283
+
284
+ // Ctrl+Y for redo
285
+ if (key.ctrl && input === "y") {
286
+ onRedo();
287
+ return;
288
+ }
289
+
290
+ // Ctrl+B for branch selector or create branch
291
+ if (key.ctrl && input === "b") {
292
+ if (branches.length > 1) {
293
+ setShowBranchSelector(true);
294
+ } else {
295
+ onCreateBranch();
296
+ }
297
+ return;
298
+ }
299
+
300
+ // Ctrl+Shift+B to always create new branch
301
+ if (key.ctrl && key.shift && input === "B") {
302
+ onCreateBranch();
303
+ return;
304
+ }
305
+ },
306
+ { isActive: isFocused && !showBranchSelector }
307
+ );
308
+
309
+ const handleBranchSelect = useCallback(
310
+ (branchId: string) => {
311
+ onSwitchBranch(branchId);
312
+ setShowBranchSelector(false);
313
+ },
314
+ [onSwitchBranch]
315
+ );
316
+
317
+ const handleBranchClose = useCallback(() => {
318
+ setShowBranchSelector(false);
319
+ }, []);
320
+
321
+ // Branch selector overlay
322
+ if (showBranchSelector) {
323
+ return (
324
+ <BranchSelector
325
+ branches={branches}
326
+ currentBranch={currentBranch}
327
+ onSelect={handleBranchSelect}
328
+ onClose={handleBranchClose}
329
+ isFocused={isFocused}
330
+ />
331
+ );
332
+ }
333
+
334
+ // Compact mode - single line
335
+ if (compact) {
336
+ return (
337
+ <Box gap={1}>
338
+ <StatusIndicator canUndo={canUndo} canRedo={canRedo} compact={true} t={t} />
339
+ <BranchIndicator
340
+ currentBranch={currentBranch}
341
+ forkCount={forkCount}
342
+ compact={true}
343
+ onClick={() => setShowBranchSelector(true)}
344
+ t={t}
345
+ />
346
+ <HistoryIndicator currentIndex={currentIndex} historyLength={historyLength} />
347
+ </Box>
348
+ );
349
+ }
350
+
351
+ // Full mode
352
+ return (
353
+ <Box flexDirection="column">
354
+ <Box gap={2}>
355
+ <StatusIndicator canUndo={canUndo} canRedo={canRedo} compact={false} t={t} />
356
+ <Text dimColor>│</Text>
357
+ <BranchIndicator
358
+ currentBranch={currentBranch}
359
+ forkCount={forkCount}
360
+ compact={false}
361
+ onClick={() => setShowBranchSelector(true)}
362
+ t={t}
363
+ />
364
+ <Text dimColor>│</Text>
365
+ <HistoryIndicator currentIndex={currentIndex} historyLength={historyLength} />
366
+ </Box>
367
+
368
+ {showHints && (
369
+ <Box marginTop={1}>
370
+ <Text dimColor>
371
+ ^Z {t("backtrack.undo").toLowerCase()} • ^Y {t("backtrack.redo").toLowerCase()} • ^B{" "}
372
+ {branches.length > 1 ? t("backtrack.switchBranch") : t("backtrack.newBranch")}
373
+ </Text>
374
+ </Box>
375
+ )}
376
+ </Box>
377
+ );
378
+ });
379
+
380
+ /**
381
+ * Compact status bar variant of BacktrackControls.
382
+ * Designed to fit in the status bar area.
383
+ */
384
+ export function BacktrackStatusBar({
385
+ backtrackState,
386
+ }: {
387
+ backtrackState: BacktrackState;
388
+ }): React.JSX.Element {
389
+ const { theme } = useTheme();
390
+ const { canUndo, canRedo, currentBranch, currentIndex, historyLength } = backtrackState;
391
+
392
+ return (
393
+ <Box gap={1}>
394
+ <Text color={canUndo ? theme.colors.info : theme.colors.muted}>◀</Text>
395
+ <Text dimColor>
396
+ {currentIndex + 1}/{historyLength}
397
+ </Text>
398
+ <Text color={canRedo ? theme.colors.info : theme.colors.muted}>▶</Text>
399
+ {currentBranch !== "Main" && <Text color={theme.colors.warning}>⎇ {currentBranch}</Text>}
400
+ </Box>
401
+ );
402
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Backtrack Components
3
+ *
4
+ * Components for conversation backtracking and branching UI.
5
+ *
6
+ * @module tui/components/backtrack
7
+ */
8
+
9
+ export {
10
+ BacktrackControls,
11
+ type BacktrackControlsProps,
12
+ BacktrackStatusBar,
13
+ } from "./BacktrackControls.js";
@@ -0,0 +1,251 @@
1
+ /**
2
+ * AutoApprovalStatus Component (Phase 35+)
3
+ *
4
+ * Displays auto-approval status and limits in the TUI.
5
+ * Shows consecutive requests/cost for automatic tool approvals.
6
+ * Uses ASCII symbols instead of emoji for terminal compatibility.
7
+ *
8
+ * @module tui/components/common/AutoApprovalStatus
9
+ */
10
+
11
+ import { Box, Text } from "ink";
12
+ import type React from "react";
13
+ import { memo } from "react";
14
+ import { useTheme } from "../../theme/index.js";
15
+
16
+ // =============================================================================
17
+ // Types
18
+ // =============================================================================
19
+
20
+ /**
21
+ * Status severity level.
22
+ */
23
+ export type AutoApprovalSeverity = "info" | "warning" | "error";
24
+
25
+ /**
26
+ * Props for the AutoApprovalStatus component.
27
+ */
28
+ export interface AutoApprovalStatusProps {
29
+ /** Number of consecutive auto-approved requests */
30
+ readonly consecutiveRequests: number;
31
+ /** Request limit for auto-approvals */
32
+ readonly requestLimit: number;
33
+ /** Cumulative cost of consecutive auto-approved operations in USD */
34
+ readonly consecutiveCost: number;
35
+ /** Cost limit for auto-approvals in USD */
36
+ readonly costLimit: number;
37
+ /** Percentage of request limit used (0-100) */
38
+ readonly requestPercentUsed: number;
39
+ /** Percentage of cost limit used (0-100) */
40
+ readonly costPercentUsed: number;
41
+ /** Whether any limit has been reached */
42
+ readonly limitReached?: boolean;
43
+ /** Which limit type was reached */
44
+ readonly limitType?: "requests" | "cost";
45
+ /** Whether to show in compact mode */
46
+ readonly compact?: boolean;
47
+ /** Override severity level */
48
+ readonly severity?: AutoApprovalSeverity;
49
+ }
50
+
51
+ // =============================================================================
52
+ // Constants - ASCII Symbols (NO EMOJI)
53
+ // =============================================================================
54
+
55
+ /**
56
+ * ASCII symbols for different severity levels.
57
+ */
58
+ const SEVERITY_SYMBOLS: Record<AutoApprovalSeverity, string> = {
59
+ info: "[i]",
60
+ warning: "[!]",
61
+ error: "[X]",
62
+ } as const;
63
+
64
+ /**
65
+ * ASCII symbol for auto-approval indicator.
66
+ */
67
+ const AUTO_SYMBOL = "[>]";
68
+
69
+ // =============================================================================
70
+ // Helper Functions
71
+ // =============================================================================
72
+
73
+ /**
74
+ * Format cost as USD string.
75
+ */
76
+ function formatCostUSD(cost: number): string {
77
+ return `$${cost.toFixed(2)}`;
78
+ }
79
+
80
+ /**
81
+ * Determine severity based on usage percentage.
82
+ */
83
+ function getSeverityFromPercent(
84
+ requestPercent: number,
85
+ costPercent: number,
86
+ limitReached: boolean
87
+ ): AutoApprovalSeverity {
88
+ if (limitReached) return "error";
89
+ const maxPercent = Math.max(requestPercent, costPercent);
90
+ if (maxPercent >= 80) return "warning";
91
+ return "info";
92
+ }
93
+
94
+ // =============================================================================
95
+ // Component
96
+ // =============================================================================
97
+
98
+ /**
99
+ * AutoApprovalStatus - Displays auto-approval limits and status.
100
+ *
101
+ * Features:
102
+ * - Shows consecutive requests vs limit
103
+ * - Shows consecutive cost vs limit
104
+ * - Different severity levels (info, warning, error)
105
+ * - Compact and full display modes
106
+ * - ASCII-only symbols for terminal compatibility
107
+ *
108
+ * @example
109
+ * ```tsx
110
+ * // Normal status
111
+ * <AutoApprovalStatus
112
+ * consecutiveRequests={45}
113
+ * requestLimit={50}
114
+ * consecutiveCost={3.50}
115
+ * costLimit={5.00}
116
+ * requestPercentUsed={90}
117
+ * costPercentUsed={70}
118
+ * />
119
+ *
120
+ * // Limit reached
121
+ * <AutoApprovalStatus
122
+ * consecutiveRequests={50}
123
+ * requestLimit={50}
124
+ * consecutiveCost={4.00}
125
+ * costLimit={5.00}
126
+ * requestPercentUsed={100}
127
+ * costPercentUsed={80}
128
+ * limitReached
129
+ * limitType="requests"
130
+ * />
131
+ * ```
132
+ */
133
+ export const AutoApprovalStatus: React.FC<AutoApprovalStatusProps> = memo(
134
+ function AutoApprovalStatus({
135
+ consecutiveRequests,
136
+ requestLimit,
137
+ consecutiveCost,
138
+ costLimit,
139
+ requestPercentUsed,
140
+ costPercentUsed,
141
+ limitReached = false,
142
+ limitType,
143
+ compact = false,
144
+ severity: severityProp,
145
+ }) {
146
+ const { theme } = useTheme();
147
+
148
+ // Determine severity from props or calculate from percentage
149
+ const severity =
150
+ severityProp ?? getSeverityFromPercent(requestPercentUsed, costPercentUsed, limitReached);
151
+
152
+ // Get colors based on severity
153
+ const getColor = () => {
154
+ switch (severity) {
155
+ case "error":
156
+ return theme.colors.error;
157
+ case "warning":
158
+ return theme.colors.warning;
159
+ default:
160
+ return theme.colors.info;
161
+ }
162
+ };
163
+
164
+ const symbol = SEVERITY_SYMBOLS[severity];
165
+ const color = getColor();
166
+
167
+ // Compact display: single line
168
+ // [i] Auto-approved: 45/50 requests ($3.50/$5.00)
169
+ if (compact) {
170
+ return (
171
+ <Box>
172
+ <Text color={color}>
173
+ {AUTO_SYMBOL} Auto-approved: {consecutiveRequests}/{requestLimit} requests (
174
+ {formatCostUSD(consecutiveCost)}/{formatCostUSD(costLimit)})
175
+ </Text>
176
+ </Box>
177
+ );
178
+ }
179
+
180
+ // Full display with limit reached message
181
+ if (limitReached) {
182
+ const limitMessage =
183
+ limitType === "requests"
184
+ ? `Request limit reached (${consecutiveRequests}/${requestLimit})`
185
+ : `Cost limit reached (${formatCostUSD(consecutiveCost)}/${formatCostUSD(costLimit)})`;
186
+
187
+ return (
188
+ <Box flexDirection="column" marginY={1}>
189
+ {/* Header line */}
190
+ <Box>
191
+ <Text color={color} bold>
192
+ {symbol} AUTO-APPROVAL LIMIT: {limitMessage}
193
+ </Text>
194
+ </Box>
195
+
196
+ {/* Instructions */}
197
+ <Box marginLeft={4}>
198
+ <Text dimColor>Waiting for user confirmation to continue...</Text>
199
+ </Box>
200
+
201
+ {/* Details */}
202
+ <Box marginLeft={4} marginTop={1}>
203
+ <Text>
204
+ {AUTO_SYMBOL} Requests: {consecutiveRequests}/{requestLimit} | Cost:{" "}
205
+ {formatCostUSD(consecutiveCost)}/{formatCostUSD(costLimit)}
206
+ </Text>
207
+ </Box>
208
+ </Box>
209
+ );
210
+ }
211
+
212
+ // Full display for warning state
213
+ return (
214
+ <Box flexDirection="column" marginY={1}>
215
+ {/* Header line */}
216
+ <Box>
217
+ <Text color={color} bold>
218
+ {symbol} Auto-Approval Status
219
+ </Text>
220
+ </Box>
221
+
222
+ {/* Request details */}
223
+ <Box marginLeft={4}>
224
+ <Text>
225
+ Requests:{" "}
226
+ <Text color={requestPercentUsed >= 80 ? theme.colors.warning : undefined}>
227
+ {consecutiveRequests}/{requestLimit}
228
+ </Text>{" "}
229
+ ({requestPercentUsed.toFixed(0)}%)
230
+ </Text>
231
+ </Box>
232
+
233
+ {/* Cost details */}
234
+ <Box marginLeft={4}>
235
+ <Text>
236
+ Cost:{" "}
237
+ <Text color={costPercentUsed >= 80 ? theme.colors.warning : undefined}>
238
+ {formatCostUSD(consecutiveCost)}/{formatCostUSD(costLimit)}
239
+ </Text>{" "}
240
+ ({costPercentUsed.toFixed(0)}%)
241
+ </Text>
242
+ </Box>
243
+ </Box>
244
+ );
245
+ }
246
+ );
247
+
248
+ /**
249
+ * Default export for convenience.
250
+ */
251
+ export default AutoApprovalStatus;