deepline 0.3.409 → 0.3.410

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 (213) hide show
  1. package/dist/bundling-sources/sdk/src/agent-runtime.ts +18 -1
  2. package/dist/bundling-sources/sdk/src/client.ts +206 -333
  3. package/dist/bundling-sources/sdk/src/compat.ts +45 -2
  4. package/dist/bundling-sources/sdk/src/db/query.ts +9 -10
  5. package/dist/bundling-sources/sdk/src/http.ts +38 -20
  6. package/dist/bundling-sources/sdk/src/index.ts +4 -5
  7. package/dist/bundling-sources/sdk/src/play.ts +10 -10
  8. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +6 -4
  9. package/dist/bundling-sources/sdk/src/plays/check-local-play-graph.ts +114 -0
  10. package/dist/bundling-sources/sdk/src/plays/client.ts +431 -0
  11. package/dist/bundling-sources/sdk/src/plays/local-play-execution.ts +2 -2
  12. package/dist/bundling-sources/sdk/src/plays/run-request.ts +106 -16
  13. package/dist/bundling-sources/sdk/src/release.ts +13 -7
  14. package/dist/bundling-sources/sdk/src/runs/read-errors.ts +8 -0
  15. package/dist/bundling-sources/sdk/src/runs/watch-polling.ts +124 -13
  16. package/dist/bundling-sources/sdk/src/tool-calls.ts +108 -19
  17. package/dist/bundling-sources/sdk/src/types.ts +18 -0
  18. package/dist/bundling-sources/shared_libs/integration-contracts/execute-retry-contract.ts +37 -0
  19. package/dist/bundling-sources/shared_libs/integration-contracts/package.json +3 -0
  20. package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +3 -1
  21. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +277 -76
  22. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +6 -0
  23. package/dist/bundling-sources/shared_libs/play-runtime/dataset-row-input.ts +124 -0
  24. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +6 -62
  25. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +1 -0
  26. package/dist/bundling-sources/shared_libs/play-runtime/durable-tool-identity.ts +67 -0
  27. package/dist/bundling-sources/shared_libs/play-runtime/execute-server-timing.ts +64 -6
  28. package/dist/bundling-sources/shared_libs/play-runtime/freshness-receipt-execution.ts +1 -5
  29. package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +1 -1
  30. package/dist/bundling-sources/shared_libs/play-runtime/play-artifact-runtime-contract.ts +3 -0
  31. package/dist/bundling-sources/shared_libs/play-runtime/play-http-request.ts +10 -0
  32. package/dist/bundling-sources/shared_libs/play-runtime/query-result-dataset.ts +3 -0
  33. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/egress-probe.ts +3 -0
  34. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +26 -16
  35. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-heartbeat.ts +36 -11
  36. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-terminal-push.ts +35 -0
  37. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-launch-transport.ts +21 -0
  38. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +21 -6
  39. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +11 -2
  40. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +85 -20
  41. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +71 -13
  42. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-execution-queries.ts +100 -0
  43. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool.ts +9 -5
  44. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +337 -146
  45. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +26 -12
  46. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +3 -1
  47. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +425 -102
  48. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-dispatch-authority.ts +4 -0
  49. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +4 -0
  50. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts +9 -0
  51. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +181 -124
  52. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-worker-wake.ts +152 -0
  53. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +5 -3
  54. package/dist/bundling-sources/shared_libs/play-runtime/tool-cache-policy.ts +31 -0
  55. package/dist/bundling-sources/shared_libs/play-runtime/transient-service-error.ts +10 -0
  56. package/dist/bundling-sources/shared_libs/plays/ambiguous-write-error.ts +25 -0
  57. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +4 -0
  58. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +63 -68
  59. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +129 -63
  60. package/dist/bundling-sources/shared_libs/plays/contracts.ts +14 -0
  61. package/dist/bundling-sources/shared_libs/plays/enrich-play-compiler.ts +58 -16
  62. package/dist/bundling-sources/shared_libs/plays/fetch-http-error.ts +50 -0
  63. package/dist/bundling-sources/shared_libs/plays/source-authoring-edition.ts +351 -0
  64. package/dist/bundling-sources/shared_libs/plays/tool-list-getter-mode.ts +9 -0
  65. package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +1 -1
  66. package/dist/cli/{auth-5HIIACF7.mjs → auth-LLXLIILR.mjs} +6 -6
  67. package/dist/cli/auth-UG4WOYGL.js +40 -0
  68. package/dist/cli/{billing-EVZ3ZWKC.mjs → billing-5FVXZYAC.mjs} +8 -8
  69. package/dist/cli/{billing-4275N7FL.js → billing-NFPK7GYP.js} +84 -84
  70. package/dist/cli/{chunk-ZAAKSJAS.js → chunk-27GJKC5Q.js} +17 -10
  71. package/dist/cli/{chunk-UHNDVD3P.js → chunk-2H4EY7KH.js} +100 -41
  72. package/dist/cli/{chunk-TQNHMWUR.mjs → chunk-2YR7BIIC.mjs} +5 -2
  73. package/dist/cli/{chunk-AU4OFDFX.js → chunk-36AHOWVS.js} +26 -26
  74. package/dist/cli/{chunk-OSDXE27V.mjs → chunk-4PG4ARL2.mjs} +17 -10
  75. package/dist/cli/{chunk-PBZYY7VZ.mjs → chunk-4XQLVUC7.mjs} +734 -511
  76. package/dist/cli/chunk-5TUGWDEB.js +313 -0
  77. package/dist/cli/{chunk-DEC3JECC.js → chunk-5UUQAGJS.js} +5 -2
  78. package/dist/cli/{chunk-JRAVVJ3T.mjs → chunk-5V5Y37BC.mjs} +2 -2
  79. package/dist/cli/{chunk-PMVFAYL7.mjs → chunk-63ILLN5H.mjs} +2 -2
  80. package/dist/cli/{chunk-V76R6HMV.js → chunk-63S7X326.js} +1029 -806
  81. package/dist/cli/{chunk-VWBTTJYQ.mjs → chunk-6PGATQ6L.mjs} +6 -3
  82. package/dist/cli/{chunk-6BJK4EJ3.mjs → chunk-AARWVK4C.mjs} +2132 -65
  83. package/dist/cli/{chunk-FERRDNMO.js → chunk-AD47BXN2.js} +5 -5
  84. package/dist/cli/{chunk-GAICVLKL.js → chunk-D37FEBES.js} +2 -2
  85. package/dist/cli/{chunk-S6R3OX7B.js → chunk-E4CABWXL.js} +25 -2
  86. package/dist/cli/{chunk-NXGCO4JB.mjs → chunk-E4IXDAZI.mjs} +5 -0
  87. package/dist/cli/chunk-EQ4Z7RJW.mjs +35 -0
  88. package/dist/cli/chunk-FR2ILQ4G.mjs +8 -0
  89. package/dist/cli/{chunk-FJCIUF34.js → chunk-FVLNYDI4.js} +128 -376
  90. package/dist/cli/{chunk-O3VSXP2F.js → chunk-FZJAM576.js} +50 -50
  91. package/dist/cli/{chunk-BZAMOCPA.mjs → chunk-IMZ56EOH.mjs} +3 -3
  92. package/dist/cli/{chunk-N44JHMKY.mjs → chunk-IPG42SD2.mjs} +452 -138
  93. package/dist/cli/chunk-J33TSWO5.js +8 -0
  94. package/dist/cli/{chunk-BEVLCKXG.mjs → chunk-JNXJZ577.mjs} +1 -1
  95. package/dist/cli/{chunk-JI2B4RZP.mjs → chunk-KCC3FKIW.mjs} +71 -12
  96. package/dist/cli/{chunk-6IKARAYD.mjs → chunk-L2VKAASU.mjs} +23 -0
  97. package/dist/cli/{chunk-WLOCMJWV.js → chunk-LTFL4JRN.js} +426 -721
  98. package/dist/cli/{chunk-YHPYUZZX.mjs → chunk-MAMVGOSC.mjs} +1 -1
  99. package/dist/cli/{chunk-NZSF57UO.mjs → chunk-MN2OWLFA.mjs} +2 -2
  100. package/dist/cli/{chunk-YD7B53RW.js → chunk-NF4V5DTY.js} +12 -12
  101. package/dist/cli/{chunk-Q2E4E4FJ.js → chunk-NPBJI7RE.js} +8 -8
  102. package/dist/cli/chunk-NTVLGHFM.js +501 -0
  103. package/dist/cli/{chunk-HQXL5526.mjs → chunk-NUX2QHNC.mjs} +1 -1
  104. package/dist/cli/{chunk-JGHG4NBA.js → chunk-OBB4QXHA.js} +19 -4
  105. package/dist/cli/{chunk-SEFMGO3Z.js → chunk-OQQOXSYA.js} +2184 -117
  106. package/dist/cli/chunk-OZ6E3IRZ.js +6084 -0
  107. package/dist/cli/{chunk-7P5AA3SN.js → chunk-PPDBRJRW.js} +6 -1
  108. package/dist/cli/{chunk-FHPCKULR.mjs → chunk-PZSLPBDA.mjs} +2 -2
  109. package/dist/cli/{chunk-ILHRA7AD.js → chunk-QADCFSGH.js} +7 -7
  110. package/dist/cli/{chunk-RTCDW2GU.js → chunk-QJI5FIOW.js} +170 -49
  111. package/dist/cli/{chunk-WYQO2CBS.mjs → chunk-QL22Y56M.mjs} +149 -28
  112. package/dist/cli/{chunk-2PRO2JTX.mjs → chunk-RFB25DSQ.mjs} +36 -284
  113. package/dist/cli/chunk-T44IIOT6.mjs +501 -0
  114. package/dist/cli/chunk-VK2LZ5IP.js +35 -0
  115. package/dist/cli/chunk-VKKVSFRD.js +62 -0
  116. package/dist/cli/{chunk-2GI3QD3L.js → chunk-VYKV5XHL.js} +644 -330
  117. package/dist/cli/{chunk-GSK6NHVM.js → chunk-WU4U6VSB.js} +5 -5
  118. package/dist/cli/chunk-XHLKJOTN.mjs +313 -0
  119. package/dist/cli/{chunk-IT3XBJQR.mjs → chunk-XIHWSXSV.mjs} +330 -625
  120. package/dist/cli/chunk-XNZJKRJA.mjs +6084 -0
  121. package/dist/cli/chunk-ZCALLYF6.mjs +62 -0
  122. package/dist/cli/{chunk-WHG43Z67.js → chunk-ZFZ427HN.js} +11 -8
  123. package/dist/cli/{chunk-J6DCKJNM.mjs → chunk-ZKYEW55U.mjs} +16 -1
  124. package/dist/cli/{csv-BBOTCGQY.js → csv-7U3FJYKZ.js} +14 -14
  125. package/dist/cli/{csv-A2MP6EFV.mjs → csv-ZWLDMM4A.mjs} +5 -5
  126. package/dist/cli/{db-G4CODDCA.js → db-DNCGV5PC.js} +42 -47
  127. package/dist/cli/{db-3W5DMTUX.mjs → db-IMYXVMGI.mjs} +15 -20
  128. package/dist/cli/{describe-XYJ2ZT4M.mjs → describe-Q23DWJUK.mjs} +20 -15
  129. package/dist/cli/{describe-PQTQ5B6F.js → describe-S34JUX5W.js} +27 -22
  130. package/dist/cli/describe-core.d.mts +2 -2
  131. package/dist/cli/describe-core.d.ts +2 -2
  132. package/dist/cli/describe-core.js +6 -6
  133. package/dist/cli/describe-core.mjs +5 -5
  134. package/dist/cli/{executions-UR67CA5H.mjs → executions-A73EUGSI.mjs} +8 -8
  135. package/dist/cli/{executions-TLANVR7Y.js → executions-XOMPX2YJ.js} +10 -10
  136. package/dist/cli/{feedback-WHCMGEIL.mjs → feedback-N4GJ2POI.mjs} +11 -7
  137. package/dist/cli/{feedback-6C2YTRJL.js → feedback-QTCHNJJH.js} +13 -9
  138. package/dist/cli/{git-GWLB6VSA.mjs → git-4Q3JIQYZ.mjs} +6 -6
  139. package/dist/cli/git-I6CPBEVG.js +24 -0
  140. package/dist/cli/index.js +236 -348
  141. package/dist/cli/index.mjs +162 -274
  142. package/dist/cli/{legacy-noops-KF4XIFEF.mjs → legacy-noops-3SOVGFF7.mjs} +6 -6
  143. package/dist/cli/{legacy-noops-ZUFA7RWI.js → legacy-noops-4OSHZM34.js} +9 -9
  144. package/dist/cli/{monitors-TB3K2IVE.js → monitors-LVE2KZNG.js} +94 -94
  145. package/dist/cli/{monitors-6UOIDIMB.mjs → monitors-QP2XID2B.mjs} +8 -8
  146. package/dist/cli/{org-WGHHMVDZ.mjs → org-IVRETVQA.mjs} +8 -8
  147. package/dist/cli/{org-CKWMBPIR.js → org-XFLK5IAP.js} +68 -68
  148. package/dist/cli/{play-LYPAXCLD.mjs → play-DE7VH6NU.mjs} +533 -98
  149. package/dist/cli/{play-N2B3KAVS.js → play-XXTPPP23.js} +1067 -632
  150. package/dist/cli/{providers-UR42MD6Z.js → providers-DLD3I4JF.js} +11 -11
  151. package/dist/cli/{providers-6DI5BVZJ.mjs → providers-GX2NIZQQ.mjs} +8 -8
  152. package/dist/cli/{quickstart-MNA2S6PO.mjs → quickstart-72B4L4PK.mjs} +5 -5
  153. package/dist/cli/{quickstart-FCJG4XGB.js → quickstart-XNS3HSWC.js} +7 -7
  154. package/dist/cli/search-6NCH4HB5.js +30 -0
  155. package/dist/cli/{search-VPPYUJ2M.mjs → search-SUTRANJI.mjs} +9 -9
  156. package/dist/cli/{secrets-QOSMVO36.js → secrets-6OBLOVEV.js} +17 -17
  157. package/dist/cli/{secrets-DRI4W7Z5.mjs → secrets-FPFXXNUH.mjs} +8 -8
  158. package/dist/cli/sessions-235532DR.js +16 -0
  159. package/dist/cli/{sessions-DQNUKP43.mjs → sessions-R25I4QKN.mjs} +6 -6
  160. package/dist/cli/{settings-DWDK3Y2R.mjs → settings-AOP6F5PZ.mjs} +12 -12
  161. package/dist/cli/{settings-JUGGCOPS.js → settings-VL5FOFPN.js} +79 -79
  162. package/dist/cli/{setup-AWBHNYXK.js → setup-BSC67YT3.js} +45 -44
  163. package/dist/cli/{setup-D5DWVNY4.mjs → setup-ZMPHBHVJ.mjs} +11 -10
  164. package/dist/cli/skills-3IWLYYRL.js +29 -0
  165. package/dist/cli/{skills-YV2XR35J.mjs → skills-KF65TVFO.mjs} +7 -7
  166. package/dist/cli/tools-LR66SPYU.js +44 -0
  167. package/dist/cli/{tools-VFJYHNV2.mjs → tools-SX4XIPM7.mjs} +19 -14
  168. package/dist/cli/{update-IM6VOTGL.mjs → update-QRMFRAQQ.mjs} +11 -9
  169. package/dist/cli/update-SP7UEO53.js +31 -0
  170. package/dist/cli/{workflow-26URBWPV.mjs → workflow-FOEEEB7G.mjs} +44 -20
  171. package/dist/cli/{workflow-3BS6U6SL.js → workflow-KOCK2FLW.js} +54 -30
  172. package/dist/{client-BfInrZPB.d.mts → client-74k4IPh6.d.mts} +135 -54
  173. package/dist/{client-BMjJFpan.d.ts → client-C1IK1f8c.d.ts} +135 -54
  174. package/dist/{compiler-manifest-Ycx-hoAr.d.mts → compiler-manifest-lzWpbV3w.d.mts} +83 -66
  175. package/dist/{compiler-manifest-Ycx-hoAr.d.ts → compiler-manifest-lzWpbV3w.d.ts} +83 -66
  176. package/dist/{index-CZXgiN3E.d.mts → index-C8Cy-YTm.d.ts} +5 -1
  177. package/dist/{index-NPG5pqxQ.d.ts → index-CtNK-0nI.d.mts} +5 -1
  178. package/dist/index.d.mts +47 -9
  179. package/dist/index.d.ts +47 -9
  180. package/dist/index.js +17 -14
  181. package/dist/index.mjs +13 -10
  182. package/dist/install-integrity.json +118 -102
  183. package/dist/plays/bundle-play-file.d.mts +3 -3
  184. package/dist/plays/bundle-play-file.d.ts +3 -3
  185. package/dist/plays/bundle-play-file.mjs +5 -4
  186. package/dist/plays/csv-data-input.js +3 -3
  187. package/dist/plays/csv-data-input.mjs +2 -2
  188. package/dist/plays/play-description.d.mts +2 -2
  189. package/dist/plays/play-description.d.ts +2 -2
  190. package/dist/plays/run-request.d.mts +2 -2
  191. package/dist/plays/run-request.d.ts +2 -2
  192. package/dist/plays/run-request.js +11 -3
  193. package/dist/plays/run-request.mjs +10 -2
  194. package/dist/release.d.mts +15 -6
  195. package/dist/release.d.ts +15 -6
  196. package/dist/release.js +2 -2
  197. package/dist/release.mjs +1 -1
  198. package/package.json +2 -2
  199. package/dist/cli/auth-F6BX32XZ.js +0 -40
  200. package/dist/cli/chunk-264PC2RN.mjs +0 -83
  201. package/dist/cli/chunk-44ZTYHMQ.mjs +0 -155
  202. package/dist/cli/chunk-53HN7WZN.js +0 -392
  203. package/dist/cli/chunk-7AALNGTA.mjs +0 -392
  204. package/dist/cli/chunk-ALD4COBH.js +0 -155
  205. package/dist/cli/chunk-CLJGSOVM.mjs +0 -1716
  206. package/dist/cli/chunk-WNUR6VP5.js +0 -83
  207. package/dist/cli/chunk-Z4VNJOF7.js +0 -1716
  208. package/dist/cli/git-VQFF6D7C.js +0 -24
  209. package/dist/cli/search-NCEEONMQ.js +0 -30
  210. package/dist/cli/sessions-3WYKQABW.js +0 -16
  211. package/dist/cli/skills-AKPAJVSO.js +0 -29
  212. package/dist/cli/tools-RBKEK6PM.js +0 -39
  213. package/dist/cli/update-VFNUBLDA.js +0 -29
