deepline 0.1.57 → 0.1.59

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
@@ -25,7 +25,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
 
26
26
  // src/cli/index.ts
27
27
  var import_promises5 = require("fs/promises");
28
- var import_node_path15 = require("path");
28
+ var import_node_path16 = require("path");
29
29
  var import_node_os9 = require("os");
30
30
  var import_commander3 = require("commander");
31
31
 
@@ -220,10 +220,10 @@ function resolveConfig(options) {
220
220
 
221
221
  // src/release.ts
222
222
  var SDK_RELEASE = {
223
- version: "0.1.57",
224
- apiContract: "2026-05-play-tool-describe-starters",
223
+ version: "0.1.59",
224
+ apiContract: "2026-05-play-bootstrap-dataset-summary",
225
225
  supportPolicy: {
226
- latest: "0.1.57",
226
+ latest: "0.1.59",
227
227
  minimumSupported: "0.1.53",
228
228
  deprecatedBelow: "0.1.53"
229
229
  }
@@ -361,8 +361,8 @@ var HttpClient = class {
361
361
  if (lastError instanceof DeeplineError) {
362
362
  throw lastError;
363
363
  }
364
- const errorMessage = lastError?.message ? `Unable to connect to ${baseUrl}. ${lastError.message}` : `Unable to connect to ${baseUrl}. Is the computer able to access the url?`;
365
- throw new DeeplineError(errorMessage);
364
+ const errorMessage2 = lastError?.message ? `Unable to connect to ${baseUrl}. ${lastError.message}` : `Unable to connect to ${baseUrl}. Is the computer able to access the url?`;
365
+ throw new DeeplineError(errorMessage2);
366
366
  }
367
367
  /**
368
368
  * Send a GET request.
@@ -535,7 +535,7 @@ function decodeSseFrame(frame) {
535
535
  return parsed;
536
536
  }
537
537
  function sleep(ms) {
538
- return new Promise((resolve11) => setTimeout(resolve11, ms));
538
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
539
539
  }
540
540
 
541
541
  // src/client.ts
@@ -545,7 +545,7 @@ var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
545
545
  var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
546
546
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
547
547
  function sleep2(ms) {
548
- return new Promise((resolve11) => setTimeout(resolve11, ms));
548
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
549
549
  }
550
550
  function isTransientCompileManifestError(error) {
551
551
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -2276,7 +2276,7 @@ function buildCandidateUrls2(url) {
2276
2276
  }
2277
2277
  }
2278
2278
  function sleep3(ms) {
2279
- return new Promise((resolve11) => setTimeout(resolve11, ms));
2279
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
2280
2280
  }
2281
2281
  function printDeeplineLogo() {
2282
2282
  if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
@@ -3044,6 +3044,33 @@ Examples:
3044
3044
  // src/cli/dataset-stats.ts
3045
3045
  var import_node_fs4 = require("fs");
3046
3046
  var import_node_path5 = require("path");
3047
+
3048
+ // ../shared_libs/plays/dataset-summary.ts
3049
+ function datasetSummaryPercentText(numerator, denominator) {
3050
+ return denominator > 0 ? `${numerator}/${denominator} (${Math.round(100 * numerator / denominator)}%)` : "0/0 (0%)";
3051
+ }
3052
+ function readCount(value) {
3053
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.trunc(value) : 0;
3054
+ }
3055
+ function formatDatasetExecutionStats(raw, denominator) {
3056
+ return {
3057
+ queued: datasetSummaryPercentText(readCount(raw.queued), denominator),
3058
+ running: datasetSummaryPercentText(readCount(raw.running), denominator),
3059
+ "completed:executed": datasetSummaryPercentText(
3060
+ readCount(raw.completed),
3061
+ denominator
3062
+ ),
3063
+ "completed:reused": datasetSummaryPercentText(readCount(raw.cached), denominator),
3064
+ "skipped:condition": datasetSummaryPercentText(
3065
+ readCount(raw.skipped),
3066
+ denominator
3067
+ ),
3068
+ "skipped:missed": datasetSummaryPercentText(readCount(raw.missed), denominator),
3069
+ failed: datasetSummaryPercentText(readCount(raw.failed), denominator)
3070
+ };
3071
+ }
3072
+
3073
+ // src/cli/dataset-stats.ts
3047
3074
  var CSV_PROJECTED_FIELDS_KEY = "__deeplineCsvProjectedFields";
3048
3075
  function csvProjectedFields(row) {
3049
3076
  const serialized = row[CSV_PROJECTED_FIELDS_KEY];
@@ -3124,9 +3151,6 @@ function rowArray(value) {
3124
3151
  function readNumber(value) {
3125
3152
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.trunc(value) : null;
3126
3153
  }
3127
- function numericStat(value) {
3128
- return readNumber(value) ?? 0;
3129
- }
3130
3154
  function inferColumns(rows) {
3131
3155
  const columns = [];
3132
3156
  const seen = /* @__PURE__ */ new Set();
@@ -3290,7 +3314,7 @@ function extractCanonicalRowsInfo(statusOrResult) {
3290
3314
  return collectCanonicalRowsInfos(statusOrResult)[0] ?? null;
3291
3315
  }
3292
3316
  function percentText(numerator, denominator) {
3293
- return denominator > 0 ? `${numerator}/${denominator} (${Math.round(100 * numerator / denominator)}%)` : "0/0 (0%)";
3317
+ return datasetSummaryPercentText(numerator, denominator);
3294
3318
  }
3295
3319
  function isDatasetExecutionStatsInput(value) {
3296
3320
  return isRecord2(value) && isRecord2(value.columnStats) && Object.values(value.columnStats).every(isRecord2);
@@ -3306,17 +3330,6 @@ function extractDatasetExecutionStats(statusOrResult) {
3306
3330
  const nested = isRecord2(statusOrResult.result) ? statusOrResult.result.dataset_execution_stats : null;
3307
3331
  return isDatasetExecutionStatsInput(nested) ? nested : null;
3308
3332
  }
3309
- function formatExecutionStats(raw, denominator) {
3310
- return {
3311
- queued: percentText(numericStat(raw.queued), denominator),
3312
- running: percentText(numericStat(raw.running), denominator),
3313
- "completed:executed": percentText(numericStat(raw.completed), denominator),
3314
- "completed:reused": percentText(numericStat(raw.cached), denominator),
3315
- "skipped:condition": percentText(numericStat(raw.skipped), denominator),
3316
- "skipped:missed": percentText(numericStat(raw.missed), denominator),
3317
- failed: percentText(numericStat(raw.failed), denominator)
3318
- };
3319
- }
3320
3333
  function countPercentText(count, denominator) {
3321
3334
  return denominator > 0 ? `${count} (${Math.round(100 * count / denominator)}%)` : "0 (0%)";
3322
3335
  }
@@ -3439,7 +3452,7 @@ function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns
3439
3452
  };
3440
3453
  const rawExecutionStats = executionStats?.columnStats[column];
3441
3454
  if (rawExecutionStats) {
3442
- stat3.execution = formatExecutionStats(rawExecutionStats, totalRows);
3455
+ stat3.execution = formatDatasetExecutionStats(rawExecutionStats, totalRows);
3443
3456
  }
3444
3457
  if (sampleValue !== void 0 && sampleValueType) {
3445
3458
  stat3.sample_value = sampleValue;
@@ -4025,8 +4038,8 @@ Examples:
4025
4038
 
4026
4039
  // src/cli/commands/play.ts
4027
4040
  var import_node_crypto3 = require("crypto");
4028
- var import_node_fs8 = require("fs");
4029
- var import_node_path10 = require("path");
4041
+ var import_node_fs9 = require("fs");
4042
+ var import_node_path11 = require("path");
4030
4043
 
4031
4044
  // src/plays/bundle-play-file.ts
4032
4045
  var import_node_os5 = require("os");
@@ -4379,6 +4392,9 @@ function localSdkAliasPlugin(adapter, options) {
4379
4392
  buildContext.onResolve({ filter: /^deepline$/ }, () => ({
4380
4393
  path: entryFile
4381
4394
  }));
4395
+ buildContext.onResolve({ filter: /^deepline\/helpers$/ }, () => ({
4396
+ path: (0, import_node_path7.join)(adapter.sdkSourceRoot, "helpers.ts")
4397
+ }));
4382
4398
  }
4383
4399
  };
4384
4400
  }
@@ -5590,6 +5606,1443 @@ async function bundlePlayFile2(filePath, options = {}) {
5590
5606
  });
5591
5607
  }
5592
5608
 
