@openai/agents-core 0.8.4 → 0.9.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 (462) hide show
  1. package/dist/agentToolRunConfig.js +3 -0
  2. package/dist/agentToolRunConfig.js.map +1 -1
  3. package/dist/agentToolRunConfig.mjs +3 -0
  4. package/dist/agentToolRunConfig.mjs.map +1 -1
  5. package/dist/errors.d.ts +10 -0
  6. package/dist/errors.js +15 -1
  7. package/dist/errors.js.map +1 -1
  8. package/dist/errors.mjs +13 -0
  9. package/dist/errors.mjs.map +1 -1
  10. package/dist/handoff.js +1 -1
  11. package/dist/handoff.js.map +1 -1
  12. package/dist/handoff.mjs +1 -1
  13. package/dist/handoff.mjs.map +1 -1
  14. package/dist/index.d.ts +5 -4
  15. package/dist/index.js +6 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +3 -2
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/items.d.ts +13 -0
  20. package/dist/items.js +15 -0
  21. package/dist/items.js.map +1 -1
  22. package/dist/items.mjs +15 -0
  23. package/dist/items.mjs.map +1 -1
  24. package/dist/memory/historyMutations.d.ts +6 -0
  25. package/dist/memory/historyMutations.js +32 -0
  26. package/dist/memory/historyMutations.js.map +1 -0
  27. package/dist/memory/historyMutations.mjs +29 -0
  28. package/dist/memory/historyMutations.mjs.map +1 -0
  29. package/dist/memory/memorySession.d.ts +3 -2
  30. package/dist/memory/memorySession.js +7 -0
  31. package/dist/memory/memorySession.js.map +1 -1
  32. package/dist/memory/memorySession.mjs +7 -0
  33. package/dist/memory/memorySession.mjs.map +1 -1
  34. package/dist/memory/session.d.ts +15 -0
  35. package/dist/memory/session.js +6 -0
  36. package/dist/memory/session.js.map +1 -1
  37. package/dist/memory/session.mjs +5 -0
  38. package/dist/memory/session.mjs.map +1 -1
  39. package/dist/metadata.js +2 -2
  40. package/dist/metadata.mjs +2 -2
  41. package/dist/model.d.ts +21 -0
  42. package/dist/run.d.ts +7 -1
  43. package/dist/run.js +116 -57
  44. package/dist/run.js.map +1 -1
  45. package/dist/run.mjs +117 -58
  46. package/dist/run.mjs.map +1 -1
  47. package/dist/runState.d.ts +83 -1
  48. package/dist/runState.js +96 -11
  49. package/dist/runState.js.map +1 -1
  50. package/dist/runState.mjs +95 -11
  51. package/dist/runState.mjs.map +1 -1
  52. package/dist/runner/errorHandlers.d.ts +13 -4
  53. package/dist/runner/errorHandlers.js +22 -4
  54. package/dist/runner/errorHandlers.js.map +1 -1
  55. package/dist/runner/errorHandlers.mjs +21 -4
  56. package/dist/runner/errorHandlers.mjs.map +1 -1
  57. package/dist/runner/items.js +11 -1
  58. package/dist/runner/items.js.map +1 -1
  59. package/dist/runner/items.mjs +11 -1
  60. package/dist/runner/items.mjs.map +1 -1
  61. package/dist/runner/modelPreparation.d.ts +1 -1
  62. package/dist/runner/modelPreparation.js +7 -7
  63. package/dist/runner/modelPreparation.js.map +1 -1
  64. package/dist/runner/modelPreparation.mjs +7 -7
  65. package/dist/runner/modelPreparation.mjs.map +1 -1
  66. package/dist/runner/runLoop.d.ts +2 -1
  67. package/dist/runner/runLoop.js +2 -2
  68. package/dist/runner/runLoop.js.map +1 -1
  69. package/dist/runner/runLoop.mjs +2 -2
  70. package/dist/runner/runLoop.mjs.map +1 -1
  71. package/dist/runner/sandbox.d.ts +33 -0
  72. package/dist/runner/sandbox.js +92 -0
  73. package/dist/runner/sandbox.js.map +1 -0
  74. package/dist/runner/sandbox.mjs +83 -0
  75. package/dist/runner/sandbox.mjs.map +1 -0
  76. package/dist/runner/toolExecution.js +25 -13
  77. package/dist/runner/toolExecution.js.map +1 -1
  78. package/dist/runner/toolExecution.mjs +25 -13
  79. package/dist/runner/toolExecution.mjs.map +1 -1
  80. package/dist/runner/tracing.js +1 -0
  81. package/dist/runner/tracing.js.map +1 -1
  82. package/dist/runner/tracing.mjs +1 -0
  83. package/dist/runner/tracing.mjs.map +1 -1
  84. package/dist/runner/turnPreparation.d.ts +2 -4
  85. package/dist/runner/turnPreparation.js +7 -3
  86. package/dist/runner/turnPreparation.js.map +1 -1
  87. package/dist/runner/turnPreparation.mjs +7 -3
  88. package/dist/runner/turnPreparation.mjs.map +1 -1
  89. package/dist/runner/turnResolution.js +158 -31
  90. package/dist/runner/turnResolution.js.map +1 -1
  91. package/dist/runner/turnResolution.mjs +160 -33
  92. package/dist/runner/turnResolution.mjs.map +1 -1
  93. package/dist/runner/types.d.ts +8 -8
  94. package/dist/sandbox/agent.d.ts +24 -0
  95. package/dist/sandbox/agent.js +68 -0
  96. package/dist/sandbox/agent.js.map +1 -0
  97. package/dist/sandbox/agent.mjs +64 -0
  98. package/dist/sandbox/agent.mjs.map +1 -0
  99. package/dist/sandbox/brand.d.ts +1 -0
  100. package/dist/sandbox/brand.js +5 -0
  101. package/dist/sandbox/brand.js.map +1 -0
  102. package/dist/sandbox/brand.mjs +2 -0
  103. package/dist/sandbox/brand.mjs.map +1 -0
  104. package/dist/sandbox/capabilities/base.d.ts +25 -0
  105. package/dist/sandbox/capabilities/base.js +89 -0
  106. package/dist/sandbox/capabilities/base.js.map +1 -0
  107. package/dist/sandbox/capabilities/base.mjs +84 -0
  108. package/dist/sandbox/capabilities/base.mjs.map +1 -0
  109. package/dist/sandbox/capabilities/compaction.d.ts +33 -0
  110. package/dist/sandbox/capabilities/compaction.js +172 -0
  111. package/dist/sandbox/capabilities/compaction.js.map +1 -0
  112. package/dist/sandbox/capabilities/compaction.mjs +164 -0
  113. package/dist/sandbox/capabilities/compaction.mjs.map +1 -0
  114. package/dist/sandbox/capabilities/filesystem.d.ts +14 -0
  115. package/dist/sandbox/capabilities/filesystem.js +447 -0
  116. package/dist/sandbox/capabilities/filesystem.js.map +1 -0
  117. package/dist/sandbox/capabilities/filesystem.mjs +444 -0
  118. package/dist/sandbox/capabilities/filesystem.mjs.map +1 -0
  119. package/dist/sandbox/capabilities/index.d.ts +19 -0
  120. package/dist/sandbox/capabilities/index.js +31 -0
  121. package/dist/sandbox/capabilities/index.js.map +1 -0
  122. package/dist/sandbox/capabilities/index.mjs +17 -0
  123. package/dist/sandbox/capabilities/index.mjs.map +1 -0
  124. package/dist/sandbox/capabilities/memory.d.ts +52 -0
  125. package/dist/sandbox/capabilities/memory.js +290 -0
  126. package/dist/sandbox/capabilities/memory.js.map +1 -0
  127. package/dist/sandbox/capabilities/memory.mjs +286 -0
  128. package/dist/sandbox/capabilities/memory.mjs.map +1 -0
  129. package/dist/sandbox/capabilities/shell.d.ts +15 -0
  130. package/dist/sandbox/capabilities/shell.js +130 -0
  131. package/dist/sandbox/capabilities/shell.js.map +1 -0
  132. package/dist/sandbox/capabilities/shell.mjs +127 -0
  133. package/dist/sandbox/capabilities/shell.mjs.map +1 -0
  134. package/dist/sandbox/capabilities/skills.d.ts +47 -0
  135. package/dist/sandbox/capabilities/skills.js +453 -0
  136. package/dist/sandbox/capabilities/skills.js.map +1 -0
  137. package/dist/sandbox/capabilities/skills.mjs +449 -0
  138. package/dist/sandbox/capabilities/skills.mjs.map +1 -0
  139. package/dist/sandbox/capabilities/transport.d.ts +3 -0
  140. package/dist/sandbox/capabilities/transport.js +33 -0
  141. package/dist/sandbox/capabilities/transport.js.map +1 -0
  142. package/dist/sandbox/capabilities/transport.mjs +28 -0
  143. package/dist/sandbox/capabilities/transport.mjs.map +1 -0
  144. package/dist/sandbox/client.d.ts +53 -0
  145. package/dist/sandbox/client.js +34 -0
  146. package/dist/sandbox/client.js.map +1 -0
  147. package/dist/sandbox/client.mjs +31 -0
  148. package/dist/sandbox/client.mjs.map +1 -0
  149. package/dist/sandbox/entries/factories.d.ts +17 -0
  150. package/dist/sandbox/entries/factories.js +112 -0
  151. package/dist/sandbox/entries/factories.js.map +1 -0
  152. package/dist/sandbox/entries/factories.mjs +94 -0
  153. package/dist/sandbox/entries/factories.mjs.map +1 -0
  154. package/dist/sandbox/entries/guards.d.ts +5 -0
  155. package/dist/sandbox/entries/guards.js +19 -0
  156. package/dist/sandbox/entries/guards.js.map +1 -0
  157. package/dist/sandbox/entries/guards.mjs +13 -0
  158. package/dist/sandbox/entries/guards.mjs.map +1 -0
  159. package/dist/sandbox/entries/index.d.ts +3 -0
  160. package/dist/sandbox/entries/index.js +26 -0
  161. package/dist/sandbox/entries/index.js.map +1 -0
  162. package/dist/sandbox/entries/index.mjs +3 -0
  163. package/dist/sandbox/entries/index.mjs.map +1 -0
  164. package/dist/sandbox/entries/types.d.ts +177 -0
  165. package/dist/sandbox/entries/types.js +3 -0
  166. package/dist/sandbox/entries/types.js.map +1 -0
  167. package/dist/sandbox/entries/types.mjs +2 -0
  168. package/dist/sandbox/entries/types.mjs.map +1 -0
  169. package/dist/sandbox/errors.d.ts +151 -0
  170. package/dist/sandbox/errors.js +303 -0
  171. package/dist/sandbox/errors.js.map +1 -0
  172. package/dist/sandbox/errors.mjs +251 -0
  173. package/dist/sandbox/errors.mjs.map +1 -0
  174. package/dist/sandbox/events.d.ts +51 -0
  175. package/dist/sandbox/events.js +104 -0
  176. package/dist/sandbox/events.js.map +1 -0
  177. package/dist/sandbox/events.mjs +95 -0
  178. package/dist/sandbox/events.mjs.map +1 -0
  179. package/dist/sandbox/index.d.ts +14 -0
  180. package/dist/sandbox/index.js +31 -0
  181. package/dist/sandbox/index.js.map +1 -0
  182. package/dist/sandbox/index.mjs +15 -0
  183. package/dist/sandbox/index.mjs.map +1 -0
  184. package/dist/sandbox/internal.d.ts +7 -0
  185. package/dist/sandbox/internal.js +46 -0
  186. package/dist/sandbox/internal.js.map +1 -0
  187. package/dist/sandbox/internal.mjs +8 -0
  188. package/dist/sandbox/internal.mjs.map +1 -0
  189. package/dist/sandbox/local.d.ts +3 -0
  190. package/dist/sandbox/local.js +20 -0
  191. package/dist/sandbox/local.js.map +1 -0
  192. package/dist/sandbox/local.mjs +4 -0
  193. package/dist/sandbox/local.mjs.map +1 -0
  194. package/dist/sandbox/localSkills.d.ts +13 -0
  195. package/dist/sandbox/localSkills.js +62 -0
  196. package/dist/sandbox/localSkills.js.map +1 -0
  197. package/dist/sandbox/localSkills.mjs +59 -0
  198. package/dist/sandbox/localSkills.mjs.map +1 -0
  199. package/dist/sandbox/manifest.d.ts +86 -0
  200. package/dist/sandbox/manifest.js +553 -0
  201. package/dist/sandbox/manifest.js.map +1 -0
  202. package/dist/sandbox/manifest.mjs +545 -0
  203. package/dist/sandbox/manifest.mjs.map +1 -0
  204. package/dist/sandbox/memory/generation.d.ts +56 -0
  205. package/dist/sandbox/memory/generation.js +426 -0
  206. package/dist/sandbox/memory/generation.js.map +1 -0
  207. package/dist/sandbox/memory/generation.mjs +385 -0
  208. package/dist/sandbox/memory/generation.mjs.map +1 -0
  209. package/dist/sandbox/memory/prompts.d.ts +16 -0
  210. package/dist/sandbox/memory/prompts.js +1685 -0
  211. package/dist/sandbox/memory/prompts.js.map +1 -0
  212. package/dist/sandbox/memory/prompts.mjs +1679 -0
  213. package/dist/sandbox/memory/prompts.mjs.map +1 -0
  214. package/dist/sandbox/memory/rollouts.d.ts +33 -0
  215. package/dist/sandbox/memory/rollouts.js +228 -0
  216. package/dist/sandbox/memory/rollouts.js.map +1 -0
  217. package/dist/sandbox/memory/rollouts.mjs +221 -0
  218. package/dist/sandbox/memory/rollouts.mjs.map +1 -0
  219. package/dist/sandbox/memory/storage.d.ts +70 -0
  220. package/dist/sandbox/memory/storage.js +543 -0
  221. package/dist/sandbox/memory/storage.js.map +1 -0
  222. package/dist/sandbox/memory/storage.mjs +537 -0
  223. package/dist/sandbox/memory/storage.mjs.map +1 -0
  224. package/dist/sandbox/pathGrants.d.ts +11 -0
  225. package/dist/sandbox/pathGrants.js +28 -0
  226. package/dist/sandbox/pathGrants.js.map +1 -0
  227. package/dist/sandbox/pathGrants.mjs +25 -0
  228. package/dist/sandbox/pathGrants.mjs.map +1 -0
  229. package/dist/sandbox/permissions.d.ts +29 -0
  230. package/dist/sandbox/permissions.js +140 -0
  231. package/dist/sandbox/permissions.js.map +1 -0
  232. package/dist/sandbox/permissions.mjs +134 -0
  233. package/dist/sandbox/permissions.mjs.map +1 -0
  234. package/dist/sandbox/runtime/agentKeys.d.ts +7 -0
  235. package/dist/sandbox/runtime/agentKeys.js +76 -0
  236. package/dist/sandbox/runtime/agentKeys.js.map +1 -0
  237. package/dist/sandbox/runtime/agentKeys.mjs +69 -0
  238. package/dist/sandbox/runtime/agentKeys.mjs.map +1 -0
  239. package/dist/sandbox/runtime/agentPreparation.d.ts +20 -0
  240. package/dist/sandbox/runtime/agentPreparation.js +178 -0
  241. package/dist/sandbox/runtime/agentPreparation.js.map +1 -0
  242. package/dist/sandbox/runtime/agentPreparation.mjs +172 -0
  243. package/dist/sandbox/runtime/agentPreparation.mjs.map +1 -0
  244. package/dist/sandbox/runtime/index.d.ts +5 -0
  245. package/dist/sandbox/runtime/index.js +22 -0
  246. package/dist/sandbox/runtime/index.js.map +1 -0
  247. package/dist/sandbox/runtime/index.mjs +6 -0
  248. package/dist/sandbox/runtime/index.mjs.map +1 -0
  249. package/dist/sandbox/runtime/livePreservedSessions.d.ts +25 -0
  250. package/dist/sandbox/runtime/livePreservedSessions.js +58 -0
  251. package/dist/sandbox/runtime/livePreservedSessions.js.map +1 -0
  252. package/dist/sandbox/runtime/livePreservedSessions.mjs +51 -0
  253. package/dist/sandbox/runtime/livePreservedSessions.mjs.map +1 -0
  254. package/dist/sandbox/runtime/manager.d.ts +68 -0
  255. package/dist/sandbox/runtime/manager.js +704 -0
  256. package/dist/sandbox/runtime/manager.js.map +1 -0
  257. package/dist/sandbox/runtime/manager.mjs +697 -0
  258. package/dist/sandbox/runtime/manager.mjs.map +1 -0
  259. package/dist/sandbox/runtime/prompts.d.ts +6 -0
  260. package/dist/sandbox/runtime/prompts.js +108 -0
  261. package/dist/sandbox/runtime/prompts.js.map +1 -0
  262. package/dist/sandbox/runtime/prompts.mjs +101 -0
  263. package/dist/sandbox/runtime/prompts.mjs.map +1 -0
  264. package/dist/sandbox/runtime/providedSessionManifest.d.ts +3 -0
  265. package/dist/sandbox/runtime/providedSessionManifest.js +175 -0
  266. package/dist/sandbox/runtime/providedSessionManifest.js.map +1 -0
  267. package/dist/sandbox/runtime/providedSessionManifest.mjs +172 -0
  268. package/dist/sandbox/runtime/providedSessionManifest.mjs.map +1 -0
  269. package/dist/sandbox/runtime/runAsManifest.d.ts +4 -0
  270. package/dist/sandbox/runtime/runAsManifest.js +40 -0
  271. package/dist/sandbox/runtime/runAsManifest.js.map +1 -0
  272. package/dist/sandbox/runtime/runAsManifest.mjs +36 -0
  273. package/dist/sandbox/runtime/runAsManifest.mjs.map +1 -0
  274. package/dist/sandbox/runtime/sessionLifecycle.d.ts +6 -0
  275. package/dist/sandbox/runtime/sessionLifecycle.js +222 -0
  276. package/dist/sandbox/runtime/sessionLifecycle.js.map +1 -0
  277. package/dist/sandbox/runtime/sessionLifecycle.mjs +215 -0
  278. package/dist/sandbox/runtime/sessionLifecycle.mjs.map +1 -0
  279. package/dist/sandbox/runtime/sessionSerialization.d.ts +12 -0
  280. package/dist/sandbox/runtime/sessionSerialization.js +74 -0
  281. package/dist/sandbox/runtime/sessionSerialization.js.map +1 -0
  282. package/dist/sandbox/runtime/sessionSerialization.mjs +71 -0
  283. package/dist/sandbox/runtime/sessionSerialization.mjs.map +1 -0
  284. package/dist/sandbox/runtime/sessionState.d.ts +26 -0
  285. package/dist/sandbox/runtime/sessionState.js +113 -0
  286. package/dist/sandbox/runtime/sessionState.js.map +1 -0
  287. package/dist/sandbox/runtime/sessionState.mjs +104 -0
  288. package/dist/sandbox/runtime/sessionState.mjs.map +1 -0
  289. package/dist/sandbox/runtime/spans.d.ts +1 -0
  290. package/dist/sandbox/runtime/spans.js +51 -0
  291. package/dist/sandbox/runtime/spans.js.map +1 -0
  292. package/dist/sandbox/runtime/spans.mjs +48 -0
  293. package/dist/sandbox/runtime/spans.mjs.map +1 -0
  294. package/dist/sandbox/runtime/toolRehydration.d.ts +34 -0
  295. package/dist/sandbox/runtime/toolRehydration.js +207 -0
  296. package/dist/sandbox/runtime/toolRehydration.js.map +1 -0
  297. package/dist/sandbox/runtime/toolRehydration.mjs +200 -0
  298. package/dist/sandbox/runtime/toolRehydration.mjs.map +1 -0
  299. package/dist/sandbox/sandboxes/docker.d.ts +75 -0
  300. package/dist/sandbox/sandboxes/docker.js +2015 -0
  301. package/dist/sandbox/sandboxes/docker.js.map +1 -0
  302. package/dist/sandbox/sandboxes/docker.mjs +2010 -0
  303. package/dist/sandbox/sandboxes/docker.mjs.map +1 -0
  304. package/dist/sandbox/sandboxes/index.d.ts +3 -0
  305. package/dist/sandbox/sandboxes/index.js +20 -0
  306. package/dist/sandbox/sandboxes/index.js.map +1 -0
  307. package/dist/sandbox/sandboxes/index.mjs +4 -0
  308. package/dist/sandbox/sandboxes/index.mjs.map +1 -0
  309. package/dist/sandbox/sandboxes/shared/localSnapshotPaths.d.ts +1 -0
  310. package/dist/sandbox/sandboxes/shared/localSnapshotPaths.js +22 -0
  311. package/dist/sandbox/sandboxes/shared/localSnapshotPaths.js.map +1 -0
  312. package/dist/sandbox/sandboxes/shared/localSnapshotPaths.mjs +19 -0
  313. package/dist/sandbox/sandboxes/shared/localSnapshotPaths.mjs.map +1 -0
  314. package/dist/sandbox/sandboxes/shared/localSnapshots.d.ts +34 -0
  315. package/dist/sandbox/sandboxes/shared/localSnapshots.js +525 -0
  316. package/dist/sandbox/sandboxes/shared/localSnapshots.js.map +1 -0
  317. package/dist/sandbox/sandboxes/shared/localSnapshots.mjs +508 -0
  318. package/dist/sandbox/sandboxes/shared/localSnapshots.mjs.map +1 -0
  319. package/dist/sandbox/sandboxes/shared/localWorkspace.d.ts +27 -0
  320. package/dist/sandbox/sandboxes/shared/localWorkspace.js +693 -0
  321. package/dist/sandbox/sandboxes/shared/localWorkspace.js.map +1 -0
  322. package/dist/sandbox/sandboxes/shared/localWorkspace.mjs +684 -0
  323. package/dist/sandbox/sandboxes/shared/localWorkspace.mjs.map +1 -0
  324. package/dist/sandbox/sandboxes/shared/manifestPersistence.d.ts +15 -0
  325. package/dist/sandbox/sandboxes/shared/manifestPersistence.js +191 -0
  326. package/dist/sandbox/sandboxes/shared/manifestPersistence.js.map +1 -0
  327. package/dist/sandbox/sandboxes/shared/manifestPersistence.mjs +182 -0
  328. package/dist/sandbox/sandboxes/shared/manifestPersistence.mjs.map +1 -0
  329. package/dist/sandbox/sandboxes/shared/pty.d.ts +9 -0
  330. package/dist/sandbox/sandboxes/shared/pty.js +151 -0
  331. package/dist/sandbox/sandboxes/shared/pty.js.map +1 -0
  332. package/dist/sandbox/sandboxes/shared/pty.mjs +148 -0
  333. package/dist/sandbox/sandboxes/shared/pty.mjs.map +1 -0
  334. package/dist/sandbox/sandboxes/shared/runProcess.d.ts +16 -0
  335. package/dist/sandbox/sandboxes/shared/runProcess.js +90 -0
  336. package/dist/sandbox/sandboxes/shared/runProcess.js.map +1 -0
  337. package/dist/sandbox/sandboxes/shared/runProcess.mjs +86 -0
  338. package/dist/sandbox/sandboxes/shared/runProcess.mjs.map +1 -0
  339. package/dist/sandbox/sandboxes/shared/sessionStateValues.d.ts +18 -0
  340. package/dist/sandbox/sandboxes/shared/sessionStateValues.js +40 -0
  341. package/dist/sandbox/sandboxes/shared/sessionStateValues.js.map +1 -0
  342. package/dist/sandbox/sandboxes/shared/sessionStateValues.mjs +35 -0
  343. package/dist/sandbox/sandboxes/shared/sessionStateValues.mjs.map +1 -0
  344. package/dist/sandbox/sandboxes/shared/shellCommand.d.ts +17 -0
  345. package/dist/sandbox/sandboxes/shared/shellCommand.js +38 -0
  346. package/dist/sandbox/sandboxes/shared/shellCommand.js.map +1 -0
  347. package/dist/sandbox/sandboxes/shared/shellCommand.mjs +34 -0
  348. package/dist/sandbox/sandboxes/shared/shellCommand.mjs.map +1 -0
  349. package/dist/sandbox/sandboxes/types.d.ts +11 -0
  350. package/dist/sandbox/sandboxes/types.js +3 -0
  351. package/dist/sandbox/sandboxes/types.js.map +1 -0
  352. package/dist/sandbox/sandboxes/types.mjs +2 -0
  353. package/dist/sandbox/sandboxes/types.mjs.map +1 -0
  354. package/dist/sandbox/sandboxes/unixLocal.d.ts +95 -0
  355. package/dist/sandbox/sandboxes/unixLocal.js +863 -0
  356. package/dist/sandbox/sandboxes/unixLocal.js.map +1 -0
  357. package/dist/sandbox/sandboxes/unixLocal.mjs +858 -0
  358. package/dist/sandbox/sandboxes/unixLocal.mjs.map +1 -0
  359. package/dist/sandbox/session.d.ts +123 -0
  360. package/dist/sandbox/session.js +58 -0
  361. package/dist/sandbox/session.js.map +1 -0
  362. package/dist/sandbox/session.mjs +50 -0
  363. package/dist/sandbox/session.mjs.map +1 -0
  364. package/dist/sandbox/shared/compare.d.ts +2 -0
  365. package/dist/sandbox/shared/compare.js +13 -0
  366. package/dist/sandbox/shared/compare.js.map +1 -0
  367. package/dist/sandbox/shared/compare.mjs +9 -0
  368. package/dist/sandbox/shared/compare.mjs.map +1 -0
  369. package/dist/sandbox/shared/environment.d.ts +14 -0
  370. package/dist/sandbox/shared/environment.js +69 -0
  371. package/dist/sandbox/shared/environment.js.map +1 -0
  372. package/dist/sandbox/shared/environment.mjs +59 -0
  373. package/dist/sandbox/shared/environment.mjs.map +1 -0
  374. package/dist/sandbox/shared/hostPath.d.ts +4 -0
  375. package/dist/sandbox/shared/hostPath.js +22 -0
  376. package/dist/sandbox/shared/hostPath.js.map +1 -0
  377. package/dist/sandbox/shared/hostPath.mjs +16 -0
  378. package/dist/sandbox/shared/hostPath.mjs.map +1 -0
  379. package/dist/sandbox/shared/manifestCollections.d.ts +12 -0
  380. package/dist/sandbox/shared/manifestCollections.js +40 -0
  381. package/dist/sandbox/shared/manifestCollections.js.map +1 -0
  382. package/dist/sandbox/shared/manifestCollections.mjs +34 -0
  383. package/dist/sandbox/shared/manifestCollections.mjs.map +1 -0
  384. package/dist/sandbox/shared/media.d.ts +6 -0
  385. package/dist/sandbox/shared/media.js +126 -0
  386. package/dist/sandbox/shared/media.js.map +1 -0
  387. package/dist/sandbox/shared/media.mjs +119 -0
  388. package/dist/sandbox/shared/media.mjs.map +1 -0
  389. package/dist/sandbox/shared/output.d.ts +12 -0
  390. package/dist/sandbox/shared/output.js +108 -0
  391. package/dist/sandbox/shared/output.js.map +1 -0
  392. package/dist/sandbox/shared/output.mjs +103 -0
  393. package/dist/sandbox/shared/output.mjs.map +1 -0
  394. package/dist/sandbox/shared/posixPath.d.ts +7 -0
  395. package/dist/sandbox/shared/posixPath.js +90 -0
  396. package/dist/sandbox/shared/posixPath.js.map +1 -0
  397. package/dist/sandbox/shared/posixPath.mjs +81 -0
  398. package/dist/sandbox/shared/posixPath.mjs.map +1 -0
  399. package/dist/sandbox/shared/remoteMountCommandAllowlist.d.ts +3 -0
  400. package/dist/sandbox/shared/remoteMountCommandAllowlist.js +33 -0
  401. package/dist/sandbox/shared/remoteMountCommandAllowlist.js.map +1 -0
  402. package/dist/sandbox/shared/remoteMountCommandAllowlist.mjs +28 -0
  403. package/dist/sandbox/shared/remoteMountCommandAllowlist.mjs.map +1 -0
  404. package/dist/sandbox/shared/shell.d.ts +1 -0
  405. package/dist/sandbox/shared/shell.js +7 -0
  406. package/dist/sandbox/shared/shell.js.map +1 -0
  407. package/dist/sandbox/shared/shell.mjs +4 -0
  408. package/dist/sandbox/shared/shell.mjs.map +1 -0
  409. package/dist/sandbox/shared/stableJson.d.ts +12 -0
  410. package/dist/sandbox/shared/stableJson.js +40 -0
  411. package/dist/sandbox/shared/stableJson.js.map +1 -0
  412. package/dist/sandbox/shared/stableJson.mjs +35 -0
  413. package/dist/sandbox/shared/stableJson.mjs.map +1 -0
  414. package/dist/sandbox/shared/typeGuards.d.ts +6 -0
  415. package/dist/sandbox/shared/typeGuards.js +34 -0
  416. package/dist/sandbox/shared/typeGuards.js.map +1 -0
  417. package/dist/sandbox/shared/typeGuards.mjs +26 -0
  418. package/dist/sandbox/shared/typeGuards.mjs.map +1 -0
  419. package/dist/sandbox/snapshot.d.ts +60 -0
  420. package/dist/sandbox/snapshot.js +45 -0
  421. package/dist/sandbox/snapshot.js.map +1 -0
  422. package/dist/sandbox/snapshot.mjs +39 -0
  423. package/dist/sandbox/snapshot.mjs.map +1 -0
  424. package/dist/sandbox/users.d.ts +11 -0
  425. package/dist/sandbox/users.js +31 -0
  426. package/dist/sandbox/users.js.map +1 -0
  427. package/dist/sandbox/users.mjs +26 -0
  428. package/dist/sandbox/users.mjs.map +1 -0
  429. package/dist/sandbox/workspacePaths.d.ts +20 -0
  430. package/dist/sandbox/workspacePaths.js +73 -0
  431. package/dist/sandbox/workspacePaths.js.map +1 -0
  432. package/dist/sandbox/workspacePaths.mjs +69 -0
  433. package/dist/sandbox/workspacePaths.mjs.map +1 -0
  434. package/dist/tool.js +1 -1
  435. package/dist/tool.js.map +1 -1
  436. package/dist/tool.mjs +1 -1
  437. package/dist/tool.mjs.map +1 -1
  438. package/dist/types/protocol.d.ts +8 -0
  439. package/dist/types/protocol.js +1 -0
  440. package/dist/types/protocol.js.map +1 -1
  441. package/dist/types/protocol.mjs +1 -0
  442. package/dist/types/protocol.mjs.map +1 -1
  443. package/dist/utils/messages.d.ts +6 -0
  444. package/dist/utils/messages.js +21 -0
  445. package/dist/utils/messages.js.map +1 -1
  446. package/dist/utils/messages.mjs +20 -0
  447. package/dist/utils/messages.mjs.map +1 -1
  448. package/dist/utils/strictToolSchema.d.ts +4 -0
  449. package/dist/utils/strictToolSchema.js +358 -0
  450. package/dist/utils/strictToolSchema.js.map +1 -0
  451. package/dist/utils/strictToolSchema.mjs +353 -0
  452. package/dist/utils/strictToolSchema.mjs.map +1 -0
  453. package/dist/utils/tools.d.ts +3 -1
  454. package/dist/utils/tools.js +18 -7
  455. package/dist/utils/tools.js.map +1 -1
  456. package/dist/utils/tools.mjs +18 -7
  457. package/dist/utils/tools.mjs.map +1 -1
  458. package/dist/utils/zodJsonSchemaCompat.js +18 -16
  459. package/dist/utils/zodJsonSchemaCompat.js.map +1 -1
  460. package/dist/utils/zodJsonSchemaCompat.mjs +18 -16
  461. package/dist/utils/zodJsonSchemaCompat.mjs.map +1 -1
  462. package/package.json +25 -1
