@machina.ai/cell-cli-core 1.13.0-rc4 → 1.16.0-rc1

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 (422) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +2 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +1 -1
  5. package/dist/src/agents/codebase-investigator.test.d.ts +6 -0
  6. package/dist/src/agents/codebase-investigator.test.js +35 -0
  7. package/dist/src/agents/codebase-investigator.test.js.map +1 -0
  8. package/dist/src/agents/executor.d.ts +3 -0
  9. package/dist/src/agents/executor.js +21 -0
  10. package/dist/src/agents/executor.js.map +1 -1
  11. package/dist/src/agents/executor.test.js +358 -3
  12. package/dist/src/agents/executor.test.js.map +1 -1
  13. package/dist/src/code_assist/codeAssist.test.d.ts +6 -0
  14. package/dist/src/code_assist/codeAssist.test.js +99 -0
  15. package/dist/src/code_assist/codeAssist.test.js.map +1 -0
  16. package/dist/src/code_assist/experiments/client_metadata.js +2 -1
  17. package/dist/src/code_assist/experiments/client_metadata.js.map +1 -1
  18. package/dist/src/code_assist/experiments/client_metadata.test.d.ts +6 -0
  19. package/dist/src/code_assist/experiments/client_metadata.test.js +99 -0
  20. package/dist/src/code_assist/experiments/client_metadata.test.js.map +1 -0
  21. package/dist/src/code_assist/experiments/experiments.js +2 -2
  22. package/dist/src/code_assist/experiments/experiments.js.map +1 -1
  23. package/dist/src/code_assist/experiments/experiments.test.d.ts +6 -0
  24. package/dist/src/code_assist/experiments/experiments.test.js +92 -0
  25. package/dist/src/code_assist/experiments/experiments.test.js.map +1 -0
  26. package/dist/src/code_assist/experiments/flagNames.d.ts +13 -0
  27. package/dist/src/code_assist/experiments/flagNames.js +13 -0
  28. package/dist/src/code_assist/experiments/flagNames.js.map +1 -0
  29. package/dist/src/code_assist/experiments/types.d.ts +1 -1
  30. package/dist/src/code_assist/oauth-credential-storage.test.js +49 -0
  31. package/dist/src/code_assist/oauth-credential-storage.test.js.map +1 -1
  32. package/dist/src/code_assist/server.js +5 -8
  33. package/dist/src/code_assist/server.js.map +1 -1
  34. package/dist/src/code_assist/server.test.js +109 -28
  35. package/dist/src/code_assist/server.test.js.map +1 -1
  36. package/dist/src/config/config.d.ts +34 -2
  37. package/dist/src/config/config.js +147 -26
  38. package/dist/src/config/config.js.map +1 -1
  39. package/dist/src/config/config.test.js +436 -19
  40. package/dist/src/config/config.test.js.map +1 -1
  41. package/dist/src/config/defaultModelConfigs.d.ts +7 -0
  42. package/dist/src/config/defaultModelConfigs.js +158 -0
  43. package/dist/src/config/defaultModelConfigs.js.map +1 -0
  44. package/dist/src/config/models.d.ts +22 -1
  45. package/dist/src/config/models.js +49 -6
  46. package/dist/src/config/models.js.map +1 -1
  47. package/dist/src/config/models.test.js +71 -10
  48. package/dist/src/config/models.test.js.map +1 -1
  49. package/dist/src/confirmation-bus/message-bus.d.ts +1 -1
  50. package/dist/src/confirmation-bus/message-bus.js +2 -2
  51. package/dist/src/confirmation-bus/message-bus.js.map +1 -1
  52. package/dist/src/confirmation-bus/message-bus.test.js +30 -24
  53. package/dist/src/confirmation-bus/message-bus.test.js.map +1 -1
  54. package/dist/src/confirmation-bus/types.d.ts +1 -0
  55. package/dist/src/core/baseLlmClient.d.ts +4 -8
  56. package/dist/src/core/baseLlmClient.js +3 -8
  57. package/dist/src/core/baseLlmClient.js.map +1 -1
  58. package/dist/src/core/baseLlmClient.test.js +22 -27
  59. package/dist/src/core/baseLlmClient.test.js.map +1 -1
  60. package/dist/src/core/client.d.ts +6 -5
  61. package/dist/src/core/client.js +33 -33
  62. package/dist/src/core/client.js.map +1 -1
  63. package/dist/src/core/client.test.js +40 -22
  64. package/dist/src/core/client.test.js.map +1 -1
  65. package/dist/src/core/coreToolScheduler.js +7 -1
  66. package/dist/src/core/coreToolScheduler.js.map +1 -1
  67. package/dist/src/core/coreToolScheduler.test.js +151 -357
  68. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  69. package/dist/src/core/geminiChat.d.ts +6 -4
  70. package/dist/src/core/geminiChat.js +106 -29
  71. package/dist/src/core/geminiChat.js.map +1 -1
  72. package/dist/src/core/geminiChat.test.js +317 -16
  73. package/dist/src/core/geminiChat.test.js.map +1 -1
  74. package/dist/src/core/logger.d.ts +7 -2
  75. package/dist/src/core/logger.js +15 -9
  76. package/dist/src/core/logger.js.map +1 -1
  77. package/dist/src/core/logger.test.js +31 -16
  78. package/dist/src/core/logger.test.js.map +1 -1
  79. package/dist/src/core/loggingContentGenerator.test.d.ts +6 -0
  80. package/dist/src/core/loggingContentGenerator.test.js +180 -0
  81. package/dist/src/core/loggingContentGenerator.test.js.map +1 -0
  82. package/dist/src/core/nonInteractiveToolExecutor.test.js +1 -0
  83. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  84. package/dist/src/core/prompts.js +8 -11
  85. package/dist/src/core/prompts.js.map +1 -1
  86. package/dist/src/core/tokenLimits.test.d.ts +6 -0
  87. package/dist/src/core/tokenLimits.test.js +26 -0
  88. package/dist/src/core/tokenLimits.test.js.map +1 -0
  89. package/dist/src/fallback/handler.js +52 -7
  90. package/dist/src/fallback/handler.js.map +1 -1
  91. package/dist/src/fallback/handler.test.js +69 -16
  92. package/dist/src/fallback/handler.test.js.map +1 -1
  93. package/dist/src/fallback/types.d.ts +1 -1
  94. package/dist/src/generated/git-commit.d.ts +2 -2
  95. package/dist/src/generated/git-commit.js +2 -2
  96. package/dist/src/hooks/hookAggregator.d.ts +68 -0
  97. package/dist/src/hooks/hookAggregator.js +262 -0
  98. package/dist/src/hooks/hookAggregator.js.map +1 -0
  99. package/dist/src/hooks/hookAggregator.test.d.ts +6 -0
  100. package/dist/src/hooks/hookAggregator.test.js +387 -0
  101. package/dist/src/hooks/hookAggregator.test.js.map +1 -0
  102. package/dist/src/hooks/hookRunner.d.ts +42 -0
  103. package/dist/src/hooks/hookRunner.js +272 -0
  104. package/dist/src/hooks/hookRunner.js.map +1 -0
  105. package/dist/src/hooks/hookRunner.test.d.ts +6 -0
  106. package/dist/src/hooks/hookRunner.test.js +468 -0
  107. package/dist/src/hooks/hookRunner.test.js.map +1 -0
  108. package/dist/src/hooks/hookTranslator.d.ts +3 -3
  109. package/dist/src/hooks/types.js +1 -1
  110. package/dist/src/hooks/types.js.map +1 -1
  111. package/dist/src/hooks/types.test.js +280 -2
  112. package/dist/src/hooks/types.test.js.map +1 -1
  113. package/dist/src/ide/detect-ide.d.ts +4 -0
  114. package/dist/src/ide/detect-ide.js +6 -1
  115. package/dist/src/ide/detect-ide.js.map +1 -1
  116. package/dist/src/ide/detect-ide.test.js +5 -0
  117. package/dist/src/ide/detect-ide.test.js.map +1 -1
  118. package/dist/src/ide/ide-client.d.ts +3 -1
  119. package/dist/src/ide/ide-client.js +9 -8
  120. package/dist/src/ide/ide-client.js.map +1 -1
  121. package/dist/src/ide/ide-client.test.js +159 -0
  122. package/dist/src/ide/ide-client.test.js.map +1 -1
  123. package/dist/src/ide/ide-installer.js +65 -20
  124. package/dist/src/ide/ide-installer.js.map +1 -1
  125. package/dist/src/ide/ide-installer.test.js +41 -0
  126. package/dist/src/ide/ide-installer.test.js.map +1 -1
  127. package/dist/src/ide/types.d.ts +1 -1
  128. package/dist/src/ide/types.js +1 -1
  129. package/dist/src/index.d.ts +2 -0
  130. package/dist/src/index.js +2 -0
  131. package/dist/src/index.js.map +1 -1
  132. package/dist/src/mcp/google-auth-provider.js +1 -1
  133. package/dist/src/mcp/google-auth-provider.js.map +1 -1
  134. package/dist/src/mcp/mcpLauncher.js +6 -2
  135. package/dist/src/mcp/mcpLauncher.js.map +1 -1
  136. package/dist/src/mcp/oauth-provider.js +2 -2
  137. package/dist/src/mcp/oauth-provider.js.map +1 -1
  138. package/dist/src/mcp/oauth-provider.test.js +177 -0
  139. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  140. package/dist/src/mcp/sa-impersonation-provider.js +1 -1
  141. package/dist/src/mcp/sa-impersonation-provider.js.map +1 -1
  142. package/dist/src/policy/config.js +3 -1
  143. package/dist/src/policy/config.js.map +1 -1
  144. package/dist/src/policy/config.test.js +135 -1
  145. package/dist/src/policy/config.test.js.map +1 -1
  146. package/dist/src/policy/policies/discovered.toml +8 -0
  147. package/dist/src/policy/policies/write.toml +10 -0
  148. package/dist/src/policy/policy-engine.d.ts +12 -3
  149. package/dist/src/policy/policy-engine.js +71 -9
  150. package/dist/src/policy/policy-engine.js.map +1 -1
  151. package/dist/src/policy/policy-engine.test.js +460 -76
  152. package/dist/src/policy/policy-engine.test.js.map +1 -1
  153. package/dist/src/policy/toml-loader.d.ts +2 -1
  154. package/dist/src/policy/toml-loader.js +103 -6
  155. package/dist/src/policy/toml-loader.js.map +1 -1
  156. package/dist/src/policy/toml-loader.test.js +222 -368
  157. package/dist/src/policy/toml-loader.test.js.map +1 -1
  158. package/dist/src/policy/types.d.ts +65 -0
  159. package/dist/src/policy/types.js +4 -0
  160. package/dist/src/policy/types.js.map +1 -1
  161. package/dist/src/prompts/mcp-prompts.test.d.ts +6 -0
  162. package/dist/src/prompts/mcp-prompts.test.js +40 -0
  163. package/dist/src/prompts/mcp-prompts.test.js.map +1 -0
  164. package/dist/src/prompts/prompt-registry.test.d.ts +6 -0
  165. package/dist/src/prompts/prompt-registry.test.js +111 -0
  166. package/dist/src/prompts/prompt-registry.test.js.map +1 -0
  167. package/dist/src/routing/modelRouterService.js +15 -0
  168. package/dist/src/routing/modelRouterService.js.map +1 -1
  169. package/dist/src/routing/modelRouterService.test.js +62 -0
  170. package/dist/src/routing/modelRouterService.test.js.map +1 -1
  171. package/dist/src/routing/strategies/classifierStrategy.d.ts +1 -1
  172. package/dist/src/routing/strategies/classifierStrategy.js +6 -14
  173. package/dist/src/routing/strategies/classifierStrategy.js.map +1 -1
  174. package/dist/src/routing/strategies/classifierStrategy.test.js +13 -10
  175. package/dist/src/routing/strategies/classifierStrategy.test.js.map +1 -1
  176. package/dist/src/routing/strategies/fallbackStrategy.js +1 -1
  177. package/dist/src/routing/strategies/fallbackStrategy.js.map +1 -1
  178. package/dist/src/routing/strategies/fallbackStrategy.test.js +4 -0
  179. package/dist/src/routing/strategies/fallbackStrategy.test.js.map +1 -1
  180. package/dist/src/routing/strategies/overrideStrategy.js +2 -2
  181. package/dist/src/routing/strategies/overrideStrategy.js.map +1 -1
  182. package/dist/src/routing/strategies/overrideStrategy.test.js +3 -0
  183. package/dist/src/routing/strategies/overrideStrategy.test.js.map +1 -1
  184. package/dist/src/safety/built-in.d.ts +21 -0
  185. package/dist/src/safety/built-in.js +106 -0
  186. package/dist/src/safety/built-in.js.map +1 -0
  187. package/dist/src/safety/built-in.test.d.ts +6 -0
  188. package/dist/src/safety/built-in.test.js +199 -0
  189. package/dist/src/safety/built-in.test.js.map +1 -0
  190. package/dist/src/safety/checker-runner.d.ts +48 -0
  191. package/dist/src/safety/checker-runner.js +208 -0
  192. package/dist/src/safety/checker-runner.js.map +1 -0
  193. package/dist/src/safety/checker-runner.test.d.ts +6 -0
  194. package/dist/src/safety/checker-runner.test.js +238 -0
  195. package/dist/src/safety/checker-runner.test.js.map +1 -0
  196. package/dist/src/safety/context-builder.d.ts +23 -0
  197. package/dist/src/safety/context-builder.js +47 -0
  198. package/dist/src/safety/context-builder.js.map +1 -0
  199. package/dist/src/safety/context-builder.test.d.ts +6 -0
  200. package/dist/src/safety/context-builder.test.js +49 -0
  201. package/dist/src/safety/context-builder.test.js.map +1 -0
  202. package/dist/src/safety/protocol.d.ts +88 -0
  203. package/dist/src/safety/protocol.js +15 -0
  204. package/dist/src/safety/protocol.js.map +1 -0
  205. package/dist/src/safety/registry.d.ts +26 -0
  206. package/dist/src/safety/registry.js +65 -0
  207. package/dist/src/safety/registry.js.map +1 -0
  208. package/dist/src/safety/registry.test.d.ts +6 -0
  209. package/dist/src/safety/registry.test.js +31 -0
  210. package/dist/src/safety/registry.test.js.map +1 -0
  211. package/dist/src/services/chatCompressionService.test.js +1 -0
  212. package/dist/src/services/chatCompressionService.test.js.map +1 -1
  213. package/dist/src/services/gitService.js +1 -1
  214. package/dist/src/services/gitService.js.map +1 -1
  215. package/dist/src/services/gitService.test.js +1 -1
  216. package/dist/src/services/gitService.test.js.map +1 -1
  217. package/dist/src/services/loopDetectionService.d.ts +3 -0
  218. package/dist/src/services/loopDetectionService.js +81 -42
  219. package/dist/src/services/loopDetectionService.js.map +1 -1
  220. package/dist/src/services/loopDetectionService.test.js +101 -1
  221. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  222. package/dist/src/services/modelConfig.golden.test.d.ts +6 -0
  223. package/dist/src/services/modelConfig.golden.test.js +42 -0
  224. package/dist/src/services/modelConfig.golden.test.js.map +1 -0
  225. package/dist/src/services/modelConfig.integration.test.d.ts +6 -0
  226. package/dist/src/services/modelConfig.integration.test.js +213 -0
  227. package/dist/src/services/modelConfig.integration.test.js.map +1 -0
  228. package/dist/src/services/modelConfigService.d.ts +46 -0
  229. package/dist/src/services/modelConfigService.js +146 -0
  230. package/dist/src/services/modelConfigService.js.map +1 -0
  231. package/dist/src/services/modelConfigService.test.d.ts +6 -0
  232. package/dist/src/services/modelConfigService.test.js +509 -0
  233. package/dist/src/services/modelConfigService.test.js.map +1 -0
  234. package/dist/src/services/test-data/resolved-aliases.golden.json +169 -0
  235. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +11 -9
  236. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +174 -150
  237. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  238. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +1 -0
  239. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +76 -20
  240. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  241. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +6 -1
  242. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +18 -5
  243. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  244. package/dist/src/telemetry/index.d.ts +2 -2
  245. package/dist/src/telemetry/index.js +2 -2
  246. package/dist/src/telemetry/index.js.map +1 -1
  247. package/dist/src/telemetry/loggers.d.ts +7 -7
  248. package/dist/src/telemetry/loggers.js +23 -23
  249. package/dist/src/telemetry/loggers.js.map +1 -1
  250. package/dist/src/telemetry/loggers.test.circular.js +0 -1
  251. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  252. package/dist/src/telemetry/loggers.test.js +72 -18
  253. package/dist/src/telemetry/loggers.test.js.map +1 -1
  254. package/dist/src/telemetry/metrics.d.ts +8 -4
  255. package/dist/src/telemetry/metrics.js +10 -4
  256. package/dist/src/telemetry/metrics.js.map +1 -1
  257. package/dist/src/telemetry/metrics.test.js +42 -0
  258. package/dist/src/telemetry/metrics.test.js.map +1 -1
  259. package/dist/src/telemetry/telemetryAttributes.js +1 -0
  260. package/dist/src/telemetry/telemetryAttributes.js.map +1 -1
  261. package/dist/src/telemetry/types.d.ts +17 -11
  262. package/dist/src/telemetry/types.js +53 -28
  263. package/dist/src/telemetry/types.js.map +1 -1
  264. package/dist/src/tools/base-tool-invocation.test.d.ts +6 -0
  265. package/dist/src/tools/base-tool-invocation.test.js +85 -0
  266. package/dist/src/tools/base-tool-invocation.test.js.map +1 -0
  267. package/dist/src/tools/edit.d.ts +1 -1
  268. package/dist/src/tools/edit.js +31 -33
  269. package/dist/src/tools/edit.js.map +1 -1
  270. package/dist/src/tools/edit.test.js +31 -20
  271. package/dist/src/tools/edit.test.js.map +1 -1
  272. package/dist/src/tools/glob.d.ts +1 -1
  273. package/dist/src/tools/glob.js +7 -7
  274. package/dist/src/tools/glob.js.map +1 -1
  275. package/dist/src/tools/glob.test.js +20 -17
  276. package/dist/src/tools/glob.test.js.map +1 -1
  277. package/dist/src/tools/grep.d.ts +1 -1
  278. package/dist/src/tools/grep.js +9 -9
  279. package/dist/src/tools/grep.js.map +1 -1
  280. package/dist/src/tools/grep.test.js +15 -12
  281. package/dist/src/tools/grep.test.js.map +1 -1
  282. package/dist/src/tools/ls.d.ts +1 -1
  283. package/dist/src/tools/ls.js +14 -15
  284. package/dist/src/tools/ls.js.map +1 -1
  285. package/dist/src/tools/ls.test.js +32 -33
  286. package/dist/src/tools/ls.test.js.map +1 -1
  287. package/dist/src/tools/mcp-client.js +24 -52
  288. package/dist/src/tools/mcp-client.js.map +1 -1
  289. package/dist/src/tools/mcp-client.test.js +18 -0
  290. package/dist/src/tools/mcp-client.test.js.map +1 -1
  291. package/dist/src/tools/mcp-tool.d.ts +1 -0
  292. package/dist/src/tools/mcp-tool.js +5 -2
  293. package/dist/src/tools/mcp-tool.js.map +1 -1
  294. package/dist/src/tools/memoryTool.js +1 -1
  295. package/dist/src/tools/memoryTool.js.map +1 -1
  296. package/dist/src/tools/memoryTool.test.js +1 -1
  297. package/dist/src/tools/memoryTool.test.js.map +1 -1
  298. package/dist/src/tools/modifiable-tool.d.ts +5 -1
  299. package/dist/src/tools/modifiable-tool.js +34 -13
  300. package/dist/src/tools/modifiable-tool.js.map +1 -1
  301. package/dist/src/tools/modifiable-tool.test.js +56 -22
  302. package/dist/src/tools/modifiable-tool.test.js.map +1 -1
  303. package/dist/src/tools/read-file.d.ts +2 -2
  304. package/dist/src/tools/read-file.js +20 -24
  305. package/dist/src/tools/read-file.js.map +1 -1
  306. package/dist/src/tools/read-file.test.js +63 -51
  307. package/dist/src/tools/read-file.test.js.map +1 -1
  308. package/dist/src/tools/read-many-files.d.ts +2 -9
  309. package/dist/src/tools/read-many-files.js +10 -21
  310. package/dist/src/tools/read-many-files.js.map +1 -1
  311. package/dist/src/tools/read-many-files.test.js +37 -35
  312. package/dist/src/tools/read-many-files.test.js.map +1 -1
  313. package/dist/src/tools/ripGrep.d.ts +25 -8
  314. package/dist/src/tools/ripGrep.js +148 -176
  315. package/dist/src/tools/ripGrep.js.map +1 -1
  316. package/dist/src/tools/ripGrep.test.js +383 -58
  317. package/dist/src/tools/ripGrep.test.js.map +1 -1
  318. package/dist/src/tools/shell.d.ts +1 -1
  319. package/dist/src/tools/shell.js +17 -15
  320. package/dist/src/tools/shell.js.map +1 -1
  321. package/dist/src/tools/shell.test.js +66 -36
  322. package/dist/src/tools/shell.test.js.map +1 -1
  323. package/dist/src/tools/smart-edit.d.ts +6 -1
  324. package/dist/src/tools/smart-edit.js +18 -17
  325. package/dist/src/tools/smart-edit.js.map +1 -1
  326. package/dist/src/tools/smart-edit.test.js +49 -24
  327. package/dist/src/tools/smart-edit.test.js.map +1 -1
  328. package/dist/src/tools/tool-registry.d.ts +29 -4
  329. package/dist/src/tools/tool-registry.js +108 -29
  330. package/dist/src/tools/tool-registry.js.map +1 -1
  331. package/dist/src/tools/tool-registry.test.js +134 -4
  332. package/dist/src/tools/tool-registry.test.js.map +1 -1
  333. package/dist/src/tools/tools.d.ts +2 -1
  334. package/dist/src/tools/tools.js +5 -2
  335. package/dist/src/tools/tools.js.map +1 -1
  336. package/dist/src/tools/web-fetch.js +2 -4
  337. package/dist/src/tools/web-fetch.js.map +1 -1
  338. package/dist/src/tools/web-fetch.test.js +11 -4
  339. package/dist/src/tools/web-fetch.test.js.map +1 -1
  340. package/dist/src/tools/web-search.js +1 -2
  341. package/dist/src/tools/web-search.js.map +1 -1
  342. package/dist/src/tools/web-search.test.js +11 -5
  343. package/dist/src/tools/web-search.test.js.map +1 -1
  344. package/dist/src/tools/write-file.js +31 -31
  345. package/dist/src/tools/write-file.js.map +1 -1
  346. package/dist/src/tools/write-file.test.js +24 -5
  347. package/dist/src/tools/write-file.test.js.map +1 -1
  348. package/dist/src/tools/write-todos.d.ts +29 -0
  349. package/dist/src/tools/write-todos.js +34 -1
  350. package/dist/src/tools/write-todos.js.map +1 -1
  351. package/dist/src/utils/editCorrector.js +4 -15
  352. package/dist/src/utils/editCorrector.js.map +1 -1
  353. package/dist/src/utils/editCorrector.test.js +16 -0
  354. package/dist/src/utils/editCorrector.test.js.map +1 -1
  355. package/dist/src/utils/editor.d.ts +3 -1
  356. package/dist/src/utils/editor.js +18 -1
  357. package/dist/src/utils/editor.js.map +1 -1
  358. package/dist/src/utils/editor.test.js +11 -0
  359. package/dist/src/utils/editor.test.js.map +1 -1
  360. package/dist/src/utils/environmentContext.js +3 -1
  361. package/dist/src/utils/environmentContext.js.map +1 -1
  362. package/dist/src/utils/environmentContext.test.js +6 -0
  363. package/dist/src/utils/environmentContext.test.js.map +1 -1
  364. package/dist/src/utils/events.d.ts +14 -11
  365. package/dist/src/utils/events.js +1 -14
  366. package/dist/src/utils/events.js.map +1 -1
  367. package/dist/src/utils/extensionLoader.d.ts +8 -0
  368. package/dist/src/utils/extensionLoader.js +61 -15
  369. package/dist/src/utils/extensionLoader.js.map +1 -1
  370. package/dist/src/utils/extensionLoader.test.js +83 -19
  371. package/dist/src/utils/extensionLoader.test.js.map +1 -1
  372. package/dist/src/utils/fileUtils.test.js +75 -60
  373. package/dist/src/utils/fileUtils.test.js.map +1 -1
  374. package/dist/src/utils/flashFallback.test.js +2 -2
  375. package/dist/src/utils/flashFallback.test.js.map +1 -1
  376. package/dist/src/utils/googleQuotaErrors.d.ts +2 -1
  377. package/dist/src/utils/googleQuotaErrors.js +20 -12
  378. package/dist/src/utils/googleQuotaErrors.js.map +1 -1
  379. package/dist/src/utils/httpErrors.d.ts +18 -0
  380. package/dist/src/utils/httpErrors.js +36 -0
  381. package/dist/src/utils/httpErrors.js.map +1 -0
  382. package/dist/src/utils/llm-edit-fixer.js +1 -2
  383. package/dist/src/utils/llm-edit-fixer.js.map +1 -1
  384. package/dist/src/utils/llm-edit-fixer.test.js +16 -1
  385. package/dist/src/utils/llm-edit-fixer.test.js.map +1 -1
  386. package/dist/src/utils/memoryDiscovery.d.ts +8 -0
  387. package/dist/src/utils/memoryDiscovery.js +24 -0
  388. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  389. package/dist/src/utils/memoryDiscovery.test.js +43 -1
  390. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  391. package/dist/src/utils/nextSpeakerChecker.js +1 -2
  392. package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
  393. package/dist/src/utils/nextSpeakerChecker.test.js +10 -4
  394. package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
  395. package/dist/src/utils/pathReader.js +4 -4
  396. package/dist/src/utils/pathReader.js.map +1 -1
  397. package/dist/src/utils/pathReader.test.js +44 -1
  398. package/dist/src/utils/pathReader.test.js.map +1 -1
  399. package/dist/src/utils/paths.d.ts +1 -1
  400. package/dist/src/utils/paths.js +5 -3
  401. package/dist/src/utils/paths.js.map +1 -1
  402. package/dist/src/utils/retry.d.ts +0 -9
  403. package/dist/src/utils/retry.js +24 -28
  404. package/dist/src/utils/retry.js.map +1 -1
  405. package/dist/src/utils/retry.test.js +51 -0
  406. package/dist/src/utils/retry.test.js.map +1 -1
  407. package/dist/src/utils/shell-utils.js +5 -3
  408. package/dist/src/utils/shell-utils.js.map +1 -1
  409. package/dist/src/utils/shell-utils.test.js +9 -9
  410. package/dist/src/utils/shell-utils.test.js.map +1 -1
  411. package/dist/src/utils/summarizer.d.ts +4 -2
  412. package/dist/src/utils/summarizer.js +6 -8
  413. package/dist/src/utils/summarizer.js.map +1 -1
  414. package/dist/src/utils/summarizer.test.js +32 -11
  415. package/dist/src/utils/summarizer.test.js.map +1 -1
  416. package/dist/src/utils/workspaceContext.d.ts +4 -3
  417. package/dist/src/utils/workspaceContext.js +10 -11
  418. package/dist/src/utils/workspaceContext.js.map +1 -1
  419. package/dist/src/utils/workspaceContext.test.js +1 -1
  420. package/dist/src/utils/workspaceContext.test.js.map +1 -1
  421. package/dist/tsconfig.tsbuildinfo +1 -1
  422. package/package.json +1 -1
