@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,173 @@
1
+ import {renderWithTheme} from '@/test-utils/render-with-theme';
2
+ import type {CheckpointListItem} from '@/types/checkpoint';
3
+ import test from 'ava';
4
+ import React from 'react';
5
+ import CheckpointSelector from './checkpoint-selector';
6
+
7
+ const createMockCheckpoint = (
8
+ name: string,
9
+ overrides: Partial<CheckpointListItem['metadata']> = {},
10
+ ): CheckpointListItem => ({
11
+ name,
12
+ metadata: {
13
+ name,
14
+ timestamp: new Date().toISOString(),
15
+ messageCount: 10,
16
+ filesChanged: ['file1.ts', 'file2.ts'],
17
+ provider: {name: 'Test Provider', model: 'test-model'},
18
+ description: 'Test checkpoint',
19
+ ...overrides,
20
+ },
21
+ sizeBytes: 1024,
22
+ });
23
+
24
+ test('CheckpointSelector renders empty state when no checkpoints', t => {
25
+ const {lastFrame} = renderWithTheme(
26
+ <CheckpointSelector
27
+ checkpoints={[]}
28
+ onSelect={() => {}}
29
+ onCancel={() => {}}
30
+ currentMessageCount={0}
31
+ />,
32
+ );
33
+
34
+ const output = lastFrame() || '';
35
+ t.true(output.includes('No Checkpoints'));
36
+ });
37
+
38
+ test('CheckpointSelector renders checkpoint list', t => {
39
+ const checkpoints = [
40
+ createMockCheckpoint('checkpoint-1'),
41
+ createMockCheckpoint('checkpoint-2'),
42
+ ];
43
+ const {lastFrame} = renderWithTheme(
44
+ <CheckpointSelector
45
+ checkpoints={checkpoints}
46
+ onSelect={() => {}}
47
+ onCancel={() => {}}
48
+ currentMessageCount={0}
49
+ />,
50
+ );
51
+
52
+ const output = lastFrame() || '';
53
+ t.true(output.includes('checkpoint-1'));
54
+ t.true(output.includes('checkpoint-2'));
55
+ });
56
+
57
+ test('CheckpointSelector renders title', t => {
58
+ const checkpoints = [createMockCheckpoint('test')];
59
+ const {lastFrame} = renderWithTheme(
60
+ <CheckpointSelector
61
+ checkpoints={checkpoints}
62
+ onSelect={() => {}}
63
+ onCancel={() => {}}
64
+ currentMessageCount={0}
65
+ />,
66
+ );
67
+
68
+ const output = lastFrame() || '';
69
+ t.true(output.includes('Select Checkpoint'));
70
+ });
71
+
72
+ test('CheckpointSelector renders navigation help', t => {
73
+ const checkpoints = [createMockCheckpoint('test')];
74
+ const {lastFrame} = renderWithTheme(
75
+ <CheckpointSelector
76
+ checkpoints={checkpoints}
77
+ onSelect={() => {}}
78
+ onCancel={() => {}}
79
+ currentMessageCount={0}
80
+ />,
81
+ );
82
+
83
+ const output = lastFrame() || '';
84
+ // The component should show some navigation instructions
85
+ t.truthy(output.length > 0);
86
+ });
87
+
88
+ test('CheckpointSelector shows message count in checkpoint label', t => {
89
+ const checkpoints = [createMockCheckpoint('test', {messageCount: 42})];
90
+ const {lastFrame} = renderWithTheme(
91
+ <CheckpointSelector
92
+ checkpoints={checkpoints}
93
+ onSelect={() => {}}
94
+ onCancel={() => {}}
95
+ currentMessageCount={0}
96
+ />,
97
+ );
98
+
99
+ const output = lastFrame() || '';
100
+ // The label format includes "42 msgs"
101
+ t.true(output.includes('42'));
102
+ });
103
+
104
+ test('CheckpointSelector shows files count in checkpoint label', t => {
105
+ const checkpoints = [
106
+ createMockCheckpoint('test', {
107
+ filesChanged: ['a.ts', 'b.ts', 'c.ts'],
108
+ }),
109
+ ];
110
+ const {lastFrame} = renderWithTheme(
111
+ <CheckpointSelector
112
+ checkpoints={checkpoints}
113
+ onSelect={() => {}}
114
+ onCancel={() => {}}
115
+ currentMessageCount={0}
116
+ />,
117
+ );
118
+
119
+ const output = lastFrame() || '';
120
+ // The label format includes "3 files"
121
+ t.true(output.includes('3'));
122
+ });
123
+
124
+ test('CheckpointSelector renders without crashing with onError prop', t => {
125
+ const checkpoints = [createMockCheckpoint('test')];
126
+ const {lastFrame} = renderWithTheme(
127
+ <CheckpointSelector
128
+ checkpoints={checkpoints}
129
+ onSelect={() => {}}
130
+ onCancel={() => {}}
131
+ onError={() => {}}
132
+ currentMessageCount={0}
133
+ />,
134
+ );
135
+
136
+ const output = lastFrame() || '';
137
+ t.true(output.includes('test'));
138
+ });
139
+
140
+ test('CheckpointSelector renders multiple checkpoints in list', t => {
141
+ const checkpoints = [
142
+ createMockCheckpoint('first-checkpoint'),
143
+ createMockCheckpoint('second-checkpoint'),
144
+ createMockCheckpoint('third-checkpoint'),
145
+ ];
146
+ const {lastFrame} = renderWithTheme(
147
+ <CheckpointSelector
148
+ checkpoints={checkpoints}
149
+ onSelect={() => {}}
150
+ onCancel={() => {}}
151
+ currentMessageCount={0}
152
+ />,
153
+ );
154
+
155
+ const output = lastFrame() || '';
156
+ t.true(output.includes('first-checkpoint'));
157
+ t.true(output.includes('second-checkpoint'));
158
+ t.true(output.includes('third-checkpoint'));
159
+ });
160
+
161
+ test('CheckpointSelector empty state message mentions create command', t => {
162
+ const {lastFrame} = renderWithTheme(
163
+ <CheckpointSelector
164
+ checkpoints={[]}
165
+ onSelect={() => {}}
166
+ onCancel={() => {}}
167
+ currentMessageCount={0}
168
+ />,
169
+ );
170
+
171
+ const output = lastFrame() || '';
172
+ t.true(output.includes('checkpoint create'));
173
+ });
@@ -0,0 +1,173 @@
1
+ import {TitledBox} from '@/components/ui/titled-box';
2
+ import {useTerminalWidth} from '@/hooks/useTerminalWidth';
3
+ import {useTheme} from '@/hooks/useTheme';
4
+ import type {CheckpointListItem} from '@/types/checkpoint';
5
+ import {formatRelativeTime} from '@/utils/checkpoint-utils';
6
+ import {Box, Text, useInput} from 'ink';
7
+ import SelectInput from 'ink-select-input';
8
+ import {useState} from 'react';
9
+
10
+ interface CheckpointSelectorProps {
11
+ checkpoints: CheckpointListItem[];
12
+ onSelect: (checkpointName: string, createBackup: boolean) => void;
13
+ onCancel: () => void;
14
+ onError?: (error: Error) => void;
15
+ currentMessageCount: number;
16
+ }
17
+
18
+ interface CheckpointOption {
19
+ label: string;
20
+ value: string;
21
+ }
22
+
23
+ export default function CheckpointSelector({
24
+ checkpoints,
25
+ onSelect,
26
+ onCancel,
27
+ currentMessageCount,
28
+ }: CheckpointSelectorProps) {
29
+ const boxWidth = useTerminalWidth();
30
+ const {colors} = useTheme();
31
+ const [selectedCheckpoint, setSelectedCheckpoint] = useState<string | null>(
32
+ null,
33
+ );
34
+ const [awaitingBackupConfirmation, setAwaitingBackupConfirmation] =
35
+ useState(false);
36
+
37
+ useInput((inputChar, key) => {
38
+ if (key.escape) {
39
+ onCancel();
40
+ return;
41
+ }
42
+
43
+ if (awaitingBackupConfirmation) {
44
+ const char = inputChar.toLowerCase();
45
+ if (char === 'y' || char === '\r' || char === '\n') {
46
+ if (selectedCheckpoint) {
47
+ onSelect(selectedCheckpoint, true);
48
+ }
49
+ } else if (char === 'n') {
50
+ if (selectedCheckpoint) {
51
+ onSelect(selectedCheckpoint, false);
52
+ }
53
+ }
54
+ }
55
+ });
56
+
57
+ const handleCheckpointSelect = (item: CheckpointOption) => {
58
+ setSelectedCheckpoint(item.value);
59
+ if (currentMessageCount > 0) {
60
+ setAwaitingBackupConfirmation(true);
61
+ } else {
62
+ onSelect(item.value, false);
63
+ }
64
+ };
65
+
66
+ if (awaitingBackupConfirmation && selectedCheckpoint) {
67
+ const checkpoint = checkpoints.find(c => c.name === selectedCheckpoint);
68
+
69
+ return (
70
+ <TitledBox
71
+ title="Checkpoint Load - Backup Confirmation"
72
+ width={boxWidth}
73
+ borderColor={colors.warning}
74
+ paddingX={2}
75
+ paddingY={1}
76
+ marginBottom={1}
77
+ >
78
+ <Box flexDirection="column">
79
+ <Box marginBottom={1}>
80
+ <Text color={colors.white}>
81
+ You have {currentMessageCount} message(s) in the current session.
82
+ </Text>
83
+ </Box>
84
+
85
+ {checkpoint && (
86
+ <Box flexDirection="column" marginBottom={1}>
87
+ <Text color={colors.secondary}>
88
+ Loading checkpoint:{' '}
89
+ <Text color={colors.primary}>{checkpoint.name}</Text>
90
+ </Text>
91
+ <Text color={colors.secondary}>
92
+ • {checkpoint.metadata.messageCount} messages
93
+ </Text>
94
+ <Text color={colors.secondary}>
95
+ • {checkpoint.metadata.filesChanged.length} files
96
+ </Text>
97
+ <Text color={colors.secondary}>
98
+ • Created {formatRelativeTime(checkpoint.metadata.timestamp)}
99
+ </Text>
100
+ </Box>
101
+ )}
102
+
103
+ <Box marginBottom={1}>
104
+ <Text color={colors.warning} bold>
105
+ Create a backup of current session before loading?
106
+ </Text>
107
+ </Box>
108
+
109
+ <Box marginBottom={1}>
110
+ <Text color={colors.white}>
111
+ [Y] Yes, create backup [N] No, skip backup [Esc] Cancel
112
+ </Text>
113
+ </Box>
114
+
115
+ <Box>
116
+ <Text color={colors.secondary} dimColor>
117
+ Press Y/Enter to backup, N to skip, or Esc to cancel
118
+ </Text>
119
+ </Box>
120
+ </Box>
121
+ </TitledBox>
122
+ );
123
+ }
124
+
125
+ const options: CheckpointOption[] = checkpoints.map(checkpoint => ({
126
+ label: `${checkpoint.name} - ${checkpoint.metadata.messageCount} msgs, ${
127
+ checkpoint.metadata.filesChanged.length
128
+ } files - ${formatRelativeTime(checkpoint.metadata.timestamp)}`,
129
+ value: checkpoint.name,
130
+ }));
131
+
132
+ if (options.length === 0) {
133
+ return (
134
+ <TitledBox
135
+ title="No Checkpoints Available"
136
+ width={boxWidth}
137
+ borderColor={colors.secondary}
138
+ paddingX={2}
139
+ paddingY={1}
140
+ marginBottom={1}
141
+ >
142
+ <Box flexDirection="column">
143
+ <Text color={colors.white}>
144
+ No checkpoints found. Create one with /checkpoint create [name]
145
+ </Text>
146
+ <Box marginTop={1}>
147
+ <Text color={colors.secondary}>Press Escape to cancel</Text>
148
+ </Box>
149
+ </Box>
150
+ </TitledBox>
151
+ );
152
+ }
153
+
154
+ return (
155
+ <TitledBox
156
+ title="Select Checkpoint to Load"
157
+ width={boxWidth}
158
+ borderColor={colors.primary}
159
+ paddingX={2}
160
+ paddingY={1}
161
+ marginBottom={1}
162
+ >
163
+ <Box flexDirection="column">
164
+ <SelectInput items={options} onSelect={handleCheckpointSelect} />
165
+ <Box marginTop={1}>
166
+ <Text color={colors.secondary}>
167
+ Use ↑↓ arrows to select, Enter to confirm, Escape to cancel
168
+ </Text>
169
+ </Box>
170
+ </Box>
171
+ </TitledBox>
172
+ );
173
+ }
@@ -0,0 +1,268 @@
1
+ import {render} from 'ink-testing-library';
2
+ import test from 'ava';
3
+ import React from 'react';
4
+ import {DevelopmentModeIndicator} from './development-mode-indicator';
5
+
6
+ // Mock colors object matching the theme structure
7
+ const mockColors = {
8
+ primary: '#FFFFFF',
9
+ secondary: '#808080',
10
+ info: '#00FFFF',
11
+ warning: '#FFA500',
12
+ error: '#FF0000',
13
+ success: '#00FF00',
14
+ tool: '#FF00FF',
15
+ white: '#FFFFFF',
16
+ black: '#000000',
17
+ };
18
+
19
+ // ============================================================================
20
+ // Component Rendering Tests
21
+ // ============================================================================
22
+
23
+ test('DevelopmentModeIndicator renders with normal mode', t => {
24
+ const {lastFrame} = render(
25
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
26
+ );
27
+
28
+ const output = lastFrame();
29
+ t.truthy(output);
30
+ t.regex(output!, /normal mode on/);
31
+ t.regex(output!, /Shift\+Tab to cycle/);
32
+ });
33
+
34
+ test('DevelopmentModeIndicator renders with auto-accept mode', t => {
35
+ const {lastFrame} = render(
36
+ <DevelopmentModeIndicator
37
+ developmentMode="auto-accept"
38
+ colors={mockColors}
39
+ />,
40
+ );
41
+
42
+ const output = lastFrame();
43
+ t.truthy(output);
44
+ t.regex(output!, /auto-accept mode on/);
45
+ t.regex(output!, /Shift\+Tab to cycle/);
46
+ });
47
+
48
+ test('DevelopmentModeIndicator renders with plan mode', t => {
49
+ const {lastFrame} = render(
50
+ <DevelopmentModeIndicator developmentMode="plan" colors={mockColors} />,
51
+ );
52
+
53
+ const output = lastFrame();
54
+ t.truthy(output);
55
+ t.regex(output!, /plan mode on/);
56
+ t.regex(output!, /Shift\+Tab to cycle/);
57
+ });
58
+
59
+ test('DevelopmentModeIndicator renders without crashing', t => {
60
+ const {unmount} = render(
61
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
62
+ );
63
+
64
+ t.notThrows(() => unmount());
65
+ });
66
+
67
+ // ============================================================================
68
+ // Props Tests
69
+ // ============================================================================
70
+
71
+ test('DevelopmentModeIndicator accepts all valid development modes', t => {
72
+ const modes = ['normal', 'auto-accept', 'plan'] as const;
73
+
74
+ for (const mode of modes) {
75
+ t.notThrows(() => {
76
+ render(
77
+ <DevelopmentModeIndicator developmentMode={mode} colors={mockColors} />,
78
+ );
79
+ });
80
+ }
81
+ });
82
+
83
+ test('DevelopmentModeIndicator accepts colors object', t => {
84
+ t.notThrows(() => {
85
+ render(
86
+ <DevelopmentModeIndicator
87
+ developmentMode="normal"
88
+ colors={mockColors}
89
+ />,
90
+ );
91
+ });
92
+ });
93
+
94
+ // ============================================================================
95
+ // Display Name Tests
96
+ // ============================================================================
97
+
98
+ test('DevelopmentModeIndicator has correct display name', t => {
99
+ t.is(DevelopmentModeIndicator.displayName, 'DevelopmentModeIndicator');
100
+ });
101
+
102
+ // ============================================================================
103
+ // Content Tests
104
+ // ============================================================================
105
+
106
+ test('DevelopmentModeIndicator shows mode label in bold', t => {
107
+ const {lastFrame} = render(
108
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
109
+ );
110
+
111
+ const output = lastFrame();
112
+ // Bold is represented by ANSI escape codes, check for the label
113
+ t.regex(output!, /normal mode on/);
114
+ });
115
+
116
+ test('DevelopmentModeIndicator shows instructions', t => {
117
+ const {lastFrame} = render(
118
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
119
+ );
120
+
121
+ const output = lastFrame();
122
+ t.regex(output!, /\(Shift\+Tab to cycle\)/);
123
+ });
124
+
125
+ test('DevelopmentModeIndicator normal mode uses correct label', t => {
126
+ const {lastFrame} = render(
127
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
128
+ );
129
+
130
+ const output = lastFrame();
131
+ t.regex(output!, /normal mode on/);
132
+ t.notRegex(output!, /auto-accept mode on/);
133
+ t.notRegex(output!, /plan mode on/);
134
+ });
135
+
136
+ test('DevelopmentModeIndicator auto-accept mode uses correct label', t => {
137
+ const {lastFrame} = render(
138
+ <DevelopmentModeIndicator
139
+ developmentMode="auto-accept"
140
+ colors={mockColors}
141
+ />,
142
+ );
143
+
144
+ const output = lastFrame();
145
+ t.regex(output!, /auto-accept mode on/);
146
+ t.notRegex(output!, /normal mode on/);
147
+ t.notRegex(output!, /plan mode on/);
148
+ });
149
+
150
+ test('DevelopmentModeIndicator plan mode uses correct label', t => {
151
+ const {lastFrame} = render(
152
+ <DevelopmentModeIndicator developmentMode="plan" colors={mockColors} />,
153
+ );
154
+
155
+ const output = lastFrame();
156
+ t.regex(output!, /plan mode on/);
157
+ t.notRegex(output!, /normal mode on/);
158
+ t.notRegex(output!, /auto-accept mode on/);
159
+ });
160
+
161
+ // ============================================================================
162
+ // Memoization Tests
163
+ // ============================================================================
164
+
165
+ test('DevelopmentModeIndicator is memoized', t => {
166
+ // React.memo components should have the same reference when props don't change
167
+ const firstRender = render(
168
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
169
+ );
170
+ const firstOutput = firstRender.lastFrame();
171
+
172
+ const secondRender = render(
173
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
174
+ );
175
+ const secondOutput = secondRender.lastFrame();
176
+
177
+ // Should produce the same output with same props
178
+ t.is(firstOutput, secondOutput);
179
+ });
180
+
181
+ test('DevelopmentModeIndicator updates when developmentMode changes', t => {
182
+ const {lastFrame, rerender} = render(
183
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
184
+ );
185
+
186
+ const normalOutput = lastFrame();
187
+ t.regex(normalOutput!, /normal mode on/);
188
+
189
+ rerender(
190
+ <DevelopmentModeIndicator
191
+ developmentMode="auto-accept"
192
+ colors={mockColors}
193
+ />,
194
+ );
195
+
196
+ const autoAcceptOutput = lastFrame();
197
+ t.regex(autoAcceptOutput!, /auto-accept mode on/);
198
+ });
199
+
200
+ // ============================================================================
201
+ // Structure Tests
202
+ // ============================================================================
203
+
204
+ test('DevelopmentModeIndicator has correct structure', t => {
205
+ const {lastFrame} = render(
206
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
207
+ );
208
+
209
+ const output = lastFrame();
210
+ // Should have both the mode label and the instructions
211
+ t.regex(output!, /normal mode on/);
212
+ t.regex(output!, /\(Shift\+Tab to cycle\)/);
213
+ });
214
+
215
+ test('DevelopmentModeIndicator component can be unmounted', t => {
216
+ const {unmount} = render(
217
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
218
+ );
219
+
220
+ t.notThrows(() => {
221
+ unmount();
222
+ });
223
+ });
224
+
225
+ // ============================================================================
226
+ // Edge Cases
227
+ // ============================================================================
228
+
229
+ test('DevelopmentModeIndicator handles rapid mode changes', t => {
230
+ const {lastFrame, rerender} = render(
231
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
232
+ );
233
+
234
+ // Cycle through modes rapidly
235
+ rerender(
236
+ <DevelopmentModeIndicator
237
+ developmentMode="auto-accept"
238
+ colors={mockColors}
239
+ />,
240
+ );
241
+ rerender(
242
+ <DevelopmentModeIndicator developmentMode="plan" colors={mockColors} />,
243
+ );
244
+ rerender(
245
+ <DevelopmentModeIndicator developmentMode="normal" colors={mockColors} />,
246
+ );
247
+
248
+ const output = lastFrame();
249
+ t.regex(output!, /normal mode on/);
250
+ });
251
+
252
+ test('DevelopmentModeIndicator handles custom colors', t => {
253
+ const customColors = {
254
+ ...mockColors,
255
+ secondary: '#123456',
256
+ info: '#789ABC',
257
+ warning: '#DEF012',
258
+ };
259
+
260
+ t.notThrows(() => {
261
+ render(
262
+ <DevelopmentModeIndicator
263
+ developmentMode="normal"
264
+ colors={customColors}
265
+ />,
266
+ );
267
+ });
268
+ });
@@ -0,0 +1,38 @@
1
+ import type {useTheme} from '@/hooks/useTheme';
2
+ import {DEVELOPMENT_MODE_LABELS} from '@/types/core';
3
+ import type {DevelopmentMode} from '@/types/core';
4
+ import {Box, Text} from 'ink';
5
+ import React from 'react';
6
+
7
+ interface DevelopmentModeIndicatorProps {
8
+ developmentMode: DevelopmentMode;
9
+ colors: ReturnType<typeof useTheme>['colors'];
10
+ }
11
+
12
+ /**
13
+ * Development mode indicator component
14
+ * Shows the current development mode (normal/auto-accept/plan) and instructions
15
+ * Always visible to help users understand the current mode
16
+ */
17
+ export const DevelopmentModeIndicator = React.memo(
18
+ ({developmentMode, colors}: DevelopmentModeIndicatorProps) => {
19
+ return (
20
+ <Box marginTop={1}>
21
+ <Text
22
+ color={
23
+ developmentMode === 'normal'
24
+ ? colors.secondary
25
+ : developmentMode === 'auto-accept'
26
+ ? colors.info
27
+ : colors.warning
28
+ }
29
+ >
30
+ <Text bold>{DEVELOPMENT_MODE_LABELS[developmentMode]}</Text>{' '}
31
+ <Text dimColor>(Shift+Tab to cycle)</Text>
32
+ </Text>
33
+ </Box>
34
+ );
35
+ },
36
+ );
37
+
38
+ DevelopmentModeIndicator.displayName = 'DevelopmentModeIndicator';