deepline 0.1.188 → 0.1.190

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.
@@ -612,7 +612,7 @@ export type CsvOptions = {
612
612
  *
613
613
  * @example
614
614
  * ```typescript
615
- * definePlay('example', async (ctx, input: { domain: string }) => {
615
+ * definePlay('example', async (ctx, input: { domain: string; csv: string }) => {
616
616
  * // Call a tool
617
617
  * const company = await ctx.tools.execute({
618
618
  * id: 'company_search',
@@ -633,8 +633,8 @@ export type CsvOptions = {
633
633
  * }))
634
634
  * .run({ description: 'Look up company details.' });
635
635
  *
636
- * // Load CSV data
637
- * const leads = await ctx.csv('leads.csv');
636
+ * // Load CSV data from a submitted play input field.
637
+ * const leads = await ctx.csv(input.csv);
638
638
  *
639
639
  * // Emit a log line (visible in `play tail`)
640
640
  * ctx.log(`Loaded ${await leads.count()} leads`);
@@ -642,8 +642,8 @@ export type CsvOptions = {
642
642
  * // Pause execution
643
643
  * await ctx.sleep(1000);
644
644
  *
645
- * // Access the raw input object
646
- * console.log(ctx.input);
645
+ * // Access submitted input through the handler's second argument.
646
+ * ctx.log(`Running for ${input.domain}`);
647
647
  *
648
648
  * return { company, enriched };
649
649
  * });
@@ -656,7 +656,12 @@ export interface DeeplinePlayRuntimeContext {
656
656
  * Use this when a play receives a CSV path from the CLI or API and row work
657
657
  * should continue through {@link DeeplinePlayRuntimeContext.dataset}. The path is
658
658
  * normally an input field such as `input.csv`, populated by
659
- * `deepline plays run my.play.ts --csv rows.csv`.
659
+ * `deepline plays run my.play.ts --csv rows.csv`. Prefer `input.csv` for row
660
+ * data so the CLI can run strict CSV preflight before starting a run.
661
+ * Pass-through flags can also target non-reserved field names. If a play
662
+ * intentionally calls `ctx.csv(input.file)`, use `--input
663
+ * '{"file":"rows.csv"}'` because `--file` is reserved for the play source
664
+ * path.
660
665
  *
661
666
  * Each CSV row becomes an object keyed by canonical column names. Use
662
667
  * `options.columns` / `options.rename` to map user headers such as
@@ -903,7 +908,11 @@ export interface DeeplinePlayRuntimeContext {
903
908
  */
904
909
  sleep(ms: number): Promise<void>;
905
910
 
906
- /** The raw input object passed when the play was started. */
911
+ /**
912
+ * @deprecated Read submitted play input from the handler's second argument:
913
+ * `definePlay('example', async (ctx, input) => ...)`. This legacy field is
914
+ * not the supported V2 play input API.
915
+ */
907
916
  readonly input: Record<string, unknown>;
908
917
  }
909
918
 
@@ -105,10 +105,10 @@ export const SDK_RELEASE = {
105
105
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
106
106
  // fields shipped in 0.1.153.
107
107
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
108
- version: '0.1.188',
108
+ version: '0.1.190',
109
109
  apiContract: '2026-06-dataset-handle-results-hard-cutover',
110
110
  supportPolicy: {
111
- latest: '0.1.188',
111
+ latest: '0.1.190',
112
112
  minimumSupported: '0.1.53',
113
113
  deprecatedBelow: '0.1.53',
114
114
  commandMinimumSupported: [
@@ -510,6 +510,7 @@ export type PlayStaticControlFlowBranch = {
510
510
  label: string;
511
511
  /** The arm's condition source text, when it has one (omitted for `else`). */
512
512
  condition?: string;
513
+ /** Static work in this arm. Empty for log/throw/return-only arms. */
513
514
  steps: PlayStaticSubstep[];
514
515
  };
515
516
 
package/dist/cli/index.js CHANGED
@@ -623,10 +623,10 @@ var SDK_RELEASE = {
623
623
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
624
624
  // fields shipped in 0.1.153.
625
625
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
626
- version: "0.1.188",
626
+ version: "0.1.190",
627
627
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
628
628
  supportPolicy: {
629
- latest: "0.1.188",
629
+ latest: "0.1.190",
630
630
  minimumSupported: "0.1.53",
631
631
  deprecatedBelow: "0.1.53",
632
632
  commandMinimumSupported: [
@@ -4829,14 +4829,64 @@ function readCsvRows(csvPath) {
4829
4829
  });
4830
4830
  }
4831
4831
  function csvStringFromRows(rows, columns) {
4832
- return (0, import_sync2.stringify)(rows, {
4832
+ return (0, import_sync2.stringify)(rows.map(csvSafeRow), {
4833
4833
  header: true,
4834
4834
  cast: {
4835
- boolean: (value) => value ? "true" : "false"
4835
+ boolean: (value) => value ? "true" : "false",
4836
+ object: (value) => {
4837
+ const cell = csvSafeCell(value);
4838
+ return typeof cell === "string" ? cell : null;
4839
+ }
4836
4840
  },
4837
4841
  ...columns?.length ? { columns } : {}
4838
4842
  });
4839
4843
  }
4844
+ function csvSafeRow(row) {
4845
+ return Object.fromEntries(
4846
+ Object.entries(row).map(([key, value]) => [key, csvSafeCell(value)])
4847
+ );
4848
+ }
4849
+ function csvSafeCell(value) {
4850
+ if (value === void 0) {
4851
+ return null;
4852
+ }
4853
+ if (value === null) {
4854
+ return null;
4855
+ }
4856
+ if (typeof value === "bigint") {
4857
+ return value.toString();
4858
+ }
4859
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4860
+ return value;
4861
+ }
4862
+ if (value instanceof Date) {
4863
+ return value.toISOString();
4864
+ }
4865
+ if (typeof value === "symbol" || typeof value === "function") {
4866
+ return null;
4867
+ }
4868
+ if (typeof value !== "object") {
4869
+ return String(value);
4870
+ }
4871
+ return csvSafeJsonString(value);
4872
+ }
4873
+ function csvSafeJsonReplacer(_key, nested) {
4874
+ if (typeof nested === "bigint") {
4875
+ return nested.toString();
4876
+ }
4877
+ if (nested === void 0 || typeof nested === "symbol" || typeof nested === "function") {
4878
+ return null;
4879
+ }
4880
+ return nested;
4881
+ }
4882
+ function csvSafeJsonString(value) {
4883
+ try {
4884
+ const serialized = JSON.stringify(value, csvSafeJsonReplacer);
4885
+ return serialized ?? null;
4886
+ } catch {
4887
+ return String(value);
4888
+ }
4889
+ }
4840
4890
  function parseMaybeJsonObject(value) {
4841
4891
  if (typeof value !== "string") {
4842
4892
  return value;
@@ -4877,14 +4927,14 @@ function flattenObjectColumns(row, options = {}) {
4877
4927
  const value = parseMaybeJsonObject(rawValue);
4878
4928
  const parsedFromString = typeof rawValue === "string" && value !== rawValue;
4879
4929
  if (key === "_metadata") {
4880
- flattened[key] = value && typeof value === "object" ? JSON.stringify(value) : value;
4930
+ flattened[key] = value && typeof value === "object" ? csvSafeJsonString(value) : value;
4881
4931
  continue;
4882
4932
  }
4883
4933
  if (value && typeof value === "object" && !Array.isArray(value)) {
4884
4934
  const record = value;
4885
4935
  const hasMatchedEnvelope = Object.prototype.hasOwnProperty.call(record, "matched_result") || Object.prototype.hasOwnProperty.call(record, "matchedResult");
4886
4936
  if (hasMatchedEnvelope) {
4887
- flattened[key] = JSON.stringify(record);
4937
+ flattened[key] = csvSafeJsonString(record);
4888
4938
  continue;
4889
4939
  }
4890
4940
  if (parsedFromString && shouldPreserveJsonStringColumn(options.preserveJsonStringColumns, key)) {
@@ -4896,16 +4946,16 @@ function flattenObjectColumns(row, options = {}) {
4896
4946
  flattened[key] = failureMessage;
4897
4947
  continue;
4898
4948
  } else if (Object.prototype.hasOwnProperty.call(record, "result")) {
4899
- flattened[key] = JSON.stringify(record);
4949
+ flattened[key] = csvSafeJsonString(record);
4900
4950
  continue;
4901
4951
  }
4902
4952
  }
4903
4953
  for (const [nestedKey, nestedValue] of Object.entries(record)) {
4904
- flattened[`${key}.${nestedKey}`] = nestedValue && typeof nestedValue === "object" ? JSON.stringify(nestedValue) : nestedValue;
4954
+ flattened[`${key}.${nestedKey}`] = nestedValue && typeof nestedValue === "object" ? csvSafeJsonString(nestedValue) : nestedValue;
4905
4955
  }
4906
4956
  continue;
4907
4957
  }
4908
- flattened[key] = Array.isArray(value) ? JSON.stringify(value) : value;
4958
+ flattened[key] = Array.isArray(value) ? csvSafeJsonString(value) : value;
4909
4959
  }
4910
4960
  return flattened;
4911
4961
  }
@@ -16968,16 +17018,39 @@ function helperSource() {
16968
17018
  ``,
16969
17019
  `function __dlGetByPath(root: unknown, path: string): unknown {`,
16970
17020
  ` let cursor = root;`,
16971
- ` for (const part of __dlPathParts(path)) {`,
17021
+ ` const parts = __dlPathParts(path);`,
17022
+ ` for (let index = 0; index < parts.length; index += 1) {`,
17023
+ ` const part = parts[index] || '';`,
17024
+ ` cursor = __dlParseJsonContainer(cursor);`,
16972
17025
  ` if (!cursor || typeof cursor !== 'object') return undefined;`,
16973
17026
  ` const record = cursor as Record<string, unknown>;`,
16974
- ` const field = __dlGetRecordField(record, part);`,
17027
+ ` let field = { found: false, value: undefined as unknown };`,
17028
+ ` for (let end = parts.length; end > index + 1; end -= 1) {`,
17029
+ ` const dottedPart = parts.slice(index, end).join('.');`,
17030
+ ` field = __dlGetRecordField(record, dottedPart);`,
17031
+ ` if (field.found) {`,
17032
+ ` index = end - 1;`,
17033
+ ` break;`,
17034
+ ` }`,
17035
+ ` }`,
17036
+ ` if (!field.found) field = __dlGetRecordField(record, part);`,
16975
17037
  ` if (!field.found) return undefined;`,
16976
17038
  ` cursor = field.value;`,
16977
17039
  ` }`,
16978
17040
  ` return cursor;`,
16979
17041
  `}`,
16980
17042
  ``,
17043
+ `function __dlParseJsonContainer(value: unknown): unknown {`,
17044
+ ` if (typeof value !== 'string') return value;`,
17045
+ ` const trimmed = value.trim();`,
17046
+ ` if ((!trimmed.startsWith('{') || !trimmed.endsWith('}')) && (!trimmed.startsWith('[') || !trimmed.endsWith(']'))) return value;`,
17047
+ ` try {`,
17048
+ ` return JSON.parse(trimmed);`,
17049
+ ` } catch {`,
17050
+ ` return value;`,
17051
+ ` }`,
17052
+ `}`,
17053
+ ``,
16981
17054
  `function __dlMeaningful(value: unknown): boolean {`,
16982
17055
  ` if (value && typeof value === 'object' && !Array.isArray(value)) {`,
16983
17056
  ` const record = value as Record<string, unknown>;`,
@@ -19998,6 +20071,12 @@ function sidecarEnrichRowsExportPath(outputPath) {
19998
20071
  const stem = (0, import_node_path12.basename)(resolved, ext);
19999
20072
  return (0, import_node_path12.join)((0, import_node_path12.dirname)(resolved), `${stem}.deepline-enrich-rows${ext}`);
20000
20073
  }
20074
+ function sidecarEnrichBatchManifestPath(outputPath) {
20075
+ const resolved = (0, import_node_path12.resolve)(outputPath);
20076
+ const ext = (0, import_node_path12.extname)(resolved) || ".csv";
20077
+ const stem = (0, import_node_path12.basename)(resolved, ext);
20078
+ return (0, import_node_path12.join)((0, import_node_path12.dirname)(resolved), `${stem}.deepline-enrich-batches.json`);
20079
+ }
20001
20080
  function collectDatasetFollowUpCommands(value, state) {
20002
20081
  if (state.depth > 12 || !value || typeof value !== "object" || state.commands.length >= 8) {
20003
20082
  return;
@@ -20503,7 +20582,7 @@ var ENRICH_FLATTENED_CONTROL_FIELDS = /* @__PURE__ */ new Set([
20503
20582
  ]);
20504
20583
  function materializeCsvCellValue(value) {
20505
20584
  if (value && typeof value === "object") {
20506
- return JSON.stringify(value);
20585
+ return csvSafeJsonString(value);
20507
20586
  }
20508
20587
  return value;
20509
20588
  }
@@ -20905,13 +20984,35 @@ function registerEnrichCommand(program) {
20905
20984
  const inPlaceCommitOutputPath = options.inPlace ? (await (0, import_promises3.lstat)(inputCsv)).isSymbolicLink() ? await (0, import_promises3.realpath)(inputCsv) : inPlaceFinalOutputPath : null;
20906
20985
  const failureReportOutputPath = options.inPlace ? inPlaceFinalOutputPath : null;
20907
20986
  const enrichIssueFollowUpOutputPath = options.inPlace && inPlaceFinalOutputPath ? sidecarEnrichRowsExportPath(inPlaceFinalOutputPath) : null;
20908
- let inPlaceCommitted = false;
20987
+ const prepareInPlaceOutput = async () => {
20988
+ if (!options.inPlace) {
20989
+ return;
20990
+ }
20991
+ if (inPlaceTempDir) {
20992
+ await (0, import_promises3.rm)(inPlaceTempDir, { recursive: true, force: true });
20993
+ }
20994
+ inPlaceTempDir = await (0, import_promises3.mkdtemp)(
20995
+ (0, import_node_path12.join)(
20996
+ (0, import_node_path12.dirname)(inPlaceCommitOutputPath ?? (0, import_node_path12.resolve)(inputCsv)),
20997
+ ".deepline-enrich-in-place-"
20998
+ )
20999
+ );
21000
+ inPlaceTempOutputPath = (0, import_node_path12.join)(inPlaceTempDir, "output.csv");
21001
+ await (0, import_promises3.copyFile)((0, import_node_path12.resolve)(inputCsv), inPlaceTempOutputPath);
21002
+ outputPath = inPlaceTempOutputPath;
21003
+ };
20909
21004
  const commitInPlaceOutput = async (exportResult) => {
20910
21005
  if (!inPlaceTempOutputPath || !inPlaceCommitOutputPath || !inPlaceFinalOutputPath) {
20911
21006
  return exportResult;
20912
21007
  }
21008
+ const committedTempDir = inPlaceTempDir;
20913
21009
  await (0, import_promises3.rename)(inPlaceTempOutputPath, inPlaceCommitOutputPath);
20914
- inPlaceCommitted = true;
21010
+ inPlaceTempDir = null;
21011
+ inPlaceTempOutputPath = null;
21012
+ outputPath = inPlaceFinalOutputPath;
21013
+ if (committedTempDir) {
21014
+ await (0, import_promises3.rm)(committedTempDir, { recursive: true, force: true });
21015
+ }
20915
21016
  if (!exportResult) {
20916
21017
  return null;
20917
21018
  }
@@ -20923,15 +21024,7 @@ function registerEnrichCommand(program) {
20923
21024
  try {
20924
21025
  await (0, import_promises3.writeFile)(tempPlay, playSource, "utf8");
20925
21026
  if (options.inPlace) {
20926
- inPlaceTempDir = await (0, import_promises3.mkdtemp)(
20927
- (0, import_node_path12.join)(
20928
- (0, import_node_path12.dirname)(inPlaceCommitOutputPath ?? (0, import_node_path12.resolve)(inputCsv)),
20929
- ".deepline-enrich-in-place-"
20930
- )
20931
- );
20932
- inPlaceTempOutputPath = (0, import_node_path12.join)(inPlaceTempDir, "output.csv");
20933
- await (0, import_promises3.copyFile)((0, import_node_path12.resolve)(inputCsv), inPlaceTempOutputPath);
20934
- outputPath = inPlaceTempOutputPath;
21027
+ await prepareInPlaceOutput();
20935
21028
  }
20936
21029
  const runOne = async (input2) => {
20937
21030
  const runtimeInput = {
@@ -20986,12 +21079,62 @@ function registerEnrichCommand(program) {
20986
21079
  const autoBatchRows = enrichAutoBatchRowsForConfig(config);
20987
21080
  if (outputPath && selectedRange.count > autoBatchRows) {
20988
21081
  const chunkCount = Math.ceil(selectedRange.count / autoBatchRows);
21082
+ const batchManifestPath = sidecarEnrichBatchManifestPath(
21083
+ inPlaceFinalOutputPath ?? (0, import_node_path12.resolve)(outputPath)
21084
+ );
21085
+ const batchManifest = {
21086
+ version: 1,
21087
+ kind: "deepline_enrich_batch_manifest",
21088
+ input: (0, import_node_path12.resolve)(inputCsv),
21089
+ output: inPlaceFinalOutputPath ?? (0, import_node_path12.resolve)(outputPath),
21090
+ selectedRows: selectedRange.count,
21091
+ sourceCsvRows: selectedRange.sourceRows,
21092
+ chunkRows: autoBatchRows,
21093
+ chunks: chunkCount,
21094
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
21095
+ batches: []
21096
+ };
21097
+ const writeBatchManifest = async () => {
21098
+ batchManifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21099
+ await (0, import_promises3.writeFile)(
21100
+ batchManifestPath,
21101
+ `${JSON.stringify(batchManifest, null, 2)}
21102
+ `,
21103
+ "utf8"
21104
+ );
21105
+ };
21106
+ const appendBatchManifestEntry = async (input2) => {
21107
+ const runId = extractRunId(input2.status) ?? firstCollectedStringField(input2.status, "runId");
21108
+ batchManifest.batches.push({
21109
+ chunk: input2.chunkIndex + 1,
21110
+ chunks: chunkCount,
21111
+ rows: {
21112
+ rowStart: input2.rows.rowStart,
21113
+ rowEnd: input2.rows.rowEnd
21114
+ },
21115
+ status: readEnrichRunStatus(input2.status),
21116
+ runId,
21117
+ customer_db: enrichCustomerDbJson({
21118
+ status: input2.status,
21119
+ client: client2,
21120
+ outputPath: enrichIssueFollowUpOutputPath ?? input2.exportResult?.path ?? outputPath
21121
+ }),
21122
+ output: enrichOutputJson(input2.exportResult),
21123
+ completedAt: (/* @__PURE__ */ new Date()).toISOString()
21124
+ });
21125
+ await writeBatchManifest();
21126
+ };
21127
+ await writeBatchManifest();
20989
21128
  if (!options.json) {
20990
21129
  process.stderr.write(
20991
21130
  `Large enrich input selected ${selectedRange.count.toLocaleString()} rows. Running ${chunkCount.toLocaleString()} sequential batch runs of up to ${autoBatchRows.toLocaleString()} rows and merging ${(0, import_node_path12.resolve)(outputPath)}.
20992
21131
  `
20993
21132
  );
20994
21133
  }
21134
+ process.stderr.write(
21135
+ `Batch recovery manifest: ${batchManifestPath}
21136
+ `
21137
+ );
20995
21138
  let workingMergeSourceCsvPath = sourceCsvPath;
20996
21139
  let lastStatus = null;
20997
21140
  const batchStatuses = [];
@@ -21034,6 +21177,7 @@ function registerEnrichCommand(program) {
21034
21177
  lastStatus = chunk.status;
21035
21178
  batchStatuses.push(chunk.status);
21036
21179
  if (chunk.captured.result !== 0) {
21180
+ let currentChunkCommittedExportResult = null;
21037
21181
  if (chunk.exportResult) {
21038
21182
  finalExportResult = chunk.exportResult;
21039
21183
  totalEnrichedRows += countEnrichedRowsInSourceRange(
@@ -21057,37 +21201,48 @@ function registerEnrichCommand(program) {
21057
21201
  waterfallStatus: batchStatuses,
21058
21202
  ...finalExportResult ? { rowSetComplete: !finalExportResult.partial } : {}
21059
21203
  });
21060
- const committedExportResult2 = finalExportResult ? await commitInPlaceOutput(finalExportResult) : null;
21204
+ if (chunk.exportResult) {
21205
+ currentChunkCommittedExportResult = await commitInPlaceOutput(chunk.exportResult);
21206
+ finalExportResult = currentChunkCommittedExportResult;
21207
+ }
21208
+ const reportedExportResult = currentChunkCommittedExportResult ?? finalExportResult;
21209
+ await appendBatchManifestEntry({
21210
+ chunkIndex,
21211
+ rows: chunkRows,
21212
+ status: chunk.status,
21213
+ exportResult: currentChunkCommittedExportResult
21214
+ });
21061
21215
  if (options.json) {
21062
21216
  printJson({
21063
21217
  ok: false,
21064
21218
  batch: {
21065
21219
  chunk: chunkIndex + 1,
21066
21220
  chunks: chunkCount,
21067
- rows: chunkRows
21221
+ rows: chunkRows,
21222
+ manifest: batchManifestPath
21068
21223
  },
21069
21224
  result: chunk.status,
21070
- output: committedExportResult2 ? {
21225
+ output: reportedExportResult ? {
21071
21226
  sourceCsvRows: selectedRange.sourceRows,
21072
21227
  selectedRows: selectedRange.count,
21073
21228
  enrichedRows: totalEnrichedRows,
21074
- path: committedExportResult2.path,
21075
- ...committedExportResult2.partial ? {
21076
- rows: committedExportResult2.rows,
21229
+ path: reportedExportResult.path,
21230
+ ...reportedExportResult.partial ? {
21231
+ rows: reportedExportResult.rows,
21077
21232
  partial: true
21078
21233
  } : {}
21079
21234
  } : null,
21080
21235
  customer_db: enrichCustomerDbJson({
21081
21236
  status: chunk.status,
21082
21237
  client: client2,
21083
- outputPath: enrichIssueFollowUpOutputPath ?? committedExportResult2?.path ?? outputPath
21238
+ outputPath: enrichIssueFollowUpOutputPath ?? reportedExportResult?.path ?? outputPath
21084
21239
  }),
21085
21240
  ...enrichReportJson(failureReport3)
21086
21241
  });
21087
21242
  } else {
21088
- if (committedExportResult2) {
21243
+ if (reportedExportResult) {
21089
21244
  process.stderr.write(
21090
- `Wrote ${committedExportResult2.rows} row(s) to ${committedExportResult2.path}${committedExportResult2.partial ? " (partial run output)" : ""}
21245
+ `Wrote ${reportedExportResult.rows} row(s) to ${reportedExportResult.path}${reportedExportResult.partial ? " (partial run output)" : ""}
21091
21246
  `
21092
21247
  );
21093
21248
  }
@@ -21102,13 +21257,22 @@ function registerEnrichCommand(program) {
21102
21257
  return;
21103
21258
  }
21104
21259
  if (chunk.exportResult) {
21105
- finalExportResult = chunk.exportResult;
21106
21260
  totalEnrichedRows += countEnrichedRowsInSourceRange(
21107
21261
  chunk.exportResult,
21108
21262
  chunkRows
21109
21263
  );
21110
21264
  batchFailureRows.push(...chunk.exportResult.enrichedDataRows);
21265
+ finalExportResult = options.inPlace ? await commitInPlaceOutput(chunk.exportResult) : chunk.exportResult;
21266
+ await appendBatchManifestEntry({
21267
+ chunkIndex,
21268
+ rows: chunkRows,
21269
+ status: chunk.status,
21270
+ exportResult: finalExportResult
21271
+ });
21111
21272
  workingMergeSourceCsvPath = outputPath;
21273
+ if (options.inPlace && (chunkRows.rowEnd ?? selectedRange.end) < selectedRange.end) {
21274
+ await prepareInPlaceOutput();
21275
+ }
21112
21276
  }
21113
21277
  }
21114
21278
  const outputRows = readCsvRows(outputPath);
@@ -21148,7 +21312,8 @@ function registerEnrichCommand(program) {
21148
21312
  batch: {
21149
21313
  chunks: chunkCount,
21150
21314
  chunkRows: autoBatchRows,
21151
- selectedRows: selectedRange.count
21315
+ selectedRows: selectedRange.count,
21316
+ manifest: batchManifestPath
21152
21317
  },
21153
21318
  output: finalExportResult ? {
21154
21319
  sourceCsvRows: selectedRange.sourceRows,
@@ -21278,7 +21443,7 @@ function registerEnrichCommand(program) {
21278
21443
  } finally {
21279
21444
  if (inPlaceTempDir) {
21280
21445
  await (0, import_promises3.rm)(inPlaceTempDir, { recursive: true, force: true });
21281
- } else if (inPlaceTempOutputPath && !inPlaceCommitted) {
21446
+ } else if (inPlaceTempOutputPath) {
21282
21447
  await (0, import_promises3.rm)(inPlaceTempOutputPath, { force: true });
21283
21448
  }
21284
21449
  await (0, import_promises3.rm)(tempDir, { recursive: true, force: true });
@@ -608,10 +608,10 @@ var SDK_RELEASE = {
608
608
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
609
609
  // fields shipped in 0.1.153.
610
610
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
611
- version: "0.1.188",
611
+ version: "0.1.190",
612
612
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
613
613
  supportPolicy: {
614
- latest: "0.1.188",
614
+ latest: "0.1.190",
615
615
  minimumSupported: "0.1.53",
616
616
  deprecatedBelow: "0.1.53",
617
617
  commandMinimumSupported: [
@@ -4826,14 +4826,64 @@ function readCsvRows(csvPath) {
4826
4826
  });
4827
4827
  }
4828
4828
  function csvStringFromRows(rows, columns) {
4829
- return stringify(rows, {
4829
+ return stringify(rows.map(csvSafeRow), {
4830
4830
  header: true,
4831
4831
  cast: {
4832
- boolean: (value) => value ? "true" : "false"
4832
+ boolean: (value) => value ? "true" : "false",
4833
+ object: (value) => {
4834
+ const cell = csvSafeCell(value);
4835
+ return typeof cell === "string" ? cell : null;
4836
+ }
4833
4837
  },
4834
4838
  ...columns?.length ? { columns } : {}
4835
4839
  });
4836
4840
  }
4841
+ function csvSafeRow(row) {
4842
+ return Object.fromEntries(
4843
+ Object.entries(row).map(([key, value]) => [key, csvSafeCell(value)])
4844
+ );
4845
+ }
4846
+ function csvSafeCell(value) {
4847
+ if (value === void 0) {
4848
+ return null;
4849
+ }
4850
+ if (value === null) {
4851
+ return null;
4852
+ }
4853
+ if (typeof value === "bigint") {
4854
+ return value.toString();
4855
+ }
4856
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4857
+ return value;
4858
+ }
4859
+ if (value instanceof Date) {
4860
+ return value.toISOString();
4861
+ }
4862
+ if (typeof value === "symbol" || typeof value === "function") {
4863
+ return null;
4864
+ }
4865
+ if (typeof value !== "object") {
4866
+ return String(value);
4867
+ }
4868
+ return csvSafeJsonString(value);
4869
+ }
4870
+ function csvSafeJsonReplacer(_key, nested) {
4871
+ if (typeof nested === "bigint") {
4872
+ return nested.toString();
4873
+ }
4874
+ if (nested === void 0 || typeof nested === "symbol" || typeof nested === "function") {
4875
+ return null;
4876
+ }
4877
+ return nested;
4878
+ }
4879
+ function csvSafeJsonString(value) {
4880
+ try {
4881
+ const serialized = JSON.stringify(value, csvSafeJsonReplacer);
4882
+ return serialized ?? null;
4883
+ } catch {
4884
+ return String(value);
4885
+ }
4886
+ }
4837
4887
  function parseMaybeJsonObject(value) {
4838
4888
  if (typeof value !== "string") {
4839
4889
  return value;
@@ -4874,14 +4924,14 @@ function flattenObjectColumns(row, options = {}) {
4874
4924
  const value = parseMaybeJsonObject(rawValue);
4875
4925
  const parsedFromString = typeof rawValue === "string" && value !== rawValue;
4876
4926
  if (key === "_metadata") {
4877
- flattened[key] = value && typeof value === "object" ? JSON.stringify(value) : value;
4927
+ flattened[key] = value && typeof value === "object" ? csvSafeJsonString(value) : value;
4878
4928
  continue;
4879
4929
  }
4880
4930
  if (value && typeof value === "object" && !Array.isArray(value)) {
4881
4931
  const record = value;
4882
4932
  const hasMatchedEnvelope = Object.prototype.hasOwnProperty.call(record, "matched_result") || Object.prototype.hasOwnProperty.call(record, "matchedResult");
4883
4933
  if (hasMatchedEnvelope) {
4884
- flattened[key] = JSON.stringify(record);
4934
+ flattened[key] = csvSafeJsonString(record);
4885
4935
  continue;
4886
4936
  }
4887
4937
  if (parsedFromString && shouldPreserveJsonStringColumn(options.preserveJsonStringColumns, key)) {
@@ -4893,16 +4943,16 @@ function flattenObjectColumns(row, options = {}) {
4893
4943
  flattened[key] = failureMessage;
4894
4944
  continue;
4895
4945
  } else if (Object.prototype.hasOwnProperty.call(record, "result")) {
4896
- flattened[key] = JSON.stringify(record);
4946
+ flattened[key] = csvSafeJsonString(record);
4897
4947
  continue;
4898
4948
  }
4899
4949
  }
4900
4950
  for (const [nestedKey, nestedValue] of Object.entries(record)) {
4901
- flattened[`${key}.${nestedKey}`] = nestedValue && typeof nestedValue === "object" ? JSON.stringify(nestedValue) : nestedValue;
4951
+ flattened[`${key}.${nestedKey}`] = nestedValue && typeof nestedValue === "object" ? csvSafeJsonString(nestedValue) : nestedValue;
4902
4952
  }
4903
4953
  continue;
4904
4954
  }
4905
- flattened[key] = Array.isArray(value) ? JSON.stringify(value) : value;
4955
+ flattened[key] = Array.isArray(value) ? csvSafeJsonString(value) : value;
4906
4956
  }
4907
4957
  return flattened;
4908
4958
  }
@@ -16995,16 +17045,39 @@ function helperSource() {
16995
17045
  ``,
16996
17046
  `function __dlGetByPath(root: unknown, path: string): unknown {`,
16997
17047
  ` let cursor = root;`,
16998
- ` for (const part of __dlPathParts(path)) {`,
17048
+ ` const parts = __dlPathParts(path);`,
17049
+ ` for (let index = 0; index < parts.length; index += 1) {`,
17050
+ ` const part = parts[index] || '';`,
17051
+ ` cursor = __dlParseJsonContainer(cursor);`,
16999
17052
  ` if (!cursor || typeof cursor !== 'object') return undefined;`,
17000
17053
  ` const record = cursor as Record<string, unknown>;`,
17001
- ` const field = __dlGetRecordField(record, part);`,
17054
+ ` let field = { found: false, value: undefined as unknown };`,
17055
+ ` for (let end = parts.length; end > index + 1; end -= 1) {`,
17056
+ ` const dottedPart = parts.slice(index, end).join('.');`,
17057
+ ` field = __dlGetRecordField(record, dottedPart);`,
17058
+ ` if (field.found) {`,
17059
+ ` index = end - 1;`,
17060
+ ` break;`,
17061
+ ` }`,
17062
+ ` }`,
17063
+ ` if (!field.found) field = __dlGetRecordField(record, part);`,
17002
17064
  ` if (!field.found) return undefined;`,
17003
17065
  ` cursor = field.value;`,
17004
17066
  ` }`,
17005
17067
  ` return cursor;`,
17006
17068
  `}`,
17007
17069
  ``,
17070
+ `function __dlParseJsonContainer(value: unknown): unknown {`,
17071
+ ` if (typeof value !== 'string') return value;`,
17072
+ ` const trimmed = value.trim();`,
17073
+ ` if ((!trimmed.startsWith('{') || !trimmed.endsWith('}')) && (!trimmed.startsWith('[') || !trimmed.endsWith(']'))) return value;`,
17074
+ ` try {`,
17075
+ ` return JSON.parse(trimmed);`,
17076
+ ` } catch {`,
17077
+ ` return value;`,
17078
+ ` }`,
17079
+ `}`,
17080
+ ``,
17008
17081
  `function __dlMeaningful(value: unknown): boolean {`,
17009
17082
  ` if (value && typeof value === 'object' && !Array.isArray(value)) {`,
17010
17083
  ` const record = value as Record<string, unknown>;`,
@@ -20025,6 +20098,12 @@ function sidecarEnrichRowsExportPath(outputPath) {
20025
20098
  const stem = basename2(resolved, ext);
20026
20099
  return join7(dirname7(resolved), `${stem}.deepline-enrich-rows${ext}`);
20027
20100
  }
20101
+ function sidecarEnrichBatchManifestPath(outputPath) {
20102
+ const resolved = resolve9(outputPath);
20103
+ const ext = extname(resolved) || ".csv";
20104
+ const stem = basename2(resolved, ext);
20105
+ return join7(dirname7(resolved), `${stem}.deepline-enrich-batches.json`);
20106
+ }
20028
20107
  function collectDatasetFollowUpCommands(value, state) {
20029
20108
  if (state.depth > 12 || !value || typeof value !== "object" || state.commands.length >= 8) {
20030
20109
  return;
@@ -20530,7 +20609,7 @@ var ENRICH_FLATTENED_CONTROL_FIELDS = /* @__PURE__ */ new Set([
20530
20609
  ]);
20531
20610
  function materializeCsvCellValue(value) {
20532
20611
  if (value && typeof value === "object") {
20533
- return JSON.stringify(value);
20612
+ return csvSafeJsonString(value);
20534
20613
  }
20535
20614
  return value;
20536
20615
  }
@@ -20932,13 +21011,35 @@ function registerEnrichCommand(program) {
20932
21011
  const inPlaceCommitOutputPath = options.inPlace ? (await lstat(inputCsv)).isSymbolicLink() ? await realpath(inputCsv) : inPlaceFinalOutputPath : null;
20933
21012
  const failureReportOutputPath = options.inPlace ? inPlaceFinalOutputPath : null;
20934
21013
  const enrichIssueFollowUpOutputPath = options.inPlace && inPlaceFinalOutputPath ? sidecarEnrichRowsExportPath(inPlaceFinalOutputPath) : null;
20935
- let inPlaceCommitted = false;
21014
+ const prepareInPlaceOutput = async () => {
21015
+ if (!options.inPlace) {
21016
+ return;
21017
+ }
21018
+ if (inPlaceTempDir) {
21019
+ await rm(inPlaceTempDir, { recursive: true, force: true });
21020
+ }
21021
+ inPlaceTempDir = await mkdtemp(
21022
+ join7(
21023
+ dirname7(inPlaceCommitOutputPath ?? resolve9(inputCsv)),
21024
+ ".deepline-enrich-in-place-"
21025
+ )
21026
+ );
21027
+ inPlaceTempOutputPath = join7(inPlaceTempDir, "output.csv");
21028
+ await copyFile(resolve9(inputCsv), inPlaceTempOutputPath);
21029
+ outputPath = inPlaceTempOutputPath;
21030
+ };
20936
21031
  const commitInPlaceOutput = async (exportResult) => {
20937
21032
  if (!inPlaceTempOutputPath || !inPlaceCommitOutputPath || !inPlaceFinalOutputPath) {
20938
21033
  return exportResult;
20939
21034
  }
21035
+ const committedTempDir = inPlaceTempDir;
20940
21036
  await rename(inPlaceTempOutputPath, inPlaceCommitOutputPath);
20941
- inPlaceCommitted = true;
21037
+ inPlaceTempDir = null;
21038
+ inPlaceTempOutputPath = null;
21039
+ outputPath = inPlaceFinalOutputPath;
21040
+ if (committedTempDir) {
21041
+ await rm(committedTempDir, { recursive: true, force: true });
21042
+ }
20942
21043
  if (!exportResult) {
20943
21044
  return null;
20944
21045
  }
@@ -20950,15 +21051,7 @@ function registerEnrichCommand(program) {
20950
21051
  try {
20951
21052
  await writeFile3(tempPlay, playSource, "utf8");
20952
21053
  if (options.inPlace) {
20953
- inPlaceTempDir = await mkdtemp(
20954
- join7(
20955
- dirname7(inPlaceCommitOutputPath ?? resolve9(inputCsv)),
20956
- ".deepline-enrich-in-place-"
20957
- )
20958
- );
20959
- inPlaceTempOutputPath = join7(inPlaceTempDir, "output.csv");
20960
- await copyFile(resolve9(inputCsv), inPlaceTempOutputPath);
20961
- outputPath = inPlaceTempOutputPath;
21054
+ await prepareInPlaceOutput();
20962
21055
  }
20963
21056
  const runOne = async (input2) => {
20964
21057
  const runtimeInput = {
@@ -21013,12 +21106,62 @@ function registerEnrichCommand(program) {
21013
21106
  const autoBatchRows = enrichAutoBatchRowsForConfig(config);
21014
21107
  if (outputPath && selectedRange.count > autoBatchRows) {
21015
21108
  const chunkCount = Math.ceil(selectedRange.count / autoBatchRows);
21109
+ const batchManifestPath = sidecarEnrichBatchManifestPath(
21110
+ inPlaceFinalOutputPath ?? resolve9(outputPath)
21111
+ );
21112
+ const batchManifest = {
21113
+ version: 1,
21114
+ kind: "deepline_enrich_batch_manifest",
21115
+ input: resolve9(inputCsv),
21116
+ output: inPlaceFinalOutputPath ?? resolve9(outputPath),
21117
+ selectedRows: selectedRange.count,
21118
+ sourceCsvRows: selectedRange.sourceRows,
21119
+ chunkRows: autoBatchRows,
21120
+ chunks: chunkCount,
21121
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
21122
+ batches: []
21123
+ };
21124
+ const writeBatchManifest = async () => {
21125
+ batchManifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21126
+ await writeFile3(
21127
+ batchManifestPath,
21128
+ `${JSON.stringify(batchManifest, null, 2)}
21129
+ `,
21130
+ "utf8"
21131
+ );
21132
+ };
21133
+ const appendBatchManifestEntry = async (input2) => {
21134
+ const runId = extractRunId(input2.status) ?? firstCollectedStringField(input2.status, "runId");
21135
+ batchManifest.batches.push({
21136
+ chunk: input2.chunkIndex + 1,
21137
+ chunks: chunkCount,
21138
+ rows: {
21139
+ rowStart: input2.rows.rowStart,
21140
+ rowEnd: input2.rows.rowEnd
21141
+ },
21142
+ status: readEnrichRunStatus(input2.status),
21143
+ runId,
21144
+ customer_db: enrichCustomerDbJson({
21145
+ status: input2.status,
21146
+ client: client2,
21147
+ outputPath: enrichIssueFollowUpOutputPath ?? input2.exportResult?.path ?? outputPath
21148
+ }),
21149
+ output: enrichOutputJson(input2.exportResult),
21150
+ completedAt: (/* @__PURE__ */ new Date()).toISOString()
21151
+ });
21152
+ await writeBatchManifest();
21153
+ };
21154
+ await writeBatchManifest();
21016
21155
  if (!options.json) {
21017
21156
  process.stderr.write(
21018
21157
  `Large enrich input selected ${selectedRange.count.toLocaleString()} rows. Running ${chunkCount.toLocaleString()} sequential batch runs of up to ${autoBatchRows.toLocaleString()} rows and merging ${resolve9(outputPath)}.
21019
21158
  `
21020
21159
  );
21021
21160
  }
21161
+ process.stderr.write(
21162
+ `Batch recovery manifest: ${batchManifestPath}
21163
+ `
21164
+ );
21022
21165
  let workingMergeSourceCsvPath = sourceCsvPath;
21023
21166
  let lastStatus = null;
21024
21167
  const batchStatuses = [];
@@ -21061,6 +21204,7 @@ function registerEnrichCommand(program) {
21061
21204
  lastStatus = chunk.status;
21062
21205
  batchStatuses.push(chunk.status);
21063
21206
  if (chunk.captured.result !== 0) {
21207
+ let currentChunkCommittedExportResult = null;
21064
21208
  if (chunk.exportResult) {
21065
21209
  finalExportResult = chunk.exportResult;
21066
21210
  totalEnrichedRows += countEnrichedRowsInSourceRange(
@@ -21084,37 +21228,48 @@ function registerEnrichCommand(program) {
21084
21228
  waterfallStatus: batchStatuses,
21085
21229
  ...finalExportResult ? { rowSetComplete: !finalExportResult.partial } : {}
21086
21230
  });
21087
- const committedExportResult2 = finalExportResult ? await commitInPlaceOutput(finalExportResult) : null;
21231
+ if (chunk.exportResult) {
21232
+ currentChunkCommittedExportResult = await commitInPlaceOutput(chunk.exportResult);
21233
+ finalExportResult = currentChunkCommittedExportResult;
21234
+ }
21235
+ const reportedExportResult = currentChunkCommittedExportResult ?? finalExportResult;
21236
+ await appendBatchManifestEntry({
21237
+ chunkIndex,
21238
+ rows: chunkRows,
21239
+ status: chunk.status,
21240
+ exportResult: currentChunkCommittedExportResult
21241
+ });
21088
21242
  if (options.json) {
21089
21243
  printJson({
21090
21244
  ok: false,
21091
21245
  batch: {
21092
21246
  chunk: chunkIndex + 1,
21093
21247
  chunks: chunkCount,
21094
- rows: chunkRows
21248
+ rows: chunkRows,
21249
+ manifest: batchManifestPath
21095
21250
  },
21096
21251
  result: chunk.status,
21097
- output: committedExportResult2 ? {
21252
+ output: reportedExportResult ? {
21098
21253
  sourceCsvRows: selectedRange.sourceRows,
21099
21254
  selectedRows: selectedRange.count,
21100
21255
  enrichedRows: totalEnrichedRows,
21101
- path: committedExportResult2.path,
21102
- ...committedExportResult2.partial ? {
21103
- rows: committedExportResult2.rows,
21256
+ path: reportedExportResult.path,
21257
+ ...reportedExportResult.partial ? {
21258
+ rows: reportedExportResult.rows,
21104
21259
  partial: true
21105
21260
  } : {}
21106
21261
  } : null,
21107
21262
  customer_db: enrichCustomerDbJson({
21108
21263
  status: chunk.status,
21109
21264
  client: client2,
21110
- outputPath: enrichIssueFollowUpOutputPath ?? committedExportResult2?.path ?? outputPath
21265
+ outputPath: enrichIssueFollowUpOutputPath ?? reportedExportResult?.path ?? outputPath
21111
21266
  }),
21112
21267
  ...enrichReportJson(failureReport3)
21113
21268
  });
21114
21269
  } else {
21115
- if (committedExportResult2) {
21270
+ if (reportedExportResult) {
21116
21271
  process.stderr.write(
21117
- `Wrote ${committedExportResult2.rows} row(s) to ${committedExportResult2.path}${committedExportResult2.partial ? " (partial run output)" : ""}
21272
+ `Wrote ${reportedExportResult.rows} row(s) to ${reportedExportResult.path}${reportedExportResult.partial ? " (partial run output)" : ""}
21118
21273
  `
21119
21274
  );
21120
21275
  }
@@ -21129,13 +21284,22 @@ function registerEnrichCommand(program) {
21129
21284
  return;
21130
21285
  }
21131
21286
  if (chunk.exportResult) {
21132
- finalExportResult = chunk.exportResult;
21133
21287
  totalEnrichedRows += countEnrichedRowsInSourceRange(
21134
21288
  chunk.exportResult,
21135
21289
  chunkRows
21136
21290
  );
21137
21291
  batchFailureRows.push(...chunk.exportResult.enrichedDataRows);
21292
+ finalExportResult = options.inPlace ? await commitInPlaceOutput(chunk.exportResult) : chunk.exportResult;
21293
+ await appendBatchManifestEntry({
21294
+ chunkIndex,
21295
+ rows: chunkRows,
21296
+ status: chunk.status,
21297
+ exportResult: finalExportResult
21298
+ });
21138
21299
  workingMergeSourceCsvPath = outputPath;
21300
+ if (options.inPlace && (chunkRows.rowEnd ?? selectedRange.end) < selectedRange.end) {
21301
+ await prepareInPlaceOutput();
21302
+ }
21139
21303
  }
21140
21304
  }
21141
21305
  const outputRows = readCsvRows(outputPath);
@@ -21175,7 +21339,8 @@ function registerEnrichCommand(program) {
21175
21339
  batch: {
21176
21340
  chunks: chunkCount,
21177
21341
  chunkRows: autoBatchRows,
21178
- selectedRows: selectedRange.count
21342
+ selectedRows: selectedRange.count,
21343
+ manifest: batchManifestPath
21179
21344
  },
21180
21345
  output: finalExportResult ? {
21181
21346
  sourceCsvRows: selectedRange.sourceRows,
@@ -21305,7 +21470,7 @@ function registerEnrichCommand(program) {
21305
21470
  } finally {
21306
21471
  if (inPlaceTempDir) {
21307
21472
  await rm(inPlaceTempDir, { recursive: true, force: true });
21308
- } else if (inPlaceTempOutputPath && !inPlaceCommitted) {
21473
+ } else if (inPlaceTempOutputPath) {
21309
21474
  await rm(inPlaceTempOutputPath, { force: true });
21310
21475
  }
21311
21476
  await rm(tempDir, { recursive: true, force: true });
@@ -111,6 +111,7 @@ type PlayStaticControlFlowBranch = {
111
111
  label: string;
112
112
  /** The arm's condition source text, when it has one (omitted for `else`). */
113
113
  condition?: string;
114
+ /** Static work in this arm. Empty for log/throw/return-only arms. */
114
115
  steps: PlayStaticSubstep[];
115
116
  };
116
117
  type PlayStaticSubstep = PlayStaticSubstepMetadata & ({
@@ -111,6 +111,7 @@ type PlayStaticControlFlowBranch = {
111
111
  label: string;
112
112
  /** The arm's condition source text, when it has one (omitted for `else`). */
113
113
  condition?: string;
114
+ /** Static work in this arm. Empty for log/throw/return-only arms. */
114
115
  steps: PlayStaticSubstep[];
115
116
  };
116
117
  type PlayStaticSubstep = PlayStaticSubstepMetadata & ({
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as PlayCompilerManifest } from './compiler-manifest-OwORQ07f.mjs';
1
+ import { a as PlayCompilerManifest } from './compiler-manifest-j6z8qzpd.mjs';
2
2
 
3
3
  declare const DEEPLINE_TOOL_CATEGORIES: readonly ["company_search", "people_search", "people_enrich", "email_finder", "email_verify", "phone_finder", "phone_verify", "identity_resolution", "reverse_lookup", "enrichment", "batch", "premium", "free"];
4
4
  type DeeplineToolCategory = (typeof DEEPLINE_TOOL_CATEGORIES)[number] | (string & {});
@@ -3313,7 +3313,7 @@ type CsvOptions = {
3313
3313
  *
3314
3314
  * @example
3315
3315
  * ```typescript
3316
- * definePlay('example', async (ctx, input: { domain: string }) => {
3316
+ * definePlay('example', async (ctx, input: { domain: string; csv: string }) => {
3317
3317
  * // Call a tool
3318
3318
  * const company = await ctx.tools.execute({
3319
3319
  * id: 'company_search',
@@ -3334,8 +3334,8 @@ type CsvOptions = {
3334
3334
  * }))
3335
3335
  * .run({ description: 'Look up company details.' });
3336
3336
  *
3337
- * // Load CSV data
3338
- * const leads = await ctx.csv('leads.csv');
3337
+ * // Load CSV data from a submitted play input field.
3338
+ * const leads = await ctx.csv(input.csv);
3339
3339
  *
3340
3340
  * // Emit a log line (visible in `play tail`)
3341
3341
  * ctx.log(`Loaded ${await leads.count()} leads`);
@@ -3343,8 +3343,8 @@ type CsvOptions = {
3343
3343
  * // Pause execution
3344
3344
  * await ctx.sleep(1000);
3345
3345
  *
3346
- * // Access the raw input object
3347
- * console.log(ctx.input);
3346
+ * // Access submitted input through the handler's second argument.
3347
+ * ctx.log(`Running for ${input.domain}`);
3348
3348
  *
3349
3349
  * return { company, enriched };
3350
3350
  * });
@@ -3357,7 +3357,12 @@ interface DeeplinePlayRuntimeContext {
3357
3357
  * Use this when a play receives a CSV path from the CLI or API and row work
3358
3358
  * should continue through {@link DeeplinePlayRuntimeContext.dataset}. The path is
3359
3359
  * normally an input field such as `input.csv`, populated by
3360
- * `deepline plays run my.play.ts --csv rows.csv`.
3360
+ * `deepline plays run my.play.ts --csv rows.csv`. Prefer `input.csv` for row
3361
+ * data so the CLI can run strict CSV preflight before starting a run.
3362
+ * Pass-through flags can also target non-reserved field names. If a play
3363
+ * intentionally calls `ctx.csv(input.file)`, use `--input
3364
+ * '{"file":"rows.csv"}'` because `--file` is reserved for the play source
3365
+ * path.
3361
3366
  *
3362
3367
  * Each CSV row becomes an object keyed by canonical column names. Use
3363
3368
  * `options.columns` / `options.rename` to map user headers such as
@@ -3570,7 +3575,11 @@ interface DeeplinePlayRuntimeContext {
3570
3575
  * @param ms - Duration in milliseconds
3571
3576
  */
3572
3577
  sleep(ms: number): Promise<void>;
3573
- /** The raw input object passed when the play was started. */
3578
+ /**
3579
+ * @deprecated Read submitted play input from the handler's second argument:
3580
+ * `definePlay('example', async (ctx, input) => ...)`. This legacy field is
3581
+ * not the supported V2 play input API.
3582
+ */
3574
3583
  readonly input: Record<string, unknown>;
3575
3584
  }
3576
3585
  /**
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as PlayCompilerManifest } from './compiler-manifest-OwORQ07f.js';
1
+ import { a as PlayCompilerManifest } from './compiler-manifest-j6z8qzpd.js';
2
2
 
3
3
  declare const DEEPLINE_TOOL_CATEGORIES: readonly ["company_search", "people_search", "people_enrich", "email_finder", "email_verify", "phone_finder", "phone_verify", "identity_resolution", "reverse_lookup", "enrichment", "batch", "premium", "free"];
4
4
  type DeeplineToolCategory = (typeof DEEPLINE_TOOL_CATEGORIES)[number] | (string & {});
@@ -3313,7 +3313,7 @@ type CsvOptions = {
3313
3313
  *
3314
3314
  * @example
3315
3315
  * ```typescript
3316
- * definePlay('example', async (ctx, input: { domain: string }) => {
3316
+ * definePlay('example', async (ctx, input: { domain: string; csv: string }) => {
3317
3317
  * // Call a tool
3318
3318
  * const company = await ctx.tools.execute({
3319
3319
  * id: 'company_search',
@@ -3334,8 +3334,8 @@ type CsvOptions = {
3334
3334
  * }))
3335
3335
  * .run({ description: 'Look up company details.' });
3336
3336
  *
3337
- * // Load CSV data
3338
- * const leads = await ctx.csv('leads.csv');
3337
+ * // Load CSV data from a submitted play input field.
3338
+ * const leads = await ctx.csv(input.csv);
3339
3339
  *
3340
3340
  * // Emit a log line (visible in `play tail`)
3341
3341
  * ctx.log(`Loaded ${await leads.count()} leads`);
@@ -3343,8 +3343,8 @@ type CsvOptions = {
3343
3343
  * // Pause execution
3344
3344
  * await ctx.sleep(1000);
3345
3345
  *
3346
- * // Access the raw input object
3347
- * console.log(ctx.input);
3346
+ * // Access submitted input through the handler's second argument.
3347
+ * ctx.log(`Running for ${input.domain}`);
3348
3348
  *
3349
3349
  * return { company, enriched };
3350
3350
  * });
@@ -3357,7 +3357,12 @@ interface DeeplinePlayRuntimeContext {
3357
3357
  * Use this when a play receives a CSV path from the CLI or API and row work
3358
3358
  * should continue through {@link DeeplinePlayRuntimeContext.dataset}. The path is
3359
3359
  * normally an input field such as `input.csv`, populated by
3360
- * `deepline plays run my.play.ts --csv rows.csv`.
3360
+ * `deepline plays run my.play.ts --csv rows.csv`. Prefer `input.csv` for row
3361
+ * data so the CLI can run strict CSV preflight before starting a run.
3362
+ * Pass-through flags can also target non-reserved field names. If a play
3363
+ * intentionally calls `ctx.csv(input.file)`, use `--input
3364
+ * '{"file":"rows.csv"}'` because `--file` is reserved for the play source
3365
+ * path.
3361
3366
  *
3362
3367
  * Each CSV row becomes an object keyed by canonical column names. Use
3363
3368
  * `options.columns` / `options.rename` to map user headers such as
@@ -3570,7 +3575,11 @@ interface DeeplinePlayRuntimeContext {
3570
3575
  * @param ms - Duration in milliseconds
3571
3576
  */
3572
3577
  sleep(ms: number): Promise<void>;
3573
- /** The raw input object passed when the play was started. */
3578
+ /**
3579
+ * @deprecated Read submitted play input from the handler's second argument:
3580
+ * `definePlay('example', async (ctx, input) => ...)`. This legacy field is
3581
+ * not the supported V2 play input API.
3582
+ */
3574
3583
  readonly input: Record<string, unknown>;
3575
3584
  }
3576
3585
  /**
package/dist/index.js CHANGED
@@ -422,10 +422,10 @@ var SDK_RELEASE = {
422
422
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
423
423
  // fields shipped in 0.1.153.
424
424
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
425
- version: "0.1.188",
425
+ version: "0.1.190",
426
426
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
427
427
  supportPolicy: {
428
- latest: "0.1.188",
428
+ latest: "0.1.190",
429
429
  minimumSupported: "0.1.53",
430
430
  deprecatedBelow: "0.1.53",
431
431
  commandMinimumSupported: [
package/dist/index.mjs CHANGED
@@ -352,10 +352,10 @@ var SDK_RELEASE = {
352
352
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
353
353
  // fields shipped in 0.1.153.
354
354
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
355
- version: "0.1.188",
355
+ version: "0.1.190",
356
356
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
357
357
  supportPolicy: {
358
- latest: "0.1.188",
358
+ latest: "0.1.190",
359
359
  minimumSupported: "0.1.53",
360
360
  deprecatedBelow: "0.1.53",
361
361
  commandMinimumSupported: [
@@ -1,5 +1,5 @@
1
- import { P as PlayArtifactKind$1, a as PlayCompilerManifest } from '../compiler-manifest-OwORQ07f.mjs';
2
- export { b as PLAY_ARTIFACT_KINDS } from '../compiler-manifest-OwORQ07f.mjs';
1
+ import { P as PlayArtifactKind$1, a as PlayCompilerManifest } from '../compiler-manifest-j6z8qzpd.mjs';
2
+ export { b as PLAY_ARTIFACT_KINDS } from '../compiler-manifest-j6z8qzpd.mjs';
3
3
 
4
4
  type PlayPackageImport = {
5
5
  name: string;
@@ -1,5 +1,5 @@
1
- import { P as PlayArtifactKind$1, a as PlayCompilerManifest } from '../compiler-manifest-OwORQ07f.js';
2
- export { b as PLAY_ARTIFACT_KINDS } from '../compiler-manifest-OwORQ07f.js';
1
+ import { P as PlayArtifactKind$1, a as PlayCompilerManifest } from '../compiler-manifest-j6z8qzpd.js';
2
+ export { b as PLAY_ARTIFACT_KINDS } from '../compiler-manifest-j6z8qzpd.js';
3
3
 
4
4
  type PlayPackageImport = {
5
5
  name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.188",
3
+ "version": "0.1.190",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {