deepline 0.1.93 → 0.1.94
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 +2702 -509
- package/dist/cli/index.mjs +2725 -525
- package/dist/index.d.mts +158 -103
- package/dist/index.d.ts +158 -103
- package/dist/index.js +129 -39
- package/dist/index.mjs +129 -39
- package/dist/repo/apps/play-runner-workers/src/entry.ts +23 -8
- package/dist/repo/sdk/src/client.ts +123 -0
- package/dist/repo/sdk/src/play.ts +51 -0
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/email-status.ts +10 -36
- package/dist/repo/shared_libs/play-runtime/extractor-targets.ts +3 -3
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +44 -0
- package/dist/repo/shared_libs/plays/secret-guardrails.ts +22 -11
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -24,8 +24,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/cli/index.ts
|
|
27
|
-
var
|
|
28
|
-
var
|
|
27
|
+
var import_promises7 = require("fs/promises");
|
|
28
|
+
var import_node_path19 = require("path");
|
|
29
29
|
var import_node_os11 = require("os");
|
|
30
30
|
var import_commander3 = require("commander");
|
|
31
31
|
|
|
@@ -229,10 +229,10 @@ var import_node_path2 = require("path");
|
|
|
229
229
|
|
|
230
230
|
// src/release.ts
|
|
231
231
|
var SDK_RELEASE = {
|
|
232
|
-
version: "0.1.
|
|
232
|
+
version: "0.1.94",
|
|
233
233
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
234
234
|
supportPolicy: {
|
|
235
|
-
latest: "0.1.
|
|
235
|
+
latest: "0.1.94",
|
|
236
236
|
minimumSupported: "0.1.53",
|
|
237
237
|
deprecatedBelow: "0.1.53"
|
|
238
238
|
}
|
|
@@ -584,7 +584,7 @@ function decodeSseFrame(frame) {
|
|
|
584
584
|
return parsed;
|
|
585
585
|
}
|
|
586
586
|
function sleep(ms) {
|
|
587
|
-
return new Promise((
|
|
587
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
588
588
|
}
|
|
589
589
|
|
|
590
590
|
// src/stream-reconnect.ts
|
|
@@ -1200,7 +1200,7 @@ async function* observeRunEvents(options) {
|
|
|
1200
1200
|
const logPageQuery = convexServer.makeFunctionReference(
|
|
1201
1201
|
OBSERVER_LOG_PAGE_QUERY
|
|
1202
1202
|
);
|
|
1203
|
-
const
|
|
1203
|
+
const client2 = new convexBrowser.ConvexClient(grant.convexUrl, {
|
|
1204
1204
|
...webSocketConstructor ? { webSocketConstructor } : {},
|
|
1205
1205
|
unsavedChangesWarning: false
|
|
1206
1206
|
});
|
|
@@ -1212,7 +1212,7 @@ async function* observeRunEvents(options) {
|
|
|
1212
1212
|
wake = null;
|
|
1213
1213
|
};
|
|
1214
1214
|
let lastForcedRefreshAt = 0;
|
|
1215
|
-
|
|
1215
|
+
client2.setAuth(async ({ forceRefreshToken }) => {
|
|
1216
1216
|
const now = Date.now();
|
|
1217
1217
|
if (!forceRefreshToken && grant.expiresAt - now > GRANT_REFRESH_MARGIN_MS) {
|
|
1218
1218
|
return grant.token;
|
|
@@ -1239,7 +1239,7 @@ async function* observeRunEvents(options) {
|
|
|
1239
1239
|
return null;
|
|
1240
1240
|
}
|
|
1241
1241
|
});
|
|
1242
|
-
const unsubscribe =
|
|
1242
|
+
const unsubscribe = client2.onUpdate(
|
|
1243
1243
|
snapshotQuery,
|
|
1244
1244
|
{ workflowId: runId },
|
|
1245
1245
|
(run) => push({ kind: "run", run: run ?? null }),
|
|
@@ -1253,7 +1253,7 @@ async function* observeRunEvents(options) {
|
|
|
1253
1253
|
const watchdog = setInterval(() => {
|
|
1254
1254
|
const now = Date.now();
|
|
1255
1255
|
try {
|
|
1256
|
-
const connectionState =
|
|
1256
|
+
const connectionState = client2.connectionState();
|
|
1257
1257
|
if (connectionState.isWebSocketConnected) {
|
|
1258
1258
|
disconnectedSince = null;
|
|
1259
1259
|
warnedReconnecting = false;
|
|
@@ -1291,14 +1291,14 @@ async function* observeRunEvents(options) {
|
|
|
1291
1291
|
try {
|
|
1292
1292
|
for (; ; ) {
|
|
1293
1293
|
if (queue.length === 0) {
|
|
1294
|
-
const waitForItem = new Promise((
|
|
1295
|
-
wake =
|
|
1294
|
+
const waitForItem = new Promise((resolve15) => {
|
|
1295
|
+
wake = resolve15;
|
|
1296
1296
|
});
|
|
1297
1297
|
if (!sawFirstSnapshot) {
|
|
1298
1298
|
const timedOut = await Promise.race([
|
|
1299
1299
|
waitForItem.then(() => false),
|
|
1300
1300
|
new Promise(
|
|
1301
|
-
(
|
|
1301
|
+
(resolve15) => setTimeout(() => resolve15(true), OBSERVE_BOOTSTRAP_TIMEOUT_MS)
|
|
1302
1302
|
)
|
|
1303
1303
|
]);
|
|
1304
1304
|
if (timedOut && queue.length === 0) {
|
|
@@ -1334,7 +1334,7 @@ async function* observeRunEvents(options) {
|
|
|
1334
1334
|
const gap = resolvePlayRunLogGap(snapshot, diffState.lastLogSeq);
|
|
1335
1335
|
if (gap && diffState.lastLogSeq > 0) {
|
|
1336
1336
|
const backfilled = await backfillLogGap({
|
|
1337
|
-
queryLogPage: (afterSeq, limit) =>
|
|
1337
|
+
queryLogPage: (afterSeq, limit) => client2.query(logPageQuery, {
|
|
1338
1338
|
workflowId: runId,
|
|
1339
1339
|
afterSeq,
|
|
1340
1340
|
limit
|
|
@@ -1384,7 +1384,7 @@ async function* observeRunEvents(options) {
|
|
|
1384
1384
|
unsubscribe();
|
|
1385
1385
|
} catch {
|
|
1386
1386
|
}
|
|
1387
|
-
await
|
|
1387
|
+
await client2.close().catch(() => void 0);
|
|
1388
1388
|
}
|
|
1389
1389
|
}
|
|
1390
1390
|
|
|
@@ -1395,7 +1395,7 @@ var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
|
|
|
1395
1395
|
var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
|
|
1396
1396
|
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
1397
1397
|
function sleep2(ms) {
|
|
1398
|
-
return new Promise((
|
|
1398
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
1399
1399
|
}
|
|
1400
1400
|
function isTransientCompileManifestError(error) {
|
|
1401
1401
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
@@ -2298,6 +2298,93 @@ var DeeplineClient = class {
|
|
|
2298
2298
|
);
|
|
2299
2299
|
return response.runs ?? [];
|
|
2300
2300
|
}
|
|
2301
|
+
// ---------------------------------------------------------------------------
|
|
2302
|
+
// Legacy workflows (double-shipped). Thin pass-throughs over the live cloud
|
|
2303
|
+
// `/api/v2/workflows/*` API so the SDK CLI keeps existing cloud workflows
|
|
2304
|
+
// working while users migrate them to plays via `workflows transform`. Kept
|
|
2305
|
+
// intentionally minimal — workflows are a deprecated surface.
|
|
2306
|
+
// ---------------------------------------------------------------------------
|
|
2307
|
+
/** List the org's workflows. `GET /api/v2/workflows`. */
|
|
2308
|
+
async listWorkflows(options) {
|
|
2309
|
+
const params = new URLSearchParams();
|
|
2310
|
+
if (typeof options?.limit === "number") {
|
|
2311
|
+
params.set("limit", String(options.limit));
|
|
2312
|
+
}
|
|
2313
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
2314
|
+
return this.http.get(`/api/v2/workflows${query}`);
|
|
2315
|
+
}
|
|
2316
|
+
/**
|
|
2317
|
+
* Fetch a single workflow (including its published-revision config — the
|
|
2318
|
+
* input to `compileWorkflowConfigToPlay`). `GET /api/v2/workflows/:id`.
|
|
2319
|
+
*/
|
|
2320
|
+
async getWorkflow(id) {
|
|
2321
|
+
return this.http.get(`/api/v2/workflows/${encodeURIComponent(id)}`);
|
|
2322
|
+
}
|
|
2323
|
+
/** Delete a workflow. `DELETE /api/v2/workflows/:id`. */
|
|
2324
|
+
async deleteWorkflow(id) {
|
|
2325
|
+
return this.http.delete(`/api/v2/workflows/${encodeURIComponent(id)}`);
|
|
2326
|
+
}
|
|
2327
|
+
/** Turn a workflow off. `POST /api/v2/workflows/:id/disable`. */
|
|
2328
|
+
async disableWorkflow(id) {
|
|
2329
|
+
return this.http.post(
|
|
2330
|
+
`/api/v2/workflows/${encodeURIComponent(id)}/disable`,
|
|
2331
|
+
{}
|
|
2332
|
+
);
|
|
2333
|
+
}
|
|
2334
|
+
/** Turn a workflow back on. `POST /api/v2/workflows/:id/enable`. */
|
|
2335
|
+
async enableWorkflow(id) {
|
|
2336
|
+
return this.http.post(
|
|
2337
|
+
`/api/v2/workflows/${encodeURIComponent(id)}/enable`,
|
|
2338
|
+
{}
|
|
2339
|
+
);
|
|
2340
|
+
}
|
|
2341
|
+
/** Create/update a workflow from config. `POST /api/v2/workflows/apply`. */
|
|
2342
|
+
async applyWorkflow(body) {
|
|
2343
|
+
return this.http.post("/api/v2/workflows/apply", body);
|
|
2344
|
+
}
|
|
2345
|
+
/** Validate a workflow config without saving. `POST /api/v2/workflows/lint`. */
|
|
2346
|
+
async lintWorkflow(body) {
|
|
2347
|
+
return this.http.post("/api/v2/workflows/lint", body);
|
|
2348
|
+
}
|
|
2349
|
+
/** Fetch live workflow request schemas. `GET /api/v2/workflows/schema`. */
|
|
2350
|
+
async getWorkflowSchema(subject) {
|
|
2351
|
+
const params = new URLSearchParams();
|
|
2352
|
+
if (subject) params.set("subject", subject);
|
|
2353
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
2354
|
+
return this.http.get(`/api/v2/workflows/schema${query}`);
|
|
2355
|
+
}
|
|
2356
|
+
/** Queue a workflow run. `POST /api/v2/workflows/call`. */
|
|
2357
|
+
async callWorkflow(body) {
|
|
2358
|
+
return this.http.post("/api/v2/workflows/call", body);
|
|
2359
|
+
}
|
|
2360
|
+
/** List a workflow's runs. `GET /api/v2/workflows/:id/runs`. */
|
|
2361
|
+
async listWorkflowRuns(id, options) {
|
|
2362
|
+
const params = new URLSearchParams();
|
|
2363
|
+
if (typeof options?.limit === "number") {
|
|
2364
|
+
params.set("limit", String(options.limit));
|
|
2365
|
+
}
|
|
2366
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
2367
|
+
return this.http.get(
|
|
2368
|
+
`/api/v2/workflows/${encodeURIComponent(id)}/runs${query}`
|
|
2369
|
+
);
|
|
2370
|
+
}
|
|
2371
|
+
/** Fetch one workflow run. `GET /api/v2/workflows/:id/runs/:runId`. */
|
|
2372
|
+
async getWorkflowRun(id, runId) {
|
|
2373
|
+
return this.http.get(
|
|
2374
|
+
`/api/v2/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(
|
|
2375
|
+
runId
|
|
2376
|
+
)}`
|
|
2377
|
+
);
|
|
2378
|
+
}
|
|
2379
|
+
/** Cancel a workflow run. `POST /api/v2/workflows/:id/runs/:runId/cancel`. */
|
|
2380
|
+
async cancelWorkflowRun(id, runId) {
|
|
2381
|
+
return this.http.post(
|
|
2382
|
+
`/api/v2/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(
|
|
2383
|
+
runId
|
|
2384
|
+
)}/cancel`,
|
|
2385
|
+
{}
|
|
2386
|
+
);
|
|
2387
|
+
}
|
|
2301
2388
|
/**
|
|
2302
2389
|
* Get a run by id using the public runs resource model.
|
|
2303
2390
|
*
|
|
@@ -3185,6 +3272,9 @@ function openInBrowser(url) {
|
|
|
3185
3272
|
} catch {
|
|
3186
3273
|
}
|
|
3187
3274
|
}
|
|
3275
|
+
function sleep3(ms) {
|
|
3276
|
+
return new Promise((resolvePromise) => setTimeout(resolvePromise, ms));
|
|
3277
|
+
}
|
|
3188
3278
|
function collectLocalEnvInfo() {
|
|
3189
3279
|
return {
|
|
3190
3280
|
os: `${process.platform} ${process.arch}`,
|
|
@@ -3222,14 +3312,38 @@ function parseMaybeJsonObject(value) {
|
|
|
3222
3312
|
return value;
|
|
3223
3313
|
}
|
|
3224
3314
|
}
|
|
3315
|
+
function failureMessageFromRecord(value) {
|
|
3316
|
+
const status = typeof value.status === "string" ? value.status.trim().toLowerCase() : "";
|
|
3317
|
+
const directError = typeof value.error === "string" ? value.error.trim() : typeof value.last_error === "string" ? value.last_error.trim() : "";
|
|
3318
|
+
const result = value.result && typeof value.result === "object" && !Array.isArray(value.result) ? value.result : null;
|
|
3319
|
+
const resultError = typeof result?.error === "string" ? result.error.trim() : typeof result?.message === "string" ? result.message.trim() : "";
|
|
3320
|
+
if (!directError && !resultError && status !== "error" && status !== "failed") {
|
|
3321
|
+
return null;
|
|
3322
|
+
}
|
|
3323
|
+
return directError || resultError || `Column status: ${status}`;
|
|
3324
|
+
}
|
|
3225
3325
|
function flattenObjectColumns(row) {
|
|
3226
3326
|
const flattened = {};
|
|
3227
3327
|
for (const [key, rawValue] of Object.entries(row)) {
|
|
3228
3328
|
const value = parseMaybeJsonObject(rawValue);
|
|
3329
|
+
if (key === "_metadata") {
|
|
3330
|
+
flattened[key] = value && typeof value === "object" ? JSON.stringify(value) : value;
|
|
3331
|
+
continue;
|
|
3332
|
+
}
|
|
3229
3333
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
)
|
|
3334
|
+
const record = value;
|
|
3335
|
+
const hasMatchedEnvelope = Object.prototype.hasOwnProperty.call(record, "matched_result") || Object.prototype.hasOwnProperty.call(record, "matchedResult");
|
|
3336
|
+
if (hasMatchedEnvelope) {
|
|
3337
|
+
flattened[key] = JSON.stringify(record);
|
|
3338
|
+
} else {
|
|
3339
|
+
const failureMessage = failureMessageFromRecord(record);
|
|
3340
|
+
if (failureMessage) {
|
|
3341
|
+
flattened[key] = failureMessage;
|
|
3342
|
+
} else if (Object.prototype.hasOwnProperty.call(record, "result")) {
|
|
3343
|
+
flattened[key] = JSON.stringify(record);
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
for (const [nestedKey, nestedValue] of Object.entries(record)) {
|
|
3233
3347
|
flattened[`${key}.${nestedKey}`] = nestedValue && typeof nestedValue === "object" ? JSON.stringify(nestedValue) : nestedValue;
|
|
3234
3348
|
}
|
|
3235
3349
|
continue;
|
|
@@ -3485,8 +3599,8 @@ function buildCandidateUrls2(url) {
|
|
|
3485
3599
|
return [url];
|
|
3486
3600
|
}
|
|
3487
3601
|
}
|
|
3488
|
-
function
|
|
3489
|
-
return new Promise((
|
|
3602
|
+
function sleep4(ms) {
|
|
3603
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
3490
3604
|
}
|
|
3491
3605
|
function printDeeplineLogo() {
|
|
3492
3606
|
if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
|
|
@@ -3589,7 +3703,7 @@ async function handleRegister(args) {
|
|
|
3589
3703
|
return EXIT_AUTH;
|
|
3590
3704
|
}
|
|
3591
3705
|
if (s >= 500 || s === 0 || s === 400) {
|
|
3592
|
-
await
|
|
3706
|
+
await sleep4(2e3);
|
|
3593
3707
|
continue;
|
|
3594
3708
|
}
|
|
3595
3709
|
if (s >= 400) {
|
|
@@ -3619,7 +3733,7 @@ async function handleRegister(args) {
|
|
|
3619
3733
|
);
|
|
3620
3734
|
return EXIT_AUTH;
|
|
3621
3735
|
}
|
|
3622
|
-
await
|
|
3736
|
+
await sleep4(2e3);
|
|
3623
3737
|
}
|
|
3624
3738
|
}
|
|
3625
3739
|
async function handleWait(args) {
|
|
@@ -3656,7 +3770,7 @@ async function handleWait(args) {
|
|
|
3656
3770
|
return EXIT_AUTH;
|
|
3657
3771
|
}
|
|
3658
3772
|
if (status >= 500 || status === 0 || status === 400) {
|
|
3659
|
-
await
|
|
3773
|
+
await sleep4(2e3);
|
|
3660
3774
|
continue;
|
|
3661
3775
|
}
|
|
3662
3776
|
if (status >= 400) {
|
|
@@ -3684,7 +3798,7 @@ async function handleWait(args) {
|
|
|
3684
3798
|
console.error("That approval link expired. Run: deepline auth register");
|
|
3685
3799
|
return EXIT_AUTH;
|
|
3686
3800
|
}
|
|
3687
|
-
await
|
|
3801
|
+
await sleep4(2e3);
|
|
3688
3802
|
}
|
|
3689
3803
|
console.error(
|
|
3690
3804
|
"Still pending. Approve the browser link, then run: deepline auth wait"
|
|
@@ -4500,6 +4614,9 @@ function isRecord3(value) {
|
|
|
4500
4614
|
function isSerializedDataset(value) {
|
|
4501
4615
|
return isRecord3(value) && value.kind === "dataset" && typeof value.count === "number" && Array.isArray(value.preview);
|
|
4502
4616
|
}
|
|
4617
|
+
function isPackagedDatasetOutput(value) {
|
|
4618
|
+
return isRecord3(value) && value.kind === "dataset" && isRecord3(value.preview) && Array.isArray(value.preview.rows);
|
|
4619
|
+
}
|
|
4503
4620
|
function pathParts(path) {
|
|
4504
4621
|
return path.split(".").map((part) => part.trim()).filter(Boolean);
|
|
4505
4622
|
}
|
|
@@ -4547,6 +4664,12 @@ function inferColumns(rows) {
|
|
|
4547
4664
|
}
|
|
4548
4665
|
return columns;
|
|
4549
4666
|
}
|
|
4667
|
+
function columnsFromDatasetSummary(summary) {
|
|
4668
|
+
if (!isRecord3(summary) || !isRecord3(summary.columnStats)) {
|
|
4669
|
+
return [];
|
|
4670
|
+
}
|
|
4671
|
+
return Object.keys(summary.columnStats).filter((column) => column);
|
|
4672
|
+
}
|
|
4550
4673
|
function canonicalRowsInfoFromCandidate(input2) {
|
|
4551
4674
|
const candidate = input2;
|
|
4552
4675
|
if (isSerializedDataset(candidate.value)) {
|
|
@@ -4569,6 +4692,28 @@ function canonicalRowsInfoFromCandidate(input2) {
|
|
|
4569
4692
|
tableNamespace: typeof candidate.value.tableNamespace === "string" ? candidate.value.tableNamespace : null
|
|
4570
4693
|
};
|
|
4571
4694
|
}
|
|
4695
|
+
if (isPackagedDatasetOutput(candidate.value)) {
|
|
4696
|
+
const rawRows = rowArray(candidate.value.preview?.rows) ?? [];
|
|
4697
|
+
const totalRows2 = readNumber(candidate.value.preview?.totalRows) ?? readNumber(candidate.value.rowCount) ?? rawRows.length;
|
|
4698
|
+
const explicitColumns = Array.isArray(candidate.value.columns) ? candidate.value.columns.filter(
|
|
4699
|
+
(column) => typeof column === "string"
|
|
4700
|
+
) : [];
|
|
4701
|
+
const rawColumns = explicitColumns.length > 0 ? explicitColumns : columnsFromDatasetSummary(candidate.value.summary);
|
|
4702
|
+
const { rows: rows2, columns } = sanitizeCsvProjectionInfo({
|
|
4703
|
+
rows: rawRows,
|
|
4704
|
+
columns: rawColumns.length > 0 ? rawColumns : inferColumns(rawRows)
|
|
4705
|
+
});
|
|
4706
|
+
return {
|
|
4707
|
+
rows: rows2,
|
|
4708
|
+
totalRows: totalRows2,
|
|
4709
|
+
columns,
|
|
4710
|
+
columnsExplicit: rawColumns.length > 0,
|
|
4711
|
+
complete: rows2.length === totalRows2,
|
|
4712
|
+
source: candidate.source,
|
|
4713
|
+
datasetId: typeof candidate.value.datasetId === "string" ? candidate.value.datasetId : null,
|
|
4714
|
+
tableNamespace: typeof candidate.value.tableNamespace === "string" ? candidate.value.tableNamespace : null
|
|
4715
|
+
};
|
|
4716
|
+
}
|
|
4572
4717
|
if (candidate.serializedOnly) {
|
|
4573
4718
|
return null;
|
|
4574
4719
|
}
|
|
@@ -4601,6 +4746,14 @@ function collectDatasetCandidates(input2) {
|
|
|
4601
4746
|
});
|
|
4602
4747
|
return;
|
|
4603
4748
|
}
|
|
4749
|
+
if (isPackagedDatasetOutput(input2.value)) {
|
|
4750
|
+
input2.output.push({
|
|
4751
|
+
source: input2.path,
|
|
4752
|
+
value: input2.value,
|
|
4753
|
+
total: input2.total
|
|
4754
|
+
});
|
|
4755
|
+
return;
|
|
4756
|
+
}
|
|
4604
4757
|
if (!isRecord3(input2.value)) {
|
|
4605
4758
|
return;
|
|
4606
4759
|
}
|
|
@@ -4673,6 +4826,19 @@ function collectCanonicalRowsInfos(statusOrResult) {
|
|
|
4673
4826
|
}
|
|
4674
4827
|
);
|
|
4675
4828
|
}
|
|
4829
|
+
if (Array.isArray(result.steps)) {
|
|
4830
|
+
result.steps.forEach((step, index) => {
|
|
4831
|
+
if (!isRecord3(step) || !isRecord3(step.output)) {
|
|
4832
|
+
return;
|
|
4833
|
+
}
|
|
4834
|
+
const source = typeof step.output.path === "string" ? step.output.path : typeof step.id === "string" ? `steps.${step.id}.output` : `steps.${index}.output`;
|
|
4835
|
+
candidates.push({
|
|
4836
|
+
source,
|
|
4837
|
+
value: step.output,
|
|
4838
|
+
total: step.output.rowCount ?? (isRecord3(step.output.preview) ? step.output.preview.totalRows : void 0) ?? (isRecord3(step.progress) ? step.progress.total : void 0)
|
|
4839
|
+
});
|
|
4840
|
+
});
|
|
4841
|
+
}
|
|
4676
4842
|
collectDatasetCandidates({
|
|
4677
4843
|
value: result,
|
|
4678
4844
|
path: "result",
|
|
@@ -4682,12 +4848,14 @@ function collectCanonicalRowsInfos(statusOrResult) {
|
|
|
4682
4848
|
const seen = /* @__PURE__ */ new Set();
|
|
4683
4849
|
const infos = [];
|
|
4684
4850
|
for (const candidate of candidates) {
|
|
4685
|
-
if (seen.has(candidate.source)) {
|
|
4686
|
-
continue;
|
|
4687
|
-
}
|
|
4688
|
-
seen.add(candidate.source);
|
|
4689
4851
|
const info = canonicalRowsInfoFromCandidate(candidate);
|
|
4690
4852
|
if (info) {
|
|
4853
|
+
if (info.source) {
|
|
4854
|
+
if (seen.has(info.source)) {
|
|
4855
|
+
continue;
|
|
4856
|
+
}
|
|
4857
|
+
seen.add(info.source);
|
|
4858
|
+
}
|
|
4691
4859
|
infos.push(info);
|
|
4692
4860
|
}
|
|
4693
4861
|
}
|
|
@@ -4708,15 +4876,17 @@ function collectSerializedDatasetRowsInfos(statusOrResult) {
|
|
|
4708
4876
|
const seen = /* @__PURE__ */ new Set();
|
|
4709
4877
|
const infos = [];
|
|
4710
4878
|
for (const candidate of candidates) {
|
|
4711
|
-
if (seen.has(candidate.source)) {
|
|
4712
|
-
continue;
|
|
4713
|
-
}
|
|
4714
|
-
seen.add(candidate.source);
|
|
4715
4879
|
const info = canonicalRowsInfoFromCandidate({
|
|
4716
4880
|
...candidate,
|
|
4717
4881
|
serializedOnly: true
|
|
4718
4882
|
});
|
|
4719
4883
|
if (info) {
|
|
4884
|
+
if (info.source) {
|
|
4885
|
+
if (seen.has(info.source)) {
|
|
4886
|
+
continue;
|
|
4887
|
+
}
|
|
4888
|
+
seen.add(info.source);
|
|
4889
|
+
}
|
|
4720
4890
|
infos.push(info);
|
|
4721
4891
|
}
|
|
4722
4892
|
}
|
|
@@ -5226,10 +5396,10 @@ async function handleDbQuery(args) {
|
|
|
5226
5396
|
}
|
|
5227
5397
|
const jsonOutput = argsWantJson(args);
|
|
5228
5398
|
const explicitJsonOutput = args.includes("--json");
|
|
5229
|
-
const
|
|
5399
|
+
const client2 = new DeeplineClient();
|
|
5230
5400
|
let result;
|
|
5231
5401
|
try {
|
|
5232
|
-
result = await
|
|
5402
|
+
result = await client2.queryCustomerDb({ sql, maxRows });
|
|
5233
5403
|
} catch (error) {
|
|
5234
5404
|
console.error(formatDbQueryError(sql, error));
|
|
5235
5405
|
return 1;
|
|
@@ -5472,23 +5642,28 @@ function shannonEntropy(value) {
|
|
|
5472
5642
|
return entropy - p * Math.log2(p);
|
|
5473
5643
|
}, 0);
|
|
5474
5644
|
}
|
|
5475
|
-
function
|
|
5645
|
+
function collectInlineSecretFindings(sourceCode) {
|
|
5476
5646
|
const findings = [];
|
|
5477
|
-
for (const match of
|
|
5647
|
+
for (const match of sourceCode.matchAll(SECRET_ENV_PATTERN)) {
|
|
5478
5648
|
findings.push(`process.env.${match[1]}`);
|
|
5479
5649
|
}
|
|
5480
|
-
if (PRIVATE_KEY_PATTERN.test(
|
|
5481
|
-
if (BEARER_LITERAL_PATTERN.test(
|
|
5482
|
-
|
|
5650
|
+
if (PRIVATE_KEY_PATTERN.test(sourceCode)) findings.push("private key block");
|
|
5651
|
+
if (BEARER_LITERAL_PATTERN.test(sourceCode))
|
|
5652
|
+
findings.push("bearer token literal");
|
|
5653
|
+
if (ASSIGNMENT_SECRET_LITERAL_PATTERN.test(sourceCode)) {
|
|
5483
5654
|
findings.push("secret-looking assignment literal");
|
|
5484
5655
|
}
|
|
5485
|
-
for (const match of
|
|
5656
|
+
for (const match of sourceCode.matchAll(HIGH_ENTROPY_LITERAL_PATTERN)) {
|
|
5486
5657
|
const literal = match[1] ?? "";
|
|
5487
5658
|
if (literal.length >= 40 && shannonEntropy(literal) >= 4.2) {
|
|
5488
5659
|
findings.push("high-entropy string literal");
|
|
5489
5660
|
break;
|
|
5490
5661
|
}
|
|
5491
5662
|
}
|
|
5663
|
+
return [...new Set(findings)];
|
|
5664
|
+
}
|
|
5665
|
+
function validatePlaySourceHasNoInlineSecrets(input2) {
|
|
5666
|
+
const findings = collectInlineSecretFindings(input2.sourceCode);
|
|
5492
5667
|
if (!findings.length) return;
|
|
5493
5668
|
throw new Error(
|
|
5494
5669
|
[
|
|
@@ -8429,13 +8604,13 @@ export default definePlay(${jsString(input2.options.name)}, async (ctx, input: I
|
|
|
8429
8604
|
|
|
8430
8605
|
`;
|
|
8431
8606
|
}
|
|
8432
|
-
async function describePlayMaybe(
|
|
8433
|
-
return playRef ?
|
|
8607
|
+
async function describePlayMaybe(client2, playRef) {
|
|
8608
|
+
return playRef ? client2.describePlay(playRef, { compact: true }) : null;
|
|
8434
8609
|
}
|
|
8435
|
-
function loadTools(
|
|
8436
|
-
return Promise.all(providers.map((provider) =>
|
|
8610
|
+
function loadTools(client2, providers) {
|
|
8611
|
+
return Promise.all(providers.map((provider) => client2.getTool(provider)));
|
|
8437
8612
|
}
|
|
8438
|
-
async function loadBootstrapContracts(
|
|
8613
|
+
async function loadBootstrapContracts(client2, options) {
|
|
8439
8614
|
const [
|
|
8440
8615
|
sourceTools,
|
|
8441
8616
|
sourcePlay,
|
|
@@ -8445,13 +8620,13 @@ async function loadBootstrapContracts(client, options) {
|
|
|
8445
8620
|
emailTools,
|
|
8446
8621
|
phoneTools
|
|
8447
8622
|
] = await Promise.all([
|
|
8448
|
-
loadTools(
|
|
8449
|
-
describePlayMaybe(
|
|
8450
|
-
describePlayMaybe(
|
|
8451
|
-
describePlayMaybe(
|
|
8452
|
-
describePlayMaybe(
|
|
8453
|
-
loadTools(
|
|
8454
|
-
loadTools(
|
|
8623
|
+
loadTools(client2, sourceProviders(options)),
|
|
8624
|
+
describePlayMaybe(client2, sourcePlayRef(options)),
|
|
8625
|
+
describePlayMaybe(client2, stagePlayRef(options.people)),
|
|
8626
|
+
describePlayMaybe(client2, stagePlayRef(options.email)),
|
|
8627
|
+
describePlayMaybe(client2, stagePlayRef(options.phone)),
|
|
8628
|
+
loadTools(client2, stageProviders(options.email)),
|
|
8629
|
+
loadTools(client2, stageProviders(options.phone))
|
|
8455
8630
|
]);
|
|
8456
8631
|
const contracts = {
|
|
8457
8632
|
sourceTools,
|
|
@@ -8500,8 +8675,8 @@ function renderPlayBootstrapError(error) {
|
|
|
8500
8675
|
}
|
|
8501
8676
|
async function runPlayBootstrap(args) {
|
|
8502
8677
|
const options = parsePlayBootstrapOptions(args);
|
|
8503
|
-
const
|
|
8504
|
-
const contracts = await loadBootstrapContracts(
|
|
8678
|
+
const client2 = new DeeplineClient();
|
|
8679
|
+
const contracts = await loadBootstrapContracts(client2, options);
|
|
8505
8680
|
const csvContext = loadCsvContext(options.from);
|
|
8506
8681
|
const source = generateBootstrapPlaySource({
|
|
8507
8682
|
options,
|
|
@@ -8907,8 +9082,8 @@ function traceCliSync(phase, fields, run) {
|
|
|
8907
9082
|
throw error;
|
|
8908
9083
|
}
|
|
8909
9084
|
}
|
|
8910
|
-
function
|
|
8911
|
-
return new Promise((
|
|
9085
|
+
function sleep5(ms) {
|
|
9086
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
8912
9087
|
}
|
|
8913
9088
|
function parseReferencedPlayTarget2(target) {
|
|
8914
9089
|
const trimmed = target.trim();
|
|
@@ -8930,9 +9105,9 @@ function buildBarePrebuiltReferenceError(input2) {
|
|
|
8930
9105
|
`Prebuilt play "${input2.requested}" must be referenced as "${input2.reference}". Use the prebuilt/ namespace anywhere you run, describe, get, or link to Deepline-managed plays.`
|
|
8931
9106
|
);
|
|
8932
9107
|
}
|
|
8933
|
-
async function assertCanonicalNamedPlayReference(
|
|
9108
|
+
async function assertCanonicalNamedPlayReference(client2, target) {
|
|
8934
9109
|
const parsed = parseReferencedPlayTarget2(target);
|
|
8935
|
-
const detail = await
|
|
9110
|
+
const detail = await client2.getPlay(parsed.playName);
|
|
8936
9111
|
if (detail.play.ownerType === "deepline" && !isPrebuiltReferenceTarget(target)) {
|
|
8937
9112
|
throw buildBarePrebuiltReferenceError({
|
|
8938
9113
|
requested: target,
|
|
@@ -9010,9 +9185,9 @@ To make your own version:
|
|
|
9010
9185
|
5. Your play will then live under your workspace namespace.`
|
|
9011
9186
|
);
|
|
9012
9187
|
}
|
|
9013
|
-
async function ensureEditableRemotePlay(
|
|
9188
|
+
async function ensureEditableRemotePlay(client2, target) {
|
|
9014
9189
|
const parsed = parseReferencedPlayTarget2(target);
|
|
9015
|
-
const detail = await
|
|
9190
|
+
const detail = await client2.getPlay(parsed.playName);
|
|
9016
9191
|
if (detail.play.ownerType === "deepline") {
|
|
9017
9192
|
throw buildReadonlyPrebuiltPlayError(formatPlayReference(detail.play));
|
|
9018
9193
|
}
|
|
@@ -9291,7 +9466,7 @@ async function collectBundledPlayGraph(entryFile, profile = null) {
|
|
|
9291
9466
|
const root = await visit(entryFile);
|
|
9292
9467
|
return { root, nodes };
|
|
9293
9468
|
}
|
|
9294
|
-
async function compileBundledPlayGraphManifests(
|
|
9469
|
+
async function compileBundledPlayGraphManifests(client2, graph) {
|
|
9295
9470
|
const compiling = /* @__PURE__ */ new Map();
|
|
9296
9471
|
const compileNode = (node) => {
|
|
9297
9472
|
const existing = compiling.get(node.filePath);
|
|
@@ -9307,7 +9482,7 @@ async function compileBundledPlayGraphManifests(client, graph) {
|
|
|
9307
9482
|
await compileNode(child);
|
|
9308
9483
|
}
|
|
9309
9484
|
const name = node.playName ?? extractPlayName(node.sourceCode, node.filePath);
|
|
9310
|
-
node.compilerManifest = await
|
|
9485
|
+
node.compilerManifest = await client2.compilePlayManifest({
|
|
9311
9486
|
name,
|
|
9312
9487
|
sourceCode: node.sourceCode,
|
|
9313
9488
|
sourceFiles: node.sourceFiles,
|
|
@@ -9341,7 +9516,7 @@ function requireCompilerManifest(node) {
|
|
|
9341
9516
|
}
|
|
9342
9517
|
return node.compilerManifest;
|
|
9343
9518
|
}
|
|
9344
|
-
async function publishImportedPlayDependencies(
|
|
9519
|
+
async function publishImportedPlayDependencies(client2, graph) {
|
|
9345
9520
|
const published = /* @__PURE__ */ new Set();
|
|
9346
9521
|
const publishNode = async (filePath, skipPublish) => {
|
|
9347
9522
|
const absolutePath = normalizePlayPath(filePath);
|
|
@@ -9360,7 +9535,7 @@ async function publishImportedPlayDependencies(client, graph) {
|
|
|
9360
9535
|
`Imported play ${absolutePath} must export definePlay(...) so it can be published for runtime composition.`
|
|
9361
9536
|
);
|
|
9362
9537
|
}
|
|
9363
|
-
await
|
|
9538
|
+
await client2.registerPlayArtifact({
|
|
9364
9539
|
name: node.playName,
|
|
9365
9540
|
sourceCode: node.sourceCode,
|
|
9366
9541
|
sourceFiles: node.sourceFiles,
|
|
@@ -9936,7 +10111,7 @@ async function waitForPlayCompletionByStream(input2) {
|
|
|
9936
10111
|
reason
|
|
9937
10112
|
});
|
|
9938
10113
|
const remainingBeforeSleep = remainingWaitMs();
|
|
9939
|
-
await
|
|
10114
|
+
await sleep5(
|
|
9940
10115
|
remainingBeforeSleep === null ? delayMs : Math.min(delayMs, Math.max(1, remainingBeforeSleep))
|
|
9941
10116
|
);
|
|
9942
10117
|
}
|
|
@@ -9961,7 +10136,7 @@ async function startAndWaitForPlayCompletionByStream(input2) {
|
|
|
9961
10136
|
attempt: attempt + 1,
|
|
9962
10137
|
reason: playStatusErrorText(status)
|
|
9963
10138
|
});
|
|
9964
|
-
await
|
|
10139
|
+
await sleep5(retryDelayMs);
|
|
9965
10140
|
}
|
|
9966
10141
|
throw new DeeplineError(
|
|
9967
10142
|
`Play ${input2.playName} did not start after retrying transient start failures.`,
|
|
@@ -11010,7 +11185,7 @@ async function resolvePlayRunOutputStatus(input2) {
|
|
|
11010
11185
|
full: input2.fullJson
|
|
11011
11186
|
});
|
|
11012
11187
|
for (let attempt = 0; attempt < 3 && streamedTextPackageIncomplete && refreshedStatus.status === "completed" && playRunPackageStepCount(getPlayRunPackage(refreshedStatus)) === 0; attempt += 1) {
|
|
11013
|
-
await
|
|
11188
|
+
await sleep5(250);
|
|
11014
11189
|
refreshedStatus = await input2.client.getPlayStatus(runId, {
|
|
11015
11190
|
billing: false,
|
|
11016
11191
|
full: input2.fullJson
|
|
@@ -11133,7 +11308,7 @@ async function fetchBackingDatasetRows(input2) {
|
|
|
11133
11308
|
source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
|
|
11134
11309
|
};
|
|
11135
11310
|
}
|
|
11136
|
-
async function exportPlayStatusRows(
|
|
11311
|
+
async function exportPlayStatusRows(client2, status, outPath, options = {}) {
|
|
11137
11312
|
if (!outPath) {
|
|
11138
11313
|
return null;
|
|
11139
11314
|
}
|
|
@@ -11168,7 +11343,7 @@ async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
|
11168
11343
|
let fetchedRowsInfo = null;
|
|
11169
11344
|
try {
|
|
11170
11345
|
fetchedRowsInfo = await fetchBackingDatasetRows({
|
|
11171
|
-
client,
|
|
11346
|
+
client: client2,
|
|
11172
11347
|
status,
|
|
11173
11348
|
rowsInfo
|
|
11174
11349
|
});
|
|
@@ -11187,7 +11362,7 @@ async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
|
11187
11362
|
return { path: writeCanonicalRowsCsv(rowsInfo, outPath), rowsInfo };
|
|
11188
11363
|
}
|
|
11189
11364
|
if (attempt < attempts && retryDelayMs > 0) {
|
|
11190
|
-
await
|
|
11365
|
+
await sleep5(retryDelayMs);
|
|
11191
11366
|
}
|
|
11192
11367
|
}
|
|
11193
11368
|
if (!rowsInfo.complete) {
|
|
@@ -11705,12 +11880,12 @@ function toolGetterHintFromMetadata(toolId, tool) {
|
|
|
11705
11880
|
raw: checkHintExpression(toolResponse.raw) || "result.toolResponse.raw"
|
|
11706
11881
|
};
|
|
11707
11882
|
}
|
|
11708
|
-
async function buildToolGetterHints(
|
|
11883
|
+
async function buildToolGetterHints(client2, staticPipeline) {
|
|
11709
11884
|
const toolIds = collectStaticPipelineToolIds(staticPipeline);
|
|
11710
11885
|
return Promise.all(
|
|
11711
11886
|
toolIds.map(async (toolId) => {
|
|
11712
11887
|
try {
|
|
11713
|
-
const tool = await
|
|
11888
|
+
const tool = await client2.getTool(toolId);
|
|
11714
11889
|
return toolGetterHintFromMetadata(toolId, tool);
|
|
11715
11890
|
} catch (error) {
|
|
11716
11891
|
return {
|
|
@@ -11750,10 +11925,10 @@ function printToolGetterHints(hints) {
|
|
|
11750
11925
|
async function handlePlayCheck(args) {
|
|
11751
11926
|
const options = parsePlayCheckOptions(args);
|
|
11752
11927
|
if (!isFileTarget(options.target)) {
|
|
11753
|
-
const
|
|
11928
|
+
const client3 = new DeeplineClient();
|
|
11754
11929
|
try {
|
|
11755
|
-
await assertCanonicalNamedPlayReference(
|
|
11756
|
-
const play = await
|
|
11930
|
+
await assertCanonicalNamedPlayReference(client3, options.target);
|
|
11931
|
+
const play = await client3.describePlay(
|
|
11757
11932
|
parseReferencedPlayTarget2(options.target).playName,
|
|
11758
11933
|
{ compact: true }
|
|
11759
11934
|
);
|
|
@@ -11835,8 +12010,8 @@ async function handlePlayCheck(args) {
|
|
|
11835
12010
|
}
|
|
11836
12011
|
return 0;
|
|
11837
12012
|
}
|
|
11838
|
-
const
|
|
11839
|
-
const result = await
|
|
12013
|
+
const client2 = new DeeplineClient();
|
|
12014
|
+
const result = await client2.checkPlayArtifact({
|
|
11840
12015
|
name: playName,
|
|
11841
12016
|
sourceCode: graph.root.sourceCode,
|
|
11842
12017
|
sourceFiles: graph.root.sourceFiles,
|
|
@@ -11848,7 +12023,7 @@ async function handlePlayCheck(args) {
|
|
|
11848
12023
|
errors: result.errors,
|
|
11849
12024
|
sourceCode: graph.root.sourceCode
|
|
11850
12025
|
}),
|
|
11851
|
-
toolGetterHints: result.toolGetterHints ?? await buildToolGetterHints(
|
|
12026
|
+
toolGetterHints: result.toolGetterHints ?? await buildToolGetterHints(client2, result.staticPipeline)
|
|
11852
12027
|
};
|
|
11853
12028
|
if (options.jsonOutput) {
|
|
11854
12029
|
process.stdout.write(
|
|
@@ -11874,7 +12049,7 @@ async function handleFileBackedRun(options) {
|
|
|
11874
12049
|
if (options.target.kind !== "file") {
|
|
11875
12050
|
throw new Error("Expected a file-backed play run target.");
|
|
11876
12051
|
}
|
|
11877
|
-
const
|
|
12052
|
+
const client2 = new DeeplineClient();
|
|
11878
12053
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
11879
12054
|
const absolutePlayPath = (0, import_node_path12.resolve)(options.target.path);
|
|
11880
12055
|
progress.phase("compiling play");
|
|
@@ -11894,7 +12069,7 @@ async function handleFileBackedRun(options) {
|
|
|
11894
12069
|
await traceCliSpan(
|
|
11895
12070
|
"cli.play_file_compile_manifests",
|
|
11896
12071
|
{ targetKind: "file" },
|
|
11897
|
-
() => compileBundledPlayGraphManifests(
|
|
12072
|
+
() => compileBundledPlayGraphManifests(client2, graph)
|
|
11898
12073
|
);
|
|
11899
12074
|
progress.phase("compiled play");
|
|
11900
12075
|
} catch (error) {
|
|
@@ -11912,7 +12087,7 @@ async function handleFileBackedRun(options) {
|
|
|
11912
12087
|
await traceCliSpan(
|
|
11913
12088
|
"cli.play_file_publish_imports",
|
|
11914
12089
|
{ targetKind: "file" },
|
|
11915
|
-
() => publishImportedPlayDependencies(
|
|
12090
|
+
() => publishImportedPlayDependencies(client2, graph)
|
|
11916
12091
|
);
|
|
11917
12092
|
} catch (error) {
|
|
11918
12093
|
progress.fail();
|
|
@@ -11933,7 +12108,7 @@ async function handleFileBackedRun(options) {
|
|
|
11933
12108
|
bindingCount: fileInputBindings.length
|
|
11934
12109
|
},
|
|
11935
12110
|
() => stageFileInputArgs({
|
|
11936
|
-
client,
|
|
12111
|
+
client: client2,
|
|
11937
12112
|
runtimeInput,
|
|
11938
12113
|
bindings: fileInputBindings,
|
|
11939
12114
|
progress
|
|
@@ -11958,7 +12133,7 @@ async function handleFileBackedRun(options) {
|
|
|
11958
12133
|
"cli.play_start_watch",
|
|
11959
12134
|
{ targetKind: "file", playName },
|
|
11960
12135
|
() => startAndWaitForPlayCompletionByStream({
|
|
11961
|
-
client,
|
|
12136
|
+
client: client2,
|
|
11962
12137
|
request: startRequest,
|
|
11963
12138
|
playName,
|
|
11964
12139
|
jsonOutput: options.jsonOutput,
|
|
@@ -11977,7 +12152,7 @@ async function handleFileBackedRun(options) {
|
|
|
11977
12152
|
}
|
|
11978
12153
|
const outputStatus = withTerminalPlayIdentity(
|
|
11979
12154
|
await resolvePlayRunOutputStatus({
|
|
11980
|
-
client,
|
|
12155
|
+
client: client2,
|
|
11981
12156
|
status: finalStatus,
|
|
11982
12157
|
fullJson: options.fullJson,
|
|
11983
12158
|
jsonOutput: options.jsonOutput
|
|
@@ -11997,11 +12172,11 @@ async function handleFileBackedRun(options) {
|
|
|
11997
12172
|
const started = await traceCliSpan(
|
|
11998
12173
|
"cli.play_start_unwatched",
|
|
11999
12174
|
{ targetKind: "file", playName },
|
|
12000
|
-
() =>
|
|
12175
|
+
() => client2.startPlayRun(startRequest).catch((error) => {
|
|
12001
12176
|
throw normalizePlayStartError(error, playName);
|
|
12002
12177
|
})
|
|
12003
12178
|
);
|
|
12004
|
-
const resolvedDashboardUrl = buildPlayDashboardUrl(
|
|
12179
|
+
const resolvedDashboardUrl = buildPlayDashboardUrl(client2.baseUrl, playName);
|
|
12005
12180
|
openPlayDashboard({
|
|
12006
12181
|
dashboardUrl: resolvedDashboardUrl,
|
|
12007
12182
|
noOpen: options.noOpen
|
|
@@ -12037,7 +12212,7 @@ async function handleNamedRun(options) {
|
|
|
12037
12212
|
if (options.target.kind !== "name") {
|
|
12038
12213
|
throw new Error("Expected a named play run target.");
|
|
12039
12214
|
}
|
|
12040
|
-
const
|
|
12215
|
+
const client2 = new DeeplineClient();
|
|
12041
12216
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
12042
12217
|
const playName = options.target.name;
|
|
12043
12218
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
@@ -12050,7 +12225,7 @@ async function handleNamedRun(options) {
|
|
|
12050
12225
|
return traceCliSpan(
|
|
12051
12226
|
"cli.play_load_definition",
|
|
12052
12227
|
{ targetKind: "name", playName, skipped: false },
|
|
12053
|
-
() => assertCanonicalNamedPlayReference(
|
|
12228
|
+
() => assertCanonicalNamedPlayReference(client2, playName)
|
|
12054
12229
|
);
|
|
12055
12230
|
})() : (recordCliTrace({
|
|
12056
12231
|
phase: "cli.play_load_definition",
|
|
@@ -12070,7 +12245,7 @@ async function handleNamedRun(options) {
|
|
|
12070
12245
|
hasExplicitRevisionId: Boolean(options.revisionId)
|
|
12071
12246
|
},
|
|
12072
12247
|
() => resolveNamedRunRevisionId({
|
|
12073
|
-
client,
|
|
12248
|
+
client: client2,
|
|
12074
12249
|
playName,
|
|
12075
12250
|
revisionId: options.revisionId,
|
|
12076
12251
|
selector: options.revisionSelector
|
|
@@ -12088,7 +12263,7 @@ async function handleNamedRun(options) {
|
|
|
12088
12263
|
bindingCount: fileInputBindings.length
|
|
12089
12264
|
},
|
|
12090
12265
|
() => stageFileInputArgs({
|
|
12091
|
-
client,
|
|
12266
|
+
client: client2,
|
|
12092
12267
|
runtimeInput,
|
|
12093
12268
|
bindings: fileInputBindings,
|
|
12094
12269
|
progress
|
|
@@ -12109,7 +12284,7 @@ async function handleNamedRun(options) {
|
|
|
12109
12284
|
"cli.play_start_watch",
|
|
12110
12285
|
{ targetKind: "name", playName },
|
|
12111
12286
|
() => startAndWaitForPlayCompletionByStream({
|
|
12112
|
-
client,
|
|
12287
|
+
client: client2,
|
|
12113
12288
|
request: startRequest,
|
|
12114
12289
|
playName,
|
|
12115
12290
|
jsonOutput: options.jsonOutput,
|
|
@@ -12128,7 +12303,7 @@ async function handleNamedRun(options) {
|
|
|
12128
12303
|
}
|
|
12129
12304
|
const outputStatus = withTerminalPlayIdentity(
|
|
12130
12305
|
await resolvePlayRunOutputStatus({
|
|
12131
|
-
client,
|
|
12306
|
+
client: client2,
|
|
12132
12307
|
status: finalStatus,
|
|
12133
12308
|
fullJson: options.fullJson,
|
|
12134
12309
|
jsonOutput: options.jsonOutput
|
|
@@ -12148,11 +12323,11 @@ async function handleNamedRun(options) {
|
|
|
12148
12323
|
const started = await traceCliSpan(
|
|
12149
12324
|
"cli.play_start_unwatched",
|
|
12150
12325
|
{ targetKind: "name", playName },
|
|
12151
|
-
() =>
|
|
12326
|
+
() => client2.startPlayRun(startRequest).catch((error) => {
|
|
12152
12327
|
throw normalizePlayStartError(error, playName);
|
|
12153
12328
|
})
|
|
12154
12329
|
);
|
|
12155
|
-
const resolvedDashboardUrl = buildPlayDashboardUrl(
|
|
12330
|
+
const resolvedDashboardUrl = buildPlayDashboardUrl(client2.baseUrl, playName);
|
|
12156
12331
|
openPlayDashboard({
|
|
12157
12332
|
dashboardUrl: resolvedDashboardUrl,
|
|
12158
12333
|
noOpen: options.noOpen
|
|
@@ -12226,8 +12401,8 @@ async function handleRunGet(args) {
|
|
|
12226
12401
|
console.error(error instanceof Error ? error.message : usage);
|
|
12227
12402
|
return 1;
|
|
12228
12403
|
}
|
|
12229
|
-
const
|
|
12230
|
-
const status = await
|
|
12404
|
+
const client2 = new DeeplineClient();
|
|
12405
|
+
const status = await client2.runs.get(runId, {
|
|
12231
12406
|
full: args.includes("--full")
|
|
12232
12407
|
});
|
|
12233
12408
|
writePlayResult(status, argsWantJson(args), {
|
|
@@ -12257,8 +12432,8 @@ async function handleRunsList(args) {
|
|
|
12257
12432
|
console.error(usage);
|
|
12258
12433
|
return 1;
|
|
12259
12434
|
}
|
|
12260
|
-
const
|
|
12261
|
-
const runs = (await
|
|
12435
|
+
const client2 = new DeeplineClient();
|
|
12436
|
+
const runs = (await client2.runs.list({
|
|
12262
12437
|
play: playName,
|
|
12263
12438
|
...statusFilter ? { status: statusFilter } : {}
|
|
12264
12439
|
})).map((run) => ({
|
|
@@ -12311,9 +12486,9 @@ async function handleRunTail(args) {
|
|
|
12311
12486
|
return 1;
|
|
12312
12487
|
}
|
|
12313
12488
|
}
|
|
12314
|
-
const
|
|
12489
|
+
const client2 = new DeeplineClient();
|
|
12315
12490
|
const jsonOutput = argsWantJson(args);
|
|
12316
|
-
const status = await
|
|
12491
|
+
const status = await client2.runs.tail(runId, {
|
|
12317
12492
|
// Human mode only: in --json mode emit nothing non-protocol.
|
|
12318
12493
|
onReconnect: jsonOutput ? void 0 : ({ reason }) => {
|
|
12319
12494
|
process.stderr.write(
|
|
@@ -12346,9 +12521,9 @@ async function handleRunLogs(args) {
|
|
|
12346
12521
|
outPath = (0, import_node_path12.resolve)(args[++index]);
|
|
12347
12522
|
}
|
|
12348
12523
|
}
|
|
12349
|
-
const
|
|
12524
|
+
const client2 = new DeeplineClient();
|
|
12350
12525
|
if (outPath) {
|
|
12351
|
-
const result2 = await
|
|
12526
|
+
const result2 = await client2.runs.logs(runId, { all: true });
|
|
12352
12527
|
const logs = result2.entries;
|
|
12353
12528
|
(0, import_node_fs10.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
12354
12529
|
printCommandEnvelope(
|
|
@@ -12377,7 +12552,7 @@ async function handleRunLogs(args) {
|
|
|
12377
12552
|
);
|
|
12378
12553
|
return 0;
|
|
12379
12554
|
}
|
|
12380
|
-
const result = await
|
|
12555
|
+
const result = await client2.runs.logs(runId, { limit });
|
|
12381
12556
|
printCommandEnvelope(
|
|
12382
12557
|
{
|
|
12383
12558
|
runId: result.runId,
|
|
@@ -12417,8 +12592,8 @@ async function handleRunStop(args) {
|
|
|
12417
12592
|
reason = args[++index];
|
|
12418
12593
|
}
|
|
12419
12594
|
}
|
|
12420
|
-
const
|
|
12421
|
-
const result = await
|
|
12595
|
+
const client2 = new DeeplineClient();
|
|
12596
|
+
const result = await client2.runs.stop(runId, { reason });
|
|
12422
12597
|
const stopNotConfirmed = result.stopped === false || result.staleSchedulerState === true;
|
|
12423
12598
|
if (stopNotConfirmed) {
|
|
12424
12599
|
const detail = typeof result.error === "string" && result.error.trim() ? result.error.trim() : result.staleSchedulerState === true ? "scheduler state for the run is stale" : "the server did not confirm the stop";
|
|
@@ -12490,9 +12665,9 @@ async function handleRunExport(args) {
|
|
|
12490
12665
|
console.error(usage);
|
|
12491
12666
|
return 1;
|
|
12492
12667
|
}
|
|
12493
|
-
const
|
|
12494
|
-
const status = await
|
|
12495
|
-
const exportResult = await exportPlayStatusRows(
|
|
12668
|
+
const client2 = new DeeplineClient();
|
|
12669
|
+
const status = await client2.getPlayStatus(runId, { full: true });
|
|
12670
|
+
const exportResult = await exportPlayStatusRows(client2, status, outPath, {
|
|
12496
12671
|
datasetPath
|
|
12497
12672
|
});
|
|
12498
12673
|
const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
|
|
@@ -12545,7 +12720,7 @@ async function handlePlayGet(args) {
|
|
|
12545
12720
|
);
|
|
12546
12721
|
return 2;
|
|
12547
12722
|
}
|
|
12548
|
-
const
|
|
12723
|
+
const client2 = new DeeplineClient();
|
|
12549
12724
|
const explicitJson = args.includes("--json");
|
|
12550
12725
|
const sourceOutput = args.includes("--source");
|
|
12551
12726
|
const jsonOutput = sourceOutput ? explicitJson : argsWantJson(args);
|
|
@@ -12557,7 +12732,7 @@ async function handlePlayGet(args) {
|
|
|
12557
12732
|
}
|
|
12558
12733
|
}
|
|
12559
12734
|
const playName = isFileTarget(target) ? extractPlayName((0, import_node_fs10.readFileSync)((0, import_node_path12.resolve)(target), "utf-8"), (0, import_node_path12.resolve)(target)) : parseReferencedPlayTarget2(target).playName;
|
|
12560
|
-
const detail = isFileTarget(target) ? await
|
|
12735
|
+
const detail = isFileTarget(target) ? await client2.getPlay(playName) : await assertCanonicalNamedPlayReference(client2, target);
|
|
12561
12736
|
const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
|
|
12562
12737
|
const materializedFile = outPath ? materializeRemotePlaySource({
|
|
12563
12738
|
target,
|
|
@@ -12637,10 +12812,10 @@ async function handlePlayVersions(args) {
|
|
|
12637
12812
|
console.error("Usage: deepline play versions --name <name> [--json]");
|
|
12638
12813
|
return 1;
|
|
12639
12814
|
}
|
|
12640
|
-
const
|
|
12815
|
+
const client2 = new DeeplineClient();
|
|
12641
12816
|
const jsonOutput = argsWantJson(args);
|
|
12642
|
-
await assertCanonicalNamedPlayReference(
|
|
12643
|
-
const versions = await
|
|
12817
|
+
await assertCanonicalNamedPlayReference(client2, playName);
|
|
12818
|
+
const versions = await client2.listPlayVersions(
|
|
12644
12819
|
parseReferencedPlayTarget2(playName).playName
|
|
12645
12820
|
);
|
|
12646
12821
|
if (jsonOutput) {
|
|
@@ -12659,8 +12834,8 @@ async function handlePlayVersions(args) {
|
|
|
12659
12834
|
}
|
|
12660
12835
|
async function handlePlayList(args) {
|
|
12661
12836
|
const jsonOutput = argsWantJson(args);
|
|
12662
|
-
const
|
|
12663
|
-
const plays = await
|
|
12837
|
+
const client2 = new DeeplineClient();
|
|
12838
|
+
const plays = await client2.listPlays();
|
|
12664
12839
|
if (jsonOutput) {
|
|
12665
12840
|
process.stdout.write(`${JSON.stringify(plays)}
|
|
12666
12841
|
`);
|
|
@@ -12843,8 +13018,8 @@ async function handlePlaySearch(args) {
|
|
|
12843
13018
|
console.error(error instanceof Error ? error.message : String(error));
|
|
12844
13019
|
return 1;
|
|
12845
13020
|
}
|
|
12846
|
-
const
|
|
12847
|
-
const plays = await
|
|
13021
|
+
const client2 = new DeeplineClient();
|
|
13022
|
+
const plays = await client2.searchPlays({
|
|
12848
13023
|
query: options.query,
|
|
12849
13024
|
compact: options.compact,
|
|
12850
13025
|
scope: options.scope
|
|
@@ -12936,8 +13111,8 @@ async function handlePlayGrep(args) {
|
|
|
12936
13111
|
}
|
|
12937
13112
|
}
|
|
12938
13113
|
const compact = args.includes("--compact");
|
|
12939
|
-
const
|
|
12940
|
-
const plays = (await
|
|
13114
|
+
const client2 = new DeeplineClient();
|
|
13115
|
+
const plays = (await client2.listPlays({
|
|
12941
13116
|
grep: query,
|
|
12942
13117
|
grepMode: mode
|
|
12943
13118
|
})).filter(
|
|
@@ -12994,9 +13169,9 @@ async function handlePlayDescribe(args) {
|
|
|
12994
13169
|
);
|
|
12995
13170
|
return 2;
|
|
12996
13171
|
}
|
|
12997
|
-
const
|
|
12998
|
-
await assertCanonicalNamedPlayReference(
|
|
12999
|
-
const play = await
|
|
13172
|
+
const client2 = new DeeplineClient();
|
|
13173
|
+
await assertCanonicalNamedPlayReference(client2, playName);
|
|
13174
|
+
const play = await client2.describePlay(
|
|
13000
13175
|
parseReferencedPlayTarget2(playName).playName,
|
|
13001
13176
|
{
|
|
13002
13177
|
compact: args.includes("--compact")
|
|
@@ -13033,7 +13208,7 @@ async function handlePlayPublish(args) {
|
|
|
13033
13208
|
console.error("Choose only one live target: --latest or --revision-id.");
|
|
13034
13209
|
return 1;
|
|
13035
13210
|
}
|
|
13036
|
-
const
|
|
13211
|
+
const client2 = new DeeplineClient();
|
|
13037
13212
|
if (isFileTarget(playName)) {
|
|
13038
13213
|
if (revisionId || useLatest) {
|
|
13039
13214
|
console.error(
|
|
@@ -13051,12 +13226,12 @@ async function handlePlayPublish(args) {
|
|
|
13051
13226
|
await traceCliSpan(
|
|
13052
13227
|
"cli.play_publish_compile_manifests",
|
|
13053
13228
|
{ targetKind: "file", nodeCount: graph.nodes.size },
|
|
13054
|
-
() => compileBundledPlayGraphManifests(
|
|
13229
|
+
() => compileBundledPlayGraphManifests(client2, graph)
|
|
13055
13230
|
);
|
|
13056
13231
|
await traceCliSpan(
|
|
13057
13232
|
"cli.play_publish_imports",
|
|
13058
13233
|
{ targetKind: "file", nodeCount: graph.nodes.size },
|
|
13059
|
-
() => publishImportedPlayDependencies(
|
|
13234
|
+
() => publishImportedPlayDependencies(client2, graph)
|
|
13060
13235
|
);
|
|
13061
13236
|
} catch (error) {
|
|
13062
13237
|
console.error(error instanceof Error ? error.message : String(error));
|
|
@@ -13070,7 +13245,7 @@ async function handlePlayPublish(args) {
|
|
|
13070
13245
|
playName: rootPlayName,
|
|
13071
13246
|
artifactHash: graph.root.artifact.artifactHash
|
|
13072
13247
|
},
|
|
13073
|
-
() =>
|
|
13248
|
+
() => client2.registerPlayArtifact({
|
|
13074
13249
|
name: rootPlayName,
|
|
13075
13250
|
sourceCode: graph.root.sourceCode,
|
|
13076
13251
|
sourceFiles: graph.root.sourceFiles,
|
|
@@ -13094,7 +13269,7 @@ async function handlePlayPublish(args) {
|
|
|
13094
13269
|
}
|
|
13095
13270
|
const resolvedName = parseReferencedPlayTarget2(playName).playName;
|
|
13096
13271
|
if (useLatest) {
|
|
13097
|
-
const versions = await
|
|
13272
|
+
const versions = await client2.listPlayVersions(resolvedName);
|
|
13098
13273
|
const latest = versions[0];
|
|
13099
13274
|
if (!latest?._id) {
|
|
13100
13275
|
console.error(`No saved revisions found for ${resolvedName}.`);
|
|
@@ -13103,12 +13278,12 @@ async function handlePlayPublish(args) {
|
|
|
13103
13278
|
revisionId = latest._id;
|
|
13104
13279
|
}
|
|
13105
13280
|
try {
|
|
13106
|
-
await ensureEditableRemotePlay(
|
|
13281
|
+
await ensureEditableRemotePlay(client2, resolvedName);
|
|
13107
13282
|
} catch (error) {
|
|
13108
13283
|
console.error(error instanceof Error ? error.message : String(error));
|
|
13109
13284
|
return 1;
|
|
13110
13285
|
}
|
|
13111
|
-
const result = await
|
|
13286
|
+
const result = await client2.publishPlayVersion(
|
|
13112
13287
|
resolvedName,
|
|
13113
13288
|
revisionId ? { revisionId } : {}
|
|
13114
13289
|
);
|
|
@@ -13129,10 +13304,10 @@ async function handlePlayDelete(args) {
|
|
|
13129
13304
|
);
|
|
13130
13305
|
return 1;
|
|
13131
13306
|
}
|
|
13132
|
-
const
|
|
13307
|
+
const client2 = new DeeplineClient();
|
|
13133
13308
|
let detail;
|
|
13134
13309
|
try {
|
|
13135
|
-
detail = await
|
|
13310
|
+
detail = await client2.getPlay(parseReferencedPlayTarget2(playName).playName);
|
|
13136
13311
|
} catch (error) {
|
|
13137
13312
|
console.error(error instanceof Error ? error.message : String(error));
|
|
13138
13313
|
return 1;
|
|
@@ -13143,7 +13318,7 @@ async function handlePlayDelete(args) {
|
|
|
13143
13318
|
);
|
|
13144
13319
|
return 1;
|
|
13145
13320
|
}
|
|
13146
|
-
const result = await
|
|
13321
|
+
const result = await client2.deletePlay(
|
|
13147
13322
|
parseReferencedPlayTarget2(formatPlayReference(detail.play)).playName
|
|
13148
13323
|
);
|
|
13149
13324
|
if (argsWantJson(args)) {
|
|
@@ -13808,11 +13983,11 @@ async function handlePlaySharePublish(args) {
|
|
|
13808
13983
|
return 2;
|
|
13809
13984
|
}
|
|
13810
13985
|
const name = parseReferencedPlayTarget2(target).playName;
|
|
13811
|
-
const
|
|
13986
|
+
const client2 = new DeeplineClient();
|
|
13812
13987
|
let revisionId = shareFlagValue(args, "--revision-id");
|
|
13813
13988
|
let resolvedVersion;
|
|
13814
13989
|
if (!revisionId) {
|
|
13815
|
-
const versions = await
|
|
13990
|
+
const versions = await client2.listPlayVersions(name);
|
|
13816
13991
|
if (versions.length === 0) {
|
|
13817
13992
|
console.error(
|
|
13818
13993
|
`No saved revisions for ${name}. Run \`deepline plays set-live ${name}\` first.`
|
|
@@ -13833,7 +14008,7 @@ async function handlePlaySharePublish(args) {
|
|
|
13833
14008
|
resolvedVersion = chosen.version;
|
|
13834
14009
|
}
|
|
13835
14010
|
if (!args.includes("--no-run-check")) {
|
|
13836
|
-
const runs = await
|
|
14011
|
+
const runs = await client2.listRuns({ play: name });
|
|
13837
14012
|
const hasCompleted = runs.some(
|
|
13838
14013
|
(r) => String(r.status).toLowerCase() === "completed"
|
|
13839
14014
|
);
|
|
@@ -13872,7 +14047,7 @@ async function handlePlaySharePublish(args) {
|
|
|
13872
14047
|
}
|
|
13873
14048
|
return 0;
|
|
13874
14049
|
}
|
|
13875
|
-
const status = await
|
|
14050
|
+
const status = await client2.publishSharePage(name, request);
|
|
13876
14051
|
if (argsWantJson(args)) {
|
|
13877
14052
|
process.stdout.write(`${JSON.stringify(status)}
|
|
13878
14053
|
`);
|
|
@@ -13920,11 +14095,11 @@ async function handlePlayShareRegenerate(args) {
|
|
|
13920
14095
|
return 2;
|
|
13921
14096
|
}
|
|
13922
14097
|
const name = parseReferencedPlayTarget2(target).playName;
|
|
13923
|
-
const
|
|
14098
|
+
const client2 = new DeeplineClient();
|
|
13924
14099
|
let revisionId = shareFlagValue(args, "--revision-id");
|
|
13925
14100
|
const versionFlag = shareFlagValue(args, "--version");
|
|
13926
14101
|
if (!revisionId && versionFlag) {
|
|
13927
|
-
const versions = await
|
|
14102
|
+
const versions = await client2.listPlayVersions(name);
|
|
13928
14103
|
const chosen = versions.find((r) => r.version === Number(versionFlag));
|
|
13929
14104
|
if (!chosen?._id) {
|
|
13930
14105
|
console.error(`Version ${versionFlag} not found for ${name}.`);
|
|
@@ -13932,7 +14107,7 @@ async function handlePlayShareRegenerate(args) {
|
|
|
13932
14107
|
}
|
|
13933
14108
|
revisionId = chosen._id;
|
|
13934
14109
|
}
|
|
13935
|
-
const status = await
|
|
14110
|
+
const status = await client2.regenerateSharePage(
|
|
13936
14111
|
name,
|
|
13937
14112
|
revisionId ? { revisionId } : {}
|
|
13938
14113
|
);
|
|
@@ -13969,52 +14144,158 @@ async function handlePlayShareUnpublish(args) {
|
|
|
13969
14144
|
return 0;
|
|
13970
14145
|
}
|
|
13971
14146
|
|
|
13972
|
-
//
|
|
13973
|
-
var
|
|
13974
|
-
"
|
|
13975
|
-
"
|
|
13976
|
-
"
|
|
13977
|
-
"
|
|
13978
|
-
"
|
|
13979
|
-
"
|
|
13980
|
-
"
|
|
13981
|
-
"
|
|
13982
|
-
"
|
|
13983
|
-
"
|
|
13984
|
-
"
|
|
13985
|
-
"
|
|
13986
|
-
"
|
|
13987
|
-
"
|
|
13988
|
-
"
|
|
13989
|
-
"
|
|
13990
|
-
"
|
|
13991
|
-
"
|
|
13992
|
-
"in",
|
|
13993
|
-
"instanceof",
|
|
13994
|
-
"new",
|
|
13995
|
-
"return",
|
|
13996
|
-
"super",
|
|
13997
|
-
"switch",
|
|
13998
|
-
"this",
|
|
13999
|
-
"throw",
|
|
14000
|
-
"try",
|
|
14001
|
-
"typeof",
|
|
14002
|
-
"var",
|
|
14003
|
-
"void",
|
|
14004
|
-
"while",
|
|
14005
|
-
"with",
|
|
14006
|
-
"yield"
|
|
14147
|
+
// ../shared_libs/plays/tool-codegen.ts
|
|
14148
|
+
var KNOWN_GETTER_NAMES = /* @__PURE__ */ new Set([
|
|
14149
|
+
"company_domain",
|
|
14150
|
+
"company_linkedin_url",
|
|
14151
|
+
"company_name",
|
|
14152
|
+
"domain",
|
|
14153
|
+
"email",
|
|
14154
|
+
"email_status",
|
|
14155
|
+
"first_name",
|
|
14156
|
+
"full_name",
|
|
14157
|
+
"job_change",
|
|
14158
|
+
"job_change_status",
|
|
14159
|
+
"job_changed",
|
|
14160
|
+
"last_name",
|
|
14161
|
+
"linkedin",
|
|
14162
|
+
"personal_email",
|
|
14163
|
+
"phone",
|
|
14164
|
+
"phone_status",
|
|
14165
|
+
"status",
|
|
14166
|
+
"title"
|
|
14007
14167
|
]);
|
|
14168
|
+
function renderToolCodegenString(value) {
|
|
14169
|
+
return JSON.stringify(value);
|
|
14170
|
+
}
|
|
14171
|
+
function renderToolRowPathExpression(path, rowName = "row") {
|
|
14172
|
+
const parts = String(path || "").replace(/\[(\d+)\]/g, ".$1").split(".").map((part) => part.trim()).filter(Boolean);
|
|
14173
|
+
if (parts.length === 0) return rowName;
|
|
14174
|
+
return parts.reduce((expr, part, index) => {
|
|
14175
|
+
if (index === 0) return `${rowName}[${renderToolCodegenString(part)}]`;
|
|
14176
|
+
return `(${expr} as Record<string, unknown> | null | undefined)?.[${renderToolCodegenString(part)}]`;
|
|
14177
|
+
}, rowName);
|
|
14178
|
+
}
|
|
14179
|
+
function renderToolPayloadExpression(value, rowName = "row") {
|
|
14180
|
+
if (Array.isArray(value)) {
|
|
14181
|
+
return `[${value.map((entry) => renderToolPayloadExpression(entry, rowName)).join(", ")}]`;
|
|
14182
|
+
}
|
|
14183
|
+
if (value && typeof value === "object") {
|
|
14184
|
+
const entries = Object.entries(value).sort(
|
|
14185
|
+
([left], [right]) => left.localeCompare(right)
|
|
14186
|
+
);
|
|
14187
|
+
return `{ ${entries.map(
|
|
14188
|
+
([key, entry]) => `${renderToolCodegenString(key)}: ${renderToolPayloadExpression(entry, rowName)}`
|
|
14189
|
+
).join(", ")} }`;
|
|
14190
|
+
}
|
|
14191
|
+
if (typeof value !== "string") return JSON.stringify(value);
|
|
14192
|
+
const exact = value.match(/^\{\{\s*([^{}]+?)\s*\}\}$/);
|
|
14193
|
+
if (exact) return renderToolRowPathExpression(exact[1] ?? "", rowName);
|
|
14194
|
+
const pieces = [];
|
|
14195
|
+
let cursor = 0;
|
|
14196
|
+
for (const match of value.matchAll(/\{\{\s*([^{}]+?)\s*\}\}/g)) {
|
|
14197
|
+
const index = match.index ?? 0;
|
|
14198
|
+
if (index > cursor) {
|
|
14199
|
+
pieces.push(renderToolCodegenString(value.slice(cursor, index)));
|
|
14200
|
+
}
|
|
14201
|
+
pieces.push(
|
|
14202
|
+
`String(${renderToolRowPathExpression(match[1] ?? "", rowName)} ?? '')`
|
|
14203
|
+
);
|
|
14204
|
+
cursor = index + match[0].length;
|
|
14205
|
+
}
|
|
14206
|
+
if (pieces.length === 0) return renderToolCodegenString(value);
|
|
14207
|
+
if (cursor < value.length) {
|
|
14208
|
+
pieces.push(renderToolCodegenString(value.slice(cursor)));
|
|
14209
|
+
}
|
|
14210
|
+
return pieces.join(" + ");
|
|
14211
|
+
}
|
|
14212
|
+
function renderExtractedValueGetterExpression(toolResultVar, targetKey) {
|
|
14213
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(targetKey) ? `${toolResultVar}.extractedValues.${targetKey}?.get()` : `${toolResultVar}.extractedValues[${renderToolCodegenString(targetKey)}]?.get()`;
|
|
14214
|
+
}
|
|
14215
|
+
function getterFromLegacyPath(path) {
|
|
14216
|
+
const last = String(path || "").replace(/\[(\d+)\]/g, ".$1").split(".").map((part) => part.trim()).filter(Boolean).at(-1);
|
|
14217
|
+
if (!last) return null;
|
|
14218
|
+
const normalized = last.replace(/[^A-Za-z0-9_]/g, "_");
|
|
14219
|
+
return KNOWN_GETTER_NAMES.has(normalized) ? normalized : null;
|
|
14220
|
+
}
|
|
14221
|
+
function getterFromLegacyExtractJs(extractJs, fallbackAlias) {
|
|
14222
|
+
const source = extractJs?.trim();
|
|
14223
|
+
if (!source) {
|
|
14224
|
+
const aliasGetter = fallbackAlias?.replace(/[^A-Za-z0-9_]/g, "_");
|
|
14225
|
+
return aliasGetter && KNOWN_GETTER_NAMES.has(aliasGetter) ? aliasGetter : null;
|
|
14226
|
+
}
|
|
14227
|
+
const directExtract = source.match(
|
|
14228
|
+
/\bextract\(\s*["'][^"']+["']\s*,\s*output_data\s*,\s*["']([^"']+)["']\s*\)/
|
|
14229
|
+
);
|
|
14230
|
+
if (directExtract?.[1]) {
|
|
14231
|
+
return getterFromLegacyPath(
|
|
14232
|
+
directExtract[1] === "linkedin_url" ? "linkedin" : directExtract[1]
|
|
14233
|
+
);
|
|
14234
|
+
}
|
|
14235
|
+
const pick = source.match(
|
|
14236
|
+
/\b(?:pick|extract|target)\(\s*(\[[\s\S]*?\]|["'][^"']+["'])\s*\)/
|
|
14237
|
+
);
|
|
14238
|
+
if (!pick?.[1]) return null;
|
|
14239
|
+
try {
|
|
14240
|
+
const parsed = JSON.parse(pick[1].replace(/'/g, '"'));
|
|
14241
|
+
const paths = Array.isArray(parsed) ? parsed : [parsed];
|
|
14242
|
+
for (const path of paths) {
|
|
14243
|
+
if (typeof path !== "string") continue;
|
|
14244
|
+
const getter = getterFromLegacyPath(path);
|
|
14245
|
+
if (getter) return getter;
|
|
14246
|
+
}
|
|
14247
|
+
} catch {
|
|
14248
|
+
return null;
|
|
14249
|
+
}
|
|
14250
|
+
return null;
|
|
14251
|
+
}
|
|
14252
|
+
|
|
14253
|
+
// src/cli/user-code-safety.ts
|
|
14254
|
+
var FORBIDDEN = [
|
|
14255
|
+
// Non-deterministic — breaks replay.
|
|
14256
|
+
{ pattern: /\bMath\s*\.\s*random\b/, reason: "Math.random()" },
|
|
14257
|
+
{ pattern: /\bDate\s*\.\s*now\b/, reason: "Date.now()" },
|
|
14258
|
+
{ pattern: /\bnew\s+Date\s*\(\s*\)/, reason: "new Date() with no argument" },
|
|
14259
|
+
{ pattern: /\bperformance\s*\.\s*now\b/, reason: "performance.now()" },
|
|
14260
|
+
{
|
|
14261
|
+
pattern: /\bcrypto\s*\.\s*(?:randomUUID|getRandomValues)\b/,
|
|
14262
|
+
reason: "crypto random"
|
|
14263
|
+
},
|
|
14264
|
+
// Sandbox escape / I/O.
|
|
14265
|
+
{ pattern: /(?<!\.)\bfetch\s*\(/, reason: "fetch()" },
|
|
14266
|
+
{ pattern: /(?<!\.)\bimport\s*\(/, reason: "dynamic import()" },
|
|
14267
|
+
{ pattern: /(?<!\.)\brequire\s*\(/, reason: "require()" },
|
|
14268
|
+
{ pattern: /(?<!\.)\beval\s*\(/, reason: "eval()" },
|
|
14269
|
+
{
|
|
14270
|
+
pattern: /(?<!\.)\bnew\s+Function\b|(?<!\.)\bFunction\s*\(/,
|
|
14271
|
+
reason: "the Function constructor"
|
|
14272
|
+
},
|
|
14273
|
+
{ pattern: /(?<!\.)\bprocess\b/, reason: "process" },
|
|
14274
|
+
{ pattern: /(?<!\.)\bglobalThis\b/, reason: "globalThis" },
|
|
14275
|
+
{ pattern: /(?<!\.)\b(?:window|self)\b/, reason: "window/self" },
|
|
14276
|
+
{ pattern: /(?<!\.)\bXMLHttpRequest\b/, reason: "XMLHttpRequest" },
|
|
14277
|
+
{ pattern: /(?<!\.)\bWebAssembly\b/, reason: "WebAssembly" }
|
|
14278
|
+
];
|
|
14279
|
+
function assertUserCodeIsSafe(code, label) {
|
|
14280
|
+
if (typeof code !== "string" || !code.trim()) return;
|
|
14281
|
+
for (const { pattern, reason } of FORBIDDEN) {
|
|
14282
|
+
if (pattern.test(code)) {
|
|
14283
|
+
throw new Error(
|
|
14284
|
+
`${label} uses ${reason}, which is not allowed in play code: it breaks deterministic replay or escapes the sandbox. Remove it and compute the value from the row/result instead.`
|
|
14285
|
+
);
|
|
14286
|
+
}
|
|
14287
|
+
}
|
|
14288
|
+
}
|
|
14289
|
+
|
|
14290
|
+
// src/cli/enrich-play-compiler.ts
|
|
14008
14291
|
function isWaterfall(command) {
|
|
14009
14292
|
return "with_waterfall" in command;
|
|
14010
14293
|
}
|
|
14011
|
-
function
|
|
14012
|
-
const
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
}
|
|
14017
|
-
return prefixed;
|
|
14294
|
+
function configHasRunJavascript(config) {
|
|
14295
|
+
const walk = (commands) => commands.some(
|
|
14296
|
+
(command) => isWaterfall(command) ? walk(command.commands) : command.tool === "run_javascript"
|
|
14297
|
+
);
|
|
14298
|
+
return walk(config.commands ?? []);
|
|
14018
14299
|
}
|
|
14019
14300
|
function stringLiteral(value) {
|
|
14020
14301
|
return JSON.stringify(value);
|
|
@@ -14041,12 +14322,23 @@ function commandCallId(command) {
|
|
|
14041
14322
|
function normalizeAlias(value) {
|
|
14042
14323
|
return value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
14043
14324
|
}
|
|
14044
|
-
function renderExecuteStep(command, options = {
|
|
14325
|
+
function renderExecuteStep(command, options = {
|
|
14326
|
+
force: false
|
|
14327
|
+
}) {
|
|
14328
|
+
if (command.play) {
|
|
14329
|
+
return renderPlayStep(command, options);
|
|
14330
|
+
}
|
|
14331
|
+
if (command.tool === "run_javascript" && options.inlineRunJavascript) {
|
|
14332
|
+
return renderInlineJavascriptStep(command, options);
|
|
14333
|
+
}
|
|
14334
|
+
if (options.idiomaticGetters) {
|
|
14335
|
+
return renderIdiomaticExecuteStep(command, options);
|
|
14336
|
+
}
|
|
14045
14337
|
const alias = stringLiteral(command.alias);
|
|
14046
14338
|
const callId = stringLiteral(commandCallId(command));
|
|
14047
14339
|
const tool = stringLiteral(command.tool);
|
|
14048
14340
|
const payload = stableJson(command.payload ?? {});
|
|
14049
|
-
const extractJs = command.extract_js ? `({ row, result, data, raw, pick, extract, target }) => { const input = row; const context = row;
|
|
14341
|
+
const extractJs = command.extract_js ? `({ row, result, data, raw, pick, extract, extractList, target, get }) => { const input = row; const context = row;
|
|
14050
14342
|
${indent(renderJavascriptBody(command.extract_js), 6)}
|
|
14051
14343
|
}` : "null";
|
|
14052
14344
|
const runIfJs = command.run_if_js ? `(row) => { const input = row; const context = row;
|
|
@@ -14056,6 +14348,8 @@ ${indent(renderJavascriptBody(command.run_if_js), 6)}
|
|
|
14056
14348
|
description: ${stringLiteral(command.description)}` : "";
|
|
14057
14349
|
const force = options.force ? `,
|
|
14058
14350
|
force: true` : "";
|
|
14351
|
+
const legacyEnvelope = options.legacyEnvelope ? `,
|
|
14352
|
+
legacyEnvelope: true` : "";
|
|
14059
14353
|
return [
|
|
14060
14354
|
`async (row, stepCtx) => {`,
|
|
14061
14355
|
...options.precheck ? [` if (${options.precheck}) return null;`] : [],
|
|
@@ -14067,253 +14361,842 @@ ${indent(renderJavascriptBody(command.run_if_js), 6)}
|
|
|
14067
14361
|
` extract: ${extractJs},`,
|
|
14068
14362
|
` runIf: ${runIfJs},`,
|
|
14069
14363
|
` row,`,
|
|
14070
|
-
` stepCtx${description}${force}`,
|
|
14364
|
+
` stepCtx${description}${force}${legacyEnvelope}`,
|
|
14365
|
+
` });`,
|
|
14366
|
+
`}`
|
|
14367
|
+
].join("\n");
|
|
14368
|
+
}
|
|
14369
|
+
function renderIdiomaticExecuteStep(command, options) {
|
|
14370
|
+
const callId = stringLiteral(commandCallId(command));
|
|
14371
|
+
const tool = stringLiteral(command.tool);
|
|
14372
|
+
const input2 = renderToolPayloadExpression(command.payload ?? {});
|
|
14373
|
+
const getter = getterFromLegacyExtractJs(command.extract_js, command.alias);
|
|
14374
|
+
const extraction = getter ? `${renderExtractedValueGetterExpression("result", getter)} ?? null` : "result";
|
|
14375
|
+
const runIfLines = command.run_if_js ? [
|
|
14376
|
+
` if (`,
|
|
14377
|
+
` !((row: Record<string, any>) => {`,
|
|
14378
|
+
` const input = row;`,
|
|
14379
|
+
` const context = row;`,
|
|
14380
|
+
indent(renderJavascriptBody(command.run_if_js), 6),
|
|
14381
|
+
` })(row as Record<string, any>)`,
|
|
14382
|
+
` ) return null;`
|
|
14383
|
+
] : [];
|
|
14384
|
+
return [
|
|
14385
|
+
`async (row, ctx) => {`,
|
|
14386
|
+
...options.precheck ? [` if (${options.precheck}) return null;`] : [],
|
|
14387
|
+
...runIfLines,
|
|
14388
|
+
` const result: any = await ctx.tools.execute({`,
|
|
14389
|
+
` id: ${callId},`,
|
|
14390
|
+
` tool: ${tool},`,
|
|
14391
|
+
` input: ${input2} as any,`,
|
|
14392
|
+
` description: ${stringLiteral((command.description ?? "").trim() || `Run ${command.alias} via ${command.tool}.`)},`,
|
|
14393
|
+
...options.force ? [` staleAfterSeconds: 1,`] : [],
|
|
14394
|
+
` });`,
|
|
14395
|
+
` return ${extraction};`,
|
|
14396
|
+
`}`
|
|
14397
|
+
].join("\n");
|
|
14398
|
+
}
|
|
14399
|
+
function renderInlineJavascriptStep(command, options) {
|
|
14400
|
+
const code = typeof command.payload?.code === "string" ? command.payload.code : "return null;";
|
|
14401
|
+
const runIfLines = command.run_if_js ? [
|
|
14402
|
+
` if (!((row: Record<string, any>) => { const input = row; const context = row;`,
|
|
14403
|
+
indent(renderJavascriptBody(command.run_if_js), 4),
|
|
14404
|
+
` })(row as Record<string, any>)) return null;`
|
|
14405
|
+
] : [];
|
|
14406
|
+
return [
|
|
14407
|
+
`async (row) => {`,
|
|
14408
|
+
...options.precheck ? [` if (${options.precheck}) return null;`] : [],
|
|
14409
|
+
...runIfLines,
|
|
14410
|
+
` return ((row: Record<string, any>, input: Record<string, any>, context: Record<string, any>) => {`,
|
|
14411
|
+
indent(renderJavascriptBody(code), 4),
|
|
14412
|
+
` })(row as Record<string, any>, row as Record<string, any>, row as Record<string, any>);`,
|
|
14413
|
+
`}`
|
|
14414
|
+
].join("\n");
|
|
14415
|
+
}
|
|
14416
|
+
function renderPlayStep(command, options) {
|
|
14417
|
+
const alias = stringLiteral(command.alias);
|
|
14418
|
+
const callId = stringLiteral(commandCallId(command));
|
|
14419
|
+
const playRef = stringLiteral(command.play?.ref ?? command.tool);
|
|
14420
|
+
const payload = stableJson(command.payload ?? {});
|
|
14421
|
+
const runIfJs = command.run_if_js ? `(row) => { const input = row; const context = row;
|
|
14422
|
+
${indent(renderJavascriptBody(command.run_if_js), 6)}
|
|
14423
|
+
}` : "null";
|
|
14424
|
+
const runIfLines = command.run_if_js ? [` const __dlRunIf = ${runIfJs};`, ` if (!__dlRunIf(row)) return null;`] : [];
|
|
14425
|
+
const playOptions = [
|
|
14426
|
+
` description: ${stringLiteral(command.description ?? command.alias)}`,
|
|
14427
|
+
...options.force ? [` staleAfterSeconds: 1`] : []
|
|
14428
|
+
].join(",\n");
|
|
14429
|
+
return [
|
|
14430
|
+
`async (row, stepCtx) => {`,
|
|
14431
|
+
...options.precheck ? [` if (${options.precheck}) return null;`] : [],
|
|
14432
|
+
...runIfLines,
|
|
14433
|
+
` const payload = __dlTemplate(${payload}, row) as Record<string, unknown>;`,
|
|
14434
|
+
` const result = await stepCtx.runPlay(${callId}, ${playRef}, payload, {`,
|
|
14435
|
+
playOptions,
|
|
14071
14436
|
` });`,
|
|
14437
|
+
` return __dlPlayResultValue(${alias}, result);`,
|
|
14072
14438
|
`}`
|
|
14073
14439
|
].join("\n");
|
|
14074
14440
|
}
|
|
14075
14441
|
function renderJavascriptBody(source) {
|
|
14442
|
+
assertUserCodeIsSafe(source, "play step code");
|
|
14076
14443
|
const trimmed = source.trim();
|
|
14444
|
+
if (/^(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>/.test(trimmed)) {
|
|
14445
|
+
return `return (${trimmed});`;
|
|
14446
|
+
}
|
|
14077
14447
|
if (trimmed && !trimmed.includes("\n") && !trimmed.includes(";") && !/\breturn\b/.test(trimmed)) {
|
|
14078
14448
|
return `return (${trimmed});`;
|
|
14079
14449
|
}
|
|
14080
14450
|
return source;
|
|
14081
14451
|
}
|
|
14082
|
-
function
|
|
14083
|
-
const
|
|
14084
|
-
|
|
14085
|
-
`
|
|
14452
|
+
function renderColumnStep(alias, resolverSource, force) {
|
|
14453
|
+
const resolver = indent(resolverSource, 8);
|
|
14454
|
+
return [
|
|
14455
|
+
` .withColumn(${stringLiteral(alias)},`,
|
|
14456
|
+
force ? `${resolver},` : resolver,
|
|
14457
|
+
...force ? [` { staleAfterSeconds: 1 }`] : [],
|
|
14458
|
+
` )`
|
|
14459
|
+
].join("\n");
|
|
14460
|
+
}
|
|
14461
|
+
function metadataMode(command) {
|
|
14462
|
+
return /\bextractList\s*\(/.test(command.extract_js ?? "") ? "list" : "scalar";
|
|
14463
|
+
}
|
|
14464
|
+
function metadataEntryForCommand(command, waterfallGroupId) {
|
|
14465
|
+
const entry = {
|
|
14466
|
+
tool_id: command.tool
|
|
14467
|
+
};
|
|
14468
|
+
if (command.play?.ref) {
|
|
14469
|
+
entry.play_ref = command.play.ref;
|
|
14470
|
+
entry.kind = "play_call";
|
|
14471
|
+
}
|
|
14472
|
+
if (command.operation) {
|
|
14473
|
+
entry.operation = command.operation;
|
|
14474
|
+
}
|
|
14475
|
+
if (command.extract_js?.trim()) {
|
|
14476
|
+
entry.extract_js = command.extract_js.trim();
|
|
14477
|
+
}
|
|
14478
|
+
if (waterfallGroupId) {
|
|
14479
|
+
entry.waterfall = {
|
|
14480
|
+
group_id: waterfallGroupId,
|
|
14481
|
+
mode: metadataMode(command)
|
|
14482
|
+
};
|
|
14483
|
+
}
|
|
14484
|
+
return entry;
|
|
14485
|
+
}
|
|
14486
|
+
function collectMetadataColumns(commands, waterfallGroupId) {
|
|
14487
|
+
const columns = {};
|
|
14488
|
+
for (const command of commands) {
|
|
14489
|
+
if (isWaterfall(command)) {
|
|
14490
|
+
Object.assign(
|
|
14491
|
+
columns,
|
|
14492
|
+
collectMetadataColumns(command.commands, command.with_waterfall)
|
|
14493
|
+
);
|
|
14494
|
+
continue;
|
|
14495
|
+
}
|
|
14496
|
+
if (command.disabled) {
|
|
14497
|
+
continue;
|
|
14498
|
+
}
|
|
14499
|
+
columns[normalizeAlias(command.alias)] = metadataEntryForCommand(
|
|
14500
|
+
command,
|
|
14501
|
+
waterfallGroupId
|
|
14502
|
+
);
|
|
14503
|
+
}
|
|
14504
|
+
return columns;
|
|
14505
|
+
}
|
|
14506
|
+
function renderMetadataColumnStep(config) {
|
|
14507
|
+
const columns = collectMetadataColumns(config.commands);
|
|
14508
|
+
if (Object.keys(columns).length === 0) {
|
|
14509
|
+
return "";
|
|
14510
|
+
}
|
|
14511
|
+
return [
|
|
14512
|
+
` .withColumn('_metadata',`,
|
|
14513
|
+
` (row) => __dlMergeMetadata(row._metadata, ${stableJson({ columns })}),`,
|
|
14514
|
+
` { staleAfterSeconds: 1 }`,
|
|
14515
|
+
` )`
|
|
14516
|
+
].join("\n");
|
|
14517
|
+
}
|
|
14518
|
+
function renderWaterfallColumns(command, forceAliases, inlineRunJavascript, idiomaticGetters) {
|
|
14519
|
+
const activeChildren = command.commands.filter(
|
|
14520
|
+
(nested) => !isWaterfall(nested) && !nested.disabled
|
|
14086
14521
|
);
|
|
14087
|
-
const
|
|
14522
|
+
const minResults = typeof command.min_results === "number" ? Math.max(1, Math.trunc(command.min_results)) : 1;
|
|
14523
|
+
const columnSteps = activeChildren.map((nested, stepIndex) => {
|
|
14088
14524
|
if (isWaterfall(nested)) {
|
|
14089
14525
|
throw new Error("Nested with_waterfall blocks are not supported.");
|
|
14090
14526
|
}
|
|
14091
14527
|
if (nested.disabled) {
|
|
14092
14528
|
return null;
|
|
14093
14529
|
}
|
|
14094
|
-
const priorAliases =
|
|
14095
|
-
const
|
|
14096
|
-
return
|
|
14097
|
-
|
|
14098
|
-
|
|
14099
|
-
|
|
14100
|
-
|
|
14101
|
-
|
|
14102
|
-
|
|
14103
|
-
|
|
14104
|
-
),
|
|
14105
|
-
|
|
14106
|
-
|
|
14530
|
+
const priorAliases = activeChildren.slice(0, stepIndex).map((prior) => prior.alias);
|
|
14531
|
+
const force = forceAliases.has(normalizeAlias(nested.alias));
|
|
14532
|
+
return renderColumnStep(
|
|
14533
|
+
nested.alias,
|
|
14534
|
+
renderExecuteStep(nested, {
|
|
14535
|
+
force,
|
|
14536
|
+
precheck: priorAliases.length > 0 ? `__dlWaterfallSatisfied(row, ${stableJson(priorAliases)}, ${minResults})` : void 0,
|
|
14537
|
+
legacyEnvelope: Boolean(nested.extract_js),
|
|
14538
|
+
inlineRunJavascript,
|
|
14539
|
+
idiomaticGetters
|
|
14540
|
+
}),
|
|
14541
|
+
force
|
|
14542
|
+
);
|
|
14107
14543
|
}).filter((line) => line !== null);
|
|
14108
|
-
const aliases =
|
|
14544
|
+
const aliases = activeChildren.map((nested) => nested.alias);
|
|
14545
|
+
const forceParent = forceAliases.has(normalizeAlias(command.with_waterfall)) || activeChildren.some(
|
|
14546
|
+
(nested) => forceAliases.has(normalizeAlias(nested.alias))
|
|
14547
|
+
);
|
|
14109
14548
|
const returnExpr = typeof command.min_results === "number" ? `__dlFirstMinResults(row, ${stableJson(aliases)}, ${Math.max(
|
|
14110
14549
|
1,
|
|
14111
14550
|
Math.trunc(command.min_results)
|
|
14112
14551
|
)})` : `__dlFirstMeaningful(row, ${stableJson(aliases)})`;
|
|
14113
|
-
|
|
14114
|
-
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
|
|
14118
|
-
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14552
|
+
if (columnSteps.length === 0) {
|
|
14553
|
+
return [];
|
|
14554
|
+
}
|
|
14555
|
+
return [
|
|
14556
|
+
...columnSteps,
|
|
14557
|
+
renderColumnStep(
|
|
14558
|
+
command.with_waterfall,
|
|
14559
|
+
`(row) => ${returnExpr}`,
|
|
14560
|
+
forceParent
|
|
14561
|
+
),
|
|
14562
|
+
renderColumnStep(
|
|
14563
|
+
`${command.with_waterfall}_source`,
|
|
14564
|
+
typeof command.min_results === "number" ? `(row) => __dlContributingAliases(row, ${stableJson(aliases)})` : `(row) => __dlFirstMeaningfulAlias(row, ${stableJson(aliases)})`,
|
|
14565
|
+
forceParent
|
|
14566
|
+
)
|
|
14567
|
+
];
|
|
14122
14568
|
}
|
|
14123
14569
|
function compileEnrichConfigToPlaySource(config, options = {}) {
|
|
14124
14570
|
const playName = options.playName ?? "deepline-enrich-v1-compat";
|
|
14125
14571
|
const mapName = options.mapName ?? "deepline_enrich_rows";
|
|
14572
|
+
const inlineRunJavascript = options.inlineRunJavascript ?? false;
|
|
14573
|
+
const idiomaticGetters = options.idiomaticGetters ?? false;
|
|
14126
14574
|
const forceAliases = new Set(
|
|
14127
14575
|
[...options.forceAliases ?? []].map((alias) => normalizeAlias(alias))
|
|
14128
14576
|
);
|
|
14129
|
-
const
|
|
14130
|
-
|
|
14131
|
-
config.commands.forEach((command, index) => {
|
|
14577
|
+
const columnSteps = [];
|
|
14578
|
+
config.commands.forEach((command) => {
|
|
14132
14579
|
if (isWaterfall(command)) {
|
|
14133
|
-
|
|
14134
|
-
|
|
14135
|
-
|
|
14136
|
-
|
|
14137
|
-
|
|
14138
|
-
|
|
14139
|
-
|
|
14140
|
-
source: rendered.source
|
|
14141
|
-
});
|
|
14142
|
-
mapSteps.push(
|
|
14143
|
-
` .step(${stringLiteral(command.with_waterfall)}, ${rendered.variableName})`
|
|
14580
|
+
columnSteps.push(
|
|
14581
|
+
...renderWaterfallColumns(
|
|
14582
|
+
command,
|
|
14583
|
+
forceAliases,
|
|
14584
|
+
inlineRunJavascript,
|
|
14585
|
+
idiomaticGetters
|
|
14586
|
+
)
|
|
14144
14587
|
);
|
|
14145
14588
|
return;
|
|
14146
14589
|
}
|
|
14147
14590
|
if (command.disabled) {
|
|
14148
14591
|
return;
|
|
14149
14592
|
}
|
|
14150
|
-
|
|
14151
|
-
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
),
|
|
14159
|
-
|
|
14160
|
-
|
|
14593
|
+
const force = forceAliases.has(normalizeAlias(command.alias));
|
|
14594
|
+
columnSteps.push(
|
|
14595
|
+
renderColumnStep(
|
|
14596
|
+
command.alias,
|
|
14597
|
+
renderExecuteStep(command, {
|
|
14598
|
+
force,
|
|
14599
|
+
inlineRunJavascript,
|
|
14600
|
+
idiomaticGetters
|
|
14601
|
+
}),
|
|
14602
|
+
force
|
|
14603
|
+
)
|
|
14161
14604
|
);
|
|
14162
14605
|
});
|
|
14163
|
-
const
|
|
14164
|
-
const
|
|
14606
|
+
const columnStepSource = columnSteps.length > 0 ? columnSteps.join("\n") : ` .withColumn('noop', () => null)`;
|
|
14607
|
+
const metadataColumnSource = renderMetadataColumnStep(config);
|
|
14608
|
+
const body = [
|
|
14609
|
+
`export default definePlay(${stringLiteral(playName)}, async (ctx, input: EnrichInput) => {`,
|
|
14610
|
+
` const sourceRows = await ctx.csv<Record<string, unknown>>(input.file);`,
|
|
14611
|
+
` const rowStart = __dlNonNegativeInteger(input.rowStart, 0);`,
|
|
14612
|
+
` const rowEndExclusive = Number.isFinite(input.rowEnd) ? Math.max(rowStart, __dlWholeNumber(input.rowEnd, rowStart) + 1) : undefined;`,
|
|
14613
|
+
` const rows = sourceRows.slice(rowStart, rowEndExclusive, { key: 'deepline_enrich_selected_rows', sourceLabel: 'Selected enrich rows' });`,
|
|
14614
|
+
` const enriched = await ctx`,
|
|
14615
|
+
` .dataset(${stringLiteral(mapName)}, rows)`,
|
|
14616
|
+
columnStepSource,
|
|
14617
|
+
...metadataColumnSource ? [metadataColumnSource] : [],
|
|
14618
|
+
` .run({ key: (row, index) => __dlStableRowKey(row, index + rowStart) });`,
|
|
14619
|
+
` return { rows: enriched, count: await enriched.count() };`,
|
|
14620
|
+
`});`
|
|
14621
|
+
];
|
|
14622
|
+
const helpers = idiomaticGetters ? selectUsedHelpers(helperSource(), body.join("\n")) : helperSource();
|
|
14165
14623
|
return [
|
|
14166
|
-
|
|
14624
|
+
...inlineRunJavascript && configHasRunJavascript(config) ? ["// @ts-nocheck", "/* eslint-disable */", ""] : [],
|
|
14625
|
+
`import { definePlay } from 'deepline';`,
|
|
14167
14626
|
``,
|
|
14168
14627
|
`type EnrichInput = { file: string; rowStart?: number | null; rowEnd?: number | null };`,
|
|
14169
14628
|
``,
|
|
14170
|
-
|
|
14629
|
+
helpers,
|
|
14171
14630
|
``,
|
|
14172
|
-
|
|
14173
|
-
` const allRows = await ctx.csv<Record<string, unknown>>(input.file);`,
|
|
14174
|
-
` const rowStart = Number.isFinite(input.rowStart) ? Math.max(0, Math.trunc(Number(input.rowStart))) : 0;`,
|
|
14175
|
-
` const rowEnd = Number.isFinite(input.rowEnd) ? Math.max(rowStart, Math.trunc(Number(input.rowEnd))) : allRows.length;`,
|
|
14176
|
-
` const rows = allRows.slice(rowStart, rowEnd);`,
|
|
14177
|
-
...waterfallSource,
|
|
14178
|
-
` const enriched = await ctx`,
|
|
14179
|
-
` .map(${stringLiteral(mapName)}, rows)`,
|
|
14180
|
-
mapStepSource,
|
|
14181
|
-
` .run({ key: (row, index) => __dlStableRowKey(row, index + rowStart) });`,
|
|
14182
|
-
` return { rows: enriched, count: await enriched.count() };`,
|
|
14183
|
-
`});`,
|
|
14631
|
+
...body,
|
|
14184
14632
|
``
|
|
14185
14633
|
].join("\n");
|
|
14186
14634
|
}
|
|
14635
|
+
function selectUsedHelpers(helperBlock, referenceSource) {
|
|
14636
|
+
const referencesSymbol = (source, symbol) => new RegExp(`\\b${symbol}\\b`).test(source);
|
|
14637
|
+
const blocks = helperBlock.split("\n\n").map((source) => source.trim()).filter(Boolean).map((source) => ({
|
|
14638
|
+
name: source.match(/(?:function|type|const)\s+(__[A-Za-z]\w*)/)?.[1] ?? "",
|
|
14639
|
+
source
|
|
14640
|
+
}));
|
|
14641
|
+
const used = /* @__PURE__ */ new Set();
|
|
14642
|
+
for (const { name } of blocks) {
|
|
14643
|
+
if (name && referencesSymbol(referenceSource, name)) used.add(name);
|
|
14644
|
+
}
|
|
14645
|
+
let changed = true;
|
|
14646
|
+
while (changed) {
|
|
14647
|
+
changed = false;
|
|
14648
|
+
const usedSource = blocks.filter((block) => used.has(block.name)).map((block) => block.source).join("\n");
|
|
14649
|
+
for (const { name } of blocks) {
|
|
14650
|
+
if (!name || used.has(name)) continue;
|
|
14651
|
+
if (referencesSymbol(usedSource, name)) {
|
|
14652
|
+
used.add(name);
|
|
14653
|
+
changed = true;
|
|
14654
|
+
}
|
|
14655
|
+
}
|
|
14656
|
+
}
|
|
14657
|
+
return blocks.filter((block) => used.has(block.name)).map((block) => block.source).join("\n\n");
|
|
14658
|
+
}
|
|
14187
14659
|
function helperSource() {
|
|
14188
14660
|
return [
|
|
14189
|
-
`function
|
|
14190
|
-
`
|
|
14191
|
-
`
|
|
14192
|
-
`
|
|
14193
|
-
` .map((part) => part.trim())`,
|
|
14194
|
-
` .filter(Boolean)`,
|
|
14195
|
-
` .reduce((cursor: unknown, part: string) => {`,
|
|
14196
|
-
` if (!cursor || typeof cursor !== 'object') return undefined;`,
|
|
14197
|
-
` const record = cursor as Record<string, unknown>;`,
|
|
14198
|
-
` if (part in record) return record[part];`,
|
|
14199
|
-
` const data = record.data;`,
|
|
14200
|
-
` return data && typeof data === 'object' ? (data as Record<string, unknown>)[part] : undefined;`,
|
|
14201
|
-
` }, root);`,
|
|
14661
|
+
`function __dlWholeNumber(value: unknown, fallback: number): number {`,
|
|
14662
|
+
` const numeric = Number(value);`,
|
|
14663
|
+
` if (!Number.isFinite(numeric)) return fallback;`,
|
|
14664
|
+
` return Math.floor(numeric);`,
|
|
14202
14665
|
`}`,
|
|
14203
14666
|
``,
|
|
14204
|
-
`function
|
|
14205
|
-
` return
|
|
14667
|
+
`function __dlNonNegativeInteger(value: unknown, fallback: number): number {`,
|
|
14668
|
+
` return Math.max(0, __dlWholeNumber(value, fallback));`,
|
|
14206
14669
|
`}`,
|
|
14207
14670
|
``,
|
|
14208
|
-
`function
|
|
14209
|
-
`
|
|
14210
|
-
` const record = result as Record<string, unknown>;`,
|
|
14211
|
-
` return __dlGetByPath(record, 'toolOutput.raw') ?? __dlGetByPath(record, 'toolResponse.raw') ?? record.result ?? record.output ?? result;`,
|
|
14671
|
+
`function __dlAtLeastOneInteger(value: number): number {`,
|
|
14672
|
+
` return Math.max(1, Math.floor(Number(value)));`,
|
|
14212
14673
|
`}`,
|
|
14213
14674
|
``,
|
|
14214
|
-
`function
|
|
14215
|
-
`
|
|
14216
|
-
`
|
|
14217
|
-
|
|
14675
|
+
`function __dlRecord(value: unknown): value is Record<string, unknown> {`,
|
|
14676
|
+
` return Boolean(value && typeof value === 'object' && !Array.isArray(value));`,
|
|
14677
|
+
`}`,
|
|
14678
|
+
``,
|
|
14679
|
+
`function __dlParseMetadata(value: unknown): Record<string, unknown> | null {`,
|
|
14680
|
+
` if (__dlRecord(value)) return value;`,
|
|
14681
|
+
` if (typeof value !== 'string') return null;`,
|
|
14682
|
+
` const trimmed = value.trim();`,
|
|
14683
|
+
` if (!trimmed) return null;`,
|
|
14684
|
+
` const candidates = [trimmed];`,
|
|
14685
|
+
` if (trimmed.includes('\\\\"')) candidates.push(trimmed.replace(/\\\\"/g, '"'));`,
|
|
14686
|
+
` for (const candidate of candidates) {`,
|
|
14687
|
+
` try {`,
|
|
14688
|
+
` const parsed = JSON.parse(candidate);`,
|
|
14689
|
+
` if (__dlRecord(parsed)) return parsed;`,
|
|
14690
|
+
` if (typeof parsed === 'string') {`,
|
|
14691
|
+
` const nested = JSON.parse(parsed);`,
|
|
14692
|
+
` if (__dlRecord(nested)) return nested;`,
|
|
14693
|
+
` }`,
|
|
14694
|
+
` } catch {}`,
|
|
14218
14695
|
` }`,
|
|
14219
|
-
`
|
|
14220
|
-
`
|
|
14221
|
-
|
|
14222
|
-
`
|
|
14223
|
-
`
|
|
14224
|
-
`
|
|
14225
|
-
` }
|
|
14696
|
+
` return null;`,
|
|
14697
|
+
`}`,
|
|
14698
|
+
``,
|
|
14699
|
+
`function __dlMergeMetadata(existing: unknown, patch: Record<string, unknown>): Record<string, unknown> {`,
|
|
14700
|
+
` const base = __dlParseMetadata(existing) ?? {};`,
|
|
14701
|
+
` const baseColumns = __dlRecord(base.columns) ? base.columns : {};`,
|
|
14702
|
+
` const patchColumns = __dlRecord(patch.columns) ? patch.columns : {};`,
|
|
14703
|
+
` return {`,
|
|
14704
|
+
` ...base,`,
|
|
14705
|
+
` ...patch,`,
|
|
14706
|
+
` columns: {`,
|
|
14707
|
+
` ...baseColumns,`,
|
|
14708
|
+
` ...patchColumns,`,
|
|
14709
|
+
` },`,
|
|
14710
|
+
` };`,
|
|
14711
|
+
`}`,
|
|
14712
|
+
``,
|
|
14713
|
+
`function __dlPathParts(path: string): string[] {`,
|
|
14714
|
+
` const source = String(path || '');`,
|
|
14715
|
+
` const parts: string[] = [];`,
|
|
14716
|
+
` let current = '';`,
|
|
14717
|
+
` for (let index = 0; index < source.length; index += 1) {`,
|
|
14718
|
+
` const char = source.slice(index, index + 1);`,
|
|
14719
|
+
` if (char === '.' || char === '[' || char === ']') {`,
|
|
14720
|
+
` const trimmed = current.trim();`,
|
|
14721
|
+
` if (trimmed) parts.push(trimmed);`,
|
|
14722
|
+
` current = '';`,
|
|
14723
|
+
` continue;`,
|
|
14724
|
+
` }`,
|
|
14725
|
+
` current += char;`,
|
|
14726
|
+
` }`,
|
|
14727
|
+
` const trimmed = current.trim();`,
|
|
14728
|
+
` if (trimmed) parts.push(trimmed);`,
|
|
14729
|
+
` return parts;`,
|
|
14730
|
+
`}`,
|
|
14731
|
+
``,
|
|
14732
|
+
`function __dlGetByPath(root: unknown, path: string): unknown {`,
|
|
14733
|
+
` let cursor = root;`,
|
|
14734
|
+
` for (const part of __dlPathParts(path)) {`,
|
|
14735
|
+
` if (!cursor || typeof cursor !== 'object') return undefined;`,
|
|
14736
|
+
` const record = cursor as Record<string, unknown>;`,
|
|
14737
|
+
` if (part in record) {`,
|
|
14738
|
+
` cursor = record[part];`,
|
|
14739
|
+
` continue;`,
|
|
14740
|
+
` }`,
|
|
14741
|
+
` const data = record.data;`,
|
|
14742
|
+
` cursor = data && typeof data === 'object' ? (data as Record<string, unknown>)[part] : undefined;`,
|
|
14743
|
+
` }`,
|
|
14744
|
+
` return cursor;`,
|
|
14745
|
+
`}`,
|
|
14746
|
+
``,
|
|
14747
|
+
`function __dlMeaningful(value: unknown): boolean {`,
|
|
14748
|
+
` if (value && typeof value === 'object' && !Array.isArray(value)) {`,
|
|
14749
|
+
` const record = value as Record<string, unknown>;`,
|
|
14750
|
+
` const status = typeof record.status === 'string' ? record.status.toLowerCase() : '';`,
|
|
14751
|
+
` if (status === 'error' || status === 'failed') return false;`,
|
|
14752
|
+
` if (typeof record.error === 'string' && record.error.trim()) return false;`,
|
|
14753
|
+
` const result = record.result;`,
|
|
14754
|
+
` if (result && typeof result === 'object' && !Array.isArray(result)) {`,
|
|
14755
|
+
` const resultRecord = result as Record<string, unknown>;`,
|
|
14756
|
+
` if (typeof resultRecord.error === 'string' && resultRecord.error.trim()) return false;`,
|
|
14757
|
+
` if (typeof resultRecord.message === 'string' && resultRecord.message.trim()) return false;`,
|
|
14758
|
+
` }`,
|
|
14759
|
+
` if ('matched_result' in record) return __dlMeaningful(record.matched_result);`,
|
|
14760
|
+
` }`,
|
|
14761
|
+
` return value !== null && value !== undefined && !(typeof value === 'string' && value.trim() === '') && !(Array.isArray(value) && value.length === 0);`,
|
|
14762
|
+
`}`,
|
|
14763
|
+
``,
|
|
14764
|
+
`function __dlErrorPayload(value: unknown): boolean {`,
|
|
14765
|
+
` if (!value || typeof value !== 'object' || Array.isArray(value)) return false;`,
|
|
14766
|
+
` const record = value as Record<string, unknown>;`,
|
|
14767
|
+
` const status = typeof record.status === 'string' ? record.status.toLowerCase() : '';`,
|
|
14768
|
+
` const result = record.result;`,
|
|
14769
|
+
` const resultError = result && typeof result === 'object' && !Array.isArray(result) ? (result as Record<string, unknown>).error : null;`,
|
|
14770
|
+
` return status === 'error' || status === 'failed' || (typeof record.error === 'string' && record.error.trim() !== '') || (typeof resultError === 'string' && resultError.trim() !== '');`,
|
|
14771
|
+
`}`,
|
|
14772
|
+
``,
|
|
14773
|
+
`function __dlRawToolOutput(result: unknown): unknown {`,
|
|
14774
|
+
` if (!result || typeof result !== 'object') return result;`,
|
|
14775
|
+
` const record = result as Record<string, unknown>;`,
|
|
14776
|
+
` return __dlGetByPath(record, 'toolOutput.raw') ?? __dlGetByPath(record, 'toolResponse.raw') ?? record.result ?? record.output ?? result;`,
|
|
14777
|
+
`}`,
|
|
14778
|
+
``,
|
|
14779
|
+
`function __dlPushCandidate(candidates: unknown[], value: unknown): void {`,
|
|
14780
|
+
` if (value === null || value === undefined) return;`,
|
|
14781
|
+
` if (!candidates.includes(value)) candidates.push(value);`,
|
|
14782
|
+
`}`,
|
|
14783
|
+
``,
|
|
14784
|
+
`function __dlRawToolCandidates(raw: unknown): unknown[] {`,
|
|
14785
|
+
` const candidates: unknown[] = [raw];`,
|
|
14786
|
+
` if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return candidates;`,
|
|
14787
|
+
` const record = raw as Record<string, unknown>;`,
|
|
14788
|
+
` __dlPushCandidate(candidates, record.data);`,
|
|
14789
|
+
` __dlPushCandidate(candidates, record.result);`,
|
|
14790
|
+
` __dlPushCandidate(candidates, record.output);`,
|
|
14791
|
+
` __dlPushCandidate(candidates, __dlGetByPath(record, 'result.data'));`,
|
|
14792
|
+
` __dlPushCandidate(candidates, __dlGetByPath(record, 'output.body'));`,
|
|
14793
|
+
` __dlPushCandidate(candidates, __dlGetByPath(record, 'toolResponse.raw'));`,
|
|
14794
|
+
` __dlPushCandidate(candidates, __dlGetByPath(record, 'toolOutput.raw'));`,
|
|
14795
|
+
` return candidates;`,
|
|
14796
|
+
`}`,
|
|
14797
|
+
``,
|
|
14798
|
+
`function __dlLegacyResultData(value: unknown): unknown {`,
|
|
14799
|
+
` if (!value || typeof value !== 'object' || Array.isArray(value)) return value;`,
|
|
14800
|
+
` const record = value as Record<string, unknown>;`,
|
|
14801
|
+
` return 'data' in record ? record.data : value;`,
|
|
14802
|
+
`}`,
|
|
14803
|
+
``,
|
|
14804
|
+
`function __dlLegacyOutputData(result: unknown, raw: unknown): unknown {`,
|
|
14805
|
+
` const rawRecord = raw && typeof raw === 'object' && !Array.isArray(raw) ? (raw as Record<string, unknown>) : null;`,
|
|
14806
|
+
` const data = rawRecord && 'data' in rawRecord ? rawRecord.data : raw;`,
|
|
14807
|
+
` const existingResult = rawRecord && rawRecord.result && typeof rawRecord.result === 'object' && !Array.isArray(rawRecord.result) ? (rawRecord.result as Record<string, unknown>) : null;`,
|
|
14808
|
+
` const resultData = existingResult && 'data' in existingResult ? __dlLegacyResultData(existingResult.data) : __dlLegacyResultData(data);`,
|
|
14809
|
+
` const resultObject = resultData && typeof resultData === 'object' && !Array.isArray(resultData) ? (resultData as Record<string, unknown>) : {};`,
|
|
14810
|
+
` return {`,
|
|
14811
|
+
` ...(rawRecord ?? {}),`,
|
|
14812
|
+
` data,`,
|
|
14813
|
+
` result: { ...resultObject, ...(existingResult ?? {}), data: resultData },`,
|
|
14814
|
+
` raw,`,
|
|
14815
|
+
` toolResponse: { raw },`,
|
|
14816
|
+
` originalResult: result,`,
|
|
14817
|
+
` };`,
|
|
14818
|
+
`}`,
|
|
14819
|
+
``,
|
|
14820
|
+
`function __dlTemplate(value: unknown, row: Record<string, unknown>): unknown {`,
|
|
14821
|
+
` if (Array.isArray(value)) return value.map((entry) => __dlTemplate(entry, row));`,
|
|
14822
|
+
` if (value && typeof value === 'object') {`,
|
|
14823
|
+
` return Object.fromEntries(Object.entries(value as Record<string, unknown>).map(([key, entry]) => [key, __dlTemplate(entry, row)]));`,
|
|
14824
|
+
` }`,
|
|
14825
|
+
` if (typeof value !== 'string') return value;`,
|
|
14826
|
+
` const exact = value.match(/^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$/);`,
|
|
14827
|
+
` if (exact) return __dlGetByPath(row, exact[1] || '');`,
|
|
14828
|
+
` let rendered = '';`,
|
|
14829
|
+
` let cursor = 0;`,
|
|
14830
|
+
` while (cursor < value.length) {`,
|
|
14831
|
+
` const open = value.indexOf('{{', cursor);`,
|
|
14832
|
+
` if (open < 0) {`,
|
|
14833
|
+
` rendered += value.slice(cursor);`,
|
|
14834
|
+
` break;`,
|
|
14835
|
+
` }`,
|
|
14836
|
+
` const close = value.indexOf('}}', open + 2);`,
|
|
14837
|
+
` if (close < 0) {`,
|
|
14838
|
+
` rendered += value.slice(cursor);`,
|
|
14839
|
+
` break;`,
|
|
14840
|
+
` }`,
|
|
14841
|
+
` rendered += value.slice(cursor, open);`,
|
|
14842
|
+
` const path = value.slice(open + 2, close).trim();`,
|
|
14843
|
+
` const replacement = __dlGetByPath(row, path);`,
|
|
14844
|
+
` rendered += replacement === null || replacement === undefined ? '' : String(replacement);`,
|
|
14845
|
+
` cursor = close + 2;`,
|
|
14846
|
+
` }`,
|
|
14847
|
+
` return rendered;`,
|
|
14226
14848
|
`}`,
|
|
14227
14849
|
``,
|
|
14228
14850
|
`function __dlStableRowKey(row: Record<string, unknown>, index: number): string {`,
|
|
14229
|
-
` for (const key of ['id', 'ID', 'email', 'Email', 'linkedin_url', 'LINKEDIN_URL', 'domain', 'DOMAIN']) {`,
|
|
14851
|
+
` for (const key of ['id', 'ID', 'row_key', 'ROW_KEY', 'email', 'Email', 'linkedin_url', 'LINKEDIN_URL', 'domain', 'DOMAIN', 'name', 'Name']) {`,
|
|
14230
14852
|
` const value = row[key];`,
|
|
14231
14853
|
` if (__dlMeaningful(value)) return String(value);`,
|
|
14232
14854
|
` }`,
|
|
14233
14855
|
` return String(index);`,
|
|
14234
14856
|
`}`,
|
|
14235
14857
|
``,
|
|
14858
|
+
`function __dlScalarValue(value: unknown): unknown {`,
|
|
14859
|
+
` if (value && typeof value === 'object' && !Array.isArray(value)) {`,
|
|
14860
|
+
` const record = value as Record<string, unknown>;`,
|
|
14861
|
+
` if ('matched_result' in record) return __dlScalarValue(record.matched_result);`,
|
|
14862
|
+
` for (const key of ['value', 'email', 'output', 'result', 'data']) {`,
|
|
14863
|
+
` const nested = record[key];`,
|
|
14864
|
+
` if (__dlMeaningful(nested)) return __dlScalarValue(nested);`,
|
|
14865
|
+
` }`,
|
|
14866
|
+
` }`,
|
|
14867
|
+
` return value;`,
|
|
14868
|
+
`}`,
|
|
14869
|
+
``,
|
|
14236
14870
|
`function __dlFirstMeaningful(row: Record<string, unknown>, aliases: string[]): unknown {`,
|
|
14237
14871
|
` for (const alias of aliases) {`,
|
|
14238
14872
|
` const value = row[alias];`,
|
|
14239
|
-
` if (__dlMeaningful(value)) return value;`,
|
|
14873
|
+
` if (__dlMeaningful(value)) return __dlScalarValue(value);`,
|
|
14874
|
+
` }`,
|
|
14875
|
+
` return null;`,
|
|
14876
|
+
`}`,
|
|
14877
|
+
``,
|
|
14878
|
+
`function __dlFirstMeaningfulAlias(row: Record<string, unknown>, aliases: string[]): string | null {`,
|
|
14879
|
+
` for (const alias of aliases) {`,
|
|
14880
|
+
` if (__dlMeaningful(row[alias])) return alias;`,
|
|
14240
14881
|
` }`,
|
|
14241
14882
|
` return null;`,
|
|
14242
14883
|
`}`,
|
|
14243
14884
|
``,
|
|
14885
|
+
`function __dlListValue(value: unknown): unknown[] {`,
|
|
14886
|
+
` if (Array.isArray(value)) return value.filter(__dlMeaningful);`,
|
|
14887
|
+
` if (value && typeof value === 'object') {`,
|
|
14888
|
+
` const record = value as Record<string, unknown>;`,
|
|
14889
|
+
` if ('matched_result' in record) return __dlListValue(record.matched_result);`,
|
|
14890
|
+
` for (const key of ['result', 'value', 'data']) {`,
|
|
14891
|
+
` const nested = record[key];`,
|
|
14892
|
+
` const nestedList = __dlListValue(nested);`,
|
|
14893
|
+
` if (nestedList.length > 0) return nestedList;`,
|
|
14894
|
+
` }`,
|
|
14895
|
+
` return __dlMeaningful(value) ? [value] : [];`,
|
|
14896
|
+
` }`,
|
|
14897
|
+
` return __dlMeaningful(value) ? [value] : [];`,
|
|
14898
|
+
`}`,
|
|
14899
|
+
``,
|
|
14244
14900
|
`function __dlFirstMinResults(row: Record<string, unknown>, aliases: string[], minResults: number): unknown {`,
|
|
14245
14901
|
` const values: unknown[] = [];`,
|
|
14246
14902
|
` for (const alias of aliases) {`,
|
|
14247
|
-
`
|
|
14248
|
-
` if (
|
|
14249
|
-
` else if (__dlMeaningful(value)) values.push(value);`,
|
|
14250
|
-
` if (values.length >= minResults) return values.slice(0, minResults);`,
|
|
14903
|
+
` values.push(...__dlListValue(row[alias]));`,
|
|
14904
|
+
` if (values.length >= minResults) return values;`,
|
|
14251
14905
|
` }`,
|
|
14252
14906
|
` return values.length > 0 ? values : null;`,
|
|
14253
14907
|
`}`,
|
|
14254
14908
|
``,
|
|
14909
|
+
`function __dlContributingAliases(row: Record<string, unknown>, aliases: string[]): string[] | null {`,
|
|
14910
|
+
` const sources: string[] = [];`,
|
|
14911
|
+
` for (const alias of aliases) {`,
|
|
14912
|
+
` if (__dlListValue(row[alias]).length > 0) sources.push(alias);`,
|
|
14913
|
+
` }`,
|
|
14914
|
+
` return sources.length > 0 ? sources : null;`,
|
|
14915
|
+
`}`,
|
|
14916
|
+
``,
|
|
14255
14917
|
`function __dlWaterfallSatisfied(row: Record<string, unknown>, aliases: string[], minResults: number): boolean {`,
|
|
14256
14918
|
` let count = 0;`,
|
|
14257
14919
|
` for (const alias of aliases) {`,
|
|
14258
|
-
`
|
|
14259
|
-
` if (
|
|
14260
|
-
` else if (__dlMeaningful(value)) count += 1;`,
|
|
14261
|
-
` if (count >= Math.max(1, Math.trunc(minResults))) return true;`,
|
|
14920
|
+
` count += __dlListValue(row[alias]).length;`,
|
|
14921
|
+
` if (count >= __dlAtLeastOneInteger(minResults)) return true;`,
|
|
14262
14922
|
` }`,
|
|
14263
14923
|
` return false;`,
|
|
14264
14924
|
`}`,
|
|
14265
14925
|
``,
|
|
14266
|
-
`function
|
|
14926
|
+
`function __dlKeyPaths(key: string): string[] {`,
|
|
14927
|
+
` const normalized = String(key || '').trim();`,
|
|
14928
|
+
` if (normalized === 'email') return ['email', 'email_address', 'person.email', 'contact.email', 'data.email', 'result.data.email'];`,
|
|
14929
|
+
` if (normalized === 'personal_email') return ['personal_email', 'email', 'email_address', 'data.personal_email', 'data.email'];`,
|
|
14930
|
+
` if (normalized === 'phone') return ['phone', 'phone_number', 'mobile_phone', 'mobile_phone_number', 'data.phone'];`,
|
|
14931
|
+
` if (normalized === 'linkedin') return ['linkedin', 'linkedin_url', 'linkedin_profile', 'profile_url', 'person.linkedin', 'person.linkedin_url'];`,
|
|
14932
|
+
` if (normalized === 'full_name') return ['full_name', 'name', 'person.full_name', 'person.name'];`,
|
|
14933
|
+
` if (normalized === 'first_name') return ['first_name', 'person.first_name'];`,
|
|
14934
|
+
` if (normalized === 'last_name') return ['last_name', 'person.last_name'];`,
|
|
14935
|
+
` if (normalized === 'title') return ['title', 'job_title', 'current_title', 'headline', 'person.title'];`,
|
|
14936
|
+
` if (normalized === 'company_name') return ['company_name', 'company.name', 'organization.name'];`,
|
|
14937
|
+
` if (normalized === 'company_domain') return ['company_domain', 'domain', 'company.domain', 'organization.domain'];`,
|
|
14938
|
+
` if (normalized === 'status') return ['status', 'verdict', 'state'];`,
|
|
14939
|
+
` if (normalized === 'email_status') return ['email_status', 'status', 'verdict', 'data.email_status'];`,
|
|
14940
|
+
` return [normalized];`,
|
|
14941
|
+
`}`,
|
|
14942
|
+
``,
|
|
14943
|
+
`function __dlSelectorKeys(selector: unknown): string[] | null {`,
|
|
14944
|
+
` if (!selector || typeof selector !== 'object' || Array.isArray(selector)) return null;`,
|
|
14945
|
+
` const keys = (selector as { keys?: unknown }).keys;`,
|
|
14946
|
+
` if (!Array.isArray(keys) || keys.length === 0) return null;`,
|
|
14947
|
+
` const out: string[] = [];`,
|
|
14948
|
+
` for (const key of keys) {`,
|
|
14949
|
+
` if (typeof key === 'string' && key.trim()) out.push(key.trim());`,
|
|
14950
|
+
` }`,
|
|
14951
|
+
` return out.length > 0 ? out : null;`,
|
|
14952
|
+
`}`,
|
|
14953
|
+
``,
|
|
14954
|
+
`function __dlFirstByPaths(payload: unknown, paths: string[] | string): unknown {`,
|
|
14955
|
+
` const candidates = Array.isArray(paths) ? paths : [paths];`,
|
|
14956
|
+
` for (const path of candidates) {`,
|
|
14957
|
+
` for (const candidate of __dlRawToolCandidates(payload)) {`,
|
|
14958
|
+
` const value = __dlGetByPath(candidate, String(path));`,
|
|
14959
|
+
` if (__dlMeaningful(value)) return value;`,
|
|
14960
|
+
` }`,
|
|
14961
|
+
` }`,
|
|
14962
|
+
` return null;`,
|
|
14963
|
+
`}`,
|
|
14964
|
+
``,
|
|
14965
|
+
`function __dlExtractTarget(payload: unknown, key: string): unknown {`,
|
|
14966
|
+
` return __dlFirstByPaths(payload, __dlKeyPaths(key));`,
|
|
14967
|
+
`}`,
|
|
14968
|
+
``,
|
|
14969
|
+
`function __dlExtractedValue(result: unknown, key: string): unknown {`,
|
|
14970
|
+
` if (!result || typeof result !== 'object' || Array.isArray(result)) return undefined;`,
|
|
14971
|
+
` const extractedValues = (result as Record<string, unknown>).extractedValues;`,
|
|
14972
|
+
` if (!extractedValues || typeof extractedValues !== 'object' || Array.isArray(extractedValues)) return undefined;`,
|
|
14973
|
+
` const accessor = (extractedValues as Record<string, unknown>)[key];`,
|
|
14974
|
+
` if (!accessor || typeof accessor !== 'object' || Array.isArray(accessor)) return undefined;`,
|
|
14975
|
+
` const record = accessor as Record<string, unknown>;`,
|
|
14976
|
+
` const get = record.get;`,
|
|
14977
|
+
` if (typeof get === 'function') {`,
|
|
14978
|
+
` try {`,
|
|
14979
|
+
` return (get as () => unknown)();`,
|
|
14980
|
+
` } catch {`,
|
|
14981
|
+
` return undefined;`,
|
|
14982
|
+
` }`,
|
|
14983
|
+
` }`,
|
|
14984
|
+
` return record.value;`,
|
|
14985
|
+
`}`,
|
|
14986
|
+
``,
|
|
14987
|
+
`function __dlLegacyExtractorPayload(payload: unknown, raw: unknown): unknown {`,
|
|
14988
|
+
` if (payload === undefined || payload === null) return raw;`,
|
|
14989
|
+
` if (payload && typeof payload === 'object' && !Array.isArray(payload) && Object.keys(payload as Record<string, unknown>).length === 0) return raw;`,
|
|
14990
|
+
` return payload;`,
|
|
14991
|
+
`}`,
|
|
14992
|
+
``,
|
|
14993
|
+
`function __dlLegacyMatchedEnvelope(value: unknown, raw: unknown): unknown {`,
|
|
14994
|
+
` if (value && typeof value === 'object' && !Array.isArray(value) && 'matched_result' in (value as Record<string, unknown>)) return value;`,
|
|
14995
|
+
` const legacyOutput = __dlLegacyOutputData(undefined, raw) as Record<string, unknown>;`,
|
|
14996
|
+
` const legacyResult = legacyOutput.result && typeof legacyOutput.result === 'object' && !Array.isArray(legacyOutput.result) ? legacyOutput.result : raw;`,
|
|
14997
|
+
` return { matched_result: value, result: legacyResult };`,
|
|
14998
|
+
`}`,
|
|
14999
|
+
``,
|
|
15000
|
+
`function __dlString(value: unknown): string | null {`,
|
|
15001
|
+
` return typeof value === 'string' && value.trim() ? value.trim() : null;`,
|
|
15002
|
+
`}`,
|
|
15003
|
+
``,
|
|
15004
|
+
`// NOTE: email_status is NOT normalized here. It is materialized once by the`,
|
|
15005
|
+
`// provider's emailStatus({...}) contract via buildEmailStatus and read back`,
|
|
15006
|
+
`// through __dlExtractedValue(result, 'email_status') below. There is no`,
|
|
15007
|
+
`// legacy string coarsening \u2014 see CONTEXT.md "Provider Email Status Contract".`,
|
|
15008
|
+
``,
|
|
15009
|
+
`function __dlListPathCandidates(selector: unknown): string[] {`,
|
|
15010
|
+
` const paths: string[] = [];`,
|
|
15011
|
+
` const push = (path: string) => { if (path && !paths.includes(path)) paths.push(path); };`,
|
|
15012
|
+
` if (Array.isArray(selector)) {`,
|
|
15013
|
+
` for (const path of selector) push(String(path));`,
|
|
15014
|
+
` } else if (typeof selector === 'string') {`,
|
|
15015
|
+
` push(selector);`,
|
|
15016
|
+
` }`,
|
|
15017
|
+
` for (const path of ['data', 'data.people', 'data.persons', 'data.contacts', 'data.results', 'data.leads', 'data.items', 'result.data', 'result.people', 'result.persons', 'result.contacts', 'result.results', 'result.leads', 'result.items', 'people', 'persons', 'contacts', 'results', 'leads', 'items', 'output.body', 'body']) push(path);`,
|
|
15018
|
+
` return paths;`,
|
|
15019
|
+
`}`,
|
|
15020
|
+
``,
|
|
15021
|
+
`function __dlFindList(payload: unknown, selector: unknown): unknown[] {`,
|
|
15022
|
+
` if (Array.isArray(payload)) return payload;`,
|
|
15023
|
+
` for (const path of __dlListPathCandidates(selector)) {`,
|
|
15024
|
+
` for (const candidate of __dlRawToolCandidates(payload)) {`,
|
|
15025
|
+
` const value = __dlGetByPath(candidate, path);`,
|
|
15026
|
+
` if (Array.isArray(value)) return value;`,
|
|
15027
|
+
` }`,
|
|
15028
|
+
` }`,
|
|
15029
|
+
` const queue = __dlRawToolCandidates(payload);`,
|
|
15030
|
+
` const seen: unknown[] = [];`,
|
|
15031
|
+
` for (let index = 0; index < queue.length; index += 1) {`,
|
|
15032
|
+
` const current = queue[index];`,
|
|
15033
|
+
` if (!current || typeof current !== 'object' || seen.includes(current)) continue;`,
|
|
15034
|
+
` seen.push(current);`,
|
|
15035
|
+
` for (const value of Object.values(current as Record<string, unknown>)) {`,
|
|
15036
|
+
` if (Array.isArray(value)) return value;`,
|
|
15037
|
+
` if (value && typeof value === 'object') queue.push(value);`,
|
|
15038
|
+
` }`,
|
|
15039
|
+
` }`,
|
|
15040
|
+
` return [];`,
|
|
15041
|
+
`}`,
|
|
15042
|
+
``,
|
|
15043
|
+
`function __dlDeriveFullName(row: Record<string, unknown>): string | null {`,
|
|
15044
|
+
` const existing = __dlFirstByPaths(row, ['full_name', 'name']);`,
|
|
15045
|
+
` if (typeof existing === 'string' && existing.trim()) return existing.trim();`,
|
|
15046
|
+
` const first = __dlFirstByPaths(row, ['first_name', 'firstName']);`,
|
|
15047
|
+
` const last = __dlFirstByPaths(row, ['last_name', 'lastName']);`,
|
|
15048
|
+
` const parts = [first, last].filter((part): part is string => typeof part === 'string').map((part) => part.trim()).filter(Boolean);`,
|
|
15049
|
+
` return parts.length > 0 ? parts.join(' ') : null;`,
|
|
15050
|
+
`}`,
|
|
15051
|
+
``,
|
|
15052
|
+
`function __dlProjectListRows(rows: unknown[], keys: string[], payload: unknown): Array<Record<string, unknown>> {`,
|
|
15053
|
+
` const projected: Array<Record<string, unknown>> = [];`,
|
|
15054
|
+
` for (const row of rows) {`,
|
|
15055
|
+
` const record = row && typeof row === 'object' && !Array.isArray(row) ? (row as Record<string, unknown>) : { value: row };`,
|
|
15056
|
+
` const out: Record<string, unknown> = {};`,
|
|
15057
|
+
` for (const key of keys) {`,
|
|
15058
|
+
` let value = __dlExtractTarget(record, key);`,
|
|
15059
|
+
` if (!__dlMeaningful(value) && key === 'full_name') value = __dlDeriveFullName(record);`,
|
|
15060
|
+
` if (!__dlMeaningful(value)) value = __dlExtractTarget(payload, key);`,
|
|
15061
|
+
` out[key] = value === undefined ? null : value;`,
|
|
15062
|
+
` }`,
|
|
15063
|
+
` if (Object.values(out).some(__dlMeaningful)) projected.push(out);`,
|
|
15064
|
+
` }`,
|
|
15065
|
+
` return projected;`,
|
|
15066
|
+
`}`,
|
|
15067
|
+
``,
|
|
15068
|
+
`type __DlExtractorHelpers = { row: Record<string, unknown>; result: unknown; data: unknown; raw: unknown; pick: (paths: string[] | string) => unknown; extract: (...args: unknown[]) => unknown; extractList: (...args: unknown[]) => unknown[]; target: (paths: string[] | string) => unknown; get: (path: string) => unknown };`,
|
|
15069
|
+
``,
|
|
15070
|
+
`function __dlErrorMessage(error: unknown): string {`,
|
|
15071
|
+
` if (error instanceof Error && error.message) return error.message;`,
|
|
15072
|
+
` if (typeof error === 'string' && error.trim()) return error.trim();`,
|
|
15073
|
+
` return 'Extractor failed';`,
|
|
15074
|
+
`}`,
|
|
15075
|
+
``,
|
|
15076
|
+
`function __dlExtractorFailure(error: unknown): unknown {`,
|
|
15077
|
+
` const message = __dlErrorMessage(error);`,
|
|
15078
|
+
` return { matched_result: null, result: { error: message, message } };`,
|
|
15079
|
+
`}`,
|
|
15080
|
+
``,
|
|
15081
|
+
`function __dlExtract(alias: string, result: unknown, row: Record<string, unknown>, extractor: ((args: __DlExtractorHelpers) => unknown) | null, legacyEnvelope = false): unknown {`,
|
|
14267
15082
|
` const raw = __dlRawToolOutput(result);`,
|
|
14268
15083
|
` if (!extractor) return raw;`,
|
|
14269
15084
|
` const pick = (paths: string[] | string) => {`,
|
|
14270
15085
|
` const candidates = Array.isArray(paths) ? paths : [paths];`,
|
|
14271
15086
|
` for (const path of candidates) {`,
|
|
14272
|
-
`
|
|
14273
|
-
`
|
|
15087
|
+
` if (typeof path === 'string') {`,
|
|
15088
|
+
` const extractedValue = __dlExtractedValue(result, path);`,
|
|
15089
|
+
` if (__dlMeaningful(extractedValue)) return extractedValue;`,
|
|
15090
|
+
` }`,
|
|
15091
|
+
` for (const candidate of __dlRawToolCandidates(raw)) {`,
|
|
15092
|
+
` const value = __dlGetByPath(candidate, String(path));`,
|
|
15093
|
+
` if (__dlMeaningful(value)) return value;`,
|
|
15094
|
+
` }`,
|
|
14274
15095
|
` }`,
|
|
14275
15096
|
` return null;`,
|
|
14276
15097
|
` };`,
|
|
14277
|
-
` const
|
|
14278
|
-
`
|
|
14279
|
-
`
|
|
15098
|
+
` const extract = (...args: unknown[]): unknown => {`,
|
|
15099
|
+
` const payload = args.length >= 3 ? __dlLegacyExtractorPayload(args[1], raw) : raw;`,
|
|
15100
|
+
` const selector = args.length >= 3 ? args[2] : args[0];`,
|
|
15101
|
+
` if (selector === undefined) return payload;`,
|
|
15102
|
+
` const keys = __dlSelectorKeys(selector);`,
|
|
15103
|
+
` if (keys) return Object.fromEntries(keys.map((key) => [key, __dlExtractTarget(payload, key) ?? null]));`,
|
|
15104
|
+
` if (Array.isArray(selector)) return __dlFirstByPaths(payload, selector.map(String));`,
|
|
15105
|
+
` if (typeof selector === 'string') {`,
|
|
15106
|
+
` const extractedValue = __dlExtractedValue(result, selector);`,
|
|
15107
|
+
` if (__dlMeaningful(extractedValue)) return __dlLegacyMatchedEnvelope(extractedValue, payload);`,
|
|
15108
|
+
` return __dlExtractTarget(payload, selector) ?? __dlFirstByPaths(payload, selector);`,
|
|
15109
|
+
` }`,
|
|
15110
|
+
` return selector;`,
|
|
15111
|
+
` };`,
|
|
15112
|
+
` const extractList = (...args: unknown[]): unknown[] => {`,
|
|
15113
|
+
` const payload = args.length >= 3 ? __dlLegacyExtractorPayload(args[1], raw) : raw;`,
|
|
15114
|
+
` const selector = args.length >= 3 ? args[2] : args[0];`,
|
|
15115
|
+
` const rows = __dlFindList(payload, selector);`,
|
|
15116
|
+
` const keys = __dlSelectorKeys(selector);`,
|
|
15117
|
+
` return keys ? __dlProjectListRows(rows, keys, payload) : rows;`,
|
|
15118
|
+
` };`,
|
|
15119
|
+
` const get = (path: string): unknown => __dlExtractedValue(result, path) ?? __dlFirstByPaths(raw, path);`,
|
|
15120
|
+
` let resolved: unknown;`,
|
|
15121
|
+
` try {`,
|
|
15122
|
+
` const extracted = extractor({ row, result, data: raw, raw, pick, extract, extractList, target: pick, get });`,
|
|
15123
|
+
` resolved = typeof extracted === 'function' ? (extracted as (outputData: unknown) => unknown)(__dlLegacyOutputData(result, raw)) : extracted;`,
|
|
15124
|
+
` } catch (error) {`,
|
|
15125
|
+
` return __dlExtractorFailure(error);`,
|
|
15126
|
+
` }`,
|
|
15127
|
+
` if (resolved && typeof resolved === 'object' && !Array.isArray(resolved) && alias in (resolved as Record<string, unknown>)) {`,
|
|
15128
|
+
` const aliasValue = (resolved as Record<string, unknown>)[alias];`,
|
|
15129
|
+
` return legacyEnvelope && __dlMeaningful(aliasValue) ? __dlLegacyMatchedEnvelope(aliasValue, raw) : aliasValue;`,
|
|
15130
|
+
` }`,
|
|
15131
|
+
` if (Array.isArray(resolved)) return __dlLegacyMatchedEnvelope(resolved, raw);`,
|
|
15132
|
+
` if ((resolved === null || resolved === undefined) && __dlErrorPayload(raw)) return raw;`,
|
|
15133
|
+
` if (legacyEnvelope && __dlMeaningful(resolved)) return __dlLegacyMatchedEnvelope(resolved, raw);`,
|
|
15134
|
+
` return resolved === undefined ? raw : resolved;`,
|
|
15135
|
+
`}`,
|
|
15136
|
+
``,
|
|
15137
|
+
`function __dlMergeContextRecord(existing: unknown, defaults: Record<string, unknown>): Record<string, unknown> {`,
|
|
15138
|
+
` if (!existing || typeof existing !== 'object' || Array.isArray(existing)) return { ...defaults };`,
|
|
15139
|
+
` return { ...defaults, ...(existing as Record<string, unknown>) };`,
|
|
15140
|
+
`}`,
|
|
15141
|
+
``,
|
|
15142
|
+
`function __dlRuntimePayload(tool: string, payload: Record<string, unknown>, row: Record<string, unknown>): Record<string, unknown> {`,
|
|
15143
|
+
` if (tool !== 'run_javascript') return payload;`,
|
|
15144
|
+
` return {`,
|
|
15145
|
+
` ...payload,`,
|
|
15146
|
+
` row: __dlMergeContextRecord(payload.row, row),`,
|
|
15147
|
+
` input: __dlMergeContextRecord(payload.input, row),`,
|
|
15148
|
+
` context: __dlMergeContextRecord(payload.context, row),`,
|
|
15149
|
+
` };`,
|
|
15150
|
+
`}`,
|
|
15151
|
+
``,
|
|
15152
|
+
`function __dlAliasCandidates(alias: string): string[] {`,
|
|
15153
|
+
` const aliases: string[] = [];`,
|
|
15154
|
+
` for (const candidate of [alias, alias.replace(/-/g, '_'), alias.replace(/_/g, '-')]) {`,
|
|
15155
|
+
` if (candidate && !aliases.includes(candidate)) aliases.push(candidate);`,
|
|
15156
|
+
` }`,
|
|
15157
|
+
` return aliases;`,
|
|
15158
|
+
`}`,
|
|
15159
|
+
``,
|
|
15160
|
+
`function __dlPlayResultValue(alias: string, result: unknown): unknown {`,
|
|
15161
|
+
` if (!result || typeof result !== 'object' || Array.isArray(result)) return result;`,
|
|
15162
|
+
` const record = result as Record<string, unknown>;`,
|
|
15163
|
+
` const aliases = __dlAliasCandidates(alias);`,
|
|
15164
|
+
` for (const key of aliases) {`,
|
|
15165
|
+
` if (key in record && __dlMeaningful(record[key])) return __dlScalarValue(record[key]);`,
|
|
14280
15166
|
` }`,
|
|
14281
|
-
`
|
|
15167
|
+
` const values = Object.values(record).filter(__dlMeaningful);`,
|
|
15168
|
+
` if (values.length === 1) return __dlScalarValue(values[0]);`,
|
|
15169
|
+
` return result;`,
|
|
14282
15170
|
`}`,
|
|
14283
15171
|
``,
|
|
14284
|
-
`async function __dlRunCommand(input: { alias: string; callId: string; tool: string; payload: Record<string, unknown>; extract: ((args:
|
|
15172
|
+
`async function __dlRunCommand(input: { alias: string; callId: string; tool: string; payload: Record<string, unknown>; extract: ((args: __DlExtractorHelpers) => 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; legacyEnvelope?: boolean }): Promise<unknown> {`,
|
|
14285
15173
|
` if (input.runIf) {`,
|
|
14286
15174
|
` const shouldRun = input.runIf(input.row);`,
|
|
14287
15175
|
` if (!shouldRun) return null;`,
|
|
14288
15176
|
` }`,
|
|
15177
|
+
` const payload = __dlRuntimePayload(input.tool, __dlTemplate(input.payload, input.row) as Record<string, unknown>, input.row);`,
|
|
14289
15178
|
` const result = await input.stepCtx.tools.execute({`,
|
|
14290
15179
|
` id: input.callId,`,
|
|
14291
15180
|
` tool: input.tool,`,
|
|
14292
|
-
` input:
|
|
15181
|
+
` input: payload,`,
|
|
14293
15182
|
` ...(input.description ? { description: input.description } : {}),`,
|
|
14294
|
-
` ...(input.force ? { staleAfterSeconds:
|
|
15183
|
+
` ...(input.force ? { staleAfterSeconds: 1 } : {}),`,
|
|
14295
15184
|
` });`,
|
|
14296
|
-
` return __dlExtract(input.alias, result, input.row, input.extract);`,
|
|
15185
|
+
` return __dlExtract(input.alias, result, input.row, input.extract, Boolean(input.legacyEnvelope));`,
|
|
14297
15186
|
`}`
|
|
14298
15187
|
].join("\n");
|
|
14299
15188
|
}
|
|
14300
15189
|
|
|
14301
15190
|
// src/cli/commands/enrich.ts
|
|
15191
|
+
var ENRICH_EXPORT_PAGE_SIZE = 5e3;
|
|
15192
|
+
var EXIT_SERVER2 = 5;
|
|
15193
|
+
var ENRICH_DEBUG_T0 = Date.now();
|
|
14302
15194
|
var PLAN_SHAPING_OPTION_NAMES = [
|
|
14303
15195
|
"with",
|
|
14304
15196
|
"withWaterfall",
|
|
14305
15197
|
"minResults",
|
|
14306
15198
|
"endWaterfall"
|
|
14307
15199
|
];
|
|
14308
|
-
var ENRICH_DEPRECATION_NOTICE = {
|
|
14309
|
-
status: "deprecated",
|
|
14310
|
-
message: "The enrich compatibility command is deprecated. This run generates a temporary .play.ts file and executes it through plays run.",
|
|
14311
|
-
generatedPlayFile: "Temporary compatibility play file; deleted after the command exits.",
|
|
14312
|
-
printGeneratedPlayCommand: "deepline enrich <same args> --dry-run > enrich.play.ts",
|
|
14313
|
-
recommendedCommand: `deepline plays run enrich.play.ts --input '{"file":"<input.csv>"}'`
|
|
14314
|
-
};
|
|
14315
|
-
var ENRICH_DEPRECATION_TEXT = `${ENRICH_DEPRECATION_NOTICE.message} Print the generated play with: ${ENRICH_DEPRECATION_NOTICE.printGeneratedPlayCommand}. Then run: ${ENRICH_DEPRECATION_NOTICE.recommendedCommand}
|
|
14316
|
-
`;
|
|
14317
15200
|
function optionWasProvided(args, ...flags) {
|
|
14318
15201
|
return args.some(
|
|
14319
15202
|
(arg) => flags.some((flag) => arg === flag || arg.startsWith(`${flag}=`))
|
|
@@ -14325,9 +15208,103 @@ function normalizeAlias2(value) {
|
|
|
14325
15208
|
function hasPlanShapingArgs(args) {
|
|
14326
15209
|
return optionWasProvided(args, "--with") || optionWasProvided(args, "--with-waterfall") || optionWasProvided(args, "--min-results") || optionWasProvided(args, "--end-waterfall");
|
|
14327
15210
|
}
|
|
14328
|
-
function
|
|
14329
|
-
|
|
14330
|
-
|
|
15211
|
+
function enrichDebugEnabled(env = process.env) {
|
|
15212
|
+
const raw = String(env.DEEPLINE_DEBUG_ENRICH ?? "").trim().toLowerCase();
|
|
15213
|
+
if (["1", "true", "yes", "on"].includes(raw)) {
|
|
15214
|
+
return true;
|
|
15215
|
+
}
|
|
15216
|
+
const nodeEnv = String(env.NODE_ENV ?? "").trim().toLowerCase();
|
|
15217
|
+
const deeplineEnv = String(env.DEEPLINE_ENV ?? "").trim().toLowerCase();
|
|
15218
|
+
return nodeEnv === "development" || ["dev", "development"].includes(deeplineEnv);
|
|
15219
|
+
}
|
|
15220
|
+
function decodeStringLiteral(raw) {
|
|
15221
|
+
try {
|
|
15222
|
+
const parsed = JSON.parse(raw);
|
|
15223
|
+
return typeof parsed === "string" ? parsed : null;
|
|
15224
|
+
} catch {
|
|
15225
|
+
const quote = raw[0];
|
|
15226
|
+
if ((quote === "'" || quote === '"') && raw[raw.length - 1] === quote) {
|
|
15227
|
+
return raw.slice(1, -1).replace(/\\'/g, "'").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
15228
|
+
}
|
|
15229
|
+
return null;
|
|
15230
|
+
}
|
|
15231
|
+
}
|
|
15232
|
+
function addStringArrayLiteralTargets(targets, arrayLiteral) {
|
|
15233
|
+
for (const match of arrayLiteral.matchAll(/(["'])(?:\\.|(?!\1).)*\1/g)) {
|
|
15234
|
+
const parsed = decodeStringLiteral(match[0] ?? "");
|
|
15235
|
+
if (parsed?.trim()) {
|
|
15236
|
+
targets.add(parsed.trim());
|
|
15237
|
+
}
|
|
15238
|
+
}
|
|
15239
|
+
}
|
|
15240
|
+
function extractExtractorTargetKeys(source) {
|
|
15241
|
+
const targets = /* @__PURE__ */ new Set();
|
|
15242
|
+
for (const match of source.matchAll(/\bkeys\s*:\s*(\[[^\]]*\])/g)) {
|
|
15243
|
+
addStringArrayLiteralTargets(targets, match[1] ?? "");
|
|
15244
|
+
}
|
|
15245
|
+
for (const match of source.matchAll(
|
|
15246
|
+
/\btarget\s*\(\s*(["'][^"']+["'])\s*\)/g
|
|
15247
|
+
)) {
|
|
15248
|
+
const parsed = decodeStringLiteral(match[1] ?? "");
|
|
15249
|
+
if (parsed?.trim()) {
|
|
15250
|
+
targets.add(parsed.trim());
|
|
15251
|
+
}
|
|
15252
|
+
}
|
|
15253
|
+
for (const match of source.matchAll(
|
|
15254
|
+
/\bextract\s*\(\s*["'][^"']+["']\s*,[^,]*,\s*(["'][^"']+["'])\s*\)/g
|
|
15255
|
+
)) {
|
|
15256
|
+
const parsed = decodeStringLiteral(match[1] ?? "");
|
|
15257
|
+
if (parsed?.trim()) {
|
|
15258
|
+
targets.add(parsed.trim());
|
|
15259
|
+
}
|
|
15260
|
+
}
|
|
15261
|
+
return [...targets].sort();
|
|
15262
|
+
}
|
|
15263
|
+
function flattenEnrichStepCommands(commands) {
|
|
15264
|
+
const steps = [];
|
|
15265
|
+
for (const command of commands) {
|
|
15266
|
+
if ("with_waterfall" in command) {
|
|
15267
|
+
steps.push(...flattenEnrichStepCommands(command.commands));
|
|
15268
|
+
continue;
|
|
15269
|
+
}
|
|
15270
|
+
if (!command.disabled) {
|
|
15271
|
+
steps.push(command);
|
|
15272
|
+
}
|
|
15273
|
+
}
|
|
15274
|
+
return steps;
|
|
15275
|
+
}
|
|
15276
|
+
function buildEnrichDebugValidationLines(config) {
|
|
15277
|
+
return flattenEnrichStepCommands(config.commands).filter(
|
|
15278
|
+
(command) => typeof command.extract_js === "string" && command.extract_js.trim()
|
|
15279
|
+
).map((command) => {
|
|
15280
|
+
const source = command.extract_js ?? "";
|
|
15281
|
+
const targets = extractExtractorTargetKeys(source);
|
|
15282
|
+
const mode = /\bextractList\s*\(/.test(source) ? "list" : "scalar";
|
|
15283
|
+
return [
|
|
15284
|
+
"validate extractor",
|
|
15285
|
+
`column=${command.alias}`,
|
|
15286
|
+
`tool_id=${command.tool || "(none)"}`,
|
|
15287
|
+
`mode=${mode}`,
|
|
15288
|
+
"has_result_sample=false",
|
|
15289
|
+
"sample_keys=<none>",
|
|
15290
|
+
`targets=${JSON.stringify(targets)}`
|
|
15291
|
+
].join(" ");
|
|
15292
|
+
});
|
|
15293
|
+
}
|
|
15294
|
+
function emitEnrichDebug(message) {
|
|
15295
|
+
if (!enrichDebugEnabled()) {
|
|
15296
|
+
return;
|
|
15297
|
+
}
|
|
15298
|
+
const now = /* @__PURE__ */ new Date();
|
|
15299
|
+
const elapsedMs = Date.now() - ENRICH_DEBUG_T0;
|
|
15300
|
+
process.stderr.write(
|
|
15301
|
+
`[deepline:enrich] ${now.toISOString()} +${elapsedMs}ms ${message}
|
|
15302
|
+
`
|
|
15303
|
+
);
|
|
15304
|
+
}
|
|
15305
|
+
function emitEnrichDebugValidationLines(config) {
|
|
15306
|
+
for (const line of buildEnrichDebugValidationLines(config)) {
|
|
15307
|
+
emitEnrichDebug(line);
|
|
14331
15308
|
}
|
|
14332
15309
|
}
|
|
14333
15310
|
function expandAtFilePath(rawPath) {
|
|
@@ -14464,15 +15441,18 @@ async function buildPlanArgs(args) {
|
|
|
14464
15441
|
"--csv",
|
|
14465
15442
|
"--output",
|
|
14466
15443
|
"--config",
|
|
15444
|
+
"--name",
|
|
14467
15445
|
"--rows",
|
|
14468
|
-
"--with-force"
|
|
15446
|
+
"--with-force",
|
|
15447
|
+
"--timeout"
|
|
14469
15448
|
]);
|
|
14470
15449
|
const localBooleanOptions = /* @__PURE__ */ new Set([
|
|
14471
15450
|
"--dry-run",
|
|
14472
15451
|
"--json",
|
|
14473
15452
|
"--force",
|
|
14474
15453
|
"--all",
|
|
14475
|
-
"--in-place"
|
|
15454
|
+
"--in-place",
|
|
15455
|
+
"--no-open"
|
|
14476
15456
|
]);
|
|
14477
15457
|
const planArgs = [];
|
|
14478
15458
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -14538,7 +15518,7 @@ async function assertSafeOutputPath(inputCsv, outputPath) {
|
|
|
14538
15518
|
const output2 = (0, import_node_path13.resolve)(outputPath);
|
|
14539
15519
|
if (input2 === output2) {
|
|
14540
15520
|
throw new Error(
|
|
14541
|
-
"--output must be
|
|
15521
|
+
"--input and --output must be different files when not using --in-place."
|
|
14542
15522
|
);
|
|
14543
15523
|
}
|
|
14544
15524
|
try {
|
|
@@ -14548,7 +15528,7 @@ async function assertSafeOutputPath(inputCsv, outputPath) {
|
|
|
14548
15528
|
]);
|
|
14549
15529
|
if (inputInfo.dev === outputInfo.dev && inputInfo.ino === outputInfo.ino) {
|
|
14550
15530
|
throw new Error(
|
|
14551
|
-
"--output must be
|
|
15531
|
+
"--input and --output must be different files when not using --in-place."
|
|
14552
15532
|
);
|
|
14553
15533
|
}
|
|
14554
15534
|
} catch (error) {
|
|
@@ -14562,6 +15542,18 @@ async function assertSafeOutputPath(inputCsv, outputPath) {
|
|
|
14562
15542
|
throw error;
|
|
14563
15543
|
}
|
|
14564
15544
|
}
|
|
15545
|
+
async function regularFileExists(path) {
|
|
15546
|
+
try {
|
|
15547
|
+
const info = await (0, import_promises5.stat)((0, import_node_path13.resolve)(path));
|
|
15548
|
+
return info.isFile();
|
|
15549
|
+
} catch (error) {
|
|
15550
|
+
const code = error && typeof error === "object" ? error.code : void 0;
|
|
15551
|
+
if (code === "ENOENT") {
|
|
15552
|
+
return false;
|
|
15553
|
+
}
|
|
15554
|
+
throw error;
|
|
15555
|
+
}
|
|
15556
|
+
}
|
|
14565
15557
|
async function readConfig(path) {
|
|
14566
15558
|
const source = await (0, import_promises5.readFile)((0, import_node_path13.resolve)(path), "utf8");
|
|
14567
15559
|
let parsed;
|
|
@@ -14584,27 +15576,30 @@ function parseRows(value, all) {
|
|
|
14584
15576
|
const trimmed = value.trim();
|
|
14585
15577
|
const range = trimmed.match(/^(\d*)\s*:\s*(\d*)$/);
|
|
14586
15578
|
if (range) {
|
|
14587
|
-
if (!range[1]
|
|
15579
|
+
if (!range[1]) {
|
|
14588
15580
|
throw new Error(
|
|
14589
|
-
"--rows must be a zero-based row number or
|
|
15581
|
+
"--rows must be a zero-based row number or inclusive range like 0:10."
|
|
14590
15582
|
);
|
|
14591
15583
|
}
|
|
14592
15584
|
const start = range[1] ? Number.parseInt(range[1], 10) : 0;
|
|
14593
15585
|
const end = range[2] ? Number.parseInt(range[2], 10) : null;
|
|
15586
|
+
if (end !== null && end < start) {
|
|
15587
|
+
throw new Error("Invalid --rows range: end must be >= start.");
|
|
15588
|
+
}
|
|
14594
15589
|
return { rowStart: start, rowEnd: end };
|
|
14595
15590
|
}
|
|
14596
15591
|
if (!/^\d+$/.test(trimmed)) {
|
|
14597
15592
|
throw new Error(
|
|
14598
|
-
"--rows must be a zero-based row number or
|
|
15593
|
+
"--rows must be a zero-based row number or inclusive range like 0:10."
|
|
14599
15594
|
);
|
|
14600
15595
|
}
|
|
14601
15596
|
const single = Number.parseInt(trimmed, 10);
|
|
14602
15597
|
if (!Number.isFinite(single) || single < 0) {
|
|
14603
15598
|
throw new Error(
|
|
14604
|
-
"--rows must be a zero-based row number or
|
|
15599
|
+
"--rows must be a zero-based row number or inclusive range like 0:10."
|
|
14605
15600
|
);
|
|
14606
15601
|
}
|
|
14607
|
-
return { rowStart: single, rowEnd: single
|
|
15602
|
+
return { rowStart: single, rowEnd: single };
|
|
14608
15603
|
}
|
|
14609
15604
|
function summarizePlan(config, playSource) {
|
|
14610
15605
|
const steps = [];
|
|
@@ -14686,9 +15681,9 @@ function parseWithForceAliases(values) {
|
|
|
14686
15681
|
return aliases;
|
|
14687
15682
|
}
|
|
14688
15683
|
function resolveForceAliases(config, options) {
|
|
14689
|
-
const { allAliases,
|
|
15684
|
+
const { allAliases, waterfallGroups } = collectCommandAliases(config);
|
|
14690
15685
|
if (options.force) {
|
|
14691
|
-
return new Set(
|
|
15686
|
+
return new Set(allAliases);
|
|
14692
15687
|
}
|
|
14693
15688
|
const requested = parseWithForceAliases(options.withForce);
|
|
14694
15689
|
const unknown = [...requested].filter((alias) => !allAliases.has(alias));
|
|
@@ -14697,62 +15692,701 @@ function resolveForceAliases(config, options) {
|
|
|
14697
15692
|
`--with-force references unknown --with column alias(es): ${unknown.sort().join(", ")}.`
|
|
14698
15693
|
);
|
|
14699
15694
|
}
|
|
14700
|
-
const resolved = /* @__PURE__ */ new Set();
|
|
14701
|
-
for (const alias of requested) {
|
|
14702
|
-
const children = waterfallGroups.get(alias);
|
|
14703
|
-
if (children) {
|
|
14704
|
-
|
|
14705
|
-
|
|
15695
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
15696
|
+
for (const alias of requested) {
|
|
15697
|
+
const children = waterfallGroups.get(alias);
|
|
15698
|
+
if (children) {
|
|
15699
|
+
resolved.add(alias);
|
|
15700
|
+
for (const child of children) {
|
|
15701
|
+
resolved.add(child);
|
|
15702
|
+
}
|
|
15703
|
+
} else {
|
|
15704
|
+
resolved.add(alias);
|
|
15705
|
+
}
|
|
15706
|
+
}
|
|
15707
|
+
return resolved;
|
|
15708
|
+
}
|
|
15709
|
+
function isPersistedFailureCell(value) {
|
|
15710
|
+
const raw = String(value ?? "").trim();
|
|
15711
|
+
if (!raw) {
|
|
15712
|
+
return false;
|
|
15713
|
+
}
|
|
15714
|
+
if (cellFailureError(value)) {
|
|
15715
|
+
return true;
|
|
15716
|
+
}
|
|
15717
|
+
return raw.includes("Error:") || raw.includes("Traceback");
|
|
15718
|
+
}
|
|
15719
|
+
function isPersistedFailureStatusCell(value) {
|
|
15720
|
+
const raw = String(value ?? "").trim().toLowerCase();
|
|
15721
|
+
return raw === "error" || raw === "failed" || raw === "failure";
|
|
15722
|
+
}
|
|
15723
|
+
function stripFailureCompanionSuffix(key) {
|
|
15724
|
+
const lowerKey = key.toLowerCase();
|
|
15725
|
+
for (const suffix of [".error", "__error"]) {
|
|
15726
|
+
if (lowerKey.endsWith(suffix)) {
|
|
15727
|
+
return { alias: key.slice(0, -suffix.length), kind: "error" };
|
|
15728
|
+
}
|
|
15729
|
+
}
|
|
15730
|
+
for (const suffix of [".status", "__status"]) {
|
|
15731
|
+
if (lowerKey.endsWith(suffix)) {
|
|
15732
|
+
return { alias: key.slice(0, -suffix.length), kind: "status" };
|
|
15733
|
+
}
|
|
15734
|
+
}
|
|
15735
|
+
return null;
|
|
15736
|
+
}
|
|
15737
|
+
function collectFailedInputAliases(config, sourceCsvPath, rows) {
|
|
15738
|
+
const { scalarAliases } = collectCommandAliases(config);
|
|
15739
|
+
if (scalarAliases.size === 0) {
|
|
15740
|
+
return /* @__PURE__ */ new Set();
|
|
15741
|
+
}
|
|
15742
|
+
const inputRows = readCsvRows(sourceCsvPath);
|
|
15743
|
+
if (inputRows.length === 0) {
|
|
15744
|
+
return /* @__PURE__ */ new Set();
|
|
15745
|
+
}
|
|
15746
|
+
const start = rows.rowStart ?? 0;
|
|
15747
|
+
const maxEnd = Math.max(start, inputRows.length - 1);
|
|
15748
|
+
const inclusiveEnd = rows.rowEnd === null || rows.rowEnd === void 0 ? maxEnd : Math.min(maxEnd, rows.rowEnd);
|
|
15749
|
+
const failedAliases = /* @__PURE__ */ new Set();
|
|
15750
|
+
for (let index = start; index <= inclusiveEnd; index += 1) {
|
|
15751
|
+
const row = inputRows[index];
|
|
15752
|
+
if (!row) {
|
|
15753
|
+
continue;
|
|
15754
|
+
}
|
|
15755
|
+
for (const [key, value] of Object.entries(row)) {
|
|
15756
|
+
const alias = normalizeAlias2(key);
|
|
15757
|
+
if (scalarAliases.has(alias) && isPersistedFailureCell(value)) {
|
|
15758
|
+
failedAliases.add(alias);
|
|
15759
|
+
continue;
|
|
15760
|
+
}
|
|
15761
|
+
const companion = stripFailureCompanionSuffix(key);
|
|
15762
|
+
if (!companion) {
|
|
15763
|
+
continue;
|
|
15764
|
+
}
|
|
15765
|
+
const companionAlias = normalizeAlias2(companion.alias);
|
|
15766
|
+
if (!scalarAliases.has(companionAlias)) {
|
|
15767
|
+
continue;
|
|
15768
|
+
}
|
|
15769
|
+
if (companion.kind === "error" ? isPersistedFailureCell(value) : isPersistedFailureStatusCell(value)) {
|
|
15770
|
+
failedAliases.add(companionAlias);
|
|
15771
|
+
}
|
|
15772
|
+
}
|
|
15773
|
+
}
|
|
15774
|
+
return failedAliases;
|
|
15775
|
+
}
|
|
15776
|
+
function parseJsonOutput(stdout) {
|
|
15777
|
+
const trimmed = stdout.trim();
|
|
15778
|
+
if (!trimmed) return null;
|
|
15779
|
+
try {
|
|
15780
|
+
return JSON.parse(trimmed);
|
|
15781
|
+
} catch {
|
|
15782
|
+
const start = trimmed.lastIndexOf("\n{");
|
|
15783
|
+
if (start >= 0) {
|
|
15784
|
+
return JSON.parse(trimmed.slice(start + 1));
|
|
15785
|
+
}
|
|
15786
|
+
throw new Error(
|
|
15787
|
+
"The generated play completed but did not emit parseable JSON."
|
|
15788
|
+
);
|
|
15789
|
+
}
|
|
15790
|
+
}
|
|
15791
|
+
function extractRunIdFromPlayOutput(stdout) {
|
|
15792
|
+
const runIdLine = stdout.match(/^\s*run id:\s*(play\/\S+\/run\/\S+)\s*$/im);
|
|
15793
|
+
if (runIdLine?.[1]) {
|
|
15794
|
+
return runIdLine[1];
|
|
15795
|
+
}
|
|
15796
|
+
return stdout.match(/\b(play\/\S+\/run\/\S+)/)?.[1] ?? null;
|
|
15797
|
+
}
|
|
15798
|
+
async function resolveWatchedGeneratedPlayStatus(input2) {
|
|
15799
|
+
const runId = extractRunIdFromPlayOutput(input2.stdout);
|
|
15800
|
+
if (!runId) {
|
|
15801
|
+
if (input2.exitCode === 0) {
|
|
15802
|
+
throw new Error(
|
|
15803
|
+
"The generated play completed but did not print a run id to inspect."
|
|
15804
|
+
);
|
|
15805
|
+
}
|
|
15806
|
+
return null;
|
|
15807
|
+
}
|
|
15808
|
+
return input2.client.runs.get(runId, { full: true });
|
|
15809
|
+
}
|
|
15810
|
+
function isRecord6(value) {
|
|
15811
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
15812
|
+
}
|
|
15813
|
+
async function captureStdout(run, options = {}) {
|
|
15814
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
15815
|
+
let stdout = "";
|
|
15816
|
+
process.stdout.write = ((chunk, ..._args) => {
|
|
15817
|
+
stdout += typeof chunk === "string" ? chunk : String(chunk);
|
|
15818
|
+
if (options.passthrough) {
|
|
15819
|
+
return originalWrite(typeof chunk === "string" ? chunk : String(chunk));
|
|
15820
|
+
}
|
|
15821
|
+
return true;
|
|
15822
|
+
});
|
|
15823
|
+
try {
|
|
15824
|
+
const result = await run();
|
|
15825
|
+
return { result, stdout };
|
|
15826
|
+
} finally {
|
|
15827
|
+
process.stdout.write = originalWrite;
|
|
15828
|
+
}
|
|
15829
|
+
}
|
|
15830
|
+
function isPlayStartStreamEndedError(error) {
|
|
15831
|
+
return error instanceof DeeplineError && error.code === "PLAY_START_STREAM_ENDED" || error instanceof Error && error.message.includes(
|
|
15832
|
+
"Play start stream ended before a terminal status"
|
|
15833
|
+
);
|
|
15834
|
+
}
|
|
15835
|
+
async function runGeneratedEnrichPlay(runArgs, options = {}) {
|
|
15836
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
15837
|
+
try {
|
|
15838
|
+
return await captureStdout(() => handlePlayRun(runArgs), {
|
|
15839
|
+
passthrough: options.passthroughStdout
|
|
15840
|
+
});
|
|
15841
|
+
} catch (error) {
|
|
15842
|
+
if (attempt === 0 && isPlayStartStreamEndedError(error)) {
|
|
15843
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
15844
|
+
continue;
|
|
15845
|
+
}
|
|
15846
|
+
throw error;
|
|
15847
|
+
}
|
|
15848
|
+
}
|
|
15849
|
+
return captureStdout(() => handlePlayRun(runArgs), {
|
|
15850
|
+
passthrough: options.passthroughStdout
|
|
15851
|
+
});
|
|
15852
|
+
}
|
|
15853
|
+
async function writeOutputCsv(outputPath, status, options) {
|
|
15854
|
+
let rowsInfo = extractCanonicalRowsInfo(status);
|
|
15855
|
+
if (!rowsInfo) {
|
|
15856
|
+
throw new Error("The generated play did not return row-shaped output.");
|
|
15857
|
+
}
|
|
15858
|
+
if (!rowsInfo.complete && options?.client) {
|
|
15859
|
+
rowsInfo = await fetchBackingRowsForCsvExport({
|
|
15860
|
+
client: options.client,
|
|
15861
|
+
status,
|
|
15862
|
+
rowsInfo
|
|
15863
|
+
}) ?? rowsInfo;
|
|
15864
|
+
}
|
|
15865
|
+
assertCompleteRowsForCsvExport(rowsInfo, status, outputPath);
|
|
15866
|
+
const merged = mergeRowsForCsvExport(rowsInfo.rows, options);
|
|
15867
|
+
const columns = orderEnrichCsvColumns(
|
|
15868
|
+
dataExportColumns(merged.rows, [
|
|
15869
|
+
...merged.preferredColumns,
|
|
15870
|
+
...rowsInfo.columns
|
|
15871
|
+
]),
|
|
15872
|
+
options?.config
|
|
15873
|
+
);
|
|
15874
|
+
await (0, import_promises5.writeFile)(
|
|
15875
|
+
(0, import_node_path13.resolve)(outputPath),
|
|
15876
|
+
csvStringFromRows(merged.rows, columns),
|
|
15877
|
+
"utf8"
|
|
15878
|
+
);
|
|
15879
|
+
return {
|
|
15880
|
+
rows: merged.rows.length,
|
|
15881
|
+
path: (0, import_node_path13.resolve)(outputPath),
|
|
15882
|
+
enrichedRows: rowsInfo.rows
|
|
15883
|
+
};
|
|
15884
|
+
}
|
|
15885
|
+
function recordField(value, key) {
|
|
15886
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value[key] : void 0;
|
|
15887
|
+
}
|
|
15888
|
+
function extractRunId(status) {
|
|
15889
|
+
const candidates = [
|
|
15890
|
+
recordField(status, "runId"),
|
|
15891
|
+
recordField(recordField(status, "run"), "id")
|
|
15892
|
+
];
|
|
15893
|
+
for (const candidate of candidates) {
|
|
15894
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
15895
|
+
return candidate.trim();
|
|
15896
|
+
}
|
|
15897
|
+
}
|
|
15898
|
+
return null;
|
|
15899
|
+
}
|
|
15900
|
+
function extractPlayName2(status) {
|
|
15901
|
+
const run = recordField(status, "run");
|
|
15902
|
+
const candidates = [
|
|
15903
|
+
recordField(status, "playName"),
|
|
15904
|
+
recordField(status, "name"),
|
|
15905
|
+
recordField(run, "playName"),
|
|
15906
|
+
recordField(run, "name")
|
|
15907
|
+
];
|
|
15908
|
+
for (const candidate of candidates) {
|
|
15909
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
15910
|
+
return candidate.trim();
|
|
15911
|
+
}
|
|
15912
|
+
}
|
|
15913
|
+
return null;
|
|
15914
|
+
}
|
|
15915
|
+
function exportableSheetRow2(row) {
|
|
15916
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
15917
|
+
return null;
|
|
15918
|
+
}
|
|
15919
|
+
const record = row;
|
|
15920
|
+
const data = record.data;
|
|
15921
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
15922
|
+
return data;
|
|
15923
|
+
}
|
|
15924
|
+
const fallback = { ...record };
|
|
15925
|
+
for (const key of [
|
|
15926
|
+
"key",
|
|
15927
|
+
"status",
|
|
15928
|
+
"cellMeta",
|
|
15929
|
+
"inputIndex",
|
|
15930
|
+
"runId",
|
|
15931
|
+
"error",
|
|
15932
|
+
"stage",
|
|
15933
|
+
"provider",
|
|
15934
|
+
"seq",
|
|
15935
|
+
"createdAt",
|
|
15936
|
+
"updatedAt"
|
|
15937
|
+
]) {
|
|
15938
|
+
delete fallback[key];
|
|
15939
|
+
}
|
|
15940
|
+
return fallback;
|
|
15941
|
+
}
|
|
15942
|
+
function collectHardFailureAliases(config) {
|
|
15943
|
+
const aliases = [];
|
|
15944
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15945
|
+
for (const command of config.commands) {
|
|
15946
|
+
if ("with_waterfall" in command) {
|
|
15947
|
+
continue;
|
|
15948
|
+
}
|
|
15949
|
+
if (command.disabled) {
|
|
15950
|
+
continue;
|
|
15951
|
+
}
|
|
15952
|
+
const alias = command.alias.trim();
|
|
15953
|
+
if (!alias || seen.has(alias)) {
|
|
15954
|
+
continue;
|
|
15955
|
+
}
|
|
15956
|
+
seen.add(alias);
|
|
15957
|
+
aliases.push(alias);
|
|
15958
|
+
}
|
|
15959
|
+
return aliases;
|
|
15960
|
+
}
|
|
15961
|
+
function cellFailureError(value) {
|
|
15962
|
+
const parsed = parseMaybeJsonObject(value);
|
|
15963
|
+
if (!isRecord6(parsed)) {
|
|
15964
|
+
return null;
|
|
15965
|
+
}
|
|
15966
|
+
const status = typeof parsed.status === "string" ? parsed.status.trim().toLowerCase() : "";
|
|
15967
|
+
const directError = typeof parsed.error === "string" ? parsed.error.trim() : typeof parsed.last_error === "string" ? parsed.last_error.trim() : "";
|
|
15968
|
+
const result = isRecord6(parsed.result) ? parsed.result : null;
|
|
15969
|
+
const resultError = typeof result?.error === "string" ? result.error.trim() : typeof result?.message === "string" ? result.message.trim() : "";
|
|
15970
|
+
if (!directError && !resultError && status !== "error" && status !== "failed") {
|
|
15971
|
+
return null;
|
|
15972
|
+
}
|
|
15973
|
+
const message = directError || resultError || `Column status: ${status}`;
|
|
15974
|
+
return {
|
|
15975
|
+
message,
|
|
15976
|
+
...typeof parsed.operation === "string" && parsed.operation.trim() ? { operation: parsed.operation.trim() } : {},
|
|
15977
|
+
...typeof parsed.provider === "string" && parsed.provider.trim() ? { provider: parsed.provider.trim() } : {}
|
|
15978
|
+
};
|
|
15979
|
+
}
|
|
15980
|
+
function buildEnrichWaterfallSummaryLines(config, rows) {
|
|
15981
|
+
if (rows.length === 0) {
|
|
15982
|
+
return [];
|
|
15983
|
+
}
|
|
15984
|
+
const lines = [];
|
|
15985
|
+
for (const command of config.commands) {
|
|
15986
|
+
if (!("with_waterfall" in command)) {
|
|
15987
|
+
continue;
|
|
15988
|
+
}
|
|
15989
|
+
for (const child of command.commands) {
|
|
15990
|
+
if ("with_waterfall" in child || child.disabled) {
|
|
15991
|
+
continue;
|
|
15992
|
+
}
|
|
15993
|
+
const failures = rows.filter(
|
|
15994
|
+
(row) => cellFailureError(row[child.alias])
|
|
15995
|
+
).length;
|
|
15996
|
+
if (failures > 0) {
|
|
15997
|
+
lines.push(
|
|
15998
|
+
`Column '${child.alias}' had high failure rate (${failures}/${rows.length}); continuing waterfall group '${command.with_waterfall}'.`
|
|
15999
|
+
);
|
|
16000
|
+
}
|
|
16001
|
+
}
|
|
16002
|
+
}
|
|
16003
|
+
return lines;
|
|
16004
|
+
}
|
|
16005
|
+
function collectEnrichFailureJobs(input2) {
|
|
16006
|
+
const aliases = collectHardFailureAliases(input2.config);
|
|
16007
|
+
if (aliases.length === 0 || input2.rows.length === 0) {
|
|
16008
|
+
return [];
|
|
16009
|
+
}
|
|
16010
|
+
const rowOffset = input2.rowStart ?? 0;
|
|
16011
|
+
const jobs = [];
|
|
16012
|
+
input2.rows.forEach((row, rowIndex) => {
|
|
16013
|
+
aliases.forEach((alias, aliasIndex) => {
|
|
16014
|
+
const failure = cellFailureError(row[alias]);
|
|
16015
|
+
if (!failure) {
|
|
16016
|
+
return;
|
|
16017
|
+
}
|
|
16018
|
+
const rowId = rowOffset + rowIndex;
|
|
16019
|
+
jobs.push({
|
|
16020
|
+
job_id: `row-${rowId}-${alias}`,
|
|
16021
|
+
row_id: rowId,
|
|
16022
|
+
col_index: aliasIndex,
|
|
16023
|
+
column: alias,
|
|
16024
|
+
status: "failed",
|
|
16025
|
+
last_error: failure.message,
|
|
16026
|
+
error: failure.message,
|
|
16027
|
+
...failure.operation ? { operation: failure.operation } : {},
|
|
16028
|
+
...failure.provider ? { provider: failure.provider } : {}
|
|
16029
|
+
});
|
|
16030
|
+
});
|
|
16031
|
+
});
|
|
16032
|
+
return jobs;
|
|
16033
|
+
}
|
|
16034
|
+
function summarizeFailedJobError(value) {
|
|
16035
|
+
const text = String(value ?? "").trim();
|
|
16036
|
+
return text.length > 500 ? `${text.slice(0, 497)}...` : text;
|
|
16037
|
+
}
|
|
16038
|
+
function formatFailureReportCommand(reportPath) {
|
|
16039
|
+
const quoted = reportPath.replace(/'/g, `'\\''`);
|
|
16040
|
+
return `Inspect failed jobs: jq -r '.jobs[] | [.job_id,.row_id,.col_index,.column,.status,.last_error] | @tsv' '${quoted}'`;
|
|
16041
|
+
}
|
|
16042
|
+
async function persistEnrichFailureReport(input2) {
|
|
16043
|
+
if (input2.jobs.length === 0) {
|
|
16044
|
+
return null;
|
|
16045
|
+
}
|
|
16046
|
+
const stateDir = (0, import_node_path13.join)((0, import_node_os7.homedir)(), ".local", "deepline", "runtime", "state");
|
|
16047
|
+
await (0, import_promises5.mkdir)(stateDir, { recursive: true });
|
|
16048
|
+
const reportPath = (0, import_node_path13.join)(
|
|
16049
|
+
stateDir,
|
|
16050
|
+
`run-block-failures-${Math.floor(Date.now() / 1e3)}-${process.pid}.json`
|
|
16051
|
+
);
|
|
16052
|
+
const report = {
|
|
16053
|
+
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16054
|
+
api_url: input2.apiUrl,
|
|
16055
|
+
output_csv: input2.outputPath ?? "",
|
|
16056
|
+
summary: {
|
|
16057
|
+
failed_count: input2.jobs.length,
|
|
16058
|
+
canceled_count: 0,
|
|
16059
|
+
pending_count: 0,
|
|
16060
|
+
missing_count: 0,
|
|
16061
|
+
total_jobs: input2.jobs.length
|
|
16062
|
+
},
|
|
16063
|
+
jobs: input2.jobs,
|
|
16064
|
+
failed_jobs: input2.jobs,
|
|
16065
|
+
canceled_jobs: [],
|
|
16066
|
+
pending_jobs: [],
|
|
16067
|
+
missing_job_ids: []
|
|
16068
|
+
};
|
|
16069
|
+
if (input2.rows.rowStart !== null && input2.rows.rowEnd !== null) {
|
|
16070
|
+
report.rows = { start: input2.rows.rowStart, end: input2.rows.rowEnd };
|
|
16071
|
+
}
|
|
16072
|
+
await (0, import_promises5.writeFile)(reportPath, `${JSON.stringify(report, null, 2)}
|
|
16073
|
+
`, "utf8");
|
|
16074
|
+
return reportPath;
|
|
16075
|
+
}
|
|
16076
|
+
async function maybeEmitEnrichFailureReport(input2) {
|
|
16077
|
+
const jobs = collectEnrichFailureJobs({
|
|
16078
|
+
config: input2.config,
|
|
16079
|
+
rows: input2.rows,
|
|
16080
|
+
rowStart: input2.rowRange.rowStart
|
|
16081
|
+
});
|
|
16082
|
+
if (jobs.length === 0) {
|
|
16083
|
+
return null;
|
|
16084
|
+
}
|
|
16085
|
+
const reportPath = await persistEnrichFailureReport({
|
|
16086
|
+
jobs,
|
|
16087
|
+
apiUrl: input2.client.baseUrl,
|
|
16088
|
+
outputPath: input2.outputPath,
|
|
16089
|
+
rows: input2.rowRange
|
|
16090
|
+
});
|
|
16091
|
+
process.stderr.write("Execution failed.\n");
|
|
16092
|
+
process.stderr.write("Failure preview (up to 5 failed jobs):\n");
|
|
16093
|
+
process.stderr.write("job_id row_id col_index column status error\n");
|
|
16094
|
+
for (const job of jobs.slice(0, 5)) {
|
|
16095
|
+
process.stderr.write(
|
|
16096
|
+
`${job.job_id} ${job.row_id} ${job.col_index} ${job.column} ${job.status} ${summarizeFailedJobError(job.last_error)}
|
|
16097
|
+
`
|
|
16098
|
+
);
|
|
16099
|
+
}
|
|
16100
|
+
if (jobs.length > 5) {
|
|
16101
|
+
process.stderr.write(`Showing 5 of ${jobs.length} failed jobs.
|
|
16102
|
+
`);
|
|
16103
|
+
}
|
|
16104
|
+
if (reportPath) {
|
|
16105
|
+
process.stderr.write(`Full failure report: ${reportPath}
|
|
16106
|
+
`);
|
|
16107
|
+
process.stderr.write(`${formatFailureReportCommand(reportPath)}
|
|
16108
|
+
`);
|
|
16109
|
+
process.stderr.write("Enrichment failed. See failure report above.\n");
|
|
16110
|
+
return { path: reportPath, jobs };
|
|
16111
|
+
}
|
|
16112
|
+
process.stderr.write("Enrichment failed.\n");
|
|
16113
|
+
return { path: "", jobs };
|
|
16114
|
+
}
|
|
16115
|
+
function mergePreferredColumns(preferredColumns, rows) {
|
|
16116
|
+
const columns = [];
|
|
16117
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16118
|
+
for (const column of preferredColumns) {
|
|
16119
|
+
if (!column || seen.has(column)) {
|
|
16120
|
+
continue;
|
|
16121
|
+
}
|
|
16122
|
+
seen.add(column);
|
|
16123
|
+
columns.push(column);
|
|
16124
|
+
}
|
|
16125
|
+
for (const row of rows) {
|
|
16126
|
+
for (const column of Object.keys(row)) {
|
|
16127
|
+
if (seen.has(column)) {
|
|
16128
|
+
continue;
|
|
16129
|
+
}
|
|
16130
|
+
seen.add(column);
|
|
16131
|
+
columns.push(column);
|
|
16132
|
+
}
|
|
16133
|
+
}
|
|
16134
|
+
return columns;
|
|
16135
|
+
}
|
|
16136
|
+
async function fetchBackingRowsForCsvExport(input2) {
|
|
16137
|
+
const runId = extractRunId(input2.status);
|
|
16138
|
+
const playName = extractPlayName2(input2.status);
|
|
16139
|
+
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
16140
|
+
if (!runId || !playName || !tableNamespace) {
|
|
16141
|
+
return null;
|
|
16142
|
+
}
|
|
16143
|
+
const sheetRows = [];
|
|
16144
|
+
let offset = 0;
|
|
16145
|
+
let expectedTotal = input2.rowsInfo.totalRows;
|
|
16146
|
+
while (true) {
|
|
16147
|
+
const page = await input2.client.runs.exportDatasetRows({
|
|
16148
|
+
playName,
|
|
16149
|
+
tableNamespace,
|
|
16150
|
+
runId,
|
|
16151
|
+
limit: ENRICH_EXPORT_PAGE_SIZE,
|
|
16152
|
+
offset
|
|
16153
|
+
});
|
|
16154
|
+
sheetRows.push(...page.rows);
|
|
16155
|
+
const summaryTotal = page.summary?.stats?.total;
|
|
16156
|
+
if (typeof summaryTotal === "number" && Number.isFinite(summaryTotal)) {
|
|
16157
|
+
expectedTotal = Math.max(expectedTotal, Math.trunc(summaryTotal));
|
|
16158
|
+
}
|
|
16159
|
+
if (page.rows.length < ENRICH_EXPORT_PAGE_SIZE || sheetRows.length >= expectedTotal) {
|
|
16160
|
+
break;
|
|
16161
|
+
}
|
|
16162
|
+
offset += page.rows.length;
|
|
16163
|
+
}
|
|
16164
|
+
const rows = sheetRows.map(exportableSheetRow2).filter((row) => Boolean(row));
|
|
16165
|
+
if (rows.length < input2.rowsInfo.totalRows) {
|
|
16166
|
+
return null;
|
|
16167
|
+
}
|
|
16168
|
+
return {
|
|
16169
|
+
...input2.rowsInfo,
|
|
16170
|
+
rows,
|
|
16171
|
+
columns: mergePreferredColumns(
|
|
16172
|
+
input2.rowsInfo.columnsExplicit ? input2.rowsInfo.columns : [],
|
|
16173
|
+
rows
|
|
16174
|
+
),
|
|
16175
|
+
totalRows: rows.length,
|
|
16176
|
+
complete: true,
|
|
16177
|
+
source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
|
|
16178
|
+
};
|
|
16179
|
+
}
|
|
16180
|
+
function mergeRowsForCsvExport(enrichedRows, options) {
|
|
16181
|
+
const rows = dataExportRows(normalizeEnrichRowsForCsvExport(enrichedRows));
|
|
16182
|
+
const range = options?.rows;
|
|
16183
|
+
if (range?.rowStart === null || range?.rowStart === void 0) {
|
|
16184
|
+
return { rows, preferredColumns: [] };
|
|
16185
|
+
}
|
|
16186
|
+
if (!options?.sourceCsvPath) {
|
|
16187
|
+
return { rows, preferredColumns: [] };
|
|
16188
|
+
}
|
|
16189
|
+
const parsedBaseRows = readCsvRows(options.sourceCsvPath);
|
|
16190
|
+
const preferredColumns = Object.keys(parsedBaseRows[0] ?? {});
|
|
16191
|
+
const baseRows = parsedBaseRows.map(
|
|
16192
|
+
(row) => ({ ...row })
|
|
16193
|
+
);
|
|
16194
|
+
const start = Math.max(0, range.rowStart);
|
|
16195
|
+
const maxEnd = Math.max(start, baseRows.length - 1);
|
|
16196
|
+
const inclusiveEnd = range.rowEnd === null ? maxEnd : Math.min(maxEnd, range.rowEnd);
|
|
16197
|
+
const merged = [...baseRows];
|
|
16198
|
+
let selectedIndex = 0;
|
|
16199
|
+
for (let rowIndex = start; rowIndex <= inclusiveEnd; rowIndex += 1) {
|
|
16200
|
+
const enriched = rows[selectedIndex++];
|
|
16201
|
+
if (!enriched) {
|
|
16202
|
+
break;
|
|
16203
|
+
}
|
|
16204
|
+
const base = merged[rowIndex] ?? {};
|
|
16205
|
+
merged[rowIndex] = {
|
|
16206
|
+
...base,
|
|
16207
|
+
...enriched
|
|
16208
|
+
};
|
|
16209
|
+
const metadata = mergeLegacyMetadataCell(
|
|
16210
|
+
base._metadata,
|
|
16211
|
+
enriched._metadata
|
|
16212
|
+
);
|
|
16213
|
+
if (metadata !== void 0) {
|
|
16214
|
+
merged[rowIndex]._metadata = metadata;
|
|
16215
|
+
}
|
|
16216
|
+
}
|
|
16217
|
+
return { rows: merged, preferredColumns };
|
|
16218
|
+
}
|
|
16219
|
+
function collectConfigScalarAliasOrder(config) {
|
|
16220
|
+
const aliases = [];
|
|
16221
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16222
|
+
const addAlias = (alias) => {
|
|
16223
|
+
const normalized = normalizeAlias2(alias);
|
|
16224
|
+
if (!normalized || seen.has(normalized)) {
|
|
16225
|
+
return;
|
|
16226
|
+
}
|
|
16227
|
+
seen.add(normalized);
|
|
16228
|
+
aliases.push(alias);
|
|
16229
|
+
};
|
|
16230
|
+
for (const command of config.commands) {
|
|
16231
|
+
if ("with_waterfall" in command) {
|
|
16232
|
+
for (const child of command.commands) {
|
|
16233
|
+
if ("with_waterfall" in child || child.disabled) {
|
|
16234
|
+
continue;
|
|
16235
|
+
}
|
|
16236
|
+
addAlias(child.alias);
|
|
16237
|
+
}
|
|
16238
|
+
continue;
|
|
16239
|
+
}
|
|
16240
|
+
if (!command.disabled) {
|
|
16241
|
+
addAlias(command.alias);
|
|
16242
|
+
}
|
|
16243
|
+
}
|
|
16244
|
+
return aliases;
|
|
16245
|
+
}
|
|
16246
|
+
function orderEnrichCsvColumns(columns, config) {
|
|
16247
|
+
if (!config || columns.length < 2) {
|
|
16248
|
+
return columns;
|
|
16249
|
+
}
|
|
16250
|
+
const aliasOrder = collectConfigScalarAliasOrder(config);
|
|
16251
|
+
if (aliasOrder.length < 2) {
|
|
16252
|
+
return columns;
|
|
16253
|
+
}
|
|
16254
|
+
const normalizedAliasOrder = aliasOrder.map(normalizeAlias2);
|
|
16255
|
+
const requestedColumnByAlias = /* @__PURE__ */ new Map();
|
|
16256
|
+
for (const column of columns) {
|
|
16257
|
+
const normalizedColumn = normalizeAlias2(column);
|
|
16258
|
+
if (normalizedAliasOrder.includes(normalizedColumn) && !requestedColumnByAlias.has(normalizedColumn)) {
|
|
16259
|
+
requestedColumnByAlias.set(normalizedColumn, column);
|
|
16260
|
+
}
|
|
16261
|
+
}
|
|
16262
|
+
const requestedColumns = normalizedAliasOrder.map((alias) => requestedColumnByAlias.get(alias)).filter((column) => Boolean(column));
|
|
16263
|
+
if (requestedColumns.length < 2) {
|
|
16264
|
+
return columns;
|
|
16265
|
+
}
|
|
16266
|
+
const requestedSet = new Set(requestedColumns);
|
|
16267
|
+
const firstRequestedIndex = columns.findIndex(
|
|
16268
|
+
(column) => requestedSet.has(column)
|
|
16269
|
+
);
|
|
16270
|
+
if (firstRequestedIndex < 0) {
|
|
16271
|
+
return columns;
|
|
16272
|
+
}
|
|
16273
|
+
const withoutRequested = columns.filter(
|
|
16274
|
+
(column) => !requestedSet.has(column)
|
|
16275
|
+
);
|
|
16276
|
+
withoutRequested.splice(firstRequestedIndex, 0, ...requestedColumns);
|
|
16277
|
+
return withoutRequested;
|
|
16278
|
+
}
|
|
16279
|
+
function isNonEmptyCsvCell(value) {
|
|
16280
|
+
return value !== null && value !== void 0 && String(value).trim() !== "";
|
|
16281
|
+
}
|
|
16282
|
+
function normalizeEnrichRowsForCsvExport(rows) {
|
|
16283
|
+
return rows.map((row) => {
|
|
16284
|
+
const metadata = legacyMetadataFromRow(row);
|
|
16285
|
+
if (!metadata) {
|
|
16286
|
+
return row;
|
|
16287
|
+
}
|
|
16288
|
+
const normalized = { ...row, _metadata: metadata };
|
|
16289
|
+
delete normalized.metadata;
|
|
16290
|
+
delete normalized["metadata.columns"];
|
|
16291
|
+
delete normalized.metadata__columns;
|
|
16292
|
+
for (const key of Object.keys(normalized)) {
|
|
16293
|
+
if (key.startsWith("metadata.columns.") || key.startsWith("metadata__columns.")) {
|
|
16294
|
+
delete normalized[key];
|
|
16295
|
+
}
|
|
16296
|
+
}
|
|
16297
|
+
return normalized;
|
|
16298
|
+
});
|
|
16299
|
+
}
|
|
16300
|
+
function legacyMetadataFromRow(row) {
|
|
16301
|
+
const direct = parseLegacyMetadataCell(row._metadata);
|
|
16302
|
+
if (direct && isRecord6(direct.columns)) {
|
|
16303
|
+
return direct;
|
|
16304
|
+
}
|
|
16305
|
+
const relocated = parseLegacyMetadataCell(row.metadata);
|
|
16306
|
+
if (relocated && isRecord6(relocated.columns)) {
|
|
16307
|
+
return relocated;
|
|
16308
|
+
}
|
|
16309
|
+
const flattenedColumns = parseLegacyMetadataCell(row["metadata.columns"]);
|
|
16310
|
+
if (flattenedColumns) {
|
|
16311
|
+
return { columns: flattenedColumns };
|
|
16312
|
+
}
|
|
16313
|
+
const flattenedUnderscoreColumns = parseLegacyMetadataCell(
|
|
16314
|
+
row.metadata__columns
|
|
16315
|
+
);
|
|
16316
|
+
if (flattenedUnderscoreColumns) {
|
|
16317
|
+
return { columns: flattenedUnderscoreColumns };
|
|
16318
|
+
}
|
|
16319
|
+
return null;
|
|
16320
|
+
}
|
|
16321
|
+
function parseLegacyMetadataCell(value) {
|
|
16322
|
+
const parsed = parseMaybeJsonObject(value);
|
|
16323
|
+
if (isRecord6(parsed)) {
|
|
16324
|
+
return parsed;
|
|
16325
|
+
}
|
|
16326
|
+
if (typeof value !== "string") {
|
|
16327
|
+
return null;
|
|
16328
|
+
}
|
|
16329
|
+
const trimmed = value.trim();
|
|
16330
|
+
if (!trimmed) {
|
|
16331
|
+
return null;
|
|
16332
|
+
}
|
|
16333
|
+
const candidates = [trimmed];
|
|
16334
|
+
if (trimmed.includes('\\"')) {
|
|
16335
|
+
candidates.push(trimmed.replace(/\\"/g, '"'));
|
|
16336
|
+
}
|
|
16337
|
+
for (const candidate of candidates) {
|
|
16338
|
+
try {
|
|
16339
|
+
const decoded = JSON.parse(candidate);
|
|
16340
|
+
if (isRecord6(decoded)) {
|
|
16341
|
+
return decoded;
|
|
14706
16342
|
}
|
|
14707
|
-
|
|
14708
|
-
|
|
16343
|
+
if (typeof decoded === "string") {
|
|
16344
|
+
const nested = JSON.parse(decoded);
|
|
16345
|
+
if (isRecord6(nested)) {
|
|
16346
|
+
return nested;
|
|
16347
|
+
}
|
|
16348
|
+
}
|
|
16349
|
+
} catch {
|
|
14709
16350
|
}
|
|
14710
16351
|
}
|
|
14711
|
-
return
|
|
16352
|
+
return null;
|
|
14712
16353
|
}
|
|
14713
|
-
function
|
|
14714
|
-
const
|
|
14715
|
-
|
|
14716
|
-
|
|
14717
|
-
|
|
14718
|
-
|
|
14719
|
-
|
|
14720
|
-
|
|
14721
|
-
|
|
14722
|
-
|
|
14723
|
-
|
|
14724
|
-
|
|
14725
|
-
);
|
|
16354
|
+
function mergeLegacyMetadataRecords(base, enriched) {
|
|
16355
|
+
const baseColumns = isRecord6(base.columns) ? base.columns : null;
|
|
16356
|
+
const enrichedColumns = isRecord6(enriched.columns) ? enriched.columns : null;
|
|
16357
|
+
const merged = {
|
|
16358
|
+
...base,
|
|
16359
|
+
...enriched
|
|
16360
|
+
};
|
|
16361
|
+
if (baseColumns || enrichedColumns) {
|
|
16362
|
+
merged.columns = {
|
|
16363
|
+
...baseColumns ?? {},
|
|
16364
|
+
...enrichedColumns ?? {}
|
|
16365
|
+
};
|
|
14726
16366
|
}
|
|
16367
|
+
return merged;
|
|
14727
16368
|
}
|
|
14728
|
-
|
|
14729
|
-
const
|
|
14730
|
-
|
|
14731
|
-
|
|
14732
|
-
|
|
14733
|
-
|
|
14734
|
-
|
|
14735
|
-
try {
|
|
14736
|
-
const result = await run();
|
|
14737
|
-
return { result, stdout };
|
|
14738
|
-
} finally {
|
|
14739
|
-
process.stdout.write = originalWrite;
|
|
16369
|
+
function mergeLegacyMetadataCell(base, enriched) {
|
|
16370
|
+
const baseRecord = parseLegacyMetadataCell(base);
|
|
16371
|
+
const enrichedRecord = parseLegacyMetadataCell(enriched);
|
|
16372
|
+
if (baseRecord && enrichedRecord) {
|
|
16373
|
+
return JSON.stringify(
|
|
16374
|
+
mergeLegacyMetadataRecords(baseRecord, enrichedRecord)
|
|
16375
|
+
);
|
|
14740
16376
|
}
|
|
14741
|
-
|
|
14742
|
-
|
|
14743
|
-
const rowsInfo = extractCanonicalRowsInfo(status);
|
|
14744
|
-
if (!rowsInfo) {
|
|
14745
|
-
throw new Error("The generated play did not return row-shaped output.");
|
|
16377
|
+
if (enrichedRecord) {
|
|
16378
|
+
return JSON.stringify(enrichedRecord);
|
|
14746
16379
|
}
|
|
14747
|
-
|
|
14748
|
-
|
|
14749
|
-
|
|
14750
|
-
|
|
14751
|
-
|
|
14752
|
-
|
|
14753
|
-
|
|
14754
|
-
|
|
14755
|
-
|
|
16380
|
+
if (baseRecord) {
|
|
16381
|
+
return JSON.stringify(baseRecord);
|
|
16382
|
+
}
|
|
16383
|
+
if (isNonEmptyCsvCell(enriched)) {
|
|
16384
|
+
return enriched;
|
|
16385
|
+
}
|
|
16386
|
+
if (isNonEmptyCsvCell(base)) {
|
|
16387
|
+
return base;
|
|
16388
|
+
}
|
|
16389
|
+
return void 0;
|
|
14756
16390
|
}
|
|
14757
16391
|
function assertCompleteRowsForCsvExport(rowsInfo, status, outputPath) {
|
|
14758
16392
|
if (rowsInfo.complete) {
|
|
@@ -14773,13 +16407,26 @@ async function compileConfig(input2) {
|
|
|
14773
16407
|
);
|
|
14774
16408
|
}
|
|
14775
16409
|
const config = await readConfig(input2.options.config);
|
|
14776
|
-
return (await input2.client.compileEnrichPlan({
|
|
16410
|
+
return (await input2.client.compileEnrichPlan({
|
|
16411
|
+
config,
|
|
16412
|
+
native_play_materialization: "inline_prebuilt"
|
|
16413
|
+
})).config;
|
|
14777
16414
|
}
|
|
14778
16415
|
const planArgs = await buildPlanArgs(input2.args);
|
|
14779
|
-
return (await input2.client.compileEnrichPlan({
|
|
16416
|
+
return (await input2.client.compileEnrichPlan({
|
|
16417
|
+
plan_args: planArgs,
|
|
16418
|
+
native_play_materialization: "inline_prebuilt"
|
|
16419
|
+
})).config;
|
|
14780
16420
|
}
|
|
14781
16421
|
function registerEnrichCommand(program) {
|
|
14782
|
-
program.command("enrich").allowUnknownOption(true).description("Run v1-style CSV enrichment through the V2 play runner.").
|
|
16422
|
+
program.command("enrich").allowUnknownOption(true).description("Run v1-style CSV enrichment through the V2 play runner.").configureHelp({
|
|
16423
|
+
optionTerm(option) {
|
|
16424
|
+
return option.long === "--timeout" ? "--timeout SECONDS" : option.flags;
|
|
16425
|
+
}
|
|
16426
|
+
}).option("--input <path>", "Input CSV path.").option("--csv <path>", "Alias for --input.").option("--output <path>", "Output CSV path.").option("--config <path>", "JSON enrich config.").requiredOption(
|
|
16427
|
+
"--name <name>",
|
|
16428
|
+
"Name for the compiled enrich play. Reuse a name to keep iterating on the same play; use a new name for a distinct enrichment so runs stay separate in the run ledger and share URLs."
|
|
16429
|
+
).option(
|
|
14783
16430
|
"--with <json>",
|
|
14784
16431
|
"Add a scalar enrich command.",
|
|
14785
16432
|
(value, previous = []) => [...previous, value]
|
|
@@ -14792,70 +16439,77 @@ function registerEnrichCommand(program) {
|
|
|
14792
16439
|
"Minimum list results for the current waterfall."
|
|
14793
16440
|
).option("--end-waterfall", "End the current waterfall group.").option(
|
|
14794
16441
|
"--rows <range>",
|
|
14795
|
-
"Zero-based row number or
|
|
16442
|
+
"Zero-based row number or inclusive range, e.g. 0:10."
|
|
14796
16443
|
).option("--all", "Run all rows.").option(
|
|
14797
16444
|
"--dry-run",
|
|
14798
16445
|
"Compile and print the generated plan without starting a run."
|
|
14799
|
-
).option("--json", "Emit JSON.").option("--force", "Force rerun for all enrich aliases.").option(
|
|
16446
|
+
).option("--json", "Emit JSON.").option("--no-open", "Do not open the play page in a browser.").option("--force", "Force rerun for all enrich aliases.").option(
|
|
14800
16447
|
"--with-force <aliases>",
|
|
14801
16448
|
"Force rerun for selected aliases.",
|
|
14802
16449
|
(value, previous = []) => [...previous, value]
|
|
14803
|
-
).option(
|
|
14804
|
-
"--
|
|
14805
|
-
"
|
|
16450
|
+
).option("--in-place", "Write enriched output back to the input CSV.").option(
|
|
16451
|
+
"--timeout <SECONDS>",
|
|
16452
|
+
"API read timeout for enrich status/API requests."
|
|
14806
16453
|
).action(async (options, _command) => {
|
|
14807
|
-
if (options.inPlace) {
|
|
14808
|
-
throw new Error(
|
|
14809
|
-
"--in-place is not supported by this V2 enrich runner yet. Use --output instead."
|
|
14810
|
-
);
|
|
16454
|
+
if (options.inPlace && options.dryRun) {
|
|
16455
|
+
throw new Error("--in-place is not supported with --dry-run.");
|
|
14811
16456
|
}
|
|
14812
16457
|
const inputCsv = options.input ?? options.csv;
|
|
14813
16458
|
if (!inputCsv) {
|
|
14814
16459
|
throw new Error("Missing required --input <csv> (or --csv <csv>).");
|
|
14815
16460
|
}
|
|
14816
16461
|
await assertInputCsvExists(inputCsv);
|
|
14817
|
-
if (options.output) {
|
|
16462
|
+
if (options.output && !options.inPlace) {
|
|
14818
16463
|
await assertSafeOutputPath(inputCsv, options.output);
|
|
14819
16464
|
}
|
|
14820
16465
|
if (!options.config && !hasPlanShapingArgs(currentEnrichArgs())) {
|
|
14821
16466
|
throw new Error("Pass --config or at least one --with enrich spec.");
|
|
14822
16467
|
}
|
|
14823
|
-
const
|
|
16468
|
+
const client2 = new DeeplineClient();
|
|
14824
16469
|
const args = currentEnrichArgs();
|
|
14825
|
-
const config = await compileConfig({ client, args, options });
|
|
14826
|
-
|
|
14827
|
-
const playSource = compileEnrichConfigToPlaySource(config, {
|
|
14828
|
-
forceAliases
|
|
14829
|
-
});
|
|
14830
|
-
const summary = summarizePlan(config, playSource);
|
|
14831
|
-
printDeprecationNotice(options);
|
|
16470
|
+
const config = await compileConfig({ client: client2, args, options });
|
|
16471
|
+
emitEnrichDebugValidationLines(config);
|
|
14832
16472
|
if (options.dryRun) {
|
|
16473
|
+
const forceAliases2 = resolveForceAliases(config, options);
|
|
16474
|
+
const playSource2 = compileEnrichConfigToPlaySource(config, {
|
|
16475
|
+
forceAliases: forceAliases2,
|
|
16476
|
+
playName: options.name
|
|
16477
|
+
});
|
|
16478
|
+
const summary = summarizePlan(config, playSource2);
|
|
14833
16479
|
if (options.json) {
|
|
14834
16480
|
printJson({
|
|
14835
16481
|
dryRun: true,
|
|
14836
|
-
deprecation: ENRICH_DEPRECATION_NOTICE,
|
|
14837
16482
|
input: (0, import_node_path13.resolve)(inputCsv),
|
|
14838
16483
|
output: options.output ? (0, import_node_path13.resolve)(options.output) : null,
|
|
14839
16484
|
plan: summary
|
|
14840
16485
|
});
|
|
14841
16486
|
return;
|
|
14842
16487
|
}
|
|
14843
|
-
process.stdout.write(`${
|
|
16488
|
+
process.stdout.write(`${playSource2}
|
|
14844
16489
|
`);
|
|
14845
16490
|
return;
|
|
14846
16491
|
}
|
|
14847
16492
|
const rows = parseRows(options.rows, options.all);
|
|
14848
|
-
|
|
14849
|
-
|
|
14850
|
-
|
|
14851
|
-
|
|
16493
|
+
const outputPath = options.inPlace ? inputCsv : options.output;
|
|
16494
|
+
const sourceCsvPath = !options.inPlace && outputPath && await regularFileExists(outputPath) ? outputPath : inputCsv;
|
|
16495
|
+
const forceAliases = resolveForceAliases(config, options);
|
|
16496
|
+
for (const alias of collectFailedInputAliases(
|
|
16497
|
+
config,
|
|
16498
|
+
sourceCsvPath,
|
|
16499
|
+
rows
|
|
16500
|
+
)) {
|
|
16501
|
+
forceAliases.add(alias);
|
|
14852
16502
|
}
|
|
16503
|
+
const playSource = compileEnrichConfigToPlaySource(config, {
|
|
16504
|
+
forceAliases,
|
|
16505
|
+
playName: options.name
|
|
16506
|
+
});
|
|
14853
16507
|
const tempDir = await (0, import_promises5.mkdtemp)((0, import_node_path13.join)((0, import_node_os7.tmpdir)(), "deepline-enrich-play-"));
|
|
14854
16508
|
const tempPlay = (0, import_node_path13.join)(tempDir, "deepline-enrich.play.ts");
|
|
14855
16509
|
try {
|
|
14856
16510
|
await (0, import_promises5.writeFile)(tempPlay, playSource, "utf8");
|
|
14857
16511
|
const runtimeInput = {
|
|
14858
|
-
file: (0, import_node_path13.resolve)(
|
|
16512
|
+
file: (0, import_node_path13.resolve)(sourceCsvPath),
|
|
14859
16513
|
...rows.rowStart !== null ? { rowStart: rows.rowStart } : {},
|
|
14860
16514
|
...rows.rowEnd !== null ? { rowEnd: rows.rowEnd } : {}
|
|
14861
16515
|
};
|
|
@@ -14864,40 +16518,91 @@ function registerEnrichCommand(program) {
|
|
|
14864
16518
|
tempPlay,
|
|
14865
16519
|
"--input",
|
|
14866
16520
|
JSON.stringify(runtimeInput),
|
|
14867
|
-
"--watch"
|
|
14868
|
-
"--no-open",
|
|
14869
|
-
"--json"
|
|
16521
|
+
"--watch"
|
|
14870
16522
|
];
|
|
14871
|
-
|
|
14872
|
-
|
|
16523
|
+
if (options.noOpen) {
|
|
16524
|
+
runArgs.push("--no-open");
|
|
16525
|
+
}
|
|
16526
|
+
if (options.json) {
|
|
16527
|
+
runArgs.push("--json");
|
|
16528
|
+
} else {
|
|
16529
|
+
runArgs.push("--logs");
|
|
16530
|
+
}
|
|
16531
|
+
const timeoutSeconds = options.timeout ? Number.parseInt(options.timeout, 10) : null;
|
|
16532
|
+
if (timeoutSeconds !== null && Number.isFinite(timeoutSeconds) && timeoutSeconds > 0) {
|
|
16533
|
+
runArgs.push("--tail-timeout-ms", String(timeoutSeconds * 1e3));
|
|
16534
|
+
}
|
|
16535
|
+
const captured = await runGeneratedEnrichPlay(runArgs, {
|
|
16536
|
+
passthroughStdout: !options.json
|
|
16537
|
+
});
|
|
16538
|
+
const status = options.json ? parseJsonOutput(captured.stdout) : await resolveWatchedGeneratedPlayStatus({
|
|
16539
|
+
client: client2,
|
|
16540
|
+
stdout: captured.stdout,
|
|
16541
|
+
exitCode: captured.result
|
|
16542
|
+
});
|
|
14873
16543
|
if (captured.result !== 0) {
|
|
14874
16544
|
if (options.json) {
|
|
14875
16545
|
printJson({
|
|
14876
|
-
deprecation: ENRICH_DEPRECATION_NOTICE,
|
|
14877
16546
|
result: status
|
|
14878
16547
|
});
|
|
14879
|
-
} else {
|
|
14880
|
-
process.stdout.write(captured.stdout);
|
|
14881
16548
|
}
|
|
14882
16549
|
process.exitCode = captured.result;
|
|
14883
16550
|
return;
|
|
14884
16551
|
}
|
|
14885
|
-
const exportResult =
|
|
16552
|
+
const exportResult = outputPath ? await writeOutputCsv(outputPath, status, {
|
|
16553
|
+
client: client2,
|
|
16554
|
+
config,
|
|
16555
|
+
sourceCsvPath,
|
|
16556
|
+
rows
|
|
16557
|
+
}) : null;
|
|
16558
|
+
const rowsForFailureReport = exportResult?.enrichedRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
|
|
14886
16559
|
if (options.json) {
|
|
16560
|
+
const failureReport2 = await maybeEmitEnrichFailureReport({
|
|
16561
|
+
config,
|
|
16562
|
+
rows: rowsForFailureReport,
|
|
16563
|
+
rowRange: rows,
|
|
16564
|
+
client: client2,
|
|
16565
|
+
outputPath: exportResult?.path ?? outputPath ?? null
|
|
16566
|
+
});
|
|
14887
16567
|
printJson({
|
|
14888
|
-
ok:
|
|
14889
|
-
deprecation: ENRICH_DEPRECATION_NOTICE,
|
|
16568
|
+
ok: !failureReport2,
|
|
14890
16569
|
run: status,
|
|
14891
|
-
output: exportResult
|
|
16570
|
+
output: exportResult ? { rows: exportResult.rows, path: exportResult.path } : null,
|
|
16571
|
+
...failureReport2 ? {
|
|
16572
|
+
failure_report: {
|
|
16573
|
+
path: failureReport2.path,
|
|
16574
|
+
jobs: failureReport2.jobs.length
|
|
16575
|
+
}
|
|
16576
|
+
} : {}
|
|
14892
16577
|
});
|
|
16578
|
+
if (failureReport2) {
|
|
16579
|
+
process.exitCode = EXIT_SERVER2;
|
|
16580
|
+
}
|
|
14893
16581
|
return;
|
|
14894
16582
|
}
|
|
14895
|
-
process.stdout.write(captured.stdout);
|
|
14896
16583
|
if (exportResult) {
|
|
14897
16584
|
process.stderr.write(
|
|
14898
16585
|
`Wrote ${exportResult.rows} row(s) to ${exportResult.path}
|
|
14899
16586
|
`
|
|
14900
16587
|
);
|
|
16588
|
+
const waterfallSummaryLines = buildEnrichWaterfallSummaryLines(
|
|
16589
|
+
config,
|
|
16590
|
+
exportResult.enrichedRows
|
|
16591
|
+
);
|
|
16592
|
+
if (waterfallSummaryLines.length > 0) {
|
|
16593
|
+
process.stdout.write(`${waterfallSummaryLines.join("\n")}
|
|
16594
|
+
`);
|
|
16595
|
+
}
|
|
16596
|
+
}
|
|
16597
|
+
const failureReport = await maybeEmitEnrichFailureReport({
|
|
16598
|
+
config,
|
|
16599
|
+
rows: rowsForFailureReport,
|
|
16600
|
+
rowRange: rows,
|
|
16601
|
+
client: client2,
|
|
16602
|
+
outputPath: exportResult?.path ?? outputPath ?? null
|
|
16603
|
+
});
|
|
16604
|
+
if (failureReport) {
|
|
16605
|
+
process.exitCode = EXIT_SERVER2;
|
|
14901
16606
|
}
|
|
14902
16607
|
} finally {
|
|
14903
16608
|
await (0, import_promises5.rm)(tempDir, { recursive: true, force: true });
|
|
@@ -15137,7 +16842,7 @@ async function readHiddenLine(prompt) {
|
|
|
15137
16842
|
if (typeof import_node_process.stdin.setRawMode === "function") import_node_process.stdin.setRawMode(true);
|
|
15138
16843
|
let value = "";
|
|
15139
16844
|
import_node_process.stdin.resume();
|
|
15140
|
-
return await new Promise((
|
|
16845
|
+
return await new Promise((resolve15, reject) => {
|
|
15141
16846
|
let settled = false;
|
|
15142
16847
|
const cleanup = () => {
|
|
15143
16848
|
import_node_process.stdin.off("data", onData);
|
|
@@ -15152,7 +16857,7 @@ async function readHiddenLine(prompt) {
|
|
|
15152
16857
|
settled = true;
|
|
15153
16858
|
import_node_process.stdout.write("\n");
|
|
15154
16859
|
cleanup();
|
|
15155
|
-
|
|
16860
|
+
resolve15(line);
|
|
15156
16861
|
};
|
|
15157
16862
|
const fail = (error) => {
|
|
15158
16863
|
if (settled) return;
|
|
@@ -15216,8 +16921,8 @@ function preventShellHistoryLeak(forbidden) {
|
|
|
15216
16921
|
}
|
|
15217
16922
|
}
|
|
15218
16923
|
async function handleList(options) {
|
|
15219
|
-
const
|
|
15220
|
-
const secrets = await
|
|
16924
|
+
const client2 = new DeeplineClient();
|
|
16925
|
+
const secrets = await client2.listSecrets();
|
|
15221
16926
|
printCommandEnvelope(
|
|
15222
16927
|
{
|
|
15223
16928
|
secrets,
|
|
@@ -15236,8 +16941,8 @@ async function handleList(options) {
|
|
|
15236
16941
|
}
|
|
15237
16942
|
async function handleCheck(nameInput, options) {
|
|
15238
16943
|
const name = normalizeSecretName(nameInput);
|
|
15239
|
-
const
|
|
15240
|
-
const secret = await
|
|
16944
|
+
const client2 = new DeeplineClient();
|
|
16945
|
+
const secret = await client2.checkSecret(name);
|
|
15241
16946
|
printCommandEnvelope(
|
|
15242
16947
|
{
|
|
15243
16948
|
ok: Boolean(secret),
|
|
@@ -15545,12 +17250,12 @@ function matchesGrepQuery(value, query, mode) {
|
|
|
15545
17250
|
return terms.every((term) => haystack.includes(term));
|
|
15546
17251
|
}
|
|
15547
17252
|
async function listTools(args) {
|
|
15548
|
-
const
|
|
17253
|
+
const client2 = new DeeplineClient();
|
|
15549
17254
|
const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
|
|
15550
17255
|
const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
|
|
15551
17256
|
const compact = !args.includes("--full");
|
|
15552
17257
|
const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
15553
|
-
const items = (await
|
|
17258
|
+
const items = (await client2.listTools({
|
|
15554
17259
|
...categoryFilter ? { categories: categoryFilter } : {},
|
|
15555
17260
|
compact
|
|
15556
17261
|
})).map(toListedTool).filter(
|
|
@@ -15597,8 +17302,8 @@ async function searchTools(queryInput, options = {}) {
|
|
|
15597
17302
|
console.error("Usage: deepline tools search <query> [--json]");
|
|
15598
17303
|
return 1;
|
|
15599
17304
|
}
|
|
15600
|
-
const
|
|
15601
|
-
const result = await
|
|
17305
|
+
const client2 = new DeeplineClient();
|
|
17306
|
+
const result = await client2.searchTools({
|
|
15602
17307
|
query,
|
|
15603
17308
|
categories: options.categories,
|
|
15604
17309
|
searchTerms: options.searchTerms,
|
|
@@ -15621,10 +17326,10 @@ async function grepTools(queryInput, options = {}) {
|
|
|
15621
17326
|
console.error("Usage: deepline tools grep <query> [--json]");
|
|
15622
17327
|
return 1;
|
|
15623
17328
|
}
|
|
15624
|
-
const
|
|
17329
|
+
const client2 = new DeeplineClient();
|
|
15625
17330
|
const requestedCategories = options.categories ? options.categories.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
15626
17331
|
const mode = options.mode ?? "all";
|
|
15627
|
-
const tools = (await
|
|
17332
|
+
const tools = (await client2.listTools({
|
|
15628
17333
|
grep: query,
|
|
15629
17334
|
grepMode: mode,
|
|
15630
17335
|
...options.categories ? { categories: options.categories } : {},
|
|
@@ -15694,12 +17399,12 @@ function compactTool(tool) {
|
|
|
15694
17399
|
function playIdentifiers(play) {
|
|
15695
17400
|
return [play.name, play.reference, ...play.aliases ?? []].filter((value) => Boolean(value?.trim())).map((value) => value.trim());
|
|
15696
17401
|
}
|
|
15697
|
-
async function findPlayForToolId(
|
|
17402
|
+
async function findPlayForToolId(client2, toolId) {
|
|
15698
17403
|
const requested = toolId.trim();
|
|
15699
17404
|
if (!requested) {
|
|
15700
17405
|
return null;
|
|
15701
17406
|
}
|
|
15702
|
-
const plays = await
|
|
17407
|
+
const plays = await client2.searchPlays({ query: requested, compact: true });
|
|
15703
17408
|
return plays.find((play) => playIdentifiers(play).includes(requested)) ?? null;
|
|
15704
17409
|
}
|
|
15705
17410
|
function playAliasToolErrorMessage(toolId, play) {
|
|
@@ -15714,7 +17419,7 @@ function printPlayAliasToolError(toolId, play) {
|
|
|
15714
17419
|
function isPlayLikeTool(tool) {
|
|
15715
17420
|
const record = tool;
|
|
15716
17421
|
if (record.isPlay === true || record.is_play === true) return true;
|
|
15717
|
-
const playExpansion =
|
|
17422
|
+
const playExpansion = recordField2(record, "playExpansion", "play_expansion");
|
|
15718
17423
|
if (Object.keys(playExpansion).length > 0) return true;
|
|
15719
17424
|
const toolId = typeof record.toolId === "string" ? record.toolId : "";
|
|
15720
17425
|
return toolId.endsWith("_waterfall");
|
|
@@ -15948,12 +17653,12 @@ async function getTool(toolId, options = {}) {
|
|
|
15948
17653
|
console.error("Usage: deepline tools get <toolId> [--json]");
|
|
15949
17654
|
return 1;
|
|
15950
17655
|
}
|
|
15951
|
-
const
|
|
17656
|
+
const client2 = new DeeplineClient();
|
|
15952
17657
|
let tool;
|
|
15953
17658
|
try {
|
|
15954
|
-
tool = await
|
|
17659
|
+
tool = await client2.getTool(toolId);
|
|
15955
17660
|
} catch (error) {
|
|
15956
|
-
const play = await findPlayForToolId(
|
|
17661
|
+
const play = await findPlayForToolId(client2, toolId);
|
|
15957
17662
|
if (play) {
|
|
15958
17663
|
printPlayAliasToolError(toolId, play);
|
|
15959
17664
|
return 2;
|
|
@@ -16020,10 +17725,10 @@ async function getTool(toolId, options = {}) {
|
|
|
16020
17725
|
function toolContractJsonForDescribe(tool, requestedToolId) {
|
|
16021
17726
|
const toolId = String(tool.toolId || requestedToolId);
|
|
16022
17727
|
const inputFields = toolInputFieldsForDisplay(
|
|
16023
|
-
|
|
17728
|
+
recordField2(tool, "inputSchema", "input_schema")
|
|
16024
17729
|
);
|
|
16025
|
-
const usageGuidance =
|
|
16026
|
-
const toolExecutionResult =
|
|
17730
|
+
const usageGuidance = recordField2(tool, "usageGuidance", "usage_guidance");
|
|
17731
|
+
const toolExecutionResult = recordField2(
|
|
16027
17732
|
usageGuidance,
|
|
16028
17733
|
"toolExecutionResult",
|
|
16029
17734
|
"tool_execution_result"
|
|
@@ -16034,7 +17739,7 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
|
|
|
16034
17739
|
const extractedValues = extractionContractEntries(
|
|
16035
17740
|
arrayField(toolExecutionResult, "extractedValues", "extracted_values")
|
|
16036
17741
|
);
|
|
16037
|
-
const cost =
|
|
17742
|
+
const cost = recordField2(tool, "cost");
|
|
16038
17743
|
const deeplineCredits = numberField(
|
|
16039
17744
|
tool,
|
|
16040
17745
|
"deeplineCreditsPerPricingUnit",
|
|
@@ -16088,7 +17793,7 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
|
|
|
16088
17793
|
}
|
|
16089
17794
|
function extractionContractEntries(entries) {
|
|
16090
17795
|
return entries.flatMap((entry) => {
|
|
16091
|
-
if (!
|
|
17796
|
+
if (!isRecord7(entry)) return [];
|
|
16092
17797
|
const name = stringField(entry, "name");
|
|
16093
17798
|
const expression = stringField(entry, "expression");
|
|
16094
17799
|
return name && expression ? [{ name, expression }] : [];
|
|
@@ -16096,8 +17801,8 @@ function extractionContractEntries(entries) {
|
|
|
16096
17801
|
}
|
|
16097
17802
|
function printCompactToolContract(tool, requestedToolId) {
|
|
16098
17803
|
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
16099
|
-
const cost =
|
|
16100
|
-
const getters =
|
|
17804
|
+
const cost = isRecord7(contract.cost) ? contract.cost : {};
|
|
17805
|
+
const getters = isRecord7(contract.getters) ? contract.getters : {};
|
|
16101
17806
|
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
16102
17807
|
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
16103
17808
|
const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
|
|
@@ -16114,7 +17819,7 @@ function printCompactToolContract(tool, requestedToolId) {
|
|
|
16114
17819
|
console.log("");
|
|
16115
17820
|
console.log("Inputs:");
|
|
16116
17821
|
for (const field of inputFields) {
|
|
16117
|
-
if (!
|
|
17822
|
+
if (!isRecord7(field)) continue;
|
|
16118
17823
|
const name = stringField(field, "name");
|
|
16119
17824
|
if (!name) continue;
|
|
16120
17825
|
const required = field.required ? "*" : "";
|
|
@@ -16127,7 +17832,7 @@ function printCompactToolContract(tool, requestedToolId) {
|
|
|
16127
17832
|
}
|
|
16128
17833
|
console.log("");
|
|
16129
17834
|
printToolExamplesOnly(tool, requestedToolId, { includeSamples: false });
|
|
16130
|
-
const starterScript =
|
|
17835
|
+
const starterScript = isRecord7(contract.starterScript) ? contract.starterScript : {};
|
|
16131
17836
|
const starterPath = stringField(starterScript, "path");
|
|
16132
17837
|
if (starterPath) {
|
|
16133
17838
|
console.log("");
|
|
@@ -16141,14 +17846,14 @@ function printCompactToolContract(tool, requestedToolId) {
|
|
|
16141
17846
|
console.log("Getters:");
|
|
16142
17847
|
if (listGetters.length) console.log("Lists:");
|
|
16143
17848
|
for (const entry of listGetters) {
|
|
16144
|
-
if (
|
|
17849
|
+
if (isRecord7(entry))
|
|
16145
17850
|
console.log(
|
|
16146
17851
|
`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
|
|
16147
17852
|
);
|
|
16148
17853
|
}
|
|
16149
17854
|
if (valueGetters.length) console.log("Values:");
|
|
16150
17855
|
for (const entry of valueGetters) {
|
|
16151
|
-
if (
|
|
17856
|
+
if (isRecord7(entry))
|
|
16152
17857
|
console.log(
|
|
16153
17858
|
`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
|
|
16154
17859
|
);
|
|
@@ -16161,7 +17866,7 @@ function printCompactToolContract(tool, requestedToolId) {
|
|
|
16161
17866
|
}
|
|
16162
17867
|
function printToolPricingOnly(tool, requestedToolId, options = {}) {
|
|
16163
17868
|
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
16164
|
-
const cost =
|
|
17869
|
+
const cost = isRecord7(contract.cost) ? contract.cost : {};
|
|
16165
17870
|
const pricingModel = stringField(cost, "pricingModel") || "unknown";
|
|
16166
17871
|
const billingMode = stringField(cost, "billingMode") || "unknown";
|
|
16167
17872
|
const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : pricingModel === "fixed" ? "call" : pricingModel.replace(/^per_/, "") || "unit";
|
|
@@ -16181,7 +17886,7 @@ function printToolSchemaOnly(tool, requestedToolId) {
|
|
|
16181
17886
|
}
|
|
16182
17887
|
console.log("Inputs:");
|
|
16183
17888
|
for (const field of inputFields) {
|
|
16184
|
-
if (!
|
|
17889
|
+
if (!isRecord7(field)) continue;
|
|
16185
17890
|
const name = stringField(field, "name");
|
|
16186
17891
|
if (!name) continue;
|
|
16187
17892
|
const required = field.required ? "*" : "";
|
|
@@ -16207,27 +17912,27 @@ function printToolExamplesOnly(tool, requestedToolId, options = {}) {
|
|
|
16207
17912
|
` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`
|
|
16208
17913
|
);
|
|
16209
17914
|
console.log("});");
|
|
16210
|
-
const getters =
|
|
17915
|
+
const getters = isRecord7(contract.getters) ? contract.getters : {};
|
|
16211
17916
|
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
16212
17917
|
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
16213
|
-
const firstGetter = [...valueGetters, ...listGetters].find(
|
|
17918
|
+
const firstGetter = [...valueGetters, ...listGetters].find(isRecord7);
|
|
16214
17919
|
if (firstGetter) {
|
|
16215
17920
|
const name = stringField(firstGetter, "name") || "value";
|
|
16216
17921
|
const expression = stringField(firstGetter, "expression");
|
|
16217
17922
|
if (expression)
|
|
16218
17923
|
console.log(
|
|
16219
|
-
`const ${
|
|
17924
|
+
`const ${safeIdentifier2(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`
|
|
16220
17925
|
);
|
|
16221
17926
|
}
|
|
16222
17927
|
console.log("```");
|
|
16223
17928
|
if (options.includeSamples !== false) {
|
|
16224
|
-
const samples =
|
|
17929
|
+
const samples = recordField2(tool, "samples");
|
|
16225
17930
|
printSamples(samples);
|
|
16226
17931
|
}
|
|
16227
17932
|
}
|
|
16228
17933
|
function printToolGettersOnly(tool, requestedToolId) {
|
|
16229
17934
|
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
16230
|
-
const getters =
|
|
17935
|
+
const getters = isRecord7(contract.getters) ? contract.getters : {};
|
|
16231
17936
|
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
16232
17937
|
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
16233
17938
|
console.log(`Getters: ${contract.toolId}`);
|
|
@@ -16240,7 +17945,7 @@ function printToolGettersOnly(tool, requestedToolId) {
|
|
|
16240
17945
|
if (listGetters.length) {
|
|
16241
17946
|
console.log("Lists:");
|
|
16242
17947
|
for (const entry of listGetters) {
|
|
16243
|
-
if (
|
|
17948
|
+
if (isRecord7(entry))
|
|
16244
17949
|
console.log(
|
|
16245
17950
|
`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
|
|
16246
17951
|
);
|
|
@@ -16249,7 +17954,7 @@ function printToolGettersOnly(tool, requestedToolId) {
|
|
|
16249
17954
|
if (valueGetters.length) {
|
|
16250
17955
|
console.log("Values:");
|
|
16251
17956
|
for (const entry of valueGetters) {
|
|
16252
|
-
if (
|
|
17957
|
+
if (isRecord7(entry))
|
|
16253
17958
|
console.log(
|
|
16254
17959
|
`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`
|
|
16255
17960
|
);
|
|
@@ -16275,7 +17980,7 @@ function sampleValueForField(field) {
|
|
|
16275
17980
|
function samplePayloadForInputFields(fields) {
|
|
16276
17981
|
return Object.fromEntries(
|
|
16277
17982
|
fields.slice(0, 4).flatMap((field) => {
|
|
16278
|
-
if (!
|
|
17983
|
+
if (!isRecord7(field)) return [];
|
|
16279
17984
|
const name = stringField(field, "name");
|
|
16280
17985
|
if (!name) return [];
|
|
16281
17986
|
return [[name, sampleValueForField(field)]];
|
|
@@ -16285,7 +17990,7 @@ function samplePayloadForInputFields(fields) {
|
|
|
16285
17990
|
function stableStepIdForTool(toolId) {
|
|
16286
17991
|
return toolId.replace(/^[a-z0-9]+_/, "").replace(/[^a-z0-9_]+/gi, "_") || "tool_call";
|
|
16287
17992
|
}
|
|
16288
|
-
function
|
|
17993
|
+
function safeIdentifier2(name) {
|
|
16289
17994
|
const cleaned = name.replace(/[^a-zA-Z0-9_$]+/g, "_").replace(/^[^a-zA-Z_$]+/, "");
|
|
16290
17995
|
return cleaned || "value";
|
|
16291
17996
|
}
|
|
@@ -16298,7 +18003,7 @@ function playResultExpression(entry) {
|
|
|
16298
18003
|
function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
16299
18004
|
const toolId = String(tool.toolId || requestedToolId);
|
|
16300
18005
|
const inputFields = toolInputFieldsForDisplay(
|
|
16301
|
-
|
|
18006
|
+
recordField2(tool, "inputSchema", "input_schema")
|
|
16302
18007
|
);
|
|
16303
18008
|
const starterScript = seedToolListScript({
|
|
16304
18009
|
toolId,
|
|
@@ -16325,7 +18030,7 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
|
16325
18030
|
provider: tool.provider,
|
|
16326
18031
|
displayName: tool.displayName,
|
|
16327
18032
|
usageGuidance: usageGuidanceWithAccessDefaults(
|
|
16328
|
-
|
|
18033
|
+
recordField2(tool, "usageGuidance", "usage_guidance")
|
|
16329
18034
|
),
|
|
16330
18035
|
runtimeOutputHelp: {
|
|
16331
18036
|
contract: "tools describe shows declared schema and Deepline getters; it is not an observed provider response.",
|
|
@@ -16350,7 +18055,7 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
|
16350
18055
|
}
|
|
16351
18056
|
function usageGuidanceWithAccessDefaults(usageGuidance) {
|
|
16352
18057
|
if (Object.keys(usageGuidance).length === 0) return usageGuidance;
|
|
16353
|
-
const existingAccess =
|
|
18058
|
+
const existingAccess = recordField2(usageGuidance, "access");
|
|
16354
18059
|
return {
|
|
16355
18060
|
...usageGuidance,
|
|
16356
18061
|
access: {
|
|
@@ -16383,18 +18088,18 @@ function listedToolDescription(tool) {
|
|
|
16383
18088
|
}
|
|
16384
18089
|
function formatListedToolCost(tool) {
|
|
16385
18090
|
const record = tool;
|
|
16386
|
-
const pricing =
|
|
18091
|
+
const pricing = recordField2(record, "pricing");
|
|
16387
18092
|
const displayText = stringField(pricing, "displayText", "display_text");
|
|
16388
18093
|
return displayText ? `Cost: ${displayText}` : "";
|
|
16389
18094
|
}
|
|
16390
18095
|
function toolInputFieldsForDisplay(inputSchema) {
|
|
16391
18096
|
if (Array.isArray(inputSchema.fields))
|
|
16392
|
-
return inputSchema.fields.filter(
|
|
16393
|
-
const jsonSchema =
|
|
16394
|
-
const properties =
|
|
18097
|
+
return inputSchema.fields.filter(isRecord7);
|
|
18098
|
+
const jsonSchema = isRecord7(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
|
|
18099
|
+
const properties = isRecord7(jsonSchema.properties) ? jsonSchema.properties : {};
|
|
16395
18100
|
const required = Array.isArray(jsonSchema.required) ? new Set(jsonSchema.required.map(String)) : /* @__PURE__ */ new Set();
|
|
16396
18101
|
return Object.entries(properties).map(([name, value]) => {
|
|
16397
|
-
const property =
|
|
18102
|
+
const property = isRecord7(value) ? value : {};
|
|
16398
18103
|
return {
|
|
16399
18104
|
name,
|
|
16400
18105
|
type: typeof property.type === "string" ? property.type : "unknown",
|
|
@@ -16423,15 +18128,15 @@ function printJsonPreview(label, payload) {
|
|
|
16423
18128
|
}
|
|
16424
18129
|
function samplePayload(samples, key) {
|
|
16425
18130
|
const entry = samples[key];
|
|
16426
|
-
if (!
|
|
18131
|
+
if (!isRecord7(entry)) return void 0;
|
|
16427
18132
|
return Object.prototype.hasOwnProperty.call(entry, "payload") ? entry.payload : entry;
|
|
16428
18133
|
}
|
|
16429
18134
|
function commandEnvelopeFromRawResponse(rawResponse) {
|
|
16430
|
-
return
|
|
18135
|
+
return isRecord7(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
|
|
16431
18136
|
}
|
|
16432
18137
|
function listExtractorPathsFromUsageGuidance(tool) {
|
|
16433
18138
|
const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
|
|
16434
|
-
const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists :
|
|
18139
|
+
const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord7(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
|
|
16435
18140
|
return extractedLists.flatMap((entry) => {
|
|
16436
18141
|
const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
|
|
16437
18142
|
if (!Array.isArray(paths)) return [];
|
|
@@ -16447,7 +18152,7 @@ function formatDecimal(value) {
|
|
|
16447
18152
|
function formatUsd(value) {
|
|
16448
18153
|
return `$${formatDecimal(value)}`;
|
|
16449
18154
|
}
|
|
16450
|
-
function
|
|
18155
|
+
function isRecord7(value) {
|
|
16451
18156
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
16452
18157
|
}
|
|
16453
18158
|
function stringField(source, ...keys) {
|
|
@@ -16471,10 +18176,10 @@ function arrayField(source, ...keys) {
|
|
|
16471
18176
|
}
|
|
16472
18177
|
return [];
|
|
16473
18178
|
}
|
|
16474
|
-
function
|
|
18179
|
+
function recordField2(source, ...keys) {
|
|
16475
18180
|
for (const key of keys) {
|
|
16476
18181
|
const value = source[key];
|
|
16477
|
-
if (
|
|
18182
|
+
if (isRecord7(value)) return value;
|
|
16478
18183
|
}
|
|
16479
18184
|
return {};
|
|
16480
18185
|
}
|
|
@@ -16540,7 +18245,7 @@ function parseJsonObjectArgument(raw, flagName) {
|
|
|
16540
18245
|
}
|
|
16541
18246
|
throw invalidJsonError(flagName, message);
|
|
16542
18247
|
}
|
|
16543
|
-
if (!
|
|
18248
|
+
if (!isRecord7(parsed)) {
|
|
16544
18249
|
throw invalidJsonError(flagName, "expected an object.");
|
|
16545
18250
|
}
|
|
16546
18251
|
return parsed;
|
|
@@ -16663,7 +18368,7 @@ function buildToolExecuteBaseEnvelope(input2) {
|
|
|
16663
18368
|
kind: summaryEntries.length > 0 ? "object" : "raw",
|
|
16664
18369
|
summary: input2.summary
|
|
16665
18370
|
};
|
|
16666
|
-
const envelopeHasCanonicalOutput =
|
|
18371
|
+
const envelopeHasCanonicalOutput = isRecord7(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
|
|
16667
18372
|
const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote(JSON.stringify(input2.params))} --json`;
|
|
16668
18373
|
const actions = input2.listConversion ? [
|
|
16669
18374
|
{
|
|
@@ -16718,12 +18423,12 @@ async function executeTool(args) {
|
|
|
16718
18423
|
}
|
|
16719
18424
|
return 1;
|
|
16720
18425
|
}
|
|
16721
|
-
const
|
|
18426
|
+
const client2 = new DeeplineClient();
|
|
16722
18427
|
let metadata;
|
|
16723
18428
|
try {
|
|
16724
|
-
metadata = await
|
|
18429
|
+
metadata = await client2.getTool(parsed.toolId);
|
|
16725
18430
|
} catch (error) {
|
|
16726
|
-
const play = await findPlayForToolId(
|
|
18431
|
+
const play = await findPlayForToolId(client2, parsed.toolId);
|
|
16727
18432
|
if (play) {
|
|
16728
18433
|
if (argsWantJson(args)) {
|
|
16729
18434
|
printJsonError(
|
|
@@ -16747,7 +18452,7 @@ async function executeTool(args) {
|
|
|
16747
18452
|
}
|
|
16748
18453
|
return 2;
|
|
16749
18454
|
}
|
|
16750
|
-
const rawResponse = await
|
|
18455
|
+
const rawResponse = await client2.executeTool(parsed.toolId, parsed.params);
|
|
16751
18456
|
const listConversion = tryConvertToList(rawResponse, {
|
|
16752
18457
|
listExtractorPaths: listExtractorPathsFromUsageGuidance(metadata)
|
|
16753
18458
|
});
|
|
@@ -16772,7 +18477,7 @@ async function executeTool(args) {
|
|
|
16772
18477
|
{
|
|
16773
18478
|
...baseEnvelope,
|
|
16774
18479
|
local: {
|
|
16775
|
-
...
|
|
18480
|
+
...isRecord7(baseEnvelope.local) ? baseEnvelope.local : {},
|
|
16776
18481
|
payload_file: jsonPath
|
|
16777
18482
|
}
|
|
16778
18483
|
},
|
|
@@ -16893,10 +18598,499 @@ async function executeTool(args) {
|
|
|
16893
18598
|
return 0;
|
|
16894
18599
|
}
|
|
16895
18600
|
|
|
18601
|
+
// src/cli/commands/workflow.ts
|
|
18602
|
+
var import_promises6 = require("fs/promises");
|
|
18603
|
+
var import_node_path16 = require("path");
|
|
18604
|
+
|
|
18605
|
+
// src/cli/workflow-to-play.ts
|
|
18606
|
+
var import_node_crypto4 = require("crypto");
|
|
18607
|
+
var HITL_WAIT_FOR_SIGNAL_TOOL = "deepline_workflow_wait_for_signal";
|
|
18608
|
+
var HITL_SLACK_TOOL = "slack_message_with_hitl";
|
|
18609
|
+
var SUB_WORKFLOW_TOOL_PREFIX = "deepline_workflow_";
|
|
18610
|
+
var UNSUPPORTED_REASON_HINT = {
|
|
18611
|
+
unsafe_user_code: "a step's JavaScript (extract_js / run_if_js / run_javascript) uses non-deterministic or sandbox-escaping code (e.g. new Date(), Date.now(), Math.random(), fetch, require). Plays replay deterministically inside a sandbox, so the compiler rejects it \u2014 rewrite it to compute from the row/result before migrating.",
|
|
18612
|
+
hitl: "human-in-the-loop / wait-for-signal steps have no play-runtime equivalent yet.",
|
|
18613
|
+
sub_workflow: "sub-workflow calls have no play-runtime equivalent yet (a future ctx.runPlay bridge).",
|
|
18614
|
+
nested_waterfall: "nested with_waterfall blocks are not supported by the play compiler.",
|
|
18615
|
+
inline_secret: 'a step inlines a hardcoded secret (API key / token / private key). Plays forbid inline secrets \u2014 move it to a dashboard secret and read it with ctx.secrets.get("NAME") before migrating.'
|
|
18616
|
+
};
|
|
18617
|
+
var UnsupportedWorkflowCommandError = class extends Error {
|
|
18618
|
+
status = 400;
|
|
18619
|
+
unsupported;
|
|
18620
|
+
constructor(unsupported) {
|
|
18621
|
+
super(
|
|
18622
|
+
`Workflow uses ${unsupported.length} command${unsupported.length === 1 ? "" : "s"} that cannot run as a play yet: ${unsupported.map((entry) => `${entry.alias} (${entry.reason})`).join(", ")}.`
|
|
18623
|
+
);
|
|
18624
|
+
this.name = "UnsupportedWorkflowCommandError";
|
|
18625
|
+
this.unsupported = unsupported;
|
|
18626
|
+
}
|
|
18627
|
+
};
|
|
18628
|
+
function isWaterfall2(command) {
|
|
18629
|
+
return "with_waterfall" in command;
|
|
18630
|
+
}
|
|
18631
|
+
function stepInlinedText(command) {
|
|
18632
|
+
return [
|
|
18633
|
+
JSON.stringify(command.payload ?? {}),
|
|
18634
|
+
command.extract_js ?? "",
|
|
18635
|
+
command.run_if_js ?? ""
|
|
18636
|
+
].join("\n");
|
|
18637
|
+
}
|
|
18638
|
+
function stepUserCode(command) {
|
|
18639
|
+
const code = [];
|
|
18640
|
+
if (command.extract_js) code.push(command.extract_js);
|
|
18641
|
+
if (command.run_if_js) code.push(command.run_if_js);
|
|
18642
|
+
if (command.tool === "run_javascript" && typeof command.payload?.code === "string") {
|
|
18643
|
+
code.push(command.payload.code);
|
|
18644
|
+
}
|
|
18645
|
+
return code;
|
|
18646
|
+
}
|
|
18647
|
+
function hasUnsafeUserCode(command) {
|
|
18648
|
+
return stepUserCode(command).some((code) => {
|
|
18649
|
+
try {
|
|
18650
|
+
assertUserCodeIsSafe(code, "play step code");
|
|
18651
|
+
return false;
|
|
18652
|
+
} catch {
|
|
18653
|
+
return true;
|
|
18654
|
+
}
|
|
18655
|
+
});
|
|
18656
|
+
}
|
|
18657
|
+
function classifyUnsupportedCommand(command) {
|
|
18658
|
+
const { tool } = command;
|
|
18659
|
+
if (tool === HITL_SLACK_TOOL || tool === HITL_WAIT_FOR_SIGNAL_TOOL) {
|
|
18660
|
+
return "hitl";
|
|
18661
|
+
}
|
|
18662
|
+
if (tool.startsWith(SUB_WORKFLOW_TOOL_PREFIX)) return "sub_workflow";
|
|
18663
|
+
if (collectInlineSecretFindings(stepInlinedText(command)).length > 0) {
|
|
18664
|
+
return "inline_secret";
|
|
18665
|
+
}
|
|
18666
|
+
if (hasUnsafeUserCode(command)) return "unsafe_user_code";
|
|
18667
|
+
return null;
|
|
18668
|
+
}
|
|
18669
|
+
function collectStepOffenders(command, offenders) {
|
|
18670
|
+
if (command.disabled) return;
|
|
18671
|
+
const reason = classifyUnsupportedCommand(command);
|
|
18672
|
+
if (reason) {
|
|
18673
|
+
offenders.push({ alias: command.alias, tool: command.tool, reason });
|
|
18674
|
+
}
|
|
18675
|
+
}
|
|
18676
|
+
function findUnsupportedWorkflowCommands(config) {
|
|
18677
|
+
const offenders = [];
|
|
18678
|
+
for (const command of config.commands ?? []) {
|
|
18679
|
+
if (!isWaterfall2(command)) {
|
|
18680
|
+
collectStepOffenders(command, offenders);
|
|
18681
|
+
continue;
|
|
18682
|
+
}
|
|
18683
|
+
for (const child of command.commands ?? []) {
|
|
18684
|
+
if (isWaterfall2(child)) {
|
|
18685
|
+
offenders.push({
|
|
18686
|
+
alias: command.with_waterfall,
|
|
18687
|
+
tool: "with_waterfall",
|
|
18688
|
+
reason: "nested_waterfall"
|
|
18689
|
+
});
|
|
18690
|
+
continue;
|
|
18691
|
+
}
|
|
18692
|
+
collectStepOffenders(child, offenders);
|
|
18693
|
+
}
|
|
18694
|
+
}
|
|
18695
|
+
return offenders;
|
|
18696
|
+
}
|
|
18697
|
+
function validateWorkflowConfigForPlay(config) {
|
|
18698
|
+
const offenders = findUnsupportedWorkflowCommands(config);
|
|
18699
|
+
if (offenders.length > 0) {
|
|
18700
|
+
throw new UnsupportedWorkflowCommandError(offenders);
|
|
18701
|
+
}
|
|
18702
|
+
}
|
|
18703
|
+
function describeUnsupportedReason(reason) {
|
|
18704
|
+
return UNSUPPORTED_REASON_HINT[reason];
|
|
18705
|
+
}
|
|
18706
|
+
var MAX_PLAY_NAME_LENGTH = 39;
|
|
18707
|
+
function sanitizePlayNameSegment(value) {
|
|
18708
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
|
|
18709
|
+
}
|
|
18710
|
+
function deriveWorkflowPlayName(workflowName) {
|
|
18711
|
+
const base = sanitizePlayNameSegment(workflowName) || "workflow";
|
|
18712
|
+
const suffix = (0, import_node_crypto4.createHash)("sha256").update(workflowName).digest("hex").slice(0, 8);
|
|
18713
|
+
const reserved = suffix.length + 1;
|
|
18714
|
+
const allowedBase = Math.max(1, MAX_PLAY_NAME_LENGTH - reserved);
|
|
18715
|
+
let name = `${base.slice(0, allowedBase)}_${suffix}`;
|
|
18716
|
+
if (name.startsWith("prebuilt")) {
|
|
18717
|
+
name = `wf_${name}`.slice(0, MAX_PLAY_NAME_LENGTH);
|
|
18718
|
+
}
|
|
18719
|
+
return name;
|
|
18720
|
+
}
|
|
18721
|
+
function compileWorkflowConfigToPlay(config, options) {
|
|
18722
|
+
validateWorkflowConfigForPlay(config);
|
|
18723
|
+
const playName = deriveWorkflowPlayName(options.workflowName);
|
|
18724
|
+
const sourceCode = compileEnrichConfigToPlaySource(config, {
|
|
18725
|
+
playName,
|
|
18726
|
+
inlineRunJavascript: true,
|
|
18727
|
+
idiomaticGetters: true
|
|
18728
|
+
});
|
|
18729
|
+
const warnings = [];
|
|
18730
|
+
if (typeof config.cost_cap_usd_per_run === "number") {
|
|
18731
|
+
warnings.push(
|
|
18732
|
+
`cost_cap_usd_per_run ($${config.cost_cap_usd_per_run}) was not carried into the play \u2014 credits are not USD. Set billing.maxCreditsPerRun manually after checking your credit conversion.`
|
|
18733
|
+
);
|
|
18734
|
+
}
|
|
18735
|
+
return { playName, sourceCode, warnings };
|
|
18736
|
+
}
|
|
18737
|
+
|
|
18738
|
+
// src/cli/commands/workflow.ts
|
|
18739
|
+
var PLAY_EQUIVALENT = {
|
|
18740
|
+
list: "deepline plays list",
|
|
18741
|
+
get: "deepline plays get <name>",
|
|
18742
|
+
call: "deepline plays run <name>",
|
|
18743
|
+
apply: "deepline plays publish <file>",
|
|
18744
|
+
lint: "deepline plays check <file>",
|
|
18745
|
+
schema: "deepline plays describe <name>",
|
|
18746
|
+
runs: "deepline runs list --play <name>",
|
|
18747
|
+
run: "deepline runs get <run-id>",
|
|
18748
|
+
tail: "deepline runs tail <run-id>",
|
|
18749
|
+
cancel: "deepline runs stop <run-id>",
|
|
18750
|
+
delete: "deepline plays delete <name>"
|
|
18751
|
+
};
|
|
18752
|
+
var MIGRATE_HINT = "deepline workflows transform <id>";
|
|
18753
|
+
var JSON_OPTION_DESCRIPTION = "Emit JSON output. Also automatic when stdout is piped";
|
|
18754
|
+
function withJsonOption(command) {
|
|
18755
|
+
return command.option("--json", JSON_OPTION_DESCRIPTION);
|
|
18756
|
+
}
|
|
18757
|
+
var TERMINAL_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
18758
|
+
"completed",
|
|
18759
|
+
"succeeded",
|
|
18760
|
+
"success",
|
|
18761
|
+
"failed",
|
|
18762
|
+
"error",
|
|
18763
|
+
"errored",
|
|
18764
|
+
"cancelled",
|
|
18765
|
+
"canceled",
|
|
18766
|
+
"done"
|
|
18767
|
+
]);
|
|
18768
|
+
function migrationDeprecation(command) {
|
|
18769
|
+
const use = PLAY_EQUIVALENT[command];
|
|
18770
|
+
if (!use) return null;
|
|
18771
|
+
return { use, migrate: MIGRATE_HINT };
|
|
18772
|
+
}
|
|
18773
|
+
function noticeToStderr(command) {
|
|
18774
|
+
const deprecation = migrationDeprecation(command);
|
|
18775
|
+
if (!deprecation) return;
|
|
18776
|
+
process.stderr.write(
|
|
18777
|
+
`note: \`deepline workflows ${command}\` is a legacy surface \u2014 workflows are becoming plays.
|
|
18778
|
+
equivalent: \`${deprecation.use}\`
|
|
18779
|
+
migrate this workflow: \`${MIGRATE_HINT}\`
|
|
18780
|
+
`
|
|
18781
|
+
);
|
|
18782
|
+
}
|
|
18783
|
+
function emitPassThrough(command, payload, options) {
|
|
18784
|
+
const json = shouldEmitJson(options.json);
|
|
18785
|
+
const deprecation = migrationDeprecation(command);
|
|
18786
|
+
if (json) {
|
|
18787
|
+
const enriched = payload && typeof payload === "object" && !Array.isArray(payload) ? { ...payload, deprecation } : { result: payload, deprecation };
|
|
18788
|
+
printJson(enriched);
|
|
18789
|
+
return;
|
|
18790
|
+
}
|
|
18791
|
+
printJson(payload);
|
|
18792
|
+
noticeToStderr(command);
|
|
18793
|
+
}
|
|
18794
|
+
function client() {
|
|
18795
|
+
return new DeeplineClient();
|
|
18796
|
+
}
|
|
18797
|
+
function readStatus(payload) {
|
|
18798
|
+
if (!payload || typeof payload !== "object") return null;
|
|
18799
|
+
const record = payload;
|
|
18800
|
+
if (typeof record.status === "string") return record.status;
|
|
18801
|
+
const run = record.run;
|
|
18802
|
+
if (run && typeof run === "object") {
|
|
18803
|
+
const status = run.status;
|
|
18804
|
+
if (typeof status === "string") return status;
|
|
18805
|
+
}
|
|
18806
|
+
return null;
|
|
18807
|
+
}
|
|
18808
|
+
async function readJsonOption(payload, file) {
|
|
18809
|
+
if (file) {
|
|
18810
|
+
const raw = await (0, import_promises6.readFile)((0, import_node_path16.resolve)(file), "utf8");
|
|
18811
|
+
return JSON.parse(raw);
|
|
18812
|
+
}
|
|
18813
|
+
if (payload) {
|
|
18814
|
+
return JSON.parse(payload);
|
|
18815
|
+
}
|
|
18816
|
+
throw new Error("Provide --payload <json> or --file <path>.");
|
|
18817
|
+
}
|
|
18818
|
+
async function transformOne(api, workflowId, outDir, publish) {
|
|
18819
|
+
const { workflow } = await api.getWorkflow(workflowId);
|
|
18820
|
+
if (!workflow) {
|
|
18821
|
+
return {
|
|
18822
|
+
ok: false,
|
|
18823
|
+
workflowId,
|
|
18824
|
+
workflowName: workflowId,
|
|
18825
|
+
reason: "Workflow not found."
|
|
18826
|
+
};
|
|
18827
|
+
}
|
|
18828
|
+
const revision = workflow.current_published_revision;
|
|
18829
|
+
if (!revision) {
|
|
18830
|
+
return {
|
|
18831
|
+
ok: false,
|
|
18832
|
+
workflowId,
|
|
18833
|
+
workflowName: workflow.name,
|
|
18834
|
+
reason: "Workflow has no published revision to transform."
|
|
18835
|
+
};
|
|
18836
|
+
}
|
|
18837
|
+
try {
|
|
18838
|
+
const compiled = compileWorkflowConfigToPlay(
|
|
18839
|
+
// The API returns the config as `unknown`; it is structurally the
|
|
18840
|
+
// EnrichCompiledConfig the compiler expects. Cast at this single boundary.
|
|
18841
|
+
revision.config,
|
|
18842
|
+
{ workflowName: workflow.name, version: revision.version }
|
|
18843
|
+
);
|
|
18844
|
+
const file = (0, import_node_path16.join)((0, import_node_path16.resolve)(outDir), `${compiled.playName}.play.ts`);
|
|
18845
|
+
await (0, import_promises6.mkdir)((0, import_node_path16.dirname)(file), { recursive: true });
|
|
18846
|
+
await (0, import_promises6.writeFile)(file, compiled.sourceCode, "utf8");
|
|
18847
|
+
let published = false;
|
|
18848
|
+
if (publish) {
|
|
18849
|
+
const code = await handlePlayPublish([file]);
|
|
18850
|
+
if (code !== 0) {
|
|
18851
|
+
return {
|
|
18852
|
+
ok: false,
|
|
18853
|
+
workflowId,
|
|
18854
|
+
workflowName: workflow.name,
|
|
18855
|
+
reason: `Wrote ${file} but publish failed (exit ${code}).`
|
|
18856
|
+
};
|
|
18857
|
+
}
|
|
18858
|
+
published = true;
|
|
18859
|
+
}
|
|
18860
|
+
return {
|
|
18861
|
+
ok: true,
|
|
18862
|
+
workflowId,
|
|
18863
|
+
workflowName: workflow.name,
|
|
18864
|
+
playName: compiled.playName,
|
|
18865
|
+
file,
|
|
18866
|
+
warnings: compiled.warnings,
|
|
18867
|
+
published
|
|
18868
|
+
};
|
|
18869
|
+
} catch (error) {
|
|
18870
|
+
if (error instanceof UnsupportedWorkflowCommandError) {
|
|
18871
|
+
return {
|
|
18872
|
+
ok: false,
|
|
18873
|
+
workflowId,
|
|
18874
|
+
workflowName: workflow.name,
|
|
18875
|
+
reason: error.unsupported.map((u) => `${u.alias} (${describeUnsupportedReason(u.reason)})`).join("; "),
|
|
18876
|
+
unsupported: error.unsupported
|
|
18877
|
+
};
|
|
18878
|
+
}
|
|
18879
|
+
throw error;
|
|
18880
|
+
}
|
|
18881
|
+
}
|
|
18882
|
+
function renderTransformReport(outcomes) {
|
|
18883
|
+
const lines = [];
|
|
18884
|
+
for (const outcome of outcomes) {
|
|
18885
|
+
if (outcome.ok) {
|
|
18886
|
+
lines.push(
|
|
18887
|
+
`\u2705 ${outcome.workflowName} \u2192 ${outcome.file}` + (outcome.published ? " (published)" : ` (next: deepline plays publish ${outcome.file})`)
|
|
18888
|
+
);
|
|
18889
|
+
for (const warning of outcome.warnings) {
|
|
18890
|
+
lines.push(` \u26A0\uFE0F ${warning}`);
|
|
18891
|
+
}
|
|
18892
|
+
} else {
|
|
18893
|
+
lines.push(`\u26A0\uFE0F ${outcome.workflowName} \u2014 skipped: ${outcome.reason}`);
|
|
18894
|
+
}
|
|
18895
|
+
}
|
|
18896
|
+
const ok = outcomes.filter((o) => o.ok).length;
|
|
18897
|
+
const total = outcomes.length;
|
|
18898
|
+
const manual = total - ok;
|
|
18899
|
+
lines.push("");
|
|
18900
|
+
lines.push(
|
|
18901
|
+
`${ok}/${total} transformed` + (manual > 0 ? `, ${manual} need manual attention` : "")
|
|
18902
|
+
);
|
|
18903
|
+
return `${lines.join("\n")}
|
|
18904
|
+
`;
|
|
18905
|
+
}
|
|
18906
|
+
async function handleTransform(id, options) {
|
|
18907
|
+
const api = client();
|
|
18908
|
+
const outDir = options.out ?? "./plays";
|
|
18909
|
+
const publish = options.publish === true;
|
|
18910
|
+
let ids;
|
|
18911
|
+
if (options.all) {
|
|
18912
|
+
const { workflows } = await api.listWorkflows();
|
|
18913
|
+
ids = workflows.map((w) => w.id);
|
|
18914
|
+
} else if (id) {
|
|
18915
|
+
ids = [id];
|
|
18916
|
+
} else {
|
|
18917
|
+
throw new Error("Provide a workflow <id> or --all.");
|
|
18918
|
+
}
|
|
18919
|
+
const outcomes = [];
|
|
18920
|
+
for (const workflowId of ids) {
|
|
18921
|
+
outcomes.push(await transformOne(api, workflowId, outDir, publish));
|
|
18922
|
+
}
|
|
18923
|
+
printCommandEnvelope(
|
|
18924
|
+
{ outcomes, deprecation: null },
|
|
18925
|
+
{
|
|
18926
|
+
json: shouldEmitJson(options.json),
|
|
18927
|
+
text: renderTransformReport(outcomes)
|
|
18928
|
+
}
|
|
18929
|
+
);
|
|
18930
|
+
return outcomes.every((o) => o.ok) ? 0 : 1;
|
|
18931
|
+
}
|
|
18932
|
+
async function handleList2(options) {
|
|
18933
|
+
const limit = options.limit ? Number(options.limit) : void 0;
|
|
18934
|
+
const result = await client().listWorkflows({
|
|
18935
|
+
limit: Number.isFinite(limit) ? limit : void 0
|
|
18936
|
+
});
|
|
18937
|
+
emitPassThrough("list", result, options);
|
|
18938
|
+
}
|
|
18939
|
+
async function handleGet(id, options) {
|
|
18940
|
+
emitPassThrough("get", await client().getWorkflow(id), options);
|
|
18941
|
+
}
|
|
18942
|
+
async function handleDelete(id, options) {
|
|
18943
|
+
emitPassThrough("delete", await client().deleteWorkflow(id), options);
|
|
18944
|
+
}
|
|
18945
|
+
async function handleDisable(id, options) {
|
|
18946
|
+
const result = await client().disableWorkflow(id);
|
|
18947
|
+
printJson(result);
|
|
18948
|
+
}
|
|
18949
|
+
async function handleEnable(id, options) {
|
|
18950
|
+
const result = await client().enableWorkflow(id);
|
|
18951
|
+
printJson(result);
|
|
18952
|
+
}
|
|
18953
|
+
async function handleApply(options) {
|
|
18954
|
+
const body = await readJsonOption(options.payload, options.file);
|
|
18955
|
+
emitPassThrough("apply", await client().applyWorkflow(body), options);
|
|
18956
|
+
}
|
|
18957
|
+
async function handleLint(options) {
|
|
18958
|
+
const body = await readJsonOption(options.payload, options.file);
|
|
18959
|
+
emitPassThrough("lint", await client().lintWorkflow(body), options);
|
|
18960
|
+
}
|
|
18961
|
+
async function handleSchema(options) {
|
|
18962
|
+
emitPassThrough(
|
|
18963
|
+
"schema",
|
|
18964
|
+
await client().getWorkflowSchema(options.subject),
|
|
18965
|
+
options
|
|
18966
|
+
);
|
|
18967
|
+
}
|
|
18968
|
+
async function handleCall(options) {
|
|
18969
|
+
const body = {};
|
|
18970
|
+
if (options.workflowId) body.workflow_id = options.workflowId;
|
|
18971
|
+
if (options.workflowName) body.workflow_name = options.workflowName;
|
|
18972
|
+
const input2 = options.payload ? JSON.parse(options.payload) : {};
|
|
18973
|
+
if (options.mode) input2.__execution_mode = options.mode;
|
|
18974
|
+
body.input = input2;
|
|
18975
|
+
emitPassThrough("call", await client().callWorkflow(body), options);
|
|
18976
|
+
}
|
|
18977
|
+
async function handleRuns(id, options) {
|
|
18978
|
+
const limit = options.limit ? Number(options.limit) : void 0;
|
|
18979
|
+
emitPassThrough(
|
|
18980
|
+
"runs",
|
|
18981
|
+
await client().listWorkflowRuns(id, {
|
|
18982
|
+
limit: Number.isFinite(limit) ? limit : void 0
|
|
18983
|
+
}),
|
|
18984
|
+
options
|
|
18985
|
+
);
|
|
18986
|
+
}
|
|
18987
|
+
async function handleRun(id, runId, options) {
|
|
18988
|
+
emitPassThrough("run", await client().getWorkflowRun(id, runId), options);
|
|
18989
|
+
}
|
|
18990
|
+
async function handleCancel(id, runId, options) {
|
|
18991
|
+
emitPassThrough(
|
|
18992
|
+
"cancel",
|
|
18993
|
+
await client().cancelWorkflowRun(id, runId),
|
|
18994
|
+
options
|
|
18995
|
+
);
|
|
18996
|
+
}
|
|
18997
|
+
async function handleTail(id, runId, options) {
|
|
18998
|
+
const api = client();
|
|
18999
|
+
const intervalMs = Math.max(500, Number(options.intervalMs ?? 2e3) || 2e3);
|
|
19000
|
+
const deadline = Date.now() + 10 * 6e4;
|
|
19001
|
+
for (; ; ) {
|
|
19002
|
+
const run = await api.getWorkflowRun(id, runId);
|
|
19003
|
+
emitPassThrough("tail", run, options);
|
|
19004
|
+
const status = readStatus(run);
|
|
19005
|
+
if (status && TERMINAL_RUN_STATUSES.has(status) || Date.now() > deadline) {
|
|
19006
|
+
return;
|
|
19007
|
+
}
|
|
19008
|
+
await sleep3(intervalMs);
|
|
19009
|
+
}
|
|
19010
|
+
}
|
|
19011
|
+
function registerWorkflowCommands(program) {
|
|
19012
|
+
const workflows = program.command("workflows").description(
|
|
19013
|
+
"Legacy cloud workflows (now becoming plays). Commands still work; use `workflows transform` to migrate one to a play."
|
|
19014
|
+
).addHelpText(
|
|
19015
|
+
"after",
|
|
19016
|
+
`
|
|
19017
|
+
Workflows are a legacy surface. They still run in the cloud and these commands
|
|
19018
|
+
keep working, but new work belongs in plays. Migrate a workflow with:
|
|
19019
|
+
|
|
19020
|
+
deepline workflows transform <id> # write a reviewable .play.ts
|
|
19021
|
+
deepline workflows transform --all --publish # migrate + publish them all
|
|
19022
|
+
|
|
19023
|
+
Equivalents: list\u2192plays list \xB7 call\u2192plays run \xB7 apply\u2192plays publish \xB7
|
|
19024
|
+
lint\u2192plays check \xB7 runs\u2192runs list.
|
|
19025
|
+
`
|
|
19026
|
+
);
|
|
19027
|
+
withJsonOption(
|
|
19028
|
+
workflows.command("transform [id]").description("Compile a workflow into a reviewable V2 play (.play.ts).").option("--all", "Transform every workflow in the workspace").option("--out <dir>", "Output directory for generated plays", "./plays").option("--publish", "Publish each clean play immediately")
|
|
19029
|
+
).addHelpText(
|
|
19030
|
+
"after",
|
|
19031
|
+
`
|
|
19032
|
+
Examples:
|
|
19033
|
+
deepline workflows transform wf_123 --out ./plays
|
|
19034
|
+
deepline workflows transform --all
|
|
19035
|
+
deepline workflows transform --all --publish --json
|
|
19036
|
+
|
|
19037
|
+
Notes:
|
|
19038
|
+
HITL, run_javascript steps, and sub-workflow calls cannot run as a play yet;
|
|
19039
|
+
those workflows are reported as needing manual attention and skipped.
|
|
19040
|
+
`
|
|
19041
|
+
).action(async (id, options) => {
|
|
19042
|
+
process.exitCode = await handleTransform(id, options);
|
|
19043
|
+
});
|
|
19044
|
+
withJsonOption(
|
|
19045
|
+
workflows.command("list").description("List workspace workflows.").option("--limit <n>", "Max workflows to return")
|
|
19046
|
+
).action(handleList2);
|
|
19047
|
+
withJsonOption(
|
|
19048
|
+
workflows.command("get <id>").description(
|
|
19049
|
+
"Fetch a workflow, including its published-revision config."
|
|
19050
|
+
)
|
|
19051
|
+
).action(handleGet);
|
|
19052
|
+
withJsonOption(
|
|
19053
|
+
workflows.command("disable <id>").description("Turn a workflow off.")
|
|
19054
|
+
).action(handleDisable);
|
|
19055
|
+
withJsonOption(
|
|
19056
|
+
workflows.command("enable <id>").description("Turn a workflow back on.")
|
|
19057
|
+
).action(handleEnable);
|
|
19058
|
+
withJsonOption(
|
|
19059
|
+
workflows.command("delete <id>").description("Delete a workflow and its revisions/runs.")
|
|
19060
|
+
).action(handleDelete);
|
|
19061
|
+
withJsonOption(
|
|
19062
|
+
workflows.command("apply").description("Create or update a workflow from config.").option("--payload <json>", "Inline config JSON").option("--file <path>", "Path to a config JSON file")
|
|
19063
|
+
).action(handleApply);
|
|
19064
|
+
withJsonOption(
|
|
19065
|
+
workflows.command("lint").description("Validate a workflow config without saving.").option("--payload <json>", "Inline config JSON").option("--file <path>", "Path to a config JSON file")
|
|
19066
|
+
).action(handleLint);
|
|
19067
|
+
withJsonOption(
|
|
19068
|
+
workflows.command("schema").description("Fetch live workflow request schemas.").option(
|
|
19069
|
+
"--subject <subject>",
|
|
19070
|
+
"Schema subject (apply|call|trigger|all|\u2026)"
|
|
19071
|
+
)
|
|
19072
|
+
).action(handleSchema);
|
|
19073
|
+
withJsonOption(
|
|
19074
|
+
workflows.command("call").description("Queue a workflow run.").option("--workflow-id <id>", "Workflow id").option("--workflow-name <name>", "Workflow name").option("--payload <json>", "Run input JSON").option("--mode <mode>", "live | dry_run | smoke_test")
|
|
19075
|
+
).action(handleCall);
|
|
19076
|
+
withJsonOption(
|
|
19077
|
+
workflows.command("runs <id>").description("List a workflow\u2019s runs.").option("--limit <n>", "Max runs to return")
|
|
19078
|
+
).action(handleRuns);
|
|
19079
|
+
withJsonOption(
|
|
19080
|
+
workflows.command("run <id> <runId>").description("Fetch a single workflow run.")
|
|
19081
|
+
).action(handleRun);
|
|
19082
|
+
withJsonOption(
|
|
19083
|
+
workflows.command("tail <id> <runId>").description("Poll a workflow run until it reaches a terminal status.").option("--interval-ms <n>", "Poll interval in ms (default 2000)")
|
|
19084
|
+
).action(handleTail);
|
|
19085
|
+
withJsonOption(
|
|
19086
|
+
workflows.command("cancel <id> <runId>").description("Cancel a running workflow run.")
|
|
19087
|
+
).action(handleCancel);
|
|
19088
|
+
}
|
|
19089
|
+
|
|
16896
19090
|
// src/cli/commands/update.ts
|
|
16897
19091
|
var import_node_child_process = require("child_process");
|
|
16898
19092
|
var import_node_fs13 = require("fs");
|
|
16899
|
-
var
|
|
19093
|
+
var import_node_path17 = require("path");
|
|
16900
19094
|
function posixShellQuote(value) {
|
|
16901
19095
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
16902
19096
|
}
|
|
@@ -16915,19 +19109,19 @@ function buildSourceUpdateCommand(sourceRoot) {
|
|
|
16915
19109
|
return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
|
|
16916
19110
|
}
|
|
16917
19111
|
function findRepoBackedSdkRoot(startPath) {
|
|
16918
|
-
let current = (0,
|
|
19112
|
+
let current = (0, import_node_path17.resolve)(startPath);
|
|
16919
19113
|
while (true) {
|
|
16920
|
-
if ((0, import_node_fs13.existsSync)((0,
|
|
19114
|
+
if ((0, import_node_fs13.existsSync)((0, import_node_path17.join)(current, "sdk", "package.json")) && (0, import_node_fs13.existsSync)((0, import_node_path17.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
|
|
16921
19115
|
return current;
|
|
16922
19116
|
}
|
|
16923
|
-
const parent = (0,
|
|
19117
|
+
const parent = (0, import_node_path17.dirname)(current);
|
|
16924
19118
|
if (parent === current) return null;
|
|
16925
19119
|
current = parent;
|
|
16926
19120
|
}
|
|
16927
19121
|
}
|
|
16928
19122
|
function resolveUpdatePlan() {
|
|
16929
|
-
const entrypoint = process.argv[1] ? (0,
|
|
16930
|
-
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0,
|
|
19123
|
+
const entrypoint = process.argv[1] ? (0, import_node_path17.resolve)(process.argv[1]) : "";
|
|
19124
|
+
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path17.dirname)(entrypoint)) : null;
|
|
16931
19125
|
if (sourceRoot) {
|
|
16932
19126
|
return {
|
|
16933
19127
|
kind: "source",
|
|
@@ -17192,7 +19386,7 @@ function unknownCommandNameFromMessage(message) {
|
|
|
17192
19386
|
var import_node_child_process2 = require("child_process");
|
|
17193
19387
|
var import_node_fs14 = require("fs");
|
|
17194
19388
|
var import_node_os10 = require("os");
|
|
17195
|
-
var
|
|
19389
|
+
var import_node_path18 = require("path");
|
|
17196
19390
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
17197
19391
|
var SDK_SKILL_NAME = "deepline-plays";
|
|
17198
19392
|
var attemptedSync = false;
|
|
@@ -17212,14 +19406,14 @@ function readPluginSkillsVersion() {
|
|
|
17212
19406
|
const dir = activePluginSkillsDir();
|
|
17213
19407
|
if (!dir) return "";
|
|
17214
19408
|
try {
|
|
17215
|
-
return (0, import_node_fs14.readFileSync)((0,
|
|
19409
|
+
return (0, import_node_fs14.readFileSync)((0, import_node_path18.join)(dir, ".version"), "utf-8").trim();
|
|
17216
19410
|
} catch {
|
|
17217
19411
|
return "";
|
|
17218
19412
|
}
|
|
17219
19413
|
}
|
|
17220
19414
|
function sdkSkillsVersionPath(baseUrl) {
|
|
17221
19415
|
const home = process.env.HOME?.trim() || (0, import_node_os10.homedir)();
|
|
17222
|
-
return (0,
|
|
19416
|
+
return (0, import_node_path18.join)(
|
|
17223
19417
|
home,
|
|
17224
19418
|
".local",
|
|
17225
19419
|
"deepline",
|
|
@@ -17241,16 +19435,16 @@ function readLocalSkillsVersion(baseUrl) {
|
|
|
17241
19435
|
}
|
|
17242
19436
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
17243
19437
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
17244
|
-
(0, import_node_fs14.mkdirSync)((0,
|
|
19438
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path18.dirname)(path), { recursive: true });
|
|
17245
19439
|
(0, import_node_fs14.writeFileSync)(path, `${version}
|
|
17246
19440
|
`, "utf-8");
|
|
17247
19441
|
}
|
|
17248
19442
|
function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
17249
19443
|
const home = process.env.HOME?.trim() || (0, import_node_os10.homedir)();
|
|
17250
19444
|
const pluginSkillsDir = activePluginSkillsDir();
|
|
17251
|
-
const roots = pluginSkillsDir ? [(0,
|
|
17252
|
-
(0,
|
|
17253
|
-
(0,
|
|
19445
|
+
const roots = pluginSkillsDir ? [(0, import_node_path18.join)(pluginSkillsDir, SDK_SKILL_NAME)] : [
|
|
19446
|
+
(0, import_node_path18.join)(home, ".claude", "skills", SDK_SKILL_NAME),
|
|
19447
|
+
(0, import_node_path18.join)(home, ".agents", "skills", SDK_SKILL_NAME)
|
|
17254
19448
|
];
|
|
17255
19449
|
const staleMarkers = [
|
|
17256
19450
|
"ctx.tools.execute(key",
|
|
@@ -17261,7 +19455,7 @@ function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
|
17261
19455
|
];
|
|
17262
19456
|
const scan = (dir) => {
|
|
17263
19457
|
for (const entry of (0, import_node_fs14.readdirSync)(dir)) {
|
|
17264
|
-
const path = (0,
|
|
19458
|
+
const path = (0, import_node_path18.join)(dir, entry);
|
|
17265
19459
|
const stat4 = (0, import_node_fs14.statSync)(path);
|
|
17266
19460
|
if (stat4.isDirectory()) {
|
|
17267
19461
|
if (scan(path)) return true;
|
|
@@ -17347,7 +19541,7 @@ function resolveSkillsInstallCommands(baseUrl) {
|
|
|
17347
19541
|
return [npxInstall];
|
|
17348
19542
|
}
|
|
17349
19543
|
function runOneSkillsInstall(install) {
|
|
17350
|
-
return new Promise((
|
|
19544
|
+
return new Promise((resolve15) => {
|
|
17351
19545
|
const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
|
|
17352
19546
|
stdio: ["ignore", "ignore", "pipe"],
|
|
17353
19547
|
env: process.env
|
|
@@ -17357,7 +19551,7 @@ function runOneSkillsInstall(install) {
|
|
|
17357
19551
|
stderr += chunk.toString("utf-8");
|
|
17358
19552
|
});
|
|
17359
19553
|
child.on("error", (error) => {
|
|
17360
|
-
|
|
19554
|
+
resolve15({
|
|
17361
19555
|
ok: false,
|
|
17362
19556
|
detail: `failed to start ${install.command}: ${error.message}`,
|
|
17363
19557
|
manualCommand: install.manualCommand
|
|
@@ -17365,11 +19559,11 @@ function runOneSkillsInstall(install) {
|
|
|
17365
19559
|
});
|
|
17366
19560
|
child.on("close", (code) => {
|
|
17367
19561
|
if (code === 0) {
|
|
17368
|
-
|
|
19562
|
+
resolve15({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
17369
19563
|
return;
|
|
17370
19564
|
}
|
|
17371
19565
|
const detail = stderr.trim();
|
|
17372
|
-
|
|
19566
|
+
resolve15({
|
|
17373
19567
|
ok: false,
|
|
17374
19568
|
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
17375
19569
|
manualCommand: install.manualCommand
|
|
@@ -17457,10 +19651,10 @@ function shouldDeferSkillsSyncForCommand() {
|
|
|
17457
19651
|
return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
|
|
17458
19652
|
}
|
|
17459
19653
|
async function runPlayRunnerHealthCheck() {
|
|
17460
|
-
const dir = await (0,
|
|
17461
|
-
const file = (0,
|
|
19654
|
+
const dir = await (0, import_promises7.mkdtemp)((0, import_node_path19.join)((0, import_node_os11.tmpdir)(), "deepline-health-play-"));
|
|
19655
|
+
const file = (0, import_node_path19.join)(dir, "health-check.play.ts");
|
|
17462
19656
|
try {
|
|
17463
|
-
await (0,
|
|
19657
|
+
await (0, import_promises7.writeFile)(
|
|
17464
19658
|
file,
|
|
17465
19659
|
[
|
|
17466
19660
|
"import { definePlay } from 'deepline';",
|
|
@@ -17508,7 +19702,7 @@ async function runPlayRunnerHealthCheck() {
|
|
|
17508
19702
|
}
|
|
17509
19703
|
};
|
|
17510
19704
|
} finally {
|
|
17511
|
-
await (0,
|
|
19705
|
+
await (0, import_promises7.rm)(dir, { recursive: true, force: true });
|
|
17512
19706
|
}
|
|
17513
19707
|
}
|
|
17514
19708
|
function pickString(value, ...keys) {
|
|
@@ -17557,14 +19751,12 @@ async function runPreflightCheck() {
|
|
|
17557
19751
|
connected: false,
|
|
17558
19752
|
error: preflightErrorMessage(error)
|
|
17559
19753
|
})),
|
|
17560
|
-
http.get("/api/v2/billing/balance").catch(
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17564
|
-
|
|
17565
|
-
|
|
17566
|
-
})
|
|
17567
|
-
)
|
|
19754
|
+
http.get("/api/v2/billing/balance").catch((error) => ({
|
|
19755
|
+
balance: null,
|
|
19756
|
+
balance_display: "unavailable",
|
|
19757
|
+
balance_status: "unknown",
|
|
19758
|
+
error: preflightErrorMessage(error)
|
|
19759
|
+
}))
|
|
17568
19760
|
]) : [
|
|
17569
19761
|
{
|
|
17570
19762
|
status: "not_connected",
|
|
@@ -17700,6 +19892,7 @@ Exit codes:
|
|
|
17700
19892
|
registerAuthCommands(program);
|
|
17701
19893
|
registerToolsCommands(program);
|
|
17702
19894
|
registerPlayCommands(program);
|
|
19895
|
+
registerWorkflowCommands(program);
|
|
17703
19896
|
registerSecretsCommands(program);
|
|
17704
19897
|
registerBillingCommands(program);
|
|
17705
19898
|
registerOrgCommands(program);
|
|
@@ -17752,8 +19945,8 @@ Examples:
|
|
|
17752
19945
|
`);
|
|
17753
19946
|
return;
|
|
17754
19947
|
}
|
|
17755
|
-
const
|
|
17756
|
-
const data = await
|
|
19948
|
+
const client2 = new DeeplineClient();
|
|
19949
|
+
const data = await client2.health();
|
|
17757
19950
|
process.stdout.write(`${JSON.stringify(data, null, 2)}
|
|
17758
19951
|
`);
|
|
17759
19952
|
} catch (error) {
|