deepline 0.1.77 → 0.1.79
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 +525 -355
- package/dist/cli/index.mjs +538 -368
- package/dist/index.d.mts +31 -2
- package/dist/index.d.ts +31 -2
- package/dist/index.js +3 -2
- package/dist/index.mjs +3 -2
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +273 -83
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +18 -3
- package/dist/repo/apps/play-runner-workers/src/workflow-retry-state.ts +203 -0
- 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/dist/repo/shared_libs/plays/static-pipeline.ts +261 -1
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -206,10 +206,10 @@ import { join as join2 } from "path";
|
|
|
206
206
|
|
|
207
207
|
// src/release.ts
|
|
208
208
|
var SDK_RELEASE = {
|
|
209
|
-
version: "0.1.
|
|
209
|
+
version: "0.1.79",
|
|
210
210
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
211
211
|
supportPolicy: {
|
|
212
|
-
latest: "0.1.
|
|
212
|
+
latest: "0.1.79",
|
|
213
213
|
minimumSupported: "0.1.53",
|
|
214
214
|
deprecatedBelow: "0.1.53"
|
|
215
215
|
}
|
|
@@ -379,8 +379,8 @@ var HttpClient = class {
|
|
|
379
379
|
if (lastError instanceof DeeplineError) {
|
|
380
380
|
throw lastError;
|
|
381
381
|
}
|
|
382
|
-
const
|
|
383
|
-
throw new DeeplineError(
|
|
382
|
+
const errorMessage3 = lastError?.message ? `Unable to connect to ${baseUrl}. ${lastError.message}` : `Unable to connect to ${baseUrl}. Is the computer able to access the url?`;
|
|
383
|
+
throw new DeeplineError(errorMessage3);
|
|
384
384
|
}
|
|
385
385
|
/**
|
|
386
386
|
* Send a GET request.
|
|
@@ -785,6 +785,7 @@ var DeeplineClient = class {
|
|
|
785
785
|
aliases,
|
|
786
786
|
inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
|
|
787
787
|
outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
|
|
788
|
+
staticPipeline: isRecord(play.staticPipeline) ? play.staticPipeline : isRecord(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
|
|
788
789
|
...csvInput ? { csvInput } : {},
|
|
789
790
|
...rowOutputSchema ? { rowOutputSchema } : {},
|
|
790
791
|
runCommand: runCommand2,
|
|
@@ -4016,6 +4017,51 @@ function customerDbRows(result) {
|
|
|
4016
4017
|
function customerDbColumnNames(result) {
|
|
4017
4018
|
return result.columns.map((column) => column.name).filter(Boolean);
|
|
4018
4019
|
}
|
|
4020
|
+
function errorMessage(value) {
|
|
4021
|
+
return value instanceof Error ? value.message : String(value ?? "");
|
|
4022
|
+
}
|
|
4023
|
+
function collectErrorText(value) {
|
|
4024
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
4025
|
+
return errorMessage(value);
|
|
4026
|
+
}
|
|
4027
|
+
const record = value;
|
|
4028
|
+
return [
|
|
4029
|
+
errorMessage(value),
|
|
4030
|
+
typeof record.error === "string" ? record.error : "",
|
|
4031
|
+
typeof record.message === "string" ? record.message : "",
|
|
4032
|
+
typeof record.detail === "string" ? record.detail : "",
|
|
4033
|
+
typeof record.hint === "string" ? record.hint : "",
|
|
4034
|
+
typeof record.code === "string" ? record.code : "",
|
|
4035
|
+
record.response ? collectErrorText(record.response) : "",
|
|
4036
|
+
record.details ? collectErrorText(record.details) : ""
|
|
4037
|
+
].filter(Boolean).join("\n");
|
|
4038
|
+
}
|
|
4039
|
+
function formatDbQueryError(sql, error) {
|
|
4040
|
+
const text = collectErrorText(error);
|
|
4041
|
+
const lower = text.toLowerCase();
|
|
4042
|
+
const referencesStorage = /"storage"\.|storage\./i.test(sql);
|
|
4043
|
+
const runIdColumnMissing = /column\s+"?run_id"?\s+does not exist/i.test(text) || /run_id.*does not exist/i.test(lower);
|
|
4044
|
+
const relationMissing = /relation\s+["']?[^"']*storage[^"']*["']?\s+does not exist/i.test(text) || /42p01/i.test(text);
|
|
4045
|
+
if (referencesStorage && relationMissing) {
|
|
4046
|
+
return [
|
|
4047
|
+
"Customer DB query failed: the referenced storage table does not exist.",
|
|
4048
|
+
"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.",
|
|
4049
|
+
"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`.",
|
|
4050
|
+
`Original error: ${errorMessage(error)}`
|
|
4051
|
+
].join("\n");
|
|
4052
|
+
}
|
|
4053
|
+
if (referencesStorage && runIdColumnMissing) {
|
|
4054
|
+
return [
|
|
4055
|
+
"Customer DB query failed: storage map tables use `_run_id`, not `run_id`.",
|
|
4056
|
+
"Prefer `deepline runs export <run-id> --dataset result.rows --out rows.csv` unless you are doing deep table debugging.",
|
|
4057
|
+
`Original error: ${errorMessage(error)}`
|
|
4058
|
+
].join("\n");
|
|
4059
|
+
}
|
|
4060
|
+
if (error instanceof DeeplineError) {
|
|
4061
|
+
return error.message;
|
|
4062
|
+
}
|
|
4063
|
+
return errorMessage(error);
|
|
4064
|
+
}
|
|
4019
4065
|
function writeCustomerDbCsv(result, outPath) {
|
|
4020
4066
|
const resolved = resolve5(outPath);
|
|
4021
4067
|
writeFileSync5(
|
|
@@ -4076,7 +4122,13 @@ async function handleDbQuery(args) {
|
|
|
4076
4122
|
const jsonOutput = argsWantJson(args);
|
|
4077
4123
|
const explicitJsonOutput = args.includes("--json");
|
|
4078
4124
|
const client = new DeeplineClient();
|
|
4079
|
-
|
|
4125
|
+
let result;
|
|
4126
|
+
try {
|
|
4127
|
+
result = await client.queryCustomerDb({ sql, maxRows });
|
|
4128
|
+
} catch (error) {
|
|
4129
|
+
console.error(formatDbQueryError(sql, error));
|
|
4130
|
+
return 1;
|
|
4131
|
+
}
|
|
4080
4132
|
const toolCommand = `deepline tools execute query_customer_db --payload ${JSON.stringify(
|
|
4081
4133
|
{
|
|
4082
4134
|
sql,
|
|
@@ -4237,7 +4289,7 @@ import {
|
|
|
4237
4289
|
readFileSync as readFileSync6,
|
|
4238
4290
|
readdirSync,
|
|
4239
4291
|
realpathSync,
|
|
4240
|
-
writeFileSync as
|
|
4292
|
+
writeFileSync as writeFileSync7
|
|
4241
4293
|
} from "fs";
|
|
4242
4294
|
import { basename as basename3, dirname as dirname8, join as join7, resolve as resolve10 } from "path";
|
|
4243
4295
|
|
|
@@ -5910,7 +5962,7 @@ async function bundlePlayFile2(filePath, options = {}) {
|
|
|
5910
5962
|
}
|
|
5911
5963
|
|
|
5912
5964
|
// src/cli/commands/plays/bootstrap.ts
|
|
5913
|
-
import { closeSync, openSync, readSync, statSync } from "fs";
|
|
5965
|
+
import { closeSync, openSync, readSync, statSync, writeFileSync as writeFileSync6 } from "fs";
|
|
5914
5966
|
import { isAbsolute as isAbsolute3, relative as relative2, resolve as resolve9 } from "path";
|
|
5915
5967
|
import { parse as parseCsvSync } from "csv-parse/sync";
|
|
5916
5968
|
|
|
@@ -6085,19 +6137,19 @@ function playBootstrapTemplateConfig(template) {
|
|
|
6085
6137
|
function templateExample(template) {
|
|
6086
6138
|
switch (template) {
|
|
6087
6139
|
case "people-list":
|
|
6088
|
-
return "deepline plays bootstrap people-list --from provider:dropleads_search_people
|
|
6140
|
+
return "deepline plays bootstrap people-list --from provider:dropleads_search_people --out people.play.ts";
|
|
6089
6141
|
case "company-list":
|
|
6090
|
-
return "deepline plays bootstrap company-list --from provider:apollo_company_search
|
|
6142
|
+
return "deepline plays bootstrap company-list --from provider:apollo_company_search --out companies.play.ts";
|
|
6091
6143
|
case "people-email":
|
|
6092
|
-
return "deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall
|
|
6144
|
+
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";
|
|
6093
6145
|
case "people-phone":
|
|
6094
|
-
return "deepline plays bootstrap people-phone --from csv:data/vp_contacts.csv --using play:prebuilt/person-to-phone
|
|
6146
|
+
return "deepline plays bootstrap people-phone --from csv:data/vp_contacts.csv --using play:prebuilt/person-to-phone --out phone-flow.play.ts";
|
|
6095
6147
|
case "company-people":
|
|
6096
|
-
return "deepline plays bootstrap company-people --from provider:apollo_company_search --using play:prebuilt/company-to-contact
|
|
6148
|
+
return "deepline plays bootstrap company-people --from provider:apollo_company_search --using play:prebuilt/company-to-contact --out company-people.play.ts";
|
|
6097
6149
|
case "company-people-email":
|
|
6098
|
-
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
|
|
6150
|
+
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";
|
|
6099
6151
|
case "company-people-phone":
|
|
6100
|
-
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
|
|
6152
|
+
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";
|
|
6101
6153
|
}
|
|
6102
6154
|
}
|
|
6103
6155
|
var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
@@ -6106,19 +6158,22 @@ var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
|
6106
6158
|
"phone"
|
|
6107
6159
|
];
|
|
6108
6160
|
function playBootstrapUsageLine() {
|
|
6109
|
-
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]
|
|
6161
|
+
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]`;
|
|
6110
6162
|
}
|
|
6111
6163
|
function requireBootstrapTemplate(rawTemplate) {
|
|
6112
6164
|
if (!rawTemplate) {
|
|
6113
6165
|
throw new PlayBootstrapUsageError(
|
|
6114
6166
|
`plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}.
|
|
6115
|
-
Example: deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall
|
|
6167
|
+
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`
|
|
6116
6168
|
);
|
|
6117
6169
|
}
|
|
6118
6170
|
if (!isPlayBootstrapTemplate(rawTemplate)) {
|
|
6171
|
+
const looksLikePlayReference = rawTemplate.includes("/") || rawTemplate.endsWith(".play.ts");
|
|
6119
6172
|
throw new PlayBootstrapUsageError(
|
|
6120
6173
|
`Unknown plays bootstrap template: ${rawTemplate}
|
|
6121
|
-
Supported templates: ${formatPlayBootstrapTemplates()}`
|
|
6174
|
+
Supported templates: ${formatPlayBootstrapTemplates()}` + (looksLikePlayReference ? `
|
|
6175
|
+
|
|
6176
|
+
"${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.` : "")
|
|
6122
6177
|
);
|
|
6123
6178
|
}
|
|
6124
6179
|
return rawTemplate;
|
|
@@ -6260,7 +6315,8 @@ function parsePlayBootstrapOptions(args) {
|
|
|
6260
6315
|
people: null,
|
|
6261
6316
|
email: null,
|
|
6262
6317
|
phone: null,
|
|
6263
|
-
limit: 5
|
|
6318
|
+
limit: 5,
|
|
6319
|
+
out: null
|
|
6264
6320
|
};
|
|
6265
6321
|
for (let index = 0; index < rest.length; index += 1) {
|
|
6266
6322
|
const arg = rest[index];
|
|
@@ -6294,6 +6350,10 @@ function parsePlayBootstrapOptions(args) {
|
|
|
6294
6350
|
options.limit = parsePositiveInteger2(value(), "--limit");
|
|
6295
6351
|
index += 1;
|
|
6296
6352
|
break;
|
|
6353
|
+
case "--out":
|
|
6354
|
+
options.out = value();
|
|
6355
|
+
index += 1;
|
|
6356
|
+
break;
|
|
6297
6357
|
default:
|
|
6298
6358
|
throw new PlayBootstrapUsageError(
|
|
6299
6359
|
`Unknown plays bootstrap option: ${arg}
|
|
@@ -6411,7 +6471,7 @@ function packagedCsvPathForPlay(csvPath) {
|
|
|
6411
6471
|
const relativePath = relative2(playDir, absoluteCsvPath);
|
|
6412
6472
|
if (relativePath === "" || relativePath.startsWith("..") || isAbsolute3(relativePath)) {
|
|
6413
6473
|
throw new PlayBootstrapUsageError(
|
|
6414
|
-
`--from csv:${csvPath} must point to a file inside the directory where you run plays bootstrap. Run bootstrap from the intended play directory
|
|
6474
|
+
`--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.`
|
|
6415
6475
|
);
|
|
6416
6476
|
}
|
|
6417
6477
|
const portablePath = relativePath.split("\\").join("/");
|
|
@@ -6818,8 +6878,18 @@ function validateBootstrapRoutes(input2) {
|
|
|
6818
6878
|
"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."
|
|
6819
6879
|
);
|
|
6820
6880
|
}
|
|
6881
|
+
assertComposablePlayRoute({
|
|
6882
|
+
stageLabel: "--people",
|
|
6883
|
+
playRef: stagePlayRef(input2.options.people),
|
|
6884
|
+
play: input2.peoplePlay
|
|
6885
|
+
});
|
|
6821
6886
|
for (const finder of ["email_finder", "phone_finder"]) {
|
|
6822
6887
|
const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
|
|
6888
|
+
assertComposablePlayRoute({
|
|
6889
|
+
stageLabel: finder === "email_finder" ? "--email/--using" : "--phone/--using",
|
|
6890
|
+
playRef: stagePlayRef(finderStage(input2.options, finder)),
|
|
6891
|
+
play: input2.finderPlays[finder] ?? null
|
|
6892
|
+
});
|
|
6823
6893
|
for (const tool of input2.finderTools[finder] ?? []) {
|
|
6824
6894
|
if (!tool.categories.includes(requiredCategory)) {
|
|
6825
6895
|
throw new PlayBootstrapValidationError(
|
|
@@ -6834,6 +6904,38 @@ function validateBootstrapRoutes(input2) {
|
|
|
6834
6904
|
}
|
|
6835
6905
|
}
|
|
6836
6906
|
}
|
|
6907
|
+
function staticPipelineSubsteps(pipeline) {
|
|
6908
|
+
if (!isRecord3(pipeline)) return [];
|
|
6909
|
+
return [
|
|
6910
|
+
...extractionEntries(pipeline.stages),
|
|
6911
|
+
...extractionEntries(pipeline.substeps)
|
|
6912
|
+
];
|
|
6913
|
+
}
|
|
6914
|
+
function playUsesMapBackedRuntime(play) {
|
|
6915
|
+
const pipeline = play?.staticPipeline;
|
|
6916
|
+
if (!isRecord3(pipeline)) return false;
|
|
6917
|
+
if (stringValue(pipeline.tableNamespace)) return true;
|
|
6918
|
+
return staticPipelineSubsteps(pipeline).some((substep) => {
|
|
6919
|
+
if (stringValue(substep.type) === "map") return true;
|
|
6920
|
+
return playUsesMapBackedRuntime({
|
|
6921
|
+
name: play?.name ?? "child",
|
|
6922
|
+
aliases: [],
|
|
6923
|
+
runCommand: "",
|
|
6924
|
+
examples: [],
|
|
6925
|
+
staticPipeline: isRecord3(substep.pipeline) ? substep.pipeline : null
|
|
6926
|
+
});
|
|
6927
|
+
});
|
|
6928
|
+
}
|
|
6929
|
+
function assertComposablePlayRoute(input2) {
|
|
6930
|
+
if (!input2.playRef || !playUsesMapBackedRuntime(input2.play)) return;
|
|
6931
|
+
const runCommand2 = input2.play?.runCommand?.trim() || `deepline plays run ${input2.playRef} --input '{...}' --watch`;
|
|
6932
|
+
throw new PlayBootstrapValidationError(
|
|
6933
|
+
`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}`
|
|
6934
|
+
);
|
|
6935
|
+
}
|
|
6936
|
+
function sourcePlayNeedsExportFirst(input2) {
|
|
6937
|
+
return input2.source.kind === "play" && playUsesMapBackedRuntime(input2.sourcePlay);
|
|
6938
|
+
}
|
|
6837
6939
|
function sourceCollectionName(entity) {
|
|
6838
6940
|
switch (entity) {
|
|
6839
6941
|
case "company":
|
|
@@ -6863,6 +6965,22 @@ function generateCsvSourceRowsBlock(input2) {
|
|
|
6863
6965
|
const ${input2.collection}: ${input2.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
6864
6966
|
}
|
|
6865
6967
|
function generatePlaySourceRowsBlock(input2) {
|
|
6968
|
+
if (sourcePlayNeedsExportFirst({
|
|
6969
|
+
source: input2.source,
|
|
6970
|
+
sourcePlay: input2.sourcePlay
|
|
6971
|
+
})) {
|
|
6972
|
+
const sourcePlay = input2.sourcePlay;
|
|
6973
|
+
const runCommand2 = sourcePlay?.runCommand?.trim() || `deepline plays run ${input2.source.value} --input '{...}' --watch`;
|
|
6974
|
+
return `// Source play ${input2.source.value} is map-backed/direct-run-only, so this generated play is stage 2.
|
|
6975
|
+
// Stage 1:
|
|
6976
|
+
// ${runCommand2}
|
|
6977
|
+
// Stage 2:
|
|
6978
|
+
// deepline runs export <stage-1-run-id> --dataset 'result.rows' --out source-export.csv
|
|
6979
|
+
// Stage 3:
|
|
6980
|
+
// deepline plays run <this-file.play.ts> --input '{"sourceCsv":"source-export.csv","limit":${input2.sourcePlay ? "5" : "5"}}' --watch
|
|
6981
|
+
const sourceDataset = await ctx.csv<${input2.collectionType}>(input.sourceCsv ?? './source-export.csv');
|
|
6982
|
+
const ${input2.collection}: ${input2.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
6983
|
+
}
|
|
6866
6984
|
const playInput = generatePlayInputObject({
|
|
6867
6985
|
schema: input2.sourcePlay?.inputSchema,
|
|
6868
6986
|
indent: " ",
|
|
@@ -7147,6 +7265,7 @@ ${typeDefinitions}
|
|
|
7147
7265
|
|
|
7148
7266
|
type Input = {
|
|
7149
7267
|
limit?: number;
|
|
7268
|
+
sourceCsv?: string;
|
|
7150
7269
|
};
|
|
7151
7270
|
|
|
7152
7271
|
export default definePlay(${jsString(input2.options.name)}, async (ctx, input: Input = {}) => {
|
|
@@ -7213,6 +7332,7 @@ async function loadBootstrapContracts(client, options) {
|
|
|
7213
7332
|
validateBootstrapRoutes({
|
|
7214
7333
|
options,
|
|
7215
7334
|
sourceTools: contracts.sourceTools,
|
|
7335
|
+
sourcePlay: contracts.sourcePlay,
|
|
7216
7336
|
peoplePlay: contracts.peoplePlay,
|
|
7217
7337
|
finderTools: contracts.finderTools,
|
|
7218
7338
|
finderPlays: contracts.finderPlays
|
|
@@ -7234,11 +7354,11 @@ function loadCsvContext(source) {
|
|
|
7234
7354
|
};
|
|
7235
7355
|
}
|
|
7236
7356
|
}
|
|
7237
|
-
function
|
|
7357
|
+
function errorMessage2(error) {
|
|
7238
7358
|
return error instanceof Error ? error.message : String(error);
|
|
7239
7359
|
}
|
|
7240
7360
|
function renderPlayBootstrapError(error) {
|
|
7241
|
-
console.error(
|
|
7361
|
+
console.error(errorMessage2(error));
|
|
7242
7362
|
return error instanceof PlayBootstrapError ? error.exitCode : 1;
|
|
7243
7363
|
}
|
|
7244
7364
|
async function runPlayBootstrap(args) {
|
|
@@ -7251,6 +7371,12 @@ async function runPlayBootstrap(args) {
|
|
|
7251
7371
|
...contracts,
|
|
7252
7372
|
...csvContext
|
|
7253
7373
|
});
|
|
7374
|
+
if (options.out) {
|
|
7375
|
+
writeFileSync6(resolve9(options.out), source, "utf-8");
|
|
7376
|
+
process.stdout.write(`Wrote ${resolve9(options.out)}
|
|
7377
|
+
`);
|
|
7378
|
+
return 0;
|
|
7379
|
+
}
|
|
7254
7380
|
process.stdout.write(source);
|
|
7255
7381
|
return 0;
|
|
7256
7382
|
}
|
|
@@ -7263,7 +7389,7 @@ function registerPlayBootstrapCommand(play) {
|
|
|
7263
7389
|
`
|
|
7264
7390
|
Notes:
|
|
7265
7391
|
Cloud-validated play generator for agents. Pick the JTBD as the positional
|
|
7266
|
-
template, bind resources with typed refs,
|
|
7392
|
+
template, bind resources with typed refs, write the .play.ts file with --out,
|
|
7267
7393
|
then edit the generated TODO mapping comments. Multiple finder providers are
|
|
7268
7394
|
generated as a waterfall in the order you pass them.
|
|
7269
7395
|
|
|
@@ -7271,9 +7397,8 @@ Notes:
|
|
|
7271
7397
|
Deepline. It prints TypeScript source only and does not run paid tools; the
|
|
7272
7398
|
generated play may spend credits later when you run it.
|
|
7273
7399
|
|
|
7274
|
-
stdout is the generated .play.ts source.
|
|
7275
|
-
|
|
7276
|
-
deepline plays bootstrap ... > scratchpad.play.ts
|
|
7400
|
+
By default stdout is the generated .play.ts source. Use --out to write a file
|
|
7401
|
+
directly. Errors and diagnostics go to stderr. There is no JSON mode.
|
|
7277
7402
|
|
|
7278
7403
|
Templates:
|
|
7279
7404
|
people-list start from people/contact rows
|
|
@@ -7297,7 +7422,7 @@ Notes:
|
|
|
7297
7422
|
email/phone finder providers must match their category and expose value getters
|
|
7298
7423
|
finder plays/providers must match the route; generated code leaves input mapping explicit
|
|
7299
7424
|
business-specific provider inputs and company -> people persona fields are TODOs in code
|
|
7300
|
-
csv: paths are resolved from the directory where you run bootstrap;
|
|
7425
|
+
csv: paths are resolved from the directory where you run bootstrap; write the play file there too
|
|
7301
7426
|
|
|
7302
7427
|
Exit codes:
|
|
7303
7428
|
0 success
|
|
@@ -7305,13 +7430,13 @@ Notes:
|
|
|
7305
7430
|
7 route validation failed
|
|
7306
7431
|
|
|
7307
7432
|
Examples:
|
|
7308
|
-
deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall --limit 5
|
|
7433
|
+
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
|
|
7309
7434
|
deepline plays check email-flow.play.ts
|
|
7310
7435
|
deepline plays run email-flow.play.ts --input '{"limit":5}' --watch
|
|
7311
7436
|
|
|
7312
|
-
deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5
|
|
7313
|
-
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
|
|
7314
|
-
deepline plays bootstrap company-list --from provider:apollo_company_search --limit 5
|
|
7437
|
+
deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5 --out prospecting.play.ts
|
|
7438
|
+
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
|
|
7439
|
+
deepline plays bootstrap company-list --from provider:apollo_company_search --limit 5 --out companies.play.ts
|
|
7315
7440
|
`
|
|
7316
7441
|
).option("--name <name>", "Generated play name").option(
|
|
7317
7442
|
"--from <ref>",
|
|
@@ -7328,7 +7453,7 @@ Examples:
|
|
|
7328
7453
|
).option(
|
|
7329
7454
|
"--phone <ref>",
|
|
7330
7455
|
"Phone finder stage: play:REF, provider:ID, or providers:ID,ID"
|
|
7331
|
-
).option("--limit <n>", "Maximum rows to fan out in the generated play").action(async (template, options) => {
|
|
7456
|
+
).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) => {
|
|
7332
7457
|
process.exitCode = await handlePlayBootstrap([
|
|
7333
7458
|
template,
|
|
7334
7459
|
...options.name ? ["--name", options.name] : [],
|
|
@@ -7337,7 +7462,8 @@ Examples:
|
|
|
7337
7462
|
...options.people ? ["--people", options.people] : [],
|
|
7338
7463
|
...options.email ? ["--email", options.email] : [],
|
|
7339
7464
|
...options.phone ? ["--phone", options.phone] : [],
|
|
7340
|
-
...options.limit ? ["--limit", options.limit] : []
|
|
7465
|
+
...options.limit ? ["--limit", options.limit] : [],
|
|
7466
|
+
...options.out ? ["--out", options.out] : []
|
|
7341
7467
|
]);
|
|
7342
7468
|
});
|
|
7343
7469
|
}
|
|
@@ -7487,204 +7613,6 @@ function createCliProgress(enabled) {
|
|
|
7487
7613
|
return progress;
|
|
7488
7614
|
}
|
|
7489
7615
|
|
|
7490
|
-
// ../shared_libs/plays/row-identity.ts
|
|
7491
|
-
var POSTGRES_IDENTIFIER_MAX_LENGTH = 63;
|
|
7492
|
-
var PLAY_NAME_MAX_LENGTH = POSTGRES_IDENTIFIER_MAX_LENGTH;
|
|
7493
|
-
var MAP_KEY_NAMESPACE_MAX_LENGTH = POSTGRES_IDENTIFIER_MAX_LENGTH;
|
|
7494
|
-
var SHA256_INITIAL_HASH = [
|
|
7495
|
-
1779033703,
|
|
7496
|
-
3144134277,
|
|
7497
|
-
1013904242,
|
|
7498
|
-
2773480762,
|
|
7499
|
-
1359893119,
|
|
7500
|
-
2600822924,
|
|
7501
|
-
528734635,
|
|
7502
|
-
1541459225
|
|
7503
|
-
];
|
|
7504
|
-
var SHA256_ROUND_CONSTANTS = [
|
|
7505
|
-
1116352408,
|
|
7506
|
-
1899447441,
|
|
7507
|
-
3049323471,
|
|
7508
|
-
3921009573,
|
|
7509
|
-
961987163,
|
|
7510
|
-
1508970993,
|
|
7511
|
-
2453635748,
|
|
7512
|
-
2870763221,
|
|
7513
|
-
3624381080,
|
|
7514
|
-
310598401,
|
|
7515
|
-
607225278,
|
|
7516
|
-
1426881987,
|
|
7517
|
-
1925078388,
|
|
7518
|
-
2162078206,
|
|
7519
|
-
2614888103,
|
|
7520
|
-
3248222580,
|
|
7521
|
-
3835390401,
|
|
7522
|
-
4022224774,
|
|
7523
|
-
264347078,
|
|
7524
|
-
604807628,
|
|
7525
|
-
770255983,
|
|
7526
|
-
1249150122,
|
|
7527
|
-
1555081692,
|
|
7528
|
-
1996064986,
|
|
7529
|
-
2554220882,
|
|
7530
|
-
2821834349,
|
|
7531
|
-
2952996808,
|
|
7532
|
-
3210313671,
|
|
7533
|
-
3336571891,
|
|
7534
|
-
3584528711,
|
|
7535
|
-
113926993,
|
|
7536
|
-
338241895,
|
|
7537
|
-
666307205,
|
|
7538
|
-
773529912,
|
|
7539
|
-
1294757372,
|
|
7540
|
-
1396182291,
|
|
7541
|
-
1695183700,
|
|
7542
|
-
1986661051,
|
|
7543
|
-
2177026350,
|
|
7544
|
-
2456956037,
|
|
7545
|
-
2730485921,
|
|
7546
|
-
2820302411,
|
|
7547
|
-
3259730800,
|
|
7548
|
-
3345764771,
|
|
7549
|
-
3516065817,
|
|
7550
|
-
3600352804,
|
|
7551
|
-
4094571909,
|
|
7552
|
-
275423344,
|
|
7553
|
-
430227734,
|
|
7554
|
-
506948616,
|
|
7555
|
-
659060556,
|
|
7556
|
-
883997877,
|
|
7557
|
-
958139571,
|
|
7558
|
-
1322822218,
|
|
7559
|
-
1537002063,
|
|
7560
|
-
1747873779,
|
|
7561
|
-
1955562222,
|
|
7562
|
-
2024104815,
|
|
7563
|
-
2227730452,
|
|
7564
|
-
2361852424,
|
|
7565
|
-
2428436474,
|
|
7566
|
-
2756734187,
|
|
7567
|
-
3204031479,
|
|
7568
|
-
3329325298
|
|
7569
|
-
];
|
|
7570
|
-
function rightRotate32(value, bits) {
|
|
7571
|
-
return value >>> bits | value << 32 - bits;
|
|
7572
|
-
}
|
|
7573
|
-
function sha256Hex(input2) {
|
|
7574
|
-
const bytes = Array.from(new TextEncoder().encode(input2));
|
|
7575
|
-
const bitLength = bytes.length * 8;
|
|
7576
|
-
bytes.push(128);
|
|
7577
|
-
while (bytes.length % 64 !== 56) {
|
|
7578
|
-
bytes.push(0);
|
|
7579
|
-
}
|
|
7580
|
-
const highBits = Math.floor(bitLength / 4294967296);
|
|
7581
|
-
const lowBits = bitLength >>> 0;
|
|
7582
|
-
bytes.push(
|
|
7583
|
-
highBits >>> 24 & 255,
|
|
7584
|
-
highBits >>> 16 & 255,
|
|
7585
|
-
highBits >>> 8 & 255,
|
|
7586
|
-
highBits & 255,
|
|
7587
|
-
lowBits >>> 24 & 255,
|
|
7588
|
-
lowBits >>> 16 & 255,
|
|
7589
|
-
lowBits >>> 8 & 255,
|
|
7590
|
-
lowBits & 255
|
|
7591
|
-
);
|
|
7592
|
-
const hash = [...SHA256_INITIAL_HASH];
|
|
7593
|
-
const words = new Array(64).fill(0);
|
|
7594
|
-
for (let offset = 0; offset < bytes.length; offset += 64) {
|
|
7595
|
-
for (let index = 0; index < 16; index += 1) {
|
|
7596
|
-
const wordOffset = offset + index * 4;
|
|
7597
|
-
words[index] = (bytes[wordOffset] ?? 0) << 24 | (bytes[wordOffset + 1] ?? 0) << 16 | (bytes[wordOffset + 2] ?? 0) << 8 | (bytes[wordOffset + 3] ?? 0);
|
|
7598
|
-
}
|
|
7599
|
-
for (let index = 16; index < 64; index += 1) {
|
|
7600
|
-
const s0 = rightRotate32(words[index - 15], 7) ^ rightRotate32(words[index - 15], 18) ^ words[index - 15] >>> 3;
|
|
7601
|
-
const s1 = rightRotate32(words[index - 2], 17) ^ rightRotate32(words[index - 2], 19) ^ words[index - 2] >>> 10;
|
|
7602
|
-
words[index] = words[index - 16] + s0 + words[index - 7] + s1 >>> 0;
|
|
7603
|
-
}
|
|
7604
|
-
let [a, b, c, d, e, f, g, h] = hash;
|
|
7605
|
-
for (let index = 0; index < 64; index += 1) {
|
|
7606
|
-
const s1 = rightRotate32(e, 6) ^ rightRotate32(e, 11) ^ rightRotate32(e, 25);
|
|
7607
|
-
const ch = e & f ^ ~e & g;
|
|
7608
|
-
const temp1 = h + s1 + ch + SHA256_ROUND_CONSTANTS[index] + words[index] >>> 0;
|
|
7609
|
-
const s0 = rightRotate32(a, 2) ^ rightRotate32(a, 13) ^ rightRotate32(a, 22);
|
|
7610
|
-
const maj = a & b ^ a & c ^ b & c;
|
|
7611
|
-
const temp2 = s0 + maj >>> 0;
|
|
7612
|
-
h = g;
|
|
7613
|
-
g = f;
|
|
7614
|
-
f = e;
|
|
7615
|
-
e = d + temp1 >>> 0;
|
|
7616
|
-
d = c;
|
|
7617
|
-
c = b;
|
|
7618
|
-
b = a;
|
|
7619
|
-
a = temp1 + temp2 >>> 0;
|
|
7620
|
-
}
|
|
7621
|
-
hash[0] = hash[0] + a >>> 0;
|
|
7622
|
-
hash[1] = hash[1] + b >>> 0;
|
|
7623
|
-
hash[2] = hash[2] + c >>> 0;
|
|
7624
|
-
hash[3] = hash[3] + d >>> 0;
|
|
7625
|
-
hash[4] = hash[4] + e >>> 0;
|
|
7626
|
-
hash[5] = hash[5] + f >>> 0;
|
|
7627
|
-
hash[6] = hash[6] + g >>> 0;
|
|
7628
|
-
hash[7] = hash[7] + h >>> 0;
|
|
7629
|
-
}
|
|
7630
|
-
return hash.map((word) => word.toString(16).padStart(8, "0")).join("");
|
|
7631
|
-
}
|
|
7632
|
-
function sanitizeIdentifierPart(value) {
|
|
7633
|
-
return value.trim().replace(/[^a-z0-9]+/gi, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
7634
|
-
}
|
|
7635
|
-
function validateIdentifierPart(rawValue, label, maxLength) {
|
|
7636
|
-
const sanitized = sanitizeIdentifierPart(rawValue);
|
|
7637
|
-
if (!sanitized) {
|
|
7638
|
-
throw new Error(
|
|
7639
|
-
`${label} must contain at least one letter or number after normalization. Use only letters, numbers, underscores, or hyphens.`
|
|
7640
|
-
);
|
|
7641
|
-
}
|
|
7642
|
-
if (sanitized.length > maxLength) {
|
|
7643
|
-
throw new Error(
|
|
7644
|
-
`${label} is too long after normalization (${sanitized.length}/${maxLength}). Shorten it to ${maxLength} characters or fewer. Normalized value: "${sanitized}".`
|
|
7645
|
-
);
|
|
7646
|
-
}
|
|
7647
|
-
return sanitized;
|
|
7648
|
-
}
|
|
7649
|
-
function normalizePlayName(value) {
|
|
7650
|
-
if (value.includes("/")) {
|
|
7651
|
-
throw new Error(
|
|
7652
|
-
'Play name cannot contain "/". Slash is reserved for qualified play references like "prebuilt/example" or "self/example".'
|
|
7653
|
-
);
|
|
7654
|
-
}
|
|
7655
|
-
return validateIdentifierPart(value, "Play name", PLAY_NAME_MAX_LENGTH);
|
|
7656
|
-
}
|
|
7657
|
-
function normalizePlayNameForSheet(value) {
|
|
7658
|
-
if (!value.includes("/")) {
|
|
7659
|
-
return normalizePlayName(value);
|
|
7660
|
-
}
|
|
7661
|
-
const digest = sha256Hex(value).slice(0, 12);
|
|
7662
|
-
const normalizedReference = sanitizeIdentifierPart(
|
|
7663
|
-
value.replace(/\//g, "__")
|
|
7664
|
-
);
|
|
7665
|
-
const prefixLength = Math.max(1, PLAY_NAME_MAX_LENGTH - digest.length - 1);
|
|
7666
|
-
const prefix = normalizedReference.slice(0, prefixLength).replace(/_+$/g, "") || "qualified_play";
|
|
7667
|
-
return `${prefix}_${digest}`;
|
|
7668
|
-
}
|
|
7669
|
-
function normalizeTableNamespace(value) {
|
|
7670
|
-
return validateIdentifierPart(
|
|
7671
|
-
value,
|
|
7672
|
-
"ctx.dataset() key",
|
|
7673
|
-
MAP_KEY_NAMESPACE_MAX_LENGTH
|
|
7674
|
-
);
|
|
7675
|
-
}
|
|
7676
|
-
function validatePlaySheetTableName(playName, tableNamespace) {
|
|
7677
|
-
const playSegment = normalizePlayNameForSheet(playName);
|
|
7678
|
-
const keySegment = normalizeTableNamespace(tableNamespace);
|
|
7679
|
-
const resolved = `${playSegment}_${keySegment}`;
|
|
7680
|
-
if (resolved.length > POSTGRES_IDENTIFIER_MAX_LENGTH) {
|
|
7681
|
-
throw new Error(
|
|
7682
|
-
`Play sheet table name is too long after normalization (${resolved.length}/63). Shorten the play name or ctx.dataset() key. Resolved table name: "${resolved}".`
|
|
7683
|
-
);
|
|
7684
|
-
}
|
|
7685
|
-
return resolved;
|
|
7686
|
-
}
|
|
7687
|
-
|
|
7688
7616
|
// src/cli/trace.ts
|
|
7689
7617
|
var cliTraceStartedAt = Date.now();
|
|
7690
7618
|
function isTruthyEnv(value) {
|
|
@@ -7735,6 +7663,11 @@ async function traceCliSpan(phase, fields, run) {
|
|
|
7735
7663
|
|
|
7736
7664
|
// src/cli/play-check-hints.ts
|
|
7737
7665
|
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.";
|
|
7666
|
+
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.";
|
|
7667
|
+
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.";
|
|
7668
|
+
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.";
|
|
7669
|
+
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.";
|
|
7670
|
+
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.";
|
|
7738
7671
|
function sourceLineForError(sourceCode, error) {
|
|
7739
7672
|
const match = error.match(/:(\d+):(\d+)\s/);
|
|
7740
7673
|
const lineNumber = match?.[1] ? Number(match[1]) : NaN;
|
|
@@ -7745,21 +7678,65 @@ function looksLikeInvalidExtractedGetter(error, sourceLine) {
|
|
|
7745
7678
|
if (!/Property '[^']+' does not exist on type/.test(error)) return false;
|
|
7746
7679
|
return /\bextracted(?:Values|Lists)\s*\./.test(sourceLine);
|
|
7747
7680
|
}
|
|
7681
|
+
function looksLikeDatasetApiMisuse(error, sourceLine) {
|
|
7682
|
+
return /Property '(?:rows|toArray|forEach|map|filter|reduce)' does not exist on type '[^']*PlayDataset/.test(
|
|
7683
|
+
error
|
|
7684
|
+
) || /\b(?:\.rows|\.toArray\(\)|\.forEach\(|\.map\(|\.filter\(|\.reduce\()/.test(
|
|
7685
|
+
sourceLine
|
|
7686
|
+
);
|
|
7687
|
+
}
|
|
7688
|
+
function looksLikeRowPropertyMismatch(error, sourceLine) {
|
|
7689
|
+
if (!/Property '[^']+' does not exist on type/.test(error)) return false;
|
|
7690
|
+
if (looksLikeInvalidExtractedGetter(error, sourceLine)) return false;
|
|
7691
|
+
return /\brow\.[A-Za-z_][A-Za-z0-9_]*/.test(sourceLine);
|
|
7692
|
+
}
|
|
7693
|
+
function looksLikeToolsExecuteSignature(error, sourceLine) {
|
|
7694
|
+
return /ctx\.tools\.execute requires a request object/i.test(error) || /Expected 1 arguments?, but got [2-9]/.test(error) && /\btools\.execute\(/.test(sourceLine);
|
|
7695
|
+
}
|
|
7696
|
+
function looksLikeRunPlaySignature(error, sourceLine) {
|
|
7697
|
+
return /ctx\.runPlay/i.test(error) || /(?:Expected|Argument of type|No overload matches)/.test(error) && /\brunPlay\(/.test(sourceLine);
|
|
7698
|
+
}
|
|
7699
|
+
function looksLikeMapBackedChild(error) {
|
|
7700
|
+
return /map-backed child play|direct-run-only|cannot call a map-backed|own durable table/i.test(
|
|
7701
|
+
error
|
|
7702
|
+
);
|
|
7703
|
+
}
|
|
7704
|
+
function hintForError(error, sourceLine) {
|
|
7705
|
+
if (looksLikeInvalidExtractedGetter(error, sourceLine)) {
|
|
7706
|
+
return EXTRACTED_GETTER_ERROR_HINT;
|
|
7707
|
+
}
|
|
7708
|
+
if (looksLikeDatasetApiMisuse(error, sourceLine)) {
|
|
7709
|
+
return DATASET_API_HINT;
|
|
7710
|
+
}
|
|
7711
|
+
if (looksLikeToolsExecuteSignature(error, sourceLine)) {
|
|
7712
|
+
return TOOLS_EXECUTE_SIGNATURE_HINT;
|
|
7713
|
+
}
|
|
7714
|
+
if (looksLikeMapBackedChild(error)) {
|
|
7715
|
+
return MAP_BACKED_CHILD_HINT;
|
|
7716
|
+
}
|
|
7717
|
+
if (looksLikeRunPlaySignature(error, sourceLine)) {
|
|
7718
|
+
return RUN_PLAY_SIGNATURE_HINT;
|
|
7719
|
+
}
|
|
7720
|
+
if (looksLikeRowPropertyMismatch(error, sourceLine)) {
|
|
7721
|
+
return ROW_PROPERTY_HINT;
|
|
7722
|
+
}
|
|
7723
|
+
return null;
|
|
7724
|
+
}
|
|
7748
7725
|
function addPlayCheckRepairHints(input2) {
|
|
7749
|
-
|
|
7726
|
+
const addedHints = /* @__PURE__ */ new Set();
|
|
7750
7727
|
return input2.errors.map((error) => {
|
|
7751
7728
|
const line = sourceLineForError(input2.sourceCode, error);
|
|
7752
|
-
|
|
7729
|
+
const hint = hintForError(error, line);
|
|
7730
|
+
if (!hint || addedHints.has(hint) || error.includes(hint)) {
|
|
7753
7731
|
return error;
|
|
7754
7732
|
}
|
|
7755
|
-
|
|
7733
|
+
addedHints.add(hint);
|
|
7756
7734
|
return `${error}
|
|
7757
|
-
${
|
|
7735
|
+
${hint}`;
|
|
7758
7736
|
});
|
|
7759
7737
|
}
|
|
7760
7738
|
|
|
7761
7739
|
// src/cli/commands/play.ts
|
|
7762
|
-
var PLAY_START_STREAM_FAST_COMPLETION_WAIT_MS = 2500;
|
|
7763
7740
|
var PLAY_RUN_RESERVED_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
7764
7741
|
"--json",
|
|
7765
7742
|
"--wait",
|
|
@@ -7869,10 +7846,10 @@ function materializeRemotePlaySource(input2) {
|
|
|
7869
7846
|
if (existingSource === input2.sourceCode) {
|
|
7870
7847
|
return { path: outputPath, status: "unchanged", created: false };
|
|
7871
7848
|
}
|
|
7872
|
-
|
|
7849
|
+
writeFileSync7(outputPath, input2.sourceCode, "utf-8");
|
|
7873
7850
|
return { path: outputPath, status: "updated", created: false };
|
|
7874
7851
|
}
|
|
7875
|
-
|
|
7852
|
+
writeFileSync7(outputPath, input2.sourceCode, "utf-8");
|
|
7876
7853
|
return { path: outputPath, status: "created", created: true };
|
|
7877
7854
|
}
|
|
7878
7855
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -8311,8 +8288,6 @@ var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
|
8311
8288
|
"cancelled"
|
|
8312
8289
|
]);
|
|
8313
8290
|
var PLAY_START_TRANSIENT_RETRY_DELAYS_MS = [500, 1500];
|
|
8314
|
-
var PLAY_CUSTOMER_STORAGE_SCHEMA_NAME = "storage";
|
|
8315
|
-
var PLAY_INTERNAL_STEP_RECEIPT_TABLE = "_deepline_step_receipts";
|
|
8316
8291
|
function getEventPayload(event) {
|
|
8317
8292
|
return event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
8318
8293
|
}
|
|
@@ -8366,36 +8341,8 @@ function getLogLinesFromLiveEvent(event) {
|
|
|
8366
8341
|
const lines = getEventPayload(event).lines;
|
|
8367
8342
|
return Array.isArray(lines) ? lines.filter((line) => typeof line === "string") : [];
|
|
8368
8343
|
}
|
|
8369
|
-
function
|
|
8370
|
-
return `
|
|
8371
|
-
}
|
|
8372
|
-
function quoteSqlLiteral(value) {
|
|
8373
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
8374
|
-
}
|
|
8375
|
-
function buildDebugDbQueryCommand(sql) {
|
|
8376
|
-
return `deepline db query --sql ${shellSingleQuote(sql)} --max-rows 20 --json`;
|
|
8377
|
-
}
|
|
8378
|
-
function buildStepReceiptsDebugCommand(runId) {
|
|
8379
|
-
const table = `${quoteSqlIdentifier(
|
|
8380
|
-
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8381
|
-
)}.${quoteSqlIdentifier(PLAY_INTERNAL_STEP_RECEIPT_TABLE)}`;
|
|
8382
|
-
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`;
|
|
8383
|
-
return buildDebugDbQueryCommand(sql);
|
|
8384
|
-
}
|
|
8385
|
-
function buildMapTableDebugCommand(input2) {
|
|
8386
|
-
try {
|
|
8387
|
-
const tableName = validatePlaySheetTableName(
|
|
8388
|
-
input2.playName,
|
|
8389
|
-
input2.tableNamespace
|
|
8390
|
-
);
|
|
8391
|
-
const table = `${quoteSqlIdentifier(
|
|
8392
|
-
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8393
|
-
)}.${quoteSqlIdentifier(tableName)}`;
|
|
8394
|
-
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(input2.runId)} limit 20`;
|
|
8395
|
-
return buildDebugDbQueryCommand(sql);
|
|
8396
|
-
} catch {
|
|
8397
|
-
return null;
|
|
8398
|
-
}
|
|
8344
|
+
function buildRunInspectCommand(runId) {
|
|
8345
|
+
return `deepline runs get ${runId} --full --json`;
|
|
8399
8346
|
}
|
|
8400
8347
|
function extractTableNamespaceFromLiveEvent(event) {
|
|
8401
8348
|
const payload = getEventPayload(event);
|
|
@@ -8420,7 +8367,7 @@ function emitLiveDebugTableHints(input2) {
|
|
|
8420
8367
|
if (!input2.state.emittedDebugKeys.has(receiptsKey)) {
|
|
8421
8368
|
input2.state.emittedDebugKeys.add(receiptsKey);
|
|
8422
8369
|
input2.progress.writeLine(
|
|
8423
|
-
`
|
|
8370
|
+
`Inspect run output: ${buildRunInspectCommand(input2.runId)}`,
|
|
8424
8371
|
process.stdout
|
|
8425
8372
|
);
|
|
8426
8373
|
}
|
|
@@ -8432,17 +8379,9 @@ function emitLiveDebugTableHints(input2) {
|
|
|
8432
8379
|
if (input2.state.emittedDebugKeys.has(tableKey)) {
|
|
8433
8380
|
return;
|
|
8434
8381
|
}
|
|
8435
|
-
const command = buildMapTableDebugCommand({
|
|
8436
|
-
playName: input2.playName,
|
|
8437
|
-
runId: input2.runId,
|
|
8438
|
-
tableNamespace
|
|
8439
|
-
});
|
|
8440
|
-
if (!command) {
|
|
8441
|
-
return;
|
|
8442
|
-
}
|
|
8443
8382
|
input2.state.emittedDebugKeys.add(tableKey);
|
|
8444
8383
|
input2.progress.writeLine(
|
|
8445
|
-
`
|
|
8384
|
+
`Possible map table ${tableNamespace}: created only after this ctx.map(...).run(...) executes. Inspect returned datasets with ${buildRunInspectCommand(input2.runId)}`,
|
|
8446
8385
|
process.stdout
|
|
8447
8386
|
);
|
|
8448
8387
|
}
|
|
@@ -8646,7 +8585,7 @@ async function waitForPlayCompletionByStream(input2) {
|
|
|
8646
8585
|
}
|
|
8647
8586
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8648
8587
|
throw new DeeplineError(
|
|
8649
|
-
`Play
|
|
8588
|
+
`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}'.`,
|
|
8650
8589
|
void 0,
|
|
8651
8590
|
"PLAY_LIVE_STREAM_ENDED",
|
|
8652
8591
|
{
|
|
@@ -8702,10 +8641,6 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8702
8641
|
let eventCount = 0;
|
|
8703
8642
|
let firstRunIdMs = null;
|
|
8704
8643
|
let lastPhase = null;
|
|
8705
|
-
const startRequest = {
|
|
8706
|
-
...input2.request,
|
|
8707
|
-
waitForCompletionMs: typeof input2.request.waitForCompletionMs === "number" ? input2.request.waitForCompletionMs : PLAY_START_STREAM_FAST_COMPLETION_WAIT_MS
|
|
8708
|
-
};
|
|
8709
8644
|
const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
|
|
8710
8645
|
() => {
|
|
8711
8646
|
timedOut = true;
|
|
@@ -8714,7 +8649,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8714
8649
|
Math.max(1, input2.waitTimeoutMs)
|
|
8715
8650
|
);
|
|
8716
8651
|
try {
|
|
8717
|
-
for await (const event of input2.client.startPlayRunStream(
|
|
8652
|
+
for await (const event of input2.client.startPlayRunStream(input2.request, {
|
|
8718
8653
|
signal: controller.signal
|
|
8719
8654
|
})) {
|
|
8720
8655
|
eventCount += 1;
|
|
@@ -8807,7 +8742,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8807
8742
|
const reason = error instanceof Error ? error.message : String(error);
|
|
8808
8743
|
if (!input2.jsonOutput) {
|
|
8809
8744
|
process.stderr.write(
|
|
8810
|
-
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
|
|
8745
|
+
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to canonical run stream (${reason})
|
|
8811
8746
|
`
|
|
8812
8747
|
);
|
|
8813
8748
|
}
|
|
@@ -8844,7 +8779,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8844
8779
|
if (lastKnownWorkflowId) {
|
|
8845
8780
|
if (!input2.jsonOutput) {
|
|
8846
8781
|
input2.progress.writeLine(
|
|
8847
|
-
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
|
|
8782
|
+
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to canonical run stream`
|
|
8848
8783
|
);
|
|
8849
8784
|
}
|
|
8850
8785
|
recordCliTrace({
|
|
@@ -8874,7 +8809,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8874
8809
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8875
8810
|
const idSuffix = lastKnownWorkflowId ? ` runId=${lastKnownWorkflowId}` : "";
|
|
8876
8811
|
throw new DeeplineError(
|
|
8877
|
-
`Play start stream ended before
|
|
8812
|
+
`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>'.`,
|
|
8878
8813
|
void 0,
|
|
8879
8814
|
"PLAY_START_STREAM_ENDED",
|
|
8880
8815
|
{
|
|
@@ -9222,6 +9157,32 @@ function formatPlayErrorForDisplay(status, error) {
|
|
|
9222
9157
|
}
|
|
9223
9158
|
return error;
|
|
9224
9159
|
}
|
|
9160
|
+
function isGenericInternalServerError(error) {
|
|
9161
|
+
if (!error) return false;
|
|
9162
|
+
return /^(?:internalservererror|internal server error|http 500|500)$/i.test(
|
|
9163
|
+
error.trim()
|
|
9164
|
+
);
|
|
9165
|
+
}
|
|
9166
|
+
function selectRunErrorForDisplay(status) {
|
|
9167
|
+
const progressError = getStringField(status.progress, "error");
|
|
9168
|
+
if (!isGenericInternalServerError(progressError)) {
|
|
9169
|
+
return progressError;
|
|
9170
|
+
}
|
|
9171
|
+
const directErrors = getRecordField(status, "errors");
|
|
9172
|
+
if (Array.isArray(directErrors)) {
|
|
9173
|
+
for (const entry of directErrors) {
|
|
9174
|
+
const message = getStringField(entry, "message");
|
|
9175
|
+
if (message && !isGenericInternalServerError(message)) {
|
|
9176
|
+
return message;
|
|
9177
|
+
}
|
|
9178
|
+
}
|
|
9179
|
+
}
|
|
9180
|
+
const directError = getStringField(status, "error");
|
|
9181
|
+
if (directError && !isGenericInternalServerError(directError)) {
|
|
9182
|
+
return directError;
|
|
9183
|
+
}
|
|
9184
|
+
return progressError;
|
|
9185
|
+
}
|
|
9225
9186
|
function normalizeRunStatusForEnvelope(status) {
|
|
9226
9187
|
const run = status.run ?? null;
|
|
9227
9188
|
return {
|
|
@@ -9359,8 +9320,7 @@ function compactPlayStatus(status) {
|
|
|
9359
9320
|
const billing = status && typeof status === "object" ? stripProviderSpendFromBilling(
|
|
9360
9321
|
status.billing
|
|
9361
9322
|
) : null;
|
|
9362
|
-
const
|
|
9363
|
-
const error = typeof progressError === "string" ? progressError : typeof status.error === "string" ? String(status.error) : null;
|
|
9323
|
+
const error = selectRunErrorForDisplay(status) ?? (typeof status.error === "string" ? String(status.error) : null);
|
|
9364
9324
|
const displayError = formatPlayErrorForDisplay(status, error);
|
|
9365
9325
|
return {
|
|
9366
9326
|
runId: status.runId,
|
|
@@ -9615,8 +9575,8 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
9615
9575
|
for (const warning of warnings) {
|
|
9616
9576
|
lines.push(` warning: ${warning}`);
|
|
9617
9577
|
}
|
|
9618
|
-
const progressError = status
|
|
9619
|
-
if (progressError
|
|
9578
|
+
const progressError = selectRunErrorForDisplay(status);
|
|
9579
|
+
if (progressError) {
|
|
9620
9580
|
const billing = extractBillingForStatus(status, progressError);
|
|
9621
9581
|
if (isInsufficientCreditsBilling(billing)) {
|
|
9622
9582
|
lines.push(...buildInsufficientCreditsSummaryLines({ status, billing }));
|
|
@@ -9668,9 +9628,6 @@ var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
|
9668
9628
|
function shellSingleQuote(value) {
|
|
9669
9629
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
9670
9630
|
}
|
|
9671
|
-
function sqlStringLiteral(value) {
|
|
9672
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
9673
|
-
}
|
|
9674
9631
|
function runExportRetryCommand(runId, outPath, datasetPath) {
|
|
9675
9632
|
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote(resolve10(outPath))}`;
|
|
9676
9633
|
}
|
|
@@ -9689,26 +9646,6 @@ function extractRunPlayName(status) {
|
|
|
9689
9646
|
}
|
|
9690
9647
|
return null;
|
|
9691
9648
|
}
|
|
9692
|
-
function normalizeCustomerDbIdentifier(value) {
|
|
9693
|
-
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
9694
|
-
}
|
|
9695
|
-
function buildCustomerDbQueryPlan(input2) {
|
|
9696
|
-
const playName = extractRunPlayName(input2.status);
|
|
9697
|
-
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9698
|
-
if (!playName || !tableNamespace || input2.rowsInfo.totalRows <= 0) {
|
|
9699
|
-
return null;
|
|
9700
|
-
}
|
|
9701
|
-
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
9702
|
-
tableNamespace
|
|
9703
|
-
)}`;
|
|
9704
|
-
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input2.status.runId)} limit ${input2.rowsInfo.totalRows}`;
|
|
9705
|
-
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input2.rowsInfo.totalRows}`;
|
|
9706
|
-
return {
|
|
9707
|
-
sql,
|
|
9708
|
-
json: `${base} --json`,
|
|
9709
|
-
csv: `${base} --format csv --out ${shellSingleQuote(resolve10(input2.outPath))}`
|
|
9710
|
-
};
|
|
9711
|
-
}
|
|
9712
9649
|
function exportableSheetRow(row) {
|
|
9713
9650
|
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
9714
9651
|
return null;
|
|
@@ -10055,8 +9992,12 @@ function renderServerResultView(value) {
|
|
|
10055
9992
|
lines.push(
|
|
10056
9993
|
` ${String(table.tableNamespace ?? "table")}${lineLabel}: ${rowLabel}${details.join(" ")}`
|
|
10057
9994
|
);
|
|
10058
|
-
if (typeof table.queryDatasetCommand === "string") {
|
|
10059
|
-
lines.push(`
|
|
9995
|
+
if (typeof table.queryDatasetCommand === "string" && typeof table.rowCount === "number" && table.rowCount > 0) {
|
|
9996
|
+
lines.push(` debug backing table: ${table.queryDatasetCommand}`);
|
|
9997
|
+
} else if (typeof table.queryDatasetCommand === "string") {
|
|
9998
|
+
lines.push(
|
|
9999
|
+
" no rows observed for this run; backing table is created only if this map ran"
|
|
10000
|
+
);
|
|
10060
10001
|
}
|
|
10061
10002
|
if (table.debugHelp && typeof table.debugHelp === "object" && !Array.isArray(table.debugHelp)) {
|
|
10062
10003
|
const debugHelp = table.debugHelp;
|
|
@@ -10402,9 +10343,51 @@ function printToolGetterHints(hints) {
|
|
|
10402
10343
|
async function handlePlayCheck(args) {
|
|
10403
10344
|
const options = parsePlayCheckOptions(args);
|
|
10404
10345
|
if (!isFileTarget(options.target)) {
|
|
10405
|
-
const
|
|
10406
|
-
|
|
10407
|
-
|
|
10346
|
+
const client2 = new DeeplineClient();
|
|
10347
|
+
try {
|
|
10348
|
+
await assertCanonicalNamedPlayReference(client2, options.target);
|
|
10349
|
+
const play = await client2.describePlay(
|
|
10350
|
+
parseReferencedPlayTarget2(options.target).playName,
|
|
10351
|
+
{ compact: true }
|
|
10352
|
+
);
|
|
10353
|
+
const result2 = {
|
|
10354
|
+
valid: true,
|
|
10355
|
+
target: options.target,
|
|
10356
|
+
name: play.name,
|
|
10357
|
+
reference: play.reference ?? options.target,
|
|
10358
|
+
origin: play.origin ?? null,
|
|
10359
|
+
ownerType: play.ownerType ?? null,
|
|
10360
|
+
inputSchema: play.inputSchema ?? null,
|
|
10361
|
+
outputSchema: play.outputSchema ?? null,
|
|
10362
|
+
staticPipeline: play.staticPipeline ?? null,
|
|
10363
|
+
note: "Named/prebuilt play contract is available. No run was started."
|
|
10364
|
+
};
|
|
10365
|
+
if (options.jsonOutput) {
|
|
10366
|
+
process.stdout.write(`${JSON.stringify(result2)}
|
|
10367
|
+
`);
|
|
10368
|
+
} else {
|
|
10369
|
+
console.log(`\u2713 ${result2.reference} passed named play contract check`);
|
|
10370
|
+
console.log(" no run started; no Deepline credits spent");
|
|
10371
|
+
if (play.runCommand) console.log(` run: ${play.runCommand}`);
|
|
10372
|
+
}
|
|
10373
|
+
return 0;
|
|
10374
|
+
} catch (error) {
|
|
10375
|
+
const resolved = resolve10(options.target);
|
|
10376
|
+
const message = error instanceof Error && error.message ? error.message : `File not found: ${resolved}`;
|
|
10377
|
+
if (options.jsonOutput) {
|
|
10378
|
+
process.stdout.write(
|
|
10379
|
+
`${JSON.stringify({
|
|
10380
|
+
valid: false,
|
|
10381
|
+
target: options.target,
|
|
10382
|
+
errors: [message]
|
|
10383
|
+
})}
|
|
10384
|
+
`
|
|
10385
|
+
);
|
|
10386
|
+
} else {
|
|
10387
|
+
console.error(message);
|
|
10388
|
+
}
|
|
10389
|
+
return 1;
|
|
10390
|
+
}
|
|
10408
10391
|
}
|
|
10409
10392
|
const absolutePlayPath = resolve10(options.target);
|
|
10410
10393
|
const sourceCode = readFileSync6(absolutePlayPath, "utf-8");
|
|
@@ -10941,7 +10924,7 @@ async function handleRunLogs(args) {
|
|
|
10941
10924
|
const status = await client.runs.get(runId);
|
|
10942
10925
|
const logs = status.progress?.logs ?? [];
|
|
10943
10926
|
if (outPath) {
|
|
10944
|
-
|
|
10927
|
+
writeFileSync7(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
10945
10928
|
printCommandEnvelope(
|
|
10946
10929
|
{
|
|
10947
10930
|
runId: status.runId,
|
|
@@ -11051,18 +11034,9 @@ async function handleRunExport(args) {
|
|
|
11051
11034
|
datasetPath
|
|
11052
11035
|
});
|
|
11053
11036
|
const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
|
|
11054
|
-
const queryPlan = exportResult && outPath ? buildCustomerDbQueryPlan({
|
|
11055
|
-
status,
|
|
11056
|
-
rowsInfo: exportResult.rowsInfo,
|
|
11057
|
-
outPath
|
|
11058
|
-
}) : null;
|
|
11059
11037
|
const next = {
|
|
11060
11038
|
...buildRunNextCommands(status),
|
|
11061
|
-
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
|
|
11062
|
-
...queryPlan ? {
|
|
11063
|
-
queryJson: queryPlan.json,
|
|
11064
|
-
queryCsv: queryPlan.csv
|
|
11065
|
-
} : {}
|
|
11039
|
+
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
|
|
11066
11040
|
};
|
|
11067
11041
|
const payload = {
|
|
11068
11042
|
runId: status.runId,
|
|
@@ -11071,13 +11045,6 @@ async function handleRunExport(args) {
|
|
|
11071
11045
|
source,
|
|
11072
11046
|
rowCount: exportResult?.rowsInfo.totalRows ?? null,
|
|
11073
11047
|
columns: exportResult?.rowsInfo.columns ?? [],
|
|
11074
|
-
...queryPlan ? {
|
|
11075
|
-
query: {
|
|
11076
|
-
sql: queryPlan.sql,
|
|
11077
|
-
json: queryPlan.json,
|
|
11078
|
-
csv: queryPlan.csv
|
|
11079
|
-
}
|
|
11080
|
-
} : {},
|
|
11081
11048
|
...metadataOutPath ? { metadata_path: metadataOutPath } : {},
|
|
11082
11049
|
local: { csv_path: exportResult?.path ?? null },
|
|
11083
11050
|
next,
|
|
@@ -11087,15 +11054,14 @@ async function handleRunExport(args) {
|
|
|
11087
11054
|
title: "run export",
|
|
11088
11055
|
lines: [
|
|
11089
11056
|
`Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
|
|
11090
|
-
...source ? [`source=${source}`] : []
|
|
11091
|
-
...queryPlan ? [`query=${queryPlan.json}`] : []
|
|
11057
|
+
...source ? [`source=${source}`] : []
|
|
11092
11058
|
]
|
|
11093
11059
|
}
|
|
11094
11060
|
]
|
|
11095
11061
|
}
|
|
11096
11062
|
};
|
|
11097
11063
|
if (metadataOutPath) {
|
|
11098
|
-
|
|
11064
|
+
writeFileSync7(
|
|
11099
11065
|
metadataOutPath,
|
|
11100
11066
|
`${JSON.stringify(payload, null, 2)}
|
|
11101
11067
|
`,
|
|
@@ -11268,7 +11234,8 @@ function parsePlaySearchOptions(args) {
|
|
|
11268
11234
|
return {
|
|
11269
11235
|
query,
|
|
11270
11236
|
jsonOutput: argsWantJson(args),
|
|
11271
|
-
compact: args.includes("--compact")
|
|
11237
|
+
compact: args.includes("--compact"),
|
|
11238
|
+
prebuiltOnly: args.includes("--prebuilt")
|
|
11272
11239
|
};
|
|
11273
11240
|
}
|
|
11274
11241
|
function printPlayDescription(play) {
|
|
@@ -11316,6 +11283,7 @@ function printPlayDescription(play) {
|
|
|
11316
11283
|
console.log(` ${line}`);
|
|
11317
11284
|
}
|
|
11318
11285
|
}
|
|
11286
|
+
console.log(` Describe: deepline plays describe ${reference} --json`);
|
|
11319
11287
|
console.log(` Run: ${play.runCommand}`);
|
|
11320
11288
|
const cloneEditStarter = play.cloneEditStarter ?? buildCloneEditStarter(play);
|
|
11321
11289
|
if (cloneEditStarter) {
|
|
@@ -11323,6 +11291,31 @@ function printPlayDescription(play) {
|
|
|
11323
11291
|
console.log(` Check starter: ${cloneEditStarter.checkCommand}`);
|
|
11324
11292
|
}
|
|
11325
11293
|
}
|
|
11294
|
+
function inputFieldNames(schema) {
|
|
11295
|
+
const fields = Array.isArray(schema?.fields) ? schema.fields : [];
|
|
11296
|
+
return fields.map(
|
|
11297
|
+
(field) => field && typeof field === "object" ? String(field.name ?? "").trim() : ""
|
|
11298
|
+
).filter(Boolean);
|
|
11299
|
+
}
|
|
11300
|
+
function printCompactPlaySearchResult(play) {
|
|
11301
|
+
const reference = formatPlayListReference(play);
|
|
11302
|
+
const aliases = play.aliases.slice(0, 6).join(", ");
|
|
11303
|
+
console.log(`Play: ${reference}`);
|
|
11304
|
+
if (play.displayName && play.displayName !== play.name) {
|
|
11305
|
+
console.log(` Display name: ${play.displayName}`);
|
|
11306
|
+
}
|
|
11307
|
+
if (aliases) {
|
|
11308
|
+
console.log(` Aliases: ${aliases}`);
|
|
11309
|
+
}
|
|
11310
|
+
const fields = inputFieldNames(play.inputSchema);
|
|
11311
|
+
if (fields.length > 0) {
|
|
11312
|
+
console.log(` Inputs: ${fields.join(", ")}`);
|
|
11313
|
+
} else if (play.inputSchema) {
|
|
11314
|
+
console.log(" Inputs: see describe");
|
|
11315
|
+
}
|
|
11316
|
+
console.log(` Describe: deepline plays describe ${reference} --json`);
|
|
11317
|
+
console.log(` Run: ${play.runCommand}`);
|
|
11318
|
+
}
|
|
11326
11319
|
function compactPlaySchema(schema) {
|
|
11327
11320
|
if (!schema) return null;
|
|
11328
11321
|
const fields = Array.isArray(schema.fields) ? schema.fields.map(
|
|
@@ -11386,22 +11379,44 @@ async function handlePlaySearch(args) {
|
|
|
11386
11379
|
return 1;
|
|
11387
11380
|
}
|
|
11388
11381
|
const client = new DeeplineClient();
|
|
11389
|
-
const plays = await client.searchPlays({
|
|
11382
|
+
const plays = (await client.searchPlays({
|
|
11390
11383
|
query: options.query,
|
|
11391
11384
|
compact: options.compact
|
|
11392
|
-
})
|
|
11385
|
+
})).filter(
|
|
11386
|
+
(play) => options.prebuiltOnly ? play.origin === "prebuilt" || play.ownerType === "deepline" : true
|
|
11387
|
+
);
|
|
11393
11388
|
if (options.jsonOutput) {
|
|
11394
|
-
|
|
11395
|
-
|
|
11389
|
+
const jsonPlays = options.prebuiltOnly ? plays.map((play) => ({
|
|
11390
|
+
...play,
|
|
11391
|
+
inputSchema: compactPlaySchema(play.inputSchema)
|
|
11392
|
+
})) : plays;
|
|
11393
|
+
process.stdout.write(
|
|
11394
|
+
`${JSON.stringify({
|
|
11395
|
+
plays: jsonPlays,
|
|
11396
|
+
total: jsonPlays.length,
|
|
11397
|
+
truncated: false
|
|
11398
|
+
})}
|
|
11399
|
+
`
|
|
11400
|
+
);
|
|
11396
11401
|
return 0;
|
|
11397
11402
|
}
|
|
11398
|
-
|
|
11403
|
+
const displayPlays = options.prebuiltOnly ? plays.slice(0, 5) : plays;
|
|
11404
|
+
process.stdout.write(
|
|
11405
|
+
`${plays.length} plays found${options.prebuiltOnly && plays.length > displayPlays.length ? `; showing top ${displayPlays.length}` : ""}:
|
|
11399
11406
|
|
|
11400
|
-
`
|
|
11401
|
-
|
|
11402
|
-
|
|
11407
|
+
`
|
|
11408
|
+
);
|
|
11409
|
+
for (const play of displayPlays) {
|
|
11410
|
+
if (options.prebuiltOnly) {
|
|
11411
|
+
printCompactPlaySearchResult(play);
|
|
11412
|
+
} else {
|
|
11413
|
+
printPlayDescription(play);
|
|
11414
|
+
}
|
|
11403
11415
|
console.log("");
|
|
11404
11416
|
}
|
|
11417
|
+
if (options.prebuiltOnly && plays.length > displayPlays.length) {
|
|
11418
|
+
console.log("Use --json for the full machine-readable result set.");
|
|
11419
|
+
}
|
|
11405
11420
|
return 0;
|
|
11406
11421
|
}
|
|
11407
11422
|
function normalizePlayGrepText(value) {
|
|
@@ -11668,15 +11683,18 @@ Common commands:
|
|
|
11668
11683
|
deepline plays get person-linkedin-to-email --json
|
|
11669
11684
|
`
|
|
11670
11685
|
);
|
|
11671
|
-
play.command("check <target>").description("
|
|
11686
|
+
play.command("check <target>").description("Check a local play file or named/prebuilt play contract.").addHelpText(
|
|
11672
11687
|
"after",
|
|
11673
11688
|
`
|
|
11674
11689
|
Notes:
|
|
11675
11690
|
Validates a local play without storing it, promoting it, or starting a run.
|
|
11676
11691
|
This uses the authoritative cloud preflight path.
|
|
11692
|
+
For named or prebuilt plays, validates that the contract is discoverable
|
|
11693
|
+
without starting a run or spending Deepline credits.
|
|
11677
11694
|
|
|
11678
11695
|
Examples:
|
|
11679
11696
|
deepline plays check my.play.ts
|
|
11697
|
+
deepline plays check prebuilt/name-and-domain-to-email-waterfall-batch
|
|
11680
11698
|
deepline plays check my.play.ts --json
|
|
11681
11699
|
`
|
|
11682
11700
|
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
|
|
@@ -11826,11 +11844,13 @@ Examples:
|
|
|
11826
11844
|
...options.json ? ["--json"] : []
|
|
11827
11845
|
]);
|
|
11828
11846
|
});
|
|
11829
|
-
const addPlaySearchCommand = (command) => command.description("Search saved and prebuilt plays.").addHelpText(
|
|
11847
|
+
const addPlaySearchCommand = (command) => command.description("Search saved and prebuilt plays.").option("--prebuilt", "Only show Deepline-managed prebuilt plays").addHelpText(
|
|
11830
11848
|
"after",
|
|
11831
11849
|
`
|
|
11832
11850
|
Notes:
|
|
11833
11851
|
Ranked discovery for workflows. Use describe on a result before running it.
|
|
11852
|
+
Prefer --prebuilt for new GTM tasks so old workspace scratchpads do not
|
|
11853
|
+
outrank Deepline-managed routes unless the user names one explicitly.
|
|
11834
11854
|
The grep alias is the same ranked retrieval surface with a more literal name
|
|
11835
11855
|
for agents that are filtering the play registry.
|
|
11836
11856
|
|
|
@@ -11842,6 +11862,7 @@ Examples:
|
|
|
11842
11862
|
).option("--compact", "Emit compact schemas").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
11843
11863
|
process.exitCode = await handlePlaySearch([
|
|
11844
11864
|
query,
|
|
11865
|
+
...options.prebuilt ? ["--prebuilt"] : [],
|
|
11845
11866
|
...options.compact ? ["--compact"] : [],
|
|
11846
11867
|
...options.json ? ["--json"] : []
|
|
11847
11868
|
]);
|
|
@@ -12089,7 +12110,7 @@ Notes:
|
|
|
12089
12110
|
Writes a returned dataset handle to the requested local CSV path. Use runs get
|
|
12090
12111
|
first to inspect dataset paths like result.rows or result.nested.contacts.
|
|
12091
12112
|
--metadata-out writes the same export metadata object returned by --json,
|
|
12092
|
-
including source
|
|
12113
|
+
including the source dataset path and row/column metadata.
|
|
12093
12114
|
|
|
12094
12115
|
Examples:
|
|
12095
12116
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
@@ -13796,12 +13817,12 @@ Examples:
|
|
|
13796
13817
|
|
|
13797
13818
|
// src/cli/commands/tools.ts
|
|
13798
13819
|
import { Option } from "commander";
|
|
13799
|
-
import { chmodSync, mkdtempSync, writeFileSync as
|
|
13820
|
+
import { chmodSync, mkdtempSync, writeFileSync as writeFileSync9 } from "fs";
|
|
13800
13821
|
import { tmpdir as tmpdir4 } from "os";
|
|
13801
13822
|
import { join as join10 } from "path";
|
|
13802
13823
|
|
|
13803
13824
|
// src/tool-output.ts
|
|
13804
|
-
import { mkdirSync as mkdirSync4, writeFileSync as
|
|
13825
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
13805
13826
|
import { homedir as homedir5 } from "os";
|
|
13806
13827
|
import { join as join9 } from "path";
|
|
13807
13828
|
function isPlainObject(value) {
|
|
@@ -13906,7 +13927,7 @@ function ensureOutputDir() {
|
|
|
13906
13927
|
function writeJsonOutputFile(payload, stem) {
|
|
13907
13928
|
const outputDir = ensureOutputDir();
|
|
13908
13929
|
const outputPath = join9(outputDir, `${stem}_${Date.now()}.json`);
|
|
13909
|
-
|
|
13930
|
+
writeFileSync8(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
13910
13931
|
return outputPath;
|
|
13911
13932
|
}
|
|
13912
13933
|
function writeCsvOutputFile(rows, stem) {
|
|
@@ -13934,7 +13955,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
13934
13955
|
for (const row of rows) {
|
|
13935
13956
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
13936
13957
|
}
|
|
13937
|
-
|
|
13958
|
+
writeFileSync8(outputPath, `${lines.join("\n")}
|
|
13938
13959
|
`, "utf-8");
|
|
13939
13960
|
const previewRows = rows.slice(0, 5);
|
|
13940
13961
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -14020,7 +14041,7 @@ async function listTools(args) {
|
|
|
14020
14041
|
const client = new DeeplineClient();
|
|
14021
14042
|
const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
|
|
14022
14043
|
const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
|
|
14023
|
-
const compact = args.includes("--compact");
|
|
14044
|
+
const compact = args.includes("--compact") || !args.includes("--json");
|
|
14024
14045
|
const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
14025
14046
|
const items = (await client.listTools({
|
|
14026
14047
|
...categoryFilter ? { categories: categoryFilter } : {}
|
|
@@ -14076,9 +14097,10 @@ async function searchTools(queryInput, options = {}) {
|
|
|
14076
14097
|
searchMode: options.searchMode,
|
|
14077
14098
|
includeSearchDebug: options.includeSearchDebug
|
|
14078
14099
|
});
|
|
14079
|
-
const
|
|
14100
|
+
const shouldCompact = options.compact || !options.json;
|
|
14101
|
+
const payload = shouldCompact && Array.isArray(result.tools) ? {
|
|
14080
14102
|
...result,
|
|
14081
|
-
tools: result.tools.map(compactTool)
|
|
14103
|
+
tools: result.tools.slice(0, 8).map(compactTool)
|
|
14082
14104
|
} : result;
|
|
14083
14105
|
printCommandEnvelope(payload, {
|
|
14084
14106
|
json: options.json || shouldEmitJson()
|
|
@@ -14119,7 +14141,8 @@ async function grepTools(queryInput, options = {}) {
|
|
|
14119
14141
|
mode
|
|
14120
14142
|
)
|
|
14121
14143
|
);
|
|
14122
|
-
const
|
|
14144
|
+
const shouldCompact = options.compact || !options.json;
|
|
14145
|
+
const outputTools = shouldCompact ? tools.slice(0, 8).map(compactTool) : tools;
|
|
14123
14146
|
printCommandEnvelope(
|
|
14124
14147
|
{
|
|
14125
14148
|
tools: outputTools,
|
|
@@ -14138,11 +14161,19 @@ async function grepTools(queryInput, options = {}) {
|
|
|
14138
14161
|
);
|
|
14139
14162
|
return 0;
|
|
14140
14163
|
}
|
|
14164
|
+
function numericToolField(tool, field) {
|
|
14165
|
+
const value = tool[field];
|
|
14166
|
+
return typeof value === "number" ? value : void 0;
|
|
14167
|
+
}
|
|
14141
14168
|
function compactTool(tool) {
|
|
14142
14169
|
const listed = toListedTool(tool);
|
|
14170
|
+
const searchScore = numericToolField(tool, "searchScore");
|
|
14171
|
+
const search_score = numericToolField(tool, "search_score");
|
|
14143
14172
|
return {
|
|
14144
14173
|
id: listed.id,
|
|
14145
14174
|
toolId: listed.toolId,
|
|
14175
|
+
...search_score !== void 0 ? { search_score } : {},
|
|
14176
|
+
...searchScore !== void 0 ? { searchScore } : {},
|
|
14146
14177
|
provider: listed.provider,
|
|
14147
14178
|
displayName: listed.displayName,
|
|
14148
14179
|
description: listed.description,
|
|
@@ -14463,7 +14494,7 @@ async function getTool(toolId, options = {}) {
|
|
|
14463
14494
|
}
|
|
14464
14495
|
if (shouldEmitJson()) {
|
|
14465
14496
|
process.stdout.write(
|
|
14466
|
-
`${JSON.stringify(
|
|
14497
|
+
`${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
|
|
14467
14498
|
`
|
|
14468
14499
|
);
|
|
14469
14500
|
return 0;
|
|
@@ -14788,8 +14819,8 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
|
14788
14819
|
invalidGetterHint: "If TypeScript says an extractedValues/extractedLists property does not exist, that field is not a declared Deepline getter.",
|
|
14789
14820
|
observeActualShape: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
14790
14821
|
observedOutput: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
14791
|
-
forPlayGetterBugs: "Run
|
|
14792
|
-
executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run
|
|
14822
|
+
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.",
|
|
14823
|
+
executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run output and returned dataset handles."
|
|
14793
14824
|
},
|
|
14794
14825
|
starterScript: {
|
|
14795
14826
|
path: starterScript.path,
|
|
@@ -15040,7 +15071,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
15040
15071
|
};
|
|
15041
15072
|
});
|
|
15042
15073
|
`;
|
|
15043
|
-
|
|
15074
|
+
writeFileSync9(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
15044
15075
|
return {
|
|
15045
15076
|
path: scriptPath,
|
|
15046
15077
|
sourceCode: script,
|
|
@@ -15596,7 +15627,7 @@ import {
|
|
|
15596
15627
|
readdirSync as readdirSync2,
|
|
15597
15628
|
readFileSync as readFileSync7,
|
|
15598
15629
|
statSync as statSync2,
|
|
15599
|
-
writeFileSync as
|
|
15630
|
+
writeFileSync as writeFileSync10
|
|
15600
15631
|
} from "fs";
|
|
15601
15632
|
import { homedir as homedir6 } from "os";
|
|
15602
15633
|
import { dirname as dirname10, join as join12 } from "path";
|
|
@@ -15630,7 +15661,7 @@ function readLocalSkillsVersion(baseUrl) {
|
|
|
15630
15661
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
15631
15662
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
15632
15663
|
mkdirSync5(dirname10(path), { recursive: true });
|
|
15633
|
-
|
|
15664
|
+
writeFileSync10(path, `${version}
|
|
15634
15665
|
`, "utf-8");
|
|
15635
15666
|
}
|
|
15636
15667
|
function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
@@ -15813,6 +15844,7 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
15813
15844
|
}
|
|
15814
15845
|
|
|
15815
15846
|
// src/cli/index.ts
|
|
15847
|
+
var PREFLIGHT_TIMEOUT_MS = 3e3;
|
|
15816
15848
|
function asCommanderError(error) {
|
|
15817
15849
|
if (!(error instanceof Error) || !("code" in error)) {
|
|
15818
15850
|
return null;
|
|
@@ -15893,6 +15925,124 @@ async function runPlayRunnerHealthCheck() {
|
|
|
15893
15925
|
await rm2(dir, { recursive: true, force: true });
|
|
15894
15926
|
}
|
|
15895
15927
|
}
|
|
15928
|
+
function pickString(value, ...keys) {
|
|
15929
|
+
for (const key of keys) {
|
|
15930
|
+
const candidate = value[key];
|
|
15931
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
15932
|
+
return candidate;
|
|
15933
|
+
}
|
|
15934
|
+
}
|
|
15935
|
+
return null;
|
|
15936
|
+
}
|
|
15937
|
+
function preflightErrorMessage(error) {
|
|
15938
|
+
return error instanceof Error ? error.message : String(error);
|
|
15939
|
+
}
|
|
15940
|
+
async function runPreflightCheck() {
|
|
15941
|
+
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
15942
|
+
const healthController = new AbortController();
|
|
15943
|
+
const healthTimeout = setTimeout(
|
|
15944
|
+
() => healthController.abort(),
|
|
15945
|
+
PREFLIGHT_TIMEOUT_MS
|
|
15946
|
+
);
|
|
15947
|
+
const health = await fetch(new URL("/api/v2/health", baseUrl), {
|
|
15948
|
+
signal: healthController.signal
|
|
15949
|
+
}).then(async (response) => {
|
|
15950
|
+
const payload = await response.json().catch(() => ({}));
|
|
15951
|
+
return {
|
|
15952
|
+
status: response.ok ? pickString(payload, "status") ?? "ok" : "unreachable",
|
|
15953
|
+
version: pickString(payload, "version")
|
|
15954
|
+
};
|
|
15955
|
+
}).catch(() => ({ status: "unreachable", version: null })).finally(() => clearTimeout(healthTimeout));
|
|
15956
|
+
const apiKey = resolveApiKeyForBaseUrl(baseUrl);
|
|
15957
|
+
const http = apiKey ? new HttpClient(
|
|
15958
|
+
resolveConfig({
|
|
15959
|
+
baseUrl,
|
|
15960
|
+
apiKey,
|
|
15961
|
+
timeout: PREFLIGHT_TIMEOUT_MS,
|
|
15962
|
+
maxRetries: 0
|
|
15963
|
+
})
|
|
15964
|
+
) : null;
|
|
15965
|
+
const [auth, billing] = http ? await Promise.all([
|
|
15966
|
+
http.post("/api/v2/auth/cli/status", {
|
|
15967
|
+
api_key: apiKey,
|
|
15968
|
+
reveal: false
|
|
15969
|
+
}).catch((error) => ({
|
|
15970
|
+
status: "not_connected",
|
|
15971
|
+
connected: false,
|
|
15972
|
+
error: preflightErrorMessage(error)
|
|
15973
|
+
})),
|
|
15974
|
+
http.get("/api/v2/billing/balance").catch(
|
|
15975
|
+
(error) => ({
|
|
15976
|
+
balance: null,
|
|
15977
|
+
balance_display: "unavailable",
|
|
15978
|
+
balance_status: "unknown",
|
|
15979
|
+
error: preflightErrorMessage(error)
|
|
15980
|
+
})
|
|
15981
|
+
)
|
|
15982
|
+
]) : [
|
|
15983
|
+
{
|
|
15984
|
+
status: "not_connected",
|
|
15985
|
+
connected: false,
|
|
15986
|
+
error: "No API key found. Run: deepline auth register"
|
|
15987
|
+
},
|
|
15988
|
+
{
|
|
15989
|
+
balance: null,
|
|
15990
|
+
balance_display: "unavailable until authenticated",
|
|
15991
|
+
balance_status: "unknown"
|
|
15992
|
+
}
|
|
15993
|
+
];
|
|
15994
|
+
const authStatus = pickString(auth, "status") ?? "unknown";
|
|
15995
|
+
const billingRecord = billing;
|
|
15996
|
+
const balanceDisplay = pickString(billing, "balance_display", "balanceDisplay") ?? `${String(billingRecord.balance ?? 0)} Deepline Credits`;
|
|
15997
|
+
const balanceStatus = pickString(billing, "balance_status", "balanceStatus") ?? "unknown";
|
|
15998
|
+
return {
|
|
15999
|
+
status: health.status === "ok" && (authStatus === "connected" || authStatus === "claimed") ? "ok" : "check",
|
|
16000
|
+
host: baseUrl,
|
|
16001
|
+
health: {
|
|
16002
|
+
status: health.status,
|
|
16003
|
+
version: health.version ?? null
|
|
16004
|
+
},
|
|
16005
|
+
auth: {
|
|
16006
|
+
status: authStatus,
|
|
16007
|
+
connected: authStatus === "connected" || authStatus === "claimed",
|
|
16008
|
+
org_id: pickString(auth, "org_id", "orgId"),
|
|
16009
|
+
org_name: pickString(auth, "org_name", "orgName"),
|
|
16010
|
+
rate_limit_tier: pickString(auth, "rate_limit_tier", "rateLimitTier"),
|
|
16011
|
+
error: pickString(auth, "error")
|
|
16012
|
+
},
|
|
16013
|
+
billing: {
|
|
16014
|
+
balance: billingRecord.balance ?? null,
|
|
16015
|
+
balance_display: balanceDisplay,
|
|
16016
|
+
rough_usd_balance: billingRecord.rough_usd_balance ?? billingRecord.roughUsdBalance ?? null,
|
|
16017
|
+
balance_status: balanceStatus,
|
|
16018
|
+
error: pickString(billing, "error")
|
|
16019
|
+
},
|
|
16020
|
+
render: {
|
|
16021
|
+
sections: [
|
|
16022
|
+
{
|
|
16023
|
+
title: "preflight",
|
|
16024
|
+
lines: [
|
|
16025
|
+
`host: ${baseUrl}`,
|
|
16026
|
+
`health: ${health.status}`,
|
|
16027
|
+
`auth: ${authStatus}`,
|
|
16028
|
+
`billing: ${balanceDisplay} (${balanceStatus})`
|
|
16029
|
+
]
|
|
16030
|
+
}
|
|
16031
|
+
]
|
|
16032
|
+
}
|
|
16033
|
+
};
|
|
16034
|
+
}
|
|
16035
|
+
function printPreflightHuman(data) {
|
|
16036
|
+
const render = data.render;
|
|
16037
|
+
const lines = render?.sections?.flatMap((section) => section.lines ?? []);
|
|
16038
|
+
if (lines?.length) {
|
|
16039
|
+
process.stdout.write(`${lines.join("\n")}
|
|
16040
|
+
`);
|
|
16041
|
+
return;
|
|
16042
|
+
}
|
|
16043
|
+
process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
16044
|
+
`);
|
|
16045
|
+
}
|
|
15896
16046
|
async function main() {
|
|
15897
16047
|
const mainStartedAt = Date.now();
|
|
15898
16048
|
recordCliTrace({
|
|
@@ -15909,6 +16059,7 @@ async function main() {
|
|
|
15909
16059
|
"after",
|
|
15910
16060
|
`
|
|
15911
16061
|
Common commands:
|
|
16062
|
+
deepline preflight
|
|
15912
16063
|
deepline health
|
|
15913
16064
|
deepline auth status --json
|
|
15914
16065
|
deepline plays search email --json
|
|
@@ -15930,7 +16081,6 @@ Output:
|
|
|
15930
16081
|
|
|
15931
16082
|
Safety:
|
|
15932
16083
|
Commands that mutate state, open a browser, write files, stop work, or spend credits say so in their help.
|
|
15933
|
-
Use --no-open where available for CI and agent runs.
|
|
15934
16084
|
|
|
15935
16085
|
Exit codes:
|
|
15936
16086
|
0 success; 2 usage/local input error; 3 auth/permission error; 4 not found;
|
|
@@ -15972,6 +16122,26 @@ Exit codes:
|
|
|
15972
16122
|
registerDbCommands(program);
|
|
15973
16123
|
registerFeedbackCommands(program);
|
|
15974
16124
|
registerUpdateCommand(program);
|
|
16125
|
+
program.command("preflight").description("Run compact health, auth, and Deepline billing checks.").option("--json", "Force JSON output.").addHelpText(
|
|
16126
|
+
"after",
|
|
16127
|
+
`
|
|
16128
|
+
Notes:
|
|
16129
|
+
Read-only setup check for the configured Deepline host. Shows server health,
|
|
16130
|
+
auth connection, and customer-visible Deepline balance in one compact command.
|
|
16131
|
+
|
|
16132
|
+
Examples:
|
|
16133
|
+
deepline preflight
|
|
16134
|
+
deepline preflight --json
|
|
16135
|
+
`
|
|
16136
|
+
).action(async (options) => {
|
|
16137
|
+
const data = await runPreflightCheck();
|
|
16138
|
+
if (shouldEmitJson(options.json)) {
|
|
16139
|
+
process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
16140
|
+
`);
|
|
16141
|
+
} else {
|
|
16142
|
+
printPreflightHuman(data);
|
|
16143
|
+
}
|
|
16144
|
+
});
|
|
15975
16145
|
program.command("health").description("Check server health.").option("--json", "Force JSON output.").option(
|
|
15976
16146
|
"--play-runner",
|
|
15977
16147
|
"Run a tiny no-provider play to verify the full play execution plane."
|