deepline 0.1.56 → 0.1.58
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 +1967 -308
- package/dist/cli/index.mjs +1912 -253
- 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 +34 -34
- package/dist/index.d.ts +34 -34
- package/dist/index.js +119 -2
- package/dist/index.mjs +103 -2
- package/dist/repo/apps/play-runner-workers/src/entry.ts +7 -83
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-http-errors.ts +198 -0
- 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 +2 -2
- package/dist/repo/sdk/src/types.ts +58 -33
- package/dist/repo/shared_libs/plays/bootstrap-routes.ts +127 -0
- package/dist/repo/shared_libs/plays/bundling/index.ts +3 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -25,7 +25,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
// src/cli/index.ts
|
|
27
27
|
var import_promises5 = require("fs/promises");
|
|
28
|
-
var
|
|
28
|
+
var import_node_path16 = require("path");
|
|
29
29
|
var import_node_os9 = require("os");
|
|
30
30
|
var import_commander3 = require("commander");
|
|
31
31
|
|
|
@@ -220,10 +220,10 @@ function resolveConfig(options) {
|
|
|
220
220
|
|
|
221
221
|
// src/release.ts
|
|
222
222
|
var SDK_RELEASE = {
|
|
223
|
-
version: "0.1.
|
|
223
|
+
version: "0.1.58",
|
|
224
224
|
apiContract: "2026-05-play-tool-describe-starters",
|
|
225
225
|
supportPolicy: {
|
|
226
|
-
latest: "0.1.
|
|
226
|
+
latest: "0.1.58",
|
|
227
227
|
minimumSupported: "0.1.53",
|
|
228
228
|
deprecatedBelow: "0.1.53"
|
|
229
229
|
}
|
|
@@ -361,8 +361,8 @@ var HttpClient = class {
|
|
|
361
361
|
if (lastError instanceof DeeplineError) {
|
|
362
362
|
throw lastError;
|
|
363
363
|
}
|
|
364
|
-
const
|
|
365
|
-
throw new DeeplineError(
|
|
364
|
+
const errorMessage2 = lastError?.message ? `Unable to connect to ${baseUrl}. ${lastError.message}` : `Unable to connect to ${baseUrl}. Is the computer able to access the url?`;
|
|
365
|
+
throw new DeeplineError(errorMessage2);
|
|
366
366
|
}
|
|
367
367
|
/**
|
|
368
368
|
* Send a GET request.
|
|
@@ -535,7 +535,7 @@ function decodeSseFrame(frame) {
|
|
|
535
535
|
return parsed;
|
|
536
536
|
}
|
|
537
537
|
function sleep(ms) {
|
|
538
|
-
return new Promise((
|
|
538
|
+
return new Promise((resolve12) => setTimeout(resolve12, ms));
|
|
539
539
|
}
|
|
540
540
|
|
|
541
541
|
// src/client.ts
|
|
@@ -545,7 +545,7 @@ var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
|
|
|
545
545
|
var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
|
|
546
546
|
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
547
547
|
function sleep2(ms) {
|
|
548
|
-
return new Promise((
|
|
548
|
+
return new Promise((resolve12) => setTimeout(resolve12, ms));
|
|
549
549
|
}
|
|
550
550
|
function isTransientCompileManifestError(error) {
|
|
551
551
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
@@ -2276,7 +2276,7 @@ function buildCandidateUrls2(url) {
|
|
|
2276
2276
|
}
|
|
2277
2277
|
}
|
|
2278
2278
|
function sleep3(ms) {
|
|
2279
|
-
return new Promise((
|
|
2279
|
+
return new Promise((resolve12) => setTimeout(resolve12, ms));
|
|
2280
2280
|
}
|
|
2281
2281
|
function printDeeplineLogo() {
|
|
2282
2282
|
if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
|
|
@@ -4025,8 +4025,8 @@ Examples:
|
|
|
4025
4025
|
|
|
4026
4026
|
// src/cli/commands/play.ts
|
|
4027
4027
|
var import_node_crypto3 = require("crypto");
|
|
4028
|
-
var
|
|
4029
|
-
var
|
|
4028
|
+
var import_node_fs9 = require("fs");
|
|
4029
|
+
var import_node_path11 = require("path");
|
|
4030
4030
|
|
|
4031
4031
|
// src/plays/bundle-play-file.ts
|
|
4032
4032
|
var import_node_os5 = require("os");
|
|
@@ -4379,6 +4379,9 @@ function localSdkAliasPlugin(adapter, options) {
|
|
|
4379
4379
|
buildContext.onResolve({ filter: /^deepline$/ }, () => ({
|
|
4380
4380
|
path: entryFile
|
|
4381
4381
|
}));
|
|
4382
|
+
buildContext.onResolve({ filter: /^deepline\/helpers$/ }, () => ({
|
|
4383
|
+
path: (0, import_node_path7.join)(adapter.sdkSourceRoot, "helpers.ts")
|
|
4384
|
+
}));
|
|
4382
4385
|
}
|
|
4383
4386
|
};
|
|
4384
4387
|
}
|
|
@@ -5552,41 +5555,1478 @@ function warnAboutNonDevelopmentBundling(filePath) {
|
|
|
5552
5555
|
if (!nodeEnv || nodeEnv === "development" || nodeEnv === "test") {
|
|
5553
5556
|
return;
|
|
5554
5557
|
}
|
|
5555
|
-
hasWarnedAboutNonDevelopmentBundling = true;
|
|
5556
|
-
console.warn(
|
|
5557
|
-
`[deepline] Warning: live play bundling was invoked while NODE_ENV=${nodeEnv} for ${filePath}. This source-first SDK path is intended for local development. For preview/production, run a published or prebuilt play reference instead of bundling source at runtime.`
|
|
5558
|
-
);
|
|
5559
|
-
console.warn(
|
|
5560
|
-
'[deepline] Preferred production call pattern: client.play("person-to-email").run(...) or run a previously registered/published org play.'
|
|
5561
|
-
);
|
|
5558
|
+
hasWarnedAboutNonDevelopmentBundling = true;
|
|
5559
|
+
console.warn(
|
|
5560
|
+
`[deepline] Warning: live play bundling was invoked while NODE_ENV=${nodeEnv} for ${filePath}. This source-first SDK path is intended for local development. For preview/production, run a published or prebuilt play reference instead of bundling source at runtime.`
|
|
5561
|
+
);
|
|
5562
|
+
console.warn(
|
|
5563
|
+
'[deepline] Preferred production call pattern: client.play("person-to-email").run(...) or run a previously registered/published org play.'
|
|
5564
|
+
);
|
|
5565
|
+
}
|
|
5566
|
+
function defaultPlayBundleTarget() {
|
|
5567
|
+
return resolveExecutionProfile(null).artifactKind;
|
|
5568
|
+
}
|
|
5569
|
+
function createSdkPlayBundlingAdapter() {
|
|
5570
|
+
return {
|
|
5571
|
+
projectRoot: PROJECT_ROOT,
|
|
5572
|
+
nodeModulesDir: (0, import_node_path9.resolve)(PROJECT_ROOT, "node_modules"),
|
|
5573
|
+
cacheDir: (0, import_node_path9.join)(
|
|
5574
|
+
(0, import_node_os5.tmpdir)(),
|
|
5575
|
+
`deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION2}`
|
|
5576
|
+
),
|
|
5577
|
+
sdkSourceRoot: SDK_SOURCE_ROOT,
|
|
5578
|
+
sdkPackageJson: SDK_PACKAGE_JSON,
|
|
5579
|
+
sdkEntryFile: SDK_ENTRY_FILE,
|
|
5580
|
+
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !(0, import_node_fs7.existsSync)(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
|
|
5581
|
+
sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
|
|
5582
|
+
workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
|
|
5583
|
+
workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
|
|
5584
|
+
discoverPackagedLocalFiles,
|
|
5585
|
+
warnAboutNonDevelopmentBundling
|
|
5586
|
+
};
|
|
5587
|
+
}
|
|
5588
|
+
async function bundlePlayFile2(filePath, options = {}) {
|
|
5589
|
+
return bundlePlayFile(filePath, {
|
|
5590
|
+
target: options.target ?? defaultPlayBundleTarget(),
|
|
5591
|
+
exportName: options.exportName,
|
|
5592
|
+
adapter: createSdkPlayBundlingAdapter()
|
|
5593
|
+
});
|
|
5594
|
+
}
|
|
5595
|
+
|
|
5596
|
+
// src/cli/commands/plays/bootstrap.ts
|
|
5597
|
+
var import_node_fs8 = require("fs");
|
|
5598
|
+
var import_node_path10 = require("path");
|
|
5599
|
+
var import_sync4 = require("csv-parse/sync");
|
|
5600
|
+
|
|
5601
|
+
// ../shared_libs/plays/bootstrap-routes.ts
|
|
5602
|
+
var PLAY_BOOTSTRAP_TEMPLATES = [
|
|
5603
|
+
"people-list",
|
|
5604
|
+
"company-list",
|
|
5605
|
+
"people-email",
|
|
5606
|
+
"people-phone",
|
|
5607
|
+
"company-people",
|
|
5608
|
+
"company-people-email",
|
|
5609
|
+
"company-people-phone"
|
|
5610
|
+
];
|
|
5611
|
+
var PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY = "company_search";
|
|
5612
|
+
var PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY = "people_search";
|
|
5613
|
+
var PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER = {
|
|
5614
|
+
email_finder: "email_finder",
|
|
5615
|
+
phone_finder: "phone_finder"
|
|
5616
|
+
};
|
|
5617
|
+
var PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER = {
|
|
5618
|
+
email_finder: "email",
|
|
5619
|
+
phone_finder: "phone"
|
|
5620
|
+
};
|
|
5621
|
+
function isPlayBootstrapTemplate(value) {
|
|
5622
|
+
return PLAY_BOOTSTRAP_TEMPLATES.includes(value);
|
|
5623
|
+
}
|
|
5624
|
+
function formatPlayBootstrapTemplates() {
|
|
5625
|
+
return PLAY_BOOTSTRAP_TEMPLATES.join("|");
|
|
5626
|
+
}
|
|
5627
|
+
|
|
5628
|
+
// src/cli/commands/plays/bootstrap.ts
|
|
5629
|
+
function parseReferencedPlayTarget(target) {
|
|
5630
|
+
const trimmed = target.trim();
|
|
5631
|
+
const slashIndex = trimmed.indexOf("/");
|
|
5632
|
+
if (slashIndex <= 0 || slashIndex === trimmed.length - 1) {
|
|
5633
|
+
return { ownerSlug: null, playName: trimmed, unqualifiedPlayName: trimmed };
|
|
5634
|
+
}
|
|
5635
|
+
return {
|
|
5636
|
+
ownerSlug: trimmed.slice(0, slashIndex),
|
|
5637
|
+
playName: trimmed,
|
|
5638
|
+
unqualifiedPlayName: trimmed.slice(slashIndex + 1)
|
|
5639
|
+
};
|
|
5640
|
+
}
|
|
5641
|
+
function parsePositiveInteger2(value, flagName) {
|
|
5642
|
+
const parsed = Number.parseInt(value, 10);
|
|
5643
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
5644
|
+
throw new PlayBootstrapUsageError(
|
|
5645
|
+
`${flagName} must be a positive integer.`
|
|
5646
|
+
);
|
|
5647
|
+
}
|
|
5648
|
+
return parsed;
|
|
5649
|
+
}
|
|
5650
|
+
function isRecord3(value) {
|
|
5651
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
5652
|
+
}
|
|
5653
|
+
function stringValue(value) {
|
|
5654
|
+
return typeof value === "string" ? value.trim() : "";
|
|
5655
|
+
}
|
|
5656
|
+
function extractionEntries(value) {
|
|
5657
|
+
if (Array.isArray(value)) return value.filter(isRecord3);
|
|
5658
|
+
if (!isRecord3(value)) return [];
|
|
5659
|
+
return Object.entries(value).map(
|
|
5660
|
+
([name, entry]) => isRecord3(entry) ? { name, ...entry } : { name }
|
|
5661
|
+
);
|
|
5662
|
+
}
|
|
5663
|
+
var PlayBootstrapError = class extends Error {
|
|
5664
|
+
constructor(message, exitCode) {
|
|
5665
|
+
super(message);
|
|
5666
|
+
this.exitCode = exitCode;
|
|
5667
|
+
}
|
|
5668
|
+
exitCode;
|
|
5669
|
+
};
|
|
5670
|
+
var PlayBootstrapUsageError = class extends PlayBootstrapError {
|
|
5671
|
+
constructor(message) {
|
|
5672
|
+
super(message, 2);
|
|
5673
|
+
}
|
|
5674
|
+
};
|
|
5675
|
+
var PlayBootstrapValidationError = class extends PlayBootstrapError {
|
|
5676
|
+
constructor(message) {
|
|
5677
|
+
super(message, 7);
|
|
5678
|
+
}
|
|
5679
|
+
};
|
|
5680
|
+
var CSV_HEADER_SAMPLE_BYTES = 64 * 1024;
|
|
5681
|
+
function parseCsvList(value) {
|
|
5682
|
+
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
5683
|
+
}
|
|
5684
|
+
function parseProviderList(value, flag) {
|
|
5685
|
+
const providers = parseCsvList(value);
|
|
5686
|
+
if (providers.length === 0) {
|
|
5687
|
+
throw new PlayBootstrapUsageError(`${flag} provider list cannot be empty.`);
|
|
5688
|
+
}
|
|
5689
|
+
return providers;
|
|
5690
|
+
}
|
|
5691
|
+
function parseBootstrapPrefixedRef(value, flag) {
|
|
5692
|
+
const separatorIndex = value.indexOf(":");
|
|
5693
|
+
if (separatorIndex <= 0 || separatorIndex === value.length - 1) {
|
|
5694
|
+
throw new PlayBootstrapUsageError(
|
|
5695
|
+
`${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.`
|
|
5696
|
+
);
|
|
5697
|
+
}
|
|
5698
|
+
return {
|
|
5699
|
+
prefix: value.slice(0, separatorIndex).trim(),
|
|
5700
|
+
body: value.slice(separatorIndex + 1).trim()
|
|
5701
|
+
};
|
|
5702
|
+
}
|
|
5703
|
+
function parseBootstrapSourceRef(value, flag = "--from") {
|
|
5704
|
+
const { prefix, body } = parseBootstrapPrefixedRef(value, flag);
|
|
5705
|
+
switch (prefix) {
|
|
5706
|
+
case "csv":
|
|
5707
|
+
return { kind: "csv", value: body };
|
|
5708
|
+
case "play":
|
|
5709
|
+
return { kind: "play", value: parseReferencedPlayTarget(body).playName };
|
|
5710
|
+
case "provider":
|
|
5711
|
+
case "providers":
|
|
5712
|
+
return { kind: "providers", values: parseProviderList(body, flag) };
|
|
5713
|
+
}
|
|
5714
|
+
throw new PlayBootstrapUsageError(
|
|
5715
|
+
`${flag} does not support ${prefix}:. Use csv:, play:, provider:, or providers:.`
|
|
5716
|
+
);
|
|
5717
|
+
}
|
|
5718
|
+
function parseBootstrapStageRef(value, flag) {
|
|
5719
|
+
const { prefix, body } = parseBootstrapPrefixedRef(value, flag);
|
|
5720
|
+
switch (prefix) {
|
|
5721
|
+
case "play":
|
|
5722
|
+
return { kind: "play", value: parseReferencedPlayTarget(body).playName };
|
|
5723
|
+
case "provider":
|
|
5724
|
+
case "providers":
|
|
5725
|
+
return { kind: "providers", values: parseProviderList(body, flag) };
|
|
5726
|
+
}
|
|
5727
|
+
throw new PlayBootstrapUsageError(
|
|
5728
|
+
`${flag} does not support ${prefix}:. Use play:, provider:, or providers:.`
|
|
5729
|
+
);
|
|
5730
|
+
}
|
|
5731
|
+
function playBootstrapTemplateConfig(template) {
|
|
5732
|
+
switch (template) {
|
|
5733
|
+
case "company-list":
|
|
5734
|
+
return { sourceEntity: "company", usingStage: null, requiredStages: [] };
|
|
5735
|
+
case "people-list":
|
|
5736
|
+
return { sourceEntity: "people", usingStage: null, requiredStages: [] };
|
|
5737
|
+
case "people-email":
|
|
5738
|
+
return {
|
|
5739
|
+
sourceEntity: "people",
|
|
5740
|
+
usingStage: "email",
|
|
5741
|
+
requiredStages: []
|
|
5742
|
+
};
|
|
5743
|
+
case "people-phone":
|
|
5744
|
+
return {
|
|
5745
|
+
sourceEntity: "people",
|
|
5746
|
+
usingStage: "phone",
|
|
5747
|
+
requiredStages: []
|
|
5748
|
+
};
|
|
5749
|
+
case "company-people":
|
|
5750
|
+
return {
|
|
5751
|
+
sourceEntity: "company",
|
|
5752
|
+
usingStage: "people",
|
|
5753
|
+
requiredStages: []
|
|
5754
|
+
};
|
|
5755
|
+
case "company-people-email":
|
|
5756
|
+
return {
|
|
5757
|
+
sourceEntity: "company",
|
|
5758
|
+
usingStage: null,
|
|
5759
|
+
requiredStages: ["people", "email"]
|
|
5760
|
+
};
|
|
5761
|
+
case "company-people-phone":
|
|
5762
|
+
return {
|
|
5763
|
+
sourceEntity: "company",
|
|
5764
|
+
usingStage: null,
|
|
5765
|
+
requiredStages: ["people", "phone"]
|
|
5766
|
+
};
|
|
5767
|
+
}
|
|
5768
|
+
}
|
|
5769
|
+
function templateExample(template) {
|
|
5770
|
+
switch (template) {
|
|
5771
|
+
case "people-list":
|
|
5772
|
+
return "deepline plays bootstrap people-list --from provider:dropleads_search_people > people.play.ts";
|
|
5773
|
+
case "company-list":
|
|
5774
|
+
return "deepline plays bootstrap company-list --from provider:apollo_company_search > companies.play.ts";
|
|
5775
|
+
case "people-email":
|
|
5776
|
+
return "deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall > email-flow.play.ts";
|
|
5777
|
+
case "people-phone":
|
|
5778
|
+
return "deepline plays bootstrap people-phone --from csv:data/vp_contacts.csv --using play:prebuilt/person-to-phone > phone-flow.play.ts";
|
|
5779
|
+
case "company-people":
|
|
5780
|
+
return "deepline plays bootstrap company-people --from provider:apollo_company_search --using play:prebuilt/company-to-contact > company-people.play.ts";
|
|
5781
|
+
case "company-people-email":
|
|
5782
|
+
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";
|
|
5783
|
+
case "company-people-phone":
|
|
5784
|
+
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";
|
|
5785
|
+
}
|
|
5786
|
+
}
|
|
5787
|
+
var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
5788
|
+
"people",
|
|
5789
|
+
"email",
|
|
5790
|
+
"phone"
|
|
5791
|
+
];
|
|
5792
|
+
function playBootstrapUsageLine() {
|
|
5793
|
+
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`;
|
|
5794
|
+
}
|
|
5795
|
+
function requireBootstrapTemplate(rawTemplate) {
|
|
5796
|
+
if (!rawTemplate) {
|
|
5797
|
+
throw new PlayBootstrapUsageError(
|
|
5798
|
+
`plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}.
|
|
5799
|
+
Example: deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall > email-flow.play.ts`
|
|
5800
|
+
);
|
|
5801
|
+
}
|
|
5802
|
+
if (!isPlayBootstrapTemplate(rawTemplate)) {
|
|
5803
|
+
throw new PlayBootstrapUsageError(
|
|
5804
|
+
`Unknown plays bootstrap template: ${rawTemplate}
|
|
5805
|
+
Supported templates: ${formatPlayBootstrapTemplates()}`
|
|
5806
|
+
);
|
|
5807
|
+
}
|
|
5808
|
+
return rawTemplate;
|
|
5809
|
+
}
|
|
5810
|
+
function nextFlagValue(args, index, flag) {
|
|
5811
|
+
const value = args[index + 1];
|
|
5812
|
+
if (!value || value.startsWith("--")) {
|
|
5813
|
+
throw new PlayBootstrapUsageError(`${flag} needs a value.`);
|
|
5814
|
+
}
|
|
5815
|
+
return value;
|
|
5816
|
+
}
|
|
5817
|
+
function stageFlag(stage) {
|
|
5818
|
+
return `--${stage}`;
|
|
5819
|
+
}
|
|
5820
|
+
function stageRefHelp(stage) {
|
|
5821
|
+
switch (stage) {
|
|
5822
|
+
case "people":
|
|
5823
|
+
return "play:<people-play>";
|
|
5824
|
+
case "email":
|
|
5825
|
+
case "phone":
|
|
5826
|
+
return "<play:REF|provider:ID|providers:ID,ID>";
|
|
5827
|
+
}
|
|
5828
|
+
}
|
|
5829
|
+
function getStageRef(options, stage) {
|
|
5830
|
+
switch (stage) {
|
|
5831
|
+
case "people":
|
|
5832
|
+
return options.people;
|
|
5833
|
+
case "email":
|
|
5834
|
+
return options.email;
|
|
5835
|
+
case "phone":
|
|
5836
|
+
return options.phone;
|
|
5837
|
+
}
|
|
5838
|
+
}
|
|
5839
|
+
function setStageRef(options, stage, ref) {
|
|
5840
|
+
switch (stage) {
|
|
5841
|
+
case "people":
|
|
5842
|
+
options.people = ref;
|
|
5843
|
+
return;
|
|
5844
|
+
case "email":
|
|
5845
|
+
options.email = ref;
|
|
5846
|
+
return;
|
|
5847
|
+
case "phone":
|
|
5848
|
+
options.phone = ref;
|
|
5849
|
+
return;
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5852
|
+
function unsupportedStageMessage(template, stage) {
|
|
5853
|
+
switch (stage) {
|
|
5854
|
+
case "people":
|
|
5855
|
+
return `${template} does not accept --people. Use company-people, company-people-email, or company-people-phone.`;
|
|
5856
|
+
case "email":
|
|
5857
|
+
return `${template} does not accept --email. Use people-email or company-people-email.`;
|
|
5858
|
+
case "phone":
|
|
5859
|
+
return `${template} does not accept --phone. Use people-phone or company-people-phone.`;
|
|
5860
|
+
}
|
|
5861
|
+
}
|
|
5862
|
+
function requireSource(options) {
|
|
5863
|
+
if (!options.from) {
|
|
5864
|
+
throw new PlayBootstrapUsageError(
|
|
5865
|
+
`${options.template} needs --from.
|
|
5866
|
+
Example: ${templateExample(options.template)}`
|
|
5867
|
+
);
|
|
5868
|
+
}
|
|
5869
|
+
return options.from;
|
|
5870
|
+
}
|
|
5871
|
+
function assertAllowedStageFlags(options, allowedStages) {
|
|
5872
|
+
const allowed = new Set(allowedStages);
|
|
5873
|
+
for (const stage of PLAY_BOOTSTRAP_STAGE_NAMES) {
|
|
5874
|
+
if (!allowed.has(stage) && getStageRef(options, stage)) {
|
|
5875
|
+
throw new PlayBootstrapUsageError(
|
|
5876
|
+
unsupportedStageMessage(options.template, stage)
|
|
5877
|
+
);
|
|
5878
|
+
}
|
|
5879
|
+
}
|
|
5880
|
+
}
|
|
5881
|
+
function assertRequiredStages(options, stages) {
|
|
5882
|
+
for (const stage of stages) {
|
|
5883
|
+
if (!getStageRef(options, stage)) {
|
|
5884
|
+
throw new PlayBootstrapUsageError(
|
|
5885
|
+
`${options.template} needs ${stageFlag(stage)} ${stageRefHelp(stage)}.
|
|
5886
|
+
Example: ${templateExample(options.template)}`
|
|
5887
|
+
);
|
|
5888
|
+
}
|
|
5889
|
+
}
|
|
5890
|
+
}
|
|
5891
|
+
function normalizeSingleStageRoute(options, stage) {
|
|
5892
|
+
const explicitStage = getStageRef(options, stage);
|
|
5893
|
+
if (options.using && explicitStage) {
|
|
5894
|
+
throw new PlayBootstrapUsageError(
|
|
5895
|
+
`${options.template} received both --using and ${stageFlag(stage)}. Choose one stage binding.`
|
|
5896
|
+
);
|
|
5897
|
+
}
|
|
5898
|
+
const selectedStage = options.using ?? explicitStage;
|
|
5899
|
+
if (!selectedStage) {
|
|
5900
|
+
throw new PlayBootstrapUsageError(
|
|
5901
|
+
`${options.template} needs --using ${stageRefHelp(stage)} or ${stageFlag(stage)} ${stageRefHelp(stage)}.
|
|
5902
|
+
Example: ${templateExample(options.template)}`
|
|
5903
|
+
);
|
|
5904
|
+
}
|
|
5905
|
+
setStageRef(options, stage, selectedStage);
|
|
5906
|
+
options.using = selectedStage;
|
|
5907
|
+
assertAllowedStageFlags(options, [stage]);
|
|
5908
|
+
}
|
|
5909
|
+
function normalizeMultiStageRoute(options, stages) {
|
|
5910
|
+
if (options.using) {
|
|
5911
|
+
throw new PlayBootstrapUsageError(
|
|
5912
|
+
`${options.template} does not accept --using. Use the explicit stage flags shown in: ${templateExample(options.template)}`
|
|
5913
|
+
);
|
|
5914
|
+
}
|
|
5915
|
+
assertRequiredStages(options, stages);
|
|
5916
|
+
assertAllowedStageFlags(options, stages);
|
|
5917
|
+
}
|
|
5918
|
+
function normalizeTemplateStages(options) {
|
|
5919
|
+
const config = playBootstrapTemplateConfig(options.template);
|
|
5920
|
+
const from = requireSource(options);
|
|
5921
|
+
switch (config.usingStage) {
|
|
5922
|
+
case "people":
|
|
5923
|
+
case "email":
|
|
5924
|
+
case "phone":
|
|
5925
|
+
normalizeSingleStageRoute(options, config.usingStage);
|
|
5926
|
+
break;
|
|
5927
|
+
case null:
|
|
5928
|
+
normalizeMultiStageRoute(options, config.requiredStages);
|
|
5929
|
+
break;
|
|
5930
|
+
}
|
|
5931
|
+
return {
|
|
5932
|
+
...options,
|
|
5933
|
+
from
|
|
5934
|
+
};
|
|
5935
|
+
}
|
|
5936
|
+
function parsePlayBootstrapOptions(args) {
|
|
5937
|
+
const [rawTemplate, ...rest] = args;
|
|
5938
|
+
const template = requireBootstrapTemplate(rawTemplate);
|
|
5939
|
+
const options = {
|
|
5940
|
+
template,
|
|
5941
|
+
name: `gtm-${template}`,
|
|
5942
|
+
from: null,
|
|
5943
|
+
using: null,
|
|
5944
|
+
people: null,
|
|
5945
|
+
email: null,
|
|
5946
|
+
phone: null,
|
|
5947
|
+
limit: 5
|
|
5948
|
+
};
|
|
5949
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
5950
|
+
const arg = rest[index];
|
|
5951
|
+
const value = () => nextFlagValue(rest, index, arg);
|
|
5952
|
+
switch (arg) {
|
|
5953
|
+
case "--name":
|
|
5954
|
+
options.name = value();
|
|
5955
|
+
index += 1;
|
|
5956
|
+
break;
|
|
5957
|
+
case "--from":
|
|
5958
|
+
options.from = parseBootstrapSourceRef(value(), "--from");
|
|
5959
|
+
index += 1;
|
|
5960
|
+
break;
|
|
5961
|
+
case "--using":
|
|
5962
|
+
options.using = parseBootstrapStageRef(value(), "--using");
|
|
5963
|
+
index += 1;
|
|
5964
|
+
break;
|
|
5965
|
+
case "--people":
|
|
5966
|
+
options.people = parseBootstrapStageRef(value(), "--people");
|
|
5967
|
+
index += 1;
|
|
5968
|
+
break;
|
|
5969
|
+
case "--email":
|
|
5970
|
+
options.email = parseBootstrapStageRef(value(), "--email");
|
|
5971
|
+
index += 1;
|
|
5972
|
+
break;
|
|
5973
|
+
case "--phone":
|
|
5974
|
+
options.phone = parseBootstrapStageRef(value(), "--phone");
|
|
5975
|
+
index += 1;
|
|
5976
|
+
break;
|
|
5977
|
+
case "--limit":
|
|
5978
|
+
options.limit = parsePositiveInteger2(value(), "--limit");
|
|
5979
|
+
index += 1;
|
|
5980
|
+
break;
|
|
5981
|
+
default:
|
|
5982
|
+
throw new PlayBootstrapUsageError(
|
|
5983
|
+
`Unknown plays bootstrap option: ${arg}
|
|
5984
|
+
${playBootstrapUsageLine()}`
|
|
5985
|
+
);
|
|
5986
|
+
}
|
|
5987
|
+
}
|
|
5988
|
+
return normalizeTemplateStages(options);
|
|
5989
|
+
}
|
|
5990
|
+
function jsString(value) {
|
|
5991
|
+
return JSON.stringify(value);
|
|
5992
|
+
}
|
|
5993
|
+
function inferCsvCellTypeExpression(values) {
|
|
5994
|
+
const nonEmptyValues = values.map((value) => value.trim()).filter((value) => value.length > 0);
|
|
5995
|
+
const hasEmptyValue = values.some((value) => value.trim().length === 0);
|
|
5996
|
+
if (nonEmptyValues.length === 0) return "string";
|
|
5997
|
+
const numericPattern = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:[eE][+-]?\d+)?$/;
|
|
5998
|
+
const booleanPattern = /^(?:true|false)$/i;
|
|
5999
|
+
let inferred = "string";
|
|
6000
|
+
if (nonEmptyValues.every((value) => numericPattern.test(value))) {
|
|
6001
|
+
inferred = "`${number}`";
|
|
6002
|
+
} else if (nonEmptyValues.every((value) => booleanPattern.test(value))) {
|
|
6003
|
+
const canonicalBooleanValues = nonEmptyValues.every(
|
|
6004
|
+
(value) => value === "true" || value === "false"
|
|
6005
|
+
);
|
|
6006
|
+
inferred = canonicalBooleanValues ? '"false" | "true"' : [...new Set(nonEmptyValues)].sort().map(jsString).join(" | ");
|
|
6007
|
+
}
|
|
6008
|
+
return hasEmptyValue && inferred !== "string" ? `${inferred} | ""` : inferred;
|
|
6009
|
+
}
|
|
6010
|
+
function inferCsvColumnSpecs(headers, rows) {
|
|
6011
|
+
return headers.map((header) => ({
|
|
6012
|
+
name: header,
|
|
6013
|
+
typeExpression: inferCsvCellTypeExpression(
|
|
6014
|
+
rows.map((row) => String(row[header] ?? ""))
|
|
6015
|
+
)
|
|
6016
|
+
}));
|
|
6017
|
+
}
|
|
6018
|
+
function readCsvSample(csvPath) {
|
|
6019
|
+
const resolvedPath = (0, import_node_path10.resolve)(csvPath);
|
|
6020
|
+
const size = (0, import_node_fs8.statSync)(resolvedPath).size;
|
|
6021
|
+
const fd = (0, import_node_fs8.openSync)(resolvedPath, "r");
|
|
6022
|
+
const byteLength = Math.min(size, CSV_HEADER_SAMPLE_BYTES);
|
|
6023
|
+
const buffer = Buffer.alloc(byteLength);
|
|
6024
|
+
const bytesRead = (0, import_node_fs8.readSync)(fd, buffer, 0, byteLength, 0);
|
|
6025
|
+
(0, import_node_fs8.closeSync)(fd);
|
|
6026
|
+
if (bytesRead === 0) {
|
|
6027
|
+
throw new PlayBootstrapUsageError(`--from csv:${csvPath} is empty.`);
|
|
6028
|
+
}
|
|
6029
|
+
return {
|
|
6030
|
+
content: buffer.subarray(0, bytesRead).toString("utf8"),
|
|
6031
|
+
truncated: size > bytesRead
|
|
6032
|
+
};
|
|
6033
|
+
}
|
|
6034
|
+
function completeCsvSample(csvPath, sample) {
|
|
6035
|
+
if (!sample.truncated) return sample.content;
|
|
6036
|
+
const lastLineBreak = Math.max(
|
|
6037
|
+
sample.content.lastIndexOf("\n"),
|
|
6038
|
+
sample.content.lastIndexOf("\r")
|
|
6039
|
+
);
|
|
6040
|
+
if (lastLineBreak < 0) {
|
|
6041
|
+
throw new PlayBootstrapUsageError(
|
|
6042
|
+
`CSV header in ${csvPath} is longer than ${CSV_HEADER_SAMPLE_BYTES} bytes; shorten the header row before bootstrapping.`
|
|
6043
|
+
);
|
|
6044
|
+
}
|
|
6045
|
+
return sample.content.slice(0, lastLineBreak + 1);
|
|
6046
|
+
}
|
|
6047
|
+
function readCsvHeaderFields(csvPath, sample) {
|
|
6048
|
+
const records = (0, import_sync4.parse)(sample, {
|
|
6049
|
+
bom: true,
|
|
6050
|
+
to_line: 1,
|
|
6051
|
+
relax_column_count: true,
|
|
6052
|
+
skip_empty_lines: false
|
|
6053
|
+
});
|
|
6054
|
+
const firstRecord = Array.isArray(records) ? records[0] : null;
|
|
6055
|
+
const fields = Array.isArray(firstRecord) ? firstRecord.map((field) => String(field ?? "").trim()).filter(Boolean) : [];
|
|
6056
|
+
const uniqueFields = [...new Set(fields)];
|
|
6057
|
+
if (uniqueFields.length === 0) {
|
|
6058
|
+
throw new PlayBootstrapUsageError(
|
|
6059
|
+
`Could not read a header row from --from csv:${csvPath}.`
|
|
6060
|
+
);
|
|
6061
|
+
}
|
|
6062
|
+
return uniqueFields;
|
|
6063
|
+
}
|
|
6064
|
+
function readCsvSampleRows(sample) {
|
|
6065
|
+
const parsedRows = (0, import_sync4.parse)(sample, {
|
|
6066
|
+
bom: true,
|
|
6067
|
+
columns: true,
|
|
6068
|
+
skip_empty_lines: true,
|
|
6069
|
+
relax_column_count: true,
|
|
6070
|
+
trim: true
|
|
6071
|
+
});
|
|
6072
|
+
return Array.isArray(parsedRows) ? parsedRows.filter(isRecord3) : [];
|
|
6073
|
+
}
|
|
6074
|
+
function readSourceCsvColumnSpecs(csvPath) {
|
|
6075
|
+
const sample = readCsvSample(csvPath);
|
|
6076
|
+
const completeSample = completeCsvSample(csvPath, sample);
|
|
6077
|
+
return inferCsvColumnSpecs(
|
|
6078
|
+
readCsvHeaderFields(csvPath, sample.content),
|
|
6079
|
+
readCsvSampleRows(completeSample)
|
|
6080
|
+
);
|
|
6081
|
+
}
|
|
6082
|
+
function renderSourceCsvRowType(columns) {
|
|
6083
|
+
if (columns.length === 0) return "";
|
|
6084
|
+
const properties = columns.map((column) => ` ${jsString(column.name)}: ${column.typeExpression};`).join("\n");
|
|
6085
|
+
return `// CSV cells are strings at runtime. \`${"${number}"}\` means a numeric-looking CSV string; cast before math.
|
|
6086
|
+
type SourceCsvRow = {
|
|
6087
|
+
${properties}
|
|
6088
|
+
};
|
|
6089
|
+
|
|
6090
|
+
`;
|
|
6091
|
+
}
|
|
6092
|
+
function packagedCsvPathForPlay(csvPath) {
|
|
6093
|
+
const playDir = process.cwd();
|
|
6094
|
+
const absoluteCsvPath = (0, import_node_path10.resolve)(csvPath);
|
|
6095
|
+
const relativePath = (0, import_node_path10.relative)(playDir, absoluteCsvPath);
|
|
6096
|
+
if (relativePath === "" || relativePath.startsWith("..") || (0, import_node_path10.isAbsolute)(relativePath)) {
|
|
6097
|
+
throw new PlayBootstrapUsageError(
|
|
6098
|
+
`--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.`
|
|
6099
|
+
);
|
|
6100
|
+
}
|
|
6101
|
+
const portablePath = relativePath.split("\\").join("/");
|
|
6102
|
+
return portablePath.startsWith(".") ? portablePath : `./${portablePath}`;
|
|
6103
|
+
}
|
|
6104
|
+
function getterNamesFromTool(tool, kind) {
|
|
6105
|
+
const usageGuidance = isRecord3(tool?.usageGuidance) ? tool.usageGuidance : {};
|
|
6106
|
+
const resultGuidance = isRecord3(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord3(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
|
|
6107
|
+
const key = kind === "list" ? "extractedLists" : "extractedValues";
|
|
6108
|
+
const snakeKey = kind === "list" ? "extracted_lists" : "extracted_values";
|
|
6109
|
+
return extractionEntries(resultGuidance[key] ?? resultGuidance[snakeKey]).map((entry) => stringValue(entry.name)).filter(Boolean);
|
|
6110
|
+
}
|
|
6111
|
+
function targetGettersFromTool(tool) {
|
|
6112
|
+
const record = isRecord3(tool) ? tool : {};
|
|
6113
|
+
const raw = record.targetGetters ?? record.target_getters;
|
|
6114
|
+
if (!isRecord3(raw)) return {};
|
|
6115
|
+
const entries = [];
|
|
6116
|
+
for (const [target, value] of Object.entries(raw)) {
|
|
6117
|
+
const paths = Array.isArray(value) ? value.map((path) => typeof path === "string" ? path.trim() : "").filter(Boolean) : [];
|
|
6118
|
+
if (target.trim() && paths.length > 0) {
|
|
6119
|
+
entries.push([target.trim(), paths]);
|
|
6120
|
+
}
|
|
6121
|
+
}
|
|
6122
|
+
return Object.fromEntries(entries);
|
|
6123
|
+
}
|
|
6124
|
+
function listRowCandidateKeysFromTool(tool) {
|
|
6125
|
+
const keys = /* @__PURE__ */ new Set();
|
|
6126
|
+
for (const paths of Object.values(targetGettersFromTool(tool))) {
|
|
6127
|
+
for (const path of paths) {
|
|
6128
|
+
const key = path.replace(/\[(?:\*|\d+)\]/g, "").split(/[.[\]]/, 1)[0]?.trim();
|
|
6129
|
+
if (key) keys.add(key);
|
|
6130
|
+
}
|
|
6131
|
+
}
|
|
6132
|
+
return [...keys].sort();
|
|
6133
|
+
}
|
|
6134
|
+
function inputPropertyNames(schema) {
|
|
6135
|
+
if (!isRecord3(schema)) return [];
|
|
6136
|
+
if (isRecord3(schema.properties)) return Object.keys(schema.properties);
|
|
6137
|
+
if (Array.isArray(schema.fields)) {
|
|
6138
|
+
return schema.fields.filter(isRecord3).map((field) => stringValue(field.name)).filter(Boolean);
|
|
6139
|
+
}
|
|
6140
|
+
return [];
|
|
6141
|
+
}
|
|
6142
|
+
function schemaFieldDetails(schema) {
|
|
6143
|
+
const required = requiredPlayInputFields({
|
|
6144
|
+
inputSchema: schema
|
|
6145
|
+
});
|
|
6146
|
+
const optional = inputPropertyNames(schema).filter(
|
|
6147
|
+
(field) => !required.includes(field)
|
|
6148
|
+
);
|
|
6149
|
+
return { required, optional };
|
|
6150
|
+
}
|
|
6151
|
+
function jsonSchemaTypeExpression(schema) {
|
|
6152
|
+
if (!isRecord3(schema)) return "unknown";
|
|
6153
|
+
const type = schema.type;
|
|
6154
|
+
if (Array.isArray(type)) {
|
|
6155
|
+
return type.map((entry) => jsonSchemaTypeExpression({ ...schema, type: entry })).join(" | ");
|
|
6156
|
+
}
|
|
6157
|
+
if (Array.isArray(schema.anyOf)) {
|
|
6158
|
+
return schema.anyOf.map(jsonSchemaTypeExpression).join(" | ");
|
|
6159
|
+
}
|
|
6160
|
+
if (Array.isArray(schema.oneOf)) {
|
|
6161
|
+
return schema.oneOf.map(jsonSchemaTypeExpression).join(" | ");
|
|
6162
|
+
}
|
|
6163
|
+
switch (type) {
|
|
6164
|
+
case "string":
|
|
6165
|
+
return "string";
|
|
6166
|
+
case "number":
|
|
6167
|
+
case "integer":
|
|
6168
|
+
return "number";
|
|
6169
|
+
case "boolean":
|
|
6170
|
+
return "boolean";
|
|
6171
|
+
case "null":
|
|
6172
|
+
return "null";
|
|
6173
|
+
case "array":
|
|
6174
|
+
return `Array<${jsonSchemaTypeExpression(schema.items)}>`;
|
|
6175
|
+
case "object":
|
|
6176
|
+
return "Record<string, unknown>";
|
|
6177
|
+
default:
|
|
6178
|
+
return "unknown";
|
|
6179
|
+
}
|
|
6180
|
+
}
|
|
6181
|
+
function objectPropertySchema(schema, property) {
|
|
6182
|
+
return isRecord3(schema) && isRecord3(schema.properties) ? schema.properties[property] : null;
|
|
6183
|
+
}
|
|
6184
|
+
function finderResultTypeName(finder) {
|
|
6185
|
+
return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
|
|
6186
|
+
}
|
|
6187
|
+
function renderFinderPlayResultType(input) {
|
|
6188
|
+
if (!input.play) return null;
|
|
6189
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
|
|
6190
|
+
const fieldSchema = objectPropertySchema(
|
|
6191
|
+
input.play.outputSchema,
|
|
6192
|
+
outputField
|
|
6193
|
+
);
|
|
6194
|
+
const fieldType = fieldSchema ? jsonSchemaTypeExpression(fieldSchema) : "string | null";
|
|
6195
|
+
return `type ${finderResultTypeName(input.finder)} =
|
|
6196
|
+
| string
|
|
6197
|
+
| null
|
|
6198
|
+
| {
|
|
6199
|
+
${outputField}?: ${fieldType};
|
|
6200
|
+
};`;
|
|
6201
|
+
}
|
|
6202
|
+
function generatedFinderPlayResultTypes(input) {
|
|
6203
|
+
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
6204
|
+
const stage = finderStage(input.options, finder);
|
|
6205
|
+
if (stage?.kind !== "play") return [];
|
|
6206
|
+
const typeDefinition = renderFinderPlayResultType({
|
|
6207
|
+
finder,
|
|
6208
|
+
play: input.finderPlays[finder]
|
|
6209
|
+
});
|
|
6210
|
+
return typeDefinition ? [typeDefinition] : [];
|
|
6211
|
+
}).join("\n\n");
|
|
6212
|
+
}
|
|
6213
|
+
function exampleValueComment(field) {
|
|
6214
|
+
if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size") {
|
|
6215
|
+
return "limit";
|
|
6216
|
+
}
|
|
6217
|
+
if (field === "roles" || field.endsWith("s")) return '["..."]';
|
|
6218
|
+
return '"..."';
|
|
6219
|
+
}
|
|
6220
|
+
function generateContactInputObjectFromSchema(schema, indent, label, fallbackFields = ["first_name", "last_name", "domain"]) {
|
|
6221
|
+
const details = schemaFieldDetails(schema);
|
|
6222
|
+
const required = details.required.length ? details.required : fallbackFields;
|
|
6223
|
+
const optional = details.optional;
|
|
6224
|
+
const lines = [
|
|
6225
|
+
`${indent}// TODO: map row fields into ${label}.`,
|
|
6226
|
+
...playInspectionComments(label, indent),
|
|
6227
|
+
`${indent}// Required: ${required.join(", ") || "none declared"}.`
|
|
6228
|
+
];
|
|
6229
|
+
for (const field of required) {
|
|
6230
|
+
lines.push(`${indent}// ${field}: row["TODO_SOURCE_FIELD"],`);
|
|
6231
|
+
}
|
|
6232
|
+
if (optional.length > 0) {
|
|
6233
|
+
lines.push("");
|
|
6234
|
+
lines.push(`${indent}// optional (delete unused):`);
|
|
6235
|
+
for (const field of optional) {
|
|
6236
|
+
lines.push(`${indent}// ${field}: row["TODO_SOURCE_FIELD"],`);
|
|
6237
|
+
}
|
|
6238
|
+
}
|
|
6239
|
+
return `{
|
|
6240
|
+
${lines.join("\n")}
|
|
6241
|
+
${indent.slice(2)}}`;
|
|
6242
|
+
}
|
|
6243
|
+
function generateCompanyInputObjectFromSchema(schema, indent, label, fallbackFields = ["domain", "company_name"]) {
|
|
6244
|
+
const details = schemaFieldDetails(schema);
|
|
6245
|
+
const required = details.required.length ? details.required : fallbackFields;
|
|
6246
|
+
const optional = details.optional;
|
|
6247
|
+
const lines = [
|
|
6248
|
+
`${indent}// TODO: map company fields into ${label}.`,
|
|
6249
|
+
...playInspectionComments(label, indent),
|
|
6250
|
+
`${indent}// Required: ${required.join(", ") || "none declared"}.`
|
|
6251
|
+
];
|
|
6252
|
+
for (const field of required) {
|
|
6253
|
+
lines.push(`${indent}// ${field}: company["TODO_SOURCE_FIELD"],`);
|
|
6254
|
+
}
|
|
6255
|
+
if (optional.length > 0) {
|
|
6256
|
+
lines.push("");
|
|
6257
|
+
lines.push(`${indent}// optional (delete unused):`);
|
|
6258
|
+
for (const field of optional) {
|
|
6259
|
+
lines.push(`${indent}// ${field}: company["TODO_SOURCE_FIELD"],`);
|
|
6260
|
+
}
|
|
6261
|
+
}
|
|
6262
|
+
return `{
|
|
6263
|
+
${lines.join("\n")}
|
|
6264
|
+
${indent.slice(2)}}`;
|
|
6265
|
+
}
|
|
6266
|
+
function generateSourceProviderInputObject(input) {
|
|
6267
|
+
const { tool, indent, label, entity } = input;
|
|
6268
|
+
const properties = inputPropertyNames(tool?.inputSchema);
|
|
6269
|
+
const details = schemaFieldDetails(tool?.inputSchema);
|
|
6270
|
+
const required = details.required;
|
|
6271
|
+
const includeOptional = properties.length === 0 ? ["query", "title", "domain", "limit"] : properties.filter(
|
|
6272
|
+
(field) => [
|
|
6273
|
+
"query",
|
|
6274
|
+
"q",
|
|
6275
|
+
"search",
|
|
6276
|
+
"title",
|
|
6277
|
+
"role",
|
|
6278
|
+
"persona",
|
|
6279
|
+
"domain",
|
|
6280
|
+
"company_domain",
|
|
6281
|
+
"limit",
|
|
6282
|
+
"numResults",
|
|
6283
|
+
"num_results",
|
|
6284
|
+
"page_size"
|
|
6285
|
+
].includes(field)
|
|
6286
|
+
);
|
|
6287
|
+
const lines = [
|
|
6288
|
+
`${indent}// TODO: fill ${entity} source inputs for ${label}.`,
|
|
6289
|
+
`${indent}// Inspect: deepline tools describe ${label} --json`
|
|
6290
|
+
];
|
|
6291
|
+
for (const field of required) {
|
|
6292
|
+
lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
|
|
6293
|
+
}
|
|
6294
|
+
const activeTodoField = required.length === 0 ? ["query", "q", "search", "title", "role", "persona"].find(
|
|
6295
|
+
(field) => includeOptional.includes(field)
|
|
6296
|
+
) ?? "query" : null;
|
|
6297
|
+
if (activeTodoField) {
|
|
6298
|
+
lines.push(
|
|
6299
|
+
`${indent}// ${activeTodoField}: ${exampleValueComment(activeTodoField)},`
|
|
6300
|
+
);
|
|
6301
|
+
}
|
|
6302
|
+
const optionalExamples = includeOptional.filter(
|
|
6303
|
+
(field) => !required.includes(field) && field !== activeTodoField
|
|
6304
|
+
);
|
|
6305
|
+
if (optionalExamples.length > 0) {
|
|
6306
|
+
lines.push("");
|
|
6307
|
+
lines.push(`${indent}// optional - uncomment what this provider supports:`);
|
|
6308
|
+
for (const field of optionalExamples) {
|
|
6309
|
+
if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size") {
|
|
6310
|
+
lines.push(`${indent}// ${field}: limit,`);
|
|
6311
|
+
} else {
|
|
6312
|
+
lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
|
|
6313
|
+
}
|
|
6314
|
+
}
|
|
6315
|
+
}
|
|
6316
|
+
if (!required.some(
|
|
6317
|
+
(field) => ["limit", "numResults", "num_results", "page_size"].includes(field)
|
|
6318
|
+
)) {
|
|
6319
|
+
lines.push(`${indent}limit,`);
|
|
6320
|
+
}
|
|
6321
|
+
return `{
|
|
6322
|
+
${lines.join("\n")}
|
|
6323
|
+
${indent.slice(2)}}`;
|
|
6324
|
+
}
|
|
6325
|
+
function generatePlayInputObject(input) {
|
|
6326
|
+
const { schema, indent, label, entity } = input;
|
|
6327
|
+
const details = schemaFieldDetails(schema);
|
|
6328
|
+
const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
|
|
6329
|
+
const required = details.required.length ? details.required : fallback;
|
|
6330
|
+
const lines = [
|
|
6331
|
+
`${indent}// TODO: fill source play inputs for ${label}.`,
|
|
6332
|
+
...playInspectionComments(label, indent)
|
|
6333
|
+
];
|
|
6334
|
+
for (const field of required) {
|
|
6335
|
+
lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
|
|
6336
|
+
}
|
|
6337
|
+
if (!required.includes("limit")) lines.push(`${indent}limit,`);
|
|
6338
|
+
return `{
|
|
6339
|
+
${lines.join("\n")}
|
|
6340
|
+
${indent.slice(2)}}`;
|
|
6341
|
+
}
|
|
6342
|
+
function requiredPlayInputFields(play) {
|
|
6343
|
+
const schema = play?.inputSchema;
|
|
6344
|
+
if (!isRecord3(schema)) return [];
|
|
6345
|
+
if (Array.isArray(schema.required)) {
|
|
6346
|
+
return schema.required.filter(
|
|
6347
|
+
(value) => typeof value === "string"
|
|
6348
|
+
);
|
|
6349
|
+
}
|
|
6350
|
+
if (Array.isArray(schema.fields)) {
|
|
6351
|
+
return schema.fields.filter(isRecord3).filter(
|
|
6352
|
+
(field) => field.required === true && typeof field.name === "string"
|
|
6353
|
+
).map((field) => String(field.name));
|
|
6354
|
+
}
|
|
6355
|
+
return [];
|
|
6356
|
+
}
|
|
6357
|
+
function sourceProviders(options) {
|
|
6358
|
+
return options.from.kind === "providers" ? options.from.values : [];
|
|
6359
|
+
}
|
|
6360
|
+
function sourcePlayRef(options) {
|
|
6361
|
+
return options.from.kind === "play" ? options.from.value : null;
|
|
6362
|
+
}
|
|
6363
|
+
function stagePlayRef(stage) {
|
|
6364
|
+
return stage?.kind === "play" ? stage.value : null;
|
|
6365
|
+
}
|
|
6366
|
+
function stageProviders(stage) {
|
|
6367
|
+
return stage?.kind === "providers" ? stage.values : [];
|
|
6368
|
+
}
|
|
6369
|
+
function finderStage(options, finder) {
|
|
6370
|
+
return finder === "email_finder" ? options.email : options.phone;
|
|
6371
|
+
}
|
|
6372
|
+
function stepFieldName(finder) {
|
|
6373
|
+
return PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[finder];
|
|
6374
|
+
}
|
|
6375
|
+
function finderProviderStepPrefix(finder) {
|
|
6376
|
+
return finder === "email_finder" ? "emailFinder" : "phoneFinder";
|
|
6377
|
+
}
|
|
6378
|
+
function safeIdentifier(value) {
|
|
6379
|
+
return value.replace(/[^A-Za-z0-9_]+/g, "_");
|
|
6380
|
+
}
|
|
6381
|
+
function playInspectionComments(playRef, indent) {
|
|
6382
|
+
return [`${indent}// Inspect: deepline plays describe ${playRef} --json`];
|
|
6383
|
+
}
|
|
6384
|
+
function accessorExpression(base, field) {
|
|
6385
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(field) ? `${base}.${field}` : `${base}[${jsString(field)}]`;
|
|
6386
|
+
}
|
|
6387
|
+
function needsWhenImport(options) {
|
|
6388
|
+
return stageProviders(options.email).length > 1 || stageProviders(options.phone).length > 1;
|
|
6389
|
+
}
|
|
6390
|
+
function sourceCollectionTypeName(entity) {
|
|
6391
|
+
return entity === "company" ? "CompanySourceRow" : "ContactSourceRow";
|
|
6392
|
+
}
|
|
6393
|
+
function renderPartialRowType(input) {
|
|
6394
|
+
if (input.fields.length === 0) {
|
|
6395
|
+
return `type ${input.typeName} = Record<string, unknown>;`;
|
|
6396
|
+
}
|
|
6397
|
+
const properties = input.fields.map((field) => ` ${jsString(field)}?: unknown;`).join("\n");
|
|
6398
|
+
return `type ${input.typeName} = Record<string, unknown> & Partial<{
|
|
6399
|
+
// ${input.comment}
|
|
6400
|
+
${properties}
|
|
6401
|
+
}>;`;
|
|
6402
|
+
}
|
|
6403
|
+
function fieldsFromSchemaDetails(input) {
|
|
6404
|
+
return [
|
|
6405
|
+
...input.details.required.length ? input.details.required : input.fallbackFields,
|
|
6406
|
+
...input.details.optional
|
|
6407
|
+
];
|
|
6408
|
+
}
|
|
6409
|
+
function schemaFieldsForStage(stage, input) {
|
|
6410
|
+
switch (stage?.kind) {
|
|
6411
|
+
case void 0:
|
|
6412
|
+
return [];
|
|
6413
|
+
case "play":
|
|
6414
|
+
return fieldsFromSchemaDetails({
|
|
6415
|
+
details: schemaFieldDetails(input.play?.inputSchema),
|
|
6416
|
+
fallbackFields: input.fallbackFields
|
|
6417
|
+
});
|
|
6418
|
+
case "providers":
|
|
6419
|
+
return input.tools.flatMap(
|
|
6420
|
+
(tool) => fieldsFromSchemaDetails({
|
|
6421
|
+
details: schemaFieldDetails(tool.inputSchema),
|
|
6422
|
+
fallbackFields: input.fallbackFields
|
|
6423
|
+
})
|
|
6424
|
+
);
|
|
6425
|
+
}
|
|
6426
|
+
}
|
|
6427
|
+
function sourceRowTypeDefinition(input) {
|
|
6428
|
+
switch (input.options.from.kind) {
|
|
6429
|
+
case "csv":
|
|
6430
|
+
return `type ${input.sourceTypeName} = SourceCsvRow;`;
|
|
6431
|
+
case "providers":
|
|
6432
|
+
return renderPartialRowType({
|
|
6433
|
+
typeName: input.sourceTypeName,
|
|
6434
|
+
fields: [
|
|
6435
|
+
...new Set(input.sourceTools.flatMap(listRowCandidateKeysFromTool))
|
|
6436
|
+
].sort(),
|
|
6437
|
+
comment: "Candidate source row keys from described list getters; confirm the actual provider keys with source_*.extractedLists.*.keys before mapping."
|
|
6438
|
+
});
|
|
6439
|
+
case "play": {
|
|
6440
|
+
const details = schemaFieldDetails(input.sourcePlay?.outputSchema);
|
|
6441
|
+
return renderPartialRowType({
|
|
6442
|
+
typeName: input.sourceTypeName,
|
|
6443
|
+
fields: [...details.required, ...details.optional].sort(),
|
|
6444
|
+
comment: "Candidate source play output fields; confirm the selected rows field before mapping."
|
|
6445
|
+
});
|
|
6446
|
+
}
|
|
6447
|
+
}
|
|
6448
|
+
}
|
|
6449
|
+
function contactBridgeRowTypeDefinition(input) {
|
|
6450
|
+
const config = playBootstrapTemplateConfig(input.options.template);
|
|
6451
|
+
if (config.sourceEntity !== "company" || !input.options.people) return null;
|
|
6452
|
+
const emailFields = schemaFieldsForStage(input.options.email, {
|
|
6453
|
+
tools: input.finderTools.email_finder ?? [],
|
|
6454
|
+
play: input.finderPlays.email_finder,
|
|
6455
|
+
fallbackFields: ["first_name", "last_name", "domain"]
|
|
6456
|
+
});
|
|
6457
|
+
const phoneFields = schemaFieldsForStage(input.options.phone, {
|
|
6458
|
+
tools: input.finderTools.phone_finder ?? [],
|
|
6459
|
+
play: input.finderPlays.phone_finder,
|
|
6460
|
+
fallbackFields: ["first_name", "last_name", "domain"]
|
|
6461
|
+
});
|
|
6462
|
+
return renderPartialRowType({
|
|
6463
|
+
typeName: "ContactSourceRow",
|
|
6464
|
+
fields: [
|
|
6465
|
+
.../* @__PURE__ */ new Set([
|
|
6466
|
+
...inputPropertyNames(input.peoplePlay?.outputSchema),
|
|
6467
|
+
...emailFields,
|
|
6468
|
+
...phoneFields
|
|
6469
|
+
])
|
|
6470
|
+
].sort(),
|
|
6471
|
+
comment: "Fields the people play or later finder stages may need; the generated code still requires explicit mapping."
|
|
6472
|
+
});
|
|
6473
|
+
}
|
|
6474
|
+
function generateRowTypeDefinitions(input) {
|
|
6475
|
+
const config = playBootstrapTemplateConfig(input.options.template);
|
|
6476
|
+
const sourceTypeName = sourceCollectionTypeName(config.sourceEntity);
|
|
6477
|
+
const definitions = [
|
|
6478
|
+
sourceRowTypeDefinition({
|
|
6479
|
+
options: input.options,
|
|
6480
|
+
sourceTypeName,
|
|
6481
|
+
sourceTools: input.sourceTools,
|
|
6482
|
+
sourcePlay: input.sourcePlay
|
|
6483
|
+
}),
|
|
6484
|
+
contactBridgeRowTypeDefinition(input)
|
|
6485
|
+
];
|
|
6486
|
+
return definitions.filter(Boolean).join("\n\n");
|
|
6487
|
+
}
|
|
6488
|
+
function validateBootstrapRoutes(input) {
|
|
6489
|
+
const config = playBootstrapTemplateConfig(input.options.template);
|
|
6490
|
+
const sourceCategory = config.sourceEntity === "company" ? PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY : PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY;
|
|
6491
|
+
for (const tool of input.sourceTools) {
|
|
6492
|
+
if (!tool.categories.includes(sourceCategory)) {
|
|
6493
|
+
throw new PlayBootstrapValidationError(
|
|
6494
|
+
`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`
|
|
6495
|
+
);
|
|
6496
|
+
}
|
|
6497
|
+
if (getterNamesFromTool(tool, "list").length === 0) {
|
|
6498
|
+
throw new PlayBootstrapValidationError(
|
|
6499
|
+
`Cannot use ${tool.toolId} as a ${config.sourceEntity} source: it exposes no extracted list getters. Run: deepline tools describe ${tool.toolId} --json`
|
|
6500
|
+
);
|
|
6501
|
+
}
|
|
6502
|
+
}
|
|
6503
|
+
if (input.options.people?.kind === "providers") {
|
|
6504
|
+
throw new PlayBootstrapValidationError(
|
|
6505
|
+
"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."
|
|
6506
|
+
);
|
|
6507
|
+
}
|
|
6508
|
+
for (const finder of ["email_finder", "phone_finder"]) {
|
|
6509
|
+
const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
|
|
6510
|
+
for (const tool of input.finderTools[finder] ?? []) {
|
|
6511
|
+
if (!tool.categories.includes(requiredCategory)) {
|
|
6512
|
+
throw new PlayBootstrapValidationError(
|
|
6513
|
+
`Cannot use ${tool.toolId} for ${finder}: expected category ${requiredCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${requiredCategory} --categories ${requiredCategory} --json`
|
|
6514
|
+
);
|
|
6515
|
+
}
|
|
6516
|
+
if (getterNamesFromTool(tool, "value").length === 0) {
|
|
6517
|
+
throw new PlayBootstrapValidationError(
|
|
6518
|
+
`Cannot use ${tool.toolId} as a ${finder}: it exposes no extracted value getters. Run: deepline tools describe ${tool.toolId} --json`
|
|
6519
|
+
);
|
|
6520
|
+
}
|
|
6521
|
+
}
|
|
6522
|
+
}
|
|
6523
|
+
}
|
|
6524
|
+
function sourceCollectionName(entity) {
|
|
6525
|
+
switch (entity) {
|
|
6526
|
+
case "company":
|
|
6527
|
+
return "companies";
|
|
6528
|
+
case "people":
|
|
6529
|
+
return "contacts";
|
|
6530
|
+
}
|
|
6531
|
+
}
|
|
6532
|
+
function requiredGetterName(input) {
|
|
6533
|
+
const getter = getterNamesFromTool(input.tool, input.kind)[0];
|
|
6534
|
+
if (!getter) {
|
|
6535
|
+
switch (input.kind) {
|
|
6536
|
+
case "list":
|
|
6537
|
+
throw new PlayBootstrapValidationError(
|
|
6538
|
+
`Cannot use ${input.label} as a source: it exposes no extracted list getters.`
|
|
6539
|
+
);
|
|
6540
|
+
case "value":
|
|
6541
|
+
throw new PlayBootstrapValidationError(
|
|
6542
|
+
`Cannot use ${input.label} as a finder: it exposes no extracted value getters.`
|
|
6543
|
+
);
|
|
6544
|
+
}
|
|
6545
|
+
}
|
|
6546
|
+
return getter;
|
|
6547
|
+
}
|
|
6548
|
+
function generateCsvSourceRowsBlock(input) {
|
|
6549
|
+
return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(input.packagedSourceCsvPath ?? input.source.value)});
|
|
6550
|
+
const ${input.collection}: ${input.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
6551
|
+
}
|
|
6552
|
+
function generatePlaySourceRowsBlock(input) {
|
|
6553
|
+
const playInput = generatePlayInputObject({
|
|
6554
|
+
schema: input.sourcePlay?.inputSchema,
|
|
6555
|
+
indent: " ",
|
|
6556
|
+
label: input.source.value,
|
|
6557
|
+
entity: input.entity
|
|
6558
|
+
});
|
|
6559
|
+
return `const sourceInput = ${playInput};
|
|
6560
|
+
throw new Error(${jsString(`TODO: map sourceInput for ${input.source.value}, choose the play output rows field, then delete this throw.`)});
|
|
6561
|
+
const sourceResult = await ctx.runPlay('source_play', ${jsString(input.source.value)}, sourceInput, {
|
|
6562
|
+
description: ${jsString(`Seed ${input.entity} rows from the selected play.`)},
|
|
6563
|
+
});
|
|
6564
|
+
// TODO: Replace sourceResult.rows with the selected play's actual row output field.
|
|
6565
|
+
const ${input.collection}: ${input.collectionType}[] = (sourceResult.rows ?? []) as ${input.collectionType}[];`;
|
|
6566
|
+
}
|
|
6567
|
+
function generateProviderSourceBlock(input) {
|
|
6568
|
+
const getter = requiredGetterName({
|
|
6569
|
+
tool: input.tool,
|
|
6570
|
+
kind: "list",
|
|
6571
|
+
label: input.provider
|
|
6572
|
+
});
|
|
6573
|
+
const inputName = `${input.entity}Input_${input.index}`;
|
|
6574
|
+
return `// ${input.entity === "company" ? "Company" : "People"} source provider: ${input.provider}
|
|
6575
|
+
const ${inputName}: Record<string, unknown> = ${generateSourceProviderInputObject(
|
|
6576
|
+
{
|
|
6577
|
+
tool: input.tool,
|
|
6578
|
+
indent: " ",
|
|
6579
|
+
label: input.provider,
|
|
6580
|
+
entity: input.entity
|
|
6581
|
+
}
|
|
6582
|
+
)};
|
|
6583
|
+
throw new Error(${jsString(`TODO: fill ${inputName} for ${input.provider}, then delete this throw.`)});
|
|
6584
|
+
const source_${input.index} = await ctx.tools.execute({
|
|
6585
|
+
id: ${jsString(`${input.entity}_source_${input.index}`)},
|
|
6586
|
+
tool: ${jsString(input.provider)},
|
|
6587
|
+
input: ${inputName},
|
|
6588
|
+
description: ${jsString(`Seed ${input.entity} rows from ${input.provider}.`)},
|
|
6589
|
+
});
|
|
6590
|
+
// extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
|
|
6591
|
+
// inspect source_${input.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
|
|
6592
|
+
const sourceRows_${input.index} = ${accessorExpression(`source_${input.index}.extractedLists`, getter)}.get() as ${input.collectionType}[];`;
|
|
6593
|
+
}
|
|
6594
|
+
function generateProviderSourceRowsBlock(input) {
|
|
6595
|
+
const blocks = input.source.values.map(
|
|
6596
|
+
(provider, index) => generateProviderSourceBlock({
|
|
6597
|
+
provider,
|
|
6598
|
+
index,
|
|
6599
|
+
tool: input.sourceTools[index] ?? null,
|
|
6600
|
+
entity: input.entity,
|
|
6601
|
+
collectionType: input.collectionType
|
|
6602
|
+
})
|
|
6603
|
+
);
|
|
6604
|
+
return `${blocks.join("\n\n ")}
|
|
6605
|
+
const ${input.collection}: ${input.collectionType}[] = [${input.source.values.map((_, index) => `...sourceRows_${index}`).join(", ")}];`;
|
|
6606
|
+
}
|
|
6607
|
+
function generateSourceRowsBlock(input) {
|
|
6608
|
+
const config = playBootstrapTemplateConfig(input.options.template);
|
|
6609
|
+
const entity = config.sourceEntity;
|
|
6610
|
+
const collection = sourceCollectionName(entity);
|
|
6611
|
+
const collectionType = sourceCollectionTypeName(entity);
|
|
6612
|
+
switch (input.options.from.kind) {
|
|
6613
|
+
case "csv":
|
|
6614
|
+
return generateCsvSourceRowsBlock({
|
|
6615
|
+
source: input.options.from,
|
|
6616
|
+
collection,
|
|
6617
|
+
collectionType,
|
|
6618
|
+
packagedSourceCsvPath: input.packagedSourceCsvPath
|
|
6619
|
+
});
|
|
6620
|
+
case "play":
|
|
6621
|
+
return generatePlaySourceRowsBlock({
|
|
6622
|
+
source: input.options.from,
|
|
6623
|
+
sourcePlay: input.sourcePlay,
|
|
6624
|
+
entity,
|
|
6625
|
+
collection,
|
|
6626
|
+
collectionType
|
|
6627
|
+
});
|
|
6628
|
+
case "providers":
|
|
6629
|
+
return generateProviderSourceRowsBlock({
|
|
6630
|
+
source: input.options.from,
|
|
6631
|
+
sourceTools: input.sourceTools,
|
|
6632
|
+
entity,
|
|
6633
|
+
collection,
|
|
6634
|
+
collectionType
|
|
6635
|
+
});
|
|
6636
|
+
}
|
|
6637
|
+
}
|
|
6638
|
+
function generateSourceSeedBlock(input) {
|
|
6639
|
+
const sourceRows = generateSourceRowsBlock(input);
|
|
6640
|
+
const peoplePlayRef = stagePlayRef(input.options.people);
|
|
6641
|
+
if (!peoplePlayRef) return sourceRows;
|
|
6642
|
+
const peopleInput = generateCompanyInputObjectFromSchema(
|
|
6643
|
+
input.peoplePlay?.inputSchema,
|
|
6644
|
+
" ",
|
|
6645
|
+
peoplePlayRef,
|
|
6646
|
+
["domain", "company_name"]
|
|
6647
|
+
);
|
|
6648
|
+
return `${sourceRows}
|
|
6649
|
+
const contacts: ContactSourceRow[] = [];
|
|
6650
|
+
for (const [index, company] of companies.slice(0, limit).entries()) {
|
|
6651
|
+
const peopleInput = ${peopleInput};
|
|
6652
|
+
throw new Error(${jsString(`TODO: map company fields into peopleInput for ${peoplePlayRef}, choose the play output rows field, then delete this throw.`)});
|
|
6653
|
+
const peopleResult = await ctx.runPlay(
|
|
6654
|
+
\`people_play_\${index}\`,
|
|
6655
|
+
${jsString(peoplePlayRef)},
|
|
6656
|
+
peopleInput,
|
|
6657
|
+
{
|
|
6658
|
+
description: 'Map one company row into people/contact rows with the selected play.',
|
|
6659
|
+
},
|
|
6660
|
+
);
|
|
6661
|
+
// TODO: Replace peopleResult.rows with the selected play's actual contact rows field.
|
|
6662
|
+
contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
|
|
6663
|
+
}`;
|
|
6664
|
+
}
|
|
6665
|
+
function finderProviderStepName(input) {
|
|
6666
|
+
return `${input.aggregateStepName}${input.index}_${safeIdentifier(input.provider)}`;
|
|
6667
|
+
}
|
|
6668
|
+
function finderValueGetter(input) {
|
|
6669
|
+
const getters = getterNamesFromTool(input.tool, "value");
|
|
6670
|
+
const getter = getters.find((name) => name === input.outputField) ?? requiredGetterName({
|
|
6671
|
+
tool: input.tool,
|
|
6672
|
+
kind: "value",
|
|
6673
|
+
label: input.provider
|
|
6674
|
+
});
|
|
6675
|
+
return getter;
|
|
6676
|
+
}
|
|
6677
|
+
function optionalFinderValueExpression(candidateExpression, outputField) {
|
|
6678
|
+
const valueExpression = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(outputField) ? `${candidateExpression}?.${outputField}` : `${candidateExpression}?.[${jsString(outputField)}]`;
|
|
6679
|
+
return `${valueExpression}?.trim()`;
|
|
6680
|
+
}
|
|
6681
|
+
function generateFinderPlayStep(input) {
|
|
6682
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
|
|
6683
|
+
const resultTypeName = finderResultTypeName(input.finder);
|
|
6684
|
+
const payload = generateContactInputObjectFromSchema(
|
|
6685
|
+
input.play?.inputSchema,
|
|
6686
|
+
" ",
|
|
6687
|
+
input.stage.value
|
|
6688
|
+
);
|
|
6689
|
+
return `.step(${jsString(outputField)}, async (row, rowCtx) => {
|
|
6690
|
+
const ${input.aggregateStepName}Input = ${payload};
|
|
6691
|
+
throw new Error(${jsString(`TODO: map ${input.aggregateStepName}Input for ${input.stage.value}, then delete this throw.`)});
|
|
6692
|
+
const ${input.aggregateStepName}Result = await rowCtx.runPlay<${resultTypeName}>(
|
|
6693
|
+
${jsString(`${input.aggregateStepName}Play`)},
|
|
6694
|
+
${jsString(input.stage.value)},
|
|
6695
|
+
${input.aggregateStepName}Input,
|
|
6696
|
+
{
|
|
6697
|
+
description: ${jsString(`Run ${input.finder} play.`)},
|
|
6698
|
+
},
|
|
6699
|
+
);
|
|
6700
|
+
return typeof ${input.aggregateStepName}Result === 'string'
|
|
6701
|
+
? ${input.aggregateStepName}Result.trim() || null
|
|
6702
|
+
: ${input.aggregateStepName}Result?.${outputField} ?? null;
|
|
6703
|
+
})`;
|
|
6704
|
+
}
|
|
6705
|
+
function generateFinderProviderResolver(input) {
|
|
6706
|
+
const payload = generateContactInputObjectFromSchema(
|
|
6707
|
+
input.tool?.inputSchema,
|
|
6708
|
+
" ",
|
|
6709
|
+
input.provider
|
|
6710
|
+
);
|
|
6711
|
+
const getter = finderValueGetter({
|
|
6712
|
+
tool: input.tool,
|
|
6713
|
+
provider: input.provider,
|
|
6714
|
+
outputField: input.outputField
|
|
6715
|
+
});
|
|
6716
|
+
return `async (row, rowCtx) => {
|
|
6717
|
+
const providerInput = ${payload};
|
|
6718
|
+
throw new Error(${jsString(`TODO: map providerInput for ${input.provider}, then delete this throw.`)});
|
|
6719
|
+
const result = await rowCtx.tools.execute({
|
|
6720
|
+
id: ${jsString(`${input.aggregateStepName}_${input.providerIndex}`)},
|
|
6721
|
+
tool: ${jsString(input.provider)},
|
|
6722
|
+
input: providerInput,
|
|
6723
|
+
description: ${jsString(`Try ${input.provider} as a ${input.finder}.`)},
|
|
6724
|
+
});
|
|
6725
|
+
return {
|
|
6726
|
+
${input.outputField}: (${accessorExpression("result.extractedValues", getter)}.get() as string | null) ?? null,
|
|
6727
|
+
result,
|
|
6728
|
+
};
|
|
6729
|
+
}`;
|
|
6730
|
+
}
|
|
6731
|
+
function generateFinderProviderStep(input) {
|
|
6732
|
+
const stepName = input.stepNames[input.index];
|
|
6733
|
+
switch (input.index) {
|
|
6734
|
+
case 0:
|
|
6735
|
+
return `.step(${jsString(stepName)}, ${input.resolver})`;
|
|
6736
|
+
default: {
|
|
6737
|
+
const priorCandidates = input.stepNames.slice(0, input.index).map((name) => `row.${name}`).join(", ");
|
|
6738
|
+
return `.step(
|
|
6739
|
+
${jsString(stepName)},
|
|
6740
|
+
when(
|
|
6741
|
+
(row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate", input.outputField)}),
|
|
6742
|
+
${input.resolver},
|
|
6743
|
+
),
|
|
6744
|
+
)`;
|
|
6745
|
+
}
|
|
6746
|
+
}
|
|
6747
|
+
}
|
|
6748
|
+
function generateFinderProviderWaterfall(input) {
|
|
6749
|
+
const legPrefix = finderProviderStepPrefix(input.finder);
|
|
6750
|
+
const stepNames = input.stage.values.map(
|
|
6751
|
+
(provider, index) => finderProviderStepName({
|
|
6752
|
+
aggregateStepName: legPrefix,
|
|
6753
|
+
provider,
|
|
6754
|
+
index
|
|
6755
|
+
})
|
|
6756
|
+
);
|
|
6757
|
+
const providerSteps = input.stage.values.map(
|
|
6758
|
+
(provider, index) => generateFinderProviderStep({
|
|
6759
|
+
index,
|
|
6760
|
+
stepNames,
|
|
6761
|
+
outputField: input.outputField,
|
|
6762
|
+
resolver: generateFinderProviderResolver({
|
|
6763
|
+
finder: input.finder,
|
|
6764
|
+
provider,
|
|
6765
|
+
providerIndex: index,
|
|
6766
|
+
tool: input.tools[index] ?? null,
|
|
6767
|
+
aggregateStepName: input.aggregateStepName,
|
|
6768
|
+
outputField: input.outputField
|
|
6769
|
+
})
|
|
6770
|
+
})
|
|
6771
|
+
);
|
|
6772
|
+
const candidateNames = stepNames.map((name) => `row.${name}`).join(", ");
|
|
6773
|
+
return `// ${input.aggregateStepName} provider waterfall. Each provider leg is active once its TODO throw is removed;
|
|
6774
|
+
// delete or comment out legs you do not want before running. Later legs are gated with when(...).
|
|
6775
|
+
${providerSteps.join("\n ")}
|
|
6776
|
+
.step(${jsString(input.aggregateStepName)}, (row) => {
|
|
6777
|
+
const candidates = [${candidateNames}];
|
|
6778
|
+
const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate", input.outputField)});
|
|
6779
|
+
return ${optionalFinderValueExpression("match", input.outputField)} ?? null;
|
|
6780
|
+
})`;
|
|
6781
|
+
}
|
|
6782
|
+
function generateFinderStageSteps(input) {
|
|
6783
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
|
|
6784
|
+
const aggregateStepName = stepFieldName(input.finder);
|
|
6785
|
+
switch (input.stage.kind) {
|
|
6786
|
+
case "play":
|
|
6787
|
+
return generateFinderPlayStep({
|
|
6788
|
+
finder: input.finder,
|
|
6789
|
+
stage: input.stage,
|
|
6790
|
+
play: input.finderPlays[input.finder],
|
|
6791
|
+
aggregateStepName
|
|
6792
|
+
});
|
|
6793
|
+
case "providers":
|
|
6794
|
+
return generateFinderProviderWaterfall({
|
|
6795
|
+
finder: input.finder,
|
|
6796
|
+
stage: input.stage,
|
|
6797
|
+
tools: input.finderTools[input.finder] ?? [],
|
|
6798
|
+
aggregateStepName,
|
|
6799
|
+
outputField
|
|
6800
|
+
});
|
|
6801
|
+
}
|
|
6802
|
+
}
|
|
6803
|
+
function generateFinderSteps(input) {
|
|
6804
|
+
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
6805
|
+
const stage = finderStage(input.options, finder);
|
|
6806
|
+
return stage ? [
|
|
6807
|
+
generateFinderStageSteps({
|
|
6808
|
+
...input,
|
|
6809
|
+
finder,
|
|
6810
|
+
stage
|
|
6811
|
+
})
|
|
6812
|
+
] : [];
|
|
6813
|
+
}).join("\n ");
|
|
6814
|
+
}
|
|
6815
|
+
function generateBootstrapPlaySource(input) {
|
|
6816
|
+
const config = playBootstrapTemplateConfig(input.options.template);
|
|
6817
|
+
const sourceSeedBlock = generateSourceSeedBlock(input);
|
|
6818
|
+
const finderSteps = generateFinderSteps(input);
|
|
6819
|
+
const hasPeople = config.sourceEntity === "people" || Boolean(input.options.people);
|
|
6820
|
+
const sourceCollection = hasPeople ? "contacts" : "companies";
|
|
6821
|
+
const mapSteps = finderSteps ? `
|
|
6822
|
+
${finderSteps}` : "";
|
|
6823
|
+
const sourceCsvRowType = input.options.from.kind === "csv" ? renderSourceCsvRowType(input.sourceCsvColumns) : "";
|
|
6824
|
+
const rowTypeDefinitions = generateRowTypeDefinitions(input);
|
|
6825
|
+
const finderPlayResultTypes = generatedFinderPlayResultTypes(input);
|
|
6826
|
+
const typeDefinitions = [
|
|
6827
|
+
sourceCsvRowType.trimEnd(),
|
|
6828
|
+
rowTypeDefinitions,
|
|
6829
|
+
finderPlayResultTypes
|
|
6830
|
+
].filter((definition) => definition.trim().length > 0).join("\n\n");
|
|
6831
|
+
const importNames = needsWhenImport(input.options) ? "definePlay, when" : "definePlay";
|
|
6832
|
+
return `import { ${importNames} } from 'deepline';
|
|
6833
|
+
|
|
6834
|
+
${typeDefinitions}
|
|
6835
|
+
|
|
6836
|
+
type Input = {
|
|
6837
|
+
limit?: number;
|
|
6838
|
+
};
|
|
6839
|
+
|
|
6840
|
+
export default definePlay(${jsString(input.options.name)}, async (ctx, input: Input = {}) => {
|
|
6841
|
+
const limit = Math.max(1, Math.min(Number(input.limit ?? ${input.options.limit}), ${input.options.limit}));
|
|
6842
|
+
${sourceSeedBlock}
|
|
6843
|
+
|
|
6844
|
+
const rowsToProcess = ${sourceCollection}.slice(0, limit);
|
|
6845
|
+
if (rowsToProcess.length === 0) {
|
|
6846
|
+
throw new Error('plays bootstrap found 0 source rows. Check the source provider/play/CSV output.');
|
|
6847
|
+
}
|
|
6848
|
+
|
|
6849
|
+
const rows = await ctx
|
|
6850
|
+
.map('bootstrap_rows', rowsToProcess)${mapSteps}
|
|
6851
|
+
.run({
|
|
6852
|
+
key: (_row, index) => index,
|
|
6853
|
+
description: ${jsString(`Bootstrap ${input.options.template}: seed source rows, run requested stages, then return the mapped rows.`)},
|
|
6854
|
+
});
|
|
6855
|
+
|
|
6856
|
+
return {
|
|
6857
|
+
count: await rows.count(),
|
|
6858
|
+
rows,
|
|
6859
|
+
};
|
|
6860
|
+
});
|
|
6861
|
+
|
|
6862
|
+
`;
|
|
6863
|
+
}
|
|
6864
|
+
async function describePlayMaybe(client, playRef) {
|
|
6865
|
+
return playRef ? client.describePlay(playRef, { compact: true }) : null;
|
|
6866
|
+
}
|
|
6867
|
+
function loadTools(client, providers) {
|
|
6868
|
+
return Promise.all(providers.map((provider) => client.getTool(provider)));
|
|
6869
|
+
}
|
|
6870
|
+
async function loadBootstrapContracts(client, options) {
|
|
6871
|
+
const [
|
|
6872
|
+
sourceTools,
|
|
6873
|
+
sourcePlay,
|
|
6874
|
+
peoplePlay,
|
|
6875
|
+
emailPlay,
|
|
6876
|
+
phonePlay,
|
|
6877
|
+
emailTools,
|
|
6878
|
+
phoneTools
|
|
6879
|
+
] = await Promise.all([
|
|
6880
|
+
loadTools(client, sourceProviders(options)),
|
|
6881
|
+
describePlayMaybe(client, sourcePlayRef(options)),
|
|
6882
|
+
describePlayMaybe(client, stagePlayRef(options.people)),
|
|
6883
|
+
describePlayMaybe(client, stagePlayRef(options.email)),
|
|
6884
|
+
describePlayMaybe(client, stagePlayRef(options.phone)),
|
|
6885
|
+
loadTools(client, stageProviders(options.email)),
|
|
6886
|
+
loadTools(client, stageProviders(options.phone))
|
|
6887
|
+
]);
|
|
6888
|
+
const contracts = {
|
|
6889
|
+
sourceTools,
|
|
6890
|
+
sourcePlay,
|
|
6891
|
+
peoplePlay,
|
|
6892
|
+
finderTools: {
|
|
6893
|
+
email_finder: emailTools,
|
|
6894
|
+
phone_finder: phoneTools
|
|
6895
|
+
},
|
|
6896
|
+
finderPlays: {
|
|
6897
|
+
email_finder: emailPlay,
|
|
6898
|
+
phone_finder: phonePlay
|
|
6899
|
+
}
|
|
6900
|
+
};
|
|
6901
|
+
validateBootstrapRoutes({
|
|
6902
|
+
options,
|
|
6903
|
+
sourceTools: contracts.sourceTools,
|
|
6904
|
+
peoplePlay: contracts.peoplePlay,
|
|
6905
|
+
finderTools: contracts.finderTools,
|
|
6906
|
+
finderPlays: contracts.finderPlays
|
|
6907
|
+
});
|
|
6908
|
+
return contracts;
|
|
6909
|
+
}
|
|
6910
|
+
function loadCsvContext(source) {
|
|
6911
|
+
switch (source.kind) {
|
|
6912
|
+
case "csv":
|
|
6913
|
+
return {
|
|
6914
|
+
packagedSourceCsvPath: packagedCsvPathForPlay(source.value),
|
|
6915
|
+
sourceCsvColumns: readSourceCsvColumnSpecs(source.value)
|
|
6916
|
+
};
|
|
6917
|
+
case "play":
|
|
6918
|
+
case "providers":
|
|
6919
|
+
return {
|
|
6920
|
+
packagedSourceCsvPath: null,
|
|
6921
|
+
sourceCsvColumns: []
|
|
6922
|
+
};
|
|
6923
|
+
}
|
|
5562
6924
|
}
|
|
5563
|
-
function
|
|
5564
|
-
return
|
|
6925
|
+
function errorMessage(error) {
|
|
6926
|
+
return error instanceof Error ? error.message : String(error);
|
|
5565
6927
|
}
|
|
5566
|
-
function
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
nodeModulesDir: (0, import_node_path9.resolve)(PROJECT_ROOT, "node_modules"),
|
|
5570
|
-
cacheDir: (0, import_node_path9.join)(
|
|
5571
|
-
(0, import_node_os5.tmpdir)(),
|
|
5572
|
-
`deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION2}`
|
|
5573
|
-
),
|
|
5574
|
-
sdkSourceRoot: SDK_SOURCE_ROOT,
|
|
5575
|
-
sdkPackageJson: SDK_PACKAGE_JSON,
|
|
5576
|
-
sdkEntryFile: SDK_ENTRY_FILE,
|
|
5577
|
-
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !(0, import_node_fs7.existsSync)(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
|
|
5578
|
-
sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
|
|
5579
|
-
workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
|
|
5580
|
-
workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
|
|
5581
|
-
discoverPackagedLocalFiles,
|
|
5582
|
-
warnAboutNonDevelopmentBundling
|
|
5583
|
-
};
|
|
6928
|
+
function renderPlayBootstrapError(error) {
|
|
6929
|
+
console.error(errorMessage(error));
|
|
6930
|
+
return error instanceof PlayBootstrapError ? error.exitCode : 1;
|
|
5584
6931
|
}
|
|
5585
|
-
async function
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
6932
|
+
async function runPlayBootstrap(args) {
|
|
6933
|
+
const options = parsePlayBootstrapOptions(args);
|
|
6934
|
+
const client = new DeeplineClient();
|
|
6935
|
+
const contracts = await loadBootstrapContracts(client, options);
|
|
6936
|
+
const csvContext = loadCsvContext(options.from);
|
|
6937
|
+
const source = generateBootstrapPlaySource({
|
|
6938
|
+
options,
|
|
6939
|
+
...contracts,
|
|
6940
|
+
...csvContext
|
|
6941
|
+
});
|
|
6942
|
+
process.stdout.write(source);
|
|
6943
|
+
return 0;
|
|
6944
|
+
}
|
|
6945
|
+
async function handlePlayBootstrap(args) {
|
|
6946
|
+
return runPlayBootstrap(args).catch(renderPlayBootstrapError);
|
|
6947
|
+
}
|
|
6948
|
+
function registerPlayBootstrapCommand(play) {
|
|
6949
|
+
play.command("bootstrap <template>").description("Print a scratchpad play for a GTM route template.").addHelpText(
|
|
6950
|
+
"after",
|
|
6951
|
+
`
|
|
6952
|
+
Notes:
|
|
6953
|
+
Cloud-validated play generator for agents. Pick the JTBD as the positional
|
|
6954
|
+
template, bind resources with typed refs, redirect stdout to a .play.ts file,
|
|
6955
|
+
then edit the generated TODO mapping comments. Multiple finder providers are
|
|
6956
|
+
generated as a waterfall in the order you pass them.
|
|
6957
|
+
|
|
6958
|
+
This command requires auth because provider/play contracts are fetched from
|
|
6959
|
+
Deepline. It prints TypeScript source only and does not run paid tools; the
|
|
6960
|
+
generated play may spend credits later when you run it.
|
|
6961
|
+
|
|
6962
|
+
stdout is the generated .play.ts source. Errors and diagnostics go to stderr.
|
|
6963
|
+
There is no JSON mode and no --out; use shell redirection:
|
|
6964
|
+
deepline plays bootstrap ... > scratchpad.play.ts
|
|
6965
|
+
|
|
6966
|
+
Templates:
|
|
6967
|
+
people-list start from people/contact rows
|
|
6968
|
+
company-list start from company/account rows
|
|
6969
|
+
people-email people/contact rows -> email finder
|
|
6970
|
+
people-phone people/contact rows -> phone finder
|
|
6971
|
+
company-people company/account rows -> people play
|
|
6972
|
+
company-people-email company/account rows -> people play -> email finder
|
|
6973
|
+
company-people-phone company/account rows -> people play -> phone finder
|
|
6974
|
+
|
|
6975
|
+
Resource refs:
|
|
6976
|
+
csv:./contacts.csv
|
|
6977
|
+
play:prebuilt/name-and-domain-to-email-waterfall
|
|
6978
|
+
provider:dropleads_search_people
|
|
6979
|
+
providers:hunter_email_finder,leadmagic_email_finder
|
|
6980
|
+
|
|
6981
|
+
Validation:
|
|
6982
|
+
source providers must match the route entity: company_search or people_search
|
|
6983
|
+
source providers must expose list getters
|
|
6984
|
+
company -> people uses a play only; provider bridge is generated later when a play exists
|
|
6985
|
+
email/phone finder providers must match their category and expose value getters
|
|
6986
|
+
finder plays/providers must match the route; generated code leaves input mapping explicit
|
|
6987
|
+
business-specific provider inputs and company -> people persona fields are TODOs in code
|
|
6988
|
+
csv: paths are resolved from the directory where you run bootstrap; redirect the play file there too
|
|
6989
|
+
|
|
6990
|
+
Exit codes:
|
|
6991
|
+
0 success
|
|
6992
|
+
2 usage/local input error
|
|
6993
|
+
7 route validation failed
|
|
6994
|
+
|
|
6995
|
+
Examples:
|
|
6996
|
+
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
|
|
6997
|
+
deepline plays check email-flow.play.ts
|
|
6998
|
+
deepline plays run email-flow.play.ts --input '{"limit":5}' --watch
|
|
6999
|
+
|
|
7000
|
+
deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5 > prospecting.play.ts
|
|
7001
|
+
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
|
|
7002
|
+
deepline plays bootstrap company-list --from provider:apollo_company_search --limit 5 > companies.play.ts
|
|
7003
|
+
`
|
|
7004
|
+
).option("--name <name>", "Generated play name").option(
|
|
7005
|
+
"--from <ref>",
|
|
7006
|
+
"Route source: csv:PATH, play:REF, provider:ID, or providers:ID,ID"
|
|
7007
|
+
).option(
|
|
7008
|
+
"--using <ref>",
|
|
7009
|
+
"Single-stage route shorthand for people-email, people-phone, or company-people"
|
|
7010
|
+
).option(
|
|
7011
|
+
"--people <ref>",
|
|
7012
|
+
"Company-to-people stage for company-people-email/phone; use play:REF"
|
|
7013
|
+
).option(
|
|
7014
|
+
"--email <ref>",
|
|
7015
|
+
"Email finder stage: play:REF, provider:ID, or providers:ID,ID"
|
|
7016
|
+
).option(
|
|
7017
|
+
"--phone <ref>",
|
|
7018
|
+
"Phone finder stage: play:REF, provider:ID, or providers:ID,ID"
|
|
7019
|
+
).option("--limit <n>", "Maximum rows to fan out in the generated play").action(async (template, options) => {
|
|
7020
|
+
process.exitCode = await handlePlayBootstrap([
|
|
7021
|
+
template,
|
|
7022
|
+
...options.name ? ["--name", options.name] : [],
|
|
7023
|
+
...options.from ? ["--from", options.from] : [],
|
|
7024
|
+
...options.using ? ["--using", options.using] : [],
|
|
7025
|
+
...options.people ? ["--people", options.people] : [],
|
|
7026
|
+
...options.email ? ["--email", options.email] : [],
|
|
7027
|
+
...options.phone ? ["--phone", options.phone] : [],
|
|
7028
|
+
...options.limit ? ["--limit", options.limit] : []
|
|
7029
|
+
]);
|
|
5590
7030
|
});
|
|
5591
7031
|
}
|
|
5592
7032
|
|
|
@@ -6041,9 +7481,9 @@ function traceCliSync(phase, fields, run) {
|
|
|
6041
7481
|
}
|
|
6042
7482
|
}
|
|
6043
7483
|
function sleep4(ms) {
|
|
6044
|
-
return new Promise((
|
|
7484
|
+
return new Promise((resolve12) => setTimeout(resolve12, ms));
|
|
6045
7485
|
}
|
|
6046
|
-
function
|
|
7486
|
+
function parseReferencedPlayTarget2(target) {
|
|
6047
7487
|
const trimmed = target.trim();
|
|
6048
7488
|
const slashIndex = trimmed.indexOf("/");
|
|
6049
7489
|
if (slashIndex <= 0 || slashIndex === trimmed.length - 1) {
|
|
@@ -6064,7 +7504,7 @@ function buildBarePrebuiltReferenceError(input) {
|
|
|
6064
7504
|
);
|
|
6065
7505
|
}
|
|
6066
7506
|
async function assertCanonicalNamedPlayReference(client, target) {
|
|
6067
|
-
const parsed =
|
|
7507
|
+
const parsed = parseReferencedPlayTarget2(target);
|
|
6068
7508
|
const detail = await client.getPlay(parsed.playName);
|
|
6069
7509
|
if (detail.play.ownerType === "deepline" && !isPrebuiltReferenceTarget(target)) {
|
|
6070
7510
|
throw buildBarePrebuiltReferenceError({
|
|
@@ -6085,10 +7525,10 @@ function formatPlayListReference(play) {
|
|
|
6085
7525
|
return play.reference || play.name;
|
|
6086
7526
|
}
|
|
6087
7527
|
function defaultMaterializedPlayPath(reference) {
|
|
6088
|
-
return (0,
|
|
7528
|
+
return (0, import_node_path11.resolve)(defaultStarterPlayPath(reference));
|
|
6089
7529
|
}
|
|
6090
7530
|
function defaultStarterPlayPath(reference) {
|
|
6091
|
-
const playName =
|
|
7531
|
+
const playName = parseReferencedPlayTarget2(reference).unqualifiedPlayName;
|
|
6092
7532
|
const safeName = playName.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
6093
7533
|
return `./${safeName || "play"}.play.ts`;
|
|
6094
7534
|
}
|
|
@@ -6111,15 +7551,15 @@ function materializeRemotePlaySource(input) {
|
|
|
6111
7551
|
return null;
|
|
6112
7552
|
}
|
|
6113
7553
|
const outputPath = input.outPath ?? defaultMaterializedPlayPath(input.playName);
|
|
6114
|
-
if ((0,
|
|
6115
|
-
const existingSource = (0,
|
|
7554
|
+
if ((0, import_node_fs9.existsSync)(outputPath)) {
|
|
7555
|
+
const existingSource = (0, import_node_fs9.readFileSync)(outputPath, "utf-8");
|
|
6116
7556
|
if (existingSource === input.sourceCode) {
|
|
6117
7557
|
return { path: outputPath, status: "unchanged", created: false };
|
|
6118
7558
|
}
|
|
6119
|
-
(0,
|
|
7559
|
+
(0, import_node_fs9.writeFileSync)(outputPath, input.sourceCode, "utf-8");
|
|
6120
7560
|
return { path: outputPath, status: "updated", created: false };
|
|
6121
7561
|
}
|
|
6122
|
-
(0,
|
|
7562
|
+
(0, import_node_fs9.writeFileSync)(outputPath, input.sourceCode, "utf-8");
|
|
6123
7563
|
return { path: outputPath, status: "created", created: true };
|
|
6124
7564
|
}
|
|
6125
7565
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -6144,7 +7584,7 @@ To make your own version:
|
|
|
6144
7584
|
);
|
|
6145
7585
|
}
|
|
6146
7586
|
async function ensureEditableRemotePlay(client, target) {
|
|
6147
|
-
const parsed =
|
|
7587
|
+
const parsed = parseReferencedPlayTarget2(target);
|
|
6148
7588
|
const detail = await client.getPlay(parsed.playName);
|
|
6149
7589
|
if (detail.play.ownerType === "deepline") {
|
|
6150
7590
|
throw buildReadonlyPrebuiltPlayError(formatPlayReference(detail.play));
|
|
@@ -6164,7 +7604,7 @@ function extractPlayName(code, filePath) {
|
|
|
6164
7604
|
throw buildMissingDefinePlayError(filePath);
|
|
6165
7605
|
}
|
|
6166
7606
|
function isFileTarget(target) {
|
|
6167
|
-
return (0,
|
|
7607
|
+
return (0, import_node_fs9.existsSync)((0, import_node_path11.resolve)(target));
|
|
6168
7608
|
}
|
|
6169
7609
|
function looksLikeRunId(target) {
|
|
6170
7610
|
return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
|
|
@@ -6185,7 +7625,7 @@ function looksLikeFilePath(target) {
|
|
|
6185
7625
|
}
|
|
6186
7626
|
return target.includes("\\") || /\.(ts|js|mjs|play\.ts)$/.test(target);
|
|
6187
7627
|
}
|
|
6188
|
-
function
|
|
7628
|
+
function parsePositiveInteger3(value, flagName) {
|
|
6189
7629
|
const parsed = Number.parseInt(value, 10);
|
|
6190
7630
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
6191
7631
|
throw new Error(`${flagName} must be a positive integer.`);
|
|
@@ -6193,7 +7633,7 @@ function parsePositiveInteger2(value, flagName) {
|
|
|
6193
7633
|
return parsed;
|
|
6194
7634
|
}
|
|
6195
7635
|
function parseJsonInput(raw) {
|
|
6196
|
-
const source = raw.startsWith("@") ? (0,
|
|
7636
|
+
const source = raw.startsWith("@") ? (0, import_node_fs9.readFileSync)((0, import_node_path11.resolve)(raw.slice(1)), "utf-8") : raw;
|
|
6197
7637
|
const parsed = JSON.parse(source);
|
|
6198
7638
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
6199
7639
|
throw new Error("--input must be a JSON object.");
|
|
@@ -6260,7 +7700,8 @@ function setDottedInputValue(input, path, value) {
|
|
|
6260
7700
|
cursor[parts[parts.length - 1]] = value;
|
|
6261
7701
|
}
|
|
6262
7702
|
function schemaMetadata(schema, key) {
|
|
6263
|
-
if (!schema || typeof schema !== "object" || Array.isArray(schema))
|
|
7703
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema))
|
|
7704
|
+
return null;
|
|
6264
7705
|
const value = schema[key];
|
|
6265
7706
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
6266
7707
|
}
|
|
@@ -6294,7 +7735,7 @@ function fileInputBindingsFromStaticPipeline(staticPipeline) {
|
|
|
6294
7735
|
function isLocalFilePathValue(value) {
|
|
6295
7736
|
if (typeof value !== "string" || !value.trim()) return false;
|
|
6296
7737
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
6297
|
-
return (0,
|
|
7738
|
+
return (0, import_node_fs9.existsSync)((0, import_node_path11.resolve)(value));
|
|
6298
7739
|
}
|
|
6299
7740
|
function inputContainsLocalFilePath(value) {
|
|
6300
7741
|
if (isLocalFilePathValue(value)) {
|
|
@@ -6315,13 +7756,15 @@ function namedRunNeedsPlayDefinition(input) {
|
|
|
6315
7756
|
}
|
|
6316
7757
|
async function stageFileInputArgs(input) {
|
|
6317
7758
|
const uniqueBindings = [
|
|
6318
|
-
...new Map(
|
|
7759
|
+
...new Map(
|
|
7760
|
+
input.bindings.map((binding) => [binding.inputPath, binding])
|
|
7761
|
+
).values()
|
|
6319
7762
|
];
|
|
6320
7763
|
const localFiles = uniqueBindings.flatMap((binding) => {
|
|
6321
7764
|
const value = getDottedInputValue(input.runtimeInput, binding.inputPath);
|
|
6322
7765
|
if (!isLocalFilePathValue(value)) return [];
|
|
6323
|
-
const absolutePath = (0,
|
|
6324
|
-
return [{ binding, absolutePath, logicalPath: (0,
|
|
7766
|
+
const absolutePath = (0, import_node_path11.resolve)(value);
|
|
7767
|
+
return [{ binding, absolutePath, logicalPath: (0, import_node_path11.basename)(absolutePath) }];
|
|
6325
7768
|
});
|
|
6326
7769
|
if (localFiles.length === 0) {
|
|
6327
7770
|
return { inputFile: null, packagedFiles: [] };
|
|
@@ -6333,10 +7776,18 @@ async function stageFileInputArgs(input) {
|
|
|
6333
7776
|
localFiles.map((file) => stageFile(file.logicalPath, file.absolutePath))
|
|
6334
7777
|
);
|
|
6335
7778
|
for (const [index, file] of localFiles.entries()) {
|
|
6336
|
-
setDottedInputValue(
|
|
7779
|
+
setDottedInputValue(
|
|
7780
|
+
input.runtimeInput,
|
|
7781
|
+
file.binding.inputPath,
|
|
7782
|
+
file.logicalPath
|
|
7783
|
+
);
|
|
6337
7784
|
const stagedFile = staged[index];
|
|
6338
7785
|
if (stagedFile && stagedFile.logicalPath !== file.logicalPath) {
|
|
6339
|
-
setDottedInputValue(
|
|
7786
|
+
setDottedInputValue(
|
|
7787
|
+
input.runtimeInput,
|
|
7788
|
+
file.binding.inputPath,
|
|
7789
|
+
stagedFile.logicalPath
|
|
7790
|
+
);
|
|
6340
7791
|
}
|
|
6341
7792
|
}
|
|
6342
7793
|
return {
|
|
@@ -6345,7 +7796,7 @@ async function stageFileInputArgs(input) {
|
|
|
6345
7796
|
};
|
|
6346
7797
|
}
|
|
6347
7798
|
function stageFile(logicalPath, absolutePath) {
|
|
6348
|
-
const buffer = (0,
|
|
7799
|
+
const buffer = (0, import_node_fs9.readFileSync)(absolutePath);
|
|
6349
7800
|
return {
|
|
6350
7801
|
logicalPath,
|
|
6351
7802
|
contentBase64: buffer.toString("base64"),
|
|
@@ -6356,9 +7807,9 @@ function stageFile(logicalPath, absolutePath) {
|
|
|
6356
7807
|
}
|
|
6357
7808
|
function normalizePlayPath(filePath) {
|
|
6358
7809
|
try {
|
|
6359
|
-
return
|
|
7810
|
+
return import_node_fs9.realpathSync.native((0, import_node_path11.resolve)(filePath));
|
|
6360
7811
|
} catch {
|
|
6361
|
-
return (0,
|
|
7812
|
+
return (0, import_node_path11.resolve)(filePath);
|
|
6362
7813
|
}
|
|
6363
7814
|
}
|
|
6364
7815
|
function formatBundlingErrors(filePath, errors) {
|
|
@@ -6716,7 +8167,10 @@ function formatProgressCounts(input) {
|
|
|
6716
8167
|
if (completed === null || total === null || total <= 0) {
|
|
6717
8168
|
return null;
|
|
6718
8169
|
}
|
|
6719
|
-
const percent = Math.max(
|
|
8170
|
+
const percent = Math.max(
|
|
8171
|
+
0,
|
|
8172
|
+
Math.min(100, Math.round(completed / total * 100))
|
|
8173
|
+
);
|
|
6720
8174
|
const failed = typeof input.failed === "number" && Number.isFinite(input.failed) && input.failed > 0 ? `, failed ${formatInteger(input.failed)}` : "";
|
|
6721
8175
|
return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
|
|
6722
8176
|
}
|
|
@@ -7430,7 +8884,9 @@ function buildInsufficientCreditsSummaryLines(input) {
|
|
|
7430
8884
|
const runId = input.status.runId?.trim();
|
|
7431
8885
|
if (runId) {
|
|
7432
8886
|
lines.push(` inspect: deepline runs get ${runId} --json`);
|
|
7433
|
-
lines.push(
|
|
8887
|
+
lines.push(
|
|
8888
|
+
` export partial: deepline runs export ${runId} --out output.csv`
|
|
8889
|
+
);
|
|
7434
8890
|
}
|
|
7435
8891
|
return lines;
|
|
7436
8892
|
}
|
|
@@ -7502,7 +8958,10 @@ function normalizeErrorsForEnvelope(status, error) {
|
|
|
7502
8958
|
}
|
|
7503
8959
|
return {
|
|
7504
8960
|
...entry,
|
|
7505
|
-
message: formatInsufficientCreditsMessage({
|
|
8961
|
+
message: formatInsufficientCreditsMessage({
|
|
8962
|
+
billing: billing2,
|
|
8963
|
+
error: message2
|
|
8964
|
+
}),
|
|
7506
8965
|
billing: stripProviderSpendFromBilling(billing2)
|
|
7507
8966
|
};
|
|
7508
8967
|
});
|
|
@@ -7657,7 +9116,9 @@ function buildRunPackageTextLines(packaged) {
|
|
|
7657
9116
|
const runId = typeof run.id === "string" ? run.id : "unknown";
|
|
7658
9117
|
const status = typeof run.status === "string" ? run.status : "unknown";
|
|
7659
9118
|
const playName = typeof run.playName === "string" ? run.playName : null;
|
|
7660
|
-
const lines = [
|
|
9119
|
+
const lines = [
|
|
9120
|
+
`${status === "completed" ? "\u2713" : status === "failed" ? "\u2717" : "\u2022"} ${status} ${runId}`
|
|
9121
|
+
];
|
|
7661
9122
|
if (playName) {
|
|
7662
9123
|
lines.push(` play: ${playName}`);
|
|
7663
9124
|
}
|
|
@@ -7728,13 +9189,16 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
7728
9189
|
}
|
|
7729
9190
|
lines.push(...renderedServerView.actions);
|
|
7730
9191
|
const payload = options?.fullJson ? enrichPlayStatusWithDatasetStats(status) : compactPlayStatus(status);
|
|
7731
|
-
printCommandEnvelope(
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
9192
|
+
printCommandEnvelope(
|
|
9193
|
+
{
|
|
9194
|
+
...payload,
|
|
9195
|
+
render: {
|
|
9196
|
+
sections: [{ title: "run result", lines }]
|
|
9197
|
+
}
|
|
9198
|
+
},
|
|
9199
|
+
{ json: jsonOutput, text: `${lines.join("\n")}
|
|
9200
|
+
` }
|
|
9201
|
+
);
|
|
7738
9202
|
}
|
|
7739
9203
|
async function resolvePlayRunOutputStatus(input) {
|
|
7740
9204
|
if (!input.fullJson || !getPlayRunPackage(input.status)) {
|
|
@@ -7759,7 +9223,7 @@ function sqlStringLiteral(value) {
|
|
|
7759
9223
|
return `'${value.replace(/'/g, "''")}'`;
|
|
7760
9224
|
}
|
|
7761
9225
|
function runExportRetryCommand(runId, outPath, datasetPath) {
|
|
7762
|
-
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0,
|
|
9226
|
+
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0, import_node_path11.resolve)(outPath))}`;
|
|
7763
9227
|
}
|
|
7764
9228
|
function extractRunPlayName(status) {
|
|
7765
9229
|
const run = status.run;
|
|
@@ -7793,7 +9257,7 @@ function buildCustomerDbQueryPlan(input) {
|
|
|
7793
9257
|
return {
|
|
7794
9258
|
sql,
|
|
7795
9259
|
json: `${base} --json`,
|
|
7796
|
-
csv: `${base} --format csv --out ${shellSingleQuote((0,
|
|
9260
|
+
csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path11.resolve)(input.outPath))}`
|
|
7797
9261
|
};
|
|
7798
9262
|
}
|
|
7799
9263
|
function exportableSheetRow(row) {
|
|
@@ -8093,7 +9557,9 @@ function renderServerResultView(value) {
|
|
|
8093
9557
|
(field) => typeof field === "string"
|
|
8094
9558
|
) : [];
|
|
8095
9559
|
if (rawResultFields.length > 0) {
|
|
8096
|
-
lines.push(
|
|
9560
|
+
lines.push(
|
|
9561
|
+
` tool-result columns: ${rawResultFields.join(", ")}`
|
|
9562
|
+
);
|
|
8097
9563
|
}
|
|
8098
9564
|
}
|
|
8099
9565
|
if (typeof table.slowExportAsCsvCommand === "string") {
|
|
@@ -8146,10 +9612,13 @@ function writeStartedPlayRun(input) {
|
|
|
8146
9612
|
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`
|
|
8147
9613
|
];
|
|
8148
9614
|
if (input.jsonOutput) {
|
|
8149
|
-
printCommandEnvelope(
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
9615
|
+
printCommandEnvelope(
|
|
9616
|
+
{
|
|
9617
|
+
...payload,
|
|
9618
|
+
render: { sections: [{ title: "play run", lines }] }
|
|
9619
|
+
},
|
|
9620
|
+
{ json: true }
|
|
9621
|
+
);
|
|
8153
9622
|
return;
|
|
8154
9623
|
}
|
|
8155
9624
|
if (input.dashboardUrl) {
|
|
@@ -8160,11 +9629,14 @@ function writeStartedPlayRun(input) {
|
|
|
8160
9629
|
input.progress.writeLine(output, process.stdout);
|
|
8161
9630
|
return;
|
|
8162
9631
|
}
|
|
8163
|
-
printCommandEnvelope(
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
9632
|
+
printCommandEnvelope(
|
|
9633
|
+
{
|
|
9634
|
+
...payload,
|
|
9635
|
+
render: { sections: [{ title: "play run", lines }] }
|
|
9636
|
+
},
|
|
9637
|
+
{ json: false, text: `${output}
|
|
9638
|
+
` }
|
|
9639
|
+
);
|
|
8168
9640
|
}
|
|
8169
9641
|
function parsePlayRunOptions(args) {
|
|
8170
9642
|
const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotency, tool call id, and ctx.map guidance.";
|
|
@@ -8187,7 +9659,7 @@ function parsePlayRunOptions(args) {
|
|
|
8187
9659
|
continue;
|
|
8188
9660
|
}
|
|
8189
9661
|
if (arg === "--name" && args[index + 1]) {
|
|
8190
|
-
playName =
|
|
9662
|
+
playName = parseReferencedPlayTarget2(args[++index]).playName;
|
|
8191
9663
|
continue;
|
|
8192
9664
|
}
|
|
8193
9665
|
if ((arg === "--input" || arg === "-i") && args[index + 1]) {
|
|
@@ -8217,7 +9689,7 @@ function parsePlayRunOptions(args) {
|
|
|
8217
9689
|
);
|
|
8218
9690
|
}
|
|
8219
9691
|
if ((arg === "--tail-timeout-ms" || arg === "--timeout-ms") && args[index + 1]) {
|
|
8220
|
-
waitTimeoutMs =
|
|
9692
|
+
waitTimeoutMs = parsePositiveInteger3(args[++index], arg);
|
|
8221
9693
|
continue;
|
|
8222
9694
|
}
|
|
8223
9695
|
if (PLAY_RUN_RESERVED_BOOLEAN_FLAGS.has(arg)) {
|
|
@@ -8251,7 +9723,7 @@ function parsePlayRunOptions(args) {
|
|
|
8251
9723
|
if (isFileTarget(arg) || looksLikeFilePath(arg)) {
|
|
8252
9724
|
filePath = arg;
|
|
8253
9725
|
} else {
|
|
8254
|
-
playName =
|
|
9726
|
+
playName = parseReferencedPlayTarget2(arg).playName;
|
|
8255
9727
|
}
|
|
8256
9728
|
continue;
|
|
8257
9729
|
}
|
|
@@ -8300,34 +9772,34 @@ function shouldUseLocalOnlyPlayCheck() {
|
|
|
8300
9772
|
const value = process.env.DEEPLINE_PLAY_CHECK_LOCAL_ONLY?.trim().toLowerCase();
|
|
8301
9773
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
8302
9774
|
}
|
|
8303
|
-
function
|
|
9775
|
+
function isRecord4(value) {
|
|
8304
9776
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
8305
9777
|
}
|
|
8306
|
-
function
|
|
9778
|
+
function stringValue2(value) {
|
|
8307
9779
|
return typeof value === "string" ? value.trim() : "";
|
|
8308
9780
|
}
|
|
8309
9781
|
function asArray(value) {
|
|
8310
9782
|
return Array.isArray(value) ? value : [];
|
|
8311
9783
|
}
|
|
8312
|
-
function
|
|
8313
|
-
if (Array.isArray(value)) return value.filter(
|
|
8314
|
-
if (!
|
|
9784
|
+
function extractionEntries2(value) {
|
|
9785
|
+
if (Array.isArray(value)) return value.filter(isRecord4);
|
|
9786
|
+
if (!isRecord4(value)) return [];
|
|
8315
9787
|
return Object.entries(value).map(
|
|
8316
|
-
([name, entry]) =>
|
|
9788
|
+
([name, entry]) => isRecord4(entry) ? { name, ...entry } : { name }
|
|
8317
9789
|
);
|
|
8318
9790
|
}
|
|
8319
9791
|
function firstRawPath(entry) {
|
|
8320
|
-
const details =
|
|
9792
|
+
const details = isRecord4(entry.details) ? entry.details : {};
|
|
8321
9793
|
const paths = [
|
|
8322
9794
|
...asArray(details.rawToolOutputPaths),
|
|
8323
9795
|
...asArray(details.raw_tool_output_paths),
|
|
8324
9796
|
...asArray(details.candidatePaths),
|
|
8325
9797
|
...asArray(details.candidate_paths)
|
|
8326
|
-
].map(
|
|
9798
|
+
].map(stringValue2).filter(Boolean);
|
|
8327
9799
|
return paths[0];
|
|
8328
9800
|
}
|
|
8329
9801
|
function checkHintExpression(value) {
|
|
8330
|
-
return
|
|
9802
|
+
return stringValue2(value).replace(/^toolExecutionResult\./, "result.");
|
|
8331
9803
|
}
|
|
8332
9804
|
function checkHintRawPath(value) {
|
|
8333
9805
|
return value?.replace(/^toolResponse\./, "result.toolResponse.");
|
|
@@ -8335,14 +9807,14 @@ function checkHintRawPath(value) {
|
|
|
8335
9807
|
function collectStaticPipelineToolIds(staticPipeline) {
|
|
8336
9808
|
const seen = /* @__PURE__ */ new Set();
|
|
8337
9809
|
const visitPipeline = (pipeline) => {
|
|
8338
|
-
if (!
|
|
9810
|
+
if (!isRecord4(pipeline)) return;
|
|
8339
9811
|
for (const step of [
|
|
8340
9812
|
...asArray(pipeline.stages),
|
|
8341
9813
|
...asArray(pipeline.substeps)
|
|
8342
9814
|
]) {
|
|
8343
|
-
if (!
|
|
9815
|
+
if (!isRecord4(step)) continue;
|
|
8344
9816
|
if (step.type === "tool") {
|
|
8345
|
-
const toolId =
|
|
9817
|
+
const toolId = stringValue2(step.toolId) || stringValue2(step.tool);
|
|
8346
9818
|
if (toolId) seen.add(toolId);
|
|
8347
9819
|
}
|
|
8348
9820
|
if (step.type === "play_call") {
|
|
@@ -8354,20 +9826,20 @@ function collectStaticPipelineToolIds(staticPipeline) {
|
|
|
8354
9826
|
return [...seen].sort();
|
|
8355
9827
|
}
|
|
8356
9828
|
function toolGetterHintFromMetadata(toolId, tool) {
|
|
8357
|
-
const usageGuidance =
|
|
8358
|
-
const resultGuidance =
|
|
8359
|
-
const toolResponse =
|
|
8360
|
-
const lists =
|
|
9829
|
+
const usageGuidance = isRecord4(tool.usageGuidance) ? tool.usageGuidance : {};
|
|
9830
|
+
const resultGuidance = isRecord4(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord4(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
|
|
9831
|
+
const toolResponse = isRecord4(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord4(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
|
|
9832
|
+
const lists = extractionEntries2(
|
|
8361
9833
|
resultGuidance.extractedLists ?? resultGuidance.extracted_lists
|
|
8362
9834
|
).map((entry) => ({
|
|
8363
|
-
name:
|
|
9835
|
+
name: stringValue2(entry.name),
|
|
8364
9836
|
expression: checkHintExpression(entry.expression),
|
|
8365
9837
|
raw: checkHintRawPath(firstRawPath(entry))
|
|
8366
9838
|
})).filter((entry) => entry.name && entry.expression);
|
|
8367
|
-
const values =
|
|
9839
|
+
const values = extractionEntries2(
|
|
8368
9840
|
resultGuidance.extractedValues ?? resultGuidance.extracted_values
|
|
8369
9841
|
).map((entry) => ({
|
|
8370
|
-
name:
|
|
9842
|
+
name: stringValue2(entry.name),
|
|
8371
9843
|
expression: checkHintExpression(entry.expression),
|
|
8372
9844
|
raw: checkHintRawPath(firstRawPath(entry))
|
|
8373
9845
|
})).filter((entry) => entry.name && entry.expression);
|
|
@@ -8423,12 +9895,12 @@ function printToolGetterHints(hints) {
|
|
|
8423
9895
|
async function handlePlayCheck(args) {
|
|
8424
9896
|
const options = parsePlayCheckOptions(args);
|
|
8425
9897
|
if (!isFileTarget(options.target)) {
|
|
8426
|
-
const resolved = (0,
|
|
9898
|
+
const resolved = (0, import_node_path11.resolve)(options.target);
|
|
8427
9899
|
console.error(`File not found: ${resolved}`);
|
|
8428
9900
|
return 1;
|
|
8429
9901
|
}
|
|
8430
|
-
const absolutePlayPath = (0,
|
|
8431
|
-
const sourceCode = (0,
|
|
9902
|
+
const absolutePlayPath = (0, import_node_path11.resolve)(options.target);
|
|
9903
|
+
const sourceCode = (0, import_node_fs9.readFileSync)(absolutePlayPath, "utf-8");
|
|
8432
9904
|
let graph;
|
|
8433
9905
|
try {
|
|
8434
9906
|
graph = await collectBundledPlayGraph(absolutePlayPath);
|
|
@@ -8455,8 +9927,10 @@ async function handlePlayCheck(args) {
|
|
|
8455
9927
|
graphHash: graph.root.artifact.graphHash
|
|
8456
9928
|
};
|
|
8457
9929
|
if (options.jsonOutput) {
|
|
8458
|
-
process.stdout.write(
|
|
8459
|
-
|
|
9930
|
+
process.stdout.write(
|
|
9931
|
+
`${JSON.stringify({ name: playName, ...result2 })}
|
|
9932
|
+
`
|
|
9933
|
+
);
|
|
8460
9934
|
} else {
|
|
8461
9935
|
console.log(`\u2713 ${playName} passed local play check`);
|
|
8462
9936
|
console.log(` artifact: ${result2.artifactHash.slice(0, 12)}`);
|
|
@@ -8480,8 +9954,10 @@ async function handlePlayCheck(args) {
|
|
|
8480
9954
|
toolGetterHints: result.toolGetterHints ?? await buildToolGetterHints(client, result.staticPipeline)
|
|
8481
9955
|
};
|
|
8482
9956
|
if (options.jsonOutput) {
|
|
8483
|
-
process.stdout.write(
|
|
8484
|
-
|
|
9957
|
+
process.stdout.write(
|
|
9958
|
+
`${JSON.stringify({ name: playName, ...enrichedResult })}
|
|
9959
|
+
`
|
|
9960
|
+
);
|
|
8485
9961
|
} else if (enrichedResult.valid) {
|
|
8486
9962
|
console.log(`\u2713 ${playName} passed cloud play check`);
|
|
8487
9963
|
if (enrichedResult.artifactHash) {
|
|
@@ -8503,12 +9979,12 @@ async function handleFileBackedRun(options) {
|
|
|
8503
9979
|
}
|
|
8504
9980
|
const client = new DeeplineClient();
|
|
8505
9981
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
8506
|
-
const absolutePlayPath = (0,
|
|
9982
|
+
const absolutePlayPath = (0, import_node_path11.resolve)(options.target.path);
|
|
8507
9983
|
progress.phase("compiling play");
|
|
8508
9984
|
const sourceCode = traceCliSync(
|
|
8509
9985
|
"cli.play_file_read_source",
|
|
8510
9986
|
{ targetKind: "file" },
|
|
8511
|
-
() => (0,
|
|
9987
|
+
() => (0, import_node_fs9.readFileSync)(absolutePlayPath, "utf-8")
|
|
8512
9988
|
);
|
|
8513
9989
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
8514
9990
|
let graph;
|
|
@@ -8792,19 +10268,19 @@ async function handlePlayRun(args) {
|
|
|
8792
10268
|
if (isFileTarget(options.target.path)) {
|
|
8793
10269
|
return handleFileBackedRun(options);
|
|
8794
10270
|
}
|
|
8795
|
-
const resolved = (0,
|
|
10271
|
+
const resolved = (0, import_node_path11.resolve)(options.target.path);
|
|
8796
10272
|
console.error(`File not found: ${resolved}`);
|
|
8797
|
-
const dir = (0,
|
|
8798
|
-
if ((0,
|
|
8799
|
-
const base = (0,
|
|
10273
|
+
const dir = (0, import_node_path11.dirname)(resolved);
|
|
10274
|
+
if ((0, import_node_fs9.existsSync)(dir)) {
|
|
10275
|
+
const base = (0, import_node_path11.basename)(resolved);
|
|
8800
10276
|
try {
|
|
8801
|
-
const siblings = (0,
|
|
10277
|
+
const siblings = (0, import_node_fs9.readdirSync)(dir).filter(
|
|
8802
10278
|
(f) => f.includes(base.replace(/\.(play\.)?ts$/, "")) || f.endsWith(".play.ts")
|
|
8803
10279
|
);
|
|
8804
10280
|
if (siblings.length > 0) {
|
|
8805
10281
|
console.error(`Did you mean one of these?`);
|
|
8806
10282
|
for (const s of siblings.slice(0, 5)) {
|
|
8807
|
-
console.error(` ${(0,
|
|
10283
|
+
console.error(` ${(0, import_node_path11.join)(dir, s)}`);
|
|
8808
10284
|
}
|
|
8809
10285
|
}
|
|
8810
10286
|
} catch {
|
|
@@ -8858,7 +10334,7 @@ async function handleRunsList(args) {
|
|
|
8858
10334
|
for (let index = 0; index < args.length; index += 1) {
|
|
8859
10335
|
const arg = args[index];
|
|
8860
10336
|
if ((arg === "--play" || arg === "--name") && args[index + 1]) {
|
|
8861
|
-
playName =
|
|
10337
|
+
playName = parseReferencedPlayTarget2(args[++index]).playName;
|
|
8862
10338
|
continue;
|
|
8863
10339
|
}
|
|
8864
10340
|
if (arg === "--status" && args[index + 1]) {
|
|
@@ -8887,15 +10363,20 @@ async function handleRunsList(args) {
|
|
|
8887
10363
|
executionTime: run.executionTime,
|
|
8888
10364
|
playName: run.memo?.playName ?? playName
|
|
8889
10365
|
}));
|
|
8890
|
-
const lines = runs.length === 0 ? [`No runs found for ${playName}.`] : runs.map(
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
10366
|
+
const lines = runs.length === 0 ? [`No runs found for ${playName}.`] : runs.map(
|
|
10367
|
+
(run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)}`
|
|
10368
|
+
);
|
|
10369
|
+
printCommandEnvelope(
|
|
10370
|
+
{
|
|
10371
|
+
runs,
|
|
10372
|
+
count: runs.length,
|
|
10373
|
+
next: {
|
|
10374
|
+
get: runs[0]?.runId ? `deepline runs get ${runs[0].runId} --json` : null
|
|
10375
|
+
},
|
|
10376
|
+
render: { sections: [{ title: "runs", lines }] }
|
|
8896
10377
|
},
|
|
8897
|
-
|
|
8898
|
-
|
|
10378
|
+
{ json: argsWantJson(args) }
|
|
10379
|
+
);
|
|
8899
10380
|
return 0;
|
|
8900
10381
|
}
|
|
8901
10382
|
async function handleRunTail(args) {
|
|
@@ -8910,7 +10391,9 @@ async function handleRunTail(args) {
|
|
|
8910
10391
|
for (let index = 0; index < args.length; index += 1) {
|
|
8911
10392
|
const arg = args[index];
|
|
8912
10393
|
if (arg === "--cursor") {
|
|
8913
|
-
console.error(
|
|
10394
|
+
console.error(
|
|
10395
|
+
"--cursor was removed. deepline runs tail reads the canonical run stream."
|
|
10396
|
+
);
|
|
8914
10397
|
return 1;
|
|
8915
10398
|
}
|
|
8916
10399
|
if (arg.startsWith("--") && arg !== "--json" && arg !== "--compact") {
|
|
@@ -8937,42 +10420,58 @@ async function handleRunLogs(args) {
|
|
|
8937
10420
|
for (let index = 0; index < args.length; index += 1) {
|
|
8938
10421
|
const arg = args[index];
|
|
8939
10422
|
if (arg === "--limit" && args[index + 1]) {
|
|
8940
|
-
limit =
|
|
10423
|
+
limit = parsePositiveInteger3(args[++index], "--limit");
|
|
8941
10424
|
continue;
|
|
8942
10425
|
}
|
|
8943
10426
|
if (arg === "--out" && args[index + 1]) {
|
|
8944
|
-
outPath = (0,
|
|
10427
|
+
outPath = (0, import_node_path11.resolve)(args[++index]);
|
|
8945
10428
|
}
|
|
8946
10429
|
}
|
|
8947
10430
|
const client = new DeeplineClient();
|
|
8948
10431
|
const status = await client.runs.get(runId);
|
|
8949
10432
|
const logs = status.progress?.logs ?? [];
|
|
8950
10433
|
if (outPath) {
|
|
8951
|
-
(0,
|
|
8952
|
-
printCommandEnvelope(
|
|
8953
|
-
|
|
8954
|
-
|
|
8955
|
-
|
|
8956
|
-
|
|
8957
|
-
|
|
8958
|
-
|
|
10434
|
+
(0, import_node_fs9.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
10435
|
+
printCommandEnvelope(
|
|
10436
|
+
{
|
|
10437
|
+
runId: status.runId,
|
|
10438
|
+
log_path: outPath,
|
|
10439
|
+
lineCount: logs.length,
|
|
10440
|
+
local: { log_path: outPath },
|
|
10441
|
+
render: {
|
|
10442
|
+
sections: [
|
|
10443
|
+
{
|
|
10444
|
+
title: "run logs",
|
|
10445
|
+
lines: [`Wrote ${logs.length} log lines to ${outPath}`]
|
|
10446
|
+
}
|
|
10447
|
+
]
|
|
10448
|
+
}
|
|
10449
|
+
},
|
|
10450
|
+
{ json: argsWantJson(args) }
|
|
10451
|
+
);
|
|
8959
10452
|
return 0;
|
|
8960
10453
|
}
|
|
8961
10454
|
const entries = logs.slice(Math.max(0, logs.length - limit));
|
|
8962
|
-
printCommandEnvelope(
|
|
8963
|
-
|
|
8964
|
-
|
|
8965
|
-
|
|
8966
|
-
|
|
8967
|
-
|
|
8968
|
-
|
|
8969
|
-
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
|
|
10455
|
+
printCommandEnvelope(
|
|
10456
|
+
{
|
|
10457
|
+
runId: status.runId,
|
|
10458
|
+
totalCount: logs.length,
|
|
10459
|
+
returnedCount: entries.length,
|
|
10460
|
+
firstSequence: logs.length === 0 ? null : logs.length - entries.length + 1,
|
|
10461
|
+
lastSequence: logs.length === 0 ? null : logs.length,
|
|
10462
|
+
truncated: logs.length > entries.length,
|
|
10463
|
+
hasMore: logs.length > entries.length,
|
|
10464
|
+
entries,
|
|
10465
|
+
next: {
|
|
10466
|
+
export: `deepline runs logs ${status.runId} --out run.log --json`
|
|
10467
|
+
},
|
|
10468
|
+
render: { sections: [{ title: "run logs", lines: entries }] }
|
|
8973
10469
|
},
|
|
8974
|
-
|
|
8975
|
-
|
|
10470
|
+
{
|
|
10471
|
+
json: argsWantJson(args),
|
|
10472
|
+
text: `${entries.join("\n")}${entries.length > 0 ? "\n" : ""}`
|
|
10473
|
+
}
|
|
10474
|
+
);
|
|
8976
10475
|
return 0;
|
|
8977
10476
|
}
|
|
8978
10477
|
async function handleRunStop(args) {
|
|
@@ -8997,10 +10496,13 @@ async function handleRunStop(args) {
|
|
|
8997
10496
|
`Stopped ${result.runId}`,
|
|
8998
10497
|
...result.hitlCancelledCount > 0 ? [`cancelled HITL waits: ${result.hitlCancelledCount}`] : []
|
|
8999
10498
|
];
|
|
9000
|
-
printCommandEnvelope(
|
|
9001
|
-
|
|
9002
|
-
|
|
9003
|
-
|
|
10499
|
+
printCommandEnvelope(
|
|
10500
|
+
{
|
|
10501
|
+
...result,
|
|
10502
|
+
render: { sections: [{ title: "run stop", lines }] }
|
|
10503
|
+
},
|
|
10504
|
+
{ json: argsWantJson(args) }
|
|
10505
|
+
);
|
|
9004
10506
|
return 0;
|
|
9005
10507
|
}
|
|
9006
10508
|
async function handleRunExport(args) {
|
|
@@ -9018,7 +10520,7 @@ async function handleRunExport(args) {
|
|
|
9018
10520
|
for (let index = 0; index < args.length; index += 1) {
|
|
9019
10521
|
const arg = args[index];
|
|
9020
10522
|
if (arg === "--out" && args[index + 1]) {
|
|
9021
|
-
outPath = (0,
|
|
10523
|
+
outPath = (0, import_node_path11.resolve)(args[++index]);
|
|
9022
10524
|
continue;
|
|
9023
10525
|
}
|
|
9024
10526
|
if (arg === "--dataset" && args[index + 1]) {
|
|
@@ -9026,7 +10528,7 @@ async function handleRunExport(args) {
|
|
|
9026
10528
|
continue;
|
|
9027
10529
|
}
|
|
9028
10530
|
if (arg === "--metadata-out" && args[index + 1]) {
|
|
9029
|
-
metadataOutPath = (0,
|
|
10531
|
+
metadataOutPath = (0, import_node_path11.resolve)(args[++index]);
|
|
9030
10532
|
}
|
|
9031
10533
|
}
|
|
9032
10534
|
if (!outPath) {
|
|
@@ -9083,7 +10585,7 @@ async function handleRunExport(args) {
|
|
|
9083
10585
|
}
|
|
9084
10586
|
};
|
|
9085
10587
|
if (metadataOutPath) {
|
|
9086
|
-
(0,
|
|
10588
|
+
(0, import_node_fs9.writeFileSync)(
|
|
9087
10589
|
metadataOutPath,
|
|
9088
10590
|
`${JSON.stringify(payload, null, 2)}
|
|
9089
10591
|
`,
|
|
@@ -9113,10 +10615,10 @@ async function handlePlayGet(args) {
|
|
|
9113
10615
|
for (let index = 1; index < args.length; index += 1) {
|
|
9114
10616
|
const arg = args[index];
|
|
9115
10617
|
if (arg === "--out" && args[index + 1]) {
|
|
9116
|
-
outPath = (0,
|
|
10618
|
+
outPath = (0, import_node_path11.resolve)(args[++index]);
|
|
9117
10619
|
}
|
|
9118
10620
|
}
|
|
9119
|
-
const playName = isFileTarget(target) ? extractPlayName((0,
|
|
10621
|
+
const playName = isFileTarget(target) ? extractPlayName((0, import_node_fs9.readFileSync)((0, import_node_path11.resolve)(target), "utf-8"), (0, import_node_path11.resolve)(target)) : parseReferencedPlayTarget2(target).playName;
|
|
9120
10622
|
const detail = isFileTarget(target) ? await client.getPlay(playName) : await assertCanonicalNamedPlayReference(client, target);
|
|
9121
10623
|
const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
|
|
9122
10624
|
const materializedFile = outPath ? materializeRemotePlaySource({
|
|
@@ -9201,7 +10703,7 @@ async function handlePlayVersions(args) {
|
|
|
9201
10703
|
const jsonOutput = argsWantJson(args);
|
|
9202
10704
|
await assertCanonicalNamedPlayReference(client, playName);
|
|
9203
10705
|
const versions = await client.listPlayVersions(
|
|
9204
|
-
|
|
10706
|
+
parseReferencedPlayTarget2(playName).playName
|
|
9205
10707
|
);
|
|
9206
10708
|
if (jsonOutput) {
|
|
9207
10709
|
process.stdout.write(`${JSON.stringify({ versions })}
|
|
@@ -9335,7 +10837,8 @@ function compactPlaySchema(schema) {
|
|
|
9335
10837
|
return fields.length > 0 ? { fields } : schema;
|
|
9336
10838
|
}
|
|
9337
10839
|
function playSchemaMetadata(schema, key) {
|
|
9338
|
-
if (!schema || typeof schema !== "object" || Array.isArray(schema))
|
|
10840
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema))
|
|
10841
|
+
return null;
|
|
9339
10842
|
const value = schema[key];
|
|
9340
10843
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
9341
10844
|
}
|
|
@@ -9350,7 +10853,10 @@ function playRunCommand(play, options) {
|
|
|
9350
10853
|
function summarizePlayListItemForCli(play, options) {
|
|
9351
10854
|
const aliases = play.aliases?.length ? play.aliases : [play.name];
|
|
9352
10855
|
const csvInput = playSchemaMetadata(play.inputSchema, "csvInput");
|
|
9353
|
-
const rowOutputSchema = playSchemaMetadata(
|
|
10856
|
+
const rowOutputSchema = playSchemaMetadata(
|
|
10857
|
+
play.outputSchema,
|
|
10858
|
+
"rowOutputSchema"
|
|
10859
|
+
);
|
|
9354
10860
|
const runCommand2 = playRunCommand(play, { csvInput });
|
|
9355
10861
|
const cloneEditStarter = buildCloneEditStarter(play);
|
|
9356
10862
|
return {
|
|
@@ -9500,7 +11006,7 @@ async function handlePlayDescribe(args) {
|
|
|
9500
11006
|
const client = new DeeplineClient();
|
|
9501
11007
|
await assertCanonicalNamedPlayReference(client, playName);
|
|
9502
11008
|
const play = await client.describePlay(
|
|
9503
|
-
|
|
11009
|
+
parseReferencedPlayTarget2(playName).playName,
|
|
9504
11010
|
{
|
|
9505
11011
|
compact: args.includes("--compact")
|
|
9506
11012
|
}
|
|
@@ -9546,7 +11052,7 @@ async function handlePlayPublish(args) {
|
|
|
9546
11052
|
}
|
|
9547
11053
|
let graph;
|
|
9548
11054
|
try {
|
|
9549
|
-
graph = await collectBundledPlayGraph((0,
|
|
11055
|
+
graph = await collectBundledPlayGraph((0, import_node_path11.resolve)(playName));
|
|
9550
11056
|
await compileBundledPlayGraphManifests(client, graph);
|
|
9551
11057
|
await publishImportedPlayDependencies(client, graph);
|
|
9552
11058
|
} catch (error) {
|
|
@@ -9575,7 +11081,7 @@ async function handlePlayPublish(args) {
|
|
|
9575
11081
|
);
|
|
9576
11082
|
return 0;
|
|
9577
11083
|
}
|
|
9578
|
-
const resolvedName =
|
|
11084
|
+
const resolvedName = parseReferencedPlayTarget2(playName).playName;
|
|
9579
11085
|
if (useLatest) {
|
|
9580
11086
|
const versions = await client.listPlayVersions(resolvedName);
|
|
9581
11087
|
const latest = versions[0];
|
|
@@ -9615,17 +11121,19 @@ async function handlePlayDelete(args) {
|
|
|
9615
11121
|
const client = new DeeplineClient();
|
|
9616
11122
|
let detail;
|
|
9617
11123
|
try {
|
|
9618
|
-
detail = await client.getPlay(
|
|
11124
|
+
detail = await client.getPlay(parseReferencedPlayTarget2(playName).playName);
|
|
9619
11125
|
} catch (error) {
|
|
9620
11126
|
console.error(error instanceof Error ? error.message : String(error));
|
|
9621
11127
|
return 1;
|
|
9622
11128
|
}
|
|
9623
11129
|
if (detail.play.ownerType === "deepline" || detail.play.origin === "prebuilt") {
|
|
9624
|
-
console.error(
|
|
11130
|
+
console.error(
|
|
11131
|
+
`Cannot delete prebuilt play: ${formatPlayReference(detail.play)}`
|
|
11132
|
+
);
|
|
9625
11133
|
return 1;
|
|
9626
11134
|
}
|
|
9627
11135
|
const result = await client.deletePlay(
|
|
9628
|
-
|
|
11136
|
+
parseReferencedPlayTarget2(formatPlayReference(detail.play)).playName
|
|
9629
11137
|
);
|
|
9630
11138
|
if (argsWantJson(args)) {
|
|
9631
11139
|
process.stdout.write(`${JSON.stringify(result)}
|
|
@@ -9770,6 +11278,7 @@ Pass-through input flags:
|
|
|
9770
11278
|
...passthroughArgs
|
|
9771
11279
|
]);
|
|
9772
11280
|
});
|
|
11281
|
+
registerPlayBootstrapCommand(play);
|
|
9773
11282
|
play.command("get <target>").description("Fetch full play details.").addHelpText(
|
|
9774
11283
|
"after",
|
|
9775
11284
|
`
|
|
@@ -9784,7 +11293,10 @@ Examples:
|
|
|
9784
11293
|
deepline plays get prebuilt/name-and-domain-to-email-waterfall-batch --source > email-waterfall.play.ts
|
|
9785
11294
|
deepline plays get prebuilt/name-and-domain-to-email-waterfall-batch --source --out ./email-waterfall.play.ts
|
|
9786
11295
|
`
|
|
9787
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
|
|
11296
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
|
|
11297
|
+
"--source",
|
|
11298
|
+
"Print raw source code; combine with --out to write a file"
|
|
11299
|
+
).option("--out <path>", "Write source to a specific path").action(async (target, options) => {
|
|
9788
11300
|
process.exitCode = await handlePlayGet([
|
|
9789
11301
|
target,
|
|
9790
11302
|
...options.json ? ["--json"] : [],
|
|
@@ -9831,7 +11343,9 @@ Examples:
|
|
|
9831
11343
|
]);
|
|
9832
11344
|
});
|
|
9833
11345
|
addPlaySearchCommand(play.command("search <query>"));
|
|
9834
|
-
play.command("grep <query>").description(
|
|
11346
|
+
play.command("grep <query>").description(
|
|
11347
|
+
"Literal grep over play names, aliases, schemas, and descriptions."
|
|
11348
|
+
).addHelpText(
|
|
9835
11349
|
"after",
|
|
9836
11350
|
`
|
|
9837
11351
|
Notes:
|
|
@@ -9917,7 +11431,9 @@ Examples:
|
|
|
9917
11431
|
]);
|
|
9918
11432
|
});
|
|
9919
11433
|
addPublishHelp(
|
|
9920
|
-
play.command("set-live <target>").description(
|
|
11434
|
+
play.command("set-live <target>").description(
|
|
11435
|
+
"Promote a local file or saved revision as the live play revision."
|
|
11436
|
+
)
|
|
9921
11437
|
).option("--latest", "Promote the newest saved revision").option("--revision-id <id>", "Revision to promote").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
|
|
9922
11438
|
process.exitCode = await handlePlayPublish([
|
|
9923
11439
|
target,
|
|
@@ -9962,7 +11478,9 @@ Examples:
|
|
|
9962
11478
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
9963
11479
|
`
|
|
9964
11480
|
);
|
|
9965
|
-
runs.command("get <runId>").description(
|
|
11481
|
+
runs.command("get <runId>").description(
|
|
11482
|
+
"Get status, progress, result, errors, and recovery metadata for a play run."
|
|
11483
|
+
).addHelpText(
|
|
9966
11484
|
"after",
|
|
9967
11485
|
`
|
|
9968
11486
|
Notes:
|
|
@@ -10030,7 +11548,11 @@ Examples:
|
|
|
10030
11548
|
deepline runs logs play/my-play/run/20260501t000000-000 --limit 500
|
|
10031
11549
|
deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
|
|
10032
11550
|
`
|
|
10033
|
-
).option(
|
|
11551
|
+
).option(
|
|
11552
|
+
"--limit <count>",
|
|
11553
|
+
"Maximum recent log lines to print without --out",
|
|
11554
|
+
"200"
|
|
11555
|
+
).option("--out <path>", "Write the full persisted log stream to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
10034
11556
|
process.exitCode = await handleRunLogs([
|
|
10035
11557
|
runId,
|
|
10036
11558
|
...options.limit ? ["--limit", options.limit] : [],
|
|
@@ -10071,7 +11593,10 @@ Examples:
|
|
|
10071
11593
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --metadata-out output.meta.json
|
|
10072
11594
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --json
|
|
10073
11595
|
`
|
|
10074
|
-
).requiredOption("--out <path>", "Output CSV path").option(
|
|
11596
|
+
).requiredOption("--out <path>", "Output CSV path").option(
|
|
11597
|
+
"--dataset <path>",
|
|
11598
|
+
"Returned dataset handle path, such as result.rows"
|
|
11599
|
+
).option("--metadata-out <path>", "Write export metadata JSON to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
10075
11600
|
process.exitCode = await handleRunExport([
|
|
10076
11601
|
runId,
|
|
10077
11602
|
...options.dataset ? ["--dataset", options.dataset] : [],
|
|
@@ -10085,14 +11610,14 @@ Examples:
|
|
|
10085
11610
|
|
|
10086
11611
|
// src/cli/commands/tools.ts
|
|
10087
11612
|
var import_commander2 = require("commander");
|
|
10088
|
-
var
|
|
11613
|
+
var import_node_fs11 = require("fs");
|
|
10089
11614
|
var import_node_os7 = require("os");
|
|
10090
|
-
var
|
|
11615
|
+
var import_node_path13 = require("path");
|
|
10091
11616
|
|
|
10092
11617
|
// src/tool-output.ts
|
|
10093
|
-
var
|
|
11618
|
+
var import_node_fs10 = require("fs");
|
|
10094
11619
|
var import_node_os6 = require("os");
|
|
10095
|
-
var
|
|
11620
|
+
var import_node_path12 = require("path");
|
|
10096
11621
|
function isPlainObject(value) {
|
|
10097
11622
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
10098
11623
|
}
|
|
@@ -10182,19 +11707,19 @@ function tryConvertToList(payload, options) {
|
|
|
10182
11707
|
return null;
|
|
10183
11708
|
}
|
|
10184
11709
|
function ensureOutputDir() {
|
|
10185
|
-
const outputDir = (0,
|
|
10186
|
-
(0,
|
|
11710
|
+
const outputDir = (0, import_node_path12.join)((0, import_node_os6.homedir)(), ".local", "share", "deepline", "data");
|
|
11711
|
+
(0, import_node_fs10.mkdirSync)(outputDir, { recursive: true });
|
|
10187
11712
|
return outputDir;
|
|
10188
11713
|
}
|
|
10189
11714
|
function writeJsonOutputFile(payload, stem) {
|
|
10190
11715
|
const outputDir = ensureOutputDir();
|
|
10191
|
-
const outputPath = (0,
|
|
10192
|
-
(0,
|
|
11716
|
+
const outputPath = (0, import_node_path12.join)(outputDir, `${stem}_${Date.now()}.json`);
|
|
11717
|
+
(0, import_node_fs10.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
10193
11718
|
return outputPath;
|
|
10194
11719
|
}
|
|
10195
11720
|
function writeCsvOutputFile(rows, stem) {
|
|
10196
11721
|
const outputDir = ensureOutputDir();
|
|
10197
|
-
const outputPath = (0,
|
|
11722
|
+
const outputPath = (0, import_node_path12.join)(outputDir, `${stem}_${Date.now()}.csv`);
|
|
10198
11723
|
const seen = /* @__PURE__ */ new Set();
|
|
10199
11724
|
const columns = [];
|
|
10200
11725
|
for (const row of rows) {
|
|
@@ -10217,7 +11742,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
10217
11742
|
for (const row of rows) {
|
|
10218
11743
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
10219
11744
|
}
|
|
10220
|
-
(0,
|
|
11745
|
+
(0, import_node_fs10.writeFileSync)(outputPath, `${lines.join("\n")}
|
|
10221
11746
|
`, "utf-8");
|
|
10222
11747
|
const previewRows = rows.slice(0, 5);
|
|
10223
11748
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -10299,11 +11824,14 @@ async function listTools(args) {
|
|
|
10299
11824
|
const client = new DeeplineClient();
|
|
10300
11825
|
const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
|
|
10301
11826
|
const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
|
|
11827
|
+
const compact = args.includes("--compact");
|
|
10302
11828
|
const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
10303
11829
|
const items = (await client.listTools({
|
|
10304
11830
|
...categoryFilter ? { categories: categoryFilter } : {}
|
|
10305
11831
|
})).map(toListedTool).filter(
|
|
10306
|
-
(item) => requestedCategories.length === 0 || requestedCategories.some(
|
|
11832
|
+
(item) => requestedCategories.length === 0 || requestedCategories.some(
|
|
11833
|
+
(category) => item.categories.includes(category)
|
|
11834
|
+
)
|
|
10307
11835
|
);
|
|
10308
11836
|
const render = {
|
|
10309
11837
|
sections: [
|
|
@@ -10323,10 +11851,11 @@ async function listTools(args) {
|
|
|
10323
11851
|
}
|
|
10324
11852
|
]
|
|
10325
11853
|
};
|
|
11854
|
+
const outputItems = compact ? items.map(compactTool) : items;
|
|
10326
11855
|
printCommandEnvelope(
|
|
10327
11856
|
{
|
|
10328
|
-
tools:
|
|
10329
|
-
count:
|
|
11857
|
+
tools: outputItems,
|
|
11858
|
+
count: outputItems.length,
|
|
10330
11859
|
filters: {
|
|
10331
11860
|
categories: requestedCategories
|
|
10332
11861
|
},
|
|
@@ -10351,7 +11880,11 @@ async function searchTools(queryInput, options = {}) {
|
|
|
10351
11880
|
searchMode: options.searchMode,
|
|
10352
11881
|
includeSearchDebug: options.includeSearchDebug
|
|
10353
11882
|
});
|
|
10354
|
-
|
|
11883
|
+
const payload = options.compact && Array.isArray(result.tools) ? {
|
|
11884
|
+
...result,
|
|
11885
|
+
tools: result.tools.map(compactTool)
|
|
11886
|
+
} : result;
|
|
11887
|
+
printCommandEnvelope(payload, {
|
|
10355
11888
|
json: options.json || shouldEmitJson()
|
|
10356
11889
|
});
|
|
10357
11890
|
return 0;
|
|
@@ -10370,7 +11903,9 @@ async function grepTools(queryInput, options = {}) {
|
|
|
10370
11903
|
grepMode: mode,
|
|
10371
11904
|
...options.categories ? { categories: options.categories } : {}
|
|
10372
11905
|
})).map(toListedTool).filter(
|
|
10373
|
-
(item) => requestedCategories.length === 0 || requestedCategories.some(
|
|
11906
|
+
(item) => requestedCategories.length === 0 || requestedCategories.some(
|
|
11907
|
+
(category) => item.categories.includes(category)
|
|
11908
|
+
)
|
|
10374
11909
|
).filter(
|
|
10375
11910
|
(item) => matchesGrepQuery(
|
|
10376
11911
|
{
|
|
@@ -10388,10 +11923,11 @@ async function grepTools(queryInput, options = {}) {
|
|
|
10388
11923
|
mode
|
|
10389
11924
|
)
|
|
10390
11925
|
);
|
|
11926
|
+
const outputTools = options.compact ? tools.map(compactTool) : tools;
|
|
10391
11927
|
printCommandEnvelope(
|
|
10392
11928
|
{
|
|
10393
|
-
tools,
|
|
10394
|
-
count:
|
|
11929
|
+
tools: outputTools,
|
|
11930
|
+
count: outputTools.length,
|
|
10395
11931
|
query,
|
|
10396
11932
|
grep: {
|
|
10397
11933
|
mode,
|
|
@@ -10406,6 +11942,19 @@ async function grepTools(queryInput, options = {}) {
|
|
|
10406
11942
|
);
|
|
10407
11943
|
return 0;
|
|
10408
11944
|
}
|
|
11945
|
+
function compactTool(tool) {
|
|
11946
|
+
const listed = toListedTool(tool);
|
|
11947
|
+
return {
|
|
11948
|
+
id: listed.id,
|
|
11949
|
+
toolId: listed.toolId,
|
|
11950
|
+
provider: listed.provider,
|
|
11951
|
+
displayName: listed.displayName,
|
|
11952
|
+
description: listed.description,
|
|
11953
|
+
categories: listed.categories,
|
|
11954
|
+
type: listed.type,
|
|
11955
|
+
executeCommand: listed.executeCommand
|
|
11956
|
+
};
|
|
11957
|
+
}
|
|
10409
11958
|
function playIdentifiers(play) {
|
|
10410
11959
|
return [play.name, play.reference, ...play.aliases ?? []].filter((value) => Boolean(value?.trim())).map((value) => value.trim());
|
|
10411
11960
|
}
|
|
@@ -10478,9 +12027,13 @@ Examples:
|
|
|
10478
12027
|
deepline tools list --categories email_finder --json
|
|
10479
12028
|
deepline tools search email --json
|
|
10480
12029
|
`
|
|
10481
|
-
).option(
|
|
12030
|
+
).option(
|
|
12031
|
+
"--categories <categories>",
|
|
12032
|
+
"Comma-separated categories to filter inventory"
|
|
12033
|
+
).option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
10482
12034
|
process.exitCode = await listTools([
|
|
10483
12035
|
...options.categories ? ["--categories", options.categories] : [],
|
|
12036
|
+
...options.compact ? ["--compact"] : [],
|
|
10484
12037
|
...options.json ? ["--json"] : []
|
|
10485
12038
|
]);
|
|
10486
12039
|
});
|
|
@@ -10498,9 +12051,19 @@ Examples:
|
|
|
10498
12051
|
deepline tools grep "company enrichment" --categories enrichment --json
|
|
10499
12052
|
deepline tools search verifier --search-mode v2 --json
|
|
10500
12053
|
`
|
|
10501
|
-
).option(
|
|
12054
|
+
).option(
|
|
12055
|
+
"--categories <categories>",
|
|
12056
|
+
"Comma-separated categories to filter ranked search"
|
|
12057
|
+
).option(
|
|
12058
|
+
"--search_terms <terms>",
|
|
12059
|
+
"Structured search terms for ranked search"
|
|
12060
|
+
).option(
|
|
12061
|
+
"--search-terms <terms>",
|
|
12062
|
+
"Structured search terms for ranked search"
|
|
12063
|
+
).option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
10502
12064
|
process.exitCode = await searchTools(query, {
|
|
10503
12065
|
json: options.json,
|
|
12066
|
+
compact: options.compact,
|
|
10504
12067
|
categories: options.categories,
|
|
10505
12068
|
searchTerms: options.searchTerms ?? options.search_terms,
|
|
10506
12069
|
searchMode: options.searchMode === "v1" || options.searchMode === "v2" ? options.searchMode : void 0,
|
|
@@ -10508,7 +12071,9 @@ Examples:
|
|
|
10508
12071
|
});
|
|
10509
12072
|
});
|
|
10510
12073
|
addToolSearchCommand(tools.command("search <query>"));
|
|
10511
|
-
tools.command("grep <query>").description(
|
|
12074
|
+
tools.command("grep <query>").description(
|
|
12075
|
+
"Literal grep over tool ids, descriptions, categories, and input fields."
|
|
12076
|
+
).addHelpText(
|
|
10512
12077
|
"after",
|
|
10513
12078
|
`
|
|
10514
12079
|
Notes:
|
|
@@ -10522,10 +12087,14 @@ Examples:
|
|
|
10522
12087
|
deepline tools grep "phone validate" --mode all --json
|
|
10523
12088
|
deepline tools grep hunter --mode phrase --json
|
|
10524
12089
|
`
|
|
10525
|
-
).option(
|
|
12090
|
+
).option(
|
|
12091
|
+
"--categories <categories>",
|
|
12092
|
+
"Comma-separated categories to filter inventory"
|
|
12093
|
+
).option("--mode <mode>", "Grep matching mode: all, any, or phrase").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
10526
12094
|
const mode = options.mode === "any" || options.mode === "phrase" ? options.mode : "all";
|
|
10527
12095
|
process.exitCode = await grepTools(query, {
|
|
10528
12096
|
json: options.json,
|
|
12097
|
+
compact: options.compact,
|
|
10529
12098
|
categories: options.categories,
|
|
10530
12099
|
mode
|
|
10531
12100
|
});
|
|
@@ -10546,7 +12115,20 @@ Examples:
|
|
|
10546
12115
|
deepline tools describe hunter_email_verifier --json
|
|
10547
12116
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
10548
12117
|
`
|
|
10549
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--pricing-only", "Only print pricing and billing semantics").option("--schema-only", "Only print input schema fields").option(
|
|
12118
|
+
).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(
|
|
12119
|
+
"--examples-only",
|
|
12120
|
+
"Only print runnable examples and sample payloads"
|
|
12121
|
+
).option("--getters-only", "Only print extracted list/value getters").addOption(
|
|
12122
|
+
new import_commander2.Option(
|
|
12123
|
+
"--compact",
|
|
12124
|
+
"Compatibility alias for the default compact view"
|
|
12125
|
+
).hideHelp()
|
|
12126
|
+
).addOption(
|
|
12127
|
+
new import_commander2.Option(
|
|
12128
|
+
"--contract-json",
|
|
12129
|
+
"Compatibility alias for compact contract JSON"
|
|
12130
|
+
).hideHelp()
|
|
12131
|
+
).action(async (toolId, options) => {
|
|
10550
12132
|
process.exitCode = await getTool(toolId, {
|
|
10551
12133
|
json: Boolean(options.json),
|
|
10552
12134
|
compact: Boolean(options.compact),
|
|
@@ -10588,13 +12170,24 @@ Examples:
|
|
|
10588
12170
|
deepline tools execute hunter_email_verifier -p email=a@b.com
|
|
10589
12171
|
deepline tools execute test_rate_limit --input '{"key":"smoke"}' --json | jq '.status'
|
|
10590
12172
|
`
|
|
10591
|
-
).option(
|
|
10592
|
-
|
|
10593
|
-
|
|
10594
|
-
|
|
12173
|
+
).option(
|
|
12174
|
+
"-p, --param <key=value>",
|
|
12175
|
+
"Pass one parameter. Repeat for multiple values.",
|
|
12176
|
+
(value, acc) => {
|
|
12177
|
+
acc.push(value);
|
|
12178
|
+
return acc;
|
|
12179
|
+
},
|
|
12180
|
+
[]
|
|
12181
|
+
).option(
|
|
12182
|
+
"--json [payload]",
|
|
12183
|
+
"Emit JSON output. Use `--input` or `--payload` for passing JSON params."
|
|
12184
|
+
).option("--input <payload>", "Merge a JSON object into the tool params").option("--payload <payload>", "Merge a JSON object into the tool params").option(
|
|
10595
12185
|
"--output-format <format>",
|
|
10596
12186
|
"Output format: auto, csv, csv_file, json, or json_file"
|
|
10597
|
-
).option(
|
|
12187
|
+
).option(
|
|
12188
|
+
"--no-preview",
|
|
12189
|
+
"Only print the extracted output path when applicable"
|
|
12190
|
+
).action(async (toolId, options) => {
|
|
10598
12191
|
const args = [
|
|
10599
12192
|
toolId,
|
|
10600
12193
|
...options.param.flatMap((value) => ["--param", value]),
|
|
@@ -10626,14 +12219,18 @@ async function getTool(toolId, options = {}) {
|
|
|
10626
12219
|
throw error;
|
|
10627
12220
|
}
|
|
10628
12221
|
if (options.contractJson) {
|
|
10629
|
-
process.stdout.write(
|
|
10630
|
-
|
|
12222
|
+
process.stdout.write(
|
|
12223
|
+
`${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
|
|
12224
|
+
`
|
|
12225
|
+
);
|
|
10631
12226
|
return 0;
|
|
10632
12227
|
}
|
|
10633
12228
|
const emitJson = options.json === true;
|
|
10634
12229
|
if (emitJson) {
|
|
10635
|
-
process.stdout.write(
|
|
10636
|
-
|
|
12230
|
+
process.stdout.write(
|
|
12231
|
+
`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
|
|
12232
|
+
`
|
|
12233
|
+
);
|
|
10637
12234
|
return 0;
|
|
10638
12235
|
}
|
|
10639
12236
|
const onlyModes = [
|
|
@@ -10643,7 +12240,9 @@ async function getTool(toolId, options = {}) {
|
|
|
10643
12240
|
options.gettersOnly
|
|
10644
12241
|
].filter(Boolean).length;
|
|
10645
12242
|
if (onlyModes > 1) {
|
|
10646
|
-
console.error(
|
|
12243
|
+
console.error(
|
|
12244
|
+
"Use only one of --pricing-only, --schema-only, --examples-only, or --getters-only."
|
|
12245
|
+
);
|
|
10647
12246
|
return 2;
|
|
10648
12247
|
}
|
|
10649
12248
|
if (options.pricingOnly) {
|
|
@@ -10667,8 +12266,10 @@ async function getTool(toolId, options = {}) {
|
|
|
10667
12266
|
return 0;
|
|
10668
12267
|
}
|
|
10669
12268
|
if (shouldEmitJson()) {
|
|
10670
|
-
process.stdout.write(
|
|
10671
|
-
|
|
12269
|
+
process.stdout.write(
|
|
12270
|
+
`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
|
|
12271
|
+
`
|
|
12272
|
+
);
|
|
10672
12273
|
return 0;
|
|
10673
12274
|
}
|
|
10674
12275
|
printCompactToolContract(tool, toolId);
|
|
@@ -10676,9 +12277,15 @@ async function getTool(toolId, options = {}) {
|
|
|
10676
12277
|
}
|
|
10677
12278
|
function toolContractJsonForDescribe(tool, requestedToolId) {
|
|
10678
12279
|
const toolId = String(tool.toolId || requestedToolId);
|
|
10679
|
-
const inputFields = toolInputFieldsForDisplay(
|
|
12280
|
+
const inputFields = toolInputFieldsForDisplay(
|
|
12281
|
+
recordField(tool, "inputSchema", "input_schema")
|
|
12282
|
+
);
|
|
10680
12283
|
const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
|
|
10681
|
-
const toolExecutionResult = recordField(
|
|
12284
|
+
const toolExecutionResult = recordField(
|
|
12285
|
+
usageGuidance,
|
|
12286
|
+
"toolExecutionResult",
|
|
12287
|
+
"tool_execution_result"
|
|
12288
|
+
);
|
|
10682
12289
|
const extractedLists = extractionContractEntries(
|
|
10683
12290
|
arrayField(toolExecutionResult, "extractedLists", "extracted_lists")
|
|
10684
12291
|
);
|
|
@@ -10731,7 +12338,7 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
|
|
|
10731
12338
|
}
|
|
10732
12339
|
function extractionContractEntries(entries) {
|
|
10733
12340
|
return entries.flatMap((entry) => {
|
|
10734
|
-
if (!
|
|
12341
|
+
if (!isRecord5(entry)) return [];
|
|
10735
12342
|
const name = stringField(entry, "name");
|
|
10736
12343
|
const expression = stringField(entry, "expression");
|
|
10737
12344
|
return name && expression ? [{ name, expression }] : [];
|
|
@@ -10739,8 +12346,8 @@ function extractionContractEntries(entries) {
|
|
|
10739
12346
|
}
|
|
10740
12347
|
function printCompactToolContract(tool, requestedToolId) {
|
|
10741
12348
|
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10742
|
-
const cost =
|
|
10743
|
-
const getters =
|
|
12349
|
+
const cost = isRecord5(contract.cost) ? contract.cost : {};
|
|
12350
|
+
const getters = isRecord5(contract.getters) ? contract.getters : {};
|
|
10744
12351
|
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
10745
12352
|
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
10746
12353
|
const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
|
|
@@ -10757,18 +12364,20 @@ function printCompactToolContract(tool, requestedToolId) {
|
|
|
10757
12364
|
console.log("");
|
|
10758
12365
|
console.log("Inputs:");
|
|
10759
12366
|
for (const field of inputFields) {
|
|
10760
|
-
if (!
|
|
12367
|
+
if (!isRecord5(field)) continue;
|
|
10761
12368
|
const name = stringField(field, "name");
|
|
10762
12369
|
if (!name) continue;
|
|
10763
12370
|
const required = field.required ? "*" : "";
|
|
10764
12371
|
const type = stringField(field, "type") || "unknown";
|
|
10765
12372
|
const description = stringField(field, "description");
|
|
10766
|
-
console.log(
|
|
12373
|
+
console.log(
|
|
12374
|
+
`- ${name}${required}: ${type}${description ? ` - ${description}` : ""}`
|
|
12375
|
+
);
|
|
10767
12376
|
}
|
|
10768
12377
|
}
|
|
10769
12378
|
console.log("");
|
|
10770
12379
|
printToolExamplesOnly(tool, requestedToolId, { includeSamples: false });
|
|
10771
|
-
const starterScript =
|
|
12380
|
+
const starterScript = isRecord5(contract.starterScript) ? contract.starterScript : {};
|
|
10772
12381
|
const starterPath = stringField(starterScript, "path");
|
|
10773
12382
|
if (starterPath) {
|
|
10774
12383
|
console.log("");
|
|
@@ -10780,19 +12389,27 @@ function printCompactToolContract(tool, requestedToolId) {
|
|
|
10780
12389
|
console.log("Getters:");
|
|
10781
12390
|
if (listGetters.length) console.log("Lists:");
|
|
10782
12391
|
for (const entry of listGetters) {
|
|
10783
|
-
if (
|
|
12392
|
+
if (isRecord5(entry))
|
|
12393
|
+
console.log(
|
|
12394
|
+
`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
|
|
12395
|
+
);
|
|
10784
12396
|
}
|
|
10785
12397
|
if (valueGetters.length) console.log("Values:");
|
|
10786
12398
|
for (const entry of valueGetters) {
|
|
10787
|
-
if (
|
|
12399
|
+
if (isRecord5(entry))
|
|
12400
|
+
console.log(
|
|
12401
|
+
`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
|
|
12402
|
+
);
|
|
10788
12403
|
}
|
|
10789
12404
|
}
|
|
10790
12405
|
console.log("");
|
|
10791
|
-
console.log(
|
|
12406
|
+
console.log(
|
|
12407
|
+
`More: deepline tools describe ${contract.toolId} --pricing-only | --schema-only | --examples-only | --getters-only | --json`
|
|
12408
|
+
);
|
|
10792
12409
|
}
|
|
10793
12410
|
function printToolPricingOnly(tool, requestedToolId, options = {}) {
|
|
10794
12411
|
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10795
|
-
const cost =
|
|
12412
|
+
const cost = isRecord5(contract.cost) ? contract.cost : {};
|
|
10796
12413
|
const pricingModel = stringField(cost, "pricingModel") || "unknown";
|
|
10797
12414
|
const billingMode = stringField(cost, "billingMode") || "unknown";
|
|
10798
12415
|
const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : pricingModel === "fixed" ? "call" : pricingModel.replace(/^per_/, "") || "unit";
|
|
@@ -10812,14 +12429,16 @@ function printToolSchemaOnly(tool, requestedToolId) {
|
|
|
10812
12429
|
}
|
|
10813
12430
|
console.log("Inputs:");
|
|
10814
12431
|
for (const field of inputFields) {
|
|
10815
|
-
if (!
|
|
12432
|
+
if (!isRecord5(field)) continue;
|
|
10816
12433
|
const name = stringField(field, "name");
|
|
10817
12434
|
if (!name) continue;
|
|
10818
12435
|
const required = field.required ? "*" : "";
|
|
10819
12436
|
const type = stringField(field, "type") || "unknown";
|
|
10820
12437
|
const description = stringField(field, "description");
|
|
10821
12438
|
const defaultSuffix = Object.prototype.hasOwnProperty.call(field, "default") ? ` default=${JSON.stringify(field.default)}` : "";
|
|
10822
|
-
console.log(
|
|
12439
|
+
console.log(
|
|
12440
|
+
`- ${name}${required}: ${type}${defaultSuffix}${description ? ` - ${description}` : ""}`
|
|
12441
|
+
);
|
|
10823
12442
|
}
|
|
10824
12443
|
}
|
|
10825
12444
|
function printToolExamplesOnly(tool, requestedToolId, options = {}) {
|
|
@@ -10832,16 +12451,21 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
|
|
|
10832
12451
|
console.log("const result = await ctx.tools.execute({");
|
|
10833
12452
|
console.log(` id: '${stableStepIdForTool(toolId)}',`);
|
|
10834
12453
|
console.log(` tool: '${toolId}',`);
|
|
10835
|
-
console.log(
|
|
12454
|
+
console.log(
|
|
12455
|
+
` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`
|
|
12456
|
+
);
|
|
10836
12457
|
console.log("});");
|
|
10837
|
-
const getters =
|
|
12458
|
+
const getters = isRecord5(contract.getters) ? contract.getters : {};
|
|
10838
12459
|
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
10839
12460
|
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
10840
|
-
const firstGetter = [...valueGetters, ...listGetters].find(
|
|
12461
|
+
const firstGetter = [...valueGetters, ...listGetters].find(isRecord5);
|
|
10841
12462
|
if (firstGetter) {
|
|
10842
12463
|
const name = stringField(firstGetter, "name") || "value";
|
|
10843
12464
|
const expression = stringField(firstGetter, "expression");
|
|
10844
|
-
if (expression)
|
|
12465
|
+
if (expression)
|
|
12466
|
+
console.log(
|
|
12467
|
+
`const ${safeIdentifier2(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`
|
|
12468
|
+
);
|
|
10845
12469
|
}
|
|
10846
12470
|
console.log("```");
|
|
10847
12471
|
if (options.includeSamples !== false) {
|
|
@@ -10851,31 +12475,40 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
|
|
|
10851
12475
|
}
|
|
10852
12476
|
function printToolGettersOnly(tool, requestedToolId) {
|
|
10853
12477
|
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10854
|
-
const getters =
|
|
12478
|
+
const getters = isRecord5(contract.getters) ? contract.getters : {};
|
|
10855
12479
|
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
10856
12480
|
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
10857
12481
|
console.log(`Getters: ${contract.toolId}`);
|
|
10858
12482
|
if (!listGetters.length && !valueGetters.length) {
|
|
10859
|
-
console.log(
|
|
12483
|
+
console.log(
|
|
12484
|
+
"No generated getters declared. Use --json only if you need raw metadata."
|
|
12485
|
+
);
|
|
10860
12486
|
return;
|
|
10861
12487
|
}
|
|
10862
12488
|
if (listGetters.length) {
|
|
10863
12489
|
console.log("Lists:");
|
|
10864
12490
|
for (const entry of listGetters) {
|
|
10865
|
-
if (
|
|
12491
|
+
if (isRecord5(entry))
|
|
12492
|
+
console.log(
|
|
12493
|
+
`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
|
|
12494
|
+
);
|
|
10866
12495
|
}
|
|
10867
12496
|
}
|
|
10868
12497
|
if (valueGetters.length) {
|
|
10869
12498
|
console.log("Values:");
|
|
10870
12499
|
for (const entry of valueGetters) {
|
|
10871
|
-
if (
|
|
12500
|
+
if (isRecord5(entry))
|
|
12501
|
+
console.log(
|
|
12502
|
+
`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
|
|
12503
|
+
);
|
|
10872
12504
|
}
|
|
10873
12505
|
}
|
|
10874
12506
|
}
|
|
10875
12507
|
function sampleValueForField(field) {
|
|
10876
12508
|
const name = stringField(field, "name").toLowerCase();
|
|
10877
12509
|
const type = stringField(field, "type").toLowerCase();
|
|
10878
|
-
if (Object.prototype.hasOwnProperty.call(field, "default"))
|
|
12510
|
+
if (Object.prototype.hasOwnProperty.call(field, "default"))
|
|
12511
|
+
return field.default;
|
|
10879
12512
|
if (name.includes("email")) return "ada@example.com";
|
|
10880
12513
|
if (name.includes("domain") || name.includes("website")) return "example.com";
|
|
10881
12514
|
if (name.includes("first")) return "Ada";
|
|
@@ -10890,7 +12523,7 @@ function sampleValueForField(field) {
|
|
|
10890
12523
|
function samplePayloadForInputFields(fields) {
|
|
10891
12524
|
return Object.fromEntries(
|
|
10892
12525
|
fields.slice(0, 4).flatMap((field) => {
|
|
10893
|
-
if (!
|
|
12526
|
+
if (!isRecord5(field)) return [];
|
|
10894
12527
|
const name = stringField(field, "name");
|
|
10895
12528
|
if (!name) return [];
|
|
10896
12529
|
return [[name, sampleValueForField(field)]];
|
|
@@ -10900,12 +12533,15 @@ function samplePayloadForInputFields(fields) {
|
|
|
10900
12533
|
function stableStepIdForTool(toolId) {
|
|
10901
12534
|
return toolId.replace(/^[a-z0-9]+_/, "").replace(/[^a-z0-9_]+/gi, "_") || "tool_call";
|
|
10902
12535
|
}
|
|
10903
|
-
function
|
|
12536
|
+
function safeIdentifier2(name) {
|
|
10904
12537
|
const cleaned = name.replace(/[^a-zA-Z0-9_$]+/g, "_").replace(/^[^a-zA-Z_$]+/, "");
|
|
10905
12538
|
return cleaned || "value";
|
|
10906
12539
|
}
|
|
10907
12540
|
function playResultExpression(entry) {
|
|
10908
|
-
return stringField(entry, "expression").replace(
|
|
12541
|
+
return stringField(entry, "expression").replace(
|
|
12542
|
+
/^toolExecutionResult\./,
|
|
12543
|
+
"result."
|
|
12544
|
+
);
|
|
10909
12545
|
}
|
|
10910
12546
|
function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
10911
12547
|
const toolId = String(tool.toolId || requestedToolId);
|
|
@@ -10996,12 +12632,13 @@ function formatListedToolCost(tool) {
|
|
|
10996
12632
|
return displayText ? `Cost: ${displayText}` : "";
|
|
10997
12633
|
}
|
|
10998
12634
|
function toolInputFieldsForDisplay(inputSchema) {
|
|
10999
|
-
if (Array.isArray(inputSchema.fields))
|
|
11000
|
-
|
|
11001
|
-
const
|
|
12635
|
+
if (Array.isArray(inputSchema.fields))
|
|
12636
|
+
return inputSchema.fields.filter(isRecord5);
|
|
12637
|
+
const jsonSchema = isRecord5(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
|
|
12638
|
+
const properties = isRecord5(jsonSchema.properties) ? jsonSchema.properties : {};
|
|
11002
12639
|
const required = Array.isArray(jsonSchema.required) ? new Set(jsonSchema.required.map(String)) : /* @__PURE__ */ new Set();
|
|
11003
12640
|
return Object.entries(properties).map(([name, value]) => {
|
|
11004
|
-
const property =
|
|
12641
|
+
const property = isRecord5(value) ? value : {};
|
|
11005
12642
|
return {
|
|
11006
12643
|
name,
|
|
11007
12644
|
type: typeof property.type === "string" ? property.type : "unknown",
|
|
@@ -11016,8 +12653,10 @@ function printSamples(samples) {
|
|
|
11016
12653
|
const responsePayload = samplePayload(samples, "response");
|
|
11017
12654
|
if (requestPayload === void 0 && responsePayload === void 0) return;
|
|
11018
12655
|
console.log(" Samples:");
|
|
11019
|
-
if (requestPayload !== void 0)
|
|
11020
|
-
|
|
12656
|
+
if (requestPayload !== void 0)
|
|
12657
|
+
printJsonPreview("Example payload", requestPayload);
|
|
12658
|
+
if (responsePayload !== void 0)
|
|
12659
|
+
printJsonPreview("Example response", responsePayload);
|
|
11021
12660
|
}
|
|
11022
12661
|
function printJsonPreview(label, payload) {
|
|
11023
12662
|
console.log(` ${label}:`);
|
|
@@ -11028,15 +12667,15 @@ function printJsonPreview(label, payload) {
|
|
|
11028
12667
|
}
|
|
11029
12668
|
function samplePayload(samples, key) {
|
|
11030
12669
|
const entry = samples[key];
|
|
11031
|
-
if (!
|
|
12670
|
+
if (!isRecord5(entry)) return void 0;
|
|
11032
12671
|
return Object.prototype.hasOwnProperty.call(entry, "payload") ? entry.payload : entry;
|
|
11033
12672
|
}
|
|
11034
12673
|
function commandEnvelopeFromRawResponse(rawResponse) {
|
|
11035
|
-
return
|
|
12674
|
+
return isRecord5(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
|
|
11036
12675
|
}
|
|
11037
12676
|
function listExtractorPathsFromUsageGuidance(tool) {
|
|
11038
12677
|
const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
|
|
11039
|
-
const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists :
|
|
12678
|
+
const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord5(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
|
|
11040
12679
|
return extractedLists.flatMap((entry) => {
|
|
11041
12680
|
const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
|
|
11042
12681
|
if (!Array.isArray(paths)) return [];
|
|
@@ -11052,7 +12691,7 @@ function formatDecimal(value) {
|
|
|
11052
12691
|
function formatUsd(value) {
|
|
11053
12692
|
return `$${formatDecimal(value)}`;
|
|
11054
12693
|
}
|
|
11055
|
-
function
|
|
12694
|
+
function isRecord5(value) {
|
|
11056
12695
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
11057
12696
|
}
|
|
11058
12697
|
function stringField(source, ...keys) {
|
|
@@ -11079,7 +12718,7 @@ function arrayField(source, ...keys) {
|
|
|
11079
12718
|
function recordField(source, ...keys) {
|
|
11080
12719
|
for (const key of keys) {
|
|
11081
12720
|
const value = source[key];
|
|
11082
|
-
if (
|
|
12721
|
+
if (isRecord5(value)) return value;
|
|
11083
12722
|
}
|
|
11084
12723
|
return {};
|
|
11085
12724
|
}
|
|
@@ -11102,7 +12741,9 @@ function normalizeOutputFormat(raw) {
|
|
|
11102
12741
|
function parseExecuteOptions(args) {
|
|
11103
12742
|
const toolId = args[0];
|
|
11104
12743
|
if (!toolId) {
|
|
11105
|
-
throw new Error(
|
|
12744
|
+
throw new Error(
|
|
12745
|
+
`Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--no-preview]`
|
|
12746
|
+
);
|
|
11106
12747
|
}
|
|
11107
12748
|
const params = {};
|
|
11108
12749
|
let outputFormat = "auto";
|
|
@@ -11151,9 +12792,9 @@ function powerShellQuote(value) {
|
|
|
11151
12792
|
function seedToolListScript(input) {
|
|
11152
12793
|
const stem = safeFileStem(input.toolId);
|
|
11153
12794
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
11154
|
-
const scriptDir = (0,
|
|
11155
|
-
(0,
|
|
11156
|
-
const scriptPath = (0,
|
|
12795
|
+
const scriptDir = (0, import_node_fs11.mkdtempSync)((0, import_node_path13.join)((0, import_node_os7.tmpdir)(), "deepline-workflow-seed-"));
|
|
12796
|
+
(0, import_node_fs11.chmodSync)(scriptDir, 448);
|
|
12797
|
+
const scriptPath = (0, import_node_path13.join)(scriptDir, fileName);
|
|
11157
12798
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
11158
12799
|
const playName = `${stem}-workflow`;
|
|
11159
12800
|
const sampleRows = input.rows.length > 0 ? `${JSON.stringify(input.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
@@ -11189,7 +12830,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
11189
12830
|
};
|
|
11190
12831
|
});
|
|
11191
12832
|
`;
|
|
11192
|
-
(0,
|
|
12833
|
+
(0, import_node_fs11.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
11193
12834
|
return {
|
|
11194
12835
|
path: scriptPath,
|
|
11195
12836
|
sourceCode: script,
|
|
@@ -11212,7 +12853,7 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
11212
12853
|
kind: summaryEntries.length > 0 ? "object" : "raw",
|
|
11213
12854
|
summary: input.summary
|
|
11214
12855
|
};
|
|
11215
|
-
const envelopeHasCanonicalOutput =
|
|
12856
|
+
const envelopeHasCanonicalOutput = isRecord5(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
|
|
11216
12857
|
const inspectCommand = `deepline tools execute ${input.toolId} --input ${shellQuote(JSON.stringify(input.params))} --json`;
|
|
11217
12858
|
const actions = input.listConversion ? [
|
|
11218
12859
|
{
|
|
@@ -11246,7 +12887,9 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
11246
12887
|
] : [
|
|
11247
12888
|
{
|
|
11248
12889
|
title: "result",
|
|
11249
|
-
lines: summaryEntries.length > 0 ? summaryEntries.map(
|
|
12890
|
+
lines: summaryEntries.length > 0 ? summaryEntries.map(
|
|
12891
|
+
([key, value]) => `${key}=${String(value)}`
|
|
12892
|
+
) : [JSON.stringify(input.rawResponse, null, 2)]
|
|
11250
12893
|
}
|
|
11251
12894
|
],
|
|
11252
12895
|
actions
|
|
@@ -11273,7 +12916,9 @@ async function executeTool(args) {
|
|
|
11273
12916
|
const play = await findPlayForToolId(client, parsed.toolId);
|
|
11274
12917
|
if (play) {
|
|
11275
12918
|
if (argsWantJson(args)) {
|
|
11276
|
-
printJsonError(
|
|
12919
|
+
printJsonError(
|
|
12920
|
+
new Error(playAliasToolErrorMessage(parsed.toolId, play))
|
|
12921
|
+
);
|
|
11277
12922
|
} else {
|
|
11278
12923
|
printPlayAliasToolError(parsed.toolId, play);
|
|
11279
12924
|
}
|
|
@@ -11309,12 +12954,15 @@ async function executeTool(args) {
|
|
|
11309
12954
|
return 0;
|
|
11310
12955
|
}
|
|
11311
12956
|
if (parsed.outputFormat === "json_file") {
|
|
11312
|
-
const jsonPath = writeJsonOutputFile(
|
|
12957
|
+
const jsonPath = writeJsonOutputFile(
|
|
12958
|
+
rawResponse,
|
|
12959
|
+
`payload_${parsed.toolId}`
|
|
12960
|
+
);
|
|
11313
12961
|
printCommandEnvelope(
|
|
11314
12962
|
{
|
|
11315
12963
|
...baseEnvelope,
|
|
11316
12964
|
local: {
|
|
11317
|
-
...
|
|
12965
|
+
...isRecord5(baseEnvelope.local) ? baseEnvelope.local : {},
|
|
11318
12966
|
payload_file: jsonPath
|
|
11319
12967
|
}
|
|
11320
12968
|
},
|
|
@@ -11324,7 +12972,10 @@ async function executeTool(args) {
|
|
|
11324
12972
|
}
|
|
11325
12973
|
if (!listConversion) {
|
|
11326
12974
|
if (parsed.outputFormat === "csv" || parsed.outputFormat === "csv_file") {
|
|
11327
|
-
const jsonPath = writeJsonOutputFile(
|
|
12975
|
+
const jsonPath = writeJsonOutputFile(
|
|
12976
|
+
rawResponse,
|
|
12977
|
+
`payload_${parsed.toolId}`
|
|
12978
|
+
);
|
|
11328
12979
|
printCommandEnvelope(
|
|
11329
12980
|
{
|
|
11330
12981
|
...baseEnvelope,
|
|
@@ -11339,7 +12990,10 @@ async function executeTool(args) {
|
|
|
11339
12990
|
printCommandEnvelope(baseEnvelope, { json: false });
|
|
11340
12991
|
return 0;
|
|
11341
12992
|
}
|
|
11342
|
-
const csv = writeCsvOutputFile(
|
|
12993
|
+
const csv = writeCsvOutputFile(
|
|
12994
|
+
listConversion.rows,
|
|
12995
|
+
`${parsed.toolId}_output`
|
|
12996
|
+
);
|
|
11343
12997
|
const seededScript = seedToolListScript({
|
|
11344
12998
|
toolId: parsed.toolId,
|
|
11345
12999
|
payload: parsed.params,
|
|
@@ -11365,7 +13019,9 @@ async function executeTool(args) {
|
|
|
11365
13019
|
title: `${csv.path} (${csv.rowCount} rows)`,
|
|
11366
13020
|
lines: [
|
|
11367
13021
|
...csv.columns.length > 0 ? [`columns: ${JSON.stringify(csv.columns)}`] : [],
|
|
11368
|
-
...Object.keys(summary).length > 0 ? [
|
|
13022
|
+
...Object.keys(summary).length > 0 ? [
|
|
13023
|
+
`summary: ${Object.entries(summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`
|
|
13024
|
+
] : [],
|
|
11369
13025
|
`preview: ${JSON.stringify(csv.preview)}`,
|
|
11370
13026
|
`starter script: ${seededScript.path}`
|
|
11371
13027
|
]
|
|
@@ -11388,22 +13044,25 @@ async function executeTool(args) {
|
|
|
11388
13044
|
}
|
|
11389
13045
|
};
|
|
11390
13046
|
if (parsed.outputFormat === "csv_file") {
|
|
11391
|
-
printCommandEnvelope(
|
|
11392
|
-
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
|
|
11402
|
-
|
|
11403
|
-
|
|
13047
|
+
printCommandEnvelope(
|
|
13048
|
+
{
|
|
13049
|
+
...materializedEnvelope,
|
|
13050
|
+
extracted_csv: csv.path,
|
|
13051
|
+
extracted_csv_rows: csv.rowCount,
|
|
13052
|
+
extracted_csv_columns: csv.columns,
|
|
13053
|
+
preview: csv.preview,
|
|
13054
|
+
list_strategy: listConversion.strategy,
|
|
13055
|
+
list_source_path: listConversion.sourcePath,
|
|
13056
|
+
starter_script: seededScript.path,
|
|
13057
|
+
project_dir: seededScript.projectDir,
|
|
13058
|
+
copy_to_project: {
|
|
13059
|
+
macos_linux: seededScript.macCopyCommand,
|
|
13060
|
+
windows_powershell: seededScript.windowsCopyCommand
|
|
13061
|
+
},
|
|
13062
|
+
summary
|
|
11404
13063
|
},
|
|
11405
|
-
|
|
11406
|
-
|
|
13064
|
+
{ json: true }
|
|
13065
|
+
);
|
|
11407
13066
|
return 0;
|
|
11408
13067
|
}
|
|
11409
13068
|
if (parsed.noPreview) {
|
|
@@ -11426,8 +13085,8 @@ async function executeTool(args) {
|
|
|
11426
13085
|
|
|
11427
13086
|
// src/cli/commands/update.ts
|
|
11428
13087
|
var import_node_child_process = require("child_process");
|
|
11429
|
-
var
|
|
11430
|
-
var
|
|
13088
|
+
var import_node_fs12 = require("fs");
|
|
13089
|
+
var import_node_path14 = require("path");
|
|
11431
13090
|
function posixShellQuote(value) {
|
|
11432
13091
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
11433
13092
|
}
|
|
@@ -11446,19 +13105,19 @@ function buildSourceUpdateCommand(sourceRoot) {
|
|
|
11446
13105
|
return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
|
|
11447
13106
|
}
|
|
11448
13107
|
function findRepoBackedSdkRoot(startPath) {
|
|
11449
|
-
let current = (0,
|
|
13108
|
+
let current = (0, import_node_path14.resolve)(startPath);
|
|
11450
13109
|
while (true) {
|
|
11451
|
-
if ((0,
|
|
13110
|
+
if ((0, import_node_fs12.existsSync)((0, import_node_path14.join)(current, "sdk", "package.json")) && (0, import_node_fs12.existsSync)((0, import_node_path14.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
|
|
11452
13111
|
return current;
|
|
11453
13112
|
}
|
|
11454
|
-
const parent = (0,
|
|
13113
|
+
const parent = (0, import_node_path14.dirname)(current);
|
|
11455
13114
|
if (parent === current) return null;
|
|
11456
13115
|
current = parent;
|
|
11457
13116
|
}
|
|
11458
13117
|
}
|
|
11459
13118
|
function resolveUpdatePlan() {
|
|
11460
|
-
const entrypoint = process.argv[1] ? (0,
|
|
11461
|
-
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0,
|
|
13119
|
+
const entrypoint = process.argv[1] ? (0, import_node_path14.resolve)(process.argv[1]) : "";
|
|
13120
|
+
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path14.dirname)(entrypoint)) : null;
|
|
11462
13121
|
if (sourceRoot) {
|
|
11463
13122
|
return {
|
|
11464
13123
|
kind: "source",
|
|
@@ -11551,9 +13210,9 @@ Examples:
|
|
|
11551
13210
|
|
|
11552
13211
|
// src/cli/skills-sync.ts
|
|
11553
13212
|
var import_node_child_process2 = require("child_process");
|
|
11554
|
-
var
|
|
13213
|
+
var import_node_fs13 = require("fs");
|
|
11555
13214
|
var import_node_os8 = require("os");
|
|
11556
|
-
var
|
|
13215
|
+
var import_node_path15 = require("path");
|
|
11557
13216
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
11558
13217
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
11559
13218
|
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
@@ -11564,28 +13223,28 @@ function shouldSkipSkillsSync() {
|
|
|
11564
13223
|
}
|
|
11565
13224
|
function sdkSkillsVersionPath(baseUrl) {
|
|
11566
13225
|
const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
|
|
11567
|
-
return (0,
|
|
13226
|
+
return (0, import_node_path15.join)(home, ".local", "deepline", baseUrlSlug(baseUrl), "sdk-skills", ".version");
|
|
11568
13227
|
}
|
|
11569
13228
|
function readLocalSkillsVersion(baseUrl) {
|
|
11570
13229
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
11571
|
-
if (!(0,
|
|
13230
|
+
if (!(0, import_node_fs13.existsSync)(path)) return "";
|
|
11572
13231
|
try {
|
|
11573
|
-
return (0,
|
|
13232
|
+
return (0, import_node_fs13.readFileSync)(path, "utf-8").trim();
|
|
11574
13233
|
} catch {
|
|
11575
13234
|
return "";
|
|
11576
13235
|
}
|
|
11577
13236
|
}
|
|
11578
13237
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
11579
13238
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
11580
|
-
(0,
|
|
11581
|
-
(0,
|
|
13239
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path15.dirname)(path), { recursive: true });
|
|
13240
|
+
(0, import_node_fs13.writeFileSync)(path, `${version}
|
|
11582
13241
|
`, "utf-8");
|
|
11583
13242
|
}
|
|
11584
13243
|
function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
11585
13244
|
const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
|
|
11586
13245
|
const roots = [
|
|
11587
|
-
(0,
|
|
11588
|
-
(0,
|
|
13246
|
+
(0, import_node_path15.join)(home, ".claude", "skills", SDK_SKILL_NAME),
|
|
13247
|
+
(0, import_node_path15.join)(home, ".agents", "skills", SDK_SKILL_NAME)
|
|
11589
13248
|
];
|
|
11590
13249
|
const staleMarkers = [
|
|
11591
13250
|
"ctx.tools.execute(key",
|
|
@@ -11595,22 +13254,22 @@ function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
|
11595
13254
|
'rowCtx.tools.execute("'
|
|
11596
13255
|
];
|
|
11597
13256
|
const scan = (dir) => {
|
|
11598
|
-
for (const entry of (0,
|
|
11599
|
-
const path = (0,
|
|
11600
|
-
const stat3 = (0,
|
|
13257
|
+
for (const entry of (0, import_node_fs13.readdirSync)(dir)) {
|
|
13258
|
+
const path = (0, import_node_path15.join)(dir, entry);
|
|
13259
|
+
const stat3 = (0, import_node_fs13.statSync)(path);
|
|
11601
13260
|
if (stat3.isDirectory()) {
|
|
11602
13261
|
if (scan(path)) return true;
|
|
11603
13262
|
continue;
|
|
11604
13263
|
}
|
|
11605
13264
|
if (!entry.endsWith(".md")) continue;
|
|
11606
|
-
const text = (0,
|
|
13265
|
+
const text = (0, import_node_fs13.readFileSync)(path, "utf-8");
|
|
11607
13266
|
if (staleMarkers.some((marker) => text.includes(marker))) return true;
|
|
11608
13267
|
}
|
|
11609
13268
|
return false;
|
|
11610
13269
|
};
|
|
11611
13270
|
for (const root of roots) {
|
|
11612
13271
|
try {
|
|
11613
|
-
if ((0,
|
|
13272
|
+
if ((0, import_node_fs13.existsSync)(root) && scan(root)) return true;
|
|
11614
13273
|
} catch {
|
|
11615
13274
|
continue;
|
|
11616
13275
|
}
|
|
@@ -11708,7 +13367,7 @@ function resolveSkillsInstallCommands(baseUrl) {
|
|
|
11708
13367
|
return [npxInstall];
|
|
11709
13368
|
}
|
|
11710
13369
|
function runOneSkillsInstall(install) {
|
|
11711
|
-
return new Promise((
|
|
13370
|
+
return new Promise((resolve12) => {
|
|
11712
13371
|
const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
|
|
11713
13372
|
stdio: ["ignore", "ignore", "pipe"],
|
|
11714
13373
|
env: process.env
|
|
@@ -11718,7 +13377,7 @@ function runOneSkillsInstall(install) {
|
|
|
11718
13377
|
stderr += chunk.toString("utf-8");
|
|
11719
13378
|
});
|
|
11720
13379
|
child.on("error", (error) => {
|
|
11721
|
-
|
|
13380
|
+
resolve12({
|
|
11722
13381
|
ok: false,
|
|
11723
13382
|
detail: `failed to start ${install.command}: ${error.message}`,
|
|
11724
13383
|
manualCommand: install.manualCommand
|
|
@@ -11726,11 +13385,11 @@ function runOneSkillsInstall(install) {
|
|
|
11726
13385
|
});
|
|
11727
13386
|
child.on("close", (code) => {
|
|
11728
13387
|
if (code === 0) {
|
|
11729
|
-
|
|
13388
|
+
resolve12({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
11730
13389
|
return;
|
|
11731
13390
|
}
|
|
11732
13391
|
const detail = stderr.trim();
|
|
11733
|
-
|
|
13392
|
+
resolve12({
|
|
11734
13393
|
ok: false,
|
|
11735
13394
|
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
11736
13395
|
manualCommand: install.manualCommand
|
|
@@ -11806,8 +13465,8 @@ function shouldDeferSkillsSyncForCommand() {
|
|
|
11806
13465
|
return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
|
|
11807
13466
|
}
|
|
11808
13467
|
async function runPlayRunnerHealthCheck() {
|
|
11809
|
-
const dir = await (0, import_promises5.mkdtemp)((0,
|
|
11810
|
-
const file = (0,
|
|
13468
|
+
const dir = await (0, import_promises5.mkdtemp)((0, import_node_path16.join)((0, import_node_os9.tmpdir)(), "deepline-health-play-"));
|
|
13469
|
+
const file = (0, import_node_path16.join)(dir, "health-check.play.ts");
|
|
11811
13470
|
try {
|
|
11812
13471
|
await (0, import_promises5.writeFile)(
|
|
11813
13472
|
file,
|