@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,199 @@
1
+ /**
2
+ * LSP Command
3
+ *
4
+ * CLI command for managing LSP servers.
5
+ *
6
+ * @module cli/commands/lsp
7
+ */
8
+
9
+ import { mkdir, writeFile } from "node:fs/promises";
10
+ import { homedir } from "node:os";
11
+ import { join, resolve } from "node:path";
12
+ import { LspHub, loadLspConfig, ServerInstaller } from "@vellum/lsp";
13
+ import chalk from "chalk";
14
+ import { Command } from "commander";
15
+ import { table } from "table";
16
+
17
+ function createHub(workspaceRoot: string): LspHub {
18
+ return LspHub.getInstance({
19
+ getGlobalConfigPath: async () => join(homedir(), ".vellum", "lsp.json"),
20
+ getProjectConfigPath: async () => join(resolve(workspaceRoot), ".vellum", "lsp.json"),
21
+ });
22
+ }
23
+
24
+ function formatStatus(status: string): string {
25
+ const statusMap: Record<string, string> = {
26
+ running: chalk.green("running"),
27
+ starting: chalk.yellow("starting"),
28
+ stopped: chalk.dim("stopped"),
29
+ error: chalk.red("error"),
30
+ };
31
+ return statusMap[status] ?? chalk.dim(status);
32
+ }
33
+
34
+ async function initConfigFile(): Promise<void> {
35
+ const configDir = join(process.cwd(), ".vellum");
36
+ const configPath = join(configDir, "lsp.json");
37
+
38
+ const template = {
39
+ $schema: "https://vellum.dev/schemas/lsp-config.json",
40
+ version: "1.0",
41
+ servers: {},
42
+ disabled: [],
43
+ cache: { maxSize: 100, ttlSeconds: 300 },
44
+ autoInstall: true,
45
+ maxConcurrentServers: 5,
46
+ };
47
+
48
+ await mkdir(configDir, { recursive: true });
49
+ await writeFile(configPath, JSON.stringify(template, null, 2));
50
+ console.log(chalk.green(`✓ Config created: ${configPath}`));
51
+ }
52
+
53
+ export function createLspCommand(): Command {
54
+ const lsp = new Command("lsp").description("Manage LSP language servers");
55
+
56
+ lsp
57
+ .command("status")
58
+ .description("Show language server status")
59
+ .option("-j, --json", "Output JSON")
60
+ .action(async (options) => {
61
+ const config = await loadLspConfig(process.cwd());
62
+ const hub = createHub(process.cwd());
63
+ await hub.initialize();
64
+
65
+ const servers = Object.entries(config.servers).map(([language, cfg]) => {
66
+ const server = hub.getServer(language);
67
+ const status = server?.status?.status ?? "stopped";
68
+ const pid =
69
+ server && "pid" in server.status && server.status.status === "running"
70
+ ? server.status.pid
71
+ : "-";
72
+
73
+ return {
74
+ language,
75
+ enabled: cfg.enabled,
76
+ status,
77
+ pid,
78
+ command: cfg.command,
79
+ };
80
+ });
81
+
82
+ if (options.json) {
83
+ console.log(JSON.stringify(servers, null, 2));
84
+ return;
85
+ }
86
+
87
+ const data = [
88
+ ["Language", "Enabled", "Status", "PID", "Command"].map((h) => chalk.bold(h)),
89
+ ...servers.map((server) => [
90
+ server.language,
91
+ server.enabled ? chalk.green("✓") : chalk.red("✗"),
92
+ formatStatus(server.status),
93
+ String(server.pid),
94
+ server.command,
95
+ ]),
96
+ ];
97
+
98
+ console.log(table(data));
99
+ });
100
+
101
+ lsp
102
+ .command("start <language>")
103
+ .description("Start a language server")
104
+ .option("-w, --workspace <path>", "Workspace root", process.cwd())
105
+ .action(async (language: string, options) => {
106
+ const config = await loadLspConfig(options.workspace);
107
+ const serverConfig = config.servers[language];
108
+
109
+ if (!serverConfig) {
110
+ console.error(chalk.red(`No server config found for ${language}`));
111
+ process.exit(1);
112
+ }
113
+
114
+ console.log(chalk.blue(`Starting ${language} server...`));
115
+ const hub = createHub(options.workspace);
116
+ try {
117
+ await hub.startServer(language, options.workspace);
118
+ console.log(chalk.green(`✓ ${language} server started`));
119
+ } catch (error) {
120
+ console.error(
121
+ chalk.red(
122
+ `Failed to start ${language}: ${error instanceof Error ? error.message : error}`
123
+ )
124
+ );
125
+ process.exit(1);
126
+ }
127
+ });
128
+
129
+ lsp
130
+ .command("stop <language>")
131
+ .description("Stop a language server")
132
+ .option("-a, --all", "Stop all servers", false)
133
+ .action(async (language: string, options) => {
134
+ const hub = createHub(process.cwd());
135
+ await hub.initialize();
136
+
137
+ if (options.all) {
138
+ console.log(chalk.blue("Stopping all servers..."));
139
+ await hub.dispose();
140
+ console.log(chalk.green("✓ All servers stopped"));
141
+ return;
142
+ }
143
+
144
+ console.log(chalk.blue(`Stopping ${language} server...`));
145
+ await hub.stopServer(language);
146
+ console.log(chalk.green(`✓ ${language} server stopped`));
147
+ });
148
+
149
+ lsp
150
+ .command("install <language>")
151
+ .description("Install a language server")
152
+ .option("-g, --global", "Use global install", false)
153
+ .action(async (language: string) => {
154
+ const config = await loadLspConfig(process.cwd());
155
+ const serverConfig = config.servers[language];
156
+
157
+ if (!serverConfig?.install) {
158
+ console.error(chalk.red(`No install config for ${language}. Install manually.`));
159
+ process.exit(1);
160
+ }
161
+
162
+ console.log(chalk.blue(`Installing ${language} server...`));
163
+ const installer = new ServerInstaller({ autoInstall: true });
164
+
165
+ try {
166
+ await installer.install(language, serverConfig);
167
+ console.log(chalk.green(`✓ ${language} server installed`));
168
+ } catch (error) {
169
+ console.error(
170
+ chalk.red(`Install failed: ${error instanceof Error ? error.message : String(error)}`)
171
+ );
172
+ process.exit(1);
173
+ }
174
+ });
175
+
176
+ lsp
177
+ .command("config")
178
+ .description("Show LSP configuration")
179
+ .option("-p, --path", "Only show config paths")
180
+ .option("--init", "Create a config file in the current project")
181
+ .action(async (options) => {
182
+ if (options.init) {
183
+ await initConfigFile();
184
+ return;
185
+ }
186
+
187
+ if (options.path) {
188
+ console.log("Global:", join(homedir(), ".vellum", "lsp.json"));
189
+ console.log("Project:", join(process.cwd(), ".vellum", "lsp.json"));
190
+ return;
191
+ }
192
+
193
+ const config = await loadLspConfig(process.cwd());
194
+ console.log(chalk.bold("Current LSP config:"));
195
+ console.log(JSON.stringify(config, null, 2));
196
+ });
197
+
198
+ return lsp;
199
+ }
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Markdown Command Loader (T033)
3
+ *
4
+ * Bridge between CommandLoader (core) and CommandRegistry (cli).
5
+ * Loads custom markdown commands from .vellum/commands/*.md and
6
+ * converts them to SlashCommand format for TUI integration.
7
+ *
8
+ * @module cli/commands/markdown-commands
9
+ * @see REQ-013
10
+ */
11
+
12
+ import { type CommandLoader, type CustomCommand, createCommandLoader } from "@vellum/core";
13
+ import type { CommandRegistry } from "./registry.js";
14
+ import type { CommandCategory, CommandContext, CommandResult, SlashCommand } from "./types.js";
15
+ import { pending, success } from "./types.js";
16
+
17
+ // =============================================================================
18
+ // Types
19
+ // =============================================================================
20
+
21
+ /**
22
+ * Result of loading markdown commands.
23
+ */
24
+ export interface MarkdownCommandLoadResult {
25
+ /** Successfully loaded commands */
26
+ commands: SlashCommand[];
27
+ /** Commands that conflict with built-ins */
28
+ conflicts: string[];
29
+ /** Errors encountered during loading */
30
+ errors: Array<{ file: string; error: string }>;
31
+ /** Total markdown files scanned */
32
+ scanned: number;
33
+ }
34
+
35
+ /**
36
+ * Options for loading markdown commands.
37
+ */
38
+ export interface MarkdownCommandLoaderOptions {
39
+ /** Current working directory (workspace root) */
40
+ cwd: string;
41
+ /** Whether to load user commands from ~/.vellum/commands/ */
42
+ loadUserCommands?: boolean;
43
+ }
44
+
45
+ // =============================================================================
46
+ // Module State
47
+ // =============================================================================
48
+
49
+ /**
50
+ * Cached CommandLoader instance.
51
+ */
52
+ let cachedLoader: CommandLoader | null = null;
53
+
54
+ /**
55
+ * Last workspace path used.
56
+ */
57
+ let lastWorkspacePath: string | null = null;
58
+
59
+ /**
60
+ * Get or create CommandLoader for the workspace.
61
+ */
62
+ function getLoader(cwd: string, loadUserCommands = true): CommandLoader {
63
+ if (cachedLoader === null || lastWorkspacePath !== cwd) {
64
+ cachedLoader = createCommandLoader({ cwd, loadUserCommands });
65
+ lastWorkspacePath = cwd;
66
+ }
67
+ return cachedLoader;
68
+ }
69
+
70
+ /**
71
+ * Clear the cached loader (for testing).
72
+ */
73
+ export function clearMarkdownCommandCache(): void {
74
+ cachedLoader = null;
75
+ lastWorkspacePath = null;
76
+ }
77
+
78
+ // =============================================================================
79
+ // Conversion Functions
80
+ // =============================================================================
81
+
82
+ /**
83
+ * Convert a CustomCommand from core to SlashCommand for CLI.
84
+ *
85
+ * @param cmd - The custom command from CommandLoader
86
+ * @returns SlashCommand ready for registry
87
+ */
88
+ function convertToSlashCommand(cmd: CustomCommand): SlashCommand {
89
+ return {
90
+ name: cmd.name,
91
+ description: `${cmd.description} ${cmd.badge ?? "[custom]"}`,
92
+ kind: "user",
93
+ category: "tools" as CommandCategory,
94
+ aliases: [],
95
+ positionalArgs: [
96
+ {
97
+ name: "args",
98
+ type: "string",
99
+ description: "Additional arguments",
100
+ required: false,
101
+ },
102
+ ],
103
+ execute: createCommandExecutor(cmd),
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Create an executor function for a custom command.
109
+ *
110
+ * Custom commands inject their markdown content as context
111
+ * for the agent to process.
112
+ *
113
+ * @param cmd - The custom command
114
+ * @returns Command executor function
115
+ */
116
+ function createCommandExecutor(
117
+ cmd: CustomCommand
118
+ ): (ctx: CommandContext) => Promise<CommandResult> {
119
+ return async (ctx: CommandContext): Promise<CommandResult> => {
120
+ // The command content is the prompt to inject
121
+ const content = cmd.content.trim();
122
+
123
+ if (!content) {
124
+ return success(`📝 Command "${cmd.name}" loaded (no content to inject)`);
125
+ }
126
+
127
+ // Check if there are additional args to append
128
+ const args = ctx.parsedArgs.raw.trim();
129
+ const fullContent = args ? `${content}\n\nUser input: ${args}` : content;
130
+
131
+ // Return pending to inject content as context
132
+ return pending({
133
+ message: `📝 Running custom command: /${cmd.name}`,
134
+ promise: Promise.resolve(success(fullContent)),
135
+ });
136
+ };
137
+ }
138
+
139
+ // =============================================================================
140
+ // Public API
141
+ // =============================================================================
142
+
143
+ /**
144
+ * Load all markdown commands from .vellum/commands/ directories.
145
+ *
146
+ * Scans project and user command directories, parses markdown files,
147
+ * and converts them to SlashCommand format.
148
+ *
149
+ * @param options - Loader options
150
+ * @returns Load result with commands, conflicts, and errors
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const result = await loadMarkdownCommands({ cwd: '/path/to/project' });
155
+ *
156
+ * console.log(`Loaded ${result.commands.length} markdown commands`);
157
+ * if (result.conflicts.length > 0) {
158
+ * console.warn('Conflicts with built-ins:', result.conflicts);
159
+ * }
160
+ * ```
161
+ */
162
+ export async function loadMarkdownCommands(
163
+ options: MarkdownCommandLoaderOptions
164
+ ): Promise<MarkdownCommandLoadResult> {
165
+ const loader = getLoader(options.cwd, options.loadUserCommands ?? true);
166
+
167
+ // Load all commands from markdown files
168
+ const customCommands = await loader.loadAll();
169
+ const conflicts = loader.getConflicts();
170
+
171
+ // Convert to SlashCommand format
172
+ const commands = customCommands.map(convertToSlashCommand);
173
+
174
+ return {
175
+ commands,
176
+ conflicts,
177
+ errors: [], // Errors are logged by CommandLoader, not returned
178
+ scanned: customCommands.length,
179
+ };
180
+ }
181
+
182
+ /**
183
+ * Load and register all markdown commands into a registry.
184
+ *
185
+ * This is the main integration point for TUI. It loads commands
186
+ * from markdown files and registers them with the command registry.
187
+ *
188
+ * @param registry - Command registry to register commands in
189
+ * @param options - Loader options
190
+ * @returns Load result with registration status
191
+ *
192
+ * @example
193
+ * ```typescript
194
+ * const registry = new CommandRegistry();
195
+ *
196
+ * // Register built-in commands first
197
+ * registry.register(helpCommand);
198
+ * registry.register(clearCommand);
199
+ *
200
+ * // Then load and register markdown commands
201
+ * const result = await registerMarkdownCommands(registry, {
202
+ * cwd: process.cwd()
203
+ * });
204
+ *
205
+ * if (result.conflicts.length > 0) {
206
+ * console.warn('Custom commands override built-ins:', result.conflicts);
207
+ * }
208
+ * ```
209
+ */
210
+ export async function registerMarkdownCommands(
211
+ registry: CommandRegistry,
212
+ options: MarkdownCommandLoaderOptions
213
+ ): Promise<MarkdownCommandLoadResult> {
214
+ const result = await loadMarkdownCommands(options);
215
+
216
+ // Register each command
217
+ for (const command of result.commands) {
218
+ try {
219
+ registry.register(command);
220
+ } catch (err) {
221
+ // If registration fails (e.g., conflict), add to errors
222
+ result.errors.push({
223
+ file: command.name,
224
+ error: err instanceof Error ? err.message : String(err),
225
+ });
226
+ }
227
+ }
228
+
229
+ return result;
230
+ }
231
+
232
+ /**
233
+ * Get the list of loaded custom command names.
234
+ *
235
+ * @param cwd - Workspace path
236
+ * @returns Array of command names
237
+ */
238
+ export async function getMarkdownCommandNames(cwd: string): Promise<string[]> {
239
+ const result = await loadMarkdownCommands({ cwd });
240
+ return result.commands.map((c) => c.name);
241
+ }
242
+
243
+ /**
244
+ * Check if a command name is a custom markdown command.
245
+ *
246
+ * @param name - Command name to check
247
+ * @param cwd - Workspace path
248
+ * @returns True if this is a custom markdown command
249
+ */
250
+ export async function isMarkdownCommand(name: string, cwd: string): Promise<boolean> {
251
+ const names = await getMarkdownCommandNames(cwd);
252
+ return names.includes(name);
253
+ }