@google/gemini-cli-core 0.36.0-preview.8 → 0.37.0-preview.0

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 (472) hide show
  1. package/dist/docs/CONTRIBUTING.md +10 -7
  2. package/dist/docs/assets/theme-tokyonight-dark.png +0 -0
  3. package/dist/docs/changelogs/index.md +24 -0
  4. package/dist/docs/changelogs/latest.md +366 -459
  5. package/dist/docs/changelogs/preview.md +362 -356
  6. package/dist/docs/cli/acp-mode.md +126 -0
  7. package/dist/docs/cli/cli-reference.md +1 -1
  8. package/dist/docs/cli/notifications.md +5 -5
  9. package/dist/docs/cli/plan-mode.md +12 -8
  10. package/dist/docs/cli/sandbox.md +1 -1
  11. package/dist/docs/cli/settings.md +14 -13
  12. package/dist/docs/cli/themes.md +5 -0
  13. package/dist/docs/core/index.md +2 -2
  14. package/dist/docs/core/subagents.md +134 -23
  15. package/dist/docs/get-started/gemini-3.md +1 -1
  16. package/dist/docs/get-started/index.md +127 -1
  17. package/dist/docs/ide-integration/index.md +99 -24
  18. package/dist/docs/index.md +0 -2
  19. package/dist/docs/redirects.json +1 -0
  20. package/dist/docs/reference/commands.md +1 -3
  21. package/dist/docs/reference/configuration.md +182 -91
  22. package/dist/docs/reference/keyboard-shortcuts.md +14 -6
  23. package/dist/docs/reference/policy-engine.md +16 -30
  24. package/dist/docs/reference/tools.md +56 -23
  25. package/dist/docs/resources/quota-and-pricing.md +23 -9
  26. package/dist/docs/sidebar.json +11 -4
  27. package/dist/docs/tools/planning.md +6 -4
  28. package/dist/src/agents/agentLoader.d.ts +12 -12
  29. package/dist/src/agents/agentLoader.js +1 -0
  30. package/dist/src/agents/agentLoader.js.map +1 -1
  31. package/dist/src/agents/browser/automationOverlay.js +2 -10
  32. package/dist/src/agents/browser/automationOverlay.js.map +1 -1
  33. package/dist/src/agents/browser/browserAgentDefinition.js +10 -3
  34. package/dist/src/agents/browser/browserAgentDefinition.js.map +1 -1
  35. package/dist/src/agents/browser/browserAgentFactory.d.ts +4 -4
  36. package/dist/src/agents/browser/browserAgentFactory.js +15 -29
  37. package/dist/src/agents/browser/browserAgentFactory.js.map +1 -1
  38. package/dist/src/agents/browser/browserAgentFactory.test.js +41 -24
  39. package/dist/src/agents/browser/browserAgentFactory.test.js.map +1 -1
  40. package/dist/src/agents/browser/browserAgentInvocation.d.ts +1 -0
  41. package/dist/src/agents/browser/browserAgentInvocation.js +60 -27
  42. package/dist/src/agents/browser/browserAgentInvocation.js.map +1 -1
  43. package/dist/src/agents/browser/browserAgentInvocation.test.js +59 -5
  44. package/dist/src/agents/browser/browserAgentInvocation.test.js.map +1 -1
  45. package/dist/src/agents/browser/browserManager.d.ts +51 -8
  46. package/dist/src/agents/browser/browserManager.js +242 -70
  47. package/dist/src/agents/browser/browserManager.js.map +1 -1
  48. package/dist/src/agents/browser/browserManager.test.js +384 -17
  49. package/dist/src/agents/browser/browserManager.test.js.map +1 -1
  50. package/dist/src/agents/browser/inputBlocker.d.ts +4 -4
  51. package/dist/src/agents/browser/inputBlocker.js +8 -18
  52. package/dist/src/agents/browser/inputBlocker.js.map +1 -1
  53. package/dist/src/agents/browser/inputBlocker.test.js +31 -3
  54. package/dist/src/agents/browser/inputBlocker.test.js.map +1 -1
  55. package/dist/src/agents/browser/mcpToolWrapper.d.ts +1 -1
  56. package/dist/src/agents/browser/mcpToolWrapper.js +9 -6
  57. package/dist/src/agents/browser/mcpToolWrapper.js.map +1 -1
  58. package/dist/src/agents/browser/mcpToolWrapper.test.js +2 -2
  59. package/dist/src/agents/browser/mcpToolWrapper.test.js.map +1 -1
  60. package/dist/src/agents/browser/snapshotSuperseder.d.ts +31 -0
  61. package/dist/src/agents/browser/snapshotSuperseder.js +101 -0
  62. package/dist/src/agents/browser/snapshotSuperseder.js.map +1 -0
  63. package/dist/src/agents/browser/snapshotSuperseder.test.js +158 -0
  64. package/dist/src/agents/browser/snapshotSuperseder.test.js.map +1 -0
  65. package/dist/src/agents/local-executor.d.ts +4 -0
  66. package/dist/src/agents/local-executor.js +46 -19
  67. package/dist/src/agents/local-executor.js.map +1 -1
  68. package/dist/src/agents/local-executor.test.js +118 -18
  69. package/dist/src/agents/local-executor.test.js.map +1 -1
  70. package/dist/src/agents/local-invocation.d.ts +1 -0
  71. package/dist/src/agents/local-invocation.js +19 -9
  72. package/dist/src/agents/local-invocation.js.map +1 -1
  73. package/dist/src/agents/local-invocation.test.js +24 -0
  74. package/dist/src/agents/local-invocation.test.js.map +1 -1
  75. package/dist/src/agents/registry.js +16 -1
  76. package/dist/src/agents/registry.js.map +1 -1
  77. package/dist/src/agents/registry.test.js +67 -0
  78. package/dist/src/agents/registry.test.js.map +1 -1
  79. package/dist/src/agents/types.d.ts +9 -0
  80. package/dist/src/agents/types.js.map +1 -1
  81. package/dist/src/code_assist/oauth2.js +8 -3
  82. package/dist/src/code_assist/oauth2.js.map +1 -1
  83. package/dist/src/code_assist/oauth2.test.js +57 -0
  84. package/dist/src/code_assist/oauth2.test.js.map +1 -1
  85. package/dist/src/code_assist/setup.js +5 -2
  86. package/dist/src/code_assist/setup.js.map +1 -1
  87. package/dist/src/code_assist/setup.test.js +27 -1
  88. package/dist/src/code_assist/setup.test.js.map +1 -1
  89. package/dist/src/code_assist/types.d.ts +80 -80
  90. package/dist/src/config/agent-loop-context.d.ts +2 -0
  91. package/dist/src/config/config.d.ts +81 -16
  92. package/dist/src/config/config.js +146 -50
  93. package/dist/src/config/config.js.map +1 -1
  94. package/dist/src/config/config.test.js +89 -2
  95. package/dist/src/config/config.test.js.map +1 -1
  96. package/dist/src/config/defaultModelConfigs.js +9 -0
  97. package/dist/src/config/defaultModelConfigs.js.map +1 -1
  98. package/dist/src/config/memory.d.ts +1 -0
  99. package/dist/src/config/memory.js +6 -0
  100. package/dist/src/config/memory.js.map +1 -1
  101. package/dist/src/config/storage.d.ts +1 -0
  102. package/dist/src/config/storage.js +4 -0
  103. package/dist/src/config/storage.js.map +1 -1
  104. package/dist/src/config/storage.test.js +5 -0
  105. package/dist/src/config/storage.test.js.map +1 -1
  106. package/dist/src/config/topicState.d.ts +21 -0
  107. package/dist/src/config/topicState.js +41 -0
  108. package/dist/src/config/topicState.js.map +1 -0
  109. package/dist/src/confirmation-bus/types.d.ts +9 -2
  110. package/dist/src/confirmation-bus/types.js +1 -0
  111. package/dist/src/confirmation-bus/types.js.map +1 -1
  112. package/dist/src/context/agentHistoryProvider.d.ts +45 -0
  113. package/dist/src/context/agentHistoryProvider.js +298 -0
  114. package/dist/src/context/agentHistoryProvider.js.map +1 -0
  115. package/dist/src/context/agentHistoryProvider.test.d.ts +6 -0
  116. package/dist/src/context/agentHistoryProvider.test.js +394 -0
  117. package/dist/src/context/agentHistoryProvider.test.js.map +1 -0
  118. package/dist/src/context/chatCompressionService.js.map +1 -0
  119. package/dist/src/context/chatCompressionService.test.js.map +1 -0
  120. package/dist/src/{services → context}/contextManager.d.ts +2 -0
  121. package/dist/src/{services → context}/contextManager.js +18 -9
  122. package/dist/src/context/contextManager.js.map +1 -0
  123. package/dist/src/{services → context}/contextManager.test.js +21 -6
  124. package/dist/src/context/contextManager.test.js.map +1 -0
  125. package/dist/src/context/toolDistillationService.d.ts +38 -0
  126. package/dist/src/context/toolDistillationService.js +170 -0
  127. package/dist/src/context/toolDistillationService.js.map +1 -0
  128. package/dist/src/context/toolDistillationService.test.d.ts +6 -0
  129. package/dist/src/context/toolDistillationService.test.js +83 -0
  130. package/dist/src/context/toolDistillationService.test.js.map +1 -0
  131. package/dist/src/{services → context}/toolOutputMaskingService.d.ts +2 -2
  132. package/dist/src/{services → context}/toolOutputMaskingService.js +7 -7
  133. package/dist/src/context/toolOutputMaskingService.js.map +1 -0
  134. package/dist/src/context/toolOutputMaskingService.test.d.ts +6 -0
  135. package/dist/src/{services → context}/toolOutputMaskingService.test.js +4 -5
  136. package/dist/src/context/toolOutputMaskingService.test.js.map +1 -0
  137. package/dist/src/context/truncation.d.ts +26 -0
  138. package/dist/src/context/truncation.js +102 -0
  139. package/dist/src/context/truncation.js.map +1 -0
  140. package/dist/src/core/client.d.ts +3 -1
  141. package/dist/src/core/client.js +23 -13
  142. package/dist/src/core/client.js.map +1 -1
  143. package/dist/src/core/client.test.js +29 -34
  144. package/dist/src/core/client.test.js.map +1 -1
  145. package/dist/src/core/contentGenerator.d.ts +0 -1
  146. package/dist/src/core/contentGenerator.js +2 -28
  147. package/dist/src/core/contentGenerator.js.map +1 -1
  148. package/dist/src/core/contentGenerator.test.js +1 -101
  149. package/dist/src/core/contentGenerator.test.js.map +1 -1
  150. package/dist/src/core/geminiChat.js +4 -5
  151. package/dist/src/core/geminiChat.js.map +1 -1
  152. package/dist/src/core/geminiChat.test.js +71 -18
  153. package/dist/src/core/geminiChat.test.js.map +1 -1
  154. package/dist/src/core/prompts-substitution.test.js +5 -0
  155. package/dist/src/core/prompts-substitution.test.js.map +1 -1
  156. package/dist/src/core/prompts.test.js +3 -0
  157. package/dist/src/core/prompts.test.js.map +1 -1
  158. package/dist/src/generated/git-commit.d.ts +2 -2
  159. package/dist/src/generated/git-commit.js +2 -2
  160. package/dist/src/index.d.ts +7 -3
  161. package/dist/src/index.js +9 -5
  162. package/dist/src/index.js.map +1 -1
  163. package/dist/src/policy/config.d.ts +1 -1
  164. package/dist/src/policy/config.js +5 -2
  165. package/dist/src/policy/config.js.map +1 -1
  166. package/dist/src/policy/policies/discovered.toml +7 -0
  167. package/dist/src/policy/policies/non-interactive.toml +7 -0
  168. package/dist/src/policy/policies/plan.toml +25 -0
  169. package/dist/src/policy/policies/read-only.toml +6 -0
  170. package/dist/src/policy/policies/sandbox-default.toml +3 -2
  171. package/dist/src/policy/policies/write.toml +21 -0
  172. package/dist/src/policy/policies/yolo.toml +1 -1
  173. package/dist/src/policy/policy-engine.d.ts +2 -4
  174. package/dist/src/policy/policy-engine.js +24 -37
  175. package/dist/src/policy/policy-engine.js.map +1 -1
  176. package/dist/src/policy/policy-engine.test.js +107 -29
  177. package/dist/src/policy/policy-engine.test.js.map +1 -1
  178. package/dist/src/policy/topic-policy.test.d.ts +6 -0
  179. package/dist/src/policy/topic-policy.test.js +48 -0
  180. package/dist/src/policy/topic-policy.test.js.map +1 -0
  181. package/dist/src/policy/types.d.ts +3 -6
  182. package/dist/src/policy/types.js.map +1 -1
  183. package/dist/src/prompts/promptProvider.js +20 -4
  184. package/dist/src/prompts/promptProvider.js.map +1 -1
  185. package/dist/src/prompts/promptProvider.test.js +84 -1
  186. package/dist/src/prompts/promptProvider.test.js.map +1 -1
  187. package/dist/src/prompts/snippets-memory-manager.test.js +1 -1
  188. package/dist/src/prompts/snippets-memory-manager.test.js.map +1 -1
  189. package/dist/src/prompts/snippets.d.ts +3 -4
  190. package/dist/src/prompts/snippets.js +33 -51
  191. package/dist/src/prompts/snippets.js.map +1 -1
  192. package/dist/src/prompts/snippets.legacy.d.ts +6 -4
  193. package/dist/src/prompts/snippets.legacy.js +32 -7
  194. package/dist/src/prompts/snippets.legacy.js.map +1 -1
  195. package/dist/src/sandbox/linux/LinuxSandboxManager.d.ts +11 -1
  196. package/dist/src/sandbox/linux/LinuxSandboxManager.js +261 -27
  197. package/dist/src/sandbox/linux/LinuxSandboxManager.js.map +1 -1
  198. package/dist/src/sandbox/linux/LinuxSandboxManager.test.js +430 -125
  199. package/dist/src/sandbox/linux/LinuxSandboxManager.test.js.map +1 -1
  200. package/dist/src/sandbox/macos/MacOsSandboxManager.d.ts +7 -22
  201. package/dist/src/sandbox/macos/MacOsSandboxManager.js +58 -57
  202. package/dist/src/sandbox/macos/MacOsSandboxManager.js.map +1 -1
  203. package/dist/src/sandbox/macos/MacOsSandboxManager.test.js +148 -103
  204. package/dist/src/sandbox/macos/MacOsSandboxManager.test.js.map +1 -1
  205. package/dist/src/sandbox/macos/baseProfile.d.ts +1 -1
  206. package/dist/src/sandbox/macos/baseProfile.js +0 -6
  207. package/dist/src/sandbox/macos/baseProfile.js.map +1 -1
  208. package/dist/src/sandbox/macos/seatbeltArgsBuilder.d.ts +10 -10
  209. package/dist/src/sandbox/macos/seatbeltArgsBuilder.js +80 -92
  210. package/dist/src/sandbox/macos/seatbeltArgsBuilder.js.map +1 -1
  211. package/dist/src/sandbox/macos/seatbeltArgsBuilder.test.js +135 -99
  212. package/dist/src/sandbox/macos/seatbeltArgsBuilder.test.js.map +1 -1
  213. package/dist/src/sandbox/{macos → utils}/commandSafety.d.ts +11 -0
  214. package/dist/src/sandbox/{macos → utils}/commandSafety.js +47 -14
  215. package/dist/src/sandbox/utils/commandSafety.js.map +1 -0
  216. package/dist/src/sandbox/utils/commandUtils.d.ts +9 -0
  217. package/dist/src/sandbox/utils/commandUtils.js +57 -0
  218. package/dist/src/sandbox/utils/commandUtils.js.map +1 -0
  219. package/dist/src/sandbox/utils/fsUtils.d.ts +11 -0
  220. package/dist/src/sandbox/utils/fsUtils.js +82 -0
  221. package/dist/src/sandbox/utils/fsUtils.js.map +1 -0
  222. package/dist/src/sandbox/utils/sandboxDenialUtils.d.ts +12 -0
  223. package/dist/src/sandbox/utils/sandboxDenialUtils.js +68 -0
  224. package/dist/src/sandbox/utils/sandboxDenialUtils.js.map +1 -0
  225. package/dist/src/sandbox/utils/sandboxDenialUtils.test.d.ts +6 -0
  226. package/dist/src/sandbox/utils/sandboxDenialUtils.test.js +37 -0
  227. package/dist/src/sandbox/utils/sandboxDenialUtils.test.js.map +1 -0
  228. package/dist/src/sandbox/utils/sandboxReadWriteUtils.d.ts +5 -0
  229. package/dist/src/sandbox/utils/sandboxReadWriteUtils.js +60 -0
  230. package/dist/src/sandbox/utils/sandboxReadWriteUtils.js.map +1 -0
  231. package/dist/src/sandbox/windows/GeminiSandbox.cs +257 -216
  232. package/dist/src/sandbox/windows/WindowsSandboxManager.d.ts +12 -2
  233. package/dist/src/sandbox/windows/WindowsSandboxManager.js +250 -38
  234. package/dist/src/sandbox/windows/WindowsSandboxManager.js.map +1 -1
  235. package/dist/src/sandbox/windows/WindowsSandboxManager.test.js +326 -9
  236. package/dist/src/sandbox/windows/WindowsSandboxManager.test.js.map +1 -1
  237. package/dist/src/sandbox/windows/commandSafety.d.ts +19 -0
  238. package/dist/src/sandbox/windows/commandSafety.js +128 -0
  239. package/dist/src/sandbox/windows/commandSafety.js.map +1 -0
  240. package/dist/src/sandbox/windows/commandSafety.test.d.ts +6 -0
  241. package/dist/src/sandbox/windows/commandSafety.test.js +42 -0
  242. package/dist/src/sandbox/windows/commandSafety.test.js.map +1 -0
  243. package/dist/src/sandbox/windows/windowsSandboxDenialUtils.d.ts +12 -0
  244. package/dist/src/sandbox/windows/windowsSandboxDenialUtils.js +68 -0
  245. package/dist/src/sandbox/windows/windowsSandboxDenialUtils.js.map +1 -0
  246. package/dist/src/sandbox/windows/windowsSandboxDenialUtils.test.d.ts +6 -0
  247. package/dist/src/sandbox/windows/windowsSandboxDenialUtils.test.js +68 -0
  248. package/dist/src/sandbox/windows/windowsSandboxDenialUtils.test.js.map +1 -0
  249. package/dist/src/scheduler/scheduler.js +12 -2
  250. package/dist/src/scheduler/scheduler.js.map +1 -1
  251. package/dist/src/scheduler/scheduler.test.js +52 -0
  252. package/dist/src/scheduler/scheduler.test.js.map +1 -1
  253. package/dist/src/scheduler/scheduler_hooks.test.js +1 -0
  254. package/dist/src/scheduler/scheduler_hooks.test.js.map +1 -1
  255. package/dist/src/scheduler/state-manager.js +1 -1
  256. package/dist/src/scheduler/state-manager.js.map +1 -1
  257. package/dist/src/scheduler/state-manager.test.js +10 -0
  258. package/dist/src/scheduler/state-manager.test.js.map +1 -1
  259. package/dist/src/scheduler/tool-executor.js +7 -2
  260. package/dist/src/scheduler/tool-executor.js.map +1 -1
  261. package/dist/src/scheduler/tool-executor.test.js +38 -0
  262. package/dist/src/scheduler/tool-executor.test.js.map +1 -1
  263. package/dist/src/scheduler/types.d.ts +4 -2
  264. package/dist/src/services/chatRecordingService.d.ts +1 -13
  265. package/dist/src/services/chatRecordingService.js +45 -46
  266. package/dist/src/services/chatRecordingService.js.map +1 -1
  267. package/dist/src/services/chatRecordingService.test.js +79 -10
  268. package/dist/src/services/chatRecordingService.test.js.map +1 -1
  269. package/dist/src/services/executionLifecycleService.d.ts +43 -6
  270. package/dist/src/services/executionLifecycleService.js +49 -12
  271. package/dist/src/services/executionLifecycleService.js.map +1 -1
  272. package/dist/src/services/executionLifecycleService.test.js +157 -3
  273. package/dist/src/services/executionLifecycleService.test.js.map +1 -1
  274. package/dist/src/services/fileDiscoveryService.d.ts +17 -2
  275. package/dist/src/services/fileDiscoveryService.js +84 -20
  276. package/dist/src/services/fileDiscoveryService.js.map +1 -1
  277. package/dist/src/services/fileDiscoveryService.test.js +67 -1
  278. package/dist/src/services/fileDiscoveryService.test.js.map +1 -1
  279. package/dist/src/services/modelConfigService.d.ts +11 -0
  280. package/dist/src/services/modelConfigService.js +67 -0
  281. package/dist/src/services/modelConfigService.js.map +1 -1
  282. package/dist/src/services/modelConfigService.test.js +30 -0
  283. package/dist/src/services/modelConfigService.test.js.map +1 -1
  284. package/dist/src/services/sandboxManager.d.ts +90 -8
  285. package/dist/src/services/sandboxManager.integration.test.js +438 -0
  286. package/dist/src/services/sandboxManager.integration.test.js.map +1 -0
  287. package/dist/src/services/sandboxManager.js +156 -13
  288. package/dist/src/services/sandboxManager.js.map +1 -1
  289. package/dist/src/services/sandboxManager.test.js +373 -117
  290. package/dist/src/services/sandboxManager.test.js.map +1 -1
  291. package/dist/src/services/sandboxManagerFactory.d.ts +2 -3
  292. package/dist/src/services/sandboxManagerFactory.js +10 -17
  293. package/dist/src/services/sandboxManagerFactory.js.map +1 -1
  294. package/dist/src/services/sandboxedFileSystemService.d.ts +1 -0
  295. package/dist/src/services/sandboxedFileSystemService.js +32 -3
  296. package/dist/src/services/sandboxedFileSystemService.js.map +1 -1
  297. package/dist/src/services/sandboxedFileSystemService.test.js +83 -12
  298. package/dist/src/services/sandboxedFileSystemService.test.js.map +1 -1
  299. package/dist/src/services/shellExecutionService.d.ts +2 -0
  300. package/dist/src/services/shellExecutionService.js +45 -16
  301. package/dist/src/services/shellExecutionService.js.map +1 -1
  302. package/dist/src/services/shellExecutionService.test.js +5 -4
  303. package/dist/src/services/shellExecutionService.test.js.map +1 -1
  304. package/dist/src/services/test-data/resolved-aliases-retry.golden.json +4 -0
  305. package/dist/src/services/test-data/resolved-aliases.golden.json +4 -0
  306. package/dist/src/services/types.d.ts +14 -0
  307. package/dist/src/services/types.js +7 -0
  308. package/dist/src/services/types.js.map +1 -0
  309. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +6 -0
  310. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  311. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +5 -1
  312. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  313. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +2 -1
  314. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +3 -1
  315. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  316. package/dist/src/telemetry/loggers.js +1 -1
  317. package/dist/src/telemetry/loggers.js.map +1 -1
  318. package/dist/src/telemetry/loggers.test.js +8 -3
  319. package/dist/src/telemetry/loggers.test.js.map +1 -1
  320. package/dist/src/telemetry/metrics.d.ts +10 -1
  321. package/dist/src/telemetry/metrics.js +19 -4
  322. package/dist/src/telemetry/metrics.js.map +1 -1
  323. package/dist/src/telemetry/metrics.test.js +44 -0
  324. package/dist/src/telemetry/metrics.test.js.map +1 -1
  325. package/dist/src/telemetry/types.d.ts +3 -3
  326. package/dist/src/telemetry/types.js +9 -4
  327. package/dist/src/telemetry/types.js.map +1 -1
  328. package/dist/src/test-utils/mock-message-bus.d.ts +1 -1
  329. package/dist/src/test-utils/mock-message-bus.js +1 -1
  330. package/dist/src/test-utils/mock-message-bus.js.map +1 -1
  331. package/dist/src/tools/definitions/base-declarations.d.ts +6 -0
  332. package/dist/src/tools/definitions/base-declarations.js +7 -0
  333. package/dist/src/tools/definitions/base-declarations.js.map +1 -1
  334. package/dist/src/tools/definitions/coreTools.d.ts +2 -1
  335. package/dist/src/tools/definitions/coreTools.js +9 -3
  336. package/dist/src/tools/definitions/coreTools.js.map +1 -1
  337. package/dist/src/tools/definitions/dynamic-declaration-helpers.d.ts +4 -0
  338. package/dist/src/tools/definitions/dynamic-declaration-helpers.js +29 -2
  339. package/dist/src/tools/definitions/dynamic-declaration-helpers.js.map +1 -1
  340. package/dist/src/tools/definitions/model-family-sets/default-legacy.js +11 -6
  341. package/dist/src/tools/definitions/model-family-sets/default-legacy.js.map +1 -1
  342. package/dist/src/tools/definitions/model-family-sets/gemini-3.js +10 -4
  343. package/dist/src/tools/definitions/model-family-sets/gemini-3.js.map +1 -1
  344. package/dist/src/tools/definitions/trackerTools.js +3 -3
  345. package/dist/src/tools/definitions/trackerTools.js.map +1 -1
  346. package/dist/src/tools/definitions/types.d.ts +1 -0
  347. package/dist/src/tools/enter-plan-mode.js +15 -0
  348. package/dist/src/tools/enter-plan-mode.js.map +1 -1
  349. package/dist/src/tools/enter-plan-mode.test.js +25 -0
  350. package/dist/src/tools/enter-plan-mode.test.js.map +1 -1
  351. package/dist/src/tools/grep-utils.d.ts +2 -1
  352. package/dist/src/tools/grep-utils.js +22 -3
  353. package/dist/src/tools/grep-utils.js.map +1 -1
  354. package/dist/src/tools/grep.js +16 -3
  355. package/dist/src/tools/grep.js.map +1 -1
  356. package/dist/src/tools/grep.test.js +34 -6
  357. package/dist/src/tools/grep.test.js.map +1 -1
  358. package/dist/src/tools/ls.js +6 -4
  359. package/dist/src/tools/ls.js.map +1 -1
  360. package/dist/src/tools/ls.test.js +22 -7
  361. package/dist/src/tools/ls.test.js.map +1 -1
  362. package/dist/src/tools/mcp-client-manager.js +6 -3
  363. package/dist/src/tools/mcp-client-manager.js.map +1 -1
  364. package/dist/src/tools/mcp-client-manager.test.js +35 -0
  365. package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
  366. package/dist/src/tools/memoryTool.d.ts +9 -2
  367. package/dist/src/tools/memoryTool.js +39 -15
  368. package/dist/src/tools/memoryTool.js.map +1 -1
  369. package/dist/src/tools/memoryTool.test.js +61 -2
  370. package/dist/src/tools/memoryTool.test.js.map +1 -1
  371. package/dist/src/tools/read-many-files.js +12 -4
  372. package/dist/src/tools/read-many-files.js.map +1 -1
  373. package/dist/src/tools/read-many-files.test.js +17 -17
  374. package/dist/src/tools/read-many-files.test.js.map +1 -1
  375. package/dist/src/tools/ripGrep.js +14 -1
  376. package/dist/src/tools/ripGrep.js.map +1 -1
  377. package/dist/src/tools/ripGrep.test.js +9 -9
  378. package/dist/src/tools/ripGrep.test.js.map +1 -1
  379. package/dist/src/tools/shell.d.ts +10 -0
  380. package/dist/src/tools/shell.js +97 -124
  381. package/dist/src/tools/shell.js.map +1 -1
  382. package/dist/src/tools/shell.test.js +22 -3
  383. package/dist/src/tools/shell.test.js.map +1 -1
  384. package/dist/src/tools/tool-names.d.ts +4 -4
  385. package/dist/src/tools/tool-names.js +5 -3
  386. package/dist/src/tools/tool-names.js.map +1 -1
  387. package/dist/src/tools/tool-registry.js +11 -1
  388. package/dist/src/tools/tool-registry.js.map +1 -1
  389. package/dist/src/tools/tool-registry.test.js +43 -1
  390. package/dist/src/tools/tool-registry.test.js.map +1 -1
  391. package/dist/src/tools/tools.d.ts +12 -1
  392. package/dist/src/tools/tools.js +15 -0
  393. package/dist/src/tools/tools.js.map +1 -1
  394. package/dist/src/tools/tools.test.js +42 -1
  395. package/dist/src/tools/tools.test.js.map +1 -1
  396. package/dist/src/tools/topicTool.d.ts +29 -0
  397. package/dist/src/tools/topicTool.js +72 -0
  398. package/dist/src/tools/topicTool.js.map +1 -0
  399. package/dist/src/tools/topicTool.test.d.ts +6 -0
  400. package/dist/src/tools/topicTool.test.js +105 -0
  401. package/dist/src/tools/topicTool.test.js.map +1 -0
  402. package/dist/src/tools/web-fetch.js +38 -20
  403. package/dist/src/tools/web-fetch.js.map +1 -1
  404. package/dist/src/tools/web-fetch.test.js +28 -0
  405. package/dist/src/tools/web-fetch.test.js.map +1 -1
  406. package/dist/src/utils/checkpointUtils.d.ts +4 -4
  407. package/dist/src/utils/errors.d.ts +3 -0
  408. package/dist/src/utils/errors.js +28 -6
  409. package/dist/src/utils/errors.js.map +1 -1
  410. package/dist/src/utils/errors.test.js +23 -0
  411. package/dist/src/utils/errors.test.js.map +1 -1
  412. package/dist/src/utils/getFolderStructure.js +1 -1
  413. package/dist/src/utils/getFolderStructure.js.map +1 -1
  414. package/dist/src/utils/gitIgnoreParser.d.ts +2 -2
  415. package/dist/src/utils/gitIgnoreParser.js +28 -50
  416. package/dist/src/utils/gitIgnoreParser.js.map +1 -1
  417. package/dist/src/utils/gitIgnoreParser.test.js +51 -185
  418. package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
  419. package/dist/src/utils/ignoreFileParser.d.ts +2 -2
  420. package/dist/src/utils/ignoreFileParser.js +6 -17
  421. package/dist/src/utils/ignoreFileParser.js.map +1 -1
  422. package/dist/src/utils/ignoreFileParser.test.js +40 -132
  423. package/dist/src/utils/ignoreFileParser.test.js.map +1 -1
  424. package/dist/src/utils/ignorePathUtils.d.ts +11 -0
  425. package/dist/src/utils/ignorePathUtils.js +39 -0
  426. package/dist/src/utils/ignorePathUtils.js.map +1 -0
  427. package/dist/src/utils/ignorePathUtils.test.d.ts +6 -0
  428. package/dist/src/utils/ignorePathUtils.test.js +70 -0
  429. package/dist/src/utils/ignorePathUtils.test.js.map +1 -0
  430. package/dist/src/utils/memoryDiscovery.d.ts +6 -4
  431. package/dist/src/utils/memoryDiscovery.js +66 -41
  432. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  433. package/dist/src/utils/memoryDiscovery.test.js +40 -0
  434. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  435. package/dist/src/utils/memoryImportProcessor.d.ts +1 -1
  436. package/dist/src/utils/memoryImportProcessor.js +24 -15
  437. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  438. package/dist/src/utils/sessionOperations.d.ts +19 -0
  439. package/dist/src/utils/sessionOperations.js +101 -0
  440. package/dist/src/utils/sessionOperations.js.map +1 -0
  441. package/dist/src/utils/sessionOperations.test.d.ts +6 -0
  442. package/dist/src/utils/sessionOperations.test.js +92 -0
  443. package/dist/src/utils/sessionOperations.test.js.map +1 -0
  444. package/dist/src/utils/shell-utils.d.ts +15 -0
  445. package/dist/src/utils/shell-utils.js +43 -2
  446. package/dist/src/utils/shell-utils.js.map +1 -1
  447. package/dist/src/utils/textUtils.d.ts +8 -0
  448. package/dist/src/utils/textUtils.js +16 -0
  449. package/dist/src/utils/textUtils.js.map +1 -1
  450. package/dist/src/utils/tokenCalculation.d.ts +2 -0
  451. package/dist/src/utils/tokenCalculation.js +2 -2
  452. package/dist/src/utils/tokenCalculation.js.map +1 -1
  453. package/dist/tsconfig.tsbuildinfo +1 -1
  454. package/package.json +1 -1
  455. package/dist/docs/get-started/examples.md +0 -141
  456. package/dist/google-gemini-cli-core-0.36.0-preview.7.tgz +0 -0
  457. package/dist/src/sandbox/macos/MacOsSandboxManager.integration.test.js +0 -164
  458. package/dist/src/sandbox/macos/MacOsSandboxManager.integration.test.js.map +0 -1
  459. package/dist/src/sandbox/macos/commandSafety.js.map +0 -1
  460. package/dist/src/services/chatCompressionService.js.map +0 -1
  461. package/dist/src/services/chatCompressionService.test.js.map +0 -1
  462. package/dist/src/services/contextManager.js.map +0 -1
  463. package/dist/src/services/contextManager.test.js.map +0 -1
  464. package/dist/src/services/toolOutputMaskingService.js.map +0 -1
  465. package/dist/src/services/toolOutputMaskingService.test.js.map +0 -1
  466. /package/dist/src/{services/toolOutputMaskingService.test.d.ts → agents/browser/snapshotSuperseder.test.d.ts} +0 -0
  467. /package/dist/src/{services → context}/chatCompressionService.d.ts +0 -0
  468. /package/dist/src/{services → context}/chatCompressionService.js +0 -0
  469. /package/dist/src/{services → context}/chatCompressionService.test.d.ts +0 -0
  470. /package/dist/src/{services → context}/chatCompressionService.test.js +0 -0
  471. /package/dist/src/{services → context}/contextManager.test.d.ts +0 -0
  472. /package/dist/src/{sandbox/macos/MacOsSandboxManager.integration.test.d.ts → services/sandboxManager.integration.test.d.ts} +0 -0
