deepline 0.1.210 → 0.1.212

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 (40) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +203 -12
  2. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/customer-console.ts +23 -0
  3. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +15 -0
  4. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-latency-profile.ts +90 -0
  5. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +162 -100
  6. package/dist/bundling-sources/sdk/src/client.ts +118 -3
  7. package/dist/bundling-sources/sdk/src/play.ts +2 -0
  8. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +1 -1
  9. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  10. package/dist/bundling-sources/sdk/src/types.ts +47 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +253 -30
  12. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +365 -103
  13. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +12 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/dataset-id.ts +10 -4
  15. package/dist/bundling-sources/shared_libs/play-runtime/db-session.ts +9 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +45 -8
  17. package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +14 -2
  18. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +4 -2
  19. package/dist/bundling-sources/shared_libs/play-runtime/receipt-sql.ts +21 -1
  20. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +128 -6
  21. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +7 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +5 -1
  23. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +37 -5
  24. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +19 -10
  25. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +63 -7
  26. package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +18 -4
  27. package/dist/bundling-sources/shared_libs/play-runtime/single-flight.ts +31 -0
  28. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +12 -1
  29. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +29 -9
  30. package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-state-machine.ts +22 -1
  31. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +79 -1
  32. package/dist/bundling-sources/shared_libs/plays/dataset.ts +41 -5
  33. package/dist/cli/index.js +728 -239
  34. package/dist/cli/index.mjs +728 -239
  35. package/dist/index.d.mts +93 -7
  36. package/dist/index.d.ts +93 -7
  37. package/dist/index.js +245 -46
  38. package/dist/index.mjs +245 -46
  39. package/dist/plays/bundle-play-file.mjs +65 -4
  40. package/package.json +1 -1
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.210",
626
+ version: "0.1.212",
627
627
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
628
628
  supportPolicy: {
629
- latest: "0.1.210",
629
+ latest: "0.1.212",
630
630
  minimumSupported: "0.1.53",
631
631
  deprecatedBelow: "0.1.53",
632
632
  commandMinimumSupported: [
@@ -1359,9 +1359,91 @@ function normalizePlayRunLedgerTerminalSource(value) {
1359
1359
  ) ? value : null;
1360
1360
  }
1361
1361
 
1362
+ // ../shared_libs/play-runtime/secret-redaction.ts
1363
+ var SECRET_REDACTION_PLACEHOLDER = "[REDACTED_SECRET]";
1364
+ var BEARER_TOKEN_RE = /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/g;
1365
+ var JWT_RE = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g;
1366
+ var PRIVATE_KEY_RE = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g;
1367
+ var COMMON_SECRET_RE = /\b(?:sk|pk|rk|pat|ghp|github_pat|xox[baprs]|key|token|secret|api[_-]?key)[A-Za-z0-9_./+=:-]{12,}\b/gi;
1368
+ var URL_SECRET_VALUE_RE = /\b(?:sk|pk|rk|pat|ghp|github_pat|xox)[A-Za-z0-9_./+=:-]{12,}\b/i;
1369
+ var HIGH_ENTROPY_ASSIGNMENT_RE = /\b(?:api[_-]?key|token|secret|password|authorization|access[_-]?token|refresh[_-]?token)\b\s*[:=]\s*["']?[^"',\s]{16,}["']?/gi;
1370
+ var SENSITIVE_URL_PARAM_RE = /[?#&](?:\w*(?:key|token)|secret|password|authorization|credential|signature|sig)(?:=|$)/i;
1371
+ function escapeRegExp(value) {
1372
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1373
+ }
1374
+ function isRecord(value) {
1375
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1376
+ }
1377
+ function redactSecretLikeString(value) {
1378
+ const trimmed = value.trim();
1379
+ if (/^https?:\/\/\S+$/i.test(trimmed)) {
1380
+ if (/^https?:\/\/[^/?#@]+@/i.test(trimmed) || SENSITIVE_URL_PARAM_RE.test(trimmed)) {
1381
+ return SECRET_REDACTION_PLACEHOLDER;
1382
+ }
1383
+ if (!URL_SECRET_VALUE_RE.test(value)) return value;
1384
+ }
1385
+ return value.replace(PRIVATE_KEY_RE, SECRET_REDACTION_PLACEHOLDER).replace(BEARER_TOKEN_RE, `Bearer ${SECRET_REDACTION_PLACEHOLDER}`).replace(JWT_RE, SECRET_REDACTION_PLACEHOLDER).replace(COMMON_SECRET_RE, SECRET_REDACTION_PLACEHOLDER).replace(HIGH_ENTROPY_ASSIGNMENT_RE, (match) => {
1386
+ const separator = match.includes("=") ? "=" : ":";
1387
+ const [key] = match.split(separator, 1);
1388
+ return `${key.trim()}${separator}${SECRET_REDACTION_PLACEHOLDER}`;
1389
+ });
1390
+ }
1391
+ function createSecretRedactionContext(initialValues = []) {
1392
+ const exactSecrets = /* @__PURE__ */ new Set();
1393
+ function register(value) {
1394
+ if (value.length >= 4) exactSecrets.add(value);
1395
+ }
1396
+ for (const value of initialValues) register(value);
1397
+ function redactString(value) {
1398
+ let output2 = value;
1399
+ for (const secret of exactSecrets) {
1400
+ output2 = output2.replace(
1401
+ new RegExp(escapeRegExp(secret), "g"),
1402
+ SECRET_REDACTION_PLACEHOLDER
1403
+ );
1404
+ try {
1405
+ const encoded = encodeURIComponent(secret);
1406
+ if (encoded !== secret) {
1407
+ output2 = output2.replace(
1408
+ new RegExp(escapeRegExp(encoded), "g"),
1409
+ SECRET_REDACTION_PLACEHOLDER
1410
+ );
1411
+ }
1412
+ } catch {
1413
+ }
1414
+ }
1415
+ return redactSecretLikeString(output2);
1416
+ }
1417
+ function redact(value) {
1418
+ if (typeof value === "string") return redactString(value);
1419
+ if (Array.isArray(value)) return value.map((entry) => redact(entry));
1420
+ if (isRecord(value)) {
1421
+ return Object.fromEntries(
1422
+ Object.entries(value).map(([key, entry]) => [key, redact(entry)])
1423
+ );
1424
+ }
1425
+ return value;
1426
+ }
1427
+ return {
1428
+ register,
1429
+ redactString,
1430
+ redact
1431
+ };
1432
+ }
1433
+
1434
+ // ../shared_libs/play-runtime/output-size-limits.ts
1435
+ var encoder = typeof TextEncoder === "undefined" ? null : new TextEncoder();
1436
+ var CUSTOMER_OUTPUT_VALUE_MAX_BYTES = 1 * 1024 * 1024;
1437
+ var CUSTOMER_OUTPUT_TOTAL_MAX_BYTES = 2 * 1024 * 1024;
1438
+ var RUNTIME_RECEIPT_OUTPUT_MAX_BYTES = 10 * 1024 * 1024;
1439
+ var RUNTIME_RECEIPT_COMPLETION_BUFFER_MAX_BYTES = 32 * 1024 * 1024;
1440
+
1441
+ // ../shared_libs/play-runtime/ledger-safe-payload.ts
1442
+ var ledgerIngressRedactor = createSecretRedactionContext();
1443
+
1362
1444
  // ../shared_libs/play-runtime/run-ledger.ts
1363
1445
  var LOG_TAIL_LIMIT = 100;
1364
- function isRecord(value) {
1446
+ function isRecord2(value) {
1365
1447
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1366
1448
  }
1367
1449
  function finiteNumber(value) {
@@ -1443,6 +1525,8 @@ function createEmptyPlayRunLedgerSnapshot(input2) {
1443
1525
  durationMs: startedAt !== null && finishedAt !== null ? Math.max(0, finishedAt - startedAt) : null,
1444
1526
  orderedStepIds: [],
1445
1527
  stepsById: {},
1528
+ orderedDatasetIds: [],
1529
+ datasetsById: {},
1446
1530
  logTail: [],
1447
1531
  totalLogCount: 0,
1448
1532
  logsTruncated: false,
@@ -1452,21 +1536,21 @@ function createEmptyPlayRunLedgerSnapshot(input2) {
1452
1536
  };
1453
1537
  }
1454
1538
  function normalizePlayRunLedgerSnapshot(value, fallback) {
1455
- if (!isRecord(value)) {
1539
+ if (!isRecord2(value)) {
1456
1540
  return createEmptyPlayRunLedgerSnapshot(fallback);
1457
1541
  }
1458
1542
  const orderedStepIds = Array.isArray(value.orderedStepIds) ? value.orderedStepIds.filter(
1459
1543
  (entry) => typeof entry === "string" && Boolean(entry.trim())
1460
1544
  ) : [];
1461
- const rawSteps = isRecord(value.stepsById) ? value.stepsById : {};
1545
+ const rawSteps = isRecord2(value.stepsById) ? value.stepsById : {};
1462
1546
  const stepsById = {};
1463
1547
  for (const [stepId, rawStep] of Object.entries(rawSteps)) {
1464
- if (!stepId.trim() || !isRecord(rawStep)) continue;
1548
+ if (!stepId.trim() || !isRecord2(rawStep)) continue;
1465
1549
  const rawStatus = normalizeStepStatus(rawStep.status);
1466
1550
  if (!rawStatus) continue;
1467
1551
  const completedAt = finiteNumber(rawStep.completedAt);
1468
1552
  const status = rawStatus === "running" && completedAt !== null ? "completed" : rawStatus;
1469
- const rawProgress = isRecord(rawStep.progress) ? rawStep.progress : null;
1553
+ const rawProgress = isRecord2(rawStep.progress) ? rawStep.progress : null;
1470
1554
  stepsById[stepId] = {
1471
1555
  stepId,
1472
1556
  label: optionalString(rawStep.label),
@@ -1481,6 +1565,23 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
1481
1565
  progress: rawProgress ? normalizeStepProgress(rawProgress) : null
1482
1566
  };
1483
1567
  }
1568
+ const rawDatasets = isRecord2(value.datasetsById) ? value.datasetsById : {};
1569
+ const datasetsById = {};
1570
+ for (const [datasetId, rawDataset] of Object.entries(rawDatasets)) {
1571
+ if (!datasetId.trim() || !isRecord2(rawDataset)) continue;
1572
+ const phase = rawDataset.phase === "available" || rawDataset.phase === "failed" ? rawDataset.phase : "registered";
1573
+ datasetsById[datasetId] = {
1574
+ datasetId,
1575
+ path: optionalString(rawDataset.path) ?? `datasets.${datasetId}`,
1576
+ tableNamespace: optionalString(rawDataset.tableNamespace) ?? datasetId,
1577
+ phase,
1578
+ persistedRows: Math.max(0, finiteNumber(rawDataset.persistedRows) ?? 0),
1579
+ succeededRows: Math.max(0, finiteNumber(rawDataset.succeededRows) ?? 0),
1580
+ failedRows: Math.max(0, finiteNumber(rawDataset.failedRows) ?? 0),
1581
+ complete: rawDataset.complete === true,
1582
+ updatedAt: finiteNumber(rawDataset.updatedAt) ?? 0
1583
+ };
1584
+ }
1484
1585
  const createdAt = finiteNumber(value.createdAt) ?? fallback.createdAt ?? null;
1485
1586
  const startedAt = finiteNumber(value.startedAt) ?? fallback.startedAt ?? null;
1486
1587
  const finishedAt = finiteNumber(value.finishedAt) ?? fallback.finishedAt ?? null;
@@ -1500,6 +1601,10 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
1500
1601
  durationMs: startedAt !== null && finishedAt !== null ? Math.max(0, finishedAt - startedAt) : finiteNumber(value.durationMs),
1501
1602
  orderedStepIds: orderedStepIds.filter((stepId) => stepsById[stepId]),
1502
1603
  stepsById,
1604
+ orderedDatasetIds: (Array.isArray(value.orderedDatasetIds) ? value.orderedDatasetIds : Object.keys(datasetsById)).filter(
1605
+ (datasetId) => typeof datasetId === "string" && Boolean(datasetsById[datasetId])
1606
+ ),
1607
+ datasetsById,
1503
1608
  logTail: logTail.slice(-LOG_TAIL_LIMIT),
1504
1609
  // Snapshots persisted before totalLogCount existed only know the retained
1505
1610
  // tail, so the best lower bound for the cumulative count is the tail size.
@@ -1594,18 +1699,18 @@ function normalizePlayRunLiveStatus(value) {
1594
1699
  function isTerminalPlayRunLiveStatus(status) {
1595
1700
  return isTerminalPlayRunLifecycleStatus(status);
1596
1701
  }
1597
- function isRecord2(value) {
1702
+ function isRecord3(value) {
1598
1703
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1599
1704
  }
1600
1705
  function finiteNumber2(value) {
1601
1706
  return typeof value === "number" && Number.isFinite(value) ? value : null;
1602
1707
  }
1603
1708
  function extractTerminalRunLogTail(result) {
1604
- if (!isRecord2(result) || !isRecord2(result._metadata)) {
1709
+ if (!isRecord3(result) || !isRecord3(result._metadata)) {
1605
1710
  return null;
1606
1711
  }
1607
1712
  const runLogTail = result._metadata.runLogTail;
1608
- if (!isRecord2(runLogTail) || !Array.isArray(runLogTail.tail)) {
1713
+ if (!isRecord3(runLogTail) || !Array.isArray(runLogTail.tail)) {
1609
1714
  return null;
1610
1715
  }
1611
1716
  const logTail = runLogTail.tail.filter(
@@ -1661,6 +1766,9 @@ function buildSnapshotFromLedger(snapshot) {
1661
1766
  ...snapshot.logsTruncated ? { logsTruncated: true } : {},
1662
1767
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1663
1768
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1769
+ datasets: snapshot.orderedDatasetIds.map((datasetId) => snapshot.datasetsById[datasetId]).filter(
1770
+ (dataset) => Boolean(dataset)
1771
+ ),
1664
1772
  nodeStates,
1665
1773
  activeNodeId: snapshot.activeStepId ?? null,
1666
1774
  ...rowOutcomes ? { rowOutcomes } : {}
@@ -2337,8 +2445,9 @@ function resolveToolExecuteTimeoutMs(toolId) {
2337
2445
  const normalized = toolId.trim().toLowerCase();
2338
2446
  return normalized === "deeplineagent" || normalized === "deeplineagent_deeplineagent" || normalized === "ai_inference" || normalized === "deeplineagent_ai_inference" || normalized === "aiinference" ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS : void 0;
2339
2447
  }
2448
+ var RUNS_FAILED_LOG_LIMIT = 20;
2340
2449
  var RUN_LOGS_PAGE_LIMIT = 1e3;
2341
- function isRecord3(value) {
2450
+ function isRecord4(value) {
2342
2451
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
2343
2452
  }
2344
2453
  function isPrebuiltPlayDescription(play) {
@@ -2495,7 +2604,7 @@ function updatePlayLiveStatusState(state, event) {
2495
2604
  }
2496
2605
  const runId = typeof payload.runId === "string" && payload.runId ? payload.runId : isPlayRunPackage(payload) ? payload.run.id : state.runId;
2497
2606
  const status = normalizeLiveStatus(payload.status) ?? (isPlayRunPackage(payload) ? normalizeLiveStatus(payload.run.status) : null) ?? state.status;
2498
- const progressPayload = isRecord3(payload.progress) ? payload.progress : {};
2607
+ const progressPayload = isRecord4(payload.progress) ? payload.progress : {};
2499
2608
  if (event.type === "play.run.final_status" && state.logs.length === 0 && state.lastLogSeq === 0) {
2500
2609
  const payloadLogs = readStringArray(payload.logs);
2501
2610
  const progressLogs = readStringArray(progressPayload.logs);
@@ -2610,9 +2719,9 @@ var DeeplineClient = class {
2610
2719
  return fields.length > 0 ? { fields } : schema;
2611
2720
  }
2612
2721
  schemaMetadata(schema, key) {
2613
- if (!isRecord3(schema)) return null;
2722
+ if (!isRecord4(schema)) return null;
2614
2723
  const value = schema[key];
2615
- return isRecord3(value) ? value : null;
2724
+ return isRecord4(value) ? value : null;
2616
2725
  }
2617
2726
  playRunCommand(play, options) {
2618
2727
  const target = play.reference || play.name;
@@ -2661,7 +2770,7 @@ var DeeplineClient = class {
2661
2770
  aliases,
2662
2771
  inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
2663
2772
  outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
2664
- staticPipeline: isRecord3(play.staticPipeline) ? play.staticPipeline : isRecord3(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord3(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
2773
+ staticPipeline: isRecord4(play.staticPipeline) ? play.staticPipeline : isRecord4(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord4(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
2665
2774
  ...csvInput ? { csvInput } : {},
2666
2775
  ...rowOutputSchema ? { rowOutputSchema } : {},
2667
2776
  runCommand: runCommand2,
@@ -3595,7 +3704,46 @@ var DeeplineClient = class {
3595
3704
  const response = await this.http.get(
3596
3705
  `/api/v2/runs/${encodeURIComponent(runId)}${query}`
3597
3706
  );
3598
- return normalizePlayStatus(response);
3707
+ const status = normalizePlayStatus(response);
3708
+ if (options?.failedLogs !== true || status.status !== "failed") {
3709
+ return status;
3710
+ }
3711
+ const requestedFailedLogLimit = typeof options.failedLogLimit === "number" && Number.isFinite(options.failedLogLimit) ? Math.max(1, Math.floor(options.failedLogLimit)) : RUNS_FAILED_LOG_LIMIT;
3712
+ let failedLogs;
3713
+ let failedLogsLoaded = true;
3714
+ try {
3715
+ failedLogs = await this.getRunLogs(runId, {
3716
+ failed: true,
3717
+ limit: Math.min(RUNS_FAILED_LOG_LIMIT, requestedFailedLogLimit)
3718
+ });
3719
+ } catch (error) {
3720
+ failedLogsLoaded = false;
3721
+ const retryCommand = `deepline runs get ${runId} --log-failed --json`;
3722
+ const reason = error instanceof Error && error.message.trim() ? ` (${error.message.trim().slice(0, 500)})` : "";
3723
+ failedLogs = {
3724
+ runId,
3725
+ totalCount: 0,
3726
+ returnedCount: 0,
3727
+ firstSequence: null,
3728
+ lastSequence: null,
3729
+ truncated: false,
3730
+ hasMore: false,
3731
+ entries: [],
3732
+ view: "failed",
3733
+ warning: `Failed logs could not be loaded${reason}. The run status and persisted datasets are still available.`,
3734
+ next: { logs: retryCommand }
3735
+ };
3736
+ }
3737
+ return {
3738
+ ...status,
3739
+ failedLogs: {
3740
+ ...failedLogs,
3741
+ view: "failed",
3742
+ ...failedLogsLoaded ? {
3743
+ association: failedLogs.association ?? "terminal_failure_window"
3744
+ } : {}
3745
+ }
3746
+ };
3599
3747
  }
3600
3748
  /**
3601
3749
  * List play runs using the public runs resource model.
@@ -3746,6 +3894,7 @@ var DeeplineClient = class {
3746
3894
  onNotice: options?.onNotice,
3747
3895
  fallback: "none"
3748
3896
  })) {
3897
+ options?.onEvent?.(event);
3749
3898
  const status = updatePlayLiveStatusState(state, event);
3750
3899
  if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
3751
3900
  continue;
@@ -3809,6 +3958,7 @@ var DeeplineClient = class {
3809
3958
  mode: "cli",
3810
3959
  signal: options?.signal
3811
3960
  })) {
3961
+ options?.onEvent?.(event);
3812
3962
  sawEvent = true;
3813
3963
  const status = updatePlayLiveStatusState(state, event);
3814
3964
  if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
@@ -3858,6 +4008,37 @@ var DeeplineClient = class {
3858
4008
  * ```
3859
4009
  */
3860
4010
  async getRunLogs(runId, options) {
4011
+ if (options?.all === true && options.failed === true) {
4012
+ throw new DeeplineError(
4013
+ "runs.logs cannot combine all and failed views.",
4014
+ void 0,
4015
+ "INVALID_RUN_LOG_VIEW"
4016
+ );
4017
+ }
4018
+ if (options?.failed === true) {
4019
+ const requestedLimit = typeof options.limit === "number" && Number.isFinite(options.limit) && options.limit > 0 ? Math.trunc(options.limit) : RUNS_FAILED_LOG_LIMIT;
4020
+ const failedLimit = Math.min(RUNS_FAILED_LOG_LIMIT, requestedLimit);
4021
+ const page = await this.http.get(
4022
+ `/api/v2/runs/${encodeURIComponent(runId)}/logs?view=failed&limit=${failedLimit}`
4023
+ );
4024
+ return {
4025
+ runId: page.runId,
4026
+ totalCount: page.totalLogCount,
4027
+ returnedCount: page.entries.length,
4028
+ firstSequence: page.firstSeq,
4029
+ lastSequence: page.lastSeq,
4030
+ // The failed view is a complete designed window, not a pageable slice.
4031
+ // `truncated` means retention loss here; association/warning explain it.
4032
+ truncated: page.logsTruncated === true,
4033
+ hasMore: false,
4034
+ entries: page.entries.map((entry) => entry.line),
4035
+ view: page.view ?? "failed",
4036
+ association: page.association ?? "terminal_failure_window",
4037
+ ...page.warning ? { warning: page.warning } : {},
4038
+ ...page.next ? { next: page.next } : {},
4039
+ ...page.logsTruncated ? { logsTruncated: true } : {}
4040
+ };
4041
+ }
3861
4042
  const limit = options?.all ? Number.MAX_SAFE_INTEGER : typeof options?.limit === "number" && Number.isFinite(options.limit) && options.limit > 0 ? Math.trunc(options.limit) : 200;
3862
4043
  const fetchPage = (afterSeq2, pageLimit) => this.http.get(
3863
4044
  `/api/v2/runs/${encodeURIComponent(runId)}/logs?afterSeq=${afterSeq2}&limit=${pageLimit}`
@@ -3891,6 +4072,7 @@ var DeeplineClient = class {
3891
4072
  truncated: entries.length < probe.totalLogCount,
3892
4073
  hasMore: lastSequence !== null && lastSequence < lastStoredSeq,
3893
4074
  entries: entries.map((entry) => entry.line),
4075
+ view: options?.all ? "all" : "tail",
3894
4076
  ...probe.logsTruncated ? { logsTruncated: true } : {}
3895
4077
  };
3896
4078
  }
@@ -7174,14 +7356,14 @@ function sanitizeCsvProjectionInfo(input2) {
7174
7356
  const rows = input2.rows.map(stripCsvProjectionFields);
7175
7357
  return { rows, columns };
7176
7358
  }
7177
- function isRecord4(value) {
7359
+ function isRecord5(value) {
7178
7360
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
7179
7361
  }
7180
7362
  function isSerializedDataset(value) {
7181
- return isRecord4(value) && value.kind === "dataset" && typeof value.count === "number" && (Array.isArray(value.preview) || typeof value.tableNamespace === "string");
7363
+ return isRecord5(value) && value.kind === "dataset" && typeof value.count === "number" && (Array.isArray(value.preview) || typeof value.tableNamespace === "string");
7182
7364
  }
7183
7365
  function isPackagedDatasetOutput(value) {
7184
- return isRecord4(value) && value.kind === "dataset" && isRecord4(value.preview) && Array.isArray(value.preview.rows);
7366
+ return isRecord5(value) && value.kind === "dataset" && isRecord5(value.preview) && Array.isArray(value.preview.rows);
7185
7367
  }
7186
7368
  function pathParts(path) {
7187
7369
  return path.split(".").map((part) => part.trim()).filter(Boolean);
@@ -7189,7 +7371,7 @@ function pathParts(path) {
7189
7371
  function valueAtPath(root, path) {
7190
7372
  let cursor = root;
7191
7373
  for (const part of pathParts(path)) {
7192
- if (!isRecord4(cursor)) {
7374
+ if (!isRecord5(cursor)) {
7193
7375
  return void 0;
7194
7376
  }
7195
7377
  cursor = cursor[part];
@@ -7197,17 +7379,17 @@ function valueAtPath(root, path) {
7197
7379
  return cursor;
7198
7380
  }
7199
7381
  function totalRowsForDataset(result, datasetPath) {
7200
- const metadata = isRecord4(result._metadata) ? result._metadata : null;
7382
+ const metadata = isRecord5(result._metadata) ? result._metadata : null;
7201
7383
  const parentPath = datasetPath.split(".").slice(0, -1).join(".");
7202
7384
  const parent = parentPath ? valueAtPath({ result }, parentPath) : result;
7203
- return metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count ?? (isRecord4(parent) ? parent.totalRows ?? parent.rowCount ?? parent.count : void 0) ?? result.totalRows ?? result.rowCount ?? result.count;
7385
+ return metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count ?? (isRecord5(parent) ? parent.totalRows ?? parent.rowCount ?? parent.count : void 0) ?? result.totalRows ?? result.rowCount ?? result.count;
7204
7386
  }
7205
7387
  function rowArray(value) {
7206
7388
  if (!Array.isArray(value)) {
7207
7389
  return null;
7208
7390
  }
7209
7391
  const rows = value.filter(
7210
- (row) => isRecord4(row)
7392
+ (row) => isRecord5(row)
7211
7393
  );
7212
7394
  return rows.length === value.length ? rows : null;
7213
7395
  }
@@ -7231,7 +7413,7 @@ function inferColumns(rows) {
7231
7413
  return columns;
7232
7414
  }
7233
7415
  function columnsFromDatasetSummary(summary) {
7234
- if (!isRecord4(summary) || !isRecord4(summary.columnStats)) {
7416
+ if (!isRecord5(summary) || !isRecord5(summary.columnStats)) {
7235
7417
  return [];
7236
7418
  }
7237
7419
  return Object.keys(summary.columnStats).filter((column) => column);
@@ -7321,7 +7503,7 @@ function collectDatasetCandidates(input2) {
7321
7503
  });
7322
7504
  return;
7323
7505
  }
7324
- if (!isRecord4(input2.value)) {
7506
+ if (!isRecord5(input2.value)) {
7325
7507
  return;
7326
7508
  }
7327
7509
  for (const [key, child] of Object.entries(input2.value)) {
@@ -7338,12 +7520,12 @@ function collectDatasetCandidates(input2) {
7338
7520
  }
7339
7521
  }
7340
7522
  function collectCanonicalRowsInfos(statusOrResult) {
7341
- const root = isRecord4(statusOrResult) ? statusOrResult : null;
7342
- const result = isRecord4(root?.result) ? root.result : root;
7523
+ const root = isRecord5(statusOrResult) ? statusOrResult : null;
7524
+ const result = isRecord5(root?.result) ? root.result : root;
7343
7525
  if (!result) {
7344
7526
  return [];
7345
7527
  }
7346
- const metadata = isRecord4(result._metadata) ? result._metadata : null;
7528
+ const metadata = isRecord5(result._metadata) ? result._metadata : null;
7347
7529
  const totalFromMetadata = metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count;
7348
7530
  const candidates = [
7349
7531
  {
@@ -7367,8 +7549,8 @@ function collectCanonicalRowsInfos(statusOrResult) {
7367
7549
  total: totalFromMetadata ?? result.totalRows ?? result.rowCount ?? result.count
7368
7550
  }
7369
7551
  ];
7370
- if (isRecord4(result.output)) {
7371
- const outputMetadata = isRecord4(result.output._metadata) ? result.output._metadata : null;
7552
+ if (isRecord5(result.output)) {
7553
+ const outputMetadata = isRecord5(result.output._metadata) ? result.output._metadata : null;
7372
7554
  const outputTotalFromMetadata = outputMetadata?.totalRows ?? outputMetadata?.rowCount ?? outputMetadata?.count;
7373
7555
  candidates.push(
7374
7556
  {
@@ -7395,14 +7577,14 @@ function collectCanonicalRowsInfos(statusOrResult) {
7395
7577
  }
7396
7578
  if (Array.isArray(result.steps)) {
7397
7579
  result.steps.forEach((step, index) => {
7398
- if (!isRecord4(step) || !isRecord4(step.output)) {
7580
+ if (!isRecord5(step) || !isRecord5(step.output)) {
7399
7581
  return;
7400
7582
  }
7401
7583
  const source = typeof step.output.path === "string" ? step.output.path : typeof step.id === "string" ? `steps.${step.id}.output` : `steps.${index}.output`;
7402
7584
  candidates.push({
7403
7585
  source,
7404
7586
  value: step.output,
7405
- total: step.output.rowCount ?? (isRecord4(step.output.preview) ? step.output.preview.totalRows : void 0) ?? (isRecord4(step.progress) ? step.progress.total : void 0)
7587
+ total: step.output.rowCount ?? (isRecord5(step.output.preview) ? step.output.preview.totalRows : void 0) ?? (isRecord5(step.progress) ? step.progress.total : void 0)
7406
7588
  });
7407
7589
  });
7408
7590
  }
@@ -7412,7 +7594,7 @@ function collectCanonicalRowsInfos(statusOrResult) {
7412
7594
  total: totalFromMetadata,
7413
7595
  output: candidates
7414
7596
  });
7415
- candidates.push(...collectPackagedStepDatasetCandidates(statusOrResult));
7597
+ candidates.push(...collectPackagedDatasetCandidates(statusOrResult));
7416
7598
  const seen = /* @__PURE__ */ new Set();
7417
7599
  const infos = [];
7418
7600
  for (const candidate of candidates) {
@@ -7429,37 +7611,33 @@ function collectCanonicalRowsInfos(statusOrResult) {
7429
7611
  }
7430
7612
  return infos;
7431
7613
  }
7432
- function collectPackagedStepDatasetCandidates(statusOrResult) {
7433
- const root = isRecord4(statusOrResult) ? statusOrResult : null;
7614
+ function collectPackagedDatasetCandidates(statusOrResult) {
7615
+ const root = isRecord5(statusOrResult) ? statusOrResult : null;
7434
7616
  if (!root) {
7435
7617
  return [];
7436
7618
  }
7437
- const pkg = isRecord4(root.package) ? root.package : root;
7438
- const steps = Array.isArray(pkg.steps) ? pkg.steps : [];
7619
+ const pkg = isRecord5(root.package) ? root.package : root;
7620
+ const datasets = Array.isArray(pkg.datasets) ? pkg.datasets : [];
7439
7621
  const candidates = [];
7440
- for (const step of steps) {
7441
- if (!isRecord4(step) || !isRecord4(step.output)) {
7442
- continue;
7443
- }
7444
- const output2 = step.output;
7445
- if (!isPackagedDatasetOutput(output2)) {
7622
+ for (const output2 of datasets) {
7623
+ if (!isRecord5(output2) || !isPackagedDatasetOutput(output2)) {
7446
7624
  continue;
7447
7625
  }
7448
- const source = typeof output2.path === "string" && output2.path.trim() ? output2.path.trim() : typeof step.id === "string" ? step.id : null;
7626
+ const source = typeof output2.path === "string" && output2.path.trim() ? output2.path.trim() : null;
7449
7627
  if (!source) {
7450
7628
  continue;
7451
7629
  }
7452
7630
  candidates.push({
7453
7631
  source,
7454
7632
  value: output2,
7455
- total: output2.rowCount ?? (isRecord4(output2.preview) ? output2.preview.totalRows : void 0) ?? (isRecord4(step.progress) ? step.progress.total : void 0)
7633
+ total: output2.rowCount ?? (isRecord5(output2.preview) ? output2.preview.totalRows : void 0)
7456
7634
  });
7457
7635
  }
7458
7636
  return candidates;
7459
7637
  }
7460
7638
  function collectSerializedDatasetRowsInfos(statusOrResult) {
7461
- const root = isRecord4(statusOrResult) ? statusOrResult : null;
7462
- const result = isRecord4(root?.result) ? root.result : root;
7639
+ const root = isRecord5(statusOrResult) ? statusOrResult : null;
7640
+ const result = isRecord5(root?.result) ? root.result : root;
7463
7641
  const candidates = [];
7464
7642
  if (result) {
7465
7643
  collectDatasetCandidates({
@@ -7467,7 +7645,7 @@ function collectSerializedDatasetRowsInfos(statusOrResult) {
7467
7645
  path: "result",
7468
7646
  output: candidates
7469
7647
  });
7470
- if (isRecord4(result.output)) {
7648
+ if (isRecord5(result.output)) {
7471
7649
  collectDatasetCandidates({
7472
7650
  value: result.output,
7473
7651
  path: "result",
@@ -7475,7 +7653,7 @@ function collectSerializedDatasetRowsInfos(statusOrResult) {
7475
7653
  });
7476
7654
  }
7477
7655
  }
7478
- candidates.push(...collectPackagedStepDatasetCandidates(statusOrResult));
7656
+ candidates.push(...collectPackagedDatasetCandidates(statusOrResult));
7479
7657
  const seen = /* @__PURE__ */ new Set();
7480
7658
  const infos = [];
7481
7659
  for (const candidate of candidates) {
@@ -7539,13 +7717,13 @@ function summarizeSampleValue(value, depth = 0) {
7539
7717
  if (typeof parsed === "number" || typeof parsed === "boolean") return parsed;
7540
7718
  if (depth >= 3) {
7541
7719
  if (Array.isArray(parsed)) return [];
7542
- if (isRecord4(parsed)) return {};
7720
+ if (isRecord5(parsed)) return {};
7543
7721
  return compactScalar(parsed);
7544
7722
  }
7545
7723
  if (Array.isArray(parsed)) {
7546
7724
  return parsed.slice(0, 3).map((item) => summarizeSampleValue(item, depth + 1));
7547
7725
  }
7548
- if (isRecord4(parsed)) {
7726
+ if (isRecord5(parsed)) {
7549
7727
  const out = {};
7550
7728
  for (const [key, nested] of Object.entries(parsed)) {
7551
7729
  if (["__dl", "meta", "metadata"].includes(key)) {
@@ -7576,7 +7754,7 @@ function compactCell(value) {
7576
7754
  }
7577
7755
  return `[${parsed.length} items]`;
7578
7756
  }
7579
- if (isRecord4(parsed)) {
7757
+ if (isRecord5(parsed)) {
7580
7758
  for (const key of ["matched_result", "output"]) {
7581
7759
  if (parsed[key] !== null && parsed[key] !== void 0 && parsed[key] !== "") {
7582
7760
  return compactCell(parsed[key]);
@@ -8615,17 +8793,17 @@ function parsePositiveInteger2(value, flagName) {
8615
8793
  }
8616
8794
  return parsed;
8617
8795
  }
8618
- function isRecord5(value) {
8796
+ function isRecord6(value) {
8619
8797
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
8620
8798
  }
8621
8799
  function stringValue(value) {
8622
8800
  return typeof value === "string" ? value.trim() : "";
8623
8801
  }
8624
8802
  function extractionEntries(value) {
8625
- if (Array.isArray(value)) return value.filter(isRecord5);
8626
- if (!isRecord5(value)) return [];
8803
+ if (Array.isArray(value)) return value.filter(isRecord6);
8804
+ if (!isRecord6(value)) return [];
8627
8805
  return Object.entries(value).map(
8628
- ([name, entry]) => isRecord5(entry) ? { name, ...entry } : { name }
8806
+ ([name, entry]) => isRecord6(entry) ? { name, ...entry } : { name }
8629
8807
  );
8630
8808
  }
8631
8809
  var PlayBootstrapError = class extends Error {
@@ -9187,7 +9365,7 @@ function readCsvSampleRows(sample) {
9187
9365
  relax_column_count: true,
9188
9366
  trim: true
9189
9367
  });
9190
- return Array.isArray(parsedRows) ? parsedRows.filter(isRecord5) : [];
9368
+ return Array.isArray(parsedRows) ? parsedRows.filter(isRecord6) : [];
9191
9369
  }
9192
9370
  function readSourceCsvColumnSpecs(csvPath) {
9193
9371
  const sample = readCsvSample(csvPath);
@@ -9220,16 +9398,16 @@ function packagedCsvPathForPlay(csvPath) {
9220
9398
  return portablePath.startsWith(".") ? portablePath : `./${portablePath}`;
9221
9399
  }
9222
9400
  function getterNamesFromTool(tool, kind) {
9223
- const usageGuidance = isRecord5(tool?.usageGuidance) ? tool.usageGuidance : {};
9224
- const resultGuidance = isRecord5(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord5(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
9401
+ const usageGuidance = isRecord6(tool?.usageGuidance) ? tool.usageGuidance : {};
9402
+ const resultGuidance = isRecord6(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord6(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
9225
9403
  const key = kind === "list" ? "extractedLists" : "extractedValues";
9226
9404
  const snakeKey = kind === "list" ? "extracted_lists" : "extracted_values";
9227
9405
  return extractionEntries(resultGuidance[key] ?? resultGuidance[snakeKey]).map((entry) => stringValue(entry.name)).filter(Boolean);
9228
9406
  }
9229
9407
  function targetGettersFromTool(tool) {
9230
- const record = isRecord5(tool) ? tool : {};
9408
+ const record = isRecord6(tool) ? tool : {};
9231
9409
  const raw = record.targetGetters ?? record.target_getters;
9232
- if (!isRecord5(raw)) return {};
9410
+ if (!isRecord6(raw)) return {};
9233
9411
  const entries = [];
9234
9412
  for (const [target, value] of Object.entries(raw)) {
9235
9413
  const paths = Array.isArray(value) ? value.map((path) => typeof path === "string" ? path.trim() : "").filter(Boolean) : [];
@@ -9250,10 +9428,10 @@ function listRowCandidateKeysFromTool(tool) {
9250
9428
  return [...keys].sort();
9251
9429
  }
9252
9430
  function inputPropertyNames(schema) {
9253
- if (!isRecord5(schema)) return [];
9254
- if (isRecord5(schema.properties)) return Object.keys(schema.properties);
9431
+ if (!isRecord6(schema)) return [];
9432
+ if (isRecord6(schema.properties)) return Object.keys(schema.properties);
9255
9433
  if (Array.isArray(schema.fields)) {
9256
- return schema.fields.filter(isRecord5).map((field) => stringValue(field.name)).filter(Boolean);
9434
+ return schema.fields.filter(isRecord6).map((field) => stringValue(field.name)).filter(Boolean);
9257
9435
  }
9258
9436
  return [];
9259
9437
  }
@@ -9267,7 +9445,7 @@ function schemaFieldDetails(schema) {
9267
9445
  return { required, optional };
9268
9446
  }
9269
9447
  function jsonSchemaTypeExpression(schema) {
9270
- if (!isRecord5(schema)) return "unknown";
9448
+ if (!isRecord6(schema)) return "unknown";
9271
9449
  const type = schema.type;
9272
9450
  if (Array.isArray(type)) {
9273
9451
  return type.map((entry) => jsonSchemaTypeExpression({ ...schema, type: entry })).join(" | ");
@@ -9297,7 +9475,7 @@ function jsonSchemaTypeExpression(schema) {
9297
9475
  }
9298
9476
  }
9299
9477
  function objectPropertySchema(schema, property) {
9300
- return isRecord5(schema) && isRecord5(schema.properties) ? schema.properties[property] : null;
9478
+ return isRecord6(schema) && isRecord6(schema.properties) ? schema.properties[property] : null;
9301
9479
  }
9302
9480
  function playOutputHasField(schema, field) {
9303
9481
  return objectPropertySchema(schema, field) != null;
@@ -9473,14 +9651,14 @@ ${indent2.slice(2)}}`;
9473
9651
  }
9474
9652
  function requiredPlayInputFields(play) {
9475
9653
  const schema = play?.inputSchema;
9476
- if (!isRecord5(schema)) return [];
9654
+ if (!isRecord6(schema)) return [];
9477
9655
  if (Array.isArray(schema.required)) {
9478
9656
  return schema.required.filter(
9479
9657
  (value) => typeof value === "string"
9480
9658
  );
9481
9659
  }
9482
9660
  if (Array.isArray(schema.fields)) {
9483
- return schema.fields.filter(isRecord5).filter(
9661
+ return schema.fields.filter(isRecord6).filter(
9484
9662
  (field) => field.required === true && typeof field.name === "string"
9485
9663
  ).map((field) => String(field.name));
9486
9664
  }
@@ -9661,7 +9839,7 @@ function validateBootstrapRoutes(input2) {
9661
9839
  }
9662
9840
  }
9663
9841
  function staticPipelineSubsteps(pipeline) {
9664
- if (!isRecord5(pipeline)) return [];
9842
+ if (!isRecord6(pipeline)) return [];
9665
9843
  return [
9666
9844
  ...extractionEntries(pipeline.stages),
9667
9845
  ...extractionEntries(pipeline.substeps)
@@ -9669,7 +9847,7 @@ function staticPipelineSubsteps(pipeline) {
9669
9847
  }
9670
9848
  function playUsesMapBackedRuntime(play) {
9671
9849
  const pipeline = play?.staticPipeline;
9672
- if (!isRecord5(pipeline)) return false;
9850
+ if (!isRecord6(pipeline)) return false;
9673
9851
  if (stringValue(pipeline.tableNamespace)) return true;
9674
9852
  return staticPipelineSubsteps(pipeline).some((substep) => {
9675
9853
  if (stringValue(substep.type) === "map") return true;
@@ -9678,7 +9856,7 @@ function playUsesMapBackedRuntime(play) {
9678
9856
  aliases: [],
9679
9857
  runCommand: "",
9680
9858
  examples: [],
9681
- staticPipeline: isRecord5(substep.pipeline) ? substep.pipeline : null
9859
+ staticPipeline: isRecord6(substep.pipeline) ? substep.pipeline : null
9682
9860
  });
9683
9861
  });
9684
9862
  }
@@ -10826,7 +11004,8 @@ var PLAY_RUN_RESERVED_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
10826
11004
  "--logs",
10827
11005
  "--full",
10828
11006
  "--force",
10829
- "--no-open"
11007
+ "--no-open",
11008
+ "--debug-map-latency"
10830
11009
  ]);
10831
11010
  function traceCliSync(phase, fields, run) {
10832
11011
  const startedAt = Date.now();
@@ -12414,6 +12593,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
12414
12593
  let timedOut = false;
12415
12594
  let emittedDashboardUrl = false;
12416
12595
  let lastKnownWorkflowId = "";
12596
+ let launchedRevisionId = input2.request.revisionId?.trim() || null;
12417
12597
  let eventCount = 0;
12418
12598
  let firstRunIdMs = null;
12419
12599
  let lastPhase = null;
@@ -12439,13 +12619,24 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
12439
12619
  }
12440
12620
  throw error;
12441
12621
  }
12442
- return TERMINAL_PLAY_STATUSES2.has(refreshed.status) ? { ...refreshed, dashboardUrl } : null;
12622
+ return TERMINAL_PLAY_STATUSES2.has(refreshed.status) ? {
12623
+ ...refreshed,
12624
+ dashboardUrl,
12625
+ ...launchedRevisionId ? { revisionId: launchedRevisionId } : {}
12626
+ } : null;
12443
12627
  };
12444
12628
  try {
12445
12629
  for await (const event of input2.client.startPlayRunStream(input2.request, {
12446
12630
  signal: controller.signal
12447
12631
  })) {
12448
12632
  eventCount += 1;
12633
+ const eventRevisionId = getStringField(
12634
+ getEventPayload(event),
12635
+ "revisionId"
12636
+ );
12637
+ if (eventRevisionId) {
12638
+ launchedRevisionId = eventRevisionId;
12639
+ }
12449
12640
  const eventRunId = getRunIdFromLiveEvent(event);
12450
12641
  if (typeof eventRunId === "string" && eventRunId && eventRunId !== "pending") {
12451
12642
  lastKnownWorkflowId = eventRunId;
@@ -12522,7 +12713,11 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
12522
12713
  const finalStatus = getFinalStatusFromLiveEvent(event);
12523
12714
  if (finalStatus) {
12524
12715
  lastKnownWorkflowId ||= finalStatus.runId ?? "";
12525
- const canonicalTerminal = input2.request.profile === "absurd" ? await fetchKnownTerminalStatus() : { ...finalStatus, dashboardUrl };
12716
+ const canonicalTerminal = input2.request.profile === "absurd" ? await fetchKnownTerminalStatus() : {
12717
+ ...finalStatus,
12718
+ dashboardUrl,
12719
+ ...launchedRevisionId ? { revisionId: launchedRevisionId } : {}
12720
+ };
12526
12721
  if (!canonicalTerminal) {
12527
12722
  recordCliTrace({
12528
12723
  phase: "cli.play_start_stream_stale_terminal_ignored",
@@ -12894,6 +13089,10 @@ function buildRunNextCommands(status) {
12894
13089
  stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
12895
13090
  logs: `deepline runs logs ${runId} --out run.log --json`
12896
13091
  };
13092
+ if (status.status === "failed") {
13093
+ commands.failedLogs = `deepline runs get ${runId} --log-failed --json`;
13094
+ if (status.rerunCommand) commands.run = status.rerunCommand;
13095
+ }
12897
13096
  if (status.dashboardUrl) {
12898
13097
  commands.open = `Open ${status.dashboardUrl} to see results.`;
12899
13098
  }
@@ -13045,7 +13244,7 @@ function buildInsufficientCreditsSummaryLines(input2) {
13045
13244
  const lines = [
13046
13245
  " status: stopped_insufficient_credits",
13047
13246
  completed === null ? " completed rows: unknown" : ` completed rows: ${formatInteger(completed)}${total !== null ? ` of ${formatInteger(total)}` : ""}`,
13048
- " reusable receipts: yes; rerun after adding credits to continue from completed provider work"
13247
+ " completed provider work: reused automatically when you rerun after adding credits"
13049
13248
  ];
13050
13249
  const billingUrl = getStringField(input2.billing, "billing_url");
13051
13250
  const recommended = formatCreditAmount(
@@ -13245,15 +13444,44 @@ function withTerminalPlayIdentity(status, playName) {
13245
13444
  function compactPlayStatus(status) {
13246
13445
  const packaged = getPlayRunPackage(status);
13247
13446
  if (packaged) {
13248
- const error2 = selectRunErrorForDisplay(status) ?? (typeof status.error === "string" ? String(status.error) : null);
13447
+ const packagedRun = readRecord(packaged.run);
13448
+ const packagedError = typeof packagedRun?.error === "string" ? packagedRun.error : null;
13449
+ const error2 = selectRunErrorForDisplay(status) ?? (typeof status.error === "string" ? String(status.error) : packagedError);
13450
+ const compactError = error2 ? compactRunErrorForEnvelope(error2, status.runId) : null;
13249
13451
  if (!error2) {
13250
- return packaged;
13452
+ return status.failedLogs || status.rerunCommand ? {
13453
+ ...packaged,
13454
+ ...status.failedLogs ? { failedLogs: status.failedLogs } : {},
13455
+ next: {
13456
+ ...readRecord(packaged.next) ?? {},
13457
+ ...status.failedLogs ? {
13458
+ failedLogs: `deepline runs get ${status.runId} --log-failed --json`
13459
+ } : {},
13460
+ ...status.rerunCommand ? { run: status.rerunCommand } : {}
13461
+ }
13462
+ } : packaged;
13251
13463
  }
13252
- const run = packaged.run && typeof packaged.run === "object" ? packaged.run : null;
13464
+ const run = packagedRun;
13253
13465
  return {
13254
13466
  ...packaged,
13255
- error: error2,
13256
- ...run ? { run: { ...run, error: error2 } } : {}
13467
+ ...status.failedLogs ? { failedLogs: status.failedLogs } : {},
13468
+ ...status.failedLogs ? {
13469
+ next: {
13470
+ ...readRecord(packaged.next) ?? {},
13471
+ failedLogs: `deepline runs get ${status.runId} --log-failed --json`
13472
+ }
13473
+ } : {},
13474
+ ...status.rerunCommand ? {
13475
+ next: {
13476
+ ...readRecord(packaged.next) ?? {},
13477
+ ...status.failedLogs ? {
13478
+ failedLogs: `deepline runs get ${status.runId} --log-failed --json`
13479
+ } : {},
13480
+ run: status.rerunCommand
13481
+ }
13482
+ } : {},
13483
+ error: compactError,
13484
+ ...run ? { run: { ...run, error: compactError } } : {}
13257
13485
  };
13258
13486
  }
13259
13487
  const rowsInfo = extractCanonicalRowsInfo(status);
@@ -13276,6 +13504,7 @@ function compactPlayStatus(status) {
13276
13504
  steps: normalizeStepsForEnvelope(status),
13277
13505
  errors: normalizeErrorsForEnvelope(status, error),
13278
13506
  logs: normalizeLogsForEnvelope(status),
13507
+ ...status.failedLogs ? { failedLogs: status.failedLogs } : {},
13279
13508
  ...displayError ? { error: displayError } : {},
13280
13509
  ...warnings.length > 0 ? { warnings } : {},
13281
13510
  ...result !== void 0 ? { result: defaultResultForEnvelope(result) } : {},
@@ -13283,6 +13512,16 @@ function compactPlayStatus(status) {
13283
13512
  next: buildRunNextCommands(status)
13284
13513
  };
13285
13514
  }
13515
+ function compactRunErrorForEnvelope(message, runId) {
13516
+ const lines = message.split("\n");
13517
+ const firstStackFrame = lines.findIndex(
13518
+ (line, index) => index > 0 && /^\s*at\s+.*(?:\(?[^()\s]+:\d+:\d+\)?|native\)?|<anonymous>\)?)\s*$/u.test(
13519
+ line
13520
+ )
13521
+ );
13522
+ const headline = firstStackFrame >= 0 ? lines.slice(0, firstStackFrame).join("\n") : message;
13523
+ return truncateErrorForDisplay(headline, runId, 1e3);
13524
+ }
13286
13525
  function readRunPackageRun(packaged) {
13287
13526
  return packaged.run && typeof packaged.run === "object" && !Array.isArray(packaged.run) ? packaged.run : {};
13288
13527
  }
@@ -13402,6 +13641,14 @@ function actionToCommand(action) {
13402
13641
  record.datasetPath
13403
13642
  )} --out ${shellSingleQuote(`${record.datasetPath.split(".").pop() || "dataset"}.csv`)}`;
13404
13643
  }
13644
+ if (record.kind === "deepline_run_logs") {
13645
+ if (typeof record.command === "string" && record.command.trim()) {
13646
+ return record.command;
13647
+ }
13648
+ if (typeof record.runId === "string") {
13649
+ return record.view === "failed" ? `deepline runs get ${record.runId} --log-failed --json` : `deepline runs logs ${record.runId} --json`;
13650
+ }
13651
+ }
13405
13652
  if (record.kind === "deepline_db_query" && typeof record.sql === "string") {
13406
13653
  const maxRows = typeof record.maxRows === "number" && Number.isFinite(record.maxRows) ? Math.trunc(record.maxRows) : 20;
13407
13654
  return `deepline db query --sql ${shellSingleQuote(record.sql)} --max-rows ${maxRows} --json`;
@@ -13409,6 +13656,10 @@ function actionToCommand(action) {
13409
13656
  return null;
13410
13657
  }
13411
13658
  function readFirstDatasetActions(packaged) {
13659
+ for (const dataset of readRecordArray(packaged.datasets)) {
13660
+ const actions = readRecord(dataset.actions);
13661
+ if (actions) return actions;
13662
+ }
13412
13663
  for (const step of readRecordArray(packaged.steps)) {
13413
13664
  const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
13414
13665
  const actions = output2?.actions && typeof output2.actions === "object" && !Array.isArray(output2.actions) ? output2.actions : null;
@@ -13458,13 +13709,34 @@ function buildRunPackageTextLines(packaged) {
13458
13709
  if (runError && (status === "failed" || status === "cancelled")) {
13459
13710
  lines.push(` error: ${truncateErrorForDisplay(runError, runId)}`);
13460
13711
  }
13461
- for (const step of readRecordArray(packaged.steps)) {
13462
- const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
13463
- if (!output2 || output2.recovered !== true) continue;
13712
+ const failedLogs = readRecord(packaged.failedLogs);
13713
+ const failedLogEntries = Array.isArray(failedLogs?.entries) ? failedLogs.entries.filter(
13714
+ (entry) => typeof entry === "string"
13715
+ ) : [];
13716
+ const failedLogAssociation = typeof failedLogs?.association === "string" ? failedLogs.association : null;
13717
+ const failedLogWarning = typeof failedLogs?.warning === "string" && failedLogs.warning.trim() ? failedLogs.warning.trim() : null;
13718
+ if (failedLogEntries.length > 0) {
13719
+ lines.push(" failed logs:");
13720
+ lines.push(...failedLogEntries.map((entry) => ` ${entry}`));
13721
+ }
13722
+ if (failedLogAssociation === "retained_before_truncation") {
13723
+ lines.push(" failed log context: last retained lines before truncation");
13724
+ }
13725
+ if (failedLogWarning) {
13726
+ lines.push(` warning: ${failedLogWarning}`);
13727
+ }
13728
+ const failedLogNext = readRecord(failedLogs?.next);
13729
+ if (failedLogWarning && typeof failedLogNext?.logs === "string") {
13730
+ lines.push(
13731
+ failedLogAssociation === "retained_before_truncation" ? ` retained logs: ${failedLogNext.logs}` : ` retry failed logs: ${failedLogNext.logs}`
13732
+ );
13733
+ }
13734
+ for (const output2 of readRecordArray(packaged.datasets)) {
13735
+ if (output2.recovered !== true) continue;
13464
13736
  const rowCount = typeof output2.rowCount === "number" ? formatInteger(output2.rowCount) : "persisted";
13465
13737
  const datasetPath = typeof output2.path === "string" ? output2.path : "dataset";
13466
13738
  lines.push(
13467
- ` recoverable: ${rowCount} rows persisted in ${datasetPath} \u2014 re-running reuses them; export with the command below`
13739
+ ` dataset ${datasetPath}: available, ${rowCount} rows persisted; re-running reuses completed work`
13468
13740
  );
13469
13741
  }
13470
13742
  if (playName) {
@@ -13473,6 +13745,7 @@ function buildRunPackageTextLines(packaged) {
13473
13745
  lines.push(...formatPackageValueOutputLines(packaged));
13474
13746
  const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
13475
13747
  const billingCommand = actionToCommand(next.billing);
13748
+ const logsCommand = actionToCommand(next.logs);
13476
13749
  if (billingCommand) {
13477
13750
  const costState = status === "completed" || status === "failed" || status === "cancelled" ? "settles asynchronously \u2014 run the billing command below for totals" : "pending";
13478
13751
  lines.push(` cost: ${costState}`);
@@ -13497,12 +13770,49 @@ function buildRunPackageTextLines(packaged) {
13497
13770
  const inspectCommand = actionToCommand(next.inspect);
13498
13771
  const queryCommand = actionToCommand(next.query) ?? actionToCommand(datasetActions.query);
13499
13772
  const exportCommand = actionToCommand(next.export) ?? actionToCommand(datasetActions.exportCsv);
13773
+ const runAgainCommand = typeof next.run === "string" && next.run.trim() ? next.run.trim() : null;
13500
13774
  if (inspectCommand) lines.push(` inspect: ${inspectCommand}`);
13775
+ if (logsCommand) lines.push(` logs: ${logsCommand}`);
13501
13776
  if (billingCommand) lines.push(` billing: ${billingCommand}`);
13502
13777
  if (queryCommand) lines.push(` query: ${queryCommand}`);
13503
13778
  if (exportCommand) lines.push(` export CSV: ${exportCommand}`);
13779
+ if (runAgainCommand) {
13780
+ lines.push(" run again (completed work is reused):");
13781
+ lines.push(` ${runAgainCommand}`);
13782
+ }
13504
13783
  return lines;
13505
13784
  }
13785
+ function buildOrdinaryPlayRunCommand(options, resolvedRevisionId) {
13786
+ const target = options.target.kind === "file" ? options.target.path : options.target.name;
13787
+ const parts = ["deepline", "plays", "run", shellSingleQuote(target)];
13788
+ if (options.input && Object.keys(options.input).length > 0) {
13789
+ parts.push("--input", shellSingleQuote(JSON.stringify(options.input)));
13790
+ }
13791
+ if (options.profile)
13792
+ parts.push("--profile", shellSingleQuote(options.profile));
13793
+ const pinnedRevisionId = options.target.kind === "name" ? resolvedRevisionId ?? options.revisionId : null;
13794
+ if (pinnedRevisionId) {
13795
+ parts.push("--revision-id", shellSingleQuote(pinnedRevisionId));
13796
+ } else if (options.revisionSelector === "latest") {
13797
+ parts.push("--latest");
13798
+ } else if (options.revisionSelector === "live") {
13799
+ parts.push("--live");
13800
+ }
13801
+ if (options.waitTimeoutMs !== null) {
13802
+ parts.push("--tail-timeout-ms", String(options.waitTimeoutMs));
13803
+ }
13804
+ if (options.noOpen) parts.push("--no-open");
13805
+ if (options.fullJson) parts.push("--full");
13806
+ if (options.jsonOutput && options.emitLogs) parts.push("--logs");
13807
+ if (options.jsonOutput) parts.push("--json");
13808
+ return parts.join(" ");
13809
+ }
13810
+ function withOrdinaryRunAgainCommand(status, options, resolvedRevisionId) {
13811
+ return status.status === "failed" ? {
13812
+ ...status,
13813
+ rerunCommand: buildOrdinaryPlayRunCommand(options, resolvedRevisionId)
13814
+ } : status;
13815
+ }
13506
13816
  function writePlayResult(status, jsonOutput, options) {
13507
13817
  const packaged = getPlayRunPackage(status);
13508
13818
  if (jsonOutput) {
@@ -13512,8 +13822,9 @@ function writePlayResult(status, jsonOutput, options) {
13512
13822
  return;
13513
13823
  }
13514
13824
  if (packaged && !options?.fullJson) {
13515
- const lines2 = buildRunPackageTextLines(packaged);
13516
- printCommandEnvelope(packaged, {
13825
+ const displayPackage = compactPlayStatus(status);
13826
+ const lines2 = buildRunPackageTextLines(displayPackage);
13827
+ printCommandEnvelope(displayPackage, {
13517
13828
  json: false,
13518
13829
  text: `${lines2.join("\n")}
13519
13830
  `
@@ -13540,6 +13851,21 @@ function writePlayResult(status, jsonOutput, options) {
13540
13851
  const displayError = formatPlayErrorForDisplay(status, progressError) ?? progressError;
13541
13852
  lines.push(` error: ${truncateErrorForDisplay(displayError, runId)}`);
13542
13853
  }
13854
+ if (status.status === "failed") {
13855
+ const failedLogEntries = status.failedLogs?.entries ?? [];
13856
+ if (failedLogEntries.length > 0) {
13857
+ lines.push(" failed logs:");
13858
+ lines.push(...failedLogEntries.map((entry) => ` ${entry}`));
13859
+ } else {
13860
+ lines.push(
13861
+ ` failed logs: deepline runs get ${runId} --log-failed --json`
13862
+ );
13863
+ }
13864
+ if (status.rerunCommand) {
13865
+ lines.push(" run again (completed work is reused):");
13866
+ lines.push(` ${status.rerunCommand}`);
13867
+ }
13868
+ }
13543
13869
  const renderedServerView = renderServerResultView(status.resultView);
13544
13870
  if (result) {
13545
13871
  lines.push(...formatReturnValue(result));
@@ -13582,20 +13908,27 @@ async function resolvePlayRunOutputStatus(input2) {
13582
13908
  const streamedPackage = getPlayRunPackage(input2.status);
13583
13909
  const refreshForFullJson = input2.fullJson && streamedPackage !== null;
13584
13910
  const streamedTextPackageIncomplete = !input2.jsonOutput && input2.status.status === "completed" && playRunPackageTextLedgerIncomplete(streamedPackage);
13585
- if (!refreshForFullJson && !streamedTextPackageIncomplete) {
13911
+ const refreshFailedTerminal = input2.status.status === "failed";
13912
+ if (!refreshForFullJson && !streamedTextPackageIncomplete && !refreshFailedTerminal) {
13586
13913
  return input2.status;
13587
13914
  }
13588
13915
  let refreshedStatus = await input2.client.getPlayStatus(runId, {
13589
13916
  billing: false,
13590
13917
  full: input2.fullJson
13591
13918
  });
13592
- for (let attempt = 0; attempt < 3 && streamedTextPackageIncomplete && refreshedStatus.status === "completed" && playRunPackageTextLedgerIncomplete(getPlayRunPackage(refreshedStatus)); attempt += 1) {
13919
+ for (let attempt = 0; attempt < 3 && (streamedTextPackageIncomplete && refreshedStatus.status === "completed" && playRunPackageTextLedgerIncomplete(getPlayRunPackage(refreshedStatus)) || refreshFailedTerminal && (refreshedStatus.status !== "failed" || getPlayRunPackage(refreshedStatus) === null)); attempt += 1) {
13593
13920
  await sleep5(250);
13594
13921
  refreshedStatus = await input2.client.getPlayStatus(runId, {
13595
13922
  billing: false,
13596
13923
  full: input2.fullJson
13597
13924
  });
13598
13925
  }
13926
+ if (refreshFailedTerminal && (refreshedStatus.status !== "failed" || getPlayRunPackage(refreshedStatus) === null)) {
13927
+ return input2.status;
13928
+ }
13929
+ if (input2.status.status === "completed" && refreshedStatus.status !== "completed") {
13930
+ return input2.status;
13931
+ }
13599
13932
  const dashboardUrl = input2.status.dashboardUrl;
13600
13933
  return typeof dashboardUrl === "string" ? { ...refreshedStatus, dashboardUrl } : refreshedStatus;
13601
13934
  }
@@ -13730,37 +14063,16 @@ function resolveDatasetByName(available, datasetPath) {
13730
14063
  if (exact) {
13731
14064
  return exact;
13732
14065
  }
14066
+ const byDatasetId = available.find((info) => info.datasetId === target);
14067
+ if (byDatasetId) {
14068
+ return byDatasetId;
14069
+ }
13733
14070
  const byNamespace = available.find(
13734
14071
  (info) => info.tableNamespace && info.tableNamespace === target
13735
14072
  );
13736
14073
  if (byNamespace) {
13737
14074
  return byNamespace;
13738
14075
  }
13739
- const trailing = target.split(".").filter(Boolean).at(-1);
13740
- if (!trailing) {
13741
- return null;
13742
- }
13743
- const byTrailing = available.find(
13744
- (info) => info.tableNamespace === trailing || typeof info.source === "string" && info.source.split(".").filter(Boolean).at(-1) === trailing
13745
- );
13746
- if (byTrailing) {
13747
- return byTrailing;
13748
- }
13749
- if (target.split(".").filter(Boolean)[0] === "result") {
13750
- const recovered = available.filter((info) => info.recovered);
13751
- if (recovered.length === 1) {
13752
- return recovered[0];
13753
- }
13754
- if (recovered.length > 1) {
13755
- const names = recovered.map((info) => info.tableNamespace ?? info.source).filter((name) => typeof name === "string");
13756
- throw new DeeplineError(
13757
- `Run returned multiple recovered datasets; '${target}' is ambiguous. Choose one with --dataset <path>: ${names.join(", ")}.`,
13758
- void 0,
13759
- "RUN_EXPORT_DATASET_AMBIGUOUS",
13760
- { dataset: target, available: names }
13761
- );
13762
- }
13763
- }
13764
14076
  return null;
13765
14077
  }
13766
14078
  function assertDatasetHasExportableRows(input2) {
@@ -13940,7 +14252,7 @@ function extractPlayValidationErrors(value) {
13940
14252
  if (value instanceof DeeplineError) {
13941
14253
  return extractPlayValidationErrors(value.details);
13942
14254
  }
13943
- if (!isRecord6(value)) {
14255
+ if (!isRecord7(value)) {
13944
14256
  return [];
13945
14257
  }
13946
14258
  const directErrors = stringArrayField(value, "errors");
@@ -14173,6 +14485,7 @@ function parsePlayRunOptions(args) {
14173
14485
  const emitLogs = !jsonOutput || args.includes("--logs");
14174
14486
  const force = args.includes("--force");
14175
14487
  const noOpen = args.includes("--no-open");
14488
+ const debugMapLatency = args.includes("--debug-map-latency");
14176
14489
  let waitTimeoutMs = null;
14177
14490
  let profile = null;
14178
14491
  for (let index = 0; index < args.length; index += 1) {
@@ -14291,7 +14604,8 @@ function parsePlayRunOptions(args) {
14291
14604
  waitTimeoutMs,
14292
14605
  force,
14293
14606
  noOpen,
14294
- profile
14607
+ profile,
14608
+ debugMapLatency
14295
14609
  };
14296
14610
  }
14297
14611
  function parsePlayCheckOptions(args) {
@@ -14306,7 +14620,7 @@ function shouldUseLocalOnlyPlayCheck() {
14306
14620
  const value = process.env.DEEPLINE_PLAY_CHECK_LOCAL_ONLY?.trim().toLowerCase();
14307
14621
  return value === "1" || value === "true" || value === "yes" || value === "on";
14308
14622
  }
14309
- function isRecord6(value) {
14623
+ function isRecord7(value) {
14310
14624
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
14311
14625
  }
14312
14626
  function stringValue2(value) {
@@ -14316,14 +14630,14 @@ function asArray(value) {
14316
14630
  return Array.isArray(value) ? value : [];
14317
14631
  }
14318
14632
  function extractionEntries2(value) {
14319
- if (Array.isArray(value)) return value.filter(isRecord6);
14320
- if (!isRecord6(value)) return [];
14633
+ if (Array.isArray(value)) return value.filter(isRecord7);
14634
+ if (!isRecord7(value)) return [];
14321
14635
  return Object.entries(value).map(
14322
- ([name, entry]) => isRecord6(entry) ? { name, ...entry } : { name }
14636
+ ([name, entry]) => isRecord7(entry) ? { name, ...entry } : { name }
14323
14637
  );
14324
14638
  }
14325
14639
  function firstRawPath(entry) {
14326
- const details = isRecord6(entry.details) ? entry.details : {};
14640
+ const details = isRecord7(entry.details) ? entry.details : {};
14327
14641
  const paths = [
14328
14642
  ...asArray(details.rawToolOutputPaths),
14329
14643
  ...asArray(details.raw_tool_output_paths),
@@ -14341,12 +14655,12 @@ function checkHintRawPath(value) {
14341
14655
  function collectStaticPipelineToolIds(staticPipeline) {
14342
14656
  const seen = /* @__PURE__ */ new Set();
14343
14657
  const visitPipeline = (pipeline) => {
14344
- if (!isRecord6(pipeline)) return;
14658
+ if (!isRecord7(pipeline)) return;
14345
14659
  for (const step of [
14346
14660
  ...asArray(pipeline.stages),
14347
14661
  ...asArray(pipeline.substeps)
14348
14662
  ]) {
14349
- if (!isRecord6(step)) continue;
14663
+ if (!isRecord7(step)) continue;
14350
14664
  if (step.type === "tool") {
14351
14665
  const toolId = stringValue2(step.toolId) || stringValue2(step.tool);
14352
14666
  if (toolId) seen.add(toolId);
@@ -14360,9 +14674,9 @@ function collectStaticPipelineToolIds(staticPipeline) {
14360
14674
  return [...seen].sort();
14361
14675
  }
14362
14676
  function toolGetterHintFromMetadata(toolId, tool) {
14363
- const usageGuidance = isRecord6(tool.usageGuidance) ? tool.usageGuidance : {};
14364
- const resultGuidance = isRecord6(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord6(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
14365
- const toolResponse = isRecord6(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord6(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
14677
+ const usageGuidance = isRecord7(tool.usageGuidance) ? tool.usageGuidance : {};
14678
+ const resultGuidance = isRecord7(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord7(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
14679
+ const toolResponse = isRecord7(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord7(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
14366
14680
  const lists = extractionEntries2(
14367
14681
  resultGuidance.extractedLists ?? resultGuidance.extracted_lists
14368
14682
  ).map((entry) => ({
@@ -14776,6 +15090,7 @@ async function handleFileBackedRun(options) {
14776
15090
  ...stagedFileInputs.packagedFiles.length ? { packagedFiles: stagedFileInputs.packagedFiles } : {},
14777
15091
  ...options.force ? { force: true } : {},
14778
15092
  ...options.profile ? { profile: options.profile } : {},
15093
+ ...options.debugMapLatency ? { testPolicyOverrides: { mapLatencyProfile: true } } : {},
14779
15094
  ...integrationMode ? { integrationMode } : {}
14780
15095
  };
14781
15096
  if (options.watch) {
@@ -14801,14 +15116,17 @@ async function handleFileBackedRun(options) {
14801
15116
  } else {
14802
15117
  progress.fail();
14803
15118
  }
14804
- const outputStatus = withTerminalPlayIdentity(
14805
- await resolvePlayRunOutputStatus({
14806
- client: client2,
14807
- status: finalStatus,
14808
- fullJson: options.fullJson,
14809
- jsonOutput: options.jsonOutput
14810
- }),
14811
- playName
15119
+ const outputStatus = withOrdinaryRunAgainCommand(
15120
+ withTerminalPlayIdentity(
15121
+ await resolvePlayRunOutputStatus({
15122
+ client: client2,
15123
+ status: finalStatus,
15124
+ fullJson: options.fullJson,
15125
+ jsonOutput: options.jsonOutput
15126
+ }),
15127
+ playName
15128
+ ),
15129
+ options
14812
15130
  );
14813
15131
  traceCliSync(
14814
15132
  "cli.play_write_result",
@@ -14817,7 +15135,7 @@ async function handleFileBackedRun(options) {
14817
15135
  fullJson: options.fullJson
14818
15136
  })
14819
15137
  );
14820
- return finalStatus.status === "completed" ? 0 : 1;
15138
+ return outputStatus.status === "completed" ? 0 : 1;
14821
15139
  }
14822
15140
  progress.phase("starting run");
14823
15141
  const started = await traceCliSpan(
@@ -14937,6 +15255,7 @@ async function handleNamedRun(options) {
14937
15255
  ...stagedFileInputs.packagedFiles.length ? { packagedFiles: stagedFileInputs.packagedFiles } : {},
14938
15256
  ...options.force ? { force: true } : {},
14939
15257
  ...options.profile ? { profile: options.profile } : {},
15258
+ ...options.debugMapLatency ? { testPolicyOverrides: { mapLatencyProfile: true } } : {},
14940
15259
  ...integrationMode ? { integrationMode } : {}
14941
15260
  };
14942
15261
  if (options.watch) {
@@ -14964,14 +15283,18 @@ async function handleNamedRun(options) {
14964
15283
  } else {
14965
15284
  progress.fail();
14966
15285
  }
14967
- const outputStatus = withTerminalPlayIdentity(
14968
- await resolvePlayRunOutputStatus({
14969
- client: client2,
14970
- status: finalStatus,
14971
- fullJson: options.fullJson,
14972
- jsonOutput: options.jsonOutput
14973
- }),
14974
- playName
15286
+ const outputStatus = withOrdinaryRunAgainCommand(
15287
+ withTerminalPlayIdentity(
15288
+ await resolvePlayRunOutputStatus({
15289
+ client: client2,
15290
+ status: finalStatus,
15291
+ fullJson: options.fullJson,
15292
+ jsonOutput: options.jsonOutput
15293
+ }),
15294
+ playName
15295
+ ),
15296
+ options,
15297
+ finalStatus.revisionId ?? selectedRevisionId
14975
15298
  );
14976
15299
  traceCliSync(
14977
15300
  "cli.play_write_result",
@@ -14980,7 +15303,7 @@ async function handleNamedRun(options) {
14980
15303
  fullJson: options.fullJson
14981
15304
  })
14982
15305
  );
14983
- return finalStatus.status === "completed" ? 0 : 1;
15306
+ return outputStatus.status === "completed" ? 0 : 1;
14984
15307
  }
14985
15308
  progress.phase("starting run");
14986
15309
  const started = await traceCliSpan(
@@ -15041,7 +15364,7 @@ async function handlePlayRun(args) {
15041
15364
  function parseRunIdPositional(args, usage) {
15042
15365
  for (let index = 0; index < args.length; index += 1) {
15043
15366
  const arg = args[index];
15044
- if (arg === "--json" || arg === "--full" || arg === "--logs" || arg === "--compact" || arg === "--limit") {
15367
+ if (arg === "--json" || arg === "--full" || arg === "--logs" || arg === "--compact" || arg === "--log-failed" || arg === "--failed" || arg === "--limit") {
15045
15368
  if (arg === "--limit" && args[index + 1]) {
15046
15369
  index += 1;
15047
15370
  }
@@ -15058,7 +15381,7 @@ function parseRunIdPositional(args, usage) {
15058
15381
  throw new DeeplineError(usage);
15059
15382
  }
15060
15383
  async function handleRunGet(args) {
15061
- const usage = "Usage: deepline runs get <run-id> [--json] [--full]";
15384
+ const usage = "Usage: deepline runs get <run-id> [--json] [--full] [--log-failed]";
15062
15385
  let runId;
15063
15386
  try {
15064
15387
  runId = parseRunIdPositional(args, usage);
@@ -15068,7 +15391,8 @@ async function handleRunGet(args) {
15068
15391
  }
15069
15392
  const client2 = new DeeplineClient();
15070
15393
  const status = await client2.runs.get(runId, {
15071
- full: args.includes("--full")
15394
+ full: args.includes("--full"),
15395
+ failedLogs: args.includes("--log-failed")
15072
15396
  });
15073
15397
  writePlayResult(status, argsWantJson(args), {
15074
15398
  fullJson: args.includes("--full")
@@ -15157,7 +15481,37 @@ async function handleRunTail(args) {
15157
15481
  }
15158
15482
  const client2 = new DeeplineClient();
15159
15483
  const jsonOutput = argsWantJson(args);
15484
+ const compact = args.includes("--compact");
15485
+ const compactState = {
15486
+ lastLogIndex: 0,
15487
+ emittedRunnerStarted: false,
15488
+ lastProgressSignature: null,
15489
+ lastProgressHeartbeatAt: 0,
15490
+ lastStatusHeartbeatAt: 0
15491
+ };
15160
15492
  const status = await client2.runs.tail(runId, {
15493
+ onEvent: compact && !jsonOutput ? (event) => {
15494
+ const transition = getStepTransitionLineFromLiveEvent(
15495
+ event,
15496
+ compactState
15497
+ );
15498
+ if (transition) process.stdout.write(`${transition}
15499
+ `);
15500
+ for (const line of getProgressLinesFromLiveEvent(event)) {
15501
+ const nowMs = Date.now();
15502
+ if (shouldPrintPlayProgressLine({
15503
+ signature: line,
15504
+ lastProgressSignature: compactState.lastProgressSignature,
15505
+ lastProgressHeartbeatAt: compactState.lastProgressHeartbeatAt,
15506
+ nowMs
15507
+ })) {
15508
+ compactState.lastProgressSignature = line;
15509
+ compactState.lastProgressHeartbeatAt = nowMs;
15510
+ process.stdout.write(`${line}
15511
+ `);
15512
+ }
15513
+ }
15514
+ } : void 0,
15161
15515
  // Human mode only: in --json mode emit nothing non-protocol.
15162
15516
  onReconnect: jsonOutput ? void 0 : ({ reason }) => {
15163
15517
  process.stderr.write(
@@ -15170,7 +15524,7 @@ async function handleRunTail(args) {
15170
15524
  return status.status === "failed" ? 1 : 0;
15171
15525
  }
15172
15526
  async function handleRunLogs(args) {
15173
- const usage = "Usage: deepline runs logs <run-id> [--limit 200] [--out run.log] [--json]";
15527
+ const usage = "Usage: deepline runs logs <run-id> [--limit 200] [--failed] [--out run.log] [--json]";
15174
15528
  let runId;
15175
15529
  try {
15176
15530
  runId = parseRunIdPositional(args, usage);
@@ -15180,6 +15534,7 @@ async function handleRunLogs(args) {
15180
15534
  }
15181
15535
  let limit = 200;
15182
15536
  let outPath = null;
15537
+ const failed = args.includes("--failed");
15183
15538
  for (let index = 0; index < args.length; index += 1) {
15184
15539
  const arg = args[index];
15185
15540
  if (arg === "--limit" && args[index + 1]) {
@@ -15190,6 +15545,12 @@ async function handleRunLogs(args) {
15190
15545
  outPath = (0, import_node_path11.resolve)(args[++index]);
15191
15546
  }
15192
15547
  }
15548
+ if (failed && outPath) {
15549
+ console.error(
15550
+ "--failed cannot be combined with --out. Remove --failed to export the full persisted log stream."
15551
+ );
15552
+ return 1;
15553
+ }
15193
15554
  const client2 = new DeeplineClient();
15194
15555
  if (outPath) {
15195
15556
  const result2 = await client2.runs.logs(runId, { all: true });
@@ -15221,7 +15582,8 @@ async function handleRunLogs(args) {
15221
15582
  );
15222
15583
  return 0;
15223
15584
  }
15224
- const result = await client2.runs.logs(runId, { limit });
15585
+ const result = await client2.runs.logs(runId, { limit, failed });
15586
+ const text = buildRunLogsText(result);
15225
15587
  printCommandEnvelope(
15226
15588
  {
15227
15589
  runId: result.runId,
@@ -15233,18 +15595,33 @@ async function handleRunLogs(args) {
15233
15595
  hasMore: result.hasMore,
15234
15596
  ...result.logsTruncated ? { logsTruncated: true } : {},
15235
15597
  entries: result.entries,
15598
+ ...result.view ? { view: result.view } : {},
15599
+ ...result.association ? { association: result.association } : {},
15600
+ ...result.warning ? { warning: result.warning } : {},
15236
15601
  next: {
15602
+ ...result.next ?? {},
15237
15603
  export: `deepline runs logs ${result.runId} --out run.log --json`
15238
15604
  },
15239
15605
  render: { sections: [{ title: "run logs", lines: result.entries }] }
15240
15606
  },
15241
15607
  {
15242
15608
  json: argsWantJson(args),
15243
- text: `${result.entries.join("\n")}${result.entries.length > 0 ? "\n" : ""}`
15609
+ text
15244
15610
  }
15245
15611
  );
15246
15612
  return 0;
15247
15613
  }
15614
+ function buildRunLogsText(result) {
15615
+ const lines = [...result.entries];
15616
+ if (result.warning) {
15617
+ if (lines.length > 0) lines.push("");
15618
+ lines.push(`warning: ${result.warning}`);
15619
+ lines.push(
15620
+ `retained logs: ${result.next?.logs ?? `deepline runs logs ${result.runId} --out run.log --json`}`
15621
+ );
15622
+ }
15623
+ return `${lines.join("\n")}${lines.length > 0 ? "\n" : ""}`;
15624
+ }
15248
15625
  async function handleRunStop(args) {
15249
15626
  const usage = 'Usage: deepline runs stop <run-id> [--reason "text"] [--json]';
15250
15627
  let runId;
@@ -16143,8 +16520,8 @@ Idempotent execution:
16143
16520
 
16144
16521
  await ctx.tools.execute({ id: 'company_lookup', tool, input });
16145
16522
 
16146
- The authored id is still required for readable logs, metadata, and receipt
16147
- attachment, but renaming it alone does not rebuy the same provider request.
16523
+ The authored id is still required for readable logs and metadata, but
16524
+ renaming it alone does not rebuy the same provider request.
16148
16525
 
16149
16526
  For rows, use ctx.dataset plus a stable row key:
16150
16527
 
@@ -16185,7 +16562,10 @@ Examples:
16185
16562
  ).option("--watch", "Compatibility alias; run waits by default").option("--wait", "Compatibility alias; run waits by default").option("--no-wait", "Start the run and return immediately").option(
16186
16563
  "--logs",
16187
16564
  "When output is non-interactive, stream play logs to stderr while waiting"
16188
- ).option("--tail-timeout-ms <ms>", "Timeout while watching the run stream").option("--force", "Start a fresh run graph").option("--no-open", "Print the play page URL without opening a browser").option("--json", "Emit JSON output").option("--full", "Debug only: with --json, emit the raw status payload").addHelpText(
16565
+ ).option("--tail-timeout-ms <ms>", "Timeout while watching the run stream").option("--force", "Start a fresh run graph").option(
16566
+ "--debug-map-latency",
16567
+ "Internal diagnostics: emit one aggregate latency profile per dataset map"
16568
+ ).option("--no-open", "Print the play page URL without opening a browser").option("--json", "Emit JSON output").option("--full", "Debug only: with --json, emit the raw status payload").addHelpText(
16189
16569
  "afterAll",
16190
16570
  `
16191
16571
  Pass-through input flags:
@@ -16221,6 +16601,7 @@ Pass-through input flags:
16221
16601
  ...options.logs ? ["--logs"] : [],
16222
16602
  ...options.tailTimeoutMs ? ["--tail-timeout-ms", options.tailTimeoutMs] : [],
16223
16603
  ...options.force ? ["--force"] : [],
16604
+ ...options.debugMapLatency ? ["--debug-map-latency"] : [],
16224
16605
  ...options.noOpen || options.open === false ? ["--no-open"] : [],
16225
16606
  ...options.json ? ["--json"] : [],
16226
16607
  ...options.full ? ["--full"] : [],
@@ -16449,13 +16830,18 @@ Notes:
16449
16830
  Examples:
16450
16831
  deepline runs get play/my-play/run/20260501t000000-000
16451
16832
  deepline runs get play/my-play/run/20260501t000000-000 --json
16833
+ deepline runs get play/my-play/run/20260501t000000-000 --log-failed --json
16452
16834
  deepline runs get play/my-play/run/20260501t000000-000 --full --json
16453
16835
  `
16454
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--full", "Debug only: with --json, emit the raw status payload").action(async (runId, options) => {
16836
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--full", "Debug only: with --json, emit the raw status payload").option(
16837
+ "--log-failed",
16838
+ "Attach a bounded terminal-failure log window for failed runs"
16839
+ ).action(async (runId, options) => {
16455
16840
  process.exitCode = await handleRunGet([
16456
16841
  runId,
16457
16842
  ...options.json ? ["--json"] : [],
16458
- ...options.full ? ["--full"] : []
16843
+ ...options.full ? ["--full"] : [],
16844
+ ...options.logFailed ? ["--log-failed"] : []
16459
16845
  ]);
16460
16846
  });
16461
16847
  runs.command("list").description("List play runs.").addHelpText(
@@ -16499,13 +16885,17 @@ Examples:
16499
16885
  `
16500
16886
  Notes:
16501
16887
  Streams live run events until the stream ends. Use get for current status and
16502
- logs for persisted log history.
16888
+ logs for persisted log history. In human output, --compact prints deduplicated
16889
+ step transitions and progress instead of the full event stream.
16503
16890
 
16504
16891
  Examples:
16505
16892
  deepline runs tail play/my-play/run/20260501t000000-000
16506
16893
  deepline runs tail play/my-play/run/20260501t000000-000 --compact --json
16507
16894
  `
16508
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--compact", "Drop verbose fields from JSON output").action(async (runId, options) => {
16895
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
16896
+ "--compact",
16897
+ "Show deduplicated step transitions and progress; compact JSON output"
16898
+ ).action(async (runId, options) => {
16509
16899
  process.exitCode = await handleRunTail([
16510
16900
  runId,
16511
16901
  ...options.json ? ["--json"] : [],
@@ -16522,17 +16912,19 @@ Notes:
16522
16912
  Examples:
16523
16913
  deepline runs logs play/my-play/run/20260501t000000-000
16524
16914
  deepline runs logs play/my-play/run/20260501t000000-000 --limit 500
16915
+ deepline runs logs play/my-play/run/20260501t000000-000 --failed --json
16525
16916
  deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
16526
16917
  `
16527
16918
  ).option(
16528
16919
  "--limit <count>",
16529
16920
  "Maximum recent log lines to print without --out",
16530
16921
  "200"
16531
- ).option("--out <path>", "Write the full persisted log stream to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
16922
+ ).option("--out <path>", "Write the full persisted log stream to a file").option("--failed", "Show the bounded terminal-failure log window").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
16532
16923
  process.exitCode = await handleRunLogs([
16533
16924
  runId,
16534
16925
  ...options.limit ? ["--limit", options.limit] : [],
16535
16926
  ...options.out ? ["--out", options.out] : [],
16927
+ ...options.failed ? ["--failed"] : [],
16536
16928
  ...options.json ? ["--json"] : []
16537
16929
  ]);
16538
16930
  });
@@ -17270,6 +17662,8 @@ function renderPlayStep(command, options) {
17270
17662
  ` const __dlRunIf = ${runIfJs};`,
17271
17663
  ` if (!__dlRunIf(templateRow)) return null;`
17272
17664
  ] : [];
17665
+ const inline = command.play?.inline;
17666
+ const inlineHandler = inline ? `__dlInlinePlay_${inline.sourceHash.slice(0, 16)}` : null;
17273
17667
  return [
17274
17668
  `async (row, stepCtx) => {`,
17275
17669
  ...options.precheck ? [` if (${options.precheck}) return null;`] : [],
@@ -17279,9 +17673,16 @@ function renderPlayStep(command, options) {
17279
17673
  ` if (__dlShouldSkipBlankPlayPayload(payload)) return null;`,
17280
17674
  ` let result: unknown;`,
17281
17675
  ` try {`,
17282
- ` result = await stepCtx.runPlay(${callId}, ${playRef}, payload, {`,
17283
- ` description: ${stringLiteral(command.description ?? command.alias)}`,
17284
- ` });`,
17676
+ ...inlineHandler ? [
17677
+ // Enrich validates and normalizes this payload against the certified
17678
+ // prebuilt contract before code generation. The attachment retains
17679
+ // its concrete input type, while generated payloads are records.
17680
+ ` result = await __dlRunInlinePlay(${inlineHandler}, stepCtx, payload as never, ${options.force});`
17681
+ ] : [
17682
+ ` result = await stepCtx.runPlay(${callId}, ${playRef}, payload, {`,
17683
+ ` description: ${stringLiteral(command.description ?? command.alias)}`,
17684
+ ` });`
17685
+ ],
17285
17686
  ` } catch (error) {`,
17286
17687
  ...options.waterfallSoftFail ? [` return __dlWaterfallToolFailure(error);`] : [` throw error;`],
17287
17688
  ` }`,
@@ -17289,6 +17690,19 @@ function renderPlayStep(command, options) {
17289
17690
  `}`
17290
17691
  ].join("\n");
17291
17692
  }
17693
+ function collectInlinePlayHandlers(commands) {
17694
+ const handlers = /* @__PURE__ */ new Map();
17695
+ const visit = (command) => {
17696
+ if (isWaterfall(command)) {
17697
+ command.commands.forEach(visit);
17698
+ return;
17699
+ }
17700
+ const inline = command.play?.inline;
17701
+ if (inline) handlers.set(inline.sourceHash, inline);
17702
+ };
17703
+ commands.forEach(visit);
17704
+ return [...handlers.values()];
17705
+ }
17292
17706
  function renderInlineJavascriptStep(command, options) {
17293
17707
  const alias = stringLiteral(command.alias);
17294
17708
  const extractJs = renderExtractFunction(command, 4);
@@ -17489,6 +17903,10 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
17489
17903
  [...options.forceAliases ?? []].map((alias) => normalizeAlias(alias))
17490
17904
  );
17491
17905
  const columnSteps = [];
17906
+ const inlineHandlers = collectInlinePlayHandlers(config.commands);
17907
+ const inlineTypeImports = [
17908
+ ...new Set(inlineHandlers.flatMap((inline) => inline.typeImports ?? []))
17909
+ ].sort();
17492
17910
  config.commands.forEach((command) => {
17493
17911
  if (isWaterfall(command)) {
17494
17912
  columnSteps.push(
@@ -17526,6 +17944,19 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
17526
17944
  const generatedAliases = collectGeneratedAliases(config.commands);
17527
17945
  const runOptionsSource = options.failFast ? `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart), onRowError: 'fail' as const }` : `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart) }`;
17528
17946
  const body = [
17947
+ `function __dlRunInlinePlay<TContext, TInput, TOutput>(handler: (ctx: TContext, input: TInput) => Promise<TOutput>, scope: TContext, payload: TInput, force: boolean): Promise<TOutput> {`,
17948
+ ` if (!force) return handler(scope, payload);`,
17949
+ ` const runtimeScope = scope as TContext & { __deeplineRunWithForcedTools?: <T>(run: () => Promise<T>) => Promise<T> };`,
17950
+ ` if (typeof runtimeScope.__deeplineRunWithForcedTools !== 'function') {`,
17951
+ ` throw new Error('This runtime does not support forced certified inline play execution.');`,
17952
+ ` }`,
17953
+ ` return runtimeScope.__deeplineRunWithForcedTools(() => handler(scope, payload));`,
17954
+ `}`,
17955
+ ``,
17956
+ ...inlineHandlers.flatMap((inline) => [
17957
+ `const __dlInlinePlay_${inline.sourceHash.slice(0, 16)} = ${inline.functionExpressionSource};`,
17958
+ ``
17959
+ ]),
17529
17960
  `export default definePlay(${stringLiteral(playName)}, async (ctx, input: EnrichInput) => {`,
17530
17961
  ` const sourceRows = await ctx.csv<Record<string, unknown>>(input.file);`,
17531
17962
  ` const rowStart = __dlNonNegativeInteger(input.rowStart, 0);`,
@@ -17550,7 +17981,8 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
17550
17981
  const helpers = idiomaticGetters ? selectUsedHelpers(helperSource(), body.join("\n")) : helperSource();
17551
17982
  return [
17552
17983
  ...inlineRunJavascript && configHasRunJavascript(config) ? ["// @ts-nocheck", "/* eslint-disable */", ""] : [],
17553
- `import { definePlay } from 'deepline';`,
17984
+ `import { definePlay, steps } from 'deepline';`,
17985
+ ...inlineTypeImports.length > 0 ? [`import type { ${inlineTypeImports.join(", ")} } from 'deepline';`] : [],
17554
17986
  ``,
17555
17987
  `type EnrichInput = { file: string; rowStart?: number | null; rowEnd?: number | null };`,
17556
17988
  ``,
@@ -18405,7 +18837,7 @@ function isMarkedTestAiInferenceCommand(command) {
18405
18837
  if (normalizeEnrichPlayRef(command.tool) !== "run_javascript") {
18406
18838
  return false;
18407
18839
  }
18408
- return isRecord7(command.payload) && command.payload[ENRICH_TEST_AI_INFERENCE_PAYLOAD_MARKER] === true;
18840
+ return isRecord8(command.payload) && command.payload[ENRICH_TEST_AI_INFERENCE_PAYLOAD_MARKER] === true;
18409
18841
  }
18410
18842
  function enrichDebugEnabled(env = process.env) {
18411
18843
  const raw = String(env.DEEPLINE_DEBUG_ENRICH ?? "").trim().toLowerCase();
@@ -18664,6 +19096,27 @@ function sdkEnrichCommandText(args) {
18664
19096
  }
18665
19097
  return `${command.slice(0, SDK_ENRICH_TELEMETRY_COMMAND_MAX_LENGTH - 3)}...`;
18666
19098
  }
19099
+ function rewriteGeneratedPlayRerunForEnrich(status, enrichCommand) {
19100
+ const rewrite = (value) => {
19101
+ if (Array.isArray(value)) {
19102
+ return value.map(rewrite);
19103
+ }
19104
+ if (!isRecord8(value)) {
19105
+ return value;
19106
+ }
19107
+ const next = Object.fromEntries(
19108
+ Object.entries(value).map(([key, entry]) => [
19109
+ key,
19110
+ key === "rerunCommand" && typeof entry === "string" ? enrichCommand : rewrite(entry)
19111
+ ])
19112
+ );
19113
+ if (isRecord8(next.next) && typeof next.next.run === "string") {
19114
+ next.next = { ...next.next, run: enrichCommand };
19115
+ }
19116
+ return next;
19117
+ };
19118
+ return rewrite(status);
19119
+ }
18667
19120
  function countConfiguredEnrichColumns(config) {
18668
19121
  const count = (commands) => commands.reduce((total, command) => {
18669
19122
  if ("with_waterfall" in command) {
@@ -18765,7 +19218,8 @@ async function buildPlanArgs(args) {
18765
19218
  "--fail-fast",
18766
19219
  "--all",
18767
19220
  "--in-place",
18768
- "--no-open"
19221
+ "--no-open",
19222
+ "--debug-map-latency"
18769
19223
  ]);
18770
19224
  const planArgs = [];
18771
19225
  for (let index = 0; index < args.length; index += 1) {
@@ -19120,7 +19574,7 @@ async function resolveWatchedGeneratedPlayStatus(input2) {
19120
19574
  }
19121
19575
  return input2.client.runs.get(runId, { full: true });
19122
19576
  }
19123
- function isRecord7(value) {
19577
+ function isRecord8(value) {
19124
19578
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
19125
19579
  }
19126
19580
  async function captureStdout(run, options = {}) {
@@ -19407,13 +19861,13 @@ function readFirstEnrichDatasetActions(value) {
19407
19861
  return null;
19408
19862
  }
19409
19863
  const record = candidate;
19410
- const actions = isRecord7(record.actions) ? record.actions : null;
19411
- const query = isRecord7(actions?.query) ? actions.query : null;
19864
+ const actions = isRecord8(record.actions) ? record.actions : null;
19865
+ const query = isRecord8(actions?.query) ? actions.query : null;
19412
19866
  if (query?.kind === "deepline_db_query") {
19413
19867
  return {
19414
19868
  dataset: record,
19415
19869
  query,
19416
- ...isRecord7(actions?.exportCsv) ? { exportCsv: actions.exportCsv } : {}
19870
+ ...isRecord8(actions?.exportCsv) ? { exportCsv: actions.exportCsv } : {}
19417
19871
  };
19418
19872
  }
19419
19873
  if (options.allowLegacy && record.kind === "dataset" && typeof record.queryDatasetCommand === "string" && record.queryDatasetCommand.trim()) {
@@ -19466,7 +19920,7 @@ function enrichCustomerDbJson(input2) {
19466
19920
  const dataset = actions.dataset;
19467
19921
  const sql = actionStringField(query, "sql") ?? parseSqlFromDbQueryCommand(actions.queryDatasetCommand);
19468
19922
  const datasetPath = actionStringField(query, "datasetPath") ?? actionStringField(dataset, "path") ?? actionStringField(dataset, "tableNamespace");
19469
- const api = isRecord7(query.api) ? query.api : null;
19923
+ const api = isRecord8(query.api) ? query.api : null;
19470
19924
  const apiPath = actionStringField(api ?? {}, "path") ?? "/api/v2/db/query";
19471
19925
  const apiMethod = actionStringField(api ?? {}, "method") ?? "POST";
19472
19926
  if (!datasetPath) {
@@ -19535,11 +19989,11 @@ function sqlStringLiteral(value) {
19535
19989
  return `'${value.replace(/'/g, "''")}'`;
19536
19990
  }
19537
19991
  function failureAliasFromCellMeta(cellMeta) {
19538
- if (!isRecord7(cellMeta)) {
19992
+ if (!isRecord8(cellMeta)) {
19539
19993
  return null;
19540
19994
  }
19541
19995
  for (const [alias, meta] of Object.entries(cellMeta)) {
19542
- if (!isRecord7(meta)) {
19996
+ if (!isRecord8(meta)) {
19543
19997
  continue;
19544
19998
  }
19545
19999
  const failure = failureCellFromMeta(meta, {});
@@ -20077,7 +20531,7 @@ function exportableSheetRow2(row, sourceRowStart = 0) {
20077
20531
  return fallback;
20078
20532
  }
20079
20533
  function failureCellFromMeta(meta, fallback) {
20080
- if (!isRecord7(meta)) {
20534
+ if (!isRecord8(meta)) {
20081
20535
  return null;
20082
20536
  }
20083
20537
  const status = typeof meta.status === "string" ? meta.status.trim().toLowerCase() : "";
@@ -20097,7 +20551,7 @@ function failureCellFromMeta(meta, fallback) {
20097
20551
  };
20098
20552
  }
20099
20553
  function applyFailureCellMeta(row, cellMeta, fallback) {
20100
- if (!isRecord7(cellMeta)) {
20554
+ if (!isRecord8(cellMeta)) {
20101
20555
  return;
20102
20556
  }
20103
20557
  for (const [field, meta] of Object.entries(cellMeta)) {
@@ -20341,7 +20795,7 @@ function stableRowSnapshot(value) {
20341
20795
  }
20342
20796
  function cellFailureError(value) {
20343
20797
  const parsed = parseMaybeJsonObject(value);
20344
- if (!isRecord7(parsed)) {
20798
+ if (!isRecord8(parsed)) {
20345
20799
  const text = typeof parsed === "string" ? parsed.trim() : "";
20346
20800
  if (/^(?:[A-Za-z0-9_:-]+:\s*)?(?:Error|TypeError|ReferenceError|SyntaxError|RangeError):\s+/.test(
20347
20801
  text
@@ -20349,12 +20803,12 @@ function cellFailureError(value) {
20349
20803
  return { message: text };
20350
20804
  }
20351
20805
  }
20352
- if (!isRecord7(parsed)) {
20806
+ if (!isRecord8(parsed)) {
20353
20807
  return null;
20354
20808
  }
20355
20809
  const status = typeof parsed.status === "string" ? parsed.status.trim().toLowerCase() : "";
20356
20810
  const directError = typeof parsed.error === "string" ? parsed.error.trim() : typeof parsed.last_error === "string" ? parsed.last_error.trim() : "";
20357
- const result = isRecord7(parsed.result) ? parsed.result : null;
20811
+ const result = isRecord8(parsed.result) ? parsed.result : null;
20358
20812
  const resultError = typeof result?.error === "string" ? result.error.trim() : typeof result?.message === "string" ? result.message.trim() : "";
20359
20813
  if (!directError && !resultError && status !== "error" && status !== "failed") {
20360
20814
  return null;
@@ -20424,7 +20878,7 @@ function assignFlattenedFailurePath(target, field, value) {
20424
20878
  let cursor = target;
20425
20879
  for (const part of normalized.slice(0, -1)) {
20426
20880
  const existing = cursor[part];
20427
- if (!isRecord7(existing)) {
20881
+ if (!isRecord8(existing)) {
20428
20882
  const next = {};
20429
20883
  cursor[part] = next;
20430
20884
  cursor = next;
@@ -20588,10 +21042,10 @@ function waterfallExecutionSignal(status, spec) {
20588
21042
  let everyChildStatOnlyConditionSkipped = true;
20589
21043
  const childAliasesWithStats = /* @__PURE__ */ new Set();
20590
21044
  for (const childAlias of childAliases) {
20591
- for (const stat2 of summaries.map((summary) => summary[childAlias]).filter(isRecord7)) {
21045
+ for (const stat2 of summaries.map((summary) => summary[childAlias]).filter(isRecord8)) {
20592
21046
  sawChildStats = true;
20593
21047
  childAliasesWithStats.add(childAlias);
20594
- const execution = isRecord7(stat2.execution) ? stat2.execution : null;
21048
+ const execution = isRecord8(stat2.execution) ? stat2.execution : null;
20595
21049
  const executedSummary = parseExecutionSummary(
20596
21050
  execution?.["completed:executed"]
20597
21051
  );
@@ -20621,7 +21075,7 @@ function waterfallExecutionSignal(status, spec) {
20621
21075
  }
20622
21076
  function emptyWaterfallStatsEvidence(status, spec) {
20623
21077
  const summaries = collectColumnStats(status);
20624
- const parentStats = summaries.map((summary) => summary[spec.alias]).filter(isRecord7);
21078
+ const parentStats = summaries.map((summary) => summary[spec.alias]).filter(isRecord8);
20625
21079
  for (const stat2 of parentStats) {
20626
21080
  const nonEmpty = parseExecutionSummary(stat2.non_empty);
20627
21081
  if (nonEmpty?.total && nonEmpty.count === 0) {
@@ -20635,7 +21089,7 @@ function emptyWaterfallStatsEvidence(status, spec) {
20635
21089
  let selectedRows = 0;
20636
21090
  let sawStatsForEveryChild = true;
20637
21091
  for (const childAlias of childAliases) {
20638
- const stat2 = summaries.map((summary) => summary[childAlias]).find(isRecord7);
21092
+ const stat2 = summaries.map((summary) => summary[childAlias]).find(isRecord8);
20639
21093
  if (!stat2) {
20640
21094
  sawStatsForEveryChild = false;
20641
21095
  break;
@@ -20644,7 +21098,7 @@ function emptyWaterfallStatsEvidence(status, spec) {
20644
21098
  if ((nonEmpty?.count ?? 0) > 0) {
20645
21099
  return null;
20646
21100
  }
20647
- const execution = isRecord7(stat2.execution) ? stat2.execution : null;
21101
+ const execution = isRecord8(stat2.execution) ? stat2.execution : null;
20648
21102
  const executed = parseExecutionSummary(execution?.["completed:executed"]);
20649
21103
  const reused = parseExecutionSummary(execution?.["completed:reused"]);
20650
21104
  const skipped = parseExecutionSummary(execution?.["skipped:condition"]);
@@ -20686,11 +21140,11 @@ function collectStatusFailureJobs(input2) {
20686
21140
  const jobs = [];
20687
21141
  aliases.forEach((spec, aliasIndex) => {
20688
21142
  const { alias } = spec;
20689
- const stat2 = summaries.map((summary) => summary[alias]).find(isRecord7);
21143
+ const stat2 = summaries.map((summary) => summary[alias]).find(isRecord8);
20690
21144
  if (!stat2) {
20691
21145
  return;
20692
21146
  }
20693
- const execution = isRecord7(stat2.execution) ? stat2.execution : null;
21147
+ const execution = isRecord8(stat2.execution) ? stat2.execution : null;
20694
21148
  const failedCount = Math.min(
20695
21149
  selectedRows,
20696
21150
  Math.max(
@@ -20797,10 +21251,10 @@ function collectColumnStats(status) {
20797
21251
  value.forEach(visit);
20798
21252
  return;
20799
21253
  }
20800
- if (!isRecord7(value)) {
21254
+ if (!isRecord8(value)) {
20801
21255
  return;
20802
21256
  }
20803
- if (isRecord7(value.columnStats)) {
21257
+ if (isRecord8(value.columnStats)) {
20804
21258
  summaries.push(value.columnStats);
20805
21259
  }
20806
21260
  Object.values(value).forEach(visit);
@@ -20812,12 +21266,12 @@ function firstAliasExecutionCounts(input2) {
20812
21266
  const aliases = collectConfigScalarAliasOrder(input2.config);
20813
21267
  const summaries = collectColumnStats(input2.status);
20814
21268
  for (const alias of aliases) {
20815
- const stat2 = summaries.map((summary) => summary[alias]).find(isRecord7);
21269
+ const stat2 = summaries.map((summary) => summary[alias]).find(isRecord8);
20816
21270
  if (!stat2) continue;
20817
21271
  if (input2.forceAliases.has(normalizeAlias2(alias))) {
20818
21272
  return { executed: input2.selectedRows, reused: 0 };
20819
21273
  }
20820
- const execution = isRecord7(stat2.execution) ? stat2.execution : null;
21274
+ const execution = isRecord8(stat2.execution) ? stat2.execution : null;
20821
21275
  if (!execution) continue;
20822
21276
  return {
20823
21277
  executed: parseExecutionCount(execution["completed:executed"]),
@@ -20844,14 +21298,14 @@ function rewriteEnrichJsonStatus(input2) {
20844
21298
  if (Array.isArray(value)) {
20845
21299
  return value.map(rewrite);
20846
21300
  }
20847
- if (!isRecord7(value)) {
21301
+ if (!isRecord8(value)) {
20848
21302
  return value;
20849
21303
  }
20850
21304
  const next = {};
20851
21305
  for (const [key, entry] of Object.entries(value)) {
20852
21306
  next[key] = rewrite(entry);
20853
21307
  }
20854
- if (isRecord7(next.progress)) {
21308
+ if (isRecord8(next.progress)) {
20855
21309
  next.progress = {
20856
21310
  ...next.progress,
20857
21311
  ...selectedRows > 0 ? { total: selectedRows } : {},
@@ -20860,8 +21314,8 @@ function rewriteEnrichJsonStatus(input2) {
20860
21314
  ...failedRows > 0 ? { failed: failedRows, pending: 0 } : {}
20861
21315
  };
20862
21316
  }
20863
- if (isRecord7(next.summary)) {
20864
- const rowCounts = isRecord7(next.summary.rowCounts) ? next.summary.rowCounts : null;
21317
+ if (isRecord8(next.summary)) {
21318
+ const rowCounts = isRecord8(next.summary.rowCounts) ? next.summary.rowCounts : null;
20865
21319
  if (failedRows > 0) {
20866
21320
  next.summary = {
20867
21321
  ...next.summary,
@@ -20874,11 +21328,11 @@ function rewriteEnrichJsonStatus(input2) {
20874
21328
  };
20875
21329
  }
20876
21330
  }
20877
- if (isRecord7(next.columnStats) && selectedRows > 0) {
21331
+ if (isRecord8(next.columnStats) && selectedRows > 0) {
20878
21332
  const columnStats = { ...next.columnStats };
20879
21333
  for (const alias of forcedAliases) {
20880
- const stat2 = isRecord7(columnStats[alias]) ? columnStats[alias] : null;
20881
- const execution = isRecord7(stat2?.execution) ? stat2.execution : null;
21334
+ const stat2 = isRecord8(columnStats[alias]) ? columnStats[alias] : null;
21335
+ const execution = isRecord8(stat2?.execution) ? stat2.execution : null;
20882
21336
  if (!stat2 || !execution) continue;
20883
21337
  columnStats[alias] = {
20884
21338
  ...stat2,
@@ -20897,14 +21351,14 @@ function rewriteEnrichJsonStatus(input2) {
20897
21351
  return next;
20898
21352
  };
20899
21353
  const rewritten = rewrite(input2.status);
20900
- if (failedRows === 0 || !isRecord7(rewritten)) {
21354
+ if (failedRows === 0 || !isRecord8(rewritten)) {
20901
21355
  return rewritten;
20902
21356
  }
20903
21357
  const partialStatus = selectedRows > 0 && failedRows < selectedRows ? "partial_success" : "failed";
20904
21358
  return {
20905
21359
  ...rewritten,
20906
21360
  ...rewritten.status === "completed" || rewritten.status === "failed" ? { status: partialStatus } : {},
20907
- ...isRecord7(rewritten.run) && (rewritten.run.status === "completed" || rewritten.run.status === "failed") ? { run: { ...rewritten.run, status: partialStatus } } : {}
21361
+ ...isRecord8(rewritten.run) && (rewritten.run.status === "completed" || rewritten.run.status === "failed") ? { run: { ...rewritten.run, status: partialStatus } } : {}
20908
21362
  };
20909
21363
  }
20910
21364
  function summarizeFailedJobError(value) {
@@ -21318,11 +21772,15 @@ async function fetchBackingRowsForCsvExport(input2) {
21318
21772
  }
21319
21773
  function mergeRowsForCsvExport(enrichedRows, options) {
21320
21774
  const compactAliases = options?.config ? enrichAiRuntimeCompactAliases(options.config) : /* @__PURE__ */ new Set();
21775
+ const preservedAliases = /* @__PURE__ */ new Set([
21776
+ ...compactAliases,
21777
+ ...options?.config ? collectConfigPlayAliases(options.config) : []
21778
+ ]);
21321
21779
  const rows = dataExportRows(
21322
21780
  normalizeEnrichRowsForCsvExport(enrichedRows, options?.config, {
21323
21781
  statusFailureMessages: options?.statusFailureMessages
21324
21782
  }),
21325
- { preserveJsonStringColumns: compactAliases }
21783
+ { preserveJsonStringColumns: preservedAliases }
21326
21784
  );
21327
21785
  const range = options?.rows;
21328
21786
  if (!options?.sourceCsvPath) {
@@ -21399,6 +21857,22 @@ function mergeRowsForCsvExport(enrichedRows, options) {
21399
21857
  }
21400
21858
  return { rows: merged, preferredColumns };
21401
21859
  }
21860
+ function collectConfigPlayAliases(config) {
21861
+ const aliases = /* @__PURE__ */ new Set();
21862
+ const visit = (commands) => {
21863
+ for (const command of commands) {
21864
+ if ("with_waterfall" in command) {
21865
+ visit(command.commands);
21866
+ continue;
21867
+ }
21868
+ if (!command.disabled && command.play) {
21869
+ aliases.add(normalizeAlias2(command.alias));
21870
+ }
21871
+ }
21872
+ };
21873
+ visit(config.commands);
21874
+ return aliases;
21875
+ }
21402
21876
  function collectConfigScalarAliasOrder(config) {
21403
21877
  const aliases = [];
21404
21878
  const seen = /* @__PURE__ */ new Set();
@@ -21496,7 +21970,7 @@ function materializeCsvCellValue(value) {
21496
21970
  return value;
21497
21971
  }
21498
21972
  function compactArrayEnvelopeCompleteValue(value) {
21499
- if (!isRecord7(value) || value.kind !== "array") {
21973
+ if (!isRecord8(value) || value.kind !== "array") {
21500
21974
  return null;
21501
21975
  }
21502
21976
  if (!Array.isArray(value.preview)) {
@@ -21510,7 +21984,7 @@ function compactArrayEnvelopeCompleteValue(value) {
21510
21984
  }
21511
21985
  function disambiguateCompactAiInferencePayload(value) {
21512
21986
  const parsed = parseMaybeJsonObject(value);
21513
- if (!isRecord7(parsed) || !cellFailureError(parsed)) {
21987
+ if (!isRecord8(parsed) || !cellFailureError(parsed)) {
21514
21988
  return value;
21515
21989
  }
21516
21990
  return {
@@ -21519,14 +21993,14 @@ function disambiguateCompactAiInferencePayload(value) {
21519
21993
  };
21520
21994
  }
21521
21995
  function compactAiInferenceCellForCsv(value) {
21522
- if (!isRecord7(value)) {
21996
+ if (!isRecord8(value)) {
21523
21997
  return value;
21524
21998
  }
21525
21999
  const extractedJson = value.extracted_json;
21526
22000
  if (extractedJson !== null && extractedJson !== void 0) {
21527
22001
  return disambiguateCompactAiInferencePayload(extractedJson);
21528
22002
  }
21529
- const result = isRecord7(value.result) ? value.result : null;
22003
+ const result = isRecord8(value.result) ? value.result : null;
21530
22004
  const object = result?.object;
21531
22005
  if (object !== null && object !== void 0) {
21532
22006
  return disambiguateCompactAiInferencePayload(object);
@@ -21543,17 +22017,20 @@ function compactAiInferenceCellForCsv(value) {
21543
22017
  }
21544
22018
  function materializeEnrichAliasCellForCsv(row, alias, options) {
21545
22019
  const direct = row[alias];
21546
- if (isRecord7(direct)) {
22020
+ if (isRecord8(direct)) {
21547
22021
  const completeArray = compactArrayEnvelopeCompleteValue(direct);
21548
22022
  if (completeArray) {
21549
22023
  return materializeCsvCellValue(completeArray);
21550
22024
  }
21551
- if (options?.compactAiCell && direct.status === "completed" && (isRecord7(direct.result) || Object.prototype.hasOwnProperty.call(direct, "extracted_json") || typeof direct.output === "string")) {
22025
+ if (options?.compactAiCell && direct.status === "completed" && (isRecord8(direct.result) || Object.prototype.hasOwnProperty.call(direct, "extracted_json") || typeof direct.output === "string")) {
21552
22026
  return materializeCsvCellValue(compactAiInferenceCellForCsv(direct));
21553
22027
  }
21554
22028
  if (Object.prototype.hasOwnProperty.call(direct, "matched_result") || Object.prototype.hasOwnProperty.call(direct, "matchedResult") || Object.prototype.hasOwnProperty.call(direct, "result")) {
21555
22029
  return materializeCsvCellValue(direct);
21556
22030
  }
22031
+ if (options?.preservePlainObject && !Object.prototype.hasOwnProperty.call(direct, "_metadata")) {
22032
+ return materializeCsvCellValue(direct);
22033
+ }
21557
22034
  const directCells = [];
21558
22035
  for (const [field, value] of Object.entries(direct)) {
21559
22036
  if (!isEnrichAliasPayloadField(field)) {
@@ -21610,6 +22087,7 @@ function materializeEnrichAliasCellForCsv(row, alias, options) {
21610
22087
  function normalizeEnrichRowsForCsvExport(rows, config, options) {
21611
22088
  const aliases = config ? collectConfigScalarAliasOrder(config) : [];
21612
22089
  const aiCompactAliases = config ? enrichAiRuntimeCompactAliases(config) : null;
22090
+ const playAliases = config ? collectConfigPlayAliases(config) : /* @__PURE__ */ new Set();
21613
22091
  const failureOperationByAlias = hardFailureOperationByAlias(config);
21614
22092
  return rows.map((row) => {
21615
22093
  const metadata = legacyMetadataFromRow(row);
@@ -21653,7 +22131,8 @@ function normalizeEnrichRowsForCsvExport(rows, config, options) {
21653
22131
  }
21654
22132
  for (const alias of aliases) {
21655
22133
  const value = materializeEnrichAliasCellForCsv(normalized, alias, {
21656
- compactAiCell: aiCompactAliases?.has(normalizeAlias2(alias)) ?? false
22134
+ compactAiCell: aiCompactAliases?.has(normalizeAlias2(alias)) ?? false,
22135
+ preservePlainObject: playAliases.has(normalizeAlias2(alias))
21657
22136
  });
21658
22137
  if (value !== void 0) {
21659
22138
  normalized[alias] = value;
@@ -21684,11 +22163,11 @@ function normalizeEnrichRowsForCsvExport(rows, config, options) {
21684
22163
  }
21685
22164
  function legacyMetadataFromRow(row) {
21686
22165
  const direct = parseLegacyMetadataCell(row._metadata);
21687
- if (direct && isRecord7(direct.columns)) {
22166
+ if (direct && isRecord8(direct.columns)) {
21688
22167
  return direct;
21689
22168
  }
21690
22169
  const relocated = parseLegacyMetadataCell(row.metadata);
21691
- if (relocated && isRecord7(relocated.columns)) {
22170
+ if (relocated && isRecord8(relocated.columns)) {
21692
22171
  return relocated;
21693
22172
  }
21694
22173
  const flattenedColumns = parseLegacyMetadataCell(row["metadata.columns"]);
@@ -21705,7 +22184,7 @@ function legacyMetadataFromRow(row) {
21705
22184
  }
21706
22185
  function parseLegacyMetadataCell(value) {
21707
22186
  const parsed = parseMaybeJsonObject(value);
21708
- if (isRecord7(parsed)) {
22187
+ if (isRecord8(parsed)) {
21709
22188
  return parsed;
21710
22189
  }
21711
22190
  if (typeof value !== "string") {
@@ -21722,12 +22201,12 @@ function parseLegacyMetadataCell(value) {
21722
22201
  for (const candidate of candidates) {
21723
22202
  try {
21724
22203
  const decoded = JSON.parse(candidate);
21725
- if (isRecord7(decoded)) {
22204
+ if (isRecord8(decoded)) {
21726
22205
  return decoded;
21727
22206
  }
21728
22207
  if (typeof decoded === "string") {
21729
22208
  const nested = JSON.parse(decoded);
21730
- if (isRecord7(nested)) {
22209
+ if (isRecord8(nested)) {
21731
22210
  return nested;
21732
22211
  }
21733
22212
  }
@@ -21737,8 +22216,8 @@ function parseLegacyMetadataCell(value) {
21737
22216
  return null;
21738
22217
  }
21739
22218
  function mergeLegacyMetadataRecords(base, enriched) {
21740
- const baseColumns = isRecord7(base.columns) ? base.columns : null;
21741
- const enrichedColumns = isRecord7(enriched.columns) ? enriched.columns : null;
22219
+ const baseColumns = isRecord8(base.columns) ? base.columns : null;
22220
+ const enrichedColumns = isRecord8(enriched.columns) ? enriched.columns : null;
21742
22221
  const merged = {
21743
22222
  ...base,
21744
22223
  ...enriched
@@ -21841,6 +22320,9 @@ function registerEnrichCommand(program) {
21841
22320
  ).option(
21842
22321
  "--profile <id>",
21843
22322
  "Internal/testing: override the execution profile for the generated play run."
22323
+ ).option(
22324
+ "--debug-map-latency",
22325
+ "Internal diagnostics: emit one aggregate latency profile per dataset map."
21844
22326
  ).option(
21845
22327
  "--fail-fast",
21846
22328
  "Fail the generated play when any selected row errors, while preserving recovered runtime-sheet rows for export."
@@ -21986,6 +22468,9 @@ function registerEnrichCommand(program) {
21986
22468
  if (options.profile) {
21987
22469
  runArgs.push("--profile", options.profile);
21988
22470
  }
22471
+ if (options.debugMapLatency) {
22472
+ runArgs.push("--debug-map-latency");
22473
+ }
21989
22474
  if (options.noOpen || input2.suppressOpen) {
21990
22475
  runArgs.push("--no-open");
21991
22476
  }
@@ -22002,11 +22487,15 @@ function registerEnrichCommand(program) {
22002
22487
  const captured2 = await runGeneratedEnrichPlay(client2, runArgs, {
22003
22488
  passthroughStdout: input2.passthroughStdout
22004
22489
  });
22005
- const status2 = input2.json ? parseJsonOutput(captured2.stdout) : await resolveWatchedGeneratedPlayStatus({
22490
+ const generatedPlayStatus = input2.json ? parseJsonOutput(captured2.stdout) : await resolveWatchedGeneratedPlayStatus({
22006
22491
  client: client2,
22007
22492
  stdout: captured2.stdout,
22008
22493
  exitCode: captured2.result
22009
22494
  });
22495
+ const status2 = rewriteGeneratedPlayRerunForEnrich(
22496
+ generatedPlayStatus,
22497
+ sdkEnrichCommandText(args)
22498
+ );
22010
22499
  const exportResult2 = await maybeWriteOutputCsv({
22011
22500
  outputPath,
22012
22501
  status: status2,
@@ -26221,7 +26710,7 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
26221
26710
  }
26222
26711
  function extractionContractEntries(entries) {
26223
26712
  return entries.flatMap((entry) => {
26224
- if (!isRecord8(entry)) return [];
26713
+ if (!isRecord9(entry)) return [];
26225
26714
  const name = stringField2(entry, "name");
26226
26715
  const expression = stringField2(entry, "expression");
26227
26716
  return name && expression ? [{ name, expression }] : [];
@@ -26229,8 +26718,8 @@ function extractionContractEntries(entries) {
26229
26718
  }
26230
26719
  function printCompactToolContract(tool, requestedToolId) {
26231
26720
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
26232
- const cost = isRecord8(contract.cost) ? contract.cost : {};
26233
- const getters = isRecord8(contract.getters) ? contract.getters : {};
26721
+ const cost = isRecord9(contract.cost) ? contract.cost : {};
26722
+ const getters = isRecord9(contract.getters) ? contract.getters : {};
26234
26723
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
26235
26724
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
26236
26725
  const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
@@ -26247,7 +26736,7 @@ function printCompactToolContract(tool, requestedToolId) {
26247
26736
  console.log("");
26248
26737
  console.log("Inputs:");
26249
26738
  for (const field of inputFields) {
26250
- if (!isRecord8(field)) continue;
26739
+ if (!isRecord9(field)) continue;
26251
26740
  const name = stringField2(field, "name");
26252
26741
  if (!name) continue;
26253
26742
  const required = field.required ? "*" : "";
@@ -26260,7 +26749,7 @@ function printCompactToolContract(tool, requestedToolId) {
26260
26749
  }
26261
26750
  console.log("");
26262
26751
  printToolExamplesOnly(tool, requestedToolId, { includeSamples: false });
26263
- const starterScript = isRecord8(contract.starterScript) ? contract.starterScript : {};
26752
+ const starterScript = isRecord9(contract.starterScript) ? contract.starterScript : {};
26264
26753
  const starterPath = stringField2(starterScript, "path");
26265
26754
  if (starterPath) {
26266
26755
  console.log("");
@@ -26274,14 +26763,14 @@ function printCompactToolContract(tool, requestedToolId) {
26274
26763
  console.log("Getters:");
26275
26764
  if (listGetters.length) console.log("Lists:");
26276
26765
  for (const entry of listGetters) {
26277
- if (isRecord8(entry))
26766
+ if (isRecord9(entry))
26278
26767
  console.log(
26279
26768
  `- ${stringField2(entry, "name")}: ${playResultExpression(entry)}`
26280
26769
  );
26281
26770
  }
26282
26771
  if (valueGetters.length) console.log("Values:");
26283
26772
  for (const entry of valueGetters) {
26284
- if (isRecord8(entry))
26773
+ if (isRecord9(entry))
26285
26774
  console.log(
26286
26775
  `- ${stringField2(entry, "name")}: ${playResultExpression(entry)}`
26287
26776
  );
@@ -26294,7 +26783,7 @@ function printCompactToolContract(tool, requestedToolId) {
26294
26783
  }
26295
26784
  function printToolPricingOnly(tool, requestedToolId, options = {}) {
26296
26785
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
26297
- const cost = isRecord8(contract.cost) ? contract.cost : {};
26786
+ const cost = isRecord9(contract.cost) ? contract.cost : {};
26298
26787
  const pricingModel = stringField2(cost, "pricingModel") || "unknown";
26299
26788
  const billingMode = stringField2(cost, "billingMode") || "unknown";
26300
26789
  const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : pricingModel === "fixed" ? "call" : pricingModel.replace(/^per_/, "") || "unit";
@@ -26314,7 +26803,7 @@ function printToolSchemaOnly(tool, requestedToolId) {
26314
26803
  }
26315
26804
  console.log("Inputs:");
26316
26805
  for (const field of inputFields) {
26317
- if (!isRecord8(field)) continue;
26806
+ if (!isRecord9(field)) continue;
26318
26807
  const name = stringField2(field, "name");
26319
26808
  if (!name) continue;
26320
26809
  const required = field.required ? "*" : "";
@@ -26344,10 +26833,10 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
26344
26833
  ` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`
26345
26834
  );
26346
26835
  console.log("});");
26347
- const getters = isRecord8(contract.getters) ? contract.getters : {};
26836
+ const getters = isRecord9(contract.getters) ? contract.getters : {};
26348
26837
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
26349
26838
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
26350
- const firstGetter = [...valueGetters, ...listGetters].find(isRecord8);
26839
+ const firstGetter = [...valueGetters, ...listGetters].find(isRecord9);
26351
26840
  if (firstGetter) {
26352
26841
  const name = stringField2(firstGetter, "name") || "value";
26353
26842
  const expression = stringField2(firstGetter, "expression");
@@ -26383,7 +26872,7 @@ function printPlayLikeToolUsage(tool, requestedToolId) {
26383
26872
  }
26384
26873
  function printToolGettersOnly(tool, requestedToolId) {
26385
26874
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
26386
- const getters = isRecord8(contract.getters) ? contract.getters : {};
26875
+ const getters = isRecord9(contract.getters) ? contract.getters : {};
26387
26876
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
26388
26877
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
26389
26878
  console.log(`Getters: ${contract.toolId}`);
@@ -26396,7 +26885,7 @@ function printToolGettersOnly(tool, requestedToolId) {
26396
26885
  if (listGetters.length) {
26397
26886
  console.log("Lists:");
26398
26887
  for (const entry of listGetters) {
26399
- if (isRecord8(entry))
26888
+ if (isRecord9(entry))
26400
26889
  console.log(
26401
26890
  `- ${stringField2(entry, "name")}: ${playResultExpression(entry)}`
26402
26891
  );
@@ -26405,7 +26894,7 @@ function printToolGettersOnly(tool, requestedToolId) {
26405
26894
  if (valueGetters.length) {
26406
26895
  console.log("Values:");
26407
26896
  for (const entry of valueGetters) {
26408
- if (isRecord8(entry))
26897
+ if (isRecord9(entry))
26409
26898
  console.log(
26410
26899
  `- ${stringField2(entry, "name")}: ${playResultExpression(entry)}`
26411
26900
  );
@@ -26431,7 +26920,7 @@ function sampleValueForField(field) {
26431
26920
  function samplePayloadForInputFields(fields) {
26432
26921
  return Object.fromEntries(
26433
26922
  fields.slice(0, 4).flatMap((field) => {
26434
- if (!isRecord8(field)) return [];
26923
+ if (!isRecord9(field)) return [];
26435
26924
  const name = stringField2(field, "name");
26436
26925
  if (!name) return [];
26437
26926
  return [[name, sampleValueForField(field)]];
@@ -26549,12 +27038,12 @@ function formatListedToolCost(tool) {
26549
27038
  }
26550
27039
  function toolInputFieldsForDisplay(inputSchema) {
26551
27040
  if (Array.isArray(inputSchema.fields))
26552
- return inputSchema.fields.filter(isRecord8);
26553
- const jsonSchema = isRecord8(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
26554
- const properties = isRecord8(jsonSchema.properties) ? jsonSchema.properties : {};
27041
+ return inputSchema.fields.filter(isRecord9);
27042
+ const jsonSchema = isRecord9(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
27043
+ const properties = isRecord9(jsonSchema.properties) ? jsonSchema.properties : {};
26555
27044
  const required = Array.isArray(jsonSchema.required) ? new Set(jsonSchema.required.map(String)) : /* @__PURE__ */ new Set();
26556
27045
  return Object.entries(properties).map(([name, value]) => {
26557
- const property = isRecord8(value) ? value : {};
27046
+ const property = isRecord9(value) ? value : {};
26558
27047
  return {
26559
27048
  name,
26560
27049
  type: typeof property.type === "string" ? property.type : "unknown",
@@ -26583,15 +27072,15 @@ function printJsonPreview(label, payload) {
26583
27072
  }
26584
27073
  function samplePayload(samples, key) {
26585
27074
  const entry = samples[key];
26586
- if (!isRecord8(entry)) return void 0;
27075
+ if (!isRecord9(entry)) return void 0;
26587
27076
  return Object.prototype.hasOwnProperty.call(entry, "payload") ? entry.payload : entry;
26588
27077
  }
26589
27078
  function commandEnvelopeFromRawResponse(rawResponse) {
26590
- return isRecord8(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
27079
+ return isRecord9(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
26591
27080
  }
26592
27081
  function listExtractorPathsFromUsageGuidance(tool) {
26593
27082
  const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
26594
- const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord8(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
27083
+ const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord9(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
26595
27084
  return extractedLists.flatMap((entry) => {
26596
27085
  const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
26597
27086
  if (!Array.isArray(paths)) return [];
@@ -26607,7 +27096,7 @@ function formatDecimal(value) {
26607
27096
  function formatUsd(value) {
26608
27097
  return `$${formatDecimal(value)}`;
26609
27098
  }
26610
- function isRecord8(value) {
27099
+ function isRecord9(value) {
26611
27100
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
26612
27101
  }
26613
27102
  function stringField2(source, ...keys) {
@@ -26634,7 +27123,7 @@ function arrayField2(source, ...keys) {
26634
27123
  function recordField2(source, ...keys) {
26635
27124
  for (const key of keys) {
26636
27125
  const value = source[key];
26637
- if (isRecord8(value)) return value;
27126
+ if (isRecord9(value)) return value;
26638
27127
  }
26639
27128
  return {};
26640
27129
  }
@@ -26700,7 +27189,7 @@ function parseJsonObjectArgument(raw, flagName) {
26700
27189
  }
26701
27190
  throw invalidJsonError(flagName, message);
26702
27191
  }
26703
- if (!isRecord8(parsed)) {
27192
+ if (!isRecord9(parsed)) {
26704
27193
  throw invalidJsonError(flagName, "expected an object.");
26705
27194
  }
26706
27195
  return parsed;
@@ -26846,7 +27335,7 @@ function buildToolExecuteBaseEnvelope(input2) {
26846
27335
  kind: summaryEntries.length > 0 ? "object" : "raw",
26847
27336
  summary: input2.summary
26848
27337
  };
26849
- const envelopeHasCanonicalOutput = isRecord8(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
27338
+ const envelopeHasCanonicalOutput = isRecord9(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
26850
27339
  const envelopeHasDeclaredOutput = Object.prototype.hasOwnProperty.call(
26851
27340
  envelope,
26852
27341
  "output"
@@ -27065,7 +27554,7 @@ async function executeTool(args) {
27065
27554
  {
27066
27555
  ...baseEnvelope,
27067
27556
  local: {
27068
- ...isRecord8(baseEnvelope.local) ? baseEnvelope.local : {},
27557
+ ...isRecord9(baseEnvelope.local) ? baseEnvelope.local : {},
27069
27558
  payload_file: jsonPath
27070
27559
  }
27071
27560
  },