@gguf/coder 0.2.9 → 0.3.1

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 (439) hide show
  1. package/.editorconfig +16 -0
  2. package/.env.example +63 -0
  3. package/.gitattributes +1 -0
  4. package/.semgrepignore +19 -0
  5. package/coder-dummy-file.ts +52 -0
  6. package/coder.config.example.json +59 -0
  7. package/coder.config.json +13 -0
  8. package/color_picker.html +36 -0
  9. package/dist/tools/execute-bash.js +3 -3
  10. package/dist/tools/execute-bash.js.map +1 -1
  11. package/dist/tools/fetch-url.js +3 -3
  12. package/dist/tools/fetch-url.js.map +1 -1
  13. package/dist/tools/find-files.d.ts.map +1 -1
  14. package/dist/tools/find-files.js +1 -1
  15. package/dist/tools/find-files.js.map +1 -1
  16. package/dist/tools/lsp-get-diagnostics.js +1 -1
  17. package/dist/tools/lsp-get-diagnostics.js.map +1 -1
  18. package/dist/tools/read-file.d.ts.map +1 -1
  19. package/dist/tools/read-file.js +6 -6
  20. package/dist/tools/read-file.js.map +1 -1
  21. package/dist/tools/search-file-contents.d.ts.map +1 -1
  22. package/dist/tools/search-file-contents.js +1 -1
  23. package/dist/tools/search-file-contents.js.map +1 -1
  24. package/dist/tools/string-replace.js +11 -11
  25. package/dist/tools/string-replace.js.map +1 -1
  26. package/dist/tools/web-search.d.ts.map +1 -1
  27. package/dist/tools/web-search.js +3 -3
  28. package/dist/tools/web-search.js.map +1 -1
  29. package/dist/tools/write-file.js +4 -4
  30. package/dist/tools/write-file.js.map +1 -1
  31. package/dist/utils/tool-result-display.d.ts.map +1 -1
  32. package/dist/utils/tool-result-display.js +3 -3
  33. package/dist/utils/tool-result-display.js.map +1 -1
  34. package/package.json +2 -14
  35. package/scripts/extract-changelog.js +73 -0
  36. package/scripts/fetch-models.js +143 -0
  37. package/scripts/test.sh +40 -0
  38. package/scripts/update-homebrew-formula.sh +125 -0
  39. package/scripts/update-nix-version.sh +157 -0
  40. package/source/ai-sdk-client/AISDKClient.spec.ts +117 -0
  41. package/source/ai-sdk-client/AISDKClient.ts +155 -0
  42. package/source/ai-sdk-client/chat/chat-handler.spec.ts +121 -0
  43. package/source/ai-sdk-client/chat/chat-handler.ts +276 -0
  44. package/source/ai-sdk-client/chat/streaming-handler.spec.ts +173 -0
  45. package/source/ai-sdk-client/chat/streaming-handler.ts +110 -0
  46. package/source/ai-sdk-client/chat/tool-processor.spec.ts +92 -0
  47. package/source/ai-sdk-client/chat/tool-processor.ts +70 -0
  48. package/source/ai-sdk-client/converters/message-converter.spec.ts +220 -0
  49. package/source/ai-sdk-client/converters/message-converter.ts +113 -0
  50. package/source/ai-sdk-client/converters/tool-converter.spec.ts +90 -0
  51. package/source/ai-sdk-client/converters/tool-converter.ts +46 -0
  52. package/source/ai-sdk-client/error-handling/error-extractor.spec.ts +55 -0
  53. package/source/ai-sdk-client/error-handling/error-extractor.ts +15 -0
  54. package/source/ai-sdk-client/error-handling/error-parser.spec.ts +169 -0
  55. package/source/ai-sdk-client/error-handling/error-parser.ts +161 -0
  56. package/source/ai-sdk-client/index.ts +7 -0
  57. package/source/ai-sdk-client/providers/provider-factory.spec.ts +71 -0
  58. package/source/ai-sdk-client/providers/provider-factory.ts +41 -0
  59. package/source/ai-sdk-client/types.ts +9 -0
  60. package/source/ai-sdk-client-empty-message.spec.ts +141 -0
  61. package/source/ai-sdk-client-error-handling.spec.ts +186 -0
  62. package/source/ai-sdk-client-maxretries.spec.ts +114 -0
  63. package/source/ai-sdk-client-preparestep.spec.ts +279 -0
  64. package/source/app/App.spec.tsx +32 -0
  65. package/source/app/App.tsx +480 -0
  66. package/source/app/components/AppContainer.spec.tsx +96 -0
  67. package/source/app/components/AppContainer.tsx +56 -0
  68. package/source/app/components/ChatInterface.spec.tsx +163 -0
  69. package/source/app/components/ChatInterface.tsx +144 -0
  70. package/source/app/components/ModalSelectors.spec.tsx +141 -0
  71. package/source/app/components/ModalSelectors.tsx +135 -0
  72. package/source/app/helpers.spec.ts +97 -0
  73. package/source/app/helpers.ts +63 -0
  74. package/source/app/index.ts +4 -0
  75. package/source/app/types.ts +39 -0
  76. package/source/app/utils/appUtils.ts +294 -0
  77. package/source/app/utils/conversationState.ts +310 -0
  78. package/source/app.spec.tsx +244 -0
  79. package/source/cli.spec.ts +73 -0
  80. package/source/cli.tsx +51 -0
  81. package/source/client-factory.spec.ts +48 -0
  82. package/source/client-factory.ts +178 -0
  83. package/source/command-parser.spec.ts +127 -0
  84. package/source/command-parser.ts +36 -0
  85. package/source/commands/checkpoint.spec.tsx +277 -0
  86. package/source/commands/checkpoint.tsx +366 -0
  87. package/source/commands/clear.tsx +22 -0
  88. package/source/commands/custom-commands.tsx +121 -0
  89. package/source/commands/exit.ts +21 -0
  90. package/source/commands/export.spec.tsx +131 -0
  91. package/source/commands/export.tsx +79 -0
  92. package/source/commands/help.tsx +120 -0
  93. package/source/commands/index.ts +17 -0
  94. package/source/commands/init.tsx +339 -0
  95. package/source/commands/lsp-command.spec.tsx +281 -0
  96. package/source/commands/lsp.tsx +120 -0
  97. package/source/commands/mcp-command.spec.tsx +313 -0
  98. package/source/commands/mcp.tsx +162 -0
  99. package/source/commands/model-database.spec.tsx +758 -0
  100. package/source/commands/model-database.tsx +418 -0
  101. package/source/commands/model.ts +12 -0
  102. package/source/commands/provider.ts +12 -0
  103. package/source/commands/setup-config.tsx +16 -0
  104. package/source/commands/simple-commands.spec.tsx +175 -0
  105. package/source/commands/status.ts +12 -0
  106. package/source/commands/theme.ts +12 -0
  107. package/source/commands/update.spec.tsx +261 -0
  108. package/source/commands/update.tsx +201 -0
  109. package/source/commands/usage.spec.tsx +495 -0
  110. package/source/commands/usage.tsx +100 -0
  111. package/source/commands.spec.ts +436 -0
  112. package/source/commands.ts +83 -0
  113. package/source/components/assistant-message.spec.tsx +796 -0
  114. package/source/components/assistant-message.tsx +34 -0
  115. package/source/components/bash-execution-indicator.tsx +21 -0
  116. package/source/components/cancelling-indicator.tsx +16 -0
  117. package/source/components/chat-queue.spec.tsx +83 -0
  118. package/source/components/chat-queue.tsx +36 -0
  119. package/source/components/checkpoint-display.spec.tsx +219 -0
  120. package/source/components/checkpoint-display.tsx +126 -0
  121. package/source/components/checkpoint-selector.spec.tsx +173 -0
  122. package/source/components/checkpoint-selector.tsx +173 -0
  123. package/source/components/development-mode-indicator.spec.tsx +268 -0
  124. package/source/components/development-mode-indicator.tsx +38 -0
  125. package/source/components/message-box.spec.tsx +427 -0
  126. package/source/components/message-box.tsx +87 -0
  127. package/source/components/model-selector.tsx +132 -0
  128. package/source/components/provider-selector.tsx +75 -0
  129. package/source/components/random-spinner.tsx +19 -0
  130. package/source/components/security-disclaimer.tsx +73 -0
  131. package/source/components/status-connection-display.spec.tsx +133 -0
  132. package/source/components/status.tsx +267 -0
  133. package/source/components/theme-selector.tsx +126 -0
  134. package/source/components/tool-confirmation.tsx +190 -0
  135. package/source/components/tool-execution-indicator.tsx +33 -0
  136. package/source/components/tool-message.tsx +85 -0
  137. package/source/components/ui/titled-box.spec.tsx +207 -0
  138. package/source/components/ui/titled-box.tsx +57 -0
  139. package/source/components/usage/progress-bar.spec.tsx +398 -0
  140. package/source/components/usage/progress-bar.tsx +30 -0
  141. package/source/components/usage/usage-display.spec.tsx +780 -0
  142. package/source/components/usage/usage-display.tsx +291 -0
  143. package/source/components/user-input.spec.tsx +327 -0
  144. package/source/components/user-input.tsx +533 -0
  145. package/source/components/user-message.spec.tsx +230 -0
  146. package/source/components/user-message.tsx +84 -0
  147. package/source/components/welcome-message.tsx +76 -0
  148. package/source/config/env-substitution.ts +65 -0
  149. package/source/config/index.spec.ts +171 -0
  150. package/source/config/index.ts +154 -0
  151. package/source/config/paths.spec.ts +241 -0
  152. package/source/config/paths.ts +55 -0
  153. package/source/config/preferences.ts +51 -0
  154. package/source/config/themes.ts +315 -0
  155. package/source/constants.ts +130 -0
  156. package/source/context/mode-context.spec.ts +79 -0
  157. package/source/context/mode-context.ts +24 -0
  158. package/source/custom-commands/executor.spec.ts +142 -0
  159. package/source/custom-commands/executor.ts +64 -0
  160. package/source/custom-commands/loader.spec.ts +314 -0
  161. package/source/custom-commands/loader.ts +153 -0
  162. package/source/custom-commands/parser.ts +196 -0
  163. package/source/hooks/chat-handler/conversation/conversation-loop.spec.ts +39 -0
  164. package/source/hooks/chat-handler/conversation/conversation-loop.tsx +511 -0
  165. package/source/hooks/chat-handler/conversation/tool-executor.spec.ts +50 -0
  166. package/source/hooks/chat-handler/conversation/tool-executor.tsx +109 -0
  167. package/source/hooks/chat-handler/index.ts +12 -0
  168. package/source/hooks/chat-handler/state/streaming-state.spec.ts +26 -0
  169. package/source/hooks/chat-handler/state/streaming-state.ts +19 -0
  170. package/source/hooks/chat-handler/types.ts +38 -0
  171. package/source/hooks/chat-handler/useChatHandler.spec.tsx +321 -0
  172. package/source/hooks/chat-handler/useChatHandler.tsx +194 -0
  173. package/source/hooks/chat-handler/utils/context-checker.spec.ts +60 -0
  174. package/source/hooks/chat-handler/utils/context-checker.tsx +73 -0
  175. package/source/hooks/chat-handler/utils/message-helpers.spec.ts +42 -0
  176. package/source/hooks/chat-handler/utils/message-helpers.tsx +36 -0
  177. package/source/hooks/chat-handler/utils/tool-filters.spec.ts +109 -0
  178. package/source/hooks/chat-handler/utils/tool-filters.ts +64 -0
  179. package/source/hooks/useAppHandlers.tsx +291 -0
  180. package/source/hooks/useAppInitialization.tsx +422 -0
  181. package/source/hooks/useAppState.tsx +311 -0
  182. package/source/hooks/useDirectoryTrust.tsx +98 -0
  183. package/source/hooks/useInputState.ts +414 -0
  184. package/source/hooks/useModeHandlers.tsx +302 -0
  185. package/source/hooks/useNonInteractiveMode.ts +140 -0
  186. package/source/hooks/useTerminalWidth.tsx +81 -0
  187. package/source/hooks/useTheme.ts +18 -0
  188. package/source/hooks/useToolHandler.tsx +349 -0
  189. package/source/hooks/useUIState.ts +61 -0
  190. package/source/init/agents-template-generator.ts +421 -0
  191. package/source/init/existing-rules-extractor.ts +319 -0
  192. package/source/init/file-scanner.spec.ts +227 -0
  193. package/source/init/file-scanner.ts +238 -0
  194. package/source/init/framework-detector.ts +382 -0
  195. package/source/init/language-detector.ts +269 -0
  196. package/source/init/project-analyzer.spec.ts +231 -0
  197. package/source/init/project-analyzer.ts +458 -0
  198. package/source/lsp/index.ts +31 -0
  199. package/source/lsp/lsp-client.spec.ts +508 -0
  200. package/source/lsp/lsp-client.ts +487 -0
  201. package/source/lsp/lsp-manager.spec.ts +477 -0
  202. package/source/lsp/lsp-manager.ts +419 -0
  203. package/source/lsp/protocol.spec.ts +502 -0
  204. package/source/lsp/protocol.ts +360 -0
  205. package/source/lsp/server-discovery.spec.ts +654 -0
  206. package/source/lsp/server-discovery.ts +515 -0
  207. package/source/markdown-parser/html-entities.spec.ts +88 -0
  208. package/source/markdown-parser/html-entities.ts +45 -0
  209. package/source/markdown-parser/index.spec.ts +281 -0
  210. package/source/markdown-parser/index.ts +126 -0
  211. package/source/markdown-parser/table-parser.spec.ts +133 -0
  212. package/source/markdown-parser/table-parser.ts +114 -0
  213. package/source/markdown-parser/utils.spec.ts +70 -0
  214. package/source/markdown-parser/utils.ts +13 -0
  215. package/source/mcp/mcp-client.spec.ts +81 -0
  216. package/source/mcp/mcp-client.ts +625 -0
  217. package/source/mcp/transport-factory.spec.ts +406 -0
  218. package/source/mcp/transport-factory.ts +312 -0
  219. package/source/message-handler.ts +67 -0
  220. package/source/model-database/database-engine.spec.ts +494 -0
  221. package/source/model-database/database-engine.ts +50 -0
  222. package/source/model-database/model-database.spec.ts +363 -0
  223. package/source/model-database/model-database.ts +91 -0
  224. package/source/model-database/model-engine.spec.ts +447 -0
  225. package/source/model-database/model-engine.ts +65 -0
  226. package/source/model-database/model-fetcher.spec.ts +583 -0
  227. package/source/model-database/model-fetcher.ts +330 -0
  228. package/source/models/index.ts +1 -0
  229. package/source/models/models-cache.spec.ts +214 -0
  230. package/source/models/models-cache.ts +78 -0
  231. package/source/models/models-dev-client.spec.ts +379 -0
  232. package/source/models/models-dev-client.ts +329 -0
  233. package/source/models/models-types.ts +68 -0
  234. package/source/prompt-history.ts +155 -0
  235. package/source/security/command-injection.spec.ts +240 -0
  236. package/source/services/checkpoint-manager.spec.ts +523 -0
  237. package/source/services/checkpoint-manager.ts +466 -0
  238. package/source/services/file-snapshot.spec.ts +569 -0
  239. package/source/services/file-snapshot.ts +220 -0
  240. package/source/test-utils/render-with-theme.tsx +48 -0
  241. package/source/tokenization/index.ts +1 -0
  242. package/source/tokenization/tokenizer-factory.spec.ts +170 -0
  243. package/source/tokenization/tokenizer-factory.ts +125 -0
  244. package/source/tokenization/tokenizers/anthropic-tokenizer.spec.ts +200 -0
  245. package/source/tokenization/tokenizers/anthropic-tokenizer.ts +43 -0
  246. package/source/tokenization/tokenizers/fallback-tokenizer.spec.ts +236 -0
  247. package/source/tokenization/tokenizers/fallback-tokenizer.ts +26 -0
  248. package/source/tokenization/tokenizers/llama-tokenizer.spec.ts +224 -0
  249. package/source/tokenization/tokenizers/llama-tokenizer.ts +41 -0
  250. package/source/tokenization/tokenizers/openai-tokenizer.spec.ts +184 -0
  251. package/source/tokenization/tokenizers/openai-tokenizer.ts +57 -0
  252. package/source/tool-calling/index.ts +5 -0
  253. package/source/tool-calling/json-parser.spec.ts +639 -0
  254. package/source/tool-calling/json-parser.ts +247 -0
  255. package/source/tool-calling/tool-parser.spec.ts +395 -0
  256. package/source/tool-calling/tool-parser.ts +120 -0
  257. package/source/tool-calling/xml-parser.spec.ts +662 -0
  258. package/source/tool-calling/xml-parser.ts +289 -0
  259. package/source/tools/execute-bash.spec.tsx +353 -0
  260. package/source/tools/execute-bash.tsx +219 -0
  261. package/source/tools/execute-function.spec.ts +130 -0
  262. package/source/tools/fetch-url.spec.tsx +342 -0
  263. package/source/tools/fetch-url.tsx +172 -0
  264. package/source/tools/find-files.spec.tsx +924 -0
  265. package/source/tools/find-files.tsx +293 -0
  266. package/source/tools/index.ts +102 -0
  267. package/source/tools/lsp-get-diagnostics.tsx +192 -0
  268. package/source/tools/needs-approval.spec.ts +282 -0
  269. package/source/tools/read-file.spec.tsx +801 -0
  270. package/source/tools/read-file.tsx +387 -0
  271. package/source/tools/search-file-contents.spec.tsx +1273 -0
  272. package/source/tools/search-file-contents.tsx +293 -0
  273. package/source/tools/string-replace.spec.tsx +730 -0
  274. package/source/tools/string-replace.tsx +548 -0
  275. package/source/tools/tool-manager.ts +210 -0
  276. package/source/tools/tool-registry.spec.ts +415 -0
  277. package/source/tools/tool-registry.ts +228 -0
  278. package/source/tools/web-search.tsx +223 -0
  279. package/source/tools/write-file.spec.tsx +559 -0
  280. package/source/tools/write-file.tsx +228 -0
  281. package/source/types/app.ts +37 -0
  282. package/source/types/checkpoint.ts +48 -0
  283. package/source/types/commands.ts +46 -0
  284. package/source/types/components.ts +27 -0
  285. package/source/types/config.ts +103 -0
  286. package/source/types/core-connection-status.spec.ts +67 -0
  287. package/source/types/core.ts +181 -0
  288. package/source/types/hooks.ts +50 -0
  289. package/source/types/index.ts +12 -0
  290. package/source/types/markdown-parser.ts +11 -0
  291. package/source/types/mcp.ts +52 -0
  292. package/source/types/system.ts +16 -0
  293. package/source/types/tokenization.ts +41 -0
  294. package/source/types/ui.ts +40 -0
  295. package/source/types/usage.ts +58 -0
  296. package/source/types/utils.ts +16 -0
  297. package/source/usage/calculator.spec.ts +385 -0
  298. package/source/usage/calculator.ts +104 -0
  299. package/source/usage/storage.spec.ts +703 -0
  300. package/source/usage/storage.ts +238 -0
  301. package/source/usage/tracker.spec.ts +456 -0
  302. package/source/usage/tracker.ts +102 -0
  303. package/source/utils/atomic-deletion.spec.ts +194 -0
  304. package/source/utils/atomic-deletion.ts +127 -0
  305. package/source/utils/bounded-map.spec.ts +300 -0
  306. package/source/utils/bounded-map.ts +193 -0
  307. package/source/utils/checkpoint-utils.spec.ts +222 -0
  308. package/source/utils/checkpoint-utils.ts +92 -0
  309. package/source/utils/error-formatter.spec.ts +169 -0
  310. package/source/utils/error-formatter.ts +194 -0
  311. package/source/utils/file-autocomplete.spec.ts +173 -0
  312. package/source/utils/file-autocomplete.ts +196 -0
  313. package/source/utils/file-cache.spec.ts +309 -0
  314. package/source/utils/file-cache.ts +195 -0
  315. package/source/utils/file-content-loader.spec.ts +180 -0
  316. package/source/utils/file-content-loader.ts +179 -0
  317. package/source/utils/file-mention-handler.spec.ts +261 -0
  318. package/source/utils/file-mention-handler.ts +84 -0
  319. package/source/utils/file-mention-parser.spec.ts +182 -0
  320. package/source/utils/file-mention-parser.ts +170 -0
  321. package/source/utils/fuzzy-matching.spec.ts +149 -0
  322. package/source/utils/fuzzy-matching.ts +146 -0
  323. package/source/utils/indentation-normalizer.spec.ts +216 -0
  324. package/source/utils/indentation-normalizer.ts +76 -0
  325. package/source/utils/installation-detector.spec.ts +178 -0
  326. package/source/utils/installation-detector.ts +153 -0
  327. package/source/utils/logging/config.spec.ts +311 -0
  328. package/source/utils/logging/config.ts +210 -0
  329. package/source/utils/logging/console-facade.spec.ts +184 -0
  330. package/source/utils/logging/console-facade.ts +384 -0
  331. package/source/utils/logging/correlation.spec.ts +679 -0
  332. package/source/utils/logging/correlation.ts +474 -0
  333. package/source/utils/logging/formatters.spec.ts +464 -0
  334. package/source/utils/logging/formatters.ts +207 -0
  335. package/source/utils/logging/health-monitor/alerts/alert-manager.spec.ts +93 -0
  336. package/source/utils/logging/health-monitor/alerts/alert-manager.ts +79 -0
  337. package/source/utils/logging/health-monitor/checks/configuration-check.spec.ts +56 -0
  338. package/source/utils/logging/health-monitor/checks/configuration-check.ts +43 -0
  339. package/source/utils/logging/health-monitor/checks/logging-check.spec.ts +56 -0
  340. package/source/utils/logging/health-monitor/checks/logging-check.ts +58 -0
  341. package/source/utils/logging/health-monitor/checks/memory-check.spec.ts +100 -0
  342. package/source/utils/logging/health-monitor/checks/memory-check.ts +78 -0
  343. package/source/utils/logging/health-monitor/checks/performance-check.spec.ts +56 -0
  344. package/source/utils/logging/health-monitor/checks/performance-check.ts +56 -0
  345. package/source/utils/logging/health-monitor/checks/request-check.spec.ts +56 -0
  346. package/source/utils/logging/health-monitor/checks/request-check.ts +76 -0
  347. package/source/utils/logging/health-monitor/core/health-check-runner.spec.ts +70 -0
  348. package/source/utils/logging/health-monitor/core/health-check-runner.ts +138 -0
  349. package/source/utils/logging/health-monitor/core/health-monitor.spec.ts +58 -0
  350. package/source/utils/logging/health-monitor/core/health-monitor.ts +344 -0
  351. package/source/utils/logging/health-monitor/core/scoring.spec.ts +65 -0
  352. package/source/utils/logging/health-monitor/core/scoring.ts +91 -0
  353. package/source/utils/logging/health-monitor/index.ts +15 -0
  354. package/source/utils/logging/health-monitor/instances.ts +48 -0
  355. package/source/utils/logging/health-monitor/middleware/http-middleware.spec.ts +141 -0
  356. package/source/utils/logging/health-monitor/middleware/http-middleware.ts +75 -0
  357. package/source/utils/logging/health-monitor/types.ts +126 -0
  358. package/source/utils/logging/index.spec.ts +284 -0
  359. package/source/utils/logging/index.ts +236 -0
  360. package/source/utils/logging/integration.spec.ts +441 -0
  361. package/source/utils/logging/log-method-factory.spec.ts +573 -0
  362. package/source/utils/logging/log-method-factory.ts +233 -0
  363. package/source/utils/logging/log-query/aggregation/aggregator.spec.ts +277 -0
  364. package/source/utils/logging/log-query/aggregation/aggregator.ts +159 -0
  365. package/source/utils/logging/log-query/aggregation/facet-generator.spec.ts +159 -0
  366. package/source/utils/logging/log-query/aggregation/facet-generator.ts +47 -0
  367. package/source/utils/logging/log-query/index.ts +23 -0
  368. package/source/utils/logging/log-query/query/filter-predicates.spec.ts +247 -0
  369. package/source/utils/logging/log-query/query/filter-predicates.ts +154 -0
  370. package/source/utils/logging/log-query/query/query-builder.spec.ts +182 -0
  371. package/source/utils/logging/log-query/query/query-builder.ts +151 -0
  372. package/source/utils/logging/log-query/query/query-engine.spec.ts +214 -0
  373. package/source/utils/logging/log-query/query/query-engine.ts +45 -0
  374. package/source/utils/logging/log-query/storage/circular-buffer.spec.ts +143 -0
  375. package/source/utils/logging/log-query/storage/circular-buffer.ts +75 -0
  376. package/source/utils/logging/log-query/storage/index-manager.spec.ts +150 -0
  377. package/source/utils/logging/log-query/storage/index-manager.ts +71 -0
  378. package/source/utils/logging/log-query/storage/log-storage.spec.ts +257 -0
  379. package/source/utils/logging/log-query/storage/log-storage.ts +80 -0
  380. package/source/utils/logging/log-query/types.ts +163 -0
  381. package/source/utils/logging/log-query/utils/helpers.spec.ts +263 -0
  382. package/source/utils/logging/log-query/utils/helpers.ts +72 -0
  383. package/source/utils/logging/log-query/utils/sorting.spec.ts +182 -0
  384. package/source/utils/logging/log-query/utils/sorting.ts +61 -0
  385. package/source/utils/logging/logger-provider.spec.ts +262 -0
  386. package/source/utils/logging/logger-provider.ts +362 -0
  387. package/source/utils/logging/performance.spec.ts +209 -0
  388. package/source/utils/logging/performance.ts +757 -0
  389. package/source/utils/logging/pino-logger.spec.ts +425 -0
  390. package/source/utils/logging/pino-logger.ts +514 -0
  391. package/source/utils/logging/redaction.spec.ts +490 -0
  392. package/source/utils/logging/redaction.ts +267 -0
  393. package/source/utils/logging/request-tracker.spec.ts +1198 -0
  394. package/source/utils/logging/request-tracker.ts +803 -0
  395. package/source/utils/logging/transports.spec.ts +505 -0
  396. package/source/utils/logging/transports.ts +305 -0
  397. package/source/utils/logging/types.ts +216 -0
  398. package/source/utils/message-builder.spec.ts +179 -0
  399. package/source/utils/message-builder.ts +101 -0
  400. package/source/utils/message-queue.tsx +486 -0
  401. package/source/utils/paste-detection.spec.ts +69 -0
  402. package/source/utils/paste-detection.ts +124 -0
  403. package/source/utils/paste-roundtrip.spec.ts +442 -0
  404. package/source/utils/paste-utils.spec.ts +128 -0
  405. package/source/utils/paste-utils.ts +52 -0
  406. package/source/utils/programming-language-helper.spec.ts +74 -0
  407. package/source/utils/programming-language-helper.ts +32 -0
  408. package/source/utils/prompt-assembly.spec.ts +221 -0
  409. package/source/utils/prompt-processor.ts +173 -0
  410. package/source/utils/tool-args-parser.spec.ts +136 -0
  411. package/source/utils/tool-args-parser.ts +54 -0
  412. package/source/utils/tool-cancellation.spec.ts +230 -0
  413. package/source/utils/tool-cancellation.ts +28 -0
  414. package/source/utils/tool-result-display.spec.tsx +469 -0
  415. package/source/utils/tool-result-display.tsx +90 -0
  416. package/source/utils/update-checker.spec.ts +383 -0
  417. package/source/utils/update-checker.ts +183 -0
  418. package/source/wizard/config-wizard.spec.tsx +103 -0
  419. package/source/wizard/config-wizard.tsx +382 -0
  420. package/source/wizard/steps/location-step.spec.tsx +186 -0
  421. package/source/wizard/steps/location-step.tsx +147 -0
  422. package/source/wizard/steps/mcp-step.spec.tsx +607 -0
  423. package/source/wizard/steps/mcp-step.tsx +632 -0
  424. package/source/wizard/steps/provider-step.spec.tsx +342 -0
  425. package/source/wizard/steps/provider-step.tsx +957 -0
  426. package/source/wizard/steps/summary-step.spec.tsx +749 -0
  427. package/source/wizard/steps/summary-step.tsx +228 -0
  428. package/source/wizard/templates/mcp-templates.spec.ts +613 -0
  429. package/source/wizard/templates/mcp-templates.ts +570 -0
  430. package/source/wizard/templates/provider-templates.spec.ts +152 -0
  431. package/source/wizard/templates/provider-templates.ts +485 -0
  432. package/source/wizard/utils/fetch-cloud-models.spec.ts +428 -0
  433. package/source/wizard/utils/fetch-cloud-models.ts +223 -0
  434. package/source/wizard/utils/fetch-local-models.spec.ts +297 -0
  435. package/source/wizard/utils/fetch-local-models.ts +192 -0
  436. package/source/wizard/validation-array.spec.ts +264 -0
  437. package/source/wizard/validation.spec.ts +373 -0
  438. package/source/wizard/validation.ts +232 -0
  439. package/source/app/prompts/main-prompt.md +0 -122
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Usage display component for /usage command
3
+ */
4
+
5
+ import {TitledBox} from '@/components/ui/titled-box';
6
+ import {useTerminalWidth} from '@/hooks/useTerminalWidth';
7
+ import {useTheme} from '@/hooks/useTheme';
8
+ import type {Message} from '@/types/core.js';
9
+ import type {TokenBreakdown} from '@/types/usage.js';
10
+ import {formatTokenCount, getUsageStatusColor} from '@/usage/calculator.js';
11
+ import {Box, Text} from 'ink';
12
+ import {ProgressBar} from './progress-bar.js';
13
+
14
+ interface UsageDisplayProps {
15
+ provider: string;
16
+ model: string;
17
+ contextLimit: number | null;
18
+ currentTokens: number;
19
+ breakdown: TokenBreakdown;
20
+ messages: Message[];
21
+ tokenizerName: string;
22
+ getMessageTokens: (message: Message) => number;
23
+ }
24
+
25
+ export function UsageDisplay({
26
+ provider,
27
+ model,
28
+ contextLimit,
29
+ currentTokens,
30
+ breakdown,
31
+ messages,
32
+ tokenizerName,
33
+ getMessageTokens,
34
+ }: UsageDisplayProps) {
35
+ const boxWidth = useTerminalWidth();
36
+ const {colors} = useTheme();
37
+
38
+ // Calculate percentages
39
+ const percentUsed = contextLimit ? (currentTokens / contextLimit) * 100 : 0;
40
+ const statusColor = getUsageStatusColor(percentUsed);
41
+ const availableTokens = contextLimit ? contextLimit - currentTokens : 0;
42
+
43
+ // Get the actual color from theme
44
+ const progressColor =
45
+ statusColor === 'success'
46
+ ? colors.success
47
+ : statusColor === 'warning'
48
+ ? colors.warning
49
+ : colors.error;
50
+
51
+ // Calculate category percentages for breakdown bars
52
+ const systemPercent = currentTokens
53
+ ? (breakdown.system / currentTokens) * 100
54
+ : 0;
55
+ const userPercent = currentTokens
56
+ ? (breakdown.userMessages / currentTokens) * 100
57
+ : 0;
58
+ const assistantPercent = currentTokens
59
+ ? (breakdown.assistantMessages / currentTokens) * 100
60
+ : 0;
61
+ const toolMessagesPercent = currentTokens
62
+ ? (breakdown.toolResults / currentTokens) * 100
63
+ : 0;
64
+ const toolDefsPercent = currentTokens
65
+ ? (breakdown.toolDefinitions / currentTokens) * 100
66
+ : 0;
67
+
68
+ // Calculate recent activity stats using cached token counts
69
+ const last5Messages = messages.slice(-5);
70
+ const last5TokenCount = last5Messages.reduce(
71
+ (sum, msg) => sum + getMessageTokens(msg),
72
+ 0,
73
+ );
74
+
75
+ // Find largest message using cached token counts
76
+ const largestMessageTokens =
77
+ messages.length > 0
78
+ ? Math.max(...messages.map(msg => getMessageTokens(msg)))
79
+ : 0;
80
+
81
+ // Responsive layout calculations based on terminal width
82
+ // For narrow terminals, reduce space for bars
83
+ const barMaxWidth = Math.max(10, Math.min(30, boxWidth - 20));
84
+ const mainProgressWidth = Math.max(20, Math.min(60, boxWidth - 12));
85
+
86
+ return (
87
+ <TitledBox
88
+ title="Context Usage"
89
+ width={boxWidth}
90
+ borderColor={colors.info}
91
+ paddingX={2}
92
+ paddingY={1}
93
+ flexDirection="column"
94
+ marginBottom={1}
95
+ >
96
+ {/* Overall Usage */}
97
+ <Box marginBottom={1}>
98
+ <Text color={colors.primary} bold>
99
+ Overall Usage
100
+ </Text>
101
+ </Box>
102
+ <Box marginBottom={0}>
103
+ <ProgressBar
104
+ percent={percentUsed}
105
+ width={mainProgressWidth}
106
+ color={progressColor}
107
+ />
108
+ <Text color={colors.white} bold>
109
+ {' '}
110
+ {Math.round(percentUsed)}%
111
+ </Text>
112
+ </Box>
113
+ <Box marginBottom={1}>
114
+ <Text color={colors.secondary}>
115
+ {formatTokenCount(currentTokens)} /{' '}
116
+ {contextLimit ? formatTokenCount(contextLimit) : 'Unknown'} tokens
117
+ </Text>
118
+ </Box>
119
+
120
+ {/* Category Breakdown */}
121
+ <Box marginTop={1} marginBottom={1}>
122
+ <Text color={colors.primary} bold>
123
+ Breakdown by Category
124
+ </Text>
125
+ </Box>
126
+
127
+ {/* System Prompt */}
128
+ <Box flexDirection="column" marginBottom={1}>
129
+ <Box marginBottom={0}>
130
+ <Text color={colors.info}>System Prompt:</Text>
131
+ </Box>
132
+ <Box flexDirection="row">
133
+ <ProgressBar
134
+ percent={systemPercent}
135
+ width={barMaxWidth}
136
+ color={colors.info}
137
+ />
138
+ <Box marginLeft={1}>
139
+ <Text color={colors.white}>
140
+ {Math.round(systemPercent)}% ({formatTokenCount(breakdown.system)}
141
+ )
142
+ </Text>
143
+ </Box>
144
+ </Box>
145
+ </Box>
146
+
147
+ {/* User Messages */}
148
+ <Box flexDirection="column" marginBottom={1}>
149
+ <Box marginBottom={0}>
150
+ <Text color={colors.secondary}>User Messages:</Text>
151
+ </Box>
152
+ <Box flexDirection="row">
153
+ <ProgressBar
154
+ percent={userPercent}
155
+ width={barMaxWidth}
156
+ color={colors.info}
157
+ />
158
+ <Box marginLeft={1}>
159
+ <Text color={colors.white}>
160
+ {Math.round(userPercent)}% (
161
+ {formatTokenCount(breakdown.userMessages)})
162
+ </Text>
163
+ </Box>
164
+ </Box>
165
+ </Box>
166
+
167
+ {/* Assistant Messages */}
168
+ <Box flexDirection="column" marginBottom={1}>
169
+ <Box marginBottom={0}>
170
+ <Text color={colors.secondary}>Assistant Messages:</Text>
171
+ </Box>
172
+ <Box flexDirection="row">
173
+ <ProgressBar
174
+ percent={assistantPercent}
175
+ width={barMaxWidth}
176
+ color={colors.info}
177
+ />
178
+ <Box marginLeft={1}>
179
+ <Text color={colors.white}>
180
+ {Math.round(assistantPercent)}% (
181
+ {formatTokenCount(breakdown.assistantMessages)})
182
+ </Text>
183
+ </Box>
184
+ </Box>
185
+ </Box>
186
+
187
+ {/* Tool Messages */}
188
+ <Box flexDirection="column" marginBottom={1}>
189
+ <Box marginBottom={0}>
190
+ <Text color={colors.secondary}>Tool Messages:</Text>
191
+ </Box>
192
+ <Box flexDirection="row">
193
+ <ProgressBar
194
+ percent={toolMessagesPercent}
195
+ width={barMaxWidth}
196
+ color={colors.info}
197
+ />
198
+ <Box marginLeft={1}>
199
+ <Text color={colors.white}>
200
+ {Math.round(toolMessagesPercent)}% (
201
+ {formatTokenCount(breakdown.toolResults)})
202
+ </Text>
203
+ </Box>
204
+ </Box>
205
+ </Box>
206
+
207
+ {/* Tool Definitions */}
208
+ <Box flexDirection="column" marginBottom={1}>
209
+ <Box marginBottom={0}>
210
+ <Text color={colors.secondary}>Tool Definitions:</Text>
211
+ </Box>
212
+ <Box flexDirection="row">
213
+ <ProgressBar
214
+ percent={toolDefsPercent}
215
+ width={barMaxWidth}
216
+ color={colors.info}
217
+ />
218
+ <Box marginLeft={1}>
219
+ <Text color={colors.white}>
220
+ {Math.round(toolDefsPercent)}% (
221
+ {formatTokenCount(breakdown.toolDefinitions)})
222
+ </Text>
223
+ </Box>
224
+ </Box>
225
+ </Box>
226
+
227
+ {/* Available Tokens */}
228
+ <Box marginTop={1} marginBottom={1}>
229
+ <Text color={colors.secondary}>
230
+ Available:{' '}
231
+ <Text color={colors.success}>
232
+ {formatTokenCount(availableTokens)} tokens
233
+ </Text>
234
+ </Text>
235
+ </Box>
236
+
237
+ {/* Model Information */}
238
+ <Box marginTop={1} marginBottom={1}>
239
+ <Text color={colors.primary} bold>
240
+ Model Information
241
+ </Text>
242
+ </Box>
243
+ <Box>
244
+ <Text color={colors.secondary}>
245
+ Provider: <Text color={colors.white}>{provider}</Text>
246
+ </Text>
247
+ </Box>
248
+ <Box>
249
+ <Text color={colors.secondary}>
250
+ Model: <Text color={colors.white}>{model}</Text>
251
+ </Text>
252
+ </Box>
253
+ <Box>
254
+ <Text color={colors.secondary}>
255
+ Context Limit:{' '}
256
+ <Text color={colors.white}>
257
+ {contextLimit ? formatTokenCount(contextLimit) : 'Unknown'}
258
+ </Text>
259
+ </Text>
260
+ </Box>
261
+ <Box marginBottom={1}>
262
+ <Text color={colors.secondary}>
263
+ Tokenizer: <Text color={colors.white}>{tokenizerName}</Text>
264
+ </Text>
265
+ </Box>
266
+
267
+ {/* Recent Activity */}
268
+ <Box marginTop={1} marginBottom={1}>
269
+ <Text color={colors.primary} bold>
270
+ Recent Activity
271
+ </Text>
272
+ </Box>
273
+ <Box>
274
+ <Text color={colors.secondary}>
275
+ Last 5 messages:{' '}
276
+ <Text color={colors.white}>
277
+ {formatTokenCount(last5TokenCount)} tokens
278
+ </Text>
279
+ </Text>
280
+ </Box>
281
+ <Box>
282
+ <Text color={colors.secondary}>
283
+ Largest message:{' '}
284
+ <Text color={colors.white}>
285
+ {formatTokenCount(largestMessageTokens)} tokens
286
+ </Text>
287
+ </Text>
288
+ </Box>
289
+ </TitledBox>
290
+ );
291
+ }
@@ -0,0 +1,327 @@
1
+ import test from 'ava';
2
+ import {render} from 'ink-testing-library';
3
+ import React from 'react';
4
+ import {themes} from '../config/themes';
5
+ import {ThemeContext} from '../hooks/useTheme';
6
+ import {UIStateProvider} from '../hooks/useUIState';
7
+ import UserInput from './user-input';
8
+
9
+ console.log(`\nuser-input.spec.tsx – ${React.version}`);
10
+
11
+ // Mock ThemeProvider for testing
12
+ const MockThemeProvider = ({children}: {children: React.ReactNode}) => {
13
+ const mockTheme = {
14
+ currentTheme: 'tokyo-night' as const,
15
+ colors: themes['tokyo-night'].colors,
16
+ setCurrentTheme: () => {},
17
+ };
18
+
19
+ return (
20
+ <ThemeContext.Provider value={mockTheme}>{children}</ThemeContext.Provider>
21
+ );
22
+ };
23
+
24
+ // Wrapper with all required providers
25
+ const TestWrapper = ({children}: {children: React.ReactNode}) => (
26
+ <MockThemeProvider>
27
+ <UIStateProvider>{children}</UIStateProvider>
28
+ </MockThemeProvider>
29
+ );
30
+
31
+ // ============================================================================
32
+ // Component Rendering Tests
33
+ // ============================================================================
34
+
35
+ test('UserInput renders without crashing', t => {
36
+ const {lastFrame} = render(
37
+ <TestWrapper>
38
+ <UserInput />
39
+ </TestWrapper>,
40
+ );
41
+
42
+ t.truthy(lastFrame());
43
+ });
44
+
45
+ test('UserInput renders with placeholder text', t => {
46
+ const {lastFrame} = render(
47
+ <TestWrapper>
48
+ <UserInput placeholder="Custom placeholder" />
49
+ </TestWrapper>,
50
+ );
51
+
52
+ const output = lastFrame();
53
+ t.truthy(output);
54
+ // Placeholder text should be visible
55
+ });
56
+
57
+ test('UserInput renders prompt symbol', t => {
58
+ const {lastFrame} = render(
59
+ <TestWrapper>
60
+ <UserInput />
61
+ </TestWrapper>,
62
+ );
63
+
64
+ const output = lastFrame();
65
+ t.truthy(output);
66
+ t.regex(output!, />/); // Prompt symbol
67
+ });
68
+
69
+ test('UserInput renders with disabled state', t => {
70
+ const {lastFrame, unmount} = render(
71
+ <TestWrapper>
72
+ <UserInput disabled={true} />
73
+ </TestWrapper>,
74
+ );
75
+
76
+ const output = lastFrame();
77
+ t.truthy(output);
78
+ // Shows a spinner when disabled (dots spinner uses braille characters like ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏)
79
+ // t.regex(output!, /[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏]/);
80
+ // t.regex(output!, /[←↖↑↗→↘↓↙]/);
81
+ t.regex(output!, /[◢◣◤◥]/);
82
+ unmount();
83
+ });
84
+
85
+ test('UserInput renders development mode indicator', t => {
86
+ const {lastFrame} = render(
87
+ <TestWrapper>
88
+ <UserInput developmentMode="normal" />
89
+ </TestWrapper>,
90
+ );
91
+
92
+ const output = lastFrame();
93
+ t.truthy(output);
94
+ t.regex(output!, /Normal Mode|Shift\+Tab/); // Development mode indicator
95
+ });
96
+
97
+ test('UserInput renders auto-accept mode indicator', t => {
98
+ const {lastFrame} = render(
99
+ <TestWrapper>
100
+ <UserInput developmentMode="auto-accept" />
101
+ </TestWrapper>,
102
+ );
103
+
104
+ const output = lastFrame();
105
+ t.truthy(output);
106
+ t.regex(output!, /auto-accept mode/); // Auto-accept mode indicator
107
+ });
108
+
109
+ test('UserInput renders plan mode indicator', t => {
110
+ const {lastFrame} = render(
111
+ <TestWrapper>
112
+ <UserInput developmentMode="plan" />
113
+ </TestWrapper>,
114
+ );
115
+
116
+ const output = lastFrame();
117
+ t.truthy(output);
118
+ t.regex(output!, /plan mode/); // Plan mode indicator
119
+ });
120
+
121
+ test('UserInput renders with custom commands', t => {
122
+ const customCommands = ['custom-command', 'another-command'];
123
+ const {lastFrame} = render(
124
+ <TestWrapper>
125
+ <UserInput customCommands={customCommands} />
126
+ </TestWrapper>,
127
+ );
128
+
129
+ const output = lastFrame();
130
+ t.truthy(output);
131
+ });
132
+
133
+ test('UserInput calls onSubmit when message is submitted', t => {
134
+ let submittedMessage = '';
135
+ const handleSubmit = (message: string) => {
136
+ submittedMessage = message;
137
+ };
138
+
139
+ const {lastFrame, stdin} = render(
140
+ <TestWrapper>
141
+ <UserInput onSubmit={handleSubmit} />
142
+ </TestWrapper>,
143
+ );
144
+
145
+ t.truthy(lastFrame());
146
+ // Note: Testing actual user interaction with stdin is complex
147
+ // This test verifies the component renders with onSubmit callback
148
+ });
149
+
150
+ test('UserInput calls onCancel when provided', t => {
151
+ let cancelCalled = false;
152
+ const handleCancel = () => {
153
+ cancelCalled = true;
154
+ };
155
+
156
+ const {lastFrame, unmount} = render(
157
+ <TestWrapper>
158
+ <UserInput onCancel={handleCancel} disabled={true} />
159
+ </TestWrapper>,
160
+ );
161
+
162
+ t.truthy(lastFrame());
163
+ // Note: Actual cancel invocation requires ESC key simulation
164
+ unmount();
165
+ });
166
+
167
+ test('UserInput calls onToggleMode when provided', t => {
168
+ let toggleCalled = false;
169
+ const handleToggle = () => {
170
+ toggleCalled = true;
171
+ };
172
+
173
+ const {lastFrame} = render(
174
+ <TestWrapper>
175
+ <UserInput onToggleMode={handleToggle} />
176
+ </TestWrapper>,
177
+ );
178
+
179
+ t.truthy(lastFrame());
180
+ // Note: Actual toggle invocation requires Shift+Tab simulation
181
+ });
182
+
183
+ test('UserInput renders bash mode indicator when input starts with !', t => {
184
+ // This test verifies the component can handle bash mode
185
+ // Actual input testing requires stdin manipulation
186
+ const {lastFrame} = render(
187
+ <TestWrapper>
188
+ <UserInput />
189
+ </TestWrapper>,
190
+ );
191
+
192
+ t.truthy(lastFrame());
193
+ });
194
+
195
+ test('UserInput renders help text when not disabled', t => {
196
+ const {lastFrame} = render(
197
+ <TestWrapper>
198
+ <UserInput />
199
+ </TestWrapper>,
200
+ );
201
+
202
+ const output = lastFrame();
203
+ t.truthy(output);
204
+ t.regex(output!, /What would you like me to help with\?/);
205
+ });
206
+
207
+ test('UserInput hides help text when disabled', t => {
208
+ const {lastFrame, unmount} = render(
209
+ <TestWrapper>
210
+ <UserInput disabled={true} />
211
+ </TestWrapper>,
212
+ );
213
+
214
+ const output = lastFrame();
215
+ t.truthy(output);
216
+ t.notRegex(output!, /What would you like me to help with\?/);
217
+ unmount();
218
+ });
219
+
220
+ test('UserInput renders with all props provided', t => {
221
+ const {lastFrame} = render(
222
+ <TestWrapper>
223
+ <UserInput
224
+ onSubmit={() => {}}
225
+ placeholder="Test"
226
+ customCommands={['test']}
227
+ disabled={false}
228
+ onCancel={() => {}}
229
+ onToggleMode={() => {}}
230
+ developmentMode="normal"
231
+ />
232
+ </TestWrapper>,
233
+ );
234
+
235
+ t.truthy(lastFrame());
236
+ });
237
+
238
+ // ============================================================================
239
+ // File Autocomplete UI Tests
240
+ // ============================================================================
241
+
242
+ test('UserInput renders file autocomplete suggestions header', t => {
243
+ // Note: Testing file autocomplete requires state manipulation
244
+ // This test verifies the component structure supports it
245
+ const {lastFrame} = render(
246
+ <TestWrapper>
247
+ <UserInput />
248
+ </TestWrapper>,
249
+ );
250
+
251
+ const output = lastFrame();
252
+ t.truthy(output);
253
+ // File suggestions would appear when @ is typed and files are found
254
+ });
255
+
256
+ test('UserInput responsive placeholder for narrow terminals', t => {
257
+ // Test that placeholder adapts to terminal width
258
+ // The actual implementation uses useResponsiveTerminal hook
259
+ const {lastFrame} = render(
260
+ <TestWrapper>
261
+ <UserInput />
262
+ </TestWrapper>,
263
+ );
264
+
265
+ const output = lastFrame();
266
+ t.truthy(output);
267
+ // Placeholder text should be present (either long or short version)
268
+ });
269
+
270
+ // ============================================================================
271
+ // Integration Tests
272
+ // ============================================================================
273
+
274
+ test('UserInput maintains state across renders', t => {
275
+ const {lastFrame, rerender} = render(
276
+ <TestWrapper>
277
+ <UserInput />
278
+ </TestWrapper>,
279
+ );
280
+
281
+ const firstRender = lastFrame();
282
+ t.truthy(firstRender);
283
+
284
+ rerender(
285
+ <TestWrapper>
286
+ <UserInput />
287
+ </TestWrapper>,
288
+ );
289
+
290
+ const secondRender = lastFrame();
291
+ t.truthy(secondRender);
292
+ });
293
+
294
+ test('UserInput renders with default development mode', t => {
295
+ const {lastFrame} = render(
296
+ <TestWrapper>
297
+ <UserInput />
298
+ </TestWrapper>,
299
+ );
300
+
301
+ const output = lastFrame();
302
+ t.truthy(output);
303
+ // Default mode is 'normal'
304
+ t.regex(output!, /normal mode/);
305
+ });
306
+
307
+ test('UserInput handles empty custom commands array', t => {
308
+ const {lastFrame} = render(
309
+ <TestWrapper>
310
+ <UserInput customCommands={[]} />
311
+ </TestWrapper>,
312
+ );
313
+
314
+ t.truthy(lastFrame());
315
+ });
316
+
317
+ test('UserInput component structure is valid', t => {
318
+ const {lastFrame} = render(
319
+ <TestWrapper>
320
+ <UserInput />
321
+ </TestWrapper>,
322
+ );
323
+
324
+ const output = lastFrame();
325
+ t.truthy(output);
326
+ t.true(output!.length > 0);
327
+ });