@@ -7,7 +7,7 @@ import { describe, it, expect, beforeEach, afterEach, afterAll, vi, } from 'vite
7
7
  import { canUseRipgrep, RipGrepTool, ensureRgPath } from './ripGrep.js';
8
8
  import path from 'node:path';
9
9
  import fs from 'node:fs/promises';
10
- import os, { EOL } from 'node:os';
10
+ import os from 'node:os';
11
11
  import { Storage } from '../config/storage.js';
12
12
  import { createMockWorkspaceContext } from '../test-utils/mockWorkspaceContext.js';
13
13
  import { spawn } from 'node:child_process';
@@ -215,19 +215,19 @@ describe('RipGrepTool', () => {
215
215
  expect(grepTool.validateToolParams(params)).toBeNull();
216
216
  });
217
217
  it('should return null for valid params (pattern and path)', () => {
218
- const params = { pattern: 'hello', path: '.' };
218
+ const params = { pattern: 'hello', dir_path: '.' };
219
219
  expect(grepTool.validateToolParams(params)).toBeNull();
220
220
  });
221
221
  it('should return null for valid params (pattern, path, and include)', () => {
222
222
  const params = {
223
223
  pattern: 'hello',
224
- path: '.',
224
+ dir_path: '.',
225
225
  include: '*.txt',
226
226
  };
227
227
  expect(grepTool.validateToolParams(params)).toBeNull();
228
228
  });
