@butlerw/vellum 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (446) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +411 -0
  3. package/__fixtures__/responses/code-generation.json +42 -0
  4. package/__fixtures__/responses/error-response.json +20 -0
  5. package/__fixtures__/responses/hello-world.json +32 -0
  6. package/dist/auth-6MCXESOH.js +26 -0
  7. package/dist/chunk-SECXJGWA.js +597 -0
  8. package/dist/index.js +34023 -0
  9. package/package.json +67 -0
  10. package/src/__tests__/commands.e2e.test.ts +728 -0
  11. package/src/__tests__/credentials.test.ts +713 -0
  12. package/src/__tests__/mode-e2e.test.ts +391 -0
  13. package/src/__tests__/tui-integration.test.tsx +1271 -0
  14. package/src/agents/__tests__/task-persistence.test.ts +235 -0
  15. package/src/agents/commands/delegate.ts +240 -0
  16. package/src/agents/commands/index.ts +10 -0
  17. package/src/agents/commands/resume.ts +335 -0
  18. package/src/agents/index.ts +29 -0
  19. package/src/agents/task-persistence.ts +272 -0
  20. package/src/agents/task-resumption.ts +242 -0
  21. package/src/app.tsx +4737 -0
  22. package/src/commands/__tests__/.gitkeep +1 -0
  23. package/src/commands/__tests__/agents.test.ts +606 -0
  24. package/src/commands/__tests__/auth.test.ts +626 -0
  25. package/src/commands/__tests__/autocomplete.test.ts +683 -0
  26. package/src/commands/__tests__/batch.test.ts +287 -0
  27. package/src/commands/__tests__/chain-pipe-parser.test.ts +654 -0
  28. package/src/commands/__tests__/completion.test.ts +238 -0
  29. package/src/commands/__tests__/core.test.ts +363 -0
  30. package/src/commands/__tests__/executor.test.ts +496 -0
  31. package/src/commands/__tests__/exit-codes.test.ts +220 -0
  32. package/src/commands/__tests__/init.test.ts +243 -0
  33. package/src/commands/__tests__/language.test.ts +353 -0
  34. package/src/commands/__tests__/mode-cli.test.ts +667 -0
  35. package/src/commands/__tests__/model.test.ts +277 -0
  36. package/src/commands/__tests__/parser.test.ts +493 -0
  37. package/src/commands/__tests__/performance.bench.ts +380 -0
  38. package/src/commands/__tests__/registry.test.ts +534 -0
  39. package/src/commands/__tests__/resume.test.ts +449 -0
  40. package/src/commands/__tests__/security.test.ts +845 -0
  41. package/src/commands/__tests__/stream-json.test.ts +372 -0
  42. package/src/commands/__tests__/user-commands.test.ts +597 -0
  43. package/src/commands/adapters.ts +267 -0
  44. package/src/commands/agent.ts +395 -0
  45. package/src/commands/agents/generate.ts +506 -0
  46. package/src/commands/agents/index.ts +272 -0
  47. package/src/commands/agents/show.ts +271 -0
  48. package/src/commands/agents/validate.ts +387 -0
  49. package/src/commands/auth.ts +883 -0
  50. package/src/commands/autocomplete.ts +480 -0
  51. package/src/commands/batch/command.ts +388 -0
  52. package/src/commands/batch/executor.ts +361 -0
  53. package/src/commands/batch/index.ts +12 -0
  54. package/src/commands/commit.ts +235 -0
  55. package/src/commands/completion/index.ts +371 -0
  56. package/src/commands/condense.ts +191 -0
  57. package/src/commands/config.ts +344 -0
  58. package/src/commands/context-provider.ts +173 -0
  59. package/src/commands/copy.ts +329 -0
  60. package/src/commands/core/clear.ts +38 -0
  61. package/src/commands/core/exit.ts +43 -0
  62. package/src/commands/core/help.ts +354 -0
  63. package/src/commands/core/index.ts +15 -0
  64. package/src/commands/cost.ts +179 -0
  65. package/src/commands/credentials.tsx +618 -0
  66. package/src/commands/custom-agents/__tests__/custom-agents.test.ts +709 -0
  67. package/src/commands/custom-agents/create.ts +377 -0
  68. package/src/commands/custom-agents/export.ts +135 -0
  69. package/src/commands/custom-agents/import.ts +199 -0
  70. package/src/commands/custom-agents/index.ts +372 -0
  71. package/src/commands/custom-agents/info.ts +318 -0
  72. package/src/commands/custom-agents/list.ts +267 -0
  73. package/src/commands/custom-agents/validate.ts +388 -0
  74. package/src/commands/diff-mode.ts +241 -0
  75. package/src/commands/env.ts +53 -0
  76. package/src/commands/executor.ts +579 -0
  77. package/src/commands/exit-codes.ts +202 -0
  78. package/src/commands/index.ts +701 -0
  79. package/src/commands/init/index.ts +15 -0
  80. package/src/commands/init/prompts.ts +366 -0
  81. package/src/commands/init/templates/commands-readme.md +80 -0
  82. package/src/commands/init/templates/example-command.md +79 -0
  83. package/src/commands/init/templates/example-skill.md +168 -0
  84. package/src/commands/init/templates/example-workflow.md +101 -0
  85. package/src/commands/init/templates/prompts-readme.md +52 -0
  86. package/src/commands/init/templates/rules-readme.md +63 -0
  87. package/src/commands/init/templates/skills-readme.md +83 -0
  88. package/src/commands/init/templates/workflows-readme.md +94 -0
  89. package/src/commands/init.ts +391 -0
  90. package/src/commands/install.ts +90 -0
  91. package/src/commands/language.ts +191 -0
  92. package/src/commands/loaders/.gitkeep +1 -0
  93. package/src/commands/lsp.ts +199 -0
  94. package/src/commands/markdown-commands.ts +253 -0
  95. package/src/commands/mcp.ts +588 -0
  96. package/src/commands/memory/export.ts +341 -0
  97. package/src/commands/memory/index.ts +148 -0
  98. package/src/commands/memory/list.ts +261 -0
  99. package/src/commands/memory/search.ts +346 -0
  100. package/src/commands/memory/utils.ts +15 -0
  101. package/src/commands/metrics.ts +75 -0
  102. package/src/commands/migrate/index.ts +16 -0
  103. package/src/commands/migrate/prompts.ts +477 -0
  104. package/src/commands/mode.ts +331 -0
  105. package/src/commands/model.ts +298 -0
  106. package/src/commands/onboard.ts +205 -0
  107. package/src/commands/open.ts +169 -0
  108. package/src/commands/output/stream-json.ts +373 -0
  109. package/src/commands/parser/chain-parser.ts +370 -0
  110. package/src/commands/parser/index.ts +29 -0
  111. package/src/commands/parser/pipe-parser.ts +480 -0
  112. package/src/commands/parser.ts +588 -0
  113. package/src/commands/persistence.ts +355 -0
  114. package/src/commands/progress.ts +18 -0
  115. package/src/commands/prompt/index.ts +17 -0
  116. package/src/commands/prompt/validate.ts +621 -0
  117. package/src/commands/prompt-priority.ts +401 -0
  118. package/src/commands/registry.ts +374 -0
  119. package/src/commands/sandbox/index.ts +131 -0
  120. package/src/commands/security/index.ts +21 -0
  121. package/src/commands/security/input-sanitizer.ts +168 -0
  122. package/src/commands/security/permission-checker.ts +456 -0
  123. package/src/commands/security/sensitive-data.ts +350 -0
  124. package/src/commands/session/delete.ts +38 -0
  125. package/src/commands/session/export.ts +39 -0
  126. package/src/commands/session/index.ts +26 -0
  127. package/src/commands/session/list.ts +26 -0
  128. package/src/commands/session/resume.ts +562 -0
  129. package/src/commands/session/search.ts +434 -0
  130. package/src/commands/session/show.ts +26 -0
  131. package/src/commands/settings.ts +368 -0
  132. package/src/commands/setup.ts +23 -0
  133. package/src/commands/shell/index.ts +16 -0
  134. package/src/commands/shell/setup.ts +422 -0
  135. package/src/commands/shell-init.ts +50 -0
  136. package/src/commands/shell-integration/index.ts +194 -0
  137. package/src/commands/skill.ts +1220 -0
  138. package/src/commands/spec.ts +558 -0
  139. package/src/commands/status.ts +246 -0
  140. package/src/commands/theme.ts +211 -0
  141. package/src/commands/think.ts +551 -0
  142. package/src/commands/trust.ts +211 -0
  143. package/src/commands/tutorial.ts +522 -0
  144. package/src/commands/types.ts +512 -0
  145. package/src/commands/update.ts +274 -0
  146. package/src/commands/usage.ts +213 -0
  147. package/src/commands/user-commands.ts +630 -0
  148. package/src/commands/utils.ts +142 -0
  149. package/src/commands/vim.ts +152 -0
  150. package/src/commands/workflow.ts +257 -0
  151. package/src/components/header.tsx +25 -0
  152. package/src/components/input.tsx +25 -0
  153. package/src/components/message-list.tsx +32 -0
  154. package/src/components/status-bar.tsx +23 -0
  155. package/src/index.tsx +614 -0
  156. package/src/onboarding/__tests__/tutorial.test.ts +740 -0
  157. package/src/onboarding/index.ts +69 -0
  158. package/src/onboarding/tips/index.ts +9 -0
  159. package/src/onboarding/tips/tip-engine.ts +459 -0
  160. package/src/onboarding/tutorial/index.ts +88 -0
  161. package/src/onboarding/tutorial/lessons/basics.ts +151 -0
  162. package/src/onboarding/tutorial/lessons/index.ts +151 -0
  163. package/src/onboarding/tutorial/lessons/modes.ts +230 -0
  164. package/src/onboarding/tutorial/lessons/tools.ts +172 -0
  165. package/src/onboarding/tutorial/progress-tracker.ts +350 -0
  166. package/src/onboarding/tutorial/storage.ts +249 -0
  167. package/src/onboarding/tutorial/tutorial-system.ts +462 -0
  168. package/src/onboarding/tutorial/types.ts +310 -0
  169. package/src/orchestrator-singleton.ts +129 -0
  170. package/src/shutdown.ts +33 -0
  171. package/src/test/e2e/assertions.ts +267 -0
  172. package/src/test/e2e/fixtures.ts +204 -0
  173. package/src/test/e2e/harness.ts +575 -0
  174. package/src/test/e2e/index.ts +57 -0
  175. package/src/test/e2e/types.ts +228 -0
  176. package/src/test/fixtures/__tests__/fake-response-loader.test.ts +314 -0
  177. package/src/test/fixtures/fake-response-loader.ts +314 -0
  178. package/src/test/fixtures/index.ts +20 -0
  179. package/src/tui/__tests__/mcp-panel.test.tsx +82 -0
  180. package/src/tui/__tests__/mcp-wiring.test.tsx +78 -0
  181. package/src/tui/__tests__/mode-components.test.tsx +395 -0
  182. package/src/tui/__tests__/permission-ask-flow.test.tsx +138 -0
  183. package/src/tui/__tests__/sidebar-panel-data.test.tsx +148 -0
  184. package/src/tui/__tests__/tools-panel-hotkeys.test.tsx +41 -0
  185. package/src/tui/adapters/agent-adapter.ts +1008 -0
  186. package/src/tui/adapters/index.ts +48 -0
  187. package/src/tui/adapters/message-adapter.ts +315 -0
  188. package/src/tui/adapters/persistence-bridge.ts +331 -0
  189. package/src/tui/adapters/session-adapter.ts +419 -0
  190. package/src/tui/buffered-stdout.ts +223 -0
  191. package/src/tui/components/AgentProgress.tsx +424 -0
  192. package/src/tui/components/Banner/AsciiArt.ts +160 -0
  193. package/src/tui/components/Banner/Banner.tsx +355 -0
  194. package/src/tui/components/Banner/ShimmerContext.tsx +131 -0
  195. package/src/tui/components/Banner/ShimmerText.tsx +193 -0
  196. package/src/tui/components/Banner/TypeWriterGradient.tsx +321 -0
  197. package/src/tui/components/Banner/index.ts +61 -0
  198. package/src/tui/components/Banner/useShimmer.ts +241 -0
  199. package/src/tui/components/ChatView.tsx +11 -0
  200. package/src/tui/components/Checkpoint/CheckpointDiffView.tsx +371 -0
  201. package/src/tui/components/Checkpoint/SnapshotCheckpointPanel.tsx +440 -0
  202. package/src/tui/components/Checkpoint/index.ts +19 -0
  203. package/src/tui/components/CostDisplay.tsx +226 -0
  204. package/src/tui/components/InitErrorBanner.tsx +122 -0
  205. package/src/tui/components/Input/Autocomplete.tsx +603 -0
  206. package/src/tui/components/Input/EnhancedCommandInput.tsx +471 -0
  207. package/src/tui/components/Input/HighlightedText.tsx +236 -0
  208. package/src/tui/components/Input/MentionAutocomplete.tsx +375 -0
  209. package/src/tui/components/Input/TextInput.tsx +1002 -0
  210. package/src/tui/components/Input/__tests__/Autocomplete.test.tsx +374 -0
  211. package/src/tui/components/Input/__tests__/TextInput.test.tsx +241 -0
  212. package/src/tui/components/Input/__tests__/highlight.test.ts +219 -0
  213. package/src/tui/components/Input/__tests__/slash-command-utils.test.ts +104 -0
  214. package/src/tui/components/Input/highlight.ts +362 -0
  215. package/src/tui/components/Input/index.ts +36 -0
  216. package/src/tui/components/Input/slash-command-utils.ts +135 -0
  217. package/src/tui/components/Layout.tsx +432 -0
  218. package/src/tui/components/McpPanel.tsx +137 -0
  219. package/src/tui/components/MemoryPanel.tsx +448 -0
  220. package/src/tui/components/Messages/CodeBlock.tsx +527 -0
  221. package/src/tui/components/Messages/DiffView.tsx +679 -0
  222. package/src/tui/components/Messages/ImageReference.tsx +89 -0
  223. package/src/tui/components/Messages/MarkdownBlock.tsx +228 -0
  224. package/src/tui/components/Messages/MarkdownRenderer.tsx +498 -0
  225. package/src/tui/components/Messages/MessageBubble.tsx +270 -0
  226. package/src/tui/components/Messages/MessageList.tsx +1719 -0
  227. package/src/tui/components/Messages/StreamingText.tsx +216 -0
  228. package/src/tui/components/Messages/ThinkingBlock.tsx +408 -0
  229. package/src/tui/components/Messages/ToolResultPreview.tsx +243 -0
  230. package/src/tui/components/Messages/__tests__/CodeBlock.test.tsx +296 -0
  231. package/src/tui/components/Messages/__tests__/DiffView.test.tsx +239 -0
  232. package/src/tui/components/Messages/__tests__/MarkdownRenderer.test.tsx +303 -0
  233. package/src/tui/components/Messages/__tests__/MessageBubble.test.tsx +268 -0
  234. package/src/tui/components/Messages/__tests__/MessageList.test.tsx +324 -0
  235. package/src/tui/components/Messages/__tests__/StreamingText.test.tsx +215 -0
  236. package/src/tui/components/Messages/index.ts +25 -0
  237. package/src/tui/components/ModeIndicator.tsx +177 -0
  238. package/src/tui/components/ModeSelector.tsx +216 -0
  239. package/src/tui/components/ModelSelector.tsx +339 -0
  240. package/src/tui/components/OnboardingWizard.tsx +670 -0
  241. package/src/tui/components/PhaseProgressIndicator.tsx +270 -0
  242. package/src/tui/components/RateLimitIndicator.tsx +82 -0
  243. package/src/tui/components/ScreenReaderLayout.tsx +295 -0
  244. package/src/tui/components/SettingsPanel.tsx +643 -0
  245. package/src/tui/components/Sidebar/SystemStatusPanel.tsx +284 -0
  246. package/src/tui/components/Sidebar/index.ts +9 -0
  247. package/src/tui/components/Status/ModelStatusBar.tsx +270 -0
  248. package/src/tui/components/Status/index.ts +12 -0
  249. package/src/tui/components/StatusBar/AgentModeIndicator.tsx +257 -0
  250. package/src/tui/components/StatusBar/ContextProgress.tsx +167 -0
  251. package/src/tui/components/StatusBar/FileChangesIndicator.tsx +62 -0
  252. package/src/tui/components/StatusBar/GitIndicator.tsx +89 -0
  253. package/src/tui/components/StatusBar/HeaderBar.tsx +126 -0
  254. package/src/tui/components/StatusBar/ModelIndicator.tsx +157 -0
  255. package/src/tui/components/StatusBar/PersistenceStatusIndicator.tsx +210 -0
  256. package/src/tui/components/StatusBar/ResilienceIndicator.tsx +106 -0
  257. package/src/tui/components/StatusBar/SandboxIndicator.tsx +167 -0
  258. package/src/tui/components/StatusBar/StatusBar.tsx +368 -0
  259. package/src/tui/components/StatusBar/ThinkingModeIndicator.tsx +170 -0
  260. package/src/tui/components/StatusBar/TokenBreakdown.tsx +246 -0
  261. package/src/tui/components/StatusBar/TokenCounter.tsx +135 -0
  262. package/src/tui/components/StatusBar/TrustModeIndicator.tsx +130 -0
  263. package/src/tui/components/StatusBar/WorkspaceIndicator.tsx +86 -0
  264. package/src/tui/components/StatusBar/__tests__/AgentModeIndicator.test.tsx +193 -0
  265. package/src/tui/components/StatusBar/__tests__/StatusBar.test.tsx +729 -0
  266. package/src/tui/components/StatusBar/index.ts +60 -0
  267. package/src/tui/components/TipBanner.tsx +115 -0
  268. package/src/tui/components/TodoItem.tsx +208 -0
  269. package/src/tui/components/TodoPanel.tsx +455 -0
  270. package/src/tui/components/Tools/ApprovalQueue.tsx +407 -0
  271. package/src/tui/components/Tools/OptionSelector.tsx +160 -0
  272. package/src/tui/components/Tools/PermissionDialog.tsx +286 -0
  273. package/src/tui/components/Tools/ToolParams.tsx +483 -0
  274. package/src/tui/components/Tools/ToolsPanel.tsx +178 -0
  275. package/src/tui/components/Tools/__tests__/PermissionDialog.test.tsx +510 -0
  276. package/src/tui/components/Tools/__tests__/ToolParams.test.tsx +432 -0
  277. package/src/tui/components/Tools/index.ts +21 -0
  278. package/src/tui/components/TrustPrompt.tsx +279 -0
  279. package/src/tui/components/UpdateBanner.tsx +166 -0
  280. package/src/tui/components/VimModeIndicator.tsx +112 -0
  281. package/src/tui/components/backtrack/BacktrackControls.tsx +402 -0
  282. package/src/tui/components/backtrack/index.ts +13 -0
  283. package/src/tui/components/common/AutoApprovalStatus.tsx +251 -0
  284. package/src/tui/components/common/CostWarning.tsx +294 -0
  285. package/src/tui/components/common/DynamicShortcutHints.tsx +209 -0
  286. package/src/tui/components/common/EnhancedLoadingIndicator.tsx +305 -0
  287. package/src/tui/components/common/ErrorBoundary.tsx +140 -0
  288. package/src/tui/components/common/GradientText.tsx +224 -0
  289. package/src/tui/components/common/HotkeyHelpModal.tsx +193 -0
  290. package/src/tui/components/common/HotkeyHints.tsx +70 -0
  291. package/src/tui/components/common/MaxSizedBox.tsx +354 -0
  292. package/src/tui/components/common/NewMessagesBadge.tsx +65 -0
  293. package/src/tui/components/common/ProtectedFileLegend.tsx +89 -0
  294. package/src/tui/components/common/ScrollIndicator.tsx +160 -0
  295. package/src/tui/components/common/Spinner.tsx +342 -0
  296. package/src/tui/components/common/StreamingIndicator.tsx +316 -0
  297. package/src/tui/components/common/VirtualizedList/VirtualizedList.tsx +428 -0
  298. package/src/tui/components/common/VirtualizedList/hooks/index.ts +19 -0
  299. package/src/tui/components/common/VirtualizedList/hooks/useBatchedScroll.ts +64 -0
  300. package/src/tui/components/common/VirtualizedList/hooks/useScrollAnchor.ts +290 -0
  301. package/src/tui/components/common/VirtualizedList/hooks/useVirtualization.ts +340 -0
  302. package/src/tui/components/common/VirtualizedList/index.ts +30 -0
  303. package/src/tui/components/common/VirtualizedList/types.ts +107 -0
  304. package/src/tui/components/common/__tests__/NewMessagesBadge.test.tsx +74 -0
  305. package/src/tui/components/common/__tests__/ScrollIndicator.test.tsx +193 -0
  306. package/src/tui/components/common/index.ts +110 -0
  307. package/src/tui/components/index.ts +79 -0
  308. package/src/tui/components/session/CheckpointPanel.tsx +323 -0
  309. package/src/tui/components/session/RollbackDialog.tsx +169 -0
  310. package/src/tui/components/session/SessionItem.tsx +136 -0
  311. package/src/tui/components/session/SessionListPanel.tsx +252 -0
  312. package/src/tui/components/session/SessionPicker.tsx +449 -0
  313. package/src/tui/components/session/SessionPreview.tsx +240 -0
  314. package/src/tui/components/session/__tests__/session.test.tsx +408 -0
  315. package/src/tui/components/session/index.ts +28 -0
  316. package/src/tui/components/session/types.ts +116 -0
  317. package/src/tui/components/theme/__tests__/tokens.test.ts +471 -0
  318. package/src/tui/components/theme/index.ts +227 -0
  319. package/src/tui/components/theme/tokens.ts +484 -0
  320. package/src/tui/config/defaults.ts +134 -0
  321. package/src/tui/config/index.ts +17 -0
  322. package/src/tui/context/AnimationContext.tsx +284 -0
  323. package/src/tui/context/AppContext.tsx +349 -0
  324. package/src/tui/context/BracketedPasteContext.tsx +372 -0
  325. package/src/tui/context/LspContext.tsx +192 -0
  326. package/src/tui/context/McpContext.tsx +325 -0
  327. package/src/tui/context/MessagesContext.tsx +870 -0
  328. package/src/tui/context/OverflowContext.tsx +213 -0
  329. package/src/tui/context/RateLimitContext.tsx +108 -0
  330. package/src/tui/context/ResilienceContext.tsx +275 -0
  331. package/src/tui/context/RootProvider.tsx +136 -0
  332. package/src/tui/context/ScrollContext.tsx +331 -0
  333. package/src/tui/context/ToolsContext.tsx +702 -0
  334. package/src/tui/context/__tests__/BracketedPasteContext.test.tsx +416 -0
  335. package/src/tui/context/index.ts +140 -0
  336. package/src/tui/enterprise-integration.ts +282 -0
  337. package/src/tui/hooks/__tests__/useBacktrack.test.tsx +138 -0
  338. package/src/tui/hooks/__tests__/useBracketedPaste.test.tsx +222 -0
  339. package/src/tui/hooks/__tests__/useCopyMode.test.tsx +336 -0
  340. package/src/tui/hooks/__tests__/useHotkeys.ctrl-input.test.tsx +96 -0
  341. package/src/tui/hooks/__tests__/useHotkeys.test.tsx +454 -0
  342. package/src/tui/hooks/__tests__/useInputHistory.test.tsx +660 -0
  343. package/src/tui/hooks/__tests__/useLineBuffer.test.ts +295 -0
  344. package/src/tui/hooks/__tests__/useModeController.test.ts +137 -0
  345. package/src/tui/hooks/__tests__/useModeShortcuts.test.tsx +142 -0
  346. package/src/tui/hooks/__tests__/useScrollController.test.ts +464 -0
  347. package/src/tui/hooks/__tests__/useVim.test.tsx +531 -0
  348. package/src/tui/hooks/index.ts +252 -0
  349. package/src/tui/hooks/useAgentLoop.ts +712 -0
  350. package/src/tui/hooks/useAlternateBuffer.ts +398 -0
  351. package/src/tui/hooks/useAnimatedScrollbar.ts +241 -0
  352. package/src/tui/hooks/useBacktrack.ts +443 -0
  353. package/src/tui/hooks/useBracketedPaste.ts +104 -0
  354. package/src/tui/hooks/useCollapsible.ts +240 -0
  355. package/src/tui/hooks/useCopyMode.ts +382 -0
  356. package/src/tui/hooks/useCostSummary.ts +75 -0
  357. package/src/tui/hooks/useDesktopNotification.ts +414 -0
  358. package/src/tui/hooks/useDiffMode.ts +44 -0
  359. package/src/tui/hooks/useFileChangeStats.ts +110 -0
  360. package/src/tui/hooks/useFileSuggestions.ts +284 -0
  361. package/src/tui/hooks/useFlickerDetector.ts +250 -0
  362. package/src/tui/hooks/useGitStatus.ts +200 -0
  363. package/src/tui/hooks/useHotkeys.ts +579 -0
  364. package/src/tui/hooks/useImagePaste.ts +114 -0
  365. package/src/tui/hooks/useInputHighlight.ts +145 -0
  366. package/src/tui/hooks/useInputHistory.ts +246 -0
  367. package/src/tui/hooks/useKeyboardScroll.ts +209 -0
  368. package/src/tui/hooks/useLineBuffer.ts +356 -0
  369. package/src/tui/hooks/useMentionAutocomplete.ts +235 -0
  370. package/src/tui/hooks/useModeController.ts +167 -0
  371. package/src/tui/hooks/useModeShortcuts.ts +196 -0
  372. package/src/tui/hooks/usePermissionHandler.ts +146 -0
  373. package/src/tui/hooks/usePersistence.ts +480 -0
  374. package/src/tui/hooks/usePersistenceShortcuts.ts +225 -0
  375. package/src/tui/hooks/usePlaceholderRotation.ts +143 -0
  376. package/src/tui/hooks/useProviderStatus.ts +270 -0
  377. package/src/tui/hooks/useRateLimitStatus.ts +90 -0
  378. package/src/tui/hooks/useScreenReader.ts +315 -0
  379. package/src/tui/hooks/useScrollController.ts +450 -0
  380. package/src/tui/hooks/useScrollEventBatcher.ts +185 -0
  381. package/src/tui/hooks/useSidebarPanelData.ts +115 -0
  382. package/src/tui/hooks/useSmoothScroll.ts +202 -0
  383. package/src/tui/hooks/useSnapshots.ts +300 -0
  384. package/src/tui/hooks/useStateAndRef.ts +50 -0
  385. package/src/tui/hooks/useTerminalSize.ts +206 -0
  386. package/src/tui/hooks/useToolApprovalController.ts +91 -0
  387. package/src/tui/hooks/useVim.ts +334 -0
  388. package/src/tui/hooks/useWorkspace.ts +56 -0
  389. package/src/tui/i18n/__tests__/init.test.ts +278 -0
  390. package/src/tui/i18n/__tests__/language-config.test.ts +199 -0
  391. package/src/tui/i18n/__tests__/locale-detection.test.ts +250 -0
  392. package/src/tui/i18n/__tests__/settings-integration.test.ts +262 -0
  393. package/src/tui/i18n/index.ts +72 -0
  394. package/src/tui/i18n/init.ts +131 -0
  395. package/src/tui/i18n/language-config.ts +106 -0
  396. package/src/tui/i18n/locale-detection.ts +173 -0
  397. package/src/tui/i18n/settings-integration.ts +557 -0
  398. package/src/tui/i18n/tui-namespace.ts +538 -0
  399. package/src/tui/i18n/types.ts +312 -0
  400. package/src/tui/index.ts +43 -0
  401. package/src/tui/lsp-integration.ts +409 -0
  402. package/src/tui/metrics-integration.ts +366 -0
  403. package/src/tui/plugins.ts +383 -0
  404. package/src/tui/resilience.ts +342 -0
  405. package/src/tui/sandbox-integration.ts +317 -0
  406. package/src/tui/services/clipboard.ts +348 -0
  407. package/src/tui/services/fuzzy-search.ts +441 -0
  408. package/src/tui/services/index.ts +72 -0
  409. package/src/tui/services/markdown-renderer.ts +565 -0
  410. package/src/tui/services/open-external.ts +247 -0
  411. package/src/tui/services/syntax-highlighter.ts +483 -0
  412. package/src/tui/slash-commands.ts +12 -0
  413. package/src/tui/theme/index.ts +15 -0
  414. package/src/tui/theme/provider.tsx +206 -0
  415. package/src/tui/tip-integration.ts +300 -0
  416. package/src/tui/types/__tests__/ink-extended.test.ts +121 -0
  417. package/src/tui/types/ink-extended.ts +87 -0
  418. package/src/tui/utils/__tests__/bracketedPaste.test.ts +231 -0
  419. package/src/tui/utils/__tests__/heightEstimator.test.ts +157 -0
  420. package/src/tui/utils/__tests__/text-width.test.ts +158 -0
  421. package/src/tui/utils/__tests__/textSanitizer.test.ts +266 -0
  422. package/src/tui/utils/__tests__/ui-sizing.test.ts +169 -0
  423. package/src/tui/utils/bracketedPaste.ts +107 -0
  424. package/src/tui/utils/cursor-manager.ts +131 -0
  425. package/src/tui/utils/detectTerminal.ts +596 -0
  426. package/src/tui/utils/findLastSafeSplitPoint.ts +92 -0
  427. package/src/tui/utils/heightEstimator.ts +198 -0
  428. package/src/tui/utils/index.ts +91 -0
  429. package/src/tui/utils/isNarrowWidth.ts +52 -0
  430. package/src/tui/utils/stdoutGuard.ts +90 -0
  431. package/src/tui/utils/synchronized-update.ts +70 -0
  432. package/src/tui/utils/text-width.ts +225 -0
  433. package/src/tui/utils/textSanitizer.ts +225 -0
  434. package/src/tui/utils/textUtils.ts +114 -0
  435. package/src/tui/utils/ui-sizing.ts +192 -0
  436. package/src/tui-blessed/app.ts +160 -0
  437. package/src/tui-blessed/index.ts +2 -0
  438. package/src/tui-blessed/neo-blessed.d.ts +6 -0
  439. package/src/tui-blessed/test.ts +21 -0
  440. package/src/tui-blessed/types.ts +14 -0
  441. package/src/utils/icons.ts +130 -0
  442. package/src/utils/index.ts +33 -0
  443. package/src/utils/resume-hint.ts +86 -0
  444. package/src/version.ts +1 -0
  445. package/tsconfig.json +8 -0
  446. package/vitest.config.ts +35 -0
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Command System Adapters
3
+ *
4
+ * Provides adapter functions for backward compatibility between:
5
+ * - Legacy SlashCommandResult format (auth.ts original)
6
+ * - New CommandResult discriminated union (types.ts)
7
+ *
8
+ * Enables gradual migration of existing commands to the new interface.
9
+ *
10
+ * @module cli/commands/adapters
11
+ */
12
+
13
+ import type { CommandContext, CommandError, CommandResult, InteractivePrompt } from "./types.js";
14
+
15
+ // =============================================================================
16
+ // T032/T033: Legacy Type Definition
17
+ // =============================================================================
18
+
19
+ /**
20
+ * Legacy SlashCommandResult format
21
+ *
22
+ * Used by existing auth commands before migration to enhanced interface.
23
+ */
24
+ export interface LegacySlashCommandResult {
25
+ /** Whether the command succeeded */
26
+ success: boolean;
27
+ /** Message to display to user */
28
+ message: string;
29
+ /** Additional data (for programmatic use) */
30
+ data?: Record<string, unknown>;
31
+ /** Whether to prompt for input */
32
+ promptForInput?: {
33
+ type: "api_key";
34
+ provider: string;
35
+ placeholder: string;
36
+ onSubmit: (value: string) => Promise<LegacySlashCommandResult>;
37
+ };
38
+ }
39
+
40
+ // =============================================================================
41
+ // T032: toSlashCommandResult - New → Legacy Adapter
42
+ // =============================================================================
43
+
44
+ /**
45
+ * Convert new CommandResult to legacy SlashCommandResult format
46
+ *
47
+ * Maps the discriminated union result to the legacy format:
48
+ * - success: kind === 'success'
49
+ * - error: kind === 'error'
50
+ * - interactive: converted to promptForInput if password type
51
+ *
52
+ * @param result - New CommandResult to convert
53
+ * @returns Legacy SlashCommandResult format
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const newResult: CommandResult = { kind: 'success', message: 'Done' };
58
+ * const legacy = toSlashCommandResult(newResult);
59
+ * // { success: true, message: 'Done' }
60
+ * ```
61
+ */
62
+ export function toSlashCommandResult(result: CommandResult): LegacySlashCommandResult {
63
+ switch (result.kind) {
64
+ case "success":
65
+ return {
66
+ success: true,
67
+ message: result.message ?? "",
68
+ data: result.data as Record<string, unknown> | undefined,
69
+ };
70
+
71
+ case "error":
72
+ return {
73
+ success: false,
74
+ message: result.message,
75
+ data: {
76
+ code: result.code,
77
+ suggestions: result.suggestions,
78
+ },
79
+ };
80
+
81
+ case "interactive": {
82
+ const { prompt } = result;
83
+
84
+ // Convert interactive prompt to legacy promptForInput if applicable
85
+ if (prompt.inputType === "password" || prompt.inputType === "text") {
86
+ return {
87
+ success: true,
88
+ message: prompt.message,
89
+ promptForInput: {
90
+ type: "api_key",
91
+ provider: prompt.provider ?? "",
92
+ placeholder: prompt.placeholder ?? "",
93
+ onSubmit: async (value: string): Promise<LegacySlashCommandResult> => {
94
+ const handlerResult = await prompt.handler(value);
95
+ return toSlashCommandResult(handlerResult);
96
+ },
97
+ },
98
+ };
99
+ }
100
+
101
+ // For confirm/select, return message only
102
+ return {
103
+ success: true,
104
+ message: prompt.message,
105
+ };
106
+ }
107
+
108
+ case "pending":
109
+ return {
110
+ success: true,
111
+ message: result.operation.message,
112
+ data: {
113
+ pending: true,
114
+ },
115
+ };
116
+
117
+ default: {
118
+ // Exhaustive check - result should never reach here
119
+ result satisfies never;
120
+ return {
121
+ success: false,
122
+ message: "Unknown result type",
123
+ };
124
+ }
125
+ }
126
+ }
127
+
128
+ // =============================================================================
129
+ // T033: fromSlashCommandResult - Legacy → New Adapter
130
+ // =============================================================================
131
+
132
+ /**
133
+ * Convert legacy SlashCommandResult to new CommandResult format
134
+ *
135
+ * Maps the legacy result to the discriminated union:
136
+ * - success: true → CommandSuccess
137
+ * - success: false → CommandError
138
+ * - promptForInput → CommandInteractive
139
+ *
140
+ * @param legacy - Legacy SlashCommandResult to convert
141
+ * @returns New CommandResult discriminated union
142
+ *
143
+ * @example
144
+ * ```typescript
145
+ * const legacy = { success: true, message: 'Done' };
146
+ * const result = fromSlashCommandResult(legacy);
147
+ * // { kind: 'success', message: 'Done' }
148
+ * ```
149
+ */
150
+ export function fromSlashCommandResult(legacy: LegacySlashCommandResult): CommandResult {
151
+ // Handle interactive prompts
152
+ if (legacy.promptForInput) {
153
+ const { promptForInput } = legacy;
154
+
155
+ const prompt: InteractivePrompt = {
156
+ inputType: "password",
157
+ message: legacy.message,
158
+ placeholder: promptForInput.placeholder,
159
+ provider: promptForInput.provider,
160
+ handler: async (value: string): Promise<CommandResult> => {
161
+ const legacyResult = await promptForInput.onSubmit(value);
162
+ return fromSlashCommandResult(legacyResult);
163
+ },
164
+ onCancel: () => ({
165
+ kind: "error" as const,
166
+ code: "COMMAND_ABORTED" as const,
167
+ message: "Operation cancelled",
168
+ }),
169
+ };
170
+
171
+ return {
172
+ kind: "interactive",
173
+ prompt,
174
+ };
175
+ }
176
+
177
+ // Handle success
178
+ if (legacy.success) {
179
+ return {
180
+ kind: "success",
181
+ message: legacy.message || undefined,
182
+ data: legacy.data,
183
+ };
184
+ }
185
+
186
+ // Handle error
187
+ return {
188
+ kind: "error",
189
+ code: (legacy.data?.code as CommandError["code"]) ?? "UNKNOWN_ERROR",
190
+ message: legacy.message,
191
+ suggestions: legacy.data?.suggestions as readonly string[] | undefined,
192
+ };
193
+ }
194
+
195
+ // =============================================================================
196
+ // T034A: wrapLegacyHandler - Legacy Handler Wrapper
197
+ // =============================================================================
198
+
199
+ /**
200
+ * Legacy command handler function signature
201
+ */
202
+ export type LegacyHandler = (
203
+ args: string[],
204
+ context: { currentProvider?: string; credentialManager: CommandContext["credentials"] }
205
+ ) => Promise<LegacySlashCommandResult>;
206
+
207
+ /**
208
+ * Wrap a legacy handler to work with the new command system
209
+ *
210
+ * Converts CommandContext to legacy context format,
211
+ * calls the legacy handler, then converts the result.
212
+ *
213
+ * @param legacyHandler - Legacy handler function
214
+ * @returns New-style command handler
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * const newHandler = wrapLegacyHandler(handleLogin);
219
+ *
220
+ * const command: SlashCommand = {
221
+ * name: 'login',
222
+ * execute: newHandler,
223
+ * };
224
+ * ```
225
+ */
226
+ export function wrapLegacyHandler(
227
+ legacyHandler: LegacyHandler
228
+ ): (ctx: CommandContext) => Promise<CommandResult> {
229
+ return async (ctx: CommandContext): Promise<CommandResult> => {
230
+ // Extract positional args as string array
231
+ const args = ctx.parsedArgs.positional.map((arg) => String(arg));
232
+
233
+ // Build legacy context
234
+ const legacyContext = {
235
+ currentProvider: ctx.session.provider,
236
+ credentialManager: ctx.credentials,
237
+ };
238
+
239
+ // Call legacy handler
240
+ const legacyResult = await legacyHandler(args, legacyContext);
241
+
242
+ // Convert to new result format
243
+ return fromSlashCommandResult(legacyResult);
244
+ };
245
+ }
246
+
247
+ // =============================================================================
248
+ // Utility: Create Legacy Context from CommandContext
249
+ // =============================================================================
250
+
251
+ /**
252
+ * Extract legacy context from CommandContext
253
+ *
254
+ * Useful when calling legacy handlers directly within new commands.
255
+ *
256
+ * @param ctx - New CommandContext
257
+ * @returns Legacy context object
258
+ */
259
+ export function toLegacyContext(ctx: CommandContext): {
260
+ currentProvider?: string;
261
+ credentialManager: CommandContext["credentials"];
262
+ } {
263
+ return {
264
+ currentProvider: ctx.session.provider,
265
+ credentialManager: ctx.credentials,
266
+ };
267
+ }
@@ -0,0 +1,395 @@
1
+ /**
2
+ * Agent Level Slash Commands (T046c)
3
+ *
4
+ * Provides slash commands for agent level management:
5
+ * - /agent - Show current agent level and options
6
+ * - /agent l0 - Switch to orchestrator level
7
+ * - /agent l1 - Switch to workflow level
8
+ * - /agent l2 - Switch to worker level
9
+ * - /agent clear - Clear level override
10
+ * - /agent list - List registered agents
11
+ *
12
+ * @module cli/commands/agent
13
+ */
14
+
15
+ import { AgentLevel, type ModeManager } from "@vellum/core";
16
+ import type { CommandContext, CommandResult, SlashCommand } from "./types.js";
17
+ import { error, success } from "./types.js";
18
+
19
+ // =============================================================================
20
+ // Module State
21
+ // =============================================================================
22
+
23
+ /**
24
+ * Reference to the active ModeManager instance.
25
+ * Set by the App component when initialized.
26
+ */
27
+ let modeManager: ModeManager | null = null;
28
+
29
+ /**
30
+ * Set the ModeManager instance for agent commands.
31
+ * Called by the App component during initialization.
32
+ *
33
+ * @param manager - The ModeManager instance to use
34
+ */
35
+ export function setAgentCommandsManager(manager: ModeManager | null): void {
36
+ modeManager = manager;
37
+ }
38
+
39
+ /**
40
+ * Get the current ModeManager instance.
41
+ * Returns null if not yet initialized.
42
+ */
43
+ export function getAgentCommandsManager(): ModeManager | null {
44
+ return modeManager;
45
+ }
46
+
47
+ // =============================================================================
48
+ // Agent Level Constants
49
+ // =============================================================================
50
+
51
+ /**
52
+ * Agent level names for display.
53
+ */
54
+ const AGENT_LEVEL_NAMES: Record<AgentLevel, string> = {
55
+ [AgentLevel.orchestrator]: "Orchestrator",
56
+ [AgentLevel.workflow]: "Workflow",
57
+ [AgentLevel.worker]: "Worker",
58
+ } as const;
59
+
60
+ /**
61
+ * Agent level descriptions.
62
+ */
63
+ const AGENT_LEVEL_DESCRIPTIONS: Record<AgentLevel, string> = {
64
+ [AgentLevel.orchestrator]: "Top-level coordinator, spawns workflow agents",
65
+ [AgentLevel.workflow]: "Mid-level manager, spawns worker agents",
66
+ [AgentLevel.worker]: "Leaf-level executor, cannot spawn agents",
67
+ } as const;
68
+
69
+ /**
70
+ * Agent level icons.
71
+ */
72
+ const AGENT_LEVEL_ICONS: Record<AgentLevel, string> = {
73
+ [AgentLevel.orchestrator]: "[L0]",
74
+ [AgentLevel.workflow]: "[L1]",
75
+ [AgentLevel.worker]: "[L2]",
76
+ } as const;
77
+
78
+ /**
79
+ * Subcommand to AgentLevel mapping.
80
+ */
81
+ const SUBCOMMAND_TO_LEVEL: Record<string, AgentLevel> = {
82
+ l0: AgentLevel.orchestrator,
83
+ l1: AgentLevel.workflow,
84
+ l2: AgentLevel.worker,
85
+ orchestrator: AgentLevel.orchestrator,
86
+ workflow: AgentLevel.workflow,
87
+ worker: AgentLevel.worker,
88
+ } as const;
89
+
90
+ // =============================================================================
91
+ // Helper Functions
92
+ // =============================================================================
93
+
94
+ /**
95
+ * Format agent level info for display.
96
+ */
97
+ function formatLevelInfo(level: AgentLevel, isCurrent: boolean): string {
98
+ const icon = AGENT_LEVEL_ICONS[level];
99
+ const name = AGENT_LEVEL_NAMES[level];
100
+ const desc = AGENT_LEVEL_DESCRIPTIONS[level];
101
+ const marker = isCurrent ? " (current)" : "";
102
+ return ` ${icon} ${name}${marker} - ${desc}`;
103
+ }
104
+
105
+ /**
106
+ * Get numeric level from AgentLevel.
107
+ */
108
+ function getLevelNumber(level: AgentLevel): number {
109
+ return level; // AgentLevel enum values are 0, 1, 2
110
+ }
111
+
112
+ // =============================================================================
113
+ // /agent Command - Show Current Level and Options
114
+ // =============================================================================
115
+
116
+ /**
117
+ * /agent command - Display current agent level and available options.
118
+ *
119
+ * Shows the current agent level and lists all available levels
120
+ * with their descriptions. Supports subcommands for switching levels.
121
+ */
122
+ export const agentCommand: SlashCommand = {
123
+ name: "agent",
124
+ description: "Switch agent level or show current level",
125
+ kind: "builtin",
126
+ category: "workflow",
127
+ aliases: ["ag"],
128
+ positionalArgs: [
129
+ {
130
+ name: "subcommand",
131
+ type: "string",
132
+ description: "Subcommand: l0, l1, l2, clear, or list",
133
+ required: false,
134
+ },
135
+ ],
136
+ examples: [
137
+ "/agent - Show current agent level and options",
138
+ "/agent l0 - Switch to orchestrator level (L0)",
139
+ "/agent l1 - Switch to workflow level (L1)",
140
+ "/agent l2 - Switch to worker level (L2)",
141
+ "/agent clear - Clear level override, restore mode default",
142
+ "/agent list - List registered agents",
143
+ ],
144
+ subcommands: [
145
+ { name: "l0", description: "Switch to orchestrator level" },
146
+ { name: "l1", description: "Switch to workflow level" },
147
+ { name: "l2", description: "Switch to worker level" },
148
+ { name: "clear", description: "Clear level override" },
149
+ { name: "list", description: "List registered agents" },
150
+ ],
151
+
152
+ execute: async (ctx: CommandContext): Promise<CommandResult> => {
153
+ const subcommand = ctx.parsedArgs.positional[0] as string | undefined;
154
+
155
+ // Handle subcommands
156
+ if (subcommand) {
157
+ const normalized = subcommand.toLowerCase();
158
+
159
+ // Check for level switch commands
160
+ const level = SUBCOMMAND_TO_LEVEL[normalized as keyof typeof SUBCOMMAND_TO_LEVEL];
161
+ if (level !== undefined) {
162
+ return switchToLevel(level);
163
+ }
164
+
165
+ // Handle clear command
166
+ if (normalized === "clear") {
167
+ return clearLevelOverride();
168
+ }
169
+
170
+ // Handle list command
171
+ if (normalized === "list") {
172
+ return listAgents();
173
+ }
174
+
175
+ // Unknown subcommand
176
+ return error("INVALID_ARGUMENT", `Unknown subcommand: ${subcommand}`, [
177
+ "Valid subcommands: l0, l1, l2, clear, list",
178
+ ]);
179
+ }
180
+
181
+ // No subcommand - show current level and options
182
+ return showCurrentLevel();
183
+ },
184
+ };
185
+
186
+ // =============================================================================
187
+ // Subcommand Handlers
188
+ // =============================================================================
189
+
190
+ /**
191
+ * Show current agent level and available options.
192
+ */
193
+ function showCurrentLevel(): CommandResult {
194
+ if (!modeManager) {
195
+ const lines = [
196
+ "Agent Levels",
197
+ "",
198
+ "Available levels:",
199
+ formatLevelInfo(AgentLevel.orchestrator, false),
200
+ formatLevelInfo(AgentLevel.workflow, false),
201
+ formatLevelInfo(AgentLevel.worker, true), // Default
202
+ "",
203
+ "Mode system not initialized. Using default: L2 (Worker)",
204
+ "",
205
+ "Use /agent l0, /agent l1, or /agent l2 to switch levels.",
206
+ ];
207
+ return success(lines.join("\n"));
208
+ }
209
+
210
+ const effectiveLevel = modeManager.getEffectiveAgentLevel();
211
+ const override = modeManager.getAgentLevelOverride();
212
+ const hasOverride = modeManager.hasAgentLevelOverride();
213
+
214
+ const levelIcon = AGENT_LEVEL_ICONS[effectiveLevel];
215
+ const levelName = AGENT_LEVEL_NAMES[effectiveLevel];
216
+
217
+ const lines = [
218
+ "Agent Levels",
219
+ "",
220
+ `Current level: ${levelIcon} ${levelName} (L${getLevelNumber(effectiveLevel)})`,
221
+ ];
222
+
223
+ if (hasOverride && override) {
224
+ lines.push(`Override source: ${override.source}`);
225
+ lines.push("");
226
+ lines.push("[INFO] Use /agent clear to restore mode default.");
227
+ } else {
228
+ lines.push("(Mode-derived, no override active)");
229
+ }
230
+
231
+ lines.push("");
232
+ lines.push("Available levels:");
233
+ lines.push(formatLevelInfo(AgentLevel.orchestrator, effectiveLevel === AgentLevel.orchestrator));
234
+ lines.push(formatLevelInfo(AgentLevel.workflow, effectiveLevel === AgentLevel.workflow));
235
+ lines.push(formatLevelInfo(AgentLevel.worker, effectiveLevel === AgentLevel.worker));
236
+ lines.push("");
237
+ lines.push("Use /agent l0, /agent l1, or /agent l2 to switch levels.");
238
+
239
+ return success(lines.join("\n"));
240
+ }
241
+
242
+ /**
243
+ * Switch to a specific agent level.
244
+ */
245
+ function switchToLevel(level: AgentLevel): CommandResult {
246
+ if (!modeManager) {
247
+ return error("OPERATION_NOT_ALLOWED", "Mode system not initialized", [
248
+ "Cannot set agent level override without ModeManager.",
249
+ ]);
250
+ }
251
+
252
+ const currentLevel = modeManager.getEffectiveAgentLevel();
253
+
254
+ // Check if already at this level with override
255
+ if (modeManager.hasAgentLevelOverride()) {
256
+ const override = modeManager.getAgentLevelOverride();
257
+ if (override?.level === level) {
258
+ const icon = AGENT_LEVEL_ICONS[level];
259
+ const name = AGENT_LEVEL_NAMES[level];
260
+ return success(`Already at ${icon} ${name} level (L${getLevelNumber(level)}).`);
261
+ }
262
+ }
263
+
264
+ // Set the override
265
+ modeManager.setAgentLevelOverride(level, "command");
266
+
267
+ const icon = AGENT_LEVEL_ICONS[level];
268
+ const name = AGENT_LEVEL_NAMES[level];
269
+ const prevIcon = AGENT_LEVEL_ICONS[currentLevel];
270
+ const prevName = AGENT_LEVEL_NAMES[currentLevel];
271
+
272
+ return success(
273
+ `${icon} Switched to ${name} level (L${getLevelNumber(level)}).\n` +
274
+ `Previous: ${prevIcon} ${prevName} (L${getLevelNumber(currentLevel)})`
275
+ );
276
+ }
277
+
278
+ /**
279
+ * Clear agent level override.
280
+ */
281
+ function clearLevelOverride(): CommandResult {
282
+ if (!modeManager) {
283
+ return error("OPERATION_NOT_ALLOWED", "Mode system not initialized", [
284
+ "Cannot clear agent level override without ModeManager.",
285
+ ]);
286
+ }
287
+
288
+ if (!modeManager.hasAgentLevelOverride()) {
289
+ const effectiveLevel = modeManager.getEffectiveAgentLevel();
290
+ const icon = AGENT_LEVEL_ICONS[effectiveLevel];
291
+ const name = AGENT_LEVEL_NAMES[effectiveLevel];
292
+ return success(
293
+ `No override active. Current level: ${icon} ${name} (L${getLevelNumber(effectiveLevel)})`
294
+ );
295
+ }
296
+
297
+ const previousOverride = modeManager.getAgentLevelOverride();
298
+ const prevLevel: AgentLevel = previousOverride?.level ?? AgentLevel.worker;
299
+ modeManager.clearAgentLevelOverride();
300
+
301
+ const newLevel = modeManager.getEffectiveAgentLevel();
302
+ const newIcon = AGENT_LEVEL_ICONS[newLevel];
303
+ const newName = AGENT_LEVEL_NAMES[newLevel];
304
+
305
+ const prevIcon = AGENT_LEVEL_ICONS[prevLevel];
306
+ const prevName = AGENT_LEVEL_NAMES[prevLevel];
307
+
308
+ return success(
309
+ `Override cleared.\n` +
310
+ `Previous: ${prevIcon} ${prevName} (L${getLevelNumber(prevLevel)})\n` +
311
+ `Now: ${newIcon} ${newName} (L${getLevelNumber(newLevel)}) (mode-derived)`
312
+ );
313
+ }
314
+
315
+ /**
316
+ * List registered agents.
317
+ *
318
+ * Currently returns a placeholder as agent registry is not yet implemented.
319
+ */
320
+ function listAgents(): CommandResult {
321
+ // TODO: Once agent registry is implemented, list actual agents
322
+ const lines = [
323
+ "Registered Agents",
324
+ "",
325
+ "Built-in agent configurations:",
326
+ " [L2] Vibe Agent - Fast autonomous worker",
327
+ " [L1] Plan Agent - Plan-then-execute workflow",
328
+ " [L0] Spec Orchestrator - 6-phase structured workflow",
329
+ "",
330
+ "Use /mode to switch between agent configurations.",
331
+ "Use /agent l0|l1|l2 to manually override agent level.",
332
+ ];
333
+ return success(lines.join("\n"));
334
+ }
335
+
336
+ // =============================================================================
337
+ // Shortcut Commands
338
+ // =============================================================================
339
+
340
+ /**
341
+ * /l0 command - Quick switch to orchestrator level.
342
+ */
343
+ export const l0Command: SlashCommand = {
344
+ name: "l0",
345
+ description: "Switch to orchestrator level (L0)",
346
+ kind: "builtin",
347
+ category: "workflow",
348
+ aliases: ["orchestrator"],
349
+ examples: ["/l0 - Switch to orchestrator level"],
350
+
351
+ execute: async (_ctx: CommandContext): Promise<CommandResult> => {
352
+ return switchToLevel(AgentLevel.orchestrator);
353
+ },
354
+ };
355
+
356
+ /**
357
+ * /l1 command - Quick switch to workflow level.
358
+ */
359
+ export const l1Command: SlashCommand = {
360
+ name: "l1",
361
+ description: "Switch to workflow level (L1)",
362
+ kind: "builtin",
363
+ category: "workflow",
364
+ aliases: ["workflow"],
365
+ examples: ["/l1 - Switch to workflow level"],
366
+
367
+ execute: async (_ctx: CommandContext): Promise<CommandResult> => {
368
+ return switchToLevel(AgentLevel.workflow);
369
+ },
370
+ };
371
+
372
+ /**
373
+ * /l2 command - Quick switch to worker level.
374
+ */
375
+ export const l2Command: SlashCommand = {
376
+ name: "l2",
377
+ description: "Switch to worker level (L2)",
378
+ kind: "builtin",
379
+ category: "workflow",
380
+ aliases: ["worker"],
381
+ examples: ["/l2 - Switch to worker level"],
382
+
383
+ execute: async (_ctx: CommandContext): Promise<CommandResult> => {
384
+ return switchToLevel(AgentLevel.worker);
385
+ },
386
+ };
387
+
388
+ // =============================================================================
389
+ // Export All Agent Commands
390
+ // =============================================================================
391
+
392
+ /**
393
+ * All agent-related slash commands for registration.
394
+ */
395
+ export const agentSlashCommands: SlashCommand[] = [agentCommand, l0Command, l1Command, l2Command];