@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,314 @@
1
+ /**
2
+ * FakeResponseLoader - Load and manage fake API responses for testing
3
+ *
4
+ * This module provides infrastructure for loading and managing mock API responses
5
+ * during E2E and integration testing. It enables deterministic testing without
6
+ * making actual API calls.
7
+ *
8
+ * @module cli/test/fixtures/fake-response-loader
9
+ */
10
+
11
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
12
+ import { join, resolve } from "node:path";
13
+
14
+ /**
15
+ * Supported stream event types for mock responses
16
+ */
17
+ export type MockEventType =
18
+ | "text"
19
+ | "reasoning"
20
+ | "tool_call_start"
21
+ | "tool_call_delta"
22
+ | "tool_call_end"
23
+ | "usage"
24
+ | "end"
25
+ | "error";
26
+
27
+ /**
28
+ * Mock stream event structure
29
+ */
30
+ export interface MockStreamEvent {
31
+ type: MockEventType;
32
+ content?: string;
33
+ toolCallId?: string;
34
+ toolName?: string;
35
+ arguments?: string;
36
+ stopReason?: string;
37
+ usage?: {
38
+ inputTokens: number;
39
+ outputTokens: number;
40
+ };
41
+ error?: {
42
+ code: string;
43
+ message: string;
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Mock response fixture structure
49
+ */
50
+ export interface MockResponse {
51
+ /** Unique identifier for this response fixture */
52
+ id: string;
53
+ /** Pattern to match against prompts */
54
+ promptPattern: string;
55
+ /** Whether the pattern is a regex (default: false) */
56
+ isRegex?: boolean;
57
+ /** Description of what this fixture tests */
58
+ description?: string;
59
+ /** Delay in milliseconds between events (simulates streaming) */
60
+ streamDelay?: number;
61
+ /** The mock events to return */
62
+ events: MockStreamEvent[];
63
+ }
64
+
65
+ /**
66
+ * Environment variable to enable fake responses mode
67
+ */
68
+ export const FAKE_RESPONSES_ENV = "VELLUM_FAKE_RESPONSES";
69
+
70
+ /**
71
+ * Environment variable for custom fixtures directory
72
+ */
73
+ export const FIXTURES_DIR_ENV = "VELLUM_FIXTURES_DIR";
74
+
75
+ /**
76
+ * Default fixtures directory relative to package root
77
+ */
78
+ export const DEFAULT_FIXTURES_DIR = "__fixtures__/responses";
79
+
80
+ /**
81
+ * FakeResponseLoader - Load and manage fake API responses for testing
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * const loader = new FakeResponseLoader();
86
+ * const response = loader.getResponse("Hello, world");
87
+ * if (response) {
88
+ * for (const event of response.events) {
89
+ * // Process mock events
90
+ * }
91
+ * }
92
+ * ```
93
+ */
94
+ export class FakeResponseLoader {
95
+ private fixtures: Map<string, MockResponse>;
96
+ private readonly fixturesDir: string;
97
+ private loaded = false;
98
+
99
+ /**
100
+ * Create a new FakeResponseLoader
101
+ *
102
+ * @param fixturesDir - Custom directory for fixtures (optional)
103
+ */
104
+ constructor(fixturesDir?: string) {
105
+ this.fixtures = new Map();
106
+ this.fixturesDir = fixturesDir ?? this.resolveDefaultFixturesDir();
107
+ }
108
+
109
+ /**
110
+ * Resolve the default fixtures directory
111
+ */
112
+ private resolveDefaultFixturesDir(): string {
113
+ // Check environment variable first
114
+ const envDir = process.env[FIXTURES_DIR_ENV];
115
+ if (envDir) {
116
+ return resolve(envDir);
117
+ }
118
+
119
+ // Default to package __fixtures__ directory
120
+ // Navigate from src/test/fixtures to package root
121
+ return resolve(__dirname, "../../..", DEFAULT_FIXTURES_DIR);
122
+ }
123
+
124
+ /**
125
+ * Load a single fixture from file
126
+ *
127
+ * @param name - Fixture filename (without .json extension)
128
+ * @returns The loaded fixture or null if not found
129
+ */
130
+ load(name: string): MockResponse | null {
131
+ const filename = name.endsWith(".json") ? name : `${name}.json`;
132
+ const filepath = join(this.fixturesDir, filename);
133
+
134
+ if (!existsSync(filepath)) {
135
+ return null;
136
+ }
137
+
138
+ try {
139
+ const content = readFileSync(filepath, "utf-8");
140
+ const fixture = JSON.parse(content) as MockResponse;
141
+
142
+ // Ensure fixture has an ID
143
+ if (!fixture.id) {
144
+ fixture.id = name.replace(/\.json$/, "");
145
+ }
146
+
147
+ // Cache the fixture
148
+ this.fixtures.set(fixture.id, fixture);
149
+
150
+ return fixture;
151
+ } catch (error) {
152
+ console.error(`Failed to load fixture ${name}:`, error);
153
+ return null;
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Load all fixtures from the fixtures directory
159
+ */
160
+ loadAll(): void {
161
+ if (this.loaded) {
162
+ return;
163
+ }
164
+
165
+ if (!existsSync(this.fixturesDir)) {
166
+ console.warn(`Fixtures directory not found: ${this.fixturesDir}`);
167
+ this.loaded = true;
168
+ return;
169
+ }
170
+
171
+ try {
172
+ const files = readdirSync(this.fixturesDir).filter((f) => f.endsWith(".json"));
173
+
174
+ for (const file of files) {
175
+ this.load(file);
176
+ }
177
+
178
+ this.loaded = true;
179
+ } catch (error) {
180
+ console.error("Failed to load fixtures:", error);
181
+ this.loaded = true;
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Get a response matching a prompt pattern
187
+ *
188
+ * @param prompt - The prompt to match against
189
+ * @returns Matching response or null if no match found
190
+ */
191
+ getResponse(prompt: string): MockResponse | null {
192
+ // Ensure all fixtures are loaded
193
+ this.loadAll();
194
+
195
+ // Search through fixtures for a match
196
+ for (const fixture of this.fixtures.values()) {
197
+ if (this.matchesPattern(prompt, fixture)) {
198
+ return fixture;
199
+ }
200
+ }
201
+
202
+ return null;
203
+ }
204
+
205
+ /**
206
+ * Check if a prompt matches a fixture's pattern
207
+ */
208
+ private matchesPattern(prompt: string, fixture: MockResponse): boolean {
209
+ const pattern = fixture.promptPattern;
210
+
211
+ if (fixture.isRegex) {
212
+ try {
213
+ const regex = new RegExp(pattern, "i");
214
+ return regex.test(prompt);
215
+ } catch {
216
+ return false;
217
+ }
218
+ }
219
+
220
+ // Simple substring match (case-insensitive)
221
+ return prompt.toLowerCase().includes(pattern.toLowerCase());
222
+ }
223
+
224
+ /**
225
+ * Get a fixture by ID
226
+ *
227
+ * @param id - The fixture ID
228
+ * @returns The fixture or null if not found
229
+ */
230
+ getById(id: string): MockResponse | null {
231
+ // Try cache first
232
+ if (this.fixtures.has(id)) {
233
+ return this.fixtures.get(id) ?? null;
234
+ }
235
+
236
+ // Try loading by name
237
+ return this.load(id);
238
+ }
239
+
240
+ /**
241
+ * Get all loaded fixtures
242
+ */
243
+ getAll(): MockResponse[] {
244
+ this.loadAll();
245
+ return Array.from(this.fixtures.values());
246
+ }
247
+
248
+ /**
249
+ * Clear all cached fixtures
250
+ */
251
+ clear(): void {
252
+ this.fixtures.clear();
253
+ this.loaded = false;
254
+ }
255
+
256
+ /**
257
+ * Get the fixtures directory path
258
+ */
259
+ getFixturesDir(): string {
260
+ return this.fixturesDir;
261
+ }
262
+
263
+ /**
264
+ * Check if fake responses mode is enabled
265
+ *
266
+ * @returns true if VELLUM_FAKE_RESPONSES env var is set to 'true' or '1'
267
+ */
268
+ static isEnabled(): boolean {
269
+ const value = process.env[FAKE_RESPONSES_ENV];
270
+ return value === "true" || value === "1";
271
+ }
272
+
273
+ /**
274
+ * Create a stream from a mock response
275
+ *
276
+ * @param response - The mock response to stream
277
+ * @returns AsyncIterable of mock stream events
278
+ */
279
+ static async *createStream(response: MockResponse): AsyncIterable<MockStreamEvent> {
280
+ const delay = response.streamDelay ?? 0;
281
+
282
+ for (const event of response.events) {
283
+ if (delay > 0) {
284
+ await new Promise((resolve) => setTimeout(resolve, delay));
285
+ }
286
+ yield event;
287
+ }
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Global singleton instance for convenience
293
+ */
294
+ let globalLoader: FakeResponseLoader | null = null;
295
+
296
+ /**
297
+ * Get the global FakeResponseLoader instance
298
+ *
299
+ * @returns The global loader instance
300
+ */
301
+ export function getFakeResponseLoader(): FakeResponseLoader {
302
+ if (!globalLoader) {
303
+ globalLoader = new FakeResponseLoader();
304
+ }
305
+ return globalLoader;
306
+ }
307
+
308
+ /**
309
+ * Reset the global loader instance (useful for tests)
310
+ */
311
+ export function resetFakeResponseLoader(): void {
312
+ globalLoader?.clear();
313
+ globalLoader = null;
314
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Test Fixtures Module
3
+ *
4
+ * Exports for test fixture utilities including the FakeResponseLoader
5
+ * for mocking API responses in E2E and integration tests.
6
+ *
7
+ * @module cli/test/fixtures
8
+ */
9
+
10
+ export {
11
+ DEFAULT_FIXTURES_DIR,
12
+ FAKE_RESPONSES_ENV,
13
+ FakeResponseLoader,
14
+ FIXTURES_DIR_ENV,
15
+ getFakeResponseLoader,
16
+ type MockEventType,
17
+ type MockResponse,
18
+ type MockStreamEvent,
19
+ resetFakeResponseLoader,
20
+ } from "./fake-response-loader.js";
@@ -0,0 +1,82 @@
1
+ /**
2
+ * MCP panel render tests
3
+ *
4
+ * Verifies basic read-only status output for the MCP sidebar panel.
5
+ *
6
+ * @vitest-environment node
7
+ */
8
+
9
+ import { createToolRegistry, type ToolExecutor } from "@vellum/core";
10
+ import { render } from "ink-testing-library";
11
+ import { act } from "react";
12
+ import { describe, expect, it, vi } from "vitest";
13
+
14
+ let mockConnections: Array<{ server: { name: string; statusInfo: unknown } }> = [];
15
+
16
+ vi.mock("@vellum/mcp", () => {
17
+ class MockMcpHub {
18
+ public connections = mockConnections as unknown[];
19
+
20
+ async initialize(): Promise<void> {}
21
+
22
+ async dispose(): Promise<void> {}
23
+ }
24
+
25
+ return {
26
+ McpHub: MockMcpHub,
27
+ createOAuthCredentialAdapter: vi.fn(),
28
+ getProcessManager: () => ({
29
+ onCleanup: vi.fn(),
30
+ }),
31
+ };
32
+ });
33
+
34
+ describe("McpPanel", () => {
35
+ it("renders server count and MCP tool count", async () => {
36
+ const { RootProvider, McpPanel } = await import("../index.js");
37
+
38
+ const registry = createToolRegistry();
39
+
40
+ registry.registerMcpTool(
41
+ "c1a2b3",
42
+ {
43
+ name: "ping",
44
+ description: "Ping",
45
+ inputSchema: { type: "object", properties: {} },
46
+ },
47
+ async () => "ok"
48
+ );
49
+
50
+ const executor: ToolExecutor = {
51
+ registerTool: vi.fn(),
52
+ } as unknown as ToolExecutor;
53
+
54
+ mockConnections = [
55
+ { server: { name: "Server A", statusInfo: { status: "connected" } } },
56
+ { server: { name: "Server B", statusInfo: { status: "failed", error: "boom" } } },
57
+ ];
58
+
59
+ const { lastFrame } = render(
60
+ <RootProvider theme="dark" toolRegistry={registry} toolExecutor={executor}>
61
+ <McpPanel isFocused={true} toolRegistry={registry} />
62
+ </RootProvider>
63
+ );
64
+
65
+ await act(async () => {
66
+ await Promise.resolve();
67
+ await Promise.resolve();
68
+ });
69
+
70
+ const frame = lastFrame() ?? "";
71
+
72
+ expect(frame).toContain("MCP");
73
+ expect(frame).toContain("Servers: 2");
74
+ expect(frame).toContain("MCP tools registered: 1");
75
+ expect(frame).toContain("Last error:");
76
+
77
+ // Footer hotkey hints (Alt primary)
78
+ expect(frame).toContain("Alt+K");
79
+ expect(frame).toContain("Alt+O");
80
+ expect(frame).toContain("MCP");
81
+ });
82
+ });
@@ -0,0 +1,78 @@
1
+ /**
2
+ * MCP wiring tests
3
+ *
4
+ * Ensures that the TUI-level McpProvider (via RootProvider) receives the shared
5
+ * ToolRegistry and ToolExecutor so MCP tools are registered into the same
6
+ * running tool system as the agent.
7
+ *
8
+ * @vitest-environment node
9
+ */
10
+
11
+ import { createToolRegistry, type ToolExecutor, type ToolRegistry } from "@vellum/core";
12
+ import { Text } from "ink";
13
+ import { render } from "ink-testing-library";
14
+ import { act } from "react";
15
+ import { describe, expect, it, vi } from "vitest";
16
+
17
+ let lastMcpHubOptions: Record<string, unknown> | null = null;
18
+
19
+ vi.mock("@vellum/mcp", () => {
20
+ class MockMcpHub {
21
+ public connections: unknown[] = [];
22
+
23
+ constructor(options: Record<string, unknown>) {
24
+ lastMcpHubOptions = options;
25
+ }
26
+
27
+ async initialize(): Promise<void> {}
28
+
29
+ async dispose(): Promise<void> {}
30
+ }
31
+
32
+ return {
33
+ McpHub: MockMcpHub,
34
+ createOAuthCredentialAdapter: vi.fn(),
35
+ getProcessManager: () => ({
36
+ onCleanup: vi.fn(),
37
+ }),
38
+ };
39
+ });
40
+
41
+ describe("MCP wiring", () => {
42
+ it("passes shared ToolRegistry and ToolExecutor into McpHub", async () => {
43
+ const { RootProvider } = await import("../index.js");
44
+
45
+ const registry: ToolRegistry = createToolRegistry();
46
+ const executor: ToolExecutor = {
47
+ // The provider only forwards this reference to McpHub.
48
+ registerTool: vi.fn(),
49
+ } as unknown as ToolExecutor;
50
+
51
+ lastMcpHubOptions = null;
52
+
53
+ render(
54
+ <RootProvider theme="dark" toolRegistry={registry} toolExecutor={executor}>
55
+ <Text>ok</Text>
56
+ </RootProvider>
57
+ );
58
+
59
+ // Allow effects to run.
60
+ await act(async () => {
61
+ await Promise.resolve();
62
+ await Promise.resolve();
63
+ });
64
+
65
+ expect(lastMcpHubOptions).not.toBeNull();
66
+ if (!lastMcpHubOptions) {
67
+ throw new Error("Expected McpHub to be constructed");
68
+ }
69
+
70
+ const options = lastMcpHubOptions as unknown as {
71
+ toolRegistry?: unknown;
72
+ toolExecutor?: unknown;
73
+ };
74
+
75
+ expect(options.toolRegistry).toBe(registry);
76
+ expect(options.toolExecutor).toBe(executor);
77
+ });
78
+ });