deepline 0.1.76 → 0.1.78
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/README.md +5 -8
- package/dist/cli/index.js +534 -350
- package/dist/cli/index.mjs +547 -363
- package/dist/index.d.mts +40 -2
- package/dist/index.d.ts +40 -2
- package/dist/index.js +198 -2
- package/dist/index.mjs +198 -2
- package/dist/repo/sdk/src/client.ts +7 -0
- package/dist/repo/sdk/src/play.ts +1 -1
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/sdk/src/types.ts +4 -0
- package/dist/repo/shared_libs/play-runtime/email-status.ts +301 -0
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +58 -1
- package/dist/repo/shared_libs/plays/dataset.ts +3 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -229,10 +229,10 @@ var import_node_path2 = require("path");
|
|
|
229
229
|
|
|
230
230
|
// src/release.ts
|
|
231
231
|
var SDK_RELEASE = {
|
|
232
|
-
version: "0.1.
|
|
232
|
+
version: "0.1.78",
|
|
233
233
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
234
234
|
supportPolicy: {
|
|
235
|
-
latest: "0.1.
|
|
235
|
+
latest: "0.1.78",
|
|
236
236
|
minimumSupported: "0.1.53",
|
|
237
237
|
deprecatedBelow: "0.1.53"
|
|
238
238
|
}
|
|
@@ -402,8 +402,8 @@ var HttpClient = class {
|
|
|
402
402
|
if (lastError instanceof DeeplineError) {
|
|
403
403
|
throw lastError;
|
|
404
404
|
}
|
|
405
|
-
const
|
|
406
|
-
throw new DeeplineError(
|
|
405
|
+
const errorMessage3 = lastError?.message ? `Unable to connect to ${baseUrl}. ${lastError.message}` : `Unable to connect to ${baseUrl}. Is the computer able to access the url?`;
|
|
406
|
+
throw new DeeplineError(errorMessage3);
|
|
407
407
|
}
|
|
408
408
|
/**
|
|
409
409
|
* Send a GET request.
|
|
@@ -808,6 +808,7 @@ var DeeplineClient = class {
|
|
|
808
808
|
aliases,
|
|
809
809
|
inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
|
|
810
810
|
outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
|
|
811
|
+
staticPipeline: isRecord(play.staticPipeline) ? play.staticPipeline : isRecord(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
|
|
811
812
|
...csvInput ? { csvInput } : {},
|
|
812
813
|
...rowOutputSchema ? { rowOutputSchema } : {},
|
|
813
814
|
runCommand: runCommand2,
|
|
@@ -4033,6 +4034,51 @@ function customerDbRows(result) {
|
|
|
4033
4034
|
function customerDbColumnNames(result) {
|
|
4034
4035
|
return result.columns.map((column) => column.name).filter(Boolean);
|
|
4035
4036
|
}
|
|
4037
|
+
function errorMessage(value) {
|
|
4038
|
+
return value instanceof Error ? value.message : String(value ?? "");
|
|
4039
|
+
}
|
|
4040
|
+
function collectErrorText(value) {
|
|
4041
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
4042
|
+
return errorMessage(value);
|
|
4043
|
+
}
|
|
4044
|
+
const record = value;
|
|
4045
|
+
return [
|
|
4046
|
+
errorMessage(value),
|
|
4047
|
+
typeof record.error === "string" ? record.error : "",
|
|
4048
|
+
typeof record.message === "string" ? record.message : "",
|
|
4049
|
+
typeof record.detail === "string" ? record.detail : "",
|
|
4050
|
+
typeof record.hint === "string" ? record.hint : "",
|
|
4051
|
+
typeof record.code === "string" ? record.code : "",
|
|
4052
|
+
record.response ? collectErrorText(record.response) : "",
|
|
4053
|
+
record.details ? collectErrorText(record.details) : ""
|
|
4054
|
+
].filter(Boolean).join("\n");
|
|
4055
|
+
}
|
|
4056
|
+
function formatDbQueryError(sql, error) {
|
|
4057
|
+
const text = collectErrorText(error);
|
|
4058
|
+
const lower = text.toLowerCase();
|
|
4059
|
+
const referencesStorage = /"storage"\.|storage\./i.test(sql);
|
|
4060
|
+
const runIdColumnMissing = /column\s+"?run_id"?\s+does not exist/i.test(text) || /run_id.*does not exist/i.test(lower);
|
|
4061
|
+
const relationMissing = /relation\s+["']?[^"']*storage[^"']*["']?\s+does not exist/i.test(text) || /42p01/i.test(text);
|
|
4062
|
+
if (referencesStorage && relationMissing) {
|
|
4063
|
+
return [
|
|
4064
|
+
"Customer DB query failed: the referenced storage table does not exist.",
|
|
4065
|
+
"Play map tables are created only when the corresponding ctx.map(...).run(...) call executes. Pilot branches, early returns, and runs that fail before the map do not create that table.",
|
|
4066
|
+
"Use `deepline runs get <run-id> --full --json` to inspect returned dataset handles, then export them with `deepline runs export <run-id> --dataset result.rows --out rows.csv`.",
|
|
4067
|
+
`Original error: ${errorMessage(error)}`
|
|
4068
|
+
].join("\n");
|
|
4069
|
+
}
|
|
4070
|
+
if (referencesStorage && runIdColumnMissing) {
|
|
4071
|
+
return [
|
|
4072
|
+
"Customer DB query failed: storage map tables use `_run_id`, not `run_id`.",
|
|
4073
|
+
"Prefer `deepline runs export <run-id> --dataset result.rows --out rows.csv` unless you are doing deep table debugging.",
|
|
4074
|
+
`Original error: ${errorMessage(error)}`
|
|
4075
|
+
].join("\n");
|
|
4076
|
+
}
|
|
4077
|
+
if (error instanceof DeeplineError) {
|
|
4078
|
+
return error.message;
|
|
4079
|
+
}
|
|
4080
|
+
return errorMessage(error);
|
|
4081
|
+
}
|
|
4036
4082
|
function writeCustomerDbCsv(result, outPath) {
|
|
4037
4083
|
const resolved = (0, import_node_path7.resolve)(outPath);
|
|
4038
4084
|
(0, import_node_fs6.writeFileSync)(
|
|
@@ -4093,7 +4139,13 @@ async function handleDbQuery(args) {
|
|
|
4093
4139
|
const jsonOutput = argsWantJson(args);
|
|
4094
4140
|
const explicitJsonOutput = args.includes("--json");
|
|
4095
4141
|
const client = new DeeplineClient();
|
|
4096
|
-
|
|
4142
|
+
let result;
|
|
4143
|
+
try {
|
|
4144
|
+
result = await client.queryCustomerDb({ sql, maxRows });
|
|
4145
|
+
} catch (error) {
|
|
4146
|
+
console.error(formatDbQueryError(sql, error));
|
|
4147
|
+
return 1;
|
|
4148
|
+
}
|
|
4097
4149
|
const toolCommand = `deepline tools execute query_customer_db --payload ${JSON.stringify(
|
|
4098
4150
|
{
|
|
4099
4151
|
sql,
|
|
@@ -4190,13 +4242,18 @@ function registerDbCommands(program) {
|
|
|
4190
4242
|
"after",
|
|
4191
4243
|
`
|
|
4192
4244
|
Notes:
|
|
4193
|
-
|
|
4245
|
+
Agent-safe SQL for the active workspace customer database.
|
|
4246
|
+
Reads: SELECT, EXPLAIN, and read-only WITH can inspect permitted schemas.
|
|
4247
|
+
Writes: CREATE TABLE, INSERT, UPDATE, DELETE, ALTER, DROP, TRUNCATE, and
|
|
4248
|
+
CREATE INDEX must target schema-qualified storage tables, such as storage.agent_notes.
|
|
4249
|
+
If CREATE TABLE blocked (...) fails, use CREATE TABLE storage.blocked (...).
|
|
4194
4250
|
Results are bounded by the server and --max-rows. Use --json for stable output.
|
|
4195
4251
|
Use --format csv or --format markdown for agent-readable exports and display tables.
|
|
4196
4252
|
|
|
4197
4253
|
Examples:
|
|
4198
4254
|
deepline db query --sql "select * from companies limit 20"
|
|
4199
4255
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
4256
|
+
deepline db query --sql "create table if not exists storage.agent_notes (id text primary key, note text not null)"
|
|
4200
4257
|
deepline db query --sql "select * from contacts" --max-rows 100 --json
|
|
4201
4258
|
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
4202
4259
|
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
@@ -4208,12 +4265,16 @@ Examples:
|
|
|
4208
4265
|
Notes:
|
|
4209
4266
|
Requires --sql. Output is a compact table in a terminal and raw JSON with
|
|
4210
4267
|
--json or when stdout is piped. The active auth workspace determines scope.
|
|
4268
|
+
Read permitted schemas with SELECT, EXPLAIN, or read-only WITH.
|
|
4269
|
+
Write only to schema-qualified storage tables. For example, use
|
|
4270
|
+
CREATE TABLE storage.blocked (...) instead of CREATE TABLE blocked (...).
|
|
4211
4271
|
--format csv and --format markdown are explicit data/display formats and can
|
|
4212
4272
|
be written directly with --out.
|
|
4213
4273
|
|
|
4214
4274
|
Examples:
|
|
4215
4275
|
deepline db query --sql "select * from companies limit 20"
|
|
4216
4276
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
4277
|
+
deepline db query --sql "create table if not exists storage.agent_notes (id text primary key, note text not null)"
|
|
4217
4278
|
deepline db psql --sql "select count(*) from contacts" --json
|
|
4218
4279
|
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
4219
4280
|
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
@@ -6073,19 +6134,19 @@ function playBootstrapTemplateConfig(template) {
|
|
|
6073
6134
|
function templateExample(template) {
|
|
6074
6135
|
switch (template) {
|
|
6075
6136
|
case "people-list":
|
|
6076
|
-
return "deepline plays bootstrap people-list --from provider:dropleads_search_people
|
|
6137
|
+
return "deepline plays bootstrap people-list --from provider:dropleads_search_people --out people.play.ts";
|
|
6077
6138
|
case "company-list":
|
|
6078
|
-
return "deepline plays bootstrap company-list --from provider:apollo_company_search
|
|
6139
|
+
return "deepline plays bootstrap company-list --from provider:apollo_company_search --out companies.play.ts";
|
|
6079
6140
|
case "people-email":
|
|
6080
|
-
return "deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall
|
|
6141
|
+
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";
|
|
6081
6142
|
case "people-phone":
|
|
6082
|
-
return "deepline plays bootstrap people-phone --from csv:data/vp_contacts.csv --using play:prebuilt/person-to-phone
|
|
6143
|
+
return "deepline plays bootstrap people-phone --from csv:data/vp_contacts.csv --using play:prebuilt/person-to-phone --out phone-flow.play.ts";
|
|
6083
6144
|
case "company-people":
|
|
6084
|
-
return "deepline plays bootstrap company-people --from provider:apollo_company_search --using play:prebuilt/company-to-contact
|
|
6145
|
+
return "deepline plays bootstrap company-people --from provider:apollo_company_search --using play:prebuilt/company-to-contact --out company-people.play.ts";
|
|
6085
6146
|
case "company-people-email":
|
|
6086
|
-
return "deepline plays bootstrap company-people-email --from provider:apollo_company_search --people play:prebuilt/company-to-contact --email providers:hunter_email_finder,leadmagic_email_finder
|
|
6147
|
+
return "deepline plays bootstrap company-people-email --from provider:apollo_company_search --people play:prebuilt/company-to-contact --email providers:hunter_email_finder,leadmagic_email_finder --out account-emails.play.ts";
|
|
6087
6148
|
case "company-people-phone":
|
|
6088
|
-
return "deepline plays bootstrap company-people-phone --from provider:apollo_company_search --people play:prebuilt/company-to-contact --phone providers:ai_ark_mobile_phone_finder
|
|
6149
|
+
return "deepline plays bootstrap company-people-phone --from provider:apollo_company_search --people play:prebuilt/company-to-contact --phone providers:ai_ark_mobile_phone_finder --out account-phones.play.ts";
|
|
6089
6150
|
}
|
|
6090
6151
|
}
|
|
6091
6152
|
var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
@@ -6094,19 +6155,22 @@ var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
|
6094
6155
|
"phone"
|
|
6095
6156
|
];
|
|
6096
6157
|
function playBootstrapUsageLine() {
|
|
6097
|
-
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]
|
|
6158
|
+
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]`;
|
|
6098
6159
|
}
|
|
6099
6160
|
function requireBootstrapTemplate(rawTemplate) {
|
|
6100
6161
|
if (!rawTemplate) {
|
|
6101
6162
|
throw new PlayBootstrapUsageError(
|
|
6102
6163
|
`plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}.
|
|
6103
|
-
Example: deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall
|
|
6164
|
+
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`
|
|
6104
6165
|
);
|
|
6105
6166
|
}
|
|
6106
6167
|
if (!isPlayBootstrapTemplate(rawTemplate)) {
|
|
6168
|
+
const looksLikePlayReference = rawTemplate.includes("/") || rawTemplate.endsWith(".play.ts");
|
|
6107
6169
|
throw new PlayBootstrapUsageError(
|
|
6108
6170
|
`Unknown plays bootstrap template: ${rawTemplate}
|
|
6109
|
-
Supported templates: ${formatPlayBootstrapTemplates()}`
|
|
6171
|
+
Supported templates: ${formatPlayBootstrapTemplates()}` + (looksLikePlayReference ? `
|
|
6172
|
+
|
|
6173
|
+
"${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 '{...}' --watch" to run it directly, "deepline plays describe ${rawTemplate} --json" to inspect its contract, or "deepline plays get ${rawTemplate} --source --out scratchpad.play.ts" to clone/edit it.` : "")
|
|
6110
6174
|
);
|
|
6111
6175
|
}
|
|
6112
6176
|
return rawTemplate;
|
|
@@ -6248,7 +6312,8 @@ function parsePlayBootstrapOptions(args) {
|
|
|
6248
6312
|
people: null,
|
|
6249
6313
|
email: null,
|
|
6250
6314
|
phone: null,
|
|
6251
|
-
limit: 5
|
|
6315
|
+
limit: 5,
|
|
6316
|
+
out: null
|
|
6252
6317
|
};
|
|
6253
6318
|
for (let index = 0; index < rest.length; index += 1) {
|
|
6254
6319
|
const arg = rest[index];
|
|
@@ -6282,6 +6347,10 @@ function parsePlayBootstrapOptions(args) {
|
|
|
6282
6347
|
options.limit = parsePositiveInteger2(value(), "--limit");
|
|
6283
6348
|
index += 1;
|
|
6284
6349
|
break;
|
|
6350
|
+
case "--out":
|
|
6351
|
+
options.out = value();
|
|
6352
|
+
index += 1;
|
|
6353
|
+
break;
|
|
6285
6354
|
default:
|
|
6286
6355
|
throw new PlayBootstrapUsageError(
|
|
6287
6356
|
`Unknown plays bootstrap option: ${arg}
|
|
@@ -6399,7 +6468,7 @@ function packagedCsvPathForPlay(csvPath) {
|
|
|
6399
6468
|
const relativePath = (0, import_node_path11.relative)(playDir, absoluteCsvPath);
|
|
6400
6469
|
if (relativePath === "" || relativePath.startsWith("..") || (0, import_node_path11.isAbsolute)(relativePath)) {
|
|
6401
6470
|
throw new PlayBootstrapUsageError(
|
|
6402
|
-
`--from csv:${csvPath} must point to a file inside the directory where you run plays bootstrap. Run bootstrap from the intended play directory
|
|
6471
|
+
`--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.`
|
|
6403
6472
|
);
|
|
6404
6473
|
}
|
|
6405
6474
|
const portablePath = relativePath.split("\\").join("/");
|
|
@@ -6806,8 +6875,18 @@ function validateBootstrapRoutes(input2) {
|
|
|
6806
6875
|
"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."
|
|
6807
6876
|
);
|
|
6808
6877
|
}
|
|
6878
|
+
assertComposablePlayRoute({
|
|
6879
|
+
stageLabel: "--people",
|
|
6880
|
+
playRef: stagePlayRef(input2.options.people),
|
|
6881
|
+
play: input2.peoplePlay
|
|
6882
|
+
});
|
|
6809
6883
|
for (const finder of ["email_finder", "phone_finder"]) {
|
|
6810
6884
|
const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
|
|
6885
|
+
assertComposablePlayRoute({
|
|
6886
|
+
stageLabel: finder === "email_finder" ? "--email/--using" : "--phone/--using",
|
|
6887
|
+
playRef: stagePlayRef(finderStage(input2.options, finder)),
|
|
6888
|
+
play: input2.finderPlays[finder] ?? null
|
|
6889
|
+
});
|
|
6811
6890
|
for (const tool of input2.finderTools[finder] ?? []) {
|
|
6812
6891
|
if (!tool.categories.includes(requiredCategory)) {
|
|
6813
6892
|
throw new PlayBootstrapValidationError(
|
|
@@ -6822,6 +6901,38 @@ function validateBootstrapRoutes(input2) {
|
|
|
6822
6901
|
}
|
|
6823
6902
|
}
|
|
6824
6903
|
}
|
|
6904
|
+
function staticPipelineSubsteps(pipeline) {
|
|
6905
|
+
if (!isRecord3(pipeline)) return [];
|
|
6906
|
+
return [
|
|
6907
|
+
...extractionEntries(pipeline.stages),
|
|
6908
|
+
...extractionEntries(pipeline.substeps)
|
|
6909
|
+
];
|
|
6910
|
+
}
|
|
6911
|
+
function playUsesMapBackedRuntime(play) {
|
|
6912
|
+
const pipeline = play?.staticPipeline;
|
|
6913
|
+
if (!isRecord3(pipeline)) return false;
|
|
6914
|
+
if (stringValue(pipeline.tableNamespace)) return true;
|
|
6915
|
+
return staticPipelineSubsteps(pipeline).some((substep) => {
|
|
6916
|
+
if (stringValue(substep.type) === "map") return true;
|
|
6917
|
+
return playUsesMapBackedRuntime({
|
|
6918
|
+
name: play?.name ?? "child",
|
|
6919
|
+
aliases: [],
|
|
6920
|
+
runCommand: "",
|
|
6921
|
+
examples: [],
|
|
6922
|
+
staticPipeline: isRecord3(substep.pipeline) ? substep.pipeline : null
|
|
6923
|
+
});
|
|
6924
|
+
});
|
|
6925
|
+
}
|
|
6926
|
+
function assertComposablePlayRoute(input2) {
|
|
6927
|
+
if (!input2.playRef || !playUsesMapBackedRuntime(input2.play)) return;
|
|
6928
|
+
const runCommand2 = input2.play?.runCommand?.trim() || `deepline plays run ${input2.playRef} --input '{...}' --watch`;
|
|
6929
|
+
throw new PlayBootstrapValidationError(
|
|
6930
|
+
`Cannot use ${input2.stageLabel} play:${input2.playRef} in plays bootstrap composition: the selected play is map-backed/direct-run-only. Child plays that use ctx.map() 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: ${runCommand2}`
|
|
6931
|
+
);
|
|
6932
|
+
}
|
|
6933
|
+
function sourcePlayNeedsExportFirst(input2) {
|
|
6934
|
+
return input2.source.kind === "play" && playUsesMapBackedRuntime(input2.sourcePlay);
|
|
6935
|
+
}
|
|
6825
6936
|
function sourceCollectionName(entity) {
|
|
6826
6937
|
switch (entity) {
|
|
6827
6938
|
case "company":
|
|
@@ -6851,6 +6962,22 @@ function generateCsvSourceRowsBlock(input2) {
|
|
|
6851
6962
|
const ${input2.collection}: ${input2.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
6852
6963
|
}
|
|
6853
6964
|
function generatePlaySourceRowsBlock(input2) {
|
|
6965
|
+
if (sourcePlayNeedsExportFirst({
|
|
6966
|
+
source: input2.source,
|
|
6967
|
+
sourcePlay: input2.sourcePlay
|
|
6968
|
+
})) {
|
|
6969
|
+
const sourcePlay = input2.sourcePlay;
|
|
6970
|
+
const runCommand2 = sourcePlay?.runCommand?.trim() || `deepline plays run ${input2.source.value} --input '{...}' --watch`;
|
|
6971
|
+
return `// Source play ${input2.source.value} is map-backed/direct-run-only, so this generated play is stage 2.
|
|
6972
|
+
// Stage 1:
|
|
6973
|
+
// ${runCommand2}
|
|
6974
|
+
// Stage 2:
|
|
6975
|
+
// deepline runs export <stage-1-run-id> --dataset 'result.rows' --out source-export.csv
|
|
6976
|
+
// Stage 3:
|
|
6977
|
+
// deepline plays run <this-file.play.ts> --input '{"sourceCsv":"source-export.csv","limit":${input2.sourcePlay ? "5" : "5"}}' --watch
|
|
6978
|
+
const sourceDataset = await ctx.csv<${input2.collectionType}>(input.sourceCsv ?? './source-export.csv');
|
|
6979
|
+
const ${input2.collection}: ${input2.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
6980
|
+
}
|
|
6854
6981
|
const playInput = generatePlayInputObject({
|
|
6855
6982
|
schema: input2.sourcePlay?.inputSchema,
|
|
6856
6983
|
indent: " ",
|
|
@@ -7135,6 +7262,7 @@ ${typeDefinitions}
|
|
|
7135
7262
|
|
|
7136
7263
|
type Input = {
|
|
7137
7264
|
limit?: number;
|
|
7265
|
+
sourceCsv?: string;
|
|
7138
7266
|
};
|
|
7139
7267
|
|
|
7140
7268
|
export default definePlay(${jsString(input2.options.name)}, async (ctx, input: Input = {}) => {
|
|
@@ -7201,6 +7329,7 @@ async function loadBootstrapContracts(client, options) {
|
|
|
7201
7329
|
validateBootstrapRoutes({
|
|
7202
7330
|
options,
|
|
7203
7331
|
sourceTools: contracts.sourceTools,
|
|
7332
|
+
sourcePlay: contracts.sourcePlay,
|
|
7204
7333
|
peoplePlay: contracts.peoplePlay,
|
|
7205
7334
|
finderTools: contracts.finderTools,
|
|
7206
7335
|
finderPlays: contracts.finderPlays
|
|
@@ -7222,11 +7351,11 @@ function loadCsvContext(source) {
|
|
|
7222
7351
|
};
|
|
7223
7352
|
}
|
|
7224
7353
|
}
|
|
7225
|
-
function
|
|
7354
|
+
function errorMessage2(error) {
|
|
7226
7355
|
return error instanceof Error ? error.message : String(error);
|
|
7227
7356
|
}
|
|
7228
7357
|
function renderPlayBootstrapError(error) {
|
|
7229
|
-
console.error(
|
|
7358
|
+
console.error(errorMessage2(error));
|
|
7230
7359
|
return error instanceof PlayBootstrapError ? error.exitCode : 1;
|
|
7231
7360
|
}
|
|
7232
7361
|
async function runPlayBootstrap(args) {
|
|
@@ -7239,6 +7368,12 @@ async function runPlayBootstrap(args) {
|
|
|
7239
7368
|
...contracts,
|
|
7240
7369
|
...csvContext
|
|
7241
7370
|
});
|
|
7371
|
+
if (options.out) {
|
|
7372
|
+
(0, import_node_fs9.writeFileSync)((0, import_node_path11.resolve)(options.out), source, "utf-8");
|
|
7373
|
+
process.stdout.write(`Wrote ${(0, import_node_path11.resolve)(options.out)}
|
|
7374
|
+
`);
|
|
7375
|
+
return 0;
|
|
7376
|
+
}
|
|
7242
7377
|
process.stdout.write(source);
|
|
7243
7378
|
return 0;
|
|
7244
7379
|
}
|
|
@@ -7251,7 +7386,7 @@ function registerPlayBootstrapCommand(play) {
|
|
|
7251
7386
|
`
|
|
7252
7387
|
Notes:
|
|
7253
7388
|
Cloud-validated play generator for agents. Pick the JTBD as the positional
|
|
7254
|
-
template, bind resources with typed refs,
|
|
7389
|
+
template, bind resources with typed refs, write the .play.ts file with --out,
|
|
7255
7390
|
then edit the generated TODO mapping comments. Multiple finder providers are
|
|
7256
7391
|
generated as a waterfall in the order you pass them.
|
|
7257
7392
|
|
|
@@ -7259,9 +7394,8 @@ Notes:
|
|
|
7259
7394
|
Deepline. It prints TypeScript source only and does not run paid tools; the
|
|
7260
7395
|
generated play may spend credits later when you run it.
|
|
7261
7396
|
|
|
7262
|
-
stdout is the generated .play.ts source.
|
|
7263
|
-
|
|
7264
|
-
deepline plays bootstrap ... > scratchpad.play.ts
|
|
7397
|
+
By default stdout is the generated .play.ts source. Use --out to write a file
|
|
7398
|
+
directly. Errors and diagnostics go to stderr. There is no JSON mode.
|
|
7265
7399
|
|
|
7266
7400
|
Templates:
|
|
7267
7401
|
people-list start from people/contact rows
|
|
@@ -7285,7 +7419,7 @@ Notes:
|
|
|
7285
7419
|
email/phone finder providers must match their category and expose value getters
|
|
7286
7420
|
finder plays/providers must match the route; generated code leaves input mapping explicit
|
|
7287
7421
|
business-specific provider inputs and company -> people persona fields are TODOs in code
|
|
7288
|
-
csv: paths are resolved from the directory where you run bootstrap;
|
|
7422
|
+
csv: paths are resolved from the directory where you run bootstrap; write the play file there too
|
|
7289
7423
|
|
|
7290
7424
|
Exit codes:
|
|
7291
7425
|
0 success
|
|
@@ -7293,13 +7427,13 @@ Notes:
|
|
|
7293
7427
|
7 route validation failed
|
|
7294
7428
|
|
|
7295
7429
|
Examples:
|
|
7296
|
-
deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall --limit 5
|
|
7430
|
+
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
|
|
7297
7431
|
deepline plays check email-flow.play.ts
|
|
7298
7432
|
deepline plays run email-flow.play.ts --input '{"limit":5}' --watch
|
|
7299
7433
|
|
|
7300
|
-
deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5
|
|
7301
|
-
deepline plays bootstrap company-people-email --from provider:apollo_company_search --people play:prebuilt/company-to-contact --email play:prebuilt/name-and-domain-to-email-waterfall --limit 5
|
|
7302
|
-
deepline plays bootstrap company-list --from provider:apollo_company_search --limit 5
|
|
7434
|
+
deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5 --out prospecting.play.ts
|
|
7435
|
+
deepline plays bootstrap company-people-email --from provider:apollo_company_search --people play:prebuilt/company-to-contact --email play:prebuilt/name-and-domain-to-email-waterfall --limit 5 --out account-contacts.play.ts
|
|
7436
|
+
deepline plays bootstrap company-list --from provider:apollo_company_search --limit 5 --out companies.play.ts
|
|
7303
7437
|
`
|
|
7304
7438
|
).option("--name <name>", "Generated play name").option(
|
|
7305
7439
|
"--from <ref>",
|
|
@@ -7316,7 +7450,7 @@ Examples:
|
|
|
7316
7450
|
).option(
|
|
7317
7451
|
"--phone <ref>",
|
|
7318
7452
|
"Phone finder stage: play:REF, provider:ID, or providers:ID,ID"
|
|
7319
|
-
).option("--limit <n>", "Maximum rows to fan out in the generated play").action(async (template, options) => {
|
|
7453
|
+
).option("--limit <n>", "Maximum rows to fan out in the generated play").option("--out <path>", "Write generated play source to a file").action(async (template, options) => {
|
|
7320
7454
|
process.exitCode = await handlePlayBootstrap([
|
|
7321
7455
|
template,
|
|
7322
7456
|
...options.name ? ["--name", options.name] : [],
|
|
@@ -7325,7 +7459,8 @@ Examples:
|
|
|
7325
7459
|
...options.people ? ["--people", options.people] : [],
|
|
7326
7460
|
...options.email ? ["--email", options.email] : [],
|
|
7327
7461
|
...options.phone ? ["--phone", options.phone] : [],
|
|
7328
|
-
...options.limit ? ["--limit", options.limit] : []
|
|
7462
|
+
...options.limit ? ["--limit", options.limit] : [],
|
|
7463
|
+
...options.out ? ["--out", options.out] : []
|
|
7329
7464
|
]);
|
|
7330
7465
|
});
|
|
7331
7466
|
}
|
|
@@ -7475,204 +7610,6 @@ function createCliProgress(enabled) {
|
|
|
7475
7610
|
return progress;
|
|
7476
7611
|
}
|
|
7477
7612
|
|
|
7478
|
-
// ../shared_libs/plays/row-identity.ts
|
|
7479
|
-
var POSTGRES_IDENTIFIER_MAX_LENGTH = 63;
|
|
7480
|
-
var PLAY_NAME_MAX_LENGTH = POSTGRES_IDENTIFIER_MAX_LENGTH;
|
|
7481
|
-
var MAP_KEY_NAMESPACE_MAX_LENGTH = POSTGRES_IDENTIFIER_MAX_LENGTH;
|
|
7482
|
-
var SHA256_INITIAL_HASH = [
|
|
7483
|
-
1779033703,
|
|
7484
|
-
3144134277,
|
|
7485
|
-
1013904242,
|
|
7486
|
-
2773480762,
|
|
7487
|
-
1359893119,
|
|
7488
|
-
2600822924,
|
|
7489
|
-
528734635,
|
|
7490
|
-
1541459225
|
|
7491
|
-
];
|
|
7492
|
-
var SHA256_ROUND_CONSTANTS = [
|
|
7493
|
-
1116352408,
|
|
7494
|
-
1899447441,
|
|
7495
|
-
3049323471,
|
|
7496
|
-
3921009573,
|
|
7497
|
-
961987163,
|
|
7498
|
-
1508970993,
|
|
7499
|
-
2453635748,
|
|
7500
|
-
2870763221,
|
|
7501
|
-
3624381080,
|
|
7502
|
-
310598401,
|
|
7503
|
-
607225278,
|
|
7504
|
-
1426881987,
|
|
7505
|
-
1925078388,
|
|
7506
|
-
2162078206,
|
|
7507
|
-
2614888103,
|
|
7508
|
-
3248222580,
|
|
7509
|
-
3835390401,
|
|
7510
|
-
4022224774,
|
|
7511
|
-
264347078,
|
|
7512
|
-
604807628,
|
|
7513
|
-
770255983,
|
|
7514
|
-
1249150122,
|
|
7515
|
-
1555081692,
|
|
7516
|
-
1996064986,
|
|
7517
|
-
2554220882,
|
|
7518
|
-
2821834349,
|
|
7519
|
-
2952996808,
|
|
7520
|
-
3210313671,
|
|
7521
|
-
3336571891,
|
|
7522
|
-
3584528711,
|
|
7523
|
-
113926993,
|
|
7524
|
-
338241895,
|
|
7525
|
-
666307205,
|
|
7526
|
-
773529912,
|
|
7527
|
-
1294757372,
|
|
7528
|
-
1396182291,
|
|
7529
|
-
1695183700,
|
|
7530
|
-
1986661051,
|
|
7531
|
-
2177026350,
|
|
7532
|
-
2456956037,
|
|
7533
|
-
2730485921,
|
|
7534
|
-
2820302411,
|
|
7535
|
-
3259730800,
|
|
7536
|
-
3345764771,
|
|
7537
|
-
3516065817,
|
|
7538
|
-
3600352804,
|
|
7539
|
-
4094571909,
|
|
7540
|
-
275423344,
|
|
7541
|
-
430227734,
|
|
7542
|
-
506948616,
|
|
7543
|
-
659060556,
|
|
7544
|
-
883997877,
|
|
7545
|
-
958139571,
|
|
7546
|
-
1322822218,
|
|
7547
|
-
1537002063,
|
|
7548
|
-
1747873779,
|
|
7549
|
-
1955562222,
|
|
7550
|
-
2024104815,
|
|
7551
|
-
2227730452,
|
|
7552
|
-
2361852424,
|
|
7553
|
-
2428436474,
|
|
7554
|
-
2756734187,
|
|
7555
|
-
3204031479,
|
|
7556
|
-
3329325298
|
|
7557
|
-
];
|
|
7558
|
-
function rightRotate32(value, bits) {
|
|
7559
|
-
return value >>> bits | value << 32 - bits;
|
|
7560
|
-
}
|
|
7561
|
-
function sha256Hex(input2) {
|
|
7562
|
-
const bytes = Array.from(new TextEncoder().encode(input2));
|
|
7563
|
-
const bitLength = bytes.length * 8;
|
|
7564
|
-
bytes.push(128);
|
|
7565
|
-
while (bytes.length % 64 !== 56) {
|
|
7566
|
-
bytes.push(0);
|
|
7567
|
-
}
|
|
7568
|
-
const highBits = Math.floor(bitLength / 4294967296);
|
|
7569
|
-
const lowBits = bitLength >>> 0;
|
|
7570
|
-
bytes.push(
|
|
7571
|
-
highBits >>> 24 & 255,
|
|
7572
|
-
highBits >>> 16 & 255,
|
|
7573
|
-
highBits >>> 8 & 255,
|
|
7574
|
-
highBits & 255,
|
|
7575
|
-
lowBits >>> 24 & 255,
|
|
7576
|
-
lowBits >>> 16 & 255,
|
|
7577
|
-
lowBits >>> 8 & 255,
|
|
7578
|
-
lowBits & 255
|
|
7579
|
-
);
|
|
7580
|
-
const hash = [...SHA256_INITIAL_HASH];
|
|
7581
|
-
const words = new Array(64).fill(0);
|
|
7582
|
-
for (let offset = 0; offset < bytes.length; offset += 64) {
|
|
7583
|
-
for (let index = 0; index < 16; index += 1) {
|
|
7584
|
-
const wordOffset = offset + index * 4;
|
|
7585
|
-
words[index] = (bytes[wordOffset] ?? 0) << 24 | (bytes[wordOffset + 1] ?? 0) << 16 | (bytes[wordOffset + 2] ?? 0) << 8 | (bytes[wordOffset + 3] ?? 0);
|
|
7586
|
-
}
|
|
7587
|
-
for (let index = 16; index < 64; index += 1) {
|
|
7588
|
-
const s0 = rightRotate32(words[index - 15], 7) ^ rightRotate32(words[index - 15], 18) ^ words[index - 15] >>> 3;
|
|
7589
|
-
const s1 = rightRotate32(words[index - 2], 17) ^ rightRotate32(words[index - 2], 19) ^ words[index - 2] >>> 10;
|
|
7590
|
-
words[index] = words[index - 16] + s0 + words[index - 7] + s1 >>> 0;
|
|
7591
|
-
}
|
|
7592
|
-
let [a, b, c, d, e, f, g, h] = hash;
|
|
7593
|
-
for (let index = 0; index < 64; index += 1) {
|
|
7594
|
-
const s1 = rightRotate32(e, 6) ^ rightRotate32(e, 11) ^ rightRotate32(e, 25);
|
|
7595
|
-
const ch = e & f ^ ~e & g;
|
|
7596
|
-
const temp1 = h + s1 + ch + SHA256_ROUND_CONSTANTS[index] + words[index] >>> 0;
|
|
7597
|
-
const s0 = rightRotate32(a, 2) ^ rightRotate32(a, 13) ^ rightRotate32(a, 22);
|
|
7598
|
-
const maj = a & b ^ a & c ^ b & c;
|
|
7599
|
-
const temp2 = s0 + maj >>> 0;
|
|
7600
|
-
h = g;
|
|
7601
|
-
g = f;
|
|
7602
|
-
f = e;
|
|
7603
|
-
e = d + temp1 >>> 0;
|
|
7604
|
-
d = c;
|
|
7605
|
-
c = b;
|
|
7606
|
-
b = a;
|
|
7607
|
-
a = temp1 + temp2 >>> 0;
|
|
7608
|
-
}
|
|
7609
|
-
hash[0] = hash[0] + a >>> 0;
|
|
7610
|
-
hash[1] = hash[1] + b >>> 0;
|
|
7611
|
-
hash[2] = hash[2] + c >>> 0;
|
|
7612
|
-
hash[3] = hash[3] + d >>> 0;
|
|
7613
|
-
hash[4] = hash[4] + e >>> 0;
|
|
7614
|
-
hash[5] = hash[5] + f >>> 0;
|
|
7615
|
-
hash[6] = hash[6] + g >>> 0;
|
|
7616
|
-
hash[7] = hash[7] + h >>> 0;
|
|
7617
|
-
}
|
|
7618
|
-
return hash.map((word) => word.toString(16).padStart(8, "0")).join("");
|
|
7619
|
-
}
|
|
7620
|
-
function sanitizeIdentifierPart(value) {
|
|
7621
|
-
return value.trim().replace(/[^a-z0-9]+/gi, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
7622
|
-
}
|
|
7623
|
-
function validateIdentifierPart(rawValue, label, maxLength) {
|
|
7624
|
-
const sanitized = sanitizeIdentifierPart(rawValue);
|
|
7625
|
-
if (!sanitized) {
|
|
7626
|
-
throw new Error(
|
|
7627
|
-
`${label} must contain at least one letter or number after normalization. Use only letters, numbers, underscores, or hyphens.`
|
|
7628
|
-
);
|
|
7629
|
-
}
|
|
7630
|
-
if (sanitized.length > maxLength) {
|
|
7631
|
-
throw new Error(
|
|
7632
|
-
`${label} is too long after normalization (${sanitized.length}/${maxLength}). Shorten it to ${maxLength} characters or fewer. Normalized value: "${sanitized}".`
|
|
7633
|
-
);
|
|
7634
|
-
}
|
|
7635
|
-
return sanitized;
|
|
7636
|
-
}
|
|
7637
|
-
function normalizePlayName(value) {
|
|
7638
|
-
if (value.includes("/")) {
|
|
7639
|
-
throw new Error(
|
|
7640
|
-
'Play name cannot contain "/". Slash is reserved for qualified play references like "prebuilt/example" or "self/example".'
|
|
7641
|
-
);
|
|
7642
|
-
}
|
|
7643
|
-
return validateIdentifierPart(value, "Play name", PLAY_NAME_MAX_LENGTH);
|
|
7644
|
-
}
|
|
7645
|
-
function normalizePlayNameForSheet(value) {
|
|
7646
|
-
if (!value.includes("/")) {
|
|
7647
|
-
return normalizePlayName(value);
|
|
7648
|
-
}
|
|
7649
|
-
const digest = sha256Hex(value).slice(0, 12);
|
|
7650
|
-
const normalizedReference = sanitizeIdentifierPart(
|
|
7651
|
-
value.replace(/\//g, "__")
|
|
7652
|
-
);
|
|
7653
|
-
const prefixLength = Math.max(1, PLAY_NAME_MAX_LENGTH - digest.length - 1);
|
|
7654
|
-
const prefix = normalizedReference.slice(0, prefixLength).replace(/_+$/g, "") || "qualified_play";
|
|
7655
|
-
return `${prefix}_${digest}`;
|
|
7656
|
-
}
|
|
7657
|
-
function normalizeTableNamespace(value) {
|
|
7658
|
-
return validateIdentifierPart(
|
|
7659
|
-
value,
|
|
7660
|
-
"ctx.dataset() key",
|
|
7661
|
-
MAP_KEY_NAMESPACE_MAX_LENGTH
|
|
7662
|
-
);
|
|
7663
|
-
}
|
|
7664
|
-
function validatePlaySheetTableName(playName, tableNamespace) {
|
|
7665
|
-
const playSegment = normalizePlayNameForSheet(playName);
|
|
7666
|
-
const keySegment = normalizeTableNamespace(tableNamespace);
|
|
7667
|
-
const resolved = `${playSegment}_${keySegment}`;
|
|
7668
|
-
if (resolved.length > POSTGRES_IDENTIFIER_MAX_LENGTH) {
|
|
7669
|
-
throw new Error(
|
|
7670
|
-
`Play sheet table name is too long after normalization (${resolved.length}/63). Shorten the play name or ctx.dataset() key. Resolved table name: "${resolved}".`
|
|
7671
|
-
);
|
|
7672
|
-
}
|
|
7673
|
-
return resolved;
|
|
7674
|
-
}
|
|
7675
|
-
|
|
7676
7613
|
// src/cli/trace.ts
|
|
7677
7614
|
var cliTraceStartedAt = Date.now();
|
|
7678
7615
|
function isTruthyEnv(value) {
|
|
@@ -7723,6 +7660,11 @@ async function traceCliSpan(phase, fields, run) {
|
|
|
7723
7660
|
|
|
7724
7661
|
// src/cli/play-check-hints.ts
|
|
7725
7662
|
var EXTRACTED_GETTER_ERROR_HINT = "Deepline hint: extractedValues/extractedLists .get() only works for declared Deepline getters listed by `deepline tools describe <tool> --json`. Use `toolExecutionResult.toolResponse.raw` for provider/tool-specific fields.";
|
|
7663
|
+
var DATASET_API_HINT = "Deepline hint: PlayDataset is lazy and durable. Use `.peek(n)` for a small preview or `.materialize()` when you intentionally need rows in memory; do not use `.rows`, `.toArray()`, or array methods directly on the dataset handle.";
|
|
7664
|
+
var ROW_PROPERTY_HINT = "Deepline hint: this row type only contains fields produced by the CSV/schema and previous map steps. Check source column casing and the exact output field names from earlier steps before scaling.";
|
|
7665
|
+
var TOOLS_EXECUTE_SIGNATURE_HINT = "Deepline hint: ctx.tools.execute requires a request object: `ctx.tools.execute({ id, tool, input, description })`. The stable `id` is required for replay-safe receipts.";
|
|
7666
|
+
var RUN_PLAY_SIGNATURE_HINT = "Deepline hint: ctx.runPlay uses a stable key plus a composable child play reference. Direct-run-only or map-backed batch plays must be run directly, exported, then consumed by a separate play.";
|
|
7667
|
+
var MAP_BACKED_CHILD_HINT = "Deepline hint: map-backed child plays own durable table state and cannot be called from another play. Run that play directly, export its dataset, then pass the CSV to the next play.";
|
|
7726
7668
|
function sourceLineForError(sourceCode, error) {
|
|
7727
7669
|
const match = error.match(/:(\d+):(\d+)\s/);
|
|
7728
7670
|
const lineNumber = match?.[1] ? Number(match[1]) : NaN;
|
|
@@ -7733,16 +7675,61 @@ function looksLikeInvalidExtractedGetter(error, sourceLine) {
|
|
|
7733
7675
|
if (!/Property '[^']+' does not exist on type/.test(error)) return false;
|
|
7734
7676
|
return /\bextracted(?:Values|Lists)\s*\./.test(sourceLine);
|
|
7735
7677
|
}
|
|
7678
|
+
function looksLikeDatasetApiMisuse(error, sourceLine) {
|
|
7679
|
+
return /Property '(?:rows|toArray|forEach|map|filter|reduce)' does not exist on type '[^']*PlayDataset/.test(
|
|
7680
|
+
error
|
|
7681
|
+
) || /\b(?:\.rows|\.toArray\(\)|\.forEach\(|\.map\(|\.filter\(|\.reduce\()/.test(
|
|
7682
|
+
sourceLine
|
|
7683
|
+
);
|
|
7684
|
+
}
|
|
7685
|
+
function looksLikeRowPropertyMismatch(error, sourceLine) {
|
|
7686
|
+
if (!/Property '[^']+' does not exist on type/.test(error)) return false;
|
|
7687
|
+
if (looksLikeInvalidExtractedGetter(error, sourceLine)) return false;
|
|
7688
|
+
return /\brow\.[A-Za-z_][A-Za-z0-9_]*/.test(sourceLine);
|
|
7689
|
+
}
|
|
7690
|
+
function looksLikeToolsExecuteSignature(error, sourceLine) {
|
|
7691
|
+
return /ctx\.tools\.execute requires a request object/i.test(error) || /Expected 1 arguments?, but got [2-9]/.test(error) && /\btools\.execute\(/.test(sourceLine);
|
|
7692
|
+
}
|
|
7693
|
+
function looksLikeRunPlaySignature(error, sourceLine) {
|
|
7694
|
+
return /ctx\.runPlay/i.test(error) || /(?:Expected|Argument of type|No overload matches)/.test(error) && /\brunPlay\(/.test(sourceLine);
|
|
7695
|
+
}
|
|
7696
|
+
function looksLikeMapBackedChild(error) {
|
|
7697
|
+
return /map-backed child play|direct-run-only|cannot call a map-backed|own durable table/i.test(
|
|
7698
|
+
error
|
|
7699
|
+
);
|
|
7700
|
+
}
|
|
7701
|
+
function hintForError(error, sourceLine) {
|
|
7702
|
+
if (looksLikeInvalidExtractedGetter(error, sourceLine)) {
|
|
7703
|
+
return EXTRACTED_GETTER_ERROR_HINT;
|
|
7704
|
+
}
|
|
7705
|
+
if (looksLikeDatasetApiMisuse(error, sourceLine)) {
|
|
7706
|
+
return DATASET_API_HINT;
|
|
7707
|
+
}
|
|
7708
|
+
if (looksLikeToolsExecuteSignature(error, sourceLine)) {
|
|
7709
|
+
return TOOLS_EXECUTE_SIGNATURE_HINT;
|
|
7710
|
+
}
|
|
7711
|
+
if (looksLikeMapBackedChild(error)) {
|
|
7712
|
+
return MAP_BACKED_CHILD_HINT;
|
|
7713
|
+
}
|
|
7714
|
+
if (looksLikeRunPlaySignature(error, sourceLine)) {
|
|
7715
|
+
return RUN_PLAY_SIGNATURE_HINT;
|
|
7716
|
+
}
|
|
7717
|
+
if (looksLikeRowPropertyMismatch(error, sourceLine)) {
|
|
7718
|
+
return ROW_PROPERTY_HINT;
|
|
7719
|
+
}
|
|
7720
|
+
return null;
|
|
7721
|
+
}
|
|
7736
7722
|
function addPlayCheckRepairHints(input2) {
|
|
7737
|
-
|
|
7723
|
+
const addedHints = /* @__PURE__ */ new Set();
|
|
7738
7724
|
return input2.errors.map((error) => {
|
|
7739
7725
|
const line = sourceLineForError(input2.sourceCode, error);
|
|
7740
|
-
|
|
7726
|
+
const hint = hintForError(error, line);
|
|
7727
|
+
if (!hint || addedHints.has(hint) || error.includes(hint)) {
|
|
7741
7728
|
return error;
|
|
7742
7729
|
}
|
|
7743
|
-
|
|
7730
|
+
addedHints.add(hint);
|
|
7744
7731
|
return `${error}
|
|
7745
|
-
${
|
|
7732
|
+
${hint}`;
|
|
7746
7733
|
});
|
|
7747
7734
|
}
|
|
7748
7735
|
|
|
@@ -8299,8 +8286,6 @@ var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
|
8299
8286
|
"cancelled"
|
|
8300
8287
|
]);
|
|
8301
8288
|
var PLAY_START_TRANSIENT_RETRY_DELAYS_MS = [500, 1500];
|
|
8302
|
-
var PLAY_CUSTOMER_STORAGE_SCHEMA_NAME = "storage";
|
|
8303
|
-
var PLAY_INTERNAL_STEP_RECEIPT_TABLE = "_deepline_step_receipts";
|
|
8304
8289
|
function getEventPayload(event) {
|
|
8305
8290
|
return event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
8306
8291
|
}
|
|
@@ -8354,36 +8339,8 @@ function getLogLinesFromLiveEvent(event) {
|
|
|
8354
8339
|
const lines = getEventPayload(event).lines;
|
|
8355
8340
|
return Array.isArray(lines) ? lines.filter((line) => typeof line === "string") : [];
|
|
8356
8341
|
}
|
|
8357
|
-
function
|
|
8358
|
-
return `
|
|
8359
|
-
}
|
|
8360
|
-
function quoteSqlLiteral(value) {
|
|
8361
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
8362
|
-
}
|
|
8363
|
-
function buildDebugDbQueryCommand(sql) {
|
|
8364
|
-
return `deepline db query --sql ${shellSingleQuote(sql)} --max-rows 20 --json`;
|
|
8365
|
-
}
|
|
8366
|
-
function buildStepReceiptsDebugCommand(runId) {
|
|
8367
|
-
const table = `${quoteSqlIdentifier(
|
|
8368
|
-
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8369
|
-
)}.${quoteSqlIdentifier(PLAY_INTERNAL_STEP_RECEIPT_TABLE)}`;
|
|
8370
|
-
const sql = `select convert_from(k, 'UTF8') as receipt_key, case status when 0 then 'pending' when 1 then 'running' when 2 then 'completed' when 3 then 'failed' when 4 then 'skipped' else status::text end as status, output, error, updated_at from ${table} where run_id = ${quoteSqlLiteral(runId)} order by updated_at asc, receipt_key asc limit 20`;
|
|
8371
|
-
return buildDebugDbQueryCommand(sql);
|
|
8372
|
-
}
|
|
8373
|
-
function buildMapTableDebugCommand(input2) {
|
|
8374
|
-
try {
|
|
8375
|
-
const tableName = validatePlaySheetTableName(
|
|
8376
|
-
input2.playName,
|
|
8377
|
-
input2.tableNamespace
|
|
8378
|
-
);
|
|
8379
|
-
const table = `${quoteSqlIdentifier(
|
|
8380
|
-
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8381
|
-
)}.${quoteSqlIdentifier(tableName)}`;
|
|
8382
|
-
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(input2.runId)} limit 20`;
|
|
8383
|
-
return buildDebugDbQueryCommand(sql);
|
|
8384
|
-
} catch {
|
|
8385
|
-
return null;
|
|
8386
|
-
}
|
|
8342
|
+
function buildRunInspectCommand(runId) {
|
|
8343
|
+
return `deepline runs get ${runId} --full --json`;
|
|
8387
8344
|
}
|
|
8388
8345
|
function extractTableNamespaceFromLiveEvent(event) {
|
|
8389
8346
|
const payload = getEventPayload(event);
|
|
@@ -8408,7 +8365,7 @@ function emitLiveDebugTableHints(input2) {
|
|
|
8408
8365
|
if (!input2.state.emittedDebugKeys.has(receiptsKey)) {
|
|
8409
8366
|
input2.state.emittedDebugKeys.add(receiptsKey);
|
|
8410
8367
|
input2.progress.writeLine(
|
|
8411
|
-
`
|
|
8368
|
+
`Inspect run output: ${buildRunInspectCommand(input2.runId)}`,
|
|
8412
8369
|
process.stdout
|
|
8413
8370
|
);
|
|
8414
8371
|
}
|
|
@@ -8420,17 +8377,9 @@ function emitLiveDebugTableHints(input2) {
|
|
|
8420
8377
|
if (input2.state.emittedDebugKeys.has(tableKey)) {
|
|
8421
8378
|
return;
|
|
8422
8379
|
}
|
|
8423
|
-
const command = buildMapTableDebugCommand({
|
|
8424
|
-
playName: input2.playName,
|
|
8425
|
-
runId: input2.runId,
|
|
8426
|
-
tableNamespace
|
|
8427
|
-
});
|
|
8428
|
-
if (!command) {
|
|
8429
|
-
return;
|
|
8430
|
-
}
|
|
8431
8380
|
input2.state.emittedDebugKeys.add(tableKey);
|
|
8432
8381
|
input2.progress.writeLine(
|
|
8433
|
-
`
|
|
8382
|
+
`Possible map table ${tableNamespace}: created only after this ctx.map(...).run(...) executes. Inspect returned datasets with ${buildRunInspectCommand(input2.runId)}`,
|
|
8434
8383
|
process.stdout
|
|
8435
8384
|
);
|
|
8436
8385
|
}
|
|
@@ -8634,7 +8583,7 @@ async function waitForPlayCompletionByStream(input2) {
|
|
|
8634
8583
|
}
|
|
8635
8584
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8636
8585
|
throw new DeeplineError(
|
|
8637
|
-
`Play
|
|
8586
|
+
`Play watch stream ended before the run reached a terminal status. runId=${input2.workflowId}${phaseSuffix}. Inspect the current run with 'deepline runs get ${input2.workflowId} --full --json' or continue watching with 'deepline runs tail ${input2.workflowId}'.`,
|
|
8638
8587
|
void 0,
|
|
8639
8588
|
"PLAY_LIVE_STREAM_ENDED",
|
|
8640
8589
|
{
|
|
@@ -8795,7 +8744,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8795
8744
|
const reason = error instanceof Error ? error.message : String(error);
|
|
8796
8745
|
if (!input2.jsonOutput) {
|
|
8797
8746
|
process.stderr.write(
|
|
8798
|
-
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
|
|
8747
|
+
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to canonical run stream (${reason})
|
|
8799
8748
|
`
|
|
8800
8749
|
);
|
|
8801
8750
|
}
|
|
@@ -8832,7 +8781,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8832
8781
|
if (lastKnownWorkflowId) {
|
|
8833
8782
|
if (!input2.jsonOutput) {
|
|
8834
8783
|
input2.progress.writeLine(
|
|
8835
|
-
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
|
|
8784
|
+
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to canonical run stream`
|
|
8836
8785
|
);
|
|
8837
8786
|
}
|
|
8838
8787
|
recordCliTrace({
|
|
@@ -8862,7 +8811,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8862
8811
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8863
8812
|
const idSuffix = lastKnownWorkflowId ? ` runId=${lastKnownWorkflowId}` : "";
|
|
8864
8813
|
throw new DeeplineError(
|
|
8865
|
-
`Play start stream ended before
|
|
8814
|
+
`Play start stream ended before a terminal status was observed${idSuffix}${phaseSuffix}. If a run id was printed, inspect it with 'deepline runs get <run-id> --full --json' or continue watching with 'deepline runs tail <run-id>'.`,
|
|
8866
8815
|
void 0,
|
|
8867
8816
|
"PLAY_START_STREAM_ENDED",
|
|
8868
8817
|
{
|
|
@@ -9210,6 +9159,32 @@ function formatPlayErrorForDisplay(status, error) {
|
|
|
9210
9159
|
}
|
|
9211
9160
|
return error;
|
|
9212
9161
|
}
|
|
9162
|
+
function isGenericInternalServerError(error) {
|
|
9163
|
+
if (!error) return false;
|
|
9164
|
+
return /^(?:internalservererror|internal server error|http 500|500)$/i.test(
|
|
9165
|
+
error.trim()
|
|
9166
|
+
);
|
|
9167
|
+
}
|
|
9168
|
+
function selectRunErrorForDisplay(status) {
|
|
9169
|
+
const progressError = getStringField(status.progress, "error");
|
|
9170
|
+
if (!isGenericInternalServerError(progressError)) {
|
|
9171
|
+
return progressError;
|
|
9172
|
+
}
|
|
9173
|
+
const directErrors = getRecordField(status, "errors");
|
|
9174
|
+
if (Array.isArray(directErrors)) {
|
|
9175
|
+
for (const entry of directErrors) {
|
|
9176
|
+
const message = getStringField(entry, "message");
|
|
9177
|
+
if (message && !isGenericInternalServerError(message)) {
|
|
9178
|
+
return message;
|
|
9179
|
+
}
|
|
9180
|
+
}
|
|
9181
|
+
}
|
|
9182
|
+
const directError = getStringField(status, "error");
|
|
9183
|
+
if (directError && !isGenericInternalServerError(directError)) {
|
|
9184
|
+
return directError;
|
|
9185
|
+
}
|
|
9186
|
+
return progressError;
|
|
9187
|
+
}
|
|
9213
9188
|
function normalizeRunStatusForEnvelope(status) {
|
|
9214
9189
|
const run = status.run ?? null;
|
|
9215
9190
|
return {
|
|
@@ -9347,8 +9322,7 @@ function compactPlayStatus(status) {
|
|
|
9347
9322
|
const billing = status && typeof status === "object" ? stripProviderSpendFromBilling(
|
|
9348
9323
|
status.billing
|
|
9349
9324
|
) : null;
|
|
9350
|
-
const
|
|
9351
|
-
const error = typeof progressError === "string" ? progressError : typeof status.error === "string" ? String(status.error) : null;
|
|
9325
|
+
const error = selectRunErrorForDisplay(status) ?? (typeof status.error === "string" ? String(status.error) : null);
|
|
9352
9326
|
const displayError = formatPlayErrorForDisplay(status, error);
|
|
9353
9327
|
return {
|
|
9354
9328
|
runId: status.runId,
|
|
@@ -9603,8 +9577,8 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
9603
9577
|
for (const warning of warnings) {
|
|
9604
9578
|
lines.push(` warning: ${warning}`);
|
|
9605
9579
|
}
|
|
9606
|
-
const progressError = status
|
|
9607
|
-
if (progressError
|
|
9580
|
+
const progressError = selectRunErrorForDisplay(status);
|
|
9581
|
+
if (progressError) {
|
|
9608
9582
|
const billing = extractBillingForStatus(status, progressError);
|
|
9609
9583
|
if (isInsufficientCreditsBilling(billing)) {
|
|
9610
9584
|
lines.push(...buildInsufficientCreditsSummaryLines({ status, billing }));
|
|
@@ -9656,9 +9630,6 @@ var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
|
9656
9630
|
function shellSingleQuote(value) {
|
|
9657
9631
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
9658
9632
|
}
|
|
9659
|
-
function sqlStringLiteral(value) {
|
|
9660
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
9661
|
-
}
|
|
9662
9633
|
function runExportRetryCommand(runId, outPath, datasetPath) {
|
|
9663
9634
|
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0, import_node_path12.resolve)(outPath))}`;
|
|
9664
9635
|
}
|
|
@@ -9677,26 +9648,6 @@ function extractRunPlayName(status) {
|
|
|
9677
9648
|
}
|
|
9678
9649
|
return null;
|
|
9679
9650
|
}
|
|
9680
|
-
function normalizeCustomerDbIdentifier(value) {
|
|
9681
|
-
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
9682
|
-
}
|
|
9683
|
-
function buildCustomerDbQueryPlan(input2) {
|
|
9684
|
-
const playName = extractRunPlayName(input2.status);
|
|
9685
|
-
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9686
|
-
if (!playName || !tableNamespace || input2.rowsInfo.totalRows <= 0) {
|
|
9687
|
-
return null;
|
|
9688
|
-
}
|
|
9689
|
-
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
9690
|
-
tableNamespace
|
|
9691
|
-
)}`;
|
|
9692
|
-
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input2.status.runId)} limit ${input2.rowsInfo.totalRows}`;
|
|
9693
|
-
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input2.rowsInfo.totalRows}`;
|
|
9694
|
-
return {
|
|
9695
|
-
sql,
|
|
9696
|
-
json: `${base} --json`,
|
|
9697
|
-
csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path12.resolve)(input2.outPath))}`
|
|
9698
|
-
};
|
|
9699
|
-
}
|
|
9700
9651
|
function exportableSheetRow(row) {
|
|
9701
9652
|
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
9702
9653
|
return null;
|
|
@@ -10043,8 +9994,12 @@ function renderServerResultView(value) {
|
|
|
10043
9994
|
lines.push(
|
|
10044
9995
|
` ${String(table.tableNamespace ?? "table")}${lineLabel}: ${rowLabel}${details.join(" ")}`
|
|
10045
9996
|
);
|
|
10046
|
-
if (typeof table.queryDatasetCommand === "string") {
|
|
10047
|
-
lines.push(`
|
|
9997
|
+
if (typeof table.queryDatasetCommand === "string" && typeof table.rowCount === "number" && table.rowCount > 0) {
|
|
9998
|
+
lines.push(` debug backing table: ${table.queryDatasetCommand}`);
|
|
9999
|
+
} else if (typeof table.queryDatasetCommand === "string") {
|
|
10000
|
+
lines.push(
|
|
10001
|
+
" no rows observed for this run; backing table is created only if this map ran"
|
|
10002
|
+
);
|
|
10048
10003
|
}
|
|
10049
10004
|
if (table.debugHelp && typeof table.debugHelp === "object" && !Array.isArray(table.debugHelp)) {
|
|
10050
10005
|
const debugHelp = table.debugHelp;
|
|
@@ -10390,9 +10345,51 @@ function printToolGetterHints(hints) {
|
|
|
10390
10345
|
async function handlePlayCheck(args) {
|
|
10391
10346
|
const options = parsePlayCheckOptions(args);
|
|
10392
10347
|
if (!isFileTarget(options.target)) {
|
|
10393
|
-
const
|
|
10394
|
-
|
|
10395
|
-
|
|
10348
|
+
const client2 = new DeeplineClient();
|
|
10349
|
+
try {
|
|
10350
|
+
await assertCanonicalNamedPlayReference(client2, options.target);
|
|
10351
|
+
const play = await client2.describePlay(
|
|
10352
|
+
parseReferencedPlayTarget2(options.target).playName,
|
|
10353
|
+
{ compact: true }
|
|
10354
|
+
);
|
|
10355
|
+
const result2 = {
|
|
10356
|
+
valid: true,
|
|
10357
|
+
target: options.target,
|
|
10358
|
+
name: play.name,
|
|
10359
|
+
reference: play.reference ?? options.target,
|
|
10360
|
+
origin: play.origin ?? null,
|
|
10361
|
+
ownerType: play.ownerType ?? null,
|
|
10362
|
+
inputSchema: play.inputSchema ?? null,
|
|
10363
|
+
outputSchema: play.outputSchema ?? null,
|
|
10364
|
+
staticPipeline: play.staticPipeline ?? null,
|
|
10365
|
+
note: "Named/prebuilt play contract is available. No run was started."
|
|
10366
|
+
};
|
|
10367
|
+
if (options.jsonOutput) {
|
|
10368
|
+
process.stdout.write(`${JSON.stringify(result2)}
|
|
10369
|
+
`);
|
|
10370
|
+
} else {
|
|
10371
|
+
console.log(`\u2713 ${result2.reference} passed named play contract check`);
|
|
10372
|
+
console.log(" no run started; no Deepline credits spent");
|
|
10373
|
+
if (play.runCommand) console.log(` run: ${play.runCommand}`);
|
|
10374
|
+
}
|
|
10375
|
+
return 0;
|
|
10376
|
+
} catch (error) {
|
|
10377
|
+
const resolved = (0, import_node_path12.resolve)(options.target);
|
|
10378
|
+
const message = error instanceof Error && error.message ? error.message : `File not found: ${resolved}`;
|
|
10379
|
+
if (options.jsonOutput) {
|
|
10380
|
+
process.stdout.write(
|
|
10381
|
+
`${JSON.stringify({
|
|
10382
|
+
valid: false,
|
|
10383
|
+
target: options.target,
|
|
10384
|
+
errors: [message]
|
|
10385
|
+
})}
|
|
10386
|
+
`
|
|
10387
|
+
);
|
|
10388
|
+
} else {
|
|
10389
|
+
console.error(message);
|
|
10390
|
+
}
|
|
10391
|
+
return 1;
|
|
10392
|
+
}
|
|
10396
10393
|
}
|
|
10397
10394
|
const absolutePlayPath = (0, import_node_path12.resolve)(options.target);
|
|
10398
10395
|
const sourceCode = (0, import_node_fs10.readFileSync)(absolutePlayPath, "utf-8");
|
|
@@ -11039,18 +11036,9 @@ async function handleRunExport(args) {
|
|
|
11039
11036
|
datasetPath
|
|
11040
11037
|
});
|
|
11041
11038
|
const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
|
|
11042
|
-
const queryPlan = exportResult && outPath ? buildCustomerDbQueryPlan({
|
|
11043
|
-
status,
|
|
11044
|
-
rowsInfo: exportResult.rowsInfo,
|
|
11045
|
-
outPath
|
|
11046
|
-
}) : null;
|
|
11047
11039
|
const next = {
|
|
11048
11040
|
...buildRunNextCommands(status),
|
|
11049
|
-
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
|
|
11050
|
-
...queryPlan ? {
|
|
11051
|
-
queryJson: queryPlan.json,
|
|
11052
|
-
queryCsv: queryPlan.csv
|
|
11053
|
-
} : {}
|
|
11041
|
+
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
|
|
11054
11042
|
};
|
|
11055
11043
|
const payload = {
|
|
11056
11044
|
runId: status.runId,
|
|
@@ -11059,13 +11047,6 @@ async function handleRunExport(args) {
|
|
|
11059
11047
|
source,
|
|
11060
11048
|
rowCount: exportResult?.rowsInfo.totalRows ?? null,
|
|
11061
11049
|
columns: exportResult?.rowsInfo.columns ?? [],
|
|
11062
|
-
...queryPlan ? {
|
|
11063
|
-
query: {
|
|
11064
|
-
sql: queryPlan.sql,
|
|
11065
|
-
json: queryPlan.json,
|
|
11066
|
-
csv: queryPlan.csv
|
|
11067
|
-
}
|
|
11068
|
-
} : {},
|
|
11069
11050
|
...metadataOutPath ? { metadata_path: metadataOutPath } : {},
|
|
11070
11051
|
local: { csv_path: exportResult?.path ?? null },
|
|
11071
11052
|
next,
|
|
@@ -11075,8 +11056,7 @@ async function handleRunExport(args) {
|
|
|
11075
11056
|
title: "run export",
|
|
11076
11057
|
lines: [
|
|
11077
11058
|
`Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
|
|
11078
|
-
...source ? [`source=${source}`] : []
|
|
11079
|
-
...queryPlan ? [`query=${queryPlan.json}`] : []
|
|
11059
|
+
...source ? [`source=${source}`] : []
|
|
11080
11060
|
]
|
|
11081
11061
|
}
|
|
11082
11062
|
]
|
|
@@ -11256,7 +11236,8 @@ function parsePlaySearchOptions(args) {
|
|
|
11256
11236
|
return {
|
|
11257
11237
|
query,
|
|
11258
11238
|
jsonOutput: argsWantJson(args),
|
|
11259
|
-
compact: args.includes("--compact")
|
|
11239
|
+
compact: args.includes("--compact"),
|
|
11240
|
+
prebuiltOnly: args.includes("--prebuilt")
|
|
11260
11241
|
};
|
|
11261
11242
|
}
|
|
11262
11243
|
function printPlayDescription(play) {
|
|
@@ -11304,6 +11285,7 @@ function printPlayDescription(play) {
|
|
|
11304
11285
|
console.log(` ${line}`);
|
|
11305
11286
|
}
|
|
11306
11287
|
}
|
|
11288
|
+
console.log(` Describe: deepline plays describe ${reference} --json`);
|
|
11307
11289
|
console.log(` Run: ${play.runCommand}`);
|
|
11308
11290
|
const cloneEditStarter = play.cloneEditStarter ?? buildCloneEditStarter(play);
|
|
11309
11291
|
if (cloneEditStarter) {
|
|
@@ -11311,6 +11293,31 @@ function printPlayDescription(play) {
|
|
|
11311
11293
|
console.log(` Check starter: ${cloneEditStarter.checkCommand}`);
|
|
11312
11294
|
}
|
|
11313
11295
|
}
|
|
11296
|
+
function inputFieldNames(schema) {
|
|
11297
|
+
const fields = Array.isArray(schema?.fields) ? schema.fields : [];
|
|
11298
|
+
return fields.map(
|
|
11299
|
+
(field) => field && typeof field === "object" ? String(field.name ?? "").trim() : ""
|
|
11300
|
+
).filter(Boolean);
|
|
11301
|
+
}
|
|
11302
|
+
function printCompactPlaySearchResult(play) {
|
|
11303
|
+
const reference = formatPlayListReference(play);
|
|
11304
|
+
const aliases = play.aliases.slice(0, 6).join(", ");
|
|
11305
|
+
console.log(`Play: ${reference}`);
|
|
11306
|
+
if (play.displayName && play.displayName !== play.name) {
|
|
11307
|
+
console.log(` Display name: ${play.displayName}`);
|
|
11308
|
+
}
|
|
11309
|
+
if (aliases) {
|
|
11310
|
+
console.log(` Aliases: ${aliases}`);
|
|
11311
|
+
}
|
|
11312
|
+
const fields = inputFieldNames(play.inputSchema);
|
|
11313
|
+
if (fields.length > 0) {
|
|
11314
|
+
console.log(` Inputs: ${fields.join(", ")}`);
|
|
11315
|
+
} else if (play.inputSchema) {
|
|
11316
|
+
console.log(" Inputs: see describe");
|
|
11317
|
+
}
|
|
11318
|
+
console.log(` Describe: deepline plays describe ${reference} --json`);
|
|
11319
|
+
console.log(` Run: ${play.runCommand}`);
|
|
11320
|
+
}
|
|
11314
11321
|
function compactPlaySchema(schema) {
|
|
11315
11322
|
if (!schema) return null;
|
|
11316
11323
|
const fields = Array.isArray(schema.fields) ? schema.fields.map(
|
|
@@ -11374,22 +11381,44 @@ async function handlePlaySearch(args) {
|
|
|
11374
11381
|
return 1;
|
|
11375
11382
|
}
|
|
11376
11383
|
const client = new DeeplineClient();
|
|
11377
|
-
const plays = await client.searchPlays({
|
|
11384
|
+
const plays = (await client.searchPlays({
|
|
11378
11385
|
query: options.query,
|
|
11379
11386
|
compact: options.compact
|
|
11380
|
-
})
|
|
11387
|
+
})).filter(
|
|
11388
|
+
(play) => options.prebuiltOnly ? play.origin === "prebuilt" || play.ownerType === "deepline" : true
|
|
11389
|
+
);
|
|
11381
11390
|
if (options.jsonOutput) {
|
|
11382
|
-
|
|
11383
|
-
|
|
11391
|
+
const jsonPlays = options.prebuiltOnly ? plays.map((play) => ({
|
|
11392
|
+
...play,
|
|
11393
|
+
inputSchema: compactPlaySchema(play.inputSchema)
|
|
11394
|
+
})) : plays;
|
|
11395
|
+
process.stdout.write(
|
|
11396
|
+
`${JSON.stringify({
|
|
11397
|
+
plays: jsonPlays,
|
|
11398
|
+
total: jsonPlays.length,
|
|
11399
|
+
truncated: false
|
|
11400
|
+
})}
|
|
11401
|
+
`
|
|
11402
|
+
);
|
|
11384
11403
|
return 0;
|
|
11385
11404
|
}
|
|
11386
|
-
|
|
11405
|
+
const displayPlays = options.prebuiltOnly ? plays.slice(0, 5) : plays;
|
|
11406
|
+
process.stdout.write(
|
|
11407
|
+
`${plays.length} plays found${options.prebuiltOnly && plays.length > displayPlays.length ? `; showing top ${displayPlays.length}` : ""}:
|
|
11387
11408
|
|
|
11388
|
-
`
|
|
11389
|
-
|
|
11390
|
-
|
|
11409
|
+
`
|
|
11410
|
+
);
|
|
11411
|
+
for (const play of displayPlays) {
|
|
11412
|
+
if (options.prebuiltOnly) {
|
|
11413
|
+
printCompactPlaySearchResult(play);
|
|
11414
|
+
} else {
|
|
11415
|
+
printPlayDescription(play);
|
|
11416
|
+
}
|
|
11391
11417
|
console.log("");
|
|
11392
11418
|
}
|
|
11419
|
+
if (options.prebuiltOnly && plays.length > displayPlays.length) {
|
|
11420
|
+
console.log("Use --json for the full machine-readable result set.");
|
|
11421
|
+
}
|
|
11393
11422
|
return 0;
|
|
11394
11423
|
}
|
|
11395
11424
|
function normalizePlayGrepText(value) {
|
|
@@ -11656,15 +11685,18 @@ Common commands:
|
|
|
11656
11685
|
deepline plays get person-linkedin-to-email --json
|
|
11657
11686
|
`
|
|
11658
11687
|
);
|
|
11659
|
-
play.command("check <target>").description("
|
|
11688
|
+
play.command("check <target>").description("Check a local play file or named/prebuilt play contract.").addHelpText(
|
|
11660
11689
|
"after",
|
|
11661
11690
|
`
|
|
11662
11691
|
Notes:
|
|
11663
11692
|
Validates a local play without storing it, promoting it, or starting a run.
|
|
11664
11693
|
This uses the authoritative cloud preflight path.
|
|
11694
|
+
For named or prebuilt plays, validates that the contract is discoverable
|
|
11695
|
+
without starting a run or spending Deepline credits.
|
|
11665
11696
|
|
|
11666
11697
|
Examples:
|
|
11667
11698
|
deepline plays check my.play.ts
|
|
11699
|
+
deepline plays check prebuilt/name-and-domain-to-email-waterfall-batch
|
|
11668
11700
|
deepline plays check my.play.ts --json
|
|
11669
11701
|
`
|
|
11670
11702
|
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
|
|
@@ -11814,11 +11846,13 @@ Examples:
|
|
|
11814
11846
|
...options.json ? ["--json"] : []
|
|
11815
11847
|
]);
|
|
11816
11848
|
});
|
|
11817
|
-
const addPlaySearchCommand = (command) => command.description("Search saved and prebuilt plays.").addHelpText(
|
|
11849
|
+
const addPlaySearchCommand = (command) => command.description("Search saved and prebuilt plays.").option("--prebuilt", "Only show Deepline-managed prebuilt plays").addHelpText(
|
|
11818
11850
|
"after",
|
|
11819
11851
|
`
|
|
11820
11852
|
Notes:
|
|
11821
11853
|
Ranked discovery for workflows. Use describe on a result before running it.
|
|
11854
|
+
Prefer --prebuilt for new GTM tasks so old workspace scratchpads do not
|
|
11855
|
+
outrank Deepline-managed routes unless the user names one explicitly.
|
|
11822
11856
|
The grep alias is the same ranked retrieval surface with a more literal name
|
|
11823
11857
|
for agents that are filtering the play registry.
|
|
11824
11858
|
|
|
@@ -11830,6 +11864,7 @@ Examples:
|
|
|
11830
11864
|
).option("--compact", "Emit compact schemas").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
11831
11865
|
process.exitCode = await handlePlaySearch([
|
|
11832
11866
|
query,
|
|
11867
|
+
...options.prebuilt ? ["--prebuilt"] : [],
|
|
11833
11868
|
...options.compact ? ["--compact"] : [],
|
|
11834
11869
|
...options.json ? ["--json"] : []
|
|
11835
11870
|
]);
|
|
@@ -12077,7 +12112,7 @@ Notes:
|
|
|
12077
12112
|
Writes a returned dataset handle to the requested local CSV path. Use runs get
|
|
12078
12113
|
first to inspect dataset paths like result.rows or result.nested.contacts.
|
|
12079
12114
|
--metadata-out writes the same export metadata object returned by --json,
|
|
12080
|
-
including source
|
|
12115
|
+
including the source dataset path and row/column metadata.
|
|
12081
12116
|
|
|
12082
12117
|
Examples:
|
|
12083
12118
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
@@ -14008,7 +14043,7 @@ async function listTools(args) {
|
|
|
14008
14043
|
const client = new DeeplineClient();
|
|
14009
14044
|
const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
|
|
14010
14045
|
const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
|
|
14011
|
-
const compact = args.includes("--compact");
|
|
14046
|
+
const compact = args.includes("--compact") || !args.includes("--json");
|
|
14012
14047
|
const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
14013
14048
|
const items = (await client.listTools({
|
|
14014
14049
|
...categoryFilter ? { categories: categoryFilter } : {}
|
|
@@ -14064,9 +14099,10 @@ async function searchTools(queryInput, options = {}) {
|
|
|
14064
14099
|
searchMode: options.searchMode,
|
|
14065
14100
|
includeSearchDebug: options.includeSearchDebug
|
|
14066
14101
|
});
|
|
14067
|
-
const
|
|
14102
|
+
const shouldCompact = options.compact || !options.json;
|
|
14103
|
+
const payload = shouldCompact && Array.isArray(result.tools) ? {
|
|
14068
14104
|
...result,
|
|
14069
|
-
tools: result.tools.map(compactTool)
|
|
14105
|
+
tools: result.tools.slice(0, 8).map(compactTool)
|
|
14070
14106
|
} : result;
|
|
14071
14107
|
printCommandEnvelope(payload, {
|
|
14072
14108
|
json: options.json || shouldEmitJson()
|
|
@@ -14107,7 +14143,8 @@ async function grepTools(queryInput, options = {}) {
|
|
|
14107
14143
|
mode
|
|
14108
14144
|
)
|
|
14109
14145
|
);
|
|
14110
|
-
const
|
|
14146
|
+
const shouldCompact = options.compact || !options.json;
|
|
14147
|
+
const outputTools = shouldCompact ? tools.slice(0, 8).map(compactTool) : tools;
|
|
14111
14148
|
printCommandEnvelope(
|
|
14112
14149
|
{
|
|
14113
14150
|
tools: outputTools,
|
|
@@ -14126,11 +14163,19 @@ async function grepTools(queryInput, options = {}) {
|
|
|
14126
14163
|
);
|
|
14127
14164
|
return 0;
|
|
14128
14165
|
}
|
|
14166
|
+
function numericToolField(tool, field) {
|
|
14167
|
+
const value = tool[field];
|
|
14168
|
+
return typeof value === "number" ? value : void 0;
|
|
14169
|
+
}
|
|
14129
14170
|
function compactTool(tool) {
|
|
14130
14171
|
const listed = toListedTool(tool);
|
|
14172
|
+
const searchScore = numericToolField(tool, "searchScore");
|
|
14173
|
+
const search_score = numericToolField(tool, "search_score");
|
|
14131
14174
|
return {
|
|
14132
14175
|
id: listed.id,
|
|
14133
14176
|
toolId: listed.toolId,
|
|
14177
|
+
...search_score !== void 0 ? { search_score } : {},
|
|
14178
|
+
...searchScore !== void 0 ? { searchScore } : {},
|
|
14134
14179
|
provider: listed.provider,
|
|
14135
14180
|
displayName: listed.displayName,
|
|
14136
14181
|
description: listed.description,
|
|
@@ -14451,7 +14496,7 @@ async function getTool(toolId, options = {}) {
|
|
|
14451
14496
|
}
|
|
14452
14497
|
if (shouldEmitJson()) {
|
|
14453
14498
|
process.stdout.write(
|
|
14454
|
-
`${JSON.stringify(
|
|
14499
|
+
`${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
|
|
14455
14500
|
`
|
|
14456
14501
|
);
|
|
14457
14502
|
return 0;
|
|
@@ -14776,8 +14821,8 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
|
14776
14821
|
invalidGetterHint: "If TypeScript says an extractedValues/extractedLists property does not exist, that field is not a declared Deepline getter.",
|
|
14777
14822
|
observeActualShape: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
14778
14823
|
observedOutput: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
14779
|
-
forPlayGetterBugs: "Run
|
|
14780
|
-
executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run
|
|
14824
|
+
forPlayGetterBugs: "Run a tiny play, inspect `deepline runs get <run-id> --full --json`, and export returned dataset handles with `deepline runs export`. Backing tables exist only for ctx.map(...).run(...) stages that actually executed.",
|
|
14825
|
+
executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run output and returned dataset handles."
|
|
14781
14826
|
},
|
|
14782
14827
|
starterScript: {
|
|
14783
14828
|
path: starterScript.path,
|
|
@@ -15794,6 +15839,7 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
15794
15839
|
}
|
|
15795
15840
|
|
|
15796
15841
|
// src/cli/index.ts
|
|
15842
|
+
var PREFLIGHT_TIMEOUT_MS = 3e3;
|
|
15797
15843
|
function asCommanderError(error) {
|
|
15798
15844
|
if (!(error instanceof Error) || !("code" in error)) {
|
|
15799
15845
|
return null;
|
|
@@ -15874,6 +15920,124 @@ async function runPlayRunnerHealthCheck() {
|
|
|
15874
15920
|
await (0, import_promises6.rm)(dir, { recursive: true, force: true });
|
|
15875
15921
|
}
|
|
15876
15922
|
}
|
|
15923
|
+
function pickString(value, ...keys) {
|
|
15924
|
+
for (const key of keys) {
|
|
15925
|
+
const candidate = value[key];
|
|
15926
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
15927
|
+
return candidate;
|
|
15928
|
+
}
|
|
15929
|
+
}
|
|
15930
|
+
return null;
|
|
15931
|
+
}
|
|
15932
|
+
function preflightErrorMessage(error) {
|
|
15933
|
+
return error instanceof Error ? error.message : String(error);
|
|
15934
|
+
}
|
|
15935
|
+
async function runPreflightCheck() {
|
|
15936
|
+
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
15937
|
+
const healthController = new AbortController();
|
|
15938
|
+
const healthTimeout = setTimeout(
|
|
15939
|
+
() => healthController.abort(),
|
|
15940
|
+
PREFLIGHT_TIMEOUT_MS
|
|
15941
|
+
);
|
|
15942
|
+
const health = await fetch(new URL("/api/v2/health", baseUrl), {
|
|
15943
|
+
signal: healthController.signal
|
|
15944
|
+
}).then(async (response) => {
|
|
15945
|
+
const payload = await response.json().catch(() => ({}));
|
|
15946
|
+
return {
|
|
15947
|
+
status: response.ok ? pickString(payload, "status") ?? "ok" : "unreachable",
|
|
15948
|
+
version: pickString(payload, "version")
|
|
15949
|
+
};
|
|
15950
|
+
}).catch(() => ({ status: "unreachable", version: null })).finally(() => clearTimeout(healthTimeout));
|
|
15951
|
+
const apiKey = resolveApiKeyForBaseUrl(baseUrl);
|
|
15952
|
+
const http = apiKey ? new HttpClient(
|
|
15953
|
+
resolveConfig({
|
|
15954
|
+
baseUrl,
|
|
15955
|
+
apiKey,
|
|
15956
|
+
timeout: PREFLIGHT_TIMEOUT_MS,
|
|
15957
|
+
maxRetries: 0
|
|
15958
|
+
})
|
|
15959
|
+
) : null;
|
|
15960
|
+
const [auth, billing] = http ? await Promise.all([
|
|
15961
|
+
http.post("/api/v2/auth/cli/status", {
|
|
15962
|
+
api_key: apiKey,
|
|
15963
|
+
reveal: false
|
|
15964
|
+
}).catch((error) => ({
|
|
15965
|
+
status: "not_connected",
|
|
15966
|
+
connected: false,
|
|
15967
|
+
error: preflightErrorMessage(error)
|
|
15968
|
+
})),
|
|
15969
|
+
http.get("/api/v2/billing/balance").catch(
|
|
15970
|
+
(error) => ({
|
|
15971
|
+
balance: null,
|
|
15972
|
+
balance_display: "unavailable",
|
|
15973
|
+
balance_status: "unknown",
|
|
15974
|
+
error: preflightErrorMessage(error)
|
|
15975
|
+
})
|
|
15976
|
+
)
|
|
15977
|
+
]) : [
|
|
15978
|
+
{
|
|
15979
|
+
status: "not_connected",
|
|
15980
|
+
connected: false,
|
|
15981
|
+
error: "No API key found. Run: deepline auth register"
|
|
15982
|
+
},
|
|
15983
|
+
{
|
|
15984
|
+
balance: null,
|
|
15985
|
+
balance_display: "unavailable until authenticated",
|
|
15986
|
+
balance_status: "unknown"
|
|
15987
|
+
}
|
|
15988
|
+
];
|
|
15989
|
+
const authStatus = pickString(auth, "status") ?? "unknown";
|
|
15990
|
+
const billingRecord = billing;
|
|
15991
|
+
const balanceDisplay = pickString(billing, "balance_display", "balanceDisplay") ?? `${String(billingRecord.balance ?? 0)} Deepline Credits`;
|
|
15992
|
+
const balanceStatus = pickString(billing, "balance_status", "balanceStatus") ?? "unknown";
|
|
15993
|
+
return {
|
|
15994
|
+
status: health.status === "ok" && (authStatus === "connected" || authStatus === "claimed") ? "ok" : "check",
|
|
15995
|
+
host: baseUrl,
|
|
15996
|
+
health: {
|
|
15997
|
+
status: health.status,
|
|
15998
|
+
version: health.version ?? null
|
|
15999
|
+
},
|
|
16000
|
+
auth: {
|
|
16001
|
+
status: authStatus,
|
|
16002
|
+
connected: authStatus === "connected" || authStatus === "claimed",
|
|
16003
|
+
org_id: pickString(auth, "org_id", "orgId"),
|
|
16004
|
+
org_name: pickString(auth, "org_name", "orgName"),
|
|
16005
|
+
rate_limit_tier: pickString(auth, "rate_limit_tier", "rateLimitTier"),
|
|
16006
|
+
error: pickString(auth, "error")
|
|
16007
|
+
},
|
|
16008
|
+
billing: {
|
|
16009
|
+
balance: billingRecord.balance ?? null,
|
|
16010
|
+
balance_display: balanceDisplay,
|
|
16011
|
+
rough_usd_balance: billingRecord.rough_usd_balance ?? billingRecord.roughUsdBalance ?? null,
|
|
16012
|
+
balance_status: balanceStatus,
|
|
16013
|
+
error: pickString(billing, "error")
|
|
16014
|
+
},
|
|
16015
|
+
render: {
|
|
16016
|
+
sections: [
|
|
16017
|
+
{
|
|
16018
|
+
title: "preflight",
|
|
16019
|
+
lines: [
|
|
16020
|
+
`host: ${baseUrl}`,
|
|
16021
|
+
`health: ${health.status}`,
|
|
16022
|
+
`auth: ${authStatus}`,
|
|
16023
|
+
`billing: ${balanceDisplay} (${balanceStatus})`
|
|
16024
|
+
]
|
|
16025
|
+
}
|
|
16026
|
+
]
|
|
16027
|
+
}
|
|
16028
|
+
};
|
|
16029
|
+
}
|
|
16030
|
+
function printPreflightHuman(data) {
|
|
16031
|
+
const render = data.render;
|
|
16032
|
+
const lines = render?.sections?.flatMap((section) => section.lines ?? []);
|
|
16033
|
+
if (lines?.length) {
|
|
16034
|
+
process.stdout.write(`${lines.join("\n")}
|
|
16035
|
+
`);
|
|
16036
|
+
return;
|
|
16037
|
+
}
|
|
16038
|
+
process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
16039
|
+
`);
|
|
16040
|
+
}
|
|
15877
16041
|
async function main() {
|
|
15878
16042
|
const mainStartedAt = Date.now();
|
|
15879
16043
|
recordCliTrace({
|
|
@@ -15890,6 +16054,7 @@ async function main() {
|
|
|
15890
16054
|
"after",
|
|
15891
16055
|
`
|
|
15892
16056
|
Common commands:
|
|
16057
|
+
deepline preflight
|
|
15893
16058
|
deepline health
|
|
15894
16059
|
deepline auth status --json
|
|
15895
16060
|
deepline plays search email --json
|
|
@@ -15911,7 +16076,6 @@ Output:
|
|
|
15911
16076
|
|
|
15912
16077
|
Safety:
|
|
15913
16078
|
Commands that mutate state, open a browser, write files, stop work, or spend credits say so in their help.
|
|
15914
|
-
Use --no-open where available for CI and agent runs.
|
|
15915
16079
|
|
|
15916
16080
|
Exit codes:
|
|
15917
16081
|
0 success; 2 usage/local input error; 3 auth/permission error; 4 not found;
|
|
@@ -15953,6 +16117,26 @@ Exit codes:
|
|
|
15953
16117
|
registerDbCommands(program);
|
|
15954
16118
|
registerFeedbackCommands(program);
|
|
15955
16119
|
registerUpdateCommand(program);
|
|
16120
|
+
program.command("preflight").description("Run compact health, auth, and Deepline billing checks.").option("--json", "Force JSON output.").addHelpText(
|
|
16121
|
+
"after",
|
|
16122
|
+
`
|
|
16123
|
+
Notes:
|
|
16124
|
+
Read-only setup check for the configured Deepline host. Shows server health,
|
|
16125
|
+
auth connection, and customer-visible Deepline balance in one compact command.
|
|
16126
|
+
|
|
16127
|
+
Examples:
|
|
16128
|
+
deepline preflight
|
|
16129
|
+
deepline preflight --json
|
|
16130
|
+
`
|
|
16131
|
+
).action(async (options) => {
|
|
16132
|
+
const data = await runPreflightCheck();
|
|
16133
|
+
if (shouldEmitJson(options.json)) {
|
|
16134
|
+
process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
16135
|
+
`);
|
|
16136
|
+
} else {
|
|
16137
|
+
printPreflightHuman(data);
|
|
16138
|
+
}
|
|
16139
|
+
});
|
|
15956
16140
|
program.command("health").description("Check server health.").option("--json", "Force JSON output.").option(
|
|
15957
16141
|
"--play-runner",
|
|
15958
16142
|
"Run a tiny no-provider play to verify the full play execution plane."
|