deepline 0.1.211 → 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 (33) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +150 -11
  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/tool-dispatch.ts +1 -1
  4. package/dist/bundling-sources/sdk/src/client.ts +118 -3
  5. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +1 -1
  6. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  7. package/dist/bundling-sources/sdk/src/types.ts +47 -0
  8. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +253 -30
  9. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +22 -20
  10. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +12 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/dataset-id.ts +10 -4
  12. package/dist/bundling-sources/shared_libs/play-runtime/db-session.ts +9 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +3 -5
  14. package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +14 -2
  15. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +4 -2
  16. package/dist/bundling-sources/shared_libs/play-runtime/receipt-sql.ts +21 -1
  17. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +128 -6
  18. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +7 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +37 -5
  20. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +19 -10
  21. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +63 -7
  22. package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +18 -4
  23. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +29 -9
  24. package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-state-machine.ts +22 -1
  25. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +79 -1
  26. package/dist/cli/index.js +637 -229
  27. package/dist/cli/index.mjs +637 -229
  28. package/dist/index.d.mts +76 -6
  29. package/dist/index.d.ts +76 -6
  30. package/dist/index.js +225 -43
  31. package/dist/index.mjs +225 -43
  32. package/dist/plays/bundle-play-file.mjs +65 -4
  33. 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.211",
626
+ version: "0.1.212",
627
627
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
628
628
  supportPolicy: {
629
- latest: "0.1.211",
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)) {
7622
+ for (const output2 of datasets) {
7623
+ if (!isRecord5(output2) || !isPackagedDatasetOutput(output2)) {
7442
7624
  continue;
7443
7625
  }
7444
- const output2 = step.output;
7445
- if (!isPackagedDatasetOutput(output2)) {
7446
- continue;
7447
- }
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
  }
@@ -12415,6 +12593,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
12415
12593
  let timedOut = false;
12416
12594
  let emittedDashboardUrl = false;
12417
12595
  let lastKnownWorkflowId = "";
12596
+ let launchedRevisionId = input2.request.revisionId?.trim() || null;
12418
12597
  let eventCount = 0;
12419
12598
  let firstRunIdMs = null;
12420
12599
  let lastPhase = null;
@@ -12440,13 +12619,24 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
12440
12619
  }
12441
12620
  throw error;
12442
12621
  }
12443
- 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;
12444
12627
  };
