@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,267 @@
1
+ /**
2
+ * Output Assertions for CLI E2E Tests
3
+ *
4
+ * @module cli/test/e2e/assertions
5
+ */
6
+
7
+ import type { AssertionFailure, CLIResult, OutputMatcher } from "./types.js";
8
+
9
+ /**
10
+ * Assert CLI output against expected matchers
11
+ */
12
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Assertion function needs to check multiple output conditions
13
+ export function assertOutput(result: CLIResult, expected: OutputMatcher): AssertionFailure[] {
14
+ const failures: AssertionFailure[] = [];
15
+
16
+ // Check exit code
17
+ if (expected.exitCode !== undefined && result.exitCode !== expected.exitCode) {
18
+ failures.push({
19
+ type: "exitCode",
20
+ expected: expected.exitCode,
21
+ actual: result.exitCode,
22
+ message: `Expected exit code ${expected.exitCode}, got ${result.exitCode}`,
23
+ });
24
+ }
25
+
26
+ // Check stdout
27
+ if (expected.stdout !== undefined) {
28
+ if (typeof expected.stdout === "string") {
29
+ if (!result.stdout.includes(expected.stdout)) {
30
+ failures.push({
31
+ type: "stdout",
32
+ expected: expected.stdout,
33
+ actual: result.stdout,
34
+ message: `stdout does not contain expected string: "${expected.stdout}"`,
35
+ });
36
+ }
37
+ } else if (!expected.stdout.test(result.stdout)) {
38
+ failures.push({
39
+ type: "stdout",
40
+ expected: expected.stdout.toString(),
41
+ actual: result.stdout,
42
+ message: `stdout does not match pattern: ${expected.stdout.toString()}`,
43
+ });
44
+ }
45
+ }
46
+
47
+ // Check stderr
48
+ if (expected.stderr !== undefined) {
49
+ if (typeof expected.stderr === "string") {
50
+ if (!result.stderr.includes(expected.stderr)) {
51
+ failures.push({
52
+ type: "stderr",
53
+ expected: expected.stderr,
54
+ actual: result.stderr,
55
+ message: `stderr does not contain expected string: "${expected.stderr}"`,
56
+ });
57
+ }
58
+ } else if (!expected.stderr.test(result.stderr)) {
59
+ failures.push({
60
+ type: "stderr",
61
+ expected: expected.stderr.toString(),
62
+ actual: result.stderr,
63
+ message: `stderr does not match pattern: ${expected.stderr.toString()}`,
64
+ });
65
+ }
66
+ }
67
+
68
+ // Check contains (stdout + stderr combined)
69
+ if (expected.contains) {
70
+ const combined = result.stdout + result.stderr;
71
+ for (const text of expected.contains) {
72
+ if (!combined.includes(text)) {
73
+ failures.push({
74
+ type: "contains",
75
+ expected: text,
76
+ actual: combined,
77
+ message: `Output does not contain: "${text}"`,
78
+ });
79
+ }
80
+ }
81
+ }
82
+
83
+ // Check excludes (stdout + stderr combined)
84
+ if (expected.excludes) {
85
+ const combined = result.stdout + result.stderr;
86
+ for (const text of expected.excludes) {
87
+ if (combined.includes(text)) {
88
+ failures.push({
89
+ type: "excludes",
90
+ expected: `not "${text}"`,
91
+ actual: combined,
92
+ message: `Output should NOT contain: "${text}"`,
93
+ });
94
+ }
95
+ }
96
+ }
97
+
98
+ // Check timeout
99
+ if (result.timedOut) {
100
+ failures.push({
101
+ type: "timeout",
102
+ expected: "no timeout",
103
+ actual: "timed out",
104
+ message: `Process timed out after ${result.duration}ms`,
105
+ });
106
+ }
107
+
108
+ return failures;
109
+ }
110
+
111
+ /**
112
+ * Assert that output contains a string
113
+ */
114
+ export function assertContains(result: CLIResult, text: string): void {
115
+ const combined = result.stdout + result.stderr;
116
+ if (!combined.includes(text)) {
117
+ throw new Error(`Expected output to contain "${text}"\nActual:\n${combined}`);
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Assert that output does not contain a string
123
+ */
124
+ export function assertNotContains(result: CLIResult, text: string): void {
125
+ const combined = result.stdout + result.stderr;
126
+ if (combined.includes(text)) {
127
+ throw new Error(`Expected output NOT to contain "${text}"\nActual:\n${combined}`);
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Assert stdout matches exactly
133
+ */
134
+ export function assertStdout(result: CLIResult, expected: string | RegExp): void {
135
+ if (typeof expected === "string") {
136
+ if (result.stdout !== expected) {
137
+ throw new Error(`Expected stdout:\n${expected}\nActual:\n${result.stdout}`);
138
+ }
139
+ } else if (!expected.test(result.stdout)) {
140
+ throw new Error(`Expected stdout to match ${expected.toString()}\nActual:\n${result.stdout}`);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Assert stderr matches exactly
146
+ */
147
+ export function assertStderr(result: CLIResult, expected: string | RegExp): void {
148
+ if (typeof expected === "string") {
149
+ if (result.stderr !== expected) {
150
+ throw new Error(`Expected stderr:\n${expected}\nActual:\n${result.stderr}`);
151
+ }
152
+ } else if (!expected.test(result.stderr)) {
153
+ throw new Error(`Expected stderr to match ${expected.toString()}\nActual:\n${result.stderr}`);
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Assert exit code
159
+ */
160
+ export function assertExitCode(result: CLIResult, expected: number): void {
161
+ if (result.exitCode !== expected) {
162
+ throw new Error(
163
+ `Expected exit code ${expected}, got ${result.exitCode}\nstdout: ${result.stdout}\nstderr: ${result.stderr}`
164
+ );
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Assert process did not timeout
170
+ */
171
+ export function assertNoTimeout(result: CLIResult): void {
172
+ if (result.timedOut) {
173
+ throw new Error(
174
+ `Process timed out after ${result.duration}ms\nstdout: ${result.stdout}\nstderr: ${result.stderr}`
175
+ );
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Assert success (exit code 0, no timeout)
181
+ */
182
+ export function assertSuccess(result: CLIResult): void {
183
+ assertNoTimeout(result);
184
+ assertExitCode(result, 0);
185
+ }
186
+
187
+ /**
188
+ * Assert failure (non-zero exit code)
189
+ */
190
+ export function assertFailure(result: CLIResult, expectedCode?: number): void {
191
+ assertNoTimeout(result);
192
+ if (expectedCode !== undefined) {
193
+ assertExitCode(result, expectedCode);
194
+ } else if (result.exitCode === 0) {
195
+ throw new Error(
196
+ `Expected non-zero exit code, got 0\nstdout: ${result.stdout}\nstderr: ${result.stderr}`
197
+ );
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Assert output contains JSON
203
+ */
204
+ export function assertJSON(result: CLIResult): unknown {
205
+ try {
206
+ return JSON.parse(result.stdout) as unknown;
207
+ } catch {
208
+ throw new Error(`Expected stdout to be valid JSON\nActual:\n${result.stdout}`);
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Assert output contains lines in order
214
+ */
215
+ export function assertLinesInOrder(result: CLIResult, lines: string[]): void {
216
+ const combined = result.stdout + result.stderr;
217
+ let lastIndex = -1;
218
+
219
+ for (const line of lines) {
220
+ const index = combined.indexOf(line, lastIndex + 1);
221
+ if (index === -1) {
222
+ throw new Error(
223
+ `Expected to find "${line}" after position ${lastIndex + 1}\nActual:\n${combined}`
224
+ );
225
+ }
226
+ lastIndex = index;
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Create matcher for use with vitest expect
232
+ */
233
+ export const cliMatchers = {
234
+ toContainOutput(result: CLIResult, expected: string) {
235
+ const combined = result.stdout + result.stderr;
236
+ const pass = combined.includes(expected);
237
+ return {
238
+ pass,
239
+ message: () =>
240
+ pass
241
+ ? `Expected output NOT to contain "${expected}"`
242
+ : `Expected output to contain "${expected}"\nActual:\n${combined}`,
243
+ };
244
+ },
245
+
246
+ toExitWith(result: CLIResult, expected: number) {
247
+ const pass = result.exitCode === expected;
248
+ return {
249
+ pass,
250
+ message: () =>
251
+ pass
252
+ ? `Expected exit code NOT to be ${expected}`
253
+ : `Expected exit code ${expected}, got ${result.exitCode}`,
254
+ };
255
+ },
256
+
257
+ toSucceed(result: CLIResult) {
258
+ const pass = result.exitCode === 0 && !result.timedOut;
259
+ return {
260
+ pass,
261
+ message: () =>
262
+ pass
263
+ ? `Expected command NOT to succeed`
264
+ : `Expected command to succeed\nexit code: ${result.exitCode}\ntimedOut: ${result.timedOut}\nstdout: ${result.stdout}\nstderr: ${result.stderr}`,
265
+ };
266
+ },
267
+ };
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Test Fixtures - Temporary Directory Management
3
+ *
4
+ * @module cli/test/e2e/fixtures
5
+ */
6
+
7
+ import { mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+
11
+ /**
12
+ * Options for temp directory creation
13
+ */
14
+ export interface TempDirOptions {
15
+ /** Prefix for temp directory name */
16
+ prefix?: string;
17
+
18
+ /** Initial files to create */
19
+ files?: Record<string, string>;
20
+
21
+ /** Cleanup on process exit */
22
+ autoCleanup?: boolean;
23
+ }
24
+
25
+ /**
26
+ * Temporary directory manager
27
+ */
28
+ export class TempDir {
29
+ private readonly path: string;
30
+ private cleaned = false;
31
+
32
+ private constructor(path: string) {
33
+ this.path = path;
34
+ }
35
+
36
+ /**
37
+ * Get the temp directory path
38
+ */
39
+ get dir(): string {
40
+ return this.path;
41
+ }
42
+
43
+ /**
44
+ * Create a new temp directory
45
+ */
46
+ static async create(options: TempDirOptions = {}): Promise<TempDir> {
47
+ const prefix = options.prefix ?? "vellum-e2e-";
48
+ const path = await mkdtemp(join(tmpdir(), prefix));
49
+ const tempDir = new TempDir(path);
50
+
51
+ // Create initial files
52
+ if (options.files) {
53
+ for (const [name, content] of Object.entries(options.files)) {
54
+ await tempDir.writeFile(name, content);
55
+ }
56
+ }
57
+
58
+ // Register cleanup on exit
59
+ if (options.autoCleanup) {
60
+ process.on("exit", () => {
61
+ void tempDir.cleanup();
62
+ });
63
+ }
64
+
65
+ return tempDir;
66
+ }
67
+
68
+ /**
69
+ * Write a file to the temp directory
70
+ */
71
+ async writeFile(relativePath: string, content: string): Promise<string> {
72
+ const fullPath = join(this.path, relativePath);
73
+ const dir = join(fullPath, "..");
74
+ await mkdir(dir, { recursive: true });
75
+ await writeFile(fullPath, content, "utf-8");
76
+ return fullPath;
77
+ }
78
+
79
+ /**
80
+ * Read a file from the temp directory
81
+ */
82
+ async readFile(relativePath: string): Promise<string> {
83
+ const fullPath = join(this.path, relativePath);
84
+ return readFile(fullPath, "utf-8");
85
+ }
86
+
87
+ /**
88
+ * Check if a file exists
89
+ */
90
+ async exists(relativePath: string): Promise<boolean> {
91
+ const fullPath = join(this.path, relativePath);
92
+ try {
93
+ await stat(fullPath);
94
+ return true;
95
+ } catch {
96
+ return false;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Create a subdirectory
102
+ */
103
+ async mkdir(relativePath: string): Promise<string> {
104
+ const fullPath = join(this.path, relativePath);
105
+ await mkdir(fullPath, { recursive: true });
106
+ return fullPath;
107
+ }
108
+
109
+ /**
110
+ * Get full path for a relative path
111
+ */
112
+ resolve(relativePath: string): string {
113
+ return join(this.path, relativePath);
114
+ }
115
+
116
+ /**
117
+ * Clean up the temp directory
118
+ */
119
+ async cleanup(): Promise<void> {
120
+ if (this.cleaned) return;
121
+ this.cleaned = true;
122
+
123
+ try {
124
+ await rm(this.path, { recursive: true, force: true });
125
+ } catch {
126
+ // Ignore cleanup errors
127
+ }
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Fixture manager for managing multiple fixtures
133
+ */
134
+ export class FixtureManager {
135
+ private readonly fixtures: TempDir[] = [];
136
+
137
+ /**
138
+ * Create a new temp directory
139
+ */
140
+ async createTempDir(options?: TempDirOptions): Promise<TempDir> {
141
+ const tempDir = await TempDir.create(options);
142
+ this.fixtures.push(tempDir);
143
+ return tempDir;
144
+ }
145
+
146
+ /**
147
+ * Clean up all managed fixtures
148
+ */
149
+ async cleanup(): Promise<void> {
150
+ await Promise.all(this.fixtures.map((f) => f.cleanup()));
151
+ this.fixtures.length = 0;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Create a fixture with a vellum project structure
157
+ */
158
+ export async function createProjectFixture(): Promise<TempDir> {
159
+ return TempDir.create({
160
+ prefix: "vellum-project-",
161
+ files: {
162
+ "package.json": JSON.stringify(
163
+ {
164
+ name: "test-project",
165
+ version: "1.0.0",
166
+ type: "module",
167
+ },
168
+ null,
169
+ 2
170
+ ),
171
+ ".vellum/config.json": JSON.stringify(
172
+ {
173
+ version: "1.0",
174
+ },
175
+ null,
176
+ 2
177
+ ),
178
+ },
179
+ });
180
+ }
181
+
182
+ /**
183
+ * Create fixture with git repository
184
+ */
185
+ export async function createGitFixture(): Promise<TempDir> {
186
+ const tempDir = await createProjectFixture();
187
+ await tempDir.mkdir(".git");
188
+ await tempDir.writeFile(".git/config", "[core]\n\trepositoryformatversion = 0\n");
189
+ await tempDir.writeFile(".git/HEAD", "ref: refs/heads/main\n");
190
+ return tempDir;
191
+ }
192
+
193
+ /**
194
+ * Vitest-compatible fixture helpers
195
+ */
196
+ export function useFixtures() {
197
+ const manager = new FixtureManager();
198
+
199
+ return {
200
+ manager,
201
+ createTempDir: (options?: TempDirOptions) => manager.createTempDir(options),
202
+ cleanup: () => manager.cleanup(),
203
+ };
204
+ }