@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,228 @@
1
+ /**
2
+ * E2E Test Harness Type Definitions
3
+ *
4
+ * @module cli/test/e2e/types
5
+ */
6
+
7
+ /**
8
+ * Configuration for the CLI test harness
9
+ */
10
+ export interface HarnessConfig {
11
+ /** Path to CLI entry point (default: dist/index.js) */
12
+ cliPath?: string;
13
+
14
+ /** Default timeout in milliseconds (default: 30000) */
15
+ timeout?: number;
16
+
17
+ /** Working directory for CLI execution */
18
+ cwd?: string;
19
+
20
+ /** Environment variables to inject */
21
+ env?: Record<string, string>;
22
+
23
+ /** Whether to inherit parent env (default: true) */
24
+ inheritEnv?: boolean;
25
+
26
+ /** Encoding for stdout/stderr (default: utf-8) */
27
+ encoding?: BufferEncoding;
28
+
29
+ /** Enable debug logging */
30
+ debug?: boolean;
31
+ }
32
+
33
+ /**
34
+ * Resolved harness configuration with defaults applied
35
+ */
36
+ export interface ResolvedHarnessConfig {
37
+ cliPath: string;
38
+ timeout: number;
39
+ cwd: string;
40
+ env: Record<string, string>;
41
+ inheritEnv: boolean;
42
+ encoding: BufferEncoding;
43
+ debug: boolean;
44
+ }
45
+
46
+ /**
47
+ * Input step for interactive CLI testing
48
+ */
49
+ export interface InputStep {
50
+ /** The input to send to stdin */
51
+ input: string;
52
+
53
+ /** Delay before sending input (ms) */
54
+ delay?: number;
55
+
56
+ /** Wait for specific output before sending */
57
+ waitFor?: string | RegExp;
58
+
59
+ /** Timeout for waitFor (ms) */
60
+ waitTimeout?: number;
61
+ }
62
+
63
+ /**
64
+ * Expected output matcher
65
+ */
66
+ export interface OutputMatcher {
67
+ /** Match stdout */
68
+ stdout?: string | RegExp;
69
+
70
+ /** Match stderr */
71
+ stderr?: string | RegExp;
72
+
73
+ /** Expected exit code */
74
+ exitCode?: number;
75
+
76
+ /** Output should contain all of these */
77
+ contains?: string[];
78
+
79
+ /** Output should NOT contain any of these */
80
+ excludes?: string[];
81
+ }
82
+
83
+ /**
84
+ * Test scenario definition
85
+ */
86
+ export interface TestScenario {
87
+ /** Scenario name for reporting */
88
+ name: string;
89
+
90
+ /** Description of what this scenario tests */
91
+ description?: string;
92
+
93
+ /** CLI arguments to pass */
94
+ args: string[];
95
+
96
+ /** Interactive input steps */
97
+ inputs?: InputStep[];
98
+
99
+ /** Expected output/behavior */
100
+ expected: OutputMatcher;
101
+
102
+ /** Scenario-specific timeout (overrides harness default) */
103
+ timeout?: number;
104
+
105
+ /** Environment variables for this scenario */
106
+ env?: Record<string, string>;
107
+
108
+ /** Working directory for this scenario */
109
+ cwd?: string;
110
+
111
+ /** Skip this scenario */
112
+ skip?: boolean;
113
+
114
+ /** Run only this scenario */
115
+ only?: boolean;
116
+
117
+ /** Setup function before scenario runs */
118
+ setup?: () => Promise<void>;
119
+
120
+ /** Teardown function after scenario completes */
121
+ teardown?: () => Promise<void>;
122
+ }
123
+
124
+ /**
125
+ * Result of a CLI execution
126
+ */
127
+ export interface CLIResult {
128
+ /** Combined stdout output */
129
+ stdout: string;
130
+
131
+ /** Combined stderr output */
132
+ stderr: string;
133
+
134
+ /** Exit code (null if process was killed) */
135
+ exitCode: number | null;
136
+
137
+ /** Signal that terminated the process (if any) */
138
+ signal: NodeJS.Signals | null;
139
+
140
+ /** Execution duration in milliseconds */
141
+ duration: number;
142
+
143
+ /** Whether the process timed out */
144
+ timedOut: boolean;
145
+
146
+ /** Raw stdout chunks for streaming analysis */
147
+ stdoutChunks: string[];
148
+
149
+ /** Raw stderr chunks for streaming analysis */
150
+ stderrChunks: string[];
151
+ }
152
+
153
+ /**
154
+ * Scenario execution result
155
+ */
156
+ export interface ScenarioResult {
157
+ /** The executed scenario */
158
+ scenario: TestScenario;
159
+
160
+ /** CLI execution result */
161
+ result: CLIResult;
162
+
163
+ /** Whether all assertions passed */
164
+ passed: boolean;
165
+
166
+ /** Assertion failures (if any) */
167
+ failures: AssertionFailure[];
168
+
169
+ /** Execution error (if any) */
170
+ error?: Error;
171
+ }
172
+
173
+ /**
174
+ * Assertion failure details
175
+ */
176
+ export interface AssertionFailure {
177
+ /** Type of assertion that failed */
178
+ type: "stdout" | "stderr" | "exitCode" | "contains" | "excludes" | "timeout";
179
+
180
+ /** Expected value */
181
+ expected: unknown;
182
+
183
+ /** Actual value */
184
+ actual: unknown;
185
+
186
+ /** Human-readable message */
187
+ message: string;
188
+ }
189
+
190
+ /**
191
+ * Batch run result
192
+ */
193
+ export interface BatchResult {
194
+ /** Total scenarios executed */
195
+ total: number;
196
+
197
+ /** Passed scenarios */
198
+ passed: number;
199
+
200
+ /** Failed scenarios */
201
+ failed: number;
202
+
203
+ /** Skipped scenarios */
204
+ skipped: number;
205
+
206
+ /** Individual results */
207
+ results: ScenarioResult[];
208
+
209
+ /** Total duration in milliseconds */
210
+ duration: number;
211
+ }
212
+
213
+ /**
214
+ * Event emitted during CLI execution
215
+ */
216
+ export type HarnessEvent =
217
+ | { type: "spawn"; pid: number }
218
+ | { type: "stdout"; data: string }
219
+ | { type: "stderr"; data: string }
220
+ | { type: "input"; data: string }
221
+ | { type: "exit"; code: number | null; signal: NodeJS.Signals | null }
222
+ | { type: "timeout" }
223
+ | { type: "error"; error: Error };
224
+
225
+ /**
226
+ * Event listener for harness events
227
+ */
228
+ export type HarnessEventListener = (event: HarnessEvent) => void;
@@ -0,0 +1,314 @@
1
+ /**
2
+ * Tests for FakeResponseLoader
3
+ *
4
+ * @module cli/test/fixtures/__tests__/fake-response-loader
5
+ */
6
+
7
+ import { join } from "node:path";
8
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
9
+ import {
10
+ FAKE_RESPONSES_ENV,
11
+ FakeResponseLoader,
12
+ FIXTURES_DIR_ENV,
13
+ getFakeResponseLoader,
14
+ type MockResponse,
15
+ type MockStreamEvent,
16
+ resetFakeResponseLoader,
17
+ } from "../fake-response-loader.js";
18
+
19
+ // Path to test fixtures
20
+ const TEST_FIXTURES_DIR = join(__dirname, "../../../../__fixtures__/responses");
21
+
22
+ describe("FakeResponseLoader", () => {
23
+ let loader: FakeResponseLoader;
24
+
25
+ beforeEach(() => {
26
+ loader = new FakeResponseLoader(TEST_FIXTURES_DIR);
27
+ });
28
+
29
+ afterEach(() => {
30
+ resetFakeResponseLoader();
31
+ vi.unstubAllEnvs();
32
+ });
33
+
34
+ describe("constructor", () => {
35
+ it("should create loader with custom fixtures directory", () => {
36
+ const customDir = "/custom/fixtures";
37
+ const customLoader = new FakeResponseLoader(customDir);
38
+ expect(customLoader.getFixturesDir()).toBe(customDir);
39
+ });
40
+
41
+ it("should use environment variable for fixtures directory", () => {
42
+ const envDir = join(__dirname, "test-env-fixtures");
43
+ vi.stubEnv(FIXTURES_DIR_ENV, envDir);
44
+
45
+ const envLoader = new FakeResponseLoader();
46
+ expect(envLoader.getFixturesDir()).toBe(envDir);
47
+ });
48
+ });
49
+
50
+ describe("load", () => {
51
+ it("should load a valid fixture file", () => {
52
+ const fixture = loader.load("hello-world");
53
+
54
+ expect(fixture).not.toBeNull();
55
+ expect(fixture?.id).toBe("hello-world");
56
+ expect(fixture?.promptPattern).toBe("hello");
57
+ expect(fixture?.events).toBeInstanceOf(Array);
58
+ expect(fixture?.events.length).toBeGreaterThan(0);
59
+ });
60
+
61
+ it("should load fixture with .json extension", () => {
62
+ const fixture = loader.load("hello-world.json");
63
+
64
+ expect(fixture).not.toBeNull();
65
+ expect(fixture?.id).toBe("hello-world");
66
+ });
67
+
68
+ it("should return null for non-existent fixture", () => {
69
+ const fixture = loader.load("non-existent-fixture");
70
+ expect(fixture).toBeNull();
71
+ });
72
+
73
+ it("should cache loaded fixtures", () => {
74
+ const fixture1 = loader.load("hello-world");
75
+ const fixture2 = loader.getById("hello-world");
76
+
77
+ expect(fixture1).toBe(fixture2);
78
+ });
79
+ });
80
+
81
+ describe("loadAll", () => {
82
+ it("should load all fixtures from directory", () => {
83
+ loader.loadAll();
84
+ const fixtures = loader.getAll();
85
+
86
+ expect(fixtures.length).toBeGreaterThanOrEqual(3);
87
+ expect(fixtures.some((f: MockResponse) => f.id === "hello-world")).toBe(true);
88
+ expect(fixtures.some((f: MockResponse) => f.id === "code-generation")).toBe(true);
89
+ expect(fixtures.some((f: MockResponse) => f.id === "error-response")).toBe(true);
90
+ });
91
+
92
+ it("should only load once when called multiple times", () => {
93
+ loader.loadAll();
94
+ const count1 = loader.getAll().length;
95
+
96
+ loader.loadAll();
97
+ const count2 = loader.getAll().length;
98
+
99
+ expect(count1).toBe(count2);
100
+ });
101
+ });
102
+
103
+ describe("getResponse", () => {
104
+ it("should match simple string pattern", () => {
105
+ const response = loader.getResponse("hello world");
106
+
107
+ expect(response).not.toBeNull();
108
+ expect(response?.id).toBe("hello-world");
109
+ });
110
+
111
+ it("should match case-insensitively for simple patterns", () => {
112
+ const response = loader.getResponse("HELLO there");
113
+
114
+ expect(response).not.toBeNull();
115
+ expect(response?.id).toBe("hello-world");
116
+ });
117
+
118
+ it("should match regex patterns", () => {
119
+ const response = loader.getResponse("Please write a function for me");
120
+
121
+ expect(response).not.toBeNull();
122
+ expect(response?.id).toBe("code-generation");
123
+ });
124
+
125
+ it("should match another regex pattern variation", () => {
126
+ const response = loader.getResponse("Can you create some code?");
127
+
128
+ expect(response).not.toBeNull();
129
+ expect(response?.id).toBe("code-generation");
130
+ });
131
+
132
+ it("should return null for no match", () => {
133
+ const response = loader.getResponse("unrelated query xyz");
134
+ expect(response).toBeNull();
135
+ });
136
+
137
+ it("should match error trigger patterns", () => {
138
+ const response = loader.getResponse("trigger-error now");
139
+
140
+ expect(response).not.toBeNull();
141
+ expect(response?.id).toBe("error-response");
142
+ });
143
+ });
144
+
145
+ describe("getById", () => {
146
+ it("should return fixture by ID after loading", () => {
147
+ loader.load("code-generation");
148
+ const fixture = loader.getById("code-generation");
149
+
150
+ expect(fixture).not.toBeNull();
151
+ expect(fixture?.id).toBe("code-generation");
152
+ });
153
+
154
+ it("should attempt to load fixture if not cached", () => {
155
+ const fixture = loader.getById("hello-world");
156
+
157
+ expect(fixture).not.toBeNull();
158
+ expect(fixture?.id).toBe("hello-world");
159
+ });
160
+
161
+ it("should return null for non-existent ID", () => {
162
+ const fixture = loader.getById("does-not-exist");
163
+ expect(fixture).toBeNull();
164
+ });
165
+ });
166
+
167
+ describe("clear", () => {
168
+ it("should clear all cached fixtures", () => {
169
+ // Manually load some fixtures
170
+ loader.load("hello-world");
171
+ loader.load("code-generation");
172
+ loader.load("error-response");
173
+
174
+ loader.clear();
175
+ // After clear, getById should not find cached fixtures
176
+ // (but would load from disk if we call getById)
177
+ // The internal map should be empty
178
+ const fixture = loader.getById("does-not-exist-random");
179
+ expect(fixture).toBeNull();
180
+ });
181
+
182
+ it("should allow reloading after clear", () => {
183
+ loader.loadAll();
184
+ loader.clear();
185
+
186
+ const fixture = loader.load("hello-world");
187
+ expect(fixture).not.toBeNull();
188
+ });
189
+ });
190
+
191
+ describe("isEnabled", () => {
192
+ it("should return false when env var not set", () => {
193
+ vi.stubEnv(FAKE_RESPONSES_ENV, "");
194
+ expect(FakeResponseLoader.isEnabled()).toBe(false);
195
+ });
196
+
197
+ it("should return true when env var is 'true'", () => {
198
+ vi.stubEnv(FAKE_RESPONSES_ENV, "true");
199
+ expect(FakeResponseLoader.isEnabled()).toBe(true);
200
+ });
201
+
202
+ it("should return true when env var is '1'", () => {
203
+ vi.stubEnv(FAKE_RESPONSES_ENV, "1");
204
+ expect(FakeResponseLoader.isEnabled()).toBe(true);
205
+ });
206
+
207
+ it("should return false for other values", () => {
208
+ vi.stubEnv(FAKE_RESPONSES_ENV, "yes");
209
+ expect(FakeResponseLoader.isEnabled()).toBe(false);
210
+
211
+ vi.stubEnv(FAKE_RESPONSES_ENV, "false");
212
+ expect(FakeResponseLoader.isEnabled()).toBe(false);
213
+ });
214
+ });
215
+
216
+ describe("createStream", () => {
217
+ it("should create async iterable from response events", async () => {
218
+ const response: MockResponse = {
219
+ id: "test",
220
+ promptPattern: "test",
221
+ streamDelay: 0,
222
+ events: [
223
+ { type: "text", content: "Hello" },
224
+ { type: "text", content: " World" },
225
+ { type: "end", stopReason: "end_turn" },
226
+ ],
227
+ };
228
+
229
+ const events: MockStreamEvent[] = [];
230
+ for await (const event of FakeResponseLoader.createStream(response)) {
231
+ events.push(event);
232
+ }
233
+
234
+ expect(events.length).toBe(3);
235
+ expect(events[0]?.type).toBe("text");
236
+ expect(events[0]?.content).toBe("Hello");
237
+ expect(events[2]?.type).toBe("end");
238
+ });
239
+
240
+ it("should respect stream delay", async () => {
241
+ const response: MockResponse = {
242
+ id: "test",
243
+ promptPattern: "test",
244
+ streamDelay: 50,
245
+ events: [
246
+ { type: "text", content: "A" },
247
+ { type: "text", content: "B" },
248
+ ],
249
+ };
250
+
251
+ const start = Date.now();
252
+ const events: MockStreamEvent[] = [];
253
+ for await (const event of FakeResponseLoader.createStream(response)) {
254
+ events.push(event);
255
+ }
256
+ const elapsed = Date.now() - start;
257
+
258
+ expect(events.length).toBe(2);
259
+ expect(elapsed).toBeGreaterThanOrEqual(90); // ~50ms * 2 events (with some tolerance)
260
+ });
261
+ });
262
+
263
+ describe("global loader", () => {
264
+ it("should return singleton instance", () => {
265
+ const loader1 = getFakeResponseLoader();
266
+ const loader2 = getFakeResponseLoader();
267
+
268
+ expect(loader1).toBe(loader2);
269
+ });
270
+
271
+ it("should reset global instance", () => {
272
+ const loader1 = getFakeResponseLoader();
273
+ resetFakeResponseLoader();
274
+ const loader2 = getFakeResponseLoader();
275
+
276
+ expect(loader1).not.toBe(loader2);
277
+ });
278
+ });
279
+
280
+ describe("fixture content validation", () => {
281
+ it("hello-world fixture has correct structure", () => {
282
+ const fixture = loader.load("hello-world");
283
+
284
+ expect(fixture).not.toBeNull();
285
+ expect(fixture?.events.some((e: MockStreamEvent) => e.type === "text")).toBe(true);
286
+ expect(fixture?.events.some((e: MockStreamEvent) => e.type === "usage")).toBe(true);
287
+ expect(fixture?.events.some((e: MockStreamEvent) => e.type === "end")).toBe(true);
288
+ });
289
+
290
+ it("code-generation fixture has tool call events", () => {
291
+ const fixture = loader.load("code-generation");
292
+
293
+ expect(fixture).not.toBeNull();
294
+ expect(fixture?.events.some((e: MockStreamEvent) => e.type === "tool_call_start")).toBe(true);
295
+ expect(fixture?.events.some((e: MockStreamEvent) => e.type === "tool_call_delta")).toBe(true);
296
+ expect(fixture?.events.some((e: MockStreamEvent) => e.type === "tool_call_end")).toBe(true);
297
+
298
+ const toolStart = fixture?.events.find((e: MockStreamEvent) => e.type === "tool_call_start");
299
+ expect(toolStart?.toolCallId).toBe("toolu_01ABC123");
300
+ expect(toolStart?.toolName).toBe("write_file");
301
+ });
302
+
303
+ it("error-response fixture has error event", () => {
304
+ const fixture = loader.load("error-response");
305
+
306
+ expect(fixture).not.toBeNull();
307
+ expect(fixture?.events.some((e: MockStreamEvent) => e.type === "error")).toBe(true);
308
+
309
+ const errorEvent = fixture?.events.find((e: MockStreamEvent) => e.type === "error");
310
+ expect(errorEvent?.error?.code).toBe("RATE_LIMIT_EXCEEDED");
311
+ expect(errorEvent?.error?.message).toContain("rate limit");
312
+ });
313
+ });
314
+ });