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