@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,443 @@
1
+ /**
2
+ * useBacktrack Hook (T058)
3
+ *
4
+ * React hook for managing conversation backtracking and branching.
5
+ * Provides undo/redo functionality with support for creating alternative
6
+ * conversation branches (forks).
7
+ *
8
+ * @module @vellum/cli
9
+ */
10
+
11
+ import { useCallback, useMemo, useReducer } from "react";
12
+
13
+ // =============================================================================
14
+ // Types
15
+ // =============================================================================
16
+
17
+ /**
18
+ * Represents a single state snapshot in the history.
19
+ */
20
+ export interface HistorySnapshot<T> {
21
+ /** Unique identifier for this snapshot */
22
+ readonly id: string;
23
+ /** The state data at this point */
24
+ readonly state: T;
25
+ /** Timestamp when this snapshot was created */
26
+ readonly timestamp: number;
27
+ /** Optional description of what changed */
28
+ readonly description?: string;
29
+ }
30
+
31
+ /**
32
+ * Represents a branch (fork) in the conversation history.
33
+ */
34
+ export interface Branch<T> {
35
+ /** Unique identifier for this branch */
36
+ readonly id: string;
37
+ /** Human-readable name for the branch */
38
+ readonly name: string;
39
+ /** Index in the parent branch where this fork occurred */
40
+ readonly forkPoint: number;
41
+ /** The history snapshots in this branch */
42
+ readonly history: ReadonlyArray<HistorySnapshot<T>>;
43
+ /** ID of the parent branch (null for main branch) */
44
+ readonly parentBranchId: string | null;
45
+ /** Timestamp when this branch was created */
46
+ readonly createdAt: number;
47
+ }
48
+
49
+ /**
50
+ * Current backtrack state exposed to consumers.
51
+ */
52
+ export interface BacktrackState {
53
+ /** Whether undo is available */
54
+ readonly canUndo: boolean;
55
+ /** Whether redo is available */
56
+ readonly canRedo: boolean;
57
+ /** Total number of forks/branches */
58
+ readonly forkCount: number;
59
+ /** Current branch identifier */
60
+ readonly currentBranch: string;
61
+ /** Current position in history */
62
+ readonly currentIndex: number;
63
+ /** Total history length in current branch */
64
+ readonly historyLength: number;
65
+ }
66
+
67
+ /**
68
+ * Options for the useBacktrack hook.
69
+ */
70
+ export interface UseBacktrackOptions<T> {
71
+ /** Initial state */
72
+ readonly initialState: T;
73
+ /** Maximum history length per branch (default: 100) */
74
+ readonly maxHistory?: number;
75
+ /** Whether to enable branching (default: true) */
76
+ readonly enableBranching?: boolean;
77
+ /** Callback when state changes */
78
+ readonly onStateChange?: (state: T, action: "undo" | "redo" | "push" | "branch") => void;
79
+ }
80
+
81
+ /**
82
+ * Return value of useBacktrack hook.
83
+ */
84
+ export interface UseBacktrackReturn<T> {
85
+ /** Current state */
86
+ readonly currentState: T;
87
+ /** Backtrack state information */
88
+ readonly backtrackState: BacktrackState;
89
+ /** All available branches */
90
+ readonly branches: ReadonlyArray<Branch<T>>;
91
+ /** Push a new state to history */
92
+ readonly push: (state: T, description?: string) => void;
93
+ /** Undo to previous state */
94
+ readonly undo: () => void;
95
+ /** Redo to next state */
96
+ readonly redo: () => void;
97
+ /** Create a new branch from current position */
98
+ readonly createBranch: (name?: string) => string;
99
+ /** Switch to a different branch */
100
+ readonly switchBranch: (branchId: string) => void;
101
+ /** Get branch by ID */
102
+ readonly getBranch: (branchId: string) => Branch<T> | undefined;
103
+ /** Reset to initial state */
104
+ readonly reset: () => void;
105
+ /** Go to specific point in history */
106
+ readonly goTo: (index: number) => void;
107
+ }
108
+
109
+ // =============================================================================
110
+ // Constants
111
+ // =============================================================================
112
+
113
+ /** Default maximum history length */
114
+ const DEFAULT_MAX_HISTORY = 100;
115
+
116
+ /** Main branch identifier */
117
+ const MAIN_BRANCH_ID = "main";
118
+
119
+ // =============================================================================
120
+ // Internal State Types
121
+ // =============================================================================
122
+
123
+ interface InternalState<T> {
124
+ readonly branches: Record<string, Branch<T>>;
125
+ readonly currentBranchId: string;
126
+ readonly currentIndex: number;
127
+ readonly maxHistory: number;
128
+ }
129
+
130
+ type Action<T> =
131
+ | { type: "PUSH"; state: T; description?: string }
132
+ | { type: "UNDO" }
133
+ | { type: "REDO" }
134
+ | { type: "GO_TO"; index: number }
135
+ | { type: "CREATE_BRANCH"; name?: string; newBranchId: string }
136
+ | { type: "SWITCH_BRANCH"; branchId: string }
137
+ | { type: "RESET"; initialState: T };
138
+
139
+ // =============================================================================
140
+ // Utility Functions
141
+ // =============================================================================
142
+
143
+ /**
144
+ * Generate a unique ID for snapshots and branches.
145
+ */
146
+ function generateId(): string {
147
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
148
+ }
149
+
150
+ /**
151
+ * Create a new snapshot.
152
+ */
153
+ function createSnapshot<T>(state: T, description?: string): HistorySnapshot<T> {
154
+ return {
155
+ id: generateId(),
156
+ state,
157
+ timestamp: Date.now(),
158
+ description,
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Create initial branch with initial state.
164
+ */
165
+ function createInitialBranch<T>(initialState: T): Branch<T> {
166
+ return {
167
+ id: MAIN_BRANCH_ID,
168
+ name: "Main",
169
+ forkPoint: 0,
170
+ history: [createSnapshot(initialState, "Initial state")],
171
+ parentBranchId: null,
172
+ createdAt: Date.now(),
173
+ };
174
+ }
175
+
176
+ // =============================================================================
177
+ // Reducer
178
+ // =============================================================================
179
+
180
+ function reducer<T>(state: InternalState<T>, action: Action<T>): InternalState<T> {
181
+ const currentBranch = state.branches[state.currentBranchId];
182
+ if (!currentBranch) {
183
+ return state;
184
+ }
185
+
186
+ switch (action.type) {
187
+ case "PUSH": {
188
+ const newSnapshot = createSnapshot(action.state, action.description);
189
+
190
+ // If we're not at the end, truncate future history
191
+ const truncatedHistory = currentBranch.history.slice(0, state.currentIndex + 1);
192
+
193
+ // Add new snapshot
194
+ let newHistory = [...truncatedHistory, newSnapshot];
195
+
196
+ // Enforce max history limit
197
+ if (newHistory.length > state.maxHistory) {
198
+ newHistory = newHistory.slice(newHistory.length - state.maxHistory);
199
+ }
200
+
201
+ const updatedBranch: Branch<T> = {
202
+ ...currentBranch,
203
+ history: newHistory,
204
+ };
205
+
206
+ return {
207
+ ...state,
208
+ branches: {
209
+ ...state.branches,
210
+ [state.currentBranchId]: updatedBranch,
211
+ },
212
+ currentIndex: newHistory.length - 1,
213
+ };
214
+ }
215
+
216
+ case "UNDO": {
217
+ if (state.currentIndex <= 0) {
218
+ return state;
219
+ }
220
+ return {
221
+ ...state,
222
+ currentIndex: state.currentIndex - 1,
223
+ };
224
+ }
225
+
226
+ case "REDO": {
227
+ if (state.currentIndex >= currentBranch.history.length - 1) {
228
+ return state;
229
+ }
230
+ return {
231
+ ...state,
232
+ currentIndex: state.currentIndex + 1,
233
+ };
234
+ }
235
+
236
+ case "GO_TO": {
237
+ const targetIndex = Math.max(0, Math.min(action.index, currentBranch.history.length - 1));
238
+ if (targetIndex === state.currentIndex) {
239
+ return state;
240
+ }
241
+ return {
242
+ ...state,
243
+ currentIndex: targetIndex,
244
+ };
245
+ }
246
+
247
+ case "CREATE_BRANCH": {
248
+ const branchName = action.name ?? `Branch ${Object.keys(state.branches).length}`;
249
+
250
+ // Copy history up to current point
251
+ const forkedHistory = currentBranch.history.slice(0, state.currentIndex + 1);
252
+
253
+ const newBranch: Branch<T> = {
254
+ id: action.newBranchId,
255
+ name: branchName,
256
+ forkPoint: state.currentIndex,
257
+ history: forkedHistory,
258
+ parentBranchId: state.currentBranchId,
259
+ createdAt: Date.now(),
260
+ };
261
+
262
+ return {
263
+ ...state,
264
+ branches: {
265
+ ...state.branches,
266
+ [action.newBranchId]: newBranch,
267
+ },
268
+ currentBranchId: action.newBranchId,
269
+ currentIndex: forkedHistory.length - 1,
270
+ };
271
+ }
272
+
273
+ case "SWITCH_BRANCH": {
274
+ const targetBranch = state.branches[action.branchId];
275
+ if (!targetBranch) {
276
+ return state;
277
+ }
278
+ return {
279
+ ...state,
280
+ currentBranchId: action.branchId,
281
+ currentIndex: targetBranch.history.length - 1,
282
+ };
283
+ }
284
+
285
+ case "RESET": {
286
+ const initialBranch = createInitialBranch(action.initialState);
287
+ return {
288
+ ...state,
289
+ branches: { [MAIN_BRANCH_ID]: initialBranch },
290
+ currentBranchId: MAIN_BRANCH_ID,
291
+ currentIndex: 0,
292
+ };
293
+ }
294
+ }
295
+ }
296
+
297
+ // =============================================================================
298
+ // Hook Implementation
299
+ // =============================================================================
300
+
301
+ /**
302
+ * Hook for managing conversation backtracking and branching.
303
+ *
304
+ * Provides undo/redo functionality with support for creating alternative
305
+ * conversation branches (forks) from any point in history.
306
+ *
307
+ * @example
308
+ * ```tsx
309
+ * function ConversationView() {
310
+ * const {
311
+ * currentState,
312
+ * backtrackState,
313
+ * push,
314
+ * undo,
315
+ * redo,
316
+ * createBranch,
317
+ * } = useBacktrack({
318
+ * initialState: { messages: [] },
319
+ * });
320
+ *
321
+ * // Ctrl+Z to undo
322
+ * useHotkeys([
323
+ * { key: 'z', ctrl: true, handler: undo },
324
+ * { key: 'y', ctrl: true, handler: redo },
325
+ * { key: 'b', ctrl: true, handler: () => createBranch() },
326
+ * ]);
327
+ *
328
+ * return (
329
+ * <Box>
330
+ * <Text>Can Undo: {backtrackState.canUndo ? 'Yes' : 'No'}</Text>
331
+ * <Text>Branch: {backtrackState.currentBranch}</Text>
332
+ * </Box>
333
+ * );
334
+ * }
335
+ * ```
336
+ */
337
+ export function useBacktrack<T>(options: UseBacktrackOptions<T>): UseBacktrackReturn<T> {
338
+ const { initialState, maxHistory = DEFAULT_MAX_HISTORY, onStateChange } = options;
339
+
340
+ // Initialize state
341
+ const [state, dispatch] = useReducer(reducer<T>, {
342
+ branches: { [MAIN_BRANCH_ID]: createInitialBranch(initialState) },
343
+ currentBranchId: MAIN_BRANCH_ID,
344
+ currentIndex: 0,
345
+ maxHistory,
346
+ });
347
+
348
+ // Get current branch and state
349
+ const currentBranch = state.branches[state.currentBranchId];
350
+ const currentSnapshot = currentBranch?.history[state.currentIndex];
351
+ const currentState = currentSnapshot?.state ?? initialState;
352
+
353
+ // Compute backtrack state
354
+ const backtrackState = useMemo<BacktrackState>(
355
+ () => ({
356
+ canUndo: state.currentIndex > 0,
357
+ canRedo: currentBranch ? state.currentIndex < currentBranch.history.length - 1 : false,
358
+ forkCount: Object.keys(state.branches).length - 1, // Exclude main branch
359
+ currentBranch: currentBranch?.name ?? "Main",
360
+ currentIndex: state.currentIndex,
361
+ historyLength: currentBranch?.history.length ?? 0,
362
+ }),
363
+ [state.currentIndex, currentBranch, state.branches]
364
+ );
365
+
366
+ // Get all branches as array
367
+ const branches = useMemo<ReadonlyArray<Branch<T>>>(
368
+ () => Object.values(state.branches) as ReadonlyArray<Branch<T>>,
369
+ [state.branches]
370
+ );
371
+
372
+ // Action handlers
373
+ const push = useCallback(
374
+ (newState: T, description?: string) => {
375
+ dispatch({ type: "PUSH", state: newState, description });
376
+ onStateChange?.(newState, "push");
377
+ },
378
+ [onStateChange]
379
+ );
380
+
381
+ const undo = useCallback(() => {
382
+ if (state.currentIndex > 0) {
383
+ dispatch({ type: "UNDO" });
384
+ const prevState = currentBranch?.history[state.currentIndex - 1]?.state;
385
+ if (prevState) {
386
+ onStateChange?.(prevState, "undo");
387
+ }
388
+ }
389
+ }, [state.currentIndex, currentBranch?.history, onStateChange]);
390
+
391
+ const redo = useCallback(() => {
392
+ if (currentBranch && state.currentIndex < currentBranch.history.length - 1) {
393
+ dispatch({ type: "REDO" });
394
+ const nextState = currentBranch.history[state.currentIndex + 1]?.state;
395
+ if (nextState) {
396
+ onStateChange?.(nextState, "redo");
397
+ }
398
+ }
399
+ }, [state.currentIndex, currentBranch, onStateChange]);
400
+
401
+ const createBranch = useCallback(
402
+ (name?: string): string => {
403
+ const newBranchId = generateId();
404
+ dispatch({ type: "CREATE_BRANCH", name, newBranchId });
405
+ onStateChange?.(currentState, "branch");
406
+ return newBranchId;
407
+ },
408
+ [currentState, onStateChange]
409
+ );
410
+
411
+ const switchBranch = useCallback((branchId: string) => {
412
+ dispatch({ type: "SWITCH_BRANCH", branchId });
413
+ }, []);
414
+
415
+ const getBranch = useCallback(
416
+ (branchId: string): Branch<T> | undefined => {
417
+ return state.branches[branchId] as Branch<T> | undefined;
418
+ },
419
+ [state.branches]
420
+ );
421
+
422
+ const reset = useCallback(() => {
423
+ dispatch({ type: "RESET", initialState });
424
+ }, [initialState]);
425
+
426
+ const goTo = useCallback((index: number) => {
427
+ dispatch({ type: "GO_TO", index });
428
+ }, []);
429
+
430
+ return {
431
+ currentState,
432
+ backtrackState,
433
+ branches,
434
+ push,
435
+ undo,
436
+ redo,
437
+ createBranch,
438
+ switchBranch,
439
+ getBranch,
440
+ reset,
441
+ goTo,
442
+ };
443
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Bracketed Paste Hook
3
+ *
4
+ * React hook that enables bracketed paste mode when mounted and ensures
5
+ * proper cleanup on unmount or process exit.
6
+ *
7
+ * @module tui/hooks/useBracketedPaste
8
+ */
9
+
10
+ import { useEffect } from "react";
11
+ import { disableBracketedPaste, enableBracketedPaste } from "../utils/bracketedPaste.js";
12
+
13
+ // =============================================================================
14
+ // Types
15
+ // =============================================================================
16
+
17
+ /**
18
+ * Options for the useBracketedPaste hook
19
+ */
20
+ export interface UseBracketedPasteOptions {
21
+ /**
22
+ * Whether bracketed paste mode should be enabled.
23
+ * @default true
24
+ */
25
+ readonly enabled?: boolean;
26
+ }
27
+
28
+ // =============================================================================
29
+ // Hook
30
+ // =============================================================================
31
+
32
+ /**
33
+ * Hook to manage bracketed paste mode lifecycle.
34
+ *
35
+ * Enables bracketed paste mode when the component mounts and disables it
36
+ * on unmount. Also handles process signals (SIGINT, SIGTERM) and beforeExit
37
+ * to ensure the terminal state is properly restored.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * function App() {
42
+ * // Enable bracketed paste for the entire app
43
+ * useBracketedPaste();
44
+ *
45
+ * return <MyComponents />;
46
+ * }
47
+ * ```
48
+ *
49
+ * @example
50
+ * ```tsx
51
+ * function ConditionalPaste() {
52
+ * const [pasteEnabled, setPasteEnabled] = useState(true);
53
+ *
54
+ * // Conditionally enable/disable
55
+ * useBracketedPaste({ enabled: pasteEnabled });
56
+ *
57
+ * return <MyComponents />;
58
+ * }
59
+ * ```
60
+ */
61
+ export function useBracketedPaste(options: UseBracketedPasteOptions = {}): void {
62
+ const { enabled = true } = options;
63
+
64
+ useEffect(() => {
65
+ if (!enabled) {
66
+ return;
67
+ }
68
+
69
+ // Enable bracketed paste mode
70
+ enableBracketedPaste();
71
+
72
+ // Cleanup function for graceful shutdown
73
+ const cleanup = () => {
74
+ disableBracketedPaste();
75
+ };
76
+
77
+ // Handle various exit scenarios
78
+ const handleSignal = () => {
79
+ cleanup();
80
+ // Let the signal propagate
81
+ };
82
+
83
+ const handleExit = () => {
84
+ cleanup();
85
+ };
86
+
87
+ // Register cleanup handlers
88
+ process.on("SIGINT", handleSignal);
89
+ process.on("SIGTERM", handleSignal);
90
+ process.on("beforeExit", handleExit);
91
+ process.on("exit", handleExit);
92
+
93
+ // Cleanup on unmount or when disabled
94
+ return () => {
95
+ cleanup();
96
+
97
+ // Remove event listeners
98
+ process.off("SIGINT", handleSignal);
99
+ process.off("SIGTERM", handleSignal);
100
+ process.off("beforeExit", handleExit);
101
+ process.off("exit", handleExit);
102
+ };
103
+ }, [enabled]);
104
+ }