deepline 0.1.74 → 0.1.77
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/dist/cli/index.js +1305 -345
- package/dist/cli/index.mjs +1307 -347
- package/dist/index.d.mts +77 -1
- package/dist/index.d.ts +77 -1
- package/dist/index.js +201 -3
- package/dist/index.mjs +201 -3
- package/dist/repo/apps/play-runner-workers/src/entry.ts +101 -45
- package/dist/repo/sdk/src/client.ts +8 -0
- package/dist/repo/sdk/src/play.ts +2 -1
- package/dist/repo/sdk/src/plays/harness-stub.ts +1 -0
- package/dist/repo/sdk/src/release.ts +3 -3
- package/dist/repo/sdk/src/worker-play-entry.ts +3 -0
- package/dist/repo/shared_libs/play-runtime/cell-staleness.ts +88 -0
- package/dist/repo/shared_libs/play-runtime/email-status.ts +301 -0
- package/dist/repo/shared_libs/play-runtime/step-program-dataset-builder.ts +5 -0
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +58 -1
- package/dist/repo/shared_libs/plays/row-identity.ts +0 -40
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -24,9 +24,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/cli/index.ts
|
|
27
|
-
var
|
|
28
|
-
var
|
|
29
|
-
var
|
|
27
|
+
var import_promises6 = require("fs/promises");
|
|
28
|
+
var import_node_path18 = require("path");
|
|
29
|
+
var import_node_os11 = require("os");
|
|
30
30
|
var import_commander3 = require("commander");
|
|
31
31
|
|
|
32
32
|
// src/config.ts
|
|
@@ -229,10 +229,10 @@ var import_node_path2 = require("path");
|
|
|
229
229
|
|
|
230
230
|
// src/release.ts
|
|
231
231
|
var SDK_RELEASE = {
|
|
232
|
-
version: "0.1.
|
|
233
|
-
apiContract: "2026-06-dataset-column-
|
|
232
|
+
version: "0.1.77",
|
|
233
|
+
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
234
234
|
supportPolicy: {
|
|
235
|
-
latest: "0.1.
|
|
235
|
+
latest: "0.1.77",
|
|
236
236
|
minimumSupported: "0.1.53",
|
|
237
237
|
deprecatedBelow: "0.1.53"
|
|
238
238
|
}
|
|
@@ -579,7 +579,7 @@ function decodeSseFrame(frame) {
|
|
|
579
579
|
return parsed;
|
|
580
580
|
}
|
|
581
581
|
function sleep(ms) {
|
|
582
|
-
return new Promise((
|
|
582
|
+
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
583
583
|
}
|
|
584
584
|
|
|
585
585
|
// src/client.ts
|
|
@@ -589,7 +589,7 @@ var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
|
|
|
589
589
|
var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
|
|
590
590
|
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
591
591
|
function sleep2(ms) {
|
|
592
|
-
return new Promise((
|
|
592
|
+
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
593
593
|
}
|
|
594
594
|
function isTransientCompileManifestError(error) {
|
|
595
595
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
@@ -1115,6 +1115,9 @@ var DeeplineClient = class {
|
|
|
1115
1115
|
async checkPlayArtifact(input2) {
|
|
1116
1116
|
return this.http.post("/api/v2/plays/check", input2);
|
|
1117
1117
|
}
|
|
1118
|
+
async compileEnrichPlan(input2) {
|
|
1119
|
+
return this.http.post("/api/v2/enrich/compile", input2);
|
|
1120
|
+
}
|
|
1118
1121
|
async startPlayRunFromBundle(input2) {
|
|
1119
1122
|
const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
|
|
1120
1123
|
name: input2.name,
|
|
@@ -2397,7 +2400,7 @@ function buildCandidateUrls2(url) {
|
|
|
2397
2400
|
}
|
|
2398
2401
|
}
|
|
2399
2402
|
function sleep3(ms) {
|
|
2400
|
-
return new Promise((
|
|
2403
|
+
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
2401
2404
|
}
|
|
2402
2405
|
function printDeeplineLogo() {
|
|
2403
2406
|
if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
|
|
@@ -3775,38 +3778,38 @@ function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns
|
|
|
3775
3778
|
}
|
|
3776
3779
|
}
|
|
3777
3780
|
const denominator = nonEmpty + empty;
|
|
3778
|
-
const
|
|
3781
|
+
const stat4 = {
|
|
3779
3782
|
non_empty: percentText(nonEmpty, denominator),
|
|
3780
3783
|
unique: valueCounts.size
|
|
3781
3784
|
};
|
|
3782
3785
|
const rawExecutionStats = executionStats?.columnStats[column];
|
|
3783
3786
|
if (rawExecutionStats) {
|
|
3784
|
-
|
|
3787
|
+
stat4.execution = formatDatasetExecutionStats(
|
|
3785
3788
|
rawExecutionStats,
|
|
3786
3789
|
totalRows
|
|
3787
3790
|
);
|
|
3788
3791
|
}
|
|
3789
3792
|
if (sampleValue !== void 0 && sampleValueType) {
|
|
3790
|
-
|
|
3791
|
-
|
|
3793
|
+
stat4.sample_value = sampleValue;
|
|
3794
|
+
stat4.sample_type = sampleValueType;
|
|
3792
3795
|
}
|
|
3793
3796
|
if (valueCounts.size > 0 && valueCounts.size < nonEmpty) {
|
|
3794
3797
|
const top = [...valueCounts.entries()].sort((left, right) => right[1] - left[1]).slice(0, 3);
|
|
3795
3798
|
const topKeys = new Set(top.map(([key]) => key));
|
|
3796
3799
|
const otherCount = [...valueCounts.entries()].filter(([key]) => !topKeys.has(key)).reduce((sum, [, count]) => sum + count, 0);
|
|
3797
|
-
|
|
3800
|
+
stat4.top_values = Object.fromEntries(
|
|
3798
3801
|
top.map(([key, count]) => [key, countPercentText(count, denominator)])
|
|
3799
3802
|
);
|
|
3800
3803
|
if (otherCount > 0) {
|
|
3801
|
-
|
|
3804
|
+
stat4.top_values["(other)"] = countPercentText(otherCount, denominator);
|
|
3802
3805
|
}
|
|
3803
3806
|
if (empty > 0) {
|
|
3804
|
-
|
|
3807
|
+
stat4.top_values["(null)"] = countPercentText(empty, denominator);
|
|
3805
3808
|
}
|
|
3806
3809
|
} else if (empty > 0 && nonEmpty > 0) {
|
|
3807
|
-
|
|
3810
|
+
stat4.top_values = { "(null)": countPercentText(empty, denominator) };
|
|
3808
3811
|
}
|
|
3809
|
-
columnStats[column] =
|
|
3812
|
+
columnStats[column] = stat4;
|
|
3810
3813
|
}
|
|
3811
3814
|
return {
|
|
3812
3815
|
total_rows: totalRows,
|
|
@@ -4187,13 +4190,18 @@ function registerDbCommands(program) {
|
|
|
4187
4190
|
"after",
|
|
4188
4191
|
`
|
|
4189
4192
|
Notes:
|
|
4190
|
-
|
|
4193
|
+
Agent-safe SQL for the active workspace customer database.
|
|
4194
|
+
Reads: SELECT, EXPLAIN, and read-only WITH can inspect permitted schemas.
|
|
4195
|
+
Writes: CREATE TABLE, INSERT, UPDATE, DELETE, ALTER, DROP, TRUNCATE, and
|
|
4196
|
+
CREATE INDEX must target schema-qualified storage tables, such as storage.agent_notes.
|
|
4197
|
+
If CREATE TABLE blocked (...) fails, use CREATE TABLE storage.blocked (...).
|
|
4191
4198
|
Results are bounded by the server and --max-rows. Use --json for stable output.
|
|
4192
4199
|
Use --format csv or --format markdown for agent-readable exports and display tables.
|
|
4193
4200
|
|
|
4194
4201
|
Examples:
|
|
4195
4202
|
deepline db query --sql "select * from companies limit 20"
|
|
4196
4203
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
4204
|
+
deepline db query --sql "create table if not exists storage.agent_notes (id text primary key, note text not null)"
|
|
4197
4205
|
deepline db query --sql "select * from contacts" --max-rows 100 --json
|
|
4198
4206
|
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
4199
4207
|
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
@@ -4205,12 +4213,16 @@ Examples:
|
|
|
4205
4213
|
Notes:
|
|
4206
4214
|
Requires --sql. Output is a compact table in a terminal and raw JSON with
|
|
4207
4215
|
--json or when stdout is piped. The active auth workspace determines scope.
|
|
4216
|
+
Read permitted schemas with SELECT, EXPLAIN, or read-only WITH.
|
|
4217
|
+
Write only to schema-qualified storage tables. For example, use
|
|
4218
|
+
CREATE TABLE storage.blocked (...) instead of CREATE TABLE blocked (...).
|
|
4208
4219
|
--format csv and --format markdown are explicit data/display formats and can
|
|
4209
4220
|
be written directly with --out.
|
|
4210
4221
|
|
|
4211
4222
|
Examples:
|
|
4212
4223
|
deepline db query --sql "select * from companies limit 20"
|
|
4213
4224
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
4225
|
+
deepline db query --sql "create table if not exists storage.agent_notes (id text primary key, note text not null)"
|
|
4214
4226
|
deepline db psql --sql "select count(*) from contacts" --json
|
|
4215
4227
|
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
4216
4228
|
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
@@ -4230,210 +4242,10 @@ Examples:
|
|
|
4230
4242
|
});
|
|
4231
4243
|
}
|
|
4232
4244
|
|
|
4233
|
-
// src/cli/commands/
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
text,
|
|
4238
|
-
environment: collectLocalEnvInfo(),
|
|
4239
|
-
...options.command ? { command: options.command } : {},
|
|
4240
|
-
...options.payload ? { payload: options.payload } : {}
|
|
4241
|
-
});
|
|
4242
|
-
printCommandEnvelope(
|
|
4243
|
-
{
|
|
4244
|
-
...response,
|
|
4245
|
-
render: {
|
|
4246
|
-
sections: [
|
|
4247
|
-
{ title: "feedback", lines: ["Feedback submitted. Thank you."] }
|
|
4248
|
-
]
|
|
4249
|
-
}
|
|
4250
|
-
},
|
|
4251
|
-
{ json: options.json }
|
|
4252
|
-
);
|
|
4253
|
-
}
|
|
4254
|
-
function registerFeedbackCommands(program) {
|
|
4255
|
-
const feedback = program.command("feedback").description("Submit CLI feedback to Deepline.").addHelpText(
|
|
4256
|
-
"after",
|
|
4257
|
-
`
|
|
4258
|
-
Notes:
|
|
4259
|
-
Sends the feedback text plus local CLI environment info to Deepline support.
|
|
4260
|
-
Use --command and --payload to attach a reproducible command shape.
|
|
4261
|
-
|
|
4262
|
-
Examples:
|
|
4263
|
-
deepline feedback "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
|
|
4264
|
-
deepline feedback "unexpected billing output" --payload '{"command":"billing usage"}' --json
|
|
4265
|
-
`
|
|
4266
|
-
);
|
|
4267
|
-
feedback.argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
|
|
4268
|
-
program.command("provide-feedback").description("Legacy alias for `deepline feedback`.").addHelpText(
|
|
4269
|
-
"after",
|
|
4270
|
-
`
|
|
4271
|
-
Notes:
|
|
4272
|
-
Compatibility alias. Prefer deepline feedback in new scripts and docs.
|
|
4273
|
-
|
|
4274
|
-
Examples:
|
|
4275
|
-
deepline feedback "tools search returned stale results" --json
|
|
4276
|
-
`
|
|
4277
|
-
).argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
|
|
4278
|
-
}
|
|
4279
|
-
|
|
4280
|
-
// src/cli/commands/org.ts
|
|
4281
|
-
async function fetchOrganizations(http, apiKey) {
|
|
4282
|
-
return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
|
|
4283
|
-
}
|
|
4284
|
-
function orgListLines(orgs) {
|
|
4285
|
-
return orgs.map((org, index) => {
|
|
4286
|
-
const current = org.is_current ? " (current)" : "";
|
|
4287
|
-
const role = org.role ? ` [${org.role}]` : "";
|
|
4288
|
-
return `${index + 1}. ${org.name}${role}${current}`;
|
|
4289
|
-
});
|
|
4290
|
-
}
|
|
4291
|
-
async function handleOrgList(options) {
|
|
4292
|
-
const config = resolveConfig();
|
|
4293
|
-
const http = new HttpClient(config);
|
|
4294
|
-
const payload = await fetchOrganizations(http, config.apiKey);
|
|
4295
|
-
printCommandEnvelope(
|
|
4296
|
-
{
|
|
4297
|
-
...payload,
|
|
4298
|
-
render: {
|
|
4299
|
-
sections: [
|
|
4300
|
-
{
|
|
4301
|
-
title: "Your organizations:",
|
|
4302
|
-
lines: orgListLines(payload.organizations)
|
|
4303
|
-
}
|
|
4304
|
-
]
|
|
4305
|
-
}
|
|
4306
|
-
},
|
|
4307
|
-
{ json: options.json }
|
|
4308
|
-
);
|
|
4309
|
-
}
|
|
4310
|
-
async function handleOrgSwitch(selection, options) {
|
|
4311
|
-
const config = resolveConfig();
|
|
4312
|
-
const http = new HttpClient(config);
|
|
4313
|
-
const payload = await fetchOrganizations(http, config.apiKey);
|
|
4314
|
-
if (!selection && !options.orgId) {
|
|
4315
|
-
printCommandEnvelope(
|
|
4316
|
-
{
|
|
4317
|
-
...payload,
|
|
4318
|
-
next: { switch: "deepline org switch <number>" },
|
|
4319
|
-
render: {
|
|
4320
|
-
sections: [
|
|
4321
|
-
{
|
|
4322
|
-
title: "Your organizations:",
|
|
4323
|
-
lines: orgListLines(payload.organizations)
|
|
4324
|
-
}
|
|
4325
|
-
],
|
|
4326
|
-
actions: [{ label: "Run", command: "deepline org switch <number>" }]
|
|
4327
|
-
}
|
|
4328
|
-
},
|
|
4329
|
-
{ json: options.json }
|
|
4330
|
-
);
|
|
4331
|
-
return;
|
|
4332
|
-
}
|
|
4333
|
-
let target = payload.organizations.find(
|
|
4334
|
-
(org) => org.org_id === options.orgId
|
|
4335
|
-
);
|
|
4336
|
-
if (!target && selection) {
|
|
4337
|
-
const index = Number.parseInt(selection, 10);
|
|
4338
|
-
if (Number.isFinite(index) && index >= 1 && index <= payload.organizations.length) {
|
|
4339
|
-
target = payload.organizations[index - 1];
|
|
4340
|
-
} else {
|
|
4341
|
-
target = payload.organizations.find(
|
|
4342
|
-
(org) => org.name === selection || org.org_id === selection
|
|
4343
|
-
);
|
|
4344
|
-
}
|
|
4345
|
-
}
|
|
4346
|
-
if (!target) {
|
|
4347
|
-
throw new Error("Could not resolve the selected organization.");
|
|
4348
|
-
}
|
|
4349
|
-
if (target.is_current) {
|
|
4350
|
-
printCommandEnvelope(
|
|
4351
|
-
{
|
|
4352
|
-
ok: true,
|
|
4353
|
-
unchanged: true,
|
|
4354
|
-
organization: target,
|
|
4355
|
-
render: {
|
|
4356
|
-
sections: [
|
|
4357
|
-
{ title: "org switch", lines: [`Already on ${target.name}.`] }
|
|
4358
|
-
]
|
|
4359
|
-
}
|
|
4360
|
-
},
|
|
4361
|
-
{ json: options.json }
|
|
4362
|
-
);
|
|
4363
|
-
return;
|
|
4364
|
-
}
|
|
4365
|
-
const switched = await http.post("/api/v2/auth/cli/switch", {
|
|
4366
|
-
api_key: config.apiKey,
|
|
4367
|
-
org_id: target.org_id
|
|
4368
|
-
});
|
|
4369
|
-
saveHostEnvValues(config.baseUrl, {
|
|
4370
|
-
DEEPLINE_API_KEY: switched.api_key,
|
|
4371
|
-
DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
|
|
4372
|
-
DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
|
|
4373
|
-
});
|
|
4374
|
-
const { api_key: _apiKey, ...publicSwitched } = switched;
|
|
4375
|
-
printCommandEnvelope(
|
|
4376
|
-
{
|
|
4377
|
-
ok: true,
|
|
4378
|
-
host_env_path: hostEnvFilePath(config.baseUrl),
|
|
4379
|
-
...publicSwitched,
|
|
4380
|
-
api_key_saved: true,
|
|
4381
|
-
render: {
|
|
4382
|
-
sections: [
|
|
4383
|
-
{
|
|
4384
|
-
title: "org switch",
|
|
4385
|
-
lines: [
|
|
4386
|
-
`Switched to ${switched.org_name}.`,
|
|
4387
|
-
`Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
|
|
4388
|
-
]
|
|
4389
|
-
}
|
|
4390
|
-
]
|
|
4391
|
-
}
|
|
4392
|
-
},
|
|
4393
|
-
{ json: options.json }
|
|
4394
|
-
);
|
|
4395
|
-
}
|
|
4396
|
-
function registerOrgCommands(program) {
|
|
4397
|
-
const org = program.command("org").description("List and switch organizations.").addHelpText(
|
|
4398
|
-
"after",
|
|
4399
|
-
`
|
|
4400
|
-
Notes:
|
|
4401
|
-
Organizations are workspaces. Switching organizations mutates the saved host
|
|
4402
|
-
auth file so later CLI commands target the selected workspace.
|
|
4403
|
-
|
|
4404
|
-
Examples:
|
|
4405
|
-
deepline org list --json
|
|
4406
|
-
deepline org switch 2
|
|
4407
|
-
deepline org switch --org-id org_123 --json
|
|
4408
|
-
`
|
|
4409
|
-
);
|
|
4410
|
-
org.command("list").description("List your organizations.").addHelpText(
|
|
4411
|
-
"after",
|
|
4412
|
-
`
|
|
4413
|
-
Notes:
|
|
4414
|
-
Read-only. Marks the active organization when the server returns that metadata.
|
|
4415
|
-
|
|
4416
|
-
Examples:
|
|
4417
|
-
deepline org list
|
|
4418
|
-
deepline org list --json
|
|
4419
|
-
`
|
|
4420
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgList);
|
|
4421
|
-
org.command("switch [selection]").description(
|
|
4422
|
-
"Switch to another organization and save the new API key in the host auth file."
|
|
4423
|
-
).addHelpText(
|
|
4424
|
-
"after",
|
|
4425
|
-
`
|
|
4426
|
-
Notes:
|
|
4427
|
-
Mutates the saved host auth file. Selection can be a list number, exact
|
|
4428
|
-
organization name, or organization id. Without a selection, prints choices.
|
|
4429
|
-
|
|
4430
|
-
Examples:
|
|
4431
|
-
deepline org switch
|
|
4432
|
-
deepline org switch 2
|
|
4433
|
-
deepline org switch --org-id org_123 --json
|
|
4434
|
-
`
|
|
4435
|
-
).option("--org-id <id>", "Switch using an explicit organization id").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgSwitch);
|
|
4436
|
-
}
|
|
4245
|
+
// src/cli/commands/enrich.ts
|
|
4246
|
+
var import_promises5 = require("fs/promises");
|
|
4247
|
+
var import_node_os7 = require("os");
|
|
4248
|
+
var import_node_path13 = require("path");
|
|
4437
4249
|
|
|
4438
4250
|
// src/cli/commands/play.ts
|
|
4439
4251
|
var import_node_crypto3 = require("crypto");
|
|
@@ -6718,54 +6530,54 @@ function exampleValueComment(field) {
|
|
|
6718
6530
|
if (field === "roles" || field.endsWith("s")) return '["..."]';
|
|
6719
6531
|
return '"..."';
|
|
6720
6532
|
}
|
|
6721
|
-
function generateContactInputObjectFromSchema(schema,
|
|
6533
|
+
function generateContactInputObjectFromSchema(schema, indent2, label, fallbackFields = ["first_name", "last_name", "domain"]) {
|
|
6722
6534
|
const details = schemaFieldDetails(schema);
|
|
6723
6535
|
const required = details.required.length ? details.required : fallbackFields;
|
|
6724
6536
|
const optional = details.optional;
|
|
6725
6537
|
const lines = [
|
|
6726
|
-
`${
|
|
6727
|
-
...playInspectionComments(label,
|
|
6728
|
-
`${
|
|
6538
|
+
`${indent2}// TODO: map row fields into ${label}.`,
|
|
6539
|
+
...playInspectionComments(label, indent2),
|
|
6540
|
+
`${indent2}// Required: ${required.join(", ") || "none declared"}.`
|
|
6729
6541
|
];
|
|
6730
6542
|
for (const field of required) {
|
|
6731
|
-
lines.push(`${
|
|
6543
|
+
lines.push(`${indent2}// ${field}: row["TODO_SOURCE_FIELD"],`);
|
|
6732
6544
|
}
|
|
6733
6545
|
if (optional.length > 0) {
|
|
6734
6546
|
lines.push("");
|
|
6735
|
-
lines.push(`${
|
|
6547
|
+
lines.push(`${indent2}// optional (delete unused):`);
|
|
6736
6548
|
for (const field of optional) {
|
|
6737
|
-
lines.push(`${
|
|
6549
|
+
lines.push(`${indent2}// ${field}: row["TODO_SOURCE_FIELD"],`);
|
|
6738
6550
|
}
|
|
6739
6551
|
}
|
|
6740
6552
|
return `{
|
|
6741
6553
|
${lines.join("\n")}
|
|
6742
|
-
${
|
|
6554
|
+
${indent2.slice(2)}}`;
|
|
6743
6555
|
}
|
|
6744
|
-
function generateCompanyInputObjectFromSchema(schema,
|
|
6556
|
+
function generateCompanyInputObjectFromSchema(schema, indent2, label, fallbackFields = ["domain", "company_name"]) {
|
|
6745
6557
|
const details = schemaFieldDetails(schema);
|
|
6746
6558
|
const required = details.required.length ? details.required : fallbackFields;
|
|
6747
6559
|
const optional = details.optional;
|
|
6748
6560
|
const lines = [
|
|
6749
|
-
`${
|
|
6750
|
-
...playInspectionComments(label,
|
|
6751
|
-
`${
|
|
6561
|
+
`${indent2}// TODO: map company fields into ${label}.`,
|
|
6562
|
+
...playInspectionComments(label, indent2),
|
|
6563
|
+
`${indent2}// Required: ${required.join(", ") || "none declared"}.`
|
|
6752
6564
|
];
|
|
6753
6565
|
for (const field of required) {
|
|
6754
|
-
lines.push(`${
|
|
6566
|
+
lines.push(`${indent2}// ${field}: company["TODO_SOURCE_FIELD"],`);
|
|
6755
6567
|
}
|
|
6756
6568
|
if (optional.length > 0) {
|
|
6757
6569
|
lines.push("");
|
|
6758
|
-
lines.push(`${
|
|
6570
|
+
lines.push(`${indent2}// optional (delete unused):`);
|
|
6759
6571
|
for (const field of optional) {
|
|
6760
|
-
lines.push(`${
|
|
6572
|
+
lines.push(`${indent2}// ${field}: company["TODO_SOURCE_FIELD"],`);
|
|
6761
6573
|
}
|
|
6762
6574
|
}
|
|
6763
6575
|
return `{
|
|
6764
6576
|
${lines.join("\n")}
|
|
6765
|
-
${
|
|
6577
|
+
${indent2.slice(2)}}`;
|
|
6766
6578
|
}
|
|
6767
6579
|
function generateSourceProviderInputObject(input2) {
|
|
6768
|
-
const { tool, indent, label, entity } = input2;
|
|
6580
|
+
const { tool, indent: indent2, label, entity } = input2;
|
|
6769
6581
|
const properties = inputPropertyNames(tool?.inputSchema);
|
|
6770
6582
|
const details = schemaFieldDetails(tool?.inputSchema);
|
|
6771
6583
|
const required = details.required;
|
|
@@ -6786,18 +6598,18 @@ function generateSourceProviderInputObject(input2) {
|
|
|
6786
6598
|
].includes(field)
|
|
6787
6599
|
);
|
|
6788
6600
|
const lines = [
|
|
6789
|
-
`${
|
|
6790
|
-
`${
|
|
6601
|
+
`${indent2}// TODO: fill ${entity} source inputs for ${label}.`,
|
|
6602
|
+
`${indent2}// Inspect: deepline tools describe ${label} --json`
|
|
6791
6603
|
];
|
|
6792
6604
|
for (const field of required) {
|
|
6793
|
-
lines.push(`${
|
|
6605
|
+
lines.push(`${indent2}// ${field}: ${exampleValueComment(field)},`);
|
|
6794
6606
|
}
|
|
6795
6607
|
const activeTodoField = required.length === 0 ? ["query", "q", "search", "title", "role", "persona"].find(
|
|
6796
6608
|
(field) => includeOptional.includes(field)
|
|
6797
6609
|
) ?? "query" : null;
|
|
6798
6610
|
if (activeTodoField) {
|
|
6799
6611
|
lines.push(
|
|
6800
|
-
`${
|
|
6612
|
+
`${indent2}// ${activeTodoField}: ${exampleValueComment(activeTodoField)},`
|
|
6801
6613
|
);
|
|
6802
6614
|
}
|
|
6803
6615
|
const optionalExamples = includeOptional.filter(
|
|
@@ -6805,40 +6617,40 @@ function generateSourceProviderInputObject(input2) {
|
|
|
6805
6617
|
);
|
|
6806
6618
|
if (optionalExamples.length > 0) {
|
|
6807
6619
|
lines.push("");
|
|
6808
|
-
lines.push(`${
|
|
6620
|
+
lines.push(`${indent2}// optional - uncomment what this provider supports:`);
|
|
6809
6621
|
for (const field of optionalExamples) {
|
|
6810
6622
|
if (field === "limit" || field === "numResults" || field === "num_results" || field === "page_size") {
|
|
6811
|
-
lines.push(`${
|
|
6623
|
+
lines.push(`${indent2}// ${field}: limit,`);
|
|
6812
6624
|
} else {
|
|
6813
|
-
lines.push(`${
|
|
6625
|
+
lines.push(`${indent2}// ${field}: ${exampleValueComment(field)},`);
|
|
6814
6626
|
}
|
|
6815
6627
|
}
|
|
6816
6628
|
}
|
|
6817
6629
|
if (!required.some(
|
|
6818
6630
|
(field) => ["limit", "numResults", "num_results", "page_size"].includes(field)
|
|
6819
6631
|
)) {
|
|
6820
|
-
lines.push(`${
|
|
6632
|
+
lines.push(`${indent2}limit,`);
|
|
6821
6633
|
}
|
|
6822
6634
|
return `{
|
|
6823
6635
|
${lines.join("\n")}
|
|
6824
|
-
${
|
|
6636
|
+
${indent2.slice(2)}}`;
|
|
6825
6637
|
}
|
|
6826
6638
|
function generatePlayInputObject(input2) {
|
|
6827
|
-
const { schema, indent, label, entity } = input2;
|
|
6639
|
+
const { schema, indent: indent2, label, entity } = input2;
|
|
6828
6640
|
const details = schemaFieldDetails(schema);
|
|
6829
6641
|
const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
|
|
6830
6642
|
const required = details.required.length ? details.required : fallback;
|
|
6831
6643
|
const lines = [
|
|
6832
|
-
`${
|
|
6833
|
-
...playInspectionComments(label,
|
|
6644
|
+
`${indent2}// TODO: fill source play inputs for ${label}.`,
|
|
6645
|
+
...playInspectionComments(label, indent2)
|
|
6834
6646
|
];
|
|
6835
6647
|
for (const field of required) {
|
|
6836
|
-
lines.push(`${
|
|
6648
|
+
lines.push(`${indent2}// ${field}: ${exampleValueComment(field)},`);
|
|
6837
6649
|
}
|
|
6838
|
-
if (!required.includes("limit")) lines.push(`${
|
|
6650
|
+
if (!required.includes("limit")) lines.push(`${indent2}limit,`);
|
|
6839
6651
|
return `{
|
|
6840
6652
|
${lines.join("\n")}
|
|
6841
|
-
${
|
|
6653
|
+
${indent2.slice(2)}}`;
|
|
6842
6654
|
}
|
|
6843
6655
|
function requiredPlayInputFields(play) {
|
|
6844
6656
|
const schema = play?.inputSchema;
|
|
@@ -6879,8 +6691,8 @@ function finderProviderStepPrefix(finder) {
|
|
|
6879
6691
|
function safeIdentifier(value) {
|
|
6880
6692
|
return value.replace(/[^A-Za-z0-9_]+/g, "_");
|
|
6881
6693
|
}
|
|
6882
|
-
function playInspectionComments(playRef,
|
|
6883
|
-
return [`${
|
|
6694
|
+
function playInspectionComments(playRef, indent2) {
|
|
6695
|
+
return [`${indent2}// Inspect: deepline plays describe ${playRef} --json`];
|
|
6884
6696
|
}
|
|
6885
6697
|
function accessorExpression(base, field) {
|
|
6886
6698
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(field) ? `${base}.${field}` : `${base}[${jsString(field)}]`;
|
|
@@ -7979,7 +7791,7 @@ function traceCliSync(phase, fields, run) {
|
|
|
7979
7791
|
}
|
|
7980
7792
|
}
|
|
7981
7793
|
function sleep4(ms) {
|
|
7982
|
-
return new Promise((
|
|
7794
|
+
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
7983
7795
|
}
|
|
7984
7796
|
function parseReferencedPlayTarget2(target) {
|
|
7985
7797
|
const trimmed = target.trim();
|
|
@@ -9622,20 +9434,20 @@ function attachDatasetStatsToResult(result, datasetStats) {
|
|
|
9622
9434
|
};
|
|
9623
9435
|
return attach(result, "");
|
|
9624
9436
|
}
|
|
9625
|
-
function formatDatasetStatsLines(datasetStats,
|
|
9437
|
+
function formatDatasetStatsLines(datasetStats, indent2 = " ") {
|
|
9626
9438
|
if (!datasetStats) {
|
|
9627
9439
|
return [];
|
|
9628
9440
|
}
|
|
9629
|
-
const lines = [`${
|
|
9630
|
-
for (const [column,
|
|
9441
|
+
const lines = [`${indent2}summary:`];
|
|
9442
|
+
for (const [column, stat4] of Object.entries(datasetStats.columnStats).slice(
|
|
9631
9443
|
0,
|
|
9632
9444
|
12
|
|
9633
9445
|
)) {
|
|
9634
|
-
const topValues =
|
|
9635
|
-
const sample =
|
|
9636
|
-
const execution =
|
|
9446
|
+
const topValues = stat4.top_values ? `, top_values=${Object.entries(stat4.top_values).slice(0, 3).map(([value, count]) => `${value}=${count}`).join(", ")}` : "";
|
|
9447
|
+
const sample = stat4.sample_value !== void 0 ? `, sample_value=${JSON.stringify(stat4.sample_value)}` : "";
|
|
9448
|
+
const execution = stat4.execution ? `, execution=${Object.entries(stat4.execution).map(([bucket, count]) => `${bucket}=${count}`).join(", ")}` : "";
|
|
9637
9449
|
lines.push(
|
|
9638
|
-
`${
|
|
9450
|
+
`${indent2} ${column}: non_empty=${stat4.non_empty}, unique=${stat4.unique}${topValues}${sample}${execution}`
|
|
9639
9451
|
);
|
|
9640
9452
|
}
|
|
9641
9453
|
return lines;
|
|
@@ -9676,7 +9488,7 @@ function formatSummaryScalarParts(record, skipKeys = /* @__PURE__ */ new Set())
|
|
|
9676
9488
|
}
|
|
9677
9489
|
return parts;
|
|
9678
9490
|
}
|
|
9679
|
-
function formatPackageDatasetSummaryLines(summary,
|
|
9491
|
+
function formatPackageDatasetSummaryLines(summary, indent2 = " ") {
|
|
9680
9492
|
const record = readRecord(summary);
|
|
9681
9493
|
const columnStats = readRecord(record?.columnStats);
|
|
9682
9494
|
if (!record || !columnStats) {
|
|
@@ -9685,7 +9497,7 @@ function formatPackageDatasetSummaryLines(summary, indent = " ") {
|
|
|
9685
9497
|
const lines = [];
|
|
9686
9498
|
const parts = formatSummaryScalarParts(record, /* @__PURE__ */ new Set(["columnStats"]));
|
|
9687
9499
|
if (parts.length > 0) {
|
|
9688
|
-
lines.push(`${
|
|
9500
|
+
lines.push(`${indent2}summary: ${parts.join(" ")}`);
|
|
9689
9501
|
}
|
|
9690
9502
|
for (const [column, rawColumnSummary] of Object.entries(columnStats)) {
|
|
9691
9503
|
const columnSummary = readRecord(rawColumnSummary);
|
|
@@ -9697,7 +9509,7 @@ function formatPackageDatasetSummaryLines(summary, indent = " ") {
|
|
|
9697
9509
|
executionText ? `execution=${executionText}` : null
|
|
9698
9510
|
].filter(Boolean);
|
|
9699
9511
|
if (columnParts.length > 0) {
|
|
9700
|
-
lines.push(`${
|
|
9512
|
+
lines.push(`${indent2} ${column}: ${columnParts.join(" ")}`);
|
|
9701
9513
|
}
|
|
9702
9514
|
}
|
|
9703
9515
|
return lines;
|
|
@@ -11907,9 +11719,11 @@ Idempotent execution:
|
|
|
11907
11719
|
.run({ key: 'domain' });
|
|
11908
11720
|
|
|
11909
11721
|
Reuse needs the same play, tool id, dataset name, row key, and compatible logic.
|
|
11910
|
-
To
|
|
11722
|
+
To recompute a visible cell on a later cron/user run after a window, put
|
|
11723
|
+
staleAfterSeconds on the cell-producing column:
|
|
11911
11724
|
|
|
11912
|
-
.
|
|
11725
|
+
.withColumn('cto', resolver, { staleAfterSeconds: 86400 })
|
|
11726
|
+
.run({ key: 'domain' })
|
|
11913
11727
|
|
|
11914
11728
|
Examples:
|
|
11915
11729
|
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
@@ -12438,7 +12252,9 @@ async function handlePlayShareStatus(args) {
|
|
|
12438
12252
|
);
|
|
12439
12253
|
return 0;
|
|
12440
12254
|
}
|
|
12441
|
-
console.log(
|
|
12255
|
+
console.log(
|
|
12256
|
+
`${status.playName}: published v${status.share.publishedVersion}`
|
|
12257
|
+
);
|
|
12442
12258
|
console.log(` url: ${status.share.publicPath}`);
|
|
12443
12259
|
console.log(` seo: ${status.share.seoIndexing}`);
|
|
12444
12260
|
console.log(
|
|
@@ -12600,7 +12416,9 @@ async function handlePlayShareRegenerate(args) {
|
|
|
12600
12416
|
async function handlePlayShareUnpublish(args) {
|
|
12601
12417
|
const target = args[0];
|
|
12602
12418
|
if (!target) {
|
|
12603
|
-
console.error(
|
|
12419
|
+
console.error(
|
|
12420
|
+
"Usage: deepline plays share unpublish <play> --yes [--json]"
|
|
12421
|
+
);
|
|
12604
12422
|
return 2;
|
|
12605
12423
|
}
|
|
12606
12424
|
if (!args.includes("--yes")) {
|
|
@@ -12620,49 +12438,1190 @@ async function handlePlayShareUnpublish(args) {
|
|
|
12620
12438
|
return 0;
|
|
12621
12439
|
}
|
|
12622
12440
|
|
|
12623
|
-
// src/cli/
|
|
12624
|
-
var
|
|
12625
|
-
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12629
|
-
|
|
12630
|
-
|
|
12631
|
-
|
|
12441
|
+
// src/cli/enrich-play-compiler.ts
|
|
12442
|
+
var RESERVED_WORDS = /* @__PURE__ */ new Set([
|
|
12443
|
+
"break",
|
|
12444
|
+
"case",
|
|
12445
|
+
"catch",
|
|
12446
|
+
"class",
|
|
12447
|
+
"const",
|
|
12448
|
+
"continue",
|
|
12449
|
+
"debugger",
|
|
12450
|
+
"default",
|
|
12451
|
+
"delete",
|
|
12452
|
+
"do",
|
|
12453
|
+
"else",
|
|
12454
|
+
"export",
|
|
12455
|
+
"extends",
|
|
12456
|
+
"finally",
|
|
12457
|
+
"for",
|
|
12458
|
+
"function",
|
|
12459
|
+
"if",
|
|
12460
|
+
"import",
|
|
12461
|
+
"in",
|
|
12462
|
+
"instanceof",
|
|
12463
|
+
"new",
|
|
12464
|
+
"return",
|
|
12465
|
+
"super",
|
|
12466
|
+
"switch",
|
|
12467
|
+
"this",
|
|
12468
|
+
"throw",
|
|
12469
|
+
"try",
|
|
12470
|
+
"typeof",
|
|
12471
|
+
"var",
|
|
12472
|
+
"void",
|
|
12473
|
+
"while",
|
|
12474
|
+
"with",
|
|
12475
|
+
"yield"
|
|
12476
|
+
]);
|
|
12477
|
+
function isWaterfall(command) {
|
|
12478
|
+
return "with_waterfall" in command;
|
|
12479
|
+
}
|
|
12480
|
+
function safeIdentifier2(value, fallback) {
|
|
12481
|
+
const cleaned = value.replace(/[^A-Za-z0-9_$]/g, "_");
|
|
12482
|
+
const prefixed = /^[A-Za-z_$]/.test(cleaned) ? cleaned : `_${cleaned}`;
|
|
12483
|
+
if (!prefixed || RESERVED_WORDS.has(prefixed)) {
|
|
12484
|
+
return fallback;
|
|
12632
12485
|
}
|
|
12633
|
-
return
|
|
12486
|
+
return prefixed;
|
|
12634
12487
|
}
|
|
12635
|
-
function
|
|
12636
|
-
|
|
12637
|
-
return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}`;
|
|
12488
|
+
function stringLiteral(value) {
|
|
12489
|
+
return JSON.stringify(value);
|
|
12638
12490
|
}
|
|
12639
|
-
|
|
12640
|
-
if (
|
|
12641
|
-
|
|
12642
|
-
|
|
12491
|
+
function stableJson(value) {
|
|
12492
|
+
if (Array.isArray(value)) {
|
|
12493
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
12494
|
+
}
|
|
12495
|
+
if (value && typeof value === "object") {
|
|
12496
|
+
const entries = Object.entries(value).sort(
|
|
12497
|
+
([left], [right]) => left.localeCompare(right)
|
|
12643
12498
|
);
|
|
12499
|
+
return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`).join(",")}}`;
|
|
12644
12500
|
}
|
|
12645
|
-
|
|
12646
|
-
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12501
|
+
return JSON.stringify(value);
|
|
12502
|
+
}
|
|
12503
|
+
function indent(source, spaces) {
|
|
12504
|
+
const pad = " ".repeat(spaces);
|
|
12505
|
+
return source.split("\n").map((line) => line ? `${pad}${line}` : line).join("\n");
|
|
12506
|
+
}
|
|
12507
|
+
function commandCallId(command) {
|
|
12508
|
+
return `${command.alias}__${command.tool}`;
|
|
12509
|
+
}
|
|
12510
|
+
function normalizeAlias(value) {
|
|
12511
|
+
return value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
12512
|
+
}
|
|
12513
|
+
function renderExecuteStep(command, options = { force: false }) {
|
|
12514
|
+
const alias = stringLiteral(command.alias);
|
|
12515
|
+
const callId = stringLiteral(commandCallId(command));
|
|
12516
|
+
const tool = stringLiteral(command.tool);
|
|
12517
|
+
const payload = stableJson(command.payload ?? {});
|
|
12518
|
+
const extractJs = command.extract_js ? `({ row, result, data, raw, pick, extract, target }) => { const input = row; const context = row;
|
|
12519
|
+
${indent(renderJavascriptBody(command.extract_js), 6)}
|
|
12520
|
+
}` : "null";
|
|
12521
|
+
const runIfJs = command.run_if_js ? `(row) => { const input = row; const context = row;
|
|
12522
|
+
${indent(renderJavascriptBody(command.run_if_js), 6)}
|
|
12523
|
+
}` : "null";
|
|
12524
|
+
const description = command.description ? `,
|
|
12525
|
+
description: ${stringLiteral(command.description)}` : "";
|
|
12526
|
+
const force = options.force ? `,
|
|
12527
|
+
force: true` : "";
|
|
12528
|
+
return [
|
|
12529
|
+
`async (row, stepCtx) => {`,
|
|
12530
|
+
...options.precheck ? [` if (${options.precheck}) return null;`] : [],
|
|
12531
|
+
` return __dlRunCommand({`,
|
|
12532
|
+
` alias: ${alias},`,
|
|
12533
|
+
` callId: ${callId},`,
|
|
12534
|
+
` tool: ${tool},`,
|
|
12535
|
+
` payload: ${payload},`,
|
|
12536
|
+
` extract: ${extractJs},`,
|
|
12537
|
+
` runIf: ${runIfJs},`,
|
|
12538
|
+
` row,`,
|
|
12539
|
+
` stepCtx${description}${force}`,
|
|
12540
|
+
` });`,
|
|
12541
|
+
`}`
|
|
12542
|
+
].join("\n");
|
|
12543
|
+
}
|
|
12544
|
+
function renderJavascriptBody(source) {
|
|
12545
|
+
const trimmed = source.trim();
|
|
12546
|
+
if (trimmed && !trimmed.includes("\n") && !trimmed.includes(";") && !/\breturn\b/.test(trimmed)) {
|
|
12547
|
+
return `return (${trimmed});`;
|
|
12548
|
+
}
|
|
12549
|
+
return source;
|
|
12550
|
+
}
|
|
12551
|
+
function renderWaterfallProgram(command, index, forceAliases) {
|
|
12552
|
+
const variableName = safeIdentifier2(
|
|
12553
|
+
`${command.with_waterfall}_${index}_waterfall`,
|
|
12554
|
+
`waterfall_${index}`
|
|
12555
|
+
);
|
|
12556
|
+
const stepLines = command.commands.map((nested, stepIndex) => {
|
|
12557
|
+
if (isWaterfall(nested)) {
|
|
12558
|
+
throw new Error("Nested with_waterfall blocks are not supported.");
|
|
12559
|
+
}
|
|
12560
|
+
if (nested.disabled) {
|
|
12561
|
+
return null;
|
|
12562
|
+
}
|
|
12563
|
+
const priorAliases = command.commands.slice(0, stepIndex).filter((prior) => !isWaterfall(prior)).filter((prior) => !prior.disabled).map((prior) => prior.alias);
|
|
12564
|
+
const minResults = typeof command.min_results === "number" ? Math.max(1, Math.trunc(command.min_results)) : 1;
|
|
12565
|
+
return [
|
|
12566
|
+
` .step(${stringLiteral(nested.alias)},`,
|
|
12567
|
+
indent(
|
|
12568
|
+
renderExecuteStep(nested, {
|
|
12569
|
+
force: forceAliases.has(normalizeAlias(nested.alias)),
|
|
12570
|
+
precheck: priorAliases.length > 0 ? `__dlWaterfallSatisfied(row, ${stableJson(priorAliases)}, ${minResults})` : void 0
|
|
12571
|
+
}),
|
|
12572
|
+
4
|
|
12573
|
+
),
|
|
12574
|
+
` )`
|
|
12575
|
+
].join("\n");
|
|
12576
|
+
}).filter((line) => line !== null);
|
|
12577
|
+
const aliases = command.commands.filter((nested) => !isWaterfall(nested)).filter((nested) => !nested.disabled).map((nested) => nested.alias);
|
|
12578
|
+
const returnExpr = typeof command.min_results === "number" ? `__dlFirstMinResults(row, ${stableJson(aliases)}, ${Math.max(
|
|
12579
|
+
1,
|
|
12580
|
+
Math.trunc(command.min_results)
|
|
12581
|
+
)})` : `__dlFirstMeaningful(row, ${stableJson(aliases)})`;
|
|
12582
|
+
return {
|
|
12583
|
+
variableName,
|
|
12584
|
+
hasSteps: stepLines.length > 0,
|
|
12585
|
+
source: [
|
|
12586
|
+
`const ${variableName} = steps<Record<string, unknown>>()`,
|
|
12587
|
+
...stepLines,
|
|
12588
|
+
` .return((row) => ${returnExpr});`
|
|
12589
|
+
].join("\n")
|
|
12590
|
+
};
|
|
12591
|
+
}
|
|
12592
|
+
function compileEnrichConfigToPlaySource(config, options = {}) {
|
|
12593
|
+
const playName = options.playName ?? "deepline-enrich-v1-compat";
|
|
12594
|
+
const mapName = options.mapName ?? "deepline_enrich_rows";
|
|
12595
|
+
const forceAliases = new Set(
|
|
12596
|
+
[...options.forceAliases ?? []].map((alias) => normalizeAlias(alias))
|
|
12597
|
+
);
|
|
12598
|
+
const waterfalls = [];
|
|
12599
|
+
const mapSteps = [];
|
|
12600
|
+
config.commands.forEach((command, index) => {
|
|
12601
|
+
if (isWaterfall(command)) {
|
|
12602
|
+
const rendered = renderWaterfallProgram(command, index, forceAliases);
|
|
12603
|
+
if (!rendered.hasSteps) {
|
|
12604
|
+
return;
|
|
12605
|
+
}
|
|
12606
|
+
waterfalls.push({
|
|
12607
|
+
alias: command.with_waterfall,
|
|
12608
|
+
variableName: rendered.variableName,
|
|
12609
|
+
source: rendered.source
|
|
12610
|
+
});
|
|
12611
|
+
mapSteps.push(
|
|
12612
|
+
` .step(${stringLiteral(command.with_waterfall)}, ${rendered.variableName})`
|
|
12613
|
+
);
|
|
12614
|
+
return;
|
|
12615
|
+
}
|
|
12616
|
+
if (command.disabled) {
|
|
12617
|
+
return;
|
|
12618
|
+
}
|
|
12619
|
+
mapSteps.push(
|
|
12620
|
+
[
|
|
12621
|
+
` .step(${stringLiteral(command.alias)},`,
|
|
12622
|
+
indent(
|
|
12623
|
+
renderExecuteStep(command, {
|
|
12624
|
+
force: forceAliases.has(normalizeAlias(command.alias))
|
|
12625
|
+
}),
|
|
12626
|
+
8
|
|
12627
|
+
),
|
|
12628
|
+
` )`
|
|
12629
|
+
].join("\n")
|
|
12630
|
+
);
|
|
12631
|
+
});
|
|
12632
|
+
const waterfallSource = waterfalls.map((entry) => indent(entry.source, 4));
|
|
12633
|
+
const mapStepSource = mapSteps.length > 0 ? mapSteps.join("\n") : ` .step('noop', (row) => row)`;
|
|
12634
|
+
return [
|
|
12635
|
+
`import { definePlay, steps } from 'deepline';`,
|
|
12636
|
+
``,
|
|
12637
|
+
`type EnrichInput = { file: string; rowStart?: number | null; rowEnd?: number | null };`,
|
|
12638
|
+
``,
|
|
12639
|
+
helperSource(),
|
|
12640
|
+
``,
|
|
12641
|
+
`export default definePlay(${stringLiteral(playName)}, async (ctx, input: EnrichInput) => {`,
|
|
12642
|
+
` const allRows = await ctx.csv<Record<string, unknown>>(input.file);`,
|
|
12643
|
+
` const rowStart = Number.isFinite(input.rowStart) ? Math.max(0, Math.trunc(Number(input.rowStart))) : 0;`,
|
|
12644
|
+
` const rowEnd = Number.isFinite(input.rowEnd) ? Math.max(rowStart, Math.trunc(Number(input.rowEnd))) : allRows.length;`,
|
|
12645
|
+
` const rows = allRows.slice(rowStart, rowEnd);`,
|
|
12646
|
+
...waterfallSource,
|
|
12647
|
+
` const enriched = await ctx`,
|
|
12648
|
+
` .map(${stringLiteral(mapName)}, rows)`,
|
|
12649
|
+
mapStepSource,
|
|
12650
|
+
` .run({ key: (row, index) => __dlStableRowKey(row, index + rowStart) });`,
|
|
12651
|
+
` return { rows: enriched, count: await enriched.count() };`,
|
|
12652
|
+
`});`,
|
|
12653
|
+
``
|
|
12654
|
+
].join("\n");
|
|
12655
|
+
}
|
|
12656
|
+
function helperSource() {
|
|
12657
|
+
return [
|
|
12658
|
+
`function __dlGetByPath(root: unknown, path: string): unknown {`,
|
|
12659
|
+
` return String(path || '')`,
|
|
12660
|
+
` .replace(/\\[(\\d+)\\]/g, '.$1')`,
|
|
12661
|
+
` .split('.')`,
|
|
12662
|
+
` .map((part) => part.trim())`,
|
|
12663
|
+
` .filter(Boolean)`,
|
|
12664
|
+
` .reduce((cursor: unknown, part: string) => {`,
|
|
12665
|
+
` if (!cursor || typeof cursor !== 'object') return undefined;`,
|
|
12666
|
+
` const record = cursor as Record<string, unknown>;`,
|
|
12667
|
+
` if (part in record) return record[part];`,
|
|
12668
|
+
` const data = record.data;`,
|
|
12669
|
+
` return data && typeof data === 'object' ? (data as Record<string, unknown>)[part] : undefined;`,
|
|
12670
|
+
` }, root);`,
|
|
12671
|
+
`}`,
|
|
12672
|
+
``,
|
|
12673
|
+
`function __dlMeaningful(value: unknown): boolean {`,
|
|
12674
|
+
` return value !== null && value !== undefined && !(typeof value === 'string' && value.trim() === '') && !(Array.isArray(value) && value.length === 0);`,
|
|
12675
|
+
`}`,
|
|
12676
|
+
``,
|
|
12677
|
+
`function __dlRawToolOutput(result: unknown): unknown {`,
|
|
12678
|
+
` if (!result || typeof result !== 'object') return result;`,
|
|
12679
|
+
` const record = result as Record<string, unknown>;`,
|
|
12680
|
+
` return __dlGetByPath(record, 'toolOutput.raw') ?? __dlGetByPath(record, 'toolResponse.raw') ?? record.result ?? record.output ?? result;`,
|
|
12681
|
+
`}`,
|
|
12682
|
+
``,
|
|
12683
|
+
`function __dlTemplate(value: unknown, row: Record<string, unknown>): unknown {`,
|
|
12684
|
+
` if (Array.isArray(value)) return value.map((entry) => __dlTemplate(entry, row));`,
|
|
12685
|
+
` if (value && typeof value === 'object') {`,
|
|
12686
|
+
` return Object.fromEntries(Object.entries(value as Record<string, unknown>).map(([key, entry]) => [key, __dlTemplate(entry, row)]));`,
|
|
12687
|
+
` }`,
|
|
12688
|
+
` if (typeof value !== 'string') return value;`,
|
|
12689
|
+
` const exact = value.match(/^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$/);`,
|
|
12690
|
+
` if (exact) return __dlGetByPath(row, exact[1] || '');`,
|
|
12691
|
+
` return value.replace(/\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g, (_match, path) => {`,
|
|
12692
|
+
` const replacement = __dlGetByPath(row, String(path || ''));`,
|
|
12693
|
+
` return replacement === null || replacement === undefined ? '' : String(replacement);`,
|
|
12694
|
+
` });`,
|
|
12695
|
+
`}`,
|
|
12696
|
+
``,
|
|
12697
|
+
`function __dlStableRowKey(row: Record<string, unknown>, index: number): string {`,
|
|
12698
|
+
` for (const key of ['id', 'ID', 'email', 'Email', 'linkedin_url', 'LINKEDIN_URL', 'domain', 'DOMAIN']) {`,
|
|
12699
|
+
` const value = row[key];`,
|
|
12700
|
+
` if (__dlMeaningful(value)) return String(value);`,
|
|
12701
|
+
` }`,
|
|
12702
|
+
` return String(index);`,
|
|
12703
|
+
`}`,
|
|
12704
|
+
``,
|
|
12705
|
+
`function __dlFirstMeaningful(row: Record<string, unknown>, aliases: string[]): unknown {`,
|
|
12706
|
+
` for (const alias of aliases) {`,
|
|
12707
|
+
` const value = row[alias];`,
|
|
12708
|
+
` if (__dlMeaningful(value)) return value;`,
|
|
12709
|
+
` }`,
|
|
12710
|
+
` return null;`,
|
|
12711
|
+
`}`,
|
|
12712
|
+
``,
|
|
12713
|
+
`function __dlFirstMinResults(row: Record<string, unknown>, aliases: string[], minResults: number): unknown {`,
|
|
12714
|
+
` const values: unknown[] = [];`,
|
|
12715
|
+
` for (const alias of aliases) {`,
|
|
12716
|
+
` const value = row[alias];`,
|
|
12717
|
+
` if (Array.isArray(value)) values.push(...value.filter(__dlMeaningful));`,
|
|
12718
|
+
` else if (__dlMeaningful(value)) values.push(value);`,
|
|
12719
|
+
` if (values.length >= minResults) return values.slice(0, minResults);`,
|
|
12720
|
+
` }`,
|
|
12721
|
+
` return values.length > 0 ? values : null;`,
|
|
12722
|
+
`}`,
|
|
12723
|
+
``,
|
|
12724
|
+
`function __dlWaterfallSatisfied(row: Record<string, unknown>, aliases: string[], minResults: number): boolean {`,
|
|
12725
|
+
` let count = 0;`,
|
|
12726
|
+
` for (const alias of aliases) {`,
|
|
12727
|
+
` const value = row[alias];`,
|
|
12728
|
+
` if (Array.isArray(value)) count += value.filter(__dlMeaningful).length;`,
|
|
12729
|
+
` else if (__dlMeaningful(value)) count += 1;`,
|
|
12730
|
+
` if (count >= Math.max(1, Math.trunc(minResults))) return true;`,
|
|
12731
|
+
` }`,
|
|
12732
|
+
` return false;`,
|
|
12733
|
+
`}`,
|
|
12734
|
+
``,
|
|
12735
|
+
`function __dlExtract(alias: string, result: unknown, row: Record<string, unknown>, extractor: ((args: { row: Record<string, unknown>; result: unknown; data: unknown; raw: unknown; pick: (paths: string[] | string) => unknown; extract: (paths: string[] | string) => unknown; target: (paths: string[] | string) => unknown }) => unknown) | null): unknown {`,
|
|
12736
|
+
` const raw = __dlRawToolOutput(result);`,
|
|
12737
|
+
` if (!extractor) return raw;`,
|
|
12738
|
+
` const pick = (paths: string[] | string) => {`,
|
|
12739
|
+
` const candidates = Array.isArray(paths) ? paths : [paths];`,
|
|
12740
|
+
` for (const path of candidates) {`,
|
|
12741
|
+
` const value = __dlGetByPath(raw, String(path));`,
|
|
12742
|
+
` if (__dlMeaningful(value)) return value;`,
|
|
12743
|
+
` }`,
|
|
12744
|
+
` return null;`,
|
|
12745
|
+
` };`,
|
|
12746
|
+
` const extracted = extractor({ row, result, data: raw, raw, pick, extract: pick, target: pick });`,
|
|
12747
|
+
` if (extracted && typeof extracted === 'object' && !Array.isArray(extracted) && alias in (extracted as Record<string, unknown>)) {`,
|
|
12748
|
+
` return (extracted as Record<string, unknown>)[alias];`,
|
|
12749
|
+
` }`,
|
|
12750
|
+
` return extracted === undefined ? raw : extracted;`,
|
|
12751
|
+
`}`,
|
|
12752
|
+
``,
|
|
12753
|
+
`async function __dlRunCommand(input: { alias: string; callId: string; tool: string; payload: Record<string, unknown>; extract: ((args: { row: Record<string, unknown>; result: unknown; data: unknown; raw: unknown; pick: (paths: string[] | string) => unknown; extract: (paths: string[] | string) => unknown; target: (paths: string[] | string) => unknown }) => unknown) | null; runIf: ((row: Record<string, unknown>) => unknown) | null; row: Record<string, unknown>; stepCtx: { tools: { execute: (request: Record<string, unknown>) => Promise<unknown> } }; description?: string; force?: boolean }): Promise<unknown> {`,
|
|
12754
|
+
` if (input.runIf) {`,
|
|
12755
|
+
` const shouldRun = input.runIf(input.row);`,
|
|
12756
|
+
` if (!shouldRun) return null;`,
|
|
12757
|
+
` }`,
|
|
12758
|
+
` const result = await input.stepCtx.tools.execute({`,
|
|
12759
|
+
` id: input.callId,`,
|
|
12760
|
+
` tool: input.tool,`,
|
|
12761
|
+
` input: __dlTemplate(input.payload, input.row) as Record<string, unknown>,`,
|
|
12762
|
+
` ...(input.description ? { description: input.description } : {}),`,
|
|
12763
|
+
` ...(input.force ? { staleAfterSeconds: 0 } : {}),`,
|
|
12764
|
+
` });`,
|
|
12765
|
+
` return __dlExtract(input.alias, result, input.row, input.extract);`,
|
|
12766
|
+
`}`
|
|
12767
|
+
].join("\n");
|
|
12768
|
+
}
|
|
12769
|
+
|
|
12770
|
+
// src/cli/commands/enrich.ts
|
|
12771
|
+
var PLAN_SHAPING_OPTION_NAMES = [
|
|
12772
|
+
"with",
|
|
12773
|
+
"withWaterfall",
|
|
12774
|
+
"minResults",
|
|
12775
|
+
"endWaterfall"
|
|
12776
|
+
];
|
|
12777
|
+
var ENRICH_DEPRECATION_NOTICE = {
|
|
12778
|
+
status: "deprecated",
|
|
12779
|
+
message: "The enrich compatibility command is deprecated. This run generates a temporary .play.ts file and executes it through plays run.",
|
|
12780
|
+
generatedPlayFile: "Temporary compatibility play file; deleted after the command exits.",
|
|
12781
|
+
printGeneratedPlayCommand: "deepline enrich <same args> --dry-run > enrich.play.ts",
|
|
12782
|
+
recommendedCommand: `deepline plays run enrich.play.ts --input '{"file":"<input.csv>"}'`
|
|
12783
|
+
};
|
|
12784
|
+
var ENRICH_DEPRECATION_TEXT = `${ENRICH_DEPRECATION_NOTICE.message} Print the generated play with: ${ENRICH_DEPRECATION_NOTICE.printGeneratedPlayCommand}. Then run: ${ENRICH_DEPRECATION_NOTICE.recommendedCommand}
|
|
12785
|
+
`;
|
|
12786
|
+
function optionWasProvided(args, ...flags) {
|
|
12787
|
+
return args.some(
|
|
12788
|
+
(arg) => flags.some((flag) => arg === flag || arg.startsWith(`${flag}=`))
|
|
12789
|
+
);
|
|
12790
|
+
}
|
|
12791
|
+
function normalizeAlias2(value) {
|
|
12792
|
+
return value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
12793
|
+
}
|
|
12794
|
+
function hasPlanShapingArgs(args) {
|
|
12795
|
+
return optionWasProvided(args, "--with") || optionWasProvided(args, "--with-waterfall") || optionWasProvided(args, "--min-results") || optionWasProvided(args, "--end-waterfall");
|
|
12796
|
+
}
|
|
12797
|
+
function printDeprecationNotice(options) {
|
|
12798
|
+
if (!options.json) {
|
|
12799
|
+
process.stderr.write(ENRICH_DEPRECATION_TEXT);
|
|
12800
|
+
}
|
|
12801
|
+
}
|
|
12802
|
+
function expandAtFilePath(rawPath) {
|
|
12803
|
+
let expanded = rawPath.trim();
|
|
12804
|
+
expanded = expanded.replace(
|
|
12805
|
+
/\$([A-Za-z_][A-Za-z0-9_]*)|\$\{([^}]+)\}/g,
|
|
12806
|
+
(_match, bareName, bracedName) => process.env[bareName ?? bracedName ?? ""] ?? ""
|
|
12807
|
+
);
|
|
12808
|
+
if (expanded === "~") {
|
|
12809
|
+
return (0, import_node_os7.homedir)();
|
|
12810
|
+
}
|
|
12811
|
+
if (expanded.startsWith("~/") || expanded.startsWith("~\\")) {
|
|
12812
|
+
return (0, import_node_path13.join)((0, import_node_os7.homedir)(), expanded.slice(2));
|
|
12813
|
+
}
|
|
12814
|
+
return expanded;
|
|
12815
|
+
}
|
|
12816
|
+
async function readAtFileReference(value, argumentName, strip = true) {
|
|
12817
|
+
if (!value.startsWith("@")) {
|
|
12818
|
+
return strip ? value.trim() : value.replace(/^\uFEFF/, "");
|
|
12819
|
+
}
|
|
12820
|
+
const filePath = expandAtFilePath(value.slice(1));
|
|
12821
|
+
if (!filePath) {
|
|
12822
|
+
throw new Error(`Invalid ${argumentName} value: empty @file path.`);
|
|
12823
|
+
}
|
|
12824
|
+
try {
|
|
12825
|
+
const text = await (0, import_promises5.readFile)(filePath, "utf8");
|
|
12826
|
+
const normalized = text.replace(/^\uFEFF/, "");
|
|
12827
|
+
return strip ? normalized.trim() : normalized;
|
|
12828
|
+
} catch (error) {
|
|
12829
|
+
throw new Error(
|
|
12830
|
+
`Failed to read ${argumentName} file '${filePath}': ${error instanceof Error ? error.message : String(error)}`
|
|
12831
|
+
);
|
|
12832
|
+
}
|
|
12833
|
+
}
|
|
12834
|
+
function normalizeExtractJs(source) {
|
|
12835
|
+
return source.replace(/\\"/g, '"').replace(/\\'/g, "'");
|
|
12836
|
+
}
|
|
12837
|
+
async function normalizeWithSpec(rawSpec) {
|
|
12838
|
+
const raw = await readAtFileReference(rawSpec.trim(), "--with");
|
|
12839
|
+
let parsed;
|
|
12840
|
+
try {
|
|
12841
|
+
parsed = JSON.parse(raw);
|
|
12842
|
+
} catch (error) {
|
|
12843
|
+
throw new Error(
|
|
12844
|
+
`Invalid JSON payload in --with spec: ${raw} (${error instanceof Error ? error.message : String(error)})`
|
|
12845
|
+
);
|
|
12846
|
+
}
|
|
12847
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
12848
|
+
throw new Error("Invalid --with spec: expected JSON object.");
|
|
12849
|
+
}
|
|
12850
|
+
const spec = parsed;
|
|
12851
|
+
const normalized = { ...spec };
|
|
12852
|
+
for (const field of ["extract_js", "run_if_js"]) {
|
|
12853
|
+
const value = normalized[field];
|
|
12854
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
12855
|
+
continue;
|
|
12856
|
+
}
|
|
12857
|
+
const fromFile = value.trim().startsWith("@") ? await readAtFileReference(value.trim(), `--with ${field}`, false) : null;
|
|
12858
|
+
normalized[field] = fromFile !== null ? fromFile.trim() : normalizeExtractJs(value.trim());
|
|
12859
|
+
}
|
|
12860
|
+
const tool = String(
|
|
12861
|
+
normalized.tool ?? normalized.tool_ref ?? normalized.tool_id ?? ""
|
|
12862
|
+
).trim();
|
|
12863
|
+
const payload = normalized.payload;
|
|
12864
|
+
if (tool === "run_javascript" && payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
12865
|
+
const payloadRecord = payload;
|
|
12866
|
+
const code = payloadRecord.code;
|
|
12867
|
+
if (typeof code === "string" && code.trim().startsWith("@")) {
|
|
12868
|
+
normalized.payload = {
|
|
12869
|
+
...payloadRecord,
|
|
12870
|
+
code: await readAtFileReference(
|
|
12871
|
+
code.trim(),
|
|
12872
|
+
"run_javascript payload.code",
|
|
12873
|
+
false
|
|
12874
|
+
)
|
|
12875
|
+
};
|
|
12876
|
+
}
|
|
12877
|
+
}
|
|
12878
|
+
return JSON.stringify(normalized);
|
|
12879
|
+
}
|
|
12880
|
+
async function expandCompiledConfigAtFiles(value) {
|
|
12881
|
+
if (Array.isArray(value)) {
|
|
12882
|
+
return Promise.all(
|
|
12883
|
+
value.map((entry) => expandCompiledConfigAtFiles(entry))
|
|
12884
|
+
);
|
|
12885
|
+
}
|
|
12886
|
+
if (!value || typeof value !== "object") {
|
|
12887
|
+
return value;
|
|
12888
|
+
}
|
|
12889
|
+
const record = value;
|
|
12890
|
+
const expanded = {};
|
|
12891
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
12892
|
+
expanded[key] = await expandCompiledConfigAtFiles(entry);
|
|
12893
|
+
}
|
|
12894
|
+
for (const field of ["extract_js", "run_if_js"]) {
|
|
12895
|
+
const entry = expanded[field];
|
|
12896
|
+
if (typeof entry === "string" && entry.trim().startsWith("@")) {
|
|
12897
|
+
expanded[field] = (await readAtFileReference(entry.trim(), `--config ${field}`, false)).trim();
|
|
12898
|
+
}
|
|
12899
|
+
}
|
|
12900
|
+
const tool = String(
|
|
12901
|
+
expanded.tool ?? expanded.tool_ref ?? expanded.tool_id ?? ""
|
|
12902
|
+
).trim();
|
|
12903
|
+
const payload = expanded.payload;
|
|
12904
|
+
if (tool === "run_javascript" && payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
12905
|
+
const payloadRecord = payload;
|
|
12906
|
+
const code = payloadRecord.code;
|
|
12907
|
+
if (typeof code === "string" && code.trim().startsWith("@")) {
|
|
12908
|
+
expanded.payload = {
|
|
12909
|
+
...payloadRecord,
|
|
12910
|
+
code: await readAtFileReference(
|
|
12911
|
+
code.trim(),
|
|
12912
|
+
"--config run_javascript payload.code",
|
|
12913
|
+
false
|
|
12914
|
+
)
|
|
12915
|
+
};
|
|
12916
|
+
}
|
|
12917
|
+
}
|
|
12918
|
+
return expanded;
|
|
12919
|
+
}
|
|
12920
|
+
function currentEnrichArgs() {
|
|
12921
|
+
const index = process.argv.findIndex((arg) => arg === "enrich");
|
|
12922
|
+
return index >= 0 ? process.argv.slice(index + 1) : [];
|
|
12923
|
+
}
|
|
12924
|
+
async function buildPlanArgs(args) {
|
|
12925
|
+
const passthrough = /* @__PURE__ */ new Set([
|
|
12926
|
+
"--with",
|
|
12927
|
+
"--with-waterfall",
|
|
12928
|
+
"--min-results",
|
|
12929
|
+
"--end-waterfall"
|
|
12930
|
+
]);
|
|
12931
|
+
const localOptionsWithValue = /* @__PURE__ */ new Set([
|
|
12932
|
+
"--input",
|
|
12933
|
+
"--csv",
|
|
12934
|
+
"--output",
|
|
12935
|
+
"--config",
|
|
12936
|
+
"--rows",
|
|
12937
|
+
"--with-force"
|
|
12938
|
+
]);
|
|
12939
|
+
const localBooleanOptions = /* @__PURE__ */ new Set([
|
|
12940
|
+
"--dry-run",
|
|
12941
|
+
"--json",
|
|
12942
|
+
"--force",
|
|
12943
|
+
"--all",
|
|
12944
|
+
"--in-place"
|
|
12945
|
+
]);
|
|
12946
|
+
const planArgs = [];
|
|
12947
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
12948
|
+
const arg = args[index];
|
|
12949
|
+
const equalsIndex = arg.indexOf("=");
|
|
12950
|
+
const flag = equalsIndex >= 0 ? arg.slice(0, equalsIndex) : arg;
|
|
12951
|
+
const inlineValue = equalsIndex >= 0 ? arg.slice(equalsIndex + 1) : void 0;
|
|
12952
|
+
if (!passthrough.has(flag)) {
|
|
12953
|
+
if (localOptionsWithValue.has(flag)) {
|
|
12954
|
+
if (inlineValue === void 0) {
|
|
12955
|
+
const value = args[index + 1];
|
|
12956
|
+
if (!value || value.startsWith("--")) {
|
|
12957
|
+
throw new Error(`${flag} requires a value.`);
|
|
12958
|
+
}
|
|
12959
|
+
index += 1;
|
|
12960
|
+
}
|
|
12961
|
+
continue;
|
|
12962
|
+
}
|
|
12963
|
+
if (localBooleanOptions.has(flag)) {
|
|
12964
|
+
if (inlineValue !== void 0) {
|
|
12965
|
+
throw new Error(`${flag} does not accept a value.`);
|
|
12966
|
+
}
|
|
12967
|
+
continue;
|
|
12968
|
+
}
|
|
12969
|
+
if (flag.startsWith("--")) {
|
|
12970
|
+
throw new Error(`Unknown enrich option: ${flag}.`);
|
|
12971
|
+
}
|
|
12972
|
+
throw new Error(`Unexpected enrich argument: ${arg}.`);
|
|
12973
|
+
}
|
|
12974
|
+
planArgs.push(flag);
|
|
12975
|
+
if (inlineValue !== void 0) {
|
|
12976
|
+
planArgs.push(
|
|
12977
|
+
flag === "--with" ? await normalizeWithSpec(inlineValue) : inlineValue
|
|
12978
|
+
);
|
|
12979
|
+
continue;
|
|
12980
|
+
}
|
|
12981
|
+
if (flag !== "--end-waterfall") {
|
|
12982
|
+
const value = args[++index];
|
|
12983
|
+
if (!value) {
|
|
12984
|
+
throw new Error(`${flag} requires a value.`);
|
|
12985
|
+
}
|
|
12986
|
+
planArgs.push(flag === "--with" ? await normalizeWithSpec(value) : value);
|
|
12987
|
+
}
|
|
12988
|
+
}
|
|
12989
|
+
return planArgs;
|
|
12990
|
+
}
|
|
12991
|
+
async function assertInputCsvExists(inputCsv) {
|
|
12992
|
+
const path = (0, import_node_path13.resolve)(inputCsv);
|
|
12993
|
+
try {
|
|
12994
|
+
const info = await (0, import_promises5.stat)(path);
|
|
12995
|
+
if (info.isFile()) {
|
|
12996
|
+
return;
|
|
12997
|
+
}
|
|
12998
|
+
throw new Error("not a file");
|
|
12999
|
+
} catch (error) {
|
|
13000
|
+
throw new Error(
|
|
13001
|
+
`Input CSV does not exist or is not a file: ${path}${error instanceof Error && error.message !== "not a file" ? ` (${error.message})` : ""}`
|
|
13002
|
+
);
|
|
13003
|
+
}
|
|
13004
|
+
}
|
|
13005
|
+
async function assertSafeOutputPath(inputCsv, outputPath) {
|
|
13006
|
+
const input2 = (0, import_node_path13.resolve)(inputCsv);
|
|
13007
|
+
const output2 = (0, import_node_path13.resolve)(outputPath);
|
|
13008
|
+
if (input2 === output2) {
|
|
13009
|
+
throw new Error(
|
|
13010
|
+
"--output must be a different path from --input. --in-place is not supported by this V2 enrich runner yet."
|
|
13011
|
+
);
|
|
13012
|
+
}
|
|
13013
|
+
try {
|
|
13014
|
+
const [inputInfo, outputInfo] = await Promise.all([
|
|
13015
|
+
(0, import_promises5.stat)(input2),
|
|
13016
|
+
(0, import_promises5.stat)(output2)
|
|
13017
|
+
]);
|
|
13018
|
+
if (inputInfo.dev === outputInfo.dev && inputInfo.ino === outputInfo.ino) {
|
|
13019
|
+
throw new Error(
|
|
13020
|
+
"--output must be a different file from --input. --in-place is not supported by this V2 enrich runner yet."
|
|
13021
|
+
);
|
|
13022
|
+
}
|
|
13023
|
+
} catch (error) {
|
|
13024
|
+
if (error instanceof Error && error.message.startsWith("--output must")) {
|
|
13025
|
+
throw error;
|
|
13026
|
+
}
|
|
13027
|
+
const code = error && typeof error === "object" ? error.code : void 0;
|
|
13028
|
+
if (code === "ENOENT") {
|
|
13029
|
+
return;
|
|
13030
|
+
}
|
|
13031
|
+
throw error;
|
|
13032
|
+
}
|
|
13033
|
+
}
|
|
13034
|
+
async function readConfig(path) {
|
|
13035
|
+
const source = await (0, import_promises5.readFile)((0, import_node_path13.resolve)(path), "utf8");
|
|
13036
|
+
let parsed;
|
|
13037
|
+
try {
|
|
13038
|
+
parsed = JSON.parse(source);
|
|
13039
|
+
} catch (error) {
|
|
13040
|
+
throw new Error(
|
|
13041
|
+
`Invalid JSON in --config ${path}: ${error instanceof Error ? error.message : String(error)}`
|
|
13042
|
+
);
|
|
13043
|
+
}
|
|
13044
|
+
return expandCompiledConfigAtFiles(parsed);
|
|
13045
|
+
}
|
|
13046
|
+
function parseRows(value, all) {
|
|
13047
|
+
if (all && value) {
|
|
13048
|
+
throw new Error("Do not combine --rows with --all.");
|
|
13049
|
+
}
|
|
13050
|
+
if (all || !value) {
|
|
13051
|
+
return { rowStart: null, rowEnd: null };
|
|
13052
|
+
}
|
|
13053
|
+
const trimmed = value.trim();
|
|
13054
|
+
const range = trimmed.match(/^(\d*)\s*:\s*(\d*)$/);
|
|
13055
|
+
if (range) {
|
|
13056
|
+
if (!range[1] && !range[2]) {
|
|
13057
|
+
throw new Error(
|
|
13058
|
+
"--rows must be a zero-based row number or end-exclusive range like 0:10."
|
|
13059
|
+
);
|
|
13060
|
+
}
|
|
13061
|
+
const start = range[1] ? Number.parseInt(range[1], 10) : 0;
|
|
13062
|
+
const end = range[2] ? Number.parseInt(range[2], 10) : null;
|
|
13063
|
+
return { rowStart: start, rowEnd: end };
|
|
13064
|
+
}
|
|
13065
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
13066
|
+
throw new Error(
|
|
13067
|
+
"--rows must be a zero-based row number or end-exclusive range like 0:10."
|
|
13068
|
+
);
|
|
13069
|
+
}
|
|
13070
|
+
const single = Number.parseInt(trimmed, 10);
|
|
13071
|
+
if (!Number.isFinite(single) || single < 0) {
|
|
13072
|
+
throw new Error(
|
|
13073
|
+
"--rows must be a zero-based row number or end-exclusive range like 0:10."
|
|
13074
|
+
);
|
|
13075
|
+
}
|
|
13076
|
+
return { rowStart: single, rowEnd: single + 1 };
|
|
13077
|
+
}
|
|
13078
|
+
function summarizePlan(config, playSource) {
|
|
13079
|
+
const steps = [];
|
|
13080
|
+
for (const command of config.commands) {
|
|
13081
|
+
if ("with_waterfall" in command) {
|
|
13082
|
+
steps.push({
|
|
13083
|
+
type: "waterfall",
|
|
13084
|
+
alias: command.with_waterfall,
|
|
13085
|
+
min_results: command.min_results ?? 1,
|
|
13086
|
+
steps: command.commands.map(
|
|
13087
|
+
(step) => "with_waterfall" in step ? { type: "waterfall", alias: step.with_waterfall } : { alias: step.alias, tool: step.tool, operation: step.operation }
|
|
13088
|
+
)
|
|
13089
|
+
});
|
|
13090
|
+
continue;
|
|
13091
|
+
}
|
|
13092
|
+
steps.push({
|
|
13093
|
+
type: "step",
|
|
13094
|
+
alias: command.alias,
|
|
13095
|
+
tool: command.tool,
|
|
13096
|
+
operation: command.operation
|
|
13097
|
+
});
|
|
13098
|
+
}
|
|
13099
|
+
return {
|
|
13100
|
+
version: config.version,
|
|
13101
|
+
commandCount: config.commands.length,
|
|
13102
|
+
steps,
|
|
13103
|
+
generatedPlay: playSource
|
|
13104
|
+
};
|
|
13105
|
+
}
|
|
13106
|
+
function collectCommandAliases(config) {
|
|
13107
|
+
const allAliases = /* @__PURE__ */ new Set();
|
|
13108
|
+
const scalarAliases = /* @__PURE__ */ new Set();
|
|
13109
|
+
const waterfallGroups = /* @__PURE__ */ new Map();
|
|
13110
|
+
for (const command of config.commands) {
|
|
13111
|
+
if ("with_waterfall" in command) {
|
|
13112
|
+
const groupAlias = normalizeAlias2(command.with_waterfall);
|
|
13113
|
+
if (groupAlias) {
|
|
13114
|
+
allAliases.add(groupAlias);
|
|
13115
|
+
}
|
|
13116
|
+
const childAliases = /* @__PURE__ */ new Set();
|
|
13117
|
+
for (const child of command.commands) {
|
|
13118
|
+
if ("with_waterfall" in child || child.disabled) {
|
|
13119
|
+
continue;
|
|
13120
|
+
}
|
|
13121
|
+
const childAlias = normalizeAlias2(child.alias);
|
|
13122
|
+
if (!childAlias) {
|
|
13123
|
+
continue;
|
|
13124
|
+
}
|
|
13125
|
+
allAliases.add(childAlias);
|
|
13126
|
+
scalarAliases.add(childAlias);
|
|
13127
|
+
childAliases.add(childAlias);
|
|
13128
|
+
}
|
|
13129
|
+
if (groupAlias) {
|
|
13130
|
+
waterfallGroups.set(groupAlias, childAliases);
|
|
13131
|
+
}
|
|
13132
|
+
continue;
|
|
13133
|
+
}
|
|
13134
|
+
if (command.disabled) {
|
|
13135
|
+
continue;
|
|
13136
|
+
}
|
|
13137
|
+
const alias = normalizeAlias2(command.alias);
|
|
13138
|
+
if (alias) {
|
|
13139
|
+
allAliases.add(alias);
|
|
13140
|
+
scalarAliases.add(alias);
|
|
13141
|
+
}
|
|
13142
|
+
}
|
|
13143
|
+
return { allAliases, scalarAliases, waterfallGroups };
|
|
13144
|
+
}
|
|
13145
|
+
function parseWithForceAliases(values) {
|
|
13146
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
13147
|
+
for (const value of values ?? []) {
|
|
13148
|
+
for (const item of value.split(",")) {
|
|
13149
|
+
const alias = normalizeAlias2(item.trim());
|
|
13150
|
+
if (alias) {
|
|
13151
|
+
aliases.add(alias);
|
|
13152
|
+
}
|
|
13153
|
+
}
|
|
13154
|
+
}
|
|
13155
|
+
return aliases;
|
|
13156
|
+
}
|
|
13157
|
+
function resolveForceAliases(config, options) {
|
|
13158
|
+
const { allAliases, scalarAliases, waterfallGroups } = collectCommandAliases(config);
|
|
13159
|
+
if (options.force) {
|
|
13160
|
+
return new Set(scalarAliases);
|
|
13161
|
+
}
|
|
13162
|
+
const requested = parseWithForceAliases(options.withForce);
|
|
13163
|
+
const unknown = [...requested].filter((alias) => !allAliases.has(alias));
|
|
13164
|
+
if (unknown.length > 0) {
|
|
13165
|
+
throw new Error(
|
|
13166
|
+
`--with-force references unknown --with column alias(es): ${unknown.sort().join(", ")}.`
|
|
13167
|
+
);
|
|
13168
|
+
}
|
|
13169
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
13170
|
+
for (const alias of requested) {
|
|
13171
|
+
const children = waterfallGroups.get(alias);
|
|
13172
|
+
if (children) {
|
|
13173
|
+
for (const child of children) {
|
|
13174
|
+
resolved.add(child);
|
|
13175
|
+
}
|
|
13176
|
+
} else {
|
|
13177
|
+
resolved.add(alias);
|
|
13178
|
+
}
|
|
13179
|
+
}
|
|
13180
|
+
return resolved;
|
|
13181
|
+
}
|
|
13182
|
+
function parseJsonOutput(stdout) {
|
|
13183
|
+
const trimmed = stdout.trim();
|
|
13184
|
+
if (!trimmed) return null;
|
|
13185
|
+
try {
|
|
13186
|
+
return JSON.parse(trimmed);
|
|
13187
|
+
} catch {
|
|
13188
|
+
const start = trimmed.lastIndexOf("\n{");
|
|
13189
|
+
if (start >= 0) {
|
|
13190
|
+
return JSON.parse(trimmed.slice(start + 1));
|
|
13191
|
+
}
|
|
13192
|
+
throw new Error(
|
|
13193
|
+
"The generated play completed but did not emit parseable JSON."
|
|
13194
|
+
);
|
|
13195
|
+
}
|
|
13196
|
+
}
|
|
13197
|
+
async function captureStdout(run) {
|
|
13198
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
13199
|
+
let stdout = "";
|
|
13200
|
+
process.stdout.write = ((chunk, ..._args) => {
|
|
13201
|
+
stdout += typeof chunk === "string" ? chunk : String(chunk);
|
|
13202
|
+
return true;
|
|
13203
|
+
});
|
|
13204
|
+
try {
|
|
13205
|
+
const result = await run();
|
|
13206
|
+
return { result, stdout };
|
|
13207
|
+
} finally {
|
|
13208
|
+
process.stdout.write = originalWrite;
|
|
13209
|
+
}
|
|
13210
|
+
}
|
|
13211
|
+
async function writeOutputCsv(outputPath, status) {
|
|
13212
|
+
const rowsInfo = extractCanonicalRowsInfo(status);
|
|
13213
|
+
if (!rowsInfo) {
|
|
13214
|
+
throw new Error("The generated play did not return row-shaped output.");
|
|
13215
|
+
}
|
|
13216
|
+
assertCompleteRowsForCsvExport(rowsInfo, status, outputPath);
|
|
13217
|
+
const rows = dataExportRows(rowsInfo.rows);
|
|
13218
|
+
const columns = dataExportColumns(rows, rowsInfo.columns);
|
|
13219
|
+
await (0, import_promises5.writeFile)(
|
|
13220
|
+
(0, import_node_path13.resolve)(outputPath),
|
|
13221
|
+
csvStringFromRows(rows, columns),
|
|
13222
|
+
"utf8"
|
|
13223
|
+
);
|
|
13224
|
+
return { rows: rows.length, path: (0, import_node_path13.resolve)(outputPath) };
|
|
13225
|
+
}
|
|
13226
|
+
function assertCompleteRowsForCsvExport(rowsInfo, status, outputPath) {
|
|
13227
|
+
if (rowsInfo.complete) {
|
|
13228
|
+
return;
|
|
13229
|
+
}
|
|
13230
|
+
const runId = status && typeof status === "object" && !Array.isArray(status) && typeof status.runId === "string" ? status.runId : null;
|
|
13231
|
+
const dataset = rowsInfo.source ?? "result.rows";
|
|
13232
|
+
const retry = runId ? ` Retry after the run finalizes its backing dataset with: deepline runs export ${runId} --dataset ${dataset} --out ${outputPath}` : "";
|
|
13233
|
+
throw new Error(
|
|
13234
|
+
`Refusing to write a partial CSV export: the run returned ${rowsInfo.rows.length} preview row(s) out of ${rowsInfo.totalRows}.${retry}`
|
|
13235
|
+
);
|
|
13236
|
+
}
|
|
13237
|
+
async function compileConfig(input2) {
|
|
13238
|
+
if (input2.options.config) {
|
|
13239
|
+
if (hasPlanShapingArgs(input2.args)) {
|
|
13240
|
+
throw new Error(
|
|
13241
|
+
`Do not mix --config with plan-shaping flags (${PLAN_SHAPING_OPTION_NAMES.join(", ")}). Put the plan in the config file or pass flags directly.`
|
|
13242
|
+
);
|
|
13243
|
+
}
|
|
13244
|
+
const config = await readConfig(input2.options.config);
|
|
13245
|
+
return (await input2.client.compileEnrichPlan({ config })).config;
|
|
13246
|
+
}
|
|
13247
|
+
const planArgs = await buildPlanArgs(input2.args);
|
|
13248
|
+
return (await input2.client.compileEnrichPlan({ plan_args: planArgs })).config;
|
|
13249
|
+
}
|
|
13250
|
+
function registerEnrichCommand(program) {
|
|
13251
|
+
program.command("enrich").allowUnknownOption(true).description("Run v1-style CSV enrichment through the V2 play runner.").option("--input <path>", "Input CSV path.").option("--csv <path>", "Alias for --input.").option("--output <path>", "Output CSV path.").option("--config <path>", "JSON enrich config.").option(
|
|
13252
|
+
"--with <json>",
|
|
13253
|
+
"Add a scalar enrich command.",
|
|
13254
|
+
(value, previous = []) => [...previous, value]
|
|
13255
|
+
).option(
|
|
13256
|
+
"--with-waterfall <alias>",
|
|
13257
|
+
"Start a waterfall group.",
|
|
13258
|
+
(value, previous = []) => [...previous, value]
|
|
13259
|
+
).option(
|
|
13260
|
+
"--min-results <count>",
|
|
13261
|
+
"Minimum list results for the current waterfall."
|
|
13262
|
+
).option("--end-waterfall", "End the current waterfall group.").option(
|
|
13263
|
+
"--rows <range>",
|
|
13264
|
+
"Zero-based row number or end-exclusive range, e.g. 0:10."
|
|
13265
|
+
).option("--all", "Run all rows.").option(
|
|
13266
|
+
"--dry-run",
|
|
13267
|
+
"Compile and print the generated plan without starting a run."
|
|
13268
|
+
).option("--json", "Emit JSON.").option("--force", "Force rerun for all enrich aliases.").option(
|
|
13269
|
+
"--with-force <aliases>",
|
|
13270
|
+
"Force rerun for selected aliases.",
|
|
13271
|
+
(value, previous = []) => [...previous, value]
|
|
13272
|
+
).option(
|
|
13273
|
+
"--in-place",
|
|
13274
|
+
"Not supported by the V2 enrich compatibility runner yet."
|
|
13275
|
+
).action(async (options, _command) => {
|
|
13276
|
+
if (options.inPlace) {
|
|
13277
|
+
throw new Error(
|
|
13278
|
+
"--in-place is not supported by this V2 enrich runner yet. Use --output instead."
|
|
13279
|
+
);
|
|
13280
|
+
}
|
|
13281
|
+
const inputCsv = options.input ?? options.csv;
|
|
13282
|
+
if (!inputCsv) {
|
|
13283
|
+
throw new Error("Missing required --input <csv> (or --csv <csv>).");
|
|
13284
|
+
}
|
|
13285
|
+
await assertInputCsvExists(inputCsv);
|
|
13286
|
+
if (options.output) {
|
|
13287
|
+
await assertSafeOutputPath(inputCsv, options.output);
|
|
13288
|
+
}
|
|
13289
|
+
if (!options.config && !hasPlanShapingArgs(currentEnrichArgs())) {
|
|
13290
|
+
throw new Error("Pass --config or at least one --with enrich spec.");
|
|
13291
|
+
}
|
|
13292
|
+
const client = new DeeplineClient();
|
|
13293
|
+
const args = currentEnrichArgs();
|
|
13294
|
+
const config = await compileConfig({ client, args, options });
|
|
13295
|
+
const forceAliases = resolveForceAliases(config, options);
|
|
13296
|
+
const playSource = compileEnrichConfigToPlaySource(config, {
|
|
13297
|
+
forceAliases
|
|
13298
|
+
});
|
|
13299
|
+
const summary = summarizePlan(config, playSource);
|
|
13300
|
+
printDeprecationNotice(options);
|
|
13301
|
+
if (options.dryRun) {
|
|
13302
|
+
if (options.json) {
|
|
13303
|
+
printJson({
|
|
13304
|
+
dryRun: true,
|
|
13305
|
+
deprecation: ENRICH_DEPRECATION_NOTICE,
|
|
13306
|
+
input: (0, import_node_path13.resolve)(inputCsv),
|
|
13307
|
+
output: options.output ? (0, import_node_path13.resolve)(options.output) : null,
|
|
13308
|
+
plan: summary
|
|
13309
|
+
});
|
|
13310
|
+
return;
|
|
13311
|
+
}
|
|
13312
|
+
process.stdout.write(`${playSource}
|
|
13313
|
+
`);
|
|
13314
|
+
return;
|
|
13315
|
+
}
|
|
13316
|
+
const rows = parseRows(options.rows, options.all);
|
|
13317
|
+
if (options.output && options.rows) {
|
|
13318
|
+
throw new Error(
|
|
13319
|
+
"CSV export with --rows is not supported yet because it would write only the selected rows. Run without --rows or omit --output."
|
|
13320
|
+
);
|
|
13321
|
+
}
|
|
13322
|
+
const tempDir = await (0, import_promises5.mkdtemp)((0, import_node_path13.join)((0, import_node_os7.tmpdir)(), "deepline-enrich-play-"));
|
|
13323
|
+
const tempPlay = (0, import_node_path13.join)(tempDir, "deepline-enrich.play.ts");
|
|
13324
|
+
try {
|
|
13325
|
+
await (0, import_promises5.writeFile)(tempPlay, playSource, "utf8");
|
|
13326
|
+
const runtimeInput = {
|
|
13327
|
+
file: (0, import_node_path13.resolve)(inputCsv),
|
|
13328
|
+
...rows.rowStart !== null ? { rowStart: rows.rowStart } : {},
|
|
13329
|
+
...rows.rowEnd !== null ? { rowEnd: rows.rowEnd } : {}
|
|
13330
|
+
};
|
|
13331
|
+
const runArgs = [
|
|
13332
|
+
"--file",
|
|
13333
|
+
tempPlay,
|
|
13334
|
+
"--input",
|
|
13335
|
+
JSON.stringify(runtimeInput),
|
|
13336
|
+
"--watch",
|
|
13337
|
+
"--no-open",
|
|
13338
|
+
"--json"
|
|
13339
|
+
];
|
|
13340
|
+
const captured = await captureStdout(() => handlePlayRun(runArgs));
|
|
13341
|
+
const status = parseJsonOutput(captured.stdout);
|
|
13342
|
+
if (captured.result !== 0) {
|
|
13343
|
+
if (options.json) {
|
|
13344
|
+
printJson({
|
|
13345
|
+
deprecation: ENRICH_DEPRECATION_NOTICE,
|
|
13346
|
+
result: status
|
|
13347
|
+
});
|
|
13348
|
+
} else {
|
|
13349
|
+
process.stdout.write(captured.stdout);
|
|
13350
|
+
}
|
|
13351
|
+
process.exitCode = captured.result;
|
|
13352
|
+
return;
|
|
13353
|
+
}
|
|
13354
|
+
const exportResult = options.output ? await writeOutputCsv(options.output, status) : null;
|
|
13355
|
+
if (options.json) {
|
|
13356
|
+
printJson({
|
|
13357
|
+
ok: true,
|
|
13358
|
+
deprecation: ENRICH_DEPRECATION_NOTICE,
|
|
13359
|
+
run: status,
|
|
13360
|
+
output: exportResult
|
|
13361
|
+
});
|
|
13362
|
+
return;
|
|
13363
|
+
}
|
|
13364
|
+
process.stdout.write(captured.stdout);
|
|
13365
|
+
if (exportResult) {
|
|
13366
|
+
process.stderr.write(
|
|
13367
|
+
`Wrote ${exportResult.rows} row(s) to ${exportResult.path}
|
|
13368
|
+
`
|
|
13369
|
+
);
|
|
13370
|
+
}
|
|
13371
|
+
} finally {
|
|
13372
|
+
await (0, import_promises5.rm)(tempDir, { recursive: true, force: true });
|
|
13373
|
+
}
|
|
13374
|
+
});
|
|
13375
|
+
}
|
|
13376
|
+
|
|
13377
|
+
// src/cli/commands/feedback.ts
|
|
13378
|
+
async function handleFeedback(text, options) {
|
|
13379
|
+
const { http } = getAuthedHttpClient();
|
|
13380
|
+
const response = await http.post("/api/v2/cli/feedback", {
|
|
13381
|
+
text,
|
|
13382
|
+
environment: collectLocalEnvInfo(),
|
|
13383
|
+
...options.command ? { command: options.command } : {},
|
|
13384
|
+
...options.payload ? { payload: options.payload } : {}
|
|
13385
|
+
});
|
|
13386
|
+
printCommandEnvelope(
|
|
13387
|
+
{
|
|
13388
|
+
...response,
|
|
13389
|
+
render: {
|
|
13390
|
+
sections: [
|
|
13391
|
+
{ title: "feedback", lines: ["Feedback submitted. Thank you."] }
|
|
13392
|
+
]
|
|
13393
|
+
}
|
|
13394
|
+
},
|
|
13395
|
+
{ json: options.json }
|
|
13396
|
+
);
|
|
13397
|
+
}
|
|
13398
|
+
function registerFeedbackCommands(program) {
|
|
13399
|
+
const feedback = program.command("feedback").description("Submit CLI feedback to Deepline.").addHelpText(
|
|
13400
|
+
"after",
|
|
13401
|
+
`
|
|
13402
|
+
Notes:
|
|
13403
|
+
Sends the feedback text plus local CLI environment info to Deepline support.
|
|
13404
|
+
Use --command and --payload to attach a reproducible command shape.
|
|
13405
|
+
|
|
13406
|
+
Examples:
|
|
13407
|
+
deepline feedback "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
|
|
13408
|
+
deepline feedback "unexpected billing output" --payload '{"command":"billing usage"}' --json
|
|
13409
|
+
`
|
|
13410
|
+
);
|
|
13411
|
+
feedback.argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
|
|
13412
|
+
program.command("provide-feedback").description("Legacy alias for `deepline feedback`.").addHelpText(
|
|
13413
|
+
"after",
|
|
13414
|
+
`
|
|
13415
|
+
Notes:
|
|
13416
|
+
Compatibility alias. Prefer deepline feedback in new scripts and docs.
|
|
13417
|
+
|
|
13418
|
+
Examples:
|
|
13419
|
+
deepline feedback "tools search returned stale results" --json
|
|
13420
|
+
`
|
|
13421
|
+
).argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
|
|
13422
|
+
}
|
|
13423
|
+
|
|
13424
|
+
// src/cli/commands/org.ts
|
|
13425
|
+
async function fetchOrganizations(http, apiKey) {
|
|
13426
|
+
return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
|
|
13427
|
+
}
|
|
13428
|
+
function orgListLines(orgs) {
|
|
13429
|
+
return orgs.map((org, index) => {
|
|
13430
|
+
const current = org.is_current ? " (current)" : "";
|
|
13431
|
+
const role = org.role ? ` [${org.role}]` : "";
|
|
13432
|
+
return `${index + 1}. ${org.name}${role}${current}`;
|
|
13433
|
+
});
|
|
13434
|
+
}
|
|
13435
|
+
async function handleOrgList(options) {
|
|
13436
|
+
const config = resolveConfig();
|
|
13437
|
+
const http = new HttpClient(config);
|
|
13438
|
+
const payload = await fetchOrganizations(http, config.apiKey);
|
|
13439
|
+
printCommandEnvelope(
|
|
13440
|
+
{
|
|
13441
|
+
...payload,
|
|
13442
|
+
render: {
|
|
13443
|
+
sections: [
|
|
13444
|
+
{
|
|
13445
|
+
title: "Your organizations:",
|
|
13446
|
+
lines: orgListLines(payload.organizations)
|
|
13447
|
+
}
|
|
13448
|
+
]
|
|
13449
|
+
}
|
|
13450
|
+
},
|
|
13451
|
+
{ json: options.json }
|
|
13452
|
+
);
|
|
13453
|
+
}
|
|
13454
|
+
async function handleOrgSwitch(selection, options) {
|
|
13455
|
+
const config = resolveConfig();
|
|
13456
|
+
const http = new HttpClient(config);
|
|
13457
|
+
const payload = await fetchOrganizations(http, config.apiKey);
|
|
13458
|
+
if (!selection && !options.orgId) {
|
|
13459
|
+
printCommandEnvelope(
|
|
13460
|
+
{
|
|
13461
|
+
...payload,
|
|
13462
|
+
next: { switch: "deepline org switch <number>" },
|
|
13463
|
+
render: {
|
|
13464
|
+
sections: [
|
|
13465
|
+
{
|
|
13466
|
+
title: "Your organizations:",
|
|
13467
|
+
lines: orgListLines(payload.organizations)
|
|
13468
|
+
}
|
|
13469
|
+
],
|
|
13470
|
+
actions: [{ label: "Run", command: "deepline org switch <number>" }]
|
|
13471
|
+
}
|
|
13472
|
+
},
|
|
13473
|
+
{ json: options.json }
|
|
13474
|
+
);
|
|
13475
|
+
return;
|
|
13476
|
+
}
|
|
13477
|
+
let target = payload.organizations.find(
|
|
13478
|
+
(org) => org.org_id === options.orgId
|
|
13479
|
+
);
|
|
13480
|
+
if (!target && selection) {
|
|
13481
|
+
const index = Number.parseInt(selection, 10);
|
|
13482
|
+
if (Number.isFinite(index) && index >= 1 && index <= payload.organizations.length) {
|
|
13483
|
+
target = payload.organizations[index - 1];
|
|
13484
|
+
} else {
|
|
13485
|
+
target = payload.organizations.find(
|
|
13486
|
+
(org) => org.name === selection || org.org_id === selection
|
|
13487
|
+
);
|
|
13488
|
+
}
|
|
13489
|
+
}
|
|
13490
|
+
if (!target) {
|
|
13491
|
+
throw new Error("Could not resolve the selected organization.");
|
|
13492
|
+
}
|
|
13493
|
+
if (target.is_current) {
|
|
13494
|
+
printCommandEnvelope(
|
|
13495
|
+
{
|
|
13496
|
+
ok: true,
|
|
13497
|
+
unchanged: true,
|
|
13498
|
+
organization: target,
|
|
13499
|
+
render: {
|
|
13500
|
+
sections: [
|
|
13501
|
+
{ title: "org switch", lines: [`Already on ${target.name}.`] }
|
|
13502
|
+
]
|
|
13503
|
+
}
|
|
13504
|
+
},
|
|
13505
|
+
{ json: options.json }
|
|
13506
|
+
);
|
|
13507
|
+
return;
|
|
13508
|
+
}
|
|
13509
|
+
const switched = await http.post("/api/v2/auth/cli/switch", {
|
|
13510
|
+
api_key: config.apiKey,
|
|
13511
|
+
org_id: target.org_id
|
|
13512
|
+
});
|
|
13513
|
+
saveHostEnvValues(config.baseUrl, {
|
|
13514
|
+
DEEPLINE_API_KEY: switched.api_key,
|
|
13515
|
+
DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
|
|
13516
|
+
DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
|
|
13517
|
+
});
|
|
13518
|
+
const { api_key: _apiKey, ...publicSwitched } = switched;
|
|
13519
|
+
printCommandEnvelope(
|
|
13520
|
+
{
|
|
13521
|
+
ok: true,
|
|
13522
|
+
host_env_path: hostEnvFilePath(config.baseUrl),
|
|
13523
|
+
...publicSwitched,
|
|
13524
|
+
api_key_saved: true,
|
|
13525
|
+
render: {
|
|
13526
|
+
sections: [
|
|
13527
|
+
{
|
|
13528
|
+
title: "org switch",
|
|
13529
|
+
lines: [
|
|
13530
|
+
`Switched to ${switched.org_name}.`,
|
|
13531
|
+
`Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
|
|
13532
|
+
]
|
|
13533
|
+
}
|
|
13534
|
+
]
|
|
13535
|
+
}
|
|
13536
|
+
},
|
|
13537
|
+
{ json: options.json }
|
|
13538
|
+
);
|
|
13539
|
+
}
|
|
13540
|
+
function registerOrgCommands(program) {
|
|
13541
|
+
const org = program.command("org").description("List and switch organizations.").addHelpText(
|
|
13542
|
+
"after",
|
|
13543
|
+
`
|
|
13544
|
+
Notes:
|
|
13545
|
+
Organizations are workspaces. Switching organizations mutates the saved host
|
|
13546
|
+
auth file so later CLI commands target the selected workspace.
|
|
13547
|
+
|
|
13548
|
+
Examples:
|
|
13549
|
+
deepline org list --json
|
|
13550
|
+
deepline org switch 2
|
|
13551
|
+
deepline org switch --org-id org_123 --json
|
|
13552
|
+
`
|
|
13553
|
+
);
|
|
13554
|
+
org.command("list").description("List your organizations.").addHelpText(
|
|
13555
|
+
"after",
|
|
13556
|
+
`
|
|
13557
|
+
Notes:
|
|
13558
|
+
Read-only. Marks the active organization when the server returns that metadata.
|
|
13559
|
+
|
|
13560
|
+
Examples:
|
|
13561
|
+
deepline org list
|
|
13562
|
+
deepline org list --json
|
|
13563
|
+
`
|
|
13564
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgList);
|
|
13565
|
+
org.command("switch [selection]").description(
|
|
13566
|
+
"Switch to another organization and save the new API key in the host auth file."
|
|
13567
|
+
).addHelpText(
|
|
13568
|
+
"after",
|
|
13569
|
+
`
|
|
13570
|
+
Notes:
|
|
13571
|
+
Mutates the saved host auth file. Selection can be a list number, exact
|
|
13572
|
+
organization name, or organization id. Without a selection, prints choices.
|
|
13573
|
+
|
|
13574
|
+
Examples:
|
|
13575
|
+
deepline org switch
|
|
13576
|
+
deepline org switch 2
|
|
13577
|
+
deepline org switch --org-id org_123 --json
|
|
13578
|
+
`
|
|
13579
|
+
).option("--org-id <id>", "Switch using an explicit organization id").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgSwitch);
|
|
13580
|
+
}
|
|
13581
|
+
|
|
13582
|
+
// src/cli/commands/secrets.ts
|
|
13583
|
+
var import_node_process = require("process");
|
|
13584
|
+
var hiddenInputBuffer = "";
|
|
13585
|
+
function normalizeSecretName(value) {
|
|
13586
|
+
const normalized = value.trim().toUpperCase();
|
|
13587
|
+
if (!/^[A-Z][A-Z0-9_]{1,63}$/.test(normalized)) {
|
|
13588
|
+
throw new Error(
|
|
13589
|
+
"Secret names must be 2-64 characters and use uppercase letters, numbers, and underscores."
|
|
13590
|
+
);
|
|
13591
|
+
}
|
|
13592
|
+
return normalized;
|
|
13593
|
+
}
|
|
13594
|
+
function renderSecret(secret) {
|
|
13595
|
+
const scope = secret.scope === "play" && secret.playName ? `play:${secret.playName}` : secret.scope;
|
|
13596
|
+
return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}`;
|
|
13597
|
+
}
|
|
13598
|
+
async function readHiddenLine(prompt) {
|
|
13599
|
+
if (!import_node_process.stdin.isTTY || !import_node_process.stdout.isTTY) {
|
|
13600
|
+
throw new Error(
|
|
13601
|
+
"Secret values must be entered from an interactive TTY. Do not pipe, pass, or script secret values."
|
|
13602
|
+
);
|
|
13603
|
+
}
|
|
13604
|
+
import_node_process.stdout.write(prompt);
|
|
13605
|
+
const previousRawMode = import_node_process.stdin.isRaw;
|
|
13606
|
+
if (typeof import_node_process.stdin.setRawMode === "function") import_node_process.stdin.setRawMode(true);
|
|
13607
|
+
let value = "";
|
|
13608
|
+
import_node_process.stdin.resume();
|
|
13609
|
+
return await new Promise((resolve13, reject) => {
|
|
13610
|
+
let settled = false;
|
|
13611
|
+
const cleanup = () => {
|
|
13612
|
+
import_node_process.stdin.off("data", onData);
|
|
13613
|
+
import_node_process.stdin.off("end", onEnd);
|
|
13614
|
+
import_node_process.stdin.off("error", onError);
|
|
13615
|
+
if (typeof import_node_process.stdin.setRawMode === "function") {
|
|
13616
|
+
import_node_process.stdin.setRawMode(previousRawMode);
|
|
13617
|
+
}
|
|
13618
|
+
};
|
|
13619
|
+
const finish = (line) => {
|
|
13620
|
+
if (settled) return;
|
|
13621
|
+
settled = true;
|
|
13622
|
+
import_node_process.stdout.write("\n");
|
|
12664
13623
|
cleanup();
|
|
12665
|
-
|
|
13624
|
+
resolve13(line);
|
|
12666
13625
|
};
|
|
12667
13626
|
const fail = (error) => {
|
|
12668
13627
|
if (settled) return;
|
|
@@ -12835,13 +13794,13 @@ Examples:
|
|
|
12835
13794
|
// src/cli/commands/tools.ts
|
|
12836
13795
|
var import_commander2 = require("commander");
|
|
12837
13796
|
var import_node_fs12 = require("fs");
|
|
12838
|
-
var
|
|
12839
|
-
var
|
|
13797
|
+
var import_node_os9 = require("os");
|
|
13798
|
+
var import_node_path15 = require("path");
|
|
12840
13799
|
|
|
12841
13800
|
// src/tool-output.ts
|
|
12842
13801
|
var import_node_fs11 = require("fs");
|
|
12843
|
-
var
|
|
12844
|
-
var
|
|
13802
|
+
var import_node_os8 = require("os");
|
|
13803
|
+
var import_node_path14 = require("path");
|
|
12845
13804
|
function isPlainObject(value) {
|
|
12846
13805
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
12847
13806
|
}
|
|
@@ -12937,19 +13896,19 @@ function tryConvertToList(payload, options) {
|
|
|
12937
13896
|
return null;
|
|
12938
13897
|
}
|
|
12939
13898
|
function ensureOutputDir() {
|
|
12940
|
-
const outputDir = (0,
|
|
13899
|
+
const outputDir = (0, import_node_path14.join)((0, import_node_os8.homedir)(), ".local", "share", "deepline", "data");
|
|
12941
13900
|
(0, import_node_fs11.mkdirSync)(outputDir, { recursive: true });
|
|
12942
13901
|
return outputDir;
|
|
12943
13902
|
}
|
|
12944
13903
|
function writeJsonOutputFile(payload, stem) {
|
|
12945
13904
|
const outputDir = ensureOutputDir();
|
|
12946
|
-
const outputPath = (0,
|
|
13905
|
+
const outputPath = (0, import_node_path14.join)(outputDir, `${stem}_${Date.now()}.json`);
|
|
12947
13906
|
(0, import_node_fs11.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
12948
13907
|
return outputPath;
|
|
12949
13908
|
}
|
|
12950
13909
|
function writeCsvOutputFile(rows, stem) {
|
|
12951
13910
|
const outputDir = ensureOutputDir();
|
|
12952
|
-
const outputPath = (0,
|
|
13911
|
+
const outputPath = (0, import_node_path14.join)(outputDir, `${stem}_${Date.now()}.csv`);
|
|
12953
13912
|
const seen = /* @__PURE__ */ new Set();
|
|
12954
13913
|
const columns = [];
|
|
12955
13914
|
for (const row of rows) {
|
|
@@ -13708,7 +14667,7 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
|
|
|
13708
14667
|
const expression = stringField(firstGetter, "expression");
|
|
13709
14668
|
if (expression)
|
|
13710
14669
|
console.log(
|
|
13711
|
-
`const ${
|
|
14670
|
+
`const ${safeIdentifier3(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`
|
|
13712
14671
|
);
|
|
13713
14672
|
}
|
|
13714
14673
|
console.log("```");
|
|
@@ -13777,7 +14736,7 @@ function samplePayloadForInputFields(fields) {
|
|
|
13777
14736
|
function stableStepIdForTool(toolId) {
|
|
13778
14737
|
return toolId.replace(/^[a-z0-9]+_/, "").replace(/[^a-z0-9_]+/gi, "_") || "tool_call";
|
|
13779
14738
|
}
|
|
13780
|
-
function
|
|
14739
|
+
function safeIdentifier3(name) {
|
|
13781
14740
|
const cleaned = name.replace(/[^a-zA-Z0-9_$]+/g, "_").replace(/^[^a-zA-Z_$]+/, "");
|
|
13782
14741
|
return cleaned || "value";
|
|
13783
14742
|
}
|
|
@@ -14040,9 +14999,9 @@ function powerShellQuote(value) {
|
|
|
14040
14999
|
function seedToolListScript(input2) {
|
|
14041
15000
|
const stem = safeFileStem(input2.toolId);
|
|
14042
15001
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
14043
|
-
const scriptDir = (0, import_node_fs12.mkdtempSync)((0,
|
|
15002
|
+
const scriptDir = (0, import_node_fs12.mkdtempSync)((0, import_node_path15.join)((0, import_node_os9.tmpdir)(), "deepline-workflow-seed-"));
|
|
14044
15003
|
(0, import_node_fs12.chmodSync)(scriptDir, 448);
|
|
14045
|
-
const scriptPath = (0,
|
|
15004
|
+
const scriptPath = (0, import_node_path15.join)(scriptDir, fileName);
|
|
14046
15005
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
14047
15006
|
const playName = `${stem}-workflow`;
|
|
14048
15007
|
const sampleRows = input2.rows.length > 0 ? `${JSON.stringify(input2.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
@@ -14334,7 +15293,7 @@ async function executeTool(args) {
|
|
|
14334
15293
|
// src/cli/commands/update.ts
|
|
14335
15294
|
var import_node_child_process = require("child_process");
|
|
14336
15295
|
var import_node_fs13 = require("fs");
|
|
14337
|
-
var
|
|
15296
|
+
var import_node_path16 = require("path");
|
|
14338
15297
|
function posixShellQuote(value) {
|
|
14339
15298
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
14340
15299
|
}
|
|
@@ -14353,19 +15312,19 @@ function buildSourceUpdateCommand(sourceRoot) {
|
|
|
14353
15312
|
return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
|
|
14354
15313
|
}
|
|
14355
15314
|
function findRepoBackedSdkRoot(startPath) {
|
|
14356
|
-
let current = (0,
|
|
15315
|
+
let current = (0, import_node_path16.resolve)(startPath);
|
|
14357
15316
|
while (true) {
|
|
14358
|
-
if ((0, import_node_fs13.existsSync)((0,
|
|
15317
|
+
if ((0, import_node_fs13.existsSync)((0, import_node_path16.join)(current, "sdk", "package.json")) && (0, import_node_fs13.existsSync)((0, import_node_path16.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
|
|
14359
15318
|
return current;
|
|
14360
15319
|
}
|
|
14361
|
-
const parent = (0,
|
|
15320
|
+
const parent = (0, import_node_path16.dirname)(current);
|
|
14362
15321
|
if (parent === current) return null;
|
|
14363
15322
|
current = parent;
|
|
14364
15323
|
}
|
|
14365
15324
|
}
|
|
14366
15325
|
function resolveUpdatePlan() {
|
|
14367
|
-
const entrypoint = process.argv[1] ? (0,
|
|
14368
|
-
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0,
|
|
15326
|
+
const entrypoint = process.argv[1] ? (0, import_node_path16.resolve)(process.argv[1]) : "";
|
|
15327
|
+
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path16.dirname)(entrypoint)) : null;
|
|
14369
15328
|
if (sourceRoot) {
|
|
14370
15329
|
return {
|
|
14371
15330
|
kind: "source",
|
|
@@ -14629,8 +15588,8 @@ function unknownCommandNameFromMessage(message) {
|
|
|
14629
15588
|
// src/cli/skills-sync.ts
|
|
14630
15589
|
var import_node_child_process2 = require("child_process");
|
|
14631
15590
|
var import_node_fs14 = require("fs");
|
|
14632
|
-
var
|
|
14633
|
-
var
|
|
15591
|
+
var import_node_os10 = require("os");
|
|
15592
|
+
var import_node_path17 = require("path");
|
|
14634
15593
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
14635
15594
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
14636
15595
|
var attemptedSync = false;
|
|
@@ -14639,8 +15598,8 @@ function shouldSkipSkillsSync() {
|
|
|
14639
15598
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
14640
15599
|
}
|
|
14641
15600
|
function sdkSkillsVersionPath(baseUrl) {
|
|
14642
|
-
const home = process.env.HOME?.trim() || (0,
|
|
14643
|
-
return (0,
|
|
15601
|
+
const home = process.env.HOME?.trim() || (0, import_node_os10.homedir)();
|
|
15602
|
+
return (0, import_node_path17.join)(
|
|
14644
15603
|
home,
|
|
14645
15604
|
".local",
|
|
14646
15605
|
"deepline",
|
|
@@ -14660,15 +15619,15 @@ function readLocalSkillsVersion(baseUrl) {
|
|
|
14660
15619
|
}
|
|
14661
15620
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
14662
15621
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
14663
|
-
(0, import_node_fs14.mkdirSync)((0,
|
|
15622
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path17.dirname)(path), { recursive: true });
|
|
14664
15623
|
(0, import_node_fs14.writeFileSync)(path, `${version}
|
|
14665
15624
|
`, "utf-8");
|
|
14666
15625
|
}
|
|
14667
15626
|
function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
14668
|
-
const home = process.env.HOME?.trim() || (0,
|
|
15627
|
+
const home = process.env.HOME?.trim() || (0, import_node_os10.homedir)();
|
|
14669
15628
|
const roots = [
|
|
14670
|
-
(0,
|
|
14671
|
-
(0,
|
|
15629
|
+
(0, import_node_path17.join)(home, ".claude", "skills", SDK_SKILL_NAME),
|
|
15630
|
+
(0, import_node_path17.join)(home, ".agents", "skills", SDK_SKILL_NAME)
|
|
14672
15631
|
];
|
|
14673
15632
|
const staleMarkers = [
|
|
14674
15633
|
"ctx.tools.execute(key",
|
|
@@ -14679,9 +15638,9 @@ function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
|
14679
15638
|
];
|
|
14680
15639
|
const scan = (dir) => {
|
|
14681
15640
|
for (const entry of (0, import_node_fs14.readdirSync)(dir)) {
|
|
14682
|
-
const path = (0,
|
|
14683
|
-
const
|
|
14684
|
-
if (
|
|
15641
|
+
const path = (0, import_node_path17.join)(dir, entry);
|
|
15642
|
+
const stat4 = (0, import_node_fs14.statSync)(path);
|
|
15643
|
+
if (stat4.isDirectory()) {
|
|
14685
15644
|
if (scan(path)) return true;
|
|
14686
15645
|
continue;
|
|
14687
15646
|
}
|
|
@@ -14765,7 +15724,7 @@ function resolveSkillsInstallCommands(baseUrl) {
|
|
|
14765
15724
|
return [npxInstall];
|
|
14766
15725
|
}
|
|
14767
15726
|
function runOneSkillsInstall(install) {
|
|
14768
|
-
return new Promise((
|
|
15727
|
+
return new Promise((resolve13) => {
|
|
14769
15728
|
const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
|
|
14770
15729
|
stdio: ["ignore", "ignore", "pipe"],
|
|
14771
15730
|
env: process.env
|
|
@@ -14775,7 +15734,7 @@ function runOneSkillsInstall(install) {
|
|
|
14775
15734
|
stderr += chunk.toString("utf-8");
|
|
14776
15735
|
});
|
|
14777
15736
|
child.on("error", (error) => {
|
|
14778
|
-
|
|
15737
|
+
resolve13({
|
|
14779
15738
|
ok: false,
|
|
14780
15739
|
detail: `failed to start ${install.command}: ${error.message}`,
|
|
14781
15740
|
manualCommand: install.manualCommand
|
|
@@ -14783,11 +15742,11 @@ function runOneSkillsInstall(install) {
|
|
|
14783
15742
|
});
|
|
14784
15743
|
child.on("close", (code) => {
|
|
14785
15744
|
if (code === 0) {
|
|
14786
|
-
|
|
15745
|
+
resolve13({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
14787
15746
|
return;
|
|
14788
15747
|
}
|
|
14789
15748
|
const detail = stderr.trim();
|
|
14790
|
-
|
|
15749
|
+
resolve13({
|
|
14791
15750
|
ok: false,
|
|
14792
15751
|
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
14793
15752
|
manualCommand: install.manualCommand
|
|
@@ -14870,10 +15829,10 @@ function shouldDeferSkillsSyncForCommand() {
|
|
|
14870
15829
|
return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
|
|
14871
15830
|
}
|
|
14872
15831
|
async function runPlayRunnerHealthCheck() {
|
|
14873
|
-
const dir = await (0,
|
|
14874
|
-
const file = (0,
|
|
15832
|
+
const dir = await (0, import_promises6.mkdtemp)((0, import_node_path18.join)((0, import_node_os11.tmpdir)(), "deepline-health-play-"));
|
|
15833
|
+
const file = (0, import_node_path18.join)(dir, "health-check.play.ts");
|
|
14875
15834
|
try {
|
|
14876
|
-
await (0,
|
|
15835
|
+
await (0, import_promises6.writeFile)(
|
|
14877
15836
|
file,
|
|
14878
15837
|
[
|
|
14879
15838
|
"import { definePlay } from 'deepline';",
|
|
@@ -14921,7 +15880,7 @@ async function runPlayRunnerHealthCheck() {
|
|
|
14921
15880
|
}
|
|
14922
15881
|
};
|
|
14923
15882
|
} finally {
|
|
14924
|
-
await (0,
|
|
15883
|
+
await (0, import_promises6.rm)(dir, { recursive: true, force: true });
|
|
14925
15884
|
}
|
|
14926
15885
|
}
|
|
14927
15886
|
async function main() {
|
|
@@ -14998,6 +15957,7 @@ Exit codes:
|
|
|
14998
15957
|
registerSecretsCommands(program);
|
|
14999
15958
|
registerBillingCommands(program);
|
|
15000
15959
|
registerOrgCommands(program);
|
|
15960
|
+
registerEnrichCommand(program);
|
|
15001
15961
|
registerCsvCommands(program);
|
|
15002
15962
|
registerDbCommands(program);
|
|
15003
15963
|
registerFeedbackCommands(program);
|