deepline 0.1.107 → 0.1.109

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 (29) hide show
  1. package/dist/cli/index.js +782 -221
  2. package/dist/cli/index.mjs +782 -221
  3. package/dist/index.d.mts +80 -7
  4. package/dist/index.d.ts +80 -7
  5. package/dist/index.js +92 -32
  6. package/dist/index.mjs +92 -32
  7. package/dist/repo/apps/play-runner-workers/src/child-play-submit.ts +196 -0
  8. package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +0 -1
  9. package/dist/repo/apps/play-runner-workers/src/entry.ts +51 -288
  10. package/dist/repo/apps/play-runner-workers/src/runtime/csv-rows.ts +102 -0
  11. package/dist/repo/apps/play-runner-workers/src/runtime/dataset-handles.ts +8 -3
  12. package/dist/repo/sdk/src/http.ts +22 -2
  13. package/dist/repo/sdk/src/index.ts +4 -0
  14. package/dist/repo/sdk/src/play.ts +96 -9
  15. package/dist/repo/sdk/src/release.ts +6 -4
  16. package/dist/repo/sdk/src/worker-play-entry.ts +4 -0
  17. package/dist/repo/shared_libs/play-data-plane/cell-policy.ts +76 -0
  18. package/dist/repo/shared_libs/play-data-plane/column-names.ts +17 -0
  19. package/dist/repo/shared_libs/play-data-plane/sheet-contract.ts +190 -0
  20. package/dist/repo/shared_libs/play-runtime/cell-staleness.ts +64 -5
  21. package/dist/repo/shared_libs/play-runtime/coordinator-headers.ts +2 -0
  22. package/dist/repo/shared_libs/play-runtime/db-session.ts +4 -0
  23. package/dist/repo/shared_libs/play-runtime/providers.ts +5 -24
  24. package/dist/repo/shared_libs/play-runtime/run-ledger.ts +76 -31
  25. package/dist/repo/shared_libs/play-runtime/run-snapshot-stream.ts +49 -0
  26. package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +18 -7
  27. package/dist/repo/shared_libs/play-runtime/step-program-dataset-builder.ts +8 -0
  28. package/dist/repo/shared_libs/plays/static-pipeline.ts +90 -14
  29. package/package.json +1 -1
