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