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.mjs
CHANGED
|
@@ -193,8 +193,8 @@ function resolveConfig(options) {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
// src/version.ts
|
|
196
|
-
var SDK_VERSION = "0.1.
|
|
197
|
-
var SDK_API_CONTRACT = "2026-05-
|
|
196
|
+
var SDK_VERSION = "0.1.36";
|
|
197
|
+
var SDK_API_CONTRACT = "2026-05-v2-tool-response";
|
|
198
198
|
|
|
199
199
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
200
200
|
var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
|
|
@@ -276,7 +276,7 @@ var HttpClient = class {
|
|
|
276
276
|
const response = await fetch(candidateUrl, {
|
|
277
277
|
method,
|
|
278
278
|
headers,
|
|
279
|
-
body: options?.formData !== void 0 ? options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
279
|
+
body: options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
280
280
|
signal: controller.signal
|
|
281
281
|
});
|
|
282
282
|
clearTimeout(timeoutId);
|
|
@@ -359,10 +359,13 @@ var HttpClient = class {
|
|
|
359
359
|
throw new AuthError();
|
|
360
360
|
}
|
|
361
361
|
if (!response.ok) {
|
|
362
|
+
const body = await response.text();
|
|
363
|
+
const parsed = parseResponseBody(body);
|
|
362
364
|
throw new DeeplineError(
|
|
363
|
-
|
|
365
|
+
apiErrorMessage(parsed, response.status),
|
|
364
366
|
response.status,
|
|
365
|
-
"API_ERROR"
|
|
367
|
+
"API_ERROR",
|
|
368
|
+
{ response: parsed }
|
|
366
369
|
);
|
|
367
370
|
}
|
|
368
371
|
if (!response.body) {
|
|
@@ -412,6 +415,26 @@ var HttpClient = class {
|
|
|
412
415
|
return this.request(path, { method: "DELETE" });
|
|
413
416
|
}
|
|
414
417
|
};
|
|
418
|
+
function parseResponseBody(body) {
|
|
419
|
+
try {
|
|
420
|
+
return JSON.parse(body);
|
|
421
|
+
} catch {
|
|
422
|
+
return body;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function apiErrorMessage(parsed, status) {
|
|
426
|
+
const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
|
|
427
|
+
if (typeof errorValue === "string") {
|
|
428
|
+
return errorValue;
|
|
429
|
+
}
|
|
430
|
+
if (errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string") {
|
|
431
|
+
return errorValue.message;
|
|
432
|
+
}
|
|
433
|
+
if (typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string") {
|
|
434
|
+
return parsed.message;
|
|
435
|
+
}
|
|
436
|
+
return `HTTP ${status}`;
|
|
437
|
+
}
|
|
415
438
|
function parseRetryAfter(response) {
|
|
416
439
|
const header = response.headers.get("retry-after");
|
|
417
440
|
if (header) {
|
|
@@ -475,15 +498,17 @@ function decodeSseFrame(frame) {
|
|
|
475
498
|
return parsed;
|
|
476
499
|
}
|
|
477
500
|
function sleep(ms) {
|
|
478
|
-
return new Promise((
|
|
501
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
479
502
|
}
|
|
480
503
|
|
|
481
504
|
// src/client.ts
|
|
482
505
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
483
506
|
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
507
|
+
var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
|
|
508
|
+
var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
|
|
484
509
|
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
485
510
|
function sleep2(ms) {
|
|
486
|
-
return new Promise((
|
|
511
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
487
512
|
}
|
|
488
513
|
function isTransientCompileManifestError(error) {
|
|
489
514
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
@@ -749,13 +774,16 @@ var DeeplineClient = class {
|
|
|
749
774
|
/**
|
|
750
775
|
* Execute a tool and return the standard execution envelope.
|
|
751
776
|
*
|
|
752
|
-
* The `
|
|
753
|
-
* contains provider
|
|
777
|
+
* The `toolResponse.raw` field contains the raw tool response.
|
|
778
|
+
* `toolResponse.meta` contains tool/provider metadata.
|
|
754
779
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
755
|
-
* Deepline execution.
|
|
780
|
+
* Deepline execution envelope.
|
|
756
781
|
*/
|
|
757
782
|
async executeTool(toolId, input, options) {
|
|
758
|
-
const headers =
|
|
783
|
+
const headers = {
|
|
784
|
+
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
785
|
+
...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
|
|
786
|
+
};
|
|
759
787
|
return this.http.post(
|
|
760
788
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
761
789
|
{ payload: input },
|
|
@@ -1053,34 +1081,37 @@ var DeeplineClient = class {
|
|
|
1053
1081
|
* ```
|
|
1054
1082
|
*/
|
|
1055
1083
|
async stagePlayFiles(files) {
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
"metadata",
|
|
1059
|
-
JSON.stringify({
|
|
1060
|
-
files: files.map((file, index) => ({
|
|
1061
|
-
index,
|
|
1062
|
-
logicalPath: file.logicalPath,
|
|
1063
|
-
contentHash: file.contentHash,
|
|
1064
|
-
contentType: file.contentType,
|
|
1065
|
-
bytes: file.bytes
|
|
1066
|
-
}))
|
|
1067
|
-
})
|
|
1068
|
-
);
|
|
1069
|
-
for (const [index, file] of files.entries()) {
|
|
1070
|
-
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1071
|
-
const body = bytes.buffer.slice(
|
|
1072
|
-
bytes.byteOffset,
|
|
1073
|
-
bytes.byteOffset + bytes.byteLength
|
|
1074
|
-
);
|
|
1084
|
+
const buildFormData = () => {
|
|
1085
|
+
const formData = new FormData();
|
|
1075
1086
|
formData.set(
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1087
|
+
"metadata",
|
|
1088
|
+
JSON.stringify({
|
|
1089
|
+
files: files.map((file, index) => ({
|
|
1090
|
+
index,
|
|
1091
|
+
logicalPath: file.logicalPath,
|
|
1092
|
+
contentHash: file.contentHash,
|
|
1093
|
+
contentType: file.contentType,
|
|
1094
|
+
bytes: file.bytes
|
|
1095
|
+
}))
|
|
1096
|
+
})
|
|
1079
1097
|
);
|
|
1080
|
-
|
|
1098
|
+
for (const [index, file] of files.entries()) {
|
|
1099
|
+
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1100
|
+
const body = bytes.buffer.slice(
|
|
1101
|
+
bytes.byteOffset,
|
|
1102
|
+
bytes.byteOffset + bytes.byteLength
|
|
1103
|
+
);
|
|
1104
|
+
formData.set(
|
|
1105
|
+
`file:${index}`,
|
|
1106
|
+
new Blob([body], { type: file.contentType }),
|
|
1107
|
+
file.logicalPath
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
return formData;
|
|
1111
|
+
};
|
|
1081
1112
|
const response = await this.http.postFormData(
|
|
1082
1113
|
"/api/v2/plays/files/stage",
|
|
1083
|
-
|
|
1114
|
+
buildFormData
|
|
1084
1115
|
);
|
|
1085
1116
|
return response.files;
|
|
1086
1117
|
}
|
|
@@ -1874,6 +1905,103 @@ function csvStringFromRows(rows, columns) {
|
|
|
1874
1905
|
...columns?.length ? { columns } : {}
|
|
1875
1906
|
});
|
|
1876
1907
|
}
|
|
1908
|
+
function parseMaybeJsonObject(value) {
|
|
1909
|
+
if (typeof value !== "string") {
|
|
1910
|
+
return value;
|
|
1911
|
+
}
|
|
1912
|
+
const trimmed = value.trim();
|
|
1913
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
|
1914
|
+
return value;
|
|
1915
|
+
}
|
|
1916
|
+
try {
|
|
1917
|
+
return JSON.parse(trimmed);
|
|
1918
|
+
} catch {
|
|
1919
|
+
return value;
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
function flattenObjectColumns(row) {
|
|
1923
|
+
const flattened = {};
|
|
1924
|
+
for (const [key, rawValue] of Object.entries(row)) {
|
|
1925
|
+
const value = parseMaybeJsonObject(rawValue);
|
|
1926
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1927
|
+
for (const [nestedKey, nestedValue] of Object.entries(
|
|
1928
|
+
value
|
|
1929
|
+
)) {
|
|
1930
|
+
flattened[`${key}.${nestedKey}`] = nestedValue && typeof nestedValue === "object" ? JSON.stringify(nestedValue) : nestedValue;
|
|
1931
|
+
}
|
|
1932
|
+
continue;
|
|
1933
|
+
}
|
|
1934
|
+
flattened[key] = Array.isArray(value) ? JSON.stringify(value) : value;
|
|
1935
|
+
}
|
|
1936
|
+
return flattened;
|
|
1937
|
+
}
|
|
1938
|
+
function recordRows(value) {
|
|
1939
|
+
return value.filter(
|
|
1940
|
+
(row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1943
|
+
function dataExportRows(rows) {
|
|
1944
|
+
return rows.map((row) => flattenObjectColumns(row));
|
|
1945
|
+
}
|
|
1946
|
+
function dataExportColumns(rows, preferredColumns = []) {
|
|
1947
|
+
const discoveredColumns = [
|
|
1948
|
+
...new Set(rows.flatMap((row) => Object.keys(row)))
|
|
1949
|
+
];
|
|
1950
|
+
if (rows.length === 0) {
|
|
1951
|
+
return [...new Set(preferredColumns.filter(Boolean))];
|
|
1952
|
+
}
|
|
1953
|
+
const discovered = new Set(discoveredColumns);
|
|
1954
|
+
const columns = [];
|
|
1955
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1956
|
+
for (const column of preferredColumns) {
|
|
1957
|
+
if (!column) {
|
|
1958
|
+
continue;
|
|
1959
|
+
}
|
|
1960
|
+
const expandedColumns = discovered.has(column) ? [column] : discoveredColumns.filter(
|
|
1961
|
+
(discoveredColumn) => discoveredColumn.startsWith(`${column}.`)
|
|
1962
|
+
);
|
|
1963
|
+
for (const expandedColumn of expandedColumns) {
|
|
1964
|
+
if (seen.has(expandedColumn)) {
|
|
1965
|
+
continue;
|
|
1966
|
+
}
|
|
1967
|
+
seen.add(expandedColumn);
|
|
1968
|
+
columns.push(expandedColumn);
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
for (const column of discoveredColumns) {
|
|
1972
|
+
if (seen.has(column)) {
|
|
1973
|
+
continue;
|
|
1974
|
+
}
|
|
1975
|
+
seen.add(column);
|
|
1976
|
+
columns.push(column);
|
|
1977
|
+
}
|
|
1978
|
+
return columns;
|
|
1979
|
+
}
|
|
1980
|
+
function dataExportCsvString(rows, preferredColumns = []) {
|
|
1981
|
+
const flattenedRows = dataExportRows(rows);
|
|
1982
|
+
return csvStringFromRows(
|
|
1983
|
+
flattenedRows,
|
|
1984
|
+
dataExportColumns(flattenedRows, preferredColumns)
|
|
1985
|
+
);
|
|
1986
|
+
}
|
|
1987
|
+
function markdownCell(value) {
|
|
1988
|
+
if (value === null || value === void 0) {
|
|
1989
|
+
return "";
|
|
1990
|
+
}
|
|
1991
|
+
const text = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
1992
|
+
return text.replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
|
|
1993
|
+
}
|
|
1994
|
+
function markdownTableFromRows(rows, preferredColumns = []) {
|
|
1995
|
+
const flattenedRows = dataExportRows(rows);
|
|
1996
|
+
const columns = dataExportColumns(flattenedRows, preferredColumns);
|
|
1997
|
+
const header = `| ${columns.map(markdownCell).join(" | ")} |`;
|
|
1998
|
+
const separator = `| ${columns.map(() => "---").join(" | ")} |`;
|
|
1999
|
+
const body = flattenedRows.map(
|
|
2000
|
+
(row) => `| ${columns.map((column) => markdownCell(row[column])).join(" | ")} |`
|
|
2001
|
+
);
|
|
2002
|
+
return `${[header, separator, ...body].join("\n")}
|
|
2003
|
+
`;
|
|
2004
|
+
}
|
|
1877
2005
|
function printJson(value) {
|
|
1878
2006
|
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
1879
2007
|
`);
|
|
@@ -2050,7 +2178,7 @@ function buildCandidateUrls2(url) {
|
|
|
2050
2178
|
}
|
|
2051
2179
|
}
|
|
2052
2180
|
function sleep3(ms) {
|
|
2053
|
-
return new Promise((
|
|
2181
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
2054
2182
|
}
|
|
2055
2183
|
function printDeeplineLogo() {
|
|
2056
2184
|
if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
|
|
@@ -3250,10 +3378,12 @@ function writeCanonicalRowsCsv(rowsInfo, outPath) {
|
|
|
3250
3378
|
rows: rowsInfo.rows,
|
|
3251
3379
|
columns: rowsInfo.columns
|
|
3252
3380
|
});
|
|
3381
|
+
const rows = dataExportRows(sanitized.rows);
|
|
3382
|
+
const columns = dataExportColumns(rows, sanitized.columns);
|
|
3253
3383
|
const resolved = resolve4(outPath);
|
|
3254
3384
|
writeFileSync4(
|
|
3255
3385
|
resolved,
|
|
3256
|
-
csvStringFromRows(
|
|
3386
|
+
csvStringFromRows(rows, columns),
|
|
3257
3387
|
"utf-8"
|
|
3258
3388
|
);
|
|
3259
3389
|
return resolved;
|
|
@@ -3374,6 +3504,14 @@ Examples:
|
|
|
3374
3504
|
}
|
|
3375
3505
|
|
|
3376
3506
|
// src/cli/commands/db.ts
|
|
3507
|
+
import { writeFileSync as writeFileSync5 } from "fs";
|
|
3508
|
+
import { resolve as resolve5 } from "path";
|
|
3509
|
+
var CUSTOMER_DB_QUERY_FORMATS = /* @__PURE__ */ new Set([
|
|
3510
|
+
"table",
|
|
3511
|
+
"json",
|
|
3512
|
+
"csv",
|
|
3513
|
+
"markdown"
|
|
3514
|
+
]);
|
|
3377
3515
|
function parsePositiveInteger(value, flagName) {
|
|
3378
3516
|
const parsed = Number.parseInt(value, 10);
|
|
3379
3517
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
@@ -3387,10 +3525,8 @@ function formatCell(value) {
|
|
|
3387
3525
|
return text.length > 80 ? `${text.slice(0, 77)}...` : text;
|
|
3388
3526
|
}
|
|
3389
3527
|
function tableLines(result) {
|
|
3390
|
-
const rows = result
|
|
3391
|
-
|
|
3392
|
-
);
|
|
3393
|
-
const responseColumns = result.columns.length > 0 ? result.columns.map((column) => column.name) : [...new Set(rows.flatMap((row) => Object.keys(row)))];
|
|
3528
|
+
const rows = dataExportRows(customerDbRows(result));
|
|
3529
|
+
const responseColumns = dataExportColumns(rows, customerDbColumnNames(result));
|
|
3394
3530
|
const businessColumns = responseColumns.filter((column) => !column.startsWith("_"));
|
|
3395
3531
|
const columns = businessColumns.length > 0 ? businessColumns : responseColumns;
|
|
3396
3532
|
const hiddenColumns = responseColumns.filter((column) => !columns.includes(column));
|
|
@@ -3424,22 +3560,146 @@ function tableLines(result) {
|
|
|
3424
3560
|
}
|
|
3425
3561
|
return lines;
|
|
3426
3562
|
}
|
|
3563
|
+
function customerDbRows(result) {
|
|
3564
|
+
return recordRows(result.rows);
|
|
3565
|
+
}
|
|
3566
|
+
function customerDbColumnNames(result) {
|
|
3567
|
+
return result.columns.map((column) => column.name).filter(Boolean);
|
|
3568
|
+
}
|
|
3569
|
+
function writeCustomerDbCsv(result, outPath) {
|
|
3570
|
+
const resolved = resolve5(outPath);
|
|
3571
|
+
writeFileSync5(
|
|
3572
|
+
resolved,
|
|
3573
|
+
dataExportCsvString(customerDbRows(result), customerDbColumnNames(result)),
|
|
3574
|
+
"utf-8"
|
|
3575
|
+
);
|
|
3576
|
+
return resolved;
|
|
3577
|
+
}
|
|
3578
|
+
function dbQueryExportEnvelope(input) {
|
|
3579
|
+
const destination = input.outPath ?? "stdout";
|
|
3580
|
+
return {
|
|
3581
|
+
command: input.result.command,
|
|
3582
|
+
format: input.format,
|
|
3583
|
+
row_count: input.result.row_count,
|
|
3584
|
+
row_count_returned: input.result.row_count_returned,
|
|
3585
|
+
truncated: input.result.truncated,
|
|
3586
|
+
...input.outPath ? { file: input.outPath, local: { file: input.outPath } } : {},
|
|
3587
|
+
next: { toolEquivalent: input.toolCommand },
|
|
3588
|
+
render: {
|
|
3589
|
+
sections: [
|
|
3590
|
+
{
|
|
3591
|
+
title: "customer db export",
|
|
3592
|
+
lines: [
|
|
3593
|
+
`Rendered ${input.result.row_count_returned} row(s) as ${input.format} to ${destination}`
|
|
3594
|
+
]
|
|
3595
|
+
}
|
|
3596
|
+
],
|
|
3597
|
+
actions: [{ label: "Tool equivalent", command: input.toolCommand }]
|
|
3598
|
+
}
|
|
3599
|
+
};
|
|
3600
|
+
}
|
|
3427
3601
|
async function handleDbQuery(args) {
|
|
3428
3602
|
const sqlIndex = args.indexOf("--sql");
|
|
3429
3603
|
const sql = sqlIndex >= 0 ? args[sqlIndex + 1]?.trim() : "";
|
|
3430
3604
|
if (!sql) {
|
|
3431
|
-
console.error(
|
|
3605
|
+
console.error(
|
|
3606
|
+
'Usage: deepline db query --sql "select * from table limit 20" [--max-rows N] [--json]'
|
|
3607
|
+
);
|
|
3432
3608
|
return 1;
|
|
3433
3609
|
}
|
|
3434
3610
|
const maxRowsIndex = args.indexOf("--max-rows");
|
|
3435
3611
|
const maxRows = maxRowsIndex >= 0 && args[maxRowsIndex + 1] ? parsePositiveInteger(args[maxRowsIndex + 1], "--max-rows") : void 0;
|
|
3612
|
+
const formatIndex = args.indexOf("--format");
|
|
3613
|
+
const format = formatIndex >= 0 ? args[formatIndex + 1]?.trim().toLowerCase() : "";
|
|
3614
|
+
if (format && !CUSTOMER_DB_QUERY_FORMATS.has(format)) {
|
|
3615
|
+
console.error(
|
|
3616
|
+
'Usage: deepline db query --sql "select * from table limit 20" [--format table|json|csv|markdown] [--out path]'
|
|
3617
|
+
);
|
|
3618
|
+
return 1;
|
|
3619
|
+
}
|
|
3620
|
+
const outIndex = args.indexOf("--out");
|
|
3621
|
+
const outPath = outIndex >= 0 ? args[outIndex + 1]?.trim() : "";
|
|
3622
|
+
if (outIndex >= 0 && !outPath) {
|
|
3623
|
+
console.error("--out requires a path.");
|
|
3624
|
+
return 1;
|
|
3625
|
+
}
|
|
3436
3626
|
const jsonOutput = argsWantJson(args);
|
|
3627
|
+
const explicitJsonOutput = args.includes("--json");
|
|
3437
3628
|
const client = new DeeplineClient();
|
|
3438
3629
|
const result = await client.queryCustomerDb({ sql, maxRows });
|
|
3439
3630
|
const toolCommand = `deepline tools execute query_customer_db --payload ${JSON.stringify({
|
|
3440
3631
|
sql,
|
|
3441
3632
|
...maxRows ? { max_rows: maxRows } : {}
|
|
3442
3633
|
})} --json`;
|
|
3634
|
+
if (format === "csv") {
|
|
3635
|
+
if (outPath) {
|
|
3636
|
+
const exportedPath = writeCustomerDbCsv(result, outPath);
|
|
3637
|
+
printCommandEnvelope(
|
|
3638
|
+
dbQueryExportEnvelope({
|
|
3639
|
+
result,
|
|
3640
|
+
format,
|
|
3641
|
+
outPath: exportedPath,
|
|
3642
|
+
toolCommand
|
|
3643
|
+
}),
|
|
3644
|
+
{
|
|
3645
|
+
json: jsonOutput,
|
|
3646
|
+
text: `Exported ${result.row_count_returned} row(s) to ${exportedPath}
|
|
3647
|
+
`
|
|
3648
|
+
}
|
|
3649
|
+
);
|
|
3650
|
+
return 0;
|
|
3651
|
+
}
|
|
3652
|
+
printCommandEnvelope(
|
|
3653
|
+
dbQueryExportEnvelope({
|
|
3654
|
+
result,
|
|
3655
|
+
format,
|
|
3656
|
+
outPath: null,
|
|
3657
|
+
toolCommand
|
|
3658
|
+
}),
|
|
3659
|
+
{
|
|
3660
|
+
json: explicitJsonOutput,
|
|
3661
|
+
text: dataExportCsvString(customerDbRows(result), customerDbColumnNames(result))
|
|
3662
|
+
}
|
|
3663
|
+
);
|
|
3664
|
+
return 0;
|
|
3665
|
+
}
|
|
3666
|
+
if (format === "markdown") {
|
|
3667
|
+
const content = markdownTableFromRows(
|
|
3668
|
+
customerDbRows(result),
|
|
3669
|
+
customerDbColumnNames(result)
|
|
3670
|
+
);
|
|
3671
|
+
if (outPath) {
|
|
3672
|
+
const exportedPath = resolve5(outPath);
|
|
3673
|
+
writeFileSync5(exportedPath, content, "utf-8");
|
|
3674
|
+
printCommandEnvelope(
|
|
3675
|
+
dbQueryExportEnvelope({
|
|
3676
|
+
result,
|
|
3677
|
+
format,
|
|
3678
|
+
outPath: exportedPath,
|
|
3679
|
+
toolCommand
|
|
3680
|
+
}),
|
|
3681
|
+
{
|
|
3682
|
+
json: jsonOutput,
|
|
3683
|
+
text: `Exported ${result.row_count_returned} row(s) to ${exportedPath}
|
|
3684
|
+
`
|
|
3685
|
+
}
|
|
3686
|
+
);
|
|
3687
|
+
return 0;
|
|
3688
|
+
}
|
|
3689
|
+
printCommandEnvelope(
|
|
3690
|
+
dbQueryExportEnvelope({
|
|
3691
|
+
result,
|
|
3692
|
+
format,
|
|
3693
|
+
outPath: null,
|
|
3694
|
+
toolCommand
|
|
3695
|
+
}),
|
|
3696
|
+
{
|
|
3697
|
+
json: explicitJsonOutput,
|
|
3698
|
+
text: content
|
|
3699
|
+
}
|
|
3700
|
+
);
|
|
3701
|
+
return 0;
|
|
3702
|
+
}
|
|
3443
3703
|
printCommandEnvelope({
|
|
3444
3704
|
...result,
|
|
3445
3705
|
next: { toolEquivalent: toolCommand },
|
|
@@ -3447,7 +3707,7 @@ async function handleDbQuery(args) {
|
|
|
3447
3707
|
sections: [{ title: "customer db query", lines: tableLines(result) }],
|
|
3448
3708
|
actions: [{ label: "Tool equivalent", command: toolCommand }]
|
|
3449
3709
|
}
|
|
3450
|
-
}, { json: jsonOutput });
|
|
3710
|
+
}, { json: jsonOutput || format === "json" });
|
|
3451
3711
|
return 0;
|
|
3452
3712
|
}
|
|
3453
3713
|
function registerDbCommands(program) {
|
|
@@ -3457,11 +3717,14 @@ function registerDbCommands(program) {
|
|
|
3457
3717
|
Notes:
|
|
3458
3718
|
Runs SQL against the active workspace customer database through Deepline APIs.
|
|
3459
3719
|
Results are bounded by the server and --max-rows. Use --json for stable output.
|
|
3720
|
+
Use --format csv or --format markdown for agent-readable exports and display tables.
|
|
3460
3721
|
|
|
3461
3722
|
Examples:
|
|
3462
3723
|
deepline db query --sql "select * from companies limit 20"
|
|
3463
3724
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
3464
3725
|
deepline db query --sql "select * from contacts" --max-rows 100 --json
|
|
3726
|
+
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
3727
|
+
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
3465
3728
|
`
|
|
3466
3729
|
);
|
|
3467
3730
|
db.command("query").alias("psql").description("Run SQL against the tenant customer database.").addHelpText(
|
|
@@ -3470,17 +3733,23 @@ Examples:
|
|
|
3470
3733
|
Notes:
|
|
3471
3734
|
Requires --sql. Output is a compact table in a terminal and raw JSON with
|
|
3472
3735
|
--json or when stdout is piped. The active auth workspace determines scope.
|
|
3736
|
+
--format csv and --format markdown are explicit data/display formats and can
|
|
3737
|
+
be written directly with --out.
|
|
3473
3738
|
|
|
3474
3739
|
Examples:
|
|
3475
3740
|
deepline db query --sql "select * from companies limit 20"
|
|
3476
3741
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
3477
3742
|
deepline db psql --sql "select count(*) from contacts" --json
|
|
3743
|
+
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
3744
|
+
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
3478
3745
|
`
|
|
3479
|
-
).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) => {
|
|
3746
|
+
).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) => {
|
|
3480
3747
|
process.exitCode = await handleDbQuery([
|
|
3481
3748
|
"--sql",
|
|
3482
3749
|
options.sql,
|
|
3483
3750
|
...options.maxRows ? ["--max-rows", options.maxRows] : [],
|
|
3751
|
+
...options.format ? ["--format", options.format] : [],
|
|
3752
|
+
...options.out ? ["--out", options.out] : [],
|
|
3484
3753
|
...options.json ? ["--json"] : []
|
|
3485
3754
|
]);
|
|
3486
3755
|
});
|
|
@@ -3661,13 +3930,13 @@ import {
|
|
|
3661
3930
|
readFileSync as readFileSync5,
|
|
3662
3931
|
readdirSync,
|
|
3663
3932
|
realpathSync,
|
|
3664
|
-
writeFileSync as
|
|
3933
|
+
writeFileSync as writeFileSync6
|
|
3665
3934
|
} from "fs";
|
|
3666
|
-
import { basename as basename3, dirname as dirname8, join as join6, resolve as
|
|
3935
|
+
import { basename as basename3, dirname as dirname8, join as join6, resolve as resolve9 } from "path";
|
|
3667
3936
|
|
|
3668
3937
|
// src/plays/bundle-play-file.ts
|
|
3669
3938
|
import { tmpdir as tmpdir2 } from "os";
|
|
3670
|
-
import { dirname as dirname7, join as join5, resolve as
|
|
3939
|
+
import { dirname as dirname7, join as join5, resolve as resolve8 } from "path";
|
|
3671
3940
|
import { fileURLToPath } from "url";
|
|
3672
3941
|
import { existsSync as existsSync5 } from "fs";
|
|
3673
3942
|
|
|
@@ -3676,7 +3945,7 @@ import { createHash } from "crypto";
|
|
|
3676
3945
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
3677
3946
|
import { mkdir as mkdir3, readFile, realpath, stat, writeFile as writeFile3 } from "fs/promises";
|
|
3678
3947
|
import { tmpdir } from "os";
|
|
3679
|
-
import { basename, dirname as dirname5, extname, isAbsolute, join as join3, resolve as
|
|
3948
|
+
import { basename, dirname as dirname5, extname, isAbsolute, join as join3, resolve as resolve6 } from "path";
|
|
3680
3949
|
import { builtinModules } from "module";
|
|
3681
3950
|
import { build } from "esbuild";
|
|
3682
3951
|
|
|
@@ -3768,7 +4037,7 @@ async function normalizeLocalPath(filePath) {
|
|
|
3768
4037
|
try {
|
|
3769
4038
|
return await realpath(filePath);
|
|
3770
4039
|
} catch {
|
|
3771
|
-
return
|
|
4040
|
+
return resolve6(filePath);
|
|
3772
4041
|
}
|
|
3773
4042
|
}
|
|
3774
4043
|
function createPlayWorkspace(entryFile) {
|
|
@@ -3937,7 +4206,7 @@ function readPackageVersionFromPackageJson(packageJsonPath, packageName) {
|
|
|
3937
4206
|
return null;
|
|
3938
4207
|
}
|
|
3939
4208
|
function findPackageJsonPathFrom(startDir, packageName) {
|
|
3940
|
-
let current =
|
|
4209
|
+
let current = resolve6(startDir);
|
|
3941
4210
|
while (true) {
|
|
3942
4211
|
const packageJsonPath = join3(
|
|
3943
4212
|
current,
|
|
@@ -3964,7 +4233,7 @@ function findPackageJsonPath(packageName, fromFile, adapter) {
|
|
|
3964
4233
|
];
|
|
3965
4234
|
const seen = /* @__PURE__ */ new Set();
|
|
3966
4235
|
for (const startDir of startDirs) {
|
|
3967
|
-
const normalized =
|
|
4236
|
+
const normalized = resolve6(startDir);
|
|
3968
4237
|
if (seen.has(normalized)) continue;
|
|
3969
4238
|
seen.add(normalized);
|
|
3970
4239
|
const packageJsonPath = findPackageJsonPathFrom(normalized, packageName);
|
|
@@ -4201,7 +4470,7 @@ async function resolveLocalImport(fromFile, specifier) {
|
|
|
4201
4470
|
if (specifier.startsWith("file:")) {
|
|
4202
4471
|
return normalizeLocalPath(new URL(specifier).pathname);
|
|
4203
4472
|
}
|
|
4204
|
-
const base = isAbsolute(specifier) ?
|
|
4473
|
+
const base = isAbsolute(specifier) ? resolve6(specifier) : resolve6(dirname5(fromFile), specifier);
|
|
4205
4474
|
const candidates = [base];
|
|
4206
4475
|
const explicitExtension = extname(base).toLowerCase();
|
|
4207
4476
|
if (!explicitExtension) {
|
|
@@ -4399,7 +4668,7 @@ function normalizeSourceMapForRuntime(sourceMapText) {
|
|
|
4399
4668
|
if (sourcePath.startsWith("data:") || sourcePath.startsWith("node:") || sourcePath.startsWith("/") || /^[a-zA-Z]+:\/\//.test(sourcePath)) {
|
|
4400
4669
|
return sourcePath;
|
|
4401
4670
|
}
|
|
4402
|
-
return
|
|
4671
|
+
return resolve6(process.cwd(), sourcePath);
|
|
4403
4672
|
});
|
|
4404
4673
|
parsed.sourceRoot = void 0;
|
|
4405
4674
|
return JSON.stringify(parsed);
|
|
@@ -4721,7 +4990,7 @@ function resolveExecutionProfile(override) {
|
|
|
4721
4990
|
// src/plays/local-file-discovery.ts
|
|
4722
4991
|
import { createHash as createHash2 } from "crypto";
|
|
4723
4992
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
4724
|
-
import { basename as basename2, dirname as dirname6, extname as extname2, isAbsolute as isAbsolute2, join as join4, relative, resolve as
|
|
4993
|
+
import { basename as basename2, dirname as dirname6, extname as extname2, isAbsolute as isAbsolute2, join as join4, relative, resolve as resolve7 } from "path";
|
|
4725
4994
|
var SOURCE_EXTENSIONS2 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
|
|
4726
4995
|
function sha2562(buffer) {
|
|
4727
4996
|
return createHash2("sha256").update(buffer).digest("hex");
|
|
@@ -4922,7 +5191,7 @@ function isPathInsideDirectory2(filePath, directory) {
|
|
|
4922
5191
|
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute2(relativePath);
|
|
4923
5192
|
}
|
|
4924
5193
|
async function resolveLocalImport2(fromFile, specifier) {
|
|
4925
|
-
const base = isAbsolute2(specifier) ?
|
|
5194
|
+
const base = isAbsolute2(specifier) ? resolve7(specifier) : resolve7(dirname6(fromFile), specifier);
|
|
4926
5195
|
const candidates = [base];
|
|
4927
5196
|
const explicitExtension = extname2(base).toLowerCase();
|
|
4928
5197
|
if (!explicitExtension) {
|
|
@@ -4940,13 +5209,13 @@ async function resolveLocalImport2(fromFile, specifier) {
|
|
|
4940
5209
|
throw new Error(`Could not resolve local import "${specifier}" from ${fromFile}`);
|
|
4941
5210
|
}
|
|
4942
5211
|
async function discoverPackagedLocalFiles(entryFile) {
|
|
4943
|
-
const absoluteEntryFile =
|
|
5212
|
+
const absoluteEntryFile = resolve7(entryFile);
|
|
4944
5213
|
const packagingRoot = dirname6(absoluteEntryFile);
|
|
4945
5214
|
const files = /* @__PURE__ */ new Map();
|
|
4946
5215
|
const unresolved = [];
|
|
4947
5216
|
const visitedFiles = /* @__PURE__ */ new Set();
|
|
4948
5217
|
const visitSourceFile = async (filePath) => {
|
|
4949
|
-
const absolutePath =
|
|
5218
|
+
const absolutePath = resolve7(filePath);
|
|
4950
5219
|
if (visitedFiles.has(absolutePath)) {
|
|
4951
5220
|
return;
|
|
4952
5221
|
}
|
|
@@ -4978,7 +5247,7 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
4978
5247
|
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."
|
|
4979
5248
|
});
|
|
4980
5249
|
} else {
|
|
4981
|
-
const absoluteCsvPath =
|
|
5250
|
+
const absoluteCsvPath = resolve7(dirname6(absolutePath), resolvedPath);
|
|
4982
5251
|
if (isAbsolute2(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
|
|
4983
5252
|
unresolved.push({
|
|
4984
5253
|
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
@@ -5018,23 +5287,23 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
5018
5287
|
// src/plays/bundle-play-file.ts
|
|
5019
5288
|
var PLAY_BUNDLE_CACHE_VERSION2 = 30;
|
|
5020
5289
|
var MODULE_DIR = dirname7(fileURLToPath(import.meta.url));
|
|
5021
|
-
var SDK_PACKAGE_ROOT =
|
|
5022
|
-
var SOURCE_REPO_ROOT =
|
|
5290
|
+
var SDK_PACKAGE_ROOT = resolve8(MODULE_DIR, "..", "..");
|
|
5291
|
+
var SOURCE_REPO_ROOT = resolve8(SDK_PACKAGE_ROOT, "..");
|
|
5023
5292
|
var HAS_SOURCE_BUNDLING_SOURCES = existsSync5(
|
|
5024
|
-
|
|
5293
|
+
resolve8(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
5025
5294
|
);
|
|
5026
|
-
var PACKAGED_REPO_ROOT =
|
|
5295
|
+
var PACKAGED_REPO_ROOT = resolve8(SDK_PACKAGE_ROOT, "dist", "repo");
|
|
5027
5296
|
var HAS_PACKAGED_BUNDLING_SOURCES = existsSync5(
|
|
5028
|
-
|
|
5297
|
+
resolve8(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
5029
5298
|
);
|
|
5030
|
-
var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT :
|
|
5031
|
-
var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ?
|
|
5032
|
-
var SDK_PACKAGE_JSON =
|
|
5033
|
-
var SDK_ENTRY_FILE =
|
|
5034
|
-
var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE :
|
|
5035
|
-
var SDK_WORKERS_ENTRY_FILE =
|
|
5036
|
-
var WORKERS_HARNESS_ENTRY_FILE =
|
|
5037
|
-
var WORKERS_HARNESS_FILES_DIR =
|
|
5299
|
+
var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : resolve8(SDK_PACKAGE_ROOT, "..");
|
|
5300
|
+
var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? resolve8(SOURCE_REPO_ROOT, "sdk", "src") : HAS_PACKAGED_BUNDLING_SOURCES ? resolve8(PACKAGED_REPO_ROOT, "sdk", "src") : resolve8(SDK_PACKAGE_ROOT, "src");
|
|
5301
|
+
var SDK_PACKAGE_JSON = resolve8(SDK_PACKAGE_ROOT, "package.json");
|
|
5302
|
+
var SDK_ENTRY_FILE = resolve8(SDK_SOURCE_ROOT, "index.ts");
|
|
5303
|
+
var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE : resolve8(SDK_PACKAGE_ROOT, "dist", "index.d.ts");
|
|
5304
|
+
var SDK_WORKERS_ENTRY_FILE = resolve8(SDK_SOURCE_ROOT, "worker-play-entry.ts");
|
|
5305
|
+
var WORKERS_HARNESS_ENTRY_FILE = resolve8(PROJECT_ROOT, "apps", "play-runner-workers", "src", "entry.ts");
|
|
5306
|
+
var WORKERS_HARNESS_FILES_DIR = resolve8(PROJECT_ROOT, "apps", "play-runner-workers", "src");
|
|
5038
5307
|
var hasWarnedAboutNonDevelopmentBundling = false;
|
|
5039
5308
|
function warnAboutNonDevelopmentBundling(filePath) {
|
|
5040
5309
|
if (hasWarnedAboutNonDevelopmentBundling) {
|
|
@@ -5058,7 +5327,7 @@ function defaultPlayBundleTarget() {
|
|
|
5058
5327
|
function createSdkPlayBundlingAdapter() {
|
|
5059
5328
|
return {
|
|
5060
5329
|
projectRoot: PROJECT_ROOT,
|
|
5061
|
-
nodeModulesDir:
|
|
5330
|
+
nodeModulesDir: resolve8(PROJECT_ROOT, "node_modules"),
|
|
5062
5331
|
cacheDir: join5(tmpdir2(), `deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION2}`),
|
|
5063
5332
|
sdkSourceRoot: SDK_SOURCE_ROOT,
|
|
5064
5333
|
sdkPackageJson: SDK_PACKAGE_JSON,
|
|
@@ -5296,7 +5565,7 @@ function traceCliSync(phase, fields, run) {
|
|
|
5296
5565
|
}
|
|
5297
5566
|
}
|
|
5298
5567
|
function sleep4(ms) {
|
|
5299
|
-
return new Promise((
|
|
5568
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
5300
5569
|
}
|
|
5301
5570
|
function parseReferencedPlayTarget(target) {
|
|
5302
5571
|
const trimmed = target.trim();
|
|
@@ -5342,7 +5611,7 @@ function formatPlayListReference(play) {
|
|
|
5342
5611
|
function defaultMaterializedPlayPath(reference) {
|
|
5343
5612
|
const playName = parseReferencedPlayTarget(reference).unqualifiedPlayName;
|
|
5344
5613
|
const safeName = playName.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
5345
|
-
return
|
|
5614
|
+
return resolve9(`${safeName || "play"}.play.ts`);
|
|
5346
5615
|
}
|
|
5347
5616
|
function materializeRemotePlaySource(input) {
|
|
5348
5617
|
if (isFileTarget(input.target)) {
|
|
@@ -5357,10 +5626,10 @@ function materializeRemotePlaySource(input) {
|
|
|
5357
5626
|
if (existingSource === input.sourceCode) {
|
|
5358
5627
|
return { path: outputPath, status: "unchanged", created: false };
|
|
5359
5628
|
}
|
|
5360
|
-
|
|
5629
|
+
writeFileSync6(outputPath, input.sourceCode, "utf-8");
|
|
5361
5630
|
return { path: outputPath, status: "updated", created: false };
|
|
5362
5631
|
}
|
|
5363
|
-
|
|
5632
|
+
writeFileSync6(outputPath, input.sourceCode, "utf-8");
|
|
5364
5633
|
return { path: outputPath, status: "created", created: true };
|
|
5365
5634
|
}
|
|
5366
5635
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -5405,7 +5674,7 @@ function extractPlayName(code, filePath) {
|
|
|
5405
5674
|
throw buildMissingDefinePlayError(filePath);
|
|
5406
5675
|
}
|
|
5407
5676
|
function isFileTarget(target) {
|
|
5408
|
-
return existsSync6(
|
|
5677
|
+
return existsSync6(resolve9(target));
|
|
5409
5678
|
}
|
|
5410
5679
|
function looksLikeFilePath(target) {
|
|
5411
5680
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -5424,7 +5693,7 @@ function parsePositiveInteger2(value, flagName) {
|
|
|
5424
5693
|
return parsed;
|
|
5425
5694
|
}
|
|
5426
5695
|
function parseJsonInput(raw) {
|
|
5427
|
-
const source = raw.startsWith("@") ? readFileSync5(
|
|
5696
|
+
const source = raw.startsWith("@") ? readFileSync5(resolve9(raw.slice(1)), "utf-8") : raw;
|
|
5428
5697
|
const parsed = JSON.parse(source);
|
|
5429
5698
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
5430
5699
|
throw new Error("--input must be a JSON object.");
|
|
@@ -5525,7 +5794,7 @@ function fileInputBindingsFromStaticPipeline(staticPipeline) {
|
|
|
5525
5794
|
function isLocalFilePathValue(value) {
|
|
5526
5795
|
if (typeof value !== "string" || !value.trim()) return false;
|
|
5527
5796
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
5528
|
-
return existsSync6(
|
|
5797
|
+
return existsSync6(resolve9(value));
|
|
5529
5798
|
}
|
|
5530
5799
|
function inputContainsLocalFilePath(value) {
|
|
5531
5800
|
if (isLocalFilePathValue(value)) {
|
|
@@ -5551,7 +5820,7 @@ async function stageFileInputArgs(input) {
|
|
|
5551
5820
|
const localFiles = uniqueBindings.flatMap((binding) => {
|
|
5552
5821
|
const value = getDottedInputValue(input.runtimeInput, binding.inputPath);
|
|
5553
5822
|
if (!isLocalFilePathValue(value)) return [];
|
|
5554
|
-
const absolutePath =
|
|
5823
|
+
const absolutePath = resolve9(value);
|
|
5555
5824
|
return [{ binding, absolutePath, logicalPath: basename3(absolutePath) }];
|
|
5556
5825
|
});
|
|
5557
5826
|
if (localFiles.length === 0) {
|
|
@@ -5587,9 +5856,9 @@ function stageFile(logicalPath, absolutePath) {
|
|
|
5587
5856
|
}
|
|
5588
5857
|
function normalizePlayPath(filePath) {
|
|
5589
5858
|
try {
|
|
5590
|
-
return realpathSync.native(
|
|
5859
|
+
return realpathSync.native(resolve9(filePath));
|
|
5591
5860
|
} catch {
|
|
5592
|
-
return
|
|
5861
|
+
return resolve9(filePath);
|
|
5593
5862
|
}
|
|
5594
5863
|
}
|
|
5595
5864
|
function formatBundlingErrors(filePath, errors) {
|
|
@@ -5742,11 +6011,42 @@ function isTransientPlayStreamError(error) {
|
|
|
5742
6011
|
text
|
|
5743
6012
|
);
|
|
5744
6013
|
}
|
|
6014
|
+
function playStatusErrorText(status) {
|
|
6015
|
+
const chunks = [];
|
|
6016
|
+
const progressError = status.progress?.error;
|
|
6017
|
+
if (typeof progressError === "string" && progressError.trim()) {
|
|
6018
|
+
chunks.push(progressError.trim());
|
|
6019
|
+
}
|
|
6020
|
+
const errorValue = status.error;
|
|
6021
|
+
if (typeof errorValue === "string" && errorValue.trim()) {
|
|
6022
|
+
chunks.push(errorValue.trim());
|
|
6023
|
+
}
|
|
6024
|
+
const errors = status.errors;
|
|
6025
|
+
if (Array.isArray(errors)) {
|
|
6026
|
+
for (const error of errors) {
|
|
6027
|
+
if (typeof error === "string" && error.trim()) {
|
|
6028
|
+
chunks.push(error.trim());
|
|
6029
|
+
} else if (error && typeof error === "object") {
|
|
6030
|
+
const message = error.message;
|
|
6031
|
+
if (typeof message === "string" && message.trim()) {
|
|
6032
|
+
chunks.push(message.trim());
|
|
6033
|
+
}
|
|
6034
|
+
}
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
return chunks.join("; ") || status.status;
|
|
6038
|
+
}
|
|
6039
|
+
function isRetryablePendingStartFailure(status) {
|
|
6040
|
+
if (status.status !== "failed") return false;
|
|
6041
|
+
if (status.runId && status.runId !== "pending") return false;
|
|
6042
|
+
return isTransientPlayStreamError(new Error(playStatusErrorText(status)));
|
|
6043
|
+
}
|
|
5745
6044
|
var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
5746
6045
|
"completed",
|
|
5747
6046
|
"failed",
|
|
5748
6047
|
"cancelled"
|
|
5749
6048
|
]);
|
|
6049
|
+
var PLAY_START_TRANSIENT_RETRY_DELAYS_MS = [500, 1500];
|
|
5750
6050
|
function getEventPayload(event) {
|
|
5751
6051
|
return event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
5752
6052
|
}
|
|
@@ -5908,6 +6208,34 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
5908
6208
|
);
|
|
5909
6209
|
}
|
|
5910
6210
|
async function startAndWaitForPlayCompletionByStream(input) {
|
|
6211
|
+
for (let attempt = 0; attempt <= PLAY_START_TRANSIENT_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
6212
|
+
const status = await startAndWaitForPlayCompletionByStreamOnce(input);
|
|
6213
|
+
const retryDelayMs = PLAY_START_TRANSIENT_RETRY_DELAYS_MS[attempt];
|
|
6214
|
+
if (retryDelayMs === void 0 || !isRetryablePendingStartFailure(status)) {
|
|
6215
|
+
return status;
|
|
6216
|
+
}
|
|
6217
|
+
if (!input.jsonOutput) {
|
|
6218
|
+
input.progress.writeLine(
|
|
6219
|
+
`[play watch] start failed before run id with a transient error; retrying (${playStatusErrorText(status)})`
|
|
6220
|
+
);
|
|
6221
|
+
}
|
|
6222
|
+
recordCliTrace({
|
|
6223
|
+
phase: "cli.play_start_stream_retry",
|
|
6224
|
+
ms: 0,
|
|
6225
|
+
ok: true,
|
|
6226
|
+
playName: input.playName,
|
|
6227
|
+
attempt: attempt + 1,
|
|
6228
|
+
reason: playStatusErrorText(status)
|
|
6229
|
+
});
|
|
6230
|
+
await sleep4(retryDelayMs);
|
|
6231
|
+
}
|
|
6232
|
+
throw new DeeplineError(
|
|
6233
|
+
`Play ${input.playName} did not start after retrying transient start failures.`,
|
|
6234
|
+
void 0,
|
|
6235
|
+
"PLAY_START_RETRY_EXHAUSTED"
|
|
6236
|
+
);
|
|
6237
|
+
}
|
|
6238
|
+
async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
5911
6239
|
const startedAt = Date.now();
|
|
5912
6240
|
const dashboardUrl = buildPlayDashboardUrl(
|
|
5913
6241
|
input.client.baseUrl,
|
|
@@ -6234,14 +6562,24 @@ function buildRunWarnings(status, rowsInfo) {
|
|
|
6234
6562
|
}
|
|
6235
6563
|
return [];
|
|
6236
6564
|
}
|
|
6237
|
-
function buildRunNextCommands(
|
|
6565
|
+
function buildRunNextCommands(status) {
|
|
6566
|
+
const runId = status.runId?.trim();
|
|
6567
|
+
if (!runId) {
|
|
6568
|
+
const playName = extractRunPlayName(status);
|
|
6569
|
+
return playName ? {
|
|
6570
|
+
list: `deepline runs list --play ${playName} --json`
|
|
6571
|
+
} : {
|
|
6572
|
+
list: "deepline runs list --json"
|
|
6573
|
+
};
|
|
6574
|
+
}
|
|
6238
6575
|
const commands = {
|
|
6239
6576
|
get: `deepline runs get ${runId} --json`,
|
|
6577
|
+
full: `deepline runs get ${runId} --full --json`,
|
|
6240
6578
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
6241
6579
|
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
6242
6580
|
};
|
|
6243
|
-
if (dashboardUrl) {
|
|
6244
|
-
commands.open = `Open ${dashboardUrl} to see results.`;
|
|
6581
|
+
if (status.dashboardUrl) {
|
|
6582
|
+
commands.open = `Open ${status.dashboardUrl} to see results.`;
|
|
6245
6583
|
}
|
|
6246
6584
|
return commands;
|
|
6247
6585
|
}
|
|
@@ -6264,6 +6602,121 @@ function getTimestampField(value, key) {
|
|
|
6264
6602
|
}
|
|
6265
6603
|
return typeof field === "string" && field.trim() ? field : null;
|
|
6266
6604
|
}
|
|
6605
|
+
function getObjectField(value, key) {
|
|
6606
|
+
const field = getRecordField(value, key);
|
|
6607
|
+
return field && typeof field === "object" && !Array.isArray(field) ? field : null;
|
|
6608
|
+
}
|
|
6609
|
+
function formatCreditAmount(value) {
|
|
6610
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
6611
|
+
return String(value ?? "-");
|
|
6612
|
+
}
|
|
6613
|
+
return Number(value.toFixed(8)).toString();
|
|
6614
|
+
}
|
|
6615
|
+
function extractJsonObjectFromText(text) {
|
|
6616
|
+
const start = text.indexOf("{");
|
|
6617
|
+
if (start < 0) {
|
|
6618
|
+
return null;
|
|
6619
|
+
}
|
|
6620
|
+
const suffix = text.slice(start);
|
|
6621
|
+
try {
|
|
6622
|
+
const parsed = JSON.parse(suffix);
|
|
6623
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
6624
|
+
} catch {
|
|
6625
|
+
let depth = 0;
|
|
6626
|
+
let inString = false;
|
|
6627
|
+
let escaped = false;
|
|
6628
|
+
for (let index = start; index < text.length; index += 1) {
|
|
6629
|
+
const char = text[index];
|
|
6630
|
+
if (inString) {
|
|
6631
|
+
if (escaped) {
|
|
6632
|
+
escaped = false;
|
|
6633
|
+
} else if (char === "\\") {
|
|
6634
|
+
escaped = true;
|
|
6635
|
+
} else if (char === '"') {
|
|
6636
|
+
inString = false;
|
|
6637
|
+
}
|
|
6638
|
+
continue;
|
|
6639
|
+
}
|
|
6640
|
+
if (char === '"') {
|
|
6641
|
+
inString = true;
|
|
6642
|
+
} else if (char === "{") {
|
|
6643
|
+
depth += 1;
|
|
6644
|
+
} else if (char === "}") {
|
|
6645
|
+
depth -= 1;
|
|
6646
|
+
if (depth === 0) {
|
|
6647
|
+
try {
|
|
6648
|
+
const parsed = JSON.parse(text.slice(start, index + 1));
|
|
6649
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
6650
|
+
} catch {
|
|
6651
|
+
return null;
|
|
6652
|
+
}
|
|
6653
|
+
}
|
|
6654
|
+
}
|
|
6655
|
+
}
|
|
6656
|
+
}
|
|
6657
|
+
return null;
|
|
6658
|
+
}
|
|
6659
|
+
function extractBillingFromText(text) {
|
|
6660
|
+
if (!text) {
|
|
6661
|
+
return null;
|
|
6662
|
+
}
|
|
6663
|
+
const parsed = extractJsonObjectFromText(text);
|
|
6664
|
+
return getObjectField(parsed, "billing");
|
|
6665
|
+
}
|
|
6666
|
+
function extractToolIdFromErrorText(text) {
|
|
6667
|
+
if (!text) {
|
|
6668
|
+
return null;
|
|
6669
|
+
}
|
|
6670
|
+
const lowerToolMatch = /\btool\s+([A-Za-z0-9_.:-]+)\s+\d{3}\b/.exec(text);
|
|
6671
|
+
if (lowerToolMatch?.[1]) {
|
|
6672
|
+
return lowerToolMatch[1];
|
|
6673
|
+
}
|
|
6674
|
+
const upperToolMatch = /\bTool\s+([A-Za-z0-9_.:-]+)\s+failed\b/.exec(text);
|
|
6675
|
+
return upperToolMatch?.[1] ?? null;
|
|
6676
|
+
}
|
|
6677
|
+
function isInsufficientCreditsBilling(billing) {
|
|
6678
|
+
return billing?.kind === "insufficient_credits";
|
|
6679
|
+
}
|
|
6680
|
+
function extractBillingForStatus(status, error) {
|
|
6681
|
+
const errorBilling = getObjectField(status, "errorBilling");
|
|
6682
|
+
if (errorBilling) {
|
|
6683
|
+
return errorBilling;
|
|
6684
|
+
}
|
|
6685
|
+
const directErrors = getRecordField(status, "errors");
|
|
6686
|
+
if (Array.isArray(directErrors)) {
|
|
6687
|
+
for (const entry of directErrors) {
|
|
6688
|
+
const billing = getObjectField(entry, "billing");
|
|
6689
|
+
if (billing) {
|
|
6690
|
+
return billing;
|
|
6691
|
+
}
|
|
6692
|
+
}
|
|
6693
|
+
}
|
|
6694
|
+
const progressError = getStringField(status.progress, "error");
|
|
6695
|
+
return extractBillingFromText(error) ?? extractBillingFromText(progressError) ?? getObjectField(status, "billing");
|
|
6696
|
+
}
|
|
6697
|
+
function formatInsufficientCreditsMessage(input) {
|
|
6698
|
+
const operation = getStringField(input.billing, "operation_id") ?? getStringField(input.billing, "operation") ?? extractToolIdFromErrorText(input.error) ?? getStringField(input.billing, "provider") ?? "tool call";
|
|
6699
|
+
const balance = formatCreditAmount(input.billing.balance_credits);
|
|
6700
|
+
const required = formatCreditAmount(input.billing.required_credits);
|
|
6701
|
+
const recommended = formatCreditAmount(
|
|
6702
|
+
input.billing.recommended_add_credits ?? input.billing.needed_credits
|
|
6703
|
+
);
|
|
6704
|
+
const billingUrl = getStringField(input.billing, "billing_url");
|
|
6705
|
+
const workspace = getStringField(input.billing, "workspace_id") ?? getStringField(input.billing, "workspaceId");
|
|
6706
|
+
const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
|
|
6707
|
+
const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
|
|
6708
|
+
return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
|
|
6709
|
+
}
|
|
6710
|
+
function formatPlayErrorForDisplay(status, error) {
|
|
6711
|
+
if (!error) {
|
|
6712
|
+
return null;
|
|
6713
|
+
}
|
|
6714
|
+
const billing = extractBillingForStatus(status, error);
|
|
6715
|
+
if (isInsufficientCreditsBilling(billing)) {
|
|
6716
|
+
return formatInsufficientCreditsMessage({ billing, error });
|
|
6717
|
+
}
|
|
6718
|
+
return error;
|
|
6719
|
+
}
|
|
6267
6720
|
function normalizeRunStatusForEnvelope(status) {
|
|
6268
6721
|
const run = status.run ?? null;
|
|
6269
6722
|
return {
|
|
@@ -6314,18 +6767,33 @@ function normalizeErrorsForEnvelope(status, error) {
|
|
|
6314
6767
|
if (Array.isArray(directErrors)) {
|
|
6315
6768
|
return directErrors.filter(
|
|
6316
6769
|
(entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
|
|
6317
|
-
)
|
|
6770
|
+
).map((entry) => {
|
|
6771
|
+
const message2 = typeof entry.message === "string" && entry.message.trim() ? entry.message : error;
|
|
6772
|
+
const billing2 = getObjectField(entry, "billing");
|
|
6773
|
+
if (!isInsufficientCreditsBilling(billing2) || !message2) {
|
|
6774
|
+
return entry;
|
|
6775
|
+
}
|
|
6776
|
+
return {
|
|
6777
|
+
...entry,
|
|
6778
|
+
message: formatInsufficientCreditsMessage({ billing: billing2, error: message2 }),
|
|
6779
|
+
billing: stripProviderSpendFromBilling(billing2)
|
|
6780
|
+
};
|
|
6781
|
+
});
|
|
6318
6782
|
}
|
|
6319
6783
|
if (!error) {
|
|
6320
6784
|
return [];
|
|
6321
6785
|
}
|
|
6786
|
+
const nextCommands = buildRunNextCommands(status);
|
|
6787
|
+
const billing = extractBillingForStatus(status, error);
|
|
6788
|
+
const message = formatPlayErrorForDisplay(status, error) ?? error;
|
|
6322
6789
|
return [
|
|
6323
6790
|
{
|
|
6324
6791
|
code: getStringField(status, "errorCode") ?? "RUN_FAILED",
|
|
6325
6792
|
phase: getStringField(status, "errorPhase") ?? "runtime",
|
|
6326
|
-
message
|
|
6793
|
+
message,
|
|
6327
6794
|
retryable: typeof getRecordField(status, "retryable") === "boolean" ? getRecordField(status, "retryable") : null,
|
|
6328
|
-
|
|
6795
|
+
...billing ? { billing: stripProviderSpendFromBilling(billing) } : {},
|
|
6796
|
+
nextAction: nextCommands.get ?? nextCommands.list
|
|
6329
6797
|
}
|
|
6330
6798
|
];
|
|
6331
6799
|
}
|
|
@@ -6374,6 +6842,7 @@ function compactPlayStatus(status) {
|
|
|
6374
6842
|
) : null;
|
|
6375
6843
|
const progressError = status.progress?.error;
|
|
6376
6844
|
const error = typeof progressError === "string" ? progressError : typeof status.error === "string" ? String(status.error) : null;
|
|
6845
|
+
const displayError = formatPlayErrorForDisplay(status, error);
|
|
6377
6846
|
return {
|
|
6378
6847
|
runId: status.runId,
|
|
6379
6848
|
apiVersion: status.apiVersion ?? 1,
|
|
@@ -6386,13 +6855,13 @@ function compactPlayStatus(status) {
|
|
|
6386
6855
|
steps: normalizeStepsForEnvelope(status),
|
|
6387
6856
|
errors: normalizeErrorsForEnvelope(status, error),
|
|
6388
6857
|
logs: normalizeLogsForEnvelope(status),
|
|
6389
|
-
...
|
|
6858
|
+
...displayError ? { error: displayError } : {},
|
|
6390
6859
|
...warnings.length > 0 ? { warnings } : {},
|
|
6391
6860
|
...result !== void 0 ? { result } : {},
|
|
6392
6861
|
...status.resultView ? { resultView: status.resultView } : {},
|
|
6393
6862
|
...datasetStats ? { dataset_stats: datasetStats } : {},
|
|
6394
6863
|
...billing ? { billing } : {},
|
|
6395
|
-
next: buildRunNextCommands(status
|
|
6864
|
+
next: buildRunNextCommands(status)
|
|
6396
6865
|
};
|
|
6397
6866
|
}
|
|
6398
6867
|
function enrichPlayStatusWithDatasetStats(status) {
|
|
@@ -6466,7 +6935,8 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
6466
6935
|
lines.push(...formatDatasetStatsLines(datasetStats));
|
|
6467
6936
|
const progressError = status.progress?.error;
|
|
6468
6937
|
if (progressError && typeof progressError === "string") {
|
|
6469
|
-
|
|
6938
|
+
const displayError = formatPlayErrorForDisplay(status, progressError) ?? progressError;
|
|
6939
|
+
lines.push(` error: ${displayError.slice(0, 200)}`);
|
|
6470
6940
|
}
|
|
6471
6941
|
const renderedServerView = renderServerResultView(status.resultView);
|
|
6472
6942
|
if (result) {
|
|
@@ -6490,8 +6960,11 @@ var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
|
6490
6960
|
function shellSingleQuote(value) {
|
|
6491
6961
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
6492
6962
|
}
|
|
6963
|
+
function sqlStringLiteral(value) {
|
|
6964
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
6965
|
+
}
|
|
6493
6966
|
function runExportRetryCommand(runId, outPath, datasetPath) {
|
|
6494
|
-
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote(
|
|
6967
|
+
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote(resolve9(outPath))}`;
|
|
6495
6968
|
}
|
|
6496
6969
|
function extractRunPlayName(status) {
|
|
6497
6970
|
const run = status.run;
|
|
@@ -6508,6 +6981,26 @@ function extractRunPlayName(status) {
|
|
|
6508
6981
|
}
|
|
6509
6982
|
return null;
|
|
6510
6983
|
}
|
|
6984
|
+
function normalizeCustomerDbIdentifier(value) {
|
|
6985
|
+
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
6986
|
+
}
|
|
6987
|
+
function buildCustomerDbQueryPlan(input) {
|
|
6988
|
+
const playName = extractRunPlayName(input.status);
|
|
6989
|
+
const tableNamespace = input.rowsInfo.tableNamespace?.trim();
|
|
6990
|
+
if (!playName || !tableNamespace || input.rowsInfo.totalRows <= 0) {
|
|
6991
|
+
return null;
|
|
6992
|
+
}
|
|
6993
|
+
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
6994
|
+
tableNamespace
|
|
6995
|
+
)}`;
|
|
6996
|
+
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input.status.runId)} limit ${input.rowsInfo.totalRows}`;
|
|
6997
|
+
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input.rowsInfo.totalRows}`;
|
|
6998
|
+
return {
|
|
6999
|
+
sql,
|
|
7000
|
+
json: `${base} --json`,
|
|
7001
|
+
csv: `${base} --format csv --out ${shellSingleQuote(resolve9(input.outPath))}`
|
|
7002
|
+
};
|
|
7003
|
+
}
|
|
6511
7004
|
function exportableSheetRow(row) {
|
|
6512
7005
|
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
6513
7006
|
return null;
|
|
@@ -6679,6 +7172,60 @@ async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
|
6679
7172
|
}
|
|
6680
7173
|
return { path: writeCanonicalRowsCsv(rowsInfo, outPath), rowsInfo };
|
|
6681
7174
|
}
|
|
7175
|
+
function extractActiveRunsFromError(error) {
|
|
7176
|
+
if (!(error instanceof DeeplineError)) {
|
|
7177
|
+
return [];
|
|
7178
|
+
}
|
|
7179
|
+
const response = error.details?.response;
|
|
7180
|
+
if (!response || typeof response !== "object" || Array.isArray(response)) {
|
|
7181
|
+
return [];
|
|
7182
|
+
}
|
|
7183
|
+
const details = response.details;
|
|
7184
|
+
if (!details || typeof details !== "object" || Array.isArray(details)) {
|
|
7185
|
+
return [];
|
|
7186
|
+
}
|
|
7187
|
+
const activeRuns = details.activeRuns;
|
|
7188
|
+
return Array.isArray(activeRuns) ? activeRuns.filter(
|
|
7189
|
+
(run) => Boolean(run) && typeof run === "object" && !Array.isArray(run)
|
|
7190
|
+
) : [];
|
|
7191
|
+
}
|
|
7192
|
+
function activeRunId(run) {
|
|
7193
|
+
return getStringField(run, "workflowId") ?? getStringField(run, "runId");
|
|
7194
|
+
}
|
|
7195
|
+
function formatActiveRunConflictError(input) {
|
|
7196
|
+
const lines = [
|
|
7197
|
+
`Active run exists for ${input.playName}. Use --force to supersede, or inspect/stop the active run first.`
|
|
7198
|
+
];
|
|
7199
|
+
for (const run of input.activeRuns.slice(0, 3)) {
|
|
7200
|
+
const runId = activeRunId(run);
|
|
7201
|
+
if (!runId) {
|
|
7202
|
+
continue;
|
|
7203
|
+
}
|
|
7204
|
+
const status = getStringField(run, "status");
|
|
7205
|
+
const startedAt = getStringField(run, "startedAt") ?? getStringField(run, "startTime");
|
|
7206
|
+
lines.push(
|
|
7207
|
+
` active: ${runId}${status ? ` status=${status}` : ""}${startedAt ? ` startedAt=${startedAt}` : ""}`
|
|
7208
|
+
);
|
|
7209
|
+
lines.push(` get: deepline runs get ${runId} --json`);
|
|
7210
|
+
lines.push(
|
|
7211
|
+
` stop: deepline runs stop ${runId} --reason "stale lock" --json`
|
|
7212
|
+
);
|
|
7213
|
+
}
|
|
7214
|
+
lines.push(` rerun: add --force to the same deepline plays run command`);
|
|
7215
|
+
return lines.join("\n");
|
|
7216
|
+
}
|
|
7217
|
+
function normalizePlayStartError(error, playName) {
|
|
7218
|
+
const activeRuns = extractActiveRunsFromError(error);
|
|
7219
|
+
if (activeRuns.length === 0) {
|
|
7220
|
+
return error;
|
|
7221
|
+
}
|
|
7222
|
+
return new DeeplineError(
|
|
7223
|
+
formatActiveRunConflictError({ playName, activeRuns }),
|
|
7224
|
+
error instanceof DeeplineError ? error.statusCode : 409,
|
|
7225
|
+
"ACTIVE_RUN_EXISTS",
|
|
7226
|
+
error instanceof DeeplineError ? error.details : void 0
|
|
7227
|
+
);
|
|
7228
|
+
}
|
|
6682
7229
|
function renderServerResultView(value) {
|
|
6683
7230
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6684
7231
|
return { lines: [], actions: [] };
|
|
@@ -6722,6 +7269,10 @@ function renderServerResultView(value) {
|
|
|
6722
7269
|
);
|
|
6723
7270
|
}
|
|
6724
7271
|
const tables = Array.isArray(view.tables) ? view.tables : [];
|
|
7272
|
+
const topLevelOutputTable = view.topLevelOutputTable && typeof view.topLevelOutputTable === "object" && !Array.isArray(view.topLevelOutputTable) ? view.topLevelOutputTable : null;
|
|
7273
|
+
if (typeof topLevelOutputTable?.queryCommand === "string") {
|
|
7274
|
+
lines.push(` top-level outputs: ${topLevelOutputTable.queryCommand}`);
|
|
7275
|
+
}
|
|
6725
7276
|
if (tables.length > 0) {
|
|
6726
7277
|
lines.push(" tables:");
|
|
6727
7278
|
for (const table of tables.slice(0, 6)) {
|
|
@@ -6738,6 +7289,21 @@ function renderServerResultView(value) {
|
|
|
6738
7289
|
lines.push(
|
|
6739
7290
|
` ${String(table.tableNamespace ?? "table")}${lineLabel}: ${rowLabel}${details.join(" ")}`
|
|
6740
7291
|
);
|
|
7292
|
+
if (typeof table.queryDatasetCommand === "string") {
|
|
7293
|
+
lines.push(` inspect rows: ${table.queryDatasetCommand}`);
|
|
7294
|
+
}
|
|
7295
|
+
if (table.debugHelp && typeof table.debugHelp === "object" && !Array.isArray(table.debugHelp)) {
|
|
7296
|
+
const debugHelp = table.debugHelp;
|
|
7297
|
+
const rawResultFields = Array.isArray(debugHelp.rawResultFields) ? debugHelp.rawResultFields.filter(
|
|
7298
|
+
(field) => typeof field === "string"
|
|
7299
|
+
) : [];
|
|
7300
|
+
if (rawResultFields.length > 0) {
|
|
7301
|
+
lines.push(` tool-result columns: ${rawResultFields.join(", ")}`);
|
|
7302
|
+
}
|
|
7303
|
+
}
|
|
7304
|
+
if (typeof table.slowExportAsCsvCommand === "string") {
|
|
7305
|
+
lines.push(` export rows: ${table.slowExportAsCsvCommand}`);
|
|
7306
|
+
}
|
|
6741
7307
|
}
|
|
6742
7308
|
}
|
|
6743
7309
|
return { lines: lines.length > 1 ? lines : [], actions: [] };
|
|
@@ -6763,7 +7329,8 @@ function writeStartedPlayRun(input) {
|
|
|
6763
7329
|
` get status: deepline runs get ${input.runId} --json`,
|
|
6764
7330
|
` logs: deepline runs logs ${input.runId} --json`,
|
|
6765
7331
|
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`,
|
|
6766
|
-
` result JSON: deepline runs get ${input.runId} --json
|
|
7332
|
+
` result JSON: deepline runs get ${input.runId} --json`,
|
|
7333
|
+
` full debug JSON: deepline runs get ${input.runId} --full --json`
|
|
6767
7334
|
];
|
|
6768
7335
|
if (input.dashboardUrl) {
|
|
6769
7336
|
lines.push(` play page: ${input.dashboardUrl}`);
|
|
@@ -6914,11 +7481,11 @@ function shouldUseLocalOnlyPlayCheck() {
|
|
|
6914
7481
|
async function handlePlayCheck(args) {
|
|
6915
7482
|
const options = parsePlayCheckOptions(args);
|
|
6916
7483
|
if (!isFileTarget(options.target)) {
|
|
6917
|
-
const resolved =
|
|
7484
|
+
const resolved = resolve9(options.target);
|
|
6918
7485
|
console.error(`File not found: ${resolved}`);
|
|
6919
7486
|
return 1;
|
|
6920
7487
|
}
|
|
6921
|
-
const absolutePlayPath =
|
|
7488
|
+
const absolutePlayPath = resolve9(options.target);
|
|
6922
7489
|
const sourceCode = readFileSync5(absolutePlayPath, "utf-8");
|
|
6923
7490
|
let graph;
|
|
6924
7491
|
try {
|
|
@@ -6982,7 +7549,7 @@ async function handleFileBackedRun(options) {
|
|
|
6982
7549
|
}
|
|
6983
7550
|
const client = new DeeplineClient();
|
|
6984
7551
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
6985
|
-
const absolutePlayPath =
|
|
7552
|
+
const absolutePlayPath = resolve9(options.target.path);
|
|
6986
7553
|
progress.phase("compiling play");
|
|
6987
7554
|
const sourceCode = traceCliSync(
|
|
6988
7555
|
"cli.play_file_read_source",
|
|
@@ -7068,6 +7635,8 @@ async function handleFileBackedRun(options) {
|
|
|
7068
7635
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
7069
7636
|
noOpen: options.noOpen,
|
|
7070
7637
|
progress
|
|
7638
|
+
}).catch((error) => {
|
|
7639
|
+
throw normalizePlayStartError(error, playName);
|
|
7071
7640
|
})
|
|
7072
7641
|
);
|
|
7073
7642
|
if (finalStatus.status === "completed") {
|
|
@@ -7086,7 +7655,9 @@ async function handleFileBackedRun(options) {
|
|
|
7086
7655
|
const started = await traceCliSpan(
|
|
7087
7656
|
"cli.play_start_unwatched",
|
|
7088
7657
|
{ targetKind: "file", playName },
|
|
7089
|
-
() => client.startPlayRun(startRequest)
|
|
7658
|
+
() => client.startPlayRun(startRequest).catch((error) => {
|
|
7659
|
+
throw normalizePlayStartError(error, playName);
|
|
7660
|
+
})
|
|
7090
7661
|
);
|
|
7091
7662
|
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7092
7663
|
openPlayDashboard({
|
|
@@ -7203,6 +7774,8 @@ async function handleNamedRun(options) {
|
|
|
7203
7774
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
7204
7775
|
noOpen: options.noOpen,
|
|
7205
7776
|
progress
|
|
7777
|
+
}).catch((error) => {
|
|
7778
|
+
throw normalizePlayStartError(error, playName);
|
|
7206
7779
|
})
|
|
7207
7780
|
);
|
|
7208
7781
|
if (finalStatus.status === "completed") {
|
|
@@ -7221,7 +7794,9 @@ async function handleNamedRun(options) {
|
|
|
7221
7794
|
const started = await traceCliSpan(
|
|
7222
7795
|
"cli.play_start_unwatched",
|
|
7223
7796
|
{ targetKind: "name", playName },
|
|
7224
|
-
() => client.startPlayRun(startRequest)
|
|
7797
|
+
() => client.startPlayRun(startRequest).catch((error) => {
|
|
7798
|
+
throw normalizePlayStartError(error, playName);
|
|
7799
|
+
})
|
|
7225
7800
|
);
|
|
7226
7801
|
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7227
7802
|
openPlayDashboard({
|
|
@@ -7247,7 +7822,7 @@ async function handlePlayRun(args) {
|
|
|
7247
7822
|
if (isFileTarget(options.target.path)) {
|
|
7248
7823
|
return handleFileBackedRun(options);
|
|
7249
7824
|
}
|
|
7250
|
-
const resolved =
|
|
7825
|
+
const resolved = resolve9(options.target.path);
|
|
7251
7826
|
console.error(`File not found: ${resolved}`);
|
|
7252
7827
|
const dir = dirname8(resolved);
|
|
7253
7828
|
if (existsSync6(dir)) {
|
|
@@ -7394,14 +7969,14 @@ async function handleRunLogs(args) {
|
|
|
7394
7969
|
continue;
|
|
7395
7970
|
}
|
|
7396
7971
|
if (arg === "--out" && args[index + 1]) {
|
|
7397
|
-
outPath =
|
|
7972
|
+
outPath = resolve9(args[++index]);
|
|
7398
7973
|
}
|
|
7399
7974
|
}
|
|
7400
7975
|
const client = new DeeplineClient();
|
|
7401
7976
|
const status = await client.runs.get(runId);
|
|
7402
7977
|
const logs = status.progress?.logs ?? [];
|
|
7403
7978
|
if (outPath) {
|
|
7404
|
-
|
|
7979
|
+
writeFileSync6(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
7405
7980
|
printCommandEnvelope({
|
|
7406
7981
|
runId: status.runId,
|
|
7407
7982
|
log_path: outPath,
|
|
@@ -7457,7 +8032,7 @@ async function handleRunStop(args) {
|
|
|
7457
8032
|
return 0;
|
|
7458
8033
|
}
|
|
7459
8034
|
async function handleRunExport(args) {
|
|
7460
|
-
const usage = "Usage: deepline runs export <run-id> [--dataset result.rows] --out output.csv [--json]";
|
|
8035
|
+
const usage = "Usage: deepline runs export <run-id> [--dataset result.rows] --out output.csv [--metadata-out export.json] [--json]";
|
|
7461
8036
|
let runId;
|
|
7462
8037
|
try {
|
|
7463
8038
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -7467,14 +8042,19 @@ async function handleRunExport(args) {
|
|
|
7467
8042
|
}
|
|
7468
8043
|
let outPath = null;
|
|
7469
8044
|
let datasetPath = null;
|
|
8045
|
+
let metadataOutPath = null;
|
|
7470
8046
|
for (let index = 0; index < args.length; index += 1) {
|
|
7471
8047
|
const arg = args[index];
|
|
7472
8048
|
if (arg === "--out" && args[index + 1]) {
|
|
7473
|
-
outPath =
|
|
8049
|
+
outPath = resolve9(args[++index]);
|
|
7474
8050
|
continue;
|
|
7475
8051
|
}
|
|
7476
8052
|
if (arg === "--dataset" && args[index + 1]) {
|
|
7477
8053
|
datasetPath = args[++index];
|
|
8054
|
+
continue;
|
|
8055
|
+
}
|
|
8056
|
+
if (arg === "--metadata-out" && args[index + 1]) {
|
|
8057
|
+
metadataOutPath = resolve9(args[++index]);
|
|
7478
8058
|
}
|
|
7479
8059
|
}
|
|
7480
8060
|
if (!outPath) {
|
|
@@ -7486,15 +8066,59 @@ async function handleRunExport(args) {
|
|
|
7486
8066
|
const exportResult = await exportPlayStatusRows(client, status, outPath, {
|
|
7487
8067
|
datasetPath
|
|
7488
8068
|
});
|
|
7489
|
-
|
|
8069
|
+
const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
|
|
8070
|
+
const queryPlan = exportResult && outPath ? buildCustomerDbQueryPlan({
|
|
8071
|
+
status,
|
|
8072
|
+
rowsInfo: exportResult.rowsInfo,
|
|
8073
|
+
outPath
|
|
8074
|
+
}) : null;
|
|
8075
|
+
const next = {
|
|
8076
|
+
...buildRunNextCommands(status),
|
|
8077
|
+
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source),
|
|
8078
|
+
...queryPlan ? {
|
|
8079
|
+
queryJson: queryPlan.json,
|
|
8080
|
+
queryCsv: queryPlan.csv
|
|
8081
|
+
} : {}
|
|
8082
|
+
};
|
|
8083
|
+
const payload = {
|
|
7490
8084
|
runId: status.runId,
|
|
7491
8085
|
...datasetPath ? { dataset: datasetPath } : {},
|
|
7492
8086
|
csv_path: exportResult?.path ?? null,
|
|
8087
|
+
source,
|
|
7493
8088
|
rowCount: exportResult?.rowsInfo.totalRows ?? null,
|
|
7494
8089
|
columns: exportResult?.rowsInfo.columns ?? [],
|
|
8090
|
+
...queryPlan ? {
|
|
8091
|
+
query: {
|
|
8092
|
+
sql: queryPlan.sql,
|
|
8093
|
+
json: queryPlan.json,
|
|
8094
|
+
csv: queryPlan.csv
|
|
8095
|
+
}
|
|
8096
|
+
} : {},
|
|
8097
|
+
...metadataOutPath ? { metadata_path: metadataOutPath } : {},
|
|
7495
8098
|
local: { csv_path: exportResult?.path ?? null },
|
|
7496
|
-
|
|
7497
|
-
|
|
8099
|
+
next,
|
|
8100
|
+
render: {
|
|
8101
|
+
sections: [
|
|
8102
|
+
{
|
|
8103
|
+
title: "run export",
|
|
8104
|
+
lines: [
|
|
8105
|
+
`Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
|
|
8106
|
+
...source ? [`source=${source}`] : [],
|
|
8107
|
+
...queryPlan ? [`query=${queryPlan.json}`] : []
|
|
8108
|
+
]
|
|
8109
|
+
}
|
|
8110
|
+
]
|
|
8111
|
+
}
|
|
8112
|
+
};
|
|
8113
|
+
if (metadataOutPath) {
|
|
8114
|
+
writeFileSync6(
|
|
8115
|
+
metadataOutPath,
|
|
8116
|
+
`${JSON.stringify(payload, null, 2)}
|
|
8117
|
+
`,
|
|
8118
|
+
"utf-8"
|
|
8119
|
+
);
|
|
8120
|
+
}
|
|
8121
|
+
printCommandEnvelope(payload, { json: argsWantJson(args) });
|
|
7498
8122
|
return 0;
|
|
7499
8123
|
}
|
|
7500
8124
|
async function handlePlayGet(args) {
|
|
@@ -7511,10 +8135,10 @@ async function handlePlayGet(args) {
|
|
|
7511
8135
|
for (let index = 1; index < args.length; index += 1) {
|
|
7512
8136
|
const arg = args[index];
|
|
7513
8137
|
if (arg === "--out" && args[index + 1]) {
|
|
7514
|
-
outPath =
|
|
8138
|
+
outPath = resolve9(args[++index]);
|
|
7515
8139
|
}
|
|
7516
8140
|
}
|
|
7517
|
-
const playName = isFileTarget(target) ? extractPlayName(readFileSync5(
|
|
8141
|
+
const playName = isFileTarget(target) ? extractPlayName(readFileSync5(resolve9(target), "utf-8"), resolve9(target)) : parseReferencedPlayTarget(target).playName;
|
|
7518
8142
|
const detail = isFileTarget(target) ? await client.getPlay(playName) : await assertCanonicalNamedPlayReference(client, target);
|
|
7519
8143
|
const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
|
|
7520
8144
|
const materializedFile = outPath ? materializeRemotePlaySource({
|
|
@@ -7806,7 +8430,7 @@ async function handlePlayPublish(args) {
|
|
|
7806
8430
|
}
|
|
7807
8431
|
let graph;
|
|
7808
8432
|
try {
|
|
7809
|
-
graph = await collectBundledPlayGraph(
|
|
8433
|
+
graph = await collectBundledPlayGraph(resolve9(playName));
|
|
7810
8434
|
await compileBundledPlayGraphManifests(client, graph);
|
|
7811
8435
|
await publishImportedPlayDependencies(client, graph);
|
|
7812
8436
|
} catch (error) {
|
|
@@ -8292,30 +8916,34 @@ Examples:
|
|
|
8292
8916
|
Notes:
|
|
8293
8917
|
Writes a returned dataset handle to the requested local CSV path. Use runs get
|
|
8294
8918
|
first to inspect dataset paths like result.rows or result.nested.contacts.
|
|
8919
|
+
--metadata-out writes the same export metadata object returned by --json,
|
|
8920
|
+
including source and follow-on customer-db query commands when available.
|
|
8295
8921
|
|
|
8296
8922
|
Examples:
|
|
8297
8923
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
8298
8924
|
deepline runs export play/my-play/run/20260501t000000-000 --dataset result.rows --out output.csv
|
|
8925
|
+
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --metadata-out output.meta.json
|
|
8299
8926
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --json
|
|
8300
8927
|
`
|
|
8301
|
-
).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) => {
|
|
8928
|
+
).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) => {
|
|
8302
8929
|
process.exitCode = await handleRunExport([
|
|
8303
8930
|
runId,
|
|
8304
8931
|
...options.dataset ? ["--dataset", options.dataset] : [],
|
|
8305
8932
|
"--out",
|
|
8306
8933
|
options.out,
|
|
8934
|
+
...options.metadataOut ? ["--metadata-out", options.metadataOut] : [],
|
|
8307
8935
|
...options.json ? ["--json"] : []
|
|
8308
8936
|
]);
|
|
8309
8937
|
});
|
|
8310
8938
|
}
|
|
8311
8939
|
|
|
8312
8940
|
// src/cli/commands/tools.ts
|
|
8313
|
-
import { chmodSync, mkdtempSync, writeFileSync as
|
|
8941
|
+
import { chmodSync, mkdtempSync, writeFileSync as writeFileSync8 } from "fs";
|
|
8314
8942
|
import { tmpdir as tmpdir3 } from "os";
|
|
8315
8943
|
import { join as join8 } from "path";
|
|
8316
8944
|
|
|
8317
8945
|
// src/tool-output.ts
|
|
8318
|
-
import { mkdirSync as mkdirSync4, writeFileSync as
|
|
8946
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
8319
8947
|
import { homedir as homedir3 } from "os";
|
|
8320
8948
|
import { join as join7 } from "path";
|
|
8321
8949
|
function isPlainObject(value) {
|
|
@@ -8340,6 +8968,21 @@ function normalizeRows(value) {
|
|
|
8340
8968
|
}
|
|
8341
8969
|
function candidateRoots(payload) {
|
|
8342
8970
|
const roots = [{ path: null, value: payload }];
|
|
8971
|
+
if (isPlainObject(payload) && isPlainObject(payload.toolResponse)) {
|
|
8972
|
+
roots.push({ path: "toolResponse", value: payload.toolResponse });
|
|
8973
|
+
if (Object.prototype.hasOwnProperty.call(payload.toolResponse, "raw")) {
|
|
8974
|
+
roots.push({
|
|
8975
|
+
path: "toolResponse.raw",
|
|
8976
|
+
value: payload.toolResponse.raw
|
|
8977
|
+
});
|
|
8978
|
+
}
|
|
8979
|
+
}
|
|
8980
|
+
if (isPlainObject(payload) && isPlainObject(payload.output)) {
|
|
8981
|
+
roots.push({ path: "output", value: payload.output });
|
|
8982
|
+
if (Object.prototype.hasOwnProperty.call(payload.output, "body")) {
|
|
8983
|
+
roots.push({ path: "output.body", value: payload.output.body });
|
|
8984
|
+
}
|
|
8985
|
+
}
|
|
8343
8986
|
if (isPlainObject(payload) && isPlainObject(payload.result)) {
|
|
8344
8987
|
roots.push({ path: "result", value: payload.result });
|
|
8345
8988
|
if (isPlainObject(payload.result.data)) {
|
|
@@ -8399,7 +9042,7 @@ function ensureOutputDir() {
|
|
|
8399
9042
|
function writeJsonOutputFile(payload, stem) {
|
|
8400
9043
|
const outputDir = ensureOutputDir();
|
|
8401
9044
|
const outputPath = join7(outputDir, `${stem}_${Date.now()}.json`);
|
|
8402
|
-
|
|
9045
|
+
writeFileSync7(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
8403
9046
|
return outputPath;
|
|
8404
9047
|
}
|
|
8405
9048
|
function writeCsvOutputFile(rows, stem) {
|
|
@@ -8427,7 +9070,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
8427
9070
|
for (const row of rows) {
|
|
8428
9071
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
8429
9072
|
}
|
|
8430
|
-
|
|
9073
|
+
writeFileSync7(outputPath, `${lines.join("\n")}
|
|
8431
9074
|
`, "utf-8");
|
|
8432
9075
|
const previewRows = rows.slice(0, 5);
|
|
8433
9076
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -8473,8 +9116,7 @@ async function listTools(args) {
|
|
|
8473
9116
|
title: `${items.length} tools available:`,
|
|
8474
9117
|
lines: items.flatMap((item) => {
|
|
8475
9118
|
const cats = item.categories.length ? ` [${item.categories.join(", ")}]` : "";
|
|
8476
|
-
|
|
8477
|
-
return [`${item.toolId}${cats}`, ` ${item.description}${listHint}`];
|
|
9119
|
+
return [`${item.toolId}${cats}`, ` ${item.description}`];
|
|
8478
9120
|
})
|
|
8479
9121
|
}
|
|
8480
9122
|
]
|
|
@@ -8553,7 +9195,7 @@ Common commands:
|
|
|
8553
9195
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
8554
9196
|
|
|
8555
9197
|
Output:
|
|
8556
|
-
Use describe for tool contracts.
|
|
9198
|
+
Use describe for tool contracts.
|
|
8557
9199
|
Use execute to run a tool. run is accepted as a compatibility alias.
|
|
8558
9200
|
`
|
|
8559
9201
|
);
|
|
@@ -8600,8 +9242,8 @@ Examples:
|
|
|
8600
9242
|
`
|
|
8601
9243
|
Notes:
|
|
8602
9244
|
Shows the tool contract, input schema, output schema, Deepline cost, aliases,
|
|
8603
|
-
and metadata. describe is the
|
|
8604
|
-
|
|
9245
|
+
and metadata. describe is the supported discovery verb. get is removed in
|
|
9246
|
+
the V2 SDK CLI; use describe for the same metadata surface.
|
|
8605
9247
|
|
|
8606
9248
|
Examples:
|
|
8607
9249
|
deepline tools describe hunter_email_verifier
|
|
@@ -8614,7 +9256,22 @@ Examples:
|
|
|
8614
9256
|
...options.json ? ["--json"] : []
|
|
8615
9257
|
]);
|
|
8616
9258
|
});
|
|
8617
|
-
addToolMetadataCommand(tools.command("describe <toolId>")
|
|
9259
|
+
addToolMetadataCommand(tools.command("describe <toolId>"));
|
|
9260
|
+
tools.command("get <toolId>").description("Deprecated. Use tools describe.").addHelpText(
|
|
9261
|
+
"after",
|
|
9262
|
+
`
|
|
9263
|
+
Examples:
|
|
9264
|
+
deepline tools describe hunter_email_verifier --json
|
|
9265
|
+
`
|
|
9266
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (toolId, options) => {
|
|
9267
|
+
const message = `tools get has been removed from the V2 SDK CLI. Use: deepline tools describe ${toolId} --json`;
|
|
9268
|
+
if (options.json || shouldEmitJson()) {
|
|
9269
|
+
printJsonError({ message, code: "TOOLS_GET_REMOVED" });
|
|
9270
|
+
} else {
|
|
9271
|
+
console.error(message);
|
|
9272
|
+
}
|
|
9273
|
+
process.exitCode = 2;
|
|
9274
|
+
});
|
|
8618
9275
|
tools.command("execute <toolId>").alias("run").description("Execute a tool by id.").addHelpText(
|
|
8619
9276
|
"after",
|
|
8620
9277
|
`
|
|
@@ -8623,7 +9280,7 @@ Notes:
|
|
|
8623
9280
|
waterfalls, row maps, checkpoints, and retries.
|
|
8624
9281
|
execute is the canonical execution verb. run is a compatibility alias.
|
|
8625
9282
|
Calling a provider-backed tool can spend Deepline credits. Use --json for the
|
|
8626
|
-
stable result payload
|
|
9283
|
+
stable result payload plus output preview and debugging helpers.
|
|
8627
9284
|
|
|
8628
9285
|
Examples:
|
|
8629
9286
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
@@ -8636,7 +9293,7 @@ Examples:
|
|
|
8636
9293
|
}, []).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(
|
|
8637
9294
|
"--output-format <format>",
|
|
8638
9295
|
"Output format: auto, csv, csv_file, json, or json_file"
|
|
8639
|
-
).option("--
|
|
9296
|
+
).option("--no-preview", "Only print the extracted output path when applicable").action(async (toolId, options) => {
|
|
8640
9297
|
const args = [
|
|
8641
9298
|
toolId,
|
|
8642
9299
|
...options.param.flatMap((value) => ["--param", value]),
|
|
@@ -8645,7 +9302,6 @@ Examples:
|
|
|
8645
9302
|
...options.input ? ["--input", options.input] : [],
|
|
8646
9303
|
...options.payload ? ["--payload", options.payload] : [],
|
|
8647
9304
|
...options.outputFormat ? ["--output-format", options.outputFormat] : [],
|
|
8648
|
-
...options.fullOutput ? ["--full-output"] : [],
|
|
8649
9305
|
...options.preview === false ? ["--no-preview"] : []
|
|
8650
9306
|
];
|
|
8651
9307
|
process.exitCode = await executeTool(args);
|
|
@@ -8670,13 +9326,29 @@ async function getTool(args) {
|
|
|
8670
9326
|
throw error;
|
|
8671
9327
|
}
|
|
8672
9328
|
if (argsWantJson(args)) {
|
|
8673
|
-
process.stdout.write(`${JSON.stringify(tool)}
|
|
9329
|
+
process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
|
|
8674
9330
|
`);
|
|
8675
9331
|
return 0;
|
|
8676
9332
|
}
|
|
8677
9333
|
printToolDetails(tool, toolId);
|
|
8678
9334
|
return 0;
|
|
8679
9335
|
}
|
|
9336
|
+
function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
9337
|
+
const toolId = String(tool.toolId || requestedToolId);
|
|
9338
|
+
return {
|
|
9339
|
+
...tool,
|
|
9340
|
+
toolId,
|
|
9341
|
+
provider: tool.provider,
|
|
9342
|
+
displayName: tool.displayName,
|
|
9343
|
+
runtimeOutputHelp: {
|
|
9344
|
+
contract: "tools describe shows the declared schema and semantic getters; it is not an observed provider response.",
|
|
9345
|
+
observeActualShape: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
9346
|
+
observedOutput: `deepline tools execute ${toolId} --input '{...}' --json`,
|
|
9347
|
+
forPlayGetterBugs: "Run the play, then inspect the emitted table commands from runs get. Use deepline db query against the run tables before editing getters.",
|
|
9348
|
+
executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run tables."
|
|
9349
|
+
}
|
|
9350
|
+
};
|
|
9351
|
+
}
|
|
8680
9352
|
function printToolDetails(tool, requestedToolId) {
|
|
8681
9353
|
const toolId = String(tool.toolId || requestedToolId);
|
|
8682
9354
|
const operation = typeof tool.operation === "string" ? tool.operation : "";
|
|
@@ -8695,7 +9367,12 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8695
9367
|
const stepContributions = arrayField(tool, "stepContributions", "step_contributions");
|
|
8696
9368
|
const playExpansion = recordField(tool, "playExpansion", "play_expansion");
|
|
8697
9369
|
const samples = recordField(tool, "samples");
|
|
9370
|
+
const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
|
|
8698
9371
|
console.log(`Tool: ${toolId}`);
|
|
9372
|
+
console.log(" Runtime output help:");
|
|
9373
|
+
console.log(" describe shows declared schema/getters, not an observed provider response");
|
|
9374
|
+
console.log(` observe actual shape: deepline tools execute ${toolId} --input '{...}' --json`);
|
|
9375
|
+
console.log(" for play getter bugs: run the play, then use the db query commands printed by runs get");
|
|
8699
9376
|
if (displayName) {
|
|
8700
9377
|
console.log(" Display name:");
|
|
8701
9378
|
console.log(` ${displayName}`);
|
|
@@ -8758,14 +9435,16 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8758
9435
|
console.log(" Tip: pass --payload with a JSON object.");
|
|
8759
9436
|
}
|
|
8760
9437
|
printSamples(samples);
|
|
9438
|
+
printUsageGuidance(usageGuidance);
|
|
8761
9439
|
if (isPlayTool(tool)) {
|
|
8762
9440
|
console.log(" Play contract:");
|
|
8763
9441
|
console.log(" - This is a deepline-native waterfall; the returned rows are extracted by target getters, not by hand-authored payload shape.");
|
|
8764
9442
|
if (playExpansion && typeof playExpansion.group === "string" && playExpansion.group.trim()) {
|
|
8765
9443
|
console.log(` - Output alias/runtime group is: ${playExpansion.group.trim()}`);
|
|
8766
9444
|
}
|
|
8767
|
-
const
|
|
8768
|
-
const
|
|
9445
|
+
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult");
|
|
9446
|
+
const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9447
|
+
const targets = extractedValues.map((entry) => isRecord3(entry) && typeof entry.name === "string" ? entry.name : "").filter(Boolean).sort();
|
|
8769
9448
|
if (targets.length) {
|
|
8770
9449
|
console.log(` - Built-in extract targets: ${targets.join(", ")}`);
|
|
8771
9450
|
}
|
|
@@ -8784,7 +9463,39 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8784
9463
|
} else {
|
|
8785
9464
|
console.log(` deepline tools execute ${toolId} --payload '{...}'`);
|
|
8786
9465
|
}
|
|
8787
|
-
console.log(" deepline tools
|
|
9466
|
+
console.log(" deepline tools describe <tool_id> --json");
|
|
9467
|
+
}
|
|
9468
|
+
function printUsageGuidance(usageGuidance) {
|
|
9469
|
+
if (Object.keys(usageGuidance).length === 0) return;
|
|
9470
|
+
const execute = stringField(usageGuidance, "execute");
|
|
9471
|
+
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
|
|
9472
|
+
const toolResponse = recordField(toolExecutionResult, "toolResponse", "tool_response");
|
|
9473
|
+
const extractedLists = arrayField(toolExecutionResult, "extractedLists", "extracted_lists");
|
|
9474
|
+
const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9475
|
+
console.log(" Usage guidance:");
|
|
9476
|
+
if (execute) console.log(` ${execute}`);
|
|
9477
|
+
const raw = stringField(toolResponse, "raw");
|
|
9478
|
+
const meta = stringField(toolResponse, "meta");
|
|
9479
|
+
if (raw) console.log(` Raw tool response: ${raw}`);
|
|
9480
|
+
if (meta) console.log(` Tool response metadata: ${meta}`);
|
|
9481
|
+
printExtractions("Extracted lists", extractedLists);
|
|
9482
|
+
printExtractions("Extracted values", extractedValues);
|
|
9483
|
+
}
|
|
9484
|
+
function printExtractions(label, entries) {
|
|
9485
|
+
if (!entries.length) return;
|
|
9486
|
+
console.log(` ${label}:`);
|
|
9487
|
+
for (const entry of entries) {
|
|
9488
|
+
if (!isRecord3(entry)) continue;
|
|
9489
|
+
const name = stringField(entry, "name");
|
|
9490
|
+
const expression = stringField(entry, "expression");
|
|
9491
|
+
const details = recordField(entry, "details");
|
|
9492
|
+
const rawToolOutputPaths = arrayField(details, "rawToolOutputPaths", "raw_tool_output_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9493
|
+
const candidatePaths = arrayField(details, "candidatePaths", "candidate_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9494
|
+
if (!name || !expression) continue;
|
|
9495
|
+
const paths = candidatePaths.length ? candidatePaths : rawToolOutputPaths;
|
|
9496
|
+
const pathSuffix = paths.length ? ` from ${paths.join(", ")}` : "";
|
|
9497
|
+
console.log(` - ${name}: ${expression}${pathSuffix}`);
|
|
9498
|
+
}
|
|
8788
9499
|
}
|
|
8789
9500
|
function printToolCost(input) {
|
|
8790
9501
|
const { cost, billingSource, deeplineCredits, deeplineUsdPerPricingUnit } = input;
|
|
@@ -8852,6 +9563,17 @@ function samplePayload(samples, key) {
|
|
|
8852
9563
|
function commandEnvelopeFromRawResponse(rawResponse) {
|
|
8853
9564
|
return isRecord3(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
|
|
8854
9565
|
}
|
|
9566
|
+
function listExtractorPathsFromUsageGuidance(tool) {
|
|
9567
|
+
const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
|
|
9568
|
+
const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord3(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
|
|
9569
|
+
return extractedLists.flatMap((entry) => {
|
|
9570
|
+
const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
|
|
9571
|
+
if (!Array.isArray(paths)) return [];
|
|
9572
|
+
return paths.map(
|
|
9573
|
+
(path) => path.trim().replace(/^toolExecutionResult\.toolResponse\.raw\.?/, "").replace(/^toolExecutionResult\.toolOutput\.raw\.?/, "").replace(/^\./, "")
|
|
9574
|
+
).filter(Boolean);
|
|
9575
|
+
});
|
|
9576
|
+
}
|
|
8855
9577
|
function isPlayTool(tool) {
|
|
8856
9578
|
const provider = typeof tool.provider === "string" ? tool.provider : "";
|
|
8857
9579
|
return provider === "deepline_native" && Boolean(recordField(tool, "playExpansion", "play_expansion"));
|
|
@@ -8920,7 +9642,7 @@ function normalizeOutputFormat(raw) {
|
|
|
8920
9642
|
function parseExecuteOptions(args) {
|
|
8921
9643
|
const toolId = args[0];
|
|
8922
9644
|
if (!toolId) {
|
|
8923
|
-
throw new Error(`Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--
|
|
9645
|
+
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]`);
|
|
8924
9646
|
}
|
|
8925
9647
|
const params = {};
|
|
8926
9648
|
let outputFormat = "auto";
|
|
@@ -8949,10 +9671,6 @@ function parseExecuteOptions(args) {
|
|
|
8949
9671
|
outputFormat = normalizeOutputFormat(args[++index]);
|
|
8950
9672
|
continue;
|
|
8951
9673
|
}
|
|
8952
|
-
if (arg === "--full-output") {
|
|
8953
|
-
outputFormat = "json";
|
|
8954
|
-
continue;
|
|
8955
|
-
}
|
|
8956
9674
|
if (arg === "--no-preview") {
|
|
8957
9675
|
noPreview = true;
|
|
8958
9676
|
continue;
|
|
@@ -8991,7 +9709,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
8991
9709
|
description: ${JSON.stringify(`Seed ${input.toolId} rows for workflow expansion.`)},
|
|
8992
9710
|
});
|
|
8993
9711
|
|
|
8994
|
-
const list = Object.values(result.
|
|
9712
|
+
const list = Object.values(result.extractedLists)[0];
|
|
8995
9713
|
const rows = (list?.get() ?? []).slice(0, 100);
|
|
8996
9714
|
// ${sampleRows}
|
|
8997
9715
|
// columns: ${columns}
|
|
@@ -9008,7 +9726,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9008
9726
|
};
|
|
9009
9727
|
});
|
|
9010
9728
|
`;
|
|
9011
|
-
|
|
9729
|
+
writeFileSync8(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
9012
9730
|
return {
|
|
9013
9731
|
path: scriptPath,
|
|
9014
9732
|
projectDir,
|
|
@@ -9019,7 +9737,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9019
9737
|
function buildToolExecuteBaseEnvelope(input) {
|
|
9020
9738
|
const envelope = commandEnvelopeFromRawResponse(input.rawResponse);
|
|
9021
9739
|
const summaryEntries = Object.entries(input.summary);
|
|
9022
|
-
const
|
|
9740
|
+
const outputPreview = input.listConversion ? {
|
|
9023
9741
|
kind: "list",
|
|
9024
9742
|
rowCount: input.listConversion.rows.length,
|
|
9025
9743
|
columns: Object.keys(input.listConversion.rows[0] ?? {}),
|
|
@@ -9030,6 +9748,8 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
9030
9748
|
kind: summaryEntries.length > 0 ? "object" : "raw",
|
|
9031
9749
|
summary: input.summary
|
|
9032
9750
|
};
|
|
9751
|
+
const envelopeHasCanonicalOutput = isRecord3(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
|
|
9752
|
+
const inspectCommand = `deepline tools execute ${input.toolId} --input ${shellQuote(JSON.stringify(input.params))} --json`;
|
|
9033
9753
|
const actions = input.listConversion ? [
|
|
9034
9754
|
{
|
|
9035
9755
|
label: "next",
|
|
@@ -9038,17 +9758,23 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
9038
9758
|
] : [];
|
|
9039
9759
|
return {
|
|
9040
9760
|
...envelope,
|
|
9041
|
-
output,
|
|
9761
|
+
...envelopeHasCanonicalOutput ? { output_preview: outputPreview } : { output: outputPreview },
|
|
9042
9762
|
...summaryEntries.length > 0 ? { summary: input.summary } : {},
|
|
9043
|
-
next:
|
|
9044
|
-
|
|
9045
|
-
|
|
9763
|
+
next: {
|
|
9764
|
+
inspect: inspectCommand,
|
|
9765
|
+
playDebugging: "When fixing a play getter, inspect the actual play run table with runs get / inspect rows; do not copy CLI preview paths blindly.",
|
|
9766
|
+
...input.listConversion ? {
|
|
9767
|
+
expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again.",
|
|
9768
|
+
listSourcePath: input.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
|
|
9769
|
+
} : {}
|
|
9770
|
+
},
|
|
9046
9771
|
render: {
|
|
9047
9772
|
sections: input.listConversion ? [
|
|
9048
9773
|
{
|
|
9049
9774
|
title: "output",
|
|
9050
9775
|
lines: [
|
|
9051
9776
|
`${input.listConversion.rows.length} row(s) extracted from ${input.listConversion.sourcePath ?? "auto-detected list"}`,
|
|
9777
|
+
"paths above are observed from this execute response; use run table rows to debug play getters",
|
|
9052
9778
|
`columns: ${JSON.stringify(Object.keys(input.listConversion.rows[0] ?? {}))}`,
|
|
9053
9779
|
`preview: ${JSON.stringify(input.listConversion.rows.slice(0, 5))}`
|
|
9054
9780
|
]
|
|
@@ -9092,11 +9818,12 @@ async function executeTool(args) {
|
|
|
9092
9818
|
}
|
|
9093
9819
|
const rawResponse = await client.executeTool(parsed.toolId, parsed.params);
|
|
9094
9820
|
const listConversion = tryConvertToList(rawResponse, {
|
|
9095
|
-
listExtractorPaths: metadata
|
|
9821
|
+
listExtractorPaths: listExtractorPathsFromUsageGuidance(metadata)
|
|
9096
9822
|
});
|
|
9097
9823
|
const summary = extractSummaryFields(rawResponse);
|
|
9098
9824
|
const baseEnvelope = buildToolExecuteBaseEnvelope({
|
|
9099
9825
|
toolId: parsed.toolId,
|
|
9826
|
+
params: parsed.params,
|
|
9100
9827
|
rawResponse,
|
|
9101
9828
|
listConversion,
|
|
9102
9829
|
summary
|
|
@@ -9224,7 +9951,7 @@ async function executeTool(args) {
|
|
|
9224
9951
|
// src/cli/commands/update.ts
|
|
9225
9952
|
import { spawn } from "child_process";
|
|
9226
9953
|
import { existsSync as existsSync7 } from "fs";
|
|
9227
|
-
import { dirname as dirname9, join as join9, resolve as
|
|
9954
|
+
import { dirname as dirname9, join as join9, resolve as resolve10 } from "path";
|
|
9228
9955
|
function posixShellQuote(value) {
|
|
9229
9956
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
9230
9957
|
}
|
|
@@ -9243,7 +9970,7 @@ function buildSourceUpdateCommand(sourceRoot) {
|
|
|
9243
9970
|
return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
|
|
9244
9971
|
}
|
|
9245
9972
|
function findRepoBackedSdkRoot(startPath) {
|
|
9246
|
-
let current =
|
|
9973
|
+
let current = resolve10(startPath);
|
|
9247
9974
|
while (true) {
|
|
9248
9975
|
if (existsSync7(join9(current, "sdk", "package.json")) && existsSync7(join9(current, "sdk", "bin", "deepline-dev.ts"))) {
|
|
9249
9976
|
return current;
|
|
@@ -9254,7 +9981,7 @@ function findRepoBackedSdkRoot(startPath) {
|
|
|
9254
9981
|
}
|
|
9255
9982
|
}
|
|
9256
9983
|
function resolveUpdatePlan() {
|
|
9257
|
-
const entrypoint = process.argv[1] ?
|
|
9984
|
+
const entrypoint = process.argv[1] ? resolve10(process.argv[1]) : "";
|
|
9258
9985
|
const sourceRoot = entrypoint ? findRepoBackedSdkRoot(dirname9(entrypoint)) : null;
|
|
9259
9986
|
if (sourceRoot) {
|
|
9260
9987
|
return {
|
|
@@ -9348,7 +10075,7 @@ Examples:
|
|
|
9348
10075
|
|
|
9349
10076
|
// src/cli/skills-sync.ts
|
|
9350
10077
|
import { spawn as spawn2, spawnSync } from "child_process";
|
|
9351
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as
|
|
10078
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync6, statSync, writeFileSync as writeFileSync9 } from "fs";
|
|
9352
10079
|
import { homedir as homedir4 } from "os";
|
|
9353
10080
|
import { dirname as dirname10, join as join10 } from "path";
|
|
9354
10081
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
@@ -9375,9 +10102,45 @@ function readLocalSkillsVersion(baseUrl) {
|
|
|
9375
10102
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
9376
10103
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
9377
10104
|
mkdirSync5(dirname10(path), { recursive: true });
|
|
9378
|
-
|
|
10105
|
+
writeFileSync9(path, `${version}
|
|
9379
10106
|
`, "utf-8");
|
|
9380
10107
|
}
|
|
10108
|
+
function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
10109
|
+
const home = process.env.HOME?.trim() || homedir4();
|
|
10110
|
+
const roots = [
|
|
10111
|
+
join10(home, ".claude", "skills", SDK_SKILL_NAME),
|
|
10112
|
+
join10(home, ".agents", "skills", SDK_SKILL_NAME)
|
|
10113
|
+
];
|
|
10114
|
+
const staleMarkers = [
|
|
10115
|
+
"ctx.tools.execute(key",
|
|
10116
|
+
"ctx.tools.execute('",
|
|
10117
|
+
'ctx.tools.execute("',
|
|
10118
|
+
"rowCtx.tools.execute('",
|
|
10119
|
+
'rowCtx.tools.execute("'
|
|
10120
|
+
];
|
|
10121
|
+
const scan = (dir) => {
|
|
10122
|
+
for (const entry of readdirSync2(dir)) {
|
|
10123
|
+
const path = join10(dir, entry);
|
|
10124
|
+
const stat3 = statSync(path);
|
|
10125
|
+
if (stat3.isDirectory()) {
|
|
10126
|
+
if (scan(path)) return true;
|
|
10127
|
+
continue;
|
|
10128
|
+
}
|
|
10129
|
+
if (!entry.endsWith(".md")) continue;
|
|
10130
|
+
const text = readFileSync6(path, "utf-8");
|
|
10131
|
+
if (staleMarkers.some((marker) => text.includes(marker))) return true;
|
|
10132
|
+
}
|
|
10133
|
+
return false;
|
|
10134
|
+
};
|
|
10135
|
+
for (const root of roots) {
|
|
10136
|
+
try {
|
|
10137
|
+
if (existsSync8(root) && scan(root)) return true;
|
|
10138
|
+
} catch {
|
|
10139
|
+
continue;
|
|
10140
|
+
}
|
|
10141
|
+
}
|
|
10142
|
+
return false;
|
|
10143
|
+
}
|
|
9381
10144
|
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
9382
10145
|
const controller = new AbortController();
|
|
9383
10146
|
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
@@ -9413,7 +10176,7 @@ function buildSkillsInstallArgs(baseUrl) {
|
|
|
9413
10176
|
"skills",
|
|
9414
10177
|
"add",
|
|
9415
10178
|
packageUrl,
|
|
9416
|
-
"--
|
|
10179
|
+
"--agent",
|
|
9417
10180
|
...SKILL_AGENTS,
|
|
9418
10181
|
"--global",
|
|
9419
10182
|
"--yes",
|
|
@@ -9429,7 +10192,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
|
|
|
9429
10192
|
"skills",
|
|
9430
10193
|
"add",
|
|
9431
10194
|
packageUrl,
|
|
9432
|
-
"--
|
|
10195
|
+
"--agent",
|
|
9433
10196
|
...SKILL_AGENTS,
|
|
9434
10197
|
"--global",
|
|
9435
10198
|
"--yes",
|
|
@@ -9469,7 +10232,7 @@ function resolveSkillsInstallCommands(baseUrl) {
|
|
|
9469
10232
|
return [npxInstall];
|
|
9470
10233
|
}
|
|
9471
10234
|
function runOneSkillsInstall(install) {
|
|
9472
|
-
return new Promise((
|
|
10235
|
+
return new Promise((resolve11) => {
|
|
9473
10236
|
const child = spawn2(install.command, install.args, {
|
|
9474
10237
|
stdio: ["ignore", "ignore", "pipe"],
|
|
9475
10238
|
env: process.env
|
|
@@ -9479,7 +10242,7 @@ function runOneSkillsInstall(install) {
|
|
|
9479
10242
|
stderr += chunk.toString("utf-8");
|
|
9480
10243
|
});
|
|
9481
10244
|
child.on("error", (error) => {
|
|
9482
|
-
|
|
10245
|
+
resolve11({
|
|
9483
10246
|
ok: false,
|
|
9484
10247
|
detail: `failed to start ${install.command}: ${error.message}`,
|
|
9485
10248
|
manualCommand: install.manualCommand
|
|
@@ -9487,11 +10250,11 @@ function runOneSkillsInstall(install) {
|
|
|
9487
10250
|
});
|
|
9488
10251
|
child.on("close", (code) => {
|
|
9489
10252
|
if (code === 0) {
|
|
9490
|
-
|
|
10253
|
+
resolve11({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
9491
10254
|
return;
|
|
9492
10255
|
}
|
|
9493
10256
|
const detail = stderr.trim();
|
|
9494
|
-
|
|
10257
|
+
resolve11({
|
|
9495
10258
|
ok: false,
|
|
9496
10259
|
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
9497
10260
|
manualCommand: install.manualCommand
|
|
@@ -9530,10 +10293,19 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
9530
10293
|
attemptedSync = true;
|
|
9531
10294
|
const localVersion = readLocalSkillsVersion(baseUrl);
|
|
9532
10295
|
const update = await fetchSkillsUpdate(baseUrl, localVersion);
|
|
9533
|
-
|
|
10296
|
+
const hasStaleInstalledSkill = installedSdkSkillHasStalePositionalExecuteExamples();
|
|
10297
|
+
if (!update?.needsUpdate && !hasStaleInstalledSkill || !update?.remoteVersion) {
|
|
10298
|
+
return;
|
|
10299
|
+
}
|
|
9534
10300
|
writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-sdk skill...");
|
|
9535
10301
|
const installed = await runSkillsInstall(baseUrl);
|
|
9536
10302
|
if (!installed) return;
|
|
10303
|
+
if (installedSdkSkillHasStalePositionalExecuteExamples()) {
|
|
10304
|
+
process.stderr.write(
|
|
10305
|
+
"SDK skills sync completed, but installed deepline-sdk docs still contain stale positional ctx.tools.execute examples.\n"
|
|
10306
|
+
);
|
|
10307
|
+
return;
|
|
10308
|
+
}
|
|
9537
10309
|
writeLocalSkillsVersion(baseUrl, update.remoteVersion);
|
|
9538
10310
|
writeSdkSkillsStatusLine("SDK skills are up to date.");
|
|
9539
10311
|
}
|