@vybestack/llxprt-code-core 0.1.14 → 0.1.16

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 (463) hide show
  1. package/README.md +90 -2
  2. package/dist/src/code_assist/converter.d.ts +2 -1
  3. package/dist/src/code_assist/converter.js +2 -1
  4. package/dist/src/code_assist/converter.js.map +1 -1
  5. package/dist/src/code_assist/converter.test.js +13 -10
  6. package/dist/src/code_assist/converter.test.js.map +1 -1
  7. package/dist/src/code_assist/oauth2.test.d.ts +1 -1
  8. package/dist/src/code_assist/oauth2.test.js +15 -15
  9. package/dist/src/code_assist/oauth2.test.js.map +1 -1
  10. package/dist/src/code_assist/server.d.ts +2 -2
  11. package/dist/src/code_assist/server.js +4 -4
  12. package/dist/src/code_assist/server.js.map +1 -1
  13. package/dist/src/code_assist/server.test.js +9 -9
  14. package/dist/src/code_assist/server.test.js.map +1 -1
  15. package/dist/src/code_assist/setup.js +1 -1
  16. package/dist/src/code_assist/setup.js.map +1 -1
  17. package/dist/src/code_assist/setup.test.js +2 -2
  18. package/dist/src/code_assist/setup.test.js.map +1 -1
  19. package/dist/src/config/config.d.ts +37 -5
  20. package/dist/src/config/config.js +85 -15
  21. package/dist/src/config/config.js.map +1 -1
  22. package/dist/src/config/config.test.js +33 -0
  23. package/dist/src/config/config.test.js.map +1 -1
  24. package/dist/src/config/flashFallback.test.js +23 -47
  25. package/dist/src/config/flashFallback.test.js.map +1 -1
  26. package/dist/src/config/models.d.ts +1 -0
  27. package/dist/src/config/models.js +1 -0
  28. package/dist/src/config/models.js.map +1 -1
  29. package/dist/src/config/profileManager.d.ts +42 -0
  30. package/dist/src/config/profileManager.js +114 -0
  31. package/dist/src/config/profileManager.js.map +1 -0
  32. package/dist/src/core/client.d.ts +15 -1
  33. package/dist/src/core/client.js +161 -45
  34. package/dist/src/core/client.js.map +1 -1
  35. package/dist/src/core/client.test.js +291 -42
  36. package/dist/src/core/client.test.js.map +1 -1
  37. package/dist/src/core/contentGenerator.d.ts +2 -2
  38. package/dist/src/core/contentGenerator.js +2 -7
  39. package/dist/src/core/contentGenerator.js.map +1 -1
  40. package/dist/src/core/contentGenerator.test.js +6 -2
  41. package/dist/src/core/contentGenerator.test.js.map +1 -1
  42. package/dist/src/core/coreToolScheduler.d.ts +1 -3
  43. package/dist/src/core/coreToolScheduler.js +48 -19
  44. package/dist/src/core/coreToolScheduler.js.map +1 -1
  45. package/dist/src/core/coreToolScheduler.test.js +90 -18
  46. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  47. package/dist/src/core/geminiChat.js +35 -2
  48. package/dist/src/core/geminiChat.js.map +1 -1
  49. package/dist/src/core/geminiChat.test.js +2 -2
  50. package/dist/src/core/geminiChat.test.js.map +1 -1
  51. package/dist/src/core/googleGenAIWrapper.d.ts +21 -0
  52. package/dist/src/core/googleGenAIWrapper.js +36 -0
  53. package/dist/src/core/googleGenAIWrapper.js.map +1 -0
  54. package/dist/src/core/googleGenAIWrapper.test.d.ts +6 -0
  55. package/dist/src/core/googleGenAIWrapper.test.js +104 -0
  56. package/dist/src/core/googleGenAIWrapper.test.js.map +1 -0
  57. package/dist/src/core/logger.d.ts +1 -0
  58. package/dist/src/core/logger.js +22 -8
  59. package/dist/src/core/logger.js.map +1 -1
  60. package/dist/src/core/logger.test.js +60 -9
  61. package/dist/src/core/logger.test.js.map +1 -1
  62. package/dist/src/core/nonInteractiveToolExecutor.js +19 -4
  63. package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
  64. package/dist/src/core/nonInteractiveToolExecutor.test.js +8 -3
  65. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  66. package/dist/src/core/prompts-async.test.d.ts +6 -0
  67. package/dist/src/core/prompts-async.test.js +115 -0
  68. package/dist/src/core/prompts-async.test.js.map +1 -0
  69. package/dist/src/core/prompts.d.ts +8 -1
  70. package/dist/src/core/prompts.js +97 -377
  71. package/dist/src/core/prompts.js.map +1 -1
  72. package/dist/src/core/prompts.test.js +46 -192
  73. package/dist/src/core/prompts.test.js.map +1 -1
  74. package/dist/src/core/tokenLimits.d.ts +1 -1
  75. package/dist/src/core/tokenLimits.js +6 -1
  76. package/dist/src/core/tokenLimits.js.map +1 -1
  77. package/dist/src/core/turn.d.ts +5 -1
  78. package/dist/src/core/turn.js +7 -2
  79. package/dist/src/core/turn.js.map +1 -1
  80. package/dist/src/core/turn.test.js +2 -2
  81. package/dist/src/core/turn.test.js.map +1 -1
  82. package/dist/src/ide/detect-ide.d.ts +10 -0
  83. package/dist/src/ide/detect-ide.js +24 -0
  84. package/dist/src/ide/detect-ide.js.map +1 -0
  85. package/dist/src/ide/ide-client.d.ts +19 -7
  86. package/dist/src/ide/ide-client.js +110 -37
  87. package/dist/src/ide/ide-client.js.map +1 -1
  88. package/dist/src/ide/ide-installer.d.ts +15 -0
  89. package/dist/src/ide/ide-installer.js +111 -0
  90. package/dist/src/ide/ide-installer.js.map +1 -0
  91. package/dist/src/ide/ide-installer.test.d.ts +6 -0
  92. package/dist/src/ide/ide-installer.test.js +78 -0
  93. package/dist/src/ide/ide-installer.test.js.map +1 -0
  94. package/dist/src/ide/ideContext.d.ts +212 -107
  95. package/dist/src/ide/ideContext.js +45 -44
  96. package/dist/src/ide/ideContext.js.map +1 -1
  97. package/dist/src/ide/ideContext.test.js +254 -100
  98. package/dist/src/ide/ideContext.test.js.map +1 -1
  99. package/dist/src/index.d.ts +16 -0
  100. package/dist/src/index.js +20 -0
  101. package/dist/src/index.js.map +1 -1
  102. package/dist/src/{providers/IProviderConfig.js → integration-tests/todo-system.test.d.ts} +0 -1
  103. package/dist/src/integration-tests/todo-system.test.js +610 -0
  104. package/dist/src/integration-tests/todo-system.test.js.map +1 -0
  105. package/dist/src/mcp/oauth-provider.d.ts +5 -1
  106. package/dist/src/mcp/oauth-provider.js +39 -14
  107. package/dist/src/mcp/oauth-provider.js.map +1 -1
  108. package/dist/src/mcp/oauth-provider.test.js +11 -10
  109. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  110. package/dist/src/mcp/oauth-token-storage.d.ts +3 -1
  111. package/dist/src/mcp/oauth-token-storage.js +3 -1
  112. package/dist/src/mcp/oauth-token-storage.js.map +1 -1
  113. package/dist/src/mcp/oauth-utils.js +2 -2
  114. package/dist/src/mcp/oauth-utils.js.map +1 -1
  115. package/dist/src/mcp/oauth-utils.test.js +1 -1
  116. package/dist/src/mcp/oauth-utils.test.js.map +1 -1
  117. package/dist/src/parsers/TextToolCallParser.d.ts +1 -0
  118. package/dist/src/parsers/TextToolCallParser.js +45 -3
  119. package/dist/src/parsers/TextToolCallParser.js.map +1 -1
  120. package/dist/src/parsers/TextToolCallParser.multibyte.test.d.ts +1 -0
  121. package/dist/src/parsers/TextToolCallParser.multibyte.test.js +42 -0
  122. package/dist/src/parsers/TextToolCallParser.multibyte.test.js.map +1 -0
  123. package/dist/src/prompt-config/TemplateEngine.d.ts +35 -0
  124. package/dist/src/prompt-config/TemplateEngine.js +149 -0
  125. package/dist/src/prompt-config/TemplateEngine.js.map +1 -0
  126. package/dist/src/prompt-config/TemplateEngine.test.d.ts +1 -0
  127. package/dist/src/prompt-config/TemplateEngine.test.js +494 -0
  128. package/dist/src/prompt-config/TemplateEngine.test.js.map +1 -0
  129. package/dist/src/prompt-config/defaults/compression.md +58 -0
  130. package/dist/src/prompt-config/defaults/core-defaults.d.ts +5 -0
  131. package/dist/src/prompt-config/defaults/core-defaults.js +332 -0
  132. package/dist/src/prompt-config/defaults/core-defaults.js.map +1 -0
  133. package/dist/src/prompt-config/defaults/core.md +267 -0
  134. package/dist/src/prompt-config/defaults/env/git-repository.md +15 -0
  135. package/dist/src/prompt-config/defaults/env/ide-mode.md +3 -0
  136. package/dist/src/prompt-config/defaults/env/macos-seatbelt.md +3 -0
  137. package/dist/src/prompt-config/defaults/env/outside-of-sandbox.md +3 -0
  138. package/dist/src/prompt-config/defaults/env/sandbox.md +3 -0
  139. package/dist/src/prompt-config/defaults/index.d.ts +14 -0
  140. package/dist/src/prompt-config/defaults/index.js +21 -0
  141. package/dist/src/prompt-config/defaults/index.js.map +1 -0
  142. package/dist/src/prompt-config/defaults/provider-defaults.d.ts +5 -0
  143. package/dist/src/prompt-config/defaults/provider-defaults.js +26 -0
  144. package/dist/src/prompt-config/defaults/provider-defaults.js.map +1 -0
  145. package/dist/src/prompt-config/defaults/providers/gemini/models/gemini-2.5-flash/core.md +10 -0
  146. package/dist/src/prompt-config/defaults/service-defaults.d.ts +5 -0
  147. package/dist/src/prompt-config/defaults/service-defaults.js +52 -0
  148. package/dist/src/prompt-config/defaults/service-defaults.js.map +1 -0
  149. package/dist/src/prompt-config/defaults/tool-defaults.d.ts +5 -0
  150. package/dist/src/prompt-config/defaults/tool-defaults.js +81 -0
  151. package/dist/src/prompt-config/defaults/tool-defaults.js.map +1 -0
  152. package/dist/src/prompt-config/defaults/tools/edit.md +2 -0
  153. package/dist/src/prompt-config/defaults/tools/glob.md +2 -0
  154. package/dist/src/prompt-config/defaults/tools/grep.md +2 -0
  155. package/dist/src/prompt-config/defaults/tools/ls.md +1 -0
  156. package/dist/src/prompt-config/defaults/tools/memory.md +1 -0
  157. package/dist/src/prompt-config/defaults/tools/read-file.md +4 -0
  158. package/dist/src/prompt-config/defaults/tools/read-many-files.md +2 -0
  159. package/dist/src/prompt-config/defaults/tools/shell.md +5 -0
  160. package/dist/src/prompt-config/defaults/tools/todo-read.md +3 -0
  161. package/dist/src/prompt-config/defaults/tools/todo-write.md +50 -0
  162. package/dist/src/prompt-config/defaults/tools/web-fetch.md +3 -0
  163. package/dist/src/prompt-config/defaults/tools/web-search.md +3 -0
  164. package/dist/src/prompt-config/defaults/tools/write-file.md +4 -0
  165. package/dist/src/prompt-config/index.d.ts +16 -0
  166. package/dist/src/prompt-config/index.js +11 -0
  167. package/dist/src/prompt-config/index.js.map +1 -0
  168. package/dist/src/prompt-config/prompt-cache.d.ts +72 -0
  169. package/dist/src/prompt-config/prompt-cache.js +271 -0
  170. package/dist/src/prompt-config/prompt-cache.js.map +1 -0
  171. package/dist/src/prompt-config/prompt-cache.test.d.ts +6 -0
  172. package/dist/src/prompt-config/prompt-cache.test.js +437 -0
  173. package/dist/src/prompt-config/prompt-cache.test.js.map +1 -0
  174. package/dist/src/prompt-config/prompt-installer.d.ts +118 -0
  175. package/dist/src/prompt-config/prompt-installer.js +723 -0
  176. package/dist/src/prompt-config/prompt-installer.js.map +1 -0
  177. package/dist/src/prompt-config/prompt-installer.test.d.ts +7 -0
  178. package/dist/src/prompt-config/prompt-installer.test.js +503 -0
  179. package/dist/src/prompt-config/prompt-installer.test.js.map +1 -0
  180. package/dist/src/prompt-config/prompt-loader.d.ts +49 -0
  181. package/dist/src/prompt-config/prompt-loader.js +331 -0
  182. package/dist/src/prompt-config/prompt-loader.js.map +1 -0
  183. package/dist/src/prompt-config/prompt-loader.test.d.ts +5 -0
  184. package/dist/src/prompt-config/prompt-loader.test.js +413 -0
  185. package/dist/src/prompt-config/prompt-loader.test.js.map +1 -0
  186. package/dist/src/prompt-config/prompt-resolver.d.ts +74 -0
  187. package/dist/src/prompt-config/prompt-resolver.js +600 -0
  188. package/dist/src/prompt-config/prompt-resolver.js.map +1 -0
  189. package/dist/src/prompt-config/prompt-resolver.test.d.ts +1 -0
  190. package/dist/src/prompt-config/prompt-resolver.test.js +529 -0
  191. package/dist/src/prompt-config/prompt-resolver.test.js.map +1 -0
  192. package/dist/src/prompt-config/prompt-service.d.ts +108 -0
  193. package/dist/src/prompt-config/prompt-service.js +435 -0
  194. package/dist/src/prompt-config/prompt-service.js.map +1 -0
  195. package/dist/src/prompt-config/prompt-service.test.d.ts +1 -0
  196. package/dist/src/prompt-config/prompt-service.test.js +811 -0
  197. package/dist/src/prompt-config/prompt-service.test.js.map +1 -0
  198. package/dist/src/prompt-config/types.d.ts +30 -0
  199. package/dist/src/prompt-config/types.js +10 -0
  200. package/dist/src/prompt-config/types.js.map +1 -0
  201. package/dist/src/prompts/mcp-prompts.d.ts +8 -0
  202. package/dist/src/prompts/mcp-prompts.js +13 -0
  203. package/dist/src/prompts/mcp-prompts.js.map +1 -0
  204. package/dist/src/prompts/prompt-registry.d.ts +26 -0
  205. package/dist/src/prompts/prompt-registry.js +47 -0
  206. package/dist/src/prompts/prompt-registry.js.map +1 -0
  207. package/dist/src/providers/IProvider.d.ts +10 -0
  208. package/dist/src/providers/adapters/GeminiCompatibleWrapper.js +24 -9
  209. package/dist/src/providers/adapters/GeminiCompatibleWrapper.js.map +1 -1
  210. package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.js +1 -1
  211. package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.js.map +1 -1
  212. package/dist/src/providers/anthropic/AnthropicProvider.d.ts +14 -1
  213. package/dist/src/providers/anthropic/AnthropicProvider.js +28 -2
  214. package/dist/src/providers/anthropic/AnthropicProvider.js.map +1 -1
  215. package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.d.ts +1 -0
  216. package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.js +48 -0
  217. package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.js.map +1 -0
  218. package/dist/src/providers/anthropic/AnthropicProvider.test.js +2 -1
  219. package/dist/src/providers/anthropic/AnthropicProvider.test.js.map +1 -1
  220. package/dist/src/providers/gemini/GeminiProvider.d.ts +11 -2
  221. package/dist/src/providers/gemini/GeminiProvider.integration.test.js +1 -1
  222. package/dist/src/providers/gemini/GeminiProvider.js +42 -25
  223. package/dist/src/providers/gemini/GeminiProvider.js.map +1 -1
  224. package/dist/src/providers/openai/OpenAIProvider.d.ts +11 -0
  225. package/dist/src/providers/openai/OpenAIProvider.js +141 -24
  226. package/dist/src/providers/openai/OpenAIProvider.js.map +1 -1
  227. package/dist/src/providers/openai/OpenAIProvider.responses.test.js +27 -3
  228. package/dist/src/providers/openai/OpenAIProvider.responses.test.js.map +1 -1
  229. package/dist/src/providers/openai/OpenAIProvider.shouldUseResponses.test.js +2 -1
  230. package/dist/src/providers/openai/OpenAIProvider.shouldUseResponses.test.js.map +1 -1
  231. package/dist/src/providers/openai/OpenAIProvider.test.js +307 -7
  232. package/dist/src/providers/openai/OpenAIProvider.test.js.map +1 -1
  233. package/dist/src/providers/openai/buildResponsesRequest.js +19 -2
  234. package/dist/src/providers/openai/buildResponsesRequest.js.map +1 -1
  235. package/dist/src/providers/test-utils/providerTestConfig.d.ts +21 -0
  236. package/dist/src/providers/test-utils/providerTestConfig.js +23 -0
  237. package/dist/src/providers/test-utils/providerTestConfig.js.map +1 -0
  238. package/dist/src/providers/types/IProviderConfig.d.ts +6 -0
  239. package/dist/src/services/complexity-analyzer.d.ts +92 -0
  240. package/dist/src/services/complexity-analyzer.js +287 -0
  241. package/dist/src/services/complexity-analyzer.js.map +1 -0
  242. package/dist/src/services/fileDiscoveryService.test.js +101 -60
  243. package/dist/src/services/fileDiscoveryService.test.js.map +1 -1
  244. package/dist/src/services/gitService.test.d.ts +1 -1
  245. package/dist/src/services/gitService.test.js +65 -102
  246. package/dist/src/services/gitService.test.js.map +1 -1
  247. package/dist/src/services/index.d.ts +9 -0
  248. package/dist/src/services/index.js +8 -0
  249. package/dist/src/services/index.js.map +1 -0
  250. package/dist/src/services/loopDetectionService.d.ts +12 -0
  251. package/dist/src/services/loopDetectionService.js +62 -12
  252. package/dist/src/services/loopDetectionService.js.map +1 -1
  253. package/dist/src/services/loopDetectionService.test.js +90 -11
  254. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  255. package/dist/src/services/shellExecutionService.d.ts +34 -0
  256. package/dist/src/services/shellExecutionService.js +121 -0
  257. package/dist/src/services/shellExecutionService.js.map +1 -0
  258. package/dist/src/services/shellExecutionService.multibyte.test.d.ts +6 -0
  259. package/dist/src/services/shellExecutionService.multibyte.test.js +72 -0
  260. package/dist/src/services/shellExecutionService.multibyte.test.js.map +1 -0
  261. package/dist/src/services/shellExecutionService.test.d.ts +6 -0
  262. package/dist/src/services/shellExecutionService.test.js +264 -0
  263. package/dist/src/services/shellExecutionService.test.js.map +1 -0
  264. package/dist/src/services/shellExecutionService.windows.multibyte.test.d.ts +6 -0
  265. package/dist/src/services/shellExecutionService.windows.multibyte.test.js +98 -0
  266. package/dist/src/services/shellExecutionService.windows.multibyte.test.js.map +1 -0
  267. package/dist/src/services/shellExecutionService.windows.test.d.ts +6 -0
  268. package/dist/src/services/shellExecutionService.windows.test.js +79 -0
  269. package/dist/src/services/shellExecutionService.windows.test.js.map +1 -0
  270. package/dist/src/services/todo-reminder-service.d.ts +42 -0
  271. package/dist/src/services/todo-reminder-service.js +77 -0
  272. package/dist/src/services/todo-reminder-service.js.map +1 -0
  273. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +4 -2
  274. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +81 -34
  275. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  276. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +6 -1
  277. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +19 -0
  278. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  279. package/dist/src/telemetry/constants.d.ts +2 -1
  280. package/dist/src/telemetry/constants.js +2 -1
  281. package/dist/src/telemetry/constants.js.map +1 -1
  282. package/dist/src/telemetry/file-exporters.d.ts +2 -2
  283. package/dist/src/telemetry/file-exporters.js +47 -20
  284. package/dist/src/telemetry/file-exporters.js.map +1 -1
  285. package/dist/src/telemetry/index.d.ts +2 -2
  286. package/dist/src/telemetry/index.js +2 -2
  287. package/dist/src/telemetry/index.js.map +1 -1
  288. package/dist/src/telemetry/loggers.d.ts +3 -2
  289. package/dist/src/telemetry/loggers.js +30 -6
  290. package/dist/src/telemetry/loggers.js.map +1 -1
  291. package/dist/src/telemetry/loggers.test.circular.js +2 -0
  292. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  293. package/dist/src/telemetry/loggers.test.js +13 -3
  294. package/dist/src/telemetry/loggers.test.js.map +1 -1
  295. package/dist/src/telemetry/sdk.d.ts +1 -1
  296. package/dist/src/telemetry/sdk.js +71 -73
  297. package/dist/src/telemetry/sdk.js.map +1 -1
  298. package/dist/src/telemetry/telemetry.test.js +7 -5
  299. package/dist/src/telemetry/telemetry.test.js.map +1 -1
  300. package/dist/src/telemetry/types.d.ts +19 -4
  301. package/dist/src/telemetry/types.js +30 -4
  302. package/dist/src/telemetry/types.js.map +1 -1
  303. package/dist/src/telemetry/uiTelemetry.test.js +3 -0
  304. package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
  305. package/dist/src/test-utils/mockWorkspaceContext.d.ts +13 -0
  306. package/dist/src/test-utils/mockWorkspaceContext.js +24 -0
  307. package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -0
  308. package/dist/src/tools/edit.js +29 -4
  309. package/dist/src/tools/edit.js.map +1 -1
  310. package/dist/src/tools/edit.test.js +104 -1
  311. package/dist/src/tools/edit.test.js.map +1 -1
  312. package/dist/src/tools/glob.js +53 -17
  313. package/dist/src/tools/glob.js.map +1 -1
  314. package/dist/src/tools/glob.test.js +32 -6
  315. package/dist/src/tools/glob.test.js.map +1 -1
  316. package/dist/src/tools/grep.d.ts +1 -1
  317. package/dist/src/tools/grep.js +81 -29
  318. package/dist/src/tools/grep.js.map +1 -1
  319. package/dist/src/tools/grep.test.js +76 -9
  320. package/dist/src/tools/grep.test.js.map +1 -1
  321. package/dist/src/tools/ls.js +4 -3
  322. package/dist/src/tools/ls.js.map +1 -1
  323. package/dist/src/tools/ls.test.d.ts +6 -0
  324. package/dist/src/tools/ls.test.js +356 -0
  325. package/dist/src/tools/ls.test.js.map +1 -0
  326. package/dist/src/tools/mcp-client.d.ts +26 -2
  327. package/dist/src/tools/mcp-client.js +72 -24
  328. package/dist/src/tools/mcp-client.js.map +1 -1
  329. package/dist/src/tools/mcp-client.test.js +87 -1
  330. package/dist/src/tools/mcp-client.test.js.map +1 -1
  331. package/dist/src/tools/memoryTool.d.ts +17 -2
  332. package/dist/src/tools/memoryTool.js +130 -13
  333. package/dist/src/tools/memoryTool.js.map +1 -1
  334. package/dist/src/tools/memoryTool.test.js +88 -3
  335. package/dist/src/tools/memoryTool.test.js.map +1 -1
  336. package/dist/src/tools/modifiable-tool.test.js +51 -62
  337. package/dist/src/tools/modifiable-tool.test.js.map +1 -1
  338. package/dist/src/tools/read-file.js +8 -6
  339. package/dist/src/tools/read-file.js.map +1 -1
  340. package/dist/src/tools/read-file.test.js +30 -2
  341. package/dist/src/tools/read-file.test.js.map +1 -1
  342. package/dist/src/tools/read-many-files.js +22 -12
  343. package/dist/src/tools/read-many-files.js.map +1 -1
  344. package/dist/src/tools/read-many-files.test.js +35 -2
  345. package/dist/src/tools/read-many-files.test.js.map +1 -1
  346. package/dist/src/tools/shell.d.ts +8 -3
  347. package/dist/src/tools/shell.js +185 -114
  348. package/dist/src/tools/shell.js.map +1 -1
  349. package/dist/src/tools/shell.multibyte.test.d.ts +6 -0
  350. package/dist/src/tools/shell.multibyte.test.js +74 -0
  351. package/dist/src/tools/shell.multibyte.test.js.map +1 -0
  352. package/dist/src/tools/shell.test.d.ts +1 -1
  353. package/dist/src/tools/shell.test.js +323 -138
  354. package/dist/src/tools/shell.test.js.map +1 -1
  355. package/dist/src/tools/todo-read.d.ts +4 -1
  356. package/dist/src/tools/todo-read.js +136 -20
  357. package/dist/src/tools/todo-read.js.map +1 -1
  358. package/dist/src/tools/todo-read.test.js +10 -6
  359. package/dist/src/tools/todo-read.test.js.map +1 -1
  360. package/dist/src/tools/todo-schemas.d.ts +4 -4
  361. package/dist/src/tools/todo-write.d.ts +3 -0
  362. package/dist/src/tools/todo-write.js +96 -9
  363. package/dist/src/tools/todo-write.js.map +1 -1
  364. package/dist/src/tools/todo-write.test.js +17 -13
  365. package/dist/src/tools/todo-write.test.js.map +1 -1
  366. package/dist/src/tools/tool-context.d.ts +14 -0
  367. package/dist/src/tools/tool-context.js +7 -0
  368. package/dist/src/tools/tool-context.js.map +1 -0
  369. package/dist/src/tools/tool-error.d.ts +22 -0
  370. package/dist/src/tools/tool-error.js +27 -0
  371. package/dist/src/tools/tool-error.js.map +1 -0
  372. package/dist/src/tools/tool-registry.d.ts +4 -1
  373. package/dist/src/tools/tool-registry.js +14 -5
  374. package/dist/src/tools/tool-registry.js.map +1 -1
  375. package/dist/src/tools/tool-registry.test.js +10 -2
  376. package/dist/src/tools/tool-registry.test.js.map +1 -1
  377. package/dist/src/tools/tools.d.ts +16 -1
  378. package/dist/src/tools/tools.js +2 -0
  379. package/dist/src/tools/tools.js.map +1 -1
  380. package/dist/src/tools/web-fetch.js +18 -4
  381. package/dist/src/tools/web-fetch.js.map +1 -1
  382. package/dist/src/tools/write-file.js +5 -3
  383. package/dist/src/tools/write-file.js.map +1 -1
  384. package/dist/src/tools/write-file.test.js +36 -2
  385. package/dist/src/tools/write-file.test.js.map +1 -1
  386. package/dist/src/types/modelParams.d.ts +62 -0
  387. package/dist/src/types/modelParams.js +7 -0
  388. package/dist/src/types/modelParams.js.map +1 -0
  389. package/dist/src/utils/bfsFileSearch.js +51 -27
  390. package/dist/src/utils/bfsFileSearch.js.map +1 -1
  391. package/dist/src/utils/bfsFileSearch.test.js +59 -0
  392. package/dist/src/utils/bfsFileSearch.test.js.map +1 -1
  393. package/dist/src/utils/editCorrector.js +2 -2
  394. package/dist/src/utils/editCorrector.js.map +1 -1
  395. package/dist/src/utils/editor.d.ts +1 -1
  396. package/dist/src/utils/editor.js +9 -0
  397. package/dist/src/utils/editor.js.map +1 -1
  398. package/dist/src/utils/editor.test.js +21 -1
  399. package/dist/src/utils/editor.test.js.map +1 -1
  400. package/dist/src/utils/fileUtils.js +12 -1
  401. package/dist/src/utils/fileUtils.js.map +1 -1
  402. package/dist/src/utils/fileUtils.test.js +29 -1
  403. package/dist/src/utils/fileUtils.test.js.map +1 -1
  404. package/dist/src/utils/flashFallback.integration.test.js +8 -0
  405. package/dist/src/utils/flashFallback.integration.test.js.map +1 -1
  406. package/dist/src/utils/formatters.d.ts +6 -0
  407. package/dist/src/utils/formatters.js +16 -0
  408. package/dist/src/utils/formatters.js.map +1 -0
  409. package/dist/src/utils/memoryDiscovery.d.ts +1 -1
  410. package/dist/src/utils/memoryDiscovery.js +61 -73
  411. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  412. package/dist/src/utils/memoryDiscovery.test.js +4 -3
  413. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  414. package/dist/src/utils/memoryImportProcessor.d.ts +19 -12
  415. package/dist/src/utils/memoryImportProcessor.js +241 -82
  416. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  417. package/dist/src/utils/memoryImportProcessor.test.js +595 -50
  418. package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
  419. package/dist/src/utils/nextSpeakerChecker.js +12 -27
  420. package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
  421. package/dist/src/utils/nextSpeakerChecker.test.js +8 -4
  422. package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
  423. package/dist/src/utils/retry.d.ts +3 -0
  424. package/dist/src/utils/retry.js.map +1 -1
  425. package/dist/src/utils/retry.test.js.map +1 -1
  426. package/dist/src/utils/sanitization.d.ts +20 -0
  427. package/dist/src/utils/sanitization.js +66 -0
  428. package/dist/src/utils/sanitization.js.map +1 -0
  429. package/dist/src/utils/sanitization.test.d.ts +6 -0
  430. package/dist/src/utils/sanitization.test.js +81 -0
  431. package/dist/src/utils/sanitization.test.js.map +1 -0
  432. package/dist/src/utils/secure-browser-launcher.d.ts +23 -0
  433. package/dist/src/utils/secure-browser-launcher.js +164 -0
  434. package/dist/src/utils/secure-browser-launcher.js.map +1 -0
  435. package/dist/src/utils/secure-browser-launcher.test.d.ts +6 -0
  436. package/dist/src/utils/secure-browser-launcher.test.js +149 -0
  437. package/dist/src/utils/secure-browser-launcher.test.js.map +1 -0
  438. package/dist/src/utils/shell-utils.d.ts +37 -3
  439. package/dist/src/utils/shell-utils.js +110 -47
  440. package/dist/src/utils/shell-utils.js.map +1 -1
  441. package/dist/src/utils/shell-utils.test.js +146 -396
  442. package/dist/src/utils/shell-utils.test.js.map +1 -1
  443. package/dist/src/utils/summarizer.js +2 -2
  444. package/dist/src/utils/summarizer.js.map +1 -1
  445. package/dist/src/utils/textUtils.d.ts +13 -0
  446. package/dist/src/utils/textUtils.js +28 -0
  447. package/dist/src/utils/textUtils.js.map +1 -0
  448. package/dist/src/utils/unicodeUtils.d.ts +44 -0
  449. package/dist/src/utils/unicodeUtils.js +93 -0
  450. package/dist/src/utils/unicodeUtils.js.map +1 -0
  451. package/dist/src/utils/unicodeUtils.test.d.ts +6 -0
  452. package/dist/src/utils/unicodeUtils.test.js +120 -0
  453. package/dist/src/utils/unicodeUtils.test.js.map +1 -0
  454. package/dist/src/utils/workspaceContext.d.ts +47 -0
  455. package/dist/src/utils/workspaceContext.js +106 -0
  456. package/dist/src/utils/workspaceContext.js.map +1 -0
  457. package/dist/src/utils/workspaceContext.test.d.ts +6 -0
  458. package/dist/src/utils/workspaceContext.test.js +209 -0
  459. package/dist/src/utils/workspaceContext.test.js.map +1 -0
  460. package/package.json +3 -2
  461. package/dist/src/providers/IProviderConfig.d.ts +0 -31
  462. package/dist/src/providers/IProviderConfig.js.map +0 -1
  463. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -4,447 +4,197 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import { expect, describe, it, beforeEach } from 'vitest';
