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.
@@ -197,10 +197,10 @@ function resolveConfig(options) {
197
197
 
198
198
  // src/release.ts
199
199
  var SDK_RELEASE = {
200
- version: "0.1.57",
201
- apiContract: "2026-05-play-tool-describe-starters",
200
+ version: "0.1.59",
201
+ apiContract: "2026-05-play-bootstrap-dataset-summary",
202
202
  supportPolicy: {
203
- latest: "0.1.57",
203
+ latest: "0.1.59",
204
204
  minimumSupported: "0.1.53",
205
205
  deprecatedBelow: "0.1.53"
206
206
  }
@@ -338,8 +338,8 @@ var HttpClient = class {
338
338
  if (lastError instanceof DeeplineError) {
339
339
  throw lastError;
340
340
  }
341
- const errorMessage = lastError?.message ? `Unable to connect to ${baseUrl}. ${lastError.message}` : `Unable to connect to ${baseUrl}. Is the computer able to access the url?`;
342
- throw new DeeplineError(errorMessage);
341
+ const errorMessage2 = lastError?.message ? `Unable to connect to ${baseUrl}. ${lastError.message}` : `Unable to connect to ${baseUrl}. Is the computer able to access the url?`;
342
+ throw new DeeplineError(errorMessage2);
343
343
  }
344
344
  /**
345
345
  * Send a GET request.
@@ -512,7 +512,7 @@ function decodeSseFrame(frame) {
512
512
  return parsed;
513
513
  }
514
514
  function sleep(ms) {
515
- return new Promise((resolve11) => setTimeout(resolve11, ms));
515
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
516
516
  }
517
517
 
518
518
  // src/client.ts
@@ -522,7 +522,7 @@ var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
522
522
  var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
523
523
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
524
524
  function sleep2(ms) {
525
- return new Promise((resolve11) => setTimeout(resolve11, ms));
525
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
526
526
  }
527
527
  function isTransientCompileManifestError(error) {
528
528
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -2258,7 +2258,7 @@ function buildCandidateUrls2(url) {
2258
2258
  }
2259
2259
  }
2260
2260
  function sleep3(ms) {
2261
- return new Promise((resolve11) => setTimeout(resolve11, ms));
2261
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
2262
2262
  }
2263
2263
  function printDeeplineLogo() {
2264
2264
  if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
@@ -3026,6 +3026,33 @@ Examples:
3026
3026
  // src/cli/dataset-stats.ts
3027
3027
  import { writeFileSync as writeFileSync4 } from "fs";
3028
3028
  import { resolve as resolve4 } from "path";
3029
+
3030
+ // ../shared_libs/plays/dataset-summary.ts
3031
+ function datasetSummaryPercentText(numerator, denominator) {
3032
+ return denominator > 0 ? `${numerator}/${denominator} (${Math.round(100 * numerator / denominator)}%)` : "0/0 (0%)";
3033
+ }
3034
+ function readCount(value) {
3035
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.trunc(value) : 0;
3036
+ }
3037
+ function formatDatasetExecutionStats(raw, denominator) {
3038
+ return {
3039
+ queued: datasetSummaryPercentText(readCount(raw.queued), denominator),
3040
+ running: datasetSummaryPercentText(readCount(raw.running), denominator),
3041
+ "completed:executed": datasetSummaryPercentText(
3042
+ readCount(raw.completed),
3043
+ denominator
3044
+ ),
3045
+ "completed:reused": datasetSummaryPercentText(readCount(raw.cached), denominator),
3046
+ "skipped:condition": datasetSummaryPercentText(
3047
+ readCount(raw.skipped),
3048
+ denominator
3049
+ ),
3050
+ "skipped:missed": datasetSummaryPercentText(readCount(raw.missed), denominator),
3051
+ failed: datasetSummaryPercentText(readCount(raw.failed), denominator)
3052
+ };
3053
+ }
3054
+
3055
+ // src/cli/dataset-stats.ts
3029
3056
  var CSV_PROJECTED_FIELDS_KEY = "__deeplineCsvProjectedFields";
3030
3057
  function csvProjectedFields(row) {
3031
3058
  const serialized = row[CSV_PROJECTED_FIELDS_KEY];
@@ -3106,9 +3133,6 @@ function rowArray(value) {
3106
3133
  function readNumber(value) {
3107
3134
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.trunc(value) : null;
3108
3135
  }
3109
- function numericStat(value) {
3110
- return readNumber(value) ?? 0;
3111
- }
3112
3136
  function inferColumns(rows) {
3113
3137
  const columns = [];
3114
3138
  const seen = /* @__PURE__ */ new Set();
@@ -3272,7 +3296,7 @@ function extractCanonicalRowsInfo(statusOrResult) {
3272
3296
  return collectCanonicalRowsInfos(statusOrResult)[0] ?? null;
3273
3297
  }
3274
3298
  function percentText(numerator, denominator) {
3275
- return denominator > 0 ? `${numerator}/${denominator} (${Math.round(100 * numerator / denominator)}%)` : "0/0 (0%)";
3299
+ return datasetSummaryPercentText(numerator, denominator);
3276
3300
  }
3277
3301
  function isDatasetExecutionStatsInput(value) {
3278
3302
  return isRecord2(value) && isRecord2(value.columnStats) && Object.values(value.columnStats).every(isRecord2);
@@ -3288,17 +3312,6 @@ function extractDatasetExecutionStats(statusOrResult) {
3288
3312
  const nested = isRecord2(statusOrResult.result) ? statusOrResult.result.dataset_execution_stats : null;
3289
3313
  return isDatasetExecutionStatsInput(nested) ? nested : null;
3290
3314
  }
3291
- function formatExecutionStats(raw, denominator) {
3292
- return {
3293
- queued: percentText(numericStat(raw.queued), denominator),
3294
- running: percentText(numericStat(raw.running), denominator),
3295
- "completed:executed": percentText(numericStat(raw.completed), denominator),
3296
- "completed:reused": percentText(numericStat(raw.cached), denominator),
3297
- "skipped:condition": percentText(numericStat(raw.skipped), denominator),
3298
- "skipped:missed": percentText(numericStat(raw.missed), denominator),
3299
- failed: percentText(numericStat(raw.failed), denominator)
3300
- };
3301
- }
3302
3315
  function countPercentText(count, denominator) {
3303
3316
  return denominator > 0 ? `${count} (${Math.round(100 * count / denominator)}%)` : "0 (0%)";
3304
3317
  }
@@ -3421,7 +3434,7 @@ function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns
3421
3434
  };
3422
3435
  const rawExecutionStats = executionStats?.columnStats[column];
3423
3436
  if (rawExecutionStats) {
3424
- stat3.execution = formatExecutionStats(rawExecutionStats, totalRows);
3437
+ stat3.execution = formatDatasetExecutionStats(rawExecutionStats, totalRows);
3425
3438
  }
3426
3439
  if (sampleValue !== void 0 && sampleValueType) {
3427
3440
  stat3.sample_value = sampleValue;
@@ -4014,7 +4027,7 @@ import {
4014
4027
  realpathSync,
4015
4028
  writeFileSync as writeFileSync6
4016
4029
  } from "fs";
4017
- import { basename as basename3, dirname as dirname8, join as join6, resolve as resolve9 } from "path";
4030
+ import { basename as basename3, dirname as dirname8, join as join6, resolve as resolve10 } from "path";
4018
4031
 
4019
4032
  // src/plays/bundle-play-file.ts
4020
4033
  import { tmpdir as tmpdir2 } from "os";
@@ -4374,6 +4387,9 @@ function localSdkAliasPlugin(adapter, options) {
4374
4387
  buildContext.onResolve({ filter: /^deepline$/ }, () => ({
4375
4388
  path: entryFile
4376
4389
  }));
4390
+ buildContext.onResolve({ filter: /^deepline\/helpers$/ }, () => ({
4391
+ path: join3(adapter.sdkSourceRoot, "helpers.ts")
4392
+ }));
4377
4393
  }
4378
4394
  };
4379
4395
  }
@@ -5576,11 +5592,1448 @@ function createSdkPlayBundlingAdapter() {
5576
5592
  warnAboutNonDevelopmentBundling
5577
5593
  };
5578
5594
  }
