@machina.ai/cell-cli-core 1.0.13-rc9 → 1.0.21-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 (484) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.js +3 -0
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +12 -4
  5. package/dist/src/code_assist/converter.d.ts +6 -3
  6. package/dist/src/code_assist/converter.js +4 -2
  7. package/dist/src/code_assist/converter.js.map +1 -1
  8. package/dist/src/code_assist/converter.test.js +61 -11
  9. package/dist/src/code_assist/converter.test.js.map +1 -1
  10. package/dist/src/code_assist/oauth2.d.ts +1 -0
  11. package/dist/src/code_assist/oauth2.js +43 -18
  12. package/dist/src/code_assist/oauth2.js.map +1 -1
  13. package/dist/src/code_assist/oauth2.test.js +142 -9
  14. package/dist/src/code_assist/oauth2.test.js.map +1 -1
  15. package/dist/src/code_assist/server.d.ts +2 -2
  16. package/dist/src/code_assist/server.js +5 -5
  17. package/dist/src/code_assist/server.js.map +1 -1
  18. package/dist/src/code_assist/server.test.js +13 -10
  19. package/dist/src/code_assist/server.test.js.map +1 -1
  20. package/dist/src/code_assist/setup.js +49 -18
  21. package/dist/src/code_assist/setup.js.map +1 -1
  22. package/dist/src/code_assist/setup.test.js +115 -9
  23. package/dist/src/code_assist/setup.test.js.map +1 -1
  24. package/dist/src/config/config.d.ts +71 -13
  25. package/dist/src/config/config.js +154 -41
  26. package/dist/src/config/config.js.map +1 -1
  27. package/dist/src/config/config.test.js +206 -21
  28. package/dist/src/config/config.test.js.map +1 -1
  29. package/dist/src/config/flashFallback.test.js +19 -47
  30. package/dist/src/config/flashFallback.test.js.map +1 -1
  31. package/dist/src/config/models.d.ts +1 -0
  32. package/dist/src/config/models.js +1 -0
  33. package/dist/src/config/models.js.map +1 -1
  34. package/dist/src/core/client.d.ts +15 -16
  35. package/dist/src/core/client.js +247 -104
  36. package/dist/src/core/client.js.map +1 -1
  37. package/dist/src/core/client.test.js +798 -49
  38. package/dist/src/core/client.test.js.map +1 -1
  39. package/dist/src/core/contentGenerator.d.ts +2 -2
  40. package/dist/src/core/contentGenerator.js +23 -21
  41. package/dist/src/core/contentGenerator.js.map +1 -1
  42. package/dist/src/core/contentGenerator.test.js +30 -126
  43. package/dist/src/core/contentGenerator.test.js.map +1 -1
  44. package/dist/src/core/coreToolScheduler.d.ts +23 -10
  45. package/dist/src/core/coreToolScheduler.js +201 -77
  46. package/dist/src/core/coreToolScheduler.js.map +1 -1
  47. package/dist/src/core/coreToolScheduler.test.js +322 -94
  48. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  49. package/dist/src/core/geminiChat.d.ts +8 -6
  50. package/dist/src/core/geminiChat.js +49 -51
  51. package/dist/src/core/geminiChat.js.map +1 -1
  52. package/dist/src/core/geminiChat.test.js +2 -2
  53. package/dist/src/core/geminiChat.test.js.map +1 -1
  54. package/dist/src/core/geminiRequest.js +2 -37
  55. package/dist/src/core/geminiRequest.js.map +1 -1
  56. package/dist/src/core/logger.d.ts +24 -1
  57. package/dist/src/core/logger.js +128 -4
  58. package/dist/src/core/logger.js.map +1 -1
  59. package/dist/src/core/logger.test.js +157 -11
  60. package/dist/src/core/logger.test.js.map +1 -1
  61. package/dist/src/core/loggingContentGenerator.d.ts +25 -0
  62. package/dist/src/core/loggingContentGenerator.js +95 -0
  63. package/dist/src/core/loggingContentGenerator.js.map +1 -0
  64. package/dist/src/core/nonInteractiveToolExecutor.js +39 -4
  65. package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
  66. package/dist/src/core/nonInteractiveToolExecutor.test.js +85 -62
  67. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  68. package/dist/src/core/prompts.js +43 -19
  69. package/dist/src/core/prompts.js.map +1 -1
  70. package/dist/src/core/prompts.test.js +118 -1
  71. package/dist/src/core/prompts.test.js.map +1 -1
  72. package/dist/src/core/subagent.d.ts +230 -0
  73. package/dist/src/core/subagent.js +447 -0
  74. package/dist/src/core/subagent.js.map +1 -0
  75. package/dist/src/core/subagent.test.js +515 -0
  76. package/dist/src/core/subagent.test.js.map +1 -0
  77. package/dist/src/core/tokenLimits.js +1 -0
  78. package/dist/src/core/tokenLimits.js.map +1 -1
  79. package/dist/src/core/turn.d.ts +3 -0
  80. package/dist/src/core/turn.js +4 -0
  81. package/dist/src/core/turn.js.map +1 -1
  82. package/dist/src/core/turn.test.js +4 -0
  83. package/dist/src/core/turn.test.js.map +1 -1
  84. package/dist/src/generated/git-commit.d.ts +7 -0
  85. package/dist/src/generated/git-commit.js +10 -0
  86. package/dist/src/generated/git-commit.js.map +1 -0
  87. package/dist/src/ide/constants.d.ts +6 -0
  88. package/dist/src/ide/constants.js +7 -0
  89. package/dist/src/ide/constants.js.map +1 -0
  90. package/dist/src/ide/detect-ide.d.ts +20 -0
  91. package/dist/src/ide/detect-ide.js +86 -0
  92. package/dist/src/ide/detect-ide.js.map +1 -0
  93. package/dist/src/ide/detect-ide.test.js +65 -0
  94. package/dist/src/ide/detect-ide.test.js.map +1 -0
  95. package/dist/src/ide/ide-client.d.ts +63 -0
  96. package/dist/src/ide/ide-client.js +320 -0
  97. package/dist/src/ide/ide-client.js.map +1 -0
  98. package/dist/src/ide/ide-client.test.d.ts +6 -0
  99. package/dist/src/ide/ide-client.test.js +43 -0
  100. package/dist/src/ide/ide-client.test.js.map +1 -0
  101. package/dist/src/ide/ide-installer.d.ts +14 -0
  102. package/dist/src/ide/ide-installer.js +98 -0
  103. package/dist/src/ide/ide-installer.js.map +1 -0
  104. package/dist/src/ide/ide-installer.test.d.ts +6 -0
  105. package/dist/src/ide/ide-installer.test.js +53 -0
  106. package/dist/src/ide/ide-installer.test.js.map +1 -0
  107. package/dist/src/ide/ideContext.d.ts +374 -0
  108. package/dist/src/ide/ideContext.js +147 -0
  109. package/dist/src/ide/ideContext.js.map +1 -0
  110. package/dist/src/ide/ideContext.test.d.ts +6 -0
  111. package/dist/src/ide/ideContext.test.js +265 -0
  112. package/dist/src/ide/ideContext.test.js.map +1 -0
  113. package/dist/src/ide/process-utils.d.ts +14 -0
  114. package/dist/src/ide/process-utils.js +57 -0
  115. package/dist/src/ide/process-utils.js.map +1 -0
  116. package/dist/src/index.d.ts +17 -1
  117. package/dist/src/index.js +20 -1
  118. package/dist/src/index.js.map +1 -1
  119. package/dist/src/mcp/google-auth-provider.d.ts +23 -0
  120. package/dist/src/mcp/google-auth-provider.js +72 -0
  121. package/dist/src/mcp/google-auth-provider.js.map +1 -0
  122. package/dist/src/mcp/google-auth-provider.test.d.ts +6 -0
  123. package/dist/src/mcp/google-auth-provider.test.js +89 -0
  124. package/dist/src/mcp/google-auth-provider.test.js.map +1 -0
  125. package/dist/src/mcp/oauth-provider.d.ts +6 -2
  126. package/dist/src/mcp/oauth-provider.js +208 -53
  127. package/dist/src/mcp/oauth-provider.js.map +1 -1
  128. package/dist/src/mcp/oauth-provider.test.js +222 -70
  129. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  130. package/dist/src/mcp/oauth-token-storage.d.ts +3 -1
  131. package/dist/src/mcp/oauth-token-storage.js +3 -1
  132. package/dist/src/mcp/oauth-token-storage.js.map +1 -1
  133. package/dist/src/mcp/oauth-utils.d.ts +3 -1
  134. package/dist/src/mcp/oauth-utils.js +52 -14
  135. package/dist/src/mcp/oauth-utils.js.map +1 -1
  136. package/dist/src/mcp/oauth-utils.test.js +18 -3
  137. package/dist/src/mcp/oauth-utils.test.js.map +1 -1
  138. package/dist/src/mocks/msw.d.ts +6 -0
  139. package/dist/src/mocks/msw.js +8 -0
  140. package/dist/src/mocks/msw.js.map +1 -0
  141. package/dist/src/prompts/mcp-prompts.d.ts +8 -0
  142. package/dist/src/prompts/mcp-prompts.js +13 -0
  143. package/dist/src/prompts/mcp-prompts.js.map +1 -0
  144. package/dist/src/prompts/prompt-registry.d.ts +34 -0
  145. package/dist/src/prompts/prompt-registry.js +63 -0
  146. package/dist/src/prompts/prompt-registry.js.map +1 -0
  147. package/dist/src/services/chatRecordingService.d.ts +150 -0
  148. package/dist/src/services/chatRecordingService.js +318 -0
  149. package/dist/src/services/chatRecordingService.js.map +1 -0
  150. package/dist/src/services/chatRecordingService.test.d.ts +6 -0
  151. package/dist/src/services/chatRecordingService.test.js +288 -0
  152. package/dist/src/services/chatRecordingService.test.js.map +1 -0
  153. package/dist/src/services/fileDiscoveryService.test.js +101 -60
  154. package/dist/src/services/fileDiscoveryService.test.js.map +1 -1
  155. package/dist/src/services/fileSystemService.d.ts +31 -0
  156. package/dist/src/services/fileSystemService.js +18 -0
  157. package/dist/src/services/fileSystemService.js.map +1 -0
  158. package/dist/src/services/fileSystemService.test.d.ts +6 -0
  159. package/dist/src/services/fileSystemService.test.js +41 -0
  160. package/dist/src/services/fileSystemService.test.js.map +1 -0
  161. package/dist/src/services/gitService.test.js +67 -86
  162. package/dist/src/services/gitService.test.js.map +1 -1
  163. package/dist/src/services/loopDetectionService.d.ts +51 -5
  164. package/dist/src/services/loopDetectionService.js +152 -45
  165. package/dist/src/services/loopDetectionService.js.map +1 -1
  166. package/dist/src/services/loopDetectionService.test.js +286 -89
  167. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  168. package/dist/src/services/shellExecutionService.d.ts +70 -0
  169. package/dist/src/services/shellExecutionService.js +175 -0
  170. package/dist/src/services/shellExecutionService.js.map +1 -0
  171. package/dist/src/services/shellExecutionService.test.d.ts +6 -0
  172. package/dist/src/services/shellExecutionService.test.js +282 -0
  173. package/dist/src/services/shellExecutionService.test.js.map +1 -0
  174. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +81 -9
  175. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +356 -182
  176. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  177. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +17 -0
  178. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +342 -0
  179. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -0
  180. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +19 -2
  181. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +51 -9
  182. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  183. package/dist/src/telemetry/constants.d.ts +4 -0
  184. package/dist/src/telemetry/constants.js +4 -0
  185. package/dist/src/telemetry/constants.js.map +1 -1
  186. package/dist/src/telemetry/file-exporters.d.ts +28 -0
  187. package/dist/src/telemetry/file-exporters.js +62 -0
  188. package/dist/src/telemetry/file-exporters.js.map +1 -0
  189. package/dist/src/telemetry/index.d.ts +2 -2
  190. package/dist/src/telemetry/index.js +2 -2
  191. package/dist/src/telemetry/index.js.map +1 -1
  192. package/dist/src/telemetry/integration.test.circular.js +1 -0
  193. package/dist/src/telemetry/integration.test.circular.js.map +1 -1
  194. package/dist/src/telemetry/loggers.d.ts +6 -1
  195. package/dist/src/telemetry/loggers.js +87 -6
  196. package/dist/src/telemetry/loggers.js.map +1 -1
  197. package/dist/src/telemetry/loggers.test.circular.js +9 -2
  198. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  199. package/dist/src/telemetry/loggers.test.js +51 -11
  200. package/dist/src/telemetry/loggers.test.js.map +1 -1
  201. package/dist/src/telemetry/metrics.d.ts +7 -2
  202. package/dist/src/telemetry/metrics.js +26 -6
  203. package/dist/src/telemetry/metrics.js.map +1 -1
  204. package/dist/src/telemetry/metrics.test.js +81 -1
  205. package/dist/src/telemetry/metrics.test.js.map +1 -1
  206. package/dist/src/telemetry/sdk.d.ts +1 -1
  207. package/dist/src/telemetry/sdk.js +77 -30
  208. package/dist/src/telemetry/sdk.js.map +1 -1
  209. package/dist/src/telemetry/sdk.test.d.ts +6 -0
  210. package/dist/src/telemetry/sdk.test.js +82 -0
  211. package/dist/src/telemetry/sdk.test.js.map +1 -0
  212. package/dist/src/telemetry/telemetry.test.js +2 -2
  213. package/dist/src/telemetry/telemetry.test.js.map +1 -1
  214. package/dist/src/telemetry/tool-call-decision.d.ts +13 -0
  215. package/dist/src/telemetry/tool-call-decision.js +29 -0
  216. package/dist/src/telemetry/tool-call-decision.js.map +1 -0
  217. package/dist/src/telemetry/types.d.ts +74 -18
  218. package/dist/src/telemetry/types.js +110 -32
  219. package/dist/src/telemetry/types.js.map +1 -1
  220. package/dist/src/telemetry/uiTelemetry.d.ts +8 -1
  221. package/dist/src/telemetry/uiTelemetry.js +17 -2
  222. package/dist/src/telemetry/uiTelemetry.js.map +1 -1
  223. package/dist/src/telemetry/uiTelemetry.test.js +60 -10
  224. package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
  225. package/dist/src/test-utils/config.d.ts +16 -0
  226. package/dist/src/test-utils/config.js +32 -0
  227. package/dist/src/test-utils/config.js.map +1 -0
  228. package/dist/src/test-utils/mockWorkspaceContext.d.ts +13 -0
  229. package/dist/src/test-utils/mockWorkspaceContext.js +24 -0
  230. package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -0
  231. package/dist/src/test-utils/tools.d.ts +44 -0
  232. package/dist/src/test-utils/tools.js +105 -0
  233. package/dist/src/test-utils/tools.js.map +1 -0
  234. package/dist/src/tools/diffOptions.d.ts +2 -0
  235. package/dist/src/tools/diffOptions.js +28 -0
  236. package/dist/src/tools/diffOptions.js.map +1 -1
  237. package/dist/src/tools/diffOptions.test.d.ts +6 -0
  238. package/dist/src/tools/diffOptions.test.js +119 -0
  239. package/dist/src/tools/diffOptions.test.js.map +1 -0
  240. package/dist/src/tools/edit.d.ts +10 -34
  241. package/dist/src/tools/edit.js +171 -131
  242. package/dist/src/tools/edit.js.map +1 -1
  243. package/dist/src/tools/edit.test.js +220 -43
  244. package/dist/src/tools/edit.test.js.map +1 -1
  245. package/dist/src/tools/glob.d.ts +4 -11
  246. package/dist/src/tools/glob.js +129 -97
  247. package/dist/src/tools/glob.js.map +1 -1
  248. package/dist/src/tools/glob.test.js +73 -17
  249. package/dist/src/tools/glob.test.js.map +1 -1
  250. package/dist/src/tools/grep.d.ts +5 -37
  251. package/dist/src/tools/grep.js +175 -100
  252. package/dist/src/tools/grep.js.map +1 -1
  253. package/dist/src/tools/grep.test.js +112 -28
  254. package/dist/src/tools/grep.test.js.map +1 -1
  255. package/dist/src/tools/ls.d.ts +4 -23
  256. package/dist/src/tools/ls.js +77 -78
  257. package/dist/src/tools/ls.js.map +1 -1
  258. package/dist/src/tools/ls.test.d.ts +6 -0
  259. package/dist/src/tools/ls.test.js +384 -0
  260. package/dist/src/tools/ls.test.js.map +1 -0
  261. package/dist/src/tools/mcp-client-manager.d.ts +38 -0
  262. package/dist/src/tools/mcp-client-manager.js +74 -0
  263. package/dist/src/tools/mcp-client-manager.js.map +1 -0
  264. package/dist/src/tools/mcp-client-manager.test.d.ts +6 -0
  265. package/dist/src/tools/mcp-client-manager.test.js +39 -0
  266. package/dist/src/tools/mcp-client-manager.test.js.map +1 -0
  267. package/dist/src/tools/mcp-client.d.ts +86 -4
  268. package/dist/src/tools/mcp-client.js +730 -59
  269. package/dist/src/tools/mcp-client.js.map +1 -1
  270. package/dist/src/tools/mcp-client.test.js +295 -22
  271. package/dist/src/tools/mcp-client.test.js.map +1 -1
  272. package/dist/src/tools/mcp-tool.d.ts +6 -13
  273. package/dist/src/tools/mcp-tool.js +163 -76
  274. package/dist/src/tools/mcp-tool.js.map +1 -1
  275. package/dist/src/tools/mcp-tool.test.js +400 -29
  276. package/dist/src/tools/mcp-tool.test.js.map +1 -1
  277. package/dist/src/tools/memoryTool.d.ts +14 -3
  278. package/dist/src/tools/memoryTool.js +159 -40
  279. package/dist/src/tools/memoryTool.js.map +1 -1
  280. package/dist/src/tools/memoryTool.test.js +116 -11
  281. package/dist/src/tools/memoryTool.test.js.map +1 -1
  282. package/dist/src/tools/modifiable-tool.d.ts +9 -6
  283. package/dist/src/tools/modifiable-tool.js +6 -3
  284. package/dist/src/tools/modifiable-tool.js.map +1 -1
  285. package/dist/src/tools/modifiable-tool.test.js +63 -74
  286. package/dist/src/tools/modifiable-tool.test.js.map +1 -1
  287. package/dist/src/tools/read-file.d.ts +4 -6
  288. package/dist/src/tools/read-file.js +100 -53
  289. package/dist/src/tools/read-file.js.map +1 -1
  290. package/dist/src/tools/read-file.test.js +238 -111
  291. package/dist/src/tools/read-file.test.js.map +1 -1
  292. package/dist/src/tools/read-many-files.d.ts +3 -6
  293. package/dist/src/tools/read-many-files.js +232 -157
  294. package/dist/src/tools/read-many-files.js.map +1 -1
  295. package/dist/src/tools/read-many-files.test.js +231 -34
  296. package/dist/src/tools/read-many-files.test.js.map +1 -1
  297. package/dist/src/tools/shell.d.ts +6 -28
  298. package/dist/src/tools/shell.js +249 -366
  299. package/dist/src/tools/shell.js.map +1 -1
  300. package/dist/src/tools/shell.test.js +305 -384
  301. package/dist/src/tools/shell.test.js.map +1 -1
  302. package/dist/src/tools/tool-error.d.ts +27 -0
  303. package/dist/src/tools/tool-error.js +32 -0
  304. package/dist/src/tools/tool-error.js.map +1 -0
  305. package/dist/src/tools/tool-registry.d.ts +38 -23
  306. package/dist/src/tools/tool-registry.js +127 -99
  307. package/dist/src/tools/tool-registry.js.map +1 -1
  308. package/dist/src/tools/tool-registry.test.js +37 -212
  309. package/dist/src/tools/tool-registry.test.js.map +1 -1
  310. package/dist/src/tools/tools.d.ts +145 -92
  311. package/dist/src/tools/tools.js +188 -61
  312. package/dist/src/tools/tools.js.map +1 -1
  313. package/dist/src/tools/tools.test.d.ts +6 -0
  314. package/dist/src/tools/tools.test.js +206 -0
  315. package/dist/src/tools/tools.test.js.map +1 -0
  316. package/dist/src/tools/web-fetch.d.ts +4 -7
  317. package/dist/src/tools/web-fetch.js +58 -64
  318. package/dist/src/tools/web-fetch.js.map +1 -1
  319. package/dist/src/tools/web-fetch.test.js +8 -4
  320. package/dist/src/tools/web-fetch.test.js.map +1 -1
  321. package/dist/src/tools/web-search.d.ts +4 -5
  322. package/dist/src/tools/web-search.js +47 -51
  323. package/dist/src/tools/web-search.js.map +1 -1
  324. package/dist/src/tools/web-search.test.d.ts +6 -0
  325. package/dist/src/tools/web-search.test.js +139 -0
  326. package/dist/src/tools/web-search.test.js.map +1 -0
  327. package/dist/src/tools/write-file.d.ts +20 -11
  328. package/dist/src/tools/write-file.js +198 -141
  329. package/dist/src/tools/write-file.js.map +1 -1
  330. package/dist/src/tools/write-file.test.js +190 -76
  331. package/dist/src/tools/write-file.test.js.map +1 -1
  332. package/dist/src/utils/bfsFileSearch.js +51 -27
  333. package/dist/src/utils/bfsFileSearch.js.map +1 -1
  334. package/dist/src/utils/bfsFileSearch.test.js +137 -136
  335. package/dist/src/utils/bfsFileSearch.test.js.map +1 -1
  336. package/dist/src/utils/browser.js +4 -3
  337. package/dist/src/utils/browser.js.map +1 -1
  338. package/dist/src/utils/editCorrector.js +23 -24
  339. package/dist/src/utils/editCorrector.js.map +1 -1
  340. package/dist/src/utils/editor.d.ts +2 -2
  341. package/dist/src/utils/editor.js +23 -6
  342. package/dist/src/utils/editor.js.map +1 -1
  343. package/dist/src/utils/editor.test.js +67 -15
  344. package/dist/src/utils/editor.test.js.map +1 -1
  345. package/dist/src/utils/environmentContext.d.ts +21 -0
  346. package/dist/src/utils/environmentContext.js +90 -0
  347. package/dist/src/utils/environmentContext.js.map +1 -0
  348. package/dist/src/utils/environmentContext.test.d.ts +6 -0
  349. package/dist/src/utils/environmentContext.test.js +140 -0
  350. package/dist/src/utils/environmentContext.test.js.map +1 -0
  351. package/dist/src/utils/errorParsing.d.ts +8 -0
  352. package/dist/src/utils/errorParsing.js +93 -0
  353. package/dist/src/utils/errorParsing.js.map +1 -0
  354. package/dist/src/utils/errorParsing.test.d.ts +6 -0
  355. package/dist/src/utils/errorParsing.test.js +172 -0
  356. package/dist/src/utils/errorParsing.test.js.map +1 -0
  357. package/dist/src/utils/errorReporting.d.ts +1 -1
  358. package/dist/src/utils/errorReporting.js +2 -2
  359. package/dist/src/utils/errorReporting.js.map +1 -1
  360. package/dist/src/utils/errorReporting.test.js +44 -38
  361. package/dist/src/utils/errorReporting.test.js.map +1 -1
  362. package/dist/src/utils/fileUtils.d.ts +9 -1
  363. package/dist/src/utils/fileUtils.js +27 -13
  364. package/dist/src/utils/fileUtils.js.map +1 -1
  365. package/dist/src/utils/fileUtils.test.js +61 -18
  366. package/dist/src/utils/fileUtils.test.js.map +1 -1
  367. package/dist/src/utils/filesearch/crawlCache.d.ts +25 -0
  368. package/dist/src/utils/filesearch/crawlCache.js +57 -0
  369. package/dist/src/utils/filesearch/crawlCache.js.map +1 -0
  370. package/dist/src/utils/filesearch/crawlCache.test.d.ts +6 -0
  371. package/dist/src/utils/filesearch/crawlCache.test.js +103 -0
  372. package/dist/src/utils/filesearch/crawlCache.test.js.map +1 -0
  373. package/dist/src/utils/filesearch/crawler.d.ts +15 -0
  374. package/dist/src/utils/filesearch/crawler.js +50 -0
  375. package/dist/src/utils/filesearch/crawler.js.map +1 -0
  376. package/dist/src/utils/filesearch/crawler.test.d.ts +6 -0
  377. package/dist/src/utils/filesearch/crawler.test.js +468 -0
  378. package/dist/src/utils/filesearch/crawler.test.js.map +1 -0
  379. package/dist/src/utils/filesearch/fileSearch.d.ts +37 -0
  380. package/dist/src/utils/filesearch/fileSearch.js +186 -0
  381. package/dist/src/utils/filesearch/fileSearch.js.map +1 -0
  382. package/dist/src/utils/filesearch/fileSearch.test.d.ts +6 -0
  383. package/dist/src/utils/filesearch/fileSearch.test.js +552 -0
  384. package/dist/src/utils/filesearch/fileSearch.test.js.map +1 -0
  385. package/dist/src/utils/filesearch/ignore.d.ts +42 -0
  386. package/dist/src/utils/filesearch/ignore.js +106 -0
  387. package/dist/src/utils/filesearch/ignore.js.map +1 -0
  388. package/dist/src/utils/filesearch/ignore.test.d.ts +6 -0
  389. package/dist/src/utils/filesearch/ignore.test.js +144 -0
  390. package/dist/src/utils/filesearch/ignore.test.js.map +1 -0
  391. package/dist/src/utils/filesearch/result-cache.d.ts +33 -0
  392. package/dist/src/utils/filesearch/result-cache.js +59 -0
  393. package/dist/src/utils/filesearch/result-cache.js.map +1 -0
  394. package/dist/src/utils/filesearch/result-cache.test.d.ts +6 -0
  395. package/dist/src/utils/filesearch/result-cache.test.js +46 -0
  396. package/dist/src/utils/filesearch/result-cache.test.js.map +1 -0
  397. package/dist/src/utils/flashFallback.integration.test.js +6 -0
  398. package/dist/src/utils/flashFallback.integration.test.js.map +1 -1
  399. package/dist/src/utils/formatters.d.ts +6 -0
  400. package/dist/src/utils/formatters.js +16 -0
  401. package/dist/src/utils/formatters.js.map +1 -0
  402. package/dist/src/utils/getFolderStructure.test.js +11 -13
  403. package/dist/src/utils/getFolderStructure.test.js.map +1 -1
  404. package/dist/src/utils/gitIgnoreParser.js +5 -11
  405. package/dist/src/utils/gitIgnoreParser.js.map +1 -1
  406. package/dist/src/utils/gitIgnoreParser.test.js +58 -61
  407. package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
  408. package/dist/src/utils/memoryDiscovery.d.ts +1 -1
  409. package/dist/src/utils/memoryDiscovery.js +76 -83
  410. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  411. package/dist/src/utils/memoryDiscovery.test.js +122 -372
  412. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  413. package/dist/src/utils/memoryImportProcessor.d.ts +19 -12
  414. package/dist/src/utils/memoryImportProcessor.js +240 -85
  415. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  416. package/dist/src/utils/memoryImportProcessor.test.js +593 -51
  417. package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
  418. package/dist/src/utils/nextSpeakerChecker.js +4 -25
  419. package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
  420. package/dist/src/utils/partUtils.d.ts +14 -0
  421. package/dist/src/utils/partUtils.js +65 -0
  422. package/dist/src/utils/partUtils.js.map +1 -0
  423. package/dist/src/utils/partUtils.test.d.ts +6 -0
  424. package/dist/src/utils/partUtils.test.js +130 -0
  425. package/dist/src/utils/partUtils.test.js.map +1 -0
  426. package/dist/src/utils/paths.d.ts +18 -2
  427. package/dist/src/utils/paths.js +39 -7
  428. package/dist/src/utils/paths.js.map +1 -1
  429. package/dist/src/utils/paths.test.d.ts +6 -0
  430. package/dist/src/utils/paths.test.js +225 -0
  431. package/dist/src/utils/paths.test.js.map +1 -0
  432. package/dist/src/utils/quotaErrorDetection.d.ts +1 -5
  433. package/dist/src/utils/quotaErrorDetection.js.map +1 -1
  434. package/dist/src/utils/retry.d.ts +3 -0
  435. package/dist/src/utils/retry.js.map +1 -1
  436. package/dist/src/utils/retry.test.js.map +1 -1
  437. package/dist/src/utils/schemaValidator.d.ts +1 -8
  438. package/dist/src/utils/schemaValidator.js +1 -32
  439. package/dist/src/utils/schemaValidator.js.map +1 -1
  440. package/dist/src/utils/secure-browser-launcher.d.ts +23 -0
  441. package/dist/src/utils/secure-browser-launcher.js +165 -0
  442. package/dist/src/utils/secure-browser-launcher.js.map +1 -0
  443. package/dist/src/utils/secure-browser-launcher.test.d.ts +6 -0
  444. package/dist/src/utils/secure-browser-launcher.test.js +149 -0
  445. package/dist/src/utils/secure-browser-launcher.test.js.map +1 -0
  446. package/dist/src/utils/shell-utils.d.ts +117 -0
  447. package/dist/src/utils/shell-utils.js +376 -0
  448. package/dist/src/utils/shell-utils.js.map +1 -0
  449. package/dist/src/utils/shell-utils.test.d.ts +6 -0
  450. package/dist/src/utils/shell-utils.test.js +328 -0
  451. package/dist/src/utils/shell-utils.test.js.map +1 -0
  452. package/dist/src/utils/summarizer.js +3 -32
  453. package/dist/src/utils/summarizer.js.map +1 -1
  454. package/dist/src/utils/systemEncoding.js +1 -1
  455. package/dist/src/utils/systemEncoding.js.map +1 -1
  456. package/dist/src/utils/systemEncoding.test.js +23 -23
  457. package/dist/src/utils/systemEncoding.test.js.map +1 -1
  458. package/dist/src/utils/textUtils.d.ts +13 -0
  459. package/dist/src/utils/textUtils.js +28 -0
  460. package/dist/src/utils/textUtils.js.map +1 -0
  461. package/dist/src/utils/user_account.js +58 -48
  462. package/dist/src/utils/user_account.js.map +1 -1
  463. package/dist/src/utils/user_account.test.js +76 -9
  464. package/dist/src/utils/user_account.test.js.map +1 -1
  465. package/dist/src/utils/workspaceContext.d.ts +66 -0
  466. package/dist/src/utils/workspaceContext.js +165 -0
  467. package/dist/src/utils/workspaceContext.js.map +1 -0
  468. package/dist/src/utils/workspaceContext.test.d.ts +6 -0
  469. package/dist/src/utils/workspaceContext.test.js +293 -0
  470. package/dist/src/utils/workspaceContext.test.js.map +1 -0
  471. package/dist/tsconfig.tsbuildinfo +1 -1
  472. package/package.json +14 -3
  473. package/dist/src/core/geminiRequest.test.js +0 -72
  474. package/dist/src/core/geminiRequest.test.js.map +0 -1
  475. package/dist/src/core/modelCheck.d.ts +0 -14
  476. package/dist/src/core/modelCheck.js +0 -62
  477. package/dist/src/core/modelCheck.js.map +0 -1
  478. package/dist/src/services/ideContext.d.ts +0 -178
  479. package/dist/src/services/ideContext.js +0 -105
  480. package/dist/src/services/ideContext.js.map +0 -1
  481. package/dist/src/services/ideContext.test.js +0 -111
  482. package/dist/src/services/ideContext.test.js.map +0 -1
  483. /package/dist/src/core/{geminiRequest.test.d.ts → subagent.test.d.ts} +0 -0
  484. /package/dist/src/{services/ideContext.test.d.ts → ide/detect-ide.test.d.ts} +0 -0
