deepline 0.1.77 → 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 +524 -349
- package/dist/cli/index.mjs +537 -362
- package/dist/index.d.mts +8 -2
- package/dist/index.d.ts +8 -2
- package/dist/index.js +3 -2
- package/dist/index.mjs +3 -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/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,
|
|
@@ -6082,19 +6134,19 @@ function playBootstrapTemplateConfig(template) {
|
|
|
6082
6134
|
function templateExample(template) {
|
|
6083
6135
|
switch (template) {
|
|
6084
6136
|
case "people-list":
|
|
6085
|
-
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";
|
|
6086
6138
|
case "company-list":
|
|
6087
|
-
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";
|
|
6088
6140
|
case "people-email":
|
|
6089
|
-
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";
|
|
6090
6142
|
case "people-phone":
|
|
6091
|
-
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";
|
|
6092
6144
|
case "company-people":
|
|
6093
|
-
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";
|
|
6094
6146
|
case "company-people-email":
|
|
6095
|
-
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";
|
|
6096
6148
|
case "company-people-phone":
|
|
6097
|
-
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";
|
|
6098
6150
|
}
|
|
6099
6151
|
}
|
|
6100
6152
|
var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
@@ -6103,19 +6155,22 @@ var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
|
6103
6155
|
"phone"
|
|
6104
6156
|
];
|
|
6105
6157
|
function playBootstrapUsageLine() {
|
|
6106
|
-
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]`;
|
|
6107
6159
|
}
|
|
6108
6160
|
function requireBootstrapTemplate(rawTemplate) {
|
|
6109
6161
|
if (!rawTemplate) {
|
|
6110
6162
|
throw new PlayBootstrapUsageError(
|
|
6111
6163
|
`plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}.
|
|
6112
|
-
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`
|
|
6113
6165
|
);
|
|
6114
6166
|
}
|
|
6115
6167
|
if (!isPlayBootstrapTemplate(rawTemplate)) {
|
|
6168
|
+
const looksLikePlayReference = rawTemplate.includes("/") || rawTemplate.endsWith(".play.ts");
|
|
6116
6169
|
throw new PlayBootstrapUsageError(
|
|
6117
6170
|
`Unknown plays bootstrap template: ${rawTemplate}
|
|
6118
|
-
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.` : "")
|
|
6119
6174
|
);
|
|
6120
6175
|
}
|
|
6121
6176
|
return rawTemplate;
|
|
@@ -6257,7 +6312,8 @@ function parsePlayBootstrapOptions(args) {
|
|
|
6257
6312
|
people: null,
|
|
6258
6313
|
email: null,
|
|
6259
6314
|
phone: null,
|
|
6260
|
-
limit: 5
|
|
6315
|
+
limit: 5,
|
|
6316
|
+
out: null
|
|
6261
6317
|
};
|
|
6262
6318
|
for (let index = 0; index < rest.length; index += 1) {
|
|
6263
6319
|
const arg = rest[index];
|
|
@@ -6291,6 +6347,10 @@ function parsePlayBootstrapOptions(args) {
|
|
|
6291
6347
|
options.limit = parsePositiveInteger2(value(), "--limit");
|
|
6292
6348
|
index += 1;
|
|
6293
6349
|
break;
|
|
6350
|
+
case "--out":
|
|
6351
|
+
options.out = value();
|
|
6352
|
+
index += 1;
|
|
6353
|
+
break;
|
|
6294
6354
|
default:
|
|
6295
6355
|
throw new PlayBootstrapUsageError(
|
|
6296
6356
|
`Unknown plays bootstrap option: ${arg}
|
|
@@ -6408,7 +6468,7 @@ function packagedCsvPathForPlay(csvPath) {
|
|
|
6408
6468
|
const relativePath = (0, import_node_path11.relative)(playDir, absoluteCsvPath);
|
|
6409
6469
|
if (relativePath === "" || relativePath.startsWith("..") || (0, import_node_path11.isAbsolute)(relativePath)) {
|
|
6410
6470
|
throw new PlayBootstrapUsageError(
|
|
6411
|
-
`--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.`
|
|
6412
6472
|
);
|
|
6413
6473
|
}
|
|
6414
6474
|
const portablePath = relativePath.split("\\").join("/");
|
|
@@ -6815,8 +6875,18 @@ function validateBootstrapRoutes(input2) {
|
|
|
6815
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."
|
|
6816
6876
|
);
|
|
6817
6877
|
}
|
|
6878
|
+
assertComposablePlayRoute({
|
|
6879
|
+
stageLabel: "--people",
|
|
6880
|
+
playRef: stagePlayRef(input2.options.people),
|
|
6881
|
+
play: input2.peoplePlay
|
|
6882
|
+
});
|
|
6818
6883
|
for (const finder of ["email_finder", "phone_finder"]) {
|
|
6819
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
|
+
});
|
|
6820
6890
|
for (const tool of input2.finderTools[finder] ?? []) {
|
|
6821
6891
|
if (!tool.categories.includes(requiredCategory)) {
|
|
6822
6892
|
throw new PlayBootstrapValidationError(
|
|
@@ -6831,6 +6901,38 @@ function validateBootstrapRoutes(input2) {
|
|
|
6831
6901
|
}
|
|
6832
6902
|
}
|
|
6833
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
|
+
}
|
|
6834
6936
|
function sourceCollectionName(entity) {
|
|
6835
6937
|
switch (entity) {
|
|
6836
6938
|
case "company":
|
|
@@ -6860,6 +6962,22 @@ function generateCsvSourceRowsBlock(input2) {
|
|
|
6860
6962
|
const ${input2.collection}: ${input2.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
6861
6963
|
}
|
|
6862
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
|
+
}
|
|
6863
6981
|
const playInput = generatePlayInputObject({
|
|
6864
6982
|
schema: input2.sourcePlay?.inputSchema,
|
|
6865
6983
|
indent: " ",
|
|
@@ -7144,6 +7262,7 @@ ${typeDefinitions}
|
|
|
7144
7262
|
|
|
7145
7263
|
type Input = {
|
|
7146
7264
|
limit?: number;
|
|
7265
|
+
sourceCsv?: string;
|
|
7147
7266
|
};
|
|
7148
7267
|
|
|
7149
7268
|
export default definePlay(${jsString(input2.options.name)}, async (ctx, input: Input = {}) => {
|
|
@@ -7210,6 +7329,7 @@ async function loadBootstrapContracts(client, options) {
|
|
|
7210
7329
|
validateBootstrapRoutes({
|
|
7211
7330
|
options,
|
|
7212
7331
|
sourceTools: contracts.sourceTools,
|
|
7332
|
+
sourcePlay: contracts.sourcePlay,
|
|
7213
7333
|
peoplePlay: contracts.peoplePlay,
|
|
7214
7334
|
finderTools: contracts.finderTools,
|
|
7215
7335
|
finderPlays: contracts.finderPlays
|
|
@@ -7231,11 +7351,11 @@ function loadCsvContext(source) {
|
|
|
7231
7351
|
};
|
|
7232
7352
|
}
|
|
7233
7353
|
}
|
|
7234
|
-
function
|
|
7354
|
+
function errorMessage2(error) {
|
|
7235
7355
|
return error instanceof Error ? error.message : String(error);
|
|
7236
7356
|
}
|
|
7237
7357
|
function renderPlayBootstrapError(error) {
|
|
7238
|
-
console.error(
|
|
7358
|
+
console.error(errorMessage2(error));
|
|
7239
7359
|
return error instanceof PlayBootstrapError ? error.exitCode : 1;
|
|
7240
7360
|
}
|
|
7241
7361
|
async function runPlayBootstrap(args) {
|
|
@@ -7248,6 +7368,12 @@ async function runPlayBootstrap(args) {
|
|
|
7248
7368
|
...contracts,
|
|
7249
7369
|
...csvContext
|
|
7250
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
|
+
}
|
|
7251
7377
|
process.stdout.write(source);
|
|
7252
7378
|
return 0;
|
|
7253
7379
|
}
|
|
@@ -7260,7 +7386,7 @@ function registerPlayBootstrapCommand(play) {
|
|
|
7260
7386
|
`
|
|
7261
7387
|
Notes:
|
|
7262
7388
|
Cloud-validated play generator for agents. Pick the JTBD as the positional
|
|
7263
|
-
template, bind resources with typed refs,
|
|
7389
|
+
template, bind resources with typed refs, write the .play.ts file with --out,
|
|
7264
7390
|
then edit the generated TODO mapping comments. Multiple finder providers are
|
|
7265
7391
|
generated as a waterfall in the order you pass them.
|
|
7266
7392
|
|
|
@@ -7268,9 +7394,8 @@ Notes:
|
|
|
7268
7394
|
Deepline. It prints TypeScript source only and does not run paid tools; the
|
|
7269
7395
|
generated play may spend credits later when you run it.
|
|
7270
7396
|
|
|
7271
|
-
stdout is the generated .play.ts source.
|
|
7272
|
-
|
|
7273
|
-
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.
|
|
7274
7399
|
|
|
7275
7400
|
Templates:
|
|
7276
7401
|
people-list start from people/contact rows
|
|
@@ -7294,7 +7419,7 @@ Notes:
|
|
|
7294
7419
|
email/phone finder providers must match their category and expose value getters
|
|
7295
7420
|
finder plays/providers must match the route; generated code leaves input mapping explicit
|
|
7296
7421
|
business-specific provider inputs and company -> people persona fields are TODOs in code
|
|
7297
|
-
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
|
|
7298
7423
|
|
|
7299
7424
|
Exit codes:
|
|
7300
7425
|
0 success
|
|
@@ -7302,13 +7427,13 @@ Notes:
|
|
|
7302
7427
|
7 route validation failed
|
|
7303
7428
|
|
|
7304
7429
|
Examples:
|
|
7305
|
-
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
|
|
7306
7431
|
deepline plays check email-flow.play.ts
|
|
7307
7432
|
deepline plays run email-flow.play.ts --input '{"limit":5}' --watch
|
|
7308
7433
|
|
|
7309
|
-
deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5
|
|
7310
|
-
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
|
|
7311
|
-
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
|
|
7312
7437
|
`
|
|
7313
7438
|
).option("--name <name>", "Generated play name").option(
|
|
7314
7439
|
"--from <ref>",
|
|
@@ -7325,7 +7450,7 @@ Examples:
|
|
|
7325
7450
|
).option(
|
|
7326
7451
|
"--phone <ref>",
|
|
7327
7452
|
"Phone finder stage: play:REF, provider:ID, or providers:ID,ID"
|
|
7328
|
-
).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) => {
|
|
7329
7454
|
process.exitCode = await handlePlayBootstrap([
|
|
7330
7455
|
template,
|
|
7331
7456
|
...options.name ? ["--name", options.name] : [],
|
|
@@ -7334,7 +7459,8 @@ Examples:
|
|
|
7334
7459
|
...options.people ? ["--people", options.people] : [],
|
|
7335
7460
|
...options.email ? ["--email", options.email] : [],
|
|
7336
7461
|
...options.phone ? ["--phone", options.phone] : [],
|
|
7337
|
-
...options.limit ? ["--limit", options.limit] : []
|
|
7462
|
+
...options.limit ? ["--limit", options.limit] : [],
|
|
7463
|
+
...options.out ? ["--out", options.out] : []
|
|
7338
7464
|
]);
|
|
7339
7465
|
});
|
|
7340
7466
|
}
|
|
@@ -7484,204 +7610,6 @@ function createCliProgress(enabled) {
|
|
|
7484
7610
|
return progress;
|
|
7485
7611
|
}
|
|
7486
7612
|
|
|
7487
|
-
// ../shared_libs/plays/row-identity.ts
|
|
7488
|
-
var POSTGRES_IDENTIFIER_MAX_LENGTH = 63;
|
|
7489
|
-
var PLAY_NAME_MAX_LENGTH = POSTGRES_IDENTIFIER_MAX_LENGTH;
|
|
7490
|
-
var MAP_KEY_NAMESPACE_MAX_LENGTH = POSTGRES_IDENTIFIER_MAX_LENGTH;
|
|
7491
|
-
var SHA256_INITIAL_HASH = [
|
|
7492
|
-
1779033703,
|
|
7493
|
-
3144134277,
|
|
7494
|
-
1013904242,
|
|
7495
|
-
2773480762,
|
|
7496
|
-
1359893119,
|
|
7497
|
-
2600822924,
|
|
7498
|
-
528734635,
|
|
7499
|
-
1541459225
|
|
7500
|
-
];
|
|
7501
|
-
var SHA256_ROUND_CONSTANTS = [
|
|
7502
|
-
1116352408,
|
|
7503
|
-
1899447441,
|
|
7504
|
-
3049323471,
|
|
7505
|
-
3921009573,
|
|
7506
|
-
961987163,
|
|
7507
|
-
1508970993,
|
|
7508
|
-
2453635748,
|
|
7509
|
-
2870763221,
|
|
7510
|
-
3624381080,
|
|
7511
|
-
310598401,
|
|
7512
|
-
607225278,
|
|
7513
|
-
1426881987,
|
|
7514
|
-
1925078388,
|
|
7515
|
-
2162078206,
|
|
7516
|
-
2614888103,
|
|
7517
|
-
3248222580,
|
|
7518
|
-
3835390401,
|
|
7519
|
-
4022224774,
|
|
7520
|
-
264347078,
|
|
7521
|
-
604807628,
|
|
7522
|
-
770255983,
|
|
7523
|
-
1249150122,
|
|
7524
|
-
1555081692,
|
|
7525
|
-
1996064986,
|
|
7526
|
-
2554220882,
|
|
7527
|
-
2821834349,
|
|
7528
|
-
2952996808,
|
|
7529
|
-
3210313671,
|
|
7530
|
-
3336571891,
|
|
7531
|
-
3584528711,
|
|
7532
|
-
113926993,
|
|
7533
|
-
338241895,
|
|
7534
|
-
666307205,
|
|
7535
|
-
773529912,
|
|
7536
|
-
1294757372,
|
|
7537
|
-
1396182291,
|
|
7538
|
-
1695183700,
|
|
7539
|
-
1986661051,
|
|
7540
|
-
2177026350,
|
|
7541
|
-
2456956037,
|
|
7542
|
-
2730485921,
|
|
7543
|
-
2820302411,
|
|
7544
|
-
3259730800,
|
|
7545
|
-
3345764771,
|
|
7546
|
-
3516065817,
|
|
7547
|
-
3600352804,
|
|
7548
|
-
4094571909,
|
|
7549
|
-
275423344,
|
|
7550
|
-
430227734,
|
|
7551
|
-
506948616,
|
|
7552
|
-
659060556,
|
|
7553
|
-
883997877,
|
|
7554
|
-
958139571,
|
|
7555
|
-
1322822218,
|
|
7556
|
-
1537002063,
|
|
7557
|
-
1747873779,
|
|
7558
|
-
1955562222,
|
|
7559
|
-
2024104815,
|
|
7560
|
-
2227730452,
|
|
7561
|
-
2361852424,
|
|
7562
|
-
2428436474,
|
|
7563
|
-
2756734187,
|
|
7564
|
-
3204031479,
|
|
7565
|
-
3329325298
|
|
7566
|
-
];
|
|
7567
|
-
function rightRotate32(value, bits) {
|
|
7568
|
-
return value >>> bits | value << 32 - bits;
|
|
7569
|
-
}
|
|
7570
|
-
function sha256Hex(input2) {
|
|
7571
|
-
const bytes = Array.from(new TextEncoder().encode(input2));
|
|
7572
|
-
const bitLength = bytes.length * 8;
|
|
7573
|
-
bytes.push(128);
|
|
7574
|
-
while (bytes.length % 64 !== 56) {
|
|
7575
|
-
bytes.push(0);
|
|
7576
|
-
}
|
|
7577
|
-
const highBits = Math.floor(bitLength / 4294967296);
|
|
7578
|
-
const lowBits = bitLength >>> 0;
|
|
7579
|
-
bytes.push(
|
|
7580
|
-
highBits >>> 24 & 255,
|
|
7581
|
-
highBits >>> 16 & 255,
|
|
7582
|
-
highBits >>> 8 & 255,
|
|
7583
|
-
highBits & 255,
|
|
7584
|
-
lowBits >>> 24 & 255,
|
|
7585
|
-
lowBits >>> 16 & 255,
|
|
7586
|
-
lowBits >>> 8 & 255,
|
|
7587
|
-
lowBits & 255
|
|
7588
|
-
);
|
|
7589
|
-
const hash = [...SHA256_INITIAL_HASH];
|
|
7590
|
-
const words = new Array(64).fill(0);
|
|
7591
|
-
for (let offset = 0; offset < bytes.length; offset += 64) {
|
|
7592
|
-
for (let index = 0; index < 16; index += 1) {
|
|
7593
|
-
const wordOffset = offset + index * 4;
|
|
7594
|
-
words[index] = (bytes[wordOffset] ?? 0) << 24 | (bytes[wordOffset + 1] ?? 0) << 16 | (bytes[wordOffset + 2] ?? 0) << 8 | (bytes[wordOffset + 3] ?? 0);
|
|
7595
|
-
}
|
|
7596
|
-
for (let index = 16; index < 64; index += 1) {
|
|
7597
|
-
const s0 = rightRotate32(words[index - 15], 7) ^ rightRotate32(words[index - 15], 18) ^ words[index - 15] >>> 3;
|
|
7598
|
-
const s1 = rightRotate32(words[index - 2], 17) ^ rightRotate32(words[index - 2], 19) ^ words[index - 2] >>> 10;
|
|
7599
|
-
words[index] = words[index - 16] + s0 + words[index - 7] + s1 >>> 0;
|
|
7600
|
-
}
|
|
7601
|
-
let [a, b, c, d, e, f, g, h] = hash;
|
|
7602
|
-
for (let index = 0; index < 64; index += 1) {
|
|
7603
|
-
const s1 = rightRotate32(e, 6) ^ rightRotate32(e, 11) ^ rightRotate32(e, 25);
|
|
7604
|
-
const ch = e & f ^ ~e & g;
|
|
7605
|
-
const temp1 = h + s1 + ch + SHA256_ROUND_CONSTANTS[index] + words[index] >>> 0;
|
|
7606
|
-
const s0 = rightRotate32(a, 2) ^ rightRotate32(a, 13) ^ rightRotate32(a, 22);
|
|
7607
|
-
const maj = a & b ^ a & c ^ b & c;
|
|
7608
|
-
const temp2 = s0 + maj >>> 0;
|
|
7609
|
-
h = g;
|
|
7610
|
-
g = f;
|
|
7611
|
-
f = e;
|
|
7612
|
-
e = d + temp1 >>> 0;
|
|
7613
|
-
d = c;
|
|
7614
|
-
c = b;
|
|
7615
|
-
b = a;
|
|
7616
|
-
a = temp1 + temp2 >>> 0;
|
|
7617
|
-
}
|
|
7618
|
-
hash[0] = hash[0] + a >>> 0;
|
|
7619
|
-
hash[1] = hash[1] + b >>> 0;
|
|
7620
|
-
hash[2] = hash[2] + c >>> 0;
|
|
7621
|
-
hash[3] = hash[3] + d >>> 0;
|
|
7622
|
-
hash[4] = hash[4] + e >>> 0;
|
|
7623
|
-
hash[5] = hash[5] + f >>> 0;
|
|
7624
|
-
hash[6] = hash[6] + g >>> 0;
|
|
7625
|
-
hash[7] = hash[7] + h >>> 0;
|
|
7626
|
-
}
|
|
7627
|
-
return hash.map((word) => word.toString(16).padStart(8, "0")).join("");
|
|
7628
|
-
}
|
|
7629
|
-
function sanitizeIdentifierPart(value) {
|
|
7630
|
-
return value.trim().replace(/[^a-z0-9]+/gi, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
7631
|
-
}
|
|
7632
|
-
function validateIdentifierPart(rawValue, label, maxLength) {
|
|
7633
|
-
const sanitized = sanitizeIdentifierPart(rawValue);
|
|
7634
|
-
if (!sanitized) {
|
|
7635
|
-
throw new Error(
|
|
7636
|
-
`${label} must contain at least one letter or number after normalization. Use only letters, numbers, underscores, or hyphens.`
|
|
7637
|
-
);
|
|
7638
|
-
}
|
|
7639
|
-
if (sanitized.length > maxLength) {
|
|
7640
|
-
throw new Error(
|
|
7641
|
-
`${label} is too long after normalization (${sanitized.length}/${maxLength}). Shorten it to ${maxLength} characters or fewer. Normalized value: "${sanitized}".`
|
|
7642
|
-
);
|
|
7643
|
-
}
|
|
7644
|
-
return sanitized;
|
|
7645
|
-
}
|
|
7646
|
-
function normalizePlayName(value) {
|
|
7647
|
-
if (value.includes("/")) {
|
|
7648
|
-
throw new Error(
|
|
7649
|
-
'Play name cannot contain "/". Slash is reserved for qualified play references like "prebuilt/example" or "self/example".'
|
|
7650
|
-
);
|
|
7651
|
-
}
|
|
7652
|
-
return validateIdentifierPart(value, "Play name", PLAY_NAME_MAX_LENGTH);
|
|
7653
|
-
}
|
|
7654
|
-
function normalizePlayNameForSheet(value) {
|
|
7655
|
-
if (!value.includes("/")) {
|
|
7656
|
-
return normalizePlayName(value);
|
|
7657
|
-
}
|
|
7658
|
-
const digest = sha256Hex(value).slice(0, 12);
|
|
7659
|
-
const normalizedReference = sanitizeIdentifierPart(
|
|
7660
|
-
value.replace(/\//g, "__")
|
|
7661
|
-
);
|
|
7662
|
-
const prefixLength = Math.max(1, PLAY_NAME_MAX_LENGTH - digest.length - 1);
|
|
7663
|
-
const prefix = normalizedReference.slice(0, prefixLength).replace(/_+$/g, "") || "qualified_play";
|
|
7664
|
-
return `${prefix}_${digest}`;
|
|
7665
|
-
}
|
|
7666
|
-
function normalizeTableNamespace(value) {
|
|
7667
|
-
return validateIdentifierPart(
|
|
7668
|
-
value,
|
|
7669
|
-
"ctx.dataset() key",
|
|
7670
|
-
MAP_KEY_NAMESPACE_MAX_LENGTH
|
|
7671
|
-
);
|
|
7672
|
-
}
|
|
7673
|
-
function validatePlaySheetTableName(playName, tableNamespace) {
|
|
7674
|
-
const playSegment = normalizePlayNameForSheet(playName);
|
|
7675
|
-
const keySegment = normalizeTableNamespace(tableNamespace);
|
|
7676
|
-
const resolved = `${playSegment}_${keySegment}`;
|
|
7677
|
-
if (resolved.length > POSTGRES_IDENTIFIER_MAX_LENGTH) {
|
|
7678
|
-
throw new Error(
|
|
7679
|
-
`Play sheet table name is too long after normalization (${resolved.length}/63). Shorten the play name or ctx.dataset() key. Resolved table name: "${resolved}".`
|
|
7680
|
-
);
|
|
7681
|
-
}
|
|
7682
|
-
return resolved;
|
|
7683
|
-
}
|
|
7684
|
-
|
|
7685
7613
|
// src/cli/trace.ts
|
|
7686
7614
|
var cliTraceStartedAt = Date.now();
|
|
7687
7615
|
function isTruthyEnv(value) {
|
|
@@ -7732,6 +7660,11 @@ async function traceCliSpan(phase, fields, run) {
|
|
|
7732
7660
|
|
|
7733
7661
|
// src/cli/play-check-hints.ts
|
|
7734
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.";
|
|
7735
7668
|
function sourceLineForError(sourceCode, error) {
|
|
7736
7669
|
const match = error.match(/:(\d+):(\d+)\s/);
|
|
7737
7670
|
const lineNumber = match?.[1] ? Number(match[1]) : NaN;
|
|
@@ -7742,16 +7675,61 @@ function looksLikeInvalidExtractedGetter(error, sourceLine) {
|
|
|
7742
7675
|
if (!/Property '[^']+' does not exist on type/.test(error)) return false;
|
|
7743
7676
|
return /\bextracted(?:Values|Lists)\s*\./.test(sourceLine);
|
|
7744
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
|
+
}
|
|
7745
7722
|
function addPlayCheckRepairHints(input2) {
|
|
7746
|
-
|
|
7723
|
+
const addedHints = /* @__PURE__ */ new Set();
|
|
7747
7724
|
return input2.errors.map((error) => {
|
|
7748
7725
|
const line = sourceLineForError(input2.sourceCode, error);
|
|
7749
|
-
|
|
7726
|
+
const hint = hintForError(error, line);
|
|
7727
|
+
if (!hint || addedHints.has(hint) || error.includes(hint)) {
|
|
7750
7728
|
return error;
|
|
7751
7729
|
}
|
|
7752
|
-
|
|
7730
|
+
addedHints.add(hint);
|
|
7753
7731
|
return `${error}
|
|
7754
|
-
${
|
|
7732
|
+
${hint}`;
|
|
7755
7733
|
});
|
|
7756
7734
|
}
|
|
7757
7735
|
|
|
@@ -8308,8 +8286,6 @@ var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
|
8308
8286
|
"cancelled"
|
|
8309
8287
|
]);
|
|
8310
8288
|
var PLAY_START_TRANSIENT_RETRY_DELAYS_MS = [500, 1500];
|
|
8311
|
-
var PLAY_CUSTOMER_STORAGE_SCHEMA_NAME = "storage";
|
|
8312
|
-
var PLAY_INTERNAL_STEP_RECEIPT_TABLE = "_deepline_step_receipts";
|
|
8313
8289
|
function getEventPayload(event) {
|
|
8314
8290
|
return event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
8315
8291
|
}
|
|
@@ -8363,36 +8339,8 @@ function getLogLinesFromLiveEvent(event) {
|
|
|
8363
8339
|
const lines = getEventPayload(event).lines;
|
|
8364
8340
|
return Array.isArray(lines) ? lines.filter((line) => typeof line === "string") : [];
|
|
8365
8341
|
}
|
|
8366
|
-
function
|
|
8367
|
-
return `
|
|
8368
|
-
}
|
|
8369
|
-
function quoteSqlLiteral(value) {
|
|
8370
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
8371
|
-
}
|
|
8372
|
-
function buildDebugDbQueryCommand(sql) {
|
|
8373
|
-
return `deepline db query --sql ${shellSingleQuote(sql)} --max-rows 20 --json`;
|
|
8374
|
-
}
|
|
8375
|
-
function buildStepReceiptsDebugCommand(runId) {
|
|
8376
|
-
const table = `${quoteSqlIdentifier(
|
|
8377
|
-
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8378
|
-
)}.${quoteSqlIdentifier(PLAY_INTERNAL_STEP_RECEIPT_TABLE)}`;
|
|
8379
|
-
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`;
|
|
8380
|
-
return buildDebugDbQueryCommand(sql);
|
|
8381
|
-
}
|
|
8382
|
-
function buildMapTableDebugCommand(input2) {
|
|
8383
|
-
try {
|
|
8384
|
-
const tableName = validatePlaySheetTableName(
|
|
8385
|
-
input2.playName,
|
|
8386
|
-
input2.tableNamespace
|
|
8387
|
-
);
|
|
8388
|
-
const table = `${quoteSqlIdentifier(
|
|
8389
|
-
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8390
|
-
)}.${quoteSqlIdentifier(tableName)}`;
|
|
8391
|
-
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(input2.runId)} limit 20`;
|
|
8392
|
-
return buildDebugDbQueryCommand(sql);
|
|
8393
|
-
} catch {
|
|
8394
|
-
return null;
|
|
8395
|
-
}
|
|
8342
|
+
function buildRunInspectCommand(runId) {
|
|
8343
|
+
return `deepline runs get ${runId} --full --json`;
|
|
8396
8344
|
}
|
|
8397
8345
|
function extractTableNamespaceFromLiveEvent(event) {
|
|
8398
8346
|
const payload = getEventPayload(event);
|
|
@@ -8417,7 +8365,7 @@ function emitLiveDebugTableHints(input2) {
|
|
|
8417
8365
|
if (!input2.state.emittedDebugKeys.has(receiptsKey)) {
|
|
8418
8366
|
input2.state.emittedDebugKeys.add(receiptsKey);
|
|
8419
8367
|
input2.progress.writeLine(
|
|
8420
|
-
`
|
|
8368
|
+
`Inspect run output: ${buildRunInspectCommand(input2.runId)}`,
|
|
8421
8369
|
process.stdout
|
|
8422
8370
|
);
|
|
8423
8371
|
}
|
|
@@ -8429,17 +8377,9 @@ function emitLiveDebugTableHints(input2) {
|
|
|
8429
8377
|
if (input2.state.emittedDebugKeys.has(tableKey)) {
|
|
8430
8378
|
return;
|
|
8431
8379
|
}
|
|
8432
|
-
const command = buildMapTableDebugCommand({
|
|
8433
|
-
playName: input2.playName,
|
|
8434
|
-
runId: input2.runId,
|
|
8435
|
-
tableNamespace
|
|
8436
|
-
});
|
|
8437
|
-
if (!command) {
|
|
8438
|
-
return;
|
|
8439
|
-
}
|
|
8440
8380
|
input2.state.emittedDebugKeys.add(tableKey);
|
|
8441
8381
|
input2.progress.writeLine(
|
|
8442
|
-
`
|
|
8382
|
+
`Possible map table ${tableNamespace}: created only after this ctx.map(...).run(...) executes. Inspect returned datasets with ${buildRunInspectCommand(input2.runId)}`,
|
|
8443
8383
|
process.stdout
|
|
8444
8384
|
);
|
|
8445
8385
|
}
|
|
@@ -8643,7 +8583,7 @@ async function waitForPlayCompletionByStream(input2) {
|
|
|
8643
8583
|
}
|
|
8644
8584
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8645
8585
|
throw new DeeplineError(
|
|
8646
|
-
`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}'.`,
|
|
8647
8587
|
void 0,
|
|
8648
8588
|
"PLAY_LIVE_STREAM_ENDED",
|
|
8649
8589
|
{
|
|
@@ -8804,7 +8744,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8804
8744
|
const reason = error instanceof Error ? error.message : String(error);
|
|
8805
8745
|
if (!input2.jsonOutput) {
|
|
8806
8746
|
process.stderr.write(
|
|
8807
|
-
`[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})
|
|
8808
8748
|
`
|
|
8809
8749
|
);
|
|
8810
8750
|
}
|
|
@@ -8841,7 +8781,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8841
8781
|
if (lastKnownWorkflowId) {
|
|
8842
8782
|
if (!input2.jsonOutput) {
|
|
8843
8783
|
input2.progress.writeLine(
|
|
8844
|
-
`[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`
|
|
8845
8785
|
);
|
|
8846
8786
|
}
|
|
8847
8787
|
recordCliTrace({
|
|
@@ -8871,7 +8811,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8871
8811
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8872
8812
|
const idSuffix = lastKnownWorkflowId ? ` runId=${lastKnownWorkflowId}` : "";
|
|
8873
8813
|
throw new DeeplineError(
|
|
8874
|
-
`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>'.`,
|
|
8875
8815
|
void 0,
|
|
8876
8816
|
"PLAY_START_STREAM_ENDED",
|
|
8877
8817
|
{
|
|
@@ -9219,6 +9159,32 @@ function formatPlayErrorForDisplay(status, error) {
|
|
|
9219
9159
|
}
|
|
9220
9160
|
return error;
|
|
9221
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
|
+
}
|
|
9222
9188
|
function normalizeRunStatusForEnvelope(status) {
|
|
9223
9189
|
const run = status.run ?? null;
|
|
9224
9190
|
return {
|
|
@@ -9356,8 +9322,7 @@ function compactPlayStatus(status) {
|
|
|
9356
9322
|
const billing = status && typeof status === "object" ? stripProviderSpendFromBilling(
|
|
9357
9323
|
status.billing
|
|
9358
9324
|
) : null;
|
|
9359
|
-
const
|
|
9360
|
-
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);
|
|
9361
9326
|
const displayError = formatPlayErrorForDisplay(status, error);
|
|
9362
9327
|
return {
|
|
9363
9328
|
runId: status.runId,
|
|
@@ -9612,8 +9577,8 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
9612
9577
|
for (const warning of warnings) {
|
|
9613
9578
|
lines.push(` warning: ${warning}`);
|
|
9614
9579
|
}
|
|
9615
|
-
const progressError = status
|
|
9616
|
-
if (progressError
|
|
9580
|
+
const progressError = selectRunErrorForDisplay(status);
|
|
9581
|
+
if (progressError) {
|
|
9617
9582
|
const billing = extractBillingForStatus(status, progressError);
|
|
9618
9583
|
if (isInsufficientCreditsBilling(billing)) {
|
|
9619
9584
|
lines.push(...buildInsufficientCreditsSummaryLines({ status, billing }));
|
|
@@ -9665,9 +9630,6 @@ var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
|
9665
9630
|
function shellSingleQuote(value) {
|
|
9666
9631
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
9667
9632
|
}
|
|
9668
|
-
function sqlStringLiteral(value) {
|
|
9669
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
9670
|
-
}
|
|
9671
9633
|
function runExportRetryCommand(runId, outPath, datasetPath) {
|
|
9672
9634
|
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0, import_node_path12.resolve)(outPath))}`;
|
|
9673
9635
|
}
|
|
@@ -9686,26 +9648,6 @@ function extractRunPlayName(status) {
|
|
|
9686
9648
|
}
|
|
9687
9649
|
return null;
|
|
9688
9650
|
}
|
|
9689
|
-
function normalizeCustomerDbIdentifier(value) {
|
|
9690
|
-
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
9691
|
-
}
|
|
9692
|
-
function buildCustomerDbQueryPlan(input2) {
|
|
9693
|
-
const playName = extractRunPlayName(input2.status);
|
|
9694
|
-
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9695
|
-
if (!playName || !tableNamespace || input2.rowsInfo.totalRows <= 0) {
|
|
9696
|
-
return null;
|
|
9697
|
-
}
|
|
9698
|
-
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
9699
|
-
tableNamespace
|
|
9700
|
-
)}`;
|
|
9701
|
-
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input2.status.runId)} limit ${input2.rowsInfo.totalRows}`;
|
|
9702
|
-
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input2.rowsInfo.totalRows}`;
|
|
9703
|
-
return {
|
|
9704
|
-
sql,
|
|
9705
|
-
json: `${base} --json`,
|
|
9706
|
-
csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path12.resolve)(input2.outPath))}`
|
|
9707
|
-
};
|
|
9708
|
-
}
|
|
9709
9651
|
function exportableSheetRow(row) {
|
|
9710
9652
|
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
9711
9653
|
return null;
|
|
@@ -10052,8 +9994,12 @@ function renderServerResultView(value) {
|
|
|
10052
9994
|
lines.push(
|
|
10053
9995
|
` ${String(table.tableNamespace ?? "table")}${lineLabel}: ${rowLabel}${details.join(" ")}`
|
|
10054
9996
|
);
|
|
10055
|
-
if (typeof table.queryDatasetCommand === "string") {
|
|
10056
|
-
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
|
+
);
|
|
10057
10003
|
}
|
|
10058
10004
|
if (table.debugHelp && typeof table.debugHelp === "object" && !Array.isArray(table.debugHelp)) {
|
|
10059
10005
|
const debugHelp = table.debugHelp;
|
|
@@ -10399,9 +10345,51 @@ function printToolGetterHints(hints) {
|
|
|
10399
10345
|
async function handlePlayCheck(args) {
|
|
10400
10346
|
const options = parsePlayCheckOptions(args);
|
|
10401
10347
|
if (!isFileTarget(options.target)) {
|
|
10402
|
-
const
|
|
10403
|
-
|
|
10404
|
-
|
|
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
|
+
}
|
|
10405
10393
|
}
|
|
10406
10394
|
const absolutePlayPath = (0, import_node_path12.resolve)(options.target);
|
|
10407
10395
|
const sourceCode = (0, import_node_fs10.readFileSync)(absolutePlayPath, "utf-8");
|
|
@@ -11048,18 +11036,9 @@ async function handleRunExport(args) {
|
|
|
11048
11036
|
datasetPath
|
|
11049
11037
|
});
|
|
11050
11038
|
const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
|
|
11051
|
-
const queryPlan = exportResult && outPath ? buildCustomerDbQueryPlan({
|
|
11052
|
-
status,
|
|
11053
|
-
rowsInfo: exportResult.rowsInfo,
|
|
11054
|
-
outPath
|
|
11055
|
-
}) : null;
|
|
11056
11039
|
const next = {
|
|
11057
11040
|
...buildRunNextCommands(status),
|
|
11058
|
-
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
|
|
11059
|
-
...queryPlan ? {
|
|
11060
|
-
queryJson: queryPlan.json,
|
|
11061
|
-
queryCsv: queryPlan.csv
|
|
11062
|
-
} : {}
|
|
11041
|
+
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
|
|
11063
11042
|
};
|
|
11064
11043
|
const payload = {
|
|
11065
11044
|
runId: status.runId,
|
|
@@ -11068,13 +11047,6 @@ async function handleRunExport(args) {
|
|
|
11068
11047
|
source,
|
|
11069
11048
|
rowCount: exportResult?.rowsInfo.totalRows ?? null,
|
|
11070
11049
|
columns: exportResult?.rowsInfo.columns ?? [],
|
|
11071
|
-
...queryPlan ? {
|
|
11072
|
-
query: {
|
|
11073
|
-
sql: queryPlan.sql,
|
|
11074
|
-
json: queryPlan.json,
|
|
11075
|
-
csv: queryPlan.csv
|
|
11076
|
-
}
|
|
11077
|
-
} : {},
|
|
11078
11050
|
...metadataOutPath ? { metadata_path: metadataOutPath } : {},
|
|
11079
11051
|
local: { csv_path: exportResult?.path ?? null },
|
|
11080
11052
|
next,
|
|
@@ -11084,8 +11056,7 @@ async function handleRunExport(args) {
|
|
|
11084
11056
|
title: "run export",
|
|
11085
11057
|
lines: [
|
|
11086
11058
|
`Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
|
|
11087
|
-
...source ? [`source=${source}`] : []
|
|
11088
|
-
...queryPlan ? [`query=${queryPlan.json}`] : []
|
|
11059
|
+
...source ? [`source=${source}`] : []
|
|
11089
11060
|
]
|
|
11090
11061
|
}
|
|
11091
11062
|
]
|
|
@@ -11265,7 +11236,8 @@ function parsePlaySearchOptions(args) {
|
|
|
11265
11236
|
return {
|
|
11266
11237
|
query,
|
|
11267
11238
|
jsonOutput: argsWantJson(args),
|
|
11268
|
-
compact: args.includes("--compact")
|
|
11239
|
+
compact: args.includes("--compact"),
|
|
11240
|
+
prebuiltOnly: args.includes("--prebuilt")
|
|
11269
11241
|
};
|
|
11270
11242
|
}
|
|
11271
11243
|
function printPlayDescription(play) {
|
|
@@ -11313,6 +11285,7 @@ function printPlayDescription(play) {
|
|
|
11313
11285
|
console.log(` ${line}`);
|
|
11314
11286
|
}
|
|
11315
11287
|
}
|
|
11288
|
+
console.log(` Describe: deepline plays describe ${reference} --json`);
|
|
11316
11289
|
console.log(` Run: ${play.runCommand}`);
|
|
11317
11290
|
const cloneEditStarter = play.cloneEditStarter ?? buildCloneEditStarter(play);
|
|
11318
11291
|
if (cloneEditStarter) {
|
|
@@ -11320,6 +11293,31 @@ function printPlayDescription(play) {
|
|
|
11320
11293
|
console.log(` Check starter: ${cloneEditStarter.checkCommand}`);
|
|
11321
11294
|
}
|
|
11322
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
|
+
}
|
|
11323
11321
|
function compactPlaySchema(schema) {
|
|
11324
11322
|
if (!schema) return null;
|
|
11325
11323
|
const fields = Array.isArray(schema.fields) ? schema.fields.map(
|
|
@@ -11383,22 +11381,44 @@ async function handlePlaySearch(args) {
|
|
|
11383
11381
|
return 1;
|
|
11384
11382
|
}
|
|
11385
11383
|
const client = new DeeplineClient();
|
|
11386
|
-
const plays = await client.searchPlays({
|
|
11384
|
+
const plays = (await client.searchPlays({
|
|
11387
11385
|
query: options.query,
|
|
11388
11386
|
compact: options.compact
|
|
11389
|
-
})
|
|
11387
|
+
})).filter(
|
|
11388
|
+
(play) => options.prebuiltOnly ? play.origin === "prebuilt" || play.ownerType === "deepline" : true
|
|
11389
|
+
);
|
|
11390
11390
|
if (options.jsonOutput) {
|
|
11391
|
-
|
|
11392
|
-
|
|
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
|
+
);
|
|
11393
11403
|
return 0;
|
|
11394
11404
|
}
|
|
11395
|
-
|
|
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}` : ""}:
|
|
11396
11408
|
|
|
11397
|
-
`
|
|
11398
|
-
|
|
11399
|
-
|
|
11409
|
+
`
|
|
11410
|
+
);
|
|
11411
|
+
for (const play of displayPlays) {
|
|
11412
|
+
if (options.prebuiltOnly) {
|
|
11413
|
+
printCompactPlaySearchResult(play);
|
|
11414
|
+
} else {
|
|
11415
|
+
printPlayDescription(play);
|
|
11416
|
+
}
|
|
11400
11417
|
console.log("");
|
|
11401
11418
|
}
|
|
11419
|
+
if (options.prebuiltOnly && plays.length > displayPlays.length) {
|
|
11420
|
+
console.log("Use --json for the full machine-readable result set.");
|
|
11421
|
+
}
|
|
11402
11422
|
return 0;
|
|
11403
11423
|
}
|
|
11404
11424
|
function normalizePlayGrepText(value) {
|
|
@@ -11665,15 +11685,18 @@ Common commands:
|
|
|
11665
11685
|
deepline plays get person-linkedin-to-email --json
|
|
11666
11686
|
`
|
|
11667
11687
|
);
|
|
11668
|
-
play.command("check <target>").description("
|
|
11688
|
+
play.command("check <target>").description("Check a local play file or named/prebuilt play contract.").addHelpText(
|
|
11669
11689
|
"after",
|
|
11670
11690
|
`
|
|
11671
11691
|
Notes:
|
|
11672
11692
|
Validates a local play without storing it, promoting it, or starting a run.
|
|
11673
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.
|
|
11674
11696
|
|
|
11675
11697
|
Examples:
|
|
11676
11698
|
deepline plays check my.play.ts
|
|
11699
|
+
deepline plays check prebuilt/name-and-domain-to-email-waterfall-batch
|
|
11677
11700
|
deepline plays check my.play.ts --json
|
|
11678
11701
|
`
|
|
11679
11702
|
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
|
|
@@ -11823,11 +11846,13 @@ Examples:
|
|
|
11823
11846
|
...options.json ? ["--json"] : []
|
|
11824
11847
|
]);
|
|
11825
11848
|
});
|
|
11826
|
-
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(
|
|
11827
11850
|
"after",
|
|
11828
11851
|
`
|
|
11829
11852
|
Notes:
|
|
11830
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.
|
|
11831
11856
|
The grep alias is the same ranked retrieval surface with a more literal name
|
|
11832
11857
|
for agents that are filtering the play registry.
|
|
11833
11858
|
|
|
@@ -11839,6 +11864,7 @@ Examples:
|
|
|
11839
11864
|
).option("--compact", "Emit compact schemas").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
11840
11865
|
process.exitCode = await handlePlaySearch([
|
|
11841
11866
|
query,
|
|
11867
|
+
...options.prebuilt ? ["--prebuilt"] : [],
|
|
11842
11868
|
...options.compact ? ["--compact"] : [],
|
|
11843
11869
|
...options.json ? ["--json"] : []
|
|
11844
11870
|
]);
|
|
@@ -12086,7 +12112,7 @@ Notes:
|
|
|
12086
12112
|
Writes a returned dataset handle to the requested local CSV path. Use runs get
|
|
12087
12113
|
first to inspect dataset paths like result.rows or result.nested.contacts.
|
|
12088
12114
|
--metadata-out writes the same export metadata object returned by --json,
|
|
12089
|
-
including source
|
|
12115
|
+
including the source dataset path and row/column metadata.
|
|
12090
12116
|
|
|
12091
12117
|
Examples:
|
|
12092
12118
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
@@ -14017,7 +14043,7 @@ async function listTools(args) {
|
|
|
14017
14043
|
const client = new DeeplineClient();
|
|
14018
14044
|
const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
|
|
14019
14045
|
const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
|
|
14020
|
-
const compact = args.includes("--compact");
|
|
14046
|
+
const compact = args.includes("--compact") || !args.includes("--json");
|
|
14021
14047
|
const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
14022
14048
|
const items = (await client.listTools({
|
|
14023
14049
|
...categoryFilter ? { categories: categoryFilter } : {}
|
|
@@ -14073,9 +14099,10 @@ async function searchTools(queryInput, options = {}) {
|
|
|
14073
14099
|
searchMode: options.searchMode,
|
|
14074
14100
|
includeSearchDebug: options.includeSearchDebug
|
|
14075
14101
|
});
|
|
14076
|
-
const
|
|
14102
|
+
const shouldCompact = options.compact || !options.json;
|
|
14103
|
+
const payload = shouldCompact && Array.isArray(result.tools) ? {
|
|
14077
14104
|
...result,
|
|
14078
|
-
tools: result.tools.map(compactTool)
|
|
14105
|
+
tools: result.tools.slice(0, 8).map(compactTool)
|
|
14079
14106
|
} : result;
|
|
14080
14107
|
printCommandEnvelope(payload, {
|
|
14081
14108
|
json: options.json || shouldEmitJson()
|
|
@@ -14116,7 +14143,8 @@ async function grepTools(queryInput, options = {}) {
|
|
|
14116
14143
|
mode
|
|
14117
14144
|
)
|
|
14118
14145
|
);
|
|
14119
|
-
const
|
|
14146
|
+
const shouldCompact = options.compact || !options.json;
|
|
14147
|
+
const outputTools = shouldCompact ? tools.slice(0, 8).map(compactTool) : tools;
|
|
14120
14148
|
printCommandEnvelope(
|
|
14121
14149
|
{
|
|
14122
14150
|
tools: outputTools,
|
|
@@ -14135,11 +14163,19 @@ async function grepTools(queryInput, options = {}) {
|
|
|
14135
14163
|
);
|
|
14136
14164
|
return 0;
|
|
14137
14165
|
}
|
|
14166
|
+
function numericToolField(tool, field) {
|
|
14167
|
+
const value = tool[field];
|
|
14168
|
+
return typeof value === "number" ? value : void 0;
|
|
14169
|
+
}
|
|
14138
14170
|
function compactTool(tool) {
|
|
14139
14171
|
const listed = toListedTool(tool);
|
|
14172
|
+
const searchScore = numericToolField(tool, "searchScore");
|
|
14173
|
+
const search_score = numericToolField(tool, "search_score");
|
|
14140
14174
|
return {
|
|
14141
14175
|
id: listed.id,
|
|
14142
14176
|
toolId: listed.toolId,
|
|
14177
|
+
...search_score !== void 0 ? { search_score } : {},
|
|
14178
|
+
...searchScore !== void 0 ? { searchScore } : {},
|
|
14143
14179
|
provider: listed.provider,
|
|
14144
14180
|
displayName: listed.displayName,
|
|
14145
14181
|
description: listed.description,
|
|
@@ -14460,7 +14496,7 @@ async function getTool(toolId, options = {}) {
|
|
|
14460
14496
|
}
|
|
14461
14497
|
if (shouldEmitJson()) {
|
|
14462
14498
|
process.stdout.write(
|
|
14463
|
-
`${JSON.stringify(
|
|
14499
|
+
`${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
|
|
14464
14500
|
`
|
|
14465
14501
|
);
|
|
14466
14502
|
return 0;
|
|
@@ -14785,8 +14821,8 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
|
14785
14821
|
invalidGetterHint: "If TypeScript says an extractedValues/extractedLists property does not exist, that field is not a declared Deepline getter.",
|
|
14786
14822
|
observeActualShape: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
14787
14823
|
observedOutput: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
14788
|
-
forPlayGetterBugs: "Run
|
|
14789
|
-
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."
|
|
14790
14826
|
},
|
|
14791
14827
|
starterScript: {
|
|
14792
14828
|
path: starterScript.path,
|
|
@@ -15803,6 +15839,7 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
15803
15839
|
}
|
|
15804
15840
|
|
|
15805
15841
|
// src/cli/index.ts
|
|
15842
|
+
var PREFLIGHT_TIMEOUT_MS = 3e3;
|
|
15806
15843
|
function asCommanderError(error) {
|
|
15807
15844
|
if (!(error instanceof Error) || !("code" in error)) {
|
|
15808
15845
|
return null;
|
|
@@ -15883,6 +15920,124 @@ async function runPlayRunnerHealthCheck() {
|
|
|
15883
15920
|
await (0, import_promises6.rm)(dir, { recursive: true, force: true });
|
|
15884
15921
|
}
|
|
15885
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
|
+
}
|
|
15886
16041
|
async function main() {
|
|
15887
16042
|
const mainStartedAt = Date.now();
|
|
15888
16043
|
recordCliTrace({
|
|
@@ -15899,6 +16054,7 @@ async function main() {
|
|
|
15899
16054
|
"after",
|
|
15900
16055
|
`
|
|
15901
16056
|
Common commands:
|
|
16057
|
+
deepline preflight
|
|
15902
16058
|
deepline health
|
|
15903
16059
|
deepline auth status --json
|
|
15904
16060
|
deepline plays search email --json
|
|
@@ -15920,7 +16076,6 @@ Output:
|
|
|
15920
16076
|
|
|
15921
16077
|
Safety:
|
|
15922
16078
|
Commands that mutate state, open a browser, write files, stop work, or spend credits say so in their help.
|
|
15923
|
-
Use --no-open where available for CI and agent runs.
|
|
15924
16079
|
|
|
15925
16080
|
Exit codes:
|
|
15926
16081
|
0 success; 2 usage/local input error; 3 auth/permission error; 4 not found;
|
|
@@ -15962,6 +16117,26 @@ Exit codes:
|
|
|
15962
16117
|
registerDbCommands(program);
|
|
15963
16118
|
registerFeedbackCommands(program);
|
|
15964
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
|
+
});
|
|
15965
16140
|
program.command("health").description("Check server health.").option("--json", "Force JSON output.").option(
|
|
15966
16141
|
"--play-runner",
|
|
15967
16142
|
"Run a tiny no-provider play to verify the full play execution plane."
|