@@ -133,12 +133,6 @@ export const BASE_SEATBELT_PROFILE = `(version 1)
133
133
  (literal "/dev/zero")
134
134
  (subpath "/tmp")
135
135
  (subpath "/private/tmp")
136
- (subpath (param "TMPDIR"))
137
- )
138
-
139
- ; Workspace access using parameterized paths
140
- (allow file-read*
141
- (subpath (param "WORKSPACE"))
142
136
  )
143
137
 
144
138
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"baseProfile.js","sourceRoot":"","sources":["../../../../src/sandbox/macos/baseProfile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmIpC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BvC,CAAC"}
1
+ {"version":3,"file":"baseProfile.js","sourceRoot":"","sources":["../../../../src/sandbox/macos/baseProfile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6HpC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BvC,CAAC"}
@@ -5,15 +5,15 @@
5
5
  */
6
6
  import { type SandboxPermissions } from '../../services/sandboxManager.js';
7
7
  /**
8
- * Options for building macOS Seatbelt arguments.
8
+ * Options for building macOS Seatbelt profile.
9
9
  */
10
10
  export interface SeatbeltArgsOptions {
11
11
  /** The primary workspace path to allow access to. */
12
12
  workspace: string;
13
13
  /** Additional paths to allow access to. */
14
- allowedPaths?: string[];
14
+ allowedPaths: string[];
15
15
  /** Absolute paths to explicitly deny read/write access to (overrides allowlists). */
16
- forbiddenPaths?: string[];
16
+ forbiddenPaths: string[];
17
17
  /** Whether to allow network access. */
18
18
  networkAccess?: boolean;
19
19
  /** Granular additional permissions. */
@@ -22,11 +22,11 @@ export interface SeatbeltArgsOptions {
22
22
  workspaceWrite?: boolean;
23
23
  }
24
24
  /**
25
- * Builds the arguments array for sandbox-exec using a strict allowlist profile.
26
- * It relies on parameters passed to sandbox-exec via the -D flag to avoid
27
- * string interpolation vulnerabilities, and normalizes paths against symlink escapes.
28
- *
29
- * Returns arguments up to the end of sandbox-exec configuration (e.g. ['-p', '<profile>', '-D', ...])
30
- * Does not include the final '--' separator or the command to run.
25
+ * Escapes a string for use within a Scheme string literal "..."
31
26
  */
32
- export declare function buildSeatbeltArgs(options: SeatbeltArgsOptions): string[];
27
+ export declare function escapeSchemeString(str: string): string;
28
+ /**
29
+ * Builds a complete macOS Seatbelt profile string using a strict allowlist.
30
+ * It embeds paths directly into the profile, properly escaped for Scheme.
31
+ */
32
+ export declare function buildSeatbeltProfile(options: SeatbeltArgsOptions): string;
@@ -7,48 +7,29 @@ import fs from 'node:fs';
7
7
  import os from 'node:os';
8
8
  import path from 'node:path';
9
9
  import { BASE_SEATBELT_PROFILE, NETWORK_SEATBELT_PROFILE, } from './baseProfile.js';
10
- import { sanitizePaths, GOVERNANCE_FILES, } from '../../services/sandboxManager.js';
10
+ import { GOVERNANCE_FILES, SECRET_FILES, } from '../../services/sandboxManager.js';
11
+ import { tryRealpath, resolveGitWorktreePaths } from '../utils/fsUtils.js';
11
12
  /**
12
- * Resolves symlinks for a given path to prevent sandbox escapes.
13
- * If a file does not exist (ENOENT), it recursively resolves the parent directory.
14
- * Other errors (e.g. EACCES) are re-thrown.
13
+ * Escapes a string for use within a Scheme string literal "..."
15
14
  */
16
- function tryRealpath(p) {
17
- try {
18
- return fs.realpathSync(p);
19
- }
20
- catch (e) {
21
- if (e instanceof Error && 'code' in e && e.code === 'ENOENT') {
22
- const parentDir = path.dirname(p);
23
- if (parentDir === p) {
24
- return p;
25
- }
26
- return path.join(tryRealpath(parentDir), path.basename(p));
27
- }
28
- throw e;
29
- }
15
+ export function escapeSchemeString(str) {
16
+ return str.replace(/[\\"]/g, '\\$&');
30
17
  }
31
18
  /**
32
- * Builds the arguments array for sandbox-exec using a strict allowlist profile.
33
- * It relies on parameters passed to sandbox-exec via the -D flag to avoid
34
- * string interpolation vulnerabilities, and normalizes paths against symlink escapes.
35
- *
36
- * Returns arguments up to the end of sandbox-exec configuration (e.g. ['-p', '<profile>', '-D', ...])
37
- * Does not include the final '--' separator or the command to run.
19
+ * Builds a complete macOS Seatbelt profile string using a strict allowlist.
20
+ * It embeds paths directly into the profile, properly escaped for Scheme.
38
21
  */
39
- export function buildSeatbeltArgs(options) {
22
+ export function buildSeatbeltProfile(options) {
40
23
  let profile = BASE_SEATBELT_PROFILE + '\n';
41
- const args = [];
42
24
  const workspacePath = tryRealpath(options.workspace);
43
- args.push('-D', `WORKSPACE=${workspacePath}`);
44
- args.push('-D', `WORKSPACE_RAW=${options.workspace}`);
45
- profile += `(allow file-read* (subpath (param "WORKSPACE_RAW")))\n`;
46
- if (options.workspaceWrite) {
47
- profile += `(allow file-write* (subpath (param "WORKSPACE_RAW")))\n`;
48
- }
25
+ profile += `(allow file-read* (subpath "${escapeSchemeString(options.workspace)}"))\n`;
26
+ profile += `(allow file-read* (subpath "${escapeSchemeString(workspacePath)}"))\n`;
49
27
  if (options.workspaceWrite) {
50
- profile += `(allow file-write* (subpath (param "WORKSPACE")))\n`;
28
+ profile += `(allow file-write* (subpath "${escapeSchemeString(options.workspace)}"))\n`;
29
+ profile += `(allow file-write* (subpath "${escapeSchemeString(workspacePath)}"))\n`;
51
30
  }
31
+ const tmpPath = tryRealpath(os.tmpdir());
32
+ profile += `(allow file-read* file-write* (subpath "${escapeSchemeString(tmpPath)}"))\n`;
52
33
  // Add explicit deny rules for governance files in the workspace.
53
34
  // These are added after the workspace allow rule to ensure they take precedence
54
35
  // (Seatbelt evaluates rules in order, later rules win for same path).
@@ -67,51 +48,48 @@ export function buildSeatbeltArgs(options) {
67
48
  // Ignore errors, use default guess
68
49
  }
69
50
  const ruleType = isDirectory ? 'subpath' : 'literal';
70
- args.push('-D', `GOVERNANCE_FILE_${i}=${governanceFile}`);
71
- profile += `(deny file-write* (${ruleType} (param "GOVERNANCE_FILE_${i}")))\n`;
51
+ profile += `(deny file-write* (${ruleType} "${escapeSchemeString(governanceFile)}"))\n`;
72
52
  if (realGovernanceFile !== governanceFile) {
73
- args.push('-D', `REAL_GOVERNANCE_FILE_${i}=${realGovernanceFile}`);
74
- profile += `(deny file-write* (${ruleType} (param "REAL_GOVERNANCE_FILE_${i}")))\n`;
53
+ profile += `(deny file-write* (${ruleType} "${escapeSchemeString(realGovernanceFile)}"))\n`;
75
54
  }
76
55
  }
77
- // Auto-detect and support git worktrees by granting read and write access to the underlying git directory
78
- try {
79
- const gitPath = path.join(workspacePath, '.git');
80
- const gitStat = fs.lstatSync(gitPath);
81
- if (gitStat.isFile()) {
82
- const gitContent = fs.readFileSync(gitPath, 'utf8');
83
- const match = gitContent.match(/^gitdir:\s*(.+)$/m);
84
- if (match && match[1]) {
85
- let worktreeGitDir = match[1].trim();
86
- if (!path.isAbsolute(worktreeGitDir)) {
87
- worktreeGitDir = path.resolve(workspacePath, worktreeGitDir);
88
- }
89
- const resolvedWorktreeGitDir = tryRealpath(worktreeGitDir);
90
- // Grant write access to the worktree's specific .git directory
91
- args.push('-D', `WORKTREE_GIT_DIR=${resolvedWorktreeGitDir}`);
92
- profile += `(allow file-read* file-write* (subpath (param "WORKTREE_GIT_DIR")))\n`;
93
- // Grant write access to the main repository's .git directory (objects, refs, etc. are shared)
94
- // resolvedWorktreeGitDir is usually like: /path/to/main-repo/.git/worktrees/worktree-name
95
- const mainGitDir = tryRealpath(path.dirname(path.dirname(resolvedWorktreeGitDir)));
96
- if (mainGitDir && mainGitDir.endsWith('.git')) {
97
- args.push('-D', `MAIN_GIT_DIR=${mainGitDir}`);
98
- profile += `(allow file-read* file-write* (subpath (param "MAIN_GIT_DIR")))\n`;
99
- }
56
+ // Add explicit deny rules for secret files (.env, .env.*) in the workspace and allowed paths.
57
+ // We use regex rules to avoid expensive file discovery scans.
58
+ // Anchoring to workspace/allowed paths to avoid over-blocking.
59
+ const searchPaths = [options.workspace, ...options.allowedPaths];
60
+ for (const basePath of searchPaths) {
61
+ const resolvedBase = tryRealpath(basePath);
62
+ for (const secret of SECRET_FILES) {
63
+ // Map pattern to Seatbelt regex
64
+ let regexPattern;
65
+ const escapedBase = escapeRegex(resolvedBase);
66
+ if (secret.pattern.endsWith('*')) {
67
+ // .env.* -> .env\..+ (match .env followed by dot and something)
68
+ // We anchor the secret file name to either a directory separator or the start of the relative path.
69
+ const basePattern = secret.pattern.slice(0, -1).replace(/\./g, '\\\\.');
70
+ regexPattern = `^${escapedBase}/(.*/)?${basePattern}[^/]+$`;
71
+ }
72
+ else {
73
+ // .env -> \.env$
74
+ const basePattern = secret.pattern.replace(/\./g, '\\\\.');
75
+ regexPattern = `^${escapedBase}/(.*/)?${basePattern}$`;
100
76
  }
77
+ profile += `(deny file-read* file-write* (regex #"${regexPattern}"))\n`;
101
78
  }
102
79
  }