5579
- async function bundlePlayFile2(filePath, options = {}) {
5580
- return bundlePlayFile(filePath, {
5581
- target: options.target ?? defaultPlayBundleTarget(),
5582
- exportName: options.exportName,
5583
- adapter: createSdkPlayBundlingAdapter()
5595
+ async function bundlePlayFile2(filePath, options = {}) {
5596
+ return bundlePlayFile(filePath, {
5597
+ target: options.target ?? defaultPlayBundleTarget(),
5598
+ exportName: options.exportName,
5599
+ adapter: createSdkPlayBundlingAdapter()
5600
+ });
5601
+ }
5602
+
5603
+ // src/cli/commands/plays/bootstrap.ts
5604
+ import { closeSync, openSync, readSync, statSync } from "fs";
5605
+ import { isAbsolute as isAbsolute3, relative as relative2, resolve as resolve9 } from "path";
5606
+ import { parse as parseCsvSync } from "csv-parse/sync";
5607
+
5608
+ // ../shared_libs/plays/bootstrap-routes.ts
5609
+ var PLAY_BOOTSTRAP_TEMPLATES = [
5610
+ "people-list",
5611
+ "company-list",
5612
+ "people-email",
5613
+ "people-phone",
5614
+ "company-people",
5615
+ "company-people-email",
5616
+ "company-people-phone"
5617
+ ];
5618
+ var PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY = "company_search";
5619
+ var PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY = "people_search";
5620
+ var PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER = {
5621
+ email_finder: "email_finder",
5622
+ phone_finder: "phone_finder"
5623
+ };
5624
+ var PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER = {
5625
+ email_finder: "email",
5626
+ phone_finder: "phone"
5627
+ };
5628
+ function isPlayBootstrapTemplate(value) {
5629
+ return PLAY_BOOTSTRAP_TEMPLATES.includes(value);
5630
+ }
5631
+ function formatPlayBootstrapTemplates() {
5632
+ return PLAY_BOOTSTRAP_TEMPLATES.join("|");
5633
+ }
5634
+
5635
+ // src/cli/commands/plays/bootstrap.ts
5636
+ function parseReferencedPlayTarget(target) {
5637
+ const trimmed = target.trim();
5638
+ const slashIndex = trimmed.indexOf("/");
5639
+ if (slashIndex <= 0 || slashIndex === trimmed.length - 1) {
5640
+ return { ownerSlug: null, playName: trimmed, unqualifiedPlayName: trimmed };
5641
+ }
5642
+ return {
5643
+ ownerSlug: trimmed.slice(0, slashIndex),
5644
+ playName: trimmed,
5645
+ unqualifiedPlayName: trimmed.slice(slashIndex + 1)
5646
+ };
5647
+ }
5648
+ function parsePositiveInteger2(value, flagName) {
5649
+ const parsed = Number.parseInt(value, 10);
5650
+ if (!Number.isFinite(parsed) || parsed <= 0) {
5651
+ throw new PlayBootstrapUsageError(
5652
+ `${flagName} must be a positive integer.`
5653
+ );
5654
+ }
5655
+ return parsed;
5656
+ }
5657
+ function isRecord3(value) {
5658
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
5659
+ }
5660
+ function stringValue(value) {
5661
+ return typeof value === "string" ? value.trim() : "";
5662
+ }
5663
+ function extractionEntries(value) {
5664
+ if (Array.isArray(value)) return value.filter(isRecord3);
5665
+ if (!isRecord3(value)) return [];
5666
+ return Object.entries(value).map(
5667
+ ([name, entry]) => isRecord3(entry) ? { name, ...entry } : { name }
5668
+ );
5669
+ }
5670
+ var PlayBootstrapError = class extends Error {
5671
+ constructor(message, exitCode) {
5672
+ super(message);
5673
+ this.exitCode = exitCode;
5674
+ }
5675
+ exitCode;
5676
+ };
5677
+ var PlayBootstrapUsageError = class extends PlayBootstrapError {
5678
+ constructor(message) {
5679
+ super(message, 2);
5680
+ }
5681
+ };
5682
+ var PlayBootstrapValidationError = class extends PlayBootstrapError {
5683
+ constructor(message) {
5684
+ super(message, 7);
5685
+ }
5686
+ };
5687
+ var CSV_HEADER_SAMPLE_BYTES = 64 * 1024;
5688
+ function parseCsvList(value) {
5689
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
5690
+ }
5691
+ function parseProviderList(value, flag) {
5692
+ const providers = parseCsvList(value);
5693
+ if (providers.length === 0) {
5694
+ throw new PlayBootstrapUsageError(`${flag} provider list cannot be empty.`);
5695
+ }
5696
+ return providers;
5697
+ }
5698
+ function parseBootstrapPrefixedRef(value, flag) {
5699
+ const separatorIndex = value.indexOf(":");
5700
+ if (separatorIndex <= 0 || separatorIndex === value.length - 1) {
5701
+ throw new PlayBootstrapUsageError(
5702
+ `${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.`
5703
+ );
5704
+ }
5705
+ return {
5706
+ prefix: value.slice(0, separatorIndex).trim(),
5707
+ body: value.slice(separatorIndex + 1).trim()
5708
+ };
5709
+ }
5710
+ function parseBootstrapSourceRef(value, flag = "--from") {
5711
+ const { prefix, body } = parseBootstrapPrefixedRef(value, flag);
5712
+ switch (prefix) {
5713
+ case "csv":
5714
+ return { kind: "csv", value: body };
5715
+ case "play":
5716
+ return { kind: "play", value: parseReferencedPlayTarget(body).playName };
5717
+ case "provider":
5718
+ case "providers":
5719
+ return { kind: "providers", values: parseProviderList(body, flag) };
5720
+ }
5721
+ throw new PlayBootstrapUsageError(
5722
+ `${flag} does not support ${prefix}:. Use csv:, play:, provider:, or providers:.`
5723
+ );
5724
+ }
5725
+ function parseBootstrapStageRef(value, flag) {
5726
+ const { prefix, body } = parseBootstrapPrefixedRef(value, flag);
5727
+ switch (prefix) {
5728
+ case "play":
5729
+ return { kind: "play", value: parseReferencedPlayTarget(body).playName };
5730
+ case "provider":
5731
+ case "providers":
5732
+ return { kind: "providers", values: parseProviderList(body, flag) };
5733
+ }
5734
+ throw new PlayBootstrapUsageError(
5735
+ `${flag} does not support ${prefix}:. Use play:, provider:, or providers:.`
5736
+ );
5737
+ }
5738
+ function playBootstrapTemplateConfig(template) {
5739
+ switch (template) {
5740
+ case "company-list":
5741
+ return { sourceEntity: "company", usingStage: null, requiredStages: [] };
5742
+ case "people-list":
5743
+ return { sourceEntity: "people", usingStage: null, requiredStages: [] };
5744
+ case "people-email":
5745
+ return {
5746
+ sourceEntity: "people",
5747
+ usingStage: "email",
5748
+ requiredStages: []
5749
+ };
5750
+ case "people-phone":
5751
+ return {
5752
+ sourceEntity: "people",
5753
+ usingStage: "phone",
5754
+ requiredStages: []
5755
+ };
5756
+ case "company-people":
5757
+ return {
5758
+ sourceEntity: "company",
5759
+ usingStage: "people",
5760
+ requiredStages: []
5761
+ };
5762
+ case "company-people-email":
5763
+ return {
5764
+ sourceEntity: "company",
5765
+ usingStage: null,
5766
+ requiredStages: ["people", "email"]
5767
+ };
5768
+ case "company-people-phone":
5769
+ return {
5770
+ sourceEntity: "company",
5771
+ usingStage: null,
5772
+ requiredStages: ["people", "phone"]
5773
+ };
5774
+ }
5775
+ }
5776
+ function templateExample(template) {
5777
+ switch (template) {
5778
+ case "people-list":
5779
+ return "deepline plays bootstrap people-list --from provider:dropleads_search_people > people.play.ts";
5780
+ case "company-list":
5781
+ return "deepline plays bootstrap company-list --from provider:apollo_company_search > companies.play.ts";
5782
+ case "people-email":
5783
+ return "deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall > email-flow.play.ts";
5784
+ case "people-phone":
5785
+ return "deepline plays bootstrap people-phone --from csv:data/vp_contacts.csv --using play:prebuilt/person-to-phone > phone-flow.play.ts";
5786
+ case "company-people":
5787
+ return "deepline plays bootstrap company-people --from provider:apollo_company_search --using play:prebuilt/company-to-contact > company-people.play.ts";
5788
+ case "company-people-email":
5789
+ 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";
5790
+ case "company-people-phone":
5791
+ 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";
5792
+ }
5793
+ }
5794
+ var PLAY_BOOTSTRAP_STAGE_NAMES = [
5795
+ "people",
5796
+ "email",
5797
+ "phone"
5798
+ ];
5799
+ function playBootstrapUsageLine() {
5800
+ 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`;
5801
+ }
5802
+ function requireBootstrapTemplate(rawTemplate) {
5803
+ if (!rawTemplate) {
5804
+ throw new PlayBootstrapUsageError(
5805
+ `plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}.
5806
+ Example: deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall > email-flow.play.ts`
5807
+ );
5808
+ }
5809
+ if (!isPlayBootstrapTemplate(rawTemplate)) {
5810
+ throw new PlayBootstrapUsageError(
5811
+ `Unknown plays bootstrap template: ${rawTemplate}
5812
+ Supported templates: ${formatPlayBootstrapTemplates()}`
5813
+ );
5814
+ }
5815
+ return rawTemplate;
5816
+ }
5817
+ function nextFlagValue(args, index, flag) {
5818
+ const value = args[index + 1];
5819
+ if (!value || value.startsWith("--")) {
5820
+ throw new PlayBootstrapUsageError(`${flag} needs a value.`);
5821
+ }
5822
+ return value;
5823
+ }
5824
+ function stageFlag(stage) {
5825
+ return `--${stage}`;
5826
+ }
5827
+ function stageRefHelp(stage) {
5828
+ switch (stage) {
5829
+ case "people":
5830
+ return "play:<people-play>";
5831
+ case "email":
5832
+ case "phone":
5833
+ return "<play:REF|provider:ID|providers:ID,ID>";
5834
+ }
5835
+ }
5836
+ function getStageRef(options, stage) {
5837
+ switch (stage) {
5838
+ case "people":
5839
+ return options.people;
5840
+ case "email":
5841
+ return options.email;
5842
+ case "phone":
5843
+ return options.phone;
5844
+ }
5845
+ }
5846
+ function setStageRef(options, stage, ref) {
5847
+ switch (stage) {
5848
+ case "people":
5849
+ options.people = ref;
5850
+ return;
5851
+ case "email":
5852
+ options.email = ref;
5853
+ return;
5854
+ case "phone":
5855
+ options.phone = ref;
5856
+ return;
5857
+ }
5858
+ }
5859
+ function unsupportedStageMessage(template, stage) {
5860
+ switch (stage) {
5861
+ case "people":
5862
+ return `${template} does not accept --people. Use company-people, company-people-email, or company-people-phone.`;
5863
+ case "email":
5864
+ return `${template} does not accept --email. Use people-email or company-people-email.`;
5865
+ case "phone":
5866
+ return `${template} does not accept --phone. Use people-phone or company-people-phone.`;
5867
+ }
5868
+ }
5869
+ function requireSource(options) {
5870
+ if (!options.from) {
5871
+ throw new PlayBootstrapUsageError(
5872
+ `${options.template} needs --from.
5873
+ Example: ${templateExample(options.template)}`
5874
+ );
5875
+ }
5876
+ return options.from;
5877
+ }
5878
+ function assertAllowedStageFlags(options, allowedStages) {
5879
+ const allowed = new Set(allowedStages);
5880
+ for (const stage of PLAY_BOOTSTRAP_STAGE_NAMES) {
5881
+ if (!allowed.has(stage) && getStageRef(options, stage)) {
5882
+ throw new PlayBootstrapUsageError(
5883
+ unsupportedStageMessage(options.template, stage)
5884
+ );
5885
+ }
5886
+ }
5887
+ }
5888
+ function assertRequiredStages(options, stages) {
5889
+ for (const stage of stages) {
5890
+ if (!getStageRef(options, stage)) {
5891
+ throw new PlayBootstrapUsageError(
5892
+ `${options.template} needs ${stageFlag(stage)} ${stageRefHelp(stage)}.
5893
+ Example: ${templateExample(options.template)}`
5894
+ );
5895
+ }
5896
+ }
5897
+ }
5898
+ function normalizeSingleStageRoute(options, stage) {
5899
+ const explicitStage = getStageRef(options, stage);
5900
+ if (options.using && explicitStage) {
5901
+ throw new PlayBootstrapUsageError(
5902
+ `${options.template} received both --using and ${stageFlag(stage)}. Choose one stage binding.`
5903
+ );
5904
+ }
5905
+ const selectedStage = options.using ?? explicitStage;
5906
+ if (!selectedStage) {
5907
+ throw new PlayBootstrapUsageError(
5908
+ `${options.template} needs --using ${stageRefHelp(stage)} or ${stageFlag(stage)} ${stageRefHelp(stage)}.
5909
+ Example: ${templateExample(options.template)}`
5910
+ );
5911
+ }
5912
+ setStageRef(options, stage, selectedStage);
5913
+ options.using = selectedStage;
5914
+ assertAllowedStageFlags(options, [stage]);
5915
+ }
5916
+ function normalizeMultiStageRoute(options, stages) {
5917
+ if (options.using) {
5918
+ throw new PlayBootstrapUsageError(
5919
+ `${options.template} does not accept --using. Use the explicit stage flags shown in: ${templateExample(options.template)}`
5920
+ );
5921
+ }
5922
+ assertRequiredStages(options, stages);
5923
+ assertAllowedStageFlags(options, stages);
5924
+ }
5925
+ function normalizeTemplateStages(options) {
5926
+ const config = playBootstrapTemplateConfig(options.template);
5927
+ const from = requireSource(options);
5928
+ switch (config.usingStage) {
5929
+ case "people":
5930
+ case "email":
5931
+ case "phone":
5932
+ normalizeSingleStageRoute(options, config.usingStage);
5933
+ break;
5934
+ case null:
5935
+ normalizeMultiStageRoute(options, config.requiredStages);
5936
+ break;
5937
+ }
5938
+ return {
5939
+ ...options,
5940
+ from
5941
+ };
5942
+ }
5943
+ function parsePlayBootstrapOptions(args) {
5944
+ const [rawTemplate, ...rest] = args;
5945
+ const template = requireBootstrapTemplate(rawTemplate);
5946
+ const options = {
5947
+ template,
5948
+ name: `gtm-${template}`,
5949
+ from: null,
5950
+ using: null,
5951
+ people: null,
5952
+ email: null,
5953
+ phone: null,
5954
+ limit: 5
5955
+ };
5956
+ for (let index = 0; index < rest.length; index += 1) {
5957
+ const arg = rest[index];
5958
+ const value = () => nextFlagValue(rest, index, arg);
5959
+ switch (arg) {
5960
+ case "--name":
5961
+ options.name = value();
5962
+ index += 1;
5963
+ break;
5964
+ case "--from":
5965
+ options.from = parseBootstrapSourceRef(value(), "--from");
5966
+ index += 1;
5967
+ break;
5968
+ case "--using":
5969
+ options.using = parseBootstrapStageRef(value(), "--using");
5970
+ index += 1;
5971
+ break;
5972
+ case "--people":
5973
+ options.people = parseBootstrapStageRef(value(), "--people");
5974
+ index += 1;
5975
+ break;
5976
+ case "--email":
5977
+ options.email = parseBootstrapStageRef(value(), "--email");
5978
+ index += 1;
5979
+ break;
5980
+ case "--phone":
5981
+ options.phone = parseBootstrapStageRef(value(), "--phone");
5982
+ index += 1;
5983
+ break;
5984
+ case "--limit":
5985
+ options.limit = parsePositiveInteger2(value(), "--limit");
5986
+ index += 1;
5987
+ break;
5988
+ default:
5989
+ throw new PlayBootstrapUsageError(
5990
+ `Unknown plays bootstrap option: ${arg}
5991
+ ${playBootstrapUsageLine()}`
5992
+ );
5993
+ }
5994
+ }
5995
+ return normalizeTemplateStages(options);
5996
+ }
5997
+ function jsString(value) {
5998
+ return JSON.stringify(value);
5999
+ }
6000
+ function inferCsvCellTypeExpression(values) {
6001
+ const nonEmptyValues = values.map((value) => value.trim()).filter((value) => value.length > 0);
6002
+ const hasEmptyValue = values.some((value) => value.trim().length === 0);
6003
+ if (nonEmptyValues.length === 0) return "string";
6004
+ const numericPattern = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:[eE][+-]?\d+)?$/;
6005
+ const booleanPattern = /^(?:true|false)$/i;
6006
+ let inferred = "string";
6007
+ if (nonEmptyValues.every((value) => numericPattern.test(value))) {
6008
+ inferred = "`${number}`";
6009
+ } else if (nonEmptyValues.every((value) => booleanPattern.test(value))) {
6010
+ const canonicalBooleanValues = nonEmptyValues.every(
6011
+ (value) => value === "true" || value === "false"
6012
+ );
6013
+ inferred = canonicalBooleanValues ? '"false" | "true"' : [...new Set(nonEmptyValues)].sort().map(jsString).join(" | ");
6014
+ }
6015
+ return hasEmptyValue && inferred !== "string" ? `${inferred} | ""` : inferred;
6016
+ }
6017
+ function inferCsvColumnSpecs(headers, rows) {
6018
+ return headers.map((header) => ({
6019
+ name: header,
6020
+ typeExpression: inferCsvCellTypeExpression(
6021
+ rows.map((row) => String(row[header] ?? ""))
6022
+ )
6023
+ }));
6024
+ }
6025
+ function readCsvSample(csvPath) {
6026
+ const resolvedPath = resolve9(csvPath);
6027
+ const size = statSync(resolvedPath).size;
6028
+ const fd = openSync(resolvedPath, "r");
6029
+ const byteLength = Math.min(size, CSV_HEADER_SAMPLE_BYTES);
6030
+ const buffer = Buffer.alloc(byteLength);
6031
+ const bytesRead = readSync(fd, buffer, 0, byteLength, 0);
6032
+ closeSync(fd);
6033
+ if (bytesRead === 0) {
6034
+ throw new PlayBootstrapUsageError(`--from csv:${csvPath} is empty.`);
6035
+ }
6036
+ return {
6037
+ content: buffer.subarray(0, bytesRead).toString("utf8"),
6038
+ truncated: size > bytesRead
6039
+ };
6040
+ }
6041
+ function completeCsvSample(csvPath, sample) {
6042
+ if (!sample.truncated) return sample.content;
6043
+ const lastLineBreak = Math.max(
6044
+ sample.content.lastIndexOf("\n"),
6045
+ sample.content.lastIndexOf("\r")
6046
+ );
6047
+ if (lastLineBreak < 0) {
6048
+ throw new PlayBootstrapUsageError(
6049
+ `CSV header in ${csvPath} is longer than ${CSV_HEADER_SAMPLE_BYTES} bytes; shorten the header row before bootstrapping.`
6050
+ );
6051
+ }
6052
+ return sample.content.slice(0, lastLineBreak + 1);
6053
+ }
6054
+ function readCsvHeaderFields(csvPath, sample) {
6055
+ const records = parseCsvSync(sample, {
6056
+ bom: true,
6057
+ to_line: 1,
6058
+ relax_column_count: true,
6059
+ skip_empty_lines: false
6060
+ });
6061
+ const firstRecord = Array.isArray(records) ? records[0] : null;
6062
+ const fields = Array.isArray(firstRecord) ? firstRecord.map((field) => String(field ?? "").trim()).filter(Boolean) : [];
6063
+ const uniqueFields = [...new Set(fields)];
6064
+ if (uniqueFields.length === 0) {
6065
+ throw new PlayBootstrapUsageError(
6066
+ `Could not read a header row from --from csv:${csvPath}.`
6067
+ );
6068
+ }
6069
+ return uniqueFields;
6070
+ }
6071
+ function readCsvSampleRows(sample) {
6072
+ const parsedRows = parseCsvSync(sample, {
6073
+ bom: true,
6074
+ columns: true,
6075
+ skip_empty_lines: true,
6076
+ relax_column_count: true,
6077
+ trim: true
6078
+ });
6079
+ return Array.isArray(parsedRows) ? parsedRows.filter(isRecord3) : [];
6080
+ }
6081
+ function readSourceCsvColumnSpecs(csvPath) {
6082
+ const sample = readCsvSample(csvPath);
6083
+ const completeSample = completeCsvSample(csvPath, sample);
6084
+ return inferCsvColumnSpecs(
6085
+ readCsvHeaderFields(csvPath, sample.content),
6086
+ readCsvSampleRows(completeSample)
6087
+ );
6088
+ }
6089
+ function renderSourceCsvRowType(columns) {
6090
+ if (columns.length === 0) return "";
6091
+ const properties = columns.map((column) => ` ${jsString(column.name)}: ${column.typeExpression};`).join("\n");
6092
+ return `// CSV cells are strings at runtime. \`${"${number}"}\` means a numeric-looking CSV string; cast before math.
6093
+ type SourceCsvRow = {
6094
+ ${properties}
6095
+ };
6096
+
6097
+ `;
6098
+ }
6099
+ function packagedCsvPathForPlay(csvPath) {
6100
+ const playDir = process.cwd();
6101
+ const absoluteCsvPath = resolve9(csvPath);
6102
+ const relativePath = relative2(playDir, absoluteCsvPath);
6103
+ if (relativePath === "" || relativePath.startsWith("..") || isAbsolute3(relativePath)) {
6104
+ throw new PlayBootstrapUsageError(
6105
+ `--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.`
6106
+ );
6107
+ }
6108
+ const portablePath = relativePath.split("\\").join("/");
6109
+ return portablePath.startsWith(".") ? portablePath : `./${portablePath}`;
6110
+ }
6111
+ function getterNamesFromTool(tool, kind) {
6112
+ const usageGuidance = isRecord3(tool?.usageGuidance) ? tool.usageGuidance : {};
6113
+ const resultGuidance = isRecord3(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord3(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
6114
+ const key = kind === "list" ? "extractedLists" : "extractedValues";
6115
+ const snakeKey = kind === "list" ? "extracted_lists" : "extracted_values";
6116
+ return extractionEntries(resultGuidance[key] ?? resultGuidance[snakeKey]).map((entry) => stringValue(entry.name)).filter(Boolean);
6117
+ }
6118
+ function targetGettersFromTool(tool) {
6119
+ const record = isRecord3(tool) ? tool : {};
6120
+ const raw = record.targetGetters ?? record.target_getters;
6121
+ if (!isRecord3(raw)) return {};
6122
+ const entries = [];
6123
+ for (const [target, value] of Object.entries(raw)) {
6124
+ const paths = Array.isArray(value) ? value.map((path) => typeof path === "string" ? path.trim() : "").filter(Boolean) : [];
6125
+ if (target.trim() && paths.length > 0) {
6126
+ entries.push([target.trim(), paths]);
6127
+ }
6128
+ }
6129
+ return Object.fromEntries(entries);
6130
+ }
6131
+ function listRowCandidateKeysFromTool(tool) {
6132
+ const keys = /* @__PURE__ */ new Set();
6133
+ for (const paths of Object.values(targetGettersFromTool(tool))) {
6134
+ for (const path of paths) {
6135
+ const key = path.replace(/\[(?:\*|\d+)\]/g, "").split(/[.[\]]/, 1)[0]?.trim();
6136
+ if (key) keys.add(key);
6137
+ }
6138
+ }
6139
+ return [...keys].sort();
6140
+ }
6141
+ function inputPropertyNames(schema) {
6142
+ if (!isRecord3(schema)) return [];
6143
+ if (isRecord3(schema.properties)) return Object.keys(schema.properties);
6144
+ if (Array.isArray(schema.fields)) {
6145
+ return schema.fields.filter(isRecord3).map((field) => stringValue(field.name)).filter(Boolean);
6146
+ }
6147
+ return [];
6148
+ }
6149
+ function schemaFieldDetails(schema) {
6150
+ const required = requiredPlayInputFields({
6151
+ inputSchema: schema
6152
+ });
6153
+ const optional = inputPropertyNames(schema).filter(
6154
+ (field) => !required.includes(field)
6155
+ );
6156
+ return { required, optional };
6157
+ }
6158
+ function jsonSchemaTypeExpression(schema) {
6159
+ if (!isRecord3(schema)) return "unknown";
6160
+ const type = schema.type;
6161
+ if (Array.isArray(type)) {
6162
+ return type.map((entry) => jsonSchemaTypeExpression({ ...schema, type: entry })).join(" | ");
6163
+ }
6164
+ if (Array.isArray(schema.anyOf)) {
6165
+ return schema.anyOf.map(jsonSchemaTypeExpression).join(" | ");
6166
+ }
6167
+ if (Array.isArray(schema.oneOf)) {
6168
+ return schema.oneOf.map(jsonSchemaTypeExpression).join(" | ");
6169
+ }
6170
+ switch (type) {
6171
+ case "string":
6172
+ return "string";
6173
+ case "number":
6174
+ case "integer":
6175
+ return "number";
6176
+ case "boolean":
6177
+ return "boolean";
6178
+ case "null":
6179
+ return "null";
6180
+ case "array":
6181
+ return `Array<${jsonSchemaTypeExpression(schema.items)}>`;
6182
+ case "object":
6183
+ return "Record<string, unknown>";
6184
+ default:
6185
+ return "unknown";
6186
+ }
6187
+ }
6188
+ function objectPropertySchema(schema, property) {
6189
+ return isRecord3(schema) && isRecord3(schema.properties) ? schema.properties[property] : null;
6190
+ }
6191
+ function finderResultTypeName(finder) {
6192
+ return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
6193
+ }
6194
+ function renderFinderPlayResultType(input) {
6195
+ if (!input.play) return null;
6196
+ const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
6197
+ const fieldSchema = objectPropertySchema(
6198
+ input.play.outputSchema,
6199
+ outputField
6200
+ );
6201
+ const fieldType = fieldSchema ? jsonSchemaTypeExpression(fieldSchema) : "string | null";
6202
+ return `type ${finderResultTypeName(input.finder)} =
6203
+ | string
6204
+ | null
6205
+ | {
6206
+ ${outputField}?: ${fieldType};
6207
+ };`;
6208
+ }
6209
+ function generatedFinderPlayResultTypes(input) {
6210
+ return ["email_finder", "phone_finder"].flatMap((finder) => {
6211
+ const stage = finderStage(input.options, finder);
6212
+ if (stage?.kind !== "play") return [];
6213
+ const typeDefinition = renderFinderPlayResultType({
6214
+ finder,
6215
+ play: input.finderPlays[finder]
6216
+ });
6217
+ return typeDefinition ? [typeDefinition] : [];
6218
+ }).join("\n\n");
6219
+ }
6220
+ function exampleValueComment(field) {
6221
+ if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size") {
6222
+ return "limit";
6223
+ }
6224
+ if (field === "roles" || field.endsWith("s")) return '["..."]';
6225
+ return '"..."';
6226
+ }
6227
+ function generateContactInputObjectFromSchema(schema, indent, label, fallbackFields = ["first_name", "last_name", "domain"]) {
6228
+ const details = schemaFieldDetails(schema);
6229
+ const required = details.required.length ? details.required : fallbackFields;
6230
+ const optional = details.optional;
6231
+ const lines = [
6232
+ `${indent}// TODO: map row fields into ${label}.`,
6233
+ ...playInspectionComments(label, indent),
6234
+ `${indent}// Required: ${required.join(", ") || "none declared"}.`
6235
+ ];
6236
+ for (const field of required) {
6237
+ lines.push(`${indent}// ${field}: row["TODO_SOURCE_FIELD"],`);
6238
+ }
6239
+ if (optional.length > 0) {
6240
+ lines.push("");
6241
+ lines.push(`${indent}// optional (delete unused):`);
6242
+ for (const field of optional) {
6243
+ lines.push(`${indent}// ${field}: row["TODO_SOURCE_FIELD"],`);
6244
+ }
6245
+ }
6246
+ return `{
6247
+ ${lines.join("\n")}
6248
+ ${indent.slice(2)}}`;
6249
+ }
6250
+ function generateCompanyInputObjectFromSchema(schema, indent, label, fallbackFields = ["domain", "company_name"]) {
6251
+ const details = schemaFieldDetails(schema);
6252
+ const required = details.required.length ? details.required : fallbackFields;
6253
+ const optional = details.optional;
6254
+ const lines = [
6255
+ `${indent}// TODO: map company fields into ${label}.`,
6256
+ ...playInspectionComments(label, indent),
6257
+ `${indent}// Required: ${required.join(", ") || "none declared"}.`
6258
+ ];
6259
+ for (const field of required) {
6260
+ lines.push(`${indent}// ${field}: company["TODO_SOURCE_FIELD"],`);
6261
+ }
6262
+ if (optional.length > 0) {
6263
+ lines.push("");
6264
+ lines.push(`${indent}// optional (delete unused):`);
6265
+ for (const field of optional) {
6266
+ lines.push(`${indent}// ${field}: company["TODO_SOURCE_FIELD"],`);
6267
+ }
6268
+ }
6269
+ return `{
6270
+ ${lines.join("\n")}
6271
+ ${indent.slice(2)}}`;
6272
+ }
6273
+ function generateSourceProviderInputObject(input) {
6274
+ const { tool, indent, label, entity } = input;
6275
+ const properties = inputPropertyNames(tool?.inputSchema);
6276
+ const details = schemaFieldDetails(tool?.inputSchema);
6277
+ const required = details.required;
6278
+ const includeOptional = properties.length === 0 ? ["query", "title", "domain", "limit"] : properties.filter(
6279
+ (field) => [
6280
+ "query",
6281
+ "q",
6282
+ "search",
6283
+ "title",
6284
+ "role",
6285
+ "persona",
6286
+ "domain",
6287
+ "company_domain",
6288
+ "limit",
6289
+ "numResults",
6290
+ "num_results",
6291
+ "page_size"
6292
+ ].includes(field)
6293
+ );
6294
+ const lines = [
6295
+ `${indent}// TODO: fill ${entity} source inputs for ${label}.`,
6296
+ `${indent}// Inspect: deepline tools describe ${label} --json`
6297
+ ];
6298
+ for (const field of required) {
6299
+ lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
6300
+ }
6301
+ const activeTodoField = required.length === 0 ? ["query", "q", "search", "title", "role", "persona"].find(
6302
+ (field) => includeOptional.includes(field)
6303
+ ) ?? "query" : null;
6304
+ if (activeTodoField) {
6305
+ lines.push(
6306
+ `${indent}// ${activeTodoField}: ${exampleValueComment(activeTodoField)},`
6307
+ );
6308
+ }
6309
+ const optionalExamples = includeOptional.filter(
6310
+ (field) => !required.includes(field) && field !== activeTodoField
6311
+ );
6312
+ if (optionalExamples.length > 0) {
6313
+ lines.push("");
6314
+ lines.push(`${indent}// optional - uncomment what this provider supports:`);
6315
+ for (const field of optionalExamples) {
6316
+ if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size") {
6317
+ lines.push(`${indent}// ${field}: limit,`);
6318
+ } else {
6319
+ lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
6320
+ }
6321
+ }
6322
+ }
6323
+ if (!required.some(
6324
+ (field) => ["limit", "numResults", "num_results", "page_size"].includes(field)
6325
+ )) {
6326
+ lines.push(`${indent}limit,`);
6327
+ }
6328
+ return `{
6329
+ ${lines.join("\n")}
6330
+ ${indent.slice(2)}}`;
6331
+ }
6332
+ function generatePlayInputObject(input) {
6333
+ const { schema, indent, label, entity } = input;
6334
+ const details = schemaFieldDetails(schema);
6335
+ const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
6336
+ const required = details.required.length ? details.required : fallback;
6337
+ const lines = [
6338
+ `${indent}// TODO: fill source play inputs for ${label}.`,
6339
+ ...playInspectionComments(label, indent)
6340
+ ];
6341
+ for (const field of required) {
6342
+ lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
6343
+ }
6344
+ if (!required.includes("limit")) lines.push(`${indent}limit,`);
6345
+ return `{
6346
+ ${lines.join("\n")}
6347
+ ${indent.slice(2)}}`;
6348
+ }
6349
+ function requiredPlayInputFields(play) {
6350
+ const schema = play?.inputSchema;
6351
+ if (!isRecord3(schema)) return [];
6352
+ if (Array.isArray(schema.required)) {
6353
+ return schema.required.filter(
6354
+ (value) => typeof value === "string"
6355
+ );
6356
+ }
6357
+ if (Array.isArray(schema.fields)) {
6358
+ return schema.fields.filter(isRecord3).filter(
6359
+ (field) => field.required === true && typeof field.name === "string"
6360
+ ).map((field) => String(field.name));
6361
+ }
6362
+ return [];
6363
+ }
6364
+ function sourceProviders(options) {
6365
+ return options.from.kind === "providers" ? options.from.values : [];
6366
+ }
6367
+ function sourcePlayRef(options) {
6368
+ return options.from.kind === "play" ? options.from.value : null;
6369
+ }
6370
+ function stagePlayRef(stage) {
6371
+ return stage?.kind === "play" ? stage.value : null;
6372
+ }
6373
+ function stageProviders(stage) {
6374
+ return stage?.kind === "providers" ? stage.values : [];
6375
+ }
6376
+ function finderStage(options, finder) {
6377
+ return finder === "email_finder" ? options.email : options.phone;
6378
+ }
6379
+ function stepFieldName(finder) {
6380
+ return PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[finder];
6381
+ }
6382
+ function finderProviderStepPrefix(finder) {
6383
+ return finder === "email_finder" ? "emailFinder" : "phoneFinder";
6384
+ }
6385
+ function safeIdentifier(value) {
6386
+ return value.replace(/[^A-Za-z0-9_]+/g, "_");
6387
+ }
6388
+ function playInspectionComments(playRef, indent) {
6389
+ return [`${indent}// Inspect: deepline plays describe ${playRef} --json`];
6390
+ }
6391
+ function accessorExpression(base, field) {
6392
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(field) ? `${base}.${field}` : `${base}[${jsString(field)}]`;
6393
+ }
6394
+ function needsWhenImport(options) {
6395
+ return stageProviders(options.email).length > 1 || stageProviders(options.phone).length > 1;
6396
+ }
6397
+ function sourceCollectionTypeName(entity) {
6398
+ return entity === "company" ? "CompanySourceRow" : "ContactSourceRow";
6399
+ }
6400
+ function renderPartialRowType(input) {
6401
+ if (input.fields.length === 0) {
6402
+ return `type ${input.typeName} = Record<string, unknown>;`;
6403
+ }
6404
+ const properties = input.fields.map((field) => ` ${jsString(field)}?: unknown;`).join("\n");
6405
+ return `type ${input.typeName} = Record<string, unknown> & Partial<{
6406
+ // ${input.comment}
6407
+ ${properties}
6408
+ }>;`;
6409
+ }
6410
+ function fieldsFromSchemaDetails(input) {
6411
+ return [
6412
+ ...input.details.required.length ? input.details.required : input.fallbackFields,
6413
+ ...input.details.optional
6414
+ ];
6415
+ }
6416
+ function schemaFieldsForStage(stage, input) {
6417
+ switch (stage?.kind) {
6418
+ case void 0:
6419
+ return [];
6420
+ case "play":
6421
+ return fieldsFromSchemaDetails({
6422
+ details: schemaFieldDetails(input.play?.inputSchema),
6423
+ fallbackFields: input.fallbackFields
6424
+ });
6425
+ case "providers":
6426
+ return input.tools.flatMap(
6427
+ (tool) => fieldsFromSchemaDetails({
6428
+ details: schemaFieldDetails(tool.inputSchema),
6429
+ fallbackFields: input.fallbackFields
6430
+ })
6431
+ );
6432
+ }
6433
+ }
6434
+ function sourceRowTypeDefinition(input) {
6435
+ switch (input.options.from.kind) {
6436
+ case "csv":
6437
+ return `type ${input.sourceTypeName} = SourceCsvRow;`;
6438
+ case "providers":
6439
+ return renderPartialRowType({
6440
+ typeName: input.sourceTypeName,
6441
+ fields: [
6442
+ ...new Set(input.sourceTools.flatMap(listRowCandidateKeysFromTool))
6443
+ ].sort(),
6444
+ comment: "Candidate source row keys from described list getters; confirm the actual provider keys with source_*.extractedLists.*.keys before mapping."
6445
+ });
6446
+ case "play": {
6447
+ const details = schemaFieldDetails(input.sourcePlay?.outputSchema);
6448
+ return renderPartialRowType({
6449
+ typeName: input.sourceTypeName,
6450
+ fields: [...details.required, ...details.optional].sort(),
6451
+ comment: "Candidate source play output fields; confirm the selected rows field before mapping."
6452
+ });
6453
+ }
6454
+ }
6455
+ }
6456
+ function contactBridgeRowTypeDefinition(input) {
6457
+ const config = playBootstrapTemplateConfig(input.options.template);
6458
+ if (config.sourceEntity !== "company" || !input.options.people) return null;
6459
+ const emailFields = schemaFieldsForStage(input.options.email, {
6460
+ tools: input.finderTools.email_finder ?? [],
6461
+ play: input.finderPlays.email_finder,
6462
+ fallbackFields: ["first_name", "last_name", "domain"]
6463
+ });
6464
+ const phoneFields = schemaFieldsForStage(input.options.phone, {
6465
+ tools: input.finderTools.phone_finder ?? [],
6466
+ play: input.finderPlays.phone_finder,
6467
+ fallbackFields: ["first_name", "last_name", "domain"]
6468
+ });
6469
+ return renderPartialRowType({
6470
+ typeName: "ContactSourceRow",
6471
+ fields: [
6472
+ .../* @__PURE__ */ new Set([
6473
+ ...inputPropertyNames(input.peoplePlay?.outputSchema),
6474
+ ...emailFields,
6475
+ ...phoneFields
6476
+ ])
6477
+ ].sort(),
6478
+ comment: "Fields the people play or later finder stages may need; the generated code still requires explicit mapping."
6479
+ });
6480
+ }
6481
+ function generateRowTypeDefinitions(input) {
6482
+ const config = playBootstrapTemplateConfig(input.options.template);
6483
+ const sourceTypeName = sourceCollectionTypeName(config.sourceEntity);
6484
+ const definitions = [
6485
+ sourceRowTypeDefinition({
6486
+ options: input.options,
6487
+ sourceTypeName,
6488
+ sourceTools: input.sourceTools,
6489
+ sourcePlay: input.sourcePlay
6490
+ }),
6491
+ contactBridgeRowTypeDefinition(input)
6492
+ ];
6493
+ return definitions.filter(Boolean).join("\n\n");
6494
+ }
6495
+ function validateBootstrapRoutes(input) {
6496
+ const config = playBootstrapTemplateConfig(input.options.template);
6497
+ const sourceCategory = config.sourceEntity === "company" ? PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY : PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY;
6498
+ for (const tool of input.sourceTools) {
6499
+ if (!tool.categories.includes(sourceCategory)) {
6500
+ throw new PlayBootstrapValidationError(
6501
+ `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`
6502
+ );
6503
+ }
6504
+ if (getterNamesFromTool(tool, "list").length === 0) {
6505
+ throw new PlayBootstrapValidationError(
6506
+ `Cannot use ${tool.toolId} as a ${config.sourceEntity} source: it exposes no extracted list getters. Run: deepline tools describe ${tool.toolId} --json`
6507
+ );
6508
+ }
6509
+ }
6510
+ if (input.options.people?.kind === "providers") {
6511
+ throw new PlayBootstrapValidationError(
6512
+ "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."
6513
+ );
6514
+ }
6515
+ for (const finder of ["email_finder", "phone_finder"]) {
6516
+ const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
6517
+ for (const tool of input.finderTools[finder] ?? []) {
6518
+ if (!tool.categories.includes(requiredCategory)) {
6519
+ throw new PlayBootstrapValidationError(
6520
+ `Cannot use ${tool.toolId} for ${finder}: expected category ${requiredCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${requiredCategory} --categories ${requiredCategory} --json`
6521
+ );
6522
+ }
6523
+ if (getterNamesFromTool(tool, "value").length === 0) {
6524
+ throw new PlayBootstrapValidationError(
6525
+ `Cannot use ${tool.toolId} as a ${finder}: it exposes no extracted value getters. Run: deepline tools describe ${tool.toolId} --json`
6526
+ );
6527
+ }
6528
+ }
6529
+ }
6530
+ }
6531
+ function sourceCollectionName(entity) {
6532
+ switch (entity) {
6533
+ case "company":
6534
+ return "companies";
6535
+ case "people":
6536
+ return "contacts";
6537
+ }
6538
+ }
6539
+ function requiredGetterName(input) {
6540
+ const getter = getterNamesFromTool(input.tool, input.kind)[0];
6541
+ if (!getter) {
6542
+ switch (input.kind) {
6543
+ case "list":
6544
+ throw new PlayBootstrapValidationError(
6545
+ `Cannot use ${input.label} as a source: it exposes no extracted list getters.`
6546
+ );
6547
+ case "value":
6548
+ throw new PlayBootstrapValidationError(
6549
+ `Cannot use ${input.label} as a finder: it exposes no extracted value getters.`
6550
+ );
6551
+ }
6552
+ }
6553
+ return getter;
6554
+ }
6555
+ function generateCsvSourceRowsBlock(input) {
6556
+ return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(input.packagedSourceCsvPath ?? input.source.value)});
6557
+ const ${input.collection}: ${input.collectionType}[] = await sourceDataset.peek(limit);`;
6558
+ }
6559
+ function generatePlaySourceRowsBlock(input) {
6560
+ const playInput = generatePlayInputObject({
6561
+ schema: input.sourcePlay?.inputSchema,
6562
+ indent: " ",
6563
+ label: input.source.value,
6564
+ entity: input.entity
6565
+ });
6566
+ return `const sourceInput = ${playInput};
6567
+ throw new Error(${jsString(`TODO: map sourceInput for ${input.source.value}, choose the play output rows field, then delete this throw.`)});
6568
+ const sourceResult = await ctx.runPlay('source_play', ${jsString(input.source.value)}, sourceInput, {
6569
+ description: ${jsString(`Seed ${input.entity} rows from the selected play.`)},
6570
+ });
6571
+ // TODO: Replace sourceResult.rows with the selected play's actual row output field.
6572
+ const ${input.collection}: ${input.collectionType}[] = (sourceResult.rows ?? []) as ${input.collectionType}[];`;
6573
+ }
6574
+ function generateProviderSourceBlock(input) {
6575
+ const getter = requiredGetterName({
6576
+ tool: input.tool,
6577
+ kind: "list",
6578
+ label: input.provider
6579
+ });
6580
+ const inputName = `${input.entity}Input_${input.index}`;
6581
+ return `// ${input.entity === "company" ? "Company" : "People"} source provider: ${input.provider}
6582
+ const ${inputName}: Record<string, unknown> = ${generateSourceProviderInputObject(
6583
+ {
6584
+ tool: input.tool,
6585
+ indent: " ",
6586
+ label: input.provider,
6587
+ entity: input.entity
6588
+ }
6589
+ )};
6590
+ throw new Error(${jsString(`TODO: fill ${inputName} for ${input.provider}, then delete this throw.`)});
6591
+ const source_${input.index} = await ctx.tools.execute({
6592
+ id: ${jsString(`${input.entity}_source_${input.index}`)},
6593
+ tool: ${jsString(input.provider)},
6594
+ input: ${inputName},
6595
+ description: ${jsString(`Seed ${input.entity} rows from ${input.provider}.`)},
6596
+ });
6597
+ // extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
6598
+ // inspect source_${input.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
6599
+ const sourceRows_${input.index} = ${accessorExpression(`source_${input.index}.extractedLists`, getter)}.get() as ${input.collectionType}[];`;
6600
+ }
6601
+ function generateProviderSourceRowsBlock(input) {
6602
+ const blocks = input.source.values.map(
6603
+ (provider, index) => generateProviderSourceBlock({
6604
+ provider,
6605
+ index,
6606
+ tool: input.sourceTools[index] ?? null,
6607
+ entity: input.entity,
6608
+ collectionType: input.collectionType
6609
+ })
6610
+ );
6611
+ return `${blocks.join("\n\n ")}
6612
+ const ${input.collection}: ${input.collectionType}[] = [${input.source.values.map((_, index) => `...sourceRows_${index}`).join(", ")}];`;
6613
+ }
6614
+ function generateSourceRowsBlock(input) {
6615
+ const config = playBootstrapTemplateConfig(input.options.template);
6616
+ const entity = config.sourceEntity;
6617
+ const collection = sourceCollectionName(entity);
6618
+ const collectionType = sourceCollectionTypeName(entity);
6619
+ switch (input.options.from.kind) {
6620
+ case "csv":
6621
+ return generateCsvSourceRowsBlock({
6622
+ source: input.options.from,
6623
+ collection,
6624
+ collectionType,
6625
+ packagedSourceCsvPath: input.packagedSourceCsvPath
6626
+ });
6627
+ case "play":
6628
+ return generatePlaySourceRowsBlock({
6629
+ source: input.options.from,
6630
+ sourcePlay: input.sourcePlay,
6631
+ entity,
6632
+ collection,
6633
+ collectionType
6634
+ });
6635
+ case "providers":
6636
+ return generateProviderSourceRowsBlock({
6637
+ source: input.options.from,
6638
+ sourceTools: input.sourceTools,
6639
+ entity,
6640
+ collection,
6641
+ collectionType
6642
+ });
6643
+ }
6644
+ }
6645
+ function generateSourceSeedBlock(input) {
6646
+ const sourceRows = generateSourceRowsBlock(input);
6647
+ const peoplePlayRef = stagePlayRef(input.options.people);
6648
+ if (!peoplePlayRef) return sourceRows;
6649
+ const peopleInput = generateCompanyInputObjectFromSchema(
6650
+ input.peoplePlay?.inputSchema,
6651
+ " ",
6652
+ peoplePlayRef,
6653
+ ["domain", "company_name"]
6654
+ );
6655
+ return `${sourceRows}
6656
+ const contacts: ContactSourceRow[] = [];
6657
+ for (const [index, company] of companies.slice(0, limit).entries()) {
6658
+ const peopleInput = ${peopleInput};
6659
+ throw new Error(${jsString(`TODO: map company fields into peopleInput for ${peoplePlayRef}, choose the play output rows field, then delete this throw.`)});
6660
+ const peopleResult = await ctx.runPlay(
6661
+ \`people_play_\${index}\`,
6662
+ ${jsString(peoplePlayRef)},
6663
+ peopleInput,
6664
+ {
6665
+ description: 'Map one company row into people/contact rows with the selected play.',
6666
+ },
6667
+ );
6668
+ // TODO: Replace peopleResult.rows with the selected play's actual contact rows field.
6669
+ contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
6670
+ }`;
6671
+ }
6672
+ function finderProviderStepName(input) {
6673
+ return `${input.aggregateStepName}${input.index}_${safeIdentifier(input.provider)}`;
6674
+ }
6675
+ function finderValueGetter(input) {
6676
+ const getters = getterNamesFromTool(input.tool, "value");
6677
+ const getter = getters.find((name) => name === input.outputField) ?? requiredGetterName({
6678
+ tool: input.tool,
6679
+ kind: "value",
6680
+ label: input.provider
6681
+ });
6682
+ return getter;
6683
+ }
6684
+ function optionalFinderValueExpression(candidateExpression, outputField) {
6685
+ const valueExpression = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(outputField) ? `${candidateExpression}?.${outputField}` : `${candidateExpression}?.[${jsString(outputField)}]`;
6686
+ return `${valueExpression}?.trim()`;
6687
+ }
6688
+ function generateFinderPlayStep(input) {
6689
+ const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
6690
+ const resultTypeName = finderResultTypeName(input.finder);
6691
+ const payload = generateContactInputObjectFromSchema(
6692
+ input.play?.inputSchema,
6693
+ " ",
6694
+ input.stage.value
6695
+ );
6696
+ return `.step(${jsString(outputField)}, async (row, rowCtx) => {
6697
+ const ${input.aggregateStepName}Input = ${payload};
6698
+ throw new Error(${jsString(`TODO: map ${input.aggregateStepName}Input for ${input.stage.value}, then delete this throw.`)});
6699
+ const ${input.aggregateStepName}Result = await rowCtx.runPlay<${resultTypeName}>(
6700
+ ${jsString(`${input.aggregateStepName}Play`)},
6701
+ ${jsString(input.stage.value)},
6702
+ ${input.aggregateStepName}Input,
6703
+ {
6704
+ description: ${jsString(`Run ${input.finder} play.`)},
6705
+ },
6706
+ );
6707
+ return typeof ${input.aggregateStepName}Result === 'string'
6708
+ ? ${input.aggregateStepName}Result.trim() || null
6709
+ : ${input.aggregateStepName}Result?.${outputField} ?? null;
6710
+ })`;
6711
+ }
6712
+ function generateFinderProviderResolver(input) {
6713
+ const payload = generateContactInputObjectFromSchema(
6714
+ input.tool?.inputSchema,
6715
+ " ",
6716
+ input.provider
6717
+ );
6718
+ const getter = finderValueGetter({
6719
+ tool: input.tool,
6720
+ provider: input.provider,
6721
+ outputField: input.outputField
6722
+ });
6723
+ return `async (row, rowCtx) => {
6724
+ const providerInput = ${payload};
6725
+ throw new Error(${jsString(`TODO: map providerInput for ${input.provider}, then delete this throw.`)});
6726
+ const result = await rowCtx.tools.execute({
6727
+ id: ${jsString(`${input.aggregateStepName}_${input.providerIndex}`)},
6728
+ tool: ${jsString(input.provider)},
6729
+ input: providerInput,
6730
+ description: ${jsString(`Try ${input.provider} as a ${input.finder}.`)},
6731
+ });
6732
+ return {
6733
+ ${input.outputField}: (${accessorExpression("result.extractedValues", getter)}.get() as string | null) ?? null,
6734
+ result,
6735
+ };
6736
+ }`;
6737
+ }
6738
+ function generateFinderProviderStep(input) {
6739
+ const stepName = input.stepNames[input.index];
6740
+ switch (input.index) {
6741
+ case 0:
6742
+ return `.step(${jsString(stepName)}, ${input.resolver})`;
6743
+ default: {
6744
+ const priorCandidates = input.stepNames.slice(0, input.index).map((name) => `row.${name}`).join(", ");
6745
+ return `.step(
6746
+ ${jsString(stepName)},
6747
+ when(
6748
+ (row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate", input.outputField)}),
6749
+ ${input.resolver},
6750
+ ),
6751
+ )`;
6752
+ }
6753
+ }
6754
+ }
6755
+ function generateFinderProviderWaterfall(input) {
6756
+ const legPrefix = finderProviderStepPrefix(input.finder);
6757
+ const stepNames = input.stage.values.map(
6758
+ (provider, index) => finderProviderStepName({
6759
+ aggregateStepName: legPrefix,
6760
+ provider,
6761
+ index
6762
+ })
6763
+ );
6764
+ const providerSteps = input.stage.values.map(
6765
+ (provider, index) => generateFinderProviderStep({
6766
+ index,
6767
+ stepNames,
6768
+ outputField: input.outputField,
6769
+ resolver: generateFinderProviderResolver({
6770
+ finder: input.finder,
6771
+ provider,
6772
+ providerIndex: index,
6773
+ tool: input.tools[index] ?? null,
6774
+ aggregateStepName: input.aggregateStepName,
6775
+ outputField: input.outputField
6776
+ })
6777
+ })
6778
+ );
6779
+ const candidateNames = stepNames.map((name) => `row.${name}`).join(", ");
6780
+ return `// ${input.aggregateStepName} provider waterfall. Each provider leg is active once its TODO throw is removed;
6781
+ // delete or comment out legs you do not want before running. Later legs are gated with when(...).
6782
+ ${providerSteps.join("\n ")}
6783
+ .step(${jsString(input.aggregateStepName)}, (row) => {
6784
+ const candidates = [${candidateNames}];
6785
+ const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate", input.outputField)});
6786
+ return ${optionalFinderValueExpression("match", input.outputField)} ?? null;
6787
+ })`;
6788
+ }
6789
+ function generateFinderStageSteps(input) {
6790
+ const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
6791
+ const aggregateStepName = stepFieldName(input.finder);
6792
+ switch (input.stage.kind) {
6793
+ case "play":
6794
+ return generateFinderPlayStep({
6795
+ finder: input.finder,
6796
+ stage: input.stage,
6797
+ play: input.finderPlays[input.finder],
6798
+ aggregateStepName
6799
+ });
6800
+ case "providers":
6801
+ return generateFinderProviderWaterfall({
6802
+ finder: input.finder,
6803
+ stage: input.stage,
6804
+ tools: input.finderTools[input.finder] ?? [],
6805
+ aggregateStepName,
6806
+ outputField
6807
+ });
6808
+ }
6809
+ }
6810
+ function generateFinderSteps(input) {
6811
+ return ["email_finder", "phone_finder"].flatMap((finder) => {
6812
+ const stage = finderStage(input.options, finder);
6813
+ return stage ? [
6814
+ generateFinderStageSteps({
6815
+ ...input,
6816
+ finder,
6817
+ stage
6818
+ })
6819
+ ] : [];
6820
+ }).join("\n ");
6821
+ }
6822
+ function generateBootstrapPlaySource(input) {
6823
+ const config = playBootstrapTemplateConfig(input.options.template);
6824
+ const sourceSeedBlock = generateSourceSeedBlock(input);
6825
+ const finderSteps = generateFinderSteps(input);
6826
+ const hasPeople = config.sourceEntity === "people" || Boolean(input.options.people);
6827
+ const sourceCollection = hasPeople ? "contacts" : "companies";
6828
+ const mapSteps = finderSteps ? `
6829
+ ${finderSteps}` : "";
6830
+ const sourceCsvRowType = input.options.from.kind === "csv" ? renderSourceCsvRowType(input.sourceCsvColumns) : "";
6831
+ const rowTypeDefinitions = generateRowTypeDefinitions(input);
6832
+ const finderPlayResultTypes = generatedFinderPlayResultTypes(input);
6833
+ const typeDefinitions = [
6834
+ sourceCsvRowType.trimEnd(),
6835
+ rowTypeDefinitions,
6836
+ finderPlayResultTypes
6837
+ ].filter((definition) => definition.trim().length > 0).join("\n\n");
6838
+ const importNames = needsWhenImport(input.options) ? "definePlay, when" : "definePlay";
6839
+ return `import { ${importNames} } from 'deepline';
6840
+
6841
+ ${typeDefinitions}
6842
+
6843
+ type Input = {
6844
+ limit?: number;
6845
+ };
6846
+
6847
+ export default definePlay(${jsString(input.options.name)}, async (ctx, input: Input = {}) => {
6848
+ const limit = Math.max(1, Math.min(Number(input.limit ?? ${input.options.limit}), ${input.options.limit}));
6849
+ ${sourceSeedBlock}
6850
+
6851
+ const rowsToProcess = ${sourceCollection}.slice(0, limit);
6852
+ if (rowsToProcess.length === 0) {
6853
+ throw new Error('plays bootstrap found 0 source rows. Check the source provider/play/CSV output.');
6854
+ }
6855
+
6856
+ const rows = await ctx
6857
+ .map('bootstrap_rows', rowsToProcess)${mapSteps}
6858
+ .run({
6859
+ key: (_row, index) => index,
6860
+ description: ${jsString(`Bootstrap ${input.options.template}: seed source rows, run requested stages, then return the mapped rows.`)},
6861
+ });
6862
+
6863
+ return {
6864
+ count: await rows.count(),
6865
+ rows,
6866
+ };
6867
+ });
6868
+
6869
+ `;
6870
+ }
6871
+ async function describePlayMaybe(client, playRef) {
6872
+ return playRef ? client.describePlay(playRef, { compact: true }) : null;
6873
+ }
6874
+ function loadTools(client, providers) {
6875
+ return Promise.all(providers.map((provider) => client.getTool(provider)));
6876
+ }
6877
+ async function loadBootstrapContracts(client, options) {
6878
+ const [
6879
+ sourceTools,
6880
+ sourcePlay,
6881
+ peoplePlay,
6882
+ emailPlay,
6883
+ phonePlay,
6884
+ emailTools,
6885
+ phoneTools
6886
+ ] = await Promise.all([
6887
+ loadTools(client, sourceProviders(options)),
6888
+ describePlayMaybe(client, sourcePlayRef(options)),
6889
+ describePlayMaybe(client, stagePlayRef(options.people)),
6890
+ describePlayMaybe(client, stagePlayRef(options.email)),
6891
+ describePlayMaybe(client, stagePlayRef(options.phone)),
6892
+ loadTools(client, stageProviders(options.email)),
6893
+ loadTools(client, stageProviders(options.phone))
6894
+ ]);
6895
+ const contracts = {
6896
+ sourceTools,
6897
+ sourcePlay,
6898
+ peoplePlay,
6899
+ finderTools: {
6900
+ email_finder: emailTools,
6901
+ phone_finder: phoneTools
6902
+ },
6903
+ finderPlays: {
6904
+ email_finder: emailPlay,
6905
+ phone_finder: phonePlay
6906
+ }
6907
+ };
6908
+ validateBootstrapRoutes({
6909
+ options,
6910
+ sourceTools: contracts.sourceTools,
6911
+ peoplePlay: contracts.peoplePlay,
6912
+ finderTools: contracts.finderTools,
6913
+ finderPlays: contracts.finderPlays
6914
+ });
6915
+ return contracts;
6916
+ }
6917
+ function loadCsvContext(source) {
6918
+ switch (source.kind) {
6919
+ case "csv":
6920
+ return {
6921
+ packagedSourceCsvPath: packagedCsvPathForPlay(source.value),
6922
+ sourceCsvColumns: readSourceCsvColumnSpecs(source.value)
6923
+ };
6924
+ case "play":
6925
+ case "providers":
6926
+ return {
6927
+ packagedSourceCsvPath: null,
6928
+ sourceCsvColumns: []
6929
+ };
6930
+ }
6931
+ }
6932
+ function errorMessage(error) {
6933
+ return error instanceof Error ? error.message : String(error);
6934
+ }
6935
+ function renderPlayBootstrapError(error) {
6936
+ console.error(errorMessage(error));
6937
+ return error instanceof PlayBootstrapError ? error.exitCode : 1;
6938
+ }
6939
+ async function runPlayBootstrap(args) {
6940
+ const options = parsePlayBootstrapOptions(args);
6941
+ const client = new DeeplineClient();
6942
+ const contracts = await loadBootstrapContracts(client, options);
6943
+ const csvContext = loadCsvContext(options.from);
6944
+ const source = generateBootstrapPlaySource({
6945
+ options,
6946
+ ...contracts,
6947
+ ...csvContext
6948
+ });
6949
+ process.stdout.write(source);
6950
+ return 0;
6951
+ }
6952
+ async function handlePlayBootstrap(args) {
6953
+ return runPlayBootstrap(args).catch(renderPlayBootstrapError);
6954
+ }
6955
+ function registerPlayBootstrapCommand(play) {
6956
+ play.command("bootstrap <template>").description("Print a scratchpad play for a GTM route template.").addHelpText(
6957
+ "after",
6958
+ `
6959
+ Notes:
6960
+ Cloud-validated play generator for agents. Pick the JTBD as the positional
6961
+ template, bind resources with typed refs, redirect stdout to a .play.ts file,
6962
+ then edit the generated TODO mapping comments. Multiple finder providers are
6963
+ generated as a waterfall in the order you pass them.
6964
+
6965
+ This command requires auth because provider/play contracts are fetched from
6966
+ Deepline. It prints TypeScript source only and does not run paid tools; the
6967
+ generated play may spend credits later when you run it.
6968
+
6969
+ stdout is the generated .play.ts source. Errors and diagnostics go to stderr.
6970
+ There is no JSON mode and no --out; use shell redirection:
6971
+ deepline plays bootstrap ... > scratchpad.play.ts
6972
+
6973
+ Templates:
6974
+ people-list start from people/contact rows
6975
+ company-list start from company/account rows
6976
+ people-email people/contact rows -> email finder
6977
+ people-phone people/contact rows -> phone finder
6978
+ company-people company/account rows -> people play
6979
+ company-people-email company/account rows -> people play -> email finder
6980
+ company-people-phone company/account rows -> people play -> phone finder
6981
+
6982
+ Resource refs:
6983
+ csv:./contacts.csv
6984
+ play:prebuilt/name-and-domain-to-email-waterfall
6985
+ provider:dropleads_search_people
6986
+ providers:hunter_email_finder,leadmagic_email_finder
6987
+
6988
+ Validation:
6989
+ source providers must match the route entity: company_search or people_search
6990
+ source providers must expose list getters
6991
+ company -> people uses a play only; provider bridge is generated later when a play exists
6992
+ email/phone finder providers must match their category and expose value getters
6993
+ finder plays/providers must match the route; generated code leaves input mapping explicit
6994
+ business-specific provider inputs and company -> people persona fields are TODOs in code
6995
+ csv: paths are resolved from the directory where you run bootstrap; redirect the play file there too
6996
+
6997
+ Exit codes:
6998
+ 0 success
6999
+ 2 usage/local input error
7000
+ 7 route validation failed
7001
+
7002
+ Examples:
7003
+ 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
7004
+ deepline plays check email-flow.play.ts
7005
+ deepline plays run email-flow.play.ts --input '{"limit":5}' --watch
7006
+
7007
+ deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5 > prospecting.play.ts
7008
+ 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
7009
+ deepline plays bootstrap company-list --from provider:apollo_company_search --limit 5 > companies.play.ts
7010
+ `
7011
+ ).option("--name <name>", "Generated play name").option(
7012
+ "--from <ref>",
7013
+ "Route source: csv:PATH, play:REF, provider:ID, or providers:ID,ID"
7014
+ ).option(
7015
+ "--using <ref>",
7016
+ "Single-stage route shorthand for people-email, people-phone, or company-people"
7017
+ ).option(
7018
+ "--people <ref>",
7019
+ "Company-to-people stage for company-people-email/phone; use play:REF"
7020
+ ).option(
7021
+ "--email <ref>",
7022
+ "Email finder stage: play:REF, provider:ID, or providers:ID,ID"
7023
+ ).option(
7024
+ "--phone <ref>",
7025
+ "Phone finder stage: play:REF, provider:ID, or providers:ID,ID"
7026
+ ).option("--limit <n>", "Maximum rows to fan out in the generated play").action(async (template, options) => {
7027
+ process.exitCode = await handlePlayBootstrap([
7028
+ template,
7029
+ ...options.name ? ["--name", options.name] : [],
7030
+ ...options.from ? ["--from", options.from] : [],
7031
+ ...options.using ? ["--using", options.using] : [],
7032
+ ...options.people ? ["--people", options.people] : [],
7033
+ ...options.email ? ["--email", options.email] : [],
7034
+ ...options.phone ? ["--phone", options.phone] : [],
7035
+ ...options.limit ? ["--limit", options.limit] : []
7036
+ ]);
5584
7037
  });
5585
7038
  }
5586
7039
 
@@ -6035,9 +7488,9 @@ function traceCliSync(phase, fields, run) {
6035
7488
  }
6036
7489
  }
