deepline 0.1.33 → 0.1.35
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 +959 -207
- package/dist/cli/index.mjs +892 -140
- package/dist/index.d.mts +127 -63
- package/dist/index.d.ts +127 -63
- package/dist/index.js +516 -45
- package/dist/index.mjs +516 -45
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +212 -1
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +129 -2
- package/dist/repo/apps/play-runner-workers/src/entry.ts +147 -64
- package/dist/repo/apps/play-runner-workers/src/workflow-retry.ts +50 -0
- package/dist/repo/sdk/src/client.ts +46 -33
- package/dist/repo/sdk/src/http.ts +44 -4
- package/dist/repo/sdk/src/index.ts +8 -5
- package/dist/repo/sdk/src/play.ts +124 -45
- package/dist/repo/sdk/src/plays/harness-stub.ts +2 -2
- package/dist/repo/sdk/src/tool-output.ts +26 -7
- package/dist/repo/sdk/src/types.ts +45 -11
- package/dist/repo/sdk/src/version.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/run-failure.ts +49 -0
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +138 -35
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -216,8 +216,8 @@ function resolveConfig(options) {
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
// src/version.ts
|
|
219
|
-
var SDK_VERSION = "0.1.
|
|
220
|
-
var SDK_API_CONTRACT = "2026-05-
|
|
219
|
+
var SDK_VERSION = "0.1.35";
|
|
220
|
+
var SDK_API_CONTRACT = "2026-05-v2-tool-result-contract";
|
|
221
221
|
|
|
222
222
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
223
223
|
var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
|
|
@@ -299,7 +299,7 @@ var HttpClient = class {
|
|
|
299
299
|
const response = await fetch(candidateUrl, {
|
|
300
300
|
method,
|
|
301
301
|
headers,
|
|
302
|
-
body: options?.formData !== void 0 ? options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
302
|
+
body: options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
303
303
|
signal: controller.signal
|
|
304
304
|
});
|
|
305
305
|
clearTimeout(timeoutId);
|
|
@@ -382,10 +382,13 @@ var HttpClient = class {
|
|
|
382
382
|
throw new AuthError();
|
|
383
383
|
}
|
|
384
384
|
if (!response.ok) {
|
|
385
|
+
const body = await response.text();
|
|
386
|
+
const parsed = parseResponseBody(body);
|
|
385
387
|
throw new DeeplineError(
|
|
386
|
-
|
|
388
|
+
apiErrorMessage(parsed, response.status),
|
|
387
389
|
response.status,
|
|
388
|
-
"API_ERROR"
|
|
390
|
+
"API_ERROR",
|
|
391
|
+
{ response: parsed }
|
|
389
392
|
);
|
|
390
393
|
}
|
|
391
394
|
if (!response.body) {
|
|
@@ -435,6 +438,26 @@ var HttpClient = class {
|
|
|
435
438
|
return this.request(path, { method: "DELETE" });
|
|
436
439
|
}
|
|
437
440
|
};
|
|
441
|
+
function parseResponseBody(body) {
|
|
442
|
+
try {
|
|
443
|
+
return JSON.parse(body);
|
|
444
|
+
} catch {
|
|
445
|
+
return body;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
function apiErrorMessage(parsed, status) {
|
|
449
|
+
const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
|
|
450
|
+
if (typeof errorValue === "string") {
|
|
451
|
+
return errorValue;
|
|
452
|
+
}
|
|
453
|
+
if (errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string") {
|
|
454
|
+
return errorValue.message;
|
|
455
|
+
}
|
|
456
|
+
if (typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string") {
|
|
457
|
+
return parsed.message;
|
|
458
|
+
}
|
|
459
|
+
return `HTTP ${status}`;
|
|
460
|
+
}
|
|
438
461
|
function parseRetryAfter(response) {
|
|
439
462
|
const header = response.headers.get("retry-after");
|
|
440
463
|
if (header) {
|
|
@@ -498,15 +521,17 @@ function decodeSseFrame(frame) {
|
|
|
498
521
|
return parsed;
|
|
499
522
|
}
|
|
500
523
|
function sleep(ms) {
|
|
501
|
-
return new Promise((
|
|
524
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
502
525
|
}
|
|
503
526
|
|
|
504
527
|
// src/client.ts
|
|
505
528
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
506
529
|
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
530
|
+
var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
|
|
531
|
+
var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-execution-result";
|
|
507
532
|
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
508
533
|
function sleep2(ms) {
|
|
509
|
-
return new Promise((
|
|
534
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
510
535
|
}
|
|
511
536
|
function isTransientCompileManifestError(error) {
|
|
512
537
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
@@ -772,13 +797,16 @@ var DeeplineClient = class {
|
|
|
772
797
|
/**
|
|
773
798
|
* Execute a tool and return the standard execution envelope.
|
|
774
799
|
*
|
|
775
|
-
* The `
|
|
776
|
-
* contains provider
|
|
800
|
+
* The `toolExecutionResult.toolOutput.raw` field contains the raw tool output.
|
|
801
|
+
* `toolExecutionResult.toolOutput.meta` contains tool/provider metadata.
|
|
777
802
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
778
|
-
* Deepline execution.
|
|
803
|
+
* Deepline execution envelope.
|
|
779
804
|
*/
|
|
780
805
|
async executeTool(toolId, input, options) {
|
|
781
|
-
const headers =
|
|
806
|
+
const headers = {
|
|
807
|
+
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
808
|
+
...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
|
|
809
|
+
};
|
|
782
810
|
return this.http.post(
|
|
783
811
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
784
812
|
{ payload: input },
|
|
@@ -1076,34 +1104,37 @@ var DeeplineClient = class {
|
|
|
1076
1104
|
* ```
|
|
1077
1105
|
*/
|
|
1078
1106
|
async stagePlayFiles(files) {
|
|
1079
|
-
const
|
|
1080
|
-
|
|
1081
|
-
"metadata",
|
|
1082
|
-
JSON.stringify({
|
|
1083
|
-
files: files.map((file, index) => ({
|
|
1084
|
-
index,
|
|
1085
|
-
logicalPath: file.logicalPath,
|
|
1086
|
-
contentHash: file.contentHash,
|
|
1087
|
-
contentType: file.contentType,
|
|
1088
|
-
bytes: file.bytes
|
|
1089
|
-
}))
|
|
1090
|
-
})
|
|
1091
|
-
);
|
|
1092
|
-
for (const [index, file] of files.entries()) {
|
|
1093
|
-
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1094
|
-
const body = bytes.buffer.slice(
|
|
1095
|
-
bytes.byteOffset,
|
|
1096
|
-
bytes.byteOffset + bytes.byteLength
|
|
1097
|
-
);
|
|
1107
|
+
const buildFormData = () => {
|
|
1108
|
+
const formData = new FormData();
|
|
1098
1109
|
formData.set(
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1110
|
+
"metadata",
|
|
1111
|
+
JSON.stringify({
|
|
1112
|
+
files: files.map((file, index) => ({
|
|
1113
|
+
index,
|
|
1114
|
+
logicalPath: file.logicalPath,
|
|
1115
|
+
contentHash: file.contentHash,
|
|
1116
|
+
contentType: file.contentType,
|
|
1117
|
+
bytes: file.bytes
|
|
1118
|
+
}))
|
|
1119
|
+
})
|
|
1102
1120
|
);
|
|
1103
|
-
|
|
1121
|
+
for (const [index, file] of files.entries()) {
|
|
1122
|
+
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1123
|
+
const body = bytes.buffer.slice(
|
|
1124
|
+
bytes.byteOffset,
|
|
1125
|
+
bytes.byteOffset + bytes.byteLength
|
|
1126
|
+
);
|
|
1127
|
+
formData.set(
|
|
1128
|
+
`file:${index}`,
|
|
1129
|
+
new Blob([body], { type: file.contentType }),
|
|
1130
|
+
file.logicalPath
|
|
1131
|
+
);
|
|
1132
|
+
}
|
|
1133
|
+
return formData;
|
|
1134
|
+
};
|
|
1104
1135
|
const response = await this.http.postFormData(
|
|
1105
1136
|
"/api/v2/plays/files/stage",
|
|
1106
|
-
|
|
1137
|
+
buildFormData
|
|
1107
1138
|
);
|
|
1108
1139
|
return response.files;
|
|
1109
1140
|
}
|
|
@@ -1892,6 +1923,103 @@ function csvStringFromRows(rows, columns) {
|
|
|
1892
1923
|
...columns?.length ? { columns } : {}
|
|
1893
1924
|
});
|
|
1894
1925
|
}
|
|
1926
|
+
function parseMaybeJsonObject(value) {
|
|
1927
|
+
if (typeof value !== "string") {
|
|
1928
|
+
return value;
|
|
1929
|
+
}
|
|
1930
|
+
const trimmed = value.trim();
|
|
1931
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
|
1932
|
+
return value;
|
|
1933
|
+
}
|
|
1934
|
+
try {
|
|
1935
|
+
return JSON.parse(trimmed);
|
|
1936
|
+
} catch {
|
|
1937
|
+
return value;
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
function flattenObjectColumns(row) {
|
|
1941
|
+
const flattened = {};
|
|
1942
|
+
for (const [key, rawValue] of Object.entries(row)) {
|
|
1943
|
+
const value = parseMaybeJsonObject(rawValue);
|
|
1944
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1945
|
+
for (const [nestedKey, nestedValue] of Object.entries(
|
|
1946
|
+
value
|
|
1947
|
+
)) {
|
|
1948
|
+
flattened[`${key}.${nestedKey}`] = nestedValue && typeof nestedValue === "object" ? JSON.stringify(nestedValue) : nestedValue;
|
|
1949
|
+
}
|
|
1950
|
+
continue;
|
|
1951
|
+
}
|
|
1952
|
+
flattened[key] = Array.isArray(value) ? JSON.stringify(value) : value;
|
|
1953
|
+
}
|
|
1954
|
+
return flattened;
|
|
1955
|
+
}
|
|
1956
|
+
function recordRows(value) {
|
|
1957
|
+
return value.filter(
|
|
1958
|
+
(row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)
|
|
1959
|
+
);
|
|
1960
|
+
}
|
|
1961
|
+
function dataExportRows(rows) {
|
|
1962
|
+
return rows.map((row) => flattenObjectColumns(row));
|
|
1963
|
+
}
|
|
1964
|
+
function dataExportColumns(rows, preferredColumns = []) {
|
|
1965
|
+
const discoveredColumns = [
|
|
1966
|
+
...new Set(rows.flatMap((row) => Object.keys(row)))
|
|
1967
|
+
];
|
|
1968
|
+
if (rows.length === 0) {
|
|
1969
|
+
return [...new Set(preferredColumns.filter(Boolean))];
|
|
1970
|
+
}
|
|
1971
|
+
const discovered = new Set(discoveredColumns);
|
|
1972
|
+
const columns = [];
|
|
1973
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1974
|
+
for (const column of preferredColumns) {
|
|
1975
|
+
if (!column) {
|
|
1976
|
+
continue;
|
|
1977
|
+
}
|
|
1978
|
+
const expandedColumns = discovered.has(column) ? [column] : discoveredColumns.filter(
|
|
1979
|
+
(discoveredColumn) => discoveredColumn.startsWith(`${column}.`)
|
|
1980
|
+
);
|
|
1981
|
+
for (const expandedColumn of expandedColumns) {
|
|
1982
|
+
if (seen.has(expandedColumn)) {
|
|
1983
|
+
continue;
|
|
1984
|
+
}
|
|
1985
|
+
seen.add(expandedColumn);
|
|
1986
|
+
columns.push(expandedColumn);
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
for (const column of discoveredColumns) {
|
|
1990
|
+
if (seen.has(column)) {
|
|
1991
|
+
continue;
|
|
1992
|
+
}
|
|
1993
|
+
seen.add(column);
|
|
1994
|
+
columns.push(column);
|
|
1995
|
+
}
|
|
1996
|
+
return columns;
|
|
1997
|
+
}
|
|
1998
|
+
function dataExportCsvString(rows, preferredColumns = []) {
|
|
1999
|
+
const flattenedRows = dataExportRows(rows);
|
|
2000
|
+
return csvStringFromRows(
|
|
2001
|
+
flattenedRows,
|
|
2002
|
+
dataExportColumns(flattenedRows, preferredColumns)
|
|
2003
|
+
);
|
|
2004
|
+
}
|
|
2005
|
+
function markdownCell(value) {
|
|
2006
|
+
if (value === null || value === void 0) {
|
|
2007
|
+
return "";
|
|
2008
|
+
}
|
|
2009
|
+
const text = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
2010
|
+
return text.replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
|
|
2011
|
+
}
|
|
2012
|
+
function markdownTableFromRows(rows, preferredColumns = []) {
|
|
2013
|
+
const flattenedRows = dataExportRows(rows);
|
|
2014
|
+
const columns = dataExportColumns(flattenedRows, preferredColumns);
|
|
2015
|
+
const header = `| ${columns.map(markdownCell).join(" | ")} |`;
|
|
2016
|
+
const separator = `| ${columns.map(() => "---").join(" | ")} |`;
|
|
2017
|
+
const body = flattenedRows.map(
|
|
2018
|
+
(row) => `| ${columns.map((column) => markdownCell(row[column])).join(" | ")} |`
|
|
2019
|
+
);
|
|
2020
|
+
return `${[header, separator, ...body].join("\n")}
|
|
2021
|
+
`;
|
|
2022
|
+
}
|
|
1895
2023
|
function printJson(value) {
|
|
1896
2024
|
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
1897
2025
|
`);
|
|
@@ -2068,7 +2196,7 @@ function buildCandidateUrls2(url) {
|
|
|
2068
2196
|
}
|
|
2069
2197
|
}
|
|
2070
2198
|
function sleep3(ms) {
|
|
2071
|
-
return new Promise((
|
|
2199
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
2072
2200
|
}
|
|
2073
2201
|
function printDeeplineLogo() {
|
|
2074
2202
|
if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
|
|
@@ -3268,10 +3396,12 @@ function writeCanonicalRowsCsv(rowsInfo, outPath) {
|
|
|
3268
3396
|
rows: rowsInfo.rows,
|
|
3269
3397
|
columns: rowsInfo.columns
|
|
3270
3398
|
});
|
|
3399
|
+
const rows = dataExportRows(sanitized.rows);
|
|
3400
|
+
const columns = dataExportColumns(rows, sanitized.columns);
|
|
3271
3401
|
const resolved = (0, import_node_path5.resolve)(outPath);
|
|
3272
3402
|
(0, import_node_fs4.writeFileSync)(
|
|
3273
3403
|
resolved,
|
|
3274
|
-
csvStringFromRows(
|
|
3404
|
+
csvStringFromRows(rows, columns),
|
|
3275
3405
|
"utf-8"
|
|
3276
3406
|
);
|
|
3277
3407
|
return resolved;
|
|
@@ -3392,6 +3522,14 @@ Examples:
|
|
|
3392
3522
|
}
|
|
3393
3523
|
|
|
3394
3524
|
// src/cli/commands/db.ts
|
|
3525
|
+
var import_node_fs5 = require("fs");
|
|
3526
|
+
var import_node_path6 = require("path");
|
|
3527
|
+
var CUSTOMER_DB_QUERY_FORMATS = /* @__PURE__ */ new Set([
|
|
3528
|
+
"table",
|
|
3529
|
+
"json",
|
|
3530
|
+
"csv",
|
|
3531
|
+
"markdown"
|
|
3532
|
+
]);
|
|
3395
3533
|
function parsePositiveInteger(value, flagName) {
|
|
3396
3534
|
const parsed = Number.parseInt(value, 10);
|
|
3397
3535
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
@@ -3405,10 +3543,8 @@ function formatCell(value) {
|
|
|
3405
3543
|
return text.length > 80 ? `${text.slice(0, 77)}...` : text;
|
|
3406
3544
|
}
|
|
3407
3545
|
function tableLines(result) {
|
|
3408
|
-
const rows = result
|
|
3409
|
-
|
|
3410
|
-
);
|
|
3411
|
-
const responseColumns = result.columns.length > 0 ? result.columns.map((column) => column.name) : [...new Set(rows.flatMap((row) => Object.keys(row)))];
|
|
3546
|
+
const rows = dataExportRows(customerDbRows(result));
|
|
3547
|
+
const responseColumns = dataExportColumns(rows, customerDbColumnNames(result));
|
|
3412
3548
|
const businessColumns = responseColumns.filter((column) => !column.startsWith("_"));
|
|
3413
3549
|
const columns = businessColumns.length > 0 ? businessColumns : responseColumns;
|
|
3414
3550
|
const hiddenColumns = responseColumns.filter((column) => !columns.includes(column));
|
|
@@ -3442,22 +3578,146 @@ function tableLines(result) {
|
|
|
3442
3578
|
}
|
|
3443
3579
|
return lines;
|
|
3444
3580
|
}
|
|
3581
|
+
function customerDbRows(result) {
|
|
3582
|
+
return recordRows(result.rows);
|
|
3583
|
+
}
|
|
3584
|
+
function customerDbColumnNames(result) {
|
|
3585
|
+
return result.columns.map((column) => column.name).filter(Boolean);
|
|
3586
|
+
}
|
|
3587
|
+
function writeCustomerDbCsv(result, outPath) {
|
|
3588
|
+
const resolved = (0, import_node_path6.resolve)(outPath);
|
|
3589
|
+
(0, import_node_fs5.writeFileSync)(
|
|
3590
|
+
resolved,
|
|
3591
|
+
dataExportCsvString(customerDbRows(result), customerDbColumnNames(result)),
|
|
3592
|
+
"utf-8"
|
|
3593
|
+
);
|
|
3594
|
+
return resolved;
|
|
3595
|
+
}
|
|
3596
|
+
function dbQueryExportEnvelope(input) {
|
|
3597
|
+
const destination = input.outPath ?? "stdout";
|
|
3598
|
+
return {
|
|
3599
|
+
command: input.result.command,
|
|
3600
|
+
format: input.format,
|
|
3601
|
+
row_count: input.result.row_count,
|
|
3602
|
+
row_count_returned: input.result.row_count_returned,
|
|
3603
|
+
truncated: input.result.truncated,
|
|
3604
|
+
...input.outPath ? { file: input.outPath, local: { file: input.outPath } } : {},
|
|
3605
|
+
next: { toolEquivalent: input.toolCommand },
|
|
3606
|
+
render: {
|
|
3607
|
+
sections: [
|
|
3608
|
+
{
|
|
3609
|
+
title: "customer db export",
|
|
3610
|
+
lines: [
|
|
3611
|
+
`Rendered ${input.result.row_count_returned} row(s) as ${input.format} to ${destination}`
|
|
3612
|
+
]
|
|
3613
|
+
}
|
|
3614
|
+
],
|
|
3615
|
+
actions: [{ label: "Tool equivalent", command: input.toolCommand }]
|
|
3616
|
+
}
|
|
3617
|
+
};
|
|
3618
|
+
}
|
|
3445
3619
|
async function handleDbQuery(args) {
|
|
3446
3620
|
const sqlIndex = args.indexOf("--sql");
|
|
3447
3621
|
const sql = sqlIndex >= 0 ? args[sqlIndex + 1]?.trim() : "";
|
|
3448
3622
|
if (!sql) {
|
|
3449
|
-
console.error(
|
|
3623
|
+
console.error(
|
|
3624
|
+
'Usage: deepline db query --sql "select * from table limit 20" [--max-rows N] [--json]'
|
|
3625
|
+
);
|
|
3450
3626
|
return 1;
|
|
3451
3627
|
}
|
|
3452
3628
|
const maxRowsIndex = args.indexOf("--max-rows");
|
|
3453
3629
|
const maxRows = maxRowsIndex >= 0 && args[maxRowsIndex + 1] ? parsePositiveInteger(args[maxRowsIndex + 1], "--max-rows") : void 0;
|
|
3630
|
+
const formatIndex = args.indexOf("--format");
|
|
3631
|
+
const format = formatIndex >= 0 ? args[formatIndex + 1]?.trim().toLowerCase() : "";
|
|
3632
|
+
if (format && !CUSTOMER_DB_QUERY_FORMATS.has(format)) {
|
|
3633
|
+
console.error(
|
|
3634
|
+
'Usage: deepline db query --sql "select * from table limit 20" [--format table|json|csv|markdown] [--out path]'
|
|
3635
|
+
);
|
|
3636
|
+
return 1;
|
|
3637
|
+
}
|
|
3638
|
+
const outIndex = args.indexOf("--out");
|
|
3639
|
+
const outPath = outIndex >= 0 ? args[outIndex + 1]?.trim() : "";
|
|
3640
|
+
if (outIndex >= 0 && !outPath) {
|
|
3641
|
+
console.error("--out requires a path.");
|
|
3642
|
+
return 1;
|
|
3643
|
+
}
|
|
3454
3644
|
const jsonOutput = argsWantJson(args);
|
|
3645
|
+
const explicitJsonOutput = args.includes("--json");
|
|
3455
3646
|
const client = new DeeplineClient();
|
|
3456
3647
|
const result = await client.queryCustomerDb({ sql, maxRows });
|
|
3457
3648
|
const toolCommand = `deepline tools execute query_customer_db --payload ${JSON.stringify({
|
|
3458
3649
|
sql,
|
|
3459
3650
|
...maxRows ? { max_rows: maxRows } : {}
|
|
3460
3651
|
})} --json`;
|
|
3652
|
+
if (format === "csv") {
|
|
3653
|
+
if (outPath) {
|
|
3654
|
+
const exportedPath = writeCustomerDbCsv(result, outPath);
|
|
3655
|
+
printCommandEnvelope(
|
|
3656
|
+
dbQueryExportEnvelope({
|
|
3657
|
+
result,
|
|
3658
|
+
format,
|
|
3659
|
+
outPath: exportedPath,
|
|
3660
|
+
toolCommand
|
|
3661
|
+
}),
|
|
3662
|
+
{
|
|
3663
|
+
json: jsonOutput,
|
|
3664
|
+
text: `Exported ${result.row_count_returned} row(s) to ${exportedPath}
|
|
3665
|
+
`
|
|
3666
|
+
}
|
|
3667
|
+
);
|
|
3668
|
+
return 0;
|
|
3669
|
+
}
|
|
3670
|
+
printCommandEnvelope(
|
|
3671
|
+
dbQueryExportEnvelope({
|
|
3672
|
+
result,
|
|
3673
|
+
format,
|
|
3674
|
+
outPath: null,
|
|
3675
|
+
toolCommand
|
|
3676
|
+
}),
|
|
3677
|
+
{
|
|
3678
|
+
json: explicitJsonOutput,
|
|
3679
|
+
text: dataExportCsvString(customerDbRows(result), customerDbColumnNames(result))
|
|
3680
|
+
}
|
|
3681
|
+
);
|
|
3682
|
+
return 0;
|
|
3683
|
+
}
|
|
3684
|
+
if (format === "markdown") {
|
|
3685
|
+
const content = markdownTableFromRows(
|
|
3686
|
+
customerDbRows(result),
|
|
3687
|
+
customerDbColumnNames(result)
|
|
3688
|
+
);
|
|
3689
|
+
if (outPath) {
|
|
3690
|
+
const exportedPath = (0, import_node_path6.resolve)(outPath);
|
|
3691
|
+
(0, import_node_fs5.writeFileSync)(exportedPath, content, "utf-8");
|
|
3692
|
+
printCommandEnvelope(
|
|
3693
|
+
dbQueryExportEnvelope({
|
|
3694
|
+
result,
|
|
3695
|
+
format,
|
|
3696
|
+
outPath: exportedPath,
|
|
3697
|
+
toolCommand
|
|
3698
|
+
}),
|
|
3699
|
+
{
|
|
3700
|
+
json: jsonOutput,
|
|
3701
|
+
text: `Exported ${result.row_count_returned} row(s) to ${exportedPath}
|
|
3702
|
+
`
|
|
3703
|
+
}
|
|
3704
|
+
);
|
|
3705
|
+
return 0;
|
|
3706
|
+
}
|
|
3707
|
+
printCommandEnvelope(
|
|
3708
|
+
dbQueryExportEnvelope({
|
|
3709
|
+
result,
|
|
3710
|
+
format,
|
|
3711
|
+
outPath: null,
|
|
3712
|
+
toolCommand
|
|
3713
|
+
}),
|
|
3714
|
+
{
|
|
3715
|
+
json: explicitJsonOutput,
|
|
3716
|
+
text: content
|
|
3717
|
+
}
|
|
3718
|
+
);
|
|
3719
|
+
return 0;
|
|
3720
|
+
}
|
|
3461
3721
|
printCommandEnvelope({
|
|
3462
3722
|
...result,
|
|
3463
3723
|
next: { toolEquivalent: toolCommand },
|
|
@@ -3465,7 +3725,7 @@ async function handleDbQuery(args) {
|
|
|
3465
3725
|
sections: [{ title: "customer db query", lines: tableLines(result) }],
|
|
3466
3726
|
actions: [{ label: "Tool equivalent", command: toolCommand }]
|
|
3467
3727
|
}
|
|
3468
|
-
}, { json: jsonOutput });
|
|
3728
|
+
}, { json: jsonOutput || format === "json" });
|
|
3469
3729
|
return 0;
|
|
3470
3730
|
}
|
|
3471
3731
|
function registerDbCommands(program) {
|
|
@@ -3475,11 +3735,14 @@ function registerDbCommands(program) {
|
|
|
3475
3735
|
Notes:
|
|
3476
3736
|
Runs SQL against the active workspace customer database through Deepline APIs.
|
|
3477
3737
|
Results are bounded by the server and --max-rows. Use --json for stable output.
|
|
3738
|
+
Use --format csv or --format markdown for agent-readable exports and display tables.
|
|
3478
3739
|
|
|
3479
3740
|
Examples:
|
|
3480
3741
|
deepline db query --sql "select * from companies limit 20"
|
|
3481
3742
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
3482
3743
|
deepline db query --sql "select * from contacts" --max-rows 100 --json
|
|
3744
|
+
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
3745
|
+
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
3483
3746
|
`
|
|
3484
3747
|
);
|
|
3485
3748
|
db.command("query").alias("psql").description("Run SQL against the tenant customer database.").addHelpText(
|
|
@@ -3488,17 +3751,23 @@ Examples:
|
|
|
3488
3751
|
Notes:
|
|
3489
3752
|
Requires --sql. Output is a compact table in a terminal and raw JSON with
|
|
3490
3753
|
--json or when stdout is piped. The active auth workspace determines scope.
|
|
3754
|
+
--format csv and --format markdown are explicit data/display formats and can
|
|
3755
|
+
be written directly with --out.
|
|
3491
3756
|
|
|
3492
3757
|
Examples:
|
|
3493
3758
|
deepline db query --sql "select * from companies limit 20"
|
|
3494
3759
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
3495
3760
|
deepline db psql --sql "select count(*) from contacts" --json
|
|
3761
|
+
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
3762
|
+
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
3496
3763
|
`
|
|
3497
|
-
).requiredOption("--sql <sql>", "SQL statement").option("--max-rows <n>", "Maximum returned rows").option("--json", "Emit raw JSON response. Also automatic when stdout is piped").action(async (options) => {
|
|
3764
|
+
).requiredOption("--sql <sql>", "SQL statement").option("--max-rows <n>", "Maximum returned rows").option("--format <format>", "Output format: table, json, csv, or markdown").option("--out <path>", "Write csv or markdown output to a file").option("--json", "Emit raw JSON response. Also automatic when stdout is piped").action(async (options) => {
|
|
3498
3765
|
process.exitCode = await handleDbQuery([
|
|
3499
3766
|
"--sql",
|
|
3500
3767
|
options.sql,
|
|
3501
3768
|
...options.maxRows ? ["--max-rows", options.maxRows] : [],
|
|
3769
|
+
...options.format ? ["--format", options.format] : [],
|
|
3770
|
+
...options.out ? ["--out", options.out] : [],
|
|
3502
3771
|
...options.json ? ["--json"] : []
|
|
3503
3772
|
]);
|
|
3504
3773
|
});
|
|
@@ -3674,21 +3943,21 @@ Examples:
|
|
|
3674
3943
|
|
|
3675
3944
|
// src/cli/commands/play.ts
|
|
3676
3945
|
var import_node_crypto3 = require("crypto");
|
|
3677
|
-
var
|
|
3678
|
-
var
|
|
3946
|
+
var import_node_fs8 = require("fs");
|
|
3947
|
+
var import_node_path10 = require("path");
|
|
3679
3948
|
|
|
3680
3949
|
// src/plays/bundle-play-file.ts
|
|
3681
3950
|
var import_node_os5 = require("os");
|
|
3682
|
-
var
|
|
3951
|
+
var import_node_path9 = require("path");
|
|
3683
3952
|
var import_node_url = require("url");
|
|
3684
|
-
var
|
|
3953
|
+
var import_node_fs7 = require("fs");
|
|
3685
3954
|
|
|
3686
3955
|
// ../shared_libs/plays/bundling/index.ts
|
|
3687
3956
|
var import_node_crypto = require("crypto");
|
|
3688
|
-
var
|
|
3957
|
+
var import_node_fs6 = require("fs");
|
|
3689
3958
|
var import_promises3 = require("fs/promises");
|
|
3690
3959
|
var import_node_os4 = require("os");
|
|
3691
|
-
var
|
|
3960
|
+
var import_node_path7 = require("path");
|
|
3692
3961
|
var import_node_module = require("module");
|
|
3693
3962
|
var import_esbuild = require("esbuild");
|
|
3694
3963
|
|
|
@@ -3747,7 +4016,7 @@ function buildPlayContractCompatibility(input) {
|
|
|
3747
4016
|
var PLAY_BUNDLE_CACHE_VERSION = 24;
|
|
3748
4017
|
var MAX_PLAY_BUNDLE_BYTES = 30 * 1024 * 1024;
|
|
3749
4018
|
var MAX_ESM_WORKERS_BUNDLE_BYTES = 115e4;
|
|
3750
|
-
var PLAY_ARTIFACT_CACHE_DIR = (0,
|
|
4019
|
+
var PLAY_ARTIFACT_CACHE_DIR = (0, import_node_path7.join)(
|
|
3751
4020
|
(0, import_node_os4.tmpdir)(),
|
|
3752
4021
|
`deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION}`
|
|
3753
4022
|
);
|
|
@@ -3780,13 +4049,13 @@ async function normalizeLocalPath(filePath) {
|
|
|
3780
4049
|
try {
|
|
3781
4050
|
return await (0, import_promises3.realpath)(filePath);
|
|
3782
4051
|
} catch {
|
|
3783
|
-
return (0,
|
|
4052
|
+
return (0, import_node_path7.resolve)(filePath);
|
|
3784
4053
|
}
|
|
3785
4054
|
}
|
|
3786
4055
|
function createPlayWorkspace(entryFile) {
|
|
3787
4056
|
return {
|
|
3788
4057
|
entryFile,
|
|
3789
|
-
rootDir: (0,
|
|
4058
|
+
rootDir: (0, import_node_path7.dirname)(entryFile)
|
|
3790
4059
|
};
|
|
3791
4060
|
}
|
|
3792
4061
|
function isPathInsideDirectory(filePath, directory) {
|
|
@@ -3939,7 +4208,7 @@ function extractDefinedPlayName(sourceCode) {
|
|
|
3939
4208
|
}
|
|
3940
4209
|
function readPackageVersionFromPackageJson(packageJsonPath, packageName) {
|
|
3941
4210
|
try {
|
|
3942
|
-
const packageJson = JSON.parse((0,
|
|
4211
|
+
const packageJson = JSON.parse((0, import_node_fs6.readFileSync)(packageJsonPath, "utf-8"));
|
|
3943
4212
|
if (packageJson.name === packageName && typeof packageJson.version === "string") {
|
|
3944
4213
|
return packageJson.version;
|
|
3945
4214
|
}
|
|
@@ -3949,18 +4218,18 @@ function readPackageVersionFromPackageJson(packageJsonPath, packageName) {
|
|
|
3949
4218
|
return null;
|
|
3950
4219
|
}
|
|
3951
4220
|
function findPackageJsonPathFrom(startDir, packageName) {
|
|
3952
|
-
let current = (0,
|
|
4221
|
+
let current = (0, import_node_path7.resolve)(startDir);
|
|
3953
4222
|
while (true) {
|
|
3954
|
-
const packageJsonPath = (0,
|
|
4223
|
+
const packageJsonPath = (0, import_node_path7.join)(
|
|
3955
4224
|
current,
|
|
3956
4225
|
"node_modules",
|
|
3957
4226
|
packageName,
|
|
3958
4227
|
"package.json"
|
|
3959
4228
|
);
|
|
3960
|
-
if ((0,
|
|
4229
|
+
if ((0, import_node_fs6.existsSync)(packageJsonPath)) {
|
|
3961
4230
|
return packageJsonPath;
|
|
3962
4231
|
}
|
|
3963
|
-
const parent = (0,
|
|
4232
|
+
const parent = (0, import_node_path7.dirname)(current);
|
|
3964
4233
|
if (parent === current) {
|
|
3965
4234
|
return null;
|
|
3966
4235
|
}
|
|
@@ -3969,29 +4238,29 @@ function findPackageJsonPathFrom(startDir, packageName) {
|
|
|
3969
4238
|
}
|
|
3970
4239
|
function findPackageJsonPath(packageName, fromFile, adapter) {
|
|
3971
4240
|
const startDirs = [
|
|
3972
|
-
(0,
|
|
4241
|
+
(0, import_node_path7.dirname)(fromFile),
|
|
3973
4242
|
adapter.projectRoot,
|
|
3974
|
-
(0,
|
|
4243
|
+
(0, import_node_path7.dirname)(adapter.sdkPackageJson),
|
|
3975
4244
|
process.cwd()
|
|
3976
4245
|
];
|
|
3977
4246
|
const seen = /* @__PURE__ */ new Set();
|
|
3978
4247
|
for (const startDir of startDirs) {
|
|
3979
|
-
const normalized = (0,
|
|
4248
|
+
const normalized = (0, import_node_path7.resolve)(startDir);
|
|
3980
4249
|
if (seen.has(normalized)) continue;
|
|
3981
4250
|
seen.add(normalized);
|
|
3982
4251
|
const packageJsonPath = findPackageJsonPathFrom(normalized, packageName);
|
|
3983
4252
|
if (packageJsonPath) return packageJsonPath;
|
|
3984
4253
|
}
|
|
3985
|
-
const adapterNodeModulesPackageJson = (0,
|
|
4254
|
+
const adapterNodeModulesPackageJson = (0, import_node_path7.join)(
|
|
3986
4255
|
adapter.nodeModulesDir,
|
|
3987
4256
|
packageName,
|
|
3988
4257
|
"package.json"
|
|
3989
4258
|
);
|
|
3990
|
-
return (0,
|
|
4259
|
+
return (0, import_node_fs6.existsSync)(adapterNodeModulesPackageJson) ? adapterNodeModulesPackageJson : null;
|
|
3991
4260
|
}
|
|
3992
4261
|
function localSdkAliasPlugin(adapter, options) {
|
|
3993
4262
|
const entryFile = options?.workersRuntime ? adapter.sdkWorkersEntryFile : adapter.sdkEntryFile;
|
|
3994
|
-
if (!(0,
|
|
4263
|
+
if (!(0, import_node_fs6.existsSync)(entryFile)) {
|
|
3995
4264
|
return null;
|
|
3996
4265
|
}
|
|
3997
4266
|
return {
|
|
@@ -4031,7 +4300,7 @@ function workersNamedPlayEntryAliasPlugin(playFilePath, exportName) {
|
|
|
4031
4300
|
contents: `export { ${exportName} as default } from ${JSON.stringify(playFilePath)};
|
|
4032
4301
|
`,
|
|
4033
4302
|
loader: "ts",
|
|
4034
|
-
resolveDir: (0,
|
|
4303
|
+
resolveDir: (0, import_node_path7.dirname)(playFilePath)
|
|
4035
4304
|
})
|
|
4036
4305
|
);
|
|
4037
4306
|
}
|
|
@@ -4195,7 +4464,7 @@ function importedPlayProxyPlugin(importedPlayDependencies) {
|
|
|
4195
4464
|
return {
|
|
4196
4465
|
contents: buildImportedPlayProxyModule(dependency.playName),
|
|
4197
4466
|
loader: "ts",
|
|
4198
|
-
resolveDir: (0,
|
|
4467
|
+
resolveDir: (0, import_node_path7.dirname)(args.path)
|
|
4199
4468
|
};
|
|
4200
4469
|
});
|
|
4201
4470
|
}
|
|
@@ -4213,12 +4482,12 @@ async function resolveLocalImport(fromFile, specifier) {
|
|
|
4213
4482
|
if (specifier.startsWith("file:")) {
|
|
4214
4483
|
return normalizeLocalPath(new URL(specifier).pathname);
|
|
4215
4484
|
}
|
|
4216
|
-
const base = (0,
|
|
4485
|
+
const base = (0, import_node_path7.isAbsolute)(specifier) ? (0, import_node_path7.resolve)(specifier) : (0, import_node_path7.resolve)((0, import_node_path7.dirname)(fromFile), specifier);
|
|
4217
4486
|
const candidates = [base];
|
|
4218
|
-
const explicitExtension = (0,
|
|
4487
|
+
const explicitExtension = (0, import_node_path7.extname)(base).toLowerCase();
|
|
4219
4488
|
if (!explicitExtension) {
|
|
4220
4489
|
candidates.push(...SOURCE_EXTENSIONS.map((extension) => `${base}${extension}`));
|
|
4221
|
-
candidates.push(...SOURCE_EXTENSIONS.map((extension) => (0,
|
|
4490
|
+
candidates.push(...SOURCE_EXTENSIONS.map((extension) => (0, import_node_path7.join)(base, `index${extension}`)));
|
|
4222
4491
|
} else if ([".js", ".jsx", ".mjs", ".cjs"].includes(explicitExtension)) {
|
|
4223
4492
|
const stem = base.slice(0, -explicitExtension.length);
|
|
4224
4493
|
candidates.push(...SOURCE_EXTENSIONS.map((extension) => `${stem}${extension}`));
|
|
@@ -4232,9 +4501,9 @@ async function resolveLocalImport(fromFile, specifier) {
|
|
|
4232
4501
|
}
|
|
4233
4502
|
function resolvePackageImport(specifier, fromFile, adapter) {
|
|
4234
4503
|
const packageName = getPackageName(specifier);
|
|
4235
|
-
if (packageName === "deepline" && (0,
|
|
4504
|
+
if (packageName === "deepline" && (0, import_node_fs6.existsSync)(adapter.sdkPackageJson)) {
|
|
4236
4505
|
const packageJson = JSON.parse(
|
|
4237
|
-
(0,
|
|
4506
|
+
(0, import_node_fs6.readFileSync)(adapter.sdkPackageJson, "utf-8")
|
|
4238
4507
|
);
|
|
4239
4508
|
return {
|
|
4240
4509
|
name: "deepline",
|
|
@@ -4266,7 +4535,7 @@ async function analyzeSourceGraph(entryFile, adapter) {
|
|
|
4266
4535
|
visited.add(absolutePath);
|
|
4267
4536
|
const sourceCode2 = await (0, import_promises3.readFile)(absolutePath, "utf-8");
|
|
4268
4537
|
localFiles.set(absolutePath, sourceCode2);
|
|
4269
|
-
if ((0,
|
|
4538
|
+
if ((0, import_node_path7.extname)(absolutePath).toLowerCase() === ".json") {
|
|
4270
4539
|
return;
|
|
4271
4540
|
}
|
|
4272
4541
|
const handleSpecifier = async (specifier, line, column, kind) => {
|
|
@@ -4370,13 +4639,13 @@ async function computeWorkersHarnessFingerprintWithAdapter(adapter) {
|
|
|
4370
4639
|
const tsFiles = entries.filter((e) => e.isFile() && /\.[cm]?ts$/.test(e.name)).map((e) => e.name).sort();
|
|
4371
4640
|
const parts = [];
|
|
4372
4641
|
for (const name of tsFiles) {
|
|
4373
|
-
const contents = await (0, import_promises3.readFile)((0,
|
|
4642
|
+
const contents = await (0, import_promises3.readFile)((0, import_node_path7.join)(adapter.workersHarnessFilesDir, name), "utf-8");
|
|
4374
4643
|
parts.push({ name, hash: sha256(contents) });
|
|
4375
4644
|
}
|
|
4376
4645
|
return sha256(JSON.stringify(parts));
|
|
4377
4646
|
}
|
|
4378
4647
|
function artifactCachePath(graphHash, artifactKind, adapter) {
|
|
4379
|
-
return (0,
|
|
4648
|
+
return (0, import_node_path7.join)(
|
|
4380
4649
|
adapter.cacheDir ?? PLAY_ARTIFACT_CACHE_DIR,
|
|
4381
4650
|
`${graphHash}.${artifactKind}.json`
|
|
4382
4651
|
);
|
|
@@ -4411,7 +4680,7 @@ function normalizeSourceMapForRuntime(sourceMapText) {
|
|
|
4411
4680
|
if (sourcePath.startsWith("data:") || sourcePath.startsWith("node:") || sourcePath.startsWith("/") || /^[a-zA-Z]+:\/\//.test(sourcePath)) {
|
|
4412
4681
|
return sourcePath;
|
|
4413
4682
|
}
|
|
4414
|
-
return (0,
|
|
4683
|
+
return (0, import_node_path7.resolve)(process.cwd(), sourcePath);
|
|
4415
4684
|
});
|
|
4416
4685
|
parsed.sourceRoot = void 0;
|
|
4417
4686
|
return JSON.stringify(parsed);
|
|
@@ -4443,8 +4712,8 @@ async function runEsbuildForCjsNode(entryFile, importedPlayDependencies, adapter
|
|
|
4443
4712
|
...namedExportShim ? {
|
|
4444
4713
|
stdin: {
|
|
4445
4714
|
contents: namedExportShim,
|
|
4446
|
-
resolveDir: (0,
|
|
4447
|
-
sourcefile: `${(0,
|
|
4715
|
+
resolveDir: (0, import_node_path7.dirname)(entryFile),
|
|
4716
|
+
sourcefile: `${(0, import_node_path7.basename)(entryFile)}.${exportName}.entry.ts`,
|
|
4448
4717
|
loader: "ts"
|
|
4449
4718
|
}
|
|
4450
4719
|
} : { entryPoints: [entryFile] },
|
|
@@ -4620,10 +4889,10 @@ workers-harness:${harnessFingerprint}`
|
|
|
4620
4889
|
}
|
|
4621
4890
|
const { bundledCode, sourceMapText, outputExtension } = buildOutcome;
|
|
4622
4891
|
const normalizedSourceMap = normalizeSourceMapForRuntime(sourceMapText);
|
|
4623
|
-
const virtualBaseName = exportName === "default" ? (0,
|
|
4892
|
+
const virtualBaseName = exportName === "default" ? (0, import_node_path7.basename)(absolutePath).replace(/\.[^.]+$/, "") : `${(0, import_node_path7.basename)(absolutePath).replace(/\.[^.]+$/, "")}.${exportName}`;
|
|
4624
4893
|
const virtualFilename = `/virtual/deepline-plays/${analysis.graphHash}/${virtualBaseName}.${outputExtension}`;
|
|
4625
4894
|
const executableCode = `${bundledCode}
|
|
4626
|
-
//# sourceMappingURL=${(0,
|
|
4895
|
+
//# sourceMappingURL=${(0, import_node_path7.basename)(virtualFilename)}.map
|
|
4627
4896
|
`;
|
|
4628
4897
|
const bundleSizeError = getBundleSizeError(
|
|
4629
4898
|
absolutePath,
|
|
@@ -4733,13 +5002,13 @@ function resolveExecutionProfile(override) {
|
|
|
4733
5002
|
// src/plays/local-file-discovery.ts
|
|
4734
5003
|
var import_node_crypto2 = require("crypto");
|
|
4735
5004
|
var import_promises4 = require("fs/promises");
|
|
4736
|
-
var
|
|
5005
|
+
var import_node_path8 = require("path");
|
|
4737
5006
|
var SOURCE_EXTENSIONS2 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
|
|
4738
5007
|
function sha2562(buffer) {
|
|
4739
5008
|
return (0, import_node_crypto2.createHash)("sha256").update(buffer).digest("hex");
|
|
4740
5009
|
}
|
|
4741
5010
|
function contentTypeForFile(filePath) {
|
|
4742
|
-
const extension = (0,
|
|
5011
|
+
const extension = (0, import_node_path8.extname)(filePath).toLowerCase();
|
|
4743
5012
|
if (extension === ".csv") return "text/csv";
|
|
4744
5013
|
if (extension === ".json") return "application/json";
|
|
4745
5014
|
if (extension === ".txt") return "text/plain";
|
|
@@ -4930,16 +5199,16 @@ async function fileExists2(filePath) {
|
|
|
4930
5199
|
}
|
|
4931
5200
|
}
|
|
4932
5201
|
function isPathInsideDirectory2(filePath, directory) {
|
|
4933
|
-
const relativePath = (0,
|
|
4934
|
-
return relativePath === "" || !relativePath.startsWith("..") && !(0,
|
|
5202
|
+
const relativePath = (0, import_node_path8.relative)(directory, filePath);
|
|
5203
|
+
return relativePath === "" || !relativePath.startsWith("..") && !(0, import_node_path8.isAbsolute)(relativePath);
|
|
4935
5204
|
}
|
|
4936
5205
|
async function resolveLocalImport2(fromFile, specifier) {
|
|
4937
|
-
const base = (0,
|
|
5206
|
+
const base = (0, import_node_path8.isAbsolute)(specifier) ? (0, import_node_path8.resolve)(specifier) : (0, import_node_path8.resolve)((0, import_node_path8.dirname)(fromFile), specifier);
|
|
4938
5207
|
const candidates = [base];
|
|
4939
|
-
const explicitExtension = (0,
|
|
5208
|
+
const explicitExtension = (0, import_node_path8.extname)(base).toLowerCase();
|
|
4940
5209
|
if (!explicitExtension) {
|
|
4941
5210
|
candidates.push(...SOURCE_EXTENSIONS2.map((extension) => `${base}${extension}`));
|
|
4942
|
-
candidates.push(...SOURCE_EXTENSIONS2.map((extension) => (0,
|
|
5211
|
+
candidates.push(...SOURCE_EXTENSIONS2.map((extension) => (0, import_node_path8.join)(base, `index${extension}`)));
|
|
4943
5212
|
} else if ([".js", ".jsx", ".mjs", ".cjs"].includes(explicitExtension)) {
|
|
4944
5213
|
const stem = base.slice(0, -explicitExtension.length);
|
|
4945
5214
|
candidates.push(...SOURCE_EXTENSIONS2.map((extension) => `${stem}${extension}`));
|
|
@@ -4952,13 +5221,13 @@ async function resolveLocalImport2(fromFile, specifier) {
|
|
|
4952
5221
|
throw new Error(`Could not resolve local import "${specifier}" from ${fromFile}`);
|
|
4953
5222
|
}
|
|
4954
5223
|
async function discoverPackagedLocalFiles(entryFile) {
|
|
4955
|
-
const absoluteEntryFile = (0,
|
|
4956
|
-
const packagingRoot = (0,
|
|
5224
|
+
const absoluteEntryFile = (0, import_node_path8.resolve)(entryFile);
|
|
5225
|
+
const packagingRoot = (0, import_node_path8.dirname)(absoluteEntryFile);
|
|
4957
5226
|
const files = /* @__PURE__ */ new Map();
|
|
4958
5227
|
const unresolved = [];
|
|
4959
5228
|
const visitedFiles = /* @__PURE__ */ new Set();
|
|
4960
5229
|
const visitSourceFile = async (filePath) => {
|
|
4961
|
-
const absolutePath = (0,
|
|
5230
|
+
const absolutePath = (0, import_node_path8.resolve)(filePath);
|
|
4962
5231
|
if (visitedFiles.has(absolutePath)) {
|
|
4963
5232
|
return;
|
|
4964
5233
|
}
|
|
@@ -4990,8 +5259,8 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
4990
5259
|
message: "Could not resolve this ctx.csv(...) path at submit time. Use a string literal, a top-level const string, or pass a runtime input like input.file."
|
|
4991
5260
|
});
|
|
4992
5261
|
} else {
|
|
4993
|
-
const absoluteCsvPath = (0,
|
|
4994
|
-
if ((0,
|
|
5262
|
+
const absoluteCsvPath = (0, import_node_path8.resolve)((0, import_node_path8.dirname)(absolutePath), resolvedPath);
|
|
5263
|
+
if ((0, import_node_path8.isAbsolute)(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
|
|
4995
5264
|
unresolved.push({
|
|
4996
5265
|
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
4997
5266
|
message: "ctx.csv(...) packaged file paths must be relative paths inside the play directory. Pass external files at runtime with input.file instead."
|
|
@@ -5030,24 +5299,24 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
5030
5299
|
// src/plays/bundle-play-file.ts
|
|
5031
5300
|
var import_meta = {};
|
|
5032
5301
|
var PLAY_BUNDLE_CACHE_VERSION2 = 30;
|
|
5033
|
-
var MODULE_DIR = (0,
|
|
5034
|
-
var SDK_PACKAGE_ROOT = (0,
|
|
5035
|
-
var SOURCE_REPO_ROOT = (0,
|
|
5036
|
-
var HAS_SOURCE_BUNDLING_SOURCES = (0,
|
|
5037
|
-
(0,
|
|
5302
|
+
var MODULE_DIR = (0, import_node_path9.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
5303
|
+
var SDK_PACKAGE_ROOT = (0, import_node_path9.resolve)(MODULE_DIR, "..", "..");
|
|
5304
|
+
var SOURCE_REPO_ROOT = (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "..");
|
|
5305
|
+
var HAS_SOURCE_BUNDLING_SOURCES = (0, import_node_fs7.existsSync)(
|
|
5306
|
+
(0, import_node_path9.resolve)(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
5038
5307
|
);
|
|
5039
|
-
var PACKAGED_REPO_ROOT = (0,
|
|
5040
|
-
var HAS_PACKAGED_BUNDLING_SOURCES = (0,
|
|
5041
|
-
(0,
|
|
5308
|
+
var PACKAGED_REPO_ROOT = (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "dist", "repo");
|
|
5309
|
+
var HAS_PACKAGED_BUNDLING_SOURCES = (0, import_node_fs7.existsSync)(
|
|
5310
|
+
(0, import_node_path9.resolve)(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
5042
5311
|
);
|
|
5043
|
-
var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : (0,
|
|
5044
|
-
var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? (0,
|
|
5045
|
-
var SDK_PACKAGE_JSON = (0,
|
|
5046
|
-
var SDK_ENTRY_FILE = (0,
|
|
5047
|
-
var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE : (0,
|
|
5048
|
-
var SDK_WORKERS_ENTRY_FILE = (0,
|
|
5049
|
-
var WORKERS_HARNESS_ENTRY_FILE = (0,
|
|
5050
|
-
var WORKERS_HARNESS_FILES_DIR = (0,
|
|
5312
|
+
var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "..");
|
|
5313
|
+
var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? (0, import_node_path9.resolve)(SOURCE_REPO_ROOT, "sdk", "src") : HAS_PACKAGED_BUNDLING_SOURCES ? (0, import_node_path9.resolve)(PACKAGED_REPO_ROOT, "sdk", "src") : (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "src");
|
|
5314
|
+
var SDK_PACKAGE_JSON = (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "package.json");
|
|
5315
|
+
var SDK_ENTRY_FILE = (0, import_node_path9.resolve)(SDK_SOURCE_ROOT, "index.ts");
|
|
5316
|
+
var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE : (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "dist", "index.d.ts");
|
|
5317
|
+
var SDK_WORKERS_ENTRY_FILE = (0, import_node_path9.resolve)(SDK_SOURCE_ROOT, "worker-play-entry.ts");
|
|
5318
|
+
var WORKERS_HARNESS_ENTRY_FILE = (0, import_node_path9.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src", "entry.ts");
|
|
5319
|
+
var WORKERS_HARNESS_FILES_DIR = (0, import_node_path9.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src");
|
|
5051
5320
|
var hasWarnedAboutNonDevelopmentBundling = false;
|
|
5052
5321
|
function warnAboutNonDevelopmentBundling(filePath) {
|
|
5053
5322
|
if (hasWarnedAboutNonDevelopmentBundling) {
|
|
@@ -5071,12 +5340,12 @@ function defaultPlayBundleTarget() {
|
|
|
5071
5340
|
function createSdkPlayBundlingAdapter() {
|
|
5072
5341
|
return {
|
|
5073
5342
|
projectRoot: PROJECT_ROOT,
|
|
5074
|
-
nodeModulesDir: (0,
|
|
5075
|
-
cacheDir: (0,
|
|
5343
|
+
nodeModulesDir: (0, import_node_path9.resolve)(PROJECT_ROOT, "node_modules"),
|
|
5344
|
+
cacheDir: (0, import_node_path9.join)((0, import_node_os5.tmpdir)(), `deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION2}`),
|
|
5076
5345
|
sdkSourceRoot: SDK_SOURCE_ROOT,
|
|
5077
5346
|
sdkPackageJson: SDK_PACKAGE_JSON,
|
|
5078
5347
|
sdkEntryFile: SDK_ENTRY_FILE,
|
|
5079
|
-
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !(0,
|
|
5348
|
+
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !(0, import_node_fs7.existsSync)(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
|
|
5080
5349
|
sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
|
|
5081
5350
|
workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
|
|
5082
5351
|
workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
|
|
@@ -5309,7 +5578,7 @@ function traceCliSync(phase, fields, run) {
|
|
|
5309
5578
|
}
|
|
5310
5579
|
}
|
|
5311
5580
|
function sleep4(ms) {
|
|
5312
|
-
return new Promise((
|
|
5581
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
5313
5582
|
}
|
|
5314
5583
|
function parseReferencedPlayTarget(target) {
|
|
5315
5584
|
const trimmed = target.trim();
|
|
@@ -5355,7 +5624,7 @@ function formatPlayListReference(play) {
|
|
|
5355
5624
|
function defaultMaterializedPlayPath(reference) {
|
|
5356
5625
|
const playName = parseReferencedPlayTarget(reference).unqualifiedPlayName;
|
|
5357
5626
|
const safeName = playName.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
5358
|
-
return (0,
|
|
5627
|
+
return (0, import_node_path10.resolve)(`${safeName || "play"}.play.ts`);
|
|
5359
5628
|
}
|
|
5360
5629
|
function materializeRemotePlaySource(input) {
|
|
5361
5630
|
if (isFileTarget(input.target)) {
|
|
@@ -5365,15 +5634,15 @@ function materializeRemotePlaySource(input) {
|
|
|
5365
5634
|
return null;
|
|
5366
5635
|
}
|
|
5367
5636
|
const outputPath = input.outPath ?? defaultMaterializedPlayPath(input.playName);
|
|
5368
|
-
if ((0,
|
|
5369
|
-
const existingSource = (0,
|
|
5637
|
+
if ((0, import_node_fs8.existsSync)(outputPath)) {
|
|
5638
|
+
const existingSource = (0, import_node_fs8.readFileSync)(outputPath, "utf-8");
|
|
5370
5639
|
if (existingSource === input.sourceCode) {
|
|
5371
5640
|
return { path: outputPath, status: "unchanged", created: false };
|
|
5372
5641
|
}
|
|
5373
|
-
(0,
|
|
5642
|
+
(0, import_node_fs8.writeFileSync)(outputPath, input.sourceCode, "utf-8");
|
|
5374
5643
|
return { path: outputPath, status: "updated", created: false };
|
|
5375
5644
|
}
|
|
5376
|
-
(0,
|
|
5645
|
+
(0, import_node_fs8.writeFileSync)(outputPath, input.sourceCode, "utf-8");
|
|
5377
5646
|
return { path: outputPath, status: "created", created: true };
|
|
5378
5647
|
}
|
|
5379
5648
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -5418,7 +5687,7 @@ function extractPlayName(code, filePath) {
|
|
|
5418
5687
|
throw buildMissingDefinePlayError(filePath);
|
|
5419
5688
|
}
|
|
5420
5689
|
function isFileTarget(target) {
|
|
5421
|
-
return (0,
|
|
5690
|
+
return (0, import_node_fs8.existsSync)((0, import_node_path10.resolve)(target));
|
|
5422
5691
|
}
|
|
5423
5692
|
function looksLikeFilePath(target) {
|
|
5424
5693
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -5437,7 +5706,7 @@ function parsePositiveInteger2(value, flagName) {
|
|
|
5437
5706
|
return parsed;
|
|
5438
5707
|
}
|
|
5439
5708
|
function parseJsonInput(raw) {
|
|
5440
|
-
const source = raw.startsWith("@") ? (0,
|
|
5709
|
+
const source = raw.startsWith("@") ? (0, import_node_fs8.readFileSync)((0, import_node_path10.resolve)(raw.slice(1)), "utf-8") : raw;
|
|
5441
5710
|
const parsed = JSON.parse(source);
|
|
5442
5711
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
5443
5712
|
throw new Error("--input must be a JSON object.");
|
|
@@ -5538,7 +5807,7 @@ function fileInputBindingsFromStaticPipeline(staticPipeline) {
|
|
|
5538
5807
|
function isLocalFilePathValue(value) {
|
|
5539
5808
|
if (typeof value !== "string" || !value.trim()) return false;
|
|
5540
5809
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
5541
|
-
return (0,
|
|
5810
|
+
return (0, import_node_fs8.existsSync)((0, import_node_path10.resolve)(value));
|
|
5542
5811
|
}
|
|
5543
5812
|
function inputContainsLocalFilePath(value) {
|
|
5544
5813
|
if (isLocalFilePathValue(value)) {
|
|
@@ -5564,8 +5833,8 @@ async function stageFileInputArgs(input) {
|
|
|
5564
5833
|
const localFiles = uniqueBindings.flatMap((binding) => {
|
|
5565
5834
|
const value = getDottedInputValue(input.runtimeInput, binding.inputPath);
|
|
5566
5835
|
if (!isLocalFilePathValue(value)) return [];
|
|
5567
|
-
const absolutePath = (0,
|
|
5568
|
-
return [{ binding, absolutePath, logicalPath: (0,
|
|
5836
|
+
const absolutePath = (0, import_node_path10.resolve)(value);
|
|
5837
|
+
return [{ binding, absolutePath, logicalPath: (0, import_node_path10.basename)(absolutePath) }];
|
|
5569
5838
|
});
|
|
5570
5839
|
if (localFiles.length === 0) {
|
|
5571
5840
|
return { inputFile: null, packagedFiles: [] };
|
|
@@ -5589,7 +5858,7 @@ async function stageFileInputArgs(input) {
|
|
|
5589
5858
|
};
|
|
5590
5859
|
}
|
|
5591
5860
|
function stageFile(logicalPath, absolutePath) {
|
|
5592
|
-
const buffer = (0,
|
|
5861
|
+
const buffer = (0, import_node_fs8.readFileSync)(absolutePath);
|
|
5593
5862
|
return {
|
|
5594
5863
|
logicalPath,
|
|
5595
5864
|
contentBase64: buffer.toString("base64"),
|
|
@@ -5600,9 +5869,9 @@ function stageFile(logicalPath, absolutePath) {
|
|
|
5600
5869
|
}
|
|
5601
5870
|
function normalizePlayPath(filePath) {
|
|
5602
5871
|
try {
|
|
5603
|
-
return
|
|
5872
|
+
return import_node_fs8.realpathSync.native((0, import_node_path10.resolve)(filePath));
|
|
5604
5873
|
} catch {
|
|
5605
|
-
return (0,
|
|
5874
|
+
return (0, import_node_path10.resolve)(filePath);
|
|
5606
5875
|
}
|
|
5607
5876
|
}
|
|
5608
5877
|
function formatBundlingErrors(filePath, errors) {
|
|
@@ -5755,11 +6024,42 @@ function isTransientPlayStreamError(error) {
|
|
|
5755
6024
|
text
|
|
5756
6025
|
);
|
|
5757
6026
|
}
|
|
6027
|
+
function playStatusErrorText(status) {
|
|
6028
|
+
const chunks = [];
|
|
6029
|
+
const progressError = status.progress?.error;
|
|
6030
|
+
if (typeof progressError === "string" && progressError.trim()) {
|
|
6031
|
+
chunks.push(progressError.trim());
|
|
6032
|
+
}
|
|
6033
|
+
const errorValue = status.error;
|
|
6034
|
+
if (typeof errorValue === "string" && errorValue.trim()) {
|
|
6035
|
+
chunks.push(errorValue.trim());
|
|
6036
|
+
}
|
|
6037
|
+
const errors = status.errors;
|
|
6038
|
+
if (Array.isArray(errors)) {
|
|
6039
|
+
for (const error of errors) {
|
|
6040
|
+
if (typeof error === "string" && error.trim()) {
|
|
6041
|
+
chunks.push(error.trim());
|
|
6042
|
+
} else if (error && typeof error === "object") {
|
|
6043
|
+
const message = error.message;
|
|
6044
|
+
if (typeof message === "string" && message.trim()) {
|
|
6045
|
+
chunks.push(message.trim());
|
|
6046
|
+
}
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
6049
|
+
}
|
|
6050
|
+
return chunks.join("; ") || status.status;
|
|
6051
|
+
}
|
|
6052
|
+
function isRetryablePendingStartFailure(status) {
|
|
6053
|
+
if (status.status !== "failed") return false;
|
|
6054
|
+
if (status.runId && status.runId !== "pending") return false;
|
|
6055
|
+
return isTransientPlayStreamError(new Error(playStatusErrorText(status)));
|
|
6056
|
+
}
|
|
5758
6057
|
var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
5759
6058
|
"completed",
|
|
5760
6059
|
"failed",
|
|
5761
6060
|
"cancelled"
|
|
5762
6061
|
]);
|
|
6062
|
+
var PLAY_START_TRANSIENT_RETRY_DELAYS_MS = [500, 1500];
|
|
5763
6063
|
function getEventPayload(event) {
|
|
5764
6064
|
return event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
5765
6065
|
}
|
|
@@ -5921,6 +6221,34 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
5921
6221
|
);
|
|
5922
6222
|
}
|
|
5923
6223
|
async function startAndWaitForPlayCompletionByStream(input) {
|
|
6224
|
+
for (let attempt = 0; attempt <= PLAY_START_TRANSIENT_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
6225
|
+
const status = await startAndWaitForPlayCompletionByStreamOnce(input);
|
|
6226
|
+
const retryDelayMs = PLAY_START_TRANSIENT_RETRY_DELAYS_MS[attempt];
|
|
6227
|
+
if (retryDelayMs === void 0 || !isRetryablePendingStartFailure(status)) {
|
|
6228
|
+
return status;
|
|
6229
|
+
}
|
|
6230
|
+
if (!input.jsonOutput) {
|
|
6231
|
+
input.progress.writeLine(
|
|
6232
|
+
`[play watch] start failed before run id with a transient error; retrying (${playStatusErrorText(status)})`
|
|
6233
|
+
);
|
|
6234
|
+
}
|
|
6235
|
+
recordCliTrace({
|
|
6236
|
+
phase: "cli.play_start_stream_retry",
|
|
6237
|
+
ms: 0,
|
|
6238
|
+
ok: true,
|
|
6239
|
+
playName: input.playName,
|
|
6240
|
+
attempt: attempt + 1,
|
|
6241
|
+
reason: playStatusErrorText(status)
|
|
6242
|
+
});
|
|
6243
|
+
await sleep4(retryDelayMs);
|
|
6244
|
+
}
|
|
6245
|
+
throw new DeeplineError(
|
|
6246
|
+
`Play ${input.playName} did not start after retrying transient start failures.`,
|
|
6247
|
+
void 0,
|
|
6248
|
+
"PLAY_START_RETRY_EXHAUSTED"
|
|
6249
|
+
);
|
|
6250
|
+
}
|
|
6251
|
+
async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
5924
6252
|
const startedAt = Date.now();
|
|
5925
6253
|
const dashboardUrl = buildPlayDashboardUrl(
|
|
5926
6254
|
input.client.baseUrl,
|
|
@@ -6247,14 +6575,23 @@ function buildRunWarnings(status, rowsInfo) {
|
|
|
6247
6575
|
}
|
|
6248
6576
|
return [];
|
|
6249
6577
|
}
|
|
6250
|
-
function buildRunNextCommands(
|
|
6578
|
+
function buildRunNextCommands(status) {
|
|
6579
|
+
const runId = status.runId?.trim();
|
|
6580
|
+
if (!runId) {
|
|
6581
|
+
const playName = extractRunPlayName(status);
|
|
6582
|
+
return playName ? {
|
|
6583
|
+
list: `deepline runs list --play ${playName} --json`
|
|
6584
|
+
} : {
|
|
6585
|
+
list: "deepline runs list --json"
|
|
6586
|
+
};
|
|
6587
|
+
}
|
|
6251
6588
|
const commands = {
|
|
6252
6589
|
get: `deepline runs get ${runId} --json`,
|
|
6253
6590
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
6254
6591
|
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
6255
6592
|
};
|
|
6256
|
-
if (dashboardUrl) {
|
|
6257
|
-
commands.open = `Open ${dashboardUrl} to see results.`;
|
|
6593
|
+
if (status.dashboardUrl) {
|
|
6594
|
+
commands.open = `Open ${status.dashboardUrl} to see results.`;
|
|
6258
6595
|
}
|
|
6259
6596
|
return commands;
|
|
6260
6597
|
}
|
|
@@ -6277,6 +6614,121 @@ function getTimestampField(value, key) {
|
|
|
6277
6614
|
}
|
|
6278
6615
|
return typeof field === "string" && field.trim() ? field : null;
|
|
6279
6616
|
}
|
|
6617
|
+
function getObjectField(value, key) {
|
|
6618
|
+
const field = getRecordField(value, key);
|
|
6619
|
+
return field && typeof field === "object" && !Array.isArray(field) ? field : null;
|
|
6620
|
+
}
|
|
6621
|
+
function formatCreditAmount(value) {
|
|
6622
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
6623
|
+
return String(value ?? "-");
|
|
6624
|
+
}
|
|
6625
|
+
return Number(value.toFixed(8)).toString();
|
|
6626
|
+
}
|
|
6627
|
+
function extractJsonObjectFromText(text) {
|
|
6628
|
+
const start = text.indexOf("{");
|
|
6629
|
+
if (start < 0) {
|
|
6630
|
+
return null;
|
|
6631
|
+
}
|
|
6632
|
+
const suffix = text.slice(start);
|
|
6633
|
+
try {
|
|
6634
|
+
const parsed = JSON.parse(suffix);
|
|
6635
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
6636
|
+
} catch {
|
|
6637
|
+
let depth = 0;
|
|
6638
|
+
let inString = false;
|
|
6639
|
+
let escaped = false;
|
|
6640
|
+
for (let index = start; index < text.length; index += 1) {
|
|
6641
|
+
const char = text[index];
|
|
6642
|
+
if (inString) {
|
|
6643
|
+
if (escaped) {
|
|
6644
|
+
escaped = false;
|
|
6645
|
+
} else if (char === "\\") {
|
|
6646
|
+
escaped = true;
|
|
6647
|
+
} else if (char === '"') {
|
|
6648
|
+
inString = false;
|
|
6649
|
+
}
|
|
6650
|
+
continue;
|
|
6651
|
+
}
|
|
6652
|
+
if (char === '"') {
|
|
6653
|
+
inString = true;
|
|
6654
|
+
} else if (char === "{") {
|
|
6655
|
+
depth += 1;
|
|
6656
|
+
} else if (char === "}") {
|
|
6657
|
+
depth -= 1;
|
|
6658
|
+
if (depth === 0) {
|
|
6659
|
+
try {
|
|
6660
|
+
const parsed = JSON.parse(text.slice(start, index + 1));
|
|
6661
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
6662
|
+
} catch {
|
|
6663
|
+
return null;
|
|
6664
|
+
}
|
|
6665
|
+
}
|
|
6666
|
+
}
|
|
6667
|
+
}
|
|
6668
|
+
}
|
|
6669
|
+
return null;
|
|
6670
|
+
}
|
|
6671
|
+
function extractBillingFromText(text) {
|
|
6672
|
+
if (!text) {
|
|
6673
|
+
return null;
|
|
6674
|
+
}
|
|
6675
|
+
const parsed = extractJsonObjectFromText(text);
|
|
6676
|
+
return getObjectField(parsed, "billing");
|
|
6677
|
+
}
|
|
6678
|
+
function extractToolIdFromErrorText(text) {
|
|
6679
|
+
if (!text) {
|
|
6680
|
+
return null;
|
|
6681
|
+
}
|
|
6682
|
+
const lowerToolMatch = /\btool\s+([A-Za-z0-9_.:-]+)\s+\d{3}\b/.exec(text);
|
|
6683
|
+
if (lowerToolMatch?.[1]) {
|
|
6684
|
+
return lowerToolMatch[1];
|
|
6685
|
+
}
|
|
6686
|
+
const upperToolMatch = /\bTool\s+([A-Za-z0-9_.:-]+)\s+failed\b/.exec(text);
|
|
6687
|
+
return upperToolMatch?.[1] ?? null;
|
|
6688
|
+
}
|
|
6689
|
+
function isInsufficientCreditsBilling(billing) {
|
|
6690
|
+
return billing?.kind === "insufficient_credits";
|
|
6691
|
+
}
|
|
6692
|
+
function extractBillingForStatus(status, error) {
|
|
6693
|
+
const errorBilling = getObjectField(status, "errorBilling");
|
|
6694
|
+
if (errorBilling) {
|
|
6695
|
+
return errorBilling;
|
|
6696
|
+
}
|
|
6697
|
+
const directErrors = getRecordField(status, "errors");
|
|
6698
|
+
if (Array.isArray(directErrors)) {
|
|
6699
|
+
for (const entry of directErrors) {
|
|
6700
|
+
const billing = getObjectField(entry, "billing");
|
|
6701
|
+
if (billing) {
|
|
6702
|
+
return billing;
|
|
6703
|
+
}
|
|
6704
|
+
}
|
|
6705
|
+
}
|
|
6706
|
+
const progressError = getStringField(status.progress, "error");
|
|
6707
|
+
return extractBillingFromText(error) ?? extractBillingFromText(progressError) ?? getObjectField(status, "billing");
|
|
6708
|
+
}
|
|
6709
|
+
function formatInsufficientCreditsMessage(input) {
|
|
6710
|
+
const operation = getStringField(input.billing, "operation_id") ?? getStringField(input.billing, "operation") ?? extractToolIdFromErrorText(input.error) ?? getStringField(input.billing, "provider") ?? "tool call";
|
|
6711
|
+
const balance = formatCreditAmount(input.billing.balance_credits);
|
|
6712
|
+
const required = formatCreditAmount(input.billing.required_credits);
|
|
6713
|
+
const recommended = formatCreditAmount(
|
|
6714
|
+
input.billing.recommended_add_credits ?? input.billing.needed_credits
|
|
6715
|
+
);
|
|
6716
|
+
const billingUrl = getStringField(input.billing, "billing_url");
|
|
6717
|
+
const workspace = getStringField(input.billing, "workspace_id") ?? getStringField(input.billing, "workspaceId");
|
|
6718
|
+
const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
|
|
6719
|
+
const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
|
|
6720
|
+
return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
|
|
6721
|
+
}
|
|
6722
|
+
function formatPlayErrorForDisplay(status, error) {
|
|
6723
|
+
if (!error) {
|
|
6724
|
+
return null;
|
|
6725
|
+
}
|
|
6726
|
+
const billing = extractBillingForStatus(status, error);
|
|
6727
|
+
if (isInsufficientCreditsBilling(billing)) {
|
|
6728
|
+
return formatInsufficientCreditsMessage({ billing, error });
|
|
6729
|
+
}
|
|
6730
|
+
return error;
|
|
6731
|
+
}
|
|
6280
6732
|
function normalizeRunStatusForEnvelope(status) {
|
|
6281
6733
|
const run = status.run ?? null;
|
|
6282
6734
|
return {
|
|
@@ -6327,18 +6779,33 @@ function normalizeErrorsForEnvelope(status, error) {
|
|
|
6327
6779
|
if (Array.isArray(directErrors)) {
|
|
6328
6780
|
return directErrors.filter(
|
|
6329
6781
|
(entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
|
|
6330
|
-
)
|
|
6782
|
+
).map((entry) => {
|
|
6783
|
+
const message2 = typeof entry.message === "string" && entry.message.trim() ? entry.message : error;
|
|
6784
|
+
const billing2 = getObjectField(entry, "billing");
|
|
6785
|
+
if (!isInsufficientCreditsBilling(billing2) || !message2) {
|
|
6786
|
+
return entry;
|
|
6787
|
+
}
|
|
6788
|
+
return {
|
|
6789
|
+
...entry,
|
|
6790
|
+
message: formatInsufficientCreditsMessage({ billing: billing2, error: message2 }),
|
|
6791
|
+
billing: stripProviderSpendFromBilling(billing2)
|
|
6792
|
+
};
|
|
6793
|
+
});
|
|
6331
6794
|
}
|
|
6332
6795
|
if (!error) {
|
|
6333
6796
|
return [];
|
|
6334
6797
|
}
|
|
6798
|
+
const nextCommands = buildRunNextCommands(status);
|
|
6799
|
+
const billing = extractBillingForStatus(status, error);
|
|
6800
|
+
const message = formatPlayErrorForDisplay(status, error) ?? error;
|
|
6335
6801
|
return [
|
|
6336
6802
|
{
|
|
6337
6803
|
code: getStringField(status, "errorCode") ?? "RUN_FAILED",
|
|
6338
6804
|
phase: getStringField(status, "errorPhase") ?? "runtime",
|
|
6339
|
-
message
|
|
6805
|
+
message,
|
|
6340
6806
|
retryable: typeof getRecordField(status, "retryable") === "boolean" ? getRecordField(status, "retryable") : null,
|
|
6341
|
-
|
|
6807
|
+
...billing ? { billing: stripProviderSpendFromBilling(billing) } : {},
|
|
6808
|
+
nextAction: nextCommands.get ?? nextCommands.list
|
|
6342
6809
|
}
|
|
6343
6810
|
];
|
|
6344
6811
|
}
|
|
@@ -6387,6 +6854,7 @@ function compactPlayStatus(status) {
|
|
|
6387
6854
|
) : null;
|
|
6388
6855
|
const progressError = status.progress?.error;
|
|
6389
6856
|
const error = typeof progressError === "string" ? progressError : typeof status.error === "string" ? String(status.error) : null;
|
|
6857
|
+
const displayError = formatPlayErrorForDisplay(status, error);
|
|
6390
6858
|
return {
|
|
6391
6859
|
runId: status.runId,
|
|
6392
6860
|
apiVersion: status.apiVersion ?? 1,
|
|
@@ -6399,13 +6867,13 @@ function compactPlayStatus(status) {
|
|
|
6399
6867
|
steps: normalizeStepsForEnvelope(status),
|
|
6400
6868
|
errors: normalizeErrorsForEnvelope(status, error),
|
|
6401
6869
|
logs: normalizeLogsForEnvelope(status),
|
|
6402
|
-
...
|
|
6870
|
+
...displayError ? { error: displayError } : {},
|
|
6403
6871
|
...warnings.length > 0 ? { warnings } : {},
|
|
6404
6872
|
...result !== void 0 ? { result } : {},
|
|
6405
6873
|
...status.resultView ? { resultView: status.resultView } : {},
|
|
6406
6874
|
...datasetStats ? { dataset_stats: datasetStats } : {},
|
|
6407
6875
|
...billing ? { billing } : {},
|
|
6408
|
-
next: buildRunNextCommands(status
|
|
6876
|
+
next: buildRunNextCommands(status)
|
|
6409
6877
|
};
|
|
6410
6878
|
}
|
|
6411
6879
|
function enrichPlayStatusWithDatasetStats(status) {
|
|
@@ -6479,7 +6947,8 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
6479
6947
|
lines.push(...formatDatasetStatsLines(datasetStats));
|
|
6480
6948
|
const progressError = status.progress?.error;
|
|
6481
6949
|
if (progressError && typeof progressError === "string") {
|
|
6482
|
-
|
|
6950
|
+
const displayError = formatPlayErrorForDisplay(status, progressError) ?? progressError;
|
|
6951
|
+
lines.push(` error: ${displayError.slice(0, 200)}`);
|
|
6483
6952
|
}
|
|
6484
6953
|
const renderedServerView = renderServerResultView(status.resultView);
|
|
6485
6954
|
if (result) {
|
|
@@ -6503,8 +6972,11 @@ var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
|
6503
6972
|
function shellSingleQuote(value) {
|
|
6504
6973
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
6505
6974
|
}
|
|
6975
|
+
function sqlStringLiteral(value) {
|
|
6976
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
6977
|
+
}
|
|
6506
6978
|
function runExportRetryCommand(runId, outPath, datasetPath) {
|
|
6507
|
-
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0,
|
|
6979
|
+
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0, import_node_path10.resolve)(outPath))}`;
|
|
6508
6980
|
}
|
|
6509
6981
|
function extractRunPlayName(status) {
|
|
6510
6982
|
const run = status.run;
|
|
@@ -6521,6 +6993,26 @@ function extractRunPlayName(status) {
|
|
|
6521
6993
|
}
|
|
6522
6994
|
return null;
|
|
6523
6995
|
}
|
|
6996
|
+
function normalizeCustomerDbIdentifier(value) {
|
|
6997
|
+
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
6998
|
+
}
|
|
6999
|
+
function buildCustomerDbQueryPlan(input) {
|
|
7000
|
+
const playName = extractRunPlayName(input.status);
|
|
7001
|
+
const tableNamespace = input.rowsInfo.tableNamespace?.trim();
|
|
7002
|
+
if (!playName || !tableNamespace || input.rowsInfo.totalRows <= 0) {
|
|
7003
|
+
return null;
|
|
7004
|
+
}
|
|
7005
|
+
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
7006
|
+
tableNamespace
|
|
7007
|
+
)}`;
|
|
7008
|
+
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input.status.runId)} limit ${input.rowsInfo.totalRows}`;
|
|
7009
|
+
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input.rowsInfo.totalRows}`;
|
|
7010
|
+
return {
|
|
7011
|
+
sql,
|
|
7012
|
+
json: `${base} --json`,
|
|
7013
|
+
csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path10.resolve)(input.outPath))}`
|
|
7014
|
+
};
|
|
7015
|
+
}
|
|
6524
7016
|
function exportableSheetRow(row) {
|
|
6525
7017
|
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
6526
7018
|
return null;
|
|
@@ -6692,6 +7184,60 @@ async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
|
6692
7184
|
}
|
|
6693
7185
|
return { path: writeCanonicalRowsCsv(rowsInfo, outPath), rowsInfo };
|
|
6694
7186
|
}
|
|
7187
|
+
function extractActiveRunsFromError(error) {
|
|
7188
|
+
if (!(error instanceof DeeplineError)) {
|
|
7189
|
+
return [];
|
|
7190
|
+
}
|
|
7191
|
+
const response = error.details?.response;
|
|
7192
|
+
if (!response || typeof response !== "object" || Array.isArray(response)) {
|
|
7193
|
+
return [];
|
|
7194
|
+
}
|
|
7195
|
+
const details = response.details;
|
|
7196
|
+
if (!details || typeof details !== "object" || Array.isArray(details)) {
|
|
7197
|
+
return [];
|
|
7198
|
+
}
|
|
7199
|
+
const activeRuns = details.activeRuns;
|
|
7200
|
+
return Array.isArray(activeRuns) ? activeRuns.filter(
|
|
7201
|
+
(run) => Boolean(run) && typeof run === "object" && !Array.isArray(run)
|
|
7202
|
+
) : [];
|
|
7203
|
+
}
|
|
7204
|
+
function activeRunId(run) {
|
|
7205
|
+
return getStringField(run, "workflowId") ?? getStringField(run, "runId");
|
|
7206
|
+
}
|
|
7207
|
+
function formatActiveRunConflictError(input) {
|
|
7208
|
+
const lines = [
|
|
7209
|
+
`Active run exists for ${input.playName}. Use --force to supersede, or inspect/stop the active run first.`
|
|
7210
|
+
];
|
|
7211
|
+
for (const run of input.activeRuns.slice(0, 3)) {
|
|
7212
|
+
const runId = activeRunId(run);
|
|
7213
|
+
if (!runId) {
|
|
7214
|
+
continue;
|
|
7215
|
+
}
|
|
7216
|
+
const status = getStringField(run, "status");
|
|
7217
|
+
const startedAt = getStringField(run, "startedAt") ?? getStringField(run, "startTime");
|
|
7218
|
+
lines.push(
|
|
7219
|
+
` active: ${runId}${status ? ` status=${status}` : ""}${startedAt ? ` startedAt=${startedAt}` : ""}`
|
|
7220
|
+
);
|
|
7221
|
+
lines.push(` get: deepline runs get ${runId} --json`);
|
|
7222
|
+
lines.push(
|
|
7223
|
+
` stop: deepline runs stop ${runId} --reason "stale lock" --json`
|
|
7224
|
+
);
|
|
7225
|
+
}
|
|
7226
|
+
lines.push(` rerun: add --force to the same deepline plays run command`);
|
|
7227
|
+
return lines.join("\n");
|
|
7228
|
+
}
|
|
7229
|
+
function normalizePlayStartError(error, playName) {
|
|
7230
|
+
const activeRuns = extractActiveRunsFromError(error);
|
|
7231
|
+
if (activeRuns.length === 0) {
|
|
7232
|
+
return error;
|
|
7233
|
+
}
|
|
7234
|
+
return new DeeplineError(
|
|
7235
|
+
formatActiveRunConflictError({ playName, activeRuns }),
|
|
7236
|
+
error instanceof DeeplineError ? error.statusCode : 409,
|
|
7237
|
+
"ACTIVE_RUN_EXISTS",
|
|
7238
|
+
error instanceof DeeplineError ? error.details : void 0
|
|
7239
|
+
);
|
|
7240
|
+
}
|
|
6695
7241
|
function renderServerResultView(value) {
|
|
6696
7242
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6697
7243
|
return { lines: [], actions: [] };
|
|
@@ -6927,12 +7473,12 @@ function shouldUseLocalOnlyPlayCheck() {
|
|
|
6927
7473
|
async function handlePlayCheck(args) {
|
|
6928
7474
|
const options = parsePlayCheckOptions(args);
|
|
6929
7475
|
if (!isFileTarget(options.target)) {
|
|
6930
|
-
const resolved = (0,
|
|
7476
|
+
const resolved = (0, import_node_path10.resolve)(options.target);
|
|
6931
7477
|
console.error(`File not found: ${resolved}`);
|
|
6932
7478
|
return 1;
|
|
6933
7479
|
}
|
|
6934
|
-
const absolutePlayPath = (0,
|
|
6935
|
-
const sourceCode = (0,
|
|
7480
|
+
const absolutePlayPath = (0, import_node_path10.resolve)(options.target);
|
|
7481
|
+
const sourceCode = (0, import_node_fs8.readFileSync)(absolutePlayPath, "utf-8");
|
|
6936
7482
|
let graph;
|
|
6937
7483
|
try {
|
|
6938
7484
|
graph = await collectBundledPlayGraph(absolutePlayPath);
|
|
@@ -6995,12 +7541,12 @@ async function handleFileBackedRun(options) {
|
|
|
6995
7541
|
}
|
|
6996
7542
|
const client = new DeeplineClient();
|
|
6997
7543
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
6998
|
-
const absolutePlayPath = (0,
|
|
7544
|
+
const absolutePlayPath = (0, import_node_path10.resolve)(options.target.path);
|
|
6999
7545
|
progress.phase("compiling play");
|
|
7000
7546
|
const sourceCode = traceCliSync(
|
|
7001
7547
|
"cli.play_file_read_source",
|
|
7002
7548
|
{ targetKind: "file" },
|
|
7003
|
-
() => (0,
|
|
7549
|
+
() => (0, import_node_fs8.readFileSync)(absolutePlayPath, "utf-8")
|
|
7004
7550
|
);
|
|
7005
7551
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
7006
7552
|
let graph;
|
|
@@ -7081,6 +7627,8 @@ async function handleFileBackedRun(options) {
|
|
|
7081
7627
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
7082
7628
|
noOpen: options.noOpen,
|
|
7083
7629
|
progress
|
|
7630
|
+
}).catch((error) => {
|
|
7631
|
+
throw normalizePlayStartError(error, playName);
|
|
7084
7632
|
})
|
|
7085
7633
|
);
|
|
7086
7634
|
if (finalStatus.status === "completed") {
|
|
@@ -7099,7 +7647,9 @@ async function handleFileBackedRun(options) {
|
|
|
7099
7647
|
const started = await traceCliSpan(
|
|
7100
7648
|
"cli.play_start_unwatched",
|
|
7101
7649
|
{ targetKind: "file", playName },
|
|
7102
|
-
() => client.startPlayRun(startRequest)
|
|
7650
|
+
() => client.startPlayRun(startRequest).catch((error) => {
|
|
7651
|
+
throw normalizePlayStartError(error, playName);
|
|
7652
|
+
})
|
|
7103
7653
|
);
|
|
7104
7654
|
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7105
7655
|
openPlayDashboard({
|
|
@@ -7216,6 +7766,8 @@ async function handleNamedRun(options) {
|
|
|
7216
7766
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
7217
7767
|
noOpen: options.noOpen,
|
|
7218
7768
|
progress
|
|
7769
|
+
}).catch((error) => {
|
|
7770
|
+
throw normalizePlayStartError(error, playName);
|
|
7219
7771
|
})
|
|
7220
7772
|
);
|
|
7221
7773
|
if (finalStatus.status === "completed") {
|
|
@@ -7234,7 +7786,9 @@ async function handleNamedRun(options) {
|
|
|
7234
7786
|
const started = await traceCliSpan(
|
|
7235
7787
|
"cli.play_start_unwatched",
|
|
7236
7788
|
{ targetKind: "name", playName },
|
|
7237
|
-
() => client.startPlayRun(startRequest)
|
|
7789
|
+
() => client.startPlayRun(startRequest).catch((error) => {
|
|
7790
|
+
throw normalizePlayStartError(error, playName);
|
|
7791
|
+
})
|
|
7238
7792
|
);
|
|
7239
7793
|
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7240
7794
|
openPlayDashboard({
|
|
@@ -7260,19 +7814,19 @@ async function handlePlayRun(args) {
|
|
|
7260
7814
|
if (isFileTarget(options.target.path)) {
|
|
7261
7815
|
return handleFileBackedRun(options);
|
|
7262
7816
|
}
|
|
7263
|
-
const resolved = (0,
|
|
7817
|
+
const resolved = (0, import_node_path10.resolve)(options.target.path);
|
|
7264
7818
|
console.error(`File not found: ${resolved}`);
|
|
7265
|
-
const dir = (0,
|
|
7266
|
-
if ((0,
|
|
7267
|
-
const base = (0,
|
|
7819
|
+
const dir = (0, import_node_path10.dirname)(resolved);
|
|
7820
|
+
if ((0, import_node_fs8.existsSync)(dir)) {
|
|
7821
|
+
const base = (0, import_node_path10.basename)(resolved);
|
|
7268
7822
|
try {
|
|
7269
|
-
const siblings = (0,
|
|
7823
|
+
const siblings = (0, import_node_fs8.readdirSync)(dir).filter(
|
|
7270
7824
|
(f) => f.includes(base.replace(/\.(play\.)?ts$/, "")) || f.endsWith(".play.ts")
|
|
7271
7825
|
);
|
|
7272
7826
|
if (siblings.length > 0) {
|
|
7273
7827
|
console.error(`Did you mean one of these?`);
|
|
7274
7828
|
for (const s of siblings.slice(0, 5)) {
|
|
7275
|
-
console.error(` ${(0,
|
|
7829
|
+
console.error(` ${(0, import_node_path10.join)(dir, s)}`);
|
|
7276
7830
|
}
|
|
7277
7831
|
}
|
|
7278
7832
|
} catch {
|
|
@@ -7407,14 +7961,14 @@ async function handleRunLogs(args) {
|
|
|
7407
7961
|
continue;
|
|
7408
7962
|
}
|
|
7409
7963
|
if (arg === "--out" && args[index + 1]) {
|
|
7410
|
-
outPath = (0,
|
|
7964
|
+
outPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7411
7965
|
}
|
|
7412
7966
|
}
|
|
7413
7967
|
const client = new DeeplineClient();
|
|
7414
7968
|
const status = await client.runs.get(runId);
|
|
7415
7969
|
const logs = status.progress?.logs ?? [];
|
|
7416
7970
|
if (outPath) {
|
|
7417
|
-
(0,
|
|
7971
|
+
(0, import_node_fs8.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
7418
7972
|
printCommandEnvelope({
|
|
7419
7973
|
runId: status.runId,
|
|
7420
7974
|
log_path: outPath,
|
|
@@ -7470,7 +8024,7 @@ async function handleRunStop(args) {
|
|
|
7470
8024
|
return 0;
|
|
7471
8025
|
}
|
|
7472
8026
|
async function handleRunExport(args) {
|
|
7473
|
-
const usage = "Usage: deepline runs export <run-id> [--dataset result.rows] --out output.csv [--json]";
|
|
8027
|
+
const usage = "Usage: deepline runs export <run-id> [--dataset result.rows] --out output.csv [--metadata-out export.json] [--json]";
|
|
7474
8028
|
let runId;
|
|
7475
8029
|
try {
|
|
7476
8030
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -7480,14 +8034,19 @@ async function handleRunExport(args) {
|
|
|
7480
8034
|
}
|
|
7481
8035
|
let outPath = null;
|
|
7482
8036
|
let datasetPath = null;
|
|
8037
|
+
let metadataOutPath = null;
|
|
7483
8038
|
for (let index = 0; index < args.length; index += 1) {
|
|
7484
8039
|
const arg = args[index];
|
|
7485
8040
|
if (arg === "--out" && args[index + 1]) {
|
|
7486
|
-
outPath = (0,
|
|
8041
|
+
outPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7487
8042
|
continue;
|
|
7488
8043
|
}
|
|
7489
8044
|
if (arg === "--dataset" && args[index + 1]) {
|
|
7490
8045
|
datasetPath = args[++index];
|
|
8046
|
+
continue;
|
|
8047
|
+
}
|
|
8048
|
+
if (arg === "--metadata-out" && args[index + 1]) {
|
|
8049
|
+
metadataOutPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7491
8050
|
}
|
|
7492
8051
|
}
|
|
7493
8052
|
if (!outPath) {
|
|
@@ -7499,15 +8058,59 @@ async function handleRunExport(args) {
|
|
|
7499
8058
|
const exportResult = await exportPlayStatusRows(client, status, outPath, {
|
|
7500
8059
|
datasetPath
|
|
7501
8060
|
});
|
|
7502
|
-
|
|
8061
|
+
const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
|
|
8062
|
+
const queryPlan = exportResult && outPath ? buildCustomerDbQueryPlan({
|
|
8063
|
+
status,
|
|
8064
|
+
rowsInfo: exportResult.rowsInfo,
|
|
8065
|
+
outPath
|
|
8066
|
+
}) : null;
|
|
8067
|
+
const next = {
|
|
8068
|
+
...buildRunNextCommands(status),
|
|
8069
|
+
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source),
|
|
8070
|
+
...queryPlan ? {
|
|
8071
|
+
queryJson: queryPlan.json,
|
|
8072
|
+
queryCsv: queryPlan.csv
|
|
8073
|
+
} : {}
|
|
8074
|
+
};
|
|
8075
|
+
const payload = {
|
|
7503
8076
|
runId: status.runId,
|
|
7504
8077
|
...datasetPath ? { dataset: datasetPath } : {},
|
|
7505
8078
|
csv_path: exportResult?.path ?? null,
|
|
8079
|
+
source,
|
|
7506
8080
|
rowCount: exportResult?.rowsInfo.totalRows ?? null,
|
|
7507
8081
|
columns: exportResult?.rowsInfo.columns ?? [],
|
|
8082
|
+
...queryPlan ? {
|
|
8083
|
+
query: {
|
|
8084
|
+
sql: queryPlan.sql,
|
|
8085
|
+
json: queryPlan.json,
|
|
8086
|
+
csv: queryPlan.csv
|
|
8087
|
+
}
|
|
8088
|
+
} : {},
|
|
8089
|
+
...metadataOutPath ? { metadata_path: metadataOutPath } : {},
|
|
7508
8090
|
local: { csv_path: exportResult?.path ?? null },
|
|
7509
|
-
|
|
7510
|
-
|
|
8091
|
+
next,
|
|
8092
|
+
render: {
|
|
8093
|
+
sections: [
|
|
8094
|
+
{
|
|
8095
|
+
title: "run export",
|
|
8096
|
+
lines: [
|
|
8097
|
+
`Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
|
|
8098
|
+
...source ? [`source=${source}`] : [],
|
|
8099
|
+
...queryPlan ? [`query=${queryPlan.json}`] : []
|
|
8100
|
+
]
|
|
8101
|
+
}
|
|
8102
|
+
]
|
|
8103
|
+
}
|
|
8104
|
+
};
|
|
8105
|
+
if (metadataOutPath) {
|
|
8106
|
+
(0, import_node_fs8.writeFileSync)(
|
|
8107
|
+
metadataOutPath,
|
|
8108
|
+
`${JSON.stringify(payload, null, 2)}
|
|
8109
|
+
`,
|
|
8110
|
+
"utf-8"
|
|
8111
|
+
);
|
|
8112
|
+
}
|
|
8113
|
+
printCommandEnvelope(payload, { json: argsWantJson(args) });
|
|
7511
8114
|
return 0;
|
|
7512
8115
|
}
|
|
7513
8116
|
async function handlePlayGet(args) {
|
|
@@ -7524,10 +8127,10 @@ async function handlePlayGet(args) {
|
|
|
7524
8127
|
for (let index = 1; index < args.length; index += 1) {
|
|
7525
8128
|
const arg = args[index];
|
|
7526
8129
|
if (arg === "--out" && args[index + 1]) {
|
|
7527
|
-
outPath = (0,
|
|
8130
|
+
outPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7528
8131
|
}
|
|
7529
8132
|
}
|
|
7530
|
-
const playName = isFileTarget(target) ? extractPlayName((0,
|
|
8133
|
+
const playName = isFileTarget(target) ? extractPlayName((0, import_node_fs8.readFileSync)((0, import_node_path10.resolve)(target), "utf-8"), (0, import_node_path10.resolve)(target)) : parseReferencedPlayTarget(target).playName;
|
|
7531
8134
|
const detail = isFileTarget(target) ? await client.getPlay(playName) : await assertCanonicalNamedPlayReference(client, target);
|
|
7532
8135
|
const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
|
|
7533
8136
|
const materializedFile = outPath ? materializeRemotePlaySource({
|
|
@@ -7819,7 +8422,7 @@ async function handlePlayPublish(args) {
|
|
|
7819
8422
|
}
|
|
7820
8423
|
let graph;
|
|
7821
8424
|
try {
|
|
7822
|
-
graph = await collectBundledPlayGraph((0,
|
|
8425
|
+
graph = await collectBundledPlayGraph((0, import_node_path10.resolve)(playName));
|
|
7823
8426
|
await compileBundledPlayGraphManifests(client, graph);
|
|
7824
8427
|
await publishImportedPlayDependencies(client, graph);
|
|
7825
8428
|
} catch (error) {
|
|
@@ -8305,32 +8908,36 @@ Examples:
|
|
|
8305
8908
|
Notes:
|
|
8306
8909
|
Writes a returned dataset handle to the requested local CSV path. Use runs get
|
|
8307
8910
|
first to inspect dataset paths like result.rows or result.nested.contacts.
|
|
8911
|
+
--metadata-out writes the same export metadata object returned by --json,
|
|
8912
|
+
including source and follow-on customer-db query commands when available.
|
|
8308
8913
|
|
|
8309
8914
|
Examples:
|
|
8310
8915
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
8311
8916
|
deepline runs export play/my-play/run/20260501t000000-000 --dataset result.rows --out output.csv
|
|
8917
|
+
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --metadata-out output.meta.json
|
|
8312
8918
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --json
|
|
8313
8919
|
`
|
|
8314
|
-
).requiredOption("--out <path>", "Output CSV path").option("--dataset <path>", "Returned dataset handle path, such as result.rows").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
8920
|
+
).requiredOption("--out <path>", "Output CSV path").option("--dataset <path>", "Returned dataset handle path, such as result.rows").option("--metadata-out <path>", "Write export metadata JSON to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
8315
8921
|
process.exitCode = await handleRunExport([
|
|
8316
8922
|
runId,
|
|
8317
8923
|
...options.dataset ? ["--dataset", options.dataset] : [],
|
|
8318
8924
|
"--out",
|
|
8319
8925
|
options.out,
|
|
8926
|
+
...options.metadataOut ? ["--metadata-out", options.metadataOut] : [],
|
|
8320
8927
|
...options.json ? ["--json"] : []
|
|
8321
8928
|
]);
|
|
8322
8929
|
});
|
|
8323
8930
|
}
|
|
8324
8931
|
|
|
8325
8932
|
// src/cli/commands/tools.ts
|
|
8326
|
-
var
|
|
8933
|
+
var import_node_fs10 = require("fs");
|
|
8327
8934
|
var import_node_os7 = require("os");
|
|
8328
|
-
var
|
|
8935
|
+
var import_node_path12 = require("path");
|
|
8329
8936
|
|
|
8330
8937
|
// src/tool-output.ts
|
|
8331
|
-
var
|
|
8938
|
+
var import_node_fs9 = require("fs");
|
|
8332
8939
|
var import_node_os6 = require("os");
|
|
8333
|
-
var
|
|
8940
|
+
var import_node_path11 = require("path");
|
|
8334
8941
|
function isPlainObject(value) {
|
|
8335
8942
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
8336
8943
|
}
|
|
@@ -8353,6 +8960,25 @@ function normalizeRows(value) {
|
|
|
8353
8960
|
}
|
|
8354
8961
|
function candidateRoots(payload) {
|
|
8355
8962
|
const roots = [{ path: null, value: payload }];
|
|
8963
|
+
if (isPlainObject(payload) && isPlainObject(payload.toolExecutionResult)) {
|
|
8964
|
+
roots.push({ path: "toolExecutionResult", value: payload.toolExecutionResult });
|
|
8965
|
+
const toolOutput = payload.toolExecutionResult.toolOutput;
|
|
8966
|
+
if (isPlainObject(toolOutput)) {
|
|
8967
|
+
roots.push({ path: "toolExecutionResult.toolOutput", value: toolOutput });
|
|
8968
|
+
if (Object.prototype.hasOwnProperty.call(toolOutput, "raw")) {
|
|
8969
|
+
roots.push({
|
|
8970
|
+
path: "toolExecutionResult.toolOutput.raw",
|
|
8971
|
+
value: toolOutput.raw
|
|
8972
|
+
});
|
|
8973
|
+
}
|
|
8974
|
+
}
|
|
8975
|
+
}
|
|
8976
|
+
if (isPlainObject(payload) && isPlainObject(payload.output)) {
|
|
8977
|
+
roots.push({ path: "output", value: payload.output });
|
|
8978
|
+
if (Object.prototype.hasOwnProperty.call(payload.output, "body")) {
|
|
8979
|
+
roots.push({ path: "output.body", value: payload.output.body });
|
|
8980
|
+
}
|
|
8981
|
+
}
|
|
8356
8982
|
if (isPlainObject(payload) && isPlainObject(payload.result)) {
|
|
8357
8983
|
roots.push({ path: "result", value: payload.result });
|
|
8358
8984
|
if (isPlainObject(payload.result.data)) {
|
|
@@ -8405,19 +9031,19 @@ function tryConvertToList(payload, options) {
|
|
|
8405
9031
|
return null;
|
|
8406
9032
|
}
|
|
8407
9033
|
function ensureOutputDir() {
|
|
8408
|
-
const outputDir = (0,
|
|
8409
|
-
(0,
|
|
9034
|
+
const outputDir = (0, import_node_path11.join)((0, import_node_os6.homedir)(), ".local", "share", "deepline", "data");
|
|
9035
|
+
(0, import_node_fs9.mkdirSync)(outputDir, { recursive: true });
|
|
8410
9036
|
return outputDir;
|
|
8411
9037
|
}
|
|
8412
9038
|
function writeJsonOutputFile(payload, stem) {
|
|
8413
9039
|
const outputDir = ensureOutputDir();
|
|
8414
|
-
const outputPath = (0,
|
|
8415
|
-
(0,
|
|
9040
|
+
const outputPath = (0, import_node_path11.join)(outputDir, `${stem}_${Date.now()}.json`);
|
|
9041
|
+
(0, import_node_fs9.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
8416
9042
|
return outputPath;
|
|
8417
9043
|
}
|
|
8418
9044
|
function writeCsvOutputFile(rows, stem) {
|
|
8419
9045
|
const outputDir = ensureOutputDir();
|
|
8420
|
-
const outputPath = (0,
|
|
9046
|
+
const outputPath = (0, import_node_path11.join)(outputDir, `${stem}_${Date.now()}.csv`);
|
|
8421
9047
|
const seen = /* @__PURE__ */ new Set();
|
|
8422
9048
|
const columns = [];
|
|
8423
9049
|
for (const row of rows) {
|
|
@@ -8440,7 +9066,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
8440
9066
|
for (const row of rows) {
|
|
8441
9067
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
8442
9068
|
}
|
|
8443
|
-
(0,
|
|
9069
|
+
(0, import_node_fs9.writeFileSync)(outputPath, `${lines.join("\n")}
|
|
8444
9070
|
`, "utf-8");
|
|
8445
9071
|
const previewRows = rows.slice(0, 5);
|
|
8446
9072
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -8486,8 +9112,7 @@ async function listTools(args) {
|
|
|
8486
9112
|
title: `${items.length} tools available:`,
|
|
8487
9113
|
lines: items.flatMap((item) => {
|
|
8488
9114
|
const cats = item.categories.length ? ` [${item.categories.join(", ")}]` : "";
|
|
8489
|
-
|
|
8490
|
-
return [`${item.toolId}${cats}`, ` ${item.description}${listHint}`];
|
|
9115
|
+
return [`${item.toolId}${cats}`, ` ${item.description}`];
|
|
8491
9116
|
})
|
|
8492
9117
|
}
|
|
8493
9118
|
]
|
|
@@ -8566,7 +9191,7 @@ Common commands:
|
|
|
8566
9191
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
8567
9192
|
|
|
8568
9193
|
Output:
|
|
8569
|
-
Use describe for tool contracts.
|
|
9194
|
+
Use describe for tool contracts.
|
|
8570
9195
|
Use execute to run a tool. run is accepted as a compatibility alias.
|
|
8571
9196
|
`
|
|
8572
9197
|
);
|
|
@@ -8613,8 +9238,8 @@ Examples:
|
|
|
8613
9238
|
`
|
|
8614
9239
|
Notes:
|
|
8615
9240
|
Shows the tool contract, input schema, output schema, Deepline cost, aliases,
|
|
8616
|
-
and metadata. describe is the
|
|
8617
|
-
|
|
9241
|
+
and metadata. describe is the supported discovery verb. get is removed in
|
|
9242
|
+
the V2 SDK CLI; use describe for the same metadata surface.
|
|
8618
9243
|
|
|
8619
9244
|
Examples:
|
|
8620
9245
|
deepline tools describe hunter_email_verifier
|
|
@@ -8627,7 +9252,22 @@ Examples:
|
|
|
8627
9252
|
...options.json ? ["--json"] : []
|
|
8628
9253
|
]);
|
|
8629
9254
|
});
|
|
8630
|
-
addToolMetadataCommand(tools.command("describe <toolId>")
|
|
9255
|
+
addToolMetadataCommand(tools.command("describe <toolId>"));
|
|
9256
|
+
tools.command("get <toolId>").description("Deprecated. Use tools describe.").addHelpText(
|
|
9257
|
+
"after",
|
|
9258
|
+
`
|
|
9259
|
+
Examples:
|
|
9260
|
+
deepline tools describe hunter_email_verifier --json
|
|
9261
|
+
`
|
|
9262
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (toolId, options) => {
|
|
9263
|
+
const message = `tools get has been removed from the V2 SDK CLI. Use: deepline tools describe ${toolId} --json`;
|
|
9264
|
+
if (options.json || shouldEmitJson()) {
|
|
9265
|
+
printJsonError({ message, code: "TOOLS_GET_REMOVED" });
|
|
9266
|
+
} else {
|
|
9267
|
+
console.error(message);
|
|
9268
|
+
}
|
|
9269
|
+
process.exitCode = 2;
|
|
9270
|
+
});
|
|
8631
9271
|
tools.command("execute <toolId>").alias("run").description("Execute a tool by id.").addHelpText(
|
|
8632
9272
|
"after",
|
|
8633
9273
|
`
|
|
@@ -8708,6 +9348,7 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8708
9348
|
const stepContributions = arrayField(tool, "stepContributions", "step_contributions");
|
|
8709
9349
|
const playExpansion = recordField(tool, "playExpansion", "play_expansion");
|
|
8710
9350
|
const samples = recordField(tool, "samples");
|
|
9351
|
+
const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
|
|
8711
9352
|
console.log(`Tool: ${toolId}`);
|
|
8712
9353
|
if (displayName) {
|
|
8713
9354
|
console.log(" Display name:");
|
|
@@ -8771,14 +9412,16 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8771
9412
|
console.log(" Tip: pass --payload with a JSON object.");
|
|
8772
9413
|
}
|
|
8773
9414
|
printSamples(samples);
|
|
9415
|
+
printUsageGuidance(usageGuidance);
|
|
8774
9416
|
if (isPlayTool(tool)) {
|
|
8775
9417
|
console.log(" Play contract:");
|
|
8776
9418
|
console.log(" - This is a deepline-native waterfall; the returned rows are extracted by target getters, not by hand-authored payload shape.");
|
|
8777
9419
|
if (playExpansion && typeof playExpansion.group === "string" && playExpansion.group.trim()) {
|
|
8778
9420
|
console.log(` - Output alias/runtime group is: ${playExpansion.group.trim()}`);
|
|
8779
9421
|
}
|
|
8780
|
-
const
|
|
8781
|
-
const
|
|
9422
|
+
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult");
|
|
9423
|
+
const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9424
|
+
const targets = extractedValues.map((entry) => isRecord3(entry) && typeof entry.name === "string" ? entry.name : "").filter(Boolean).sort();
|
|
8782
9425
|
if (targets.length) {
|
|
8783
9426
|
console.log(` - Built-in extract targets: ${targets.join(", ")}`);
|
|
8784
9427
|
}
|
|
@@ -8797,7 +9440,53 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8797
9440
|
} else {
|
|
8798
9441
|
console.log(` deepline tools execute ${toolId} --payload '{...}'`);
|
|
8799
9442
|
}
|
|
8800
|
-
console.log(" deepline tools
|
|
9443
|
+
console.log(" deepline tools describe <tool_id> --json");
|
|
9444
|
+
}
|
|
9445
|
+
function printUsageGuidance(usageGuidance) {
|
|
9446
|
+
if (Object.keys(usageGuidance).length === 0) return;
|
|
9447
|
+
const execute = stringField(usageGuidance, "execute");
|
|
9448
|
+
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
|
|
9449
|
+
const toolOutput = recordField(toolExecutionResult, "toolOutput", "tool_output");
|
|
9450
|
+
const extractedLists = extractionEntries(toolExecutionResult, "extractedLists", "extracted_lists");
|
|
9451
|
+
const extractedValues = extractionEntries(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9452
|
+
console.log(" Usage guidance:");
|
|
9453
|
+
if (execute) console.log(` ${execute}`);
|
|
9454
|
+
const raw = pathField(toolOutput, "raw");
|
|
9455
|
+
const meta = pathField(toolOutput, "meta");
|
|
9456
|
+
if (raw) console.log(` Raw tool output: ${raw}`);
|
|
9457
|
+
if (meta) console.log(` Tool output metadata: ${meta}`);
|
|
9458
|
+
printExtractions("Extracted lists", extractedLists);
|
|
9459
|
+
printExtractions("Extracted values", extractedValues);
|
|
9460
|
+
}
|
|
9461
|
+
function pathField(record, key) {
|
|
9462
|
+
const value = record[key];
|
|
9463
|
+
if (typeof value === "string") return value.trim();
|
|
9464
|
+
if (isRecord3(value)) return stringField(value, "path");
|
|
9465
|
+
return "";
|
|
9466
|
+
}
|
|
9467
|
+
function extractionEntries(record, camelKey, snakeKey) {
|
|
9468
|
+
const value = record[camelKey] ?? record[snakeKey];
|
|
9469
|
+
if (Array.isArray(value)) return value;
|
|
9470
|
+
if (!isRecord3(value)) return [];
|
|
9471
|
+
return Object.entries(value).map(
|
|
9472
|
+
([name, entry]) => isRecord3(entry) ? { name, ...entry } : { name }
|
|
9473
|
+
);
|
|
9474
|
+
}
|
|
9475
|
+
function printExtractions(label, entries) {
|
|
9476
|
+
if (!entries.length) return;
|
|
9477
|
+
console.log(` ${label}:`);
|
|
9478
|
+
for (const entry of entries) {
|
|
9479
|
+
if (!isRecord3(entry)) continue;
|
|
9480
|
+
const name = stringField(entry, "name");
|
|
9481
|
+
const expression = stringField(entry, "expression");
|
|
9482
|
+
const details = recordField(entry, "details");
|
|
9483
|
+
const rawToolOutputPaths = arrayField(details, "rawToolOutputPaths", "raw_tool_output_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9484
|
+
const candidatePaths = arrayField(details, "candidatePaths", "candidate_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9485
|
+
if (!name || !expression) continue;
|
|
9486
|
+
const paths = candidatePaths.length ? candidatePaths : rawToolOutputPaths;
|
|
9487
|
+
const pathSuffix = paths.length ? ` from ${paths.join(", ")}` : "";
|
|
9488
|
+
console.log(` - ${name}: ${expression}${pathSuffix}`);
|
|
9489
|
+
}
|
|
8801
9490
|
}
|
|
8802
9491
|
function printToolCost(input) {
|
|
8803
9492
|
const { cost, billingSource, deeplineCredits, deeplineUsdPerPricingUnit } = input;
|
|
@@ -8865,6 +9554,17 @@ function samplePayload(samples, key) {
|
|
|
8865
9554
|
function commandEnvelopeFromRawResponse(rawResponse) {
|
|
8866
9555
|
return isRecord3(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
|
|
8867
9556
|
}
|
|
9557
|
+
function listExtractorPathsFromUsageGuidance(tool) {
|
|
9558
|
+
const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
|
|
9559
|
+
const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord3(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
|
|
9560
|
+
return extractedLists.flatMap((entry) => {
|
|
9561
|
+
const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
|
|
9562
|
+
if (!Array.isArray(paths)) return [];
|
|
9563
|
+
return paths.map(
|
|
9564
|
+
(path) => path.trim().replace(/^toolExecutionResult\.toolOutput\.raw\.?/, "").replace(/^\./, "")
|
|
9565
|
+
).filter(Boolean);
|
|
9566
|
+
});
|
|
9567
|
+
}
|
|
8868
9568
|
function isPlayTool(tool) {
|
|
8869
9569
|
const provider = typeof tool.provider === "string" ? tool.provider : "";
|
|
8870
9570
|
return provider === "deepline_native" && Boolean(recordField(tool, "playExpansion", "play_expansion"));
|
|
@@ -8938,6 +9638,7 @@ function parseExecuteOptions(args) {
|
|
|
8938
9638
|
const params = {};
|
|
8939
9639
|
let outputFormat = "auto";
|
|
8940
9640
|
let noPreview = false;
|
|
9641
|
+
let fullOutput = false;
|
|
8941
9642
|
for (let index = 1; index < args.length; index += 1) {
|
|
8942
9643
|
const arg = args[index];
|
|
8943
9644
|
if ((arg === "--param" || arg === "-p") && args[index + 1]) {
|
|
@@ -8964,6 +9665,7 @@ function parseExecuteOptions(args) {
|
|
|
8964
9665
|
}
|
|
8965
9666
|
if (arg === "--full-output") {
|
|
8966
9667
|
outputFormat = "json";
|
|
9668
|
+
fullOutput = true;
|
|
8967
9669
|
continue;
|
|
8968
9670
|
}
|
|
8969
9671
|
if (arg === "--no-preview") {
|
|
@@ -8972,7 +9674,7 @@ function parseExecuteOptions(args) {
|
|
|
8972
9674
|
}
|
|
8973
9675
|
throw new Error(`Unknown option: ${arg}`);
|
|
8974
9676
|
}
|
|
8975
|
-
return { toolId, params, outputFormat, noPreview };
|
|
9677
|
+
return { toolId, params, outputFormat, noPreview, fullOutput };
|
|
8976
9678
|
}
|
|
8977
9679
|
function safeFileStem(value) {
|
|
8978
9680
|
return value.trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "tool";
|
|
@@ -8986,9 +9688,9 @@ function powerShellQuote(value) {
|
|
|
8986
9688
|
function seedToolListScript(input) {
|
|
8987
9689
|
const stem = safeFileStem(input.toolId);
|
|
8988
9690
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
8989
|
-
const scriptDir = (0,
|
|
8990
|
-
(0,
|
|
8991
|
-
const scriptPath = (0,
|
|
9691
|
+
const scriptDir = (0, import_node_fs10.mkdtempSync)((0, import_node_path12.join)((0, import_node_os7.tmpdir)(), "deepline-workflow-seed-"));
|
|
9692
|
+
(0, import_node_fs10.chmodSync)(scriptDir, 448);
|
|
9693
|
+
const scriptPath = (0, import_node_path12.join)(scriptDir, fileName);
|
|
8992
9694
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
8993
9695
|
const playName = `${stem}-workflow`;
|
|
8994
9696
|
const sampleRows = input.rows.length > 0 ? `${JSON.stringify(input.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
@@ -9004,7 +9706,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9004
9706
|
description: ${JSON.stringify(`Seed ${input.toolId} rows for workflow expansion.`)},
|
|
9005
9707
|
});
|
|
9006
9708
|
|
|
9007
|
-
const list = Object.values(result.
|
|
9709
|
+
const list = Object.values(result.extractedLists)[0];
|
|
9008
9710
|
const rows = (list?.get() ?? []).slice(0, 100);
|
|
9009
9711
|
// ${sampleRows}
|
|
9010
9712
|
// columns: ${columns}
|
|
@@ -9021,7 +9723,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9021
9723
|
};
|
|
9022
9724
|
});
|
|
9023
9725
|
`;
|
|
9024
|
-
(0,
|
|
9726
|
+
(0, import_node_fs10.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
9025
9727
|
return {
|
|
9026
9728
|
path: scriptPath,
|
|
9027
9729
|
projectDir,
|
|
@@ -9032,7 +9734,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9032
9734
|
function buildToolExecuteBaseEnvelope(input) {
|
|
9033
9735
|
const envelope = commandEnvelopeFromRawResponse(input.rawResponse);
|
|
9034
9736
|
const summaryEntries = Object.entries(input.summary);
|
|
9035
|
-
const
|
|
9737
|
+
const outputPreview = input.listConversion ? {
|
|
9036
9738
|
kind: "list",
|
|
9037
9739
|
rowCount: input.listConversion.rows.length,
|
|
9038
9740
|
columns: Object.keys(input.listConversion.rows[0] ?? {}),
|
|
@@ -9043,6 +9745,7 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
9043
9745
|
kind: summaryEntries.length > 0 ? "object" : "raw",
|
|
9044
9746
|
summary: input.summary
|
|
9045
9747
|
};
|
|
9748
|
+
const envelopeHasCanonicalOutput = isRecord3(envelope.toolExecutionResult) && isRecord3(envelope.toolExecutionResult.toolOutput) && Object.prototype.hasOwnProperty.call(envelope.toolExecutionResult.toolOutput, "raw");
|
|
9046
9749
|
const actions = input.listConversion ? [
|
|
9047
9750
|
{
|
|
9048
9751
|
label: "next",
|
|
@@ -9051,7 +9754,7 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
9051
9754
|
] : [];
|
|
9052
9755
|
return {
|
|
9053
9756
|
...envelope,
|
|
9054
|
-
output,
|
|
9757
|
+
...envelopeHasCanonicalOutput ? { output_preview: outputPreview } : { output: outputPreview },
|
|
9055
9758
|
...summaryEntries.length > 0 ? { summary: input.summary } : {},
|
|
9056
9759
|
next: input.listConversion ? {
|
|
9057
9760
|
expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again."
|
|
@@ -9104,8 +9807,12 @@ async function executeTool(args) {
|
|
|
9104
9807
|
throw error;
|
|
9105
9808
|
}
|
|
9106
9809
|
const rawResponse = await client.executeTool(parsed.toolId, parsed.params);
|
|
9810
|
+
if (parsed.fullOutput) {
|
|
9811
|
+
printJson(rawResponse);
|
|
9812
|
+
return 0;
|
|
9813
|
+
}
|
|
9107
9814
|
const listConversion = tryConvertToList(rawResponse, {
|
|
9108
|
-
listExtractorPaths: metadata
|
|
9815
|
+
listExtractorPaths: listExtractorPathsFromUsageGuidance(metadata)
|
|
9109
9816
|
});
|
|
9110
9817
|
const summary = extractSummaryFields(rawResponse);
|
|
9111
9818
|
const baseEnvelope = buildToolExecuteBaseEnvelope({
|
|
@@ -9236,8 +9943,8 @@ async function executeTool(args) {
|
|
|
9236
9943
|
|
|
9237
9944
|
// src/cli/commands/update.ts
|
|
9238
9945
|
var import_node_child_process = require("child_process");
|
|
9239
|
-
var
|
|
9240
|
-
var
|
|
9946
|
+
var import_node_fs11 = require("fs");
|
|
9947
|
+
var import_node_path13 = require("path");
|
|
9241
9948
|
function posixShellQuote(value) {
|
|
9242
9949
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
9243
9950
|
}
|
|
@@ -9256,19 +9963,19 @@ function buildSourceUpdateCommand(sourceRoot) {
|
|
|
9256
9963
|
return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
|
|
9257
9964
|
}
|
|
9258
9965
|
function findRepoBackedSdkRoot(startPath) {
|
|
9259
|
-
let current = (0,
|
|
9966
|
+
let current = (0, import_node_path13.resolve)(startPath);
|
|
9260
9967
|
while (true) {
|
|
9261
|
-
if ((0,
|
|
9968
|
+
if ((0, import_node_fs11.existsSync)((0, import_node_path13.join)(current, "sdk", "package.json")) && (0, import_node_fs11.existsSync)((0, import_node_path13.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
|
|
9262
9969
|
return current;
|
|
9263
9970
|
}
|
|
9264
|
-
const parent = (0,
|
|
9971
|
+
const parent = (0, import_node_path13.dirname)(current);
|
|
9265
9972
|
if (parent === current) return null;
|
|
9266
9973
|
current = parent;
|
|
9267
9974
|
}
|
|
9268
9975
|
}
|
|
9269
9976
|
function resolveUpdatePlan() {
|
|
9270
|
-
const entrypoint = process.argv[1] ? (0,
|
|
9271
|
-
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0,
|
|
9977
|
+
const entrypoint = process.argv[1] ? (0, import_node_path13.resolve)(process.argv[1]) : "";
|
|
9978
|
+
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path13.dirname)(entrypoint)) : null;
|
|
9272
9979
|
if (sourceRoot) {
|
|
9273
9980
|
return {
|
|
9274
9981
|
kind: "source",
|
|
@@ -9361,9 +10068,9 @@ Examples:
|
|
|
9361
10068
|
|
|
9362
10069
|
// src/cli/skills-sync.ts
|
|
9363
10070
|
var import_node_child_process2 = require("child_process");
|
|
9364
|
-
var
|
|
10071
|
+
var import_node_fs12 = require("fs");
|
|
9365
10072
|
var import_node_os8 = require("os");
|
|
9366
|
-
var
|
|
10073
|
+
var import_node_path14 = require("path");
|
|
9367
10074
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
9368
10075
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
9369
10076
|
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
@@ -9374,23 +10081,59 @@ function shouldSkipSkillsSync() {
|
|
|
9374
10081
|
}
|
|
9375
10082
|
function sdkSkillsVersionPath(baseUrl) {
|
|
9376
10083
|
const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
|
|
9377
|
-
return (0,
|
|
10084
|
+
return (0, import_node_path14.join)(home, ".local", "deepline", baseUrlSlug(baseUrl), "sdk-skills", ".version");
|
|
9378
10085
|
}
|
|
9379
10086
|
function readLocalSkillsVersion(baseUrl) {
|
|
9380
10087
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
9381
|
-
if (!(0,
|
|
10088
|
+
if (!(0, import_node_fs12.existsSync)(path)) return "";
|
|
9382
10089
|
try {
|
|
9383
|
-
return (0,
|
|
10090
|
+
return (0, import_node_fs12.readFileSync)(path, "utf-8").trim();
|
|
9384
10091
|
} catch {
|
|
9385
10092
|
return "";
|
|
9386
10093
|
}
|
|
9387
10094
|
}
|
|
9388
10095
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
9389
10096
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
9390
|
-
(0,
|
|
9391
|
-
(0,
|
|
10097
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
|
|
10098
|
+
(0, import_node_fs12.writeFileSync)(path, `${version}
|
|
9392
10099
|
`, "utf-8");
|
|
9393
10100
|
}
|
|
10101
|
+
function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
10102
|
+
const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
|
|
10103
|
+
const roots = [
|
|
10104
|
+
(0, import_node_path14.join)(home, ".claude", "skills", SDK_SKILL_NAME),
|
|
10105
|
+
(0, import_node_path14.join)(home, ".agents", "skills", SDK_SKILL_NAME)
|
|
10106
|
+
];
|
|
10107
|
+
const staleMarkers = [
|
|
10108
|
+
"ctx.tools.execute(key",
|
|
10109
|
+
"ctx.tools.execute('",
|
|
10110
|
+
'ctx.tools.execute("',
|
|
10111
|
+
"rowCtx.tools.execute('",
|
|
10112
|
+
'rowCtx.tools.execute("'
|
|
10113
|
+
];
|
|
10114
|
+
const scan = (dir) => {
|
|
10115
|
+
for (const entry of (0, import_node_fs12.readdirSync)(dir)) {
|
|
10116
|
+
const path = (0, import_node_path14.join)(dir, entry);
|
|
10117
|
+
const stat3 = (0, import_node_fs12.statSync)(path);
|
|
10118
|
+
if (stat3.isDirectory()) {
|
|
10119
|
+
if (scan(path)) return true;
|
|
10120
|
+
continue;
|
|
10121
|
+
}
|
|
10122
|
+
if (!entry.endsWith(".md")) continue;
|
|
10123
|
+
const text = (0, import_node_fs12.readFileSync)(path, "utf-8");
|
|
10124
|
+
if (staleMarkers.some((marker) => text.includes(marker))) return true;
|
|
10125
|
+
}
|
|
10126
|
+
return false;
|
|
10127
|
+
};
|
|
10128
|
+
for (const root of roots) {
|
|
10129
|
+
try {
|
|
10130
|
+
if ((0, import_node_fs12.existsSync)(root) && scan(root)) return true;
|
|
10131
|
+
} catch {
|
|
10132
|
+
continue;
|
|
10133
|
+
}
|
|
10134
|
+
}
|
|
10135
|
+
return false;
|
|
10136
|
+
}
|
|
9394
10137
|
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
9395
10138
|
const controller = new AbortController();
|
|
9396
10139
|
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
@@ -9426,7 +10169,7 @@ function buildSkillsInstallArgs(baseUrl) {
|
|
|
9426
10169
|
"skills",
|
|
9427
10170
|
"add",
|
|
9428
10171
|
packageUrl,
|
|
9429
|
-
"--
|
|
10172
|
+
"--agent",
|
|
9430
10173
|
...SKILL_AGENTS,
|
|
9431
10174
|
"--global",
|
|
9432
10175
|
"--yes",
|
|
@@ -9442,7 +10185,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
|
|
|
9442
10185
|
"skills",
|
|
9443
10186
|
"add",
|
|
9444
10187
|
packageUrl,
|
|
9445
|
-
"--
|
|
10188
|
+
"--agent",
|
|
9446
10189
|
...SKILL_AGENTS,
|
|
9447
10190
|
"--global",
|
|
9448
10191
|
"--yes",
|
|
@@ -9482,7 +10225,7 @@ function resolveSkillsInstallCommands(baseUrl) {
|
|
|
9482
10225
|
return [npxInstall];
|
|
9483
10226
|
}
|
|
9484
10227
|
function runOneSkillsInstall(install) {
|
|
9485
|
-
return new Promise((
|
|
10228
|
+
return new Promise((resolve11) => {
|
|
9486
10229
|
const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
|
|
9487
10230
|
stdio: ["ignore", "ignore", "pipe"],
|
|
9488
10231
|
env: process.env
|
|
@@ -9492,7 +10235,7 @@ function runOneSkillsInstall(install) {
|
|
|
9492
10235
|
stderr += chunk.toString("utf-8");
|
|
9493
10236
|
});
|
|
9494
10237
|
child.on("error", (error) => {
|
|
9495
|
-
|
|
10238
|
+
resolve11({
|
|
9496
10239
|
ok: false,
|
|
9497
10240
|
detail: `failed to start ${install.command}: ${error.message}`,
|
|
9498
10241
|
manualCommand: install.manualCommand
|
|
@@ -9500,11 +10243,11 @@ function runOneSkillsInstall(install) {
|
|
|
9500
10243
|
});
|
|
9501
10244
|
child.on("close", (code) => {
|
|
9502
10245
|
if (code === 0) {
|
|
9503
|
-
|
|
10246
|
+
resolve11({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
9504
10247
|
return;
|
|
9505
10248
|
}
|
|
9506
10249
|
const detail = stderr.trim();
|
|
9507
|
-
|
|
10250
|
+
resolve11({
|
|
9508
10251
|
ok: false,
|
|
9509
10252
|
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
9510
10253
|
manualCommand: install.manualCommand
|
|
@@ -9543,10 +10286,19 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
9543
10286
|
attemptedSync = true;
|
|
9544
10287
|
const localVersion = readLocalSkillsVersion(baseUrl);
|
|
9545
10288
|
const update = await fetchSkillsUpdate(baseUrl, localVersion);
|
|
9546
|
-
|
|
10289
|
+
const hasStaleInstalledSkill = installedSdkSkillHasStalePositionalExecuteExamples();
|
|
10290
|
+
if (!update?.needsUpdate && !hasStaleInstalledSkill || !update?.remoteVersion) {
|
|
10291
|
+
return;
|
|
10292
|
+
}
|
|
9547
10293
|
writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-sdk skill...");
|
|
9548
10294
|
const installed = await runSkillsInstall(baseUrl);
|
|
9549
10295
|
if (!installed) return;
|
|
10296
|
+
if (installedSdkSkillHasStalePositionalExecuteExamples()) {
|
|
10297
|
+
process.stderr.write(
|
|
10298
|
+
"SDK skills sync completed, but installed deepline-sdk docs still contain stale positional ctx.tools.execute examples.\n"
|
|
10299
|
+
);
|
|
10300
|
+
return;
|
|
10301
|
+
}
|
|
9550
10302
|
writeLocalSkillsVersion(baseUrl, update.remoteVersion);
|
|
9551
10303
|
writeSdkSkillsStatusLine("SDK skills are up to date.");
|
|
9552
10304
|
}
|