@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,279 @@
1
+ /**
2
+ * TrustPrompt TUI Component (T060)
3
+ *
4
+ * Displays a trust confirmation prompt for new directories or monorepos.
5
+ * Uses keyboard navigation (Y/N/A/S) for quick interaction.
6
+ *
7
+ * @module tui/components/TrustPrompt
8
+ */
9
+
10
+ import * as path from "node:path";
11
+ import type { TrustPromptInfo, TrustScope } from "@vellum/core";
12
+ import { Box, Text, useInput } from "ink";
13
+ import type React from "react";
14
+ import { useCallback, useState } from "react";
15
+ import { useTUITranslation } from "../i18n/index.js";
16
+ import { useTheme } from "../theme/index.js";
17
+
18
+ // =============================================================================
19
+ // Types
20
+ // =============================================================================
21
+
22
+ /**
23
+ * User's trust decision
24
+ */
25
+ export type TrustDecision = "yes" | "no" | "always" | "skip";
26
+
27
+ /**
28
+ * Props for TrustPrompt component
29
+ */
30
+ export interface TrustPromptProps {
31
+ /** Trust prompt information from TrustManager */
32
+ promptInfo: TrustPromptInfo;
33
+ /** Callback when user makes a decision */
34
+ onDecision: (decision: TrustDecision, scope?: TrustScope) => void;
35
+ /** Optional: base path for relative display */
36
+ basePath?: string;
37
+ }
38
+
39
+ // =============================================================================
40
+ // Helper Functions
41
+ // =============================================================================
42
+
43
+ /**
44
+ * Format path for display (show relative if possible)
45
+ */
46
+ function formatPath(targetPath: string, basePath?: string): string {
47
+ if (!basePath) return targetPath;
48
+
49
+ try {
50
+ const relative = path.relative(basePath, targetPath);
51
+ // Only use relative if it's actually shorter and doesn't go up too many levels
52
+ if (relative && !relative.startsWith("..\\..\\..") && !relative.startsWith("../../..")) {
53
+ return relative || ".";
54
+ }
55
+ } catch {
56
+ // Ignore errors
57
+ }
58
+
59
+ return targetPath;
60
+ }
61
+
62
+ /**
63
+ * Get monorepo type display name
64
+ */
65
+ function getMonorepoTypeName(type: string): string {
66
+ const names: Record<string, string> = {
67
+ npm: "npm workspaces",
68
+ pnpm: "pnpm workspaces",
69
+ yarn: "Yarn workspaces",
70
+ turbo: "Turborepo",
71
+ lerna: "Lerna",
72
+ };
73
+ return names[type] ?? type;
74
+ }
75
+
76
+ // =============================================================================
77
+ // Sub-components
78
+ // =============================================================================
79
+
80
+ /**
81
+ * Option button component
82
+ */
83
+ function OptionButton({
84
+ label,
85
+ shortcut,
86
+ color,
87
+ isSelected,
88
+ }: {
89
+ label: string;
90
+ shortcut: string;
91
+ color: string;
92
+ isSelected?: boolean;
93
+ }): React.ReactElement {
94
+ const { theme } = useTheme();
95
+
96
+ return (
97
+ <Box marginRight={2}>
98
+ <Text color={isSelected ? theme.colors.primary : color} bold={isSelected}>
99
+ [{shortcut}] {label}
100
+ </Text>
101
+ </Box>
102
+ );
103
+ }
104
+
105
+ // =============================================================================
106
+ // Main Component
107
+ // =============================================================================
108
+
109
+ /**
110
+ * TrustPrompt - Interactive trust confirmation dialog
111
+ *
112
+ * Shows detected information and allows user to make trust decision
113
+ * using keyboard shortcuts.
114
+ *
115
+ * @example
116
+ * ```tsx
117
+ * <TrustPrompt
118
+ * promptInfo={promptInfo}
119
+ * onDecision={(decision) => handleDecision(decision)}
120
+ * />
121
+ * ```
122
+ */
123
+ export function TrustPrompt({
124
+ promptInfo,
125
+ onDecision,
126
+ basePath,
127
+ }: TrustPromptProps): React.ReactElement {
128
+ const { theme } = useTheme();
129
+ const { t } = useTUITranslation();
130
+ const [selectedOption, setSelectedOption] = useState<TrustDecision | null>(null);
131
+
132
+ // Handle keyboard input
133
+ useInput(
134
+ useCallback(
135
+ (input: string, key) => {
136
+ // Ignore if already selected
137
+ if (selectedOption) return;
138
+
139
+ const lowerInput = input.toLowerCase();
140
+
141
+ switch (lowerInput) {
142
+ case "y":
143
+ setSelectedOption("yes");
144
+ onDecision("yes", "session");
145
+ break;
146
+ case "n":
147
+ setSelectedOption("no");
148
+ onDecision("no");
149
+ break;
150
+ case "a":
151
+ setSelectedOption("always");
152
+ onDecision("always", "always");
153
+ break;
154
+ case "s":
155
+ setSelectedOption("skip");
156
+ onDecision("skip");
157
+ break;
158
+ default:
159
+ // Enter defaults to "yes"
160
+ if (key.return) {
161
+ setSelectedOption("yes");
162
+ onDecision("yes", "session");
163
+ }
164
+ break;
165
+ }
166
+ },
167
+ [selectedOption, onDecision]
168
+ )
169
+ );
170
+
171
+ const isMonorepo = promptInfo.reason === "monorepo";
172
+ const rootDisplay = formatPath(promptInfo.rootPath, basePath);
173
+ const currentDisplay = formatPath(promptInfo.currentPath, basePath);
174
+
175
+ return (
176
+ <Box
177
+ flexDirection="column"
178
+ borderStyle="round"
179
+ borderColor={theme.colors.warning}
180
+ paddingX={2}
181
+ paddingY={1}
182
+ >
183
+ {/* Header */}
184
+ <Box marginBottom={1}>
185
+ <Text bold color={theme.colors.warning}>
186
+ 🔒 {isMonorepo ? t("trust.detected_monorepo") : t("trust.new_project")}
187
+ </Text>
188
+ </Box>
189
+
190
+ {/* Info Section */}
191
+ <Box flexDirection="column" marginBottom={1}>
192
+ {isMonorepo && promptInfo.monorepoInfo && (
193
+ <Box>
194
+ <Text color={theme.colors.muted}>
195
+ {t("trust.monorepo_type")}: {getMonorepoTypeName(promptInfo.monorepoInfo.type)}
196
+ </Text>
197
+ </Box>
198
+ )}
199
+
200
+ <Box>
201
+ <Text color={theme.colors.info}>
202
+ {t("trust.root_directory")}: <Text bold>{rootDisplay}</Text>
203
+ </Text>
204
+ </Box>
205
+
206
+ {isMonorepo && promptInfo.currentPath !== promptInfo.rootPath && (
207
+ <Box>
208
+ <Text color={theme.colors.muted}>
209
+ {t("trust.current_directory")}: {currentDisplay}
210
+ </Text>
211
+ </Box>
212
+ )}
213
+
214
+ {isMonorepo && promptInfo.monorepoInfo && promptInfo.monorepoInfo.workspaces.length > 0 && (
215
+ <Box marginTop={1}>
216
+ <Text color={theme.colors.muted}>
217
+ {t("trust.workspaces")}: {promptInfo.monorepoInfo.workspaces.slice(0, 3).join(", ")}
218
+ {promptInfo.monorepoInfo.workspaces.length > 3
219
+ ? ` (+${promptInfo.monorepoInfo.workspaces.length - 3} more)`
220
+ : ""}
221
+ </Text>
222
+ </Box>
223
+ )}
224
+ </Box>
225
+
226
+ {/* Question */}
227
+ <Box marginBottom={1}>
228
+ <Text>{t("trust.prompt_trust")}</Text>
229
+ </Box>
230
+
231
+ {/* Options */}
232
+ <Box>
233
+ <OptionButton
234
+ label={t("trust.option_yes")}
235
+ shortcut="Y"
236
+ color={theme.colors.success}
237
+ isSelected={selectedOption === "yes"}
238
+ />
239
+ <OptionButton
240
+ label={t("trust.option_no")}
241
+ shortcut="N"
242
+ color={theme.colors.error}
243
+ isSelected={selectedOption === "no"}
244
+ />
245
+ <OptionButton
246
+ label={t("trust.option_always")}
247
+ shortcut="A"
248
+ color={theme.colors.info}
249
+ isSelected={selectedOption === "always"}
250
+ />
251
+ <OptionButton
252
+ label={t("trust.option_skip")}
253
+ shortcut="S"
254
+ color={theme.colors.muted}
255
+ isSelected={selectedOption === "skip"}
256
+ />
257
+ </Box>
258
+
259
+ {/* Result indicator */}
260
+ {selectedOption && (
261
+ <Box marginTop={1}>
262
+ {selectedOption === "yes" || selectedOption === "always" ? (
263
+ <Text color={theme.colors.success}>✓ {t("trust.added")}</Text>
264
+ ) : selectedOption === "no" ? (
265
+ <Text color={theme.colors.error}>✗ {t("trust.denied")}</Text>
266
+ ) : (
267
+ <Text color={theme.colors.muted}>⊘ {t("trust.skipped")}</Text>
268
+ )}
269
+ </Box>
270
+ )}
271
+ </Box>
272
+ );
273
+ }
274
+
275
+ // =============================================================================
276
+ // Exports
277
+ // =============================================================================
278
+
279
+ export default TrustPrompt;
@@ -0,0 +1,166 @@
1
+ /**
2
+ * UpdateBanner Component (Phase 39)
3
+ *
4
+ * React Ink component for displaying update availability notifications.
5
+ * Shows a dismissible banner when a new version is available.
6
+ *
7
+ * @module tui/components/UpdateBanner
8
+ */
9
+
10
+ import { Box, Text, useInput } from "ink";
11
+ import type React from "react";
12
+ import { useState } from "react";
13
+ import { useTUITranslation } from "../i18n/index.js";
14
+
15
+ // =============================================================================
16
+ // Types
17
+ // =============================================================================
18
+
19
+ /**
20
+ * Props for the UpdateBanner component
21
+ */
22
+ export interface UpdateBannerProps {
23
+ /** Current installed version */
24
+ readonly currentVersion: string;
25
+ /** Latest available version */
26
+ readonly latestVersion: string;
27
+ /** Release notes URL (optional) */
28
+ readonly releaseNotesUrl?: string;
29
+ /** Whether the banner can be dismissed */
30
+ readonly dismissible?: boolean;
31
+ /** Callback when banner is dismissed */
32
+ readonly onDismiss?: () => void;
33
+ /** Whether to show in compact mode */
34
+ readonly compact?: boolean;
35
+ }
36
+
37
+ // =============================================================================
38
+ // Component
39
+ // =============================================================================
40
+
41
+ /**
42
+ * UpdateBanner displays a notification when a new version is available.
43
+ *
44
+ * @example
45
+ * ```tsx
46
+ * <UpdateBanner
47
+ * currentVersion="0.1.0"
48
+ * latestVersion="0.2.0"
49
+ * releaseNotesUrl="https://github.com/..."
50
+ * dismissible
51
+ * />
52
+ * ```
53
+ */
54
+ export const UpdateBanner: React.FC<UpdateBannerProps> = ({
55
+ currentVersion,
56
+ latestVersion,
57
+ releaseNotesUrl,
58
+ dismissible = true,
59
+ onDismiss,
60
+ compact = false,
61
+ }) => {
62
+ const { t } = useTUITranslation();
63
+ const [dismissed, setDismissed] = useState(false);
64
+
65
+ // Handle dismiss key press
66
+ useInput(
67
+ (input, key) => {
68
+ if (dismissible && (input === "d" || input === "D" || key.escape)) {
69
+ setDismissed(true);
70
+ onDismiss?.();
71
+ }
72
+ },
73
+ { isActive: dismissible && !dismissed }
74
+ );
75
+
76
+ // Don't render if dismissed
77
+ if (dismissed) {
78
+ return null;
79
+ }
80
+
81
+ // Compact mode - single line
82
+ if (compact) {
83
+ return (
84
+ <Box>
85
+ <Text color="yellow">
86
+ ⬆ v{latestVersion} available
87
+ {dismissible && <Text color="gray"> {t("update.dismissHint")}</Text>}
88
+ </Text>
89
+ </Box>
90
+ );
91
+ }
92
+
93
+ // Full mode - bordered box
94
+ return (
95
+ <Box flexDirection="column" borderStyle="round" borderColor="yellow" paddingX={1} marginY={1}>
96
+ <Box>
97
+ <Text color="yellow" bold>
98
+ ⬆ {t("update.available")}
99
+ </Text>
100
+ </Box>
101
+
102
+ <Box marginTop={1}>
103
+ <Text>
104
+ <Text color="gray">{t("update.current")}</Text>
105
+ <Text>v{currentVersion}</Text>
106
+ <Text color="gray"> → </Text>
107
+ <Text color="green" bold>
108
+ v{latestVersion}
109
+ </Text>
110
+ </Text>
111
+ </Box>
112
+
113
+ <Box marginTop={1}>
114
+ <Text color="cyan">{t("update.upgradeHint")}</Text>
115
+ </Box>
116
+
117
+ {releaseNotesUrl && (
118
+ <Box marginTop={1}>
119
+ <Text color="gray" dimColor>
120
+ Release notes: {releaseNotesUrl}
121
+ </Text>
122
+ </Box>
123
+ )}
124
+
125
+ {dismissible && (
126
+ <Box marginTop={1}>
127
+ <Text color="gray" dimColor>
128
+ {t("update.dismissInstructions")}
129
+ </Text>
130
+ </Box>
131
+ )}
132
+ </Box>
133
+ );
134
+ };
135
+
136
+ // =============================================================================
137
+ // Inline Banner Variant
138
+ // =============================================================================
139
+
140
+ /**
141
+ * Props for the UpdateBannerInline component
142
+ */
143
+ export interface UpdateBannerInlineProps {
144
+ /** Latest available version */
145
+ readonly latestVersion: string;
146
+ }
147
+
148
+ /**
149
+ * Inline update banner for use in status bars or headers.
150
+ * Non-dismissible, minimal styling.
151
+ *
152
+ * @example
153
+ * ```tsx
154
+ * <UpdateBannerInline latestVersion="0.2.0" />
155
+ * ```
156
+ */
157
+ export const UpdateBannerInline: React.FC<UpdateBannerInlineProps> = ({ latestVersion }) => {
158
+ return (
159
+ <Box>
160
+ <Text backgroundColor="yellow" color="black">
161
+ {" "}
162
+ ⬆ v{latestVersion}{" "}
163
+ </Text>
164
+ </Box>
165
+ );
166
+ };
@@ -0,0 +1,112 @@
1
+ /**
2
+ * VimModeIndicator Component (T041)
3
+ *
4
+ * TUI component for displaying the current Vim editing mode.
5
+ * Shows mode name with visual styling (e.g., "-- NORMAL --").
6
+ *
7
+ * @module tui/components/VimModeIndicator
8
+ */
9
+
10
+ import { Box, Text } from "ink";
11
+ import type React from "react";
12
+ import type { VimMode } from "../hooks/useVim.js";
13
+ import { useTheme } from "../theme/index.js";
14
+
15
+ // =============================================================================
16
+ // Types
17
+ // =============================================================================
18
+
19
+ /**
20
+ * Props for the VimModeIndicator component.
21
+ */
22
+ export interface VimModeIndicatorProps {
23
+ /** Whether vim mode is enabled */
24
+ readonly enabled: boolean;
25
+ /** Current Vim mode */
26
+ readonly mode: VimMode;
27
+ /** Whether to show in compact mode (mode name only, no dashes) */
28
+ readonly compact?: boolean;
29
+ }
30
+
31
+ // =============================================================================
32
+ // Constants
33
+ // =============================================================================
34
+
35
+ /**
36
+ * Mode colors mapped to theme semantic colors.
37
+ * - NORMAL: blue (info) - command mode
38
+ * - INSERT: green (success) - editing
39
+ * - VISUAL: yellow (warning) - selection
40
+ * - COMMAND: purple (primary) - command line
41
+ */
42
+ const MODE_COLOR_KEYS: Record<VimMode, "info" | "success" | "warning" | "primary"> = {
43
+ NORMAL: "info",
44
+ INSERT: "success",
45
+ VISUAL: "warning",
46
+ COMMAND: "primary",
47
+ } as const;
48
+
49
+ // =============================================================================
50
+ // VimModeIndicator Component
51
+ // =============================================================================
52
+
53
+ /**
54
+ * VimModeIndicator - Displays the current Vim editing mode.
55
+ *
56
+ * Features:
57
+ * - Traditional Vim-style mode display (-- MODE --)
58
+ * - Color-coded by mode type
59
+ * - Compact mode option for space-constrained layouts
60
+ * - Only renders when vim mode is enabled
61
+ *
62
+ * @example
63
+ * ```tsx
64
+ * // Basic usage
65
+ * <VimModeIndicator enabled={true} mode="NORMAL" />
66
+ *
67
+ * // Compact mode
68
+ * <VimModeIndicator enabled={true} mode="INSERT" compact />
69
+ * ```
70
+ */
71
+ export function VimModeIndicator({
72
+ enabled,
73
+ mode,
74
+ compact = false,
75
+ }: VimModeIndicatorProps): React.ReactElement | null {
76
+ const { theme } = useTheme();
77
+
78
+ // Don't render if vim mode is disabled
79
+ if (!enabled) {
80
+ return null;
81
+ }
82
+
83
+ // Get color from theme
84
+ const colorKey = MODE_COLOR_KEYS[mode];
85
+ const color = theme.colors[colorKey];
86
+
87
+ // Compact mode: mode name only
88
+ if (compact) {
89
+ return (
90
+ <Box>
91
+ <Text color={color} bold>
92
+ {mode}
93
+ </Text>
94
+ </Box>
95
+ );
96
+ }
97
+
98
+ // Full mode: traditional Vim-style (-- MODE --)
99
+ return (
100
+ <Box>
101
+ <Text color={color} bold>
102
+ -- {mode} --
103
+ </Text>
104
+ </Box>
105
+ );
106
+ }
107
+
108
+ // =============================================================================
109
+ // Exports
110
+ // =============================================================================
111
+
112
+ export type { VimMode };