deepline 0.1.208 → 0.1.210

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 (39) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +0 -2
  2. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +102 -138
  3. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +2 -12
  4. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +12 -4
  5. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +25 -92
  6. package/dist/bundling-sources/sdk/src/client.ts +10 -0
  7. package/dist/bundling-sources/sdk/src/play.ts +2 -2
  8. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  9. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +16 -31
  10. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +18 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/child-run-id.ts +4 -5
  12. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +316 -232
  13. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +16 -2
  14. package/dist/bundling-sources/shared_libs/play-runtime/daytona-runtime-config.ts +0 -5
  15. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +2 -4
  16. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +1 -0
  17. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +429 -102
  18. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +27 -5
  19. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +18 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +31 -12
  21. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +103 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +105 -10
  23. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +21 -1
  24. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +32 -86
  25. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +141 -2
  26. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +45 -0
  27. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +180 -447
  28. package/dist/bundling-sources/shared_libs/play-runtime/runtime-constants.ts +12 -0
  29. package/dist/bundling-sources/shared_libs/play-runtime/suspension.ts +33 -1
  30. package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +11 -0
  31. package/dist/bundling-sources/shared_libs/plays/artifact-kind-guard.ts +112 -0
  32. package/dist/cli/index.js +33 -8
  33. package/dist/cli/index.mjs +33 -8
  34. package/dist/index.d.mts +11 -2
  35. package/dist/index.d.ts +11 -2
  36. package/dist/index.js +26 -4
  37. package/dist/index.mjs +26 -4
  38. package/package.json +1 -1
  39. package/dist/bundling-sources/shared_libs/play-runtime/child-run-lifecycle.ts +0 -70
@@ -10,3 +10,15 @@ export const PLAY_RUNNER_TIMEOUT_SECONDS = 30 * 60;
10
10
 
11
11
  /** TTL for workflow executor tokens, in seconds. */
12
12
  export const WORKFLOW_EXECUTOR_TOKEN_TTL_SECONDS = PLAY_RUNNER_TIMEOUT_SECONDS;
13
+
14
+ /**
15
+ * Absurd run-claim lease window, in seconds. The scheduler expires a claim whose
16
+ * `claim_expires_at` falls this far behind, so whoever owns execution must renew
17
+ * within this window. Shared between the worker's own lease heartbeat and the
18
+ * Daytona push-execution runner (which heartbeats the receipt gateway on a
19
+ * `RUNTIME_CLAIM_LEASE_SECONDS / 3` cadence) so both agree on the deadline.
20
+ */
21
+ export const RUNTIME_CLAIM_LEASE_SECONDS = 120;
22
+
23
+ /** Heartbeat cadence divisor: renew the claim this many times per lease window. */
24
+ export const RUNTIME_CLAIM_HEARTBEAT_DIVISOR = 3;
@@ -31,8 +31,38 @@ export type PlayExecutionSuspension =
31
31
  childRunId: string;
32
32
  childPlayName: string;
33
33
  }>;
34
+ }
35
+ | {
36
+ /**
37
+ * Push-execution park (B2-final): the Daytona runner command was started
38
+ * DETACHED and the worker parks instead of holding anything. The parked
39
+ * attempt wakes on the runner's pushed terminal (the gateway emits the
40
+ * absurd wake event) or on the ceiling timeout, then finalizes from
41
+ * persisted state.
42
+ */
43
+ kind: 'detached_runner';
44
+ boundaryId: string;
45
+ /** Attempt generation whose executor token the detached runner holds —
46
+ * the key under which its pushed terminal is recorded and its wake event
47
+ * is named. */
48
+ runnerAttempt: number;
49
+ sandboxId: string;
50
+ sessionId: string;
51
+ cmdId: string;
52
+ /** Captured output/exit-code file paths inside the sandbox, used by the
53
+ * timeout-wake salvage verification. */
54
+ outputPath: string;
55
+ exitCodePath: string;
56
+ startedAtMs: number;
57
+ /** Overall run ceiling; the park timeout. */
58
+ ceilingMs: number;
34
59
  };
35
60
 
