deepline 0.3.460 → 0.3.462

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 (297) hide show
  1. package/dist/bundling-sources/sdk/src/client-core.ts +7593 -0
  2. package/dist/bundling-sources/sdk/src/client.ts +8 -7366
  3. package/dist/bundling-sources/sdk/src/http-core.ts +1239 -0
  4. package/dist/bundling-sources/sdk/src/http.ts +6 -1231
  5. package/dist/bundling-sources/sdk/src/index.ts +4 -1
  6. package/dist/bundling-sources/sdk/src/play.ts +5 -5
  7. package/dist/bundling-sources/sdk/src/plays/client-core.ts +437 -0
  8. package/dist/bundling-sources/sdk/src/plays/client.ts +4 -421
  9. package/dist/bundling-sources/sdk/src/plays/input-example.ts +3 -4
  10. package/dist/bundling-sources/sdk/src/plays/play-description.ts +1 -1
  11. package/dist/bundling-sources/sdk/src/plays/run-request.ts +1 -1
  12. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  13. package/dist/bundling-sources/sdk/src/server.ts +43 -0
  14. package/dist/bundling-sources/sdk/src/types.ts +15 -5
  15. package/dist/bundling-sources/shared_libs/integration-contracts/billing-entitlements.ts +15 -0
  16. package/dist/bundling-sources/shared_libs/monitors/billing/state.ts +28 -0
  17. package/dist/bundling-sources/shared_libs/monitors/callback-security.ts +0 -307
  18. package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +3 -0
  19. package/dist/bundling-sources/shared_libs/monitors/lifecycle-notifications.ts +3 -2
  20. package/dist/bundling-sources/shared_libs/monitors/package.json +2 -0
  21. package/dist/bundling-sources/shared_libs/monitors/provider-callback-verification.ts +34 -0
  22. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +59 -0
  23. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-upstream-identity.ts +94 -1
  24. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-dead-letter.ts +35 -1
  25. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-failure-codes.ts +24 -0
  26. package/dist/bundling-sources/shared_libs/observability/dlq.ts +32 -0
  27. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +57 -3
  28. package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +1 -0
  29. package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +66 -1
  30. package/dist/bundling-sources/shared_libs/play-data-plane/sheet-column-storage.ts +36 -7
  31. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +250 -11
  32. package/dist/bundling-sources/shared_libs/play-runtime/array-input-store.ts +319 -0
  33. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +991 -359
  34. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +17 -0
  35. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-janitor.ts +13 -0
  36. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-reaper.ts +110 -0
  37. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +155 -6
  38. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +110 -6
  39. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +127 -13
  40. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +14 -1
  41. package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +57 -1
  42. package/dist/bundling-sources/shared_libs/play-runtime/free-company-lookup-batching.ts +218 -0
  43. package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +42 -5
  44. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-budget-state-backend.ts +6 -1
  45. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +92 -31
  46. package/dist/bundling-sources/shared_libs/play-runtime/governor/block-reserving-budget-state-backend.ts +69 -14
  47. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +93 -23
  48. package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +15 -4
  49. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +22 -18
  50. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +5 -0
  51. package/dist/bundling-sources/shared_libs/play-runtime/launch-identity.ts +2 -0
  52. package/dist/bundling-sources/shared_libs/play-runtime/map-memory-limits.ts +190 -14
  53. package/dist/bundling-sources/shared_libs/play-runtime/memory-ledger.ts +131 -0
  54. package/dist/bundling-sources/shared_libs/play-runtime/modal-runtime-config.ts +77 -2
  55. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +271 -2
  56. package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +51 -0
  57. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/contracts.ts +2 -0
  58. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/job.ts +27 -1
  59. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-batching-registry.ts +2 -0
  60. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +3 -0
  61. package/dist/bundling-sources/shared_libs/play-runtime/provider-text-for-log.ts +63 -0
  62. package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +19 -0
  63. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-event-transport.ts +112 -16
  64. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +104 -2
  65. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +265 -151
  66. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-gateway-transport.ts +17 -0
  67. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +35 -14
  68. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-sheet-persistence-retry.ts +12 -1
  69. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-control-transport.ts +4 -0
  70. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-labels.ts +36 -0
  71. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-launch-transport.ts +136 -70
  72. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +237 -36
  73. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +148 -4
  74. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +6 -0
  75. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +285 -32
  76. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +251 -56
  77. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +29 -4
  78. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/sandbox-create-outcome.ts +27 -0
  79. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +22 -1
  80. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +1397 -382
  81. package/dist/bundling-sources/shared_libs/play-runtime/runtime-array-input-receipts.ts +920 -0
  82. package/dist/bundling-sources/shared_libs/play-runtime/runtime-constants.ts +16 -0
  83. package/dist/bundling-sources/shared_libs/play-runtime/runtime-environment.ts +38 -0
  84. package/dist/bundling-sources/shared_libs/play-runtime/runtime-flow.ts +6 -0
  85. package/dist/bundling-sources/shared_libs/play-runtime/runtime-incident-drills.ts +26 -1
  86. package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +30 -0
  87. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +14 -3
  88. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +31 -4
  89. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-transition.ts +47 -0
  90. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-compute-usage.ts +20 -7
  91. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +12 -0
  92. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/index.ts +9 -0
  93. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +10 -0
  94. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +4 -0
  95. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +1496 -320
  96. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +31 -1
  97. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +1389 -129
  98. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +36 -0
  99. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-dispatch-authority.ts +4 -0
  100. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +162 -23
  101. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts +499 -115
  102. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +377 -9
  103. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-ledger-reconciliation.ts +117 -8
  104. package/dist/bundling-sources/shared_libs/play-runtime/secret-resolution-retry-policy.ts +25 -0
  105. package/dist/bundling-sources/shared_libs/play-runtime/terminal-runtime-performance.ts +391 -0
  106. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +40 -0
  107. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +6 -0
  108. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/mapped-calls.ts +171 -0
  109. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/receipt-cohort.ts +16 -1
  110. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +26 -3
  111. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +16 -2
  112. package/dist/bundling-sources/shared_libs/play-runtime/transport-error-diagnostics.ts +28 -0
  113. package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-storage-contract.ts +55 -5
  114. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +41 -1
  115. package/dist/bundling-sources/shared_libs/plays/contracts.ts +4 -0
  116. package/dist/bundling-sources/shared_libs/plays/dataset.ts +9 -3
  117. package/dist/bundling-sources/shared_libs/plays/deploy/manifest-contract.ts +2 -0
  118. package/dist/bundling-sources/shared_libs/plays/deploy/manifest.ts +3 -2
  119. package/dist/bundling-sources/shared_libs/plays/deploy/project-serializer.ts +2 -2
  120. package/dist/bundling-sources/shared_libs/plays/run-output-summary.ts +66 -0
  121. package/dist/bundling-sources/shared_libs/plays/script-entry.ts +1 -1
  122. package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +43 -1
  123. package/dist/bundling-sources/shared_libs/product-notifications/content.ts +9 -0
  124. package/dist/bundling-sources/shared_libs/product-notifications/email.ts +91 -13
  125. package/dist/bundling-sources/shared_libs/product-notifications/events.ts +3 -0
  126. package/dist/bundling-sources/shared_libs/product-notifications/slack-delivery.ts +41 -24
  127. package/dist/bundling-sources/shared_libs/security/attested-client-ip.ts +91 -0
  128. package/dist/bundling-sources/shared_libs/security/internal-actor.ts +0 -11
  129. package/dist/cli/{auth-HKA6ZVHQ.mjs → auth-JDLEY7VU.mjs} +5 -4
  130. package/dist/cli/auth-UXKY6TCC.js +41 -0
  131. package/dist/cli/{billing-MTO2ZZ3G.js → billing-HXAXB3XZ.js} +152 -78
  132. package/dist/cli/{billing-26G44S5N.mjs → billing-SDHLBLMV.mjs} +84 -10
  133. package/dist/cli/{chunk-BHGII2D6.js → chunk-3ACMRZRV.js} +8 -6
  134. package/dist/cli/{chunk-S4Q2XCGM.mjs → chunk-3KZCFOZ6.mjs} +1 -1
  135. package/dist/cli/chunk-4KQ6SIBC.mjs +1038 -0
  136. package/dist/cli/{chunk-Z2GUFYT6.js → chunk-5LEAXRHV.js} +11 -11
  137. package/dist/cli/{chunk-XAYO3Q2X.mjs → chunk-6NNVJDVR.mjs} +7 -5
  138. package/dist/cli/{chunk-NMJ4D2WO.js → chunk-6PMCRYDA.js} +216 -91
  139. package/dist/cli/{chunk-OMM54B3X.mjs → chunk-6RNQGWFD.mjs} +16 -806
  140. package/dist/cli/{chunk-EBU7LQ64.js → chunk-6V7KVRR5.js} +3 -3
  141. package/dist/cli/{chunk-RDPTDDKX.js → chunk-7LFIMWMW.js} +2 -2
  142. package/dist/cli/chunk-7MJ6VI2T.mjs +19 -0
  143. package/dist/cli/chunk-7SWNPNML.js +1039 -0
  144. package/dist/cli/{chunk-CTRPCARW.mjs → chunk-7U3XNPOA.mjs} +267 -38
  145. package/dist/cli/{chunk-RBTTUYZZ.js → chunk-7VZHXVOQ.js} +1 -1
  146. package/dist/cli/{chunk-YVBWO647.mjs → chunk-AT636LLU.mjs} +2 -2
  147. package/dist/cli/{chunk-VTODQWQA.js → chunk-BGTPIMSM.js} +392 -261
  148. package/dist/cli/{chunk-KADIT5NV.mjs → chunk-CKSOY47X.mjs} +2 -2
  149. package/dist/cli/{chunk-7DH2FD7Y.mjs → chunk-D464JW3N.mjs} +5 -85
  150. package/dist/cli/chunk-D6DXOUTO.mjs +827 -0
  151. package/dist/cli/{describe-QW54QQNB.js → chunk-EM4TXCCI.js} +27 -44
  152. package/dist/cli/chunk-F6QV42MC.mjs +91 -0
  153. package/dist/cli/chunk-FKVYR3QA.mjs +1039 -0
  154. package/dist/cli/{chunk-LMAULZLF.js → chunk-GEGW5HPZ.js} +29 -27
  155. package/dist/cli/{chunk-M52JQSLK.js → chunk-HUB3CCM2.js} +13 -4
  156. package/dist/cli/{chunk-YHTQM5XI.js → chunk-I6VHOU5O.js} +27 -27
  157. package/dist/cli/{chunk-Z2XUZC34.js → chunk-IAYSWZDJ.js} +188 -76
  158. package/dist/cli/chunk-JF3TLIMQ.js +19 -0
  159. package/dist/cli/{chunk-HDFRJ4IT.mjs → chunk-JVHOS3K3.mjs} +177 -65
  160. package/dist/cli/{chunk-LAWEURCT.mjs → chunk-LFXLQEZN.mjs} +1 -1
  161. package/dist/cli/{chunk-2PBN4SZE.js → chunk-LROWFPGN.js} +16 -16
  162. package/dist/cli/{chunk-SLEUWLJE.mjs → chunk-MSY22NQW.mjs} +5 -5
  163. package/dist/cli/{chunk-LVJOFUU7.mjs → chunk-MUUQZIOF.mjs} +23 -49
  164. package/dist/cli/{chunk-2XHWOQF4.js → chunk-NBLSCHKK.js} +52 -50
  165. package/dist/cli/{chunk-526R2HON.mjs → chunk-NHRWZPWZ.mjs} +4 -2
  166. package/dist/cli/{chunk-KXMNM4AQ.js → chunk-NMU3VR5U.js} +4 -5
  167. package/dist/cli/{chunk-W3BE3CHK.mjs → chunk-O2RX5A66.mjs} +14 -12
  168. package/dist/cli/{chunk-UKFZT7RF.js → chunk-OMQ23IXL.js} +2 -2
  169. package/dist/cli/{chunk-LJTFZOHU.js → chunk-OPJAJBD4.js} +28 -54
  170. package/dist/cli/{chunk-MLFR6DVF.mjs → chunk-PHSEINNH.mjs} +5 -5
  171. package/dist/cli/{chunk-3DNKFH2G.mjs → chunk-PKHVSIJG.mjs} +19 -1
  172. package/dist/cli/{chunk-WIYWSYDS.mjs → chunk-Q2EIZKVX.mjs} +3 -3
  173. package/dist/cli/{chunk-VJAEA4CS.js → chunk-QJZ6WNWD.js} +8 -8
  174. package/dist/cli/{chunk-EIMG75BT.mjs → chunk-S3A4IXBQ.mjs} +4 -5
  175. package/dist/cli/{chunk-RZSTT45F.mjs → chunk-S42YIQNE.mjs} +13 -8
  176. package/dist/cli/{chunk-YULBYKAK.mjs → chunk-S6UAJR6V.mjs} +3 -3
  177. package/dist/cli/{chunk-G7L27KZB.mjs → chunk-TKAQR3IB.mjs} +31 -21
  178. package/dist/cli/{chunk-QWRHGGUH.js → chunk-UAJFWWZE.js} +20 -2
  179. package/dist/cli/{chunk-ZR2RLI4O.mjs → chunk-UDRPEZ5F.mjs} +223 -92
  180. package/dist/cli/{chunk-QGAWTBIR.js → chunk-ULK7JGGI.js} +511 -282
  181. package/dist/cli/chunk-V335HGX5.js +1038 -0
  182. package/dist/cli/{chunk-NH6JSJW6.mjs → chunk-V3MEA7NB.mjs} +7 -5
  183. package/dist/cli/{chunk-NRGGFVVB.js → chunk-VFGVXXZP.js} +37 -35
  184. package/dist/cli/chunk-VLEVVDWG.js +91 -0
  185. package/dist/cli/{chunk-R2GLGLDR.mjs → chunk-VPHN2HAL.mjs} +216 -91
  186. package/dist/cli/{chunk-CFUTOWE4.js → chunk-WG3KGAII.js} +8 -88
  187. package/dist/cli/{describe-TOMIAT37.mjs → chunk-WIY6U6GD.mjs} +19 -36
  188. package/dist/cli/{chunk-YS2YBSJB.js → chunk-XANRM3QA.js} +6 -6
  189. package/dist/cli/{chunk-KGQNIA37.js → chunk-XQCTG5OO.js} +44 -34
  190. package/dist/cli/{chunk-EJGBLXDZ.mjs → chunk-XZAFIOUQ.mjs} +1 -1
  191. package/dist/cli/chunk-Y4DPU4OM.js +827 -0
  192. package/dist/cli/chunk-YT5EODJO.js +920 -0
  193. package/dist/cli/{chunk-2WRO2UJ5.js → chunk-ZGQSFYD2.js} +56 -51
  194. package/dist/cli/{chunk-OJ6RUKVT.mjs → chunk-ZUK6LIJB.mjs} +10 -1
  195. package/dist/cli/command-docs.d.mts +5 -0
  196. package/dist/cli/command-docs.d.ts +5 -0
  197. package/dist/cli/command-docs.js +2 -2
  198. package/dist/cli/command-docs.mjs +1 -1
  199. package/dist/cli/{csv-6FNFYJUC.js → csv-C56GSCEU.js} +13 -12
  200. package/dist/cli/{csv-MDHT4BKK.mjs → csv-L54JS7TF.mjs} +4 -3
  201. package/dist/cli/{db-D6AMVOEW.js → db-MOGRMZTA.js} +30 -27
  202. package/dist/cli/{db-74O3RFWY.mjs → db-YVBUW2DX.mjs} +10 -7
  203. package/dist/cli/describe-KYEULWPG.js +48 -0
  204. package/dist/cli/describe-NLZKKT7C.mjs +48 -0
  205. package/dist/cli/describe-core.d.mts +153 -5
  206. package/dist/cli/describe-core.d.ts +153 -5
  207. package/dist/cli/describe-core.js +9 -5
  208. package/dist/cli/describe-core.mjs +10 -6
  209. package/dist/cli/{executions-N4FMGVSC.js → executions-A7L4ULPP.js} +9 -7
  210. package/dist/cli/{executions-PVSF4HUF.mjs → executions-ZBGSTT37.mjs} +7 -5
  211. package/dist/cli/{feedback-OB7NANZW.mjs → feedback-G6GU37FD.mjs} +6 -5
  212. package/dist/cli/{feedback-WFSPCAI2.js → feedback-OHLY7RYD.js} +10 -9
  213. package/dist/cli/getting-started.d.mts +6 -6
  214. package/dist/cli/getting-started.d.ts +6 -6
  215. package/dist/cli/getting-started.js +2 -2
  216. package/dist/cli/getting-started.mjs +1 -1
  217. package/dist/cli/git-P76N4NDQ.js +25 -0
  218. package/dist/cli/{git-FHUSPAEU.mjs → git-PKZW3QD5.mjs} +5 -4
  219. package/dist/cli/index.js +152 -142
  220. package/dist/cli/index.mjs +56 -46
  221. package/dist/cli/{legacy-noops-ECHNA5HN.js → legacy-noops-5LM3D724.js} +8 -7
  222. package/dist/cli/{legacy-noops-HMK4BSCI.mjs → legacy-noops-LJJYG6YA.mjs} +5 -4
  223. package/dist/cli/{monitors-U7VQ3EZM.mjs → monitors-72QV4ALO.mjs} +19 -6
  224. package/dist/cli/{monitors-XLLFNENH.js → monitors-UX3H5DC2.js} +103 -90
  225. package/dist/cli/{org-6H3USO5M.mjs → org-6RRRKOCP.mjs} +9 -6
  226. package/dist/cli/{org-QX6ER2HN.js → org-IF7ISUVB.js} +70 -67
  227. package/dist/cli/pages-3SU3HKL7.js +252 -0
  228. package/dist/cli/pages-DXDYYKEK.mjs +252 -0
  229. package/dist/cli/{play-MOB2WYOR.mjs → play-AHASKRLA.mjs} +512 -1508
  230. package/dist/cli/{play-WNB7HBZK.js → play-EUIUVLUH.js} +1090 -2086
  231. package/dist/cli/{providers-CXEZ23E2.mjs → providers-GWGE3WY3.mjs} +7 -5
  232. package/dist/cli/{providers-7M3DISKX.js → providers-V5WU4VXJ.js} +10 -8
  233. package/dist/cli/{quickstart-ZFCHKHF6.mjs → quickstart-OXKQ5ZST.mjs} +5 -4
  234. package/dist/cli/{quickstart-CLJT4AZL.js → quickstart-QP65I5PF.js} +13 -12
  235. package/dist/cli/run-6MM72IGL.mjs +443 -0
  236. package/dist/cli/run-F3FTYS56.js +443 -0
  237. package/dist/cli/search-OYKOOI7A.js +32 -0
  238. package/dist/cli/{search-FVYWYIC3.mjs → search-ZMEBVJZB.mjs} +8 -6
  239. package/dist/cli/{secrets-YRLKZQS5.js → secrets-ACND5N6A.js} +16 -14
  240. package/dist/cli/{secrets-WAMPTQFC.mjs → secrets-XRCJFF3L.mjs} +7 -5
  241. package/dist/cli/{sessions-IQ332BJH.mjs → sessions-RTK3CEW6.mjs} +5 -4
  242. package/dist/cli/{sessions-44J6WIVU.js → sessions-ZGRJPCFF.js} +6 -5
  243. package/dist/cli/{settings-4IJR2I2T.js → settings-PD5KWQQZ.js} +80 -77
  244. package/dist/cli/{settings-22S6NIFQ.mjs → settings-XDRBPRDE.mjs} +14 -11
  245. package/dist/cli/{setup-OZUPKKPW.mjs → setup-3HPYAOCC.mjs} +12 -10
  246. package/dist/cli/{setup-3FWSRNOX.js → setup-E2Q6PXHC.js} +53 -51
  247. package/dist/cli/{skills-5CW3NFP3.mjs → skills-OOQFMPOV.mjs} +7 -6
  248. package/dist/cli/skills-XYWV52KB.js +31 -0
  249. package/dist/cli/tools-ASCDZJCK.js +55 -0
  250. package/dist/cli/tools-C5ZT3UIC.mjs +55 -0
  251. package/dist/cli/update-5RQSEIFM.js +33 -0
  252. package/dist/cli/{update-IBULOV7P.mjs → update-ZWJTADIW.mjs} +9 -8
  253. package/dist/cli/{workflow-MVZT7MWT.mjs → workflow-23NMPAJ7.mjs} +10 -8
  254. package/dist/cli/{workflow-Z7FW6GT2.js → workflow-TCXU5YJV.js} +20 -18
  255. package/dist/client-DS2IWYZF.d.ts +10 -0
  256. package/dist/client-DTwnz_AW.d.mts +10 -0
  257. package/dist/{client-CYqG23K1.d.ts → client-core-B_6HAIBy.d.ts} +385 -12
  258. package/dist/{client-BbU5_j7n.d.mts → client-core-DzBSlY1U.d.mts} +385 -12
  259. package/dist/{compiler-manifest-CWz_sNOQ.d.mts → compiler-manifest-Dcyd3-Zd.d.mts} +43 -1
  260. package/dist/{compiler-manifest-CWz_sNOQ.d.ts → compiler-manifest-Dcyd3-Zd.d.ts} +43 -1
  261. package/dist/errors-d-sTrZhe.d.mts +142 -0
  262. package/dist/errors-yQwfgrcX.d.ts +142 -0
  263. package/dist/{index-BF2JB_Ug.d.mts → index-C6oXchjN.d.mts} +1 -1
  264. package/dist/{index-4NPXDzlD.d.ts → index-P56zy_z5.d.ts} +1 -1
  265. package/dist/index.d.mts +11 -147
  266. package/dist/index.d.ts +11 -147
  267. package/dist/index.js +15 -11
  268. package/dist/index.mjs +14 -10
  269. package/dist/install-integrity.json +141 -104
  270. package/dist/plays/bundle-play-file.d.mts +3 -3
  271. package/dist/plays/bundle-play-file.d.ts +3 -3
  272. package/dist/plays/bundle-play-file.mjs +2 -1
  273. package/dist/plays/play-description.d.mts +2 -2
  274. package/dist/plays/play-description.d.ts +2 -2
  275. package/dist/plays/play-description.js +2 -2
  276. package/dist/plays/play-description.mjs +1 -1
  277. package/dist/plays/run-request.d.mts +2 -2
  278. package/dist/plays/run-request.d.ts +2 -2
  279. package/dist/release.d.mts +1 -1
  280. package/dist/release.d.ts +1 -1
  281. package/dist/release.js +2 -2
  282. package/dist/release.mjs +1 -1
  283. package/dist/server.d.mts +17 -0
  284. package/dist/server.d.ts +17 -0
  285. package/dist/server.js +76 -0
  286. package/dist/server.mjs +76 -0
  287. package/package.json +6 -1
  288. package/dist/cli/auth-VDOCNR7H.js +0 -40
  289. package/dist/cli/chunk-PQUUWFXY.js +0 -95
  290. package/dist/cli/chunk-QJLKYYPX.js +0 -1710
  291. package/dist/cli/chunk-YBWAG72P.mjs +0 -95
  292. package/dist/cli/git-4PMBJSH5.js +0 -24
  293. package/dist/cli/search-4CCQCTVD.js +0 -30
  294. package/dist/cli/skills-LMNM6B5F.js +0 -30
  295. package/dist/cli/tools-AGBBDJ7P.js +0 -45
  296. package/dist/cli/tools-NOPBDRGW.mjs +0 -45
  297. package/dist/cli/update-U3W6USVD.js +0 -32