@@ -7,227 +7,57 @@ import fs from 'fs';
7
7
  import path from 'path';
8
8
  import os from 'os';
9
9
  import crypto from 'crypto';
10
- import { BaseTool, ToolConfirmationOutcome, Icon, } from './tools.js';
11
- import { Type } from '@google/genai';
12
- import { SchemaValidator } from '../utils/schemaValidator.js';
10
+ import { BaseDeclarativeTool, BaseToolInvocation, ToolConfirmationOutcome, Kind, } from './tools.js';
13
11
  import { getErrorMessage } from '../utils/errors.js';
14
- import stripAnsi from 'strip-ansi';
15
- import { spawn } from 'child_process';
16
12
  import { summarizeToolOutput } from '../utils/summarizer.js';
17
- const OUTPUT_UPDATE_INTERVAL_MS = 1000;
18
- export class ShellTool extends BaseTool {
13
+ import { ShellExecutionService, } from '../services/shellExecutionService.js';
14
+ import { formatMemoryUsage } from '../utils/formatters.js';
15
+ import { getCommandRoots, isCommandAllowed, stripShellWrapper, } from '../utils/shell-utils.js';
16
+ export const OUTPUT_UPDATE_INTERVAL_MS = 1000;
17
+ class ShellToolInvocation extends BaseToolInvocation {
19
18
  config;
20
- static Name = 'run_shell_command';
21
- whitelist = new Set();
22
- constructor(config) {
23
- super(ShellTool.Name, 'Shell', `This tool executes a given shell command as \`bash -c <command>\`. Command can start background processes using \`&\`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as \`kill -- -PGID\` or signaled as \`kill -s SIGNAL -- -PGID\`.
24
-
25
- The following information is returned:
26
-
27
- Command: Executed command.
28
- Directory: Directory (relative to project root) where command was executed, or \`(root)\`.
29
- Stdout: Output on stdout stream. Can be \`(empty)\` or partial on error and for any unwaited background processes.
30
- Stderr: Output on stderr stream. Can be \`(empty)\` or partial on error and for any unwaited background processes.
31
- Error: Error or \`(none)\` if no error was reported for the subprocess.
32
- Exit Code: Exit code or \`(none)\` if terminated by signal.
33
- Signal: Signal number or \`(none)\` if no signal was received.
34
- Background PIDs: List of background processes started or \`(none)\`.
35
- Process Group PGID: Process group started or \`(none)\``, Icon.Terminal, {
36
- type: Type.OBJECT,
37
- properties: {
38
- command: {
39
- type: Type.STRING,
40
- description: 'Exact bash command to execute as `bash -c <command>`',
41
- },
42
- description: {
43
- type: Type.STRING,
44
- description: 'Brief description of the command for the user. Be specific and concise. Ideally a single sentence. Can be up to 3 sentences for clarity. No line breaks.',
45
- },
46
- directory: {
47
- type: Type.STRING,
48
- description: '(OPTIONAL) Directory to run the command in, if not the project root directory. Must be relative to the project root directory and must already exist.',
49
- },
50
- },
51
- required: ['command'],
52
- }, false, // output is not markdown
53
- true);
19
+ allowlist;
20
+ constructor(config, params, allowlist) {
21
+ super(params);
54
22
  this.config = config;
23
+ this.allowlist = allowlist;
55
24
  }
56
- getDescription(params) {
57
- let description = `${params.command}`;
25
+ getDescription() {
26
+ let description = `${this.params.command}`;
58
27
  // append optional [in directory]
59
28
  // note description is needed even if validation fails due to absolute path
60
- if (params.directory) {
61
- description += ` [in ${params.directory}]`;
29
+ if (this.params.directory) {
30
+ description += ` [in ${this.params.directory}]`;
62
31
  }
63
32
  // append optional (description), replacing any line breaks with spaces
64
- if (params.description) {
65
- description += ` (${params.description.replace(/\n/g, ' ')})`;
33
+ if (this.params.description) {
34
+ description += ` (${this.params.description.replace(/\n/g, ' ')})`;
66
35
  }
67
36
  return description;
68
37
  }
69
- /**
70
- * Extracts the root command from a given shell command string.
71
- * This is used to identify the base command for permission checks.
72
- *
73
- * @param command The shell command string to parse
74
- * @returns The root command name, or undefined if it cannot be determined
75
- * @example getCommandRoot("ls -la /tmp") returns "ls"
76
- * @example getCommandRoot("git status && npm test") returns "git"
77
- */
78
- getCommandRoot(command) {
79
- return command
80
- .trim() // remove leading and trailing whitespace
81
- .replace(/[{}()]/g, '') // remove all grouping operators
82
- .split(/[\s;&|]+/)[0] // split on any whitespace or separator or chaining operators and take first part
83
- ?.split(/[/\\]/) // split on any path separators (or return undefined if previous line was undefined)
84
- .pop(); // take last part and return command root (or undefined if previous line was empty)
85
- }
86
- /**
87
- * Determines whether a given shell command is allowed to execute based on
88
- * the tool's configuration including allowlists and blocklists.
89
- *
90
- * @param command The shell command string to validate
91
- * @returns An object with 'allowed' boolean and optional 'reason' string if not allowed
92
- */
93
- isCommandAllowed(command) {
94
- // 0. Disallow command substitution
95
- if (command.includes('$(')) {
96
- return {
97
- allowed: false,
98
- reason: 'Command substitution using $() is not allowed for security reasons',
99
- };
100
- }
101
- const SHELL_TOOL_NAMES = [ShellTool.name, ShellTool.Name];
102
- const normalize = (cmd) => cmd.trim().replace(/\s+/g, ' ');
103
- /**
104
- * Checks if a command string starts with a given prefix, ensuring it's a
105
- * whole word match (i.e., followed by a space or it's an exact match).
106
- * e.g., `isPrefixedBy('npm install', 'npm')` -> true
107
- * e.g., `isPrefixedBy('npm', 'npm')` -> true
108
- * e.g., `isPrefixedBy('npminstall', 'npm')` -> false
109
- */
110
- const isPrefixedBy = (cmd, prefix) => {
111
- if (!cmd.startsWith(prefix)) {
112
- return false;
113
- }
114
- return cmd.length === prefix.length || cmd[prefix.length] === ' ';
115
- };
116
- /**
117
- * Extracts and normalizes shell commands from a list of tool strings.
118
- * e.g., 'ShellTool("ls -l")' becomes 'ls -l'
119
- */
120
- const extractCommands = (tools) => tools.flatMap((tool) => {
121
- for (const toolName of SHELL_TOOL_NAMES) {
122
- if (tool.startsWith(`${toolName}(`) && tool.endsWith(')')) {
123
- return [normalize(tool.slice(toolName.length + 1, -1))];
124
- }
125
- }
126
- return [];
127
- });
128
- const coreTools = this.config.getCoreTools() || [];
129
- const excludeTools = this.config.getExcludeTools() || [];
130
- // 1. Check if the shell tool is globally disabled.
131
- if (SHELL_TOOL_NAMES.some((name) => excludeTools.includes(name))) {
132
- return {
133
- allowed: false,
134
- reason: 'Shell tool is globally disabled in configuration',
135
- };
136
- }
137
- const blockedCommands = new Set(extractCommands(excludeTools));
138
- const allowedCommands = new Set(extractCommands(coreTools));
139
- const hasSpecificAllowedCommands = allowedCommands.size > 0;
140
- const isWildcardAllowed = SHELL_TOOL_NAMES.some((name) => coreTools.includes(name));
141
- const commandsToValidate = command.split(/&&|\|\||\||;/).map(normalize);
142
- const blockedCommandsArr = [...blockedCommands];
143
- for (const cmd of commandsToValidate) {
144
- // 2. Check if the command is on the blocklist.
145
- const isBlocked = blockedCommandsArr.some((blocked) => isPrefixedBy(cmd, blocked));
146
- if (isBlocked) {
147
- return {
148
- allowed: false,
149
- reason: `Command '${cmd}' is blocked by configuration`,
150
- };
151
- }
152
- // 3. If in strict allow-list mode, check if the command is permitted.
153
- const isStrictAllowlist = hasSpecificAllowedCommands && !isWildcardAllowed;
154
- const allowedCommandsArr = [...allowedCommands];
155
- if (isStrictAllowlist) {
156
- const isAllowed = allowedCommandsArr.some((allowed) => isPrefixedBy(cmd, allowed));
157
- if (!isAllowed) {
158
- return {
159
- allowed: false,
160
- reason: `Command '${cmd}' is not in the allowed commands list`,
161
- };
162
- }
163
- }
164
- }
165
- // 4. If all checks pass, the command is allowed.
166
- return { allowed: true };
167
- }
168
- validateToolParams(params) {
169
- const commandCheck = this.isCommandAllowed(params.command);
170
- if (!commandCheck.allowed) {
171
- if (!commandCheck.reason) {
172
- console.error('Unexpected: isCommandAllowed returned false without a reason');
173
- return `Command is not allowed: ${params.command}`;
174
- }
175
- return commandCheck.reason;
176
- }
177
- const errors = SchemaValidator.validate(this.schema.parameters, params);
178
- if (errors) {
179
- return errors;
180
- }
181
- if (!params.command.trim()) {
182
- return 'Command cannot be empty.';
183
- }
184
- if (!this.getCommandRoot(params.command)) {
185
- return 'Could not identify command root to obtain permission from user.';
186
- }
187
- if (params.directory) {
188
- if (path.isAbsolute(params.directory)) {
189
- return 'Directory cannot be absolute. Must be relative to the project root directory.';
190
- }
191
- const directory = path.resolve(this.config.getTargetDir(), params.directory);
192
- if (!fs.existsSync(directory)) {
193
- return 'Directory must exist.';
194
- }
195
- }
196
- return null;
197
- }
198
- async shouldConfirmExecute(params, _abortSignal) {
199
- if (this.validateToolParams(params)) {
200
- return false; // skip confirmation, execute call will fail immediately
201
- }
202
- const rootCommand = this.getCommandRoot(params.command); // must be non-empty string post-validation
203
- if (this.whitelist.has(rootCommand)) {
38
+ async shouldConfirmExecute(_abortSignal) {
39
+ const command = stripShellWrapper(this.params.command);
40
+ const rootCommands = [...new Set(getCommandRoots(command))];
41
+ const commandsToConfirm = rootCommands.filter((command) => !this.allowlist.has(command));
42
+ if (commandsToConfirm.length === 0) {
204
43
  return false; // already approved and whitelisted
205
44
  }
206
45
  const confirmationDetails = {
207
46
  type: 'exec',
208
47
  title: 'Confirm Shell Command',
209
- command: params.command,
210
- rootCommand,
48
+ command: this.params.command,
49
+ rootCommand: commandsToConfirm.join(', '),
211
50
  onConfirm: async (outcome) => {
212
51
  if (outcome === ToolConfirmationOutcome.ProceedAlways) {
213
- this.whitelist.add(rootCommand);
52
+ commandsToConfirm.forEach((command) => this.allowlist.add(command));
214
53
  }
215
54
  },
216
55
  };
217
56
  return confirmationDetails;
218
57
  }
219
- async execute(params, abortSignal, updateOutput) {
220
- const validationError = this.validateToolParams(params);
221
- if (validationError) {
222
- return {
223
- llmContent: [
224
- `Command rejected: ${params.command}`,
225
- `Reason: ${validationError}`,
226
- ].join('\n'),
227
- returnDisplay: `Error: ${validationError}`,
228
- };
229
- }
230
- if (abortSignal.aborted) {
58
+ async execute(signal, updateOutput) {
59
+ const strippedCommand = stripShellWrapper(this.params.command);
60
+ if (signal.aborted) {
231
61
  return {
232
62
  llmContent: 'Command was cancelled by user before it could start.',
233
63
  returnDisplay: 'Command cancelled by user.',
@@ -238,198 +68,251 @@ Process Group PGID: Process group started or \`(none)\``, Icon.Terminal, {
238
68
  .randomBytes(6)
239
69
  .toString('hex')}.tmp`;
240
70
  const tempFilePath = path.join(os.tmpdir(), tempFileName);
241
- // pgrep is not available on Windows, so we can't get background PIDs
242
- const command = isWindows
243
- ? params.command
244
- : (() => {
245
- // wrap command to append subprocess pids (via pgrep) to temporary file
246
- let command = params.command.trim();
247
- if (!command.endsWith('&'))
248
- command += ';';
249
- return `{ ${command} }; __code=$?; pgrep -g 0 >${tempFilePath} 2>&1; exit $__code;`;
250
- })();
251
- // spawn command in specified directory (or project root if not specified)
252
- const shell = isWindows
253
- ? spawn('cmd.exe', ['/c', command], {
254
- stdio: ['ignore', 'pipe', 'pipe'],
255
- // detached: true, // ensure subprocess starts its own process group (esp. in Linux)
256
- cwd: path.resolve(this.config.getTargetDir(), params.directory || ''),
257
- })
258
- : spawn('bash', ['-c', command], {
259
- stdio: ['ignore', 'pipe', 'pipe'],
260
- detached: true, // ensure subprocess starts its own process group (esp. in Linux)
261
- cwd: path.resolve(this.config.getTargetDir(), params.directory || ''),
262
- });
263
- let exited = false;
264
- let stdout = '';
265
- let output = '';
266
- let lastUpdateTime = Date.now();
267
- const appendOutput = (str) => {
268
- output += str;
269
- if (updateOutput &&
270
- Date.now() - lastUpdateTime > OUTPUT_UPDATE_INTERVAL_MS) {
271
- updateOutput(output);
272
- lastUpdateTime = Date.now();
273
- }
274
- };
275
- shell.stdout.on('data', (data) => {
276
- // continue to consume post-exit for background processes
277
- // removing listeners can overflow OS buffer and block subprocesses
278
- // destroying (e.g. shell.stdout.destroy()) can terminate subprocesses via SIGPIPE
279
- if (!exited) {
280
- const str = stripAnsi(data.toString());
281
- stdout += str;
282
- appendOutput(str);
283
- }
284
- });
285
- let stderr = '';
286
- shell.stderr.on('data', (data) => {
287
- if (!exited) {
288
- const str = stripAnsi(data.toString());
289
- stderr += str;
290
- appendOutput(str);
291
- }
292
- });
293
- let error = null;
294
- shell.on('error', (err) => {
295
- error = err;
296
- // remove wrapper from user's command in error message
297
- error.message = error.message.replace(command, params.command);
298
- });
299
- let code = null;
300
- let processSignal = null;
301
- const exitHandler = (_code, _signal) => {
302
- exited = true;
303
- code = _code;
304
- processSignal = _signal;
305
- };
306
- shell.on('exit', exitHandler);
307
- const abortHandler = async () => {
308
- if (shell.pid && !exited) {
309
- if (os.platform() === 'win32') {
310
- // For Windows, use taskkill to kill the process tree
311
- spawn('taskkill', ['/pid', shell.pid.toString(), '/f', '/t']);
71
+ try {
72
+ // pgrep is not available on Windows, so we can't get background PIDs
73
+ const commandToExecute = isWindows
74
+ ? strippedCommand
75
+ : (() => {
76
+ // wrap command to append subprocess pids (via pgrep) to temporary file
77
+ let command = strippedCommand.trim();
78
+ if (!command.endsWith('&'))
79
+ command += ';';
80
+ return `{ ${command} }; __code=$?; pgrep -g 0 >${tempFilePath} 2>&1; exit $__code;`;
81
+ })();
82
+ const cwd = path.resolve(this.config.getTargetDir(), this.params.directory || '');
83
+ let cumulativeStdout = '';
84
+ let cumulativeStderr = '';
85
+ let lastUpdateTime = Date.now();
86
+ let isBinaryStream = false;
87
+ const { result: resultPromise } = ShellExecutionService.execute(commandToExecute, cwd, (event) => {
88
+ if (!updateOutput) {
89
+ return;
312
90
  }
313
- else {
314
- try {
315
- // attempt to SIGTERM process group (negative PID)
316
- // fall back to SIGKILL (to group) after 200ms
317
- process.kill(-shell.pid, 'SIGTERM');
318
- await new Promise((resolve) => setTimeout(resolve, 200));
319
- if (shell.pid && !exited) {
320
- process.kill(-shell.pid, 'SIGKILL');
91
+ let currentDisplayOutput = '';
92
+ let shouldUpdate = false;
93
+ switch (event.type) {
94
+ case 'data':
95
+ if (isBinaryStream)
96
+ break; // Don't process text if we are in binary mode
97
+ if (event.stream === 'stdout') {
98
+ cumulativeStdout += event.chunk;
321
99
  }
322
- }
323
- catch (_e) {
324
- // if group kill fails, fall back to killing just the main process
325
- try {
326
- if (shell.pid) {
327
- shell.kill('SIGKILL');
328
- }
100
+ else {
101
+ cumulativeStderr += event.chunk;
102
+ }
103
+ currentDisplayOutput =
104
+ cumulativeStdout +
105
+ (cumulativeStderr ? `\n${cumulativeStderr}` : '');
106
+ if (Date.now() - lastUpdateTime > OUTPUT_UPDATE_INTERVAL_MS) {
107
+ shouldUpdate = true;
329
108
  }
330
- catch (_e) {
331
- console.error(`failed to kill shell process ${shell.pid}: ${_e}`);
109
+ break;
110
+ case 'binary_detected':
111
+ isBinaryStream = true;
112
+ currentDisplayOutput =
113
+ '[Binary output detected. Halting stream...]';
114
+ shouldUpdate = true;
115
+ break;
116
+ case 'binary_progress':
117
+ isBinaryStream = true;
118
+ currentDisplayOutput = `[Receiving binary output... ${formatMemoryUsage(event.bytesReceived)} received]`;
119
+ if (Date.now() - lastUpdateTime > OUTPUT_UPDATE_INTERVAL_MS) {
120
+ shouldUpdate = true;
332
121
  }
122
+ break;
123
+ default: {
124
+ throw new Error('An unhandled ShellOutputEvent was found.');
333
125
  }
334
126
  }
335
- }
336
- };
337
- abortSignal.addEventListener('abort', abortHandler);
338
- // wait for the shell to exit
339
- try {
340
- await new Promise((resolve) => shell.on('exit', resolve));
341
- }
342
- finally {
343
- abortSignal.removeEventListener('abort', abortHandler);
344
- }
345
- // parse pids (pgrep output) from temporary file and remove it
346
- const backgroundPIDs = [];
347
- if (os.platform() !== 'win32') {
348
- if (fs.existsSync(tempFilePath)) {
349
- const pgrepLines = fs
350
- .readFileSync(tempFilePath, 'utf8')
351
- .split('\n')
352
- .filter(Boolean);
353
- for (const line of pgrepLines) {
354
- if (!/^\d+$/.test(line)) {
355
- console.error(`pgrep: ${line}`);
127
+ if (shouldUpdate) {
128
+ updateOutput(currentDisplayOutput);
129
+ lastUpdateTime = Date.now();
130
+ }
131
+ }, signal);
132
+ const result = await resultPromise;
133
+ const backgroundPIDs = [];
134
+ if (os.platform() !== 'win32') {
135
+ if (fs.existsSync(tempFilePath)) {
136
+ const pgrepLines = fs
137
+ .readFileSync(tempFilePath, 'utf8')
138
+ .split('\n')
139
+ .filter(Boolean);
140
+ for (const line of pgrepLines) {
141
+ if (!/^\d+$/.test(line)) {
142
+ console.error(`pgrep: ${line}`);
143
+ }
144
+ const pid = Number(line);
145
+ if (pid !== result.pid) {
146
+ backgroundPIDs.push(pid);
147
+ }
356
148
  }
357
- const pid = Number(line);
358
- // exclude the shell subprocess pid
359
- if (pid !== shell.pid) {
360
- backgroundPIDs.push(pid);
149
+ }
150
+ else {
151
+ if (!signal.aborted) {
152
+ console.error('missing pgrep output');
361
153
  }
362
154
  }
363
- fs.unlinkSync(tempFilePath);
364
155
  }
365
- else {
366
- if (!abortSignal.aborted) {
367
- console.error('missing pgrep output');
156
+ let llmContent = '';
157
+ if (result.aborted) {
158
+ llmContent = 'Command was cancelled by user before it could complete.';
159
+ if (result.output.trim()) {
160
+ llmContent += ` Below is the output (on stdout and stderr) before it was cancelled:\n${result.output}`;
161
+ }
162
+ else {
163
+ llmContent += ' There was no output before it was cancelled.';
368
164
  }
369
- }
370
- }
371
- let llmContent = '';
372
- if (abortSignal.aborted) {
373
- llmContent = 'Command was cancelled by user before it could complete.';
374
- if (output.trim()) {
375
- llmContent += ` Below is the output (on stdout and stderr) before it was cancelled:\n${output}`;
376
165
  }
377
166
  else {
378
- llmContent += ' There was no output before it was cancelled.';
167
+ // Create a formatted error string for display, replacing the wrapper command
168
+ // with the user-facing command.
169
+ const finalError = result.error
170
+ ? result.error.message.replace(commandToExecute, this.params.command)
171
+ : '(none)';
172
+ llmContent = [
173
+ `Command: ${this.params.command}`,
174
+ `Directory: ${this.params.directory || '(root)'}`,
175
+ `Stdout: ${result.stdout || '(empty)'}`,
176
+ `Stderr: ${result.stderr || '(empty)'}`,
177
+ `Error: ${finalError}`, // Use the cleaned error string.
178
+ `Exit Code: ${result.exitCode ?? '(none)'}`,
179
+ `Signal: ${result.signal ?? '(none)'}`,
180
+ `Background PIDs: ${backgroundPIDs.length ? backgroundPIDs.join(', ') : '(none)'}`,
181
+ `Process Group PGID: ${result.pid ?? '(none)'}`,
182
+ ].join('\n');
379
183
  }
380
- }
381
- else {
382
- llmContent = [
383
- `Command: ${params.command}`,
384
- `Directory: ${params.directory || '(root)'}`,
385
- `Stdout: ${stdout || '(empty)'}`,
386
- `Stderr: ${stderr || '(empty)'}`,
387
- `Error: ${error ?? '(none)'}`,
388
- `Exit Code: ${code ?? '(none)'}`,
389
- `Signal: ${processSignal ?? '(none)'}`,
390
- `Background PIDs: ${backgroundPIDs.length ? backgroundPIDs.join(', ') : '(none)'}`,
391
- `Process Group PGID: ${shell.pid ?? '(none)'}`,
392
- ].join('\n');
393
- }
394
- let returnDisplayMessage = '';
395
- if (this.config.getDebugMode()) {
396
- returnDisplayMessage = llmContent;
397
- }
398
- else {
399
- if (output.trim()) {
400
- returnDisplayMessage = output;
184
+ let returnDisplayMessage = '';
185
+ if (this.config.getDebugMode()) {
186
+ returnDisplayMessage = llmContent;
401
187
  }
402
188
  else {
403
- // Output is empty, let's provide a reason if the command failed or was cancelled
404
- if (abortSignal.aborted) {
405
- returnDisplayMessage = 'Command cancelled by user.';
406
- }
407
- else if (processSignal) {
408
- returnDisplayMessage = `Command terminated by signal: ${processSignal}`;
189
+ if (result.output.trim()) {
190
+ returnDisplayMessage = result.output;
409
191
  }
410
- else if (error) {
411
- // If error is not null, it's an Error object (or other truthy value)
412
- returnDisplayMessage = `Command failed: ${getErrorMessage(error)}`;
413
- }
414
- else if (code !== null && code !== 0) {
415
- returnDisplayMessage = `Command exited with code: ${code}`;
192
+ else {
193
+ if (result.aborted) {
194
+ returnDisplayMessage = 'Command cancelled by user.';
195
+ }
196
+ else if (result.signal) {
197
+ returnDisplayMessage = `Command terminated by signal: ${result.signal}`;
198
+ }
199
+ else if (result.error) {
200
+ returnDisplayMessage = `Command failed: ${getErrorMessage(result.error)}`;
201
+ }
202
+ else if (result.exitCode !== null && result.exitCode !== 0) {
203
+ returnDisplayMessage = `Command exited with code: ${result.exitCode}`;
204
+ }
205
+ // If output is empty and command succeeded (code 0, no error/signal/abort),
206
+ // returnDisplayMessage will remain empty, which is fine.
416
207
  }
417
- // If output is empty and command succeeded (code 0, no error/signal/abort),
418
- // returnDisplayMessage will remain empty, which is fine.
419
208
  }
420
- }
421
- const summarizeConfig = this.config.getSummarizeToolOutputConfig();
422
- if (summarizeConfig && summarizeConfig[this.name]) {
423
- const summary = await summarizeToolOutput(llmContent, this.config.getGeminiClient(), abortSignal, summarizeConfig[this.name].tokenBudget);
209
+ const summarizeConfig = this.config.getSummarizeToolOutputConfig();
210
+ if (summarizeConfig && summarizeConfig[ShellTool.Name]) {
211
+ const summary = await summarizeToolOutput(llmContent, this.config.getGeminiClient(), signal, summarizeConfig[ShellTool.Name].tokenBudget);
212
+ return {
213
+ llmContent: summary,
214
+ returnDisplay: returnDisplayMessage,
215
+ };
216
+ }
424
217
  return {
425
- llmContent: summary,
218
+ llmContent,
426
219
  returnDisplay: returnDisplayMessage,
427
220
  };
428
221
  }
429
- return {
430
- llmContent,
431
- returnDisplay: returnDisplayMessage,
432
- };
222
+ finally {
223
+ if (fs.existsSync(tempFilePath)) {
224
+ fs.unlinkSync(tempFilePath);
225
+ }
226
+ }
227
+ }
228
+ }
229
+ function getShellToolDescription() {
230
+ const returnedInfo = `
231
+
232
+ The following information is returned:
233
+
234
+ Command: Executed command.
235
+ Directory: Directory (relative to project root) where command was executed, or \`(root)\`.
236
+ Stdout: Output on stdout stream. Can be \`(empty)\` or partial on error and for any unwaited background processes.
237
+ Stderr: Output on stderr stream. Can be \`(empty)\` or partial on error and for any unwaited background processes.
238
+ Error: Error or \`(none)\` if no error was reported for the subprocess.
239
+ Exit Code: Exit code or \`(none)\` if terminated by signal.
240
+ Signal: Signal number or \`(none)\` if no signal was received.
241
+ Background PIDs: List of background processes started or \`(none)\`.
242
+ Process Group PGID: Process group started or \`(none)\``;
243
+ if (os.platform() === 'win32') {
244
+ return `This tool executes a given shell command as \`cmd.exe /c <command>\`. Command can start background processes using \`start /b\`.${returnedInfo}`;
245
+ }
246
+ else {
247
+ return `This tool executes a given shell command as \`bash -c <command>\`. Command can start background processes using \`&\`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as \`kill -- -PGID\` or signaled as \`kill -s SIGNAL -- -PGID\`.${returnedInfo}`;
248
+ }
249
+ }
250
+ function getCommandDescription() {
251
+ if (os.platform() === 'win32') {
252
+ return 'Exact command to execute as `cmd.exe /c <command>`';
253
+ }
254
+ else {
255
+ return 'Exact bash command to execute as `bash -c <command>`';
256
+ }
257
+ }
258
+ export class ShellTool extends BaseDeclarativeTool {
259
+ config;
260
+ static Name = 'run_shell_command';
261
+ allowlist = new Set();
262
+ constructor(config) {
263
+ super(ShellTool.Name, 'Shell', getShellToolDescription(), Kind.Execute, {
264
+ type: 'object',
265
+ properties: {
266
+ command: {
267
+ type: 'string',
268
+ description: getCommandDescription(),
269
+ },
270
+ description: {
271
+ type: 'string',
272
+ description: 'Brief description of the command for the user. Be specific and concise. Ideally a single sentence. Can be up to 3 sentences for clarity. No line breaks.',
273
+ },
274
+ directory: {
275
+ type: 'string',
276
+ description: '(OPTIONAL) Directory to run the command in, if not the project root directory. Must be relative to the project root directory and must already exist.',
277
+ },
278
+ },
279
+ required: ['command'],
280
+ }, false, // output is not markdown
281
+ true);
282
+ this.config = config;
283
+ }
284
+ validateToolParamValues(params) {
285
+ const commandCheck = isCommandAllowed(params.command, this.config);
286
+ if (!commandCheck.allowed) {
287
+ if (!commandCheck.reason) {
288
+ console.error('Unexpected: isCommandAllowed returned false without a reason');
289
+ return `Command is not allowed: ${params.command}`;
290
+ }
291
+ return commandCheck.reason;
292
+ }
293
+ if (!params.command.trim()) {
294
+ return 'Command cannot be empty.';
295
+ }
296
+ if (getCommandRoots(params.command).length === 0) {
297
+ return 'Could not identify command root to obtain permission from user.';
298
+ }
299
+ if (params.directory) {
300
+ if (path.isAbsolute(params.directory)) {
301
+ return 'Directory cannot be absolute. Please refer to workspace directories by their name.';
302
+ }
303
+ const workspaceDirs = this.config.getWorkspaceContext().getDirectories();
304
+ const matchingDirs = workspaceDirs.filter((dir) => path.basename(dir) === params.directory);
305
+ if (matchingDirs.length === 0) {
306
+ return `Directory '${params.directory}' is not a registered workspace directory.`;
307
+ }
308
+ if (matchingDirs.length > 1) {
309
+ return `Directory name '${params.directory}' is ambiguous as it matches multiple workspace directories.`;
310
+ }
311
+ }
312
+ return null;
313
+ }
314
+ createInvocation(params) {
315
+ return new ShellToolInvocation(this.config, params, this.allowlist);
433
316
  }
434
317
  }
435
318
  //# sourceMappingURL=shell.js.map