7
- import { getCommandRoots, isCommandAllowed, stripShellWrapper, } from './shell-utils.js';
7
+ import { checkCommandPermissions, getCommandRoots, isCommandAllowed, stripShellWrapper, } from './shell-utils.js';
8
+ let config;
9
+ beforeEach(() => {
10
+ config = {
11
+ getCoreTools: () => [],
12
+ getExcludeTools: () => [],
13
+ };
14
+ });
8
15
  describe('isCommandAllowed', () => {
9
- let config;
10
- beforeEach(() => {
11
- config = {
12
- getCoreTools: () => undefined,
13
- getExcludeTools: () => undefined,
14
- };
15
- });
16
- it('should allow a command if no restrictions are provided', async () => {
16
+ it('should allow a command if no restrictions are provided', () => {
17
17
  const result = isCommandAllowed('ls -l', config);
18
18
  expect(result.allowed).toBe(true);
19
19
  });
20
- it('should allow a command if it is in the allowed list', async () => {
21
- config = {
22
- getCoreTools: () => ['ShellTool(ls -l)'],
23
- getExcludeTools: () => undefined,
24
- };
20
+ it('should allow a command if it is in the global allowlist', () => {
21
+ config.getCoreTools = () => ['ShellTool(ls)'];
25
22
  const result = isCommandAllowed('ls -l', config);
26
23
  expect(result.allowed).toBe(true);
27
24
  });
28
- it('should block a command if it is not in the allowed list', async () => {
29
- config = {
30
- getCoreTools: () => ['ShellTool(ls -l)'],
31
- getExcludeTools: () => undefined,
32
- };
25
+ it('should block a command if it is not in a strict global allowlist', () => {
26
+ config.getCoreTools = () => ['ShellTool(ls -l)'];
33
27
  const result = isCommandAllowed('rm -rf /', config);
34
28
  expect(result.allowed).toBe(false);
35
- expect(result.reason).toBe("Command 'rm -rf /' is not in the allowed commands list");
29
+ expect(result.reason).toBe(`Command(s) not in the allowed commands list.`);
36
30
  });
37
- it('should block a command if it is in the blocked list', async () => {
38
- config = {
39
- getCoreTools: () => undefined,
40
- getExcludeTools: () => ['ShellTool(rm -rf /)'],
41
- };
31
+ it('should block a command if it is in the blocked list', () => {
32
+ config.getExcludeTools = () => ['ShellTool(rm -rf /)'];
42
33
  const result = isCommandAllowed('rm -rf /', config);
43
34
  expect(result.allowed).toBe(false);
44
- expect(result.reason).toBe("Command 'rm -rf /' is blocked by configuration");
35
+ expect(result.reason).toBe(`Command 'rm -rf /' is blocked by configuration`);
45
36
  });
46
- it('should allow a command if it is not in the blocked list', async () => {
47
- config = {
48
- getCoreTools: () => undefined,
49
- getExcludeTools: () => ['ShellTool(rm -rf /)'],
50
- };
51
- const result = isCommandAllowed('ls -l', config);
52
- expect(result.allowed).toBe(true);
53
- });
54
- it('should block a command if it is in both the allowed and blocked lists', async () => {
55
- config = {
56
- getCoreTools: () => ['ShellTool(rm -rf /)'],
57
- getExcludeTools: () => ['ShellTool(rm -rf /)'],
58
- };
37
+ it('should prioritize the blocklist over the allowlist', () => {
38
+ config.getCoreTools = () => ['ShellTool(rm -rf /)'];
39
+ config.getExcludeTools = () => ['ShellTool(rm -rf /)'];
59
40
  const result = isCommandAllowed('rm -rf /', config);
60
41
  expect(result.allowed).toBe(false);
61
- expect(result.reason).toBe("Command 'rm -rf /' is blocked by configuration");
42
+ expect(result.reason).toBe(`Command 'rm -rf /' is blocked by configuration`);
62
43
  });
63
- it('should allow any command when ShellTool is in coreTools without specific commands', async () => {
64
- config = {
65
- getCoreTools: () => ['ShellTool'],
66
- getExcludeTools: () => [],
67
- };
68
- const result = isCommandAllowed('any command', config);
44
+ it('should allow any command when a wildcard is in coreTools', () => {
45
+ config.getCoreTools = () => ['ShellTool'];
46
+ const result = isCommandAllowed('any random command', config);
69
47
  expect(result.allowed).toBe(true);
70
48
  });
71
- it('should block any command when ShellTool is in excludeTools without specific commands', async () => {
72
- config = {
73
- getCoreTools: () => [],
74
- getExcludeTools: () => ['ShellTool'],
75
- };
76
- const result = isCommandAllowed('any command', config);
49
+ it('should block any command when a wildcard is in excludeTools', () => {
50
+ config.getExcludeTools = () => ['run_shell_command'];
51
+ const result = isCommandAllowed('any random command', config);
77
52
  expect(result.allowed).toBe(false);
78
53
  expect(result.reason).toBe('Shell tool is globally disabled in configuration');
79
54
  });
80
- it('should allow a command if it is in the allowed list using the public-facing name', async () => {
81
- config = {
82
- getCoreTools: () => ['run_shell_command(ls -l)'],
83
- getExcludeTools: () => undefined,
84
- };
85
- const result = isCommandAllowed('ls -l', config);
86
- expect(result.allowed).toBe(true);
87
- });
88
- it('should block a command if it is in the blocked list using the public-facing name', async () => {
89
- config = {
90
- getCoreTools: () => undefined,
91
- getExcludeTools: () => ['run_shell_command(rm -rf /)'],
92
- };
55
+ it('should block a command on the blocklist even with a wildcard allow', () => {
56
+ config.getCoreTools = () => ['ShellTool'];
57
+ config.getExcludeTools = () => ['ShellTool(rm -rf /)'];
93
58
  const result = isCommandAllowed('rm -rf /', config);
94
59
  expect(result.allowed).toBe(false);
95
- expect(result.reason).toBe("Command 'rm -rf /' is blocked by configuration");
96
- });
97
- it('should block any command when ShellTool is in excludeTools using the public-facing name', async () => {
98
- config = {
99
- getCoreTools: () => [],
100
- getExcludeTools: () => ['run_shell_command'],
101
- };
102
- const result = isCommandAllowed('any command', config);
103
- expect(result.allowed).toBe(false);
104
- expect(result.reason).toBe('Shell tool is globally disabled in configuration');
105
- });
106
- it('should block any command if coreTools contains an empty ShellTool command list using the public-facing name', async () => {
107
- config = {
108
- getCoreTools: () => ['run_shell_command()'],
109
- getExcludeTools: () => [],
110
- };
111
- const result = isCommandAllowed('any command', config);
112
- expect(result.allowed).toBe(false);
113
- expect(result.reason).toBe("Command 'any command' is not in the allowed commands list");
114
- });
115
- it('should block any command if coreTools contains an empty ShellTool command list', async () => {
116
- config = {
117
- getCoreTools: () => ['ShellTool()'],
118
- getExcludeTools: () => [],
119
- };
120
- const result = isCommandAllowed('any command', config);
121
- expect(result.allowed).toBe(false);
122
- expect(result.reason).toBe("Command 'any command' is not in the allowed commands list");
123
- });
124
- it('should block a command with extra whitespace if it is in the blocked list', async () => {
125
- config = {
126
- getCoreTools: () => undefined,
127
- getExcludeTools: () => ['ShellTool(rm -rf /)'],
128
- };
129
- const result = isCommandAllowed(' rm -rf / ', config);
130
- expect(result.allowed).toBe(false);
131
- expect(result.reason).toBe("Command 'rm -rf /' is blocked by configuration");
132
- });
133
- it('should allow any command when ShellTool is in present with specific commands', async () => {
134
- config = {
135
- getCoreTools: () => ['ShellTool', 'ShellTool(ls)'],
136
- getExcludeTools: () => [],
137
- };
138
- const result = isCommandAllowed('any command', config);
139
- expect(result.allowed).toBe(true);
140
- });
141
- it('should block a command on the blocklist even with a wildcard allow', async () => {
142
- config = {
143
- getCoreTools: () => ['ShellTool'],
144
- getExcludeTools: () => ['ShellTool(rm -rf /)'],
145
- };
146
- const result = isCommandAllowed('rm -rf /', config);
147
- expect(result.allowed).toBe(false);
148
- expect(result.reason).toBe("Command 'rm -rf /' is blocked by configuration");
149
- });
150
- it('should allow a command that starts with an allowed command prefix', async () => {
151
- config = {
152
- getCoreTools: () => ['ShellTool(gh issue edit)'],
153
- getExcludeTools: () => [],
154
- };
155
- const result = isCommandAllowed('gh issue edit 1 --add-label "kind/feature"', config);
156
- expect(result.allowed).toBe(true);
157
- });
158
- it('should allow a command that starts with an allowed command prefix using the public-facing name', async () => {
159
- config = {
160
- getCoreTools: () => ['run_shell_command(gh issue edit)'],
161
- getExcludeTools: () => [],
162
- };
163
- const result = isCommandAllowed('gh issue edit 1 --add-label "kind/feature"', config);
164
- expect(result.allowed).toBe(true);
165
- });
166
- it('should not allow a command that starts with an allowed command prefix but is chained with another command', async () => {
167
- config = {
168
- getCoreTools: () => ['run_shell_command(gh issue edit)'],
169
- getExcludeTools: () => [],
170
- };
171
- const result = isCommandAllowed('gh issue edit&&rm -rf /', config);
172
- expect(result.allowed).toBe(false);
173
- expect(result.reason).toBe("Command 'rm -rf /' is not in the allowed commands list");
174
- });
175
- it('should not allow a command that is a prefix of an allowed command', async () => {
176
- config = {
177
- getCoreTools: () => ['run_shell_command(gh issue edit)'],
178
- getExcludeTools: () => [],
179
- };
180
- const result = isCommandAllowed('gh issue', config);
181
- expect(result.allowed).toBe(false);
182
- expect(result.reason).toBe("Command 'gh issue' is not in the allowed commands list");
183
- });
184
- it('should not allow a command that is a prefix of a blocked command', async () => {
185
- config = {
186
- getCoreTools: () => [],
187
- getExcludeTools: () => ['run_shell_command(gh issue edit)'],
188
- };
189
- const result = isCommandAllowed('gh issue', config);
190
- expect(result.allowed).toBe(true);
60
+ expect(result.reason).toBe(`Command 'rm -rf /' is blocked by configuration`);
191
61
  });
192
- it('should not allow a command that is chained with a pipe', async () => {
193
- config = {
194
- getCoreTools: () => ['run_shell_command(gh issue list)'],
195
- getExcludeTools: () => [],
196
- };
197
- const result = isCommandAllowed('gh issue list | rm -rf /', config);
198
- expect(result.allowed).toBe(false);
199
- expect(result.reason).toBe("Command 'rm -rf /' is not in the allowed commands list");
200
- });
201
- it('should not allow a command that is chained with a semicolon', async () => {
202
- config = {
203
- getCoreTools: () => ['run_shell_command(gh issue list)'],
204
- getExcludeTools: () => [],
205
- };
206
- const result = isCommandAllowed('gh issue list; rm -rf /', config);
207
- expect(result.allowed).toBe(false);
208
- expect(result.reason).toBe("Command 'rm -rf /' is not in the allowed commands list");
209
- });
210
- it('should block a chained command if any part is blocked', async () => {
211
- config = {
212
- getCoreTools: () => ['run_shell_command(echo "hello")'],
213
- getExcludeTools: () => ['run_shell_command(rm)'],
214
- };
215
- const result = isCommandAllowed('echo "hello" && rm -rf /', config);
216
- expect(result.allowed).toBe(false);
217
- expect(result.reason).toBe("Command 'rm -rf /' is blocked by configuration");
218
- });
219
- it('should block a command if its prefix is on the blocklist, even if the command itself is on the allowlist', async () => {
220
- config = {
221
- getCoreTools: () => ['run_shell_command(git push)'],
222
- getExcludeTools: () => ['run_shell_command(git)'],
223
- };
224
- const result = isCommandAllowed('git push', config);
225
- expect(result.allowed).toBe(false);
226
- expect(result.reason).toBe("Command 'git push' is blocked by configuration");
227
- });
228
- it('should be case-sensitive in its matching', async () => {
229
- config = {
230
- getCoreTools: () => ['run_shell_command(echo)'],
231
- getExcludeTools: () => [],
232
- };
233
- const result = isCommandAllowed('ECHO "hello"', config);
234
- expect(result.allowed).toBe(false);
235
- expect(result.reason).toBe('Command \'ECHO "hello"\' is not in the allowed commands list');
236
- });
237
- it('should correctly handle commands with extra whitespace around chaining operators', async () => {
238
- config = {
239
- getCoreTools: () => ['run_shell_command(ls -l)'],
240
- getExcludeTools: () => ['run_shell_command(rm)'],
241
- };
242
- const result = isCommandAllowed('ls -l ; rm -rf /', config);
243
- expect(result.allowed).toBe(false);
244
- expect(result.reason).toBe("Command 'rm -rf /' is blocked by configuration");
245
- });
246
- it('should allow a chained command if all parts are allowed', async () => {
247
- config = {
248
- getCoreTools: () => [
249
- 'run_shell_command(echo)',
250
- 'run_shell_command(ls -l)',
251
- ],
252
- getExcludeTools: () => [],
253
- };
62
+ it('should allow a chained command if all parts are on the global allowlist', () => {
63
+ config.getCoreTools = () => [
64
+ 'run_shell_command(echo)',
65
+ 'run_shell_command(ls)',
66
+ ];
254
67
  const result = isCommandAllowed('echo "hello" && ls -l', config);
255
68
  expect(result.allowed).toBe(true);
256
69
  });
257
- it('should block a command with command substitution using backticks', async () => {
258
- config = {
259
- getCoreTools: () => ['run_shell_command(echo)'],
260
- getExcludeTools: () => [],
261
- };
262
- const result = isCommandAllowed('echo `rm -rf /`', config);
263
- expect(result.allowed).toBe(false);
264
- expect(result.reason).toBe('Command substitution using $(), <(), or >() is not allowed for security reasons');
265
- });
266
- it('should block a command with command substitution using $()', async () => {
267
- config = {
268
- getCoreTools: () => ['run_shell_command(echo)'],
269
- getExcludeTools: () => [],
270
- };
271
- const result = isCommandAllowed('echo $(rm -rf /)', config);
272
- expect(result.allowed).toBe(false);
273
- expect(result.reason).toBe('Command substitution using $(), <(), or >() is not allowed for security reasons');
274
- });
275
- it('should block a command with process substitution using <()', async () => {
276
- config = {
277
- getCoreTools: () => ['run_shell_command(diff)'],
278
- getExcludeTools: () => [],
279
- };
280
- const result = isCommandAllowed('diff <(ls) <(ls -a)', config);
70
+ it('should block a chained command if any part is blocked', () => {
71
+ config.getExcludeTools = () => ['run_shell_command(rm)'];
72
+ const result = isCommandAllowed('echo "hello" && rm -rf /', config);
281
73
  expect(result.allowed).toBe(false);
282
- expect(result.reason).toBe('Command substitution using $(), <(), or >() is not allowed for security reasons');
74
+ expect(result.reason).toBe(`Command 'rm -rf /' is blocked by configuration`);
75
+ });
76
+ describe('command substitution', () => {
77
+ it('should block command substitution using `$(...)`', () => {
78
+ const result = isCommandAllowed('echo $(rm -rf /)', config);
79
+ expect(result.allowed).toBe(false);
80
+ expect(result.reason).toContain('Command substitution');
81
+ });
82
+ it('should block command substitution using `<(...)`', () => {
83
+ const result = isCommandAllowed('diff <(ls) <(ls -a)', config);
84
+ expect(result.allowed).toBe(false);
85
+ expect(result.reason).toContain('Command substitution');
86
+ });
87
+ it('should block command substitution using backticks', () => {
88
+ const result = isCommandAllowed('echo `rm -rf /`', config);
89
+ expect(result.allowed).toBe(false);
90
+ expect(result.reason).toContain('Command substitution');
91
+ });
92
+ it('should allow substitution-like patterns inside single quotes', () => {
93
+ config.getCoreTools = () => ['ShellTool(echo)'];
94
+ const result = isCommandAllowed("echo '$(pwd)'", config);
95
+ expect(result.allowed).toBe(true);
96
+ });
283
97
  });
284
- it('should allow a command with I/O redirection', async () => {
285
- config = {
286
- getCoreTools: () => ['run_shell_command(echo)'],
287
- getExcludeTools: () => [],
288
- };
289
- const result = isCommandAllowed('echo "hello" > file.txt', config);
290
- expect(result.allowed).toBe(true);
291
- });
292
- it('should not allow a command that is chained with a double pipe', async () => {
293
- config = {
294
- getCoreTools: () => ['run_shell_command(gh issue list)'],
295
- getExcludeTools: () => [],
296
- };
297
- const result = isCommandAllowed('gh issue list || rm -rf /', config);
298
- expect(result.allowed).toBe(false);
299
- expect(result.reason).toBe("Command 'rm -rf /' is not in the allowed commands list");
98
+ });
99
+ describe('checkCommandPermissions', () => {
100
+ describe('in "Default Allow" mode (no sessionAllowlist)', () => {
101
+ it('should return a detailed success object for an allowed command', () => {
102
+ const result = checkCommandPermissions('ls -l', config);
103
+ expect(result).toEqual({
104
+ allAllowed: true,
105
+ disallowedCommands: [],
106
+ });
107
+ });
108
+ it('should return a detailed failure object for a blocked command', () => {
109
+ config.getExcludeTools = () => ['ShellTool(rm)'];
110
+ const result = checkCommandPermissions('rm -rf /', config);
111
+ expect(result).toEqual({
112
+ allAllowed: false,
113
+ disallowedCommands: ['rm -rf /'],
114
+ blockReason: `Command 'rm -rf /' is blocked by configuration`,
115
+ isHardDenial: true,
116
+ });
117
+ });
118
+ it('should return a detailed failure object for a command not on a strict allowlist', () => {
119
+ config.getCoreTools = () => ['ShellTool(ls)'];
120
+ const result = checkCommandPermissions('git status && ls', config);
121
+ expect(result).toEqual({
122
+ allAllowed: false,
123
+ disallowedCommands: ['git status'],
124
+ blockReason: `Command(s) not in the allowed commands list.`,
125
+ isHardDenial: false,
126
+ });
127
+ });
128
+ });
129
+ describe('in "Default Deny" mode (with sessionAllowlist)', () => {
130
+ it('should allow a command on the sessionAllowlist', () => {
131
+ const result = checkCommandPermissions('ls -l', config, new Set(['ls -l']));
132
+ expect(result.allAllowed).toBe(true);
133
+ });
134
+ it('should block a command not on the sessionAllowlist or global allowlist', () => {
135
+ const result = checkCommandPermissions('rm -rf /', config, new Set(['ls -l']));
136
+ expect(result.allAllowed).toBe(false);
137
+ expect(result.blockReason).toContain('not on the global or session allowlist');
138
+ expect(result.disallowedCommands).toEqual(['rm -rf /']);
139
+ });
140
+ it('should allow a command on the global allowlist even if not on the session allowlist', () => {
141
+ config.getCoreTools = () => ['ShellTool(git status)'];
142
+ const result = checkCommandPermissions('git status', config, new Set(['ls -l']));
143
+ expect(result.allAllowed).toBe(true);
144
+ });
145
+ it('should allow a chained command if parts are on different allowlists', () => {
146
+ config.getCoreTools = () => ['ShellTool(git status)'];
147
+ const result = checkCommandPermissions('git status && git commit', config, new Set(['git commit']));
148
+ expect(result.allAllowed).toBe(true);
149
+ });
150
+ it('should block a command on the sessionAllowlist if it is also globally blocked', () => {
151
+ config.getExcludeTools = () => ['run_shell_command(rm)'];
152
+ const result = checkCommandPermissions('rm -rf /', config, new Set(['rm -rf /']));
153
+ expect(result.allAllowed).toBe(false);
154
+ expect(result.blockReason).toContain('is blocked by configuration');
155
+ });
156
+ it('should block a chained command if one part is not on any allowlist', () => {
157
+ config.getCoreTools = () => ['run_shell_command(echo)'];
158
+ const result = checkCommandPermissions('echo "hello" && rm -rf /', config, new Set(['echo']));
159
+ expect(result.allAllowed).toBe(false);
160
+ expect(result.disallowedCommands).toEqual(['rm -rf /']);
161
+ });
300
162
  });
301
163
  });
302
164
  describe('getCommandRoots', () => {
303
165
  it('should return a single command', () => {
304
- const result = getCommandRoots('ls -l');
305
- expect(result).toEqual(['ls']);
166
+ expect(getCommandRoots('ls -l')).toEqual(['ls']);
306
167
  });
307
- it('should return multiple commands', () => {
308
- const result = getCommandRoots('ls -l | grep "test"');
309
- expect(result).toEqual(['ls', 'grep']);
168
+ it('should handle paths and return the binary name', () => {
169
+ expect(getCommandRoots('/usr/local/bin/node script.js')).toEqual(['node']);
310
170
  });
311
- it('should handle multiple commands with &&', () => {
312
- const result = getCommandRoots('npm run build && npm test');
313
- expect(result).toEqual(['npm', 'npm']);
314
- });
315
- it('should handle multiple commands with ;', () => {
316
- const result = getCommandRoots('echo "hello"; echo "world"');
317
- expect(result).toEqual(['echo', 'echo']);
171
+ it('should return an empty array for an empty string', () => {
172
+ expect(getCommandRoots('')).toEqual([]);
318
173
  });
319
174
  it('should handle a mix of operators', () => {
320
- const result = getCommandRoots('cat package.json | grep "version" && echo "done"');
321
- expect(result).toEqual(['cat', 'grep', 'echo']);
322
- });
323
- it('should handle commands with paths', () => {
324
- const result = getCommandRoots('/usr/local/bin/node script.js');
325
- expect(result).toEqual(['node']);
175
+ const result = getCommandRoots('a;b|c&&d||e&f');
176
+ expect(result).toEqual(['a', 'b', 'c', 'd', 'e', 'f']);
326
177
  });
327
- it('should return an empty array for an empty string', () => {
328
- const result = getCommandRoots('');
329
- expect(result).toEqual([]);
178
+ it('should correctly parse a chained command with quotes', () => {
179
+ const result = getCommandRoots('echo "hello" && git commit -m "feat"');
180
+ expect(result).toEqual(['echo', 'git']);
330
181
  });
331
182
  });
332
183
  describe('stripShellWrapper', () => {
333
- it('should strip sh -c from the beginning of the command', () => {
334
- const result = stripShellWrapper('sh -c "ls -l"');
335
- expect(result).toEqual('ls -l');
336
- });
337
- it('should strip bash -c from the beginning of the command', () => {
338
- const result = stripShellWrapper('bash -c "ls -l"');
339
- expect(result).toEqual('ls -l');
340
- });
341
- it('should strip zsh -c from the beginning of the command', () => {
342
- const result = stripShellWrapper('zsh -c "ls -l"');
343
- expect(result).toEqual('ls -l');
344
- });
345
- it('should not strip anything if the command does not start with a shell wrapper', () => {
346
- const result = stripShellWrapper('ls -l');
347
- expect(result).toEqual('ls -l');
348
- });
349
- it('should handle extra whitespace', () => {
350
- const result = stripShellWrapper(' sh -c "ls -l" ');
351
- expect(result).toEqual('ls -l');
352
- });
353
- it('should handle commands without quotes', () => {
354
- const result = stripShellWrapper('sh -c ls -l');
355
- expect(result).toEqual('ls -l');
356
- });
357
- it('should strip cmd.exe /c from the beginning of the command', () => {
358
- const result = stripShellWrapper('cmd.exe /c "dir"');
359
- expect(result).toEqual('dir');
360
- });
361
- });
362
- describe('getCommandRoots', () => {
363
- it('should handle multiple commands with &', () => {
364
- const result = getCommandRoots('echo "hello" & echo "world"');
365
- expect(result).toEqual(['echo', 'echo']);
366
- });
367
- });
368
- describe('command substitution', () => {
369
- let config;
370
- beforeEach(() => {
371
- config = {
372
- getCoreTools: () => ['run_shell_command(echo)', 'run_shell_command(gh)'],
373
- getExcludeTools: () => [],
374
- };
375
- });
376
- it('should block unquoted command substitution `$(...)`', () => {
377
- const result = isCommandAllowed('echo $(pwd)', config);
378
- expect(result.allowed).toBe(false);
184
+ it('should strip sh -c with quotes', () => {
185
+ expect(stripShellWrapper('sh -c "ls -l"')).toEqual('ls -l');
379
186
  });
380
- it('should block unquoted command substitution `<(...)`', () => {
381
- const result = isCommandAllowed('echo <(pwd)', config);
382
- expect(result.allowed).toBe(false);
383
- });
384
- it('should allow command substitution in single quotes', () => {
385
- const result = isCommandAllowed("echo '$(pwd)'", config);
386
- expect(result.allowed).toBe(true);
187
+ it('should strip bash -c with extra whitespace', () => {
188
+ expect(stripShellWrapper(' bash -c "ls -l" ')).toEqual('ls -l');
387
189
  });
388
- it('should allow backticks in single quotes', () => {
389
- const result = isCommandAllowed("echo '`rm -rf /`'", config);
390
- expect(result.allowed).toBe(true);
190
+ it('should strip zsh -c without quotes', () => {
191
+ expect(stripShellWrapper('zsh -c ls -l')).toEqual('ls -l');
391
192
  });
392
- it('should block command substitution in double quotes', () => {
393
- const result = isCommandAllowed('echo "$(pwd)"', config);
394
- expect(result.allowed).toBe(false);
395
- });
396
- it('should allow escaped command substitution', () => {
397
- const result = isCommandAllowed('echo \\$(pwd)', config);
398
- expect(result.allowed).toBe(true);
399
- });
400
- it('should allow complex commands with quoted substitution-like patterns', () => {
401
- const command = "gh pr comment 4795 --body 'This is a test comment with $(pwd) style text'";
402
- const result = isCommandAllowed(command, config);
403
- expect(result.allowed).toBe(true);
404
- });
405
- it('should block complex commands with unquoted substitution-like patterns', () => {
406
- const command = 'gh pr comment 4795 --body "This is a test comment with $(pwd) style text"';
407
- const result = isCommandAllowed(command, config);
408
- expect(result.allowed).toBe(false);
409
- });
410
- it('should allow a command with markdown content using proper quoting', () => {
411
- // Simple test with safe content in single quotes
412
- const result = isCommandAllowed("gh pr comment 4795 --body 'This is safe markdown content'", config);
413
- expect(result.allowed).toBe(true);
193
+ it('should strip cmd.exe /c', () => {
194
+ expect(stripShellWrapper('cmd.exe /c "dir"')).toEqual('dir');
414
195
  });
415
- });
416
- describe('getCommandRoots with quote handling', () => {
417
- it('should correctly parse a simple command', () => {
418
- const result = getCommandRoots('git status');
419
- expect(result).toEqual(['git']);
420
- });
421
- it('should correctly parse a command with a quoted argument', () => {
422
- const result = getCommandRoots('git commit -m "feat: new feature"');
423
- expect(result).toEqual(['git']);
424
- });
425
- it('should correctly parse a command with single quotes', () => {
426
- const result = getCommandRoots("echo 'hello world'");
427
- expect(result).toEqual(['echo']);
428
- });
429
- it('should correctly parse a chained command with quotes', () => {
430
- const result = getCommandRoots('echo "hello" && git status');
431
- expect(result).toEqual(['echo', 'git']);
432
- });
433
- it('should correctly parse a complex chained command', () => {
434
- const result = getCommandRoots('git commit -m "feat: new feature" && echo "done"');
435
- expect(result).toEqual(['git', 'echo']);
436
- });
437
- it('should handle escaped quotes', () => {
438
- const result = getCommandRoots('echo "this is a "quote""');
439
- expect(result).toEqual(['echo']);
440
- });
441
- it('should handle commands with no spaces', () => {
442
- const result = getCommandRoots('command');
443
- expect(result).toEqual(['command']);
444
- });
445
- it('should handle multiple separators', () => {
446
- const result = getCommandRoots('a;b|c&&d||e&f');
447
- expect(result).toEqual(['a', 'b', 'c', 'd', 'e', 'f']);
196
+ it('should not strip anything if no wrapper is present', () => {
197
+ expect(stripShellWrapper('ls -l')).toEqual('ls -l');
448
198
  });
449
199
  });
450
200
  //# sourceMappingURL=shell-utils.test.js.map