5609
+ // src/cli/commands/plays/bootstrap.ts
5610
+ var import_node_fs8 = require("fs");
5611
+ var import_node_path10 = require("path");
5612
+ var import_sync4 = require("csv-parse/sync");
5613
+
5614
+ // ../shared_libs/plays/bootstrap-routes.ts
5615
+ var PLAY_BOOTSTRAP_TEMPLATES = [
5616
+ "people-list",
5617
+ "company-list",
5618
+ "people-email",
5619
+ "people-phone",
5620
+ "company-people",
5621
+ "company-people-email",
5622
+ "company-people-phone"
5623
+ ];
5624
+ var PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY = "company_search";
5625
+ var PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY = "people_search";
5626
+ var PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER = {
5627
+ email_finder: "email_finder",
5628
+ phone_finder: "phone_finder"
5629
+ };
5630
+ var PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER = {
5631
+ email_finder: "email",
5632
+ phone_finder: "phone"
5633
+ };
5634
+ function isPlayBootstrapTemplate(value) {
5635
+ return PLAY_BOOTSTRAP_TEMPLATES.includes(value);
5636
+ }
5637
+ function formatPlayBootstrapTemplates() {
5638
+ return PLAY_BOOTSTRAP_TEMPLATES.join("|");
5639
+ }
5640
+
5641
+ // src/cli/commands/plays/bootstrap.ts
5642
+ function parseReferencedPlayTarget(target) {
5643
+ const trimmed = target.trim();
5644
+ const slashIndex = trimmed.indexOf("/");
5645
+ if (slashIndex <= 0 || slashIndex === trimmed.length - 1) {
5646
+ return { ownerSlug: null, playName: trimmed, unqualifiedPlayName: trimmed };
5647
+ }
5648
+ return {
5649
+ ownerSlug: trimmed.slice(0, slashIndex),
5650
+ playName: trimmed,
5651
+ unqualifiedPlayName: trimmed.slice(slashIndex + 1)
5652
+ };
5653
+ }
5654
+ function parsePositiveInteger2(value, flagName) {
5655
+ const parsed = Number.parseInt(value, 10);
5656
+ if (!Number.isFinite(parsed) || parsed <= 0) {
5657
+ throw new PlayBootstrapUsageError(
5658
+ `${flagName} must be a positive integer.`
5659
+ );
5660
+ }
5661
+ return parsed;
5662
+ }
5663
+ function isRecord3(value) {
5664
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
5665
+ }
5666
+ function stringValue(value) {
5667
+ return typeof value === "string" ? value.trim() : "";
5668
+ }
5669
+ function extractionEntries(value) {
5670
+ if (Array.isArray(value)) return value.filter(isRecord3);
5671
+ if (!isRecord3(value)) return [];
5672
+ return Object.entries(value).map(
5673
+ ([name, entry]) => isRecord3(entry) ? { name, ...entry } : { name }
5674
+ );
5675
+ }
5676
+ var PlayBootstrapError = class extends Error {
5677
+ constructor(message, exitCode) {
5678
+ super(message);
5679
+ this.exitCode = exitCode;
5680
+ }
5681
+ exitCode;
5682
+ };
5683
+ var PlayBootstrapUsageError = class extends PlayBootstrapError {
5684
+ constructor(message) {
5685
+ super(message, 2);
5686
+ }
5687
+ };
5688
+ var PlayBootstrapValidationError = class extends PlayBootstrapError {
5689
+ constructor(message) {
5690
+ super(message, 7);
5691
+ }
5692
+ };
5693
+ var CSV_HEADER_SAMPLE_BYTES = 64 * 1024;
5694
+ function parseCsvList(value) {
5695
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
5696
+ }
5697
+ function parseProviderList(value, flag) {
5698
+ const providers = parseCsvList(value);
5699
+ if (providers.length === 0) {
5700
+ throw new PlayBootstrapUsageError(`${flag} provider list cannot be empty.`);
5701
+ }
5702
+ return providers;
5703
+ }
5704
+ function parseBootstrapPrefixedRef(value, flag) {
5705
+ const separatorIndex = value.indexOf(":");
5706
+ if (separatorIndex <= 0 || separatorIndex === value.length - 1) {
5707
+ throw new PlayBootstrapUsageError(
5708
+ `${flag} expects a typed resource reference like csv:data/leads.csv, play:prebuilt/name-and-domain-to-email-waterfall, provider:dropleads_search_people, or providers:hunter_email_finder,leadmagic_email_finder.`
5709
+ );
5710
+ }
5711
+ return {
5712
+ prefix: value.slice(0, separatorIndex).trim(),
5713
+ body: value.slice(separatorIndex + 1).trim()
5714
+ };
5715
+ }
5716
+ function parseBootstrapSourceRef(value, flag = "--from") {
5717
+ const { prefix, body } = parseBootstrapPrefixedRef(value, flag);
5718
+ switch (prefix) {
5719
+ case "csv":
5720
+ return { kind: "csv", value: body };
5721
+ case "play":
5722
+ return { kind: "play", value: parseReferencedPlayTarget(body).playName };
5723
+ case "provider":
5724
+ case "providers":
5725
+ return { kind: "providers", values: parseProviderList(body, flag) };
5726
+ }
5727
+ throw new PlayBootstrapUsageError(
5728
+ `${flag} does not support ${prefix}:. Use csv:, play:, provider:, or providers:.`
5729
+ );
5730
+ }
5731
+ function parseBootstrapStageRef(value, flag) {
5732
+ const { prefix, body } = parseBootstrapPrefixedRef(value, flag);
5733
+ switch (prefix) {
5734
+ case "play":
5735
+ return { kind: "play", value: parseReferencedPlayTarget(body).playName };
5736
+ case "provider":
5737
+ case "providers":
5738
+ return { kind: "providers", values: parseProviderList(body, flag) };
5739
+ }
5740
+ throw new PlayBootstrapUsageError(
5741
+ `${flag} does not support ${prefix}:. Use play:, provider:, or providers:.`
5742
+ );
5743
+ }
5744
+ function playBootstrapTemplateConfig(template) {
5745
+ switch (template) {
5746
+ case "company-list":
5747
+ return { sourceEntity: "company", usingStage: null, requiredStages: [] };
5748
+ case "people-list":
5749
+ return { sourceEntity: "people", usingStage: null, requiredStages: [] };
5750
+ case "people-email":
5751
+ return {
5752
+ sourceEntity: "people",
5753
+ usingStage: "email",
5754
+ requiredStages: []
5755
+ };
5756
+ case "people-phone":
5757
+ return {
5758
+ sourceEntity: "people",
5759
+ usingStage: "phone",
5760
+ requiredStages: []
5761
+ };
5762
+ case "company-people":
5763
+ return {
5764
+ sourceEntity: "company",
5765
+ usingStage: "people",
5766
+ requiredStages: []
5767
+ };
5768
+ case "company-people-email":
5769
+ return {
5770
+ sourceEntity: "company",
5771
+ usingStage: null,
5772
+ requiredStages: ["people", "email"]
5773
+ };
5774
+ case "company-people-phone":
5775
+ return {
5776
+ sourceEntity: "company",
5777
+ usingStage: null,
5778
+ requiredStages: ["people", "phone"]
5779
+ };
5780
+ }
5781
+ }
5782
+ function templateExample(template) {
5783
+ switch (template) {
5784
+ case "people-list":
5785
+ return "deepline plays bootstrap people-list --from provider:dropleads_search_people > people.play.ts";
5786
+ case "company-list":
5787
+ return "deepline plays bootstrap company-list --from provider:apollo_company_search > companies.play.ts";
5788
+ case "people-email":
5789
+ return "deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall > email-flow.play.ts";
5790
+ case "people-phone":
5791
+ return "deepline plays bootstrap people-phone --from csv:data/vp_contacts.csv --using play:prebuilt/person-to-phone > phone-flow.play.ts";
5792
+ case "company-people":
5793
+ return "deepline plays bootstrap company-people --from provider:apollo_company_search --using play:prebuilt/company-to-contact > company-people.play.ts";
5794
+ case "company-people-email":
5795
+ return "deepline plays bootstrap company-people-email --from provider:apollo_company_search --people play:prebuilt/company-to-contact --email providers:hunter_email_finder,leadmagic_email_finder > account-emails.play.ts";
5796
+ case "company-people-phone":
5797
+ return "deepline plays bootstrap company-people-phone --from provider:apollo_company_search --people play:prebuilt/company-to-contact --phone providers:ai_ark_mobile_phone_finder > account-phones.play.ts";
5798
+ }
5799
+ }
5800
+ var PLAY_BOOTSTRAP_STAGE_NAMES = [
5801
+ "people",
5802
+ "email",
5803
+ "phone"
5804
+ ];
5805
+ function playBootstrapUsageLine() {
5806
+ return `Usage: deepline plays bootstrap <${formatPlayBootstrapTemplates()}> --from <csv:PATH|play:REF|provider:ID|providers:ID,ID> [--using <play:REF|providers:ID,ID>] [--people play:REF] [--email <play:REF|providers:ID,ID>] [--phone <play:REF|providers:ID,ID>] [--limit 5] > flow.play.ts`;
5807
+ }
5808
+ function requireBootstrapTemplate(rawTemplate) {
5809
+ if (!rawTemplate) {
5810
+ throw new PlayBootstrapUsageError(
5811
+ `plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}.
5812
+ Example: deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall > email-flow.play.ts`
5813
+ );
5814
+ }
5815
+ if (!isPlayBootstrapTemplate(rawTemplate)) {
5816
+ throw new PlayBootstrapUsageError(
5817
+ `Unknown plays bootstrap template: ${rawTemplate}
5818
+ Supported templates: ${formatPlayBootstrapTemplates()}`
5819
+ );
5820
+ }
5821
+ return rawTemplate;
5822
+ }
5823
+ function nextFlagValue(args, index, flag) {
5824
+ const value = args[index + 1];
5825
+ if (!value || value.startsWith("--")) {
5826
+ throw new PlayBootstrapUsageError(`${flag} needs a value.`);
5827
+ }
5828
+ return value;
5829
+ }
5830
+ function stageFlag(stage) {
5831
+ return `--${stage}`;
5832
+ }
5833
+ function stageRefHelp(stage) {
5834
+ switch (stage) {
5835
+ case "people":
5836
+ return "play:<people-play>";
5837
+ case "email":
5838
+ case "phone":
5839
+ return "<play:REF|provider:ID|providers:ID,ID>";
5840
+ }
5841
+ }
5842
+ function getStageRef(options, stage) {
5843
+ switch (stage) {
5844
+ case "people":
5845
+ return options.people;
5846
+ case "email":
5847
+ return options.email;
5848
+ case "phone":
5849
+ return options.phone;
5850
+ }
5851
+ }
5852
+ function setStageRef(options, stage, ref) {
5853
+ switch (stage) {
5854
+ case "people":
5855
+ options.people = ref;
5856
+ return;
5857
+ case "email":
5858
+ options.email = ref;
5859
+ return;
5860
+ case "phone":
5861
+ options.phone = ref;
5862
+ return;
5863
+ }
5864
+ }
5865
+ function unsupportedStageMessage(template, stage) {
5866
+ switch (stage) {
5867
+ case "people":
5868
+ return `${template} does not accept --people. Use company-people, company-people-email, or company-people-phone.`;
5869
+ case "email":
5870
+ return `${template} does not accept --email. Use people-email or company-people-email.`;
5871
+ case "phone":
5872
+ return `${template} does not accept --phone. Use people-phone or company-people-phone.`;
5873
+ }
5874
+ }
5875
+ function requireSource(options) {
5876
+ if (!options.from) {
5877
+ throw new PlayBootstrapUsageError(
5878
+ `${options.template} needs --from.
5879
+ Example: ${templateExample(options.template)}`
5880
+ );
5881
+ }
5882
+ return options.from;
5883
+ }
5884
+ function assertAllowedStageFlags(options, allowedStages) {
5885
+ const allowed = new Set(allowedStages);
5886
+ for (const stage of PLAY_BOOTSTRAP_STAGE_NAMES) {
5887
+ if (!allowed.has(stage) && getStageRef(options, stage)) {
5888
+ throw new PlayBootstrapUsageError(
5889
+ unsupportedStageMessage(options.template, stage)
5890
+ );
5891
+ }
5892
+ }
5893
+ }
5894
+ function assertRequiredStages(options, stages) {
5895
+ for (const stage of stages) {
5896
+ if (!getStageRef(options, stage)) {
5897
+ throw new PlayBootstrapUsageError(
5898
+ `${options.template} needs ${stageFlag(stage)} ${stageRefHelp(stage)}.
5899
+ Example: ${templateExample(options.template)}`
5900
+ );
5901
+ }
5902
+ }
5903
+ }
5904
+ function normalizeSingleStageRoute(options, stage) {
5905
+ const explicitStage = getStageRef(options, stage);
5906
+ if (options.using && explicitStage) {
5907
+ throw new PlayBootstrapUsageError(
5908
+ `${options.template} received both --using and ${stageFlag(stage)}. Choose one stage binding.`
5909
+ );
5910
+ }
5911
+ const selectedStage = options.using ?? explicitStage;
5912
+ if (!selectedStage) {
5913
+ throw new PlayBootstrapUsageError(
5914
+ `${options.template} needs --using ${stageRefHelp(stage)} or ${stageFlag(stage)} ${stageRefHelp(stage)}.
5915
+ Example: ${templateExample(options.template)}`
5916
+ );
5917
+ }
5918
+ setStageRef(options, stage, selectedStage);
5919
+ options.using = selectedStage;
5920
+ assertAllowedStageFlags(options, [stage]);
5921
+ }
5922
+ function normalizeMultiStageRoute(options, stages) {
5923
+ if (options.using) {
5924
+ throw new PlayBootstrapUsageError(
5925
+ `${options.template} does not accept --using. Use the explicit stage flags shown in: ${templateExample(options.template)}`
5926
+ );
5927
+ }
5928
+ assertRequiredStages(options, stages);
5929
+ assertAllowedStageFlags(options, stages);
5930
+ }
5931
+ function normalizeTemplateStages(options) {
5932
+ const config = playBootstrapTemplateConfig(options.template);
5933
+ const from = requireSource(options);
5934
+ switch (config.usingStage) {
5935
+ case "people":
5936
+ case "email":
5937
+ case "phone":
5938
+ normalizeSingleStageRoute(options, config.usingStage);
5939
+ break;
5940
+ case null:
5941
+ normalizeMultiStageRoute(options, config.requiredStages);
5942
+ break;
5943
+ }
5944
+ return {
5945
+ ...options,
5946
+ from
5947
+ };
5948
+ }
5949
+ function parsePlayBootstrapOptions(args) {
5950
+ const [rawTemplate, ...rest] = args;
5951
+ const template = requireBootstrapTemplate(rawTemplate);
5952
+ const options = {
5953
+ template,
5954
+ name: `gtm-${template}`,
5955
+ from: null,
5956
+ using: null,
5957
+ people: null,
5958
+ email: null,
5959
+ phone: null,
5960
+ limit: 5
5961
+ };
5962
+ for (let index = 0; index < rest.length; index += 1) {
5963
+ const arg = rest[index];
5964
+ const value = () => nextFlagValue(rest, index, arg);
5965
+ switch (arg) {
5966
+ case "--name":
5967
+ options.name = value();
5968
+ index += 1;
5969
+ break;
5970
+ case "--from":
5971
+ options.from = parseBootstrapSourceRef(value(), "--from");
5972
+ index += 1;
5973
+ break;
5974
+ case "--using":
5975
+ options.using = parseBootstrapStageRef(value(), "--using");
5976
+ index += 1;
5977
+ break;
5978
+ case "--people":
5979
+ options.people = parseBootstrapStageRef(value(), "--people");
5980
+ index += 1;
5981
+ break;
5982
+ case "--email":
5983
+ options.email = parseBootstrapStageRef(value(), "--email");
5984
+ index += 1;
5985
+ break;
5986
+ case "--phone":
5987
+ options.phone = parseBootstrapStageRef(value(), "--phone");
5988
+ index += 1;
5989
+ break;
5990
+ case "--limit":
5991
+ options.limit = parsePositiveInteger2(value(), "--limit");
5992
+ index += 1;
5993
+ break;
5994
+ default:
5995
+ throw new PlayBootstrapUsageError(
5996
+ `Unknown plays bootstrap option: ${arg}
5997
+ ${playBootstrapUsageLine()}`
5998
+ );
5999
+ }
6000
+ }
6001
+ return normalizeTemplateStages(options);
6002
+ }
6003
+ function jsString(value) {
6004
+ return JSON.stringify(value);
6005
+ }
6006
+ function inferCsvCellTypeExpression(values) {
6007
+ const nonEmptyValues = values.map((value) => value.trim()).filter((value) => value.length > 0);
6008
+ const hasEmptyValue = values.some((value) => value.trim().length === 0);
6009
+ if (nonEmptyValues.length === 0) return "string";
6010
+ const numericPattern = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:[eE][+-]?\d+)?$/;
6011
+ const booleanPattern = /^(?:true|false)$/i;
6012
+ let inferred = "string";
6013
+ if (nonEmptyValues.every((value) => numericPattern.test(value))) {
6014
+ inferred = "`${number}`";
6015
+ } else if (nonEmptyValues.every((value) => booleanPattern.test(value))) {
6016
+ const canonicalBooleanValues = nonEmptyValues.every(
6017
+ (value) => value === "true" || value === "false"
6018
+ );
6019
+ inferred = canonicalBooleanValues ? '"false" | "true"' : [...new Set(nonEmptyValues)].sort().map(jsString).join(" | ");
6020
+ }
6021
+ return hasEmptyValue && inferred !== "string" ? `${inferred} | ""` : inferred;
6022
+ }
6023
+ function inferCsvColumnSpecs(headers, rows) {
6024
+ return headers.map((header) => ({
6025
+ name: header,
6026
+ typeExpression: inferCsvCellTypeExpression(
6027
+ rows.map((row) => String(row[header] ?? ""))
6028
+ )
6029
+ }));
6030
+ }
6031
+ function readCsvSample(csvPath) {
6032
+ const resolvedPath = (0, import_node_path10.resolve)(csvPath);
6033
+ const size = (0, import_node_fs8.statSync)(resolvedPath).size;
6034
+ const fd = (0, import_node_fs8.openSync)(resolvedPath, "r");
6035
+ const byteLength = Math.min(size, CSV_HEADER_SAMPLE_BYTES);
6036
+ const buffer = Buffer.alloc(byteLength);
6037
+ const bytesRead = (0, import_node_fs8.readSync)(fd, buffer, 0, byteLength, 0);
6038
+ (0, import_node_fs8.closeSync)(fd);
6039
+ if (bytesRead === 0) {
6040
+ throw new PlayBootstrapUsageError(`--from csv:${csvPath} is empty.`);
6041
+ }
6042
+ return {
6043
+ content: buffer.subarray(0, bytesRead).toString("utf8"),
6044
+ truncated: size > bytesRead
6045
+ };
6046
+ }
6047
+ function completeCsvSample(csvPath, sample) {
6048
+ if (!sample.truncated) return sample.content;
6049
+ const lastLineBreak = Math.max(
6050
+ sample.content.lastIndexOf("\n"),
6051
+ sample.content.lastIndexOf("\r")
6052
+ );
6053
+ if (lastLineBreak < 0) {
6054
+ throw new PlayBootstrapUsageError(
6055
+ `CSV header in ${csvPath} is longer than ${CSV_HEADER_SAMPLE_BYTES} bytes; shorten the header row before bootstrapping.`
6056
+ );
6057
+ }
6058
+ return sample.content.slice(0, lastLineBreak + 1);
6059
+ }
6060
+ function readCsvHeaderFields(csvPath, sample) {
6061
+ const records = (0, import_sync4.parse)(sample, {
6062
+ bom: true,
6063
+ to_line: 1,
6064
+ relax_column_count: true,
6065
+ skip_empty_lines: false
6066
+ });
6067
+ const firstRecord = Array.isArray(records) ? records[0] : null;
6068
+ const fields = Array.isArray(firstRecord) ? firstRecord.map((field) => String(field ?? "").trim()).filter(Boolean) : [];
6069
+ const uniqueFields = [...new Set(fields)];
6070
+ if (uniqueFields.length === 0) {
6071
+ throw new PlayBootstrapUsageError(
6072
+ `Could not read a header row from --from csv:${csvPath}.`
6073
+ );
6074
+ }
6075
+ return uniqueFields;
6076
+ }
6077
+ function readCsvSampleRows(sample) {
6078
+ const parsedRows = (0, import_sync4.parse)(sample, {
6079
+ bom: true,
6080
+ columns: true,
6081
+ skip_empty_lines: true,
6082
+ relax_column_count: true,
6083
+ trim: true
6084
+ });
6085
+ return Array.isArray(parsedRows) ? parsedRows.filter(isRecord3) : [];
6086
+ }
6087
+ function readSourceCsvColumnSpecs(csvPath) {
6088
+ const sample = readCsvSample(csvPath);
6089
+ const completeSample = completeCsvSample(csvPath, sample);
6090
+ return inferCsvColumnSpecs(
6091
+ readCsvHeaderFields(csvPath, sample.content),
6092
+ readCsvSampleRows(completeSample)
6093
+ );
6094
+ }
6095
+ function renderSourceCsvRowType(columns) {
6096
+ if (columns.length === 0) return "";
6097
+ const properties = columns.map((column) => ` ${jsString(column.name)}: ${column.typeExpression};`).join("\n");
6098
+ return `// CSV cells are strings at runtime. \`${"${number}"}\` means a numeric-looking CSV string; cast before math.
6099
+ type SourceCsvRow = {
6100
+ ${properties}
6101
+ };
6102
+
6103
+ `;
6104
+ }
6105
+ function packagedCsvPathForPlay(csvPath) {
6106
+ const playDir = process.cwd();
6107
+ const absoluteCsvPath = (0, import_node_path10.resolve)(csvPath);
6108
+ const relativePath = (0, import_node_path10.relative)(playDir, absoluteCsvPath);
6109
+ if (relativePath === "" || relativePath.startsWith("..") || (0, import_node_path10.isAbsolute)(relativePath)) {
6110
+ throw new PlayBootstrapUsageError(
6111
+ `--from csv:${csvPath} must point to a file inside the directory where you run plays bootstrap. Run bootstrap from the intended play directory, then redirect stdout to a .play.ts file there.`
6112
+ );
6113
+ }
6114
+ const portablePath = relativePath.split("\\").join("/");
6115
+ return portablePath.startsWith(".") ? portablePath : `./${portablePath}`;
6116
+ }
6117
+ function getterNamesFromTool(tool, kind) {
6118
+ const usageGuidance = isRecord3(tool?.usageGuidance) ? tool.usageGuidance : {};
6119
+ const resultGuidance = isRecord3(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord3(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
6120
+ const key = kind === "list" ? "extractedLists" : "extractedValues";
6121
+ const snakeKey = kind === "list" ? "extracted_lists" : "extracted_values";
6122
+ return extractionEntries(resultGuidance[key] ?? resultGuidance[snakeKey]).map((entry) => stringValue(entry.name)).filter(Boolean);
6123
+ }
6124
+ function targetGettersFromTool(tool) {
6125
+ const record = isRecord3(tool) ? tool : {};
6126
+ const raw = record.targetGetters ?? record.target_getters;
6127
+ if (!isRecord3(raw)) return {};
6128
+ const entries = [];
6129
+ for (const [target, value] of Object.entries(raw)) {
6130
+ const paths = Array.isArray(value) ? value.map((path) => typeof path === "string" ? path.trim() : "").filter(Boolean) : [];
6131
+ if (target.trim() && paths.length > 0) {
6132
+ entries.push([target.trim(), paths]);
6133
+ }
6134
+ }
6135
+ return Object.fromEntries(entries);
6136
+ }
6137
+ function listRowCandidateKeysFromTool(tool) {
6138
+ const keys = /* @__PURE__ */ new Set();
6139
+ for (const paths of Object.values(targetGettersFromTool(tool))) {
6140
+ for (const path of paths) {
6141
+ const key = path.replace(/\[(?:\*|\d+)\]/g, "").split(/[.[\]]/, 1)[0]?.trim();
6142
+ if (key) keys.add(key);
6143
+ }
6144
+ }
6145
+ return [...keys].sort();
6146
+ }
6147
+ function inputPropertyNames(schema) {
6148
+ if (!isRecord3(schema)) return [];
6149
+ if (isRecord3(schema.properties)) return Object.keys(schema.properties);
6150
+ if (Array.isArray(schema.fields)) {
6151
+ return schema.fields.filter(isRecord3).map((field) => stringValue(field.name)).filter(Boolean);
6152
+ }
6153
+ return [];
6154
+ }
6155
+ function schemaFieldDetails(schema) {
6156
+ const required = requiredPlayInputFields({
6157
+ inputSchema: schema
6158
+ });
6159
+ const optional = inputPropertyNames(schema).filter(
6160
+ (field) => !required.includes(field)
6161
+ );
6162
+ return { required, optional };
6163
+ }
6164
+ function jsonSchemaTypeExpression(schema) {
6165
+ if (!isRecord3(schema)) return "unknown";
6166
+ const type = schema.type;
6167
+ if (Array.isArray(type)) {
6168
+ return type.map((entry) => jsonSchemaTypeExpression({ ...schema, type: entry })).join(" | ");
6169
+ }
6170
+ if (Array.isArray(schema.anyOf)) {
6171
+ return schema.anyOf.map(jsonSchemaTypeExpression).join(" | ");
6172
+ }
6173
+ if (Array.isArray(schema.oneOf)) {
6174
+ return schema.oneOf.map(jsonSchemaTypeExpression).join(" | ");
6175
+ }
6176
+ switch (type) {
6177
+ case "string":
6178
+ return "string";
6179
+ case "number":
6180
+ case "integer":
6181
+ return "number";
6182
+ case "boolean":
6183
+ return "boolean";
6184
+ case "null":
6185
+ return "null";
6186
+ case "array":
6187
+ return `Array<${jsonSchemaTypeExpression(schema.items)}>`;
6188
+ case "object":
6189
+ return "Record<string, unknown>";
6190
+ default:
6191
+ return "unknown";
6192
+ }
6193
+ }
6194
+ function objectPropertySchema(schema, property) {
6195
+ return isRecord3(schema) && isRecord3(schema.properties) ? schema.properties[property] : null;
6196
+ }
6197
+ function finderResultTypeName(finder) {
6198
+ return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
6199
+ }
6200
+ function renderFinderPlayResultType(input) {
6201
+ if (!input.play) return null;
6202
+ const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
6203
+ const fieldSchema = objectPropertySchema(
6204
+ input.play.outputSchema,
6205
+ outputField
6206
+ );
6207
+ const fieldType = fieldSchema ? jsonSchemaTypeExpression(fieldSchema) : "string | null";
6208
+ return `type ${finderResultTypeName(input.finder)} =
6209
+ | string
6210
+ | null
6211
+ | {
6212
+ ${outputField}?: ${fieldType};
6213
+ };`;
6214
+ }
6215
+ function generatedFinderPlayResultTypes(input) {
6216
+ return ["email_finder", "phone_finder"].flatMap((finder) => {
6217
+ const stage = finderStage(input.options, finder);
6218
+ if (stage?.kind !== "play") return [];
6219
+ const typeDefinition = renderFinderPlayResultType({
6220
+ finder,
6221
+ play: input.finderPlays[finder]
6222
+ });
6223
+ return typeDefinition ? [typeDefinition] : [];
6224
+ }).join("\n\n");
6225
+ }
6226
+ function exampleValueComment(field) {
6227
+ if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size") {
6228
+ return "limit";
6229
+ }
6230
+ if (field === "roles" || field.endsWith("s")) return '["..."]';
6231
+ return '"..."';
6232
+ }
6233
+ function generateContactInputObjectFromSchema(schema, indent, label, fallbackFields = ["first_name", "last_name", "domain"]) {
6234
+ const details = schemaFieldDetails(schema);
6235
+ const required = details.required.length ? details.required : fallbackFields;
6236
+ const optional = details.optional;
6237
+ const lines = [
6238
+ `${indent}// TODO: map row fields into ${label}.`,
6239
+ ...playInspectionComments(label, indent),
6240
+ `${indent}// Required: ${required.join(", ") || "none declared"}.`
6241
+ ];
6242
+ for (const field of required) {
6243
+ lines.push(`${indent}// ${field}: row["TODO_SOURCE_FIELD"],`);
6244
+ }
6245
+ if (optional.length > 0) {
6246
+ lines.push("");
6247
+ lines.push(`${indent}// optional (delete unused):`);
6248
+ for (const field of optional) {
6249
+ lines.push(`${indent}// ${field}: row["TODO_SOURCE_FIELD"],`);
6250
+ }
6251
+ }
6252
+ return `{
6253
+ ${lines.join("\n")}
6254
+ ${indent.slice(2)}}`;
6255
+ }
6256
+ function generateCompanyInputObjectFromSchema(schema, indent, label, fallbackFields = ["domain", "company_name"]) {
6257
+ const details = schemaFieldDetails(schema);
6258
+ const required = details.required.length ? details.required : fallbackFields;
6259
+ const optional = details.optional;
6260
+ const lines = [
6261
+ `${indent}// TODO: map company fields into ${label}.`,
6262
+ ...playInspectionComments(label, indent),
6263
+ `${indent}// Required: ${required.join(", ") || "none declared"}.`
6264
+ ];
6265
+ for (const field of required) {
6266
+ lines.push(`${indent}// ${field}: company["TODO_SOURCE_FIELD"],`);
6267
+ }
6268
+ if (optional.length > 0) {
6269
+ lines.push("");
6270
+ lines.push(`${indent}// optional (delete unused):`);
6271
+ for (const field of optional) {
6272
+ lines.push(`${indent}// ${field}: company["TODO_SOURCE_FIELD"],`);
6273
+ }
6274
+ }
6275
+ return `{
6276
+ ${lines.join("\n")}
6277
+ ${indent.slice(2)}}`;
6278
+ }
6279
+ function generateSourceProviderInputObject(input) {
6280
+ const { tool, indent, label, entity } = input;
6281
+ const properties = inputPropertyNames(tool?.inputSchema);
6282
+ const details = schemaFieldDetails(tool?.inputSchema);
6283
+ const required = details.required;
6284
+ const includeOptional = properties.length === 0 ? ["query", "title", "domain", "limit"] : properties.filter(
6285
+ (field) => [
6286
+ "query",
6287
+ "q",
6288
+ "search",
6289
+ "title",
6290
+ "role",
6291
+ "persona",
6292
+ "domain",
6293
+ "company_domain",
6294
+ "limit",
6295
+ "numResults",
6296
+ "num_results",
6297
+ "page_size"
6298
+ ].includes(field)
6299
+ );
6300
+ const lines = [
6301
+ `${indent}// TODO: fill ${entity} source inputs for ${label}.`,
6302
+ `${indent}// Inspect: deepline tools describe ${label} --json`
6303
+ ];
6304
+ for (const field of required) {
6305
+ lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
6306
+ }
6307
+ const activeTodoField = required.length === 0 ? ["query", "q", "search", "title", "role", "persona"].find(
6308
+ (field) => includeOptional.includes(field)
6309
+ ) ?? "query" : null;
6310
+ if (activeTodoField) {
6311
+ lines.push(
6312
+ `${indent}// ${activeTodoField}: ${exampleValueComment(activeTodoField)},`
6313
+ );
6314
+ }
6315
+ const optionalExamples = includeOptional.filter(
6316
+ (field) => !required.includes(field) && field !== activeTodoField
6317
+ );
6318
+ if (optionalExamples.length > 0) {
6319
+ lines.push("");
6320
+ lines.push(`${indent}// optional - uncomment what this provider supports:`);
6321
+ for (const field of optionalExamples) {
6322
+ if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size") {
6323
+ lines.push(`${indent}// ${field}: limit,`);
6324
+ } else {
6325
+ lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
6326
+ }
6327
+ }
6328
+ }
6329
+ if (!required.some(
6330
+ (field) => ["limit", "numResults", "num_results", "page_size"].includes(field)
6331
+ )) {
6332
+ lines.push(`${indent}limit,`);
6333
+ }
6334
+ return `{
6335
+ ${lines.join("\n")}
6336
+ ${indent.slice(2)}}`;
6337
+ }
6338
+ function generatePlayInputObject(input) {
6339
+ const { schema, indent, label, entity } = input;
6340
+ const details = schemaFieldDetails(schema);
6341
+ const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
6342
+ const required = details.required.length ? details.required : fallback;
6343
+ const lines = [
6344
+ `${indent}// TODO: fill source play inputs for ${label}.`,
6345
+ ...playInspectionComments(label, indent)
6346
+ ];
6347
+ for (const field of required) {
6348
+ lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
6349
+ }
6350
+ if (!required.includes("limit")) lines.push(`${indent}limit,`);
6351
+ return `{
6352
+ ${lines.join("\n")}
6353
+ ${indent.slice(2)}}`;
6354
+ }
6355
+ function requiredPlayInputFields(play) {
6356
+ const schema = play?.inputSchema;
6357
+ if (!isRecord3(schema)) return [];
6358
+ if (Array.isArray(schema.required)) {
6359
+ return schema.required.filter(
6360
+ (value) => typeof value === "string"
6361
+ );
6362
+ }
6363
+ if (Array.isArray(schema.fields)) {
6364
+ return schema.fields.filter(isRecord3).filter(
6365
+ (field) => field.required === true && typeof field.name === "string"
6366
+ ).map((field) => String(field.name));
6367
+ }
6368
+ return [];
6369
+ }
6370
+ function sourceProviders(options) {
6371
+ return options.from.kind === "providers" ? options.from.values : [];
6372
+ }
6373
+ function sourcePlayRef(options) {
6374
+ return options.from.kind === "play" ? options.from.value : null;
6375
+ }
6376
+ function stagePlayRef(stage) {
6377
+ return stage?.kind === "play" ? stage.value : null;
6378
+ }
6379
+ function stageProviders(stage) {
6380
+ return stage?.kind === "providers" ? stage.values : [];
6381
+ }
6382
+ function finderStage(options, finder) {
6383
+ return finder === "email_finder" ? options.email : options.phone;
6384
+ }
6385
+ function stepFieldName(finder) {
6386
+ return PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[finder];
6387
+ }
6388
+ function finderProviderStepPrefix(finder) {
6389
+ return finder === "email_finder" ? "emailFinder" : "phoneFinder";
6390
+ }
6391
+ function safeIdentifier(value) {
6392
+ return value.replace(/[^A-Za-z0-9_]+/g, "_");
6393
+ }
6394
+ function playInspectionComments(playRef, indent) {
6395
+ return [`${indent}// Inspect: deepline plays describe ${playRef} --json`];
6396
+ }
6397
+ function accessorExpression(base, field) {
6398
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(field) ? `${base}.${field}` : `${base}[${jsString(field)}]`;
6399
+ }
6400
+ function needsWhenImport(options) {
6401
+ return stageProviders(options.email).length > 1 || stageProviders(options.phone).length > 1;
6402
+ }
6403
+ function sourceCollectionTypeName(entity) {
6404
+ return entity === "company" ? "CompanySourceRow" : "ContactSourceRow";
6405
+ }
6406
+ function renderPartialRowType(input) {
6407
+ if (input.fields.length === 0) {
6408
+ return `type ${input.typeName} = Record<string, unknown>;`;
6409
+ }
6410
+ const properties = input.fields.map((field) => ` ${jsString(field)}?: unknown;`).join("\n");
6411
+ return `type ${input.typeName} = Record<string, unknown> & Partial<{
6412
+ // ${input.comment}
6413
+ ${properties}
6414
+ }>;`;
6415
+ }
6416
+ function fieldsFromSchemaDetails(input) {
6417
+ return [
6418
+ ...input.details.required.length ? input.details.required : input.fallbackFields,
6419
+ ...input.details.optional
6420
+ ];
6421
+ }
6422
+ function schemaFieldsForStage(stage, input) {
6423
+ switch (stage?.kind) {
6424
+ case void 0:
6425
+ return [];
6426
+ case "play":
6427
+ return fieldsFromSchemaDetails({
6428
+ details: schemaFieldDetails(input.play?.inputSchema),
6429
+ fallbackFields: input.fallbackFields
6430
+ });
6431
+ case "providers":
6432
+ return input.tools.flatMap(
6433
+ (tool) => fieldsFromSchemaDetails({
6434
+ details: schemaFieldDetails(tool.inputSchema),
6435
+ fallbackFields: input.fallbackFields
6436
+ })
6437
+ );
6438
+ }
6439
+ }
6440
+ function sourceRowTypeDefinition(input) {
6441
+ switch (input.options.from.kind) {
6442
+ case "csv":
6443
+ return `type ${input.sourceTypeName} = SourceCsvRow;`;
6444
+ case "providers":
6445
+ return renderPartialRowType({
6446
+ typeName: input.sourceTypeName,
6447
+ fields: [
6448
+ ...new Set(input.sourceTools.flatMap(listRowCandidateKeysFromTool))
6449
+ ].sort(),
6450
+ comment: "Candidate source row keys from described list getters; confirm the actual provider keys with source_*.extractedLists.*.keys before mapping."
6451
+ });
6452
+ case "play": {
6453
+ const details = schemaFieldDetails(input.sourcePlay?.outputSchema);
6454
+ return renderPartialRowType({
6455
+ typeName: input.sourceTypeName,
6456
+ fields: [...details.required, ...details.optional].sort(),
6457
+ comment: "Candidate source play output fields; confirm the selected rows field before mapping."
6458
+ });
6459
+ }
6460
+ }
6461
+ }
6462
+ function contactBridgeRowTypeDefinition(input) {
6463
+ const config = playBootstrapTemplateConfig(input.options.template);
6464
+ if (config.sourceEntity !== "company" || !input.options.people) return null;
6465
+ const emailFields = schemaFieldsForStage(input.options.email, {
6466
+ tools: input.finderTools.email_finder ?? [],
6467
+ play: input.finderPlays.email_finder,
6468
+ fallbackFields: ["first_name", "last_name", "domain"]
6469
+ });
6470
+ const phoneFields = schemaFieldsForStage(input.options.phone, {
6471
+ tools: input.finderTools.phone_finder ?? [],
6472
+ play: input.finderPlays.phone_finder,
6473
+ fallbackFields: ["first_name", "last_name", "domain"]
6474
+ });
6475
+ return renderPartialRowType({
6476
+ typeName: "ContactSourceRow",
6477
+ fields: [
6478
+ .../* @__PURE__ */ new Set([
6479
+ ...inputPropertyNames(input.peoplePlay?.outputSchema),
6480
+ ...emailFields,
6481
+ ...phoneFields
6482
+ ])
6483
+ ].sort(),
6484
+ comment: "Fields the people play or later finder stages may need; the generated code still requires explicit mapping."
6485
+ });
6486
+ }
6487
+ function generateRowTypeDefinitions(input) {
6488
+ const config = playBootstrapTemplateConfig(input.options.template);
6489
+ const sourceTypeName = sourceCollectionTypeName(config.sourceEntity);
6490
+ const definitions = [
6491
+ sourceRowTypeDefinition({
6492
+ options: input.options,
6493
+ sourceTypeName,
6494
+ sourceTools: input.sourceTools,
6495
+ sourcePlay: input.sourcePlay
6496
+ }),
6497
+ contactBridgeRowTypeDefinition(input)
6498
+ ];
6499
+ return definitions.filter(Boolean).join("\n\n");
6500
+ }
6501
+ function validateBootstrapRoutes(input) {
6502
+ const config = playBootstrapTemplateConfig(input.options.template);
6503
+ const sourceCategory = config.sourceEntity === "company" ? PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY : PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY;
6504
+ for (const tool of input.sourceTools) {
6505
+ if (!tool.categories.includes(sourceCategory)) {
6506
+ throw new PlayBootstrapValidationError(
6507
+ `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`
6508
+ );
6509
+ }
6510
+ if (getterNamesFromTool(tool, "list").length === 0) {
6511
+ throw new PlayBootstrapValidationError(
6512
+ `Cannot use ${tool.toolId} as a ${config.sourceEntity} source: it exposes no extracted list getters. Run: deepline tools describe ${tool.toolId} --json`
6513
+ );
6514
+ }
6515
+ }
6516
+ if (input.options.people?.kind === "providers") {
6517
+ throw new PlayBootstrapValidationError(
6518
+ "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."
6519
+ );
6520
+ }
6521
+ for (const finder of ["email_finder", "phone_finder"]) {
6522
+ const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
6523
+ for (const tool of input.finderTools[finder] ?? []) {
6524
+ if (!tool.categories.includes(requiredCategory)) {
6525
+ throw new PlayBootstrapValidationError(
6526
+ `Cannot use ${tool.toolId} for ${finder}: expected category ${requiredCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${requiredCategory} --categories ${requiredCategory} --json`
6527
+ );
6528
+ }
6529
+ if (getterNamesFromTool(tool, "value").length === 0) {
6530
+ throw new PlayBootstrapValidationError(
6531
+ `Cannot use ${tool.toolId} as a ${finder}: it exposes no extracted value getters. Run: deepline tools describe ${tool.toolId} --json`
6532
+ );
6533
+ }
6534
+ }
6535
+ }
6536
+ }
6537
+ function sourceCollectionName(entity) {
6538
+ switch (entity) {
6539
+ case "company":
6540
+ return "companies";
6541
+ case "people":
6542
+ return "contacts";
6543
+ }
6544
+ }
6545
+ function requiredGetterName(input) {
6546
+ const getter = getterNamesFromTool(input.tool, input.kind)[0];
6547
+ if (!getter) {
6548
+ switch (input.kind) {
6549
+ case "list":
6550
+ throw new PlayBootstrapValidationError(
6551
+ `Cannot use ${input.label} as a source: it exposes no extracted list getters.`
6552
+ );
6553
+ case "value":
6554
+ throw new PlayBootstrapValidationError(
6555
+ `Cannot use ${input.label} as a finder: it exposes no extracted value getters.`
6556
+ );
6557
+ }
6558
+ }
6559
+ return getter;
6560
+ }
6561
+ function generateCsvSourceRowsBlock(input) {
6562
+ return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(input.packagedSourceCsvPath ?? input.source.value)});
6563
+ const ${input.collection}: ${input.collectionType}[] = await sourceDataset.peek(limit);`;
6564
+ }
6565
+ function generatePlaySourceRowsBlock(input) {
6566
+ const playInput = generatePlayInputObject({
6567
+ schema: input.sourcePlay?.inputSchema,
6568
+ indent: " ",
6569
+ label: input.source.value,
6570
+ entity: input.entity
6571
+ });
6572
+ return `const sourceInput = ${playInput};
6573
+ throw new Error(${jsString(`TODO: map sourceInput for ${input.source.value}, choose the play output rows field, then delete this throw.`)});
6574
+ const sourceResult = await ctx.runPlay('source_play', ${jsString(input.source.value)}, sourceInput, {
6575
+ description: ${jsString(`Seed ${input.entity} rows from the selected play.`)},
6576
+ });
6577
+ // TODO: Replace sourceResult.rows with the selected play's actual row output field.
6578
+ const ${input.collection}: ${input.collectionType}[] = (sourceResult.rows ?? []) as ${input.collectionType}[];`;
6579
+ }
6580
+ function generateProviderSourceBlock(input) {
6581
+ const getter = requiredGetterName({
6582
+ tool: input.tool,
6583
+ kind: "list",
6584
+ label: input.provider
6585
+ });
6586
+ const inputName = `${input.entity}Input_${input.index}`;
6587
+ return `// ${input.entity === "company" ? "Company" : "People"} source provider: ${input.provider}
6588
+ const ${inputName}: Record<string, unknown> = ${generateSourceProviderInputObject(
6589
+ {
6590
+ tool: input.tool,
6591
+ indent: " ",
6592
+ label: input.provider,
6593
+ entity: input.entity
6594
+ }
6595
+ )};
6596
+ throw new Error(${jsString(`TODO: fill ${inputName} for ${input.provider}, then delete this throw.`)});
6597
+ const source_${input.index} = await ctx.tools.execute({
6598
+ id: ${jsString(`${input.entity}_source_${input.index}`)},
6599
+ tool: ${jsString(input.provider)},
6600
+ input: ${inputName},
6601
+ description: ${jsString(`Seed ${input.entity} rows from ${input.provider}.`)},
6602
+ });
6603
+ // extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
6604
+ // inspect source_${input.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
6605
+ const sourceRows_${input.index} = ${accessorExpression(`source_${input.index}.extractedLists`, getter)}.get() as ${input.collectionType}[];`;
6606
+ }
6607
+ function generateProviderSourceRowsBlock(input) {
6608
+ const blocks = input.source.values.map(
6609
+ (provider, index) => generateProviderSourceBlock({
6610
+ provider,
6611
+ index,
6612
+ tool: input.sourceTools[index] ?? null,
6613
+ entity: input.entity,
6614
+ collectionType: input.collectionType
6615
+ })
6616
+ );
6617
+ return `${blocks.join("\n\n ")}
6618
+ const ${input.collection}: ${input.collectionType}[] = [${input.source.values.map((_, index) => `...sourceRows_${index}`).join(", ")}];`;
6619
+ }
6620
+ function generateSourceRowsBlock(input) {
6621
+ const config = playBootstrapTemplateConfig(input.options.template);
6622
+ const entity = config.sourceEntity;
6623
+ const collection = sourceCollectionName(entity);
6624
+ const collectionType = sourceCollectionTypeName(entity);
6625
+ switch (input.options.from.kind) {
6626
+ case "csv":
6627
+ return generateCsvSourceRowsBlock({
6628
+ source: input.options.from,
6629
+ collection,
6630
+ collectionType,
6631
+ packagedSourceCsvPath: input.packagedSourceCsvPath
6632
+ });
6633
+ case "play":
6634
+ return generatePlaySourceRowsBlock({
6635
+ source: input.options.from,
6636
+ sourcePlay: input.sourcePlay,
6637
+ entity,
6638
+ collection,
6639
+ collectionType
6640
+ });
6641
+ case "providers":
6642
+ return generateProviderSourceRowsBlock({
6643
+ source: input.options.from,
6644
+ sourceTools: input.sourceTools,
6645
+ entity,
6646
+ collection,
6647
+ collectionType
6648
+ });
6649
+ }
6650
+ }
6651
+ function generateSourceSeedBlock(input) {
6652
+ const sourceRows = generateSourceRowsBlock(input);
6653
+ const peoplePlayRef = stagePlayRef(input.options.people);
6654
+ if (!peoplePlayRef) return sourceRows;
6655
+ const peopleInput = generateCompanyInputObjectFromSchema(
6656
+ input.peoplePlay?.inputSchema,
6657
+ " ",
6658
+ peoplePlayRef,
6659
+ ["domain", "company_name"]
6660
+ );
6661
+ return `${sourceRows}
6662
+ const contacts: ContactSourceRow[] = [];
6663
+ for (const [index, company] of companies.slice(0, limit).entries()) {
6664
+ const peopleInput = ${peopleInput};
6665
+ throw new Error(${jsString(`TODO: map company fields into peopleInput for ${peoplePlayRef}, choose the play output rows field, then delete this throw.`)});
6666
+ const peopleResult = await ctx.runPlay(
6667
+ \`people_play_\${index}\`,
6668
+ ${jsString(peoplePlayRef)},
6669
+ peopleInput,
6670
+ {
6671
+ description: 'Map one company row into people/contact rows with the selected play.',
6672
+ },
6673
+ );
6674
+ // TODO: Replace peopleResult.rows with the selected play's actual contact rows field.
6675
+ contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
6676
+ }`;
6677
+ }
6678
+ function finderProviderStepName(input) {
6679
+ return `${input.aggregateStepName}${input.index}_${safeIdentifier(input.provider)}`;
6680
+ }
6681
+ function finderValueGetter(input) {
6682
+ const getters = getterNamesFromTool(input.tool, "value");
6683
+ const getter = getters.find((name) => name === input.outputField) ?? requiredGetterName({
6684
+ tool: input.tool,
6685
+ kind: "value",
6686
+ label: input.provider
6687
+ });
6688
+ return getter;
6689
+ }
6690
+ function optionalFinderValueExpression(candidateExpression, outputField) {
6691
+ const valueExpression = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(outputField) ? `${candidateExpression}?.${outputField}` : `${candidateExpression}?.[${jsString(outputField)}]`;
6692
+ return `${valueExpression}?.trim()`;
6693
+ }
6694
+ function generateFinderPlayStep(input) {
6695
+ const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
6696
+ const resultTypeName = finderResultTypeName(input.finder);
6697
+ const payload = generateContactInputObjectFromSchema(
6698
+ input.play?.inputSchema,
6699
+ " ",
6700
+ input.stage.value
6701
+ );
6702
+ return `.step(${jsString(outputField)}, async (row, rowCtx) => {
6703
+ const ${input.aggregateStepName}Input = ${payload};
6704
+ throw new Error(${jsString(`TODO: map ${input.aggregateStepName}Input for ${input.stage.value}, then delete this throw.`)});
6705
+ const ${input.aggregateStepName}Result = await rowCtx.runPlay<${resultTypeName}>(
6706
+ ${jsString(`${input.aggregateStepName}Play`)},
6707
+ ${jsString(input.stage.value)},
6708
+ ${input.aggregateStepName}Input,
6709
+ {
6710
+ description: ${jsString(`Run ${input.finder} play.`)},
6711
+ },
6712
+ );
6713
+ return typeof ${input.aggregateStepName}Result === 'string'
6714
+ ? ${input.aggregateStepName}Result.trim() || null
6715
+ : ${input.aggregateStepName}Result?.${outputField} ?? null;
6716
+ })`;
6717
+ }
6718
+ function generateFinderProviderResolver(input) {
6719
+ const payload = generateContactInputObjectFromSchema(
6720
+ input.tool?.inputSchema,
6721
+ " ",
6722
+ input.provider
6723
+ );
6724
+ const getter = finderValueGetter({
6725
+ tool: input.tool,
6726
+ provider: input.provider,
6727
+ outputField: input.outputField
6728
+ });
6729
+ return `async (row, rowCtx) => {
6730
+ const providerInput = ${payload};
6731
+ throw new Error(${jsString(`TODO: map providerInput for ${input.provider}, then delete this throw.`)});
6732
+ const result = await rowCtx.tools.execute({
6733
+ id: ${jsString(`${input.aggregateStepName}_${input.providerIndex}`)},
6734
+ tool: ${jsString(input.provider)},
6735
+ input: providerInput,
6736
+ description: ${jsString(`Try ${input.provider} as a ${input.finder}.`)},
6737
+ });
6738
+ return {
6739
+ ${input.outputField}: (${accessorExpression("result.extractedValues", getter)}.get() as string | null) ?? null,
6740
+ result,
6741
+ };
6742
+ }`;
6743
+ }
6744
+ function generateFinderProviderStep(input) {
6745
+ const stepName = input.stepNames[input.index];
6746
+ switch (input.index) {
6747
+ case 0:
6748
+ return `.step(${jsString(stepName)}, ${input.resolver})`;
6749
+ default: {
6750
+ const priorCandidates = input.stepNames.slice(0, input.index).map((name) => `row.${name}`).join(", ");
6751
+ return `.step(
6752
+ ${jsString(stepName)},
6753
+ when(
6754
+ (row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate", input.outputField)}),
6755
+ ${input.resolver},
6756
+ ),
6757
+ )`;
6758
+ }
6759
+ }
6760
+ }
6761
+ function generateFinderProviderWaterfall(input) {
6762
+ const legPrefix = finderProviderStepPrefix(input.finder);
6763
+ const stepNames = input.stage.values.map(
6764
+ (provider, index) => finderProviderStepName({
6765
+ aggregateStepName: legPrefix,
6766
+ provider,
6767
+ index
6768
+ })
6769
+ );
6770
+ const providerSteps = input.stage.values.map(
6771
+ (provider, index) => generateFinderProviderStep({
6772
+ index,
6773
+ stepNames,
6774
+ outputField: input.outputField,
6775
+ resolver: generateFinderProviderResolver({
6776
+ finder: input.finder,
6777
+ provider,
6778
+ providerIndex: index,
6779
+ tool: input.tools[index] ?? null,
6780
+ aggregateStepName: input.aggregateStepName,
6781
+ outputField: input.outputField
6782
+ })
6783
+ })
6784
+ );
6785
+ const candidateNames = stepNames.map((name) => `row.${name}`).join(", ");
6786
+ return `// ${input.aggregateStepName} provider waterfall. Each provider leg is active once its TODO throw is removed;
6787
+ // delete or comment out legs you do not want before running. Later legs are gated with when(...).
6788
+ ${providerSteps.join("\n ")}
6789
+ .step(${jsString(input.aggregateStepName)}, (row) => {
6790
+ const candidates = [${candidateNames}];
6791
+ const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate", input.outputField)});
6792
+ return ${optionalFinderValueExpression("match", input.outputField)} ?? null;
6793
+ })`;
6794
+ }
6795
+ function generateFinderStageSteps(input) {
6796
+ const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
6797
+ const aggregateStepName = stepFieldName(input.finder);
6798
+ switch (input.stage.kind) {
6799
+ case "play":
6800
+ return generateFinderPlayStep({
6801
+ finder: input.finder,
6802
+ stage: input.stage,
6803
+ play: input.finderPlays[input.finder],
6804
+ aggregateStepName
6805
+ });
6806
+ case "providers":
6807
+ return generateFinderProviderWaterfall({
6808
+ finder: input.finder,
6809
+ stage: input.stage,
6810
+ tools: input.finderTools[input.finder] ?? [],
6811
+ aggregateStepName,
6812
+ outputField
6813
+ });
6814
+ }
6815
+ }
6816
+ function generateFinderSteps(input) {
6817
+ return ["email_finder", "phone_finder"].flatMap((finder) => {
6818
+ const stage = finderStage(input.options, finder);
6819
+ return stage ? [
6820
+ generateFinderStageSteps({
6821
+ ...input,
6822
+ finder,
6823
+ stage
6824
+ })
6825
+ ] : [];
6826
+ }).join("\n ");
6827
+ }
6828
+ function generateBootstrapPlaySource(input) {
6829
+ const config = playBootstrapTemplateConfig(input.options.template);
6830
+ const sourceSeedBlock = generateSourceSeedBlock(input);
6831
+ const finderSteps = generateFinderSteps(input);
6832
+ const hasPeople = config.sourceEntity === "people" || Boolean(input.options.people);
6833
+ const sourceCollection = hasPeople ? "contacts" : "companies";
6834
+ const mapSteps = finderSteps ? `
6835
+ ${finderSteps}` : "";
6836
+ const sourceCsvRowType = input.options.from.kind === "csv" ? renderSourceCsvRowType(input.sourceCsvColumns) : "";
6837
+ const rowTypeDefinitions = generateRowTypeDefinitions(input);
6838
+ const finderPlayResultTypes = generatedFinderPlayResultTypes(input);
6839
+ const typeDefinitions = [
6840
+ sourceCsvRowType.trimEnd(),
6841
+ rowTypeDefinitions,
6842
+ finderPlayResultTypes
6843
+ ].filter((definition) => definition.trim().length > 0).join("\n\n");
6844
+ const importNames = needsWhenImport(input.options) ? "definePlay, when" : "definePlay";
6845
+ return `import { ${importNames} } from 'deepline';
6846
+
6847
+ ${typeDefinitions}
6848
+
6849
+ type Input = {
6850
+ limit?: number;
6851
+ };
6852
+
6853
+ export default definePlay(${jsString(input.options.name)}, async (ctx, input: Input = {}) => {
6854
+ const limit = Math.max(1, Math.min(Number(input.limit ?? ${input.options.limit}), ${input.options.limit}));
6855
+ ${sourceSeedBlock}
6856
+
6857
+ const rowsToProcess = ${sourceCollection}.slice(0, limit);
6858
+ if (rowsToProcess.length === 0) {
6859
+ throw new Error('plays bootstrap found 0 source rows. Check the source provider/play/CSV output.');
6860
+ }
6861
+
6862
+ const rows = await ctx
6863
+ .map('bootstrap_rows', rowsToProcess)${mapSteps}
6864
+ .run({
6865
+ key: (_row, index) => index,
6866
+ description: ${jsString(`Bootstrap ${input.options.template}: seed source rows, run requested stages, then return the mapped rows.`)},
6867
+ });
6868
+
6869
+ return {
6870
+ count: await rows.count(),
6871
+ rows,
6872
+ };
6873
+ });
6874
+
6875
+ `;
6876
+ }
6877
+ async function describePlayMaybe(client, playRef) {
6878
+ return playRef ? client.describePlay(playRef, { compact: true }) : null;
6879
+ }
6880
+ function loadTools(client, providers) {
6881
+ return Promise.all(providers.map((provider) => client.getTool(provider)));
6882
+ }
6883
+ async function loadBootstrapContracts(client, options) {
6884
+ const [
6885
+ sourceTools,
6886
+ sourcePlay,
6887
+ peoplePlay,
6888
+ emailPlay,
6889
+ phonePlay,
6890
+ emailTools,
6891
+ phoneTools
6892
+ ] = await Promise.all([
6893
+ loadTools(client, sourceProviders(options)),
6894
+ describePlayMaybe(client, sourcePlayRef(options)),
6895
+ describePlayMaybe(client, stagePlayRef(options.people)),
6896
+ describePlayMaybe(client, stagePlayRef(options.email)),
6897
+ describePlayMaybe(client, stagePlayRef(options.phone)),
6898
+ loadTools(client, stageProviders(options.email)),
6899
+ loadTools(client, stageProviders(options.phone))
6900
+ ]);
6901
+ const contracts = {
6902
+ sourceTools,
6903
+ sourcePlay,
6904
+ peoplePlay,
6905
+ finderTools: {
6906
+ email_finder: emailTools,
6907
+ phone_finder: phoneTools
6908
+ },
6909
+ finderPlays: {
6910
+ email_finder: emailPlay,
6911
+ phone_finder: phonePlay
6912
+ }
6913
+ };
6914
+ validateBootstrapRoutes({
6915
+ options,
6916
+ sourceTools: contracts.sourceTools,
6917
+ peoplePlay: contracts.peoplePlay,
6918
+ finderTools: contracts.finderTools,
6919
+ finderPlays: contracts.finderPlays
6920
+ });
6921
+ return contracts;
6922
+ }
6923
+ function loadCsvContext(source) {
6924
+ switch (source.kind) {
6925
+ case "csv":
6926
+ return {
6927
+ packagedSourceCsvPath: packagedCsvPathForPlay(source.value),
6928
+ sourceCsvColumns: readSourceCsvColumnSpecs(source.value)
6929
+ };
6930
+ case "play":
6931
+ case "providers":
6932
+ return {
6933
+ packagedSourceCsvPath: null,
6934
+ sourceCsvColumns: []
6935
+ };
6936
+ }
6937
+ }
6938
+ function errorMessage(error) {
6939
+ return error instanceof Error ? error.message : String(error);
6940
+ }
6941
+ function renderPlayBootstrapError(error) {
6942
+ console.error(errorMessage(error));
6943
+ return error instanceof PlayBootstrapError ? error.exitCode : 1;
6944
+ }
6945
+ async function runPlayBootstrap(args) {
6946
+ const options = parsePlayBootstrapOptions(args);
6947
+ const client = new DeeplineClient();
6948
+ const contracts = await loadBootstrapContracts(client, options);
6949
+ const csvContext = loadCsvContext(options.from);
6950
+ const source = generateBootstrapPlaySource({
6951
+ options,
6952
+ ...contracts,
6953
+ ...csvContext
6954
+ });
6955
+ process.stdout.write(source);
6956
+ return 0;
6957
+ }
6958
+ async function handlePlayBootstrap(args) {
6959
+ return runPlayBootstrap(args).catch(renderPlayBootstrapError);
6960
+ }
6961
+ function registerPlayBootstrapCommand(play) {
6962
+ play.command("bootstrap <template>").description("Print a scratchpad play for a GTM route template.").addHelpText(
6963
+ "after",
6964
+ `
6965
+ Notes:
6966
+ Cloud-validated play generator for agents. Pick the JTBD as the positional
6967
+ template, bind resources with typed refs, redirect stdout to a .play.ts file,
6968
+ then edit the generated TODO mapping comments. Multiple finder providers are
6969
+ generated as a waterfall in the order you pass them.
6970
+
6971
+ This command requires auth because provider/play contracts are fetched from
6972
+ Deepline. It prints TypeScript source only and does not run paid tools; the
6973
+ generated play may spend credits later when you run it.
6974
+
6975
+ stdout is the generated .play.ts source. Errors and diagnostics go to stderr.
6976
+ There is no JSON mode and no --out; use shell redirection:
6977
+ deepline plays bootstrap ... > scratchpad.play.ts
6978
+
6979
+ Templates:
6980
+ people-list start from people/contact rows
6981
+ company-list start from company/account rows
6982
+ people-email people/contact rows -> email finder
6983
+ people-phone people/contact rows -> phone finder
6984
+ company-people company/account rows -> people play
6985
+ company-people-email company/account rows -> people play -> email finder
6986
+ company-people-phone company/account rows -> people play -> phone finder
6987
+
6988
+ Resource refs:
6989
+ csv:./contacts.csv
6990
+ play:prebuilt/name-and-domain-to-email-waterfall
6991
+ provider:dropleads_search_people
6992
+ providers:hunter_email_finder,leadmagic_email_finder
6993
+
6994
+ Validation:
6995
+ source providers must match the route entity: company_search or people_search
6996
+ source providers must expose list getters
6997
+ company -> people uses a play only; provider bridge is generated later when a play exists
6998
+ email/phone finder providers must match their category and expose value getters
6999
+ finder plays/providers must match the route; generated code leaves input mapping explicit
7000
+ business-specific provider inputs and company -> people persona fields are TODOs in code
7001
+ csv: paths are resolved from the directory where you run bootstrap; redirect the play file there too
7002
+
7003
+ Exit codes:
7004
+ 0 success
7005
+ 2 usage/local input error
7006
+ 7 route validation failed
7007
+
7008
+ Examples:
7009
+ deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall --limit 5 > email-flow.play.ts
7010
+ deepline plays check email-flow.play.ts
7011
+ deepline plays run email-flow.play.ts --input '{"limit":5}' --watch
7012
+
7013
+ deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5 > prospecting.play.ts
7014
+ deepline plays bootstrap company-people-email --from provider:apollo_company_search --people play:prebuilt/company-to-contact --email play:prebuilt/name-and-domain-to-email-waterfall --limit 5 > account-contacts.play.ts
7015
+ deepline plays bootstrap company-list --from provider:apollo_company_search --limit 5 > companies.play.ts
7016
+ `
7017
+ ).option("--name <name>", "Generated play name").option(
7018
+ "--from <ref>",
7019
+ "Route source: csv:PATH, play:REF, provider:ID, or providers:ID,ID"
7020
+ ).option(
7021
+ "--using <ref>",
7022
+ "Single-stage route shorthand for people-email, people-phone, or company-people"
7023
+ ).option(
7024
+ "--people <ref>",
7025
+ "Company-to-people stage for company-people-email/phone; use play:REF"
7026
+ ).option(
7027
+ "--email <ref>",
7028
+ "Email finder stage: play:REF, provider:ID, or providers:ID,ID"
7029
+ ).option(
7030
+ "--phone <ref>",
7031
+ "Phone finder stage: play:REF, provider:ID, or providers:ID,ID"
7032
+ ).option("--limit <n>", "Maximum rows to fan out in the generated play").action(async (template, options) => {
7033
+ process.exitCode = await handlePlayBootstrap([
7034
+ template,
7035
+ ...options.name ? ["--name", options.name] : [],
7036
+ ...options.from ? ["--from", options.from] : [],
7037
+ ...options.using ? ["--using", options.using] : [],
7038
+ ...options.people ? ["--people", options.people] : [],
7039
+ ...options.email ? ["--email", options.email] : [],
7040
+ ...options.phone ? ["--phone", options.phone] : [],
7041
+ ...options.limit ? ["--limit", options.limit] : []
7042
+ ]);
7043
+ });
7044
+ }
7045
+
5593
7046
  // src/cli/progress.ts
5594
7047
  var import_node_worker_threads = require("worker_threads");
5595
7048
  var CliProgress = class {
@@ -6041,9 +7494,9 @@ function traceCliSync(phase, fields, run) {
6041
7494
  }
6042
7495
  }
6043
7496
  function sleep4(ms) {
6044
- return new Promise((resolve11) => setTimeout(resolve11, ms));
7497
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
6045
7498
  }
6046
- function parseReferencedPlayTarget(target) {
7499
+ function parseReferencedPlayTarget2(target) {
6047
7500
  const trimmed = target.trim();
6048
7501
  const slashIndex = trimmed.indexOf("/");
6049
7502
  if (slashIndex <= 0 || slashIndex === trimmed.length - 1) {
@@ -6064,7 +7517,7 @@ function buildBarePrebuiltReferenceError(input) {
6064
7517
  );
6065
7518
  }
6066
7519
  async function assertCanonicalNamedPlayReference(client, target) {
6067
- const parsed = parseReferencedPlayTarget(target);
7520
+ const parsed = parseReferencedPlayTarget2(target);
6068
7521
  const detail = await client.getPlay(parsed.playName);
6069
7522
  if (detail.play.ownerType === "deepline" && !isPrebuiltReferenceTarget(target)) {
6070
7523
  throw buildBarePrebuiltReferenceError({
@@ -6085,10 +7538,10 @@ function formatPlayListReference(play) {
6085
7538
  return play.reference || play.name;
6086
7539
  }
6087
7540
  function defaultMaterializedPlayPath(reference) {
6088
- return (0, import_node_path10.resolve)(defaultStarterPlayPath(reference));
7541
+ return (0, import_node_path11.resolve)(defaultStarterPlayPath(reference));
6089
7542
  }
6090
7543
  function defaultStarterPlayPath(reference) {
6091
- const playName = parseReferencedPlayTarget(reference).unqualifiedPlayName;
7544
+ const playName = parseReferencedPlayTarget2(reference).unqualifiedPlayName;
6092
7545
  const safeName = playName.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
6093
7546
  return `./${safeName || "play"}.play.ts`;
6094
7547
  }
@@ -6111,15 +7564,15 @@ function materializeRemotePlaySource(input) {
6111
7564
  return null;
6112
7565
  }
6113
7566
  const outputPath = input.outPath ?? defaultMaterializedPlayPath(input.playName);
6114
- if ((0, import_node_fs8.existsSync)(outputPath)) {
6115
- const existingSource = (0, import_node_fs8.readFileSync)(outputPath, "utf-8");
7567
+ if ((0, import_node_fs9.existsSync)(outputPath)) {
7568
+ const existingSource = (0, import_node_fs9.readFileSync)(outputPath, "utf-8");
6116
7569
  if (existingSource === input.sourceCode) {
6117
7570
  return { path: outputPath, status: "unchanged", created: false };
6118
7571
  }
6119
- (0, import_node_fs8.writeFileSync)(outputPath, input.sourceCode, "utf-8");
7572
+ (0, import_node_fs9.writeFileSync)(outputPath, input.sourceCode, "utf-8");
6120
7573
  return { path: outputPath, status: "updated", created: false };
6121
7574
  }
6122
- (0, import_node_fs8.writeFileSync)(outputPath, input.sourceCode, "utf-8");
7575
+ (0, import_node_fs9.writeFileSync)(outputPath, input.sourceCode, "utf-8");
6123
7576
  return { path: outputPath, status: "created", created: true };
6124
7577
  }
6125
7578
  function formatLoadedPlayMessage(materializedFile) {
@@ -6144,7 +7597,7 @@ To make your own version:
6144
7597
  );
6145
7598
  }
6146
7599
  async function ensureEditableRemotePlay(client, target) {
6147
- const parsed = parseReferencedPlayTarget(target);
7600
+ const parsed = parseReferencedPlayTarget2(target);
6148
7601
  const detail = await client.getPlay(parsed.playName);
6149
7602
  if (detail.play.ownerType === "deepline") {
6150
7603
  throw buildReadonlyPrebuiltPlayError(formatPlayReference(detail.play));
@@ -6164,7 +7617,7 @@ function extractPlayName(code, filePath) {
6164
7617
  throw buildMissingDefinePlayError(filePath);
6165
7618
  }
6166
7619
  function isFileTarget(target) {
6167
- return (0, import_node_fs8.existsSync)((0, import_node_path10.resolve)(target));
7620
+ return (0, import_node_fs9.existsSync)((0, import_node_path11.resolve)(target));
6168
7621
  }
6169
7622
  function looksLikeRunId(target) {
6170
7623
  return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
@@ -6185,7 +7638,7 @@ function looksLikeFilePath(target) {
6185
7638
  }
6186
7639
  return target.includes("\\") || /\.(ts|js|mjs|play\.ts)$/.test(target);
6187
7640
  }
6188
- function parsePositiveInteger2(value, flagName) {
7641
+ function parsePositiveInteger3(value, flagName) {
6189
7642
  const parsed = Number.parseInt(value, 10);
6190
7643
  if (!Number.isFinite(parsed) || parsed <= 0) {
6191
7644
  throw new Error(`${flagName} must be a positive integer.`);
@@ -6193,7 +7646,7 @@ function parsePositiveInteger2(value, flagName) {
6193
7646
  return parsed;
6194
7647
  }
6195
7648
  function parseJsonInput(raw) {
6196
- const source = raw.startsWith("@") ? (0, import_node_fs8.readFileSync)((0, import_node_path10.resolve)(raw.slice(1)), "utf-8") : raw;
7649
+ const source = raw.startsWith("@") ? (0, import_node_fs9.readFileSync)((0, import_node_path11.resolve)(raw.slice(1)), "utf-8") : raw;
6197
7650
  const parsed = JSON.parse(source);
6198
7651
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
6199
7652
  throw new Error("--input must be a JSON object.");
@@ -6260,7 +7713,8 @@ function setDottedInputValue(input, path, value) {
6260
7713
  cursor[parts[parts.length - 1]] = value;
6261
7714
  }
6262
7715
  function schemaMetadata(schema, key) {
6263
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) return null;
7716
+ if (!schema || typeof schema !== "object" || Array.isArray(schema))
7717
+ return null;
6264
7718
  const value = schema[key];
6265
7719
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
6266
7720
  }
@@ -6294,7 +7748,7 @@ function fileInputBindingsFromStaticPipeline(staticPipeline) {
6294
7748
  function isLocalFilePathValue(value) {
6295
7749
  if (typeof value !== "string" || !value.trim()) return false;
6296
7750
  if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
6297
- return (0, import_node_fs8.existsSync)((0, import_node_path10.resolve)(value));
7751
+ return (0, import_node_fs9.existsSync)((0, import_node_path11.resolve)(value));
6298
7752
  }
6299
7753
  function inputContainsLocalFilePath(value) {
6300
7754
  if (isLocalFilePathValue(value)) {
@@ -6315,13 +7769,15 @@ function namedRunNeedsPlayDefinition(input) {
6315
7769
  }
6316
7770
  async function stageFileInputArgs(input) {
6317
7771
  const uniqueBindings = [
6318
- ...new Map(input.bindings.map((binding) => [binding.inputPath, binding])).values()
7772
+ ...new Map(
7773
+ input.bindings.map((binding) => [binding.inputPath, binding])
7774
+ ).values()
6319
7775
  ];
6320
7776
  const localFiles = uniqueBindings.flatMap((binding) => {
6321
7777
  const value = getDottedInputValue(input.runtimeInput, binding.inputPath);
6322
7778
  if (!isLocalFilePathValue(value)) return [];
6323
- const absolutePath = (0, import_node_path10.resolve)(value);
6324
- return [{ binding, absolutePath, logicalPath: (0, import_node_path10.basename)(absolutePath) }];
7779
+ const absolutePath = (0, import_node_path11.resolve)(value);
7780
+ return [{ binding, absolutePath, logicalPath: (0, import_node_path11.basename)(absolutePath) }];
6325
7781
  });
6326
7782
  if (localFiles.length === 0) {
6327
7783
  return { inputFile: null, packagedFiles: [] };
@@ -6333,10 +7789,18 @@ async function stageFileInputArgs(input) {
6333
7789
  localFiles.map((file) => stageFile(file.logicalPath, file.absolutePath))
6334
7790
  );
6335
7791
  for (const [index, file] of localFiles.entries()) {
6336
- setDottedInputValue(input.runtimeInput, file.binding.inputPath, file.logicalPath);
7792
+ setDottedInputValue(
7793
+ input.runtimeInput,
7794
+ file.binding.inputPath,
7795
+ file.logicalPath
7796
+ );
6337
7797
  const stagedFile = staged[index];
6338
7798
  if (stagedFile && stagedFile.logicalPath !== file.logicalPath) {
6339
- setDottedInputValue(input.runtimeInput, file.binding.inputPath, stagedFile.logicalPath);
7799
+ setDottedInputValue(
7800
+ input.runtimeInput,
7801
+ file.binding.inputPath,
7802
+ stagedFile.logicalPath
7803
+ );
6340
7804
  }
6341
7805
  }
6342
7806
  return {
@@ -6345,7 +7809,7 @@ async function stageFileInputArgs(input) {
6345
7809
  };
6346
7810
  }
6347
7811
  function stageFile(logicalPath, absolutePath) {
6348
- const buffer = (0, import_node_fs8.readFileSync)(absolutePath);
7812
+ const buffer = (0, import_node_fs9.readFileSync)(absolutePath);
6349
7813
  return {
6350
7814
  logicalPath,
6351
7815
  contentBase64: buffer.toString("base64"),
@@ -6356,9 +7820,9 @@ function stageFile(logicalPath, absolutePath) {
6356
7820
  }
6357
7821
  function normalizePlayPath(filePath) {
6358
7822
  try {
6359
- return import_node_fs8.realpathSync.native((0, import_node_path10.resolve)(filePath));
7823
+ return import_node_fs9.realpathSync.native((0, import_node_path11.resolve)(filePath));
6360
7824
  } catch {
6361
- return (0, import_node_path10.resolve)(filePath);
7825
+ return (0, import_node_path11.resolve)(filePath);
6362
7826
  }
6363
7827
  }
6364
7828
  function formatBundlingErrors(filePath, errors) {
@@ -6716,7 +8180,10 @@ function formatProgressCounts(input) {
6716
8180
  if (completed === null || total === null || total <= 0) {
6717
8181
  return null;
6718
8182
  }
6719
- const percent = Math.max(0, Math.min(100, Math.round(completed / total * 100)));
8183
+ const percent = Math.max(
8184
+ 0,
8185
+ Math.min(100, Math.round(completed / total * 100))
8186
+ );
6720
8187
  const failed = typeof input.failed === "number" && Number.isFinite(input.failed) && input.failed > 0 ? `, failed ${formatInteger(input.failed)}` : "";
6721
8188
  return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
6722
8189
  }
@@ -7223,7 +8690,7 @@ function isDatasetHandle(value) {
7223
8690
  value && typeof value === "object" && !Array.isArray(value) && value.kind === "dataset"
7224
8691
  );
7225
8692
  }
7226
- function collectDatasetHandleLines(value, path = "result") {
8693
+ function collectDatasetHandleLines(value, path = "result", datasetStats) {
7227
8694
  if (!value || typeof value !== "object" || Array.isArray(value)) {
7228
8695
  return [];
7229
8696
  }
@@ -7234,6 +8701,9 @@ function collectDatasetHandleLines(value, path = "result") {
7234
8701
  const lines2 = [
7235
8702
  ` dataset ${typeof record.path === "string" ? record.path : path}: rows=${count === null ? "-" : formatInteger(count)} preview=${formatInteger(preview.length)}`
7236
8703
  ];
8704
+ if (datasetStats && (datasetStats.source === path || datasetStats.source === record.path)) {
8705
+ lines2.push(...formatDatasetStatsLines(datasetStats.stats, " "));
8706
+ }
7237
8707
  if (typeof record.queryDatasetCommand === "string") {
7238
8708
  lines2.push(` query dataset: ${record.queryDatasetCommand}`);
7239
8709
  }
@@ -7247,7 +8717,9 @@ function collectDatasetHandleLines(value, path = "result") {
7247
8717
  if (key === "preview" || key === "access") {
7248
8718
  continue;
7249
8719
  }
7250
- lines.push(...collectDatasetHandleLines(child, `${path}.${key}`));
8720
+ lines.push(
8721
+ ...collectDatasetHandleLines(child, `${path}.${key}`, datasetStats)
8722
+ );
7251
8723
  }
7252
8724
  return lines;
7253
8725
  }
@@ -7430,7 +8902,9 @@ function buildInsufficientCreditsSummaryLines(input) {
7430
8902
  const runId = input.status.runId?.trim();
7431
8903
  if (runId) {
7432
8904
  lines.push(` inspect: deepline runs get ${runId} --json`);
7433
- lines.push(` export partial: deepline runs export ${runId} --out output.csv`);
8905
+ lines.push(
8906
+ ` export partial: deepline runs export ${runId} --out output.csv`
8907
+ );
7434
8908
  }
7435
8909
  return lines;
7436
8910
  }
@@ -7502,7 +8976,10 @@ function normalizeErrorsForEnvelope(status, error) {
7502
8976
  }
7503
8977
  return {
7504
8978
  ...entry,
7505
- message: formatInsufficientCreditsMessage({ billing: billing2, error: message2 }),
8979
+ message: formatInsufficientCreditsMessage({
8980
+ billing: billing2,
8981
+ error: message2
8982
+ }),
7506
8983
  billing: stripProviderSpendFromBilling(billing2)
7507
8984
  };
7508
8985
  });
@@ -7601,13 +9078,26 @@ function compactPlayStatus(status) {
7601
9078
  };
7602
9079
  }
7603
9080
  function enrichPlayStatusWithDatasetStats(status) {
7604
- const rowsInfo = extractCanonicalRowsInfo(status);
7605
- if (!rowsInfo?.complete) {
9081
+ const datasetStats = datasetStatsForStatus(status);
9082
+ if (!datasetStats) {
7606
9083
  return status;
7607
9084
  }
7608
9085
  return {
7609
9086
  ...status,
7610
- dataset_stats: buildDatasetStats(
9087
+ result: attachDatasetStatsToResult(
9088
+ status.result,
9089
+ datasetStats
9090
+ )
9091
+ };
9092
+ }
9093
+ function datasetStatsForStatus(status) {
9094
+ const rowsInfo = extractCanonicalRowsInfo(status);
9095
+ if (!rowsInfo?.complete) {
9096
+ return null;
9097
+ }
9098
+ return {
9099
+ source: rowsInfo.source,
9100
+ stats: buildDatasetStats(
7611
9101
  rowsInfo.rows,
7612
9102
  rowsInfo.totalRows,
7613
9103
  rowsInfo.columns,
@@ -7615,6 +9105,52 @@ function enrichPlayStatusWithDatasetStats(status) {
7615
9105
  )
7616
9106
  };
7617
9107
  }
9108
+ function attachDatasetStatsToResult(result, datasetStats) {
9109
+ if (!result || typeof result !== "object" || Array.isArray(result)) {
9110
+ return result;
9111
+ }
9112
+ const sourcePath = datasetStats.source?.replace(/^result\.?/, "") ?? "";
9113
+ const attach = (value, path) => {
9114
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
9115
+ return value;
9116
+ }
9117
+ const record = value;
9118
+ const isMatchingDataset = record.kind === "dataset" && (path === sourcePath || `result.${path}` === datasetStats.source);
9119
+ const next = { ...record };
9120
+ if (isMatchingDataset) {
9121
+ next.summary = datasetStats.stats;
9122
+ return next;
9123
+ }
9124
+ for (const [key, child] of Object.entries(record)) {
9125
+ if (key === "preview" || key === "access") continue;
9126
+ const childPath = path ? `${path}.${key}` : key;
9127
+ const attached = attach(child, childPath);
9128
+ if (attached !== child) {
9129
+ next[key] = attached;
9130
+ }
9131
+ }
9132
+ return next;
9133
+ };
9134
+ return attach(result, "");
9135
+ }
9136
+ function formatDatasetStatsLines(datasetStats, indent = " ") {
9137
+ if (!datasetStats) {
9138
+ return [];
9139
+ }
9140
+ const lines = [`${indent}summary:`];
9141
+ for (const [column, stat3] of Object.entries(datasetStats.columnStats).slice(
9142
+ 0,
9143
+ 12
9144
+ )) {
9145
+ const topValues = stat3.top_values ? `, top_values=${Object.entries(stat3.top_values).slice(0, 3).map(([value, count]) => `${value}=${count}`).join(", ")}` : "";
9146
+ const sample = stat3.sample_value !== void 0 ? `, sample_value=${JSON.stringify(stat3.sample_value)}` : "";
9147
+ const execution = stat3.execution ? `, execution=${Object.entries(stat3.execution).map(([bucket, count]) => `${bucket}=${count}`).join(", ")}` : "";
9148
+ lines.push(
9149
+ `${indent} ${column}: non_empty=${stat3.non_empty}, unique=${stat3.unique}${topValues}${sample}${execution}`
9150
+ );
9151
+ }
9152
+ return lines;
9153
+ }
7618
9154
  function readRunPackageRun(packaged) {
7619
9155
  return packaged.run && typeof packaged.run === "object" && !Array.isArray(packaged.run) ? packaged.run : {};
7620
9156
  }
@@ -7623,6 +9159,60 @@ function readRecordArray(value) {
7623
9159
  (item) => item !== null && typeof item === "object" && !Array.isArray(item)
7624
9160
  ) : [];
7625
9161
  }
9162
+ function readRecord(value) {
9163
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
9164
+ }
9165
+ function formatSummaryScalar(value) {
9166
+ if (typeof value === "number") {
9167
+ return Number.isFinite(value) ? formatInteger(Math.trunc(value)) : null;
9168
+ }
9169
+ if (typeof value === "string" || typeof value === "boolean") {
9170
+ return String(value);
9171
+ }
9172
+ if (value === null) {
9173
+ return "null";
9174
+ }
9175
+ return null;
9176
+ }
9177
+ function formatSummaryScalarParts(record, skipKeys = /* @__PURE__ */ new Set()) {
9178
+ const parts = [];
9179
+ for (const [key, value] of Object.entries(record)) {
9180
+ if (skipKeys.has(key)) {
9181
+ continue;
9182
+ }
9183
+ const formatted = formatSummaryScalar(value);
9184
+ if (formatted !== null) {
9185
+ parts.push(`${key}=${formatted}`);
9186
+ }
9187
+ }
9188
+ return parts;
9189
+ }
9190
+ function formatPackageDatasetSummaryLines(summary, indent = " ") {
9191
+ const record = readRecord(summary);
9192
+ const columnStats = readRecord(record?.columnStats);
9193
+ if (!record || !columnStats) {
9194
+ return [];
9195
+ }
9196
+ const lines = [];
9197
+ const parts = formatSummaryScalarParts(record, /* @__PURE__ */ new Set(["columnStats"]));
9198
+ if (parts.length > 0) {
9199
+ lines.push(`${indent}summary: ${parts.join(" ")}`);
9200
+ }
9201
+ for (const [column, rawColumnSummary] of Object.entries(columnStats)) {
9202
+ const columnSummary = readRecord(rawColumnSummary);
9203
+ if (!columnSummary) continue;
9204
+ const execution = readRecord(columnSummary.execution);
9205
+ const executionText = execution ? Object.entries(execution).map(([bucket, value]) => `${bucket}=${String(value)}`).join(", ") : "";
9206
+ const columnParts = [
9207
+ ...formatSummaryScalarParts(columnSummary, /* @__PURE__ */ new Set(["execution"])),
9208
+ executionText ? `execution=${executionText}` : null
9209
+ ].filter(Boolean);
9210
+ if (columnParts.length > 0) {
9211
+ lines.push(`${indent} ${column}: ${columnParts.join(" ")}`);
9212
+ }
9213
+ }
9214
+ return lines;
9215
+ }
7626
9216
  function actionToCommand(action) {
7627
9217
  if (!action || typeof action !== "object" || Array.isArray(action)) {
7628
9218
  return null;
@@ -7657,7 +9247,9 @@ function buildRunPackageTextLines(packaged) {
7657
9247
  const runId = typeof run.id === "string" ? run.id : "unknown";
7658
9248
  const status = typeof run.status === "string" ? run.status : "unknown";
7659
9249
  const playName = typeof run.playName === "string" ? run.playName : null;
7660
- const lines = [`${status === "completed" ? "\u2713" : status === "failed" ? "\u2717" : "\u2022"} ${status} ${runId}`];
9250
+ const lines = [
9251
+ `${status === "completed" ? "\u2713" : status === "failed" ? "\u2717" : "\u2022"} ${status} ${runId}`
9252
+ ];
7661
9253
  if (playName) {
7662
9254
  lines.push(` play: ${playName}`);
7663
9255
  }
@@ -7669,8 +9261,11 @@ function buildRunPackageTextLines(packaged) {
7669
9261
  const rowCount = output && typeof output.rowCount === "number" ? ` rows=${formatInteger(output.rowCount)}` : "";
7670
9262
  const preview = output?.preview && typeof output.preview === "object" && !Array.isArray(output.preview) ? output.preview : null;
7671
9263
  const previewRows = Array.isArray(preview?.rows) ? preview.rows.length : null;
7672
- const previewLabel = previewRows !== null ? ` preview=${previewRows}${preview?.truncated ? " truncated" : ""}` : "";
7673
- lines.push(` ${kind} ${id}: ${stepStatus}${rowCount}${previewLabel}`);
9264
+ lines.push(` ${kind} ${id}: ${stepStatus}${rowCount}`);
9265
+ lines.push(...formatPackageDatasetSummaryLines(output?.summary));
9266
+ if (previewRows !== null) {
9267
+ lines.push(` preview=${previewRows}${preview?.truncated ? " truncated" : ""}`);
9268
+ }
7674
9269
  }
7675
9270
  const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
7676
9271
  const datasetActions = readFirstDatasetActions(packaged);
@@ -7684,8 +9279,13 @@ function buildRunPackageTextLines(packaged) {
7684
9279
  }
7685
9280
  function writePlayResult(status, jsonOutput, options) {
7686
9281
  const packaged = getPlayRunPackage(status);
9282
+ const datasetStats = datasetStatsForStatus(status);
7687
9283
  if (jsonOutput) {
7688
- const payload2 = options?.fullJson ? status : compactPlayStatus(status);
9284
+ const compact2 = compactPlayStatus(status);
9285
+ const payload2 = options?.fullJson ? enrichPlayStatusWithDatasetStats(status) : datasetStats ? {
9286
+ ...compact2,
9287
+ result: attachDatasetStatsToResult(compact2.result, datasetStats)
9288
+ } : compact2;
7689
9289
  printCommandEnvelope(payload2, { json: true });
7690
9290
  return;
7691
9291
  }
@@ -7721,35 +9321,42 @@ function writePlayResult(status, jsonOutput, options) {
7721
9321
  const renderedServerView = renderServerResultView(status.resultView);
7722
9322
  if (result) {
7723
9323
  lines.push(...formatReturnValue(result));
7724
- lines.push(...collectDatasetHandleLines(result));
9324
+ lines.push(...collectDatasetHandleLines(result, "result", datasetStats));
7725
9325
  }
7726
9326
  if (renderedServerView.lines.length > 0) {
7727
9327
  lines.push(...renderedServerView.lines);
7728
9328
  }
7729
9329
  lines.push(...renderedServerView.actions);
7730
- const payload = options?.fullJson ? enrichPlayStatusWithDatasetStats(status) : compactPlayStatus(status);
7731
- printCommandEnvelope({
7732
- ...payload,
7733
- render: {
7734
- sections: [{ title: "run result", lines }]
7735
- }
7736
- }, { json: jsonOutput, text: `${lines.join("\n")}
7737
- ` });
9330
+ const compact = compactPlayStatus(status);
9331
+ const payload = options?.fullJson ? enrichPlayStatusWithDatasetStats(status) : datasetStats ? {
9332
+ ...compact,
9333
+ result: attachDatasetStatsToResult(compact.result, datasetStats)
9334
+ } : compact;
9335
+ printCommandEnvelope(
9336
+ {
9337
+ ...payload,
9338
+ render: {
9339
+ sections: [{ title: "run result", lines }]
9340
+ }
9341
+ },
9342
+ { json: jsonOutput, text: `${lines.join("\n")}
9343
+ ` }
9344
+ );
7738
9345
  }
7739
9346
  async function resolvePlayRunOutputStatus(input) {
7740
- if (!input.fullJson || !getPlayRunPackage(input.status)) {
9347
+ if (!getPlayRunPackage(input.status)) {
7741
9348
  return input.status;
7742
9349
  }
7743
9350
  const runId = input.status.runId;
7744
9351
  if (!runId) {
7745
9352
  return input.status;
7746
9353
  }
7747
- const fullStatus = await input.client.getPlayStatus(runId, {
9354
+ const refreshedStatus = await input.client.getPlayStatus(runId, {
7748
9355
  billing: false,
7749
- full: true
9356
+ full: input.fullJson
7750
9357
  });
7751
9358
  const dashboardUrl = input.status.dashboardUrl;
7752
- return typeof dashboardUrl === "string" ? { ...fullStatus, dashboardUrl } : fullStatus;
9359
+ return typeof dashboardUrl === "string" ? { ...refreshedStatus, dashboardUrl } : refreshedStatus;
7753
9360
  }
7754
9361
  var RUN_EXPORT_PAGE_SIZE = 5e3;
7755
9362
  function shellSingleQuote(value) {
@@ -7759,7 +9366,7 @@ function sqlStringLiteral(value) {
7759
9366
  return `'${value.replace(/'/g, "''")}'`;
7760
9367
  }
7761
9368
  function runExportRetryCommand(runId, outPath, datasetPath) {
7762
- return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0, import_node_path10.resolve)(outPath))}`;
9369
+ return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0, import_node_path11.resolve)(outPath))}`;
7763
9370
  }
7764
9371
  function extractRunPlayName(status) {
7765
9372
  const run = status.run;
@@ -7793,7 +9400,7 @@ function buildCustomerDbQueryPlan(input) {
7793
9400
  return {
7794
9401
  sql,
7795
9402
  json: `${base} --json`,
7796
- csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path10.resolve)(input.outPath))}`
9403
+ csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path11.resolve)(input.outPath))}`
7797
9404
  };
7798
9405
  }
7799
9406
  function exportableSheetRow(row) {
@@ -8093,7 +9700,9 @@ function renderServerResultView(value) {
8093
9700
  (field) => typeof field === "string"
8094
9701
  ) : [];
8095
9702
  if (rawResultFields.length > 0) {
8096
- lines.push(` tool-result columns: ${rawResultFields.join(", ")}`);
9703
+ lines.push(
9704
+ ` tool-result columns: ${rawResultFields.join(", ")}`
9705
+ );
8097
9706
  }
8098
9707
  }
8099
9708
  if (typeof table.slowExportAsCsvCommand === "string") {
@@ -8146,10 +9755,13 @@ function writeStartedPlayRun(input) {
8146
9755
  ` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`
8147
9756
  ];
8148
9757
  if (input.jsonOutput) {
8149
- printCommandEnvelope({
8150
- ...payload,
8151
- render: { sections: [{ title: "play run", lines }] }
8152
- }, { json: true });
9758
+ printCommandEnvelope(
9759
+ {
9760
+ ...payload,
9761
+ render: { sections: [{ title: "play run", lines }] }
9762
+ },
9763
+ { json: true }
9764
+ );
8153
9765
  return;
8154
9766
  }
8155
9767
  if (input.dashboardUrl) {
@@ -8160,11 +9772,14 @@ function writeStartedPlayRun(input) {
8160
9772
  input.progress.writeLine(output, process.stdout);
8161
9773
  return;
8162
9774
  }
8163
- printCommandEnvelope({
8164
- ...payload,
8165
- render: { sections: [{ title: "play run", lines }] }
8166
- }, { json: false, text: `${output}
8167
- ` });
9775
+ printCommandEnvelope(
9776
+ {
9777
+ ...payload,
9778
+ render: { sections: [{ title: "play run", lines }] }
9779
+ },
9780
+ { json: false, text: `${output}
9781
+ ` }
9782
+ );
8168
9783
  }
8169
9784
  function parsePlayRunOptions(args) {
8170
9785
  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.";
@@ -8187,7 +9802,7 @@ function parsePlayRunOptions(args) {
8187
9802
  continue;
8188
9803
  }
8189
9804
  if (arg === "--name" && args[index + 1]) {
8190
- playName = parseReferencedPlayTarget(args[++index]).playName;
9805
+ playName = parseReferencedPlayTarget2(args[++index]).playName;
8191
9806
  continue;
8192
9807
  }
8193
9808
  if ((arg === "--input" || arg === "-i") && args[index + 1]) {
@@ -8217,7 +9832,7 @@ function parsePlayRunOptions(args) {
8217
9832
  );
8218
9833
  }
8219
9834
  if ((arg === "--tail-timeout-ms" || arg === "--timeout-ms") && args[index + 1]) {
8220
- waitTimeoutMs = parsePositiveInteger2(args[++index], arg);
9835
+ waitTimeoutMs = parsePositiveInteger3(args[++index], arg);
8221
9836
  continue;
8222
9837
  }
8223
9838
  if (PLAY_RUN_RESERVED_BOOLEAN_FLAGS.has(arg)) {
@@ -8251,7 +9866,7 @@ function parsePlayRunOptions(args) {
8251
9866
  if (isFileTarget(arg) || looksLikeFilePath(arg)) {
8252
9867
  filePath = arg;
8253
9868
  } else {
8254
- playName = parseReferencedPlayTarget(arg).playName;
9869
+ playName = parseReferencedPlayTarget2(arg).playName;
8255
9870
  }
8256
9871
  continue;
8257
9872
  }
@@ -8300,34 +9915,34 @@ function shouldUseLocalOnlyPlayCheck() {
8300
9915
  const value = process.env.DEEPLINE_PLAY_CHECK_LOCAL_ONLY?.trim().toLowerCase();
8301
9916
  return value === "1" || value === "true" || value === "yes" || value === "on";
8302
9917
  }
8303
- function isRecord3(value) {
9918
+ function isRecord4(value) {
8304
9919
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
8305
9920
  }
8306
- function stringValue(value) {
9921
+ function stringValue2(value) {
8307
9922
  return typeof value === "string" ? value.trim() : "";
8308
9923
  }
8309
9924
  function asArray(value) {
8310
9925
  return Array.isArray(value) ? value : [];
8311
9926
  }
8312
- function extractionEntries(value) {
8313
- if (Array.isArray(value)) return value.filter(isRecord3);
8314
- if (!isRecord3(value)) return [];
9927
+ function extractionEntries2(value) {
9928
+ if (Array.isArray(value)) return value.filter(isRecord4);
9929
+ if (!isRecord4(value)) return [];
8315
9930
  return Object.entries(value).map(
8316
- ([name, entry]) => isRecord3(entry) ? { name, ...entry } : { name }
9931
+ ([name, entry]) => isRecord4(entry) ? { name, ...entry } : { name }
8317
9932
  );
8318
9933
  }
8319
9934
  function firstRawPath(entry) {
8320
- const details = isRecord3(entry.details) ? entry.details : {};
9935
+ const details = isRecord4(entry.details) ? entry.details : {};
8321
9936
  const paths = [
8322
9937
  ...asArray(details.rawToolOutputPaths),
8323
9938
  ...asArray(details.raw_tool_output_paths),
8324
9939
  ...asArray(details.candidatePaths),
8325
9940
  ...asArray(details.candidate_paths)
8326
- ].map(stringValue).filter(Boolean);
9941
+ ].map(stringValue2).filter(Boolean);
8327
9942
  return paths[0];
8328
9943
  }
8329
9944
  function checkHintExpression(value) {
8330
- return stringValue(value).replace(/^toolExecutionResult\./, "result.");
9945
+ return stringValue2(value).replace(/^toolExecutionResult\./, "result.");
8331
9946
  }
8332
9947
  function checkHintRawPath(value) {
8333
9948
  return value?.replace(/^toolResponse\./, "result.toolResponse.");
@@ -8335,14 +9950,14 @@ function checkHintRawPath(value) {
8335
9950
  function collectStaticPipelineToolIds(staticPipeline) {
8336
9951
  const seen = /* @__PURE__ */ new Set();
8337
9952
  const visitPipeline = (pipeline) => {
8338
- if (!isRecord3(pipeline)) return;
9953
+ if (!isRecord4(pipeline)) return;
8339
9954
  for (const step of [
8340
9955
  ...asArray(pipeline.stages),
8341
9956
  ...asArray(pipeline.substeps)
8342
9957
  ]) {
8343
- if (!isRecord3(step)) continue;
9958
+ if (!isRecord4(step)) continue;
8344
9959
  if (step.type === "tool") {
8345
- const toolId = stringValue(step.toolId) || stringValue(step.tool);
9960
+ const toolId = stringValue2(step.toolId) || stringValue2(step.tool);
8346
9961
  if (toolId) seen.add(toolId);
8347
9962
  }
8348
9963
  if (step.type === "play_call") {
@@ -8354,20 +9969,20 @@ function collectStaticPipelineToolIds(staticPipeline) {
8354
9969
  return [...seen].sort();
8355
9970
  }
8356
9971
  function toolGetterHintFromMetadata(toolId, tool) {
8357
- const usageGuidance = isRecord3(tool.usageGuidance) ? tool.usageGuidance : {};
8358
- const resultGuidance = isRecord3(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord3(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
8359
- const toolResponse = isRecord3(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord3(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
8360
- const lists = extractionEntries(
9972
+ const usageGuidance = isRecord4(tool.usageGuidance) ? tool.usageGuidance : {};
9973
+ const resultGuidance = isRecord4(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord4(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
9974
+ const toolResponse = isRecord4(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord4(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
9975
+ const lists = extractionEntries2(
8361
9976
  resultGuidance.extractedLists ?? resultGuidance.extracted_lists
8362
9977
  ).map((entry) => ({
8363
- name: stringValue(entry.name),
9978
+ name: stringValue2(entry.name),
8364
9979
  expression: checkHintExpression(entry.expression),
8365
9980
  raw: checkHintRawPath(firstRawPath(entry))
8366
9981
  })).filter((entry) => entry.name && entry.expression);
8367
- const values = extractionEntries(
9982
+ const values = extractionEntries2(
8368
9983
  resultGuidance.extractedValues ?? resultGuidance.extracted_values
8369
9984
  ).map((entry) => ({
8370
- name: stringValue(entry.name),
9985
+ name: stringValue2(entry.name),
8371
9986
  expression: checkHintExpression(entry.expression),
8372
9987
  raw: checkHintRawPath(firstRawPath(entry))
8373
9988
  })).filter((entry) => entry.name && entry.expression);
@@ -8423,12 +10038,12 @@ function printToolGetterHints(hints) {
8423
10038
  async function handlePlayCheck(args) {
8424
10039
  const options = parsePlayCheckOptions(args);
8425
10040
  if (!isFileTarget(options.target)) {
8426
- const resolved = (0, import_node_path10.resolve)(options.target);
10041
+ const resolved = (0, import_node_path11.resolve)(options.target);
8427
10042
  console.error(`File not found: ${resolved}`);
8428
10043
  return 1;
8429
10044
  }
8430
- const absolutePlayPath = (0, import_node_path10.resolve)(options.target);
8431
- const sourceCode = (0, import_node_fs8.readFileSync)(absolutePlayPath, "utf-8");
10045
+ const absolutePlayPath = (0, import_node_path11.resolve)(options.target);
10046
+ const sourceCode = (0, import_node_fs9.readFileSync)(absolutePlayPath, "utf-8");
8432
10047
  let graph;
8433
10048
  try {
8434
10049
  graph = await collectBundledPlayGraph(absolutePlayPath);
@@ -8455,8 +10070,10 @@ async function handlePlayCheck(args) {
8455
10070
  graphHash: graph.root.artifact.graphHash
8456
10071
  };
8457
10072
  if (options.jsonOutput) {
8458
- process.stdout.write(`${JSON.stringify({ name: playName, ...result2 })}
8459
- `);
10073
+ process.stdout.write(
10074
+ `${JSON.stringify({ name: playName, ...result2 })}
10075
+ `
10076
+ );
8460
10077
  } else {
8461
10078
  console.log(`\u2713 ${playName} passed local play check`);
8462
10079
  console.log(` artifact: ${result2.artifactHash.slice(0, 12)}`);
@@ -8480,8 +10097,10 @@ async function handlePlayCheck(args) {
8480
10097
  toolGetterHints: result.toolGetterHints ?? await buildToolGetterHints(client, result.staticPipeline)
8481
10098
  };
8482
10099
  if (options.jsonOutput) {
8483
- process.stdout.write(`${JSON.stringify({ name: playName, ...enrichedResult })}
8484
- `);
10100
+ process.stdout.write(
10101
+ `${JSON.stringify({ name: playName, ...enrichedResult })}
10102
+ `
10103
+ );
8485
10104
  } else if (enrichedResult.valid) {
8486
10105
  console.log(`\u2713 ${playName} passed cloud play check`);
8487
10106
  if (enrichedResult.artifactHash) {
@@ -8503,12 +10122,12 @@ async function handleFileBackedRun(options) {
8503
10122
  }
8504
10123
  const client = new DeeplineClient();
8505
10124
  const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
8506
- const absolutePlayPath = (0, import_node_path10.resolve)(options.target.path);
10125
+ const absolutePlayPath = (0, import_node_path11.resolve)(options.target.path);
8507
10126
  progress.phase("compiling play");
8508
10127
  const sourceCode = traceCliSync(
8509
10128
  "cli.play_file_read_source",
8510
10129
  { targetKind: "file" },
8511
- () => (0, import_node_fs8.readFileSync)(absolutePlayPath, "utf-8")
10130
+ () => (0, import_node_fs9.readFileSync)(absolutePlayPath, "utf-8")
8512
10131
  );
8513
10132
  const runtimeInput = options.input ? { ...options.input } : {};
8514
10133
  let graph;
@@ -8792,19 +10411,19 @@ async function handlePlayRun(args) {
8792
10411
  if (isFileTarget(options.target.path)) {
8793
10412
  return handleFileBackedRun(options);
8794
10413
  }
8795
- const resolved = (0, import_node_path10.resolve)(options.target.path);
10414
+ const resolved = (0, import_node_path11.resolve)(options.target.path);
8796
10415
  console.error(`File not found: ${resolved}`);
8797
- const dir = (0, import_node_path10.dirname)(resolved);
8798
- if ((0, import_node_fs8.existsSync)(dir)) {
8799
- const base = (0, import_node_path10.basename)(resolved);
10416
+ const dir = (0, import_node_path11.dirname)(resolved);
10417
+ if ((0, import_node_fs9.existsSync)(dir)) {
10418
+ const base = (0, import_node_path11.basename)(resolved);
8800
10419
  try {
8801
- const siblings = (0, import_node_fs8.readdirSync)(dir).filter(
10420
+ const siblings = (0, import_node_fs9.readdirSync)(dir).filter(
8802
10421
  (f) => f.includes(base.replace(/\.(play\.)?ts$/, "")) || f.endsWith(".play.ts")
8803
10422
  );
8804
10423
  if (siblings.length > 0) {
8805
10424
  console.error(`Did you mean one of these?`);
8806
10425
  for (const s of siblings.slice(0, 5)) {
8807
- console.error(` ${(0, import_node_path10.join)(dir, s)}`);
10426
+ console.error(` ${(0, import_node_path11.join)(dir, s)}`);
8808
10427
  }
8809
10428
  }
8810
10429
  } catch {
@@ -8858,7 +10477,7 @@ async function handleRunsList(args) {
8858
10477
  for (let index = 0; index < args.length; index += 1) {
8859
10478
  const arg = args[index];
8860
10479
  if ((arg === "--play" || arg === "--name") && args[index + 1]) {
8861
- playName = parseReferencedPlayTarget(args[++index]).playName;
10480
+ playName = parseReferencedPlayTarget2(args[++index]).playName;
8862
10481
  continue;
8863
10482
  }
8864
10483
  if (arg === "--status" && args[index + 1]) {
@@ -8887,15 +10506,20 @@ async function handleRunsList(args) {
8887
10506
  executionTime: run.executionTime,
8888
10507
  playName: run.memo?.playName ?? playName
8889
10508
  }));
8890
- const lines = runs.length === 0 ? [`No runs found for ${playName}.`] : runs.map((run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)}`);
8891
- printCommandEnvelope({
8892
- runs,
8893
- count: runs.length,
8894
- next: {
8895
- get: runs[0]?.runId ? `deepline runs get ${runs[0].runId} --json` : null
10509
+ const lines = runs.length === 0 ? [`No runs found for ${playName}.`] : runs.map(
10510
+ (run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)}`
10511
+ );
10512
+ printCommandEnvelope(
10513
+ {
10514
+ runs,
10515
+ count: runs.length,
10516
+ next: {
10517
+ get: runs[0]?.runId ? `deepline runs get ${runs[0].runId} --json` : null
10518
+ },
10519
+ render: { sections: [{ title: "runs", lines }] }
8896
10520
  },
8897
- render: { sections: [{ title: "runs", lines }] }
8898
- }, { json: argsWantJson(args) });
10521
+ { json: argsWantJson(args) }
10522
+ );
8899
10523
  return 0;
8900
10524
  }
8901
10525
  async function handleRunTail(args) {
@@ -8910,7 +10534,9 @@ async function handleRunTail(args) {
8910
10534
  for (let index = 0; index < args.length; index += 1) {
8911
10535
  const arg = args[index];
8912
10536
  if (arg === "--cursor") {
8913
- console.error("--cursor was removed. deepline runs tail reads the canonical run stream.");
10537
+ console.error(
10538
+ "--cursor was removed. deepline runs tail reads the canonical run stream."
10539
+ );
8914
10540
  return 1;
8915
10541
  }
8916
10542
  if (arg.startsWith("--") && arg !== "--json" && arg !== "--compact") {
@@ -8937,42 +10563,58 @@ async function handleRunLogs(args) {
8937
10563
  for (let index = 0; index < args.length; index += 1) {
8938
10564
  const arg = args[index];
8939
10565
  if (arg === "--limit" && args[index + 1]) {
8940
- limit = parsePositiveInteger2(args[++index], "--limit");
10566
+ limit = parsePositiveInteger3(args[++index], "--limit");
8941
10567
  continue;
8942
10568
  }
8943
10569
  if (arg === "--out" && args[index + 1]) {
8944
- outPath = (0, import_node_path10.resolve)(args[++index]);
10570
+ outPath = (0, import_node_path11.resolve)(args[++index]);
8945
10571
  }
8946
10572
  }
8947
10573
  const client = new DeeplineClient();
8948
10574
  const status = await client.runs.get(runId);
8949
10575
  const logs = status.progress?.logs ?? [];
8950
10576
  if (outPath) {
8951
- (0, import_node_fs8.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
8952
- printCommandEnvelope({
8953
- runId: status.runId,
8954
- log_path: outPath,
8955
- lineCount: logs.length,
8956
- local: { log_path: outPath },
8957
- render: { sections: [{ title: "run logs", lines: [`Wrote ${logs.length} log lines to ${outPath}`] }] }
8958
- }, { json: argsWantJson(args) });
10577
+ (0, import_node_fs9.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
10578
+ printCommandEnvelope(
10579
+ {
10580
+ runId: status.runId,
10581
+ log_path: outPath,
10582
+ lineCount: logs.length,
10583
+ local: { log_path: outPath },
10584
+ render: {
10585
+ sections: [
10586
+ {
10587
+ title: "run logs",
10588
+ lines: [`Wrote ${logs.length} log lines to ${outPath}`]
10589
+ }
10590
+ ]
10591
+ }
10592
+ },
10593
+ { json: argsWantJson(args) }
10594
+ );
8959
10595
  return 0;
8960
10596
  }
8961
10597
  const entries = logs.slice(Math.max(0, logs.length - limit));
8962
- printCommandEnvelope({
8963
- runId: status.runId,
8964
- totalCount: logs.length,
8965
- returnedCount: entries.length,
8966
- firstSequence: logs.length === 0 ? null : logs.length - entries.length + 1,
8967
- lastSequence: logs.length === 0 ? null : logs.length,
8968
- truncated: logs.length > entries.length,
8969
- hasMore: logs.length > entries.length,
8970
- entries,
8971
- next: {
8972
- export: `deepline runs logs ${status.runId} --out run.log --json`
10598
+ printCommandEnvelope(
10599
+ {
10600
+ runId: status.runId,
10601
+ totalCount: logs.length,
10602
+ returnedCount: entries.length,
10603
+ firstSequence: logs.length === 0 ? null : logs.length - entries.length + 1,
10604
+ lastSequence: logs.length === 0 ? null : logs.length,
10605
+ truncated: logs.length > entries.length,
10606
+ hasMore: logs.length > entries.length,
10607
+ entries,
10608
+ next: {
10609
+ export: `deepline runs logs ${status.runId} --out run.log --json`
10610
+ },
10611
+ render: { sections: [{ title: "run logs", lines: entries }] }
8973
10612
  },
8974
- render: { sections: [{ title: "run logs", lines: entries }] }
8975
- }, { json: argsWantJson(args), text: `${entries.join("\n")}${entries.length > 0 ? "\n" : ""}` });
10613
+ {
10614
+ json: argsWantJson(args),
10615
+ text: `${entries.join("\n")}${entries.length > 0 ? "\n" : ""}`
10616
+ }
10617
+ );
8976
10618
  return 0;
8977
10619
  }
8978
10620
  async function handleRunStop(args) {
@@ -8997,10 +10639,13 @@ async function handleRunStop(args) {
8997
10639
  `Stopped ${result.runId}`,
8998
10640
  ...result.hitlCancelledCount > 0 ? [`cancelled HITL waits: ${result.hitlCancelledCount}`] : []
8999
10641
  ];
9000
- printCommandEnvelope({
9001
- ...result,
9002
- render: { sections: [{ title: "run stop", lines }] }
9003
- }, { json: argsWantJson(args) });
10642
+ printCommandEnvelope(
10643
+ {
10644
+ ...result,
10645
+ render: { sections: [{ title: "run stop", lines }] }
10646
+ },
10647
+ { json: argsWantJson(args) }
10648
+ );
9004
10649
  return 0;
9005
10650
  }
9006
10651
  async function handleRunExport(args) {
@@ -9018,7 +10663,7 @@ async function handleRunExport(args) {
9018
10663
  for (let index = 0; index < args.length; index += 1) {
9019
10664
  const arg = args[index];
9020
10665
  if (arg === "--out" && args[index + 1]) {
9021
- outPath = (0, import_node_path10.resolve)(args[++index]);
10666
+ outPath = (0, import_node_path11.resolve)(args[++index]);
9022
10667
  continue;
9023
10668
  }
9024
10669
  if (arg === "--dataset" && args[index + 1]) {
@@ -9026,7 +10671,7 @@ async function handleRunExport(args) {
9026
10671
  continue;
9027
10672
  }
9028
10673
  if (arg === "--metadata-out" && args[index + 1]) {
9029
- metadataOutPath = (0, import_node_path10.resolve)(args[++index]);
10674
+ metadataOutPath = (0, import_node_path11.resolve)(args[++index]);
9030
10675
  }
9031
10676
  }
9032
10677
  if (!outPath) {
@@ -9083,7 +10728,7 @@ async function handleRunExport(args) {
9083
10728
  }
9084
10729
  };
9085
10730
  if (metadataOutPath) {
9086
- (0, import_node_fs8.writeFileSync)(
10731
+ (0, import_node_fs9.writeFileSync)(
9087
10732
  metadataOutPath,
9088
10733
  `${JSON.stringify(payload, null, 2)}
9089
10734
  `,
@@ -9113,10 +10758,10 @@ async function handlePlayGet(args) {
9113
10758
  for (let index = 1; index < args.length; index += 1) {
9114
10759
  const arg = args[index];
9115
10760
  if (arg === "--out" && args[index + 1]) {
9116
- outPath = (0, import_node_path10.resolve)(args[++index]);
10761
+ outPath = (0, import_node_path11.resolve)(args[++index]);
9117
10762
  }
9118
10763
  }
9119
- const playName = isFileTarget(target) ? extractPlayName((0, import_node_fs8.readFileSync)((0, import_node_path10.resolve)(target), "utf-8"), (0, import_node_path10.resolve)(target)) : parseReferencedPlayTarget(target).playName;
10764
+ const playName = isFileTarget(target) ? extractPlayName((0, import_node_fs9.readFileSync)((0, import_node_path11.resolve)(target), "utf-8"), (0, import_node_path11.resolve)(target)) : parseReferencedPlayTarget2(target).playName;
9120
10765
  const detail = isFileTarget(target) ? await client.getPlay(playName) : await assertCanonicalNamedPlayReference(client, target);
9121
10766
  const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
9122
10767
  const materializedFile = outPath ? materializeRemotePlaySource({
@@ -9201,7 +10846,7 @@ async function handlePlayVersions(args) {
9201
10846
  const jsonOutput = argsWantJson(args);
9202
10847
  await assertCanonicalNamedPlayReference(client, playName);
9203
10848
  const versions = await client.listPlayVersions(
9204
- parseReferencedPlayTarget(playName).playName
10849
+ parseReferencedPlayTarget2(playName).playName
9205
10850
  );
9206
10851
  if (jsonOutput) {
9207
10852
  process.stdout.write(`${JSON.stringify({ versions })}
@@ -9219,20 +10864,8 @@ async function handlePlayVersions(args) {
9219
10864
  }
9220
10865
  async function handlePlayList(args) {
9221
10866
  const jsonOutput = argsWantJson(args);
9222
- const originArgIndex = args.findIndex((arg) => arg === "--origin");
9223
- const rawOrigin = originArgIndex >= 0 ? args[originArgIndex + 1] : void 0;
9224
- if (rawOrigin && rawOrigin !== "prebuilt" && rawOrigin !== "owned") {
9225
- throw new Error(`Invalid value for --origin: ${rawOrigin}`);
9226
- }
9227
- const origin = rawOrigin;
9228
10867
  const client = new DeeplineClient();
9229
- const plays = (await client.listPlays({
9230
- ...origin ? { origin } : {}
9231
- })).filter((play) => {
9232
- if (!origin) return true;
9233
- const isPrebuilt = play.origin === "prebuilt" || play.ownerType === "deepline";
9234
- return origin === "prebuilt" ? isPrebuilt : !isPrebuilt;
9235
- });
10868
+ const plays = await client.listPlays();
9236
10869
  if (jsonOutput) {
9237
10870
  process.stdout.write(`${JSON.stringify(plays)}
9238
10871
  `);
@@ -9335,7 +10968,8 @@ function compactPlaySchema(schema) {
9335
10968
  return fields.length > 0 ? { fields } : schema;
9336
10969
  }
9337
10970
  function playSchemaMetadata(schema, key) {
9338
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) return null;
10971
+ if (!schema || typeof schema !== "object" || Array.isArray(schema))
10972
+ return null;
9339
10973
  const value = schema[key];
9340
10974
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
9341
10975
  }
@@ -9350,7 +10984,10 @@ function playRunCommand(play, options) {
9350
10984
  function summarizePlayListItemForCli(play, options) {
9351
10985
  const aliases = play.aliases?.length ? play.aliases : [play.name];
9352
10986
  const csvInput = playSchemaMetadata(play.inputSchema, "csvInput");
9353
- const rowOutputSchema = playSchemaMetadata(play.outputSchema, "rowOutputSchema");
10987
+ const rowOutputSchema = playSchemaMetadata(
10988
+ play.outputSchema,
10989
+ "rowOutputSchema"
10990
+ );
9354
10991
  const runCommand2 = playRunCommand(play, { csvInput });
9355
10992
  const cloneEditStarter = buildCloneEditStarter(play);
9356
10993
  return {
@@ -9500,7 +11137,7 @@ async function handlePlayDescribe(args) {
9500
11137
  const client = new DeeplineClient();
9501
11138
  await assertCanonicalNamedPlayReference(client, playName);
9502
11139
  const play = await client.describePlay(
9503
- parseReferencedPlayTarget(playName).playName,
11140
+ parseReferencedPlayTarget2(playName).playName,
9504
11141
  {
9505
11142
  compact: args.includes("--compact")
9506
11143
  }
@@ -9546,7 +11183,7 @@ async function handlePlayPublish(args) {
9546
11183
  }
9547
11184
  let graph;
9548
11185
  try {
9549
- graph = await collectBundledPlayGraph((0, import_node_path10.resolve)(playName));
11186
+ graph = await collectBundledPlayGraph((0, import_node_path11.resolve)(playName));
9550
11187
  await compileBundledPlayGraphManifests(client, graph);
9551
11188
  await publishImportedPlayDependencies(client, graph);
9552
11189
  } catch (error) {
@@ -9575,7 +11212,7 @@ async function handlePlayPublish(args) {
9575
11212
  );
9576
11213
  return 0;
9577
11214
  }
9578
- const resolvedName = parseReferencedPlayTarget(playName).playName;
11215
+ const resolvedName = parseReferencedPlayTarget2(playName).playName;
9579
11216
  if (useLatest) {
9580
11217
  const versions = await client.listPlayVersions(resolvedName);
9581
11218
  const latest = versions[0];
@@ -9615,17 +11252,19 @@ async function handlePlayDelete(args) {
9615
11252
  const client = new DeeplineClient();
9616
11253
  let detail;
9617
11254
  try {
9618
- detail = await client.getPlay(parseReferencedPlayTarget(playName).playName);
11255
+ detail = await client.getPlay(parseReferencedPlayTarget2(playName).playName);
9619
11256
  } catch (error) {
9620
11257
  console.error(error instanceof Error ? error.message : String(error));
9621
11258
  return 1;
9622
11259
  }
9623
11260
  if (detail.play.ownerType === "deepline" || detail.play.origin === "prebuilt") {
9624
- console.error(`Cannot delete prebuilt play: ${formatPlayReference(detail.play)}`);
11261
+ console.error(
11262
+ `Cannot delete prebuilt play: ${formatPlayReference(detail.play)}`
11263
+ );
9625
11264
  return 1;
9626
11265
  }
9627
11266
  const result = await client.deletePlay(
9628
- parseReferencedPlayTarget(formatPlayReference(detail.play)).playName
11267
+ parseReferencedPlayTarget2(formatPlayReference(detail.play)).playName
9629
11268
  );
9630
11269
  if (argsWantJson(args)) {
9631
11270
  process.stdout.write(`${JSON.stringify(result)}
@@ -9770,6 +11409,7 @@ Pass-through input flags:
9770
11409
  ...passthroughArgs
9771
11410
  ]);
9772
11411
  });
11412
+ registerPlayBootstrapCommand(play);
9773
11413
  play.command("get <target>").description("Fetch full play details.").addHelpText(
9774
11414
  "after",
9775
11415
  `
@@ -9784,7 +11424,10 @@ Examples:
9784
11424
  deepline plays get prebuilt/name-and-domain-to-email-waterfall-batch --source > email-waterfall.play.ts
9785
11425
  deepline plays get prebuilt/name-and-domain-to-email-waterfall-batch --source --out ./email-waterfall.play.ts
9786
11426
  `
9787
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--source", "Print raw source code; combine with --out to write a file").option("--out <path>", "Write source to a specific path").action(async (target, options) => {
11427
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
11428
+ "--source",
11429
+ "Print raw source code; combine with --out to write a file"
11430
+ ).option("--out <path>", "Write source to a specific path").action(async (target, options) => {
9788
11431
  process.exitCode = await handlePlayGet([
9789
11432
  target,
9790
11433
  ...options.json ? ["--json"] : [],
@@ -9801,12 +11444,10 @@ Notes:
9801
11444
 
9802
11445
  Examples:
9803
11446
  deepline plays list
9804
- deepline plays list --origin prebuilt --json
9805
11447
  deepline plays search email --json
9806
11448
  `
9807
- ).option("--origin <origin>", "Filter to prebuilt or owned plays").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
11449
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
9808
11450
  process.exitCode = await handlePlayList([
9809
- ...options.origin ? ["--origin", options.origin] : [],
9810
11451
  ...options.json ? ["--json"] : []
9811
11452
  ]);
9812
11453
  });
@@ -9831,7 +11472,9 @@ Examples:
9831
11472
  ]);
9832
11473
  });
9833
11474
  addPlaySearchCommand(play.command("search <query>"));
9834
- play.command("grep <query>").description("Literal grep over play names, aliases, schemas, and descriptions.").addHelpText(
11475
+ play.command("grep <query>").description(
11476
+ "Literal grep over play names, aliases, schemas, and descriptions."
11477
+ ).addHelpText(
9835
11478
  "after",
9836
11479
  `
9837
11480
  Notes:
@@ -9917,7 +11560,9 @@ Examples:
9917
11560
  ]);
9918
11561
  });
9919
11562
  addPublishHelp(
9920
- play.command("set-live <target>").description("Promote a local file or saved revision as the live play revision.")
11563
+ play.command("set-live <target>").description(
11564
+ "Promote a local file or saved revision as the live play revision."
11565
+ )
9921
11566
  ).option("--latest", "Promote the newest saved revision").option("--revision-id <id>", "Revision to promote").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
9922
11567
  process.exitCode = await handlePlayPublish([
9923
11568
  target,
@@ -9962,7 +11607,9 @@ Examples:
9962
11607
  deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
9963
11608
  `
9964
11609
  );
9965
- runs.command("get <runId>").description("Get status, progress, result, errors, and recovery metadata for a play run.").addHelpText(
11610
+ runs.command("get <runId>").description(
11611
+ "Get status, progress, result, errors, and recovery metadata for a play run."
11612
+ ).addHelpText(
9966
11613
  "after",
9967
11614
  `
9968
11615
  Notes:
@@ -10030,7 +11677,11 @@ Examples:
10030
11677
  deepline runs logs play/my-play/run/20260501t000000-000 --limit 500
10031
11678
  deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
10032
11679
  `
10033
- ).option("--limit <count>", "Maximum recent log lines to print without --out", "200").option("--out <path>", "Write the full persisted log stream to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
11680
+ ).option(
11681
+ "--limit <count>",
11682
+ "Maximum recent log lines to print without --out",
11683
+ "200"
11684
+ ).option("--out <path>", "Write the full persisted log stream to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
10034
11685
  process.exitCode = await handleRunLogs([
10035
11686
  runId,
10036
11687
  ...options.limit ? ["--limit", options.limit] : [],
@@ -10071,7 +11722,10 @@ Examples:
10071
11722
  deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --metadata-out output.meta.json
10072
11723
  deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --json
10073
11724
  `
10074
- ).requiredOption("--out <path>", "Output CSV path").option("--dataset <path>", "Returned dataset handle path, such as result.rows").option("--metadata-out <path>", "Write export metadata JSON to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
11725
+ ).requiredOption("--out <path>", "Output CSV path").option(
11726
+ "--dataset <path>",
11727
+ "Returned dataset handle path, such as result.rows"
11728
+ ).option("--metadata-out <path>", "Write export metadata JSON to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
10075
11729
  process.exitCode = await handleRunExport([
10076
11730
  runId,
10077
11731
  ...options.dataset ? ["--dataset", options.dataset] : [],
@@ -10085,14 +11739,14 @@ Examples:
10085
11739
 
10086
11740
  // src/cli/commands/tools.ts
10087
11741
  var import_commander2 = require("commander");
10088
- var import_node_fs10 = require("fs");
11742
+ var import_node_fs11 = require("fs");
10089
11743
  var import_node_os7 = require("os");
10090
- var import_node_path12 = require("path");
11744
+ var import_node_path13 = require("path");
10091
11745
 
10092
11746
  // src/tool-output.ts
10093
- var import_node_fs9 = require("fs");
11747
+ var import_node_fs10 = require("fs");
10094
11748
  var import_node_os6 = require("os");
10095
- var import_node_path11 = require("path");
11749
+ var import_node_path12 = require("path");
10096
11750
  function isPlainObject(value) {
10097
11751
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
10098
11752
  }
@@ -10182,19 +11836,19 @@ function tryConvertToList(payload, options) {
10182
11836
  return null;
10183
11837
  }
10184
11838
  function ensureOutputDir() {
10185
- const outputDir = (0, import_node_path11.join)((0, import_node_os6.homedir)(), ".local", "share", "deepline", "data");
10186
- (0, import_node_fs9.mkdirSync)(outputDir, { recursive: true });
11839
+ const outputDir = (0, import_node_path12.join)((0, import_node_os6.homedir)(), ".local", "share", "deepline", "data");
11840
+ (0, import_node_fs10.mkdirSync)(outputDir, { recursive: true });
10187
11841
  return outputDir;
10188
11842
  }
10189
11843
  function writeJsonOutputFile(payload, stem) {
10190
11844
  const outputDir = ensureOutputDir();
10191
- const outputPath = (0, import_node_path11.join)(outputDir, `${stem}_${Date.now()}.json`);
10192
- (0, import_node_fs9.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
11845
+ const outputPath = (0, import_node_path12.join)(outputDir, `${stem}_${Date.now()}.json`);
11846
+ (0, import_node_fs10.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
10193
11847
  return outputPath;
10194
11848
  }
10195
11849
  function writeCsvOutputFile(rows, stem) {
10196
11850
  const outputDir = ensureOutputDir();
10197
- const outputPath = (0, import_node_path11.join)(outputDir, `${stem}_${Date.now()}.csv`);
11851
+ const outputPath = (0, import_node_path12.join)(outputDir, `${stem}_${Date.now()}.csv`);
10198
11852
  const seen = /* @__PURE__ */ new Set();
10199
11853
  const columns = [];
10200
11854
  for (const row of rows) {
@@ -10217,7 +11871,7 @@ function writeCsvOutputFile(rows, stem) {
10217
11871
  for (const row of rows) {
10218
11872
  lines.push(columns.map((column) => escapeCell(row[column])).join(","));
10219
11873
  }
10220
- (0, import_node_fs9.writeFileSync)(outputPath, `${lines.join("\n")}
11874
+ (0, import_node_fs10.writeFileSync)(outputPath, `${lines.join("\n")}
10221
11875
  `, "utf-8");
10222
11876
  const previewRows = rows.slice(0, 5);
10223
11877
  const previewColumns = columns.slice(0, 5);
@@ -10299,11 +11953,14 @@ async function listTools(args) {
10299
11953
  const client = new DeeplineClient();
10300
11954
  const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
10301
11955
  const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
11956
+ const compact = args.includes("--compact");
10302
11957
  const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
10303
11958
  const items = (await client.listTools({
10304
11959
  ...categoryFilter ? { categories: categoryFilter } : {}
10305
11960
  })).map(toListedTool).filter(
10306
- (item) => requestedCategories.length === 0 || requestedCategories.some((category) => item.categories.includes(category))
11961
+ (item) => requestedCategories.length === 0 || requestedCategories.some(
11962
+ (category) => item.categories.includes(category)
11963
+ )
10307
11964
  );
10308
11965
  const render = {
10309
11966
  sections: [
@@ -10323,10 +11980,11 @@ async function listTools(args) {
10323
11980
  }
10324
11981
  ]
10325
11982
  };
11983
+ const outputItems = compact ? items.map(compactTool) : items;
10326
11984
  printCommandEnvelope(
10327
11985
  {
10328
- tools: items,
10329
- count: items.length,
11986
+ tools: outputItems,
11987
+ count: outputItems.length,
10330
11988
  filters: {
10331
11989
  categories: requestedCategories
10332
11990
  },
@@ -10351,7 +12009,11 @@ async function searchTools(queryInput, options = {}) {
10351
12009
  searchMode: options.searchMode,
10352
12010
  includeSearchDebug: options.includeSearchDebug
10353
12011
  });
10354
- printCommandEnvelope(result, {
12012
+ const payload = options.compact && Array.isArray(result.tools) ? {
12013
+ ...result,
12014
+ tools: result.tools.map(compactTool)
12015
+ } : result;
12016
+ printCommandEnvelope(payload, {
10355
12017
  json: options.json || shouldEmitJson()
10356
12018
  });
10357
12019
  return 0;
@@ -10370,7 +12032,9 @@ async function grepTools(queryInput, options = {}) {
10370
12032
  grepMode: mode,
10371
12033
  ...options.categories ? { categories: options.categories } : {}
10372
12034
  })).map(toListedTool).filter(
10373
- (item) => requestedCategories.length === 0 || requestedCategories.some((category) => item.categories.includes(category))
12035
+ (item) => requestedCategories.length === 0 || requestedCategories.some(
12036
+ (category) => item.categories.includes(category)
12037
+ )
10374
12038
  ).filter(
10375
12039
  (item) => matchesGrepQuery(
10376
12040
  {
@@ -10388,10 +12052,11 @@ async function grepTools(queryInput, options = {}) {
10388
12052
  mode
10389
12053
  )
10390
12054
  );
12055
+ const outputTools = options.compact ? tools.map(compactTool) : tools;
10391
12056
  printCommandEnvelope(
10392
12057
  {
10393
- tools,
10394
- count: tools.length,
12058
+ tools: outputTools,
12059
+ count: outputTools.length,
10395
12060
  query,
10396
12061
  grep: {
10397
12062
  mode,
@@ -10406,6 +12071,19 @@ async function grepTools(queryInput, options = {}) {
10406
12071
  );
10407
12072
  return 0;
10408
12073
  }
12074
+ function compactTool(tool) {
12075
+ const listed = toListedTool(tool);
12076
+ return {
12077
+ id: listed.id,
12078
+ toolId: listed.toolId,
12079
+ provider: listed.provider,
12080
+ displayName: listed.displayName,
12081
+ description: listed.description,
12082
+ categories: listed.categories,
12083
+ type: listed.type,
12084
+ executeCommand: listed.executeCommand
12085
+ };
12086
+ }
10409
12087
  function playIdentifiers(play) {
10410
12088
  return [play.name, play.reference, ...play.aliases ?? []].filter((value) => Boolean(value?.trim())).map((value) => value.trim());
10411
12089
  }
@@ -10478,9 +12156,13 @@ Examples:
10478
12156
  deepline tools list --categories email_finder --json
10479
12157
  deepline tools search email --json
10480
12158
  `
10481
- ).option("--categories <categories>", "Comma-separated categories to filter inventory").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
12159
+ ).option(
12160
+ "--categories <categories>",
12161
+ "Comma-separated categories to filter inventory"
12162
+ ).option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
10482
12163
  process.exitCode = await listTools([
10483
12164
  ...options.categories ? ["--categories", options.categories] : [],
12165
+ ...options.compact ? ["--compact"] : [],
10484
12166
  ...options.json ? ["--json"] : []
10485
12167
  ]);
10486
12168
  });
@@ -10498,9 +12180,19 @@ Examples:
10498
12180
  deepline tools grep "company enrichment" --categories enrichment --json
10499
12181
  deepline tools search verifier --search-mode v2 --json
10500
12182
  `
10501
- ).option("--categories <categories>", "Comma-separated categories to filter ranked search").option("--search_terms <terms>", "Structured search terms for ranked search").option("--search-terms <terms>", "Structured search terms for ranked search").option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
12183
+ ).option(
12184
+ "--categories <categories>",
12185
+ "Comma-separated categories to filter ranked search"
12186
+ ).option(
12187
+ "--search_terms <terms>",
12188
+ "Structured search terms for ranked search"
12189
+ ).option(
12190
+ "--search-terms <terms>",
12191
+ "Structured search terms for ranked search"
12192
+ ).option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
10502
12193
  process.exitCode = await searchTools(query, {
10503
12194
  json: options.json,
12195
+ compact: options.compact,
10504
12196
  categories: options.categories,
10505
12197
  searchTerms: options.searchTerms ?? options.search_terms,
10506
12198
  searchMode: options.searchMode === "v1" || options.searchMode === "v2" ? options.searchMode : void 0,
@@ -10508,7 +12200,9 @@ Examples:
10508
12200
  });
10509
12201
  });
10510
12202
  addToolSearchCommand(tools.command("search <query>"));
10511
- tools.command("grep <query>").description("Literal grep over tool ids, descriptions, categories, and input fields.").addHelpText(
12203
+ tools.command("grep <query>").description(
12204
+ "Literal grep over tool ids, descriptions, categories, and input fields."
12205
+ ).addHelpText(
10512
12206
  "after",
10513
12207
  `
10514
12208
  Notes:
@@ -10522,10 +12216,14 @@ Examples:
10522
12216
  deepline tools grep "phone validate" --mode all --json
10523
12217
  deepline tools grep hunter --mode phrase --json
10524
12218
  `
10525
- ).option("--categories <categories>", "Comma-separated categories to filter inventory").option("--mode <mode>", "Grep matching mode: all, any, or phrase").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
12219
+ ).option(
12220
+ "--categories <categories>",
12221
+ "Comma-separated categories to filter inventory"
12222
+ ).option("--mode <mode>", "Grep matching mode: all, any, or phrase").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
10526
12223
  const mode = options.mode === "any" || options.mode === "phrase" ? options.mode : "all";
10527
12224
  process.exitCode = await grepTools(query, {
10528
12225
  json: options.json,
12226
+ compact: options.compact,
10529
12227
  categories: options.categories,
10530
12228
  mode
10531
12229
  });
@@ -10546,7 +12244,20 @@ Examples:
10546
12244
  deepline tools describe hunter_email_verifier --json
10547
12245
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
10548
12246
  `
10549
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--pricing-only", "Only print pricing and billing semantics").option("--schema-only", "Only print input schema fields").option("--examples-only", "Only print runnable examples and sample payloads").option("--getters-only", "Only print extracted list/value getters").addOption(new import_commander2.Option("--compact", "Compatibility alias for the default compact view").hideHelp()).addOption(new import_commander2.Option("--contract-json", "Compatibility alias for compact contract JSON").hideHelp()).action(async (toolId, options) => {
12247
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--pricing-only", "Only print pricing and billing semantics").option("--schema-only", "Only print input schema fields").option(
12248
+ "--examples-only",
12249
+ "Only print runnable examples and sample payloads"
12250
+ ).option("--getters-only", "Only print extracted list/value getters").addOption(
12251
+ new import_commander2.Option(
12252
+ "--compact",
12253
+ "Compatibility alias for the default compact view"
12254
+ ).hideHelp()
12255
+ ).addOption(
12256
+ new import_commander2.Option(
12257
+ "--contract-json",
12258
+ "Compatibility alias for compact contract JSON"
12259
+ ).hideHelp()
12260
+ ).action(async (toolId, options) => {
10550
12261
  process.exitCode = await getTool(toolId, {
10551
12262
  json: Boolean(options.json),
10552
12263
  compact: Boolean(options.compact),
@@ -10588,13 +12299,24 @@ Examples:
10588
12299
  deepline tools execute hunter_email_verifier -p email=a@b.com
10589
12300
  deepline tools execute test_rate_limit --input '{"key":"smoke"}' --json | jq '.status'
10590
12301
  `
10591
- ).option("-p, --param <key=value>", "Pass one parameter. Repeat for multiple values.", (value, acc) => {
10592
- acc.push(value);
10593
- return acc;
10594
- }, []).option("--json [payload]", "Emit JSON output. Use `--input` or `--payload` for passing JSON params.").option("--input <payload>", "Merge a JSON object into the tool params").option("--payload <payload>", "Merge a JSON object into the tool params").option(
12302
+ ).option(
12303
+ "-p, --param <key=value>",
12304
+ "Pass one parameter. Repeat for multiple values.",
12305
+ (value, acc) => {
12306
+ acc.push(value);
12307
+ return acc;
12308
+ },
12309
+ []
12310
+ ).option(
12311
+ "--json [payload]",
12312
+ "Emit JSON output. Use `--input` or `--payload` for passing JSON params."
12313
+ ).option("--input <payload>", "Merge a JSON object into the tool params").option("--payload <payload>", "Merge a JSON object into the tool params").option(
10595
12314
  "--output-format <format>",
10596
12315
  "Output format: auto, csv, csv_file, json, or json_file"
10597
- ).option("--no-preview", "Only print the extracted output path when applicable").action(async (toolId, options) => {
12316
+ ).option(
12317
+ "--no-preview",
12318
+ "Only print the extracted output path when applicable"
12319
+ ).action(async (toolId, options) => {
10598
12320
  const args = [
10599
12321
  toolId,
10600
12322
  ...options.param.flatMap((value) => ["--param", value]),
@@ -10626,14 +12348,18 @@ async function getTool(toolId, options = {}) {
10626
12348
  throw error;
10627
12349
  }
10628
12350
  if (options.contractJson) {
10629
- process.stdout.write(`${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
10630
- `);
12351
+ process.stdout.write(
12352
+ `${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
12353
+ `
12354
+ );
10631
12355
  return 0;
10632
12356
  }
10633
12357
  const emitJson = options.json === true;
10634
12358
  if (emitJson) {
10635
- process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
10636
- `);
12359
+ process.stdout.write(
12360
+ `${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
12361
+ `
12362
+ );
10637
12363
  return 0;
10638
12364
  }
10639
12365
  const onlyModes = [
@@ -10643,7 +12369,9 @@ async function getTool(toolId, options = {}) {
10643
12369
  options.gettersOnly
10644
12370
  ].filter(Boolean).length;
10645
12371
  if (onlyModes > 1) {
10646
- console.error("Use only one of --pricing-only, --schema-only, --examples-only, or --getters-only.");
12372
+ console.error(
12373
+ "Use only one of --pricing-only, --schema-only, --examples-only, or --getters-only."
12374
+ );
10647
12375
  return 2;
10648
12376
  }
10649
12377
  if (options.pricingOnly) {
@@ -10667,8 +12395,10 @@ async function getTool(toolId, options = {}) {
10667
12395
  return 0;
10668
12396
  }
10669
12397
  if (shouldEmitJson()) {
10670
- process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
10671
- `);
12398
+ process.stdout.write(
12399
+ `${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
12400
+ `
12401
+ );
10672
12402
  return 0;
10673
12403
  }
10674
12404
  printCompactToolContract(tool, toolId);
@@ -10676,9 +12406,15 @@ async function getTool(toolId, options = {}) {
10676
12406
  }
10677
12407
  function toolContractJsonForDescribe(tool, requestedToolId) {
10678
12408
  const toolId = String(tool.toolId || requestedToolId);
10679
- const inputFields = toolInputFieldsForDisplay(recordField(tool, "inputSchema", "input_schema"));
12409
+ const inputFields = toolInputFieldsForDisplay(
12410
+ recordField(tool, "inputSchema", "input_schema")
12411
+ );
10680
12412
  const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
10681
- const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
12413
+ const toolExecutionResult = recordField(
12414
+ usageGuidance,
12415
+ "toolExecutionResult",
12416
+ "tool_execution_result"
12417
+ );
10682
12418
  const extractedLists = extractionContractEntries(
10683
12419
  arrayField(toolExecutionResult, "extractedLists", "extracted_lists")
10684
12420
  );
@@ -10731,7 +12467,7 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
10731
12467
  }
10732
12468
  function extractionContractEntries(entries) {
10733
12469
  return entries.flatMap((entry) => {
10734
- if (!isRecord4(entry)) return [];
12470
+ if (!isRecord5(entry)) return [];
10735
12471
  const name = stringField(entry, "name");
10736
12472
  const expression = stringField(entry, "expression");
10737
12473
  return name && expression ? [{ name, expression }] : [];
@@ -10739,8 +12475,8 @@ function extractionContractEntries(entries) {
10739
12475
  }
10740
12476
  function printCompactToolContract(tool, requestedToolId) {
10741
12477
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
10742
- const cost = isRecord4(contract.cost) ? contract.cost : {};
10743
- const getters = isRecord4(contract.getters) ? contract.getters : {};
12478
+ const cost = isRecord5(contract.cost) ? contract.cost : {};
12479
+ const getters = isRecord5(contract.getters) ? contract.getters : {};
10744
12480
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
10745
12481
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
10746
12482
  const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
@@ -10757,18 +12493,20 @@ function printCompactToolContract(tool, requestedToolId) {
10757
12493
  console.log("");
10758
12494
  console.log("Inputs:");
10759
12495
  for (const field of inputFields) {
10760
- if (!isRecord4(field)) continue;
12496
+ if (!isRecord5(field)) continue;
10761
12497
  const name = stringField(field, "name");
10762
12498
  if (!name) continue;
10763
12499
  const required = field.required ? "*" : "";
10764
12500
  const type = stringField(field, "type") || "unknown";
10765
12501
  const description = stringField(field, "description");
10766
- console.log(`- ${name}${required}: ${type}${description ? ` - ${description}` : ""}`);
12502
+ console.log(
12503
+ `- ${name}${required}: ${type}${description ? ` - ${description}` : ""}`
12504
+ );
10767
12505
  }
10768
12506
  }
10769
12507
  console.log("");
10770
12508
  printToolExamplesOnly(tool, requestedToolId, { includeSamples: false });
10771
- const starterScript = isRecord4(contract.starterScript) ? contract.starterScript : {};
12509
+ const starterScript = isRecord5(contract.starterScript) ? contract.starterScript : {};
10772
12510
  const starterPath = stringField(starterScript, "path");
10773
12511
  if (starterPath) {
10774
12512
  console.log("");
@@ -10780,19 +12518,27 @@ function printCompactToolContract(tool, requestedToolId) {
10780
12518
  console.log("Getters:");
10781
12519
  if (listGetters.length) console.log("Lists:");
10782
12520
  for (const entry of listGetters) {
10783
- if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
12521
+ if (isRecord5(entry))
12522
+ console.log(
12523
+ `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
12524
+ );
10784
12525
  }
10785
12526
  if (valueGetters.length) console.log("Values:");
10786
12527
  for (const entry of valueGetters) {
10787
- if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
12528
+ if (isRecord5(entry))
12529
+ console.log(
12530
+ `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
12531
+ );
10788
12532
  }
10789
12533
  }
10790
12534
  console.log("");
10791
- console.log(`More: deepline tools describe ${contract.toolId} --pricing-only | --schema-only | --examples-only | --getters-only | --json`);
12535
+ console.log(
12536
+ `More: deepline tools describe ${contract.toolId} --pricing-only | --schema-only | --examples-only | --getters-only | --json`
12537
+ );
10792
12538
  }
10793
12539
  function printToolPricingOnly(tool, requestedToolId, options = {}) {
10794
12540
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
10795
- const cost = isRecord4(contract.cost) ? contract.cost : {};
12541
+ const cost = isRecord5(contract.cost) ? contract.cost : {};
10796
12542
  const pricingModel = stringField(cost, "pricingModel") || "unknown";
10797
12543
  const billingMode = stringField(cost, "billingMode") || "unknown";
10798
12544
  const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : pricingModel === "fixed" ? "call" : pricingModel.replace(/^per_/, "") || "unit";
@@ -10812,14 +12558,16 @@ function printToolSchemaOnly(tool, requestedToolId) {
10812
12558
  }
10813
12559
  console.log("Inputs:");
10814
12560
  for (const field of inputFields) {
10815
- if (!isRecord4(field)) continue;
12561
+ if (!isRecord5(field)) continue;
10816
12562
  const name = stringField(field, "name");
10817
12563
  if (!name) continue;
10818
12564
  const required = field.required ? "*" : "";
10819
12565
  const type = stringField(field, "type") || "unknown";
10820
12566
  const description = stringField(field, "description");
10821
12567
  const defaultSuffix = Object.prototype.hasOwnProperty.call(field, "default") ? ` default=${JSON.stringify(field.default)}` : "";
10822
- console.log(`- ${name}${required}: ${type}${defaultSuffix}${description ? ` - ${description}` : ""}`);
12568
+ console.log(
12569
+ `- ${name}${required}: ${type}${defaultSuffix}${description ? ` - ${description}` : ""}`
12570
+ );
10823
12571
  }
10824
12572
  }
10825
12573
  function printToolExamplesOnly(tool, requestedToolId, options = {}) {
@@ -10832,16 +12580,21 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
10832
12580
  console.log("const result = await ctx.tools.execute({");
10833
12581
  console.log(` id: '${stableStepIdForTool(toolId)}',`);
10834
12582
  console.log(` tool: '${toolId}',`);
10835
- console.log(` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`);
12583
+ console.log(
12584
+ ` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`
12585
+ );
10836
12586
  console.log("});");
10837
- const getters = isRecord4(contract.getters) ? contract.getters : {};
12587
+ const getters = isRecord5(contract.getters) ? contract.getters : {};
10838
12588
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
10839
12589
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
10840
- const firstGetter = [...valueGetters, ...listGetters].find(isRecord4);
12590
+ const firstGetter = [...valueGetters, ...listGetters].find(isRecord5);
10841
12591
  if (firstGetter) {
10842
12592
  const name = stringField(firstGetter, "name") || "value";
10843
12593
  const expression = stringField(firstGetter, "expression");
10844
- if (expression) console.log(`const ${safeIdentifier(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`);
12594
+ if (expression)
12595
+ console.log(
12596
+ `const ${safeIdentifier2(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`
12597
+ );
10845
12598
  }
10846
12599
  console.log("```");
10847
12600
  if (options.includeSamples !== false) {
@@ -10851,31 +12604,40 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
10851
12604
  }
10852
12605
  function printToolGettersOnly(tool, requestedToolId) {
10853
12606
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
10854
- const getters = isRecord4(contract.getters) ? contract.getters : {};
12607
+ const getters = isRecord5(contract.getters) ? contract.getters : {};
10855
12608
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
10856
12609
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
10857
12610
  console.log(`Getters: ${contract.toolId}`);
10858
12611
  if (!listGetters.length && !valueGetters.length) {
10859
- console.log("No generated getters declared. Use --json only if you need raw metadata.");
12612
+ console.log(
12613
+ "No generated getters declared. Use --json only if you need raw metadata."
12614
+ );
10860
12615
  return;
10861
12616
  }
10862
12617
  if (listGetters.length) {
10863
12618
  console.log("Lists:");
10864
12619
  for (const entry of listGetters) {
10865
- if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
12620
+ if (isRecord5(entry))
12621
+ console.log(
12622
+ `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
12623
+ );
10866
12624
  }
10867
12625
  }
10868
12626
  if (valueGetters.length) {
10869
12627
  console.log("Values:");
10870
12628
  for (const entry of valueGetters) {
10871
- if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
12629
+ if (isRecord5(entry))
12630
+ console.log(
12631
+ `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
12632
+ );
10872
12633
  }
10873
12634
  }
10874
12635
  }
10875
12636
  function sampleValueForField(field) {
10876
12637
  const name = stringField(field, "name").toLowerCase();
10877
12638
  const type = stringField(field, "type").toLowerCase();
10878
- if (Object.prototype.hasOwnProperty.call(field, "default")) return field.default;
12639
+ if (Object.prototype.hasOwnProperty.call(field, "default"))
12640
+ return field.default;
10879
12641
  if (name.includes("email")) return "ada@example.com";
10880
12642
  if (name.includes("domain") || name.includes("website")) return "example.com";
10881
12643
  if (name.includes("first")) return "Ada";
@@ -10890,7 +12652,7 @@ function sampleValueForField(field) {
10890
12652
  function samplePayloadForInputFields(fields) {
10891
12653
  return Object.fromEntries(
10892
12654
  fields.slice(0, 4).flatMap((field) => {
10893
- if (!isRecord4(field)) return [];
12655
+ if (!isRecord5(field)) return [];
10894
12656
  const name = stringField(field, "name");
10895
12657
  if (!name) return [];
10896
12658
  return [[name, sampleValueForField(field)]];
@@ -10900,12 +12662,15 @@ function samplePayloadForInputFields(fields) {
10900
12662
  function stableStepIdForTool(toolId) {
10901
12663
  return toolId.replace(/^[a-z0-9]+_/, "").replace(/[^a-z0-9_]+/gi, "_") || "tool_call";
10902
12664
  }
10903
- function safeIdentifier(name) {
12665
+ function safeIdentifier2(name) {
10904
12666
  const cleaned = name.replace(/[^a-zA-Z0-9_$]+/g, "_").replace(/^[^a-zA-Z_$]+/, "");
10905
12667
  return cleaned || "value";
10906
12668
  }
10907
12669
  function playResultExpression(entry) {
10908
- return stringField(entry, "expression").replace(/^toolExecutionResult\./, "result.");
12670
+ return stringField(entry, "expression").replace(
12671
+ /^toolExecutionResult\./,
12672
+ "result."
12673
+ );
10909
12674
  }
10910
12675
  function toolMetadataJsonForDescribe(tool, requestedToolId) {
10911
12676
  const toolId = String(tool.toolId || requestedToolId);
@@ -10996,12 +12761,13 @@ function formatListedToolCost(tool) {
10996
12761
  return displayText ? `Cost: ${displayText}` : "";
10997
12762
  }
10998
12763
  function toolInputFieldsForDisplay(inputSchema) {
10999
- if (Array.isArray(inputSchema.fields)) return inputSchema.fields.filter(isRecord4);
11000
- const jsonSchema = isRecord4(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
11001
- const properties = isRecord4(jsonSchema.properties) ? jsonSchema.properties : {};
12764
+ if (Array.isArray(inputSchema.fields))
12765
+ return inputSchema.fields.filter(isRecord5);
12766
+ const jsonSchema = isRecord5(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
12767
+ const properties = isRecord5(jsonSchema.properties) ? jsonSchema.properties : {};
11002
12768
  const required = Array.isArray(jsonSchema.required) ? new Set(jsonSchema.required.map(String)) : /* @__PURE__ */ new Set();
11003
12769
  return Object.entries(properties).map(([name, value]) => {
11004
- const property = isRecord4(value) ? value : {};
12770
+ const property = isRecord5(value) ? value : {};
11005
12771
  return {
11006
12772
  name,
11007
12773
  type: typeof property.type === "string" ? property.type : "unknown",
@@ -11016,8 +12782,10 @@ function printSamples(samples) {
11016
12782
  const responsePayload = samplePayload(samples, "response");
11017
12783
  if (requestPayload === void 0 && responsePayload === void 0) return;
11018
12784
  console.log(" Samples:");
11019
- if (requestPayload !== void 0) printJsonPreview("Example payload", requestPayload);
11020
- if (responsePayload !== void 0) printJsonPreview("Example response", responsePayload);
12785
+ if (requestPayload !== void 0)
12786
+ printJsonPreview("Example payload", requestPayload);
12787
+ if (responsePayload !== void 0)
12788
+ printJsonPreview("Example response", responsePayload);
11021
12789
  }
11022
12790
  function printJsonPreview(label, payload) {
11023
12791
  console.log(` ${label}:`);
@@ -11028,15 +12796,15 @@ function printJsonPreview(label, payload) {
11028
12796
  }
11029
12797
  function samplePayload(samples, key) {
11030
12798
  const entry = samples[key];
11031
- if (!isRecord4(entry)) return void 0;
12799
+ if (!isRecord5(entry)) return void 0;
11032
12800
  return Object.prototype.hasOwnProperty.call(entry, "payload") ? entry.payload : entry;
11033
12801
  }
11034
12802
  function commandEnvelopeFromRawResponse(rawResponse) {
11035
- return isRecord4(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
12803
+ return isRecord5(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
11036
12804
  }
11037
12805
  function listExtractorPathsFromUsageGuidance(tool) {
11038
12806
  const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
11039
- const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord4(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
12807
+ const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord5(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
11040
12808
  return extractedLists.flatMap((entry) => {
11041
12809
  const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
11042
12810
  if (!Array.isArray(paths)) return [];
@@ -11052,7 +12820,7 @@ function formatDecimal(value) {
11052
12820
  function formatUsd(value) {
11053
12821
  return `$${formatDecimal(value)}`;
11054
12822
  }
11055
- function isRecord4(value) {
12823
+ function isRecord5(value) {
11056
12824
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
11057
12825
  }
11058
12826
  function stringField(source, ...keys) {
@@ -11079,7 +12847,7 @@ function arrayField(source, ...keys) {
11079
12847
  function recordField(source, ...keys) {
11080
12848
  for (const key of keys) {
11081
12849
  const value = source[key];
11082
- if (isRecord4(value)) return value;
12850
+ if (isRecord5(value)) return value;
11083
12851
  }
11084
12852
  return {};
11085
12853
  }
@@ -11102,7 +12870,9 @@ function normalizeOutputFormat(raw) {
11102
12870
  function parseExecuteOptions(args) {
11103
12871
  const toolId = args[0];
11104
12872
  if (!toolId) {
11105
- throw new Error(`Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--no-preview]`);
12873
+ throw new Error(
12874
+ `Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--no-preview]`
12875
+ );
11106
12876
  }
11107
12877
  const params = {};
11108
12878
  let outputFormat = "auto";
@@ -11151,9 +12921,9 @@ function powerShellQuote(value) {
11151
12921
  function seedToolListScript(input) {
11152
12922
  const stem = safeFileStem(input.toolId);
11153
12923
  const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
11154
- const scriptDir = (0, import_node_fs10.mkdtempSync)((0, import_node_path12.join)((0, import_node_os7.tmpdir)(), "deepline-workflow-seed-"));
11155
- (0, import_node_fs10.chmodSync)(scriptDir, 448);
11156
- const scriptPath = (0, import_node_path12.join)(scriptDir, fileName);
12924
+ const scriptDir = (0, import_node_fs11.mkdtempSync)((0, import_node_path13.join)((0, import_node_os7.tmpdir)(), "deepline-workflow-seed-"));
12925
+ (0, import_node_fs11.chmodSync)(scriptDir, 448);
12926
+ const scriptPath = (0, import_node_path13.join)(scriptDir, fileName);
11157
12927
  const projectDir = `deepline/projects/${stem}-workflow`;
11158
12928
  const playName = `${stem}-workflow`;
11159
12929
  const sampleRows = input.rows.length > 0 ? `${JSON.stringify(input.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
@@ -11189,7 +12959,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
11189
12959
  };
11190
12960
  });
11191
12961
  `;
11192
- (0, import_node_fs10.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
12962
+ (0, import_node_fs11.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
11193
12963
  return {
11194
12964
  path: scriptPath,
11195
12965
  sourceCode: script,
@@ -11212,7 +12982,7 @@ function buildToolExecuteBaseEnvelope(input) {
11212
12982
  kind: summaryEntries.length > 0 ? "object" : "raw",
11213
12983
  summary: input.summary
11214
12984
  };
11215
- const envelopeHasCanonicalOutput = isRecord4(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
12985
+ const envelopeHasCanonicalOutput = isRecord5(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
11216
12986
  const inspectCommand = `deepline tools execute ${input.toolId} --input ${shellQuote(JSON.stringify(input.params))} --json`;
11217
12987
  const actions = input.listConversion ? [
11218
12988
  {
@@ -11246,7 +13016,9 @@ function buildToolExecuteBaseEnvelope(input) {
11246
13016
  ] : [
11247
13017
  {
11248
13018
  title: "result",
11249
- lines: summaryEntries.length > 0 ? summaryEntries.map(([key, value]) => `${key}=${String(value)}`) : [JSON.stringify(input.rawResponse, null, 2)]
13019
+ lines: summaryEntries.length > 0 ? summaryEntries.map(
13020
+ ([key, value]) => `${key}=${String(value)}`
13021
+ ) : [JSON.stringify(input.rawResponse, null, 2)]
11250
13022
  }
11251
13023
  ],
11252
13024
  actions
@@ -11273,7 +13045,9 @@ async function executeTool(args) {
11273
13045
  const play = await findPlayForToolId(client, parsed.toolId);
11274
13046
  if (play) {
11275
13047
  if (argsWantJson(args)) {
11276
- printJsonError(new Error(playAliasToolErrorMessage(parsed.toolId, play)));
13048
+ printJsonError(
13049
+ new Error(playAliasToolErrorMessage(parsed.toolId, play))
13050
+ );
11277
13051
  } else {
11278
13052
  printPlayAliasToolError(parsed.toolId, play);
11279
13053
  }
@@ -11309,12 +13083,15 @@ async function executeTool(args) {
11309
13083
  return 0;
11310
13084
  }
11311
13085
  if (parsed.outputFormat === "json_file") {
11312
- const jsonPath = writeJsonOutputFile(rawResponse, `payload_${parsed.toolId}`);
13086
+ const jsonPath = writeJsonOutputFile(
13087
+ rawResponse,
13088
+ `payload_${parsed.toolId}`
13089
+ );
11313
13090
  printCommandEnvelope(
11314
13091
  {
11315
13092
  ...baseEnvelope,
11316
13093
  local: {
11317
- ...isRecord4(baseEnvelope.local) ? baseEnvelope.local : {},
13094
+ ...isRecord5(baseEnvelope.local) ? baseEnvelope.local : {},
11318
13095
  payload_file: jsonPath
11319
13096
  }
11320
13097
  },
@@ -11324,7 +13101,10 @@ async function executeTool(args) {
11324
13101
  }
11325
13102
  if (!listConversion) {
11326
13103
  if (parsed.outputFormat === "csv" || parsed.outputFormat === "csv_file") {
11327
- const jsonPath = writeJsonOutputFile(rawResponse, `payload_${parsed.toolId}`);
13104
+ const jsonPath = writeJsonOutputFile(
13105
+ rawResponse,
13106
+ `payload_${parsed.toolId}`
13107
+ );
11328
13108
  printCommandEnvelope(
11329
13109
  {
11330
13110
  ...baseEnvelope,
@@ -11339,7 +13119,10 @@ async function executeTool(args) {
11339
13119
  printCommandEnvelope(baseEnvelope, { json: false });
11340
13120
  return 0;
11341
13121
  }
11342
- const csv = writeCsvOutputFile(listConversion.rows, `${parsed.toolId}_output`);
13122
+ const csv = writeCsvOutputFile(
13123
+ listConversion.rows,
13124
+ `${parsed.toolId}_output`
13125
+ );
11343
13126
  const seededScript = seedToolListScript({
11344
13127
  toolId: parsed.toolId,
11345
13128
  payload: parsed.params,
@@ -11365,7 +13148,9 @@ async function executeTool(args) {
11365
13148
  title: `${csv.path} (${csv.rowCount} rows)`,
11366
13149
  lines: [
11367
13150
  ...csv.columns.length > 0 ? [`columns: ${JSON.stringify(csv.columns)}`] : [],
11368
- ...Object.keys(summary).length > 0 ? [`summary: ${Object.entries(summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`] : [],
13151
+ ...Object.keys(summary).length > 0 ? [
13152
+ `summary: ${Object.entries(summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`
13153
+ ] : [],
11369
13154
  `preview: ${JSON.stringify(csv.preview)}`,
11370
13155
  `starter script: ${seededScript.path}`
11371
13156
  ]
@@ -11388,22 +13173,25 @@ async function executeTool(args) {
11388
13173
  }
11389
13174
  };
11390
13175
  if (parsed.outputFormat === "csv_file") {
11391
- printCommandEnvelope({
11392
- ...materializedEnvelope,
11393
- extracted_csv: csv.path,
11394
- extracted_csv_rows: csv.rowCount,
11395
- extracted_csv_columns: csv.columns,
11396
- preview: csv.preview,
11397
- list_strategy: listConversion.strategy,
11398
- list_source_path: listConversion.sourcePath,
11399
- starter_script: seededScript.path,
11400
- project_dir: seededScript.projectDir,
11401
- copy_to_project: {
11402
- macos_linux: seededScript.macCopyCommand,
11403
- windows_powershell: seededScript.windowsCopyCommand
13176
+ printCommandEnvelope(
13177
+ {
13178
+ ...materializedEnvelope,
13179
+ extracted_csv: csv.path,
13180
+ extracted_csv_rows: csv.rowCount,
13181
+ extracted_csv_columns: csv.columns,
13182
+ preview: csv.preview,
13183
+ list_strategy: listConversion.strategy,
13184
+ list_source_path: listConversion.sourcePath,
13185
+ starter_script: seededScript.path,
13186
+ project_dir: seededScript.projectDir,
13187
+ copy_to_project: {
13188
+ macos_linux: seededScript.macCopyCommand,
13189
+ windows_powershell: seededScript.windowsCopyCommand
13190
+ },
13191
+ summary
11404
13192
  },
11405
- summary
11406
- }, { json: true });
13193
+ { json: true }
13194
+ );
11407
13195
  return 0;
11408
13196
  }
11409
13197
  if (parsed.noPreview) {
@@ -11426,8 +13214,8 @@ async function executeTool(args) {
11426
13214
 
11427
13215
  // src/cli/commands/update.ts
11428
13216
  var import_node_child_process = require("child_process");
11429
- var import_node_fs11 = require("fs");
11430
- var import_node_path13 = require("path");
13217
+ var import_node_fs12 = require("fs");
13218
+ var import_node_path14 = require("path");
11431
13219
  function posixShellQuote(value) {
11432
13220
  return `'${value.replace(/'/g, `'\\''`)}'`;
11433
13221
  }
@@ -11446,19 +13234,19 @@ function buildSourceUpdateCommand(sourceRoot) {
11446
13234
  return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
11447
13235
  }
11448
13236
  function findRepoBackedSdkRoot(startPath) {
11449
- let current = (0, import_node_path13.resolve)(startPath);
13237
+ let current = (0, import_node_path14.resolve)(startPath);
11450
13238
  while (true) {
11451
- if ((0, import_node_fs11.existsSync)((0, import_node_path13.join)(current, "sdk", "package.json")) && (0, import_node_fs11.existsSync)((0, import_node_path13.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
13239
+ if ((0, import_node_fs12.existsSync)((0, import_node_path14.join)(current, "sdk", "package.json")) && (0, import_node_fs12.existsSync)((0, import_node_path14.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
11452
13240
  return current;
11453
13241
  }
11454
- const parent = (0, import_node_path13.dirname)(current);
13242
+ const parent = (0, import_node_path14.dirname)(current);
11455
13243
  if (parent === current) return null;
11456
13244
  current = parent;
11457
13245
  }
11458
13246
  }
11459
13247
  function resolveUpdatePlan() {
11460
- const entrypoint = process.argv[1] ? (0, import_node_path13.resolve)(process.argv[1]) : "";
11461
- const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path13.dirname)(entrypoint)) : null;
13248
+ const entrypoint = process.argv[1] ? (0, import_node_path14.resolve)(process.argv[1]) : "";
13249
+ const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path14.dirname)(entrypoint)) : null;
11462
13250
  if (sourceRoot) {
11463
13251
  return {
11464
13252
  kind: "source",
@@ -11551,9 +13339,9 @@ Examples:
11551
13339
 
11552
13340
  // src/cli/skills-sync.ts
11553
13341
  var import_node_child_process2 = require("child_process");
11554
- var import_node_fs12 = require("fs");
13342
+ var import_node_fs13 = require("fs");
11555
13343
  var import_node_os8 = require("os");
11556
- var import_node_path14 = require("path");
13344
+ var import_node_path15 = require("path");
11557
13345
  var CHECK_TIMEOUT_MS2 = 3e3;
11558
13346
  var SDK_SKILL_NAME = "deepline-sdk";
11559
13347
  var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
@@ -11564,28 +13352,28 @@ function shouldSkipSkillsSync() {
11564
13352
  }
11565
13353
  function sdkSkillsVersionPath(baseUrl) {
11566
13354
  const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
11567
- return (0, import_node_path14.join)(home, ".local", "deepline", baseUrlSlug(baseUrl), "sdk-skills", ".version");
13355
+ return (0, import_node_path15.join)(home, ".local", "deepline", baseUrlSlug(baseUrl), "sdk-skills", ".version");
11568
13356
  }
11569
13357
  function readLocalSkillsVersion(baseUrl) {
11570
13358
  const path = sdkSkillsVersionPath(baseUrl);
11571
- if (!(0, import_node_fs12.existsSync)(path)) return "";
13359
+ if (!(0, import_node_fs13.existsSync)(path)) return "";
11572
13360
  try {
11573
- return (0, import_node_fs12.readFileSync)(path, "utf-8").trim();
13361
+ return (0, import_node_fs13.readFileSync)(path, "utf-8").trim();
11574
13362
  } catch {
11575
13363
  return "";
11576
13364
  }
11577
13365
  }
11578
13366
  function writeLocalSkillsVersion(baseUrl, version) {
11579
13367
  const path = sdkSkillsVersionPath(baseUrl);
11580
- (0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
11581
- (0, import_node_fs12.writeFileSync)(path, `${version}
13368
+ (0, import_node_fs13.mkdirSync)((0, import_node_path15.dirname)(path), { recursive: true });
13369
+ (0, import_node_fs13.writeFileSync)(path, `${version}
11582
13370
  `, "utf-8");
11583
13371
  }
11584
13372
  function installedSdkSkillHasStalePositionalExecuteExamples() {
11585
13373
  const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
11586
13374
  const roots = [
11587
- (0, import_node_path14.join)(home, ".claude", "skills", SDK_SKILL_NAME),
11588
- (0, import_node_path14.join)(home, ".agents", "skills", SDK_SKILL_NAME)
13375
+ (0, import_node_path15.join)(home, ".claude", "skills", SDK_SKILL_NAME),
13376
+ (0, import_node_path15.join)(home, ".agents", "skills", SDK_SKILL_NAME)
11589
13377
  ];
11590
13378
  const staleMarkers = [
11591
13379
  "ctx.tools.execute(key",
@@ -11595,22 +13383,22 @@ function installedSdkSkillHasStalePositionalExecuteExamples() {
11595
13383
  'rowCtx.tools.execute("'
11596
13384
  ];
11597
13385
  const scan = (dir) => {
11598
- for (const entry of (0, import_node_fs12.readdirSync)(dir)) {
11599
- const path = (0, import_node_path14.join)(dir, entry);
11600
- const stat3 = (0, import_node_fs12.statSync)(path);
13386
+ for (const entry of (0, import_node_fs13.readdirSync)(dir)) {
13387
+ const path = (0, import_node_path15.join)(dir, entry);
13388
+ const stat3 = (0, import_node_fs13.statSync)(path);
11601
13389
  if (stat3.isDirectory()) {
11602
13390
  if (scan(path)) return true;
11603
13391
  continue;
11604
13392
  }
11605
13393
  if (!entry.endsWith(".md")) continue;
11606
- const text = (0, import_node_fs12.readFileSync)(path, "utf-8");
13394
+ const text = (0, import_node_fs13.readFileSync)(path, "utf-8");
11607
13395
  if (staleMarkers.some((marker) => text.includes(marker))) return true;
11608
13396
  }
11609
13397
  return false;
11610
13398
  };
11611
13399
  for (const root of roots) {
11612
13400
  try {
11613
- if ((0, import_node_fs12.existsSync)(root) && scan(root)) return true;
13401
+ if ((0, import_node_fs13.existsSync)(root) && scan(root)) return true;
11614
13402
  } catch {
11615
13403
  continue;
11616
13404
  }
@@ -11708,7 +13496,7 @@ function resolveSkillsInstallCommands(baseUrl) {
11708
13496
  return [npxInstall];
11709
13497
  }
11710
13498
  function runOneSkillsInstall(install) {
11711
- return new Promise((resolve11) => {
13499
+ return new Promise((resolve12) => {
11712
13500
  const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
11713
13501
  stdio: ["ignore", "ignore", "pipe"],
11714
13502
  env: process.env
@@ -11718,7 +13506,7 @@ function runOneSkillsInstall(install) {
11718
13506
  stderr += chunk.toString("utf-8");
11719
13507
  });
11720
13508
  child.on("error", (error) => {
11721
- resolve11({
13509
+ resolve12({
11722
13510
  ok: false,
11723
13511
  detail: `failed to start ${install.command}: ${error.message}`,
11724
13512
  manualCommand: install.manualCommand
@@ -11726,11 +13514,11 @@ function runOneSkillsInstall(install) {
11726
13514
  });
11727
13515
  child.on("close", (code) => {
11728
13516
  if (code === 0) {
11729
- resolve11({ ok: true, detail: "", manualCommand: install.manualCommand });
13517
+ resolve12({ ok: true, detail: "", manualCommand: install.manualCommand });
11730
13518
  return;
11731
13519
  }
11732
13520
  const detail = stderr.trim();
11733
- resolve11({
13521
+ resolve12({
11734
13522
  ok: false,
11735
13523
  detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
11736
13524
  manualCommand: install.manualCommand
@@ -11806,8 +13594,8 @@ function shouldDeferSkillsSyncForCommand() {
11806
13594
  return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
11807
13595
  }
11808
13596
  async function runPlayRunnerHealthCheck() {
11809
- const dir = await (0, import_promises5.mkdtemp)((0, import_node_path15.join)((0, import_node_os9.tmpdir)(), "deepline-health-play-"));
11810
- const file = (0, import_node_path15.join)(dir, "health-check.play.ts");
13597
+ const dir = await (0, import_promises5.mkdtemp)((0, import_node_path16.join)((0, import_node_os9.tmpdir)(), "deepline-health-play-"));
13598
+ const file = (0, import_node_path16.join)(dir, "health-check.play.ts");
11811
13599
  try {
11812
13600
  await (0, import_promises5.writeFile)(
11813
13601
  file,
@@ -12015,6 +13803,6 @@ Examples:
12015
13803
  }
12016
13804
  process.exitCode = 1;
12017
13805
  }
12018
- process.exit(process.exitCode ?? 0);
13806
+ process.exitCode = process.exitCode ?? 0;
12019
13807
  }
12020
13808
  main();