@@ -7,6 +7,7 @@ import {
7
7
  } from '../types';
8
8
  import { buildPlayRunnerBundle } from '../bundle';
9
9
  import { findPlayRunnerResult, parsePlayRunnerEvents } from '../runner-events';
10
+ import { logSandboxCreateOutcome } from '../sandbox-create-outcome';
10
11
  import type {
11
12
  PlayRunnerExecutionConfig,
12
13
  PlayRunnerResult,
@@ -21,6 +22,7 @@ import {
21
22
  MODAL_SANDBOX_MEMORY_MIB,
22
23
  loadModalClientConfig,
23
24
  loadModalRequiredConfig,
25
+ withModalCallSignal,
24
26
  } from '../../modal-runtime-config';
25
27
  import type { PlaySandboxRuntimeLimits } from '../../../plays/sandbox-runtime-limits';
26
28
  import { validateDaytonaExecutionContext } from './daytona-lifecycle';
@@ -33,6 +35,7 @@ import {
33
35
  isPlayRunRecoveryError,
34
36
  recoveryForOpenModalCircuit,
35
37
  recoveryForModalSandboxCreateFailure,
38
+ recoveryForRunnerStartupNotLive,
36
39
  } from '../../play-run-recovery-policy';
37
40
  import { shouldInjectModalSandboxCreateResourceExhausted } from '../../test-runtime-seams';
38
41
  import { RUNTIME_RELIABILITY_POLICY } from '../../runtime-reliability-policy';
@@ -44,8 +47,19 @@ const MODAL_SANDBOX_CREATE_TIMEOUT_MS =
44
47
  const MODAL_PAYLOAD_UPLOAD_TIMEOUT_MS = 90_000;
45
48
  const MODAL_TERMINATION_TIMEOUT_MS = 10_000;
46
49
  const MODAL_DETACHED_INSPECTION_TIMEOUT_MS = 10_000;
50
+ /** Completion-marker reads still out, after their deadline or not. */
51
+ export const MODAL_RUNTIME_COMPLETION_READS_MAX = 8;
52
+ let modalRuntimeCompletionReadsOutstanding = 0;
53
+ /**
54
+ * A state-only read serves the fixed controller's liveness sweep, so it ends
55
+ * well inside that sweep's 10-second pass. The deadline cancels the call, so
56
+ * a provider that never answers leaves no abandoned read holding a slot.
57
+ */
58
+ export const MODAL_SANDBOX_STATE_READ_TIMEOUT_MS = 5_000;
47
59
  const MODAL_CAPACITY_RELEASE_RETRY_DELAYS_MS = [0, 100, 500, 2_000] as const;
48
60
  const MODAL_LATE_CREATE_PERSIST_RETRY_DELAYS_MS = [0, 100, 500, 2_000] as const;
61
+ // The SDK does not export gRPC status codes.
62
+ const MODAL_GRPC_STATUS_NOT_FOUND = 5;
49
63
  type ModalSandbox = Awaited<ReturnType<ModalClient['sandboxes']['create']>>;
50
64
 
51
65
  class ModalPayloadUploadTimeoutError extends Error {
@@ -57,6 +71,18 @@ class ModalPayloadUploadTimeoutError extends Error {
57
71
  }
58
72
  }
59
73
 
74
+ /**
75
+ * A file did not reach the sandbox because Modal reports the sandbox
76
+ * unavailable, which another sandbox can outrun. Staging sends no command, so
77
+ * nothing could run. By name, as `isModalSandboxNotFoundError` reads the SDK's
78
+ * errors. Other write errors stay loud: the SDK folds a refused credential into
79
+ * the same `SandboxFilesystemError` as a provider fault, and a stalled upload
80
+ * may be input too large for any sandbox.
81
+ */
82
+ function isUndeliveredModalRunnerFailure(error: unknown): boolean {
83
+ return error instanceof Error && error.name === 'NotFoundError';
84
+ }
85
+
60
86
  async function writeModalFileWithDeadline(input: {
61
87
  sandbox: ModalSandbox;
62
88
  content: Buffer;
@@ -205,13 +231,15 @@ function emitModalStage(
205
231
  );
206
232
  }
207
233
 
208
- async function confirmDetachedModalRunnerReady(input: {
234
+ export async function confirmDetachedModalRunnerReady(input: {
209
235
  readiness: NonNullable<PlayRunnerCallbacks['readDetachedRunnerReadiness']>;
210
236
  baselineHeartbeatAt: string | null;
211
237
  cancellation?: Promise<never>;
238
+ timeoutMs?: number;
212
239
  }): Promise<void> {
213
240
  const cancellation = input.cancellation ?? new Promise<never>(() => {});
214
- const deadline = Date.now() + MODAL_RUNNER_READY_TIMEOUT_MS;
241
+ const timeoutMs = input.timeoutMs ?? MODAL_RUNNER_READY_TIMEOUT_MS;
242
+ const deadline = Date.now() + timeoutMs;
215
243
  let delayMs = 50;
216
244
  while (Date.now() < deadline) {
217
245
  const response = await Promise.race([
@@ -225,8 +253,10 @@ async function confirmDetachedModalRunnerReady(input: {
225
253
  ]);
226
254
  delayMs = Math.min(1_000, delayMs * 2);
227
255
  }
228
- throw new Error(
229
- `RUNTIME_SANDBOX_START_FAILED: Modal accepted the runner command, but the scheduler did not observe play-runner liveness within ${MODAL_RUNNER_READY_TIMEOUT_MS}ms. Customer play execution was not parked.`,
256
+ throw recoveryForRunnerStartupNotLive(
257
+ new Error(
258
+ `RUNTIME_SANDBOX_START_FAILED: Modal accepted the runner command, but the scheduler did not observe play-runner liveness within ${timeoutMs}ms. Customer play execution was not parked.`,
259
+ ),
230
260
  );
231
261
  }
232
262
 
@@ -355,6 +385,7 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
355
385
  attempt: String(config.context.runAttempt ?? 0),
356
386
  };
357
387
  let sandbox: ModalSandbox;
388
+ let createSent = false;
358
389
  try {
359
390
  // This is deliberately adjacent to the real provider boundary. The
360
391
  // reservation proves the scheduler observes the same no-resource
@@ -394,6 +425,7 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
394
425
  ? { sandboxCapacityLeaseId: capacityReservation.leaseId }
395
426
  : {}),
396
427
  });
428
+ createSent = true;
397
429
  sandbox = await awaitModalSandboxCreate({
398
430
  create: modalConfig.client.sandboxes.create(app, image, {
399
431
  cpu: MODAL_SANDBOX_CPU_CORES,
@@ -409,6 +441,12 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
409
441
  : {}),
410
442
  }),
411
443
  onLateSuccess: async (lateSandbox) => {
444
+ logSandboxCreateOutcome({
445
+ provider: 'modal',
446
+ outcome: 'succeeded',
447
+ runId: config.context.runId,
448
+ reason: 'late',
449
+ });
412
450
  // Do not directly delete a late sandbox. First store it as a
413
451
  // durable cleanup obligation, then let the normal cleanup worker
414
452
  // perform provider-confirmed deletion, capacity release, and
@@ -467,7 +505,25 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
467
505
  await callbacks?.onAmbiguousModalCreateResolved?.();
468
506
  },
469
507
  });
508
+ logSandboxCreateOutcome({
509
+ provider: 'modal',
510
+ outcome: 'succeeded',
511
+ runId: config.context.runId,
512
+ });
470
513
  } catch (error) {
514
+ if (createSent) {
515
+ logSandboxCreateOutcome({
516
+ provider: 'modal',
517
+ outcome:
518
+ error instanceof ModalSandboxCreateOutcomeUnknownError
519
+ ? 'unknown'
520
+ : 'failed',
521
+ runId: config.context.runId,
522
+ reason:
523
+ recoveryForModalSandboxCreateFailure(error)?.decision.reason ??
524
+ null,
525
+ });
526
+ }
471
527
  if (
472
528
  capacityReservation &&
473
529
  !(error instanceof ModalSandboxCreateOutcomeUnknownError)
@@ -604,7 +660,17 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
604
660
  emitModalStage(config.context, stage, extra),
605
661
  }),
606
662
  cancellationPromise,
607
- ]);
663
+ ]).catch((error: unknown) => {
664
+ // The runner never reached this sandbox. `finally` terminates it,
665
+ // and the defer starts a new attempt on a new sandbox.
666
+ if (
667
+ !callbacks?.cancellationSignal?.aborted &&
668
+ isUndeliveredModalRunnerFailure(error)
669
+ ) {
670
+ throw recoveryForRunnerStartupNotLive(error);
671
+ }
672
+ throw error;
673
+ });
608
674
  runtimeTiming.modalUploadMs = Date.now() - uploadStartedAt;
