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.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.78",
|
|
210
210
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
211
211
|
supportPolicy: {
|
|
212
|
-
latest: "0.1.
|
|
212
|
+
latest: "0.1.78",
|
|
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,16 +7678,61 @@ 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
|
|
|
@@ -7869,10 +7847,10 @@ function materializeRemotePlaySource(input2) {
|
|
|
7869
7847
|
if (existingSource === input2.sourceCode) {
|
|
7870
7848
|
return { path: outputPath, status: "unchanged", created: false };
|
|
7871
7849
|
}
|
|
7872
|
-
|
|
7850
|
+
writeFileSync7(outputPath, input2.sourceCode, "utf-8");
|
|
7873
7851
|
return { path: outputPath, status: "updated", created: false };
|
|
7874
7852
|
}
|
|
7875
|
-
|
|
7853
|
+
writeFileSync7(outputPath, input2.sourceCode, "utf-8");
|
|
7876
7854
|
return { path: outputPath, status: "created", created: true };
|
|
7877
7855
|
}
|
|
7878
7856
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -8311,8 +8289,6 @@ var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
|
8311
8289
|
"cancelled"
|
|
8312
8290
|
]);
|
|
8313
8291
|
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
8292
|
function getEventPayload(event) {
|
|
8317
8293
|
return event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
8318
8294
|
}
|
|
@@ -8366,36 +8342,8 @@ function getLogLinesFromLiveEvent(event) {
|
|
|
8366
8342
|
const lines = getEventPayload(event).lines;
|
|
8367
8343
|
return Array.isArray(lines) ? lines.filter((line) => typeof line === "string") : [];
|
|
8368
8344
|
}
|
|
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
|
-
}
|
|
8345
|
+
function buildRunInspectCommand(runId) {
|
|
8346
|
+
return `deepline runs get ${runId} --full --json`;
|
|
8399
8347
|
}
|
|
8400
8348
|
function extractTableNamespaceFromLiveEvent(event) {
|
|
8401
8349
|
const payload = getEventPayload(event);
|
|
@@ -8420,7 +8368,7 @@ function emitLiveDebugTableHints(input2) {
|
|
|
8420
8368
|
if (!input2.state.emittedDebugKeys.has(receiptsKey)) {
|
|
8421
8369
|
input2.state.emittedDebugKeys.add(receiptsKey);
|
|
8422
8370
|
input2.progress.writeLine(
|
|
8423
|
-
`
|
|
8371
|
+
`Inspect run output: ${buildRunInspectCommand(input2.runId)}`,
|
|
8424
8372
|
process.stdout
|
|
8425
8373
|
);
|
|
8426
8374
|
}
|
|
@@ -8432,17 +8380,9 @@ function emitLiveDebugTableHints(input2) {
|
|
|
8432
8380
|
if (input2.state.emittedDebugKeys.has(tableKey)) {
|
|
8433
8381
|
return;
|
|
8434
8382
|
}
|
|
8435
|
-
const command = buildMapTableDebugCommand({
|
|
8436
|
-
playName: input2.playName,
|
|
8437
|
-
runId: input2.runId,
|
|
8438
|
-
tableNamespace
|
|
8439
|
-
});
|
|
8440
|
-
if (!command) {
|
|
8441
|
-
return;
|
|
8442
|
-
}
|
|
8443
8383
|
input2.state.emittedDebugKeys.add(tableKey);
|
|
8444
8384
|
input2.progress.writeLine(
|
|
8445
|
-
`
|
|
8385
|
+
`Possible map table ${tableNamespace}: created only after this ctx.map(...).run(...) executes. Inspect returned datasets with ${buildRunInspectCommand(input2.runId)}`,
|
|
8446
8386
|
process.stdout
|
|
8447
8387
|
);
|
|
8448
8388
|
}
|
|
@@ -8646,7 +8586,7 @@ async function waitForPlayCompletionByStream(input2) {
|
|
|
8646
8586
|
}
|
|
8647
8587
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8648
8588
|
throw new DeeplineError(
|
|
8649
|
-
`Play
|
|
8589
|
+
`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
8590
|
void 0,
|
|
8651
8591
|
"PLAY_LIVE_STREAM_ENDED",
|
|
8652
8592
|
{
|
|
@@ -8807,7 +8747,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8807
8747
|
const reason = error instanceof Error ? error.message : String(error);
|
|
8808
8748
|
if (!input2.jsonOutput) {
|
|
8809
8749
|
process.stderr.write(
|
|
8810
|
-
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
|
|
8750
|
+
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to canonical run stream (${reason})
|
|
8811
8751
|
`
|
|
8812
8752
|
);
|
|
8813
8753
|
}
|
|
@@ -8844,7 +8784,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8844
8784
|
if (lastKnownWorkflowId) {
|
|
8845
8785
|
if (!input2.jsonOutput) {
|
|
8846
8786
|
input2.progress.writeLine(
|
|
8847
|
-
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
|
|
8787
|
+
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to canonical run stream`
|
|
8848
8788
|
);
|
|
8849
8789
|
}
|
|
8850
8790
|
recordCliTrace({
|
|
@@ -8874,7 +8814,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8874
8814
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8875
8815
|
const idSuffix = lastKnownWorkflowId ? ` runId=${lastKnownWorkflowId}` : "";
|
|
8876
8816
|
throw new DeeplineError(
|
|
8877
|
-
`Play start stream ended before
|
|
8817
|
+
`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
8818
|
void 0,
|
|
8879
8819
|
"PLAY_START_STREAM_ENDED",
|
|
8880
8820
|
{
|
|
@@ -9222,6 +9162,32 @@ function formatPlayErrorForDisplay(status, error) {
|
|
|
9222
9162
|
}
|
|
9223
9163
|
return error;
|
|
9224
9164
|
}
|
|
9165
|
+
function isGenericInternalServerError(error) {
|
|
9166
|
+
if (!error) return false;
|
|
9167
|
+
return /^(?:internalservererror|internal server error|http 500|500)$/i.test(
|
|
9168
|
+
error.trim()
|
|
9169
|
+
);
|
|
9170
|
+
}
|
|
9171
|
+
function selectRunErrorForDisplay(status) {
|
|
9172
|
+
const progressError = getStringField(status.progress, "error");
|
|
9173
|
+
if (!isGenericInternalServerError(progressError)) {
|
|
9174
|
+
return progressError;
|
|
9175
|
+
}
|
|
9176
|
+
const directErrors = getRecordField(status, "errors");
|
|
9177
|
+
if (Array.isArray(directErrors)) {
|
|
9178
|
+
for (const entry of directErrors) {
|
|
9179
|
+
const message = getStringField(entry, "message");
|
|
9180
|
+
if (message && !isGenericInternalServerError(message)) {
|
|
9181
|
+
return message;
|
|
9182
|
+
}
|
|
9183
|
+
}
|
|
9184
|
+
}
|
|
9185
|
+
const directError = getStringField(status, "error");
|
|
9186
|
+
if (directError && !isGenericInternalServerError(directError)) {
|
|
9187
|
+
return directError;
|
|
9188
|
+
}
|
|
9189
|
+
return progressError;
|
|
9190
|
+
}
|
|
9225
9191
|
function normalizeRunStatusForEnvelope(status) {
|
|
9226
9192
|
const run = status.run ?? null;
|
|
9227
9193
|
return {
|
|
@@ -9359,8 +9325,7 @@ function compactPlayStatus(status) {
|
|
|
9359
9325
|
const billing = status && typeof status === "object" ? stripProviderSpendFromBilling(
|
|
9360
9326
|
status.billing
|
|
9361
9327
|
) : null;
|
|
9362
|
-
const
|
|
9363
|
-
const error = typeof progressError === "string" ? progressError : typeof status.error === "string" ? String(status.error) : null;
|
|
9328
|
+
const error = selectRunErrorForDisplay(status) ?? (typeof status.error === "string" ? String(status.error) : null);
|
|
9364
9329
|
const displayError = formatPlayErrorForDisplay(status, error);
|
|
9365
9330
|
return {
|
|
9366
9331
|
runId: status.runId,
|
|
@@ -9615,8 +9580,8 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
9615
9580
|
for (const warning of warnings) {
|
|
9616
9581
|
lines.push(` warning: ${warning}`);
|
|
9617
9582
|
}
|
|
9618
|
-
const progressError = status
|
|
9619
|
-
if (progressError
|
|
9583
|
+
const progressError = selectRunErrorForDisplay(status);
|
|
9584
|
+
if (progressError) {
|
|
9620
9585
|
const billing = extractBillingForStatus(status, progressError);
|
|
9621
9586
|
if (isInsufficientCreditsBilling(billing)) {
|
|
9622
9587
|
lines.push(...buildInsufficientCreditsSummaryLines({ status, billing }));
|
|
@@ -9668,9 +9633,6 @@ var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
|
9668
9633
|
function shellSingleQuote(value) {
|
|
9669
9634
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
9670
9635
|
}
|
|
9671
|
-
function sqlStringLiteral(value) {
|
|
9672
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
9673
|
-
}
|
|
9674
9636
|
function runExportRetryCommand(runId, outPath, datasetPath) {
|
|
9675
9637
|
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote(resolve10(outPath))}`;
|
|
9676
9638
|
}
|
|
@@ -9689,26 +9651,6 @@ function extractRunPlayName(status) {
|
|
|
9689
9651
|
}
|
|
9690
9652
|
return null;
|
|
9691
9653
|
}
|
|
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
9654
|
function exportableSheetRow(row) {
|
|
9713
9655
|
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
9714
9656
|
return null;
|
|
@@ -10055,8 +9997,12 @@ function renderServerResultView(value) {
|
|
|
10055
9997
|
lines.push(
|
|
10056
9998
|
` ${String(table.tableNamespace ?? "table")}${lineLabel}: ${rowLabel}${details.join(" ")}`
|
|
10057
9999
|
);
|
|
10058
|
-
if (typeof table.queryDatasetCommand === "string") {
|
|
10059
|
-
lines.push(`
|
|
10000
|
+
if (typeof table.queryDatasetCommand === "string" && typeof table.rowCount === "number" && table.rowCount > 0) {
|
|
10001
|
+
lines.push(` debug backing table: ${table.queryDatasetCommand}`);
|
|
10002
|
+
} else if (typeof table.queryDatasetCommand === "string") {
|
|
10003
|
+
lines.push(
|
|
10004
|
+
" no rows observed for this run; backing table is created only if this map ran"
|
|
10005
|
+
);
|
|
10060
10006
|
}
|
|
10061
10007
|
if (table.debugHelp && typeof table.debugHelp === "object" && !Array.isArray(table.debugHelp)) {
|
|
10062
10008
|
const debugHelp = table.debugHelp;
|
|
@@ -10402,9 +10348,51 @@ function printToolGetterHints(hints) {
|
|
|
10402
10348
|
async function handlePlayCheck(args) {
|
|
10403
10349
|
const options = parsePlayCheckOptions(args);
|
|
10404
10350
|
if (!isFileTarget(options.target)) {
|
|
10405
|
-
const
|
|
10406
|
-
|
|
10407
|
-
|
|
10351
|
+
const client2 = new DeeplineClient();
|
|
10352
|
+
try {
|
|
10353
|
+
await assertCanonicalNamedPlayReference(client2, options.target);
|
|
10354
|
+
const play = await client2.describePlay(
|
|
10355
|
+
parseReferencedPlayTarget2(options.target).playName,
|
|
10356
|
+
{ compact: true }
|
|
10357
|
+
);
|
|
10358
|
+
const result2 = {
|
|
10359
|
+
valid: true,
|
|
10360
|
+
target: options.target,
|
|
10361
|
+
name: play.name,
|
|
10362
|
+
reference: play.reference ?? options.target,
|
|
10363
|
+
origin: play.origin ?? null,
|
|
10364
|
+
ownerType: play.ownerType ?? null,
|
|
10365
|
+
inputSchema: play.inputSchema ?? null,
|
|
10366
|
+
outputSchema: play.outputSchema ?? null,
|
|
10367
|
+
staticPipeline: play.staticPipeline ?? null,
|
|
10368
|
+
note: "Named/prebuilt play contract is available. No run was started."
|
|
10369
|
+
};
|
|
10370
|
+
if (options.jsonOutput) {
|
|
10371
|
+
process.stdout.write(`${JSON.stringify(result2)}
|
|
10372
|
+
`);
|
|
10373
|
+
} else {
|
|
10374
|
+
console.log(`\u2713 ${result2.reference} passed named play contract check`);
|
|
10375
|
+
console.log(" no run started; no Deepline credits spent");
|
|
10376
|
+
if (play.runCommand) console.log(` run: ${play.runCommand}`);
|
|
10377
|
+
}
|
|
10378
|
+
return 0;
|
|
10379
|
+
} catch (error) {
|
|
10380
|
+
const resolved = resolve10(options.target);
|
|
10381
|
+
const message = error instanceof Error && error.message ? error.message : `File not found: ${resolved}`;
|
|
10382
|
+
if (options.jsonOutput) {
|
|
10383
|
+
process.stdout.write(
|
|
10384
|
+
`${JSON.stringify({
|
|
10385
|
+
valid: false,
|
|
10386
|
+
target: options.target,
|
|
10387
|
+
errors: [message]
|
|
10388
|
+
})}
|
|
10389
|
+
`
|
|
10390
|
+
);
|
|
10391
|
+
} else {
|
|
10392
|
+
console.error(message);
|
|
10393
|
+
}
|
|
10394
|
+
return 1;
|
|
10395
|
+
}
|
|
10408
10396
|
}
|
|
10409
10397
|
const absolutePlayPath = resolve10(options.target);
|
|
10410
10398
|
const sourceCode = readFileSync6(absolutePlayPath, "utf-8");
|
|
@@ -10941,7 +10929,7 @@ async function handleRunLogs(args) {
|
|
|
10941
10929
|
const status = await client.runs.get(runId);
|
|
10942
10930
|
const logs = status.progress?.logs ?? [];
|
|
10943
10931
|
if (outPath) {
|
|
10944
|
-
|
|
10932
|
+
writeFileSync7(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
10945
10933
|
printCommandEnvelope(
|
|
10946
10934
|
{
|
|
10947
10935
|
runId: status.runId,
|
|
@@ -11051,18 +11039,9 @@ async function handleRunExport(args) {
|
|
|
11051
11039
|
datasetPath
|
|
11052
11040
|
});
|
|
11053
11041
|
const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
|
|
11054
|
-
const queryPlan = exportResult && outPath ? buildCustomerDbQueryPlan({
|
|
11055
|
-
status,
|
|
11056
|
-
rowsInfo: exportResult.rowsInfo,
|
|
11057
|
-
outPath
|
|
11058
|
-
}) : null;
|
|
11059
11042
|
const next = {
|
|
11060
11043
|
...buildRunNextCommands(status),
|
|
11061
|
-
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
|
|
11062
|
-
...queryPlan ? {
|
|
11063
|
-
queryJson: queryPlan.json,
|
|
11064
|
-
queryCsv: queryPlan.csv
|
|
11065
|
-
} : {}
|
|
11044
|
+
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
|
|
11066
11045
|
};
|
|
11067
11046
|
const payload = {
|
|
11068
11047
|
runId: status.runId,
|
|
@@ -11071,13 +11050,6 @@ async function handleRunExport(args) {
|
|
|
11071
11050
|
source,
|
|
11072
11051
|
rowCount: exportResult?.rowsInfo.totalRows ?? null,
|
|
11073
11052
|
columns: exportResult?.rowsInfo.columns ?? [],
|
|
11074
|
-
...queryPlan ? {
|
|
11075
|
-
query: {
|
|
11076
|
-
sql: queryPlan.sql,
|
|
11077
|
-
json: queryPlan.json,
|
|
11078
|
-
csv: queryPlan.csv
|
|
11079
|
-
}
|
|
11080
|
-
} : {},
|
|
11081
11053
|
...metadataOutPath ? { metadata_path: metadataOutPath } : {},
|
|
11082
11054
|
local: { csv_path: exportResult?.path ?? null },
|
|
11083
11055
|
next,
|
|
@@ -11087,15 +11059,14 @@ async function handleRunExport(args) {
|
|
|
11087
11059
|
title: "run export",
|
|
11088
11060
|
lines: [
|
|
11089
11061
|
`Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
|
|
11090
|
-
...source ? [`source=${source}`] : []
|
|
11091
|
-
...queryPlan ? [`query=${queryPlan.json}`] : []
|
|
11062
|
+
...source ? [`source=${source}`] : []
|
|
11092
11063
|
]
|
|
11093
11064
|
}
|
|
11094
11065
|
]
|
|
11095
11066
|
}
|
|
11096
11067
|
};
|
|
11097
11068
|
if (metadataOutPath) {
|
|
11098
|
-
|
|
11069
|
+
writeFileSync7(
|
|
11099
11070
|
metadataOutPath,
|
|
11100
11071
|
`${JSON.stringify(payload, null, 2)}
|
|
11101
11072
|
`,
|
|
@@ -11268,7 +11239,8 @@ function parsePlaySearchOptions(args) {
|
|
|
11268
11239
|
return {
|
|
11269
11240
|
query,
|
|
11270
11241
|
jsonOutput: argsWantJson(args),
|
|
11271
|
-
compact: args.includes("--compact")
|
|
11242
|
+
compact: args.includes("--compact"),
|
|
11243
|
+
prebuiltOnly: args.includes("--prebuilt")
|
|
11272
11244
|
};
|
|
11273
11245
|
}
|
|
11274
11246
|
function printPlayDescription(play) {
|
|
@@ -11316,6 +11288,7 @@ function printPlayDescription(play) {
|
|
|
11316
11288
|
console.log(` ${line}`);
|
|
11317
11289
|
}
|
|
11318
11290
|
}
|
|
11291
|
+
console.log(` Describe: deepline plays describe ${reference} --json`);
|
|
11319
11292
|
console.log(` Run: ${play.runCommand}`);
|
|
11320
11293
|
const cloneEditStarter = play.cloneEditStarter ?? buildCloneEditStarter(play);
|
|
11321
11294
|
if (cloneEditStarter) {
|
|
@@ -11323,6 +11296,31 @@ function printPlayDescription(play) {
|
|
|
11323
11296
|
console.log(` Check starter: ${cloneEditStarter.checkCommand}`);
|
|
11324
11297
|
}
|
|
11325
11298
|
}
|
|
11299
|
+
function inputFieldNames(schema) {
|
|
11300
|
+
const fields = Array.isArray(schema?.fields) ? schema.fields : [];
|
|
11301
|
+
return fields.map(
|
|
11302
|
+
(field) => field && typeof field === "object" ? String(field.name ?? "").trim() : ""
|
|
11303
|
+
).filter(Boolean);
|
|
11304
|
+
}
|
|
11305
|
+
function printCompactPlaySearchResult(play) {
|
|
11306
|
+
const reference = formatPlayListReference(play);
|
|
11307
|
+
const aliases = play.aliases.slice(0, 6).join(", ");
|
|
11308
|
+
console.log(`Play: ${reference}`);
|
|
11309
|
+
if (play.displayName && play.displayName !== play.name) {
|
|
11310
|
+
console.log(` Display name: ${play.displayName}`);
|
|
11311
|
+
}
|
|
11312
|
+
if (aliases) {
|
|
11313
|
+
console.log(` Aliases: ${aliases}`);
|
|
11314
|
+
}
|
|
11315
|
+
const fields = inputFieldNames(play.inputSchema);
|
|
11316
|
+
if (fields.length > 0) {
|
|
11317
|
+
console.log(` Inputs: ${fields.join(", ")}`);
|
|
11318
|
+
} else if (play.inputSchema) {
|
|
11319
|
+
console.log(" Inputs: see describe");
|
|
11320
|
+
}
|
|
11321
|
+
console.log(` Describe: deepline plays describe ${reference} --json`);
|
|
11322
|
+
console.log(` Run: ${play.runCommand}`);
|
|
11323
|
+
}
|
|
11326
11324
|
function compactPlaySchema(schema) {
|
|
11327
11325
|
if (!schema) return null;
|
|
11328
11326
|
const fields = Array.isArray(schema.fields) ? schema.fields.map(
|
|
@@ -11386,22 +11384,44 @@ async function handlePlaySearch(args) {
|
|
|
11386
11384
|
return 1;
|
|
11387
11385
|
}
|
|
11388
11386
|
const client = new DeeplineClient();
|
|
11389
|
-
const plays = await client.searchPlays({
|
|
11387
|
+
const plays = (await client.searchPlays({
|
|
11390
11388
|
query: options.query,
|
|
11391
11389
|
compact: options.compact
|
|
11392
|
-
})
|
|
11390
|
+
})).filter(
|
|
11391
|
+
(play) => options.prebuiltOnly ? play.origin === "prebuilt" || play.ownerType === "deepline" : true
|
|
11392
|
+
);
|
|
11393
11393
|
if (options.jsonOutput) {
|
|
11394
|
-
|
|
11395
|
-
|
|
11394
|
+
const jsonPlays = options.prebuiltOnly ? plays.map((play) => ({
|
|
11395
|
+
...play,
|
|
11396
|
+
inputSchema: compactPlaySchema(play.inputSchema)
|
|
11397
|
+
})) : plays;
|
|
11398
|
+
process.stdout.write(
|
|
11399
|
+
`${JSON.stringify({
|
|
11400
|
+
plays: jsonPlays,
|
|
11401
|
+
total: jsonPlays.length,
|
|
11402
|
+
truncated: false
|
|
11403
|
+
})}
|
|
11404
|
+
`
|
|
11405
|
+
);
|
|
11396
11406
|
return 0;
|
|
11397
11407
|
}
|
|
11398
|
-
|
|
11408
|
+
const displayPlays = options.prebuiltOnly ? plays.slice(0, 5) : plays;
|
|
11409
|
+
process.stdout.write(
|
|
11410
|
+
`${plays.length} plays found${options.prebuiltOnly && plays.length > displayPlays.length ? `; showing top ${displayPlays.length}` : ""}:
|
|
11399
11411
|
|
|
11400
|
-
`
|
|
11401
|
-
|
|
11402
|
-
|
|
11412
|
+
`
|
|
11413
|
+
);
|
|
11414
|
+
for (const play of displayPlays) {
|
|
11415
|
+
if (options.prebuiltOnly) {
|
|
11416
|
+
printCompactPlaySearchResult(play);
|
|
11417
|
+
} else {
|
|
11418
|
+
printPlayDescription(play);
|
|
11419
|
+
}
|
|
11403
11420
|
console.log("");
|
|
11404
11421
|
}
|
|
11422
|
+
if (options.prebuiltOnly && plays.length > displayPlays.length) {
|
|
11423
|
+
console.log("Use --json for the full machine-readable result set.");
|
|
11424
|
+
}
|
|
11405
11425
|
return 0;
|
|
11406
11426
|
}
|
|
11407
11427
|
function normalizePlayGrepText(value) {
|
|
@@ -11668,15 +11688,18 @@ Common commands:
|
|
|
11668
11688
|
deepline plays get person-linkedin-to-email --json
|
|
11669
11689
|
`
|
|
11670
11690
|
);
|
|
11671
|
-
play.command("check <target>").description("
|
|
11691
|
+
play.command("check <target>").description("Check a local play file or named/prebuilt play contract.").addHelpText(
|
|
11672
11692
|
"after",
|
|
11673
11693
|
`
|
|
11674
11694
|
Notes:
|
|
11675
11695
|
Validates a local play without storing it, promoting it, or starting a run.
|
|
11676
11696
|
This uses the authoritative cloud preflight path.
|
|
11697
|
+
For named or prebuilt plays, validates that the contract is discoverable
|
|
11698
|
+
without starting a run or spending Deepline credits.
|
|
11677
11699
|
|
|
11678
11700
|
Examples:
|
|
11679
11701
|
deepline plays check my.play.ts
|
|
11702
|
+
deepline plays check prebuilt/name-and-domain-to-email-waterfall-batch
|
|
11680
11703
|
deepline plays check my.play.ts --json
|
|
11681
11704
|
`
|
|
11682
11705
|
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
|
|
@@ -11826,11 +11849,13 @@ Examples:
|
|
|
11826
11849
|
...options.json ? ["--json"] : []
|
|
11827
11850
|
]);
|
|
11828
11851
|
});
|
|
11829
|
-
const addPlaySearchCommand = (command) => command.description("Search saved and prebuilt plays.").addHelpText(
|
|
11852
|
+
const addPlaySearchCommand = (command) => command.description("Search saved and prebuilt plays.").option("--prebuilt", "Only show Deepline-managed prebuilt plays").addHelpText(
|
|
11830
11853
|
"after",
|
|
11831
11854
|
`
|
|
11832
11855
|
Notes:
|
|
11833
11856
|
Ranked discovery for workflows. Use describe on a result before running it.
|
|
11857
|
+
Prefer --prebuilt for new GTM tasks so old workspace scratchpads do not
|
|
11858
|
+
outrank Deepline-managed routes unless the user names one explicitly.
|
|
11834
11859
|
The grep alias is the same ranked retrieval surface with a more literal name
|
|
11835
11860
|
for agents that are filtering the play registry.
|
|
11836
11861
|
|
|
@@ -11842,6 +11867,7 @@ Examples:
|
|
|
11842
11867
|
).option("--compact", "Emit compact schemas").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
11843
11868
|
process.exitCode = await handlePlaySearch([
|
|
11844
11869
|
query,
|
|
11870
|
+
...options.prebuilt ? ["--prebuilt"] : [],
|
|
11845
11871
|
...options.compact ? ["--compact"] : [],
|
|
11846
11872
|
...options.json ? ["--json"] : []
|
|
11847
11873
|
]);
|
|
@@ -12089,7 +12115,7 @@ Notes:
|
|
|
12089
12115
|
Writes a returned dataset handle to the requested local CSV path. Use runs get
|
|
12090
12116
|
first to inspect dataset paths like result.rows or result.nested.contacts.
|
|
12091
12117
|
--metadata-out writes the same export metadata object returned by --json,
|
|
12092
|
-
including source
|
|
12118
|
+
including the source dataset path and row/column metadata.
|
|
12093
12119
|
|
|
12094
12120
|
Examples:
|
|
12095
12121
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
@@ -13796,12 +13822,12 @@ Examples:
|
|
|
13796
13822
|
|
|
13797
13823
|
// src/cli/commands/tools.ts
|
|
13798
13824
|
import { Option } from "commander";
|
|
13799
|
-
import { chmodSync, mkdtempSync, writeFileSync as
|
|
13825
|
+
import { chmodSync, mkdtempSync, writeFileSync as writeFileSync9 } from "fs";
|
|
13800
13826
|
import { tmpdir as tmpdir4 } from "os";
|
|
13801
13827
|
import { join as join10 } from "path";
|
|
13802
13828
|
|
|
13803
13829
|
// src/tool-output.ts
|
|
13804
|
-
import { mkdirSync as mkdirSync4, writeFileSync as
|
|
13830
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
13805
13831
|
import { homedir as homedir5 } from "os";
|
|
13806
13832
|
import { join as join9 } from "path";
|
|
13807
13833
|
function isPlainObject(value) {
|
|
@@ -13906,7 +13932,7 @@ function ensureOutputDir() {
|
|
|
13906
13932
|
function writeJsonOutputFile(payload, stem) {
|
|
13907
13933
|
const outputDir = ensureOutputDir();
|
|
13908
13934
|
const outputPath = join9(outputDir, `${stem}_${Date.now()}.json`);
|
|
13909
|
-
|
|
13935
|
+
writeFileSync8(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
13910
13936
|
return outputPath;
|
|
13911
13937
|
}
|
|
13912
13938
|
function writeCsvOutputFile(rows, stem) {
|
|
@@ -13934,7 +13960,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
13934
13960
|
for (const row of rows) {
|
|
13935
13961
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
13936
13962
|
}
|
|
13937
|
-
|
|
13963
|
+
writeFileSync8(outputPath, `${lines.join("\n")}
|
|
13938
13964
|
`, "utf-8");
|
|
13939
13965
|
const previewRows = rows.slice(0, 5);
|
|
13940
13966
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -14020,7 +14046,7 @@ async function listTools(args) {
|
|
|
14020
14046
|
const client = new DeeplineClient();
|
|
14021
14047
|
const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
|
|
14022
14048
|
const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
|
|
14023
|
-
const compact = args.includes("--compact");
|
|
14049
|
+
const compact = args.includes("--compact") || !args.includes("--json");
|
|
14024
14050
|
const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
14025
14051
|
const items = (await client.listTools({
|
|
14026
14052
|
...categoryFilter ? { categories: categoryFilter } : {}
|
|
@@ -14076,9 +14102,10 @@ async function searchTools(queryInput, options = {}) {
|
|
|
14076
14102
|
searchMode: options.searchMode,
|
|
14077
14103
|
includeSearchDebug: options.includeSearchDebug
|
|
14078
14104
|
});
|
|
14079
|
-
const
|
|
14105
|
+
const shouldCompact = options.compact || !options.json;
|
|
14106
|
+
const payload = shouldCompact && Array.isArray(result.tools) ? {
|
|
14080
14107
|
...result,
|
|
14081
|
-
tools: result.tools.map(compactTool)
|
|
14108
|
+
tools: result.tools.slice(0, 8).map(compactTool)
|
|
14082
14109
|
} : result;
|
|
14083
14110
|
printCommandEnvelope(payload, {
|
|
14084
14111
|
json: options.json || shouldEmitJson()
|
|
@@ -14119,7 +14146,8 @@ async function grepTools(queryInput, options = {}) {
|
|
|
14119
14146
|
mode
|
|
14120
14147
|
)
|
|
14121
14148
|
);
|
|
14122
|
-
const
|
|
14149
|
+
const shouldCompact = options.compact || !options.json;
|
|
14150
|
+
const outputTools = shouldCompact ? tools.slice(0, 8).map(compactTool) : tools;
|
|
14123
14151
|
printCommandEnvelope(
|
|
14124
14152
|
{
|
|
14125
14153
|
tools: outputTools,
|
|
@@ -14138,11 +14166,19 @@ async function grepTools(queryInput, options = {}) {
|
|
|
14138
14166
|
);
|
|
14139
14167
|
return 0;
|
|
14140
14168
|
}
|
|
14169
|
+
function numericToolField(tool, field) {
|
|
14170
|
+
const value = tool[field];
|
|
14171
|
+
return typeof value === "number" ? value : void 0;
|
|
14172
|
+
}
|
|
14141
14173
|
function compactTool(tool) {
|
|
14142
14174
|
const listed = toListedTool(tool);
|
|
14175
|
+
const searchScore = numericToolField(tool, "searchScore");
|
|
14176
|
+
const search_score = numericToolField(tool, "search_score");
|
|
14143
14177
|
return {
|
|
14144
14178
|
id: listed.id,
|
|
14145
14179
|
toolId: listed.toolId,
|
|
14180
|
+
...search_score !== void 0 ? { search_score } : {},
|
|
14181
|
+
...searchScore !== void 0 ? { searchScore } : {},
|
|
14146
14182
|
provider: listed.provider,
|
|
14147
14183
|
displayName: listed.displayName,
|
|
14148
14184
|
description: listed.description,
|
|
@@ -14463,7 +14499,7 @@ async function getTool(toolId, options = {}) {
|
|
|
14463
14499
|
}
|
|
14464
14500
|
if (shouldEmitJson()) {
|
|
14465
14501
|
process.stdout.write(
|
|
14466
|
-
`${JSON.stringify(
|
|
14502
|
+
`${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
|
|
14467
14503
|
`
|
|
14468
14504
|
);
|
|
14469
14505
|
return 0;
|
|
@@ -14788,8 +14824,8 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
|
14788
14824
|
invalidGetterHint: "If TypeScript says an extractedValues/extractedLists property does not exist, that field is not a declared Deepline getter.",
|
|
14789
14825
|
observeActualShape: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
14790
14826
|
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
|
|
14827
|
+
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.",
|
|
14828
|
+
executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run output and returned dataset handles."
|
|
14793
14829
|
},
|
|
14794
14830
|
starterScript: {
|
|
14795
14831
|
path: starterScript.path,
|
|
@@ -15040,7 +15076,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
15040
15076
|
};
|
|
15041
15077
|
});
|
|
15042
15078
|
`;
|
|
15043
|
-
|
|
15079
|
+
writeFileSync9(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
15044
15080
|
return {
|
|
15045
15081
|
path: scriptPath,
|
|
15046
15082
|
sourceCode: script,
|
|
@@ -15596,7 +15632,7 @@ import {
|
|
|
15596
15632
|
readdirSync as readdirSync2,
|
|
15597
15633
|
readFileSync as readFileSync7,
|
|
15598
15634
|
statSync as statSync2,
|
|
15599
|
-
writeFileSync as
|
|
15635
|
+
writeFileSync as writeFileSync10
|
|
15600
15636
|
} from "fs";
|
|
15601
15637
|
import { homedir as homedir6 } from "os";
|
|
15602
15638
|
import { dirname as dirname10, join as join12 } from "path";
|
|
@@ -15630,7 +15666,7 @@ function readLocalSkillsVersion(baseUrl) {
|
|
|
15630
15666
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
15631
15667
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
15632
15668
|
mkdirSync5(dirname10(path), { recursive: true });
|
|
15633
|
-
|
|
15669
|
+
writeFileSync10(path, `${version}
|
|
15634
15670
|
`, "utf-8");
|
|
15635
15671
|
}
|
|
15636
15672
|
function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
@@ -15813,6 +15849,7 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
15813
15849
|
}
|
|
15814
15850
|
|
|
15815
15851
|
// src/cli/index.ts
|
|
15852
|
+
var PREFLIGHT_TIMEOUT_MS = 3e3;
|
|
15816
15853
|
function asCommanderError(error) {
|
|
15817
15854
|
if (!(error instanceof Error) || !("code" in error)) {
|
|
15818
15855
|
return null;
|
|
@@ -15893,6 +15930,124 @@ async function runPlayRunnerHealthCheck() {
|
|
|
15893
15930
|
await rm2(dir, { recursive: true, force: true });
|
|
15894
15931
|
}
|
|
15895
15932
|
}
|
|
15933
|
+
function pickString(value, ...keys) {
|
|
15934
|
+
for (const key of keys) {
|
|
15935
|
+
const candidate = value[key];
|
|
15936
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
15937
|
+
return candidate;
|
|
15938
|
+
}
|
|
15939
|
+
}
|
|
15940
|
+
return null;
|
|
15941
|
+
}
|
|
15942
|
+
function preflightErrorMessage(error) {
|
|
15943
|
+
return error instanceof Error ? error.message : String(error);
|
|
15944
|
+
}
|
|
15945
|
+
async function runPreflightCheck() {
|
|
15946
|
+
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
15947
|
+
const healthController = new AbortController();
|
|
15948
|
+
const healthTimeout = setTimeout(
|
|
15949
|
+
() => healthController.abort(),
|
|
15950
|
+
PREFLIGHT_TIMEOUT_MS
|
|
15951
|
+
);
|
|
15952
|
+
const health = await fetch(new URL("/api/v2/health", baseUrl), {
|
|
15953
|
+
signal: healthController.signal
|
|
15954
|
+
}).then(async (response) => {
|
|
15955
|
+
const payload = await response.json().catch(() => ({}));
|
|
15956
|
+
return {
|
|
15957
|
+
status: response.ok ? pickString(payload, "status") ?? "ok" : "unreachable",
|
|
15958
|
+
version: pickString(payload, "version")
|
|
15959
|
+
};
|
|
15960
|
+
}).catch(() => ({ status: "unreachable", version: null })).finally(() => clearTimeout(healthTimeout));
|
|
15961
|
+
const apiKey = resolveApiKeyForBaseUrl(baseUrl);
|
|
15962
|
+
const http = apiKey ? new HttpClient(
|
|
15963
|
+
resolveConfig({
|
|
15964
|
+
baseUrl,
|
|
15965
|
+
apiKey,
|
|
15966
|
+
timeout: PREFLIGHT_TIMEOUT_MS,
|
|
15967
|
+
maxRetries: 0
|
|
15968
|
+
})
|
|
15969
|
+
) : null;
|
|
15970
|
+
const [auth, billing] = http ? await Promise.all([
|
|
15971
|
+
http.post("/api/v2/auth/cli/status", {
|
|
15972
|
+
api_key: apiKey,
|
|
15973
|
+
reveal: false
|
|
15974
|
+
}).catch((error) => ({
|
|
15975
|
+
status: "not_connected",
|
|
15976
|
+
connected: false,
|
|
15977
|
+
error: preflightErrorMessage(error)
|
|
15978
|
+
})),
|
|
15979
|
+
http.get("/api/v2/billing/balance").catch(
|
|
15980
|
+
(error) => ({
|
|
15981
|
+
balance: null,
|
|
15982
|
+
balance_display: "unavailable",
|
|
15983
|
+
balance_status: "unknown",
|
|
15984
|
+
error: preflightErrorMessage(error)
|
|
15985
|
+
})
|
|
15986
|
+
)
|
|
15987
|
+
]) : [
|
|
15988
|
+
{
|
|
15989
|
+
status: "not_connected",
|
|
15990
|
+
connected: false,
|
|
15991
|
+
error: "No API key found. Run: deepline auth register"
|
|
15992
|
+
},
|
|
15993
|
+
{
|
|
15994
|
+
balance: null,
|
|
15995
|
+
balance_display: "unavailable until authenticated",
|
|
15996
|
+
balance_status: "unknown"
|
|
15997
|
+
}
|
|
15998
|
+
];
|
|
15999
|
+
const authStatus = pickString(auth, "status") ?? "unknown";
|
|
16000
|
+
const billingRecord = billing;
|
|
16001
|
+
const balanceDisplay = pickString(billing, "balance_display", "balanceDisplay") ?? `${String(billingRecord.balance ?? 0)} Deepline Credits`;
|
|
16002
|
+
const balanceStatus = pickString(billing, "balance_status", "balanceStatus") ?? "unknown";
|
|
16003
|
+
return {
|
|
16004
|
+
status: health.status === "ok" && (authStatus === "connected" || authStatus === "claimed") ? "ok" : "check",
|
|
16005
|
+
host: baseUrl,
|
|
16006
|
+
health: {
|
|
16007
|
+
status: health.status,
|
|
16008
|
+
version: health.version ?? null
|
|
16009
|
+
},
|
|
16010
|
+
auth: {
|
|
16011
|
+
status: authStatus,
|
|
16012
|
+
connected: authStatus === "connected" || authStatus === "claimed",
|
|
16013
|
+
org_id: pickString(auth, "org_id", "orgId"),
|
|
16014
|
+
org_name: pickString(auth, "org_name", "orgName"),
|
|
16015
|
+
rate_limit_tier: pickString(auth, "rate_limit_tier", "rateLimitTier"),
|
|
16016
|
+
error: pickString(auth, "error")
|
|
16017
|
+
},
|
|
16018
|
+
billing: {
|
|
16019
|
+
balance: billingRecord.balance ?? null,
|
|
16020
|
+
balance_display: balanceDisplay,
|
|
16021
|
+
rough_usd_balance: billingRecord.rough_usd_balance ?? billingRecord.roughUsdBalance ?? null,
|
|
16022
|
+
balance_status: balanceStatus,
|
|
16023
|
+
error: pickString(billing, "error")
|
|
16024
|
+
},
|
|
16025
|
+
render: {
|
|
16026
|
+
sections: [
|
|
16027
|
+
{
|
|
16028
|
+
title: "preflight",
|
|
16029
|
+
lines: [
|
|
16030
|
+
`host: ${baseUrl}`,
|
|
16031
|
+
`health: ${health.status}`,
|
|
16032
|
+
`auth: ${authStatus}`,
|
|
16033
|
+
`billing: ${balanceDisplay} (${balanceStatus})`
|
|
16034
|
+
]
|
|
16035
|
+
}
|
|
16036
|
+
]
|
|
16037
|
+
}
|
|
16038
|
+
};
|
|
16039
|
+
}
|
|
16040
|
+
function printPreflightHuman(data) {
|
|
16041
|
+
const render = data.render;
|
|
16042
|
+
const lines = render?.sections?.flatMap((section) => section.lines ?? []);
|
|
16043
|
+
if (lines?.length) {
|
|
16044
|
+
process.stdout.write(`${lines.join("\n")}
|
|
16045
|
+
`);
|
|
16046
|
+
return;
|
|
16047
|
+
}
|
|
16048
|
+
process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
16049
|
+
`);
|
|
16050
|
+
}
|
|
15896
16051
|
async function main() {
|
|
15897
16052
|
const mainStartedAt = Date.now();
|
|
15898
16053
|
recordCliTrace({
|
|
@@ -15909,6 +16064,7 @@ async function main() {
|
|
|
15909
16064
|
"after",
|
|
15910
16065
|
`
|
|
15911
16066
|
Common commands:
|
|
16067
|
+
deepline preflight
|
|
15912
16068
|
deepline health
|
|
15913
16069
|
deepline auth status --json
|
|
15914
16070
|
deepline plays search email --json
|
|
@@ -15930,7 +16086,6 @@ Output:
|
|
|
15930
16086
|
|
|
15931
16087
|
Safety:
|
|
15932
16088
|
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
16089
|
|
|
15935
16090
|
Exit codes:
|
|
15936
16091
|
0 success; 2 usage/local input error; 3 auth/permission error; 4 not found;
|
|
@@ -15972,6 +16127,26 @@ Exit codes:
|
|
|
15972
16127
|
registerDbCommands(program);
|
|
15973
16128
|
registerFeedbackCommands(program);
|
|
15974
16129
|
registerUpdateCommand(program);
|
|
16130
|
+
program.command("preflight").description("Run compact health, auth, and Deepline billing checks.").option("--json", "Force JSON output.").addHelpText(
|
|
16131
|
+
"after",
|
|
16132
|
+
`
|
|
16133
|
+
Notes:
|
|
16134
|
+
Read-only setup check for the configured Deepline host. Shows server health,
|
|
16135
|
+
auth connection, and customer-visible Deepline balance in one compact command.
|
|
16136
|
+
|
|
16137
|
+
Examples:
|
|
16138
|
+
deepline preflight
|
|
16139
|
+
deepline preflight --json
|
|
16140
|
+
`
|
|
16141
|
+
).action(async (options) => {
|
|
16142
|
+
const data = await runPreflightCheck();
|
|
16143
|
+
if (shouldEmitJson(options.json)) {
|
|
16144
|
+
process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
16145
|
+
`);
|
|
16146
|
+
} else {
|
|
16147
|
+
printPreflightHuman(data);
|
|
16148
|
+
}
|
|
16149
|
+
});
|
|
15975
16150
|
program.command("health").description("Check server health.").option("--json", "Force JSON output.").option(
|
|
15976
16151
|
"--play-runner",
|
|
15977
16152
|
"Run a tiny no-provider play to verify the full play execution plane."
|