12445
12628
  try {
12446
12629
  for await (const event of input2.client.startPlayRunStream(input2.request, {
12447
12630
  signal: controller.signal
12448
12631
  })) {
12449
12632
  eventCount += 1;
12633
+ const eventRevisionId = getStringField(
12634
+ getEventPayload(event),
12635
+ "revisionId"
12636
+ );
12637
+ if (eventRevisionId) {
12638
+ launchedRevisionId = eventRevisionId;
12639
+ }
12450
12640
  const eventRunId = getRunIdFromLiveEvent(event);
12451
12641
  if (typeof eventRunId === "string" && eventRunId && eventRunId !== "pending") {
12452
12642
  lastKnownWorkflowId = eventRunId;
@@ -12523,7 +12713,11 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
12523
12713
  const finalStatus = getFinalStatusFromLiveEvent(event);
12524
12714
  if (finalStatus) {
12525
12715
  lastKnownWorkflowId ||= finalStatus.runId ?? "";
12526
- 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
+ };
12527
12721
  if (!canonicalTerminal) {
12528
12722
  recordCliTrace({
12529
12723
  phase: "cli.play_start_stream_stale_terminal_ignored",
@@ -12895,6 +13089,10 @@ function buildRunNextCommands(status) {
12895
13089
  stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
12896
13090
  logs: `deepline runs logs ${runId} --out run.log --json`
12897
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
+ }
12898
13096
  if (status.dashboardUrl) {
12899
13097
  commands.open = `Open ${status.dashboardUrl} to see results.`;
12900
13098
  }
@@ -13046,7 +13244,7 @@ function buildInsufficientCreditsSummaryLines(input2) {
13046
13244
  const lines = [
13047
13245
  " status: stopped_insufficient_credits",
13048
13246
  completed === null ? " completed rows: unknown" : ` completed rows: ${formatInteger(completed)}${total !== null ? ` of ${formatInteger(total)}` : ""}`,
13049
- " 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"
13050
13248
  ];
13051
13249
  const billingUrl = getStringField(input2.billing, "billing_url");
13052
13250
  const recommended = formatCreditAmount(
@@ -13246,15 +13444,44 @@ function withTerminalPlayIdentity(status, playName) {
13246
13444
  function compactPlayStatus(status) {
13247
13445
  const packaged = getPlayRunPackage(status);
13248
13446
  if (packaged) {
13249
- 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;
13250
13451
  if (!error2) {
13251
- 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;
13252
13463
  }
13253
- const run = packaged.run && typeof packaged.run === "object" ? packaged.run : null;
13464
+ const run = packagedRun;
13254
13465
  return {
13255
13466
  ...packaged,
13256
- error: error2,
13257
- ...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 } } : {}
13258
13485
  };
13259
13486
  }
13260
13487
  const rowsInfo = extractCanonicalRowsInfo(status);
@@ -13277,6 +13504,7 @@ function compactPlayStatus(status) {
13277
13504
  steps: normalizeStepsForEnvelope(status),
13278
13505
  errors: normalizeErrorsForEnvelope(status, error),
13279
13506
  logs: normalizeLogsForEnvelope(status),
13507
+ ...status.failedLogs ? { failedLogs: status.failedLogs } : {},
13280
13508
  ...displayError ? { error: displayError } : {},
13281
13509
  ...warnings.length > 0 ? { warnings } : {},
13282
13510
  ...result !== void 0 ? { result: defaultResultForEnvelope(result) } : {},
@@ -13284,6 +13512,16 @@ function compactPlayStatus(status) {
13284
13512
  next: buildRunNextCommands(status)
13285
13513
  };
13286
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
+ }
13287
13525
  function readRunPackageRun(packaged) {
13288
13526
  return packaged.run && typeof packaged.run === "object" && !Array.isArray(packaged.run) ? packaged.run : {};
13289
13527
  }
@@ -13403,6 +13641,14 @@ function actionToCommand(action) {
13403
13641
  record.datasetPath
13404
13642
  )} --out ${shellSingleQuote(`${record.datasetPath.split(".").pop() || "dataset"}.csv`)}`;
13405
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
+ }
13406
13652
  if (record.kind === "deepline_db_query" && typeof record.sql === "string") {
13407
13653
  const maxRows = typeof record.maxRows === "number" && Number.isFinite(record.maxRows) ? Math.trunc(record.maxRows) : 20;
13408
13654
  return `deepline db query --sql ${shellSingleQuote(record.sql)} --max-rows ${maxRows} --json`;
@@ -13410,6 +13656,10 @@ function actionToCommand(action) {
13410
13656
  return null;
13411
13657
  }
13412
13658
  function readFirstDatasetActions(packaged) {
13659
+ for (const dataset of readRecordArray(packaged.datasets)) {
13660
+ const actions = readRecord(dataset.actions);
13661
+ if (actions) return actions;
13662
+ }
13413
13663
  for (const step of readRecordArray(packaged.steps)) {
13414
13664
  const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
13415
13665
  const actions = output2?.actions && typeof output2.actions === "object" && !Array.isArray(output2.actions) ? output2.actions : null;
@@ -13459,13 +13709,34 @@ function buildRunPackageTextLines(packaged) {
13459
13709
  if (runError && (status === "failed" || status === "cancelled")) {
13460
13710
  lines.push(` error: ${truncateErrorForDisplay(runError, runId)}`);
13461
13711
  }
13462
- for (const step of readRecordArray(packaged.steps)) {
13463
- const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
13464
- 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;
13465
13736
  const rowCount = typeof output2.rowCount === "number" ? formatInteger(output2.rowCount) : "persisted";
13466
13737
  const datasetPath = typeof output2.path === "string" ? output2.path : "dataset";
13467
13738
  lines.push(
13468
- ` 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`
13469
13740
  );
13470
13741
  }
13471
13742
  if (playName) {
@@ -13474,6 +13745,7 @@ function buildRunPackageTextLines(packaged) {
13474
13745
  lines.push(...formatPackageValueOutputLines(packaged));
13475
13746
  const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
13476
13747
  const billingCommand = actionToCommand(next.billing);
13748
+ const logsCommand = actionToCommand(next.logs);
13477
13749
  if (billingCommand) {
13478
13750
  const costState = status === "completed" || status === "failed" || status === "cancelled" ? "settles asynchronously \u2014 run the billing command below for totals" : "pending";
13479
13751
  lines.push(` cost: ${costState}`);
@@ -13498,12 +13770,49 @@ function buildRunPackageTextLines(packaged) {
13498
13770
  const inspectCommand = actionToCommand(next.inspect);
13499
13771
  const queryCommand = actionToCommand(next.query) ?? actionToCommand(datasetActions.query);
13500
13772
  const exportCommand = actionToCommand(next.export) ?? actionToCommand(datasetActions.exportCsv);
13773
+ const runAgainCommand = typeof next.run === "string" && next.run.trim() ? next.run.trim() : null;
13501
13774
  if (inspectCommand) lines.push(` inspect: ${inspectCommand}`);
13775
+ if (logsCommand) lines.push(` logs: ${logsCommand}`);
13502
13776
  if (billingCommand) lines.push(` billing: ${billingCommand}`);
13503
13777
  if (queryCommand) lines.push(` query: ${queryCommand}`);
13504
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
+ }
13505
13783
  return lines;
13506
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
+ }
13507
13816
  function writePlayResult(status, jsonOutput, options) {
13508
13817
  const packaged = getPlayRunPackage(status);
13509
13818
  if (jsonOutput) {
@@ -13513,8 +13822,9 @@ function writePlayResult(status, jsonOutput, options) {
13513
13822
  return;
13514
13823
  }
13515
13824
  if (packaged && !options?.fullJson) {
13516
- const lines2 = buildRunPackageTextLines(packaged);
13517
- printCommandEnvelope(packaged, {
13825
+ const displayPackage = compactPlayStatus(status);
13826
+ const lines2 = buildRunPackageTextLines(displayPackage);
13827
+ printCommandEnvelope(displayPackage, {
13518
13828
  json: false,
13519
13829
  text: `${lines2.join("\n")}
13520
13830
  `
@@ -13541,6 +13851,21 @@ function writePlayResult(status, jsonOutput, options) {
13541
13851
  const displayError = formatPlayErrorForDisplay(status, progressError) ?? progressError;
13542
13852
  lines.push(` error: ${truncateErrorForDisplay(displayError, runId)}`);
13543
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
+ }
13544
13869
  const renderedServerView = renderServerResultView(status.resultView);
13545
13870
  if (result) {
13546
13871
  lines.push(...formatReturnValue(result));
@@ -13583,20 +13908,27 @@ async function resolvePlayRunOutputStatus(input2) {
13583
13908
  const streamedPackage = getPlayRunPackage(input2.status);
13584
13909
  const refreshForFullJson = input2.fullJson && streamedPackage !== null;
13585
13910
  const streamedTextPackageIncomplete = !input2.jsonOutput && input2.status.status === "completed" && playRunPackageTextLedgerIncomplete(streamedPackage);
13586
- if (!refreshForFullJson && !streamedTextPackageIncomplete) {
13911
+ const refreshFailedTerminal = input2.status.status === "failed";
13912
+ if (!refreshForFullJson && !streamedTextPackageIncomplete && !refreshFailedTerminal) {
13587
13913
  return input2.status;
13588
13914
  }
13589
13915
  let refreshedStatus = await input2.client.getPlayStatus(runId, {
13590
13916
  billing: false,
13591
13917
  full: input2.fullJson
13592
13918
  });
13593
- 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) {
13594
13920
  await sleep5(250);
13595
13921
  refreshedStatus = await input2.client.getPlayStatus(runId, {
13596
13922
  billing: false,
13597
13923
  full: input2.fullJson
13598
13924
  });
13599
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
+ }
13600
13932
  const dashboardUrl = input2.status.dashboardUrl;
13601
13933
  return typeof dashboardUrl === "string" ? { ...refreshedStatus, dashboardUrl } : refreshedStatus;
13602
13934
  }
@@ -13731,37 +14063,16 @@ function resolveDatasetByName(available, datasetPath) {
13731
14063
  if (exact) {
13732
14064
  return exact;
13733
14065
  }
14066
+ const byDatasetId = available.find((info) => info.datasetId === target);
14067
+ if (byDatasetId) {
14068
+ return byDatasetId;
14069
+ }
13734
14070
  const byNamespace = available.find(
13735
14071
  (info) => info.tableNamespace && info.tableNamespace === target
13736
14072
  );
13737
14073
  if (byNamespace) {
13738
14074
  return byNamespace;
13739
14075
  }
13740
- const trailing = target.split(".").filter(Boolean).at(-1);
13741
- if (!trailing) {
13742
- return null;
13743
- }
13744
- const byTrailing = available.find(
13745
- (info) => info.tableNamespace === trailing || typeof info.source === "string" && info.source.split(".").filter(Boolean).at(-1) === trailing
13746
- );
13747
- if (byTrailing) {
13748
- return byTrailing;
13749
- }
13750
- if (target.split(".").filter(Boolean)[0] === "result") {
13751
- const recovered = available.filter((info) => info.recovered);
13752
- if (recovered.length === 1) {
13753
- return recovered[0];
13754
- }
13755
- if (recovered.length > 1) {
13756
- const names = recovered.map((info) => info.tableNamespace ?? info.source).filter((name) => typeof name === "string");
13757
- throw new DeeplineError(
13758
- `Run returned multiple recovered datasets; '${target}' is ambiguous. Choose one with --dataset <path>: ${names.join(", ")}.`,
13759
- void 0,
13760
- "RUN_EXPORT_DATASET_AMBIGUOUS",
13761
- { dataset: target, available: names }
13762
- );
13763
- }
13764
- }
13765
14076
  return null;
13766
14077
  }
13767
14078
  function assertDatasetHasExportableRows(input2) {
@@ -13941,7 +14252,7 @@ function extractPlayValidationErrors(value) {
13941
14252
  if (value instanceof DeeplineError) {
13942
14253
  return extractPlayValidationErrors(value.details);
13943
14254
  }
13944
- if (!isRecord6(value)) {
14255
+ if (!isRecord7(value)) {
13945
14256
  return [];
13946
14257
  }
13947
14258
  const directErrors = stringArrayField(value, "errors");
@@ -14309,7 +14620,7 @@ function shouldUseLocalOnlyPlayCheck() {
14309
14620
  const value = process.env.DEEPLINE_PLAY_CHECK_LOCAL_ONLY?.trim().toLowerCase();
14310
14621
  return value === "1" || value === "true" || value === "yes" || value === "on";
14311
14622
  }
14312
- function isRecord6(value) {
14623
+ function isRecord7(value) {
14313
14624
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
14314
14625
  }
14315
14626
  function stringValue2(value) {
@@ -14319,14 +14630,14 @@ function asArray(value) {
14319
14630
  return Array.isArray(value) ? value : [];
14320
14631
  }
14321
14632
  function extractionEntries2(value) {
14322
- if (Array.isArray(value)) return value.filter(isRecord6);
14323
- if (!isRecord6(value)) return [];
14633
+ if (Array.isArray(value)) return value.filter(isRecord7);
14634
+ if (!isRecord7(value)) return [];
14324
14635
  return Object.entries(value).map(
14325
- ([name, entry]) => isRecord6(entry) ? { name, ...entry } : { name }
14636
+ ([name, entry]) => isRecord7(entry) ? { name, ...entry } : { name }
14326
14637
  );
14327
14638
  }
14328
14639
  function firstRawPath(entry) {
14329
- const details = isRecord6(entry.details) ? entry.details : {};
14640
+ const details = isRecord7(entry.details) ? entry.details : {};
14330
14641
  const paths = [
14331
14642
  ...asArray(details.rawToolOutputPaths),
14332
14643
  ...asArray(details.raw_tool_output_paths),
@@ -14344,12 +14655,12 @@ function checkHintRawPath(value) {
14344
14655
  function collectStaticPipelineToolIds(staticPipeline) {
14345
14656
  const seen = /* @__PURE__ */ new Set();
14346
14657
  const visitPipeline = (pipeline) => {
14347
- if (!isRecord6(pipeline)) return;
14658
+ if (!isRecord7(pipeline)) return;
14348
14659
  for (const step of [
14349
14660
  ...asArray(pipeline.stages),
14350
14661
  ...asArray(pipeline.substeps)
14351
14662
  ]) {
14352
- if (!isRecord6(step)) continue;
14663
+ if (!isRecord7(step)) continue;
14353
14664
  if (step.type === "tool") {
14354
14665
  const toolId = stringValue2(step.toolId) || stringValue2(step.tool);
14355
14666
  if (toolId) seen.add(toolId);
@@ -14363,9 +14674,9 @@ function collectStaticPipelineToolIds(staticPipeline) {
14363
14674
  return [...seen].sort();
14364
14675
  }
14365
14676
  function toolGetterHintFromMetadata(toolId, tool) {
14366
- const usageGuidance = isRecord6(tool.usageGuidance) ? tool.usageGuidance : {};
14367
- const resultGuidance = isRecord6(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord6(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
14368
- 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 : {};
14369
14680
  const lists = extractionEntries2(
14370
14681
  resultGuidance.extractedLists ?? resultGuidance.extracted_lists
14371
14682
  ).map((entry) => ({
@@ -14805,14 +15116,17 @@ async function handleFileBackedRun(options) {
14805
15116
  } else {
14806
15117
  progress.fail();
14807
15118
  }
14808
- const outputStatus = withTerminalPlayIdentity(
14809
- await resolvePlayRunOutputStatus({
14810
- client: client2,
14811
- status: finalStatus,
14812
- fullJson: options.fullJson,
14813
- jsonOutput: options.jsonOutput
14814
- }),
14815
- 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
14816
15130
  );
14817
15131
  traceCliSync(
14818
15132
  "cli.play_write_result",
@@ -14821,7 +15135,7 @@ async function handleFileBackedRun(options) {
14821
15135
  fullJson: options.fullJson
14822
15136
  })
14823
15137
  );
14824
- return finalStatus.status === "completed" ? 0 : 1;
15138
+ return outputStatus.status === "completed" ? 0 : 1;
14825
15139
  }
14826
15140
  progress.phase("starting run");
14827
15141
  const started = await traceCliSpan(
@@ -14969,14 +15283,18 @@ async function handleNamedRun(options) {
14969
15283
  } else {
14970
15284
  progress.fail();
14971
15285
  }
14972
- const outputStatus = withTerminalPlayIdentity(
14973
- await resolvePlayRunOutputStatus({
14974
- client: client2,
14975
- status: finalStatus,
14976
- fullJson: options.fullJson,
14977
- jsonOutput: options.jsonOutput
14978
- }),
14979
- 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
14980
15298
  );
14981
15299
  traceCliSync(
14982
15300
  "cli.play_write_result",
@@ -14985,7 +15303,7 @@ async function handleNamedRun(options) {
14985
15303
  fullJson: options.fullJson
14986
15304
  })
14987
15305
  );
14988
- return finalStatus.status === "completed" ? 0 : 1;
15306
+ return outputStatus.status === "completed" ? 0 : 1;
14989
15307
  }
14990
15308
  progress.phase("starting run");
14991
15309
  const started = await traceCliSpan(
@@ -15046,7 +15364,7 @@ async function handlePlayRun(args) {
15046
15364
  function parseRunIdPositional(args, usage) {
15047
15365
  for (let index = 0; index < args.length; index += 1) {
15048
15366
  const arg = args[index];
15049
- 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") {
15050
15368
  if (arg === "--limit" && args[index + 1]) {
15051
15369
  index += 1;
15052
15370
  }
@@ -15063,7 +15381,7 @@ function parseRunIdPositional(args, usage) {
15063
15381
  throw new DeeplineError(usage);
15064
15382
  }
15065
15383
  async function handleRunGet(args) {
15066
- const usage = "Usage: deepline runs get <run-id> [--json] [--full]";
15384
+ const usage = "Usage: deepline runs get <run-id> [--json] [--full] [--log-failed]";
15067
15385
  let runId;
15068
15386
  try {
15069
15387
  runId = parseRunIdPositional(args, usage);
@@ -15073,7 +15391,8 @@ async function handleRunGet(args) {
15073
15391
  }
15074
15392
  const client2 = new DeeplineClient();
15075
15393
  const status = await client2.runs.get(runId, {
15076
- full: args.includes("--full")
15394
+ full: args.includes("--full"),
15395
+ failedLogs: args.includes("--log-failed")
15077
15396
  });
15078
15397
  writePlayResult(status, argsWantJson(args), {
15079
15398
  fullJson: args.includes("--full")
@@ -15162,7 +15481,37 @@ async function handleRunTail(args) {
15162
15481
  }
15163
15482
  const client2 = new DeeplineClient();
15164
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
+ };
15165
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,
15166
15515
  // Human mode only: in --json mode emit nothing non-protocol.
15167
15516
  onReconnect: jsonOutput ? void 0 : ({ reason }) => {
15168
15517
  process.stderr.write(
@@ -15175,7 +15524,7 @@ async function handleRunTail(args) {
15175
15524
  return status.status === "failed" ? 1 : 0;
15176
15525
  }
15177
15526
  async function handleRunLogs(args) {
15178
- 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]";
15179
15528
  let runId;
15180
15529
  try {
15181
15530
  runId = parseRunIdPositional(args, usage);
@@ -15185,6 +15534,7 @@ async function handleRunLogs(args) {
15185
15534
  }
15186
15535
  let limit = 200;
15187
15536
  let outPath = null;
15537
+ const failed = args.includes("--failed");
15188
15538
  for (let index = 0; index < args.length; index += 1) {
15189
15539
  const arg = args[index];
15190
15540
  if (arg === "--limit" && args[index + 1]) {
@@ -15195,6 +15545,12 @@ async function handleRunLogs(args) {
15195
15545
  outPath = (0, import_node_path11.resolve)(args[++index]);
15196
15546
  }
15197
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
+ }
15198
15554
  const client2 = new DeeplineClient();
15199
15555
  if (outPath) {
15200
15556
  const result2 = await client2.runs.logs(runId, { all: true });
@@ -15226,7 +15582,8 @@ async function handleRunLogs(args) {
15226
15582
  );
15227
15583
  return 0;
15228
15584
  }
15229
- const result = await client2.runs.logs(runId, { limit });
15585
+ const result = await client2.runs.logs(runId, { limit, failed });
15586
+ const text = buildRunLogsText(result);
15230
15587
  printCommandEnvelope(
15231
15588
  {
15232
15589
  runId: result.runId,
@@ -15238,18 +15595,33 @@ async function handleRunLogs(args) {
15238
15595
  hasMore: result.hasMore,
15239
15596
  ...result.logsTruncated ? { logsTruncated: true } : {},
15240
15597
  entries: result.entries,
15598
+ ...result.view ? { view: result.view } : {},
15599
+ ...result.association ? { association: result.association } : {},
15600
+ ...result.warning ? { warning: result.warning } : {},
15241
15601
  next: {
15602
+ ...result.next ?? {},
15242
15603
  export: `deepline runs logs ${result.runId} --out run.log --json`
15243
15604
  },
15244
15605
  render: { sections: [{ title: "run logs", lines: result.entries }] }
15245
15606
  },
15246
15607
  {
15247
15608
  json: argsWantJson(args),
15248
- text: `${result.entries.join("\n")}${result.entries.length > 0 ? "\n" : ""}`
15609
+ text
15249
15610
  }
15250
15611
  );
15251
15612
  return 0;
15252
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
+ }
15253
15625
  async function handleRunStop(args) {
15254
15626
  const usage = 'Usage: deepline runs stop <run-id> [--reason "text"] [--json]';
15255
15627
  let runId;
@@ -16148,8 +16520,8 @@ Idempotent execution:
16148
16520
 
16149
16521
  await ctx.tools.execute({ id: 'company_lookup', tool, input });
16150
16522
 
16151
- The authored id is still required for readable logs, metadata, and receipt
16152
- 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.
16153
16525
 
16154
16526
  For rows, use ctx.dataset plus a stable row key:
16155
16527
 
@@ -16458,13 +16830,18 @@ Notes:
16458
16830
  Examples:
16459
16831
  deepline runs get play/my-play/run/20260501t000000-000
16460
16832
  deepline runs get play/my-play/run/20260501t000000-000 --json
16833
+ deepline runs get play/my-play/run/20260501t000000-000 --log-failed --json
16461
16834
  deepline runs get play/my-play/run/20260501t000000-000 --full --json
16462
16835
  `
16463
- ).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) => {
16464
16840
  process.exitCode = await handleRunGet([
16465
16841
  runId,
16466
16842
  ...options.json ? ["--json"] : [],
16467
- ...options.full ? ["--full"] : []
16843
+ ...options.full ? ["--full"] : [],
16844
+ ...options.logFailed ? ["--log-failed"] : []
16468
16845
  ]);
16469
16846
  });
16470
16847
  runs.command("list").description("List play runs.").addHelpText(
@@ -16508,13 +16885,17 @@ Examples:
16508
16885
  `
16509
16886
  Notes:
16510
16887
  Streams live run events until the stream ends. Use get for current status and
16511
- 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.
16512
16890
 
16513
16891
  Examples:
16514
16892
  deepline runs tail play/my-play/run/20260501t000000-000
16515
16893
  deepline runs tail play/my-play/run/20260501t000000-000 --compact --json
16516
16894
  `
16517
- ).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) => {
16518
16899
  process.exitCode = await handleRunTail([
16519
16900
  runId,
16520
16901
  ...options.json ? ["--json"] : [],
@@ -16531,17 +16912,19 @@ Notes:
16531
16912
  Examples:
16532
16913
  deepline runs logs play/my-play/run/20260501t000000-000
16533
16914
  deepline runs logs play/my-play/run/20260501t000000-000 --limit 500
16915
+ deepline runs logs play/my-play/run/20260501t000000-000 --failed --json
16534
16916
  deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
16535
16917
  `
16536
16918
  ).option(
16537
16919
  "--limit <count>",
16538
16920
  "Maximum recent log lines to print without --out",
16539
16921
  "200"
16540
- ).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) => {
16541
16923
  process.exitCode = await handleRunLogs([
16542
16924
  runId,
16543
16925
  ...options.limit ? ["--limit", options.limit] : [],
16544
16926
  ...options.out ? ["--out", options.out] : [],
16927
+ ...options.failed ? ["--failed"] : [],
16545
16928
  ...options.json ? ["--json"] : []
16546
16929
  ]);
16547
16930
  });
@@ -18454,7 +18837,7 @@ function isMarkedTestAiInferenceCommand(command) {
18454
18837
  if (normalizeEnrichPlayRef(command.tool) !== "run_javascript") {
18455
18838
  return false;
18456
18839
  }
18457
- 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;
18458
18841
  }
18459
18842
  function enrichDebugEnabled(env = process.env) {
18460
18843
  const raw = String(env.DEEPLINE_DEBUG_ENRICH ?? "").trim().toLowerCase();
@@ -18713,6 +19096,27 @@ function sdkEnrichCommandText(args) {
18713
19096
  }
18714
19097
  return `${command.slice(0, SDK_ENRICH_TELEMETRY_COMMAND_MAX_LENGTH - 3)}...`;
18715
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
+ }
18716
19120
  function countConfiguredEnrichColumns(config) {
18717
19121
  const count = (commands) => commands.reduce((total, command) => {
18718
19122
  if ("with_waterfall" in command) {
@@ -19170,7 +19574,7 @@ async function resolveWatchedGeneratedPlayStatus(input2) {
19170
19574
  }
19171
19575
  return input2.client.runs.get(runId, { full: true });
19172
19576
  }
19173
- function isRecord7(value) {
19577
+ function isRecord8(value) {
19174
19578
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
19175
19579
  }
19176
19580
  async function captureStdout(run, options = {}) {
@@ -19457,13 +19861,13 @@ function readFirstEnrichDatasetActions(value) {
19457
19861
  return null;
19458
19862
  }
19459
19863
  const record = candidate;
19460
- const actions = isRecord7(record.actions) ? record.actions : null;
19461
- 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;
19462
19866
  if (query?.kind === "deepline_db_query") {
19463
19867
  return {
19464
19868
  dataset: record,
19465
19869
  query,
19466
- ...isRecord7(actions?.exportCsv) ? { exportCsv: actions.exportCsv } : {}
19870
+ ...isRecord8(actions?.exportCsv) ? { exportCsv: actions.exportCsv } : {}
19467
19871
  };
19468
19872
  }
19469
19873
  if (options.allowLegacy && record.kind === "dataset" && typeof record.queryDatasetCommand === "string" && record.queryDatasetCommand.trim()) {
@@ -19516,7 +19920,7 @@ function enrichCustomerDbJson(input2) {
19516
19920
  const dataset = actions.dataset;
19517
19921
  const sql = actionStringField(query, "sql") ?? parseSqlFromDbQueryCommand(actions.queryDatasetCommand);
19518
19922
  const datasetPath = actionStringField(query, "datasetPath") ?? actionStringField(dataset, "path") ?? actionStringField(dataset, "tableNamespace");
19519
- const api = isRecord7(query.api) ? query.api : null;
19923
+ const api = isRecord8(query.api) ? query.api : null;
19520
19924
  const apiPath = actionStringField(api ?? {}, "path") ?? "/api/v2/db/query";
19521
19925
  const apiMethod = actionStringField(api ?? {}, "method") ?? "POST";
19522
19926
  if (!datasetPath) {
@@ -19585,11 +19989,11 @@ function sqlStringLiteral(value) {
19585
19989
  return `'${value.replace(/'/g, "''")}'`;
19586
19990
  }
19587
19991
  function failureAliasFromCellMeta(cellMeta) {
19588
- if (!isRecord7(cellMeta)) {
19992
+ if (!isRecord8(cellMeta)) {
19589
19993
  return null;
19590
19994
  }
19591
19995
  for (const [alias, meta] of Object.entries(cellMeta)) {
19592
- if (!isRecord7(meta)) {
19996
+ if (!isRecord8(meta)) {
19593
19997
  continue;
19594
19998
  }
19595
19999
  const failure = failureCellFromMeta(meta, {});
@@ -20127,7 +20531,7 @@ function exportableSheetRow2(row, sourceRowStart = 0) {
20127
20531
  return fallback;
20128
20532
  }
20129
20533
  function failureCellFromMeta(meta, fallback) {
20130
- if (!isRecord7(meta)) {
20534
+ if (!isRecord8(meta)) {
20131
20535
  return null;
20132
20536
  }
20133
20537
  const status = typeof meta.status === "string" ? meta.status.trim().toLowerCase() : "";
@@ -20147,7 +20551,7 @@ function failureCellFromMeta(meta, fallback) {
20147
20551
  };
20148
20552
  }
20149
20553
  function applyFailureCellMeta(row, cellMeta, fallback) {
20150
- if (!isRecord7(cellMeta)) {
20554
+ if (!isRecord8(cellMeta)) {
20151
20555
  return;
20152
20556
  }
20153
20557
  for (const [field, meta] of Object.entries(cellMeta)) {
@@ -20391,7 +20795,7 @@ function stableRowSnapshot(value) {
20391
20795
  }
20392
20796
  function cellFailureError(value) {
20393
20797
  const parsed = parseMaybeJsonObject(value);
20394
- if (!isRecord7(parsed)) {
20798
+ if (!isRecord8(parsed)) {
20395
20799
  const text = typeof parsed === "string" ? parsed.trim() : "";
20396
20800
  if (/^(?:[A-Za-z0-9_:-]+:\s*)?(?:Error|TypeError|ReferenceError|SyntaxError|RangeError):\s+/.test(
20397
20801
  text
@@ -20399,12 +20803,12 @@ function cellFailureError(value) {
20399
20803
  return { message: text };
20400
20804
  }
20401
20805
  }
20402
- if (!isRecord7(parsed)) {
20806
+ if (!isRecord8(parsed)) {
20403
20807
  return null;
20404
20808
  }
20405
20809
  const status = typeof parsed.status === "string" ? parsed.status.trim().toLowerCase() : "";
20406
20810
  const directError = typeof parsed.error === "string" ? parsed.error.trim() : typeof parsed.last_error === "string" ? parsed.last_error.trim() : "";
20407
- const result = isRecord7(parsed.result) ? parsed.result : null;
20811
+ const result = isRecord8(parsed.result) ? parsed.result : null;
20408
20812
  const resultError = typeof result?.error === "string" ? result.error.trim() : typeof result?.message === "string" ? result.message.trim() : "";
20409
20813
  if (!directError && !resultError && status !== "error" && status !== "failed") {
20410
20814
  return null;
@@ -20474,7 +20878,7 @@ function assignFlattenedFailurePath(target, field, value) {
20474
20878
  let cursor = target;
20475
20879
  for (const part of normalized.slice(0, -1)) {
20476
20880
  const existing = cursor[part];
20477
- if (!isRecord7(existing)) {
20881
+ if (!isRecord8(existing)) {
20478
20882
  const next = {};
20479
20883
  cursor[part] = next;
20480
20884
  cursor = next;
@@ -20638,10 +21042,10 @@ function waterfallExecutionSignal(status, spec) {
20638
21042
  let everyChildStatOnlyConditionSkipped = true;
20639
21043
  const childAliasesWithStats = /* @__PURE__ */ new Set();
20640
21044
  for (const childAlias of childAliases) {
20641
- for (const stat2 of summaries.map((summary) => summary[childAlias]).filter(isRecord7)) {
21045
+ for (const stat2 of summaries.map((summary) => summary[childAlias]).filter(isRecord8)) {
20642
21046
  sawChildStats = true;
20643
21047
  childAliasesWithStats.add(childAlias);
20644
- const execution = isRecord7(stat2.execution) ? stat2.execution : null;
21048
+ const execution = isRecord8(stat2.execution) ? stat2.execution : null;
20645
21049
  const executedSummary = parseExecutionSummary(
20646
21050
  execution?.["completed:executed"]
20647
21051
  );
@@ -20671,7 +21075,7 @@ function waterfallExecutionSignal(status, spec) {
20671
21075
  }
20672
21076
  function emptyWaterfallStatsEvidence(status, spec) {
20673
21077
  const summaries = collectColumnStats(status);
20674
- const parentStats = summaries.map((summary) => summary[spec.alias]).filter(isRecord7);
21078
+ const parentStats = summaries.map((summary) => summary[spec.alias]).filter(isRecord8);
20675
21079
  for (const stat2 of parentStats) {
20676
21080
  const nonEmpty = parseExecutionSummary(stat2.non_empty);
20677
21081
  if (nonEmpty?.total && nonEmpty.count === 0) {
@@ -20685,7 +21089,7 @@ function emptyWaterfallStatsEvidence(status, spec) {
20685
21089
  let selectedRows = 0;
20686
21090
  let sawStatsForEveryChild = true;
20687
21091
  for (const childAlias of childAliases) {
20688
- const stat2 = summaries.map((summary) => summary[childAlias]).find(isRecord7);
21092
+ const stat2 = summaries.map((summary) => summary[childAlias]).find(isRecord8);
20689
21093
  if (!stat2) {
20690
21094
  sawStatsForEveryChild = false;
20691
21095
  break;
@@ -20694,7 +21098,7 @@ function emptyWaterfallStatsEvidence(status, spec) {
20694
21098
  if ((nonEmpty?.count ?? 0) > 0) {
20695
21099
  return null;
20696
21100
  }
20697
- const execution = isRecord7(stat2.execution) ? stat2.execution : null;
21101
+ const execution = isRecord8(stat2.execution) ? stat2.execution : null;
20698
21102
  const executed = parseExecutionSummary(execution?.["completed:executed"]);
20699
21103
  const reused = parseExecutionSummary(execution?.["completed:reused"]);
20700
21104
  const skipped = parseExecutionSummary(execution?.["skipped:condition"]);
@@ -20736,11 +21140,11 @@ function collectStatusFailureJobs(input2) {
20736
21140
  const jobs = [];
20737
21141
  aliases.forEach((spec, aliasIndex) => {
20738
21142
  const { alias } = spec;
20739
- const stat2 = summaries.map((summary) => summary[alias]).find(isRecord7);
21143
+ const stat2 = summaries.map((summary) => summary[alias]).find(isRecord8);
20740
21144
  if (!stat2) {
20741
21145
  return;
20742
21146
  }
20743
- const execution = isRecord7(stat2.execution) ? stat2.execution : null;
21147
+ const execution = isRecord8(stat2.execution) ? stat2.execution : null;
20744
21148
  const failedCount = Math.min(
20745
21149
  selectedRows,
20746
21150
  Math.max(
@@ -20847,10 +21251,10 @@ function collectColumnStats(status) {
20847
21251
  value.forEach(visit);
20848
21252
  return;
20849
21253
  }
20850
- if (!isRecord7(value)) {
21254
+ if (!isRecord8(value)) {
20851
21255
  return;
20852
21256
  }
20853
- if (isRecord7(value.columnStats)) {
21257
+ if (isRecord8(value.columnStats)) {
20854
21258
  summaries.push(value.columnStats);
20855
21259
  }
20856
21260
  Object.values(value).forEach(visit);
@@ -20862,12 +21266,12 @@ function firstAliasExecutionCounts(input2) {
20862
21266
  const aliases = collectConfigScalarAliasOrder(input2.config);
20863
21267
  const summaries = collectColumnStats(input2.status);
20864
21268
  for (const alias of aliases) {
20865
- const stat2 = summaries.map((summary) => summary[alias]).find(isRecord7);
21269
+ const stat2 = summaries.map((summary) => summary[alias]).find(isRecord8);
20866
21270
  if (!stat2) continue;
20867
21271
  if (input2.forceAliases.has(normalizeAlias2(alias))) {
20868
21272
  return { executed: input2.selectedRows, reused: 0 };
20869
21273
  }
20870
- const execution = isRecord7(stat2.execution) ? stat2.execution : null;
21274
+ const execution = isRecord8(stat2.execution) ? stat2.execution : null;
20871
21275
  if (!execution) continue;
20872
21276
  return {
20873
21277
  executed: parseExecutionCount(execution["completed:executed"]),
@@ -20894,14 +21298,14 @@ function rewriteEnrichJsonStatus(input2) {
20894
21298
  if (Array.isArray(value)) {
20895
21299
  return value.map(rewrite);
20896
21300
  }
20897
- if (!isRecord7(value)) {
21301
+ if (!isRecord8(value)) {
20898
21302
  return value;
20899
21303
  }
20900
21304
  const next = {};
20901
21305
  for (const [key, entry] of Object.entries(value)) {
20902
21306
  next[key] = rewrite(entry);
20903
21307
  }
20904
- if (isRecord7(next.progress)) {
21308
+ if (isRecord8(next.progress)) {
20905
21309
  next.progress = {
20906
21310
  ...next.progress,
20907
21311
  ...selectedRows > 0 ? { total: selectedRows } : {},
@@ -20910,8 +21314,8 @@ function rewriteEnrichJsonStatus(input2) {
20910
21314
  ...failedRows > 0 ? { failed: failedRows, pending: 0 } : {}
20911
21315
  };
20912
21316
  }
20913
- if (isRecord7(next.summary)) {
20914
- 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;
20915
21319
  if (failedRows > 0) {
20916
21320
  next.summary = {
20917
21321
  ...next.summary,
@@ -20924,11 +21328,11 @@ function rewriteEnrichJsonStatus(input2) {
20924
21328
  };
20925
21329
  }
20926
21330
  }
20927
- if (isRecord7(next.columnStats) && selectedRows > 0) {
21331
+ if (isRecord8(next.columnStats) && selectedRows > 0) {
20928
21332
  const columnStats = { ...next.columnStats };
20929
21333
  for (const alias of forcedAliases) {
20930
- const stat2 = isRecord7(columnStats[alias]) ? columnStats[alias] : null;
20931
- 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;
20932
21336
  if (!stat2 || !execution) continue;
20933
21337
  columnStats[alias] = {
20934
21338
  ...stat2,
@@ -20947,14 +21351,14 @@ function rewriteEnrichJsonStatus(input2) {
20947
21351
  return next;
20948
21352
  };
20949
21353
  const rewritten = rewrite(input2.status);
20950
- if (failedRows === 0 || !isRecord7(rewritten)) {
21354
+ if (failedRows === 0 || !isRecord8(rewritten)) {
20951
21355
  return rewritten;
20952
21356
  }
20953
21357
  const partialStatus = selectedRows > 0 && failedRows < selectedRows ? "partial_success" : "failed";
20954
21358
  return {
20955
21359
  ...rewritten,
20956
21360
  ...rewritten.status === "completed" || rewritten.status === "failed" ? { status: partialStatus } : {},
20957
- ...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 } } : {}
20958
21362
  };
20959
21363
  }
20960
21364
  function summarizeFailedJobError(value) {
@@ -21566,7 +21970,7 @@ function materializeCsvCellValue(value) {
21566
21970
  return value;
21567
21971
  }
21568
21972
  function compactArrayEnvelopeCompleteValue(value) {
21569
- if (!isRecord7(value) || value.kind !== "array") {
21973
+ if (!isRecord8(value) || value.kind !== "array") {
21570
21974
  return null;
21571
21975
  }
21572
21976
  if (!Array.isArray(value.preview)) {
@@ -21580,7 +21984,7 @@ function compactArrayEnvelopeCompleteValue(value) {
21580
21984
  }
21581
21985
  function disambiguateCompactAiInferencePayload(value) {
21582
21986
  const parsed = parseMaybeJsonObject(value);
21583
- if (!isRecord7(parsed) || !cellFailureError(parsed)) {
21987
+ if (!isRecord8(parsed) || !cellFailureError(parsed)) {
21584
21988
  return value;
21585
21989
  }
21586
21990
  return {
@@ -21589,14 +21993,14 @@ function disambiguateCompactAiInferencePayload(value) {
21589
21993
  };
21590
21994
  }
21591
21995
  function compactAiInferenceCellForCsv(value) {
21592
- if (!isRecord7(value)) {
21996
+ if (!isRecord8(value)) {
21593
21997
  return value;
21594
21998
  }
21595
21999
  const extractedJson = value.extracted_json;
21596
22000
  if (extractedJson !== null && extractedJson !== void 0) {
21597
22001
  return disambiguateCompactAiInferencePayload(extractedJson);
21598
22002
  }
21599
- const result = isRecord7(value.result) ? value.result : null;
22003
+ const result = isRecord8(value.result) ? value.result : null;
21600
22004
  const object = result?.object;
21601
22005
  if (object !== null && object !== void 0) {
21602
22006
  return disambiguateCompactAiInferencePayload(object);
@@ -21613,12 +22017,12 @@ function compactAiInferenceCellForCsv(value) {
21613
22017
  }
21614
22018
  function materializeEnrichAliasCellForCsv(row, alias, options) {
21615
22019
  const direct = row[alias];
21616
- if (isRecord7(direct)) {
22020
+ if (isRecord8(direct)) {
21617
22021
  const completeArray = compactArrayEnvelopeCompleteValue(direct);
21618
22022
  if (completeArray) {
21619
22023
  return materializeCsvCellValue(completeArray);
21620
22024
  }
21621
- 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")) {
21622
22026
  return materializeCsvCellValue(compactAiInferenceCellForCsv(direct));
21623
22027
  }
21624
22028
  if (Object.prototype.hasOwnProperty.call(direct, "matched_result") || Object.prototype.hasOwnProperty.call(direct, "matchedResult") || Object.prototype.hasOwnProperty.call(direct, "result")) {
@@ -21759,11 +22163,11 @@ function normalizeEnrichRowsForCsvExport(rows, config, options) {
21759
22163
  }
21760
22164
  function legacyMetadataFromRow(row) {
21761
22165
  const direct = parseLegacyMetadataCell(row._metadata);
21762
- if (direct && isRecord7(direct.columns)) {
22166
+ if (direct && isRecord8(direct.columns)) {
21763
22167
  return direct;
21764
22168
  }
21765
22169
  const relocated = parseLegacyMetadataCell(row.metadata);
21766
- if (relocated && isRecord7(relocated.columns)) {
22170
+ if (relocated && isRecord8(relocated.columns)) {
21767
22171
  return relocated;
21768
22172
  }
21769
22173
  const flattenedColumns = parseLegacyMetadataCell(row["metadata.columns"]);
@@ -21780,7 +22184,7 @@ function legacyMetadataFromRow(row) {
21780
22184
  }
21781
22185
  function parseLegacyMetadataCell(value) {
21782
22186
  const parsed = parseMaybeJsonObject(value);
21783
- if (isRecord7(parsed)) {
22187
+ if (isRecord8(parsed)) {
21784
22188
  return parsed;
21785
22189
  }
21786
22190
  if (typeof value !== "string") {
@@ -21797,12 +22201,12 @@ function parseLegacyMetadataCell(value) {
21797
22201
  for (const candidate of candidates) {
21798
22202
  try {
21799
22203
  const decoded = JSON.parse(candidate);
21800
- if (isRecord7(decoded)) {
22204
+ if (isRecord8(decoded)) {
21801
22205
  return decoded;
21802
22206
  }
21803
22207
  if (typeof decoded === "string") {
21804
22208
  const nested = JSON.parse(decoded);
21805
- if (isRecord7(nested)) {
22209
+ if (isRecord8(nested)) {
21806
22210
  return nested;
21807
22211
  }
21808
22212
  }
@@ -21812,8 +22216,8 @@ function parseLegacyMetadataCell(value) {
21812
22216
  return null;
21813
22217
  }
21814
22218
  function mergeLegacyMetadataRecords(base, enriched) {
21815
- const baseColumns = isRecord7(base.columns) ? base.columns : null;
21816
- 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;
21817
22221
  const merged = {
21818
22222
  ...base,
21819
22223
  ...enriched
@@ -22083,11 +22487,15 @@ function registerEnrichCommand(program) {
22083
22487
  const captured2 = await runGeneratedEnrichPlay(client2, runArgs, {
22084
22488
  passthroughStdout: input2.passthroughStdout
22085
22489
  });
22086
- const status2 = input2.json ? parseJsonOutput(captured2.stdout) : await resolveWatchedGeneratedPlayStatus({
22490
+ const generatedPlayStatus = input2.json ? parseJsonOutput(captured2.stdout) : await resolveWatchedGeneratedPlayStatus({
22087
22491
  client: client2,
22088
22492
  stdout: captured2.stdout,
22089
22493
  exitCode: captured2.result
22090
22494
  });
22495
+ const status2 = rewriteGeneratedPlayRerunForEnrich(
22496
+ generatedPlayStatus,
22497
+ sdkEnrichCommandText(args)
22498
+ );
22091
22499
  const exportResult2 = await maybeWriteOutputCsv({
22092
22500
  outputPath,
22093
22501
  status: status2,
@@ -26302,7 +26710,7 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
26302
26710
  }
26303
26711
  function extractionContractEntries(entries) {
26304
26712
  return entries.flatMap((entry) => {
26305
- if (!isRecord8(entry)) return [];
26713
+ if (!isRecord9(entry)) return [];
26306
26714
  const name = stringField2(entry, "name");
26307
26715
  const expression = stringField2(entry, "expression");
26308
26716
  return name && expression ? [{ name, expression }] : [];
@@ -26310,8 +26718,8 @@ function extractionContractEntries(entries) {
26310
26718
  }
26311
26719
  function printCompactToolContract(tool, requestedToolId) {
26312
26720
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
26313
- const cost = isRecord8(contract.cost) ? contract.cost : {};
26314
- const getters = isRecord8(contract.getters) ? contract.getters : {};
26721
+ const cost = isRecord9(contract.cost) ? contract.cost : {};
26722
+ const getters = isRecord9(contract.getters) ? contract.getters : {};
26315
26723
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
26316
26724
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
26317
26725
  const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
@@ -26328,7 +26736,7 @@ function printCompactToolContract(tool, requestedToolId) {
26328
26736
  console.log("");
26329
26737
  console.log("Inputs:");
26330
26738
  for (const field of inputFields) {
26331
- if (!isRecord8(field)) continue;
26739
+ if (!isRecord9(field)) continue;
26332
26740
  const name = stringField2(field, "name");
26333
26741
  if (!name) continue;
26334
26742
  const required = field.required ? "*" : "";
@@ -26341,7 +26749,7 @@ function printCompactToolContract(tool, requestedToolId) {
26341
26749
  }
26342
26750
  console.log("");
26343
26751
  printToolExamplesOnly(tool, requestedToolId, { includeSamples: false });
26344
- const starterScript = isRecord8(contract.starterScript) ? contract.starterScript : {};
26752
+ const starterScript = isRecord9(contract.starterScript) ? contract.starterScript : {};
26345
26753
  const starterPath = stringField2(starterScript, "path");
26346
26754
  if (starterPath) {
26347
26755
  console.log("");
@@ -26355,14 +26763,14 @@ function printCompactToolContract(tool, requestedToolId) {
26355
26763
  console.log("Getters:");
26356
26764
  if (listGetters.length) console.log("Lists:");
26357
26765
  for (const entry of listGetters) {
26358
- if (isRecord8(entry))
26766
+ if (isRecord9(entry))
26359
26767
  console.log(
26360
26768
  `- ${stringField2(entry, "name")}: ${playResultExpression(entry)}`
26361
26769
  );
26362
26770
  }
26363
26771
  if (valueGetters.length) console.log("Values:");
26364
26772
  for (const entry of valueGetters) {
26365
- if (isRecord8(entry))
26773
+ if (isRecord9(entry))
26366
26774
  console.log(
26367
26775
  `- ${stringField2(entry, "name")}: ${playResultExpression(entry)}`
26368
26776
  );
@@ -26375,7 +26783,7 @@ function printCompactToolContract(tool, requestedToolId) {
26375
26783
  }
26376
26784
  function printToolPricingOnly(tool, requestedToolId, options = {}) {
26377
26785
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
26378
- const cost = isRecord8(contract.cost) ? contract.cost : {};
26786
+ const cost = isRecord9(contract.cost) ? contract.cost : {};
26379
26787
  const pricingModel = stringField2(cost, "pricingModel") || "unknown";
26380
26788
  const billingMode = stringField2(cost, "billingMode") || "unknown";
26381
26789
  const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : pricingModel === "fixed" ? "call" : pricingModel.replace(/^per_/, "") || "unit";
@@ -26395,7 +26803,7 @@ function printToolSchemaOnly(tool, requestedToolId) {
26395
26803
  }
26396
26804
  console.log("Inputs:");
26397
26805
  for (const field of inputFields) {
26398
- if (!isRecord8(field)) continue;
26806
+ if (!isRecord9(field)) continue;
26399
26807
  const name = stringField2(field, "name");
26400
26808
  if (!name) continue;
26401
26809
  const required = field.required ? "*" : "";
@@ -26425,10 +26833,10 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
26425
26833
  ` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`
26426
26834
  );
26427
26835
  console.log("});");
26428
- const getters = isRecord8(contract.getters) ? contract.getters : {};
26836
+ const getters = isRecord9(contract.getters) ? contract.getters : {};
26429
26837
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
26430
26838
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
26431
- const firstGetter = [...valueGetters, ...listGetters].find(isRecord8);
26839
+ const firstGetter = [...valueGetters, ...listGetters].find(isRecord9);
26432
26840
  if (firstGetter) {
26433
26841
  const name = stringField2(firstGetter, "name") || "value";
26434
26842
  const expression = stringField2(firstGetter, "expression");
@@ -26464,7 +26872,7 @@ function printPlayLikeToolUsage(tool, requestedToolId) {
26464
26872
  }
26465
26873
  function printToolGettersOnly(tool, requestedToolId) {
26466
26874
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
26467
- const getters = isRecord8(contract.getters) ? contract.getters : {};
26875
+ const getters = isRecord9(contract.getters) ? contract.getters : {};
26468
26876
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
26469
26877
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
26470
26878
  console.log(`Getters: ${contract.toolId}`);
@@ -26477,7 +26885,7 @@ function printToolGettersOnly(tool, requestedToolId) {
26477
26885
  if (listGetters.length) {
26478
26886
  console.log("Lists:");
26479
26887
  for (const entry of listGetters) {
26480
- if (isRecord8(entry))
26888
+ if (isRecord9(entry))
26481
26889
  console.log(
26482
26890
  `- ${stringField2(entry, "name")}: ${playResultExpression(entry)}`
26483
26891
  );
@@ -26486,7 +26894,7 @@ function printToolGettersOnly(tool, requestedToolId) {
26486
26894
  if (valueGetters.length) {
26487
26895
  console.log("Values:");
26488
26896
  for (const entry of valueGetters) {
26489
- if (isRecord8(entry))
26897
+ if (isRecord9(entry))
26490
26898
  console.log(
26491
26899
  `- ${stringField2(entry, "name")}: ${playResultExpression(entry)}`
26492
26900
  );
@@ -26512,7 +26920,7 @@ function sampleValueForField(field) {
26512
26920
  function samplePayloadForInputFields(fields) {
26513
26921
  return Object.fromEntries(
26514
26922
  fields.slice(0, 4).flatMap((field) => {
26515
- if (!isRecord8(field)) return [];
26923
+ if (!isRecord9(field)) return [];
26516
26924
  const name = stringField2(field, "name");
26517
26925
  if (!name) return [];
26518
26926
  return [[name, sampleValueForField(field)]];
@@ -26630,12 +27038,12 @@ function formatListedToolCost(tool) {
26630
27038
  }
26631
27039
  function toolInputFieldsForDisplay(inputSchema) {
26632
27040
  if (Array.isArray(inputSchema.fields))
26633
- return inputSchema.fields.filter(isRecord8);
26634
- const jsonSchema = isRecord8(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
26635
- 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 : {};
26636
27044
  const required = Array.isArray(jsonSchema.required) ? new Set(jsonSchema.required.map(String)) : /* @__PURE__ */ new Set();
26637
27045
  return Object.entries(properties).map(([name, value]) => {
26638
- const property = isRecord8(value) ? value : {};
27046
+ const property = isRecord9(value) ? value : {};
26639
27047
  return {
26640
27048
  name,
26641
27049
  type: typeof property.type === "string" ? property.type : "unknown",
@@ -26664,15 +27072,15 @@ function printJsonPreview(label, payload) {
26664
27072
  }
26665
27073
  function samplePayload(samples, key) {
26666
27074
  const entry = samples[key];
26667
- if (!isRecord8(entry)) return void 0;
27075
+ if (!isRecord9(entry)) return void 0;
26668
27076
  return Object.prototype.hasOwnProperty.call(entry, "payload") ? entry.payload : entry;
26669
27077
  }
26670
27078
  function commandEnvelopeFromRawResponse(rawResponse) {
26671
- return isRecord8(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
27079
+ return isRecord9(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
26672
27080
  }
26673
27081
  function listExtractorPathsFromUsageGuidance(tool) {
26674
27082
  const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
26675
- 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) : [];
26676
27084
  return extractedLists.flatMap((entry) => {
26677
27085
  const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
26678
27086
  if (!Array.isArray(paths)) return [];
@@ -26688,7 +27096,7 @@ function formatDecimal(value) {
26688
27096
  function formatUsd(value) {
26689
27097
  return `$${formatDecimal(value)}`;
26690
27098
  }
26691
- function isRecord8(value) {
27099
+ function isRecord9(value) {
26692
27100
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
26693
27101
  }
26694
27102
  function stringField2(source, ...keys) {
@@ -26715,7 +27123,7 @@ function arrayField2(source, ...keys) {
26715
27123
  function recordField2(source, ...keys) {
26716
27124
  for (const key of keys) {
26717
27125
  const value = source[key];
26718
- if (isRecord8(value)) return value;
27126
+ if (isRecord9(value)) return value;
26719
27127
  }
26720
27128
  return {};
26721
27129
  }
@@ -26781,7 +27189,7 @@ function parseJsonObjectArgument(raw, flagName) {
26781
27189
  }
26782
27190
  throw invalidJsonError(flagName, message);
26783
27191
  }
26784
- if (!isRecord8(parsed)) {
27192
+ if (!isRecord9(parsed)) {
26785
27193
  throw invalidJsonError(flagName, "expected an object.");
26786
27194
  }
26787
27195
  return parsed;
@@ -26927,7 +27335,7 @@ function buildToolExecuteBaseEnvelope(input2) {
26927
27335
  kind: summaryEntries.length > 0 ? "object" : "raw",
26928
27336
  summary: input2.summary
26929
27337
  };
26930
- 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");
26931
27339
  const envelopeHasDeclaredOutput = Object.prototype.hasOwnProperty.call(
26932
27340
  envelope,
26933
27341
  "output"
@@ -27146,7 +27554,7 @@ async function executeTool(args) {
27146
27554
  {
27147
27555
  ...baseEnvelope,
27148
27556
  local: {
27149
- ...isRecord8(baseEnvelope.local) ? baseEnvelope.local : {},
27557
+ ...isRecord9(baseEnvelope.local) ? baseEnvelope.local : {},
27150
27558
  payload_file: jsonPath
27151
27559
  }
27152
27560
  },