deepline 0.1.32 → 0.1.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -20
- package/dist/cli/index.js +1117 -381
- package/dist/cli/index.mjs +1058 -322
- package/dist/index.d.mts +131 -85
- package/dist/index.d.ts +131 -85
- package/dist/index.js +569 -124
- package/dist/index.mjs +570 -125
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +212 -1
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +129 -2
- package/dist/repo/apps/play-runner-workers/src/entry.ts +147 -64
- package/dist/repo/apps/play-runner-workers/src/workflow-retry.ts +50 -0
- package/dist/repo/sdk/src/client.ts +46 -33
- package/dist/repo/sdk/src/config.ts +109 -233
- package/dist/repo/sdk/src/http.ts +44 -4
- package/dist/repo/sdk/src/index.ts +8 -5
- package/dist/repo/sdk/src/play.ts +124 -45
- package/dist/repo/sdk/src/plays/harness-stub.ts +2 -2
- package/dist/repo/sdk/src/tool-output.ts +26 -7
- package/dist/repo/sdk/src/types.ts +48 -12
- 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/scheduler-backend.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +138 -35
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -67,19 +67,12 @@ var ConfigError = class extends DeeplineError {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
// src/config.ts
|
|
70
|
+
var HOST_URL_ENV = "DEEPLINE_HOST_URL";
|
|
71
|
+
var API_KEY_ENV = "DEEPLINE_API_KEY";
|
|
70
72
|
var PROD_URL = "https://code.deepline.com";
|
|
71
73
|
var DEFAULT_TIMEOUT = 6e4;
|
|
72
74
|
var DEFAULT_MAX_RETRIES = 3;
|
|
73
|
-
var
|
|
74
|
-
function isProdBaseUrl(baseUrl) {
|
|
75
|
-
return baseUrl.trim().replace(/\/$/, "") === PROD_URL;
|
|
76
|
-
}
|
|
77
|
-
function profileNameForBaseUrl(baseUrl) {
|
|
78
|
-
return isProdBaseUrl(baseUrl) ? "prod" : "dev";
|
|
79
|
-
}
|
|
80
|
-
function projectEnvStartDir() {
|
|
81
|
-
return process.env.DEEPLINE_PROJECT_ENV_DIR?.trim() || process.cwd();
|
|
82
|
-
}
|
|
75
|
+
var PROJECT_DEEPLINE_ENV_FILE = ".env.deepline";
|
|
83
76
|
function baseUrlSlug(baseUrl) {
|
|
84
77
|
let url;
|
|
85
78
|
try {
|
|
@@ -88,7 +81,7 @@ function baseUrlSlug(baseUrl) {
|
|
|
88
81
|
return "unknown";
|
|
89
82
|
}
|
|
90
83
|
const host = url.hostname || "unknown";
|
|
91
|
-
const port = url.port ? parseInt(url.port, 10) : null;
|
|
84
|
+
const port = url.port ? Number.parseInt(url.port, 10) : null;
|
|
92
85
|
let slug = host.replace(/[^a-zA-Z0-9]/g, "-");
|
|
93
86
|
if (port && port !== 80 && port !== 443) {
|
|
94
87
|
slug = `${slug}-${port}`;
|
|
@@ -115,79 +108,52 @@ function parseEnvFile(filePath) {
|
|
|
115
108
|
}
|
|
116
109
|
return env;
|
|
117
110
|
}
|
|
118
|
-
function findNearestEnvFile(
|
|
111
|
+
function findNearestEnvFile(name, startDir = process.cwd()) {
|
|
119
112
|
let current = (0, import_node_path.resolve)(startDir);
|
|
120
113
|
while (true) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if ((0, import_node_fs.existsSync)(filePath)) return filePath;
|
|
124
|
-
}
|
|
114
|
+
const filePath = (0, import_node_path.join)(current, name);
|
|
115
|
+
if ((0, import_node_fs.existsSync)(filePath)) return filePath;
|
|
125
116
|
const parent = (0, import_node_path.dirname)(current);
|
|
126
117
|
if (parent === current) return null;
|
|
127
118
|
current = parent;
|
|
128
119
|
}
|
|
129
120
|
}
|
|
130
|
-
function
|
|
131
|
-
const filePath = findNearestEnvFile(
|
|
121
|
+
function loadProjectDeeplineEnv(startDir = process.cwd()) {
|
|
122
|
+
const filePath = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
|
|
132
123
|
return filePath ? parseEnvFile(filePath) : {};
|
|
133
124
|
}
|
|
134
|
-
function
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
function resolveProfileEnvFileNames() {
|
|
138
|
-
const explicitProfile = process.env.DEEPLINE_ENV_PROFILE?.trim() || process.env.DEEPLINE_PROFILE?.trim() || "";
|
|
139
|
-
const names = [];
|
|
140
|
-
if (explicitProfile) names.push(`.env.deepline.${explicitProfile}`);
|
|
141
|
-
const nodeEnv = process.env.NODE_ENV?.trim();
|
|
142
|
-
if (nodeEnv === "production") names.push(".env.deepline.prod");
|
|
143
|
-
else if (nodeEnv === "staging") names.push(".env.deepline.staging");
|
|
144
|
-
names.push(ACTIVE_DEEPLINE_ENV_FILE);
|
|
145
|
-
return names;
|
|
146
|
-
}
|
|
147
|
-
function resolveProjectAppEnvFileNames() {
|
|
148
|
-
const nodeEnv = process.env.NODE_ENV?.trim();
|
|
149
|
-
const names = [];
|
|
150
|
-
if (nodeEnv === "production") names.push(".env.prod");
|
|
151
|
-
if (nodeEnv === "staging") names.push(".env.staging");
|
|
152
|
-
names.push(".env.local", ".env");
|
|
153
|
-
return names;
|
|
154
|
-
}
|
|
155
|
-
function resolveBaseUrlFromEnvValues(env) {
|
|
156
|
-
return env.DEEPLINE_ORIGIN_URL?.trim() || env.DEEPLINE_API_BASE_URL?.trim() || "";
|
|
157
|
-
}
|
|
158
|
-
function loadProjectDeeplineEnv() {
|
|
159
|
-
return findNearestEnv(resolveProfileEnvFileNames(), projectEnvStartDir());
|
|
160
|
-
}
|
|
161
|
-
function loadProjectAppEnv() {
|
|
162
|
-
return findNearestEnv(resolveProjectAppEnvFileNames(), projectEnvStartDir());
|
|
163
|
-
}
|
|
164
|
-
function normalizeWorktreeBaseUrl(baseUrl, worktreeEnv = findNearestWorktreeEnv()) {
|
|
165
|
-
const trimmed = baseUrl.trim().replace(/\/$/, "");
|
|
166
|
-
if (!trimmed) return trimmed;
|
|
125
|
+
function normalizeBaseUrl(baseUrl) {
|
|
126
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
127
|
+
if (!trimmed) return "";
|
|
167
128
|
try {
|
|
168
129
|
const parsed = new URL(trimmed);
|
|
169
|
-
if (parsed.
|
|
170
|
-
|
|
171
|
-
if (port) return `${parsed.protocol}//localhost:${port}`;
|
|
130
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
131
|
+
return "";
|
|
172
132
|
}
|
|
133
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
173
134
|
} catch {
|
|
135
|
+
return "";
|
|
174
136
|
}
|
|
175
|
-
return trimmed;
|
|
176
137
|
}
|
|
177
|
-
function
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return
|
|
138
|
+
function firstNonEmpty(...values) {
|
|
139
|
+
for (const value of values) {
|
|
140
|
+
const trimmed = value?.trim();
|
|
141
|
+
if (trimmed) return trimmed;
|
|
142
|
+
}
|
|
143
|
+
return "";
|
|
183
144
|
}
|
|
184
|
-
function
|
|
145
|
+
function sdkCliConfigDir(baseUrl) {
|
|
185
146
|
const home = process.env.HOME?.trim() || (0, import_node_os.homedir)();
|
|
186
|
-
return (0, import_node_path.join)(home, ".local", "deepline", baseUrlSlug(baseUrl || PROD_URL)
|
|
147
|
+
return (0, import_node_path.join)(home, ".local", "deepline", baseUrlSlug(baseUrl || PROD_URL));
|
|
148
|
+
}
|
|
149
|
+
function sdkCliEnvFilePath(baseUrl) {
|
|
150
|
+
return (0, import_node_path.join)(sdkCliConfigDir(baseUrl), ".env");
|
|
187
151
|
}
|
|
188
152
|
function loadCliEnv(baseUrl = PROD_URL) {
|
|
189
|
-
|
|
190
|
-
|
|
153
|
+
return parseEnvFile(sdkCliEnvFilePath(baseUrl));
|
|
154
|
+
}
|
|
155
|
+
function hostConfigDirPath(baseUrl) {
|
|
156
|
+
return sdkCliConfigDir(baseUrl);
|
|
191
157
|
}
|
|
192
158
|
function hostEnvFilePath(baseUrl) {
|
|
193
159
|
return sdkCliEnvFilePath(baseUrl);
|
|
@@ -198,9 +164,10 @@ function saveHostEnvValues(baseUrl, values) {
|
|
|
198
164
|
if (!(0, import_node_fs.existsSync)(dir)) {
|
|
199
165
|
(0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
200
166
|
}
|
|
201
|
-
const existing =
|
|
167
|
+
const existing = parseEnvFile(filePath);
|
|
202
168
|
const merged = { ...existing, ...values };
|
|
203
|
-
const
|
|
169
|
+
const allowedKeys = /* @__PURE__ */ new Set([HOST_URL_ENV, API_KEY_ENV]);
|
|
170
|
+
const lines = Object.entries(merged).filter(([key, value]) => allowedKeys.has(key) && value !== "").map(([key, value]) => `${key}=${value}`);
|
|
204
171
|
(0, import_node_fs.writeFileSync)(filePath, `${lines.join("\n")}
|
|
205
172
|
`, "utf-8");
|
|
206
173
|
}
|
|
@@ -208,31 +175,36 @@ function loadGlobalCliEnv() {
|
|
|
208
175
|
return loadCliEnv(PROD_URL);
|
|
209
176
|
}
|
|
210
177
|
function autoDetectBaseUrl() {
|
|
211
|
-
const
|
|
212
|
-
if (envOrigin) return normalizeWorktreeBaseUrl(envOrigin);
|
|
213
|
-
const envBase = process.env.DEEPLINE_API_BASE_URL?.trim();
|
|
214
|
-
if (envBase) return normalizeWorktreeBaseUrl(envBase);
|
|
215
|
-
const projectDeeplineBaseUrl = resolveBaseUrlFromEnvValues(loadProjectDeeplineEnv());
|
|
216
|
-
if (projectDeeplineBaseUrl) return normalizeWorktreeBaseUrl(projectDeeplineBaseUrl);
|
|
217
|
-
const projectAppBaseUrl = resolveBaseUrlFromEnvValues(loadProjectAppEnv());
|
|
218
|
-
if (projectAppBaseUrl) return normalizeWorktreeBaseUrl(projectAppBaseUrl);
|
|
219
|
-
const worktreeBaseUrl = resolveWorktreeBaseUrl();
|
|
220
|
-
if (worktreeBaseUrl) return worktreeBaseUrl;
|
|
178
|
+
const projectEnv = loadProjectDeeplineEnv();
|
|
221
179
|
const globalEnv = loadGlobalCliEnv();
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
180
|
+
return normalizeBaseUrl(process.env[HOST_URL_ENV] ?? "") || normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "") || normalizeBaseUrl(globalEnv[HOST_URL_ENV] ?? "") || PROD_URL;
|
|
181
|
+
}
|
|
182
|
+
function resolveApiKeyForBaseUrl(baseUrl, explicitApiKey) {
|
|
183
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
184
|
+
const projectEnv = loadProjectDeeplineEnv();
|
|
185
|
+
const cliEnv = loadCliEnv(normalizedBaseUrl || baseUrl);
|
|
186
|
+
const projectBaseUrl = normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "");
|
|
187
|
+
const projectKeyApplies = projectBaseUrl === normalizedBaseUrl;
|
|
188
|
+
return firstNonEmpty(
|
|
189
|
+
explicitApiKey,
|
|
190
|
+
process.env[API_KEY_ENV],
|
|
191
|
+
projectKeyApplies ? projectEnv[API_KEY_ENV] : "",
|
|
192
|
+
cliEnv[API_KEY_ENV]
|
|
193
|
+
);
|
|
225
194
|
}
|
|
226
195
|
function resolveConfig(options) {
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
196
|
+
const baseUrl = normalizeBaseUrl(
|
|
197
|
+
options?.baseUrl?.trim() || autoDetectBaseUrl()
|
|
198
|
+
);
|
|
199
|
+
if (!baseUrl) {
|
|
200
|
+
throw new ConfigError(
|
|
201
|
+
`Invalid ${HOST_URL_ENV}. Expected an http(s) URL such as https://code.deepline.com.`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
const apiKey = resolveApiKeyForBaseUrl(baseUrl, options?.apiKey);
|
|
233
205
|
if (!apiKey) {
|
|
234
206
|
throw new ConfigError(
|
|
235
|
-
`No API key found. Set
|
|
207
|
+
`No API key found. Set ${API_KEY_ENV}, add it to .env.deepline, or run: deepline auth register`
|
|
236
208
|
);
|
|
237
209
|
}
|
|
238
210
|
return {
|
|
@@ -242,32 +214,10 @@ function resolveConfig(options) {
|
|
|
242
214
|
maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES
|
|
243
215
|
};
|
|
244
216
|
}
|
|
245
|
-
function mergeEnvFile(filePath, values) {
|
|
246
|
-
const existing = (0, import_node_fs.existsSync)(filePath) ? parseEnvFile(filePath) : {};
|
|
247
|
-
const merged = { ...existing, ...values };
|
|
248
|
-
const dir = (0, import_node_path.dirname)(filePath);
|
|
249
|
-
if (!(0, import_node_fs.existsSync)(dir)) (0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
250
|
-
const lines = Object.entries(merged).filter(([, value]) => value !== "").map(([key, value]) => `${key}=${value}`);
|
|
251
|
-
(0, import_node_fs.writeFileSync)(filePath, `${lines.join("\n")}
|
|
252
|
-
`, "utf-8");
|
|
253
|
-
}
|
|
254
|
-
function saveProjectDeeplineEnvValues(baseUrl, values, startDir = projectEnvStartDir()) {
|
|
255
|
-
const root = (0, import_node_path.resolve)(startDir);
|
|
256
|
-
const profile = profileNameForBaseUrl(baseUrl);
|
|
257
|
-
const files = [
|
|
258
|
-
(0, import_node_path.join)(root, ACTIVE_DEEPLINE_ENV_FILE),
|
|
259
|
-
(0, import_node_path.join)(root, `.env.deepline.${profile}`)
|
|
260
|
-
];
|
|
261
|
-
if (profile === "dev") files.push((0, import_node_path.join)(root, ".env"));
|
|
262
|
-
for (const filePath of files) {
|
|
263
|
-
mergeEnvFile(filePath, values);
|
|
264
|
-
}
|
|
265
|
-
return files;
|
|
266
|
-
}
|
|
267
217
|
|
|
268
218
|
// src/version.ts
|
|
269
|
-
var SDK_VERSION = "0.1.
|
|
270
|
-
var SDK_API_CONTRACT = "2026-05-
|
|
219
|
+
var SDK_VERSION = "0.1.35";
|
|
220
|
+
var SDK_API_CONTRACT = "2026-05-v2-tool-result-contract";
|
|
271
221
|
|
|
272
222
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
273
223
|
var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
|
|
@@ -349,7 +299,7 @@ var HttpClient = class {
|
|
|
349
299
|
const response = await fetch(candidateUrl, {
|
|
350
300
|
method,
|
|
351
301
|
headers,
|
|
352
|
-
body: options?.formData !== void 0 ? options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
302
|
+
body: options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
353
303
|
signal: controller.signal
|
|
354
304
|
});
|
|
355
305
|
clearTimeout(timeoutId);
|
|
@@ -432,10 +382,13 @@ var HttpClient = class {
|
|
|
432
382
|
throw new AuthError();
|
|
433
383
|
}
|
|
434
384
|
if (!response.ok) {
|
|
385
|
+
const body = await response.text();
|
|
386
|
+
const parsed = parseResponseBody(body);
|
|
435
387
|
throw new DeeplineError(
|
|
436
|
-
|
|
388
|
+
apiErrorMessage(parsed, response.status),
|
|
437
389
|
response.status,
|
|
438
|
-
"API_ERROR"
|
|
390
|
+
"API_ERROR",
|
|
391
|
+
{ response: parsed }
|
|
439
392
|
);
|
|
440
393
|
}
|
|
441
394
|
if (!response.body) {
|
|
@@ -485,6 +438,26 @@ var HttpClient = class {
|
|
|
485
438
|
return this.request(path, { method: "DELETE" });
|
|
486
439
|
}
|
|
487
440
|
};
|
|
441
|
+
function parseResponseBody(body) {
|
|
442
|
+
try {
|
|
443
|
+
return JSON.parse(body);
|
|
444
|
+
} catch {
|
|
445
|
+
return body;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
function apiErrorMessage(parsed, status) {
|
|
449
|
+
const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
|
|
450
|
+
if (typeof errorValue === "string") {
|
|
451
|
+
return errorValue;
|
|
452
|
+
}
|
|
453
|
+
if (errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string") {
|
|
454
|
+
return errorValue.message;
|
|
455
|
+
}
|
|
456
|
+
if (typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string") {
|
|
457
|
+
return parsed.message;
|
|
458
|
+
}
|
|
459
|
+
return `HTTP ${status}`;
|
|
460
|
+
}
|
|
488
461
|
function parseRetryAfter(response) {
|
|
489
462
|
const header = response.headers.get("retry-after");
|
|
490
463
|
if (header) {
|
|
@@ -548,15 +521,17 @@ function decodeSseFrame(frame) {
|
|
|
548
521
|
return parsed;
|
|
549
522
|
}
|
|
550
523
|
function sleep(ms) {
|
|
551
|
-
return new Promise((
|
|
524
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
552
525
|
}
|
|
553
526
|
|
|
554
527
|
// src/client.ts
|
|
555
528
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
556
529
|
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
530
|
+
var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
|
|
531
|
+
var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-execution-result";
|
|
557
532
|
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
558
533
|
function sleep2(ms) {
|
|
559
|
-
return new Promise((
|
|
534
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
560
535
|
}
|
|
561
536
|
function isTransientCompileManifestError(error) {
|
|
562
537
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
@@ -822,13 +797,16 @@ var DeeplineClient = class {
|
|
|
822
797
|
/**
|
|
823
798
|
* Execute a tool and return the standard execution envelope.
|
|
824
799
|
*
|
|
825
|
-
* The `
|
|
826
|
-
* contains provider
|
|
800
|
+
* The `toolExecutionResult.toolOutput.raw` field contains the raw tool output.
|
|
801
|
+
* `toolExecutionResult.toolOutput.meta` contains tool/provider metadata.
|
|
827
802
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
828
|
-
* Deepline execution.
|
|
803
|
+
* Deepline execution envelope.
|
|
829
804
|
*/
|
|
830
805
|
async executeTool(toolId, input, options) {
|
|
831
|
-
const headers =
|
|
806
|
+
const headers = {
|
|
807
|
+
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
808
|
+
...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
|
|
809
|
+
};
|
|
832
810
|
return this.http.post(
|
|
833
811
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
834
812
|
{ payload: input },
|
|
@@ -1126,34 +1104,37 @@ var DeeplineClient = class {
|
|
|
1126
1104
|
* ```
|
|
1127
1105
|
*/
|
|
1128
1106
|
async stagePlayFiles(files) {
|
|
1129
|
-
const
|
|
1130
|
-
|
|
1131
|
-
"metadata",
|
|
1132
|
-
JSON.stringify({
|
|
1133
|
-
files: files.map((file, index) => ({
|
|
1134
|
-
index,
|
|
1135
|
-
logicalPath: file.logicalPath,
|
|
1136
|
-
contentHash: file.contentHash,
|
|
1137
|
-
contentType: file.contentType,
|
|
1138
|
-
bytes: file.bytes
|
|
1139
|
-
}))
|
|
1140
|
-
})
|
|
1141
|
-
);
|
|
1142
|
-
for (const [index, file] of files.entries()) {
|
|
1143
|
-
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1144
|
-
const body = bytes.buffer.slice(
|
|
1145
|
-
bytes.byteOffset,
|
|
1146
|
-
bytes.byteOffset + bytes.byteLength
|
|
1147
|
-
);
|
|
1107
|
+
const buildFormData = () => {
|
|
1108
|
+
const formData = new FormData();
|
|
1148
1109
|
formData.set(
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1110
|
+
"metadata",
|
|
1111
|
+
JSON.stringify({
|
|
1112
|
+
files: files.map((file, index) => ({
|
|
1113
|
+
index,
|
|
1114
|
+
logicalPath: file.logicalPath,
|
|
1115
|
+
contentHash: file.contentHash,
|
|
1116
|
+
contentType: file.contentType,
|
|
1117
|
+
bytes: file.bytes
|
|
1118
|
+
}))
|
|
1119
|
+
})
|
|
1152
1120
|
);
|
|
1153
|
-
|
|
1121
|
+
for (const [index, file] of files.entries()) {
|
|
1122
|
+
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1123
|
+
const body = bytes.buffer.slice(
|
|
1124
|
+
bytes.byteOffset,
|
|
1125
|
+
bytes.byteOffset + bytes.byteLength
|
|
1126
|
+
);
|
|
1127
|
+
formData.set(
|
|
1128
|
+
`file:${index}`,
|
|
1129
|
+
new Blob([body], { type: file.contentType }),
|
|
1130
|
+
file.logicalPath
|
|
1131
|
+
);
|
|
1132
|
+
}
|
|
1133
|
+
return formData;
|
|
1134
|
+
};
|
|
1154
1135
|
const response = await this.http.postFormData(
|
|
1155
1136
|
"/api/v2/plays/files/stage",
|
|
1156
|
-
|
|
1137
|
+
buildFormData
|
|
1157
1138
|
);
|
|
1158
1139
|
return response.files;
|
|
1159
1140
|
}
|
|
@@ -1686,10 +1667,11 @@ var import_node_fs2 = require("fs");
|
|
|
1686
1667
|
var import_promises = require("fs/promises");
|
|
1687
1668
|
var import_node_os2 = require("os");
|
|
1688
1669
|
var import_node_path2 = require("path");
|
|
1689
|
-
var
|
|
1670
|
+
var childProcess = __toESM(require("child_process"));
|
|
1690
1671
|
var import_sync = require("csv-parse/sync");
|
|
1691
1672
|
var import_sync2 = require("csv-stringify/sync");
|
|
1692
1673
|
var BROWSER_FOCUS_COOLDOWN_MS = 3e4;
|
|
1674
|
+
var defaultBrowserCommandRunner = childProcess;
|
|
1693
1675
|
function getAuthedHttpClient() {
|
|
1694
1676
|
const config = resolveConfig();
|
|
1695
1677
|
return { config, http: new HttpClient(config) };
|
|
@@ -1758,9 +1740,9 @@ function browserAppNameFromBundleId(bundleId) {
|
|
|
1758
1740
|
};
|
|
1759
1741
|
return names[bundleId.toLowerCase()] ?? "";
|
|
1760
1742
|
}
|
|
1761
|
-
function readDefaultMacBrowserBundleId() {
|
|
1743
|
+
function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
1762
1744
|
try {
|
|
1763
|
-
const output =
|
|
1745
|
+
const output = runner.execFileSync(
|
|
1764
1746
|
"/usr/bin/defaults",
|
|
1765
1747
|
[
|
|
1766
1748
|
"read",
|
|
@@ -1796,8 +1778,8 @@ function browserStrategyForBundleId(bundleId) {
|
|
|
1796
1778
|
}
|
|
1797
1779
|
return normalized === "com.apple.safari" ? "safari" : "fallback";
|
|
1798
1780
|
}
|
|
1799
|
-
function runAppleScript(script, args) {
|
|
1800
|
-
const result =
|
|
1781
|
+
function runAppleScript(script, args, runner = defaultBrowserCommandRunner) {
|
|
1782
|
+
const result = runner.spawnSync("osascript", ["-", ...args], {
|
|
1801
1783
|
input: script,
|
|
1802
1784
|
encoding: "utf-8",
|
|
1803
1785
|
stdio: ["pipe", "ignore", "ignore"],
|
|
@@ -1805,7 +1787,7 @@ function runAppleScript(script, args) {
|
|
|
1805
1787
|
});
|
|
1806
1788
|
return result.status === 0;
|
|
1807
1789
|
}
|
|
1808
|
-
function retargetChromiumMacos(appName, targetUrl, allowFocus) {
|
|
1790
|
+
function retargetChromiumMacos(appName, targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
1809
1791
|
const host = extractUrlHost(targetUrl);
|
|
1810
1792
|
if (!host) return false;
|
|
1811
1793
|
const escapedAppName = appName.replace(/"/g, '\\"');
|
|
@@ -1837,9 +1819,9 @@ ${newTabBlock} end if
|
|
|
1837
1819
|
end tell
|
|
1838
1820
|
end run
|
|
1839
1821
|
`;
|
|
1840
|
-
return runAppleScript(script, [targetUrl, host]);
|
|
1822
|
+
return runAppleScript(script, [targetUrl, host], runner);
|
|
1841
1823
|
}
|
|
1842
|
-
function retargetSafariMacos(appName, targetUrl, allowFocus) {
|
|
1824
|
+
function retargetSafariMacos(appName, targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
1843
1825
|
const host = extractUrlHost(targetUrl);
|
|
1844
1826
|
if (!host) return false;
|
|
1845
1827
|
const escapedAppName = appName.replace(/"/g, '\\"');
|
|
@@ -1871,30 +1853,38 @@ ${newTabBlock} end if
|
|
|
1871
1853
|
end tell
|
|
1872
1854
|
end run
|
|
1873
1855
|
`;
|
|
1874
|
-
return runAppleScript(script, [targetUrl, host]);
|
|
1856
|
+
return runAppleScript(script, [targetUrl, host], runner);
|
|
1875
1857
|
}
|
|
1876
|
-
function openUrlMacos(targetUrl, allowFocus) {
|
|
1877
|
-
const defaultBundleId = readDefaultMacBrowserBundleId();
|
|
1858
|
+
function openUrlMacos(targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
1859
|
+
const defaultBundleId = readDefaultMacBrowserBundleId(runner);
|
|
1878
1860
|
const appName = defaultBundleId ? browserAppNameFromBundleId(defaultBundleId) : "";
|
|
1879
1861
|
const strategy = browserStrategyForBundleId(defaultBundleId);
|
|
1880
|
-
if (appName && strategy === "chromium" && retargetChromiumMacos(appName, targetUrl, allowFocus)) {
|
|
1862
|
+
if (appName && strategy === "chromium" && retargetChromiumMacos(appName, targetUrl, allowFocus, runner)) {
|
|
1881
1863
|
return true;
|
|
1882
1864
|
}
|
|
1883
|
-
if (appName && strategy === "safari" && retargetSafariMacos(appName, targetUrl, allowFocus)) {
|
|
1865
|
+
if (appName && strategy === "safari" && retargetSafariMacos(appName, targetUrl, allowFocus, runner)) {
|
|
1884
1866
|
return true;
|
|
1885
1867
|
}
|
|
1886
|
-
if (!allowFocus) {
|
|
1887
|
-
return false;
|
|
1888
|
-
}
|
|
1889
1868
|
try {
|
|
1890
|
-
|
|
1869
|
+
runner.execFileSync(
|
|
1870
|
+
"open",
|
|
1871
|
+
[...allowFocus ? [] : ["-g"], targetUrl],
|
|
1872
|
+
{ stdio: "ignore" }
|
|
1873
|
+
);
|
|
1891
1874
|
return true;
|
|
1892
1875
|
} catch {
|
|
1893
1876
|
return false;
|
|
1894
1877
|
}
|
|
1895
1878
|
}
|
|
1879
|
+
function browserOpeningDisabled() {
|
|
1880
|
+
const value = String(
|
|
1881
|
+
process.env.DEEPLINE_NO_BROWSER ?? process.env.PLAYGROUND_HEADLESS ?? ""
|
|
1882
|
+
).trim().toLowerCase();
|
|
1883
|
+
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
1884
|
+
}
|
|
1896
1885
|
function openInBrowser(url) {
|
|
1897
1886
|
try {
|
|
1887
|
+
if (browserOpeningDisabled()) return;
|
|
1898
1888
|
const targetUrl = String(url || "").trim();
|
|
1899
1889
|
if (!targetUrl) return;
|
|
1900
1890
|
const allowFocus = claimBrowserFocus();
|
|
@@ -1904,12 +1894,12 @@ function openInBrowser(url) {
|
|
|
1904
1894
|
}
|
|
1905
1895
|
if (!allowFocus) return;
|
|
1906
1896
|
if (process.platform === "win32") {
|
|
1907
|
-
|
|
1897
|
+
childProcess.execFileSync("cmd.exe", ["/c", "start", "", targetUrl], {
|
|
1908
1898
|
stdio: "ignore"
|
|
1909
1899
|
});
|
|
1910
1900
|
return;
|
|
1911
1901
|
}
|
|
1912
|
-
|
|
1902
|
+
childProcess.execFileSync("xdg-open", [targetUrl], { stdio: "ignore" });
|
|
1913
1903
|
} catch {
|
|
1914
1904
|
}
|
|
1915
1905
|
}
|
|
@@ -1933,6 +1923,103 @@ function csvStringFromRows(rows, columns) {
|
|
|
1933
1923
|
...columns?.length ? { columns } : {}
|
|
1934
1924
|
});
|
|
1935
1925
|
}
|
|
1926
|
+
function parseMaybeJsonObject(value) {
|
|
1927
|
+
if (typeof value !== "string") {
|
|
1928
|
+
return value;
|
|
1929
|
+
}
|
|
1930
|
+
const trimmed = value.trim();
|
|
1931
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
|
1932
|
+
return value;
|
|
1933
|
+
}
|
|
1934
|
+
try {
|
|
1935
|
+
return JSON.parse(trimmed);
|
|
1936
|
+
} catch {
|
|
1937
|
+
return value;
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
function flattenObjectColumns(row) {
|
|
1941
|
+
const flattened = {};
|
|
1942
|
+
for (const [key, rawValue] of Object.entries(row)) {
|
|
1943
|
+
const value = parseMaybeJsonObject(rawValue);
|
|
1944
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1945
|
+
for (const [nestedKey, nestedValue] of Object.entries(
|
|
1946
|
+
value
|
|
1947
|
+
)) {
|
|
1948
|
+
flattened[`${key}.${nestedKey}`] = nestedValue && typeof nestedValue === "object" ? JSON.stringify(nestedValue) : nestedValue;
|
|
1949
|
+
}
|
|
1950
|
+
continue;
|
|
1951
|
+
}
|
|
1952
|
+
flattened[key] = Array.isArray(value) ? JSON.stringify(value) : value;
|
|
1953
|
+
}
|
|
1954
|
+
return flattened;
|
|
1955
|
+
}
|
|
1956
|
+
function recordRows(value) {
|
|
1957
|
+
return value.filter(
|
|
1958
|
+
(row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)
|
|
1959
|
+
);
|
|
1960
|
+
}
|
|
1961
|
+
function dataExportRows(rows) {
|
|
1962
|
+
return rows.map((row) => flattenObjectColumns(row));
|
|
1963
|
+
}
|
|
1964
|
+
function dataExportColumns(rows, preferredColumns = []) {
|
|
1965
|
+
const discoveredColumns = [
|
|
1966
|
+
...new Set(rows.flatMap((row) => Object.keys(row)))
|
|
1967
|
+
];
|
|
1968
|
+
if (rows.length === 0) {
|
|
1969
|
+
return [...new Set(preferredColumns.filter(Boolean))];
|
|
1970
|
+
}
|
|
1971
|
+
const discovered = new Set(discoveredColumns);
|
|
1972
|
+
const columns = [];
|
|
1973
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1974
|
+
for (const column of preferredColumns) {
|
|
1975
|
+
if (!column) {
|
|
1976
|
+
continue;
|
|
1977
|
+
}
|
|
1978
|
+
const expandedColumns = discovered.has(column) ? [column] : discoveredColumns.filter(
|
|
1979
|
+
(discoveredColumn) => discoveredColumn.startsWith(`${column}.`)
|
|
1980
|
+
);
|
|
1981
|
+
for (const expandedColumn of expandedColumns) {
|
|
1982
|
+
if (seen.has(expandedColumn)) {
|
|
1983
|
+
continue;
|
|
1984
|
+
}
|
|
1985
|
+
seen.add(expandedColumn);
|
|
1986
|
+
columns.push(expandedColumn);
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
for (const column of discoveredColumns) {
|
|
1990
|
+
if (seen.has(column)) {
|
|
1991
|
+
continue;
|
|
1992
|
+
}
|
|
1993
|
+
seen.add(column);
|
|
1994
|
+
columns.push(column);
|
|
1995
|
+
}
|
|
1996
|
+
return columns;
|
|
1997
|
+
}
|
|
1998
|
+
function dataExportCsvString(rows, preferredColumns = []) {
|
|
1999
|
+
const flattenedRows = dataExportRows(rows);
|
|
2000
|
+
return csvStringFromRows(
|
|
2001
|
+
flattenedRows,
|
|
2002
|
+
dataExportColumns(flattenedRows, preferredColumns)
|
|
2003
|
+
);
|
|
2004
|
+
}
|
|
2005
|
+
function markdownCell(value) {
|
|
2006
|
+
if (value === null || value === void 0) {
|
|
2007
|
+
return "";
|
|
2008
|
+
}
|
|
2009
|
+
const text = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
2010
|
+
return text.replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
|
|
2011
|
+
}
|
|
2012
|
+
function markdownTableFromRows(rows, preferredColumns = []) {
|
|
2013
|
+
const flattenedRows = dataExportRows(rows);
|
|
2014
|
+
const columns = dataExportColumns(flattenedRows, preferredColumns);
|
|
2015
|
+
const header = `| ${columns.map(markdownCell).join(" | ")} |`;
|
|
2016
|
+
const separator = `| ${columns.map(() => "---").join(" | ")} |`;
|
|
2017
|
+
const body = flattenedRows.map(
|
|
2018
|
+
(row) => `| ${columns.map((column) => markdownCell(row[column])).join(" | ")} |`
|
|
2019
|
+
);
|
|
2020
|
+
return `${[header, separator, ...body].join("\n")}
|
|
2021
|
+
`;
|
|
2022
|
+
}
|
|
1936
2023
|
function printJson(value) {
|
|
1937
2024
|
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
1938
2025
|
`);
|
|
@@ -2023,17 +2110,39 @@ var EXIT_SERVER = 2;
|
|
|
2023
2110
|
function envFilePath(baseUrl) {
|
|
2024
2111
|
return hostEnvFilePath(baseUrl);
|
|
2025
2112
|
}
|
|
2026
|
-
function
|
|
2027
|
-
|
|
2113
|
+
function pendingClaimTokenPath(baseUrl) {
|
|
2114
|
+
return `${hostConfigDirPath(baseUrl)}/pending-claim-token`;
|
|
2115
|
+
}
|
|
2116
|
+
function savePendingClaimToken(baseUrl, claimToken) {
|
|
2117
|
+
const filePath = pendingClaimTokenPath(baseUrl);
|
|
2028
2118
|
const dir = (0, import_node_path3.dirname)(filePath);
|
|
2029
2119
|
if (!(0, import_node_fs3.existsSync)(dir)) {
|
|
2030
2120
|
(0, import_node_fs3.mkdirSync)(dir, { recursive: true });
|
|
2031
2121
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2122
|
+
(0, import_node_fs3.writeFileSync)(filePath, `${claimToken}
|
|
2123
|
+
`, "utf-8");
|
|
2124
|
+
}
|
|
2125
|
+
function readPendingClaimToken(baseUrl) {
|
|
2126
|
+
const filePath = pendingClaimTokenPath(baseUrl);
|
|
2127
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return "";
|
|
2128
|
+
try {
|
|
2129
|
+
return (0, import_node_fs3.readFileSync)(filePath, "utf-8").trim();
|
|
2130
|
+
} catch {
|
|
2131
|
+
return "";
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
function clearPendingClaimToken(baseUrl) {
|
|
2135
|
+
try {
|
|
2136
|
+
(0, import_node_fs3.rmSync)(pendingClaimTokenPath(baseUrl), { force: true });
|
|
2137
|
+
} catch {
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
function saveEnvValues(values, baseUrl) {
|
|
2141
|
+
const filtered = {
|
|
2142
|
+
...values[HOST_URL_ENV] ? { [HOST_URL_ENV]: values[HOST_URL_ENV] } : {},
|
|
2143
|
+
...values[API_KEY_ENV] ? { [API_KEY_ENV]: values[API_KEY_ENV] } : {}
|
|
2144
|
+
};
|
|
2145
|
+
saveHostEnvValues(baseUrl, filtered);
|
|
2037
2146
|
}
|
|
2038
2147
|
async function httpJson(method, url, apiKey, body) {
|
|
2039
2148
|
const headers = { "Content-Type": "application/json" };
|
|
@@ -2087,7 +2196,7 @@ function buildCandidateUrls2(url) {
|
|
|
2087
2196
|
}
|
|
2088
2197
|
}
|
|
2089
2198
|
function sleep3(ms) {
|
|
2090
|
-
return new Promise((
|
|
2199
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
2091
2200
|
}
|
|
2092
2201
|
function printDeeplineLogo() {
|
|
2093
2202
|
if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
|
|
@@ -2139,9 +2248,9 @@ async function handleRegister(args) {
|
|
|
2139
2248
|
const claimUrl = String(data.claim_url || "");
|
|
2140
2249
|
const claimToken = String(data.claim_token || "");
|
|
2141
2250
|
if (claimToken) {
|
|
2251
|
+
savePendingClaimToken(baseUrl, claimToken);
|
|
2142
2252
|
saveEnvValues({
|
|
2143
|
-
|
|
2144
|
-
DEEPLINE_CLAIM_TOKEN: claimToken
|
|
2253
|
+
[HOST_URL_ENV]: baseUrl
|
|
2145
2254
|
}, baseUrl);
|
|
2146
2255
|
}
|
|
2147
2256
|
if (claimUrl) {
|
|
@@ -2165,6 +2274,7 @@ async function handleRegister(args) {
|
|
|
2165
2274
|
{ claim_token: claimToken, reveal: true }
|
|
2166
2275
|
);
|
|
2167
2276
|
if (s === 401 || s === 403) {
|
|
2277
|
+
clearPendingClaimToken(baseUrl);
|
|
2168
2278
|
console.log("Status: unauthorized");
|
|
2169
2279
|
return EXIT_AUTH;
|
|
2170
2280
|
}
|
|
@@ -2181,15 +2291,16 @@ async function handleRegister(args) {
|
|
|
2181
2291
|
const apiKey = String(statusData.api_key || "");
|
|
2182
2292
|
if (apiKey) {
|
|
2183
2293
|
saveEnvValues({
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
DEEPLINE_CLAIM_TOKEN: ""
|
|
2294
|
+
[HOST_URL_ENV]: baseUrl,
|
|
2295
|
+
[API_KEY_ENV]: apiKey
|
|
2187
2296
|
}, baseUrl);
|
|
2297
|
+
clearPendingClaimToken(baseUrl);
|
|
2188
2298
|
printClaimSuccessBanner(statusData);
|
|
2189
2299
|
return EXIT_OK;
|
|
2190
2300
|
}
|
|
2191
2301
|
}
|
|
2192
2302
|
if (state === "expired") {
|
|
2303
|
+
clearPendingClaimToken(baseUrl);
|
|
2193
2304
|
console.log("That approval link expired. Please run: deepline auth register");
|
|
2194
2305
|
return EXIT_AUTH;
|
|
2195
2306
|
}
|
|
@@ -2207,13 +2318,12 @@ async function handleWait(args) {
|
|
|
2207
2318
|
}
|
|
2208
2319
|
}
|
|
2209
2320
|
}
|
|
2210
|
-
const
|
|
2211
|
-
if (env.DEEPLINE_API_KEY?.trim()) {
|
|
2212
|
-
console.log("Already connected.");
|
|
2213
|
-
return EXIT_OK;
|
|
2214
|
-
}
|
|
2215
|
-
const claimToken = env.DEEPLINE_CLAIM_TOKEN?.trim() || "";
|
|
2321
|
+
const claimToken = readPendingClaimToken(baseUrl);
|
|
2216
2322
|
if (!claimToken) {
|
|
2323
|
+
if (resolveApiKeyForBaseUrl(baseUrl)) {
|
|
2324
|
+
console.log("Already connected.");
|
|
2325
|
+
return EXIT_OK;
|
|
2326
|
+
}
|
|
2217
2327
|
console.error("No pending approval. Run: deepline auth register --no-wait");
|
|
2218
2328
|
return EXIT_AUTH;
|
|
2219
2329
|
}
|
|
@@ -2226,6 +2336,7 @@ async function handleWait(args) {
|
|
|
2226
2336
|
{ claim_token: claimToken, reveal: true }
|
|
2227
2337
|
);
|
|
2228
2338
|
if (status === 401 || status === 403) {
|
|
2339
|
+
clearPendingClaimToken(baseUrl);
|
|
2229
2340
|
console.error("Claim is invalid. Run: deepline auth register");
|
|
2230
2341
|
return EXIT_AUTH;
|
|
2231
2342
|
}
|
|
@@ -2242,15 +2353,16 @@ async function handleWait(args) {
|
|
|
2242
2353
|
const apiKey = String(data.api_key || "");
|
|
2243
2354
|
if (apiKey) {
|
|
2244
2355
|
saveEnvValues({
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
DEEPLINE_CLAIM_TOKEN: ""
|
|
2356
|
+
[HOST_URL_ENV]: baseUrl,
|
|
2357
|
+
[API_KEY_ENV]: apiKey
|
|
2248
2358
|
}, baseUrl);
|
|
2359
|
+
clearPendingClaimToken(baseUrl);
|
|
2249
2360
|
printClaimSuccessBanner(data);
|
|
2250
2361
|
return EXIT_OK;
|
|
2251
2362
|
}
|
|
2252
2363
|
}
|
|
2253
2364
|
if (state === "expired") {
|
|
2365
|
+
clearPendingClaimToken(baseUrl);
|
|
2254
2366
|
console.error("That approval link expired. Run: deepline auth register");
|
|
2255
2367
|
return EXIT_AUTH;
|
|
2256
2368
|
}
|
|
@@ -2285,10 +2397,9 @@ async function handleStatus(args) {
|
|
|
2285
2397
|
};
|
|
2286
2398
|
hostLines.push(`Host: ${baseUrl} (unreachable)`);
|
|
2287
2399
|
}
|
|
2288
|
-
const
|
|
2289
|
-
const apiKey = process.env.DEEPLINE_API_KEY?.trim() || env.DEEPLINE_API_KEY || "";
|
|
2400
|
+
const apiKey = resolveApiKeyForBaseUrl(baseUrl);
|
|
2290
2401
|
if (!apiKey) {
|
|
2291
|
-
if (
|
|
2402
|
+
if (readPendingClaimToken(baseUrl)) {
|
|
2292
2403
|
printCommandEnvelope({
|
|
2293
2404
|
...hostStatusPayload ?? { host: baseUrl },
|
|
2294
2405
|
status: "pending",
|
|
@@ -2334,6 +2445,7 @@ async function handleStatus(args) {
|
|
|
2334
2445
|
console.error(`Auth status error (status ${status}).`);
|
|
2335
2446
|
return EXIT_SERVER;
|
|
2336
2447
|
}
|
|
2448
|
+
clearPendingClaimToken(baseUrl);
|
|
2337
2449
|
const payload = {
|
|
2338
2450
|
...hostStatusPayload ?? { host: baseUrl },
|
|
2339
2451
|
status: data.status || "(unknown)",
|
|
@@ -2354,9 +2466,8 @@ async function handleStatus(args) {
|
|
|
2354
2466
|
const apiKeyResp = String(data.api_key || apiKey);
|
|
2355
2467
|
if (apiKeyResp) {
|
|
2356
2468
|
saveEnvValues({
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
DEEPLINE_CLAIM_TOKEN: ""
|
|
2469
|
+
[HOST_URL_ENV]: baseUrl,
|
|
2470
|
+
[API_KEY_ENV]: apiKeyResp
|
|
2360
2471
|
}, baseUrl);
|
|
2361
2472
|
savedApiKeyPath = envFilePath(baseUrl);
|
|
2362
2473
|
}
|
|
@@ -3285,10 +3396,12 @@ function writeCanonicalRowsCsv(rowsInfo, outPath) {
|
|
|
3285
3396
|
rows: rowsInfo.rows,
|
|
3286
3397
|
columns: rowsInfo.columns
|
|
3287
3398
|
});
|
|
3399
|
+
const rows = dataExportRows(sanitized.rows);
|
|
3400
|
+
const columns = dataExportColumns(rows, sanitized.columns);
|
|
3288
3401
|
const resolved = (0, import_node_path5.resolve)(outPath);
|
|
3289
3402
|
(0, import_node_fs4.writeFileSync)(
|
|
3290
3403
|
resolved,
|
|
3291
|
-
csvStringFromRows(
|
|
3404
|
+
csvStringFromRows(rows, columns),
|
|
3292
3405
|
"utf-8"
|
|
3293
3406
|
);
|
|
3294
3407
|
return resolved;
|
|
@@ -3409,6 +3522,14 @@ Examples:
|
|
|
3409
3522
|
}
|
|
3410
3523
|
|
|
3411
3524
|
// src/cli/commands/db.ts
|
|
3525
|
+
var import_node_fs5 = require("fs");
|
|
3526
|
+
var import_node_path6 = require("path");
|
|
3527
|
+
var CUSTOMER_DB_QUERY_FORMATS = /* @__PURE__ */ new Set([
|
|
3528
|
+
"table",
|
|
3529
|
+
"json",
|
|
3530
|
+
"csv",
|
|
3531
|
+
"markdown"
|
|
3532
|
+
]);
|
|
3412
3533
|
function parsePositiveInteger(value, flagName) {
|
|
3413
3534
|
const parsed = Number.parseInt(value, 10);
|
|
3414
3535
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
@@ -3422,10 +3543,8 @@ function formatCell(value) {
|
|
|
3422
3543
|
return text.length > 80 ? `${text.slice(0, 77)}...` : text;
|
|
3423
3544
|
}
|
|
3424
3545
|
function tableLines(result) {
|
|
3425
|
-
const rows = result
|
|
3426
|
-
|
|
3427
|
-
);
|
|
3428
|
-
const responseColumns = result.columns.length > 0 ? result.columns.map((column) => column.name) : [...new Set(rows.flatMap((row) => Object.keys(row)))];
|
|
3546
|
+
const rows = dataExportRows(customerDbRows(result));
|
|
3547
|
+
const responseColumns = dataExportColumns(rows, customerDbColumnNames(result));
|
|
3429
3548
|
const businessColumns = responseColumns.filter((column) => !column.startsWith("_"));
|
|
3430
3549
|
const columns = businessColumns.length > 0 ? businessColumns : responseColumns;
|
|
3431
3550
|
const hiddenColumns = responseColumns.filter((column) => !columns.includes(column));
|
|
@@ -3459,22 +3578,146 @@ function tableLines(result) {
|
|
|
3459
3578
|
}
|
|
3460
3579
|
return lines;
|
|
3461
3580
|
}
|
|
3581
|
+
function customerDbRows(result) {
|
|
3582
|
+
return recordRows(result.rows);
|
|
3583
|
+
}
|
|
3584
|
+
function customerDbColumnNames(result) {
|
|
3585
|
+
return result.columns.map((column) => column.name).filter(Boolean);
|
|
3586
|
+
}
|
|
3587
|
+
function writeCustomerDbCsv(result, outPath) {
|
|
3588
|
+
const resolved = (0, import_node_path6.resolve)(outPath);
|
|
3589
|
+
(0, import_node_fs5.writeFileSync)(
|
|
3590
|
+
resolved,
|
|
3591
|
+
dataExportCsvString(customerDbRows(result), customerDbColumnNames(result)),
|
|
3592
|
+
"utf-8"
|
|
3593
|
+
);
|
|
3594
|
+
return resolved;
|
|
3595
|
+
}
|
|
3596
|
+
function dbQueryExportEnvelope(input) {
|
|
3597
|
+
const destination = input.outPath ?? "stdout";
|
|
3598
|
+
return {
|
|
3599
|
+
command: input.result.command,
|
|
3600
|
+
format: input.format,
|
|
3601
|
+
row_count: input.result.row_count,
|
|
3602
|
+
row_count_returned: input.result.row_count_returned,
|
|
3603
|
+
truncated: input.result.truncated,
|
|
3604
|
+
...input.outPath ? { file: input.outPath, local: { file: input.outPath } } : {},
|
|
3605
|
+
next: { toolEquivalent: input.toolCommand },
|
|
3606
|
+
render: {
|
|
3607
|
+
sections: [
|
|
3608
|
+
{
|
|
3609
|
+
title: "customer db export",
|
|
3610
|
+
lines: [
|
|
3611
|
+
`Rendered ${input.result.row_count_returned} row(s) as ${input.format} to ${destination}`
|
|
3612
|
+
]
|
|
3613
|
+
}
|
|
3614
|
+
],
|
|
3615
|
+
actions: [{ label: "Tool equivalent", command: input.toolCommand }]
|
|
3616
|
+
}
|
|
3617
|
+
};
|
|
3618
|
+
}
|
|
3462
3619
|
async function handleDbQuery(args) {
|
|
3463
3620
|
const sqlIndex = args.indexOf("--sql");
|
|
3464
3621
|
const sql = sqlIndex >= 0 ? args[sqlIndex + 1]?.trim() : "";
|
|
3465
3622
|
if (!sql) {
|
|
3466
|
-
console.error(
|
|
3623
|
+
console.error(
|
|
3624
|
+
'Usage: deepline db query --sql "select * from table limit 20" [--max-rows N] [--json]'
|
|
3625
|
+
);
|
|
3467
3626
|
return 1;
|
|
3468
3627
|
}
|
|
3469
3628
|
const maxRowsIndex = args.indexOf("--max-rows");
|
|
3470
3629
|
const maxRows = maxRowsIndex >= 0 && args[maxRowsIndex + 1] ? parsePositiveInteger(args[maxRowsIndex + 1], "--max-rows") : void 0;
|
|
3630
|
+
const formatIndex = args.indexOf("--format");
|
|
3631
|
+
const format = formatIndex >= 0 ? args[formatIndex + 1]?.trim().toLowerCase() : "";
|
|
3632
|
+
if (format && !CUSTOMER_DB_QUERY_FORMATS.has(format)) {
|
|
3633
|
+
console.error(
|
|
3634
|
+
'Usage: deepline db query --sql "select * from table limit 20" [--format table|json|csv|markdown] [--out path]'
|
|
3635
|
+
);
|
|
3636
|
+
return 1;
|
|
3637
|
+
}
|
|
3638
|
+
const outIndex = args.indexOf("--out");
|
|
3639
|
+
const outPath = outIndex >= 0 ? args[outIndex + 1]?.trim() : "";
|
|
3640
|
+
if (outIndex >= 0 && !outPath) {
|
|
3641
|
+
console.error("--out requires a path.");
|
|
3642
|
+
return 1;
|
|
3643
|
+
}
|
|
3471
3644
|
const jsonOutput = argsWantJson(args);
|
|
3645
|
+
const explicitJsonOutput = args.includes("--json");
|
|
3472
3646
|
const client = new DeeplineClient();
|
|
3473
3647
|
const result = await client.queryCustomerDb({ sql, maxRows });
|
|
3474
3648
|
const toolCommand = `deepline tools execute query_customer_db --payload ${JSON.stringify({
|
|
3475
3649
|
sql,
|
|
3476
3650
|
...maxRows ? { max_rows: maxRows } : {}
|
|
3477
3651
|
})} --json`;
|
|
3652
|
+
if (format === "csv") {
|
|
3653
|
+
if (outPath) {
|
|
3654
|
+
const exportedPath = writeCustomerDbCsv(result, outPath);
|
|
3655
|
+
printCommandEnvelope(
|
|
3656
|
+
dbQueryExportEnvelope({
|
|
3657
|
+
result,
|
|
3658
|
+
format,
|
|
3659
|
+
outPath: exportedPath,
|
|
3660
|
+
toolCommand
|
|
3661
|
+
}),
|
|
3662
|
+
{
|
|
3663
|
+
json: jsonOutput,
|
|
3664
|
+
text: `Exported ${result.row_count_returned} row(s) to ${exportedPath}
|
|
3665
|
+
`
|
|
3666
|
+
}
|
|
3667
|
+
);
|
|
3668
|
+
return 0;
|
|
3669
|
+
}
|
|
3670
|
+
printCommandEnvelope(
|
|
3671
|
+
dbQueryExportEnvelope({
|
|
3672
|
+
result,
|
|
3673
|
+
format,
|
|
3674
|
+
outPath: null,
|
|
3675
|
+
toolCommand
|
|
3676
|
+
}),
|
|
3677
|
+
{
|
|
3678
|
+
json: explicitJsonOutput,
|
|
3679
|
+
text: dataExportCsvString(customerDbRows(result), customerDbColumnNames(result))
|
|
3680
|
+
}
|
|
3681
|
+
);
|
|
3682
|
+
return 0;
|
|
3683
|
+
}
|
|
3684
|
+
if (format === "markdown") {
|
|
3685
|
+
const content = markdownTableFromRows(
|
|
3686
|
+
customerDbRows(result),
|
|
3687
|
+
customerDbColumnNames(result)
|
|
3688
|
+
);
|
|
3689
|
+
if (outPath) {
|
|
3690
|
+
const exportedPath = (0, import_node_path6.resolve)(outPath);
|
|
3691
|
+
(0, import_node_fs5.writeFileSync)(exportedPath, content, "utf-8");
|
|
3692
|
+
printCommandEnvelope(
|
|
3693
|
+
dbQueryExportEnvelope({
|
|
3694
|
+
result,
|
|
3695
|
+
format,
|
|
3696
|
+
outPath: exportedPath,
|
|
3697
|
+
toolCommand
|
|
3698
|
+
}),
|
|
3699
|
+
{
|
|
3700
|
+
json: jsonOutput,
|
|
3701
|
+
text: `Exported ${result.row_count_returned} row(s) to ${exportedPath}
|
|
3702
|
+
`
|
|
3703
|
+
}
|
|
3704
|
+
);
|
|
3705
|
+
return 0;
|
|
3706
|
+
}
|
|
3707
|
+
printCommandEnvelope(
|
|
3708
|
+
dbQueryExportEnvelope({
|
|
3709
|
+
result,
|
|
3710
|
+
format,
|
|
3711
|
+
outPath: null,
|
|
3712
|
+
toolCommand
|
|
3713
|
+
}),
|
|
3714
|
+
{
|
|
3715
|
+
json: explicitJsonOutput,
|
|
3716
|
+
text: content
|
|
3717
|
+
}
|
|
3718
|
+
);
|
|
3719
|
+
return 0;
|
|
3720
|
+
}
|
|
3478
3721
|
printCommandEnvelope({
|
|
3479
3722
|
...result,
|
|
3480
3723
|
next: { toolEquivalent: toolCommand },
|
|
@@ -3482,7 +3725,7 @@ async function handleDbQuery(args) {
|
|
|
3482
3725
|
sections: [{ title: "customer db query", lines: tableLines(result) }],
|
|
3483
3726
|
actions: [{ label: "Tool equivalent", command: toolCommand }]
|
|
3484
3727
|
}
|
|
3485
|
-
}, { json: jsonOutput });
|
|
3728
|
+
}, { json: jsonOutput || format === "json" });
|
|
3486
3729
|
return 0;
|
|
3487
3730
|
}
|
|
3488
3731
|
function registerDbCommands(program) {
|
|
@@ -3492,11 +3735,14 @@ function registerDbCommands(program) {
|
|
|
3492
3735
|
Notes:
|
|
3493
3736
|
Runs SQL against the active workspace customer database through Deepline APIs.
|
|
3494
3737
|
Results are bounded by the server and --max-rows. Use --json for stable output.
|
|
3738
|
+
Use --format csv or --format markdown for agent-readable exports and display tables.
|
|
3495
3739
|
|
|
3496
3740
|
Examples:
|
|
3497
3741
|
deepline db query --sql "select * from companies limit 20"
|
|
3498
3742
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
3499
3743
|
deepline db query --sql "select * from contacts" --max-rows 100 --json
|
|
3744
|
+
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
3745
|
+
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
3500
3746
|
`
|
|
3501
3747
|
);
|
|
3502
3748
|
db.command("query").alias("psql").description("Run SQL against the tenant customer database.").addHelpText(
|
|
@@ -3505,17 +3751,23 @@ Examples:
|
|
|
3505
3751
|
Notes:
|
|
3506
3752
|
Requires --sql. Output is a compact table in a terminal and raw JSON with
|
|
3507
3753
|
--json or when stdout is piped. The active auth workspace determines scope.
|
|
3754
|
+
--format csv and --format markdown are explicit data/display formats and can
|
|
3755
|
+
be written directly with --out.
|
|
3508
3756
|
|
|
3509
3757
|
Examples:
|
|
3510
3758
|
deepline db query --sql "select * from companies limit 20"
|
|
3511
3759
|
deepline db query --sql "select domain, name from companies limit 20" --json
|
|
3512
3760
|
deepline db psql --sql "select count(*) from contacts" --json
|
|
3761
|
+
deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
|
|
3762
|
+
deepline db query --sql "select domain, name from companies limit 20" --format markdown
|
|
3513
3763
|
`
|
|
3514
|
-
).requiredOption("--sql <sql>", "SQL statement").option("--max-rows <n>", "Maximum returned rows").option("--json", "Emit raw JSON response. Also automatic when stdout is piped").action(async (options) => {
|
|
3764
|
+
).requiredOption("--sql <sql>", "SQL statement").option("--max-rows <n>", "Maximum returned rows").option("--format <format>", "Output format: table, json, csv, or markdown").option("--out <path>", "Write csv or markdown output to a file").option("--json", "Emit raw JSON response. Also automatic when stdout is piped").action(async (options) => {
|
|
3515
3765
|
process.exitCode = await handleDbQuery([
|
|
3516
3766
|
"--sql",
|
|
3517
3767
|
options.sql,
|
|
3518
3768
|
...options.maxRows ? ["--max-rows", options.maxRows] : [],
|
|
3769
|
+
...options.format ? ["--format", options.format] : [],
|
|
3770
|
+
...options.out ? ["--out", options.out] : [],
|
|
3519
3771
|
...options.json ? ["--json"] : []
|
|
3520
3772
|
]);
|
|
3521
3773
|
});
|
|
@@ -3691,21 +3943,21 @@ Examples:
|
|
|
3691
3943
|
|
|
3692
3944
|
// src/cli/commands/play.ts
|
|
3693
3945
|
var import_node_crypto3 = require("crypto");
|
|
3694
|
-
var
|
|
3695
|
-
var
|
|
3946
|
+
var import_node_fs8 = require("fs");
|
|
3947
|
+
var import_node_path10 = require("path");
|
|
3696
3948
|
|
|
3697
3949
|
// src/plays/bundle-play-file.ts
|
|
3698
3950
|
var import_node_os5 = require("os");
|
|
3699
|
-
var
|
|
3951
|
+
var import_node_path9 = require("path");
|
|
3700
3952
|
var import_node_url = require("url");
|
|
3701
|
-
var
|
|
3953
|
+
var import_node_fs7 = require("fs");
|
|
3702
3954
|
|
|
3703
3955
|
// ../shared_libs/plays/bundling/index.ts
|
|
3704
3956
|
var import_node_crypto = require("crypto");
|
|
3705
|
-
var
|
|
3957
|
+
var import_node_fs6 = require("fs");
|
|
3706
3958
|
var import_promises3 = require("fs/promises");
|
|
3707
3959
|
var import_node_os4 = require("os");
|
|
3708
|
-
var
|
|
3960
|
+
var import_node_path7 = require("path");
|
|
3709
3961
|
var import_node_module = require("module");
|
|
3710
3962
|
var import_esbuild = require("esbuild");
|
|
3711
3963
|
|
|
@@ -3764,7 +4016,7 @@ function buildPlayContractCompatibility(input) {
|
|
|
3764
4016
|
var PLAY_BUNDLE_CACHE_VERSION = 24;
|
|
3765
4017
|
var MAX_PLAY_BUNDLE_BYTES = 30 * 1024 * 1024;
|
|
3766
4018
|
var MAX_ESM_WORKERS_BUNDLE_BYTES = 115e4;
|
|
3767
|
-
var PLAY_ARTIFACT_CACHE_DIR = (0,
|
|
4019
|
+
var PLAY_ARTIFACT_CACHE_DIR = (0, import_node_path7.join)(
|
|
3768
4020
|
(0, import_node_os4.tmpdir)(),
|
|
3769
4021
|
`deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION}`
|
|
3770
4022
|
);
|
|
@@ -3797,13 +4049,13 @@ async function normalizeLocalPath(filePath) {
|
|
|
3797
4049
|
try {
|
|
3798
4050
|
return await (0, import_promises3.realpath)(filePath);
|
|
3799
4051
|
} catch {
|
|
3800
|
-
return (0,
|
|
4052
|
+
return (0, import_node_path7.resolve)(filePath);
|
|
3801
4053
|
}
|
|
3802
4054
|
}
|
|
3803
4055
|
function createPlayWorkspace(entryFile) {
|
|
3804
4056
|
return {
|
|
3805
4057
|
entryFile,
|
|
3806
|
-
rootDir: (0,
|
|
4058
|
+
rootDir: (0, import_node_path7.dirname)(entryFile)
|
|
3807
4059
|
};
|
|
3808
4060
|
}
|
|
3809
4061
|
function isPathInsideDirectory(filePath, directory) {
|
|
@@ -3956,7 +4208,7 @@ function extractDefinedPlayName(sourceCode) {
|
|
|
3956
4208
|
}
|
|
3957
4209
|
function readPackageVersionFromPackageJson(packageJsonPath, packageName) {
|
|
3958
4210
|
try {
|
|
3959
|
-
const packageJson = JSON.parse((0,
|
|
4211
|
+
const packageJson = JSON.parse((0, import_node_fs6.readFileSync)(packageJsonPath, "utf-8"));
|
|
3960
4212
|
if (packageJson.name === packageName && typeof packageJson.version === "string") {
|
|
3961
4213
|
return packageJson.version;
|
|
3962
4214
|
}
|
|
@@ -3966,18 +4218,18 @@ function readPackageVersionFromPackageJson(packageJsonPath, packageName) {
|
|
|
3966
4218
|
return null;
|
|
3967
4219
|
}
|
|
3968
4220
|
function findPackageJsonPathFrom(startDir, packageName) {
|
|
3969
|
-
let current = (0,
|
|
4221
|
+
let current = (0, import_node_path7.resolve)(startDir);
|
|
3970
4222
|
while (true) {
|
|
3971
|
-
const packageJsonPath = (0,
|
|
4223
|
+
const packageJsonPath = (0, import_node_path7.join)(
|
|
3972
4224
|
current,
|
|
3973
4225
|
"node_modules",
|
|
3974
4226
|
packageName,
|
|
3975
4227
|
"package.json"
|
|
3976
4228
|
);
|
|
3977
|
-
if ((0,
|
|
4229
|
+
if ((0, import_node_fs6.existsSync)(packageJsonPath)) {
|
|
3978
4230
|
return packageJsonPath;
|
|
3979
4231
|
}
|
|
3980
|
-
const parent = (0,
|
|
4232
|
+
const parent = (0, import_node_path7.dirname)(current);
|
|
3981
4233
|
if (parent === current) {
|
|
3982
4234
|
return null;
|
|
3983
4235
|
}
|
|
@@ -3986,29 +4238,29 @@ function findPackageJsonPathFrom(startDir, packageName) {
|
|
|
3986
4238
|
}
|
|
3987
4239
|
function findPackageJsonPath(packageName, fromFile, adapter) {
|
|
3988
4240
|
const startDirs = [
|
|
3989
|
-
(0,
|
|
4241
|
+
(0, import_node_path7.dirname)(fromFile),
|
|
3990
4242
|
adapter.projectRoot,
|
|
3991
|
-
(0,
|
|
4243
|
+
(0, import_node_path7.dirname)(adapter.sdkPackageJson),
|
|
3992
4244
|
process.cwd()
|
|
3993
4245
|
];
|
|
3994
4246
|
const seen = /* @__PURE__ */ new Set();
|
|
3995
4247
|
for (const startDir of startDirs) {
|
|
3996
|
-
const normalized = (0,
|
|
4248
|
+
const normalized = (0, import_node_path7.resolve)(startDir);
|
|
3997
4249
|
if (seen.has(normalized)) continue;
|
|
3998
4250
|
seen.add(normalized);
|
|
3999
4251
|
const packageJsonPath = findPackageJsonPathFrom(normalized, packageName);
|
|
4000
4252
|
if (packageJsonPath) return packageJsonPath;
|
|
4001
4253
|
}
|
|
4002
|
-
const adapterNodeModulesPackageJson = (0,
|
|
4254
|
+
const adapterNodeModulesPackageJson = (0, import_node_path7.join)(
|
|
4003
4255
|
adapter.nodeModulesDir,
|
|
4004
4256
|
packageName,
|
|
4005
4257
|
"package.json"
|
|
4006
4258
|
);
|
|
4007
|
-
return (0,
|
|
4259
|
+
return (0, import_node_fs6.existsSync)(adapterNodeModulesPackageJson) ? adapterNodeModulesPackageJson : null;
|
|
4008
4260
|
}
|
|
4009
4261
|
function localSdkAliasPlugin(adapter, options) {
|
|
4010
4262
|
const entryFile = options?.workersRuntime ? adapter.sdkWorkersEntryFile : adapter.sdkEntryFile;
|
|
4011
|
-
if (!(0,
|
|
4263
|
+
if (!(0, import_node_fs6.existsSync)(entryFile)) {
|
|
4012
4264
|
return null;
|
|
4013
4265
|
}
|
|
4014
4266
|
return {
|
|
@@ -4048,7 +4300,7 @@ function workersNamedPlayEntryAliasPlugin(playFilePath, exportName) {
|
|
|
4048
4300
|
contents: `export { ${exportName} as default } from ${JSON.stringify(playFilePath)};
|
|
4049
4301
|
`,
|
|
4050
4302
|
loader: "ts",
|
|
4051
|
-
resolveDir: (0,
|
|
4303
|
+
resolveDir: (0, import_node_path7.dirname)(playFilePath)
|
|
4052
4304
|
})
|
|
4053
4305
|
);
|
|
4054
4306
|
}
|
|
@@ -4212,7 +4464,7 @@ function importedPlayProxyPlugin(importedPlayDependencies) {
|
|
|
4212
4464
|
return {
|
|
4213
4465
|
contents: buildImportedPlayProxyModule(dependency.playName),
|
|
4214
4466
|
loader: "ts",
|
|
4215
|
-
resolveDir: (0,
|
|
4467
|
+
resolveDir: (0, import_node_path7.dirname)(args.path)
|
|
4216
4468
|
};
|
|
4217
4469
|
});
|
|
4218
4470
|
}
|
|
@@ -4230,12 +4482,12 @@ async function resolveLocalImport(fromFile, specifier) {
|
|
|
4230
4482
|
if (specifier.startsWith("file:")) {
|
|
4231
4483
|
return normalizeLocalPath(new URL(specifier).pathname);
|
|
4232
4484
|
}
|
|
4233
|
-
const base = (0,
|
|
4485
|
+
const base = (0, import_node_path7.isAbsolute)(specifier) ? (0, import_node_path7.resolve)(specifier) : (0, import_node_path7.resolve)((0, import_node_path7.dirname)(fromFile), specifier);
|
|
4234
4486
|
const candidates = [base];
|
|
4235
|
-
const explicitExtension = (0,
|
|
4487
|
+
const explicitExtension = (0, import_node_path7.extname)(base).toLowerCase();
|
|
4236
4488
|
if (!explicitExtension) {
|
|
4237
4489
|
candidates.push(...SOURCE_EXTENSIONS.map((extension) => `${base}${extension}`));
|
|
4238
|
-
candidates.push(...SOURCE_EXTENSIONS.map((extension) => (0,
|
|
4490
|
+
candidates.push(...SOURCE_EXTENSIONS.map((extension) => (0, import_node_path7.join)(base, `index${extension}`)));
|
|
4239
4491
|
} else if ([".js", ".jsx", ".mjs", ".cjs"].includes(explicitExtension)) {
|
|
4240
4492
|
const stem = base.slice(0, -explicitExtension.length);
|
|
4241
4493
|
candidates.push(...SOURCE_EXTENSIONS.map((extension) => `${stem}${extension}`));
|
|
@@ -4249,9 +4501,9 @@ async function resolveLocalImport(fromFile, specifier) {
|
|
|
4249
4501
|
}
|
|
4250
4502
|
function resolvePackageImport(specifier, fromFile, adapter) {
|
|
4251
4503
|
const packageName = getPackageName(specifier);
|
|
4252
|
-
if (packageName === "deepline" && (0,
|
|
4504
|
+
if (packageName === "deepline" && (0, import_node_fs6.existsSync)(adapter.sdkPackageJson)) {
|
|
4253
4505
|
const packageJson = JSON.parse(
|
|
4254
|
-
(0,
|
|
4506
|
+
(0, import_node_fs6.readFileSync)(adapter.sdkPackageJson, "utf-8")
|
|
4255
4507
|
);
|
|
4256
4508
|
return {
|
|
4257
4509
|
name: "deepline",
|
|
@@ -4283,7 +4535,7 @@ async function analyzeSourceGraph(entryFile, adapter) {
|
|
|
4283
4535
|
visited.add(absolutePath);
|
|
4284
4536
|
const sourceCode2 = await (0, import_promises3.readFile)(absolutePath, "utf-8");
|
|
4285
4537
|
localFiles.set(absolutePath, sourceCode2);
|
|
4286
|
-
if ((0,
|
|
4538
|
+
if ((0, import_node_path7.extname)(absolutePath).toLowerCase() === ".json") {
|
|
4287
4539
|
return;
|
|
4288
4540
|
}
|
|
4289
4541
|
const handleSpecifier = async (specifier, line, column, kind) => {
|
|
@@ -4387,13 +4639,13 @@ async function computeWorkersHarnessFingerprintWithAdapter(adapter) {
|
|
|
4387
4639
|
const tsFiles = entries.filter((e) => e.isFile() && /\.[cm]?ts$/.test(e.name)).map((e) => e.name).sort();
|
|
4388
4640
|
const parts = [];
|
|
4389
4641
|
for (const name of tsFiles) {
|
|
4390
|
-
const contents = await (0, import_promises3.readFile)((0,
|
|
4642
|
+
const contents = await (0, import_promises3.readFile)((0, import_node_path7.join)(adapter.workersHarnessFilesDir, name), "utf-8");
|
|
4391
4643
|
parts.push({ name, hash: sha256(contents) });
|
|
4392
4644
|
}
|
|
4393
4645
|
return sha256(JSON.stringify(parts));
|
|
4394
4646
|
}
|
|
4395
4647
|
function artifactCachePath(graphHash, artifactKind, adapter) {
|
|
4396
|
-
return (0,
|
|
4648
|
+
return (0, import_node_path7.join)(
|
|
4397
4649
|
adapter.cacheDir ?? PLAY_ARTIFACT_CACHE_DIR,
|
|
4398
4650
|
`${graphHash}.${artifactKind}.json`
|
|
4399
4651
|
);
|
|
@@ -4428,7 +4680,7 @@ function normalizeSourceMapForRuntime(sourceMapText) {
|
|
|
4428
4680
|
if (sourcePath.startsWith("data:") || sourcePath.startsWith("node:") || sourcePath.startsWith("/") || /^[a-zA-Z]+:\/\//.test(sourcePath)) {
|
|
4429
4681
|
return sourcePath;
|
|
4430
4682
|
}
|
|
4431
|
-
return (0,
|
|
4683
|
+
return (0, import_node_path7.resolve)(process.cwd(), sourcePath);
|
|
4432
4684
|
});
|
|
4433
4685
|
parsed.sourceRoot = void 0;
|
|
4434
4686
|
return JSON.stringify(parsed);
|
|
@@ -4460,8 +4712,8 @@ async function runEsbuildForCjsNode(entryFile, importedPlayDependencies, adapter
|
|
|
4460
4712
|
...namedExportShim ? {
|
|
4461
4713
|
stdin: {
|
|
4462
4714
|
contents: namedExportShim,
|
|
4463
|
-
resolveDir: (0,
|
|
4464
|
-
sourcefile: `${(0,
|
|
4715
|
+
resolveDir: (0, import_node_path7.dirname)(entryFile),
|
|
4716
|
+
sourcefile: `${(0, import_node_path7.basename)(entryFile)}.${exportName}.entry.ts`,
|
|
4465
4717
|
loader: "ts"
|
|
4466
4718
|
}
|
|
4467
4719
|
} : { entryPoints: [entryFile] },
|
|
@@ -4637,10 +4889,10 @@ workers-harness:${harnessFingerprint}`
|
|
|
4637
4889
|
}
|
|
4638
4890
|
const { bundledCode, sourceMapText, outputExtension } = buildOutcome;
|
|
4639
4891
|
const normalizedSourceMap = normalizeSourceMapForRuntime(sourceMapText);
|
|
4640
|
-
const virtualBaseName = exportName === "default" ? (0,
|
|
4892
|
+
const virtualBaseName = exportName === "default" ? (0, import_node_path7.basename)(absolutePath).replace(/\.[^.]+$/, "") : `${(0, import_node_path7.basename)(absolutePath).replace(/\.[^.]+$/, "")}.${exportName}`;
|
|
4641
4893
|
const virtualFilename = `/virtual/deepline-plays/${analysis.graphHash}/${virtualBaseName}.${outputExtension}`;
|
|
4642
4894
|
const executableCode = `${bundledCode}
|
|
4643
|
-
//# sourceMappingURL=${(0,
|
|
4895
|
+
//# sourceMappingURL=${(0, import_node_path7.basename)(virtualFilename)}.map
|
|
4644
4896
|
`;
|
|
4645
4897
|
const bundleSizeError = getBundleSizeError(
|
|
4646
4898
|
absolutePath,
|
|
@@ -4750,13 +5002,13 @@ function resolveExecutionProfile(override) {
|
|
|
4750
5002
|
// src/plays/local-file-discovery.ts
|
|
4751
5003
|
var import_node_crypto2 = require("crypto");
|
|
4752
5004
|
var import_promises4 = require("fs/promises");
|
|
4753
|
-
var
|
|
5005
|
+
var import_node_path8 = require("path");
|
|
4754
5006
|
var SOURCE_EXTENSIONS2 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
|
|
4755
5007
|
function sha2562(buffer) {
|
|
4756
5008
|
return (0, import_node_crypto2.createHash)("sha256").update(buffer).digest("hex");
|
|
4757
5009
|
}
|
|
4758
5010
|
function contentTypeForFile(filePath) {
|
|
4759
|
-
const extension = (0,
|
|
5011
|
+
const extension = (0, import_node_path8.extname)(filePath).toLowerCase();
|
|
4760
5012
|
if (extension === ".csv") return "text/csv";
|
|
4761
5013
|
if (extension === ".json") return "application/json";
|
|
4762
5014
|
if (extension === ".txt") return "text/plain";
|
|
@@ -4947,16 +5199,16 @@ async function fileExists2(filePath) {
|
|
|
4947
5199
|
}
|
|
4948
5200
|
}
|
|
4949
5201
|
function isPathInsideDirectory2(filePath, directory) {
|
|
4950
|
-
const relativePath = (0,
|
|
4951
|
-
return relativePath === "" || !relativePath.startsWith("..") && !(0,
|
|
5202
|
+
const relativePath = (0, import_node_path8.relative)(directory, filePath);
|
|
5203
|
+
return relativePath === "" || !relativePath.startsWith("..") && !(0, import_node_path8.isAbsolute)(relativePath);
|
|
4952
5204
|
}
|
|
4953
5205
|
async function resolveLocalImport2(fromFile, specifier) {
|
|
4954
|
-
const base = (0,
|
|
5206
|
+
const base = (0, import_node_path8.isAbsolute)(specifier) ? (0, import_node_path8.resolve)(specifier) : (0, import_node_path8.resolve)((0, import_node_path8.dirname)(fromFile), specifier);
|
|
4955
5207
|
const candidates = [base];
|
|
4956
|
-
const explicitExtension = (0,
|
|
5208
|
+
const explicitExtension = (0, import_node_path8.extname)(base).toLowerCase();
|
|
4957
5209
|
if (!explicitExtension) {
|
|
4958
5210
|
candidates.push(...SOURCE_EXTENSIONS2.map((extension) => `${base}${extension}`));
|
|
4959
|
-
candidates.push(...SOURCE_EXTENSIONS2.map((extension) => (0,
|
|
5211
|
+
candidates.push(...SOURCE_EXTENSIONS2.map((extension) => (0, import_node_path8.join)(base, `index${extension}`)));
|
|
4960
5212
|
} else if ([".js", ".jsx", ".mjs", ".cjs"].includes(explicitExtension)) {
|
|
4961
5213
|
const stem = base.slice(0, -explicitExtension.length);
|
|
4962
5214
|
candidates.push(...SOURCE_EXTENSIONS2.map((extension) => `${stem}${extension}`));
|
|
@@ -4969,13 +5221,13 @@ async function resolveLocalImport2(fromFile, specifier) {
|
|
|
4969
5221
|
throw new Error(`Could not resolve local import "${specifier}" from ${fromFile}`);
|
|
4970
5222
|
}
|
|
4971
5223
|
async function discoverPackagedLocalFiles(entryFile) {
|
|
4972
|
-
const absoluteEntryFile = (0,
|
|
4973
|
-
const packagingRoot = (0,
|
|
5224
|
+
const absoluteEntryFile = (0, import_node_path8.resolve)(entryFile);
|
|
5225
|
+
const packagingRoot = (0, import_node_path8.dirname)(absoluteEntryFile);
|
|
4974
5226
|
const files = /* @__PURE__ */ new Map();
|
|
4975
5227
|
const unresolved = [];
|
|
4976
5228
|
const visitedFiles = /* @__PURE__ */ new Set();
|
|
4977
5229
|
const visitSourceFile = async (filePath) => {
|
|
4978
|
-
const absolutePath = (0,
|
|
5230
|
+
const absolutePath = (0, import_node_path8.resolve)(filePath);
|
|
4979
5231
|
if (visitedFiles.has(absolutePath)) {
|
|
4980
5232
|
return;
|
|
4981
5233
|
}
|
|
@@ -5007,8 +5259,8 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
5007
5259
|
message: "Could not resolve this ctx.csv(...) path at submit time. Use a string literal, a top-level const string, or pass a runtime input like input.file."
|
|
5008
5260
|
});
|
|
5009
5261
|
} else {
|
|
5010
|
-
const absoluteCsvPath = (0,
|
|
5011
|
-
if ((0,
|
|
5262
|
+
const absoluteCsvPath = (0, import_node_path8.resolve)((0, import_node_path8.dirname)(absolutePath), resolvedPath);
|
|
5263
|
+
if ((0, import_node_path8.isAbsolute)(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
|
|
5012
5264
|
unresolved.push({
|
|
5013
5265
|
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
5014
5266
|
message: "ctx.csv(...) packaged file paths must be relative paths inside the play directory. Pass external files at runtime with input.file instead."
|
|
@@ -5047,24 +5299,24 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
5047
5299
|
// src/plays/bundle-play-file.ts
|
|
5048
5300
|
var import_meta = {};
|
|
5049
5301
|
var PLAY_BUNDLE_CACHE_VERSION2 = 30;
|
|
5050
|
-
var MODULE_DIR = (0,
|
|
5051
|
-
var SDK_PACKAGE_ROOT = (0,
|
|
5052
|
-
var SOURCE_REPO_ROOT = (0,
|
|
5053
|
-
var HAS_SOURCE_BUNDLING_SOURCES = (0,
|
|
5054
|
-
(0,
|
|
5302
|
+
var MODULE_DIR = (0, import_node_path9.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
5303
|
+
var SDK_PACKAGE_ROOT = (0, import_node_path9.resolve)(MODULE_DIR, "..", "..");
|
|
5304
|
+
var SOURCE_REPO_ROOT = (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "..");
|
|
5305
|
+
var HAS_SOURCE_BUNDLING_SOURCES = (0, import_node_fs7.existsSync)(
|
|
5306
|
+
(0, import_node_path9.resolve)(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
5055
5307
|
);
|
|
5056
|
-
var PACKAGED_REPO_ROOT = (0,
|
|
5057
|
-
var HAS_PACKAGED_BUNDLING_SOURCES = (0,
|
|
5058
|
-
(0,
|
|
5308
|
+
var PACKAGED_REPO_ROOT = (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "dist", "repo");
|
|
5309
|
+
var HAS_PACKAGED_BUNDLING_SOURCES = (0, import_node_fs7.existsSync)(
|
|
5310
|
+
(0, import_node_path9.resolve)(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
5059
5311
|
);
|
|
5060
|
-
var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : (0,
|
|
5061
|
-
var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? (0,
|
|
5062
|
-
var SDK_PACKAGE_JSON = (0,
|
|
5063
|
-
var SDK_ENTRY_FILE = (0,
|
|
5064
|
-
var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE : (0,
|
|
5065
|
-
var SDK_WORKERS_ENTRY_FILE = (0,
|
|
5066
|
-
var WORKERS_HARNESS_ENTRY_FILE = (0,
|
|
5067
|
-
var WORKERS_HARNESS_FILES_DIR = (0,
|
|
5312
|
+
var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "..");
|
|
5313
|
+
var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? (0, import_node_path9.resolve)(SOURCE_REPO_ROOT, "sdk", "src") : HAS_PACKAGED_BUNDLING_SOURCES ? (0, import_node_path9.resolve)(PACKAGED_REPO_ROOT, "sdk", "src") : (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "src");
|
|
5314
|
+
var SDK_PACKAGE_JSON = (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "package.json");
|
|
5315
|
+
var SDK_ENTRY_FILE = (0, import_node_path9.resolve)(SDK_SOURCE_ROOT, "index.ts");
|
|
5316
|
+
var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE : (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "dist", "index.d.ts");
|
|
5317
|
+
var SDK_WORKERS_ENTRY_FILE = (0, import_node_path9.resolve)(SDK_SOURCE_ROOT, "worker-play-entry.ts");
|
|
5318
|
+
var WORKERS_HARNESS_ENTRY_FILE = (0, import_node_path9.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src", "entry.ts");
|
|
5319
|
+
var WORKERS_HARNESS_FILES_DIR = (0, import_node_path9.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src");
|
|
5068
5320
|
var hasWarnedAboutNonDevelopmentBundling = false;
|
|
5069
5321
|
function warnAboutNonDevelopmentBundling(filePath) {
|
|
5070
5322
|
if (hasWarnedAboutNonDevelopmentBundling) {
|
|
@@ -5088,12 +5340,12 @@ function defaultPlayBundleTarget() {
|
|
|
5088
5340
|
function createSdkPlayBundlingAdapter() {
|
|
5089
5341
|
return {
|
|
5090
5342
|
projectRoot: PROJECT_ROOT,
|
|
5091
|
-
nodeModulesDir: (0,
|
|
5092
|
-
cacheDir: (0,
|
|
5343
|
+
nodeModulesDir: (0, import_node_path9.resolve)(PROJECT_ROOT, "node_modules"),
|
|
5344
|
+
cacheDir: (0, import_node_path9.join)((0, import_node_os5.tmpdir)(), `deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION2}`),
|
|
5093
5345
|
sdkSourceRoot: SDK_SOURCE_ROOT,
|
|
5094
5346
|
sdkPackageJson: SDK_PACKAGE_JSON,
|
|
5095
5347
|
sdkEntryFile: SDK_ENTRY_FILE,
|
|
5096
|
-
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !(0,
|
|
5348
|
+
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !(0, import_node_fs7.existsSync)(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
|
|
5097
5349
|
sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
|
|
5098
5350
|
workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
|
|
5099
5351
|
workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
|
|
@@ -5326,7 +5578,7 @@ function traceCliSync(phase, fields, run) {
|
|
|
5326
5578
|
}
|
|
5327
5579
|
}
|
|
5328
5580
|
function sleep4(ms) {
|
|
5329
|
-
return new Promise((
|
|
5581
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
5330
5582
|
}
|
|
5331
5583
|
function parseReferencedPlayTarget(target) {
|
|
5332
5584
|
const trimmed = target.trim();
|
|
@@ -5372,7 +5624,7 @@ function formatPlayListReference(play) {
|
|
|
5372
5624
|
function defaultMaterializedPlayPath(reference) {
|
|
5373
5625
|
const playName = parseReferencedPlayTarget(reference).unqualifiedPlayName;
|
|
5374
5626
|
const safeName = playName.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
5375
|
-
return (0,
|
|
5627
|
+
return (0, import_node_path10.resolve)(`${safeName || "play"}.play.ts`);
|
|
5376
5628
|
}
|
|
5377
5629
|
function materializeRemotePlaySource(input) {
|
|
5378
5630
|
if (isFileTarget(input.target)) {
|
|
@@ -5382,15 +5634,15 @@ function materializeRemotePlaySource(input) {
|
|
|
5382
5634
|
return null;
|
|
5383
5635
|
}
|
|
5384
5636
|
const outputPath = input.outPath ?? defaultMaterializedPlayPath(input.playName);
|
|
5385
|
-
if ((0,
|
|
5386
|
-
const existingSource = (0,
|
|
5637
|
+
if ((0, import_node_fs8.existsSync)(outputPath)) {
|
|
5638
|
+
const existingSource = (0, import_node_fs8.readFileSync)(outputPath, "utf-8");
|
|
5387
5639
|
if (existingSource === input.sourceCode) {
|
|
5388
5640
|
return { path: outputPath, status: "unchanged", created: false };
|
|
5389
5641
|
}
|
|
5390
|
-
(0,
|
|
5642
|
+
(0, import_node_fs8.writeFileSync)(outputPath, input.sourceCode, "utf-8");
|
|
5391
5643
|
return { path: outputPath, status: "updated", created: false };
|
|
5392
5644
|
}
|
|
5393
|
-
(0,
|
|
5645
|
+
(0, import_node_fs8.writeFileSync)(outputPath, input.sourceCode, "utf-8");
|
|
5394
5646
|
return { path: outputPath, status: "created", created: true };
|
|
5395
5647
|
}
|
|
5396
5648
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -5435,7 +5687,7 @@ function extractPlayName(code, filePath) {
|
|
|
5435
5687
|
throw buildMissingDefinePlayError(filePath);
|
|
5436
5688
|
}
|
|
5437
5689
|
function isFileTarget(target) {
|
|
5438
|
-
return (0,
|
|
5690
|
+
return (0, import_node_fs8.existsSync)((0, import_node_path10.resolve)(target));
|
|
5439
5691
|
}
|
|
5440
5692
|
function looksLikeFilePath(target) {
|
|
5441
5693
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -5454,7 +5706,7 @@ function parsePositiveInteger2(value, flagName) {
|
|
|
5454
5706
|
return parsed;
|
|
5455
5707
|
}
|
|
5456
5708
|
function parseJsonInput(raw) {
|
|
5457
|
-
const source = raw.startsWith("@") ? (0,
|
|
5709
|
+
const source = raw.startsWith("@") ? (0, import_node_fs8.readFileSync)((0, import_node_path10.resolve)(raw.slice(1)), "utf-8") : raw;
|
|
5458
5710
|
const parsed = JSON.parse(source);
|
|
5459
5711
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
5460
5712
|
throw new Error("--input must be a JSON object.");
|
|
@@ -5555,7 +5807,7 @@ function fileInputBindingsFromStaticPipeline(staticPipeline) {
|
|
|
5555
5807
|
function isLocalFilePathValue(value) {
|
|
5556
5808
|
if (typeof value !== "string" || !value.trim()) return false;
|
|
5557
5809
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
5558
|
-
return (0,
|
|
5810
|
+
return (0, import_node_fs8.existsSync)((0, import_node_path10.resolve)(value));
|
|
5559
5811
|
}
|
|
5560
5812
|
function inputContainsLocalFilePath(value) {
|
|
5561
5813
|
if (isLocalFilePathValue(value)) {
|
|
@@ -5581,8 +5833,8 @@ async function stageFileInputArgs(input) {
|
|
|
5581
5833
|
const localFiles = uniqueBindings.flatMap((binding) => {
|
|
5582
5834
|
const value = getDottedInputValue(input.runtimeInput, binding.inputPath);
|
|
5583
5835
|
if (!isLocalFilePathValue(value)) return [];
|
|
5584
|
-
const absolutePath = (0,
|
|
5585
|
-
return [{ binding, absolutePath, logicalPath: (0,
|
|
5836
|
+
const absolutePath = (0, import_node_path10.resolve)(value);
|
|
5837
|
+
return [{ binding, absolutePath, logicalPath: (0, import_node_path10.basename)(absolutePath) }];
|
|
5586
5838
|
});
|
|
5587
5839
|
if (localFiles.length === 0) {
|
|
5588
5840
|
return { inputFile: null, packagedFiles: [] };
|
|
@@ -5606,7 +5858,7 @@ async function stageFileInputArgs(input) {
|
|
|
5606
5858
|
};
|
|
5607
5859
|
}
|
|
5608
5860
|
function stageFile(logicalPath, absolutePath) {
|
|
5609
|
-
const buffer = (0,
|
|
5861
|
+
const buffer = (0, import_node_fs8.readFileSync)(absolutePath);
|
|
5610
5862
|
return {
|
|
5611
5863
|
logicalPath,
|
|
5612
5864
|
contentBase64: buffer.toString("base64"),
|
|
@@ -5617,9 +5869,9 @@ function stageFile(logicalPath, absolutePath) {
|
|
|
5617
5869
|
}
|
|
5618
5870
|
function normalizePlayPath(filePath) {
|
|
5619
5871
|
try {
|
|
5620
|
-
return
|
|
5872
|
+
return import_node_fs8.realpathSync.native((0, import_node_path10.resolve)(filePath));
|
|
5621
5873
|
} catch {
|
|
5622
|
-
return (0,
|
|
5874
|
+
return (0, import_node_path10.resolve)(filePath);
|
|
5623
5875
|
}
|
|
5624
5876
|
}
|
|
5625
5877
|
function formatBundlingErrors(filePath, errors) {
|
|
@@ -5772,11 +6024,42 @@ function isTransientPlayStreamError(error) {
|
|
|
5772
6024
|
text
|
|
5773
6025
|
);
|
|
5774
6026
|
}
|
|
6027
|
+
function playStatusErrorText(status) {
|
|
6028
|
+
const chunks = [];
|
|
6029
|
+
const progressError = status.progress?.error;
|
|
6030
|
+
if (typeof progressError === "string" && progressError.trim()) {
|
|
6031
|
+
chunks.push(progressError.trim());
|
|
6032
|
+
}
|
|
6033
|
+
const errorValue = status.error;
|
|
6034
|
+
if (typeof errorValue === "string" && errorValue.trim()) {
|
|
6035
|
+
chunks.push(errorValue.trim());
|
|
6036
|
+
}
|
|
6037
|
+
const errors = status.errors;
|
|
6038
|
+
if (Array.isArray(errors)) {
|
|
6039
|
+
for (const error of errors) {
|
|
6040
|
+
if (typeof error === "string" && error.trim()) {
|
|
6041
|
+
chunks.push(error.trim());
|
|
6042
|
+
} else if (error && typeof error === "object") {
|
|
6043
|
+
const message = error.message;
|
|
6044
|
+
if (typeof message === "string" && message.trim()) {
|
|
6045
|
+
chunks.push(message.trim());
|
|
6046
|
+
}
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
6049
|
+
}
|
|
6050
|
+
return chunks.join("; ") || status.status;
|
|
6051
|
+
}
|
|
6052
|
+
function isRetryablePendingStartFailure(status) {
|
|
6053
|
+
if (status.status !== "failed") return false;
|
|
6054
|
+
if (status.runId && status.runId !== "pending") return false;
|
|
6055
|
+
return isTransientPlayStreamError(new Error(playStatusErrorText(status)));
|
|
6056
|
+
}
|
|
5775
6057
|
var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
5776
6058
|
"completed",
|
|
5777
6059
|
"failed",
|
|
5778
6060
|
"cancelled"
|
|
5779
6061
|
]);
|
|
6062
|
+
var PLAY_START_TRANSIENT_RETRY_DELAYS_MS = [500, 1500];
|
|
5780
6063
|
function getEventPayload(event) {
|
|
5781
6064
|
return event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
5782
6065
|
}
|
|
@@ -5843,10 +6126,6 @@ function openPlayDashboard(input) {
|
|
|
5843
6126
|
}
|
|
5844
6127
|
openInBrowser(input.dashboardUrl);
|
|
5845
6128
|
}
|
|
5846
|
-
function getDashboardUrlFromLiveEvent(event) {
|
|
5847
|
-
const dashboardUrl = getEventPayload(event).dashboardUrl;
|
|
5848
|
-
return typeof dashboardUrl === "string" && dashboardUrl.trim() ? dashboardUrl.trim() : null;
|
|
5849
|
-
}
|
|
5850
6129
|
function printPlayLogLines(input) {
|
|
5851
6130
|
for (const line of input.lines) {
|
|
5852
6131
|
if (input.emitLogs) {
|
|
@@ -5915,7 +6194,7 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
5915
6194
|
billing: false
|
|
5916
6195
|
});
|
|
5917
6196
|
if (TERMINAL_PLAY_STATUSES2.has(finalStatus.status)) {
|
|
5918
|
-
return finalStatus;
|
|
6197
|
+
return input.dashboardUrl ? { ...finalStatus, dashboardUrl: input.dashboardUrl } : finalStatus;
|
|
5919
6198
|
}
|
|
5920
6199
|
}
|
|
5921
6200
|
}
|
|
@@ -5942,7 +6221,39 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
5942
6221
|
);
|
|
5943
6222
|
}
|
|
5944
6223
|
async function startAndWaitForPlayCompletionByStream(input) {
|
|
6224
|
+
for (let attempt = 0; attempt <= PLAY_START_TRANSIENT_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
6225
|
+
const status = await startAndWaitForPlayCompletionByStreamOnce(input);
|
|
6226
|
+
const retryDelayMs = PLAY_START_TRANSIENT_RETRY_DELAYS_MS[attempt];
|
|
6227
|
+
if (retryDelayMs === void 0 || !isRetryablePendingStartFailure(status)) {
|
|
6228
|
+
return status;
|
|
6229
|
+
}
|
|
6230
|
+
if (!input.jsonOutput) {
|
|
6231
|
+
input.progress.writeLine(
|
|
6232
|
+
`[play watch] start failed before run id with a transient error; retrying (${playStatusErrorText(status)})`
|
|
6233
|
+
);
|
|
6234
|
+
}
|
|
6235
|
+
recordCliTrace({
|
|
6236
|
+
phase: "cli.play_start_stream_retry",
|
|
6237
|
+
ms: 0,
|
|
6238
|
+
ok: true,
|
|
6239
|
+
playName: input.playName,
|
|
6240
|
+
attempt: attempt + 1,
|
|
6241
|
+
reason: playStatusErrorText(status)
|
|
6242
|
+
});
|
|
6243
|
+
await sleep4(retryDelayMs);
|
|
6244
|
+
}
|
|
6245
|
+
throw new DeeplineError(
|
|
6246
|
+
`Play ${input.playName} did not start after retrying transient start failures.`,
|
|
6247
|
+
void 0,
|
|
6248
|
+
"PLAY_START_RETRY_EXHAUSTED"
|
|
6249
|
+
);
|
|
6250
|
+
}
|
|
6251
|
+
async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
5945
6252
|
const startedAt = Date.now();
|
|
6253
|
+
const dashboardUrl = buildPlayDashboardUrl(
|
|
6254
|
+
input.client.baseUrl,
|
|
6255
|
+
input.playName
|
|
6256
|
+
);
|
|
5946
6257
|
const state = {
|
|
5947
6258
|
lastLogIndex: 0,
|
|
5948
6259
|
emittedRunnerStarted: false
|
|
@@ -5973,7 +6284,6 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5973
6284
|
}
|
|
5974
6285
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
5975
6286
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
5976
|
-
const dashboardUrl = getDashboardUrlFromLiveEvent(event) ?? buildPlayDashboardUrl(input.client.baseUrl, input.playName);
|
|
5977
6287
|
openPlayDashboard({
|
|
5978
6288
|
dashboardUrl,
|
|
5979
6289
|
jsonOutput: input.jsonOutput,
|
|
@@ -6022,7 +6332,7 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
6022
6332
|
firstRunIdMs,
|
|
6023
6333
|
lastPhase
|
|
6024
6334
|
});
|
|
6025
|
-
return finalStatus;
|
|
6335
|
+
return { ...finalStatus, dashboardUrl };
|
|
6026
6336
|
}
|
|
6027
6337
|
}
|
|
6028
6338
|
} catch (error) {
|
|
@@ -6059,6 +6369,7 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
6059
6369
|
return waitForPlayCompletionByStream({
|
|
6060
6370
|
client: input.client,
|
|
6061
6371
|
workflowId: lastKnownWorkflowId,
|
|
6372
|
+
dashboardUrl,
|
|
6062
6373
|
jsonOutput: input.jsonOutput,
|
|
6063
6374
|
emitLogs: input.emitLogs,
|
|
6064
6375
|
waitTimeoutMs: input.waitTimeoutMs,
|
|
@@ -6093,6 +6404,7 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
6093
6404
|
return waitForPlayCompletionByStream({
|
|
6094
6405
|
client: input.client,
|
|
6095
6406
|
workflowId: lastKnownWorkflowId,
|
|
6407
|
+
dashboardUrl,
|
|
6096
6408
|
jsonOutput: input.jsonOutput,
|
|
6097
6409
|
emitLogs: input.emitLogs,
|
|
6098
6410
|
waitTimeoutMs: input.waitTimeoutMs,
|
|
@@ -6263,12 +6575,25 @@ function buildRunWarnings(status, rowsInfo) {
|
|
|
6263
6575
|
}
|
|
6264
6576
|
return [];
|
|
6265
6577
|
}
|
|
6266
|
-
function buildRunNextCommands(
|
|
6267
|
-
|
|
6578
|
+
function buildRunNextCommands(status) {
|
|
6579
|
+
const runId = status.runId?.trim();
|
|
6580
|
+
if (!runId) {
|
|
6581
|
+
const playName = extractRunPlayName(status);
|
|
6582
|
+
return playName ? {
|
|
6583
|
+
list: `deepline runs list --play ${playName} --json`
|
|
6584
|
+
} : {
|
|
6585
|
+
list: "deepline runs list --json"
|
|
6586
|
+
};
|
|
6587
|
+
}
|
|
6588
|
+
const commands = {
|
|
6268
6589
|
get: `deepline runs get ${runId} --json`,
|
|
6269
6590
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
6270
6591
|
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
6271
6592
|
};
|
|
6593
|
+
if (status.dashboardUrl) {
|
|
6594
|
+
commands.open = `Open ${status.dashboardUrl} to see results.`;
|
|
6595
|
+
}
|
|
6596
|
+
return commands;
|
|
6272
6597
|
}
|
|
6273
6598
|
var RUN_LOG_PREVIEW_LIMIT = 20;
|
|
6274
6599
|
function getRecordField(value, key) {
|
|
@@ -6289,6 +6614,121 @@ function getTimestampField(value, key) {
|
|
|
6289
6614
|
}
|
|
6290
6615
|
return typeof field === "string" && field.trim() ? field : null;
|
|
6291
6616
|
}
|
|
6617
|
+
function getObjectField(value, key) {
|
|
6618
|
+
const field = getRecordField(value, key);
|
|
6619
|
+
return field && typeof field === "object" && !Array.isArray(field) ? field : null;
|
|
6620
|
+
}
|
|
6621
|
+
function formatCreditAmount(value) {
|
|
6622
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
6623
|
+
return String(value ?? "-");
|
|
6624
|
+
}
|
|
6625
|
+
return Number(value.toFixed(8)).toString();
|
|
6626
|
+
}
|
|
6627
|
+
function extractJsonObjectFromText(text) {
|
|
6628
|
+
const start = text.indexOf("{");
|
|
6629
|
+
if (start < 0) {
|
|
6630
|
+
return null;
|
|
6631
|
+
}
|
|
6632
|
+
const suffix = text.slice(start);
|
|
6633
|
+
try {
|
|
6634
|
+
const parsed = JSON.parse(suffix);
|
|
6635
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
6636
|
+
} catch {
|
|
6637
|
+
let depth = 0;
|
|
6638
|
+
let inString = false;
|
|
6639
|
+
let escaped = false;
|
|
6640
|
+
for (let index = start; index < text.length; index += 1) {
|
|
6641
|
+
const char = text[index];
|
|
6642
|
+
if (inString) {
|
|
6643
|
+
if (escaped) {
|
|
6644
|
+
escaped = false;
|
|
6645
|
+
} else if (char === "\\") {
|
|
6646
|
+
escaped = true;
|
|
6647
|
+
} else if (char === '"') {
|
|
6648
|
+
inString = false;
|
|
6649
|
+
}
|
|
6650
|
+
continue;
|
|
6651
|
+
}
|
|
6652
|
+
if (char === '"') {
|
|
6653
|
+
inString = true;
|
|
6654
|
+
} else if (char === "{") {
|
|
6655
|
+
depth += 1;
|
|
6656
|
+
} else if (char === "}") {
|
|
6657
|
+
depth -= 1;
|
|
6658
|
+
if (depth === 0) {
|
|
6659
|
+
try {
|
|
6660
|
+
const parsed = JSON.parse(text.slice(start, index + 1));
|
|
6661
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
6662
|
+
} catch {
|
|
6663
|
+
return null;
|
|
6664
|
+
}
|
|
6665
|
+
}
|
|
6666
|
+
}
|
|
6667
|
+
}
|
|
6668
|
+
}
|
|
6669
|
+
return null;
|
|
6670
|
+
}
|
|
6671
|
+
function extractBillingFromText(text) {
|
|
6672
|
+
if (!text) {
|
|
6673
|
+
return null;
|
|
6674
|
+
}
|
|
6675
|
+
const parsed = extractJsonObjectFromText(text);
|
|
6676
|
+
return getObjectField(parsed, "billing");
|
|
6677
|
+
}
|
|
6678
|
+
function extractToolIdFromErrorText(text) {
|
|
6679
|
+
if (!text) {
|
|
6680
|
+
return null;
|
|
6681
|
+
}
|
|
6682
|
+
const lowerToolMatch = /\btool\s+([A-Za-z0-9_.:-]+)\s+\d{3}\b/.exec(text);
|
|
6683
|
+
if (lowerToolMatch?.[1]) {
|
|
6684
|
+
return lowerToolMatch[1];
|
|
6685
|
+
}
|
|
6686
|
+
const upperToolMatch = /\bTool\s+([A-Za-z0-9_.:-]+)\s+failed\b/.exec(text);
|
|
6687
|
+
return upperToolMatch?.[1] ?? null;
|
|
6688
|
+
}
|
|
6689
|
+
function isInsufficientCreditsBilling(billing) {
|
|
6690
|
+
return billing?.kind === "insufficient_credits";
|
|
6691
|
+
}
|
|
6692
|
+
function extractBillingForStatus(status, error) {
|
|
6693
|
+
const errorBilling = getObjectField(status, "errorBilling");
|
|
6694
|
+
if (errorBilling) {
|
|
6695
|
+
return errorBilling;
|
|
6696
|
+
}
|
|
6697
|
+
const directErrors = getRecordField(status, "errors");
|
|
6698
|
+
if (Array.isArray(directErrors)) {
|
|
6699
|
+
for (const entry of directErrors) {
|
|
6700
|
+
const billing = getObjectField(entry, "billing");
|
|
6701
|
+
if (billing) {
|
|
6702
|
+
return billing;
|
|
6703
|
+
}
|
|
6704
|
+
}
|
|
6705
|
+
}
|
|
6706
|
+
const progressError = getStringField(status.progress, "error");
|
|
6707
|
+
return extractBillingFromText(error) ?? extractBillingFromText(progressError) ?? getObjectField(status, "billing");
|
|
6708
|
+
}
|
|
6709
|
+
function formatInsufficientCreditsMessage(input) {
|
|
6710
|
+
const operation = getStringField(input.billing, "operation_id") ?? getStringField(input.billing, "operation") ?? extractToolIdFromErrorText(input.error) ?? getStringField(input.billing, "provider") ?? "tool call";
|
|
6711
|
+
const balance = formatCreditAmount(input.billing.balance_credits);
|
|
6712
|
+
const required = formatCreditAmount(input.billing.required_credits);
|
|
6713
|
+
const recommended = formatCreditAmount(
|
|
6714
|
+
input.billing.recommended_add_credits ?? input.billing.needed_credits
|
|
6715
|
+
);
|
|
6716
|
+
const billingUrl = getStringField(input.billing, "billing_url");
|
|
6717
|
+
const workspace = getStringField(input.billing, "workspace_id") ?? getStringField(input.billing, "workspaceId");
|
|
6718
|
+
const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
|
|
6719
|
+
const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
|
|
6720
|
+
return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
|
|
6721
|
+
}
|
|
6722
|
+
function formatPlayErrorForDisplay(status, error) {
|
|
6723
|
+
if (!error) {
|
|
6724
|
+
return null;
|
|
6725
|
+
}
|
|
6726
|
+
const billing = extractBillingForStatus(status, error);
|
|
6727
|
+
if (isInsufficientCreditsBilling(billing)) {
|
|
6728
|
+
return formatInsufficientCreditsMessage({ billing, error });
|
|
6729
|
+
}
|
|
6730
|
+
return error;
|
|
6731
|
+
}
|
|
6292
6732
|
function normalizeRunStatusForEnvelope(status) {
|
|
6293
6733
|
const run = status.run ?? null;
|
|
6294
6734
|
return {
|
|
@@ -6339,18 +6779,33 @@ function normalizeErrorsForEnvelope(status, error) {
|
|
|
6339
6779
|
if (Array.isArray(directErrors)) {
|
|
6340
6780
|
return directErrors.filter(
|
|
6341
6781
|
(entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
|
|
6342
|
-
)
|
|
6782
|
+
).map((entry) => {
|
|
6783
|
+
const message2 = typeof entry.message === "string" && entry.message.trim() ? entry.message : error;
|
|
6784
|
+
const billing2 = getObjectField(entry, "billing");
|
|
6785
|
+
if (!isInsufficientCreditsBilling(billing2) || !message2) {
|
|
6786
|
+
return entry;
|
|
6787
|
+
}
|
|
6788
|
+
return {
|
|
6789
|
+
...entry,
|
|
6790
|
+
message: formatInsufficientCreditsMessage({ billing: billing2, error: message2 }),
|
|
6791
|
+
billing: stripProviderSpendFromBilling(billing2)
|
|
6792
|
+
};
|
|
6793
|
+
});
|
|
6343
6794
|
}
|
|
6344
6795
|
if (!error) {
|
|
6345
6796
|
return [];
|
|
6346
6797
|
}
|
|
6798
|
+
const nextCommands = buildRunNextCommands(status);
|
|
6799
|
+
const billing = extractBillingForStatus(status, error);
|
|
6800
|
+
const message = formatPlayErrorForDisplay(status, error) ?? error;
|
|
6347
6801
|
return [
|
|
6348
6802
|
{
|
|
6349
6803
|
code: getStringField(status, "errorCode") ?? "RUN_FAILED",
|
|
6350
6804
|
phase: getStringField(status, "errorPhase") ?? "runtime",
|
|
6351
|
-
message
|
|
6805
|
+
message,
|
|
6352
6806
|
retryable: typeof getRecordField(status, "retryable") === "boolean" ? getRecordField(status, "retryable") : null,
|
|
6353
|
-
|
|
6807
|
+
...billing ? { billing: stripProviderSpendFromBilling(billing) } : {},
|
|
6808
|
+
nextAction: nextCommands.get ?? nextCommands.list
|
|
6354
6809
|
}
|
|
6355
6810
|
];
|
|
6356
6811
|
}
|
|
@@ -6399,24 +6854,26 @@ function compactPlayStatus(status) {
|
|
|
6399
6854
|
) : null;
|
|
6400
6855
|
const progressError = status.progress?.error;
|
|
6401
6856
|
const error = typeof progressError === "string" ? progressError : typeof status.error === "string" ? String(status.error) : null;
|
|
6857
|
+
const displayError = formatPlayErrorForDisplay(status, error);
|
|
6402
6858
|
return {
|
|
6403
6859
|
runId: status.runId,
|
|
6404
6860
|
apiVersion: status.apiVersion ?? 1,
|
|
6405
6861
|
...typeof status.name === "string" ? { name: status.name } : {},
|
|
6406
6862
|
...typeof status.playName === "string" ? { playName: status.playName } : {},
|
|
6863
|
+
...status.dashboardUrl ? { dashboardUrl: status.dashboardUrl } : {},
|
|
6407
6864
|
status: status.status,
|
|
6408
6865
|
run: normalizeRunStatusForEnvelope(status),
|
|
6409
6866
|
progress: normalizeProgressForEnvelope(status, rowsInfo),
|
|
6410
6867
|
steps: normalizeStepsForEnvelope(status),
|
|
6411
6868
|
errors: normalizeErrorsForEnvelope(status, error),
|
|
6412
6869
|
logs: normalizeLogsForEnvelope(status),
|
|
6413
|
-
...
|
|
6870
|
+
...displayError ? { error: displayError } : {},
|
|
6414
6871
|
...warnings.length > 0 ? { warnings } : {},
|
|
6415
6872
|
...result !== void 0 ? { result } : {},
|
|
6416
6873
|
...status.resultView ? { resultView: status.resultView } : {},
|
|
6417
6874
|
...datasetStats ? { dataset_stats: datasetStats } : {},
|
|
6418
6875
|
...billing ? { billing } : {},
|
|
6419
|
-
next: buildRunNextCommands(status
|
|
6876
|
+
next: buildRunNextCommands(status)
|
|
6420
6877
|
};
|
|
6421
6878
|
}
|
|
6422
6879
|
function enrichPlayStatusWithDatasetStats(status) {
|
|
@@ -6490,7 +6947,8 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
6490
6947
|
lines.push(...formatDatasetStatsLines(datasetStats));
|
|
6491
6948
|
const progressError = status.progress?.error;
|
|
6492
6949
|
if (progressError && typeof progressError === "string") {
|
|
6493
|
-
|
|
6950
|
+
const displayError = formatPlayErrorForDisplay(status, progressError) ?? progressError;
|
|
6951
|
+
lines.push(` error: ${displayError.slice(0, 200)}`);
|
|
6494
6952
|
}
|
|
6495
6953
|
const renderedServerView = renderServerResultView(status.resultView);
|
|
6496
6954
|
if (result) {
|
|
@@ -6514,8 +6972,11 @@ var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
|
6514
6972
|
function shellSingleQuote(value) {
|
|
6515
6973
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
6516
6974
|
}
|
|
6975
|
+
function sqlStringLiteral(value) {
|
|
6976
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
6977
|
+
}
|
|
6517
6978
|
function runExportRetryCommand(runId, outPath, datasetPath) {
|
|
6518
|
-
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0,
|
|
6979
|
+
return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0, import_node_path10.resolve)(outPath))}`;
|
|
6519
6980
|
}
|
|
6520
6981
|
function extractRunPlayName(status) {
|
|
6521
6982
|
const run = status.run;
|
|
@@ -6532,6 +6993,26 @@ function extractRunPlayName(status) {
|
|
|
6532
6993
|
}
|
|
6533
6994
|
return null;
|
|
6534
6995
|
}
|
|
6996
|
+
function normalizeCustomerDbIdentifier(value) {
|
|
6997
|
+
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
6998
|
+
}
|
|
6999
|
+
function buildCustomerDbQueryPlan(input) {
|
|
7000
|
+
const playName = extractRunPlayName(input.status);
|
|
7001
|
+
const tableNamespace = input.rowsInfo.tableNamespace?.trim();
|
|
7002
|
+
if (!playName || !tableNamespace || input.rowsInfo.totalRows <= 0) {
|
|
7003
|
+
return null;
|
|
7004
|
+
}
|
|
7005
|
+
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
7006
|
+
tableNamespace
|
|
7007
|
+
)}`;
|
|
7008
|
+
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input.status.runId)} limit ${input.rowsInfo.totalRows}`;
|
|
7009
|
+
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input.rowsInfo.totalRows}`;
|
|
7010
|
+
return {
|
|
7011
|
+
sql,
|
|
7012
|
+
json: `${base} --json`,
|
|
7013
|
+
csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path10.resolve)(input.outPath))}`
|
|
7014
|
+
};
|
|
7015
|
+
}
|
|
6535
7016
|
function exportableSheetRow(row) {
|
|
6536
7017
|
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
6537
7018
|
return null;
|
|
@@ -6629,7 +7110,7 @@ async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
|
6629
7110
|
return null;
|
|
6630
7111
|
}
|
|
6631
7112
|
const availableRows = collectSerializedDatasetRowsInfos(status);
|
|
6632
|
-
|
|
7113
|
+
const rowsInfo = options.datasetPath ? availableRows.find((info) => info.source === options.datasetPath) ?? null : availableRows.length === 1 ? availableRows[0] : null;
|
|
6633
7114
|
if (!rowsInfo && options.datasetPath) {
|
|
6634
7115
|
const available = availableRows.map((info) => info.source).filter((source) => typeof source === "string");
|
|
6635
7116
|
throw new DeeplineError(
|
|
@@ -6703,6 +7184,60 @@ async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
|
6703
7184
|
}
|
|
6704
7185
|
return { path: writeCanonicalRowsCsv(rowsInfo, outPath), rowsInfo };
|
|
6705
7186
|
}
|
|
7187
|
+
function extractActiveRunsFromError(error) {
|
|
7188
|
+
if (!(error instanceof DeeplineError)) {
|
|
7189
|
+
return [];
|
|
7190
|
+
}
|
|
7191
|
+
const response = error.details?.response;
|
|
7192
|
+
if (!response || typeof response !== "object" || Array.isArray(response)) {
|
|
7193
|
+
return [];
|
|
7194
|
+
}
|
|
7195
|
+
const details = response.details;
|
|
7196
|
+
if (!details || typeof details !== "object" || Array.isArray(details)) {
|
|
7197
|
+
return [];
|
|
7198
|
+
}
|
|
7199
|
+
const activeRuns = details.activeRuns;
|
|
7200
|
+
return Array.isArray(activeRuns) ? activeRuns.filter(
|
|
7201
|
+
(run) => Boolean(run) && typeof run === "object" && !Array.isArray(run)
|
|
7202
|
+
) : [];
|
|
7203
|
+
}
|
|
7204
|
+
function activeRunId(run) {
|
|
7205
|
+
return getStringField(run, "workflowId") ?? getStringField(run, "runId");
|
|
7206
|
+
}
|
|
7207
|
+
function formatActiveRunConflictError(input) {
|
|
7208
|
+
const lines = [
|
|
7209
|
+
`Active run exists for ${input.playName}. Use --force to supersede, or inspect/stop the active run first.`
|
|
7210
|
+
];
|
|
7211
|
+
for (const run of input.activeRuns.slice(0, 3)) {
|
|
7212
|
+
const runId = activeRunId(run);
|
|
7213
|
+
if (!runId) {
|
|
7214
|
+
continue;
|
|
7215
|
+
}
|
|
7216
|
+
const status = getStringField(run, "status");
|
|
7217
|
+
const startedAt = getStringField(run, "startedAt") ?? getStringField(run, "startTime");
|
|
7218
|
+
lines.push(
|
|
7219
|
+
` active: ${runId}${status ? ` status=${status}` : ""}${startedAt ? ` startedAt=${startedAt}` : ""}`
|
|
7220
|
+
);
|
|
7221
|
+
lines.push(` get: deepline runs get ${runId} --json`);
|
|
7222
|
+
lines.push(
|
|
7223
|
+
` stop: deepline runs stop ${runId} --reason "stale lock" --json`
|
|
7224
|
+
);
|
|
7225
|
+
}
|
|
7226
|
+
lines.push(` rerun: add --force to the same deepline plays run command`);
|
|
7227
|
+
return lines.join("\n");
|
|
7228
|
+
}
|
|
7229
|
+
function normalizePlayStartError(error, playName) {
|
|
7230
|
+
const activeRuns = extractActiveRunsFromError(error);
|
|
7231
|
+
if (activeRuns.length === 0) {
|
|
7232
|
+
return error;
|
|
7233
|
+
}
|
|
7234
|
+
return new DeeplineError(
|
|
7235
|
+
formatActiveRunConflictError({ playName, activeRuns }),
|
|
7236
|
+
error instanceof DeeplineError ? error.statusCode : 409,
|
|
7237
|
+
"ACTIVE_RUN_EXISTS",
|
|
7238
|
+
error instanceof DeeplineError ? error.details : void 0
|
|
7239
|
+
);
|
|
7240
|
+
}
|
|
6706
7241
|
function renderServerResultView(value) {
|
|
6707
7242
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6708
7243
|
return { lines: [], actions: [] };
|
|
@@ -6938,12 +7473,12 @@ function shouldUseLocalOnlyPlayCheck() {
|
|
|
6938
7473
|
async function handlePlayCheck(args) {
|
|
6939
7474
|
const options = parsePlayCheckOptions(args);
|
|
6940
7475
|
if (!isFileTarget(options.target)) {
|
|
6941
|
-
const resolved = (0,
|
|
7476
|
+
const resolved = (0, import_node_path10.resolve)(options.target);
|
|
6942
7477
|
console.error(`File not found: ${resolved}`);
|
|
6943
7478
|
return 1;
|
|
6944
7479
|
}
|
|
6945
|
-
const absolutePlayPath = (0,
|
|
6946
|
-
const sourceCode = (0,
|
|
7480
|
+
const absolutePlayPath = (0, import_node_path10.resolve)(options.target);
|
|
7481
|
+
const sourceCode = (0, import_node_fs8.readFileSync)(absolutePlayPath, "utf-8");
|
|
6947
7482
|
let graph;
|
|
6948
7483
|
try {
|
|
6949
7484
|
graph = await collectBundledPlayGraph(absolutePlayPath);
|
|
@@ -7006,12 +7541,12 @@ async function handleFileBackedRun(options) {
|
|
|
7006
7541
|
}
|
|
7007
7542
|
const client = new DeeplineClient();
|
|
7008
7543
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
7009
|
-
const absolutePlayPath = (0,
|
|
7544
|
+
const absolutePlayPath = (0, import_node_path10.resolve)(options.target.path);
|
|
7010
7545
|
progress.phase("compiling play");
|
|
7011
7546
|
const sourceCode = traceCliSync(
|
|
7012
7547
|
"cli.play_file_read_source",
|
|
7013
7548
|
{ targetKind: "file" },
|
|
7014
|
-
() => (0,
|
|
7549
|
+
() => (0, import_node_fs8.readFileSync)(absolutePlayPath, "utf-8")
|
|
7015
7550
|
);
|
|
7016
7551
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
7017
7552
|
let graph;
|
|
@@ -7092,6 +7627,8 @@ async function handleFileBackedRun(options) {
|
|
|
7092
7627
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
7093
7628
|
noOpen: options.noOpen,
|
|
7094
7629
|
progress
|
|
7630
|
+
}).catch((error) => {
|
|
7631
|
+
throw normalizePlayStartError(error, playName);
|
|
7095
7632
|
})
|
|
7096
7633
|
);
|
|
7097
7634
|
if (finalStatus.status === "completed") {
|
|
@@ -7110,10 +7647,11 @@ async function handleFileBackedRun(options) {
|
|
|
7110
7647
|
const started = await traceCliSpan(
|
|
7111
7648
|
"cli.play_start_unwatched",
|
|
7112
7649
|
{ targetKind: "file", playName },
|
|
7113
|
-
() => client.startPlayRun(startRequest)
|
|
7650
|
+
() => client.startPlayRun(startRequest).catch((error) => {
|
|
7651
|
+
throw normalizePlayStartError(error, playName);
|
|
7652
|
+
})
|
|
7114
7653
|
);
|
|
7115
|
-
const
|
|
7116
|
-
const resolvedDashboardUrl = started.dashboardUrl ?? dashboardUrl;
|
|
7654
|
+
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7117
7655
|
openPlayDashboard({
|
|
7118
7656
|
dashboardUrl: resolvedDashboardUrl,
|
|
7119
7657
|
jsonOutput: options.jsonOutput,
|
|
@@ -7228,6 +7766,8 @@ async function handleNamedRun(options) {
|
|
|
7228
7766
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
7229
7767
|
noOpen: options.noOpen,
|
|
7230
7768
|
progress
|
|
7769
|
+
}).catch((error) => {
|
|
7770
|
+
throw normalizePlayStartError(error, playName);
|
|
7231
7771
|
})
|
|
7232
7772
|
);
|
|
7233
7773
|
if (finalStatus.status === "completed") {
|
|
@@ -7246,13 +7786,11 @@ async function handleNamedRun(options) {
|
|
|
7246
7786
|
const started = await traceCliSpan(
|
|
7247
7787
|
"cli.play_start_unwatched",
|
|
7248
7788
|
{ targetKind: "name", playName },
|
|
7249
|
-
() => client.startPlayRun(startRequest)
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
client.baseUrl,
|
|
7253
|
-
playName
|
|
7789
|
+
() => client.startPlayRun(startRequest).catch((error) => {
|
|
7790
|
+
throw normalizePlayStartError(error, playName);
|
|
7791
|
+
})
|
|
7254
7792
|
);
|
|
7255
|
-
const resolvedDashboardUrl =
|
|
7793
|
+
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7256
7794
|
openPlayDashboard({
|
|
7257
7795
|
dashboardUrl: resolvedDashboardUrl,
|
|
7258
7796
|
jsonOutput: options.jsonOutput,
|
|
@@ -7276,19 +7814,19 @@ async function handlePlayRun(args) {
|
|
|
7276
7814
|
if (isFileTarget(options.target.path)) {
|
|
7277
7815
|
return handleFileBackedRun(options);
|
|
7278
7816
|
}
|
|
7279
|
-
const resolved = (0,
|
|
7817
|
+
const resolved = (0, import_node_path10.resolve)(options.target.path);
|
|
7280
7818
|
console.error(`File not found: ${resolved}`);
|
|
7281
|
-
const dir = (0,
|
|
7282
|
-
if ((0,
|
|
7283
|
-
const base = (0,
|
|
7819
|
+
const dir = (0, import_node_path10.dirname)(resolved);
|
|
7820
|
+
if ((0, import_node_fs8.existsSync)(dir)) {
|
|
7821
|
+
const base = (0, import_node_path10.basename)(resolved);
|
|
7284
7822
|
try {
|
|
7285
|
-
const siblings = (0,
|
|
7823
|
+
const siblings = (0, import_node_fs8.readdirSync)(dir).filter(
|
|
7286
7824
|
(f) => f.includes(base.replace(/\.(play\.)?ts$/, "")) || f.endsWith(".play.ts")
|
|
7287
7825
|
);
|
|
7288
7826
|
if (siblings.length > 0) {
|
|
7289
7827
|
console.error(`Did you mean one of these?`);
|
|
7290
7828
|
for (const s of siblings.slice(0, 5)) {
|
|
7291
|
-
console.error(` ${(0,
|
|
7829
|
+
console.error(` ${(0, import_node_path10.join)(dir, s)}`);
|
|
7292
7830
|
}
|
|
7293
7831
|
}
|
|
7294
7832
|
} catch {
|
|
@@ -7423,14 +7961,14 @@ async function handleRunLogs(args) {
|
|
|
7423
7961
|
continue;
|
|
7424
7962
|
}
|
|
7425
7963
|
if (arg === "--out" && args[index + 1]) {
|
|
7426
|
-
outPath = (0,
|
|
7964
|
+
outPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7427
7965
|
}
|
|
7428
7966
|
}
|
|
7429
7967
|
const client = new DeeplineClient();
|
|
7430
7968
|
const status = await client.runs.get(runId);
|
|
7431
7969
|
const logs = status.progress?.logs ?? [];
|
|
7432
7970
|
if (outPath) {
|
|
7433
|
-
(0,
|
|
7971
|
+
(0, import_node_fs8.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
7434
7972
|
printCommandEnvelope({
|
|
7435
7973
|
runId: status.runId,
|
|
7436
7974
|
log_path: outPath,
|
|
@@ -7486,7 +8024,7 @@ async function handleRunStop(args) {
|
|
|
7486
8024
|
return 0;
|
|
7487
8025
|
}
|
|
7488
8026
|
async function handleRunExport(args) {
|
|
7489
|
-
const usage = "Usage: deepline runs export <run-id> [--dataset result.rows] --out output.csv [--json]";
|
|
8027
|
+
const usage = "Usage: deepline runs export <run-id> [--dataset result.rows] --out output.csv [--metadata-out export.json] [--json]";
|
|
7490
8028
|
let runId;
|
|
7491
8029
|
try {
|
|
7492
8030
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -7496,14 +8034,19 @@ async function handleRunExport(args) {
|
|
|
7496
8034
|
}
|
|
7497
8035
|
let outPath = null;
|
|
7498
8036
|
let datasetPath = null;
|
|
8037
|
+
let metadataOutPath = null;
|
|
7499
8038
|
for (let index = 0; index < args.length; index += 1) {
|
|
7500
8039
|
const arg = args[index];
|
|
7501
8040
|
if (arg === "--out" && args[index + 1]) {
|
|
7502
|
-
outPath = (0,
|
|
8041
|
+
outPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7503
8042
|
continue;
|
|
7504
8043
|
}
|
|
7505
8044
|
if (arg === "--dataset" && args[index + 1]) {
|
|
7506
8045
|
datasetPath = args[++index];
|
|
8046
|
+
continue;
|
|
8047
|
+
}
|
|
8048
|
+
if (arg === "--metadata-out" && args[index + 1]) {
|
|
8049
|
+
metadataOutPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7507
8050
|
}
|
|
7508
8051
|
}
|
|
7509
8052
|
if (!outPath) {
|
|
@@ -7515,15 +8058,59 @@ async function handleRunExport(args) {
|
|
|
7515
8058
|
const exportResult = await exportPlayStatusRows(client, status, outPath, {
|
|
7516
8059
|
datasetPath
|
|
7517
8060
|
});
|
|
7518
|
-
|
|
8061
|
+
const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
|
|
8062
|
+
const queryPlan = exportResult && outPath ? buildCustomerDbQueryPlan({
|
|
8063
|
+
status,
|
|
8064
|
+
rowsInfo: exportResult.rowsInfo,
|
|
8065
|
+
outPath
|
|
8066
|
+
}) : null;
|
|
8067
|
+
const next = {
|
|
8068
|
+
...buildRunNextCommands(status),
|
|
8069
|
+
export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source),
|
|
8070
|
+
...queryPlan ? {
|
|
8071
|
+
queryJson: queryPlan.json,
|
|
8072
|
+
queryCsv: queryPlan.csv
|
|
8073
|
+
} : {}
|
|
8074
|
+
};
|
|
8075
|
+
const payload = {
|
|
7519
8076
|
runId: status.runId,
|
|
7520
8077
|
...datasetPath ? { dataset: datasetPath } : {},
|
|
7521
8078
|
csv_path: exportResult?.path ?? null,
|
|
8079
|
+
source,
|
|
7522
8080
|
rowCount: exportResult?.rowsInfo.totalRows ?? null,
|
|
7523
8081
|
columns: exportResult?.rowsInfo.columns ?? [],
|
|
8082
|
+
...queryPlan ? {
|
|
8083
|
+
query: {
|
|
8084
|
+
sql: queryPlan.sql,
|
|
8085
|
+
json: queryPlan.json,
|
|
8086
|
+
csv: queryPlan.csv
|
|
8087
|
+
}
|
|
8088
|
+
} : {},
|
|
8089
|
+
...metadataOutPath ? { metadata_path: metadataOutPath } : {},
|
|
7524
8090
|
local: { csv_path: exportResult?.path ?? null },
|
|
7525
|
-
|
|
7526
|
-
|
|
8091
|
+
next,
|
|
8092
|
+
render: {
|
|
8093
|
+
sections: [
|
|
8094
|
+
{
|
|
8095
|
+
title: "run export",
|
|
8096
|
+
lines: [
|
|
8097
|
+
`Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
|
|
8098
|
+
...source ? [`source=${source}`] : [],
|
|
8099
|
+
...queryPlan ? [`query=${queryPlan.json}`] : []
|
|
8100
|
+
]
|
|
8101
|
+
}
|
|
8102
|
+
]
|
|
8103
|
+
}
|
|
8104
|
+
};
|
|
8105
|
+
if (metadataOutPath) {
|
|
8106
|
+
(0, import_node_fs8.writeFileSync)(
|
|
8107
|
+
metadataOutPath,
|
|
8108
|
+
`${JSON.stringify(payload, null, 2)}
|
|
8109
|
+
`,
|
|
8110
|
+
"utf-8"
|
|
8111
|
+
);
|
|
8112
|
+
}
|
|
8113
|
+
printCommandEnvelope(payload, { json: argsWantJson(args) });
|
|
7527
8114
|
return 0;
|
|
7528
8115
|
}
|
|
7529
8116
|
async function handlePlayGet(args) {
|
|
@@ -7540,10 +8127,10 @@ async function handlePlayGet(args) {
|
|
|
7540
8127
|
for (let index = 1; index < args.length; index += 1) {
|
|
7541
8128
|
const arg = args[index];
|
|
7542
8129
|
if (arg === "--out" && args[index + 1]) {
|
|
7543
|
-
outPath = (0,
|
|
8130
|
+
outPath = (0, import_node_path10.resolve)(args[++index]);
|
|
7544
8131
|
}
|
|
7545
8132
|
}
|
|
7546
|
-
const playName = isFileTarget(target) ? extractPlayName((0,
|
|
8133
|
+
const playName = isFileTarget(target) ? extractPlayName((0, import_node_fs8.readFileSync)((0, import_node_path10.resolve)(target), "utf-8"), (0, import_node_path10.resolve)(target)) : parseReferencedPlayTarget(target).playName;
|
|
7547
8134
|
const detail = isFileTarget(target) ? await client.getPlay(playName) : await assertCanonicalNamedPlayReference(client, target);
|
|
7548
8135
|
const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
|
|
7549
8136
|
const materializedFile = outPath ? materializeRemotePlaySource({
|
|
@@ -7835,7 +8422,7 @@ async function handlePlayPublish(args) {
|
|
|
7835
8422
|
}
|
|
7836
8423
|
let graph;
|
|
7837
8424
|
try {
|
|
7838
|
-
graph = await collectBundledPlayGraph((0,
|
|
8425
|
+
graph = await collectBundledPlayGraph((0, import_node_path10.resolve)(playName));
|
|
7839
8426
|
await compileBundledPlayGraphManifests(client, graph);
|
|
7840
8427
|
await publishImportedPlayDependencies(client, graph);
|
|
7841
8428
|
} catch (error) {
|
|
@@ -8321,32 +8908,36 @@ Examples:
|
|
|
8321
8908
|
Notes:
|
|
8322
8909
|
Writes a returned dataset handle to the requested local CSV path. Use runs get
|
|
8323
8910
|
first to inspect dataset paths like result.rows or result.nested.contacts.
|
|
8911
|
+
--metadata-out writes the same export metadata object returned by --json,
|
|
8912
|
+
including source and follow-on customer-db query commands when available.
|
|
8324
8913
|
|
|
8325
8914
|
Examples:
|
|
8326
8915
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
8327
8916
|
deepline runs export play/my-play/run/20260501t000000-000 --dataset result.rows --out output.csv
|
|
8917
|
+
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --metadata-out output.meta.json
|
|
8328
8918
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --json
|
|
8329
8919
|
`
|
|
8330
|
-
).requiredOption("--out <path>", "Output CSV path").option("--dataset <path>", "Returned dataset handle path, such as result.rows").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
8920
|
+
).requiredOption("--out <path>", "Output CSV path").option("--dataset <path>", "Returned dataset handle path, such as result.rows").option("--metadata-out <path>", "Write export metadata JSON to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
8331
8921
|
process.exitCode = await handleRunExport([
|
|
8332
8922
|
runId,
|
|
8333
8923
|
...options.dataset ? ["--dataset", options.dataset] : [],
|
|
8334
8924
|
"--out",
|
|
8335
8925
|
options.out,
|
|
8926
|
+
...options.metadataOut ? ["--metadata-out", options.metadataOut] : [],
|
|
8336
8927
|
...options.json ? ["--json"] : []
|
|
8337
8928
|
]);
|
|
8338
8929
|
});
|
|
8339
8930
|
}
|
|
8340
8931
|
|
|
8341
8932
|
// src/cli/commands/tools.ts
|
|
8342
|
-
var
|
|
8933
|
+
var import_node_fs10 = require("fs");
|
|
8343
8934
|
var import_node_os7 = require("os");
|
|
8344
|
-
var
|
|
8935
|
+
var import_node_path12 = require("path");
|
|
8345
8936
|
|
|
8346
8937
|
// src/tool-output.ts
|
|
8347
|
-
var
|
|
8938
|
+
var import_node_fs9 = require("fs");
|
|
8348
8939
|
var import_node_os6 = require("os");
|
|
8349
|
-
var
|
|
8940
|
+
var import_node_path11 = require("path");
|
|
8350
8941
|
function isPlainObject(value) {
|
|
8351
8942
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
8352
8943
|
}
|
|
@@ -8369,6 +8960,25 @@ function normalizeRows(value) {
|
|
|
8369
8960
|
}
|
|
8370
8961
|
function candidateRoots(payload) {
|
|
8371
8962
|
const roots = [{ path: null, value: payload }];
|
|
8963
|
+
if (isPlainObject(payload) && isPlainObject(payload.toolExecutionResult)) {
|
|
8964
|
+
roots.push({ path: "toolExecutionResult", value: payload.toolExecutionResult });
|
|
8965
|
+
const toolOutput = payload.toolExecutionResult.toolOutput;
|
|
8966
|
+
if (isPlainObject(toolOutput)) {
|
|
8967
|
+
roots.push({ path: "toolExecutionResult.toolOutput", value: toolOutput });
|
|
8968
|
+
if (Object.prototype.hasOwnProperty.call(toolOutput, "raw")) {
|
|
8969
|
+
roots.push({
|
|
8970
|
+
path: "toolExecutionResult.toolOutput.raw",
|
|
8971
|
+
value: toolOutput.raw
|
|
8972
|
+
});
|
|
8973
|
+
}
|
|
8974
|
+
}
|
|
8975
|
+
}
|
|
8976
|
+
if (isPlainObject(payload) && isPlainObject(payload.output)) {
|
|
8977
|
+
roots.push({ path: "output", value: payload.output });
|
|
8978
|
+
if (Object.prototype.hasOwnProperty.call(payload.output, "body")) {
|
|
8979
|
+
roots.push({ path: "output.body", value: payload.output.body });
|
|
8980
|
+
}
|
|
8981
|
+
}
|
|
8372
8982
|
if (isPlainObject(payload) && isPlainObject(payload.result)) {
|
|
8373
8983
|
roots.push({ path: "result", value: payload.result });
|
|
8374
8984
|
if (isPlainObject(payload.result.data)) {
|
|
@@ -8421,19 +9031,19 @@ function tryConvertToList(payload, options) {
|
|
|
8421
9031
|
return null;
|
|
8422
9032
|
}
|
|
8423
9033
|
function ensureOutputDir() {
|
|
8424
|
-
const outputDir = (0,
|
|
8425
|
-
(0,
|
|
9034
|
+
const outputDir = (0, import_node_path11.join)((0, import_node_os6.homedir)(), ".local", "share", "deepline", "data");
|
|
9035
|
+
(0, import_node_fs9.mkdirSync)(outputDir, { recursive: true });
|
|
8426
9036
|
return outputDir;
|
|
8427
9037
|
}
|
|
8428
9038
|
function writeJsonOutputFile(payload, stem) {
|
|
8429
9039
|
const outputDir = ensureOutputDir();
|
|
8430
|
-
const outputPath = (0,
|
|
8431
|
-
(0,
|
|
9040
|
+
const outputPath = (0, import_node_path11.join)(outputDir, `${stem}_${Date.now()}.json`);
|
|
9041
|
+
(0, import_node_fs9.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
8432
9042
|
return outputPath;
|
|
8433
9043
|
}
|
|
8434
9044
|
function writeCsvOutputFile(rows, stem) {
|
|
8435
9045
|
const outputDir = ensureOutputDir();
|
|
8436
|
-
const outputPath = (0,
|
|
9046
|
+
const outputPath = (0, import_node_path11.join)(outputDir, `${stem}_${Date.now()}.csv`);
|
|
8437
9047
|
const seen = /* @__PURE__ */ new Set();
|
|
8438
9048
|
const columns = [];
|
|
8439
9049
|
for (const row of rows) {
|
|
@@ -8456,7 +9066,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
8456
9066
|
for (const row of rows) {
|
|
8457
9067
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
8458
9068
|
}
|
|
8459
|
-
(0,
|
|
9069
|
+
(0, import_node_fs9.writeFileSync)(outputPath, `${lines.join("\n")}
|
|
8460
9070
|
`, "utf-8");
|
|
8461
9071
|
const previewRows = rows.slice(0, 5);
|
|
8462
9072
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -8502,8 +9112,7 @@ async function listTools(args) {
|
|
|
8502
9112
|
title: `${items.length} tools available:`,
|
|
8503
9113
|
lines: items.flatMap((item) => {
|
|
8504
9114
|
const cats = item.categories.length ? ` [${item.categories.join(", ")}]` : "";
|
|
8505
|
-
|
|
8506
|
-
return [`${item.toolId}${cats}`, ` ${item.description}${listHint}`];
|
|
9115
|
+
return [`${item.toolId}${cats}`, ` ${item.description}`];
|
|
8507
9116
|
})
|
|
8508
9117
|
}
|
|
8509
9118
|
]
|
|
@@ -8582,7 +9191,7 @@ Common commands:
|
|
|
8582
9191
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
8583
9192
|
|
|
8584
9193
|
Output:
|
|
8585
|
-
Use describe for tool contracts.
|
|
9194
|
+
Use describe for tool contracts.
|
|
8586
9195
|
Use execute to run a tool. run is accepted as a compatibility alias.
|
|
8587
9196
|
`
|
|
8588
9197
|
);
|
|
@@ -8629,8 +9238,8 @@ Examples:
|
|
|
8629
9238
|
`
|
|
8630
9239
|
Notes:
|
|
8631
9240
|
Shows the tool contract, input schema, output schema, Deepline cost, aliases,
|
|
8632
|
-
and metadata. describe is the
|
|
8633
|
-
|
|
9241
|
+
and metadata. describe is the supported discovery verb. get is removed in
|
|
9242
|
+
the V2 SDK CLI; use describe for the same metadata surface.
|
|
8634
9243
|
|
|
8635
9244
|
Examples:
|
|
8636
9245
|
deepline tools describe hunter_email_verifier
|
|
@@ -8643,7 +9252,22 @@ Examples:
|
|
|
8643
9252
|
...options.json ? ["--json"] : []
|
|
8644
9253
|
]);
|
|
8645
9254
|
});
|
|
8646
|
-
addToolMetadataCommand(tools.command("describe <toolId>")
|
|
9255
|
+
addToolMetadataCommand(tools.command("describe <toolId>"));
|
|
9256
|
+
tools.command("get <toolId>").description("Deprecated. Use tools describe.").addHelpText(
|
|
9257
|
+
"after",
|
|
9258
|
+
`
|
|
9259
|
+
Examples:
|
|
9260
|
+
deepline tools describe hunter_email_verifier --json
|
|
9261
|
+
`
|
|
9262
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (toolId, options) => {
|
|
9263
|
+
const message = `tools get has been removed from the V2 SDK CLI. Use: deepline tools describe ${toolId} --json`;
|
|
9264
|
+
if (options.json || shouldEmitJson()) {
|
|
9265
|
+
printJsonError({ message, code: "TOOLS_GET_REMOVED" });
|
|
9266
|
+
} else {
|
|
9267
|
+
console.error(message);
|
|
9268
|
+
}
|
|
9269
|
+
process.exitCode = 2;
|
|
9270
|
+
});
|
|
8647
9271
|
tools.command("execute <toolId>").alias("run").description("Execute a tool by id.").addHelpText(
|
|
8648
9272
|
"after",
|
|
8649
9273
|
`
|
|
@@ -8724,6 +9348,7 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8724
9348
|
const stepContributions = arrayField(tool, "stepContributions", "step_contributions");
|
|
8725
9349
|
const playExpansion = recordField(tool, "playExpansion", "play_expansion");
|
|
8726
9350
|
const samples = recordField(tool, "samples");
|
|
9351
|
+
const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
|
|
8727
9352
|
console.log(`Tool: ${toolId}`);
|
|
8728
9353
|
if (displayName) {
|
|
8729
9354
|
console.log(" Display name:");
|
|
@@ -8787,14 +9412,16 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8787
9412
|
console.log(" Tip: pass --payload with a JSON object.");
|
|
8788
9413
|
}
|
|
8789
9414
|
printSamples(samples);
|
|
9415
|
+
printUsageGuidance(usageGuidance);
|
|
8790
9416
|
if (isPlayTool(tool)) {
|
|
8791
9417
|
console.log(" Play contract:");
|
|
8792
9418
|
console.log(" - This is a deepline-native waterfall; the returned rows are extracted by target getters, not by hand-authored payload shape.");
|
|
8793
9419
|
if (playExpansion && typeof playExpansion.group === "string" && playExpansion.group.trim()) {
|
|
8794
9420
|
console.log(` - Output alias/runtime group is: ${playExpansion.group.trim()}`);
|
|
8795
9421
|
}
|
|
8796
|
-
const
|
|
8797
|
-
const
|
|
9422
|
+
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult");
|
|
9423
|
+
const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9424
|
+
const targets = extractedValues.map((entry) => isRecord3(entry) && typeof entry.name === "string" ? entry.name : "").filter(Boolean).sort();
|
|
8798
9425
|
if (targets.length) {
|
|
8799
9426
|
console.log(` - Built-in extract targets: ${targets.join(", ")}`);
|
|
8800
9427
|
}
|
|
@@ -8813,7 +9440,53 @@ function printToolDetails(tool, requestedToolId) {
|
|
|
8813
9440
|
} else {
|
|
8814
9441
|
console.log(` deepline tools execute ${toolId} --payload '{...}'`);
|
|
8815
9442
|
}
|
|
8816
|
-
console.log(" deepline tools
|
|
9443
|
+
console.log(" deepline tools describe <tool_id> --json");
|
|
9444
|
+
}
|
|
9445
|
+
function printUsageGuidance(usageGuidance) {
|
|
9446
|
+
if (Object.keys(usageGuidance).length === 0) return;
|
|
9447
|
+
const execute = stringField(usageGuidance, "execute");
|
|
9448
|
+
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
|
|
9449
|
+
const toolOutput = recordField(toolExecutionResult, "toolOutput", "tool_output");
|
|
9450
|
+
const extractedLists = extractionEntries(toolExecutionResult, "extractedLists", "extracted_lists");
|
|
9451
|
+
const extractedValues = extractionEntries(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9452
|
+
console.log(" Usage guidance:");
|
|
9453
|
+
if (execute) console.log(` ${execute}`);
|
|
9454
|
+
const raw = pathField(toolOutput, "raw");
|
|
9455
|
+
const meta = pathField(toolOutput, "meta");
|
|
9456
|
+
if (raw) console.log(` Raw tool output: ${raw}`);
|
|
9457
|
+
if (meta) console.log(` Tool output metadata: ${meta}`);
|
|
9458
|
+
printExtractions("Extracted lists", extractedLists);
|
|
9459
|
+
printExtractions("Extracted values", extractedValues);
|
|
9460
|
+
}
|
|
9461
|
+
function pathField(record, key) {
|
|
9462
|
+
const value = record[key];
|
|
9463
|
+
if (typeof value === "string") return value.trim();
|
|
9464
|
+
if (isRecord3(value)) return stringField(value, "path");
|
|
9465
|
+
return "";
|
|
9466
|
+
}
|
|
9467
|
+
function extractionEntries(record, camelKey, snakeKey) {
|
|
9468
|
+
const value = record[camelKey] ?? record[snakeKey];
|
|
9469
|
+
if (Array.isArray(value)) return value;
|
|
9470
|
+
if (!isRecord3(value)) return [];
|
|
9471
|
+
return Object.entries(value).map(
|
|
9472
|
+
([name, entry]) => isRecord3(entry) ? { name, ...entry } : { name }
|
|
9473
|
+
);
|
|
9474
|
+
}
|
|
9475
|
+
function printExtractions(label, entries) {
|
|
9476
|
+
if (!entries.length) return;
|
|
9477
|
+
console.log(` ${label}:`);
|
|
9478
|
+
for (const entry of entries) {
|
|
9479
|
+
if (!isRecord3(entry)) continue;
|
|
9480
|
+
const name = stringField(entry, "name");
|
|
9481
|
+
const expression = stringField(entry, "expression");
|
|
9482
|
+
const details = recordField(entry, "details");
|
|
9483
|
+
const rawToolOutputPaths = arrayField(details, "rawToolOutputPaths", "raw_tool_output_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9484
|
+
const candidatePaths = arrayField(details, "candidatePaths", "candidate_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9485
|
+
if (!name || !expression) continue;
|
|
9486
|
+
const paths = candidatePaths.length ? candidatePaths : rawToolOutputPaths;
|
|
9487
|
+
const pathSuffix = paths.length ? ` from ${paths.join(", ")}` : "";
|
|
9488
|
+
console.log(` - ${name}: ${expression}${pathSuffix}`);
|
|
9489
|
+
}
|
|
8817
9490
|
}
|
|
8818
9491
|
function printToolCost(input) {
|
|
8819
9492
|
const { cost, billingSource, deeplineCredits, deeplineUsdPerPricingUnit } = input;
|
|
@@ -8881,6 +9554,17 @@ function samplePayload(samples, key) {
|
|
|
8881
9554
|
function commandEnvelopeFromRawResponse(rawResponse) {
|
|
8882
9555
|
return isRecord3(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
|
|
8883
9556
|
}
|
|
9557
|
+
function listExtractorPathsFromUsageGuidance(tool) {
|
|
9558
|
+
const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
|
|
9559
|
+
const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord3(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
|
|
9560
|
+
return extractedLists.flatMap((entry) => {
|
|
9561
|
+
const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
|
|
9562
|
+
if (!Array.isArray(paths)) return [];
|
|
9563
|
+
return paths.map(
|
|
9564
|
+
(path) => path.trim().replace(/^toolExecutionResult\.toolOutput\.raw\.?/, "").replace(/^\./, "")
|
|
9565
|
+
).filter(Boolean);
|
|
9566
|
+
});
|
|
9567
|
+
}
|
|
8884
9568
|
function isPlayTool(tool) {
|
|
8885
9569
|
const provider = typeof tool.provider === "string" ? tool.provider : "";
|
|
8886
9570
|
return provider === "deepline_native" && Boolean(recordField(tool, "playExpansion", "play_expansion"));
|
|
@@ -8954,6 +9638,7 @@ function parseExecuteOptions(args) {
|
|
|
8954
9638
|
const params = {};
|
|
8955
9639
|
let outputFormat = "auto";
|
|
8956
9640
|
let noPreview = false;
|
|
9641
|
+
let fullOutput = false;
|
|
8957
9642
|
for (let index = 1; index < args.length; index += 1) {
|
|
8958
9643
|
const arg = args[index];
|
|
8959
9644
|
if ((arg === "--param" || arg === "-p") && args[index + 1]) {
|
|
@@ -8980,6 +9665,7 @@ function parseExecuteOptions(args) {
|
|
|
8980
9665
|
}
|
|
8981
9666
|
if (arg === "--full-output") {
|
|
8982
9667
|
outputFormat = "json";
|
|
9668
|
+
fullOutput = true;
|
|
8983
9669
|
continue;
|
|
8984
9670
|
}
|
|
8985
9671
|
if (arg === "--no-preview") {
|
|
@@ -8988,7 +9674,7 @@ function parseExecuteOptions(args) {
|
|
|
8988
9674
|
}
|
|
8989
9675
|
throw new Error(`Unknown option: ${arg}`);
|
|
8990
9676
|
}
|
|
8991
|
-
return { toolId, params, outputFormat, noPreview };
|
|
9677
|
+
return { toolId, params, outputFormat, noPreview, fullOutput };
|
|
8992
9678
|
}
|
|
8993
9679
|
function safeFileStem(value) {
|
|
8994
9680
|
return value.trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "tool";
|
|
@@ -9002,9 +9688,9 @@ function powerShellQuote(value) {
|
|
|
9002
9688
|
function seedToolListScript(input) {
|
|
9003
9689
|
const stem = safeFileStem(input.toolId);
|
|
9004
9690
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
9005
|
-
const scriptDir = (0,
|
|
9006
|
-
(0,
|
|
9007
|
-
const scriptPath = (0,
|
|
9691
|
+
const scriptDir = (0, import_node_fs10.mkdtempSync)((0, import_node_path12.join)((0, import_node_os7.tmpdir)(), "deepline-workflow-seed-"));
|
|
9692
|
+
(0, import_node_fs10.chmodSync)(scriptDir, 448);
|
|
9693
|
+
const scriptPath = (0, import_node_path12.join)(scriptDir, fileName);
|
|
9008
9694
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
9009
9695
|
const playName = `${stem}-workflow`;
|
|
9010
9696
|
const sampleRows = input.rows.length > 0 ? `${JSON.stringify(input.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
@@ -9020,7 +9706,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9020
9706
|
description: ${JSON.stringify(`Seed ${input.toolId} rows for workflow expansion.`)},
|
|
9021
9707
|
});
|
|
9022
9708
|
|
|
9023
|
-
const list = Object.values(result.
|
|
9709
|
+
const list = Object.values(result.extractedLists)[0];
|
|
9024
9710
|
const rows = (list?.get() ?? []).slice(0, 100);
|
|
9025
9711
|
// ${sampleRows}
|
|
9026
9712
|
// columns: ${columns}
|
|
@@ -9037,7 +9723,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9037
9723
|
};
|
|
9038
9724
|
});
|
|
9039
9725
|
`;
|
|
9040
|
-
(0,
|
|
9726
|
+
(0, import_node_fs10.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
9041
9727
|
return {
|
|
9042
9728
|
path: scriptPath,
|
|
9043
9729
|
projectDir,
|
|
@@ -9048,7 +9734,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
9048
9734
|
function buildToolExecuteBaseEnvelope(input) {
|
|
9049
9735
|
const envelope = commandEnvelopeFromRawResponse(input.rawResponse);
|
|
9050
9736
|
const summaryEntries = Object.entries(input.summary);
|
|
9051
|
-
const
|
|
9737
|
+
const outputPreview = input.listConversion ? {
|
|
9052
9738
|
kind: "list",
|
|
9053
9739
|
rowCount: input.listConversion.rows.length,
|
|
9054
9740
|
columns: Object.keys(input.listConversion.rows[0] ?? {}),
|
|
@@ -9059,6 +9745,7 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
9059
9745
|
kind: summaryEntries.length > 0 ? "object" : "raw",
|
|
9060
9746
|
summary: input.summary
|
|
9061
9747
|
};
|
|
9748
|
+
const envelopeHasCanonicalOutput = isRecord3(envelope.toolExecutionResult) && isRecord3(envelope.toolExecutionResult.toolOutput) && Object.prototype.hasOwnProperty.call(envelope.toolExecutionResult.toolOutput, "raw");
|
|
9062
9749
|
const actions = input.listConversion ? [
|
|
9063
9750
|
{
|
|
9064
9751
|
label: "next",
|
|
@@ -9067,7 +9754,7 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
9067
9754
|
] : [];
|
|
9068
9755
|
return {
|
|
9069
9756
|
...envelope,
|
|
9070
|
-
output,
|
|
9757
|
+
...envelopeHasCanonicalOutput ? { output_preview: outputPreview } : { output: outputPreview },
|
|
9071
9758
|
...summaryEntries.length > 0 ? { summary: input.summary } : {},
|
|
9072
9759
|
next: input.listConversion ? {
|
|
9073
9760
|
expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again."
|
|
@@ -9120,8 +9807,12 @@ async function executeTool(args) {
|
|
|
9120
9807
|
throw error;
|
|
9121
9808
|
}
|
|
9122
9809
|
const rawResponse = await client.executeTool(parsed.toolId, parsed.params);
|
|
9810
|
+
if (parsed.fullOutput) {
|
|
9811
|
+
printJson(rawResponse);
|
|
9812
|
+
return 0;
|
|
9813
|
+
}
|
|
9123
9814
|
const listConversion = tryConvertToList(rawResponse, {
|
|
9124
|
-
listExtractorPaths: metadata
|
|
9815
|
+
listExtractorPaths: listExtractorPathsFromUsageGuidance(metadata)
|
|
9125
9816
|
});
|
|
9126
9817
|
const summary = extractSummaryFields(rawResponse);
|
|
9127
9818
|
const baseEnvelope = buildToolExecuteBaseEnvelope({
|
|
@@ -9251,9 +9942,9 @@ async function executeTool(args) {
|
|
|
9251
9942
|
}
|
|
9252
9943
|
|
|
9253
9944
|
// src/cli/commands/update.ts
|
|
9254
|
-
var
|
|
9255
|
-
var
|
|
9256
|
-
var
|
|
9945
|
+
var import_node_child_process = require("child_process");
|
|
9946
|
+
var import_node_fs11 = require("fs");
|
|
9947
|
+
var import_node_path13 = require("path");
|
|
9257
9948
|
function posixShellQuote(value) {
|
|
9258
9949
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
9259
9950
|
}
|
|
@@ -9272,19 +9963,19 @@ function buildSourceUpdateCommand(sourceRoot) {
|
|
|
9272
9963
|
return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
|
|
9273
9964
|
}
|
|
9274
9965
|
function findRepoBackedSdkRoot(startPath) {
|
|
9275
|
-
let current = (0,
|
|
9966
|
+
let current = (0, import_node_path13.resolve)(startPath);
|
|
9276
9967
|
while (true) {
|
|
9277
|
-
if ((0,
|
|
9968
|
+
if ((0, import_node_fs11.existsSync)((0, import_node_path13.join)(current, "sdk", "package.json")) && (0, import_node_fs11.existsSync)((0, import_node_path13.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
|
|
9278
9969
|
return current;
|
|
9279
9970
|
}
|
|
9280
|
-
const parent = (0,
|
|
9971
|
+
const parent = (0, import_node_path13.dirname)(current);
|
|
9281
9972
|
if (parent === current) return null;
|
|
9282
9973
|
current = parent;
|
|
9283
9974
|
}
|
|
9284
9975
|
}
|
|
9285
9976
|
function resolveUpdatePlan() {
|
|
9286
|
-
const entrypoint = process.argv[1] ? (0,
|
|
9287
|
-
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0,
|
|
9977
|
+
const entrypoint = process.argv[1] ? (0, import_node_path13.resolve)(process.argv[1]) : "";
|
|
9978
|
+
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path13.dirname)(entrypoint)) : null;
|
|
9288
9979
|
if (sourceRoot) {
|
|
9289
9980
|
return {
|
|
9290
9981
|
kind: "source",
|
|
@@ -9303,7 +9994,7 @@ function resolveUpdatePlan() {
|
|
|
9303
9994
|
}
|
|
9304
9995
|
function runCommand(command, args) {
|
|
9305
9996
|
return new Promise((resolveExitCode) => {
|
|
9306
|
-
const child = (0,
|
|
9997
|
+
const child = (0, import_node_child_process.spawn)(command, args, {
|
|
9307
9998
|
stdio: "inherit",
|
|
9308
9999
|
shell: process.platform === "win32",
|
|
9309
10000
|
env: process.env
|
|
@@ -9376,10 +10067,10 @@ Examples:
|
|
|
9376
10067
|
}
|
|
9377
10068
|
|
|
9378
10069
|
// src/cli/skills-sync.ts
|
|
9379
|
-
var
|
|
9380
|
-
var
|
|
10070
|
+
var import_node_child_process2 = require("child_process");
|
|
10071
|
+
var import_node_fs12 = require("fs");
|
|
9381
10072
|
var import_node_os8 = require("os");
|
|
9382
|
-
var
|
|
10073
|
+
var import_node_path14 = require("path");
|
|
9383
10074
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
9384
10075
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
9385
10076
|
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
@@ -9390,23 +10081,59 @@ function shouldSkipSkillsSync() {
|
|
|
9390
10081
|
}
|
|
9391
10082
|
function sdkSkillsVersionPath(baseUrl) {
|
|
9392
10083
|
const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
|
|
9393
|
-
return (0,
|
|
10084
|
+
return (0, import_node_path14.join)(home, ".local", "deepline", baseUrlSlug(baseUrl), "sdk-skills", ".version");
|
|
9394
10085
|
}
|
|
9395
10086
|
function readLocalSkillsVersion(baseUrl) {
|
|
9396
10087
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
9397
|
-
if (!(0,
|
|
10088
|
+
if (!(0, import_node_fs12.existsSync)(path)) return "";
|
|
9398
10089
|
try {
|
|
9399
|
-
return (0,
|
|
10090
|
+
return (0, import_node_fs12.readFileSync)(path, "utf-8").trim();
|
|
9400
10091
|
} catch {
|
|
9401
10092
|
return "";
|
|
9402
10093
|
}
|
|
9403
10094
|
}
|
|
9404
10095
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
9405
10096
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
9406
|
-
(0,
|
|
9407
|
-
(0,
|
|
10097
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
|
|
10098
|
+
(0, import_node_fs12.writeFileSync)(path, `${version}
|
|
9408
10099
|
`, "utf-8");
|
|
9409
10100
|
}
|
|
10101
|
+
function installedSdkSkillHasStalePositionalExecuteExamples() {
|
|
10102
|
+
const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
|
|
10103
|
+
const roots = [
|
|
10104
|
+
(0, import_node_path14.join)(home, ".claude", "skills", SDK_SKILL_NAME),
|
|
10105
|
+
(0, import_node_path14.join)(home, ".agents", "skills", SDK_SKILL_NAME)
|
|
10106
|
+
];
|
|
10107
|
+
const staleMarkers = [
|
|
10108
|
+
"ctx.tools.execute(key",
|
|
10109
|
+
"ctx.tools.execute('",
|
|
10110
|
+
'ctx.tools.execute("',
|
|
10111
|
+
"rowCtx.tools.execute('",
|
|
10112
|
+
'rowCtx.tools.execute("'
|
|
10113
|
+
];
|
|
10114
|
+
const scan = (dir) => {
|
|
10115
|
+
for (const entry of (0, import_node_fs12.readdirSync)(dir)) {
|
|
10116
|
+
const path = (0, import_node_path14.join)(dir, entry);
|
|
10117
|
+
const stat3 = (0, import_node_fs12.statSync)(path);
|
|
10118
|
+
if (stat3.isDirectory()) {
|
|
10119
|
+
if (scan(path)) return true;
|
|
10120
|
+
continue;
|
|
10121
|
+
}
|
|
10122
|
+
if (!entry.endsWith(".md")) continue;
|
|
10123
|
+
const text = (0, import_node_fs12.readFileSync)(path, "utf-8");
|
|
10124
|
+
if (staleMarkers.some((marker) => text.includes(marker))) return true;
|
|
10125
|
+
}
|
|
10126
|
+
return false;
|
|
10127
|
+
};
|
|
10128
|
+
for (const root of roots) {
|
|
10129
|
+
try {
|
|
10130
|
+
if ((0, import_node_fs12.existsSync)(root) && scan(root)) return true;
|
|
10131
|
+
} catch {
|
|
10132
|
+
continue;
|
|
10133
|
+
}
|
|
10134
|
+
}
|
|
10135
|
+
return false;
|
|
10136
|
+
}
|
|
9410
10137
|
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
9411
10138
|
const controller = new AbortController();
|
|
9412
10139
|
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
@@ -9442,7 +10169,7 @@ function buildSkillsInstallArgs(baseUrl) {
|
|
|
9442
10169
|
"skills",
|
|
9443
10170
|
"add",
|
|
9444
10171
|
packageUrl,
|
|
9445
|
-
"--
|
|
10172
|
+
"--agent",
|
|
9446
10173
|
...SKILL_AGENTS,
|
|
9447
10174
|
"--global",
|
|
9448
10175
|
"--yes",
|
|
@@ -9458,7 +10185,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
|
|
|
9458
10185
|
"skills",
|
|
9459
10186
|
"add",
|
|
9460
10187
|
packageUrl,
|
|
9461
|
-
"--
|
|
10188
|
+
"--agent",
|
|
9462
10189
|
...SKILL_AGENTS,
|
|
9463
10190
|
"--global",
|
|
9464
10191
|
"--yes",
|
|
@@ -9468,7 +10195,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
|
|
|
9468
10195
|
];
|
|
9469
10196
|
}
|
|
9470
10197
|
function hasCommand(command) {
|
|
9471
|
-
const result = (0,
|
|
10198
|
+
const result = (0, import_node_child_process2.spawnSync)(command, ["--version"], {
|
|
9472
10199
|
stdio: "ignore",
|
|
9473
10200
|
shell: process.platform === "win32"
|
|
9474
10201
|
});
|
|
@@ -9498,8 +10225,8 @@ function resolveSkillsInstallCommands(baseUrl) {
|
|
|
9498
10225
|
return [npxInstall];
|
|
9499
10226
|
}
|
|
9500
10227
|
function runOneSkillsInstall(install) {
|
|
9501
|
-
return new Promise((
|
|
9502
|
-
const child = (0,
|
|
10228
|
+
return new Promise((resolve11) => {
|
|
10229
|
+
const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
|
|
9503
10230
|
stdio: ["ignore", "ignore", "pipe"],
|
|
9504
10231
|
env: process.env
|
|
9505
10232
|
});
|
|
@@ -9508,7 +10235,7 @@ function runOneSkillsInstall(install) {
|
|
|
9508
10235
|
stderr += chunk.toString("utf-8");
|
|
9509
10236
|
});
|
|
9510
10237
|
child.on("error", (error) => {
|
|
9511
|
-
|
|
10238
|
+
resolve11({
|
|
9512
10239
|
ok: false,
|
|
9513
10240
|
detail: `failed to start ${install.command}: ${error.message}`,
|
|
9514
10241
|
manualCommand: install.manualCommand
|
|
@@ -9516,11 +10243,11 @@ function runOneSkillsInstall(install) {
|
|
|
9516
10243
|
});
|
|
9517
10244
|
child.on("close", (code) => {
|
|
9518
10245
|
if (code === 0) {
|
|
9519
|
-
|
|
10246
|
+
resolve11({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
9520
10247
|
return;
|
|
9521
10248
|
}
|
|
9522
10249
|
const detail = stderr.trim();
|
|
9523
|
-
|
|
10250
|
+
resolve11({
|
|
9524
10251
|
ok: false,
|
|
9525
10252
|
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
9526
10253
|
manualCommand: install.manualCommand
|
|
@@ -9559,10 +10286,19 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
9559
10286
|
attemptedSync = true;
|
|
9560
10287
|
const localVersion = readLocalSkillsVersion(baseUrl);
|
|
9561
10288
|
const update = await fetchSkillsUpdate(baseUrl, localVersion);
|
|
9562
|
-
|
|
10289
|
+
const hasStaleInstalledSkill = installedSdkSkillHasStalePositionalExecuteExamples();
|
|
10290
|
+
if (!update?.needsUpdate && !hasStaleInstalledSkill || !update?.remoteVersion) {
|
|
10291
|
+
return;
|
|
10292
|
+
}
|
|
9563
10293
|
writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-sdk skill...");
|
|
9564
10294
|
const installed = await runSkillsInstall(baseUrl);
|
|
9565
10295
|
if (!installed) return;
|
|
10296
|
+
if (installedSdkSkillHasStalePositionalExecuteExamples()) {
|
|
10297
|
+
process.stderr.write(
|
|
10298
|
+
"SDK skills sync completed, but installed deepline-sdk docs still contain stale positional ctx.tools.execute examples.\n"
|
|
10299
|
+
);
|
|
10300
|
+
return;
|
|
10301
|
+
}
|
|
9566
10302
|
writeLocalSkillsVersion(baseUrl, update.remoteVersion);
|
|
9567
10303
|
writeSdkSkillsStatusLine("SDK skills are up to date.");
|
|
9568
10304
|
}
|