@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,143 @@
1
+ /**
2
+ * usePlaceholderRotation Hook
3
+ *
4
+ * Rotates through example placeholder texts to help users discover capabilities.
5
+ * Inspired by OpenCode's prompt-input pattern.
6
+ *
7
+ * @module tui/hooks/usePlaceholderRotation
8
+ */
9
+
10
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
11
+
12
+ // =============================================================================
13
+ // Types
14
+ // =============================================================================
15
+
16
+ /**
17
+ * Options for the usePlaceholderRotation hook.
18
+ */
19
+ export interface UsePlaceholderRotationOptions {
20
+ /** Rotation interval in milliseconds (default: 5000) */
21
+ readonly interval?: number;
22
+ /** Whether rotation is enabled (default: true) */
23
+ readonly enabled?: boolean;
24
+ /** Custom placeholder examples (uses defaults if not provided) */
25
+ readonly examples?: readonly string[];
26
+ /** Static placeholder to use when input has content */
27
+ readonly staticPlaceholder?: string;
28
+ }
29
+
30
+ /**
31
+ * Return value of usePlaceholderRotation hook.
32
+ */
33
+ export interface UsePlaceholderRotationReturn {
34
+ /** Current placeholder text to display */
35
+ readonly placeholder: string;
36
+ /** Index of current placeholder in examples array */
37
+ readonly currentIndex: number;
38
+ /** Manually advance to next placeholder */
39
+ readonly next: () => void;
40
+ /** Reset to first placeholder */
41
+ readonly reset: () => void;
42
+ }
43
+
44
+ // =============================================================================
45
+ // Constants
46
+ // =============================================================================
47
+
48
+ /**
49
+ * Default placeholder examples showcasing Vellum capabilities.
50
+ * Each demonstrates a different type of task users can request.
51
+ */
52
+ export const DEFAULT_PLACEHOLDER_EXAMPLES: readonly string[] = [
53
+ "Implement a user authentication feature...",
54
+ "Fix the bug in the payment service...",
55
+ "Refactor this function to be more readable...",
56
+ "Add unit tests for the API endpoints...",
57
+ "Explain how this code works...",
58
+ "Create a React component for...",
59
+ "Optimize this database query...",
60
+ "Review this code for security issues...",
61
+ "Generate TypeScript types for this API...",
62
+ "Help me debug this error...",
63
+ ] as const;
64
+
65
+ /** Default rotation interval: 5 seconds */
66
+ const DEFAULT_INTERVAL_MS = 5000;
67
+
68
+ // =============================================================================
69
+ // Hook Implementation
70
+ // =============================================================================
71
+
72
+ /**
73
+ * Hook that rotates through placeholder examples.
74
+ *
75
+ * @example
76
+ * ```tsx
77
+ * const { placeholder } = usePlaceholderRotation({
78
+ * interval: 5000,
79
+ * enabled: inputValue.length === 0,
80
+ * });
81
+ *
82
+ * return <TextInput placeholder={placeholder} />;
83
+ * ```
84
+ */
85
+ export function usePlaceholderRotation({
86
+ interval = DEFAULT_INTERVAL_MS,
87
+ enabled = true,
88
+ examples = DEFAULT_PLACEHOLDER_EXAMPLES,
89
+ staticPlaceholder = "Type a message, /command, or @mention...",
90
+ }: UsePlaceholderRotationOptions = {}): UsePlaceholderRotationReturn {
91
+ const [currentIndex, setCurrentIndex] = useState(0);
92
+ const intervalRef = useRef<NodeJS.Timeout | null>(null);
93
+
94
+ // Memoize examples array to prevent unnecessary effect triggers
95
+ const memoizedExamples = useMemo(() => examples, [examples]);
96
+
97
+ // Cleanup interval on unmount or when dependencies change
98
+ const clearRotationInterval = useCallback(() => {
99
+ if (intervalRef.current !== null) {
100
+ clearInterval(intervalRef.current);
101
+ intervalRef.current = null;
102
+ }
103
+ }, []);
104
+
105
+ // Advance to next placeholder
106
+ const next = useCallback(() => {
107
+ setCurrentIndex((prev) => (prev + 1) % memoizedExamples.length);
108
+ }, [memoizedExamples.length]);
109
+
110
+ // Reset to first placeholder
111
+ const reset = useCallback(() => {
112
+ setCurrentIndex(0);
113
+ }, []);
114
+
115
+ // Set up rotation interval
116
+ useEffect(() => {
117
+ if (!enabled || memoizedExamples.length <= 1) {
118
+ clearRotationInterval();
119
+ return;
120
+ }
121
+
122
+ intervalRef.current = setInterval(() => {
123
+ setCurrentIndex((prev) => (prev + 1) % memoizedExamples.length);
124
+ }, interval);
125
+
126
+ return clearRotationInterval;
127
+ }, [enabled, interval, memoizedExamples.length, clearRotationInterval]);
128
+
129
+ // Get current placeholder
130
+ const placeholder = useMemo(() => {
131
+ if (!enabled || memoizedExamples.length === 0) {
132
+ return staticPlaceholder;
133
+ }
134
+ return memoizedExamples[currentIndex] ?? staticPlaceholder;
135
+ }, [enabled, memoizedExamples, currentIndex, staticPlaceholder]);
136
+
137
+ return {
138
+ placeholder,
139
+ currentIndex,
140
+ next,
141
+ reset,
142
+ };
143
+ }
@@ -0,0 +1,270 @@
1
+ /**
2
+ * useProviderStatus Hook
3
+ *
4
+ * Tracks provider status including circuit breaker states for the TUI.
5
+ * Provides real-time status updates for model status bar display.
6
+ *
7
+ * @module tui/hooks/useProviderStatus
8
+ */
9
+
10
+ import { useCallback, useEffect, useState } from "react";
11
+
12
+ // =============================================================================
13
+ // Types
14
+ // =============================================================================
15
+
16
+ /**
17
+ * Circuit breaker state following standard pattern.
18
+ * - CLOSED: Normal operation, requests pass through
19
+ * - OPEN: Failure threshold exceeded, requests rejected
20
+ * - HALF_OPEN: Testing if service has recovered
21
+ */
22
+ export type CircuitState = "CLOSED" | "OPEN" | "HALF_OPEN";
23
+
24
+ /**
25
+ * Individual provider status entry.
26
+ */
27
+ export interface ProviderStatusEntry {
28
+ /** Provider identifier (e.g., 'anthropic', 'openai', 'google') */
29
+ readonly id: string;
30
+ /** Display name for the provider */
31
+ readonly name: string;
32
+ /** Current circuit breaker state */
33
+ readonly circuitState: CircuitState;
34
+ /** Whether this is the currently active provider */
35
+ readonly isActive: boolean;
36
+ /** Number of failures in current window */
37
+ readonly failureCount: number;
38
+ /** Time until circuit may reset (ms), 0 if not in OPEN state */
39
+ readonly timeUntilReset: number;
40
+ /** Last error message if any */
41
+ readonly lastError?: string;
42
+ }
43
+
44
+ /**
45
+ * Return type for useProviderStatus hook.
46
+ */
47
+ export interface UseProviderStatusReturn {
48
+ /** Array of all tracked provider statuses */
49
+ readonly providers: readonly ProviderStatusEntry[];
50
+ /** Currently active provider ID */
51
+ readonly activeProviderId: string | undefined;
52
+ /** Set the active provider */
53
+ readonly setActiveProvider: (providerId: string) => void;
54
+ /** Update a provider's circuit state */
55
+ readonly updateProviderState: (
56
+ providerId: string,
57
+ state: CircuitState,
58
+ failureCount?: number,
59
+ lastError?: string
60
+ ) => void;
61
+ /** Register a new provider */
62
+ readonly registerProvider: (id: string, name: string) => void;
63
+ /** Unregister a provider */
64
+ readonly unregisterProvider: (id: string) => void;
65
+ /** Get status for a specific provider */
66
+ readonly getProviderStatus: (providerId: string) => ProviderStatusEntry | undefined;
67
+ /** Count of healthy (CLOSED state) providers */
68
+ readonly healthyCount: number;
69
+ /** Count of unhealthy (OPEN state) providers */
70
+ readonly unhealthyCount: number;
71
+ /** Count of half-open providers */
72
+ readonly halfOpenCount: number;
73
+ }
74
+
75
+ /**
76
+ * Options for useProviderStatus hook.
77
+ */
78
+ export interface UseProviderStatusOptions {
79
+ /** Initial providers to track */
80
+ readonly initialProviders?: ReadonlyArray<{
81
+ readonly id: string;
82
+ readonly name: string;
83
+ readonly isActive?: boolean;
84
+ }>;
85
+ /** Interval to update time-until-reset values (ms) */
86
+ readonly updateInterval?: number;
87
+ }
88
+
89
+ // =============================================================================
90
+ // Constants
91
+ // =============================================================================
92
+
93
+ /** Default update interval for time-based state changes */
94
+ const DEFAULT_UPDATE_INTERVAL = 1000;
95
+
96
+ // =============================================================================
97
+ // Hook Implementation
98
+ // =============================================================================
99
+
100
+ /**
101
+ * Hook for tracking provider status including circuit breaker states.
102
+ *
103
+ * @param options - Configuration options
104
+ * @returns Provider status state and actions
105
+ *
106
+ * @example
107
+ * ```tsx
108
+ * const { providers, activeProviderId, setActiveProvider } = useProviderStatus({
109
+ * initialProviders: [
110
+ * { id: 'anthropic', name: 'Claude', isActive: true },
111
+ * { id: 'openai', name: 'GPT-4' },
112
+ * { id: 'google', name: 'Gemini' },
113
+ * ],
114
+ * });
115
+ * ```
116
+ */
117
+ export function useProviderStatus(options: UseProviderStatusOptions = {}): UseProviderStatusReturn {
118
+ const { initialProviders = [], updateInterval = DEFAULT_UPDATE_INTERVAL } = options;
119
+
120
+ // State: Map of provider ID to status entry
121
+ const [providerMap, setProviderMap] = useState<Map<string, ProviderStatusEntry>>(() => {
122
+ const map = new Map<string, ProviderStatusEntry>();
123
+ for (const provider of initialProviders) {
124
+ map.set(provider.id, {
125
+ id: provider.id,
126
+ name: provider.name,
127
+ circuitState: "CLOSED",
128
+ isActive: provider.isActive ?? false,
129
+ failureCount: 0,
130
+ timeUntilReset: 0,
131
+ });
132
+ }
133
+ return map;
134
+ });
135
+
136
+ // Derived: Active provider ID
137
+ const activeProviderId = Array.from(providerMap.values()).find((p) => p.isActive)?.id;
138
+
139
+ // Set active provider
140
+ const setActiveProvider = useCallback((providerId: string) => {
141
+ setProviderMap((prev) => {
142
+ const next = new Map(prev);
143
+ for (const [id, entry] of next) {
144
+ next.set(id, {
145
+ ...entry,
146
+ isActive: id === providerId,
147
+ });
148
+ }
149
+ return next;
150
+ });
151
+ }, []);
152
+
153
+ // Update provider circuit state
154
+ const updateProviderState = useCallback(
155
+ (providerId: string, state: CircuitState, failureCount?: number, lastError?: string) => {
156
+ setProviderMap((prev) => {
157
+ const entry = prev.get(providerId);
158
+ if (!entry) return prev;
159
+
160
+ const next = new Map(prev);
161
+ next.set(providerId, {
162
+ ...entry,
163
+ circuitState: state,
164
+ failureCount: failureCount ?? entry.failureCount,
165
+ lastError: lastError ?? entry.lastError,
166
+ // Reset timeUntilReset based on state
167
+ timeUntilReset: state === "OPEN" ? 30000 : 0, // Default 30s reset timeout
168
+ });
169
+ return next;
170
+ });
171
+ },
172
+ []
173
+ );
174
+
175
+ // Register new provider
176
+ const registerProvider = useCallback((id: string, name: string) => {
177
+ setProviderMap((prev) => {
178
+ if (prev.has(id)) return prev;
179
+
180
+ const next = new Map(prev);
181
+ next.set(id, {
182
+ id,
183
+ name,
184
+ circuitState: "CLOSED",
185
+ isActive: next.size === 0, // First provider is active by default
186
+ failureCount: 0,
187
+ timeUntilReset: 0,
188
+ });
189
+ return next;
190
+ });
191
+ }, []);
192
+
193
+ // Unregister provider
194
+ const unregisterProvider = useCallback((id: string) => {
195
+ setProviderMap((prev) => {
196
+ if (!prev.has(id)) return prev;
197
+
198
+ const next = new Map(prev);
199
+ const wasActive = next.get(id)?.isActive;
200
+ next.delete(id);
201
+
202
+ // If removed provider was active, activate first remaining provider
203
+ if (wasActive && next.size > 0) {
204
+ const firstId = next.keys().next().value;
205
+ if (firstId !== undefined) {
206
+ const firstEntry = next.get(firstId);
207
+ if (firstEntry) {
208
+ next.set(firstId, { ...firstEntry, isActive: true });
209
+ }
210
+ }
211
+ }
212
+
213
+ return next;
214
+ });
215
+ }, []);
216
+
217
+ // Get status for specific provider
218
+ const getProviderStatus = useCallback(
219
+ (providerId: string): ProviderStatusEntry | undefined => {
220
+ return providerMap.get(providerId);
221
+ },
222
+ [providerMap]
223
+ );
224
+
225
+ // Timer to decrement timeUntilReset for OPEN circuits
226
+ useEffect(() => {
227
+ const timer = setInterval(() => {
228
+ setProviderMap((prev) => {
229
+ let hasChanges = false;
230
+ const next = new Map(prev);
231
+
232
+ for (const [id, entry] of next) {
233
+ if (entry.circuitState === "OPEN" && entry.timeUntilReset > 0) {
234
+ hasChanges = true;
235
+ const newTime = Math.max(0, entry.timeUntilReset - updateInterval);
236
+ next.set(id, {
237
+ ...entry,
238
+ timeUntilReset: newTime,
239
+ // Auto-transition to HALF_OPEN when timer expires
240
+ circuitState: newTime === 0 ? "HALF_OPEN" : "OPEN",
241
+ });
242
+ }
243
+ }
244
+
245
+ return hasChanges ? next : prev;
246
+ });
247
+ }, updateInterval);
248
+
249
+ return () => clearInterval(timer);
250
+ }, [updateInterval]);
251
+
252
+ // Compute counts
253
+ const providers = Array.from(providerMap.values());
254
+ const healthyCount = providers.filter((p) => p.circuitState === "CLOSED").length;
255
+ const unhealthyCount = providers.filter((p) => p.circuitState === "OPEN").length;
256
+ const halfOpenCount = providers.filter((p) => p.circuitState === "HALF_OPEN").length;
257
+
258
+ return {
259
+ providers,
260
+ activeProviderId,
261
+ setActiveProvider,
262
+ updateProviderState,
263
+ registerProvider,
264
+ unregisterProvider,
265
+ getProviderStatus,
266
+ healthyCount,
267
+ unhealthyCount,
268
+ halfOpenCount,
269
+ };
270
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Rate Limit Status Hook
3
+ *
4
+ * Provides rate limit status information for API providers.
5
+ * Placeholder implementation - to be expanded.
6
+ *
7
+ * @module tui/hooks/useRateLimitStatus
8
+ */
9
+
10
+ import { useCallback, useEffect, useState } from "react";
11
+
12
+ // =============================================================================
13
+ // Types
14
+ // =============================================================================
15
+
16
+ export interface RateLimitStatus {
17
+ /** Whether currently rate limited */
18
+ isLimited: boolean;
19
+ /** Remaining requests in current window */
20
+ remaining?: number;
21
+ /** Total limit for the window */
22
+ limit?: number;
23
+ /** Time until limit resets (seconds) */
24
+ resetIn?: number;
25
+ /** Provider name */
26
+ provider?: string;
27
+ }
28
+
29
+ export interface UseRateLimitStatusOptions {
30
+ /** Provider to track */
31
+ provider?: string;
32
+ /** Polling interval in ms */
33
+ pollInterval?: number;
34
+ }
35
+
36
+ export interface UseRateLimitStatusResult {
37
+ /** Current rate limit status */
38
+ status: RateLimitStatus;
39
+ /** Whether data is loading */
40
+ isLoading: boolean;
41
+ /** Any error that occurred */
42
+ error: Error | null;
43
+ /** Refresh the status */
44
+ refresh: () => void;
45
+ }
46
+
47
+ // =============================================================================
48
+ // Hook
49
+ // =============================================================================
50
+
51
+ const defaultStatus: RateLimitStatus = {
52
+ isLimited: false,
53
+ };
54
+
55
+ /**
56
+ * Hook to track rate limit status
57
+ */
58
+ export function useRateLimitStatus(
59
+ options: UseRateLimitStatusOptions = {}
60
+ ): UseRateLimitStatusResult {
61
+ const { provider, pollInterval } = options;
62
+ const [status, setStatus] = useState<RateLimitStatus>(defaultStatus);
63
+ const [isLoading, setIsLoading] = useState(false);
64
+ const [error, _setError] = useState<Error | null>(null);
65
+
66
+ const refresh = useCallback(() => {
67
+ setIsLoading(true);
68
+ // Placeholder: In real implementation, fetch status from provider
69
+ setStatus({ ...defaultStatus, provider });
70
+ setIsLoading(false);
71
+ }, [provider]);
72
+
73
+ useEffect(() => {
74
+ refresh();
75
+
76
+ if (pollInterval && pollInterval > 0) {
77
+ const interval = setInterval(refresh, pollInterval);
78
+ return () => clearInterval(interval);
79
+ }
80
+ }, [pollInterval, refresh]);
81
+
82
+ return {
83
+ status,
84
+ isLoading,
85
+ error,
86
+ refresh,
87
+ };
88
+ }
89
+
90
+ export default useRateLimitStatus;