@@ -0,0 +1,431 @@
1
+ /**
2
+ * Remote Play operations shared by the full SDK client and imported Play handles.
3
+ * Handles resolve configuration lazily; a submitted job keeps its original client.
4
+ */
5
+ import { resolveConfig } from '../config';
6
+ import { DeeplineError } from '../errors';
7
+ import { HttpClient } from '../http';
8
+ import { SDK_API_MAJOR } from '../version';
9
+ import type {
10
+ DeeplineClientOptions,
11
+ ClearPlayHistoryRequest,
12
+ ClearPlayHistoryResult,
13
+ PlayDetail,
14
+ PlayRevisionSummary,
15
+ PlayRunListItem,
16
+ PlayRunStart,
17
+ PlayStatus,
18
+ PublishPlayVersionRequest,
19
+ PublishPlayVersionResult,
20
+ StartPlayRunRequest,
21
+ StopPlayRunResult,
22
+ } from '../types';
23
+ import {
24
+ isPlayRunPackage,
25
+ startPlayRun,
26
+ type ResolvedStartPlayRunRequest,
27
+ type PlayRunStartOptions,
28
+ } from './run-request';
29
+ import {
30
+ RUNTIME_ENVIRONMENT_TOKEN_HEADER,
31
+ RETAINED_PIPELINE_RECEIVERS_HEADER,
32
+ } from '../../../shared_libs/play-runtime/coordinator-headers.js';
33
+ import {
34
+ normalizePlayRuntimeEnvironment,
35
+ normalizePlayRuntimeNamespace,
36
+ normalizePlayRuntimeSandboxPlacementPolicy,
37
+ normalizePlayRuntimeSelection,
38
+ type PlayRuntimeSelection,
39
+ } from '../../../shared_libs/play-runtime/runtime-environment.js';
40
+ import { decodePlayRunPublicStatus } from '../../../shared_libs/play-runtime/run-lifecycle-policy.js';
41
+
42
+ export function normalizePlayRunIntegrationMode(
43
+ value: unknown,
44
+ ): 'live' | 'eval_stub' | 'fixture' | undefined {
45
+ if (value === 'live' || value === 'eval_stub' || value === 'fixture') {
46
+ return value;
47
+ }
48
+ return undefined;
49
+ }
50
+
51
+ export type ClientEnvironment = Readonly<Record<string, string | undefined>>;
52
+
53
+ function resolvePlayRunIntegrationMode(
54
+ request: StartPlayRunRequest,
55
+ env: ClientEnvironment,
56
+ ): 'live' | 'eval_stub' | 'fixture' | undefined {
57
+ return normalizePlayRunIntegrationMode(
58
+ request.integrationMode ?? env.DEEPLINE_EVAL_INTEGRATION_MODE,
59
+ );
60
+ }
61
+
62
+ function resolvePlayRunRuntimeSelection(
63
+ request: StartPlayRunRequest,
64
+ env: ClientEnvironment,
65
+ ): PlayRuntimeSelection | undefined {
66
+ if (request.runtime !== undefined) {
67
+ const runtime = normalizePlayRuntimeSelection(request.runtime);
68
+ if (!runtime) {
69
+ throw new DeeplineError(
70
+ 'runtime must be { environment: "preview", namespace, backend?: "daytona" | "modal", sandboxPlacementPolicy?: "policy_name@1" } with namespace matching ^[a-z][a-z0-9-]{0,30}$.',
71
+ undefined,
72
+ 'INVALID_RUNTIME_SELECTION',
73
+ );
74
+ }
75
+ return runtime;
76
+ }
77
+ // These variables select where the app executes a run, not which app the
78
+ // SDK calls. DEEPLINE_API_BASE_URL still chooses the app host. Environment
79
+ // opts into remote preview routing, namespace names the isolated lane, and
80
+ // the token only authorizes that selection. Omitting all three leaves the
81
+ // app free to use its native runtime (local for a local app, prod for prod).
82
+ const configured = env.DEEPLINE_RUNTIME_ENVIRONMENT?.trim();
83
+ const configuredNamespace = env.DEEPLINE_RUNTIME_NAMESPACE?.trim();
84
+ const configuredToken = env.DEEPLINE_RUNTIME_ENVIRONMENT_TOKEN?.trim();
85
+ const configuredPlacementPolicy =
86
+ env.DEEPLINE_RUNTIME_SANDBOX_PLACEMENT_POLICY?.trim();
87
+ if (!configured) {
88
+ if (configuredNamespace || configuredToken || configuredPlacementPolicy) {
89
+ // Name the variables that are actually set. This branch is almost always
90
+ // hit by a stale value auto-loaded from a .env/.env.local rather than by
91
+ // a deliberate export, so the message has to say where to look and how
92
+ // to run the command anyway.
93
+ const present: string[] = [];
94
+ if (configuredNamespace) present.push('DEEPLINE_RUNTIME_NAMESPACE');
95
+ if (configuredToken) present.push('DEEPLINE_RUNTIME_ENVIRONMENT_TOKEN');
96
+ if (configuredPlacementPolicy) {
97
+ present.push('DEEPLINE_RUNTIME_SANDBOX_PLACEMENT_POLICY');
98
+ }
99
+ const isPlural = present.length > 1;
100
+ throw new DeeplineError(
101
+ [
102
+ `Incomplete play runtime selection: ${present.join(' and ')} ${isPlural ? 'are' : 'is'} set but DEEPLINE_RUNTIME_ENVIRONMENT is not.`,
103
+ 'Preview routing requires DEEPLINE_RUNTIME_ENVIRONMENT=preview together with DEEPLINE_RUNTIME_NAMESPACE; the token alone authorizes nothing.',
104
+ `If you did not export ${isPlural ? 'these' : 'this'} yourself, ${isPlural ? 'they were' : 'it was'} most likely auto-loaded from a .env or .env.local in the current directory (bun loads those automatically, and in a git worktree .env.local is usually a symlink to the main checkout).`,
105
+ `To run against the app-native runtime, clear ${isPlural ? 'them' : 'it'} for this command: ${present.map((name) => `${name}=`).join(' ')} <your deepline command>`,
106
+ ].join('\n'),
107
+ undefined,
108
+ 'INVALID_RUNTIME_ENVIRONMENT',
109
+ );
110
+ }
111
+ return undefined;
112
+ }
113
+ const environment = normalizePlayRuntimeEnvironment(configured);
114
+ if (!environment) {
115
+ throw new DeeplineError(
116
+ `DEEPLINE_RUNTIME_ENVIRONMENT supports only explicit preview selection. Received "${configured}". Omit it to use the app-native runtime.`,
117
+ undefined,
118
+ 'INVALID_RUNTIME_ENVIRONMENT',
119
+ );
120
+ }
121
+ const namespace = normalizePlayRuntimeNamespace(configuredNamespace);
122
+ if (!namespace) {
123
+ throw new DeeplineError(
124
+ 'DEEPLINE_RUNTIME_NAMESPACE is required for preview and must match ^[a-z][a-z0-9-]{0,30}$.',
125
+ undefined,
126
+ 'INVALID_RUNTIME_NAMESPACE',
127
+ );
128
+ }
129
+ const configuredBackendValue = env.DEEPLINE_PLAY_RUNNER_BACKEND?.trim();
130
+ const configuredBackend =
131
+ configuredBackendValue === 'daytona' || configuredBackendValue === 'modal'
132
+ ? configuredBackendValue
133
+ : undefined;
134
+ if (configuredBackendValue && !configuredBackend) {
135
+ throw new DeeplineError(
136
+ `DEEPLINE_PLAY_RUNNER_BACKEND must be daytona or modal for preview runtime selection. Received "${configuredBackendValue}".`,
137
+ undefined,
138
+ 'INVALID_RUNTIME_BACKEND',
139
+ );
140
+ }
141
+ if (
142
+ configuredPlacementPolicy &&
143
+ !normalizePlayRuntimeSandboxPlacementPolicy(configuredPlacementPolicy)
144
+ ) {
145
+ throw new DeeplineError(
146
+ `DEEPLINE_RUNTIME_SANDBOX_PLACEMENT_POLICY must be a versioned placement policy id such as daytona_only@1. Received "${configuredPlacementPolicy}".`,
147
+ undefined,
148
+ 'INVALID_RUNTIME_SANDBOX_PLACEMENT_POLICY',
149
+ );
150
+ }
151
+ return {
152
+ environment,
153
+ namespace,
154
+ ...(configuredBackend ? { backend: configuredBackend } : {}),
155
+ ...(configuredPlacementPolicy
156
+ ? { sandboxPlacementPolicy: configuredPlacementPolicy }
157
+ : {}),
158
+ };
159
+ }
160
+
161
+ /**
162
+ * Resolve the environment-derived run-start fields (eval integration mode,
163
+ * test policy overrides, preview runtime) into explicit request fields, in the
164
+ * order the SDK has always validated them. The shared body builder in
165
+ * `plays/run-request` never reads the environment.
166
+ */
167
+ export function resolveStartPlayRunRequest(
168
+ request: StartPlayRunRequest,
169
+ env: ClientEnvironment,
170
+ ): {
171
+ request: ResolvedStartPlayRunRequest;
172
+ runtime: PlayRuntimeSelection | undefined;
173
+ } {
174
+ const integrationMode = resolvePlayRunIntegrationMode(request, env);
175
+ const testPolicyOverrides =
176
+ request.testPolicyOverrides ?? parseEnvTestPolicyOverrides(env);
177
+ const runtime = resolvePlayRunRuntimeSelection(request, env);
178
+ const resolved: ResolvedStartPlayRunRequest = { ...request };
179
+ delete resolved.integrationMode;
180
+ delete resolved.runtime;
181
+ delete resolved.testPolicyOverrides;
182
+ if (integrationMode) resolved.integrationMode = integrationMode;
183
+ if (runtime) resolved.runtime = runtime;
184
+ if (testPolicyOverrides) resolved.testPolicyOverrides = testPolicyOverrides;
185
+ return { request: resolved, runtime };
186
+ }
187
+
188
+ export function runtimeSelectionHeaders(
189
+ runtime: PlayRuntimeSelection | undefined,
190
+ env: ClientEnvironment,
191
+ ): Record<string, string> | undefined {
192
+ if (!runtime) return undefined;
193
+ // Keep the credential out of the typed runtime payload. The app consumes it
194
+ // at the HTTP boundary and never forwards it to Fly, Absurd, or Daytona.
195
+ const token = env.DEEPLINE_RUNTIME_ENVIRONMENT_TOKEN?.trim();
196
+ if (!token) {
197
+ throw new DeeplineError(
198
+ 'DEEPLINE_RUNTIME_ENVIRONMENT_TOKEN is required for explicit preview runtime selection.',
199
+ undefined,
200
+ 'RUNTIME_ENVIRONMENT_TOKEN_REQUIRED',
201
+ );
202
+ }
203
+ const receivers = env.DEEPLINE_RUNTIME_RETAINED_PIPELINE_RECEIVERS?.trim();
204
+ return {
205
+ [RUNTIME_ENVIRONMENT_TOKEN_HEADER]: token,
206
+ ...(receivers ? { [RETAINED_PIPELINE_RECEIVERS_HEADER]: receivers } : {}),
207
+ };
208
+ }
209
+
210
+ function normalizeTestPolicyOverrides(
211
+ value: unknown,
212
+ source: string,
213
+ ): Record<string, unknown> {
214
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
215
+ return value as Record<string, unknown>;
216
+ }
217
+ throw new DeeplineError(
218
+ `${source} must be a JSON object.`,
219
+ undefined,
220
+ 'INVALID_TEST_POLICY_OVERRIDES',
221
+ );
222
+ }
223
+
224
+ function parseEnvTestPolicyOverrides(
225
+ env: ClientEnvironment,
226
+ ): Record<string, unknown> | undefined {
227
+ const raw = env.DEEPLINE_TEST_POLICY_OVERRIDES;
228
+ const trimmed = raw?.trim();
229
+ if (!trimmed) return undefined;
230
+ let parsed: unknown;
231
+ try {
232
+ parsed = JSON.parse(trimmed);
233
+ } catch (error) {
234
+ const detail = error instanceof Error ? ` ${error.message}` : '';
235
+ throw new DeeplineError(
236
+ `DEEPLINE_TEST_POLICY_OVERRIDES must be valid JSON.${detail}`,
237
+ undefined,
238
+ 'INVALID_TEST_POLICY_OVERRIDES',
239
+ );
240
+ }
241
+ return normalizeTestPolicyOverrides(parsed, 'DEEPLINE_TEST_POLICY_OVERRIDES');
242
+ }
243
+
244
+ function isRecord(value: unknown): value is Record<string, unknown> {
245
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value));
246
+ }
247
+
248
+ export function normalizePlayStatus(raw: Record<string, unknown>): PlayStatus {
249
+ const runPackage = isPlayRunPackage(raw)
250
+ ? raw
251
+ : isPlayRunPackage(raw.package)
252
+ ? raw.package
253
+ : null;
254
+ const packageRun = runPackage?.run;
255
+ const rawStatus =
256
+ typeof raw.status === 'string'
257
+ ? raw.status
258
+ : typeof packageRun?.status === 'string'
259
+ ? packageRun.status
260
+ : null;
261
+ const status = decodePlayRunPublicStatus(rawStatus);
262
+ if (!status) {
263
+ throw new Error(
264
+ `Invalid play run lifecycle status in API response: ${JSON.stringify(rawStatus)}.`,
265
+ );
266
+ }
267
+ const runId =
268
+ typeof raw.runId === 'string'
269
+ ? raw.runId
270
+ : typeof raw.workflowId === 'string'
271
+ ? raw.workflowId
272
+ : (packageRun?.id ?? '');
273
+ const legacyOverview = runPackage?.overview ?? raw.overview;
274
+ const runStatus = runPackage?.runStatus ?? raw.runStatus;
275
+ return {
276
+ ...(raw as unknown as Omit<PlayStatus, 'runId' | 'status'>),
277
+ runId,
278
+ ...(isRecord(legacyOverview)
279
+ ? {
280
+ overview: legacyOverview as unknown as PlayStatus['overview'],
281
+ }
282
+ : {}),
283
+ ...(isRecord(runStatus)
284
+ ? { runStatus: runStatus as unknown as PlayStatus['runStatus'] }
285
+ : {}),
286
+ ...(runPackage
287
+ ? {
288
+ package: runPackage,
289
+ outputs: runPackage.outputs,
290
+ }
291
+ : {}),
292
+ status,
293
+ };
294
+ }
295
+
296
+ export class PlayClient {
297
+ constructor(
298
+ private readonly http: HttpClient,
299
+ private readonly environment: ClientEnvironment = process.env,
300
+ ) {}
301
+
302
+ async startPlayRun(
303
+ request: StartPlayRunRequest,
304
+ options?: PlayRunStartOptions,
305
+ ): Promise<PlayRunStart> {
306
+ const resolved = resolveStartPlayRunRequest(request, this.environment);
307
+ const headers = runtimeSelectionHeaders(resolved.runtime, this.environment);
308
+ return startPlayRun(
309
+ this.http,
310
+ resolved.request,
311
+ options?.cliAdmission
312
+ ? { ...headers, 'X-Deepline-API-Major': String(SDK_API_MAJOR) }
313
+ : headers,
314
+ options,
315
+ );
316
+ }
317
+
318
+ async getPlayStatus(
319
+ workflowId: string,
320
+ options?: { billing?: boolean; full?: boolean },
321
+ ): Promise<PlayStatus> {
322
+ const params = new URLSearchParams();
323
+ if (options?.billing === false) {
324
+ params.set('billing', 'false');
325
+ }
326
+ if (options?.full === true) {
327
+ params.set('full', 'true');
328
+ }
329
+ const query = params.size > 0 ? `?${params.toString()}` : '';
330
+ const response = await this.http.get<Record<string, unknown>>(
331
+ `/api/v2/runs/${encodeURIComponent(workflowId)}${query}`,
332
+ );
333
+ return normalizePlayStatus(response);
334
+ }
335
+
336
+ async cancelPlay(workflowId: string): Promise<void> {
337
+ await this.http.request(
338
+ `/api/v2/runs/${encodeURIComponent(workflowId)}/stop`,
339
+ { method: 'POST' },
340
+ );
341
+ }
342
+
343
+ async stopPlay(
344
+ workflowId: string,
345
+ options?: { reason?: string },
346
+ ): Promise<StopPlayRunResult> {
347
+ return this.http.post<StopPlayRunResult>(
348
+ `/api/v2/runs/${encodeURIComponent(workflowId)}/stop`,
349
+ options?.reason ? { reason: options.reason } : {},
350
+ );
351
+ }
352
+
353
+ async listPlayRuns(playName: string): Promise<PlayRunListItem[]> {
354
+ const encodedName = encodeURIComponent(playName);
355
+ const response = await this.http.get<{ runs: PlayRunListItem[] }>(
356
+ `/api/v2/plays/${encodedName}/runs`,
357
+ );
358
+ return response.runs ?? [];
359
+ }
360
+
361
+ async getPlay(
362
+ name: string,
363
+ options?: {
364
+ source?: 'working' | 'live' | `version:${number}`;
365
+ guidance?: boolean;
366
+ },
367
+ ): Promise<PlayDetail> {
368
+ const encodedName = encodeURIComponent(name);
369
+ const query = options?.source
370
+ ? `?include=source&revision=${encodeURIComponent(options.source)}`
371
+ : options?.guidance
372
+ ? '?include=guidance'
373
+ : '';
374
+ return this.http.get<PlayDetail>(`/api/v2/plays/${encodedName}${query}`);
375
+ }
376
+
377
+ async clearPlayHistory(
378
+ name: string,
379
+ request: ClearPlayHistoryRequest = {},
380
+ ): Promise<ClearPlayHistoryResult> {
381
+ const encodedName = encodeURIComponent(name);
382
+ return this.http.post<ClearPlayHistoryResult>(
383
+ `/api/v2/plays/${encodedName}/history/clear`,
384
+ request,
385
+ );
386
+ }
387
+
388
+ async listPlayVersions(
389
+ name: string,
390
+ options?: { full?: boolean },
391
+ ): Promise<PlayRevisionSummary[]> {
392
+ const encodedName = encodeURIComponent(name);
393
+ const suffix = options?.full ? '?full=true' : '';
394
+ const response = await this.http.get<{ versions: PlayRevisionSummary[] }>(
395
+ `/api/v2/plays/${encodedName}/versions${suffix}`,
396
+ );
397
+ return response.versions ?? [];
398
+ }
399
+
400
+ async publishPlayVersion(
401
+ name: string,
402
+ request: PublishPlayVersionRequest = {},
403
+ ): Promise<PublishPlayVersionResult> {
404
+ const encodedName = encodeURIComponent(name);
405
+ return this.http.post<PublishPlayVersionResult>(
406
+ `/api/v2/plays/${encodedName}/live`,
407
+ request,
408
+ );
409
+ }
410
+ }
411
+
412
+ export type PlayClientOperations = Pick<
413
+ PlayClient,
414
+ | 'getPlay'
415
+ | 'listPlayRuns'
416
+ | 'listPlayVersions'
417
+ | 'publishPlayVersion'
418
+ | 'clearPlayHistory'
419
+ | 'startPlayRun'
420
+ | 'getPlayStatus'
421
+ | 'cancelPlay'
422
+ | 'stopPlay'
423
+ >;
424
+
425
+ export function createPlayClient(options?: DeeplineClientOptions): PlayClient {
426
+ const config = resolveConfig(options);
427
+ return new PlayClient(
428
+ new HttpClient(config),
429
+ config.environment ?? process.env,
430
+ );
431
+ }
@@ -1,5 +1,5 @@
1
- import type { DeeplineClient } from '../client';
2
- import type { BundledPlayFileSuccess } from './bundle-play-file';
1
+ import type { DeeplineClient } from '../client.js';
2
+ import type { BundledPlayFileSuccess } from './bundle-play-file.js';
3
3
 
