@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,557 @@
1
+ /**
2
+ * Settings Integration Module
3
+ *
4
+ * Manages language preference storage in user settings file.
5
+ * Provides graceful error handling for all file operations.
6
+ *
7
+ * @module tui/i18n/settings-integration
8
+ */
9
+
10
+ import * as fs from "node:fs";
11
+ import * as os from "node:os";
12
+ import * as path from "node:path";
13
+ import { isConptyTerminal } from "../utils/detectTerminal.js";
14
+ import { isLocaleSupported, type LocaleCode } from "./language-config.js";
15
+
16
+ /**
17
+ * UI configuration options.
18
+ */
19
+ export interface UISettings {
20
+ /** Enable alternate screen buffer (default: true) */
21
+ alternateBuffer?: boolean;
22
+ }
23
+
24
+ /**
25
+ * Thinking display mode.
26
+ * - "full": Show thinking content (default, current behavior)
27
+ * - "compact": Only show thinking header, no content preview
28
+ */
29
+ export type ThinkingDisplayMode = "full" | "compact";
30
+
31
+ /**
32
+ * Thinking mode configuration.
33
+ */
34
+ export interface ThinkingSettings {
35
+ enabled?: boolean;
36
+ budgetTokens?: number;
37
+ priority?: "global" | "mode" | "merge";
38
+ displayMode?: ThinkingDisplayMode;
39
+ }
40
+
41
+ /**
42
+ * Model configuration.
43
+ */
44
+ export interface ModelSettings {
45
+ provider?: string;
46
+ modelId?: string;
47
+ }
48
+
49
+ /**
50
+ * Diff view display mode configuration.
51
+ */
52
+ export type DiffViewMode = "unified" | "side-by-side";
53
+
54
+ /**
55
+ * Settings file structure.
56
+ */
57
+ export interface VellumSettings {
58
+ language?: LocaleCode;
59
+ bannerSeen?: boolean;
60
+ ui?: UISettings;
61
+ thinking?: ThinkingSettings;
62
+ theme?: string;
63
+ model?: ModelSettings;
64
+ mode?: string; // "vibe" | "plan" | "spec"
65
+ diffViewMode?: DiffViewMode;
66
+ [key: string]: unknown;
67
+ }
68
+
69
+ /**
70
+ * Get the path to the Vellum settings directory.
71
+ *
72
+ * @returns Absolute path to ~/.vellum/
73
+ */
74
+ function getSettingsDir(): string {
75
+ return path.join(os.homedir(), ".vellum");
76
+ }
77
+
78
+ /**
79
+ * Get the path to the Vellum settings file.
80
+ *
81
+ * @returns Absolute path to ~/.vellum/settings.json
82
+ */
83
+ function getSettingsPath(): string {
84
+ return path.join(getSettingsDir(), "settings.json");
85
+ }
86
+
87
+ /**
88
+ * Read and parse the settings file.
89
+ *
90
+ * @returns Parsed settings object, or null on any error
91
+ */
92
+ function readSettings(): VellumSettings | null {
93
+ try {
94
+ const settingsPath = getSettingsPath();
95
+ if (!fs.existsSync(settingsPath)) {
96
+ return null;
97
+ }
98
+ const content = fs.readFileSync(settingsPath, "utf-8");
99
+ const parsed = JSON.parse(content) as unknown;
100
+
101
+ // Validate that parsed content is an object
102
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
103
+ return null;
104
+ }
105
+
106
+ return parsed as VellumSettings;
107
+ } catch {
108
+ // Silently handle any error (file not found, permission, parse error, etc.)
109
+ return null;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Write settings to the settings file.
115
+ *
116
+ * Creates the settings directory if it doesn't exist.
117
+ *
118
+ * @param settings - Settings object to write
119
+ * @returns True if successful, false on any error
120
+ */
121
+ function writeSettings(settings: VellumSettings): boolean {
122
+ try {
123
+ const settingsDir = getSettingsDir();
124
+ const settingsPath = getSettingsPath();
125
+
126
+ // Ensure settings directory exists
127
+ if (!fs.existsSync(settingsDir)) {
128
+ fs.mkdirSync(settingsDir, { recursive: true });
129
+ }
130
+
131
+ const content = JSON.stringify(settings, null, 2);
132
+ fs.writeFileSync(settingsPath, content, "utf-8");
133
+ return true;
134
+ } catch {
135
+ // Silently handle any error (permission, disk space, etc.)
136
+ return false;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Load the current settings from the settings file.
142
+ *
143
+ * @returns Current settings object, or empty object if file doesn't exist
144
+ */
145
+ export function loadSettings(): VellumSettings {
146
+ return readSettings() ?? {};
147
+ }
148
+
149
+ /**
150
+ * Save settings to the settings file.
151
+ *
152
+ * @param settings - Complete settings object to save
153
+ * @returns True if successful, false on error
154
+ */
155
+ export function saveSettings(settings: VellumSettings): boolean {
156
+ return writeSettings(settings);
157
+ }
158
+
159
+ /**
160
+ * Save a single user setting by key.
161
+ *
162
+ * This is a convenience helper that loads current settings,
163
+ * updates the specified key, and saves back to disk.
164
+ *
165
+ * @param key - The setting key to update
166
+ * @param value - The new value for the setting
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * await saveUserSetting("thinking", { enabled: true, budgetTokens: 20000 });
171
+ * await saveUserSetting("theme", "dracula");
172
+ * await saveUserSetting("mode", "plan");
173
+ * ```
174
+ */
175
+ export async function saveUserSetting<K extends keyof VellumSettings>(
176
+ key: K,
177
+ value: VellumSettings[K]
178
+ ): Promise<void> {
179
+ const current = loadSettings();
180
+ const updated = { ...current, [key]: value };
181
+ saveSettings(updated);
182
+ }
183
+
184
+ /**
185
+ * Get the saved language preference from settings.
186
+ *
187
+ * @returns Saved locale code, or undefined if not set or invalid
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * const savedLang = getSavedLanguage();
192
+ * if (savedLang) {
193
+ * setLocale(savedLang);
194
+ * }
195
+ * ```
196
+ */
197
+ export function getSavedLanguage(): LocaleCode | undefined {
198
+ const settings = readSettings();
199
+ if (!settings?.language) {
200
+ return undefined;
201
+ }
202
+
203
+ // Validate that the saved language is still supported
204
+ if (!isLocaleSupported(settings.language)) {
205
+ return undefined;
206
+ }
207
+
208
+ return settings.language;
209
+ }
210
+
211
+ /**
212
+ * Save language preference to settings.
213
+ *
214
+ * Creates the settings file and directory if they don't exist.
215
+ * Preserves other settings in the file.
216
+ *
217
+ * @param locale - The locale code to save
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * saveLanguage("zh");
222
+ * // Now getSavedLanguage() returns "zh"
223
+ * ```
224
+ */
225
+ export function saveLanguage(locale: LocaleCode): void {
226
+ const existingSettings = readSettings() ?? {};
227
+ const newSettings: VellumSettings = {
228
+ ...existingSettings,
229
+ language: locale,
230
+ };
231
+ writeSettings(newSettings);
232
+ }
233
+
234
+ /**
235
+ * Remove language preference from settings.
236
+ *
237
+ * Preserves other settings in the file.
238
+ * Does nothing if settings file doesn't exist.
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * clearSavedLanguage();
243
+ * // Now getSavedLanguage() returns undefined
244
+ * ```
245
+ */
246
+ export function clearSavedLanguage(): void {
247
+ const settings = readSettings();
248
+ if (!settings) {
249
+ return;
250
+ }
251
+
252
+ // Remove the language property while preserving others
253
+ const { language: _, ...rest } = settings;
254
+ writeSettings(rest as VellumSettings);
255
+ }
256
+
257
+ /**
258
+ * Check whether the startup banner has been shown before.
259
+ *
260
+ * @returns True if the banner has been shown, false otherwise
261
+ */
262
+ export function getBannerSeen(): boolean {
263
+ const settings = readSettings();
264
+ return settings?.bannerSeen === true;
265
+ }
266
+
267
+ /**
268
+ * Persist the banner seen flag.
269
+ *
270
+ * @param seen - Whether the banner has been shown
271
+ */
272
+ export function setBannerSeen(seen: boolean): void {
273
+ const existingSettings = readSettings() ?? {};
274
+ const newSettings: VellumSettings = {
275
+ ...existingSettings,
276
+ bannerSeen: seen,
277
+ };
278
+ writeSettings(newSettings);
279
+ }
280
+
281
+ // =============================================================================
282
+ // UI Settings
283
+ // =============================================================================
284
+
285
+ /**
286
+ * Get the alternate buffer preference from settings.
287
+ *
288
+ * @returns True if alternate buffer is enabled (default: true), false if disabled
289
+ *
290
+ * @example
291
+ * ```typescript
292
+ * const altBufferEnabled = getAlternateBufferEnabled();
293
+ * ```
294
+ */
295
+ export function getAlternateBufferSetting(): boolean | undefined {
296
+ const settings = readSettings();
297
+ return settings?.ui?.alternateBuffer;
298
+ }
299
+
300
+ export function getDefaultAlternateBufferEnabled(): boolean {
301
+ return !isConptyTerminal();
302
+ }
303
+
304
+ export function getAlternateBufferEnabled(): boolean {
305
+ const explicit = getAlternateBufferSetting();
306
+ if (typeof explicit === "boolean") {
307
+ return explicit;
308
+ }
309
+ return getDefaultAlternateBufferEnabled();
310
+ }
311
+
312
+ /**
313
+ * Save alternate buffer preference to settings.
314
+ *
315
+ * Creates the settings file and directory if they don't exist.
316
+ * Preserves other settings in the file.
317
+ *
318
+ * @param enabled - Whether to enable alternate buffer
319
+ *
320
+ * @example
321
+ * ```typescript
322
+ * setAlternateBufferEnabled(false);
323
+ * // Now getAlternateBufferEnabled() returns false
324
+ * ```
325
+ */
326
+ export function setAlternateBufferEnabled(enabled: boolean): void {
327
+ const existingSettings = readSettings() ?? {};
328
+ const newSettings: VellumSettings = {
329
+ ...existingSettings,
330
+ ui: {
331
+ ...existingSettings.ui,
332
+ alternateBuffer: enabled,
333
+ },
334
+ };
335
+ writeSettings(newSettings);
336
+ }
337
+
338
+ /**
339
+ * Get all UI settings.
340
+ *
341
+ * @returns UI settings object with defaults applied
342
+ */
343
+ export function getUISettings(): UISettings {
344
+ const settings = readSettings();
345
+ return {
346
+ alternateBuffer: settings?.ui?.alternateBuffer ?? getDefaultAlternateBufferEnabled(),
347
+ };
348
+ }
349
+
350
+ // =============================================================================
351
+ // Thinking Settings
352
+ // =============================================================================
353
+
354
+ /**
355
+ * Get the saved thinking settings.
356
+ *
357
+ * @returns Thinking settings object, or undefined if not saved
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * const thinking = getThinkingSettings();
362
+ * if (thinking?.enabled) {
363
+ * enableThinking(thinking.budgetTokens);
364
+ * }
365
+ * ```
366
+ */
367
+ export function getThinkingSettings(): ThinkingSettings | undefined {
368
+ const settings = readSettings();
369
+ return settings?.thinking;
370
+ }
371
+
372
+ /**
373
+ * Save thinking settings.
374
+ *
375
+ * @param thinking - Thinking settings to save
376
+ */
377
+ export function setThinkingSettings(thinking: ThinkingSettings): void {
378
+ const existingSettings = readSettings() ?? {};
379
+ const newSettings: VellumSettings = {
380
+ ...existingSettings,
381
+ thinking,
382
+ };
383
+ writeSettings(newSettings);
384
+ }
385
+
386
+ /**
387
+ * Get the thinking display mode preference.
388
+ *
389
+ * @returns Display mode ("full" or "compact"), defaults to "full"
390
+ *
391
+ * @example
392
+ * ```typescript
393
+ * const mode = getThinkingDisplayMode();
394
+ * // mode is "full" | "compact"
395
+ * ```
396
+ */
397
+ export function getThinkingDisplayMode(): ThinkingDisplayMode {
398
+ const settings = readSettings();
399
+ const mode = settings?.thinking?.displayMode;
400
+ if (mode === "full" || mode === "compact") {
401
+ return mode;
402
+ }
403
+ return "full"; // Default
404
+ }
405
+
406
+ /**
407
+ * Set the thinking display mode preference.
408
+ *
409
+ * @param mode - Display mode to save ("full" or "compact")
410
+ *
411
+ * @example
412
+ * ```typescript
413
+ * setThinkingDisplayMode("compact");
414
+ * // Now thinking blocks will be compact by default
415
+ * ```
416
+ */
417
+ export function setThinkingDisplayMode(mode: ThinkingDisplayMode): void {
418
+ const existingSettings = readSettings() ?? {};
419
+ const existingThinking = existingSettings.thinking ?? {};
420
+ const newSettings: VellumSettings = {
421
+ ...existingSettings,
422
+ thinking: {
423
+ ...existingThinking,
424
+ displayMode: mode,
425
+ },
426
+ };
427
+ writeSettings(newSettings);
428
+ }
429
+
430
+ // =============================================================================
431
+ // Theme Settings
432
+ // =============================================================================
433
+
434
+ /**
435
+ * Get the saved theme preference.
436
+ *
437
+ * @returns Theme name, or undefined if not saved
438
+ */
439
+ export function getThemeFromSettings(): string | undefined {
440
+ const settings = readSettings();
441
+ return settings?.theme;
442
+ }
443
+
444
+ /**
445
+ * Save theme preference.
446
+ *
447
+ * @param theme - Theme name to save
448
+ */
449
+ export function setThemeInSettings(theme: string): void {
450
+ const existingSettings = readSettings() ?? {};
451
+ const newSettings: VellumSettings = {
452
+ ...existingSettings,
453
+ theme,
454
+ };
455
+ writeSettings(newSettings);
456
+ }
457
+
458
+ // =============================================================================
459
+ // Mode Settings
460
+ // =============================================================================
461
+
462
+ /**
463
+ * Get the saved mode preference.
464
+ *
465
+ * @returns Mode name, or undefined if not saved
466
+ */
467
+ export function getModeFromSettings(): string | undefined {
468
+ const settings = readSettings();
469
+ return settings?.mode;
470
+ }
471
+
472
+ /**
473
+ * Save mode preference.
474
+ *
475
+ * @param mode - Mode name to save
476
+ */
477
+ export function setModeInSettings(mode: string): void {
478
+ const existingSettings = readSettings() ?? {};
479
+ const newSettings: VellumSettings = {
480
+ ...existingSettings,
481
+ mode,
482
+ };
483
+ writeSettings(newSettings);
484
+ }
485
+
486
+ // =============================================================================
487
+ // Model Settings
488
+ // =============================================================================
489
+
490
+ /**
491
+ * Get the saved model configuration.
492
+ *
493
+ * @returns Model settings, or undefined if not saved
494
+ */
495
+ export function getModelSettings(): ModelSettings | undefined {
496
+ const settings = readSettings();
497
+ return settings?.model;
498
+ }
499
+
500
+ /**
501
+ * Save model configuration.
502
+ *
503
+ * @param model - Model settings to save
504
+ */
505
+ export function setModelSettings(model: ModelSettings): void {
506
+ const existingSettings = readSettings() ?? {};
507
+ const newSettings: VellumSettings = {
508
+ ...existingSettings,
509
+ model,
510
+ };
511
+ writeSettings(newSettings);
512
+ }
513
+
514
+ // =============================================================================
515
+ // Diff View Mode Settings
516
+ // =============================================================================
517
+
518
+ /**
519
+ * Get the saved diff view mode preference.
520
+ *
521
+ * @returns Diff view mode ("unified" or "side-by-side"), or undefined if not saved
522
+ *
523
+ * @example
524
+ * ```typescript
525
+ * const mode = getDiffViewMode();
526
+ * // mode is "unified" | "side-by-side" | undefined
527
+ * ```
528
+ */
529
+ export function getDiffViewMode(): DiffViewMode | undefined {
530
+ const settings = readSettings();
531
+ const mode = settings?.diffViewMode;
532
+ // Validate the value
533
+ if (mode === "unified" || mode === "side-by-side") {
534
+ return mode;
535
+ }
536
+ return undefined;
537
+ }
538
+
539
+ /**
540
+ * Save diff view mode preference.
541
+ *
542
+ * @param mode - Diff view mode to save ("unified" or "side-by-side")
543
+ *
544
+ * @example
545
+ * ```typescript
546
+ * setDiffViewMode("side-by-side");
547
+ * // Now getDiffViewMode() returns "side-by-side"
548
+ * ```
549
+ */
550
+ export function setDiffViewMode(mode: DiffViewMode): void {
551
+ const existingSettings = readSettings() ?? {};
552
+ const newSettings: VellumSettings = {
553
+ ...existingSettings,
554
+ diffViewMode: mode,
555
+ };
556
+ writeSettings(newSettings);
557
+ }