609
675
  const baselineHeartbeatAt = await Promise.race([
610
676
  captureDetachedDaytonaRunnerReadinessBaseline({
@@ -628,10 +694,10 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
628
694
  provider: 'modal',
629
695
  sandboxId: sandbox.sandboxId,
630
696
  });
631
- // A readiness observation after the command is accepted is ambiguous:
632
- // the detached runner may already have received its durable park and
633
- // started customer code while this worker cannot read the scheduler.
634
- // Never translate that ambiguity into a fresh sandbox retry.
697
+ // The runner holds customer code until this worker parks the attempt,
698
+ // and that park comes after this check. A runner that never reports
699
+ // live therefore never released anything, and the scheduler's defer
700
+ // starts a new attempt whose fence rejects it.
635
701
  await confirmDetachedModalRunnerReady({
636
702
  readiness: readRunnerReadiness,
637
703
  baselineHeartbeatAt,
@@ -746,6 +812,46 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
746
812
  },
747
813
  };
748
814
 
815
+ /**
816
+ * `poll()` and `terminate()` pass Modal's gRPC failure through unchanged, so
817
+ * Modal not knowing an exact sandbox id arrives as a gRPC NOT_FOUND. The SDK's
818
+ * `NotFoundError` is what its other lookups raise for the same fact.
819
+ *
820
+ * Use this only on those calls. `sandbox.filesystem` also raises
821
+ * `NotFoundError` for transient failures such as UNAVAILABLE, so a failed file
822
+ * read proves nothing about the sandbox.
823
+ */
824
+ function isModalSandboxNotFoundError(error: unknown): boolean {
825
+ if (!(error instanceof Error)) return false;
826
+ if (error.name === 'NotFoundError') return true;
827
+ return (
828
+ error.name === 'ClientError' &&
829
+ (error as { code?: unknown }).code === MODAL_GRPC_STATUS_NOT_FOUND
830
+ );
831
+ }
832
+
833
+ /**
834
+ * What Modal says about one sandbox. A failed read throws: it is not a state,
835
+ * and a stale runner must stay unproven rather than be called lost.
836
+ */
837
+ async function readModalSandboxState(
838
+ sandbox: ModalSandbox,
839
+ ): Promise<
840
+ | { kind: 'running' }
841
+ | { kind: 'stopped'; returnCode: number }
842
+ | { kind: 'missing' }
843
+ > {
844
+ try {
845
+ const returnCode = await sandbox.poll();
846
+ return returnCode === null
847
+ ? { kind: 'running' }
848
+ : { kind: 'stopped', returnCode };
849
+ } catch (error) {
850
+ if (isModalSandboxNotFoundError(error)) return { kind: 'missing' };
851
+ throw error;
852
+ }
853
+ }
854
+
749
855
  export async function deleteModalSandboxById(input: {
750
856
  sandboxId: string;
751
857
  expectedAppId?: string | null;
@@ -768,17 +874,19 @@ export async function deleteModalSandboxById(input: {
768
874
  }
769
875
  try {
770
876
  const { client } = await loadModalClientConfig();
771
- for await (const sandbox of client.sandboxes.list({
772
- appId: expectedAppId,
773
- })) {
774
- if (sandbox.sandboxId !== input.sandboxId) continue;
775
- await sandbox.terminate({ wait: true });
776
- return { kind: 'deleted', appId: expectedAppId };
777
- }
778
- // Cleanup means ensure absent. An exact app-scoped inventory proving the
779
- // id is absent satisfies the obligation without an unsafe cross-app get.
780
- return { kind: 'already_absent', appId: expectedAppId };
877
+ // Never walk the app here: each walk spends Modal's LIST limit, and on
878
+ // Oct 29 that throttled deletes while finished sandboxes kept billing.
879
+ // `fromId` makes no call. Modal has no public read of a sandbox's app, so
880
+ // the exact id persisted at create is the authority and `terminate` is
881
+ // the first thing to learn whether it still exists.
882
+ const sandbox = await client.sandboxes.fromId(input.sandboxId);
883
+ await sandbox.terminate({ wait: true });
884
+ return { kind: 'deleted', appId: expectedAppId };
781
885
  } catch (error) {
886
+ // Cleanup means ensure absent, and this answer is about this exact id.
887
+ if (isModalSandboxNotFoundError(error)) {
888
+ return { kind: 'already_absent', appId: expectedAppId };
889
+ }
782
890
  console.warn('[play-runner.modal.reclaim_sandbox_delete_failed]', {
783
891
  sandboxId: input.sandboxId,
784
892
  expectedAppId,
@@ -797,6 +905,8 @@ export async function deleteModalSandboxById(input: {
797
905
  * Read the provider inventory using the exact app + tag selector persisted
798
906
  * before a Modal create call. This is deliberately a tiny provider adapter:
799
907
  * the scheduler owns claim/fencing, resource recording, cleanup, and policy.
908
+ * A list is required here: a create with an unknown outcome has no sandbox id
909
+ * to read, and these tags name one attempt, so this does not walk the app.
800
910
  */
801
911
  export async function findModalSandboxIdsByTags(input: {
802
912
  modalAppId: string;
@@ -827,14 +937,16 @@ export async function findModalSandboxIdsByTags(input: {
827
937
 
828
938
  /**
829
939
  * Best-effort terminal recovery for an already-detached Modal runner. This
830
- * reads only the payload wrapper's captured files; it never executes Play
831
- * code or launches a replacement sandbox.
940
+ * reads the sandbox's state and the payload wrapper's captured files; it never
941
+ * executes Play code or launches a replacement sandbox.
832
942
  */
833
943
  export async function inspectDetachedModalRunner(input: {
834
944
  sandboxId: string;
835
945
  outputPath: string;
836
946
  exitCodePath: string;
837
947
  expectedAppId?: string | null;
948
+ /** Answer from the sandbox's state alone. See the reconciliation seam. */
949
+ skipCapturedOutput?: boolean;
838
950
  }): Promise<{
839
951
  exitCode: number | null;
840
952
  result: PlayRunnerResult | null;
@@ -852,15 +964,59 @@ export async function inspectDetachedModalRunner(input: {
852
964
  };
853
965
  }
854
966
 
855
- let timer: ReturnType<typeof setTimeout> | undefined;
967
+ const timeoutMs = input.skipCapturedOutput
968
+ ? MODAL_SANDBOX_STATE_READ_TIMEOUT_MS
969
+ : MODAL_DETACHED_INSPECTION_TIMEOUT_MS;
970
+ // The deadline cancels Modal's calls as well as the wait, so a read that
971
+ // times out is over and a stuck provider cannot pile reads up behind it.
972
+ const deadline = new AbortController();
973
+ const timer = setTimeout(() => {
974
+ deadline.abort(
975
+ new Error(
976
+ `Modal detached-runner inspection exceeded ${timeoutMs}ms.`,
977
+ ),
978
+ );
979
+ }, timeoutMs);
856
980
  try {
857
981
  return await Promise.race([
858
- (async () => {
982
+ withModalCallSignal(deadline.signal, async () => {
859
983
  const { client } = await loadModalClientConfig();
860
- for await (const sandbox of client.sandboxes.list({
861
- appId: expectedAppId,
862
- })) {
863
- if (sandbox.sandboxId !== input.sandboxId) continue;
984
+ const sandbox = await client.sandboxes.fromId(input.sandboxId);
985
+ try {
986
+ // Proof of loss is a read of this one sandbox. The app list holds
987
+ // only running sandboxes and is rate limited, so absence from it
988
+ // proves nothing.
989
+ const state = await readModalSandboxState(sandbox);
990
+ if (state.kind === 'missing') {
991
+ return {
992
+ exitCode: null,
993
+ result: null,
994
+ diagnosis: {
995
+ stage: 'sandbox_missing',
996
+ detail: 'Modal has no sandbox with this id.',
997
+ },
998
+ };
999
+ }
1000
+ if (state.kind === 'stopped') {
1001
+ // Files cannot be read from a stopped sandbox. The return code is
1002
+ // the sandbox's own, not the runner's, and 137 covers both a spend
1003
+ // limit kill and a terminate, so it stays out of `exitCode`.
1004
+ return {
1005
+ exitCode: null,
1006
+ result: null,
1007
+ diagnosis: {
1008
+ stage: 'sandbox_stopped',
1009
+ detail: `Modal sandbox ended with return code ${state.returnCode}.`,
1010
+ },
1011
+ };
1012
+ }
1013
+ if (input.skipCapturedOutput) {
1014
+ return {
1015
+ exitCode: null,
1016
+ result: null,
1017
+ diagnosis: { stage: 'sandbox_not_ended', detail: null },
1018
+ };
1019
+ }
864
1020
  const [output, exitCode] = await Promise.allSettled([
865
1021
  sandbox.filesystem.readText(input.outputPath),
866
1022
  sandbox.filesystem.readText(input.exitCodePath),
@@ -892,24 +1048,18 @@ export async function inspectDetachedModalRunner(input: {
892
1048
  ? { stage: 'salvaged', detail: null }
893
1049
  : { stage: 'result_missing', detail: null },
894
1050
  };
1051
+ } finally {
1052
+ sandbox.detach();
895
1053
  }
896
- return {
897
- exitCode: null,
898
- result: null,
899
- diagnosis: {
900
- stage: 'sandbox_missing',
901
- detail: 'Sandbox was not found in the launch-pinned Modal app.',
902
- },
903
- };
904
- })(),
1054
+ }),
1055
+ // An auth token refresh is shared and keeps running, so do not wait on
1056
+ // whatever the abort could not cancel.
905
1057
  new Promise<never>((_resolve, reject) => {
906
- timer = setTimeout(() => {
907
- reject(
908
- new Error(
909
- `Modal detached-runner inspection exceeded ${MODAL_DETACHED_INSPECTION_TIMEOUT_MS}ms.`,
910
- ),
911
- );
912
- }, MODAL_DETACHED_INSPECTION_TIMEOUT_MS);
1058
+ deadline.signal.addEventListener(
1059
+ 'abort',
1060
+ () => reject(deadline.signal.reason),
1061
+ { once: true },
1062
+ );
913
1063
  }),
914
1064
  ]);
915
1065
  } catch (error) {
@@ -927,7 +1077,7 @@ export async function inspectDetachedModalRunner(input: {
927
1077
  },
928
1078
  };
929
1079
  } finally {
930
- if (timer) clearTimeout(timer);
1080
+ clearTimeout(timer);
931
1081
  }
932
1082
  }
933
1083
 
@@ -938,20 +1088,63 @@ export async function readDetachedModalRuntimeCompletion(input: {
938
1088
  }): Promise<number | null> {
939
1089
  const expectedAppId = input.expectedAppId?.trim() || null;
940
1090
  if (!expectedAppId) return null;
1091
+ // A read past its deadline keeps running, so a Modal that never answers
1092
+ // would otherwise gather one per settlement. The marker is only telemetry.
1093
+ if (
1094
+ modalRuntimeCompletionReadsOutstanding >= MODAL_RUNTIME_COMPLETION_READS_MAX
1095
+ ) {
1096
+ console.warn('[play-runner.modal.runtime_completion_marker_unavailable]', {
1097
+ sandboxId: input.sandboxId,
1098
+ expectedAppId,
1099
+ error: `${modalRuntimeCompletionReadsOutstanding} earlier reads have not answered.`,
1100
+ });
1101
+ return null;
1102
+ }
1103
+ modalRuntimeCompletionReadsOutstanding += 1;
1104
+ const read = readModalRuntimeCompletionMarker(input, expectedAppId).finally(
1105
+ () => {
1106
+ modalRuntimeCompletionReadsOutstanding -= 1;
1107
+ },
1108
+ );
1109
+ // Terminal settlement awaits this read. Modal's calls have no RPC deadline
1110
+ // and retry throttling without limit, so settle without the marker rather
1111
+ // than leave a finished run `running`. The read cannot be cancelled.
1112
+ let timer: ReturnType<typeof setTimeout> | undefined;
1113
+ return await Promise.race([
1114
+ read,
1115
+ new Promise<null>((resolve) => {
1116
+ timer = setTimeout(() => {
1117
+ console.warn(
1118
+ '[play-runner.modal.runtime_completion_marker_unavailable]',
1119
+ {
1120
+ sandboxId: input.sandboxId,
1121
+ expectedAppId,
1122
+ error: `No answer within ${MODAL_DETACHED_INSPECTION_TIMEOUT_MS}ms.`,
1123
+ },
1124
+ );
1125
+ resolve(null);
1126
+ }, MODAL_DETACHED_INSPECTION_TIMEOUT_MS);
1127
+ }),
1128
+ ]).finally(() => clearTimeout(timer));
1129
+ }
1130
+
1131
+ async function readModalRuntimeCompletionMarker(
1132
+ input: { sandboxId: string; runtimeCompletedPath: string },
1133
+ expectedAppId: string,
1134
+ ): Promise<number | null> {
1135
+ let sandbox: ModalSandbox | undefined;
941
1136
  try {
942
1137
  const { client } = await loadModalClientConfig();
943
- for await (const sandbox of client.sandboxes.list({
944
- appId: expectedAppId,
945
- })) {
946
- if (sandbox.sandboxId !== input.sandboxId) continue;
947
- const marker = JSON.parse(
948
- await sandbox.filesystem.readText(input.runtimeCompletedPath),
949
- ) as { at?: unknown };
950
- return typeof marker.at === 'number' && Number.isFinite(marker.at)
951
- ? marker.at
952
- : null;
953
- }
954
- return null;
1138
+ sandbox = await client.sandboxes.fromId(input.sandboxId);
1139
+ // The marker went with a stopped sandbox. Check first: a file read of a
1140
+ // sandbox with no task yet can wait minutes inside the SDK.
1141
+ if ((await readModalSandboxState(sandbox)).kind !== 'running') return null;
1142
+ const marker = JSON.parse(
1143
+ await sandbox.filesystem.readText(input.runtimeCompletedPath),
1144
+ ) as { at?: unknown };
1145
+ return typeof marker.at === 'number' && Number.isFinite(marker.at)
1146
+ ? marker.at
1147
+ : null;
955
1148
  } catch (error) {
956
1149
  console.warn('[play-runner.modal.runtime_completion_marker_unavailable]', {
957
1150
  sandboxId: input.sandboxId,
@@ -959,5 +1152,7 @@ export async function readDetachedModalRuntimeCompletion(input: {
959
1152
  error: error instanceof Error ? error.message : String(error),
960
1153
  });
961
1154
  return null;
1155
+ } finally {
1156
+ sandbox?.detach();
962
1157
  }
963
1158
  }
@@ -32,6 +32,7 @@ export type RuntimeSandboxReconciliationAdapter = {
32
32
  inspectDetachedRunner(
33
33
  ref: RuntimeSandboxRef,
34
34
  suspension: DetachedRunnerSuspension,
35
+ options?: RuntimeSandboxDetachedInspectionOptions,
35
36
  ): Promise<RuntimeSandboxDetachedRunnerInspection | null>;
36
37
  readWorkCompletedAt(
37
38
  ref: RuntimeSandboxRef,
@@ -44,6 +45,7 @@ export type RuntimeSandboxReconciliation = {
44
45
  inspectDetachedRunner(
45
46
  ref: RuntimeSandboxRef,
46
47
  suspension: DetachedRunnerSuspension,
48
+ options?: RuntimeSandboxDetachedInspectionOptions,
47
49
  ): Promise<RuntimeSandboxDetachedRunnerInspection | null>;
48
50
  readWorkCompletedAt(
49
51
  ref: RuntimeSandboxRef,
@@ -57,11 +59,28 @@ export type RuntimeSandboxDetachedRunnerInspection = {
57
59
  diagnosis: { stage: string; detail: string | null };
58
60
  };
59
61
 
62
+ export type RuntimeSandboxDetachedInspectionOptions = {
63
+ /**
64
+ * Prove only whether the sandbox itself has ended. A runner's captured output
65
+ * grows with customer logs, so a small fixed controller must never load it,
66
+ * and an ended sandbox has no files left to read. A sandbox that has not
67
+ * ended stays unproven here, and its parked attempt can still salvage it.
68
+ */
69
+ skipCapturedOutput?: boolean;
70
+ };
71
+
60
72
  export type RuntimeSandboxDeleteOutcome =
61
73
  | {
62
74
  kind: 'deleted' | 'already_absent';
63
75
  routingDomain: string | null;
64
76
  }
77
+ | {
78
+ kind: 'delete_pending';
79
+ routingDomain: string | null;
80
+ code: string;
81
+ detail: string;
82
+ deleteAccepted: boolean;
83
+ }
65
84
  | {
66
85
  kind: 'timed_out' | 'rate_limited' | 'failed';
67
86
  routingDomain: string | null;
@@ -116,8 +135,8 @@ export function createRuntimeSandboxReconciliation(input: {
116
135
  };
117
136
  return {
118
137
  delete: (ref) => resolve(ref).delete(ref),
119
- inspectDetachedRunner: (ref, suspension) =>
120
- resolve(ref).inspectDetachedRunner(ref, suspension),
138
+ inspectDetachedRunner: (ref, suspension, ...options) =>
139
+ resolve(ref).inspectDetachedRunner(ref, suspension, ...options),
121
140
  readWorkCompletedAt: (ref, path) =>
122
141
  resolve(ref).readWorkCompletedAt(ref, path),
123
142
  };
@@ -205,7 +224,7 @@ export const defaultRuntimeSandboxReconciliation =
205
224
  routingDomain: outcome.organizationId,
206
225
  };
207
226
  },
208
- inspectDetachedRunner: (ref, suspension) =>
227
+ inspectDetachedRunner: (ref, suspension, options) =>
209
228
  inspectDetachedDaytonaRunner({
210
229
  sandboxId: ref.resourceId,
211
230
  sessionId: suspension.sessionId,
@@ -213,6 +232,9 @@ export const defaultRuntimeSandboxReconciliation =
213
232
  outputPath: suspension.outputPath,
214
233
  exitCodePath: suspension.exitCodePath,
215
234
  expectedOrganizationId: ref.routingDomain,
235
+ ...(options?.skipCapturedOutput
236
+ ? { skipCapturedOutput: true }
237
+ : {}),
216
238
  }),
217
239
  readWorkCompletedAt: (ref, path) =>
218
240
  readDetachedDaytonaRuntimeCompletion({
@@ -233,12 +255,15 @@ export const defaultRuntimeSandboxReconciliation =
233
255
  routingDomain: outcome.appId,
234
256
  };
235
257
  },
236
- inspectDetachedRunner: (ref, suspension) =>
258
+ inspectDetachedRunner: (ref, suspension, options) =>
237
259
  inspectDetachedModalRunner({
238
260
  sandboxId: ref.resourceId,
239
261
  outputPath: suspension.outputPath,
240
262
  exitCodePath: suspension.exitCodePath,
241
263
  expectedAppId: ref.routingDomain,
264
+ ...(options?.skipCapturedOutput
265
+ ? { skipCapturedOutput: true }
266
+ : {}),
242
267
  }),
243
268
  readWorkCompletedAt: (ref, path) =>
244
269
  readDetachedModalRuntimeCompletion({
@@ -0,0 +1,27 @@
1
+ export type SandboxCreateOutcome = 'succeeded' | 'failed' | 'unknown';
2
+
3
+ /**
4
+ * One line for each create request that reached a provider, read by the
5
+ * provider outage alert. Log it only where a request was really sent: a run held
6
+ * behind the open Modal circuit makes no request, and account reads prove
7
+ * nothing, since Modal reported no limit on Oct 31 while refusing a real create.
8
+ * `unknown` means the request outlived its client deadline and may still land.
9
+ */
10
+ export function logSandboxCreateOutcome(input: {
11
+ provider: 'daytona' | 'modal';
12
+ outcome: SandboxCreateOutcome;
13
+ runId: string | null | undefined;
14
+ reason?: string | null;
15
+ }): void {
16
+ console.info('[runtime.sandbox.create_outcome]', {
17
+ event: 'runtime.sandbox.create_outcome',
18
+ provider: input.provider,
19
+ outcome: input.outcome,
20
+ runId: input.runId ?? null,
21
+ reason: input.reason ?? null,
22
+ runtimeEnvironment:
23
+ process.env.DEEPLINE_RUNTIME_ENVIRONMENT === 'preview'
24
+ ? 'preview'
25
+ : 'production',
26
+ });
27
+ }
@@ -46,6 +46,17 @@ export type PlayRunnerRuntimeResource = {
46
46
  sandboxCapacityLeaseId?: string;
47
47
  };
48
48
 
49
+ /** Exact durable owner identity required before reconciling an ambiguous
50
+ * Daytona create by deleting the sandbox it produced. */
51
+ export type PlayRunnerDaytonaCleanupIntent = {
52
+ leaseId: string;
53
+ providerOperationToken: string;
54
+ orgId: string;
55
+ runId: string;
56
+ sandboxId: string;
57
+ routingDomain: string;
58
+ };
59
+
49
60
  /**
50
61
  * Durable identity for a Modal create that can outlive the caller's timeout.
51
62
  * These fields are only provider routing and correlation data; payloads,
@@ -183,9 +194,19 @@ export interface PlayRunnerCallbacks {
183
194
  reserveSandboxCapacity?: (
184
195
  provider: 'daytona' | 'modal' | 'agentcore_runtime',
185
196
  providerAttempt?: number,
186
- ) => Promise<{ leaseId: string; providerOperationToken: string | null }>;
197
+ ) => Promise<{
198
+ leaseId: string;
199
+ providerOperationToken: string | null;
200
+ resumeExistingProviderOperation?: boolean;
201
+ resumePendingDelete?: boolean;
202
+ existingProviderOperationAgeMs?: number;
203
+ }>;
187
204
  /** Release an unbound reservation when provider create never produced a resource. */
188
205
  releaseSandboxCapacity?: (leaseId: string) => Promise<void>;
206
+ /** Persist a cleanup obligation before removing an ambiguously-created sandbox. */
207
+ recordDaytonaCleanupIntent?: (
208
+ intent: PlayRunnerDaytonaCleanupIntent,
209
+ ) => Promise<void>;
189
210
  /**
190
211
  * Scheduler-owned dependency circuit admission. A false result means no
191
212
  * provider call is safe to make yet; the backend must return/throw a typed