@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,235 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as os from "node:os";
3
+ import * as path from "node:path";
4
+ import type { TaskChain, TaskChainNode } from "@vellum/core";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
+ import {
7
+ createTaskPersistence,
8
+ type PersistedTaskState,
9
+ type TaskPersistence,
10
+ } from "../task-persistence.js";
11
+
12
+ describe("TaskPersistence", () => {
13
+ let tempDir: string;
14
+ let persistence: TaskPersistence;
15
+
16
+ beforeEach(async () => {
17
+ tempDir = path.join(os.tmpdir(), `vellum-test-${Date.now()}`);
18
+ persistence = createTaskPersistence(tempDir);
19
+ });
20
+
21
+ afterEach(async () => {
22
+ // Clean up temp directory
23
+ try {
24
+ await fs.rm(tempDir, { recursive: true, force: true });
25
+ } catch {
26
+ // Ignore cleanup errors
27
+ }
28
+ });
29
+
30
+ function createMockTaskChain(): TaskChain {
31
+ const nodes = new Map<string, TaskChainNode>();
32
+ nodes.set("task-1", {
33
+ taskId: "task-1",
34
+ parentTaskId: undefined,
35
+ agentSlug: "orchestrator",
36
+ depth: 0,
37
+ createdAt: new Date("2025-01-01T00:00:00Z"),
38
+ status: "completed",
39
+ });
40
+ nodes.set("task-2", {
41
+ taskId: "task-2",
42
+ parentTaskId: "task-1",
43
+ agentSlug: "coder",
44
+ depth: 1,
45
+ createdAt: new Date("2025-01-01T00:01:00Z"),
46
+ status: "running",
47
+ });
48
+
49
+ return {
50
+ chainId: "chain-123",
51
+ rootTaskId: "task-1",
52
+ nodes,
53
+ maxDepth: 3,
54
+ };
55
+ }
56
+
57
+ function createMockState(overrides: Partial<PersistedTaskState> = {}): PersistedTaskState {
58
+ return {
59
+ chainId: "chain-123",
60
+ chain: createMockTaskChain(),
61
+ status: "running",
62
+ lastTaskId: "task-2",
63
+ checkpoint: {
64
+ completedTasks: ["task-1"],
65
+ pendingTasks: [],
66
+ failedTasks: [],
67
+ },
68
+ savedAt: new Date("2025-01-01T00:02:00Z"),
69
+ ...overrides,
70
+ };
71
+ }
72
+
73
+ describe("saveTaskState", () => {
74
+ it("should create directory and save state as JSON", async () => {
75
+ const state = createMockState();
76
+
77
+ await persistence.saveTaskState(state);
78
+
79
+ const filePath = path.join(tempDir, "chain-123.json");
80
+ const content = await fs.readFile(filePath, "utf-8");
81
+ const parsed = JSON.parse(content);
82
+
83
+ expect(parsed.chainId).toBe("chain-123");
84
+ expect(parsed.status).toBe("running");
85
+ expect(parsed.lastTaskId).toBe("task-2");
86
+ expect(parsed.chain.nodes).toHaveLength(2);
87
+ });
88
+
89
+ it("should sanitize chainId to prevent path traversal", async () => {
90
+ const state = createMockState({ chainId: "../../../evil" });
91
+
92
+ await persistence.saveTaskState(state);
93
+
94
+ // Should create sanitized file name (../../../evil -> _________evil)
95
+ const files = await fs.readdir(tempDir);
96
+ expect(files).toContain("_________evil.json");
97
+ expect(files).not.toContain("evil.json");
98
+ });
99
+
100
+ it("should overwrite existing state", async () => {
101
+ const state1 = createMockState({ status: "running" });
102
+ const state2 = createMockState({ status: "paused" });
103
+
104
+ await persistence.saveTaskState(state1);
105
+ await persistence.saveTaskState(state2);
106
+
107
+ const loaded = await persistence.loadTaskState("chain-123");
108
+ expect(loaded?.status).toBe("paused");
109
+ });
110
+ });
111
+
112
+ describe("loadTaskState", () => {
113
+ it("should return null for non-existent chain", async () => {
114
+ const result = await persistence.loadTaskState("non-existent");
115
+
116
+ expect(result).toBeNull();
117
+ });
118
+
119
+ it("should load and deserialize saved state", async () => {
120
+ const state = createMockState();
121
+ await persistence.saveTaskState(state);
122
+
123
+ const loaded = await persistence.loadTaskState("chain-123");
124
+
125
+ expect(loaded).not.toBeNull();
126
+ if (!loaded) throw new Error("loaded should not be null");
127
+ expect(loaded.chainId).toBe("chain-123");
128
+ expect(loaded.status).toBe("running");
129
+ expect(loaded.chain.nodes.size).toBe(2);
130
+ expect(loaded.chain.nodes.get("task-1")?.status).toBe("completed");
131
+ expect(loaded.savedAt).toBeInstanceOf(Date);
132
+ expect(loaded.chain.nodes.get("task-1")?.createdAt).toBeInstanceOf(Date);
133
+ });
134
+
135
+ it("should correctly restore Map from array", async () => {
136
+ const state = createMockState();
137
+ await persistence.saveTaskState(state);
138
+
139
+ const loaded = await persistence.loadTaskState("chain-123");
140
+
141
+ if (!loaded) throw new Error("loaded should not be null");
142
+ expect(loaded.chain.nodes).toBeInstanceOf(Map);
143
+ expect(loaded.chain.nodes.get("task-2")?.agentSlug).toBe("coder");
144
+ });
145
+ });
146
+
147
+ describe("listResumable", () => {
148
+ it("should return empty array when no tasks exist", async () => {
149
+ const result = await persistence.listResumable();
150
+
151
+ expect(result).toEqual([]);
152
+ });
153
+
154
+ it("should only list running and paused tasks", async () => {
155
+ await persistence.saveTaskState(createMockState({ chainId: "running-1", status: "running" }));
156
+ await persistence.saveTaskState(createMockState({ chainId: "paused-1", status: "paused" }));
157
+ await persistence.saveTaskState(
158
+ createMockState({ chainId: "completed-1", status: "completed" })
159
+ );
160
+ await persistence.saveTaskState(createMockState({ chainId: "failed-1", status: "failed" }));
161
+
162
+ const result = await persistence.listResumable();
163
+
164
+ expect(result).toHaveLength(2);
165
+ expect(result.map((r) => r.chainId)).toContain("running-1");
166
+ expect(result.map((r) => r.chainId)).toContain("paused-1");
167
+ expect(result.map((r) => r.chainId)).not.toContain("completed-1");
168
+ expect(result.map((r) => r.chainId)).not.toContain("failed-1");
169
+ });
170
+
171
+ it("should sort by savedAt descending", async () => {
172
+ await persistence.saveTaskState(
173
+ createMockState({
174
+ chainId: "older",
175
+ status: "running",
176
+ savedAt: new Date("2025-01-01T00:00:00Z"),
177
+ })
178
+ );
179
+ await persistence.saveTaskState(
180
+ createMockState({
181
+ chainId: "newer",
182
+ status: "running",
183
+ savedAt: new Date("2025-01-02T00:00:00Z"),
184
+ })
185
+ );
186
+
187
+ const result = await persistence.listResumable();
188
+
189
+ expect(result[0]?.chainId).toBe("newer");
190
+ expect(result[1]?.chainId).toBe("older");
191
+ });
192
+
193
+ it("should include status and savedAt in results", async () => {
194
+ await persistence.saveTaskState(
195
+ createMockState({
196
+ chainId: "test",
197
+ status: "paused",
198
+ savedAt: new Date("2025-06-15T12:30:00Z"),
199
+ })
200
+ );
201
+
202
+ const result = await persistence.listResumable();
203
+
204
+ expect(result[0]?.status).toBe("paused");
205
+ expect(result[0]?.savedAt).toBeInstanceOf(Date);
206
+ });
207
+ });
208
+
209
+ describe("deleteTaskState", () => {
210
+ it("should return false for non-existent chain", async () => {
211
+ const result = await persistence.deleteTaskState("non-existent");
212
+
213
+ expect(result).toBe(false);
214
+ });
215
+
216
+ it("should delete existing state and return true", async () => {
217
+ await persistence.saveTaskState(createMockState());
218
+
219
+ const result = await persistence.deleteTaskState("chain-123");
220
+
221
+ expect(result).toBe(true);
222
+
223
+ const loaded = await persistence.loadTaskState("chain-123");
224
+ expect(loaded).toBeNull();
225
+ });
226
+ });
227
+
228
+ describe("createTaskPersistence", () => {
229
+ it("should use default directory when not specified", () => {
230
+ const defaultPersistence = createTaskPersistence();
231
+ // Just verify it creates without error
232
+ expect(defaultPersistence).toBeDefined();
233
+ });
234
+ });
235
+ });
@@ -0,0 +1,240 @@
1
+ /**
2
+ * CLI Delegate Command - REQ-034)
3
+ *
4
+ * Implements the `vellum delegate <agent> <task>` CLI command
5
+ * for delegating tasks to specific agents.
6
+ *
7
+ * @module cli/agents/commands/delegate
8
+ */
9
+
10
+ import {
11
+ AgentLevel,
12
+ DEFAULT_DELEGATION_TIMEOUT,
13
+ type DelegateTaskContext,
14
+ type DelegateTaskParams,
15
+ type DelegateTaskResult,
16
+ type DelegationTarget,
17
+ executeDelegateTask,
18
+ } from "@vellum/core";
19
+ import type { Command } from "commander";
20
+
21
+ import { ICONS } from "../../utils/icons.js";
22
+
23
+ // =============================================================================
24
+ // Types
25
+ // =============================================================================
26
+
27
+ /**
28
+ * Options for the delegate command.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const options: DelegateCommandOptions = {
33
+ * files: ['src/auth/login.ts', 'src/auth/types.ts'],
34
+ * timeout: 60000,
35
+ * confirm: true,
36
+ * };
37
+ * ```
38
+ */
39
+ export interface DelegateCommandOptions {
40
+ /** Related files for the task (comma-separated in CLI, parsed to array) */
41
+ files?: string[];
42
+ /** Task timeout in milliseconds */
43
+ timeout?: number;
44
+ /** Whether to show confirmation prompt before delegation */
45
+ confirm?: boolean;
46
+ }
47
+
48
+ // =============================================================================
49
+ // Helpers
50
+ // =============================================================================
51
+
52
+ /**
53
+ * Parse comma-separated file paths into an array.
54
+ *
55
+ * @param value - Comma-separated file paths
56
+ * @returns Array of file paths, or undefined if empty
57
+ */
58
+ function parseFiles(value: string | undefined): string[] | undefined {
59
+ if (!value) return undefined;
60
+ return value
61
+ .split(",")
62
+ .map((f) => f.trim())
63
+ .filter((f) => f.length > 0);
64
+ }
65
+
66
+ /**
67
+ * Parse timeout value with validation.
68
+ *
69
+ * @param value - Timeout string value
70
+ * @returns Parsed timeout in milliseconds
71
+ * @throws Error if timeout is invalid
72
+ */
73
+ function parseTimeout(value: string): number {
74
+ const timeout = parseInt(value, 10);
75
+ if (Number.isNaN(timeout) || timeout <= 0) {
76
+ throw new Error(`Invalid timeout value: ${value}. Must be a positive integer.`);
77
+ }
78
+ return timeout;
79
+ }
80
+
81
+ /**
82
+ * Create a DelegationTarget from an agent slug.
83
+ *
84
+ * CLI delegation supports builtin agents and MCP targets.
85
+ * Custom agents require a mode config and should be created
86
+ * through the TUI or programmatic API.
87
+ *
88
+ * @param agent - Agent identifier (slug or prefixed identifier)
89
+ * @returns DelegationTarget for the specified agent
90
+ * @throws Error if target format is invalid or unsupported
91
+ */
92
+ function createDelegationTarget(agent: string): DelegationTarget {
93
+ // Custom agents require mode config - not supported via CLI
94
+ if (agent.startsWith("custom:")) {
95
+ throw new Error(
96
+ `Custom agents require a mode configuration and cannot be delegated via CLI. ` +
97
+ `Use the TUI or programmatic API for custom agent delegation.`
98
+ );
99
+ }
100
+
101
+ // MCP targets: mcp:serverId/toolName
102
+ if (agent.startsWith("mcp:")) {
103
+ const mcpPart = agent.slice(4);
104
+ const [serverId, toolName] = mcpPart.split("/");
105
+ if (!serverId || !toolName) {
106
+ throw new Error(`Invalid MCP target format: ${agent}. Expected 'mcp:serverId/toolName'.`);
107
+ }
108
+ return {
109
+ kind: "mcp",
110
+ serverId,
111
+ toolName,
112
+ };
113
+ }
114
+
115
+ // Default to builtin agent
116
+ return {
117
+ kind: "builtin",
118
+ slug: agent,
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Create a mock DelegateTaskContext for CLI execution.
124
+ *
125
+ * In a full implementation, this would be integrated with the
126
+ * session and agent management systems.
127
+ *
128
+ * @returns DelegateTaskContext for CLI execution
129
+ */
130
+ function createCliContext(): DelegateTaskContext {
131
+ return {
132
+ workingDir: process.cwd(),
133
+ sessionId: `cli-${Date.now()}`,
134
+ messageId: `msg-${Date.now()}`,
135
+ callId: `call-${Date.now()}`,
136
+ abortSignal: new AbortController().signal,
137
+ // CLI runs as orchestrator level (can delegate)
138
+ agentLevel: AgentLevel.orchestrator,
139
+ agentSlug: "cli",
140
+ checkPermission: async () => true,
141
+ };
142
+ }
143
+
144
+ // =============================================================================
145
+ // Command Registration
146
+ // =============================================================================
147
+
148
+ /**
149
+ * Register the delegate command with Commander.js.
150
+ *
151
+ * Command: `vellum delegate <agent> <task>`
152
+ *
153
+ * Options:
154
+ * --files <paths> Related files (comma-separated)
155
+ * --timeout <ms> Task timeout in milliseconds (default: 300000)
156
+ * --no-confirm Skip confirmation prompt
157
+ *
158
+ * @example
159
+ * ```bash
160
+ * # Delegate a task to the coder agent
161
+ * vellum delegate coder "Implement authentication module"
162
+ *
163
+ * # With files context
164
+ * vellum delegate coder "Fix bug in login" --files src/auth/login.ts,src/auth/types.ts
165
+ *
166
+ * # With custom timeout
167
+ * vellum delegate analyst "Analyze codebase" --timeout 600000
168
+ *
169
+ * # Delegate to custom agent
170
+ * vellum delegate custom:my-agent "Custom task"
171
+ *
172
+ * # Delegate to MCP tool
173
+ * vellum delegate mcp:server/tool "MCP task"
174
+ * ```
175
+ *
176
+ * @param program - Commander program instance
177
+ */
178
+ export function registerDelegateCommand(program: Command): void {
179
+ program
180
+ .command("delegate <agent> <task>")
181
+ .description("Delegate a task to a specific agent")
182
+ .option("--files <paths>", "Related files (comma-separated)")
183
+ .option("--timeout <ms>", "Task timeout in milliseconds", String(DEFAULT_DELEGATION_TIMEOUT))
184
+ .option("--no-confirm", "Skip confirmation prompt")
185
+ .action(async (agent: string, task: string, options: Record<string, unknown>) => {
186
+ try {
187
+ // Parse options
188
+ const delegateOptions: DelegateCommandOptions = {
189
+ files: parseFiles(options.files as string | undefined),
190
+ timeout: parseTimeout((options.timeout as string) || String(DEFAULT_DELEGATION_TIMEOUT)),
191
+ confirm: options.confirm !== false,
192
+ };
193
+
194
+ // Create delegation target
195
+ const target = createDelegationTarget(agent);
196
+
197
+ // Confirmation prompt (if enabled)
198
+ if (delegateOptions.confirm) {
199
+ console.log(`\n${ICONS.workflow} Delegation Details:`);
200
+ console.log(` Agent: ${agent}`);
201
+ console.log(` Task: ${task}`);
202
+ if (delegateOptions.files?.length) {
203
+ console.log(` Files: ${delegateOptions.files.join(", ")}`);
204
+ }
205
+ console.log(` Timeout: ${delegateOptions.timeout}ms`);
206
+ console.log("");
207
+
208
+ // In a full implementation, use readline or inquirer for confirmation
209
+ // For now, we proceed directly (confirmation can be skipped with --no-confirm)
210
+ }
211
+
212
+ // Build delegation parameters
213
+ const params: DelegateTaskParams = {
214
+ target,
215
+ task,
216
+ context: delegateOptions.files ? { files: delegateOptions.files } : undefined,
217
+ timeout: delegateOptions.timeout,
218
+ };
219
+
220
+ // Execute delegation
221
+ const context = createCliContext();
222
+ const result: DelegateTaskResult = await executeDelegateTask(params, context);
223
+
224
+ if (result.success) {
225
+ console.log(`\n${ICONS.success} Delegation successful!`);
226
+ console.log(` Task Packet ID: ${result.taskPacketId}`);
227
+ if (result.agentId) {
228
+ console.log(` Agent ID: ${result.agentId}`);
229
+ }
230
+ } else {
231
+ console.error(`\n${ICONS.error} Delegation failed:`);
232
+ console.error(` ${result.error}`);
233
+ process.exit(1);
234
+ }
235
+ } catch (error) {
236
+ console.error(`\n${ICONS.error} Error:`, error instanceof Error ? error.message : error);
237
+ process.exit(1);
238
+ }
239
+ });
240
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Agent Commands Index
3
+ *
4
+ * Re-exports all agent-related CLI commands.
5
+ *
6
+ * @module cli/agents/commands
7
+ */
8
+
9
+ export { type DelegateCommandOptions, registerDelegateCommand } from "./delegate.js";
10
+ export { type ResumeCommandOptions, registerResumeCommand } from "./resume.js";