deepline 0.1.67 → 0.1.70

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.
@@ -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.67",
209
+ version: "0.1.70",
210
210
  apiContract: "2026-05-play-bootstrap-dataset-summary",
211
211
  supportPolicy: {
212
- latest: "0.1.67",
212
+ latest: "0.1.70",
213
213
  minimumSupported: "0.1.53",
214
214
  deprecatedBelow: "0.1.53"
215
215
  }
@@ -716,7 +716,7 @@ var DeeplineClient = class {
716
716
  list: (options2) => this.listRuns(options2),
717
717
  tail: (runId, options2) => this.tailRun(runId, options2),
718
718
  logs: (runId, options2) => this.getRunLogs(runId, options2),
719
- exportDatasetRows: (input) => this.getPlaySheetRows(input),
719
+ exportDatasetRows: (input2) => this.getPlaySheetRows(input2),
720
720
  stop: (runId, options2) => this.stopRun(runId, options2)
721
721
  };
722
722
  }
@@ -803,6 +803,22 @@ var DeeplineClient = class {
803
803
  };
804
804
  }
805
805
  // ——————————————————————————————————————————————————————————
806
+ // Secrets
807
+ // ——————————————————————————————————————————————————————————
808
+ async listSecrets() {
809
+ const response = await this.http.get(
810
+ "/api/v2/secrets"
811
+ );
812
+ return Array.isArray(response.secrets) ? response.secrets : [];
813
+ }
814
+ async checkSecret(name) {
815
+ const normalized = name.trim().toUpperCase();
816
+ const secrets = await this.listSecrets();
817
+ return secrets.find(
818
+ (secret) => secret.name === normalized && secret.status === "active" && secret.hasValue
819
+ ) ?? null;
820
+ }
821
+ // ——————————————————————————————————————————————————————————
806
822
  // Tools
807
823
  // ——————————————————————————————————————————————————————————
808
824
  /**
@@ -895,24 +911,24 @@ var DeeplineClient = class {
895
911
  * Top-level fields such as `status`, `job_id`, and `billing` describe the
896
912
  * Deepline execution envelope.
897
913
  */
