@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,294 @@
1
+ /**
2
+ * CostWarning Component (Phase 35+)
3
+ *
4
+ * Displays cost limit warnings and status in the TUI.
5
+ * Uses ASCII symbols instead of emoji for terminal compatibility.
6
+ *
7
+ * @module tui/components/common/CostWarning
8
+ */
9
+
10
+ import { Box, Text } from "ink";
11
+ import type React from "react";
12
+ import { memo } from "react";
13
+ import { useTheme } from "../../theme/index.js";
14
+
15
+ // =============================================================================
16
+ // Types
17
+ // =============================================================================
18
+
19
+ /**
20
+ * Warning severity level.
21
+ */
22
+ export type CostWarningSeverity = "info" | "warning" | "error";
23
+
24
+ /**
25
+ * Props for the CostWarning component.
26
+ */
27
+ export interface CostWarningProps {
28
+ /** Current cost used in USD */
29
+ readonly costUsed: number;
30
+ /** Cost limit in USD (undefined if no limit) */
31
+ readonly costLimit?: number;
32
+ /** Number of requests made */
33
+ readonly requestsUsed: number;
34
+ /** Request limit (undefined if no limit) */
35
+ readonly requestLimit?: number;
36
+ /** Percentage of limit used (0-100) */
37
+ readonly percentUsed: number;
38
+ /** Whether limit has been reached */
39
+ readonly limitReached?: boolean;
40
+ /** Whether awaiting user approval */
41
+ readonly awaitingApproval?: boolean;
42
+ /** Severity level for styling */
43
+ readonly severity?: CostWarningSeverity;
44
+ /** Whether to show in compact mode */
45
+ readonly compact?: boolean;
46
+ /** Callback when user approves continuation */
47
+ readonly onApprove?: () => void;
48
+ /** Callback when user denies continuation */
49
+ readonly onDeny?: () => void;
50
+ }
51
+
52
+ // =============================================================================
53
+ // Constants - ASCII Symbols (NO EMOJI)
54
+ // =============================================================================
55
+
56
+ /**
57
+ * ASCII symbols for different severity levels.
58
+ */
59
+ const SEVERITY_SYMBOLS: Record<CostWarningSeverity, string> = {
60
+ info: "[i]",
61
+ warning: "[!]",
62
+ error: "[X]",
63
+ } as const;
64
+
65
+ /**
66
+ * ASCII symbol for cost indicator.
67
+ */
68
+ const COST_SYMBOL = "[$]";
69
+
70
+ // =============================================================================
71
+ // Helper Functions
72
+ // =============================================================================
73
+
74
+ /**
75
+ * Format cost as USD string.
76
+ */
77
+ function formatCostUSD(cost: number): string {
78
+ return `$${cost.toFixed(2)}`;
79
+ }
80
+
81
+ /**
82
+ * Determine severity based on percentage used.
83
+ */
84
+ function getSeverityFromPercent(percentUsed: number, limitReached: boolean): CostWarningSeverity {
85
+ if (limitReached) return "error";
86
+ if (percentUsed >= 80) return "warning";
87
+ return "info";
88
+ }
89
+
90
+ // =============================================================================
91
+ // Component
92
+ // =============================================================================
93
+
94
+ /**
95
+ * CostWarning - Displays cost limit warnings and status.
96
+ *
97
+ * Features:
98
+ * - Shows current cost vs limit
99
+ * - Shows request count vs limit
100
+ * - Displays percentage used with progress indicator
101
+ * - Different severity levels (info, warning, error)
102
+ * - Compact and full display modes
103
+ * - ASCII-only symbols for terminal compatibility
104
+ *
105
+ * @example
106
+ * ```tsx
107
+ * // Warning at 80%
108
+ * <CostWarning
109
+ * costUsed={4.00}
110
+ * costLimit={5.00}
111
+ * requestsUsed={80}
112
+ * requestLimit={100}
113
+ * percentUsed={80}
114
+ * severity="warning"
115
+ * />
116
+ *
117
+ * // Limit reached
118
+ * <CostWarning
119
+ * costUsed={5.20}
120
+ * costLimit={5.00}
121
+ * requestsUsed={100}
122
+ * percentUsed={100}
123
+ * limitReached
124
+ * awaitingApproval
125
+ * />
126
+ * ```
127
+ */
128
+ export const CostWarning: React.FC<CostWarningProps> = memo(function CostWarning({
129
+ costUsed,
130
+ costLimit,
131
+ requestsUsed,
132
+ requestLimit,
133
+ percentUsed,
134
+ limitReached = false,
135
+ awaitingApproval = false,
136
+ severity: severityProp,
137
+ compact = false,
138
+ }) {
139
+ const { theme } = useTheme();
140
+
141
+ // Determine severity from props or calculate from percentage
142
+ const severity = severityProp ?? getSeverityFromPercent(percentUsed, limitReached);
143
+
144
+ // Get colors based on severity
145
+ const getColor = () => {
146
+ switch (severity) {
147
+ case "error":
148
+ return theme.colors.error;
149
+ case "warning":
150
+ return theme.colors.warning;
151
+ default:
152
+ return theme.colors.info;
153
+ }
154
+ };
155
+
156
+ const symbol = SEVERITY_SYMBOLS[severity];
157
+ const color = getColor();
158
+
159
+ // Compact display: single line
160
+ if (compact) {
161
+ const limitDisplay = costLimit
162
+ ? `${formatCostUSD(costUsed)} / ${formatCostUSD(costLimit)}`
163
+ : formatCostUSD(costUsed);
164
+
165
+ return (
166
+ <Box>
167
+ <Text color={color}>
168
+ {COST_SYMBOL} {limitDisplay} ({percentUsed.toFixed(0)}%)
169
+ </Text>
170
+ </Box>
171
+ );
172
+ }
173
+
174
+ // Full display
175
+ return (
176
+ <Box flexDirection="column" marginY={1}>
177
+ {/* Header line */}
178
+ <Box>
179
+ <Text color={color} bold>
180
+ {symbol}{" "}
181
+ {limitReached
182
+ ? "LIMIT REACHED: Cost limit exceeded"
183
+ : `WARNING: Cost limit ${percentUsed.toFixed(0)}% reached`}
184
+ </Text>
185
+ </Box>
186
+
187
+ {/* Cost details */}
188
+ <Box marginLeft={4}>
189
+ <Text>
190
+ {COST_SYMBOL} Cost:{" "}
191
+ <Text color={color}>
192
+ {formatCostUSD(costUsed)}
193
+ {costLimit && ` / ${formatCostUSD(costLimit)}`}
194
+ </Text>
195
+ </Text>
196
+ </Box>
197
+
198
+ {/* Request details (if limit set) */}
199
+ {requestLimit && (
200
+ <Box marginLeft={4}>
201
+ <Text>
202
+ [#] Requests:{" "}
203
+ <Text color={color}>
204
+ {requestsUsed} / {requestLimit}
205
+ </Text>
206
+ </Text>
207
+ </Box>
208
+ )}
209
+
210
+ {/* Progress bar */}
211
+ <Box marginLeft={4} marginTop={1}>
212
+ <ProgressBar percent={percentUsed} color={color} width={30} />
213
+ </Box>
214
+
215
+ {/* Approval prompt */}
216
+ {awaitingApproval && (
217
+ <Box marginTop={1} marginLeft={4}>
218
+ <Text color={theme.colors.warning}>Press [y] to continue or [n] to stop</Text>
219
+ </Box>
220
+ )}
221
+ </Box>
222
+ );
223
+ });
224
+
225
+ // =============================================================================
226
+ // Progress Bar Sub-component
227
+ // =============================================================================
228
+
229
+ interface ProgressBarProps {
230
+ readonly percent: number;
231
+ readonly color: string;
232
+ readonly width?: number;
233
+ }
234
+
235
+ /**
236
+ * Simple ASCII progress bar.
237
+ */
238
+ const ProgressBar: React.FC<ProgressBarProps> = memo(function ProgressBar({
239
+ percent,
240
+ color,
241
+ width = 20,
242
+ }) {
243
+ const filled = Math.round((percent / 100) * width);
244
+ const empty = width - filled;
245
+
246
+ return (
247
+ <Box>
248
+ <Text color={color}>[</Text>
249
+ <Text color={color}>{"=".repeat(Math.max(0, filled))}</Text>
250
+ <Text dimColor>{"-".repeat(Math.max(0, empty))}</Text>
251
+ <Text color={color}>]</Text>
252
+ <Text dimColor> {percent.toFixed(0)}%</Text>
253
+ </Box>
254
+ );
255
+ });
256
+
257
+ // =============================================================================
258
+ // Compact Cost Display
259
+ // =============================================================================
260
+
261
+ /**
262
+ * Props for CompactCostDisplay.
263
+ */
264
+ export interface CompactCostDisplayProps {
265
+ /** Current cost used in USD */
266
+ readonly cost: number;
267
+ /** Cost limit (optional) */
268
+ readonly limit?: number;
269
+ /** Show warning color if approaching limit */
270
+ readonly showWarning?: boolean;
271
+ }
272
+
273
+ /**
274
+ * Compact single-line cost display for status bar.
275
+ *
276
+ * @example
277
+ * ```tsx
278
+ * <CompactCostDisplay cost={2.50} limit={5.00} />
279
+ * // Output: [$] $2.50 / $5.00
280
+ * ```
281
+ */
282
+ export const CompactCostDisplay: React.FC<CompactCostDisplayProps> = memo(
283
+ function CompactCostDisplay({ cost, limit, showWarning = false }) {
284
+ const { theme } = useTheme();
285
+ const color = showWarning ? theme.colors.warning : theme.colors.muted;
286
+
287
+ return (
288
+ <Text color={color}>
289
+ {COST_SYMBOL} {formatCostUSD(cost)}
290
+ {limit && ` / ${formatCostUSD(limit)}`}
291
+ </Text>
292
+ );
293
+ }
294
+ );
@@ -0,0 +1,209 @@
1
+ /**
2
+ * DynamicShortcutHints Component
3
+ *
4
+ * Displays context-aware keyboard shortcuts based on current UI state.
5
+ * Shows different hints for:
6
+ * - Input mode (typing)
7
+ * - Agent running (processing)
8
+ * - Idle state
9
+ * - Autocomplete active
10
+ *
11
+ * @module tui/components/common/DynamicShortcutHints
12
+ */
13
+
14
+ import { Box, Text } from "ink";
15
+ import type React from "react";
16
+ import { memo, useMemo } from "react";
17
+ import { useTheme } from "../../theme/index.js";
18
+ import { type HotkeyHint, HotkeyHints } from "./HotkeyHints.js";
19
+
20
+ // =============================================================================
21
+ // Types
22
+ // =============================================================================
23
+
24
+ /**
25
+ * Current UI state for determining which shortcuts to show.
26
+ */
27
+ export type UIState =
28
+ | "idle" // Waiting for input
29
+ | "input" // User is typing
30
+ | "running" // Agent is processing
31
+ | "autocomplete" // Autocomplete menu is open
32
+ | "confirmation" // Waiting for user confirmation
33
+ | "multiline"; // Multiline input mode
34
+
35
+ /**
36
+ * Props for DynamicShortcutHints component.
37
+ */
38
+ export interface DynamicShortcutHintsProps {
39
+ /** Current UI state */
40
+ readonly state: UIState;
41
+ /** Whether sidebar is visible */
42
+ readonly sidebarVisible?: boolean;
43
+ /** Whether vim mode is active */
44
+ readonly vimMode?: boolean;
45
+ /** Additional custom hints to append */
46
+ readonly customHints?: readonly HotkeyHint[];
47
+ /** Whether to show compact version (fewer hints) */
48
+ readonly compact?: boolean;
49
+ }
50
+
51
+ // =============================================================================
52
+ // Constants
53
+ // =============================================================================
54
+
55
+ /**
56
+ * Shortcut hints for different UI states.
57
+ */
58
+ const STATE_HINTS: Record<UIState, readonly HotkeyHint[]> = {
59
+ idle: [
60
+ { keys: "Enter", label: "Send" },
61
+ { keys: "↑/↓", label: "History" },
62
+ { keys: "/", label: "Commands" },
63
+ { keys: "@", label: "Mention" },
64
+ { keys: "!", label: "Shell" },
65
+ ],
66
+ input: [
67
+ { keys: "Enter", label: "Send" },
68
+ { keys: "Ctrl+C", label: "Clear" },
69
+ { keys: "Tab", label: "Complete" },
70
+ { keys: "↑/↓", label: "History" },
71
+ ],
72
+ running: [
73
+ { keys: "Esc", label: "Stop" },
74
+ { keys: "PgUp/Dn", label: "Scroll" },
75
+ { keys: "Ctrl+C", label: "Cancel" },
76
+ ],
77
+ autocomplete: [
78
+ { keys: "↑/↓", label: "Navigate" },
79
+ { keys: "Tab/Enter", label: "Select" },
80
+ { keys: "Esc", label: "Close" },
81
+ ],
82
+ confirmation: [
83
+ { keys: "y/Enter", label: "Confirm" },
84
+ { keys: "n/Esc", label: "Cancel" },
85
+ { keys: "a", label: "Always" },
86
+ ],
87
+ multiline: [
88
+ { keys: "Ctrl+Enter", label: "Send" },
89
+ { keys: "Enter", label: "Newline" },
90
+ { keys: "Esc", label: "Exit" },
91
+ ],
92
+ };
93
+
94
+ /**
95
+ * Compact hints (fewer items for narrow terminals).
96
+ */
97
+ const COMPACT_HINTS: Record<UIState, readonly HotkeyHint[]> = {
98
+ idle: [
99
+ { keys: "Enter", label: "Send" },
100
+ { keys: "/", label: "Cmds" },
101
+ { keys: "!", label: "Shell" },
102
+ ],
103
+ input: [
104
+ { keys: "Enter", label: "Send" },
105
+ { keys: "Tab", label: "Complete" },
106
+ ],
107
+ running: [
108
+ { keys: "Esc", label: "Stop" },
109
+ { keys: "Ctrl+C", label: "Cancel" },
110
+ ],
111
+ autocomplete: [
112
+ { keys: "↑/↓", label: "Nav" },
113
+ { keys: "Enter", label: "Select" },
114
+ ],
115
+ confirmation: [
116
+ { keys: "y", label: "Yes" },
117
+ { keys: "n", label: "No" },
118
+ ],
119
+ multiline: [
120
+ { keys: "Ctrl+Enter", label: "Send" },
121
+ { keys: "Esc", label: "Exit" },
122
+ ],
123
+ };
124
+
125
+ // =============================================================================
126
+ // Component
127
+ // =============================================================================
128
+
129
+ /**
130
+ * Get hints for the current state.
131
+ */
132
+ function getHintsForState(
133
+ state: UIState,
134
+ compact: boolean,
135
+ sidebarVisible: boolean,
136
+ vimMode: boolean,
137
+ customHints?: readonly HotkeyHint[]
138
+ ): HotkeyHint[] {
139
+ const baseHints = compact ? COMPACT_HINTS[state] : STATE_HINTS[state];
140
+ const hints: HotkeyHint[] = [...baseHints];
141
+
142
+ // Add sidebar toggle hint if not in compact mode
143
+ if (!compact && state !== "running" && state !== "autocomplete") {
144
+ hints.push({ keys: "Alt+K", label: sidebarVisible ? "Hide sidebar" : "Show sidebar" });
145
+ }
146
+
147
+ // Add vim mode indicator if active
148
+ if (vimMode && !compact) {
149
+ hints.push({ keys: "Esc", label: "Vim normal" });
150
+ }
151
+
152
+ // Append custom hints
153
+ if (customHints) {
154
+ hints.push(...customHints);
155
+ }
156
+
157
+ return hints;
158
+ }
159
+
160
+ /**
161
+ * DynamicShortcutHints displays context-aware keyboard shortcuts.
162
+ *
163
+ * @example
164
+ * ```tsx
165
+ * <DynamicShortcutHints
166
+ * state={isRunning ? "running" : hasInput ? "input" : "idle"}
167
+ * sidebarVisible={showSidebar}
168
+ * />
169
+ * ```
170
+ */
171
+ function DynamicShortcutHintsImpl({
172
+ state,
173
+ sidebarVisible = false,
174
+ vimMode = false,
175
+ customHints,
176
+ compact = false,
177
+ }: DynamicShortcutHintsProps): React.JSX.Element {
178
+ const { theme } = useTheme();
179
+
180
+ const hints = useMemo(
181
+ () => getHintsForState(state, compact, sidebarVisible, vimMode, customHints),
182
+ [state, compact, sidebarVisible, vimMode, customHints]
183
+ );
184
+
185
+ return (
186
+ <Box flexDirection="row" alignItems="center">
187
+ <Text color={theme.semantic.text.muted} dimColor>
188
+ <HotkeyHints hints={hints} />
189
+ </Text>
190
+ </Box>
191
+ );
192
+ }
193
+
194
+ /**
195
+ * Compare props for memo optimization.
196
+ */
197
+ function arePropsEqual(prev: DynamicShortcutHintsProps, next: DynamicShortcutHintsProps): boolean {
198
+ return (
199
+ prev.state === next.state &&
200
+ prev.sidebarVisible === next.sidebarVisible &&
201
+ prev.vimMode === next.vimMode &&
202
+ prev.compact === next.compact &&
203
+ prev.customHints === next.customHints
204
+ );
205
+ }
206
+
207
+ export const DynamicShortcutHints = memo(DynamicShortcutHintsImpl, arePropsEqual);
208
+
209
+ export default DynamicShortcutHints;