@gguf/coder 0.3.0 → 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 (414) 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/package.json +2 -14
  10. package/scripts/extract-changelog.js +73 -0
  11. package/scripts/fetch-models.js +143 -0
  12. package/scripts/test.sh +40 -0
  13. package/scripts/update-homebrew-formula.sh +125 -0
  14. package/scripts/update-nix-version.sh +157 -0
  15. package/source/ai-sdk-client/AISDKClient.spec.ts +117 -0
  16. package/source/ai-sdk-client/AISDKClient.ts +155 -0
  17. package/source/ai-sdk-client/chat/chat-handler.spec.ts +121 -0
  18. package/source/ai-sdk-client/chat/chat-handler.ts +276 -0
  19. package/source/ai-sdk-client/chat/streaming-handler.spec.ts +173 -0
  20. package/source/ai-sdk-client/chat/streaming-handler.ts +110 -0
  21. package/source/ai-sdk-client/chat/tool-processor.spec.ts +92 -0
  22. package/source/ai-sdk-client/chat/tool-processor.ts +70 -0
  23. package/source/ai-sdk-client/converters/message-converter.spec.ts +220 -0
  24. package/source/ai-sdk-client/converters/message-converter.ts +113 -0
  25. package/source/ai-sdk-client/converters/tool-converter.spec.ts +90 -0
  26. package/source/ai-sdk-client/converters/tool-converter.ts +46 -0
  27. package/source/ai-sdk-client/error-handling/error-extractor.spec.ts +55 -0
  28. package/source/ai-sdk-client/error-handling/error-extractor.ts +15 -0
  29. package/source/ai-sdk-client/error-handling/error-parser.spec.ts +169 -0
  30. package/source/ai-sdk-client/error-handling/error-parser.ts +161 -0
  31. package/source/ai-sdk-client/index.ts +7 -0
  32. package/source/ai-sdk-client/providers/provider-factory.spec.ts +71 -0
  33. package/source/ai-sdk-client/providers/provider-factory.ts +41 -0
  34. package/source/ai-sdk-client/types.ts +9 -0
  35. package/source/ai-sdk-client-empty-message.spec.ts +141 -0
  36. package/source/ai-sdk-client-error-handling.spec.ts +186 -0
  37. package/source/ai-sdk-client-maxretries.spec.ts +114 -0
  38. package/source/ai-sdk-client-preparestep.spec.ts +279 -0
  39. package/source/app/App.spec.tsx +32 -0
  40. package/source/app/App.tsx +480 -0
  41. package/source/app/components/AppContainer.spec.tsx +96 -0
  42. package/source/app/components/AppContainer.tsx +56 -0
  43. package/source/app/components/ChatInterface.spec.tsx +163 -0
  44. package/source/app/components/ChatInterface.tsx +144 -0
  45. package/source/app/components/ModalSelectors.spec.tsx +141 -0
  46. package/source/app/components/ModalSelectors.tsx +135 -0
  47. package/source/app/helpers.spec.ts +97 -0
  48. package/source/app/helpers.ts +63 -0
  49. package/source/app/index.ts +4 -0
  50. package/source/app/types.ts +39 -0
  51. package/source/app/utils/appUtils.ts +294 -0
  52. package/source/app/utils/conversationState.ts +310 -0
  53. package/source/app.spec.tsx +244 -0
  54. package/source/cli.spec.ts +73 -0
  55. package/source/cli.tsx +51 -0
  56. package/source/client-factory.spec.ts +48 -0
  57. package/source/client-factory.ts +178 -0
  58. package/source/command-parser.spec.ts +127 -0
  59. package/source/command-parser.ts +36 -0
  60. package/source/commands/checkpoint.spec.tsx +277 -0
  61. package/source/commands/checkpoint.tsx +366 -0
  62. package/source/commands/clear.tsx +22 -0
  63. package/source/commands/custom-commands.tsx +121 -0
  64. package/source/commands/exit.ts +21 -0
  65. package/source/commands/export.spec.tsx +131 -0
  66. package/source/commands/export.tsx +79 -0
  67. package/source/commands/help.tsx +120 -0
  68. package/source/commands/index.ts +17 -0
  69. package/source/commands/init.tsx +339 -0
  70. package/source/commands/lsp-command.spec.tsx +281 -0
  71. package/source/commands/lsp.tsx +120 -0
  72. package/source/commands/mcp-command.spec.tsx +313 -0
  73. package/source/commands/mcp.tsx +162 -0
  74. package/source/commands/model-database.spec.tsx +758 -0
  75. package/source/commands/model-database.tsx +418 -0
  76. package/source/commands/model.ts +12 -0
  77. package/source/commands/provider.ts +12 -0
  78. package/source/commands/setup-config.tsx +16 -0
  79. package/source/commands/simple-commands.spec.tsx +175 -0
  80. package/source/commands/status.ts +12 -0
  81. package/source/commands/theme.ts +12 -0
  82. package/source/commands/update.spec.tsx +261 -0
  83. package/source/commands/update.tsx +201 -0
  84. package/source/commands/usage.spec.tsx +495 -0
  85. package/source/commands/usage.tsx +100 -0
  86. package/source/commands.spec.ts +436 -0
  87. package/source/commands.ts +83 -0
  88. package/source/components/assistant-message.spec.tsx +796 -0
  89. package/source/components/assistant-message.tsx +34 -0
  90. package/source/components/bash-execution-indicator.tsx +21 -0
  91. package/source/components/cancelling-indicator.tsx +16 -0
  92. package/source/components/chat-queue.spec.tsx +83 -0
  93. package/source/components/chat-queue.tsx +36 -0
  94. package/source/components/checkpoint-display.spec.tsx +219 -0
  95. package/source/components/checkpoint-display.tsx +126 -0
  96. package/source/components/checkpoint-selector.spec.tsx +173 -0
  97. package/source/components/checkpoint-selector.tsx +173 -0
  98. package/source/components/development-mode-indicator.spec.tsx +268 -0
  99. package/source/components/development-mode-indicator.tsx +38 -0
  100. package/source/components/message-box.spec.tsx +427 -0
  101. package/source/components/message-box.tsx +87 -0
  102. package/source/components/model-selector.tsx +132 -0
  103. package/source/components/provider-selector.tsx +75 -0
  104. package/source/components/random-spinner.tsx +19 -0
  105. package/source/components/security-disclaimer.tsx +73 -0
  106. package/source/components/status-connection-display.spec.tsx +133 -0
  107. package/source/components/status.tsx +267 -0
  108. package/source/components/theme-selector.tsx +126 -0
  109. package/source/components/tool-confirmation.tsx +190 -0
  110. package/source/components/tool-execution-indicator.tsx +33 -0
  111. package/source/components/tool-message.tsx +85 -0
  112. package/source/components/ui/titled-box.spec.tsx +207 -0
  113. package/source/components/ui/titled-box.tsx +57 -0
  114. package/source/components/usage/progress-bar.spec.tsx +398 -0
  115. package/source/components/usage/progress-bar.tsx +30 -0
  116. package/source/components/usage/usage-display.spec.tsx +780 -0
  117. package/source/components/usage/usage-display.tsx +291 -0
  118. package/source/components/user-input.spec.tsx +327 -0
  119. package/source/components/user-input.tsx +533 -0
  120. package/source/components/user-message.spec.tsx +230 -0
  121. package/source/components/user-message.tsx +84 -0
  122. package/source/components/welcome-message.tsx +76 -0
  123. package/source/config/env-substitution.ts +65 -0
  124. package/source/config/index.spec.ts +171 -0
  125. package/source/config/index.ts +154 -0
  126. package/source/config/paths.spec.ts +241 -0
  127. package/source/config/paths.ts +55 -0
  128. package/source/config/preferences.ts +51 -0
  129. package/source/config/themes.ts +315 -0
  130. package/source/constants.ts +130 -0
  131. package/source/context/mode-context.spec.ts +79 -0
  132. package/source/context/mode-context.ts +24 -0
  133. package/source/custom-commands/executor.spec.ts +142 -0
  134. package/source/custom-commands/executor.ts +64 -0
  135. package/source/custom-commands/loader.spec.ts +314 -0
  136. package/source/custom-commands/loader.ts +153 -0
  137. package/source/custom-commands/parser.ts +196 -0
  138. package/source/hooks/chat-handler/conversation/conversation-loop.spec.ts +39 -0
  139. package/source/hooks/chat-handler/conversation/conversation-loop.tsx +511 -0
  140. package/source/hooks/chat-handler/conversation/tool-executor.spec.ts +50 -0
  141. package/source/hooks/chat-handler/conversation/tool-executor.tsx +109 -0
  142. package/source/hooks/chat-handler/index.ts +12 -0
  143. package/source/hooks/chat-handler/state/streaming-state.spec.ts +26 -0
  144. package/source/hooks/chat-handler/state/streaming-state.ts +19 -0
  145. package/source/hooks/chat-handler/types.ts +38 -0
  146. package/source/hooks/chat-handler/useChatHandler.spec.tsx +321 -0
  147. package/source/hooks/chat-handler/useChatHandler.tsx +194 -0
  148. package/source/hooks/chat-handler/utils/context-checker.spec.ts +60 -0
  149. package/source/hooks/chat-handler/utils/context-checker.tsx +73 -0
  150. package/source/hooks/chat-handler/utils/message-helpers.spec.ts +42 -0
  151. package/source/hooks/chat-handler/utils/message-helpers.tsx +36 -0
  152. package/source/hooks/chat-handler/utils/tool-filters.spec.ts +109 -0
  153. package/source/hooks/chat-handler/utils/tool-filters.ts +64 -0
  154. package/source/hooks/useAppHandlers.tsx +291 -0
  155. package/source/hooks/useAppInitialization.tsx +422 -0
  156. package/source/hooks/useAppState.tsx +311 -0
  157. package/source/hooks/useDirectoryTrust.tsx +98 -0
  158. package/source/hooks/useInputState.ts +414 -0
  159. package/source/hooks/useModeHandlers.tsx +302 -0
  160. package/source/hooks/useNonInteractiveMode.ts +140 -0
  161. package/source/hooks/useTerminalWidth.tsx +81 -0
  162. package/source/hooks/useTheme.ts +18 -0
  163. package/source/hooks/useToolHandler.tsx +349 -0
  164. package/source/hooks/useUIState.ts +61 -0
  165. package/source/init/agents-template-generator.ts +421 -0
  166. package/source/init/existing-rules-extractor.ts +319 -0
  167. package/source/init/file-scanner.spec.ts +227 -0
  168. package/source/init/file-scanner.ts +238 -0
  169. package/source/init/framework-detector.ts +382 -0
  170. package/source/init/language-detector.ts +269 -0
  171. package/source/init/project-analyzer.spec.ts +231 -0
  172. package/source/init/project-analyzer.ts +458 -0
  173. package/source/lsp/index.ts +31 -0
  174. package/source/lsp/lsp-client.spec.ts +508 -0
  175. package/source/lsp/lsp-client.ts +487 -0
  176. package/source/lsp/lsp-manager.spec.ts +477 -0
  177. package/source/lsp/lsp-manager.ts +419 -0
  178. package/source/lsp/protocol.spec.ts +502 -0
  179. package/source/lsp/protocol.ts +360 -0
  180. package/source/lsp/server-discovery.spec.ts +654 -0
  181. package/source/lsp/server-discovery.ts +515 -0
  182. package/source/markdown-parser/html-entities.spec.ts +88 -0
  183. package/source/markdown-parser/html-entities.ts +45 -0
  184. package/source/markdown-parser/index.spec.ts +281 -0
  185. package/source/markdown-parser/index.ts +126 -0
  186. package/source/markdown-parser/table-parser.spec.ts +133 -0
  187. package/source/markdown-parser/table-parser.ts +114 -0
  188. package/source/markdown-parser/utils.spec.ts +70 -0
  189. package/source/markdown-parser/utils.ts +13 -0
  190. package/source/mcp/mcp-client.spec.ts +81 -0
  191. package/source/mcp/mcp-client.ts +625 -0
  192. package/source/mcp/transport-factory.spec.ts +406 -0
  193. package/source/mcp/transport-factory.ts +312 -0
  194. package/source/message-handler.ts +67 -0
  195. package/source/model-database/database-engine.spec.ts +494 -0
  196. package/source/model-database/database-engine.ts +50 -0
  197. package/source/model-database/model-database.spec.ts +363 -0
  198. package/source/model-database/model-database.ts +91 -0
  199. package/source/model-database/model-engine.spec.ts +447 -0
  200. package/source/model-database/model-engine.ts +65 -0
  201. package/source/model-database/model-fetcher.spec.ts +583 -0
  202. package/source/model-database/model-fetcher.ts +330 -0
  203. package/source/models/index.ts +1 -0
  204. package/source/models/models-cache.spec.ts +214 -0
  205. package/source/models/models-cache.ts +78 -0
  206. package/source/models/models-dev-client.spec.ts +379 -0
  207. package/source/models/models-dev-client.ts +329 -0
  208. package/source/models/models-types.ts +68 -0
  209. package/source/prompt-history.ts +155 -0
  210. package/source/security/command-injection.spec.ts +240 -0
  211. package/source/services/checkpoint-manager.spec.ts +523 -0
  212. package/source/services/checkpoint-manager.ts +466 -0
  213. package/source/services/file-snapshot.spec.ts +569 -0
  214. package/source/services/file-snapshot.ts +220 -0
  215. package/source/test-utils/render-with-theme.tsx +48 -0
  216. package/source/tokenization/index.ts +1 -0
  217. package/source/tokenization/tokenizer-factory.spec.ts +170 -0
  218. package/source/tokenization/tokenizer-factory.ts +125 -0
  219. package/source/tokenization/tokenizers/anthropic-tokenizer.spec.ts +200 -0
  220. package/source/tokenization/tokenizers/anthropic-tokenizer.ts +43 -0
  221. package/source/tokenization/tokenizers/fallback-tokenizer.spec.ts +236 -0
  222. package/source/tokenization/tokenizers/fallback-tokenizer.ts +26 -0
  223. package/source/tokenization/tokenizers/llama-tokenizer.spec.ts +224 -0
  224. package/source/tokenization/tokenizers/llama-tokenizer.ts +41 -0
  225. package/source/tokenization/tokenizers/openai-tokenizer.spec.ts +184 -0
  226. package/source/tokenization/tokenizers/openai-tokenizer.ts +57 -0
  227. package/source/tool-calling/index.ts +5 -0
  228. package/source/tool-calling/json-parser.spec.ts +639 -0
  229. package/source/tool-calling/json-parser.ts +247 -0
  230. package/source/tool-calling/tool-parser.spec.ts +395 -0
  231. package/source/tool-calling/tool-parser.ts +120 -0
  232. package/source/tool-calling/xml-parser.spec.ts +662 -0
  233. package/source/tool-calling/xml-parser.ts +289 -0
  234. package/source/tools/execute-bash.spec.tsx +353 -0
  235. package/source/tools/execute-bash.tsx +219 -0
  236. package/source/tools/execute-function.spec.ts +130 -0
  237. package/source/tools/fetch-url.spec.tsx +342 -0
  238. package/source/tools/fetch-url.tsx +172 -0
  239. package/source/tools/find-files.spec.tsx +924 -0
  240. package/source/tools/find-files.tsx +293 -0
  241. package/source/tools/index.ts +102 -0
  242. package/source/tools/lsp-get-diagnostics.tsx +192 -0
  243. package/source/tools/needs-approval.spec.ts +282 -0
  244. package/source/tools/read-file.spec.tsx +801 -0
  245. package/source/tools/read-file.tsx +387 -0
  246. package/source/tools/search-file-contents.spec.tsx +1273 -0
  247. package/source/tools/search-file-contents.tsx +293 -0
  248. package/source/tools/string-replace.spec.tsx +730 -0
  249. package/source/tools/string-replace.tsx +548 -0
  250. package/source/tools/tool-manager.ts +210 -0
  251. package/source/tools/tool-registry.spec.ts +415 -0
  252. package/source/tools/tool-registry.ts +228 -0
  253. package/source/tools/web-search.tsx +223 -0
  254. package/source/tools/write-file.spec.tsx +559 -0
  255. package/source/tools/write-file.tsx +228 -0
  256. package/source/types/app.ts +37 -0
  257. package/source/types/checkpoint.ts +48 -0
  258. package/source/types/commands.ts +46 -0
  259. package/source/types/components.ts +27 -0
  260. package/source/types/config.ts +103 -0
  261. package/source/types/core-connection-status.spec.ts +67 -0
  262. package/source/types/core.ts +181 -0
  263. package/source/types/hooks.ts +50 -0
  264. package/source/types/index.ts +12 -0
  265. package/source/types/markdown-parser.ts +11 -0
  266. package/source/types/mcp.ts +52 -0
  267. package/source/types/system.ts +16 -0
  268. package/source/types/tokenization.ts +41 -0
  269. package/source/types/ui.ts +40 -0
  270. package/source/types/usage.ts +58 -0
  271. package/source/types/utils.ts +16 -0
  272. package/source/usage/calculator.spec.ts +385 -0
  273. package/source/usage/calculator.ts +104 -0
  274. package/source/usage/storage.spec.ts +703 -0
  275. package/source/usage/storage.ts +238 -0
  276. package/source/usage/tracker.spec.ts +456 -0
  277. package/source/usage/tracker.ts +102 -0
  278. package/source/utils/atomic-deletion.spec.ts +194 -0
  279. package/source/utils/atomic-deletion.ts +127 -0
  280. package/source/utils/bounded-map.spec.ts +300 -0
  281. package/source/utils/bounded-map.ts +193 -0
  282. package/source/utils/checkpoint-utils.spec.ts +222 -0
  283. package/source/utils/checkpoint-utils.ts +92 -0
  284. package/source/utils/error-formatter.spec.ts +169 -0
  285. package/source/utils/error-formatter.ts +194 -0
  286. package/source/utils/file-autocomplete.spec.ts +173 -0
  287. package/source/utils/file-autocomplete.ts +196 -0
  288. package/source/utils/file-cache.spec.ts +309 -0
  289. package/source/utils/file-cache.ts +195 -0
  290. package/source/utils/file-content-loader.spec.ts +180 -0
  291. package/source/utils/file-content-loader.ts +179 -0
  292. package/source/utils/file-mention-handler.spec.ts +261 -0
  293. package/source/utils/file-mention-handler.ts +84 -0
  294. package/source/utils/file-mention-parser.spec.ts +182 -0
  295. package/source/utils/file-mention-parser.ts +170 -0
  296. package/source/utils/fuzzy-matching.spec.ts +149 -0
  297. package/source/utils/fuzzy-matching.ts +146 -0
  298. package/source/utils/indentation-normalizer.spec.ts +216 -0
  299. package/source/utils/indentation-normalizer.ts +76 -0
  300. package/source/utils/installation-detector.spec.ts +178 -0
  301. package/source/utils/installation-detector.ts +153 -0
  302. package/source/utils/logging/config.spec.ts +311 -0
  303. package/source/utils/logging/config.ts +210 -0
  304. package/source/utils/logging/console-facade.spec.ts +184 -0
  305. package/source/utils/logging/console-facade.ts +384 -0
  306. package/source/utils/logging/correlation.spec.ts +679 -0
  307. package/source/utils/logging/correlation.ts +474 -0
  308. package/source/utils/logging/formatters.spec.ts +464 -0
  309. package/source/utils/logging/formatters.ts +207 -0
  310. package/source/utils/logging/health-monitor/alerts/alert-manager.spec.ts +93 -0
  311. package/source/utils/logging/health-monitor/alerts/alert-manager.ts +79 -0
  312. package/source/utils/logging/health-monitor/checks/configuration-check.spec.ts +56 -0
  313. package/source/utils/logging/health-monitor/checks/configuration-check.ts +43 -0
  314. package/source/utils/logging/health-monitor/checks/logging-check.spec.ts +56 -0
  315. package/source/utils/logging/health-monitor/checks/logging-check.ts +58 -0
  316. package/source/utils/logging/health-monitor/checks/memory-check.spec.ts +100 -0
  317. package/source/utils/logging/health-monitor/checks/memory-check.ts +78 -0
  318. package/source/utils/logging/health-monitor/checks/performance-check.spec.ts +56 -0
  319. package/source/utils/logging/health-monitor/checks/performance-check.ts +56 -0
  320. package/source/utils/logging/health-monitor/checks/request-check.spec.ts +56 -0
  321. package/source/utils/logging/health-monitor/checks/request-check.ts +76 -0
  322. package/source/utils/logging/health-monitor/core/health-check-runner.spec.ts +70 -0
  323. package/source/utils/logging/health-monitor/core/health-check-runner.ts +138 -0
  324. package/source/utils/logging/health-monitor/core/health-monitor.spec.ts +58 -0
  325. package/source/utils/logging/health-monitor/core/health-monitor.ts +344 -0
  326. package/source/utils/logging/health-monitor/core/scoring.spec.ts +65 -0
  327. package/source/utils/logging/health-monitor/core/scoring.ts +91 -0
  328. package/source/utils/logging/health-monitor/index.ts +15 -0
  329. package/source/utils/logging/health-monitor/instances.ts +48 -0
  330. package/source/utils/logging/health-monitor/middleware/http-middleware.spec.ts +141 -0
  331. package/source/utils/logging/health-monitor/middleware/http-middleware.ts +75 -0
  332. package/source/utils/logging/health-monitor/types.ts +126 -0
  333. package/source/utils/logging/index.spec.ts +284 -0
  334. package/source/utils/logging/index.ts +236 -0
  335. package/source/utils/logging/integration.spec.ts +441 -0
  336. package/source/utils/logging/log-method-factory.spec.ts +573 -0
  337. package/source/utils/logging/log-method-factory.ts +233 -0
  338. package/source/utils/logging/log-query/aggregation/aggregator.spec.ts +277 -0
  339. package/source/utils/logging/log-query/aggregation/aggregator.ts +159 -0
  340. package/source/utils/logging/log-query/aggregation/facet-generator.spec.ts +159 -0
  341. package/source/utils/logging/log-query/aggregation/facet-generator.ts +47 -0
  342. package/source/utils/logging/log-query/index.ts +23 -0
  343. package/source/utils/logging/log-query/query/filter-predicates.spec.ts +247 -0
  344. package/source/utils/logging/log-query/query/filter-predicates.ts +154 -0
  345. package/source/utils/logging/log-query/query/query-builder.spec.ts +182 -0
  346. package/source/utils/logging/log-query/query/query-builder.ts +151 -0
  347. package/source/utils/logging/log-query/query/query-engine.spec.ts +214 -0
  348. package/source/utils/logging/log-query/query/query-engine.ts +45 -0
  349. package/source/utils/logging/log-query/storage/circular-buffer.spec.ts +143 -0
  350. package/source/utils/logging/log-query/storage/circular-buffer.ts +75 -0
  351. package/source/utils/logging/log-query/storage/index-manager.spec.ts +150 -0
  352. package/source/utils/logging/log-query/storage/index-manager.ts +71 -0
  353. package/source/utils/logging/log-query/storage/log-storage.spec.ts +257 -0
  354. package/source/utils/logging/log-query/storage/log-storage.ts +80 -0
  355. package/source/utils/logging/log-query/types.ts +163 -0
  356. package/source/utils/logging/log-query/utils/helpers.spec.ts +263 -0
  357. package/source/utils/logging/log-query/utils/helpers.ts +72 -0
  358. package/source/utils/logging/log-query/utils/sorting.spec.ts +182 -0
  359. package/source/utils/logging/log-query/utils/sorting.ts +61 -0
  360. package/source/utils/logging/logger-provider.spec.ts +262 -0
  361. package/source/utils/logging/logger-provider.ts +362 -0
  362. package/source/utils/logging/performance.spec.ts +209 -0
  363. package/source/utils/logging/performance.ts +757 -0
  364. package/source/utils/logging/pino-logger.spec.ts +425 -0
  365. package/source/utils/logging/pino-logger.ts +514 -0
  366. package/source/utils/logging/redaction.spec.ts +490 -0
  367. package/source/utils/logging/redaction.ts +267 -0
  368. package/source/utils/logging/request-tracker.spec.ts +1198 -0
  369. package/source/utils/logging/request-tracker.ts +803 -0
  370. package/source/utils/logging/transports.spec.ts +505 -0
  371. package/source/utils/logging/transports.ts +305 -0
  372. package/source/utils/logging/types.ts +216 -0
  373. package/source/utils/message-builder.spec.ts +179 -0
  374. package/source/utils/message-builder.ts +101 -0
  375. package/source/utils/message-queue.tsx +486 -0
  376. package/source/utils/paste-detection.spec.ts +69 -0
  377. package/source/utils/paste-detection.ts +124 -0
  378. package/source/utils/paste-roundtrip.spec.ts +442 -0
  379. package/source/utils/paste-utils.spec.ts +128 -0
  380. package/source/utils/paste-utils.ts +52 -0
  381. package/source/utils/programming-language-helper.spec.ts +74 -0
  382. package/source/utils/programming-language-helper.ts +32 -0
  383. package/source/utils/prompt-assembly.spec.ts +221 -0
  384. package/source/utils/prompt-processor.ts +173 -0
  385. package/source/utils/tool-args-parser.spec.ts +136 -0
  386. package/source/utils/tool-args-parser.ts +54 -0
  387. package/source/utils/tool-cancellation.spec.ts +230 -0
  388. package/source/utils/tool-cancellation.ts +28 -0
  389. package/source/utils/tool-result-display.spec.tsx +469 -0
  390. package/source/utils/tool-result-display.tsx +90 -0
  391. package/source/utils/update-checker.spec.ts +383 -0
  392. package/source/utils/update-checker.ts +183 -0
  393. package/source/wizard/config-wizard.spec.tsx +103 -0
  394. package/source/wizard/config-wizard.tsx +382 -0
  395. package/source/wizard/steps/location-step.spec.tsx +186 -0
  396. package/source/wizard/steps/location-step.tsx +147 -0
  397. package/source/wizard/steps/mcp-step.spec.tsx +607 -0
  398. package/source/wizard/steps/mcp-step.tsx +632 -0
  399. package/source/wizard/steps/provider-step.spec.tsx +342 -0
  400. package/source/wizard/steps/provider-step.tsx +957 -0
  401. package/source/wizard/steps/summary-step.spec.tsx +749 -0
  402. package/source/wizard/steps/summary-step.tsx +228 -0
  403. package/source/wizard/templates/mcp-templates.spec.ts +613 -0
  404. package/source/wizard/templates/mcp-templates.ts +570 -0
  405. package/source/wizard/templates/provider-templates.spec.ts +152 -0
  406. package/source/wizard/templates/provider-templates.ts +485 -0
  407. package/source/wizard/utils/fetch-cloud-models.spec.ts +428 -0
  408. package/source/wizard/utils/fetch-cloud-models.ts +223 -0
  409. package/source/wizard/utils/fetch-local-models.spec.ts +297 -0
  410. package/source/wizard/utils/fetch-local-models.ts +192 -0
  411. package/source/wizard/validation-array.spec.ts +264 -0
  412. package/source/wizard/validation.spec.ts +373 -0
  413. package/source/wizard/validation.ts +232 -0
  414. package/source/app/prompts/main-prompt.md +0 -122