898
- async executeTool(toolId, input, options) {
914
+ async executeTool(toolId, input2, options) {
899
915
  const headers = {
900
916
  [EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
901
917
  ...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
902
918
  };
903
919
  return this.http.post(
904
920
  `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
905
- { payload: input },
921
+ { payload: input2 },
906
922
  headers
907
923
  );
908
924
  }
909
- async executeToolRaw(toolId, input, options) {
910
- return this.executeTool(toolId, input, options);
925
+ async executeToolRaw(toolId, input2, options) {
926
+ return this.executeTool(toolId, input2, options);
911
927
  }
912
- async queryCustomerDb(input) {
928
+ async queryCustomerDb(input2) {
913
929
  return this.http.post("/api/v2/db/query", {
914
- sql: input.sql,
915
- ...input.maxRows ? { max_rows: input.maxRows } : {}
930
+ sql: input2.sql,
931
+ ...input2.maxRows ? { max_rows: input2.maxRows } : {}
916
932
  });
917
933
  }
918
934
  // ——————————————————————————————————————————————————————————
@@ -998,6 +1014,7 @@ var DeeplineClient = class {
998
1014
  ...request.inputFile ? { inputFile: request.inputFile } : {},
999
1015
  ...request.packagedFiles?.length ? { packagedFiles: request.packagedFiles } : {},
1000
1016
  ...request.force ? { force: true } : {},
1017
+ ...typeof request.waitForCompletionMs === "number" ? { waitForCompletionMs: request.waitForCompletionMs } : {},
1001
1018
  ...request.profile ? { profile: request.profile } : {}
1002
1019
  };
1003
1020
  for await (const event of this.http.streamSse(
@@ -1019,15 +1036,15 @@ var DeeplineClient = class {
1019
1036
  * Internal/advanced primitive used by packaging flows. Public callers should
1020
1037
  * prefer the CLI, {@link submitPlay}, or {@link runPlay}.
1021
1038
  */
1022
- async registerPlayArtifact(input) {
1023
- const compilerManifest = input.compilerManifest ?? await this.compilePlayManifest({
1024
- name: input.name,
1025
- sourceCode: input.sourceCode,
1026
- sourceFiles: input.sourceFiles,
1027
- artifact: input.artifact
1039
+ async registerPlayArtifact(input2) {
1040
+ const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
1041
+ name: input2.name,
1042
+ sourceCode: input2.sourceCode,
1043
+ sourceFiles: input2.sourceFiles,
1044
+ artifact: input2.artifact
1028
1045
  });
1029
1046
  return this.http.post("/api/v2/plays/artifacts", {
1030
- ...input,
1047
+ ...input2,
1031
1048
  compilerManifest
1032
1049
  });
1033
1050
  }
@@ -1047,14 +1064,14 @@ var DeeplineClient = class {
1047
1064
  artifacts: compiledArtifacts
1048
1065
  });
1049
1066
  }
1050
- async compilePlayManifest(input) {
1067
+ async compilePlayManifest(input2) {
1051
1068
  const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
1052
1069
  0,
1053
1070
  Math.max(0, this.config.maxRetries)
1054
1071
  );
1055
1072
  for (let attempt = 0; ; attempt += 1) {
1056
1073
  try {
1057
- const response = await this.http.post("/api/v2/plays/compile-manifest", input);
1074
+ const response = await this.http.post("/api/v2/plays/compile-manifest", input2);
1058
1075
  return response.compilerManifest;
1059
1076
  } catch (error) {
1060
1077
  const delayMs = retryDelays[attempt];
@@ -1072,21 +1089,21 @@ var DeeplineClient = class {
1072
1089
  * publish a revision, or start a run. It is the authoritative cloud validation
1073
1090
  * path used by `deepline play check`.
1074
1091
  */
1075
- async checkPlayArtifact(input) {
1076
- return this.http.post("/api/v2/plays/check", input);
1077
- }
1078
- async startPlayRunFromBundle(input) {
1079
- const compilerManifest = input.compilerManifest ?? await this.compilePlayManifest({
1080
- name: input.name,
1081
- sourceCode: input.sourceCode,
1082
- sourceFiles: input.sourceFiles,
1083
- artifact: input.artifact
1092
+ async checkPlayArtifact(input2) {
1093
+ return this.http.post("/api/v2/plays/check", input2);
1094
+ }
1095
+ async startPlayRunFromBundle(input2) {
1096
+ const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
1097
+ name: input2.name,
1098
+ sourceCode: input2.sourceCode,
1099
+ sourceFiles: input2.sourceFiles,
1100
+ artifact: input2.artifact
1084
1101
  });
1085
1102
  const registeredArtifact = await this.registerPlayArtifact({
1086
- name: input.name,
1087
- sourceCode: input.sourceCode,
1088
- sourceFiles: input.sourceFiles,
1089
- artifact: input.artifact,
1103
+ name: input2.name,
1104
+ sourceCode: input2.sourceCode,
1105
+ sourceFiles: input2.sourceFiles,
1106
+ artifact: input2.artifact,
1090
1107
  compilerManifest,
1091
1108
  publish: false
1092
1109
  });
@@ -1096,13 +1113,13 @@ var DeeplineClient = class {
1096
1113
  );
1097
1114
  }
1098
1115
  return this.startPlayRun({
1099
- name: input.name,
1116
+ name: input2.name,
1100
1117
  artifactStorageKey: registeredArtifact.artifactStorageKey,
1101
1118
  compilerManifest,
1102
- ...input.input ? { input: input.input } : {},
1103
- ...input.inputFile ? { inputFile: input.inputFile } : {},
1104
- ...input.packagedFiles?.length ? { packagedFiles: input.packagedFiles } : {},
1105
- ...input.force ? { force: true } : {}
1119
+ ...input2.input ? { input: input2.input } : {},
1120
+ ...input2.inputFile ? { inputFile: input2.inputFile } : {},
1121
+ ...input2.packagedFiles?.length ? { packagedFiles: input2.packagedFiles } : {},
1122
+ ...input2.force ? { force: true } : {}
1106
1123
  });
1107
1124
  }
1108
1125
  /**
@@ -1447,17 +1464,17 @@ var DeeplineClient = class {
1447
1464
  entries
1448
1465
  };
1449
1466
  }
1450
- async getPlaySheetRows(input) {
1467
+ async getPlaySheetRows(input2) {
1451
1468
  const params = new URLSearchParams({
1452
- tableNamespace: input.tableNamespace,
1453
- limit: String(input.limit ?? 5e3),
1454
- offset: String(input.offset ?? 0)
1469
+ tableNamespace: input2.tableNamespace,
1470
+ limit: String(input2.limit ?? 5e3),
1471
+ offset: String(input2.offset ?? 0)
1455
1472
  });
1456
- if (input.runId?.trim()) {
1457
- params.set("runId", input.runId.trim());
1473
+ if (input2.runId?.trim()) {
1474
+ params.set("runId", input2.runId.trim());
1458
1475
  }
1459
1476
  return await this.http.get(
1460
- `/api/v2/plays/${encodeURIComponent(input.playName)}/sheet?${params.toString()}`
1477
+ `/api/v2/plays/${encodeURIComponent(input2.playName)}/sheet?${params.toString()}`
1461
1478
  );
1462
1479
  }
1463
1480
  /**
@@ -1906,7 +1923,7 @@ function browserAppNameFromBundleId(bundleId) {
1906
1923
  }
1907
1924
  function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
1908
1925
  try {
1909
- const output = runner.execFileSync(
1926
+ const output2 = runner.execFileSync(
1910
1927
  "/usr/bin/defaults",
1911
1928
  [
1912
1929
  "read",
@@ -1915,10 +1932,10 @@ function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
1915
1932
  ],
1916
1933
  { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
1917
1934
  );
1918
- const httpsMatch = output.match(
1935
+ const httpsMatch = output2.match(
1919
1936
  /LSHandlerURLScheme\s*=\s*https;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
1920
1937
  );
1921
- const httpMatch = output.match(
1938
+ const httpMatch = output2.match(
1922
1939
  /LSHandlerURLScheme\s*=\s*http;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
1923
1940
  );
1924
1941
  return (httpsMatch?.[1] ?? httpMatch?.[1] ?? "").trim();
@@ -3363,9 +3380,9 @@ function stripCsvProjectionColumns(columns, rows) {
3363
3380
  (column) => column !== CSV_PROJECTED_FIELDS_KEY && !projectedFields.has(column)
3364
3381
  );
3365
3382
  }
3366
- function sanitizeCsvProjectionInfo(input) {
3367
- const columns = stripCsvProjectionColumns(input.columns, input.rows);
3368
- const rows = input.rows.map(stripCsvProjectionFields);
3383
+ function sanitizeCsvProjectionInfo(input2) {
3384
+ const columns = stripCsvProjectionColumns(input2.columns, input2.rows);
3385
+ const rows = input2.rows.map(stripCsvProjectionFields);
3369
3386
  return { rows, columns };
3370
3387
  }
3371
3388
  function isRecord2(value) {
@@ -3421,8 +3438,8 @@ function inferColumns(rows) {
3421
3438
  }
3422
3439
  return columns;
3423
3440
  }
3424
- function canonicalRowsInfoFromCandidate(input) {
3425
- const candidate = input;
3441
+ function canonicalRowsInfoFromCandidate(input2) {
3442
+ const candidate = input2;
3426
3443
  if (isSerializedDataset(candidate.value)) {
3427
3444
  const rawRows = rowArray(candidate.value.preview) ?? [];
3428
3445
  const totalRows2 = readNumber(candidate.value.count) ?? rawRows.length;
@@ -3463,31 +3480,31 @@ function canonicalRowsInfoFromCandidate(input) {
3463
3480
  source: candidate.source
3464
3481
  };
3465
3482
  }
3466
- function collectDatasetCandidates(input) {
3467
- if (input.depth && input.depth > 16) {
3483
+ function collectDatasetCandidates(input2) {
3484
+ if (input2.depth && input2.depth > 16) {
3468
3485
  return;
3469
3486
  }
3470
- if (isSerializedDataset(input.value)) {
3471
- input.output.push({
3472
- source: input.path,
3473
- value: input.value,
3474
- total: input.total
3487
+ if (isSerializedDataset(input2.value)) {
3488
+ input2.output.push({
3489
+ source: input2.path,
3490
+ value: input2.value,
3491
+ total: input2.total
3475
3492
  });
3476
3493
  return;
3477
3494
  }
3478
- if (!isRecord2(input.value)) {
3495
+ if (!isRecord2(input2.value)) {
3479
3496
  return;
3480
3497
  }
3481
- for (const [key, child] of Object.entries(input.value)) {
3498
+ for (const [key, child] of Object.entries(input2.value)) {
3482
3499
  if (key === "preview" || key === "access") {
3483
3500
  continue;
3484
3501
  }
3485
3502
  collectDatasetCandidates({
3486
3503
  value: child,
3487
- path: `${input.path}.${key}`,
3488
- total: totalRowsForDataset(input.value, `${input.path}.${key}`),
3489
- output: input.output,
3490
- depth: (input.depth ?? 0) + 1
3504
+ path: `${input2.path}.${key}`,
3505
+ total: totalRowsForDataset(input2.value, `${input2.path}.${key}`),
3506
+ output: input2.output,
3507
+ depth: (input2.depth ?? 0) + 1
3491
3508
  });
3492
3509
  }
3493
3510
  }
@@ -4005,26 +4022,26 @@ function writeCustomerDbCsv(result, outPath) {
4005
4022
  );
4006
4023
  return resolved;
4007
4024
  }
4008
- function dbQueryExportEnvelope(input) {
4009
- const destination = input.outPath ?? "stdout";
4025
+ function dbQueryExportEnvelope(input2) {
4026
+ const destination = input2.outPath ?? "stdout";
4010
4027
  return {
4011
- command: input.result.command,
4012
- format: input.format,
4013
- row_count: input.result.row_count,
4014
- row_count_returned: input.result.row_count_returned,
4015
- truncated: input.result.truncated,
4016
- ...input.outPath ? { file: input.outPath, local: { file: input.outPath } } : {},
4017
- next: { toolEquivalent: input.toolCommand },
4028
+ command: input2.result.command,
4029
+ format: input2.format,
4030
+ row_count: input2.result.row_count,
4031
+ row_count_returned: input2.result.row_count_returned,
4032
+ truncated: input2.result.truncated,
4033
+ ...input2.outPath ? { file: input2.outPath, local: { file: input2.outPath } } : {},
4034
+ next: { toolEquivalent: input2.toolCommand },
4018
4035
  render: {
4019
4036
  sections: [
4020
4037
  {
4021
4038
  title: "customer db export",
4022
4039
  lines: [
4023
- `Rendered ${input.result.row_count_returned} row(s) as ${input.format} to ${destination}`
4040
+ `Rendered ${input2.result.row_count_returned} row(s) as ${input2.format} to ${destination}`
4024
4041
  ]
4025
4042
  }
4026
4043
  ],
4027
- actions: [{ label: "Tool equivalent", command: input.toolCommand }]
4044
+ actions: [{ label: "Tool equivalent", command: input2.toolCommand }]
4028
4045
  }
4029
4046
  };
4030
4047
  }
@@ -4475,16 +4492,63 @@ var PLAY_RUNTIME_FEATURES = [
4475
4492
  "durable_sleep",
4476
4493
  "packaged_files"
4477
4494
  ];
4478
- function buildPlayContractCompatibility(input) {
4495
+ function buildPlayContractCompatibility(input2) {
4479
4496
  return {
4480
4497
  apiVersion: PLAY_PUBLIC_API_VERSION,
4481
4498
  artifactVersion: PLAY_ARTIFACT_VERSION,
4482
4499
  minRunnerVersion: PLAY_MIN_RUNNER_VERSION,
4483
4500
  runtimeFeatures: [...PLAY_RUNTIME_FEATURES],
4484
- runtimeBackend: input?.runtimeBackend ?? null
4501
+ runtimeBackend: input2?.runtimeBackend ?? null
4485
4502
  };
4486
4503
  }
4487
4504
 
4505
+ // ../shared_libs/plays/secret-guardrails.ts
4506
+ var SECRET_ENV_PATTERN = /\bprocess(?:\.env|\[['"]env['"]\])(?:\.|\[['"])([A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PRIVATE[_-]?KEY|ACCESS[_-]?KEY)[A-Z0-9_]*)(?:['"]\])?/g;
4507
+ var PRIVATE_KEY_PATTERN = /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/;
4508
+ var BEARER_LITERAL_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/i;
4509
+ var ASSIGNMENT_SECRET_LITERAL_PATTERN = /\b(?:api[_-]?key|token|secret|password)\b\s*[:=]\s*['"][^'"]{12,}['"]/i;
4510
+ var HIGH_ENTROPY_LITERAL_PATTERN = /['"]([A-Za-z0-9+/=_-]{32,})['"]/g;
4511
+ function shannonEntropy(value) {
4512
+ const counts = /* @__PURE__ */ new Map();
4513
+ for (const char of value) counts.set(char, (counts.get(char) ?? 0) + 1);
4514
+ return [...counts.values()].reduce((entropy, count) => {
4515
+ const p = count / value.length;
4516
+ return entropy - p * Math.log2(p);
4517
+ }, 0);
4518
+ }
4519
+ function validatePlaySourceHasNoInlineSecrets(input2) {
4520
+ const findings = [];
4521
+ for (const match of input2.sourceCode.matchAll(SECRET_ENV_PATTERN)) {
4522
+ findings.push(`process.env.${match[1]}`);
4523
+ }
4524
+ if (PRIVATE_KEY_PATTERN.test(input2.sourceCode)) findings.push("private key block");
4525
+ if (BEARER_LITERAL_PATTERN.test(input2.sourceCode)) findings.push("bearer token literal");
4526
+ if (ASSIGNMENT_SECRET_LITERAL_PATTERN.test(input2.sourceCode)) {
4527
+ findings.push("secret-looking assignment literal");
4528
+ }
4529
+ for (const match of input2.sourceCode.matchAll(HIGH_ENTROPY_LITERAL_PATTERN)) {
4530
+ const literal = match[1] ?? "";
4531
+ if (literal.length >= 40 && shannonEntropy(literal) >= 4.2) {
4532
+ findings.push("high-entropy string literal");
4533
+ break;
4534
+ }
4535
+ }
4536
+ if (!findings.length) return;
4537
+ throw new Error(
4538
+ [
4539
+ `Play source ${input2.filePath} appears to contain inline secret material: ${[
4540
+ ...new Set(findings)
4541
+ ].join(", ")}.`,
4542
+ 'Author secrets in the dashboard and use ctx.secrets.get("NAME") with an approved helper such as ctx.secrets.bearer(handle).'
4543
+ ].join(" ")
4544
+ );
4545
+ }
4546
+ function validatePlaySourceFilesHaveNoInlineSecrets(sourceFiles) {
4547
+ for (const [filePath, sourceCode] of Object.entries(sourceFiles)) {
4548
+ validatePlaySourceHasNoInlineSecrets({ filePath, sourceCode });
4549
+ }
4550
+ }
4551
+
4488
4552
  // ../shared_libs/plays/bundling/index.ts
4489
4553
  var PLAY_BUNDLE_CACHE_VERSION = 24;
4490
4554
  var MAX_PLAY_BUNDLE_BYTES = 30 * 1024 * 1024;
@@ -4546,12 +4610,12 @@ function createPlayWorkspace(entryFile) {
4546
4610
  function isPathInsideDirectory(filePath, directory) {
4547
4611
  return filePath === directory || filePath.startsWith(`${directory}/`);
4548
4612
  }
4549
- function assertWithinPlayWorkspace(input) {
4550
- if (isPathInsideDirectory(input.resolvedPath, input.workspace.rootDir)) {
4613
+ function assertWithinPlayWorkspace(input2) {
4614
+ if (isPathInsideDirectory(input2.resolvedPath, input2.workspace.rootDir)) {
4551
4615
  return;
4552
4616
  }
4553
4617
  throw new Error(
4554
- `${input.importer}:${input.line}:${input.column} Local play imports must stay inside the play workspace (${input.workspace.rootDir}). Import "${input.specifier}" resolved to ${input.resolvedPath}, which crosses into app/backend code. Use the public SDK/API surface or move shared helpers into the play workspace.`
4618
+ `${input2.importer}:${input2.line}:${input2.column} Local play imports must stay inside the play workspace (${input2.workspace.rootDir}). Import "${input2.specifier}" resolved to ${input2.resolvedPath}, which crosses into app/backend code. Use the public SDK/API surface or move shared helpers into the play workspace.`
4555
4619
  );
4556
4620
  }
4557
4621
  function getPackageName(specifier) {
@@ -5406,6 +5470,15 @@ entry-export:${exportName}`
5406
5470
  workers-harness:${harnessFingerprint}`
5407
5471
  );
5408
5472
  }
5473
+ try {
5474
+ validatePlaySourceFilesHaveNoInlineSecrets(analysis.sourceFiles);
5475
+ } catch (error) {
5476
+ return {
5477
+ success: false,
5478
+ filePath: absolutePath,
5479
+ errors: [error instanceof Error ? error.message : String(error)]
5480
+ };
5481
+ }
5409
5482
  const typecheckErrors = [
5410
5483
  ...await adapter.typecheckPlaySource?.({
5411
5484
  sourceCode: analysis.sourceCode,
@@ -6015,11 +6088,13 @@ function createSdkPlayBundlingAdapter() {
6015
6088
  };
6016
6089
  }
6017
6090
  async function bundlePlayFile2(filePath, options = {}) {
6018
- return bundlePlayFile(filePath, {
6091
+ const result = await bundlePlayFile(filePath, {
6019
6092
  target: options.target ?? defaultPlayBundleTarget(),
6020
6093
  exportName: options.exportName,
6021
6094
  adapter: createSdkPlayBundlingAdapter()
6022
6095
  });
6096
+ if (result.success) validatePlaySourceFilesHaveNoInlineSecrets(result.sourceFiles);
6097
+ return result;
6023
6098
  }
6024
6099
 
6025
6100
  // src/cli/commands/plays/bootstrap.ts
@@ -6613,28 +6688,28 @@ function objectPropertySchema(schema, property) {
6613
6688
  function finderResultTypeName(finder) {
6614
6689
  return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
6615
6690
  }
6616
- function renderFinderPlayResultType(input) {
6617
- if (!input.play) return null;
6618
- const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
6691
+ function renderFinderPlayResultType(input2) {
6692
+ if (!input2.play) return null;
6693
+ const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
6619
6694
  const fieldSchema = objectPropertySchema(
6620
- input.play.outputSchema,
6695
+ input2.play.outputSchema,
6621
6696
  outputField
6622
6697
  );
6623
6698
  const fieldType = fieldSchema ? jsonSchemaTypeExpression(fieldSchema) : "string | null";
6624
- return `type ${finderResultTypeName(input.finder)} =
6699
+ return `type ${finderResultTypeName(input2.finder)} =
6625
6700
  | string
6626
6701
  | null
6627
6702
  | {
6628
6703
  ${outputField}?: ${fieldType};
6629
6704
  };`;
6630
6705
  }
6631
- function generatedFinderPlayResultTypes(input) {
6706
+ function generatedFinderPlayResultTypes(input2) {
6632
6707
  return ["email_finder", "phone_finder"].flatMap((finder) => {
6633
- const stage = finderStage(input.options, finder);
6708
+ const stage = finderStage(input2.options, finder);
6634
6709
  if (stage?.kind !== "play") return [];
6635
6710
  const typeDefinition = renderFinderPlayResultType({
6636
6711
  finder,
6637
- play: input.finderPlays[finder]
6712
+ play: input2.finderPlays[finder]
6638
6713
  });
6639
6714
  return typeDefinition ? [typeDefinition] : [];
6640
6715
  }).join("\n\n");
@@ -6692,8 +6767,8 @@ function generateCompanyInputObjectFromSchema(schema, indent, label, fallbackFie
6692
6767
  ${lines.join("\n")}
6693
6768
  ${indent.slice(2)}}`;
6694
6769
  }
6695
- function generateSourceProviderInputObject(input) {
6696
- const { tool, indent, label, entity } = input;
6770
+ function generateSourceProviderInputObject(input2) {
6771
+ const { tool, indent, label, entity } = input2;
6697
6772
  const properties = inputPropertyNames(tool?.inputSchema);
6698
6773
  const details = schemaFieldDetails(tool?.inputSchema);
6699
6774
  const required = details.required;
@@ -6751,8 +6826,8 @@ function generateSourceProviderInputObject(input) {
6751
6826
  ${lines.join("\n")}
6752
6827
  ${indent.slice(2)}}`;
6753
6828
  }
6754
- function generatePlayInputObject(input) {
6755
- const { schema, indent, label, entity } = input;
6829
+ function generatePlayInputObject(input2) {
6830
+ const { schema, indent, label, entity } = input2;
6756
6831
  const details = schemaFieldDetails(schema);
6757
6832
  const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
6758
6833
  const required = details.required.length ? details.required : fallback;
@@ -6819,80 +6894,80 @@ function needsWhenImport(options) {
6819
6894
  function sourceCollectionTypeName(entity) {
6820
6895
  return entity === "company" ? "CompanySourceRow" : "ContactSourceRow";
6821
6896
  }
6822
- function renderPartialRowType(input) {
6823
- if (input.fields.length === 0) {
6824
- return `type ${input.typeName} = Record<string, unknown>;`;
6897
+ function renderPartialRowType(input2) {
6898
+ if (input2.fields.length === 0) {
6899
+ return `type ${input2.typeName} = Record<string, unknown>;`;
6825
6900
  }
6826
- const properties = input.fields.map((field) => ` ${jsString(field)}?: unknown;`).join("\n");
6827
- return `type ${input.typeName} = Record<string, unknown> & Partial<{
6828
- // ${input.comment}
6901
+ const properties = input2.fields.map((field) => ` ${jsString(field)}?: unknown;`).join("\n");
6902
+ return `type ${input2.typeName} = Record<string, unknown> & Partial<{
6903
+ // ${input2.comment}
6829
6904
  ${properties}
6830
6905
  }>;`;
6831
6906
  }
6832
- function fieldsFromSchemaDetails(input) {
6907
+ function fieldsFromSchemaDetails(input2) {
6833
6908
  return [
6834
- ...input.details.required.length ? input.details.required : input.fallbackFields,
6835
- ...input.details.optional
6909
+ ...input2.details.required.length ? input2.details.required : input2.fallbackFields,
6910
+ ...input2.details.optional
6836
6911
  ];
6837
6912
  }
6838
- function schemaFieldsForStage(stage, input) {
6913
+ function schemaFieldsForStage(stage, input2) {
6839
6914
  switch (stage?.kind) {
6840
6915
  case void 0:
6841
6916
  return [];
6842
6917
  case "play":
6843
6918
  return fieldsFromSchemaDetails({
6844
- details: schemaFieldDetails(input.play?.inputSchema),
6845
- fallbackFields: input.fallbackFields
6919
+ details: schemaFieldDetails(input2.play?.inputSchema),
6920
+ fallbackFields: input2.fallbackFields
6846
6921
  });
6847
6922
  case "providers":
6848
- return input.tools.flatMap(
6923
+ return input2.tools.flatMap(
6849
6924
  (tool) => fieldsFromSchemaDetails({
6850
6925
  details: schemaFieldDetails(tool.inputSchema),
6851
- fallbackFields: input.fallbackFields
6926
+ fallbackFields: input2.fallbackFields
6852
6927
  })
6853
6928
  );
6854
6929
  }
6855
6930
  }
6856
- function sourceRowTypeDefinition(input) {
6857
- switch (input.options.from.kind) {
6931
+ function sourceRowTypeDefinition(input2) {
6932
+ switch (input2.options.from.kind) {
6858
6933
  case "csv":
6859
- return `type ${input.sourceTypeName} = SourceCsvRow;`;
6934
+ return `type ${input2.sourceTypeName} = SourceCsvRow;`;
6860
6935
  case "providers":
6861
6936
  return renderPartialRowType({
6862
- typeName: input.sourceTypeName,
6937
+ typeName: input2.sourceTypeName,
6863
6938
  fields: [
6864
- ...new Set(input.sourceTools.flatMap(listRowCandidateKeysFromTool))
6939
+ ...new Set(input2.sourceTools.flatMap(listRowCandidateKeysFromTool))
6865
6940
  ].sort(),
6866
6941
  comment: "Candidate source row keys from described list getters; confirm the actual provider keys with source_*.extractedLists.*.keys before mapping."
6867
6942
  });
6868
6943
  case "play": {
6869
- const details = schemaFieldDetails(input.sourcePlay?.outputSchema);
6944
+ const details = schemaFieldDetails(input2.sourcePlay?.outputSchema);
6870
6945
  return renderPartialRowType({
6871
- typeName: input.sourceTypeName,
6946
+ typeName: input2.sourceTypeName,
6872
6947
  fields: [...details.required, ...details.optional].sort(),
6873
6948
  comment: "Candidate source play output fields; confirm the selected rows field before mapping."
6874
6949
  });
6875
6950
  }
6876
6951
  }
6877
6952
  }
6878
- function contactBridgeRowTypeDefinition(input) {
6879
- const config = playBootstrapTemplateConfig(input.options.template);
6880
- if (config.sourceEntity !== "company" || !input.options.people) return null;
6881
- const emailFields = schemaFieldsForStage(input.options.email, {
6882
- tools: input.finderTools.email_finder ?? [],
6883
- play: input.finderPlays.email_finder,
6953
+ function contactBridgeRowTypeDefinition(input2) {
6954
+ const config = playBootstrapTemplateConfig(input2.options.template);
6955
+ if (config.sourceEntity !== "company" || !input2.options.people) return null;
6956
+ const emailFields = schemaFieldsForStage(input2.options.email, {
6957
+ tools: input2.finderTools.email_finder ?? [],
6958
+ play: input2.finderPlays.email_finder,
6884
6959
  fallbackFields: ["first_name", "last_name", "domain"]
6885
6960
  });
6886
- const phoneFields = schemaFieldsForStage(input.options.phone, {
6887
- tools: input.finderTools.phone_finder ?? [],
6888
- play: input.finderPlays.phone_finder,
6961
+ const phoneFields = schemaFieldsForStage(input2.options.phone, {
6962
+ tools: input2.finderTools.phone_finder ?? [],
6963
+ play: input2.finderPlays.phone_finder,
6889
6964
  fallbackFields: ["first_name", "last_name", "domain"]
6890
6965
  });
6891
6966
  return renderPartialRowType({
6892
6967
  typeName: "ContactSourceRow",
6893
6968
  fields: [
6894
6969
  .../* @__PURE__ */ new Set([
6895
- ...inputPropertyNames(input.peoplePlay?.outputSchema),
6970
+ ...inputPropertyNames(input2.peoplePlay?.outputSchema),
6896
6971
  ...emailFields,
6897
6972
  ...phoneFields
6898
6973
  ])
@@ -6900,27 +6975,27 @@ function contactBridgeRowTypeDefinition(input) {
6900
6975
  comment: "Fields the people play or later finder stages may need; the generated code still requires explicit mapping."
6901
6976
  });
6902
6977
  }
6903
- function generateRowTypeDefinitions(input) {
6904
- const config = playBootstrapTemplateConfig(input.options.template);
6978
+ function generateRowTypeDefinitions(input2) {
6979
+ const config = playBootstrapTemplateConfig(input2.options.template);
6905
6980
  const sourceTypeName = sourceCollectionTypeName(config.sourceEntity);
6906
6981
  const definitions = [
6907
6982
  sourceRowTypeDefinition({
6908
- options: input.options,
6983
+ options: input2.options,
6909
6984
  sourceTypeName,
6910
- sourceTools: input.sourceTools,
6911
- sourcePlay: input.sourcePlay
6985
+ sourceTools: input2.sourceTools,
6986
+ sourcePlay: input2.sourcePlay
6912
6987
  }),
6913
- contactBridgeRowTypeDefinition(input)
6988
+ contactBridgeRowTypeDefinition(input2)
6914
6989
  ];
6915
6990
  return definitions.filter(Boolean).join("\n\n");
6916
6991
  }
6917
- function validateBootstrapRoutes(input) {
6918
- const config = playBootstrapTemplateConfig(input.options.template);
6992
+ function validateBootstrapRoutes(input2) {
6993
+ const config = playBootstrapTemplateConfig(input2.options.template);
6919
6994
  const sourceCategory = config.sourceEntity === "company" ? PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY : PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY;
6920
- for (const tool of input.sourceTools) {
6995
+ for (const tool of input2.sourceTools) {
6921
6996
  if (!tool.categories.includes(sourceCategory)) {
6922
6997
  throw new PlayBootstrapValidationError(
6923
- `Cannot use ${tool.toolId} as a ${config.sourceEntity} source for ${input.options.template}: expected category ${sourceCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${sourceCategory} --categories ${sourceCategory} --json`
6998
+ `Cannot use ${tool.toolId} as a ${config.sourceEntity} source for ${input2.options.template}: expected category ${sourceCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${sourceCategory} --categories ${sourceCategory} --json`
6924
6999
  );
6925
7000
  }
6926
7001
  if (getterNamesFromTool(tool, "list").length === 0) {
@@ -6929,14 +7004,14 @@ function validateBootstrapRoutes(input) {
6929
7004
  );
6930
7005
  }
6931
7006
  }
6932
- if (input.options.people?.kind === "providers") {
7007
+ if (input2.options.people?.kind === "providers") {
6933
7008
  throw new PlayBootstrapValidationError(
6934
7009
  "Company-to-people bootstrap only accepts --people play:<play-ref> for now. Providers are too task-specific; choose or create a people play so the generated file can show the mapping contract."
6935
7010
  );
6936
7011
  }
6937
7012
  for (const finder of ["email_finder", "phone_finder"]) {
6938
7013
  const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
6939
- for (const tool of input.finderTools[finder] ?? []) {
7014
+ for (const tool of input2.finderTools[finder] ?? []) {
6940
7015
  if (!tool.categories.includes(requiredCategory)) {
6941
7016
  throw new PlayBootstrapValidationError(
6942
7017
  `Cannot use ${tool.toolId} for ${finder}: expected category ${requiredCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${requiredCategory} --categories ${requiredCategory} --json`
@@ -6958,118 +7033,118 @@ function sourceCollectionName(entity) {
6958
7033
  return "contacts";
6959
7034
  }
6960
7035
  }
6961
- function requiredGetterName(input) {
6962
- const getter = getterNamesFromTool(input.tool, input.kind)[0];
7036
+ function requiredGetterName(input2) {
7037
+ const getter = getterNamesFromTool(input2.tool, input2.kind)[0];
6963
7038
  if (!getter) {
6964
- switch (input.kind) {
7039
+ switch (input2.kind) {
6965
7040
  case "list":
6966
7041
  throw new PlayBootstrapValidationError(
6967
- `Cannot use ${input.label} as a source: it exposes no extracted list getters.`
7042
+ `Cannot use ${input2.label} as a source: it exposes no extracted list getters.`
6968
7043
  );
6969
7044
  case "value":
6970
7045
  throw new PlayBootstrapValidationError(
6971
- `Cannot use ${input.label} as a finder: it exposes no extracted value getters.`
7046
+ `Cannot use ${input2.label} as a finder: it exposes no extracted value getters.`
6972
7047
  );
6973
7048
  }
6974
7049
  }
6975
7050
  return getter;
6976
7051
  }
6977
- function generateCsvSourceRowsBlock(input) {
6978
- return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(input.packagedSourceCsvPath ?? input.source.value)});
6979
- const ${input.collection}: ${input.collectionType}[] = await sourceDataset.peek(limit);`;
7052
+ function generateCsvSourceRowsBlock(input2) {
7053
+ return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(input2.packagedSourceCsvPath ?? input2.source.value)});
7054
+ const ${input2.collection}: ${input2.collectionType}[] = await sourceDataset.peek(limit);`;
6980
7055
  }
6981
- function generatePlaySourceRowsBlock(input) {
7056
+ function generatePlaySourceRowsBlock(input2) {
6982
7057
  const playInput = generatePlayInputObject({
6983
- schema: input.sourcePlay?.inputSchema,
7058
+ schema: input2.sourcePlay?.inputSchema,
6984
7059
  indent: " ",
6985
- label: input.source.value,
6986
- entity: input.entity
7060
+ label: input2.source.value,
7061
+ entity: input2.entity
6987
7062
  });
6988
7063
  return `const sourceInput = ${playInput};
6989
- throw new Error(${jsString(`TODO: map sourceInput for ${input.source.value}, choose the play output rows field, then delete this throw.`)});
6990
- const sourceResult = await ctx.runPlay('source_play', ${jsString(input.source.value)}, sourceInput, {
6991
- description: ${jsString(`Seed ${input.entity} rows from the selected play.`)},
7064
+ throw new Error(${jsString(`TODO: map sourceInput for ${input2.source.value}, choose the play output rows field, then delete this throw.`)});
7065
+ const sourceResult = await ctx.runPlay('source_play', ${jsString(input2.source.value)}, sourceInput, {
7066
+ description: ${jsString(`Seed ${input2.entity} rows from the selected play.`)},
6992
7067
  });
6993
7068
  // TODO: Replace sourceResult.rows with the selected play's actual row output field.
6994
- const ${input.collection}: ${input.collectionType}[] = (sourceResult.rows ?? []) as ${input.collectionType}[];`;
7069
+ const ${input2.collection}: ${input2.collectionType}[] = (sourceResult.rows ?? []) as ${input2.collectionType}[];`;
6995
7070
  }
6996
- function generateProviderSourceBlock(input) {
7071
+ function generateProviderSourceBlock(input2) {
6997
7072
  const getter = requiredGetterName({
6998
- tool: input.tool,
7073
+ tool: input2.tool,
6999
7074
  kind: "list",
7000
- label: input.provider
7075
+ label: input2.provider
7001
7076
  });
7002
- const inputName = `${input.entity}Input_${input.index}`;
7003
- return `// ${input.entity === "company" ? "Company" : "People"} source provider: ${input.provider}
7077
+ const inputName = `${input2.entity}Input_${input2.index}`;
7078
+ return `// ${input2.entity === "company" ? "Company" : "People"} source provider: ${input2.provider}
7004
7079
  const ${inputName}: Record<string, unknown> = ${generateSourceProviderInputObject(
7005
7080
  {
7006
- tool: input.tool,
7081
+ tool: input2.tool,
7007
7082
  indent: " ",
7008
- label: input.provider,
7009
- entity: input.entity
7083
+ label: input2.provider,
7084
+ entity: input2.entity
7010
7085
  }
7011
7086
  )};
7012
- throw new Error(${jsString(`TODO: fill ${inputName} for ${input.provider}, then delete this throw.`)});
7013
- const source_${input.index} = await ctx.tools.execute({
7014
- id: ${jsString(`${input.entity}_source_${input.index}`)},
7015
- tool: ${jsString(input.provider)},
7087
+ throw new Error(${jsString(`TODO: fill ${inputName} for ${input2.provider}, then delete this throw.`)});
7088
+ const source_${input2.index} = await ctx.tools.execute({
7089
+ id: ${jsString(`${input2.entity}_source_${input2.index}`)},
7090
+ tool: ${jsString(input2.provider)},
7016
7091
  input: ${inputName},
7017
- description: ${jsString(`Seed ${input.entity} rows from ${input.provider}.`)},
7092
+ description: ${jsString(`Seed ${input2.entity} rows from ${input2.provider}.`)},
7018
7093
  });
7019
7094
  // extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
7020
- // inspect source_${input.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
7021
- const sourceRows_${input.index} = ${accessorExpression(`source_${input.index}.extractedLists`, getter)}.get() as ${input.collectionType}[];`;
7095
+ // inspect source_${input2.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
7096
+ const sourceRows_${input2.index} = ${accessorExpression(`source_${input2.index}.extractedLists`, getter)}.get() as ${input2.collectionType}[];`;
7022
7097
  }
7023
- function generateProviderSourceRowsBlock(input) {
7024
- const blocks = input.source.values.map(
7098
+ function generateProviderSourceRowsBlock(input2) {
7099
+ const blocks = input2.source.values.map(
7025
7100
  (provider, index) => generateProviderSourceBlock({
7026
7101
  provider,
7027
7102
  index,
7028
- tool: input.sourceTools[index] ?? null,
7029
- entity: input.entity,
7030
- collectionType: input.collectionType
7103
+ tool: input2.sourceTools[index] ?? null,
7104
+ entity: input2.entity,
7105
+ collectionType: input2.collectionType
7031
7106
  })
7032
7107
  );
7033
7108
  return `${blocks.join("\n\n ")}
7034
- const ${input.collection}: ${input.collectionType}[] = [${input.source.values.map((_, index) => `...sourceRows_${index}`).join(", ")}];`;
7109
+ const ${input2.collection}: ${input2.collectionType}[] = [${input2.source.values.map((_, index) => `...sourceRows_${index}`).join(", ")}];`;
7035
7110
  }
7036
- function generateSourceRowsBlock(input) {
7037
- const config = playBootstrapTemplateConfig(input.options.template);
7111
+ function generateSourceRowsBlock(input2) {
7112
+ const config = playBootstrapTemplateConfig(input2.options.template);
7038
7113
  const entity = config.sourceEntity;
7039
7114
  const collection = sourceCollectionName(entity);
7040
7115
  const collectionType = sourceCollectionTypeName(entity);
7041
- switch (input.options.from.kind) {
7116
+ switch (input2.options.from.kind) {
7042
7117
  case "csv":
7043
7118
  return generateCsvSourceRowsBlock({
7044
- source: input.options.from,
7119
+ source: input2.options.from,
7045
7120
  collection,
7046
7121
  collectionType,
7047
- packagedSourceCsvPath: input.packagedSourceCsvPath
7122
+ packagedSourceCsvPath: input2.packagedSourceCsvPath
7048
7123
  });
7049
7124
  case "play":
7050
7125
  return generatePlaySourceRowsBlock({
7051
- source: input.options.from,
7052
- sourcePlay: input.sourcePlay,
7126
+ source: input2.options.from,
7127
+ sourcePlay: input2.sourcePlay,
7053
7128
  entity,
7054
7129
  collection,
7055
7130
  collectionType
7056
7131
  });
7057
7132
  case "providers":
7058
7133
  return generateProviderSourceRowsBlock({
7059
- source: input.options.from,
7060
- sourceTools: input.sourceTools,
7134
+ source: input2.options.from,
7135
+ sourceTools: input2.sourceTools,
7061
7136
  entity,
7062
7137
  collection,
7063
7138
  collectionType
7064
7139
  });
7065
7140
  }
7066
7141
  }
7067
- function generateSourceSeedBlock(input) {
7068
- const sourceRows = generateSourceRowsBlock(input);
7069
- const peoplePlayRef = stagePlayRef(input.options.people);
7142
+ function generateSourceSeedBlock(input2) {
7143
+ const sourceRows = generateSourceRowsBlock(input2);
7144
+ const peoplePlayRef = stagePlayRef(input2.options.people);
7070
7145
  if (!peoplePlayRef) return sourceRows;
7071
7146
  const peopleInput = generateCompanyInputObjectFromSchema(
7072
- input.peoplePlay?.inputSchema,
7147
+ input2.peoplePlay?.inputSchema,
7073
7148
  " ",
7074
7149
  peoplePlayRef,
7075
7150
  ["domain", "company_name"]
@@ -7091,15 +7166,15 @@ function generateSourceSeedBlock(input) {
7091
7166
  contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
7092
7167
  }`;
7093
7168
  }
7094
- function finderProviderStepName(input) {
7095
- return `${input.aggregateStepName}${input.index}_${safeIdentifier(input.provider)}`;
7169
+ function finderProviderStepName(input2) {
7170
+ return `${input2.aggregateStepName}${input2.index}_${safeIdentifier(input2.provider)}`;
7096
7171
  }
7097
- function finderValueGetter(input) {
7098
- const getters = getterNamesFromTool(input.tool, "value");
7099
- const getter = getters.find((name) => name === input.outputField) ?? requiredGetterName({
7100
- tool: input.tool,
7172
+ function finderValueGetter(input2) {
7173
+ const getters = getterNamesFromTool(input2.tool, "value");
7174
+ const getter = getters.find((name) => name === input2.outputField) ?? requiredGetterName({
7175
+ tool: input2.tool,
7101
7176
  kind: "value",
7102
- label: input.provider
7177
+ label: input2.provider
7103
7178
  });
7104
7179
  return getter;
7105
7180
  }
@@ -7107,157 +7182,157 @@ function optionalFinderValueExpression(candidateExpression, outputField) {
7107
7182
  const valueExpression = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(outputField) ? `${candidateExpression}?.${outputField}` : `${candidateExpression}?.[${jsString(outputField)}]`;
7108
7183
  return `${valueExpression}?.trim()`;
7109
7184
  }
7110
- function generateFinderPlayStep(input) {
7111
- const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
7112
- const resultTypeName = finderResultTypeName(input.finder);
7185
+ function generateFinderPlayStep(input2) {
7186
+ const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
7187
+ const resultTypeName = finderResultTypeName(input2.finder);
7113
7188
  const payload = generateContactInputObjectFromSchema(
7114
- input.play?.inputSchema,
7189
+ input2.play?.inputSchema,
7115
7190
  " ",
7116
- input.stage.value
7191
+ input2.stage.value
7117
7192
  );
7118
7193
  return `.step(${jsString(outputField)}, async (row, rowCtx) => {
7119
- const ${input.aggregateStepName}Input = ${payload};
7120
- throw new Error(${jsString(`TODO: map ${input.aggregateStepName}Input for ${input.stage.value}, then delete this throw.`)});
7121
- const ${input.aggregateStepName}Result = await rowCtx.runPlay<${resultTypeName}>(
7122
- ${jsString(`${input.aggregateStepName}Play`)},
7123
- ${jsString(input.stage.value)},
7124
- ${input.aggregateStepName}Input,
7194
+ const ${input2.aggregateStepName}Input = ${payload};
7195
+ throw new Error(${jsString(`TODO: map ${input2.aggregateStepName}Input for ${input2.stage.value}, then delete this throw.`)});
7196
+ const ${input2.aggregateStepName}Result = await rowCtx.runPlay<${resultTypeName}>(
7197
+ ${jsString(`${input2.aggregateStepName}Play`)},
7198
+ ${jsString(input2.stage.value)},
7199
+ ${input2.aggregateStepName}Input,
7125
7200
  {
7126
- description: ${jsString(`Run ${input.finder} play.`)},
7201
+ description: ${jsString(`Run ${input2.finder} play.`)},
7127
7202
  },
7128
7203
  );
7129
- return typeof ${input.aggregateStepName}Result === 'string'
7130
- ? ${input.aggregateStepName}Result.trim() || null
7131
- : ${input.aggregateStepName}Result?.${outputField} ?? null;
7204
+ return typeof ${input2.aggregateStepName}Result === 'string'
7205
+ ? ${input2.aggregateStepName}Result.trim() || null
7206
+ : ${input2.aggregateStepName}Result?.${outputField} ?? null;
7132
7207
  })`;
7133
7208
  }
7134
- function generateFinderProviderResolver(input) {
7209
+ function generateFinderProviderResolver(input2) {
7135
7210
  const payload = generateContactInputObjectFromSchema(
7136
- input.tool?.inputSchema,
7211
+ input2.tool?.inputSchema,
7137
7212
  " ",
7138
- input.provider
7213
+ input2.provider
7139
7214
  );
7140
7215
  const getter = finderValueGetter({
7141
- tool: input.tool,
7142
- provider: input.provider,
7143
- outputField: input.outputField
7216
+ tool: input2.tool,
7217
+ provider: input2.provider,
7218
+ outputField: input2.outputField
7144
7219
  });
7145
7220
  return `async (row, rowCtx) => {
7146
7221
  const providerInput = ${payload};
7147
- throw new Error(${jsString(`TODO: map providerInput for ${input.provider}, then delete this throw.`)});
7222
+ throw new Error(${jsString(`TODO: map providerInput for ${input2.provider}, then delete this throw.`)});
7148
7223
  const result = await rowCtx.tools.execute({
7149
- id: ${jsString(`${input.aggregateStepName}_${input.providerIndex}`)},
7150
- tool: ${jsString(input.provider)},
7224
+ id: ${jsString(`${input2.aggregateStepName}_${input2.providerIndex}`)},
7225
+ tool: ${jsString(input2.provider)},
7151
7226
  input: providerInput,
7152
- description: ${jsString(`Try ${input.provider} as a ${input.finder}.`)},
7227
+ description: ${jsString(`Try ${input2.provider} as a ${input2.finder}.`)},
7153
7228
  });
7154
7229
  return {
7155
- ${input.outputField}: (${accessorExpression("result.extractedValues", getter)}.get() as string | null) ?? null,
7230
+ ${input2.outputField}: (${accessorExpression("result.extractedValues", getter)}.get() as string | null) ?? null,
7156
7231
  result,
7157
7232
  };
7158
7233
  }`;
7159
7234
  }
7160
- function generateFinderProviderStep(input) {
7161
- const stepName = input.stepNames[input.index];
7162
- switch (input.index) {
7235
+ function generateFinderProviderStep(input2) {
7236
+ const stepName = input2.stepNames[input2.index];
7237
+ switch (input2.index) {
7163
7238
  case 0:
7164
- return `.step(${jsString(stepName)}, ${input.resolver})`;
7239
+ return `.step(${jsString(stepName)}, ${input2.resolver})`;
7165
7240
  default: {
7166
- const priorCandidates = input.stepNames.slice(0, input.index).map((name) => `row.${name}`).join(", ");
7241
+ const priorCandidates = input2.stepNames.slice(0, input2.index).map((name) => `row.${name}`).join(", ");
7167
7242
  return `.step(
7168
7243
  ${jsString(stepName)},
7169
7244
  when(
7170
- (row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate", input.outputField)}),
7171
- ${input.resolver},
7245
+ (row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate", input2.outputField)}),
7246
+ ${input2.resolver},
7172
7247
  ),
7173
7248
  )`;
7174
7249
  }
7175
7250
  }
7176
7251
  }
7177
- function generateFinderProviderWaterfall(input) {
7178
- const legPrefix = finderProviderStepPrefix(input.finder);
7179
- const stepNames = input.stage.values.map(
7252
+ function generateFinderProviderWaterfall(input2) {
7253
+ const legPrefix = finderProviderStepPrefix(input2.finder);
7254
+ const stepNames = input2.stage.values.map(
7180
7255
  (provider, index) => finderProviderStepName({
7181
7256
  aggregateStepName: legPrefix,
7182
7257
  provider,
7183
7258
  index
7184
7259
  })
7185
7260
  );
7186
- const providerSteps = input.stage.values.map(
7261
+ const providerSteps = input2.stage.values.map(
7187
7262
  (provider, index) => generateFinderProviderStep({
7188
7263
  index,
7189
7264
  stepNames,
7190
- outputField: input.outputField,
7265
+ outputField: input2.outputField,
7191
7266
  resolver: generateFinderProviderResolver({
7192
- finder: input.finder,
7267
+ finder: input2.finder,
7193
7268
  provider,
7194
7269
  providerIndex: index,
7195
- tool: input.tools[index] ?? null,
7196
- aggregateStepName: input.aggregateStepName,
7197
- outputField: input.outputField
7270
+ tool: input2.tools[index] ?? null,
7271
+ aggregateStepName: input2.aggregateStepName,
7272
+ outputField: input2.outputField
7198
7273
  })
7199
7274
  })
7200
7275
  );
7201
7276
  const candidateNames = stepNames.map((name) => `row.${name}`).join(", ");
7202
- return `// ${input.aggregateStepName} provider waterfall. Each provider leg is active once its TODO throw is removed;
7277
+ return `// ${input2.aggregateStepName} provider waterfall. Each provider leg is active once its TODO throw is removed;
7203
7278
  // delete or comment out legs you do not want before running. Later legs are gated with when(...).
7204
7279
  ${providerSteps.join("\n ")}
7205
- .step(${jsString(input.aggregateStepName)}, (row) => {
7280
+ .step(${jsString(input2.aggregateStepName)}, (row) => {
7206
7281
  const candidates = [${candidateNames}];
7207
- const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate", input.outputField)});
7208
- return ${optionalFinderValueExpression("match", input.outputField)} ?? null;
7282
+ const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate", input2.outputField)});
7283
+ return ${optionalFinderValueExpression("match", input2.outputField)} ?? null;
7209
7284
  })`;
7210
7285
  }
7211
- function generateFinderStageSteps(input) {
7212
- const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
7213
- const aggregateStepName = stepFieldName(input.finder);
7214
- switch (input.stage.kind) {
7286
+ function generateFinderStageSteps(input2) {
7287
+ const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
7288
+ const aggregateStepName = stepFieldName(input2.finder);
7289
+ switch (input2.stage.kind) {
7215
7290
  case "play":
7216
7291
  return generateFinderPlayStep({
7217
- finder: input.finder,
7218
- stage: input.stage,
7219
- play: input.finderPlays[input.finder],
7292
+ finder: input2.finder,
7293
+ stage: input2.stage,
7294
+ play: input2.finderPlays[input2.finder],
7220
7295
  aggregateStepName
7221
7296
  });
7222
7297
  case "providers":
7223
7298
  return generateFinderProviderWaterfall({
7224
- finder: input.finder,
7225
- stage: input.stage,
7226
- tools: input.finderTools[input.finder] ?? [],
7299
+ finder: input2.finder,
7300
+ stage: input2.stage,
7301
+ tools: input2.finderTools[input2.finder] ?? [],
7227
7302
  aggregateStepName,
7228
7303
  outputField
7229
7304
  });
7230
7305
  }
7231
7306
  }
7232
- function generateFinderSteps(input) {
7307
+ function generateFinderSteps(input2) {
7233
7308
  return ["email_finder", "phone_finder"].flatMap((finder) => {
7234
- const stage = finderStage(input.options, finder);
7309
+ const stage = finderStage(input2.options, finder);
7235
7310
  return stage ? [
7236
7311
  generateFinderStageSteps({
7237
- ...input,
7312
+ ...input2,
7238
7313
  finder,
7239
7314
  stage
7240
7315
  })
7241
7316
  ] : [];
7242
7317
  }).join("\n ");
7243
7318
  }
7244
- function generateBootstrapPlaySource(input) {
7245
- const config = playBootstrapTemplateConfig(input.options.template);
7246
- const sourceSeedBlock = generateSourceSeedBlock(input);
7247
- const finderSteps = generateFinderSteps(input);
7248
- const hasPeople = config.sourceEntity === "people" || Boolean(input.options.people);
7319
+ function generateBootstrapPlaySource(input2) {
7320
+ const config = playBootstrapTemplateConfig(input2.options.template);
7321
+ const sourceSeedBlock = generateSourceSeedBlock(input2);
7322
+ const finderSteps = generateFinderSteps(input2);
7323
+ const hasPeople = config.sourceEntity === "people" || Boolean(input2.options.people);
7249
7324
  const sourceCollection = hasPeople ? "contacts" : "companies";
7250
7325
  const mapSteps = finderSteps ? `
7251
7326
  ${finderSteps}` : "";
7252
- const sourceCsvRowType = input.options.from.kind === "csv" ? renderSourceCsvRowType(input.sourceCsvColumns) : "";
7253
- const rowTypeDefinitions = generateRowTypeDefinitions(input);
7254
- const finderPlayResultTypes = generatedFinderPlayResultTypes(input);
7327
+ const sourceCsvRowType = input2.options.from.kind === "csv" ? renderSourceCsvRowType(input2.sourceCsvColumns) : "";
7328
+ const rowTypeDefinitions = generateRowTypeDefinitions(input2);
7329
+ const finderPlayResultTypes = generatedFinderPlayResultTypes(input2);
7255
7330
  const typeDefinitions = [
7256
7331
  sourceCsvRowType.trimEnd(),
7257
7332
  rowTypeDefinitions,
7258
7333
  finderPlayResultTypes
7259
7334
  ].filter((definition) => definition.trim().length > 0).join("\n\n");
7260
- const importNames = needsWhenImport(input.options) ? "definePlay, when" : "definePlay";
7335
+ const importNames = needsWhenImport(input2.options) ? "definePlay, when" : "definePlay";
7261
7336
  return `import { ${importNames} } from 'deepline';
7262
7337
 
7263
7338
  ${typeDefinitions}
@@ -7266,8 +7341,8 @@ type Input = {
7266
7341
  limit?: number;
7267
7342
  };
7268
7343
 
7269
- export default definePlay(${jsString(input.options.name)}, async (ctx, input: Input = {}) => {
7270
- const limit = Math.max(1, Math.min(Number(input.limit ?? ${input.options.limit}), ${input.options.limit}));
7344
+ export default definePlay(${jsString(input2.options.name)}, async (ctx, input: Input = {}) => {
7345
+ const limit = Math.max(1, Math.min(Number(input.limit ?? ${input2.options.limit}), ${input2.options.limit}));
7271
7346
  ${sourceSeedBlock}
7272
7347
 
7273
7348
  const rowsToProcess = ${sourceCollection}.slice(0, limit);
@@ -7279,7 +7354,7 @@ export default definePlay(${jsString(input.options.name)}, async (ctx, input: In
7279
7354
  .map('bootstrap_rows', rowsToProcess)${mapSteps}
7280
7355
  .run({
7281
7356
  key: (_row, index) => index,
7282
- description: ${jsString(`Bootstrap ${input.options.template}: seed source rows, run requested stages, then return the mapped rows.`)},
7357
+ description: ${jsString(`Bootstrap ${input2.options.template}: seed source rows, run requested stages, then return the mapped rows.`)},
7283
7358
  });
7284
7359
 
7285
7360
  return {
@@ -7687,8 +7762,8 @@ var SHA256_ROUND_CONSTANTS = [
7687
7762
  function rightRotate32(value, bits) {
7688
7763
  return value >>> bits | value << 32 - bits;
7689
7764
  }
7690
- function sha256Hex(input) {
7691
- const bytes = Array.from(new TextEncoder().encode(input));
7765
+ function sha256Hex(input2) {
7766
+ const bytes = Array.from(new TextEncoder().encode(input2));
7692
7767
  const bitLength = bytes.length * 8;
7693
7768
  bytes.push(128);
7694
7769
  while (bytes.length % 64 !== 56) {
@@ -7862,10 +7937,10 @@ function looksLikeInvalidExtractedGetter(error, sourceLine) {
7862
7937
  if (!/Property '[^']+' does not exist on type/.test(error)) return false;
7863
7938
  return /\bextracted(?:Values|Lists)\s*\./.test(sourceLine);
7864
7939
  }
7865
- function addPlayCheckRepairHints(input) {
7940
+ function addPlayCheckRepairHints(input2) {
7866
7941
  let addedHint = false;
7867
- return input.errors.map((error) => {
7868
- const line = sourceLineForError(input.sourceCode, error);
7942
+ return input2.errors.map((error) => {
7943
+ const line = sourceLineForError(input2.sourceCode, error);
7869
7944
  if (addedHint || !looksLikeInvalidExtractedGetter(error, line) || error.includes(EXTRACTED_GETTER_ERROR_HINT)) {
7870
7945
  return error;
7871
7946
  }
@@ -7876,6 +7951,7 @@ ${EXTRACTED_GETTER_ERROR_HINT}`;
7876
7951
  }
7877
7952
 
7878
7953
  // src/cli/commands/play.ts
7954
+ var PLAY_START_STREAM_FAST_COMPLETION_WAIT_MS = 2500;
7879
7955
  var PLAY_RUN_RESERVED_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
7880
7956
  "--json",
7881
7957
  "--wait",
@@ -7927,9 +8003,9 @@ function parseReferencedPlayTarget2(target) {
7927
8003
  function isPrebuiltReferenceTarget(target) {
7928
8004
  return target.trim().toLowerCase().startsWith("prebuilt/");
7929
8005
  }
7930
- function buildBarePrebuiltReferenceError(input) {
8006
+ function buildBarePrebuiltReferenceError(input2) {
7931
8007
  return new Error(
7932
- `Prebuilt play "${input.requested}" must be referenced as "${input.reference}". Use the prebuilt/ namespace anywhere you run, describe, get, or link to Deepline-managed plays.`
8008
+ `Prebuilt play "${input2.requested}" must be referenced as "${input2.reference}". Use the prebuilt/ namespace anywhere you run, describe, get, or link to Deepline-managed plays.`
7933
8009
  );
7934
8010
  }
7935
8011
  async function assertCanonicalNamedPlayReference(client, target) {
@@ -7972,23 +8048,23 @@ function buildCloneEditStarter(play) {
7972
8048
  checkCommand: `deepline plays check ${path}`
7973
8049
  };
7974
8050
  }
7975
- function materializeRemotePlaySource(input) {
7976
- if (isFileTarget(input.target)) {
8051
+ function materializeRemotePlaySource(input2) {
8052
+ if (isFileTarget(input2.target)) {
7977
8053
  return null;
7978
8054
  }
7979
- if (!input.sourceCode.trim()) {
8055
+ if (!input2.sourceCode.trim()) {
7980
8056
  return null;
7981
8057
  }
7982
- const outputPath = input.outPath ?? defaultMaterializedPlayPath(input.playName);
8058
+ const outputPath = input2.outPath ?? defaultMaterializedPlayPath(input2.playName);
7983
8059
  if (existsSync7(outputPath)) {
7984
8060
  const existingSource = readFileSync6(outputPath, "utf-8");
7985
- if (existingSource === input.sourceCode) {
8061
+ if (existingSource === input2.sourceCode) {
7986
8062
  return { path: outputPath, status: "unchanged", created: false };
7987
8063
  }
7988
- writeFileSync6(outputPath, input.sourceCode, "utf-8");
8064
+ writeFileSync6(outputPath, input2.sourceCode, "utf-8");
7989
8065
  return { path: outputPath, status: "updated", created: false };
7990
8066
  }
7991
- writeFileSync6(outputPath, input.sourceCode, "utf-8");
8067
+ writeFileSync6(outputPath, input2.sourceCode, "utf-8");
7992
8068
  return { path: outputPath, status: "created", created: true };
7993
8069
  }
7994
8070
  function formatLoadedPlayMessage(materializedFile) {
@@ -8038,12 +8114,12 @@ function isFileTarget(target) {
8038
8114
  function looksLikeRunId(target) {
8039
8115
  return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
8040
8116
  }
8041
- function formatPlayCommandReceivedRunIdError(input) {
8042
- return `\`deepline plays ${input.command} <run-id>\` expects a play name, but this looks like a run id.
8117
+ function formatPlayCommandReceivedRunIdError(input2) {
8118
+ return `\`deepline plays ${input2.command} <run-id>\` expects a play name, but this looks like a run id.
8043
8119
  Use:
8044
- deepline runs get ${input.runId} --json
8045
- deepline runs logs ${input.runId} --json
8046
- deepline runs export ${input.runId} --out output.csv`;
8120
+ deepline runs get ${input2.runId} --json
8121
+ deepline runs logs ${input2.runId} --json
8122
+ deepline runs export ${input2.runId} --out output.csv`;
8047
8123
  }
8048
8124
  function looksLikeFilePath(target) {
8049
8125
  if (target.trim().toLowerCase().startsWith("prebuilt/")) {
@@ -8097,9 +8173,9 @@ function parseInputFlagValue(raw) {
8097
8173
  }
8098
8174
  return raw;
8099
8175
  }
8100
- function getDottedInputValue(input, path) {
8176
+ function getDottedInputValue(input2, path) {
8101
8177
  const parts = path.split(".").map((part) => part.trim()).filter(Boolean);
8102
- let cursor = input;
8178
+ let cursor = input2;
8103
8179
  for (const part of parts) {
8104
8180
  if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) {
8105
8181
  return void 0;
@@ -8108,12 +8184,12 @@ function getDottedInputValue(input, path) {
8108
8184
  }
8109
8185
  return cursor;
8110
8186
  }
8111
- function setDottedInputValue(input, path, value) {
8187
+ function setDottedInputValue(input2, path, value) {
8112
8188
  const parts = path.split(".").map((part) => part.trim()).filter(Boolean);
8113
8189
  if (parts.length === 0) {
8114
8190
  throw new Error(`Invalid play input flag path: ${path}`);
8115
8191
  }
8116
- let cursor = input;
8192
+ let cursor = input2;
8117
8193
  for (const part of parts.slice(0, -1)) {
8118
8194
  const existing = cursor[part];
8119
8195
  if (existing !== void 0 && (!existing || typeof existing !== "object" || Array.isArray(existing))) {
@@ -8180,17 +8256,17 @@ function inputContainsLocalFilePath(value) {
8180
8256
  }
8181
8257
  return false;
8182
8258
  }
8183
- function namedRunNeedsPlayDefinition(input) {
8184
- return input.revisionSelector === "latest" || inputContainsLocalFilePath(input.runtimeInput);
8259
+ function namedRunNeedsPlayDefinition(input2) {
8260
+ return input2.revisionSelector === "latest" || inputContainsLocalFilePath(input2.runtimeInput);
8185
8261
  }
8186
- async function stageFileInputArgs(input) {
8262
+ async function stageFileInputArgs(input2) {
8187
8263
  const uniqueBindings = [
8188
8264
  ...new Map(
8189
- input.bindings.map((binding) => [binding.inputPath, binding])
8265
+ input2.bindings.map((binding) => [binding.inputPath, binding])
8190
8266
  ).values()
8191
8267
  ];
8192
8268
  const localFiles = uniqueBindings.flatMap((binding) => {
8193
- const value = getDottedInputValue(input.runtimeInput, binding.inputPath);
8269
+ const value = getDottedInputValue(input2.runtimeInput, binding.inputPath);
8194
8270
  if (!isLocalFilePathValue(value)) return [];
8195
8271
  const absolutePath = resolve10(value);
8196
8272
  return [{ binding, absolutePath, logicalPath: basename3(absolutePath) }];
@@ -8198,22 +8274,22 @@ async function stageFileInputArgs(input) {
8198
8274
  if (localFiles.length === 0) {
8199
8275
  return { inputFile: null, packagedFiles: [] };
8200
8276
  }
8201
- input.progress.phase(
8277
+ input2.progress.phase(
8202
8278
  localFiles.length === 1 ? "staging input file" : "staging input files"
8203
8279
  );
8204
- const staged = await input.client.stagePlayFiles(
8280
+ const staged = await input2.client.stagePlayFiles(
8205
8281
  localFiles.map((file) => stageFile(file.logicalPath, file.absolutePath))
8206
8282
  );
8207
8283
  for (const [index, file] of localFiles.entries()) {
8208
8284
  setDottedInputValue(
8209
- input.runtimeInput,
8285
+ input2.runtimeInput,
8210
8286
  file.binding.inputPath,
8211
8287
  file.logicalPath
8212
8288
  );
8213
8289
  const stagedFile = staged[index];
8214
8290
  if (stagedFile && stagedFile.logicalPath !== file.logicalPath) {
8215
8291
  setDottedInputValue(
8216
- input.runtimeInput,
8292
+ input2.runtimeInput,
8217
8293
  file.binding.inputPath,
8218
8294
  stagedFile.logicalPath
8219
8295
  );
@@ -8498,16 +8574,16 @@ function buildStepReceiptsDebugCommand(runId) {
8498
8574
  const sql = `select convert_from(k, 'UTF8') as receipt_key, case status when 0 then 'pending' when 1 then 'running' when 2 then 'completed' when 3 then 'failed' when 4 then 'skipped' else status::text end as status, output, error, updated_at from ${table} where run_id = ${quoteSqlLiteral(runId)} order by updated_at asc, receipt_key asc limit 20`;
8499
8575
  return buildDebugDbQueryCommand(sql);
8500
8576
  }
8501
- function buildMapTableDebugCommand(input) {
8577
+ function buildMapTableDebugCommand(input2) {
8502
8578
  try {
8503
8579
  const tableName = validatePlaySheetTableName(
8504
- input.playName,
8505
- input.tableNamespace
8580
+ input2.playName,
8581
+ input2.tableNamespace
8506
8582
  );
8507
8583
  const table = `${quoteSqlIdentifier(
8508
8584
  PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
8509
8585
  )}.${quoteSqlIdentifier(tableName)}`;
8510
- const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(input.runId)} limit 20`;
8586
+ const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(input2.runId)} limit 20`;
8511
8587
  return buildDebugDbQueryCommand(sql);
8512
8588
  } catch {
8513
8589
  return null;
@@ -8527,37 +8603,37 @@ function extractTableNamespaceFromLiveEvent(event) {
8527
8603
  }
8528
8604
  return null;
8529
8605
  }
8530
- function emitLiveDebugTableHints(input) {
8531
- if (input.jsonOutput || !input.runId || input.runId === "pending") {
8606
+ function emitLiveDebugTableHints(input2) {
8607
+ if (input2.jsonOutput || !input2.runId || input2.runId === "pending") {
8532
8608
  return;
8533
8609
  }
8534
- input.state.emittedDebugKeys ??= /* @__PURE__ */ new Set();
8535
- const receiptsKey = `receipts:${input.runId}`;
8536
- if (!input.state.emittedDebugKeys.has(receiptsKey)) {
8537
- input.state.emittedDebugKeys.add(receiptsKey);
8538
- input.progress.writeLine(
8539
- `Debug top-level outputs: ${buildStepReceiptsDebugCommand(input.runId)}`,
8610
+ input2.state.emittedDebugKeys ??= /* @__PURE__ */ new Set();
8611
+ const receiptsKey = `receipts:${input2.runId}`;
8612
+ if (!input2.state.emittedDebugKeys.has(receiptsKey)) {
8613
+ input2.state.emittedDebugKeys.add(receiptsKey);
8614
+ input2.progress.writeLine(
8615
+ `Debug top-level outputs: ${buildStepReceiptsDebugCommand(input2.runId)}`,
8540
8616
  process.stdout
8541
8617
  );
8542
8618
  }
8543
- const tableNamespace = extractTableNamespaceFromLiveEvent(input.event);
8619
+ const tableNamespace = extractTableNamespaceFromLiveEvent(input2.event);
8544
8620
  if (!tableNamespace) {
8545
8621
  return;
8546
8622
  }
8547
- const tableKey = `table:${input.runId}:${tableNamespace}`;
8548
- if (input.state.emittedDebugKeys.has(tableKey)) {
8623
+ const tableKey = `table:${input2.runId}:${tableNamespace}`;
8624
+ if (input2.state.emittedDebugKeys.has(tableKey)) {
8549
8625
  return;
8550
8626
  }
8551
8627
  const command = buildMapTableDebugCommand({
8552
- playName: input.playName,
8553
- runId: input.runId,
8628
+ playName: input2.playName,
8629
+ runId: input2.runId,
8554
8630
  tableNamespace
8555
8631
  });
8556
8632
  if (!command) {
8557
8633
  return;
8558
8634
  }
8559
- input.state.emittedDebugKeys.add(tableKey);
8560
- input.progress.writeLine(
8635
+ input2.state.emittedDebugKeys.add(tableKey);
8636
+ input2.progress.writeLine(
8561
8637
  `Debug rows for ${tableNamespace}: ${command}`,
8562
8638
  process.stdout
8563
8639
  );
@@ -8590,9 +8666,9 @@ function formatProgressLabel(raw) {
8590
8666
  const value = typeof raw === "string" && raw.trim() ? raw.trim() : "step";
8591
8667
  return value.replace(/^map:/, "").replace(/^tool:/, "");
8592
8668
  }
8593
- function formatProgressCounts(input) {
8594
- const completed = typeof input.completed === "number" && Number.isFinite(input.completed) ? input.completed : null;
8595
- const total = typeof input.total === "number" && Number.isFinite(input.total) ? input.total : null;
8669
+ function formatProgressCounts(input2) {
8670
+ const completed = typeof input2.completed === "number" && Number.isFinite(input2.completed) ? input2.completed : null;
8671
+ const total = typeof input2.total === "number" && Number.isFinite(input2.total) ? input2.total : null;
8596
8672
  if (completed === null || total === null || total <= 0) {
8597
8673
  return null;
8598
8674
  }
@@ -8600,7 +8676,7 @@ function formatProgressCounts(input) {
8600
8676
  0,
8601
8677
  Math.min(100, Math.round(completed / total * 100))
8602
8678
  );
8603
- const failed = typeof input.failed === "number" && Number.isFinite(input.failed) && input.failed > 0 ? `, failed ${formatInteger(input.failed)}` : "";
8679
+ const failed = typeof input2.failed === "number" && Number.isFinite(input2.failed) && input2.failed > 0 ? `, failed ${formatInteger(input2.failed)}` : "";
8604
8680
  return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
8605
8681
  }
8606
8682
  function getProgressLinesFromLiveEvent(event) {
@@ -8642,14 +8718,14 @@ function getProgressLinesFromLiveEvent(event) {
8642
8718
  }
8643
8719
  return lines;
8644
8720
  }
8645
- function printPlayProgressLines(input) {
8646
- for (const line of input.lines) {
8721
+ function printPlayProgressLines(input2) {
8722
+ for (const line of input2.lines) {
8647
8723
  const signature = line.trim();
8648
- if (!signature || input.state.lastProgressSignature === signature) {
8724
+ if (!signature || input2.state.lastProgressSignature === signature) {
8649
8725
  continue;
8650
8726
  }
8651
- input.state.lastProgressSignature = signature;
8652
- input.progress.writeLine(line);
8727
+ input2.state.lastProgressSignature = signature;
8728
+ input2.progress.writeLine(line);
8653
8729
  }
8654
8730
  }
8655
8731
  function buildPlayDashboardUrl(baseUrl, playName) {
@@ -8657,102 +8733,102 @@ function buildPlayDashboardUrl(baseUrl, playName) {
8657
8733
  const encodedPlayName = encodeURIComponent(playName);
8658
8734
  return `${trimmedBase}/dashboard/plays/${encodedPlayName}`;
8659
8735
  }
8660
- function openPlayDashboard(input) {
8661
- if (input.jsonOutput || input.noOpen || !input.dashboardUrl) {
8736
+ function openPlayDashboard(input2) {
8737
+ if (input2.jsonOutput || input2.noOpen || !input2.dashboardUrl) {
8662
8738
  return;
8663
8739
  }
8664
- openInBrowser(input.dashboardUrl);
8740
+ openInBrowser(input2.dashboardUrl);
8665
8741
  }
8666
- function printPlayLogLines(input) {
8667
- for (const line of input.lines) {
8668
- if (input.emitLogs) {
8742
+ function printPlayLogLines(input2) {
8743
+ for (const line of input2.lines) {
8744
+ if (input2.emitLogs) {
8669
8745
  const formatted = formatPlayLogLine(
8670
8746
  line,
8671
- input.status ?? void 0,
8672
- input.state
8747
+ input2.status ?? void 0,
8748
+ input2.state
8673
8749
  );
8674
8750
  if (formatted) {
8675
- input.progress.writeLogLine(formatted);
8751
+ input2.progress.writeLogLine(formatted);
8676
8752
  }
8677
8753
  }
8678
- input.state.lastLogIndex += 1;
8754
+ input2.state.lastLogIndex += 1;
8679
8755
  }
8680
8756
  }
8681
- function assertPlayWaitNotTimedOut(input) {
8682
- if (input.waitTimeoutMs !== null && Date.now() - input.startedAt >= input.waitTimeoutMs) {
8683
- const hasRealRunId = input.workflowId.length > 0 && input.workflowId !== "pending";
8684
- const phaseSuffix = input.lastPhase && input.lastPhase.trim() ? ` (last observed phase: ${input.lastPhase.trim()})` : "";
8685
- const tailHint = hasRealRunId ? ` Run 'deepline runs tail ${input.workflowId} --json' to inspect it, or rerun with a larger --tail-timeout-ms.` : ` The run never reported a workflow id \u2014 the start request likely failed before reaching the scheduler. Check server logs and rerun with a larger --tail-timeout-ms.`;
8757
+ function assertPlayWaitNotTimedOut(input2) {
8758
+ if (input2.waitTimeoutMs !== null && Date.now() - input2.startedAt >= input2.waitTimeoutMs) {
8759
+ const hasRealRunId = input2.workflowId.length > 0 && input2.workflowId !== "pending";
8760
+ const phaseSuffix = input2.lastPhase && input2.lastPhase.trim() ? ` (last observed phase: ${input2.lastPhase.trim()})` : "";
8761
+ const tailHint = hasRealRunId ? ` Run 'deepline runs tail ${input2.workflowId} --json' to inspect it, or rerun with a larger --tail-timeout-ms.` : ` The run never reported a workflow id \u2014 the start request likely failed before reaching the scheduler. Check server logs and rerun with a larger --tail-timeout-ms.`;
8686
8762
  throw new DeeplineError(
8687
- `Timed out waiting for play ${hasRealRunId ? input.workflowId : "<no run id>"} after ${Math.ceil(input.waitTimeoutMs / 1e3)}s${phaseSuffix}.${tailHint}`,
8763
+ `Timed out waiting for play ${hasRealRunId ? input2.workflowId : "<no run id>"} after ${Math.ceil(input2.waitTimeoutMs / 1e3)}s${phaseSuffix}.${tailHint}`,
8688
8764
  void 0,
8689
8765
  "PLAY_WAIT_TIMEOUT",
8690
8766
  {
8691
- ...hasRealRunId ? { runId: input.workflowId, workflowId: input.workflowId } : {},
8692
- ...input.lastPhase ? { phase: input.lastPhase } : {},
8693
- timeoutMs: input.waitTimeoutMs
8767
+ ...hasRealRunId ? { runId: input2.workflowId, workflowId: input2.workflowId } : {},
8768
+ ...input2.lastPhase ? { phase: input2.lastPhase } : {},
8769
+ timeoutMs: input2.waitTimeoutMs
8694
8770
  }
8695
8771
  );
8696
8772
  }
8697
8773
  }
8698
- async function waitForPlayCompletionByStream(input) {
8774
+ async function waitForPlayCompletionByStream(input2) {
8699
8775
  const controller = new AbortController();
8700
8776
  let timedOut = false;
8701
8777
  let lastPhase = null;
8702
- const timeout = input.waitTimeoutMs === null ? null : setTimeout(
8778
+ const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
8703
8779
  () => {
8704
8780
  timedOut = true;
8705
8781
  controller.abort();
8706
8782
  },
8707
- Math.max(1, input.waitTimeoutMs - (Date.now() - input.startedAt))
8783
+ Math.max(1, input2.waitTimeoutMs - (Date.now() - input2.startedAt))
8708
8784
  );
8709
8785
  try {
8710
- for await (const event of input.client.streamPlayRunEvents(
8711
- input.workflowId,
8786
+ for await (const event of input2.client.streamPlayRunEvents(
8787
+ input2.workflowId,
8712
8788
  { signal: controller.signal }
8713
8789
  )) {
8714
- assertPlayWaitNotTimedOut({ ...input, lastPhase });
8790
+ assertPlayWaitNotTimedOut({ ...input2, lastPhase });
8715
8791
  const phase = describeLiveEventPhase(event);
8716
8792
  if (phase) {
8717
8793
  lastPhase = phase;
8718
- input.progress.phase(phase);
8794
+ input2.progress.phase(phase);
8719
8795
  }
8720
8796
  emitLiveDebugTableHints({
8721
8797
  event,
8722
- playName: input.playName,
8723
- runId: input.workflowId,
8724
- jsonOutput: input.jsonOutput,
8725
- state: input.state,
8726
- progress: input.progress
8798
+ playName: input2.playName,
8799
+ runId: input2.workflowId,
8800
+ jsonOutput: input2.jsonOutput,
8801
+ state: input2.state,
8802
+ progress: input2.progress
8727
8803
  });
8728
8804
  printPlayLogLines({
8729
8805
  lines: getLogLinesFromLiveEvent(event),
8730
8806
  status: null,
8731
- jsonOutput: input.jsonOutput,
8732
- emitLogs: input.emitLogs,
8733
- state: input.state,
8734
- progress: input.progress
8807
+ jsonOutput: input2.jsonOutput,
8808
+ emitLogs: input2.emitLogs,
8809
+ state: input2.state,
8810
+ progress: input2.progress
8735
8811
  });
8736
- if (!input.jsonOutput) {
8812
+ if (!input2.jsonOutput) {
8737
8813
  printPlayProgressLines({
8738
8814
  lines: getProgressLinesFromLiveEvent(event),
8739
- state: input.state,
8740
- progress: input.progress
8815
+ state: input2.state,
8816
+ progress: input2.progress
8741
8817
  });
8742
8818
  }
8743
8819
  const status = getStatusFromLiveEvent(event);
8744
8820
  if (status && TERMINAL_PLAY_STATUSES2.has(status)) {
8745
- const finalStatus = await input.client.getPlayStatus(input.workflowId, {
8821
+ const finalStatus = await input2.client.getPlayStatus(input2.workflowId, {
8746
8822
  billing: false
8747
8823
  });
8748
8824
  if (TERMINAL_PLAY_STATUSES2.has(finalStatus.status)) {
8749
- return input.dashboardUrl ? { ...finalStatus, dashboardUrl: input.dashboardUrl } : finalStatus;
8825
+ return input2.dashboardUrl ? { ...finalStatus, dashboardUrl: input2.dashboardUrl } : finalStatus;
8750
8826
  }
8751
8827
  }
8752
8828
  }
8753
8829
  } catch (error) {
8754
8830
  if (timedOut) {
8755
- assertPlayWaitNotTimedOut({ ...input, lastPhase });
8831
+ assertPlayWaitNotTimedOut({ ...input2, lastPhase });
8756
8832
  }
8757
8833
  throw error;
8758
8834
  } finally {
@@ -8762,25 +8838,25 @@ async function waitForPlayCompletionByStream(input) {
8762
8838
  }
8763
8839
  const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
8764
8840
  throw new DeeplineError(
8765
- `Play live stream ended before the run reached a terminal state runId=${input.workflowId}${phaseSuffix}.`,
8841
+ `Play live stream ended before the run reached a terminal state runId=${input2.workflowId}${phaseSuffix}.`,
8766
8842
  void 0,
8767
8843
  "PLAY_LIVE_STREAM_ENDED",
8768
8844
  {
8769
- runId: input.workflowId,
8770
- workflowId: input.workflowId,
8845
+ runId: input2.workflowId,
8846
+ workflowId: input2.workflowId,
8771
8847
  ...lastPhase ? { phase: lastPhase } : {}
8772
8848
  }
8773
8849
  );
8774
8850
  }
8775
- async function startAndWaitForPlayCompletionByStream(input) {
8851
+ async function startAndWaitForPlayCompletionByStream(input2) {
8776
8852
  for (let attempt = 0; attempt <= PLAY_START_TRANSIENT_RETRY_DELAYS_MS.length; attempt += 1) {
8777
- const status = await startAndWaitForPlayCompletionByStreamOnce(input);
8853
+ const status = await startAndWaitForPlayCompletionByStreamOnce(input2);
8778
8854
  const retryDelayMs = PLAY_START_TRANSIENT_RETRY_DELAYS_MS[attempt];
8779
8855
  if (retryDelayMs === void 0 || !isRetryablePendingStartFailure(status)) {
8780
8856
  return status;
8781
8857
  }
8782
- if (!input.jsonOutput) {
8783
- input.progress.writeLine(
8858
+ if (!input2.jsonOutput) {
8859
+ input2.progress.writeLine(
8784
8860
  `[play watch] start failed before run id with a transient error; retrying (${playStatusErrorText(status)})`
8785
8861
  );
8786
8862
  }
@@ -8788,23 +8864,23 @@ async function startAndWaitForPlayCompletionByStream(input) {
8788
8864
  phase: "cli.play_start_stream_retry",
8789
8865
  ms: 0,
8790
8866
  ok: true,
8791
- playName: input.playName,
8867
+ playName: input2.playName,
8792
8868
  attempt: attempt + 1,
8793
8869
  reason: playStatusErrorText(status)
8794
8870
  });
8795
8871
  await sleep4(retryDelayMs);
8796
8872
  }
8797
8873
  throw new DeeplineError(
8798
- `Play ${input.playName} did not start after retrying transient start failures.`,
8874
+ `Play ${input2.playName} did not start after retrying transient start failures.`,
8799
8875
  void 0,
8800
8876
  "PLAY_START_RETRY_EXHAUSTED"
8801
8877
  );
8802
8878
  }
8803
- async function startAndWaitForPlayCompletionByStreamOnce(input) {
8879
+ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
8804
8880
  const startedAt = Date.now();
8805
8881
  const dashboardUrl = buildPlayDashboardUrl(
8806
- input.client.baseUrl,
8807
- input.playName
8882
+ input2.client.baseUrl,
8883
+ input2.playName
8808
8884
  );
8809
8885
  const state = {
8810
8886
  lastLogIndex: 0,
@@ -8818,15 +8894,19 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
8818
8894
  let eventCount = 0;
8819
8895
  let firstRunIdMs = null;
8820
8896
  let lastPhase = null;
8821
- const timeout = input.waitTimeoutMs === null ? null : setTimeout(
8897
+ const startRequest = {
8898
+ ...input2.request,
8899
+ waitForCompletionMs: typeof input2.request.waitForCompletionMs === "number" ? input2.request.waitForCompletionMs : PLAY_START_STREAM_FAST_COMPLETION_WAIT_MS
8900
+ };
8901
+ const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
8822
8902
  () => {
8823
8903
  timedOut = true;
8824
8904
  controller.abort();
8825
8905
  },
8826
- Math.max(1, input.waitTimeoutMs)
8906
+ Math.max(1, input2.waitTimeoutMs)
8827
8907
  );
8828
8908
  try {
8829
- for await (const event of input.client.startPlayRunStream(input.request, {
8909
+ for await (const event of input2.client.startPlayRunStream(startRequest, {
8830
8910
  signal: controller.signal
8831
8911
  })) {
8832
8912
  eventCount += 1;
@@ -8837,55 +8917,55 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
8837
8917
  }
8838
8918
  const workflowId = lastKnownWorkflowId || "pending";
8839
8919
  if (workflowId !== "pending" && !emittedDashboardUrl) {
8840
- if (!input.jsonOutput) {
8920
+ if (!input2.jsonOutput) {
8841
8921
  writeStartedPlayRun({
8842
8922
  runId: workflowId,
8843
- playName: input.playName,
8923
+ playName: input2.playName,
8844
8924
  dashboardUrl,
8845
8925
  jsonOutput: false,
8846
- progress: input.progress
8926
+ progress: input2.progress
8847
8927
  });
8848
8928
  }
8849
8929
  openPlayDashboard({
8850
8930
  dashboardUrl,
8851
- jsonOutput: input.jsonOutput,
8852
- noOpen: input.noOpen
8931
+ jsonOutput: input2.jsonOutput,
8932
+ noOpen: input2.noOpen
8853
8933
  });
8854
- input.progress.phase(`loading play on ${dashboardUrl}`);
8934
+ input2.progress.phase(`loading play on ${dashboardUrl}`);
8855
8935
  emittedDashboardUrl = true;
8856
8936
  }
8857
8937
  assertPlayWaitNotTimedOut({
8858
8938
  workflowId,
8859
8939
  startedAt,
8860
- waitTimeoutMs: input.waitTimeoutMs,
8940
+ waitTimeoutMs: input2.waitTimeoutMs,
8861
8941
  lastPhase
8862
8942
  });
8863
8943
  const phase = describeLiveEventPhase(event);
8864
8944
  if (phase) {
8865
8945
  lastPhase = phase;
8866
- input.progress.phase(phase);
8946
+ input2.progress.phase(phase);
8867
8947
  }
8868
8948
  printPlayLogLines({
8869
8949
  lines: getLogLinesFromLiveEvent(event),
8870
8950
  status: null,
8871
- jsonOutput: input.jsonOutput,
8872
- emitLogs: input.emitLogs,
8951
+ jsonOutput: input2.jsonOutput,
8952
+ emitLogs: input2.emitLogs,
8873
8953
  state,
8874
- progress: input.progress
8954
+ progress: input2.progress
8875
8955
  });
8876
8956
  emitLiveDebugTableHints({
8877
8957
  event,
8878
- playName: input.playName,
8958
+ playName: input2.playName,
8879
8959
  runId: workflowId,
8880
- jsonOutput: input.jsonOutput,
8960
+ jsonOutput: input2.jsonOutput,
8881
8961
  state,
8882
- progress: input.progress
8962
+ progress: input2.progress
8883
8963
  });
8884
- if (!input.jsonOutput) {
8964
+ if (!input2.jsonOutput) {
8885
8965
  printPlayProgressLines({
8886
8966
  lines: getProgressLinesFromLiveEvent(event),
8887
8967
  state,
8888
- progress: input.progress
8968
+ progress: input2.progress
8889
8969
  });
8890
8970
  }
8891
8971
  const finalStatus = getFinalStatusFromLiveEvent(event);
@@ -8894,7 +8974,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
8894
8974
  phase: "cli.play_start_stream_terminal",
8895
8975
  ms: Date.now() - startedAt,
8896
8976
  ok: true,
8897
- playName: input.playName,
8977
+ playName: input2.playName,
8898
8978
  workflowId: finalStatus.runId || lastKnownWorkflowId || null,
8899
8979
  eventCount,
8900
8980
  firstRunIdMs,
@@ -8908,7 +8988,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
8908
8988
  assertPlayWaitNotTimedOut({
8909
8989
  workflowId: lastKnownWorkflowId,
8910
8990
  startedAt,
8911
- waitTimeoutMs: input.waitTimeoutMs,
8991
+ waitTimeoutMs: input2.waitTimeoutMs,
8912
8992
  lastPhase
8913
8993
  });
8914
8994
  }
@@ -8917,7 +8997,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
8917
8997
  clearTimeout(timeout);
8918
8998
  }
8919
8999
  const reason = error instanceof Error ? error.message : String(error);
8920
- if (!input.jsonOutput) {
9000
+ if (!input2.jsonOutput) {
8921
9001
  process.stderr.write(
8922
9002
  `[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
8923
9003
  `
@@ -8927,7 +9007,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
8927
9007
  phase: "cli.play_start_stream_reconnect",
8928
9008
  ms: Date.now() - startedAt,
8929
9009
  ok: true,
8930
- playName: input.playName,
9010
+ playName: input2.playName,
8931
9011
  workflowId: lastKnownWorkflowId,
8932
9012
  eventCount,
8933
9013
  firstRunIdMs,
@@ -8935,16 +9015,16 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
8935
9015
  reason
8936
9016
  });
8937
9017
  return waitForPlayCompletionByStream({
8938
- client: input.client,
8939
- playName: input.playName,
9018
+ client: input2.client,
9019
+ playName: input2.playName,
8940
9020
  workflowId: lastKnownWorkflowId,
8941
9021
  dashboardUrl,
8942
- jsonOutput: input.jsonOutput,
8943
- emitLogs: input.emitLogs,
8944
- waitTimeoutMs: input.waitTimeoutMs,
9022
+ jsonOutput: input2.jsonOutput,
9023
+ emitLogs: input2.emitLogs,
9024
+ waitTimeoutMs: input2.waitTimeoutMs,
8945
9025
  startedAt,
8946
9026
  state,
8947
- progress: input.progress
9027
+ progress: input2.progress
8948
9028
  });
8949
9029
  }
8950
9030
  throw error;
@@ -8954,8 +9034,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
8954
9034
  }
8955
9035
  }
8956
9036
  if (lastKnownWorkflowId) {
8957
- if (!input.jsonOutput) {
8958
- input.progress.writeLine(
9037
+ if (!input2.jsonOutput) {
9038
+ input2.progress.writeLine(
8959
9039
  `[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
8960
9040
  );
8961
9041
  }
@@ -8963,7 +9043,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
8963
9043
  phase: "cli.play_start_stream_reconnect",
8964
9044
  ms: Date.now() - startedAt,
8965
9045
  ok: true,
8966
- playName: input.playName,
9046
+ playName: input2.playName,
8967
9047
  workflowId: lastKnownWorkflowId,
8968
9048
  eventCount,
8969
9049
  firstRunIdMs,
@@ -8971,16 +9051,16 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
8971
9051
  reason: "stream ended before terminal event"
8972
9052
  });
8973
9053
  return waitForPlayCompletionByStream({
8974
- client: input.client,
8975
- playName: input.playName,
9054
+ client: input2.client,
9055
+ playName: input2.playName,
8976
9056
  workflowId: lastKnownWorkflowId,
8977
9057
  dashboardUrl,
8978
- jsonOutput: input.jsonOutput,
8979
- emitLogs: input.emitLogs,
8980
- waitTimeoutMs: input.waitTimeoutMs,
9058
+ jsonOutput: input2.jsonOutput,
9059
+ emitLogs: input2.emitLogs,
9060
+ waitTimeoutMs: input2.waitTimeoutMs,
8981
9061
  startedAt,
8982
9062
  state,
8983
- progress: input.progress
9063
+ progress: input2.progress
8984
9064
  });
8985
9065
  }
8986
9066
  const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
@@ -9061,7 +9141,7 @@ function compactReturnValue(value, depth = 0) {
9061
9141
  if (!value || typeof value !== "object") {
9062
9142
  return value;
9063
9143
  }
9064
- const output = {};
9144
+ const output2 = {};
9065
9145
  for (const [key, entry] of Object.entries(value)) {
9066
9146
  if (depth === 0 && key === "_metadata") {
9067
9147
  continue;
@@ -9072,9 +9152,9 @@ function compactReturnValue(value, depth = 0) {
9072
9152
  if (key === "access") {
9073
9153
  continue;
9074
9154
  }
9075
- output[key] = compactReturnValue(entry, depth + 1);
9155
+ output2[key] = compactReturnValue(entry, depth + 1);
9076
9156
  }
9077
- return output;
9157
+ return output2;
9078
9158
  }
9079
9159
  function formatJsonPreview(value) {
9080
9160
  const json = JSON.stringify(value, null, 2);
@@ -9283,22 +9363,22 @@ function extractBillingForStatus(status, error) {
9283
9363
  const progressError = getStringField(status.progress, "error");
9284
9364
  return extractBillingFromText(error) ?? extractBillingFromText(progressError) ?? getObjectField(status, "billing");
9285
9365
  }
9286
- function formatInsufficientCreditsMessage(input) {
9287
- const operation = getStringField(input.billing, "operation_id") ?? getStringField(input.billing, "operation") ?? extractToolIdFromErrorText(input.error) ?? getStringField(input.billing, "provider") ?? "tool call";
9288
- const balance = formatCreditAmount(input.billing.balance_credits);
9289
- const required = formatCreditAmount(input.billing.required_credits);
9366
+ function formatInsufficientCreditsMessage(input2) {
9367
+ const operation = getStringField(input2.billing, "operation_id") ?? getStringField(input2.billing, "operation") ?? extractToolIdFromErrorText(input2.error) ?? getStringField(input2.billing, "provider") ?? "tool call";
9368
+ const balance = formatCreditAmount(input2.billing.balance_credits);
9369
+ const required = formatCreditAmount(input2.billing.required_credits);
9290
9370
  const recommended = formatCreditAmount(
9291
- input.billing.recommended_add_credits ?? input.billing.needed_credits
9371
+ input2.billing.recommended_add_credits ?? input2.billing.needed_credits
9292
9372
  );
9293
- const billingUrl = getStringField(input.billing, "billing_url");
9294
- const workspace = getStringField(input.billing, "workspace_id") ?? getStringField(input.billing, "workspaceId");
9373
+ const billingUrl = getStringField(input2.billing, "billing_url");
9374
+ const workspace = getStringField(input2.billing, "workspace_id") ?? getStringField(input2.billing, "workspaceId");
9295
9375
  const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
9296
9376
  const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
9297
9377
  return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
9298
9378
  }
9299
- function buildInsufficientCreditsSummaryLines(input) {
9300
- const progress = input.status.progress;
9301
- const rowsInfo = extractCanonicalRowsInfo(input.status);
9379
+ function buildInsufficientCreditsSummaryLines(input2) {
9380
+ const progress = input2.status.progress;
9381
+ const rowsInfo = extractCanonicalRowsInfo(input2.status);
9302
9382
  const completed = getNumericField(progress, "completed") ?? getNumericField(progress, "completedRows") ?? rowsInfo?.rows.length ?? null;
9303
9383
  const total = getNumericField(progress, "total") ?? getNumericField(progress, "totalRows") ?? rowsInfo?.totalRows ?? null;
9304
9384
  const lines = [
@@ -9306,16 +9386,16 @@ function buildInsufficientCreditsSummaryLines(input) {
9306
9386
  completed === null ? " completed rows: unknown" : ` completed rows: ${formatInteger(completed)}${total !== null ? ` of ${formatInteger(total)}` : ""}`,
9307
9387
  " reusable receipts: yes; rerun after adding credits to continue from completed provider work"
9308
9388
  ];
9309
- const billingUrl = getStringField(input.billing, "billing_url");
9389
+ const billingUrl = getStringField(input2.billing, "billing_url");
9310
9390
  const recommended = formatCreditAmount(
9311
- input.billing.recommended_add_credits ?? input.billing.needed_credits
9391
+ input2.billing.recommended_add_credits ?? input2.billing.needed_credits
9312
9392
  );
9313
9393
  if (billingUrl) {
9314
9394
  lines.push(
9315
9395
  recommended !== "-" ? ` add credits: add >=${recommended} at ${billingUrl}` : ` add credits: ${billingUrl}`
9316
9396
  );
9317
9397
  }
9318
- const runId = input.status.runId?.trim();
9398
+ const runId = input2.status.runId?.trim();
9319
9399
  if (runId) {
9320
9400
  lines.push(` inspect: deepline runs get ${runId} --json`);
9321
9401
  lines.push(
@@ -9650,8 +9730,8 @@ function actionToCommand(action) {
9650
9730
  }
9651
9731
  function readFirstDatasetActions(packaged) {
9652
9732
  for (const step of readRecordArray(packaged.steps)) {
9653
- const output = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
9654
- const actions = output?.actions && typeof output.actions === "object" && !Array.isArray(output.actions) ? output.actions : null;
9733
+ const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
9734
+ const actions = output2?.actions && typeof output2.actions === "object" && !Array.isArray(output2.actions) ? output2.actions : null;
9655
9735
  if (actions) {
9656
9736
  return actions;
9657
9737
  }
@@ -9673,12 +9753,12 @@ function buildRunPackageTextLines(packaged) {
9673
9753
  const id = typeof step.id === "string" ? step.id : "step";
9674
9754
  const kind = typeof step.kind === "string" ? step.kind : "step";
9675
9755
  const stepStatus = typeof step.status === "string" ? step.status : status;
9676
- const output = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
9677
- const rowCount = output && typeof output.rowCount === "number" ? ` rows=${formatInteger(output.rowCount)}` : "";
9678
- const preview = output?.preview && typeof output.preview === "object" && !Array.isArray(output.preview) ? output.preview : null;
9756
+ const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
9757
+ const rowCount = output2 && typeof output2.rowCount === "number" ? ` rows=${formatInteger(output2.rowCount)}` : "";
9758
+ const preview = output2?.preview && typeof output2.preview === "object" && !Array.isArray(output2.preview) ? output2.preview : null;
9679
9759
  const previewRows = Array.isArray(preview?.rows) ? preview.rows.length : null;
9680
9760
  lines.push(` ${kind} ${id}: ${stepStatus}${rowCount}`);
9681
- lines.push(...formatPackageDatasetSummaryLines(output?.summary));
9761
+ lines.push(...formatPackageDatasetSummaryLines(output2?.summary));
9682
9762
  if (previewRows !== null) {
9683
9763
  lines.push(
9684
9764
  ` preview=${previewRows}${preview?.truncated ? " truncated" : ""}`
@@ -9761,19 +9841,19 @@ function writePlayResult(status, jsonOutput, options) {
9761
9841
  ` }
9762
9842
  );
9763
9843
  }
9764
- async function resolvePlayRunOutputStatus(input) {
9765
- if (!getPlayRunPackage(input.status)) {
9766
- return input.status;
9844
+ async function resolvePlayRunOutputStatus(input2) {
9845
+ if (!getPlayRunPackage(input2.status)) {
9846
+ return input2.status;
9767
9847
  }
9768
- const runId = input.status.runId;
9848
+ const runId = input2.status.runId;
9769
9849
  if (!runId) {
9770
- return input.status;
9850
+ return input2.status;
9771
9851
  }
9772
- const refreshedStatus = await input.client.getPlayStatus(runId, {
9852
+ const refreshedStatus = await input2.client.getPlayStatus(runId, {
9773
9853
  billing: false,
9774
- full: input.fullJson
9854
+ full: input2.fullJson
9775
9855
  });
9776
- const dashboardUrl = input.status.dashboardUrl;
9856
+ const dashboardUrl = input2.status.dashboardUrl;
9777
9857
  return typeof dashboardUrl === "string" ? { ...refreshedStatus, dashboardUrl } : refreshedStatus;
9778
9858
  }
9779
9859
  var RUN_EXPORT_PAGE_SIZE = 5e3;
@@ -9804,21 +9884,21 @@ function extractRunPlayName(status) {
9804
9884
  function normalizeCustomerDbIdentifier(value) {
9805
9885
  return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
9806
9886
  }
9807
- function buildCustomerDbQueryPlan(input) {
9808
- const playName = extractRunPlayName(input.status);
9809
- const tableNamespace = input.rowsInfo.tableNamespace?.trim();
9810
- if (!playName || !tableNamespace || input.rowsInfo.totalRows <= 0) {
9887
+ function buildCustomerDbQueryPlan(input2) {
9888
+ const playName = extractRunPlayName(input2.status);
9889
+ const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
9890
+ if (!playName || !tableNamespace || input2.rowsInfo.totalRows <= 0) {
9811
9891
  return null;
9812
9892
  }
9813
9893
  const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
9814
9894
  tableNamespace
9815
9895
  )}`;
9816
- const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input.status.runId)} limit ${input.rowsInfo.totalRows}`;
9817
- const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input.rowsInfo.totalRows}`;
9896
+ const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input2.status.runId)} limit ${input2.rowsInfo.totalRows}`;
9897
+ const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input2.rowsInfo.totalRows}`;
9818
9898
  return {
9819
9899
  sql,
9820
9900
  json: `${base} --json`,
9821
- csv: `${base} --format csv --out ${shellSingleQuote(resolve10(input.outPath))}`
9901
+ csv: `${base} --format csv --out ${shellSingleQuote(resolve10(input2.outPath))}`
9822
9902
  };
9823
9903
  }
9824
9904
  function exportableSheetRow(row) {
@@ -9869,20 +9949,20 @@ function mergeExportColumns(preferredColumns, rows) {
9869
9949
  }
9870
9950
  return columns;
9871
9951
  }
9872
- async function fetchBackingDatasetRows(input) {
9873
- const playName = extractRunPlayName(input.status);
9874
- const tableNamespace = input.rowsInfo.tableNamespace?.trim();
9952
+ async function fetchBackingDatasetRows(input2) {
9953
+ const playName = extractRunPlayName(input2.status);
9954
+ const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
9875
9955
  if (!playName || !tableNamespace) {
9876
9956
  return null;
9877
9957
  }
9878
9958
  const sheetRows = [];
9879
9959
  let offset = 0;
9880
- let expectedTotal = input.rowsInfo.totalRows;
9960
+ let expectedTotal = input2.rowsInfo.totalRows;
9881
9961
  while (true) {
9882
- const page = await input.client.runs.exportDatasetRows({
9962
+ const page = await input2.client.runs.exportDatasetRows({
9883
9963
  playName,
9884
9964
  tableNamespace,
9885
- runId: input.status.runId,
9965
+ runId: input2.status.runId,
9886
9966
  limit: RUN_EXPORT_PAGE_SIZE,
9887
9967
  offset
9888
9968
  });
@@ -9897,20 +9977,20 @@ async function fetchBackingDatasetRows(input) {
9897
9977
  offset += page.rows.length;
9898
9978
  }
9899
9979
  const rows = sheetRows.map(exportableSheetRow).filter((row) => Boolean(row));
9900
- if (rows.length < input.rowsInfo.totalRows) {
9980
+ if (rows.length < input2.rowsInfo.totalRows) {
9901
9981
  return null;
9902
9982
  }
9903
9983
  const columns = mergeExportColumns(
9904
- input.rowsInfo.columnsExplicit ? input.rowsInfo.columns : [],
9984
+ input2.rowsInfo.columnsExplicit ? input2.rowsInfo.columns : [],
9905
9985
  rows
9906
9986
  );
9907
9987
  return {
9908
- ...input.rowsInfo,
9988
+ ...input2.rowsInfo,
9909
9989
  rows,
9910
9990
  columns,
9911
9991
  totalRows: rows.length,
9912
9992
  complete: true,
9913
- source: `${input.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
9993
+ source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
9914
9994
  };
9915
9995
  }
9916
9996
  async function exportPlayStatusRows(client, status, outPath, options = {}) {
@@ -10012,11 +10092,11 @@ function extractActiveRunsFromError(error) {
10012
10092
  function activeRunId(run) {
10013
10093
  return getStringField(run, "workflowId") ?? getStringField(run, "runId");
10014
10094
  }
10015
- function formatActiveRunConflictError(input) {
10095
+ function formatActiveRunConflictError(input2) {
10016
10096
  const lines = [
10017
- `Active run exists for ${input.playName}. Use --force to supersede, or inspect/stop the active run first.`
10097
+ `Active run exists for ${input2.playName}. Use --force to supersede, or inspect/stop the active run first.`
10018
10098
  ];
10019
- for (const run of input.activeRuns.slice(0, 3)) {
10099
+ for (const run of input2.activeRuns.slice(0, 3)) {
10020
10100
  const runId = activeRunId(run);
10021
10101
  if (!runId) {
10022
10102
  continue;
@@ -10130,49 +10210,49 @@ function renderServerResultView(value) {
10130
10210
  }
10131
10211
  return { lines: lines.length > 1 ? lines : [], actions: [] };
10132
10212
  }
10133
- function writeStartedPlayRun(input) {
10134
- if (input.package && isPlayRunPackageValue(input.package)) {
10135
- if (input.jsonOutput) {
10136
- printCommandEnvelope(input.package, { json: true });
10213
+ function writeStartedPlayRun(input2) {
10214
+ if (input2.package && isPlayRunPackageValue(input2.package)) {
10215
+ if (input2.jsonOutput) {
10216
+ printCommandEnvelope(input2.package, { json: true });
10137
10217
  return;
10138
10218
  }
10139
- const lines2 = buildRunPackageTextLines(input.package);
10140
- const output2 = lines2.join("\n");
10141
- if (input.progress) {
10142
- input.progress.writeLine(output2, process.stdout);
10219
+ const lines2 = buildRunPackageTextLines(input2.package);
10220
+ const output3 = lines2.join("\n");
10221
+ if (input2.progress) {
10222
+ input2.progress.writeLine(output3, process.stdout);
10143
10223
  return;
10144
10224
  }
10145
- printCommandEnvelope(input.package, {
10225
+ printCommandEnvelope(input2.package, {
10146
10226
  json: false,
10147
- text: `${output2}
10227
+ text: `${output3}
10148
10228
  `
10149
10229
  });
10150
10230
  return;
10151
10231
  }
10152
10232
  const payload = {
10153
- runId: input.runId,
10154
- workflowId: input.runId,
10155
- name: input.playName,
10156
- status: input.status ?? "started",
10157
- dashboardUrl: input.dashboardUrl,
10233
+ runId: input2.runId,
10234
+ workflowId: input2.runId,
10235
+ name: input2.playName,
10236
+ status: input2.status ?? "started",
10237
+ dashboardUrl: input2.dashboardUrl,
10158
10238
  next: {
10159
- inspect: `deepline runs get ${input.runId} --json`,
10160
- full: `deepline runs get ${input.runId} --full --json`,
10161
- logs: `deepline runs logs ${input.runId} --json`,
10162
- export: `deepline runs export ${input.runId} --out output.csv`,
10163
- stop: `deepline runs stop ${input.runId} --reason "stale lock" --json`
10239
+ inspect: `deepline runs get ${input2.runId} --json`,
10240
+ full: `deepline runs get ${input2.runId} --full --json`,
10241
+ logs: `deepline runs logs ${input2.runId} --json`,
10242
+ export: `deepline runs export ${input2.runId} --out output.csv`,
10243
+ stop: `deepline runs stop ${input2.runId} --reason "stale lock" --json`
10164
10244
  }
10165
10245
  };
10166
10246
  const lines = [
10167
- `Started ${input.playName}`,
10168
- ` run id: ${input.runId}`,
10169
- ` inspect: deepline runs get ${input.runId} --json`,
10170
- ` full debug: deepline runs get ${input.runId} --full --json`,
10171
- ` logs: deepline runs logs ${input.runId} --json`,
10172
- ` export after completion: deepline runs export ${input.runId} --out output.csv`,
10173
- ` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`
10247
+ `Started ${input2.playName}`,
10248
+ ` run id: ${input2.runId}`,
10249
+ ` inspect: deepline runs get ${input2.runId} --json`,
10250
+ ` full debug: deepline runs get ${input2.runId} --full --json`,
10251
+ ` logs: deepline runs logs ${input2.runId} --json`,
10252
+ ` export after completion: deepline runs export ${input2.runId} --out output.csv`,
10253
+ ` stop run: deepline runs stop ${input2.runId} --reason "stale lock" --json`
10174
10254
  ];
10175
- if (input.jsonOutput) {
10255
+ if (input2.jsonOutput) {
10176
10256
  printCommandEnvelope(
10177
10257
  {
10178
10258
  ...payload,
@@ -10182,12 +10262,12 @@ function writeStartedPlayRun(input) {
10182
10262
  );
10183
10263
  return;
10184
10264
  }
10185
- if (input.dashboardUrl) {
10186
- lines.push(` play page: ${input.dashboardUrl}`);
10265
+ if (input2.dashboardUrl) {
10266
+ lines.push(` play page: ${input2.dashboardUrl}`);
10187
10267
  }
10188
- const output = lines.join("\n");
10189
- if (input.progress) {
10190
- input.progress.writeLine(output, process.stdout);
10268
+ const output2 = lines.join("\n");
10269
+ if (input2.progress) {
10270
+ input2.progress.writeLine(output2, process.stdout);
10191
10271
  return;
10192
10272
  }
10193
10273
  printCommandEnvelope(
@@ -10195,7 +10275,7 @@ function writeStartedPlayRun(input) {
10195
10275
  ...payload,
10196
10276
  render: { sections: [{ title: "play run", lines }] }
10197
10277
  },
10198
- { json: false, text: `${output}
10278
+ { json: false, text: `${output2}
10199
10279
  ` }
10200
10280
  );
10201
10281
  }
@@ -10203,7 +10283,7 @@ function parsePlayRunOptions(args) {
10203
10283
  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.map guidance.";
10204
10284
  let filePath = null;
10205
10285
  let playName = null;
10206
- let input = null;
10286
+ let input2 = null;
10207
10287
  let revisionId = null;
10208
10288
  let revisionSelector = null;
10209
10289
  const watch = !args.includes("--no-wait");
@@ -10224,7 +10304,7 @@ function parsePlayRunOptions(args) {
10224
10304
  continue;
10225
10305
  }
10226
10306
  if ((arg === "--input" || arg === "-i") && args[index + 1]) {
10227
- input = parseJsonInput(args[++index]);
10307
+ input2 = parseJsonInput(args[++index]);
10228
10308
  continue;
10229
10309
  }
10230
10310
  if (arg === "--revision-id" && args[index + 1]) {
@@ -10273,8 +10353,8 @@ function parsePlayRunOptions(args) {
10273
10353
  }
10274
10354
  if (arg.startsWith("--")) {
10275
10355
  const { path, value } = parseInputFieldFlag(arg, args[index + 1]);
10276
- input ??= {};
10277
- setDottedInputValue(input, path, parseInputFlagValue(value));
10356
+ input2 ??= {};
10357
+ setDottedInputValue(input2, path, parseInputFlagValue(value));
10278
10358
  if (!arg.includes("=")) {
10279
10359
  index += 1;
10280
10360
  }
@@ -10309,7 +10389,7 @@ function parsePlayRunOptions(args) {
10309
10389
  }
10310
10390
  return {
10311
10391
  target: filePath ? { kind: "file", path: filePath } : { kind: "name", name: playName },
10312
- input,
10392
+ input: input2,
10313
10393
  revisionId,
10314
10394
  revisionSelector,
10315
10395
  watch,
@@ -10676,15 +10756,15 @@ async function handleFileBackedRun(options) {
10676
10756
  });
10677
10757
  return 0;
10678
10758
  }
10679
- async function resolveNamedRunRevisionId(input) {
10680
- if (input.revisionId) {
10681
- return input.revisionId;
10759
+ async function resolveNamedRunRevisionId(input2) {
10760
+ if (input2.revisionId) {
10761
+ return input2.revisionId;
10682
10762
  }
10683
- if (input.selector === "latest") {
10684
- const versions = await input.client.listPlayVersions(input.playName);
10763
+ if (input2.selector === "latest") {
10764
+ const versions = await input2.client.listPlayVersions(input2.playName);
10685
10765
  const latest = versions[0];
10686
10766
  if (!latest?._id) {
10687
- throw new Error(`No saved revisions found for ${input.playName}.`);
10767
+ throw new Error(`No saved revisions found for ${input2.playName}.`);
10688
10768
  }
10689
10769
  return latest._id;
10690
10770
  }
@@ -12484,6 +12564,218 @@ async function handlePlayShareUnpublish(args) {
12484
12564
  return 0;
12485
12565
  }
12486
12566
 
12567
+ // src/cli/commands/secrets.ts
12568
+ import { stdin as input, stdout as output } from "process";
12569
+ var hiddenInputBuffer = "";
12570
+ function normalizeSecretName(value) {
12571
+ const normalized = value.trim().toUpperCase();
12572
+ if (!/^[A-Z][A-Z0-9_]{1,63}$/.test(normalized)) {
12573
+ throw new Error(
12574
+ "Secret names must be 2-64 characters and use uppercase letters, numbers, and underscores."
12575
+ );
12576
+ }
12577
+ return normalized;
12578
+ }
12579
+ function renderSecret(secret) {
12580
+ const scope = secret.scope === "play" && secret.playName ? `play:${secret.playName}` : secret.scope;
12581
+ return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}`;
12582
+ }
12583
+ async function readHiddenLine(prompt) {
12584
+ if (!input.isTTY || !output.isTTY) {
12585
+ throw new Error(
12586
+ "Secret values must be entered from an interactive TTY. Do not pipe, pass, or script secret values."
12587
+ );
12588
+ }
12589
+ output.write(prompt);
12590
+ const previousRawMode = input.isRaw;
12591
+ if (typeof input.setRawMode === "function") input.setRawMode(true);
12592
+ let value = "";
12593
+ input.resume();
12594
+ return await new Promise((resolve12, reject) => {
12595
+ let settled = false;
12596
+ const cleanup = () => {
12597
+ input.off("data", onData);
12598
+ input.off("end", onEnd);
12599
+ input.off("error", onError);
12600
+ if (typeof input.setRawMode === "function") {
12601
+ input.setRawMode(previousRawMode);
12602
+ }
12603
+ };
12604
+ const finish = (line) => {
12605
+ if (settled) return;
12606
+ settled = true;
12607
+ output.write("\n");
12608
+ cleanup();
12609
+ resolve12(line);
12610
+ };
12611
+ const fail = (error) => {
12612
+ if (settled) return;
12613
+ settled = true;
12614
+ output.write("\n");
12615
+ cleanup();
12616
+ reject(error);
12617
+ };
12618
+ const processText = (text) => {
12619
+ for (let index = 0; index < text.length; index++) {
12620
+ const char = text[index];
12621
+ const code = char.charCodeAt(0);
12622
+ if (char === "\r" || char === "\n") {
12623
+ hiddenInputBuffer = text.slice(index + 1);
12624
+ finish(value);
12625
+ return;
12626
+ }
12627
+ if (code === 3) {
12628
+ fail(new Error("Secret input cancelled."));
12629
+ return;
12630
+ }
12631
+ if (code === 8 || code === 127) {
12632
+ value = value.slice(0, -1);
12633
+ continue;
12634
+ }
12635
+ if (code >= 32) {
12636
+ value += char;
12637
+ }
12638
+ }
12639
+ hiddenInputBuffer = "";
12640
+ };
12641
+ const onData = (chunk) => {
12642
+ processText(chunk.toString());
12643
+ };
12644
+ const onEnd = () => fail(new Error("Secret input ended before a value was entered."));
12645
+ const onError = (error) => fail(error);
12646
+ input.on("data", onData);
12647
+ input.once("end", onEnd);
12648
+ input.once("error", onError);
12649
+ if (hiddenInputBuffer) {
12650
+ const buffered = hiddenInputBuffer;
12651
+ hiddenInputBuffer = "";
12652
+ processText(buffered);
12653
+ }
12654
+ });
12655
+ }
12656
+ async function readSecretValue() {
12657
+ const first = await readHiddenLine("Secret value: ");
12658
+ if (!first) throw new Error("Secret value is required.");
12659
+ const second = await readHiddenLine("Confirm secret value: ");
12660
+ if (first !== second) {
12661
+ throw new Error("Secret values did not match.");
12662
+ }
12663
+ return first;
12664
+ }
12665
+ function preventShellHistoryLeak(forbidden) {
12666
+ if (forbidden.length > 0) {
12667
+ throw new Error(
12668
+ "Do not pass secret values as command arguments. Run `deepline secrets set NAME` and enter the value at the hidden prompt."
12669
+ );
12670
+ }
12671
+ }
12672
+ async function handleList(options) {
12673
+ const client = new DeeplineClient();
12674
+ const secrets = await client.listSecrets();
12675
+ printCommandEnvelope(
12676
+ {
12677
+ secrets,
12678
+ count: secrets.length,
12679
+ render: {
12680
+ sections: [
12681
+ {
12682
+ title: "secrets",
12683
+ lines: secrets.length ? secrets.map(renderSecret) : ["No play secrets are configured."]
12684
+ }
12685
+ ]
12686
+ }
12687
+ },
12688
+ { json: options.json }
12689
+ );
12690
+ }
12691
+ async function handleCheck(nameInput, options) {
12692
+ const name = normalizeSecretName(nameInput);
12693
+ const client = new DeeplineClient();
12694
+ const secret = await client.checkSecret(name);
12695
+ printCommandEnvelope(
12696
+ {
12697
+ ok: Boolean(secret),
12698
+ name,
12699
+ secret: secret ?? null,
12700
+ render: {
12701
+ sections: [
12702
+ {
12703
+ title: "secret check",
12704
+ lines: [
12705
+ secret ? `${name}: active` : `${name}: missing, disabled, or empty`
12706
+ ]
12707
+ }
12708
+ ]
12709
+ }
12710
+ },
12711
+ { json: options.json }
12712
+ );
12713
+ if (!secret) process.exitCode = 4;
12714
+ }
12715
+ async function handleSet(nameInput, forbidden, options) {
12716
+ preventShellHistoryLeak(forbidden);
12717
+ const name = normalizeSecretName(nameInput);
12718
+ const scope = options.scope === "play" ? "play" : "org";
12719
+ const playName = options.play?.trim();
12720
+ if (scope === "play" && !playName) {
12721
+ throw new Error("--play <name> is required when --scope play is used.");
12722
+ }
12723
+ const value = await readSecretValue();
12724
+ const { http } = getAuthedHttpClient();
12725
+ const response = await http.post(
12726
+ "/api/v2/secrets",
12727
+ {
12728
+ name,
12729
+ value,
12730
+ scope,
12731
+ ...playName ? { playName } : {}
12732
+ }
12733
+ );
12734
+ const secret = response.secret;
12735
+ printCommandEnvelope(
12736
+ {
12737
+ ok: true,
12738
+ secret,
12739
+ render: {
12740
+ sections: [
12741
+ {
12742
+ title: "secret saved",
12743
+ lines: [`${secret.name}: saved (${secret.scope})`]
12744
+ }
12745
+ ]
12746
+ }
12747
+ },
12748
+ { json: options.json }
12749
+ );
12750
+ }
12751
+ function registerSecretsCommands(program) {
12752
+ const secrets = program.command("secrets").description("Manage play secrets without revealing values.").addHelpText(
12753
+ "after",
12754
+ `
12755
+ Notes:
12756
+ Secret values are never accepted as command arguments, stdin pipes, env vars,
12757
+ or files. Use deepline secrets set NAME and type the value at the hidden TTY
12758
+ prompt. Agents can list/check metadata but should not enter secret values.
12759
+
12760
+ Examples:
12761
+ deepline secrets list
12762
+ deepline secrets check HUBSPOT_TOKEN
12763
+ deepline secrets set HUBSPOT_TOKEN
12764
+ `
12765
+ );
12766
+ secrets.command("list").description("List secret metadata only.").option("--json", "Emit JSON output").action(async (options) => {
12767
+ await handleList(options);
12768
+ });
12769
+ secrets.command("check").description("Check whether a secret exists and is active.").argument("<name>", "Secret name").option("--json", "Emit JSON output").action(async (name, options) => {
12770
+ await handleCheck(name, options);
12771
+ });
12772
+ secrets.command("set").description("Set or rotate a secret through a hidden interactive prompt.").argument("<name>", "Secret name").argument("[forbidden...]", "Do not pass secret values here").option("--json", "Emit JSON output").option("--scope <scope>", "Secret scope: org or play", "org").option("--play <name>", "Play name for play-scoped secrets").action(
12773
+ async (name, forbidden, options) => {
12774
+ await handleSet(name, forbidden ?? [], options);
12775
+ }
12776
+ );
12777
+ }
12778
+
12487
12779
  // src/cli/commands/tools.ts
12488
12780
  import { Option } from "commander";
12489
12781
  import { chmodSync, mkdtempSync, writeFileSync as writeFileSync8 } from "fs";
@@ -13689,25 +13981,25 @@ function shellQuote(value) {
13689
13981
  function powerShellQuote(value) {
13690
13982
  return `'${value.replace(/'/g, "''")}'`;
13691
13983
  }
13692
- function seedToolListScript(input) {
13693
- const stem = safeFileStem(input.toolId);
13984
+ function seedToolListScript(input2) {
13985
+ const stem = safeFileStem(input2.toolId);
13694
13986
  const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
13695
13987
  const scriptDir = mkdtempSync(join9(tmpdir3(), "deepline-workflow-seed-"));
13696
13988
  chmodSync(scriptDir, 448);
13697
13989
  const scriptPath = join9(scriptDir, fileName);
13698
13990
  const projectDir = `deepline/projects/${stem}-workflow`;
13699
13991
  const playName = `${stem}-workflow`;
13700
- const sampleRows = input.rows.length > 0 ? `${JSON.stringify(input.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
13701
- const columns = Object.keys(input.rows[0] ?? {}).join(", ");
13702
- const rowKey = Object.prototype.hasOwnProperty.call(input.rows[0] ?? {}, "id") ? '"id"' : "(row) => JSON.stringify(row)";
13992
+ const sampleRows = input2.rows.length > 0 ? `${JSON.stringify(input2.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
13993
+ const columns = Object.keys(input2.rows[0] ?? {}).join(", ");
13994
+ const rowKey = Object.prototype.hasOwnProperty.call(input2.rows[0] ?? {}, "id") ? '"id"' : "(row) => JSON.stringify(row)";
13703
13995
  const script = `import { definePlay } from 'deepline';
13704
13996
 
13705
13997
  export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
13706
13998
  const result = await ctx.tools.execute({
13707
- id: ${JSON.stringify(input.toolId)},
13708
- tool: ${JSON.stringify(input.toolId)},
13709
- input: ${JSON.stringify(input.payload)},
13710
- description: ${JSON.stringify(`Seed ${input.toolId} rows for workflow expansion.`)},
13999
+ id: ${JSON.stringify(input2.toolId)},
14000
+ tool: ${JSON.stringify(input2.toolId)},
14001
+ input: ${JSON.stringify(input2.payload)},
14002
+ description: ${JSON.stringify(`Seed ${input2.toolId} rows for workflow expansion.`)},
13711
14003
  });
13712
14004
 
13713
14005
  const list = Object.values(result.extractedLists)[0];
@@ -13739,23 +14031,23 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
13739
14031
  windowsCopyCommand: `New-Item -ItemType Directory -Force -Path ${powerShellQuote(projectDir.replace(/\//g, "\\"))} | Out-Null; Copy-Item -LiteralPath ${powerShellQuote(scriptPath)} -Destination ${powerShellQuote(`${projectDir.replace(/\//g, "\\")}\\${fileName}`)}`
13740
14032
  };
13741
14033
  }
13742
- function buildToolExecuteBaseEnvelope(input) {
13743
- const envelope = commandEnvelopeFromRawResponse(input.rawResponse);
13744
- const summaryEntries = Object.entries(input.summary);
13745
- const outputPreview = input.listConversion ? {
14034
+ function buildToolExecuteBaseEnvelope(input2) {
14035
+ const envelope = commandEnvelopeFromRawResponse(input2.rawResponse);
14036
+ const summaryEntries = Object.entries(input2.summary);
14037
+ const outputPreview = input2.listConversion ? {
13746
14038
  kind: "list",
13747
- rowCount: input.listConversion.rows.length,
13748
- columns: Object.keys(input.listConversion.rows[0] ?? {}),
13749
- preview: input.listConversion.rows.slice(0, 5),
13750
- listStrategy: input.listConversion.strategy,
13751
- listSourcePath: input.listConversion.sourcePath
14039
+ rowCount: input2.listConversion.rows.length,
14040
+ columns: Object.keys(input2.listConversion.rows[0] ?? {}),
14041
+ preview: input2.listConversion.rows.slice(0, 5),
14042
+ listStrategy: input2.listConversion.strategy,
14043
+ listSourcePath: input2.listConversion.sourcePath
13752
14044
  } : {
13753
14045
  kind: summaryEntries.length > 0 ? "object" : "raw",
13754
- summary: input.summary
14046
+ summary: input2.summary
13755
14047
  };
13756
14048
  const envelopeHasCanonicalOutput = isRecord5(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
13757
- const inspectCommand = `deepline tools execute ${input.toolId} --input ${shellQuote(JSON.stringify(input.params))} --json`;
13758
- const actions = input.listConversion ? [
14049
+ const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote(JSON.stringify(input2.params))} --json`;
14050
+ const actions = input2.listConversion ? [
13759
14051
  {
13760
14052
  label: "next",
13761
14053
  command: "move starter script into a project folder and expand it into a Deepline play"
@@ -13764,24 +14056,24 @@ function buildToolExecuteBaseEnvelope(input) {
13764
14056
  return {
13765
14057
  ...envelope,
13766
14058
  ...envelopeHasCanonicalOutput ? { output_preview: outputPreview } : { output: outputPreview },
13767
- ...summaryEntries.length > 0 ? { summary: input.summary } : {},
14059
+ ...summaryEntries.length > 0 ? { summary: input2.summary } : {},
13768
14060
  next: {
13769
14061
  inspect: inspectCommand,
13770
14062
  playDebugging: "When fixing a play getter, inspect the actual play run table with runs get / inspect rows; do not copy CLI preview paths blindly.",
13771
- ...input.listConversion ? {
14063
+ ...input2.listConversion ? {
13772
14064
  expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again.",
13773
- listSourcePath: input.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
14065
+ listSourcePath: input2.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
13774
14066
  } : {}
13775
14067
  },
13776
14068
  render: {
13777
- sections: input.listConversion ? [
14069
+ sections: input2.listConversion ? [
13778
14070
  {
13779
14071
  title: "output",
13780
14072
  lines: [
13781
- `${input.listConversion.rows.length} row(s) extracted from ${input.listConversion.sourcePath ?? "auto-detected list"}`,
14073
+ `${input2.listConversion.rows.length} row(s) extracted from ${input2.listConversion.sourcePath ?? "auto-detected list"}`,
13782
14074
  "paths above are observed from this execute response; use run table rows to debug play getters",
13783
- `columns: ${JSON.stringify(Object.keys(input.listConversion.rows[0] ?? {}))}`,
13784
- `preview: ${JSON.stringify(input.listConversion.rows.slice(0, 5))}`
14075
+ `columns: ${JSON.stringify(Object.keys(input2.listConversion.rows[0] ?? {}))}`,
14076
+ `preview: ${JSON.stringify(input2.listConversion.rows.slice(0, 5))}`
13785
14077
  ]
13786
14078
  }
13787
14079
  ] : [
@@ -13789,7 +14081,7 @@ function buildToolExecuteBaseEnvelope(input) {
13789
14081
  title: "result",
13790
14082
  lines: summaryEntries.length > 0 ? summaryEntries.map(
13791
14083
  ([key, value]) => `${key}=${String(value)}`
13792
- ) : [JSON.stringify(input.rawResponse, null, 2)]
14084
+ ) : [JSON.stringify(input2.rawResponse, null, 2)]
13793
14085
  }
13794
14086
  ],
13795
14087
  actions
@@ -14110,6 +14402,174 @@ Examples:
14110
14402
  });
14111
14403
  }
14112
14404
 
14405
+ // ../shared_libs/cli/command-compatibility.json
14406
+ var command_compatibility_default = {
14407
+ enrich: {
14408
+ family: "python",
14409
+ label: "a legacy Python CLI enrichment command",
14410
+ sdk_alternative: "Use `deepline plays ...` for durable workflows or `deepline tools execute ...` for one tool call."
14411
+ },
14412
+ session: {
14413
+ family: "python",
14414
+ label: "a legacy Python CLI session/playground command",
14415
+ sdk_alternative: "Use SDK play run output and run commands such as `deepline plays run ...`."
14416
+ },
14417
+ workflows: {
14418
+ family: "python",
14419
+ label: "a legacy Python CLI workflow command",
14420
+ sdk_alternative: "Use `deepline plays ...` in the SDK CLI."
14421
+ },
14422
+ backend: {
14423
+ family: "python",
14424
+ label: "a legacy Python CLI playground backend command"
14425
+ },
14426
+ events: {
14427
+ family: "python",
14428
+ label: "a legacy Python CLI event command"
14429
+ },
14430
+ plays: {
14431
+ family: "sdk",
14432
+ label: "an SDK CLI play command",
14433
+ python_alternative: "Use `deepline workflows ...` only for legacy workflows."
14434
+ },
14435
+ play: {
14436
+ family: "sdk",
14437
+ label: "an SDK CLI play command",
14438
+ python_alternative: "Use `deepline workflows ...` only for legacy workflows."
14439
+ },
14440
+ runs: {
14441
+ family: "sdk",
14442
+ label: "an SDK CLI run inspection command"
14443
+ },
14444
+ health: {
14445
+ family: "sdk",
14446
+ label: "an SDK CLI health command"
14447
+ }
14448
+ };
14449
+
14450
+ // ../shared_libs/cli/install-commands.json
14451
+ var install_commands_default = {
14452
+ skills: {
14453
+ index_path: "/.well-known/skills/index.json",
14454
+ default_agents: ["codex", "claude-code", "cursor"],
14455
+ npx_binary: "npx",
14456
+ npx_add_args_template: [
14457
+ "--yes",
14458
+ "skills",
14459
+ "add",
14460
+ "{skills_index_url}",
14461
+ "--agent",
14462
+ "{agents}",
14463
+ "--global",
14464
+ "--yes",
14465
+ "--skill",
14466
+ "{skill_name}",
14467
+ "--full-depth"
14468
+ ]
14469
+ },
14470
+ cli: {
14471
+ legacy_python_shell_template: "curl -s {base_url}/api/v2/cli/install | bash",
14472
+ sdk_npm_global: "npm install -g deepline@latest"
14473
+ }
14474
+ };
14475
+
14476
+ // src/cli/install-commands.ts
14477
+ var INSTALL_COMMANDS = install_commands_default;
14478
+ function normalizeBaseUrl2(baseUrl) {
14479
+ return baseUrl.replace(/\/$/, "");
14480
+ }
14481
+ function renderTemplate(template, values) {
14482
+ return template.replace(/\{([a-z_]+)\}/g, (match, key) => {
14483
+ return values[key] ?? match;
14484
+ });
14485
+ }
14486
+ function shellJoin(args) {
14487
+ return args.join(" ");
14488
+ }
14489
+ function skillsIndexUrl(baseUrl) {
14490
+ return `${normalizeBaseUrl2(baseUrl)}${INSTALL_COMMANDS.skills.index_path}`;
14491
+ }
14492
+ function buildSkillsAddArgs(baseUrl, skillName, options = {}) {
14493
+ const values = {
14494
+ skills_index_url: skillsIndexUrl(baseUrl),
14495
+ agents: INSTALL_COMMANDS.skills.default_agents.join(" "),
14496
+ skill_name: skillName
14497
+ };
14498
+ const rendered = INSTALL_COMMANDS.skills.npx_add_args_template.flatMap(
14499
+ (arg, index) => {
14500
+ const next = index === 0 && options.firstArg ? options.firstArg : arg;
14501
+ const value = renderTemplate(next, values);
14502
+ return arg === "{agents}" ? INSTALL_COMMANDS.skills.default_agents : value;
14503
+ }
14504
+ );
14505
+ return rendered;
14506
+ }
14507
+ function skillsInstallCommand(baseUrl, skillName) {
14508
+ return `${INSTALL_COMMANDS.skills.npx_binary} ${shellJoin(
14509
+ buildSkillsAddArgs(baseUrl, skillName)
14510
+ )}`;
14511
+ }
14512
+ function legacyPythonInstallCommand(baseUrl) {
14513
+ return renderTemplate(INSTALL_COMMANDS.cli.legacy_python_shell_template, {
14514
+ base_url: normalizeBaseUrl2(baseUrl)
14515
+ });
14516
+ }
14517
+ function sdkNpmGlobalInstallCommand() {
14518
+ return INSTALL_COMMANDS.cli.sdk_npm_global;
14519
+ }
14520
+
14521
+ // src/cli/command-compatibility.ts
14522
+ var COMMAND_COMPATIBILITY = command_compatibility_default;
14523
+ function cliFamilyLabel(family) {
14524
+ return family === "sdk" ? "SDK CLI" : "legacy Python CLI";
14525
+ }
14526
+ function commandCompatibilityHint(currentFamily, commandName, baseUrl) {
14527
+ const compatibility = COMMAND_COMPATIBILITY[commandName];
14528
+ if (!compatibility || compatibility.family === currentFamily) {
14529
+ return null;
14530
+ }
14531
+ const expectedFamily = compatibility.family;
14532
+ const currentLabel = cliFamilyLabel(currentFamily);
14533
+ const expectedLabel = cliFamilyLabel(expectedFamily);
14534
+ const lines = [
14535
+ "",
14536
+ "Command compatibility:",
14537
+ ` \`deepline ${commandName}\` is ${compatibility.label}.`,
14538
+ ` Current binary: ${currentLabel}. Required binary: ${expectedLabel}.`,
14539
+ " If this came from an agent skill, the installed skill likely targets the other Deepline CLI."
14540
+ ];
14541
+ if (currentFamily === "sdk") {
14542
+ lines.push(
14543
+ "",
14544
+ " To stay on the SDK CLI, install the SDK agent skill:",
14545
+ ` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
14546
+ " To use the legacy Python CLI instead:",
14547
+ ` ${legacyPythonInstallCommand(baseUrl)}`,
14548
+ " `deepline update` updates this SDK CLI, but it will not switch CLI families."
14549
+ );
14550
+ if (compatibility.sdk_alternative) {
14551
+ lines.push(` SDK alternative: ${compatibility.sdk_alternative}`);
14552
+ }
14553
+ } else {
14554
+ lines.push(
14555
+ "",
14556
+ " To use SDK commands, install the SDK CLI and SDK agent skill:",
14557
+ ` ${sdkNpmGlobalInstallCommand()}`,
14558
+ ` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
14559
+ " `deepline update` updates this Python CLI and its skills, but it will not switch CLI families."
14560
+ );
14561
+ if (compatibility.python_alternative) {
14562
+ lines.push(` Python alternative: ${compatibility.python_alternative}`);
14563
+ }
14564
+ }
14565
+ return lines.join("\n");
14566
+ }
14567
+ function unknownCommandNameFromMessage(message) {
14568
+ const match = message.match(/unknown command ['"]([^'"]+)['"]/i);
14569
+ const command = match?.[1]?.trim();
14570
+ return command ? command : null;
14571
+ }
14572
+
14113
14573
  // src/cli/skills-sync.ts
14114
14574
  import { spawn as spawn2, spawnSync } from "child_process";
14115
14575
  import {
@@ -14124,7 +14584,6 @@ import { homedir as homedir5 } from "os";
14124
14584
  import { dirname as dirname10, join as join11 } from "path";
14125
14585
  var CHECK_TIMEOUT_MS2 = 3e3;
14126
14586
  var SDK_SKILL_NAME = "deepline-sdk";
14127
- var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
14128
14587
  var attemptedSync = false;
14129
14588
  function shouldSkipSkillsSync() {
14130
14589
  const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
@@ -14221,42 +14680,10 @@ async function fetchSkillsUpdate(baseUrl, localVersion) {
14221
14680
  }
14222
14681
  }
14223
14682
  function buildSkillsInstallArgs(baseUrl) {
14224
- const packageUrl = new URL(
14225
- "/.well-known/skills/index.json",
14226
- baseUrl
14227
- ).toString();
14228
- return [
14229
- "--yes",
14230
- "skills",
14231
- "add",
14232
- packageUrl,
14233
- "--agent",
14234
- ...SKILL_AGENTS,
14235
- "--global",
14236
- "--yes",
14237
- "--skill",
14238
- SDK_SKILL_NAME,
14239
- "--full-depth"
14240
- ];
14683
+ return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME);
14241
14684
  }
14242
14685
  function buildBunxSkillsInstallArgs(baseUrl) {
14243
- const packageUrl = new URL(
14244
- "/.well-known/skills/index.json",
14245
- baseUrl
14246
- ).toString();
14247
- return [
14248
- "--bun",
14249
- "skills",
14250
- "add",
14251
- packageUrl,
14252
- "--agent",
14253
- ...SKILL_AGENTS,
14254
- "--global",
14255
- "--yes",
14256
- "--skill",
14257
- SDK_SKILL_NAME,
14258
- "--full-depth"
14259
- ];
14686
+ return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME, { firstArg: "--bun" });
14260
14687
  }
14261
14688
  function hasCommand(command) {
14262
14689
  const result = spawnSync(command, ["--version"], {
@@ -14368,6 +14795,13 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
14368
14795
  }
14369
14796
 
14370
14797
  // src/cli/index.ts
14798
+ function asCommanderError(error) {
14799
+ if (!(error instanceof Error) || !("code" in error)) {
14800
+ return null;
14801
+ }
14802
+ const code = error.code;
14803
+ return typeof code === "string" && code.startsWith("commander.") ? error : null;
14804
+ }
14371
14805
  function shouldPrintStartupPhase() {
14372
14806
  if (process.argv.includes("--json")) {
14373
14807
  return false;
@@ -14453,7 +14887,7 @@ async function main() {
14453
14887
  progress?.phase("loading deepline cli");
14454
14888
  }
14455
14889
  const program = new Command3();
14456
- program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").showHelpAfterError().showSuggestionAfterError(true).addHelpText(
14890
+ program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").exitOverride().showHelpAfterError().showSuggestionAfterError(true).addHelpText(
14457
14891
  "after",
14458
14892
  `
14459
14893
  Common commands:
@@ -14462,6 +14896,7 @@ Common commands:
14462
14896
  deepline plays search email --json
14463
14897
  deepline plays describe person-linkedin-to-email --json
14464
14898
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
14899
+ deepline secrets check HUBSPOT_TOKEN
14465
14900
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
14466
14901
  deepline update
14467
14902
 
@@ -14511,6 +14946,7 @@ Exit codes:
14511
14946
  registerAuthCommands(program);
14512
14947
  registerToolsCommands(program);
14513
14948
  registerPlayCommands(program);
14949
+ registerSecretsCommands(program);
14514
14950
  registerBillingCommands(program);
14515
14951
  registerOrgCommands(program);
14516
14952
  registerCsvCommands(program);
@@ -14580,6 +15016,7 @@ Examples:
14580
15016
  ok: true
14581
15017
  });
14582
15018
  } catch (error) {
15019
+ const commanderError = asCommanderError(error);
14583
15020
  recordCliTrace({
14584
15021
  phase: "cli.main_total",
14585
15022
  ms: Date.now() - mainStartedAt,
@@ -14587,7 +15024,26 @@ Examples:
14587
15024
  error: error instanceof Error ? error.message : String(error)
14588
15025
  });
14589
15026
  progress?.fail();
14590
- if (process.argv.includes("--json")) {
15027
+ const wantsJson = process.argv.includes("--json");
15028
+ if (commanderError) {
15029
+ if (commanderError.code === "commander.unknownCommand") {
15030
+ const commandName = unknownCommandNameFromMessage(
15031
+ commanderError.message
15032
+ );
15033
+ if (commandName && !wantsJson) {
15034
+ const hint = commandCompatibilityHint(
15035
+ "sdk",
15036
+ commandName,
15037
+ autoDetectBaseUrl()
15038
+ );
15039
+ if (hint) {
15040
+ console.error(hint);
15041
+ }
15042
+ }
15043
+ }
15044
+ process.exitCode = commanderError.code === "commander.unknownCommand" && !wantsJson ? 2 : commanderError.exitCode ?? 1;
15045
+ return;
15046
+ } else if (wantsJson) {
14591
15047
  printJsonError(error);
14592
15048
  } else if (error instanceof Error) {
14593
15049
  console.error(`Error: ${error.message}`);