deepline 0.1.74 → 0.1.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -24,9 +24,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/cli/index.ts
27
- var import_promises5 = require("fs/promises");
28
- var import_node_path17 = require("path");
29
- var import_node_os10 = require("os");
27
+ var import_promises6 = require("fs/promises");
28
+ var import_node_path18 = require("path");
29
+ var import_node_os11 = require("os");
30
30
  var import_commander3 = require("commander");
31
31
 
32
32
  // src/config.ts
@@ -229,10 +229,10 @@ var import_node_path2 = require("path");
229
229
 
230
230
  // src/release.ts
231
231
  var SDK_RELEASE = {
232
- version: "0.1.74",
233
- apiContract: "2026-06-dataset-column-syntax-cutover",
232
+ version: "0.1.76",
233
+ apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
234
234
  supportPolicy: {
235
- latest: "0.1.74",
235
+ latest: "0.1.76",
236
236
  minimumSupported: "0.1.53",
237
237
  deprecatedBelow: "0.1.53"
238
238
  }
@@ -579,7 +579,7 @@ function decodeSseFrame(frame) {
579
579
  return parsed;
580
580
  }
581
581
  function sleep(ms) {
582
- return new Promise((resolve12) => setTimeout(resolve12, ms));
582
+ return new Promise((resolve13) => setTimeout(resolve13, ms));
583
583
  }
584
584
 
585
585
  // src/client.ts
@@ -589,7 +589,7 @@ var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
589
589
  var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
590
590
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
591
591
  function sleep2(ms) {
592
- return new Promise((resolve12) => setTimeout(resolve12, ms));
592
+ return new Promise((resolve13) => setTimeout(resolve13, ms));
593
593
  }
594
594
  function isTransientCompileManifestError(error) {
595
595
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -1115,6 +1115,9 @@ var DeeplineClient = class {
1115
1115
  async checkPlayArtifact(input2) {
1116
1116
  return this.http.post("/api/v2/plays/check", input2);
1117
1117
  }
1118
+ async compileEnrichPlan(input2) {
1119
+ return this.http.post("/api/v2/enrich/compile", input2);
1120
+ }
1118
1121
  async startPlayRunFromBundle(input2) {
1119
1122
  const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
1120
1123
  name: input2.name,
@@ -2397,7 +2400,7 @@ function buildCandidateUrls2(url) {
2397
2400
  }
2398
2401
  }
2399
2402
  function sleep3(ms) {
2400
- return new Promise((resolve12) => setTimeout(resolve12, ms));
2403
+ return new Promise((resolve13) => setTimeout(resolve13, ms));
2401
2404
  }
2402
2405
  function printDeeplineLogo() {
2403
2406
  if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
@@ -3775,38 +3778,38 @@ function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns
3775
3778
  }
3776
3779
  }
3777
3780
  const denominator = nonEmpty + empty;
3778
- const stat3 = {
3781
+ const stat4 = {
3779
3782
  non_empty: percentText(nonEmpty, denominator),
3780
3783
  unique: valueCounts.size
3781
3784
  };
3782
3785
  const rawExecutionStats = executionStats?.columnStats[column];
3783
3786
  if (rawExecutionStats) {
3784
- stat3.execution = formatDatasetExecutionStats(
3787
+ stat4.execution = formatDatasetExecutionStats(
3785
3788
  rawExecutionStats,
3786
3789
  totalRows
3787
3790
  );
3788
3791
  }
3789
3792
  if (sampleValue !== void 0 && sampleValueType) {
3790
- stat3.sample_value = sampleValue;
3791
- stat3.sample_type = sampleValueType;
3793
+ stat4.sample_value = sampleValue;
3794
+ stat4.sample_type = sampleValueType;
3792
3795
  }
3793
3796
  if (valueCounts.size > 0 && valueCounts.size < nonEmpty) {
3794
3797
  const top = [...valueCounts.entries()].sort((left, right) => right[1] - left[1]).slice(0, 3);
3795
3798
  const topKeys = new Set(top.map(([key]) => key));
3796
3799
  const otherCount = [...valueCounts.entries()].filter(([key]) => !topKeys.has(key)).reduce((sum, [, count]) => sum + count, 0);
3797
- stat3.top_values = Object.fromEntries(
3800
+ stat4.top_values = Object.fromEntries(
3798
3801
  top.map(([key, count]) => [key, countPercentText(count, denominator)])
3799
3802
  );
3800
3803
  if (otherCount > 0) {
3801
- stat3.top_values["(other)"] = countPercentText(otherCount, denominator);
3804
+ stat4.top_values["(other)"] = countPercentText(otherCount, denominator);
3802
3805
  }
3803
3806
  if (empty > 0) {
3804
- stat3.top_values["(null)"] = countPercentText(empty, denominator);
3807
+ stat4.top_values["(null)"] = countPercentText(empty, denominator);
3805
3808
  }
3806
3809
  } else if (empty > 0 && nonEmpty > 0) {
3807
- stat3.top_values = { "(null)": countPercentText(empty, denominator) };
3810
+ stat4.top_values = { "(null)": countPercentText(empty, denominator) };
3808
3811
  }
3809
- columnStats[column] = stat3;
3812
+ columnStats[column] = stat4;
3810
3813
  }
3811
3814
  return {
3812
3815
  total_rows: totalRows,
@@ -4230,210 +4233,10 @@ Examples:
4230
4233
  });
4231
4234
  }
4232
4235
 
4233
- // src/cli/commands/feedback.ts
4234
- async function handleFeedback(text, options) {
4235
- const { http } = getAuthedHttpClient();
4236
- const response = await http.post("/api/v2/cli/feedback", {
4237
- text,
4238
- environment: collectLocalEnvInfo(),
4239
- ...options.command ? { command: options.command } : {},
4240
- ...options.payload ? { payload: options.payload } : {}
4241
- });
4242
- printCommandEnvelope(
4243
- {
4244
- ...response,
4245
- render: {
4246
- sections: [
4247
- { title: "feedback", lines: ["Feedback submitted. Thank you."] }
4248
- ]
4249
- }
4250
- },
4251
- { json: options.json }
4252
- );
4253
- }
4254
- function registerFeedbackCommands(program) {
4255
- const feedback = program.command("feedback").description("Submit CLI feedback to Deepline.").addHelpText(
4256
- "after",
4257
- `
4258
- Notes:
4259
- Sends the feedback text plus local CLI environment info to Deepline support.
4260
- Use --command and --payload to attach a reproducible command shape.
4261
-
4262
- Examples:
4263
- deepline feedback "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
4264
- deepline feedback "unexpected billing output" --payload '{"command":"billing usage"}' --json
4265
- `
4266
- );
4267
- feedback.argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
4268
- program.command("provide-feedback").description("Legacy alias for `deepline feedback`.").addHelpText(
4269
- "after",
4270
- `
4271
- Notes:
4272
- Compatibility alias. Prefer deepline feedback in new scripts and docs.
4273
-
4274
- Examples:
4275
- deepline feedback "tools search returned stale results" --json
4276
- `
4277
- ).argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
4278
- }
4279
-
4280
- // src/cli/commands/org.ts
4281
- async function fetchOrganizations(http, apiKey) {
4282
- return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
4283
- }
4284
- function orgListLines(orgs) {
4285
- return orgs.map((org, index) => {
4286
- const current = org.is_current ? " (current)" : "";
4287
- const role = org.role ? ` [${org.role}]` : "";
4288
- return `${index + 1}. ${org.name}${role}${current}`;
4289
- });
4290
- }
4291
- async function handleOrgList(options) {
4292
- const config = resolveConfig();
4293
- const http = new HttpClient(config);
4294
- const payload = await fetchOrganizations(http, config.apiKey);
4295
- printCommandEnvelope(
4296
- {
4297
- ...payload,
4298
- render: {
4299
- sections: [
4300
- {
4301
- title: "Your organizations:",
4302
- lines: orgListLines(payload.organizations)
4303
- }
4304
- ]
4305
- }
4306
- },
4307
- { json: options.json }
4308
- );
4309
- }
4310
- async function handleOrgSwitch(selection, options) {
4311
- const config = resolveConfig();
4312
- const http = new HttpClient(config);
4313
- const payload = await fetchOrganizations(http, config.apiKey);
4314
- if (!selection && !options.orgId) {
4315
- printCommandEnvelope(
4316
- {
4317
- ...payload,
4318
- next: { switch: "deepline org switch <number>" },
4319
- render: {
4320
- sections: [
4321
- {
4322
- title: "Your organizations:",
4323
- lines: orgListLines(payload.organizations)
4324
- }
4325
- ],
4326
- actions: [{ label: "Run", command: "deepline org switch <number>" }]
4327
- }
4328
- },
4329
- { json: options.json }
4330
- );
4331
- return;
4332
- }
4333
- let target = payload.organizations.find(
4334
- (org) => org.org_id === options.orgId
4335
- );
4336
- if (!target && selection) {
4337
- const index = Number.parseInt(selection, 10);
4338
- if (Number.isFinite(index) && index >= 1 && index <= payload.organizations.length) {
4339
- target = payload.organizations[index - 1];
4340
- } else {
4341
- target = payload.organizations.find(
4342
- (org) => org.name === selection || org.org_id === selection
4343
- );
4344
- }
4345
- }
4346
- if (!target) {
4347
- throw new Error("Could not resolve the selected organization.");
4348
- }
4349
- if (target.is_current) {
4350
- printCommandEnvelope(
4351
- {
4352
- ok: true,
4353
- unchanged: true,
4354
- organization: target,
4355
- render: {
4356
- sections: [
4357
- { title: "org switch", lines: [`Already on ${target.name}.`] }
4358
- ]
4359
- }
4360
- },
4361
- { json: options.json }
4362
- );
4363
- return;
4364
- }
4365
- const switched = await http.post("/api/v2/auth/cli/switch", {
4366
- api_key: config.apiKey,
4367
- org_id: target.org_id
4368
- });
4369
- saveHostEnvValues(config.baseUrl, {
4370
- DEEPLINE_API_KEY: switched.api_key,
4371
- DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
4372
- DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
4373
- });
4374
- const { api_key: _apiKey, ...publicSwitched } = switched;
4375
- printCommandEnvelope(
4376
- {
4377
- ok: true,
4378
- host_env_path: hostEnvFilePath(config.baseUrl),
4379
- ...publicSwitched,
4380
- api_key_saved: true,
4381
- render: {
4382
- sections: [
4383
- {
4384
- title: "org switch",
4385
- lines: [
4386
- `Switched to ${switched.org_name}.`,
4387
- `Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
4388
- ]
4389
- }
4390
- ]
4391
- }
4392
- },
4393
- { json: options.json }
4394
- );
4395
- }
4396
- function registerOrgCommands(program) {
4397
- const org = program.command("org").description("List and switch organizations.").addHelpText(
4398
- "after",
4399
- `
4400
- Notes:
4401
- Organizations are workspaces. Switching organizations mutates the saved host
4402
- auth file so later CLI commands target the selected workspace.
4403
-
4404
- Examples:
4405
- deepline org list --json
4406
- deepline org switch 2
4407
- deepline org switch --org-id org_123 --json
4408
- `
4409
- );
4410
- org.command("list").description("List your organizations.").addHelpText(
4411
- "after",
4412
- `
4413
- Notes:
4414
- Read-only. Marks the active organization when the server returns that metadata.
4415
-
4416
- Examples:
4417
- deepline org list
4418
- deepline org list --json
4419
- `
4420
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgList);
4421
- org.command("switch [selection]").description(
4422
- "Switch to another organization and save the new API key in the host auth file."
4423
- ).addHelpText(
4424
- "after",
4425
- `
4426
- Notes:
4427
- Mutates the saved host auth file. Selection can be a list number, exact
4428
- organization name, or organization id. Without a selection, prints choices.
4429
-
4430
- Examples:
4431
- deepline org switch
4432
- deepline org switch 2
4433
- deepline org switch --org-id org_123 --json
4434
- `
4435
- ).option("--org-id <id>", "Switch using an explicit organization id").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgSwitch);
4436
- }
4236
+ // src/cli/commands/enrich.ts
4237
+ var import_promises5 = require("fs/promises");
4238
+ var import_node_os7 = require("os");
4239
+ var import_node_path13 = require("path");
4437
4240
 
4438
4241
  // src/cli/commands/play.ts
4439
4242
  var import_node_crypto3 = require("crypto");
@@ -6718,54 +6521,54 @@ function exampleValueComment(field) {
6718
6521
  if (field === "roles" || field.endsWith("s")) return '["..."]';
6719
6522
  return '"..."';
6720
6523
  }
6721
- function generateContactInputObjectFromSchema(schema, indent, label, fallbackFields = ["first_name", "last_name", "domain"]) {
6524
+ function generateContactInputObjectFromSchema(schema, indent2, label, fallbackFields = ["first_name", "last_name", "domain"]) {
6722
6525
  const details = schemaFieldDetails(schema);
6723
6526
  const required = details.required.length ? details.required : fallbackFields;
6724
6527
  const optional = details.optional;
6725
6528
  const lines = [
6726
- `${indent}// TODO: map row fields into ${label}.`,
6727
- ...playInspectionComments(label, indent),
6728
- `${indent}// Required: ${required.join(", ") || "none declared"}.`
6529
+ `${indent2}// TODO: map row fields into ${label}.`,
6530
+ ...playInspectionComments(label, indent2),
6531
+ `${indent2}// Required: ${required.join(", ") || "none declared"}.`
6729
6532
  ];
6730
6533
  for (const field of required) {
6731
- lines.push(`${indent}// ${field}: row["TODO_SOURCE_FIELD"],`);
6534
+ lines.push(`${indent2}// ${field}: row["TODO_SOURCE_FIELD"],`);
6732
6535
  }
6733
6536
  if (optional.length > 0) {
6734
6537
  lines.push("");
6735
- lines.push(`${indent}// optional (delete unused):`);
6538
+ lines.push(`${indent2}// optional (delete unused):`);
6736
6539
  for (const field of optional) {
6737
- lines.push(`${indent}// ${field}: row["TODO_SOURCE_FIELD"],`);
6540
+ lines.push(`${indent2}// ${field}: row["TODO_SOURCE_FIELD"],`);
6738
6541
  }
6739
6542
  }
6740
6543
  return `{
6741
6544
  ${lines.join("\n")}
6742
- ${indent.slice(2)}}`;
6545
+ ${indent2.slice(2)}}`;
6743
6546
  }
6744
- function generateCompanyInputObjectFromSchema(schema, indent, label, fallbackFields = ["domain", "company_name"]) {
6547
+ function generateCompanyInputObjectFromSchema(schema, indent2, label, fallbackFields = ["domain", "company_name"]) {
6745
6548
  const details = schemaFieldDetails(schema);
6746
6549
  const required = details.required.length ? details.required : fallbackFields;
6747
6550
  const optional = details.optional;
6748
6551
  const lines = [
6749
- `${indent}// TODO: map company fields into ${label}.`,
6750
- ...playInspectionComments(label, indent),
6751
- `${indent}// Required: ${required.join(", ") || "none declared"}.`
6552
+ `${indent2}// TODO: map company fields into ${label}.`,
6553
+ ...playInspectionComments(label, indent2),
6554
+ `${indent2}// Required: ${required.join(", ") || "none declared"}.`
6752
6555
  ];
6753
6556
  for (const field of required) {
6754
- lines.push(`${indent}// ${field}: company["TODO_SOURCE_FIELD"],`);
6557
+ lines.push(`${indent2}// ${field}: company["TODO_SOURCE_FIELD"],`);
6755
6558
  }
6756
6559
  if (optional.length > 0) {
6757
6560
  lines.push("");
6758
- lines.push(`${indent}// optional (delete unused):`);
6561
+ lines.push(`${indent2}// optional (delete unused):`);
6759
6562
  for (const field of optional) {
6760
- lines.push(`${indent}// ${field}: company["TODO_SOURCE_FIELD"],`);
6563
+ lines.push(`${indent2}// ${field}: company["TODO_SOURCE_FIELD"],`);
6761
6564
  }
6762
6565
  }
6763
6566
  return `{
6764
6567
  ${lines.join("\n")}
6765
- ${indent.slice(2)}}`;
6568
+ ${indent2.slice(2)}}`;
6766
6569
  }
6767
6570
  function generateSourceProviderInputObject(input2) {
6768
- const { tool, indent, label, entity } = input2;
6571
+ const { tool, indent: indent2, label, entity } = input2;
6769
6572
  const properties = inputPropertyNames(tool?.inputSchema);
6770
6573
  const details = schemaFieldDetails(tool?.inputSchema);
6771
6574
  const required = details.required;
@@ -6786,18 +6589,18 @@ function generateSourceProviderInputObject(input2) {
6786
6589
  ].includes(field)
6787
6590
  );
6788
6591
  const lines = [
6789
- `${indent}// TODO: fill ${entity} source inputs for ${label}.`,
6790
- `${indent}// Inspect: deepline tools describe ${label} --json`
6592
+ `${indent2}// TODO: fill ${entity} source inputs for ${label}.`,
6593
+ `${indent2}// Inspect: deepline tools describe ${label} --json`
6791
6594
  ];
6792
6595
  for (const field of required) {
6793
- lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
6596
+ lines.push(`${indent2}// ${field}: ${exampleValueComment(field)},`);
6794
6597
  }
6795
6598
  const activeTodoField = required.length === 0 ? ["query", "q", "search", "title", "role", "persona"].find(
6796
6599
  (field) => includeOptional.includes(field)
6797
6600
  ) ?? "query" : null;
6798
6601
  if (activeTodoField) {
6799
6602
  lines.push(
6800
- `${indent}// ${activeTodoField}: ${exampleValueComment(activeTodoField)},`
6603
+ `${indent2}// ${activeTodoField}: ${exampleValueComment(activeTodoField)},`
6801
6604
  );
6802
6605
  }
6803
6606
  const optionalExamples = includeOptional.filter(
@@ -6805,40 +6608,40 @@ function generateSourceProviderInputObject(input2) {
6805
6608
  );
6806
6609
  if (optionalExamples.length > 0) {
6807
6610
  lines.push("");
6808
- lines.push(`${indent}// optional - uncomment what this provider supports:`);
6611
+ lines.push(`${indent2}// optional - uncomment what this provider supports:`);
6809
6612
  for (const field of optionalExamples) {
6810
6613
  if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size") {
6811
- lines.push(`${indent}// ${field}: limit,`);
6614
+ lines.push(`${indent2}// ${field}: limit,`);
6812
6615
  } else {
6813
- lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
6616
+ lines.push(`${indent2}// ${field}: ${exampleValueComment(field)},`);
6814
6617
  }
6815
6618
  }
6816
6619
  }
6817
6620
  if (!required.some(
6818
6621
  (field) => ["limit", "numResults", "num_results", "page_size"].includes(field)
6819
6622
  )) {
6820
- lines.push(`${indent}limit,`);
6623
+ lines.push(`${indent2}limit,`);
6821
6624
  }
6822
6625
  return `{
6823
6626
  ${lines.join("\n")}
6824
- ${indent.slice(2)}}`;
6627
+ ${indent2.slice(2)}}`;
6825
6628
  }
6826
6629
  function generatePlayInputObject(input2) {
6827
- const { schema, indent, label, entity } = input2;
6630
+ const { schema, indent: indent2, label, entity } = input2;
6828
6631
  const details = schemaFieldDetails(schema);
6829
6632
  const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
6830
6633
  const required = details.required.length ? details.required : fallback;
6831
6634
  const lines = [
6832
- `${indent}// TODO: fill source play inputs for ${label}.`,
6833
- ...playInspectionComments(label, indent)
6635
+ `${indent2}// TODO: fill source play inputs for ${label}.`,
6636
+ ...playInspectionComments(label, indent2)
6834
6637
  ];
6835
6638
  for (const field of required) {
6836
- lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
6639
+ lines.push(`${indent2}// ${field}: ${exampleValueComment(field)},`);
6837
6640
  }
6838
- if (!required.includes("limit")) lines.push(`${indent}limit,`);
6641
+ if (!required.includes("limit")) lines.push(`${indent2}limit,`);
6839
6642
  return `{
6840
6643
  ${lines.join("\n")}
6841
- ${indent.slice(2)}}`;
6644
+ ${indent2.slice(2)}}`;
6842
6645
  }
6843
6646
  function requiredPlayInputFields(play) {
6844
6647
  const schema = play?.inputSchema;
@@ -6879,8 +6682,8 @@ function finderProviderStepPrefix(finder) {
6879
6682
  function safeIdentifier(value) {
6880
6683
  return value.replace(/[^A-Za-z0-9_]+/g, "_");
6881
6684
  }
6882
- function playInspectionComments(playRef, indent) {
6883
- return [`${indent}// Inspect: deepline plays describe ${playRef} --json`];
6685
+ function playInspectionComments(playRef, indent2) {
6686
+ return [`${indent2}// Inspect: deepline plays describe ${playRef} --json`];
6884
6687
  }
6885
6688
  function accessorExpression(base, field) {
6886
6689
  return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(field) ? `${base}.${field}` : `${base}[${jsString(field)}]`;
@@ -7979,7 +7782,7 @@ function traceCliSync(phase, fields, run) {
7979
7782
  }
7980
7783
  }
7981
7784
  function sleep4(ms) {
7982
- return new Promise((resolve12) => setTimeout(resolve12, ms));
7785
+ return new Promise((resolve13) => setTimeout(resolve13, ms));
7983
7786
  }
7984
7787
  function parseReferencedPlayTarget2(target) {
7985
7788
  const trimmed = target.trim();
@@ -9622,20 +9425,20 @@ function attachDatasetStatsToResult(result, datasetStats) {
9622
9425
  };
9623
9426
  return attach(result, "");
9624
9427
  }
9625
- function formatDatasetStatsLines(datasetStats, indent = " ") {
9428
+ function formatDatasetStatsLines(datasetStats, indent2 = " ") {
9626
9429
  if (!datasetStats) {
9627
9430
  return [];
9628
9431
  }
9629
- const lines = [`${indent}summary:`];
9630
- for (const [column, stat3] of Object.entries(datasetStats.columnStats).slice(
9432
+ const lines = [`${indent2}summary:`];
9433
+ for (const [column, stat4] of Object.entries(datasetStats.columnStats).slice(
9631
9434
  0,
9632
9435
  12
9633
9436
  )) {
9634
- const topValues = stat3.top_values ? `, top_values=${Object.entries(stat3.top_values).slice(0, 3).map(([value, count]) => `${value}=${count}`).join(", ")}` : "";
9635
- const sample = stat3.sample_value !== void 0 ? `, sample_value=${JSON.stringify(stat3.sample_value)}` : "";
9636
- const execution = stat3.execution ? `, execution=${Object.entries(stat3.execution).map(([bucket, count]) => `${bucket}=${count}`).join(", ")}` : "";
9437
+ const topValues = stat4.top_values ? `, top_values=${Object.entries(stat4.top_values).slice(0, 3).map(([value, count]) => `${value}=${count}`).join(", ")}` : "";
9438
+ const sample = stat4.sample_value !== void 0 ? `, sample_value=${JSON.stringify(stat4.sample_value)}` : "";
9439
+ const execution = stat4.execution ? `, execution=${Object.entries(stat4.execution).map(([bucket, count]) => `${bucket}=${count}`).join(", ")}` : "";
9637
9440
  lines.push(
9638
- `${indent} ${column}: non_empty=${stat3.non_empty}, unique=${stat3.unique}${topValues}${sample}${execution}`
9441
+ `${indent2} ${column}: non_empty=${stat4.non_empty}, unique=${stat4.unique}${topValues}${sample}${execution}`
9639
9442
  );
9640
9443
  }
9641
9444
  return lines;
@@ -9676,7 +9479,7 @@ function formatSummaryScalarParts(record, skipKeys = /* @__PURE__ */ new Set())
9676
9479
  }
9677
9480
  return parts;
9678
9481
  }
9679
- function formatPackageDatasetSummaryLines(summary, indent = " ") {
9482
+ function formatPackageDatasetSummaryLines(summary, indent2 = " ") {
9680
9483
  const record = readRecord(summary);
9681
9484
  const columnStats = readRecord(record?.columnStats);
9682
9485
  if (!record || !columnStats) {
@@ -9685,7 +9488,7 @@ function formatPackageDatasetSummaryLines(summary, indent = " ") {
9685
9488
  const lines = [];
9686
9489
  const parts = formatSummaryScalarParts(record, /* @__PURE__ */ new Set(["columnStats"]));
9687
9490
  if (parts.length > 0) {
9688
- lines.push(`${indent}summary: ${parts.join(" ")}`);
9491
+ lines.push(`${indent2}summary: ${parts.join(" ")}`);
9689
9492
  }
9690
9493
  for (const [column, rawColumnSummary] of Object.entries(columnStats)) {
9691
9494
  const columnSummary = readRecord(rawColumnSummary);
@@ -9697,7 +9500,7 @@ function formatPackageDatasetSummaryLines(summary, indent = " ") {
9697
9500
  executionText ? `execution=${executionText}` : null
9698
9501
  ].filter(Boolean);
9699
9502
  if (columnParts.length > 0) {
9700
- lines.push(`${indent} ${column}: ${columnParts.join(" ")}`);
9503
+ lines.push(`${indent2} ${column}: ${columnParts.join(" ")}`);
9701
9504
  }
9702
9505
  }
9703
9506
  return lines;
@@ -11907,9 +11710,11 @@ Idempotent execution:
11907
11710
  .run({ key: 'domain' });
11908
11711
 
11909
11712
  Reuse needs the same play, tool id, dataset name, row key, and compatible logic.
11910
- To refresh, change the id/dataset key or set staleAfterSeconds:
11713
+ To recompute a visible cell on a later cron/user run after a window, put
11714
+ staleAfterSeconds on the cell-producing column:
11911
11715
 
11912
- .run({ key: 'domain', staleAfterSeconds: 86400 })
11716
+ .withColumn('cto', resolver, { staleAfterSeconds: 86400 })
11717
+ .run({ key: 'domain' })
11913
11718
 
11914
11719
  Examples:
11915
11720
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
@@ -12438,7 +12243,9 @@ async function handlePlayShareStatus(args) {
12438
12243
  );
12439
12244
  return 0;
12440
12245
  }
12441
- console.log(`${status.playName}: published v${status.share.publishedVersion}`);
12246
+ console.log(
12247
+ `${status.playName}: published v${status.share.publishedVersion}`
12248
+ );
12442
12249
  console.log(` url: ${status.share.publicPath}`);
12443
12250
  console.log(` seo: ${status.share.seoIndexing}`);
12444
12251
  console.log(
@@ -12600,7 +12407,9 @@ async function handlePlayShareRegenerate(args) {
12600
12407
  async function handlePlayShareUnpublish(args) {
12601
12408
  const target = args[0];
12602
12409
  if (!target) {
12603
- console.error("Usage: deepline plays share unpublish <play> --yes [--json]");
12410
+ console.error(
12411
+ "Usage: deepline plays share unpublish <play> --yes [--json]"
12412
+ );
12604
12413
  return 2;
12605
12414
  }
12606
12415
  if (!args.includes("--yes")) {
@@ -12620,49 +12429,1190 @@ async function handlePlayShareUnpublish(args) {
12620
12429
  return 0;
12621
12430
  }
12622
12431
 
12623
- // src/cli/commands/secrets.ts
12624
- var import_node_process = require("process");
12625
- var hiddenInputBuffer = "";
12626
- function normalizeSecretName(value) {
12627
- const normalized = value.trim().toUpperCase();
12628
- if (!/^[A-Z][A-Z0-9_]{1,63}$/.test(normalized)) {
12629
- throw new Error(
12630
- "Secret names must be 2-64 characters and use uppercase letters, numbers, and underscores."
12631
- );
12432
+ // src/cli/enrich-play-compiler.ts
12433
+ var RESERVED_WORDS = /* @__PURE__ */ new Set([
12434
+ "break",
12435
+ "case",
12436
+ "catch",
12437
+ "class",
12438
+ "const",
12439
+ "continue",
12440
+ "debugger",
12441
+ "default",
12442
+ "delete",
12443
+ "do",
12444
+ "else",
12445
+ "export",
12446
+ "extends",
12447
+ "finally",
12448
+ "for",
12449
+ "function",
12450
+ "if",
12451
+ "import",
12452
+ "in",
12453
+ "instanceof",
12454
+ "new",
12455
+ "return",
12456
+ "super",
12457
+ "switch",
12458
+ "this",
12459
+ "throw",
12460
+ "try",
12461
+ "typeof",
12462
+ "var",
12463
+ "void",
12464
+ "while",
12465
+ "with",
12466
+ "yield"
12467
+ ]);
12468
+ function isWaterfall(command) {
12469
+ return "with_waterfall" in command;
12470
+ }
12471
+ function safeIdentifier2(value, fallback) {
12472
+ const cleaned = value.replace(/[^A-Za-z0-9_$]/g, "_");
12473
+ const prefixed = /^[A-Za-z_$]/.test(cleaned) ? cleaned : `_${cleaned}`;
12474
+ if (!prefixed || RESERVED_WORDS.has(prefixed)) {
12475
+ return fallback;
12632
12476
  }
12633
- return normalized;
12477
+ return prefixed;
12634
12478
  }
12635
- function renderSecret(secret) {
12636
- const scope = secret.scope === "play" && secret.playName ? `play:${secret.playName}` : secret.scope;
12637
- return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}`;
12479
+ function stringLiteral(value) {
12480
+ return JSON.stringify(value);
12638
12481
  }
12639
- async function readHiddenLine(prompt) {
12640
- if (!import_node_process.stdin.isTTY || !import_node_process.stdout.isTTY) {
12641
- throw new Error(
12642
- "Secret values must be entered from an interactive TTY. Do not pipe, pass, or script secret values."
12482
+ function stableJson(value) {
12483
+ if (Array.isArray(value)) {
12484
+ return `[${value.map(stableJson).join(",")}]`;
12485
+ }
12486
+ if (value && typeof value === "object") {
12487
+ const entries = Object.entries(value).sort(
12488
+ ([left], [right]) => left.localeCompare(right)
12643
12489
  );
12490
+ return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`).join(",")}}`;
12644
12491
  }
12645
- import_node_process.stdout.write(prompt);
12646
- const previousRawMode = import_node_process.stdin.isRaw;
12647
- if (typeof import_node_process.stdin.setRawMode === "function") import_node_process.stdin.setRawMode(true);
12648
- let value = "";
12649
- import_node_process.stdin.resume();
12650
- return await new Promise((resolve12, reject) => {
12651
- let settled = false;
12652
- const cleanup = () => {
12653
- import_node_process.stdin.off("data", onData);
12654
- import_node_process.stdin.off("end", onEnd);
12655
- import_node_process.stdin.off("error", onError);
12656
- if (typeof import_node_process.stdin.setRawMode === "function") {
12657
- import_node_process.stdin.setRawMode(previousRawMode);
12658
- }
12659
- };
12660
- const finish = (line) => {
12661
- if (settled) return;
12662
- settled = true;
12663
- import_node_process.stdout.write("\n");
12492
+ return JSON.stringify(value);
12493
+ }
12494
+ function indent(source, spaces) {
12495
+ const pad = " ".repeat(spaces);
12496
+ return source.split("\n").map((line) => line ? `${pad}${line}` : line).join("\n");
12497
+ }
12498
+ function commandCallId(command) {
12499
+ return `${command.alias}__${command.tool}`;
12500
+ }
12501
+ function normalizeAlias(value) {
12502
+ return value.toLowerCase().replace(/[^a-z0-9]/g, "");
12503
+ }
12504
+ function renderExecuteStep(command, options = { force: false }) {
12505
+ const alias = stringLiteral(command.alias);
12506
+ const callId = stringLiteral(commandCallId(command));
12507
+ const tool = stringLiteral(command.tool);
12508
+ const payload = stableJson(command.payload ?? {});
12509
+ const extractJs = command.extract_js ? `({ row, result, data, raw, pick, extract, target }) => { const input = row; const context = row;
12510
+ ${indent(renderJavascriptBody(command.extract_js), 6)}
12511
+ }` : "null";
12512
+ const runIfJs = command.run_if_js ? `(row) => { const input = row; const context = row;
12513
+ ${indent(renderJavascriptBody(command.run_if_js), 6)}
12514
+ }` : "null";
12515
+ const description = command.description ? `,
12516
+ description: ${stringLiteral(command.description)}` : "";
12517
+ const force = options.force ? `,
12518
+ force: true` : "";
12519
+ return [
12520
+ `async (row, stepCtx) => {`,
12521
+ ...options.precheck ? [` if (${options.precheck}) return null;`] : [],
12522
+ ` return __dlRunCommand({`,
12523
+ ` alias: ${alias},`,
12524
+ ` callId: ${callId},`,
12525
+ ` tool: ${tool},`,
12526
+ ` payload: ${payload},`,
12527
+ ` extract: ${extractJs},`,
12528
+ ` runIf: ${runIfJs},`,
12529
+ ` row,`,
12530
+ ` stepCtx${description}${force}`,
12531
+ ` });`,
12532
+ `}`
12533
+ ].join("\n");
12534
+ }
12535
+ function renderJavascriptBody(source) {
12536
+ const trimmed = source.trim();
12537
+ if (trimmed && !trimmed.includes("\n") && !trimmed.includes(";") && !/\breturn\b/.test(trimmed)) {
12538
+ return `return (${trimmed});`;
12539
+ }
12540
+ return source;
12541
+ }
12542
+ function renderWaterfallProgram(command, index, forceAliases) {
12543
+ const variableName = safeIdentifier2(
12544
+ `${command.with_waterfall}_${index}_waterfall`,
12545
+ `waterfall_${index}`
12546
+ );
12547
+ const stepLines = command.commands.map((nested, stepIndex) => {
12548
+ if (isWaterfall(nested)) {
12549
+ throw new Error("Nested with_waterfall blocks are not supported.");
12550
+ }
12551
+ if (nested.disabled) {
12552
+ return null;
12553
+ }
12554
+ const priorAliases = command.commands.slice(0, stepIndex).filter((prior) => !isWaterfall(prior)).filter((prior) => !prior.disabled).map((prior) => prior.alias);
12555
+ const minResults = typeof command.min_results === "number" ? Math.max(1, Math.trunc(command.min_results)) : 1;
12556
+ return [
12557
+ ` .step(${stringLiteral(nested.alias)},`,
12558
+ indent(
12559
+ renderExecuteStep(nested, {
12560
+ force: forceAliases.has(normalizeAlias(nested.alias)),
12561
+ precheck: priorAliases.length > 0 ? `__dlWaterfallSatisfied(row, ${stableJson(priorAliases)}, ${minResults})` : void 0
12562
+ }),
12563
+ 4
12564
+ ),
12565
+ ` )`
12566
+ ].join("\n");
12567
+ }).filter((line) => line !== null);
12568
+ const aliases = command.commands.filter((nested) => !isWaterfall(nested)).filter((nested) => !nested.disabled).map((nested) => nested.alias);
12569
+ const returnExpr = typeof command.min_results === "number" ? `__dlFirstMinResults(row, ${stableJson(aliases)}, ${Math.max(
12570
+ 1,
12571
+ Math.trunc(command.min_results)
12572
+ )})` : `__dlFirstMeaningful(row, ${stableJson(aliases)})`;
12573
+ return {
12574
+ variableName,
12575
+ hasSteps: stepLines.length > 0,
12576
+ source: [
12577
+ `const ${variableName} = steps<Record<string, unknown>>()`,
12578
+ ...stepLines,
12579
+ ` .return((row) => ${returnExpr});`
12580
+ ].join("\n")
12581
+ };
12582
+ }
12583
+ function compileEnrichConfigToPlaySource(config, options = {}) {
12584
+ const playName = options.playName ?? "deepline-enrich-v1-compat";
12585
+ const mapName = options.mapName ?? "deepline_enrich_rows";
12586
+ const forceAliases = new Set(
12587
+ [...options.forceAliases ?? []].map((alias) => normalizeAlias(alias))
12588
+ );
12589
+ const waterfalls = [];
12590
+ const mapSteps = [];
12591
+ config.commands.forEach((command, index) => {
12592
+ if (isWaterfall(command)) {
12593
+ const rendered = renderWaterfallProgram(command, index, forceAliases);
12594
+ if (!rendered.hasSteps) {
12595
+ return;
12596
+ }
12597
+ waterfalls.push({
12598
+ alias: command.with_waterfall,
12599
+ variableName: rendered.variableName,
12600
+ source: rendered.source
12601
+ });
12602
+ mapSteps.push(
12603
+ ` .step(${stringLiteral(command.with_waterfall)}, ${rendered.variableName})`
12604
+ );
12605
+ return;
12606
+ }
12607
+ if (command.disabled) {
12608
+ return;
12609
+ }
12610
+ mapSteps.push(
12611
+ [
12612
+ ` .step(${stringLiteral(command.alias)},`,
12613
+ indent(
12614
+ renderExecuteStep(command, {
12615
+ force: forceAliases.has(normalizeAlias(command.alias))
12616
+ }),
12617
+ 8
12618
+ ),
12619
+ ` )`
12620
+ ].join("\n")
12621
+ );
12622
+ });
12623
+ const waterfallSource = waterfalls.map((entry) => indent(entry.source, 4));
12624
+ const mapStepSource = mapSteps.length > 0 ? mapSteps.join("\n") : ` .step('noop', (row) => row)`;
12625
+ return [
12626
+ `import { definePlay, steps } from 'deepline';`,
12627
+ ``,
12628
+ `type EnrichInput = { file: string; rowStart?: number | null; rowEnd?: number | null };`,
12629
+ ``,
12630
+ helperSource(),
12631
+ ``,
12632
+ `export default definePlay(${stringLiteral(playName)}, async (ctx, input: EnrichInput) => {`,
12633
+ ` const allRows = await ctx.csv<Record<string, unknown>>(input.file);`,
12634
+ ` const rowStart = Number.isFinite(input.rowStart) ? Math.max(0, Math.trunc(Number(input.rowStart))) : 0;`,
12635
+ ` const rowEnd = Number.isFinite(input.rowEnd) ? Math.max(rowStart, Math.trunc(Number(input.rowEnd))) : allRows.length;`,
12636
+ ` const rows = allRows.slice(rowStart, rowEnd);`,
12637
+ ...waterfallSource,
12638
+ ` const enriched = await ctx`,
12639
+ ` .map(${stringLiteral(mapName)}, rows)`,
12640
+ mapStepSource,
12641
+ ` .run({ key: (row, index) => __dlStableRowKey(row, index + rowStart) });`,
12642
+ ` return { rows: enriched, count: await enriched.count() };`,
12643
+ `});`,
12644
+ ``
12645
+ ].join("\n");
12646
+ }
12647
+ function helperSource() {
12648
+ return [
12649
+ `function __dlGetByPath(root: unknown, path: string): unknown {`,
12650
+ ` return String(path || '')`,
12651
+ ` .replace(/\\[(\\d+)\\]/g, '.$1')`,
12652
+ ` .split('.')`,
12653
+ ` .map((part) => part.trim())`,
12654
+ ` .filter(Boolean)`,
12655
+ ` .reduce((cursor: unknown, part: string) => {`,
12656
+ ` if (!cursor || typeof cursor !== 'object') return undefined;`,
12657
+ ` const record = cursor as Record<string, unknown>;`,
12658
+ ` if (part in record) return record[part];`,
12659
+ ` const data = record.data;`,
12660
+ ` return data && typeof data === 'object' ? (data as Record<string, unknown>)[part] : undefined;`,
12661
+ ` }, root);`,
12662
+ `}`,
12663
+ ``,
12664
+ `function __dlMeaningful(value: unknown): boolean {`,
12665
+ ` return value !== null && value !== undefined && !(typeof value === 'string' && value.trim() === '') && !(Array.isArray(value) && value.length === 0);`,
12666
+ `}`,
12667
+ ``,
12668
+ `function __dlRawToolOutput(result: unknown): unknown {`,
12669
+ ` if (!result || typeof result !== 'object') return result;`,
12670
+ ` const record = result as Record<string, unknown>;`,
12671
+ ` return __dlGetByPath(record, 'toolOutput.raw') ?? __dlGetByPath(record, 'toolResponse.raw') ?? record.result ?? record.output ?? result;`,
12672
+ `}`,
12673
+ ``,
12674
+ `function __dlTemplate(value: unknown, row: Record<string, unknown>): unknown {`,
12675
+ ` if (Array.isArray(value)) return value.map((entry) => __dlTemplate(entry, row));`,
12676
+ ` if (value && typeof value === 'object') {`,
12677
+ ` return Object.fromEntries(Object.entries(value as Record<string, unknown>).map(([key, entry]) => [key, __dlTemplate(entry, row)]));`,
12678
+ ` }`,
12679
+ ` if (typeof value !== 'string') return value;`,
12680
+ ` const exact = value.match(/^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$/);`,
12681
+ ` if (exact) return __dlGetByPath(row, exact[1] || '');`,
12682
+ ` return value.replace(/\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g, (_match, path) => {`,
12683
+ ` const replacement = __dlGetByPath(row, String(path || ''));`,
12684
+ ` return replacement === null || replacement === undefined ? '' : String(replacement);`,
12685
+ ` });`,
12686
+ `}`,
12687
+ ``,
12688
+ `function __dlStableRowKey(row: Record<string, unknown>, index: number): string {`,
12689
+ ` for (const key of ['id', 'ID', 'email', 'Email', 'linkedin_url', 'LINKEDIN_URL', 'domain', 'DOMAIN']) {`,
12690
+ ` const value = row[key];`,
12691
+ ` if (__dlMeaningful(value)) return String(value);`,
12692
+ ` }`,
12693
+ ` return String(index);`,
12694
+ `}`,
12695
+ ``,
12696
+ `function __dlFirstMeaningful(row: Record<string, unknown>, aliases: string[]): unknown {`,
12697
+ ` for (const alias of aliases) {`,
12698
+ ` const value = row[alias];`,
12699
+ ` if (__dlMeaningful(value)) return value;`,
12700
+ ` }`,
12701
+ ` return null;`,
12702
+ `}`,
12703
+ ``,
12704
+ `function __dlFirstMinResults(row: Record<string, unknown>, aliases: string[], minResults: number): unknown {`,
12705
+ ` const values: unknown[] = [];`,
12706
+ ` for (const alias of aliases) {`,
12707
+ ` const value = row[alias];`,
12708
+ ` if (Array.isArray(value)) values.push(...value.filter(__dlMeaningful));`,
12709
+ ` else if (__dlMeaningful(value)) values.push(value);`,
12710
+ ` if (values.length >= minResults) return values.slice(0, minResults);`,
12711
+ ` }`,
12712
+ ` return values.length > 0 ? values : null;`,
12713
+ `}`,
12714
+ ``,
12715
+ `function __dlWaterfallSatisfied(row: Record<string, unknown>, aliases: string[], minResults: number): boolean {`,
12716
+ ` let count = 0;`,
12717
+ ` for (const alias of aliases) {`,
12718
+ ` const value = row[alias];`,
12719
+ ` if (Array.isArray(value)) count += value.filter(__dlMeaningful).length;`,
12720
+ ` else if (__dlMeaningful(value)) count += 1;`,
12721
+ ` if (count >= Math.max(1, Math.trunc(minResults))) return true;`,
12722
+ ` }`,
12723
+ ` return false;`,
12724
+ `}`,
12725
+ ``,
12726
+ `function __dlExtract(alias: string, result: unknown, row: Record<string, unknown>, extractor: ((args: { row: Record<string, unknown>; result: unknown; data: unknown; raw: unknown; pick: (paths: string[] | string) => unknown; extract: (paths: string[] | string) => unknown; target: (paths: string[] | string) => unknown }) => unknown) | null): unknown {`,
12727
+ ` const raw = __dlRawToolOutput(result);`,
12728
+ ` if (!extractor) return raw;`,
12729
+ ` const pick = (paths: string[] | string) => {`,
12730
+ ` const candidates = Array.isArray(paths) ? paths : [paths];`,
12731
+ ` for (const path of candidates) {`,
12732
+ ` const value = __dlGetByPath(raw, String(path));`,
12733
+ ` if (__dlMeaningful(value)) return value;`,
12734
+ ` }`,
12735
+ ` return null;`,
12736
+ ` };`,
12737
+ ` const extracted = extractor({ row, result, data: raw, raw, pick, extract: pick, target: pick });`,
12738
+ ` if (extracted && typeof extracted === 'object' && !Array.isArray(extracted) && alias in (extracted as Record<string, unknown>)) {`,
12739
+ ` return (extracted as Record<string, unknown>)[alias];`,
12740
+ ` }`,
12741
+ ` return extracted === undefined ? raw : extracted;`,
12742
+ `}`,
12743
+ ``,
12744
+ `async function __dlRunCommand(input: { alias: string; callId: string; tool: string; payload: Record<string, unknown>; extract: ((args: { row: Record<string, unknown>; result: unknown; data: unknown; raw: unknown; pick: (paths: string[] | string) => unknown; extract: (paths: string[] | string) => unknown; target: (paths: string[] | string) => unknown }) => unknown) | null; runIf: ((row: Record<string, unknown>) => unknown) | null; row: Record<string, unknown>; stepCtx: { tools: { execute: (request: Record<string, unknown>) => Promise<unknown> } }; description?: string; force?: boolean }): Promise<unknown> {`,
12745
+ ` if (input.runIf) {`,
12746
+ ` const shouldRun = input.runIf(input.row);`,
12747
+ ` if (!shouldRun) return null;`,
12748
+ ` }`,
12749
+ ` const result = await input.stepCtx.tools.execute({`,
12750
+ ` id: input.callId,`,
12751
+ ` tool: input.tool,`,
12752
+ ` input: __dlTemplate(input.payload, input.row) as Record<string, unknown>,`,
12753
+ ` ...(input.description ? { description: input.description } : {}),`,
12754
+ ` ...(input.force ? { staleAfterSeconds: 0 } : {}),`,
12755
+ ` });`,
12756
+ ` return __dlExtract(input.alias, result, input.row, input.extract);`,
12757
+ `}`
12758
+ ].join("\n");
12759
+ }
12760
+
12761
+ // src/cli/commands/enrich.ts
12762
+ var PLAN_SHAPING_OPTION_NAMES = [
12763
+ "with",
12764
+ "withWaterfall",
12765
+ "minResults",
12766
+ "endWaterfall"
12767
+ ];
12768
+ var ENRICH_DEPRECATION_NOTICE = {
12769
+ status: "deprecated",
12770
+ message: "The enrich compatibility command is deprecated. This run generates a temporary .play.ts file and executes it through plays run.",
12771
+ generatedPlayFile: "Temporary compatibility play file; deleted after the command exits.",
12772
+ printGeneratedPlayCommand: "deepline enrich <same args> --dry-run > enrich.play.ts",
12773
+ recommendedCommand: `deepline plays run enrich.play.ts --input '{"file":"<input.csv>"}'`
12774
+ };
12775
+ var ENRICH_DEPRECATION_TEXT = `${ENRICH_DEPRECATION_NOTICE.message} Print the generated play with: ${ENRICH_DEPRECATION_NOTICE.printGeneratedPlayCommand}. Then run: ${ENRICH_DEPRECATION_NOTICE.recommendedCommand}
12776
+ `;
12777
+ function optionWasProvided(args, ...flags) {
12778
+ return args.some(
12779
+ (arg) => flags.some((flag) => arg === flag || arg.startsWith(`${flag}=`))
12780
+ );
12781
+ }
12782
+ function normalizeAlias2(value) {
12783
+ return value.toLowerCase().replace(/[^a-z0-9]/g, "");
12784
+ }
12785
+ function hasPlanShapingArgs(args) {
12786
+ return optionWasProvided(args, "--with") || optionWasProvided(args, "--with-waterfall") || optionWasProvided(args, "--min-results") || optionWasProvided(args, "--end-waterfall");
12787
+ }
12788
+ function printDeprecationNotice(options) {
12789
+ if (!options.json) {
12790
+ process.stderr.write(ENRICH_DEPRECATION_TEXT);
12791
+ }
12792
+ }
12793
+ function expandAtFilePath(rawPath) {
12794
+ let expanded = rawPath.trim();
12795
+ expanded = expanded.replace(
12796
+ /\$([A-Za-z_][A-Za-z0-9_]*)|\$\{([^}]+)\}/g,
12797
+ (_match, bareName, bracedName) => process.env[bareName ?? bracedName ?? ""] ?? ""
12798
+ );
12799
+ if (expanded === "~") {
12800
+ return (0, import_node_os7.homedir)();
12801
+ }
12802
+ if (expanded.startsWith("~/") || expanded.startsWith("~\\")) {
12803
+ return (0, import_node_path13.join)((0, import_node_os7.homedir)(), expanded.slice(2));
12804
+ }
12805
+ return expanded;
12806
+ }
12807
+ async function readAtFileReference(value, argumentName, strip = true) {
12808
+ if (!value.startsWith("@")) {
12809
+ return strip ? value.trim() : value.replace(/^\uFEFF/, "");
12810
+ }
12811
+ const filePath = expandAtFilePath(value.slice(1));
12812
+ if (!filePath) {
12813
+ throw new Error(`Invalid ${argumentName} value: empty @file path.`);
12814
+ }
12815
+ try {
12816
+ const text = await (0, import_promises5.readFile)(filePath, "utf8");
12817
+ const normalized = text.replace(/^\uFEFF/, "");
12818
+ return strip ? normalized.trim() : normalized;
12819
+ } catch (error) {
12820
+ throw new Error(
12821
+ `Failed to read ${argumentName} file '${filePath}': ${error instanceof Error ? error.message : String(error)}`
12822
+ );
12823
+ }
12824
+ }
12825
+ function normalizeExtractJs(source) {
12826
+ return source.replace(/\\"/g, '"').replace(/\\'/g, "'");
12827
+ }
12828
+ async function normalizeWithSpec(rawSpec) {
12829
+ const raw = await readAtFileReference(rawSpec.trim(), "--with");
12830
+ let parsed;
12831
+ try {
12832
+ parsed = JSON.parse(raw);
12833
+ } catch (error) {
12834
+ throw new Error(
12835
+ `Invalid JSON payload in --with spec: ${raw} (${error instanceof Error ? error.message : String(error)})`
12836
+ );
12837
+ }
12838
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
12839
+ throw new Error("Invalid --with spec: expected JSON object.");
12840
+ }
12841
+ const spec = parsed;
12842
+ const normalized = { ...spec };
12843
+ for (const field of ["extract_js", "run_if_js"]) {
12844
+ const value = normalized[field];
12845
+ if (typeof value !== "string" || !value.trim()) {
12846
+ continue;
12847
+ }
12848
+ const fromFile = value.trim().startsWith("@") ? await readAtFileReference(value.trim(), `--with ${field}`, false) : null;
12849
+ normalized[field] = fromFile !== null ? fromFile.trim() : normalizeExtractJs(value.trim());
12850
+ }
12851
+ const tool = String(
12852
+ normalized.tool ?? normalized.tool_ref ?? normalized.tool_id ?? ""
12853
+ ).trim();
12854
+ const payload = normalized.payload;
12855
+ if (tool === "run_javascript" && payload && typeof payload === "object" && !Array.isArray(payload)) {
12856
+ const payloadRecord = payload;
12857
+ const code = payloadRecord.code;
12858
+ if (typeof code === "string" && code.trim().startsWith("@")) {
12859
+ normalized.payload = {
12860
+ ...payloadRecord,
12861
+ code: await readAtFileReference(
12862
+ code.trim(),
12863
+ "run_javascript payload.code",
12864
+ false
12865
+ )
12866
+ };
12867
+ }
12868
+ }
12869
+ return JSON.stringify(normalized);
12870
+ }
12871
+ async function expandCompiledConfigAtFiles(value) {
12872
+ if (Array.isArray(value)) {
12873
+ return Promise.all(
12874
+ value.map((entry) => expandCompiledConfigAtFiles(entry))
12875
+ );
12876
+ }
12877
+ if (!value || typeof value !== "object") {
12878
+ return value;
12879
+ }
12880
+ const record = value;
12881
+ const expanded = {};
12882
+ for (const [key, entry] of Object.entries(record)) {
12883
+ expanded[key] = await expandCompiledConfigAtFiles(entry);
12884
+ }
12885
+ for (const field of ["extract_js", "run_if_js"]) {
12886
+ const entry = expanded[field];
12887
+ if (typeof entry === "string" && entry.trim().startsWith("@")) {
12888
+ expanded[field] = (await readAtFileReference(entry.trim(), `--config ${field}`, false)).trim();
12889
+ }
12890
+ }
12891
+ const tool = String(
12892
+ expanded.tool ?? expanded.tool_ref ?? expanded.tool_id ?? ""
12893
+ ).trim();
12894
+ const payload = expanded.payload;
12895
+ if (tool === "run_javascript" && payload && typeof payload === "object" && !Array.isArray(payload)) {
12896
+ const payloadRecord = payload;
12897
+ const code = payloadRecord.code;
12898
+ if (typeof code === "string" && code.trim().startsWith("@")) {
12899
+ expanded.payload = {
12900
+ ...payloadRecord,
12901
+ code: await readAtFileReference(
12902
+ code.trim(),
12903
+ "--config run_javascript payload.code",
12904
+ false
12905
+ )
12906
+ };
12907
+ }
12908
+ }
12909
+ return expanded;
12910
+ }
12911
+ function currentEnrichArgs() {
12912
+ const index = process.argv.findIndex((arg) => arg === "enrich");
12913
+ return index >= 0 ? process.argv.slice(index + 1) : [];
12914
+ }
12915
+ async function buildPlanArgs(args) {
12916
+ const passthrough = /* @__PURE__ */ new Set([
12917
+ "--with",
12918
+ "--with-waterfall",
12919
+ "--min-results",
12920
+ "--end-waterfall"
12921
+ ]);
12922
+ const localOptionsWithValue = /* @__PURE__ */ new Set([
12923
+ "--input",
12924
+ "--csv",
12925
+ "--output",
12926
+ "--config",
12927
+ "--rows",
12928
+ "--with-force"
12929
+ ]);
12930
+ const localBooleanOptions = /* @__PURE__ */ new Set([
12931
+ "--dry-run",
12932
+ "--json",
12933
+ "--force",
12934
+ "--all",
12935
+ "--in-place"
12936
+ ]);
12937
+ const planArgs = [];
12938
+ for (let index = 0; index < args.length; index += 1) {
12939
+ const arg = args[index];
12940
+ const equalsIndex = arg.indexOf("=");
12941
+ const flag = equalsIndex >= 0 ? arg.slice(0, equalsIndex) : arg;
12942
+ const inlineValue = equalsIndex >= 0 ? arg.slice(equalsIndex + 1) : void 0;
12943
+ if (!passthrough.has(flag)) {
12944
+ if (localOptionsWithValue.has(flag)) {
12945
+ if (inlineValue === void 0) {
12946
+ const value = args[index + 1];
12947
+ if (!value || value.startsWith("--")) {
12948
+ throw new Error(`${flag} requires a value.`);
12949
+ }
12950
+ index += 1;
12951
+ }
12952
+ continue;
12953
+ }
12954
+ if (localBooleanOptions.has(flag)) {
12955
+ if (inlineValue !== void 0) {
12956
+ throw new Error(`${flag} does not accept a value.`);
12957
+ }
12958
+ continue;
12959
+ }
12960
+ if (flag.startsWith("--")) {
12961
+ throw new Error(`Unknown enrich option: ${flag}.`);
12962
+ }
12963
+ throw new Error(`Unexpected enrich argument: ${arg}.`);
12964
+ }
12965
+ planArgs.push(flag);
12966
+ if (inlineValue !== void 0) {
12967
+ planArgs.push(
12968
+ flag === "--with" ? await normalizeWithSpec(inlineValue) : inlineValue
12969
+ );
12970
+ continue;
12971
+ }
12972
+ if (flag !== "--end-waterfall") {
12973
+ const value = args[++index];
12974
+ if (!value) {
12975
+ throw new Error(`${flag} requires a value.`);
12976
+ }
12977
+ planArgs.push(flag === "--with" ? await normalizeWithSpec(value) : value);
12978
+ }
12979
+ }
12980
+ return planArgs;
12981
+ }
12982
+ async function assertInputCsvExists(inputCsv) {
12983
+ const path = (0, import_node_path13.resolve)(inputCsv);
12984
+ try {
12985
+ const info = await (0, import_promises5.stat)(path);
12986
+ if (info.isFile()) {
12987
+ return;
12988
+ }
12989
+ throw new Error("not a file");
12990
+ } catch (error) {
12991
+ throw new Error(
12992
+ `Input CSV does not exist or is not a file: ${path}${error instanceof Error && error.message !== "not a file" ? ` (${error.message})` : ""}`
12993
+ );
12994
+ }
12995
+ }
12996
+ async function assertSafeOutputPath(inputCsv, outputPath) {
12997
+ const input2 = (0, import_node_path13.resolve)(inputCsv);
12998
+ const output2 = (0, import_node_path13.resolve)(outputPath);
12999
+ if (input2 === output2) {
13000
+ throw new Error(
13001
+ "--output must be a different path from --input. --in-place is not supported by this V2 enrich runner yet."
13002
+ );
13003
+ }
13004
+ try {
13005
+ const [inputInfo, outputInfo] = await Promise.all([
13006
+ (0, import_promises5.stat)(input2),
13007
+ (0, import_promises5.stat)(output2)
13008
+ ]);
13009
+ if (inputInfo.dev === outputInfo.dev && inputInfo.ino === outputInfo.ino) {
13010
+ throw new Error(
13011
+ "--output must be a different file from --input. --in-place is not supported by this V2 enrich runner yet."
13012
+ );
13013
+ }
13014
+ } catch (error) {
13015
+ if (error instanceof Error && error.message.startsWith("--output must")) {
13016
+ throw error;
13017
+ }
13018
+ const code = error && typeof error === "object" ? error.code : void 0;
13019
+ if (code === "ENOENT") {
13020
+ return;
13021
+ }
13022
+ throw error;
13023
+ }
13024
+ }
13025
+ async function readConfig(path) {
13026
+ const source = await (0, import_promises5.readFile)((0, import_node_path13.resolve)(path), "utf8");
13027
+ let parsed;
13028
+ try {
13029
+ parsed = JSON.parse(source);
13030
+ } catch (error) {
13031
+ throw new Error(
13032
+ `Invalid JSON in --config ${path}: ${error instanceof Error ? error.message : String(error)}`
13033
+ );
13034
+ }
13035
+ return expandCompiledConfigAtFiles(parsed);
13036
+ }
13037
+ function parseRows(value, all) {
13038
+ if (all && value) {
13039
+ throw new Error("Do not combine --rows with --all.");
13040
+ }
13041
+ if (all || !value) {
13042
+ return { rowStart: null, rowEnd: null };
13043
+ }
13044
+ const trimmed = value.trim();
13045
+ const range = trimmed.match(/^(\d*)\s*:\s*(\d*)$/);
13046
+ if (range) {
13047
+ if (!range[1] && !range[2]) {
13048
+ throw new Error(
13049
+ "--rows must be a zero-based row number or end-exclusive range like 0:10."
13050
+ );
13051
+ }
13052
+ const start = range[1] ? Number.parseInt(range[1], 10) : 0;
13053
+ const end = range[2] ? Number.parseInt(range[2], 10) : null;
13054
+ return { rowStart: start, rowEnd: end };
13055
+ }
13056
+ if (!/^\d+$/.test(trimmed)) {
13057
+ throw new Error(
13058
+ "--rows must be a zero-based row number or end-exclusive range like 0:10."
13059
+ );
13060
+ }
13061
+ const single = Number.parseInt(trimmed, 10);
13062
+ if (!Number.isFinite(single) || single < 0) {
13063
+ throw new Error(
13064
+ "--rows must be a zero-based row number or end-exclusive range like 0:10."
13065
+ );
13066
+ }
13067
+ return { rowStart: single, rowEnd: single + 1 };
13068
+ }
13069
+ function summarizePlan(config, playSource) {
13070
+ const steps = [];
13071
+ for (const command of config.commands) {
13072
+ if ("with_waterfall" in command) {
13073
+ steps.push({
13074
+ type: "waterfall",
13075
+ alias: command.with_waterfall,
13076
+ min_results: command.min_results ?? 1,
13077
+ steps: command.commands.map(
13078
+ (step) => "with_waterfall" in step ? { type: "waterfall", alias: step.with_waterfall } : { alias: step.alias, tool: step.tool, operation: step.operation }
13079
+ )
13080
+ });
13081
+ continue;
13082
+ }
13083
+ steps.push({
13084
+ type: "step",
13085
+ alias: command.alias,
13086
+ tool: command.tool,
13087
+ operation: command.operation
13088
+ });
13089
+ }
13090
+ return {
13091
+ version: config.version,
13092
+ commandCount: config.commands.length,
13093
+ steps,
13094
+ generatedPlay: playSource
13095
+ };
13096
+ }
13097
+ function collectCommandAliases(config) {
13098
+ const allAliases = /* @__PURE__ */ new Set();
13099
+ const scalarAliases = /* @__PURE__ */ new Set();
13100
+ const waterfallGroups = /* @__PURE__ */ new Map();
13101
+ for (const command of config.commands) {
13102
+ if ("with_waterfall" in command) {
13103
+ const groupAlias = normalizeAlias2(command.with_waterfall);
13104
+ if (groupAlias) {
13105
+ allAliases.add(groupAlias);
13106
+ }
13107
+ const childAliases = /* @__PURE__ */ new Set();
13108
+ for (const child of command.commands) {
13109
+ if ("with_waterfall" in child || child.disabled) {
13110
+ continue;
13111
+ }
13112
+ const childAlias = normalizeAlias2(child.alias);
13113
+ if (!childAlias) {
13114
+ continue;
13115
+ }
13116
+ allAliases.add(childAlias);
13117
+ scalarAliases.add(childAlias);
13118
+ childAliases.add(childAlias);
13119
+ }
13120
+ if (groupAlias) {
13121
+ waterfallGroups.set(groupAlias, childAliases);
13122
+ }
13123
+ continue;
13124
+ }
13125
+ if (command.disabled) {
13126
+ continue;
13127
+ }
13128
+ const alias = normalizeAlias2(command.alias);
13129
+ if (alias) {
13130
+ allAliases.add(alias);
13131
+ scalarAliases.add(alias);
13132
+ }
13133
+ }
13134
+ return { allAliases, scalarAliases, waterfallGroups };
13135
+ }
13136
+ function parseWithForceAliases(values) {
13137
+ const aliases = /* @__PURE__ */ new Set();
13138
+ for (const value of values ?? []) {
13139
+ for (const item of value.split(",")) {
13140
+ const alias = normalizeAlias2(item.trim());
13141
+ if (alias) {
13142
+ aliases.add(alias);
13143
+ }
13144
+ }
13145
+ }
13146
+ return aliases;
13147
+ }
13148
+ function resolveForceAliases(config, options) {
13149
+ const { allAliases, scalarAliases, waterfallGroups } = collectCommandAliases(config);
13150
+ if (options.force) {
13151
+ return new Set(scalarAliases);
13152
+ }
13153
+ const requested = parseWithForceAliases(options.withForce);
13154
+ const unknown = [...requested].filter((alias) => !allAliases.has(alias));
13155
+ if (unknown.length > 0) {
13156
+ throw new Error(
13157
+ `--with-force references unknown --with column alias(es): ${unknown.sort().join(", ")}.`
13158
+ );
13159
+ }
13160
+ const resolved = /* @__PURE__ */ new Set();
13161
+ for (const alias of requested) {
13162
+ const children = waterfallGroups.get(alias);
13163
+ if (children) {
13164
+ for (const child of children) {
13165
+ resolved.add(child);
13166
+ }
13167
+ } else {
13168
+ resolved.add(alias);
13169
+ }
13170
+ }
13171
+ return resolved;
13172
+ }
13173
+ function parseJsonOutput(stdout) {
13174
+ const trimmed = stdout.trim();
13175
+ if (!trimmed) return null;
13176
+ try {
13177
+ return JSON.parse(trimmed);
13178
+ } catch {
13179
+ const start = trimmed.lastIndexOf("\n{");
13180
+ if (start >= 0) {
13181
+ return JSON.parse(trimmed.slice(start + 1));
13182
+ }
13183
+ throw new Error(
13184
+ "The generated play completed but did not emit parseable JSON."
13185
+ );
13186
+ }
13187
+ }
13188
+ async function captureStdout(run) {
13189
+ const originalWrite = process.stdout.write.bind(process.stdout);
13190
+ let stdout = "";
13191
+ process.stdout.write = ((chunk, ..._args) => {
13192
+ stdout += typeof chunk === "string" ? chunk : String(chunk);
13193
+ return true;
13194
+ });
13195
+ try {
13196
+ const result = await run();
13197
+ return { result, stdout };
13198
+ } finally {
13199
+ process.stdout.write = originalWrite;
13200
+ }
13201
+ }
13202
+ async function writeOutputCsv(outputPath, status) {
13203
+ const rowsInfo = extractCanonicalRowsInfo(status);
13204
+ if (!rowsInfo) {
13205
+ throw new Error("The generated play did not return row-shaped output.");
13206
+ }
13207
+ assertCompleteRowsForCsvExport(rowsInfo, status, outputPath);
13208
+ const rows = dataExportRows(rowsInfo.rows);
13209
+ const columns = dataExportColumns(rows, rowsInfo.columns);
13210
+ await (0, import_promises5.writeFile)(
13211
+ (0, import_node_path13.resolve)(outputPath),
13212
+ csvStringFromRows(rows, columns),
13213
+ "utf8"
13214
+ );
13215
+ return { rows: rows.length, path: (0, import_node_path13.resolve)(outputPath) };
13216
+ }
13217
+ function assertCompleteRowsForCsvExport(rowsInfo, status, outputPath) {
13218
+ if (rowsInfo.complete) {
13219
+ return;
13220
+ }
13221
+ const runId = status && typeof status === "object" && !Array.isArray(status) && typeof status.runId === "string" ? status.runId : null;
13222
+ const dataset = rowsInfo.source ?? "result.rows";
13223
+ const retry = runId ? ` Retry after the run finalizes its backing dataset with: deepline runs export ${runId} --dataset ${dataset} --out ${outputPath}` : "";
13224
+ throw new Error(
13225
+ `Refusing to write a partial CSV export: the run returned ${rowsInfo.rows.length} preview row(s) out of ${rowsInfo.totalRows}.${retry}`
13226
+ );
13227
+ }
13228
+ async function compileConfig(input2) {
13229
+ if (input2.options.config) {
13230
+ if (hasPlanShapingArgs(input2.args)) {
13231
+ throw new Error(
13232
+ `Do not mix --config with plan-shaping flags (${PLAN_SHAPING_OPTION_NAMES.join(", ")}). Put the plan in the config file or pass flags directly.`
13233
+ );
13234
+ }
13235
+ const config = await readConfig(input2.options.config);
13236
+ return (await input2.client.compileEnrichPlan({ config })).config;
13237
+ }
13238
+ const planArgs = await buildPlanArgs(input2.args);
13239
+ return (await input2.client.compileEnrichPlan({ plan_args: planArgs })).config;
13240
+ }
13241
+ function registerEnrichCommand(program) {
13242
+ program.command("enrich").allowUnknownOption(true).description("Run v1-style CSV enrichment through the V2 play runner.").option("--input <path>", "Input CSV path.").option("--csv <path>", "Alias for --input.").option("--output <path>", "Output CSV path.").option("--config <path>", "JSON enrich config.").option(
13243
+ "--with <json>",
13244
+ "Add a scalar enrich command.",
13245
+ (value, previous = []) => [...previous, value]
13246
+ ).option(
13247
+ "--with-waterfall <alias>",
13248
+ "Start a waterfall group.",
13249
+ (value, previous = []) => [...previous, value]
13250
+ ).option(
13251
+ "--min-results <count>",
13252
+ "Minimum list results for the current waterfall."
13253
+ ).option("--end-waterfall", "End the current waterfall group.").option(
13254
+ "--rows <range>",
13255
+ "Zero-based row number or end-exclusive range, e.g. 0:10."
13256
+ ).option("--all", "Run all rows.").option(
13257
+ "--dry-run",
13258
+ "Compile and print the generated plan without starting a run."
13259
+ ).option("--json", "Emit JSON.").option("--force", "Force rerun for all enrich aliases.").option(
13260
+ "--with-force <aliases>",
13261
+ "Force rerun for selected aliases.",
13262
+ (value, previous = []) => [...previous, value]
13263
+ ).option(
13264
+ "--in-place",
13265
+ "Not supported by the V2 enrich compatibility runner yet."
13266
+ ).action(async (options, _command) => {
13267
+ if (options.inPlace) {
13268
+ throw new Error(
13269
+ "--in-place is not supported by this V2 enrich runner yet. Use --output instead."
13270
+ );
13271
+ }
13272
+ const inputCsv = options.input ?? options.csv;
13273
+ if (!inputCsv) {
13274
+ throw new Error("Missing required --input <csv> (or --csv <csv>).");
13275
+ }
13276
+ await assertInputCsvExists(inputCsv);
13277
+ if (options.output) {
13278
+ await assertSafeOutputPath(inputCsv, options.output);
13279
+ }
13280
+ if (!options.config && !hasPlanShapingArgs(currentEnrichArgs())) {
13281
+ throw new Error("Pass --config or at least one --with enrich spec.");
13282
+ }
13283
+ const client = new DeeplineClient();
13284
+ const args = currentEnrichArgs();
13285
+ const config = await compileConfig({ client, args, options });
13286
+ const forceAliases = resolveForceAliases(config, options);
13287
+ const playSource = compileEnrichConfigToPlaySource(config, {
13288
+ forceAliases
13289
+ });
13290
+ const summary = summarizePlan(config, playSource);
13291
+ printDeprecationNotice(options);
13292
+ if (options.dryRun) {
13293
+ if (options.json) {
13294
+ printJson({
13295
+ dryRun: true,
13296
+ deprecation: ENRICH_DEPRECATION_NOTICE,
13297
+ input: (0, import_node_path13.resolve)(inputCsv),
13298
+ output: options.output ? (0, import_node_path13.resolve)(options.output) : null,
13299
+ plan: summary
13300
+ });
13301
+ return;
13302
+ }
13303
+ process.stdout.write(`${playSource}
13304
+ `);
13305
+ return;
13306
+ }
13307
+ const rows = parseRows(options.rows, options.all);
13308
+ if (options.output && options.rows) {
13309
+ throw new Error(
13310
+ "CSV export with --rows is not supported yet because it would write only the selected rows. Run without --rows or omit --output."
13311
+ );
13312
+ }
13313
+ const tempDir = await (0, import_promises5.mkdtemp)((0, import_node_path13.join)((0, import_node_os7.tmpdir)(), "deepline-enrich-play-"));
13314
+ const tempPlay = (0, import_node_path13.join)(tempDir, "deepline-enrich.play.ts");
13315
+ try {
13316
+ await (0, import_promises5.writeFile)(tempPlay, playSource, "utf8");
13317
+ const runtimeInput = {
13318
+ file: (0, import_node_path13.resolve)(inputCsv),
13319
+ ...rows.rowStart !== null ? { rowStart: rows.rowStart } : {},
13320
+ ...rows.rowEnd !== null ? { rowEnd: rows.rowEnd } : {}
13321
+ };
13322
+ const runArgs = [
13323
+ "--file",
13324
+ tempPlay,
13325
+ "--input",
13326
+ JSON.stringify(runtimeInput),
13327
+ "--watch",
13328
+ "--no-open",
13329
+ "--json"
13330
+ ];
13331
+ const captured = await captureStdout(() => handlePlayRun(runArgs));
13332
+ const status = parseJsonOutput(captured.stdout);
13333
+ if (captured.result !== 0) {
13334
+ if (options.json) {
13335
+ printJson({
13336
+ deprecation: ENRICH_DEPRECATION_NOTICE,
13337
+ result: status
13338
+ });
13339
+ } else {
13340
+ process.stdout.write(captured.stdout);
13341
+ }
13342
+ process.exitCode = captured.result;
13343
+ return;
13344
+ }
13345
+ const exportResult = options.output ? await writeOutputCsv(options.output, status) : null;
13346
+ if (options.json) {
13347
+ printJson({
13348
+ ok: true,
13349
+ deprecation: ENRICH_DEPRECATION_NOTICE,
13350
+ run: status,
13351
+ output: exportResult
13352
+ });
13353
+ return;
13354
+ }
13355
+ process.stdout.write(captured.stdout);
13356
+ if (exportResult) {
13357
+ process.stderr.write(
13358
+ `Wrote ${exportResult.rows} row(s) to ${exportResult.path}
13359
+ `
13360
+ );
13361
+ }
13362
+ } finally {
13363
+ await (0, import_promises5.rm)(tempDir, { recursive: true, force: true });
13364
+ }
13365
+ });
13366
+ }
13367
+
13368
+ // src/cli/commands/feedback.ts
13369
+ async function handleFeedback(text, options) {
13370
+ const { http } = getAuthedHttpClient();
13371
+ const response = await http.post("/api/v2/cli/feedback", {
13372
+ text,
13373
+ environment: collectLocalEnvInfo(),
13374
+ ...options.command ? { command: options.command } : {},
13375
+ ...options.payload ? { payload: options.payload } : {}
13376
+ });
13377
+ printCommandEnvelope(
13378
+ {
13379
+ ...response,
13380
+ render: {
13381
+ sections: [
13382
+ { title: "feedback", lines: ["Feedback submitted. Thank you."] }
13383
+ ]
13384
+ }
13385
+ },
13386
+ { json: options.json }
13387
+ );
13388
+ }
13389
+ function registerFeedbackCommands(program) {
13390
+ const feedback = program.command("feedback").description("Submit CLI feedback to Deepline.").addHelpText(
13391
+ "after",
13392
+ `
13393
+ Notes:
13394
+ Sends the feedback text plus local CLI environment info to Deepline support.
13395
+ Use --command and --payload to attach a reproducible command shape.
13396
+
13397
+ Examples:
13398
+ deepline feedback "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
13399
+ deepline feedback "unexpected billing output" --payload '{"command":"billing usage"}' --json
13400
+ `
13401
+ );
13402
+ feedback.argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
13403
+ program.command("provide-feedback").description("Legacy alias for `deepline feedback`.").addHelpText(
13404
+ "after",
13405
+ `
13406
+ Notes:
13407
+ Compatibility alias. Prefer deepline feedback in new scripts and docs.
13408
+
13409
+ Examples:
13410
+ deepline feedback "tools search returned stale results" --json
13411
+ `
13412
+ ).argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
13413
+ }
13414
+
13415
+ // src/cli/commands/org.ts
13416
+ async function fetchOrganizations(http, apiKey) {
13417
+ return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
13418
+ }
13419
+ function orgListLines(orgs) {
13420
+ return orgs.map((org, index) => {
13421
+ const current = org.is_current ? " (current)" : "";
13422
+ const role = org.role ? ` [${org.role}]` : "";
13423
+ return `${index + 1}. ${org.name}${role}${current}`;
13424
+ });
13425
+ }
13426
+ async function handleOrgList(options) {
13427
+ const config = resolveConfig();
13428
+ const http = new HttpClient(config);
13429
+ const payload = await fetchOrganizations(http, config.apiKey);
13430
+ printCommandEnvelope(
13431
+ {
13432
+ ...payload,
13433
+ render: {
13434
+ sections: [
13435
+ {
13436
+ title: "Your organizations:",
13437
+ lines: orgListLines(payload.organizations)
13438
+ }
13439
+ ]
13440
+ }
13441
+ },
13442
+ { json: options.json }
13443
+ );
13444
+ }
13445
+ async function handleOrgSwitch(selection, options) {
13446
+ const config = resolveConfig();
13447
+ const http = new HttpClient(config);
13448
+ const payload = await fetchOrganizations(http, config.apiKey);
13449
+ if (!selection && !options.orgId) {
13450
+ printCommandEnvelope(
13451
+ {
13452
+ ...payload,
13453
+ next: { switch: "deepline org switch <number>" },
13454
+ render: {
13455
+ sections: [
13456
+ {
13457
+ title: "Your organizations:",
13458
+ lines: orgListLines(payload.organizations)
13459
+ }
13460
+ ],
13461
+ actions: [{ label: "Run", command: "deepline org switch <number>" }]
13462
+ }
13463
+ },
13464
+ { json: options.json }
13465
+ );
13466
+ return;
13467
+ }
13468
+ let target = payload.organizations.find(
13469
+ (org) => org.org_id === options.orgId
13470
+ );
13471
+ if (!target && selection) {
13472
+ const index = Number.parseInt(selection, 10);
13473
+ if (Number.isFinite(index) && index >= 1 && index <= payload.organizations.length) {
13474
+ target = payload.organizations[index - 1];
13475
+ } else {
13476
+ target = payload.organizations.find(
13477
+ (org) => org.name === selection || org.org_id === selection
13478
+ );
13479
+ }
13480
+ }
13481
+ if (!target) {
13482
+ throw new Error("Could not resolve the selected organization.");
13483
+ }
13484
+ if (target.is_current) {
13485
+ printCommandEnvelope(
13486
+ {
13487
+ ok: true,
13488
+ unchanged: true,
13489
+ organization: target,
13490
+ render: {
13491
+ sections: [
13492
+ { title: "org switch", lines: [`Already on ${target.name}.`] }
13493
+ ]
13494
+ }
13495
+ },
13496
+ { json: options.json }
13497
+ );
13498
+ return;
13499
+ }
13500
+ const switched = await http.post("/api/v2/auth/cli/switch", {
13501
+ api_key: config.apiKey,
13502
+ org_id: target.org_id
13503
+ });
13504
+ saveHostEnvValues(config.baseUrl, {
13505
+ DEEPLINE_API_KEY: switched.api_key,
13506
+ DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
13507
+ DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
13508
+ });
13509
+ const { api_key: _apiKey, ...publicSwitched } = switched;
13510
+ printCommandEnvelope(
13511
+ {
13512
+ ok: true,
13513
+ host_env_path: hostEnvFilePath(config.baseUrl),
13514
+ ...publicSwitched,
13515
+ api_key_saved: true,
13516
+ render: {
13517
+ sections: [
13518
+ {
13519
+ title: "org switch",
13520
+ lines: [
13521
+ `Switched to ${switched.org_name}.`,
13522
+ `Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
13523
+ ]
13524
+ }
13525
+ ]
13526
+ }
13527
+ },
13528
+ { json: options.json }
13529
+ );
13530
+ }
13531
+ function registerOrgCommands(program) {
13532
+ const org = program.command("org").description("List and switch organizations.").addHelpText(
13533
+ "after",
13534
+ `
13535
+ Notes:
13536
+ Organizations are workspaces. Switching organizations mutates the saved host
13537
+ auth file so later CLI commands target the selected workspace.
13538
+
13539
+ Examples:
13540
+ deepline org list --json
13541
+ deepline org switch 2
13542
+ deepline org switch --org-id org_123 --json
13543
+ `
13544
+ );
13545
+ org.command("list").description("List your organizations.").addHelpText(
13546
+ "after",
13547
+ `
13548
+ Notes:
13549
+ Read-only. Marks the active organization when the server returns that metadata.
13550
+
13551
+ Examples:
13552
+ deepline org list
13553
+ deepline org list --json
13554
+ `
13555
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgList);
13556
+ org.command("switch [selection]").description(
13557
+ "Switch to another organization and save the new API key in the host auth file."
13558
+ ).addHelpText(
13559
+ "after",
13560
+ `
13561
+ Notes:
13562
+ Mutates the saved host auth file. Selection can be a list number, exact
13563
+ organization name, or organization id. Without a selection, prints choices.
13564
+
13565
+ Examples:
13566
+ deepline org switch
13567
+ deepline org switch 2
13568
+ deepline org switch --org-id org_123 --json
13569
+ `
13570
+ ).option("--org-id <id>", "Switch using an explicit organization id").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgSwitch);
13571
+ }
13572
+
13573
+ // src/cli/commands/secrets.ts
13574
+ var import_node_process = require("process");
13575
+ var hiddenInputBuffer = "";
13576
+ function normalizeSecretName(value) {
13577
+ const normalized = value.trim().toUpperCase();
13578
+ if (!/^[A-Z][A-Z0-9_]{1,63}$/.test(normalized)) {
13579
+ throw new Error(
13580
+ "Secret names must be 2-64 characters and use uppercase letters, numbers, and underscores."
13581
+ );
13582
+ }
13583
+ return normalized;
13584
+ }
13585
+ function renderSecret(secret) {
13586
+ const scope = secret.scope === "play" && secret.playName ? `play:${secret.playName}` : secret.scope;
13587
+ return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}`;
13588
+ }
13589
+ async function readHiddenLine(prompt) {
13590
+ if (!import_node_process.stdin.isTTY || !import_node_process.stdout.isTTY) {
13591
+ throw new Error(
13592
+ "Secret values must be entered from an interactive TTY. Do not pipe, pass, or script secret values."
13593
+ );
13594
+ }
13595
+ import_node_process.stdout.write(prompt);
13596
+ const previousRawMode = import_node_process.stdin.isRaw;
13597
+ if (typeof import_node_process.stdin.setRawMode === "function") import_node_process.stdin.setRawMode(true);
13598
+ let value = "";
13599
+ import_node_process.stdin.resume();
13600
+ return await new Promise((resolve13, reject) => {
13601
+ let settled = false;
13602
+ const cleanup = () => {
13603
+ import_node_process.stdin.off("data", onData);
13604
+ import_node_process.stdin.off("end", onEnd);
13605
+ import_node_process.stdin.off("error", onError);
13606
+ if (typeof import_node_process.stdin.setRawMode === "function") {
13607
+ import_node_process.stdin.setRawMode(previousRawMode);
13608
+ }
13609
+ };
13610
+ const finish = (line) => {
13611
+ if (settled) return;
13612
+ settled = true;
13613
+ import_node_process.stdout.write("\n");
12664
13614
  cleanup();
12665
- resolve12(line);
13615
+ resolve13(line);
12666
13616
  };
12667
13617
  const fail = (error) => {
12668
13618
  if (settled) return;
@@ -12835,13 +13785,13 @@ Examples:
12835
13785
  // src/cli/commands/tools.ts
12836
13786
  var import_commander2 = require("commander");
12837
13787
  var import_node_fs12 = require("fs");
12838
- var import_node_os8 = require("os");
12839
- var import_node_path14 = require("path");
13788
+ var import_node_os9 = require("os");
13789
+ var import_node_path15 = require("path");
12840
13790
 
12841
13791
  // src/tool-output.ts
12842
13792
  var import_node_fs11 = require("fs");
12843
- var import_node_os7 = require("os");
12844
- var import_node_path13 = require("path");
13793
+ var import_node_os8 = require("os");
13794
+ var import_node_path14 = require("path");
12845
13795
  function isPlainObject(value) {
12846
13796
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
12847
13797
  }
@@ -12937,19 +13887,19 @@ function tryConvertToList(payload, options) {
12937
13887
  return null;
12938
13888
  }
12939
13889
  function ensureOutputDir() {
12940
- const outputDir = (0, import_node_path13.join)((0, import_node_os7.homedir)(), ".local", "share", "deepline", "data");
13890
+ const outputDir = (0, import_node_path14.join)((0, import_node_os8.homedir)(), ".local", "share", "deepline", "data");
12941
13891
  (0, import_node_fs11.mkdirSync)(outputDir, { recursive: true });
12942
13892
  return outputDir;
12943
13893
  }
12944
13894
  function writeJsonOutputFile(payload, stem) {
12945
13895
  const outputDir = ensureOutputDir();
12946
- const outputPath = (0, import_node_path13.join)(outputDir, `${stem}_${Date.now()}.json`);
13896
+ const outputPath = (0, import_node_path14.join)(outputDir, `${stem}_${Date.now()}.json`);
12947
13897
  (0, import_node_fs11.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
12948
13898
  return outputPath;
12949
13899
  }
12950
13900
  function writeCsvOutputFile(rows, stem) {
12951
13901
  const outputDir = ensureOutputDir();
12952
- const outputPath = (0, import_node_path13.join)(outputDir, `${stem}_${Date.now()}.csv`);
13902
+ const outputPath = (0, import_node_path14.join)(outputDir, `${stem}_${Date.now()}.csv`);
12953
13903
  const seen = /* @__PURE__ */ new Set();
12954
13904
  const columns = [];
12955
13905
  for (const row of rows) {
@@ -13708,7 +14658,7 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
13708
14658
  const expression = stringField(firstGetter, "expression");
13709
14659
  if (expression)
13710
14660
  console.log(
13711
- `const ${safeIdentifier2(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`
14661
+ `const ${safeIdentifier3(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`
13712
14662
  );
13713
14663
  }
13714
14664
  console.log("```");
@@ -13777,7 +14727,7 @@ function samplePayloadForInputFields(fields) {
13777
14727
  function stableStepIdForTool(toolId) {
13778
14728
  return toolId.replace(/^[a-z0-9]+_/, "").replace(/[^a-z0-9_]+/gi, "_") || "tool_call";
13779
14729
  }
13780
- function safeIdentifier2(name) {
14730
+ function safeIdentifier3(name) {
13781
14731
  const cleaned = name.replace(/[^a-zA-Z0-9_$]+/g, "_").replace(/^[^a-zA-Z_$]+/, "");
13782
14732
  return cleaned || "value";
13783
14733
  }
@@ -14040,9 +14990,9 @@ function powerShellQuote(value) {
14040
14990
  function seedToolListScript(input2) {
14041
14991
  const stem = safeFileStem(input2.toolId);
14042
14992
  const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
14043
- const scriptDir = (0, import_node_fs12.mkdtempSync)((0, import_node_path14.join)((0, import_node_os8.tmpdir)(), "deepline-workflow-seed-"));
14993
+ const scriptDir = (0, import_node_fs12.mkdtempSync)((0, import_node_path15.join)((0, import_node_os9.tmpdir)(), "deepline-workflow-seed-"));
14044
14994
  (0, import_node_fs12.chmodSync)(scriptDir, 448);
14045
- const scriptPath = (0, import_node_path14.join)(scriptDir, fileName);
14995
+ const scriptPath = (0, import_node_path15.join)(scriptDir, fileName);
14046
14996
  const projectDir = `deepline/projects/${stem}-workflow`;
14047
14997
  const playName = `${stem}-workflow`;
14048
14998
  const sampleRows = input2.rows.length > 0 ? `${JSON.stringify(input2.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
@@ -14334,7 +15284,7 @@ async function executeTool(args) {
14334
15284
  // src/cli/commands/update.ts
14335
15285
  var import_node_child_process = require("child_process");
14336
15286
  var import_node_fs13 = require("fs");
14337
- var import_node_path15 = require("path");
15287
+ var import_node_path16 = require("path");
14338
15288
  function posixShellQuote(value) {
14339
15289
  return `'${value.replace(/'/g, `'\\''`)}'`;
14340
15290
  }
@@ -14353,19 +15303,19 @@ function buildSourceUpdateCommand(sourceRoot) {
14353
15303
  return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
14354
15304
  }
14355
15305
  function findRepoBackedSdkRoot(startPath) {
14356
- let current = (0, import_node_path15.resolve)(startPath);
15306
+ let current = (0, import_node_path16.resolve)(startPath);
14357
15307
  while (true) {
14358
- if ((0, import_node_fs13.existsSync)((0, import_node_path15.join)(current, "sdk", "package.json")) && (0, import_node_fs13.existsSync)((0, import_node_path15.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
15308
+ if ((0, import_node_fs13.existsSync)((0, import_node_path16.join)(current, "sdk", "package.json")) && (0, import_node_fs13.existsSync)((0, import_node_path16.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
14359
15309
  return current;
14360
15310
  }
14361
- const parent = (0, import_node_path15.dirname)(current);
15311
+ const parent = (0, import_node_path16.dirname)(current);
14362
15312
  if (parent === current) return null;
14363
15313
  current = parent;
14364
15314
  }
14365
15315
  }
14366
15316
  function resolveUpdatePlan() {
14367
- const entrypoint = process.argv[1] ? (0, import_node_path15.resolve)(process.argv[1]) : "";
14368
- const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path15.dirname)(entrypoint)) : null;
15317
+ const entrypoint = process.argv[1] ? (0, import_node_path16.resolve)(process.argv[1]) : "";
15318
+ const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path16.dirname)(entrypoint)) : null;
14369
15319
  if (sourceRoot) {
14370
15320
  return {
14371
15321
  kind: "source",
@@ -14629,8 +15579,8 @@ function unknownCommandNameFromMessage(message) {
14629
15579
  // src/cli/skills-sync.ts
14630
15580
  var import_node_child_process2 = require("child_process");
14631
15581
  var import_node_fs14 = require("fs");
14632
- var import_node_os9 = require("os");
14633
- var import_node_path16 = require("path");
15582
+ var import_node_os10 = require("os");
15583
+ var import_node_path17 = require("path");
14634
15584
  var CHECK_TIMEOUT_MS2 = 3e3;
14635
15585
  var SDK_SKILL_NAME = "deepline-sdk";
14636
15586
  var attemptedSync = false;
@@ -14639,8 +15589,8 @@ function shouldSkipSkillsSync() {
14639
15589
  return value === "1" || value === "true" || value === "yes" || value === "on";
14640
15590
  }
14641
15591
  function sdkSkillsVersionPath(baseUrl) {
14642
- const home = process.env.HOME?.trim() || (0, import_node_os9.homedir)();
14643
- return (0, import_node_path16.join)(
15592
+ const home = process.env.HOME?.trim() || (0, import_node_os10.homedir)();
15593
+ return (0, import_node_path17.join)(
14644
15594
  home,
14645
15595
  ".local",
14646
15596
  "deepline",
@@ -14660,15 +15610,15 @@ function readLocalSkillsVersion(baseUrl) {
14660
15610
  }
14661
15611
  function writeLocalSkillsVersion(baseUrl, version) {
14662
15612
  const path = sdkSkillsVersionPath(baseUrl);
14663
- (0, import_node_fs14.mkdirSync)((0, import_node_path16.dirname)(path), { recursive: true });
15613
+ (0, import_node_fs14.mkdirSync)((0, import_node_path17.dirname)(path), { recursive: true });
14664
15614
  (0, import_node_fs14.writeFileSync)(path, `${version}
14665
15615
  `, "utf-8");
14666
15616
  }
14667
15617
  function installedSdkSkillHasStalePositionalExecuteExamples() {
14668
- const home = process.env.HOME?.trim() || (0, import_node_os9.homedir)();
15618
+ const home = process.env.HOME?.trim() || (0, import_node_os10.homedir)();
14669
15619
  const roots = [
14670
- (0, import_node_path16.join)(home, ".claude", "skills", SDK_SKILL_NAME),
14671
- (0, import_node_path16.join)(home, ".agents", "skills", SDK_SKILL_NAME)
15620
+ (0, import_node_path17.join)(home, ".claude", "skills", SDK_SKILL_NAME),
15621
+ (0, import_node_path17.join)(home, ".agents", "skills", SDK_SKILL_NAME)
14672
15622
  ];
14673
15623
  const staleMarkers = [
14674
15624
  "ctx.tools.execute(key",
@@ -14679,9 +15629,9 @@ function installedSdkSkillHasStalePositionalExecuteExamples() {
14679
15629
  ];
14680
15630
  const scan = (dir) => {
14681
15631
  for (const entry of (0, import_node_fs14.readdirSync)(dir)) {
14682
- const path = (0, import_node_path16.join)(dir, entry);
14683
- const stat3 = (0, import_node_fs14.statSync)(path);
14684
- if (stat3.isDirectory()) {
15632
+ const path = (0, import_node_path17.join)(dir, entry);
15633
+ const stat4 = (0, import_node_fs14.statSync)(path);
15634
+ if (stat4.isDirectory()) {
14685
15635
  if (scan(path)) return true;
14686
15636
  continue;
14687
15637
  }
@@ -14765,7 +15715,7 @@ function resolveSkillsInstallCommands(baseUrl) {
14765
15715
  return [npxInstall];
14766
15716
  }
14767
15717
  function runOneSkillsInstall(install) {
14768
- return new Promise((resolve12) => {
15718
+ return new Promise((resolve13) => {
14769
15719
  const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
14770
15720
  stdio: ["ignore", "ignore", "pipe"],
14771
15721
  env: process.env
@@ -14775,7 +15725,7 @@ function runOneSkillsInstall(install) {
14775
15725
  stderr += chunk.toString("utf-8");
14776
15726
  });
14777
15727
  child.on("error", (error) => {
14778
- resolve12({
15728
+ resolve13({
14779
15729
  ok: false,
14780
15730
  detail: `failed to start ${install.command}: ${error.message}`,
14781
15731
  manualCommand: install.manualCommand
@@ -14783,11 +15733,11 @@ function runOneSkillsInstall(install) {
14783
15733
  });
14784
15734
  child.on("close", (code) => {
14785
15735
  if (code === 0) {
14786
- resolve12({ ok: true, detail: "", manualCommand: install.manualCommand });
15736
+ resolve13({ ok: true, detail: "", manualCommand: install.manualCommand });
14787
15737
  return;
14788
15738
  }
14789
15739
  const detail = stderr.trim();
14790
- resolve12({
15740
+ resolve13({
14791
15741
  ok: false,
14792
15742
  detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
14793
15743
  manualCommand: install.manualCommand
@@ -14870,10 +15820,10 @@ function shouldDeferSkillsSyncForCommand() {
14870
15820
  return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
14871
15821
  }
14872
15822
  async function runPlayRunnerHealthCheck() {
14873
- const dir = await (0, import_promises5.mkdtemp)((0, import_node_path17.join)((0, import_node_os10.tmpdir)(), "deepline-health-play-"));
14874
- const file = (0, import_node_path17.join)(dir, "health-check.play.ts");
15823
+ const dir = await (0, import_promises6.mkdtemp)((0, import_node_path18.join)((0, import_node_os11.tmpdir)(), "deepline-health-play-"));
15824
+ const file = (0, import_node_path18.join)(dir, "health-check.play.ts");
14875
15825
  try {
14876
- await (0, import_promises5.writeFile)(
15826
+ await (0, import_promises6.writeFile)(
14877
15827
  file,
14878
15828
  [
14879
15829
  "import { definePlay } from 'deepline';",
@@ -14921,7 +15871,7 @@ async function runPlayRunnerHealthCheck() {
14921
15871
  }
14922
15872
  };
14923
15873
  } finally {
14924
- await (0, import_promises5.rm)(dir, { recursive: true, force: true });
15874
+ await (0, import_promises6.rm)(dir, { recursive: true, force: true });
14925
15875
  }
14926
15876
  }
14927
15877
  async function main() {
@@ -14998,6 +15948,7 @@ Exit codes:
14998
15948
  registerSecretsCommands(program);
14999
15949
  registerBillingCommands(program);
15000
15950
  registerOrgCommands(program);
15951
+ registerEnrichCommand(program);
15001
15952
  registerCsvCommands(program);
15002
15953
  registerDbCommands(program);
15003
15954
  registerFeedbackCommands(program);