103
- catch (_e) {
104
- // Ignore if .git doesn't exist, isn't readable, etc.
80
+ // Auto-detect and support git worktrees by granting read and write access to the underlying git directory
81
+ const { worktreeGitDir, mainGitDir } = resolveGitWorktreePaths(workspacePath);
82
+ if (worktreeGitDir) {
83
+ profile += `(allow file-read* file-write* (subpath "${escapeSchemeString(worktreeGitDir)}"))\n`;
84
+ }
85
+ if (mainGitDir) {
86
+ profile += `(allow file-read* file-write* (subpath "${escapeSchemeString(mainGitDir)}"))\n`;
105
87
  }
106
- const tmpPath = tryRealpath(os.tmpdir());
107
- args.push('-D', `TMPDIR=${tmpPath}`);
108
88
  const nodeRootPath = tryRealpath(path.dirname(path.dirname(process.execPath)));
109
- args.push('-D', `NODE_ROOT=${nodeRootPath}`);
110
- profile += `(allow file-read* (subpath (param "NODE_ROOT")))\n`;
89
+ profile += `(allow file-read* (subpath "${escapeSchemeString(nodeRootPath)}"))\n`;
111
90
  // Add PATH directories as read-only to support nvm, homebrew, etc.
112
91
  if (process.env['PATH']) {
113
92
  const paths = process.env['PATH'].split(':');
114
- let pathIndex = 0;
115
93
  const addedPaths = new Set();
116
94
  for (const p of paths) {
117
95
  if (!p.trim())
@@ -126,9 +104,7 @@ export function buildSeatbeltArgs(options) {
126
104
  }
127
105
  if (!addedPaths.has(resolved)) {
128
106
  addedPaths.add(resolved);
129
- args.push('-D', `SYS_PATH_${pathIndex}=${resolved}`);
130
- profile += `(allow file-read* (subpath (param "SYS_PATH_${pathIndex}")))\n`;
131
- pathIndex++;
107
+ profile += `(allow file-read* (subpath "${escapeSchemeString(resolved)}"))\n`;
132
108
  }
133
109
  }
134
110
  catch (_e) {
@@ -137,20 +113,17 @@ export function buildSeatbeltArgs(options) {
137
113
  }
138
114
  }
139
115
  // Handle allowedPaths
140
- const allowedPaths = sanitizePaths(options.allowedPaths) || [];
116
+ const allowedPaths = options.allowedPaths;
141
117
  for (let i = 0; i < allowedPaths.length; i++) {
142
118
  const allowedPath = tryRealpath(allowedPaths[i]);
143
- args.push('-D', `ALLOWED_PATH_${i}=${allowedPath}`);
144
- profile += `(allow file-read* file-write* (subpath (param "ALLOWED_PATH_${i}")))\n`;
119
+ profile += `(allow file-read* file-write* (subpath "${escapeSchemeString(allowedPath)}"))\n`;
145
120
  }
146
121
  // Handle granular additional permissions
147
122
  if (options.additionalPermissions?.fileSystem) {
148
123
  const { read, write } = options.additionalPermissions.fileSystem;
149
124
  if (read) {
150
- read.forEach((p, i) => {
151
- const resolved = tryRealpath(p);
152
- const paramName = `ADDITIONAL_READ_${i}`;
153
- args.push('-D', `${paramName}=${resolved}`);
125
+ for (let i = 0; i < read.length; i++) {
126
+ const resolved = tryRealpath(read[i]);
154
127
  let isFile = false;
155
128
  try {
156
129
  isFile = fs.statSync(resolved).isFile();
@@ -159,18 +132,16 @@ export function buildSeatbeltArgs(options) {
159
132
  // Ignore error
160
133
  }
161
134
  if (isFile) {
162
- profile += `(allow file-read* (literal (param "${paramName}")))\n`;
135
+ profile += `(allow file-read* (literal "${escapeSchemeString(resolved)}"))\n`;
163
136
  }
164
137
  else {
165
- profile += `(allow file-read* (subpath (param "${paramName}")))\n`;
138
+ profile += `(allow file-read* (subpath "${escapeSchemeString(resolved)}"))\n`;
166
139
  }
167
- });
140
+ }
168
141
  }
169
142
  if (write) {
170
- write.forEach((p, i) => {
171
- const resolved = tryRealpath(p);
172
- const paramName = `ADDITIONAL_WRITE_${i}`;
173
- args.push('-D', `${paramName}=${resolved}`);
143
+ for (let i = 0; i < write.length; i++) {
144
+ const resolved = tryRealpath(write[i]);
174
145
  let isFile = false;
175
146
  try {
176
147
  isFile = fs.statSync(resolved).isFile();
@@ -179,25 +150,42 @@ export function buildSeatbeltArgs(options) {
179
150
  // Ignore error
180
151
  }
181
152
  if (isFile) {
182
- profile += `(allow file-read* file-write* (literal (param "${paramName}")))\n`;
153
+ profile += `(allow file-read* file-write* (literal "${escapeSchemeString(resolved)}"))\n`;
183
154
  }
184
155
  else {
185
- profile += `(allow file-read* file-write* (subpath (param "${paramName}")))\n`;
156
+ profile += `(allow file-read* file-write* (subpath "${escapeSchemeString(resolved)}"))\n`;
186
157
  }
187
- });
158
+ }
188
159
  }
189
160
  }
190
161
  // Handle forbiddenPaths
191
- const forbiddenPaths = sanitizePaths(options.forbiddenPaths) || [];
162
+ const forbiddenPaths = options.forbiddenPaths;
192
163
  for (let i = 0; i < forbiddenPaths.length; i++) {
193
164
  const forbiddenPath = tryRealpath(forbiddenPaths[i]);
194
- args.push('-D', `FORBIDDEN_PATH_${i}=${forbiddenPath}`);
195
- profile += `(deny file-read* file-write* (subpath (param "FORBIDDEN_PATH_${i}")))\n`;
165
+ profile += `(deny file-read* file-write* (subpath "${escapeSchemeString(forbiddenPath)}"))\n`;
196
166
  }
197
167
  if (options.networkAccess || options.additionalPermissions?.network) {
198
168
  profile += NETWORK_SEATBELT_PROFILE;
199
169
  }
200
- args.unshift('-p', profile);
201
- return args;
170
+ return profile;
171
+ }
172
+ /**
173
+ * Escapes a string for use within a Seatbelt regex literal #"..."
174
+ */
175
+ function escapeRegex(str) {
176
+ return str.replace(/[.*+?^${}()|[\]\\"]/g, (c) => {
177
+ if (c === '"') {
178
+ // Escape double quotes for the Scheme string literal
179
+ return '\\"';
180
+ }
181
+ if (c === '\\') {
182
+ // A literal backslash needs to be \\ in the regex.
183
+ // To get \\ in the regex engine, we need \\\\ in the Scheme string literal.
184
+ return '\\\\\\\\';
185
+ }
186
+ // For other regex special characters (like .), we need \c in the regex.
187
+ // To get \c in the regex engine, we need \\c in the Scheme string literal.
188
+ return '\\\\' + c;
189
+ });
202
190
  }
203
191
  //# sourceMappingURL=seatbeltArgsBuilder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"seatbeltArgsBuilder.js","sourceRoot":"","sources":["../../../../src/sandbox/macos/seatbeltArgsBuilder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"seatbeltArgsBuilder.js","sourceRoot":"","sources":["../../../../src/sandbox/macos/seatbeltArgsBuilder.ts"],"names":[],"mappings":"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"}
@@ -3,116 +3,152 @@
3
3
  * Copyright 2026 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { describe, it, expect, vi } from 'vitest';
7
- import { buildSeatbeltArgs } from './seatbeltArgsBuilder.js';
6
+ import { describe, it, expect, vi, afterEach } from 'vitest';
7
+ import { buildSeatbeltProfile, escapeSchemeString, } from './seatbeltArgsBuilder.js';
8
+ import * as fsUtils from '../utils/fsUtils.js';
8
9
  import fs from 'node:fs';
9
- import os from 'node:os';
10
+ vi.mock('../utils/fsUtils.js', async () => {
11
+ const actual = await vi.importActual('../utils/fsUtils.js');
12
+ return {
13
+ ...actual,
14
+ tryRealpath: vi.fn((p) => p),
15
+ resolveGitWorktreePaths: vi.fn(() => ({})),
16
+ };
17
+ });
10
18
  describe('seatbeltArgsBuilder', () => {
11
- it('should build a strict allowlist profile allowing the workspace via param', () => {
12
- // Mock realpathSync to just return the path for testing
13
- vi.spyOn(fs, 'realpathSync').mockImplementation((p) => p);
14
- const args = buildSeatbeltArgs({ workspace: '/Users/test/workspace' });
15
- expect(args[0]).toBe('-p');
16
- const profile = args[1];
17
- expect(profile).toContain('(version 1)');
18
- expect(profile).toContain('(deny default)');
19
- expect(profile).toContain('(allow process-exec)');
20
- expect(profile).toContain('(subpath (param "WORKSPACE"))');
21
- expect(profile).not.toContain('(allow network*)');
22
- expect(args).toContain('-D');
23
- expect(args).toContain('WORKSPACE=/Users/test/workspace');
24
- expect(args).toContain(`TMPDIR=${os.tmpdir()}`);
19
+ afterEach(() => {
25
20
  vi.restoreAllMocks();
26
21
  });
27
- it('should allow network when networkAccess is true', () => {
28
- const args = buildSeatbeltArgs({ workspace: '/test', networkAccess: true });
29
- const profile = args[1];
30
- expect(profile).toContain('(allow network-outbound)');
31
- });
32
- it('should parameterize allowed paths and normalize them', () => {
33
- vi.spyOn(fs, 'realpathSync').mockImplementation((p) => {
34
- if (p === '/test/symlink')
35
- return '/test/real_path';
36
- return p;
22
+ describe('escapeSchemeString', () => {
23
+ it('escapes quotes and backslashes', () => {
24
+ expect(escapeSchemeString('path/to/"file"')).toBe('path/to/\\"file\\"');
25
+ expect(escapeSchemeString('path\\to\\file')).toBe('path\\\\to\\\\file');
37
26
  });
38
- const args = buildSeatbeltArgs({
39
- workspace: '/test',
40
- allowedPaths: ['/custom/path1', '/test/symlink'],
41
- });
42
- const profile = args[1];
43
- expect(profile).toContain('(subpath (param "ALLOWED_PATH_0"))');
44
- expect(profile).toContain('(subpath (param "ALLOWED_PATH_1"))');
45
- expect(args).toContain('-D');
46
- expect(args).toContain('ALLOWED_PATH_0=/custom/path1');
47
- expect(args).toContain('ALLOWED_PATH_1=/test/real_path');
48
- vi.restoreAllMocks();
49
27
  });
50
- it('should resolve parent directories if a file does not exist', () => {
51
- vi.spyOn(fs, 'realpathSync').mockImplementation((p) => {
52
- if (p === '/test/symlink/nonexistent.txt') {
53
- const error = new Error('ENOENT');
54
- Object.assign(error, { code: 'ENOENT' });
55
- throw error;
56
- }
57
- if (p === '/test/symlink') {
58
- return '/test/real_path';
59
- }
60
- return p;
28
+ describe('buildSeatbeltProfile', () => {
29
+ it('should build a strict allowlist profile allowing the workspace', () => {
30
+ vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p);
31
+ const profile = buildSeatbeltProfile({
32
+ workspace: '/Users/test/workspace',
33
+ allowedPaths: [],
34
+ forbiddenPaths: [],
35
+ });
36
+ expect(profile).toContain('(version 1)');
37
+ expect(profile).toContain('(deny default)');
38
+ expect(profile).toContain('(allow process-exec)');
39
+ expect(profile).toContain(`(subpath "/Users/test/workspace")`);
40
+ expect(profile).not.toContain('(allow network*)');
61
41
  });
62
- const args = buildSeatbeltArgs({
63
- workspace: '/test/symlink/nonexistent.txt',
42
+ it('should allow network when networkAccess is true', () => {
43
+ vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p);
44
+ const profile = buildSeatbeltProfile({
45
+ workspace: '/test',
46
+ allowedPaths: [],
47
+ forbiddenPaths: [],
48
+ networkAccess: true,
49
+ });
50
+ expect(profile).toContain('(allow network-outbound)');
64
51
  });
65
- expect(args).toContain('WORKSPACE=/test/real_path/nonexistent.txt');
66
- vi.restoreAllMocks();
67
- });
68
- it('should throw if realpathSync throws a non-ENOENT error', () => {
69
- vi.spyOn(fs, 'realpathSync').mockImplementation(() => {
70
- const error = new Error('Permission denied');
71
- Object.assign(error, { code: 'EACCES' });
72
- throw error;
52
+ describe('governance files', () => {
53
+ it('should inject explicit deny rules for governance files', () => {
54
+ vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p.toString());
55
+ vi.spyOn(fs, 'existsSync').mockReturnValue(true);
56
+ vi.spyOn(fs, 'lstatSync').mockImplementation((p) => ({
57
+ isDirectory: () => p.toString().endsWith('.git'),
58
+ isFile: () => !p.toString().endsWith('.git'),
59
+ }));
60
+ const profile = buildSeatbeltProfile({
61
+ workspace: '/test/workspace',
62
+ allowedPaths: [],
63
+ forbiddenPaths: [],
64
+ });
65
+ expect(profile).toContain(`(deny file-write* (literal "/test/workspace/.gitignore"))`);
66
+ expect(profile).toContain(`(deny file-write* (subpath "/test/workspace/.git"))`);
67
+ });
68
+ it('should protect both the symlink and the real path if they differ', () => {
69
+ vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => {
70
+ if (p === '/test/workspace/.gitignore')
71
+ return '/test/real/.gitignore';
72
+ return p.toString();
73
+ });
74
+ vi.spyOn(fs, 'existsSync').mockReturnValue(true);
75
+ vi.spyOn(fs, 'lstatSync').mockImplementation(() => ({
76
+ isDirectory: () => false,
77
+ isFile: () => true,
78
+ }));
79
+ const profile = buildSeatbeltProfile({
80
+ workspace: '/test/workspace',
81
+ allowedPaths: [],
82
+ forbiddenPaths: [],
83
+ });
84
+ expect(profile).toContain(`(deny file-write* (literal "/test/workspace/.gitignore"))`);
85
+ expect(profile).toContain(`(deny file-write* (literal "/test/real/.gitignore"))`);
86
+ });
73
87
  });
74
- expect(() => buildSeatbeltArgs({
75
- workspace: '/test/workspace',
76
- })).toThrow('Permission denied');
77
- vi.restoreAllMocks();
78
- });
79
- describe('governance files', () => {
80
- it('should inject explicit deny rules for governance files', () => {
81
- vi.spyOn(fs, 'realpathSync').mockImplementation((p) => p.toString());
82
- vi.spyOn(fs, 'existsSync').mockReturnValue(true);
83
- vi.spyOn(fs, 'lstatSync').mockImplementation((p) => ({
84
- isDirectory: () => p.toString().endsWith('.git'),
85
- isFile: () => !p.toString().endsWith('.git'),
86
- }));
87
- const args = buildSeatbeltArgs({ workspace: '/Users/test/workspace' });
88
- const profile = args[1];
89
- // .gitignore should be a literal deny
90
- expect(args).toContain('-D');
91
- expect(args).toContain('GOVERNANCE_FILE_0=/Users/test/workspace/.gitignore');
92
- expect(profile).toContain('(deny file-write* (literal (param "GOVERNANCE_FILE_0")))');
93
- // .git should be a subpath deny
94
- expect(args).toContain('GOVERNANCE_FILE_2=/Users/test/workspace/.git');
95
- expect(profile).toContain('(deny file-write* (subpath (param "GOVERNANCE_FILE_2")))');
96
- vi.restoreAllMocks();
88
+ describe('allowedPaths', () => {
89
+ it('should embed allowed paths and normalize them', () => {
90
+ vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => {
91
+ if (p === '/test/symlink')
92
+ return '/test/real_path';
93
+ return p;
94
+ });
95
+ const profile = buildSeatbeltProfile({
96
+ workspace: '/test',
97
+ allowedPaths: ['/custom/path1', '/test/symlink'],
98
+ forbiddenPaths: [],
99
+ });
100
+ expect(profile).toContain(`(subpath "/custom/path1")`);
101
+ expect(profile).toContain(`(subpath "/test/real_path")`);
102
+ });
97
103
  });
98
- it('should protect both the symlink and the real path if they differ', () => {
99
- vi.spyOn(fs, 'realpathSync').mockImplementation((p) => {
100
- if (p === '/test/workspace/.gitignore')
101
- return '/test/real/.gitignore';
102
- return p.toString();
104
+ describe('forbiddenPaths', () => {
105
+ it('should explicitly deny forbidden paths', () => {
106
+ vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p);
107
+ const profile = buildSeatbeltProfile({
108
+ workspace: '/test',
109
+ allowedPaths: [],
110
+ forbiddenPaths: ['/secret/path'],
111
+ });
112
+ expect(profile).toContain(`(deny file-read* file-write* (subpath "/secret/path"))`);
113
+ });
114
+ it('resolves forbidden symlink paths to their real paths', () => {
115
+ vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => {
116
+ if (p === '/test/symlink' || p === '/test/missing-dir') {
117
+ return '/test/real_path';
118
+ }
119
+ return p;
120
+ });
121
+ const profile = buildSeatbeltProfile({
122
+ workspace: '/test',
123
+ allowedPaths: [],
124
+ forbiddenPaths: ['/test/symlink'],
125
+ });
126
+ expect(profile).toContain(`(deny file-read* file-write* (subpath "/test/real_path"))`);
127
+ });
128
+ it('explicitly denies non-existent forbidden paths to prevent creation', () => {
129
+ vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p);
130
+ const profile = buildSeatbeltProfile({
131
+ workspace: '/test',
132
+ allowedPaths: [],
133
+ forbiddenPaths: ['/test/missing-dir/missing-file.txt'],
134
+ });
135
+ expect(profile).toContain(`(deny file-read* file-write* (subpath "/test/missing-dir/missing-file.txt"))`);
136
+ });
137
+ it('should override allowed paths if a path is also in forbidden paths', () => {
138
+ vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p);
139
+ const profile = buildSeatbeltProfile({
140
+ workspace: '/test',
141
+ allowedPaths: ['/custom/path1'],
142
+ forbiddenPaths: ['/custom/path1'],
143
+ });
144
+ const allowString = `(allow file-read* file-write* (subpath "/custom/path1"))`;
145
+ const denyString = `(deny file-read* file-write* (subpath "/custom/path1"))`;
146
+ expect(profile).toContain(allowString);
147
+ expect(profile).toContain(denyString);
148
+ const allowIndex = profile.indexOf(allowString);
149
+ const denyIndex = profile.indexOf(denyString);
150
+ expect(denyIndex).toBeGreaterThan(allowIndex);
103
151
  });
104
- vi.spyOn(fs, 'existsSync').mockReturnValue(true);
105
- vi.spyOn(fs, 'lstatSync').mockImplementation(() => ({
106
- isDirectory: () => false,
107
- isFile: () => true,
108
- }));
109
- const args = buildSeatbeltArgs({ workspace: '/test/workspace' });
110
- const profile = args[1];
111
- expect(args).toContain('GOVERNANCE_FILE_0=/test/workspace/.gitignore');
112
- expect(args).toContain('REAL_GOVERNANCE_FILE_0=/test/real/.gitignore');
113
- expect(profile).toContain('(deny file-write* (literal (param "GOVERNANCE_FILE_0")))');
114
- expect(profile).toContain('(deny file-write* (literal (param "REAL_GOVERNANCE_FILE_0")))');
115
- vi.restoreAllMocks();
116
152
  });
117
153
  });
118
154
  });