deepline 0.1.63 → 0.1.64
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 +702 -339
- package/dist/cli/index.mjs +727 -348
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +56 -40
- package/dist/index.mjs +56 -40
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +9 -10
- package/dist/repo/apps/play-runner-workers/src/runtime/dataset-handles.ts +36 -27
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-http-errors.ts +5 -2
- package/dist/repo/sdk/src/client.ts +71 -63
- package/dist/repo/sdk/src/errors.ts +5 -1
- package/dist/repo/sdk/src/http.ts +25 -17
- package/dist/repo/sdk/src/plays/local-file-discovery.ts +93 -24
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/sdk/src/tool-output.ts +40 -20
- package/dist/repo/shared_libs/play-runtime/batch-runtime.ts +10 -3
- package/dist/repo/shared_libs/play-runtime/batching-types.ts +15 -4
- package/dist/repo/shared_libs/play-runtime/coordinator-headers.ts +2 -1
- package/dist/repo/shared_libs/play-runtime/dedup-backend.ts +0 -0
- package/dist/repo/shared_libs/play-runtime/default-batch-strategies.ts +3 -4
- package/dist/repo/shared_libs/play-runtime/run-failure.ts +1 -3
- package/dist/repo/shared_libs/play-runtime/step-lifecycle-tracker.ts +4 -1
- package/dist/repo/shared_libs/play-runtime/tool-batch-executor.ts +4 -1
- package/dist/repo/shared_libs/plays/dataset.ts +10 -11
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -34,7 +34,11 @@ var RateLimitError = class extends DeeplineError {
|
|
|
34
34
|
/** Milliseconds to wait before retrying, from the `Retry-After` response header. Defaults to 5000. */
|
|
35
35
|
retryAfterMs;
|
|
36
36
|
constructor(retryAfterMs = 5e3, message) {
|
|
37
|
-
super(
|
|
37
|
+
super(
|
|
38
|
+
message ?? `Rate limited. Retry after ${retryAfterMs}ms.`,
|
|
39
|
+
429,
|
|
40
|
+
"RATE_LIMIT"
|
|
41
|
+
);
|
|
38
42
|
this.name = "RateLimitError";
|
|
39
43
|
this.retryAfterMs = retryAfterMs;
|
|
40
44
|
}
|
|
@@ -197,10 +201,10 @@ function resolveConfig(options) {
|
|
|
197
201
|
|
|
198
202
|
// src/release.ts
|
|
199
203
|
var SDK_RELEASE = {
|
|
200
|
-
version: "0.1.
|
|
204
|
+
version: "0.1.64",
|
|
201
205
|
apiContract: "2026-05-play-bootstrap-dataset-summary",
|
|
202
206
|
supportPolicy: {
|
|
203
|
-
latest: "0.1.
|
|
207
|
+
latest: "0.1.64",
|
|
204
208
|
minimumSupported: "0.1.53",
|
|
205
209
|
deprecatedBelow: "0.1.53"
|
|
206
210
|
}
|
|
@@ -223,7 +227,7 @@ var HttpClient = class {
|
|
|
223
227
|
config;
|
|
224
228
|
authHeaders(extra) {
|
|
225
229
|
const headers = {
|
|
226
|
-
|
|
230
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
227
231
|
"User-Agent": `deepline-ts-sdk/${SDK_VERSION}`,
|
|
228
232
|
"X-Deepline-SDK-Version": SDK_VERSION,
|
|
229
233
|
"X-Deepline-API-Contract": SDK_API_CONTRACT,
|
|
@@ -906,31 +910,34 @@ var DeeplineClient = class {
|
|
|
906
910
|
* artifactStorageKey: 'plays/v1/orgs/acme/plays/my-play/artifacts/playgraph_abc123.json',
|
|
907
911
|
* });
|
|
908
912
|
* ```
|
|
909
|
-
|
|
913
|
+
*/
|
|
910
914
|
async startPlayRun(request) {
|
|
911
|
-
const response = await this.http.post(
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
915
|
+
const response = await this.http.post(
|
|
916
|
+
"/api/v2/plays/run",
|
|
917
|
+
{
|
|
918
|
+
...request.name ? { name: request.name } : {},
|
|
919
|
+
...request.revisionId ? { revisionId: request.revisionId } : {},
|
|
920
|
+
...request.artifactStorageKey ? { artifactStorageKey: request.artifactStorageKey } : {},
|
|
921
|
+
...request.sourceCode ? { sourceCode: request.sourceCode } : {},
|
|
922
|
+
...request.sourceFiles ? { sourceFiles: request.sourceFiles } : {},
|
|
923
|
+
..."staticPipeline" in request ? { staticPipeline: request.staticPipeline } : {},
|
|
924
|
+
...request.artifactHash ? { artifactHash: request.artifactHash } : {},
|
|
925
|
+
...request.graphHash ? { graphHash: request.graphHash } : {},
|
|
926
|
+
...request.runtimeArtifact ? { runtimeArtifact: request.runtimeArtifact } : {},
|
|
927
|
+
...request.compilerManifest ? { compilerManifest: request.compilerManifest } : {},
|
|
928
|
+
...request.inputFileUpload ? { inputFileUpload: request.inputFileUpload } : {},
|
|
929
|
+
...request.packagedFileUploads?.length ? { packagedFileUploads: request.packagedFileUploads } : {},
|
|
930
|
+
...request.input ? { input: request.input } : {},
|
|
931
|
+
...request.inputFile ? { inputFile: request.inputFile } : {},
|
|
932
|
+
...request.packagedFiles?.length ? { packagedFiles: request.packagedFiles } : {},
|
|
933
|
+
...request.force ? { force: true } : {},
|
|
934
|
+
...typeof request.waitForCompletionMs === "number" ? { waitForCompletionMs: request.waitForCompletionMs } : {},
|
|
935
|
+
// Profile selection is the API's job, not the CLI's. The server
|
|
936
|
+
// hardcodes workers_edge as the default; tests that want a
|
|
937
|
+
// different profile pass `request.profile` explicitly.
|
|
938
|
+
...request.profile ? { profile: request.profile } : {}
|
|
939
|
+
}
|
|
940
|
+
);
|
|
934
941
|
return normalizePlayRunStart(response);
|
|
935
942
|
}
|
|
936
943
|
async *startPlayRunStream(request, options) {
|
|
@@ -1182,10 +1189,7 @@ var DeeplineClient = class {
|
|
|
1182
1189
|
}
|
|
1183
1190
|
return formData;
|
|
1184
1191
|
};
|
|
1185
|
-
const response = await this.http.postFormData(
|
|
1186
|
-
"/api/v2/plays/files/stage",
|
|
1187
|
-
buildFormData
|
|
1188
|
-
);
|
|
1192
|
+
const response = await this.http.postFormData("/api/v2/plays/files/stage", buildFormData);
|
|
1189
1193
|
return response.files;
|
|
1190
1194
|
}
|
|
1191
1195
|
async resolveStagedPlayFiles(files) {
|
|
@@ -1632,7 +1636,9 @@ var DeeplineClient = class {
|
|
|
1632
1636
|
}
|
|
1633
1637
|
options?.onProgress?.(status);
|
|
1634
1638
|
if (TERMINAL_PLAY_STATUSES.has(status.status)) {
|
|
1635
|
-
const finalStatus = await this.getPlayStatus(
|
|
1639
|
+
const finalStatus = await this.getPlayStatus(
|
|
1640
|
+
status.runId || workflowId
|
|
1641
|
+
).catch(() => status);
|
|
1636
1642
|
return playRunResultFromStatus(finalStatus, start, workflowId);
|
|
1637
1643
|
}
|
|
1638
1644
|
}
|
|
@@ -1715,17 +1721,18 @@ async function enforceSdkCompatibility(baseUrl) {
|
|
|
1715
1721
|
}
|
|
1716
1722
|
|
|
1717
1723
|
// src/cli/commands/auth.ts
|
|
1718
|
-
import {
|
|
1724
|
+
import {
|
|
1725
|
+
existsSync as existsSync3,
|
|
1726
|
+
mkdirSync as mkdirSync3,
|
|
1727
|
+
readFileSync as readFileSync3,
|
|
1728
|
+
rmSync,
|
|
1729
|
+
writeFileSync as writeFileSync3
|
|
1730
|
+
} from "fs";
|
|
1719
1731
|
import { hostname } from "os";
|
|
1720
1732
|
import { dirname as dirname3 } from "path";
|
|
1721
1733
|
|
|
1722
1734
|
// src/cli/utils.ts
|
|
1723
|
-
import {
|
|
1724
|
-
existsSync as existsSync2,
|
|
1725
|
-
mkdirSync as mkdirSync2,
|
|
1726
|
-
readFileSync as readFileSync2,
|
|
1727
|
-
writeFileSync as writeFileSync2
|
|
1728
|
-
} from "fs";
|
|
1735
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
1729
1736
|
import { mkdir, writeFile } from "fs/promises";
|
|
1730
1737
|
import { homedir as homedir2 } from "os";
|
|
1731
1738
|
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
@@ -1928,11 +1935,9 @@ function openUrlMacos(targetUrl, allowFocus, runner = defaultBrowserCommandRunne
|
|
|
1928
1935
|
return true;
|
|
1929
1936
|
}
|
|
1930
1937
|
try {
|
|
1931
|
-
runner.execFileSync(
|
|
1932
|
-
"
|
|
1933
|
-
|
|
1934
|
-
{ stdio: "ignore" }
|
|
1935
|
-
);
|
|
1938
|
+
runner.execFileSync("open", [...allowFocus ? [] : ["-g"], targetUrl], {
|
|
1939
|
+
stdio: "ignore"
|
|
1940
|
+
});
|
|
1936
1941
|
return true;
|
|
1937
1942
|
} catch {
|
|
1938
1943
|
return false;
|
|
@@ -2126,7 +2131,10 @@ function createTimestampedName(prefix, extension) {
|
|
|
2126
2131
|
return `${prefix}-${timestamp}.${extension}`;
|
|
2127
2132
|
}
|
|
2128
2133
|
async function writeCsvRowsFile(prefix, rows) {
|
|
2129
|
-
const path = await writeOutputFile(
|
|
2134
|
+
const path = await writeOutputFile(
|
|
2135
|
+
createTimestampedName(prefix, "csv"),
|
|
2136
|
+
csvStringFromRows(rows)
|
|
2137
|
+
);
|
|
2130
2138
|
return path;
|
|
2131
2139
|
}
|
|
2132
2140
|
function clip(value, maxLength) {
|
|
@@ -2207,7 +2215,9 @@ function saveEnvValues(values, baseUrl) {
|
|
|
2207
2215
|
saveHostEnvValues(baseUrl, filtered);
|
|
2208
2216
|
}
|
|
2209
2217
|
async function httpJson(method, url, apiKey, body) {
|
|
2210
|
-
const headers = {
|
|
2218
|
+
const headers = {
|
|
2219
|
+
"Content-Type": "application/json"
|
|
2220
|
+
};
|
|
2211
2221
|
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
|
|
2212
2222
|
let response = null;
|
|
2213
2223
|
let lastError = null;
|
|
@@ -2262,12 +2272,24 @@ function sleep3(ms) {
|
|
|
2262
2272
|
}
|
|
2263
2273
|
function printDeeplineLogo() {
|
|
2264
2274
|
if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
|
|
2265
|
-
console.log(
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
console.log(
|
|
2269
|
-
|
|
2270
|
-
|
|
2275
|
+
console.log(
|
|
2276
|
+
" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"
|
|
2277
|
+
);
|
|
2278
|
+
console.log(
|
|
2279
|
+
" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D"
|
|
2280
|
+
);
|
|
2281
|
+
console.log(
|
|
2282
|
+
" \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557"
|
|
2283
|
+
);
|
|
2284
|
+
console.log(
|
|
2285
|
+
" \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D"
|
|
2286
|
+
);
|
|
2287
|
+
console.log(
|
|
2288
|
+
" \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"
|
|
2289
|
+
);
|
|
2290
|
+
console.log(
|
|
2291
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
|
|
2292
|
+
);
|
|
2271
2293
|
console.log("");
|
|
2272
2294
|
return;
|
|
2273
2295
|
}
|
|
@@ -2301,7 +2323,12 @@ async function handleRegister(args) {
|
|
|
2301
2323
|
const payload = {};
|
|
2302
2324
|
if (orgName) payload.org_name = orgName;
|
|
2303
2325
|
if (agentName) payload.agent_name = agentName;
|
|
2304
|
-
const { status, data } = await httpJson(
|
|
2326
|
+
const { status, data } = await httpJson(
|
|
2327
|
+
"POST",
|
|
2328
|
+
`${baseUrl}/api/v2/auth/cli/register`,
|
|
2329
|
+
null,
|
|
2330
|
+
payload
|
|
2331
|
+
);
|
|
2305
2332
|
if (status >= 400) {
|
|
2306
2333
|
console.error(`Auth register failed (status ${status}).`);
|
|
2307
2334
|
if (data.error) console.error(String(data.error));
|
|
@@ -2311,9 +2338,12 @@ async function handleRegister(args) {
|
|
|
2311
2338
|
const claimToken = String(data.claim_token || "");
|
|
2312
2339
|
if (claimToken) {
|
|
2313
2340
|
savePendingClaimToken(baseUrl, claimToken);
|
|
2314
|
-
saveEnvValues(
|
|
2315
|
-
|
|
2316
|
-
|
|
2341
|
+
saveEnvValues(
|
|
2342
|
+
{
|
|
2343
|
+
[HOST_URL_ENV]: baseUrl
|
|
2344
|
+
},
|
|
2345
|
+
baseUrl
|
|
2346
|
+
);
|
|
2317
2347
|
}
|
|
2318
2348
|
if (claimUrl) {
|
|
2319
2349
|
console.log(" Opening approval page in your browser.");
|
|
@@ -2352,10 +2382,13 @@ async function handleRegister(args) {
|
|
|
2352
2382
|
if (state === "claimed") {
|
|
2353
2383
|
const apiKey = String(statusData.api_key || "");
|
|
2354
2384
|
if (apiKey) {
|
|
2355
|
-
saveEnvValues(
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2385
|
+
saveEnvValues(
|
|
2386
|
+
{
|
|
2387
|
+
[HOST_URL_ENV]: baseUrl,
|
|
2388
|
+
[API_KEY_ENV]: apiKey
|
|
2389
|
+
},
|
|
2390
|
+
baseUrl
|
|
2391
|
+
);
|
|
2359
2392
|
clearPendingClaimToken(baseUrl);
|
|
2360
2393
|
printClaimSuccessBanner(statusData);
|
|
2361
2394
|
return EXIT_OK;
|
|
@@ -2363,7 +2396,9 @@ async function handleRegister(args) {
|
|
|
2363
2396
|
}
|
|
2364
2397
|
if (state === "expired") {
|
|
2365
2398
|
clearPendingClaimToken(baseUrl);
|
|
2366
|
-
console.log(
|
|
2399
|
+
console.log(
|
|
2400
|
+
"That approval link expired. Please run: deepline auth register"
|
|
2401
|
+
);
|
|
2367
2402
|
return EXIT_AUTH;
|
|
2368
2403
|
}
|
|
2369
2404
|
await sleep3(2e3);
|
|
@@ -2414,10 +2449,13 @@ async function handleWait(args) {
|
|
|
2414
2449
|
if (state === "claimed") {
|
|
2415
2450
|
const apiKey = String(data.api_key || "");
|
|
2416
2451
|
if (apiKey) {
|
|
2417
|
-
saveEnvValues(
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2452
|
+
saveEnvValues(
|
|
2453
|
+
{
|
|
2454
|
+
[HOST_URL_ENV]: baseUrl,
|
|
2455
|
+
[API_KEY_ENV]: apiKey
|
|
2456
|
+
},
|
|
2457
|
+
baseUrl
|
|
2458
|
+
);
|
|
2421
2459
|
clearPendingClaimToken(baseUrl);
|
|
2422
2460
|
printClaimSuccessBanner(data);
|
|
2423
2461
|
return EXIT_OK;
|
|
@@ -2430,7 +2468,9 @@ async function handleWait(args) {
|
|
|
2430
2468
|
}
|
|
2431
2469
|
await sleep3(2e3);
|
|
2432
2470
|
}
|
|
2433
|
-
console.error(
|
|
2471
|
+
console.error(
|
|
2472
|
+
"Still pending. Approve the browser link, then run: deepline auth wait"
|
|
2473
|
+
);
|
|
2434
2474
|
return EXIT_AUTH;
|
|
2435
2475
|
}
|
|
2436
2476
|
async function handleStatus(args) {
|
|
@@ -2440,7 +2480,11 @@ async function handleStatus(args) {
|
|
|
2440
2480
|
let hostStatusPayload = null;
|
|
2441
2481
|
const hostLines = [];
|
|
2442
2482
|
try {
|
|
2443
|
-
const { status: hStatus, data: hData } = await httpJson(
|
|
2483
|
+
const { status: hStatus, data: hData } = await httpJson(
|
|
2484
|
+
"GET",
|
|
2485
|
+
`${baseUrl}/api/v2/health`,
|
|
2486
|
+
null
|
|
2487
|
+
);
|
|
2444
2488
|
if (hStatus === 200) {
|
|
2445
2489
|
hostStatusPayload = {
|
|
2446
2490
|
host: baseUrl,
|
|
@@ -2462,45 +2506,74 @@ async function handleStatus(args) {
|
|
|
2462
2506
|
const apiKey = resolveApiKeyForBaseUrl(baseUrl);
|
|
2463
2507
|
if (!apiKey) {
|
|
2464
2508
|
if (readPendingClaimToken(baseUrl)) {
|
|
2465
|
-
printCommandEnvelope(
|
|
2509
|
+
printCommandEnvelope(
|
|
2510
|
+
{
|
|
2511
|
+
...hostStatusPayload ?? { host: baseUrl },
|
|
2512
|
+
status: "pending",
|
|
2513
|
+
connected: false,
|
|
2514
|
+
next: "deepline auth wait",
|
|
2515
|
+
render: {
|
|
2516
|
+
sections: [
|
|
2517
|
+
{
|
|
2518
|
+
title: "auth status",
|
|
2519
|
+
lines: [...hostLines, "Status: pending"]
|
|
2520
|
+
}
|
|
2521
|
+
],
|
|
2522
|
+
actions: [{ label: "Run", command: "deepline auth wait" }]
|
|
2523
|
+
}
|
|
2524
|
+
},
|
|
2525
|
+
{ json: jsonOutput }
|
|
2526
|
+
);
|
|
2527
|
+
return EXIT_OK;
|
|
2528
|
+
}
|
|
2529
|
+
printCommandEnvelope(
|
|
2530
|
+
{
|
|
2466
2531
|
...hostStatusPayload ?? { host: baseUrl },
|
|
2467
|
-
status: "
|
|
2532
|
+
status: "not connected",
|
|
2468
2533
|
connected: false,
|
|
2469
|
-
next: "deepline auth
|
|
2534
|
+
next: "deepline auth register",
|
|
2470
2535
|
render: {
|
|
2471
|
-
sections: [
|
|
2472
|
-
|
|
2536
|
+
sections: [
|
|
2537
|
+
{
|
|
2538
|
+
title: "auth status",
|
|
2539
|
+
lines: [...hostLines, "Status: not connected"]
|
|
2540
|
+
}
|
|
2541
|
+
],
|
|
2542
|
+
actions: [{ label: "Run", command: "deepline auth register" }]
|
|
2473
2543
|
}
|
|
2474
|
-
},
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
printCommandEnvelope({
|
|
2478
|
-
...hostStatusPayload ?? { host: baseUrl },
|
|
2479
|
-
status: "not connected",
|
|
2480
|
-
connected: false,
|
|
2481
|
-
next: "deepline auth register",
|
|
2482
|
-
render: {
|
|
2483
|
-
sections: [{ title: "auth status", lines: [...hostLines, "Status: not connected"] }],
|
|
2484
|
-
actions: [{ label: "Run", command: "deepline auth register" }]
|
|
2485
|
-
}
|
|
2486
|
-
}, { json: jsonOutput });
|
|
2544
|
+
},
|
|
2545
|
+
{ json: jsonOutput }
|
|
2546
|
+
);
|
|
2487
2547
|
return EXIT_OK;
|
|
2488
2548
|
}
|
|
2489
|
-
const { status, data } = await httpJson(
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2549
|
+
const { status, data } = await httpJson(
|
|
2550
|
+
"POST",
|
|
2551
|
+
`${baseUrl}/api/v2/auth/cli/status`,
|
|
2552
|
+
apiKey,
|
|
2553
|
+
{
|
|
2554
|
+
api_key: apiKey,
|
|
2555
|
+
reveal
|
|
2556
|
+
}
|
|
2557
|
+
);
|
|
2493
2558
|
if (status === 401 || status === 403) {
|
|
2494
|
-
printCommandEnvelope(
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2559
|
+
printCommandEnvelope(
|
|
2560
|
+
{
|
|
2561
|
+
...hostStatusPayload ?? { host: baseUrl },
|
|
2562
|
+
status: "unauthorized",
|
|
2563
|
+
connected: false,
|
|
2564
|
+
next: "deepline auth register",
|
|
2565
|
+
render: {
|
|
2566
|
+
sections: [
|
|
2567
|
+
{
|
|
2568
|
+
title: "auth status",
|
|
2569
|
+
lines: [...hostLines, "Status: unauthorized"]
|
|
2570
|
+
}
|
|
2571
|
+
],
|
|
2572
|
+
actions: [{ label: "Run", command: "deepline auth register" }]
|
|
2573
|
+
}
|
|
2574
|
+
},
|
|
2575
|
+
{ json: jsonOutput }
|
|
2576
|
+
);
|
|
2504
2577
|
return EXIT_AUTH;
|
|
2505
2578
|
}
|
|
2506
2579
|
if (status >= 400) {
|
|
@@ -2527,35 +2600,44 @@ async function handleStatus(args) {
|
|
|
2527
2600
|
if (reveal) {
|
|
2528
2601
|
const apiKeyResp = String(data.api_key || apiKey);
|
|
2529
2602
|
if (apiKeyResp) {
|
|
2530
|
-
saveEnvValues(
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2603
|
+
saveEnvValues(
|
|
2604
|
+
{
|
|
2605
|
+
[HOST_URL_ENV]: baseUrl,
|
|
2606
|
+
[API_KEY_ENV]: apiKeyResp
|
|
2607
|
+
},
|
|
2608
|
+
baseUrl
|
|
2609
|
+
);
|
|
2534
2610
|
savedApiKeyPath = envFilePath(baseUrl);
|
|
2535
2611
|
}
|
|
2536
2612
|
}
|
|
2537
|
-
printCommandEnvelope(
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2613
|
+
printCommandEnvelope(
|
|
2614
|
+
{
|
|
2615
|
+
...payload,
|
|
2616
|
+
...savedApiKeyPath ? { saved_api_key_path: savedApiKeyPath } : {},
|
|
2617
|
+
render: {
|
|
2618
|
+
sections: [
|
|
2619
|
+
{
|
|
2620
|
+
title: "auth status",
|
|
2621
|
+
lines: [
|
|
2622
|
+
...hostLines,
|
|
2623
|
+
`Status: ${payload.status}`,
|
|
2624
|
+
`Rate limit tier: ${payload.rateLimitTier}`,
|
|
2625
|
+
...payload.workspace.name ? [`Workspace: ${payload.workspace.name}`] : [],
|
|
2626
|
+
...payload.workspace.slug ? [`Workspace slug: ${payload.workspace.slug}`] : [],
|
|
2627
|
+
...payload.workspace.id != null ? [`Org ID: ${payload.workspace.id}`] : [],
|
|
2628
|
+
...payload.user.id != null ? [`User ID: ${payload.user.id}`] : [],
|
|
2629
|
+
...payload.examples.length > 0 ? [
|
|
2630
|
+
"Examples:",
|
|
2631
|
+
...payload.examples.slice(0, 3).map((example) => ` ${String(example)}`)
|
|
2632
|
+
] : [],
|
|
2633
|
+
...savedApiKeyPath ? [`Saved API key to ${savedApiKeyPath}`] : []
|
|
2634
|
+
]
|
|
2635
|
+
}
|
|
2636
|
+
]
|
|
2637
|
+
}
|
|
2638
|
+
},
|
|
2639
|
+
{ json: jsonOutput }
|
|
2640
|
+
);
|
|
2559
2641
|
return EXIT_OK;
|
|
2560
2642
|
}
|
|
2561
2643
|
function registerAuthCommands(program) {
|
|
@@ -2575,7 +2657,9 @@ Notes:
|
|
|
2575
2657
|
Auth status shows the target host and active workspace without printing secrets.
|
|
2576
2658
|
`
|
|
2577
2659
|
);
|
|
2578
|
-
auth.command("register").description(
|
|
2660
|
+
auth.command("register").description(
|
|
2661
|
+
"Register this device and open the approval page in your browser."
|
|
2662
|
+
).addHelpText(
|
|
2579
2663
|
"after",
|
|
2580
2664
|
`
|
|
2581
2665
|
Notes:
|
|
@@ -2622,7 +2706,10 @@ Examples:
|
|
|
2622
2706
|
deepline auth status
|
|
2623
2707
|
deepline auth status --json
|
|
2624
2708
|
`
|
|
2625
|
-
).option(
|
|
2709
|
+
).option(
|
|
2710
|
+
"--reveal",
|
|
2711
|
+
"Persist the revealed API key back to the host auth file"
|
|
2712
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
2626
2713
|
process.exitCode = await handleStatus([
|
|
2627
2714
|
...options.reveal ? ["--reveal"] : [],
|
|
2628
2715
|
...options.json ? ["--json"] : []
|
|
@@ -2647,7 +2734,9 @@ function recentUsageLines(entries) {
|
|
|
2647
2734
|
const op = `${humanize(entry.provider)} ${humanize(entry.operation)}`.trim();
|
|
2648
2735
|
const charge = entry.billing_mode === "no_bill" ? "free" : `${entry.credits ?? 0} cr`;
|
|
2649
2736
|
const status = entry.status || "completed";
|
|
2650
|
-
lines.push(
|
|
2737
|
+
lines.push(
|
|
2738
|
+
`${op} | ${charge} | ${status} | ${entry.created_at || "unknown"}`
|
|
2739
|
+
);
|
|
2651
2740
|
}
|
|
2652
2741
|
return lines;
|
|
2653
2742
|
}
|
|
@@ -2701,16 +2790,21 @@ function defaultLedgerExportPath() {
|
|
|
2701
2790
|
}
|
|
2702
2791
|
async function handleBalance(options) {
|
|
2703
2792
|
const { http } = getAuthedHttpClient();
|
|
2704
|
-
const payload = await http.get(
|
|
2793
|
+
const payload = await http.get(
|
|
2794
|
+
"/api/v2/billing/balance"
|
|
2795
|
+
);
|
|
2705
2796
|
const status = String(payload.balance_status || "");
|
|
2706
2797
|
const lines = status === "no_billing" ? [
|
|
2707
2798
|
"Balance: 0 credits",
|
|
2708
2799
|
"Billing: No billing account or payment method set up for this workspace."
|
|
2709
2800
|
] : [`Balance: ${payload.balance ?? "(unknown)"} credits`];
|
|
2710
|
-
printCommandEnvelope(
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2801
|
+
printCommandEnvelope(
|
|
2802
|
+
{
|
|
2803
|
+
...payload,
|
|
2804
|
+
render: { sections: [{ title: "billing balance", lines }] }
|
|
2805
|
+
},
|
|
2806
|
+
{ json: options.json }
|
|
2807
|
+
);
|
|
2714
2808
|
return;
|
|
2715
2809
|
}
|
|
2716
2810
|
async function handleUsage(options) {
|
|
@@ -2719,7 +2813,9 @@ async function handleUsage(options) {
|
|
|
2719
2813
|
if (options.limit) params.set("recent_limit", options.limit);
|
|
2720
2814
|
if (options.offset) params.set("recent_offset", options.offset);
|
|
2721
2815
|
const suffix = Array.from(params).length > 0 ? `?${params.toString()}` : "";
|
|
2722
|
-
const payload = await http.get(
|
|
2816
|
+
const payload = await http.get(
|
|
2817
|
+
`/api/v2/billing/usage${suffix}`
|
|
2818
|
+
);
|
|
2723
2819
|
const usage = payload.usage ?? {};
|
|
2724
2820
|
const quota = payload.quota ?? {};
|
|
2725
2821
|
const recent = payload.recent ?? {};
|
|
@@ -2727,24 +2823,34 @@ async function handleUsage(options) {
|
|
|
2727
2823
|
`Balance: ${payload.balance ?? "(unknown)"}`,
|
|
2728
2824
|
`Last 30 days spent: ${usage.month_spent_credits ?? "(unknown)"}`,
|
|
2729
2825
|
`Monthly limit: ${quota.enabled ? quota.monthly_credits_limit ?? "(unknown)" : "off"}`,
|
|
2730
|
-
...recentUsageLines(
|
|
2826
|
+
...recentUsageLines(
|
|
2827
|
+
Array.isArray(recent.entries) ? recent.entries : []
|
|
2828
|
+
)
|
|
2731
2829
|
];
|
|
2732
|
-
printCommandEnvelope(
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2830
|
+
printCommandEnvelope(
|
|
2831
|
+
{
|
|
2832
|
+
...payload,
|
|
2833
|
+
render: { sections: [{ title: "billing usage", lines }] }
|
|
2834
|
+
},
|
|
2835
|
+
{ json: options.json }
|
|
2836
|
+
);
|
|
2736
2837
|
}
|
|
2737
2838
|
async function handleLimit(options) {
|
|
2738
2839
|
const { http } = getAuthedHttpClient();
|
|
2739
|
-
const payload = await http.get(
|
|
2840
|
+
const payload = await http.get(
|
|
2841
|
+
"/api/v2/billing/limit"
|
|
2842
|
+
);
|
|
2740
2843
|
const lines = payload.enabled ? [
|
|
2741
2844
|
`Monthly limit: ${payload.monthly_credits_limit ?? "(unknown)"}`,
|
|
2742
2845
|
`Remaining before cap: ${payload.remaining_credits ?? "(unknown)"}`
|
|
2743
2846
|
] : ["Monthly limit: off"];
|
|
2744
|
-
printCommandEnvelope(
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2847
|
+
printCommandEnvelope(
|
|
2848
|
+
{
|
|
2849
|
+
...payload,
|
|
2850
|
+
render: { sections: [{ title: "billing limit", lines }] }
|
|
2851
|
+
},
|
|
2852
|
+
{ json: options.json }
|
|
2853
|
+
);
|
|
2748
2854
|
}
|
|
2749
2855
|
async function handleSetLimit(credits, options) {
|
|
2750
2856
|
const { http } = getAuthedHttpClient();
|
|
@@ -2752,26 +2858,53 @@ async function handleSetLimit(credits, options) {
|
|
|
2752
2858
|
method: "PUT",
|
|
2753
2859
|
body: { monthly_credits_limit: Number.parseInt(credits, 10) }
|
|
2754
2860
|
});
|
|
2755
|
-
printCommandEnvelope(
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2861
|
+
printCommandEnvelope(
|
|
2862
|
+
{
|
|
2863
|
+
...payload,
|
|
2864
|
+
render: {
|
|
2865
|
+
sections: [
|
|
2866
|
+
{
|
|
2867
|
+
title: "billing limit",
|
|
2868
|
+
lines: [`Monthly billing limit set to ${credits} credits.`]
|
|
2869
|
+
}
|
|
2870
|
+
]
|
|
2871
|
+
}
|
|
2872
|
+
},
|
|
2873
|
+
{ json: options.json }
|
|
2874
|
+
);
|
|
2761
2875
|
}
|
|
2762
2876
|
async function handleLimitOff(options) {
|
|
2763
2877
|
const { http } = getAuthedHttpClient();
|
|
2764
|
-
const payload = await http.request("/api/v2/billing/limit", {
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2878
|
+
const payload = await http.request("/api/v2/billing/limit", {
|
|
2879
|
+
method: "DELETE"
|
|
2880
|
+
});
|
|
2881
|
+
printCommandEnvelope(
|
|
2882
|
+
{
|
|
2883
|
+
...payload,
|
|
2884
|
+
render: {
|
|
2885
|
+
sections: [
|
|
2886
|
+
{
|
|
2887
|
+
title: "billing limit",
|
|
2888
|
+
lines: ["Monthly billing limit is now off."]
|
|
2889
|
+
}
|
|
2890
|
+
]
|
|
2891
|
+
}
|
|
2892
|
+
},
|
|
2893
|
+
{ json: options.json }
|
|
2894
|
+
);
|
|
2769
2895
|
}
|
|
2770
2896
|
async function handleHistory(options) {
|
|
2771
2897
|
const { http } = getAuthedHttpClient();
|
|
2772
|
-
const windows = {
|
|
2898
|
+
const windows = {
|
|
2899
|
+
"1d": 86400,
|
|
2900
|
+
"1w": 604800,
|
|
2901
|
+
"1m": 2592e3,
|
|
2902
|
+
"1y": 31536e3
|
|
2903
|
+
};
|
|
2773
2904
|
const sinceAt = Math.max(0, Math.floor(Date.now() / 1e3) - windows[options.time]) * 1e3;
|
|
2774
|
-
const payload = await http.get(
|
|
2905
|
+
const payload = await http.get(
|
|
2906
|
+
`/api/v2/billing/ledger?since_at=${sinceAt}&limit=5000`
|
|
2907
|
+
);
|
|
2775
2908
|
const entries = Array.isArray(payload.entries) ? payload.entries : [];
|
|
2776
2909
|
const rows = entries.map((entry) => {
|
|
2777
2910
|
const metadata = entry.metadata ?? {};
|
|
@@ -2783,21 +2916,30 @@ async function handleHistory(options) {
|
|
|
2783
2916
|
operation: metadata.operation ?? ""
|
|
2784
2917
|
};
|
|
2785
2918
|
});
|
|
2786
|
-
const outputPath = await writeCsvRowsFile(
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2919
|
+
const outputPath = await writeCsvRowsFile(
|
|
2920
|
+
`billing-history-${options.time}`,
|
|
2921
|
+
rows
|
|
2922
|
+
);
|
|
2923
|
+
printCommandEnvelope(
|
|
2924
|
+
{
|
|
2925
|
+
output_path: outputPath,
|
|
2926
|
+
row_count: rows.length,
|
|
2927
|
+
time_window: options.time,
|
|
2928
|
+
render: {
|
|
2929
|
+
sections: [
|
|
2930
|
+
{
|
|
2931
|
+
title: "billing history",
|
|
2932
|
+
lines: [
|
|
2933
|
+
`Billing history written to ${outputPath}`,
|
|
2934
|
+
`${rows.length} row(s) exported.`
|
|
2935
|
+
]
|
|
2936
|
+
}
|
|
2937
|
+
]
|
|
2938
|
+
},
|
|
2939
|
+
local: { output_path: outputPath }
|
|
2798
2940
|
},
|
|
2799
|
-
|
|
2800
|
-
|
|
2941
|
+
{ json: options.json }
|
|
2942
|
+
);
|
|
2801
2943
|
}
|
|
2802
2944
|
async function handleLedgerExportAll(options) {
|
|
2803
2945
|
const { http } = getAuthedHttpClient();
|
|
@@ -2829,51 +2971,75 @@ async function handleLedgerExportAll(options) {
|
|
|
2829
2971
|
if (nextCursor === cursor) break;
|
|
2830
2972
|
cursor = nextCursor;
|
|
2831
2973
|
}
|
|
2832
|
-
printCommandEnvelope(
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2974
|
+
printCommandEnvelope(
|
|
2975
|
+
{
|
|
2976
|
+
output_path: outputPath,
|
|
2977
|
+
row_count: summary.row_count,
|
|
2978
|
+
net_delta_credits: summary.net_delta_credits,
|
|
2979
|
+
scope: "current_auth_context",
|
|
2980
|
+
render: {
|
|
2981
|
+
sections: [
|
|
2982
|
+
{
|
|
2983
|
+
title: "billing ledger",
|
|
2984
|
+
lines: [
|
|
2985
|
+
`Billing ledger written to ${outputPath}`,
|
|
2986
|
+
`${summary.row_count} row(s) exported for the current auth context.`,
|
|
2987
|
+
`Net ledger delta: ${summary.net_delta_credits} Deepline Credits`
|
|
2988
|
+
]
|
|
2989
|
+
}
|
|
2990
|
+
]
|
|
2991
|
+
},
|
|
2992
|
+
local: { output_path: outputPath }
|
|
2848
2993
|
},
|
|
2849
|
-
|
|
2850
|
-
|
|
2994
|
+
{ json: options.json }
|
|
2995
|
+
);
|
|
2851
2996
|
}
|
|
2852
2997
|
async function handleCheckout(options) {
|
|
2853
2998
|
const { http } = getAuthedHttpClient();
|
|
2854
|
-
const payload = await http.post(
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2999
|
+
const payload = await http.post(
|
|
3000
|
+
"/api/v2/billing/checkout",
|
|
3001
|
+
{
|
|
3002
|
+
...options.tier ? { tierId: options.tier } : {},
|
|
3003
|
+
...options.credits ? { credits: Number.parseInt(options.credits, 10) } : {},
|
|
3004
|
+
...options.discountCode ? { discountCode: options.discountCode } : {}
|
|
3005
|
+
}
|
|
3006
|
+
);
|
|
2859
3007
|
const url = String(payload.url || payload.checkout_url || "");
|
|
2860
3008
|
if (!options.json && !options.noOpen && url) openInBrowser(url);
|
|
2861
|
-
printCommandEnvelope(
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
3009
|
+
printCommandEnvelope(
|
|
3010
|
+
{
|
|
3011
|
+
...payload,
|
|
3012
|
+
render: {
|
|
3013
|
+
sections: [
|
|
3014
|
+
{
|
|
3015
|
+
title: "billing checkout",
|
|
3016
|
+
lines: [url || "Checkout session created."]
|
|
3017
|
+
}
|
|
3018
|
+
]
|
|
3019
|
+
}
|
|
3020
|
+
},
|
|
3021
|
+
{ json: options.json }
|
|
3022
|
+
);
|
|
2865
3023
|
}
|
|
2866
3024
|
async function handleRedeemCode(code, options) {
|
|
2867
3025
|
const { http } = getAuthedHttpClient();
|
|
2868
|
-
const payload = await http.post(
|
|
2869
|
-
|
|
2870
|
-
|
|
3026
|
+
const payload = await http.post(
|
|
3027
|
+
"/api/v2/billing/checkout",
|
|
3028
|
+
{
|
|
3029
|
+
discountCode: code
|
|
3030
|
+
}
|
|
3031
|
+
);
|
|
2871
3032
|
const url = String(payload.url || payload.checkout_url || "");
|
|
2872
3033
|
if (!options.json && !options.noOpen && url) openInBrowser(url);
|
|
2873
|
-
printCommandEnvelope(
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
3034
|
+
printCommandEnvelope(
|
|
3035
|
+
{
|
|
3036
|
+
...payload,
|
|
3037
|
+
render: {
|
|
3038
|
+
sections: [{ title: "billing code", lines: [url || "Code redeemed."] }]
|
|
3039
|
+
}
|
|
3040
|
+
},
|
|
3041
|
+
{ json: options.json }
|
|
3042
|
+
);
|
|
2877
3043
|
}
|
|
2878
3044
|
function registerBillingCommands(program) {
|
|
2879
3045
|
const billing = program.command("billing").description("Inspect balance, usage, limits, and checkout flows.").addHelpText(
|
|
@@ -2981,7 +3147,10 @@ Examples:
|
|
|
2981
3147
|
deepline billing ledger export all
|
|
2982
3148
|
deepline billing ledger export all --json
|
|
2983
3149
|
`
|
|
2984
|
-
).option("--output <path>", "Write CSV to an explicit path").option(
|
|
3150
|
+
).option("--output <path>", "Write CSV to an explicit path").option(
|
|
3151
|
+
"--json",
|
|
3152
|
+
"Emit JSON output. Also automatic when stdout is piped"
|
|
3153
|
+
).action(handleLedgerExportAll)
|
|
2985
3154
|
)
|
|
2986
3155
|
);
|
|
2987
3156
|
billing.command("history").description("Export billing ledger history to CSV.").addHelpText(
|
|
@@ -2996,7 +3165,9 @@ Examples:
|
|
|
2996
3165
|
deepline billing history --time 1y --json
|
|
2997
3166
|
`
|
|
2998
3167
|
).requiredOption("--time <window>", "Rolling time window: 1d, 1w, 1m, or 1y").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleHistory);
|
|
2999
|
-
billing.command("checkout").description(
|
|
3168
|
+
billing.command("checkout").description(
|
|
3169
|
+
"Create a checkout session and optionally open it in your browser."
|
|
3170
|
+
).addHelpText(
|
|
3000
3171
|
"after",
|
|
3001
3172
|
`
|
|
3002
3173
|
Notes:
|
|
@@ -3042,12 +3213,18 @@ function formatDatasetExecutionStats(raw, denominator) {
|
|
|
3042
3213
|
readCount(raw.completed),
|
|
3043
3214
|
denominator
|
|
3044
3215
|
),
|
|
3045
|
-
"completed:reused": datasetSummaryPercentText(
|
|
3216
|
+
"completed:reused": datasetSummaryPercentText(
|
|
3217
|
+
readCount(raw.cached),
|
|
3218
|
+
denominator
|
|
3219
|
+
),
|
|
3046
3220
|
"skipped:condition": datasetSummaryPercentText(
|
|
3047
3221
|
readCount(raw.skipped),
|
|
3048
3222
|
denominator
|
|
3049
3223
|
),
|
|
3050
|
-
"skipped:missed": datasetSummaryPercentText(
|
|
3224
|
+
"skipped:missed": datasetSummaryPercentText(
|
|
3225
|
+
readCount(raw.missed),
|
|
3226
|
+
denominator
|
|
3227
|
+
),
|
|
3051
3228
|
failed: datasetSummaryPercentText(readCount(raw.failed), denominator)
|
|
3052
3229
|
};
|
|
3053
3230
|
}
|
|
@@ -3228,19 +3405,51 @@ function collectCanonicalRowsInfos(statusOrResult) {
|
|
|
3228
3405
|
const metadata = isRecord2(result._metadata) ? result._metadata : null;
|
|
3229
3406
|
const totalFromMetadata = metadata?.totalRows ?? metadata?.rowCount ?? metadata?.count;
|
|
3230
3407
|
const candidates = [
|
|
3231
|
-
{
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3408
|
+
{
|
|
3409
|
+
source: "result.contacts",
|
|
3410
|
+
value: result.contacts,
|
|
3411
|
+
total: totalFromMetadata ?? result.totalRows ?? result.rowCount ?? result.count
|
|
3412
|
+
},
|
|
3413
|
+
{
|
|
3414
|
+
source: "result.previewRows",
|
|
3415
|
+
value: result.previewRows,
|
|
3416
|
+
total: totalFromMetadata ?? result.totalRows ?? result.rowCount ?? result.count
|
|
3417
|
+
},
|
|
3418
|
+
{
|
|
3419
|
+
source: "result.rows",
|
|
3420
|
+
value: result.rows,
|
|
3421
|
+
total: totalFromMetadata ?? result.totalRows ?? result.rowCount ?? result.count
|
|
3422
|
+
},
|
|
3423
|
+
{
|
|
3424
|
+
source: "result.results",
|
|
3425
|
+
value: result.results,
|
|
3426
|
+
total: totalFromMetadata ?? result.totalRows ?? result.rowCount ?? result.count
|
|
3427
|
+
}
|
|
3235
3428
|
];
|
|
3236
3429
|
if (isRecord2(result.output)) {
|
|
3237
3430
|
const outputMetadata = isRecord2(result.output._metadata) ? result.output._metadata : null;
|
|
3238
3431
|
const outputTotalFromMetadata = outputMetadata?.totalRows ?? outputMetadata?.rowCount ?? outputMetadata?.count;
|
|
3239
3432
|
candidates.push(
|
|
3240
|
-
{
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3433
|
+
{
|
|
3434
|
+
source: "result.output.contacts",
|
|
3435
|
+
value: result.output.contacts,
|
|
3436
|
+
total: outputTotalFromMetadata ?? result.output.totalRows ?? result.output.rowCount ?? result.output.count
|
|
3437
|
+
},
|
|
3438
|
+
{
|
|
3439
|
+
source: "result.output.previewRows",
|
|
3440
|
+
value: result.output.previewRows,
|
|
3441
|
+
total: outputTotalFromMetadata ?? result.output.totalRows ?? result.output.rowCount ?? result.output.count
|
|
3442
|
+
},
|
|
3443
|
+
{
|
|
3444
|
+
source: "result.output.rows",
|
|
3445
|
+
value: result.output.rows,
|
|
3446
|
+
total: outputTotalFromMetadata ?? result.output.totalRows ?? result.output.rowCount ?? result.output.count
|
|
3447
|
+
},
|
|
3448
|
+
{
|
|
3449
|
+
source: "result.output.results",
|
|
3450
|
+
value: result.output.results,
|
|
3451
|
+
total: outputTotalFromMetadata ?? result.output.totalRows ?? result.output.rowCount ?? result.output.count
|
|
3452
|
+
}
|
|
3244
3453
|
);
|
|
3245
3454
|
}
|
|
3246
3455
|
collectDatasetCandidates({
|
|
@@ -3378,7 +3587,8 @@ function compactCell(value) {
|
|
|
3378
3587
|
const parsed = parseJsonLike(value);
|
|
3379
3588
|
if (parsed === null || parsed === void 0) return "";
|
|
3380
3589
|
if (typeof parsed === "string") return compactScalar(parsed, 120);
|
|
3381
|
-
if (typeof parsed === "number" || typeof parsed === "boolean")
|
|
3590
|
+
if (typeof parsed === "number" || typeof parsed === "boolean")
|
|
3591
|
+
return String(parsed);
|
|
3382
3592
|
if (Array.isArray(parsed)) {
|
|
3383
3593
|
if (parsed.length === 0) return "";
|
|
3384
3594
|
if (parsed.slice(0, 3).every((item) => ["string", "number", "boolean"].includes(typeof item))) {
|
|
@@ -3392,7 +3602,15 @@ function compactCell(value) {
|
|
|
3392
3602
|
return compactCell(parsed[key]);
|
|
3393
3603
|
}
|
|
3394
3604
|
}
|
|
3395
|
-
const preferred = [
|
|
3605
|
+
const preferred = [
|
|
3606
|
+
"email",
|
|
3607
|
+
"status",
|
|
3608
|
+
"name",
|
|
3609
|
+
"full_name",
|
|
3610
|
+
"title",
|
|
3611
|
+
"domain",
|
|
3612
|
+
"linkedin_url"
|
|
3613
|
+
];
|
|
3396
3614
|
const parts = [];
|
|
3397
3615
|
for (const key of preferred) {
|
|
3398
3616
|
if (parsed[key] !== null && parsed[key] !== void 0 && parsed[key] !== "") {
|
|
@@ -3434,7 +3652,10 @@ function buildDatasetStats(rows, totalRows = rows.length, columns = inferColumns
|
|
|
3434
3652
|
};
|
|
3435
3653
|
const rawExecutionStats = executionStats?.columnStats[column];
|
|
3436
3654
|
if (rawExecutionStats) {
|
|
3437
|
-
stat3.execution = formatDatasetExecutionStats(
|
|
3655
|
+
stat3.execution = formatDatasetExecutionStats(
|
|
3656
|
+
rawExecutionStats,
|
|
3657
|
+
totalRows
|
|
3658
|
+
);
|
|
3438
3659
|
}
|
|
3439
3660
|
if (sampleValue !== void 0 && sampleValueType) {
|
|
3440
3661
|
stat3.sample_value = sampleValue;
|
|
@@ -3476,11 +3697,7 @@ function writeCanonicalRowsCsv(rowsInfo, outPath) {
|
|
|
3476
3697
|
const rows = dataExportRows(sanitized.rows);
|
|
3477
3698
|
const columns = dataExportColumns(rows, sanitized.columns);
|
|
3478
3699
|
const resolved = resolve4(outPath);
|
|
3479
|
-
writeFileSync4(
|
|
3480
|
-
resolved,
|
|
3481
|
-
csvStringFromRows(rows, columns),
|
|
3482
|
-
"utf-8"
|
|
3483
|
-
);
|
|
3700
|
+
writeFileSync4(resolved, csvStringFromRows(rows, columns), "utf-8");
|
|
3484
3701
|
return resolved;
|
|
3485
3702
|
}
|
|
3486
3703
|
|
|
@@ -3491,7 +3708,9 @@ function parseRowRange(raw) {
|
|
|
3491
3708
|
const start = Number.parseInt(startRaw ?? "", 10);
|
|
3492
3709
|
const end = Number.parseInt(endRaw ?? "", 10);
|
|
3493
3710
|
if (!Number.isFinite(start) || !Number.isFinite(end) || start < 0 || end < start) {
|
|
3494
|
-
throw new Error(
|
|
3711
|
+
throw new Error(
|
|
3712
|
+
`Invalid --rows value: ${source} (expected start:end, e.g. 0:19).`
|
|
3713
|
+
);
|
|
3495
3714
|
}
|
|
3496
3715
|
return [start, end];
|
|
3497
3716
|
}
|
|
@@ -3502,7 +3721,9 @@ function selectColumns(rows, rawColumns) {
|
|
|
3502
3721
|
if (!rawColumns?.trim()) return rows;
|
|
3503
3722
|
const requested = rawColumns.split(",").map((part) => part.trim()).filter(Boolean);
|
|
3504
3723
|
if (requested.length === 0) {
|
|
3505
|
-
throw new Error(
|
|
3724
|
+
throw new Error(
|
|
3725
|
+
"Invalid --columns value: provide at least one column name."
|
|
3726
|
+
);
|
|
3506
3727
|
}
|
|
3507
3728
|
const available = new Set(Object.keys(rows[0] ?? {}));
|
|
3508
3729
|
const missing = requested.filter((column) => !available.has(column));
|
|
@@ -3539,13 +3760,22 @@ function renderTable(rows, totalRows, verbose) {
|
|
|
3539
3760
|
return display.padEnd(widths[column]);
|
|
3540
3761
|
}).join(" | ")
|
|
3541
3762
|
);
|
|
3542
|
-
return [
|
|
3763
|
+
return [
|
|
3764
|
+
header,
|
|
3765
|
+
divider,
|
|
3766
|
+
...body,
|
|
3767
|
+
"",
|
|
3768
|
+
`showing ${rows.length} row(s) of ${totalRows}`
|
|
3769
|
+
].join("\n");
|
|
3543
3770
|
}
|
|
3544
3771
|
async function handleCsvShow(options) {
|
|
3545
3772
|
const csvPath = options.csv;
|
|
3546
3773
|
const [rowStart, rowEnd] = parseRowRange(options.rows);
|
|
3547
3774
|
const allRows = readCsvRows(csvPath);
|
|
3548
|
-
const selected = selectColumns(
|
|
3775
|
+
const selected = selectColumns(
|
|
3776
|
+
selectRows(allRows, rowStart, rowEnd),
|
|
3777
|
+
options.columns
|
|
3778
|
+
);
|
|
3549
3779
|
const format = options.format ?? "json";
|
|
3550
3780
|
if (options.summary) {
|
|
3551
3781
|
printJson(buildDatasetStats(selected, allRows.length));
|
|
@@ -3562,13 +3792,17 @@ async function handleCsvShow(options) {
|
|
|
3562
3792
|
process.stdout.write(`${columns.join(",")}
|
|
3563
3793
|
`);
|
|
3564
3794
|
for (const row of selected) {
|
|
3565
|
-
process.stdout.write(
|
|
3566
|
-
|
|
3795
|
+
process.stdout.write(
|
|
3796
|
+
`${columns.map((column) => JSON.stringify(row[column] ?? "")).join(",")}
|
|
3797
|
+
`
|
|
3798
|
+
);
|
|
3567
3799
|
}
|
|
3568
3800
|
return;
|
|
3569
3801
|
}
|
|
3570
|
-
process.stdout.write(
|
|
3571
|
-
|
|
3802
|
+
process.stdout.write(
|
|
3803
|
+
`${renderTable(selected, allRows.length, Boolean(options.verbose))}
|
|
3804
|
+
`
|
|
3805
|
+
);
|
|
3572
3806
|
}
|
|
3573
3807
|
function registerCsvCommands(program) {
|
|
3574
3808
|
const csv = program.command("csv").description("Inspect local CSV files.").addHelpText(
|
|
@@ -3601,12 +3835,7 @@ Examples:
|
|
|
3601
3835
|
// src/cli/commands/db.ts
|
|
3602
3836
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
3603
3837
|
import { resolve as resolve5 } from "path";
|
|
3604
|
-
var CUSTOMER_DB_QUERY_FORMATS = /* @__PURE__ */ new Set([
|
|
3605
|
-
"table",
|
|
3606
|
-
"json",
|
|
3607
|
-
"csv",
|
|
3608
|
-
"markdown"
|
|
3609
|
-
]);
|
|
3838
|
+
var CUSTOMER_DB_QUERY_FORMATS = /* @__PURE__ */ new Set(["table", "json", "csv", "markdown"]);
|
|
3610
3839
|
function parsePositiveInteger(value, flagName) {
|
|
3611
3840
|
const parsed = Number.parseInt(value, 10);
|
|
3612
3841
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
@@ -3621,10 +3850,17 @@ function formatCell(value) {
|
|
|
3621
3850
|
}
|
|
3622
3851
|
function tableLines(result) {
|
|
3623
3852
|
const rows = dataExportRows(customerDbRows(result));
|
|
3624
|
-
const responseColumns = dataExportColumns(
|
|
3625
|
-
|
|
3853
|
+
const responseColumns = dataExportColumns(
|
|
3854
|
+
rows,
|
|
3855
|
+
customerDbColumnNames(result)
|
|
3856
|
+
);
|
|
3857
|
+
const businessColumns = responseColumns.filter(
|
|
3858
|
+
(column) => !column.startsWith("_")
|
|
3859
|
+
);
|
|
3626
3860
|
const columns = businessColumns.length > 0 ? businessColumns : responseColumns;
|
|
3627
|
-
const hiddenColumns = responseColumns.filter(
|
|
3861
|
+
const hiddenColumns = responseColumns.filter(
|
|
3862
|
+
(column) => !columns.includes(column)
|
|
3863
|
+
);
|
|
3628
3864
|
const lines = [
|
|
3629
3865
|
`${result.command} returned ${result.row_count_returned} row(s)` + (result.truncated ? " (truncated)" : "")
|
|
3630
3866
|
];
|
|
@@ -3632,7 +3868,9 @@ function tableLines(result) {
|
|
|
3632
3868
|
lines.push(
|
|
3633
3869
|
`Showing ${columns.length}/${responseColumns.length} columns; hidden metadata: ${hiddenColumns.join(", ")}`
|
|
3634
3870
|
);
|
|
3635
|
-
lines.push(
|
|
3871
|
+
lines.push(
|
|
3872
|
+
"Use --json or select metadata columns explicitly when you need run ids/errors/stages."
|
|
3873
|
+
);
|
|
3636
3874
|
}
|
|
3637
3875
|
if (rows.length === 0) {
|
|
3638
3876
|
return lines;
|
|
@@ -3646,7 +3884,9 @@ function tableLines(result) {
|
|
|
3646
3884
|
)
|
|
3647
3885
|
)
|
|
3648
3886
|
);
|
|
3649
|
-
lines.push(
|
|
3887
|
+
lines.push(
|
|
3888
|
+
columns.map((column, index) => column.padEnd(widths[index])).join(" ")
|
|
3889
|
+
);
|
|
3650
3890
|
lines.push(widths.map((width) => "-".repeat(width)).join(" "));
|
|
3651
3891
|
for (const row of rows) {
|
|
3652
3892
|
lines.push(
|
|
@@ -3722,10 +3962,12 @@ async function handleDbQuery(args) {
|
|
|
3722
3962
|
const explicitJsonOutput = args.includes("--json");
|
|
3723
3963
|
const client = new DeeplineClient();
|
|
3724
3964
|
const result = await client.queryCustomerDb({ sql, maxRows });
|
|
3725
|
-
const toolCommand = `deepline tools execute query_customer_db --payload ${JSON.stringify(
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3965
|
+
const toolCommand = `deepline tools execute query_customer_db --payload ${JSON.stringify(
|
|
3966
|
+
{
|
|
3967
|
+
sql,
|
|
3968
|
+
...maxRows ? { max_rows: maxRows } : {}
|
|
3969
|
+
}
|
|
3970
|
+
)} --json`;
|
|
3729
3971
|
if (format === "csv") {
|
|
3730
3972
|
if (outPath) {
|
|
3731
3973
|
const exportedPath = writeCustomerDbCsv(result, outPath);
|
|
@@ -3753,7 +3995,10 @@ async function handleDbQuery(args) {
|
|
|
3753
3995
|
}),
|
|
3754
3996
|
{
|
|
3755
3997
|
json: explicitJsonOutput,
|
|
3756
|
-
text: dataExportCsvString(
|
|
3998
|
+
text: dataExportCsvString(
|
|
3999
|
+
customerDbRows(result),
|
|
4000
|
+
customerDbColumnNames(result)
|
|
4001
|
+
)
|
|
3757
4002
|
}
|
|
3758
4003
|
);
|
|
3759
4004
|
return 0;
|
|
@@ -3795,14 +4040,17 @@ async function handleDbQuery(args) {
|
|
|
3795
4040
|
);
|
|
3796
4041
|
return 0;
|
|
3797
4042
|
}
|
|
3798
|
-
printCommandEnvelope(
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
4043
|
+
printCommandEnvelope(
|
|
4044
|
+
{
|
|
4045
|
+
...result,
|
|
4046
|
+
next: { toolEquivalent: toolCommand },
|
|
4047
|
+
render: {
|
|
4048
|
+
sections: [{ title: "customer db query", lines: tableLines(result) }],
|
|
4049
|
+
actions: [{ label: "Tool equivalent", command: toolCommand }]
|
|
4050
|
+
}
|
|
4051
|
+
},
|
|
4052
|
+
{ json: jsonOutput || format === "json" }
|
|
4053
|
+
);
|
|
3806
4054
|
return 0;
|
|
3807
4055
|
}
|
|
3808
4056
|
function registerDbCommands(program) {
|
|
@@ -3838,7 +4086,10 @@ Examples:
|
|
|
3838
4086
|
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
3839
4087
|
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
3840
4088
|
`
|
|
3841
|
-
).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(
|
|
4089
|
+
).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(
|
|
4090
|
+
"--json",
|
|
4091
|
+
"Emit raw JSON response. Also automatic when stdout is piped"
|
|
4092
|
+
).action(async (options) => {
|
|
3842
4093
|
process.exitCode = await handleDbQuery([
|
|
3843
4094
|
"--sql",
|
|
3844
4095
|
options.sql,
|
|
@@ -3859,12 +4110,17 @@ async function handleFeedback(text, options) {
|
|
|
3859
4110
|
...options.command ? { command: options.command } : {},
|
|
3860
4111
|
...options.payload ? { payload: options.payload } : {}
|
|
3861
4112
|
});
|
|
3862
|
-
printCommandEnvelope(
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
4113
|
+
printCommandEnvelope(
|
|
4114
|
+
{
|
|
4115
|
+
...response,
|
|
4116
|
+
render: {
|
|
4117
|
+
sections: [
|
|
4118
|
+
{ title: "feedback", lines: ["Feedback submitted. Thank you."] }
|
|
4119
|
+
]
|
|
4120
|
+
}
|
|
4121
|
+
},
|
|
4122
|
+
{ json: options.json }
|
|
4123
|
+
);
|
|
3868
4124
|
}
|
|
3869
4125
|
function registerFeedbackCommands(program) {
|
|
3870
4126
|
const feedback = program.command("feedback").description("Submit CLI feedback to Deepline.").addHelpText(
|
|
@@ -3907,76 +4163,106 @@ async function handleOrgList(options) {
|
|
|
3907
4163
|
const config = resolveConfig();
|
|
3908
4164
|
const http = new HttpClient(config);
|
|
3909
4165
|
const payload = await fetchOrganizations(http, config.apiKey);
|
|
3910
|
-
printCommandEnvelope(
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
4166
|
+
printCommandEnvelope(
|
|
4167
|
+
{
|
|
4168
|
+
...payload,
|
|
4169
|
+
render: {
|
|
4170
|
+
sections: [
|
|
4171
|
+
{
|
|
4172
|
+
title: "Your organizations:",
|
|
4173
|
+
lines: orgListLines(payload.organizations)
|
|
4174
|
+
}
|
|
4175
|
+
]
|
|
4176
|
+
}
|
|
4177
|
+
},
|
|
4178
|
+
{ json: options.json }
|
|
4179
|
+
);
|
|
3916
4180
|
}
|
|
3917
4181
|
async function handleOrgSwitch(selection, options) {
|
|
3918
4182
|
const config = resolveConfig();
|
|
3919
4183
|
const http = new HttpClient(config);
|
|
3920
4184
|
const payload = await fetchOrganizations(http, config.apiKey);
|
|
3921
4185
|
if (!selection && !options.orgId) {
|
|
3922
|
-
printCommandEnvelope(
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
4186
|
+
printCommandEnvelope(
|
|
4187
|
+
{
|
|
4188
|
+
...payload,
|
|
4189
|
+
next: { switch: "deepline org switch <number>" },
|
|
4190
|
+
render: {
|
|
4191
|
+
sections: [
|
|
4192
|
+
{
|
|
4193
|
+
title: "Your organizations:",
|
|
4194
|
+
lines: orgListLines(payload.organizations)
|
|
4195
|
+
}
|
|
4196
|
+
],
|
|
4197
|
+
actions: [{ label: "Run", command: "deepline org switch <number>" }]
|
|
4198
|
+
}
|
|
4199
|
+
},
|
|
4200
|
+
{ json: options.json }
|
|
4201
|
+
);
|
|
3930
4202
|
return;
|
|
3931
4203
|
}
|
|
3932
|
-
let target = payload.organizations.find(
|
|
4204
|
+
let target = payload.organizations.find(
|
|
4205
|
+
(org) => org.org_id === options.orgId
|
|
4206
|
+
);
|
|
3933
4207
|
if (!target && selection) {
|
|
3934
4208
|
const index = Number.parseInt(selection, 10);
|
|
3935
4209
|
if (Number.isFinite(index) && index >= 1 && index <= payload.organizations.length) {
|
|
3936
4210
|
target = payload.organizations[index - 1];
|
|
3937
4211
|
} else {
|
|
3938
|
-
target = payload.organizations.find(
|
|
4212
|
+
target = payload.organizations.find(
|
|
4213
|
+
(org) => org.name === selection || org.org_id === selection
|
|
4214
|
+
);
|
|
3939
4215
|
}
|
|
3940
4216
|
}
|
|
3941
4217
|
if (!target) {
|
|
3942
4218
|
throw new Error("Could not resolve the selected organization.");
|
|
3943
4219
|
}
|
|
3944
4220
|
if (target.is_current) {
|
|
3945
|
-
printCommandEnvelope(
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
4221
|
+
printCommandEnvelope(
|
|
4222
|
+
{
|
|
4223
|
+
ok: true,
|
|
4224
|
+
unchanged: true,
|
|
4225
|
+
organization: target,
|
|
4226
|
+
render: {
|
|
4227
|
+
sections: [
|
|
4228
|
+
{ title: "org switch", lines: [`Already on ${target.name}.`] }
|
|
4229
|
+
]
|
|
4230
|
+
}
|
|
4231
|
+
},
|
|
4232
|
+
{ json: options.json }
|
|
4233
|
+
);
|
|
3951
4234
|
return;
|
|
3952
4235
|
}
|
|
3953
|
-
const switched = await http.post(
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
);
|
|
4236
|
+
const switched = await http.post("/api/v2/auth/cli/switch", {
|
|
4237
|
+
api_key: config.apiKey,
|
|
4238
|
+
org_id: target.org_id
|
|
4239
|
+
});
|
|
3957
4240
|
saveHostEnvValues(config.baseUrl, {
|
|
3958
4241
|
DEEPLINE_API_KEY: switched.api_key,
|
|
3959
4242
|
DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
|
|
3960
4243
|
DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
|
|
3961
4244
|
});
|
|
3962
4245
|
const { api_key: _apiKey, ...publicSwitched } = switched;
|
|
3963
|
-
printCommandEnvelope(
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
4246
|
+
printCommandEnvelope(
|
|
4247
|
+
{
|
|
4248
|
+
ok: true,
|
|
4249
|
+
host_env_path: hostEnvFilePath(config.baseUrl),
|
|
4250
|
+
...publicSwitched,
|
|
4251
|
+
api_key_saved: true,
|
|
4252
|
+
render: {
|
|
4253
|
+
sections: [
|
|
4254
|
+
{
|
|
4255
|
+
title: "org switch",
|
|
4256
|
+
lines: [
|
|
4257
|
+
`Switched to ${switched.org_name}.`,
|
|
4258
|
+
`Saved host auth in ${hostEnvFilePath(config.baseUrl)}`
|
|
4259
|
+
]
|
|
4260
|
+
}
|
|
4261
|
+
]
|
|
4262
|
+
}
|
|
4263
|
+
},
|
|
4264
|
+
{ json: options.json }
|
|
4265
|
+
);
|
|
3980
4266
|
}
|
|
3981
4267
|
function registerOrgCommands(program) {
|
|
3982
4268
|
const org = program.command("org").description("List and switch organizations.").addHelpText(
|
|
@@ -4003,7 +4289,9 @@ Examples:
|
|
|
4003
4289
|
deepline org list --json
|
|
4004
4290
|
`
|
|
4005
4291
|
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgList);
|
|
4006
|
-
org.command("switch [selection]").description(
|
|
4292
|
+
org.command("switch [selection]").description(
|
|
4293
|
+
"Switch to another organization and save the new API key in the host auth file."
|
|
4294
|
+
).addHelpText(
|
|
4007
4295
|
"after",
|
|
4008
4296
|
`
|
|
4009
4297
|
Notes:
|
|
@@ -5228,8 +5516,26 @@ function resolveExecutionProfile(override) {
|
|
|
5228
5516
|
// src/plays/local-file-discovery.ts
|
|
5229
5517
|
import { createHash as createHash2 } from "crypto";
|
|
5230
5518
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
5231
|
-
import {
|
|
5232
|
-
|
|
5519
|
+
import {
|
|
5520
|
+
basename as basename2,
|
|
5521
|
+
dirname as dirname6,
|
|
5522
|
+
extname as extname2,
|
|
5523
|
+
isAbsolute as isAbsolute2,
|
|
5524
|
+
join as join4,
|
|
5525
|
+
relative,
|
|
5526
|
+
resolve as resolve7
|
|
5527
|
+
} from "path";
|
|
5528
|
+
var SOURCE_EXTENSIONS2 = [
|
|
5529
|
+
".ts",
|
|
5530
|
+
".tsx",
|
|
5531
|
+
".mts",
|
|
5532
|
+
".cts",
|
|
5533
|
+
".js",
|
|
5534
|
+
".jsx",
|
|
5535
|
+
".mjs",
|
|
5536
|
+
".cjs",
|
|
5537
|
+
".json"
|
|
5538
|
+
];
|
|
5233
5539
|
function sha2562(buffer) {
|
|
5234
5540
|
return createHash2("sha256").update(buffer).digest("hex");
|
|
5235
5541
|
}
|
|
@@ -5253,7 +5559,9 @@ function unquoteStringLiteral2(literal) {
|
|
|
5253
5559
|
return null;
|
|
5254
5560
|
}
|
|
5255
5561
|
try {
|
|
5256
|
-
return JSON.parse(
|
|
5562
|
+
return JSON.parse(
|
|
5563
|
+
quote === '"' ? trimmed : `"${trimmed.slice(1, -1).replace(/"/g, '\\"')}"`
|
|
5564
|
+
);
|
|
5257
5565
|
} catch {
|
|
5258
5566
|
return trimmed.slice(1, -1);
|
|
5259
5567
|
}
|
|
@@ -5314,7 +5622,9 @@ function resolveStringExpression(expression, constants) {
|
|
|
5314
5622
|
}
|
|
5315
5623
|
const parts = splitTopLevelPlus(value);
|
|
5316
5624
|
if (parts) {
|
|
5317
|
-
const resolved = parts.map(
|
|
5625
|
+
const resolved = parts.map(
|
|
5626
|
+
(part) => resolveStringExpression(part, constants)
|
|
5627
|
+
);
|
|
5318
5628
|
return resolved.every((part) => part != null) ? resolved.join("") : null;
|
|
5319
5629
|
}
|
|
5320
5630
|
return null;
|
|
@@ -5322,7 +5632,9 @@ function resolveStringExpression(expression, constants) {
|
|
|
5322
5632
|
function collectTopLevelStringConstants(sourceCode) {
|
|
5323
5633
|
const constants = /* @__PURE__ */ new Map();
|
|
5324
5634
|
const source = stripCommentsToSpaces2(sourceCode);
|
|
5325
|
-
for (const match of source.matchAll(
|
|
5635
|
+
for (const match of source.matchAll(
|
|
5636
|
+
/(?:^|\n)\s*const\s+([A-Za-z_$][\w$]*)\s*=\s*([^;\n]+)/g
|
|
5637
|
+
)) {
|
|
5326
5638
|
const resolved = resolveStringExpression(match[2], constants);
|
|
5327
5639
|
if (resolved != null) {
|
|
5328
5640
|
constants.set(match[1], resolved);
|
|
@@ -5411,7 +5723,9 @@ function localImportSpecifiers(sourceCode) {
|
|
|
5411
5723
|
)) {
|
|
5412
5724
|
if (match[1]?.startsWith(".")) specifiers.push(match[1]);
|
|
5413
5725
|
}
|
|
5414
|
-
for (const match of source.matchAll(
|
|
5726
|
+
for (const match of source.matchAll(
|
|
5727
|
+
/\brequire\s*\(\s*(['"])(\.[^'"]*)\1\s*\)/g
|
|
5728
|
+
)) {
|
|
5415
5729
|
specifiers.push(match[2]);
|
|
5416
5730
|
}
|
|
5417
5731
|
return specifiers;
|
|
@@ -5433,18 +5747,26 @@ async function resolveLocalImport2(fromFile, specifier) {
|
|
|
5433
5747
|
const candidates = [base];
|
|
5434
5748
|
const explicitExtension = extname2(base).toLowerCase();
|
|
5435
5749
|
if (!explicitExtension) {
|
|
5436
|
-
candidates.push(
|
|
5437
|
-
|
|
5750
|
+
candidates.push(
|
|
5751
|
+
...SOURCE_EXTENSIONS2.map((extension) => `${base}${extension}`)
|
|
5752
|
+
);
|
|
5753
|
+
candidates.push(
|
|
5754
|
+
...SOURCE_EXTENSIONS2.map((extension) => join4(base, `index${extension}`))
|
|
5755
|
+
);
|
|
5438
5756
|
} else if ([".js", ".jsx", ".mjs", ".cjs"].includes(explicitExtension)) {
|
|
5439
5757
|
const stem = base.slice(0, -explicitExtension.length);
|
|
5440
|
-
candidates.push(
|
|
5758
|
+
candidates.push(
|
|
5759
|
+
...SOURCE_EXTENSIONS2.map((extension) => `${stem}${extension}`)
|
|
5760
|
+
);
|
|
5441
5761
|
}
|
|
5442
5762
|
for (const candidate of candidates) {
|
|
5443
5763
|
if (await fileExists2(candidate)) {
|
|
5444
5764
|
return candidate;
|
|
5445
5765
|
}
|
|
5446
5766
|
}
|
|
5447
|
-
throw new Error(
|
|
5767
|
+
throw new Error(
|
|
5768
|
+
`Could not resolve local import "${specifier}" from ${fromFile}`
|
|
5769
|
+
);
|
|
5448
5770
|
}
|
|
5449
5771
|
async function discoverPackagedLocalFiles(entryFile) {
|
|
5450
5772
|
const absoluteEntryFile = resolve7(entryFile);
|
|
@@ -5462,12 +5784,17 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
5462
5784
|
const scanSource = stripCommentsToSpaces2(sourceCode);
|
|
5463
5785
|
const constants = collectTopLevelStringConstants(sourceCode);
|
|
5464
5786
|
const childVisits = [];
|
|
5465
|
-
for (const match of scanSource.matchAll(
|
|
5787
|
+
for (const match of scanSource.matchAll(
|
|
5788
|
+
/\b([A-Za-z_$][\w$]*)\s*\.\s*csv\b/g
|
|
5789
|
+
)) {
|
|
5466
5790
|
const target = match[1];
|
|
5467
5791
|
if (target !== "ctx" && !target.endsWith("Ctx")) {
|
|
5468
5792
|
continue;
|
|
5469
5793
|
}
|
|
5470
|
-
const openParen = findCallOpenParen(
|
|
5794
|
+
const openParen = findCallOpenParen(
|
|
5795
|
+
scanSource,
|
|
5796
|
+
match.index + match[0].length
|
|
5797
|
+
);
|
|
5471
5798
|
if (openParen < 0) {
|
|
5472
5799
|
continue;
|
|
5473
5800
|
}
|
|
@@ -9258,7 +9585,9 @@ function buildRunPackageTextLines(packaged) {
|
|
|
9258
9585
|
lines.push(` ${kind} ${id}: ${stepStatus}${rowCount}`);
|
|
9259
9586
|
lines.push(...formatPackageDatasetSummaryLines(output?.summary));
|
|
9260
9587
|
if (previewRows !== null) {
|
|
9261
|
-
lines.push(
|
|
9588
|
+
lines.push(
|
|
9589
|
+
` preview=${previewRows}${preview?.truncated ? " truncated" : ""}`
|
|
9590
|
+
);
|
|
9262
9591
|
}
|
|
9263
9592
|
}
|
|
9264
9593
|
const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
|
|
@@ -11060,7 +11389,9 @@ function matchesPlayGrepQuery(value, query, mode) {
|
|
|
11060
11389
|
async function handlePlayGrep(args) {
|
|
11061
11390
|
const query = args[0]?.trim();
|
|
11062
11391
|
if (!query) {
|
|
11063
|
-
console.error(
|
|
11392
|
+
console.error(
|
|
11393
|
+
"Usage: deepline plays grep <query> [--mode all|any|phrase] [--compact] [--json]"
|
|
11394
|
+
);
|
|
11064
11395
|
return 1;
|
|
11065
11396
|
}
|
|
11066
11397
|
let mode = "all";
|
|
@@ -11093,13 +11424,15 @@ async function handlePlayGrep(args) {
|
|
|
11093
11424
|
)
|
|
11094
11425
|
).map((play) => summarizePlayListItemForCli(play, { compact }));
|
|
11095
11426
|
if (argsWantJson(args)) {
|
|
11096
|
-
process.stdout.write(
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11427
|
+
process.stdout.write(
|
|
11428
|
+
`${JSON.stringify({
|
|
11429
|
+
plays,
|
|
11430
|
+
count: plays.length,
|
|
11431
|
+
query,
|
|
11432
|
+
grep: { mode, terms: parsePlayGrepTerms(query, mode) }
|
|
11433
|
+
})}
|
|
11434
|
+
`
|
|
11435
|
+
);
|
|
11103
11436
|
return 0;
|
|
11104
11437
|
}
|
|
11105
11438
|
process.stdout.write(`${plays.length} plays found:
|
|
@@ -11762,7 +12095,9 @@ function normalizeRows(value) {
|
|
|
11762
12095
|
});
|
|
11763
12096
|
}
|
|
11764
12097
|
function candidateRoots(payload) {
|
|
11765
|
-
const roots = [
|
|
12098
|
+
const roots = [
|
|
12099
|
+
{ path: null, value: payload }
|
|
12100
|
+
];
|
|
11766
12101
|
if (isPlainObject(payload) && isPlainObject(payload.toolResponse)) {
|
|
11767
12102
|
roots.push({ path: "toolResponse", value: payload.toolResponse });
|
|
11768
12103
|
if (Object.prototype.hasOwnProperty.call(payload.toolResponse, "raw")) {
|
|
@@ -11789,7 +12124,9 @@ function candidateRoots(payload) {
|
|
|
11789
12124
|
function findBestArrayCandidate(value, pathPrefix = "", depth = 0) {
|
|
11790
12125
|
if (depth > 5) return null;
|
|
11791
12126
|
const directRows = normalizeRows(value);
|
|
11792
|
-
const hasObjectRow = directRows?.some(
|
|
12127
|
+
const hasObjectRow = directRows?.some(
|
|
12128
|
+
(row) => Object.keys(row).some((key) => key !== "value")
|
|
12129
|
+
) ?? false;
|
|
11793
12130
|
let best = directRows && directRows.length > 0 && hasObjectRow ? { path: pathPrefix, rows: directRows } : null;
|
|
11794
12131
|
if (!isPlainObject(value)) {
|
|
11795
12132
|
return best;
|
|
@@ -11805,7 +12142,9 @@ function findBestArrayCandidate(value, pathPrefix = "", depth = 0) {
|
|
|
11805
12142
|
return best;
|
|
11806
12143
|
}
|
|
11807
12144
|
function tryConvertToList(payload, options) {
|
|
11808
|
-
const listExtractorPaths = Array.isArray(options?.listExtractorPaths) ? options?.listExtractorPaths.filter(
|
|
12145
|
+
const listExtractorPaths = Array.isArray(options?.listExtractorPaths) ? options?.listExtractorPaths.filter(
|
|
12146
|
+
(entry) => typeof entry === "string" && entry.trim().length > 0
|
|
12147
|
+
) : [];
|
|
11809
12148
|
if (listExtractorPaths.length > 0) {
|
|
11810
12149
|
for (const root of candidateRoots(payload)) {
|
|
11811
12150
|
for (const extractorPath of listExtractorPaths) {
|
|
@@ -11871,7 +12210,9 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
11871
12210
|
const previewColumns = columns.slice(0, 5);
|
|
11872
12211
|
const preview = [
|
|
11873
12212
|
previewColumns.join(","),
|
|
11874
|
-
...previewRows.map(
|
|
12213
|
+
...previewRows.map(
|
|
12214
|
+
(row) => previewColumns.map((column) => escapeCell(row[column])).join(",")
|
|
12215
|
+
)
|
|
11875
12216
|
].join("\n");
|
|
11876
12217
|
return {
|
|
11877
12218
|
path: outputPath,
|
|
@@ -11884,9 +12225,11 @@ function extractSummaryFields(payload) {
|
|
|
11884
12225
|
const candidates = candidateRoots(payload);
|
|
11885
12226
|
for (const candidate of candidates) {
|
|
11886
12227
|
if (!isPlainObject(candidate.value)) continue;
|
|
11887
|
-
const summaryEntries = Object.entries(candidate.value).filter(
|
|
11888
|
-
|
|
11889
|
-
|
|
12228
|
+
const summaryEntries = Object.entries(candidate.value).filter(
|
|
12229
|
+
([, value]) => {
|
|
12230
|
+
return value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
12231
|
+
}
|
|
12232
|
+
);
|
|
11890
12233
|
if (summaryEntries.length === 0) continue;
|
|
11891
12234
|
return Object.fromEntries(summaryEntries);
|
|
11892
12235
|
}
|
|
@@ -12416,8 +12759,16 @@ function toolContractJsonForDescribe(tool, requestedToolId) {
|
|
|
12416
12759
|
arrayField(toolExecutionResult, "extractedValues", "extracted_values")
|
|
12417
12760
|
);
|
|
12418
12761
|
const cost = recordField(tool, "cost");
|
|
12419
|
-
const deeplineCredits = numberField(
|
|
12420
|
-
|
|
12762
|
+
const deeplineCredits = numberField(
|
|
12763
|
+
tool,
|
|
12764
|
+
"deeplineCreditsPerPricingUnit",
|
|
12765
|
+
"deepline_credits_per_pricing_unit"
|
|
12766
|
+
);
|
|
12767
|
+
const deeplineUsdPerPricingUnit = numberField(
|
|
12768
|
+
tool,
|
|
12769
|
+
"deeplineUsdPerPricingUnit",
|
|
12770
|
+
"deepline_usd_per_pricing_unit"
|
|
12771
|
+
);
|
|
12421
12772
|
const starterScript = seedToolListScript({
|
|
12422
12773
|
toolId,
|
|
12423
12774
|
payload: samplePayloadForInputFields(inputFields),
|
|
@@ -12505,7 +12856,9 @@ function printCompactToolContract(tool, requestedToolId) {
|
|
|
12505
12856
|
if (starterPath) {
|
|
12506
12857
|
console.log("");
|
|
12507
12858
|
console.log(`Starter script: ${starterPath}`);
|
|
12508
|
-
console.log(
|
|
12859
|
+
console.log(
|
|
12860
|
+
"Copy it into your project and replace the sample input with the proven probe payload."
|
|
12861
|
+
);
|
|
12509
12862
|
}
|
|
12510
12863
|
if (listGetters.length || valueGetters.length) {
|
|
12511
12864
|
console.log("");
|
|
@@ -12668,7 +13021,9 @@ function playResultExpression(entry) {
|
|
|
12668
13021
|
}
|
|
12669
13022
|
function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
12670
13023
|
const toolId = String(tool.toolId || requestedToolId);
|
|
12671
|
-
const inputFields = toolInputFieldsForDisplay(
|
|
13024
|
+
const inputFields = toolInputFieldsForDisplay(
|
|
13025
|
+
recordField(tool, "inputSchema", "input_schema")
|
|
13026
|
+
);
|
|
12672
13027
|
const starterScript = seedToolListScript({
|
|
12673
13028
|
toolId,
|
|
12674
13029
|
payload: samplePayloadForInputFields(inputFields),
|
|
@@ -12693,7 +13048,9 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
|
12693
13048
|
toolId,
|
|
12694
13049
|
provider: tool.provider,
|
|
12695
13050
|
displayName: tool.displayName,
|
|
12696
|
-
usageGuidance: usageGuidanceWithAccessDefaults(
|
|
13051
|
+
usageGuidance: usageGuidanceWithAccessDefaults(
|
|
13052
|
+
recordField(tool, "usageGuidance", "usage_guidance")
|
|
13053
|
+
),
|
|
12697
13054
|
runtimeOutputHelp: {
|
|
12698
13055
|
contract: "tools describe shows declared schema and Deepline getters; it is not an observed provider response.",
|
|
12699
13056
|
getterScope: "extractedValues/extractedLists .get() only works for declared Deepline getters listed in usageGuidance.toolExecutionResult.",
|
|
@@ -13308,8 +13665,10 @@ async function handleUpdate(options) {
|
|
|
13308
13665
|
printCommandEnvelope({ ...plan, render }, { json: false });
|
|
13309
13666
|
return 0;
|
|
13310
13667
|
}
|
|
13311
|
-
process.stderr.write(
|
|
13312
|
-
`
|
|
13668
|
+
process.stderr.write(
|
|
13669
|
+
`Updating Deepline SDK/CLI with: ${plan.manualCommand}
|
|
13670
|
+
`
|
|
13671
|
+
);
|
|
13313
13672
|
return runCommand(plan.command, plan.args);
|
|
13314
13673
|
}
|
|
13315
13674
|
function registerUpdateCommand(program) {
|
|
@@ -13333,7 +13692,14 @@ Examples:
|
|
|
13333
13692
|
|
|
13334
13693
|
// src/cli/skills-sync.ts
|
|
13335
13694
|
import { spawn as spawn2, spawnSync } from "child_process";
|
|
13336
|
-
import {
|
|
13695
|
+
import {
|
|
13696
|
+
existsSync as existsSync8,
|
|
13697
|
+
mkdirSync as mkdirSync5,
|
|
13698
|
+
readdirSync as readdirSync2,
|
|
13699
|
+
readFileSync as readFileSync6,
|
|
13700
|
+
statSync as statSync2,
|
|
13701
|
+
writeFileSync as writeFileSync9
|
|
13702
|
+
} from "fs";
|
|
13337
13703
|
import { homedir as homedir4 } from "os";
|
|
13338
13704
|
import { dirname as dirname10, join as join10 } from "path";
|
|
13339
13705
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
@@ -13346,7 +13712,14 @@ function shouldSkipSkillsSync() {
|
|
|
13346
13712
|
}
|
|
13347
13713
|
function sdkSkillsVersionPath(baseUrl) {
|
|
13348
13714
|
const home = process.env.HOME?.trim() || homedir4();
|
|
13349
|
-
return join10(
|
|
13715
|
+
return join10(
|
|
13716
|
+
home,
|
|
13717
|
+
".local",
|
|
13718
|
+
"deepline",
|
|
13719
|
+
baseUrlSlug(baseUrl),
|
|
13720
|
+
"sdk-skills",
|
|
13721
|
+
".version"
|
|
13722
|
+
);
|
|
13350
13723
|
}
|
|
13351
13724
|
function readLocalSkillsVersion(baseUrl) {
|
|
13352
13725
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
@@ -13428,7 +13801,10 @@ async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
|
13428
13801
|
}
|
|
13429
13802
|
}
|
|
13430
13803
|
function buildSkillsInstallArgs(baseUrl) {
|
|
13431
|
-
const packageUrl = new URL(
|
|
13804
|
+
const packageUrl = new URL(
|
|
13805
|
+
"/.well-known/skills/index.json",
|
|
13806
|
+
baseUrl
|
|
13807
|
+
).toString();
|
|
13432
13808
|
return [
|
|
13433
13809
|
"--yes",
|
|
13434
13810
|
"skills",
|
|
@@ -13444,7 +13820,10 @@ function buildSkillsInstallArgs(baseUrl) {
|
|
|
13444
13820
|
];
|
|
13445
13821
|
}
|
|
13446
13822
|
function buildBunxSkillsInstallArgs(baseUrl) {
|
|
13447
|
-
const packageUrl = new URL(
|
|
13823
|
+
const packageUrl = new URL(
|
|
13824
|
+
"/.well-known/skills/index.json",
|
|
13825
|
+
baseUrl
|
|
13826
|
+
).toString();
|
|
13448
13827
|
return [
|
|
13449
13828
|
"--bun",
|
|
13450
13829
|
"skills",
|