deepline 0.3.351 → 0.3.353
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/bundling-sources/sdk/src/gtm.ts +1 -1
- package/dist/bundling-sources/sdk/src/index.ts +1 -20
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +2 -14
- package/dist/bundling-sources/shared_libs/integration-contracts/monitor-input-contract.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/tool-categories.ts +19 -0
- package/dist/bundling-sources/shared_libs/plays/tool-category-descriptions.ts +1 -1
- package/dist/cli/{auth-NQLQ5QBV.mjs → auth-FVIZVTCB.mjs} +4 -4
- package/dist/cli/auth-GJZ3S4QH.js +31 -0
- package/dist/cli/{billing-AZCBAJ6Q.js → billing-NWL7KQPZ.js} +73 -73
- package/dist/cli/{billing-AXSNXOTN.mjs → billing-PYTYGWPG.mjs} +4 -4
- package/dist/cli/{chunk-73J3BGJ3.js → chunk-2UWRFDI4.js} +60 -60
- package/dist/cli/{chunk-BR3XFSXN.mjs → chunk-37F4EUJA.mjs} +161 -1848
- package/dist/cli/{chunk-QD7W3OBA.js → chunk-55XOA2VW.js} +8 -8
- package/dist/cli/{chunk-URBPUPJS.mjs → chunk-BVHUTDCW.mjs} +5 -5
- package/dist/cli/{chunk-J5NA2TTX.js → chunk-C374C22Y.js} +2 -2
- package/dist/cli/{chunk-QOYD2THS.mjs → chunk-CQQ5N4YO.mjs} +2 -2
- package/dist/cli/{chunk-OF4N5X7Z.mjs → chunk-CXMSK2VV.mjs} +2 -2
- package/dist/cli/{chunk-7BGGBA4V.mjs → chunk-D477W2OQ.mjs} +4 -4
- package/dist/cli/{chunk-CFALTV4O.mjs → chunk-DY253DRK.mjs} +2 -2
- package/dist/cli/{chunk-L7YXXM5W.js → chunk-EDEO7NG4.js} +1 -1
- package/dist/cli/{chunk-GVESPYSY.mjs → chunk-ERFN2QY4.mjs} +1 -102
- package/dist/cli/{chunk-LVEDPCLJ.js → chunk-GEJDBXXM.js} +1 -102
- package/dist/cli/{chunk-H5JUSKHB.mjs → chunk-GFLHAA2O.mjs} +1 -1
- package/dist/cli/{chunk-BOOZ7D7V.js → chunk-HU4SUDWU.js} +567 -2254
- package/dist/cli/{chunk-WOHBA5PV.js → chunk-IF75RD6U.js} +1 -1
- package/dist/cli/{chunk-IKC7EPDS.mjs → chunk-IVGFLYQ6.mjs} +1 -1
- package/dist/cli/{chunk-NUD2WO3E.js → chunk-JHPVZR6F.js} +4 -4
- package/dist/cli/{chunk-DBWASDYS.mjs → chunk-LLI4RITH.mjs} +27 -3
- package/dist/cli/{chunk-ICZTTYDS.js → chunk-M4UPRX3M.js} +40 -16
- package/dist/cli/{chunk-TAC3JIFE.mjs → chunk-MI6ZP7XI.mjs} +1 -1
- package/dist/cli/{chunk-BKOYPUK2.js → chunk-NFEQHNDQ.js} +26 -26
- package/dist/cli/{chunk-CIDP2FSO.js → chunk-NPU4SMKT.js} +9 -9
- package/dist/cli/{chunk-AQQFVUDI.mjs → chunk-NZNUDZDW.mjs} +2 -2
- package/dist/cli/{chunk-7ZAG2XG5.js → chunk-R2T4HQ64.js} +6 -6
- package/dist/cli/{chunk-HUZXWOSK.mjs → chunk-R4RG4FV5.mjs} +1 -1
- package/dist/cli/{chunk-XFTGWGZ5.mjs → chunk-RRDCBCRI.mjs} +1 -1
- package/dist/cli/{chunk-722274AA.mjs → chunk-U3FUXTIB.mjs} +1 -1
- package/dist/cli/{chunk-BWFUBETD.js → chunk-VALAAQQM.js} +48 -48
- package/dist/cli/{chunk-WY5N3SSC.js → chunk-XI5IMY45.js} +2 -2
- package/dist/cli/{chunk-SDLFAGQS.js → chunk-Z6LVVOOJ.js} +15 -15
- package/dist/cli/{chunk-JV6GFIQQ.js → chunk-ZCCXX55K.js} +45 -45
- package/dist/cli/{chunk-GT5HPOM3.mjs → chunk-ZDEO3EGW.mjs} +1 -1
- package/dist/cli/{client-NTEDBLQK.mjs → client-IH7I5D7T.mjs} +3 -3
- package/dist/cli/client-Z6BCEGFA.js +20 -0
- package/dist/cli/{csv-SSSPKSKU.mjs → csv-G5WXNCLQ.mjs} +3 -3
- package/dist/cli/{csv-6PZZ4ARC.js → csv-TJIWKUCX.js} +12 -12
- package/dist/cli/{db-3YL7YWTM.js → db-3DCS2JXS.js} +29 -29
- package/dist/cli/{db-XEVVDWOP.mjs → db-EBHV2MGE.mjs} +4 -4
- package/dist/cli/{describe-XZNQXFXD.js → describe-5XKBPWD7.js} +16 -16
- package/dist/cli/{describe-YZ365BKT.mjs → describe-QUOLGZKH.mjs} +9 -9
- package/dist/cli/{executions-ZAV7YCQC.mjs → executions-EERWIJ5I.mjs} +4 -4
- package/dist/cli/{executions-WBTIT2RU.js → executions-NYIOENKH.js} +6 -6
- package/dist/cli/{feedback-NOYG63QE.mjs → feedback-4RYJJCYL.mjs} +3 -3
- package/dist/cli/{feedback-PRVJ26X7.js → feedback-Z2I5MQYZ.js} +7 -7
- package/dist/cli/{git-AOSMM4US.mjs → git-EMU7AKX3.mjs} +4 -4
- package/dist/cli/git-QYQ5ZFIG.js +23 -0
- package/dist/cli/index.js +79 -79
- package/dist/cli/index.mjs +31 -31
- package/dist/cli/{legacy-noops-RTNAEYVF.js → legacy-noops-BEUYYRSU.js} +7 -7
- package/dist/cli/{legacy-noops-T6DKTGZY.mjs → legacy-noops-HHLNM523.mjs} +4 -4
- package/dist/cli/{monitors-QIR3T2QR.mjs → monitors-BVJSHUV4.mjs} +7 -7
- package/dist/cli/{monitors-7ERJ4277.js → monitors-KQXLMPZ4.js} +96 -96
- package/dist/cli/{org-7P46IVVU.js → org-HRYNVOUH.js} +60 -60
- package/dist/cli/{org-WNRQQZNP.mjs → org-KSROOKSJ.mjs} +4 -4
- package/dist/cli/play-CRHUA45Q.js +153 -0
- package/dist/cli/{play-57XTHKER.mjs → play-PGFW6PFE.mjs} +8 -8
- package/dist/cli/{providers-USRX4UVZ.js → providers-BJM725CV.js} +7 -7
- package/dist/cli/{providers-ET6UBGWJ.mjs → providers-EUKJK6ZE.mjs} +4 -4
- package/dist/cli/{quickstart-OGZ7BZKS.mjs → quickstart-72JYHUJC.mjs} +3 -3
- package/dist/cli/{quickstart-BPPQFMWI.js → quickstart-FEERYTYY.js} +5 -5
- package/dist/cli/{search-MZARI5XA.mjs → search-LUAIOM56.mjs} +5 -5
- package/dist/cli/search-X25S2U54.js +26 -0
- package/dist/cli/{secrets-O6XG35SA.js → secrets-J65QCH57.js} +13 -13
- package/dist/cli/{secrets-WMUJ6PB4.mjs → secrets-YYFRYS2Z.mjs} +4 -4
- package/dist/cli/{sessions-LCHVGXMV.js → sessions-FWUUEK6V.js} +5 -5
- package/dist/cli/{sessions-EYALESPC.mjs → sessions-WBA67YYT.mjs} +4 -4
- package/dist/cli/{settings-25YT2IQK.js → settings-I7AZ4JVI.js} +74 -74
- package/dist/cli/{settings-LUGKMDDX.mjs → settings-RUMTSUE5.mjs} +7 -7
- package/dist/cli/{setup-KSRA3V42.mjs → setup-BHRRNT5C.mjs} +6 -6
- package/dist/cli/{setup-AKZWHNKU.js → setup-R3IUFNDP.js} +41 -41
- package/dist/cli/{skills-VJJIB4F5.mjs → skills-EKD5O7GQ.mjs} +4 -4
- package/dist/cli/skills-OOZ5SDVB.js +28 -0
- package/dist/cli/{tools-NYQD3VSU.mjs → tools-L5OA2343.mjs} +6 -6
- package/dist/cli/tools-MYH33NTL.js +40 -0
- package/dist/cli/update-EWNPE3NF.js +28 -0
- package/dist/cli/{update-GU4TALAI.mjs → update-UUHL6FER.mjs} +6 -6
- package/dist/cli/{workflow-TFOUWNEJ.js → workflow-7NBSG5OT.js} +15 -15
- package/dist/cli/{workflow-T4VNPJA4.mjs → workflow-V24VHOQT.mjs} +5 -5
- package/dist/{client-4DbE-U6e.d.ts → client-Chzd2LFo.d.ts} +1 -25
- package/dist/{client-DIJpwhl-.d.mts → client-jV6bQunU.d.mts} +1 -25
- package/dist/helpers.d.mts +1 -1
- package/dist/helpers.d.ts +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +25 -39
- package/dist/index.mjs +23 -37
- package/dist/install-integrity.json +83 -83
- package/dist/monitor-fleet-contract.js +3 -3
- package/dist/monitor-fleet-contract.mjs +2 -2
- package/dist/monitor-input-contract.js +2 -2
- package/dist/monitor-input-contract.mjs +1 -1
- package/dist/plays/run-request.d.mts +1 -1
- package/dist/plays/run-request.d.ts +1 -1
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +2 -2
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
- package/dist/bundling-sources/shared_libs/plays/bootstrap-routes.ts +0 -127
- package/dist/cli/auth-YTDZKDCB.js +0 -31
- package/dist/cli/client-3GCQER5K.js +0 -20
- package/dist/cli/git-ZI4H72YR.js +0 -23
- package/dist/cli/play-QIX7RZ74.js +0 -153
- package/dist/cli/search-P447HWLU.js +0 -26
- package/dist/cli/skills-GYWMMOFQ.js +0 -28
- package/dist/cli/tools-HN6E2AH6.js +0 -40
- package/dist/cli/update-IIEKVC75.js +0 -28
|
@@ -11,21 +11,15 @@ import {
|
|
|
11
11
|
} from "./chunk-EDWJY6T4.mjs";
|
|
12
12
|
import {
|
|
13
13
|
registerDeprecatedSearchCommand
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-LLI4RITH.mjs";
|
|
15
15
|
import {
|
|
16
16
|
handleDeploymentGet,
|
|
17
17
|
handleDeploymentsList
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-DY253DRK.mjs";
|
|
19
19
|
import {
|
|
20
|
-
PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY,
|
|
21
|
-
PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER,
|
|
22
|
-
PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY,
|
|
23
|
-
PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER,
|
|
24
|
-
formatPlayBootstrapTemplates,
|
|
25
|
-
isPlayBootstrapTemplate,
|
|
26
20
|
pinLocalPlayImports,
|
|
27
21
|
planLocalPlayExecution
|
|
28
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-ERFN2QY4.mjs";
|
|
29
23
|
import {
|
|
30
24
|
CSV_HEADER_MATCHING_NOTE,
|
|
31
25
|
DeeplineClient,
|
|
@@ -40,7 +34,7 @@ import {
|
|
|
40
34
|
normalizeRunEventOperationRequest,
|
|
41
35
|
parseLogLevel,
|
|
42
36
|
playInputExampleArgs
|
|
43
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-IVGFLYQ6.mjs";
|
|
44
38
|
import {
|
|
45
39
|
CSV_DATA_INPUT_KEY,
|
|
46
40
|
buildNamedPlayRunRequest,
|
|
@@ -73,10 +67,10 @@ import {
|
|
|
73
67
|
printJsonError,
|
|
74
68
|
renderCommandEnvelopeText,
|
|
75
69
|
shouldEmitJson
|
|
76
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-ZDEO3EGW.mjs";
|
|
77
71
|
import {
|
|
78
72
|
fetchWithDeploymentProtection
|
|
79
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-U3FUXTIB.mjs";
|
|
80
74
|
import {
|
|
81
75
|
PLAY_DEFAULT_EXPORT,
|
|
82
76
|
extractDefinedPlayName,
|
|
@@ -3971,8 +3965,8 @@ import {
|
|
|
3971
3965
|
readFileSync as readFileSync2,
|
|
3972
3966
|
readdirSync,
|
|
3973
3967
|
realpathSync,
|
|
3974
|
-
statSync
|
|
3975
|
-
writeFileSync as
|
|
3968
|
+
statSync,
|
|
3969
|
+
writeFileSync as writeFileSync3
|
|
3976
3970
|
} from "fs";
|
|
3977
3971
|
import {
|
|
3978
3972
|
lstat,
|
|
@@ -3985,1693 +3979,13 @@ import {
|
|
|
3985
3979
|
import {
|
|
3986
3980
|
basename,
|
|
3987
3981
|
dirname as dirname2,
|
|
3988
|
-
isAbsolute as
|
|
3982
|
+
isAbsolute as isAbsolute2,
|
|
3989
3983
|
join as join6,
|
|
3990
|
-
relative as
|
|
3991
|
-
resolve as
|
|
3984
|
+
relative as relative3,
|
|
3985
|
+
resolve as resolve5
|
|
3992
3986
|
} from "path";
|
|
3993
3987
|
import { Option as Option2 } from "commander";
|
|
3994
3988
|
|
|
3995
|
-
// src/cli/commands/plays/bootstrap.ts
|
|
3996
|
-
import {
|
|
3997
|
-
closeSync,
|
|
3998
|
-
openSync,
|
|
3999
|
-
readSync,
|
|
4000
|
-
statSync,
|
|
4001
|
-
writeFileSync
|
|
4002
|
-
} from "fs";
|
|
4003
|
-
import { isAbsolute, relative, resolve } from "path";
|
|
4004
|
-
import { parse as parseCsvSync } from "csv-parse/sync";
|
|
4005
|
-
function parseReferencedPlayTarget(target) {
|
|
4006
|
-
const trimmed = target.trim();
|
|
4007
|
-
const slashIndex = trimmed.indexOf("/");
|
|
4008
|
-
if (slashIndex <= 0 || slashIndex === trimmed.length - 1) {
|
|
4009
|
-
return { ownerSlug: null, playName: trimmed, unqualifiedPlayName: trimmed };
|
|
4010
|
-
}
|
|
4011
|
-
return {
|
|
4012
|
-
ownerSlug: trimmed.slice(0, slashIndex),
|
|
4013
|
-
playName: trimmed,
|
|
4014
|
-
unqualifiedPlayName: trimmed.slice(slashIndex + 1)
|
|
4015
|
-
};
|
|
4016
|
-
}
|
|
4017
|
-
function parsePositiveInteger(value, flagName) {
|
|
4018
|
-
const parsed = Number.parseInt(value, 10);
|
|
4019
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
4020
|
-
throw new PlayBootstrapUsageError(
|
|
4021
|
-
`${flagName} must be a positive integer.`
|
|
4022
|
-
);
|
|
4023
|
-
}
|
|
4024
|
-
return parsed;
|
|
4025
|
-
}
|
|
4026
|
-
function isRecord(value) {
|
|
4027
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
4028
|
-
}
|
|
4029
|
-
function stringValue(value) {
|
|
4030
|
-
return typeof value === "string" ? value.trim() : "";
|
|
4031
|
-
}
|
|
4032
|
-
function extractionEntries(value) {
|
|
4033
|
-
if (Array.isArray(value)) return value.filter(isRecord);
|
|
4034
|
-
if (!isRecord(value)) return [];
|
|
4035
|
-
return Object.entries(value).map(
|
|
4036
|
-
([name, entry]) => isRecord(entry) ? { name, ...entry } : { name }
|
|
4037
|
-
);
|
|
4038
|
-
}
|
|
4039
|
-
var PlayBootstrapError = class extends Error {
|
|
4040
|
-
constructor(message, exitCode) {
|
|
4041
|
-
super(message);
|
|
4042
|
-
this.exitCode = exitCode;
|
|
4043
|
-
}
|
|
4044
|
-
};
|
|
4045
|
-
var PlayBootstrapUsageError = class extends PlayBootstrapError {
|
|
4046
|
-
constructor(message) {
|
|
4047
|
-
super(message, 2);
|
|
4048
|
-
}
|
|
4049
|
-
};
|
|
4050
|
-
var PlayBootstrapValidationError = class extends PlayBootstrapError {
|
|
4051
|
-
constructor(message) {
|
|
4052
|
-
super(message, 7);
|
|
4053
|
-
}
|
|
4054
|
-
};
|
|
4055
|
-
var CSV_HEADER_SAMPLE_BYTES = 64 * 1024;
|
|
4056
|
-
function parseCsvList(value) {
|
|
4057
|
-
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
4058
|
-
}
|
|
4059
|
-
function parseProviderList(value, flag) {
|
|
4060
|
-
const providers = parseCsvList(value);
|
|
4061
|
-
if (providers.length === 0) {
|
|
4062
|
-
throw new PlayBootstrapUsageError(`${flag} provider list cannot be empty.`);
|
|
4063
|
-
}
|
|
4064
|
-
return providers;
|
|
4065
|
-
}
|
|
4066
|
-
function parseBootstrapPrefixedRef(value, flag) {
|
|
4067
|
-
const separatorIndex = value.indexOf(":");
|
|
4068
|
-
if (separatorIndex <= 0 || separatorIndex === value.length - 1) {
|
|
4069
|
-
throw new PlayBootstrapUsageError(
|
|
4070
|
-
`${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.`
|
|
4071
|
-
);
|
|
4072
|
-
}
|
|
4073
|
-
return {
|
|
4074
|
-
prefix: value.slice(0, separatorIndex).trim(),
|
|
4075
|
-
body: value.slice(separatorIndex + 1).trim()
|
|
4076
|
-
};
|
|
4077
|
-
}
|
|
4078
|
-
function parseBootstrapSourceRef(value, flag = "--from") {
|
|
4079
|
-
const { prefix, body } = parseBootstrapPrefixedRef(value, flag);
|
|
4080
|
-
switch (prefix) {
|
|
4081
|
-
case "csv":
|
|
4082
|
-
return { kind: "csv", value: body };
|
|
4083
|
-
case "play":
|
|
4084
|
-
return { kind: "play", value: parseReferencedPlayTarget(body).playName };
|
|
4085
|
-
case "provider":
|
|
4086
|
-
case "providers":
|
|
4087
|
-
return { kind: "providers", values: parseProviderList(body, flag) };
|
|
4088
|
-
}
|
|
4089
|
-
throw new PlayBootstrapUsageError(
|
|
4090
|
-
`${flag} does not support ${prefix}:. Use csv:, play:, provider:, or providers:.`
|
|
4091
|
-
);
|
|
4092
|
-
}
|
|
4093
|
-
function parseBootstrapStageRef(value, flag) {
|
|
4094
|
-
const { prefix, body } = parseBootstrapPrefixedRef(value, flag);
|
|
4095
|
-
switch (prefix) {
|
|
4096
|
-
case "play":
|
|
4097
|
-
return { kind: "play", value: parseReferencedPlayTarget(body).playName };
|
|
4098
|
-
case "provider":
|
|
4099
|
-
case "providers":
|
|
4100
|
-
return { kind: "providers", values: parseProviderList(body, flag) };
|
|
4101
|
-
}
|
|
4102
|
-
throw new PlayBootstrapUsageError(
|
|
4103
|
-
`${flag} does not support ${prefix}:. Use play:, provider:, or providers:.`
|
|
4104
|
-
);
|
|
4105
|
-
}
|
|
4106
|
-
function playBootstrapTemplateConfig(template) {
|
|
4107
|
-
switch (template) {
|
|
4108
|
-
case "company-list":
|
|
4109
|
-
return { sourceEntity: "company", usingStage: null, requiredStages: [] };
|
|
4110
|
-
case "people-list":
|
|
4111
|
-
return { sourceEntity: "people", usingStage: null, requiredStages: [] };
|
|
4112
|
-
case "people-email":
|
|
4113
|
-
return {
|
|
4114
|
-
sourceEntity: "people",
|
|
4115
|
-
usingStage: "email",
|
|
4116
|
-
requiredStages: []
|
|
4117
|
-
};
|
|
4118
|
-
case "people-phone":
|
|
4119
|
-
return {
|
|
4120
|
-
sourceEntity: "people",
|
|
4121
|
-
usingStage: "phone",
|
|
4122
|
-
requiredStages: []
|
|
4123
|
-
};
|
|
4124
|
-
case "company-people":
|
|
4125
|
-
return {
|
|
4126
|
-
sourceEntity: "company",
|
|
4127
|
-
usingStage: "people",
|
|
4128
|
-
requiredStages: []
|
|
4129
|
-
};
|
|
4130
|
-
case "company-people-email":
|
|
4131
|
-
return {
|
|
4132
|
-
sourceEntity: "company",
|
|
4133
|
-
usingStage: null,
|
|
4134
|
-
requiredStages: ["people", "email"]
|
|
4135
|
-
};
|
|
4136
|
-
case "company-people-phone":
|
|
4137
|
-
return {
|
|
4138
|
-
sourceEntity: "company",
|
|
4139
|
-
usingStage: null,
|
|
4140
|
-
requiredStages: ["people", "phone"]
|
|
4141
|
-
};
|
|
4142
|
-
}
|
|
4143
|
-
}
|
|
4144
|
-
function templateExample(template) {
|
|
4145
|
-
switch (template) {
|
|
4146
|
-
case "people-list":
|
|
4147
|
-
return "deepline plays bootstrap people-list --from provider:dropleads_search_people --out people.play.ts";
|
|
4148
|
-
case "company-list":
|
|
4149
|
-
return "deepline plays bootstrap company-list --from provider:crustdata_companydb_search --out companies.play.ts";
|
|
4150
|
-
case "people-email":
|
|
4151
|
-
return "deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall --out email-flow.play.ts";
|
|
4152
|
-
case "people-phone":
|
|
4153
|
-
return "deepline plays bootstrap people-phone --from csv:data/vp_contacts.csv --using play:prebuilt/person-to-phone --out phone-flow.play.ts";
|
|
4154
|
-
case "company-people":
|
|
4155
|
-
return "deepline plays bootstrap company-people --from provider:crustdata_companydb_search --using play:prebuilt/company-to-contact --out company-people.play.ts";
|
|
4156
|
-
case "company-people-email":
|
|
4157
|
-
return "deepline plays bootstrap company-people-email --from provider:crustdata_companydb_search --people play:prebuilt/company-to-contact --email providers:hunter_email_finder,leadmagic_email_finder --out account-emails.play.ts";
|
|
4158
|
-
case "company-people-phone":
|
|
4159
|
-
return "deepline plays bootstrap company-people-phone --from provider:crustdata_companydb_search --people play:prebuilt/company-to-contact --phone providers:ai_ark_mobile_phone_finder --out account-phones.play.ts";
|
|
4160
|
-
}
|
|
4161
|
-
}
|
|
4162
|
-
var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
4163
|
-
"people",
|
|
4164
|
-
"email",
|
|
4165
|
-
"phone"
|
|
4166
|
-
];
|
|
4167
|
-
var MONITOR_BOOTSTRAP_TEMPLATE = "monitor-triggered";
|
|
4168
|
-
var MONITOR_BOOTSTRAP_DEFAULT_TOOL = "deepline_native.company_radar";
|
|
4169
|
-
var MONITOR_BOOTSTRAP_DEFAULT_STREAM = "company_job_openings";
|
|
4170
|
-
function isMonitorBootstrapTemplate(value) {
|
|
4171
|
-
return value === MONITOR_BOOTSTRAP_TEMPLATE;
|
|
4172
|
-
}
|
|
4173
|
-
function hasMonitorBootstrapForbiddenChar(value) {
|
|
4174
|
-
for (const char of value) {
|
|
4175
|
-
const code = char.codePointAt(0) ?? 0;
|
|
4176
|
-
if (code < 32 || code === 127) return true;
|
|
4177
|
-
if (char === "'" || char === '"' || char === "`" || char === "\\") {
|
|
4178
|
-
return true;
|
|
4179
|
-
}
|
|
4180
|
-
}
|
|
4181
|
-
return false;
|
|
4182
|
-
}
|
|
4183
|
-
function validateMonitorBootstrapFlagValue(flag, value) {
|
|
4184
|
-
if (hasMonitorBootstrapForbiddenChar(value)) {
|
|
4185
|
-
throw new PlayBootstrapUsageError(
|
|
4186
|
-
`${flag} may not contain line breaks, control characters, quotes, or backticks. It is interpolated into the generated play source (including comments); use a plain monitor tool id / stream key / name.`
|
|
4187
|
-
);
|
|
4188
|
-
}
|
|
4189
|
-
return value;
|
|
4190
|
-
}
|
|
4191
|
-
function parseMonitorBootstrapOptions(args) {
|
|
4192
|
-
const [, ...rest] = args;
|
|
4193
|
-
const options = {
|
|
4194
|
-
name: MONITOR_BOOTSTRAP_TEMPLATE,
|
|
4195
|
-
tool: MONITOR_BOOTSTRAP_DEFAULT_TOOL,
|
|
4196
|
-
stream: MONITOR_BOOTSTRAP_DEFAULT_STREAM,
|
|
4197
|
-
out: null
|
|
4198
|
-
};
|
|
4199
|
-
for (let index = 0; index < rest.length; index += 1) {
|
|
4200
|
-
const arg = rest[index];
|
|
4201
|
-
const value = () => nextFlagValue(rest, index, arg);
|
|
4202
|
-
switch (arg) {
|
|
4203
|
-
case "--name":
|
|
4204
|
-
options.name = validateMonitorBootstrapFlagValue("--name", value());
|
|
4205
|
-
index += 1;
|
|
4206
|
-
break;
|
|
4207
|
-
case "--tool":
|
|
4208
|
-
options.tool = validateMonitorBootstrapFlagValue("--tool", value());
|
|
4209
|
-
index += 1;
|
|
4210
|
-
break;
|
|
4211
|
-
case "--stream":
|
|
4212
|
-
options.stream = validateMonitorBootstrapFlagValue("--stream", value());
|
|
4213
|
-
index += 1;
|
|
4214
|
-
break;
|
|
4215
|
-
case "--out":
|
|
4216
|
-
options.out = value();
|
|
4217
|
-
index += 1;
|
|
4218
|
-
break;
|
|
4219
|
-
default:
|
|
4220
|
-
throw new PlayBootstrapUsageError(
|
|
4221
|
-
`Unknown plays bootstrap option for ${MONITOR_BOOTSTRAP_TEMPLATE}: ${arg}
|
|
4222
|
-
Usage: deepline plays bootstrap ${MONITOR_BOOTSTRAP_TEMPLATE} [--tool <monitor-tool-id>] [--stream <stream-key>] [--name NAME] [--out monitor.play.ts]`
|
|
4223
|
-
);
|
|
4224
|
-
}
|
|
4225
|
-
}
|
|
4226
|
-
if (!options.tool) {
|
|
4227
|
-
throw new PlayBootstrapUsageError(
|
|
4228
|
-
`${MONITOR_BOOTSTRAP_TEMPLATE} needs a non-empty --tool.`
|
|
4229
|
-
);
|
|
4230
|
-
}
|
|
4231
|
-
if (!options.stream) {
|
|
4232
|
-
throw new PlayBootstrapUsageError(
|
|
4233
|
-
`${MONITOR_BOOTSTRAP_TEMPLATE} needs a non-empty --stream.`
|
|
4234
|
-
);
|
|
4235
|
-
}
|
|
4236
|
-
return options;
|
|
4237
|
-
}
|
|
4238
|
-
function generateMonitorTriggeredPlaySource(options) {
|
|
4239
|
-
return `import { definePlay } from 'deepline';
|
|
4240
|
-
import type { SqlListenerEvent } from 'deepline';
|
|
4241
|
-
|
|
4242
|
-
// Row shape delivered by ${options.tool} / ${options.stream}. This is a starting
|
|
4243
|
-
// point only: inspect the real columns with
|
|
4244
|
-
// deepline monitors available ${options.tool}
|
|
4245
|
-
// and tighten this type to the fields you read below.
|
|
4246
|
-
//
|
|
4247
|
-
// Before deploying a NEW monitor, run \`deepline monitors list\` \u2014 if one
|
|
4248
|
-
// already feeds this stream for your scope, this play will already react to its
|
|
4249
|
-
// rows (a play binds to the shared stream), so you may not need to deploy at all.
|
|
4250
|
-
type MonitorRow = Record<string, unknown>;
|
|
4251
|
-
|
|
4252
|
-
export default definePlay(
|
|
4253
|
-
${jsString(options.name)},
|
|
4254
|
-
async (ctx, event: SqlListenerEvent<MonitorRow>) => {
|
|
4255
|
-
// The monitor delivers the changed row as event.after. It is null for
|
|
4256
|
-
// DELETE operations, so guard before reading fields.
|
|
4257
|
-
const row = event.after;
|
|
4258
|
-
if (!row) {
|
|
4259
|
-
ctx.log(\`Monitor \${event.tool}/\${event.stream} \${event.operation} with no row; nothing to do.\`);
|
|
4260
|
-
return { handled: false, operation: event.operation };
|
|
4261
|
-
}
|
|
4262
|
-
|
|
4263
|
-
ctx.log(
|
|
4264
|
-
\`Monitor \${event.tool}/\${event.stream} \${event.operation}: \${JSON.stringify(row).slice(0, 200)}\`,
|
|
4265
|
-
);
|
|
4266
|
-
|
|
4267
|
-
// Capture the changed row into a durable dataset so the run has inspectable,
|
|
4268
|
-
// exportable output. ctx.dataset is a CALLABLE: ctx.dataset(key, rows) where
|
|
4269
|
-
// key is a compile-time string LITERAL and rows is an array of row objects.
|
|
4270
|
-
// It returns a builder; add per-row columns with .withColumn(name, resolver)
|
|
4271
|
-
// and finish with .run(). There is no .push/.add \u2014 pass all rows up front.
|
|
4272
|
-
// TODO: replace this plain persist with your real per-row work \u2014 enrich each
|
|
4273
|
-
// row via .withColumn('...', (row, rowCtx) => rowCtx.tools.execute(...)),
|
|
4274
|
-
// notify, write to another table, or fan out with rowCtx.runPlay.
|
|
4275
|
-
const captured = await ctx.dataset('monitor_events', [row]).run({
|
|
4276
|
-
description: \`Captured \${event.tool}/\${event.stream} \${event.operation} rows.\`,
|
|
4277
|
-
});
|
|
4278
|
-
|
|
4279
|
-
return {
|
|
4280
|
-
handled: true,
|
|
4281
|
-
tool: event.tool,
|
|
4282
|
-
stream: event.stream,
|
|
4283
|
-
operation: event.operation,
|
|
4284
|
-
changedAt: event.changedAt,
|
|
4285
|
-
capturedRows: await captured.count(),
|
|
4286
|
-
};
|
|
4287
|
-
},
|
|
4288
|
-
{
|
|
4289
|
-
description: ${jsString(`Run whenever ${options.tool} writes a new ${options.stream} row.`)},
|
|
4290
|
-
// A monitor trigger: this play wakes on row changes written by the bound
|
|
4291
|
-
// monitor tool + stream. Discover a tool's streams and columns with:
|
|
4292
|
-
// deepline monitors available ${options.tool}
|
|
4293
|
-
// To bind a different monitor, swap tool/stream (and re-check operations)
|
|
4294
|
-
// for one of its (tool, stream) pairs.
|
|
4295
|
-
sqlListeners: [
|
|
4296
|
-
{
|
|
4297
|
-
id: 'events',
|
|
4298
|
-
tool: ${jsString(options.tool)},
|
|
4299
|
-
stream: ${jsString(options.stream)},
|
|
4300
|
-
operations: ['INSERT'],
|
|
4301
|
-
// Optional: only wake on some rows \u2014 add a where filter to the binding above:
|
|
4302
|
-
// where: { after: { <column>: { eq: 'value' } } } // operators: eq, neq, in, notIn, isNull, isNotNull, ilike
|
|
4303
|
-
},
|
|
4304
|
-
],
|
|
4305
|
-
},
|
|
4306
|
-
);
|
|
4307
|
-
`;
|
|
4308
|
-
}
|
|
4309
|
-
function playBootstrapUsageLine() {
|
|
4310
|
-
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] [--out flow.play.ts]`;
|
|
4311
|
-
}
|
|
4312
|
-
function requireBootstrapTemplate(rawTemplate) {
|
|
4313
|
-
if (!rawTemplate) {
|
|
4314
|
-
throw new PlayBootstrapUsageError(
|
|
4315
|
-
`plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}|${MONITOR_BOOTSTRAP_TEMPLATE}.
|
|
4316
|
-
Example: deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall --out email-flow.play.ts`
|
|
4317
|
-
);
|
|
4318
|
-
}
|
|
4319
|
-
if (!isPlayBootstrapTemplate(rawTemplate)) {
|
|
4320
|
-
const looksLikePlayReference = rawTemplate.includes("/") || rawTemplate.endsWith(".play.ts");
|
|
4321
|
-
throw new PlayBootstrapUsageError(
|
|
4322
|
-
`Unknown plays bootstrap template: ${rawTemplate}
|
|
4323
|
-
Supported templates: ${formatPlayBootstrapTemplates()}|${MONITOR_BOOTSTRAP_TEMPLATE}` + (looksLikePlayReference ? `
|
|
4324
|
-
|
|
4325
|
-
"${rawTemplate}" looks like an existing play reference or file, not a bootstrap template. Do not run plays bootstrap on prebuilt/<play-name>. Use "deepline plays run ${rawTemplate} --input '{...}'" to run it directly, "deepline describe ${rawTemplate}" to inspect its contract, or "deepline plays get ${rawTemplate} --source --out scratchpad.play.ts" to clone/edit it.` : "")
|
|
4326
|
-
);
|
|
4327
|
-
}
|
|
4328
|
-
return rawTemplate;
|
|
4329
|
-
}
|
|
4330
|
-
function nextFlagValue(args, index, flag) {
|
|
4331
|
-
const value = args[index + 1];
|
|
4332
|
-
if (!value || value.startsWith("--")) {
|
|
4333
|
-
throw new PlayBootstrapUsageError(`${flag} needs a value.`);
|
|
4334
|
-
}
|
|
4335
|
-
return value;
|
|
4336
|
-
}
|
|
4337
|
-
function stageFlag(stage) {
|
|
4338
|
-
return `--${stage}`;
|
|
4339
|
-
}
|
|
4340
|
-
function stageRefHelp(stage) {
|
|
4341
|
-
switch (stage) {
|
|
4342
|
-
case "people":
|
|
4343
|
-
return "play:<people-play>";
|
|
4344
|
-
case "email":
|
|
4345
|
-
case "phone":
|
|
4346
|
-
return "<play:REF|provider:ID|providers:ID,ID>";
|
|
4347
|
-
}
|
|
4348
|
-
}
|
|
4349
|
-
function getStageRef(options, stage) {
|
|
4350
|
-
switch (stage) {
|
|
4351
|
-
case "people":
|
|
4352
|
-
return options.people;
|
|
4353
|
-
case "email":
|
|
4354
|
-
return options.email;
|
|
4355
|
-
case "phone":
|
|
4356
|
-
return options.phone;
|
|
4357
|
-
}
|
|
4358
|
-
}
|
|
4359
|
-
function setStageRef(options, stage, ref) {
|
|
4360
|
-
switch (stage) {
|
|
4361
|
-
case "people":
|
|
4362
|
-
options.people = ref;
|
|
4363
|
-
return;
|
|
4364
|
-
case "email":
|
|
4365
|
-
options.email = ref;
|
|
4366
|
-
return;
|
|
4367
|
-
case "phone":
|
|
4368
|
-
options.phone = ref;
|
|
4369
|
-
return;
|
|
4370
|
-
}
|
|
4371
|
-
}
|
|
4372
|
-
function unsupportedStageMessage(template, stage) {
|
|
4373
|
-
switch (stage) {
|
|
4374
|
-
case "people":
|
|
4375
|
-
return `${template} does not accept --people. Use company-people, company-people-email, or company-people-phone.`;
|
|
4376
|
-
case "email":
|
|
4377
|
-
return `${template} does not accept --email. Use people-email or company-people-email.`;
|
|
4378
|
-
case "phone":
|
|
4379
|
-
return `${template} does not accept --phone. Use people-phone or company-people-phone.`;
|
|
4380
|
-
}
|
|
4381
|
-
}
|
|
4382
|
-
function requireSource(options) {
|
|
4383
|
-
if (!options.from) {
|
|
4384
|
-
throw new PlayBootstrapUsageError(
|
|
4385
|
-
`${options.template} needs --from.
|
|
4386
|
-
Example: ${templateExample(options.template)}`
|
|
4387
|
-
);
|
|
4388
|
-
}
|
|
4389
|
-
return options.from;
|
|
4390
|
-
}
|
|
4391
|
-
function assertAllowedStageFlags(options, allowedStages) {
|
|
4392
|
-
const allowed = new Set(allowedStages);
|
|
4393
|
-
for (const stage of PLAY_BOOTSTRAP_STAGE_NAMES) {
|
|
4394
|
-
if (!allowed.has(stage) && getStageRef(options, stage)) {
|
|
4395
|
-
throw new PlayBootstrapUsageError(
|
|
4396
|
-
unsupportedStageMessage(options.template, stage)
|
|
4397
|
-
);
|
|
4398
|
-
}
|
|
4399
|
-
}
|
|
4400
|
-
}
|
|
4401
|
-
function assertRequiredStages(options, stages) {
|
|
4402
|
-
for (const stage of stages) {
|
|
4403
|
-
if (!getStageRef(options, stage)) {
|
|
4404
|
-
throw new PlayBootstrapUsageError(
|
|
4405
|
-
`${options.template} needs ${stageFlag(stage)} ${stageRefHelp(stage)}.
|
|
4406
|
-
Example: ${templateExample(options.template)}`
|
|
4407
|
-
);
|
|
4408
|
-
}
|
|
4409
|
-
}
|
|
4410
|
-
}
|
|
4411
|
-
function normalizeSingleStageRoute(options, stage) {
|
|
4412
|
-
const explicitStage = getStageRef(options, stage);
|
|
4413
|
-
if (options.using && explicitStage) {
|
|
4414
|
-
throw new PlayBootstrapUsageError(
|
|
4415
|
-
`${options.template} received both --using and ${stageFlag(stage)}. Choose one stage binding.`
|
|
4416
|
-
);
|
|
4417
|
-
}
|
|
4418
|
-
const selectedStage = options.using ?? explicitStage;
|
|
4419
|
-
if (!selectedStage) {
|
|
4420
|
-
throw new PlayBootstrapUsageError(
|
|
4421
|
-
`${options.template} needs --using ${stageRefHelp(stage)} or ${stageFlag(stage)} ${stageRefHelp(stage)}.
|
|
4422
|
-
Example: ${templateExample(options.template)}`
|
|
4423
|
-
);
|
|
4424
|
-
}
|
|
4425
|
-
setStageRef(options, stage, selectedStage);
|
|
4426
|
-
options.using = selectedStage;
|
|
4427
|
-
assertAllowedStageFlags(options, [stage]);
|
|
4428
|
-
}
|
|
4429
|
-
function normalizeMultiStageRoute(options, stages) {
|
|
4430
|
-
if (options.using) {
|
|
4431
|
-
throw new PlayBootstrapUsageError(
|
|
4432
|
-
`${options.template} does not accept --using. Use the explicit stage flags shown in: ${templateExample(options.template)}`
|
|
4433
|
-
);
|
|
4434
|
-
}
|
|
4435
|
-
assertRequiredStages(options, stages);
|
|
4436
|
-
assertAllowedStageFlags(options, stages);
|
|
4437
|
-
}
|
|
4438
|
-
function normalizeTemplateStages(options) {
|
|
4439
|
-
const config = playBootstrapTemplateConfig(options.template);
|
|
4440
|
-
const from = requireSource(options);
|
|
4441
|
-
switch (config.usingStage) {
|
|
4442
|
-
case "people":
|
|
4443
|
-
case "email":
|
|
4444
|
-
case "phone":
|
|
4445
|
-
normalizeSingleStageRoute(options, config.usingStage);
|
|
4446
|
-
break;
|
|
4447
|
-
case null:
|
|
4448
|
-
normalizeMultiStageRoute(options, config.requiredStages);
|
|
4449
|
-
break;
|
|
4450
|
-
}
|
|
4451
|
-
return {
|
|
4452
|
-
...options,
|
|
4453
|
-
from
|
|
4454
|
-
};
|
|
4455
|
-
}
|
|
4456
|
-
function parsePlayBootstrapOptions(args) {
|
|
4457
|
-
const [rawTemplate, ...rest] = args;
|
|
4458
|
-
const template = requireBootstrapTemplate(rawTemplate);
|
|
4459
|
-
const options = {
|
|
4460
|
-
template,
|
|
4461
|
-
name: `gtm-${template}`,
|
|
4462
|
-
from: null,
|
|
4463
|
-
using: null,
|
|
4464
|
-
people: null,
|
|
4465
|
-
email: null,
|
|
4466
|
-
phone: null,
|
|
4467
|
-
limit: 5,
|
|
4468
|
-
out: null
|
|
4469
|
-
};
|
|
4470
|
-
for (let index = 0; index < rest.length; index += 1) {
|
|
4471
|
-
const arg = rest[index];
|
|
4472
|
-
const value = () => nextFlagValue(rest, index, arg);
|
|
4473
|
-
switch (arg) {
|
|
4474
|
-
case "--name":
|
|
4475
|
-
options.name = value();
|
|
4476
|
-
index += 1;
|
|
4477
|
-
break;
|
|
4478
|
-
case "--from":
|
|
4479
|
-
options.from = parseBootstrapSourceRef(value(), "--from");
|
|
4480
|
-
index += 1;
|
|
4481
|
-
break;
|
|
4482
|
-
case "--using":
|
|
4483
|
-
options.using = parseBootstrapStageRef(value(), "--using");
|
|
4484
|
-
index += 1;
|
|
4485
|
-
break;
|
|
4486
|
-
case "--people":
|
|
4487
|
-
options.people = parseBootstrapStageRef(value(), "--people");
|
|
4488
|
-
index += 1;
|
|
4489
|
-
break;
|
|
4490
|
-
case "--email":
|
|
4491
|
-
options.email = parseBootstrapStageRef(value(), "--email");
|
|
4492
|
-
index += 1;
|
|
4493
|
-
break;
|
|
4494
|
-
case "--phone":
|
|
4495
|
-
options.phone = parseBootstrapStageRef(value(), "--phone");
|
|
4496
|
-
index += 1;
|
|
4497
|
-
break;
|
|
4498
|
-
case "--limit":
|
|
4499
|
-
options.limit = parsePositiveInteger(value(), "--limit");
|
|
4500
|
-
index += 1;
|
|
4501
|
-
break;
|
|
4502
|
-
case "--out":
|
|
4503
|
-
options.out = value();
|
|
4504
|
-
index += 1;
|
|
4505
|
-
break;
|
|
4506
|
-
default:
|
|
4507
|
-
throw new PlayBootstrapUsageError(
|
|
4508
|
-
`Unknown plays bootstrap option: ${arg}
|
|
4509
|
-
${playBootstrapUsageLine()}`
|
|
4510
|
-
);
|
|
4511
|
-
}
|
|
4512
|
-
}
|
|
4513
|
-
return normalizeTemplateStages(options);
|
|
4514
|
-
}
|
|
4515
|
-
function jsString(value) {
|
|
4516
|
-
return JSON.stringify(value);
|
|
4517
|
-
}
|
|
4518
|
-
function inferCsvCellTypeExpression(values) {
|
|
4519
|
-
const nonEmptyValues = values.map((value) => value.trim()).filter((value) => value.length > 0);
|
|
4520
|
-
const hasEmptyValue = values.some((value) => value.trim().length === 0);
|
|
4521
|
-
if (nonEmptyValues.length === 0) return "string";
|
|
4522
|
-
const numericPattern = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:[eE][+-]?\d+)?$/;
|
|
4523
|
-
const booleanPattern = /^(?:true|false)$/i;
|
|
4524
|
-
let inferred = "string";
|
|
4525
|
-
if (nonEmptyValues.every((value) => numericPattern.test(value))) {
|
|
4526
|
-
inferred = "`${number}`";
|
|
4527
|
-
} else if (nonEmptyValues.every((value) => booleanPattern.test(value))) {
|
|
4528
|
-
const canonicalBooleanValues = nonEmptyValues.every(
|
|
4529
|
-
(value) => value === "true" || value === "false"
|
|
4530
|
-
);
|
|
4531
|
-
inferred = canonicalBooleanValues ? '"false" | "true"' : [...new Set(nonEmptyValues)].sort().map(jsString).join(" | ");
|
|
4532
|
-
}
|
|
4533
|
-
return hasEmptyValue && inferred !== "string" ? `${inferred} | ""` : inferred;
|
|
4534
|
-
}
|
|
4535
|
-
function inferCsvColumnSpecs(headers, rows) {
|
|
4536
|
-
return headers.map((header) => ({
|
|
4537
|
-
name: header,
|
|
4538
|
-
typeExpression: inferCsvCellTypeExpression(
|
|
4539
|
-
rows.map((row) => String(row[header] ?? ""))
|
|
4540
|
-
)
|
|
4541
|
-
}));
|
|
4542
|
-
}
|
|
4543
|
-
function readCsvSample(csvPath) {
|
|
4544
|
-
const resolvedPath = resolve(csvPath);
|
|
4545
|
-
const size = statSync(resolvedPath).size;
|
|
4546
|
-
const fd = openSync(resolvedPath, "r");
|
|
4547
|
-
const byteLength = Math.min(size, CSV_HEADER_SAMPLE_BYTES);
|
|
4548
|
-
const buffer = Buffer.alloc(byteLength);
|
|
4549
|
-
const bytesRead = readSync(fd, buffer, 0, byteLength, 0);
|
|
4550
|
-
closeSync(fd);
|
|
4551
|
-
if (bytesRead === 0) {
|
|
4552
|
-
throw new PlayBootstrapUsageError(`--from csv:${csvPath} is empty.`);
|
|
4553
|
-
}
|
|
4554
|
-
return {
|
|
4555
|
-
content: buffer.subarray(0, bytesRead).toString("utf8"),
|
|
4556
|
-
truncated: size > bytesRead
|
|
4557
|
-
};
|
|
4558
|
-
}
|
|
4559
|
-
function completeCsvSample(csvPath, sample) {
|
|
4560
|
-
if (!sample.truncated) return sample.content;
|
|
4561
|
-
const lastLineBreak = Math.max(
|
|
4562
|
-
sample.content.lastIndexOf("\n"),
|
|
4563
|
-
sample.content.lastIndexOf("\r")
|
|
4564
|
-
);
|
|
4565
|
-
if (lastLineBreak < 0) {
|
|
4566
|
-
throw new PlayBootstrapUsageError(
|
|
4567
|
-
`CSV header in ${csvPath} is longer than ${CSV_HEADER_SAMPLE_BYTES} bytes; shorten the header row before bootstrapping.`
|
|
4568
|
-
);
|
|
4569
|
-
}
|
|
4570
|
-
return sample.content.slice(0, lastLineBreak + 1);
|
|
4571
|
-
}
|
|
4572
|
-
function readCsvHeaderFields(csvPath, sample) {
|
|
4573
|
-
const records = parseCsvSync(sample, {
|
|
4574
|
-
bom: true,
|
|
4575
|
-
to_line: 1,
|
|
4576
|
-
relax_column_count: true,
|
|
4577
|
-
skip_empty_lines: false
|
|
4578
|
-
});
|
|
4579
|
-
const firstRecord = Array.isArray(records) ? records[0] : null;
|
|
4580
|
-
const fields2 = Array.isArray(firstRecord) ? firstRecord.map((field) => String(field ?? "").trim()).filter(Boolean) : [];
|
|
4581
|
-
const uniqueFields = [...new Set(fields2)];
|
|
4582
|
-
if (uniqueFields.length === 0) {
|
|
4583
|
-
throw new PlayBootstrapUsageError(
|
|
4584
|
-
`Could not read a header row from --from csv:${csvPath}.`
|
|
4585
|
-
);
|
|
4586
|
-
}
|
|
4587
|
-
return uniqueFields;
|
|
4588
|
-
}
|
|
4589
|
-
function readCsvSampleRows(sample) {
|
|
4590
|
-
const parsedRows = parseCsvSync(sample, {
|
|
4591
|
-
bom: true,
|
|
4592
|
-
columns: true,
|
|
4593
|
-
skip_empty_lines: true,
|
|
4594
|
-
relax_column_count: true,
|
|
4595
|
-
trim: true
|
|
4596
|
-
});
|
|
4597
|
-
return Array.isArray(parsedRows) ? parsedRows.filter(isRecord) : [];
|
|
4598
|
-
}
|
|
4599
|
-
function readSourceCsvColumnSpecs(csvPath) {
|
|
4600
|
-
const sample = readCsvSample(csvPath);
|
|
4601
|
-
const completeSample = completeCsvSample(csvPath, sample);
|
|
4602
|
-
return inferCsvColumnSpecs(
|
|
4603
|
-
readCsvHeaderFields(csvPath, sample.content),
|
|
4604
|
-
readCsvSampleRows(completeSample)
|
|
4605
|
-
);
|
|
4606
|
-
}
|
|
4607
|
-
function renderSourceCsvRowType(columns) {
|
|
4608
|
-
if (columns.length === 0) return "";
|
|
4609
|
-
const properties = columns.map((column) => ` ${jsString(column.name)}: ${column.typeExpression};`).join("\n");
|
|
4610
|
-
return `// CSV cells are strings at runtime. \`${"${number}"}\` means a numeric-looking CSV string; cast before math.
|
|
4611
|
-
type SourceCsvRow = {
|
|
4612
|
-
${properties}
|
|
4613
|
-
};
|
|
4614
|
-
|
|
4615
|
-
`;
|
|
4616
|
-
}
|
|
4617
|
-
function packagedCsvPathForPlay(csvPath) {
|
|
4618
|
-
const playDir = process.cwd();
|
|
4619
|
-
const absoluteCsvPath = resolve(csvPath);
|
|
4620
|
-
const relativePath = relative(playDir, absoluteCsvPath);
|
|
4621
|
-
if (relativePath === "" || relativePath.startsWith("..") || isAbsolute(relativePath)) {
|
|
4622
|
-
throw new PlayBootstrapUsageError(
|
|
4623
|
-
`--from csv:${csvPath} must point to a file inside the directory where you run plays bootstrap. Run bootstrap from the intended play directory and write the play with --out there.`
|
|
4624
|
-
);
|
|
4625
|
-
}
|
|
4626
|
-
const portablePath = relativePath.split("\\").join("/");
|
|
4627
|
-
return portablePath.startsWith(".") ? portablePath : `./${portablePath}`;
|
|
4628
|
-
}
|
|
4629
|
-
function getterNamesFromTool(tool, kind) {
|
|
4630
|
-
const usageGuidance = isRecord(tool?.usageGuidance) ? tool.usageGuidance : {};
|
|
4631
|
-
const resultGuidance = isRecord(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
|
|
4632
|
-
const key = kind === "list" ? "extractedLists" : "extractedValues";
|
|
4633
|
-
const snakeKey = kind === "list" ? "extracted_lists" : "extracted_values";
|
|
4634
|
-
return extractionEntries(resultGuidance[key] ?? resultGuidance[snakeKey]).map((entry) => stringValue(entry.name)).filter(Boolean);
|
|
4635
|
-
}
|
|
4636
|
-
function targetGettersFromTool(tool) {
|
|
4637
|
-
const record3 = isRecord(tool) ? tool : {};
|
|
4638
|
-
const raw = record3.targetGetters ?? record3.target_getters;
|
|
4639
|
-
if (!isRecord(raw)) return {};
|
|
4640
|
-
const entries = [];
|
|
4641
|
-
for (const [target, value] of Object.entries(raw)) {
|
|
4642
|
-
const paths = Array.isArray(value) ? value.map((path) => typeof path === "string" ? path.trim() : "").filter(Boolean) : [];
|
|
4643
|
-
if (target.trim() && paths.length > 0) {
|
|
4644
|
-
entries.push([target.trim(), paths]);
|
|
4645
|
-
}
|
|
4646
|
-
}
|
|
4647
|
-
return Object.fromEntries(entries);
|
|
4648
|
-
}
|
|
4649
|
-
function listRowCandidateKeysFromTool(tool) {
|
|
4650
|
-
const keys = /* @__PURE__ */ new Set();
|
|
4651
|
-
for (const paths of Object.values(targetGettersFromTool(tool))) {
|
|
4652
|
-
for (const path of paths) {
|
|
4653
|
-
const key = path.replace(/\[(?:\*|\d+)\]/g, "").split(/[.[\]]/, 1)[0]?.trim();
|
|
4654
|
-
if (key) keys.add(key);
|
|
4655
|
-
}
|
|
4656
|
-
}
|
|
4657
|
-
return [...keys].sort();
|
|
4658
|
-
}
|
|
4659
|
-
function inputPropertyNames(schema) {
|
|
4660
|
-
if (!isRecord(schema)) return [];
|
|
4661
|
-
if (isRecord(schema.properties)) return Object.keys(schema.properties);
|
|
4662
|
-
if (Array.isArray(schema.fields)) {
|
|
4663
|
-
return schema.fields.filter(isRecord).map((field) => stringValue(field.name)).filter(Boolean);
|
|
4664
|
-
}
|
|
4665
|
-
return [];
|
|
4666
|
-
}
|
|
4667
|
-
function schemaFieldDetails(schema) {
|
|
4668
|
-
const required = requiredPlayInputFields({
|
|
4669
|
-
inputSchema: schema
|
|
4670
|
-
});
|
|
4671
|
-
const optional = inputPropertyNames(schema).filter(
|
|
4672
|
-
(field) => !required.includes(field)
|
|
4673
|
-
);
|
|
4674
|
-
return { required, optional };
|
|
4675
|
-
}
|
|
4676
|
-
function jsonSchemaTypeExpression(schema) {
|
|
4677
|
-
if (!isRecord(schema)) return "unknown";
|
|
4678
|
-
const type = schema.type;
|
|
4679
|
-
if (Array.isArray(type)) {
|
|
4680
|
-
return type.map((entry) => jsonSchemaTypeExpression({ ...schema, type: entry })).join(" | ");
|
|
4681
|
-
}
|
|
4682
|
-
if (Array.isArray(schema.anyOf)) {
|
|
4683
|
-
return schema.anyOf.map(jsonSchemaTypeExpression).join(" | ");
|
|
4684
|
-
}
|
|
4685
|
-
if (Array.isArray(schema.oneOf)) {
|
|
4686
|
-
return schema.oneOf.map(jsonSchemaTypeExpression).join(" | ");
|
|
4687
|
-
}
|
|
4688
|
-
switch (type) {
|
|
4689
|
-
case "string":
|
|
4690
|
-
return "string";
|
|
4691
|
-
case "number":
|
|
4692
|
-
case "integer":
|
|
4693
|
-
return "number";
|
|
4694
|
-
case "boolean":
|
|
4695
|
-
return "boolean";
|
|
4696
|
-
case "null":
|
|
4697
|
-
return "null";
|
|
4698
|
-
case "array":
|
|
4699
|
-
return `Array<${jsonSchemaTypeExpression(schema.items)}>`;
|
|
4700
|
-
case "object":
|
|
4701
|
-
return "Record<string, unknown>";
|
|
4702
|
-
default:
|
|
4703
|
-
return "unknown";
|
|
4704
|
-
}
|
|
4705
|
-
}
|
|
4706
|
-
function objectPropertySchema(schema, property) {
|
|
4707
|
-
return isRecord(schema) && isRecord(schema.properties) ? schema.properties[property] : null;
|
|
4708
|
-
}
|
|
4709
|
-
function playOutputHasField(schema, field) {
|
|
4710
|
-
return objectPropertySchema(schema, field) != null;
|
|
4711
|
-
}
|
|
4712
|
-
function finderResultTypeName(finder) {
|
|
4713
|
-
return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
|
|
4714
|
-
}
|
|
4715
|
-
function renderFinderPlayResultType(input) {
|
|
4716
|
-
if (!input.play) return null;
|
|
4717
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
|
|
4718
|
-
const fieldSchema = objectPropertySchema(
|
|
4719
|
-
input.play.outputSchema,
|
|
4720
|
-
outputField
|
|
4721
|
-
);
|
|
4722
|
-
if (fieldSchema) {
|
|
4723
|
-
const fieldType = jsonSchemaTypeExpression(fieldSchema);
|
|
4724
|
-
return `type ${finderResultTypeName(input.finder)} = {
|
|
4725
|
-
${outputField}?: ${fieldType};
|
|
4726
|
-
};`;
|
|
4727
|
-
}
|
|
4728
|
-
return `type ${finderResultTypeName(input.finder)} = ${jsonSchemaTypeExpression(input.play.outputSchema)};`;
|
|
4729
|
-
}
|
|
4730
|
-
function generatedFinderPlayResultTypes(input) {
|
|
4731
|
-
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
4732
|
-
const stage = finderStage(input.options, finder);
|
|
4733
|
-
if (stage?.kind !== "play") return [];
|
|
4734
|
-
const typeDefinition = renderFinderPlayResultType({
|
|
4735
|
-
finder,
|
|
4736
|
-
play: input.finderPlays[finder]
|
|
4737
|
-
});
|
|
4738
|
-
return typeDefinition ? [typeDefinition] : [];
|
|
4739
|
-
}).join("\n\n");
|
|
4740
|
-
}
|
|
4741
|
-
function exampleValueComment(field) {
|
|
4742
|
-
if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size") {
|
|
4743
|
-
return "limit";
|
|
4744
|
-
}
|
|
4745
|
-
if (field === "roles" || field.endsWith("s")) return '["..."]';
|
|
4746
|
-
return '"..."';
|
|
4747
|
-
}
|
|
4748
|
-
function rowFieldValueExpression(field) {
|
|
4749
|
-
if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size" || field === "max_duration") {
|
|
4750
|
-
return `Number(row[${jsString(field)}] ?? 0)`;
|
|
4751
|
-
}
|
|
4752
|
-
if (field === "roles" || field.endsWith("s")) {
|
|
4753
|
-
return `String(row[${jsString(field)}] ?? '').split(',').map((item) => item.trim()).filter(Boolean)`;
|
|
4754
|
-
}
|
|
4755
|
-
return `String(row[${jsString(field)}] ?? '')`;
|
|
4756
|
-
}
|
|
4757
|
-
function generateContactInputObjectFromSchema(schema, indent, label, fallbackFields = ["first_name", "last_name", "domain"]) {
|
|
4758
|
-
const details = schemaFieldDetails(schema);
|
|
4759
|
-
const required = details.required.length ? details.required : fallbackFields;
|
|
4760
|
-
const optional = details.optional;
|
|
4761
|
-
const lines = [
|
|
4762
|
-
`${indent}// TODO: map row fields into ${label}.`,
|
|
4763
|
-
...playInspectionComments(label, indent),
|
|
4764
|
-
`${indent}// Required: ${required.join(", ") || "none declared"}.`
|
|
4765
|
-
];
|
|
4766
|
-
for (const field of required) {
|
|
4767
|
-
lines.push(
|
|
4768
|
-
`${indent}${field}: ${rowFieldValueExpression(field)}, // TODO: confirm source field`
|
|
4769
|
-
);
|
|
4770
|
-
}
|
|
4771
|
-
if (optional.length > 0) {
|
|
4772
|
-
lines.push("");
|
|
4773
|
-
lines.push(`${indent}// optional (delete unused):`);
|
|
4774
|
-
for (const field of optional) {
|
|
4775
|
-
lines.push(`${indent}// ${field}: row["TODO_SOURCE_FIELD"],`);
|
|
4776
|
-
}
|
|
4777
|
-
}
|
|
4778
|
-
return `{
|
|
4779
|
-
${lines.join("\n")}
|
|
4780
|
-
${indent.slice(2)}}`;
|
|
4781
|
-
}
|
|
4782
|
-
function generateCompanyInputObjectFromSchema(schema, indent, label, fallbackFields = ["domain", "company_name"]) {
|
|
4783
|
-
const details = schemaFieldDetails(schema);
|
|
4784
|
-
const required = details.required.length ? details.required : fallbackFields;
|
|
4785
|
-
const optional = details.optional;
|
|
4786
|
-
const lines = [
|
|
4787
|
-
`${indent}// TODO: map company fields into ${label}.`,
|
|
4788
|
-
...playInspectionComments(label, indent),
|
|
4789
|
-
`${indent}// Required: ${required.join(", ") || "none declared"}.`
|
|
4790
|
-
];
|
|
4791
|
-
for (const field of required) {
|
|
4792
|
-
lines.push(`${indent}// ${field}: company["TODO_SOURCE_FIELD"],`);
|
|
4793
|
-
}
|
|
4794
|
-
if (optional.length > 0) {
|
|
4795
|
-
lines.push("");
|
|
4796
|
-
lines.push(`${indent}// optional (delete unused):`);
|
|
4797
|
-
for (const field of optional) {
|
|
4798
|
-
lines.push(`${indent}// ${field}: company["TODO_SOURCE_FIELD"],`);
|
|
4799
|
-
}
|
|
4800
|
-
}
|
|
4801
|
-
return `{
|
|
4802
|
-
${lines.join("\n")}
|
|
4803
|
-
${indent.slice(2)}}`;
|
|
4804
|
-
}
|
|
4805
|
-
function generateSourceProviderInputObject(input) {
|
|
4806
|
-
const { tool, indent, label, entity } = input;
|
|
4807
|
-
const properties = inputPropertyNames(tool?.inputSchema);
|
|
4808
|
-
const details = schemaFieldDetails(tool?.inputSchema);
|
|
4809
|
-
const required = details.required;
|
|
4810
|
-
const includeOptional = properties.length === 0 ? ["query", "title", "domain", "limit"] : properties.filter(
|
|
4811
|
-
(field) => [
|
|
4812
|
-
"query",
|
|
4813
|
-
"q",
|
|
4814
|
-
"search",
|
|
4815
|
-
"title",
|
|
4816
|
-
"role",
|
|
4817
|
-
"persona",
|
|
4818
|
-
"domain",
|
|
4819
|
-
"company_domain",
|
|
4820
|
-
"limit",
|
|
4821
|
-
"numResults",
|
|
4822
|
-
"num_results",
|
|
4823
|
-
"page_size"
|
|
4824
|
-
].includes(field)
|
|
4825
|
-
);
|
|
4826
|
-
const lines = [
|
|
4827
|
-
`${indent}// TODO: fill ${entity} source inputs for ${label}.`,
|
|
4828
|
-
`${indent}// Inspect: deepline describe ${label}`
|
|
4829
|
-
];
|
|
4830
|
-
for (const field of required) {
|
|
4831
|
-
lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
|
|
4832
|
-
}
|
|
4833
|
-
const activeTodoField = required.length === 0 ? ["query", "q", "search", "title", "role", "persona"].find(
|
|
4834
|
-
(field) => includeOptional.includes(field)
|
|
4835
|
-
) ?? "query" : null;
|
|
4836
|
-
if (activeTodoField) {
|
|
4837
|
-
lines.push(
|
|
4838
|
-
`${indent}// ${activeTodoField}: ${exampleValueComment(activeTodoField)},`
|
|
4839
|
-
);
|
|
4840
|
-
}
|
|
4841
|
-
const optionalExamples = includeOptional.filter(
|
|
4842
|
-
(field) => !required.includes(field) && field !== activeTodoField
|
|
4843
|
-
);
|
|
4844
|
-
if (optionalExamples.length > 0) {
|
|
4845
|
-
lines.push("");
|
|
4846
|
-
lines.push(`${indent}// optional - uncomment what this provider supports:`);
|
|
4847
|
-
for (const field of optionalExamples) {
|
|
4848
|
-
if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size") {
|
|
4849
|
-
lines.push(`${indent}// ${field}: limit,`);
|
|
4850
|
-
} else {
|
|
4851
|
-
lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
|
|
4852
|
-
}
|
|
4853
|
-
}
|
|
4854
|
-
}
|
|
4855
|
-
if (!required.some(
|
|
4856
|
-
(field) => ["limit", "numResults", "num_results", "page_size"].includes(field)
|
|
4857
|
-
)) {
|
|
4858
|
-
lines.push(`${indent}limit,`);
|
|
4859
|
-
}
|
|
4860
|
-
return `{
|
|
4861
|
-
${lines.join("\n")}
|
|
4862
|
-
${indent.slice(2)}}`;
|
|
4863
|
-
}
|
|
4864
|
-
function generatePlayInputObject(input) {
|
|
4865
|
-
const { schema, indent, label, entity } = input;
|
|
4866
|
-
const details = schemaFieldDetails(schema);
|
|
4867
|
-
const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
|
|
4868
|
-
const required = details.required.length ? details.required : fallback;
|
|
4869
|
-
const lines = [
|
|
4870
|
-
`${indent}// TODO: fill source play inputs for ${label}.`,
|
|
4871
|
-
...playInspectionComments(label, indent)
|
|
4872
|
-
];
|
|
4873
|
-
for (const field of required) {
|
|
4874
|
-
lines.push(`${indent}// ${field}: ${exampleValueComment(field)},`);
|
|
4875
|
-
}
|
|
4876
|
-
if (!required.includes("limit")) lines.push(`${indent}limit,`);
|
|
4877
|
-
return `{
|
|
4878
|
-
${lines.join("\n")}
|
|
4879
|
-
${indent.slice(2)}}`;
|
|
4880
|
-
}
|
|
4881
|
-
function requiredPlayInputFields(play) {
|
|
4882
|
-
const schema = play?.inputSchema;
|
|
4883
|
-
if (!isRecord(schema)) return [];
|
|
4884
|
-
if (Array.isArray(schema.required)) {
|
|
4885
|
-
return schema.required.filter(
|
|
4886
|
-
(value) => typeof value === "string"
|
|
4887
|
-
);
|
|
4888
|
-
}
|
|
4889
|
-
if (Array.isArray(schema.fields)) {
|
|
4890
|
-
return schema.fields.filter(isRecord).filter(
|
|
4891
|
-
(field) => field.required === true && typeof field.name === "string"
|
|
4892
|
-
).map((field) => String(field.name));
|
|
4893
|
-
}
|
|
4894
|
-
return [];
|
|
4895
|
-
}
|
|
4896
|
-
function sourceProviders(options) {
|
|
4897
|
-
return options.from.kind === "providers" ? options.from.values : [];
|
|
4898
|
-
}
|
|
4899
|
-
function sourcePlayRef(options) {
|
|
4900
|
-
return options.from.kind === "play" ? options.from.value : null;
|
|
4901
|
-
}
|
|
4902
|
-
function stagePlayRef(stage) {
|
|
4903
|
-
return stage?.kind === "play" ? stage.value : null;
|
|
4904
|
-
}
|
|
4905
|
-
function stageProviders(stage) {
|
|
4906
|
-
return stage?.kind === "providers" ? stage.values : [];
|
|
4907
|
-
}
|
|
4908
|
-
function finderStage(options, finder) {
|
|
4909
|
-
return finder === "email_finder" ? options.email : options.phone;
|
|
4910
|
-
}
|
|
4911
|
-
function stepFieldName(finder) {
|
|
4912
|
-
return PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[finder];
|
|
4913
|
-
}
|
|
4914
|
-
function finderProviderStepPrefix(finder) {
|
|
4915
|
-
return finder === "email_finder" ? "emailFinder" : "phoneFinder";
|
|
4916
|
-
}
|
|
4917
|
-
function safeIdentifier(value) {
|
|
4918
|
-
return value.replace(/[^A-Za-z0-9_]+/g, "_");
|
|
4919
|
-
}
|
|
4920
|
-
function playInspectionComments(playRef, indent) {
|
|
4921
|
-
return [`${indent}// Inspect: deepline describe ${playRef}`];
|
|
4922
|
-
}
|
|
4923
|
-
function accessorExpression(base, field) {
|
|
4924
|
-
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(field) ? `${base}.${field}` : `${base}[${jsString(field)}]`;
|
|
4925
|
-
}
|
|
4926
|
-
function sourceCollectionTypeName(entity) {
|
|
4927
|
-
return entity === "company" ? "CompanySourceRow" : "ContactSourceRow";
|
|
4928
|
-
}
|
|
4929
|
-
function renderPartialRowType(input) {
|
|
4930
|
-
if (input.fields.length === 0) {
|
|
4931
|
-
return `type ${input.typeName} = Record<string, unknown>;`;
|
|
4932
|
-
}
|
|
4933
|
-
const properties = input.fields.map((field) => ` ${jsString(field)}?: unknown;`).join("\n");
|
|
4934
|
-
return `type ${input.typeName} = Record<string, unknown> & Partial<{
|
|
4935
|
-
// ${input.comment}
|
|
4936
|
-
${properties}
|
|
4937
|
-
}>;`;
|
|
4938
|
-
}
|
|
4939
|
-
function fieldsFromSchemaDetails(input) {
|
|
4940
|
-
return [
|
|
4941
|
-
...input.details.required.length ? input.details.required : input.fallbackFields,
|
|
4942
|
-
...input.details.optional
|
|
4943
|
-
];
|
|
4944
|
-
}
|
|
4945
|
-
function schemaFieldsForStage(stage, input) {
|
|
4946
|
-
switch (stage?.kind) {
|
|
4947
|
-
case void 0:
|
|
4948
|
-
return [];
|
|
4949
|
-
case "play":
|
|
4950
|
-
return fieldsFromSchemaDetails({
|
|
4951
|
-
details: schemaFieldDetails(input.play?.inputSchema),
|
|
4952
|
-
fallbackFields: input.fallbackFields
|
|
4953
|
-
});
|
|
4954
|
-
case "providers":
|
|
4955
|
-
return input.tools.flatMap(
|
|
4956
|
-
(tool) => fieldsFromSchemaDetails({
|
|
4957
|
-
details: schemaFieldDetails(tool.inputSchema),
|
|
4958
|
-
fallbackFields: input.fallbackFields
|
|
4959
|
-
})
|
|
4960
|
-
);
|
|
4961
|
-
}
|
|
4962
|
-
}
|
|
4963
|
-
function sourceRowTypeDefinition(input) {
|
|
4964
|
-
switch (input.options.from.kind) {
|
|
4965
|
-
case "csv":
|
|
4966
|
-
return `type ${input.sourceTypeName} = SourceCsvRow;`;
|
|
4967
|
-
case "providers":
|
|
4968
|
-
return renderPartialRowType({
|
|
4969
|
-
typeName: input.sourceTypeName,
|
|
4970
|
-
fields: [
|
|
4971
|
-
...new Set(input.sourceTools.flatMap(listRowCandidateKeysFromTool))
|
|
4972
|
-
].sort(),
|
|
4973
|
-
comment: "Candidate source row keys from described list getters; confirm the actual provider keys with source_*.extractedLists.*.keys before mapping."
|
|
4974
|
-
});
|
|
4975
|
-
case "play": {
|
|
4976
|
-
const details = schemaFieldDetails(input.sourcePlay?.outputSchema);
|
|
4977
|
-
return renderPartialRowType({
|
|
4978
|
-
typeName: input.sourceTypeName,
|
|
4979
|
-
fields: [...details.required, ...details.optional].sort(),
|
|
4980
|
-
comment: "Candidate source play output fields; confirm the selected rows field before mapping."
|
|
4981
|
-
});
|
|
4982
|
-
}
|
|
4983
|
-
}
|
|
4984
|
-
}
|
|
4985
|
-
function contactBridgeRowTypeDefinition(input) {
|
|
4986
|
-
const config = playBootstrapTemplateConfig(input.options.template);
|
|
4987
|
-
if (config.sourceEntity !== "company" || !input.options.people) return null;
|
|
4988
|
-
const emailFields = schemaFieldsForStage(input.options.email, {
|
|
4989
|
-
tools: input.finderTools.email_finder ?? [],
|
|
4990
|
-
play: input.finderPlays.email_finder,
|
|
4991
|
-
fallbackFields: ["first_name", "last_name", "domain"]
|
|
4992
|
-
});
|
|
4993
|
-
const phoneFields = schemaFieldsForStage(input.options.phone, {
|
|
4994
|
-
tools: input.finderTools.phone_finder ?? [],
|
|
4995
|
-
play: input.finderPlays.phone_finder,
|
|
4996
|
-
fallbackFields: ["first_name", "last_name", "domain"]
|
|
4997
|
-
});
|
|
4998
|
-
return renderPartialRowType({
|
|
4999
|
-
typeName: "ContactSourceRow",
|
|
5000
|
-
fields: [
|
|
5001
|
-
.../* @__PURE__ */ new Set([
|
|
5002
|
-
...inputPropertyNames(input.peoplePlay?.outputSchema),
|
|
5003
|
-
...emailFields,
|
|
5004
|
-
...phoneFields
|
|
5005
|
-
])
|
|
5006
|
-
].sort(),
|
|
5007
|
-
comment: "Fields the people play or later finder stages may need; the generated code still requires explicit mapping."
|
|
5008
|
-
});
|
|
5009
|
-
}
|
|
5010
|
-
function generateRowTypeDefinitions(input) {
|
|
5011
|
-
const config = playBootstrapTemplateConfig(input.options.template);
|
|
5012
|
-
const sourceTypeName = sourceCollectionTypeName(config.sourceEntity);
|
|
5013
|
-
const definitions = [
|
|
5014
|
-
sourceRowTypeDefinition({
|
|
5015
|
-
options: input.options,
|
|
5016
|
-
sourceTypeName,
|
|
5017
|
-
sourceTools: input.sourceTools,
|
|
5018
|
-
sourcePlay: input.sourcePlay
|
|
5019
|
-
}),
|
|
5020
|
-
contactBridgeRowTypeDefinition(input)
|
|
5021
|
-
];
|
|
5022
|
-
return definitions.filter(Boolean).join("\n\n");
|
|
5023
|
-
}
|
|
5024
|
-
function validateBootstrapRoutes(input) {
|
|
5025
|
-
const config = playBootstrapTemplateConfig(input.options.template);
|
|
5026
|
-
const sourceCategory = config.sourceEntity === "company" ? PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY : PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY;
|
|
5027
|
-
for (const tool of input.sourceTools) {
|
|
5028
|
-
if (!tool.categories.includes(sourceCategory)) {
|
|
5029
|
-
throw new PlayBootstrapValidationError(
|
|
5030
|
-
`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`
|
|
5031
|
-
);
|
|
5032
|
-
}
|
|
5033
|
-
if (getterNamesFromTool(tool, "list").length === 0) {
|
|
5034
|
-
throw new PlayBootstrapValidationError(
|
|
5035
|
-
`Cannot use ${tool.toolId} as a ${config.sourceEntity} source: it exposes no extracted list getters. Run: deepline describe ${tool.toolId}`
|
|
5036
|
-
);
|
|
5037
|
-
}
|
|
5038
|
-
}
|
|
5039
|
-
if (input.options.people?.kind === "providers") {
|
|
5040
|
-
throw new PlayBootstrapValidationError(
|
|
5041
|
-
"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."
|
|
5042
|
-
);
|
|
5043
|
-
}
|
|
5044
|
-
assertComposablePlayRoute({
|
|
5045
|
-
stageLabel: "--people",
|
|
5046
|
-
playRef: stagePlayRef(input.options.people),
|
|
5047
|
-
play: input.peoplePlay
|
|
5048
|
-
});
|
|
5049
|
-
for (const finder of ["email_finder", "phone_finder"]) {
|
|
5050
|
-
const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
|
|
5051
|
-
assertComposablePlayRoute({
|
|
5052
|
-
stageLabel: finder === "email_finder" ? "--email/--using" : "--phone/--using",
|
|
5053
|
-
playRef: stagePlayRef(finderStage(input.options, finder)),
|
|
5054
|
-
play: input.finderPlays[finder] ?? null
|
|
5055
|
-
});
|
|
5056
|
-
for (const tool of input.finderTools[finder] ?? []) {
|
|
5057
|
-
if (!tool.categories.includes(requiredCategory)) {
|
|
5058
|
-
throw new PlayBootstrapValidationError(
|
|
5059
|
-
`Cannot use ${tool.toolId} for ${finder}: expected category ${requiredCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${requiredCategory} --categories ${requiredCategory} --json`
|
|
5060
|
-
);
|
|
5061
|
-
}
|
|
5062
|
-
if (getterNamesFromTool(tool, "value").length === 0) {
|
|
5063
|
-
throw new PlayBootstrapValidationError(
|
|
5064
|
-
`Cannot use ${tool.toolId} as a ${finder}: it exposes no extracted value getters. Run: deepline describe ${tool.toolId}`
|
|
5065
|
-
);
|
|
5066
|
-
}
|
|
5067
|
-
}
|
|
5068
|
-
}
|
|
5069
|
-
}
|
|
5070
|
-
function staticPipelineSubsteps(pipeline) {
|
|
5071
|
-
if (!isRecord(pipeline)) return [];
|
|
5072
|
-
return [
|
|
5073
|
-
...extractionEntries(pipeline.stages),
|
|
5074
|
-
...extractionEntries(pipeline.substeps)
|
|
5075
|
-
];
|
|
5076
|
-
}
|
|
5077
|
-
function playUsesMapBackedRuntime(play) {
|
|
5078
|
-
const pipeline = play?.staticPipeline;
|
|
5079
|
-
if (!isRecord(pipeline)) return false;
|
|
5080
|
-
if (stringValue(pipeline.tableNamespace)) return true;
|
|
5081
|
-
return staticPipelineSubsteps(pipeline).some((substep) => {
|
|
5082
|
-
if (stringValue(substep.type) === "map") return true;
|
|
5083
|
-
return playUsesMapBackedRuntime({
|
|
5084
|
-
name: play?.name ?? "child",
|
|
5085
|
-
aliases: [],
|
|
5086
|
-
runCommand: "",
|
|
5087
|
-
examples: [],
|
|
5088
|
-
staticPipeline: isRecord(substep.pipeline) ? substep.pipeline : null
|
|
5089
|
-
});
|
|
5090
|
-
});
|
|
5091
|
-
}
|
|
5092
|
-
function assertComposablePlayRoute(input) {
|
|
5093
|
-
if (!input.playRef || !playUsesMapBackedRuntime(input.play)) return;
|
|
5094
|
-
const runCommand = input.play?.runCommand?.trim() || `deepline plays run ${input.playRef} --input '{...}'`;
|
|
5095
|
-
throw new PlayBootstrapValidationError(
|
|
5096
|
-
`Cannot use ${input.stageLabel} play:${input.playRef} in plays bootstrap composition: the selected play is dataset-backed/direct-run-only. Child plays that use ctx.dataset() own durable table state and must be run directly, exported, or validated as their own play instead of wrapped with ctx.runPlay. Run it directly first: ${runCommand}`
|
|
5097
|
-
);
|
|
5098
|
-
}
|
|
5099
|
-
function sourcePlayNeedsExportFirst(input) {
|
|
5100
|
-
return input.source.kind === "play" && playUsesMapBackedRuntime(input.sourcePlay);
|
|
5101
|
-
}
|
|
5102
|
-
function sourceCollectionName(entity) {
|
|
5103
|
-
switch (entity) {
|
|
5104
|
-
case "company":
|
|
5105
|
-
return "companies";
|
|
5106
|
-
case "people":
|
|
5107
|
-
return "contacts";
|
|
5108
|
-
}
|
|
5109
|
-
}
|
|
5110
|
-
function requiredGetterName(input) {
|
|
5111
|
-
const getter = getterNamesFromTool(input.tool, input.kind)[0];
|
|
5112
|
-
if (!getter) {
|
|
5113
|
-
switch (input.kind) {
|
|
5114
|
-
case "list":
|
|
5115
|
-
throw new PlayBootstrapValidationError(
|
|
5116
|
-
`Cannot use ${input.label} as a source: it exposes no extracted list getters.`
|
|
5117
|
-
);
|
|
5118
|
-
case "value":
|
|
5119
|
-
throw new PlayBootstrapValidationError(
|
|
5120
|
-
`Cannot use ${input.label} as a finder: it exposes no extracted value getters.`
|
|
5121
|
-
);
|
|
5122
|
-
}
|
|
5123
|
-
}
|
|
5124
|
-
return getter;
|
|
5125
|
-
}
|
|
5126
|
-
function generateCsvSourceRowsBlock(input) {
|
|
5127
|
-
return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(input.packagedSourceCsvPath ?? input.source.value)});
|
|
5128
|
-
const ${input.collection}: ${input.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
5129
|
-
}
|
|
5130
|
-
function generatePlaySourceRowsBlock(input) {
|
|
5131
|
-
if (sourcePlayNeedsExportFirst({
|
|
5132
|
-
source: input.source,
|
|
5133
|
-
sourcePlay: input.sourcePlay
|
|
5134
|
-
})) {
|
|
5135
|
-
const sourcePlay = input.sourcePlay;
|
|
5136
|
-
const runCommand = sourcePlay?.runCommand?.trim() || `deepline plays run ${input.source.value} --input '{...}'`;
|
|
5137
|
-
return `// Source play ${input.source.value} is dataset-backed/direct-run-only, so this generated play is stage 2.
|
|
5138
|
-
// Stage 1:
|
|
5139
|
-
// ${runCommand}
|
|
5140
|
-
// Stage 2:
|
|
5141
|
-
// deepline runs export <stage-1-run-id> --dataset 'result.rows' --out source-export.csv
|
|
5142
|
-
// Stage 3:
|
|
5143
|
-
// deepline plays run <this-file.play.ts> --input '{"sourceCsv":"source-export.csv","limit":${input.sourcePlay ? "5" : "5"}}'
|
|
5144
|
-
const sourceDataset = await ctx.csv<${input.collectionType}>(input.sourceCsv ?? './source-export.csv');
|
|
5145
|
-
const ${input.collection}: ${input.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
5146
|
-
}
|
|
5147
|
-
const playInput = generatePlayInputObject({
|
|
5148
|
-
schema: input.sourcePlay?.inputSchema,
|
|
5149
|
-
indent: " ",
|
|
5150
|
-
label: input.source.value,
|
|
5151
|
-
entity: input.entity
|
|
5152
|
-
});
|
|
5153
|
-
return `const sourceInput = ${playInput};
|
|
5154
|
-
throw new Error(${jsString(`TODO: map sourceInput for ${input.source.value}, choose the play output rows field, then delete this throw.`)});
|
|
5155
|
-
const sourceResult = (await ctx.runPlay('source_play', ${jsString(input.source.value)}, sourceInput, {
|
|
5156
|
-
description: ${jsString(`Seed ${input.entity} rows from the selected play.`)},
|
|
5157
|
-
})) as { rows?: unknown[] };
|
|
5158
|
-
// TODO: Replace sourceResult.rows with the selected play's actual row output field.
|
|
5159
|
-
const ${input.collection}: ${input.collectionType}[] = (sourceResult.rows ?? []) as ${input.collectionType}[];`;
|
|
5160
|
-
}
|
|
5161
|
-
function generateProviderSourceBlock(input) {
|
|
5162
|
-
const getter = requiredGetterName({
|
|
5163
|
-
tool: input.tool,
|
|
5164
|
-
kind: "list",
|
|
5165
|
-
label: input.provider
|
|
5166
|
-
});
|
|
5167
|
-
const inputName = `${input.entity}Input_${input.index}`;
|
|
5168
|
-
return `// ${input.entity === "company" ? "Company" : "People"} source provider: ${input.provider}
|
|
5169
|
-
const ${inputName}: Record<string, unknown> = ${generateSourceProviderInputObject(
|
|
5170
|
-
{
|
|
5171
|
-
tool: input.tool,
|
|
5172
|
-
indent: " ",
|
|
5173
|
-
label: input.provider,
|
|
5174
|
-
entity: input.entity
|
|
5175
|
-
}
|
|
5176
|
-
)};
|
|
5177
|
-
throw new Error(${jsString(`TODO: fill ${inputName} for ${input.provider}, then delete this throw.`)});
|
|
5178
|
-
const source_${input.index} = await ctx.tools.execute({
|
|
5179
|
-
staleAfterSeconds: 0,
|
|
5180
|
-
id: ${jsString(`${input.entity}_source_${input.index}`)},
|
|
5181
|
-
tool: ${jsString(input.provider)},
|
|
5182
|
-
input: ${inputName},
|
|
5183
|
-
description: ${jsString(`Seed ${input.entity} rows from ${input.provider}.`)},
|
|
5184
|
-
});
|
|
5185
|
-
// extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
|
|
5186
|
-
// inspect source_${input.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
|
|
5187
|
-
const sourceList_${input.index} = ${accessorExpression(`source_${input.index}.extractedLists`, getter)}.get();
|
|
5188
|
-
// Legacy admitted Plays use a dataset getter; the new contract returns an ordinary array.
|
|
5189
|
-
const sourceRows_${input.index} = (Array.isArray(sourceList_${input.index})
|
|
5190
|
-
? sourceList_${input.index}.slice(0, limit)
|
|
5191
|
-
: await sourceList_${input.index}.peek(limit)) as ${input.collectionType}[];`;
|
|
5192
|
-
}
|
|
5193
|
-
function generateProviderSourceRowsBlock(input) {
|
|
5194
|
-
const blocks = input.source.values.map(
|
|
5195
|
-
(provider, index) => generateProviderSourceBlock({
|
|
5196
|
-
provider,
|
|
5197
|
-
index,
|
|
5198
|
-
tool: input.sourceTools[index] ?? null,
|
|
5199
|
-
entity: input.entity,
|
|
5200
|
-
collectionType: input.collectionType
|
|
5201
|
-
})
|
|
5202
|
-
);
|
|
5203
|
-
return `${blocks.join("\n\n ")}
|
|
5204
|
-
const ${input.collection}: ${input.collectionType}[] = [${input.source.values.map((_, index) => `...sourceRows_${index}`).join(", ")}];`;
|
|
5205
|
-
}
|
|
5206
|
-
function generateSourceRowsBlock(input) {
|
|
5207
|
-
const config = playBootstrapTemplateConfig(input.options.template);
|
|
5208
|
-
const entity = config.sourceEntity;
|
|
5209
|
-
const collection = sourceCollectionName(entity);
|
|
5210
|
-
const collectionType = sourceCollectionTypeName(entity);
|
|
5211
|
-
switch (input.options.from.kind) {
|
|
5212
|
-
case "csv":
|
|
5213
|
-
return generateCsvSourceRowsBlock({
|
|
5214
|
-
source: input.options.from,
|
|
5215
|
-
collection,
|
|
5216
|
-
collectionType,
|
|
5217
|
-
packagedSourceCsvPath: input.packagedSourceCsvPath
|
|
5218
|
-
});
|
|
5219
|
-
case "play":
|
|
5220
|
-
return generatePlaySourceRowsBlock({
|
|
5221
|
-
source: input.options.from,
|
|
5222
|
-
sourcePlay: input.sourcePlay,
|
|
5223
|
-
entity,
|
|
5224
|
-
collection,
|
|
5225
|
-
collectionType
|
|
5226
|
-
});
|
|
5227
|
-
case "providers":
|
|
5228
|
-
return generateProviderSourceRowsBlock({
|
|
5229
|
-
source: input.options.from,
|
|
5230
|
-
sourceTools: input.sourceTools,
|
|
5231
|
-
entity,
|
|
5232
|
-
collection,
|
|
5233
|
-
collectionType
|
|
5234
|
-
});
|
|
5235
|
-
}
|
|
5236
|
-
}
|
|
5237
|
-
function generateSourceSeedBlock(input) {
|
|
5238
|
-
const sourceRows = generateSourceRowsBlock(input);
|
|
5239
|
-
const peoplePlayRef = stagePlayRef(input.options.people);
|
|
5240
|
-
if (!peoplePlayRef) return sourceRows;
|
|
5241
|
-
const peopleInput = generateCompanyInputObjectFromSchema(
|
|
5242
|
-
input.peoplePlay?.inputSchema,
|
|
5243
|
-
" ",
|
|
5244
|
-
peoplePlayRef,
|
|
5245
|
-
["domain", "company_name"]
|
|
5246
|
-
);
|
|
5247
|
-
return `${sourceRows}
|
|
5248
|
-
const contacts: ContactSourceRow[] = [];
|
|
5249
|
-
for (const [index, company] of companies.slice(0, limit).entries()) {
|
|
5250
|
-
const peopleInput = ${peopleInput};
|
|
5251
|
-
throw new Error(${jsString(`TODO: map company fields into peopleInput for ${peoplePlayRef}, choose the play output rows field, then delete this throw.`)});
|
|
5252
|
-
const peopleResult = (await ctx.runPlay(
|
|
5253
|
-
\`people_play_\${index}\`,
|
|
5254
|
-
${jsString(peoplePlayRef)},
|
|
5255
|
-
peopleInput,
|
|
5256
|
-
{
|
|
5257
|
-
description: 'Map one company row into people/contact rows with the selected play.',
|
|
5258
|
-
},
|
|
5259
|
-
)) as { rows?: unknown[] };
|
|
5260
|
-
// TODO: Replace peopleResult.rows with the selected play's actual contact rows field.
|
|
5261
|
-
contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
|
|
5262
|
-
}`;
|
|
5263
|
-
}
|
|
5264
|
-
function finderProviderStepName(input) {
|
|
5265
|
-
return `${input.aggregateStepName}${input.index}_${safeIdentifier(input.provider)}`;
|
|
5266
|
-
}
|
|
5267
|
-
function finderValueGetter(input) {
|
|
5268
|
-
const getters = getterNamesFromTool(input.tool, "value");
|
|
5269
|
-
const getter = getters.find((name) => name === input.outputField) ?? requiredGetterName({
|
|
5270
|
-
tool: input.tool,
|
|
5271
|
-
kind: "value",
|
|
5272
|
-
label: input.provider
|
|
5273
|
-
});
|
|
5274
|
-
return getter;
|
|
5275
|
-
}
|
|
5276
|
-
function optionalFinderValueExpression(candidateExpression, outputField) {
|
|
5277
|
-
const valueExpression = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(outputField) ? `${candidateExpression}?.${outputField}` : `${candidateExpression}?.[${jsString(outputField)}]`;
|
|
5278
|
-
return `${valueExpression}?.trim()`;
|
|
5279
|
-
}
|
|
5280
|
-
function generateFinderPlayStep(input) {
|
|
5281
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
|
|
5282
|
-
const resultTypeName = finderResultTypeName(input.finder);
|
|
5283
|
-
const returnsObjectWithField = playOutputHasField(
|
|
5284
|
-
input.play?.outputSchema,
|
|
5285
|
-
outputField
|
|
5286
|
-
);
|
|
5287
|
-
const payload = generateContactInputObjectFromSchema(
|
|
5288
|
-
input.play?.inputSchema,
|
|
5289
|
-
" ",
|
|
5290
|
-
input.stage.value
|
|
5291
|
-
);
|
|
5292
|
-
return `.withColumn(${jsString(outputField)}, async (row, rowCtx) => {
|
|
5293
|
-
const ${input.aggregateStepName}Input = ${payload};
|
|
5294
|
-
throw new Error(${jsString(`TODO: map ${input.aggregateStepName}Input for ${input.stage.value}, then delete this throw.`)});
|
|
5295
|
-
const ${input.aggregateStepName}Result = await rowCtx.runPlay<${resultTypeName}>(
|
|
5296
|
-
${jsString(`${input.aggregateStepName}Play`)},
|
|
5297
|
-
${jsString(input.stage.value)},
|
|
5298
|
-
${input.aggregateStepName}Input,
|
|
5299
|
-
{
|
|
5300
|
-
description: ${jsString(`Run ${input.finder} play.`)},
|
|
5301
|
-
},
|
|
5302
|
-
);
|
|
5303
|
-
return ${returnsObjectWithField ? `${input.aggregateStepName}Result.${outputField} ?? null` : `${input.aggregateStepName}Result ?? null`};
|
|
5304
|
-
})`;
|
|
5305
|
-
}
|
|
5306
|
-
function generateFinderProviderResolver(input) {
|
|
5307
|
-
const payload = generateContactInputObjectFromSchema(
|
|
5308
|
-
input.tool?.inputSchema,
|
|
5309
|
-
" ",
|
|
5310
|
-
input.provider
|
|
5311
|
-
);
|
|
5312
|
-
const getter = finderValueGetter({
|
|
5313
|
-
tool: input.tool,
|
|
5314
|
-
provider: input.provider,
|
|
5315
|
-
outputField: input.outputField
|
|
5316
|
-
});
|
|
5317
|
-
return `async (row, rowCtx) => {
|
|
5318
|
-
const providerInput = ${payload};
|
|
5319
|
-
throw new Error(${jsString(`TODO: map providerInput for ${input.provider}, then delete this throw.`)});
|
|
5320
|
-
const result = await rowCtx.tools.execute({
|
|
5321
|
-
staleAfterSeconds: 0,
|
|
5322
|
-
id: ${jsString(`${input.aggregateStepName}_${input.providerIndex}`)},
|
|
5323
|
-
tool: ${jsString(input.provider)},
|
|
5324
|
-
input: providerInput,
|
|
5325
|
-
description: ${jsString(`Try ${input.provider} as a ${input.finder}.`)},
|
|
5326
|
-
});
|
|
5327
|
-
return {
|
|
5328
|
-
${input.outputField}: (${accessorExpression("result.extractedValues", getter)}.get() as string | null) ?? null,
|
|
5329
|
-
result,
|
|
5330
|
-
};
|
|
5331
|
-
}`;
|
|
5332
|
-
}
|
|
5333
|
-
function generateFinderProviderStep(input) {
|
|
5334
|
-
const stepName = input.stepNames[input.index];
|
|
5335
|
-
switch (input.index) {
|
|
5336
|
-
case 0:
|
|
5337
|
-
return `.withColumn(${jsString(stepName)}, ${input.resolver})`;
|
|
5338
|
-
default: {
|
|
5339
|
-
const priorCandidates = input.stepNames.slice(0, input.index).map((name) => `row.${name}`).join(", ");
|
|
5340
|
-
return `.withColumn(
|
|
5341
|
-
${jsString(stepName)},
|
|
5342
|
-
${input.resolver},
|
|
5343
|
-
{
|
|
5344
|
-
runIf: (row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate", input.outputField)}),
|
|
5345
|
-
},
|
|
5346
|
-
)`;
|
|
5347
|
-
}
|
|
5348
|
-
}
|
|
5349
|
-
}
|
|
5350
|
-
function generateFinderProviderWaterfall(input) {
|
|
5351
|
-
const legPrefix = finderProviderStepPrefix(input.finder);
|
|
5352
|
-
const stepNames = input.stage.values.map(
|
|
5353
|
-
(provider, index) => finderProviderStepName({
|
|
5354
|
-
aggregateStepName: legPrefix,
|
|
5355
|
-
provider,
|
|
5356
|
-
index
|
|
5357
|
-
})
|
|
5358
|
-
);
|
|
5359
|
-
const providerSteps = input.stage.values.map(
|
|
5360
|
-
(provider, index) => generateFinderProviderStep({
|
|
5361
|
-
index,
|
|
5362
|
-
stepNames,
|
|
5363
|
-
outputField: input.outputField,
|
|
5364
|
-
resolver: generateFinderProviderResolver({
|
|
5365
|
-
finder: input.finder,
|
|
5366
|
-
provider,
|
|
5367
|
-
providerIndex: index,
|
|
5368
|
-
tool: input.tools[index] ?? null,
|
|
5369
|
-
aggregateStepName: input.aggregateStepName,
|
|
5370
|
-
outputField: input.outputField
|
|
5371
|
-
})
|
|
5372
|
-
})
|
|
5373
|
-
);
|
|
5374
|
-
const candidateNames = stepNames.map((name) => `row.${name}`).join(", ");
|
|
5375
|
-
return `// ${input.aggregateStepName} provider waterfall. Each provider leg is active once its TODO throw is removed;
|
|
5376
|
-
// delete or comment out legs you do not want before running. Later legs are gated with { runIf }.
|
|
5377
|
-
${providerSteps.join("\n ")}
|
|
5378
|
-
.withColumn(${jsString(input.aggregateStepName)}, (row) => {
|
|
5379
|
-
const candidates = [${candidateNames}];
|
|
5380
|
-
const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate", input.outputField)});
|
|
5381
|
-
return ${optionalFinderValueExpression("match", input.outputField)} ?? null;
|
|
5382
|
-
})`;
|
|
5383
|
-
}
|
|
5384
|
-
function generateFinderStageSteps(input) {
|
|
5385
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input.finder];
|
|
5386
|
-
const aggregateStepName = stepFieldName(input.finder);
|
|
5387
|
-
switch (input.stage.kind) {
|
|
5388
|
-
case "play":
|
|
5389
|
-
return generateFinderPlayStep({
|
|
5390
|
-
finder: input.finder,
|
|
5391
|
-
stage: input.stage,
|
|
5392
|
-
play: input.finderPlays[input.finder],
|
|
5393
|
-
aggregateStepName
|
|
5394
|
-
});
|
|
5395
|
-
case "providers":
|
|
5396
|
-
return generateFinderProviderWaterfall({
|
|
5397
|
-
finder: input.finder,
|
|
5398
|
-
stage: input.stage,
|
|
5399
|
-
tools: input.finderTools[input.finder] ?? [],
|
|
5400
|
-
aggregateStepName,
|
|
5401
|
-
outputField
|
|
5402
|
-
});
|
|
5403
|
-
}
|
|
5404
|
-
}
|
|
5405
|
-
function generateFinderSteps(input) {
|
|
5406
|
-
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
5407
|
-
const stage = finderStage(input.options, finder);
|
|
5408
|
-
return stage ? [
|
|
5409
|
-
generateFinderStageSteps({
|
|
5410
|
-
...input,
|
|
5411
|
-
finder,
|
|
5412
|
-
stage
|
|
5413
|
-
})
|
|
5414
|
-
] : [];
|
|
5415
|
-
}).join("\n ");
|
|
5416
|
-
}
|
|
5417
|
-
function generateBootstrapPlaySource(input) {
|
|
5418
|
-
const config = playBootstrapTemplateConfig(input.options.template);
|
|
5419
|
-
const sourceSeedBlock = generateSourceSeedBlock(input);
|
|
5420
|
-
const finderSteps = generateFinderSteps(input);
|
|
5421
|
-
const hasPeople = config.sourceEntity === "people" || Boolean(input.options.people);
|
|
5422
|
-
const sourceCollection = hasPeople ? "contacts" : "companies";
|
|
5423
|
-
const mapSteps = finderSteps ? `
|
|
5424
|
-
${finderSteps}` : "";
|
|
5425
|
-
const sourceCsvRowType = input.options.from.kind === "csv" ? renderSourceCsvRowType(input.sourceCsvColumns) : "";
|
|
5426
|
-
const rowTypeDefinitions = generateRowTypeDefinitions(input);
|
|
5427
|
-
const finderPlayResultTypes = generatedFinderPlayResultTypes(input);
|
|
5428
|
-
const typeDefinitions = [
|
|
5429
|
-
sourceCsvRowType.trimEnd(),
|
|
5430
|
-
rowTypeDefinitions,
|
|
5431
|
-
finderPlayResultTypes
|
|
5432
|
-
].filter((definition) => definition.trim().length > 0).join("\n\n");
|
|
5433
|
-
return `import { definePlay } from 'deepline';
|
|
5434
|
-
|
|
5435
|
-
${typeDefinitions}
|
|
5436
|
-
|
|
5437
|
-
type Input = {
|
|
5438
|
-
limit?: number;
|
|
5439
|
-
sourceCsv?: string;
|
|
5440
|
-
};
|
|
5441
|
-
|
|
5442
|
-
export default definePlay(${jsString(input.options.name)}, async (ctx, input: Input = {}) => {
|
|
5443
|
-
const limit = Math.max(1, Math.min(Number(input.limit ?? ${input.options.limit}), ${input.options.limit}));
|
|
5444
|
-
${sourceSeedBlock}
|
|
5445
|
-
|
|
5446
|
-
const rowsToProcess = ${sourceCollection}.slice(0, limit);
|
|
5447
|
-
if (rowsToProcess.length === 0) {
|
|
5448
|
-
throw new Error('plays bootstrap found 0 source rows. Check the source provider/play/CSV output.');
|
|
5449
|
-
}
|
|
5450
|
-
|
|
5451
|
-
const rows = await ctx
|
|
5452
|
-
.dataset('bootstrap_rows', rowsToProcess)${mapSteps}
|
|
5453
|
-
.run({
|
|
5454
|
-
key: (_row, index) => index,
|
|
5455
|
-
description: ${jsString(`Bootstrap ${input.options.template}: seed source rows, run requested stages, then return the mapped rows.`)},
|
|
5456
|
-
});
|
|
5457
|
-
|
|
5458
|
-
return {
|
|
5459
|
-
count: await rows.count(),
|
|
5460
|
-
rows,
|
|
5461
|
-
};
|
|
5462
|
-
}, {
|
|
5463
|
-
description: ${jsString(`Bootstrap ${input.options.template}: seed source rows, run requested stages, and return mapped rows.`)},
|
|
5464
|
-
});
|
|
5465
|
-
|
|
5466
|
-
`;
|
|
5467
|
-
}
|
|
5468
|
-
async function describePlayMaybe(client, playRef) {
|
|
5469
|
-
return playRef ? client.describePlay(playRef, { compact: true }) : null;
|
|
5470
|
-
}
|
|
5471
|
-
function loadTools(client, providers) {
|
|
5472
|
-
return Promise.all(providers.map((provider) => client.getTool(provider)));
|
|
5473
|
-
}
|
|
5474
|
-
async function loadBootstrapContracts(client, options) {
|
|
5475
|
-
const [
|
|
5476
|
-
sourceTools,
|
|
5477
|
-
sourcePlay,
|
|
5478
|
-
peoplePlay,
|
|
5479
|
-
emailPlay,
|
|
5480
|
-
phonePlay,
|
|
5481
|
-
emailTools,
|
|
5482
|
-
phoneTools
|
|
5483
|
-
] = await Promise.all([
|
|
5484
|
-
loadTools(client, sourceProviders(options)),
|
|
5485
|
-
describePlayMaybe(client, sourcePlayRef(options)),
|
|
5486
|
-
describePlayMaybe(client, stagePlayRef(options.people)),
|
|
5487
|
-
describePlayMaybe(client, stagePlayRef(options.email)),
|
|
5488
|
-
describePlayMaybe(client, stagePlayRef(options.phone)),
|
|
5489
|
-
loadTools(client, stageProviders(options.email)),
|
|
5490
|
-
loadTools(client, stageProviders(options.phone))
|
|
5491
|
-
]);
|
|
5492
|
-
const contracts = {
|
|
5493
|
-
sourceTools,
|
|
5494
|
-
sourcePlay,
|
|
5495
|
-
peoplePlay,
|
|
5496
|
-
finderTools: {
|
|
5497
|
-
email_finder: emailTools,
|
|
5498
|
-
phone_finder: phoneTools
|
|
5499
|
-
},
|
|
5500
|
-
finderPlays: {
|
|
5501
|
-
email_finder: emailPlay,
|
|
5502
|
-
phone_finder: phonePlay
|
|
5503
|
-
}
|
|
5504
|
-
};
|
|
5505
|
-
validateBootstrapRoutes({
|
|
5506
|
-
options,
|
|
5507
|
-
sourceTools: contracts.sourceTools,
|
|
5508
|
-
sourcePlay: contracts.sourcePlay,
|
|
5509
|
-
peoplePlay: contracts.peoplePlay,
|
|
5510
|
-
finderTools: contracts.finderTools,
|
|
5511
|
-
finderPlays: contracts.finderPlays
|
|
5512
|
-
});
|
|
5513
|
-
return contracts;
|
|
5514
|
-
}
|
|
5515
|
-
function loadCsvContext(source) {
|
|
5516
|
-
switch (source.kind) {
|
|
5517
|
-
case "csv":
|
|
5518
|
-
return {
|
|
5519
|
-
packagedSourceCsvPath: packagedCsvPathForPlay(source.value),
|
|
5520
|
-
sourceCsvColumns: readSourceCsvColumnSpecs(source.value)
|
|
5521
|
-
};
|
|
5522
|
-
case "play":
|
|
5523
|
-
case "providers":
|
|
5524
|
-
return {
|
|
5525
|
-
packagedSourceCsvPath: null,
|
|
5526
|
-
sourceCsvColumns: []
|
|
5527
|
-
};
|
|
5528
|
-
}
|
|
5529
|
-
}
|
|
5530
|
-
function errorMessage(error) {
|
|
5531
|
-
return error instanceof Error ? error.message : String(error);
|
|
5532
|
-
}
|
|
5533
|
-
function renderPlayBootstrapError(error) {
|
|
5534
|
-
console.error(errorMessage(error));
|
|
5535
|
-
return error instanceof PlayBootstrapError ? error.exitCode : 1;
|
|
5536
|
-
}
|
|
5537
|
-
function writeBootstrapSource(source, out) {
|
|
5538
|
-
if (out) {
|
|
5539
|
-
writeFileSync(resolve(out), source, "utf-8");
|
|
5540
|
-
process.stdout.write(`Wrote ${resolve(out)}
|
|
5541
|
-
`);
|
|
5542
|
-
return 0;
|
|
5543
|
-
}
|
|
5544
|
-
process.stdout.write(source);
|
|
5545
|
-
return 0;
|
|
5546
|
-
}
|
|
5547
|
-
function runMonitorBootstrap(args) {
|
|
5548
|
-
const options = parseMonitorBootstrapOptions(args);
|
|
5549
|
-
const source = generateMonitorTriggeredPlaySource(options);
|
|
5550
|
-
return writeBootstrapSource(source, options.out);
|
|
5551
|
-
}
|
|
5552
|
-
async function runPlayBootstrap(args) {
|
|
5553
|
-
if (isMonitorBootstrapTemplate(args[0])) {
|
|
5554
|
-
return runMonitorBootstrap(args);
|
|
5555
|
-
}
|
|
5556
|
-
const options = parsePlayBootstrapOptions(args);
|
|
5557
|
-
const client = new DeeplineClient();
|
|
5558
|
-
const contracts = await loadBootstrapContracts(client, options);
|
|
5559
|
-
const csvContext = loadCsvContext(options.from);
|
|
5560
|
-
const source = generateBootstrapPlaySource({
|
|
5561
|
-
options,
|
|
5562
|
-
...contracts,
|
|
5563
|
-
...csvContext
|
|
5564
|
-
});
|
|
5565
|
-
return writeBootstrapSource(source, options.out);
|
|
5566
|
-
}
|
|
5567
|
-
async function handlePlayBootstrap(args) {
|
|
5568
|
-
return runPlayBootstrap(args).catch(renderPlayBootstrapError);
|
|
5569
|
-
}
|
|
5570
|
-
function registerPlayBootstrapCommand(play) {
|
|
5571
|
-
play.command("bootstrap <template>").description(
|
|
5572
|
-
"Print a scratchpad play for a GTM route or monitor-triggered template."
|
|
5573
|
-
).addHelpText(
|
|
5574
|
-
"after",
|
|
5575
|
-
`
|
|
5576
|
-
Notes:
|
|
5577
|
-
Cloud-validated play generator for agents. Pick the JTBD as the positional
|
|
5578
|
-
template, bind resources with typed refs, write the .play.ts file with --out,
|
|
5579
|
-
then edit the generated TODO mapping comments. Multiple finder providers are
|
|
5580
|
-
generated as a waterfall in the order you pass them.
|
|
5581
|
-
|
|
5582
|
-
This command requires auth because provider/play contracts are fetched from
|
|
5583
|
-
Deepline. It prints TypeScript source only and does not run paid tools; the
|
|
5584
|
-
generated play may spend credits later when you run it.
|
|
5585
|
-
|
|
5586
|
-
By default stdout is the generated .play.ts source. Use --out to write a file
|
|
5587
|
-
directly. Errors and diagnostics go to stderr. There is no JSON mode.
|
|
5588
|
-
|
|
5589
|
-
Templates:
|
|
5590
|
-
people-list start from people/contact rows
|
|
5591
|
-
company-list start from company/account rows
|
|
5592
|
-
people-email people/contact rows -> email finder
|
|
5593
|
-
people-phone people/contact rows -> phone finder
|
|
5594
|
-
company-people company/account rows -> people play
|
|
5595
|
-
company-people-email company/account rows -> people play -> email finder
|
|
5596
|
-
company-people-phone company/account rows -> people play -> phone finder
|
|
5597
|
-
monitor-triggered run a play whenever a monitor writes a new row
|
|
5598
|
-
(definePlay with sqlListeners; no --from/stage flags)
|
|
5599
|
-
|
|
5600
|
-
Monitor-triggered options (only for the monitor-triggered template):
|
|
5601
|
-
--tool <monitor-tool-id> monitor tool to bind (default deepline_native.company_radar)
|
|
5602
|
-
--stream <stream-key> output stream to listen on (default company_job_openings)
|
|
5603
|
-
Discover a tool's streams/columns with: deepline monitors available <id>
|
|
5604
|
-
|
|
5605
|
-
Resource refs:
|
|
5606
|
-
csv:./contacts.csv
|
|
5607
|
-
play:prebuilt/name-and-domain-to-email-waterfall
|
|
5608
|
-
provider:dropleads_search_people
|
|
5609
|
-
providers:hunter_email_finder,leadmagic_email_finder
|
|
5610
|
-
|
|
5611
|
-
Validation:
|
|
5612
|
-
source providers must match the route entity: company_search or people_search
|
|
5613
|
-
source providers must expose list getters
|
|
5614
|
-
company -> people uses a play only; provider bridge is generated later when a play exists
|
|
5615
|
-
email/phone finder providers must match their category and expose value getters
|
|
5616
|
-
finder plays/providers must match the route; generated code leaves input mapping explicit
|
|
5617
|
-
business-specific provider inputs and company -> people persona fields are TODOs in code
|
|
5618
|
-
csv: paths are resolved from the directory where you run bootstrap; write the play file there too
|
|
5619
|
-
|
|
5620
|
-
Exit codes:
|
|
5621
|
-
0 success
|
|
5622
|
-
2 usage/local input error
|
|
5623
|
-
7 route validation failed
|
|
5624
|
-
|
|
5625
|
-
Examples:
|
|
5626
|
-
deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall --limit 5 --out email-flow.play.ts
|
|
5627
|
-
deepline plays check email-flow.play.ts
|
|
5628
|
-
deepline plays run email-flow.play.ts --input '{"limit":5}'
|
|
5629
|
-
|
|
5630
|
-
deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5 --out prospecting.play.ts
|
|
5631
|
-
deepline plays bootstrap company-people-email --from provider:crustdata_companydb_search --people play:prebuilt/company-to-contact --email play:prebuilt/name-and-domain-to-email-waterfall --limit 5 --out account-contacts.play.ts
|
|
5632
|
-
deepline plays bootstrap company-list --from provider:crustdata_companydb_search --limit 5 --out companies.play.ts
|
|
5633
|
-
|
|
5634
|
-
deepline plays bootstrap monitor-triggered --out on-new-row.play.ts
|
|
5635
|
-
deepline plays bootstrap monitor-triggered --tool deepline_native.company_radar --stream company_job_openings --out on-new-job.play.ts
|
|
5636
|
-
`
|
|
5637
|
-
).option("--name <name>", "Generated play name").option(
|
|
5638
|
-
"--from <ref>",
|
|
5639
|
-
"Route source: csv:PATH, play:REF, provider:ID, or providers:ID,ID"
|
|
5640
|
-
).option(
|
|
5641
|
-
"--using <ref>",
|
|
5642
|
-
"Single-stage route shorthand for people-email, people-phone, or company-people"
|
|
5643
|
-
).option(
|
|
5644
|
-
"--people <ref>",
|
|
5645
|
-
"Company-to-people stage for company-people-email/phone; use play:REF"
|
|
5646
|
-
).option(
|
|
5647
|
-
"--email <ref>",
|
|
5648
|
-
"Email finder stage: play:REF, provider:ID, or providers:ID,ID"
|
|
5649
|
-
).option(
|
|
5650
|
-
"--phone <ref>",
|
|
5651
|
-
"Phone finder stage: play:REF, provider:ID, or providers:ID,ID"
|
|
5652
|
-
).option("--limit <n>", "Maximum rows to fan out in the generated play").option(
|
|
5653
|
-
"--tool <id>",
|
|
5654
|
-
"monitor-triggered only: monitor tool id to bind (e.g. deepline_native.company_radar)"
|
|
5655
|
-
).option(
|
|
5656
|
-
"--stream <key>",
|
|
5657
|
-
"monitor-triggered only: monitor output stream to listen on (e.g. company_job_openings)"
|
|
5658
|
-
).option("--out <path>", "Write generated play source to a file").action(async (template, options) => {
|
|
5659
|
-
process.exitCode = await handlePlayBootstrap([
|
|
5660
|
-
template,
|
|
5661
|
-
...options.name ? ["--name", options.name] : [],
|
|
5662
|
-
...options.from ? ["--from", options.from] : [],
|
|
5663
|
-
...options.using ? ["--using", options.using] : [],
|
|
5664
|
-
...options.people ? ["--people", options.people] : [],
|
|
5665
|
-
...options.email ? ["--email", options.email] : [],
|
|
5666
|
-
...options.phone ? ["--phone", options.phone] : [],
|
|
5667
|
-
...options.limit ? ["--limit", options.limit] : [],
|
|
5668
|
-
...options.tool ? ["--tool", options.tool] : [],
|
|
5669
|
-
...options.stream ? ["--stream", options.stream] : [],
|
|
5670
|
-
...options.out ? ["--out", options.out] : []
|
|
5671
|
-
]);
|
|
5672
|
-
});
|
|
5673
|
-
}
|
|
5674
|
-
|
|
5675
3989
|
// src/cli/commands/run-receipt.ts
|
|
5676
3990
|
import { readFile, writeFile } from "fs/promises";
|
|
5677
3991
|
function registerRunReceiptCommand(runs) {
|
|
@@ -6028,8 +4342,8 @@ function formatRunHitCountLines(tables) {
|
|
|
6028
4342
|
}
|
|
6029
4343
|
|
|
6030
4344
|
// src/cli/run-dataset-csv.ts
|
|
6031
|
-
import { writeFileSync
|
|
6032
|
-
import { resolve
|
|
4345
|
+
import { writeFileSync } from "fs";
|
|
4346
|
+
import { resolve } from "path";
|
|
6033
4347
|
|
|
6034
4348
|
// ../plays/table-csv.ts
|
|
6035
4349
|
var TABLE_EXPORT_ERROR_COLUMN = "_error";
|
|
@@ -6135,9 +4449,9 @@ var RunDatasetCsv = class _RunDatasetCsv {
|
|
|
6135
4449
|
return this.#projection;
|
|
6136
4450
|
}
|
|
6137
4451
|
write(outPath) {
|
|
6138
|
-
const absolutePath =
|
|
4452
|
+
const absolutePath = resolve(outPath);
|
|
6139
4453
|
const { rows, columns } = this.#projection;
|
|
6140
|
-
|
|
4454
|
+
writeFileSync(
|
|
6141
4455
|
absolutePath,
|
|
6142
4456
|
tableCsvText(
|
|
6143
4457
|
columns,
|
|
@@ -6376,24 +4690,24 @@ function sanitizeCsvProjectionInfo(input) {
|
|
|
6376
4690
|
const rows = input.rows.map(stripCsvProjectionFields);
|
|
6377
4691
|
return { rows, columns };
|
|
6378
4692
|
}
|
|
6379
|
-
function
|
|
4693
|
+
function isRecord(value) {
|
|
6380
4694
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
6381
4695
|
}
|
|
6382
4696
|
function isSerializedDataset(value) {
|
|
6383
|
-
return
|
|
4697
|
+
return isRecord(value) && value.kind === "dataset" && typeof value.count === "number" && (Array.isArray(value.preview) || typeof value.tableNamespace === "string");
|
|
6384
4698
|
}
|
|
6385
4699
|
function isPackagedDatasetOutput(value) {
|
|
6386
|
-
return
|
|
4700
|
+
return isRecord(value) && value.kind === "dataset" && isRecord(value.preview) && Array.isArray(value.preview.rows);
|
|
6387
4701
|
}
|
|
6388
4702
|
function hasCurrentTableExport(value) {
|
|
6389
|
-
if (!
|
|
4703
|
+
if (!isRecord(value) || !isRecord(value.actions)) return false;
|
|
6390
4704
|
const exportCsv = value.actions.exportCsv;
|
|
6391
|
-
return
|
|
4705
|
+
return isRecord(exportCsv) && isRecord(exportCsv.scope) && exportCsv.scope.kind === "database" && exportCsv.scope.mutability === "current";
|
|
6392
4706
|
}
|
|
6393
4707
|
function currentTableQueryCommand(value) {
|
|
6394
|
-
if (!
|
|
4708
|
+
if (!isRecord(value) || !isRecord(value.actions)) return void 0;
|
|
6395
4709
|
const query = value.actions.queryCurrentTable;
|
|
6396
|
-
const command =
|
|
4710
|
+
const command = isRecord(query) ? query.command : void 0;
|
|
6397
4711
|
return typeof command === "string" && command.trim() ? command.trim() : void 0;
|
|
6398
4712
|
}
|
|
6399
4713
|
function recoveredReturnPaths(value) {
|
|
@@ -6425,7 +4739,7 @@ function pathParts(path) {
|
|
|
6425
4739
|
function valueAtPath(root, path) {
|
|
6426
4740
|
let cursor = root;
|
|
6427
4741
|
for (const part of pathParts(path)) {
|
|
6428
|
-
if (!
|
|
4742
|
+
if (!isRecord(cursor)) {
|
|
6429
4743
|
return void 0;
|
|
6430
4744
|
}
|
|
6431
4745
|
cursor = cursor[part];
|
|
@@ -6433,17 +4747,17 @@ function valueAtPath(root, path) {
|
|
|
6433
4747
|
return cursor;
|
|
6434
4748
|
}
|
|
6435
4749
|
function totalRowsForDataset(result, datasetPath) {
|
|
6436
|
-
const metadata =
|
|
4750
|
+
const metadata = isRecord(result._metadata) ? result._metadata : null;
|
|
6437
4751
|
const parentPath = datasetPath.split(".").slice(0, -1).join(".");
|
|
6438
4752
|
const parent = parentPath ? valueAtPath({ result }, parentPath) : result;
|
|
6439
|
-
return metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count ?? (
|
|
4753
|
+
return metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count ?? (isRecord(parent) ? parent.totalRows ?? parent.rowCount ?? parent.count : void 0) ?? result.totalRows ?? result.rowCount ?? result.count;
|
|
6440
4754
|
}
|
|
6441
4755
|
function rowArray(value) {
|
|
6442
4756
|
if (!Array.isArray(value)) {
|
|
6443
4757
|
return null;
|
|
6444
4758
|
}
|
|
6445
4759
|
const rows = value.filter(
|
|
6446
|
-
(row) =>
|
|
4760
|
+
(row) => isRecord(row)
|
|
6447
4761
|
);
|
|
6448
4762
|
return rows.length === value.length ? rows : null;
|
|
6449
4763
|
}
|
|
@@ -6467,7 +4781,7 @@ function inferColumns(rows) {
|
|
|
6467
4781
|
return columns;
|
|
6468
4782
|
}
|
|
6469
4783
|
function columnsFromDatasetSummary(summary) {
|
|
6470
|
-
if (!
|
|
4784
|
+
if (!isRecord(summary) || !isRecord(summary.columnStats)) {
|
|
6471
4785
|
return [];
|
|
6472
4786
|
}
|
|
6473
4787
|
return Object.keys(summary.columnStats).filter((column) => column);
|
|
@@ -6529,7 +4843,7 @@ function canonicalRowsInfoFromCandidate(input) {
|
|
|
6529
4843
|
candidate.value.recoveredReturnPaths
|
|
6530
4844
|
)
|
|
6531
4845
|
} : {},
|
|
6532
|
-
...
|
|
4846
|
+
...isRecord(candidate.value.exportUnavailable) && (candidate.value.exportUnavailable.reason === "empty_dataset" || candidate.value.exportUnavailable.reason === "shared_table_namespace" || candidate.value.exportUnavailable.reason === "ambiguous_selector" || candidate.value.exportUnavailable.reason === "returned_dataset_not_persisted") ? {
|
|
6533
4847
|
exportUnavailableReason: candidate.value.exportUnavailable.reason,
|
|
6534
4848
|
...typeof candidate.value.exportUnavailable.message === "string" ? {
|
|
6535
4849
|
exportUnavailableMessage: candidate.value.exportUnavailable.message
|
|
@@ -6577,7 +4891,7 @@ function collectDatasetCandidates(input) {
|
|
|
6577
4891
|
});
|
|
6578
4892
|
return;
|
|
6579
4893
|
}
|
|
6580
|
-
if (!
|
|
4894
|
+
if (!isRecord(input.value)) {
|
|
6581
4895
|
return;
|
|
6582
4896
|
}
|
|
6583
4897
|
for (const [key, child] of Object.entries(input.value)) {
|
|
@@ -6594,12 +4908,12 @@ function collectDatasetCandidates(input) {
|
|
|
6594
4908
|
}
|
|
6595
4909
|
}
|
|
6596
4910
|
function collectCanonicalRowsInfos(statusOrResult) {
|
|
6597
|
-
const root =
|
|
6598
|
-
const result =
|
|
4911
|
+
const root = isRecord(statusOrResult) ? statusOrResult : null;
|
|
4912
|
+
const result = isRecord(root?.result) ? root.result : root;
|
|
6599
4913
|
if (!result) {
|
|
6600
4914
|
return [];
|
|
6601
4915
|
}
|
|
6602
|
-
const metadata =
|
|
4916
|
+
const metadata = isRecord(result._metadata) ? result._metadata : null;
|
|
6603
4917
|
const totalFromMetadata = metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count;
|
|
6604
4918
|
const candidates = [
|
|
6605
4919
|
{
|
|
@@ -6623,8 +4937,8 @@ function collectCanonicalRowsInfos(statusOrResult) {
|
|
|
6623
4937
|
total: totalFromMetadata ?? result.totalRows ?? result.rowCount ?? result.count
|
|
6624
4938
|
}
|
|
6625
4939
|
];
|
|
6626
|
-
if (
|
|
6627
|
-
const outputMetadata =
|
|
4940
|
+
if (isRecord(result.output)) {
|
|
4941
|
+
const outputMetadata = isRecord(result.output._metadata) ? result.output._metadata : null;
|
|
6628
4942
|
const outputTotalFromMetadata = outputMetadata?.totalRows ?? outputMetadata?.rowCount ?? outputMetadata?.count;
|
|
6629
4943
|
candidates.push(
|
|
6630
4944
|
{
|
|
@@ -6651,14 +4965,14 @@ function collectCanonicalRowsInfos(statusOrResult) {
|
|
|
6651
4965
|
}
|
|
6652
4966
|
if (Array.isArray(result.steps)) {
|
|
6653
4967
|
result.steps.forEach((step, index) => {
|
|
6654
|
-
if (!
|
|
4968
|
+
if (!isRecord(step) || !isRecord(step.output)) {
|
|
6655
4969
|
return;
|
|
6656
4970
|
}
|
|
6657
4971
|
const source = typeof step.output.path === "string" ? step.output.path : typeof step.id === "string" ? `steps.${step.id}.output` : `steps.${index}.output`;
|
|
6658
4972
|
candidates.push({
|
|
6659
4973
|
source,
|
|
6660
4974
|
value: step.output,
|
|
6661
|
-
total: step.output.rowCount ?? (
|
|
4975
|
+
total: step.output.rowCount ?? (isRecord(step.output.preview) ? step.output.preview.totalRows : void 0) ?? (isRecord(step.progress) ? step.progress.total : void 0)
|
|
6662
4976
|
});
|
|
6663
4977
|
});
|
|
6664
4978
|
}
|
|
@@ -6679,15 +4993,15 @@ function collectCanonicalRowsInfos(statusOrResult) {
|
|
|
6679
4993
|
return distinctCanonicalRowsInfos(infos);
|
|
6680
4994
|
}
|
|
6681
4995
|
function collectPackagedDatasetCandidates(statusOrResult) {
|
|
6682
|
-
const root =
|
|
4996
|
+
const root = isRecord(statusOrResult) ? statusOrResult : null;
|
|
6683
4997
|
if (!root) {
|
|
6684
4998
|
return [];
|
|
6685
4999
|
}
|
|
6686
|
-
const pkg =
|
|
5000
|
+
const pkg = isRecord(root.package) ? root.package : root;
|
|
6687
5001
|
const datasets = Array.isArray(pkg.datasets) ? pkg.datasets : [];
|
|
6688
5002
|
const candidates = [];
|
|
6689
5003
|
for (const output of datasets) {
|
|
6690
|
-
if (!
|
|
5004
|
+
if (!isRecord(output) || !isPackagedDatasetOutput(output)) {
|
|
6691
5005
|
continue;
|
|
6692
5006
|
}
|
|
6693
5007
|
const source = typeof output.path === "string" && output.path.trim() ? output.path.trim() : null;
|
|
@@ -6697,18 +5011,18 @@ function collectPackagedDatasetCandidates(statusOrResult) {
|
|
|
6697
5011
|
candidates.push({
|
|
6698
5012
|
source,
|
|
6699
5013
|
value: output,
|
|
6700
|
-
total: output.rowCount ?? (
|
|
5014
|
+
total: output.rowCount ?? (isRecord(output.preview) ? output.preview.totalRows : void 0)
|
|
6701
5015
|
});
|
|
6702
5016
|
}
|
|
6703
5017
|
return candidates;
|
|
6704
5018
|
}
|
|
6705
5019
|
function collectPackagedStepDatasetCandidates(statusOrResult) {
|
|
6706
|
-
const root =
|
|
5020
|
+
const root = isRecord(statusOrResult) ? statusOrResult : null;
|
|
6707
5021
|
if (!root) return [];
|
|
6708
|
-
const pkg =
|
|
5022
|
+
const pkg = isRecord(root.package) ? root.package : root;
|
|
6709
5023
|
const steps = Array.isArray(pkg.steps) ? pkg.steps : [];
|
|
6710
5024
|
return steps.flatMap((step) => {
|
|
6711
|
-
if (!
|
|
5025
|
+
if (!isRecord(step) || !isPackagedDatasetOutput(step.output)) return [];
|
|
6712
5026
|
const source = typeof step.output.path === "string" && step.output.path.trim() ? step.output.path.trim() : null;
|
|
6713
5027
|
return source ? [
|
|
6714
5028
|
{
|
|
@@ -6720,8 +5034,8 @@ function collectPackagedStepDatasetCandidates(statusOrResult) {
|
|
|
6720
5034
|
});
|
|
6721
5035
|
}
|
|
6722
5036
|
function collectSerializedDatasetRowsInfos(statusOrResult) {
|
|
6723
|
-
const root =
|
|
6724
|
-
const result = root && "result" in root ?
|
|
5037
|
+
const root = isRecord(statusOrResult) ? statusOrResult : null;
|
|
5038
|
+
const result = root && "result" in root ? isRecord(root.result) ? root.result : null : root?.kind === "play_run" || isRecord(root?.package) ? null : root;
|
|
6725
5039
|
const candidates = [];
|
|
6726
5040
|
if (result) {
|
|
6727
5041
|
collectDatasetCandidates({
|
|
@@ -6729,7 +5043,7 @@ function collectSerializedDatasetRowsInfos(statusOrResult) {
|
|
|
6729
5043
|
path: "result",
|
|
6730
5044
|
output: candidates
|
|
6731
5045
|
});
|
|
6732
|
-
if (
|
|
5046
|
+
if (isRecord(result.output)) {
|
|
6733
5047
|
collectDatasetCandidates({
|
|
6734
5048
|
value: result.output,
|
|
6735
5049
|
path: "result",
|
|
@@ -6776,8 +5090,8 @@ function extractCanonicalRowsInfo(statusOrResult) {
|
|
|
6776
5090
|
}
|
|
6777
5091
|
|
|
6778
5092
|
// src/cli/run-dataset-selection.ts
|
|
6779
|
-
import { writeFileSync as
|
|
6780
|
-
import { resolve as
|
|
5093
|
+
import { writeFileSync as writeFileSync2 } from "fs";
|
|
5094
|
+
import { resolve as resolve2 } from "path";
|
|
6781
5095
|
var Run = class _Run {
|
|
6782
5096
|
#datasets;
|
|
6783
5097
|
constructor(input) {
|
|
@@ -6903,8 +5217,8 @@ var RunDataset = class _RunDataset {
|
|
|
6903
5217
|
);
|
|
6904
5218
|
}
|
|
6905
5219
|
if (options.format === "json") {
|
|
6906
|
-
const absolutePath =
|
|
6907
|
-
|
|
5220
|
+
const absolutePath = resolve2(outPath);
|
|
5221
|
+
writeFileSync2(
|
|
6908
5222
|
absolutePath,
|
|
6909
5223
|
`${JSON.stringify(orderRunExportJson(this.rows), null, 2)}
|
|
6910
5224
|
`,
|
|
@@ -6958,7 +5272,7 @@ function withReturnedDatasetAliases(runPackage, available) {
|
|
|
6958
5272
|
for (const outputValue of Object.values(outputs)) {
|
|
6959
5273
|
const output = recordValue(outputValue);
|
|
6960
5274
|
if (output.kind !== "dataset") continue;
|
|
6961
|
-
const alias =
|
|
5275
|
+
const alias = stringValue(output.path);
|
|
6962
5276
|
if (!alias) continue;
|
|
6963
5277
|
const canonical = resolveReturnedDataset(output, available);
|
|
6964
5278
|
expanded.push(withDatasetAlias(canonical, alias));
|
|
@@ -6973,7 +5287,7 @@ function returnedRunDatasets(runPackage, available) {
|
|
|
6973
5287
|
for (const outputValue of Object.values(outputs)) {
|
|
6974
5288
|
const output = recordValue(outputValue);
|
|
6975
5289
|
if (output.kind !== "dataset") continue;
|
|
6976
|
-
const alias =
|
|
5290
|
+
const alias = stringValue(output.path);
|
|
6977
5291
|
const info = resolveReturnedDataset(output, available);
|
|
6978
5292
|
selected.push(alias ? withDatasetAlias(info, alias) : info);
|
|
6979
5293
|
}
|
|
@@ -7004,8 +5318,8 @@ function withDatasetAlias(info, alias) {
|
|
|
7004
5318
|
};
|
|
7005
5319
|
}
|
|
7006
5320
|
function resolveReturnedDataset(output, available) {
|
|
7007
|
-
const datasetId =
|
|
7008
|
-
const path =
|
|
5321
|
+
const datasetId = stringValue(output.datasetId);
|
|
5322
|
+
const path = stringValue(output.dataset) ?? stringValue(output.path);
|
|
7009
5323
|
if (datasetId) {
|
|
7010
5324
|
const identified = uniqueDatasetMatch(
|
|
7011
5325
|
available.filter((info) => info.datasetId === datasetId),
|
|
@@ -7032,7 +5346,7 @@ function resolveReturnedDataset(output, available) {
|
|
|
7032
5346
|
function recordValue(value) {
|
|
7033
5347
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
7034
5348
|
}
|
|
7035
|
-
function
|
|
5349
|
+
function stringValue(value) {
|
|
7036
5350
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
7037
5351
|
}
|
|
7038
5352
|
|
|
@@ -7288,7 +5602,7 @@ function isInternalGlueStepId(stepId) {
|
|
|
7288
5602
|
import { randomUUID } from "crypto";
|
|
7289
5603
|
import { mkdtemp as mkdtemp2, realpath, rm as rm2 } from "fs/promises";
|
|
7290
5604
|
import { tmpdir } from "os";
|
|
7291
|
-
import { join as join4, resolve as
|
|
5605
|
+
import { join as join4, resolve as resolve3 } from "path";
|
|
7292
5606
|
|
|
7293
5607
|
// ../plays/deploy/run-deployment.ts
|
|
7294
5608
|
import { join as join3 } from "path";
|
|
@@ -7465,7 +5779,7 @@ var DeployApiClient = class {
|
|
|
7465
5779
|
// ../plays/deploy/manifest.ts
|
|
7466
5780
|
var import_picomatch = __toESM(require_picomatch2(), 1);
|
|
7467
5781
|
import { readdir, readFile as readFile2, stat } from "fs/promises";
|
|
7468
|
-
import { join, relative
|
|
5782
|
+
import { join, relative } from "path";
|
|
7469
5783
|
var DEFAULT_PLAY_GLOBS = ["**/*.play.ts"];
|
|
7470
5784
|
var DEFAULT_MONITOR_GLOBS = ["**/*.monitor.json"];
|
|
7471
5785
|
var MAX_DISCOVERED_FILES = 200;
|
|
@@ -7566,7 +5880,7 @@ async function discoverDeploymentFiles(input) {
|
|
|
7566
5880
|
continue;
|
|
7567
5881
|
}
|
|
7568
5882
|
if (!entry.isFile()) continue;
|
|
7569
|
-
const relativePath =
|
|
5883
|
+
const relativePath = relative(input.projectRoot, absolute);
|
|
7570
5884
|
if (matchers.some((match) => match(relativePath))) {
|
|
7571
5885
|
found.push(relativePath);
|
|
7572
5886
|
if (found.length > MAX_DISCOVERED_FILES) {
|
|
@@ -7906,7 +6220,7 @@ async function runDeployment(params, hooks) {
|
|
|
7906
6220
|
throw lastError;
|
|
7907
6221
|
}
|
|
7908
6222
|
await new Promise(
|
|
7909
|
-
(
|
|
6223
|
+
(resolve6) => setTimeout(resolve6, hooks.checkRunRetryDelayMs ?? 1e3)
|
|
7910
6224
|
);
|
|
7911
6225
|
}
|
|
7912
6226
|
}
|
|
@@ -8389,7 +6703,7 @@ async function runDeployment(params, hooks) {
|
|
|
8389
6703
|
"Monitor jobs are still reconciling. Retrying this deployment will resume the same jobs."
|
|
8390
6704
|
);
|
|
8391
6705
|
}
|
|
8392
|
-
await new Promise((
|
|
6706
|
+
await new Promise((resolve6) => setTimeout(resolve6, 1e3));
|
|
8393
6707
|
for (let index = 0; index < monitorOutcomes.length; index += 1) {
|
|
8394
6708
|
const outcome = monitorOutcomes[index];
|
|
8395
6709
|
if (outcome.status !== "applying") continue;
|
|
@@ -8602,8 +6916,8 @@ function printResult2(input) {
|
|
|
8602
6916
|
);
|
|
8603
6917
|
}
|
|
8604
6918
|
async function handlePlaysDeploy(directory, options) {
|
|
8605
|
-
const root = await realpath(
|
|
8606
|
-
throw new Error(`No such directory: ${
|
|
6919
|
+
const root = await realpath(resolve3(directory ?? ".")).catch(() => {
|
|
6920
|
+
throw new Error(`No such directory: ${resolve3(directory ?? ".")}`);
|
|
8607
6921
|
});
|
|
8608
6922
|
const { http, config } = getAuthedHttpClient();
|
|
8609
6923
|
const deliveryId = `local:${randomUUID()}`;
|
|
@@ -8674,7 +6988,7 @@ async function handlePlaysDeploy(directory, options) {
|
|
|
8674
6988
|
|
|
8675
6989
|
// src/cli/operations/play-run-options.ts
|
|
8676
6990
|
import { existsSync, readFileSync } from "fs";
|
|
8677
|
-
import { resolve as
|
|
6991
|
+
import { resolve as resolve4 } from "path";
|
|
8678
6992
|
|
|
8679
6993
|
// ../play-runtime/fixture-behavior.ts
|
|
8680
6994
|
var FIXTURE_BEHAVIOR_VERSION = 1;
|
|
@@ -9119,7 +7433,7 @@ function parsePlayRunHeaderFlag(raw) {
|
|
|
9119
7433
|
function isBarePlayRunDebugFlag(args, index) {
|
|
9120
7434
|
return args[index] === "--debug" && (args[index + 1] === void 0 || args[index + 1].startsWith("--"));
|
|
9121
7435
|
}
|
|
9122
|
-
function
|
|
7436
|
+
function parseReferencedPlayTarget(target) {
|
|
9123
7437
|
const trimmed = target.trim();
|
|
9124
7438
|
const slashIndex = trimmed.indexOf("/");
|
|
9125
7439
|
if (slashIndex <= 0 || slashIndex === trimmed.length - 1) {
|
|
@@ -9132,7 +7446,7 @@ function parseReferencedPlayTarget2(target) {
|
|
|
9132
7446
|
};
|
|
9133
7447
|
}
|
|
9134
7448
|
function isFileTarget(target) {
|
|
9135
|
-
return existsSync(
|
|
7449
|
+
return existsSync(resolve4(target));
|
|
9136
7450
|
}
|
|
9137
7451
|
function looksLikeFilePath(target) {
|
|
9138
7452
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -9143,7 +7457,7 @@ function looksLikeFilePath(target) {
|
|
|
9143
7457
|
}
|
|
9144
7458
|
return target.includes("\\") || /\.(ts|js|mjs|play\.ts)$/.test(target);
|
|
9145
7459
|
}
|
|
9146
|
-
function
|
|
7460
|
+
function parsePositiveInteger(value, flagName) {
|
|
9147
7461
|
const parsed = Number.parseInt(value, 10);
|
|
9148
7462
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
9149
7463
|
throw new Error(`${flagName} must be a positive integer.`);
|
|
@@ -9151,7 +7465,7 @@ function parsePositiveInteger2(value, flagName) {
|
|
|
9151
7465
|
return parsed;
|
|
9152
7466
|
}
|
|
9153
7467
|
function parseJsonInput(raw, flag = "--input") {
|
|
9154
|
-
const source = raw.startsWith("@") ? readFileSync(
|
|
7468
|
+
const source = raw.startsWith("@") ? readFileSync(resolve4(raw.slice(1)), "utf-8") : raw;
|
|
9155
7469
|
let parsed;
|
|
9156
7470
|
try {
|
|
9157
7471
|
parsed = JSON.parse(source);
|
|
@@ -9243,7 +7557,7 @@ function parsePlayRunOptions(args, initialInput = null) {
|
|
|
9243
7557
|
continue;
|
|
9244
7558
|
}
|
|
9245
7559
|
if (arg === "--name" && args[index + 1]) {
|
|
9246
|
-
playName =
|
|
7560
|
+
playName = parseReferencedPlayTarget(args[++index]).playName;
|
|
9247
7561
|
continue;
|
|
9248
7562
|
}
|
|
9249
7563
|
if ((arg === "--input" || arg === "-i") && args[index + 1]) {
|
|
@@ -9310,7 +7624,7 @@ function parsePlayRunOptions(args, initialInput = null) {
|
|
|
9310
7624
|
"--max-concurrent-external-calls requires a positive whole number."
|
|
9311
7625
|
);
|
|
9312
7626
|
}
|
|
9313
|
-
maxConcurrentExternalCalls =
|
|
7627
|
+
maxConcurrentExternalCalls = parsePositiveInteger(
|
|
9314
7628
|
value,
|
|
9315
7629
|
"--max-concurrent-external-calls"
|
|
9316
7630
|
);
|
|
@@ -9328,7 +7642,7 @@ function parsePlayRunOptions(args, initialInput = null) {
|
|
|
9328
7642
|
"--max-concurrent-rows requires a positive whole number."
|
|
9329
7643
|
);
|
|
9330
7644
|
}
|
|
9331
|
-
maxConcurrentRows =
|
|
7645
|
+
maxConcurrentRows = parsePositiveInteger(value, "--max-concurrent-rows");
|
|
9332
7646
|
resolveMaxConcurrentRows(maxConcurrentRows);
|
|
9333
7647
|
index += 1;
|
|
9334
7648
|
continue;
|
|
@@ -9376,7 +7690,7 @@ function parsePlayRunOptions(args, initialInput = null) {
|
|
|
9376
7690
|
);
|
|
9377
7691
|
}
|
|
9378
7692
|
if ((arg === "--tail-timeout-ms" || arg === "--timeout-ms") && args[index + 1]) {
|
|
9379
|
-
waitTimeoutMs =
|
|
7693
|
+
waitTimeoutMs = parsePositiveInteger(args[++index], arg);
|
|
9380
7694
|
continue;
|
|
9381
7695
|
}
|
|
9382
7696
|
if (arg === "--debug" && args[index + 1] && !args[index + 1].startsWith("--")) {
|
|
@@ -9424,7 +7738,7 @@ function parsePlayRunOptions(args, initialInput = null) {
|
|
|
9424
7738
|
if (isFileTarget(arg) || looksLikeFilePath(arg)) {
|
|
9425
7739
|
filePath = arg;
|
|
9426
7740
|
} else {
|
|
9427
|
-
playName =
|
|
7741
|
+
playName = parseReferencedPlayTarget(arg).playName;
|
|
9428
7742
|
}
|
|
9429
7743
|
continue;
|
|
9430
7744
|
}
|
|
@@ -9512,7 +7826,7 @@ function resolvePlayRunCliOptions(target, options, inputArgs = []) {
|
|
|
9512
7826
|
);
|
|
9513
7827
|
const resolvedTarget = file !== void 0 ? { kind: "file", path: file } : name !== void 0 ? {
|
|
9514
7828
|
kind: "name",
|
|
9515
|
-
name:
|
|
7829
|
+
name: parseReferencedPlayTarget(name).playName
|
|
9516
7830
|
} : base.target;
|
|
9517
7831
|
const revisionId = stringOption(options.revisionId, "--revision-id") ?? base.revisionId;
|
|
9518
7832
|
const selectors = [
|
|
@@ -9616,12 +7930,12 @@ function resolvePlayRunCliOptions(target, options, inputArgs = []) {
|
|
|
9616
7930
|
}
|
|
9617
7931
|
|
|
9618
7932
|
// src/plays/authoring-graph-path.ts
|
|
9619
|
-
import { dirname, isAbsolute
|
|
7933
|
+
import { dirname, isAbsolute, join as join5, relative as relative2 } from "path";
|
|
9620
7934
|
function playAuthoringGraphPath(parent, filePath) {
|
|
9621
|
-
if (
|
|
7935
|
+
if (isAbsolute(parent.artifact.entryFile)) return filePath;
|
|
9622
7936
|
return join5(
|
|
9623
7937
|
dirname(parent.artifact.entryFile),
|
|
9624
|
-
|
|
7938
|
+
relative2(dirname(parent.filePath), filePath)
|
|
9625
7939
|
).replaceAll("\\", "/");
|
|
9626
7940
|
}
|
|
9627
7941
|
|
|
@@ -9696,7 +8010,7 @@ async function removeRunIdTempFile(path) {
|
|
|
9696
8010
|
}
|
|
9697
8011
|
}
|
|
9698
8012
|
async function preflightRunIdFile(path) {
|
|
9699
|
-
const destination =
|
|
8013
|
+
const destination = resolve5(path);
|
|
9700
8014
|
if (await pathExistsIncludingSymlink(destination)) {
|
|
9701
8015
|
throw new Error(
|
|
9702
8016
|
`--run-id-file destination already exists: ${destination}. Choose a new path so this run cannot overwrite another run identity.`
|
|
@@ -9811,9 +8125,9 @@ function traceCliSync(phase, fields2, run) {
|
|
|
9811
8125
|
}
|
|
9812
8126
|
}
|
|
9813
8127
|
function sleep(ms) {
|
|
9814
|
-
return new Promise((
|
|
8128
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
9815
8129
|
}
|
|
9816
|
-
function
|
|
8130
|
+
function parseReferencedPlayTarget2(target) {
|
|
9817
8131
|
const trimmed = target.trim();
|
|
9818
8132
|
const slashIndex = trimmed.indexOf("/");
|
|
9819
8133
|
if (slashIndex <= 0 || slashIndex === trimmed.length - 1) {
|
|
@@ -9860,7 +8174,7 @@ function playSuggestionReference(play) {
|
|
|
9860
8174
|
return ownerSlug ? `${ownerSlug}/${play.name}` : play.name;
|
|
9861
8175
|
}
|
|
9862
8176
|
function scorePlayReferenceSuggestion(requested, play) {
|
|
9863
|
-
const parsed =
|
|
8177
|
+
const parsed = parseReferencedPlayTarget2(requested);
|
|
9864
8178
|
const requestedTrimmed = requested.trim();
|
|
9865
8179
|
const requestedRef = requestedTrimmed.toLowerCase();
|
|
9866
8180
|
const requestedName = parsed.unqualifiedPlayName;
|
|
@@ -9938,7 +8252,7 @@ function rankPlayReferenceSuggestions(input) {
|
|
|
9938
8252
|
}).slice(0, input.limit ?? 5);
|
|
9939
8253
|
}
|
|
9940
8254
|
function searchQueryForMissingPlayReference(target) {
|
|
9941
|
-
return
|
|
8255
|
+
return parseReferencedPlayTarget2(target).unqualifiedPlayName.replace(/[-_./]+/g, " ").replace(/\s+/g, " ").trim();
|
|
9942
8256
|
}
|
|
9943
8257
|
function buildPlayReferenceNotFoundMessage(input) {
|
|
9944
8258
|
const lines = [`Play not found: ${input.requested}`];
|
|
@@ -10015,7 +8329,7 @@ async function isMissingRunPlayReferenceError(input) {
|
|
|
10015
8329
|
}
|
|
10016
8330
|
try {
|
|
10017
8331
|
await input.client.getPlay(
|
|
10018
|
-
|
|
8332
|
+
parseReferencedPlayTarget2(input.playName).playName
|
|
10019
8333
|
);
|
|
10020
8334
|
return false;
|
|
10021
8335
|
} catch (lookupError) {
|
|
@@ -10023,7 +8337,7 @@ async function isMissingRunPlayReferenceError(input) {
|
|
|
10023
8337
|
}
|
|
10024
8338
|
}
|
|
10025
8339
|
async function assertCanonicalNamedPlayReference(client, target, options = {}) {
|
|
10026
|
-
const parsed =
|
|
8340
|
+
const parsed = parseReferencedPlayTarget2(target);
|
|
10027
8341
|
let detail;
|
|
10028
8342
|
try {
|
|
10029
8343
|
detail = await client.getPlay(
|
|
@@ -10060,10 +8374,10 @@ function formatPlayListReference(play) {
|
|
|
10060
8374
|
return play.reference || play.name;
|
|
10061
8375
|
}
|
|
10062
8376
|
function defaultMaterializedPlayPath(reference) {
|
|
10063
|
-
return
|
|
8377
|
+
return resolve5(defaultStarterPlayPath(reference));
|
|
10064
8378
|
}
|
|
10065
8379
|
function defaultStarterPlayPath(reference) {
|
|
10066
|
-
const playName =
|
|
8380
|
+
const playName = parseReferencedPlayTarget2(reference).unqualifiedPlayName;
|
|
10067
8381
|
const safeName = playName.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
10068
8382
|
return `./${safeName || "play"}.play.ts`;
|
|
10069
8383
|
}
|
|
@@ -10093,23 +8407,23 @@ function materializeRemotePlaySource(input) {
|
|
|
10093
8407
|
`Play ${input.playName} has ${files.length} source files. Use --out <directory> to write the complete bundle.`
|
|
10094
8408
|
);
|
|
10095
8409
|
}
|
|
10096
|
-
const outputDirectory =
|
|
8410
|
+
const outputDirectory = resolve5(input.outPath);
|
|
10097
8411
|
let created = 0;
|
|
10098
8412
|
let updated = 0;
|
|
10099
8413
|
for (const [logicalPath, sourceCode] of files) {
|
|
10100
|
-
const outputPath2 =
|
|
10101
|
-
const outputRelativePath =
|
|
10102
|
-
if (!outputRelativePath || outputRelativePath.startsWith("..") ||
|
|
8414
|
+
const outputPath2 = resolve5(outputDirectory, logicalPath);
|
|
8415
|
+
const outputRelativePath = relative3(outputDirectory, outputPath2);
|
|
8416
|
+
if (!outputRelativePath || outputRelativePath.startsWith("..") || isAbsolute2(outputRelativePath)) {
|
|
10103
8417
|
throw new Error(
|
|
10104
8418
|
`Refusing to materialize unsafe Play source path ${JSON.stringify(logicalPath)}.`
|
|
10105
8419
|
);
|
|
10106
8420
|
}
|
|
10107
8421
|
mkdirSync(dirname2(outputPath2), { recursive: true });
|
|
10108
8422
|
if (!existsSync2(outputPath2)) {
|
|
10109
|
-
|
|
8423
|
+
writeFileSync3(outputPath2, sourceCode, "utf-8");
|
|
10110
8424
|
created += 1;
|
|
10111
8425
|
} else if (readFileSync2(outputPath2, "utf-8") !== sourceCode) {
|
|
10112
|
-
|
|
8426
|
+
writeFileSync3(outputPath2, sourceCode, "utf-8");
|
|
10113
8427
|
updated += 1;
|
|
10114
8428
|
}
|
|
10115
8429
|
}
|
|
@@ -10126,10 +8440,10 @@ function materializeRemotePlaySource(input) {
|
|
|
10126
8440
|
if (existingSource === entrySource) {
|
|
10127
8441
|
return { path: outputPath, status: "unchanged", created: false };
|
|
10128
8442
|
}
|
|
10129
|
-
|
|
8443
|
+
writeFileSync3(outputPath, entrySource, "utf-8");
|
|
10130
8444
|
return { path: outputPath, status: "updated", created: false };
|
|
10131
8445
|
}
|
|
10132
|
-
|
|
8446
|
+
writeFileSync3(outputPath, entrySource, "utf-8");
|
|
10133
8447
|
return { path: outputPath, status: "created", created: true };
|
|
10134
8448
|
}
|
|
10135
8449
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -10154,7 +8468,7 @@ To make your own version:
|
|
|
10154
8468
|
);
|
|
10155
8469
|
}
|
|
10156
8470
|
async function ensureEditableRemotePlay(client, target) {
|
|
10157
|
-
const parsed =
|
|
8471
|
+
const parsed = parseReferencedPlayTarget2(target);
|
|
10158
8472
|
const detail = await client.getPlay(parsed.playName);
|
|
10159
8473
|
if (detail.play.ownerType === "deepline") {
|
|
10160
8474
|
throw buildReadonlyPrebuiltPlayError(formatPlayReference(detail.play));
|
|
@@ -10174,7 +8488,7 @@ function extractPlayName(code, filePath) {
|
|
|
10174
8488
|
throw buildMissingDefinePlayError(filePath);
|
|
10175
8489
|
}
|
|
10176
8490
|
function isFileTarget2(target) {
|
|
10177
|
-
return existsSync2(
|
|
8491
|
+
return existsSync2(resolve5(target));
|
|
10178
8492
|
}
|
|
10179
8493
|
function looksLikeRunId(target) {
|
|
10180
8494
|
return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
|
|
@@ -10195,7 +8509,7 @@ function looksLikeFilePath2(target) {
|
|
|
10195
8509
|
}
|
|
10196
8510
|
return target.includes("\\") || /\.(ts|js|mjs|play\.ts)$/.test(target);
|
|
10197
8511
|
}
|
|
10198
|
-
function
|
|
8512
|
+
function parsePositiveInteger2(value, flagName) {
|
|
10199
8513
|
const parsed = Number.parseInt(value, 10);
|
|
10200
8514
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
10201
8515
|
throw new Error(`${flagName} must be a positive integer.`);
|
|
@@ -10205,7 +8519,7 @@ function parsePositiveInteger3(value, flagName) {
|
|
|
10205
8519
|
function isLocalFilePathValue(value) {
|
|
10206
8520
|
if (typeof value !== "string" || !value.trim()) return false;
|
|
10207
8521
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
10208
|
-
return existsSync2(
|
|
8522
|
+
return existsSync2(resolve5(value));
|
|
10209
8523
|
}
|
|
10210
8524
|
function inputContainsLocalFilePath(value) {
|
|
10211
8525
|
if (isLocalFilePathValue(value)) {
|
|
@@ -10251,7 +8565,7 @@ function collectLocalFileInputRefs(value, inputPath, key, out) {
|
|
|
10251
8565
|
const looksLikeFile = /\.[a-z0-9]{1,8}$/i.test(trimmed);
|
|
10252
8566
|
if (keyIsCsvData) {
|
|
10253
8567
|
out.push({ inputPath, value: trimmed, isCsvData: true });
|
|
10254
|
-
} else if (endsWithCsv || looksLikeFile && existsSync2(
|
|
8568
|
+
} else if (endsWithCsv || looksLikeFile && existsSync2(resolve5(trimmed))) {
|
|
10255
8569
|
out.push({ inputPath, value: trimmed, isCsvData: false });
|
|
10256
8570
|
}
|
|
10257
8571
|
return;
|
|
@@ -10293,7 +8607,7 @@ function preflightLocalFileInputs(runtimeInput) {
|
|
|
10293
8607
|
collectLocalFileInputRefs(value, key, key, refs);
|
|
10294
8608
|
}
|
|
10295
8609
|
for (const ref of refs) {
|
|
10296
|
-
const absolutePath =
|
|
8610
|
+
const absolutePath = resolve5(ref.value);
|
|
10297
8611
|
if (!existsSync2(absolutePath)) {
|
|
10298
8612
|
throw new DeeplineError(
|
|
10299
8613
|
`Input ${ref.inputPath} references a local file that does not exist: ${ref.value} (resolved to ${absolutePath}). No run was created.`,
|
|
@@ -10304,7 +8618,7 @@ function preflightLocalFileInputs(runtimeInput) {
|
|
|
10304
8618
|
}
|
|
10305
8619
|
let stat2;
|
|
10306
8620
|
try {
|
|
10307
|
-
stat2 =
|
|
8621
|
+
stat2 = statSync(absolutePath);
|
|
10308
8622
|
} catch (error) {
|
|
10309
8623
|
throw new DeeplineError(
|
|
10310
8624
|
`Input ${ref.inputPath} references a local file that is not readable: ${ref.value} (${error instanceof Error ? error.message : String(error)}). No run was created.`,
|
|
@@ -10358,7 +8672,7 @@ async function stageFileInputArgs(input) {
|
|
|
10358
8672
|
codec: NODE_STAGED_FILE_CODEC,
|
|
10359
8673
|
resolveLocalFile: (value) => {
|
|
10360
8674
|
if (!isLocalFilePathValue(value)) return null;
|
|
10361
|
-
const absolutePath =
|
|
8675
|
+
const absolutePath = resolve5(value);
|
|
10362
8676
|
return {
|
|
10363
8677
|
logicalPath: basename(absolutePath),
|
|
10364
8678
|
read: async () => readFileSync2(absolutePath)
|
|
@@ -10381,9 +8695,9 @@ function stageFile(logicalPath, absolutePath) {
|
|
|
10381
8695
|
}
|
|
10382
8696
|
function normalizePlayPath(filePath) {
|
|
10383
8697
|
try {
|
|
10384
|
-
return realpathSync.native(
|
|
8698
|
+
return realpathSync.native(resolve5(filePath));
|
|
10385
8699
|
} catch {
|
|
10386
|
-
return
|
|
8700
|
+
return resolve5(filePath);
|
|
10387
8701
|
}
|
|
10388
8702
|
}
|
|
10389
8703
|
var PlayBundleGraphError = class extends Error {
|
|
@@ -13473,7 +11787,7 @@ async function resolvePlayRunOutputStatus(input) {
|
|
|
13473
11787
|
}
|
|
13474
11788
|
var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
13475
11789
|
function runExportRetryCommand(runId, outPath, datasetPath, options = {}) {
|
|
13476
|
-
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellQuote(datasetPath)}` : ""} --out ${shellQuote(
|
|
11790
|
+
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellQuote(datasetPath)}` : ""} --out ${shellQuote(resolve5(outPath))}${options.format === "json" ? " --format json" : ""}`;
|
|
13477
11791
|
}
|
|
13478
11792
|
function extractRunPlayName(status) {
|
|
13479
11793
|
const run = status.run;
|
|
@@ -13999,7 +12313,7 @@ function extractPlayValidationErrors(value) {
|
|
|
13999
12313
|
if (value instanceof DeeplineError) {
|
|
14000
12314
|
return extractPlayValidationErrors(value.details);
|
|
14001
12315
|
}
|
|
14002
|
-
if (!
|
|
12316
|
+
if (!isRecord2(value)) {
|
|
14003
12317
|
return [];
|
|
14004
12318
|
}
|
|
14005
12319
|
const directErrors = stringArrayField(value, "errors");
|
|
@@ -14390,34 +12704,34 @@ function formatPlayRuntimeLimit(runtimeLimit) {
|
|
|
14390
12704
|
if (seconds % 60 === 0) return `${seconds / 60} min`;
|
|
14391
12705
|
return `${seconds} sec`;
|
|
14392
12706
|
}
|
|
14393
|
-
function
|
|
12707
|
+
function isRecord2(value) {
|
|
14394
12708
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
14395
12709
|
}
|
|
14396
|
-
function
|
|
12710
|
+
function stringValue2(value) {
|
|
14397
12711
|
return typeof value === "string" ? value.trim() : "";
|
|
14398
12712
|
}
|
|
14399
12713
|
function asArray(value) {
|
|
14400
12714
|
return Array.isArray(value) ? value : [];
|
|
14401
12715
|
}
|
|
14402
|
-
function
|
|
14403
|
-
if (Array.isArray(value)) return value.filter(
|
|
14404
|
-
if (!
|
|
12716
|
+
function extractionEntries(value) {
|
|
12717
|
+
if (Array.isArray(value)) return value.filter(isRecord2);
|
|
12718
|
+
if (!isRecord2(value)) return [];
|
|
14405
12719
|
return Object.entries(value).map(
|
|
14406
|
-
([name, entry]) =>
|
|
12720
|
+
([name, entry]) => isRecord2(entry) ? { name, ...entry } : { name }
|
|
14407
12721
|
);
|
|
14408
12722
|
}
|
|
14409
12723
|
function firstRawPath(entry) {
|
|
14410
|
-
const details =
|
|
12724
|
+
const details = isRecord2(entry.details) ? entry.details : {};
|
|
14411
12725
|
const paths = [
|
|
14412
12726
|
...asArray(details.rawToolOutputPaths),
|
|
14413
12727
|
...asArray(details.raw_tool_output_paths),
|
|
14414
12728
|
...asArray(details.candidatePaths),
|
|
14415
12729
|
...asArray(details.candidate_paths)
|
|
14416
|
-
].map(
|
|
12730
|
+
].map(stringValue2).filter(Boolean);
|
|
14417
12731
|
return paths[0];
|
|
14418
12732
|
}
|
|
14419
12733
|
function checkHintExpression(value) {
|
|
14420
|
-
return
|
|
12734
|
+
return stringValue2(value).replace(/^toolExecutionResult\./, "result.");
|
|
14421
12735
|
}
|
|
14422
12736
|
function checkHintRawPath(value) {
|
|
14423
12737
|
return value?.startsWith("toolResponse.rawV2") ? value.replace(/^toolResponse\./, "result.toolResponse.") : void 0;
|
|
@@ -14425,14 +12739,14 @@ function checkHintRawPath(value) {
|
|
|
14425
12739
|
function collectStaticPipelineToolIds(staticPipeline) {
|
|
14426
12740
|
const seen = /* @__PURE__ */ new Set();
|
|
14427
12741
|
const visitPipeline = (pipeline) => {
|
|
14428
|
-
if (!
|
|
12742
|
+
if (!isRecord2(pipeline)) return;
|
|
14429
12743
|
for (const step of [
|
|
14430
12744
|
...asArray(pipeline.stages),
|
|
14431
12745
|
...asArray(pipeline.substeps)
|
|
14432
12746
|
]) {
|
|
14433
|
-
if (!
|
|
12747
|
+
if (!isRecord2(step)) continue;
|
|
14434
12748
|
if (step.type === "tool") {
|
|
14435
|
-
const toolId =
|
|
12749
|
+
const toolId = stringValue2(step.toolId) || stringValue2(step.tool);
|
|
14436
12750
|
if (toolId) seen.add(toolId);
|
|
14437
12751
|
}
|
|
14438
12752
|
if (step.type === "play_call") {
|
|
@@ -14444,20 +12758,20 @@ function collectStaticPipelineToolIds(staticPipeline) {
|
|
|
14444
12758
|
return [...seen].sort();
|
|
14445
12759
|
}
|
|
14446
12760
|
function toolGetterHintFromMetadata(toolId, tool) {
|
|
14447
|
-
const usageGuidance =
|
|
14448
|
-
const resultGuidance =
|
|
14449
|
-
const toolResponse =
|
|
14450
|
-
const lists =
|
|
12761
|
+
const usageGuidance = isRecord2(tool.usageGuidance) ? tool.usageGuidance : {};
|
|
12762
|
+
const resultGuidance = isRecord2(usageGuidance.toolExecutionResult) ? usageGuidance.toolExecutionResult : isRecord2(usageGuidance.tool_execution_result) ? usageGuidance.tool_execution_result : {};
|
|
12763
|
+
const toolResponse = isRecord2(resultGuidance.toolResponse) ? resultGuidance.toolResponse : isRecord2(resultGuidance.tool_response) ? resultGuidance.tool_response : {};
|
|
12764
|
+
const lists = extractionEntries(
|
|
14451
12765
|
resultGuidance.extractedLists ?? resultGuidance.extracted_lists
|
|
14452
12766
|
).map((entry) => ({
|
|
14453
|
-
name:
|
|
12767
|
+
name: stringValue2(entry.name),
|
|
14454
12768
|
expression: checkHintExpression(entry.expression),
|
|
14455
12769
|
raw: checkHintRawPath(firstRawPath(entry))
|
|
14456
12770
|
})).filter((entry) => entry.name && entry.expression);
|
|
14457
|
-
const values =
|
|
12771
|
+
const values = extractionEntries(
|
|
14458
12772
|
resultGuidance.extractedValues ?? resultGuidance.extracted_values
|
|
14459
12773
|
).map((entry) => ({
|
|
14460
|
-
name:
|
|
12774
|
+
name: stringValue2(entry.name),
|
|
14461
12775
|
expression: checkHintExpression(entry.expression),
|
|
14462
12776
|
raw: checkHintRawPath(firstRawPath(entry))
|
|
14463
12777
|
})).filter((entry) => entry.name && entry.expression);
|
|
@@ -14584,7 +12898,7 @@ async function handlePlayCheck(args) {
|
|
|
14584
12898
|
command: "check"
|
|
14585
12899
|
});
|
|
14586
12900
|
const play = await client.describePlay(
|
|
14587
|
-
|
|
12901
|
+
parseReferencedPlayTarget2(options.target).playName,
|
|
14588
12902
|
{ compact: true }
|
|
14589
12903
|
);
|
|
14590
12904
|
const result = {
|
|
@@ -14614,7 +12928,7 @@ async function handlePlayCheck(args) {
|
|
|
14614
12928
|
});
|
|
14615
12929
|
return 0;
|
|
14616
12930
|
} catch (error) {
|
|
14617
|
-
const resolved =
|
|
12931
|
+
const resolved = resolve5(options.target);
|
|
14618
12932
|
const message = error instanceof Error && error.message ? error.message : `File not found: ${resolved}`;
|
|
14619
12933
|
if (options.jsonOutput) {
|
|
14620
12934
|
printCommandEnvelope(
|
|
@@ -14635,7 +12949,7 @@ async function handlePlayCheck(args) {
|
|
|
14635
12949
|
return 1;
|
|
14636
12950
|
}
|
|
14637
12951
|
}
|
|
14638
|
-
const absolutePlayPath =
|
|
12952
|
+
const absolutePlayPath = resolve5(options.target);
|
|
14639
12953
|
const sourceCode = readFileSync2(absolutePlayPath, "utf-8");
|
|
14640
12954
|
const exportNames = resolvePlayCheckExportNames(sourceCode);
|
|
14641
12955
|
const outcomes = [];
|
|
@@ -14685,7 +12999,7 @@ function artifactForProductionCompatibilityCheck(artifact) {
|
|
|
14685
12999
|
"DEEPLINE_PROD_CHECK_AUTHORING_CONTRACT_EDITION must be a positive integer."
|
|
14686
13000
|
);
|
|
14687
13001
|
}
|
|
14688
|
-
const compatibility =
|
|
13002
|
+
const compatibility = isRecord2(artifact.compatibility) ? artifact.compatibility : {};
|
|
14689
13003
|
return {
|
|
14690
13004
|
...artifact,
|
|
14691
13005
|
compatibility: {
|
|
@@ -14755,7 +13069,7 @@ async function handleFileBackedRun(options, hooks) {
|
|
|
14755
13069
|
}
|
|
14756
13070
|
let client;
|
|
14757
13071
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
14758
|
-
const absolutePlayPath =
|
|
13072
|
+
const absolutePlayPath = resolve5(options.target.path);
|
|
14759
13073
|
progress.phase("compiling play");
|
|
14760
13074
|
const sourceCode = traceCliSync(
|
|
14761
13075
|
"cli.play_file_read_source",
|
|
@@ -15164,7 +13478,7 @@ async function handlePlayRun(args, hooks) {
|
|
|
15164
13478
|
const parsedOptions = Array.isArray(args) ? parsePlayRunOptions(args) : args;
|
|
15165
13479
|
const options = parsedOptions.runIdFile ? {
|
|
15166
13480
|
...parsedOptions,
|
|
15167
|
-
runIdFile: parsedOptions.dryRun ?
|
|
13481
|
+
runIdFile: parsedOptions.dryRun ? resolve5(parsedOptions.runIdFile) : await preflightRunIdFile(parsedOptions.runIdFile)
|
|
15168
13482
|
} : parsedOptions;
|
|
15169
13483
|
const runHooks = options.runIdFile ? {
|
|
15170
13484
|
...hooks,
|
|
@@ -15197,7 +13511,7 @@ async function handlePlayRun(args, hooks) {
|
|
|
15197
13511
|
if (isFileTarget2(options.target.path)) {
|
|
15198
13512
|
return handleFileBackedRun(options, runHooks);
|
|
15199
13513
|
}
|
|
15200
|
-
const resolved =
|
|
13514
|
+
const resolved = resolve5(options.target.path);
|
|
15201
13515
|
console.error(`File not found: ${resolved}`);
|
|
15202
13516
|
const dir = dirname2(resolved);
|
|
15203
13517
|
if (existsSync2(dir)) {
|
|
@@ -15958,11 +14272,11 @@ async function handleRunLogs(args) {
|
|
|
15958
14272
|
continue;
|
|
15959
14273
|
}
|
|
15960
14274
|
if (arg === "--limit" && args[index + 1]) {
|
|
15961
|
-
limit =
|
|
14275
|
+
limit = parsePositiveInteger2(args[++index], "--limit");
|
|
15962
14276
|
continue;
|
|
15963
14277
|
}
|
|
15964
14278
|
if (arg === "--out" && args[index + 1]) {
|
|
15965
|
-
outPath =
|
|
14279
|
+
outPath = resolve5(args[++index]);
|
|
15966
14280
|
continue;
|
|
15967
14281
|
}
|
|
15968
14282
|
if (arg === "--cursor" && args[index + 1]) {
|
|
@@ -15997,7 +14311,7 @@ async function handleRunLogs(args) {
|
|
|
15997
14311
|
if (outPath) {
|
|
15998
14312
|
const result2 = await client.runs.logs(runId, { all: true });
|
|
15999
14313
|
const logs = result2.entries.filter((line) => logLevelReaches(classifyLogLine(line).level, logLevel)).map((line) => classifyLogLine(line).line);
|
|
16000
|
-
|
|
14314
|
+
writeFileSync3(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
16001
14315
|
printCommandEnvelope(
|
|
16002
14316
|
{
|
|
16003
14317
|
runId: result2.runId,
|
|
@@ -16483,7 +14797,7 @@ async function handleRunExport(args) {
|
|
|
16483
14797
|
for (let index = 0; index < args.length; index += 1) {
|
|
16484
14798
|
const arg = args[index];
|
|
16485
14799
|
if (arg === "--out" && args[index + 1]) {
|
|
16486
|
-
outPath =
|
|
14800
|
+
outPath = resolve5(args[++index]);
|
|
16487
14801
|
continue;
|
|
16488
14802
|
}
|
|
16489
14803
|
if (arg === "--dataset" && args[index + 1]) {
|
|
@@ -16491,11 +14805,11 @@ async function handleRunExport(args) {
|
|
|
16491
14805
|
continue;
|
|
16492
14806
|
}
|
|
16493
14807
|
if (arg === "--metadata-out" && args[index + 1]) {
|
|
16494
|
-
metadataOutPath =
|
|
14808
|
+
metadataOutPath = resolve5(args[++index]);
|
|
16495
14809
|
}
|
|
16496
14810
|
if (arg === "--format") format = args[++index] ?? "";
|
|
16497
14811
|
if (arg === "--timeout-ms") {
|
|
16498
|
-
waitTimeoutMs =
|
|
14812
|
+
waitTimeoutMs = parsePositiveInteger2(args[++index] ?? "", arg);
|
|
16499
14813
|
if (!wait) {
|
|
16500
14814
|
throw new DeeplineError(
|
|
16501
14815
|
"--timeout-ms requires --wait.",
|
|
@@ -16625,7 +14939,7 @@ async function handleRunExport(args) {
|
|
|
16625
14939
|
payload.actions
|
|
16626
14940
|
);
|
|
16627
14941
|
if (metadataOutPath) {
|
|
16628
|
-
|
|
14942
|
+
writeFileSync3(
|
|
16629
14943
|
metadataOutPath,
|
|
16630
14944
|
`${JSON.stringify(payload, null, 2)}
|
|
16631
14945
|
`,
|
|
@@ -16676,7 +14990,7 @@ async function handlePlayGet(args) {
|
|
|
16676
14990
|
for (let index = 1; index < args.length; index += 1) {
|
|
16677
14991
|
const arg = args[index];
|
|
16678
14992
|
if (arg === "--out" && args[index + 1]) {
|
|
16679
|
-
outPath =
|
|
14993
|
+
outPath = resolve5(args[++index]);
|
|
16680
14994
|
}
|
|
16681
14995
|
if (arg === "--revision") {
|
|
16682
14996
|
const rawVersion = args[++index];
|
|
@@ -16697,7 +15011,7 @@ async function handlePlayGet(args) {
|
|
|
16697
15011
|
);
|
|
16698
15012
|
return 2;
|
|
16699
15013
|
}
|
|
16700
|
-
const playName = isFileTarget2(target) ? extractPlayName(readFileSync2(
|
|
15014
|
+
const playName = isFileTarget2(target) ? extractPlayName(readFileSync2(resolve5(target), "utf-8"), resolve5(target)) : parseReferencedPlayTarget2(target).playName;
|
|
16701
15015
|
const includeSource = sourceOutput || outPath !== null;
|
|
16702
15016
|
const detail = isFileTarget2(target) ? await client.getPlay(
|
|
16703
15017
|
playName,
|
|
@@ -16810,7 +15124,7 @@ async function handlePlayVersions(args) {
|
|
|
16810
15124
|
command: "versions"
|
|
16811
15125
|
});
|
|
16812
15126
|
const versions = await client.listPlayVersions(
|
|
16813
|
-
|
|
15127
|
+
parseReferencedPlayTarget2(playName).playName
|
|
16814
15128
|
);
|
|
16815
15129
|
if (jsonOutput) {
|
|
16816
15130
|
printCompactJson({ versions });
|
|
@@ -16970,7 +15284,7 @@ async function handlePlayPin(args, pinned) {
|
|
|
16970
15284
|
);
|
|
16971
15285
|
return 2;
|
|
16972
15286
|
}
|
|
16973
|
-
const parsedTarget =
|
|
15287
|
+
const parsedTarget = parseReferencedPlayTarget2(target);
|
|
16974
15288
|
if (parsedTarget.ownerSlug) {
|
|
16975
15289
|
console.error(
|
|
16976
15290
|
`deepline plays ${pinned ? "pin" : "unpin"} accepts an org-owned Play identifier without a namespace. Use "${parsedTarget.unqualifiedPlayName}" instead of "${target}".`
|
|
@@ -16989,12 +15303,12 @@ async function handlePlayPin(args, pinned) {
|
|
|
16989
15303
|
return 0;
|
|
16990
15304
|
}
|
|
16991
15305
|
function csvColumnLines(csvInput) {
|
|
16992
|
-
const rowSchema =
|
|
16993
|
-
const columns =
|
|
15306
|
+
const rowSchema = isRecord2(csvInput.rowInputSchema) ? csvInput.rowInputSchema : {};
|
|
15307
|
+
const columns = isRecord2(rowSchema.properties) ? Object.keys(rowSchema.properties) : [];
|
|
16994
15308
|
const required = new Set(
|
|
16995
15309
|
Array.isArray(rowSchema.required) ? rowSchema.required.map(String) : []
|
|
16996
15310
|
);
|
|
16997
|
-
const defaults =
|
|
15311
|
+
const defaults = isRecord2(csvInput.defaultColumns) ? csvInput.defaultColumns : {};
|
|
16998
15312
|
return [
|
|
16999
15313
|
...columns.map((column) => {
|
|
17000
15314
|
const headers = [defaults[column]].flat().filter((header) => header && header !== column);
|
|
@@ -17007,7 +15321,7 @@ function describedPlay(play) {
|
|
|
17007
15321
|
const reference = formatPlayListReference(play);
|
|
17008
15322
|
const starter = play.cloneEditStarter ?? buildCloneEditStarter(play);
|
|
17009
15323
|
const csv = play.csvInput ?? {};
|
|
17010
|
-
const headers =
|
|
15324
|
+
const headers = isRecord2(csv.defaultColumns) ? csv.defaultColumns : {};
|
|
17011
15325
|
const rowInputs = schemaFields(csv.rowInputSchema).map((field) => {
|
|
17012
15326
|
const header = [headers[field.name]].flat().filter((name) => name && name !== field.name).join(" or ");
|
|
17013
15327
|
return header ? {
|
|
@@ -17016,7 +15330,7 @@ function describedPlay(play) {
|
|
|
17016
15330
|
} : field;
|
|
17017
15331
|
});
|
|
17018
15332
|
const rowOutput = play.rowOutputSchema ?? {};
|
|
17019
|
-
const added =
|
|
15333
|
+
const added = isRecord2(rowOutput.addedColumns) ? rowOutput.addedColumns : {};
|
|
17020
15334
|
const rowOutputs = schemaFields(
|
|
17021
15335
|
Object.keys(added).length ? { properties: added } : rowOutput
|
|
17022
15336
|
).map((field) => ({ ...field, required: true }));
|
|
@@ -17195,7 +15509,7 @@ async function handlePlayDescribe(args) {
|
|
|
17195
15509
|
const definedName = isFileTarget2(playName) ? (() => {
|
|
17196
15510
|
try {
|
|
17197
15511
|
return extractPlayName(
|
|
17198
|
-
readFileSync2(
|
|
15512
|
+
readFileSync2(resolve5(playName), "utf-8"),
|
|
17199
15513
|
playName
|
|
17200
15514
|
);
|
|
17201
15515
|
} catch {
|
|
@@ -17226,7 +15540,7 @@ async function handlePlayDescribe(args) {
|
|
|
17226
15540
|
command: "describe"
|
|
17227
15541
|
});
|
|
17228
15542
|
const play = await client.describePlay(
|
|
17229
|
-
|
|
15543
|
+
parseReferencedPlayTarget2(playName).playName,
|
|
17230
15544
|
{
|
|
17231
15545
|
compact: args.includes("--compact")
|
|
17232
15546
|
}
|
|
@@ -17258,7 +15572,7 @@ async function handlePlaySave(args) {
|
|
|
17258
15572
|
graph = await traceCliSpan(
|
|
17259
15573
|
"cli.play_save_bundle_graph",
|
|
17260
15574
|
{ targetKind: "file" },
|
|
17261
|
-
() => collectBundledPlayGraph(
|
|
15575
|
+
() => collectBundledPlayGraph(resolve5(options.target))
|
|
17262
15576
|
);
|
|
17263
15577
|
assertPlayGraphAuthoring(graph);
|
|
17264
15578
|
} catch (error) {
|
|
@@ -17383,7 +15697,7 @@ async function handlePlayPublish(args) {
|
|
|
17383
15697
|
graph = await traceCliSpan(
|
|
17384
15698
|
"cli.play_publish_bundle_graph",
|
|
17385
15699
|
{ targetKind: "file" },
|
|
17386
|
-
() => collectBundledPlayGraph(
|
|
15700
|
+
() => collectBundledPlayGraph(resolve5(playName))
|
|
17387
15701
|
);
|
|
17388
15702
|
assertPlayGraphAuthoring(graph);
|
|
17389
15703
|
} catch (error) {
|
|
@@ -17527,7 +15841,7 @@ async function handlePlayPublish(args) {
|
|
|
17527
15841
|
printCompactJson(result2);
|
|
17528
15842
|
return 0;
|
|
17529
15843
|
}
|
|
17530
|
-
const resolvedName =
|
|
15844
|
+
const resolvedName = parseReferencedPlayTarget2(playName).playName;
|
|
17531
15845
|
if (useLatest) {
|
|
17532
15846
|
const versions = await client.listPlayVersions(resolvedName);
|
|
17533
15847
|
const latest = versions[0];
|
|
@@ -17591,7 +15905,7 @@ async function handlePlayDelete(args) {
|
|
|
17591
15905
|
const client = new DeeplineClient();
|
|
17592
15906
|
let detail;
|
|
17593
15907
|
try {
|
|
17594
|
-
detail = await client.getPlay(
|
|
15908
|
+
detail = await client.getPlay(parseReferencedPlayTarget2(playName).playName);
|
|
17595
15909
|
} catch (error) {
|
|
17596
15910
|
console.error(error instanceof Error ? error.message : String(error));
|
|
17597
15911
|
return 5;
|
|
@@ -17602,7 +15916,7 @@ async function handlePlayDelete(args) {
|
|
|
17602
15916
|
);
|
|
17603
15917
|
return 2;
|
|
17604
15918
|
}
|
|
17605
|
-
const resolvedName =
|
|
15919
|
+
const resolvedName = parseReferencedPlayTarget2(
|
|
17606
15920
|
formatPlayReference(detail.play)
|
|
17607
15921
|
).playName;
|
|
17608
15922
|
if (args.includes("--dry-run")) {
|
|
@@ -17666,7 +15980,7 @@ async function handlePlayRestore(args) {
|
|
|
17666
15980
|
const client = new DeeplineClient();
|
|
17667
15981
|
try {
|
|
17668
15982
|
const result = await client.restorePlay(
|
|
17669
|
-
|
|
15983
|
+
parseReferencedPlayTarget2(playName).playName
|
|
17670
15984
|
);
|
|
17671
15985
|
if (argsWantJson(args)) {
|
|
17672
15986
|
printCompactJson(result);
|
|
@@ -17960,7 +16274,6 @@ JSON field selection:
|
|
|
17960
16274
|
process.exitCode = exitCode;
|
|
17961
16275
|
}
|
|
17962
16276
|
);
|
|
17963
|
-
registerPlayBootstrapCommand(play);
|
|
17964
16277
|
registerPlaySettingsCommands(play);
|
|
17965
16278
|
registerPlayTriggerConfigCommands(play);
|
|
17966
16279
|
play.command("get <target>").description(
|
|
@@ -18160,7 +16473,7 @@ Examples:
|
|
|
18160
16473
|
process.exitCode = await ownView();
|
|
18161
16474
|
return;
|
|
18162
16475
|
}
|
|
18163
|
-
const { describeAnything } = await import("./describe-
|
|
16476
|
+
const { describeAnything } = await import("./describe-QUOLGZKH.mjs");
|
|
18164
16477
|
process.exitCode = await describeAnything(
|
|
18165
16478
|
name,
|
|
18166
16479
|
{
|
|
@@ -18898,7 +17211,7 @@ async function handlePlayShareStatus(args) {
|
|
|
18898
17211
|
console.error("Usage: deepline plays share status <play> [--json]");
|
|
18899
17212
|
return 2;
|
|
18900
17213
|
}
|
|
18901
|
-
const name =
|
|
17214
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
18902
17215
|
const status = await new DeeplineClient().getSharePage(name);
|
|
18903
17216
|
const outputStatus = shareStatusForOutput(status);
|
|
18904
17217
|
if (argsWantJson(args)) {
|
|
@@ -18940,7 +17253,7 @@ async function handlePlaySharePublish(args) {
|
|
|
18940
17253
|
);
|
|
18941
17254
|
return 2;
|
|
18942
17255
|
}
|
|
18943
|
-
const name =
|
|
17256
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
18944
17257
|
const client = new DeeplineClient();
|
|
18945
17258
|
let revisionId = shareFlagValue(args, "--revision-id");
|
|
18946
17259
|
let resolvedVersion;
|
|
@@ -19032,7 +17345,7 @@ async function handlePlayShareUpdate(args) {
|
|
|
19032
17345
|
);
|
|
19033
17346
|
return 2;
|
|
19034
17347
|
}
|
|
19035
|
-
const name =
|
|
17348
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
19036
17349
|
const seo = shareFlagValue(args, "--seo");
|
|
19037
17350
|
const seoIndexing = seo === "index" ? "index" : seo === "noindex" ? "noindex" : void 0;
|
|
19038
17351
|
const request = {
|
|
@@ -19056,7 +17369,7 @@ async function handlePlayShareRegenerate(args) {
|
|
|
19056
17369
|
);
|
|
19057
17370
|
return 2;
|
|
19058
17371
|
}
|
|
19059
|
-
const name =
|
|
17372
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
19060
17373
|
const client = new DeeplineClient();
|
|
19061
17374
|
let revisionId = shareFlagValue(args, "--revision-id");
|
|
19062
17375
|
const versionFlag = shareFlagValue(args, "--version");
|
|
@@ -19099,7 +17412,7 @@ async function handlePlayShareUnpublish(args) {
|
|
|
19099
17412
|
);
|
|
19100
17413
|
return 2;
|
|
19101
17414
|
}
|
|
19102
|
-
const name =
|
|
17415
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
19103
17416
|
const status = await new DeeplineClient().unpublishSharePage(name);
|
|
19104
17417
|
if (argsWantJson(args)) {
|
|
19105
17418
|
printCompactJson(status);
|