6037
7490
  function sleep4(ms) {
6038
- return new Promise((resolve11) => setTimeout(resolve11, ms));
7491
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
6039
7492
  }
6040
- function parseReferencedPlayTarget(target) {
7493
+ function parseReferencedPlayTarget2(target) {
6041
7494
  const trimmed = target.trim();
6042
7495
  const slashIndex = trimmed.indexOf("/");
6043
7496
  if (slashIndex <= 0 || slashIndex === trimmed.length - 1) {
@@ -6058,7 +7511,7 @@ function buildBarePrebuiltReferenceError(input) {
6058
7511
  );
6059
7512
  }
6060
7513
  async function assertCanonicalNamedPlayReference(client, target) {
6061
- const parsed = parseReferencedPlayTarget(target);
7514
+ const parsed = parseReferencedPlayTarget2(target);
6062
7515
  const detail = await client.getPlay(parsed.playName);
6063
7516
  if (detail.play.ownerType === "deepline" && !isPrebuiltReferenceTarget(target)) {
6064
7517
  throw buildBarePrebuiltReferenceError({
@@ -6079,10 +7532,10 @@ function formatPlayListReference(play) {
6079
7532
  return play.reference || play.name;
6080
7533
  }
6081
7534
  function defaultMaterializedPlayPath(reference) {
6082
- return resolve9(defaultStarterPlayPath(reference));
7535
+ return resolve10(defaultStarterPlayPath(reference));
6083
7536
  }
6084
7537
  function defaultStarterPlayPath(reference) {
6085
- const playName = parseReferencedPlayTarget(reference).unqualifiedPlayName;
7538
+ const playName = parseReferencedPlayTarget2(reference).unqualifiedPlayName;
6086
7539
  const safeName = playName.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
6087
7540
  return `./${safeName || "play"}.play.ts`;
6088
7541
  }
@@ -6138,7 +7591,7 @@ To make your own version:
6138
7591
  );
6139
7592
  }
6140
7593
  async function ensureEditableRemotePlay(client, target) {
6141
- const parsed = parseReferencedPlayTarget(target);
7594
+ const parsed = parseReferencedPlayTarget2(target);
6142
7595
  const detail = await client.getPlay(parsed.playName);
6143
7596
  if (detail.play.ownerType === "deepline") {
6144
7597
  throw buildReadonlyPrebuiltPlayError(formatPlayReference(detail.play));
@@ -6158,7 +7611,7 @@ function extractPlayName(code, filePath) {
6158
7611
  throw buildMissingDefinePlayError(filePath);
6159
7612
  }
6160
7613
  function isFileTarget(target) {
6161
- return existsSync6(resolve9(target));
7614
+ return existsSync6(resolve10(target));
6162
7615
  }
6163
7616
  function looksLikeRunId(target) {
6164
7617
  return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
@@ -6179,7 +7632,7 @@ function looksLikeFilePath(target) {
6179
7632
  }
6180
7633
  return target.includes("\\") || /\.(ts|js|mjs|play\.ts)$/.test(target);
6181
7634
  }
6182
- function parsePositiveInteger2(value, flagName) {
7635
+ function parsePositiveInteger3(value, flagName) {
6183
7636
  const parsed = Number.parseInt(value, 10);
6184
7637
  if (!Number.isFinite(parsed) || parsed <= 0) {
6185
7638
  throw new Error(`${flagName} must be a positive integer.`);
@@ -6187,7 +7640,7 @@ function parsePositiveInteger2(value, flagName) {
6187
7640
  return parsed;
6188
7641
  }
6189
7642
  function parseJsonInput(raw) {
6190
- const source = raw.startsWith("@") ? readFileSync5(resolve9(raw.slice(1)), "utf-8") : raw;
7643
+ const source = raw.startsWith("@") ? readFileSync5(resolve10(raw.slice(1)), "utf-8") : raw;
6191
7644
  const parsed = JSON.parse(source);
6192
7645
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
6193
7646
  throw new Error("--input must be a JSON object.");
@@ -6254,7 +7707,8 @@ function setDottedInputValue(input, path, value) {
6254
7707
  cursor[parts[parts.length - 1]] = value;
6255
7708
  }
6256
7709
  function schemaMetadata(schema, key) {
6257
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) return null;
7710
+ if (!schema || typeof schema !== "object" || Array.isArray(schema))
7711
+ return null;
6258
7712
  const value = schema[key];
6259
7713
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
6260
7714
  }
@@ -6288,7 +7742,7 @@ function fileInputBindingsFromStaticPipeline(staticPipeline) {
6288
7742
  function isLocalFilePathValue(value) {
6289
7743
  if (typeof value !== "string" || !value.trim()) return false;
6290
7744
  if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
6291
- return existsSync6(resolve9(value));
7745
+ return existsSync6(resolve10(value));
6292
7746
  }
6293
7747
  function inputContainsLocalFilePath(value) {
6294
7748
  if (isLocalFilePathValue(value)) {
@@ -6309,12 +7763,14 @@ function namedRunNeedsPlayDefinition(input) {
6309
7763
  }
6310
7764
  async function stageFileInputArgs(input) {
6311
7765
  const uniqueBindings = [
6312
- ...new Map(input.bindings.map((binding) => [binding.inputPath, binding])).values()
7766
+ ...new Map(
7767
+ input.bindings.map((binding) => [binding.inputPath, binding])
7768
+ ).values()
6313
7769
  ];
6314
7770
  const localFiles = uniqueBindings.flatMap((binding) => {
6315
7771
  const value = getDottedInputValue(input.runtimeInput, binding.inputPath);
6316
7772
  if (!isLocalFilePathValue(value)) return [];
6317
- const absolutePath = resolve9(value);
7773
+ const absolutePath = resolve10(value);
6318
7774
  return [{ binding, absolutePath, logicalPath: basename3(absolutePath) }];
6319
7775
  });
6320
7776
  if (localFiles.length === 0) {
@@ -6327,10 +7783,18 @@ async function stageFileInputArgs(input) {
6327
7783
  localFiles.map((file) => stageFile(file.logicalPath, file.absolutePath))
6328
7784
  );
6329
7785
  for (const [index, file] of localFiles.entries()) {
6330
- setDottedInputValue(input.runtimeInput, file.binding.inputPath, file.logicalPath);
7786
+ setDottedInputValue(
7787
+ input.runtimeInput,
7788
+ file.binding.inputPath,
7789
+ file.logicalPath
7790
+ );
6331
7791
  const stagedFile = staged[index];
6332
7792
  if (stagedFile && stagedFile.logicalPath !== file.logicalPath) {
6333
- setDottedInputValue(input.runtimeInput, file.binding.inputPath, stagedFile.logicalPath);
7793
+ setDottedInputValue(
7794
+ input.runtimeInput,
7795
+ file.binding.inputPath,
7796
+ stagedFile.logicalPath
7797
+ );
6334
7798
  }
6335
7799
  }
6336
7800
  return {
@@ -6350,9 +7814,9 @@ function stageFile(logicalPath, absolutePath) {
6350
7814
  }
6351
7815
  function normalizePlayPath(filePath) {
6352
7816
  try {
6353
- return realpathSync.native(resolve9(filePath));
7817
+ return realpathSync.native(resolve10(filePath));
6354
7818
  } catch {
6355
- return resolve9(filePath);
7819
+ return resolve10(filePath);
6356
7820
  }
6357
7821
  }
6358
7822
  function formatBundlingErrors(filePath, errors) {
@@ -6710,7 +8174,10 @@ function formatProgressCounts(input) {
6710
8174
  if (completed === null || total === null || total <= 0) {
6711
8175
  return null;
6712
8176
  }
6713
- const percent = Math.max(0, Math.min(100, Math.round(completed / total * 100)));
8177
+ const percent = Math.max(
8178
+ 0,
8179
+ Math.min(100, Math.round(completed / total * 100))
8180
+ );
6714
8181
  const failed = typeof input.failed === "number" && Number.isFinite(input.failed) && input.failed > 0 ? `, failed ${formatInteger(input.failed)}` : "";
6715
8182
  return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
6716
8183
  }
@@ -7217,7 +8684,7 @@ function isDatasetHandle(value) {
7217
8684
  value && typeof value === "object" && !Array.isArray(value) && value.kind === "dataset"
7218
8685
  );
7219
8686
  }
7220
- function collectDatasetHandleLines(value, path = "result") {
8687
+ function collectDatasetHandleLines(value, path = "result", datasetStats) {
7221
8688
  if (!value || typeof value !== "object" || Array.isArray(value)) {
7222
8689
  return [];
7223
8690
  }
@@ -7228,6 +8695,9 @@ function collectDatasetHandleLines(value, path = "result") {
7228
8695
  const lines2 = [
7229
8696
  ` dataset ${typeof record.path === "string" ? record.path : path}: rows=${count === null ? "-" : formatInteger(count)} preview=${formatInteger(preview.length)}`
7230
8697
  ];
8698
+ if (datasetStats && (datasetStats.source === path || datasetStats.source === record.path)) {
8699
+ lines2.push(...formatDatasetStatsLines(datasetStats.stats, " "));
8700
+ }
7231
8701
  if (typeof record.queryDatasetCommand === "string") {
7232
8702
  lines2.push(` query dataset: ${record.queryDatasetCommand}`);
7233
8703
  }
@@ -7241,7 +8711,9 @@ function collectDatasetHandleLines(value, path = "result") {
7241
8711
  if (key === "preview" || key === "access") {
7242
8712
  continue;
7243
8713
  }
7244
- lines.push(...collectDatasetHandleLines(child, `${path}.${key}`));
8714
+ lines.push(
8715
+ ...collectDatasetHandleLines(child, `${path}.${key}`, datasetStats)
8716
+ );
7245
8717
  }
7246
8718
  return lines;
7247
8719
  }
@@ -7424,7 +8896,9 @@ function buildInsufficientCreditsSummaryLines(input) {
7424
8896
  const runId = input.status.runId?.trim();
7425
8897
  if (runId) {
7426
8898
  lines.push(` inspect: deepline runs get ${runId} --json`);
7427
- lines.push(` export partial: deepline runs export ${runId} --out output.csv`);
8899
+ lines.push(
8900
+ ` export partial: deepline runs export ${runId} --out output.csv`
8901
+ );
7428
8902
  }
7429
8903
  return lines;
7430
8904
  }
@@ -7496,7 +8970,10 @@ function normalizeErrorsForEnvelope(status, error) {
7496
8970
  }
7497
8971
  return {
7498
8972
  ...entry,
7499
- message: formatInsufficientCreditsMessage({ billing: billing2, error: message2 }),
8973
+ message: formatInsufficientCreditsMessage({
8974
+ billing: billing2,
8975
+ error: message2
8976
+ }),
7500
8977
  billing: stripProviderSpendFromBilling(billing2)
7501
8978
  };
7502
8979
  });
@@ -7595,13 +9072,26 @@ function compactPlayStatus(status) {
7595
9072
  };
7596
9073
  }
7597
9074
  function enrichPlayStatusWithDatasetStats(status) {
7598
- const rowsInfo = extractCanonicalRowsInfo(status);
7599
- if (!rowsInfo?.complete) {
9075
+ const datasetStats = datasetStatsForStatus(status);
9076
+ if (!datasetStats) {
7600
9077
  return status;
7601
9078
  }
7602
9079
  return {
7603
9080
  ...status,
7604
- dataset_stats: buildDatasetStats(
9081
+ result: attachDatasetStatsToResult(
9082
+ status.result,
9083
+ datasetStats
9084
+ )
9085
+ };
9086
+ }
9087
+ function datasetStatsForStatus(status) {
9088
+ const rowsInfo = extractCanonicalRowsInfo(status);
9089
+ if (!rowsInfo?.complete) {
9090
+ return null;
9091
+ }
9092
+ return {
9093
+ source: rowsInfo.source,
9094
+ stats: buildDatasetStats(
7605
9095
  rowsInfo.rows,
7606
9096
  rowsInfo.totalRows,
7607
9097
  rowsInfo.columns,
@@ -7609,6 +9099,52 @@ function enrichPlayStatusWithDatasetStats(status) {
7609
9099
  )
7610
9100
  };
7611
9101
  }
9102
+ function attachDatasetStatsToResult(result, datasetStats) {
9103
+ if (!result || typeof result !== "object" || Array.isArray(result)) {
9104
+ return result;
9105
+ }
9106
+ const sourcePath = datasetStats.source?.replace(/^result\.?/, "") ?? "";
9107
+ const attach = (value, path) => {
9108
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
9109
+ return value;
9110
+ }
9111
+ const record = value;
9112
+ const isMatchingDataset = record.kind === "dataset" && (path === sourcePath || `result.${path}` === datasetStats.source);
9113
+ const next = { ...record };
9114
+ if (isMatchingDataset) {
9115
+ next.summary = datasetStats.stats;
9116
+ return next;
9117
+ }
9118
+ for (const [key, child] of Object.entries(record)) {
9119
+ if (key === "preview" || key === "access") continue;
9120
+ const childPath = path ? `${path}.${key}` : key;
9121
+ const attached = attach(child, childPath);
9122
+ if (attached !== child) {
9123
+ next[key] = attached;
9124
+ }
9125
+ }
9126
+ return next;
9127
+ };
9128
+ return attach(result, "");
9129
+ }
9130
+ function formatDatasetStatsLines(datasetStats, indent = " ") {
9131
+ if (!datasetStats) {
9132
+ return [];
9133
+ }
9134
+ const lines = [`${indent}summary:`];
9135
+ for (const [column, stat3] of Object.entries(datasetStats.columnStats).slice(
9136
+ 0,
9137
+ 12
9138
+ )) {
9139
+ const topValues = stat3.top_values ? `, top_values=${Object.entries(stat3.top_values).slice(0, 3).map(([value, count]) => `${value}=${count}`).join(", ")}` : "";
9140
+ const sample = stat3.sample_value !== void 0 ? `, sample_value=${JSON.stringify(stat3.sample_value)}` : "";
9141
+ const execution = stat3.execution ? `, execution=${Object.entries(stat3.execution).map(([bucket, count]) => `${bucket}=${count}`).join(", ")}` : "";
9142
+ lines.push(
9143
+ `${indent} ${column}: non_empty=${stat3.non_empty}, unique=${stat3.unique}${topValues}${sample}${execution}`
9144
+ );
9145
+ }
9146
+ return lines;
9147
+ }
7612
9148
  function readRunPackageRun(packaged) {
7613
9149
  return packaged.run && typeof packaged.run === "object" && !Array.isArray(packaged.run) ? packaged.run : {};
7614
9150
  }
@@ -7617,6 +9153,60 @@ function readRecordArray(value) {
7617
9153
  (item) => item !== null && typeof item === "object" && !Array.isArray(item)
7618
9154
  ) : [];
7619
9155
  }
9156
+ function readRecord(value) {
9157
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
9158
+ }
9159
+ function formatSummaryScalar(value) {
9160
+ if (typeof value === "number") {
9161
+ return Number.isFinite(value) ? formatInteger(Math.trunc(value)) : null;
9162
+ }
9163
+ if (typeof value === "string" || typeof value === "boolean") {
9164
+ return String(value);
9165
+ }
9166
+ if (value === null) {
9167
+ return "null";
9168
+ }
9169
+ return null;
9170
+ }
9171
+ function formatSummaryScalarParts(record, skipKeys = /* @__PURE__ */ new Set()) {
9172
+ const parts = [];
9173
+ for (const [key, value] of Object.entries(record)) {
9174
+ if (skipKeys.has(key)) {
9175
+ continue;
9176
+ }
9177
+ const formatted = formatSummaryScalar(value);
9178
+ if (formatted !== null) {
9179
+ parts.push(`${key}=${formatted}`);
9180
+ }
9181
+ }
9182
+ return parts;
9183
+ }
9184
+ function formatPackageDatasetSummaryLines(summary, indent = " ") {
9185
+ const record = readRecord(summary);
9186
+ const columnStats = readRecord(record?.columnStats);
9187
+ if (!record || !columnStats) {
9188
+ return [];
9189
+ }
9190
+ const lines = [];
9191
+ const parts = formatSummaryScalarParts(record, /* @__PURE__ */ new Set(["columnStats"]));
9192
+ if (parts.length > 0) {
9193
+ lines.push(`${indent}summary: ${parts.join(" ")}`);
9194
+ }
9195
+ for (const [column, rawColumnSummary] of Object.entries(columnStats)) {
9196
+ const columnSummary = readRecord(rawColumnSummary);
9197
+ if (!columnSummary) continue;
9198
+ const execution = readRecord(columnSummary.execution);
9199
+ const executionText = execution ? Object.entries(execution).map(([bucket, value]) => `${bucket}=${String(value)}`).join(", ") : "";
9200
+ const columnParts = [
9201
+ ...formatSummaryScalarParts(columnSummary, /* @__PURE__ */ new Set(["execution"])),
9202
+ executionText ? `execution=${executionText}` : null
9203
+ ].filter(Boolean);
9204
+ if (columnParts.length > 0) {
9205
+ lines.push(`${indent} ${column}: ${columnParts.join(" ")}`);
9206
+ }
9207
+ }
9208
+ return lines;
9209
+ }
7620
9210
  function actionToCommand(action) {
7621
9211
  if (!action || typeof action !== "object" || Array.isArray(action)) {
7622
9212
  return null;
@@ -7651,7 +9241,9 @@ function buildRunPackageTextLines(packaged) {
7651
9241
  const runId = typeof run.id === "string" ? run.id : "unknown";
7652
9242
  const status = typeof run.status === "string" ? run.status : "unknown";
7653
9243
  const playName = typeof run.playName === "string" ? run.playName : null;
7654
- const lines = [`${status === "completed" ? "\u2713" : status === "failed" ? "\u2717" : "\u2022"} ${status} ${runId}`];
9244
+ const lines = [
9245
+ `${status === "completed" ? "\u2713" : status === "failed" ? "\u2717" : "\u2022"} ${status} ${runId}`
9246
+ ];
7655
9247
  if (playName) {
7656
9248
  lines.push(` play: ${playName}`);
7657
9249
  }
@@ -7663,8 +9255,11 @@ function buildRunPackageTextLines(packaged) {
7663
9255
  const rowCount = output && typeof output.rowCount === "number" ? ` rows=${formatInteger(output.rowCount)}` : "";
7664
9256
  const preview = output?.preview && typeof output.preview === "object" && !Array.isArray(output.preview) ? output.preview : null;
7665
9257
  const previewRows = Array.isArray(preview?.rows) ? preview.rows.length : null;
7666
- const previewLabel = previewRows !== null ? ` preview=${previewRows}${preview?.truncated ? " truncated" : ""}` : "";
7667
- lines.push(` ${kind} ${id}: ${stepStatus}${rowCount}${previewLabel}`);
9258
+ lines.push(` ${kind} ${id}: ${stepStatus}${rowCount}`);
9259
+ lines.push(...formatPackageDatasetSummaryLines(output?.summary));
9260
+ if (previewRows !== null) {
9261
+ lines.push(` preview=${previewRows}${preview?.truncated ? " truncated" : ""}`);
9262
+ }
7668
9263
  }
7669
9264
  const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
7670
9265
  const datasetActions = readFirstDatasetActions(packaged);
@@ -7678,8 +9273,13 @@ function buildRunPackageTextLines(packaged) {
7678
9273
  }
7679
9274
  function writePlayResult(status, jsonOutput, options) {
7680
9275
  const packaged = getPlayRunPackage(status);
9276
+ const datasetStats = datasetStatsForStatus(status);
7681
9277
  if (jsonOutput) {
7682
- const payload2 = options?.fullJson ? status : compactPlayStatus(status);
9278
+ const compact2 = compactPlayStatus(status);
9279
+ const payload2 = options?.fullJson ? enrichPlayStatusWithDatasetStats(status) : datasetStats ? {
9280
+ ...compact2,
9281
+ result: attachDatasetStatsToResult(compact2.result, datasetStats)
9282
+ } : compact2;
7683
9283
  printCommandEnvelope(payload2, { json: true });
7684
9284
  return;
7685
9285
  }
@@ -7715,35 +9315,42 @@ function writePlayResult(status, jsonOutput, options) {
7715
9315
  const renderedServerView = renderServerResultView(status.resultView);
7716
9316
  if (result) {
7717
9317
  lines.push(...formatReturnValue(result));
7718
- lines.push(...collectDatasetHandleLines(result));
9318
+ lines.push(...collectDatasetHandleLines(result, "result", datasetStats));
7719
9319
  }
7720
9320
  if (renderedServerView.lines.length > 0) {
7721
9321
  lines.push(...renderedServerView.lines);
7722
9322
  }
7723
9323
  lines.push(...renderedServerView.actions);
7724
- const payload = options?.fullJson ? enrichPlayStatusWithDatasetStats(status) : compactPlayStatus(status);
7725
- printCommandEnvelope({
7726
- ...payload,
7727
- render: {
7728
- sections: [{ title: "run result", lines }]
7729
- }
7730
- }, { json: jsonOutput, text: `${lines.join("\n")}
7731
- ` });
9324
+ const compact = compactPlayStatus(status);
9325
+ const payload = options?.fullJson ? enrichPlayStatusWithDatasetStats(status) : datasetStats ? {
9326
+ ...compact,
9327
+ result: attachDatasetStatsToResult(compact.result, datasetStats)
9328
+ } : compact;
9329
+ printCommandEnvelope(
9330
+ {
9331
+ ...payload,
9332
+ render: {
9333
+ sections: [{ title: "run result", lines }]
9334
+ }
9335
+ },
9336
+ { json: jsonOutput, text: `${lines.join("\n")}
9337
+ ` }
9338
+ );
7732
9339
  }
7733
9340
  async function resolvePlayRunOutputStatus(input) {
7734
- if (!input.fullJson || !getPlayRunPackage(input.status)) {
9341
+ if (!getPlayRunPackage(input.status)) {
7735
9342
  return input.status;
7736
9343
  }
7737
9344
  const runId = input.status.runId;
7738
9345
  if (!runId) {
7739
9346
  return input.status;
7740
9347
  }
7741
- const fullStatus = await input.client.getPlayStatus(runId, {
9348
+ const refreshedStatus = await input.client.getPlayStatus(runId, {
7742
9349
  billing: false,
7743
- full: true
9350
+ full: input.fullJson
7744
9351
  });
7745
9352
  const dashboardUrl = input.status.dashboardUrl;
7746
- return typeof dashboardUrl === "string" ? { ...fullStatus, dashboardUrl } : fullStatus;
9353
+ return typeof dashboardUrl === "string" ? { ...refreshedStatus, dashboardUrl } : refreshedStatus;
7747
9354
  }
7748
9355
  var RUN_EXPORT_PAGE_SIZE = 5e3;
7749
9356
  function shellSingleQuote(value) {
@@ -7753,7 +9360,7 @@ function sqlStringLiteral(value) {
7753
9360
  return `'${value.replace(/'/g, "''")}'`;
7754
9361
  }
7755
9362
  function runExportRetryCommand(runId, outPath, datasetPath) {
7756
- return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote(resolve9(outPath))}`;
9363
+ return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote(resolve10(outPath))}`;
7757
9364
  }
7758
9365
  function extractRunPlayName(status) {
7759
9366
  const run = status.run;
@@ -7787,7 +9394,7 @@ function buildCustomerDbQueryPlan(input) {
7787
9394
  return {
7788
9395
  sql,
7789
9396
  json: `${base} --json`,
7790
- csv: `${base} --format csv --out ${shellSingleQuote(resolve9(input.outPath))}`
9397
+ csv: `${base} --format csv --out ${shellSingleQuote(resolve10(input.outPath))}`
7791
9398
  };
7792
9399
  }
7793
9400
  function exportableSheetRow(row) {
@@ -8087,7 +9694,9 @@ function renderServerResultView(value) {
8087
9694
  (field) => typeof field === "string"
8088
9695
  ) : [];
8089
9696
  if (rawResultFields.length > 0) {
8090
- lines.push(` tool-result columns: ${rawResultFields.join(", ")}`);
9697
+ lines.push(
9698
+ ` tool-result columns: ${rawResultFields.join(", ")}`
9699
+ );
8091
9700
  }
8092
9701
  }
8093
9702
  if (typeof table.slowExportAsCsvCommand === "string") {
@@ -8140,10 +9749,13 @@ function writeStartedPlayRun(input) {
8140
9749
  ` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`
8141
9750
  ];
8142
9751
  if (input.jsonOutput) {
8143
- printCommandEnvelope({
8144
- ...payload,
8145
- render: { sections: [{ title: "play run", lines }] }
8146
- }, { json: true });
9752
+ printCommandEnvelope(
9753
+ {
9754
+ ...payload,
9755
+ render: { sections: [{ title: "play run", lines }] }
9756
+ },
9757
+ { json: true }
9758
+ );
8147
9759
  return;
8148
9760
  }
8149
9761
  if (input.dashboardUrl) {
@@ -8154,11 +9766,14 @@ function writeStartedPlayRun(input) {
8154
9766
  input.progress.writeLine(output, process.stdout);
8155
9767
  return;
8156
9768
  }
8157
- printCommandEnvelope({
8158
- ...payload,
8159
- render: { sections: [{ title: "play run", lines }] }
8160
- }, { json: false, text: `${output}
8161
- ` });
9769
+ printCommandEnvelope(
9770
+ {
9771
+ ...payload,
9772
+ render: { sections: [{ title: "play run", lines }] }
9773
+ },
9774
+ { json: false, text: `${output}
9775
+ ` }
9776
+ );
8162
9777
  }
8163
9778
  function parsePlayRunOptions(args) {
8164
9779
  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.";
@@ -8181,7 +9796,7 @@ function parsePlayRunOptions(args) {
8181
9796
  continue;
8182
9797
  }
8183
9798
  if (arg === "--name" && args[index + 1]) {
8184
- playName = parseReferencedPlayTarget(args[++index]).playName;
9799
+ playName = parseReferencedPlayTarget2(args[++index]).playName;
8185
9800
  continue;
8186
9801
  }
8187
9802
  if ((arg === "--input" || arg === "-i") && args[index + 1]) {
@@ -8211,7 +9826,7 @@ function parsePlayRunOptions(args) {
8211
9826
  );
8212
9827
  }
8213
9828
  if ((arg === "--tail-timeout-ms" || arg === "--timeout-ms") && args[index + 1]) {
8214
- waitTimeoutMs = parsePositiveInteger2(args[++index], arg);
9829
+ waitTimeoutMs = parsePositiveInteger3(args[++index], arg);
8215
9830
  continue;
8216
9831
  }
8217
9832
  if (PLAY_RUN_RESERVED_BOOLEAN_FLAGS.has(arg)) {
@@ -8245,7 +9860,7 @@ function parsePlayRunOptions(args) {
8245
9860
  if (isFileTarget(arg) || looksLikeFilePath(arg)) {
8246
9861
  filePath = arg;
8247
9862
  } else {
8248
- playName = parseReferencedPlayTarget(arg).playName;
9863
+ playName = parseReferencedPlayTarget2(arg).playName;
8249
9864
  }
8250
9865
  continue;
8251
9866
  }
@@ -8294,34 +9909,34 @@ function shouldUseLocalOnlyPlayCheck() {
8294
9909
  const value = process.env.DEEPLINE_PLAY_CHECK_LOCAL_ONLY?.trim().toLowerCase();
8295
9910
  return value === "1" || value === "true" || value === "yes" || value === "on";
8296
9911
  }
8297
- function isRecord3(value) {
9912
+ function isRecord4(value) {
8298
9913
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
8299
9914
  }
8300
- function stringValue(value) {
9915
+ function stringValue2(value) {
8301
9916
  return typeof value === "string" ? value.trim() : "";
8302
9917
  }
8303
9918
  function asArray(value) {
8304
9919
  return Array.isArray(value) ? value : [];
8305
9920
  }
8306
- function extractionEntries(value) {
8307
- if (Array.isArray(value)) return value.filter(isRecord3);
8308
- if (!isRecord3(value)) return [];
9921
+ function extractionEntries2(value) {
9922
+ if (Array.isArray(value)) return value.filter(isRecord4);
9923
+ if (!isRecord4(value)) return [];
8309
9924
  return Object.entries(value).map(
8310
- ([name, entry]) => isRecord3(entry) ? { name, ...entry } : { name }
9925
+ ([name, entry]) => isRecord4(entry) ? { name, ...entry } : { name }
8311
9926
  );
8312
9927
  }
8313
9928
  function firstRawPath(entry) {
8314
- const details = isRecord3(entry.details) ? entry.details : {};
9929
+ const details = isRecord4(entry.details) ? entry.details : {};
8315
9930
  const paths = [
8316
9931
  ...asArray(details.rawToolOutputPaths),
8317
9932
  ...asArray(details.raw_tool_output_paths),
8318
9933
  ...asArray(details.candidatePaths),
8319
9934
  ...asArray(details.candidate_paths)
8320
- ].map(stringValue).filter(Boolean);
9935
+ ].map(stringValue2).filter(Boolean);
8321
9936
  return paths[0];
8322
9937
  }
8323
9938
  function checkHintExpression(value) {
8324
- return stringValue(value).replace(/^toolExecutionResult\./, "result.");
9939
+ return stringValue2(value).replace(/^toolExecutionResult\./, "result.");
8325
9940
  }
8326
9941
  function checkHintRawPath(value) {
8327
9942
  return value?.replace(/^toolResponse\./, "result.toolResponse.");
@@ -8329,14 +9944,14 @@ function checkHintRawPath(value) {
8329
9944
  function collectStaticPipelineToolIds(staticPipeline) {
8330
9945
  const seen = /* @__PURE__ */ new Set();
8331
9946
  const visitPipeline = (pipeline) => {
8332
- if (!isRecord3(pipeline)) return;
9947
+ if (!isRecord4(pipeline)) return;
8333
9948
  for (const step of [
8334
9949
  ...asArray(pipeline.stages),
8335
9950
  ...asArray(pipeline.substeps)
8336
9951
  ]) {
8337
- if (!isRecord3(step)) continue;
9952
+ if (!isRecord4(step)) continue;
8338
9953
  if (step.type === "tool") {
8339
- const toolId = stringValue(step.toolId) || stringValue(step.tool);
9954
+ const toolId = stringValue2(step.toolId) || stringValue2(step.tool);
8340
9955
  if (toolId) seen.add(toolId);
8341
9956
  }
8342
9957
  if (step.type === "play_call") {
@@ -8348,20 +9963,20 @@ function collectStaticPipelineToolIds(staticPipeline) {
8348
9963
  return [...seen].sort();
8349
9964
  }
8350
9965
  function toolGetterHintFromMetadata(toolId, tool) {
8351
- const usageGuidance = isRecord3(tool.usageGuidance) ? tool.usageGuidance : {};
8352
- const resultGuidance = isRecord3(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord3(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
8353
- const toolResponse = isRecord3(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord3(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
8354
- const lists = extractionEntries(
9966
+ const usageGuidance = isRecord4(tool.usageGuidance) ? tool.usageGuidance : {};
9967
+ const resultGuidance = isRecord4(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord4(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
9968
+ const toolResponse = isRecord4(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord4(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
9969
+ const lists = extractionEntries2(
8355
9970
  resultGuidance.extractedLists ?? resultGuidance.extracted_lists
8356
9971
  ).map((entry) => ({
8357
- name: stringValue(entry.name),
9972
+ name: stringValue2(entry.name),
8358
9973
  expression: checkHintExpression(entry.expression),
8359
9974
  raw: checkHintRawPath(firstRawPath(entry))
8360
9975
  })).filter((entry) => entry.name && entry.expression);
8361
- const values = extractionEntries(
9976
+ const values = extractionEntries2(
8362
9977
  resultGuidance.extractedValues ?? resultGuidance.extracted_values
8363
9978
  ).map((entry) => ({
8364
- name: stringValue(entry.name),
9979
+ name: stringValue2(entry.name),
8365
9980
  expression: checkHintExpression(entry.expression),
8366
9981
  raw: checkHintRawPath(firstRawPath(entry))
8367
9982
  })).filter((entry) => entry.name && entry.expression);
@@ -8417,11 +10032,11 @@ function printToolGetterHints(hints) {
8417
10032
  async function handlePlayCheck(args) {
8418
10033
  const options = parsePlayCheckOptions(args);
8419
10034
  if (!isFileTarget(options.target)) {
8420
- const resolved = resolve9(options.target);
10035
+ const resolved = resolve10(options.target);
8421
10036
  console.error(`File not found: ${resolved}`);
8422
10037
  return 1;
8423
10038
  }
8424
- const absolutePlayPath = resolve9(options.target);
10039
+ const absolutePlayPath = resolve10(options.target);
8425
10040
  const sourceCode = readFileSync5(absolutePlayPath, "utf-8");
8426
10041
  let graph;
8427
10042
  try {
@@ -8449,8 +10064,10 @@ async function handlePlayCheck(args) {
8449
10064
  graphHash: graph.root.artifact.graphHash
8450
10065
  };
8451
10066
  if (options.jsonOutput) {
8452
- process.stdout.write(`${JSON.stringify({ name: playName, ...result2 })}
8453
- `);
10067
+ process.stdout.write(
10068
+ `${JSON.stringify({ name: playName, ...result2 })}
10069
+ `
10070
+ );
8454
10071
  } else {
8455
10072
  console.log(`\u2713 ${playName} passed local play check`);
8456
10073
  console.log(` artifact: ${result2.artifactHash.slice(0, 12)}`);
@@ -8474,8 +10091,10 @@ async function handlePlayCheck(args) {
8474
10091
  toolGetterHints: result.toolGetterHints ?? await buildToolGetterHints(client, result.staticPipeline)
8475
10092
  };
8476
10093
  if (options.jsonOutput) {
8477
- process.stdout.write(`${JSON.stringify({ name: playName, ...enrichedResult })}
8478
- `);
10094
+ process.stdout.write(
10095
+ `${JSON.stringify({ name: playName, ...enrichedResult })}
10096
+ `
10097
+ );
8479
10098
  } else if (enrichedResult.valid) {
8480
10099
  console.log(`\u2713 ${playName} passed cloud play check`);
8481
10100
  if (enrichedResult.artifactHash) {
@@ -8497,7 +10116,7 @@ async function handleFileBackedRun(options) {
8497
10116
  }
8498
10117
  const client = new DeeplineClient();
8499
10118
  const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
8500
- const absolutePlayPath = resolve9(options.target.path);
10119
+ const absolutePlayPath = resolve10(options.target.path);
8501
10120
  progress.phase("compiling play");
8502
10121
  const sourceCode = traceCliSync(
8503
10122
  "cli.play_file_read_source",
@@ -8786,7 +10405,7 @@ async function handlePlayRun(args) {
8786
10405
  if (isFileTarget(options.target.path)) {
8787
10406
  return handleFileBackedRun(options);
8788
10407
  }
8789
- const resolved = resolve9(options.target.path);
10408
+ const resolved = resolve10(options.target.path);
8790
10409
  console.error(`File not found: ${resolved}`);
8791
10410
  const dir = dirname8(resolved);
8792
10411
  if (existsSync6(dir)) {
@@ -8852,7 +10471,7 @@ async function handleRunsList(args) {
8852
10471
  for (let index = 0; index < args.length; index += 1) {
8853
10472
  const arg = args[index];
8854
10473
  if ((arg === "--play" || arg === "--name") && args[index + 1]) {
8855
- playName = parseReferencedPlayTarget(args[++index]).playName;
10474
+ playName = parseReferencedPlayTarget2(args[++index]).playName;
8856
10475
  continue;
8857
10476
  }
8858
10477
  if (arg === "--status" && args[index + 1]) {
@@ -8881,15 +10500,20 @@ async function handleRunsList(args) {
8881
10500
  executionTime: run.executionTime,
8882
10501
  playName: run.memo?.playName ?? playName
8883
10502
  }));
8884
- const lines = runs.length === 0 ? [`No runs found for ${playName}.`] : runs.map((run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)}`);
8885
- printCommandEnvelope({
8886
- runs,
8887
- count: runs.length,
8888
- next: {
8889
- get: runs[0]?.runId ? `deepline runs get ${runs[0].runId} --json` : null
10503
+ const lines = runs.length === 0 ? [`No runs found for ${playName}.`] : runs.map(
10504
+ (run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)}`
10505
+ );
10506
+ printCommandEnvelope(
10507
+ {
10508
+ runs,
10509
+ count: runs.length,
10510
+ next: {
10511
+ get: runs[0]?.runId ? `deepline runs get ${runs[0].runId} --json` : null
10512
+ },
10513
+ render: { sections: [{ title: "runs", lines }] }
8890
10514
  },
8891
- render: { sections: [{ title: "runs", lines }] }
8892
- }, { json: argsWantJson(args) });
10515
+ { json: argsWantJson(args) }
10516
+ );
8893
10517
  return 0;
8894
10518
  }
8895
10519
  async function handleRunTail(args) {
@@ -8904,7 +10528,9 @@ async function handleRunTail(args) {
8904
10528
  for (let index = 0; index < args.length; index += 1) {
8905
10529
  const arg = args[index];
8906
10530
  if (arg === "--cursor") {
8907
- console.error("--cursor was removed. deepline runs tail reads the canonical run stream.");
10531
+ console.error(
10532
+ "--cursor was removed. deepline runs tail reads the canonical run stream."
10533
+ );
8908
10534
  return 1;
8909
10535
  }
8910
10536
  if (arg.startsWith("--") && arg !== "--json" && arg !== "--compact") {
@@ -8931,11 +10557,11 @@ async function handleRunLogs(args) {
8931
10557
  for (let index = 0; index < args.length; index += 1) {
8932
10558
  const arg = args[index];
8933
10559
  if (arg === "--limit" && args[index + 1]) {
8934
- limit = parsePositiveInteger2(args[++index], "--limit");
10560
+ limit = parsePositiveInteger3(args[++index], "--limit");
8935
10561
  continue;
8936
10562
  }
8937
10563
  if (arg === "--out" && args[index + 1]) {
8938
- outPath = resolve9(args[++index]);
10564
+ outPath = resolve10(args[++index]);
8939
10565
  }
8940
10566
  }
8941
10567
  const client = new DeeplineClient();
@@ -8943,30 +10569,46 @@ async function handleRunLogs(args) {
8943
10569
  const logs = status.progress?.logs ?? [];
8944
10570
  if (outPath) {
8945
10571
  writeFileSync6(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
8946
- printCommandEnvelope({
8947
- runId: status.runId,
8948
- log_path: outPath,
8949
- lineCount: logs.length,
8950
- local: { log_path: outPath },
8951
- render: { sections: [{ title: "run logs", lines: [`Wrote ${logs.length} log lines to ${outPath}`] }] }
8952
- }, { json: argsWantJson(args) });
10572
+ printCommandEnvelope(
10573
+ {
10574
+ runId: status.runId,
10575
+ log_path: outPath,
10576
+ lineCount: logs.length,
10577
+ local: { log_path: outPath },
10578
+ render: {
10579
+ sections: [
10580
+ {
10581
+ title: "run logs",
10582
+ lines: [`Wrote ${logs.length} log lines to ${outPath}`]
10583
+ }
10584
+ ]
10585
+ }
10586
+ },
10587
+ { json: argsWantJson(args) }
10588
+ );
8953
10589
  return 0;
8954
10590
  }
8955
10591
  const entries = logs.slice(Math.max(0, logs.length - limit));
8956
- printCommandEnvelope({
8957
- runId: status.runId,
8958
- totalCount: logs.length,
8959
- returnedCount: entries.length,
8960
- firstSequence: logs.length === 0 ? null : logs.length - entries.length + 1,
8961
- lastSequence: logs.length === 0 ? null : logs.length,
8962
- truncated: logs.length > entries.length,
8963
- hasMore: logs.length > entries.length,
8964
- entries,
8965
- next: {
8966
- export: `deepline runs logs ${status.runId} --out run.log --json`
10592
+ printCommandEnvelope(
10593
+ {
10594
+ runId: status.runId,
10595
+ totalCount: logs.length,
10596
+ returnedCount: entries.length,
10597
+ firstSequence: logs.length === 0 ? null : logs.length - entries.length + 1,
10598
+ lastSequence: logs.length === 0 ? null : logs.length,
10599
+ truncated: logs.length > entries.length,
10600
+ hasMore: logs.length > entries.length,
10601
+ entries,
10602
+ next: {
10603
+ export: `deepline runs logs ${status.runId} --out run.log --json`
10604
+ },
10605
+ render: { sections: [{ title: "run logs", lines: entries }] }
8967
10606
  },
8968
- render: { sections: [{ title: "run logs", lines: entries }] }
8969
- }, { json: argsWantJson(args), text: `${entries.join("\n")}${entries.length > 0 ? "\n" : ""}` });
10607
+ {
10608
+ json: argsWantJson(args),
10609
+ text: `${entries.join("\n")}${entries.length > 0 ? "\n" : ""}`
10610
+ }
10611
+ );
8970
10612
  return 0;
8971
10613
  }
8972
10614
  async function handleRunStop(args) {
@@ -8991,10 +10633,13 @@ async function handleRunStop(args) {
8991
10633
  `Stopped ${result.runId}`,
8992
10634
  ...result.hitlCancelledCount > 0 ? [`cancelled HITL waits: ${result.hitlCancelledCount}`] : []
8993
10635
  ];
8994
- printCommandEnvelope({
8995
- ...result,
8996
- render: { sections: [{ title: "run stop", lines }] }
8997
- }, { json: argsWantJson(args) });
10636
+ printCommandEnvelope(
10637
+ {
10638
+ ...result,
10639
+ render: { sections: [{ title: "run stop", lines }] }
10640
+ },
10641
+ { json: argsWantJson(args) }
10642
+ );
8998
10643
  return 0;
8999
10644
  }
9000
10645
  async function handleRunExport(args) {
@@ -9012,7 +10657,7 @@ async function handleRunExport(args) {
9012
10657
  for (let index = 0; index < args.length; index += 1) {
9013
10658
  const arg = args[index];
9014
10659
  if (arg === "--out" && args[index + 1]) {
9015
- outPath = resolve9(args[++index]);
10660
+ outPath = resolve10(args[++index]);
9016
10661
  continue;
9017
10662
  }
9018
10663
  if (arg === "--dataset" && args[index + 1]) {
@@ -9020,7 +10665,7 @@ async function handleRunExport(args) {
9020
10665
  continue;
9021
10666
  }
9022
10667
  if (arg === "--metadata-out" && args[index + 1]) {
9023
- metadataOutPath = resolve9(args[++index]);
10668
+ metadataOutPath = resolve10(args[++index]);
9024
10669
  }
9025
10670
  }
9026
10671
  if (!outPath) {
@@ -9107,10 +10752,10 @@ async function handlePlayGet(args) {
9107
10752
  for (let index = 1; index < args.length; index += 1) {
9108
10753
  const arg = args[index];
9109
10754
  if (arg === "--out" && args[index + 1]) {
9110
- outPath = resolve9(args[++index]);
10755
+ outPath = resolve10(args[++index]);
9111
10756
  }
9112
10757
  }
9113
- const playName = isFileTarget(target) ? extractPlayName(readFileSync5(resolve9(target), "utf-8"), resolve9(target)) : parseReferencedPlayTarget(target).playName;
10758
+ const playName = isFileTarget(target) ? extractPlayName(readFileSync5(resolve10(target), "utf-8"), resolve10(target)) : parseReferencedPlayTarget2(target).playName;
9114
10759
  const detail = isFileTarget(target) ? await client.getPlay(playName) : await assertCanonicalNamedPlayReference(client, target);
9115
10760
  const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
9116
10761
  const materializedFile = outPath ? materializeRemotePlaySource({
@@ -9195,7 +10840,7 @@ async function handlePlayVersions(args) {
9195
10840
  const jsonOutput = argsWantJson(args);
9196
10841
  await assertCanonicalNamedPlayReference(client, playName);
9197
10842
  const versions = await client.listPlayVersions(
9198
- parseReferencedPlayTarget(playName).playName
10843
+ parseReferencedPlayTarget2(playName).playName
9199
10844
  );
9200
10845
  if (jsonOutput) {
9201
10846
  process.stdout.write(`${JSON.stringify({ versions })}
@@ -9213,20 +10858,8 @@ async function handlePlayVersions(args) {
9213
10858
  }
9214
10859
  async function handlePlayList(args) {
9215
10860
  const jsonOutput = argsWantJson(args);
9216
- const originArgIndex = args.findIndex((arg) => arg === "--origin");
9217
- const rawOrigin = originArgIndex >= 0 ? args[originArgIndex + 1] : void 0;
9218
- if (rawOrigin && rawOrigin !== "prebuilt" && rawOrigin !== "owned") {
9219
- throw new Error(`Invalid value for --origin: ${rawOrigin}`);
9220
- }
9221
- const origin = rawOrigin;
9222
10861
  const client = new DeeplineClient();
9223
- const plays = (await client.listPlays({
9224
- ...origin ? { origin } : {}
9225
- })).filter((play) => {
9226
- if (!origin) return true;
9227
- const isPrebuilt = play.origin === "prebuilt" || play.ownerType === "deepline";
9228
- return origin === "prebuilt" ? isPrebuilt : !isPrebuilt;
9229
- });
10862
+ const plays = await client.listPlays();
9230
10863
  if (jsonOutput) {
9231
10864
  process.stdout.write(`${JSON.stringify(plays)}
9232
10865
  `);
@@ -9329,7 +10962,8 @@ function compactPlaySchema(schema) {
9329
10962
  return fields.length > 0 ? { fields } : schema;
9330
10963
  }
9331
10964
  function playSchemaMetadata(schema, key) {
9332
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) return null;
10965
+ if (!schema || typeof schema !== "object" || Array.isArray(schema))
10966
+ return null;
9333
10967
  const value = schema[key];
9334
10968
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
9335
10969
  }
@@ -9344,7 +10978,10 @@ function playRunCommand(play, options) {
9344
10978
  function summarizePlayListItemForCli(play, options) {
9345
10979
  const aliases = play.aliases?.length ? play.aliases : [play.name];
9346
10980
  const csvInput = playSchemaMetadata(play.inputSchema, "csvInput");
9347
- const rowOutputSchema = playSchemaMetadata(play.outputSchema, "rowOutputSchema");
10981
+ const rowOutputSchema = playSchemaMetadata(
10982
+ play.outputSchema,
10983
+ "rowOutputSchema"
10984
+ );
9348
10985
  const runCommand2 = playRunCommand(play, { csvInput });
9349
10986
  const cloneEditStarter = buildCloneEditStarter(play);
9350
10987
  return {
@@ -9494,7 +11131,7 @@ async function handlePlayDescribe(args) {
9494
11131
  const client = new DeeplineClient();
9495
11132
  await assertCanonicalNamedPlayReference(client, playName);
9496
11133
  const play = await client.describePlay(
9497
- parseReferencedPlayTarget(playName).playName,
11134
+ parseReferencedPlayTarget2(playName).playName,
9498
11135
  {
9499
11136
  compact: args.includes("--compact")
9500
11137
  }
@@ -9540,7 +11177,7 @@ async function handlePlayPublish(args) {
9540
11177
  }
9541
11178
  let graph;
9542
11179
  try {
9543
- graph = await collectBundledPlayGraph(resolve9(playName));
11180
+ graph = await collectBundledPlayGraph(resolve10(playName));
9544
11181
  await compileBundledPlayGraphManifests(client, graph);
9545
11182
  await publishImportedPlayDependencies(client, graph);
9546
11183
  } catch (error) {
@@ -9569,7 +11206,7 @@ async function handlePlayPublish(args) {
9569
11206
  );
9570
11207
  return 0;
9571
11208
  }
9572
- const resolvedName = parseReferencedPlayTarget(playName).playName;
11209
+ const resolvedName = parseReferencedPlayTarget2(playName).playName;
9573
11210
  if (useLatest) {
9574
11211
  const versions = await client.listPlayVersions(resolvedName);
9575
11212
  const latest = versions[0];
@@ -9609,17 +11246,19 @@ async function handlePlayDelete(args) {
9609
11246
  const client = new DeeplineClient();
9610
11247
  let detail;
9611
11248
  try {
9612
- detail = await client.getPlay(parseReferencedPlayTarget(playName).playName);
11249
+ detail = await client.getPlay(parseReferencedPlayTarget2(playName).playName);
9613
11250
  } catch (error) {
9614
11251
  console.error(error instanceof Error ? error.message : String(error));
9615
11252
  return 1;
9616
11253
  }
9617
11254
  if (detail.play.ownerType === "deepline" || detail.play.origin === "prebuilt") {
9618
- console.error(`Cannot delete prebuilt play: ${formatPlayReference(detail.play)}`);
11255
+ console.error(
11256
+ `Cannot delete prebuilt play: ${formatPlayReference(detail.play)}`
11257
+ );
9619
11258
  return 1;
9620
11259
  }
9621
11260
  const result = await client.deletePlay(
9622
- parseReferencedPlayTarget(formatPlayReference(detail.play)).playName
11261
+ parseReferencedPlayTarget2(formatPlayReference(detail.play)).playName
9623
11262
  );
9624
11263
  if (argsWantJson(args)) {
9625
11264
  process.stdout.write(`${JSON.stringify(result)}
@@ -9764,6 +11403,7 @@ Pass-through input flags:
9764
11403
  ...passthroughArgs
9765
11404
  ]);
9766
11405
  });
11406
+ registerPlayBootstrapCommand(play);
9767
11407
  play.command("get <target>").description("Fetch full play details.").addHelpText(
9768
11408
  "after",
9769
11409
  `
@@ -9778,7 +11418,10 @@ Examples:
9778
11418
  deepline plays get prebuilt/name-and-domain-to-email-waterfall-batch --source > email-waterfall.play.ts
9779
11419
  deepline plays get prebuilt/name-and-domain-to-email-waterfall-batch --source --out ./email-waterfall.play.ts
9780
11420
  `
9781
- ).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) => {
11421
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
11422
+ "--source",
11423
+ "Print raw source code; combine with --out to write a file"
11424
+ ).option("--out <path>", "Write source to a specific path").action(async (target, options) => {
9782
11425
  process.exitCode = await handlePlayGet([
9783
11426
  target,
9784
11427
  ...options.json ? ["--json"] : [],
@@ -9795,12 +11438,10 @@ Notes:
9795
11438
 
9796
11439
  Examples:
9797
11440
  deepline plays list
9798
- deepline plays list --origin prebuilt --json
9799
11441
  deepline plays search email --json
9800
11442
  `
9801
- ).option("--origin <origin>", "Filter to prebuilt or owned plays").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
11443
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
9802
11444
  process.exitCode = await handlePlayList([
9803
- ...options.origin ? ["--origin", options.origin] : [],
9804
11445
  ...options.json ? ["--json"] : []
9805
11446
  ]);
9806
11447
  });
@@ -9825,7 +11466,9 @@ Examples:
9825
11466
  ]);
9826
11467
  });
9827
11468
  addPlaySearchCommand(play.command("search <query>"));
9828
- play.command("grep <query>").description("Literal grep over play names, aliases, schemas, and descriptions.").addHelpText(
11469
+ play.command("grep <query>").description(
11470
+ "Literal grep over play names, aliases, schemas, and descriptions."
11471
+ ).addHelpText(
9829
11472
  "after",
9830
11473
  `
9831
11474
  Notes:
@@ -9911,7 +11554,9 @@ Examples:
9911
11554
  ]);
9912
11555
  });
9913
11556
  addPublishHelp(
9914
- play.command("set-live <target>").description("Promote a local file or saved revision as the live play revision.")
11557
+ play.command("set-live <target>").description(
11558
+ "Promote a local file or saved revision as the live play revision."
11559
+ )
9915
11560
  ).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) => {
9916
11561
  process.exitCode = await handlePlayPublish([
9917
11562
  target,
@@ -9956,7 +11601,9 @@ Examples:
9956
11601
  deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
9957
11602
  `
9958
11603
  );
9959
- runs.command("get <runId>").description("Get status, progress, result, errors, and recovery metadata for a play run.").addHelpText(
11604
+ runs.command("get <runId>").description(
11605
+ "Get status, progress, result, errors, and recovery metadata for a play run."
11606
+ ).addHelpText(
9960
11607
  "after",
9961
11608
  `
9962
11609
  Notes:
@@ -10024,7 +11671,11 @@ Examples:
10024
11671
  deepline runs logs play/my-play/run/20260501t000000-000 --limit 500
10025
11672
  deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
10026
11673
  `
10027
- ).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) => {
11674
+ ).option(
11675
+ "--limit <count>",
11676
+ "Maximum recent log lines to print without --out",
11677
+ "200"
11678
+ ).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) => {
10028
11679
  process.exitCode = await handleRunLogs([
10029
11680
  runId,
10030
11681
  ...options.limit ? ["--limit", options.limit] : [],
@@ -10065,7 +11716,10 @@ Examples:
10065
11716
  deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --metadata-out output.meta.json
10066
11717
  deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --json
10067
11718
  `
10068
- ).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) => {
11719
+ ).requiredOption("--out <path>", "Output CSV path").option(
11720
+ "--dataset <path>",
11721
+ "Returned dataset handle path, such as result.rows"
11722
+ ).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) => {
10069
11723
  process.exitCode = await handleRunExport([
10070
11724
  runId,
10071
11725
  ...options.dataset ? ["--dataset", options.dataset] : [],
@@ -10293,11 +11947,14 @@ async function listTools(args) {
10293
11947
  const client = new DeeplineClient();
10294
11948
  const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
10295
11949
  const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
11950
+ const compact = args.includes("--compact");
10296
11951
  const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
10297
11952
  const items = (await client.listTools({
10298
11953
  ...categoryFilter ? { categories: categoryFilter } : {}
10299
11954
  })).map(toListedTool).filter(
10300
- (item) => requestedCategories.length === 0 || requestedCategories.some((category) => item.categories.includes(category))
11955
+ (item) => requestedCategories.length === 0 || requestedCategories.some(
11956
+ (category) => item.categories.includes(category)
11957
+ )
10301
11958
  );
10302
11959
  const render = {
10303
11960
  sections: [
@@ -10317,10 +11974,11 @@ async function listTools(args) {
10317
11974
  }
10318
11975
  ]
10319
11976
  };
11977
+ const outputItems = compact ? items.map(compactTool) : items;
10320
11978
  printCommandEnvelope(
10321
11979
  {
10322
- tools: items,
10323
- count: items.length,
11980
+ tools: outputItems,
11981
+ count: outputItems.length,
10324
11982
  filters: {
10325
11983
  categories: requestedCategories
10326
11984
  },
@@ -10345,7 +12003,11 @@ async function searchTools(queryInput, options = {}) {
10345
12003
  searchMode: options.searchMode,
10346
12004
  includeSearchDebug: options.includeSearchDebug
10347
12005
  });
10348
- printCommandEnvelope(result, {
12006
+ const payload = options.compact && Array.isArray(result.tools) ? {
12007
+ ...result,
12008
+ tools: result.tools.map(compactTool)
12009
+ } : result;
12010
+ printCommandEnvelope(payload, {
10349
12011
  json: options.json || shouldEmitJson()
10350
12012
  });
10351
12013
  return 0;
@@ -10364,7 +12026,9 @@ async function grepTools(queryInput, options = {}) {
10364
12026
  grepMode: mode,
10365
12027
  ...options.categories ? { categories: options.categories } : {}
10366
12028
  })).map(toListedTool).filter(
10367
- (item) => requestedCategories.length === 0 || requestedCategories.some((category) => item.categories.includes(category))
12029
+ (item) => requestedCategories.length === 0 || requestedCategories.some(
12030
+ (category) => item.categories.includes(category)
12031
+ )
10368
12032
  ).filter(
10369
12033
  (item) => matchesGrepQuery(
10370
12034
  {
@@ -10382,10 +12046,11 @@ async function grepTools(queryInput, options = {}) {
10382
12046
  mode
10383
12047
  )
10384
12048
  );
12049
+ const outputTools = options.compact ? tools.map(compactTool) : tools;
10385
12050
  printCommandEnvelope(
10386
12051
  {
10387
- tools,
10388
- count: tools.length,
12052
+ tools: outputTools,
12053
+ count: outputTools.length,
10389
12054
  query,
10390
12055
  grep: {
10391
12056
  mode,
@@ -10400,6 +12065,19 @@ async function grepTools(queryInput, options = {}) {
10400
12065
  );
10401
12066
  return 0;
10402
12067
  }
12068
+ function compactTool(tool) {
12069
+ const listed = toListedTool(tool);
12070
+ return {
12071
+ id: listed.id,
12072
+ toolId: listed.toolId,
12073
+ provider: listed.provider,
12074
+ displayName: listed.displayName,
12075
+ description: listed.description,
12076
+ categories: listed.categories,
12077
+ type: listed.type,
12078
+ executeCommand: listed.executeCommand
12079
+ };
12080
+ }
10403
12081
  function playIdentifiers(play) {
10404
12082
  return [play.name, play.reference, ...play.aliases ?? []].filter((value) => Boolean(value?.trim())).map((value) => value.trim());
10405
12083
  }
@@ -10472,9 +12150,13 @@ Examples:
10472
12150
  deepline tools list --categories email_finder --json
10473
12151
  deepline tools search email --json
10474
12152
  `
10475
- ).option("--categories <categories>", "Comma-separated categories to filter inventory").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
12153
+ ).option(
12154
+ "--categories <categories>",
12155
+ "Comma-separated categories to filter inventory"
12156
+ ).option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
10476
12157
  process.exitCode = await listTools([
10477
12158
  ...options.categories ? ["--categories", options.categories] : [],
12159
+ ...options.compact ? ["--compact"] : [],
10478
12160
  ...options.json ? ["--json"] : []
10479
12161
  ]);
10480
12162
  });
@@ -10492,9 +12174,19 @@ Examples:
10492
12174
  deepline tools grep "company enrichment" --categories enrichment --json
10493
12175
  deepline tools search verifier --search-mode v2 --json
10494
12176
  `
10495
- ).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) => {
12177
+ ).option(
12178
+ "--categories <categories>",
12179
+ "Comma-separated categories to filter ranked search"
12180
+ ).option(
12181
+ "--search_terms <terms>",
12182
+ "Structured search terms for ranked search"
12183
+ ).option(
12184
+ "--search-terms <terms>",
12185
+ "Structured search terms for ranked search"
12186
+ ).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) => {
10496
12187
  process.exitCode = await searchTools(query, {
10497
12188
  json: options.json,
12189
+ compact: options.compact,
10498
12190
  categories: options.categories,
10499
12191
  searchTerms: options.searchTerms ?? options.search_terms,
10500
12192
  searchMode: options.searchMode === "v1" || options.searchMode === "v2" ? options.searchMode : void 0,
@@ -10502,7 +12194,9 @@ Examples:
10502
12194
  });
10503
12195
  });
10504
12196
  addToolSearchCommand(tools.command("search <query>"));
10505
- tools.command("grep <query>").description("Literal grep over tool ids, descriptions, categories, and input fields.").addHelpText(
12197
+ tools.command("grep <query>").description(
12198
+ "Literal grep over tool ids, descriptions, categories, and input fields."
12199
+ ).addHelpText(
10506
12200
  "after",
10507
12201
  `
10508
12202
  Notes:
@@ -10516,10 +12210,14 @@ Examples:
10516
12210
  deepline tools grep "phone validate" --mode all --json
10517
12211
  deepline tools grep hunter --mode phrase --json
10518
12212
  `
10519
- ).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) => {
12213
+ ).option(
12214
+ "--categories <categories>",
12215
+ "Comma-separated categories to filter inventory"
12216
+ ).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) => {
10520
12217
  const mode = options.mode === "any" || options.mode === "phrase" ? options.mode : "all";
10521
12218
  process.exitCode = await grepTools(query, {
10522
12219
  json: options.json,
12220
+ compact: options.compact,
10523
12221
  categories: options.categories,
10524
12222
  mode
10525
12223
  });
@@ -10540,7 +12238,20 @@ Examples:
10540
12238
  deepline tools describe hunter_email_verifier --json
10541
12239
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
10542
12240
  `
10543
- ).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 Option("--compact", "Compatibility alias for the default compact view").hideHelp()).addOption(new Option("--contract-json", "Compatibility alias for compact contract JSON").hideHelp()).action(async (toolId, options) => {
12241
+ ).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(
12242
+ "--examples-only",
12243
+ "Only print runnable examples and sample payloads"
12244
+ ).option("--getters-only", "Only print extracted list/value getters").addOption(
12245
+ new Option(
12246
+ "--compact",
12247
+ "Compatibility alias for the default compact view"
12248
+ ).hideHelp()
12249
+ ).addOption(
12250
+ new Option(
12251
+ "--contract-json",
12252
+ "Compatibility alias for compact contract JSON"
12253
+ ).hideHelp()
12254
+ ).action(async (toolId, options) => {
10544
12255
  process.exitCode = await getTool(toolId, {
10545
12256
  json: Boolean(options.json),
10546
12257
  compact: Boolean(options.compact),
@@ -10582,13 +12293,24 @@ Examples:
10582
12293
  deepline tools execute hunter_email_verifier -p email=a@b.com
10583
12294
  deepline tools execute test_rate_limit --input '{"key":"smoke"}' --json | jq '.status'
10584
12295
  `
10585
- ).option("-p, --param <key=value>", "Pass one parameter. Repeat for multiple values.", (value, acc) => {
10586
- acc.push(value);
10587
- return acc;
10588
- }, []).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(
12296
+ ).option(
12297
+ "-p, --param <key=value>",
12298
+ "Pass one parameter. Repeat for multiple values.",
12299
+ (value, acc) => {
12300
+ acc.push(value);
12301
+ return acc;
12302
+ },
12303
+ []
12304
+ ).option(
12305
+ "--json [payload]",
12306
+ "Emit JSON output. Use `--input` or `--payload` for passing JSON params."
12307
+ ).option("--input <payload>", "Merge a JSON object into the tool params").option("--payload <payload>", "Merge a JSON object into the tool params").option(
10589
12308
  "--output-format <format>",
10590
12309
  "Output format: auto, csv, csv_file, json, or json_file"
10591
- ).option("--no-preview", "Only print the extracted output path when applicable").action(async (toolId, options) => {
12310
+ ).option(
12311
+ "--no-preview",
12312
+ "Only print the extracted output path when applicable"
12313
+ ).action(async (toolId, options) => {
10592
12314
  const args = [
10593
12315
  toolId,
10594
12316
  ...options.param.flatMap((value) => ["--param", value]),
@@ -10620,14 +12342,18 @@ async function getTool(toolId, options = {}) {
10620
12342
  throw error;
10621
12343
  }
10622
12344
  if (options.contractJson) {
10623
- process.stdout.write(`${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
10624
- `);
12345
+ process.stdout.write(
12346
+ `${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
12347
+ `
12348
+ );
10625
12349
  return 0;
10626
12350
  }
10627
12351
  const emitJson = options.json === true;
10628
12352
  if (emitJson) {
10629
- process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
10630
- `);
12353
+ process.stdout.write(
12354
+ `${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
12355
+ `
12356
+ );
10631
12357
  return 0;
10632
12358
  }
10633
12359
  const onlyModes = [
@@ -10637,7 +12363,9 @@ async function getTool(toolId, options = {}) {
10637
12363
  options.gettersOnly
10638
12364
  ].filter(Boolean).length;
10639
12365
  if (onlyModes > 1) {
10640
- console.error("Use only one of --pricing-only, --schema-only, --examples-only, or --getters-only.");
12366
+ console.error(
12367
+ "Use only one of --pricing-only, --schema-only, --examples-only, or --getters-only."
12368
+ );
10641
12369
  return 2;
10642
12370
  }
10643
12371
  if (options.pricingOnly) {
@@ -10661,8 +12389,10 @@ async function getTool(toolId, options = {}) {
10661
12389
  return 0;
10662
12390
  }
10663
12391
  if (shouldEmitJson()) {
10664
- process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
10665
- `);
12392
+ process.stdout.write(
12393
+ `${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
12394
+ `
12395
+ );
10666
12396
  return 0;
10667
12397
  }
10668
12398
  printCompactToolContract(tool, toolId);
@@ -10670,9 +12400,15 @@ async function getTool(toolId, options = {}) {
10670
12400
  }
10671
12401
  function toolContractJsonForDescribe(tool, requestedToolId) {
10672
12402
  const toolId = String(tool.toolId || requestedToolId);
10673
- const inputFields = toolInputFieldsForDisplay(recordField(tool, "inputSchema", "input_schema"));
12403
+ const inputFields = toolInputFieldsForDisplay(
12404
+ recordField(tool, "inputSchema", "input_schema")
12405
+ );
10674
12406
  const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
10675
- const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
12407
+ const toolExecutionResult = recordField(
12408
+ usageGuidance,
12409
+ "toolExecutionResult",
12410
+ "tool_execution_result"
12411
+ );
10676
12412
  const extractedLists = extractionContractEntries(
10677
12413
  arrayField(toolExecutionResult, "extractedLists", "extracted_lists")
10678
12414
  );
@@ -10725,7 +12461,7 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
10725
12461
  }
10726
12462
  function extractionContractEntries(entries) {
10727
12463
  return entries.flatMap((entry) => {
10728
- if (!isRecord4(entry)) return [];
12464
+ if (!isRecord5(entry)) return [];
10729
12465
  const name = stringField(entry, "name");
10730
12466
  const expression = stringField(entry, "expression");
10731
12467
  return name && expression ? [{ name, expression }] : [];
@@ -10733,8 +12469,8 @@ function extractionContractEntries(entries) {
10733
12469
  }
10734
12470
  function printCompactToolContract(tool, requestedToolId) {
10735
12471
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
10736
- const cost = isRecord4(contract.cost) ? contract.cost : {};
10737
- const getters = isRecord4(contract.getters) ? contract.getters : {};
12472
+ const cost = isRecord5(contract.cost) ? contract.cost : {};
12473
+ const getters = isRecord5(contract.getters) ? contract.getters : {};
10738
12474
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
10739
12475
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
10740
12476
  const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
@@ -10751,18 +12487,20 @@ function printCompactToolContract(tool, requestedToolId) {
10751
12487
  console.log("");
10752
12488
  console.log("Inputs:");
10753
12489
  for (const field of inputFields) {
10754
- if (!isRecord4(field)) continue;
12490
+ if (!isRecord5(field)) continue;
10755
12491
  const name = stringField(field, "name");
10756
12492
  if (!name) continue;
10757
12493
  const required = field.required ? "*" : "";
10758
12494
  const type = stringField(field, "type") || "unknown";
10759
12495
  const description = stringField(field, "description");
10760
- console.log(`- ${name}${required}: ${type}${description ? ` - ${description}` : ""}`);
12496
+ console.log(
12497
+ `- ${name}${required}: ${type}${description ? ` - ${description}` : ""}`
12498
+ );
10761
12499
  }
10762
12500
  }
10763
12501
  console.log("");
10764
12502
  printToolExamplesOnly(tool, requestedToolId, { includeSamples: false });
10765
- const starterScript = isRecord4(contract.starterScript) ? contract.starterScript : {};
12503
+ const starterScript = isRecord5(contract.starterScript) ? contract.starterScript : {};
10766
12504
  const starterPath = stringField(starterScript, "path");
10767
12505
  if (starterPath) {
10768
12506
  console.log("");
@@ -10774,19 +12512,27 @@ function printCompactToolContract(tool, requestedToolId) {
10774
12512
  console.log("Getters:");
10775
12513
  if (listGetters.length) console.log("Lists:");
10776
12514
  for (const entry of listGetters) {
10777
- if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
12515
+ if (isRecord5(entry))
12516
+ console.log(
12517
+ `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
12518
+ );
10778
12519
  }
10779
12520
  if (valueGetters.length) console.log("Values:");
10780
12521
  for (const entry of valueGetters) {
10781
- if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
12522
+ if (isRecord5(entry))
12523
+ console.log(
12524
+ `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
12525
+ );
10782
12526
  }
10783
12527
  }
10784
12528
  console.log("");
10785
- console.log(`More: deepline tools describe ${contract.toolId} --pricing-only | --schema-only | --examples-only | --getters-only | --json`);
12529
+ console.log(
12530
+ `More: deepline tools describe ${contract.toolId} --pricing-only | --schema-only | --examples-only | --getters-only | --json`
12531
+ );
10786
12532
  }
10787
12533
  function printToolPricingOnly(tool, requestedToolId, options = {}) {
10788
12534
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
10789
- const cost = isRecord4(contract.cost) ? contract.cost : {};
12535
+ const cost = isRecord5(contract.cost) ? contract.cost : {};
10790
12536
  const pricingModel = stringField(cost, "pricingModel") || "unknown";
10791
12537
  const billingMode = stringField(cost, "billingMode") || "unknown";
10792
12538
  const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : pricingModel === "fixed" ? "call" : pricingModel.replace(/^per_/, "") || "unit";
@@ -10806,14 +12552,16 @@ function printToolSchemaOnly(tool, requestedToolId) {
10806
12552
  }
10807
12553
  console.log("Inputs:");
10808
12554
  for (const field of inputFields) {
10809
- if (!isRecord4(field)) continue;
12555
+ if (!isRecord5(field)) continue;
10810
12556
  const name = stringField(field, "name");
10811
12557
  if (!name) continue;
10812
12558
  const required = field.required ? "*" : "";
10813
12559
  const type = stringField(field, "type") || "unknown";
10814
12560
  const description = stringField(field, "description");
10815
12561
  const defaultSuffix = Object.prototype.hasOwnProperty.call(field, "default") ? ` default=${JSON.stringify(field.default)}` : "";
10816
- console.log(`- ${name}${required}: ${type}${defaultSuffix}${description ? ` - ${description}` : ""}`);
12562
+ console.log(
12563
+ `- ${name}${required}: ${type}${defaultSuffix}${description ? ` - ${description}` : ""}`
12564
+ );
10817
12565
  }
10818
12566
  }
10819
12567
  function printToolExamplesOnly(tool, requestedToolId, options = {}) {
@@ -10826,16 +12574,21 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
10826
12574
  console.log("const result = await ctx.tools.execute({");
10827
12575
  console.log(` id: '${stableStepIdForTool(toolId)}',`);
10828
12576
  console.log(` tool: '${toolId}',`);
10829
- console.log(` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`);
12577
+ console.log(
12578
+ ` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`
12579
+ );
10830
12580
  console.log("});");
10831
- const getters = isRecord4(contract.getters) ? contract.getters : {};
12581
+ const getters = isRecord5(contract.getters) ? contract.getters : {};
10832
12582
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
10833
12583
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
10834
- const firstGetter = [...valueGetters, ...listGetters].find(isRecord4);
12584
+ const firstGetter = [...valueGetters, ...listGetters].find(isRecord5);
10835
12585
  if (firstGetter) {
10836
12586
  const name = stringField(firstGetter, "name") || "value";
10837
12587
  const expression = stringField(firstGetter, "expression");
10838
- if (expression) console.log(`const ${safeIdentifier(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`);
12588
+ if (expression)
12589
+ console.log(
12590
+ `const ${safeIdentifier2(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`
12591
+ );
10839
12592
  }
10840
12593
  console.log("```");
10841
12594
  if (options.includeSamples !== false) {
@@ -10845,31 +12598,40 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
10845
12598
  }
10846
12599
  function printToolGettersOnly(tool, requestedToolId) {
10847
12600
  const contract = toolContractJsonForDescribe(tool, requestedToolId);
10848
- const getters = isRecord4(contract.getters) ? contract.getters : {};
12601
+ const getters = isRecord5(contract.getters) ? contract.getters : {};
10849
12602
  const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
10850
12603
  const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
10851
12604
  console.log(`Getters: ${contract.toolId}`);
10852
12605
  if (!listGetters.length && !valueGetters.length) {
10853
- console.log("No generated getters declared. Use --json only if you need raw metadata.");
12606
+ console.log(
12607
+ "No generated getters declared. Use --json only if you need raw metadata."
12608
+ );
10854
12609
  return;
10855
12610
  }
10856
12611
  if (listGetters.length) {
10857
12612
  console.log("Lists:");
10858
12613
  for (const entry of listGetters) {
10859
- if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
12614
+ if (isRecord5(entry))
12615
+ console.log(
12616
+ `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
12617
+ );
10860
12618
  }
10861
12619
  }
10862
12620
  if (valueGetters.length) {
10863
12621
  console.log("Values:");
10864
12622
  for (const entry of valueGetters) {
10865
- if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
12623
+ if (isRecord5(entry))
12624
+ console.log(
12625
+ `- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
12626
+ );
10866
12627
  }
10867
12628
  }
10868
12629
  }
10869
12630
  function sampleValueForField(field) {
10870
12631
  const name = stringField(field, "name").toLowerCase();
10871
12632
  const type = stringField(field, "type").toLowerCase();
10872
- if (Object.prototype.hasOwnProperty.call(field, "default")) return field.default;
12633
+ if (Object.prototype.hasOwnProperty.call(field, "default"))
12634
+ return field.default;
10873
12635
  if (name.includes("email")) return "ada@example.com";
10874
12636
  if (name.includes("domain") || name.includes("website")) return "example.com";
10875
12637
  if (name.includes("first")) return "Ada";
@@ -10884,7 +12646,7 @@ function sampleValueForField(field) {
10884
12646
  function samplePayloadForInputFields(fields) {
10885
12647
  return Object.fromEntries(
10886
12648
  fields.slice(0, 4).flatMap((field) => {
10887
- if (!isRecord4(field)) return [];
12649
+ if (!isRecord5(field)) return [];
10888
12650
  const name = stringField(field, "name");
10889
12651
  if (!name) return [];
10890
12652
  return [[name, sampleValueForField(field)]];
@@ -10894,12 +12656,15 @@ function samplePayloadForInputFields(fields) {
10894
12656
  function stableStepIdForTool(toolId) {
10895
12657
  return toolId.replace(/^[a-z0-9]+_/, "").replace(/[^a-z0-9_]+/gi, "_") || "tool_call";
10896
12658
  }
10897
- function safeIdentifier(name) {
12659
+ function safeIdentifier2(name) {
10898
12660
  const cleaned = name.replace(/[^a-zA-Z0-9_$]+/g, "_").replace(/^[^a-zA-Z_$]+/, "");
10899
12661
  return cleaned || "value";
10900
12662
  }
10901
12663
  function playResultExpression(entry) {
10902
- return stringField(entry, "expression").replace(/^toolExecutionResult\./, "result.");
12664
+ return stringField(entry, "expression").replace(
12665
+ /^toolExecutionResult\./,
12666
+ "result."
12667
+ );
10903
12668
  }
10904
12669
  function toolMetadataJsonForDescribe(tool, requestedToolId) {
10905
12670
  const toolId = String(tool.toolId || requestedToolId);
@@ -10990,12 +12755,13 @@ function formatListedToolCost(tool) {
10990
12755
  return displayText ? `Cost: ${displayText}` : "";
10991
12756
  }
10992
12757
  function toolInputFieldsForDisplay(inputSchema) {
10993
- if (Array.isArray(inputSchema.fields)) return inputSchema.fields.filter(isRecord4);
10994
- const jsonSchema = isRecord4(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
10995
- const properties = isRecord4(jsonSchema.properties) ? jsonSchema.properties : {};
12758
+ if (Array.isArray(inputSchema.fields))
12759
+ return inputSchema.fields.filter(isRecord5);
12760
+ const jsonSchema = isRecord5(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
12761
+ const properties = isRecord5(jsonSchema.properties) ? jsonSchema.properties : {};
10996
12762
  const required = Array.isArray(jsonSchema.required) ? new Set(jsonSchema.required.map(String)) : /* @__PURE__ */ new Set();
10997
12763
  return Object.entries(properties).map(([name, value]) => {
10998
- const property = isRecord4(value) ? value : {};
12764
+ const property = isRecord5(value) ? value : {};
10999
12765
  return {
11000
12766
  name,
11001
12767
  type: typeof property.type === "string" ? property.type : "unknown",
@@ -11010,8 +12776,10 @@ function printSamples(samples) {
11010
12776
  const responsePayload = samplePayload(samples, "response");
11011
12777
  if (requestPayload === void 0 && responsePayload === void 0) return;
11012
12778
  console.log(" Samples:");
11013
- if (requestPayload !== void 0) printJsonPreview("Example payload", requestPayload);
11014
- if (responsePayload !== void 0) printJsonPreview("Example response", responsePayload);
12779
+ if (requestPayload !== void 0)
12780
+ printJsonPreview("Example payload", requestPayload);
12781
+ if (responsePayload !== void 0)
12782
+ printJsonPreview("Example response", responsePayload);
11015
12783
  }
11016
12784
  function printJsonPreview(label, payload) {
11017
12785
  console.log(` ${label}:`);
@@ -11022,15 +12790,15 @@ function printJsonPreview(label, payload) {
11022
12790
  }
11023
12791
  function samplePayload(samples, key) {
11024
12792
  const entry = samples[key];
11025
- if (!isRecord4(entry)) return void 0;
12793
+ if (!isRecord5(entry)) return void 0;
11026
12794
  return Object.prototype.hasOwnProperty.call(entry, "payload") ? entry.payload : entry;
11027
12795
  }
11028
12796
  function commandEnvelopeFromRawResponse(rawResponse) {
11029
- return isRecord4(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
12797
+ return isRecord5(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
11030
12798
  }
11031
12799
  function listExtractorPathsFromUsageGuidance(tool) {
11032
12800
  const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
11033
- const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord4(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
12801
+ const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord5(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
11034
12802
  return extractedLists.flatMap((entry) => {
11035
12803
  const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
11036
12804
  if (!Array.isArray(paths)) return [];
@@ -11046,7 +12814,7 @@ function formatDecimal(value) {
11046
12814
  function formatUsd(value) {
11047
12815
  return `$${formatDecimal(value)}`;
11048
12816
  }
11049
- function isRecord4(value) {
12817
+ function isRecord5(value) {
11050
12818
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
11051
12819
  }
11052
12820
  function stringField(source, ...keys) {
@@ -11073,7 +12841,7 @@ function arrayField(source, ...keys) {
11073
12841
  function recordField(source, ...keys) {
11074
12842
  for (const key of keys) {
11075
12843
  const value = source[key];
11076
- if (isRecord4(value)) return value;
12844
+ if (isRecord5(value)) return value;
11077
12845
  }
11078
12846
  return {};
11079
12847
  }
@@ -11096,7 +12864,9 @@ function normalizeOutputFormat(raw) {
11096
12864
  function parseExecuteOptions(args) {
11097
12865
  const toolId = args[0];
11098
12866
  if (!toolId) {
11099
- 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]`);
12867
+ throw new Error(
12868
+ `Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--no-preview]`
12869
+ );
11100
12870
  }
11101
12871
  const params = {};
11102
12872
  let outputFormat = "auto";
@@ -11206,7 +12976,7 @@ function buildToolExecuteBaseEnvelope(input) {
11206
12976
  kind: summaryEntries.length > 0 ? "object" : "raw",
11207
12977
  summary: input.summary
11208
12978
  };
11209
- const envelopeHasCanonicalOutput = isRecord4(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
12979
+ const envelopeHasCanonicalOutput = isRecord5(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
11210
12980
  const inspectCommand = `deepline tools execute ${input.toolId} --input ${shellQuote(JSON.stringify(input.params))} --json`;
11211
12981
  const actions = input.listConversion ? [
11212
12982
  {
@@ -11240,7 +13010,9 @@ function buildToolExecuteBaseEnvelope(input) {
11240
13010
  ] : [
11241
13011
  {
11242
13012
  title: "result",
11243
- lines: summaryEntries.length > 0 ? summaryEntries.map(([key, value]) => `${key}=${String(value)}`) : [JSON.stringify(input.rawResponse, null, 2)]
13013
+ lines: summaryEntries.length > 0 ? summaryEntries.map(
13014
+ ([key, value]) => `${key}=${String(value)}`
13015
+ ) : [JSON.stringify(input.rawResponse, null, 2)]
11244
13016
  }
11245
13017
  ],
11246
13018
  actions
@@ -11267,7 +13039,9 @@ async function executeTool(args) {
11267
13039
  const play = await findPlayForToolId(client, parsed.toolId);
11268
13040
  if (play) {
11269
13041
  if (argsWantJson(args)) {
11270
- printJsonError(new Error(playAliasToolErrorMessage(parsed.toolId, play)));
13042
+ printJsonError(
13043
+ new Error(playAliasToolErrorMessage(parsed.toolId, play))
13044
+ );
11271
13045
  } else {
11272
13046
  printPlayAliasToolError(parsed.toolId, play);
11273
13047
  }
@@ -11303,12 +13077,15 @@ async function executeTool(args) {
11303
13077
  return 0;
11304
13078
  }
11305
13079
  if (parsed.outputFormat === "json_file") {
11306
- const jsonPath = writeJsonOutputFile(rawResponse, `payload_${parsed.toolId}`);
13080
+ const jsonPath = writeJsonOutputFile(
13081
+ rawResponse,
13082
+ `payload_${parsed.toolId}`
13083
+ );
11307
13084
  printCommandEnvelope(
11308
13085
  {
11309
13086
  ...baseEnvelope,
11310
13087
  local: {
11311
- ...isRecord4(baseEnvelope.local) ? baseEnvelope.local : {},
13088
+ ...isRecord5(baseEnvelope.local) ? baseEnvelope.local : {},
11312
13089
  payload_file: jsonPath
11313
13090
  }
11314
13091
  },
@@ -11318,7 +13095,10 @@ async function executeTool(args) {
11318
13095
  }
11319
13096
  if (!listConversion) {
11320
13097
  if (parsed.outputFormat === "csv" || parsed.outputFormat === "csv_file") {
11321
- const jsonPath = writeJsonOutputFile(rawResponse, `payload_${parsed.toolId}`);
13098
+ const jsonPath = writeJsonOutputFile(
13099
+ rawResponse,
13100
+ `payload_${parsed.toolId}`
13101
+ );
11322
13102
  printCommandEnvelope(
11323
13103
  {
11324
13104
  ...baseEnvelope,
@@ -11333,7 +13113,10 @@ async function executeTool(args) {
11333
13113
  printCommandEnvelope(baseEnvelope, { json: false });
11334
13114
  return 0;
11335
13115
  }
11336
- const csv = writeCsvOutputFile(listConversion.rows, `${parsed.toolId}_output`);
13116
+ const csv = writeCsvOutputFile(
13117
+ listConversion.rows,
13118
+ `${parsed.toolId}_output`
13119
+ );
11337
13120
  const seededScript = seedToolListScript({
11338
13121
  toolId: parsed.toolId,
11339
13122
  payload: parsed.params,
@@ -11359,7 +13142,9 @@ async function executeTool(args) {
11359
13142
  title: `${csv.path} (${csv.rowCount} rows)`,
11360
13143
  lines: [
11361
13144
  ...csv.columns.length > 0 ? [`columns: ${JSON.stringify(csv.columns)}`] : [],
11362
- ...Object.keys(summary).length > 0 ? [`summary: ${Object.entries(summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`] : [],
13145
+ ...Object.keys(summary).length > 0 ? [
13146
+ `summary: ${Object.entries(summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`
13147
+ ] : [],
11363
13148
  `preview: ${JSON.stringify(csv.preview)}`,
11364
13149
  `starter script: ${seededScript.path}`
11365
13150
  ]
@@ -11382,22 +13167,25 @@ async function executeTool(args) {
11382
13167
  }
11383
13168
  };
11384
13169
  if (parsed.outputFormat === "csv_file") {
11385
- printCommandEnvelope({
11386
- ...materializedEnvelope,
11387
- extracted_csv: csv.path,
11388
- extracted_csv_rows: csv.rowCount,
11389
- extracted_csv_columns: csv.columns,
11390
- preview: csv.preview,
11391
- list_strategy: listConversion.strategy,
11392
- list_source_path: listConversion.sourcePath,
11393
- starter_script: seededScript.path,
11394
- project_dir: seededScript.projectDir,
11395
- copy_to_project: {
11396
- macos_linux: seededScript.macCopyCommand,
11397
- windows_powershell: seededScript.windowsCopyCommand
13170
+ printCommandEnvelope(
13171
+ {
13172
+ ...materializedEnvelope,
13173
+ extracted_csv: csv.path,
13174
+ extracted_csv_rows: csv.rowCount,
13175
+ extracted_csv_columns: csv.columns,
13176
+ preview: csv.preview,
13177
+ list_strategy: listConversion.strategy,
13178
+ list_source_path: listConversion.sourcePath,
13179
+ starter_script: seededScript.path,
13180
+ project_dir: seededScript.projectDir,
13181
+ copy_to_project: {
13182
+ macos_linux: seededScript.macCopyCommand,
13183
+ windows_powershell: seededScript.windowsCopyCommand
13184
+ },
13185
+ summary
11398
13186
  },
11399
- summary
11400
- }, { json: true });
13187
+ { json: true }
13188
+ );
11401
13189
  return 0;
11402
13190
  }
11403
13191
  if (parsed.noPreview) {
@@ -11421,7 +13209,7 @@ async function executeTool(args) {
11421
13209
  // src/cli/commands/update.ts
11422
13210
  import { spawn } from "child_process";
11423
13211
  import { existsSync as existsSync7 } from "fs";
11424
- import { dirname as dirname9, join as join9, resolve as resolve10 } from "path";
13212
+ import { dirname as dirname9, join as join9, resolve as resolve11 } from "path";
11425
13213
  function posixShellQuote(value) {
11426
13214
  return `'${value.replace(/'/g, `'\\''`)}'`;
11427
13215
  }
@@ -11440,7 +13228,7 @@ function buildSourceUpdateCommand(sourceRoot) {
11440
13228
  return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
11441
13229
  }
11442
13230
  function findRepoBackedSdkRoot(startPath) {
11443
- let current = resolve10(startPath);
13231
+ let current = resolve11(startPath);
11444
13232
  while (true) {
11445
13233
  if (existsSync7(join9(current, "sdk", "package.json")) && existsSync7(join9(current, "sdk", "bin", "deepline-dev.ts"))) {
11446
13234
  return current;
@@ -11451,7 +13239,7 @@ function findRepoBackedSdkRoot(startPath) {
11451
13239
  }
11452
13240
  }
11453
13241
  function resolveUpdatePlan() {
11454
- const entrypoint = process.argv[1] ? resolve10(process.argv[1]) : "";
13242
+ const entrypoint = process.argv[1] ? resolve11(process.argv[1]) : "";
11455
13243
  const sourceRoot = entrypoint ? findRepoBackedSdkRoot(dirname9(entrypoint)) : null;
11456
13244
  if (sourceRoot) {
11457
13245
  return {
@@ -11545,7 +13333,7 @@ Examples:
11545
13333
 
11546
13334
  // src/cli/skills-sync.ts
11547
13335
  import { spawn as spawn2, spawnSync } from "child_process";
11548
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync6, statSync, writeFileSync as writeFileSync9 } from "fs";
13336
+ import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync2, writeFileSync as writeFileSync9 } from "fs";
11549
13337
  import { homedir as homedir4 } from "os";
11550
13338
  import { dirname as dirname10, join as join10 } from "path";
11551
13339
  var CHECK_TIMEOUT_MS2 = 3e3;
@@ -11591,7 +13379,7 @@ function installedSdkSkillHasStalePositionalExecuteExamples() {
11591
13379
  const scan = (dir) => {
11592
13380
  for (const entry of readdirSync2(dir)) {
11593
13381
  const path = join10(dir, entry);
11594
- const stat3 = statSync(path);
13382
+ const stat3 = statSync2(path);
11595
13383
  if (stat3.isDirectory()) {
11596
13384
  if (scan(path)) return true;
11597
13385
  continue;
@@ -11702,7 +13490,7 @@ function resolveSkillsInstallCommands(baseUrl) {
11702
13490
  return [npxInstall];
11703
13491
  }
11704
13492
  function runOneSkillsInstall(install) {
11705
- return new Promise((resolve11) => {
13493
+ return new Promise((resolve12) => {
11706
13494
  const child = spawn2(install.command, install.args, {
11707
13495
  stdio: ["ignore", "ignore", "pipe"],
11708
13496
  env: process.env
@@ -11712,7 +13500,7 @@ function runOneSkillsInstall(install) {
11712
13500
  stderr += chunk.toString("utf-8");
11713
13501
  });
11714
13502
  child.on("error", (error) => {
11715
- resolve11({
13503
+ resolve12({
11716
13504
  ok: false,
11717
13505
  detail: `failed to start ${install.command}: ${error.message}`,
11718
13506
  manualCommand: install.manualCommand
@@ -11720,11 +13508,11 @@ function runOneSkillsInstall(install) {
11720
13508
  });
11721
13509
  child.on("close", (code) => {
11722
13510
  if (code === 0) {
11723
- resolve11({ ok: true, detail: "", manualCommand: install.manualCommand });
13511
+ resolve12({ ok: true, detail: "", manualCommand: install.manualCommand });
11724
13512
  return;
11725
13513
  }
11726
13514
  const detail = stderr.trim();
11727
- resolve11({
13515
+ resolve12({
11728
13516
  ok: false,
11729
13517
  detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
11730
13518
  manualCommand: install.manualCommand
@@ -12009,6 +13797,6 @@ Examples:
12009
13797
  }
12010
13798
  process.exitCode = 1;
12011
13799
  }
12012
- process.exit(process.exitCode ?? 0);
13800
+ process.exitCode = process.exitCode ?? 0;
12013
13801
  }
12014
13802
  main();