@@ -215,22 +215,24 @@ var SDK_RELEASE = {
215
215
  // preflight (existence, data rows, quotes, duplicate headers), HTML error
216
216
  // scrubbing, and word-boundary watch truncation.
217
217
  // 0.1.103 ships the refined SDK CLI command surface.
218
- // 0.1.104 ships postgres_fast suspension/billing parity and runtime worker hardening.
218
+ // 0.1.104 shipped the retired Postgres scheduler suspension/billing parity and runtime worker hardening.
219
219
  // 0.1.105 ships the billing catalog surface: billing plans, subscribe,
220
220
  // subscription status/cancel, invoices, and the client.billing namespace.
221
221
  // 0.1.106 ships play cell provenance metadata and v2 preview retry hardening.
222
222
  // 0.1.107 ships the v2 quickstart command, the deepline-plays-quickstart
223
223
  // skill on the sdk sync surface, and the people-search-to-email prebuilt.
224
- version: "0.1.107",
224
+ // 0.1.108 ships explicit dataset column/tool recompute policy and removes
225
+ // the SDK enrich generator's one-second stale policy.
226
+ version: "0.1.109",
225
227
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
226
228
  supportPolicy: {
227
- latest: "0.1.107",
229
+ latest: "0.1.109",
228
230
  minimumSupported: "0.1.53",
229
231
  deprecatedBelow: "0.1.53",
230
232
  commandMinimumSupported: [
231
233
  {
232
234
  command: "enrich",
233
- minimumSupported: "0.1.106",
235
+ minimumSupported: "0.1.108",
234
236
  reason: "Older SDK CLI enrich generated stale play source for the current dataset API."
235
237
  }
236
238
  ],
@@ -246,6 +248,7 @@ var SDK_API_CONTRACT = SDK_RELEASE.apiContract;
246
248
  var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
247
249
  var COORDINATOR_URL_OVERRIDE_HEADER = "x-deepline-coordinator-url";
248
250
  var WORKER_CALLBACK_URL_OVERRIDE_HEADER = "x-deepline-worker-callback-url";
251
+ var RUNTIME_SCHEDULER_SCHEMA_OVERRIDE_HEADER = "x-deepline-runtime-scheduler-schema";
249
252
  var SYNTHETIC_RUN_HEADER = "x-deepline-synthetic-run";
250
253
 
251
254
  // src/http.ts
@@ -314,6 +317,10 @@ var HttpClient = class {
314
317
  if (workerCallbackUrl?.trim()) {
315
318
  headers[WORKER_CALLBACK_URL_OVERRIDE_HEADER] = workerCallbackUrl.trim();
316
319
  }
320
+ const runtimeSchedulerSchema = typeof process !== "undefined" ? process.env?.DEEPLINE_RUNTIME_SCHEDULER_SCHEMA : void 0;
321
+ if (runtimeSchedulerSchema?.trim()) {
322
+ headers[RUNTIME_SCHEDULER_SCHEMA_OVERRIDE_HEADER] = runtimeSchedulerSchema.trim();
323
+ }
317
324
  const syntheticRun = typeof process !== "undefined" ? process.env?.DEEPLINE_SYNTHETIC_RUN : void 0;
318
325
  if (syntheticRun && syntheticRun.trim() && syntheticRun.trim() !== "0") {
319
326
  headers[SYNTHETIC_RUN_HEADER] = "1";
@@ -520,8 +527,19 @@ var HttpClient = class {
520
527
  headers
521
528
  });
522
529
  }
530
+ /**
531
+ * Send a PATCH request with a JSON body.
532
+ *
533
+ * @typeParam T - Expected response body type
534
+ * @param path - API path
535
+ * @param body - JSON-serializable request body
536
+ */
523
537
  async patch(path, body, headers) {
524
- return this.request(path, { method: "PATCH", body, headers });
538
+ return this.request(path, {
539
+ method: "PATCH",
540
+ body,
541
+ headers
542
+ });
525
543
  }
526
544
  /**
527
545
  * Send a DELETE request.
@@ -834,6 +852,8 @@ function normalizeStepProgress(value) {
834
852
  value.artifactTableNamespace
835
853
  )
836
854
  } : {},
855
+ ...finiteNumber(value.startedAt) !== null ? { startedAt: finiteNumber(value.startedAt) } : {},
856
+ ...finiteNumber(value.completedAt) !== null ? { completedAt: finiteNumber(value.completedAt) } : {},
837
857
  ...finiteNumber(value.updatedAt) !== null ? { updatedAt: finiteNumber(value.updatedAt) } : {}
838
858
  };
839
859
  }
@@ -870,6 +890,35 @@ function normalizePlayRunLiveStatus(value) {
870
890
  function isTerminalPlayRunLiveStatus(status) {
871
891
  return status === "completed" || status === "failed" || status === "cancelled" || status === "terminated" || status === "timed_out";
872
892
  }
893
+ function isRecord2(value) {
894
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
895
+ }
896
+ function finiteNumber2(value) {
897
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
898
+ }
899
+ function extractTerminalRunLogTail(result) {
900
+ if (!isRecord2(result) || !isRecord2(result._metadata)) {
901
+ return null;
902
+ }
903
+ const runLogTail = result._metadata.runLogTail;
904
+ if (!isRecord2(runLogTail) || !Array.isArray(runLogTail.tail)) {
905
+ return null;
906
+ }
907
+ const logTail = runLogTail.tail.filter(
908
+ (line) => typeof line === "string" && line.trim().length > 0
909
+ );
910
+ if (logTail.length === 0) {
911
+ return null;
912
+ }
913
+ const totalLogCount = Math.max(
914
+ finiteNumber2(runLogTail.totalLogCount) ?? logTail.length,
915
+ logTail.length
916
+ );
917
+ return {
918
+ logTail: logTail.slice(-LOG_TAIL_LIMIT),
919
+ totalLogCount
920
+ };
921
+ }
873
922
  function buildSnapshotFromLedger(snapshot) {
874
923
  const nodeStates = snapshot.orderedStepIds.map((stepId) => snapshot.stepsById[stepId]).filter((step) => Boolean(step)).map((step) => ({
875
924
  nodeId: step.stepId,
@@ -916,6 +965,14 @@ function buildPlayRunStatusSnapshot(input2) {
916
965
  updatedAt: input2.run.updatedAt ?? null,
917
966
  finishedAt: input2.run.finishedAt ?? null
918
967
  });
968
+ const terminalRunLogTail = extractTerminalRunLogTail(input2.run.result);
969
+ if (terminalRunLogTail && terminalRunLogTail.totalLogCount > ledgerSnapshot.totalLogCount) {
970
+ return buildSnapshotFromLedger({
971
+ ...ledgerSnapshot,
972
+ logTail: terminalRunLogTail.logTail,
973
+ totalLogCount: terminalRunLogTail.totalLogCount
974
+ });
975
+ }
919
976
  return buildSnapshotFromLedger(ledgerSnapshot);
920
977
  }
921
978
  function makeRunStreamEvent(input2) {
@@ -1510,7 +1567,7 @@ function chunkRegisterPlayArtifacts(artifacts) {
1510
1567
  return chunks;
1511
1568
  }
1512
1569
  var RUN_LOGS_PAGE_LIMIT = 1e3;
1513
- function isRecord2(value) {
1570
+ function isRecord3(value) {
1514
1571
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1515
1572
  }
1516
1573
  function isPrebuiltPlayDescription(play) {
@@ -1612,7 +1669,7 @@ function updatePlayLiveStatusState(state, event) {
1612
1669
  }
1613
1670
  const runId = typeof payload.runId === "string" && payload.runId ? payload.runId : isPlayRunPackage(payload) ? payload.run.id : state.runId;
1614
1671
  const status = normalizeLiveStatus(payload.status) ?? (isPlayRunPackage(payload) ? normalizeLiveStatus(payload.run.status) : null) ?? state.status;
1615
- const progressPayload = isRecord2(payload.progress) ? payload.progress : {};
1672
+ const progressPayload = isRecord3(payload.progress) ? payload.progress : {};
1616
1673
  if (event.type === "play.run.final_status" && state.logs.length === 0 && state.lastLogSeq === 0) {
1617
1674
  const payloadLogs = readStringArray(payload.logs);
1618
1675
  const progressLogs = readStringArray(progressPayload.logs);
@@ -1725,9 +1782,9 @@ var DeeplineClient = class {
1725
1782
  return fields.length > 0 ? { fields } : schema;
1726
1783
  }
1727
1784
  schemaMetadata(schema, key) {
1728
- if (!isRecord2(schema)) return null;
1785
+ if (!isRecord3(schema)) return null;
1729
1786
  const value = schema[key];
1730
- return isRecord2(value) ? value : null;
1787
+ return isRecord3(value) ? value : null;
1731
1788
  }
1732
1789
  playRunCommand(play, options) {
1733
1790
  const target = play.reference || play.name;
@@ -1774,7 +1831,7 @@ var DeeplineClient = class {
1774
1831
  aliases,
1775
1832
  inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
1776
1833
  outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
1777
- staticPipeline: isRecord2(play.staticPipeline) ? play.staticPipeline : isRecord2(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord2(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
1834
+ staticPipeline: isRecord3(play.staticPipeline) ? play.staticPipeline : isRecord3(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord3(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
1778
1835
  ...csvInput ? { csvInput } : {},
1779
1836
  ...rowOutputSchema ? { rowOutputSchema } : {},
1780
1837
  runCommand: runCommand2,
@@ -5280,14 +5337,14 @@ function sanitizeCsvProjectionInfo(input2) {
5280
5337
  const rows = input2.rows.map(stripCsvProjectionFields);
5281
5338
  return { rows, columns };
5282
5339
  }
5283
- function isRecord3(value) {
5340
+ function isRecord4(value) {
5284
5341
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
5285
5342
  }
5286
5343
  function isSerializedDataset(value) {
5287
- return isRecord3(value) && value.kind === "dataset" && typeof value.count === "number" && Array.isArray(value.preview);
5344
+ return isRecord4(value) && value.kind === "dataset" && typeof value.count === "number" && Array.isArray(value.preview);
5288
5345
  }
5289
5346
  function isPackagedDatasetOutput(value) {
5290
- return isRecord3(value) && value.kind === "dataset" && isRecord3(value.preview) && Array.isArray(value.preview.rows);
5347
+ return isRecord4(value) && value.kind === "dataset" && isRecord4(value.preview) && Array.isArray(value.preview.rows);
5291
5348
  }
5292
5349
  function pathParts(path) {
5293
5350
  return path.split(".").map((part) => part.trim()).filter(Boolean);
@@ -5295,7 +5352,7 @@ function pathParts(path) {
5295
5352
  function valueAtPath(root, path) {
5296
5353
  let cursor = root;
5297
5354
  for (const part of pathParts(path)) {
5298
- if (!isRecord3(cursor)) {
5355
+ if (!isRecord4(cursor)) {
5299
5356
  return void 0;
5300
5357
  }
5301
5358
  cursor = cursor[part];
@@ -5303,17 +5360,17 @@ function valueAtPath(root, path) {
5303
5360
  return cursor;
5304
5361
  }
5305
5362
  function totalRowsForDataset(result, datasetPath) {
5306
- const metadata = isRecord3(result._metadata) ? result._metadata : null;
5363
+ const metadata = isRecord4(result._metadata) ? result._metadata : null;
5307
5364
  const parentPath = datasetPath.split(".").slice(0, -1).join(".");
5308
5365
  const parent = parentPath ? valueAtPath({ result }, parentPath) : result;
5309
- return metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count ?? (isRecord3(parent) ? parent.totalRows ?? parent.rowCount ?? parent.count : void 0) ?? result.totalRows ?? result.rowCount ?? result.count;
5366
+ return metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count ?? (isRecord4(parent) ? parent.totalRows ?? parent.rowCount ?? parent.count : void 0) ?? result.totalRows ?? result.rowCount ?? result.count;
5310
5367
  }
5311
5368
  function rowArray(value) {
5312
5369
  if (!Array.isArray(value)) {
5313
5370
  return null;
5314
5371
  }
5315
5372
  const rows = value.filter(
5316
- (row) => isRecord3(row)
5373
+ (row) => isRecord4(row)
5317
5374
  );
5318
5375
  return rows.length === value.length ? rows : null;
5319
5376
  }
@@ -5337,7 +5394,7 @@ function inferColumns(rows) {
5337
5394
  return columns;
5338
5395
  }
5339
5396
  function columnsFromDatasetSummary(summary) {
5340
- if (!isRecord3(summary) || !isRecord3(summary.columnStats)) {
5397
+ if (!isRecord4(summary) || !isRecord4(summary.columnStats)) {
5341
5398
  return [];
5342
5399
  }
5343
5400
  return Object.keys(summary.columnStats).filter((column) => column);
@@ -5366,7 +5423,7 @@ function canonicalRowsInfoFromCandidate(input2) {
5366
5423
  }
5367
5424
  if (isPackagedDatasetOutput(candidate.value)) {
5368
5425
  const rawRows = rowArray(candidate.value.preview?.rows) ?? [];
5369
- const totalRows2 = readNumber(candidate.value.preview?.totalRows) ?? readNumber(candidate.value.rowCount) ?? rawRows.length;
5426
+ const totalRows2 = readNumber(candidate.value.rowCount) ?? readNumber(candidate.value.preview?.totalRows) ?? rawRows.length;
5370
5427
  const explicitColumns = Array.isArray(candidate.value.columns) ? candidate.value.columns.filter(
5371
5428
  (column) => typeof column === "string"
5372
5429
  ) : [];
@@ -5427,7 +5484,7 @@ function collectDatasetCandidates(input2) {
5427
5484
  });
5428
5485
  return;
5429
5486
  }
5430
- if (!isRecord3(input2.value)) {
5487
+ if (!isRecord4(input2.value)) {
5431
5488
  return;
5432
5489
  }
5433
5490
  for (const [key, child] of Object.entries(input2.value)) {
@@ -5444,12 +5501,12 @@ function collectDatasetCandidates(input2) {
5444
5501
  }
5445
5502
  }
5446
5503
  function collectCanonicalRowsInfos(statusOrResult) {
5447
- const root = isRecord3(statusOrResult) ? statusOrResult : null;
5448
- const result = isRecord3(root?.result) ? root.result : root;
5504
+ const root = isRecord4(statusOrResult) ? statusOrResult : null;
5505
+ const result = isRecord4(root?.result) ? root.result : root;
5449
5506
  if (!result) {
5450
5507
  return [];
5451
5508
  }
5452
- const metadata = isRecord3(result._metadata) ? result._metadata : null;
5509
+ const metadata = isRecord4(result._metadata) ? result._metadata : null;
5453
5510
  const totalFromMetadata = metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count;
5454
5511
  const candidates = [
5455
5512
  {
@@ -5473,8 +5530,8 @@ function collectCanonicalRowsInfos(statusOrResult) {
5473
5530
  total: totalFromMetadata ?? result.totalRows ?? result.rowCount ?? result.count
5474
5531
  }
5475
5532
  ];
5476
- if (isRecord3(result.output)) {
5477
- const outputMetadata = isRecord3(result.output._metadata) ? result.output._metadata : null;
5533
+ if (isRecord4(result.output)) {
5534
+ const outputMetadata = isRecord4(result.output._metadata) ? result.output._metadata : null;
5478
5535
  const outputTotalFromMetadata = outputMetadata?.totalRows ?? outputMetadata?.rowCount ?? outputMetadata?.count;
5479
5536
  candidates.push(
5480
5537
  {
@@ -5501,14 +5558,14 @@ function collectCanonicalRowsInfos(statusOrResult) {
5501
5558
  }
5502
5559
  if (Array.isArray(result.steps)) {
5503
5560
  result.steps.forEach((step, index) => {
5504
- if (!isRecord3(step) || !isRecord3(step.output)) {
5561
+ if (!isRecord4(step) || !isRecord4(step.output)) {
5505
5562
  return;
5506
5563
  }
5507
5564
  const source = typeof step.output.path === "string" ? step.output.path : typeof step.id === "string" ? `steps.${step.id}.output` : `steps.${index}.output`;
5508
5565
  candidates.push({
5509
5566
  source,
5510
5567
  value: step.output,
5511
- total: step.output.rowCount ?? (isRecord3(step.output.preview) ? step.output.preview.totalRows : void 0) ?? (isRecord3(step.progress) ? step.progress.total : void 0)
5568
+ total: step.output.rowCount ?? (isRecord4(step.output.preview) ? step.output.preview.totalRows : void 0) ?? (isRecord4(step.progress) ? step.progress.total : void 0)
5512
5569
  });
5513
5570
  });
5514
5571
  }
@@ -5535,15 +5592,15 @@ function collectCanonicalRowsInfos(statusOrResult) {
5535
5592
  return infos;
5536
5593
  }
5537
5594
  function collectPackagedStepDatasetCandidates(statusOrResult) {
5538
- const root = isRecord3(statusOrResult) ? statusOrResult : null;
5595
+ const root = isRecord4(statusOrResult) ? statusOrResult : null;
5539
5596
  if (!root) {
5540
5597
  return [];
5541
5598
  }
5542
- const pkg = isRecord3(root.package) ? root.package : root;
5599
+ const pkg = isRecord4(root.package) ? root.package : root;
5543
5600
  const steps = Array.isArray(pkg.steps) ? pkg.steps : [];
5544
5601
  const candidates = [];
5545
5602
  for (const step of steps) {
5546
- if (!isRecord3(step) || !isRecord3(step.output)) {
5603
+ if (!isRecord4(step) || !isRecord4(step.output)) {
5547
5604
  continue;
5548
5605
  }
5549
5606
  const output2 = step.output;
@@ -5557,14 +5614,14 @@ function collectPackagedStepDatasetCandidates(statusOrResult) {
5557
5614
  candidates.push({
5558
5615
  source,
5559
5616
  value: output2,
5560
- total: output2.rowCount ?? (isRecord3(output2.preview) ? output2.preview.totalRows : void 0) ?? (isRecord3(step.progress) ? step.progress.total : void 0)
5617
+ total: output2.rowCount ?? (isRecord4(output2.preview) ? output2.preview.totalRows : void 0) ?? (isRecord4(step.progress) ? step.progress.total : void 0)
5561
5618
  });
5562
5619
  }
5563
5620
  return candidates;
5564
5621
  }
5565
5622
  function collectSerializedDatasetRowsInfos(statusOrResult) {
5566
- const root = isRecord3(statusOrResult) ? statusOrResult : null;
5567
- const result = isRecord3(root?.result) ? root.result : root;
5623
+ const root = isRecord4(statusOrResult) ? statusOrResult : null;
5624
+ const result = isRecord4(root?.result) ? root.result : root;
5568
5625
  const candidates = [];
5569
5626
  if (result) {
5570
5627
  collectDatasetCandidates({
@@ -5600,17 +5657,17 @@ function percentText(numerator, denominator) {
5600
5657
  return datasetSummaryPercentText(numerator, denominator);
5601
5658
  }
5602
5659
  function isDatasetExecutionStatsInput(value) {
5603
- return isRecord3(value) && isRecord3(value.columnStats) && Object.values(value.columnStats).every(isRecord3);
5660
+ return isRecord4(value) && isRecord4(value.columnStats) && Object.values(value.columnStats).every(isRecord4);
5604
5661
  }
5605
5662
  function extractDatasetExecutionStats(statusOrResult) {
5606
- if (!isRecord3(statusOrResult)) {
5663
+ if (!isRecord4(statusOrResult)) {
5607
5664
  return null;
5608
5665
  }
5609
5666
  const direct = statusOrResult.dataset_execution_stats;
5610
5667
  if (isDatasetExecutionStatsInput(direct)) {
5611
5668
  return direct;
5612
5669
  }
5613
- const nested = isRecord3(statusOrResult.result) ? statusOrResult.result.dataset_execution_stats : null;
5670
+ const nested = isRecord4(statusOrResult.result) ? statusOrResult.result.dataset_execution_stats : null;
5614
5671
  return isDatasetExecutionStatsInput(nested) ? nested : null;
5615
5672
  }
5616
5673
  function countPercentText(count, denominator) {
@@ -5651,13 +5708,13 @@ function summarizeSampleValue(value, depth = 0) {
5651
5708
  if (typeof parsed === "number" || typeof parsed === "boolean") return parsed;
5652
5709
  if (depth >= 3) {
5653
5710
  if (Array.isArray(parsed)) return [];
5654
- if (isRecord3(parsed)) return {};
5711
+ if (isRecord4(parsed)) return {};
5655
5712
  return compactScalar(parsed);
5656
5713
  }
5657
5714
  if (Array.isArray(parsed)) {
5658
5715
  return parsed.slice(0, 3).map((item) => summarizeSampleValue(item, depth + 1));
5659
5716
  }
5660
- if (isRecord3(parsed)) {
5717
+ if (isRecord4(parsed)) {
5661
5718
  const out = {};
5662
5719
  for (const [key, nested] of Object.entries(parsed)) {
5663
5720
  if (["__dl", "meta", "metadata"].includes(key)) {
@@ -5688,7 +5745,7 @@ function compactCell(value) {
5688
5745
  }
5689
5746
  return `[${parsed.length} items]`;
5690
5747
  }
5691
- if (isRecord3(parsed)) {
5748
+ if (isRecord4(parsed)) {
5692
5749
  for (const key of ["matched_result", "output"]) {
5693
5750
  if (parsed[key] !== null && parsed[key] !== void 0 && parsed[key] !== "") {
5694
5751
  return compactCell(parsed[key]);
@@ -7479,16 +7536,19 @@ var PLAY_DEDUP_BACKENDS = {
7479
7536
  var PLAY_SCHEDULER_BACKENDS = {
7480
7537
  temporal: "temporal",
7481
7538
  cfWorkflows: "cf-workflows",
7539
+ /**
7540
+ * Private legacy id retained only so old persisted rows can be interpreted.
7541
+ * It is not a selectable scheduler backend after the Hatchet hard cutover.
7542
+ */
7482
7543
  postgres: "postgres",
7544
+ hatchet: "hatchet",
7483
7545
  inProcess: "in-process"
7484
7546
  };
7485
7547
 
7486
7548
  // ../shared_libs/play-runtime/providers.ts
7487
7549
  var PLAY_RUNTIME_PROVIDER_IDS = {
7488
7550
  workersEdge: "workers_edge",
7489
- postgresFast: "postgres_fast",
7490
- postgresFastSandbox: "postgres_fast_sandbox",
7491
- postgresFastWorkers: "postgres_fast_workers",
7551
+ hatchet: "hatchet",
7492
7552
  local: "local"
7493
7553
  };
7494
7554
  var PLAY_RUNTIME_PROVIDERS = {
@@ -7500,29 +7560,13 @@ var PLAY_RUNTIME_PROVIDERS = {
7500
7560
  artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
7501
7561
  label: "Cloudflare Dynamic Workflows + Dynamic Workers + DO dedup"
7502
7562
  },
7503
- postgres_fast: {
7504
- id: PLAY_RUNTIME_PROVIDER_IDS.postgresFast,
7505
- scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
7563
+ hatchet: {
7564
+ id: PLAY_RUNTIME_PROVIDER_IDS.hatchet,
7565
+ scheduler: PLAY_SCHEDULER_BACKENDS.hatchet,
7506
7566
  runner: PLAY_RUNTIME_BACKENDS.daytona,
7507
7567
  dedup: PLAY_DEDUP_BACKENDS.durableObject,
7508
7568
  artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
7509
- label: "BETA: Postgres Scheduler + warm sandbox runner + DO dedup"
7510
- },
7511
- postgres_fast_sandbox: {
7512
- id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastSandbox,
7513
- scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
7514
- runner: PLAY_RUNTIME_BACKENDS.daytona,
7515
- dedup: PLAY_DEDUP_BACKENDS.durableObject,
7516
- artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
7517
- label: "BETA: Postgres Scheduler + warm sandbox runner + DO dedup"
7518
- },
7519
- postgres_fast_workers: {
7520
- id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastWorkers,
7521
- scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
7522
- runner: PLAY_RUNTIME_BACKENDS.cloudflareWorkers,
7523
- dedup: PLAY_DEDUP_BACKENDS.durableObject,
7524
- artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
7525
- label: "Experimental Postgres Scheduler + Queue/DO-woken Workers + DO dedup"
7569
+ label: "Hatchet scheduler + one-shot Daytona runner + DO dedup"
7526
7570
  },
7527
7571
  local: {
7528
7572
  id: PLAY_RUNTIME_PROVIDER_IDS.local,
@@ -8041,17 +8085,17 @@ function parsePositiveInteger2(value, flagName) {
8041
8085
  }
8042
8086
  return parsed;
8043
8087
  }
8044
- function isRecord4(value) {
8088
+ function isRecord5(value) {
8045
8089
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
8046
8090
  }
8047
8091
  function stringValue(value) {
8048
8092
  return typeof value === "string" ? value.trim() : "";
8049
8093
  }
8050
8094
  function extractionEntries(value) {
8051
- if (Array.isArray(value)) return value.filter(isRecord4);
8052
- if (!isRecord4(value)) return [];
8095
+ if (Array.isArray(value)) return value.filter(isRecord5);
8096
+ if (!isRecord5(value)) return [];
8053
8097
  return Object.entries(value).map(
8054
- ([name, entry]) => isRecord4(entry) ? { name, ...entry } : { name }
8098
+ ([name, entry]) => isRecord5(entry) ? { name, ...entry } : { name }
8055
8099
  );
8056
8100
  }
8057
8101
  var PlayBootstrapError = class extends Error {
@@ -8471,7 +8515,7 @@ function readCsvSampleRows(sample) {
8471
8515
  relax_column_count: true,
8472
8516
  trim: true
8473
8517
  });
8474
- return Array.isArray(parsedRows) ? parsedRows.filter(isRecord4) : [];
8518
+ return Array.isArray(parsedRows) ? parsedRows.filter(isRecord5) : [];
8475
8519
  }
8476
8520
  function readSourceCsvColumnSpecs(csvPath) {
8477
8521
  const sample = readCsvSample(csvPath);
@@ -8504,16 +8548,16 @@ function packagedCsvPathForPlay(csvPath) {
8504
8548
  return portablePath.startsWith(".") ? portablePath : `./${portablePath}`;
8505
8549
  }
8506
8550
  function getterNamesFromTool(tool, kind) {
8507
- const usageGuidance = isRecord4(tool?.usageGuidance) ? tool.usageGuidance : {};
8508
- const resultGuidance = isRecord4(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord4(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
8551
+ const usageGuidance = isRecord5(tool?.usageGuidance) ? tool.usageGuidance : {};
8552
+ const resultGuidance = isRecord5(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord5(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
8509
8553
  const key = kind === "list" ? "extractedLists" : "extractedValues";
8510
8554
  const snakeKey = kind === "list" ? "extracted_lists" : "extracted_values";
8511
8555
  return extractionEntries(resultGuidance[key] ?? resultGuidance[snakeKey]).map((entry) => stringValue(entry.name)).filter(Boolean);
8512
8556
  }
8513
8557
  function targetGettersFromTool(tool) {
8514
- const record = isRecord4(tool) ? tool : {};
8558
+ const record = isRecord5(tool) ? tool : {};
8515
8559
  const raw = record.targetGetters ?? record.target_getters;
8516
- if (!isRecord4(raw)) return {};
8560
+ if (!isRecord5(raw)) return {};
8517
8561
  const entries = [];
8518
8562
  for (const [target, value] of Object.entries(raw)) {
8519
8563
  const paths = Array.isArray(value) ? value.map((path) => typeof path === "string" ? path.trim() : "").filter(Boolean) : [];
@@ -8534,10 +8578,10 @@ function listRowCandidateKeysFromTool(tool) {
8534
8578
  return [...keys].sort();
8535
8579
  }
8536
8580
  function inputPropertyNames(schema) {
8537
- if (!isRecord4(schema)) return [];
8538
- if (isRecord4(schema.properties)) return Object.keys(schema.properties);
8581
+ if (!isRecord5(schema)) return [];
8582
+ if (isRecord5(schema.properties)) return Object.keys(schema.properties);
8539
8583
  if (Array.isArray(schema.fields)) {
8540
- return schema.fields.filter(isRecord4).map((field) => stringValue(field.name)).filter(Boolean);
8584
+ return schema.fields.filter(isRecord5).map((field) => stringValue(field.name)).filter(Boolean);
8541
8585
  }
8542
8586
  return [];
8543
8587
  }
@@ -8551,7 +8595,7 @@ function schemaFieldDetails(schema) {
8551
8595
  return { required, optional };
8552
8596
  }
8553
8597
  function jsonSchemaTypeExpression(schema) {
8554
- if (!isRecord4(schema)) return "unknown";
8598
+ if (!isRecord5(schema)) return "unknown";
8555
8599
  const type = schema.type;
8556
8600
  if (Array.isArray(type)) {
8557
8601
  return type.map((entry) => jsonSchemaTypeExpression({ ...schema, type: entry })).join(" | ");
@@ -8581,7 +8625,7 @@ function jsonSchemaTypeExpression(schema) {
8581
8625
  }
8582
8626
  }
8583
8627
  function objectPropertySchema(schema, property) {
8584
- return isRecord4(schema) && isRecord4(schema.properties) ? schema.properties[property] : null;
8628
+ return isRecord5(schema) && isRecord5(schema.properties) ? schema.properties[property] : null;
8585
8629
  }
8586
8630
  function playOutputHasField(schema, field) {
8587
8631
  return objectPropertySchema(schema, field) != null;
@@ -8757,14 +8801,14 @@ ${indent2.slice(2)}}`;
8757
8801
  }
8758
8802
  function requiredPlayInputFields(play) {
8759
8803
  const schema = play?.inputSchema;
8760
- if (!isRecord4(schema)) return [];
8804
+ if (!isRecord5(schema)) return [];
8761
8805
  if (Array.isArray(schema.required)) {
8762
8806
  return schema.required.filter(
8763
8807
  (value) => typeof value === "string"
8764
8808
  );
8765
8809
  }
8766
8810
  if (Array.isArray(schema.fields)) {
8767
- return schema.fields.filter(isRecord4).filter(
8811
+ return schema.fields.filter(isRecord5).filter(
8768
8812
  (field) => field.required === true && typeof field.name === "string"
8769
8813
  ).map((field) => String(field.name));
8770
8814
  }
@@ -8945,7 +8989,7 @@ function validateBootstrapRoutes(input2) {
8945
8989
  }
8946
8990
  }
8947
8991
  function staticPipelineSubsteps(pipeline) {
8948
- if (!isRecord4(pipeline)) return [];
8992
+ if (!isRecord5(pipeline)) return [];
8949
8993
  return [
8950
8994
  ...extractionEntries(pipeline.stages),
8951
8995
  ...extractionEntries(pipeline.substeps)
@@ -8953,7 +8997,7 @@ function staticPipelineSubsteps(pipeline) {
8953
8997
  }
8954
8998
  function playUsesMapBackedRuntime(play) {
8955
8999
  const pipeline = play?.staticPipeline;
8956
- if (!isRecord4(pipeline)) return false;
9000
+ if (!isRecord5(pipeline)) return false;
8957
9001
  if (stringValue(pipeline.tableNamespace)) return true;
8958
9002
  return staticPipelineSubsteps(pipeline).some((substep) => {
8959
9003
  if (stringValue(substep.type) === "map") return true;
@@ -8962,7 +9006,7 @@ function playUsesMapBackedRuntime(play) {
8962
9006
  aliases: [],
8963
9007
  runCommand: "",
8964
9008
  examples: [],
8965
- staticPipeline: isRecord4(substep.pipeline) ? substep.pipeline : null
9009
+ staticPipeline: isRecord5(substep.pipeline) ? substep.pipeline : null
8966
9010
  });
8967
9011
  });
8968
9012
  }
@@ -10524,10 +10568,12 @@ function playStatusValue(value) {
10524
10568
  return value === "queued" || value === "running" || value === "waiting" || value === "completed" || value === "failed" || value === "cancelled" ? value : null;
10525
10569
  }
10526
10570
  function getRunRecordFromPackage(value) {
10527
- if (!isPlayRunPackageValue(value)) {
10571
+ const nestedPackage = value.package;
10572
+ const playRunPackage = isPlayRunPackageValue(value) ? value : isPlayRunPackageValue(nestedPackage) ? nestedPackage : null;
10573
+ if (!playRunPackage) {
10528
10574
  return null;
10529
10575
  }
10530
- const run = value.run;
10576
+ const run = playRunPackage.run;
10531
10577
  return run && typeof run === "object" && !Array.isArray(run) ? run : null;
10532
10578
  }
10533
10579
  function getRunIdFromLiveEvent(event) {
@@ -10557,10 +10603,12 @@ function getFinalStatusFromLiveEvent(event) {
10557
10603
  return null;
10558
10604
  }
10559
10605
  const runId = typeof payload.runId === "string" ? payload.runId : typeof packageRun?.id === "string" ? packageRun.id : "";
10606
+ const error = typeof payload.error === "string" ? payload.error : typeof packageRun?.error === "string" ? packageRun.error : void 0;
10560
10607
  return {
10561
10608
  ...payload,
10562
10609
  runId,
10563
- status
10610
+ status,
10611
+ ...error ? { error } : {}
10564
10612
  };
10565
10613
  }
10566
10614
  function getLogLinesFromLiveEvent(event) {
@@ -11879,7 +11927,16 @@ function withTerminalPlayIdentity(status, playName) {
11879
11927
  function compactPlayStatus(status) {
11880
11928
  const packaged = getPlayRunPackage(status);
11881
11929
  if (packaged) {
11882
- return packaged;
11930
+ const error2 = selectRunErrorForDisplay(status) ?? (typeof status.error === "string" ? String(status.error) : null);
11931
+ if (!error2) {
11932
+ return packaged;
11933
+ }
11934
+ const run = packaged.run && typeof packaged.run === "object" ? packaged.run : null;
11935
+ return {
11936
+ ...packaged,
11937
+ error: error2,
11938
+ ...run ? { run: { ...run, error: error2 } } : {}
11939
+ };
11883
11940
  }
11884
11941
  const rowsInfo = extractCanonicalRowsInfo(status);
11885
11942
  const result = status && typeof status === "object" ? status.result : null;
@@ -12219,10 +12276,17 @@ function writePlayResult(status, jsonOutput, options) {
12219
12276
  ` }
12220
12277
  );
12221
12278
  }
12222
- function playRunPackageStepCount(pkg) {
12223
- if (!pkg) return 0;
12224
- const steps = pkg.steps;
12225
- return Array.isArray(steps) ? steps.length : 0;
12279
+ function playRunPackageTextLedgerIncomplete(pkg) {
12280
+ if (!pkg) return true;
12281
+ const steps = readRecordArray(pkg.steps);
12282
+ if (steps.length === 0) return true;
12283
+ for (const step of steps) {
12284
+ if (step.kind !== "dataset" || step.status !== "completed") continue;
12285
+ const output2 = readRecord(step.output);
12286
+ if (!output2 || typeof output2.rowCount !== "number") return true;
12287
+ if (!readRecord(output2.summary)) return true;
12288
+ }
12289
+ return false;
12226
12290
  }
12227
12291
  async function resolvePlayRunOutputStatus(input2) {
12228
12292
  const runId = input2.status.runId;
@@ -12231,7 +12295,7 @@ async function resolvePlayRunOutputStatus(input2) {
12231
12295
  }
12232
12296
  const streamedPackage = getPlayRunPackage(input2.status);
12233
12297
  const refreshForFullJson = input2.fullJson && streamedPackage !== null;
12234
- const streamedTextPackageIncomplete = !input2.jsonOutput && input2.status.status === "completed" && playRunPackageStepCount(streamedPackage) === 0;
12298
+ const streamedTextPackageIncomplete = !input2.jsonOutput && input2.status.status === "completed" && playRunPackageTextLedgerIncomplete(streamedPackage);
12235
12299
  if (!refreshForFullJson && !streamedTextPackageIncomplete) {
12236
12300
  return input2.status;
12237
12301
  }
@@ -12239,7 +12303,7 @@ async function resolvePlayRunOutputStatus(input2) {
12239
12303
  billing: false,
12240
12304
  full: input2.fullJson
12241
12305
  });
12242
- for (let attempt = 0; attempt < 3 && streamedTextPackageIncomplete && refreshedStatus.status === "completed" && playRunPackageStepCount(getPlayRunPackage(refreshedStatus)) === 0; attempt += 1) {
12306
+ for (let attempt = 0; attempt < 3 && streamedTextPackageIncomplete && refreshedStatus.status === "completed" && playRunPackageTextLedgerIncomplete(getPlayRunPackage(refreshedStatus)); attempt += 1) {
12243
12307
  await sleep5(250);
12244
12308
  refreshedStatus = await input2.client.getPlayStatus(runId, {
12245
12309
  billing: false,
@@ -12548,7 +12612,7 @@ function extractPlayValidationErrors(value) {
12548
12612
  if (value instanceof DeeplineError) {
12549
12613
  return extractPlayValidationErrors(value.details);
12550
12614
  }
12551
- if (!isRecord5(value)) {
12615
+ if (!isRecord6(value)) {
12552
12616
  return [];
12553
12617
  }
12554
12618
  const directErrors = stringArrayField(value, "errors");
@@ -12761,7 +12825,7 @@ function writeStartedPlayRun(input2) {
12761
12825
  );
12762
12826
  }
12763
12827
  function parsePlayRunOptions(args) {
12764
- const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--profile <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--profile <id>] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n --profile defaults to workers_edge; postgres_fast is BETA (opt-in per run, never the default).\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotency, tool call id, and ctx.dataset guidance.";
12828
+ const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--profile <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--profile <id>] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n --profile defaults to workers_edge; hatchet is the durable Daytona-backed preview runtime.\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotency, tool call id, and ctx.dataset guidance.";
12765
12829
  let filePath = null;
12766
12830
  let playName = null;
12767
12831
  let input2 = null;
@@ -12906,7 +12970,7 @@ function shouldUseLocalOnlyPlayCheck() {
12906
12970
  const value = process.env.DEEPLINE_PLAY_CHECK_LOCAL_ONLY?.trim().toLowerCase();
12907
12971
  return value === "1" || value === "true" || value === "yes" || value === "on";
12908
12972
  }
12909
- function isRecord5(value) {
12973
+ function isRecord6(value) {
12910
12974
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
12911
12975
  }
12912
12976
  function stringValue2(value) {
@@ -12916,14 +12980,14 @@ function asArray(value) {
12916
12980
  return Array.isArray(value) ? value : [];
12917
12981
  }
12918
12982
  function extractionEntries2(value) {
12919
- if (Array.isArray(value)) return value.filter(isRecord5);
12920
- if (!isRecord5(value)) return [];
12983
+ if (Array.isArray(value)) return value.filter(isRecord6);
12984
+ if (!isRecord6(value)) return [];
12921
12985
  return Object.entries(value).map(
12922
- ([name, entry]) => isRecord5(entry) ? { name, ...entry } : { name }
12986
+ ([name, entry]) => isRecord6(entry) ? { name, ...entry } : { name }
12923
12987
  );
12924
12988
  }
12925
12989
  function firstRawPath(entry) {
12926
- const details = isRecord5(entry.details) ? entry.details : {};
12990
+ const details = isRecord6(entry.details) ? entry.details : {};
12927
12991
  const paths = [
12928
12992
  ...asArray(details.rawToolOutputPaths),
12929
12993
  ...asArray(details.raw_tool_output_paths),
@@ -12941,12 +13005,12 @@ function checkHintRawPath(value) {
12941
13005
  function collectStaticPipelineToolIds(staticPipeline) {
12942
13006
  const seen = /* @__PURE__ */ new Set();
12943
13007
  const visitPipeline = (pipeline) => {
12944
- if (!isRecord5(pipeline)) return;
13008
+ if (!isRecord6(pipeline)) return;
12945
13009
  for (const step of [
12946
13010
  ...asArray(pipeline.stages),
12947
13011
  ...asArray(pipeline.substeps)
12948
13012
  ]) {
12949
- if (!isRecord5(step)) continue;
13013
+ if (!isRecord6(step)) continue;
12950
13014
  if (step.type === "tool") {
12951
13015
  const toolId = stringValue2(step.toolId) || stringValue2(step.tool);
12952
13016
  if (toolId) seen.add(toolId);
@@ -12960,9 +13024,9 @@ function collectStaticPipelineToolIds(staticPipeline) {
12960
13024
  return [...seen].sort();
12961
13025
  }
12962
13026
  function toolGetterHintFromMetadata(toolId, tool) {
12963
- const usageGuidance = isRecord5(tool.usageGuidance) ? tool.usageGuidance : {};
12964
- const resultGuidance = isRecord5(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord5(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
12965
- const toolResponse = isRecord5(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord5(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
13027
+ const usageGuidance = isRecord6(tool.usageGuidance) ? tool.usageGuidance : {};
13028
+ const resultGuidance = isRecord6(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord6(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
13029
+ const toolResponse = isRecord6(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord6(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
12966
13030
  const lists = extractionEntries2(
12967
13031
  resultGuidance.extractedLists ?? resultGuidance.extracted_lists
12968
13032
  ).map((entry) => ({
@@ -14287,6 +14351,40 @@ async function handlePlayDescribe(args) {
14287
14351
  );
14288
14352
  return 2;
14289
14353
  }
14354
+ if (isFileTarget(playName) || looksLikeFilePath(playName)) {
14355
+ const message = "Local play files can be checked and run, but describe only supports saved/prebuilt play references.";
14356
+ const definedName = isFileTarget(playName) ? (() => {
14357
+ try {
14358
+ return extractPlayName(
14359
+ readFileSync6(resolve10(playName), "utf-8"),
14360
+ playName
14361
+ );
14362
+ } catch {
14363
+ return null;
14364
+ }
14365
+ })() : null;
14366
+ const next = [
14367
+ `deepline plays check ${playName}`,
14368
+ ...definedName ? [`deepline plays describe <workspace>/${definedName}`] : []
14369
+ ];
14370
+ if (argsWantJson(args)) {
14371
+ process.stdout.write(
14372
+ `${JSON.stringify({
14373
+ ok: false,
14374
+ error: { message },
14375
+ next
14376
+ })}
14377
+ `
14378
+ );
14379
+ } else {
14380
+ console.error(message);
14381
+ console.error(`Try: ${next[0]}`);
14382
+ if (next[1]) {
14383
+ console.error(`Or after publishing/running: ${next[1]}`);
14384
+ }
14385
+ }
14386
+ return 2;
14387
+ }
14290
14388
  const client2 = new DeeplineClient();
14291
14389
  await assertCanonicalNamedPlayReference(client2, playName);
14292
14390
  const play = await client2.describePlay(
@@ -15368,6 +15466,18 @@ function getterFromLegacyExtractJs(extractJs, fallbackAlias) {
15368
15466
  return null;
15369
15467
  }
15370
15468
 
15469
+ // src/cli/enrich-compat-adapter.ts
15470
+ var ENRICH_COMPAT_DEFAULT_PLAY_NAME = "deepline-enrich-v1-compat";
15471
+ var ENRICH_COMPAT_DEFAULT_MAP_NAME = "deepline_enrich_rows";
15472
+ var ENRICH_COMPAT_METADATA_CELL_POLICY_SOURCE = "{ recompute: true }";
15473
+ function buildEnrichCompatibilityPlan(options = {}) {
15474
+ return {
15475
+ playName: options.playName?.trim() || ENRICH_COMPAT_DEFAULT_PLAY_NAME,
15476
+ mapName: options.mapName?.trim() || ENRICH_COMPAT_DEFAULT_MAP_NAME,
15477
+ metadataCellPolicySource: ENRICH_COMPAT_METADATA_CELL_POLICY_SOURCE
15478
+ };
15479
+ }
15480
+
15371
15481
  // src/cli/user-code-safety.ts
15372
15482
  var FORBIDDEN = [
15373
15483
  // Non-deterministic — breaks replay.
@@ -15508,7 +15618,7 @@ function renderIdiomaticExecuteStep(command, options) {
15508
15618
  ` tool: ${tool},`,
15509
15619
  ` input: ${input2} as any,`,
15510
15620
  ` description: ${stringLiteral((command.description ?? "").trim() || `Run ${command.alias} via ${command.tool}.`)},`,
15511
- ...options.force ? [` staleAfterSeconds: 1,`] : [],
15621
+ ...options.force ? [` force: true,`] : [],
15512
15622
  ` });`,
15513
15623
  ` return ${extraction};`,
15514
15624
  `}`
@@ -15539,18 +15649,18 @@ function renderPlayStep(command, options) {
15539
15649
  const runIfJs = command.run_if_js ? `(row) => { const input = row; const context = row;
15540
15650
  ${indent(renderJavascriptBody(command.run_if_js), 6)}
15541
15651
  }` : "null";
15542
- const runIfLines = command.run_if_js ? [` const __dlRunIf = ${runIfJs};`, ` if (!__dlRunIf(row)) return null;`] : [];
15543
- const playOptions = [
15544
- ` description: ${stringLiteral(command.description ?? command.alias)}`,
15545
- ...options.force ? [` staleAfterSeconds: 1`] : []
15546
- ].join(",\n");
15652
+ const runIfLines = command.run_if_js ? [
15653
+ ` const __dlRunIf = ${runIfJs};`,
15654
+ ` if (!__dlRunIf(templateRow)) return null;`
15655
+ ] : [];
15547
15656
  return [
15548
15657
  `async (row, stepCtx) => {`,
15549
15658
  ...options.precheck ? [` if (${options.precheck}) return null;`] : [],
15659
+ ` const templateRow = __dlPrepareEnrichRow(row, [${alias}]);`,
15550
15660
  ...runIfLines,
15551
- ` const payload = __dlTemplate(${payload}, row) as Record<string, unknown>;`,
15661
+ ` const payload = __dlTemplate(${payload}, templateRow) as Record<string, unknown>;`,
15552
15662
  ` const result = await stepCtx.runPlay(${callId}, ${playRef}, payload, {`,
15553
- playOptions,
15663
+ ` description: ${stringLiteral(command.description ?? command.alias)}`,
15554
15664
  ` });`,
15555
15665
  ` return __dlPlayResultValue(${alias}, result);`,
15556
15666
  `}`
@@ -15567,12 +15677,17 @@ function renderJavascriptBody(source) {
15567
15677
  }
15568
15678
  return source;
15569
15679
  }
15570
- function renderColumnStep(alias, resolverSource, force) {
15680
+ function renderColumnStep(alias, resolverSource, options = {}) {
15571
15681
  const resolver = indent(resolverSource, 8);
15682
+ const optionFields = [
15683
+ ...options.recompute === true ? ["recompute: true"] : [],
15684
+ ...options.recomputeOnError === true ? ["recomputeOnError: true"] : []
15685
+ ];
15686
+ const optionSource = optionFields.length > 0 ? `{ ${optionFields.join(", ")} }` : null;
15572
15687
  return [
15573
15688
  ` .withColumn(${stringLiteral(alias)},`,
15574
- force ? `${resolver},` : resolver,
15575
- ...force ? [` { staleAfterSeconds: 1 }`] : [],
15689
+ `${resolver}${optionSource ? "," : ""}`,
15690
+ ...optionSource ? [` ${optionSource},`] : [],
15576
15691
  ` )`
15577
15692
  ].join("\n");
15578
15693
  }
@@ -15621,15 +15736,38 @@ function collectMetadataColumns(commands, waterfallGroupId) {
15621
15736
  }
15622
15737
  return columns;
15623
15738
  }
15624
- function renderMetadataColumnStep(config) {
15739
+ function collectGeneratedAliases(commands) {
15740
+ const aliases = [];
15741
+ const addAlias = (alias) => {
15742
+ if (alias && !aliases.includes(alias)) {
15743
+ aliases.push(alias);
15744
+ }
15745
+ };
15746
+ for (const command of commands) {
15747
+ if (isWaterfall(command)) {
15748
+ const before = aliases.length;
15749
+ collectGeneratedAliases(command.commands).forEach(addAlias);
15750
+ if (aliases.length > before) {
15751
+ addAlias(command.with_waterfall);
15752
+ addAlias(`${command.with_waterfall}_source`);
15753
+ }
15754
+ continue;
15755
+ }
15756
+ if (!command.disabled) {
15757
+ addAlias(command.alias);
15758
+ }
15759
+ }
15760
+ return aliases;
15761
+ }
15762
+ function renderMetadataColumnStep(config, policySource) {
15625
15763
  const columns = collectMetadataColumns(config.commands);
15626
15764
  if (Object.keys(columns).length === 0) {
15627
15765
  return "";
15628
15766
  }
15629
15767
  return [
15630
15768
  ` .withColumn('_metadata',`,
15631
- ` (row) => __dlMergeMetadata(row._metadata, ${stableJson({ columns })}),`,
15632
- ` { staleAfterSeconds: 1 }`,
15769
+ ` (row) => __dlMergeMetadata(__dlMetadataFromRow(row), ${stableJson({ columns })}),`,
15770
+ ` ${policySource},`,
15633
15771
  ` )`
15634
15772
  ].join("\n");
15635
15773
  }
@@ -15656,7 +15794,7 @@ function renderWaterfallColumns(command, forceAliases, inlineRunJavascript, idio
15656
15794
  inlineRunJavascript,
15657
15795
  idiomaticGetters
15658
15796
  }),
15659
- force
15797
+ { recompute: force, recomputeOnError: true }
15660
15798
  );
15661
15799
  }).filter((line) => line !== null);
15662
15800
  const aliases = activeChildren.map((nested) => nested.alias);
@@ -15672,21 +15810,19 @@ function renderWaterfallColumns(command, forceAliases, inlineRunJavascript, idio
15672
15810
  }
15673
15811
  return [
15674
15812
  ...columnSteps,
15675
- renderColumnStep(
15676
- command.with_waterfall,
15677
- `(row) => ${returnExpr}`,
15678
- forceParent
15679
- ),
15813
+ renderColumnStep(command.with_waterfall, `(row) => ${returnExpr}`, {
15814
+ recompute: forceParent
15815
+ }),
15680
15816
  renderColumnStep(
15681
15817
  `${command.with_waterfall}_source`,
15682
15818
  typeof command.min_results === "number" ? `(row) => __dlContributingAliases(row, ${stableJson(aliases)})` : `(row) => __dlFirstMeaningfulAlias(row, ${stableJson(aliases)})`,
15683
- forceParent
15819
+ { recompute: forceParent }
15684
15820
  )
15685
15821
  ];
15686
15822
  }
15687
15823
  function compileEnrichConfigToPlaySource(config, options = {}) {
15688
- const playName = options.playName ?? "deepline-enrich-v1-compat";
15689
- const mapName = options.mapName ?? "deepline_enrich_rows";
15824
+ const compatibility = buildEnrichCompatibilityPlan(options);
15825
+ const { playName, mapName } = compatibility;
15690
15826
  const inlineRunJavascript = options.inlineRunJavascript ?? false;
15691
15827
  const idiomaticGetters = options.idiomaticGetters ?? false;
15692
15828
  const forceAliases = new Set(
@@ -15717,18 +15853,30 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
15717
15853
  inlineRunJavascript,
15718
15854
  idiomaticGetters
15719
15855
  }),
15720
- force
15856
+ { recompute: force, recomputeOnError: true }
15721
15857
  )
15722
15858
  );
15723
15859
  });
15724
15860
  const columnStepSource = columnSteps.length > 0 ? columnSteps.join("\n") : ` .withColumn('noop', () => null)`;
15725
- const metadataColumnSource = renderMetadataColumnStep(config);
15861
+ const metadataColumnSource = renderMetadataColumnStep(
15862
+ config,
15863
+ compatibility.metadataCellPolicySource
15864
+ );
15865
+ const generatedAliases = collectGeneratedAliases(config.commands);
15726
15866
  const body = [
15727
15867
  `export default definePlay(${stringLiteral(playName)}, async (ctx, input: EnrichInput) => {`,
15728
15868
  ` const sourceRows = await ctx.csv<Record<string, unknown>>(input.file);`,
15729
15869
  ` const rowStart = __dlNonNegativeInteger(input.rowStart, 0);`,
15730
15870
  ` const rowEndExclusive = Number.isFinite(input.rowEnd) ? Math.max(rowStart, __dlWholeNumber(input.rowEnd, rowStart) + 1) : undefined;`,
15731
- ` const rows = sourceRows.slice(rowStart, rowEndExclusive, { key: 'deepline_enrich_selected_rows', sourceLabel: 'Selected enrich rows' });`,
15871
+ ` const rows: Array<Record<string, unknown>> = [];`,
15872
+ ` let sourceRowIndex = 0;`,
15873
+ ` for await (const row of sourceRows) {`,
15874
+ ` if (rowEndExclusive !== undefined && sourceRowIndex >= rowEndExclusive) break;`,
15875
+ ` if (sourceRowIndex >= rowStart) {`,
15876
+ ` rows.push(__dlPrepareEnrichRow(row, ${stableJson(generatedAliases)}));`,
15877
+ ` }`,
15878
+ ` sourceRowIndex += 1;`,
15879
+ ` }`,
15732
15880
  ` const enriched = await ctx`,
15733
15881
  ` .dataset(${stringLiteral(mapName)}, rows)`,
15734
15882
  columnStepSource,
@@ -15814,6 +15962,18 @@ function helperSource() {
15814
15962
  ` return null;`,
15815
15963
  `}`,
15816
15964
  ``,
15965
+ `function __dlMetadataFromRow(row: Record<string, unknown>): unknown {`,
15966
+ ` const direct = __dlParseMetadata(row._metadata);`,
15967
+ ` if (direct) return direct;`,
15968
+ ` const relocated = __dlParseMetadata(row.metadata);`,
15969
+ ` if (relocated) return relocated;`,
15970
+ ` const dotted = __dlParseMetadata(row['metadata.columns']);`,
15971
+ ` if (dotted) return { columns: dotted };`,
15972
+ ` const underscored = __dlParseMetadata(row.metadata__columns);`,
15973
+ ` if (underscored) return { columns: underscored };`,
15974
+ ` return row._metadata;`,
15975
+ `}`,
15976
+ ``,
15817
15977
  `function __dlMergeMetadata(existing: unknown, patch: Record<string, unknown>): Record<string, unknown> {`,
15818
15978
  ` const base = __dlParseMetadata(existing) ?? {};`,
15819
15979
  ` const baseColumns = __dlRecord(base.columns) ? base.columns : {};`,
@@ -15847,17 +16007,55 @@ function helperSource() {
15847
16007
  ` return parts;`,
15848
16008
  `}`,
15849
16009
  ``,
16010
+ `function __dlNormalizeHeader(value: string): string {`,
16011
+ ` return value.trim().replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');`,
16012
+ `}`,
16013
+ ``,
16014
+ `function __dlOwnStringKeys(record: Record<string, unknown>): string[] {`,
16015
+ ` return Object.keys(record);`,
16016
+ `}`,
16017
+ ``,
16018
+ `function __dlReadOwnField(record: Record<string, unknown>, key: string): unknown {`,
16019
+ ` return record[key];`,
16020
+ `}`,
16021
+ ``,
16022
+ `function __dlGetNormalizedKey(record: Record<string, unknown>, part: string): string | null {`,
16023
+ ` const normalized = __dlNormalizeHeader(part);`,
16024
+ ` for (const key of __dlOwnStringKeys(record)) {`,
16025
+ ` if (__dlNormalizeHeader(key) === normalized) return key;`,
16026
+ ` }`,
16027
+ ` return null;`,
16028
+ `}`,
16029
+ ``,
16030
+ `function __dlGetRecordField(record: Record<string, unknown>, part: string): { found: boolean; value: unknown } {`,
16031
+ ` if (part in record) return { found: true, value: record[part] };`,
16032
+ ` const normalizedKey = __dlGetNormalizedKey(record, part);`,
16033
+ ` if (normalizedKey) return { found: true, value: __dlReadOwnField(record, normalizedKey) };`,
16034
+ ` const projectedValues = record.__deeplineCsvProjectedValues;`,
16035
+ ` if (projectedValues && typeof projectedValues === 'object' && !Array.isArray(projectedValues)) {`,
16036
+ ` const projectedRecord = projectedValues as Record<string, unknown>;`,
16037
+ ` if (part in projectedRecord) return { found: true, value: projectedRecord[part] };`,
16038
+ ` const projectedKey = __dlGetNormalizedKey(projectedRecord, part);`,
16039
+ ` if (projectedKey) return { found: true, value: __dlReadOwnField(projectedRecord, projectedKey) };`,
16040
+ ` }`,
16041
+ ` const data = record.data;`,
16042
+ ` if (data && typeof data === 'object' && !Array.isArray(data)) {`,
16043
+ ` const dataRecord = data as Record<string, unknown>;`,
16044
+ ` if (part in dataRecord) return { found: true, value: dataRecord[part] };`,
16045
+ ` const dataKey = __dlGetNormalizedKey(dataRecord, part);`,
16046
+ ` if (dataKey) return { found: true, value: __dlReadOwnField(dataRecord, dataKey) };`,
16047
+ ` }`,
16048
+ ` return { found: false, value: undefined };`,
16049
+ `}`,
16050
+ ``,
15850
16051
  `function __dlGetByPath(root: unknown, path: string): unknown {`,
15851
16052
  ` let cursor = root;`,
15852
16053
  ` for (const part of __dlPathParts(path)) {`,
15853
16054
  ` if (!cursor || typeof cursor !== 'object') return undefined;`,
15854
16055
  ` const record = cursor as Record<string, unknown>;`,
15855
- ` if (part in record) {`,
15856
- ` cursor = record[part];`,
15857
- ` continue;`,
15858
- ` }`,
15859
- ` const data = record.data;`,
15860
- ` cursor = data && typeof data === 'object' ? (data as Record<string, unknown>)[part] : undefined;`,
16056
+ ` const field = __dlGetRecordField(record, part);`,
16057
+ ` if (!field.found) return undefined;`,
16058
+ ` cursor = field.value;`,
15861
16059
  ` }`,
15862
16060
  ` return cursor;`,
15863
16061
  `}`,
@@ -15888,6 +16086,64 @@ function helperSource() {
15888
16086
  ` return status === 'error' || status === 'failed' || (typeof record.error === 'string' && record.error.trim() !== '') || (typeof resultError === 'string' && resultError.trim() !== '');`,
15889
16087
  `}`,
15890
16088
  ``,
16089
+ `function __dlGeneratedCellError(value: unknown): boolean {`,
16090
+ ` if (typeof value === 'string') {`,
16091
+ ` const lower = value.trim().toLowerCase();`,
16092
+ ` if (!lower) return false;`,
16093
+ ` if (lower.startsWith('error:') || lower.includes(': error:') || lower.includes('"error"')) return true;`,
16094
+ ` try {`,
16095
+ ` return __dlGeneratedCellError(JSON.parse(value));`,
16096
+ ` } catch {`,
16097
+ ` return false;`,
16098
+ ` }`,
16099
+ ` }`,
16100
+ ` if (!__dlRecord(value)) return false;`,
16101
+ ` const status = typeof value.status === 'string' ? value.status.toLowerCase() : '';`,
16102
+ ` if (status === 'error' || status === 'failed') return true;`,
16103
+ ` if (typeof value.error === 'string' && value.error.trim() !== '') return true;`,
16104
+ ` const raw = __dlGetByPath(value, 'toolResponse.raw') ?? __dlGetByPath(value, 'toolOutput.raw');`,
16105
+ ` if (raw !== undefined && raw !== value && __dlGeneratedCellError(raw)) return true;`,
16106
+ ` const result = value.result;`,
16107
+ ` return result !== undefined && result !== value && __dlGeneratedCellError(result);`,
16108
+ `}`,
16109
+ ``,
16110
+ `function __dlStripErroredGeneratedColumns(row: Record<string, unknown>, aliases: string[]): Record<string, unknown> {`,
16111
+ ` let next: Record<string, unknown> | null = null;`,
16112
+ ` for (const alias of aliases) {`,
16113
+ ` for (const key of __dlAliasCandidates(alias)) {`,
16114
+ ` if (key in row && __dlGeneratedCellError(row[key])) {`,
16115
+ ` if (next === null) next = { ...row };`,
16116
+ ` delete next[key];`,
16117
+ ` }`,
16118
+ ` }`,
16119
+ ` }`,
16120
+ ` return next ?? row;`,
16121
+ `}`,
16122
+ ``,
16123
+ `function __dlTemplateContext(row: Record<string, unknown>): Record<string, unknown> {`,
16124
+ ` const context: Record<string, unknown> = {};`,
16125
+ ` const projectedValues = row.__deeplineCsvProjectedValues;`,
16126
+ ` if (__dlRecord(projectedValues)) {`,
16127
+ ` for (const [key, value] of Object.entries(projectedValues)) context[key] = value;`,
16128
+ ` }`,
16129
+ ` for (const [key, value] of Object.entries(row)) {`,
16130
+ ` if (key.startsWith('__deepline')) continue;`,
16131
+ ` context[key] = value;`,
16132
+ ` }`,
16133
+ ` return context;`,
16134
+ `}`,
16135
+ ``,
16136
+ `function __dlPrepareEnrichRow(row: Record<string, unknown>, aliases: string[]): Record<string, unknown> {`,
16137
+ ` const cleaned = __dlStripErroredGeneratedColumns(row, aliases);`,
16138
+ ` const templateContext = __dlTemplateContext(cleaned);`,
16139
+ ` return {`,
16140
+ ` ...templateContext,`,
16141
+ ` ...cleaned,`,
16142
+ ` __deeplineCsvProjectedFields: Object.keys(templateContext),`,
16143
+ ` __deeplineCsvProjectedValues: templateContext,`,
16144
+ ` };`,
16145
+ `}`,
16146
+ ``,
15891
16147
  `function __dlRawToolOutput(result: unknown): unknown {`,
15892
16148
  ` if (!result || typeof result !== 'object') return result;`,
15893
16149
  ` const record = result as Record<string, unknown>;`,
@@ -16298,7 +16554,7 @@ function helperSource() {
16298
16554
  ` tool: input.tool,`,
16299
16555
  ` input: payload,`,
16300
16556
  ` ...(input.description ? { description: input.description } : {}),`,
16301
- ` ...(input.force ? { staleAfterSeconds: 1 } : {}),`,
16557
+ ` ...(input.force ? { force: true } : {}),`,
16302
16558
  ` });`,
16303
16559
  ` return __dlExtract(input.alias, result, input.row, input.extract, Boolean(input.legacyEnvelope));`,
16304
16560
  `}`
@@ -16925,7 +17181,7 @@ async function resolveWatchedGeneratedPlayStatus(input2) {
16925
17181
  }
16926
17182
  return input2.client.runs.get(runId, { full: true });
16927
17183
  }
16928
- function isRecord6(value) {
17184
+ function isRecord7(value) {
16929
17185
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
16930
17186
  }
16931
17187
  async function captureStdout(run, options = {}) {
@@ -16973,12 +17229,12 @@ async function writeOutputCsv(outputPath, status, options) {
16973
17229
  if (!rowsInfo) {
16974
17230
  throw new Error("The generated play did not return row-shaped output.");
16975
17231
  }
16976
- if (!rowsInfo.complete && options?.client) {
17232
+ if (options?.client) {
16977
17233
  rowsInfo = await fetchBackingRowsForCsvExport({
16978
17234
  client: options.client,
16979
17235
  status,
16980
17236
  rowsInfo
16981
- }) ?? rowsInfo;
17237
+ }).catch(() => null) ?? rowsInfo;
16982
17238
  }
16983
17239
  assertCompleteRowsForCsvExport(rowsInfo, status, outputPath);
16984
17240
  const merged = mergeRowsForCsvExport(rowsInfo.rows, options);
@@ -16994,10 +17250,14 @@ async function writeOutputCsv(outputPath, status, options) {
16994
17250
  csvStringFromRows(merged.rows, columns),
16995
17251
  "utf8"
16996
17252
  );
17253
+ const sourceCsvRows = options?.sourceCsvPath ? readCsvRows(options.sourceCsvPath).length : null;
16997
17254
  return {
17255
+ sourceCsvRows,
17256
+ selectedRows: rowsInfo.totalRows,
17257
+ enrichedRows: rowsInfo.rows.length,
16998
17258
  rows: merged.rows.length,
16999
17259
  path: resolve11(outputPath),
17000
- enrichedRows: rowsInfo.rows
17260
+ enrichedDataRows: rowsInfo.rows
17001
17261
  };
17002
17262
  }
17003
17263
  function recordField(value, key) {
@@ -17078,12 +17338,12 @@ function collectHardFailureAliases(config) {
17078
17338
  }
17079
17339
  function cellFailureError(value) {
17080
17340
  const parsed = parseMaybeJsonObject(value);
17081
- if (!isRecord6(parsed)) {
17341
+ if (!isRecord7(parsed)) {
17082
17342
  return null;
17083
17343
  }
17084
17344
  const status = typeof parsed.status === "string" ? parsed.status.trim().toLowerCase() : "";
17085
17345
  const directError = typeof parsed.error === "string" ? parsed.error.trim() : typeof parsed.last_error === "string" ? parsed.last_error.trim() : "";
17086
- const result = isRecord6(parsed.result) ? parsed.result : null;
17346
+ const result = isRecord7(parsed.result) ? parsed.result : null;
17087
17347
  const resultError = typeof result?.error === "string" ? result.error.trim() : typeof result?.message === "string" ? result.message.trim() : "";
17088
17348
  if (!directError && !resultError && status !== "error" && status !== "failed") {
17089
17349
  return null;
@@ -17149,6 +17409,136 @@ function collectEnrichFailureJobs(input2) {
17149
17409
  });
17150
17410
  return jobs;
17151
17411
  }
17412
+ function parseExecutionCount(value) {
17413
+ if (typeof value === "number" && Number.isFinite(value)) {
17414
+ return Math.max(0, Math.trunc(value));
17415
+ }
17416
+ if (typeof value !== "string") {
17417
+ return null;
17418
+ }
17419
+ const match = value.trim().match(/^(\d+)\s*\//);
17420
+ return match?.[1] ? Number.parseInt(match[1], 10) : null;
17421
+ }
17422
+ function executionSummaryText(count, total) {
17423
+ const percent = total > 0 ? Math.round(count / total * 100) : 0;
17424
+ return `${count}/${total} (${percent}%)`;
17425
+ }
17426
+ function collectColumnStats(status) {
17427
+ const summaries = [];
17428
+ const visit = (value) => {
17429
+ if (Array.isArray(value)) {
17430
+ value.forEach(visit);
17431
+ return;
17432
+ }
17433
+ if (!isRecord7(value)) {
17434
+ return;
17435
+ }
17436
+ if (isRecord7(value.columnStats)) {
17437
+ summaries.push(value.columnStats);
17438
+ }
17439
+ Object.values(value).forEach(visit);
17440
+ };
17441
+ visit(status);
17442
+ return summaries;
17443
+ }
17444
+ function firstAliasExecutionCounts(input2) {
17445
+ const aliases = collectConfigScalarAliasOrder(input2.config);
17446
+ const summaries = collectColumnStats(input2.status);
17447
+ for (const alias of aliases) {
17448
+ const stat4 = summaries.map((summary) => summary[alias]).find(isRecord7);
17449
+ if (!stat4) continue;
17450
+ if (input2.forceAliases.has(normalizeAlias2(alias))) {
17451
+ return { executed: input2.selectedRows, reused: 0 };
17452
+ }
17453
+ const execution = isRecord7(stat4.execution) ? stat4.execution : null;
17454
+ if (!execution) continue;
17455
+ return {
17456
+ executed: parseExecutionCount(execution["completed:executed"]),
17457
+ reused: parseExecutionCount(execution["completed:reused"])
17458
+ };
17459
+ }
17460
+ return { executed: null, reused: null };
17461
+ }
17462
+ function rewriteEnrichJsonStatus(input2) {
17463
+ const selectedRows = input2.output?.selectedRows ?? extractCanonicalRowsInfo(input2.status)?.totalRows ?? 0;
17464
+ const failedRows = new Set(
17465
+ input2.failureReport?.jobs.map((job) => job.row_id) ?? []
17466
+ ).size;
17467
+ const executionCounts = firstAliasExecutionCounts({
17468
+ status: input2.status,
17469
+ config: input2.config,
17470
+ forceAliases: input2.forceAliases,
17471
+ selectedRows
17472
+ });
17473
+ const forcedAliases = new Set(
17474
+ collectConfigScalarAliasOrder(input2.config).filter((alias) => input2.forceAliases.has(normalizeAlias2(alias))).map((alias) => alias)
17475
+ );
17476
+ const rewrite = (value) => {
17477
+ if (Array.isArray(value)) {
17478
+ return value.map(rewrite);
17479
+ }
17480
+ if (!isRecord7(value)) {
17481
+ return value;
17482
+ }
17483
+ const next = {};
17484
+ for (const [key, entry] of Object.entries(value)) {
17485
+ next[key] = rewrite(entry);
17486
+ }
17487
+ if (isRecord7(next.progress)) {
17488
+ next.progress = {
17489
+ ...next.progress,
17490
+ ...selectedRows > 0 ? { total: selectedRows } : {},
17491
+ ...executionCounts.executed !== null ? { executed: executionCounts.executed } : {},
17492
+ ...executionCounts.reused !== null ? { reused: executionCounts.reused } : {},
17493
+ ...failedRows > 0 ? { failed: failedRows, pending: 0 } : {}
17494
+ };
17495
+ }
17496
+ if (isRecord7(next.summary)) {
17497
+ const rowCounts = isRecord7(next.summary.rowCounts) ? next.summary.rowCounts : null;
17498
+ if (failedRows > 0) {
17499
+ next.summary = {
17500
+ ...next.summary,
17501
+ rowCounts: {
17502
+ ...rowCounts ?? {},
17503
+ persisted: selectedRows,
17504
+ succeeded: Math.max(0, selectedRows - failedRows),
17505
+ failed: failedRows
17506
+ }
17507
+ };
17508
+ }
17509
+ }
17510
+ if (isRecord7(next.columnStats) && selectedRows > 0) {
17511
+ const columnStats = { ...next.columnStats };
17512
+ for (const alias of forcedAliases) {
17513
+ const stat4 = isRecord7(columnStats[alias]) ? columnStats[alias] : null;
17514
+ const execution = isRecord7(stat4?.execution) ? stat4.execution : null;
17515
+ if (!stat4 || !execution) continue;
17516
+ columnStats[alias] = {
17517
+ ...stat4,
17518
+ execution: {
17519
+ ...execution,
17520
+ "completed:executed": executionSummaryText(
17521
+ selectedRows,
17522
+ selectedRows
17523
+ ),
17524
+ "completed:reused": executionSummaryText(0, selectedRows)
17525
+ }
17526
+ };
17527
+ }
17528
+ next.columnStats = columnStats;
17529
+ }
17530
+ return next;
17531
+ };
17532
+ const rewritten = rewrite(input2.status);
17533
+ if (failedRows === 0 || !isRecord7(rewritten)) {
17534
+ return rewritten;
17535
+ }
17536
+ return {
17537
+ ...rewritten,
17538
+ ...rewritten.status === "completed" ? { status: "failed" } : {},
17539
+ ...isRecord7(rewritten.run) && rewritten.run.status === "completed" ? { run: { ...rewritten.run, status: "failed" } } : {}
17540
+ };
17541
+ }
17152
17542
  function summarizeFailedJobError(value) {
17153
17543
  const text = String(value ?? "").trim();
17154
17544
  return text.length > 500 ? `${text.slice(0, 497)}...` : text;
@@ -17417,11 +17807,11 @@ function normalizeEnrichRowsForCsvExport(rows) {
17417
17807
  }
17418
17808
  function legacyMetadataFromRow(row) {
17419
17809
  const direct = parseLegacyMetadataCell(row._metadata);
17420
- if (direct && isRecord6(direct.columns)) {
17810
+ if (direct && isRecord7(direct.columns)) {
17421
17811
  return direct;
17422
17812
  }
17423
17813
  const relocated = parseLegacyMetadataCell(row.metadata);
17424
- if (relocated && isRecord6(relocated.columns)) {
17814
+ if (relocated && isRecord7(relocated.columns)) {
17425
17815
  return relocated;
17426
17816
  }
17427
17817
  const flattenedColumns = parseLegacyMetadataCell(row["metadata.columns"]);
@@ -17438,7 +17828,7 @@ function legacyMetadataFromRow(row) {
17438
17828
  }
17439
17829
  function parseLegacyMetadataCell(value) {
17440
17830
  const parsed = parseMaybeJsonObject(value);
17441
- if (isRecord6(parsed)) {
17831
+ if (isRecord7(parsed)) {
17442
17832
  return parsed;
17443
17833
  }
17444
17834
  if (typeof value !== "string") {
@@ -17455,12 +17845,12 @@ function parseLegacyMetadataCell(value) {
17455
17845
  for (const candidate of candidates) {
17456
17846
  try {
17457
17847
  const decoded = JSON.parse(candidate);
17458
- if (isRecord6(decoded)) {
17848
+ if (isRecord7(decoded)) {
17459
17849
  return decoded;
17460
17850
  }
17461
17851
  if (typeof decoded === "string") {
17462
17852
  const nested = JSON.parse(decoded);
17463
- if (isRecord6(nested)) {
17853
+ if (isRecord7(nested)) {
17464
17854
  return nested;
17465
17855
  }
17466
17856
  }
@@ -17470,8 +17860,8 @@ function parseLegacyMetadataCell(value) {
17470
17860
  return null;
17471
17861
  }
17472
17862
  function mergeLegacyMetadataRecords(base, enriched) {
17473
- const baseColumns = isRecord6(base.columns) ? base.columns : null;
17474
- const enrichedColumns = isRecord6(enriched.columns) ? enriched.columns : null;
17863
+ const baseColumns = isRecord7(base.columns) ? base.columns : null;
17864
+ const enrichedColumns = isRecord7(enriched.columns) ? enriched.columns : null;
17475
17865
  const merged = {
17476
17866
  ...base,
17477
17867
  ...enriched
@@ -17673,7 +18063,7 @@ function registerEnrichCommand(program) {
17673
18063
  sourceCsvPath,
17674
18064
  rows
17675
18065
  }) : null;
17676
- const rowsForFailureReport = exportResult?.enrichedRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
18066
+ const rowsForFailureReport = exportResult?.enrichedDataRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
17677
18067
  if (options.json) {
17678
18068
  const failureReport2 = await maybeEmitEnrichFailureReport({
17679
18069
  config,
@@ -17682,10 +18072,22 @@ function registerEnrichCommand(program) {
17682
18072
  client: client2,
17683
18073
  outputPath: exportResult?.path ?? outputPath ?? null
17684
18074
  });
18075
+ const run = rewriteEnrichJsonStatus({
18076
+ status,
18077
+ config,
18078
+ forceAliases,
18079
+ output: exportResult,
18080
+ failureReport: failureReport2
18081
+ });
17685
18082
  printJson({
17686
18083
  ok: !failureReport2,
17687
- run: status,
17688
- output: exportResult ? { rows: exportResult.rows, path: exportResult.path } : null,
18084
+ run,
18085
+ output: exportResult ? {
18086
+ sourceCsvRows: exportResult.sourceCsvRows,
18087
+ selectedRows: exportResult.selectedRows,
18088
+ enrichedRows: exportResult.enrichedRows,
18089
+ path: exportResult.path
18090
+ } : null,
17689
18091
  ...failureReport2 ? {
17690
18092
  failure_report: {
17691
18093
  path: failureReport2.path,
@@ -17705,7 +18107,7 @@ function registerEnrichCommand(program) {
17705
18107
  );
17706
18108
  const waterfallSummaryLines = buildEnrichWaterfallSummaryLines(
17707
18109
  config,
17708
- exportResult.enrichedRows
18110
+ exportResult.enrichedDataRows
17709
18111
  );
17710
18112
  if (waterfallSummaryLines.length > 0) {
17711
18113
  process.stdout.write(`${waterfallSummaryLines.join("\n")}
@@ -17772,6 +18174,129 @@ Examples:
17772
18174
  ).argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
17773
18175
  }
17774
18176
 
18177
+ // src/cli/commands/legacy-noops.ts
18178
+ var SESSION_SUBCOMMANDS = [
18179
+ "start",
18180
+ "status",
18181
+ "output",
18182
+ "alert",
18183
+ "usage",
18184
+ "limit",
18185
+ "render",
18186
+ "send"
18187
+ ];
18188
+ var BACKEND_SUBCOMMANDS = [
18189
+ "start",
18190
+ "stop",
18191
+ "status",
18192
+ "refresh-runtime",
18193
+ "sync-runtime"
18194
+ ];
18195
+ function legacyNoopEnvelope(input2) {
18196
+ const command = [
18197
+ "deepline",
18198
+ input2.family,
18199
+ input2.subcommand
18200
+ ].filter(Boolean).join(" ");
18201
+ const subject = input2.family === "session" ? "Legacy Session UI/playground command" : "Legacy local playground backend command";
18202
+ const note = input2.family === "session" ? "The SDK CLI does not manage the legacy Python Session UI. This command is accepted for backwards compatibility and intentionally does nothing." : "The SDK CLI does not start or stop the legacy Python local playground backend. This command is accepted for backwards compatibility and intentionally does nothing.";
18203
+ return {
18204
+ ok: true,
18205
+ noop: true,
18206
+ command,
18207
+ compatibility: {
18208
+ family: "legacy_python_cli",
18209
+ sdk_behavior: "noop"
18210
+ },
18211
+ render: {
18212
+ sections: [
18213
+ {
18214
+ title: subject,
18215
+ lines: [note]
18216
+ }
18217
+ ]
18218
+ }
18219
+ };
18220
+ }
18221
+ function printLegacyNoop(input2) {
18222
+ printCommandEnvelope(legacyNoopEnvelope(input2), { json: input2.options.json });
18223
+ }
18224
+ function legacySubcommandFromArgv(family) {
18225
+ const args = process.argv.slice(2);
18226
+ const familyIndex = args.indexOf(family);
18227
+ const nextToken = familyIndex >= 0 ? args[familyIndex + 1] : void 0;
18228
+ return nextToken && !nextToken.startsWith("-") ? nextToken : void 0;
18229
+ }
18230
+ function addLegacyNoopSubcommand(parent, family, subcommand, description) {
18231
+ parent.command(subcommand).description(description).allowUnknownOption(true).allowExcessArguments(true).option("--json", "Emit JSON output").argument("[args...]").action((_args, options) => {
18232
+ printLegacyNoop({ family, subcommand, options });
18233
+ });
18234
+ }
18235
+ function registerLegacyNoopCommands(program) {
18236
+ const session = program.command("session").description(
18237
+ "Compatibility no-ops for legacy Python Session UI commands."
18238
+ ).allowUnknownOption(true).allowExcessArguments(true).option("--json", "Emit JSON output").argument("[args...]").addHelpText(
18239
+ "after",
18240
+ `
18241
+ Notes:
18242
+ The SDK CLI accepts singular session commands from older agent skills so they
18243
+ do not fail, but it does not manage the legacy Python Session UI.
18244
+ Use "deepline sessions send" or "deepline sessions render" for real SDK
18245
+ transcript workflows.
18246
+
18247
+ Examples:
18248
+ deepline session start --steps '["Inspect CSV","Run pilot"]'
18249
+ deepline session status --message "Running pilot"
18250
+ deepline session output --csv ./results.csv --label "Results"
18251
+ `
18252
+ ).action((args, options) => {
18253
+ void args;
18254
+ printLegacyNoop({
18255
+ family: "session",
18256
+ subcommand: legacySubcommandFromArgv("session"),
18257
+ options
18258
+ });
18259
+ });
18260
+ for (const subcommand of SESSION_SUBCOMMANDS) {
18261
+ addLegacyNoopSubcommand(
18262
+ session,
18263
+ "session",
18264
+ subcommand,
18265
+ `Accept legacy "deepline session ${subcommand}" as an SDK no-op.`
18266
+ );
18267
+ }
18268
+ const backend = program.command("backend").description(
18269
+ "Compatibility no-ops for legacy Python local backend commands."
18270
+ ).allowUnknownOption(true).allowExcessArguments(true).option("--json", "Emit JSON output").argument("[args...]").addHelpText(
18271
+ "after",
18272
+ `
18273
+ Notes:
18274
+ The SDK CLI uses the configured Deepline host and V2 play runtime. It does not
18275
+ start, stop, or refresh the legacy Python local playground backend.
18276
+
18277
+ Examples:
18278
+ deepline backend start
18279
+ deepline backend stop --just-backend
18280
+ deepline backend status --json
18281
+ `
18282
+ ).action((args, options) => {
18283
+ void args;
18284
+ printLegacyNoop({
18285
+ family: "backend",
18286
+ subcommand: legacySubcommandFromArgv("backend"),
18287
+ options
18288
+ });
18289
+ });
18290
+ for (const subcommand of BACKEND_SUBCOMMANDS) {
18291
+ addLegacyNoopSubcommand(
18292
+ backend,
18293
+ "backend",
18294
+ subcommand,
18295
+ `Accept legacy "deepline backend ${subcommand}" as an SDK no-op.`
18296
+ );
18297
+ }
18298
+ }
18299
+
17775
18300
  // src/cli/commands/org.ts
17776
18301
  async function fetchOrganizations(http, apiKey) {
17777
18302
  return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
@@ -19687,11 +20212,13 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
19687
20212
  "deeplineUsdPerPricingUnit",
19688
20213
  "deepline_usd_per_pricing_unit"
19689
20214
  );
19690
- const starterScript = seedToolListScript({
19691
- toolId,
19692
- payload: samplePayloadForInputFields(inputFields),
19693
- rows: []
19694
- });
20215
+ const starterScript = extractedLists.length > 0 ? starterScriptJson(
20216
+ seedToolListScript({
20217
+ toolId,
20218
+ payload: samplePayloadForInputFields(inputFields),
20219
+ rows: []
20220
+ })
20221
+ ) : null;
19695
20222
  return {
19696
20223
  schemaVersion: 1,
19697
20224
  toolId,
@@ -19717,20 +20244,12 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
19717
20244
  extractedValues
19718
20245
  },
19719
20246
  executeCommand: `deepline tools execute ${toolId} --input '{...}' --json`,
19720
- starterScript: {
19721
- path: starterScript.path,
19722
- sourceCode: starterScript.sourceCode,
19723
- projectDir: starterScript.projectDir,
19724
- copyToProject: {
19725
- macosLinux: starterScript.macCopyCommand,
19726
- windowsPowerShell: starterScript.windowsCopyCommand
19727
- }
19728
- }
20247
+ ...starterScript ? { starterScript } : {}
19729
20248
  };
19730
20249
  }
19731
20250
  function extractionContractEntries(entries) {
19732
20251
  return entries.flatMap((entry) => {
19733
- if (!isRecord7(entry)) return [];
20252
+ if (!isRecord8(entry)) return [];
19734
20253
  const name = stringField(entry, "name");
19735
20254
  const expression = stringField(entry, "expression");
19736
20255
  return name && expression ? [{ name, expression }] : [];
@@ -19738,8 +20257,8 @@ function extractionContractEntries(entries) {
19738
20257
  }
19739
20258
  function printCompactToolContract(tool, requestedToolId) {
19740
20259
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
19741
- const cost = isRecord7(contract.cost) ? contract.cost : {};
19742
- const getters = isRecord7(contract.getters) ? contract.getters : {};
20260
+ const cost = isRecord8(contract.cost) ? contract.cost : {};
20261
+ const getters = isRecord8(contract.getters) ? contract.getters : {};
19743
20262
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
19744
20263
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
19745
20264
  const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
@@ -19756,7 +20275,7 @@ function printCompactToolContract(tool, requestedToolId) {
19756
20275
  console.log("");
19757
20276
  console.log("Inputs:");
19758
20277
  for (const field of inputFields) {
19759
- if (!isRecord7(field)) continue;
20278
+ if (!isRecord8(field)) continue;
19760
20279
  const name = stringField(field, "name");
19761
20280
  if (!name) continue;
19762
20281
  const required = field.required ? "*" : "";
@@ -19769,7 +20288,7 @@ function printCompactToolContract(tool, requestedToolId) {
19769
20288
  }
19770
20289
  console.log("");
19771
20290
  printToolExamplesOnly(tool, requestedToolId, { includeSamples: false });
19772
- const starterScript = isRecord7(contract.starterScript) ? contract.starterScript : {};
20291
+ const starterScript = isRecord8(contract.starterScript) ? contract.starterScript : {};
19773
20292
  const starterPath = stringField(starterScript, "path");
19774
20293
  if (starterPath) {
19775
20294
  console.log("");
@@ -19783,14 +20302,14 @@ function printCompactToolContract(tool, requestedToolId) {
19783
20302
  console.log("Getters:");
19784
20303
  if (listGetters.length) console.log("Lists:");
19785
20304
  for (const entry of listGetters) {
19786
- if (isRecord7(entry))
20305
+ if (isRecord8(entry))
19787
20306
  console.log(
19788
20307
  `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
19789
20308
  );
19790
20309
  }
19791
20310
  if (valueGetters.length) console.log("Values:");
19792
20311
  for (const entry of valueGetters) {
19793
- if (isRecord7(entry))
20312
+ if (isRecord8(entry))
19794
20313
  console.log(
19795
20314
  `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
19796
20315
  );
@@ -19803,7 +20322,7 @@ function printCompactToolContract(tool, requestedToolId) {
19803
20322
  }
19804
20323
  function printToolPricingOnly(tool, requestedToolId, options = {}) {
19805
20324
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
19806
- const cost = isRecord7(contract.cost) ? contract.cost : {};
20325
+ const cost = isRecord8(contract.cost) ? contract.cost : {};
19807
20326
  const pricingModel = stringField(cost, "pricingModel") || "unknown";
19808
20327
  const billingMode = stringField(cost, "billingMode") || "unknown";
19809
20328
  const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : pricingModel === "fixed" ? "call" : pricingModel.replace(/^per_/, "") || "unit";
@@ -19823,7 +20342,7 @@ function printToolSchemaOnly(tool, requestedToolId) {
19823
20342
  }
19824
20343
  console.log("Inputs:");
19825
20344
  for (const field of inputFields) {
19826
- if (!isRecord7(field)) continue;
20345
+ if (!isRecord8(field)) continue;
19827
20346
  const name = stringField(field, "name");
19828
20347
  if (!name) continue;
19829
20348
  const required = field.required ? "*" : "";
@@ -19849,10 +20368,10 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
19849
20368
  ` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`
19850
20369
  );
19851
20370
  console.log("});");
19852
- const getters = isRecord7(contract.getters) ? contract.getters : {};
20371
+ const getters = isRecord8(contract.getters) ? contract.getters : {};
19853
20372
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
19854
20373
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
19855
- const firstGetter = [...valueGetters, ...listGetters].find(isRecord7);
20374
+ const firstGetter = [...valueGetters, ...listGetters].find(isRecord8);
19856
20375
  if (firstGetter) {
19857
20376
  const name = stringField(firstGetter, "name") || "value";
19858
20377
  const expression = stringField(firstGetter, "expression");
@@ -19869,7 +20388,7 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
19869
20388
  }
19870
20389
  function printToolGettersOnly(tool, requestedToolId) {
19871
20390
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
19872
- const getters = isRecord7(contract.getters) ? contract.getters : {};
20391
+ const getters = isRecord8(contract.getters) ? contract.getters : {};
19873
20392
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
19874
20393
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
19875
20394
  console.log(`Getters: ${contract.toolId}`);
@@ -19882,7 +20401,7 @@ function printToolGettersOnly(tool, requestedToolId) {
19882
20401
  if (listGetters.length) {
19883
20402
  console.log("Lists:");
19884
20403
  for (const entry of listGetters) {
19885
- if (isRecord7(entry))
20404
+ if (isRecord8(entry))
19886
20405
  console.log(
19887
20406
  `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
19888
20407
  );
@@ -19891,7 +20410,7 @@ function printToolGettersOnly(tool, requestedToolId) {
19891
20410
  if (valueGetters.length) {
19892
20411
  console.log("Values:");
19893
20412
  for (const entry of valueGetters) {
19894
- if (isRecord7(entry))
20413
+ if (isRecord8(entry))
19895
20414
  console.log(
19896
20415
  `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
19897
20416
  );
@@ -19917,7 +20436,7 @@ function sampleValueForField(field) {
19917
20436
  function samplePayloadForInputFields(fields) {
19918
20437
  return Object.fromEntries(
19919
20438
  fields.slice(0, 4).flatMap((field) => {
19920
- if (!isRecord7(field)) return [];
20439
+ if (!isRecord8(field)) return [];
19921
20440
  const name = stringField(field, "name");
19922
20441
  if (!name) return [];
19923
20442
  return [[name, sampleValueForField(field)]];
@@ -19942,11 +20461,24 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
19942
20461
  const inputFields = toolInputFieldsForDisplay(
19943
20462
  recordField2(tool, "inputSchema", "input_schema")
19944
20463
  );
19945
- const starterScript = seedToolListScript({
19946
- toolId,
19947
- payload: samplePayloadForInputFields(inputFields),
19948
- rows: []
19949
- });
20464
+ const usageGuidance = usageGuidanceWithAccessDefaults(
20465
+ recordField2(tool, "usageGuidance", "usage_guidance")
20466
+ );
20467
+ const toolExecutionResult = recordField2(
20468
+ usageGuidance,
20469
+ "toolExecutionResult",
20470
+ "tool_execution_result"
20471
+ );
20472
+ const extractedLists = extractionContractEntries(
20473
+ arrayField(toolExecutionResult, "extractedLists", "extracted_lists")
20474
+ );
20475
+ const starterScript = extractedLists.length > 0 ? starterScriptJson(
20476
+ seedToolListScript({
20477
+ toolId,
20478
+ payload: samplePayloadForInputFields(inputFields),
20479
+ rows: []
20480
+ })
20481
+ ) : null;
19950
20482
  const {
19951
20483
  cost: _cost,
19952
20484
  deeplineCreditsPerPricingUnit: _deeplineCreditsPerPricingUnit,
@@ -19966,9 +20498,7 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
19966
20498
  toolId,
19967
20499
  provider: tool.provider,
19968
20500
  displayName: tool.displayName,
19969
- usageGuidance: usageGuidanceWithAccessDefaults(
19970
- recordField2(tool, "usageGuidance", "usage_guidance")
19971
- ),
20501
+ usageGuidance,
19972
20502
  runtimeOutputHelp: {
19973
20503
  contract: "tools describe shows declared schema and Deepline getters; it is not an observed provider response.",
19974
20504
  getterScope: "extractedValues/extractedLists .get() only works for declared Deepline getters listed in usageGuidance.toolExecutionResult.",
@@ -19979,15 +20509,7 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
19979
20509
  forPlayGetterBugs: "Run a tiny play, inspect `deepline runs get <run-id> --full --json`, and export returned dataset handles with `deepline runs export`. Backing tables exist only for ctx.map(...).run(...) stages that actually executed.",
19980
20510
  executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run output and returned dataset handles."
19981
20511
  },
19982
- starterScript: {
19983
- path: starterScript.path,
19984
- sourceCode: starterScript.sourceCode,
19985
- projectDir: starterScript.projectDir,
19986
- copyToProject: {
19987
- macosLinux: starterScript.macCopyCommand,
19988
- windowsPowerShell: starterScript.windowsCopyCommand
19989
- }
19990
- }
20512
+ ...starterScript ? { starterScript } : {}
19991
20513
  };
19992
20514
  }
19993
20515
  function usageGuidanceWithAccessDefaults(usageGuidance) {
@@ -20031,12 +20553,12 @@ function formatListedToolCost(tool) {
20031
20553
  }
20032
20554
  function toolInputFieldsForDisplay(inputSchema) {
20033
20555
  if (Array.isArray(inputSchema.fields))
20034
- return inputSchema.fields.filter(isRecord7);
20035
- const jsonSchema = isRecord7(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
20036
- const properties = isRecord7(jsonSchema.properties) ? jsonSchema.properties : {};
20556
+ return inputSchema.fields.filter(isRecord8);
20557
+ const jsonSchema = isRecord8(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
20558
+ const properties = isRecord8(jsonSchema.properties) ? jsonSchema.properties : {};
20037
20559
  const required = Array.isArray(jsonSchema.required) ? new Set(jsonSchema.required.map(String)) : /* @__PURE__ */ new Set();
20038
20560
  return Object.entries(properties).map(([name, value]) => {
20039
- const property = isRecord7(value) ? value : {};
20561
+ const property = isRecord8(value) ? value : {};
20040
20562
  return {
20041
20563
  name,
20042
20564
  type: typeof property.type === "string" ? property.type : "unknown",
@@ -20065,15 +20587,15 @@ function printJsonPreview(label, payload) {
20065
20587
  }
20066
20588
  function samplePayload(samples, key) {
20067
20589
  const entry = samples[key];
20068
- if (!isRecord7(entry)) return void 0;
20590
+ if (!isRecord8(entry)) return void 0;
20069
20591
  return Object.prototype.hasOwnProperty.call(entry, "payload") ? entry.payload : entry;
20070
20592
  }
20071
20593
  function commandEnvelopeFromRawResponse(rawResponse) {
20072
- return isRecord7(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
20594
+ return isRecord8(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
20073
20595
  }
20074
20596
  function listExtractorPathsFromUsageGuidance(tool) {
20075
20597
  const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
20076
- const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord7(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
20598
+ const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord8(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
20077
20599
  return extractedLists.flatMap((entry) => {
20078
20600
  const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
20079
20601
  if (!Array.isArray(paths)) return [];
@@ -20089,7 +20611,7 @@ function formatDecimal(value) {
20089
20611
  function formatUsd(value) {
20090
20612
  return `$${formatDecimal(value)}`;
20091
20613
  }
20092
- function isRecord7(value) {
20614
+ function isRecord8(value) {
20093
20615
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
20094
20616
  }
20095
20617
  function stringField(source, ...keys) {
@@ -20116,7 +20638,7 @@ function arrayField(source, ...keys) {
20116
20638
  function recordField2(source, ...keys) {
20117
20639
  for (const key of keys) {
20118
20640
  const value = source[key];
20119
- if (isRecord7(value)) return value;
20641
+ if (isRecord8(value)) return value;
20120
20642
  }
20121
20643
  return {};
20122
20644
  }
@@ -20182,7 +20704,7 @@ function parseJsonObjectArgument(raw, flagName) {
20182
20704
  }
20183
20705
  throw invalidJsonError(flagName, message);
20184
20706
  }
20185
- if (!isRecord7(parsed)) {
20707
+ if (!isRecord8(parsed)) {
20186
20708
  throw invalidJsonError(flagName, "expected an object.");
20187
20709
  }
20188
20710
  return parsed;
@@ -20241,6 +20763,17 @@ function shellQuote2(value) {
20241
20763
  function powerShellQuote(value) {
20242
20764
  return `'${value.replace(/'/g, "''")}'`;
20243
20765
  }
20766
+ function starterScriptJson(script) {
20767
+ return {
20768
+ path: script.path,
20769
+ sourceCode: script.sourceCode,
20770
+ projectDir: script.projectDir,
20771
+ copyToProject: {
20772
+ macosLinux: script.macCopyCommand,
20773
+ windowsPowerShell: script.windowsCopyCommand
20774
+ }
20775
+ };
20776
+ }
20244
20777
  function seedToolListScript(input2) {
20245
20778
  const stem = safeFileStem(input2.toolId);
20246
20779
  const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
@@ -20305,7 +20838,7 @@ function buildToolExecuteBaseEnvelope(input2) {
20305
20838
  kind: summaryEntries.length > 0 ? "object" : "raw",
20306
20839
  summary: input2.summary
20307
20840
  };
20308
- const envelopeHasCanonicalOutput = isRecord7(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
20841
+ const envelopeHasCanonicalOutput = isRecord8(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
20309
20842
  const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote2(JSON.stringify(input2.params))} --json`;
20310
20843
  const actions = input2.listConversion ? [
20311
20844
  {
@@ -20414,7 +20947,7 @@ async function executeTool(args) {
20414
20947
  {
20415
20948
  ...baseEnvelope,
20416
20949
  local: {
20417
- ...isRecord7(baseEnvelope.local) ? baseEnvelope.local : {},
20950
+ ...isRecord8(baseEnvelope.local) ? baseEnvelope.local : {},
20418
20951
  payload_file: jsonPath
20419
20952
  }
20420
20953
  },
@@ -21174,10 +21707,6 @@ var command_compatibility_default = {
21174
21707
  label: "a legacy Python CLI workflow command",
21175
21708
  sdk_alternative: "Use `deepline plays ...` in the SDK CLI."
21176
21709
  },
21177
- backend: {
21178
- family: "python",
21179
- label: "a legacy Python CLI playground backend command"
21180
- },
21181
21710
  events: {
21182
21711
  family: "python",
21183
21712
  label: "a legacy Python CLI event command"
@@ -21413,7 +21942,11 @@ import { homedir as homedir7 } from "os";
21413
21942
  import { dirname as dirname12, join as join14 } from "path";
21414
21943
  var CHECK_TIMEOUT_MS2 = 3e3;
21415
21944
  var SDK_SKILL_NAME = "deepline-plays";
21416
- var SDK_SKILL_NAMES = [SDK_SKILL_NAME, "deepline-plays-quickstart"];
21945
+ var SDK_SKILL_NAMES = [
21946
+ SDK_SKILL_NAME,
21947
+ "deepline-plays-feedback",
21948
+ "deepline-plays-quickstart"
21949
+ ];
21417
21950
  var attemptedSync = false;
21418
21951
  function shouldSkipSkillsSync() {
21419
21952
  const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
@@ -21635,7 +22168,9 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
21635
22168
  if (!update?.needsUpdate && !hasStaleInstalledSkill || !update?.remoteVersion) {
21636
22169
  return;
21637
22170
  }
21638
- writeSdkSkillsStatusLine("SDK skills changed; syncing Deepline SDK skills...");
22171
+ writeSdkSkillsStatusLine(
22172
+ "SDK skills changed; syncing Deepline SDK skills..."
22173
+ );
21639
22174
  const installed = await runSkillsInstall(baseUrl);
21640
22175
  if (!installed) return;
21641
22176
  if (installedSdkSkillHasStalePositionalExecuteExamples()) {
@@ -21675,6 +22210,19 @@ function shouldDeferSkillsSyncForCommand() {
21675
22210
  const subcommand = args[1];
21676
22211
  return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
21677
22212
  }
22213
+ function isLegacyNoopInvocation() {
22214
+ const command = process.argv.slice(2)[0];
22215
+ return command === "session" || command === "backend";
22216
+ }
22217
+ function topLevelCommandKnown(program, commandName) {
22218
+ const normalized = commandName.trim();
22219
+ if (!normalized || normalized.startsWith("-")) {
22220
+ return true;
22221
+ }
22222
+ return program.commands.some(
22223
+ (command) => command.name() === normalized || command.aliases().includes(normalized)
22224
+ );
22225
+ }
21678
22226
  async function runPlayRunnerHealthCheck() {
21679
22227
  const dir = await mkdtemp2(join15(tmpdir5(), "deepline-health-play-"));
21680
22228
  const file = join15(dir, "health-check.play.ts");
@@ -21894,7 +22442,7 @@ Exit codes:
21894
22442
  `
21895
22443
  );
21896
22444
  program.hook("preAction", async (_thisCommand, actionCommand) => {
21897
- if (actionCommand.name() === "version" || actionCommand.name() === "update") {
22445
+ if (actionCommand.name() === "version" || actionCommand.name() === "update" || isLegacyNoopInvocation()) {
21898
22446
  return;
21899
22447
  }
21900
22448
  if (printStartupPhase) {
@@ -21911,9 +22459,7 @@ Exit codes:
21911
22459
  if (compatibility.error) {
21912
22460
  return;
21913
22461
  }
21914
- const relaunched = await maybeAutoUpdateAndRelaunch(
21915
- compatibility.response
21916
- );
22462
+ const relaunched = await maybeAutoUpdateAndRelaunch(compatibility.response);
21917
22463
  if (relaunched) {
21918
22464
  return;
21919
22465
  }
@@ -21941,6 +22487,7 @@ Exit codes:
21941
22487
  registerCsvCommands(program);
21942
22488
  registerDbCommands(program);
21943
22489
  registerFeedbackCommands(program);
22490
+ registerLegacyNoopCommands(program);
21944
22491
  registerUpdateCommand(program);
21945
22492
  registerQuickstartCommands(program);
21946
22493
  program.command("preflight").description("Run compact health, auth, and Deepline billing checks.").option("--json", "Force JSON output.").addHelpText(
@@ -22041,6 +22588,20 @@ Examples:
22041
22588
  process.exitCode = 2;
22042
22589
  return;
22043
22590
  }
22591
+ const requestedTopLevelCommand = process.argv.slice(2)[0] ?? "";
22592
+ if (!topLevelCommandKnown(program, requestedTopLevelCommand)) {
22593
+ console.error(`error: unknown command '${requestedTopLevelCommand}'`);
22594
+ const hint = commandCompatibilityHint(
22595
+ "sdk",
22596
+ requestedTopLevelCommand,
22597
+ autoDetectBaseUrl()
22598
+ );
22599
+ if (hint && !process.argv.includes("--json")) {
22600
+ console.error(hint);
22601
+ }
22602
+ process.exitCode = 2;
22603
+ return;
22604
+ }
22044
22605
  try {
22045
22606
  await program.parseAsync(process.argv);
22046
22607
  recordCliTrace({