61
+ export type DetachedRunnerSuspension = Extract<
62
+ PlayExecutionSuspension,
63
+ { kind: 'detached_runner' }
64
+ >;
65
+
36
66
  export class PlayExecutionSuspendedError extends Error {
37
67
  readonly suspension: PlayExecutionSuspension;
38
68
 
@@ -46,7 +76,9 @@ export class PlayExecutionSuspendedError extends Error {
46
76
  ? `Play execution suspended waiting for ${suspension.boundaries.length} child plays.`
47
77
  : suspension.kind === 'child_play'
48
78
  ? `Play execution suspended waiting for child play ${JSON.stringify(suspension.childPlayName)}.`
49
- : `Play execution suspended waiting for integration event ${JSON.stringify(suspension.eventKey)}.`,
79
+ : suspension.kind === 'detached_runner'
80
+ ? `Play execution parked on detached runner ${suspension.cmdId} (sandbox ${suspension.sandboxId}).`
81
+ : `Play execution suspended waiting for integration event ${JSON.stringify(suspension.eventKey)}.`,
50
82
  );
51
83
  this.name = 'PlayExecutionSuspendedError';
52
84
  this.suspension = suspension;
@@ -97,6 +97,16 @@ function normalizeHardBillingPayload(
97
97
  };
98
98
  }
99
99
 