229
229
  it('should return error if pattern is missing', () => {
230
- const params = { path: '.' };
230
+ const params = { dir_path: '.' };
231
231
  expect(grepTool.validateToolParams(params)).toBe(`params must have required property 'pattern'`);
232
232
  });
233
233
  it('should return null for what would be an invalid regex pattern', () => {
@@ -237,28 +237,57 @@ describe('RipGrepTool', () => {
237
237
  it('should return error if path does not exist', () => {
238
238
  const params = {
239
239
  pattern: 'hello',
240
- path: 'nonexistent',
240
+ dir_path: 'nonexistent',
241
241
  };
242
242
  // Check for the core error message, as the full path might vary
243
- expect(grepTool.validateToolParams(params)).toContain('Failed to access path stats for');
243
+ expect(grepTool.validateToolParams(params)).toContain('Path does not exist');
244
244
  expect(grepTool.validateToolParams(params)).toContain('nonexistent');
245
245
  });
246
- it('should return error if path is a file, not a directory', async () => {
246
+ it('should allow path to be a file', async () => {
247
247
  const filePath = path.join(tempRootDir, 'fileA.txt');
248
- const params = { pattern: 'hello', path: filePath };
249
- expect(grepTool.validateToolParams(params)).toContain(`Path is not a directory: ${filePath}`);
248
+ const params = {
249
+ pattern: 'hello',
250
+ dir_path: filePath,
251
+ };
252
+ expect(grepTool.validateToolParams(params)).toBeNull();
250
253
  });
251
254
  });
252
255
  describe('execute', () => {
253
256
  it('should find matches for a simple pattern in all files', async () => {
254
257
  mockSpawn.mockImplementationOnce(createMockSpawn({
255
- outputData: `fileA.txt:1:hello world${EOL}fileA.txt:2:second line with world${EOL}sub/fileC.txt:1:another world in sub dir${EOL}`,
258
+ outputData: JSON.stringify({
259
+ type: 'match',
260
+ data: {
261
+ path: { text: 'fileA.txt' },
262
+ line_number: 1,
263
+ lines: { text: 'hello world\n' },
264
+ },
265
+ }) +
266
+ '\n' +
267
+ JSON.stringify({
268
+ type: 'match',
269
+ data: {
270
+ path: { text: 'fileA.txt' },
271
+ line_number: 2,
272
+ lines: { text: 'second line with world\n' },
273
+ },
274
+ }) +
275
+ '\n' +
276
+ JSON.stringify({
277
+ type: 'match',
278
+ data: {
279
+ path: { text: 'sub/fileC.txt' },
280
+ line_number: 1,
281
+ lines: { text: 'another world in sub dir\n' },
282
+ },
283
+ }) +
284
+ '\n',
256
285
  exitCode: 0,
257
286
  }));
258
287
  const params = { pattern: 'world' };
259
288
  const invocation = grepTool.build(params);
260
289
  const result = await invocation.execute(abortSignal);
261
- expect(result.llmContent).toContain('Found 3 matches for pattern "world" in the workspace directory');
290
+ expect(result.llmContent).toContain('Found 3 matches for pattern "world" in path "."');
262
291
  expect(result.llmContent).toContain('File: fileA.txt');
263
292
  expect(result.llmContent).toContain('L1: hello world');
264
293
  expect(result.llmContent).toContain('L2: second line with world');
@@ -269,10 +298,17 @@ describe('RipGrepTool', () => {
269
298
  it('should find matches in a specific path', async () => {
270
299
  // Setup specific mock for this test - searching in 'sub' should only return matches from that directory
271
300
  mockSpawn.mockImplementationOnce(createMockSpawn({
272
- outputData: `fileC.txt:1:another world in sub dir${EOL}`,
301
+ outputData: JSON.stringify({
302
+ type: 'match',
303
+ data: {
304
+ path: { text: 'fileC.txt' },
305
+ line_number: 1,
306
+ lines: { text: 'another world in sub dir\n' },
307
+ },
308
+ }) + '\n',
273
309
  exitCode: 0,
274
310
  }));
275
- const params = { pattern: 'world', path: 'sub' };
311
+ const params = { pattern: 'world', dir_path: 'sub' };
276
312
  const invocation = grepTool.build(params);
277
313
  const result = await invocation.execute(abortSignal);
278
314
  expect(result.llmContent).toContain('Found 1 match for pattern "world" in path "sub"');
@@ -283,13 +319,20 @@ describe('RipGrepTool', () => {
283
319
  it('should find matches with an include glob', async () => {
284
320
  // Setup specific mock for this test
285
321
  mockSpawn.mockImplementationOnce(createMockSpawn({
286
- outputData: `fileB.js:2:function baz() { return "hello"; }${EOL}`,
322
+ outputData: JSON.stringify({
323
+ type: 'match',
324
+ data: {
325
+ path: { text: 'fileB.js' },
326
+ line_number: 2,
327
+ lines: { text: 'function baz() { return "hello"; }\n' },
328
+ },
329
+ }) + '\n',
287
330
  exitCode: 0,
288
331
  }));
289
332
  const params = { pattern: 'hello', include: '*.js' };
290
333
  const invocation = grepTool.build(params);
291
334
  const result = await invocation.execute(abortSignal);
292
- expect(result.llmContent).toContain('Found 1 match for pattern "hello" in the workspace directory (filter: "*.js"):');
335
+ expect(result.llmContent).toContain('Found 1 match for pattern "hello" in path "." (filter: "*.js"):');
293
336
  expect(result.llmContent).toContain('File: fileB.js');
294
337
  expect(result.llmContent).toContain('L2: function baz() { return "hello"; }');
295
338
  expect(result.returnDisplay).toBe('Found 1 match');
@@ -316,7 +359,14 @@ describe('RipGrepTool', () => {
316
359
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
317
360
  if (onData) {
318
361
  // Only return match from the .js file in sub directory
319
- onData(Buffer.from(`another.js:1:const greeting = "hello";${EOL}`));
362
+ onData(Buffer.from(JSON.stringify({
363
+ type: 'match',
364
+ data: {
365
+ path: { text: 'another.js' },
366
+ line_number: 1,
367
+ lines: { text: 'const greeting = "hello";\n' },
368
+ },
369
+ }) + '\n'));
320
370
  }
321
371
  if (onClose) {
322
372
  onClose(0);
@@ -326,7 +376,7 @@ describe('RipGrepTool', () => {
326
376
  });
327
377
  const params = {
328
378
  pattern: 'hello',
329
- path: 'sub',
379
+ dir_path: 'sub',
330
380
  include: '*.js',
331
381
  };
332
382
  const invocation = grepTool.build(params);
@@ -344,7 +394,7 @@ describe('RipGrepTool', () => {
344
394
  const params = { pattern: 'nonexistentpattern' };
345
395
  const invocation = grepTool.build(params);
346
396
  const result = await invocation.execute(abortSignal);
347
- expect(result.llmContent).toContain('No matches found for pattern "nonexistentpattern" in the workspace directory.');
397
+ expect(result.llmContent).toContain('No matches found for pattern "nonexistentpattern" in path ".".');
348
398
  expect(result.returnDisplay).toBe('No matches found');
349
399
  });
350
400
  it('should return an error from ripgrep for invalid regex pattern', async () => {
@@ -378,7 +428,14 @@ describe('RipGrepTool', () => {
378
428
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
379
429
  if (onData) {
380
430
  // Return match for the regex pattern
381
- onData(Buffer.from(`fileB.js:1:const foo = "bar";${EOL}`));
431
+ onData(Buffer.from(JSON.stringify({
432
+ type: 'match',
433
+ data: {
434
+ path: { text: 'fileB.js' },
435
+ line_number: 1,
436
+ lines: { text: 'const foo = "bar";\n' },
437
+ },
438
+ }) + '\n'));
382
439
  }
383
440
  if (onClose) {
384
441
  onClose(0);
@@ -389,7 +446,7 @@ describe('RipGrepTool', () => {
389
446
  const params = { pattern: 'foo.*bar' }; // Matches 'const foo = "bar";'
390
447
  const invocation = grepTool.build(params);
391
448
  const result = await invocation.execute(abortSignal);
392
- expect(result.llmContent).toContain('Found 1 match for pattern "foo.*bar" in the workspace directory:');
449
+ expect(result.llmContent).toContain('Found 1 match for pattern "foo.*bar" in path ".":');
393
450
  expect(result.llmContent).toContain('File: fileB.js');
394
451
  expect(result.llmContent).toContain('L1: const foo = "bar";');
395
452
  });
@@ -414,7 +471,24 @@ describe('RipGrepTool', () => {
414
471
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
415
472
  if (onData) {
416
473
  // Return case-insensitive matches for 'HELLO'
417
- onData(Buffer.from(`fileA.txt:1:hello world${EOL}fileB.js:2:function baz() { return "hello"; }${EOL}`));
474
+ onData(Buffer.from(JSON.stringify({
475
+ type: 'match',
476
+ data: {
477
+ path: { text: 'fileA.txt' },
478
+ line_number: 1,
479
+ lines: { text: 'hello world\n' },
480
+ },
481
+ }) +
482
+ '\n' +
483
+ JSON.stringify({
484
+ type: 'match',
485
+ data: {
486
+ path: { text: 'fileB.js' },
487
+ line_number: 2,
488
+ lines: { text: 'function baz() { return "hello"; }\n' },
489
+ },
490
+ }) +
491
+ '\n'));
418
492
  }
419
493
  if (onClose) {
420
494
  onClose(0);
@@ -425,14 +499,14 @@ describe('RipGrepTool', () => {
425
499
  const params = { pattern: 'HELLO' };
426
500
  const invocation = grepTool.build(params);
427
501
  const result = await invocation.execute(abortSignal);
428
- expect(result.llmContent).toContain('Found 2 matches for pattern "HELLO" in the workspace directory:');
502
+ expect(result.llmContent).toContain('Found 2 matches for pattern "HELLO" in path ".":');
429
503
  expect(result.llmContent).toContain('File: fileA.txt');
430
504
  expect(result.llmContent).toContain('L1: hello world');
431
505
  expect(result.llmContent).toContain('File: fileB.js');
432
506
  expect(result.llmContent).toContain('L2: function baz() { return "hello"; }');
433
507
  });
434
508
  it('should throw an error if params are invalid', async () => {
435
- const params = { path: '.' }; // Invalid: pattern missing
509
+ const params = { dir_path: '.' }; // Invalid: pattern missing
436
510
  expect(() => grepTool.build(params)).toThrow(/params must have required property 'pattern'/);
437
511
  });
438
512
  it('should throw an error if ripgrep is not available', async () => {
@@ -447,7 +521,7 @@ describe('RipGrepTool', () => {
447
521
  });
448
522
  });
449
523
  describe('multi-directory workspace', () => {
450
- it('should search across all workspace directories when no path is specified', async () => {
524
+ it('should search only CWD when no path is specified (default behavior)', async () => {
451
525
  // Create additional directory with test files
452
526
  const secondDir = await fs.mkdtemp(path.join(os.tmpdir(), 'grep-tool-second-'));
453
527
  await fs.writeFile(path.join(secondDir, 'other.txt'), 'hello from second directory\nworld in second');
@@ -483,19 +557,55 @@ describe('RipGrepTool', () => {
483
557
  if (callCount === 1) {
484
558
  // First directory (tempRootDir)
485
559
  outputData =
486
- [
487
- 'fileA.txt:1:hello world',
488
- 'fileA.txt:2:second line with world',
489
- 'sub/fileC.txt:1:another world in sub dir',
490
- ].join(EOL) + EOL;
560
+ JSON.stringify({
561
+ type: 'match',
562
+ data: {
563
+ path: { text: 'fileA.txt' },
564
+ line_number: 1,
565
+ lines: { text: 'hello world\n' },
566
+ },
567
+ }) +
568
+ '\n' +
569
+ JSON.stringify({
570
+ type: 'match',
571
+ data: {
572
+ path: { text: 'fileA.txt' },
573
+ line_number: 2,
574
+ lines: { text: 'second line with world\n' },
575
+ },
576
+ }) +
577
+ '\n' +
578
+ JSON.stringify({
579
+ type: 'match',
580
+ data: {
581
+ path: { text: 'sub/fileC.txt' },
582
+ line_number: 1,
583
+ lines: { text: 'another world in sub dir\n' },
584
+ },
585
+ }) +
586
+ '\n';
491
587
  }
492
588
  else if (callCount === 2) {
493
589
  // Second directory (secondDir)
494
590
  outputData =
495
- [
496
- 'other.txt:2:world in second',
497
- 'another.js:1:function world() { return "test"; }',
498
- ].join(EOL) + EOL;
591
+ JSON.stringify({
592
+ type: 'match',
593
+ data: {
594
+ path: { text: 'other.txt' },
595
+ line_number: 2,
596
+ lines: { text: 'world in second\n' },
597
+ },
598
+ }) +
599
+ '\n' +
600
+ JSON.stringify({
601
+ type: 'match',
602
+ data: {
603
+ path: { text: 'another.js' },
604
+ line_number: 1,
605
+ lines: { text: 'function world() { return "test"; }\n' },
606
+ },
607
+ }) +
608
+ '\n';
499
609
  }
500
610
  if (stdoutDataHandler && outputData) {
501
611
  stdoutDataHandler(Buffer.from(outputData));
@@ -510,19 +620,19 @@ describe('RipGrepTool', () => {
510
620
  const params = { pattern: 'world' };
511
621
  const invocation = multiDirGrepTool.build(params);
512
622
  const result = await invocation.execute(abortSignal);
513
- // Should find matches in both directories
514
- expect(result.llmContent).toContain('Found 5 matches for pattern "world"');
623
+ // Should find matches in CWD only (default behavior now)
624
+ expect(result.llmContent).toContain('Found 3 matches for pattern "world" in path "."');
515
625
  // Matches from first directory
516
626
  expect(result.llmContent).toContain('fileA.txt');
517
627
  expect(result.llmContent).toContain('L1: hello world');
518
628
  expect(result.llmContent).toContain('L2: second line with world');
519
629
  expect(result.llmContent).toContain('fileC.txt');
520
630
  expect(result.llmContent).toContain('L1: another world in sub dir');
521
- // Matches from both directories
522
- expect(result.llmContent).toContain('other.txt');
523
- expect(result.llmContent).toContain('L2: world in second');
524
- expect(result.llmContent).toContain('another.js');
525
- expect(result.llmContent).toContain('L1: function world()');
631
+ // Should NOT find matches from second directory
632
+ expect(result.llmContent).not.toContain('other.txt');
633
+ expect(result.llmContent).not.toContain('world in second');
634
+ expect(result.llmContent).not.toContain('another.js');
635
+ expect(result.llmContent).not.toContain('function world()');
526
636
  // Clean up
527
637
  await fs.rm(secondDir, { recursive: true, force: true });
528
638
  mockSpawn.mockClear();
@@ -557,7 +667,14 @@ describe('RipGrepTool', () => {
557
667
  const onData = mockProcess.stdout.on.mock.calls.find((call) => call[0] === 'data')?.[1];
558
668
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
559
669
  if (onData) {
560
- onData(Buffer.from(`fileC.txt:1:another world in sub dir${EOL}`));
670
+ onData(Buffer.from(JSON.stringify({
671
+ type: 'match',
672
+ data: {
673
+ path: { text: 'fileC.txt' },
674
+ line_number: 1,
675
+ lines: { text: 'another world in sub dir\n' },
676
+ },
677
+ }) + '\n'));
561
678
  }
562
679
  if (onClose) {
563
680
  onClose(0);
@@ -567,7 +684,7 @@ describe('RipGrepTool', () => {
567
684
  });
568
685
  const multiDirGrepTool = new RipGrepTool(multiDirConfig);
569
686
  // Search only in the 'sub' directory of the first workspace
570
- const params = { pattern: 'world', path: 'sub' };
687
+ const params = { pattern: 'world', dir_path: 'sub' };
571
688
  const invocation = multiDirGrepTool.build(params);
572
689
  const result = await invocation.execute(abortSignal);
573
690
  // Should only find matches in the specified sub directory
@@ -627,7 +744,10 @@ describe('RipGrepTool', () => {
627
744
  });
628
745
  describe('error handling and edge cases', () => {
629
746
  it('should handle workspace boundary violations', () => {
630
- const params = { pattern: 'test', path: '../outside' };
747
+ const params = {
748
+ pattern: 'test',
749
+ dir_path: '../outside',
750
+ };
631
751
  expect(() => grepTool.build(params)).toThrow(/Path validation failed/);
632
752
  });
633
753
  it('should handle empty directories gracefully', async () => {
@@ -656,7 +776,7 @@ describe('RipGrepTool', () => {
656
776
  }, 0);
657
777
  return mockProcess;
658
778
  });
659
- const params = { pattern: 'test', path: 'empty' };
779
+ const params = { pattern: 'test', dir_path: 'empty' };
660
780
  const invocation = grepTool.build(params);
661
781
  const result = await invocation.execute(abortSignal);
662
782
  expect(result.llmContent).toContain('No matches found');
@@ -714,7 +834,14 @@ describe('RipGrepTool', () => {
714
834
  const onData = mockProcess.stdout.on.mock.calls.find((call) => call[0] === 'data')?.[1];
715
835
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
716
836
  if (onData) {
717
- onData(Buffer.from(`${specialFileName}:1:hello world with special chars${EOL}`));
837
+ onData(Buffer.from(JSON.stringify({
838
+ type: 'match',
839
+ data: {
840
+ path: { text: specialFileName },
841
+ line_number: 1,
842
+ lines: { text: 'hello world with special chars\n' },
843
+ },
844
+ }) + '\n'));
718
845
  }
719
846
  if (onClose) {
720
847
  onClose(0);
@@ -751,7 +878,14 @@ describe('RipGrepTool', () => {
751
878
  const onData = mockProcess.stdout.on.mock.calls.find((call) => call[0] === 'data')?.[1];
752
879
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
753
880
  if (onData) {
754
- onData(Buffer.from(`a/b/c/d/e/deep.txt:1:content in deep directory${EOL}`));
881
+ onData(Buffer.from(JSON.stringify({
882
+ type: 'match',
883
+ data: {
884
+ path: { text: 'a/b/c/d/e/deep.txt' },
885
+ line_number: 1,
886
+ lines: { text: 'content in deep directory\n' },
887
+ },
888
+ }) + '\n'));
755
889
  }
756
890
  if (onClose) {
757
891
  onClose(0);
@@ -788,7 +922,14 @@ describe('RipGrepTool', () => {
788
922
  const onData = mockProcess.stdout.on.mock.calls.find((call) => call[0] === 'data')?.[1];
789
923
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
790
924
  if (onData) {
791
- onData(Buffer.from(`code.js:1:function getName() { return "test"; }${EOL}`));
925
+ onData(Buffer.from(JSON.stringify({
926
+ type: 'match',
927
+ data: {
928
+ path: { text: 'code.js' },
929
+ line_number: 1,
930
+ lines: { text: 'function getName() { return "test"; }\n' },
931
+ },
932
+ }) + '\n'));
792
933
  }
793
934
  if (onClose) {
794
935
  onClose(0);
@@ -823,7 +964,33 @@ describe('RipGrepTool', () => {
823
964
  const onData = mockProcess.stdout.on.mock.calls.find((call) => call[0] === 'data')?.[1];
824
965
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
825
966
  if (onData) {
826
- onData(Buffer.from(`case.txt:1:Hello World${EOL}case.txt:2:hello world${EOL}case.txt:3:HELLO WORLD${EOL}`));
967
+ onData(Buffer.from(JSON.stringify({
968
+ type: 'match',
969
+ data: {
970
+ path: { text: 'case.txt' },
971
+ line_number: 1,
972
+ lines: { text: 'Hello World\n' },
973
+ },
974
+ }) +
975
+ '\n' +
976
+ JSON.stringify({
977
+ type: 'match',
978
+ data: {
979
+ path: { text: 'case.txt' },
980
+ line_number: 2,
981
+ lines: { text: 'hello world\n' },
982
+ },
983
+ }) +
984
+ '\n' +
985
+ JSON.stringify({
986
+ type: 'match',
987
+ data: {
988
+ path: { text: 'case.txt' },
989
+ line_number: 3,
990
+ lines: { text: 'HELLO WORLD\n' },
991
+ },
992
+ }) +
993
+ '\n'));
827
994
  }
828
995
  if (onClose) {
829
996
  onClose(0);
@@ -859,7 +1026,14 @@ describe('RipGrepTool', () => {
859
1026
  const onData = mockProcess.stdout.on.mock.calls.find((call) => call[0] === 'data')?.[1];
860
1027
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
861
1028
  if (onData) {
862
- onData(Buffer.from(`special.txt:1:Price: $19.99${EOL}`));
1029
+ onData(Buffer.from(JSON.stringify({
1030
+ type: 'match',
1031
+ data: {
1032
+ path: { text: 'special.txt' },
1033
+ line_number: 1,
1034
+ lines: { text: 'Price: $19.99\n' },
1035
+ },
1036
+ }) + '\n'));
863
1037
  }
864
1038
  if (onClose) {
865
1039
  onClose(0);
@@ -899,7 +1073,24 @@ describe('RipGrepTool', () => {
899
1073
  const onData = mockProcess.stdout.on.mock.calls.find((call) => call[0] === 'data')?.[1];
900
1074
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
901
1075
  if (onData) {
902
- onData(Buffer.from(`test.ts:1:typescript content${EOL}test.tsx:1:tsx content${EOL}`));
1076
+ onData(Buffer.from(JSON.stringify({
1077
+ type: 'match',
1078
+ data: {
1079
+ path: { text: 'test.ts' },
1080
+ line_number: 1,
1081
+ lines: { text: 'typescript content\n' },
1082
+ },
1083
+ }) +
1084
+ '\n' +
1085
+ JSON.stringify({
1086
+ type: 'match',
1087
+ data: {
1088
+ path: { text: 'test.tsx' },
1089
+ line_number: 1,
1090
+ lines: { text: 'tsx content\n' },
1091
+ },
1092
+ }) +
1093
+ '\n'));
903
1094
  }
904
1095
  if (onClose) {
905
1096
  onClose(0);
@@ -941,7 +1132,14 @@ describe('RipGrepTool', () => {
941
1132
  const onData = mockProcess.stdout.on.mock.calls.find((call) => call[0] === 'data')?.[1];
942
1133
  const onClose = mockProcess.on.mock.calls.find((call) => call[0] === 'close')?.[1];
943
1134
  if (onData) {
944
- onData(Buffer.from(`src/main.ts:1:source code${EOL}`));
1135
+ onData(Buffer.from(JSON.stringify({
1136
+ type: 'match',
1137
+ data: {
1138
+ path: { text: 'src/main.ts' },
1139
+ line_number: 1,
1140
+ lines: { text: 'source code\n' },
1141
+ },
1142
+ }) + '\n'));
945
1143
  }
946
1144
  if (onClose) {
947
1145
  onClose(0);
@@ -959,11 +1157,135 @@ describe('RipGrepTool', () => {
959
1157
  expect(result.llmContent).not.toContain('other.ts');
960
1158
  });
961
1159
  });
1160
+ describe('advanced search options', () => {
1161
+ it('should handle case_sensitive parameter', async () => {
1162
+ // Case-insensitive search (default)
1163
+ mockSpawn.mockImplementationOnce(createMockSpawn({
1164
+ outputData: JSON.stringify({
1165
+ type: 'match',
1166
+ data: {
1167
+ path: { text: 'fileA.txt' },
1168
+ line_number: 1,
1169
+ lines: { text: 'hello world\n' },
1170
+ },
1171
+ }) + '\n',
1172
+ exitCode: 0,
1173
+ }));
1174
+ let params = { pattern: 'HELLO' };
1175
+ let invocation = grepTool.build(params);
1176
+ let result = await invocation.execute(abortSignal);
1177
+ expect(mockSpawn).toHaveBeenLastCalledWith(expect.anything(), expect.arrayContaining(['--ignore-case']), expect.anything());
1178
+ expect(result.llmContent).toContain('Found 1 match for pattern "HELLO"');
1179
+ expect(result.llmContent).toContain('L1: hello world');
1180
+ // Case-sensitive search
1181
+ mockSpawn.mockImplementationOnce(createMockSpawn({
1182
+ outputData: JSON.stringify({
1183
+ type: 'match',
1184
+ data: {
1185
+ path: { text: 'fileA.txt' },
1186
+ line_number: 1,
1187
+ lines: { text: 'HELLO world\n' },
1188
+ },
1189
+ }) + '\n',
1190
+ exitCode: 0,
1191
+ }));
1192
+ params = { pattern: 'HELLO', case_sensitive: true };
1193
+ invocation = grepTool.build(params);
1194
+ result = await invocation.execute(abortSignal);
1195
+ expect(mockSpawn).toHaveBeenLastCalledWith(expect.anything(), expect.not.arrayContaining(['--ignore-case']), expect.anything());
1196
+ expect(result.llmContent).toContain('Found 1 match for pattern "HELLO"');
1197
+ expect(result.llmContent).toContain('L1: HELLO world');
1198
+ });
1199
+ it('should handle fixed_strings parameter', async () => {
1200
+ mockSpawn.mockImplementationOnce(createMockSpawn({
1201
+ outputData: JSON.stringify({
1202
+ type: 'match',
1203
+ data: {
1204
+ path: { text: 'fileA.txt' },
1205
+ line_number: 1,
1206
+ lines: { text: 'hello.world\n' },
1207
+ },
1208
+ }) + '\n',
1209
+ exitCode: 0,
1210
+ }));
1211
+ const params = {
1212
+ pattern: 'hello.world',
1213
+ fixed_strings: true,
1214
+ };
1215
+ const invocation = grepTool.build(params);
1216
+ const result = await invocation.execute(abortSignal);
1217
+ expect(mockSpawn).toHaveBeenLastCalledWith(expect.anything(), expect.arrayContaining(['--fixed-strings']), expect.anything());
1218
+ expect(result.llmContent).toContain('Found 1 match for pattern "hello.world"');
1219
+ expect(result.llmContent).toContain('L1: hello.world');
1220
+ });
1221
+ it('should handle no_ignore parameter', async () => {
1222
+ mockSpawn.mockImplementationOnce(createMockSpawn({
1223
+ outputData: JSON.stringify({
1224
+ type: 'match',
1225
+ data: {
1226
+ path: { text: 'ignored.log' },
1227
+ line_number: 1,
1228
+ lines: { text: 'secret log entry\n' },
1229
+ },
1230
+ }) + '\n',
1231
+ exitCode: 0,
1232
+ }));
1233
+ const params = { pattern: 'secret', no_ignore: true };
1234
+ const invocation = grepTool.build(params);
1235
+ const result = await invocation.execute(abortSignal);
1236
+ // Should have --no-ignore
1237
+ expect(mockSpawn).toHaveBeenLastCalledWith(expect.anything(), expect.arrayContaining(['--no-ignore']), expect.anything());
1238
+ // Should NOT have default excludes when no_ignore is true
1239
+ expect(mockSpawn).toHaveBeenLastCalledWith(expect.anything(), expect.not.arrayContaining(['--glob', '!node_modules']), expect.anything());
1240
+ expect(result.llmContent).toContain('Found 1 match for pattern "secret"');
1241
+ expect(result.llmContent).toContain('File: ignored.log');
1242
+ expect(result.llmContent).toContain('L1: secret log entry');
1243
+ });
1244
+ it('should handle context parameters', async () => {
1245
+ mockSpawn.mockImplementationOnce(createMockSpawn({
1246
+ outputData: JSON.stringify({
1247
+ type: 'match',
1248
+ data: {
1249
+ path: { text: 'fileA.txt' },
1250
+ line_number: 2,
1251
+ lines: { text: 'second line with world\n' },
1252
+ lines_before: [{ text: 'hello world\n' }],
1253
+ lines_after: [
1254
+ { text: 'third line\n' },
1255
+ { text: 'fourth line\n' },
1256
+ ],
1257
+ },
1258
+ }) + '\n',
1259
+ exitCode: 0,
1260
+ }));
1261
+ const params = {
1262
+ pattern: 'world',
1263
+ context: 1,
1264
+ after: 2,
1265
+ before: 1,
1266
+ };
1267
+ const invocation = grepTool.build(params);
1268
+ const result = await invocation.execute(abortSignal);
1269
+ expect(mockSpawn).toHaveBeenLastCalledWith(expect.anything(), expect.arrayContaining([
1270
+ '--context',
1271
+ '1',
1272
+ '--after-context',
1273
+ '2',
1274
+ '--before-context',
1275
+ '1',
1276
+ ]), expect.anything());
1277
+ expect(result.llmContent).toContain('Found 1 match for pattern "world"');
1278
+ expect(result.llmContent).toContain('File: fileA.txt');
1279
+ expect(result.llmContent).toContain('L2: second line with world');
1280
+ // Note: Ripgrep JSON output for context lines doesn't include line numbers for context lines directly
1281
+ // The current parsing only extracts the matched line, so we only assert on that.
1282
+ });
1283
+ });
962
1284
  describe('getDescription', () => {
963
1285
  it('should generate correct description with pattern only', () => {
964
1286
  const params = { pattern: 'testPattern' };
965
1287
  const invocation = grepTool.build(params);
966
- expect(invocation.getDescription()).toBe("'testPattern'");
1288
+ expect(invocation.getDescription()).toBe("'testPattern' within ./");
967
1289
  });
968
1290
  it('should generate correct description with pattern and include', () => {
969
1291
  const params = {
@@ -971,21 +1293,21 @@ describe('RipGrepTool', () => {
971
1293
  include: '*.ts',
972
1294
  };
973
1295
  const invocation = grepTool.build(params);
974
- expect(invocation.getDescription()).toBe("'testPattern' in *.ts");
1296
+ expect(invocation.getDescription()).toBe("'testPattern' in *.ts within ./");
975
1297
  });
976
1298
  it('should generate correct description with pattern and path', async () => {
977
1299
  const dirPath = path.join(tempRootDir, 'src', 'app');
978
1300
  await fs.mkdir(dirPath, { recursive: true });
979
1301
  const params = {
980
1302
  pattern: 'testPattern',
981
- path: path.join('src', 'app'),
1303
+ dir_path: path.join('src', 'app'),
982
1304
  };
983
1305
  const invocation = grepTool.build(params);
984
1306
  // The path will be relative to the tempRootDir, so we check for containment.
985
1307
  expect(invocation.getDescription()).toContain("'testPattern' within");
986
1308
  expect(invocation.getDescription()).toContain(path.join('src', 'app'));
987
1309
  });
988
- it('should indicate searching across all workspace directories when no path specified', () => {
1310
+ it('should use ./ when no path is specified (defaults to CWD)', () => {
989
1311
  // Create a mock config with multiple directories
990
1312
  const multiDirConfig = {
991
1313
  getTargetDir: () => tempRootDir,
@@ -995,7 +1317,7 @@ describe('RipGrepTool', () => {
995
1317
  const multiDirGrepTool = new RipGrepTool(multiDirConfig);
996
1318
  const params = { pattern: 'testPattern' };
997
1319
  const invocation = multiDirGrepTool.build(params);
998
- expect(invocation.getDescription()).toBe("'testPattern' across all workspace directories");
1320
+ expect(invocation.getDescription()).toBe("'testPattern' within ./");
999
1321
  });
1000
1322
  it('should generate correct description with pattern, include, and path', async () => {
1001
1323
  const dirPath = path.join(tempRootDir, 'src', 'app');
@@ -1003,14 +1325,17 @@ describe('RipGrepTool', () => {
1003
1325
  const params = {
1004
1326
  pattern: 'testPattern',
1005
1327
  include: '*.ts',
1006
- path: path.join('src', 'app'),
1328
+ dir_path: path.join('src', 'app'),
1007
1329
  };
1008
1330
  const invocation = grepTool.build(params);
1009
1331
  expect(invocation.getDescription()).toContain("'testPattern' in *.ts within");
1010
1332
  expect(invocation.getDescription()).toContain(path.join('src', 'app'));
1011
1333
  });
1012
1334
  it('should use ./ for root path in description', () => {
1013
- const params = { pattern: 'testPattern', path: '.' };
1335
+ const params = {
1336
+ pattern: 'testPattern',
1337
+ dir_path: '.',
1338
+ };
1014
1339
  const invocation = grepTool.build(params);
1015
1340
  expect(invocation.getDescription()).toBe("'testPattern' within ./");
1016
1341
  });