@@ -0,0 +1,2015 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DockerSandboxClient = exports.DockerSandboxSession = void 0;
4
+ const errors_1 = require("../../errors.js");
5
+ const applyDiff_1 = require("../../utils/applyDiff.js");
6
+ const errors_2 = require("../errors.js");
7
+ const promises_1 = require("node:fs/promises");
8
+ const node_crypto_1 = require("node:crypto");
9
+ const node_child_process_1 = require("node:child_process");
10
+ const node_path_1 = require("node:path");
11
+ const node_os_1 = require("node:os");
12
+ const entries_1 = require("../entries/index.js");
13
+ const client_1 = require("../client.js");
14
+ const manifest_1 = require("../manifest.js");
15
+ const workspacePaths_1 = require("../workspacePaths.js");
16
+ const session_1 = require("../session.js");
17
+ const unixLocal_1 = require("./unixLocal.js");
18
+ const localWorkspace_1 = require("./shared/localWorkspace.js");
19
+ const manifestPersistence_1 = require("./shared/manifestPersistence.js");
20
+ const media_1 = require("../shared/media.js");
21
+ const localSnapshots_1 = require("./shared/localSnapshots.js");
22
+ const pty_1 = require("./shared/pty.js");
23
+ const runProcess_1 = require("./shared/runProcess.js");
24
+ const shellCommand_1 = require("./shared/shellCommand.js");
25
+ const shell_1 = require("../shared/shell.js");
26
+ const sessionStateValues_1 = require("./shared/sessionStateValues.js");
27
+ const typeGuards_1 = require("../shared/typeGuards.js");
28
+ const DEFAULT_DOCKER_IMAGE = 'python:3.14-slim';
29
+ const DEFAULT_CONTAINER_COMMAND = 'trap "exit 0" TERM INT; while true; do sleep 3600; done';
30
+ const DOCKER_FAST_COMMAND_TIMEOUT_MS = 10_000;
31
+ const DOCKER_CONTAINER_START_TIMEOUT_MS = 2 * 60_000;
32
+ const DOCKER_CONTAINER_REMOVE_TIMEOUT_MS = 30_000;
33
+ class DockerSandboxSession extends unixLocal_1.UnixLocalSandboxSession {
34
+ containerClosed = false;
35
+ async resolveFilesystemRunAs(runAs) {
36
+ if (runAs && runAs.trim().length > 0) {
37
+ throw new errors_1.UserError('DockerSandboxClient does not support runAs for filesystem operations.');
38
+ }
39
+ return undefined;
40
+ }
41
+ createEditor(runAs) {
42
+ if (!runAs) {
43
+ return super.createEditor();
44
+ }
45
+ return new DockerSandboxEditor(this, runAs);
46
+ }
47
+ async viewImage(args) {
48
+ if (!args.runAs) {
49
+ return await super.viewImage(args);
50
+ }
51
+ const bytes = await this.readDockerFileAs(this.resolveContainerFilesystemPath(args.path), args.runAs);
52
+ return (0, media_1.imageOutputFromBytes)(args.path, bytes);
53
+ }
54
+ async pathExists(path, runAs) {
55
+ if (!runAs && !this.pathRequiresDockerFilesystem(path)) {
56
+ return await super.pathExists(path);
57
+ }
58
+ const result = await this.runDockerFilesystemCommand(`test -e ${(0, shell_1.shellQuote)(this.resolveContainerFilesystemPath(path))}`, { runAs });
59
+ return result.status === 0;
60
+ }
61
+ async readFile(args) {
62
+ if (!args.runAs && !this.pathRequiresDockerFilesystem(args.path)) {
63
+ return await super.readFile(args);
64
+ }
65
+ const bytes = await this.readDockerFileAs(this.resolveContainerFilesystemPath(args.path), args.runAs);
66
+ if (typeof args.maxBytes === 'number' && bytes.byteLength > args.maxBytes) {
67
+ return bytes.subarray(0, args.maxBytes);
68
+ }
69
+ return bytes;
70
+ }
71
+ async listDir(args) {
72
+ if (!args.runAs && !this.pathRequiresDockerFilesystem(args.path)) {
73
+ return await super.listDir(args);
74
+ }
75
+ const absolutePath = this.resolveContainerFilesystemPath(args.path);
76
+ const output = await this.runCheckedDockerFilesystemCommand([
77
+ `find ${(0, shell_1.shellQuote)(absolutePath)} -mindepth 1 -maxdepth 1 -printf '%y\\t%f\\n'`,
78
+ ].join(' && '), { runAs: args.runAs }, `list directory ${absolutePath}`);
79
+ const logicalPath = this.resolveLogicalPath(args.path);
80
+ return output
81
+ .split(/\r?\n/u)
82
+ .filter((line) => line.trim().length > 0)
83
+ .map((line) => {
84
+ const separator = line.indexOf('\t');
85
+ const kind = separator >= 0 ? line.slice(0, separator) : '';
86
+ const name = separator >= 0 ? line.slice(separator + 1) : line;
87
+ return {
88
+ name,
89
+ path: logicalPath ? `${logicalPath}/${name}` : name,
90
+ type: kind === 'd' ? 'dir' : kind === 'f' ? 'file' : 'other',
91
+ };
92
+ });
93
+ }
94
+ pathRequiresDockerFilesystem(path) {
95
+ return Boolean(dockerInContainerMountContainingPath(this.state.manifest, path));
96
+ }
97
+ async materializeEntry(args) {
98
+ if ((0, entries_1.isMount)(args.entry) && isDockerInContainerMount(args.entry)) {
99
+ const logicalPath = this.resolveLogicalPath(args.path);
100
+ assertDockerCanApplyInContainerMounts(this.state.manifest, new manifest_1.Manifest({
101
+ entries: {
102
+ [logicalPath]: args.entry,
103
+ },
104
+ }));
105
+ (0, localWorkspace_1.assertLocalWorkspaceManifestMetadataSupported)('DockerSandboxClient', new manifest_1.Manifest({
106
+ entries: {
107
+ [logicalPath]: args.entry,
108
+ },
109
+ }), {
110
+ allowLocalBindMounts: false,
111
+ allowIdentityMetadata: true,
112
+ supportsMount: isSupportedDockerApplyMount,
113
+ });
114
+ await materializeDockerMountPoint(this.state.workspaceRootPath, this.state.manifest.root, logicalPath, args.entry);
115
+ if (args.runAs) {
116
+ const mountPath = resolveDockerMountPath(this.state.manifest.root, logicalPath, args.entry);
117
+ await this.mkdirDockerPathAs(mountPath, 'root');
118
+ await this.chownContainerPath(mountPath, args.runAs);
119
+ }
120
+ await applyDockerInContainerMount(this, logicalPath, args.entry);
121
+ this.state.manifest = (0, manifestPersistence_1.mergeManifestEntryDelta)(this.state.manifest, logicalPath, args.entry);
122
+ return;
123
+ }
124
+ if (!args.runAs) {
125
+ await super.materializeEntry(args);
126
+ return;
127
+ }
128
+ const logicalPath = this.resolveLogicalPath(args.path);
129
+ (0, localWorkspace_1.assertLocalWorkspaceManifestMetadataSupported)('DockerSandboxClient', new manifest_1.Manifest({
130
+ entries: {
131
+ [logicalPath]: args.entry,
132
+ },
133
+ }), {
134
+ allowLocalBindMounts: false,
135
+ allowIdentityMetadata: true,
136
+ supportsMount: isSupportedDockerApplyMount,
137
+ });
138
+ await (0, localWorkspace_1.materializeLocalWorkspaceManifestEntry)(this.state.workspaceRootPath, logicalPath, args.entry);
139
+ await this.chownContainerPath(this.resolveContainerFilesystemPath(args.path), args.runAs);
140
+ this.state.manifest = (0, manifestPersistence_1.mergeManifestEntryDelta)(this.state.manifest, logicalPath, args.entry);
141
+ }
142
+ async applyManifest(manifest, runAs) {
143
+ assertDockerManifestDeltaSupported(manifest);
144
+ assertDockerCanApplyInContainerMounts(this.state.manifest, manifest);
145
+ const environment = await manifest.resolveEnvironment();
146
+ const previousEnvironment = this.state.environment;
147
+ const nextEnvironment = {
148
+ ...this.state.environment,
149
+ ...environment,
150
+ };
151
+ this.state.environment = nextEnvironment;
152
+ try {
153
+ await provisionDockerAccounts(this.state.containerId, manifest);
154
+ const materializedManifest = stripDockerIdentityMetadata(manifest);
155
+ await (0, localWorkspace_1.materializeLocalWorkspaceManifest)(materializedManifest, this.state.workspaceRootPath, {
156
+ allowLocalBindMounts: false,
157
+ allowIdentityMetadata: true,
158
+ supportsMount: isSupportedDockerApplyMount,
159
+ materializeMount: async ({ logicalPath, entry }) => {
160
+ await materializeDockerMountPoint(this.state.workspaceRootPath, this.state.manifest.root, logicalPath, entry);
161
+ },
162
+ });
163
+ if (runAs) {
164
+ for (const [path, entry] of Object.entries(manifest.entries)) {
165
+ if ((0, entries_1.isMount)(entry)) {
166
+ const mountPath = resolveDockerMountPath(this.state.manifest.root, path, entry);
167
+ await this.mkdirDockerPathAs(mountPath, 'root');
168
+ await this.chownContainerPath(mountPath, runAs);
169
+ }
170
+ else {
171
+ await this.chownContainerPath(this.resolveContainerFilesystemPath(path), runAs);
172
+ }
173
+ }
174
+ }
175
+ await applyDockerInContainerMounts(this, manifest);
176
+ this.state.manifest = mergeDockerIdentityMetadata((0, manifestPersistence_1.mergeManifestDelta)(this.state.manifest, materializedManifest), manifest);
177
+ }
178
+ catch (error) {
179
+ this.state.environment = previousEnvironment;
180
+ throw error;
181
+ }
182
+ }
183
+ async resolveExposedPort(port) {
184
+ const containerPort = (0, session_1.normalizeExposedPort)(port);
185
+ const configuredPorts = this.state.configuredExposedPorts ?? [];
186
+ if (configuredPorts.length > 0 &&
187
+ !configuredPorts.includes(containerPort)) {
188
+ throw new errors_2.SandboxConfigurationError(`DockerSandboxClient was not configured to expose port ${containerPort}.`, {
189
+ provider: 'DockerSandboxClient',
190
+ port: containerPort,
191
+ configuredPorts,
192
+ });
193
+ }
194
+ const recorded = (0, session_1.getRecordedExposedPortEndpoint)(this.state, containerPort);
195
+ if (recorded) {
196
+ return recorded;
197
+ }
198
+ const result = await (0, runProcess_1.runSandboxProcess)('docker', ['port', this.state.containerId, `${containerPort}/tcp`], {
199
+ timeoutMs: DOCKER_FAST_COMMAND_TIMEOUT_MS,
200
+ });
201
+ if (result.status !== 0) {
202
+ throw new errors_1.UserError(`Failed to resolve Docker exposed port ${containerPort}: ${(0, runProcess_1.formatSandboxProcessError)(result)}`);
203
+ }
204
+ return (0, session_1.recordExposedPortEndpoint)(this.state, {
205
+ ...parseDockerPortBinding(result.stdout, containerPort),
206
+ tls: false,
207
+ }, containerPort);
208
+ }
209
+ resolveCommandWorkdir(path) {
210
+ const logicalPath = this.resolveLogicalPath(path);
211
+ return (0, localWorkspace_1.joinSandboxLogicalPath)(this.state.manifest.root, logicalPath);
212
+ }
213
+ async spawnShellCommand(command, args) {
214
+ const { shellPath, flag } = (0, shellCommand_1.resolveFallbackShellCommand)({
215
+ shell: args.shell,
216
+ defaultShell: this.defaultShell,
217
+ login: args.login,
218
+ });
219
+ const dockerArgs = ['exec', '-i', '-w', args.cwd];
220
+ if (args.tty) {
221
+ dockerArgs.splice(2, 0, '-t');
222
+ }
223
+ for (const [key, value] of Object.entries(this.state.environment)) {
224
+ dockerArgs.push('-e', `${key}=${value}`);
225
+ }
226
+ const runAs = args.runAs ?? this.state.defaultUser;
227
+ if (runAs) {
228
+ dockerArgs.push('-u', runAs);
229
+ }
230
+ dockerArgs.push(this.state.containerId, shellPath, flag, command);
231
+ if (args.tty) {
232
+ return (0, pty_1.spawnInPseudoTerminal)('docker', dockerArgs);
233
+ }
234
+ return (0, node_child_process_1.spawn)('docker', dockerArgs, {
235
+ stdio: 'pipe',
236
+ });
237
+ }
238
+ translateCommandInput(command) {
239
+ return command;
240
+ }
241
+ translateCommandOutput(output) {
242
+ return output;
243
+ }
244
+ async materializeRestoredWorkspaceMounts() {
245
+ await prepareDockerWorkspaceRoot(this.state.workspaceRootPath, this.state.manifest);
246
+ await (0, localWorkspace_1.materializeLocalWorkspaceManifestMounts)(this.state.manifest, this.state.workspaceRootPath, {
247
+ allowLocalBindMounts: false,
248
+ allowIdentityMetadata: true,
249
+ supportsMount: isSupportedDockerCreateMount,
250
+ materializeMount: async ({ logicalPath, entry }) => {
251
+ await materializeDockerMountPoint(this.state.workspaceRootPath, this.state.manifest.root, logicalPath, entry);
252
+ },
253
+ });
254
+ await applyDockerInContainerMounts(this, this.state.manifest);
255
+ }
256
+ resolveSandboxPath(path, options = {}) {
257
+ const mountPath = dockerVolumeMountContainingPath(this.state.manifest, path);
258
+ if (mountPath) {
259
+ throw new errors_1.UserError(`DockerSandboxClient filesystem operations cannot access Docker volume mount path "${path ?? mountPath}". Use execCommand for container-visible paths under "${mountPath}".`);
260
+ }
261
+ const inContainerMountPath = dockerInContainerMountContainingPath(this.state.manifest, path);
262
+ if (inContainerMountPath) {
263
+ throw new errors_1.UserError(`DockerSandboxClient host filesystem operations cannot access in-container mount path "${path ?? inContainerMountPath}". Use execCommand for container-visible paths under "${inContainerMountPath}".`);
264
+ }
265
+ return super.resolveSandboxPath(path, options);
266
+ }
267
+ resolveContainerFilesystemPath(path, options = {}) {
268
+ const resolved = new workspacePaths_1.WorkspacePathPolicy({
269
+ root: this.state.manifest.root,
270
+ extraPathGrants: this.state.manifest.extraPathGrants,
271
+ }).resolve(path, options);
272
+ return resolved.path;
273
+ }
274
+ async readDockerFileAs(path, runAs) {
275
+ const output = await this.runCheckedDockerFilesystemCommand(`base64 -- ${(0, shell_1.shellQuote)(path)}`, { runAs }, `read file ${path}`);
276
+ return Buffer.from(output.replace(/\s+/gu, ''), 'base64');
277
+ }
278
+ async writeDockerTextFileAs(path, content, runAs) {
279
+ const parent = dockerPosixDirname(path);
280
+ await this.runCheckedDockerFilesystemCommand(parent === '/' || parent === '.'
281
+ ? `cat > ${(0, shell_1.shellQuote)(path)}`
282
+ : `mkdir -p -- ${(0, shell_1.shellQuote)(parent)} && cat > ${(0, shell_1.shellQuote)(path)}`, { runAs, input: content }, `write file ${path}`);
283
+ }
284
+ async deleteDockerPathAs(path, runAs) {
285
+ await this.runCheckedDockerFilesystemCommand(`rm -f -- ${(0, shell_1.shellQuote)(path)}`, { runAs }, `delete path ${path}`);
286
+ }
287
+ async mkdirDockerPathAs(path, runAs) {
288
+ await this.runCheckedDockerFilesystemCommand(`mkdir -p -- ${(0, shell_1.shellQuote)(path)}`, { runAs }, `create directory ${path}`);
289
+ }
290
+ async runDockerMountCommand(command, action, options = {}) {
291
+ return await this.runCheckedDockerFilesystemCommand(command, { runAs: 'root', input: options.input }, action);
292
+ }
293
+ async chownContainerPath(path, runAs) {
294
+ await this.runCheckedDockerFilesystemCommand(`chown -R ${(0, shell_1.shellQuote)(runAs)}:${(0, shell_1.shellQuote)(runAs)} -- ${(0, shell_1.shellQuote)(path)}`, { runAs: 'root' }, `set ownership on ${path}`);
295
+ }
296
+ async runCheckedDockerFilesystemCommand(command, options = {}, action) {
297
+ const result = await this.runDockerFilesystemCommand(command, options);
298
+ if (result.status !== 0) {
299
+ throw new errors_1.UserError(`DockerSandboxClient failed to ${action}: ${(0, runProcess_1.formatSandboxProcessError)(result)}`);
300
+ }
301
+ return result.stdout;
302
+ }
303
+ async runDockerFilesystemCommand(command, options = {}) {
304
+ const dockerArgs = ['exec', '-i', '-w', '/'];
305
+ for (const [key, value] of Object.entries(this.state.environment)) {
306
+ dockerArgs.push('-e', `${key}=${value}`);
307
+ }
308
+ const runAs = options.runAs ?? this.state.defaultUser;
309
+ if (runAs) {
310
+ dockerArgs.push('-u', runAs);
311
+ }
312
+ dockerArgs.push(this.state.containerId, '/bin/sh', '-lc', command);
313
+ return await runDockerProcess(dockerArgs, options.input);
314
+ }
315
+ async close() {
316
+ let cleanupError;
317
+ if (!this.containerClosed) {
318
+ try {
319
+ await removeDockerContainer(this.state.containerId, {
320
+ ignoreMissing: true,
321
+ });
322
+ this.containerClosed = true;
323
+ }
324
+ catch (error) {
325
+ cleanupError = error;
326
+ }
327
+ }
328
+ try {
329
+ await removeDockerVolumes(this.state.dockerVolumeNames ?? []);
330
+ }
331
+ catch (error) {
332
+ cleanupError ??= error;
333
+ }
334
+ try {
335
+ await super.close();
336
+ }
337
+ catch (error) {
338
+ cleanupError ??= error;
339
+ }
340
+ if (cleanupError) {
341
+ throw cleanupError;
342
+ }
343
+ }
344
+ }
345
+ exports.DockerSandboxSession = DockerSandboxSession;
346
+ class DockerSandboxEditor {
347
+ session;
348
+ runAs;
349
+ constructor(session, runAs) {
350
+ this.session = session;
351
+ this.runAs = runAs;
352
+ }
353
+ async createFile(operation) {
354
+ const path = this.session.resolveContainerFilesystemPath(operation.path, {
355
+ forWrite: true,
356
+ });
357
+ if (await this.session.pathExists(operation.path, this.runAs)) {
358
+ throw new errors_1.UserError(`Cannot create file because it already exists: ${path}`);
359
+ }
360
+ const content = (0, applyDiff_1.applyDiff)('', operation.diff, 'create');
361
+ const parent = dockerPosixDirname(path);
362
+ if (parent !== '.' && parent !== '/') {
363
+ await this.session.mkdirDockerPathAs(parent, this.runAs);
364
+ }
365
+ await this.session.writeDockerTextFileAs(path, content, this.runAs);
366
+ return {};
367
+ }
368
+ async updateFile(operation) {
369
+ const path = this.session.resolveContainerFilesystemPath(operation.path, {
370
+ forWrite: true,
371
+ });
372
+ const destination = operation.moveTo
373
+ ? this.session.resolveContainerFilesystemPath(operation.moveTo, {
374
+ forWrite: true,
375
+ })
376
+ : path;
377
+ const current = new TextDecoder().decode(await this.session.readDockerFileAs(path, this.runAs));
378
+ const next = (0, applyDiff_1.applyDiff)(current, operation.diff);
379
+ const parent = dockerPosixDirname(destination);
380
+ if (parent !== '.' && parent !== '/') {
381
+ await this.session.mkdirDockerPathAs(parent, this.runAs);
382
+ }
383
+ await this.session.writeDockerTextFileAs(destination, next, this.runAs);
384
+ if (operation.moveTo && destination !== path) {
385
+ await this.session.deleteDockerPathAs(path, this.runAs);
386
+ }
387
+ return {};
388
+ }
389
+ async deleteFile(operation) {
390
+ await this.session.deleteDockerPathAs(this.session.resolveContainerFilesystemPath(operation.path, {
391
+ forWrite: true,
392
+ }), this.runAs);
393
+ return {};
394
+ }
395
+ }
396
+ class DockerSandboxClient {
397
+ backendId = 'docker';
398
+ supportsDefaultOptions = true;
399
+ options;
400
+ constructor(options = {}) {
401
+ this.options = options;
402
+ }
403
+ async create(args, manifestOptions) {
404
+ const createArgs = (0, client_1.normalizeSandboxClientCreateArgs)(args, manifestOptions);
405
+ const manifest = createArgs.manifest;
406
+ assertDockerManifestSupported(manifest);
407
+ await ensureDockerAvailable();
408
+ const resolvedOptions = {
409
+ ...this.options,
410
+ ...createArgs.options,
411
+ ...(createArgs.snapshot
412
+ ? { snapshot: createArgs.snapshot }
413
+ : {}),
414
+ ...(createArgs.concurrencyLimits
415
+ ? { concurrencyLimits: createArgs.concurrencyLimits }
416
+ : {}),
417
+ };
418
+ const workspaceRootPath = await (0, promises_1.mkdtemp)((0, node_path_1.join)(resolvedOptions.workspaceBaseDir ?? (0, node_os_1.tmpdir)(), 'openai-agents-docker-sandbox-'));
419
+ await (0, localWorkspace_1.materializeLocalWorkspaceManifest)(manifest, workspaceRootPath, {
420
+ concurrencyLimits: resolvedOptions.concurrencyLimits,
421
+ allowLocalBindMounts: false,
422
+ allowIdentityMetadata: true,
423
+ supportsMount: isSupportedDockerCreateMount,
424
+ materializeMount: async ({ logicalPath, entry }) => {
425
+ await materializeDockerMountPoint(workspaceRootPath, manifest.root, logicalPath, entry);
426
+ },
427
+ });
428
+ await prepareDockerWorkspaceRoot(workspaceRootPath, manifest);
429
+ const image = resolvedOptions.image ?? DEFAULT_DOCKER_IMAGE;
430
+ const environment = await manifest.resolveEnvironment();
431
+ const defaultUser = getHostDockerUser();
432
+ const configuredExposedPorts = (0, sessionStateValues_1.normalizeExposedPorts)(resolvedOptions.exposedPorts);
433
+ const container = await startDockerContainer({
434
+ image,
435
+ manifest,
436
+ manifestRoot: manifest.root,
437
+ workspaceRootPath,
438
+ environment,
439
+ defaultUser,
440
+ exposedPorts: configuredExposedPorts,
441
+ });
442
+ const session = new DockerSandboxSession({
443
+ state: {
444
+ manifest,
445
+ workspaceRootPath,
446
+ workspaceRootOwned: true,
447
+ environment,
448
+ snapshotSpec: resolvedOptions.snapshot ?? null,
449
+ snapshot: null,
450
+ image,
451
+ containerId: container.containerId,
452
+ defaultUser,
453
+ configuredExposedPorts,
454
+ dockerVolumeNames: container.volumeNames,
455
+ },
456
+ });
457
+ try {
458
+ await provisionDockerAccounts(container.containerId, manifest);
459
+ await applyDockerInContainerMounts(session, manifest);
460
+ }
461
+ catch (error) {
462
+ await cleanupStartedDockerContainer({
463
+ containerId: container.containerId,
464
+ volumeNames: container.volumeNames,
465
+ workspaceRootPath,
466
+ removeWorkspace: true,
467
+ });
468
+ throw error;
469
+ }
470
+ return session;
471
+ }
472
+ async resume(state) {
473
+ assertDockerManifestSupported(state.manifest);
474
+ await ensureDockerAvailable();
475
+ const restoredState = await this.restoreIfNeeded(state);
476
+ return new DockerSandboxSession({
477
+ state: restoredState,
478
+ });
479
+ }
480
+ async serializeSessionState(state) {
481
+ const snapshotSpec = state.snapshotSpec ?? this.options.snapshot ?? null;
482
+ attachDockerSnapshotExcludedPaths(state);
483
+ const snapshot = await (0, localSnapshots_1.persistLocalSnapshot)('DockerSandboxClient', state, snapshotSpec);
484
+ state.snapshotSpec = snapshotSpec;
485
+ return {
486
+ manifest: (0, manifestPersistence_1.serializeManifest)(state.manifest),
487
+ workspaceRootPath: state.workspaceRootPath,
488
+ workspaceRootOwned: state.workspaceRootOwned,
489
+ environment: (0, manifestPersistence_1.sanitizeEnvironmentForPersistence)(state),
490
+ snapshotSpec: (0, localSnapshots_1.serializeLocalSnapshotSpec)(snapshotSpec),
491
+ snapshot,
492
+ snapshotFingerprint: state.snapshotFingerprint ?? null,
493
+ snapshotFingerprintVersion: state.snapshotFingerprintVersion ?? null,
494
+ image: state.image,
495
+ containerId: state.containerId,
496
+ defaultUser: state.defaultUser,
497
+ configuredExposedPorts: state.configuredExposedPorts ?? [],
498
+ dockerVolumeNames: state.dockerVolumeNames ?? [],
499
+ exposedPorts: state.exposedPorts ?? null,
500
+ };
501
+ }
502
+ async deserializeSessionState(state) {
503
+ const baseState = (0, sessionStateValues_1.deserializeLocalSandboxSessionStateValues)(state, this.options.snapshot);
504
+ return {
505
+ ...baseState,
506
+ image: (0, typeGuards_1.readString)(state, 'image'),
507
+ containerId: (0, typeGuards_1.readString)(state, 'containerId'),
508
+ defaultUser: (0, typeGuards_1.readOptionalString)(state, 'defaultUser') ?? getHostDockerUser(),
509
+ dockerVolumeNames: (0, typeGuards_1.readStringArray)(state.dockerVolumeNames),
510
+ };
511
+ }
512
+ async restoreIfNeeded(state) {
513
+ attachDockerSnapshotExcludedPaths(state);
514
+ const containerRunning = await inspectContainerRunning(state.containerId);
515
+ const workspaceExists = await (0, localWorkspace_1.pathExists)(state.workspaceRootPath);
516
+ if (workspaceExists) {
517
+ if (containerRunning) {
518
+ return state;
519
+ }
520
+ if (await (0, localSnapshots_1.canReuseLocalSnapshotWorkspace)(state)) {
521
+ await this.cleanupDockerResources(state);
522
+ return await this.restartContainer(state, state.workspaceRootPath);
523
+ }
524
+ if (await (0, localSnapshots_1.localSnapshotIsRestorable)(state)) {
525
+ const restoredState = await (0, localSnapshots_1.restoreLocalSnapshotToWorkspace)(state, state.workspaceRootPath);
526
+ await this.cleanupDockerResources(state);
527
+ return await this.restartContainer(restoredState, restoredState.workspaceRootPath);
528
+ }
529
+ }
530
+ if (!(await (0, localSnapshots_1.localSnapshotIsRestorable)(state))) {
531
+ throw new errors_1.UserError('Docker sandbox resources are unavailable and no local snapshot could be restored.');
532
+ }
533
+ await this.cleanupDockerResources(state);
534
+ const workspaceRootPath = await (0, promises_1.mkdtemp)((0, node_path_1.join)(this.options.workspaceBaseDir ?? (0, node_os_1.tmpdir)(), 'openai-agents-docker-sandbox-'));
535
+ const restoredState = await (0, localSnapshots_1.restoreLocalSnapshotToWorkspace)({
536
+ ...state,
537
+ workspaceRootPath,
538
+ workspaceRootOwned: true,
539
+ }, workspaceRootPath);
540
+ return await this.restartContainer(restoredState, workspaceRootPath);
541
+ }
542
+ async cleanupDockerResources(state) {
543
+ await removeDockerContainer(state.containerId, { ignoreMissing: true });
544
+ await removeDockerVolumes(state.dockerVolumeNames ?? []);
545
+ }
546
+ async restartContainer(state, workspaceRootPath) {
547
+ await (0, localWorkspace_1.materializeLocalWorkspaceManifestMounts)(state.manifest, workspaceRootPath, {
548
+ allowLocalBindMounts: false,
549
+ allowIdentityMetadata: true,
550
+ supportsMount: isSupportedDockerCreateMount,
551
+ materializeMount: async ({ logicalPath, entry }) => {
552
+ await materializeDockerMountPoint(workspaceRootPath, state.manifest.root, logicalPath, entry);
553
+ },
554
+ });
555
+ await prepareDockerWorkspaceRoot(workspaceRootPath, state.manifest);
556
+ const container = await startDockerContainer({
557
+ image: state.image,
558
+ manifest: state.manifest,
559
+ manifestRoot: state.manifest.root,
560
+ workspaceRootPath,
561
+ environment: state.environment,
562
+ defaultUser: state.defaultUser,
563
+ exposedPorts: state.configuredExposedPorts,
564
+ });
565
+ const nextState = {
566
+ ...state,
567
+ workspaceRootPath,
568
+ containerId: container.containerId,
569
+ dockerVolumeNames: container.volumeNames,
570
+ exposedPorts: undefined,
571
+ };
572
+ const session = new DockerSandboxSession({ state: nextState });
573
+ try {
574
+ await provisionDockerAccounts(container.containerId, state.manifest);
575
+ await applyDockerInContainerMounts(session, state.manifest);
576
+ }
577
+ catch (error) {
578
+ await cleanupStartedDockerContainer({
579
+ containerId: container.containerId,
580
+ volumeNames: container.volumeNames,
581
+ workspaceRootPath,
582
+ removeWorkspace: false,
583
+ });
584
+ throw error;
585
+ }
586
+ return nextState;
587
+ }
588
+ }
589
+ exports.DockerSandboxClient = DockerSandboxClient;
590
+ async function cleanupStartedDockerContainer(args) {
591
+ await removeDockerContainer(args.containerId, { ignoreMissing: true }).catch(() => undefined);
592
+ await removeDockerVolumes(args.volumeNames);
593
+ if (args.removeWorkspace) {
594
+ await (0, promises_1.rm)(args.workspaceRootPath, { recursive: true, force: true }).catch(() => undefined);
595
+ }
596
+ }
597
+ function assertDockerManifestSupported(manifest) {
598
+ assertDockerManifestRootSupported(manifest);
599
+ (0, localWorkspace_1.assertLocalWorkspaceManifestMetadataSupported)('DockerSandboxClient', manifest, {
600
+ allowLocalBindMounts: false,
601
+ allowIdentityMetadata: true,
602
+ supportsMount: isSupportedDockerCreateMount,
603
+ });
604
+ }
605
+ function assertDockerManifestDeltaSupported(manifest) {
606
+ (0, localWorkspace_1.assertLocalWorkspaceManifestMetadataSupported)('DockerSandboxClient', manifest, {
607
+ allowLocalBindMounts: false,
608
+ allowIdentityMetadata: true,
609
+ supportsMount: isSupportedDockerApplyMount,
610
+ });
611
+ }
612
+ function assertDockerManifestRootSupported(manifest) {
613
+ // Docker maps the host workspace as a bind mount at manifest.root; mounting it
614
+ // over "/" would hide the image filesystem rather than emulate root confinement.
615
+ if (manifest.root === '/') {
616
+ throw new errors_1.UserError('DockerSandboxClient does not support manifest root "/".');
617
+ }
618
+ }
619
+ async function prepareDockerWorkspaceRoot(workspaceRootPath, manifest) {
620
+ if (manifest.users.length === 0 && manifest.groups.length === 0) {
621
+ return;
622
+ }
623
+ await (0, promises_1.chmod)(workspaceRootPath, 0o755);
624
+ }
625
+ async function provisionDockerAccounts(containerId, manifest) {
626
+ for (const command of dockerAccountProvisionCommands(manifest)) {
627
+ const result = await (0, runProcess_1.runSandboxProcess)('docker', ['exec', '-u', 'root', containerId, '/bin/sh', '-c', command], {
628
+ timeoutMs: DOCKER_FAST_COMMAND_TIMEOUT_MS,
629
+ });
630
+ if (result.status !== 0) {
631
+ throw new errors_1.UserError(`Failed to provision Docker sandbox manifest accounts: ${(0, runProcess_1.formatSandboxProcessError)(result)}`);
632
+ }
633
+ }
634
+ }
635
+ function dockerAccountProvisionCommands(manifest) {
636
+ const commands = [];
637
+ const users = new Set(manifest.users.map((user) => user.name));
638
+ for (const group of manifest.groups) {
639
+ commands.push(`getent group ${(0, shell_1.shellQuote)(group.name)} >/dev/null 2>&1 || groupadd ${(0, shell_1.shellQuote)(group.name)}`);
640
+ for (const user of group.users ?? []) {
641
+ users.add(user.name);
642
+ }
643
+ }
644
+ for (const user of users) {
645
+ const quotedUser = (0, shell_1.shellQuote)(user);
646
+ commands.push([
647
+ `if id -u ${quotedUser} >/dev/null 2>&1; then exit 0; fi`,
648
+ `if getent group ${quotedUser} >/dev/null 2>&1; then useradd -M -s /usr/sbin/nologin -g ${quotedUser} ${quotedUser}; else useradd -U -M -s /usr/sbin/nologin ${quotedUser}; fi`,
649
+ ].join('; '));
650
+ }
651
+ for (const group of manifest.groups) {
652
+ for (const user of group.users ?? []) {
653
+ commands.push(`usermod -aG ${(0, shell_1.shellQuote)(group.name)} ${(0, shell_1.shellQuote)(user.name)}`);
654
+ }
655
+ }
656
+ return commands;
657
+ }
658
+ function stripDockerIdentityMetadata(manifest) {
659
+ return new manifest_1.Manifest({
660
+ version: manifest.version,
661
+ root: manifest.root,
662
+ entries: manifest.entries,
663
+ environment: Object.fromEntries(Object.entries(manifest.environment).map(([key, value]) => [
664
+ key,
665
+ value.init(),
666
+ ])),
667
+ extraPathGrants: manifest.extraPathGrants,
668
+ remoteMountCommandAllowlist: manifest.remoteMountCommandAllowlist,
669
+ });
670
+ }
671
+ function mergeDockerIdentityMetadata(current, delta) {
672
+ return (0, manifestPersistence_1.mergeManifestDelta)(current, new manifest_1.Manifest({
673
+ users: delta.users,
674
+ groups: delta.groups,
675
+ }));
676
+ }
677
+ async function ensureDockerAvailable() {
678
+ const result = await (0, runProcess_1.runSandboxProcess)('docker', ['version'], {
679
+ timeoutMs: DOCKER_FAST_COMMAND_TIMEOUT_MS,
680
+ });
681
+ if (result.status !== 0) {
682
+ throw new errors_1.UserError('Docker sandbox execution requires a working Docker CLI and daemon.');
683
+ }
684
+ }
685
+ async function inspectContainerRunning(containerId) {
686
+ const result = await (0, runProcess_1.runSandboxProcess)('docker', [
687
+ 'inspect',
688
+ '--type',
689
+ 'container',
690
+ '--format',
691
+ '{{.State.Running}}',
692
+ containerId,
693
+ ], {
694
+ timeoutMs: DOCKER_FAST_COMMAND_TIMEOUT_MS,
695
+ });
696
+ return result.status === 0 && result.stdout.trim() === 'true';
697
+ }
698
+ async function runDockerProcess(args, input) {
699
+ const child = (0, node_child_process_1.spawn)('docker', args, {
700
+ stdio: 'pipe',
701
+ });
702
+ const stdoutChunks = [];
703
+ const stderrChunks = [];
704
+ child.stdout.on('data', (chunk) => {
705
+ stdoutChunks.push(chunk);
706
+ });
707
+ child.stderr.on('data', (chunk) => {
708
+ stderrChunks.push(chunk);
709
+ });
710
+ const closed = new Promise((resolve) => {
711
+ child.on('close', (code) => {
712
+ resolve(code ?? 1);
713
+ });
714
+ child.on('error', (error) => {
715
+ stderrChunks.push(Buffer.from(error.message));
716
+ resolve(1);
717
+ });
718
+ });
719
+ if (input !== undefined) {
720
+ child.stdin.write(input);
721
+ }
722
+ child.stdin.end();
723
+ return {
724
+ status: await closed,
725
+ signal: null,
726
+ timedOut: false,
727
+ stdout: Buffer.concat(stdoutChunks).toString('utf8'),
728
+ stderr: Buffer.concat(stderrChunks).toString('utf8'),
729
+ };
730
+ }
731
+ async function removeDockerContainer(containerId, options = {}) {
732
+ const result = await (0, runProcess_1.runSandboxProcess)('docker', ['rm', '-f', containerId], {
733
+ timeoutMs: DOCKER_CONTAINER_REMOVE_TIMEOUT_MS,
734
+ });
735
+ if (result.status !== 0) {
736
+ if (options.ignoreMissing && isMissingDockerContainerError(result)) {
737
+ return;
738
+ }
739
+ throw new errors_1.UserError(`Failed to remove Docker sandbox container: ${(0, runProcess_1.formatSandboxProcessError)(result)}`);
740
+ }
741
+ }
742
+ function isMissingDockerContainerError(result) {
743
+ const message = (0, runProcess_1.formatSandboxProcessError)(result).toLowerCase();
744
+ return (message.includes('no such container') || message.includes('no such object'));
745
+ }
746
+ async function startDockerContainer(args) {
747
+ const envArgs = Object.entries(args.environment).flatMap(([key, value]) => [
748
+ '-e',
749
+ `${key}=${value}`,
750
+ ]);
751
+ const userArgs = args.defaultUser ? ['--user', args.defaultUser] : [];
752
+ const portArgs = (0, sessionStateValues_1.normalizeExposedPorts)(args.exposedPorts).flatMap((port) => [
753
+ '-p',
754
+ `127.0.0.1::${port}`,
755
+ ]);
756
+ const containerName = `openai-agents-sandbox-${(0, node_crypto_1.randomUUID)().slice(0, 8)}`;
757
+ const { mountArgs, volumeNames } = dockerMountArgsForManifest(args.manifest, containerName);
758
+ const privilegeArgs = dockerInContainerMountPrivilegeArgs(args.manifest);
759
+ const result = await (0, runProcess_1.runSandboxProcess)('docker', [
760
+ 'run',
761
+ '-d',
762
+ '--name',
763
+ containerName,
764
+ '--label',
765
+ 'openai-agents-sandbox=true',
766
+ '-v',
767
+ `${args.workspaceRootPath}:${args.manifestRoot}`,
768
+ ...dockerExtraPathGrantMountArgs(args.manifest),
769
+ ...mountArgs,
770
+ ...privilegeArgs,
771
+ '-w',
772
+ args.manifestRoot,
773
+ ...portArgs,
774
+ ...userArgs,
775
+ ...envArgs,
776
+ args.image,
777
+ '/bin/sh',
778
+ '-c',
779
+ DEFAULT_CONTAINER_COMMAND,
780
+ ], {
781
+ timeoutMs: DOCKER_CONTAINER_START_TIMEOUT_MS,
782
+ });
783
+ if (result.status !== 0) {
784
+ throw new errors_1.UserError(`Failed to start Docker sandbox container: ${(0, runProcess_1.formatSandboxProcessError)(result)}`);
785
+ }
786
+ return {
787
+ containerId: result.stdout.trim(),
788
+ volumeNames,
789
+ };
790
+ }
791
+ async function materializeDockerMountPoint(workspaceRootPath, manifestRoot, logicalPath, entry) {
792
+ const relativePath = resolveDockerMountWorkspaceRelativePath(manifestRoot, logicalPath, entry);
793
+ if (!relativePath) {
794
+ return;
795
+ }
796
+ await (0, promises_1.mkdir)((0, node_path_1.resolve)(workspaceRootPath, relativePath), { recursive: true });
797
+ }
798
+ function isSupportedDockerCreateMount(entry) {
799
+ return (isDockerBindMount(entry) ||
800
+ isDockerVolumeMount(entry) ||
801
+ isSupportedDockerInContainerMount(entry));
802
+ }
803
+ function isSupportedDockerApplyMount(entry) {
804
+ return isSupportedDockerInContainerMount(entry);
805
+ }
806
+ function isDockerBindMount(entry) {
807
+ return (entry.type === 'mount' &&
808
+ typeof entry.source === 'string' &&
809
+ (0, node_path_1.isAbsolute)(entry.source) &&
810
+ (entry.mountStrategy === undefined ||
811
+ entry.mountStrategy.type === 'local_bind'));
812
+ }
813
+ function isDockerVolumeMount(entry) {
814
+ return Boolean(dockerVolumeDriverConfig(entry));
815
+ }
816
+ function isDockerInContainerMount(entry) {
817
+ return entry.mountStrategy?.type === 'in_container';
818
+ }
819
+ function isSupportedDockerInContainerMount(entry) {
820
+ if (!isDockerInContainerMount(entry)) {
821
+ return false;
822
+ }
823
+ let pattern;
824
+ try {
825
+ pattern = dockerInContainerMountPattern(entry);
826
+ }
827
+ catch {
828
+ return false;
829
+ }
830
+ switch (pattern.type) {
831
+ case 'rclone':
832
+ return dockerRcloneMountTypes.has(entry.type);
833
+ case 'mountpoint':
834
+ return entry.type === 's3_mount' || entry.type === 'gcs_mount';
835
+ case 's3files':
836
+ return entry.type === 's3_files_mount';
837
+ case 'fuse':
838
+ return entry.type === 'azure_blob_mount' || Boolean(pattern.command);
839
+ default:
840
+ return false;
841
+ }
842
+ }
843
+ function assertDockerCanApplyInContainerMounts(currentManifest, deltaManifest) {
844
+ const currentPrivilege = dockerInContainerMountPrivilege(currentManifest);
845
+ const requiredPrivilege = dockerInContainerMountPrivilege(deltaManifest);
846
+ if (dockerPrivilegeSatisfies(currentPrivilege, requiredPrivilege)) {
847
+ return;
848
+ }
849
+ throw new errors_2.SandboxUnsupportedFeatureError('DockerSandboxClient cannot add this in-container mount to an already-running container because it requires Docker privileges that were not granted at container start.', {
850
+ provider: 'DockerSandboxClient',
851
+ currentPrivilege,
852
+ requiredPrivilege,
853
+ });
854
+ }
855
+ function dockerPrivilegeSatisfies(current, required) {
856
+ if (required === 'none' || current === required) {
857
+ return true;
858
+ }
859
+ return current === 'fuse' && required === 'sys_admin';
860
+ }
861
+ function dockerVolumeMountContainingPath(manifest, path) {
862
+ return dockerMountContainingPath(manifest, path, isDockerVolumeMount);
863
+ }
864
+ function dockerInContainerMountContainingPath(manifest, path) {
865
+ return dockerMountContainingPath(manifest, path, isDockerInContainerMount);
866
+ }
867
+ function dockerMountContainingPath(manifest, path, predicate) {
868
+ const resolved = new workspacePaths_1.WorkspacePathPolicy({
869
+ root: manifest.root,
870
+ extraPathGrants: manifest.extraPathGrants,
871
+ }).resolve(path);
872
+ for (const { entry, mountPath } of manifest.mountTargets()) {
873
+ if (!predicate(entry)) {
874
+ continue;
875
+ }
876
+ if (pathWithinDockerMount(resolved.path, mountPath)) {
877
+ return mountPath;
878
+ }
879
+ }
880
+ return undefined;
881
+ }
882
+ function pathWithinDockerMount(path, mountPath) {
883
+ if (mountPath === '/') {
884
+ return true;
885
+ }
886
+ return path === mountPath || path.startsWith(`${mountPath}/`);
887
+ }
888
+ async function applyDockerInContainerMounts(session, manifest) {
889
+ const appliedMountPaths = [];
890
+ for (const { logicalPath, entry, } of manifest.mountTargetsForMaterialization()) {
891
+ if (!isDockerInContainerMount(entry)) {
892
+ continue;
893
+ }
894
+ try {
895
+ appliedMountPaths.push(await applyDockerInContainerMount(session, logicalPath, entry));
896
+ }
897
+ catch (error) {
898
+ await cleanupDockerAppliedMounts(session, appliedMountPaths);
899
+ throw error;
900
+ }
901
+ }
902
+ }
903
+ async function applyDockerInContainerMount(session, logicalPath, entry) {
904
+ const mountPath = resolveDockerMountPath(session.state.manifest.root, logicalPath, entry);
905
+ const pattern = dockerInContainerMountPattern(entry);
906
+ try {
907
+ switch (pattern.type) {
908
+ case 'rclone':
909
+ await applyDockerRcloneMount(session, entry, mountPath, pattern);
910
+ return mountPath;
911
+ case 'mountpoint':
912
+ await applyDockerMountpointMount(session, entry, mountPath, pattern);
913
+ return mountPath;
914
+ case 's3files':
915
+ await applyDockerS3FilesMount(session, entry, mountPath, pattern);
916
+ return mountPath;
917
+ case 'fuse':
918
+ await applyDockerFuseMount(session, entry, mountPath, pattern);
919
+ return mountPath;
920
+ default:
921
+ throw new errors_2.SandboxUnsupportedFeatureError('DockerSandboxClient does not support this in-container mount pattern.', {
922
+ provider: 'DockerSandboxClient',
923
+ feature: 'entry.mountStrategy.pattern',
924
+ mountType: entry.type,
925
+ patternType: pattern.type,
926
+ });
927
+ }
928
+ }
929
+ catch (error) {
930
+ await cleanupDockerAppliedMounts(session, [mountPath]);
931
+ throw error;
932
+ }
933
+ }
934
+ async function cleanupDockerAppliedMounts(session, mountPaths) {
935
+ for (const mountPath of [...mountPaths].reverse()) {
936
+ await session
937
+ .runDockerMountCommand([
938
+ `fusermount3 -u ${(0, shell_1.shellQuote)(mountPath)} >/dev/null 2>&1 || true`,
939
+ `fusermount -u ${(0, shell_1.shellQuote)(mountPath)} >/dev/null 2>&1 || true`,
940
+ `umount ${(0, shell_1.shellQuote)(mountPath)} >/dev/null 2>&1 || true`,
941
+ `umount -l ${(0, shell_1.shellQuote)(mountPath)} >/dev/null 2>&1 || true`,
942
+ dockerSafeKillRcloneNfsPidFileCommand(dockerRcloneNfsPidPath(session, mountPath)),
943
+ ].join(' ; '), `cleanup Docker mount ${mountPath}`)
944
+ .catch(() => undefined);
945
+ }
946
+ }
947
+ function dockerInContainerMountPattern(entry) {
948
+ const pattern = entry.mountStrategy?.pattern;
949
+ if (pattern) {
950
+ return pattern;
951
+ }
952
+ if (entry.type === 's3_files_mount') {
953
+ return { type: 's3files' };
954
+ }
955
+ if (dockerRcloneMountTypes.has(entry.type)) {
956
+ return { type: 'rclone', mode: 'fuse' };
957
+ }
958
+ throw new errors_2.SandboxUnsupportedFeatureError('DockerSandboxClient in-container mounts require a mount strategy pattern for this mount type.', {
959
+ provider: 'DockerSandboxClient',
960
+ feature: 'entry.mountStrategy.pattern',
961
+ mountType: entry.type,
962
+ });
963
+ }
964
+ function attachDockerSnapshotExcludedPaths(state) {
965
+ state.snapshotExcludedPaths = dockerInternalSnapshotExcludedPaths(state.manifest);
966
+ }
967
+ function dockerInternalSnapshotExcludedPaths(manifest) {
968
+ const paths = new Set();
969
+ for (const { entry } of manifest.mountTargetsForMaterialization()) {
970
+ if (!isDockerInContainerMount(entry)) {
971
+ continue;
972
+ }
973
+ const pattern = dockerInContainerMountPattern(entry);
974
+ if (entry.type === 'azure_blob_mount' && pattern.type === 'fuse') {
975
+ paths.add('.sandbox-blobfuse-config');
976
+ paths.add('.sandbox-blobfuse-cache');
977
+ const cachePath = dockerBlobfuseWorkspaceCachePath(pattern);
978
+ if (cachePath) {
979
+ paths.add(cachePath);
980
+ }
981
+ }
982
+ }
983
+ return [...paths];
984
+ }
985
+ async function applyDockerRcloneMount(session, entry, mountPath, pattern) {
986
+ const mode = pattern.mode ?? 'fuse';
987
+ if (mode !== 'fuse' && mode !== 'nfs') {
988
+ throw new errors_2.SandboxUnsupportedFeatureError('DockerSandboxClient rclone mounts support fuse and nfs modes only.', {
989
+ provider: 'DockerSandboxClient',
990
+ feature: 'entry.mountStrategy.pattern.mode',
991
+ mode,
992
+ });
993
+ }
994
+ const config = await dockerRcloneMountConfig(session, entry, pattern, mountPath);
995
+ const configDir = `/tmp/openai-agents-docker-mounts-${dockerPathHash(`${session.state.containerId}:${mountPath}`)}`;
996
+ const configPath = `${configDir}/${config.remoteName}.conf`;
997
+ const baseCommand = [
998
+ `mkdir -p -- ${(0, shell_1.shellQuote)(mountPath)}`,
999
+ `rm -rf -- ${(0, shell_1.shellQuote)(configDir)}`,
1000
+ `trap ${(0, shell_1.shellQuote)(`rm -rf -- ${(0, shell_1.shellQuote)(configDir)}`)} EXIT`,
1001
+ `install -d -m 700 -- ${(0, shell_1.shellQuote)(configDir)}`,
1002
+ `(umask 077 && cat > ${(0, shell_1.shellQuote)(configPath)})`,
1003
+ ];
1004
+ if (mode === 'nfs') {
1005
+ const nfsAddr = rclonePatternString(pattern, 'nfsAddr') ?? '127.0.0.1:2049';
1006
+ const pidPath = dockerRcloneNfsPidPath(session, mountPath);
1007
+ const [host, port] = splitDockerNfsAddr(nfsAddr);
1008
+ const serverArgs = [
1009
+ 'rclone',
1010
+ 'serve',
1011
+ 'nfs',
1012
+ `${config.remoteName}:${config.remotePath}`,
1013
+ '--addr',
1014
+ nfsAddr,
1015
+ '--config',
1016
+ configPath,
1017
+ ...(config.readOnly ? ['--read-only'] : []),
1018
+ ...dockerRclonePatternArgs(pattern),
1019
+ ];
1020
+ const mountOptions = rclonePatternStringArray(pattern, 'nfsMountOptions') ?? ['vers=4.1', 'tcp', `port=${port}`, 'soft', 'timeo=50', 'retrans=1'];
1021
+ const mountCommand = [
1022
+ '{ mounted=0',
1023
+ `for i in 1 2 3; do if mount -v -t nfs -o ${(0, shell_1.shellQuote)(mountOptions.join(','))} ${(0, shell_1.shellQuote)(`${host}:/`)} ${(0, shell_1.shellQuote)(mountPath)}; then mounted=1; break; fi; sleep 1; done`,
1024
+ `if [ "$mounted" = 1 ]; then rm -rf -- ${(0, shell_1.shellQuote)(configDir)}; exit 0; fi`,
1025
+ dockerSafeKillRcloneNfsPidFileCommand(pidPath),
1026
+ `rm -rf -- ${(0, shell_1.shellQuote)(configDir)}`,
1027
+ 'exit 1',
1028
+ '}',
1029
+ ].join('; ');
1030
+ await session.runDockerMountCommand([
1031
+ ...baseCommand,
1032
+ `(${shellCommand(serverArgs)} & printf %s "$!" > ${(0, shell_1.shellQuote)(pidPath)}) && ${mountCommand}`,
1033
+ ].join(' && '), `mount rclone ${entry.type}`, { input: config.configText });
1034
+ return;
1035
+ }
1036
+ const mountArgs = [
1037
+ 'rclone',
1038
+ 'mount',
1039
+ `${config.remoteName}:${config.remotePath}`,
1040
+ mountPath,
1041
+ ...(config.readOnly ? ['--read-only'] : []),
1042
+ ...dockerRcloneFuseAccessArgs(session),
1043
+ '--config',
1044
+ configPath,
1045
+ '--daemon',
1046
+ ...dockerRclonePatternArgs(pattern),
1047
+ ];
1048
+ await session.runDockerMountCommand([
1049
+ ...baseCommand,
1050
+ dockerEnableFuseAllowOtherCommand(),
1051
+ shellCommand(mountArgs),
1052
+ `rm -rf -- ${(0, shell_1.shellQuote)(configDir)}`,
1053
+ ].join(' && '), `mount rclone ${entry.type}`, { input: config.configText });
1054
+ }
1055
+ function dockerRcloneNfsPidPath(session, mountPath) {
1056
+ return `/tmp/openai-agents-rclone-nfs-${dockerPathHash(`${session.state.containerId}:${mountPath}`)}.pid`;
1057
+ }
1058
+ function dockerSafeKillRcloneNfsPidFileCommand(pidPath) {
1059
+ return [
1060
+ `pid=$(cat ${(0, shell_1.shellQuote)(pidPath)} 2>/dev/null || true)`,
1061
+ `case "$pid" in ''|0|*[!0-9]*) ;; *) cmdline=$(tr '\\000' ' ' < "/proc/$pid/cmdline" 2>/dev/null || true); case "$cmdline" in *rclone*serve\\ nfs*) kill "$pid" >/dev/null 2>&1 || true ;; esac ;; esac`,
1062
+ `rm -f -- ${(0, shell_1.shellQuote)(pidPath)}`,
1063
+ ].join('; ');
1064
+ }
1065
+ function dockerEnableFuseAllowOtherCommand() {
1066
+ return "touch /etc/fuse.conf && (grep -qxF user_allow_other /etc/fuse.conf || printf '\\nuser_allow_other\\n' >> /etc/fuse.conf)";
1067
+ }
1068
+ function dockerRcloneFuseAccessArgs(session) {
1069
+ const user = session.state.defaultUser;
1070
+ const match = /^(\d+):(\d+)$/u.exec(user ?? '');
1071
+ return [
1072
+ '--allow-other',
1073
+ ...(match ? ['--uid', match[1], '--gid', match[2]] : []),
1074
+ ];
1075
+ }
1076
+ async function applyDockerMountpointMount(session, entry, mountPath, pattern) {
1077
+ if (entry.type !== 's3_mount' && entry.type !== 'gcs_mount') {
1078
+ throw new errors_2.SandboxUnsupportedFeatureError('DockerSandboxClient mountpoint mounts support S3 and GCS mount entries only.', {
1079
+ provider: 'DockerSandboxClient',
1080
+ mountType: entry.type,
1081
+ });
1082
+ }
1083
+ const options = dockerMountpointPatternOptions(pattern);
1084
+ const endpointUrl = entry.endpointUrl ??
1085
+ options.endpointUrl ??
1086
+ (entry.type === 'gcs_mount' ? 'https://storage.googleapis.com' : undefined);
1087
+ const mountArgs = [
1088
+ 'mount-s3',
1089
+ ...((entry.readOnly ?? true)
1090
+ ? ['--read-only']
1091
+ : ['--allow-overwrite', '--allow-delete']),
1092
+ ...((entry.region ?? options.region)
1093
+ ? ['--region', entry.region ?? options.region]
1094
+ : []),
1095
+ ...(endpointUrl ? ['--endpoint-url', endpointUrl] : []),
1096
+ ...(entry.type === 'gcs_mount' ? ['--upload-checksums', 'off'] : []),
1097
+ ...((entry.prefix ?? options.prefix)
1098
+ ? ['--prefix', entry.prefix ?? options.prefix]
1099
+ : []),
1100
+ entry.bucket,
1101
+ mountPath,
1102
+ ];
1103
+ const envText = entry.type === 's3_mount'
1104
+ ? dockerMountpointAwsEnv(entry.accessKeyId, entry.secretAccessKey, entry.sessionToken)
1105
+ : dockerMountpointAwsEnv((0, typeGuards_1.readOptionalString)(entry, 'accessId'), (0, typeGuards_1.readOptionalString)(entry, 'secretAccessKey'));
1106
+ const envDir = `/tmp/openai-agents-mountpoint-env-${dockerPathHash(`${session.state.containerId}:${mountPath}`)}`;
1107
+ const envPath = `${envDir}/credentials.env`;
1108
+ const command = envText
1109
+ ? [
1110
+ `rm -rf -- ${(0, shell_1.shellQuote)(envDir)}`,
1111
+ `install -d -m 700 -- ${(0, shell_1.shellQuote)(envDir)}`,
1112
+ `(umask 077 && cat > ${(0, shell_1.shellQuote)(envPath)})`,
1113
+ `set -a && . ${(0, shell_1.shellQuote)(envPath)} && set +a`,
1114
+ `rm -rf -- ${(0, shell_1.shellQuote)(envDir)}`,
1115
+ shellCommand(mountArgs),
1116
+ ].join(' && ')
1117
+ : shellCommand(mountArgs);
1118
+ await session.runDockerMountCommand([`mkdir -p -- ${(0, shell_1.shellQuote)(mountPath)}`, command].join(' && '), `mount mountpoint ${entry.type}`, envText ? { input: envText } : {});
1119
+ }
1120
+ async function applyDockerS3FilesMount(session, entry, mountPath, pattern) {
1121
+ if (entry.type !== 's3_files_mount') {
1122
+ throw new errors_2.SandboxUnsupportedFeatureError('DockerSandboxClient s3files mounts require an s3FilesMount() entry.', {
1123
+ provider: 'DockerSandboxClient',
1124
+ mountType: entry.type,
1125
+ });
1126
+ }
1127
+ const s3Files = entry;
1128
+ if (!s3Files.fileSystemId) {
1129
+ throw new errors_2.SandboxMountError('s3FilesMount() requires fileSystemId for Docker in-container mounts.', { mountType: entry.type }, 'mount_config_invalid');
1130
+ }
1131
+ const patternOptions = dockerS3FilesPatternOptions(pattern);
1132
+ const options = {
1133
+ ...readStringNullRecord(patternOptions.extraOptions),
1134
+ ...readStringNullRecord(s3Files.extraOptions),
1135
+ };
1136
+ if (entry.readOnly ?? true) {
1137
+ options.ro = null;
1138
+ }
1139
+ const mountTargetIp = s3Files.mountTargetIp ?? patternOptions.mountTargetIp;
1140
+ const accessPoint = s3Files.accessPoint ?? patternOptions.accessPoint;
1141
+ const region = s3Files.region ?? patternOptions.region;
1142
+ if (mountTargetIp) {
1143
+ options.mounttargetip = mountTargetIp;
1144
+ }
1145
+ if (accessPoint) {
1146
+ options.accesspoint = accessPoint;
1147
+ }
1148
+ if (region) {
1149
+ options.region = region;
1150
+ }
1151
+ const device = s3Files.subpath
1152
+ ? `${s3Files.fileSystemId}:${s3Files.subpath}`
1153
+ : s3Files.fileSystemId;
1154
+ const mountArgs = [
1155
+ 'mount',
1156
+ '-t',
1157
+ 's3files',
1158
+ ...(Object.keys(options).length > 0
1159
+ ? ['-o', dockerMountOptions(options)]
1160
+ : []),
1161
+ device,
1162
+ mountPath,
1163
+ ];
1164
+ await session.runDockerMountCommand([`mkdir -p -- ${(0, shell_1.shellQuote)(mountPath)}`, shellCommand(mountArgs)].join(' && '), `mount s3files ${entry.type}`);
1165
+ }
1166
+ async function applyDockerFuseMount(session, entry, mountPath, pattern) {
1167
+ if (entry.type === 'azure_blob_mount') {
1168
+ await applyDockerAzureBlobFuseMount(session, entry, mountPath, pattern);
1169
+ return;
1170
+ }
1171
+ if (!pattern.command) {
1172
+ throw new errors_2.SandboxUnsupportedFeatureError('DockerSandboxClient fuse command mounts require pattern.command.', {
1173
+ provider: 'DockerSandboxClient',
1174
+ mountType: entry.type,
1175
+ });
1176
+ }
1177
+ const command = Array.isArray(pattern.command)
1178
+ ? shellCommand(pattern.command)
1179
+ : pattern.command;
1180
+ await session.runDockerMountCommand([
1181
+ `mkdir -p -- ${(0, shell_1.shellQuote)(mountPath)}`,
1182
+ [
1183
+ `export OPENAI_AGENTS_MOUNT_PATH=${(0, shell_1.shellQuote)(mountPath)}`,
1184
+ ...(entry.source
1185
+ ? [`export OPENAI_AGENTS_MOUNT_SOURCE=${(0, shell_1.shellQuote)(entry.source)}`]
1186
+ : []),
1187
+ command,
1188
+ ].join('; '),
1189
+ ].join(' && '), `mount fuse command ${entry.type}`);
1190
+ }
1191
+ async function applyDockerAzureBlobFuseMount(session, entry, mountPath, pattern) {
1192
+ const account = entry.account ?? entry.accountName;
1193
+ if (!account) {
1194
+ throw new errors_2.SandboxMountError('azureBlobMount() requires account or accountName for Docker fuse mounts.', { mountType: entry.type }, 'mount_config_invalid');
1195
+ }
1196
+ if (entry.prefix) {
1197
+ throw new errors_2.SandboxUnsupportedFeatureError('DockerSandboxClient blobfuse mounts do not support azureBlobMount().prefix. Use an rclone mount pattern for prefix-scoped Azure Blob mounts.', {
1198
+ provider: 'DockerSandboxClient',
1199
+ mountType: entry.type,
1200
+ });
1201
+ }
1202
+ const cacheType = dockerFusePatternString(pattern, 'cacheType', 'block_cache');
1203
+ if (cacheType !== 'block_cache' && cacheType !== 'file_cache') {
1204
+ throw new errors_2.SandboxMountError('blobfuse cacheType must be "block_cache" or "file_cache".', { mountType: entry.type, cacheType }, 'mount_config_invalid');
1205
+ }
1206
+ const workspaceRoot = session.state.manifest.root;
1207
+ const cacheDir = resolveDockerBlobfuseCacheDir(workspaceRoot, pattern, session.state.containerId, account, entry.container);
1208
+ if (pathWithinDockerMount(cacheDir, mountPath)) {
1209
+ throw new errors_2.SandboxMountError('blobfuse cachePath must be outside the mount path.', {
1210
+ mountPath,
1211
+ cachePath: cacheDir,
1212
+ }, 'mount_config_invalid');
1213
+ }
1214
+ const configDir = `/tmp/openai-agents-blobfuse-config-${dockerPathHash(`${session.state.containerId}:${mountPath}`)}`;
1215
+ const configName = `${sanitizeDockerMountName(account)}_${sanitizeDockerMountName(entry.container)}.yaml`;
1216
+ const configPath = `${configDir}/${configName}`;
1217
+ const configText = dockerBlobfuseConfigText({
1218
+ account,
1219
+ container: entry.container,
1220
+ endpoint: azureBlobEndpoint(entry) ?? `https://${account}.blob.core.windows.net`,
1221
+ cacheType,
1222
+ cacheSizeMb: dockerFusePatternNumber(pattern, 'cacheSizeMb') ??
1223
+ (cacheType === 'block_cache' ? 50_000 : 4_096),
1224
+ blockCacheBlockSizeMb: dockerFusePatternNumber(pattern, 'blockCacheBlockSizeMb') ?? 16,
1225
+ blockCacheDiskTimeoutSec: dockerFusePatternNumber(pattern, 'blockCacheDiskTimeoutSec') ?? 3600,
1226
+ fileCacheTimeoutSec: dockerFusePatternNumber(pattern, 'fileCacheTimeoutSec') ?? 120,
1227
+ fileCacheMaxSizeMb: dockerFusePatternNumber(pattern, 'fileCacheMaxSizeMb'),
1228
+ cacheDir,
1229
+ allowOther: dockerFusePatternBoolean(pattern, 'allowOther', true),
1230
+ logType: dockerFusePatternString(pattern, 'logType', 'syslog'),
1231
+ logLevel: dockerFusePatternString(pattern, 'logLevel', 'log_debug'),
1232
+ entryCacheTimeoutSec: dockerFusePatternNumber(pattern, 'entryCacheTimeoutSec'),
1233
+ negativeEntryCacheTimeoutSec: dockerFusePatternNumber(pattern, 'negativeEntryCacheTimeoutSec'),
1234
+ attrCacheTimeoutSec: dockerFusePatternNumber(pattern, 'attrCacheTimeoutSec'),
1235
+ identityClientId: entry.identityClientId,
1236
+ accountKey: entry.accountKey,
1237
+ });
1238
+ const mountArgs = [
1239
+ 'blobfuse2',
1240
+ 'mount',
1241
+ ...((entry.readOnly ?? true) ? ['--read-only'] : []),
1242
+ '--config-file',
1243
+ configPath,
1244
+ mountPath,
1245
+ ];
1246
+ await session.runDockerMountCommand([
1247
+ 'command -v blobfuse2 >/dev/null 2>&1',
1248
+ `mkdir -p -- ${(0, shell_1.shellQuote)(mountPath)} ${(0, shell_1.shellQuote)(cacheDir)}`,
1249
+ `rm -rf -- ${(0, shell_1.shellQuote)(configDir)}`,
1250
+ `trap ${(0, shell_1.shellQuote)(`rm -rf -- ${(0, shell_1.shellQuote)(configDir)}`)} EXIT`,
1251
+ `install -d -m 700 -- ${(0, shell_1.shellQuote)(configDir)}`,
1252
+ `(umask 077 && cat > ${(0, shell_1.shellQuote)(configPath)})`,
1253
+ dockerEnableFuseAllowOtherCommand(),
1254
+ shellCommand(mountArgs),
1255
+ `rm -rf -- ${(0, shell_1.shellQuote)(configDir)}`,
1256
+ ].join(' && '), `mount blobfuse ${entry.type}`, { input: configText });
1257
+ }
1258
+ function resolveDockerBlobfuseCacheDir(workspaceRoot, pattern, containerId, account, container) {
1259
+ const configuredCachePath = dockerFusePatternString(pattern, 'cachePath');
1260
+ if (configuredCachePath) {
1261
+ return (0, localWorkspace_1.joinSandboxLogicalPath)(workspaceRoot, normalizeDockerBlobfuseCachePath(configuredCachePath));
1262
+ }
1263
+ return (0, localWorkspace_1.joinSandboxLogicalPath)(workspaceRoot, [
1264
+ '.sandbox-blobfuse-cache',
1265
+ dockerPathHash(containerId),
1266
+ sanitizeDockerMountName(account),
1267
+ sanitizeDockerMountName(container),
1268
+ ].join('/'));
1269
+ }
1270
+ function dockerBlobfuseWorkspaceCachePath(pattern) {
1271
+ const configuredCachePath = dockerFusePatternString(pattern, 'cachePath');
1272
+ return configuredCachePath
1273
+ ? normalizeDockerBlobfuseCachePath(configuredCachePath)
1274
+ : undefined;
1275
+ }
1276
+ function normalizeDockerBlobfuseCachePath(cachePath) {
1277
+ const normalized = cachePath.replace(/\\/gu, '/');
1278
+ const parts = normalized.split('/').filter((part) => part.length > 0);
1279
+ if (normalized.startsWith('/') ||
1280
+ /^[A-Za-z]:\//u.test(normalized) ||
1281
+ normalized === '.' ||
1282
+ parts.includes('..')) {
1283
+ throw new errors_2.SandboxMountError('blobfuse cachePath must be relative to the workspace root.', { cachePath }, 'mount_config_invalid');
1284
+ }
1285
+ return normalized.replace(/^\.\/+/u, '');
1286
+ }
1287
+ function dockerBlobfuseConfigText(args) {
1288
+ const lines = [];
1289
+ if (args.allowOther) {
1290
+ lines.push('allow-other: true', '');
1291
+ }
1292
+ lines.push('logging:', ` type: ${args.logType}`, ` level: ${args.logLevel}`, '', 'components:', ' - libfuse', ` - ${args.cacheType}`, ' - attr_cache', ' - azstorage', '');
1293
+ const libfuseLines = [];
1294
+ if (args.entryCacheTimeoutSec !== undefined) {
1295
+ libfuseLines.push(` entry-expiration-sec: ${args.entryCacheTimeoutSec}`);
1296
+ }
1297
+ if (args.negativeEntryCacheTimeoutSec !== undefined) {
1298
+ libfuseLines.push(` negative-entry-expiration-sec: ${args.negativeEntryCacheTimeoutSec}`);
1299
+ }
1300
+ if (libfuseLines.length > 0) {
1301
+ lines.push('libfuse:', ...libfuseLines, '');
1302
+ }
1303
+ if (args.cacheType === 'block_cache') {
1304
+ lines.push('block_cache:', ` block-size-mb: ${args.blockCacheBlockSizeMb}`, ` mem-size-mb: ${args.cacheSizeMb}`, ` path: ${args.cacheDir}`, ` disk-size-mb: ${args.cacheSizeMb}`, ` disk-timeout-sec: ${args.blockCacheDiskTimeoutSec}`, '');
1305
+ }
1306
+ else {
1307
+ lines.push('file_cache:', ` path: ${args.cacheDir}`, ` timeout-sec: ${args.fileCacheTimeoutSec}`, ` max-size-mb: ${args.fileCacheMaxSizeMb ?? args.cacheSizeMb}`, '');
1308
+ }
1309
+ lines.push('attr_cache:', ` timeout-sec: ${args.attrCacheTimeoutSec ?? 7200}`, '', 'azstorage:', ' type: block', ` account-name: ${args.account}`, ` container: ${args.container}`, ` endpoint: ${args.endpoint}`);
1310
+ if (args.accountKey) {
1311
+ lines.push(' auth-type: key', ` account-key: ${args.accountKey}`);
1312
+ }
1313
+ else {
1314
+ lines.push(' mode: msi');
1315
+ }
1316
+ if (args.identityClientId) {
1317
+ lines.push(` identity-client-id: ${args.identityClientId}`);
1318
+ }
1319
+ lines.push('');
1320
+ return lines.join('\n');
1321
+ }
1322
+ function dockerFusePatternString(pattern, key, fallback) {
1323
+ const value = pattern[key];
1324
+ return typeof value === 'string' ? value : (fallback ?? '');
1325
+ }
1326
+ function dockerFusePatternNumber(pattern, key, fallback) {
1327
+ const value = pattern[key];
1328
+ return typeof value === 'number' ? value : fallback;
1329
+ }
1330
+ function dockerFusePatternBoolean(pattern, key, fallback) {
1331
+ const value = pattern[key];
1332
+ return typeof value === 'boolean' ? value : fallback;
1333
+ }
1334
+ function dockerMountArgsForManifest(manifest, containerName) {
1335
+ const mountArgs = [];
1336
+ const volumeNames = [];
1337
+ for (const { mountPath, entry, } of manifest.mountTargetsForMaterialization()) {
1338
+ if (isDockerBindMount(entry)) {
1339
+ mountArgs.push('--mount', dockerMountArg({
1340
+ type: 'bind',
1341
+ source: entry.source,
1342
+ target: mountPath,
1343
+ readOnly: entry.readOnly ?? true,
1344
+ }));
1345
+ continue;
1346
+ }
1347
+ const volumeConfig = dockerVolumeDriverConfig(entry);
1348
+ if (!volumeConfig) {
1349
+ continue;
1350
+ }
1351
+ const volumeName = dockerVolumeName(containerName, mountPath);
1352
+ volumeNames.push(volumeName);
1353
+ mountArgs.push('--mount', dockerMountArg({
1354
+ type: 'volume',
1355
+ source: volumeName,
1356
+ target: mountPath,
1357
+ readOnly: volumeConfig.readOnly,
1358
+ volumeDriver: volumeConfig.driver,
1359
+ volumeOptions: volumeConfig.options,
1360
+ }));
1361
+ }
1362
+ return { mountArgs, volumeNames };
1363
+ }
1364
+ function dockerExtraPathGrantMountArgs(manifest) {
1365
+ return manifest.extraPathGrants.flatMap((grant) => [
1366
+ '--mount',
1367
+ dockerMountArg({
1368
+ type: 'bind',
1369
+ source: grant.path,
1370
+ target: grant.path,
1371
+ readOnly: grant.readOnly,
1372
+ }),
1373
+ ]);
1374
+ }
1375
+ function dockerVolumeDriverConfig(entry) {
1376
+ if (entry.mountStrategy?.type !== 'docker_volume') {
1377
+ return undefined;
1378
+ }
1379
+ const driver = entry.mountStrategy.driver ?? 'local';
1380
+ const driverOptions = entry.mountStrategy.driverOptions ?? {};
1381
+ const readOnly = entry.readOnly ?? true;
1382
+ switch (entry.type) {
1383
+ case 's3_mount':
1384
+ if (driver !== 'rclone' && driver !== 'mountpoint') {
1385
+ return undefined;
1386
+ }
1387
+ return {
1388
+ driver,
1389
+ options: {
1390
+ ...(driver === 'rclone'
1391
+ ? dockerRcloneS3Options(entry)
1392
+ : dockerMountpointS3Options(entry)),
1393
+ ...driverOptions,
1394
+ },
1395
+ readOnly,
1396
+ };
1397
+ case 'gcs_mount':
1398
+ if (driver !== 'rclone' && driver !== 'mountpoint') {
1399
+ return undefined;
1400
+ }
1401
+ return {
1402
+ driver,
1403
+ options: {
1404
+ ...(driver === 'rclone'
1405
+ ? dockerRcloneGcsOptions(entry)
1406
+ : dockerMountpointGcsOptions(entry)),
1407
+ ...driverOptions,
1408
+ },
1409
+ readOnly,
1410
+ };
1411
+ case 'r2_mount':
1412
+ if (driver !== 'rclone') {
1413
+ return undefined;
1414
+ }
1415
+ return {
1416
+ driver,
1417
+ options: {
1418
+ ...dockerRcloneR2Options(entry),
1419
+ ...driverOptions,
1420
+ },
1421
+ readOnly,
1422
+ };
1423
+ case 'azure_blob_mount':
1424
+ if (driver !== 'rclone') {
1425
+ return undefined;
1426
+ }
1427
+ return {
1428
+ driver,
1429
+ options: {
1430
+ ...dockerRcloneAzureBlobOptions(entry),
1431
+ ...driverOptions,
1432
+ },
1433
+ readOnly,
1434
+ };
1435
+ case 'box_mount':
1436
+ if (driver !== 'rclone') {
1437
+ return undefined;
1438
+ }
1439
+ return {
1440
+ driver,
1441
+ options: {
1442
+ ...dockerRcloneBoxOptions(entry),
1443
+ ...driverOptions,
1444
+ },
1445
+ readOnly,
1446
+ };
1447
+ default:
1448
+ return undefined;
1449
+ }
1450
+ }
1451
+ const dockerRcloneMountTypes = new Set([
1452
+ 's3_mount',
1453
+ 'r2_mount',
1454
+ 'gcs_mount',
1455
+ 'azure_blob_mount',
1456
+ 'box_mount',
1457
+ ]);
1458
+ async function dockerRcloneMountConfig(session, entry, pattern, mountPath) {
1459
+ const remoteName = dockerRcloneRemoteName(entry, pattern, mountPath);
1460
+ const withConfigText = async (config) => {
1461
+ const configFilePath = rclonePatternString(pattern, 'configFilePath');
1462
+ if (!configFilePath) {
1463
+ return config;
1464
+ }
1465
+ const sourcePath = resolveDockerRcloneConfigPath(session.state.manifest, configFilePath);
1466
+ const encodedConfig = await session.runDockerMountCommand(`base64 -- ${(0, shell_1.shellQuote)(sourcePath)}`, `read rclone config ${sourcePath}`);
1467
+ const sourceConfigText = Buffer.from(encodedConfig.replace(/\s+/gu, ''), 'base64').toString('utf8');
1468
+ return {
1469
+ ...config,
1470
+ configText: supplementDockerRcloneConfigText(sourceConfigText, remoteName, config.configText, entry.type),
1471
+ };
1472
+ };
1473
+ switch (entry.type) {
1474
+ case 's3_mount':
1475
+ return await withConfigText({
1476
+ remoteName,
1477
+ remotePath: joinRemotePath(entry.bucket, entry.prefix),
1478
+ configText: [
1479
+ `[${remoteName}]`,
1480
+ 'type = s3',
1481
+ `provider = ${entry.s3Provider ?? 'AWS'}`,
1482
+ ...(entry.endpointUrl ? [`endpoint = ${entry.endpointUrl}`] : []),
1483
+ ...(entry.region ? [`region = ${entry.region}`] : []),
1484
+ ...s3CredentialLines(entry),
1485
+ '',
1486
+ ].join('\n'),
1487
+ readOnly: entry.readOnly ?? true,
1488
+ });
1489
+ case 'r2_mount':
1490
+ validateCredentialPair('R2', entry.type, entry.accessKeyId, entry.secretAccessKey);
1491
+ if (!entry.accountId) {
1492
+ throw new errors_2.SandboxMountError('R2 mounts require accountId.', { mountType: entry.type }, 'mount_config_invalid');
1493
+ }
1494
+ return await withConfigText({
1495
+ remoteName,
1496
+ remotePath: joinRemotePath(entry.bucket, entry.prefix),
1497
+ configText: [
1498
+ `[${remoteName}]`,
1499
+ 'type = s3',
1500
+ 'provider = Cloudflare',
1501
+ `endpoint = ${entry.customDomain ?? `https://${entry.accountId}.r2.cloudflarestorage.com`}`,
1502
+ 'acl = private',
1503
+ ...(entry.accessKeyId && entry.secretAccessKey
1504
+ ? [
1505
+ 'env_auth = false',
1506
+ `access_key_id = ${entry.accessKeyId}`,
1507
+ `secret_access_key = ${entry.secretAccessKey}`,
1508
+ ]
1509
+ : ['env_auth = true']),
1510
+ '',
1511
+ ].join('\n'),
1512
+ readOnly: entry.readOnly ?? true,
1513
+ });
1514
+ case 'gcs_mount':
1515
+ return await withConfigText(dockerGcsRcloneMountConfig(entry, remoteName));
1516
+ case 'azure_blob_mount':
1517
+ return await withConfigText(dockerAzureBlobRcloneMountConfig(entry, remoteName));
1518
+ case 'box_mount':
1519
+ return await withConfigText({
1520
+ remoteName,
1521
+ remotePath: normalizeBoxRemotePath(entry.path),
1522
+ configText: [
1523
+ `[${remoteName}]`,
1524
+ 'type = box',
1525
+ ...(entry.clientId ? [`client_id = ${entry.clientId}`] : []),
1526
+ ...(entry.clientSecret
1527
+ ? [`client_secret = ${entry.clientSecret}`]
1528
+ : []),
1529
+ ...(entry.accessToken ? [`access_token = ${entry.accessToken}`] : []),
1530
+ ...(entry.token ? [`token = ${entry.token}`] : []),
1531
+ ...(entry.boxConfigFile
1532
+ ? [`box_config_file = ${entry.boxConfigFile}`]
1533
+ : []),
1534
+ ...(entry.configCredentials
1535
+ ? [`config_credentials = ${entry.configCredentials}`]
1536
+ : []),
1537
+ ...(entry.boxSubType && entry.boxSubType !== 'user'
1538
+ ? [`box_sub_type = ${entry.boxSubType}`]
1539
+ : []),
1540
+ ...(entry.rootFolderId
1541
+ ? [`root_folder_id = ${entry.rootFolderId}`]
1542
+ : []),
1543
+ ...(entry.impersonate ? [`impersonate = ${entry.impersonate}`] : []),
1544
+ ...(entry.ownedBy ? [`owned_by = ${entry.ownedBy}`] : []),
1545
+ '',
1546
+ ].join('\n'),
1547
+ readOnly: entry.readOnly ?? true,
1548
+ });
1549
+ default:
1550
+ throw new errors_2.SandboxUnsupportedFeatureError('DockerSandboxClient rclone mounts do not support this mount entry.', {
1551
+ provider: 'DockerSandboxClient',
1552
+ mountType: entry.type,
1553
+ });
1554
+ }
1555
+ }
1556
+ function dockerAzureBlobRcloneMountConfig(entry, remoteName) {
1557
+ const account = entry.account ?? entry.accountName;
1558
+ if (!account) {
1559
+ throw new errors_2.SandboxMountError('Azure Blob mounts require account or accountName.', { mountType: entry.type }, 'mount_config_invalid');
1560
+ }
1561
+ return {
1562
+ remoteName,
1563
+ remotePath: joinRemotePath(entry.container, entry.prefix),
1564
+ configText: [
1565
+ `[${remoteName}]`,
1566
+ 'type = azureblob',
1567
+ `account = ${account}`,
1568
+ ...(azureBlobEndpoint(entry)
1569
+ ? [`endpoint = ${azureBlobEndpoint(entry)}`]
1570
+ : []),
1571
+ ...(entry.accountKey
1572
+ ? [`key = ${entry.accountKey}`]
1573
+ : [
1574
+ 'use_msi = true',
1575
+ ...(entry.identityClientId
1576
+ ? [`msi_client_id = ${entry.identityClientId}`]
1577
+ : []),
1578
+ ]),
1579
+ '',
1580
+ ].join('\n'),
1581
+ readOnly: entry.readOnly ?? true,
1582
+ };
1583
+ }
1584
+ function azureBlobEndpoint(entry) {
1585
+ return entry.endpointUrl ?? entry.endpoint;
1586
+ }
1587
+ function dockerGcsRcloneMountConfig(entry, remoteName) {
1588
+ const accessId = (0, typeGuards_1.readOptionalString)(entry, 'accessId');
1589
+ const secretAccessKey = (0, typeGuards_1.readOptionalString)(entry, 'secretAccessKey');
1590
+ if (accessId && secretAccessKey) {
1591
+ return {
1592
+ remoteName,
1593
+ remotePath: joinRemotePath(entry.bucket, entry.prefix),
1594
+ configText: [
1595
+ `[${remoteName}]`,
1596
+ 'type = s3',
1597
+ 'provider = GCS',
1598
+ 'env_auth = false',
1599
+ `access_key_id = ${accessId}`,
1600
+ `secret_access_key = ${secretAccessKey}`,
1601
+ `endpoint = ${entry.endpointUrl ?? 'https://storage.googleapis.com'}`,
1602
+ ...(entry.region ? [`region = ${entry.region}`] : []),
1603
+ '',
1604
+ ].join('\n'),
1605
+ readOnly: entry.readOnly ?? true,
1606
+ };
1607
+ }
1608
+ return {
1609
+ remoteName,
1610
+ remotePath: joinRemotePath(entry.bucket, entry.prefix),
1611
+ configText: [
1612
+ `[${remoteName}]`,
1613
+ 'type = google cloud storage',
1614
+ ...(entry.serviceAccountFile
1615
+ ? [`service_account_file = ${entry.serviceAccountFile}`]
1616
+ : []),
1617
+ ...(entry.serviceAccountCredentials
1618
+ ? [`service_account_credentials = ${entry.serviceAccountCredentials}`]
1619
+ : []),
1620
+ ...(entry.accessToken ? [`access_token = ${entry.accessToken}`] : []),
1621
+ entry.serviceAccountFile ||
1622
+ entry.serviceAccountCredentials ||
1623
+ entry.accessToken
1624
+ ? 'env_auth = false'
1625
+ : 'env_auth = true',
1626
+ '',
1627
+ ].join('\n'),
1628
+ readOnly: entry.readOnly ?? true,
1629
+ };
1630
+ }
1631
+ function dockerInContainerMountPrivilegeArgs(manifest) {
1632
+ const privilege = dockerInContainerMountPrivilege(manifest);
1633
+ if (privilege === 'fuse') {
1634
+ return [
1635
+ '--device',
1636
+ '/dev/fuse',
1637
+ '--cap-add',
1638
+ 'SYS_ADMIN',
1639
+ '--security-opt',
1640
+ 'apparmor:unconfined',
1641
+ ];
1642
+ }
1643
+ if (privilege === 'sys_admin') {
1644
+ return ['--cap-add', 'SYS_ADMIN', '--security-opt', 'apparmor:unconfined'];
1645
+ }
1646
+ return [];
1647
+ }
1648
+ function dockerInContainerMountPrivilege(manifest) {
1649
+ let needsSysAdmin = false;
1650
+ for (const { entry } of manifest.mountTargetsForMaterialization()) {
1651
+ if (!isDockerInContainerMount(entry)) {
1652
+ continue;
1653
+ }
1654
+ const pattern = dockerInContainerMountPattern(entry);
1655
+ if (pattern.type === 'fuse' ||
1656
+ pattern.type === 'mountpoint' ||
1657
+ (pattern.type === 'rclone' && (pattern.mode ?? 'fuse') === 'fuse')) {
1658
+ return 'fuse';
1659
+ }
1660
+ if (pattern.type === 's3files' ||
1661
+ (pattern.type === 'rclone' && pattern.mode === 'nfs')) {
1662
+ needsSysAdmin = true;
1663
+ }
1664
+ }
1665
+ return needsSysAdmin ? 'sys_admin' : 'none';
1666
+ }
1667
+ function s3CredentialLines(entry) {
1668
+ const lines = [];
1669
+ if (entry.accessKeyId && entry.secretAccessKey) {
1670
+ lines.push('env_auth = false');
1671
+ lines.push(`access_key_id = ${entry.accessKeyId}`);
1672
+ lines.push(`secret_access_key = ${entry.secretAccessKey}`);
1673
+ if (entry.sessionToken) {
1674
+ lines.push(`session_token = ${entry.sessionToken}`);
1675
+ }
1676
+ }
1677
+ else {
1678
+ lines.push('env_auth = true');
1679
+ }
1680
+ return lines;
1681
+ }
1682
+ function validateCredentialPair(provider, mountType, accessKeyId, secretAccessKey) {
1683
+ if (Boolean(accessKeyId) !== Boolean(secretAccessKey)) {
1684
+ throw new errors_2.SandboxMountError(`${provider} mounts require both accessKeyId and secretAccessKey when either is provided.`, { mountType }, 'mount_config_invalid');
1685
+ }
1686
+ }
1687
+ function dockerMountpointAwsEnv(accessKeyId, secretAccessKey, sessionToken) {
1688
+ if (!accessKeyId || !secretAccessKey) {
1689
+ return '';
1690
+ }
1691
+ return [
1692
+ `AWS_ACCESS_KEY_ID=${(0, shell_1.shellQuote)(accessKeyId)}`,
1693
+ `AWS_SECRET_ACCESS_KEY=${(0, shell_1.shellQuote)(secretAccessKey)}`,
1694
+ ...(sessionToken ? [`AWS_SESSION_TOKEN=${(0, shell_1.shellQuote)(sessionToken)}`] : []),
1695
+ '',
1696
+ ].join('\n');
1697
+ }
1698
+ function splitDockerNfsAddr(value) {
1699
+ const index = value.lastIndexOf(':');
1700
+ if (index < 0) {
1701
+ return [
1702
+ value === '0.0.0.0' || value === '::' ? '127.0.0.1' : value,
1703
+ '2049',
1704
+ ];
1705
+ }
1706
+ const host = value.slice(0, index);
1707
+ return [
1708
+ host === '0.0.0.0' || host === '::' ? '127.0.0.1' : host,
1709
+ value.slice(index + 1),
1710
+ ];
1711
+ }
1712
+ function dockerMountpointPatternOptions(pattern) {
1713
+ const options = readRecord(pattern.options);
1714
+ return {
1715
+ prefix: (0, typeGuards_1.readOptionalString)(options, 'prefix'),
1716
+ region: (0, typeGuards_1.readOptionalString)(options, 'region'),
1717
+ endpointUrl: (0, typeGuards_1.readOptionalString)(options, 'endpointUrl'),
1718
+ };
1719
+ }
1720
+ function dockerS3FilesPatternOptions(pattern) {
1721
+ const options = readRecord(pattern.options);
1722
+ return {
1723
+ mountTargetIp: (0, typeGuards_1.readOptionalString)(options, 'mountTargetIp'),
1724
+ accessPoint: (0, typeGuards_1.readOptionalString)(options, 'accessPoint'),
1725
+ region: (0, typeGuards_1.readOptionalString)(options, 'region'),
1726
+ extraOptions: readStringNullRecord(options.extraOptions),
1727
+ };
1728
+ }
1729
+ function dockerRcloneRemoteName(entry, pattern, mountPath) {
1730
+ const remoteName = rclonePatternString(pattern, 'remoteName') ??
1731
+ rclonePatternString(pattern, 'remote');
1732
+ if (!remoteName) {
1733
+ return `sandbox_${sanitizeDockerMountName(entry.type)}_${dockerPathHash(mountPath)}`;
1734
+ }
1735
+ if (!/^[A-Za-z0-9_-]+$/u.test(remoteName)) {
1736
+ throw new errors_2.SandboxMountError('DockerSandboxClient rclone mounts require remoteName to contain only letters, numbers, underscores, and hyphens.', {
1737
+ mountType: entry.type,
1738
+ remoteName,
1739
+ }, 'mount_config_invalid');
1740
+ }
1741
+ return remoteName;
1742
+ }
1743
+ function resolveDockerRcloneConfigPath(manifest, configFilePath) {
1744
+ return new workspacePaths_1.WorkspacePathPolicy({
1745
+ root: manifest.root,
1746
+ extraPathGrants: manifest.extraPathGrants,
1747
+ }).resolve(configFilePath).path;
1748
+ }
1749
+ function supplementDockerRcloneConfigText(configText, remoteName, requiredConfigText, mountType) {
1750
+ const escapedRemote = remoteName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
1751
+ const sectionPattern = new RegExp(`^\\s*\\[${escapedRemote}\\]\\s*$`, 'mu');
1752
+ const match = sectionPattern.exec(configText);
1753
+ if (!match) {
1754
+ throw new errors_2.SandboxMountError('DockerSandboxClient rclone config file is missing the required remote section.', {
1755
+ mountType,
1756
+ remoteName,
1757
+ }, 'mount_config_invalid');
1758
+ }
1759
+ const sectionStart = match.index;
1760
+ const sectionEnd = match.index + match[0].length;
1761
+ const nextSection = /^\s*\[.+\]\s*$/mu.exec(configText.slice(sectionEnd));
1762
+ const sectionBodyEnd = nextSection
1763
+ ? sectionEnd + nextSection.index
1764
+ : configText.length;
1765
+ const before = configText.slice(0, sectionStart);
1766
+ const sectionBody = configText.slice(sectionStart, sectionBodyEnd).trimEnd();
1767
+ const after = configText.slice(sectionBodyEnd);
1768
+ const requiredLines = requiredConfigText.trimEnd().split('\n').slice(1);
1769
+ const supplement = requiredLines.length > 0 ? `\n${requiredLines.join('\n')}` : '';
1770
+ return `${before}${sectionBody}${supplement}\n${after}`;
1771
+ }
1772
+ function dockerRclonePatternArgs(pattern) {
1773
+ return [
1774
+ ...(rclonePatternStringArray(pattern, 'args') ?? []),
1775
+ ...(rclonePatternStringArray(pattern, 'extraArgs') ?? []),
1776
+ ];
1777
+ }
1778
+ function rclonePatternString(pattern, key) {
1779
+ return (0, typeGuards_1.readOptionalString)(pattern, key);
1780
+ }
1781
+ function rclonePatternStringArray(pattern, key) {
1782
+ const value = (0, typeGuards_1.readStringArray)(pattern[key]);
1783
+ return value.length > 0 ? value : undefined;
1784
+ }
1785
+ function readRecord(value) {
1786
+ return value && typeof value === 'object' && !Array.isArray(value)
1787
+ ? value
1788
+ : {};
1789
+ }
1790
+ function readStringNullRecord(value) {
1791
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
1792
+ return {};
1793
+ }
1794
+ return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === 'string' || entry[1] === null));
1795
+ }
1796
+ function dockerMountOptions(options) {
1797
+ return Object.entries(options)
1798
+ .map(([key, value]) => (value === null ? key : `${key}=${value}`))
1799
+ .join(',');
1800
+ }
1801
+ function shellCommand(parts) {
1802
+ return parts.map((part) => (0, shell_1.shellQuote)(part)).join(' ');
1803
+ }
1804
+ function sanitizeDockerMountName(value) {
1805
+ return value.replace(/[^A-Za-z0-9_-]/gu, '_');
1806
+ }
1807
+ function dockerPathHash(path) {
1808
+ return (0, node_crypto_1.createHash)('sha256').update(path).digest('hex').slice(0, 12);
1809
+ }
1810
+ function dockerPosixDirname(path) {
1811
+ const index = path.lastIndexOf('/');
1812
+ if (index <= 0) {
1813
+ return index === 0 ? '/' : '.';
1814
+ }
1815
+ return path.slice(0, index);
1816
+ }
1817
+ function resolveDockerMountPath(manifestRoot, logicalPath, entry) {
1818
+ if (entry.mountPath?.startsWith('/')) {
1819
+ return entry.mountPath;
1820
+ }
1821
+ const mountPath = entry.mountPath ?? logicalPath;
1822
+ return (0, localWorkspace_1.joinSandboxLogicalPath)(manifestRoot, mountPath);
1823
+ }
1824
+ function resolveDockerMountWorkspaceRelativePath(manifestRoot, logicalPath, entry) {
1825
+ const target = resolveDockerMountPath(manifestRoot, logicalPath, entry);
1826
+ if (target === '/') {
1827
+ throw new errors_2.SandboxUnsupportedFeatureError('DockerSandboxClient does not support mounting over the container root.');
1828
+ }
1829
+ try {
1830
+ const resolved = new workspacePaths_1.WorkspacePathPolicy({ root: manifestRoot }).resolve(target, { forWrite: true });
1831
+ return resolved.workspaceRelativePath ?? null;
1832
+ }
1833
+ catch {
1834
+ return null;
1835
+ }
1836
+ }
1837
+ function dockerMountArg(args) {
1838
+ return [
1839
+ dockerMountField('type', args.type),
1840
+ dockerMountField('source', args.source),
1841
+ dockerMountField('target', args.target),
1842
+ ...(args.readOnly ? ['readonly'] : []),
1843
+ ...(args.volumeDriver
1844
+ ? [dockerMountField('volume-driver', args.volumeDriver)]
1845
+ : []),
1846
+ ...Object.entries(args.volumeOptions ?? {}).map(([key, value]) => dockerMountField('volume-opt', `${key}=${value}`)),
1847
+ ].join(',');
1848
+ }
1849
+ function dockerMountField(key, value) {
1850
+ return dockerMountCsvField(`${key}=${value}`);
1851
+ }
1852
+ function dockerMountCsvField(field) {
1853
+ if (!/[",\n\r]/u.test(field)) {
1854
+ return field;
1855
+ }
1856
+ return `"${field.replace(/"/gu, '""')}"`;
1857
+ }
1858
+ function dockerVolumeName(containerName, mountPath) {
1859
+ const pathHash = (0, node_crypto_1.createHash)('sha256')
1860
+ .update(mountPath)
1861
+ .digest('hex')
1862
+ .slice(0, 12);
1863
+ const safePath = mountPath.replace(/[^A-Za-z0-9_.-]+/gu, '_').replace(/^_+|_+$/gu, '') ||
1864
+ 'workspace';
1865
+ return `${containerName}-${pathHash}-${safePath.slice(0, 80)}`;
1866
+ }
1867
+ async function removeDockerVolumes(volumeNames) {
1868
+ await Promise.all(volumeNames.map(async (volumeName) => {
1869
+ await (0, runProcess_1.runSandboxProcess)('docker', ['volume', 'rm', '-f', volumeName], {
1870
+ timeoutMs: DOCKER_FAST_COMMAND_TIMEOUT_MS,
1871
+ }).catch(() => undefined);
1872
+ }));
1873
+ }
1874
+ function dockerRcloneS3Options(entry) {
1875
+ return withDefinedStringValues({
1876
+ type: 's3',
1877
+ 's3-provider': entry.s3Provider ?? 'AWS',
1878
+ path: joinRemotePath(entry.bucket, entry.prefix),
1879
+ 's3-access-key-id': entry.accessKeyId,
1880
+ 's3-secret-access-key': entry.secretAccessKey,
1881
+ 's3-session-token': entry.sessionToken,
1882
+ 's3-endpoint': entry.endpointUrl,
1883
+ 's3-region': entry.region,
1884
+ });
1885
+ }
1886
+ function dockerMountpointS3Options(entry) {
1887
+ return withDefinedStringValues({
1888
+ bucket: entry.bucket,
1889
+ access_key_id: entry.accessKeyId,
1890
+ secret_access_key: entry.secretAccessKey,
1891
+ session_token: entry.sessionToken,
1892
+ endpoint_url: entry.endpointUrl,
1893
+ region: entry.region,
1894
+ prefix: entry.prefix,
1895
+ });
1896
+ }
1897
+ function dockerRcloneGcsOptions(entry) {
1898
+ if (entry.accessId && entry.secretAccessKey) {
1899
+ return withDefinedStringValues({
1900
+ type: 's3',
1901
+ path: joinRemotePath(entry.bucket, entry.prefix),
1902
+ 's3-provider': 'GCS',
1903
+ 's3-access-key-id': entry.accessId,
1904
+ 's3-secret-access-key': entry.secretAccessKey,
1905
+ 's3-endpoint': entry.endpointUrl ?? 'https://storage.googleapis.com',
1906
+ 's3-region': entry.region,
1907
+ });
1908
+ }
1909
+ return withDefinedStringValues({
1910
+ type: 'google cloud storage',
1911
+ path: joinRemotePath(entry.bucket, entry.prefix),
1912
+ 'gcs-service-account-file': entry.serviceAccountFile,
1913
+ 'gcs-service-account-credentials': entry.serviceAccountCredentials,
1914
+ 'gcs-access-token': entry.accessToken,
1915
+ });
1916
+ }
1917
+ function dockerMountpointGcsOptions(entry) {
1918
+ return withDefinedStringValues({
1919
+ bucket: entry.bucket,
1920
+ endpoint_url: entry.endpointUrl ?? 'https://storage.googleapis.com',
1921
+ access_key_id: entry.accessId,
1922
+ secret_access_key: entry.secretAccessKey,
1923
+ region: entry.region,
1924
+ prefix: entry.prefix,
1925
+ });
1926
+ }
1927
+ function dockerRcloneR2Options(entry) {
1928
+ validateCredentialPair('R2', entry.type, entry.accessKeyId, entry.secretAccessKey);
1929
+ if (!entry.accountId) {
1930
+ throw new errors_2.SandboxMountError('R2 Docker volume mounts require accountId.', { mountType: entry.type }, 'mount_config_invalid');
1931
+ }
1932
+ return withDefinedStringValues({
1933
+ type: 's3',
1934
+ path: joinRemotePath(entry.bucket, entry.prefix),
1935
+ 's3-provider': 'Cloudflare',
1936
+ 's3-endpoint': entry.customDomain ??
1937
+ `https://${entry.accountId}.r2.cloudflarestorage.com`,
1938
+ 's3-access-key-id': entry.accessKeyId,
1939
+ 's3-secret-access-key': entry.secretAccessKey,
1940
+ });
1941
+ }
1942
+ function dockerRcloneAzureBlobOptions(entry) {
1943
+ return withDefinedStringValues({
1944
+ type: 'azureblob',
1945
+ path: joinRemotePath(entry.container, entry.prefix),
1946
+ 'azureblob-account': entry.account ?? entry.accountName,
1947
+ 'azureblob-endpoint': azureBlobEndpoint(entry),
1948
+ 'azureblob-msi-client-id': entry.identityClientId,
1949
+ 'azureblob-key': entry.accountKey,
1950
+ });
1951
+ }
1952
+ function dockerRcloneBoxOptions(entry) {
1953
+ return withDefinedStringValues({
1954
+ type: 'box',
1955
+ path: normalizeBoxRemotePath(entry.path),
1956
+ 'box-client-id': entry.clientId,
1957
+ 'box-client-secret': entry.clientSecret,
1958
+ 'box-access-token': entry.accessToken,
1959
+ 'box-token': entry.token,
1960
+ 'box-box-config-file': entry.boxConfigFile,
1961
+ 'box-config-credentials': entry.configCredentials,
1962
+ 'box-box-sub-type': entry.boxSubType && entry.boxSubType !== 'user'
1963
+ ? entry.boxSubType
1964
+ : undefined,
1965
+ 'box-root-folder-id': entry.rootFolderId,
1966
+ 'box-impersonate': entry.impersonate,
1967
+ 'box-owned-by': entry.ownedBy,
1968
+ });
1969
+ }
1970
+ function joinRemotePath(base, prefix) {
1971
+ const normalizedPrefix = prefix?.replace(/^\/+|\/+$/gu, '');
1972
+ return normalizedPrefix ? `${base}/${normalizedPrefix}` : base;
1973
+ }
1974
+ function normalizeBoxRemotePath(path) {
1975
+ return path?.replace(/^\/+/gu, '') ?? '';
1976
+ }
1977
+ function withDefinedStringValues(values) {
1978
+ return Object.fromEntries(Object.entries(values).filter((entry) => typeof entry[1] === 'string'));
1979
+ }
1980
+ function parseDockerPortBinding(stdout, containerPort) {
1981
+ const line = stdout
1982
+ .split(/\r?\n/u)
1983
+ .map((value) => value.trim())
1984
+ .find(Boolean);
1985
+ if (!line) {
1986
+ throw new errors_1.UserError(`Docker did not report a host binding for exposed port ${containerPort}.`);
1987
+ }
1988
+ const bracketMatch = line.match(/^\[([^\]]+)\]:(\d+)$/u);
1989
+ const match = bracketMatch ?? line.match(/^(.+):(\d+)$/u);
1990
+ if (!match) {
1991
+ throw new errors_1.UserError(`Docker reported an unrecognized host binding for exposed port ${containerPort}: ${line}`);
1992
+ }
1993
+ const rawHost = match[1];
1994
+ return {
1995
+ host: normalizeDockerBindingHost(rawHost),
1996
+ port: (0, session_1.normalizeExposedPort)(Number(match[2])),
1997
+ };
1998
+ }
1999
+ function normalizeDockerBindingHost(host) {
2000
+ if (host === '0.0.0.0') {
2001
+ return '127.0.0.1';
2002
+ }
2003
+ if (host === '::' || host === '') {
2004
+ return '::1';
2005
+ }
2006
+ return host;
2007
+ }
2008
+ function getHostDockerUser() {
2009
+ if (typeof process.getuid !== 'function' ||
2010
+ typeof process.getgid !== 'function') {
2011
+ return undefined;
2012
+ }
2013
+ return `${process.getuid()}:${process.getgid()}`;
2014
+ }
2015
+ //# sourceMappingURL=docker.js.map