4
4
  export type LocalPlayGraph = {
5
5
  root: BundledPlayFileSuccess;
@@ -31,9 +31,12 @@ import type { PlayStagedFileRef } from './local-file-discovery';
31
31
 
32
32
  export { DeeplineError };
33
33
 
34
- /** The single run-start route. CLI, SDK, API, and dashboard all POST here. */
34
+ /** Canonical admission; the CLI adapter adds compatibility before this handler. */
35
35
  export const PLAY_RUN_START_PATH = '/api/v2/plays/run';
36
+ export const CLI_PLAY_RUN_START_PATH = `${PLAY_RUN_START_PATH}/cli`;
37
+ export const CLI_PLAY_RUN_SUPPORTED_HEADER = 'x-deepline-cli-play-admission';
36
38
  export const PLAY_RUN_START_STREAM_PATH = `${PLAY_RUN_START_PATH}?stream=true`;
39
+ export const CLI_PLAY_RUN_START_STREAM_PATH = `${CLI_PLAY_RUN_START_PATH}?stream=true`;
37
40
  export const PLAY_FILES_STAGE_PATH = '/api/v2/plays/files/stage';
38
41
  export const PLAY_FILES_STAGE_MINT_PATH = `${PLAY_FILES_STAGE_PATH}/mint`;
39
42
 
@@ -44,12 +47,20 @@ export const PLAY_FILES_STAGE_MINT_PATH = `${PLAY_FILES_STAGE_PATH}/mint`;
44
47
  * responses so the staging fallbacks below classify failures identically.
45
48
  */
46
49
  export interface PlayRunHttp {
47
- get?<T = unknown>(path: string): Promise<T>;
50
+ get?<T = unknown>(
51
+ path: string,
52
+ options?: { signal?: AbortSignal },
53
+ ): Promise<T>;
48
54
  post<T = unknown>(
49
55
  path: string,
50
56
  body: unknown,
51
57
  headers?: Record<string, string>,
52
- options?: { maxRetries?: number; exactUrlOnly?: boolean },
58
+ options?: {
59
+ maxRetries?: number;
60
+ exactUrlOnly?: boolean;
61
+ signal?: AbortSignal;
62
+ onResponse?: (response: Response) => void;
63
+ },
53
64
  ): Promise<T>;
54
65
  postFormData<T = unknown>(
55
66
  path: string,
@@ -66,6 +77,28 @@ export interface PlayRunHttp {
66
77
  */
67
78
  export type ResolvedStartPlayRunRequest = StartPlayRunRequest;
68
79
 
80
+ export type PlayRunStartOptions = {
81
+ signal?: AbortSignal;
82
+ onSubmission?: (intent: {
83
+ workflowId: string;
84
+ orgId: string;
85
+ request: Record<string, unknown>;
86
+ }) => void | Promise<void>;
87
+ /** @internal CLI JSON admission checks compatibility in the same request. */
88
+ cliAdmission?: boolean;
89
+ };
90
+
91
+ /** Only the transport can prove that the named action never dispatched. */
92
+ export class CliPlayAdmissionUnsupportedError extends DeeplineError {
93
+ constructor(status: number) {
94
+ super(
95
+ 'This server does not support CLI Play admission.',
96
+ status,
97
+ 'CLI_PLAY_ADMISSION_UNSUPPORTED',
98
+ );
99
+ }
100
+ }
101
+
69
102
  /** The exact JSON body `POST /api/v2/plays/run` receives. Key order is part of the contract. */
70
103
  export function buildPlayRunStartBody(
71
104
  request: ResolvedStartPlayRunRequest,
@@ -122,6 +155,7 @@ export function buildPlayRunStartBody(
122
155
  ...(typeof request.waitForCompletionMs === 'number'
123
156
  ? { waitForCompletionMs: request.waitForCompletionMs }
124
157
  : {}),
158
+ ...(request.terminalStatus === 'full' ? { terminalStatus: 'full' } : {}),
125
159
  // Profile selection is the API's job, not the caller's. The server
126
160
  // defaults to absurd; callers normally omit this field.
127
161
  ...(request.profile ? { profile: request.profile } : {}),
@@ -154,6 +188,7 @@ export async function preparePlayRunAdmission(
154
188
  orgId: string;
155
189
  request: Record<string, unknown>;
156
190
  }) => void | Promise<void>,
191
+ options?: { signal?: AbortSignal },
157
192
  ): Promise<{
158
193
  body: Record<string, unknown>;
159
194
  workflowId?: string;
@@ -168,7 +203,7 @@ export async function preparePlayRunAdmission(
168
203
  } | null = null;
169
204
  if (http.get) {
170
205
  try {
171
- capability = await http.get(PLAY_RUN_START_PATH);
206
+ capability = await http.get(PLAY_RUN_START_PATH, options);
172
207
  } catch (error) {
173
208
  if (
174
209
  !(error instanceof DeeplineError) ||
@@ -193,6 +228,7 @@ export async function preparePlayRunAdmission(
193
228
  }
194
229
  const supportsCallerIntent =
195
230
  capability?.admissionContract === 'caller-intent-v1';
231
+ options?.signal?.throwIfAborted();
196
232
  if (
197
233
  supportsCallerIntent &&
198
234
  (!capability?.orgId ||
@@ -211,6 +247,23 @@ export async function preparePlayRunAdmission(
211
247
  'PLAY_RUN_ADMISSION_RECOVERY_UNSUPPORTED',
212
248
  );
213
249
  }
250
+ if (
251
+ request.maxTotalCredits !== undefined &&
252
+ capability?.strictTotalBudget === 'unbounded-v1'
253
+ ) {
254
+ if (request.maxTotalCredits === 0) {
255
+ throw new DeeplineError(
256
+ 'A zero-credit total budget cannot admit a Play: sandbox compute is billed even when provider tools are free.',
257
+ 422,
258
+ 'PLAY_TOTAL_BUDGET_COMPUTE_REQUIRED',
259
+ );
260
+ }
261
+ throw new DeeplineError(
262
+ 'A strict total Play budget cannot currently be admitted: provider operations, Customer DB compute, and additional sandbox sessions do not have a finite admitted upper bound.',
263
+ 422,
264
+ 'PLAY_TOTAL_BUDGET_UNBOUNDED',
265
+ );
266
+ }
214
267
  if (
215
268
  request.maxTotalCredits !== undefined &&
216
269
  capability?.strictTotalBudget !== 'fail-closed-v1'
@@ -267,26 +320,49 @@ export async function startPlayRun(
267
320
  http: PlayRunHttp,
268
321
  request: ResolvedStartPlayRunRequest,
269
322
  headers?: Record<string, string>,
270
- onSubmission?: (intent: {
271
- workflowId: string;
272
- orgId: string;
273
- request: Record<string, unknown>;
274
- }) => void | Promise<void>,
323
+ options?: PlayRunStartOptions,
275
324
  ): Promise<PlayRunStart> {
276
325
  const {
277
326
  body: submittedBody,
278
327
  workflowId,
279
328
  supportsCallerIntent,
280
- } = await preparePlayRunAdmission(http, request, onSubmission);
329
+ } = await preparePlayRunAdmission(
330
+ http,
331
+ request,
332
+ options?.onSubmission,
333
+ options,
334
+ );
335
+ let cliAdmissionSupported = false;
281
336
  let response: Record<string, unknown>;
282
337
  try {
283
338
  response = await http.post<Record<string, unknown>>(
284
- PLAY_RUN_START_PATH,
339
+ options?.cliAdmission ? CLI_PLAY_RUN_START_PATH : PLAY_RUN_START_PATH,
285
340
  submittedBody,
286
341
  headers,
287
- { maxRetries: 0, exactUrlOnly: true },
342
+ {
343
+ maxRetries: 0,
344
+ exactUrlOnly: true,
345
+ ...(options?.signal ? { signal: options.signal } : {}),
346
+ ...(options?.cliAdmission
347
+ ? {
348
+ onResponse: (response: Response) => {
349
+ cliAdmissionSupported =
350
+ response.headers.get(CLI_PLAY_RUN_SUPPORTED_HEADER) ===
351
+ 'true';
352
+ },
353
+ }
354
+ : {}),
355
+ },
288
356
  );
289
357
  } catch (error) {
358
+ if (
359
+ options?.cliAdmission &&
360
+ !cliAdmissionSupported &&
361
+ error instanceof DeeplineError &&
362
+ (error.statusCode === 404 || error.statusCode === 405)
363
+ ) {
364
+ throw new CliPlayAdmissionUnsupportedError(error.statusCode);
365
+ }
290
366
  if (
291
367
  (error instanceof DeeplineError &&
292
368
  ['NETWORK_TIMEOUT', 'NETWORK_ERROR', 'FETCH_FAILED'].includes(
@@ -320,7 +396,18 @@ export async function startPlayRun(
320
396
  }
321
397
  throw error;
322
398
  }
323
- return normalizePlayRunStart(response);
399
+ const started = normalizePlayRunStart(response);
400
+ if (
401
+ options?.cliAdmission &&
402
+ (!started.workflowId || started.workflowId === 'pending')
403
+ ) {
404
+ throw new DeeplineError(
405
+ 'Play admission returned no run id. Check recent runs before submitting again.',
406
+ undefined,
407
+ 'PLAY_START_MISSING_RUN_ID',
408
+ );
409
+ }
410
+ return started;
324
411
  }
325
412
 
326
413
  export function isPlayRunPackage(value: unknown): value is PlayRunPackage {
@@ -367,7 +454,9 @@ export function normalizePlayRunStart(
367
454
  ? { dashboardUrl: runPackage.run.dashboardUrl }
368
455
  : {}),
369
456
  ...(isTerminalPlayRunLifecycleStatus(status)
370
- ? { finalStatus: runPackage }
457
+ ? raw.finalStatusView === 'full' && raw.runId === runPackage.run.id
458
+ ? { finalStatus: raw, finalStatusView: 'full' as const }
459
+ : { finalStatus: runPackage }
371
460
  : {}),
372
461
  package: runPackage,
373
462
  };
@@ -1018,12 +1107,13 @@ export function createSessionPlayRunHttp(
1018
1107
  return parsed as T;
1019
1108
  };
1020
1109
  return {
1021
- get: (path) => send(path, { method: 'GET' }),
1022
- post: (path, body, headers) =>
1110
+ get: (path, options) => send(path, { method: 'GET', ...options }),
1111
+ post: (path, body, headers, options) =>
1023
1112
  send(path, {
1024
1113
  method: 'POST',
1025
1114
  headers: { 'content-type': 'application/json', ...headers },
1026
1115
  body: JSON.stringify(body),
1116
+ ...(options?.signal ? { signal: options.signal } : {}),
1027
1117
  }),
1028
1118
  postFormData: (path, formData) =>
1029
1119
  send(path, {
@@ -139,11 +139,14 @@ export type SdkRelease = {
139
139
  */
140
140
  version: string;
141
141
  /**
142
- * One concise, agent-readable explanation shown while this release is an
143
- * available update. Keep it actionable; the compatibility route includes it
144
- * in its existing update message so older installed CLIs can print it too.
142
+ * One concise, agent-readable explanation of what a named release changed.
143
+ * The compatibility route shows it only to clients older than
144
+ * `introducedIn`, labelled with that version. `version` above is bumped on
145
+ * every publish while this text is written by hand, so labelling it with the
146
+ * latest version would repeat the same line for releases it does not
147
+ * describe. Keep it actionable; older installed CLIs print it too.
145
148
  */
146
- updateSummary?: string;
149
+ updateSummary?: { introducedIn: string; summary: string };
147
150
  /** Capabilities stamped into the published package's `deepline` metadata. */
148
151
  packageCapabilities: {
149
152
  updatePreferences: 1;
@@ -202,9 +205,12 @@ export const SDK_RELEASE = {
202
205
  // getters keep their established compatibility behavior.
203
206
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
204
207
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
205
- version: '0.3.409',
206
- updateSummary:
207
- 'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
208
+ version: '0.3.410',
209
+ updateSummary: {
210
+ introducedIn: '0.3.90',
211
+ summary:
212
+ 'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
213
+ },
208
214
  packageCapabilities: {
209
215
  updatePreferences: 1,
210
216
  skillsGuidance: 1,