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
package/dist/cli/index.js CHANGED
@@ -238,22 +238,24 @@ var SDK_RELEASE = {
238
238
  // preflight (existence, data rows, quotes, duplicate headers), HTML error
239
239
  // scrubbing, and word-boundary watch truncation.
240
240
  // 0.1.103 ships the refined SDK CLI command surface.
241
- // 0.1.104 ships postgres_fast suspension/billing parity and runtime worker hardening.
241
+ // 0.1.104 shipped the retired Postgres scheduler suspension/billing parity and runtime worker hardening.
242
242
  // 0.1.105 ships the billing catalog surface: billing plans, subscribe,
243
243
  // subscription status/cancel, invoices, and the client.billing namespace.
244
244
  // 0.1.106 ships play cell provenance metadata and v2 preview retry hardening.
245
245
  // 0.1.107 ships the v2 quickstart command, the deepline-plays-quickstart
246
246
  // skill on the sdk sync surface, and the people-search-to-email prebuilt.
247
- version: "0.1.107",
247
+ // 0.1.108 ships explicit dataset column/tool recompute policy and removes
248
+ // the SDK enrich generator's one-second stale policy.
249
+ version: "0.1.109",
248
250
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
249
251
  supportPolicy: {
250
- latest: "0.1.107",
252
+ latest: "0.1.109",
251
253
  minimumSupported: "0.1.53",
252
254
  deprecatedBelow: "0.1.53",
253
255
  commandMinimumSupported: [
254
256
  {
255
257
  command: "enrich",
256
- minimumSupported: "0.1.106",
258
+ minimumSupported: "0.1.108",
257
259
  reason: "Older SDK CLI enrich generated stale play source for the current dataset API."
258
260
  }
259
261
  ],
@@ -269,6 +271,7 @@ var SDK_API_CONTRACT = SDK_RELEASE.apiContract;
269
271
  var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
270
272
  var COORDINATOR_URL_OVERRIDE_HEADER = "x-deepline-coordinator-url";
271
273
  var WORKER_CALLBACK_URL_OVERRIDE_HEADER = "x-deepline-worker-callback-url";
274
+ var RUNTIME_SCHEDULER_SCHEMA_OVERRIDE_HEADER = "x-deepline-runtime-scheduler-schema";
272
275
  var SYNTHETIC_RUN_HEADER = "x-deepline-synthetic-run";
273
276
 
274
277
  // src/http.ts
@@ -337,6 +340,10 @@ var HttpClient = class {
337
340
  if (workerCallbackUrl?.trim()) {
338
341
  headers[WORKER_CALLBACK_URL_OVERRIDE_HEADER] = workerCallbackUrl.trim();
339
342
  }
343
+ const runtimeSchedulerSchema = typeof process !== "undefined" ? process.env?.DEEPLINE_RUNTIME_SCHEDULER_SCHEMA : void 0;
344
+ if (runtimeSchedulerSchema?.trim()) {
345
+ headers[RUNTIME_SCHEDULER_SCHEMA_OVERRIDE_HEADER] = runtimeSchedulerSchema.trim();
346
+ }
340
347
  const syntheticRun = typeof process !== "undefined" ? process.env?.DEEPLINE_SYNTHETIC_RUN : void 0;
341
348
  if (syntheticRun && syntheticRun.trim() && syntheticRun.trim() !== "0") {
342
349
  headers[SYNTHETIC_RUN_HEADER] = "1";
@@ -543,8 +550,19 @@ var HttpClient = class {
543
550
  headers
544
551
  });
545
552
  }
553
+ /**
554
+ * Send a PATCH request with a JSON body.
555
+ *
556
+ * @typeParam T - Expected response body type
557
+ * @param path - API path
558
+ * @param body - JSON-serializable request body
559
+ */
546
560
  async patch(path, body, headers) {
547
- return this.request(path, { method: "PATCH", body, headers });
561
+ return this.request(path, {
562
+ method: "PATCH",
563
+ body,
564
+ headers
565
+ });
548
566
  }
549
567
  /**
550
568
  * Send a DELETE request.
@@ -857,6 +875,8 @@ function normalizeStepProgress(value) {
857
875
  value.artifactTableNamespace
858
876
  )
859
877
  } : {},
878
+ ...finiteNumber(value.startedAt) !== null ? { startedAt: finiteNumber(value.startedAt) } : {},
879
+ ...finiteNumber(value.completedAt) !== null ? { completedAt: finiteNumber(value.completedAt) } : {},
860
880
  ...finiteNumber(value.updatedAt) !== null ? { updatedAt: finiteNumber(value.updatedAt) } : {}
861
881
  };
862
882
  }
@@ -893,6 +913,35 @@ function normalizePlayRunLiveStatus(value) {
893
913
  function isTerminalPlayRunLiveStatus(status) {
894
914
  return status === "completed" || status === "failed" || status === "cancelled" || status === "terminated" || status === "timed_out";
895
915
  }
916
+ function isRecord2(value) {
917
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
918
+ }
919
+ function finiteNumber2(value) {
920
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
921
+ }
922
+ function extractTerminalRunLogTail(result) {
923
+ if (!isRecord2(result) || !isRecord2(result._metadata)) {
924
+ return null;
925
+ }
926
+ const runLogTail = result._metadata.runLogTail;
927
+ if (!isRecord2(runLogTail) || !Array.isArray(runLogTail.tail)) {
928
+ return null;
929
+ }
930
+ const logTail = runLogTail.tail.filter(
931
+ (line) => typeof line === "string" && line.trim().length > 0
932
+ );
933
+ if (logTail.length === 0) {
934
+ return null;
935
+ }
936
+ const totalLogCount = Math.max(
937
+ finiteNumber2(runLogTail.totalLogCount) ?? logTail.length,
938
+ logTail.length
939
+ );
940
+ return {
941
+ logTail: logTail.slice(-LOG_TAIL_LIMIT),
942
+ totalLogCount
943
+ };
944
+ }
896
945
  function buildSnapshotFromLedger(snapshot) {
897
946
  const nodeStates = snapshot.orderedStepIds.map((stepId) => snapshot.stepsById[stepId]).filter((step) => Boolean(step)).map((step) => ({
898
947
  nodeId: step.stepId,
@@ -939,6 +988,14 @@ function buildPlayRunStatusSnapshot(input2) {
939
988
  updatedAt: input2.run.updatedAt ?? null,
940
989
  finishedAt: input2.run.finishedAt ?? null
941
990
  });
991
+ const terminalRunLogTail = extractTerminalRunLogTail(input2.run.result);
992
+ if (terminalRunLogTail && terminalRunLogTail.totalLogCount > ledgerSnapshot.totalLogCount) {
993
+ return buildSnapshotFromLedger({
994
+ ...ledgerSnapshot,
995
+ logTail: terminalRunLogTail.logTail,
996
+ totalLogCount: terminalRunLogTail.totalLogCount
997
+ });
998
+ }
942
999
  return buildSnapshotFromLedger(ledgerSnapshot);
943
1000
  }
944
1001
  function makeRunStreamEvent(input2) {
@@ -1533,7 +1590,7 @@ function chunkRegisterPlayArtifacts(artifacts) {
1533
1590
  return chunks;
1534
1591
  }
1535
1592
  var RUN_LOGS_PAGE_LIMIT = 1e3;
1536
- function isRecord2(value) {
1593
+ function isRecord3(value) {
1537
1594
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1538
1595
  }
1539
1596
  function isPrebuiltPlayDescription(play) {
@@ -1635,7 +1692,7 @@ function updatePlayLiveStatusState(state, event) {
1635
1692
  }
1636
1693
  const runId = typeof payload.runId === "string" && payload.runId ? payload.runId : isPlayRunPackage(payload) ? payload.run.id : state.runId;
1637
1694
  const status = normalizeLiveStatus(payload.status) ?? (isPlayRunPackage(payload) ? normalizeLiveStatus(payload.run.status) : null) ?? state.status;
1638
- const progressPayload = isRecord2(payload.progress) ? payload.progress : {};
1695
+ const progressPayload = isRecord3(payload.progress) ? payload.progress : {};
1639
1696
  if (event.type === "play.run.final_status" && state.logs.length === 0 && state.lastLogSeq === 0) {
1640
1697
  const payloadLogs = readStringArray(payload.logs);
1641
1698
  const progressLogs = readStringArray(progressPayload.logs);
@@ -1748,9 +1805,9 @@ var DeeplineClient = class {
1748
1805
  return fields.length > 0 ? { fields } : schema;
1749
1806
  }
1750
1807
  schemaMetadata(schema, key) {
1751
- if (!isRecord2(schema)) return null;
1808
+ if (!isRecord3(schema)) return null;
1752
1809
  const value = schema[key];
1753
- return isRecord2(value) ? value : null;
1810
+ return isRecord3(value) ? value : null;
1754
1811
  }
1755
1812
  playRunCommand(play, options) {
1756
1813
  const target = play.reference || play.name;
@@ -1797,7 +1854,7 @@ var DeeplineClient = class {
1797
1854
  aliases,
1798
1855
  inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
1799
1856
  outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
1800
- staticPipeline: isRecord2(play.staticPipeline) ? play.staticPipeline : isRecord2(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord2(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
1857
+ staticPipeline: isRecord3(play.staticPipeline) ? play.staticPipeline : isRecord3(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord3(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
1801
1858
  ...csvInput ? { csvInput } : {},
1802
1859
  ...rowOutputSchema ? { rowOutputSchema } : {},
1803
1860
  runCommand: runCommand2,
@@ -5291,14 +5348,14 @@ function sanitizeCsvProjectionInfo(input2) {
5291
5348
  const rows = input2.rows.map(stripCsvProjectionFields);
5292
5349
  return { rows, columns };
5293
5350
  }
5294
- function isRecord3(value) {
5351
+ function isRecord4(value) {
5295
5352
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
5296
5353
  }
5297
5354
  function isSerializedDataset(value) {
5298
- return isRecord3(value) && value.kind === "dataset" && typeof value.count === "number" && Array.isArray(value.preview);
5355
+ return isRecord4(value) && value.kind === "dataset" && typeof value.count === "number" && Array.isArray(value.preview);
5299
5356
  }
5300
5357
  function isPackagedDatasetOutput(value) {
5301
- return isRecord3(value) && value.kind === "dataset" && isRecord3(value.preview) && Array.isArray(value.preview.rows);
5358
+ return isRecord4(value) && value.kind === "dataset" && isRecord4(value.preview) && Array.isArray(value.preview.rows);
5302
5359
  }
5303
5360
  function pathParts(path) {
5304
5361
  return path.split(".").map((part) => part.trim()).filter(Boolean);
@@ -5306,7 +5363,7 @@ function pathParts(path) {
5306
5363
  function valueAtPath(root, path) {
5307
5364
  let cursor = root;
5308
5365
  for (const part of pathParts(path)) {
5309
- if (!isRecord3(cursor)) {
5366
+ if (!isRecord4(cursor)) {
5310
5367
  return void 0;
5311
5368
  }
5312
5369
  cursor = cursor[part];
@@ -5314,17 +5371,17 @@ function valueAtPath(root, path) {
5314
5371
  return cursor;
5315
5372
  }
5316
5373
  function totalRowsForDataset(result, datasetPath) {
5317
- const metadata = isRecord3(result._metadata) ? result._metadata : null;
5374
+ const metadata = isRecord4(result._metadata) ? result._metadata : null;
5318
5375
  const parentPath = datasetPath.split(".").slice(0, -1).join(".");
5319
5376
  const parent = parentPath ? valueAtPath({ result }, parentPath) : result;
5320
- return metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count ?? (isRecord3(parent) ? parent.totalRows ?? parent.rowCount ?? parent.count : void 0) ?? result.totalRows ?? result.rowCount ?? result.count;
5377
+ return metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count ?? (isRecord4(parent) ? parent.totalRows ?? parent.rowCount ?? parent.count : void 0) ?? result.totalRows ?? result.rowCount ?? result.count;
5321
5378
  }
5322
5379
  function rowArray(value) {
5323
5380
  if (!Array.isArray(value)) {
5324
5381
  return null;
5325
5382
  }
5326
5383
  const rows = value.filter(
5327
- (row) => isRecord3(row)
5384
+ (row) => isRecord4(row)
5328
5385
  );
5329
5386
  return rows.length === value.length ? rows : null;
5330
5387
  }
@@ -5348,7 +5405,7 @@ function inferColumns(rows) {
5348
5405
  return columns;
5349
5406
  }
5350
5407
  function columnsFromDatasetSummary(summary) {
5351
- if (!isRecord3(summary) || !isRecord3(summary.columnStats)) {
5408
+ if (!isRecord4(summary) || !isRecord4(summary.columnStats)) {
5352
5409
  return [];
5353
5410
  }
5354
5411
  return Object.keys(summary.columnStats).filter((column) => column);
@@ -5377,7 +5434,7 @@ function canonicalRowsInfoFromCandidate(input2) {
5377
5434
  }
5378
5435
  if (isPackagedDatasetOutput(candidate.value)) {
5379
5436
  const rawRows = rowArray(candidate.value.preview?.rows) ?? [];
5380
- const totalRows2 = readNumber(candidate.value.preview?.totalRows) ?? readNumber(candidate.value.rowCount) ?? rawRows.length;
5437
+ const totalRows2 = readNumber(candidate.value.rowCount) ?? readNumber(candidate.value.preview?.totalRows) ?? rawRows.length;
5381
5438
  const explicitColumns = Array.isArray(candidate.value.columns) ? candidate.value.columns.filter(
5382
5439
  (column) => typeof column === "string"
5383
5440
  ) : [];
@@ -5438,7 +5495,7 @@ function collectDatasetCandidates(input2) {
5438
5495
  });
5439
5496
  return;
5440
5497
  }
5441
- if (!isRecord3(input2.value)) {
5498
+ if (!isRecord4(input2.value)) {
5442
5499
  return;
5443
5500
  }
5444
5501
  for (const [key, child] of Object.entries(input2.value)) {
@@ -5455,12 +5512,12 @@ function collectDatasetCandidates(input2) {
5455
5512
  }
5456
5513
  }
5457
5514
  function collectCanonicalRowsInfos(statusOrResult) {
5458
- const root = isRecord3(statusOrResult) ? statusOrResult : null;
5459
- const result = isRecord3(root?.result) ? root.result : root;
5515
+ const root = isRecord4(statusOrResult) ? statusOrResult : null;
5516
+ const result = isRecord4(root?.result) ? root.result : root;
5460
5517
  if (!result) {
5461
5518
  return [];
5462
5519
  }
5463
- const metadata = isRecord3(result._metadata) ? result._metadata : null;
5520
+ const metadata = isRecord4(result._metadata) ? result._metadata : null;
5464
5521
  const totalFromMetadata = metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count;
5465
5522
  const candidates = [
5466
5523
  {
@@ -5484,8 +5541,8 @@ function collectCanonicalRowsInfos(statusOrResult) {
5484
5541
  total: totalFromMetadata ?? result.totalRows ?? result.rowCount ?? result.count
5485
5542
  }
5486
5543
  ];
5487
- if (isRecord3(result.output)) {
5488
- const outputMetadata = isRecord3(result.output._metadata) ? result.output._metadata : null;
5544
+ if (isRecord4(result.output)) {
5545
+ const outputMetadata = isRecord4(result.output._metadata) ? result.output._metadata : null;
5489
5546
  const outputTotalFromMetadata = outputMetadata?.totalRows ?? outputMetadata?.rowCount ?? outputMetadata?.count;
5490
5547
  candidates.push(
5491
5548
  {
@@ -5512,14 +5569,14 @@ function collectCanonicalRowsInfos(statusOrResult) {
5512
5569
  }
5513
5570
  if (Array.isArray(result.steps)) {
5514
5571
  result.steps.forEach((step, index) => {
5515
- if (!isRecord3(step) || !isRecord3(step.output)) {
5572
+ if (!isRecord4(step) || !isRecord4(step.output)) {
5516
5573
  return;
5517
5574
  }
5518
5575
  const source = typeof step.output.path === "string" ? step.output.path : typeof step.id === "string" ? `steps.${step.id}.output` : `steps.${index}.output`;
5519
5576
  candidates.push({
5520
5577
  source,
5521
5578
  value: step.output,
5522
- total: step.output.rowCount ?? (isRecord3(step.output.preview) ? step.output.preview.totalRows : void 0) ?? (isRecord3(step.progress) ? step.progress.total : void 0)
5579
+ total: step.output.rowCount ?? (isRecord4(step.output.preview) ? step.output.preview.totalRows : void 0) ?? (isRecord4(step.progress) ? step.progress.total : void 0)
5523
5580
  });
5524
5581
  });
5525
5582
  }
@@ -5546,15 +5603,15 @@ function collectCanonicalRowsInfos(statusOrResult) {
5546
5603
  return infos;
5547
5604
  }
5548
5605
  function collectPackagedStepDatasetCandidates(statusOrResult) {
5549
- const root = isRecord3(statusOrResult) ? statusOrResult : null;
5606
+ const root = isRecord4(statusOrResult) ? statusOrResult : null;
5550
5607
  if (!root) {
5551
5608
  return [];
5552
5609
  }
5553
- const pkg = isRecord3(root.package) ? root.package : root;
5610
+ const pkg = isRecord4(root.package) ? root.package : root;
5554
5611
  const steps = Array.isArray(pkg.steps) ? pkg.steps : [];
5555
5612
  const candidates = [];
5556
5613
  for (const step of steps) {
5557
- if (!isRecord3(step) || !isRecord3(step.output)) {
5614
+ if (!isRecord4(step) || !isRecord4(step.output)) {
5558
5615
  continue;
5559
5616
  }
5560
5617
  const output2 = step.output;
@@ -5568,14 +5625,14 @@ function collectPackagedStepDatasetCandidates(statusOrResult) {
5568
5625
  candidates.push({
5569
5626
  source,
5570
5627
  value: output2,
5571
- total: output2.rowCount ?? (isRecord3(output2.preview) ? output2.preview.totalRows : void 0) ?? (isRecord3(step.progress) ? step.progress.total : void 0)
5628
+ total: output2.rowCount ?? (isRecord4(output2.preview) ? output2.preview.totalRows : void 0) ?? (isRecord4(step.progress) ? step.progress.total : void 0)
5572
5629
  });
5573
5630
  }
5574
5631
  return candidates;
5575
5632
  }
5576
5633
  function collectSerializedDatasetRowsInfos(statusOrResult) {
5577
- const root = isRecord3(statusOrResult) ? statusOrResult : null;
5578
- const result = isRecord3(root?.result) ? root.result : root;
5634
+ const root = isRecord4(statusOrResult) ? statusOrResult : null;
5635
+ const result = isRecord4(root?.result) ? root.result : root;
5579
5636
  const candidates = [];
5580
5637
  if (result) {
5581
5638
  collectDatasetCandidates({
@@ -5611,17 +5668,17 @@ function percentText(numerator, denominator) {
5611
5668
  return datasetSummaryPercentText(numerator, denominator);
5612
5669
  }
5613
5670
  function isDatasetExecutionStatsInput(value) {
5614
- return isRecord3(value) && isRecord3(value.columnStats) && Object.values(value.columnStats).every(isRecord3);
5671
+ return isRecord4(value) && isRecord4(value.columnStats) && Object.values(value.columnStats).every(isRecord4);
5615
5672
  }
5616
5673
  function extractDatasetExecutionStats(statusOrResult) {
5617
- if (!isRecord3(statusOrResult)) {
5674
+ if (!isRecord4(statusOrResult)) {
5618
5675
  return null;
5619
5676
  }
5620
5677
  const direct = statusOrResult.dataset_execution_stats;
5621
5678
  if (isDatasetExecutionStatsInput(direct)) {
5622
5679
  return direct;
5623
5680
  }
5624
- const nested = isRecord3(statusOrResult.result) ? statusOrResult.result.dataset_execution_stats : null;
5681
+ const nested = isRecord4(statusOrResult.result) ? statusOrResult.result.dataset_execution_stats : null;
5625
5682
  return isDatasetExecutionStatsInput(nested) ? nested : null;
5626
5683
  }
5627
5684
  function countPercentText(count, denominator) {
@@ -5662,13 +5719,13 @@ function summarizeSampleValue(value, depth = 0) {
5662
5719
  if (typeof parsed === "number" || typeof parsed === "boolean") return parsed;
5663
5720
  if (depth >= 3) {
5664
5721
  if (Array.isArray(parsed)) return [];
5665
- if (isRecord3(parsed)) return {};
5722
+ if (isRecord4(parsed)) return {};
5666
5723
  return compactScalar(parsed);
5667
5724
  }
5668
5725
  if (Array.isArray(parsed)) {
5669
5726
  return parsed.slice(0, 3).map((item) => summarizeSampleValue(item, depth + 1));
5670
5727
  }
5671
- if (isRecord3(parsed)) {
5728
+ if (isRecord4(parsed)) {
5672
5729
  const out = {};
5673
5730
  for (const [key, nested] of Object.entries(parsed)) {
5674
5731
  if (["__dl", "meta", "metadata"].includes(key)) {
@@ -5699,7 +5756,7 @@ function compactCell(value) {
5699
5756
  }
5700
5757
  return `[${parsed.length} items]`;
5701
5758
  }
5702
- if (isRecord3(parsed)) {
5759
+ if (isRecord4(parsed)) {
5703
5760
  for (const key of ["matched_result", "output"]) {
5704
5761
  if (parsed[key] !== null && parsed[key] !== void 0 && parsed[key] !== "") {
5705
5762
  return compactCell(parsed[key]);
@@ -7469,16 +7526,19 @@ var PLAY_DEDUP_BACKENDS = {
7469
7526
  var PLAY_SCHEDULER_BACKENDS = {
7470
7527
  temporal: "temporal",
7471
7528
  cfWorkflows: "cf-workflows",
7529
+ /**
7530
+ * Private legacy id retained only so old persisted rows can be interpreted.
7531
+ * It is not a selectable scheduler backend after the Hatchet hard cutover.
7532
+ */
7472
7533
  postgres: "postgres",
7534
+ hatchet: "hatchet",
7473
7535
  inProcess: "in-process"
7474
7536
  };
7475
7537
 
7476
7538
  // ../shared_libs/play-runtime/providers.ts
7477
7539
  var PLAY_RUNTIME_PROVIDER_IDS = {
7478
7540
  workersEdge: "workers_edge",
7479
- postgresFast: "postgres_fast",
7480
- postgresFastSandbox: "postgres_fast_sandbox",
7481
- postgresFastWorkers: "postgres_fast_workers",
7541
+ hatchet: "hatchet",
7482
7542
  local: "local"
7483
7543
  };
7484
7544
  var PLAY_RUNTIME_PROVIDERS = {
@@ -7490,29 +7550,13 @@ var PLAY_RUNTIME_PROVIDERS = {
7490
7550
  artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
7491
7551
  label: "Cloudflare Dynamic Workflows + Dynamic Workers + DO dedup"
7492
7552
  },
7493
- postgres_fast: {
7494
- id: PLAY_RUNTIME_PROVIDER_IDS.postgresFast,
7495
- scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
7553
+ hatchet: {
7554
+ id: PLAY_RUNTIME_PROVIDER_IDS.hatchet,
7555
+ scheduler: PLAY_SCHEDULER_BACKENDS.hatchet,
7496
7556
  runner: PLAY_RUNTIME_BACKENDS.daytona,
7497
7557
  dedup: PLAY_DEDUP_BACKENDS.durableObject,
7498
7558
  artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
7499
- label: "BETA: Postgres Scheduler + warm sandbox runner + DO dedup"
7500
- },
7501
- postgres_fast_sandbox: {
7502
- id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastSandbox,
7503
- scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
7504
- runner: PLAY_RUNTIME_BACKENDS.daytona,
7505
- dedup: PLAY_DEDUP_BACKENDS.durableObject,
7506
- artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
7507
- label: "BETA: Postgres Scheduler + warm sandbox runner + DO dedup"
7508
- },
7509
- postgres_fast_workers: {
7510
- id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastWorkers,
7511
- scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
7512
- runner: PLAY_RUNTIME_BACKENDS.cloudflareWorkers,
7513
- dedup: PLAY_DEDUP_BACKENDS.durableObject,
7514
- artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
7515
- label: "Experimental Postgres Scheduler + Queue/DO-woken Workers + DO dedup"
7559
+ label: "Hatchet scheduler + one-shot Daytona runner + DO dedup"
7516
7560
  },
7517
7561
  local: {
7518
7562
  id: PLAY_RUNTIME_PROVIDER_IDS.local,
@@ -8024,17 +8068,17 @@ function parsePositiveInteger2(value, flagName) {
8024
8068
  }
8025
8069
  return parsed;
8026
8070
  }
8027
- function isRecord4(value) {
8071
+ function isRecord5(value) {
8028
8072
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
8029
8073
  }
8030
8074
  function stringValue(value) {
8031
8075
  return typeof value === "string" ? value.trim() : "";
8032
8076
  }
8033
8077
  function extractionEntries(value) {
8034
- if (Array.isArray(value)) return value.filter(isRecord4);
8035
- if (!isRecord4(value)) return [];
8078
+ if (Array.isArray(value)) return value.filter(isRecord5);
8079
+ if (!isRecord5(value)) return [];
8036
8080
  return Object.entries(value).map(
8037
- ([name, entry]) => isRecord4(entry) ? { name, ...entry } : { name }
8081
+ ([name, entry]) => isRecord5(entry) ? { name, ...entry } : { name }
8038
8082
  );
8039
8083
  }
8040
8084
  var PlayBootstrapError = class extends Error {
@@ -8454,7 +8498,7 @@ function readCsvSampleRows(sample) {
8454
8498
  relax_column_count: true,
8455
8499
  trim: true
8456
8500
  });
8457
- return Array.isArray(parsedRows) ? parsedRows.filter(isRecord4) : [];
8501
+ return Array.isArray(parsedRows) ? parsedRows.filter(isRecord5) : [];
8458
8502
  }
8459
8503
  function readSourceCsvColumnSpecs(csvPath) {
8460
8504
  const sample = readCsvSample(csvPath);
@@ -8487,16 +8531,16 @@ function packagedCsvPathForPlay(csvPath) {
8487
8531
  return portablePath.startsWith(".") ? portablePath : `./${portablePath}`;
8488
8532
  }
8489
8533
  function getterNamesFromTool(tool, kind) {
8490
- const usageGuidance = isRecord4(tool?.usageGuidance) ? tool.usageGuidance : {};
8491
- const resultGuidance = isRecord4(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord4(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
8534
+ const usageGuidance = isRecord5(tool?.usageGuidance) ? tool.usageGuidance : {};
8535
+ const resultGuidance = isRecord5(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord5(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
8492
8536
  const key = kind === "list" ? "extractedLists" : "extractedValues";
8493
8537
  const snakeKey = kind === "list" ? "extracted_lists" : "extracted_values";
8494
8538
  return extractionEntries(resultGuidance[key] ?? resultGuidance[snakeKey]).map((entry) => stringValue(entry.name)).filter(Boolean);
8495
8539
  }
8496
8540
  function targetGettersFromTool(tool) {
8497
- const record = isRecord4(tool) ? tool : {};
8541
+ const record = isRecord5(tool) ? tool : {};
8498
8542
  const raw = record.targetGetters ?? record.target_getters;
8499
- if (!isRecord4(raw)) return {};
8543
+ if (!isRecord5(raw)) return {};
8500
8544
  const entries = [];
8501
8545
  for (const [target, value] of Object.entries(raw)) {
8502
8546
  const paths = Array.isArray(value) ? value.map((path) => typeof path === "string" ? path.trim() : "").filter(Boolean) : [];
@@ -8517,10 +8561,10 @@ function listRowCandidateKeysFromTool(tool) {
8517
8561
  return [...keys].sort();
8518
8562
  }
8519
8563
  function inputPropertyNames(schema) {
8520
- if (!isRecord4(schema)) return [];
8521
- if (isRecord4(schema.properties)) return Object.keys(schema.properties);
8564
+ if (!isRecord5(schema)) return [];
8565
+ if (isRecord5(schema.properties)) return Object.keys(schema.properties);
8522
8566
  if (Array.isArray(schema.fields)) {
8523
- return schema.fields.filter(isRecord4).map((field) => stringValue(field.name)).filter(Boolean);
8567
+ return schema.fields.filter(isRecord5).map((field) => stringValue(field.name)).filter(Boolean);
8524
8568
  }
8525
8569
  return [];
8526
8570
  }
@@ -8534,7 +8578,7 @@ function schemaFieldDetails(schema) {
8534
8578
  return { required, optional };
8535
8579
  }
8536
8580
  function jsonSchemaTypeExpression(schema) {
8537
- if (!isRecord4(schema)) return "unknown";
8581
+ if (!isRecord5(schema)) return "unknown";
8538
8582
  const type = schema.type;
8539
8583
  if (Array.isArray(type)) {
8540
8584
  return type.map((entry) => jsonSchemaTypeExpression({ ...schema, type: entry })).join(" | ");
@@ -8564,7 +8608,7 @@ function jsonSchemaTypeExpression(schema) {
8564
8608
  }
8565
8609
  }
8566
8610
  function objectPropertySchema(schema, property) {
8567
- return isRecord4(schema) && isRecord4(schema.properties) ? schema.properties[property] : null;
8611
+ return isRecord5(schema) && isRecord5(schema.properties) ? schema.properties[property] : null;
8568
8612
  }
8569
8613
  function playOutputHasField(schema, field) {
8570
8614
  return objectPropertySchema(schema, field) != null;
@@ -8740,14 +8784,14 @@ ${indent2.slice(2)}}`;
8740
8784
  }
8741
8785
  function requiredPlayInputFields(play) {
8742
8786
  const schema = play?.inputSchema;
8743
- if (!isRecord4(schema)) return [];
8787
+ if (!isRecord5(schema)) return [];
8744
8788
  if (Array.isArray(schema.required)) {
8745
8789
  return schema.required.filter(
8746
8790
  (value) => typeof value === "string"
8747
8791
  );
8748
8792
  }
8749
8793
  if (Array.isArray(schema.fields)) {
8750
- return schema.fields.filter(isRecord4).filter(
8794
+ return schema.fields.filter(isRecord5).filter(
8751
8795
  (field) => field.required === true && typeof field.name === "string"
8752
8796
  ).map((field) => String(field.name));
8753
8797
  }
@@ -8928,7 +8972,7 @@ function validateBootstrapRoutes(input2) {
8928
8972
  }
8929
8973
  }
8930
8974
  function staticPipelineSubsteps(pipeline) {
8931
- if (!isRecord4(pipeline)) return [];
8975
+ if (!isRecord5(pipeline)) return [];
8932
8976
  return [
8933
8977
  ...extractionEntries(pipeline.stages),
8934
8978
  ...extractionEntries(pipeline.substeps)
@@ -8936,7 +8980,7 @@ function staticPipelineSubsteps(pipeline) {
8936
8980
  }
8937
8981
  function playUsesMapBackedRuntime(play) {
8938
8982
  const pipeline = play?.staticPipeline;
8939
- if (!isRecord4(pipeline)) return false;
8983
+ if (!isRecord5(pipeline)) return false;
8940
8984
  if (stringValue(pipeline.tableNamespace)) return true;
8941
8985
  return staticPipelineSubsteps(pipeline).some((substep) => {
8942
8986
  if (stringValue(substep.type) === "map") return true;
@@ -8945,7 +8989,7 @@ function playUsesMapBackedRuntime(play) {
8945
8989
  aliases: [],
8946
8990
  runCommand: "",
8947
8991
  examples: [],
8948
- staticPipeline: isRecord4(substep.pipeline) ? substep.pipeline : null
8992
+ staticPipeline: isRecord5(substep.pipeline) ? substep.pipeline : null
8949
8993
  });
8950
8994
  });
8951
8995
  }
@@ -10507,10 +10551,12 @@ function playStatusValue(value) {
10507
10551
  return value === "queued" || value === "running" || value === "waiting" || value === "completed" || value === "failed" || value === "cancelled" ? value : null;
10508
10552
  }
10509
10553
  function getRunRecordFromPackage(value) {
10510
- if (!isPlayRunPackageValue(value)) {
10554
+ const nestedPackage = value.package;
10555
+ const playRunPackage = isPlayRunPackageValue(value) ? value : isPlayRunPackageValue(nestedPackage) ? nestedPackage : null;
10556
+ if (!playRunPackage) {
10511
10557
  return null;
10512
10558
  }
10513
- const run = value.run;
10559
+ const run = playRunPackage.run;
10514
10560
  return run && typeof run === "object" && !Array.isArray(run) ? run : null;
10515
10561
  }
10516
10562
  function getRunIdFromLiveEvent(event) {
@@ -10540,10 +10586,12 @@ function getFinalStatusFromLiveEvent(event) {
10540
10586
  return null;
10541
10587
  }
10542
10588
  const runId = typeof payload.runId === "string" ? payload.runId : typeof packageRun?.id === "string" ? packageRun.id : "";
10589
+ const error = typeof payload.error === "string" ? payload.error : typeof packageRun?.error === "string" ? packageRun.error : void 0;
10543
10590
  return {
10544
10591
  ...payload,
10545
10592
  runId,
10546
- status
10593
+ status,
10594
+ ...error ? { error } : {}
10547
10595
  };
10548
10596
  }
10549
10597
  function getLogLinesFromLiveEvent(event) {
@@ -11862,7 +11910,16 @@ function withTerminalPlayIdentity(status, playName) {
11862
11910
  function compactPlayStatus(status) {
11863
11911
  const packaged = getPlayRunPackage(status);
11864
11912
  if (packaged) {
11865
- return packaged;
11913
+ const error2 = selectRunErrorForDisplay(status) ?? (typeof status.error === "string" ? String(status.error) : null);
11914
+ if (!error2) {
11915
+ return packaged;
11916
+ }
11917
+ const run = packaged.run && typeof packaged.run === "object" ? packaged.run : null;
11918
+ return {
11919
+ ...packaged,
11920
+ error: error2,
11921
+ ...run ? { run: { ...run, error: error2 } } : {}
11922
+ };
11866
11923
  }
11867
11924
  const rowsInfo = extractCanonicalRowsInfo(status);
11868
11925
  const result = status && typeof status === "object" ? status.result : null;
@@ -12202,10 +12259,17 @@ function writePlayResult(status, jsonOutput, options) {
12202
12259
  ` }
12203
12260
  );
12204
12261
  }
12205
- function playRunPackageStepCount(pkg) {
12206
- if (!pkg) return 0;
12207
- const steps = pkg.steps;
12208
- return Array.isArray(steps) ? steps.length : 0;
12262
+ function playRunPackageTextLedgerIncomplete(pkg) {
12263
+ if (!pkg) return true;
12264
+ const steps = readRecordArray(pkg.steps);
12265
+ if (steps.length === 0) return true;
12266
+ for (const step of steps) {
12267
+ if (step.kind !== "dataset" || step.status !== "completed") continue;
12268
+ const output2 = readRecord(step.output);
12269
+ if (!output2 || typeof output2.rowCount !== "number") return true;
12270
+ if (!readRecord(output2.summary)) return true;
12271
+ }
12272
+ return false;
12209
12273
  }
12210
12274
  async function resolvePlayRunOutputStatus(input2) {
12211
12275
  const runId = input2.status.runId;
@@ -12214,7 +12278,7 @@ async function resolvePlayRunOutputStatus(input2) {
12214
12278
  }
12215
12279
  const streamedPackage = getPlayRunPackage(input2.status);
12216
12280
  const refreshForFullJson = input2.fullJson && streamedPackage !== null;
12217
- const streamedTextPackageIncomplete = !input2.jsonOutput && input2.status.status === "completed" && playRunPackageStepCount(streamedPackage) === 0;
12281
+ const streamedTextPackageIncomplete = !input2.jsonOutput && input2.status.status === "completed" && playRunPackageTextLedgerIncomplete(streamedPackage);
12218
12282
  if (!refreshForFullJson && !streamedTextPackageIncomplete) {
12219
12283
  return input2.status;
12220
12284
  }
@@ -12222,7 +12286,7 @@ async function resolvePlayRunOutputStatus(input2) {
12222
12286
  billing: false,
12223
12287
  full: input2.fullJson
12224
12288
  });
12225
- for (let attempt = 0; attempt < 3 && streamedTextPackageIncomplete && refreshedStatus.status === "completed" && playRunPackageStepCount(getPlayRunPackage(refreshedStatus)) === 0; attempt += 1) {
12289
+ for (let attempt = 0; attempt < 3 && streamedTextPackageIncomplete && refreshedStatus.status === "completed" && playRunPackageTextLedgerIncomplete(getPlayRunPackage(refreshedStatus)); attempt += 1) {
12226
12290
  await sleep5(250);
12227
12291
  refreshedStatus = await input2.client.getPlayStatus(runId, {
12228
12292
  billing: false,
@@ -12531,7 +12595,7 @@ function extractPlayValidationErrors(value) {
12531
12595
  if (value instanceof DeeplineError) {
12532
12596
  return extractPlayValidationErrors(value.details);
12533
12597
  }
12534
- if (!isRecord5(value)) {
12598
+ if (!isRecord6(value)) {
12535
12599
  return [];
12536
12600
  }
12537
12601
  const directErrors = stringArrayField(value, "errors");
@@ -12744,7 +12808,7 @@ function writeStartedPlayRun(input2) {
12744
12808
  );
12745
12809
  }
12746
12810
  function parsePlayRunOptions(args) {
12747
- 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.";
12811
+ 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.";
12748
12812
  let filePath = null;
12749
12813
  let playName = null;
12750
12814
  let input2 = null;
@@ -12889,7 +12953,7 @@ function shouldUseLocalOnlyPlayCheck() {
12889
12953
  const value = process.env.DEEPLINE_PLAY_CHECK_LOCAL_ONLY?.trim().toLowerCase();
12890
12954
  return value === "1" || value === "true" || value === "yes" || value === "on";
12891
12955
  }
12892
- function isRecord5(value) {
12956
+ function isRecord6(value) {
12893
12957
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
12894
12958
  }
12895
12959
  function stringValue2(value) {
@@ -12899,14 +12963,14 @@ function asArray(value) {
12899
12963
  return Array.isArray(value) ? value : [];
12900
12964
  }
12901
12965
  function extractionEntries2(value) {
12902
- if (Array.isArray(value)) return value.filter(isRecord5);
12903
- if (!isRecord5(value)) return [];
12966
+ if (Array.isArray(value)) return value.filter(isRecord6);
12967
+ if (!isRecord6(value)) return [];
12904
12968
  return Object.entries(value).map(
12905
- ([name, entry]) => isRecord5(entry) ? { name, ...entry } : { name }
12969
+ ([name, entry]) => isRecord6(entry) ? { name, ...entry } : { name }
12906
12970
  );
12907
12971
  }
12908
12972
  function firstRawPath(entry) {
12909
- const details = isRecord5(entry.details) ? entry.details : {};
12973
+ const details = isRecord6(entry.details) ? entry.details : {};
12910
12974
  const paths = [
12911
12975
  ...asArray(details.rawToolOutputPaths),
12912
12976
  ...asArray(details.raw_tool_output_paths),
@@ -12924,12 +12988,12 @@ function checkHintRawPath(value) {
12924
12988
  function collectStaticPipelineToolIds(staticPipeline) {
12925
12989
  const seen = /* @__PURE__ */ new Set();
12926
12990
  const visitPipeline = (pipeline) => {
12927
- if (!isRecord5(pipeline)) return;
12991
+ if (!isRecord6(pipeline)) return;
12928
12992
  for (const step of [
12929
12993
  ...asArray(pipeline.stages),
12930
12994
  ...asArray(pipeline.substeps)
12931
12995
  ]) {
12932
- if (!isRecord5(step)) continue;
12996
+ if (!isRecord6(step)) continue;
12933
12997
  if (step.type === "tool") {
12934
12998
  const toolId = stringValue2(step.toolId) || stringValue2(step.tool);
12935
12999
  if (toolId) seen.add(toolId);
@@ -12943,9 +13007,9 @@ function collectStaticPipelineToolIds(staticPipeline) {
12943
13007
  return [...seen].sort();
12944
13008
  }
12945
13009
  function toolGetterHintFromMetadata(toolId, tool) {
12946
- const usageGuidance = isRecord5(tool.usageGuidance) ? tool.usageGuidance : {};
12947
- const resultGuidance = isRecord5(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord5(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
12948
- const toolResponse = isRecord5(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord5(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
13010
+ const usageGuidance = isRecord6(tool.usageGuidance) ? tool.usageGuidance : {};
13011
+ const resultGuidance = isRecord6(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord6(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
13012
+ const toolResponse = isRecord6(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord6(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
12949
13013
  const lists = extractionEntries2(
12950
13014
  resultGuidance.extractedLists ?? resultGuidance.extracted_lists
12951
13015
  ).map((entry) => ({
@@ -14270,6 +14334,40 @@ async function handlePlayDescribe(args) {
14270
14334
  );
14271
14335
  return 2;
14272
14336
  }
14337
+ if (isFileTarget(playName) || looksLikeFilePath(playName)) {
14338
+ const message = "Local play files can be checked and run, but describe only supports saved/prebuilt play references.";
14339
+ const definedName = isFileTarget(playName) ? (() => {
14340
+ try {
14341
+ return extractPlayName(
14342
+ (0, import_node_fs10.readFileSync)((0, import_node_path12.resolve)(playName), "utf-8"),
14343
+ playName
14344
+ );
14345
+ } catch {
14346
+ return null;
14347
+ }
14348
+ })() : null;
14349
+ const next = [
14350
+ `deepline plays check ${playName}`,
14351
+ ...definedName ? [`deepline plays describe <workspace>/${definedName}`] : []
14352
+ ];
14353
+ if (argsWantJson(args)) {
14354
+ process.stdout.write(
14355
+ `${JSON.stringify({
14356
+ ok: false,
14357
+ error: { message },
14358
+ next
14359
+ })}
14360
+ `
14361
+ );
14362
+ } else {
14363
+ console.error(message);
14364
+ console.error(`Try: ${next[0]}`);
14365
+ if (next[1]) {
14366
+ console.error(`Or after publishing/running: ${next[1]}`);
14367
+ }
14368
+ }
14369
+ return 2;
14370
+ }
14273
14371
  const client2 = new DeeplineClient();
14274
14372
  await assertCanonicalNamedPlayReference(client2, playName);
14275
14373
  const play = await client2.describePlay(
@@ -15351,6 +15449,18 @@ function getterFromLegacyExtractJs(extractJs, fallbackAlias) {
15351
15449
  return null;
15352
15450
  }
15353
15451
 
15452
+ // src/cli/enrich-compat-adapter.ts
15453
+ var ENRICH_COMPAT_DEFAULT_PLAY_NAME = "deepline-enrich-v1-compat";
15454
+ var ENRICH_COMPAT_DEFAULT_MAP_NAME = "deepline_enrich_rows";
15455
+ var ENRICH_COMPAT_METADATA_CELL_POLICY_SOURCE = "{ recompute: true }";
15456
+ function buildEnrichCompatibilityPlan(options = {}) {
15457
+ return {
15458
+ playName: options.playName?.trim() || ENRICH_COMPAT_DEFAULT_PLAY_NAME,
15459
+ mapName: options.mapName?.trim() || ENRICH_COMPAT_DEFAULT_MAP_NAME,
15460
+ metadataCellPolicySource: ENRICH_COMPAT_METADATA_CELL_POLICY_SOURCE
15461
+ };
15462
+ }
15463
+
15354
15464
  // src/cli/user-code-safety.ts
15355
15465
  var FORBIDDEN = [
15356
15466
  // Non-deterministic — breaks replay.
@@ -15491,7 +15601,7 @@ function renderIdiomaticExecuteStep(command, options) {
15491
15601
  ` tool: ${tool},`,
15492
15602
  ` input: ${input2} as any,`,
15493
15603
  ` description: ${stringLiteral((command.description ?? "").trim() || `Run ${command.alias} via ${command.tool}.`)},`,
15494
- ...options.force ? [` staleAfterSeconds: 1,`] : [],
15604
+ ...options.force ? [` force: true,`] : [],
15495
15605
  ` });`,
15496
15606
  ` return ${extraction};`,
15497
15607
  `}`
@@ -15522,18 +15632,18 @@ function renderPlayStep(command, options) {
15522
15632
  const runIfJs = command.run_if_js ? `(row) => { const input = row; const context = row;
15523
15633
  ${indent(renderJavascriptBody(command.run_if_js), 6)}
15524
15634
  }` : "null";
15525
- const runIfLines = command.run_if_js ? [` const __dlRunIf = ${runIfJs};`, ` if (!__dlRunIf(row)) return null;`] : [];
15526
- const playOptions = [
15527
- ` description: ${stringLiteral(command.description ?? command.alias)}`,
15528
- ...options.force ? [` staleAfterSeconds: 1`] : []
15529
- ].join(",\n");
15635
+ const runIfLines = command.run_if_js ? [
15636
+ ` const __dlRunIf = ${runIfJs};`,
15637
+ ` if (!__dlRunIf(templateRow)) return null;`
15638
+ ] : [];
15530
15639
  return [
15531
15640
  `async (row, stepCtx) => {`,
15532
15641
  ...options.precheck ? [` if (${options.precheck}) return null;`] : [],
15642
+ ` const templateRow = __dlPrepareEnrichRow(row, [${alias}]);`,
15533
15643
  ...runIfLines,
15534
- ` const payload = __dlTemplate(${payload}, row) as Record<string, unknown>;`,
15644
+ ` const payload = __dlTemplate(${payload}, templateRow) as Record<string, unknown>;`,
15535
15645
  ` const result = await stepCtx.runPlay(${callId}, ${playRef}, payload, {`,
15536
- playOptions,
15646
+ ` description: ${stringLiteral(command.description ?? command.alias)}`,
15537
15647
  ` });`,
15538
15648
  ` return __dlPlayResultValue(${alias}, result);`,
15539
15649
  `}`
@@ -15550,12 +15660,17 @@ function renderJavascriptBody(source) {
15550
15660
  }
15551
15661
  return source;
15552
15662
  }
15553
- function renderColumnStep(alias, resolverSource, force) {
15663
+ function renderColumnStep(alias, resolverSource, options = {}) {
15554
15664
  const resolver = indent(resolverSource, 8);
15665
+ const optionFields = [
15666
+ ...options.recompute === true ? ["recompute: true"] : [],
15667
+ ...options.recomputeOnError === true ? ["recomputeOnError: true"] : []
15668
+ ];
15669
+ const optionSource = optionFields.length > 0 ? `{ ${optionFields.join(", ")} }` : null;
15555
15670
  return [
15556
15671
  ` .withColumn(${stringLiteral(alias)},`,
15557
- force ? `${resolver},` : resolver,
15558
- ...force ? [` { staleAfterSeconds: 1 }`] : [],
15672
+ `${resolver}${optionSource ? "," : ""}`,
15673
+ ...optionSource ? [` ${optionSource},`] : [],
15559
15674
  ` )`
15560
15675
  ].join("\n");
15561
15676
  }
@@ -15604,15 +15719,38 @@ function collectMetadataColumns(commands, waterfallGroupId) {
15604
15719
  }
15605
15720
  return columns;
15606
15721
  }
15607
- function renderMetadataColumnStep(config) {
15722
+ function collectGeneratedAliases(commands) {
15723
+ const aliases = [];
15724
+ const addAlias = (alias) => {
15725
+ if (alias && !aliases.includes(alias)) {
15726
+ aliases.push(alias);
15727
+ }
15728
+ };
15729
+ for (const command of commands) {
15730
+ if (isWaterfall(command)) {
15731
+ const before = aliases.length;
15732
+ collectGeneratedAliases(command.commands).forEach(addAlias);
15733
+ if (aliases.length > before) {
15734
+ addAlias(command.with_waterfall);
15735
+ addAlias(`${command.with_waterfall}_source`);
15736
+ }
15737
+ continue;
15738
+ }
15739
+ if (!command.disabled) {
15740
+ addAlias(command.alias);
15741
+ }
15742
+ }
15743
+ return aliases;
15744
+ }
15745
+ function renderMetadataColumnStep(config, policySource) {
15608
15746
  const columns = collectMetadataColumns(config.commands);
15609
15747
  if (Object.keys(columns).length === 0) {
15610
15748
  return "";
15611
15749
  }
15612
15750
  return [
15613
15751
  ` .withColumn('_metadata',`,
15614
- ` (row) => __dlMergeMetadata(row._metadata, ${stableJson({ columns })}),`,
15615
- ` { staleAfterSeconds: 1 }`,
15752
+ ` (row) => __dlMergeMetadata(__dlMetadataFromRow(row), ${stableJson({ columns })}),`,
15753
+ ` ${policySource},`,
15616
15754
  ` )`
15617
15755
  ].join("\n");
15618
15756
  }
@@ -15639,7 +15777,7 @@ function renderWaterfallColumns(command, forceAliases, inlineRunJavascript, idio
15639
15777
  inlineRunJavascript,
15640
15778
  idiomaticGetters
15641
15779
  }),
15642
- force
15780
+ { recompute: force, recomputeOnError: true }
15643
15781
  );
15644
15782
  }).filter((line) => line !== null);
15645
15783
  const aliases = activeChildren.map((nested) => nested.alias);
@@ -15655,21 +15793,19 @@ function renderWaterfallColumns(command, forceAliases, inlineRunJavascript, idio
15655
15793
  }
15656
15794
  return [
15657
15795
  ...columnSteps,
15658
- renderColumnStep(
15659
- command.with_waterfall,
15660
- `(row) => ${returnExpr}`,
15661
- forceParent
15662
- ),
15796
+ renderColumnStep(command.with_waterfall, `(row) => ${returnExpr}`, {
15797
+ recompute: forceParent
15798
+ }),
15663
15799
  renderColumnStep(
15664
15800
  `${command.with_waterfall}_source`,
15665
15801
  typeof command.min_results === "number" ? `(row) => __dlContributingAliases(row, ${stableJson(aliases)})` : `(row) => __dlFirstMeaningfulAlias(row, ${stableJson(aliases)})`,
15666
- forceParent
15802
+ { recompute: forceParent }
15667
15803
  )
15668
15804
  ];
15669
15805
  }
15670
15806
  function compileEnrichConfigToPlaySource(config, options = {}) {
15671
- const playName = options.playName ?? "deepline-enrich-v1-compat";
15672
- const mapName = options.mapName ?? "deepline_enrich_rows";
15807
+ const compatibility = buildEnrichCompatibilityPlan(options);
15808
+ const { playName, mapName } = compatibility;
15673
15809
  const inlineRunJavascript = options.inlineRunJavascript ?? false;
15674
15810
  const idiomaticGetters = options.idiomaticGetters ?? false;
15675
15811
  const forceAliases = new Set(
@@ -15700,18 +15836,30 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
15700
15836
  inlineRunJavascript,
15701
15837
  idiomaticGetters
15702
15838
  }),
15703
- force
15839
+ { recompute: force, recomputeOnError: true }
15704
15840
  )
15705
15841
  );
15706
15842
  });
15707
15843
  const columnStepSource = columnSteps.length > 0 ? columnSteps.join("\n") : ` .withColumn('noop', () => null)`;
15708
- const metadataColumnSource = renderMetadataColumnStep(config);
15844
+ const metadataColumnSource = renderMetadataColumnStep(
15845
+ config,
15846
+ compatibility.metadataCellPolicySource
15847
+ );
15848
+ const generatedAliases = collectGeneratedAliases(config.commands);
15709
15849
  const body = [
15710
15850
  `export default definePlay(${stringLiteral(playName)}, async (ctx, input: EnrichInput) => {`,
15711
15851
  ` const sourceRows = await ctx.csv<Record<string, unknown>>(input.file);`,
15712
15852
  ` const rowStart = __dlNonNegativeInteger(input.rowStart, 0);`,
15713
15853
  ` const rowEndExclusive = Number.isFinite(input.rowEnd) ? Math.max(rowStart, __dlWholeNumber(input.rowEnd, rowStart) + 1) : undefined;`,
15714
- ` const rows = sourceRows.slice(rowStart, rowEndExclusive, { key: 'deepline_enrich_selected_rows', sourceLabel: 'Selected enrich rows' });`,
15854
+ ` const rows: Array<Record<string, unknown>> = [];`,
15855
+ ` let sourceRowIndex = 0;`,
15856
+ ` for await (const row of sourceRows) {`,
15857
+ ` if (rowEndExclusive !== undefined && sourceRowIndex >= rowEndExclusive) break;`,
15858
+ ` if (sourceRowIndex >= rowStart) {`,
15859
+ ` rows.push(__dlPrepareEnrichRow(row, ${stableJson(generatedAliases)}));`,
15860
+ ` }`,
15861
+ ` sourceRowIndex += 1;`,
15862
+ ` }`,
15715
15863
  ` const enriched = await ctx`,
15716
15864
  ` .dataset(${stringLiteral(mapName)}, rows)`,
15717
15865
  columnStepSource,
@@ -15797,6 +15945,18 @@ function helperSource() {
15797
15945
  ` return null;`,
15798
15946
  `}`,
15799
15947
  ``,
15948
+ `function __dlMetadataFromRow(row: Record<string, unknown>): unknown {`,
15949
+ ` const direct = __dlParseMetadata(row._metadata);`,
15950
+ ` if (direct) return direct;`,
15951
+ ` const relocated = __dlParseMetadata(row.metadata);`,
15952
+ ` if (relocated) return relocated;`,
15953
+ ` const dotted = __dlParseMetadata(row['metadata.columns']);`,
15954
+ ` if (dotted) return { columns: dotted };`,
15955
+ ` const underscored = __dlParseMetadata(row.metadata__columns);`,
15956
+ ` if (underscored) return { columns: underscored };`,
15957
+ ` return row._metadata;`,
15958
+ `}`,
15959
+ ``,
15800
15960
  `function __dlMergeMetadata(existing: unknown, patch: Record<string, unknown>): Record<string, unknown> {`,
15801
15961
  ` const base = __dlParseMetadata(existing) ?? {};`,
15802
15962
  ` const baseColumns = __dlRecord(base.columns) ? base.columns : {};`,
@@ -15830,17 +15990,55 @@ function helperSource() {
15830
15990
  ` return parts;`,
15831
15991
  `}`,
15832
15992
  ``,
15993
+ `function __dlNormalizeHeader(value: string): string {`,
15994
+ ` return value.trim().replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');`,
15995
+ `}`,
15996
+ ``,
15997
+ `function __dlOwnStringKeys(record: Record<string, unknown>): string[] {`,
15998
+ ` return Object.keys(record);`,
15999
+ `}`,
16000
+ ``,
16001
+ `function __dlReadOwnField(record: Record<string, unknown>, key: string): unknown {`,
16002
+ ` return record[key];`,
16003
+ `}`,
16004
+ ``,
16005
+ `function __dlGetNormalizedKey(record: Record<string, unknown>, part: string): string | null {`,
16006
+ ` const normalized = __dlNormalizeHeader(part);`,
16007
+ ` for (const key of __dlOwnStringKeys(record)) {`,
16008
+ ` if (__dlNormalizeHeader(key) === normalized) return key;`,
16009
+ ` }`,
16010
+ ` return null;`,
16011
+ `}`,
16012
+ ``,
16013
+ `function __dlGetRecordField(record: Record<string, unknown>, part: string): { found: boolean; value: unknown } {`,
16014
+ ` if (part in record) return { found: true, value: record[part] };`,
16015
+ ` const normalizedKey = __dlGetNormalizedKey(record, part);`,
16016
+ ` if (normalizedKey) return { found: true, value: __dlReadOwnField(record, normalizedKey) };`,
16017
+ ` const projectedValues = record.__deeplineCsvProjectedValues;`,
16018
+ ` if (projectedValues && typeof projectedValues === 'object' && !Array.isArray(projectedValues)) {`,
16019
+ ` const projectedRecord = projectedValues as Record<string, unknown>;`,
16020
+ ` if (part in projectedRecord) return { found: true, value: projectedRecord[part] };`,
16021
+ ` const projectedKey = __dlGetNormalizedKey(projectedRecord, part);`,
16022
+ ` if (projectedKey) return { found: true, value: __dlReadOwnField(projectedRecord, projectedKey) };`,
16023
+ ` }`,
16024
+ ` const data = record.data;`,
16025
+ ` if (data && typeof data === 'object' && !Array.isArray(data)) {`,
16026
+ ` const dataRecord = data as Record<string, unknown>;`,
16027
+ ` if (part in dataRecord) return { found: true, value: dataRecord[part] };`,
16028
+ ` const dataKey = __dlGetNormalizedKey(dataRecord, part);`,
16029
+ ` if (dataKey) return { found: true, value: __dlReadOwnField(dataRecord, dataKey) };`,
16030
+ ` }`,
16031
+ ` return { found: false, value: undefined };`,
16032
+ `}`,
16033
+ ``,
15833
16034
  `function __dlGetByPath(root: unknown, path: string): unknown {`,
15834
16035
  ` let cursor = root;`,
15835
16036
  ` for (const part of __dlPathParts(path)) {`,
15836
16037
  ` if (!cursor || typeof cursor !== 'object') return undefined;`,
15837
16038
  ` const record = cursor as Record<string, unknown>;`,
15838
- ` if (part in record) {`,
15839
- ` cursor = record[part];`,
15840
- ` continue;`,
15841
- ` }`,
15842
- ` const data = record.data;`,
15843
- ` cursor = data && typeof data === 'object' ? (data as Record<string, unknown>)[part] : undefined;`,
16039
+ ` const field = __dlGetRecordField(record, part);`,
16040
+ ` if (!field.found) return undefined;`,
16041
+ ` cursor = field.value;`,
15844
16042
  ` }`,
15845
16043
  ` return cursor;`,
15846
16044
  `}`,
@@ -15871,6 +16069,64 @@ function helperSource() {
15871
16069
  ` return status === 'error' || status === 'failed' || (typeof record.error === 'string' && record.error.trim() !== '') || (typeof resultError === 'string' && resultError.trim() !== '');`,
15872
16070
  `}`,
15873
16071
  ``,
16072
+ `function __dlGeneratedCellError(value: unknown): boolean {`,
16073
+ ` if (typeof value === 'string') {`,
16074
+ ` const lower = value.trim().toLowerCase();`,
16075
+ ` if (!lower) return false;`,
16076
+ ` if (lower.startsWith('error:') || lower.includes(': error:') || lower.includes('"error"')) return true;`,
16077
+ ` try {`,
16078
+ ` return __dlGeneratedCellError(JSON.parse(value));`,
16079
+ ` } catch {`,
16080
+ ` return false;`,
16081
+ ` }`,
16082
+ ` }`,
16083
+ ` if (!__dlRecord(value)) return false;`,
16084
+ ` const status = typeof value.status === 'string' ? value.status.toLowerCase() : '';`,
16085
+ ` if (status === 'error' || status === 'failed') return true;`,
16086
+ ` if (typeof value.error === 'string' && value.error.trim() !== '') return true;`,
16087
+ ` const raw = __dlGetByPath(value, 'toolResponse.raw') ?? __dlGetByPath(value, 'toolOutput.raw');`,
16088
+ ` if (raw !== undefined && raw !== value && __dlGeneratedCellError(raw)) return true;`,
16089
+ ` const result = value.result;`,
16090
+ ` return result !== undefined && result !== value && __dlGeneratedCellError(result);`,
16091
+ `}`,
16092
+ ``,
16093
+ `function __dlStripErroredGeneratedColumns(row: Record<string, unknown>, aliases: string[]): Record<string, unknown> {`,
16094
+ ` let next: Record<string, unknown> | null = null;`,
16095
+ ` for (const alias of aliases) {`,
16096
+ ` for (const key of __dlAliasCandidates(alias)) {`,
16097
+ ` if (key in row && __dlGeneratedCellError(row[key])) {`,
16098
+ ` if (next === null) next = { ...row };`,
16099
+ ` delete next[key];`,
16100
+ ` }`,
16101
+ ` }`,
16102
+ ` }`,
16103
+ ` return next ?? row;`,
16104
+ `}`,
16105
+ ``,
16106
+ `function __dlTemplateContext(row: Record<string, unknown>): Record<string, unknown> {`,
16107
+ ` const context: Record<string, unknown> = {};`,
16108
+ ` const projectedValues = row.__deeplineCsvProjectedValues;`,
16109
+ ` if (__dlRecord(projectedValues)) {`,
16110
+ ` for (const [key, value] of Object.entries(projectedValues)) context[key] = value;`,
16111
+ ` }`,
16112
+ ` for (const [key, value] of Object.entries(row)) {`,
16113
+ ` if (key.startsWith('__deepline')) continue;`,
16114
+ ` context[key] = value;`,
16115
+ ` }`,
16116
+ ` return context;`,
16117
+ `}`,
16118
+ ``,
16119
+ `function __dlPrepareEnrichRow(row: Record<string, unknown>, aliases: string[]): Record<string, unknown> {`,
16120
+ ` const cleaned = __dlStripErroredGeneratedColumns(row, aliases);`,
16121
+ ` const templateContext = __dlTemplateContext(cleaned);`,
16122
+ ` return {`,
16123
+ ` ...templateContext,`,
16124
+ ` ...cleaned,`,
16125
+ ` __deeplineCsvProjectedFields: Object.keys(templateContext),`,
16126
+ ` __deeplineCsvProjectedValues: templateContext,`,
16127
+ ` };`,
16128
+ `}`,
16129
+ ``,
15874
16130
  `function __dlRawToolOutput(result: unknown): unknown {`,
15875
16131
  ` if (!result || typeof result !== 'object') return result;`,
15876
16132
  ` const record = result as Record<string, unknown>;`,
@@ -16281,7 +16537,7 @@ function helperSource() {
16281
16537
  ` tool: input.tool,`,
16282
16538
  ` input: payload,`,
16283
16539
  ` ...(input.description ? { description: input.description } : {}),`,
16284
- ` ...(input.force ? { staleAfterSeconds: 1 } : {}),`,
16540
+ ` ...(input.force ? { force: true } : {}),`,
16285
16541
  ` });`,
16286
16542
  ` return __dlExtract(input.alias, result, input.row, input.extract, Boolean(input.legacyEnvelope));`,
16287
16543
  `}`
@@ -16908,7 +17164,7 @@ async function resolveWatchedGeneratedPlayStatus(input2) {
16908
17164
  }
16909
17165
  return input2.client.runs.get(runId, { full: true });
16910
17166
  }
16911
- function isRecord6(value) {
17167
+ function isRecord7(value) {
16912
17168
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
16913
17169
  }
16914
17170
  async function captureStdout(run, options = {}) {
@@ -16956,12 +17212,12 @@ async function writeOutputCsv(outputPath, status, options) {
16956
17212
  if (!rowsInfo) {
16957
17213
  throw new Error("The generated play did not return row-shaped output.");
16958
17214
  }
16959
- if (!rowsInfo.complete && options?.client) {
17215
+ if (options?.client) {
16960
17216
  rowsInfo = await fetchBackingRowsForCsvExport({
16961
17217
  client: options.client,
16962
17218
  status,
16963
17219
  rowsInfo
16964
- }) ?? rowsInfo;
17220
+ }).catch(() => null) ?? rowsInfo;
16965
17221
  }
16966
17222
  assertCompleteRowsForCsvExport(rowsInfo, status, outputPath);
16967
17223
  const merged = mergeRowsForCsvExport(rowsInfo.rows, options);
@@ -16977,10 +17233,14 @@ async function writeOutputCsv(outputPath, status, options) {
16977
17233
  csvStringFromRows(merged.rows, columns),
16978
17234
  "utf8"
16979
17235
  );
17236
+ const sourceCsvRows = options?.sourceCsvPath ? readCsvRows(options.sourceCsvPath).length : null;
16980
17237
  return {
17238
+ sourceCsvRows,
17239
+ selectedRows: rowsInfo.totalRows,
17240
+ enrichedRows: rowsInfo.rows.length,
16981
17241
  rows: merged.rows.length,
16982
17242
  path: (0, import_node_path13.resolve)(outputPath),
16983
- enrichedRows: rowsInfo.rows
17243
+ enrichedDataRows: rowsInfo.rows
16984
17244
  };
16985
17245
  }
16986
17246
  function recordField(value, key) {
@@ -17061,12 +17321,12 @@ function collectHardFailureAliases(config) {
17061
17321
  }
17062
17322
  function cellFailureError(value) {
17063
17323
  const parsed = parseMaybeJsonObject(value);
17064
- if (!isRecord6(parsed)) {
17324
+ if (!isRecord7(parsed)) {
17065
17325
  return null;
17066
17326
  }
17067
17327
  const status = typeof parsed.status === "string" ? parsed.status.trim().toLowerCase() : "";
17068
17328
  const directError = typeof parsed.error === "string" ? parsed.error.trim() : typeof parsed.last_error === "string" ? parsed.last_error.trim() : "";
17069
- const result = isRecord6(parsed.result) ? parsed.result : null;
17329
+ const result = isRecord7(parsed.result) ? parsed.result : null;
17070
17330
  const resultError = typeof result?.error === "string" ? result.error.trim() : typeof result?.message === "string" ? result.message.trim() : "";
17071
17331
  if (!directError && !resultError && status !== "error" && status !== "failed") {
17072
17332
  return null;
@@ -17132,6 +17392,136 @@ function collectEnrichFailureJobs(input2) {
17132
17392
  });
17133
17393
  return jobs;
17134
17394
  }
17395
+ function parseExecutionCount(value) {
17396
+ if (typeof value === "number" && Number.isFinite(value)) {
17397
+ return Math.max(0, Math.trunc(value));
17398
+ }
17399
+ if (typeof value !== "string") {
17400
+ return null;
17401
+ }
17402
+ const match = value.trim().match(/^(\d+)\s*\//);
17403
+ return match?.[1] ? Number.parseInt(match[1], 10) : null;
17404
+ }
17405
+ function executionSummaryText(count, total) {
17406
+ const percent = total > 0 ? Math.round(count / total * 100) : 0;
17407
+ return `${count}/${total} (${percent}%)`;
17408
+ }
17409
+ function collectColumnStats(status) {
17410
+ const summaries = [];
17411
+ const visit = (value) => {
17412
+ if (Array.isArray(value)) {
17413
+ value.forEach(visit);
17414
+ return;
17415
+ }
17416
+ if (!isRecord7(value)) {
17417
+ return;
17418
+ }
17419
+ if (isRecord7(value.columnStats)) {
17420
+ summaries.push(value.columnStats);
17421
+ }
17422
+ Object.values(value).forEach(visit);
17423
+ };
17424
+ visit(status);
17425
+ return summaries;
17426
+ }
17427
+ function firstAliasExecutionCounts(input2) {
17428
+ const aliases = collectConfigScalarAliasOrder(input2.config);
17429
+ const summaries = collectColumnStats(input2.status);
17430
+ for (const alias of aliases) {
17431
+ const stat4 = summaries.map((summary) => summary[alias]).find(isRecord7);
17432
+ if (!stat4) continue;
17433
+ if (input2.forceAliases.has(normalizeAlias2(alias))) {
17434
+ return { executed: input2.selectedRows, reused: 0 };
17435
+ }
17436
+ const execution = isRecord7(stat4.execution) ? stat4.execution : null;
17437
+ if (!execution) continue;
17438
+ return {
17439
+ executed: parseExecutionCount(execution["completed:executed"]),
17440
+ reused: parseExecutionCount(execution["completed:reused"])
17441
+ };
17442
+ }
17443
+ return { executed: null, reused: null };
17444
+ }
17445
+ function rewriteEnrichJsonStatus(input2) {
17446
+ const selectedRows = input2.output?.selectedRows ?? extractCanonicalRowsInfo(input2.status)?.totalRows ?? 0;
17447
+ const failedRows = new Set(
17448
+ input2.failureReport?.jobs.map((job) => job.row_id) ?? []
17449
+ ).size;
17450
+ const executionCounts = firstAliasExecutionCounts({
17451
+ status: input2.status,
17452
+ config: input2.config,
17453
+ forceAliases: input2.forceAliases,
17454
+ selectedRows
17455
+ });
17456
+ const forcedAliases = new Set(
17457
+ collectConfigScalarAliasOrder(input2.config).filter((alias) => input2.forceAliases.has(normalizeAlias2(alias))).map((alias) => alias)
17458
+ );
17459
+ const rewrite = (value) => {
17460
+ if (Array.isArray(value)) {
17461
+ return value.map(rewrite);
17462
+ }
17463
+ if (!isRecord7(value)) {
17464
+ return value;
17465
+ }
17466
+ const next = {};
17467
+ for (const [key, entry] of Object.entries(value)) {
17468
+ next[key] = rewrite(entry);
17469
+ }
17470
+ if (isRecord7(next.progress)) {
17471
+ next.progress = {
17472
+ ...next.progress,
17473
+ ...selectedRows > 0 ? { total: selectedRows } : {},
17474
+ ...executionCounts.executed !== null ? { executed: executionCounts.executed } : {},
17475
+ ...executionCounts.reused !== null ? { reused: executionCounts.reused } : {},
17476
+ ...failedRows > 0 ? { failed: failedRows, pending: 0 } : {}
17477
+ };
17478
+ }
17479
+ if (isRecord7(next.summary)) {
17480
+ const rowCounts = isRecord7(next.summary.rowCounts) ? next.summary.rowCounts : null;
17481
+ if (failedRows > 0) {
17482
+ next.summary = {
17483
+ ...next.summary,
17484
+ rowCounts: {
17485
+ ...rowCounts ?? {},
17486
+ persisted: selectedRows,
17487
+ succeeded: Math.max(0, selectedRows - failedRows),
17488
+ failed: failedRows
17489
+ }
17490
+ };
17491
+ }
17492
+ }
17493
+ if (isRecord7(next.columnStats) && selectedRows > 0) {
17494
+ const columnStats = { ...next.columnStats };
17495
+ for (const alias of forcedAliases) {
17496
+ const stat4 = isRecord7(columnStats[alias]) ? columnStats[alias] : null;
17497
+ const execution = isRecord7(stat4?.execution) ? stat4.execution : null;
17498
+ if (!stat4 || !execution) continue;
17499
+ columnStats[alias] = {
17500
+ ...stat4,
17501
+ execution: {
17502
+ ...execution,
17503
+ "completed:executed": executionSummaryText(
17504
+ selectedRows,
17505
+ selectedRows
17506
+ ),
17507
+ "completed:reused": executionSummaryText(0, selectedRows)
17508
+ }
17509
+ };
17510
+ }
17511
+ next.columnStats = columnStats;
17512
+ }
17513
+ return next;
17514
+ };
17515
+ const rewritten = rewrite(input2.status);
17516
+ if (failedRows === 0 || !isRecord7(rewritten)) {
17517
+ return rewritten;
17518
+ }
17519
+ return {
17520
+ ...rewritten,
17521
+ ...rewritten.status === "completed" ? { status: "failed" } : {},
17522
+ ...isRecord7(rewritten.run) && rewritten.run.status === "completed" ? { run: { ...rewritten.run, status: "failed" } } : {}
17523
+ };
17524
+ }
17135
17525
  function summarizeFailedJobError(value) {
17136
17526
  const text = String(value ?? "").trim();
17137
17527
  return text.length > 500 ? `${text.slice(0, 497)}...` : text;
@@ -17400,11 +17790,11 @@ function normalizeEnrichRowsForCsvExport(rows) {
17400
17790
  }
17401
17791
  function legacyMetadataFromRow(row) {
17402
17792
  const direct = parseLegacyMetadataCell(row._metadata);
17403
- if (direct && isRecord6(direct.columns)) {
17793
+ if (direct && isRecord7(direct.columns)) {
17404
17794
  return direct;
17405
17795
  }
17406
17796
  const relocated = parseLegacyMetadataCell(row.metadata);
17407
- if (relocated && isRecord6(relocated.columns)) {
17797
+ if (relocated && isRecord7(relocated.columns)) {
17408
17798
  return relocated;
17409
17799
  }
17410
17800
  const flattenedColumns = parseLegacyMetadataCell(row["metadata.columns"]);
@@ -17421,7 +17811,7 @@ function legacyMetadataFromRow(row) {
17421
17811
  }
17422
17812
  function parseLegacyMetadataCell(value) {
17423
17813
  const parsed = parseMaybeJsonObject(value);
17424
- if (isRecord6(parsed)) {
17814
+ if (isRecord7(parsed)) {
17425
17815
  return parsed;
17426
17816
  }
17427
17817
  if (typeof value !== "string") {
@@ -17438,12 +17828,12 @@ function parseLegacyMetadataCell(value) {
17438
17828
  for (const candidate of candidates) {
17439
17829
  try {
17440
17830
  const decoded = JSON.parse(candidate);
17441
- if (isRecord6(decoded)) {
17831
+ if (isRecord7(decoded)) {
17442
17832
  return decoded;
17443
17833
  }
17444
17834
  if (typeof decoded === "string") {
17445
17835
  const nested = JSON.parse(decoded);
17446
- if (isRecord6(nested)) {
17836
+ if (isRecord7(nested)) {
17447
17837
  return nested;
17448
17838
  }
17449
17839
  }
@@ -17453,8 +17843,8 @@ function parseLegacyMetadataCell(value) {
17453
17843
  return null;
17454
17844
  }
17455
17845
  function mergeLegacyMetadataRecords(base, enriched) {
17456
- const baseColumns = isRecord6(base.columns) ? base.columns : null;
17457
- const enrichedColumns = isRecord6(enriched.columns) ? enriched.columns : null;
17846
+ const baseColumns = isRecord7(base.columns) ? base.columns : null;
17847
+ const enrichedColumns = isRecord7(enriched.columns) ? enriched.columns : null;
17458
17848
  const merged = {
17459
17849
  ...base,
17460
17850
  ...enriched
@@ -17656,7 +18046,7 @@ function registerEnrichCommand(program) {
17656
18046
  sourceCsvPath,
17657
18047
  rows
17658
18048
  }) : null;
17659
- const rowsForFailureReport = exportResult?.enrichedRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
18049
+ const rowsForFailureReport = exportResult?.enrichedDataRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
17660
18050
  if (options.json) {
17661
18051
  const failureReport2 = await maybeEmitEnrichFailureReport({
17662
18052
  config,
@@ -17665,10 +18055,22 @@ function registerEnrichCommand(program) {
17665
18055
  client: client2,
17666
18056
  outputPath: exportResult?.path ?? outputPath ?? null
17667
18057
  });
18058
+ const run = rewriteEnrichJsonStatus({
18059
+ status,
18060
+ config,
18061
+ forceAliases,
18062
+ output: exportResult,
18063
+ failureReport: failureReport2
18064
+ });
17668
18065
  printJson({
17669
18066
  ok: !failureReport2,
17670
- run: status,
17671
- output: exportResult ? { rows: exportResult.rows, path: exportResult.path } : null,
18067
+ run,
18068
+ output: exportResult ? {
18069
+ sourceCsvRows: exportResult.sourceCsvRows,
18070
+ selectedRows: exportResult.selectedRows,
18071
+ enrichedRows: exportResult.enrichedRows,
18072
+ path: exportResult.path
18073
+ } : null,
17672
18074
  ...failureReport2 ? {
17673
18075
  failure_report: {
17674
18076
  path: failureReport2.path,
@@ -17688,7 +18090,7 @@ function registerEnrichCommand(program) {
17688
18090
  );
17689
18091
  const waterfallSummaryLines = buildEnrichWaterfallSummaryLines(
17690
18092
  config,
17691
- exportResult.enrichedRows
18093
+ exportResult.enrichedDataRows
17692
18094
  );
17693
18095
  if (waterfallSummaryLines.length > 0) {
17694
18096
  process.stdout.write(`${waterfallSummaryLines.join("\n")}
@@ -17755,6 +18157,129 @@ Examples:
17755
18157
  ).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);
17756
18158
  }
17757
18159
 
18160
+ // src/cli/commands/legacy-noops.ts
18161
+ var SESSION_SUBCOMMANDS = [
18162
+ "start",
18163
+ "status",
18164
+ "output",
18165
+ "alert",
18166
+ "usage",
18167
+ "limit",
18168
+ "render",
18169
+ "send"
18170
+ ];
18171
+ var BACKEND_SUBCOMMANDS = [
18172
+ "start",
18173
+ "stop",
18174
+ "status",
18175
+ "refresh-runtime",
18176
+ "sync-runtime"
18177
+ ];
18178
+ function legacyNoopEnvelope(input2) {
18179
+ const command = [
18180
+ "deepline",
18181
+ input2.family,
18182
+ input2.subcommand
18183
+ ].filter(Boolean).join(" ");
18184
+ const subject = input2.family === "session" ? "Legacy Session UI/playground command" : "Legacy local playground backend command";
18185
+ 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.";
18186
+ return {
18187
+ ok: true,
18188
+ noop: true,
18189
+ command,
18190
+ compatibility: {
18191
+ family: "legacy_python_cli",
18192
+ sdk_behavior: "noop"
18193
+ },
18194
+ render: {
18195
+ sections: [
18196
+ {
18197
+ title: subject,
18198
+ lines: [note]
18199
+ }
18200
+ ]
18201
+ }
18202
+ };
18203
+ }
18204
+ function printLegacyNoop(input2) {
18205
+ printCommandEnvelope(legacyNoopEnvelope(input2), { json: input2.options.json });
18206
+ }
18207
+ function legacySubcommandFromArgv(family) {
18208
+ const args = process.argv.slice(2);
18209
+ const familyIndex = args.indexOf(family);
18210
+ const nextToken = familyIndex >= 0 ? args[familyIndex + 1] : void 0;
18211
+ return nextToken && !nextToken.startsWith("-") ? nextToken : void 0;
18212
+ }
18213
+ function addLegacyNoopSubcommand(parent, family, subcommand, description) {
18214
+ parent.command(subcommand).description(description).allowUnknownOption(true).allowExcessArguments(true).option("--json", "Emit JSON output").argument("[args...]").action((_args, options) => {
18215
+ printLegacyNoop({ family, subcommand, options });
18216
+ });
18217
+ }
18218
+ function registerLegacyNoopCommands(program) {
18219
+ const session = program.command("session").description(
18220
+ "Compatibility no-ops for legacy Python Session UI commands."
18221
+ ).allowUnknownOption(true).allowExcessArguments(true).option("--json", "Emit JSON output").argument("[args...]").addHelpText(
18222
+ "after",
18223
+ `
18224
+ Notes:
18225
+ The SDK CLI accepts singular session commands from older agent skills so they
18226
+ do not fail, but it does not manage the legacy Python Session UI.
18227
+ Use "deepline sessions send" or "deepline sessions render" for real SDK
18228
+ transcript workflows.
18229
+
18230
+ Examples:
18231
+ deepline session start --steps '["Inspect CSV","Run pilot"]'
18232
+ deepline session status --message "Running pilot"
18233
+ deepline session output --csv ./results.csv --label "Results"
18234
+ `
18235
+ ).action((args, options) => {
18236
+ void args;
18237
+ printLegacyNoop({
18238
+ family: "session",
18239
+ subcommand: legacySubcommandFromArgv("session"),
18240
+ options
18241
+ });
18242
+ });
18243
+ for (const subcommand of SESSION_SUBCOMMANDS) {
18244
+ addLegacyNoopSubcommand(
18245
+ session,
18246
+ "session",
18247
+ subcommand,
18248
+ `Accept legacy "deepline session ${subcommand}" as an SDK no-op.`
18249
+ );
18250
+ }
18251
+ const backend = program.command("backend").description(
18252
+ "Compatibility no-ops for legacy Python local backend commands."
18253
+ ).allowUnknownOption(true).allowExcessArguments(true).option("--json", "Emit JSON output").argument("[args...]").addHelpText(
18254
+ "after",
18255
+ `
18256
+ Notes:
18257
+ The SDK CLI uses the configured Deepline host and V2 play runtime. It does not
18258
+ start, stop, or refresh the legacy Python local playground backend.
18259
+
18260
+ Examples:
18261
+ deepline backend start
18262
+ deepline backend stop --just-backend
18263
+ deepline backend status --json
18264
+ `
18265
+ ).action((args, options) => {
18266
+ void args;
18267
+ printLegacyNoop({
18268
+ family: "backend",
18269
+ subcommand: legacySubcommandFromArgv("backend"),
18270
+ options
18271
+ });
18272
+ });
18273
+ for (const subcommand of BACKEND_SUBCOMMANDS) {
18274
+ addLegacyNoopSubcommand(
18275
+ backend,
18276
+ "backend",
18277
+ subcommand,
18278
+ `Accept legacy "deepline backend ${subcommand}" as an SDK no-op.`
18279
+ );
18280
+ }
18281
+ }
18282
+
17758
18283
  // src/cli/commands/org.ts
17759
18284
  async function fetchOrganizations(http, apiKey) {
17760
18285
  return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
@@ -19657,11 +20182,13 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
19657
20182
  "deeplineUsdPerPricingUnit",
19658
20183
  "deepline_usd_per_pricing_unit"
19659
20184
  );
19660
- const starterScript = seedToolListScript({
19661
- toolId,
19662
- payload: samplePayloadForInputFields(inputFields),
19663
- rows: []
19664
- });
20185
+ const starterScript = extractedLists.length > 0 ? starterScriptJson(
20186
+ seedToolListScript({
20187
+ toolId,
20188
+ payload: samplePayloadForInputFields(inputFields),
20189
+ rows: []
20190
+ })
20191
+ ) : null;
19665
20192
  return {
19666
20193
  schemaVersion: 1,
19667
20194
  toolId,
@@ -19687,20 +20214,12 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
19687
20214
  extractedValues
19688
20215
  },
19689
20216
  executeCommand: `deepline tools execute ${toolId} --input '{...}' --json`,
19690
- starterScript: {
19691
- path: starterScript.path,
19692
- sourceCode: starterScript.sourceCode,
19693
- projectDir: starterScript.projectDir,
19694
- copyToProject: {
19695
- macosLinux: starterScript.macCopyCommand,
19696
- windowsPowerShell: starterScript.windowsCopyCommand
19697
- }
19698
- }
20217
+ ...starterScript ? { starterScript } : {}
19699
20218
  };
19700
20219
  }
19701
20220
  function extractionContractEntries(entries) {
19702
20221
  return entries.flatMap((entry) => {
19703
- if (!isRecord7(entry)) return [];
20222
+ if (!isRecord8(entry)) return [];
19704
20223
  const name = stringField(entry, "name");
19705
20224
  const expression = stringField(entry, "expression");
19706
20225
  return name && expression ? [{ name, expression }] : [];
@@ -19708,8 +20227,8 @@ function extractionContractEntries(entries) {
19708
20227
  }
19709
20228
  function printCompactToolContract(tool, requestedToolId) {
19710
20229
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
19711
- const cost = isRecord7(contract.cost) ? contract.cost : {};
19712
- const getters = isRecord7(contract.getters) ? contract.getters : {};
20230
+ const cost = isRecord8(contract.cost) ? contract.cost : {};
20231
+ const getters = isRecord8(contract.getters) ? contract.getters : {};
19713
20232
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
19714
20233
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
19715
20234
  const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
@@ -19726,7 +20245,7 @@ function printCompactToolContract(tool, requestedToolId) {
19726
20245
  console.log("");
19727
20246
  console.log("Inputs:");
19728
20247
  for (const field of inputFields) {
19729
- if (!isRecord7(field)) continue;
20248
+ if (!isRecord8(field)) continue;
19730
20249
  const name = stringField(field, "name");
19731
20250
  if (!name) continue;
19732
20251
  const required = field.required ? "*" : "";
@@ -19739,7 +20258,7 @@ function printCompactToolContract(tool, requestedToolId) {
19739
20258
  }
19740
20259
  console.log("");
19741
20260
  printToolExamplesOnly(tool, requestedToolId, { includeSamples: false });
19742
- const starterScript = isRecord7(contract.starterScript) ? contract.starterScript : {};
20261
+ const starterScript = isRecord8(contract.starterScript) ? contract.starterScript : {};
19743
20262
  const starterPath = stringField(starterScript, "path");
19744
20263
  if (starterPath) {
19745
20264
  console.log("");
@@ -19753,14 +20272,14 @@ function printCompactToolContract(tool, requestedToolId) {
19753
20272
  console.log("Getters:");
19754
20273
  if (listGetters.length) console.log("Lists:");
19755
20274
  for (const entry of listGetters) {
19756
- if (isRecord7(entry))
20275
+ if (isRecord8(entry))
19757
20276
  console.log(
19758
20277
  `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
19759
20278
  );
19760
20279
  }
19761
20280
  if (valueGetters.length) console.log("Values:");
19762
20281
  for (const entry of valueGetters) {
19763
- if (isRecord7(entry))
20282
+ if (isRecord8(entry))
19764
20283
  console.log(
19765
20284
  `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
19766
20285
  );
@@ -19773,7 +20292,7 @@ function printCompactToolContract(tool, requestedToolId) {
19773
20292
  }
19774
20293
  function printToolPricingOnly(tool, requestedToolId, options = {}) {
19775
20294
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
19776
- const cost = isRecord7(contract.cost) ? contract.cost : {};
20295
+ const cost = isRecord8(contract.cost) ? contract.cost : {};
19777
20296
  const pricingModel = stringField(cost, "pricingModel") || "unknown";
19778
20297
  const billingMode = stringField(cost, "billingMode") || "unknown";
19779
20298
  const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : pricingModel === "fixed" ? "call" : pricingModel.replace(/^per_/, "") || "unit";
@@ -19793,7 +20312,7 @@ function printToolSchemaOnly(tool, requestedToolId) {
19793
20312
  }
19794
20313
  console.log("Inputs:");
19795
20314
  for (const field of inputFields) {
19796
- if (!isRecord7(field)) continue;
20315
+ if (!isRecord8(field)) continue;
19797
20316
  const name = stringField(field, "name");
19798
20317
  if (!name) continue;
19799
20318
  const required = field.required ? "*" : "";
@@ -19819,10 +20338,10 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
19819
20338
  ` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`
19820
20339
  );
19821
20340
  console.log("});");
19822
- const getters = isRecord7(contract.getters) ? contract.getters : {};
20341
+ const getters = isRecord8(contract.getters) ? contract.getters : {};
19823
20342
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
19824
20343
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
19825
- const firstGetter = [...valueGetters, ...listGetters].find(isRecord7);
20344
+ const firstGetter = [...valueGetters, ...listGetters].find(isRecord8);
19826
20345
  if (firstGetter) {
19827
20346
  const name = stringField(firstGetter, "name") || "value";
19828
20347
  const expression = stringField(firstGetter, "expression");
@@ -19839,7 +20358,7 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
19839
20358
  }
19840
20359
  function printToolGettersOnly(tool, requestedToolId) {
19841
20360
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
19842
- const getters = isRecord7(contract.getters) ? contract.getters : {};
20361
+ const getters = isRecord8(contract.getters) ? contract.getters : {};
19843
20362
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
19844
20363
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
19845
20364
  console.log(`Getters: ${contract.toolId}`);
@@ -19852,7 +20371,7 @@ function printToolGettersOnly(tool, requestedToolId) {
19852
20371
  if (listGetters.length) {
19853
20372
  console.log("Lists:");
19854
20373
  for (const entry of listGetters) {
19855
- if (isRecord7(entry))
20374
+ if (isRecord8(entry))
19856
20375
  console.log(
19857
20376
  `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
19858
20377
  );
@@ -19861,7 +20380,7 @@ function printToolGettersOnly(tool, requestedToolId) {
19861
20380
  if (valueGetters.length) {
19862
20381
  console.log("Values:");
19863
20382
  for (const entry of valueGetters) {
19864
- if (isRecord7(entry))
20383
+ if (isRecord8(entry))
19865
20384
  console.log(
19866
20385
  `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
19867
20386
  );
@@ -19887,7 +20406,7 @@ function sampleValueForField(field) {
19887
20406
  function samplePayloadForInputFields(fields) {
19888
20407
  return Object.fromEntries(
19889
20408
  fields.slice(0, 4).flatMap((field) => {
19890
- if (!isRecord7(field)) return [];
20409
+ if (!isRecord8(field)) return [];
19891
20410
  const name = stringField(field, "name");
19892
20411
  if (!name) return [];
19893
20412
  return [[name, sampleValueForField(field)]];
@@ -19912,11 +20431,24 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
19912
20431
  const inputFields = toolInputFieldsForDisplay(
19913
20432
  recordField2(tool, "inputSchema", "input_schema")
19914
20433
  );
19915
- const starterScript = seedToolListScript({
19916
- toolId,
19917
- payload: samplePayloadForInputFields(inputFields),
19918
- rows: []
19919
- });
20434
+ const usageGuidance = usageGuidanceWithAccessDefaults(
20435
+ recordField2(tool, "usageGuidance", "usage_guidance")
20436
+ );
20437
+ const toolExecutionResult = recordField2(
20438
+ usageGuidance,
20439
+ "toolExecutionResult",
20440
+ "tool_execution_result"
20441
+ );
20442
+ const extractedLists = extractionContractEntries(
20443
+ arrayField(toolExecutionResult, "extractedLists", "extracted_lists")
20444
+ );
20445
+ const starterScript = extractedLists.length > 0 ? starterScriptJson(
20446
+ seedToolListScript({
20447
+ toolId,
20448
+ payload: samplePayloadForInputFields(inputFields),
20449
+ rows: []
20450
+ })
20451
+ ) : null;
19920
20452
  const {
19921
20453
  cost: _cost,
19922
20454
  deeplineCreditsPerPricingUnit: _deeplineCreditsPerPricingUnit,
@@ -19936,9 +20468,7 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
19936
20468
  toolId,
19937
20469
  provider: tool.provider,
19938
20470
  displayName: tool.displayName,
19939
- usageGuidance: usageGuidanceWithAccessDefaults(
19940
- recordField2(tool, "usageGuidance", "usage_guidance")
19941
- ),
20471
+ usageGuidance,
19942
20472
  runtimeOutputHelp: {
19943
20473
  contract: "tools describe shows declared schema and Deepline getters; it is not an observed provider response.",
19944
20474
  getterScope: "extractedValues/extractedLists .get() only works for declared Deepline getters listed in usageGuidance.toolExecutionResult.",
@@ -19949,15 +20479,7 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
19949
20479
  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.",
19950
20480
  executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run output and returned dataset handles."
19951
20481
  },
19952
- starterScript: {
19953
- path: starterScript.path,
19954
- sourceCode: starterScript.sourceCode,
19955
- projectDir: starterScript.projectDir,
19956
- copyToProject: {
19957
- macosLinux: starterScript.macCopyCommand,
19958
- windowsPowerShell: starterScript.windowsCopyCommand
19959
- }
19960
- }
20482
+ ...starterScript ? { starterScript } : {}
19961
20483
  };
19962
20484
  }
19963
20485
  function usageGuidanceWithAccessDefaults(usageGuidance) {
@@ -20001,12 +20523,12 @@ function formatListedToolCost(tool) {
20001
20523
  }
20002
20524
  function toolInputFieldsForDisplay(inputSchema) {
20003
20525
  if (Array.isArray(inputSchema.fields))
20004
- return inputSchema.fields.filter(isRecord7);
20005
- const jsonSchema = isRecord7(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
20006
- const properties = isRecord7(jsonSchema.properties) ? jsonSchema.properties : {};
20526
+ return inputSchema.fields.filter(isRecord8);
20527
+ const jsonSchema = isRecord8(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
20528
+ const properties = isRecord8(jsonSchema.properties) ? jsonSchema.properties : {};
20007
20529
  const required = Array.isArray(jsonSchema.required) ? new Set(jsonSchema.required.map(String)) : /* @__PURE__ */ new Set();
20008
20530
  return Object.entries(properties).map(([name, value]) => {
20009
- const property = isRecord7(value) ? value : {};
20531
+ const property = isRecord8(value) ? value : {};
20010
20532
  return {
20011
20533
  name,
20012
20534
  type: typeof property.type === "string" ? property.type : "unknown",
@@ -20035,15 +20557,15 @@ function printJsonPreview(label, payload) {
20035
20557
  }
20036
20558
  function samplePayload(samples, key) {
20037
20559
  const entry = samples[key];
20038
- if (!isRecord7(entry)) return void 0;
20560
+ if (!isRecord8(entry)) return void 0;
20039
20561
  return Object.prototype.hasOwnProperty.call(entry, "payload") ? entry.payload : entry;
20040
20562
  }
20041
20563
  function commandEnvelopeFromRawResponse(rawResponse) {
20042
- return isRecord7(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
20564
+ return isRecord8(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
20043
20565
  }
20044
20566
  function listExtractorPathsFromUsageGuidance(tool) {
20045
20567
  const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
20046
- const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord7(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
20568
+ const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord8(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
20047
20569
  return extractedLists.flatMap((entry) => {
20048
20570
  const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
20049
20571
  if (!Array.isArray(paths)) return [];
@@ -20059,7 +20581,7 @@ function formatDecimal(value) {
20059
20581
  function formatUsd(value) {
20060
20582
  return `$${formatDecimal(value)}`;
20061
20583
  }
20062
- function isRecord7(value) {
20584
+ function isRecord8(value) {
20063
20585
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
20064
20586
  }
20065
20587
  function stringField(source, ...keys) {
@@ -20086,7 +20608,7 @@ function arrayField(source, ...keys) {
20086
20608
  function recordField2(source, ...keys) {
20087
20609
  for (const key of keys) {
20088
20610
  const value = source[key];
20089
- if (isRecord7(value)) return value;
20611
+ if (isRecord8(value)) return value;
20090
20612
  }
20091
20613
  return {};
20092
20614
  }
@@ -20152,7 +20674,7 @@ function parseJsonObjectArgument(raw, flagName) {
20152
20674
  }
20153
20675
  throw invalidJsonError(flagName, message);
20154
20676
  }
20155
- if (!isRecord7(parsed)) {
20677
+ if (!isRecord8(parsed)) {
20156
20678
  throw invalidJsonError(flagName, "expected an object.");
20157
20679
  }
20158
20680
  return parsed;
@@ -20211,6 +20733,17 @@ function shellQuote2(value) {
20211
20733
  function powerShellQuote(value) {
20212
20734
  return `'${value.replace(/'/g, "''")}'`;
20213
20735
  }
20736
+ function starterScriptJson(script) {
20737
+ return {
20738
+ path: script.path,
20739
+ sourceCode: script.sourceCode,
20740
+ projectDir: script.projectDir,
20741
+ copyToProject: {
20742
+ macosLinux: script.macCopyCommand,
20743
+ windowsPowerShell: script.windowsCopyCommand
20744
+ }
20745
+ };
20746
+ }
20214
20747
  function seedToolListScript(input2) {
20215
20748
  const stem = safeFileStem(input2.toolId);
20216
20749
  const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
@@ -20275,7 +20808,7 @@ function buildToolExecuteBaseEnvelope(input2) {
20275
20808
  kind: summaryEntries.length > 0 ? "object" : "raw",
20276
20809
  summary: input2.summary
20277
20810
  };
20278
- const envelopeHasCanonicalOutput = isRecord7(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
20811
+ const envelopeHasCanonicalOutput = isRecord8(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
20279
20812
  const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote2(JSON.stringify(input2.params))} --json`;
20280
20813
  const actions = input2.listConversion ? [
20281
20814
  {
@@ -20384,7 +20917,7 @@ async function executeTool(args) {
20384
20917
  {
20385
20918
  ...baseEnvelope,
20386
20919
  local: {
20387
- ...isRecord7(baseEnvelope.local) ? baseEnvelope.local : {},
20920
+ ...isRecord8(baseEnvelope.local) ? baseEnvelope.local : {},
20388
20921
  payload_file: jsonPath
20389
20922
  }
20390
20923
  },
@@ -21144,10 +21677,6 @@ var command_compatibility_default = {
21144
21677
  label: "a legacy Python CLI workflow command",
21145
21678
  sdk_alternative: "Use `deepline plays ...` in the SDK CLI."
21146
21679
  },
21147
- backend: {
21148
- family: "python",
21149
- label: "a legacy Python CLI playground backend command"
21150
- },
21151
21680
  events: {
21152
21681
  family: "python",
21153
21682
  label: "a legacy Python CLI event command"
@@ -21376,7 +21905,11 @@ var import_node_os11 = require("os");
21376
21905
  var import_node_path19 = require("path");
21377
21906
  var CHECK_TIMEOUT_MS2 = 3e3;
21378
21907
  var SDK_SKILL_NAME = "deepline-plays";
21379
- var SDK_SKILL_NAMES = [SDK_SKILL_NAME, "deepline-plays-quickstart"];
21908
+ var SDK_SKILL_NAMES = [
21909
+ SDK_SKILL_NAME,
21910
+ "deepline-plays-feedback",
21911
+ "deepline-plays-quickstart"
21912
+ ];
21380
21913
  var attemptedSync = false;
21381
21914
  function shouldSkipSkillsSync() {
21382
21915
  const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
@@ -21598,7 +22131,9 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
21598
22131
  if (!update?.needsUpdate && !hasStaleInstalledSkill || !update?.remoteVersion) {
21599
22132
  return;
21600
22133
  }
21601
- writeSdkSkillsStatusLine("SDK skills changed; syncing Deepline SDK skills...");
22134
+ writeSdkSkillsStatusLine(
22135
+ "SDK skills changed; syncing Deepline SDK skills..."
22136
+ );
21602
22137
  const installed = await runSkillsInstall(baseUrl);
21603
22138
  if (!installed) return;
21604
22139
  if (installedSdkSkillHasStalePositionalExecuteExamples()) {
@@ -21638,6 +22173,19 @@ function shouldDeferSkillsSyncForCommand() {
21638
22173
  const subcommand = args[1];
21639
22174
  return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
21640
22175
  }
22176
+ function isLegacyNoopInvocation() {
22177
+ const command = process.argv.slice(2)[0];
22178
+ return command === "session" || command === "backend";
22179
+ }
22180
+ function topLevelCommandKnown(program, commandName) {
22181
+ const normalized = commandName.trim();
22182
+ if (!normalized || normalized.startsWith("-")) {
22183
+ return true;
22184
+ }
22185
+ return program.commands.some(
22186
+ (command) => command.name() === normalized || command.aliases().includes(normalized)
22187
+ );
22188
+ }
21641
22189
  async function runPlayRunnerHealthCheck() {
21642
22190
  const dir = await (0, import_promises7.mkdtemp)((0, import_node_path20.join)((0, import_node_os12.tmpdir)(), "deepline-health-play-"));
21643
22191
  const file = (0, import_node_path20.join)(dir, "health-check.play.ts");
@@ -21857,7 +22405,7 @@ Exit codes:
21857
22405
  `
21858
22406
  );
21859
22407
  program.hook("preAction", async (_thisCommand, actionCommand) => {
21860
- if (actionCommand.name() === "version" || actionCommand.name() === "update") {
22408
+ if (actionCommand.name() === "version" || actionCommand.name() === "update" || isLegacyNoopInvocation()) {
21861
22409
  return;
21862
22410
  }
21863
22411
  if (printStartupPhase) {
@@ -21874,9 +22422,7 @@ Exit codes:
21874
22422
  if (compatibility.error) {
21875
22423
  return;
21876
22424
  }
21877
- const relaunched = await maybeAutoUpdateAndRelaunch(
21878
- compatibility.response
21879
- );
22425
+ const relaunched = await maybeAutoUpdateAndRelaunch(compatibility.response);
21880
22426
  if (relaunched) {
21881
22427
  return;
21882
22428
  }
@@ -21904,6 +22450,7 @@ Exit codes:
21904
22450
  registerCsvCommands(program);
21905
22451
  registerDbCommands(program);
21906
22452
  registerFeedbackCommands(program);
22453
+ registerLegacyNoopCommands(program);
21907
22454
  registerUpdateCommand(program);
21908
22455
  registerQuickstartCommands(program);
21909
22456
  program.command("preflight").description("Run compact health, auth, and Deepline billing checks.").option("--json", "Force JSON output.").addHelpText(
@@ -22004,6 +22551,20 @@ Examples:
22004
22551
  process.exitCode = 2;
22005
22552
  return;
22006
22553
  }
22554
+ const requestedTopLevelCommand = process.argv.slice(2)[0] ?? "";
22555
+ if (!topLevelCommandKnown(program, requestedTopLevelCommand)) {
22556
+ console.error(`error: unknown command '${requestedTopLevelCommand}'`);
22557
+ const hint = commandCompatibilityHint(
22558
+ "sdk",
22559
+ requestedTopLevelCommand,
22560
+ autoDetectBaseUrl()
22561
+ );
22562
+ if (hint && !process.argv.includes("--json")) {
22563
+ console.error(hint);
22564
+ }
22565
+ process.exitCode = 2;
22566
+ return;
22567
+ }
22007
22568
  try {
22008
22569
  await program.parseAsync(process.argv);
22009
22570
  recordCliTrace({