100
+ function receiptFailureKindForToolErrorPayload(
101
+ payload: Record<string, unknown> | null,
102
+ ): WorkReceiptFailureKind {
103
+ const code = getStringField(payload, 'code')?.toUpperCase();
104
+ // A credential connection can be added or replaced between play runs. Keep
105
+ // the failure terminal within its owning run, but let a later run reclaim
106
+ // the durable receipt instead of replaying stale authorization state.
107
+ return code === 'INTEGRATION_CREDENTIALS_MISSING' ? 'repairable' : 'terminal';
108
+ }
109
+
100
110
  function formatHardBillingFailureMessage(input: {
101
111
  billing: Record<string, unknown>;
102
112
  toolId: string;
@@ -226,6 +236,7 @@ export function normalizeToolHttpErrorMessage(input: {
226
236
  )}`,
227
237
  billing,
228
238
  input.status,
239
+ receiptFailureKindForToolErrorPayload(parsed),
229
240
  );
230
241
  }
231
242
 
@@ -0,0 +1,112 @@
1
+ import type { PlayArtifactKind, PlayBundleArtifact } from './artifact-types';
2
+
3
+ /**
4
+ * Loud, directional guard that stops a Cloudflare-Workers (`esm_workers`)
5
+ * bundle from reaching a Node/Daytona (`cjs_node20`) runner.
6
+ *
7
+ * The Node runner loads play code with `Module._compile`, which cannot resolve
8
+ * `cloudflare:workers` scheme imports and dies with the opaque
9
+ * `ERR_UNSUPPORTED_ESM_URL_SCHEME: Received protocol 'cloudflare:'`. Those
10
+ * imports only exist in the Cloudflare Workers harness apps
11
+ * (`apps/play-runner-workers/`, `apps/play-harness-worker/`) baked into
12
+ * `esm_workers` artifacts. When the wrong artifact kind is targeted for a node
13
+ * profile (e.g. the absurd/Daytona scheduler falling back to a verbatim stored
14
+ * `esm_workers` bundle), this guard fires at the targeting/load seam with a
15
+ * message that names the mismatch instead of surfacing the ESM scheme error.
16
+ */
17
+
18
+ /**
19
+ * Legacy artifacts predate the `artifactKind` field; they are always
20
+ * `cjs_node20` (the only kind that existed before the workers split). Mirror the
21
+ * default documented on `PlayBundleArtifact.artifactKind`.
22
+ */
23
+ export function artifactKindOf(artifact: PlayBundleArtifact): PlayArtifactKind {
24
+ return artifact.artifactKind ?? 'cjs_node20';
25
+ }
26
+
27
+ /**
28
+ * Detect `cloudflare:` scheme imports in bundled code. Matches both static
29
+ * `import ... from 'cloudflare:workers'` and `require('cloudflare:...')` forms,
30
+ * with single or double quotes. This is the exact shape the Node runner cannot
31
+ * load.
32
+ */
33
+ const CLOUDFLARE_SCHEME_IMPORT =
34
+ /(?:\bfrom\s*|\bimport\s*|\brequire\s*\(\s*)['"]cloudflare:[^'"]*['"]/;
35
+
36
+ export function bundledCodeHasCloudflareSchemeImport(
37
+ bundledCode: string,
38
+ ): boolean {
39
+ return CLOUDFLARE_SCHEME_IMPORT.test(bundledCode);
40
+ }
41
+
42
+ export class PlayArtifactKindMismatchError extends Error {
43
+ readonly expectedKind: PlayArtifactKind;
44
+ readonly actualKind: PlayArtifactKind;
45
+ readonly reason: 'kind_mismatch' | 'cloudflare_scheme_import';
46
+
47
+ constructor(input: {
48
+ expectedKind: PlayArtifactKind;
49
+ actualKind: PlayArtifactKind;
50
+ reason: 'kind_mismatch' | 'cloudflare_scheme_import';
51
+ message: string;
52
+ }) {
53
+ super(input.message);
54
+ this.name = 'PlayArtifactKindMismatchError';
55
+ this.expectedKind = input.expectedKind;
56
+ this.actualKind = input.actualKind;
57
+ this.reason = input.reason;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Assert an artifact is loadable by the Node (`cjs_node20`) runner. Throws a
63
+ * `PlayArtifactKindMismatchError` naming the run/profile and expected vs actual
64
+ * kind if the artifact is an `esm_workers` bundle or carries `cloudflare:`
65
+ * scheme imports.
66
+ *
67
+ * `context` is a short human-readable locator (run id, play name, submit path)
68
+ * woven into the error so the failure points at the wrong targeting decision,
69
+ * not the downstream ESM scheme error.
70
+ */
71
+ export function assertNodeRunnableArtifact(input: {
72
+ artifact: PlayBundleArtifact;
73
+ expectedKind: PlayArtifactKind;
74
+ context: string;
75
+ }): void {
76
+ const { artifact, expectedKind, context } = input;
77
+ if (expectedKind !== 'cjs_node20') {
78
+ // This helper only guards the node runner. A workers-edge target never
79
+ // reaches the Node/Daytona load path, so there is nothing to assert.
80
+ return;
81
+ }
82
+
83
+ const actualKind = artifactKindOf(artifact);
84
+ if (actualKind !== 'cjs_node20') {
85
+ throw new PlayArtifactKindMismatchError({
86
+ expectedKind,
87
+ actualKind,
88
+ reason: 'kind_mismatch',
89
+ message:
90
+ `Node runner (${context}) received a "${actualKind}" play artifact but ` +
91
+ `requires "cjs_node20". An "esm_workers" bundle embeds the Cloudflare ` +
92
+ `Workers harness (cloudflare:workers imports) and cannot load under ` +
93
+ `Module._compile. Rebundle/republish the play for the node runner ` +
94
+ `(profile=absurd / backend=daytona|local_process) instead of serving ` +
95
+ `the stored workers artifact verbatim.`,
96
+ });
97
+ }
98
+
99
+ if (bundledCodeHasCloudflareSchemeImport(artifact.bundledCode)) {
100
+ throw new PlayArtifactKindMismatchError({
101
+ expectedKind,
102
+ actualKind,
103
+ reason: 'cloudflare_scheme_import',
104
+ message:
105
+ `Node runner (${context}) received a play artifact tagged ` +
106
+ `"cjs_node20" whose bundledCode still contains a cloudflare: scheme ` +
107
+ `import. This bundle would die with ERR_UNSUPPORTED_ESM_URL_SCHEME ` +
108
+ `under Module._compile. The artifact was mis-tagged or mis-targeted; ` +
109
+ `rebundle for the node runner.`,
110
+ });
111
+ }
112
+ }
package/dist/cli/index.js CHANGED
@@ -623,10 +623,10 @@ var SDK_RELEASE = {
623
623
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
624
624
  // fields shipped in 0.1.153.
625
625
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
626
- version: "0.1.208",
626
+ version: "0.1.210",
627
627
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
628
628
  supportPolicy: {
629
- latest: "0.1.208",
629
+ latest: "0.1.210",
630
630
  minimumSupported: "0.1.53",
631
631
  deprecatedBelow: "0.1.53",
632
632
  commandMinimumSupported: [
@@ -1408,6 +1408,25 @@ function normalizePlayRunLedgerStatus(value) {
1408
1408
  return "unknown";
1409
1409
  }
1410
1410
  }
1411
+ function summarizeRunRowOutcomes(snapshot) {
1412
+ let completedRows = 0;
1413
+ let failedRows = 0;
1414
+ let totalRows = 0;
1415
+ for (const step of Object.values(snapshot.stepsById)) {
1416
+ const progress = step.progress;
1417
+ if (!progress) continue;
1418
+ completedRows += Math.max(0, finiteNumber(progress.completed) ?? 0);
1419
+ failedRows += Math.max(0, finiteNumber(progress.failed) ?? 0);
1420
+ const stepTotal = finiteNumber(progress.total);
1421
+ totalRows += stepTotal !== null && stepTotal >= 0 ? stepTotal : Math.max(0, finiteNumber(progress.completed) ?? 0) + Math.max(0, finiteNumber(progress.failed) ?? 0);
1422
+ }
1423
+ return {
1424
+ completedRows,
1425
+ failedRows,
1426
+ totalRows,
1427
+ hasRowFailures: failedRows > 0
1428
+ };
1429
+ }
1411
1430
  function createEmptyPlayRunLedgerSnapshot(input2) {
1412
1431
  const status = normalizePlayRunLedgerStatus(input2.status ?? "unknown");
1413
1432
  const startedAt = finiteNumber(input2.startedAt) ?? null;
@@ -1627,9 +1646,11 @@ function buildSnapshotFromLedger(snapshot) {
1627
1646
  completedAt: step.completedAt ?? null,
1628
1647
  updatedAt: step.updatedAt ?? null
1629
1648
  }));
1649
+ const liveStatus = normalizePlayRunLiveStatus(snapshot.status);
1650
+ const rowOutcomes = isTerminalPlayRunLiveStatus(liveStatus) && Object.keys(snapshot.stepsById).length > 0 ? summarizeRunRowOutcomes(snapshot) : null;
1630
1651
  return {
1631
1652
  runId: snapshot.runId,
1632
- status: normalizePlayRunLiveStatus(snapshot.status),
1653
+ status: liveStatus,
1633
1654
  createdAt: snapshot.createdAt ?? null,
1634
1655
  startedAt: snapshot.startedAt ?? null,
1635
1656
  finishedAt: snapshot.finishedAt ?? null,
@@ -1641,7 +1662,8 @@ function buildSnapshotFromLedger(snapshot) {
1641
1662
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1642
1663
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1643
1664
  nodeStates,
1644
- activeNodeId: snapshot.activeStepId ?? null
1665
+ activeNodeId: snapshot.activeStepId ?? null,
1666
+ ...rowOutcomes ? { rowOutcomes } : {}
1645
1667
  };
1646
1668
  }
1647
1669
  function buildPlayRunStatusSnapshot(input2) {
@@ -14599,12 +14621,18 @@ async function handlePlayCheck(args) {
14599
14621
  }
14600
14622
  const client2 = new DeeplineClient();
14601
14623
  const integrationMode = resolveEvalIntegrationMode();
14624
+ const importedPlays = [...graph.nodes.values()].filter((node) => node.filePath !== graph.root.filePath).map((node) => ({
14625
+ playName: node.playName,
14626
+ sourceCode: node.sourceCode,
14627
+ sourcePath: node.filePath
14628
+ }));
14602
14629
  const result = await client2.checkPlayArtifact({
14603
14630
  name: playName,
14604
14631
  sourceCode: graph.root.sourceCode,
14605
14632
  sourceFiles: graph.root.sourceFiles,
14606
14633
  description: graph.root.playDescription ?? void 0,
14607
14634
  artifact: graph.root.artifact,
14635
+ ...importedPlays.length > 0 ? { importedPlays } : {},
14608
14636
  ...integrationMode ? { integrationMode } : {}
14609
14637
  });
14610
14638
  const enrichedResult = {
@@ -17187,12 +17215,9 @@ function renderColumnRunIfFunction(command) {
17187
17215
  if (!command.run_if_js) {
17188
17216
  return null;
17189
17217
  }
17190
- if (command.play) {
17191
- return `(__dlRawRow) => { const row = __dlPrepareEnrichRow(__dlRawRow, [${stringLiteral(command.alias)}]); const input = row; const context = row;
17218
+ return `(__dlRawRow) => { const row = __dlPrepareEnrichRow(__dlRawRow, [${stringLiteral(command.alias)}]); const input = row; const context = row;
17192
17219
  ${indent(renderJavascriptBody(command.run_if_js), 6)}
17193
17220
  }`;
17194
- }
17195
- return renderRunIfFunction(command);
17196
17221
  }
17197
17222
  function renderCombinedRunIfFunction(precheck, runIfSource) {
17198
17223
  if (!runIfSource) {
@@ -608,10 +608,10 @@ var SDK_RELEASE = {
608
608
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
609
609
  // fields shipped in 0.1.153.
610
610
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
611
- version: "0.1.208",
611
+ version: "0.1.210",
612
612
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
613
613
  supportPolicy: {
614
- latest: "0.1.208",
614
+ latest: "0.1.210",
615
615
  minimumSupported: "0.1.53",
616
616
  deprecatedBelow: "0.1.53",
617
617
  commandMinimumSupported: [
@@ -1393,6 +1393,25 @@ function normalizePlayRunLedgerStatus(value) {
1393
1393
  return "unknown";
1394
1394
  }
1395
1395
  }
1396
+ function summarizeRunRowOutcomes(snapshot) {
1397
+ let completedRows = 0;
1398
+ let failedRows = 0;
1399
+ let totalRows = 0;
1400
+ for (const step of Object.values(snapshot.stepsById)) {
1401
+ const progress = step.progress;
1402
+ if (!progress) continue;
1403
+ completedRows += Math.max(0, finiteNumber(progress.completed) ?? 0);
1404
+ failedRows += Math.max(0, finiteNumber(progress.failed) ?? 0);
1405
+ const stepTotal = finiteNumber(progress.total);
1406
+ totalRows += stepTotal !== null && stepTotal >= 0 ? stepTotal : Math.max(0, finiteNumber(progress.completed) ?? 0) + Math.max(0, finiteNumber(progress.failed) ?? 0);
1407
+ }
1408
+ return {
1409
+ completedRows,
1410
+ failedRows,
1411
+ totalRows,
1412
+ hasRowFailures: failedRows > 0
1413
+ };
1414
+ }
1396
1415
  function createEmptyPlayRunLedgerSnapshot(input2) {
1397
1416
  const status = normalizePlayRunLedgerStatus(input2.status ?? "unknown");
1398
1417
  const startedAt = finiteNumber(input2.startedAt) ?? null;
@@ -1612,9 +1631,11 @@ function buildSnapshotFromLedger(snapshot) {
1612
1631
  completedAt: step.completedAt ?? null,
1613
1632
  updatedAt: step.updatedAt ?? null
1614
1633
  }));
1634
+ const liveStatus = normalizePlayRunLiveStatus(snapshot.status);
1635
+ const rowOutcomes = isTerminalPlayRunLiveStatus(liveStatus) && Object.keys(snapshot.stepsById).length > 0 ? summarizeRunRowOutcomes(snapshot) : null;
1615
1636
  return {
1616
1637
  runId: snapshot.runId,
1617
- status: normalizePlayRunLiveStatus(snapshot.status),
1638
+ status: liveStatus,
1618
1639
  createdAt: snapshot.createdAt ?? null,
1619
1640
  startedAt: snapshot.startedAt ?? null,
1620
1641
  finishedAt: snapshot.finishedAt ?? null,
@@ -1626,7 +1647,8 @@ function buildSnapshotFromLedger(snapshot) {
1626
1647
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1627
1648
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1628
1649
  nodeStates,
1629
- activeNodeId: snapshot.activeStepId ?? null
1650
+ activeNodeId: snapshot.activeStepId ?? null,
1651
+ ...rowOutcomes ? { rowOutcomes } : {}
1630
1652
  };
1631
1653
  }
1632
1654
  function buildPlayRunStatusSnapshot(input2) {
@@ -14628,12 +14650,18 @@ async function handlePlayCheck(args) {
14628
14650
  }
14629
14651
  const client2 = new DeeplineClient();
14630
14652
  const integrationMode = resolveEvalIntegrationMode();
14653
+ const importedPlays = [...graph.nodes.values()].filter((node) => node.filePath !== graph.root.filePath).map((node) => ({
14654
+ playName: node.playName,
14655
+ sourceCode: node.sourceCode,
14656
+ sourcePath: node.filePath
14657
+ }));
14631
14658
  const result = await client2.checkPlayArtifact({
14632
14659
  name: playName,
14633
14660
  sourceCode: graph.root.sourceCode,
14634
14661
  sourceFiles: graph.root.sourceFiles,
14635
14662
  description: graph.root.playDescription ?? void 0,
14636
14663
  artifact: graph.root.artifact,
14664
+ ...importedPlays.length > 0 ? { importedPlays } : {},
14637
14665
  ...integrationMode ? { integrationMode } : {}
14638
14666
  });
14639
14667
  const enrichedResult = {
@@ -17216,12 +17244,9 @@ function renderColumnRunIfFunction(command) {
17216
17244
  if (!command.run_if_js) {
17217
17245
  return null;
17218
17246
  }
17219
- if (command.play) {
17220
- return `(__dlRawRow) => { const row = __dlPrepareEnrichRow(__dlRawRow, [${stringLiteral(command.alias)}]); const input = row; const context = row;
17247
+ return `(__dlRawRow) => { const row = __dlPrepareEnrichRow(__dlRawRow, [${stringLiteral(command.alias)}]); const input = row; const context = row;
17221
17248
  ${indent(renderJavascriptBody(command.run_if_js), 6)}
17222
17249
  }`;
17223
- }
17224
- return renderRunIfFunction(command);
17225
17250
  }
17226
17251
  function renderCombinedRunIfFunction(precheck, runIfSource) {
17227
17252
  if (!runIfSource) {
package/dist/index.d.mts CHANGED
@@ -1811,6 +1811,16 @@ declare class DeeplineClient {
1811
1811
  description?: string;
1812
1812
  artifact: Record<string, unknown>;
1813
1813
  integrationMode?: 'live' | 'eval_stub' | 'fixture';
1814
+ /**
1815
+ * Sibling plays from the same local bundle graph. Lets the server splice
1816
+ * unpublished local children into the checked plan and enforce the
1817
+ * row-scoped batch rule (ADR 0013).
1818
+ */
1819
+ importedPlays?: Array<{
1820
+ playName?: string | null;
1821
+ sourceCode: string;
1822
+ sourcePath?: string | null;
1823
+ }>;
1814
1824
  }): Promise<PlayCheckResult>;
1815
1825
  /**
1816
1826
  * Compile legacy enrich command arguments into a runtime plan.
@@ -3209,7 +3219,7 @@ type StepOptions<Row, Value = unknown> = {
3209
3219
  * Legacy dataset-column recompute flag accepted for older authored plays.
3210
3220
  *
3211
3221
  * Prefer putting freshness on the actual reusable call
3212
- * (`ctx.tools.execute`, `ctx.step`, `ctx.fetch`, or `ctx.runPlay`).
3222
+ * (`ctx.tools.execute`, `ctx.step`, or `ctx.fetch`).
3213
3223
  */
3214
3224
  readonly recompute?: boolean;
3215
3225
  /** Legacy error-recompute flag accepted for older authored plays. */
@@ -3597,7 +3607,6 @@ interface DeeplinePlayRuntimeContext {
3597
3607
  */
3598
3608
  runPlay<TOutput = unknown>(key: string, playRef: string | PlayReferenceLike, input: Record<string, unknown>, options: {
3599
3609
  description: string;
3600
- staleAfterSeconds?: number;
3601
3610
  }): Promise<TOutput>;
3602
3611
  /**
3603
3612
  * Emit a log line visible in `play tail` and the play's progress logs.
package/dist/index.d.ts CHANGED
@@ -1811,6 +1811,16 @@ declare class DeeplineClient {
1811
1811
  description?: string;
1812
1812
  artifact: Record<string, unknown>;
1813
1813
  integrationMode?: 'live' | 'eval_stub' | 'fixture';
1814
+ /**
1815
+ * Sibling plays from the same local bundle graph. Lets the server splice
1816
+ * unpublished local children into the checked plan and enforce the
1817
+ * row-scoped batch rule (ADR 0013).
1818
+ */
1819
+ importedPlays?: Array<{
1820
+ playName?: string | null;
1821
+ sourceCode: string;
1822
+ sourcePath?: string | null;
1823
+ }>;
1814
1824
  }): Promise<PlayCheckResult>;
1815
1825
  /**
1816
1826
  * Compile legacy enrich command arguments into a runtime plan.
@@ -3209,7 +3219,7 @@ type StepOptions<Row, Value = unknown> = {
3209
3219
  * Legacy dataset-column recompute flag accepted for older authored plays.
3210
3220
  *
3211
3221
  * Prefer putting freshness on the actual reusable call
3212
- * (`ctx.tools.execute`, `ctx.step`, `ctx.fetch`, or `ctx.runPlay`).
3222
+ * (`ctx.tools.execute`, `ctx.step`, or `ctx.fetch`).
3213
3223
  */
3214
3224
  readonly recompute?: boolean;
3215
3225
  /** Legacy error-recompute flag accepted for older authored plays. */
@@ -3597,7 +3607,6 @@ interface DeeplinePlayRuntimeContext {
3597
3607
  */
3598
3608
  runPlay<TOutput = unknown>(key: string, playRef: string | PlayReferenceLike, input: Record<string, unknown>, options: {
3599
3609
  description: string;
3600
- staleAfterSeconds?: number;
3601
3610
  }): Promise<TOutput>;
3602
3611
  /**
3603
3612
  * Emit a log line visible in `play tail` and the play's progress logs.
package/dist/index.js CHANGED
@@ -422,10 +422,10 @@ var SDK_RELEASE = {
422
422
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
423
423
  // fields shipped in 0.1.153.
424
424
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
425
- version: "0.1.208",
425
+ version: "0.1.210",
426
426
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
427
427
  supportPolicy: {
428
- latest: "0.1.208",
428
+ latest: "0.1.210",
429
429
  minimumSupported: "0.1.53",
430
430
  deprecatedBelow: "0.1.53",
431
431
  commandMinimumSupported: [
@@ -1207,6 +1207,25 @@ function normalizePlayRunLedgerStatus(value) {
1207
1207
  return "unknown";
1208
1208
  }
1209
1209
  }
1210
+ function summarizeRunRowOutcomes(snapshot) {
1211
+ let completedRows = 0;
1212
+ let failedRows = 0;
1213
+ let totalRows = 0;
1214
+ for (const step of Object.values(snapshot.stepsById)) {
1215
+ const progress = step.progress;
1216
+ if (!progress) continue;
1217
+ completedRows += Math.max(0, finiteNumber(progress.completed) ?? 0);
1218
+ failedRows += Math.max(0, finiteNumber(progress.failed) ?? 0);
1219
+ const stepTotal = finiteNumber(progress.total);
1220
+ totalRows += stepTotal !== null && stepTotal >= 0 ? stepTotal : Math.max(0, finiteNumber(progress.completed) ?? 0) + Math.max(0, finiteNumber(progress.failed) ?? 0);
1221
+ }
1222
+ return {
1223
+ completedRows,
1224
+ failedRows,
1225
+ totalRows,
1226
+ hasRowFailures: failedRows > 0
1227
+ };
1228
+ }
1210
1229
  function createEmptyPlayRunLedgerSnapshot(input) {
1211
1230
  const status = normalizePlayRunLedgerStatus(input.status ?? "unknown");
1212
1231
  const startedAt = finiteNumber(input.startedAt) ?? null;
@@ -1426,9 +1445,11 @@ function buildSnapshotFromLedger(snapshot) {
1426
1445
  completedAt: step.completedAt ?? null,
1427
1446
  updatedAt: step.updatedAt ?? null
1428
1447
  }));
1448
+ const liveStatus = normalizePlayRunLiveStatus(snapshot.status);
1449
+ const rowOutcomes = isTerminalPlayRunLiveStatus(liveStatus) && Object.keys(snapshot.stepsById).length > 0 ? summarizeRunRowOutcomes(snapshot) : null;
1429
1450
  return {
1430
1451
  runId: snapshot.runId,
1431
- status: normalizePlayRunLiveStatus(snapshot.status),
1452
+ status: liveStatus,
1432
1453
  createdAt: snapshot.createdAt ?? null,
1433
1454
  startedAt: snapshot.startedAt ?? null,
1434
1455
  finishedAt: snapshot.finishedAt ?? null,
@@ -1440,7 +1461,8 @@ function buildSnapshotFromLedger(snapshot) {
1440
1461
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1441
1462
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1442
1463
  nodeStates,
1443
- activeNodeId: snapshot.activeStepId ?? null
1464
+ activeNodeId: snapshot.activeStepId ?? null,
1465
+ ...rowOutcomes ? { rowOutcomes } : {}
1444
1466
  };
1445
1467
  }
1446
1468
  function buildPlayRunStatusSnapshot(input) {
package/dist/index.mjs CHANGED
@@ -352,10 +352,10 @@ var SDK_RELEASE = {
352
352
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
353
353
  // fields shipped in 0.1.153.
354
354
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
355
- version: "0.1.208",
355
+ version: "0.1.210",
356
356
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
357
357
  supportPolicy: {
358
- latest: "0.1.208",
358
+ latest: "0.1.210",
359
359
  minimumSupported: "0.1.53",
360
360
  deprecatedBelow: "0.1.53",
361
361
  commandMinimumSupported: [
@@ -1137,6 +1137,25 @@ function normalizePlayRunLedgerStatus(value) {
1137
1137
  return "unknown";
1138
1138
  }
1139
1139
  }
1140
+ function summarizeRunRowOutcomes(snapshot) {
1141
+ let completedRows = 0;
1142
+ let failedRows = 0;
1143
+ let totalRows = 0;
1144
+ for (const step of Object.values(snapshot.stepsById)) {
1145
+ const progress = step.progress;
1146
+ if (!progress) continue;
1147
+ completedRows += Math.max(0, finiteNumber(progress.completed) ?? 0);
1148
+ failedRows += Math.max(0, finiteNumber(progress.failed) ?? 0);
1149
+ const stepTotal = finiteNumber(progress.total);
1150
+ totalRows += stepTotal !== null && stepTotal >= 0 ? stepTotal : Math.max(0, finiteNumber(progress.completed) ?? 0) + Math.max(0, finiteNumber(progress.failed) ?? 0);
1151
+ }
1152
+ return {
1153
+ completedRows,
1154
+ failedRows,
1155
+ totalRows,
1156
+ hasRowFailures: failedRows > 0
1157
+ };
1158
+ }
1140
1159
  function createEmptyPlayRunLedgerSnapshot(input) {
1141
1160
  const status = normalizePlayRunLedgerStatus(input.status ?? "unknown");
1142
1161
  const startedAt = finiteNumber(input.startedAt) ?? null;
@@ -1356,9 +1375,11 @@ function buildSnapshotFromLedger(snapshot) {
1356
1375
  completedAt: step.completedAt ?? null,
1357
1376
  updatedAt: step.updatedAt ?? null
1358
1377
  }));
1378
+ const liveStatus = normalizePlayRunLiveStatus(snapshot.status);
1379
+ const rowOutcomes = isTerminalPlayRunLiveStatus(liveStatus) && Object.keys(snapshot.stepsById).length > 0 ? summarizeRunRowOutcomes(snapshot) : null;
1359
1380
  return {
1360
1381
  runId: snapshot.runId,
1361
- status: normalizePlayRunLiveStatus(snapshot.status),
1382
+ status: liveStatus,
1362
1383
  createdAt: snapshot.createdAt ?? null,
1363
1384
  startedAt: snapshot.startedAt ?? null,
1364
1385
  finishedAt: snapshot.finishedAt ?? null,
@@ -1370,7 +1391,8 @@ function buildSnapshotFromLedger(snapshot) {
1370
1391
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1371
1392
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1372
1393
  nodeStates,
1373
- activeNodeId: snapshot.activeStepId ?? null
1394
+ activeNodeId: snapshot.activeStepId ?? null,
1395
+ ...rowOutcomes ? { rowOutcomes } : {}
1374
1396
  };
1375
1397
  }
1376
1398
  function buildPlayRunStatusSnapshot(input) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.208",
3
+ "version": "0.1.210",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,70 +0,0 @@
1
- import type { RunExecutionScope } from './run-execution-scope';
2
-
3
- export type ChildRunPlacement = 'inline' | 'scheduled';
4
-
5
- export interface ChildRunLifecycleMetadata {
6
- placement: ChildRunPlacement;
7
- }
8
-
9
- export interface ChildRunLifecycleAdapter<
10
- Metadata extends ChildRunLifecycleMetadata,
11
- Result,
12
- > {
13
- open(scope: RunExecutionScope, metadata: Metadata): Promise<void> | void;
14
- started(scope: RunExecutionScope, metadata: Metadata): Promise<void> | void;
15
- complete(
16
- scope: RunExecutionScope,
17
- metadata: Metadata,
18
- result: Result,
19
- ): Promise<void> | void;
20
- fail(
21
- scope: RunExecutionScope,
22
- metadata: Metadata,
23
- error: unknown,
24
- ): Promise<void> | void;
25
- }
26
-
27
- export interface ExecuteChildRunLifecycleInput<
28
- Metadata extends ChildRunLifecycleMetadata,
29
- Result,
30
- > {
31
- scope: RunExecutionScope;
32
- metadata: Metadata;
33
- adapter: ChildRunLifecycleAdapter<Metadata, Result>;
34
- execute(
35
- scope: RunExecutionScope,
36
- metadata: Metadata,
37
- ): Promise<Result> | Result;
38
- }
39
-
40
- /**
41
- * Projects one logical child execution through its lifecycle. Placement is
42
- * descriptive metadata; inline and scheduled children use the same protocol.
43
- */
44
- export async function executeChildRunLifecycle<
45
- Metadata extends ChildRunLifecycleMetadata,
46
- Result,
47
- >(input: ExecuteChildRunLifecycleInput<Metadata, Result>): Promise<Result> {
48
- const { adapter, execute, metadata, scope } = input;
49
-
50
- let result: Result;
51
- try {
52
- await adapter.open(scope, metadata);
53
- await adapter.started(scope, metadata);
54
- result = await execute(scope, metadata);
55
- } catch (executionError) {
56
- try {
57
- await adapter.fail(scope, metadata, executionError);
58
- } catch (failureProjectionError) {
59
- throw new AggregateError(
60
- [executionError, failureProjectionError],
61
- 'Child run execution and failure projection both failed',
62
- { cause: executionError },
63
- );
64
- }
65
- throw executionError;
66
- }
67
-
68
- await adapter.complete(scope, metadata, result);
69
- return result;
70
- }