@@ -0,0 +1,289 @@
1
+ import type {ToolCall} from '@/types/index';
2
+
3
+ interface ParsedToolCall {
4
+ toolName: string;
5
+ parameters: Record<string, unknown>;
6
+ }
7
+
8
+ /**
9
+ * Parses XML-formatted tool calls from non-function-calling models
10
+ * Expected format: <tool_name><param1>value1</param1><param2>value2</param2></tool_name>
11
+ */
12
+ export class XMLToolCallParser {
13
+ private static readonly TOOL_CALL_REGEX = /<(\w+)>(.*?)<\/\1>/gs;
14
+ private static readonly PARAMETER_REGEX = /<(\w+)>(.*?)<\/\1>/gs;
15
+
16
+ /**
17
+ * Extracts tool calls from text content containing XML-formatted tool calls
18
+ */
19
+ static parseToolCalls(content: string): ParsedToolCall[] {
20
+ const toolCalls: ParsedToolCall[] = [];
21
+ let match;
22
+
23
+ // Handle content that might be wrapped in markdown code blocks
24
+ let processedContent = content;
25
+ const codeBlockMatch = content.match(/```(?:\w+)?\s*\n?([\s\S]*?)\n?```/);
26
+ if (codeBlockMatch && codeBlockMatch[1]) {
27
+ processedContent = codeBlockMatch[1].trim();
28
+ }
29
+
30
+ // Remove <tool_call> wrapper tags if present
31
+ processedContent = processedContent.replace(/<\/?tool_call>/g, '').trim();
32
+
33
+ // Find all tool call blocks
34
+ this.TOOL_CALL_REGEX.lastIndex = 0; // Reset regex state
35
+ while ((match = this.TOOL_CALL_REGEX.exec(processedContent)) !== null) {
36
+ const [fullMatch, toolName, innerXml] = match;
37
+
38
+ // Skip if this is a generic "tool_call" tag that slipped through
39
+ if (toolName === 'tool_call') {
40
+ continue;
41
+ }
42
+
43
+ // Validate that this is a properly formed tool call
44
+ if (!this.isValidToolCall(fullMatch, toolName)) {
45
+ continue;
46
+ }
47
+
48
+ const parameters = this.parseParameters(innerXml);
49
+
50
+ toolCalls.push({
51
+ toolName,
52
+ parameters,
53
+ });
54
+ }
55
+
56
+ return toolCalls;
57
+ }
58
+
59
+ /**
60
+ * Validates that a matched string is a proper tool call
61
+ * Rejects partial matches, malformed syntax, and invalid structures
62
+ */
63
+ private static isValidToolCall(fullMatch: string, toolName: string): boolean {
64
+ // Reject common HTML tags that might be in model output
65
+ const htmlTags = [
66
+ 'div',
67
+ 'span',
68
+ 'p',
69
+ 'a',
70
+ 'ul',
71
+ 'ol',
72
+ 'li',
73
+ 'table',
74
+ 'tr',
75
+ 'td',
76
+ 'th',
77
+ 'thead',
78
+ 'tbody',
79
+ 'h1',
80
+ 'h2',
81
+ 'h3',
82
+ 'h4',
83
+ 'h5',
84
+ 'h6',
85
+ 'br',
86
+ 'hr',
87
+ 'strong',
88
+ 'em',
89
+ 'code',
90
+ 'pre',
91
+ 'blockquote',
92
+ 'img',
93
+ 'section',
94
+ 'article',
95
+ 'header',
96
+ 'footer',
97
+ 'nav',
98
+ 'aside',
99
+ ];
100
+ if (htmlTags.includes(toolName.toLowerCase())) {
101
+ return false;
102
+ }
103
+
104
+ // Check for malformed attribute-style syntax like <function=name> or <parameter=name>
105
+ if (fullMatch.includes('=')) {
106
+ return false;
107
+ }
108
+
109
+ // Check if the closing tag is properly formed
110
+ if (!fullMatch.endsWith(`</${toolName}>`)) {
111
+ return false;
112
+ }
113
+
114
+ // Extract inner content between opening and closing tags
115
+ const innerContent = fullMatch.substring(
116
+ toolName.length + 2,
117
+ fullMatch.length - (toolName.length + 3),
118
+ );
119
+
120
+ // Valid tool calls should contain parameter tags (other XML tags inside)
121
+ // This prevents matching on standalone parameter tags from malformed XML
122
+ const hasNestedTags = /<\w+>/.test(innerContent);
123
+
124
+ // Tool names should contain underscores (snake_case convention for tools)
125
+ // or be reasonably long compound words
126
+ const hasUnderscore = toolName.includes('_');
127
+
128
+ // Allow if it has nested tags OR follows naming convention
129
+ if (!hasNestedTags && !hasUnderscore) {
130
+ return false;
131
+ }
132
+
133
+ return true;
134
+ }
135
+
136
+ /**
137
+ * Parses parameters from inner XML content
138
+ */
139
+ private static parseParameters(innerXml: string): Record<string, unknown> {
140
+ const parameters: Record<string, unknown> = {};
141
+ let match;
142
+
143
+ // Reset regex state
144
+ this.PARAMETER_REGEX.lastIndex = 0;
145
+
146
+ while ((match = this.PARAMETER_REGEX.exec(innerXml)) !== null) {
147
+ const [, paramName, paramValue] = match;
148
+
149
+ // Trim whitespace from parameter value
150
+ const trimmedValue = paramValue.trim();
151
+
152
+ // Try to parse as JSON for complex objects/arrays
153
+ try {
154
+ parameters[paramName] = JSON.parse(trimmedValue) as unknown;
155
+ } catch {
156
+ // If not valid JSON, use as string (preserving internal whitespace/newlines)
157
+ parameters[paramName] = trimmedValue;
158
+ }
159
+ }
160
+
161
+ return parameters;
162
+ }
163
+
164
+ /**
165
+ * Converts parsed tool calls to the standard ToolCall format
166
+ */
167
+ static convertToToolCalls(parsedCalls: ParsedToolCall[]): ToolCall[] {
168
+ return parsedCalls.map((call, index) => ({
169
+ id: `xml_call_${index}`,
170
+ function: {
171
+ name: call.toolName,
172
+ arguments: call.parameters,
173
+ },
174
+ }));
175
+ }
176
+
177
+ /**
178
+ * Removes XML tool call blocks from content, leaving only the text
179
+ */
180
+ static removeToolCallsFromContent(content: string): string {
181
+ let cleanedContent = content;
182
+
183
+ // Remove all markdown code blocks that contain XML tool calls (using global flag)
184
+ cleanedContent = cleanedContent.replace(
185
+ /```(?:\w+)?\s*\n?([\s\S]*?)\n?```/g,
186
+ (match, blockContent: string) => {
187
+ if (blockContent) {
188
+ // Reset regex and check if this block contains XML tool calls
189
+ this.TOOL_CALL_REGEX.lastIndex = 0;
190
+ if (this.TOOL_CALL_REGEX.test(blockContent)) {
191
+ // This code block contains XML tool calls, remove it entirely
192
+ return '';
193
+ }
194
+ }
195
+ // Keep blocks that don't contain XML tool calls
196
+ return match;
197
+ },
198
+ );
199
+
200
+ // Remove XML tool calls that aren't in code blocks
201
+ this.TOOL_CALL_REGEX.lastIndex = 0;
202
+ cleanedContent = cleanedContent.replace(this.TOOL_CALL_REGEX, '');
203
+
204
+ // Remove any <tool_call> wrapper tags that may be left behind
205
+ cleanedContent = cleanedContent.replace(/<\/?tool_call>/g, '');
206
+
207
+ // Clean up whitespace artifacts left by removed tool calls
208
+ cleanedContent = cleanedContent
209
+ // Remove trailing whitespace from each line
210
+ .replace(/[ \t]+$/gm, '')
211
+ // Collapse multiple spaces (but not at start of line for indentation)
212
+ .replace(/([^ \t\n]) {2,}/g, '$1 ')
213
+ // Remove lines that are only whitespace
214
+ .replace(/^[ \t]+$/gm, '')
215
+ // Collapse 2+ consecutive blank lines to a single blank line
216
+ .replace(/\n{3,}/g, '\n\n')
217
+ .trim();
218
+
219
+ return cleanedContent;
220
+ }
221
+
222
+ /**
223
+ * Checks if content contains XML-formatted tool calls
224
+ */
225
+ static hasToolCalls(content: string): boolean {
226
+ // Use parseToolCalls with validation to ensure we only detect valid tool calls
227
+ const toolCalls = this.parseToolCalls(content);
228
+ return toolCalls.length > 0;
229
+ }
230
+
231
+ /**
232
+ * Detects malformed XML tool call attempts and returns error details
233
+ * Returns null if no malformed tool calls detected
234
+ */
235
+ static detectMalformedToolCall(
236
+ content: string,
237
+ ): {error: string; examples: string} | null {
238
+ // Common malformed patterns
239
+ const patterns = [
240
+ {
241
+ // [tool_use: name] or [Tool: name] syntax (common with some models like GLM)
242
+ regex: /\[(?:tool_use|Tool):\s*(\w+)\]/i,
243
+ error:
244
+ 'Invalid syntax: [tool_use: name] or [Tool: name] format is not supported',
245
+ },
246
+ {
247
+ // <function=name> syntax
248
+ regex: /<function=(\w+)>/,
249
+ error: 'Invalid syntax: <function=name> is not supported',
250
+ },
251
+ {
252
+ // <parameter=name> syntax
253
+ regex: /<parameter=(\w+)>/,
254
+ error: 'Invalid syntax: <parameter=name> is not supported',
255
+ },
256
+ {
257
+ // Generic closing </parameter> without proper name
258
+ regex: /<parameter=\w+>[\s\S]*?<\/parameter>/,
259
+ error:
260
+ 'Invalid parameter syntax: parameters must use named tags, not generic <parameter> wrapper',
261
+ },
262
+ {
263
+ // Generic closing </function> when <function=name> was used
264
+ regex: /<function=\w+>[\s\S]*?<\/function>/,
265
+ error:
266
+ 'Invalid function syntax: use simple named tags, not <function=name> wrapper',
267
+ },
268
+ ];
269
+
270
+ for (const pattern of patterns) {
271
+ const match = content.match(pattern.regex);
272
+ if (match) {
273
+ return {
274
+ error: pattern.error,
275
+ examples: this.getCorrectFormatExamples(),
276
+ };
277
+ }
278
+ }
279
+
280
+ return null;
281
+ }
282
+
283
+ /**
284
+ * Generates correct format examples for error messages
285
+ */
286
+ private static getCorrectFormatExamples(): string {
287
+ return `Please use the native tool calling format provided by the system. The tools are already available to you - call them directly using the function calling interface.`;
288
+ }
289
+ }
@@ -0,0 +1,353 @@
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 {executeBashTool} from './execute-bash';
7
+
8
+ // ============================================================================
9
+ // Test Helpers
10
+ // ============================================================================
11
+
12
+ console.log(`\nexecute-bash.spec.tsx – ${React.version}`);
13
+
14
+ // Create a mock theme provider for tests
15
+ function TestThemeProvider({children}: {children: React.ReactNode}) {
16
+ const themeContextValue = {
17
+ currentTheme: 'tokyo-night' as const,
18
+ colors: themes['tokyo-night'].colors,
19
+ setCurrentTheme: () => {},
20
+ };
21
+
22
+ return (
23
+ <ThemeContext.Provider value={themeContextValue}>
24
+ {children}
25
+ </ThemeContext.Provider>
26
+ );
27
+ }
28
+
29
+ // ============================================================================
30
+ // Tests for ExecuteBashFormatter Component Rendering
31
+ // ============================================================================
32
+
33
+ test('ExecuteBashFormatter renders with command', t => {
34
+ const formatter = executeBashTool.formatter;
35
+ if (!formatter) {
36
+ t.fail('Formatter is not defined');
37
+ return;
38
+ }
39
+
40
+ const element = formatter({command: 'echo "hello"'}, 'hello');
41
+ const {lastFrame} = render(<TestThemeProvider>{element}</TestThemeProvider>);
42
+
43
+ const output = lastFrame();
44
+ t.truthy(output);
45
+ t.regex(output!, /execute_bash/);
46
+ t.regex(output!, /echo "hello"/);
47
+ });
48
+
49
+ test('ExecuteBashFormatter displays output size', t => {
50
+ const formatter = executeBashTool.formatter;
51
+ if (!formatter) {
52
+ t.fail('Formatter is not defined');
53
+ return;
54
+ }
55
+
56
+ const result = 'test output';
57
+ const element = formatter({command: 'echo test'}, result);
58
+ const {lastFrame} = render(<TestThemeProvider>{element}</TestThemeProvider>);
59
+
60
+ const output = lastFrame();
61
+ t.truthy(output);
62
+ t.regex(output!, /characters/);
63
+ t.regex(output!, /tokens/);
64
+ });
65
+
66
+ test('ExecuteBashFormatter renders without result', t => {
67
+ const formatter = executeBashTool.formatter;
68
+ if (!formatter) {
69
+ t.fail('Formatter is not defined');
70
+ return;
71
+ }
72
+
73
+ const element = formatter({command: 'ls'});
74
+ const {lastFrame} = render(<TestThemeProvider>{element}</TestThemeProvider>);
75
+
76
+ const output = lastFrame();
77
+ t.truthy(output);
78
+ t.regex(output!, /execute_bash/);
79
+ t.regex(output!, /ls/);
80
+ });
81
+
82
+ test('ExecuteBashFormatter handles complex commands', t => {
83
+ const formatter = executeBashTool.formatter;
84
+ if (!formatter) {
85
+ t.fail('Formatter is not defined');
86
+ return;
87
+ }
88
+
89
+ const command = 'find . -name "*.ts" | grep -v node_modules';
90
+ const element = formatter({command}, 'file1.ts\nfile2.ts');
91
+ const {lastFrame} = render(<TestThemeProvider>{element}</TestThemeProvider>);
92
+
93
+ const output = lastFrame();
94
+ t.truthy(output);
95
+ t.regex(output!, /find/);
96
+ });
97
+
98
+ // ============================================================================
99
+ // Tests for execute_bash Tool Handler - Basic Functionality
100
+ // ============================================================================
101
+
102
+ test('execute_bash runs simple echo command', async t => {
103
+ const result = await executeBashTool.tool.execute!(
104
+ {command: 'echo "test output"'},
105
+ {toolCallId: 'test', messages: []},
106
+ );
107
+
108
+ t.truthy(result);
109
+ t.true(result.includes('test output'));
110
+ });
111
+
112
+ test('execute_bash returns output from ls command', async t => {
113
+ const result = await executeBashTool.tool.execute!(
114
+ {command: 'ls'},
115
+ {toolCallId: 'test', messages: []},
116
+ );
117
+
118
+ t.truthy(result);
119
+ t.is(typeof result, 'string');
120
+ });
121
+
122
+ test('execute_bash handles command with pipes', async t => {
123
+ const result = await executeBashTool.tool.execute!(
124
+ {
125
+ command: 'echo "line1\nline2\nline3" | grep line2',
126
+ },
127
+ {toolCallId: 'test', messages: []},
128
+ );
129
+
130
+ t.truthy(result);
131
+ t.true(result.includes('line2'));
132
+ t.false(result.includes('line1'));
133
+ });
134
+
135
+ test('execute_bash handles command with redirects', async t => {
136
+ const result = await executeBashTool.tool.execute!(
137
+ {
138
+ command: 'echo "test" 2>&1',
139
+ },
140
+ {toolCallId: 'test', messages: []},
141
+ );
142
+
143
+ t.truthy(result);
144
+ t.true(result.includes('test'));
145
+ });
146
+
147
+ test('execute_bash preserves multiline output', async t => {
148
+ const result = await executeBashTool.tool.execute!(
149
+ {
150
+ command: 'echo "line1"; echo "line2"; echo "line3"',
151
+ },
152
+ {toolCallId: 'test', messages: []},
153
+ );
154
+
155
+ t.truthy(result);
156
+ t.true(result.includes('line1'));
157
+ t.true(result.includes('line2'));
158
+ t.true(result.includes('line3'));
159
+ });
160
+
161
+ // ============================================================================
162
+ // Tests for execute_bash Tool Handler - Error Handling
163
+ // ============================================================================
164
+
165
+ test('execute_bash captures stderr output', async t => {
166
+ const result = await executeBashTool.tool.execute!(
167
+ {
168
+ command: 'echo "error message" >&2',
169
+ },
170
+ {toolCallId: 'test', messages: []},
171
+ );
172
+
173
+ t.truthy(result);
174
+ // Should include STDERR label when stderr is present
175
+ t.true(result.includes('STDERR') || result.includes('error message'));
176
+ });
177
+
178
+ test('execute_bash handles command not found', async t => {
179
+ const result = await executeBashTool.tool.execute!(
180
+ {
181
+ command: 'nonexistentcommand12345',
182
+ },
183
+ {toolCallId: 'test', messages: []},
184
+ );
185
+
186
+ t.truthy(result);
187
+ // Should capture the error output
188
+ t.true(
189
+ result.includes('not found') ||
190
+ result.includes('command not found') ||
191
+ result.includes('STDERR'),
192
+ );
193
+ });
194
+
195
+ test('execute_bash handles syntax errors', async t => {
196
+ const result = await executeBashTool.tool.execute!(
197
+ {
198
+ command: 'echo "unclosed quote',
199
+ },
200
+ {toolCallId: 'test', messages: []},
201
+ );
202
+
203
+ t.truthy(result);
204
+ // Should capture the syntax error
205
+ t.is(typeof result, 'string');
206
+ });
207
+
208
+ // ============================================================================
209
+ // Tests for execute_bash Tool Handler - Output Truncation
210
+ // ============================================================================
211
+
212
+ test('execute_bash truncates long output to 2000 characters', async t => {
213
+ // Generate output longer than 2000 characters
214
+ // Use POSIX-compatible syntax (seq instead of bash brace expansion)
215
+ const longCommand =
216
+ 'seq 1 100 | while read i; do echo "This is a long line of text that repeats many times"; done';
217
+ const result = await executeBashTool.tool.execute!(
218
+ {command: longCommand},
219
+ {toolCallId: 'test', messages: []},
220
+ );
221
+
222
+ t.truthy(result);
223
+ // Should be truncated to around 2000 characters
224
+ t.true(
225
+ result.length <= 2100,
226
+ `Output length ${result.length} should be <= 2100`,
227
+ );
228
+ // Should include truncation message
229
+ t.true(result.includes('[Output truncated'));
230
+ });
231
+
232
+ test('execute_bash does not truncate short output', async t => {
233
+ const result = await executeBashTool.tool.execute!(
234
+ {
235
+ command: 'echo "short output"',
236
+ },
237
+ {toolCallId: 'test', messages: []},
238
+ );
239
+
240
+ t.truthy(result);
241
+ t.false(result.includes('[Output truncated'));
242
+ t.true(result.includes('short output'));
243
+ });
244
+
245
+ test('execute_bash returns plain string not JSON', async t => {
246
+ const result = await executeBashTool.tool.execute!(
247
+ {command: 'echo "test"'},
248
+ {toolCallId: 'test', messages: []},
249
+ );
250
+
251
+ t.truthy(result);
252
+ t.is(typeof result, 'string');
253
+ // Should NOT be JSON with fullOutput and llmContext
254
+ t.false(result.includes('fullOutput'));
255
+ t.false(result.includes('llmContext'));
256
+ });
257
+
258
+ // ============================================================================
259
+ // Tests for execute_bash Tool Handler - Special Characters
260
+ // ============================================================================
261
+
262
+ test('execute_bash handles special characters in output', async t => {
263
+ const result = await executeBashTool.tool.execute!(
264
+ {
265
+ command: 'echo "special: $@#%^&*()"',
266
+ },
267
+ {toolCallId: 'test', messages: []},
268
+ );
269
+
270
+ t.truthy(result);
271
+ t.true(result.includes('special'));
272
+ });
273
+
274
+ test('execute_bash handles quotes in commands', async t => {
275
+ const result = await executeBashTool.tool.execute!(
276
+ {
277
+ command: 'echo "He said \\"hello\\""',
278
+ },
279
+ {toolCallId: 'test', messages: []},
280
+ );
281
+
282
+ t.truthy(result);
283
+ t.true(result.includes('said'));
284
+ });
285
+
286
+ test('execute_bash handles newlines in command', async t => {
287
+ const result = await executeBashTool.tool.execute!(
288
+ {
289
+ command: 'echo "line1\nline2"',
290
+ },
291
+ {toolCallId: 'test', messages: []},
292
+ );
293
+
294
+ t.truthy(result);
295
+ t.is(typeof result, 'string');
296
+ });
297
+
298
+ // ============================================================================
299
+ // Tests for execute_bash Tool Configuration
300
+ // ============================================================================
301
+
302
+ test('execute_bash tool has correct name', t => {
303
+ t.is(executeBashTool.name, 'execute_bash');
304
+ });
305
+
306
+ test('execute_bash tool requires confirmation', t => {
307
+ // Execute bash should require confirmation for security
308
+ t.not(executeBashTool.tool.needsApproval, false);
309
+ });
310
+
311
+ test('execute_bash tool has handler function', t => {
312
+ t.is(typeof executeBashTool.tool.execute, 'function');
313
+ });
314
+
315
+ test('execute_bash tool has formatter function', t => {
316
+ t.is(typeof executeBashTool.formatter, 'function');
317
+ });
318
+
319
+ // ============================================================================
320
+ // Tests for execute_bash Tool Handler - Edge Cases
321
+ // ============================================================================
322
+
323
+ test('execute_bash handles empty command output', async t => {
324
+ const result = await executeBashTool.tool.execute!(
325
+ {command: 'true'},
326
+ {toolCallId: 'test', messages: []},
327
+ );
328
+
329
+ // Empty output returns empty string, which is falsy but valid
330
+ t.is(typeof result, 'string');
331
+ // Empty output is still a valid string
332
+ t.true(result.length >= 0);
333
+ });
334
+
335
+ test('execute_bash handles commands with no output', async t => {
336
+ const result = await executeBashTool.tool.execute!(
337
+ {command: ':'},
338
+ {toolCallId: 'test', messages: []},
339
+ );
340
+
341
+ // Empty output returns empty string, which is falsy but valid
342
+ t.is(typeof result, 'string');
343
+ });
344
+
345
+ test('execute_bash handles whitespace-only output', async t => {
346
+ const result = await executeBashTool.tool.execute!(
347
+ {command: 'echo " "'},
348
+ {toolCallId: 'test', messages: []},
349
+ );
350
+
351
+ t.truthy(result);
352
+ t.is(typeof result, 'string');
353
+ });