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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (422) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +2 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +1 -1
  5. package/dist/src/agents/codebase-investigator.test.d.ts +6 -0
  6. package/dist/src/agents/codebase-investigator.test.js +35 -0
  7. package/dist/src/agents/codebase-investigator.test.js.map +1 -0
  8. package/dist/src/agents/executor.d.ts +3 -0
  9. package/dist/src/agents/executor.js +21 -0
  10. package/dist/src/agents/executor.js.map +1 -1
  11. package/dist/src/agents/executor.test.js +358 -3
  12. package/dist/src/agents/executor.test.js.map +1 -1
  13. package/dist/src/code_assist/codeAssist.test.d.ts +6 -0
  14. package/dist/src/code_assist/codeAssist.test.js +99 -0
  15. package/dist/src/code_assist/codeAssist.test.js.map +1 -0
  16. package/dist/src/code_assist/experiments/client_metadata.js +2 -1
  17. package/dist/src/code_assist/experiments/client_metadata.js.map +1 -1
  18. package/dist/src/code_assist/experiments/client_metadata.test.d.ts +6 -0
  19. package/dist/src/code_assist/experiments/client_metadata.test.js +99 -0
  20. package/dist/src/code_assist/experiments/client_metadata.test.js.map +1 -0
  21. package/dist/src/code_assist/experiments/experiments.js +2 -2
  22. package/dist/src/code_assist/experiments/experiments.js.map +1 -1
  23. package/dist/src/code_assist/experiments/experiments.test.d.ts +6 -0
  24. package/dist/src/code_assist/experiments/experiments.test.js +92 -0
  25. package/dist/src/code_assist/experiments/experiments.test.js.map +1 -0
  26. package/dist/src/code_assist/experiments/flagNames.d.ts +13 -0
  27. package/dist/src/code_assist/experiments/flagNames.js +13 -0
  28. package/dist/src/code_assist/experiments/flagNames.js.map +1 -0
  29. package/dist/src/code_assist/experiments/types.d.ts +1 -1
  30. package/dist/src/code_assist/oauth-credential-storage.test.js +49 -0
  31. package/dist/src/code_assist/oauth-credential-storage.test.js.map +1 -1
  32. package/dist/src/code_assist/server.js +5 -8
  33. package/dist/src/code_assist/server.js.map +1 -1
  34. package/dist/src/code_assist/server.test.js +109 -28
  35. package/dist/src/code_assist/server.test.js.map +1 -1
  36. package/dist/src/config/config.d.ts +34 -2
  37. package/dist/src/config/config.js +147 -26
  38. package/dist/src/config/config.js.map +1 -1
  39. package/dist/src/config/config.test.js +436 -19
  40. package/dist/src/config/config.test.js.map +1 -1
  41. package/dist/src/config/defaultModelConfigs.d.ts +7 -0
  42. package/dist/src/config/defaultModelConfigs.js +158 -0
  43. package/dist/src/config/defaultModelConfigs.js.map +1 -0
  44. package/dist/src/config/models.d.ts +22 -1
  45. package/dist/src/config/models.js +49 -6
  46. package/dist/src/config/models.js.map +1 -1
  47. package/dist/src/config/models.test.js +71 -10
  48. package/dist/src/config/models.test.js.map +1 -1
  49. package/dist/src/confirmation-bus/message-bus.d.ts +1 -1
  50. package/dist/src/confirmation-bus/message-bus.js +2 -2
  51. package/dist/src/confirmation-bus/message-bus.js.map +1 -1
  52. package/dist/src/confirmation-bus/message-bus.test.js +30 -24
  53. package/dist/src/confirmation-bus/message-bus.test.js.map +1 -1
  54. package/dist/src/confirmation-bus/types.d.ts +1 -0
  55. package/dist/src/core/baseLlmClient.d.ts +4 -8
  56. package/dist/src/core/baseLlmClient.js +3 -8
  57. package/dist/src/core/baseLlmClient.js.map +1 -1
  58. package/dist/src/core/baseLlmClient.test.js +22 -27
  59. package/dist/src/core/baseLlmClient.test.js.map +1 -1
  60. package/dist/src/core/client.d.ts +6 -5
  61. package/dist/src/core/client.js +33 -33
  62. package/dist/src/core/client.js.map +1 -1
  63. package/dist/src/core/client.test.js +40 -22
  64. package/dist/src/core/client.test.js.map +1 -1
  65. package/dist/src/core/coreToolScheduler.js +7 -1
  66. package/dist/src/core/coreToolScheduler.js.map +1 -1
  67. package/dist/src/core/coreToolScheduler.test.js +151 -357
  68. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  69. package/dist/src/core/geminiChat.d.ts +6 -4
  70. package/dist/src/core/geminiChat.js +106 -29
  71. package/dist/src/core/geminiChat.js.map +1 -1
  72. package/dist/src/core/geminiChat.test.js +317 -16
  73. package/dist/src/core/geminiChat.test.js.map +1 -1
  74. package/dist/src/core/logger.d.ts +7 -2
  75. package/dist/src/core/logger.js +15 -9
  76. package/dist/src/core/logger.js.map +1 -1
  77. package/dist/src/core/logger.test.js +31 -16
  78. package/dist/src/core/logger.test.js.map +1 -1
  79. package/dist/src/core/loggingContentGenerator.test.d.ts +6 -0
  80. package/dist/src/core/loggingContentGenerator.test.js +180 -0
  81. package/dist/src/core/loggingContentGenerator.test.js.map +1 -0
  82. package/dist/src/core/nonInteractiveToolExecutor.test.js +1 -0
  83. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  84. package/dist/src/core/prompts.js +8 -11
  85. package/dist/src/core/prompts.js.map +1 -1
  86. package/dist/src/core/tokenLimits.test.d.ts +6 -0
  87. package/dist/src/core/tokenLimits.test.js +26 -0
  88. package/dist/src/core/tokenLimits.test.js.map +1 -0
  89. package/dist/src/fallback/handler.js +52 -7
  90. package/dist/src/fallback/handler.js.map +1 -1
  91. package/dist/src/fallback/handler.test.js +69 -16
  92. package/dist/src/fallback/handler.test.js.map +1 -1
  93. package/dist/src/fallback/types.d.ts +1 -1
  94. package/dist/src/generated/git-commit.d.ts +2 -2
  95. package/dist/src/generated/git-commit.js +2 -2
  96. package/dist/src/hooks/hookAggregator.d.ts +68 -0
  97. package/dist/src/hooks/hookAggregator.js +262 -0
  98. package/dist/src/hooks/hookAggregator.js.map +1 -0
  99. package/dist/src/hooks/hookAggregator.test.d.ts +6 -0
  100. package/dist/src/hooks/hookAggregator.test.js +387 -0
  101. package/dist/src/hooks/hookAggregator.test.js.map +1 -0
  102. package/dist/src/hooks/hookRunner.d.ts +42 -0
  103. package/dist/src/hooks/hookRunner.js +272 -0
  104. package/dist/src/hooks/hookRunner.js.map +1 -0
  105. package/dist/src/hooks/hookRunner.test.d.ts +6 -0
  106. package/dist/src/hooks/hookRunner.test.js +468 -0
  107. package/dist/src/hooks/hookRunner.test.js.map +1 -0
  108. package/dist/src/hooks/hookTranslator.d.ts +3 -3
  109. package/dist/src/hooks/types.js +1 -1
  110. package/dist/src/hooks/types.js.map +1 -1
  111. package/dist/src/hooks/types.test.js +280 -2
  112. package/dist/src/hooks/types.test.js.map +1 -1
  113. package/dist/src/ide/detect-ide.d.ts +4 -0
  114. package/dist/src/ide/detect-ide.js +6 -1
  115. package/dist/src/ide/detect-ide.js.map +1 -1
  116. package/dist/src/ide/detect-ide.test.js +5 -0
  117. package/dist/src/ide/detect-ide.test.js.map +1 -1
  118. package/dist/src/ide/ide-client.d.ts +3 -1
  119. package/dist/src/ide/ide-client.js +9 -8
  120. package/dist/src/ide/ide-client.js.map +1 -1
  121. package/dist/src/ide/ide-client.test.js +159 -0
  122. package/dist/src/ide/ide-client.test.js.map +1 -1
  123. package/dist/src/ide/ide-installer.js +65 -20
  124. package/dist/src/ide/ide-installer.js.map +1 -1
  125. package/dist/src/ide/ide-installer.test.js +41 -0
  126. package/dist/src/ide/ide-installer.test.js.map +1 -1
  127. package/dist/src/ide/types.d.ts +1 -1
  128. package/dist/src/ide/types.js +1 -1
  129. package/dist/src/index.d.ts +2 -0
  130. package/dist/src/index.js +2 -0
  131. package/dist/src/index.js.map +1 -1
  132. package/dist/src/mcp/google-auth-provider.js +1 -1
  133. package/dist/src/mcp/google-auth-provider.js.map +1 -1
  134. package/dist/src/mcp/mcpLauncher.js +6 -2
  135. package/dist/src/mcp/mcpLauncher.js.map +1 -1
  136. package/dist/src/mcp/oauth-provider.js +2 -2
  137. package/dist/src/mcp/oauth-provider.js.map +1 -1
  138. package/dist/src/mcp/oauth-provider.test.js +177 -0
  139. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  140. package/dist/src/mcp/sa-impersonation-provider.js +1 -1
  141. package/dist/src/mcp/sa-impersonation-provider.js.map +1 -1
  142. package/dist/src/policy/config.js +3 -1
  143. package/dist/src/policy/config.js.map +1 -1
  144. package/dist/src/policy/config.test.js +135 -1
  145. package/dist/src/policy/config.test.js.map +1 -1
  146. package/dist/src/policy/policies/discovered.toml +8 -0
  147. package/dist/src/policy/policies/write.toml +10 -0
  148. package/dist/src/policy/policy-engine.d.ts +12 -3
  149. package/dist/src/policy/policy-engine.js +71 -9
  150. package/dist/src/policy/policy-engine.js.map +1 -1
  151. package/dist/src/policy/policy-engine.test.js +460 -76
  152. package/dist/src/policy/policy-engine.test.js.map +1 -1
  153. package/dist/src/policy/toml-loader.d.ts +2 -1
  154. package/dist/src/policy/toml-loader.js +103 -6
  155. package/dist/src/policy/toml-loader.js.map +1 -1
  156. package/dist/src/policy/toml-loader.test.js +222 -368
  157. package/dist/src/policy/toml-loader.test.js.map +1 -1
  158. package/dist/src/policy/types.d.ts +65 -0
  159. package/dist/src/policy/types.js +4 -0
  160. package/dist/src/policy/types.js.map +1 -1
  161. package/dist/src/prompts/mcp-prompts.test.d.ts +6 -0
  162. package/dist/src/prompts/mcp-prompts.test.js +40 -0
  163. package/dist/src/prompts/mcp-prompts.test.js.map +1 -0
  164. package/dist/src/prompts/prompt-registry.test.d.ts +6 -0
  165. package/dist/src/prompts/prompt-registry.test.js +111 -0
  166. package/dist/src/prompts/prompt-registry.test.js.map +1 -0
  167. package/dist/src/routing/modelRouterService.js +15 -0
  168. package/dist/src/routing/modelRouterService.js.map +1 -1
  169. package/dist/src/routing/modelRouterService.test.js +62 -0
  170. package/dist/src/routing/modelRouterService.test.js.map +1 -1
  171. package/dist/src/routing/strategies/classifierStrategy.d.ts +1 -1
  172. package/dist/src/routing/strategies/classifierStrategy.js +6 -14
  173. package/dist/src/routing/strategies/classifierStrategy.js.map +1 -1
  174. package/dist/src/routing/strategies/classifierStrategy.test.js +13 -10
  175. package/dist/src/routing/strategies/classifierStrategy.test.js.map +1 -1
  176. package/dist/src/routing/strategies/fallbackStrategy.js +1 -1
  177. package/dist/src/routing/strategies/fallbackStrategy.js.map +1 -1
  178. package/dist/src/routing/strategies/fallbackStrategy.test.js +4 -0
  179. package/dist/src/routing/strategies/fallbackStrategy.test.js.map +1 -1
  180. package/dist/src/routing/strategies/overrideStrategy.js +2 -2
  181. package/dist/src/routing/strategies/overrideStrategy.js.map +1 -1
  182. package/dist/src/routing/strategies/overrideStrategy.test.js +3 -0
  183. package/dist/src/routing/strategies/overrideStrategy.test.js.map +1 -1
  184. package/dist/src/safety/built-in.d.ts +21 -0
  185. package/dist/src/safety/built-in.js +106 -0
  186. package/dist/src/safety/built-in.js.map +1 -0
  187. package/dist/src/safety/built-in.test.d.ts +6 -0
  188. package/dist/src/safety/built-in.test.js +199 -0
  189. package/dist/src/safety/built-in.test.js.map +1 -0
  190. package/dist/src/safety/checker-runner.d.ts +48 -0
  191. package/dist/src/safety/checker-runner.js +208 -0
  192. package/dist/src/safety/checker-runner.js.map +1 -0
  193. package/dist/src/safety/checker-runner.test.d.ts +6 -0
  194. package/dist/src/safety/checker-runner.test.js +238 -0
  195. package/dist/src/safety/checker-runner.test.js.map +1 -0
  196. package/dist/src/safety/context-builder.d.ts +23 -0
  197. package/dist/src/safety/context-builder.js +47 -0
  198. package/dist/src/safety/context-builder.js.map +1 -0
  199. package/dist/src/safety/context-builder.test.d.ts +6 -0
  200. package/dist/src/safety/context-builder.test.js +49 -0
  201. package/dist/src/safety/context-builder.test.js.map +1 -0
  202. package/dist/src/safety/protocol.d.ts +88 -0
  203. package/dist/src/safety/protocol.js +15 -0
  204. package/dist/src/safety/protocol.js.map +1 -0
  205. package/dist/src/safety/registry.d.ts +26 -0
  206. package/dist/src/safety/registry.js +65 -0
  207. package/dist/src/safety/registry.js.map +1 -0
  208. package/dist/src/safety/registry.test.d.ts +6 -0
  209. package/dist/src/safety/registry.test.js +31 -0
  210. package/dist/src/safety/registry.test.js.map +1 -0
  211. package/dist/src/services/chatCompressionService.test.js +1 -0
  212. package/dist/src/services/chatCompressionService.test.js.map +1 -1
  213. package/dist/src/services/gitService.js +1 -1
  214. package/dist/src/services/gitService.js.map +1 -1
  215. package/dist/src/services/gitService.test.js +1 -1
  216. package/dist/src/services/gitService.test.js.map +1 -1
  217. package/dist/src/services/loopDetectionService.d.ts +3 -0
  218. package/dist/src/services/loopDetectionService.js +81 -42
  219. package/dist/src/services/loopDetectionService.js.map +1 -1
  220. package/dist/src/services/loopDetectionService.test.js +101 -1
  221. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  222. package/dist/src/services/modelConfig.golden.test.d.ts +6 -0
  223. package/dist/src/services/modelConfig.golden.test.js +42 -0
  224. package/dist/src/services/modelConfig.golden.test.js.map +1 -0
  225. package/dist/src/services/modelConfig.integration.test.d.ts +6 -0
  226. package/dist/src/services/modelConfig.integration.test.js +213 -0
  227. package/dist/src/services/modelConfig.integration.test.js.map +1 -0
  228. package/dist/src/services/modelConfigService.d.ts +46 -0
  229. package/dist/src/services/modelConfigService.js +146 -0
  230. package/dist/src/services/modelConfigService.js.map +1 -0
  231. package/dist/src/services/modelConfigService.test.d.ts +6 -0
  232. package/dist/src/services/modelConfigService.test.js +509 -0
  233. package/dist/src/services/modelConfigService.test.js.map +1 -0
  234. package/dist/src/services/test-data/resolved-aliases.golden.json +169 -0
  235. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +11 -9
  236. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +174 -150
  237. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  238. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +1 -0
  239. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +76 -20
  240. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  241. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +6 -1
  242. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +18 -5
  243. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  244. package/dist/src/telemetry/index.d.ts +2 -2
  245. package/dist/src/telemetry/index.js +2 -2
  246. package/dist/src/telemetry/index.js.map +1 -1
  247. package/dist/src/telemetry/loggers.d.ts +7 -7
  248. package/dist/src/telemetry/loggers.js +23 -23
  249. package/dist/src/telemetry/loggers.js.map +1 -1
  250. package/dist/src/telemetry/loggers.test.circular.js +0 -1
  251. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  252. package/dist/src/telemetry/loggers.test.js +72 -18
  253. package/dist/src/telemetry/loggers.test.js.map +1 -1
  254. package/dist/src/telemetry/metrics.d.ts +8 -4
  255. package/dist/src/telemetry/metrics.js +10 -4
  256. package/dist/src/telemetry/metrics.js.map +1 -1
  257. package/dist/src/telemetry/metrics.test.js +42 -0
  258. package/dist/src/telemetry/metrics.test.js.map +1 -1
  259. package/dist/src/telemetry/telemetryAttributes.js +1 -0
  260. package/dist/src/telemetry/telemetryAttributes.js.map +1 -1
  261. package/dist/src/telemetry/types.d.ts +17 -11
  262. package/dist/src/telemetry/types.js +53 -28
  263. package/dist/src/telemetry/types.js.map +1 -1
  264. package/dist/src/tools/base-tool-invocation.test.d.ts +6 -0
  265. package/dist/src/tools/base-tool-invocation.test.js +85 -0
  266. package/dist/src/tools/base-tool-invocation.test.js.map +1 -0
  267. package/dist/src/tools/edit.d.ts +1 -1
  268. package/dist/src/tools/edit.js +31 -33
  269. package/dist/src/tools/edit.js.map +1 -1
  270. package/dist/src/tools/edit.test.js +31 -20
  271. package/dist/src/tools/edit.test.js.map +1 -1
  272. package/dist/src/tools/glob.d.ts +1 -1
  273. package/dist/src/tools/glob.js +7 -7
  274. package/dist/src/tools/glob.js.map +1 -1
  275. package/dist/src/tools/glob.test.js +20 -17
  276. package/dist/src/tools/glob.test.js.map +1 -1
  277. package/dist/src/tools/grep.d.ts +1 -1
  278. package/dist/src/tools/grep.js +9 -9
  279. package/dist/src/tools/grep.js.map +1 -1
  280. package/dist/src/tools/grep.test.js +15 -12
  281. package/dist/src/tools/grep.test.js.map +1 -1
  282. package/dist/src/tools/ls.d.ts +1 -1
  283. package/dist/src/tools/ls.js +14 -15
  284. package/dist/src/tools/ls.js.map +1 -1
  285. package/dist/src/tools/ls.test.js +32 -33
  286. package/dist/src/tools/ls.test.js.map +1 -1
  287. package/dist/src/tools/mcp-client.js +24 -52
  288. package/dist/src/tools/mcp-client.js.map +1 -1
  289. package/dist/src/tools/mcp-client.test.js +18 -0
  290. package/dist/src/tools/mcp-client.test.js.map +1 -1
  291. package/dist/src/tools/mcp-tool.d.ts +1 -0
  292. package/dist/src/tools/mcp-tool.js +5 -2
  293. package/dist/src/tools/mcp-tool.js.map +1 -1
  294. package/dist/src/tools/memoryTool.js +1 -1
  295. package/dist/src/tools/memoryTool.js.map +1 -1
  296. package/dist/src/tools/memoryTool.test.js +1 -1
  297. package/dist/src/tools/memoryTool.test.js.map +1 -1
  298. package/dist/src/tools/modifiable-tool.d.ts +5 -1
  299. package/dist/src/tools/modifiable-tool.js +34 -13
  300. package/dist/src/tools/modifiable-tool.js.map +1 -1
  301. package/dist/src/tools/modifiable-tool.test.js +56 -22
  302. package/dist/src/tools/modifiable-tool.test.js.map +1 -1
  303. package/dist/src/tools/read-file.d.ts +2 -2
  304. package/dist/src/tools/read-file.js +20 -24
  305. package/dist/src/tools/read-file.js.map +1 -1
  306. package/dist/src/tools/read-file.test.js +63 -51
  307. package/dist/src/tools/read-file.test.js.map +1 -1
  308. package/dist/src/tools/read-many-files.d.ts +2 -9
  309. package/dist/src/tools/read-many-files.js +10 -21
  310. package/dist/src/tools/read-many-files.js.map +1 -1
  311. package/dist/src/tools/read-many-files.test.js +37 -35
  312. package/dist/src/tools/read-many-files.test.js.map +1 -1
  313. package/dist/src/tools/ripGrep.d.ts +25 -8
  314. package/dist/src/tools/ripGrep.js +148 -176
  315. package/dist/src/tools/ripGrep.js.map +1 -1
  316. package/dist/src/tools/ripGrep.test.js +383 -58
  317. package/dist/src/tools/ripGrep.test.js.map +1 -1
  318. package/dist/src/tools/shell.d.ts +1 -1
  319. package/dist/src/tools/shell.js +17 -15
  320. package/dist/src/tools/shell.js.map +1 -1
  321. package/dist/src/tools/shell.test.js +66 -36
  322. package/dist/src/tools/shell.test.js.map +1 -1
  323. package/dist/src/tools/smart-edit.d.ts +6 -1
  324. package/dist/src/tools/smart-edit.js +18 -17
  325. package/dist/src/tools/smart-edit.js.map +1 -1
  326. package/dist/src/tools/smart-edit.test.js +49 -24
  327. package/dist/src/tools/smart-edit.test.js.map +1 -1
  328. package/dist/src/tools/tool-registry.d.ts +29 -4
  329. package/dist/src/tools/tool-registry.js +108 -29
  330. package/dist/src/tools/tool-registry.js.map +1 -1
  331. package/dist/src/tools/tool-registry.test.js +134 -4
  332. package/dist/src/tools/tool-registry.test.js.map +1 -1
  333. package/dist/src/tools/tools.d.ts +2 -1
  334. package/dist/src/tools/tools.js +5 -2
  335. package/dist/src/tools/tools.js.map +1 -1
  336. package/dist/src/tools/web-fetch.js +2 -4
  337. package/dist/src/tools/web-fetch.js.map +1 -1
  338. package/dist/src/tools/web-fetch.test.js +11 -4
  339. package/dist/src/tools/web-fetch.test.js.map +1 -1
  340. package/dist/src/tools/web-search.js +1 -2
  341. package/dist/src/tools/web-search.js.map +1 -1
  342. package/dist/src/tools/web-search.test.js +11 -5
  343. package/dist/src/tools/web-search.test.js.map +1 -1
  344. package/dist/src/tools/write-file.js +31 -31
  345. package/dist/src/tools/write-file.js.map +1 -1
  346. package/dist/src/tools/write-file.test.js +24 -5
  347. package/dist/src/tools/write-file.test.js.map +1 -1
  348. package/dist/src/tools/write-todos.d.ts +29 -0
  349. package/dist/src/tools/write-todos.js +34 -1
  350. package/dist/src/tools/write-todos.js.map +1 -1
  351. package/dist/src/utils/editCorrector.js +4 -15
  352. package/dist/src/utils/editCorrector.js.map +1 -1
  353. package/dist/src/utils/editCorrector.test.js +16 -0
  354. package/dist/src/utils/editCorrector.test.js.map +1 -1
  355. package/dist/src/utils/editor.d.ts +3 -1
  356. package/dist/src/utils/editor.js +18 -1
  357. package/dist/src/utils/editor.js.map +1 -1
  358. package/dist/src/utils/editor.test.js +11 -0
  359. package/dist/src/utils/editor.test.js.map +1 -1
  360. package/dist/src/utils/environmentContext.js +3 -1
  361. package/dist/src/utils/environmentContext.js.map +1 -1
  362. package/dist/src/utils/environmentContext.test.js +6 -0
  363. package/dist/src/utils/environmentContext.test.js.map +1 -1
  364. package/dist/src/utils/events.d.ts +14 -11
  365. package/dist/src/utils/events.js +1 -14
  366. package/dist/src/utils/events.js.map +1 -1
  367. package/dist/src/utils/extensionLoader.d.ts +8 -0
  368. package/dist/src/utils/extensionLoader.js +61 -15
  369. package/dist/src/utils/extensionLoader.js.map +1 -1
  370. package/dist/src/utils/extensionLoader.test.js +83 -19
  371. package/dist/src/utils/extensionLoader.test.js.map +1 -1
  372. package/dist/src/utils/fileUtils.test.js +75 -60
  373. package/dist/src/utils/fileUtils.test.js.map +1 -1
  374. package/dist/src/utils/flashFallback.test.js +2 -2
  375. package/dist/src/utils/flashFallback.test.js.map +1 -1
  376. package/dist/src/utils/googleQuotaErrors.d.ts +2 -1
  377. package/dist/src/utils/googleQuotaErrors.js +20 -12
  378. package/dist/src/utils/googleQuotaErrors.js.map +1 -1
  379. package/dist/src/utils/httpErrors.d.ts +18 -0
  380. package/dist/src/utils/httpErrors.js +36 -0
  381. package/dist/src/utils/httpErrors.js.map +1 -0
  382. package/dist/src/utils/llm-edit-fixer.js +1 -2
  383. package/dist/src/utils/llm-edit-fixer.js.map +1 -1
  384. package/dist/src/utils/llm-edit-fixer.test.js +16 -1
  385. package/dist/src/utils/llm-edit-fixer.test.js.map +1 -1
  386. package/dist/src/utils/memoryDiscovery.d.ts +8 -0
  387. package/dist/src/utils/memoryDiscovery.js +24 -0
  388. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  389. package/dist/src/utils/memoryDiscovery.test.js +43 -1
  390. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  391. package/dist/src/utils/nextSpeakerChecker.js +1 -2
  392. package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
  393. package/dist/src/utils/nextSpeakerChecker.test.js +10 -4
  394. package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
  395. package/dist/src/utils/pathReader.js +4 -4
  396. package/dist/src/utils/pathReader.js.map +1 -1
  397. package/dist/src/utils/pathReader.test.js +44 -1
  398. package/dist/src/utils/pathReader.test.js.map +1 -1
  399. package/dist/src/utils/paths.d.ts +1 -1
  400. package/dist/src/utils/paths.js +5 -3
  401. package/dist/src/utils/paths.js.map +1 -1
  402. package/dist/src/utils/retry.d.ts +0 -9
  403. package/dist/src/utils/retry.js +24 -28
  404. package/dist/src/utils/retry.js.map +1 -1
  405. package/dist/src/utils/retry.test.js +51 -0
  406. package/dist/src/utils/retry.test.js.map +1 -1
  407. package/dist/src/utils/shell-utils.js +5 -3
  408. package/dist/src/utils/shell-utils.js.map +1 -1
  409. package/dist/src/utils/shell-utils.test.js +9 -9
  410. package/dist/src/utils/shell-utils.test.js.map +1 -1
  411. package/dist/src/utils/summarizer.d.ts +4 -2
  412. package/dist/src/utils/summarizer.js +6 -8
  413. package/dist/src/utils/summarizer.js.map +1 -1
  414. package/dist/src/utils/summarizer.test.js +32 -11
  415. package/dist/src/utils/summarizer.test.js.map +1 -1
  416. package/dist/src/utils/workspaceContext.d.ts +4 -3
  417. package/dist/src/utils/workspaceContext.js +10 -11
  418. package/dist/src/utils/workspaceContext.js.map +1 -1
  419. package/dist/src/utils/workspaceContext.test.js +1 -1
  420. package/dist/src/utils/workspaceContext.test.js.map +1 -1
  421. package/dist/tsconfig.tsbuildinfo +1 -1
  422. package/package.json +1 -1
