@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,142 @@
1
+ /**
2
+ * Command System Utilities
3
+ *
4
+ * Shared utility functions for the command system.
5
+ *
6
+ * @module cli/commands/utils
7
+ */
8
+
9
+ // =============================================================================
10
+ // T034B: isSlashCommand
11
+ // =============================================================================
12
+
13
+ /**
14
+ * Check if input is a slash command
15
+ *
16
+ * Returns true if the input starts with a forward slash after trimming.
17
+ * Handles edge cases:
18
+ * - Empty string → false
19
+ * - Whitespace only → false
20
+ * - Just "/" → false (no command name)
21
+ * - "/command" → true
22
+ * - " /command" → true (leading whitespace allowed)
23
+ *
24
+ * @param input - User input string to check
25
+ * @returns True if input is a slash command
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * isSlashCommand('/help') // true
30
+ * isSlashCommand(' /login') // true
31
+ * isSlashCommand('/a') // true
32
+ * isSlashCommand('/') // false (no command name)
33
+ * isSlashCommand('') // false
34
+ * isSlashCommand(' ') // false
35
+ * isSlashCommand('hello') // false
36
+ * isSlashCommand('//comment') // true (starts with /)
37
+ * ```
38
+ */
39
+ export function isSlashCommand(input: string): boolean {
40
+ // Handle empty or whitespace-only
41
+ if (!input || typeof input !== "string") {
42
+ return false;
43
+ }
44
+
45
+ const trimmed = input.trim();
46
+
47
+ // Must have at least 2 chars: "/" + command char
48
+ if (trimmed.length < 2) {
49
+ return false;
50
+ }
51
+
52
+ // Must start with "/"
53
+ if (trimmed[0] !== "/") {
54
+ return false;
55
+ }
56
+
57
+ // Second character must not be whitespace (ensures command name exists)
58
+ const secondChar = trimmed[1];
59
+ if (secondChar === " " || secondChar === "\t" || secondChar === "\n") {
60
+ return false;
61
+ }
62
+
63
+ return true;
64
+ }
65
+
66
+ // =============================================================================
67
+ // Additional Utilities
68
+ // =============================================================================
69
+
70
+ /**
71
+ * Extract command name from slash command input
72
+ *
73
+ * @param input - Slash command input (e.g., "/help topic")
74
+ * @returns Command name without slash, or null if not a valid command
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * extractCommandName('/help topic') // 'help'
79
+ * extractCommandName('/login') // 'login'
80
+ * extractCommandName('hello') // null
81
+ * ```
82
+ */
83
+ export function extractCommandName(input: string): string | null {
84
+ if (!isSlashCommand(input)) {
85
+ return null;
86
+ }
87
+
88
+ const trimmed = input.trim();
89
+ // Remove leading slash and split by whitespace
90
+ const parts = trimmed.slice(1).split(/\s+/);
91
+ return parts[0]?.toLowerCase() ?? null;
92
+ }
93
+
94
+ /**
95
+ * Split command input into command name and arguments
96
+ *
97
+ * @param input - Slash command input
98
+ * @returns Object with command name and args array, or null if invalid
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * parseCommandInput('/login anthropic --store keychain')
103
+ * // { command: 'login', args: ['anthropic', '--store', 'keychain'] }
104
+ * ```
105
+ */
106
+ export function parseCommandInput(input: string): { command: string; args: string[] } | null {
107
+ if (!isSlashCommand(input)) {
108
+ return null;
109
+ }
110
+
111
+ const trimmed = input.trim();
112
+ const parts = trimmed.slice(1).split(/\s+/);
113
+ const command = parts[0]?.toLowerCase() ?? "";
114
+ const args = parts.slice(1);
115
+
116
+ return { command, args };
117
+ }
118
+
119
+ /**
120
+ * Mask a sensitive value for display
121
+ *
122
+ * Shows first and last few characters with dots in between.
123
+ *
124
+ * @param value - Value to mask
125
+ * @param visibleChars - Number of visible chars at start and end (default: 4)
126
+ * @returns Masked string
127
+ *
128
+ * @example
129
+ * ```typescript
130
+ * maskValue('sk-1234567890abcdef') // 'sk-1...cdef'
131
+ * maskValue('short') // '****'
132
+ * ```
133
+ */
134
+ export function maskValue(value: string, visibleChars = 4): string {
135
+ if (value.length <= visibleChars * 2) {
136
+ return "*".repeat(Math.max(4, value.length));
137
+ }
138
+
139
+ const start = value.slice(0, visibleChars);
140
+ const end = value.slice(-visibleChars);
141
+ return `${start}...${end}`;
142
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Vim Mode Slash Command (T041)
3
+ *
4
+ * Provides the /vim command for toggling Vim editing mode.
5
+ *
6
+ * @module cli/commands/vim
7
+ */
8
+
9
+ import type { CommandContext, CommandResult, SlashCommand } from "./types.js";
10
+ import { success } from "./types.js";
11
+
12
+ // =============================================================================
13
+ // Module State
14
+ // =============================================================================
15
+
16
+ /**
17
+ * Callback to toggle vim mode.
18
+ * Set by the App component when initialized.
19
+ */
20
+ let vimToggleCallback: (() => void) | null = null;
21
+
22
+ /**
23
+ * Callback to check if vim mode is enabled.
24
+ * Set by the App component when initialized.
25
+ */
26
+ let vimEnabledCallback: (() => boolean) | null = null;
27
+
28
+ /**
29
+ * Set the vim mode callbacks for the /vim command.
30
+ * Called by the App component during initialization.
31
+ *
32
+ * @param toggle - Callback to toggle vim mode on/off
33
+ * @param isEnabled - Callback to check if vim mode is currently enabled
34
+ */
35
+ export function setVimCallbacks(toggle: () => void, isEnabled: () => boolean): void {
36
+ vimToggleCallback = toggle;
37
+ vimEnabledCallback = isEnabled;
38
+ }
39
+
40
+ /**
41
+ * Clear vim mode callbacks.
42
+ * Called during cleanup.
43
+ */
44
+ export function clearVimCallbacks(): void {
45
+ vimToggleCallback = null;
46
+ vimEnabledCallback = null;
47
+ }
48
+
49
+ // =============================================================================
50
+ // /vim Command
51
+ // =============================================================================
52
+
53
+ /**
54
+ * /vim command - Toggle Vim editing mode.
55
+ *
56
+ * When enabled:
57
+ * - Input field uses Vim-style modal editing
58
+ * - NORMAL mode: navigation and commands
59
+ * - INSERT mode: text entry (i, a, I, A, o, O)
60
+ * - VISUAL mode: text selection (v, V)
61
+ * - COMMAND mode: command line (:)
62
+ * - Press Escape to return to NORMAL mode
63
+ * - Press Ctrl+V to toggle vim mode on/off
64
+ *
65
+ * @example
66
+ * ```
67
+ * /vim - Toggle vim mode on/off
68
+ * /vim on - Enable vim mode
69
+ * /vim off - Disable vim mode
70
+ * ```
71
+ */
72
+ export const vimCommand: SlashCommand = {
73
+ name: "vim",
74
+ description: "Toggle Vim editing mode for input",
75
+ kind: "builtin",
76
+ category: "config",
77
+ aliases: ["vi"],
78
+ positionalArgs: [
79
+ {
80
+ name: "state",
81
+ type: "string",
82
+ description: "Explicitly set state: 'on' or 'off'",
83
+ required: false,
84
+ },
85
+ ],
86
+ examples: [
87
+ "/vim - Toggle vim mode on/off",
88
+ "/vim on - Enable vim mode",
89
+ "/vim off - Disable vim mode",
90
+ ],
91
+
92
+ execute: async (ctx: CommandContext): Promise<CommandResult> => {
93
+ const state = ctx.parsedArgs.positional[0] as string | undefined;
94
+
95
+ // Check if callbacks are available
96
+ if (!vimToggleCallback || !vimEnabledCallback) {
97
+ return success("Vim mode system not initialized.");
98
+ }
99
+
100
+ const currentlyEnabled = vimEnabledCallback();
101
+
102
+ // Handle explicit on/off
103
+ if (state === "on") {
104
+ if (currentlyEnabled) {
105
+ return success(
106
+ "Vim mode is already enabled.\n\nUse 'i' to enter INSERT mode, Escape to return to NORMAL mode."
107
+ );
108
+ }
109
+ vimToggleCallback();
110
+ return success(
111
+ "🟢 Vim mode enabled.\n\nYou are now in NORMAL mode. Press 'i' to enter INSERT mode for typing."
112
+ );
113
+ }
114
+
115
+ if (state === "off") {
116
+ if (!currentlyEnabled) {
117
+ return success("Vim mode is already disabled.");
118
+ }
119
+ vimToggleCallback();
120
+ return success("⚫ Vim mode disabled.\n\nReturned to standard input mode.");
121
+ }
122
+
123
+ // Toggle
124
+ vimToggleCallback();
125
+ const newState = vimEnabledCallback();
126
+
127
+ if (newState) {
128
+ return success(
129
+ "🟢 Vim mode enabled.\n\n" +
130
+ "You are now in NORMAL mode. Key bindings:\n" +
131
+ " • i, a, I, A, o, O - Enter INSERT mode\n" +
132
+ " • v, V - Enter VISUAL mode\n" +
133
+ " • : - Enter COMMAND mode\n" +
134
+ " • h, j, k, l - Navigation\n" +
135
+ " • Escape - Return to NORMAL mode\n" +
136
+ " • Ctrl+V - Toggle vim mode off\n\n" +
137
+ "Press 'i' to start typing."
138
+ );
139
+ }
140
+
141
+ return success("⚫ Vim mode disabled.\n\nReturned to standard input mode.");
142
+ },
143
+ };
144
+
145
+ // =============================================================================
146
+ // Export
147
+ // =============================================================================
148
+
149
+ /**
150
+ * All vim-related slash commands for registration.
151
+ */
152
+ export const vimSlashCommands: SlashCommand[] = [vimCommand];
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Workflow Slash Commands (T035)
3
+ *
4
+ * Provides slash commands for workflow management:
5
+ * - /workflow - List available workflows
6
+ * - /workflow {name} - Inject workflow instructions
7
+ *
8
+ * Workflows are loaded from .vellum/workflows/*.md files.
9
+ *
10
+ * @module cli/commands/workflow
11
+ * @see REQ-011
12
+ */
13
+
14
+ import { createWorkflowLoader, type Workflow, type WorkflowLoader } from "@vellum/core";
15
+ import { ICONS } from "../utils/icons.js";
16
+ import type { CommandContext, CommandResult, SlashCommand } from "./types.js";
17
+ import { error, pending, success } from "./types.js";
18
+
19
+ // =============================================================================
20
+ // Module State
21
+ // =============================================================================
22
+
23
+ /**
24
+ * Cached WorkflowLoader instance.
25
+ * Initialized lazily on first use.
26
+ */
27
+ let cachedLoader: WorkflowLoader | null = null;
28
+
29
+ /**
30
+ * Last workspace path used to create the loader.
31
+ */
32
+ let lastWorkspacePath: string | null = null;
33
+
34
+ /**
35
+ * Get or create WorkflowLoader for the given workspace.
36
+ *
37
+ * @param cwd - Current working directory (workspace root)
38
+ * @returns WorkflowLoader instance
39
+ */
40
+ function getLoader(cwd: string): WorkflowLoader {
41
+ // Create new loader if workspace changed
42
+ if (cachedLoader === null || lastWorkspacePath !== cwd) {
43
+ cachedLoader = createWorkflowLoader({ cwd });
44
+ lastWorkspacePath = cwd;
45
+ }
46
+ return cachedLoader;
47
+ }
48
+
49
+ /**
50
+ * Clear the cached loader (for testing).
51
+ */
52
+ export function clearWorkflowLoaderCache(): void {
53
+ cachedLoader = null;
54
+ lastWorkspacePath = null;
55
+ }
56
+
57
+ // =============================================================================
58
+ // Helper Functions
59
+ // =============================================================================
60
+
61
+ /**
62
+ * Format workflow list for display.
63
+ *
64
+ * @param workflows - Array of loaded workflows
65
+ * @returns Formatted string for TUI display
66
+ */
67
+ function formatWorkflowList(workflows: Workflow[]): string {
68
+ if (workflows.length === 0) {
69
+ return `📂 No workflows found.
70
+
71
+ Create workflows in .vellum/workflows/*.md with YAML frontmatter:
72
+
73
+ \`\`\`yaml
74
+ ---
75
+ id: deploy
76
+ name: Deploy to Production
77
+ description: Step-by-step deployment workflow
78
+ steps:
79
+ - id: build
80
+ prompt: "Build the project for production"
81
+ - id: test
82
+ prompt: "Run all tests"
83
+ - id: deploy
84
+ prompt: "Deploy to production server"
85
+ ---
86
+ \`\`\`
87
+
88
+ Then run: /workflow deploy`;
89
+ }
90
+
91
+ const lines = [`${ICONS.workflow} Available Workflows:\n`];
92
+
93
+ for (const wf of workflows) {
94
+ const stepCount = wf.steps.length;
95
+ const source = wf.source === "project" ? "[project]" : "[user]";
96
+ lines.push(` ${ICONS.bullet} ${wf.id} - ${wf.name || wf.description || "No description"}`);
97
+ lines.push(` ${stepCount} step${stepCount !== 1 ? "s" : ""} ${source}\n`);
98
+ }
99
+
100
+ lines.push("\nUsage: /workflow <name> [--var=value ...]");
101
+
102
+ return lines.join("\n");
103
+ }
104
+
105
+ /**
106
+ * Format workflow instructions for injection.
107
+ *
108
+ * @param workflow - The workflow to format
109
+ * @param variables - Variable values for interpolation
110
+ * @returns Formatted workflow instructions
111
+ */
112
+ function formatWorkflowInstructions(workflow: Workflow, variables: Record<string, string>): string {
113
+ const loader = getLoader(lastWorkspacePath ?? process.cwd());
114
+ return loader.getWorkflowInstructions(workflow, variables);
115
+ }
116
+
117
+ /**
118
+ * Parse variable arguments from command args.
119
+ * Format: --var=value or --var value
120
+ *
121
+ * @param args - Raw argument string
122
+ * @returns Parsed variables object
123
+ */
124
+ function parseVariables(args: string): { name: string; variables: Record<string, string> } {
125
+ const parts = args.trim().split(/\s+/);
126
+ const name = parts[0] ?? "";
127
+ const variables: Record<string, string> = {};
128
+
129
+ for (let i = 1; i < parts.length; i++) {
130
+ const part = parts[i];
131
+ if (part?.startsWith("--")) {
132
+ const eqIndex = part.indexOf("=");
133
+ if (eqIndex > 2) {
134
+ // --key=value format
135
+ const key = part.slice(2, eqIndex);
136
+ const value = part.slice(eqIndex + 1);
137
+ variables[key] = value;
138
+ } else {
139
+ const nextPart = parts[i + 1];
140
+ if (nextPart && !nextPart.startsWith("--")) {
141
+ // --key value format
142
+ const key = part.slice(2);
143
+ variables[key] = nextPart;
144
+ i++;
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ return { name, variables };
151
+ }
152
+
153
+ // =============================================================================
154
+ // /workflow Command - List and Execute Workflows
155
+ // =============================================================================
156
+
157
+ /**
158
+ * /workflow command handler.
159
+ *
160
+ * Without arguments: Lists all available workflows
161
+ * With workflow name: Loads and injects workflow instructions
162
+ *
163
+ * @example
164
+ * ```
165
+ * /workflow # List all workflows
166
+ * /workflow deploy # Inject deploy workflow
167
+ * /workflow deploy --env=prod --branch=main
168
+ * ```
169
+ */
170
+ async function executeWorkflow(ctx: CommandContext): Promise<CommandResult> {
171
+ const args = ctx.parsedArgs.raw.trim();
172
+ const loader = getLoader(ctx.session.cwd);
173
+
174
+ // No arguments - list workflows
175
+ if (!args) {
176
+ try {
177
+ const workflows = await loader.loadAll();
178
+ return success(formatWorkflowList(workflows));
179
+ } catch (err) {
180
+ return error(
181
+ "INTERNAL_ERROR",
182
+ `Failed to load workflows: ${err instanceof Error ? err.message : String(err)}`
183
+ );
184
+ }
185
+ }
186
+
187
+ // Parse workflow name and variables
188
+ const { name, variables } = parseVariables(args);
189
+
190
+ if (!name) {
191
+ return error(
192
+ "INVALID_ARGUMENT",
193
+ "Please specify a workflow name. Use /workflow to list available workflows."
194
+ );
195
+ }
196
+
197
+ try {
198
+ // Try to load the specific workflow
199
+ const workflow = await loader.load(name);
200
+
201
+ if (!workflow) {
202
+ // Workflow not found - show helpful message
203
+ const workflows = await loader.loadAll();
204
+ const names = workflows.map((w: Workflow) => w.id);
205
+ const suggestion =
206
+ names.length > 0
207
+ ? `\n\nAvailable workflows: ${names.join(", ")}`
208
+ : "\n\nNo workflows found. Create one in .vellum/workflows/";
209
+
210
+ return error("RESOURCE_NOT_FOUND", `Workflow "${name}" not found.${suggestion}`);
211
+ }
212
+
213
+ // Format workflow instructions for injection
214
+ const instructions = formatWorkflowInstructions(workflow, variables);
215
+
216
+ // Return pending result to inject instructions into context
217
+ return pending({
218
+ message: `${ICONS.workflow} Loading workflow: ${workflow.name || workflow.id}`,
219
+ promise: Promise.resolve(success(instructions)),
220
+ });
221
+ } catch (err) {
222
+ return error(
223
+ "INTERNAL_ERROR",
224
+ `Failed to load workflow "${name}": ${err instanceof Error ? err.message : String(err)}`
225
+ );
226
+ }
227
+ }
228
+
229
+ /**
230
+ * /workflow slash command definition.
231
+ */
232
+ export const workflowCommand: SlashCommand = {
233
+ name: "workflow",
234
+ description: "List or execute workflows from .vellum/workflows/",
235
+ kind: "builtin",
236
+ category: "workflow",
237
+ aliases: ["wf"],
238
+ positionalArgs: [
239
+ {
240
+ name: "name",
241
+ type: "string",
242
+ description: "Workflow name to execute (optional)",
243
+ required: false,
244
+ },
245
+ ],
246
+ subcommands: [
247
+ { name: "list", description: "List available workflows", aliases: ["ls"] },
248
+ { name: "run", description: "Run a workflow by name" },
249
+ { name: "validate", description: "Validate workflow file syntax" },
250
+ ],
251
+ execute: executeWorkflow,
252
+ };
253
+
254
+ /**
255
+ * All workflow-related slash commands.
256
+ */
257
+ export const workflowCommands: SlashCommand[] = [workflowCommand];
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Header Component
3
+ * @module cli/components/header
4
+ */
5
+
6
+ import { Box, Text } from "ink";
7
+ import type { FC } from "react";
8
+
9
+ export interface HeaderProps {
10
+ title?: string;
11
+ model?: string;
12
+ provider?: string;
13
+ }
14
+
15
+ export const Header: FC<HeaderProps> = ({ title = "Vellum", model, provider }) => {
16
+ return (
17
+ <Box borderStyle="single" paddingX={1}>
18
+ <Text bold color="blue">
19
+ {title}
20
+ </Text>
21
+ {model && <Text> | Model: {model}</Text>}
22
+ {provider && <Text> | Provider: {provider}</Text>}
23
+ </Box>
24
+ );
25
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Input Component
3
+ * @module cli/components/input
4
+ */
5
+
6
+ import { Box, Text } from "ink";
7
+ import type { FC } from "react";
8
+
9
+ export interface InputProps {
10
+ value?: string;
11
+ onChange?: (value: string) => void;
12
+ onSubmit?: (value: string) => void;
13
+ placeholder?: string;
14
+ disabled?: boolean;
15
+ }
16
+
17
+ export const Input: FC<InputProps> = ({ value = "", placeholder = ">" }) => {
18
+ return (
19
+ <Box>
20
+ <Text>
21
+ {placeholder} {value}
22
+ </Text>
23
+ </Box>
24
+ );
25
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Message List Component
3
+ * @module cli/components/message-list
4
+ */
5
+
6
+ import { Box, Text } from "ink";
7
+ import type { FC } from "react";
8
+
9
+ export interface Message {
10
+ role: "user" | "assistant";
11
+ content: string;
12
+ }
13
+
14
+ export interface MessageListProps {
15
+ messages?: Message[];
16
+ }
17
+
18
+ export const MessageList: FC<MessageListProps> = ({ messages = [] }) => {
19
+ return (
20
+ <Box flexDirection="column">
21
+ {messages.map((msg, i) => (
22
+ // biome-ignore lint/suspicious/noArrayIndexKey: Messages don't have stable IDs
23
+ <Box key={i} marginBottom={1}>
24
+ <Text color={msg.role === "user" ? "green" : "blue"}>
25
+ {msg.role === "user" ? "You: " : "Assistant: "}
26
+ </Text>
27
+ <Text>{msg.content}</Text>
28
+ </Box>
29
+ ))}
30
+ </Box>
31
+ );
32
+ };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Status Bar Component
3
+ * @module cli/components/status-bar
4
+ */
5
+
6
+ import { Box, Text } from "ink";
7
+ import type { FC } from "react";
8
+
9
+ export interface StatusBarProps {
10
+ status?: string;
11
+ model?: string;
12
+ tokens?: number;
13
+ }
14
+
15
+ export const StatusBar: FC<StatusBarProps> = ({ status = "Ready", model, tokens }) => {
16
+ return (
17
+ <Box borderStyle="single" paddingX={1}>
18
+ <Text color="gray">{status}</Text>
19
+ {model && <Text> | {model}</Text>}
20
+ {tokens !== undefined && <Text> | Tokens: {tokens}</Text>}
21
+ </Box>
22
+ );
23
+ };