deepline 0.1.33 → 0.1.36
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 +991 -219
- package/dist/cli/index.mjs +924 -152
- package/dist/index.d.mts +124 -62
- package/dist/index.d.ts +124 -62
- package/dist/index.js +522 -45
- package/dist/index.mjs +522 -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 +186 -75
- package/dist/repo/apps/play-runner-workers/src/runtime/receipts.ts +138 -0
- package/dist/repo/apps/play-runner-workers/src/workflow-retry.ts +50 -0
- package/dist/repo/sdk/src/client.ts +43 -32
- 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 +126 -45
- package/dist/repo/sdk/src/plays/harness-stub.ts +2 -2
- package/dist/repo/sdk/src/tool-output.ts +22 -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 +154 -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.36";
|
|
220
|
+
var SDK_API_CONTRACT = "2026-05-v2-tool-response";
|
|
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-response";
|
|
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 `toolResponse.raw` field contains the raw tool response.
|
|
801
|
+
* `toolResponse.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,24 @@ 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`,
|
|
6590
|
+
full: `deepline runs get ${runId} --full --json`,
|
|
6253
6591
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
6254
6592
|
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
6255
6593
|
};
|
|
6256
|
-
if (dashboardUrl) {
|
|
6257
|
-
commands.open = `Open ${dashboardUrl} to see results.`;
|
|
6594
|
+
if (status.dashboardUrl) {
|
|
6595
|
+
commands.open = `Open ${status.dashboardUrl} to see results.`;
|
|
6258
6596
|
}
|
|
6259
6597
|
return commands;
|
|
6260
6598
|
}
|
|
@@ -6277,6 +6615,121 @@ function getTimestampField(value, key) {
|
|
|
6277
6615
|
}
|
|
6278
6616
|
return typeof field === "string" && field.trim() ? field : null;
|
|
6279
6617
|
}
|
|
6618
|
+
function getObjectField(value, key) {
|
|
6619
|
+
const field = getRecordField(value, key);
|
|
6620
|
+
return field && typeof field === "object" && !Array.isArray(field) ? field : null;
|
|
6621
|
+
}
|
|
6622
|
+
function formatCreditAmount(value) {
|
|
6623
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
6624
|
+
return String(value ?? "-");
|
|
6625
|
+
}
|
|
6626
|
+
return Number(value.toFixed(8)).toString();
|
|
6627
|
+
}
|
|
6628
|
+
function extractJsonObjectFromText(text) {
|
|
6629
|
+
const start = text.indexOf("{");
|
|
6630
|
+
if (start < 0) {
|
|
6631
|
+
return null;
|
|
6632
|
+
}
|
|
6633
|
+
const suffix = text.slice(start);
|
|
6634
|
+
try {
|
|
6635
|
+
const parsed = JSON.parse(suffix);
|
|
6636
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
6637
|
+
} catch {
|
|
6638
|
+
let depth = 0;
|
|
6639
|
+
let inString = false;
|
|
6640
|
+
let escaped = false;
|
|
6641
|
+
for (let index = start; index < text.length; index += 1) {
|
|
6642
|
+
const char = text[index];
|
|
6643
|
+
if (inString) {
|
|
6644
|
+
if (escaped) {
|
|
6645
|
+
escaped = false;
|
|
6646
|
+
} else if (char === "\\") {
|
|
6647
|
+
escaped = true;
|
|
6648
|
+
} else if (char === '"') {
|
|
6649
|
+
inString = false;
|
|
6650
|
+
}
|
|
6651
|
+
continue;
|
|
6652
|
+
}
|
|
6653
|
+
if (char === '"') {
|
|
6654
|
+
inString = true;
|
|
6655
|
+
} else if (char === "{") {
|
|
6656
|
+
depth += 1;
|
|
6657
|
+
} else if (char === "}") {
|
|
6658
|
+
depth -= 1;
|
|
6659
|
+
if (depth === 0) {
|
|
6660
|
+
try {
|
|
6661
|
+
const parsed = JSON.parse(text.slice(start, index + 1));
|
|
6662
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
6663
|
+
} catch {
|
|
6664
|
+
return null;
|
|
6665
|
+
}
|
|
6666
|
+
}
|
|
6667
|
+
}
|
|
6668
|
+
}
|
|
6669
|
+
}
|
|
6670
|
+
return null;
|
|
6671
|
+
}
|
|
6672
|
+
function extractBillingFromText(text) {
|
|
6673
|
+
if (!text) {
|
|
6674
|
+
return null;
|
|
6675
|
+
}
|
|
6676
|
+
const parsed = extractJsonObjectFromText(text);
|
|
6677
|
+
return getObjectField(parsed, "billing");
|
|
6678
|
+
}
|
|
6679
|
+
function extractToolIdFromErrorText(text) {
|
|
6680
|
+
if (!text) {
|
|
6681
|
+
return null;
|
|
6682
|
+
}
|
|
6683
|
+
const lowerToolMatch = /\btool\s+([A-Za-z0-9_.:-]+)\s+\d{3}\b/.exec(text);
|
|
6684
|
+
if (lowerToolMatch?.[1]) {
|
|
6685
|
+
return lowerToolMatch[1];
|
|
6686
|
+
}
|
|
6687
|
+
const upperToolMatch = /\bTool\s+([A-Za-z0-9_.:-]+)\s+failed\b/.exec(text);
|
|
6688
|
+
return upperToolMatch?.[1] ?? null;
|
|
6689
|
+
}
|
|
6690
|
+
function isInsufficientCreditsBilling(billing) {
|
|
6691
|
+
return billing?.kind === "insufficient_credits";
|
|
6692
|
+
}
|
|
6693
|
+
function extractBillingForStatus(status, error) {
|
|
6694
|
+
const errorBilling = getObjectField(status, "errorBilling");
|
|
6695
|
+
if (errorBilling) {
|
|
6696
|
+
return errorBilling;
|
|
6697
|
+
}
|
|
6698
|
+
const directErrors = getRecordField(status, "errors");
|
|
6699
|
+
if (Array.isArray(directErrors)) {
|
|
6700
|
+
for (const entry of directErrors) {
|
|
6701
|
+
const billing = getObjectField(entry, "billing");
|
|
6702
|
+
if (billing) {
|
|
6703
|
+
return billing;
|
|
6704
|
+
}
|
|
6705
|
+
}
|
|
6706
|
+
}
|
|
6707
|
+
const progressError = getStringField(status.progress, "error");
|
|
6708
|
+
return extractBillingFromText(error) ?? extractBillingFromText(progressError) ?? getObjectField(status, "billing");
|
|
6709
|
+
}
|
|
6710
|
+
function formatInsufficientCreditsMessage(input) {
|
|
6711
|
+
const operation = getStringField(input.billing, "operation_id") ?? getStringField(input.billing, "operation") ?? extractToolIdFromErrorText(input.error) ?? getStringField(input.billing, "provider") ?? "tool call";
|
|
6712
|
+
const balance = formatCreditAmount(input.billing.balance_credits);
|
|
6713
|
+
const required = formatCreditAmount(input.billing.required_credits);
|
|
6714
|
+
const recommended = formatCreditAmount(
|
|
6715
|
+
input.billing.recommended_add_credits ?? input.billing.needed_credits
|
|
6716
|
+
);
|
|
6717
|
+
const billingUrl = getStringField(input.billing, "billing_url");
|
|
6718
|
+
const workspace = getStringField(input.billing, "workspace_id") ?? getStringField(input.billing, "workspaceId");
|
|
6719
|
+
const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
|
|
6720
|
+
const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
|
|
6721
|
+
return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
|
|
6722
|
+
}
|
|
6723
|
+
function formatPlayErrorForDisplay(status, error) {
|
|
6724
|
+
if (!error) {
|
|
6725
|
+
return null;
|
|
6726
|
+
}
|
|
6727
|
+
const billing = extractBillingForStatus(status, error);
|
|
6728
|
+
if (isInsufficientCreditsBilling(billing)) {
|
|
6729
|
+
return formatInsufficientCreditsMessage({ billing, error });
|
|
6730
|
+
}
|
|
6731
|
+
return error;
|
|
6732
|
+
}
|
|
6280
6733
|
function normalizeRunStatusForEnvelope(status) {
|
|
6281
6734
|
const run = status.run ?? null;
|
|
6282
6735
|
return {
|
|
@@ -6327,18 +6780,33 @@ function normalizeErrorsForEnvelope(status, error) {
|
|
|
6327
6780
|
if (Array.isArray(directErrors)) {
|
|
6328
6781
|
return directErrors.filter(
|
|
6329
6782
|
(entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
|
|
6330
|
-
)
|
|
6783
|
+
).map((entry) => {
|
|
6784
|
+
const message2 = typeof entry.message === "string" && entry.message.trim() ? entry.message : error;
|
|
6785
|
+
const billing2 = getObjectField(entry, "billing");
|
|
6786
|
+
if (!isInsufficientCreditsBilling(billing2) || !message2) {
|
|
6787
|
+
return entry;
|
|
6788
|
+
}
|
|
6789
|
+
return {
|
|
6790
|
+
...entry,
|
|
6791
|
+
message: formatInsufficientCreditsMessage({ billing: billing2, error: message2 }),
|
|
6792
|
+
billing: stripProviderSpendFromBilling(billing2)
|
|
6793
|
+
};
|
|
6794
|
+
});
|
|
6331
6795
|
}
|
|
6332
6796
|
if (!error) {
|
|
6333
6797
|
return [];
|
|
6334
6798
|
}
|
|
6799
|
+
const nextCommands = buildRunNextCommands(status);
|
|
6800
|
+
const billing = extractBillingForStatus(status, error);
|
|
6801
|
+
const message = formatPlayErrorForDisplay(status, error) ?? error;
|
|
6335
6802
|
return [
|
|
6336
6803
|
{
|
|
6337
6804
|
code: getStringField(status, "errorCode") ?? "RUN_FAILED",
|
|
6338
6805
|
phase: getStringField(status, "errorPhase") ?? "runtime",
|
|
6339
|
-
message
|
|
6806
|
+
message,
|
|
6340
6807
|
retryable: typeof getRecordField(status, "retryable") === "boolean" ? getRecordField(status, "retryable") : null,
|
|
6341
|
-
|
|
6808
|
+
...billing ? { billing: stripProviderSpendFromBilling(billing) } : {},
|
|
6809
|
+
nextAction: nextCommands.get ?? nextCommands.list
|
|
6342
6810
|
}
|
|
6343
6811
|
];
|
|
6344
6812
|
}
|
|
@@ -6387,6 +6855,7 @@ function compactPlayStatus(status) {
|
|
|
6387
6855
|
) : null;
|
|
6388
6856
|
const progressError = status.progress?.error;
|
|
6389
6857
|
const error = typeof progressError === "string" ? progressError : typeof status.error === "string" ? String(status.error) : null;
|
|
6858
|
+
const displayError = formatPlayErrorForDisplay(status, error);
|
|
6390
6859
|
return {
|
|
6391
6860
|
runId: status.runId,
|
|
6392
6861
|
apiVersion: status.apiVersion ?? 1,
|
|
@@ -6399,13 +6868,13 @@ function compactPlayStatus(status) {
|
|
|
6399
6868
|
steps: normalizeStepsForEnvelope(status),
|
|
6400
6869
|
errors: normalizeErrorsForEnvelope(status, error),
|
|
6401
6870
|
logs: normalizeLogsForEnvelope(status),
|
|
6402
|
-
...
|
|
6871
|
+
...displayError ? { error: displayError } : {},
|
|
6403
6872
|
...warnings.length > 0 ? { warnings } : {},
|
|
6404
6873
|
...result !== void 0 ? { result } : {},
|
|
6405
6874
|
...status.resultView ? { resultView: status.resultView } : {},
|
|
6406
6875
|
...datasetStats ? { dataset_stats: datasetStats } : {},
|
|
6407
6876
|
...billing ? { billing } : {},
|
|
6408
|
-
next: buildRunNextCommands(status
|
|
6877
|
+
next: buildRunNextCommands(status)
|
|
6409
6878
|
};
|
|
6410
6879
|
}
|
|
6411
6880
|
function enrichPlayStatusWithDatasetStats(status) {
|
|
@@ -6479,7 +6948,8 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
6479
6948
|
lines.push(...formatDatasetStatsLines(datasetStats));
|
|
6480
6949
|
const progressError = status.progress?.error;
|
|
6481
6950
|
if (progressError && typeof progressError === "string") {
|
|
6482
|
-
|
|
6951
|
+
const displayError = formatPlayErrorForDisplay(status, progressError) ?? progressError;
|
|
6952
|
+
lines.push(` error: ${displayError.slice(0, 200)}`);
|
|
6483
6953
|
}
|
|
6484
6954
|
const renderedServerView = renderServerResultView(status.resultView);
|
|
6485
6955
|
if (result) {
|
|
@@ -6503,8 +6973,11 @@ var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
|
6503
6973
|
function shellSingleQuote(value) {
|
|
6504
6974
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
6505
6975
|
}
|
|
6976
|
+
function sqlStringLiteral(value) {
|
|
6977
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
6978
|
+
}
|
|
6506
6979
|
function runExportRetryCommand(runId, outPath, datasetPath) {
|
|
6507
|
-
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0,
|
|
6980
|
+
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0, import_node_path10.resolve)(outPath))}`;
|
|
6508
6981
|
}
|
|
6509
6982
|
function extractRunPlayName(status) {
|
|
6510
6983
|
const run = status.run;
|
|
@@ -6521,6 +6994,26 @@ function extractRunPlayName(status) {
|
|
|
6521
6994
|
}
|
|
6522
6995
|
return null;
|
|
6523
6996
|
}
|
|
6997
|
+
function normalizeCustomerDbIdentifier(value) {
|
|
6998
|
+
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
6999
|
+
}
|
|
7000
|
+
function buildCustomerDbQueryPlan(input) {
|
|
7001
|
+
const playName = extractRunPlayName(input.status);
|
|
7002
|
+
const tableNamespace = input.rowsInfo.tableNamespace?.trim();
|
|
7003
|
+
if (!playName || !tableNamespace || input.rowsInfo.totalRows <= 0) {
|
|
7004
|
+
return null;
|
|
7005
|
+
}
|
|
7006
|
+
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
7007
|
+
tableNamespace
|
|
7008
|
+
)}`;
|
|
7009
|
+
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input.status.runId)} limit ${input.rowsInfo.totalRows}`;
|
|
7010
|
+
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input.rowsInfo.totalRows}`;
|
|
7011
|
+
return {
|
|
7012
|
+
sql,
|
|
7013
|
+
json: `${base} --json`,
|
|
7014
|
+
csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path10.resolve)(input.outPath))}`
|
|
7015
|
+
};
|
|
7016
|
+
}
|
|
6524
7017
|
function exportableSheetRow(row) {
|
|
6525
7018
|
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
6526
7019
|
return null;
|
|
@@ -6692,6 +7185,60 @@ async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
|
6692
7185
|
}
|
|
6693
7186
|
return { path: writeCanonicalRowsCsv(rowsInfo, outPath), rowsInfo };
|
|
6694
7187
|
}
|
|
7188
|
+
function extractActiveRunsFromError(error) {
|
|
7189
|
+
if (!(error instanceof DeeplineError)) {
|
|
7190
|
+
return [];
|
|
7191
|
+
}
|
|
7192
|
+
const response = error.details?.response;
|
|
7193
|
+
if (!response || typeof response !== "object" || Array.isArray(response)) {
|
|
7194
|
+
return [];
|
|
7195
|
+
}
|
|
7196
|
+
const details = response.details;
|
|
7197
|
+
if (!details || typeof details !== "object" || Array.isArray(details)) {
|
|
7198
|
+
return [];
|
|
7199
|
+
}
|
|
7200
|
+
const activeRuns = details.activeRuns;
|
|
7201
|
+
return Array.isArray(activeRuns) ? activeRuns.filter(
|
|
7202
|
+
(run) => Boolean(run) && typeof run === "object" && !Array.isArray(run)
|
|
7203
|
+
) : [];
|
|
7204
|
+
}
|
|
7205
|
+
function activeRunId(run) {
|
|
7206
|
+
return getStringField(run, "workflowId") ?? getStringField(run, "runId");
|
|
7207
|
+
}
|
|
7208
|
+
function formatActiveRunConflictError(input) {
|
|
7209
|
+
const lines = [
|
|
7210
|
+
`Active run exists for ${input.playName}. Use --force to supersede, or inspect/stop the active run first.`
|
|
7211
|
+
];
|
|
7212
|
+
for (const run of input.activeRuns.slice(0, 3)) {
|
|
7213
|
+
const runId = activeRunId(run);
|
|
7214
|
+
if (!runId) {
|
|
7215
|
+
continue;
|
|
7216
|
+
}
|
|
7217
|
+
const status = getStringField(run, "status");
|
|
7218
|
+
const startedAt = getStringField(run, "startedAt") ?? getStringField(run, "startTime");
|
|
7219
|
+
lines.push(
|
|
7220
|
+
` active: ${runId}${status ? ` status=${status}` : ""}${startedAt ? ` startedAt=${startedAt}` : ""}`
|
|
7221
|
+
);
|
|
7222
|
+
lines.push(` get: deepline runs get ${runId} --json`);
|
|
7223
|
+
lines.push(
|
|
7224
|
+
` stop: deepline runs stop ${runId} --reason "stale lock" --json`
|
|
7225
|
+
);
|
|
7226
|
+
}
|
|
7227
|
+
lines.push(` rerun: add --force to the same deepline plays run command`);
|
|
7228
|
+
return lines.join("\n");
|
|
7229
|
+
}
|
|
7230
|
+
function normalizePlayStartError(error, playName) {
|
|
7231
|
+
const activeRuns = extractActiveRunsFromError(error);
|
|
7232
|
+
if (activeRuns.length === 0) {
|
|
7233
|
+
return error;
|
|
7234
|
+
}
|
|
7235
|
+
return new DeeplineError(
|
|
7236
|
+
formatActiveRunConflictError({ playName, activeRuns }),
|
|
7237
|
+
error instanceof DeeplineError ? error.statusCode : 409,
|
|
7238
|
+
"ACTIVE_RUN_EXISTS",
|
|
7239
|
+
error instanceof DeeplineError ? error.details : void 0
|
|
7240
|
+
);
|
|
7241
|
+
}
|
|
6695
7242
|
function renderServerResultView(value) {
|
|
6696
7243
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6697
7244
|
return { lines: [], actions: [] };
|
|
@@ -6735,6 +7282,10 @@ function renderServerResultView(value) {
|
|
|
6735
7282
|
);
|
|
6736
7283
|
}
|
|
6737
7284
|
const tables = Array.isArray(view.tables) ? view.tables : [];
|
|
7285
|
+
const topLevelOutputTable = view.topLevelOutputTable && typeof view.topLevelOutputTable === "object" && !Array.isArray(view.topLevelOutputTable) ? view.topLevelOutputTable : null;
|
|
7286
|
+
if (typeof topLevelOutputTable?.queryCommand === "string") {
|
|
7287
|
+
lines.push(` top-level outputs: ${topLevelOutputTable.queryCommand}`);
|
|
7288
|
+
}
|
|
6738
7289
|
if (tables.length > 0) {
|
|
6739
7290
|
lines.push(" tables:");
|
|
6740
7291
|
for (const table of tables.slice(0, 6)) {
|
|
@@ -6751,6 +7302,21 @@ function renderServerResultView(value) {
|
|
|
6751
7302
|
lines.push(
|
|
6752
7303
|
` ${String(table.tableNamespace ?? "table")}${lineLabel}: ${rowLabel}${details.join(" ")}`
|
|
6753
7304
|
);
|
|
7305
|
+
if (typeof table.queryDatasetCommand === "string") {
|
|
7306
|
+
lines.push(` inspect rows: ${table.queryDatasetCommand}`);
|
|
7307
|
+
}
|
|
7308
|
+
if (table.debugHelp && typeof table.debugHelp === "object" && !Array.isArray(table.debugHelp)) {
|
|
7309
|
+
const debugHelp = table.debugHelp;
|
|
7310
|
+
const rawResultFields = Array.isArray(debugHelp.rawResultFields) ? debugHelp.rawResultFields.filter(
|
|
7311
|
+
(field) => typeof field === "string"
|
|
7312
|
+
) : [];
|
|
7313
|
+
if (rawResultFields.length > 0) {
|
|
7314
|
+
lines.push(` tool-result columns: ${rawResultFields.join(", ")}`);
|
|
7315
|
+
}
|
|
7316
|
+
}
|
|
7317
|
+
if (typeof table.slowExportAsCsvCommand === "string") {
|
|
7318
|
+
lines.push(` export rows: ${table.slowExportAsCsvCommand}`);
|
|
7319
|
+
}
|
|
6754
7320
|
}
|
|
6755
7321
|
}
|
|
6756
7322
|
return { lines: lines.length > 1 ? lines : [], actions: [] };
|
|
@@ -6776,7 +7342,8 @@ function writeStartedPlayRun(input) {
|
|
|
6776
7342
|
` get status: deepline runs get ${input.runId} --json`,
|
|
6777
7343
|
` logs: deepline runs logs ${input.runId} --json`,
|
|
6778
7344
|
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`,
|
|
6779
|
-
` result JSON: deepline runs get ${input.runId} --json
|
|
7345
|
+
` result JSON: deepline runs get ${input.runId} --json`,
|
|
7346
|
+
` full debug JSON: deepline runs get ${input.runId} --full --json`
|
|
6780
7347
|
];
|
|
6781
7348
|
if (input.dashboardUrl) {
|
|
6782
7349
|
lines.push(` play page: ${input.dashboardUrl}`);
|
|
@@ -6927,12 +7494,12 @@ function shouldUseLocalOnlyPlayCheck() {
|
|
|
6927
7494
|
async function handlePlayCheck(args) {
|
|
6928
7495
|
const options = parsePlayCheckOptions(args);
|
|
6929
7496
|
if (!isFileTarget(options.target)) {
|
|
6930
|
-
const resolved = (0,
|
|
7497
|
+
const resolved = (0, import_node_path10.resolve)(options.target);
|
|
6931
7498
|
console.error(`File not found: ${resolved}`);
|
|
6932
7499
|
return 1;
|
|
6933
7500
|
}
|
|
6934
|
-
const absolutePlayPath = (0,
|
|
6935
|
-
const sourceCode = (0,
|
|
7501
|
+
const absolutePlayPath = (0, import_node_path10.resolve)(options.target);
|
|
7502
|
+
const sourceCode = (0, import_node_fs8.readFileSync)(absolutePlayPath, "utf-8");
|
|
6936
7503
|
let graph;
|
|
6937
7504
|
try {
|
|
6938
7505
|
graph = await collectBundledPlayGraph(absolutePlayPath);
|
|
@@ -6995,12 +7562,12 @@ async function handleFileBackedRun(options) {
|
|
|
6995
7562
|
}
|
|
6996
7563
|
const client = new DeeplineClient();
|
|
6997
7564
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
6998
|
-
const absolutePlayPath = (0,
|
|
7565
|
+
const absolutePlayPath = (0, import_node_path10.resolve)(options.target.path);
|
|
6999
7566
|
progress.phase("compiling play");
|
|
7000
7567
|
const sourceCode = traceCliSync(
|
|
7001
7568
|
"cli.play_file_read_source",
|
|
7002
7569
|
{ targetKind: "file" },
|
|
7003
|
-
() => (0,
|
|
7570
|
+
() => (0, import_node_fs8.readFileSync)(absolutePlayPath, "utf-8")
|
|
7004
7571
|
);
|
|
7005
7572
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
7006
7573
|
let graph;
|
|
@@ -7081,6 +7648,8 @@ async function handleFileBackedRun(options) {
|
|
|
7081
7648
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
7082
7649
|
noOpen: options.noOpen,
|
|
7083
7650
|
progress
|
|
7651
|
+
}).catch((error) => {
|
|
7652
|
+
throw normalizePlayStartError(error, playName);
|
|
7084
7653
|
})
|
|
7085
7654
|
);
|
|
7086
7655
|
if (finalStatus.status === "completed") {
|
|
@@ -7099,7 +7668,9 @@ async function handleFileBackedRun(options) {
|
|
|
7099
7668
|
const started = await traceCliSpan(
|
|
7100
7669
|
"cli.play_start_unwatched",
|
|
7101
7670
|
{ targetKind: "file", playName },
|
|
7102
|
-
() => client.startPlayRun(startRequest)
|
|
7671
|
+
() => client.startPlayRun(startRequest).catch((error) => {
|
|
7672
|
+
throw normalizePlayStartError(error, playName);
|
|
7673
|
+
})
|
|
7103
7674
|
);
|
|
7104
7675
|
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7105
7676
|
openPlayDashboard({
|
|
@@ -7216,6 +7787,8 @@ async function handleNamedRun(options) {
|
|
|
7216
7787
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
7217
7788
|
noOpen: options.noOpen,
|
|
7218
7789
|
progress
|
|
7790
|
+
}).catch((error) => {
|
|
7791
|
+
throw normalizePlayStartError(error, playName);
|
|
7219
7792
|
})
|
|
7220
7793
|
);
|
|
7221
7794
|
if (finalStatus.status === "completed") {
|
|
@@ -7234,7 +7807,9 @@ async function handleNamedRun(options) {
|
|
|
7234
7807
|
const started = await traceCliSpan(
|
|
7235
7808
|
"cli.play_start_unwatched",
|
|
7236
7809
|
{ targetKind: "name", playName },
|
|
7237
|
-
() => client.startPlayRun(startRequest)
|
|
7810
|
+
() => client.startPlayRun(startRequest).catch((error) => {
|
|
7811
|
+
throw normalizePlayStartError(error, playName);
|
|
7812
|
+
})
|
|
7238
7813
|
);
|
|
7239
7814
|
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7240
7815
|
openPlayDashboard({
|
|
@@ -7260,19 +7835,19 @@ async function handlePlayRun(args) {
|
|
|
7260
7835
|
if (isFileTarget(options.target.path)) {
|
|
7261
7836
|
return handleFileBackedRun(options);
|
|
7262
7837
|
}
|
|
7263
|
-
const resolved = (0,
|
|
7838
|
+
const resolved = (0, import_node_path10.resolve)(options.target.path);
|
|
7264
7839
|
console.error(`File not found: ${resolved}`);
|
|
7265
|
-
const dir = (0,
|
|
7266
|
-
if ((0,
|
|
7267
|
-
const base = (0,
|
|
7840
|
+
const dir = (0, import_node_path10.dirname)(resolved);
|
|
7841
|
+
if ((0, import_node_fs8.existsSync)(dir)) {
|
|
7842
|
+
const base = (0, import_node_path10.basename)(resolved);
|
|
7268
7843
|
try {
|
|
7269
|
-
const siblings = (0,
|
|
7844
|
+
const siblings = (0, import_node_fs8.readdirSync)(dir).filter(
|
|
7270
7845
|
(f) => f.includes(base.replace(/\.(play\.)?ts$/, "")) || f.endsWith(".play.ts")
|
|
7271
7846
|
);
|
|
7272
7847
|
if (siblings.length > 0) {
|
|
7273
7848
|
console.error(`Did you mean one of these?`);
|
|
7274
7849
|
for (const s of siblings.slice(0, 5)) {
|
|
7275
|
-
console.error(` ${(0,
|
|
7850
|
+
console.error(` ${(0, import_node_path10.join)(dir, s)}`);
|
|
7276
7851
|
}
|
|
7277
7852
|
}
|
|
7278
7853
|
} catch {
|
|
@@ -7407,14 +7982,14 @@ async function handleRunLogs(args) {
|
|
|
7407
7982
|
continue;
|
|
7408
7983
|
}
|
|
7409
7984
|
if (arg === "--out" && args[index + 1]) {
|
|
7410
|
-
outPath = (0,
|
|
7985
|
+
outPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7411
7986
|
}
|
|
7412
7987
|
}
|
|
7413
7988
|
const client = new DeeplineClient();
|
|
7414
7989
|
const status = await client.runs.get(runId);
|
|
7415
7990
|
const logs = status.progress?.logs ?? [];
|
|
7416
7991
|
if (outPath) {
|
|
7417
|
-
(0,
|
|
7992
|
+
(0, import_node_fs8.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
7418
7993
|
printCommandEnvelope({
|
|
7419
7994
|
runId: status.runId,
|
|
7420
7995
|
log_path: outPath,
|
|
@@ -7470,7 +8045,7 @@ async function handleRunStop(args) {
|
|
|
7470
8045
|
return 0;
|
|
7471
8046
|
}
|
|
7472
8047
|
async function handleRunExport(args) {
|
|
7473
|
-
const usage = "Usage: deepline runs export <run-id> [--dataset result.rows] --out output.csv [--json]";
|
|
8048
|
+
const usage = "Usage: deepline runs export <run-id> [--dataset result.rows] --out output.csv [--metadata-out export.json] [--json]";
|
|
7474
8049
|
let runId;
|
|
7475
8050
|
try {
|
|
7476
8051
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -7480,14 +8055,19 @@ async function handleRunExport(args) {
|
|
|
7480
8055
|
}
|
|
7481
8056
|
let outPath = null;
|
|
7482
8057
|
let datasetPath = null;
|
|
8058
|
+
let metadataOutPath = null;
|
|
7483
8059
|
for (let index = 0; index < args.length; index += 1) {
|
|
7484
8060
|
const arg = args[index];
|
|
7485
8061
|
if (arg === "--out" && args[index + 1]) {
|
|
7486
|
-
outPath = (0,
|
|
8062
|
+
outPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7487
8063
|
continue;
|
|
7488
8064
|
}
|
|
7489
8065
|
if (arg === "--dataset" && args[index + 1]) {
|
|
7490
8066
|
datasetPath = args[++index];
|
|
8067
|
+
continue;
|
|
8068
|
+
}
|
|
8069
|
+
if (arg === "--metadata-out" && args[index + 1]) {
|
|
8070
|
+
metadataOutPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7491
8071
|
}
|
|
7492
8072
|
}
|
|
7493
8073
|
if (!outPath) {
|
|
@@ -7499,15 +8079,59 @@ async function handleRunExport(args) {
|
|
|
7499
8079
|
const exportResult = await exportPlayStatusRows(client, status, outPath, {
|
|
7500
8080
|
datasetPath
|
|
7501
8081
|
});
|
|
7502
|
-
|
|
8082
|
+
const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
|
|
8083
|
+
const queryPlan = exportResult && outPath ? buildCustomerDbQueryPlan({
|
|
8084
|
+
status,
|
|
8085
|
+
rowsInfo: exportResult.rowsInfo,
|
|
8086
|
+
outPath
|
|
8087
|
+
}) : null;
|
|
8088
|
+
const next = {
|
|
8089
|
+
...buildRunNextCommands(status),
|
|
8090
|
+
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source),
|
|
8091
|
+
...queryPlan ? {
|
|
8092
|
+
queryJson: queryPlan.json,
|
|
8093
|
+
queryCsv: queryPlan.csv
|
|
8094
|
+
} : {}
|
|
8095
|
+
};
|
|
8096
|
+
const payload = {
|
|
7503
8097
|
runId: status.runId,
|
|
7504
8098
|
...datasetPath ? { dataset: datasetPath } : {},
|
|
7505
8099
|
csv_path: exportResult?.path ?? null,
|
|
8100
|
+
source,
|
|
7506
8101
|
rowCount: exportResult?.rowsInfo.totalRows ?? null,
|
|
7507
8102
|
columns: exportResult?.rowsInfo.columns ?? [],
|
|
8103
|
+
...queryPlan ? {
|
|
8104
|
+
query: {
|
|
8105
|
+
sql: queryPlan.sql,
|
|
8106
|
+
json: queryPlan.json,
|
|
8107
|
+
csv: queryPlan.csv
|
|
8108
|
+
}
|
|
8109
|
+
} : {},
|
|
8110
|
+
...metadataOutPath ? { metadata_path: metadataOutPath } : {},
|
|
7508
8111
|
local: { csv_path: exportResult?.path ?? null },
|
|
7509
|
-
|
|
7510
|
-
|
|
8112
|
+
next,
|
|
8113
|
+
render: {
|
|
8114
|
+
sections: [
|
|
8115
|
+
{
|
|
8116
|
+
title: "run export",
|
|
8117
|
+
lines: [
|
|
8118
|
+
`Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
|
|
8119
|
+
...source ? [`source=${source}`] : [],
|
|
8120
|
+
...queryPlan ? [`query=${queryPlan.json}`] : []
|
|
8121
|
+
]
|
|
8122
|
+
}
|
|
8123
|
+
]
|
|
8124
|
+
}
|
|
8125
|
+
};
|
|
8126
|
+
if (metadataOutPath) {
|
|
8127
|
+
(0, import_node_fs8.writeFileSync)(
|
|
8128
|
+
metadataOutPath,
|
|
8129
|
+
`${JSON.stringify(payload, null, 2)}
|
|
8130
|
+
`,
|
|
8131
|
+
"utf-8"
|
|
8132
|
+
);
|
|
8133
|
+
}
|
|
8134
|
+
printCommandEnvelope(payload, { json: argsWantJson(args) });
|
|
7511
8135
|
return 0;
|
|
7512
8136
|
}
|
|
7513
8137
|
async function handlePlayGet(args) {
|
|
@@ -7524,10 +8148,10 @@ async function handlePlayGet(args) {
|
|
|
7524
8148
|
for (let index = 1; index < args.length; index += 1) {
|
|
7525
8149
|
const arg = args[index];
|
|
7526
8150
|
if (arg === "--out" && args[index + 1]) {
|
|
7527
|
-
outPath = (0,
|
|
8151
|
+
outPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7528
8152
|
}
|
|
7529
8153
|
}
|
|
7530
|
-
const playName = isFileTarget(target) ? extractPlayName((0,
|
|
8154
|
+
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
8155
|
const detail = isFileTarget(target) ? await client.getPlay(playName) : await assertCanonicalNamedPlayReference(client, target);
|
|
7532
8156
|
const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
|
|
7533
8157
|
const materializedFile = outPath ? materializeRemotePlaySource({
|
|
@@ -7819,7 +8443,7 @@ async function handlePlayPublish(args) {
|
|
|
7819
8443
|
}
|
|
7820
8444
|
let graph;
|
|
7821
8445
|
try {
|
|
7822
|
-
graph = await collectBundledPlayGraph((0,
|
|
8446
|
+
graph = await collectBundledPlayGraph((0, import_node_path10.resolve)(playName));
|
|
7823
8447
|
await compileBundledPlayGraphManifests(client, graph);
|
|
7824
8448
|
await publishImportedPlayDependencies(client, graph);
|
|
7825
8449
|
} catch (error) {
|
|
@@ -8305,32 +8929,36 @@ Examples:
|
|
|
8305
8929
|
Notes:
|
|
8306
8930
|
Writes a returned dataset handle to the requested local CSV path. Use runs get
|
|
8307
8931
|
first to inspect dataset paths like result.rows or result.nested.contacts.
|
|
8932
|
+
--metadata-out writes the same export metadata object returned by --json,
|
|
8933
|
+
including source and follow-on customer-db query commands when available.
|
|
8308
8934
|
|
|
8309
8935
|
Examples:
|
|
8310
8936
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
8311
8937
|
deepline runs export play/my-play/run/20260501t000000-000 --dataset result.rows --out output.csv
|
|
8938
|
+
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --metadata-out output.meta.json
|
|
8312
8939
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --json
|
|
8313
8940
|
`
|
|
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) => {
|
|
8941
|
+
).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
8942
|
process.exitCode = await handleRunExport([
|
|
8316
8943
|
runId,
|
|
8317
8944
|
...options.dataset ? ["--dataset", options.dataset] : [],
|
|
8318
8945
|
"--out",
|
|
8319
8946
|
options.out,
|
|
8947
|
+
...options.metadataOut ? ["--metadata-out", options.metadataOut] : [],
|
|
8320
8948
|
...options.json ? ["--json"] : []
|
|
8321
8949
|
]);
|
|
8322
8950
|
});
|
|
8323
8951
|
}
|
|
8324
8952
|
|
|
8325
8953
|
// src/cli/commands/tools.ts
|
|
8326
|
-
var
|
|
8954
|
+
var import_node_fs10 = require("fs");
|
|
8327
8955
|
var import_node_os7 = require("os");
|
|
8328
|
-
var
|
|
8956
|
+
var import_node_path12 = require("path");
|
|
8329
8957
|
|
|
8330
8958
|
// src/tool-output.ts
|
|
8331
|
-
var
|
|
8959
|
+
var import_node_fs9 = require("fs");
|
|
8332
8960
|
var import_node_os6 = require("os");
|
|
8333
|
-
var
|
|
8961
|
+
var import_node_path11 = require("path");
|
|
8334
8962
|
function isPlainObject(value) {
|
|
8335
8963
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
8336
8964
|
}
|
|
@@ -8353,6 +8981,21 @@ function normalizeRows(value) {
|
|
|
8353
8981
|
}
|
|
8354
8982
|
function candidateRoots(payload) {
|
|
8355
8983
|
const roots = [{ path: null, value: payload }];
|
|
8984
|
+
if (isPlainObject(payload) && isPlainObject(payload.toolResponse)) {
|
|
8985
|
+
roots.push({ path: "toolResponse", value: payload.toolResponse });
|
|
8986
|
+
if (Object.prototype.hasOwnProperty.call(payload.toolResponse, "raw")) {
|
|
8987
|
+
roots.push({
|
|
8988
|
+
path: "toolResponse.raw",
|
|
8989
|
+
value: payload.toolResponse.raw
|
|
8990
|
+
});
|
|
8991
|
+
}
|
|
8992
|
+
}
|
|
8993
|
+
if (isPlainObject(payload) && isPlainObject(payload.output)) {
|
|
8994
|
+
roots.push({ path: "output", value: payload.output });
|
|
8995
|
+
if (Object.prototype.hasOwnProperty.call(payload.output, "body")) {
|
|
8996
|
+
roots.push({ path: "output.body", value: payload.output.body });
|
|
8997
|
+
}
|
|
8998
|
+
}
|
|
8356
8999
|
if (isPlainObject(payload) && isPlainObject(payload.result)) {
|
|
8357
9000
|
roots.push({ path: "result", value: payload.result });
|
|
8358
9001
|
if (isPlainObject(payload.result.data)) {
|
|
@@ -8405,19 +9048,19 @@ function tryConvertToList(payload, options) {
|
|
|
8405
9048
|
return null;
|
|
8406
9049
|
}
|
|
8407
9050
|
function ensureOutputDir() {
|
|
8408
|
-
const outputDir = (0,
|
|
8409
|
-
(0,
|
|
9051
|
+
const outputDir = (0, import_node_path11.join)((0, import_node_os6.homedir)(), ".local", "share", "deepline", "data");
|
|
9052
|
+
(0, import_node_fs9.mkdirSync)(outputDir, { recursive: true });
|
|
8410
9053
|
return outputDir;
|
|
8411
9054
|
}
|
|
8412
9055
|
function writeJsonOutputFile(payload, stem) {
|
|
8413
9056
|
const outputDir = ensureOutputDir();
|
|
8414
|
-
const outputPath = (0,
|
|
8415
|
-
(0,
|
|
9057
|
+
const outputPath = (0, import_node_path11.join)(outputDir, `${stem}_${Date.now()}.json`);
|
|
9058
|
+
(0, import_node_fs9.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
8416
9059
|
return outputPath;
|
|
8417
9060
|
}
|
|
8418
9061
|
function writeCsvOutputFile(rows, stem) {
|
|
8419
9062
|
const outputDir = ensureOutputDir();
|
|
8420
|
-
const outputPath = (0,
|
|
9063
|
+
const outputPath = (0, import_node_path11.join)(outputDir, `${stem}_${Date.now()}.csv`);
|
|
8421
9064
|
const seen = /* @__PURE__ */ new Set();
|
|
8422
9065
|
const columns = [];
|
|
8423
9066
|
for (const row of rows) {
|
|
@@ -8440,7 +9083,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
8440
9083
|
for (const row of rows) {
|
|
8441
9084
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
8442
9085
|
}
|
|
8443
|
-
(0,
|
|
9086
|
+
(0, import_node_fs9.writeFileSync)(outputPath, `${lines.join("\n")}
|
|
8444
9087
|
`, "utf-8");
|
|
8445
9088
|
const previewRows = rows.slice(0, 5);
|
|
8446
9089
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -8486,8 +9129,7 @@ async function listTools(args) {
|
|
|
8486
9129
|
title: `${items.length} tools available:`,
|
|
8487
9130
|
lines: items.flatMap((item) => {
|
|
8488
9131
|
const cats = item.categories.length ? ` [${item.categories.join(", ")}]` : "";
|
|
8489
|
-
|
|
8490
|
-
return [`${item.toolId}${cats}`, ` ${item.description}${listHint}`];
|
|
9132
|
+
return [`${item.toolId}${cats}`, ` ${item.description}`];
|
|
8491
9133
|
})
|
|
8492
9134
|
}
|
|
8493
9135
|
]
|
|
@@ -8566,7 +9208,7 @@ Common commands:
|
|
|
8566
9208
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
8567
9209
|
|
|
8568
9210
|
Output:
|
|
8569
|
-
Use describe for tool contracts.
|
|
9211
|
+
Use describe for tool contracts.
|
|
8570
9212
|
Use execute to run a tool. run is accepted as a compatibility alias.
|
|
8571
9213
|
`
|
|
8572
9214
|
);
|
|
@@ -8613,8 +9255,8 @@ Examples:
|
|
|
8613
9255
|
`
|
|
8614
9256
|
Notes:
|
|
8615
9257
|
Shows the tool contract, input schema, output schema, Deepline cost, aliases,
|
|
8616
|
-
and metadata. describe is the
|
|
8617
|
-
|
|
9258
|
+
and metadata. describe is the supported discovery verb. get is removed in
|
|
9259
|
+
the V2 SDK CLI; use describe for the same metadata surface.
|
|
8618
9260
|
|
|
8619
9261
|
Examples:
|
|
8620
9262
|
deepline tools describe hunter_email_verifier
|
|
@@ -8627,7 +9269,22 @@ Examples:
|
|
|
8627
9269
|
...options.json ? ["--json"] : []
|
|
8628
9270
|
]);
|
|
8629
9271
|
});
|
|
8630
|
-
addToolMetadataCommand(tools.command("describe <toolId>")
|
|
9272
|
+
addToolMetadataCommand(tools.command("describe <toolId>"));
|
|
9273
|
+
tools.command("get <toolId>").description("Deprecated. Use tools describe.").addHelpText(
|
|
9274
|
+
"after",
|
|
9275
|
+
`
|
|
9276
|
+
Examples:
|
|
9277
|
+
deepline tools describe hunter_email_verifier --json
|
|
9278
|
+
`
|
|
9279
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (toolId, options) => {
|
|
9280
|
+
const message = `tools get has been removed from the V2 SDK CLI. Use: deepline tools describe ${toolId} --json`;
|
|
9281
|
+
if (options.json || shouldEmitJson()) {
|
|
9282
|
+
printJsonError({ message, code: "TOOLS_GET_REMOVED" });
|
|
9283
|
+
} else {
|
|
9284
|
+
console.error(message);
|
|
9285
|
+
}
|
|
9286
|
+
process.exitCode = 2;
|
|
9287
|
+
});
|
|
8631
9288
|
tools.command("execute <toolId>").alias("run").description("Execute a tool by id.").addHelpText(
|
|
8632
9289
|
"after",
|
|
8633
9290
|
`
|
|
@@ -8636,7 +9293,7 @@ Notes:
|
|
|
8636
9293
|
waterfalls, row maps, checkpoints, and retries.
|
|
8637
9294
|
execute is the canonical execution verb. run is a compatibility alias.
|
|
8638
9295
|
Calling a provider-backed tool can spend Deepline credits. Use --json for the
|
|
8639
|
-
stable result payload
|
|
9296
|
+
stable result payload plus output preview and debugging helpers.
|
|
8640
9297
|
|
|
8641
9298
|
Examples:
|
|
8642
9299
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
@@ -8649,7 +9306,7 @@ Examples:
|
|
|
8649
9306
|
}, []).option("--json [payload]", "Emit JSON output. Use `--input` or `--payload` for passing JSON params.").option("--input <payload>", "Merge a JSON object into the tool params").option("--payload <payload>", "Merge a JSON object into the tool params").option(
|
|
8650
9307
|
"--output-format <format>",
|
|
8651
9308
|
"Output format: auto, csv, csv_file, json, or json_file"
|
|
8652
|
-
).option("--
|
|
9309
|
+
).option("--no-preview", "Only print the extracted output path when applicable").action(async (toolId, options) => {
|
|
8653
9310
|
const args = [
|
|
8654
9311
|
toolId,
|
|
8655
9312
|
...options.param.flatMap((value) => ["--param", value]),
|
|
@@ -8658,7 +9315,6 @@ Examples:
|
|
|
8658
9315
|
...options.input ? ["--input", options.input] : [],
|
|
8659
9316
|
...options.payload ? ["--payload", options.payload] : [],
|
|
8660
9317
|
...options.outputFormat ? ["--output-format", options.outputFormat] : [],
|
|
8661
|
-
...options.fullOutput ? ["--full-output"] : [],
|
|
8662
9318
|
...options.preview === false ? ["--no-preview"] : []
|
|
8663
9319
|
];
|
|
8664
9320
|
process.exitCode = await executeTool(args);
|
|
@@ -8683,13 +9339,29 @@ async function getTool(args) {
|
|
|
8683
9339
|
throw error;
|
|
8684
9340
|
}
|
|
8685
9341
|
if (argsWantJson(args)) {
|
|
8686
|
-
process.stdout.write(`${JSON.stringify(tool)}
|
|
9342
|
+
process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
|
|
8687
9343
|
`);
|
|
8688
9344
|
return 0;
|
|
8689
9345
|
}
|
|
8690
9346
|
printToolDetails(tool, toolId);
|
|
8691
9347
|
return 0;
|
|
8692
9348
|
}
|
|
9349
|
+
function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
9350
|
+
const toolId = String(tool.toolId || requestedToolId);
|
|
9351
|
+
return {
|
|
9352
|
+
...tool,
|
|
9353
|
+
toolId,
|
|
9354
|
+
provider: tool.provider,
|
|
9355
|
+
displayName: tool.displayName,
|
|
9356
|
+
runtimeOutputHelp: {
|
|
9357
|
+
contract: "tools describe shows the declared schema and semantic getters; it is not an observed provider response.",
|
|
9358
|
+
observeActualShape: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
9359
|
+
observedOutput: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
9360
|
+
forPlayGetterBugs: "Run the play, then inspect the emitted table commands from runs get. Use deepline db query against the run tables before editing getters.",
|
|
9361
|
+
executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run tables."
|
|
9362
|
+
}
|
|
9363
|
+
};
|
|
9364
|
+
}
|
|
8693
9365
|
function printToolDetails(tool, requestedToolId) {
|
|
8694
9366
|
const toolId = String(tool.toolId || requestedToolId);
|
|
8695
9367
|
const operation = typeof tool.operation === "string" ? tool.operation : "";
|
|
@@ -8708,7 +9380,12 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8708
9380
|
const stepContributions = arrayField(tool, "stepContributions", "step_contributions");
|
|
8709
9381
|
const playExpansion = recordField(tool, "playExpansion", "play_expansion");
|
|
8710
9382
|
const samples = recordField(tool, "samples");
|
|
9383
|
+
const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
|
|
8711
9384
|
console.log(`Tool: ${toolId}`);
|
|
9385
|
+
console.log(" Runtime output help:");
|
|
9386
|
+
console.log(" describe shows declared schema/getters, not an observed provider response");
|
|
9387
|
+
console.log(` observe actual shape: deepline tools execute ${toolId} --input '{...}' --json`);
|
|
9388
|
+
console.log(" for play getter bugs: run the play, then use the db query commands printed by runs get");
|
|
8712
9389
|
if (displayName) {
|
|
8713
9390
|
console.log(" Display name:");
|
|
8714
9391
|
console.log(` ${displayName}`);
|
|
@@ -8771,14 +9448,16 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8771
9448
|
console.log(" Tip: pass --payload with a JSON object.");
|
|
8772
9449
|
}
|
|
8773
9450
|
printSamples(samples);
|
|
9451
|
+
printUsageGuidance(usageGuidance);
|
|
8774
9452
|
if (isPlayTool(tool)) {
|
|
8775
9453
|
console.log(" Play contract:");
|
|
8776
9454
|
console.log(" - This is a deepline-native waterfall; the returned rows are extracted by target getters, not by hand-authored payload shape.");
|
|
8777
9455
|
if (playExpansion && typeof playExpansion.group === "string" && playExpansion.group.trim()) {
|
|
8778
9456
|
console.log(` - Output alias/runtime group is: ${playExpansion.group.trim()}`);
|
|
8779
9457
|
}
|
|
8780
|
-
const
|
|
8781
|
-
const
|
|
9458
|
+
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult");
|
|
9459
|
+
const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9460
|
+
const targets = extractedValues.map((entry) => isRecord3(entry) && typeof entry.name === "string" ? entry.name : "").filter(Boolean).sort();
|
|
8782
9461
|
if (targets.length) {
|
|
8783
9462
|
console.log(` - Built-in extract targets: ${targets.join(", ")}`);
|
|
8784
9463
|
}
|
|
@@ -8797,7 +9476,39 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8797
9476
|
} else {
|
|
8798
9477
|
console.log(` deepline tools execute ${toolId} --payload '{...}'`);
|
|
8799
9478
|
}
|
|
8800
|
-
console.log(" deepline tools
|
|
9479
|
+
console.log(" deepline tools describe <tool_id> --json");
|
|
9480
|
+
}
|
|
9481
|
+
function printUsageGuidance(usageGuidance) {
|
|
9482
|
+
if (Object.keys(usageGuidance).length === 0) return;
|
|
9483
|
+
const execute = stringField(usageGuidance, "execute");
|
|
9484
|
+
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
|
|
9485
|
+
const toolResponse = recordField(toolExecutionResult, "toolResponse", "tool_response");
|
|
9486
|
+
const extractedLists = arrayField(toolExecutionResult, "extractedLists", "extracted_lists");
|
|
9487
|
+
const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9488
|
+
console.log(" Usage guidance:");
|
|
9489
|
+
if (execute) console.log(` ${execute}`);
|
|
9490
|
+
const raw = stringField(toolResponse, "raw");
|
|
9491
|
+
const meta = stringField(toolResponse, "meta");
|
|
9492
|
+
if (raw) console.log(` Raw tool response: ${raw}`);
|
|
9493
|
+
if (meta) console.log(` Tool response metadata: ${meta}`);
|
|
9494
|
+
printExtractions("Extracted lists", extractedLists);
|
|
9495
|
+
printExtractions("Extracted values", extractedValues);
|
|
9496
|
+
}
|
|
9497
|
+
function printExtractions(label, entries) {
|
|
9498
|
+
if (!entries.length) return;
|
|
9499
|
+
console.log(` ${label}:`);
|
|
9500
|
+
for (const entry of entries) {
|
|
9501
|
+
if (!isRecord3(entry)) continue;
|
|
9502
|
+
const name = stringField(entry, "name");
|
|
9503
|
+
const expression = stringField(entry, "expression");
|
|
9504
|
+
const details = recordField(entry, "details");
|
|
9505
|
+
const rawToolOutputPaths = arrayField(details, "rawToolOutputPaths", "raw_tool_output_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9506
|
+
const candidatePaths = arrayField(details, "candidatePaths", "candidate_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9507
|
+
if (!name || !expression) continue;
|
|
9508
|
+
const paths = candidatePaths.length ? candidatePaths : rawToolOutputPaths;
|
|
9509
|
+
const pathSuffix = paths.length ? ` from ${paths.join(", ")}` : "";
|
|
9510
|
+
console.log(` - ${name}: ${expression}${pathSuffix}`);
|
|
9511
|
+
}
|
|
8801
9512
|
}
|
|
8802
9513
|
function printToolCost(input) {
|
|
8803
9514
|
const { cost, billingSource, deeplineCredits, deeplineUsdPerPricingUnit } = input;
|
|
@@ -8865,6 +9576,17 @@ function samplePayload(samples, key) {
|
|
|
8865
9576
|
function commandEnvelopeFromRawResponse(rawResponse) {
|
|
8866
9577
|
return isRecord3(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
|
|
8867
9578
|
}
|
|
9579
|
+
function listExtractorPathsFromUsageGuidance(tool) {
|
|
9580
|
+
const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
|
|
9581
|
+
const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord3(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
|
|
9582
|
+
return extractedLists.flatMap((entry) => {
|
|
9583
|
+
const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
|
|
9584
|
+
if (!Array.isArray(paths)) return [];
|
|
9585
|
+
return paths.map(
|
|
9586
|
+
(path) => path.trim().replace(/^toolExecutionResult\.toolResponse\.raw\.?/, "").replace(/^toolExecutionResult\.toolOutput\.raw\.?/, "").replace(/^\./, "")
|
|
9587
|
+
).filter(Boolean);
|
|
9588
|
+
});
|
|
9589
|
+
}
|
|
8868
9590
|
function isPlayTool(tool) {
|
|
8869
9591
|
const provider = typeof tool.provider === "string" ? tool.provider : "";
|
|
8870
9592
|
return provider === "deepline_native" && Boolean(recordField(tool, "playExpansion", "play_expansion"));
|
|
@@ -8933,7 +9655,7 @@ function normalizeOutputFormat(raw) {
|
|
|
8933
9655
|
function parseExecuteOptions(args) {
|
|
8934
9656
|
const toolId = args[0];
|
|
8935
9657
|
if (!toolId) {
|
|
8936
|
-
throw new Error(`Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--
|
|
9658
|
+
throw new Error(`Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--no-preview]`);
|
|
8937
9659
|
}
|
|
8938
9660
|
const params = {};
|
|
8939
9661
|
let outputFormat = "auto";
|
|
@@ -8962,10 +9684,6 @@ function parseExecuteOptions(args) {
|
|
|
8962
9684
|
outputFormat = normalizeOutputFormat(args[++index]);
|
|
8963
9685
|
continue;
|
|
8964
9686
|
}
|
|
8965
|
-
if (arg === "--full-output") {
|
|
8966
|
-
outputFormat = "json";
|
|
8967
|
-
continue;
|
|
8968
|
-
}
|
|
8969
9687
|
if (arg === "--no-preview") {
|
|
8970
9688
|
noPreview = true;
|
|
8971
9689
|
continue;
|
|
@@ -8986,9 +9704,9 @@ function powerShellQuote(value) {
|
|
|
8986
9704
|
function seedToolListScript(input) {
|
|
8987
9705
|
const stem = safeFileStem(input.toolId);
|
|
8988
9706
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
8989
|
-
const scriptDir = (0,
|
|
8990
|
-
(0,
|
|
8991
|
-
const scriptPath = (0,
|
|
9707
|
+
const scriptDir = (0, import_node_fs10.mkdtempSync)((0, import_node_path12.join)((0, import_node_os7.tmpdir)(), "deepline-workflow-seed-"));
|
|
9708
|
+
(0, import_node_fs10.chmodSync)(scriptDir, 448);
|
|
9709
|
+
const scriptPath = (0, import_node_path12.join)(scriptDir, fileName);
|
|
8992
9710
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
8993
9711
|
const playName = `${stem}-workflow`;
|
|
8994
9712
|
const sampleRows = input.rows.length > 0 ? `${JSON.stringify(input.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
@@ -9004,7 +9722,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9004
9722
|
description: ${JSON.stringify(`Seed ${input.toolId} rows for workflow expansion.`)},
|
|
9005
9723
|
});
|
|
9006
9724
|
|
|
9007
|
-
const list = Object.values(result.
|
|
9725
|
+
const list = Object.values(result.extractedLists)[0];
|
|
9008
9726
|
const rows = (list?.get() ?? []).slice(0, 100);
|
|
9009
9727
|
// ${sampleRows}
|
|
9010
9728
|
// columns: ${columns}
|
|
@@ -9021,7 +9739,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9021
9739
|
};
|
|
9022
9740
|
});
|
|
9023
9741
|
`;
|
|
9024
|
-
(0,
|
|
9742
|
+
(0, import_node_fs10.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
9025
9743
|
return {
|
|
9026
9744
|
path: scriptPath,
|
|
9027
9745
|
projectDir,
|
|
@@ -9032,7 +9750,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9032
9750
|
function buildToolExecuteBaseEnvelope(input) {
|
|
9033
9751
|
const envelope = commandEnvelopeFromRawResponse(input.rawResponse);
|
|
9034
9752
|
const summaryEntries = Object.entries(input.summary);
|
|
9035
|
-
const
|
|
9753
|
+
const outputPreview = input.listConversion ? {
|
|
9036
9754
|
kind: "list",
|
|
9037
9755
|
rowCount: input.listConversion.rows.length,
|
|
9038
9756
|
columns: Object.keys(input.listConversion.rows[0] ?? {}),
|
|
@@ -9043,6 +9761,8 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
9043
9761
|
kind: summaryEntries.length > 0 ? "object" : "raw",
|
|
9044
9762
|
summary: input.summary
|
|
9045
9763
|
};
|
|
9764
|
+
const envelopeHasCanonicalOutput = isRecord3(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
|
|
9765
|
+
const inspectCommand = `deepline tools execute ${input.toolId} --input ${shellQuote(JSON.stringify(input.params))} --json`;
|
|
9046
9766
|
const actions = input.listConversion ? [
|
|
9047
9767
|
{
|
|
9048
9768
|
label: "next",
|
|
@@ -9051,17 +9771,23 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
9051
9771
|
] : [];
|
|
9052
9772
|
return {
|
|
9053
9773
|
...envelope,
|
|
9054
|
-
output,
|
|
9774
|
+
...envelopeHasCanonicalOutput ? { output_preview: outputPreview } : { output: outputPreview },
|
|
9055
9775
|
...summaryEntries.length > 0 ? { summary: input.summary } : {},
|
|
9056
|
-
next:
|
|
9057
|
-
|
|
9058
|
-
|
|
9776
|
+
next: {
|
|
9777
|
+
inspect: inspectCommand,
|
|
9778
|
+
playDebugging: "When fixing a play getter, inspect the actual play run table with runs get / inspect rows; do not copy CLI preview paths blindly.",
|
|
9779
|
+
...input.listConversion ? {
|
|
9780
|
+
expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again.",
|
|
9781
|
+
listSourcePath: input.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
|
|
9782
|
+
} : {}
|
|
9783
|
+
},
|
|
9059
9784
|
render: {
|
|
9060
9785
|
sections: input.listConversion ? [
|
|
9061
9786
|
{
|
|
9062
9787
|
title: "output",
|
|
9063
9788
|
lines: [
|
|
9064
9789
|
`${input.listConversion.rows.length} row(s) extracted from ${input.listConversion.sourcePath ?? "auto-detected list"}`,
|
|
9790
|
+
"paths above are observed from this execute response; use run table rows to debug play getters",
|
|
9065
9791
|
`columns: ${JSON.stringify(Object.keys(input.listConversion.rows[0] ?? {}))}`,
|
|
9066
9792
|
`preview: ${JSON.stringify(input.listConversion.rows.slice(0, 5))}`
|
|
9067
9793
|
]
|
|
@@ -9105,11 +9831,12 @@ async function executeTool(args) {
|
|
|
9105
9831
|
}
|
|
9106
9832
|
const rawResponse = await client.executeTool(parsed.toolId, parsed.params);
|
|
9107
9833
|
const listConversion = tryConvertToList(rawResponse, {
|
|
9108
|
-
listExtractorPaths: metadata
|
|
9834
|
+
listExtractorPaths: listExtractorPathsFromUsageGuidance(metadata)
|
|
9109
9835
|
});
|
|
9110
9836
|
const summary = extractSummaryFields(rawResponse);
|
|
9111
9837
|
const baseEnvelope = buildToolExecuteBaseEnvelope({
|
|
9112
9838
|
toolId: parsed.toolId,
|
|
9839
|
+
params: parsed.params,
|
|
9113
9840
|
rawResponse,
|
|
9114
9841
|
listConversion,
|
|
9115
9842
|
summary
|
|
@@ -9236,8 +9963,8 @@ async function executeTool(args) {
|
|
|
9236
9963
|
|
|
9237
9964
|
// src/cli/commands/update.ts
|
|
9238
9965
|
var import_node_child_process = require("child_process");
|
|
9239
|
-
var
|
|
9240
|
-
var
|
|
9966
|
+
var import_node_fs11 = require("fs");
|
|
9967
|
+
var import_node_path13 = require("path");
|
|
9241
9968
|
function posixShellQuote(value) {
|
|
9242
9969
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
9243
9970
|
}
|
|
@@ -9256,19 +9983,19 @@ function buildSourceUpdateCommand(sourceRoot) {
|
|
|
9256
9983
|
return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
|
|
9257
9984
|
}
|
|
9258
9985
|
function findRepoBackedSdkRoot(startPath) {
|
|
9259
|
-
let current = (0,
|
|
9986
|
+
let current = (0, import_node_path13.resolve)(startPath);
|
|
9260
9987
|
while (true) {
|
|
9261
|
-
if ((0,
|
|
9988
|
+
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
9989
|
return current;
|
|
9263
9990
|
}
|
|
9264
|
-
const parent = (0,
|
|
9991
|
+
const parent = (0, import_node_path13.dirname)(current);
|
|
9265
9992
|
if (parent === current) return null;
|
|
9266
9993
|
current = parent;
|
|
9267
9994
|
}
|
|
9268
9995
|
}
|
|
9269
9996
|
function resolveUpdatePlan() {
|
|
9270
|
-
const entrypoint = process.argv[1] ? (0,
|
|
9271
|
-
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0,
|
|
9997
|
+
const entrypoint = process.argv[1] ? (0, import_node_path13.resolve)(process.argv[1]) : "";
|
|
9998
|
+
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path13.dirname)(entrypoint)) : null;
|
|
9272
9999
|
if (sourceRoot) {
|
|
9273
10000
|
return {
|
|
9274
10001
|
kind: "source",
|
|
@@ -9361,9 +10088,9 @@ Examples:
|
|
|
9361
10088
|
|
|
9362
10089
|
// src/cli/skills-sync.ts
|
|
9363
10090
|
var import_node_child_process2 = require("child_process");
|
|
9364
|
-
var
|
|
10091
|
+
var import_node_fs12 = require("fs");
|
|
9365
10092
|
var import_node_os8 = require("os");
|
|
9366
|
-
var
|
|
10093
|
+
var import_node_path14 = require("path");
|
|
9367
10094
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
9368
10095
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
9369
10096
|
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
@@ -9374,23 +10101,59 @@ function shouldSkipSkillsSync() {
|
|
|
9374
10101
|
}
|
|
9375
10102
|
function sdkSkillsVersionPath(baseUrl) {
|
|
9376
10103
|
const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
|
|
9377
|
-
return (0,
|
|
10104
|
+
return (0, import_node_path14.join)(home, ".local", "deepline", baseUrlSlug(baseUrl), "sdk-skills", ".version");
|
|
9378
10105
|
}
|
|
9379
10106
|
function readLocalSkillsVersion(baseUrl) {
|
|
9380
10107
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
9381
|
-
if (!(0,
|
|
10108
|
+
if (!(0, import_node_fs12.existsSync)(path)) return "";
|
|
9382
10109
|
try {
|
|
9383
|
-
return (0,
|
|
10110
|
+
return (0, import_node_fs12.readFileSync)(path, "utf-8").trim();
|
|
9384
10111
|
} catch {
|
|
9385
10112
|
return "";
|
|
9386
10113
|
}
|
|
9387
10114
|
}
|
|
9388
10115
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
9389
10116
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
9390
|
-
(0,
|
|
9391
|
-
(0,
|
|
10117
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
|
|
10118
|
+
(0, import_node_fs12.writeFileSync)(path, `${version}
|
|
9392
10119
|
`, "utf-8");
|
|
9393
10120
|
}
|
|
10121
|
+
function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
10122
|
+
const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
|
|
10123
|
+
const roots = [
|
|
10124
|
+
(0, import_node_path14.join)(home, ".claude", "skills", SDK_SKILL_NAME),
|
|
10125
|
+
(0, import_node_path14.join)(home, ".agents", "skills", SDK_SKILL_NAME)
|
|
10126
|
+
];
|
|
10127
|
+
const staleMarkers = [
|
|
10128
|
+
"ctx.tools.execute(key",
|
|
10129
|
+
"ctx.tools.execute('",
|
|
10130
|
+
'ctx.tools.execute("',
|
|
10131
|
+
"rowCtx.tools.execute('",
|
|
10132
|
+
'rowCtx.tools.execute("'
|
|
10133
|
+
];
|
|
10134
|
+
const scan = (dir) => {
|
|
10135
|
+
for (const entry of (0, import_node_fs12.readdirSync)(dir)) {
|
|
10136
|
+
const path = (0, import_node_path14.join)(dir, entry);
|
|
10137
|
+
const stat3 = (0, import_node_fs12.statSync)(path);
|
|
10138
|
+
if (stat3.isDirectory()) {
|
|
10139
|
+
if (scan(path)) return true;
|
|
10140
|
+
continue;
|
|
10141
|
+
}
|
|
10142
|
+
if (!entry.endsWith(".md")) continue;
|
|
10143
|
+
const text = (0, import_node_fs12.readFileSync)(path, "utf-8");
|
|
10144
|
+
if (staleMarkers.some((marker) => text.includes(marker))) return true;
|
|
10145
|
+
}
|
|
10146
|
+
return false;
|
|
10147
|
+
};
|
|
10148
|
+
for (const root of roots) {
|
|
10149
|
+
try {
|
|
10150
|
+
if ((0, import_node_fs12.existsSync)(root) && scan(root)) return true;
|
|
10151
|
+
} catch {
|
|
10152
|
+
continue;
|
|
10153
|
+
}
|
|
10154
|
+
}
|
|
10155
|
+
return false;
|
|
10156
|
+
}
|
|
9394
10157
|
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
9395
10158
|
const controller = new AbortController();
|
|
9396
10159
|
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
@@ -9426,7 +10189,7 @@ function buildSkillsInstallArgs(baseUrl) {
|
|
|
9426
10189
|
"skills",
|
|
9427
10190
|
"add",
|
|
9428
10191
|
packageUrl,
|
|
9429
|
-
"--
|
|
10192
|
+
"--agent",
|
|
9430
10193
|
...SKILL_AGENTS,
|
|
9431
10194
|
"--global",
|
|
9432
10195
|
"--yes",
|
|
@@ -9442,7 +10205,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
|
|
|
9442
10205
|
"skills",
|
|
9443
10206
|
"add",
|
|
9444
10207
|
packageUrl,
|
|
9445
|
-
"--
|
|
10208
|
+
"--agent",
|
|
9446
10209
|
...SKILL_AGENTS,
|
|
9447
10210
|
"--global",
|
|
9448
10211
|
"--yes",
|
|
@@ -9482,7 +10245,7 @@ function resolveSkillsInstallCommands(baseUrl) {
|
|
|
9482
10245
|
return [npxInstall];
|
|
9483
10246
|
}
|
|
9484
10247
|
function runOneSkillsInstall(install) {
|
|
9485
|
-
return new Promise((
|
|
10248
|
+
return new Promise((resolve11) => {
|
|
9486
10249
|
const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
|
|
9487
10250
|
stdio: ["ignore", "ignore", "pipe"],
|
|
9488
10251
|
env: process.env
|
|
@@ -9492,7 +10255,7 @@ function runOneSkillsInstall(install) {
|
|
|
9492
10255
|
stderr += chunk.toString("utf-8");
|
|
9493
10256
|
});
|
|
9494
10257
|
child.on("error", (error) => {
|
|
9495
|
-
|
|
10258
|
+
resolve11({
|
|
9496
10259
|
ok: false,
|
|
9497
10260
|
detail: `failed to start ${install.command}: ${error.message}`,
|
|
9498
10261
|
manualCommand: install.manualCommand
|
|
@@ -9500,11 +10263,11 @@ function runOneSkillsInstall(install) {
|
|
|
9500
10263
|
});
|
|
9501
10264
|
child.on("close", (code) => {
|
|
9502
10265
|
if (code === 0) {
|
|
9503
|
-
|
|
10266
|
+
resolve11({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
9504
10267
|
return;
|
|
9505
10268
|
}
|
|
9506
10269
|
const detail = stderr.trim();
|
|
9507
|
-
|
|
10270
|
+
resolve11({
|
|
9508
10271
|
ok: false,
|
|
9509
10272
|
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
9510
10273
|
manualCommand: install.manualCommand
|
|
@@ -9543,10 +10306,19 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
9543
10306
|
attemptedSync = true;
|
|
9544
10307
|
const localVersion = readLocalSkillsVersion(baseUrl);
|
|
9545
10308
|
const update = await fetchSkillsUpdate(baseUrl, localVersion);
|
|
9546
|
-
|
|
10309
|
+
const hasStaleInstalledSkill = installedSdkSkillHasStalePositionalExecuteExamples();
|
|
10310
|
+
if (!update?.needsUpdate && !hasStaleInstalledSkill || !update?.remoteVersion) {
|
|
10311
|
+
return;
|
|
10312
|
+
}
|
|
9547
10313
|
writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-sdk skill...");
|
|
9548
10314
|
const installed = await runSkillsInstall(baseUrl);
|
|
9549
10315
|
if (!installed) return;
|
|
10316
|
+
if (installedSdkSkillHasStalePositionalExecuteExamples()) {
|
|
10317
|
+
process.stderr.write(
|
|
10318
|
+
"SDK skills sync completed, but installed deepline-sdk docs still contain stale positional ctx.tools.execute examples.\n"
|
|
10319
|
+
);
|
|
10320
|
+
return;
|
|
10321
|
+
}
|
|
9550
10322
|
writeLocalSkillsVersion(baseUrl, update.remoteVersion);
|
|
9551
10323
|
writeSdkSkillsStatusLine("SDK skills are up to date.");
|
|
9552
10324
|
}
|