@@ -3,97 +3,57 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
6
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
7
7
  import { ApprovalMode, PolicyDecision } from './types.js';
8
- import nodePath from 'node:path';
8
+ import * as fs from 'node:fs/promises';
9
+ import * as path from 'node:path';
10
+ import * as os from 'node:os';
11
+ import { loadPoliciesFromToml } from './toml-loader.js';
9
12
  describe('policy-toml-loader', () => {
10
- beforeEach(() => {
11
- vi.resetModules();
13
+ let tempDir;
14
+ beforeEach(async () => {
15
+ tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'policy-test-'));
12
16
  });
13
- afterEach(() => {
14
- vi.restoreAllMocks();
15
- vi.doUnmock('node:fs/promises');
17
+ afterEach(async () => {
18
+ if (tempDir) {
19
+ await fs.rm(tempDir, {
20
+ recursive: true,
21
+ force: true,
22
+ maxRetries: 3,
23
+ retryDelay: 10,
24
+ });
25
+ }
16
26
  });
27
+ async function runLoadPoliciesFromToml(tomlContent, fileName = 'test.toml') {
28
+ await fs.writeFile(path.join(tempDir, fileName), tomlContent);
29
+ const getPolicyTier = (_dir) => 1;
30
+ return loadPoliciesFromToml(ApprovalMode.DEFAULT, [tempDir], getPolicyTier);
31
+ }
17
32
  describe('loadPoliciesFromToml', () => {
18
33
  it('should load and parse a simple policy file', async () => {
19
- const actualFs = await vi.importActual('node:fs/promises');
20
- const mockReaddir = vi.fn(async (path, _options) => {
21
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
22
- return [
23
- {
24
- name: 'test.toml',
25
- isFile: () => true,
26
- isDirectory: () => false,
27
- },
28
- ];
29
- }
30
- return [];
31
- });
32
- const mockReadFile = vi.fn(async (path) => {
33
- if (nodePath.normalize(path) ===
34
- nodePath.normalize(nodePath.join('/policies', 'test.toml'))) {
35
- return `
34
+ const result = await runLoadPoliciesFromToml(`
36
35
  [[rule]]
37
36
  toolName = "glob"
38
37
  decision = "allow"
39
38
  priority = 100
40
- `;
41
- }
42
- throw new Error('File not found');
43
- });
44
- vi.doMock('node:fs/promises', () => ({
45
- ...actualFs,
46
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
47
- readFile: mockReadFile,
48
- readdir: mockReaddir,
49
- }));
50
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
51
- const getPolicyTier = (_dir) => 1;
52
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
39
+ `);
53
40
  expect(result.rules).toHaveLength(1);
54
41
  expect(result.rules[0]).toEqual({
55
42
  toolName: 'glob',
56
43
  decision: PolicyDecision.ALLOW,
57
44
  priority: 1.1, // tier 1 + 100/1000
58
45
  });
46
+ expect(result.checkers).toHaveLength(0);
59
47
  expect(result.errors).toHaveLength(0);
60
48
  });
61
49
  it('should expand commandPrefix array to multiple rules', async () => {
62
- const actualFs = await vi.importActual('node:fs/promises');
63
- const mockReaddir = vi.fn(async (path, _options) => {
64
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
65
- return [
66
- {
67
- name: 'shell.toml',
68
- isFile: () => true,
69
- isDirectory: () => false,
70
- },
71
- ];
72
- }
73
- return [];
74
- });
75
- const mockReadFile = vi.fn(async (path) => {
76
- if (nodePath.normalize(path) ===
77
- nodePath.normalize(nodePath.join('/policies', 'shell.toml'))) {
78
- return `
50
+ const result = await runLoadPoliciesFromToml(`
79
51
  [[rule]]
80
52
  toolName = "run_shell_command"
81
53
  commandPrefix = ["git status", "git log"]
82
54
  decision = "allow"
83
55
  priority = 100
84
- `;
85
- }
86
- throw new Error('File not found');
87
- });
88
- vi.doMock('node:fs/promises', () => ({
89
- ...actualFs,
90
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
91
- readFile: mockReadFile,
92
- readdir: mockReaddir,
93
- }));
94
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
95
- const getPolicyTier = (_dir) => 2;
96
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
56
+ `);
97
57
  expect(result.rules).toHaveLength(2);
98
58
  expect(result.rules[0].toolName).toBe('run_shell_command');
99
59
  expect(result.rules[1].toolName).toBe('run_shell_command');
@@ -102,41 +62,13 @@ priority = 100
102
62
  expect(result.errors).toHaveLength(0);
103
63
  });
104
64
  it('should transform commandRegex to argsPattern', async () => {
105
- const actualFs = await vi.importActual('node:fs/promises');
106
- const mockReaddir = vi.fn(async (path, _options) => {
107
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
108
- return [
109
- {
110
- name: 'shell.toml',
111
- isFile: () => true,
112
- isDirectory: () => false,
113
- },
114
- ];
115
- }
116
- return [];
117
- });
118
- const mockReadFile = vi.fn(async (path) => {
119
- if (nodePath.normalize(path) ===
120
- nodePath.normalize(nodePath.join('/policies', 'shell.toml'))) {
121
- return `
65
+ const result = await runLoadPoliciesFromToml(`
122
66
  [[rule]]
123
67
  toolName = "run_shell_command"
124
68
  commandRegex = "git (status|log).*"
125
69
  decision = "allow"
126
70
  priority = 100
127
- `;
128
- }
129
- throw new Error('File not found');
130
- });
131
- vi.doMock('node:fs/promises', () => ({
132
- ...actualFs,
133
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
134
- readFile: mockReadFile,
135
- readdir: mockReaddir,
136
- }));
137
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
138
- const getPolicyTier = (_dir) => 2;
139
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
71
+ `);
140
72
  expect(result.rules).toHaveLength(1);
141
73
  expect(result.rules[0].argsPattern?.test('{"command":"git status"}')).toBe(true);
142
74
  expect(result.rules[0].argsPattern?.test('{"command":"git log --all"}')).toBe(true);
@@ -144,40 +76,12 @@ priority = 100
144
76
  expect(result.errors).toHaveLength(0);
145
77
  });
146
78
  it('should expand toolName array', async () => {
147
- const actualFs = await vi.importActual('node:fs/promises');
148
- const mockReaddir = vi.fn(async (path, _options) => {
149
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
150
- return [
151
- {
152
- name: 'tools.toml',
153
- isFile: () => true,
154
- isDirectory: () => false,
155
- },
156
- ];
157
- }
158
- return [];
159
- });
160
- const mockReadFile = vi.fn(async (path) => {
161
- if (nodePath.normalize(path) ===
162
- nodePath.normalize(nodePath.join('/policies', 'tools.toml'))) {
163
- return `
79
+ const result = await runLoadPoliciesFromToml(`
164
80
  [[rule]]
165
81
  toolName = ["glob", "grep", "read"]
166
82
  decision = "allow"
167
83
  priority = 100
168
- `;
169
- }
170
- throw new Error('File not found');
171
- });
172
- vi.doMock('node:fs/promises', () => ({
173
- ...actualFs,
174
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
175
- readFile: mockReadFile,
176
- readdir: mockReaddir,
177
- }));
178
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
179
- const getPolicyTier = (_dir) => 1;
180
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
84
+ `);
181
85
  expect(result.rules).toHaveLength(3);
182
86
  expect(result.rules.map((r) => r.toolName)).toEqual([
183
87
  'glob',
@@ -187,64 +91,20 @@ priority = 100
187
91
  expect(result.errors).toHaveLength(0);
188
92
  });
189
93
  it('should transform mcpName to composite toolName', async () => {
190
- const actualFs = await vi.importActual('node:fs/promises');
191
- const mockReaddir = vi.fn(async (path, _options) => {
192
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
193
- return [
194
- {
195
- name: 'mcp.toml',
196
- isFile: () => true,
197
- isDirectory: () => false,
198
- },
199
- ];
200
- }
201
- return [];
202
- });
203
- const mockReadFile = vi.fn(async (path) => {
204
- if (nodePath.normalize(path) ===
205
- nodePath.normalize(nodePath.join('/policies', 'mcp.toml'))) {
206
- return `
94
+ const result = await runLoadPoliciesFromToml(`
207
95
  [[rule]]
208
96
  mcpName = "google-workspace"
209
97
  toolName = ["calendar.list", "calendar.get"]
210
98
  decision = "allow"
211
99
  priority = 100
212
- `;
213
- }
214
- throw new Error('File not found');
215
- });
216
- vi.doMock('node:fs/promises', () => ({
217
- ...actualFs,
218
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
219
- readFile: mockReadFile,
220
- readdir: mockReaddir,
221
- }));
222
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
223
- const getPolicyTier = (_dir) => 2;
224
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
100
+ `);
225
101
  expect(result.rules).toHaveLength(2);
226
102
  expect(result.rules[0].toolName).toBe('google-workspace__calendar.list');
227
103
  expect(result.rules[1].toolName).toBe('google-workspace__calendar.get');
228
104
  expect(result.errors).toHaveLength(0);
229
105
  });
230
106
  it('should filter rules by mode', async () => {
231
- const actualFs = await vi.importActual('node:fs/promises');
232
- const mockReaddir = vi.fn(async (path, _options) => {
233
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
234
- return [
235
- {
236
- name: 'modes.toml',
237
- isFile: () => true,
238
- isDirectory: () => false,
239
- },
240
- ];
241
- }
242
- return [];
243
- });
244
- const mockReadFile = vi.fn(async (path) => {
245
- if (nodePath.normalize(path) ===
246
- nodePath.normalize(nodePath.join('/policies', 'modes.toml'))) {
247
- return `
107
+ const result = await runLoadPoliciesFromToml(`
248
108
  [[rule]]
249
109
  toolName = "glob"
250
110
  decision = "allow"
@@ -256,267 +116,261 @@ toolName = "grep"
256
116
  decision = "allow"
257
117
  priority = 100
258
118
  modes = ["yolo"]
259
- `;
260
- }
261
- throw new Error('File not found');
262
- });
263
- vi.doMock('node:fs/promises', () => ({
264
- ...actualFs,
265
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
266
- readFile: mockReadFile,
267
- readdir: mockReaddir,
268
- }));
269
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
270
- const getPolicyTier = (_dir) => 1;
271
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
119
+ `);
272
120
  // Only the first rule should be included (modes includes "default")
273
121
  expect(result.rules).toHaveLength(1);
274
122
  expect(result.rules[0].toolName).toBe('glob');
275
123
  expect(result.errors).toHaveLength(0);
276
124
  });
277
125
  it('should handle TOML parse errors', async () => {
278
- const actualFs = await vi.importActual('node:fs/promises');
279
- const mockReaddir = vi.fn(async (path, _options) => {
280
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
281
- return [
282
- {
283
- name: 'invalid.toml',
284
- isFile: () => true,
285
- isDirectory: () => false,
286
- },
287
- ];
288
- }
289
- return [];
290
- });
291
- const mockReadFile = vi.fn(async (path) => {
292
- if (nodePath.normalize(path) ===
293
- nodePath.normalize(nodePath.join('/policies', 'invalid.toml'))) {
294
- return `
126
+ const result = await runLoadPoliciesFromToml(`
295
127
  [[rule]
296
128
  toolName = "glob"
297
129
  decision = "allow"
298
130
  priority = 100
299
- `;
300
- }
301
- throw new Error('File not found');
302
- });
303
- vi.doMock('node:fs/promises', () => ({
304
- ...actualFs,
305
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
306
- readFile: mockReadFile,
307
- readdir: mockReaddir,
308
- }));
309
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
310
- const getPolicyTier = (_dir) => 1;
311
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
131
+ `);
312
132
  expect(result.rules).toHaveLength(0);
313
133
  expect(result.errors).toHaveLength(1);
314
134
  expect(result.errors[0].errorType).toBe('toml_parse');
315
- expect(result.errors[0].fileName).toBe('invalid.toml');
135
+ expect(result.errors[0].fileName).toBe('test.toml');
316
136
  });
317
137
  it('should handle schema validation errors', async () => {
318
- const actualFs = await vi.importActual('node:fs/promises');
319
- const mockReaddir = vi.fn(async (path, _options) => {
320
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
321
- return [
322
- {
323
- name: 'invalid.toml',
324
- isFile: () => true,
325
- isDirectory: () => false,
326
- },
327
- ];
328
- }
329
- return [];
330
- });
331
- const mockReadFile = vi.fn(async (path) => {
332
- if (nodePath.normalize(path) ===
333
- nodePath.normalize(nodePath.join('/policies', 'invalid.toml'))) {
334
- return `
138
+ const result = await runLoadPoliciesFromToml(`
335
139
  [[rule]]
336
140
  toolName = "glob"
337
141
  priority = 100
338
- `;
339
- }
340
- throw new Error('File not found');
341
- });
342
- vi.doMock('node:fs/promises', () => ({
343
- ...actualFs,
344
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
345
- readFile: mockReadFile,
346
- readdir: mockReaddir,
347
- }));
348
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
349
- const getPolicyTier = (_dir) => 1;
350
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
142
+ `);
351
143
  expect(result.rules).toHaveLength(0);
352
144
  expect(result.errors).toHaveLength(1);
353
145
  expect(result.errors[0].errorType).toBe('schema_validation');
354
146
  expect(result.errors[0].details).toContain('decision');
355
147
  });
356
148
  it('should reject commandPrefix without run_shell_command', async () => {
357
- const actualFs = await vi.importActual('node:fs/promises');
358
- const mockReaddir = vi.fn(async (path, _options) => {
359
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
360
- return [
361
- {
362
- name: 'invalid.toml',
363
- isFile: () => true,
364
- isDirectory: () => false,
365
- },
366
- ];
367
- }
368
- return [];
369
- });
370
- const mockReadFile = vi.fn(async (path) => {
371
- if (nodePath.normalize(path) ===
372
- nodePath.normalize(nodePath.join('/policies', 'invalid.toml'))) {
373
- return `
149
+ const result = await runLoadPoliciesFromToml(`
374
150
  [[rule]]
375
151
  toolName = "glob"
376
152
  commandPrefix = "git status"
377
153
  decision = "allow"
378
154
  priority = 100
379
- `;
380
- }
381
- throw new Error('File not found');
382
- });
383
- vi.doMock('node:fs/promises', () => ({
384
- ...actualFs,
385
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
386
- readFile: mockReadFile,
387
- readdir: mockReaddir,
388
- }));
389
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
390
- const getPolicyTier = (_dir) => 1;
391
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
155
+ `);
392
156
  expect(result.errors).toHaveLength(1);
393
157
  expect(result.errors[0].errorType).toBe('rule_validation');
394
158
  expect(result.errors[0].details).toContain('run_shell_command');
395
159
  });
396
160
  it('should reject commandPrefix + argsPattern combination', async () => {
397
- const actualFs = await vi.importActual('node:fs/promises');
398
- const mockReaddir = vi.fn(async (path, _options) => {
399
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
400
- return [
401
- {
402
- name: 'invalid.toml',
403
- isFile: () => true,
404
- isDirectory: () => false,
405
- },
406
- ];
407
- }
408
- return [];
409
- });
410
- const mockReadFile = vi.fn(async (path) => {
411
- if (nodePath.normalize(path) ===
412
- nodePath.normalize(nodePath.join('/policies', 'invalid.toml'))) {
413
- return `
161
+ const result = await runLoadPoliciesFromToml(`
414
162
  [[rule]]
415
163
  toolName = "run_shell_command"
416
164
  commandPrefix = "git status"
417
165
  argsPattern = "test"
418
166
  decision = "allow"
419
167
  priority = 100
420
- `;
421
- }
422
- throw new Error('File not found');
423
- });
424
- vi.doMock('node:fs/promises', () => ({
425
- ...actualFs,
426
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
427
- readFile: mockReadFile,
428
- readdir: mockReaddir,
429
- }));
430
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
431
- const getPolicyTier = (_dir) => 1;
432
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
168
+ `);
433
169
  expect(result.errors).toHaveLength(1);
434
170
  expect(result.errors[0].errorType).toBe('rule_validation');
435
171
  expect(result.errors[0].details).toContain('mutually exclusive');
436
172
  });
437
173
  it('should handle invalid regex patterns', async () => {
438
- const actualFs = await vi.importActual('node:fs/promises');
439
- const mockReaddir = vi.fn(async (path, _options) => {
440
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
441
- return [
442
- {
443
- name: 'invalid.toml',
444
- isFile: () => true,
445
- isDirectory: () => false,
446
- },
447
- ];
448
- }
449
- return [];
450
- });
451
- const mockReadFile = vi.fn(async (path) => {
452
- if (nodePath.normalize(path) ===
453
- nodePath.normalize(nodePath.join('/policies', 'invalid.toml'))) {
454
- return `
174
+ const result = await runLoadPoliciesFromToml(`
455
175
  [[rule]]
456
176
  toolName = "run_shell_command"
457
177
  commandRegex = "git (status|branch"
458
178
  decision = "allow"
459
179
  priority = 100
460
- `;
461
- }
462
- throw new Error('File not found');
463
- });
464
- vi.doMock('node:fs/promises', () => ({
465
- ...actualFs,
466
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
467
- readFile: mockReadFile,
468
- readdir: mockReaddir,
469
- }));
470
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
471
- const getPolicyTier = (_dir) => 1;
472
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
180
+ `);
473
181
  expect(result.rules).toHaveLength(0);
474
182
  expect(result.errors).toHaveLength(1);
475
183
  expect(result.errors[0].errorType).toBe('regex_compilation');
476
184
  expect(result.errors[0].details).toContain('git (status|branch');
477
185
  });
478
186
  it('should escape regex special characters in commandPrefix', async () => {
479
- const actualFs = await vi.importActual('node:fs/promises');
480
- const mockReaddir = vi.fn(async (path, _options) => {
481
- if (nodePath.normalize(path) === nodePath.normalize('/policies')) {
482
- return [
483
- {
484
- name: 'shell.toml',
485
- isFile: () => true,
486
- isDirectory: () => false,
487
- },
488
- ];
489
- }
490
- return [];
491
- });
492
- const mockReadFile = vi.fn(async (path) => {
493
- if (nodePath.normalize(path) ===
494
- nodePath.normalize(nodePath.join('/policies', 'shell.toml'))) {
495
- return `
187
+ const result = await runLoadPoliciesFromToml(`
496
188
  [[rule]]
497
189
  toolName = "run_shell_command"
498
190
  commandPrefix = "git log *.txt"
499
191
  decision = "allow"
500
192
  priority = 100
501
- `;
502
- }
503
- throw new Error('File not found');
504
- });
505
- vi.doMock('node:fs/promises', () => ({
506
- ...actualFs,
507
- default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
508
- readFile: mockReadFile,
509
- readdir: mockReaddir,
510
- }));
511
- const { loadPoliciesFromToml: load } = await import('./toml-loader.js');
512
- const getPolicyTier = (_dir) => 1;
513
- const result = await load(ApprovalMode.DEFAULT, ['/policies'], getPolicyTier);
193
+ `);
514
194
  expect(result.rules).toHaveLength(1);
515
195
  // The regex should have escaped the * and .
516
196
  expect(result.rules[0].argsPattern?.test('{"command":"git log file.txt"}')).toBe(false);
517
197
  expect(result.rules[0].argsPattern?.test('{"command":"git log *.txt"}')).toBe(true);
518
198
  expect(result.errors).toHaveLength(0);
519
199
  });
200
+ it('should handle a mix of valid and invalid policy files', async () => {
201
+ await fs.writeFile(path.join(tempDir, 'valid.toml'), `
202
+ [[rule]]
203
+ toolName = "glob"
204
+ decision = "allow"
205
+ priority = 100
206
+ `);
207
+ await fs.writeFile(path.join(tempDir, 'invalid.toml'), `
208
+ [[rule]]
209
+ toolName = "grep"
210
+ decision = "allow"
211
+ priority = -1
212
+ `);
213
+ const getPolicyTier = (_dir) => 1;
214
+ const result = await loadPoliciesFromToml(ApprovalMode.DEFAULT, [tempDir], getPolicyTier);
215
+ expect(result.rules).toHaveLength(1);
216
+ expect(result.rules[0].toolName).toBe('glob');
217
+ expect(result.errors).toHaveLength(1);
218
+ expect(result.errors[0].fileName).toBe('invalid.toml');
219
+ expect(result.errors[0].errorType).toBe('schema_validation');
220
+ });
221
+ });
222
+ describe('Negative Tests', () => {
223
+ it('should return a schema_validation error if priority is missing', async () => {
224
+ const result = await runLoadPoliciesFromToml(`
225
+ [[rule]]
226
+ toolName = "test"
227
+ decision = "allow"
228
+ `);
229
+ expect(result.errors).toHaveLength(1);
230
+ const error = result.errors[0];
231
+ expect(error.errorType).toBe('schema_validation');
232
+ expect(error.details).toContain('priority');
233
+ });
234
+ it('should return a schema_validation error if priority is a float', async () => {
235
+ const result = await runLoadPoliciesFromToml(`
236
+ [[rule]]
237
+ toolName = "test"
238
+ decision = "allow"
239
+ priority = 1.5
240
+ `);
241
+ expect(result.errors).toHaveLength(1);
242
+ const error = result.errors[0];
243
+ expect(error.errorType).toBe('schema_validation');
244
+ expect(error.details).toContain('priority');
245
+ expect(error.details).toContain('integer');
246
+ });
247
+ it('should return a schema_validation error if priority is negative', async () => {
248
+ const result = await runLoadPoliciesFromToml(`
249
+ [[rule]]
250
+ toolName = "test"
251
+ decision = "allow"
252
+ priority = -1
253
+ `);
254
+ expect(result.errors).toHaveLength(1);
255
+ const error = result.errors[0];
256
+ expect(error.errorType).toBe('schema_validation');
257
+ expect(error.details).toContain('priority');
258
+ expect(error.details).toContain('>= 0');
259
+ });
260
+ it('should return a schema_validation error if priority is much lower than 0', async () => {
261
+ const result = await runLoadPoliciesFromToml(`
262
+ [[rule]]
263
+ toolName = "test"
264
+ decision = "allow"
265
+ priority = -9999
266
+ `);
267
+ expect(result.errors).toHaveLength(1);
268
+ const error = result.errors[0];
269
+ expect(error.errorType).toBe('schema_validation');
270
+ expect(error.details).toContain('priority');
271
+ expect(error.details).toContain('>= 0');
272
+ });
273
+ it('should return a schema_validation error if priority is >= 1000', async () => {
274
+ const result = await runLoadPoliciesFromToml(`
275
+ [[rule]]
276
+ toolName = "test"
277
+ decision = "allow"
278
+ priority = 1000
279
+ `);
280
+ expect(result.errors).toHaveLength(1);
281
+ const error = result.errors[0];
282
+ expect(error.errorType).toBe('schema_validation');
283
+ expect(error.details).toContain('priority');
284
+ expect(error.details).toContain('<= 999');
285
+ });
286
+ it('should return a schema_validation error if priority is much higher than 1000', async () => {
287
+ const result = await runLoadPoliciesFromToml(`
288
+ [[rule]]
289
+ toolName = "test"
290
+ decision = "allow"
291
+ priority = 9999
292
+ `);
293
+ expect(result.errors).toHaveLength(1);
294
+ const error = result.errors[0];
295
+ expect(error.errorType).toBe('schema_validation');
296
+ expect(error.details).toContain('priority');
297
+ expect(error.details).toContain('<= 999');
298
+ });
299
+ it('should return a schema_validation error if decision is invalid', async () => {
300
+ const result = await runLoadPoliciesFromToml(`
301
+ [[rule]]
302
+ toolName = "test"
303
+ decision = "maybe"
304
+ priority = 100
305
+ `);
306
+ expect(result.errors).toHaveLength(1);
307
+ const error = result.errors[0];
308
+ expect(error.errorType).toBe('schema_validation');
309
+ expect(error.details).toContain('decision');
310
+ });
311
+ it('should return a schema_validation error if toolName is not a string or array', async () => {
312
+ const result = await runLoadPoliciesFromToml(`
313
+ [[rule]]
314
+ toolName = 123
315
+ decision = "allow"
316
+ priority = 100
317
+ `);
318
+ expect(result.errors).toHaveLength(1);
319
+ const error = result.errors[0];
320
+ expect(error.errorType).toBe('schema_validation');
321
+ expect(error.details).toContain('toolName');
322
+ });
323
+ it('should return a rule_validation error if commandRegex is used with wrong toolName', async () => {
324
+ const result = await runLoadPoliciesFromToml(`
325
+ [[rule]]
326
+ toolName = "not_shell"
327
+ commandRegex = ".*"
328
+ decision = "allow"
329
+ priority = 100
330
+ `);
331
+ expect(result.errors).toHaveLength(1);
332
+ const error = result.errors[0];
333
+ expect(error.errorType).toBe('rule_validation');
334
+ expect(error.details).toContain('run_shell_command');
335
+ });
336
+ it('should return a rule_validation error if commandPrefix and commandRegex are combined', async () => {
337
+ const result = await runLoadPoliciesFromToml(`
338
+ [[rule]]
339
+ toolName = "run_shell_command"
340
+ commandPrefix = "git"
341
+ commandRegex = ".*"
342
+ decision = "allow"
343
+ priority = 100
344
+ `);
345
+ expect(result.errors).toHaveLength(1);
346
+ const error = result.errors[0];
347
+ expect(error.errorType).toBe('rule_validation');
348
+ expect(error.details).toContain('mutually exclusive');
349
+ });
350
+ it('should return a regex_compilation error for invalid argsPattern', async () => {
351
+ const result = await runLoadPoliciesFromToml(`
352
+ [[rule]]
353
+ toolName = "test"
354
+ argsPattern = "([a-z)"
355
+ decision = "allow"
356
+ priority = 100
357
+ `);
358
+ expect(result.errors).toHaveLength(1);
359
+ const error = result.errors[0];
360
+ expect(error.errorType).toBe('regex_compilation');
361
+ expect(error.message).toBe('Invalid regex pattern');
362
+ });
363
+ it('should return a file_read error if readdir fails', async () => {
364
+ // Create a file and pass it as a directory to trigger ENOTDIR
365
+ const filePath = path.join(tempDir, 'not-a-dir');
366
+ await fs.writeFile(filePath, 'content');
367
+ const getPolicyTier = (_dir) => 1;
368
+ const result = await loadPoliciesFromToml(ApprovalMode.DEFAULT, [filePath], getPolicyTier);
369
+ expect(result.errors).toHaveLength(1);
370
+ const error = result.errors[0];
371
+ expect(error.errorType).toBe('file_read');
372
+ expect(error.message).toContain('Failed to read policy directory');
373
+ });
520
374
  });
521
375
  });
522
376
  //# sourceMappingURL=toml-loader.test.js.map