@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,391 @@
1
+ /**
2
+ * Init Command
3
+ *
4
+ * Interactive wizard to create AGENTS.md for project configuration.
5
+ * Supports both interactive and non-interactive modes.
6
+ *
7
+ * Usage:
8
+ * - `vellum init` - Interactive wizard
9
+ * - `vellum init --minimal` - Skip wizard, use defaults
10
+ * - `vellum init --force` - Overwrite existing AGENTS.md
11
+ *
12
+ * @module cli/commands/init
13
+ */
14
+
15
+ import { existsSync } from "node:fs";
16
+ import { writeFile } from "node:fs/promises";
17
+ import { basename, join } from "node:path";
18
+
19
+ import { confirm, input, select } from "@inquirer/prompts";
20
+ import chalk from "chalk";
21
+
22
+ import { EXIT_CODES } from "./exit-codes.js";
23
+
24
+ // =============================================================================
25
+ // Types
26
+ // =============================================================================
27
+
28
+ /**
29
+ * Init command options
30
+ */
31
+ export interface InitOptions {
32
+ /** Overwrite existing AGENTS.md without prompting */
33
+ force?: boolean;
34
+ /** Skip wizard prompts, use defaults */
35
+ minimal?: boolean;
36
+ /** Non-interactive mode (for CI) */
37
+ nonInteractive?: boolean;
38
+ }
39
+
40
+ /**
41
+ * Project information gathered from wizard
42
+ */
43
+ export interface ProjectInfo {
44
+ /** Project name */
45
+ name: string;
46
+ /** Brief description */
47
+ description: string;
48
+ /** Programming language/stack */
49
+ language: string;
50
+ /** Framework (if any) */
51
+ framework: string;
52
+ }
53
+
54
+ /**
55
+ * Init command result
56
+ */
57
+ export interface InitResult {
58
+ /** Whether initialization succeeded */
59
+ success: boolean;
60
+ /** Output file path */
61
+ filePath?: string;
62
+ /** Error message if failed */
63
+ error?: string;
64
+ /** Exit code */
65
+ exitCode: number;
66
+ }
67
+
68
+ // =============================================================================
69
+ // Constants
70
+ // =============================================================================
71
+
72
+ /**
73
+ * Default project name from current directory
74
+ */
75
+ function getDefaultProjectName(): string {
76
+ return basename(process.cwd());
77
+ }
78
+
79
+ /**
80
+ * Available language choices
81
+ */
82
+ const LANGUAGE_CHOICES = [
83
+ { name: "TypeScript", value: "TypeScript" },
84
+ { name: "JavaScript", value: "JavaScript" },
85
+ { name: "Python", value: "Python" },
86
+ { name: "Rust", value: "Rust" },
87
+ { name: "Go", value: "Go" },
88
+ { name: "Java", value: "Java" },
89
+ { name: "C#", value: "C#" },
90
+ { name: "Other", value: "Other" },
91
+ ];
92
+
93
+ /**
94
+ * Available framework choices by language
95
+ */
96
+ const FRAMEWORK_CHOICES: Record<string, Array<{ name: string; value: string }>> = {
97
+ TypeScript: [
98
+ { name: "React", value: "React" },
99
+ { name: "Vue", value: "Vue" },
100
+ { name: "Node.js", value: "Node.js" },
101
+ { name: "Next.js", value: "Next.js" },
102
+ { name: "None", value: "None" },
103
+ ],
104
+ JavaScript: [
105
+ { name: "React", value: "React" },
106
+ { name: "Vue", value: "Vue" },
107
+ { name: "Node.js", value: "Node.js" },
108
+ { name: "Express", value: "Express" },
109
+ { name: "None", value: "None" },
110
+ ],
111
+ Python: [
112
+ { name: "FastAPI", value: "FastAPI" },
113
+ { name: "Django", value: "Django" },
114
+ { name: "Flask", value: "Flask" },
115
+ { name: "None", value: "None" },
116
+ ],
117
+ Rust: [
118
+ { name: "Actix", value: "Actix" },
119
+ { name: "Axum", value: "Axum" },
120
+ { name: "Tokio", value: "Tokio" },
121
+ { name: "None", value: "None" },
122
+ ],
123
+ Go: [
124
+ { name: "Gin", value: "Gin" },
125
+ { name: "Echo", value: "Echo" },
126
+ { name: "Fiber", value: "Fiber" },
127
+ { name: "None", value: "None" },
128
+ ],
129
+ Java: [
130
+ { name: "Spring Boot", value: "Spring Boot" },
131
+ { name: "Quarkus", value: "Quarkus" },
132
+ { name: "None", value: "None" },
133
+ ],
134
+ "C#": [
135
+ { name: ".NET Core", value: ".NET Core" },
136
+ { name: "ASP.NET", value: "ASP.NET" },
137
+ { name: "None", value: "None" },
138
+ ],
139
+ Other: [{ name: "None", value: "None" }],
140
+ };
141
+
142
+ // =============================================================================
143
+ // Template Generation
144
+ // =============================================================================
145
+
146
+ /**
147
+ * Generate AGENTS.md content from project info
148
+ *
149
+ * @param info - Project information
150
+ * @returns Generated AGENTS.md content
151
+ */
152
+ export function generateAgentsMd(info: ProjectInfo): string {
153
+ const frameworkLine = info.framework && info.framework !== "None" ? `\n- ${info.framework}` : "";
154
+
155
+ return `---
156
+ name: "${info.name}"
157
+ version: "1.0.0"
158
+ description: "${info.description || `AI coding assistant configuration for ${info.name}`}"
159
+ priority: 100
160
+ merge:
161
+ strategy: extend
162
+ arrays: append
163
+ ---
164
+
165
+ # Instructions
166
+
167
+ You are an AI coding assistant for ${info.name}.
168
+
169
+ ## Tech Stack
170
+ - ${info.language}${frameworkLine}
171
+
172
+ ## Coding Standards
173
+ - Follow project conventions
174
+ - Write clean, readable code
175
+ - Use meaningful variable and function names
176
+ - Add appropriate comments for complex logic
177
+
178
+ ## Allowed Tools
179
+ - @readonly
180
+ - @edit
181
+ - !bash
182
+ `;
183
+ }
184
+
185
+ /**
186
+ * Generate minimal AGENTS.md content
187
+ *
188
+ * @param projectName - Project name
189
+ * @returns Minimal AGENTS.md content
190
+ */
191
+ export function generateMinimalAgentsMd(projectName: string): string {
192
+ return `---
193
+ name: "${projectName}"
194
+ version: "1.0.0"
195
+ priority: 100
196
+ ---
197
+
198
+ # Instructions
199
+
200
+ You are an AI coding assistant for ${projectName}.
201
+
202
+ ## Allowed Tools
203
+ - @readonly
204
+ - @edit
205
+ `;
206
+ }
207
+
208
+ // =============================================================================
209
+ // Wizard Prompts
210
+ // =============================================================================
211
+
212
+ /**
213
+ * Run interactive wizard to gather project information
214
+ *
215
+ * @returns Project information
216
+ */
217
+ async function runWizard(): Promise<ProjectInfo> {
218
+ console.log(chalk.bold.blue("\n🚀 Initialize AGENTS.md\n"));
219
+
220
+ const name = await input({
221
+ message: "Project name:",
222
+ default: getDefaultProjectName(),
223
+ });
224
+
225
+ const description = await input({
226
+ message: "Brief description (optional):",
227
+ default: "",
228
+ });
229
+
230
+ const language = await select({
231
+ message: "Primary language/stack:",
232
+ choices: LANGUAGE_CHOICES,
233
+ });
234
+
235
+ const frameworkChoices = FRAMEWORK_CHOICES[language] || [{ name: "None", value: "None" }];
236
+ const framework = await select({
237
+ message: "Framework:",
238
+ choices: frameworkChoices,
239
+ });
240
+
241
+ return { name, description, language, framework };
242
+ }
243
+
244
+ // =============================================================================
245
+ // Init Command Handler
246
+ // =============================================================================
247
+
248
+ /**
249
+ * Execute init command
250
+ *
251
+ * @param options - Command options
252
+ * @returns Init result
253
+ */
254
+ export async function executeInit(options: InitOptions = {}): Promise<InitResult> {
255
+ const targetPath = join(process.cwd(), "AGENTS.md");
256
+
257
+ try {
258
+ // Check for existing file
259
+ const fileExists = existsSync(targetPath);
260
+
261
+ if (fileExists && !options.force) {
262
+ // In non-interactive mode, fail if file exists
263
+ if (options.nonInteractive || options.minimal) {
264
+ console.log(chalk.yellow("AGENTS.md already exists. Use --force to overwrite."));
265
+ return {
266
+ success: false,
267
+ error: "File already exists",
268
+ exitCode: EXIT_CODES.ERROR,
269
+ };
270
+ }
271
+
272
+ // Interactive confirmation
273
+ const shouldOverwrite = await confirm({
274
+ message: "AGENTS.md already exists. Overwrite?",
275
+ default: false,
276
+ });
277
+
278
+ if (!shouldOverwrite) {
279
+ console.log(chalk.gray("Aborted."));
280
+ return {
281
+ success: false,
282
+ error: "Aborted by user",
283
+ exitCode: EXIT_CODES.SUCCESS, // User choice, not an error
284
+ };
285
+ }
286
+ }
287
+
288
+ // Generate content
289
+ let content: string;
290
+
291
+ if (options.minimal || options.nonInteractive) {
292
+ // Use minimal template with defaults
293
+ content = generateMinimalAgentsMd(getDefaultProjectName());
294
+ } else {
295
+ // Run interactive wizard
296
+ const info = await runWizard();
297
+ content = generateAgentsMd(info);
298
+ }
299
+
300
+ // Write file
301
+ await writeFile(targetPath, content, "utf-8");
302
+
303
+ console.log(chalk.green(`\n✅ Created ${targetPath}`));
304
+ console.log(chalk.gray("\nNext steps:"));
305
+ console.log(chalk.gray(" • Review and customize AGENTS.md"));
306
+ console.log(chalk.gray(" • Run `vellum agents validate` to check syntax"));
307
+ console.log(chalk.gray(" • Run `vellum agents show` to view merged config\n"));
308
+
309
+ return {
310
+ success: true,
311
+ filePath: targetPath,
312
+ exitCode: EXIT_CODES.SUCCESS,
313
+ };
314
+ } catch (err) {
315
+ const message = err instanceof Error ? err.message : String(err);
316
+ console.error(chalk.red(`\n❌ Failed to create AGENTS.md: ${message}`));
317
+ return {
318
+ success: false,
319
+ error: message,
320
+ exitCode: EXIT_CODES.ERROR,
321
+ };
322
+ }
323
+ }
324
+
325
+ // =============================================================================
326
+ // Command Definition (SlashCommand format for TUI)
327
+ // =============================================================================
328
+
329
+ import type { CommandContext, CommandResult, SlashCommand } from "./types.js";
330
+ import { error, pending, success } from "./types.js";
331
+
332
+ /**
333
+ * Init slash command for TUI
334
+ *
335
+ * Creates AGENTS.md in the current working directory.
336
+ */
337
+ export const initSlashCommand: SlashCommand = {
338
+ name: "init",
339
+ description: "Initialize AGENTS.md for your project",
340
+ kind: "builtin",
341
+ category: "config",
342
+ aliases: [],
343
+ namedArgs: [
344
+ {
345
+ name: "force",
346
+ shorthand: "f",
347
+ type: "boolean",
348
+ description: "Overwrite existing AGENTS.md without prompting",
349
+ required: false,
350
+ default: false,
351
+ },
352
+ {
353
+ name: "minimal",
354
+ shorthand: "m",
355
+ type: "boolean",
356
+ description: "Skip wizard prompts, use defaults",
357
+ required: false,
358
+ default: false,
359
+ },
360
+ ],
361
+ examples: [
362
+ "/init - Interactive wizard",
363
+ "/init --minimal - Skip wizard, use defaults",
364
+ "/init --force - Overwrite existing file",
365
+ ],
366
+
367
+ execute: async (ctx: CommandContext): Promise<CommandResult> => {
368
+ const force = ctx.parsedArgs.named.force as boolean | undefined;
369
+ const minimal = ctx.parsedArgs.named.minimal as boolean | undefined;
370
+
371
+ // Return pending result with async operation
372
+ return pending({
373
+ message: "Initializing AGENTS.md...",
374
+ showProgress: true,
375
+ promise: (async (): Promise<CommandResult> => {
376
+ const result = await executeInit({
377
+ force: force ?? false,
378
+ minimal: minimal ?? false,
379
+ // In TUI context, assume interactive is available
380
+ nonInteractive: false,
381
+ });
382
+
383
+ if (result.success) {
384
+ return success(`Created ${result.filePath}`, { filePath: result.filePath });
385
+ }
386
+
387
+ return error("INTERNAL_ERROR", result.error ?? "Failed to initialize AGENTS.md");
388
+ })(),
389
+ });
390
+ },
391
+ };
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Install/Uninstall Commands (Phase 37)
3
+ * @module cli/commands/install
4
+ */
5
+
6
+ import type { CommandResult, SlashCommand } from "./types.js";
7
+ import { success } from "./types.js";
8
+
9
+ export interface InstallCommandOptions {
10
+ shell?: string;
11
+ force?: boolean;
12
+ }
13
+
14
+ export interface InstallCommandResult {
15
+ success: boolean;
16
+ message?: string;
17
+ }
18
+
19
+ export interface UninstallCommandOptions {
20
+ shell?: string;
21
+ force?: boolean;
22
+ }
23
+
24
+ /**
25
+ * Install command
26
+ */
27
+ export const installCommand: SlashCommand = {
28
+ name: "install",
29
+ description: "Install shell integration",
30
+ kind: "builtin",
31
+ category: "system",
32
+ execute: async (): Promise<CommandResult> => success("Install command not yet implemented"),
33
+ };
34
+
35
+ /**
36
+ * Uninstall command
37
+ */
38
+ export const uninstallCommand: SlashCommand = {
39
+ name: "uninstall",
40
+ description: "Uninstall shell integration",
41
+ kind: "builtin",
42
+ category: "system",
43
+ execute: async (): Promise<CommandResult> => success("Uninstall command not yet implemented"),
44
+ };
45
+
46
+ /**
47
+ * Execute install
48
+ */
49
+ export async function executeInstall(
50
+ _options?: InstallCommandOptions
51
+ ): Promise<InstallCommandResult> {
52
+ return { success: true, message: "Installed" };
53
+ }
54
+
55
+ /**
56
+ * Execute uninstall
57
+ */
58
+ export async function executeUninstall(
59
+ _options?: UninstallCommandOptions
60
+ ): Promise<InstallCommandResult> {
61
+ return { success: true, message: "Uninstalled" };
62
+ }
63
+
64
+ /**
65
+ * Handle install
66
+ */
67
+ export async function handleInstall(_options?: InstallCommandOptions): Promise<void> {
68
+ // Placeholder
69
+ }
70
+
71
+ /**
72
+ * Handle uninstall
73
+ */
74
+ export async function handleUninstall(_options?: UninstallCommandOptions): Promise<void> {
75
+ // Placeholder
76
+ }
77
+
78
+ /**
79
+ * Print install result
80
+ */
81
+ export function printInstallResult(_result: InstallCommandResult): void {
82
+ // Placeholder
83
+ }
84
+
85
+ /**
86
+ * Print uninstall result
87
+ */
88
+ export function printUninstallResult(_result: InstallCommandResult): void {
89
+ // Placeholder
90
+ }
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Language Command
3
+ *
4
+ * Slash command for viewing and changing the TUI language setting.
5
+ *
6
+ * @module cli/commands/language
7
+ */
8
+
9
+ import {
10
+ clearSavedLanguage,
11
+ getAvailableLocales,
12
+ getGlobalLocale,
13
+ getLanguageDisplayName,
14
+ isLocaleSupported,
15
+ type LocaleCode,
16
+ saveLanguage,
17
+ setGlobalLocale,
18
+ } from "../tui/i18n/index.js";
19
+ import type { CommandContext, CommandResult, SlashCommand } from "./types.js";
20
+
21
+ // =============================================================================
22
+ // T011/T012: Language Command Implementation
23
+ // =============================================================================
24
+
25
+ /**
26
+ * Format a locale for display with its native name.
27
+ *
28
+ * @param locale - The locale code
29
+ * @returns Formatted string like "zh (中文)"
30
+ */
31
+ function formatLocale(locale: LocaleCode): string {
32
+ return `${locale} (${getLanguageDisplayName(locale)})`;
33
+ }
34
+
35
+ /**
36
+ * Build the list of available languages for display.
37
+ *
38
+ * @returns Formatted list of available locales
39
+ */
40
+ function buildLanguageList(): string {
41
+ const locales = getAvailableLocales();
42
+ return locales.map((locale) => ` • ${formatLocale(locale)}`).join("\n");
43
+ }
44
+
45
+ /**
46
+ * Handle no-argument case: show current locale and list available languages.
47
+ *
48
+ * @returns Success result with current language info
49
+ */
50
+ function handleShowCurrent(): CommandResult {
51
+ const currentLocale = getGlobalLocale();
52
+ const availableList = buildLanguageList();
53
+
54
+ const message = [
55
+ `Current language: ${currentLocale}`,
56
+ "",
57
+ "Available languages:",
58
+ availableList,
59
+ "",
60
+ 'Use "/language <code>" to switch, or "/language auto" for auto-detection.',
61
+ ].join("\n");
62
+
63
+ return {
64
+ kind: "success",
65
+ message,
66
+ data: {
67
+ currentLocale,
68
+ availableLocales: getAvailableLocales(),
69
+ },
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Handle "auto" argument: clear saved preference and use auto-detection.
75
+ *
76
+ * @returns Success result confirming auto mode
77
+ */
78
+ function handleAutoDetect(): CommandResult {
79
+ clearSavedLanguage();
80
+
81
+ return {
82
+ kind: "success",
83
+ message:
84
+ "Language preference cleared. Auto-detection will be used.\nRestart the application for the change to take effect.",
85
+ data: {
86
+ mode: "auto",
87
+ },
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Handle valid locale code: switch to that language and save preference.
93
+ *
94
+ * @param locale - The valid locale code to switch to
95
+ * @returns Success result confirming language change
96
+ */
97
+ function handleValidLocale(locale: LocaleCode): CommandResult {
98
+ // Save the preference for future sessions
99
+ saveLanguage(locale);
100
+
101
+ // Switch immediately for the current session
102
+ setGlobalLocale(locale);
103
+
104
+ return {
105
+ kind: "success",
106
+ message: `Language changed to ${formatLocale(locale)}.`,
107
+ data: {
108
+ locale,
109
+ displayName: getLanguageDisplayName(locale),
110
+ },
111
+ refresh: true,
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Handle invalid locale code: show error with suggestions.
117
+ *
118
+ * @param input - The invalid locale string provided
119
+ * @returns Error result with available options
120
+ */
121
+ function handleInvalidLocale(input: string): CommandResult {
122
+ const availableList = buildLanguageList();
123
+
124
+ return {
125
+ kind: "error",
126
+ code: "INVALID_ARGUMENT",
127
+ message: `Unknown language: "${input}"`,
128
+ suggestions: [
129
+ `Available languages:\n${availableList}`,
130
+ 'Use "/language auto" for auto-detection',
131
+ ],
132
+ };
133
+ }
134
+
135
+ /**
136
+ * Language command - view or change the current language setting
137
+ *
138
+ * Usage:
139
+ * /language - Show current language and available options
140
+ * /language <code> - Switch to a specific language (e.g., /language zh)
141
+ * /language auto - Clear preference and use auto-detection
142
+ */
143
+ export const languageCommand: SlashCommand = {
144
+ name: "language",
145
+ description: "Change or view current language setting",
146
+ kind: "builtin",
147
+ category: "config",
148
+ aliases: ["lang"],
149
+ positionalArgs: [
150
+ {
151
+ name: "locale",
152
+ type: "string",
153
+ description: 'Language code (e.g., "en", "zh") or "auto"',
154
+ required: false,
155
+ },
156
+ ],
157
+ examples: [
158
+ "/language - Show current language",
159
+ "/language zh - Switch to Chinese",
160
+ "/language auto - Use auto-detection",
161
+ ],
162
+ subcommands: [
163
+ { name: "en", description: "English" },
164
+ { name: "zh", description: "中文" },
165
+ { name: "auto", description: "Auto-detect" },
166
+ ],
167
+
168
+ execute: async (ctx: CommandContext): Promise<CommandResult> => {
169
+ const { parsedArgs } = ctx;
170
+
171
+ // Case 1: No arguments - show current locale and available options
172
+ if (parsedArgs.positional.length === 0) {
173
+ return handleShowCurrent();
174
+ }
175
+
176
+ const localeArg = String(parsedArgs.positional[0]).toLowerCase().trim();
177
+
178
+ // Case 2: "auto" - clear saved preference
179
+ if (localeArg === "auto") {
180
+ return handleAutoDetect();
181
+ }
182
+
183
+ // Case 3: Valid locale code - switch to that language
184
+ if (isLocaleSupported(localeArg)) {
185
+ return handleValidLocale(localeArg);
186
+ }
187
+
188
+ // Case 4: Invalid locale code - show error with suggestions
189
+ return handleInvalidLocale(localeArg);
190
+ },
191
+ };
@@ -0,0 +1 @@
1
+ # Placeholder to track empty directory in Git