deepline 0.1.76 → 0.1.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -8
- package/dist/cli/index.js +534 -350
- package/dist/cli/index.mjs +547 -363
- package/dist/index.d.mts +40 -2
- package/dist/index.d.ts +40 -2
- package/dist/index.js +198 -2
- package/dist/index.mjs +198 -2
- package/dist/repo/sdk/src/client.ts +7 -0
- package/dist/repo/sdk/src/play.ts +1 -1
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/sdk/src/types.ts +4 -0
- package/dist/repo/shared_libs/play-runtime/email-status.ts +301 -0
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +58 -1
- package/dist/repo/shared_libs/plays/dataset.ts +3 -1
- package/package.json +1 -1
package/dist/cli/index.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,
|
|
@@ -4173,13 +4225,18 @@ function registerDbCommands(program) {
|
|
|
4173
4225
|
"after",
|
|
4174
4226
|
`
|
|
4175
4227
|
Notes:
|
|
4176
|
-
|
|
4228
|
+
Agent-safe SQL for the active workspace customer database.
|
|
4229
|
+
Reads: SELECT, EXPLAIN, and read-only WITH can inspect permitted schemas.
|
|
4230
|
+
Writes: CREATE TABLE, INSERT, UPDATE, DELETE, ALTER, DROP, TRUNCATE, and
|
|
4231
|
+
CREATE INDEX must target schema-qualified storage tables, such as storage.agent_notes.
|
|
4232
|
+
If CREATE TABLE blocked (...) fails, use CREATE TABLE storage.blocked (...).
|
|
4177
4233
|
Results are bounded by the server and --max-rows. Use --json for stable output.
|
|
4178
4234
|
Use --format csv or --format markdown for agent-readable exports and display tables.
|
|
4179
4235
|
|
|
4180
4236
|
Examples:
|
|
4181
4237
|
deepline db query --sql "select * from companies limit 20"
|
|
4182
4238
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
4239
|
+
deepline db query --sql "create table if not exists storage.agent_notes (id text primary key, note text not null)"
|
|
4183
4240
|
deepline db query --sql "select * from contacts" --max-rows 100 --json
|
|
4184
4241
|
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
4185
4242
|
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
@@ -4191,12 +4248,16 @@ Examples:
|
|
|
4191
4248
|
Notes:
|
|
4192
4249
|
Requires --sql. Output is a compact table in a terminal and raw JSON with
|
|
4193
4250
|
--json or when stdout is piped. The active auth workspace determines scope.
|
|
4251
|
+
Read permitted schemas with SELECT, EXPLAIN, or read-only WITH.
|
|
4252
|
+
Write only to schema-qualified storage tables. For example, use
|
|
4253
|
+
CREATE TABLE storage.blocked (...) instead of CREATE TABLE blocked (...).
|
|
4194
4254
|
--format csv and --format markdown are explicit data/display formats and can
|
|
4195
4255
|
be written directly with --out.
|
|
4196
4256
|
|
|
4197
4257
|
Examples:
|
|
4198
4258
|
deepline db query --sql "select * from companies limit 20"
|
|
4199
4259
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
4260
|
+
deepline db query --sql "create table if not exists storage.agent_notes (id text primary key, note text not null)"
|
|
4200
4261
|
deepline db psql --sql "select count(*) from contacts" --json
|
|
4201
4262
|
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
4202
4263
|
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
@@ -4228,7 +4289,7 @@ import {
|
|
|
4228
4289
|
readFileSync as readFileSync6,
|
|
4229
4290
|
readdirSync,
|
|
4230
4291
|
realpathSync,
|
|
4231
|
-
writeFileSync as
|
|
4292
|
+
writeFileSync as writeFileSync7
|
|
4232
4293
|
} from "fs";
|
|
4233
4294
|
import { basename as basename3, dirname as dirname8, join as join7, resolve as resolve10 } from "path";
|
|
4234
4295
|
|
|
@@ -5901,7 +5962,7 @@ async function bundlePlayFile2(filePath, options = {}) {
|
|
|
5901
5962
|
}
|
|
5902
5963
|
|
|
5903
5964
|
// src/cli/commands/plays/bootstrap.ts
|
|
5904
|
-
import { closeSync, openSync, readSync, statSync } from "fs";
|
|
5965
|
+
import { closeSync, openSync, readSync, statSync, writeFileSync as writeFileSync6 } from "fs";
|
|
5905
5966
|
import { isAbsolute as isAbsolute3, relative as relative2, resolve as resolve9 } from "path";
|
|
5906
5967
|
import { parse as parseCsvSync } from "csv-parse/sync";
|
|
5907
5968
|
|
|
@@ -6076,19 +6137,19 @@ function playBootstrapTemplateConfig(template) {
|
|
|
6076
6137
|
function templateExample(template) {
|
|
6077
6138
|
switch (template) {
|
|
6078
6139
|
case "people-list":
|
|
6079
|
-
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";
|
|
6080
6141
|
case "company-list":
|
|
6081
|
-
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";
|
|
6082
6143
|
case "people-email":
|
|
6083
|
-
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";
|
|
6084
6145
|
case "people-phone":
|
|
6085
|
-
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";
|
|
6086
6147
|
case "company-people":
|
|
6087
|
-
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";
|
|
6088
6149
|
case "company-people-email":
|
|
6089
|
-
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";
|
|
6090
6151
|
case "company-people-phone":
|
|
6091
|
-
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";
|
|
6092
6153
|
}
|
|
6093
6154
|
}
|
|
6094
6155
|
var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
@@ -6097,19 +6158,22 @@ var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
|
6097
6158
|
"phone"
|
|
6098
6159
|
];
|
|
6099
6160
|
function playBootstrapUsageLine() {
|
|
6100
|
-
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]`;
|
|
6101
6162
|
}
|
|
6102
6163
|
function requireBootstrapTemplate(rawTemplate) {
|
|
6103
6164
|
if (!rawTemplate) {
|
|
6104
6165
|
throw new PlayBootstrapUsageError(
|
|
6105
6166
|
`plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}.
|
|
6106
|
-
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`
|
|
6107
6168
|
);
|
|
6108
6169
|
}
|
|
6109
6170
|
if (!isPlayBootstrapTemplate(rawTemplate)) {
|
|
6171
|
+
const looksLikePlayReference = rawTemplate.includes("/") || rawTemplate.endsWith(".play.ts");
|
|
6110
6172
|
throw new PlayBootstrapUsageError(
|
|
6111
6173
|
`Unknown plays bootstrap template: ${rawTemplate}
|
|
6112
|
-
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.` : "")
|
|
6113
6177
|
);
|
|
6114
6178
|
}
|
|
6115
6179
|
return rawTemplate;
|
|
@@ -6251,7 +6315,8 @@ function parsePlayBootstrapOptions(args) {
|
|
|
6251
6315
|
people: null,
|
|
6252
6316
|
email: null,
|
|
6253
6317
|
phone: null,
|
|
6254
|
-
limit: 5
|
|
6318
|
+
limit: 5,
|
|
6319
|
+
out: null
|
|
6255
6320
|
};
|
|
6256
6321
|
for (let index = 0; index < rest.length; index += 1) {
|
|
6257
6322
|
const arg = rest[index];
|
|
@@ -6285,6 +6350,10 @@ function parsePlayBootstrapOptions(args) {
|
|
|
6285
6350
|
options.limit = parsePositiveInteger2(value(), "--limit");
|
|
6286
6351
|
index += 1;
|
|
6287
6352
|
break;
|
|
6353
|
+
case "--out":
|
|
6354
|
+
options.out = value();
|
|
6355
|
+
index += 1;
|
|
6356
|
+
break;
|
|
6288
6357
|
default:
|
|
6289
6358
|
throw new PlayBootstrapUsageError(
|
|
6290
6359
|
`Unknown plays bootstrap option: ${arg}
|
|
@@ -6402,7 +6471,7 @@ function packagedCsvPathForPlay(csvPath) {
|
|
|
6402
6471
|
const relativePath = relative2(playDir, absoluteCsvPath);
|
|
6403
6472
|
if (relativePath === "" || relativePath.startsWith("..") || isAbsolute3(relativePath)) {
|
|
6404
6473
|
throw new PlayBootstrapUsageError(
|
|
6405
|
-
`--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.`
|
|
6406
6475
|
);
|
|
6407
6476
|
}
|
|
6408
6477
|
const portablePath = relativePath.split("\\").join("/");
|
|
@@ -6809,8 +6878,18 @@ function validateBootstrapRoutes(input2) {
|
|
|
6809
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."
|
|
6810
6879
|
);
|
|
6811
6880
|
}
|
|
6881
|
+
assertComposablePlayRoute({
|
|
6882
|
+
stageLabel: "--people",
|
|
6883
|
+
playRef: stagePlayRef(input2.options.people),
|
|
6884
|
+
play: input2.peoplePlay
|
|
6885
|
+
});
|
|
6812
6886
|
for (const finder of ["email_finder", "phone_finder"]) {
|
|
6813
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
|
+
});
|
|
6814
6893
|
for (const tool of input2.finderTools[finder] ?? []) {
|
|
6815
6894
|
if (!tool.categories.includes(requiredCategory)) {
|
|
6816
6895
|
throw new PlayBootstrapValidationError(
|
|
@@ -6825,6 +6904,38 @@ function validateBootstrapRoutes(input2) {
|
|
|
6825
6904
|
}
|
|
6826
6905
|
}
|
|
6827
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
|
+
}
|
|
6828
6939
|
function sourceCollectionName(entity) {
|
|
6829
6940
|
switch (entity) {
|
|
6830
6941
|
case "company":
|
|
@@ -6854,6 +6965,22 @@ function generateCsvSourceRowsBlock(input2) {
|
|
|
6854
6965
|
const ${input2.collection}: ${input2.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
6855
6966
|
}
|
|
6856
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
|
+
}
|
|
6857
6984
|
const playInput = generatePlayInputObject({
|
|
6858
6985
|
schema: input2.sourcePlay?.inputSchema,
|
|
6859
6986
|
indent: " ",
|
|
@@ -7138,6 +7265,7 @@ ${typeDefinitions}
|
|
|
7138
7265
|
|
|
7139
7266
|
type Input = {
|
|
7140
7267
|
limit?: number;
|
|
7268
|
+
sourceCsv?: string;
|
|
7141
7269
|
};
|
|
7142
7270
|
|
|
7143
7271
|
export default definePlay(${jsString(input2.options.name)}, async (ctx, input: Input = {}) => {
|
|
@@ -7204,6 +7332,7 @@ async function loadBootstrapContracts(client, options) {
|
|
|
7204
7332
|
validateBootstrapRoutes({
|
|
7205
7333
|
options,
|
|
7206
7334
|
sourceTools: contracts.sourceTools,
|
|
7335
|
+
sourcePlay: contracts.sourcePlay,
|
|
7207
7336
|
peoplePlay: contracts.peoplePlay,
|
|
7208
7337
|
finderTools: contracts.finderTools,
|
|
7209
7338
|
finderPlays: contracts.finderPlays
|
|
@@ -7225,11 +7354,11 @@ function loadCsvContext(source) {
|
|
|
7225
7354
|
};
|
|
7226
7355
|
}
|
|
7227
7356
|
}
|
|
7228
|
-
function
|
|
7357
|
+
function errorMessage2(error) {
|
|
7229
7358
|
return error instanceof Error ? error.message : String(error);
|
|
7230
7359
|
}
|
|
7231
7360
|
function renderPlayBootstrapError(error) {
|
|
7232
|
-
console.error(
|
|
7361
|
+
console.error(errorMessage2(error));
|
|
7233
7362
|
return error instanceof PlayBootstrapError ? error.exitCode : 1;
|
|
7234
7363
|
}
|
|
7235
7364
|
async function runPlayBootstrap(args) {
|
|
@@ -7242,6 +7371,12 @@ async function runPlayBootstrap(args) {
|
|
|
7242
7371
|
...contracts,
|
|
7243
7372
|
...csvContext
|
|
7244
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
|
+
}
|
|
7245
7380
|
process.stdout.write(source);
|
|
7246
7381
|
return 0;
|
|
7247
7382
|
}
|
|
@@ -7254,7 +7389,7 @@ function registerPlayBootstrapCommand(play) {
|
|
|
7254
7389
|
`
|
|
7255
7390
|
Notes:
|
|
7256
7391
|
Cloud-validated play generator for agents. Pick the JTBD as the positional
|
|
7257
|
-
template, bind resources with typed refs,
|
|
7392
|
+
template, bind resources with typed refs, write the .play.ts file with --out,
|
|
7258
7393
|
then edit the generated TODO mapping comments. Multiple finder providers are
|
|
7259
7394
|
generated as a waterfall in the order you pass them.
|
|
7260
7395
|
|
|
@@ -7262,9 +7397,8 @@ Notes:
|
|
|
7262
7397
|
Deepline. It prints TypeScript source only and does not run paid tools; the
|
|
7263
7398
|
generated play may spend credits later when you run it.
|
|
7264
7399
|
|
|
7265
|
-
stdout is the generated .play.ts source.
|
|
7266
|
-
|
|
7267
|
-
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.
|
|
7268
7402
|
|
|
7269
7403
|
Templates:
|
|
7270
7404
|
people-list start from people/contact rows
|
|
@@ -7288,7 +7422,7 @@ Notes:
|
|
|
7288
7422
|
email/phone finder providers must match their category and expose value getters
|
|
7289
7423
|
finder plays/providers must match the route; generated code leaves input mapping explicit
|
|
7290
7424
|
business-specific provider inputs and company -> people persona fields are TODOs in code
|
|
7291
|
-
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
|
|
7292
7426
|
|
|
7293
7427
|
Exit codes:
|
|
7294
7428
|
0 success
|
|
@@ -7296,13 +7430,13 @@ Notes:
|
|
|
7296
7430
|
7 route validation failed
|
|
7297
7431
|
|
|
7298
7432
|
Examples:
|
|
7299
|
-
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
|
|
7300
7434
|
deepline plays check email-flow.play.ts
|
|
7301
7435
|
deepline plays run email-flow.play.ts --input '{"limit":5}' --watch
|
|
7302
7436
|
|
|
7303
|
-
deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5
|
|
7304
|
-
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
|
|
7305
|
-
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
|
|
7306
7440
|
`
|
|
7307
7441
|
).option("--name <name>", "Generated play name").option(
|
|
7308
7442
|
"--from <ref>",
|
|
@@ -7319,7 +7453,7 @@ Examples:
|
|
|
7319
7453
|
).option(
|
|
7320
7454
|
"--phone <ref>",
|
|
7321
7455
|
"Phone finder stage: play:REF, provider:ID, or providers:ID,ID"
|
|
7322
|
-
).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) => {
|
|
7323
7457
|
process.exitCode = await handlePlayBootstrap([
|
|
7324
7458
|
template,
|
|
7325
7459
|
...options.name ? ["--name", options.name] : [],
|
|
@@ -7328,7 +7462,8 @@ Examples:
|
|
|
7328
7462
|
...options.people ? ["--people", options.people] : [],
|
|
7329
7463
|
...options.email ? ["--email", options.email] : [],
|
|
7330
7464
|
...options.phone ? ["--phone", options.phone] : [],
|
|
7331
|
-
...options.limit ? ["--limit", options.limit] : []
|
|
7465
|
+
...options.limit ? ["--limit", options.limit] : [],
|
|
7466
|
+
...options.out ? ["--out", options.out] : []
|
|
7332
7467
|
]);
|
|
7333
7468
|
});
|
|
7334
7469
|
}
|
|
@@ -7478,204 +7613,6 @@ function createCliProgress(enabled) {
|
|
|
7478
7613
|
return progress;
|
|
7479
7614
|
}
|
|
7480
7615
|
|
|
7481
|
-
// ../shared_libs/plays/row-identity.ts
|
|
7482
|
-
var POSTGRES_IDENTIFIER_MAX_LENGTH = 63;
|
|
7483
|
-
var PLAY_NAME_MAX_LENGTH = POSTGRES_IDENTIFIER_MAX_LENGTH;
|
|
7484
|
-
var MAP_KEY_NAMESPACE_MAX_LENGTH = POSTGRES_IDENTIFIER_MAX_LENGTH;
|
|
7485
|
-
var SHA256_INITIAL_HASH = [
|
|
7486
|
-
1779033703,
|
|
7487
|
-
3144134277,
|
|
7488
|
-
1013904242,
|
|
7489
|
-
2773480762,
|
|
7490
|
-
1359893119,
|
|
7491
|
-
2600822924,
|
|
7492
|
-
528734635,
|
|
7493
|
-
1541459225
|
|
7494
|
-
];
|
|
7495
|
-
var SHA256_ROUND_CONSTANTS = [
|
|
7496
|
-
1116352408,
|
|
7497
|
-
1899447441,
|
|
7498
|
-
3049323471,
|
|
7499
|
-
3921009573,
|
|
7500
|
-
961987163,
|
|
7501
|
-
1508970993,
|
|
7502
|
-
2453635748,
|
|
7503
|
-
2870763221,
|
|
7504
|
-
3624381080,
|
|
7505
|
-
310598401,
|
|
7506
|
-
607225278,
|
|
7507
|
-
1426881987,
|
|
7508
|
-
1925078388,
|
|
7509
|
-
2162078206,
|
|
7510
|
-
2614888103,
|
|
7511
|
-
3248222580,
|
|
7512
|
-
3835390401,
|
|
7513
|
-
4022224774,
|
|
7514
|
-
264347078,
|
|
7515
|
-
604807628,
|
|
7516
|
-
770255983,
|
|
7517
|
-
1249150122,
|
|
7518
|
-
1555081692,
|
|
7519
|
-
1996064986,
|
|
7520
|
-
2554220882,
|
|
7521
|
-
2821834349,
|
|
7522
|
-
2952996808,
|
|
7523
|
-
3210313671,
|
|
7524
|
-
3336571891,
|
|
7525
|
-
3584528711,
|
|
7526
|
-
113926993,
|
|
7527
|
-
338241895,
|
|
7528
|
-
666307205,
|
|
7529
|
-
773529912,
|
|
7530
|
-
1294757372,
|
|
7531
|
-
1396182291,
|
|
7532
|
-
1695183700,
|
|
7533
|
-
1986661051,
|
|
7534
|
-
2177026350,
|
|
7535
|
-
2456956037,
|
|
7536
|
-
2730485921,
|
|
7537
|
-
2820302411,
|
|
7538
|
-
3259730800,
|
|
7539
|
-
3345764771,
|
|
7540
|
-
3516065817,
|
|
7541
|
-
3600352804,
|
|
7542
|
-
4094571909,
|
|
7543
|
-
275423344,
|
|
7544
|
-
430227734,
|
|
7545
|
-
506948616,
|
|
7546
|
-
659060556,
|
|
7547
|
-
883997877,
|
|
7548
|
-
958139571,
|
|
7549
|
-
1322822218,
|
|
7550
|
-
1537002063,
|
|
7551
|
-
1747873779,
|
|
7552
|
-
1955562222,
|
|
7553
|
-
2024104815,
|
|
7554
|
-
2227730452,
|
|
7555
|
-
2361852424,
|
|
7556
|
-
2428436474,
|
|
7557
|
-
2756734187,
|
|
7558
|
-
3204031479,
|
|
7559
|
-
3329325298
|
|
7560
|
-
];
|
|
7561
|
-
function rightRotate32(value, bits) {
|
|
7562
|
-
return value >>> bits | value << 32 - bits;
|
|
7563
|
-
}
|
|
7564
|
-
function sha256Hex(input2) {
|
|
7565
|
-
const bytes = Array.from(new TextEncoder().encode(input2));
|
|
7566
|
-
const bitLength = bytes.length * 8;
|
|
7567
|
-
bytes.push(128);
|
|
7568
|
-
while (bytes.length % 64 !== 56) {
|
|
7569
|
-
bytes.push(0);
|
|
7570
|
-
}
|
|
7571
|
-
const highBits = Math.floor(bitLength / 4294967296);
|
|
7572
|
-
const lowBits = bitLength >>> 0;
|
|
7573
|
-
bytes.push(
|
|
7574
|
-
highBits >>> 24 & 255,
|
|
7575
|
-
highBits >>> 16 & 255,
|
|
7576
|
-
highBits >>> 8 & 255,
|
|
7577
|
-
highBits & 255,
|
|
7578
|
-
lowBits >>> 24 & 255,
|
|
7579
|
-
lowBits >>> 16 & 255,
|
|
7580
|
-
lowBits >>> 8 & 255,
|
|
7581
|
-
lowBits & 255
|
|
7582
|
-
);
|
|
7583
|
-
const hash = [...SHA256_INITIAL_HASH];
|
|
7584
|
-
const words = new Array(64).fill(0);
|
|
7585
|
-
for (let offset = 0; offset < bytes.length; offset += 64) {
|
|
7586
|
-
for (let index = 0; index < 16; index += 1) {
|
|
7587
|
-
const wordOffset = offset + index * 4;
|
|
7588
|
-
words[index] = (bytes[wordOffset] ?? 0) << 24 | (bytes[wordOffset + 1] ?? 0) << 16 | (bytes[wordOffset + 2] ?? 0) << 8 | (bytes[wordOffset + 3] ?? 0);
|
|
7589
|
-
}
|
|
7590
|
-
for (let index = 16; index < 64; index += 1) {
|
|
7591
|
-
const s0 = rightRotate32(words[index - 15], 7) ^ rightRotate32(words[index - 15], 18) ^ words[index - 15] >>> 3;
|
|
7592
|
-
const s1 = rightRotate32(words[index - 2], 17) ^ rightRotate32(words[index - 2], 19) ^ words[index - 2] >>> 10;
|
|
7593
|
-
words[index] = words[index - 16] + s0 + words[index - 7] + s1 >>> 0;
|
|
7594
|
-
}
|
|
7595
|
-
let [a, b, c, d, e, f, g, h] = hash;
|
|
7596
|
-
for (let index = 0; index < 64; index += 1) {
|
|
7597
|
-
const s1 = rightRotate32(e, 6) ^ rightRotate32(e, 11) ^ rightRotate32(e, 25);
|
|
7598
|
-
const ch = e & f ^ ~e & g;
|
|
7599
|
-
const temp1 = h + s1 + ch + SHA256_ROUND_CONSTANTS[index] + words[index] >>> 0;
|
|
7600
|
-
const s0 = rightRotate32(a, 2) ^ rightRotate32(a, 13) ^ rightRotate32(a, 22);
|
|
7601
|
-
const maj = a & b ^ a & c ^ b & c;
|
|
7602
|
-
const temp2 = s0 + maj >>> 0;
|
|
7603
|
-
h = g;
|
|
7604
|
-
g = f;
|
|
7605
|
-
f = e;
|
|
7606
|
-
e = d + temp1 >>> 0;
|
|
7607
|
-
d = c;
|
|
7608
|
-
c = b;
|
|
7609
|
-
b = a;
|
|
7610
|
-
a = temp1 + temp2 >>> 0;
|
|
7611
|
-
}
|
|
7612
|
-
hash[0] = hash[0] + a >>> 0;
|
|
7613
|
-
hash[1] = hash[1] + b >>> 0;
|
|
7614
|
-
hash[2] = hash[2] + c >>> 0;
|
|
7615
|
-
hash[3] = hash[3] + d >>> 0;
|
|
7616
|
-
hash[4] = hash[4] + e >>> 0;
|
|
7617
|
-
hash[5] = hash[5] + f >>> 0;
|
|
7618
|
-
hash[6] = hash[6] + g >>> 0;
|
|
7619
|
-
hash[7] = hash[7] + h >>> 0;
|
|
7620
|
-
}
|
|
7621
|
-
return hash.map((word) => word.toString(16).padStart(8, "0")).join("");
|
|
7622
|
-
}
|
|
7623
|
-
function sanitizeIdentifierPart(value) {
|
|
7624
|
-
return value.trim().replace(/[^a-z0-9]+/gi, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
7625
|
-
}
|
|
7626
|
-
function validateIdentifierPart(rawValue, label, maxLength) {
|
|
7627
|
-
const sanitized = sanitizeIdentifierPart(rawValue);
|
|
7628
|
-
if (!sanitized) {
|
|
7629
|
-
throw new Error(
|
|
7630
|
-
`${label} must contain at least one letter or number after normalization. Use only letters, numbers, underscores, or hyphens.`
|
|
7631
|
-
);
|
|
7632
|
-
}
|
|
7633
|
-
if (sanitized.length > maxLength) {
|
|
7634
|
-
throw new Error(
|
|
7635
|
-
`${label} is too long after normalization (${sanitized.length}/${maxLength}). Shorten it to ${maxLength} characters or fewer. Normalized value: "${sanitized}".`
|
|
7636
|
-
);
|
|
7637
|
-
}
|
|
7638
|
-
return sanitized;
|
|
7639
|
-
}
|
|
7640
|
-
function normalizePlayName(value) {
|
|
7641
|
-
if (value.includes("/")) {
|
|
7642
|
-
throw new Error(
|
|
7643
|
-
'Play name cannot contain "/". Slash is reserved for qualified play references like "prebuilt/example" or "self/example".'
|
|
7644
|
-
);
|
|
7645
|
-
}
|
|
7646
|
-
return validateIdentifierPart(value, "Play name", PLAY_NAME_MAX_LENGTH);
|
|
7647
|
-
}
|
|
7648
|
-
function normalizePlayNameForSheet(value) {
|
|
7649
|
-
if (!value.includes("/")) {
|
|
7650
|
-
return normalizePlayName(value);
|
|
7651
|
-
}
|
|
7652
|
-
const digest = sha256Hex(value).slice(0, 12);
|
|
7653
|
-
const normalizedReference = sanitizeIdentifierPart(
|
|
7654
|
-
value.replace(/\//g, "__")
|
|
7655
|
-
);
|
|
7656
|
-
const prefixLength = Math.max(1, PLAY_NAME_MAX_LENGTH - digest.length - 1);
|
|
7657
|
-
const prefix = normalizedReference.slice(0, prefixLength).replace(/_+$/g, "") || "qualified_play";
|
|
7658
|
-
return `${prefix}_${digest}`;
|
|
7659
|
-
}
|
|
7660
|
-
function normalizeTableNamespace(value) {
|
|
7661
|
-
return validateIdentifierPart(
|
|
7662
|
-
value,
|
|
7663
|
-
"ctx.dataset() key",
|
|
7664
|
-
MAP_KEY_NAMESPACE_MAX_LENGTH
|
|
7665
|
-
);
|
|
7666
|
-
}
|
|
7667
|
-
function validatePlaySheetTableName(playName, tableNamespace) {
|
|
7668
|
-
const playSegment = normalizePlayNameForSheet(playName);
|
|
7669
|
-
const keySegment = normalizeTableNamespace(tableNamespace);
|
|
7670
|
-
const resolved = `${playSegment}_${keySegment}`;
|
|
7671
|
-
if (resolved.length > POSTGRES_IDENTIFIER_MAX_LENGTH) {
|
|
7672
|
-
throw new Error(
|
|
7673
|
-
`Play sheet table name is too long after normalization (${resolved.length}/63). Shorten the play name or ctx.dataset() key. Resolved table name: "${resolved}".`
|
|
7674
|
-
);
|
|
7675
|
-
}
|
|
7676
|
-
return resolved;
|
|
7677
|
-
}
|
|
7678
|
-
|
|
7679
7616
|
// src/cli/trace.ts
|
|
7680
7617
|
var cliTraceStartedAt = Date.now();
|
|
7681
7618
|
function isTruthyEnv(value) {
|
|
@@ -7726,6 +7663,11 @@ async function traceCliSpan(phase, fields, run) {
|
|
|
7726
7663
|
|
|
7727
7664
|
// src/cli/play-check-hints.ts
|
|
7728
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.";
|
|
7729
7671
|
function sourceLineForError(sourceCode, error) {
|
|
7730
7672
|
const match = error.match(/:(\d+):(\d+)\s/);
|
|
7731
7673
|
const lineNumber = match?.[1] ? Number(match[1]) : NaN;
|
|
@@ -7736,16 +7678,61 @@ function looksLikeInvalidExtractedGetter(error, sourceLine) {
|
|
|
7736
7678
|
if (!/Property '[^']+' does not exist on type/.test(error)) return false;
|
|
7737
7679
|
return /\bextracted(?:Values|Lists)\s*\./.test(sourceLine);
|
|
7738
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
|
+
}
|
|
7739
7725
|
function addPlayCheckRepairHints(input2) {
|
|
7740
|
-
|
|
7726
|
+
const addedHints = /* @__PURE__ */ new Set();
|
|
7741
7727
|
return input2.errors.map((error) => {
|
|
7742
7728
|
const line = sourceLineForError(input2.sourceCode, error);
|
|
7743
|
-
|
|
7729
|
+
const hint = hintForError(error, line);
|
|
7730
|
+
if (!hint || addedHints.has(hint) || error.includes(hint)) {
|
|
7744
7731
|
return error;
|
|
7745
7732
|
}
|
|
7746
|
-
|
|
7733
|
+
addedHints.add(hint);
|
|
7747
7734
|
return `${error}
|
|
7748
|
-
${
|
|
7735
|
+
${hint}`;
|
|
7749
7736
|
});
|
|
7750
7737
|
}
|
|
7751
7738
|
|
|
@@ -7860,10 +7847,10 @@ function materializeRemotePlaySource(input2) {
|
|
|
7860
7847
|
if (existingSource === input2.sourceCode) {
|
|
7861
7848
|
return { path: outputPath, status: "unchanged", created: false };
|
|
7862
7849
|
}
|
|
7863
|
-
|
|
7850
|
+
writeFileSync7(outputPath, input2.sourceCode, "utf-8");
|
|
7864
7851
|
return { path: outputPath, status: "updated", created: false };
|
|
7865
7852
|
}
|
|
7866
|
-
|
|
7853
|
+
writeFileSync7(outputPath, input2.sourceCode, "utf-8");
|
|
7867
7854
|
return { path: outputPath, status: "created", created: true };
|
|
7868
7855
|
}
|
|
7869
7856
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -8302,8 +8289,6 @@ var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
|
8302
8289
|
"cancelled"
|
|
8303
8290
|
]);
|
|
8304
8291
|
var PLAY_START_TRANSIENT_RETRY_DELAYS_MS = [500, 1500];
|
|
8305
|
-
var PLAY_CUSTOMER_STORAGE_SCHEMA_NAME = "storage";
|
|
8306
|
-
var PLAY_INTERNAL_STEP_RECEIPT_TABLE = "_deepline_step_receipts";
|
|
8307
8292
|
function getEventPayload(event) {
|
|
8308
8293
|
return event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
8309
8294
|
}
|
|
@@ -8357,36 +8342,8 @@ function getLogLinesFromLiveEvent(event) {
|
|
|
8357
8342
|
const lines = getEventPayload(event).lines;
|
|
8358
8343
|
return Array.isArray(lines) ? lines.filter((line) => typeof line === "string") : [];
|
|
8359
8344
|
}
|
|
8360
|
-
function
|
|
8361
|
-
return `
|
|
8362
|
-
}
|
|
8363
|
-
function quoteSqlLiteral(value) {
|
|
8364
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
8365
|
-
}
|
|
8366
|
-
function buildDebugDbQueryCommand(sql) {
|
|
8367
|
-
return `deepline db query --sql ${shellSingleQuote(sql)} --max-rows 20 --json`;
|
|
8368
|
-
}
|
|
8369
|
-
function buildStepReceiptsDebugCommand(runId) {
|
|
8370
|
-
const table = `${quoteSqlIdentifier(
|
|
8371
|
-
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8372
|
-
)}.${quoteSqlIdentifier(PLAY_INTERNAL_STEP_RECEIPT_TABLE)}`;
|
|
8373
|
-
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`;
|
|
8374
|
-
return buildDebugDbQueryCommand(sql);
|
|
8375
|
-
}
|
|
8376
|
-
function buildMapTableDebugCommand(input2) {
|
|
8377
|
-
try {
|
|
8378
|
-
const tableName = validatePlaySheetTableName(
|
|
8379
|
-
input2.playName,
|
|
8380
|
-
input2.tableNamespace
|
|
8381
|
-
);
|
|
8382
|
-
const table = `${quoteSqlIdentifier(
|
|
8383
|
-
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8384
|
-
)}.${quoteSqlIdentifier(tableName)}`;
|
|
8385
|
-
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(input2.runId)} limit 20`;
|
|
8386
|
-
return buildDebugDbQueryCommand(sql);
|
|
8387
|
-
} catch {
|
|
8388
|
-
return null;
|
|
8389
|
-
}
|
|
8345
|
+
function buildRunInspectCommand(runId) {
|
|
8346
|
+
return `deepline runs get ${runId} --full --json`;
|
|
8390
8347
|
}
|
|
8391
8348
|
function extractTableNamespaceFromLiveEvent(event) {
|
|
8392
8349
|
const payload = getEventPayload(event);
|
|
@@ -8411,7 +8368,7 @@ function emitLiveDebugTableHints(input2) {
|
|
|
8411
8368
|
if (!input2.state.emittedDebugKeys.has(receiptsKey)) {
|
|
8412
8369
|
input2.state.emittedDebugKeys.add(receiptsKey);
|
|
8413
8370
|
input2.progress.writeLine(
|
|
8414
|
-
`
|
|
8371
|
+
`Inspect run output: ${buildRunInspectCommand(input2.runId)}`,
|
|
8415
8372
|
process.stdout
|
|
8416
8373
|
);
|
|
8417
8374
|
}
|
|
@@ -8423,17 +8380,9 @@ function emitLiveDebugTableHints(input2) {
|
|
|
8423
8380
|
if (input2.state.emittedDebugKeys.has(tableKey)) {
|
|
8424
8381
|
return;
|
|
8425
8382
|
}
|
|
8426
|
-
const command = buildMapTableDebugCommand({
|
|
8427
|
-
playName: input2.playName,
|
|
8428
|
-
runId: input2.runId,
|
|
8429
|
-
tableNamespace
|
|
8430
|
-
});
|
|
8431
|
-
if (!command) {
|
|
8432
|
-
return;
|
|
8433
|
-
}
|
|
8434
8383
|
input2.state.emittedDebugKeys.add(tableKey);
|
|
8435
8384
|
input2.progress.writeLine(
|
|
8436
|
-
`
|
|
8385
|
+
`Possible map table ${tableNamespace}: created only after this ctx.map(...).run(...) executes. Inspect returned datasets with ${buildRunInspectCommand(input2.runId)}`,
|
|
8437
8386
|
process.stdout
|
|
8438
8387
|
);
|
|
8439
8388
|
}
|
|
@@ -8637,7 +8586,7 @@ async function waitForPlayCompletionByStream(input2) {
|
|
|
8637
8586
|
}
|
|
8638
8587
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8639
8588
|
throw new DeeplineError(
|
|
8640
|
-
`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}'.`,
|
|
8641
8590
|
void 0,
|
|
8642
8591
|
"PLAY_LIVE_STREAM_ENDED",
|
|
8643
8592
|
{
|
|
@@ -8798,7 +8747,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8798
8747
|
const reason = error instanceof Error ? error.message : String(error);
|
|
8799
8748
|
if (!input2.jsonOutput) {
|
|
8800
8749
|
process.stderr.write(
|
|
8801
|
-
`[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})
|
|
8802
8751
|
`
|
|
8803
8752
|
);
|
|
8804
8753
|
}
|
|
@@ -8835,7 +8784,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8835
8784
|
if (lastKnownWorkflowId) {
|
|
8836
8785
|
if (!input2.jsonOutput) {
|
|
8837
8786
|
input2.progress.writeLine(
|
|
8838
|
-
`[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`
|
|
8839
8788
|
);
|
|
8840
8789
|
}
|
|
8841
8790
|
recordCliTrace({
|
|
@@ -8865,7 +8814,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
8865
8814
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8866
8815
|
const idSuffix = lastKnownWorkflowId ? ` runId=${lastKnownWorkflowId}` : "";
|
|
8867
8816
|
throw new DeeplineError(
|
|
8868
|
-
`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>'.`,
|
|
8869
8818
|
void 0,
|
|
8870
8819
|
"PLAY_START_STREAM_ENDED",
|
|
8871
8820
|
{
|
|
@@ -9213,6 +9162,32 @@ function formatPlayErrorForDisplay(status, error) {
|
|
|
9213
9162
|
}
|
|
9214
9163
|
return error;
|
|
9215
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
|
+
}
|
|
9216
9191
|
function normalizeRunStatusForEnvelope(status) {
|
|
9217
9192
|
const run = status.run ?? null;
|
|
9218
9193
|
return {
|
|
@@ -9350,8 +9325,7 @@ function compactPlayStatus(status) {
|
|
|
9350
9325
|
const billing = status && typeof status === "object" ? stripProviderSpendFromBilling(
|
|
9351
9326
|
status.billing
|
|
9352
9327
|
) : null;
|
|
9353
|
-
const
|
|
9354
|
-
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);
|
|
9355
9329
|
const displayError = formatPlayErrorForDisplay(status, error);
|
|
9356
9330
|
return {
|
|
9357
9331
|
runId: status.runId,
|
|
@@ -9606,8 +9580,8 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
9606
9580
|
for (const warning of warnings) {
|
|
9607
9581
|
lines.push(` warning: ${warning}`);
|
|
9608
9582
|
}
|
|
9609
|
-
const progressError = status
|
|
9610
|
-
if (progressError
|
|
9583
|
+
const progressError = selectRunErrorForDisplay(status);
|
|
9584
|
+
if (progressError) {
|
|
9611
9585
|
const billing = extractBillingForStatus(status, progressError);
|
|
9612
9586
|
if (isInsufficientCreditsBilling(billing)) {
|
|
9613
9587
|
lines.push(...buildInsufficientCreditsSummaryLines({ status, billing }));
|
|
@@ -9659,9 +9633,6 @@ var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
|
9659
9633
|
function shellSingleQuote(value) {
|
|
9660
9634
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
9661
9635
|
}
|
|
9662
|
-
function sqlStringLiteral(value) {
|
|
9663
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
9664
|
-
}
|
|
9665
9636
|
function runExportRetryCommand(runId, outPath, datasetPath) {
|
|
9666
9637
|
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote(resolve10(outPath))}`;
|
|
9667
9638
|
}
|
|
@@ -9680,26 +9651,6 @@ function extractRunPlayName(status) {
|
|
|
9680
9651
|
}
|
|
9681
9652
|
return null;
|
|
9682
9653
|
}
|
|
9683
|
-
function normalizeCustomerDbIdentifier(value) {
|
|
9684
|
-
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
9685
|
-
}
|
|
9686
|
-
function buildCustomerDbQueryPlan(input2) {
|
|
9687
|
-
const playName = extractRunPlayName(input2.status);
|
|
9688
|
-
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9689
|
-
if (!playName || !tableNamespace || input2.rowsInfo.totalRows <= 0) {
|
|
9690
|
-
return null;
|
|
9691
|
-
}
|
|
9692
|
-
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
9693
|
-
tableNamespace
|
|
9694
|
-
)}`;
|
|
9695
|
-
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input2.status.runId)} limit ${input2.rowsInfo.totalRows}`;
|
|
9696
|
-
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input2.rowsInfo.totalRows}`;
|
|
9697
|
-
return {
|
|
9698
|
-
sql,
|
|
9699
|
-
json: `${base} --json`,
|
|
9700
|
-
csv: `${base} --format csv --out ${shellSingleQuote(resolve10(input2.outPath))}`
|
|
9701
|
-
};
|
|
9702
|
-
}
|
|
9703
9654
|
function exportableSheetRow(row) {
|
|
9704
9655
|
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
9705
9656
|
return null;
|
|
@@ -10046,8 +9997,12 @@ function renderServerResultView(value) {
|
|
|
10046
9997
|
lines.push(
|
|
10047
9998
|
` ${String(table.tableNamespace ?? "table")}${lineLabel}: ${rowLabel}${details.join(" ")}`
|
|
10048
9999
|
);
|
|
10049
|
-
if (typeof table.queryDatasetCommand === "string") {
|
|
10050
|
-
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
|
+
);
|
|
10051
10006
|
}
|
|
10052
10007
|
if (table.debugHelp && typeof table.debugHelp === "object" && !Array.isArray(table.debugHelp)) {
|
|
10053
10008
|
const debugHelp = table.debugHelp;
|
|
@@ -10393,9 +10348,51 @@ function printToolGetterHints(hints) {
|
|
|
10393
10348
|
async function handlePlayCheck(args) {
|
|
10394
10349
|
const options = parsePlayCheckOptions(args);
|
|
10395
10350
|
if (!isFileTarget(options.target)) {
|
|
10396
|
-
const
|
|
10397
|
-
|
|
10398
|
-
|
|
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
|
+
}
|
|
10399
10396
|
}
|
|
10400
10397
|
const absolutePlayPath = resolve10(options.target);
|
|
10401
10398
|
const sourceCode = readFileSync6(absolutePlayPath, "utf-8");
|
|
@@ -10932,7 +10929,7 @@ async function handleRunLogs(args) {
|
|
|
10932
10929
|
const status = await client.runs.get(runId);
|
|
10933
10930
|
const logs = status.progress?.logs ?? [];
|
|
10934
10931
|
if (outPath) {
|
|
10935
|
-
|
|
10932
|
+
writeFileSync7(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
10936
10933
|
printCommandEnvelope(
|
|
10937
10934
|
{
|
|
10938
10935
|
runId: status.runId,
|
|
@@ -11042,18 +11039,9 @@ async function handleRunExport(args) {
|
|
|
11042
11039
|
datasetPath
|
|
11043
11040
|
});
|
|
11044
11041
|
const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
|
|
11045
|
-
const queryPlan = exportResult && outPath ? buildCustomerDbQueryPlan({
|
|
11046
|
-
status,
|
|
11047
|
-
rowsInfo: exportResult.rowsInfo,
|
|
11048
|
-
outPath
|
|
11049
|
-
}) : null;
|
|
11050
11042
|
const next = {
|
|
11051
11043
|
...buildRunNextCommands(status),
|
|
11052
|
-
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
|
|
11053
|
-
...queryPlan ? {
|
|
11054
|
-
queryJson: queryPlan.json,
|
|
11055
|
-
queryCsv: queryPlan.csv
|
|
11056
|
-
} : {}
|
|
11044
|
+
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
|
|
11057
11045
|
};
|
|
11058
11046
|
const payload = {
|
|
11059
11047
|
runId: status.runId,
|
|
@@ -11062,13 +11050,6 @@ async function handleRunExport(args) {
|
|
|
11062
11050
|
source,
|
|
11063
11051
|
rowCount: exportResult?.rowsInfo.totalRows ?? null,
|
|
11064
11052
|
columns: exportResult?.rowsInfo.columns ?? [],
|
|
11065
|
-
...queryPlan ? {
|
|
11066
|
-
query: {
|
|
11067
|
-
sql: queryPlan.sql,
|
|
11068
|
-
json: queryPlan.json,
|
|
11069
|
-
csv: queryPlan.csv
|
|
11070
|
-
}
|
|
11071
|
-
} : {},
|
|
11072
11053
|
...metadataOutPath ? { metadata_path: metadataOutPath } : {},
|
|
11073
11054
|
local: { csv_path: exportResult?.path ?? null },
|
|
11074
11055
|
next,
|
|
@@ -11078,15 +11059,14 @@ async function handleRunExport(args) {
|
|
|
11078
11059
|
title: "run export",
|
|
11079
11060
|
lines: [
|
|
11080
11061
|
`Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
|
|
11081
|
-
...source ? [`source=${source}`] : []
|
|
11082
|
-
...queryPlan ? [`query=${queryPlan.json}`] : []
|
|
11062
|
+
...source ? [`source=${source}`] : []
|
|
11083
11063
|
]
|
|
11084
11064
|
}
|
|
11085
11065
|
]
|
|
11086
11066
|
}
|
|
11087
11067
|
};
|
|
11088
11068
|
if (metadataOutPath) {
|
|
11089
|
-
|
|
11069
|
+
writeFileSync7(
|
|
11090
11070
|
metadataOutPath,
|
|
11091
11071
|
`${JSON.stringify(payload, null, 2)}
|
|
11092
11072
|
`,
|
|
@@ -11259,7 +11239,8 @@ function parsePlaySearchOptions(args) {
|
|
|
11259
11239
|
return {
|
|
11260
11240
|
query,
|
|
11261
11241
|
jsonOutput: argsWantJson(args),
|
|
11262
|
-
compact: args.includes("--compact")
|
|
11242
|
+
compact: args.includes("--compact"),
|
|
11243
|
+
prebuiltOnly: args.includes("--prebuilt")
|
|
11263
11244
|
};
|
|
11264
11245
|
}
|
|
11265
11246
|
function printPlayDescription(play) {
|
|
@@ -11307,6 +11288,7 @@ function printPlayDescription(play) {
|
|
|
11307
11288
|
console.log(` ${line}`);
|
|
11308
11289
|
}
|
|
11309
11290
|
}
|
|
11291
|
+
console.log(` Describe: deepline plays describe ${reference} --json`);
|
|
11310
11292
|
console.log(` Run: ${play.runCommand}`);
|
|
11311
11293
|
const cloneEditStarter = play.cloneEditStarter ?? buildCloneEditStarter(play);
|
|
11312
11294
|
if (cloneEditStarter) {
|
|
@@ -11314,6 +11296,31 @@ function printPlayDescription(play) {
|
|
|
11314
11296
|
console.log(` Check starter: ${cloneEditStarter.checkCommand}`);
|
|
11315
11297
|
}
|
|
11316
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
|
+
}
|
|
11317
11324
|
function compactPlaySchema(schema) {
|
|
11318
11325
|
if (!schema) return null;
|
|
11319
11326
|
const fields = Array.isArray(schema.fields) ? schema.fields.map(
|
|
@@ -11377,22 +11384,44 @@ async function handlePlaySearch(args) {
|
|
|
11377
11384
|
return 1;
|
|
11378
11385
|
}
|
|
11379
11386
|
const client = new DeeplineClient();
|
|
11380
|
-
const plays = await client.searchPlays({
|
|
11387
|
+
const plays = (await client.searchPlays({
|
|
11381
11388
|
query: options.query,
|
|
11382
11389
|
compact: options.compact
|
|
11383
|
-
})
|
|
11390
|
+
})).filter(
|
|
11391
|
+
(play) => options.prebuiltOnly ? play.origin === "prebuilt" || play.ownerType === "deepline" : true
|
|
11392
|
+
);
|
|
11384
11393
|
if (options.jsonOutput) {
|
|
11385
|
-
|
|
11386
|
-
|
|
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
|
+
);
|
|
11387
11406
|
return 0;
|
|
11388
11407
|
}
|
|
11389
|
-
|
|
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}` : ""}:
|
|
11390
11411
|
|
|
11391
|
-
`
|
|
11392
|
-
|
|
11393
|
-
|
|
11412
|
+
`
|
|
11413
|
+
);
|
|
11414
|
+
for (const play of displayPlays) {
|
|
11415
|
+
if (options.prebuiltOnly) {
|
|
11416
|
+
printCompactPlaySearchResult(play);
|
|
11417
|
+
} else {
|
|
11418
|
+
printPlayDescription(play);
|
|
11419
|
+
}
|
|
11394
11420
|
console.log("");
|
|
11395
11421
|
}
|
|
11422
|
+
if (options.prebuiltOnly && plays.length > displayPlays.length) {
|
|
11423
|
+
console.log("Use --json for the full machine-readable result set.");
|
|
11424
|
+
}
|
|
11396
11425
|
return 0;
|
|
11397
11426
|
}
|
|
11398
11427
|
function normalizePlayGrepText(value) {
|
|
@@ -11659,15 +11688,18 @@ Common commands:
|
|
|
11659
11688
|
deepline plays get person-linkedin-to-email --json
|
|
11660
11689
|
`
|
|
11661
11690
|
);
|
|
11662
|
-
play.command("check <target>").description("
|
|
11691
|
+
play.command("check <target>").description("Check a local play file or named/prebuilt play contract.").addHelpText(
|
|
11663
11692
|
"after",
|
|
11664
11693
|
`
|
|
11665
11694
|
Notes:
|
|
11666
11695
|
Validates a local play without storing it, promoting it, or starting a run.
|
|
11667
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.
|
|
11668
11699
|
|
|
11669
11700
|
Examples:
|
|
11670
11701
|
deepline plays check my.play.ts
|
|
11702
|
+
deepline plays check prebuilt/name-and-domain-to-email-waterfall-batch
|
|
11671
11703
|
deepline plays check my.play.ts --json
|
|
11672
11704
|
`
|
|
11673
11705
|
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
|
|
@@ -11817,11 +11849,13 @@ Examples:
|
|
|
11817
11849
|
...options.json ? ["--json"] : []
|
|
11818
11850
|
]);
|
|
11819
11851
|
});
|
|
11820
|
-
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(
|
|
11821
11853
|
"after",
|
|
11822
11854
|
`
|
|
11823
11855
|
Notes:
|
|
11824
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.
|
|
11825
11859
|
The grep alias is the same ranked retrieval surface with a more literal name
|
|
11826
11860
|
for agents that are filtering the play registry.
|
|
11827
11861
|
|
|
@@ -11833,6 +11867,7 @@ Examples:
|
|
|
11833
11867
|
).option("--compact", "Emit compact schemas").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
11834
11868
|
process.exitCode = await handlePlaySearch([
|
|
11835
11869
|
query,
|
|
11870
|
+
...options.prebuilt ? ["--prebuilt"] : [],
|
|
11836
11871
|
...options.compact ? ["--compact"] : [],
|
|
11837
11872
|
...options.json ? ["--json"] : []
|
|
11838
11873
|
]);
|
|
@@ -12080,7 +12115,7 @@ Notes:
|
|
|
12080
12115
|
Writes a returned dataset handle to the requested local CSV path. Use runs get
|
|
12081
12116
|
first to inspect dataset paths like result.rows or result.nested.contacts.
|
|
12082
12117
|
--metadata-out writes the same export metadata object returned by --json,
|
|
12083
|
-
including source
|
|
12118
|
+
including the source dataset path and row/column metadata.
|
|
12084
12119
|
|
|
12085
12120
|
Examples:
|
|
12086
12121
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
@@ -13787,12 +13822,12 @@ Examples:
|
|
|
13787
13822
|
|
|
13788
13823
|
// src/cli/commands/tools.ts
|
|
13789
13824
|
import { Option } from "commander";
|
|
13790
|
-
import { chmodSync, mkdtempSync, writeFileSync as
|
|
13825
|
+
import { chmodSync, mkdtempSync, writeFileSync as writeFileSync9 } from "fs";
|
|
13791
13826
|
import { tmpdir as tmpdir4 } from "os";
|
|
13792
13827
|
import { join as join10 } from "path";
|
|
13793
13828
|
|
|
13794
13829
|
// src/tool-output.ts
|
|
13795
|
-
import { mkdirSync as mkdirSync4, writeFileSync as
|
|
13830
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
13796
13831
|
import { homedir as homedir5 } from "os";
|
|
13797
13832
|
import { join as join9 } from "path";
|
|
13798
13833
|
function isPlainObject(value) {
|
|
@@ -13897,7 +13932,7 @@ function ensureOutputDir() {
|
|
|
13897
13932
|
function writeJsonOutputFile(payload, stem) {
|
|
13898
13933
|
const outputDir = ensureOutputDir();
|
|
13899
13934
|
const outputPath = join9(outputDir, `${stem}_${Date.now()}.json`);
|
|
13900
|
-
|
|
13935
|
+
writeFileSync8(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
13901
13936
|
return outputPath;
|
|
13902
13937
|
}
|
|
13903
13938
|
function writeCsvOutputFile(rows, stem) {
|
|
@@ -13925,7 +13960,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
13925
13960
|
for (const row of rows) {
|
|
13926
13961
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
13927
13962
|
}
|
|
13928
|
-
|
|
13963
|
+
writeFileSync8(outputPath, `${lines.join("\n")}
|
|
13929
13964
|
`, "utf-8");
|
|
13930
13965
|
const previewRows = rows.slice(0, 5);
|
|
13931
13966
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -14011,7 +14046,7 @@ async function listTools(args) {
|
|
|
14011
14046
|
const client = new DeeplineClient();
|
|
14012
14047
|
const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
|
|
14013
14048
|
const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
|
|
14014
|
-
const compact = args.includes("--compact");
|
|
14049
|
+
const compact = args.includes("--compact") || !args.includes("--json");
|
|
14015
14050
|
const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
14016
14051
|
const items = (await client.listTools({
|
|
14017
14052
|
...categoryFilter ? { categories: categoryFilter } : {}
|
|
@@ -14067,9 +14102,10 @@ async function searchTools(queryInput, options = {}) {
|
|
|
14067
14102
|
searchMode: options.searchMode,
|
|
14068
14103
|
includeSearchDebug: options.includeSearchDebug
|
|
14069
14104
|
});
|
|
14070
|
-
const
|
|
14105
|
+
const shouldCompact = options.compact || !options.json;
|
|
14106
|
+
const payload = shouldCompact && Array.isArray(result.tools) ? {
|
|
14071
14107
|
...result,
|
|
14072
|
-
tools: result.tools.map(compactTool)
|
|
14108
|
+
tools: result.tools.slice(0, 8).map(compactTool)
|
|
14073
14109
|
} : result;
|
|
14074
14110
|
printCommandEnvelope(payload, {
|
|
14075
14111
|
json: options.json || shouldEmitJson()
|
|
@@ -14110,7 +14146,8 @@ async function grepTools(queryInput, options = {}) {
|
|
|
14110
14146
|
mode
|
|
14111
14147
|
)
|
|
14112
14148
|
);
|
|
14113
|
-
const
|
|
14149
|
+
const shouldCompact = options.compact || !options.json;
|
|
14150
|
+
const outputTools = shouldCompact ? tools.slice(0, 8).map(compactTool) : tools;
|
|
14114
14151
|
printCommandEnvelope(
|
|
14115
14152
|
{
|
|
14116
14153
|
tools: outputTools,
|
|
@@ -14129,11 +14166,19 @@ async function grepTools(queryInput, options = {}) {
|
|
|
14129
14166
|
);
|
|
14130
14167
|
return 0;
|
|
14131
14168
|
}
|
|
14169
|
+
function numericToolField(tool, field) {
|
|
14170
|
+
const value = tool[field];
|
|
14171
|
+
return typeof value === "number" ? value : void 0;
|
|
14172
|
+
}
|
|
14132
14173
|
function compactTool(tool) {
|
|
14133
14174
|
const listed = toListedTool(tool);
|
|
14175
|
+
const searchScore = numericToolField(tool, "searchScore");
|
|
14176
|
+
const search_score = numericToolField(tool, "search_score");
|
|
14134
14177
|
return {
|
|
14135
14178
|
id: listed.id,
|
|
14136
14179
|
toolId: listed.toolId,
|
|
14180
|
+
...search_score !== void 0 ? { search_score } : {},
|
|
14181
|
+
...searchScore !== void 0 ? { searchScore } : {},
|
|
14137
14182
|
provider: listed.provider,
|
|
14138
14183
|
displayName: listed.displayName,
|
|
14139
14184
|
description: listed.description,
|
|
@@ -14454,7 +14499,7 @@ async function getTool(toolId, options = {}) {
|
|
|
14454
14499
|
}
|
|
14455
14500
|
if (shouldEmitJson()) {
|
|
14456
14501
|
process.stdout.write(
|
|
14457
|
-
`${JSON.stringify(
|
|
14502
|
+
`${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
|
|
14458
14503
|
`
|
|
14459
14504
|
);
|
|
14460
14505
|
return 0;
|
|
@@ -14779,8 +14824,8 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
|
14779
14824
|
invalidGetterHint: "If TypeScript says an extractedValues/extractedLists property does not exist, that field is not a declared Deepline getter.",
|
|
14780
14825
|
observeActualShape: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
14781
14826
|
observedOutput: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
14782
|
-
forPlayGetterBugs: "Run
|
|
14783
|
-
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."
|
|
14784
14829
|
},
|
|
14785
14830
|
starterScript: {
|
|
14786
14831
|
path: starterScript.path,
|
|
@@ -15031,7 +15076,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
15031
15076
|
};
|
|
15032
15077
|
});
|
|
15033
15078
|
`;
|
|
15034
|
-
|
|
15079
|
+
writeFileSync9(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
15035
15080
|
return {
|
|
15036
15081
|
path: scriptPath,
|
|
15037
15082
|
sourceCode: script,
|
|
@@ -15587,7 +15632,7 @@ import {
|
|
|
15587
15632
|
readdirSync as readdirSync2,
|
|
15588
15633
|
readFileSync as readFileSync7,
|
|
15589
15634
|
statSync as statSync2,
|
|
15590
|
-
writeFileSync as
|
|
15635
|
+
writeFileSync as writeFileSync10
|
|
15591
15636
|
} from "fs";
|
|
15592
15637
|
import { homedir as homedir6 } from "os";
|
|
15593
15638
|
import { dirname as dirname10, join as join12 } from "path";
|
|
@@ -15621,7 +15666,7 @@ function readLocalSkillsVersion(baseUrl) {
|
|
|
15621
15666
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
15622
15667
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
15623
15668
|
mkdirSync5(dirname10(path), { recursive: true });
|
|
15624
|
-
|
|
15669
|
+
writeFileSync10(path, `${version}
|
|
15625
15670
|
`, "utf-8");
|
|
15626
15671
|
}
|
|
15627
15672
|
function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
@@ -15804,6 +15849,7 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
15804
15849
|
}
|
|
15805
15850
|
|
|
15806
15851
|
// src/cli/index.ts
|
|
15852
|
+
var PREFLIGHT_TIMEOUT_MS = 3e3;
|
|
15807
15853
|
function asCommanderError(error) {
|
|
15808
15854
|
if (!(error instanceof Error) || !("code" in error)) {
|
|
15809
15855
|
return null;
|
|
@@ -15884,6 +15930,124 @@ async function runPlayRunnerHealthCheck() {
|
|
|
15884
15930
|
await rm2(dir, { recursive: true, force: true });
|
|
15885
15931
|
}
|
|
15886
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
|
+
}
|
|
15887
16051
|
async function main() {
|
|
15888
16052
|
const mainStartedAt = Date.now();
|
|
15889
16053
|
recordCliTrace({
|
|
@@ -15900,6 +16064,7 @@ async function main() {
|
|
|
15900
16064
|
"after",
|
|
15901
16065
|
`
|
|
15902
16066
|
Common commands:
|
|
16067
|
+
deepline preflight
|
|
15903
16068
|
deepline health
|
|
15904
16069
|
deepline auth status --json
|
|
15905
16070
|
deepline plays search email --json
|
|
@@ -15921,7 +16086,6 @@ Output:
|
|
|
15921
16086
|
|
|
15922
16087
|
Safety:
|
|
15923
16088
|
Commands that mutate state, open a browser, write files, stop work, or spend credits say so in their help.
|
|
15924
|
-
Use --no-open where available for CI and agent runs.
|
|
15925
16089
|
|
|
15926
16090
|
Exit codes:
|
|
15927
16091
|
0 success; 2 usage/local input error; 3 auth/permission error; 4 not found;
|
|
@@ -15963,6 +16127,26 @@ Exit codes:
|
|
|
15963
16127
|
registerDbCommands(program);
|
|
15964
16128
|
registerFeedbackCommands(program);
|
|
15965
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
|
+
});
|
|
15966
16150
|
program.command("health").description("Check server health.").option("--json", "Force JSON output.").option(
|
|
15967
16151
|
"--play-runner",
|
|
15968
16152
|
"Run a tiny no-provider play to verify the full play execution plane."
|