@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,416 @@
1
+ /**
2
+ * BracketedPasteContext Tests
3
+ *
4
+ * Tests for the BracketedPasteContext provider and related hooks.
5
+ *
6
+ * Note: Tests that require stdin events are tested via direct context
7
+ * subscription since ink-testing-library provides its own stdin handling.
8
+ *
9
+ * @module @vellum/cli
10
+ */
11
+
12
+ import { Text } from "ink";
13
+ import { render } from "ink-testing-library";
14
+ import type { ReactNode } from "react";
15
+ import { useEffect } from "react";
16
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
17
+ import {
18
+ BracketedPasteProvider,
19
+ useBracketedPasteContext,
20
+ useIsPasting,
21
+ usePasteHandler,
22
+ } from "../BracketedPasteContext.js";
23
+
24
+ // =============================================================================
25
+ // Mocks
26
+ // =============================================================================
27
+
28
+ // Process event listeners tracking
29
+ const processListeners: Map<string, Set<() => void>> = new Map();
30
+ const originalOn = process.on.bind(process);
31
+ const originalOff = process.off.bind(process);
32
+ const originalWrite = process.stdout.write;
33
+ let writtenData: string[] = [];
34
+
35
+ beforeEach(() => {
36
+ writtenData = [];
37
+ processListeners.clear();
38
+
39
+ // Mock stdout.write
40
+ process.stdout.write = vi.fn((data: string | Uint8Array) => {
41
+ writtenData.push(typeof data === "string" ? data : data.toString());
42
+ return true;
43
+ }) as typeof process.stdout.write;
44
+
45
+ // Mock process event listeners
46
+ process.on = vi.fn((event: string, listener: () => void) => {
47
+ if (!processListeners.has(event)) {
48
+ processListeners.set(event, new Set());
49
+ }
50
+ processListeners.get(event)?.add(listener);
51
+ return process;
52
+ }) as typeof process.on;
53
+
54
+ process.off = vi.fn((event: string, listener: () => void) => {
55
+ processListeners.get(event)?.delete(listener);
56
+ return process;
57
+ }) as typeof process.off;
58
+ });
59
+
60
+ afterEach(() => {
61
+ process.stdout.write = originalWrite;
62
+ process.on = originalOn;
63
+ process.off = originalOff;
64
+ });
65
+
66
+ // =============================================================================
67
+ // Test Helpers
68
+ // =============================================================================
69
+
70
+ /**
71
+ * Wrapper component for testing context
72
+ */
73
+ function TestWrapper({ children, enabled = true }: { children: ReactNode; enabled?: boolean }) {
74
+ return <BracketedPasteProvider enabled={enabled}>{children}</BracketedPasteProvider>;
75
+ }
76
+
77
+ // =============================================================================
78
+ // Tests
79
+ // =============================================================================
80
+
81
+ describe("BracketedPasteContext", () => {
82
+ describe("BracketedPasteProvider", () => {
83
+ it("renders children", () => {
84
+ const { lastFrame } = render(
85
+ <TestWrapper>
86
+ <Text>child content</Text>
87
+ </TestWrapper>
88
+ );
89
+
90
+ expect(lastFrame()).toContain("child content");
91
+ });
92
+
93
+ // Note: enable/disable tests depend on stdin being available.
94
+ // ink-testing-library provides a mock stdin that may not trigger
95
+ // the useEffect that calls enableBracketedPaste. These behaviors
96
+ // are tested indirectly through the utility function tests.
97
+ it.skip("enables bracketed paste mode on mount (requires real stdin)", () => {
98
+ render(
99
+ <TestWrapper>
100
+ <Text>test</Text>
101
+ </TestWrapper>
102
+ );
103
+
104
+ // Verify enable sequence was written
105
+ expect(writtenData.some((d) => d.includes("\x1b[?2004h"))).toBe(true);
106
+ });
107
+
108
+ it.skip("disables bracketed paste mode on unmount (requires real stdin)", () => {
109
+ const { unmount } = render(
110
+ <TestWrapper>
111
+ <Text>test</Text>
112
+ </TestWrapper>
113
+ );
114
+
115
+ writtenData = [];
116
+ unmount();
117
+
118
+ // Verify disable sequence was written
119
+ expect(writtenData.some((d) => d.includes("\x1b[?2004l"))).toBe(true);
120
+ });
121
+
122
+ it("does not enable when enabled=false", () => {
123
+ render(
124
+ <TestWrapper enabled={false}>
125
+ <Text>test</Text>
126
+ </TestWrapper>
127
+ );
128
+
129
+ // Should not contain enable sequence
130
+ expect(writtenData.some((d) => d.includes("\x1b[?2004h"))).toBe(false);
131
+ });
132
+
133
+ it("registers process signal handlers when enabled", () => {
134
+ render(
135
+ <TestWrapper>
136
+ <Text>test</Text>
137
+ </TestWrapper>
138
+ );
139
+
140
+ // At least SIGINT or SIGTERM should be registered
141
+ expect(processListeners.has("SIGINT") || processListeners.has("SIGTERM")).toBe(true);
142
+ });
143
+
144
+ it("cleans up process handlers on unmount", () => {
145
+ const { unmount } = render(
146
+ <TestWrapper>
147
+ <Text>test</Text>
148
+ </TestWrapper>
149
+ );
150
+
151
+ const sigintBefore = processListeners.get("SIGINT")?.size ?? 0;
152
+ unmount();
153
+ const sigintAfter = processListeners.get("SIGINT")?.size ?? 0;
154
+
155
+ // Handlers should be removed
156
+ expect(sigintAfter).toBeLessThanOrEqual(sigintBefore);
157
+ });
158
+ });
159
+
160
+ describe("useBracketedPasteContext", () => {
161
+ it("throws when used outside provider", () => {
162
+ // Test that the hook throws by catching in the component
163
+ let thrownError: Error | undefined;
164
+
165
+ function ThrowingComponent() {
166
+ try {
167
+ // biome-ignore lint/correctness/useHookAtTopLevel: Testing that hook throws outside provider
168
+ useBracketedPasteContext();
169
+ } catch (e) {
170
+ thrownError = e as Error;
171
+ }
172
+ return null;
173
+ }
174
+
175
+ render(<ThrowingComponent />);
176
+
177
+ expect(thrownError).toBeDefined();
178
+ expect(thrownError?.message).toBe(
179
+ "useBracketedPasteContext must be used within BracketedPasteProvider"
180
+ );
181
+ });
182
+
183
+ it("returns context value inside provider", () => {
184
+ let contextValue: ReturnType<typeof useBracketedPasteContext> | undefined;
185
+
186
+ function Consumer() {
187
+ contextValue = useBracketedPasteContext();
188
+ return null;
189
+ }
190
+
191
+ render(
192
+ <TestWrapper>
193
+ <Consumer />
194
+ </TestWrapper>
195
+ );
196
+
197
+ expect(contextValue).toBeDefined();
198
+ expect(contextValue?.subscribe).toBeInstanceOf(Function);
199
+ expect(typeof contextValue?.isPasting).toBe("boolean");
200
+ });
201
+
202
+ it("subscribe returns unsubscribe function", () => {
203
+ let unsubscribe: (() => void) | null = null;
204
+
205
+ function Consumer() {
206
+ const { subscribe } = useBracketedPasteContext();
207
+ useEffect(() => {
208
+ unsubscribe = subscribe(() => {});
209
+ }, [subscribe]);
210
+ return null;
211
+ }
212
+
213
+ render(
214
+ <TestWrapper>
215
+ <Consumer />
216
+ </TestWrapper>
217
+ );
218
+
219
+ expect(unsubscribe).toBeInstanceOf(Function);
220
+ });
221
+ });
222
+
223
+ describe("usePasteHandler", () => {
224
+ it("does not throw when outside provider", () => {
225
+ const pasteHandler = vi.fn();
226
+
227
+ function OrphanConsumer() {
228
+ usePasteHandler(pasteHandler);
229
+ return null;
230
+ }
231
+
232
+ // Should not throw when rendered without provider
233
+ expect(() => {
234
+ render(<OrphanConsumer />);
235
+ }).not.toThrow();
236
+ });
237
+
238
+ it("handler is not called when outside provider", () => {
239
+ const pasteHandler = vi.fn();
240
+
241
+ function OrphanConsumer() {
242
+ usePasteHandler(pasteHandler);
243
+ return null;
244
+ }
245
+
246
+ render(<OrphanConsumer />);
247
+
248
+ // Should not have been called
249
+ expect(pasteHandler).not.toHaveBeenCalled();
250
+ });
251
+
252
+ it("subscribes when inside provider", () => {
253
+ const pasteHandler = vi.fn();
254
+
255
+ function Consumer() {
256
+ usePasteHandler(pasteHandler);
257
+ return null;
258
+ }
259
+
260
+ // Should not throw
261
+ expect(() => {
262
+ render(
263
+ <TestWrapper>
264
+ <Consumer />
265
+ </TestWrapper>
266
+ );
267
+ }).not.toThrow();
268
+ });
269
+ });
270
+
271
+ describe("useIsPasting", () => {
272
+ it("returns false initially", () => {
273
+ let isPasting: boolean | undefined;
274
+
275
+ function Consumer() {
276
+ isPasting = useIsPasting();
277
+ return null;
278
+ }
279
+
280
+ render(
281
+ <TestWrapper>
282
+ <Consumer />
283
+ </TestWrapper>
284
+ );
285
+
286
+ expect(isPasting).toBe(false);
287
+ });
288
+
289
+ it("returns false when outside provider", () => {
290
+ let isPasting: boolean | undefined;
291
+
292
+ function Consumer() {
293
+ isPasting = useIsPasting();
294
+ return null;
295
+ }
296
+
297
+ render(<Consumer />);
298
+
299
+ expect(isPasting).toBe(false);
300
+ });
301
+ });
302
+
303
+ describe("subscription mechanism", () => {
304
+ it("allows subscribing via context", () => {
305
+ let contextRef: ReturnType<typeof useBracketedPasteContext> | undefined;
306
+
307
+ function Consumer() {
308
+ const ctx = useBracketedPasteContext();
309
+ contextRef = ctx;
310
+ return null;
311
+ }
312
+
313
+ render(
314
+ <TestWrapper>
315
+ <Consumer />
316
+ </TestWrapper>
317
+ );
318
+
319
+ // Context should be available
320
+ expect(contextRef).toBeDefined();
321
+ expect(contextRef?.subscribe).toBeInstanceOf(Function);
322
+ });
323
+
324
+ it("unsubscribe function is returned", () => {
325
+ let unsubscribeFn: (() => void) | null = null;
326
+
327
+ function Consumer() {
328
+ const { subscribe } = useBracketedPasteContext();
329
+
330
+ useEffect(() => {
331
+ unsubscribeFn = subscribe(() => {});
332
+ return () => {
333
+ unsubscribeFn?.();
334
+ };
335
+ }, [subscribe]);
336
+
337
+ return null;
338
+ }
339
+
340
+ render(
341
+ <TestWrapper>
342
+ <Consumer />
343
+ </TestWrapper>
344
+ );
345
+
346
+ // Unsubscribe should be a function
347
+ expect(unsubscribeFn).toBeInstanceOf(Function);
348
+ });
349
+
350
+ it("multiple consumers can subscribe", () => {
351
+ let subscribeCount = 0;
352
+
353
+ function Consumer1() {
354
+ const { subscribe } = useBracketedPasteContext();
355
+ useEffect(() => {
356
+ subscribe(() => {});
357
+ subscribeCount++;
358
+ }, [subscribe]);
359
+ return null;
360
+ }
361
+
362
+ function Consumer2() {
363
+ const { subscribe } = useBracketedPasteContext();
364
+ useEffect(() => {
365
+ subscribe(() => {});
366
+ subscribeCount++;
367
+ }, [subscribe]);
368
+ return null;
369
+ }
370
+
371
+ render(
372
+ <TestWrapper>
373
+ <Consumer1 />
374
+ <Consumer2 />
375
+ </TestWrapper>
376
+ );
377
+
378
+ // Both consumers should have subscribed
379
+ expect(subscribeCount).toBe(2);
380
+ });
381
+ });
382
+
383
+ describe("lifecycle", () => {
384
+ it("cleans up on unmount without errors", () => {
385
+ const { unmount } = render(
386
+ <TestWrapper>
387
+ <Text>test</Text>
388
+ </TestWrapper>
389
+ );
390
+
391
+ // Should not throw
392
+ expect(() => {
393
+ unmount();
394
+ }).not.toThrow();
395
+ });
396
+
397
+ it("signal handler cleanup disables paste mode", () => {
398
+ render(
399
+ <TestWrapper>
400
+ <Text>test</Text>
401
+ </TestWrapper>
402
+ );
403
+
404
+ // Get a SIGINT handler if registered
405
+ const sigintHandlers = processListeners.get("SIGINT");
406
+ if (sigintHandlers && sigintHandlers.size > 0) {
407
+ writtenData = [];
408
+ const handler = Array.from(sigintHandlers)[0];
409
+ handler?.();
410
+
411
+ // Should have written disable sequence
412
+ expect(writtenData.some((d) => d.includes("\x1b[?2004l"))).toBe(true);
413
+ }
414
+ });
415
+ });
416
+ });
@@ -0,0 +1,140 @@
1
+ /**
2
+ * TUI Context
3
+ *
4
+ * React contexts for state management in the Vellum TUI.
5
+ *
6
+ * @module tui/context
7
+ */
8
+
9
+ // Animation context (global animation loop for spinners, etc.)
10
+ export {
11
+ AnimationContext,
12
+ type AnimationContextValue,
13
+ AnimationProvider,
14
+ type AnimationProviderProps,
15
+ type AnimationState,
16
+ useAnimation,
17
+ useAnimationFrame,
18
+ } from "./AnimationContext.js";
19
+
20
+ // Application state context
21
+ export {
22
+ type AppAction,
23
+ AppContext,
24
+ type AppContextValue,
25
+ type AppMode,
26
+ AppProvider,
27
+ type AppProviderProps,
28
+ type AppState,
29
+ type FocusedArea,
30
+ initialState,
31
+ type ResetAction,
32
+ type SetErrorAction,
33
+ type SetFocusedAreaAction,
34
+ type SetLoadingAction,
35
+ type SetModeAction,
36
+ type SetVimModeAction,
37
+ type ToggleVimModeAction,
38
+ useApp,
39
+ } from "./AppContext.js";
40
+
41
+ // Bracketed paste context
42
+ export {
43
+ BracketedPasteProvider,
44
+ type PasteHandler,
45
+ useBracketedPasteContext,
46
+ useIsPasting,
47
+ usePasteHandler,
48
+ } from "./BracketedPasteContext.js";
49
+
50
+ // LSP Context
51
+ export {
52
+ type LspContextState,
53
+ LspProvider,
54
+ type LspProviderProps,
55
+ useLsp,
56
+ useLspOptional,
57
+ } from "./LspContext.js";
58
+
59
+ // T047: MCP Context
60
+ export {
61
+ type McpContextState,
62
+ McpProvider,
63
+ type McpProviderProps,
64
+ useMcp,
65
+ useMcpHub,
66
+ } from "./McpContext.js";
67
+ // Messages state context
68
+ export {
69
+ type AddMessageAction,
70
+ type AppendToMessageAction,
71
+ type ClearMessagesAction,
72
+ initialState as messagesInitialState,
73
+ type Message,
74
+ type MessageRole,
75
+ type MessagesAction,
76
+ MessagesContext,
77
+ type MessagesContextValue,
78
+ MessagesProvider,
79
+ type MessagesProviderProps,
80
+ type MessagesState,
81
+ type SetStreamingAction,
82
+ type ToolCallInfo,
83
+ type ToolCallStatus,
84
+ type UpdateMessageAction,
85
+ useMessages,
86
+ } from "./MessagesContext.js";
87
+ // Overflow tracking context (ported from Gemini CLI)
88
+ export {
89
+ OverflowContext,
90
+ type OverflowContextValue,
91
+ OverflowProvider,
92
+ type OverflowProviderProps,
93
+ type OverflowState,
94
+ useOverflow,
95
+ useOverflowOptional,
96
+ } from "./OverflowContext.js";
97
+ // Resilience context (rate limiting, retry feedback)
98
+ export {
99
+ type ResilienceContextState,
100
+ ResilienceProvider,
101
+ type ResilienceProviderProps,
102
+ type ResilienceStatus,
103
+ useIsResilienceActive,
104
+ useResilience,
105
+ useResilienceOptional,
106
+ useResilienceStatus,
107
+ } from "./ResilienceContext.js";
108
+ // Root provider composition
109
+ export { RootProvider, type RootProviderProps } from "./RootProvider.js";
110
+ // Scroll state context (ported from Gemini CLI)
111
+ export {
112
+ ScrollContext,
113
+ type ScrollContextValue,
114
+ ScrollProvider,
115
+ type ScrollProviderProps,
116
+ type ScrollState,
117
+ useScroll,
118
+ useScrollOptional,
119
+ useScrollState,
120
+ } from "./ScrollContext.js";
121
+
122
+ // Tools state context
123
+ export {
124
+ type AddExecutionAction,
125
+ type ApproveAllAction,
126
+ type ApproveExecutionAction,
127
+ type ClearExecutionsAction,
128
+ initialState as toolsInitialState,
129
+ type RejectExecutionAction,
130
+ type ToolExecution,
131
+ type ToolExecutionStatus,
132
+ type ToolsAction,
133
+ ToolsContext,
134
+ type ToolsContextValue,
135
+ ToolsProvider,
136
+ type ToolsProviderProps,
137
+ type ToolsState,
138
+ type UpdateExecutionAction,
139
+ useTools,
140
+ } from "./ToolsContext.js";