deepline 0.1.82 → 0.1.85

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.
package/dist/cli/index.js CHANGED
@@ -229,10 +229,10 @@ var import_node_path2 = require("path");
229
229
 
230
230
  // src/release.ts
231
231
  var SDK_RELEASE = {
232
- version: "0.1.82",
232
+ version: "0.1.85",
233
233
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
234
234
  supportPolicy: {
235
- latest: "0.1.82",
235
+ latest: "0.1.85",
236
236
  minimumSupported: "0.1.53",
237
237
  deprecatedBelow: "0.1.53"
238
238
  }
@@ -2136,6 +2136,9 @@ function readCsvRows(csvPath) {
2136
2136
  function csvStringFromRows(rows, columns) {
2137
2137
  return (0, import_sync2.stringify)(rows, {
2138
2138
  header: true,
2139
+ cast: {
2140
+ boolean: (value) => value ? "true" : "false"
2141
+ },
2139
2142
  ...columns?.length ? { columns } : {}
2140
2143
  });
2141
2144
  }
@@ -5506,12 +5509,16 @@ var PLAY_DEDUP_BACKENDS = {
5506
5509
  var PLAY_SCHEDULER_BACKENDS = {
5507
5510
  temporal: "temporal",
5508
5511
  cfWorkflows: "cf-workflows",
5512
+ postgres: "postgres",
5509
5513
  inProcess: "in-process"
5510
5514
  };
5511
5515
 
5512
5516
  // ../shared_libs/play-runtime/providers.ts
5513
5517
  var PLAY_RUNTIME_PROVIDER_IDS = {
5514
5518
  workersEdge: "workers_edge",
5519
+ postgresFast: "postgres_fast",
5520
+ postgresFastSandbox: "postgres_fast_sandbox",
5521
+ postgresFastWorkers: "postgres_fast_workers",
5515
5522
  local: "local"
5516
5523
  };
5517
5524
  var PLAY_RUNTIME_PROVIDERS = {
@@ -5523,6 +5530,30 @@ var PLAY_RUNTIME_PROVIDERS = {
5523
5530
  artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
5524
5531
  label: "Cloudflare Dynamic Workflows + Dynamic Workers + DO dedup"
5525
5532
  },
5533
+ postgres_fast: {
5534
+ id: PLAY_RUNTIME_PROVIDER_IDS.postgresFast,
5535
+ scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
5536
+ runner: PLAY_RUNTIME_BACKENDS.daytona,
5537
+ dedup: PLAY_DEDUP_BACKENDS.durableObject,
5538
+ artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
5539
+ label: "Experimental Postgres Scheduler + warm sandbox runner + DO dedup"
5540
+ },
5541
+ postgres_fast_sandbox: {
5542
+ id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastSandbox,
5543
+ scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
5544
+ runner: PLAY_RUNTIME_BACKENDS.daytona,
5545
+ dedup: PLAY_DEDUP_BACKENDS.durableObject,
5546
+ artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
5547
+ label: "Experimental Postgres Scheduler + warm sandbox runner + DO dedup"
5548
+ },
5549
+ postgres_fast_workers: {
5550
+ id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastWorkers,
5551
+ scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
5552
+ runner: PLAY_RUNTIME_BACKENDS.cloudflareWorkers,
5553
+ dedup: PLAY_DEDUP_BACKENDS.durableObject,
5554
+ artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
5555
+ label: "Experimental Postgres Scheduler + Queue/DO-woken Workers + DO dedup"
5556
+ },
5526
5557
  local: {
5527
5558
  id: PLAY_RUNTIME_PROVIDER_IDS.local,
5528
5559
  scheduler: PLAY_SCHEDULER_BACKENDS.temporal,
@@ -6575,6 +6606,9 @@ function jsonSchemaTypeExpression(schema) {
6575
6606
  function objectPropertySchema(schema, property) {
6576
6607
  return isRecord3(schema) && isRecord3(schema.properties) ? schema.properties[property] : null;
6577
6608
  }
6609
+ function playOutputHasField(schema, field) {
6610
+ return objectPropertySchema(schema, field) != null;
6611
+ }
6578
6612
  function finderResultTypeName(finder) {
6579
6613
  return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
6580
6614
  }
@@ -6585,13 +6619,13 @@ function renderFinderPlayResultType(input2) {
6585
6619
  input2.play.outputSchema,
6586
6620
  outputField
6587
6621
  );
6588
- const fieldType = fieldSchema ? jsonSchemaTypeExpression(fieldSchema) : "string | null";
6589
- return `type ${finderResultTypeName(input2.finder)} =
6590
- | string
6591
- | null
6592
- | {
6622
+ if (fieldSchema) {
6623
+ const fieldType = jsonSchemaTypeExpression(fieldSchema);
6624
+ return `type ${finderResultTypeName(input2.finder)} = {
6593
6625
  ${outputField}?: ${fieldType};
6594
6626
  };`;
6627
+ }
6628
+ return `type ${finderResultTypeName(input2.finder)} = ${jsonSchemaTypeExpression(input2.play.outputSchema)};`;
6595
6629
  }
6596
6630
  function generatedFinderPlayResultTypes(input2) {
6597
6631
  return ["email_finder", "phone_finder"].flatMap((finder) => {
@@ -6611,6 +6645,15 @@ function exampleValueComment(field) {
6611
6645
  if (field === "roles" || field.endsWith("s")) return '["..."]';
6612
6646
  return '"..."';
6613
6647
  }
6648
+ function rowFieldValueExpression(field) {
6649
+ if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size" || field === "max_duration") {
6650
+ return `Number(row[${jsString(field)}] ?? 0)`;
6651
+ }
6652
+ if (field === "roles" || field.endsWith("s")) {
6653
+ return `String(row[${jsString(field)}] ?? '').split(',').map((item) => item.trim()).filter(Boolean)`;
6654
+ }
6655
+ return `String(row[${jsString(field)}] ?? '')`;
6656
+ }
6614
6657
  function generateContactInputObjectFromSchema(schema, indent2, label, fallbackFields = ["first_name", "last_name", "domain"]) {
6615
6658
  const details = schemaFieldDetails(schema);
6616
6659
  const required = details.required.length ? details.required : fallbackFields;
@@ -6621,7 +6664,9 @@ function generateContactInputObjectFromSchema(schema, indent2, label, fallbackFi
6621
6664
  `${indent2}// Required: ${required.join(", ") || "none declared"}.`
6622
6665
  ];
6623
6666
  for (const field of required) {
6624
- lines.push(`${indent2}// ${field}: row["TODO_SOURCE_FIELD"],`);
6667
+ lines.push(
6668
+ `${indent2}${field}: ${rowFieldValueExpression(field)}, // TODO: confirm source field`
6669
+ );
6625
6670
  }
6626
6671
  if (optional.length > 0) {
6627
6672
  lines.push("");
@@ -7007,9 +7052,9 @@ function generatePlaySourceRowsBlock(input2) {
7007
7052
  });
7008
7053
  return `const sourceInput = ${playInput};
7009
7054
  throw new Error(${jsString(`TODO: map sourceInput for ${input2.source.value}, choose the play output rows field, then delete this throw.`)});
7010
- const sourceResult = await ctx.runPlay('source_play', ${jsString(input2.source.value)}, sourceInput, {
7055
+ const sourceResult = (await ctx.runPlay('source_play', ${jsString(input2.source.value)}, sourceInput, {
7011
7056
  description: ${jsString(`Seed ${input2.entity} rows from the selected play.`)},
7012
- });
7057
+ })) as { rows?: unknown[] };
7013
7058
  // TODO: Replace sourceResult.rows with the selected play's actual row output field.
7014
7059
  const ${input2.collection}: ${input2.collectionType}[] = (sourceResult.rows ?? []) as ${input2.collectionType}[];`;
7015
7060
  }
@@ -7099,14 +7144,14 @@ function generateSourceSeedBlock(input2) {
7099
7144
  for (const [index, company] of companies.slice(0, limit).entries()) {
7100
7145
  const peopleInput = ${peopleInput};
7101
7146
  throw new Error(${jsString(`TODO: map company fields into peopleInput for ${peoplePlayRef}, choose the play output rows field, then delete this throw.`)});
7102
- const peopleResult = await ctx.runPlay(
7147
+ const peopleResult = (await ctx.runPlay(
7103
7148
  \`people_play_\${index}\`,
7104
7149
  ${jsString(peoplePlayRef)},
7105
7150
  peopleInput,
7106
7151
  {
7107
7152
  description: 'Map one company row into people/contact rows with the selected play.',
7108
7153
  },
7109
- );
7154
+ )) as { rows?: unknown[] };
7110
7155
  // TODO: Replace peopleResult.rows with the selected play's actual contact rows field.
7111
7156
  contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
7112
7157
  }`;
@@ -7130,6 +7175,10 @@ function optionalFinderValueExpression(candidateExpression, outputField) {
7130
7175
  function generateFinderPlayStep(input2) {
7131
7176
  const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
7132
7177
  const resultTypeName = finderResultTypeName(input2.finder);
7178
+ const returnsObjectWithField = playOutputHasField(
7179
+ input2.play?.outputSchema,
7180
+ outputField
7181
+ );
7133
7182
  const payload = generateContactInputObjectFromSchema(
7134
7183
  input2.play?.inputSchema,
7135
7184
  " ",
@@ -7146,9 +7195,7 @@ function generateFinderPlayStep(input2) {
7146
7195
  description: ${jsString(`Run ${input2.finder} play.`)},
7147
7196
  },
7148
7197
  );
7149
- return typeof ${input2.aggregateStepName}Result === 'string'
7150
- ? ${input2.aggregateStepName}Result.trim() || null
7151
- : ${input2.aggregateStepName}Result?.${outputField} ?? null;
7198
+ return ${returnsObjectWithField ? `${input2.aggregateStepName}Result.${outputField} ?? null` : `${input2.aggregateStepName}Result ?? null`};
7152
7199
  })`;
7153
7200
  }
7154
7201
  function generateFinderProviderResolver(input2) {
@@ -8127,9 +8174,10 @@ function formatUnresolvedPackagedFiles(filePath, unresolvedFileReferences) {
8127
8174
  const details = unresolvedFileReferences.map((unresolved) => `${unresolved.sourceFragment}: ${unresolved.message}`).join("; ");
8128
8175
  return `Failed to package local ctx.csv(...) files in ${filePath}: ${details}`;
8129
8176
  }
8130
- async function collectBundledPlayGraph(entryFile) {
8177
+ async function collectBundledPlayGraph(entryFile, profile = null) {
8131
8178
  const nodes = /* @__PURE__ */ new Map();
8132
8179
  const visiting = /* @__PURE__ */ new Set();
8180
+ const artifactKind = resolveExecutionProfile(profile).artifactKind;
8133
8181
  const visit = async (filePath) => {
8134
8182
  const absolutePath = normalizePlayPath(filePath);
8135
8183
  const cached = nodes.get(absolutePath);
@@ -8144,7 +8192,7 @@ async function collectBundledPlayGraph(entryFile) {
8144
8192
  visiting.add(absolutePath);
8145
8193
  try {
8146
8194
  const bundleResult = await bundlePlayFile2(absolutePath, {
8147
- target: "esm_workers"
8195
+ target: artifactKind
8148
8196
  });
8149
8197
  if (bundleResult.success === false) {
8150
8198
  throw new Error(
@@ -8259,7 +8307,8 @@ function formatTimestamp(value) {
8259
8307
  return date.toISOString();
8260
8308
  }
8261
8309
  function formatRunLine(run) {
8262
- return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)}`;
8310
+ const credits = typeof run.billingTotalCredits === "number" && Number.isFinite(run.billingTotalCredits) ? `${formatCreditAmount(run.billingTotalCredits)} credits` : "\u2014";
8311
+ return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)} ${credits}`;
8263
8312
  }
8264
8313
  function isTransientPlayStreamError(error) {
8265
8314
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -10111,7 +10160,7 @@ function writeStartedPlayRun(input2) {
10111
10160
  );
10112
10161
  }
10113
10162
  function parsePlayRunOptions(args) {
10114
- 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 '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\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.";
10163
+ 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 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.";
10115
10164
  let filePath = null;
10116
10165
  let playName = null;
10117
10166
  let input2 = null;
@@ -10124,6 +10173,7 @@ function parsePlayRunOptions(args) {
10124
10173
  const force = args.includes("--force");
10125
10174
  const noOpen = args.includes("--no-open");
10126
10175
  let waitTimeoutMs = null;
10176
+ let profile = null;
10127
10177
  for (let index = 0; index < args.length; index += 1) {
10128
10178
  const arg = args[index];
10129
10179
  if (arg === "--file" && args[index + 1]) {
@@ -10142,6 +10192,16 @@ function parsePlayRunOptions(args) {
10142
10192
  revisionId = args[++index];
10143
10193
  continue;
10144
10194
  }
10195
+ if (arg === "--profile") {
10196
+ const value = args[index + 1];
10197
+ if (!value) {
10198
+ throw new Error("--profile requires an execution profile id.");
10199
+ }
10200
+ profile = value.trim();
10201
+ resolveExecutionProfile(profile);
10202
+ index += 1;
10203
+ continue;
10204
+ }
10145
10205
  if (arg === "--live") {
10146
10206
  revisionSelector = "live";
10147
10207
  continue;
@@ -10229,7 +10289,8 @@ function parsePlayRunOptions(args) {
10229
10289
  fullJson,
10230
10290
  waitTimeoutMs,
10231
10291
  force,
10232
- noOpen
10292
+ noOpen,
10293
+ profile
10233
10294
  };
10234
10295
  }
10235
10296
  function parsePlayCheckOptions(args) {
@@ -10506,7 +10567,7 @@ async function handleFileBackedRun(options) {
10506
10567
  graph = await traceCliSpan(
10507
10568
  "cli.play_file_bundle_graph",
10508
10569
  { targetKind: "file" },
10509
- () => collectBundledPlayGraph(absolutePlayPath)
10570
+ () => collectBundledPlayGraph(absolutePlayPath, options.profile)
10510
10571
  );
10511
10572
  await traceCliSpan(
10512
10573
  "cli.play_file_compile_manifests",
@@ -10566,7 +10627,8 @@ async function handleFileBackedRun(options) {
10566
10627
  ...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
10567
10628
  ...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
10568
10629
  ...stagedFileInputs.packagedFiles.length ? { packagedFiles: stagedFileInputs.packagedFiles } : {},
10569
- ...options.force ? { force: true } : {}
10630
+ ...options.force ? { force: true } : {},
10631
+ ...options.profile ? { profile: options.profile } : {}
10570
10632
  };
10571
10633
  if (options.watch) {
10572
10634
  progress.phase("starting run");
@@ -10712,7 +10774,8 @@ async function handleNamedRun(options) {
10712
10774
  ...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
10713
10775
  ...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
10714
10776
  ...stagedFileInputs.packagedFiles.length ? { packagedFiles: stagedFileInputs.packagedFiles } : {},
10715
- ...options.force ? { force: true } : {}
10777
+ ...options.force ? { force: true } : {},
10778
+ ...options.profile ? { profile: options.profile } : {}
10716
10779
  };
10717
10780
  if (options.watch) {
10718
10781
  progress.phase("starting run");
@@ -10876,10 +10939,12 @@ async function handleRunsList(args) {
10876
10939
  startedAt: run.startTime,
10877
10940
  finishedAt: run.closeTime,
10878
10941
  executionTime: run.executionTime,
10942
+ billingTotalCredits: run.billingTotalCredits,
10943
+ billingMaxCreditsPerRun: run.billingMaxCreditsPerRun,
10879
10944
  playName: run.memo?.playName ?? playName
10880
10945
  }));
10881
10946
  const lines = runs.length === 0 ? [`No runs found for ${playName}.`] : runs.map(
10882
- (run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)}`
10947
+ (run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)} ${typeof run.billingTotalCredits === "number" && Number.isFinite(run.billingTotalCredits) ? `${formatCreditAmount(run.billingTotalCredits)} credits` : "\u2014"}`
10883
10948
  );
10884
10949
  printCommandEnvelope(
10885
10950
  {
@@ -11800,6 +11865,9 @@ Examples:
11800
11865
  ).option("--file <path>", "Local play file to run").option("--name <name>", "Saved play name to run").option("-i, --input <json>", "Input JSON object or @file path").option("--live", "Run the current live revision explicitly").option("--latest", "Run the newest saved revision, even if it is not live").option(
11801
11866
  "--revision-id <id>",
11802
11867
  "Run a specific saved revision instead of the live revision"
11868
+ ).option(
11869
+ "--profile <id>",
11870
+ "Internal/testing: override the execution profile for this run"
11803
11871
  ).option("--watch", "Compatibility alias; run waits by default").option("--wait", "Compatibility alias; run waits by default").option("--no-wait", "Start the run and return immediately").option(
11804
11872
  "--logs",
11805
11873
  "When output is non-interactive, stream play logs to stderr while waiting"
@@ -11833,6 +11901,7 @@ Pass-through input flags:
11833
11901
  ...options.live ? ["--live"] : [],
11834
11902
  ...options.latest ? ["--latest"] : [],
11835
11903
  ...options.revisionId ? ["--revision-id", options.revisionId] : [],
11904
+ ...options.profile ? ["--profile", options.profile] : [],
11836
11905
  ...options.wait === false ? ["--no-wait"] : [],
11837
11906
  ...options.watch || options.wait ? ["--watch"] : [],
11838
11907
  ...options.logs ? ["--logs"] : [],
@@ -206,10 +206,10 @@ import { join as join2 } from "path";
206
206
 
207
207
  // src/release.ts
208
208
  var SDK_RELEASE = {
209
- version: "0.1.82",
209
+ version: "0.1.85",
210
210
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
211
211
  supportPolicy: {
212
- latest: "0.1.82",
212
+ latest: "0.1.85",
213
213
  minimumSupported: "0.1.53",
214
214
  deprecatedBelow: "0.1.53"
215
215
  }
@@ -2125,6 +2125,9 @@ function readCsvRows(csvPath) {
2125
2125
  function csvStringFromRows(rows, columns) {
2126
2126
  return stringify(rows, {
2127
2127
  header: true,
2128
+ cast: {
2129
+ boolean: (value) => value ? "true" : "false"
2130
+ },
2128
2131
  ...columns?.length ? { columns } : {}
2129
2132
  });
2130
2133
  }
@@ -5508,12 +5511,16 @@ var PLAY_DEDUP_BACKENDS = {
5508
5511
  var PLAY_SCHEDULER_BACKENDS = {
5509
5512
  temporal: "temporal",
5510
5513
  cfWorkflows: "cf-workflows",
5514
+ postgres: "postgres",
5511
5515
  inProcess: "in-process"
5512
5516
  };
5513
5517
 
5514
5518
  // ../shared_libs/play-runtime/providers.ts
5515
5519
  var PLAY_RUNTIME_PROVIDER_IDS = {
5516
5520
  workersEdge: "workers_edge",
5521
+ postgresFast: "postgres_fast",
5522
+ postgresFastSandbox: "postgres_fast_sandbox",
5523
+ postgresFastWorkers: "postgres_fast_workers",
5517
5524
  local: "local"
5518
5525
  };
5519
5526
  var PLAY_RUNTIME_PROVIDERS = {
@@ -5525,6 +5532,30 @@ var PLAY_RUNTIME_PROVIDERS = {
5525
5532
  artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
5526
5533
  label: "Cloudflare Dynamic Workflows + Dynamic Workers + DO dedup"
5527
5534
  },
5535
+ postgres_fast: {
5536
+ id: PLAY_RUNTIME_PROVIDER_IDS.postgresFast,
5537
+ scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
5538
+ runner: PLAY_RUNTIME_BACKENDS.daytona,
5539
+ dedup: PLAY_DEDUP_BACKENDS.durableObject,
5540
+ artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
5541
+ label: "Experimental Postgres Scheduler + warm sandbox runner + DO dedup"
5542
+ },
5543
+ postgres_fast_sandbox: {
5544
+ id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastSandbox,
5545
+ scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
5546
+ runner: PLAY_RUNTIME_BACKENDS.daytona,
5547
+ dedup: PLAY_DEDUP_BACKENDS.durableObject,
5548
+ artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
5549
+ label: "Experimental Postgres Scheduler + warm sandbox runner + DO dedup"
5550
+ },
5551
+ postgres_fast_workers: {
5552
+ id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastWorkers,
5553
+ scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
5554
+ runner: PLAY_RUNTIME_BACKENDS.cloudflareWorkers,
5555
+ dedup: PLAY_DEDUP_BACKENDS.durableObject,
5556
+ artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
5557
+ label: "Experimental Postgres Scheduler + Queue/DO-woken Workers + DO dedup"
5558
+ },
5528
5559
  local: {
5529
5560
  id: PLAY_RUNTIME_PROVIDER_IDS.local,
5530
5561
  scheduler: PLAY_SCHEDULER_BACKENDS.temporal,
@@ -6584,6 +6615,9 @@ function jsonSchemaTypeExpression(schema) {
6584
6615
  function objectPropertySchema(schema, property) {
6585
6616
  return isRecord3(schema) && isRecord3(schema.properties) ? schema.properties[property] : null;
6586
6617
  }
6618
+ function playOutputHasField(schema, field) {
6619
+ return objectPropertySchema(schema, field) != null;
6620
+ }
6587
6621
  function finderResultTypeName(finder) {
6588
6622
  return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
6589
6623
  }
@@ -6594,13 +6628,13 @@ function renderFinderPlayResultType(input2) {
6594
6628
  input2.play.outputSchema,
6595
6629
  outputField
6596
6630
  );
6597
- const fieldType = fieldSchema ? jsonSchemaTypeExpression(fieldSchema) : "string | null";
6598
- return `type ${finderResultTypeName(input2.finder)} =
6599
- | string
6600
- | null
6601
- | {
6631
+ if (fieldSchema) {
6632
+ const fieldType = jsonSchemaTypeExpression(fieldSchema);
6633
+ return `type ${finderResultTypeName(input2.finder)} = {
6602
6634
  ${outputField}?: ${fieldType};
6603
6635
  };`;
6636
+ }
6637
+ return `type ${finderResultTypeName(input2.finder)} = ${jsonSchemaTypeExpression(input2.play.outputSchema)};`;
6604
6638
  }
6605
6639
  function generatedFinderPlayResultTypes(input2) {
6606
6640
  return ["email_finder", "phone_finder"].flatMap((finder) => {
@@ -6620,6 +6654,15 @@ function exampleValueComment(field) {
6620
6654
  if (field === "roles" || field.endsWith("s")) return '["..."]';
6621
6655
  return '"..."';
6622
6656
  }
6657
+ function rowFieldValueExpression(field) {
6658
+ if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size" || field === "max_duration") {
6659
+ return `Number(row[${jsString(field)}] ?? 0)`;
6660
+ }
6661
+ if (field === "roles" || field.endsWith("s")) {
6662
+ return `String(row[${jsString(field)}] ?? '').split(',').map((item) => item.trim()).filter(Boolean)`;
6663
+ }
6664
+ return `String(row[${jsString(field)}] ?? '')`;
6665
+ }
6623
6666
  function generateContactInputObjectFromSchema(schema, indent2, label, fallbackFields = ["first_name", "last_name", "domain"]) {
6624
6667
  const details = schemaFieldDetails(schema);
6625
6668
  const required = details.required.length ? details.required : fallbackFields;
@@ -6630,7 +6673,9 @@ function generateContactInputObjectFromSchema(schema, indent2, label, fallbackFi
6630
6673
  `${indent2}// Required: ${required.join(", ") || "none declared"}.`
6631
6674
  ];
6632
6675
  for (const field of required) {
6633
- lines.push(`${indent2}// ${field}: row["TODO_SOURCE_FIELD"],`);
6676
+ lines.push(
6677
+ `${indent2}${field}: ${rowFieldValueExpression(field)}, // TODO: confirm source field`
6678
+ );
6634
6679
  }
6635
6680
  if (optional.length > 0) {
6636
6681
  lines.push("");
@@ -7016,9 +7061,9 @@ function generatePlaySourceRowsBlock(input2) {
7016
7061
  });
7017
7062
  return `const sourceInput = ${playInput};
7018
7063
  throw new Error(${jsString(`TODO: map sourceInput for ${input2.source.value}, choose the play output rows field, then delete this throw.`)});
7019
- const sourceResult = await ctx.runPlay('source_play', ${jsString(input2.source.value)}, sourceInput, {
7064
+ const sourceResult = (await ctx.runPlay('source_play', ${jsString(input2.source.value)}, sourceInput, {
7020
7065
  description: ${jsString(`Seed ${input2.entity} rows from the selected play.`)},
7021
- });
7066
+ })) as { rows?: unknown[] };
7022
7067
  // TODO: Replace sourceResult.rows with the selected play's actual row output field.
7023
7068
  const ${input2.collection}: ${input2.collectionType}[] = (sourceResult.rows ?? []) as ${input2.collectionType}[];`;
7024
7069
  }
@@ -7108,14 +7153,14 @@ function generateSourceSeedBlock(input2) {
7108
7153
  for (const [index, company] of companies.slice(0, limit).entries()) {
7109
7154
  const peopleInput = ${peopleInput};
7110
7155
  throw new Error(${jsString(`TODO: map company fields into peopleInput for ${peoplePlayRef}, choose the play output rows field, then delete this throw.`)});
7111
- const peopleResult = await ctx.runPlay(
7156
+ const peopleResult = (await ctx.runPlay(
7112
7157
  \`people_play_\${index}\`,
7113
7158
  ${jsString(peoplePlayRef)},
7114
7159
  peopleInput,
7115
7160
  {
7116
7161
  description: 'Map one company row into people/contact rows with the selected play.',
7117
7162
  },
7118
- );
7163
+ )) as { rows?: unknown[] };
7119
7164
  // TODO: Replace peopleResult.rows with the selected play's actual contact rows field.
7120
7165
  contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
7121
7166
  }`;
@@ -7139,6 +7184,10 @@ function optionalFinderValueExpression(candidateExpression, outputField) {
7139
7184
  function generateFinderPlayStep(input2) {
7140
7185
  const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
7141
7186
  const resultTypeName = finderResultTypeName(input2.finder);
7187
+ const returnsObjectWithField = playOutputHasField(
7188
+ input2.play?.outputSchema,
7189
+ outputField
7190
+ );
7142
7191
  const payload = generateContactInputObjectFromSchema(
7143
7192
  input2.play?.inputSchema,
7144
7193
  " ",
@@ -7155,9 +7204,7 @@ function generateFinderPlayStep(input2) {
7155
7204
  description: ${jsString(`Run ${input2.finder} play.`)},
7156
7205
  },
7157
7206
  );
7158
- return typeof ${input2.aggregateStepName}Result === 'string'
7159
- ? ${input2.aggregateStepName}Result.trim() || null
7160
- : ${input2.aggregateStepName}Result?.${outputField} ?? null;
7207
+ return ${returnsObjectWithField ? `${input2.aggregateStepName}Result.${outputField} ?? null` : `${input2.aggregateStepName}Result ?? null`};
7161
7208
  })`;
7162
7209
  }
7163
7210
  function generateFinderProviderResolver(input2) {
@@ -8136,9 +8183,10 @@ function formatUnresolvedPackagedFiles(filePath, unresolvedFileReferences) {
8136
8183
  const details = unresolvedFileReferences.map((unresolved) => `${unresolved.sourceFragment}: ${unresolved.message}`).join("; ");
8137
8184
  return `Failed to package local ctx.csv(...) files in ${filePath}: ${details}`;
8138
8185
  }
8139
- async function collectBundledPlayGraph(entryFile) {
8186
+ async function collectBundledPlayGraph(entryFile, profile = null) {
8140
8187
  const nodes = /* @__PURE__ */ new Map();
8141
8188
  const visiting = /* @__PURE__ */ new Set();
8189
+ const artifactKind = resolveExecutionProfile(profile).artifactKind;
8142
8190
  const visit = async (filePath) => {
8143
8191
  const absolutePath = normalizePlayPath(filePath);
8144
8192
  const cached = nodes.get(absolutePath);
@@ -8153,7 +8201,7 @@ async function collectBundledPlayGraph(entryFile) {
8153
8201
  visiting.add(absolutePath);
8154
8202
  try {
8155
8203
  const bundleResult = await bundlePlayFile2(absolutePath, {
8156
- target: "esm_workers"
8204
+ target: artifactKind
8157
8205
  });
8158
8206
  if (bundleResult.success === false) {
8159
8207
  throw new Error(
@@ -8268,7 +8316,8 @@ function formatTimestamp(value) {
8268
8316
  return date.toISOString();
8269
8317
  }
8270
8318
  function formatRunLine(run) {
8271
- return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)}`;
8319
+ const credits = typeof run.billingTotalCredits === "number" && Number.isFinite(run.billingTotalCredits) ? `${formatCreditAmount(run.billingTotalCredits)} credits` : "\u2014";
8320
+ return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)} ${credits}`;
8272
8321
  }
8273
8322
  function isTransientPlayStreamError(error) {
8274
8323
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -10120,7 +10169,7 @@ function writeStartedPlayRun(input2) {
10120
10169
  );
10121
10170
  }
10122
10171
  function parsePlayRunOptions(args) {
10123
- 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 '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\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.";
10172
+ 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 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.";
10124
10173
  let filePath = null;
10125
10174
  let playName = null;
10126
10175
  let input2 = null;
@@ -10133,6 +10182,7 @@ function parsePlayRunOptions(args) {
10133
10182
  const force = args.includes("--force");
10134
10183
  const noOpen = args.includes("--no-open");
10135
10184
  let waitTimeoutMs = null;
10185
+ let profile = null;
10136
10186
  for (let index = 0; index < args.length; index += 1) {
10137
10187
  const arg = args[index];
10138
10188
  if (arg === "--file" && args[index + 1]) {
@@ -10151,6 +10201,16 @@ function parsePlayRunOptions(args) {
10151
10201
  revisionId = args[++index];
10152
10202
  continue;
10153
10203
  }
10204
+ if (arg === "--profile") {
10205
+ const value = args[index + 1];
10206
+ if (!value) {
10207
+ throw new Error("--profile requires an execution profile id.");
10208
+ }
10209
+ profile = value.trim();
10210
+ resolveExecutionProfile(profile);
10211
+ index += 1;
10212
+ continue;
10213
+ }
10154
10214
  if (arg === "--live") {
10155
10215
  revisionSelector = "live";
10156
10216
  continue;
@@ -10238,7 +10298,8 @@ function parsePlayRunOptions(args) {
10238
10298
  fullJson,
10239
10299
  waitTimeoutMs,
10240
10300
  force,
10241
- noOpen
10301
+ noOpen,
10302
+ profile
10242
10303
  };
10243
10304
  }
10244
10305
  function parsePlayCheckOptions(args) {
@@ -10515,7 +10576,7 @@ async function handleFileBackedRun(options) {
10515
10576
  graph = await traceCliSpan(
10516
10577
  "cli.play_file_bundle_graph",
10517
10578
  { targetKind: "file" },
10518
- () => collectBundledPlayGraph(absolutePlayPath)
10579
+ () => collectBundledPlayGraph(absolutePlayPath, options.profile)
10519
10580
  );
10520
10581
  await traceCliSpan(
10521
10582
  "cli.play_file_compile_manifests",
@@ -10575,7 +10636,8 @@ async function handleFileBackedRun(options) {
10575
10636
  ...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
10576
10637
  ...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
10577
10638
  ...stagedFileInputs.packagedFiles.length ? { packagedFiles: stagedFileInputs.packagedFiles } : {},
10578
- ...options.force ? { force: true } : {}
10639
+ ...options.force ? { force: true } : {},
10640
+ ...options.profile ? { profile: options.profile } : {}
10579
10641
  };
10580
10642
  if (options.watch) {
10581
10643
  progress.phase("starting run");
@@ -10721,7 +10783,8 @@ async function handleNamedRun(options) {
10721
10783
  ...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
10722
10784
  ...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
10723
10785
  ...stagedFileInputs.packagedFiles.length ? { packagedFiles: stagedFileInputs.packagedFiles } : {},
10724
- ...options.force ? { force: true } : {}
10786
+ ...options.force ? { force: true } : {},
10787
+ ...options.profile ? { profile: options.profile } : {}
10725
10788
  };
10726
10789
  if (options.watch) {
10727
10790
  progress.phase("starting run");
@@ -10885,10 +10948,12 @@ async function handleRunsList(args) {
10885
10948
  startedAt: run.startTime,
10886
10949
  finishedAt: run.closeTime,
10887
10950
  executionTime: run.executionTime,
10951
+ billingTotalCredits: run.billingTotalCredits,
10952
+ billingMaxCreditsPerRun: run.billingMaxCreditsPerRun,
10888
10953
  playName: run.memo?.playName ?? playName
10889
10954
  }));
10890
10955
  const lines = runs.length === 0 ? [`No runs found for ${playName}.`] : runs.map(
10891
- (run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)}`
10956
+ (run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)} ${typeof run.billingTotalCredits === "number" && Number.isFinite(run.billingTotalCredits) ? `${formatCreditAmount(run.billingTotalCredits)} credits` : "\u2014"}`
10892
10957
  );
10893
10958
  printCommandEnvelope(
10894
10959
  {
@@ -11809,6 +11874,9 @@ Examples:
11809
11874
  ).option("--file <path>", "Local play file to run").option("--name <name>", "Saved play name to run").option("-i, --input <json>", "Input JSON object or @file path").option("--live", "Run the current live revision explicitly").option("--latest", "Run the newest saved revision, even if it is not live").option(
11810
11875
  "--revision-id <id>",
11811
11876
  "Run a specific saved revision instead of the live revision"
11877
+ ).option(
11878
+ "--profile <id>",
11879
+ "Internal/testing: override the execution profile for this run"
11812
11880
  ).option("--watch", "Compatibility alias; run waits by default").option("--wait", "Compatibility alias; run waits by default").option("--no-wait", "Start the run and return immediately").option(
11813
11881
  "--logs",
11814
11882
  "When output is non-interactive, stream play logs to stderr while waiting"
@@ -11842,6 +11910,7 @@ Pass-through input flags:
11842
11910
  ...options.live ? ["--live"] : [],
11843
11911
  ...options.latest ? ["--latest"] : [],
11844
11912
  ...options.revisionId ? ["--revision-id", options.revisionId] : [],
11913
+ ...options.profile ? ["--profile", options.profile] : [],
11845
11914
  ...options.wait === false ? ["--no-wait"] : [],
11846
11915
  ...options.watch || options.wait ? ["--watch"] : [],
11847
11916
  ...options.logs ? ["--logs"] : [],