deepline 0.1.20 → 0.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +845 -337
- package/dist/cli/index.mjs +902 -389
- package/dist/index.d.mts +23 -58
- package/dist/index.d.ts +23 -58
- package/dist/index.js +195 -92
- package/dist/index.mjs +195 -92
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +888 -227
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +540 -36
- package/dist/repo/apps/play-runner-workers/src/entry.ts +477 -374
- package/dist/repo/sdk/src/client.ts +245 -118
- package/dist/repo/sdk/src/http.ts +19 -1
- package/dist/repo/sdk/src/plays/harness-stub.ts +12 -0
- package/dist/repo/sdk/src/types.ts +8 -14
- package/dist/repo/sdk/src/version.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/profiles.ts +4 -14
- package/dist/repo/shared_libs/play-runtime/runtime-actions.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +3 -6
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -243,7 +243,7 @@ function saveProjectDeeplineEnvValues(baseUrl, values, startDir = projectEnvStar
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
// src/version.ts
|
|
246
|
-
var SDK_VERSION = "0.1.
|
|
246
|
+
var SDK_VERSION = "0.1.22";
|
|
247
247
|
var SDK_API_CONTRACT = "2026-05-runs-v2";
|
|
248
248
|
|
|
249
249
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
@@ -326,7 +326,7 @@ var HttpClient = class {
|
|
|
326
326
|
const response = await fetch(candidateUrl, {
|
|
327
327
|
method,
|
|
328
328
|
headers,
|
|
329
|
-
body: options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
329
|
+
body: options?.formData !== void 0 ? options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
330
330
|
signal: controller.signal
|
|
331
331
|
});
|
|
332
332
|
clearTimeout(timeoutId);
|
|
@@ -445,6 +445,13 @@ var HttpClient = class {
|
|
|
445
445
|
headers
|
|
446
446
|
});
|
|
447
447
|
}
|
|
448
|
+
async postFormData(path, formData, headers) {
|
|
449
|
+
return this.request(path, {
|
|
450
|
+
method: "POST",
|
|
451
|
+
formData,
|
|
452
|
+
headers
|
|
453
|
+
});
|
|
454
|
+
}
|
|
448
455
|
/**
|
|
449
456
|
* Send a DELETE request.
|
|
450
457
|
*
|
|
@@ -528,7 +535,7 @@ function isRecord(value) {
|
|
|
528
535
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
529
536
|
}
|
|
530
537
|
function normalizePlayStatus(raw) {
|
|
531
|
-
const status = typeof raw.status === "string" ? raw.status :
|
|
538
|
+
const status = typeof raw.status === "string" ? raw.status : "running";
|
|
532
539
|
const runId = typeof raw.runId === "string" ? raw.runId : typeof raw.workflowId === "string" ? raw.workflowId : "";
|
|
533
540
|
return {
|
|
534
541
|
...raw,
|
|
@@ -536,22 +543,86 @@ function normalizePlayStatus(raw) {
|
|
|
536
543
|
status
|
|
537
544
|
};
|
|
538
545
|
}
|
|
539
|
-
function
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
546
|
+
function decodeBase64Bytes(value) {
|
|
547
|
+
const binary = atob(value);
|
|
548
|
+
const bytes = new Uint8Array(binary.length);
|
|
549
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
550
|
+
bytes[index] = binary.charCodeAt(index);
|
|
551
|
+
}
|
|
552
|
+
return bytes;
|
|
553
|
+
}
|
|
554
|
+
function readStringArray(value) {
|
|
555
|
+
return Array.isArray(value) ? value.filter((line) => typeof line === "string") : [];
|
|
556
|
+
}
|
|
557
|
+
function getPlayLiveEventPayload(event) {
|
|
558
|
+
return event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
559
|
+
}
|
|
560
|
+
function normalizeLiveStatus(value) {
|
|
561
|
+
if (value === "queued" || value === "running" || value === "waiting" || value === "completed" || value === "failed" || value === "cancelled") {
|
|
562
|
+
return value;
|
|
563
|
+
}
|
|
564
|
+
return null;
|
|
565
|
+
}
|
|
566
|
+
function updatePlayLiveStatusState(state, event) {
|
|
567
|
+
const payload = getPlayLiveEventPayload(event);
|
|
568
|
+
if (event.type === "play.run.log") {
|
|
569
|
+
state.logs.push(...readStringArray(payload.lines));
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
if (event.type !== "play.run.snapshot" && event.type !== "play.run.status" && event.type !== "play.run.final_status") {
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
const runId = typeof payload.runId === "string" && payload.runId ? payload.runId : state.runId;
|
|
576
|
+
const status = normalizeLiveStatus(payload.status) ?? state.status;
|
|
577
|
+
const logs = readStringArray(payload.logs);
|
|
578
|
+
if (logs.length > 0 || event.type === "play.run.snapshot") {
|
|
579
|
+
state.logs = logs;
|
|
580
|
+
}
|
|
581
|
+
if ("result" in payload) {
|
|
582
|
+
state.result = payload.result;
|
|
583
|
+
}
|
|
584
|
+
if (typeof payload.error === "string" && payload.error.trim()) {
|
|
585
|
+
state.error = payload.error;
|
|
554
586
|
}
|
|
587
|
+
state.runId = runId;
|
|
588
|
+
state.status = status;
|
|
589
|
+
const progressRecord = payload.progress && typeof payload.progress === "object" && !Array.isArray(payload.progress) ? payload.progress : {};
|
|
590
|
+
const next = {
|
|
591
|
+
...payload,
|
|
592
|
+
runId,
|
|
593
|
+
status,
|
|
594
|
+
progress: {
|
|
595
|
+
...progressRecord,
|
|
596
|
+
status: typeof progressRecord.status === "string" ? progressRecord.status : status,
|
|
597
|
+
logs: state.logs,
|
|
598
|
+
...state.error ? { error: state.error } : {}
|
|
599
|
+
},
|
|
600
|
+
..."result" in state ? { result: state.result } : {}
|
|
601
|
+
};
|
|
602
|
+
state.latest = next;
|
|
603
|
+
return next;
|
|
604
|
+
}
|
|
605
|
+
function playRunResultFromStatus(status, startedAt, fallbackRunId) {
|
|
606
|
+
return {
|
|
607
|
+
success: status.status === "completed",
|
|
608
|
+
runId: status.runId || fallbackRunId,
|
|
609
|
+
result: status.result,
|
|
610
|
+
logs: status.progress?.logs ?? [],
|
|
611
|
+
durationMs: Date.now() - startedAt,
|
|
612
|
+
error: status.progress?.error ?? (status.status !== "completed" ? status.status : void 0)
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
function playRunStatusFromState(state) {
|
|
616
|
+
return {
|
|
617
|
+
runId: state.runId,
|
|
618
|
+
status: state.status,
|
|
619
|
+
progress: {
|
|
620
|
+
status: state.status,
|
|
621
|
+
logs: state.logs,
|
|
622
|
+
...state.error ? { error: state.error } : {}
|
|
623
|
+
},
|
|
624
|
+
..."result" in state ? { result: state.result } : {}
|
|
625
|
+
};
|
|
555
626
|
}
|
|
556
627
|
var DeeplineClient = class {
|
|
557
628
|
http;
|
|
@@ -662,7 +733,7 @@ var DeeplineClient = class {
|
|
|
662
733
|
/**
|
|
663
734
|
* Search available tools using Deepline's ranked backend search.
|
|
664
735
|
*
|
|
665
|
-
* This is the same discovery surface used by the
|
|
736
|
+
* This is the same discovery surface used by the CLI: it ranks across
|
|
666
737
|
* tool metadata, categories, agent guidance, and input schema fields.
|
|
667
738
|
*/
|
|
668
739
|
async searchTools(options = {}) {
|
|
@@ -755,7 +826,7 @@ var DeeplineClient = class {
|
|
|
755
826
|
* `progress.logs`; they are not part of the user output object.
|
|
756
827
|
*
|
|
757
828
|
* @param request - Play run configuration (name, code, input, etc.)
|
|
758
|
-
* @returns
|
|
829
|
+
* @returns Run metadata including the public `workflowId`
|
|
759
830
|
*
|
|
760
831
|
* @example
|
|
761
832
|
* ```typescript
|
|
@@ -1004,9 +1075,34 @@ var DeeplineClient = class {
|
|
|
1004
1075
|
* ```
|
|
1005
1076
|
*/
|
|
1006
1077
|
async stagePlayFiles(files) {
|
|
1007
|
-
const
|
|
1078
|
+
const formData = new FormData();
|
|
1079
|
+
formData.set(
|
|
1080
|
+
"metadata",
|
|
1081
|
+
JSON.stringify({
|
|
1082
|
+
files: files.map((file, index) => ({
|
|
1083
|
+
index,
|
|
1084
|
+
logicalPath: file.logicalPath,
|
|
1085
|
+
contentHash: file.contentHash,
|
|
1086
|
+
contentType: file.contentType,
|
|
1087
|
+
bytes: file.bytes
|
|
1088
|
+
}))
|
|
1089
|
+
})
|
|
1090
|
+
);
|
|
1091
|
+
for (const [index, file] of files.entries()) {
|
|
1092
|
+
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1093
|
+
const body = bytes.buffer.slice(
|
|
1094
|
+
bytes.byteOffset,
|
|
1095
|
+
bytes.byteOffset + bytes.byteLength
|
|
1096
|
+
);
|
|
1097
|
+
formData.set(
|
|
1098
|
+
`file:${index}`,
|
|
1099
|
+
new Blob([body], { type: file.contentType }),
|
|
1100
|
+
file.logicalPath
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
const response = await this.http.postFormData(
|
|
1008
1104
|
"/api/v2/plays/files/stage",
|
|
1009
|
-
|
|
1105
|
+
formData
|
|
1010
1106
|
);
|
|
1011
1107
|
return response.files;
|
|
1012
1108
|
}
|
|
@@ -1022,9 +1118,6 @@ var DeeplineClient = class {
|
|
|
1022
1118
|
* Internal/advanced primitive. Public callers should usually prefer
|
|
1023
1119
|
* {@link runPlay}, {@link PlayJob.get}, or `deepline play run --watch`.
|
|
1024
1120
|
*
|
|
1025
|
-
* Poll this method until `status` reaches a terminal state:
|
|
1026
|
-
* `'completed'`, `'failed'`, or `'cancelled'`.
|
|
1027
|
-
*
|
|
1028
1121
|
* @param workflowId - Play-run id from {@link startPlayRun}
|
|
1029
1122
|
* @returns Current status with progress logs and partial results
|
|
1030
1123
|
*
|
|
@@ -1035,41 +1128,22 @@ var DeeplineClient = class {
|
|
|
1035
1128
|
* console.log(`Logs: ${status.progress?.logs.length ?? 0} lines`);
|
|
1036
1129
|
* ```
|
|
1037
1130
|
*/
|
|
1038
|
-
async getPlayStatus(workflowId) {
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
return normalizePlayStatus(response);
|
|
1043
|
-
}
|
|
1044
|
-
/**
|
|
1045
|
-
* Get the lightweight tail-polling status for a play execution.
|
|
1046
|
-
*
|
|
1047
|
-
* This is intentionally smaller than {@link getPlayStatus}: it returns the
|
|
1048
|
-
* fields needed for CLI log tailing while the run is in flight, without
|
|
1049
|
-
* forcing the API to rebuild final result views on every poll. Call
|
|
1050
|
-
* {@link getPlayStatus} once after a terminal state for the full result.
|
|
1051
|
-
*/
|
|
1052
|
-
async getPlayTailStatus(workflowId, options) {
|
|
1053
|
-
const params = new URLSearchParams({ mode: "tail" });
|
|
1054
|
-
if (typeof options?.afterLogIndex === "number") {
|
|
1055
|
-
params.set("afterLogIndex", String(options.afterLogIndex));
|
|
1056
|
-
}
|
|
1057
|
-
if (typeof options?.waitMs === "number") {
|
|
1058
|
-
params.set("waitMs", String(options.waitMs));
|
|
1059
|
-
}
|
|
1060
|
-
if (options?.terminalOnly) {
|
|
1061
|
-
params.set("terminalOnly", "true");
|
|
1131
|
+
async getPlayStatus(workflowId, options) {
|
|
1132
|
+
const params = new URLSearchParams();
|
|
1133
|
+
if (options?.billing === false) {
|
|
1134
|
+
params.set("billing", "false");
|
|
1062
1135
|
}
|
|
1136
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
1063
1137
|
const response = await this.http.get(
|
|
1064
|
-
`/api/v2/plays/run/${encodeURIComponent(workflowId)}
|
|
1138
|
+
`/api/v2/plays/run/${encodeURIComponent(workflowId)}${query}`
|
|
1065
1139
|
);
|
|
1066
1140
|
return normalizePlayStatus(response);
|
|
1067
1141
|
}
|
|
1068
1142
|
/**
|
|
1069
1143
|
* Stream semantic play-run events using the same SSE feed as the dashboard.
|
|
1070
1144
|
*
|
|
1071
|
-
*
|
|
1072
|
-
*
|
|
1145
|
+
* The server emits a canonical `play.run.snapshot` event first for every
|
|
1146
|
+
* connection, then incremental live events until terminal state or reconnect.
|
|
1073
1147
|
*/
|
|
1074
1148
|
async *streamPlayRunEvents(workflowId, options) {
|
|
1075
1149
|
const headers = options?.lastEventId && options.lastEventId.trim() ? { "Last-Event-ID": options.lastEventId.trim() } : void 0;
|
|
@@ -1089,7 +1163,7 @@ var DeeplineClient = class {
|
|
|
1089
1163
|
*
|
|
1090
1164
|
* Sends a stop request for the run.
|
|
1091
1165
|
*
|
|
1092
|
-
* @param workflowId -
|
|
1166
|
+
* @param workflowId - Public Deepline play-run id to cancel
|
|
1093
1167
|
*
|
|
1094
1168
|
* @example
|
|
1095
1169
|
* ```typescript
|
|
@@ -1105,7 +1179,7 @@ var DeeplineClient = class {
|
|
|
1105
1179
|
/**
|
|
1106
1180
|
* Stop a running play execution, including open HITL waits.
|
|
1107
1181
|
*
|
|
1108
|
-
* @param workflowId -
|
|
1182
|
+
* @param workflowId - Public Deepline play-run id to stop
|
|
1109
1183
|
* @param options.reason - Optional audit/debug reason
|
|
1110
1184
|
*/
|
|
1111
1185
|
async stopPlay(workflowId, options) {
|
|
@@ -1177,32 +1251,42 @@ var DeeplineClient = class {
|
|
|
1177
1251
|
);
|
|
1178
1252
|
return response.runs ?? [];
|
|
1179
1253
|
}
|
|
1180
|
-
/**
|
|
1181
|
-
* Fetch the lightweight tail status for a run using the public runs resource model.
|
|
1182
|
-
*
|
|
1183
|
-
* This is the SDK equivalent of:
|
|
1184
|
-
*
|
|
1185
|
-
* ```bash
|
|
1186
|
-
* deepline runs tail <run-id> --json
|
|
1187
|
-
* ```
|
|
1188
|
-
*/
|
|
1254
|
+
/** Read the canonical run stream and return the latest run snapshot. */
|
|
1189
1255
|
async tailRun(runId, options) {
|
|
1190
|
-
const
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1256
|
+
const state = {
|
|
1257
|
+
runId,
|
|
1258
|
+
status: "running",
|
|
1259
|
+
logs: [],
|
|
1260
|
+
latest: null
|
|
1261
|
+
};
|
|
1262
|
+
let terminal = false;
|
|
1263
|
+
for await (const event of this.streamPlayRunEvents(runId, {
|
|
1264
|
+
mode: "cli",
|
|
1265
|
+
signal: options?.signal
|
|
1266
|
+
})) {
|
|
1267
|
+
const status = updatePlayLiveStatusState(state, event);
|
|
1268
|
+
if (!status) {
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
terminal = TERMINAL_PLAY_STATUSES.has(status.status);
|
|
1272
|
+
if (terminal) {
|
|
1273
|
+
break;
|
|
1274
|
+
}
|
|
1194
1275
|
}
|
|
1195
|
-
if (
|
|
1196
|
-
|
|
1276
|
+
if (terminal && state.latest) {
|
|
1277
|
+
return await this.getRunStatus(state.latest.runId || runId).catch(
|
|
1278
|
+
() => state.latest ?? playRunStatusFromState(state)
|
|
1279
|
+
);
|
|
1197
1280
|
}
|
|
1198
|
-
if (
|
|
1199
|
-
|
|
1281
|
+
if (state.latest) {
|
|
1282
|
+
return state.latest;
|
|
1200
1283
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1284
|
+
throw new DeeplineError(
|
|
1285
|
+
`Run stream for ${runId} ended before the initial snapshot.`,
|
|
1286
|
+
void 0,
|
|
1287
|
+
"PLAY_RUN_STREAM_EMPTY",
|
|
1288
|
+
{ runId }
|
|
1204
1289
|
);
|
|
1205
|
-
return normalizePlayStatus(response);
|
|
1206
1290
|
}
|
|
1207
1291
|
/**
|
|
1208
1292
|
* Fetch persisted logs for a run using the public runs resource model.
|
|
@@ -1359,11 +1443,11 @@ var DeeplineClient = class {
|
|
|
1359
1443
|
// Plays — high-level orchestration
|
|
1360
1444
|
// ——————————————————————————————————————————————————————————
|
|
1361
1445
|
/**
|
|
1362
|
-
* Run a play end-to-end: submit,
|
|
1446
|
+
* Run a play end-to-end: submit, stream until terminal, return result.
|
|
1363
1447
|
*
|
|
1364
1448
|
* This is the highest-level play execution method. It submits the play,
|
|
1365
|
-
*
|
|
1366
|
-
* and timing. Supports cancellation via `AbortSignal`.
|
|
1449
|
+
* reads the canonical run stream for status updates, and returns a structured
|
|
1450
|
+
* result with logs and timing. Supports cancellation via `AbortSignal`.
|
|
1367
1451
|
*
|
|
1368
1452
|
* @param code - Source string fallback; pass the bundled artifact in `options.artifact`
|
|
1369
1453
|
* @param csvPath - Input CSV path, or `null`
|
|
@@ -1379,7 +1463,6 @@ var DeeplineClient = class {
|
|
|
1379
1463
|
* const logs = status.progress?.logs ?? [];
|
|
1380
1464
|
* console.log(`[${status.status}] ${logs.length} log lines`);
|
|
1381
1465
|
* },
|
|
1382
|
-
* pollIntervalMs: 1000,
|
|
1383
1466
|
* });
|
|
1384
1467
|
*
|
|
1385
1468
|
* if (result.success) {
|
|
@@ -1410,33 +1493,53 @@ var DeeplineClient = class {
|
|
|
1410
1493
|
packagedFiles: options?.packagedFiles,
|
|
1411
1494
|
force: options?.force
|
|
1412
1495
|
});
|
|
1413
|
-
const pollInterval = options?.pollIntervalMs ?? 500;
|
|
1414
1496
|
const start = Date.now();
|
|
1415
|
-
|
|
1497
|
+
const state = {
|
|
1498
|
+
runId: workflowId,
|
|
1499
|
+
status: "running",
|
|
1500
|
+
logs: [],
|
|
1501
|
+
latest: null
|
|
1502
|
+
};
|
|
1503
|
+
if (options?.signal?.aborted) {
|
|
1504
|
+
await this.cancelPlay(workflowId);
|
|
1505
|
+
return {
|
|
1506
|
+
success: false,
|
|
1507
|
+
runId: workflowId,
|
|
1508
|
+
logs: [],
|
|
1509
|
+
durationMs: Date.now() - start,
|
|
1510
|
+
error: "Cancelled by user"
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
for await (const event of this.streamPlayRunEvents(workflowId, {
|
|
1514
|
+
mode: "cli",
|
|
1515
|
+
signal: options?.signal
|
|
1516
|
+
})) {
|
|
1416
1517
|
if (options?.signal?.aborted) {
|
|
1417
1518
|
await this.cancelPlay(workflowId);
|
|
1418
1519
|
return {
|
|
1419
1520
|
success: false,
|
|
1420
1521
|
runId: workflowId,
|
|
1421
|
-
logs:
|
|
1522
|
+
logs: state.logs,
|
|
1422
1523
|
durationMs: Date.now() - start,
|
|
1423
1524
|
error: "Cancelled by user"
|
|
1424
1525
|
};
|
|
1425
1526
|
}
|
|
1426
|
-
const status =
|
|
1527
|
+
const status = updatePlayLiveStatusState(state, event);
|
|
1528
|
+
if (!status) {
|
|
1529
|
+
continue;
|
|
1530
|
+
}
|
|
1427
1531
|
options?.onProgress?.(status);
|
|
1428
1532
|
if (TERMINAL_PLAY_STATUSES.has(status.status)) {
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
runId: status.runId || workflowId,
|
|
1432
|
-
result: status.result,
|
|
1433
|
-
logs: status.progress?.logs ?? [],
|
|
1434
|
-
durationMs: Date.now() - start,
|
|
1435
|
-
error: status.progress?.error ?? (status.status !== "completed" ? status.status : void 0)
|
|
1436
|
-
};
|
|
1533
|
+
const finalStatus = await this.getPlayStatus(status.runId || workflowId).catch(() => status);
|
|
1534
|
+
return playRunResultFromStatus(finalStatus, start, workflowId);
|
|
1437
1535
|
}
|
|
1438
|
-
await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
|
|
1439
1536
|
}
|
|
1537
|
+
throw new DeeplineError(
|
|
1538
|
+
`Run stream for ${workflowId} ended before the run reached a terminal state.`,
|
|
1539
|
+
void 0,
|
|
1540
|
+
"PLAY_RUN_STREAM_ENDED",
|
|
1541
|
+
{ runId: workflowId, workflowId }
|
|
1542
|
+
);
|
|
1440
1543
|
}
|
|
1441
1544
|
// ——————————————————————————————————————————————————————————
|
|
1442
1545
|
// Health
|
|
@@ -1510,18 +1613,24 @@ async function enforceSdkCompatibility(baseUrl) {
|
|
|
1510
1613
|
}
|
|
1511
1614
|
|
|
1512
1615
|
// src/cli/commands/auth.ts
|
|
1513
|
-
import { writeFileSync as
|
|
1616
|
+
import { writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
1514
1617
|
import { hostname } from "os";
|
|
1515
|
-
import { dirname as
|
|
1618
|
+
import { dirname as dirname3 } from "path";
|
|
1516
1619
|
|
|
1517
1620
|
// src/cli/utils.ts
|
|
1518
|
-
import {
|
|
1621
|
+
import {
|
|
1622
|
+
existsSync as existsSync2,
|
|
1623
|
+
mkdirSync as mkdirSync2,
|
|
1624
|
+
readFileSync as readFileSync2,
|
|
1625
|
+
writeFileSync as writeFileSync2
|
|
1626
|
+
} from "fs";
|
|
1519
1627
|
import { mkdir, writeFile } from "fs/promises";
|
|
1520
1628
|
import { homedir as homedir2 } from "os";
|
|
1521
|
-
import { join as join2, resolve as resolve2 } from "path";
|
|
1522
|
-
import {
|
|
1629
|
+
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
1630
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
1523
1631
|
import { parse } from "csv-parse/sync";
|
|
1524
1632
|
import { stringify } from "csv-stringify/sync";
|
|
1633
|
+
var BROWSER_FOCUS_COOLDOWN_MS = 3e4;
|
|
1525
1634
|
function getAuthedHttpClient() {
|
|
1526
1635
|
const config = resolveConfig();
|
|
1527
1636
|
return { config, http: new HttpClient(config) };
|
|
@@ -1533,12 +1642,215 @@ async function writeOutputFile(filename, content) {
|
|
|
1533
1642
|
await writeFile(fullPath, content, "utf-8");
|
|
1534
1643
|
return fullPath;
|
|
1535
1644
|
}
|
|
1645
|
+
function browserFocusStateFile() {
|
|
1646
|
+
const homeDir = process.env.HOME || homedir2();
|
|
1647
|
+
return join2(
|
|
1648
|
+
homeDir,
|
|
1649
|
+
".local",
|
|
1650
|
+
"deepline",
|
|
1651
|
+
"runtime",
|
|
1652
|
+
"state",
|
|
1653
|
+
"browser-focus.json"
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
function claimBrowserFocus(now = Date.now()) {
|
|
1657
|
+
const statePath = browserFocusStateFile();
|
|
1658
|
+
try {
|
|
1659
|
+
mkdirSync2(dirname2(statePath), { recursive: true });
|
|
1660
|
+
let lastFocusedAt = 0;
|
|
1661
|
+
if (existsSync2(statePath)) {
|
|
1662
|
+
const payload = JSON.parse(readFileSync2(statePath, "utf-8"));
|
|
1663
|
+
const value = payload.lastFocusedAt ?? payload.last_focused_at;
|
|
1664
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1665
|
+
lastFocusedAt = value;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
if (lastFocusedAt > now) {
|
|
1669
|
+
lastFocusedAt = 0;
|
|
1670
|
+
}
|
|
1671
|
+
if (now - lastFocusedAt < BROWSER_FOCUS_COOLDOWN_MS) {
|
|
1672
|
+
return false;
|
|
1673
|
+
}
|
|
1674
|
+
writeFileSync2(statePath, JSON.stringify({ lastFocusedAt: now }), "utf-8");
|
|
1675
|
+
return true;
|
|
1676
|
+
} catch {
|
|
1677
|
+
return true;
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
function extractUrlHost(raw) {
|
|
1681
|
+
try {
|
|
1682
|
+
const parsed = new URL(raw.includes("://") ? raw : `https://${raw}`);
|
|
1683
|
+
return parsed.port ? `${parsed.hostname.toLowerCase()}:${parsed.port}` : parsed.hostname.toLowerCase();
|
|
1684
|
+
} catch {
|
|
1685
|
+
return "";
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
function browserAppNameFromBundleId(bundleId) {
|
|
1689
|
+
const names = {
|
|
1690
|
+
"com.google.chrome": "Google Chrome",
|
|
1691
|
+
"com.google.chrome.canary": "Google Chrome Canary",
|
|
1692
|
+
"com.microsoft.edgemac": "Microsoft Edge",
|
|
1693
|
+
"com.brave.browser": "Brave Browser",
|
|
1694
|
+
"com.operasoftware.opera": "Opera",
|
|
1695
|
+
"com.operasoftware.operagx": "Opera GX",
|
|
1696
|
+
"com.vivaldi.vivaldi": "Vivaldi",
|
|
1697
|
+
"company.thebrowser.browser": "Arc",
|
|
1698
|
+
"com.apple.safari": "Safari"
|
|
1699
|
+
};
|
|
1700
|
+
return names[bundleId.toLowerCase()] ?? "";
|
|
1701
|
+
}
|
|
1702
|
+
function readDefaultMacBrowserBundleId() {
|
|
1703
|
+
try {
|
|
1704
|
+
const output = execFileSync(
|
|
1705
|
+
"/usr/bin/defaults",
|
|
1706
|
+
[
|
|
1707
|
+
"read",
|
|
1708
|
+
`${homedir2()}/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist`,
|
|
1709
|
+
"LSHandlers"
|
|
1710
|
+
],
|
|
1711
|
+
{ encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
1712
|
+
);
|
|
1713
|
+
const httpsMatch = output.match(
|
|
1714
|
+
/LSHandlerURLScheme\s*=\s*https;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1715
|
+
);
|
|
1716
|
+
const httpMatch = output.match(
|
|
1717
|
+
/LSHandlerURLScheme\s*=\s*http;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1718
|
+
);
|
|
1719
|
+
return (httpsMatch?.[1] ?? httpMatch?.[1] ?? "").trim();
|
|
1720
|
+
} catch {
|
|
1721
|
+
return "";
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
function browserStrategyForBundleId(bundleId) {
|
|
1725
|
+
const normalized = bundleId.toLowerCase();
|
|
1726
|
+
if ((/* @__PURE__ */ new Set([
|
|
1727
|
+
"com.google.chrome",
|
|
1728
|
+
"com.google.chrome.canary",
|
|
1729
|
+
"com.microsoft.edgemac",
|
|
1730
|
+
"com.brave.browser",
|
|
1731
|
+
"com.operasoftware.opera",
|
|
1732
|
+
"com.operasoftware.operagx",
|
|
1733
|
+
"com.vivaldi.vivaldi",
|
|
1734
|
+
"company.thebrowser.browser"
|
|
1735
|
+
])).has(normalized)) {
|
|
1736
|
+
return "chromium";
|
|
1737
|
+
}
|
|
1738
|
+
return normalized === "com.apple.safari" ? "safari" : "fallback";
|
|
1739
|
+
}
|
|
1740
|
+
function runAppleScript(script, args) {
|
|
1741
|
+
const result = spawnSync("osascript", ["-", ...args], {
|
|
1742
|
+
input: script,
|
|
1743
|
+
encoding: "utf-8",
|
|
1744
|
+
stdio: ["pipe", "ignore", "ignore"],
|
|
1745
|
+
timeout: 5e3
|
|
1746
|
+
});
|
|
1747
|
+
return result.status === 0;
|
|
1748
|
+
}
|
|
1749
|
+
function retargetChromiumMacos(appName, targetUrl, allowFocus) {
|
|
1750
|
+
const host = extractUrlHost(targetUrl);
|
|
1751
|
+
if (!host) return false;
|
|
1752
|
+
const escapedAppName = appName.replace(/"/g, '\\"');
|
|
1753
|
+
const activateBlock = allowFocus ? " activate\n" : "";
|
|
1754
|
+
const foundTabBlock = allowFocus ? " set active tab index of w to i\n set index of w to 1\n set URL of t to targetUrl\n" : " set URL of t to targetUrl\n";
|
|
1755
|
+
const newTabBlock = allowFocus ? " tell window 1\n make new tab with properties {URL:targetUrl}\n set active tab index to (count of tabs)\n set index to 1\n end tell\n" : " tell window 1\n make new tab with properties {URL:targetUrl}\n end tell\n";
|
|
1756
|
+
const script = `
|
|
1757
|
+
on run argv
|
|
1758
|
+
set targetUrl to item 1 of argv
|
|
1759
|
+
set targetHost to item 2 of argv
|
|
1760
|
+
tell application "${escapedAppName}"
|
|
1761
|
+
${activateBlock} if (count of windows) is 0 then
|
|
1762
|
+
make new window
|
|
1763
|
+
end if
|
|
1764
|
+
set foundTab to false
|
|
1765
|
+
repeat with w in windows
|
|
1766
|
+
set tabCount to count of tabs of w
|
|
1767
|
+
repeat with i from 1 to tabCount
|
|
1768
|
+
set t to tab i of w
|
|
1769
|
+
if (URL of t) contains targetHost then
|
|
1770
|
+
${foundTabBlock} set foundTab to true
|
|
1771
|
+
exit repeat
|
|
1772
|
+
end if
|
|
1773
|
+
end repeat
|
|
1774
|
+
if foundTab then exit repeat
|
|
1775
|
+
end repeat
|
|
1776
|
+
if not foundTab then
|
|
1777
|
+
${newTabBlock} end if
|
|
1778
|
+
end tell
|
|
1779
|
+
end run
|
|
1780
|
+
`;
|
|
1781
|
+
return runAppleScript(script, [targetUrl, host]);
|
|
1782
|
+
}
|
|
1783
|
+
function retargetSafariMacos(appName, targetUrl, allowFocus) {
|
|
1784
|
+
const host = extractUrlHost(targetUrl);
|
|
1785
|
+
if (!host) return false;
|
|
1786
|
+
const escapedAppName = appName.replace(/"/g, '\\"');
|
|
1787
|
+
const activateBlock = allowFocus ? " activate\n" : "";
|
|
1788
|
+
const foundTabBlock = allowFocus ? " set current tab of w to t\n set index of w to 1\n set URL of t to targetUrl\n" : " set URL of t to targetUrl\n";
|
|
1789
|
+
const newTabBlock = allowFocus ? " tell window 1\n set current tab to (make new tab with properties {URL:targetUrl})\n set index to 1\n end tell\n" : " tell window 1\n make new tab with properties {URL:targetUrl}\n end tell\n";
|
|
1790
|
+
const script = `
|
|
1791
|
+
on run argv
|
|
1792
|
+
set targetUrl to item 1 of argv
|
|
1793
|
+
set targetHost to item 2 of argv
|
|
1794
|
+
tell application "${escapedAppName}"
|
|
1795
|
+
${activateBlock} if (count of windows) is 0 then
|
|
1796
|
+
make new document
|
|
1797
|
+
end if
|
|
1798
|
+
set foundTab to false
|
|
1799
|
+
repeat with w in windows
|
|
1800
|
+
set tabCount to count of tabs of w
|
|
1801
|
+
repeat with i from 1 to tabCount
|
|
1802
|
+
set t to tab i of w
|
|
1803
|
+
if (URL of t) contains targetHost then
|
|
1804
|
+
${foundTabBlock} set foundTab to true
|
|
1805
|
+
exit repeat
|
|
1806
|
+
end if
|
|
1807
|
+
end repeat
|
|
1808
|
+
if foundTab then exit repeat
|
|
1809
|
+
end repeat
|
|
1810
|
+
if not foundTab then
|
|
1811
|
+
${newTabBlock} end if
|
|
1812
|
+
end tell
|
|
1813
|
+
end run
|
|
1814
|
+
`;
|
|
1815
|
+
return runAppleScript(script, [targetUrl, host]);
|
|
1816
|
+
}
|
|
1817
|
+
function openUrlMacos(targetUrl, allowFocus) {
|
|
1818
|
+
const defaultBundleId = readDefaultMacBrowserBundleId();
|
|
1819
|
+
const appName = defaultBundleId ? browserAppNameFromBundleId(defaultBundleId) : "";
|
|
1820
|
+
const strategy = browserStrategyForBundleId(defaultBundleId);
|
|
1821
|
+
if (appName && strategy === "chromium" && retargetChromiumMacos(appName, targetUrl, allowFocus)) {
|
|
1822
|
+
return true;
|
|
1823
|
+
}
|
|
1824
|
+
if (appName && strategy === "safari" && retargetSafariMacos(appName, targetUrl, allowFocus)) {
|
|
1825
|
+
return true;
|
|
1826
|
+
}
|
|
1827
|
+
if (!allowFocus) {
|
|
1828
|
+
return false;
|
|
1829
|
+
}
|
|
1830
|
+
try {
|
|
1831
|
+
execFileSync("open", [targetUrl], { stdio: "ignore" });
|
|
1832
|
+
return true;
|
|
1833
|
+
} catch {
|
|
1834
|
+
return false;
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1536
1837
|
function openInBrowser(url) {
|
|
1537
1838
|
try {
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1839
|
+
const targetUrl = String(url || "").trim();
|
|
1840
|
+
if (!targetUrl) return;
|
|
1841
|
+
const allowFocus = claimBrowserFocus();
|
|
1842
|
+
if (process.platform === "darwin") {
|
|
1843
|
+
openUrlMacos(targetUrl, allowFocus);
|
|
1844
|
+
return;
|
|
1845
|
+
}
|
|
1846
|
+
if (!allowFocus) return;
|
|
1847
|
+
if (process.platform === "win32") {
|
|
1848
|
+
execFileSync("cmd.exe", ["/c", "start", "", targetUrl], {
|
|
1849
|
+
stdio: "ignore"
|
|
1850
|
+
});
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
execFileSync("xdg-open", [targetUrl], { stdio: "ignore" });
|
|
1542
1854
|
} catch {
|
|
1543
1855
|
}
|
|
1544
1856
|
}
|
|
@@ -1622,14 +1934,14 @@ function envFilePath(baseUrl) {
|
|
|
1622
1934
|
}
|
|
1623
1935
|
function saveEnvValues(values, baseUrl) {
|
|
1624
1936
|
const filePath = envFilePath(baseUrl);
|
|
1625
|
-
const dir =
|
|
1626
|
-
if (!
|
|
1627
|
-
|
|
1937
|
+
const dir = dirname3(filePath);
|
|
1938
|
+
if (!existsSync3(dir)) {
|
|
1939
|
+
mkdirSync3(dir, { recursive: true });
|
|
1628
1940
|
}
|
|
1629
|
-
const existing =
|
|
1941
|
+
const existing = existsSync3(filePath) ? parseEnvFile(filePath) : {};
|
|
1630
1942
|
const merged = { ...existing, ...values };
|
|
1631
1943
|
const lines = Object.entries(merged).filter(([, v]) => v !== "").map(([k, v]) => `${k}=${v}`);
|
|
1632
|
-
|
|
1944
|
+
writeFileSync3(filePath, lines.join("\n") + "\n", "utf-8");
|
|
1633
1945
|
saveProjectDeeplineEnvValues(baseUrl, values);
|
|
1634
1946
|
}
|
|
1635
1947
|
async function httpJson(method, url, apiKey, body) {
|
|
@@ -2168,7 +2480,7 @@ function registerBillingCommands(program) {
|
|
|
2168
2480
|
}
|
|
2169
2481
|
|
|
2170
2482
|
// src/cli/dataset-stats.ts
|
|
2171
|
-
import { writeFileSync as
|
|
2483
|
+
import { writeFileSync as writeFileSync4 } from "fs";
|
|
2172
2484
|
import { resolve as resolve3 } from "path";
|
|
2173
2485
|
var CSV_PROJECTED_FIELDS_KEY = "__deeplineCsvProjectedFields";
|
|
2174
2486
|
function csvProjectedFields(row) {
|
|
@@ -2500,7 +2812,7 @@ function writeCanonicalRowsCsv(rowsInfo, outPath) {
|
|
|
2500
2812
|
columns: rowsInfo.columns
|
|
2501
2813
|
});
|
|
2502
2814
|
const resolved = resolve3(outPath);
|
|
2503
|
-
|
|
2815
|
+
writeFileSync4(
|
|
2504
2816
|
resolved,
|
|
2505
2817
|
csvStringFromRows(sanitized.rows, sanitized.columns),
|
|
2506
2818
|
"utf-8"
|
|
@@ -2793,25 +3105,25 @@ function registerOrgCommands(program) {
|
|
|
2793
3105
|
// src/cli/commands/play.ts
|
|
2794
3106
|
import { createHash as createHash3 } from "crypto";
|
|
2795
3107
|
import {
|
|
2796
|
-
existsSync as
|
|
3108
|
+
existsSync as existsSync5,
|
|
2797
3109
|
readFileSync as readFileSync3,
|
|
2798
3110
|
readdirSync,
|
|
2799
3111
|
realpathSync,
|
|
2800
|
-
writeFileSync as
|
|
3112
|
+
writeFileSync as writeFileSync5
|
|
2801
3113
|
} from "fs";
|
|
2802
|
-
import { basename as basename3, dirname as
|
|
3114
|
+
import { basename as basename3, dirname as dirname7, join as join6, resolve as resolve7 } from "path";
|
|
2803
3115
|
|
|
2804
3116
|
// src/plays/bundle-play-file.ts
|
|
2805
3117
|
import { tmpdir as tmpdir2 } from "os";
|
|
2806
|
-
import { dirname as
|
|
3118
|
+
import { dirname as dirname6, join as join5, resolve as resolve6 } from "path";
|
|
2807
3119
|
import { fileURLToPath } from "url";
|
|
2808
|
-
import { existsSync as
|
|
3120
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2809
3121
|
|
|
2810
3122
|
// ../shared_libs/plays/bundling/index.ts
|
|
2811
3123
|
import { createHash } from "crypto";
|
|
2812
3124
|
import { mkdir as mkdir2, readFile, realpath, stat, writeFile as writeFile2 } from "fs/promises";
|
|
2813
3125
|
import { tmpdir } from "os";
|
|
2814
|
-
import { basename, dirname as
|
|
3126
|
+
import { basename, dirname as dirname4, extname, isAbsolute, join as join3, resolve as resolve4 } from "path";
|
|
2815
3127
|
import { builtinModules, createRequire } from "module";
|
|
2816
3128
|
import { build } from "esbuild";
|
|
2817
3129
|
|
|
@@ -2910,7 +3222,7 @@ async function normalizeLocalPath(filePath) {
|
|
|
2910
3222
|
function createPlayWorkspace(entryFile) {
|
|
2911
3223
|
return {
|
|
2912
3224
|
entryFile,
|
|
2913
|
-
rootDir:
|
|
3225
|
+
rootDir: dirname4(entryFile)
|
|
2914
3226
|
};
|
|
2915
3227
|
}
|
|
2916
3228
|
function isPathInsideDirectory(filePath, directory) {
|
|
@@ -3111,7 +3423,7 @@ function workersNamedPlayEntryAliasPlugin(playFilePath, exportName) {
|
|
|
3111
3423
|
contents: `export { ${exportName} as default } from ${JSON.stringify(playFilePath)};
|
|
3112
3424
|
`,
|
|
3113
3425
|
loader: "ts",
|
|
3114
|
-
resolveDir:
|
|
3426
|
+
resolveDir: dirname4(playFilePath)
|
|
3115
3427
|
})
|
|
3116
3428
|
);
|
|
3117
3429
|
}
|
|
@@ -3275,7 +3587,7 @@ function importedPlayProxyPlugin(importedPlayDependencies) {
|
|
|
3275
3587
|
return {
|
|
3276
3588
|
contents: buildImportedPlayProxyModule(dependency.playName),
|
|
3277
3589
|
loader: "ts",
|
|
3278
|
-
resolveDir:
|
|
3590
|
+
resolveDir: dirname4(args.path)
|
|
3279
3591
|
};
|
|
3280
3592
|
});
|
|
3281
3593
|
}
|
|
@@ -3293,7 +3605,7 @@ async function resolveLocalImport(fromFile, specifier) {
|
|
|
3293
3605
|
if (specifier.startsWith("file:")) {
|
|
3294
3606
|
return normalizeLocalPath(new URL(specifier).pathname);
|
|
3295
3607
|
}
|
|
3296
|
-
const base = isAbsolute(specifier) ? resolve4(specifier) : resolve4(
|
|
3608
|
+
const base = isAbsolute(specifier) ? resolve4(specifier) : resolve4(dirname4(fromFile), specifier);
|
|
3297
3609
|
const candidates = [base];
|
|
3298
3610
|
const explicitExtension = extname(base).toLowerCase();
|
|
3299
3611
|
if (!explicitExtension) {
|
|
@@ -3543,7 +3855,7 @@ async function runEsbuildForCjsNode(entryFile, importedPlayDependencies, adapter
|
|
|
3543
3855
|
...namedExportShim ? {
|
|
3544
3856
|
stdin: {
|
|
3545
3857
|
contents: namedExportShim,
|
|
3546
|
-
resolveDir:
|
|
3858
|
+
resolveDir: dirname4(entryFile),
|
|
3547
3859
|
sourcefile: `${basename(entryFile)}.${exportName}.entry.ts`,
|
|
3548
3860
|
loader: "ts"
|
|
3549
3861
|
}
|
|
@@ -3799,13 +4111,6 @@ var PLAY_DEDUP_BACKENDS = {
|
|
|
3799
4111
|
|
|
3800
4112
|
// ../shared_libs/play-runtime/profiles.ts
|
|
3801
4113
|
var PLAY_EXECUTION_PROFILES = {
|
|
3802
|
-
legacy: {
|
|
3803
|
-
id: "legacy",
|
|
3804
|
-
scheduler: PLAY_SCHEDULER_BACKENDS.temporal,
|
|
3805
|
-
runner: PLAY_RUNTIME_BACKENDS.daytona,
|
|
3806
|
-
dedup: PLAY_DEDUP_BACKENDS.inMemory,
|
|
3807
|
-
label: "Daytona + Temporal (production today)"
|
|
3808
|
-
},
|
|
3809
4114
|
workers_edge: {
|
|
3810
4115
|
id: "workers_edge",
|
|
3811
4116
|
scheduler: PLAY_SCHEDULER_BACKENDS.cfWorkflows,
|
|
@@ -3840,7 +4145,7 @@ function resolveExecutionProfile(override) {
|
|
|
3840
4145
|
// src/plays/local-file-discovery.ts
|
|
3841
4146
|
import { createHash as createHash2 } from "crypto";
|
|
3842
4147
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
3843
|
-
import { basename as basename2, dirname as
|
|
4148
|
+
import { basename as basename2, dirname as dirname5, extname as extname2, isAbsolute as isAbsolute2, join as join4, relative, resolve as resolve5 } from "path";
|
|
3844
4149
|
var SOURCE_EXTENSIONS2 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
|
|
3845
4150
|
function sha2562(buffer) {
|
|
3846
4151
|
return createHash2("sha256").update(buffer).digest("hex");
|
|
@@ -4041,7 +4346,7 @@ function isPathInsideDirectory2(filePath, directory) {
|
|
|
4041
4346
|
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute2(relativePath);
|
|
4042
4347
|
}
|
|
4043
4348
|
async function resolveLocalImport2(fromFile, specifier) {
|
|
4044
|
-
const base = isAbsolute2(specifier) ? resolve5(specifier) : resolve5(
|
|
4349
|
+
const base = isAbsolute2(specifier) ? resolve5(specifier) : resolve5(dirname5(fromFile), specifier);
|
|
4045
4350
|
const candidates = [base];
|
|
4046
4351
|
const explicitExtension = extname2(base).toLowerCase();
|
|
4047
4352
|
if (!explicitExtension) {
|
|
@@ -4060,7 +4365,7 @@ async function resolveLocalImport2(fromFile, specifier) {
|
|
|
4060
4365
|
}
|
|
4061
4366
|
async function discoverPackagedLocalFiles(entryFile) {
|
|
4062
4367
|
const absoluteEntryFile = resolve5(entryFile);
|
|
4063
|
-
const packagingRoot =
|
|
4368
|
+
const packagingRoot = dirname5(absoluteEntryFile);
|
|
4064
4369
|
const files = /* @__PURE__ */ new Map();
|
|
4065
4370
|
const unresolved = [];
|
|
4066
4371
|
const visitedFiles = /* @__PURE__ */ new Set();
|
|
@@ -4097,7 +4402,7 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
4097
4402
|
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."
|
|
4098
4403
|
});
|
|
4099
4404
|
} else {
|
|
4100
|
-
const absoluteCsvPath = resolve5(
|
|
4405
|
+
const absoluteCsvPath = resolve5(dirname5(absolutePath), resolvedPath);
|
|
4101
4406
|
if (isAbsolute2(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
|
|
4102
4407
|
unresolved.push({
|
|
4103
4408
|
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
@@ -4136,14 +4441,14 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
4136
4441
|
|
|
4137
4442
|
// src/plays/bundle-play-file.ts
|
|
4138
4443
|
var PLAY_BUNDLE_CACHE_VERSION2 = 26;
|
|
4139
|
-
var MODULE_DIR =
|
|
4444
|
+
var MODULE_DIR = dirname6(fileURLToPath(import.meta.url));
|
|
4140
4445
|
var SDK_PACKAGE_ROOT = resolve6(MODULE_DIR, "..", "..");
|
|
4141
4446
|
var SOURCE_REPO_ROOT = resolve6(SDK_PACKAGE_ROOT, "..");
|
|
4142
|
-
var HAS_SOURCE_BUNDLING_SOURCES =
|
|
4447
|
+
var HAS_SOURCE_BUNDLING_SOURCES = existsSync4(
|
|
4143
4448
|
resolve6(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
4144
4449
|
);
|
|
4145
4450
|
var PACKAGED_REPO_ROOT = resolve6(SDK_PACKAGE_ROOT, "dist", "repo");
|
|
4146
|
-
var HAS_PACKAGED_BUNDLING_SOURCES =
|
|
4451
|
+
var HAS_PACKAGED_BUNDLING_SOURCES = existsSync4(
|
|
4147
4452
|
resolve6(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
4148
4453
|
);
|
|
4149
4454
|
var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : resolve6(SDK_PACKAGE_ROOT, "..");
|
|
@@ -4182,7 +4487,7 @@ function createSdkPlayBundlingAdapter() {
|
|
|
4182
4487
|
sdkSourceRoot: SDK_SOURCE_ROOT,
|
|
4183
4488
|
sdkPackageJson: SDK_PACKAGE_JSON,
|
|
4184
4489
|
sdkEntryFile: SDK_ENTRY_FILE,
|
|
4185
|
-
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !
|
|
4490
|
+
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !existsSync4(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
|
|
4186
4491
|
sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
|
|
4187
4492
|
workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
|
|
4188
4493
|
workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
|
|
@@ -4343,7 +4648,77 @@ function createCliProgress(enabled) {
|
|
|
4343
4648
|
return progress;
|
|
4344
4649
|
}
|
|
4345
4650
|
|
|
4651
|
+
// src/cli/trace.ts
|
|
4652
|
+
var cliTraceStartedAt = Date.now();
|
|
4653
|
+
function isTruthyEnv(value) {
|
|
4654
|
+
return value === "1" || value === "true" || value === "yes";
|
|
4655
|
+
}
|
|
4656
|
+
function isCliTraceEnabled() {
|
|
4657
|
+
return isTruthyEnv(process.env.DEEPLINE_CLI_TRACE);
|
|
4658
|
+
}
|
|
4659
|
+
function recordCliTrace(event) {
|
|
4660
|
+
if (!isCliTraceEnabled()) {
|
|
4661
|
+
return;
|
|
4662
|
+
}
|
|
4663
|
+
const now = Date.now();
|
|
4664
|
+
const payload = {
|
|
4665
|
+
ts: now,
|
|
4666
|
+
source: "cli",
|
|
4667
|
+
sinceStartMs: now - cliTraceStartedAt,
|
|
4668
|
+
...event
|
|
4669
|
+
};
|
|
4670
|
+
process.stderr.write(`[cli-trace] ${JSON.stringify(payload)}
|
|
4671
|
+
`);
|
|
4672
|
+
}
|
|
4673
|
+
async function traceCliSpan(phase, fields, run) {
|
|
4674
|
+
if (!isCliTraceEnabled()) {
|
|
4675
|
+
return run();
|
|
4676
|
+
}
|
|
4677
|
+
const startedAt = Date.now();
|
|
4678
|
+
try {
|
|
4679
|
+
const result = await run();
|
|
4680
|
+
recordCliTrace({
|
|
4681
|
+
phase,
|
|
4682
|
+
ms: Date.now() - startedAt,
|
|
4683
|
+
ok: true,
|
|
4684
|
+
...fields
|
|
4685
|
+
});
|
|
4686
|
+
return result;
|
|
4687
|
+
} catch (error) {
|
|
4688
|
+
recordCliTrace({
|
|
4689
|
+
phase,
|
|
4690
|
+
ms: Date.now() - startedAt,
|
|
4691
|
+
ok: false,
|
|
4692
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4693
|
+
...fields
|
|
4694
|
+
});
|
|
4695
|
+
throw error;
|
|
4696
|
+
}
|
|
4697
|
+
}
|
|
4698
|
+
|
|
4346
4699
|
// src/cli/commands/play.ts
|
|
4700
|
+
function traceCliSync(phase, fields, run) {
|
|
4701
|
+
const startedAt = Date.now();
|
|
4702
|
+
try {
|
|
4703
|
+
const result = run();
|
|
4704
|
+
recordCliTrace({
|
|
4705
|
+
phase,
|
|
4706
|
+
ms: Date.now() - startedAt,
|
|
4707
|
+
ok: true,
|
|
4708
|
+
...fields
|
|
4709
|
+
});
|
|
4710
|
+
return result;
|
|
4711
|
+
} catch (error) {
|
|
4712
|
+
recordCliTrace({
|
|
4713
|
+
phase,
|
|
4714
|
+
ms: Date.now() - startedAt,
|
|
4715
|
+
ok: false,
|
|
4716
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4717
|
+
...fields
|
|
4718
|
+
});
|
|
4719
|
+
throw error;
|
|
4720
|
+
}
|
|
4721
|
+
}
|
|
4347
4722
|
function parseReferencedPlayTarget(target) {
|
|
4348
4723
|
const trimmed = target.trim();
|
|
4349
4724
|
const slashIndex = trimmed.indexOf("/");
|
|
@@ -4398,15 +4773,15 @@ function materializeRemotePlaySource(input) {
|
|
|
4398
4773
|
return null;
|
|
4399
4774
|
}
|
|
4400
4775
|
const outputPath = input.outPath ?? defaultMaterializedPlayPath(input.playName);
|
|
4401
|
-
if (
|
|
4776
|
+
if (existsSync5(outputPath)) {
|
|
4402
4777
|
const existingSource = readFileSync3(outputPath, "utf-8");
|
|
4403
4778
|
if (existingSource === input.sourceCode) {
|
|
4404
4779
|
return { path: outputPath, status: "unchanged", created: false };
|
|
4405
4780
|
}
|
|
4406
|
-
|
|
4781
|
+
writeFileSync5(outputPath, input.sourceCode, "utf-8");
|
|
4407
4782
|
return { path: outputPath, status: "updated", created: false };
|
|
4408
4783
|
}
|
|
4409
|
-
|
|
4784
|
+
writeFileSync5(outputPath, input.sourceCode, "utf-8");
|
|
4410
4785
|
return { path: outputPath, status: "created", created: true };
|
|
4411
4786
|
}
|
|
4412
4787
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -4451,7 +4826,7 @@ function extractPlayName(code, filePath) {
|
|
|
4451
4826
|
throw buildMissingDefinePlayError(filePath);
|
|
4452
4827
|
}
|
|
4453
4828
|
function isFileTarget(target) {
|
|
4454
|
-
return
|
|
4829
|
+
return existsSync5(resolve7(target));
|
|
4455
4830
|
}
|
|
4456
4831
|
function looksLikeFilePath(target) {
|
|
4457
4832
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -4580,7 +4955,24 @@ function applyCsvShortcutInput(input) {
|
|
|
4580
4955
|
function isLocalFilePathValue(value) {
|
|
4581
4956
|
if (typeof value !== "string" || !value.trim()) return false;
|
|
4582
4957
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
4583
|
-
return
|
|
4958
|
+
return existsSync5(resolve7(value));
|
|
4959
|
+
}
|
|
4960
|
+
function inputContainsLocalFilePath(value) {
|
|
4961
|
+
if (isLocalFilePathValue(value)) {
|
|
4962
|
+
return true;
|
|
4963
|
+
}
|
|
4964
|
+
if (Array.isArray(value)) {
|
|
4965
|
+
return value.some((entry) => inputContainsLocalFilePath(entry));
|
|
4966
|
+
}
|
|
4967
|
+
if (value && typeof value === "object") {
|
|
4968
|
+
return Object.values(value).some(
|
|
4969
|
+
(entry) => inputContainsLocalFilePath(entry)
|
|
4970
|
+
);
|
|
4971
|
+
}
|
|
4972
|
+
return false;
|
|
4973
|
+
}
|
|
4974
|
+
function namedRunNeedsPlayDefinition(input) {
|
|
4975
|
+
return input.revisionSelector === "latest" || getDottedInputValue(input.runtimeInput, "csv") != null || inputContainsLocalFilePath(input.runtimeInput);
|
|
4584
4976
|
}
|
|
4585
4977
|
async function stageFileInputArgs(input) {
|
|
4586
4978
|
const uniqueBindings = [
|
|
@@ -4768,7 +5160,7 @@ function formatTimestamp(value) {
|
|
|
4768
5160
|
function formatRunLine(run) {
|
|
4769
5161
|
return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)}`;
|
|
4770
5162
|
}
|
|
4771
|
-
function
|
|
5163
|
+
function isTransientPlayStreamError(error) {
|
|
4772
5164
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
4773
5165
|
return error.statusCode >= 500 && error.statusCode < 600;
|
|
4774
5166
|
}
|
|
@@ -4777,12 +5169,6 @@ function isTransientPlayStatusPollError(error) {
|
|
|
4777
5169
|
text
|
|
4778
5170
|
);
|
|
4779
5171
|
}
|
|
4780
|
-
function isTerminalPlayStatusPollError(input) {
|
|
4781
|
-
if (input.error instanceof DeeplineError && input.error.statusCode === 404 && input.hasSeenRun) {
|
|
4782
|
-
return true;
|
|
4783
|
-
}
|
|
4784
|
-
return false;
|
|
4785
|
-
}
|
|
4786
5172
|
var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
4787
5173
|
"completed",
|
|
4788
5174
|
"failed",
|
|
@@ -4848,6 +5234,12 @@ function buildPlayDashboardUrl(baseUrl, playName) {
|
|
|
4848
5234
|
const encodedPlayName = encodeURIComponent(playName);
|
|
4849
5235
|
return `${trimmedBase}/dashboard/plays/${encodedPlayName}`;
|
|
4850
5236
|
}
|
|
5237
|
+
function openPlayDashboard(input) {
|
|
5238
|
+
if (input.jsonOutput || input.noOpen || !input.dashboardUrl) {
|
|
5239
|
+
return;
|
|
5240
|
+
}
|
|
5241
|
+
openInBrowser(input.dashboardUrl);
|
|
5242
|
+
}
|
|
4851
5243
|
function getDashboardUrlFromLiveEvent(event) {
|
|
4852
5244
|
const dashboardUrl = getEventPayload(event).dashboardUrl;
|
|
4853
5245
|
return typeof dashboardUrl === "string" && dashboardUrl.trim() ? dashboardUrl.trim() : null;
|
|
@@ -4884,6 +5276,68 @@ function assertPlayWaitNotTimedOut(input) {
|
|
|
4884
5276
|
);
|
|
4885
5277
|
}
|
|
4886
5278
|
}
|
|
5279
|
+
async function waitForPlayCompletionByStream(input) {
|
|
5280
|
+
const controller = new AbortController();
|
|
5281
|
+
let timedOut = false;
|
|
5282
|
+
let lastPhase = null;
|
|
5283
|
+
const timeout = input.waitTimeoutMs === null ? null : setTimeout(
|
|
5284
|
+
() => {
|
|
5285
|
+
timedOut = true;
|
|
5286
|
+
controller.abort();
|
|
5287
|
+
},
|
|
5288
|
+
Math.max(1, input.waitTimeoutMs - (Date.now() - input.startedAt))
|
|
5289
|
+
);
|
|
5290
|
+
try {
|
|
5291
|
+
for await (const event of input.client.streamPlayRunEvents(
|
|
5292
|
+
input.workflowId,
|
|
5293
|
+
{ signal: controller.signal }
|
|
5294
|
+
)) {
|
|
5295
|
+
assertPlayWaitNotTimedOut({ ...input, lastPhase });
|
|
5296
|
+
const phase = describeLiveEventPhase(event);
|
|
5297
|
+
if (phase) {
|
|
5298
|
+
lastPhase = phase;
|
|
5299
|
+
input.progress.phase(phase);
|
|
5300
|
+
}
|
|
5301
|
+
printPlayLogLines({
|
|
5302
|
+
lines: getLogLinesFromLiveEvent(event),
|
|
5303
|
+
status: null,
|
|
5304
|
+
jsonOutput: input.jsonOutput,
|
|
5305
|
+
emitLogs: input.emitLogs,
|
|
5306
|
+
state: input.state,
|
|
5307
|
+
progress: input.progress
|
|
5308
|
+
});
|
|
5309
|
+
const status = getStatusFromLiveEvent(event);
|
|
5310
|
+
if (status && TERMINAL_PLAY_STATUSES2.has(status)) {
|
|
5311
|
+
const finalStatus = await input.client.getPlayStatus(input.workflowId, {
|
|
5312
|
+
billing: false
|
|
5313
|
+
});
|
|
5314
|
+
if (TERMINAL_PLAY_STATUSES2.has(finalStatus.status)) {
|
|
5315
|
+
return finalStatus;
|
|
5316
|
+
}
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5319
|
+
} catch (error) {
|
|
5320
|
+
if (timedOut) {
|
|
5321
|
+
assertPlayWaitNotTimedOut({ ...input, lastPhase });
|
|
5322
|
+
}
|
|
5323
|
+
throw error;
|
|
5324
|
+
} finally {
|
|
5325
|
+
if (timeout) {
|
|
5326
|
+
clearTimeout(timeout);
|
|
5327
|
+
}
|
|
5328
|
+
}
|
|
5329
|
+
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
5330
|
+
throw new DeeplineError(
|
|
5331
|
+
`Play live stream ended before the run reached a terminal state runId=${input.workflowId}${phaseSuffix}.`,
|
|
5332
|
+
void 0,
|
|
5333
|
+
"PLAY_LIVE_STREAM_ENDED",
|
|
5334
|
+
{
|
|
5335
|
+
runId: input.workflowId,
|
|
5336
|
+
workflowId: input.workflowId,
|
|
5337
|
+
...lastPhase ? { phase: lastPhase } : {}
|
|
5338
|
+
}
|
|
5339
|
+
);
|
|
5340
|
+
}
|
|
4887
5341
|
async function startAndWaitForPlayCompletionByStream(input) {
|
|
4888
5342
|
const startedAt = Date.now();
|
|
4889
5343
|
const state = {
|
|
@@ -4894,6 +5348,8 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4894
5348
|
let timedOut = false;
|
|
4895
5349
|
let emittedDashboardUrl = false;
|
|
4896
5350
|
let lastKnownWorkflowId = "";
|
|
5351
|
+
let eventCount = 0;
|
|
5352
|
+
let firstRunIdMs = null;
|
|
4897
5353
|
let lastPhase = null;
|
|
4898
5354
|
const timeout = input.waitTimeoutMs === null ? null : setTimeout(
|
|
4899
5355
|
() => {
|
|
@@ -4906,13 +5362,20 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4906
5362
|
for await (const event of input.client.startPlayRunStream(input.request, {
|
|
4907
5363
|
signal: controller.signal
|
|
4908
5364
|
})) {
|
|
5365
|
+
eventCount += 1;
|
|
4909
5366
|
const eventRunId = getEventPayload(event).runId;
|
|
4910
5367
|
if (typeof eventRunId === "string" && eventRunId && eventRunId !== "pending") {
|
|
4911
5368
|
lastKnownWorkflowId = eventRunId;
|
|
5369
|
+
firstRunIdMs ??= Date.now() - startedAt;
|
|
4912
5370
|
}
|
|
4913
5371
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
4914
5372
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
4915
5373
|
const dashboardUrl = getDashboardUrlFromLiveEvent(event) ?? buildPlayDashboardUrl(input.client.baseUrl, input.playName);
|
|
5374
|
+
openPlayDashboard({
|
|
5375
|
+
dashboardUrl,
|
|
5376
|
+
jsonOutput: input.jsonOutput,
|
|
5377
|
+
noOpen: input.noOpen
|
|
5378
|
+
});
|
|
4916
5379
|
if (!input.jsonOutput) {
|
|
4917
5380
|
writeStartedPlayRun({
|
|
4918
5381
|
runId: workflowId,
|
|
@@ -4946,6 +5409,16 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4946
5409
|
});
|
|
4947
5410
|
const finalStatus = getFinalStatusFromLiveEvent(event);
|
|
4948
5411
|
if (finalStatus) {
|
|
5412
|
+
recordCliTrace({
|
|
5413
|
+
phase: "cli.play_start_stream_terminal",
|
|
5414
|
+
ms: Date.now() - startedAt,
|
|
5415
|
+
ok: true,
|
|
5416
|
+
playName: input.playName,
|
|
5417
|
+
workflowId: finalStatus.runId || lastKnownWorkflowId || null,
|
|
5418
|
+
eventCount,
|
|
5419
|
+
firstRunIdMs,
|
|
5420
|
+
lastPhase
|
|
5421
|
+
});
|
|
4949
5422
|
return finalStatus;
|
|
4950
5423
|
}
|
|
4951
5424
|
}
|
|
@@ -4958,21 +5431,31 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4958
5431
|
lastPhase
|
|
4959
5432
|
});
|
|
4960
5433
|
}
|
|
4961
|
-
if (lastKnownWorkflowId &&
|
|
5434
|
+
if (lastKnownWorkflowId && isTransientPlayStreamError(error)) {
|
|
4962
5435
|
if (timeout) {
|
|
4963
5436
|
clearTimeout(timeout);
|
|
4964
5437
|
}
|
|
4965
5438
|
const reason = error instanceof Error ? error.message : String(error);
|
|
4966
5439
|
if (!input.jsonOutput) {
|
|
4967
5440
|
process.stderr.write(
|
|
4968
|
-
`[play watch] start stream failed after run ${lastKnownWorkflowId};
|
|
5441
|
+
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
|
|
4969
5442
|
`
|
|
4970
5443
|
);
|
|
4971
5444
|
}
|
|
4972
|
-
|
|
5445
|
+
recordCliTrace({
|
|
5446
|
+
phase: "cli.play_start_stream_reconnect",
|
|
5447
|
+
ms: Date.now() - startedAt,
|
|
5448
|
+
ok: true,
|
|
5449
|
+
playName: input.playName,
|
|
5450
|
+
workflowId: lastKnownWorkflowId,
|
|
5451
|
+
eventCount,
|
|
5452
|
+
firstRunIdMs,
|
|
5453
|
+
lastPhase,
|
|
5454
|
+
reason
|
|
5455
|
+
});
|
|
5456
|
+
return waitForPlayCompletionByStream({
|
|
4973
5457
|
client: input.client,
|
|
4974
5458
|
workflowId: lastKnownWorkflowId,
|
|
4975
|
-
pollIntervalMs: 500,
|
|
4976
5459
|
jsonOutput: input.jsonOutput,
|
|
4977
5460
|
emitLogs: input.emitLogs,
|
|
4978
5461
|
waitTimeoutMs: input.waitTimeoutMs,
|
|
@@ -4990,13 +5473,23 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4990
5473
|
if (lastKnownWorkflowId) {
|
|
4991
5474
|
if (!input.jsonOutput) {
|
|
4992
5475
|
input.progress.writeLine(
|
|
4993
|
-
`[play watch] start stream ended after run ${lastKnownWorkflowId};
|
|
5476
|
+
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
|
|
4994
5477
|
);
|
|
4995
5478
|
}
|
|
4996
|
-
|
|
5479
|
+
recordCliTrace({
|
|
5480
|
+
phase: "cli.play_start_stream_reconnect",
|
|
5481
|
+
ms: Date.now() - startedAt,
|
|
5482
|
+
ok: true,
|
|
5483
|
+
playName: input.playName,
|
|
5484
|
+
workflowId: lastKnownWorkflowId,
|
|
5485
|
+
eventCount,
|
|
5486
|
+
firstRunIdMs,
|
|
5487
|
+
lastPhase,
|
|
5488
|
+
reason: "stream ended before terminal event"
|
|
5489
|
+
});
|
|
5490
|
+
return waitForPlayCompletionByStream({
|
|
4997
5491
|
client: input.client,
|
|
4998
5492
|
workflowId: lastKnownWorkflowId,
|
|
4999
|
-
pollIntervalMs: 500,
|
|
5000
5493
|
jsonOutput: input.jsonOutput,
|
|
5001
5494
|
emitLogs: input.emitLogs,
|
|
5002
5495
|
waitTimeoutMs: input.waitTimeoutMs,
|
|
@@ -5017,71 +5510,6 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5017
5510
|
}
|
|
5018
5511
|
);
|
|
5019
5512
|
}
|
|
5020
|
-
async function waitForPlayCompletionByPolling(input) {
|
|
5021
|
-
let lastTransientPollWarningAt = 0;
|
|
5022
|
-
let hasSeenRun = false;
|
|
5023
|
-
while (true) {
|
|
5024
|
-
assertPlayWaitNotTimedOut(input);
|
|
5025
|
-
let status;
|
|
5026
|
-
try {
|
|
5027
|
-
status = await input.client.getPlayTailStatus(input.workflowId, {
|
|
5028
|
-
afterLogIndex: input.state.lastLogIndex,
|
|
5029
|
-
// Keep the server-side tail wait close to the caller's requested poll
|
|
5030
|
-
// cadence. A long wait makes tiny remote runs look slow whenever the
|
|
5031
|
-
// terminal update lands just after the held request starts.
|
|
5032
|
-
waitMs: Math.max(50, Math.min(input.pollIntervalMs, 1e3))
|
|
5033
|
-
});
|
|
5034
|
-
} catch (error) {
|
|
5035
|
-
if (isTerminalPlayStatusPollError({ error, hasSeenRun })) {
|
|
5036
|
-
throw new DeeplineError(
|
|
5037
|
-
`Play run ${input.workflowId} no longer exists on the server (404). The run was deleted or the backend lost it.`,
|
|
5038
|
-
404,
|
|
5039
|
-
"PLAY_RUN_NOT_FOUND"
|
|
5040
|
-
);
|
|
5041
|
-
}
|
|
5042
|
-
if (!isTransientPlayStatusPollError(error)) {
|
|
5043
|
-
throw error;
|
|
5044
|
-
}
|
|
5045
|
-
const now = Date.now();
|
|
5046
|
-
if (now - lastTransientPollWarningAt >= 3e4) {
|
|
5047
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
5048
|
-
input.progress.writeLine(
|
|
5049
|
-
`[play tail] transient status poll failed; retrying: ${message}`
|
|
5050
|
-
);
|
|
5051
|
-
lastTransientPollWarningAt = now;
|
|
5052
|
-
}
|
|
5053
|
-
await new Promise(
|
|
5054
|
-
(resolvePromise) => setTimeout(resolvePromise, input.pollIntervalMs)
|
|
5055
|
-
);
|
|
5056
|
-
continue;
|
|
5057
|
-
}
|
|
5058
|
-
hasSeenRun = true;
|
|
5059
|
-
const logs = status.progress?.logs ?? [];
|
|
5060
|
-
input.progress.phase(status.status);
|
|
5061
|
-
printPlayLogLines({
|
|
5062
|
-
lines: logs.slice(input.state.lastLogIndex),
|
|
5063
|
-
status,
|
|
5064
|
-
jsonOutput: input.jsonOutput,
|
|
5065
|
-
emitLogs: input.emitLogs,
|
|
5066
|
-
state: input.state,
|
|
5067
|
-
progress: input.progress
|
|
5068
|
-
});
|
|
5069
|
-
if (TERMINAL_PLAY_STATUSES2.has(status.status)) {
|
|
5070
|
-
return status.result !== void 0 ? status : await input.client.getPlayStatus(input.workflowId);
|
|
5071
|
-
}
|
|
5072
|
-
const authoritativeStatus = await input.client.getPlayStatus(
|
|
5073
|
-
input.workflowId
|
|
5074
|
-
);
|
|
5075
|
-
if (TERMINAL_PLAY_STATUSES2.has(authoritativeStatus.status)) {
|
|
5076
|
-
return authoritativeStatus;
|
|
5077
|
-
}
|
|
5078
|
-
if ((status.progress?.logs ?? []).length === input.state.lastLogIndex) {
|
|
5079
|
-
await new Promise(
|
|
5080
|
-
(resolvePromise) => setTimeout(resolvePromise, input.pollIntervalMs)
|
|
5081
|
-
);
|
|
5082
|
-
}
|
|
5083
|
-
}
|
|
5084
|
-
}
|
|
5085
5513
|
function formatInteger(value) {
|
|
5086
5514
|
return typeof value === "number" && Number.isFinite(value) ? value.toLocaleString("en-US") : String(value ?? "-");
|
|
5087
5515
|
}
|
|
@@ -5222,7 +5650,6 @@ function buildRunWarnings(status, rowsInfo) {
|
|
|
5222
5650
|
function buildRunNextCommands(runId, rowsInfo) {
|
|
5223
5651
|
const commands = {
|
|
5224
5652
|
get: `deepline runs get ${runId} --json`,
|
|
5225
|
-
tail: `deepline runs tail ${runId} --json`,
|
|
5226
5653
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
5227
5654
|
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
5228
5655
|
};
|
|
@@ -5338,10 +5765,9 @@ function normalizeErrorsForEnvelope(status, error) {
|
|
|
5338
5765
|
}
|
|
5339
5766
|
function normalizeLogsForEnvelope(status) {
|
|
5340
5767
|
const logs = Array.isArray(status.progress?.logs) ? status.progress.logs : [];
|
|
5341
|
-
const
|
|
5342
|
-
const totalCount = offset + logs.length;
|
|
5768
|
+
const totalCount = logs.length;
|
|
5343
5769
|
const entries = logs.slice(Math.max(0, logs.length - RUN_LOG_PREVIEW_LIMIT));
|
|
5344
|
-
const firstSequence = entries.length === 0 ? null :
|
|
5770
|
+
const firstSequence = entries.length === 0 ? null : logs.length - entries.length + 1;
|
|
5345
5771
|
const lastSequence = totalCount === 0 ? null : totalCount;
|
|
5346
5772
|
return {
|
|
5347
5773
|
totalCount,
|
|
@@ -5587,7 +6013,6 @@ function writeStartedPlayRun(input) {
|
|
|
5587
6013
|
workflowId: input.runId,
|
|
5588
6014
|
name: input.playName,
|
|
5589
6015
|
status: input.status ?? "started",
|
|
5590
|
-
statusUrl: input.statusUrl,
|
|
5591
6016
|
dashboardUrl: input.dashboardUrl
|
|
5592
6017
|
};
|
|
5593
6018
|
if (input.jsonOutput) {
|
|
@@ -5599,7 +6024,7 @@ function writeStartedPlayRun(input) {
|
|
|
5599
6024
|
`Started ${input.playName}`,
|
|
5600
6025
|
` run id: ${input.runId}`,
|
|
5601
6026
|
` get status: deepline runs get ${input.runId} --json`,
|
|
5602
|
-
`
|
|
6027
|
+
` logs: deepline runs logs ${input.runId} --json`,
|
|
5603
6028
|
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`,
|
|
5604
6029
|
` result JSON: deepline runs get ${input.runId} --json`
|
|
5605
6030
|
];
|
|
@@ -5614,7 +6039,7 @@ function writeStartedPlayRun(input) {
|
|
|
5614
6039
|
console.log(output);
|
|
5615
6040
|
}
|
|
5616
6041
|
function parsePlayRunOptions(args) {
|
|
5617
|
-
const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--watch] [--out output.csv] [--tail-timeout-ms 30000] [--force] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--watch] [--out output.csv] [--tail-timeout-ms 30000] [--force] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--watch] [--out output.csv] [--tail-timeout-ms 30000] [--force] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--live|--latest|--revision-id <id>] [--watch] [--out output.csv] [--tail-timeout-ms 30000] [--force] [--json] [--<input> value]";
|
|
6042
|
+
const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--watch] [--out output.csv] [--tail-timeout-ms 30000] [--force] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--watch] [--out output.csv] [--tail-timeout-ms 30000] [--force] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--watch] [--out output.csv] [--tail-timeout-ms 30000] [--force] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--live|--latest|--revision-id <id>] [--watch] [--out output.csv] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--<input> value]\nRun `deepline plays run --help` for idempotency, tool call id, and ctx.map guidance.";
|
|
5618
6043
|
let filePath = null;
|
|
5619
6044
|
let playName = null;
|
|
5620
6045
|
let input = null;
|
|
@@ -5624,8 +6049,8 @@ function parsePlayRunOptions(args) {
|
|
|
5624
6049
|
let jsonOutput = watch ? args.includes("--json") : argsWantJson(args);
|
|
5625
6050
|
const emitLogs = !jsonOutput || args.includes("--logs");
|
|
5626
6051
|
const force = args.includes("--force");
|
|
6052
|
+
const noOpen = args.includes("--no-open");
|
|
5627
6053
|
let outPath = null;
|
|
5628
|
-
let pollIntervalMs = 500;
|
|
5629
6054
|
let waitTimeoutMs = null;
|
|
5630
6055
|
for (let index = 0; index < args.length; index += 1) {
|
|
5631
6056
|
const arg = args[index];
|
|
@@ -5657,15 +6082,16 @@ function parsePlayRunOptions(args) {
|
|
|
5657
6082
|
outPath = resolve7(args[++index]);
|
|
5658
6083
|
continue;
|
|
5659
6084
|
}
|
|
5660
|
-
if (
|
|
5661
|
-
|
|
5662
|
-
|
|
6085
|
+
if (arg === "--poll-interval-ms" || arg === "--interval-ms") {
|
|
6086
|
+
throw new Error(
|
|
6087
|
+
`${arg} was removed. --watch uses the canonical run stream directly.`
|
|
6088
|
+
);
|
|
5663
6089
|
}
|
|
5664
6090
|
if ((arg === "--tail-timeout-ms" || arg === "--timeout-ms") && args[index + 1]) {
|
|
5665
6091
|
waitTimeoutMs = parsePositiveInteger2(args[++index], arg);
|
|
5666
6092
|
continue;
|
|
5667
6093
|
}
|
|
5668
|
-
if (arg === "--json" || arg === "--wait" || arg === "--tail" || arg === "--watch" || arg === "--logs" || arg === "--force") {
|
|
6094
|
+
if (arg === "--json" || arg === "--wait" || arg === "--tail" || arg === "--watch" || arg === "--logs" || arg === "--force" || arg === "--no-open") {
|
|
5669
6095
|
if (arg === "--watch") {
|
|
5670
6096
|
continue;
|
|
5671
6097
|
}
|
|
@@ -5734,10 +6160,10 @@ function parsePlayRunOptions(args) {
|
|
|
5734
6160
|
watch,
|
|
5735
6161
|
emitLogs,
|
|
5736
6162
|
jsonOutput,
|
|
5737
|
-
pollIntervalMs,
|
|
5738
6163
|
waitTimeoutMs,
|
|
5739
6164
|
force,
|
|
5740
|
-
outPath
|
|
6165
|
+
outPath,
|
|
6166
|
+
noOpen
|
|
5741
6167
|
};
|
|
5742
6168
|
}
|
|
5743
6169
|
function parsePlayCheckOptions(args) {
|
|
@@ -5825,11 +6251,24 @@ async function handleFileBackedRun(options) {
|
|
|
5825
6251
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
5826
6252
|
const absolutePlayPath = resolve7(options.target.path);
|
|
5827
6253
|
progress.phase("compiling play");
|
|
5828
|
-
const sourceCode =
|
|
6254
|
+
const sourceCode = traceCliSync(
|
|
6255
|
+
"cli.play_file_read_source",
|
|
6256
|
+
{ targetKind: "file" },
|
|
6257
|
+
() => readFileSync3(absolutePlayPath, "utf-8")
|
|
6258
|
+
);
|
|
6259
|
+
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5829
6260
|
let graph;
|
|
5830
6261
|
try {
|
|
5831
|
-
graph = await
|
|
5832
|
-
|
|
6262
|
+
graph = await traceCliSpan(
|
|
6263
|
+
"cli.play_file_bundle_graph",
|
|
6264
|
+
{ targetKind: "file" },
|
|
6265
|
+
() => collectBundledPlayGraph(absolutePlayPath)
|
|
6266
|
+
);
|
|
6267
|
+
await traceCliSpan(
|
|
6268
|
+
"cli.play_file_compile_manifests",
|
|
6269
|
+
{ targetKind: "file" },
|
|
6270
|
+
() => compileBundledPlayGraphManifests(client, graph)
|
|
6271
|
+
);
|
|
5833
6272
|
progress.phase("compiled play");
|
|
5834
6273
|
} catch (error) {
|
|
5835
6274
|
progress.fail();
|
|
@@ -5840,36 +6279,47 @@ async function handleFileBackedRun(options) {
|
|
|
5840
6279
|
const playName = bundleResult.playName ?? extractPlayName(sourceCode, absolutePlayPath);
|
|
5841
6280
|
try {
|
|
5842
6281
|
progress.phase("publishing imported plays");
|
|
5843
|
-
await
|
|
6282
|
+
await traceCliSpan(
|
|
6283
|
+
"cli.play_file_publish_imports",
|
|
6284
|
+
{ targetKind: "file" },
|
|
6285
|
+
() => publishImportedPlayDependencies(client, graph)
|
|
6286
|
+
);
|
|
5844
6287
|
} catch (error) {
|
|
5845
6288
|
progress.fail();
|
|
5846
6289
|
console.error(error instanceof Error ? error.message : String(error));
|
|
5847
6290
|
return 1;
|
|
5848
6291
|
}
|
|
5849
|
-
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5850
6292
|
const packagedFileUploads = bundleResult.packagedFiles.map(
|
|
5851
6293
|
(file) => stageFile(file.logicalPath, file.absolutePath)
|
|
5852
6294
|
);
|
|
6295
|
+
const compilerManifest = requireCompilerManifest(bundleResult);
|
|
5853
6296
|
const fileInputBindings = fileInputBindingsFromStaticPipeline(
|
|
5854
|
-
|
|
6297
|
+
compilerManifest.staticPipeline
|
|
5855
6298
|
);
|
|
5856
6299
|
applyCsvShortcutInput({
|
|
5857
6300
|
runtimeInput,
|
|
5858
6301
|
bindings: fileInputBindings,
|
|
5859
6302
|
fallbackInputPath: "file"
|
|
5860
6303
|
});
|
|
5861
|
-
const stagedFileInputs = await
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
6304
|
+
const stagedFileInputs = await traceCliSpan(
|
|
6305
|
+
"cli.play_stage_inputs",
|
|
6306
|
+
{
|
|
6307
|
+
targetKind: "file",
|
|
6308
|
+
bindingCount: fileInputBindings.length
|
|
6309
|
+
},
|
|
6310
|
+
() => stageFileInputArgs({
|
|
6311
|
+
client,
|
|
6312
|
+
runtimeInput,
|
|
6313
|
+
bindings: fileInputBindings,
|
|
6314
|
+
progress
|
|
6315
|
+
})
|
|
6316
|
+
);
|
|
5867
6317
|
const startRequest = {
|
|
5868
6318
|
name: playName,
|
|
5869
6319
|
sourceCode: bundleResult.sourceCode,
|
|
5870
6320
|
sourceFiles: bundleResult.sourceFiles,
|
|
5871
6321
|
runtimeArtifact: bundleResult.artifact,
|
|
5872
|
-
compilerManifest
|
|
6322
|
+
compilerManifest,
|
|
5873
6323
|
packagedFileUploads,
|
|
5874
6324
|
...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
|
|
5875
6325
|
...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
|
|
@@ -5878,35 +6328,57 @@ async function handleFileBackedRun(options) {
|
|
|
5878
6328
|
};
|
|
5879
6329
|
if (options.watch) {
|
|
5880
6330
|
progress.phase("starting run");
|
|
5881
|
-
const finalStatus = await
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
6331
|
+
const finalStatus = await traceCliSpan(
|
|
6332
|
+
"cli.play_start_watch",
|
|
6333
|
+
{ targetKind: "file", playName },
|
|
6334
|
+
() => startAndWaitForPlayCompletionByStream({
|
|
6335
|
+
client,
|
|
6336
|
+
request: startRequest,
|
|
6337
|
+
playName,
|
|
6338
|
+
jsonOutput: options.jsonOutput,
|
|
6339
|
+
emitLogs: options.emitLogs,
|
|
6340
|
+
waitTimeoutMs: options.waitTimeoutMs,
|
|
6341
|
+
noOpen: options.noOpen,
|
|
6342
|
+
progress
|
|
6343
|
+
})
|
|
6344
|
+
);
|
|
6345
|
+
const exportedPath = traceCliSync(
|
|
6346
|
+
"cli.play_export_rows",
|
|
6347
|
+
{ targetKind: "file", playName },
|
|
6348
|
+
() => exportPlayStatusRows(finalStatus, options.outPath)
|
|
6349
|
+
);
|
|
5891
6350
|
if (finalStatus.status === "completed") {
|
|
5892
6351
|
progress.complete();
|
|
5893
6352
|
} else {
|
|
5894
6353
|
progress.fail();
|
|
5895
6354
|
}
|
|
5896
|
-
|
|
6355
|
+
traceCliSync(
|
|
6356
|
+
"cli.play_write_result",
|
|
6357
|
+
{ targetKind: "file", playName },
|
|
6358
|
+
() => writePlayResult(finalStatus, options.jsonOutput, { exportedPath })
|
|
6359
|
+
);
|
|
5897
6360
|
return finalStatus.status === "completed" ? 0 : 1;
|
|
5898
6361
|
}
|
|
5899
6362
|
progress.phase("starting run");
|
|
5900
|
-
const started = await
|
|
6363
|
+
const started = await traceCliSpan(
|
|
6364
|
+
"cli.play_start_unwatched",
|
|
6365
|
+
{ targetKind: "file", playName },
|
|
6366
|
+
() => client.startPlayRun(startRequest)
|
|
6367
|
+
);
|
|
5901
6368
|
const dashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
5902
|
-
|
|
6369
|
+
const resolvedDashboardUrl = started.dashboardUrl ?? dashboardUrl;
|
|
6370
|
+
openPlayDashboard({
|
|
6371
|
+
dashboardUrl: resolvedDashboardUrl,
|
|
6372
|
+
jsonOutput: options.jsonOutput,
|
|
6373
|
+
noOpen: options.noOpen
|
|
6374
|
+
});
|
|
6375
|
+
progress.phase(`loading play on ${resolvedDashboardUrl}`);
|
|
5903
6376
|
progress.complete();
|
|
5904
6377
|
writeStartedPlayRun({
|
|
5905
6378
|
runId: started.workflowId,
|
|
5906
6379
|
playName,
|
|
5907
6380
|
status: started.status,
|
|
5908
|
-
|
|
5909
|
-
dashboardUrl: started.dashboardUrl ?? dashboardUrl,
|
|
6381
|
+
dashboardUrl: resolvedDashboardUrl,
|
|
5910
6382
|
jsonOutput: options.jsonOutput,
|
|
5911
6383
|
progress
|
|
5912
6384
|
});
|
|
@@ -5932,32 +6404,67 @@ async function handleNamedRun(options) {
|
|
|
5932
6404
|
}
|
|
5933
6405
|
const client = new DeeplineClient();
|
|
5934
6406
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
5935
|
-
|
|
5936
|
-
const playDetail = await assertCanonicalNamedPlayReference(client, options.target.name);
|
|
5937
|
-
progress.phase("selecting revision");
|
|
5938
|
-
const selectedRevisionId = await resolveNamedRunRevisionId({
|
|
5939
|
-
client,
|
|
5940
|
-
playName: options.target.name,
|
|
5941
|
-
revisionId: options.revisionId,
|
|
5942
|
-
selector: options.revisionSelector
|
|
5943
|
-
});
|
|
6407
|
+
const playName = options.target.name;
|
|
5944
6408
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5945
|
-
const
|
|
6409
|
+
const needsPlayDefinition = namedRunNeedsPlayDefinition({
|
|
6410
|
+
runtimeInput,
|
|
6411
|
+
revisionSelector: options.revisionSelector
|
|
6412
|
+
});
|
|
6413
|
+
const playDetail = needsPlayDefinition ? await (async () => {
|
|
6414
|
+
progress.phase("loading play definition");
|
|
6415
|
+
return traceCliSpan(
|
|
6416
|
+
"cli.play_load_definition",
|
|
6417
|
+
{ targetKind: "name", playName, skipped: false },
|
|
6418
|
+
() => assertCanonicalNamedPlayReference(client, playName)
|
|
6419
|
+
);
|
|
6420
|
+
})() : (recordCliTrace({
|
|
6421
|
+
phase: "cli.play_load_definition",
|
|
6422
|
+
ms: 0,
|
|
6423
|
+
ok: true,
|
|
6424
|
+
targetKind: "name",
|
|
6425
|
+
playName,
|
|
6426
|
+
skipped: true
|
|
6427
|
+
}), null);
|
|
6428
|
+
progress.phase("selecting revision");
|
|
6429
|
+
const selectedRevisionId = await traceCliSpan(
|
|
6430
|
+
"cli.play_select_revision",
|
|
6431
|
+
{
|
|
6432
|
+
targetKind: "name",
|
|
6433
|
+
playName,
|
|
6434
|
+
selector: options.revisionSelector,
|
|
6435
|
+
hasExplicitRevisionId: Boolean(options.revisionId)
|
|
6436
|
+
},
|
|
6437
|
+
() => resolveNamedRunRevisionId({
|
|
6438
|
+
client,
|
|
6439
|
+
playName,
|
|
6440
|
+
revisionId: options.revisionId,
|
|
6441
|
+
selector: options.revisionSelector
|
|
6442
|
+
})
|
|
6443
|
+
);
|
|
6444
|
+
const fileInputBindings = playDetail ? [
|
|
5946
6445
|
...fileInputBindingsFromPlaySchema(playDetail.play.inputSchema),
|
|
5947
6446
|
...fileInputBindingsFromStaticPipeline(playDetail.play.staticPipeline)
|
|
5948
|
-
];
|
|
6447
|
+
] : [];
|
|
5949
6448
|
applyCsvShortcutInput({
|
|
5950
6449
|
runtimeInput,
|
|
5951
6450
|
bindings: fileInputBindings
|
|
5952
6451
|
});
|
|
5953
|
-
const stagedFileInputs = await
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
6452
|
+
const stagedFileInputs = await traceCliSpan(
|
|
6453
|
+
"cli.play_stage_inputs",
|
|
6454
|
+
{
|
|
6455
|
+
targetKind: "name",
|
|
6456
|
+
playName,
|
|
6457
|
+
bindingCount: fileInputBindings.length
|
|
6458
|
+
},
|
|
6459
|
+
() => stageFileInputArgs({
|
|
6460
|
+
client,
|
|
6461
|
+
runtimeInput,
|
|
6462
|
+
bindings: fileInputBindings,
|
|
6463
|
+
progress
|
|
6464
|
+
})
|
|
6465
|
+
);
|
|
5959
6466
|
const startRequest = {
|
|
5960
|
-
name:
|
|
6467
|
+
name: playName,
|
|
5961
6468
|
...selectedRevisionId ? { revisionId: selectedRevisionId } : {},
|
|
5962
6469
|
...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
|
|
5963
6470
|
...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
|
|
@@ -5966,38 +6473,60 @@ async function handleNamedRun(options) {
|
|
|
5966
6473
|
};
|
|
5967
6474
|
if (options.watch) {
|
|
5968
6475
|
progress.phase("starting run");
|
|
5969
|
-
const finalStatus = await
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
6476
|
+
const finalStatus = await traceCliSpan(
|
|
6477
|
+
"cli.play_start_watch",
|
|
6478
|
+
{ targetKind: "name", playName },
|
|
6479
|
+
() => startAndWaitForPlayCompletionByStream({
|
|
6480
|
+
client,
|
|
6481
|
+
request: startRequest,
|
|
6482
|
+
playName,
|
|
6483
|
+
jsonOutput: options.jsonOutput,
|
|
6484
|
+
emitLogs: options.emitLogs,
|
|
6485
|
+
waitTimeoutMs: options.waitTimeoutMs,
|
|
6486
|
+
noOpen: options.noOpen,
|
|
6487
|
+
progress
|
|
6488
|
+
})
|
|
6489
|
+
);
|
|
6490
|
+
const exportedPath = traceCliSync(
|
|
6491
|
+
"cli.play_export_rows",
|
|
6492
|
+
{ targetKind: "name", playName },
|
|
6493
|
+
() => exportPlayStatusRows(finalStatus, options.outPath)
|
|
6494
|
+
);
|
|
5979
6495
|
if (finalStatus.status === "completed") {
|
|
5980
6496
|
progress.complete();
|
|
5981
6497
|
} else {
|
|
5982
6498
|
progress.fail();
|
|
5983
6499
|
}
|
|
5984
|
-
|
|
6500
|
+
traceCliSync(
|
|
6501
|
+
"cli.play_write_result",
|
|
6502
|
+
{ targetKind: "name", playName },
|
|
6503
|
+
() => writePlayResult(finalStatus, options.jsonOutput, { exportedPath })
|
|
6504
|
+
);
|
|
5985
6505
|
return finalStatus.status === "completed" ? 0 : 1;
|
|
5986
6506
|
}
|
|
5987
6507
|
progress.phase("starting run");
|
|
5988
|
-
const started = await
|
|
6508
|
+
const started = await traceCliSpan(
|
|
6509
|
+
"cli.play_start_unwatched",
|
|
6510
|
+
{ targetKind: "name", playName },
|
|
6511
|
+
() => client.startPlayRun(startRequest)
|
|
6512
|
+
);
|
|
5989
6513
|
const dashboardUrl = buildPlayDashboardUrl(
|
|
5990
6514
|
client.baseUrl,
|
|
5991
|
-
|
|
6515
|
+
playName
|
|
5992
6516
|
);
|
|
5993
|
-
|
|
6517
|
+
const resolvedDashboardUrl = started.dashboardUrl ?? dashboardUrl;
|
|
6518
|
+
openPlayDashboard({
|
|
6519
|
+
dashboardUrl: resolvedDashboardUrl,
|
|
6520
|
+
jsonOutput: options.jsonOutput,
|
|
6521
|
+
noOpen: options.noOpen
|
|
6522
|
+
});
|
|
6523
|
+
progress.phase(`loading play on ${resolvedDashboardUrl}`);
|
|
5994
6524
|
progress.complete();
|
|
5995
6525
|
writeStartedPlayRun({
|
|
5996
6526
|
runId: started.workflowId,
|
|
5997
|
-
playName: started.name ??
|
|
6527
|
+
playName: started.name ?? playName,
|
|
5998
6528
|
status: started.status,
|
|
5999
|
-
|
|
6000
|
-
dashboardUrl: started.dashboardUrl ?? dashboardUrl,
|
|
6529
|
+
dashboardUrl: resolvedDashboardUrl,
|
|
6001
6530
|
jsonOutput: options.jsonOutput,
|
|
6002
6531
|
progress
|
|
6003
6532
|
});
|
|
@@ -6011,8 +6540,8 @@ async function handlePlayRun(args) {
|
|
|
6011
6540
|
}
|
|
6012
6541
|
const resolved = resolve7(options.target.path);
|
|
6013
6542
|
console.error(`File not found: ${resolved}`);
|
|
6014
|
-
const dir =
|
|
6015
|
-
if (
|
|
6543
|
+
const dir = dirname7(resolved);
|
|
6544
|
+
if (existsSync5(dir)) {
|
|
6016
6545
|
const base = basename3(resolved);
|
|
6017
6546
|
try {
|
|
6018
6547
|
const siblings = readdirSync(dir).filter(
|
|
@@ -6040,7 +6569,7 @@ function parseRunIdPositional(args, usage) {
|
|
|
6040
6569
|
}
|
|
6041
6570
|
continue;
|
|
6042
6571
|
}
|
|
6043
|
-
if ((arg === "--out" || arg === "--
|
|
6572
|
+
if ((arg === "--out" || arg === "--reason") && args[index + 1]) {
|
|
6044
6573
|
index += 1;
|
|
6045
6574
|
continue;
|
|
6046
6575
|
}
|
|
@@ -6125,7 +6654,7 @@ async function handleRunsList(args) {
|
|
|
6125
6654
|
return 0;
|
|
6126
6655
|
}
|
|
6127
6656
|
async function handleRunTail(args) {
|
|
6128
|
-
const usage = "Usage: deepline runs tail <run-id> [--json] [--compact]
|
|
6657
|
+
const usage = "Usage: deepline runs tail <run-id> [--json] [--compact]";
|
|
6129
6658
|
let runId;
|
|
6130
6659
|
try {
|
|
6131
6660
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -6133,20 +6662,19 @@ async function handleRunTail(args) {
|
|
|
6133
6662
|
console.error(error instanceof Error ? error.message : usage);
|
|
6134
6663
|
return 1;
|
|
6135
6664
|
}
|
|
6136
|
-
const client = new DeeplineClient();
|
|
6137
|
-
let afterLogIndex;
|
|
6138
6665
|
for (let index = 0; index < args.length; index += 1) {
|
|
6139
6666
|
const arg = args[index];
|
|
6140
|
-
if (arg === "--cursor"
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6667
|
+
if (arg === "--cursor") {
|
|
6668
|
+
console.error("--cursor was removed. deepline runs tail reads the canonical run stream.");
|
|
6669
|
+
return 1;
|
|
6670
|
+
}
|
|
6671
|
+
if (arg.startsWith("--") && arg !== "--json" && arg !== "--compact") {
|
|
6672
|
+
console.error(`${arg} is not supported by deepline runs tail.`);
|
|
6673
|
+
return 1;
|
|
6145
6674
|
}
|
|
6146
6675
|
}
|
|
6147
|
-
const
|
|
6148
|
-
|
|
6149
|
-
});
|
|
6676
|
+
const client = new DeeplineClient();
|
|
6677
|
+
const status = await client.runs.tail(runId);
|
|
6150
6678
|
writePlayResult(status, argsWantJson(args));
|
|
6151
6679
|
return status.status === "failed" ? 1 : 0;
|
|
6152
6680
|
}
|
|
@@ -6175,7 +6703,7 @@ async function handleRunLogs(args) {
|
|
|
6175
6703
|
const status = await client.runs.get(runId);
|
|
6176
6704
|
const logs = status.progress?.logs ?? [];
|
|
6177
6705
|
if (outPath) {
|
|
6178
|
-
|
|
6706
|
+
writeFileSync5(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
6179
6707
|
if (argsWantJson(args)) {
|
|
6180
6708
|
process.stdout.write(
|
|
6181
6709
|
`${JSON.stringify({
|
|
@@ -6687,8 +7215,9 @@ function registerPlayCommands(program) {
|
|
|
6687
7215
|
"after",
|
|
6688
7216
|
`
|
|
6689
7217
|
Concepts:
|
|
6690
|
-
Plays are durable
|
|
6691
|
-
|
|
7218
|
+
Plays are durable cloud workflows.
|
|
7219
|
+
Stable ctx.tools.execute({ id, tool, input }) calls are replay-safe.
|
|
7220
|
+
ctx.map adds row keys and row progress.
|
|
6692
7221
|
|
|
6693
7222
|
Common commands:
|
|
6694
7223
|
deepline plays search email --json
|
|
@@ -6719,17 +7248,42 @@ Examples:
|
|
|
6719
7248
|
"after",
|
|
6720
7249
|
`
|
|
6721
7250
|
Notes:
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
7251
|
+
Local files are bundled, preflighted, then run in Deepline cloud.
|
|
7252
|
+
Named plays run the live saved revision.
|
|
7253
|
+
Unknown --foo and --foo.bar flags are treated as play input args.
|
|
7254
|
+
File args accept local paths; the CLI stages files before submit.
|
|
7255
|
+
--watch prints logs, previews, stats, and next commands.
|
|
7256
|
+
The play page opens in your browser as soon as the run starts; use --no-open
|
|
7257
|
+
to only print the URL.
|
|
7258
|
+
--force supersedes active runs; it does not bypass completed reuse.
|
|
7259
|
+
|
|
7260
|
+
Idempotent execution:
|
|
7261
|
+
Stable tool call ids are the reuse key:
|
|
7262
|
+
|
|
7263
|
+
await ctx.tools.execute({ id: 'company_lookup', tool, input });
|
|
7264
|
+
|
|
7265
|
+
For rows, use ctx.map plus a stable row key:
|
|
7266
|
+
|
|
7267
|
+
const rows = await ctx
|
|
7268
|
+
.map('companies_v1', companies)
|
|
7269
|
+
.step('cto', (row, ctx) => ctx.tools.execute({
|
|
7270
|
+
id: 'find_cto',
|
|
7271
|
+
tool: 'apollo_search_people_with_match',
|
|
7272
|
+
input: { q_organization_domains_list: [row.domain], per_page: 1 },
|
|
7273
|
+
}))
|
|
7274
|
+
.run({ key: 'domain' });
|
|
7275
|
+
|
|
7276
|
+
Reuse needs the same play, tool id, map name, row key, and compatible logic.
|
|
7277
|
+
To refresh, change the id/map key or set staleAfterSeconds:
|
|
7278
|
+
|
|
7279
|
+
.run({ key: 'domain', staleAfterSeconds: 86400 })
|
|
6728
7280
|
|
|
6729
7281
|
Examples:
|
|
6730
7282
|
deepline plays run my.play.ts --input '{"domain":"stripe.com"}' --watch
|
|
6731
7283
|
deepline plays run person-linkedin-to-email --input '{"linkedin_url":"..."}' --watch
|
|
6732
7284
|
deepline plays run enrich.play.ts --csv leads.csv --watch --out leads-enriched.csv
|
|
7285
|
+
deepline plays run cto-search.play.ts --limit 5 --watch
|
|
7286
|
+
deepline runs get <run-id>
|
|
6733
7287
|
`
|
|
6734
7288
|
).option("--file <path>", "Local play file to run").option("--name <name>", "Saved play name to run").option("-i, --input <json>", "Input JSON object or @file path").option("--live", "Run the current live revision explicitly").option("--latest", "Run the newest saved revision, even if it is not live").option(
|
|
6735
7289
|
"--revision-id <id>",
|
|
@@ -6740,7 +7294,7 @@ Examples:
|
|
|
6740
7294
|
).option("--watch", "Stream logs until completion").option(
|
|
6741
7295
|
"--logs",
|
|
6742
7296
|
"When output is non-interactive, stream play logs to stderr while waiting"
|
|
6743
|
-
).option("--
|
|
7297
|
+
).option("--tail-timeout-ms <ms>", "Timeout while watching the run stream").option("--force", "Supersede any active runs for this play").option("--no-open", "Print the play page URL without opening a browser").option("--json", "Emit JSON output").action(async (target, options, command) => {
|
|
6744
7298
|
const passthroughArgs = [...command.args];
|
|
6745
7299
|
const explicitTarget = options.file || options.name;
|
|
6746
7300
|
const targetIsInputFlag = typeof target === "string" && target.startsWith("--");
|
|
@@ -6762,9 +7316,9 @@ Examples:
|
|
|
6762
7316
|
...options.out ? ["--out", options.out] : [],
|
|
6763
7317
|
...options.watch ? ["--watch"] : [],
|
|
6764
7318
|
...options.logs ? ["--logs"] : [],
|
|
6765
|
-
...options.pollIntervalMs ? ["--poll-interval-ms", options.pollIntervalMs] : [],
|
|
6766
7319
|
...options.tailTimeoutMs ? ["--tail-timeout-ms", options.tailTimeoutMs] : [],
|
|
6767
7320
|
...options.force ? ["--force"] : [],
|
|
7321
|
+
...options.open === false ? ["--no-open"] : [],
|
|
6768
7322
|
...options.json ? ["--json"] : [],
|
|
6769
7323
|
...passthroughArgs
|
|
6770
7324
|
]);
|
|
@@ -6871,12 +7425,11 @@ Examples:
|
|
|
6871
7425
|
...options.json ? ["--json"] : []
|
|
6872
7426
|
]);
|
|
6873
7427
|
});
|
|
6874
|
-
runs.command("tail <runId>").description("
|
|
7428
|
+
runs.command("tail <runId>").description("Read the canonical live stream for a play run.").option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--compact", "Drop verbose fields from JSON output").action(async (runId, options) => {
|
|
6875
7429
|
process.exitCode = await handleRunTail([
|
|
6876
7430
|
runId,
|
|
6877
7431
|
...options.json ? ["--json"] : [],
|
|
6878
|
-
...options.compact ? ["--compact"] : []
|
|
6879
|
-
...options.cursor ? ["--cursor", options.cursor] : []
|
|
7432
|
+
...options.compact ? ["--compact"] : []
|
|
6880
7433
|
]);
|
|
6881
7434
|
});
|
|
6882
7435
|
runs.command("logs <runId>").description("Fetch persisted logs for a play run.").option("--limit <count>", "Maximum recent log lines to print without --out", "200").option("--out <path>", "Write the full persisted log stream to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
@@ -6905,12 +7458,12 @@ Examples:
|
|
|
6905
7458
|
}
|
|
6906
7459
|
|
|
6907
7460
|
// src/cli/commands/tools.ts
|
|
6908
|
-
import { chmodSync, mkdtempSync, writeFileSync as
|
|
7461
|
+
import { chmodSync, mkdtempSync, writeFileSync as writeFileSync7 } from "fs";
|
|
6909
7462
|
import { tmpdir as tmpdir3 } from "os";
|
|
6910
7463
|
import { join as join8 } from "path";
|
|
6911
7464
|
|
|
6912
7465
|
// src/tool-output.ts
|
|
6913
|
-
import { mkdirSync as
|
|
7466
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
6914
7467
|
import { homedir as homedir3 } from "os";
|
|
6915
7468
|
import { join as join7 } from "path";
|
|
6916
7469
|
function isPlainObject(value) {
|
|
@@ -6988,13 +7541,13 @@ function tryConvertToList(payload, options) {
|
|
|
6988
7541
|
}
|
|
6989
7542
|
function ensureOutputDir() {
|
|
6990
7543
|
const outputDir = join7(homedir3(), ".local", "share", "deepline", "data");
|
|
6991
|
-
|
|
7544
|
+
mkdirSync4(outputDir, { recursive: true });
|
|
6992
7545
|
return outputDir;
|
|
6993
7546
|
}
|
|
6994
7547
|
function writeJsonOutputFile(payload, stem) {
|
|
6995
7548
|
const outputDir = ensureOutputDir();
|
|
6996
7549
|
const outputPath = join7(outputDir, `${stem}_${Date.now()}.json`);
|
|
6997
|
-
|
|
7550
|
+
writeFileSync6(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
6998
7551
|
return outputPath;
|
|
6999
7552
|
}
|
|
7000
7553
|
function writeCsvOutputFile(rows, stem) {
|
|
@@ -7022,7 +7575,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
7022
7575
|
for (const row of rows) {
|
|
7023
7576
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
7024
7577
|
}
|
|
7025
|
-
|
|
7578
|
+
writeFileSync6(outputPath, `${lines.join("\n")}
|
|
7026
7579
|
`, "utf-8");
|
|
7027
7580
|
const previewRows = rows.slice(0, 5);
|
|
7028
7581
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -7559,7 +8112,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
7559
8112
|
};
|
|
7560
8113
|
});
|
|
7561
8114
|
`;
|
|
7562
|
-
|
|
8115
|
+
writeFileSync7(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
7563
8116
|
return {
|
|
7564
8117
|
path: scriptPath,
|
|
7565
8118
|
projectDir,
|
|
@@ -7666,10 +8219,10 @@ async function executeTool(args) {
|
|
|
7666
8219
|
}
|
|
7667
8220
|
|
|
7668
8221
|
// src/cli/skills-sync.ts
|
|
7669
|
-
import { spawn, spawnSync } from "child_process";
|
|
7670
|
-
import { existsSync as
|
|
8222
|
+
import { spawn, spawnSync as spawnSync2 } from "child_process";
|
|
8223
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
7671
8224
|
import { homedir as homedir4 } from "os";
|
|
7672
|
-
import { dirname as
|
|
8225
|
+
import { dirname as dirname8, join as join9 } from "path";
|
|
7673
8226
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
7674
8227
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
7675
8228
|
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
@@ -7684,7 +8237,7 @@ function sdkSkillsVersionPath(baseUrl) {
|
|
|
7684
8237
|
}
|
|
7685
8238
|
function readLocalSkillsVersion(baseUrl) {
|
|
7686
8239
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
7687
|
-
if (!
|
|
8240
|
+
if (!existsSync6(path)) return "";
|
|
7688
8241
|
try {
|
|
7689
8242
|
return readFileSync4(path, "utf-8").trim();
|
|
7690
8243
|
} catch {
|
|
@@ -7693,8 +8246,8 @@ function readLocalSkillsVersion(baseUrl) {
|
|
|
7693
8246
|
}
|
|
7694
8247
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
7695
8248
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
7696
|
-
|
|
7697
|
-
|
|
8249
|
+
mkdirSync5(dirname8(path), { recursive: true });
|
|
8250
|
+
writeFileSync8(path, `${version}
|
|
7698
8251
|
`, "utf-8");
|
|
7699
8252
|
}
|
|
7700
8253
|
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
@@ -7758,7 +8311,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
|
|
|
7758
8311
|
];
|
|
7759
8312
|
}
|
|
7760
8313
|
function hasCommand(command) {
|
|
7761
|
-
const result =
|
|
8314
|
+
const result = spawnSync2(command, ["--version"], {
|
|
7762
8315
|
stdio: "ignore",
|
|
7763
8316
|
shell: process.platform === "win32"
|
|
7764
8317
|
});
|
|
@@ -7857,54 +8410,6 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
7857
8410
|
writeSdkSkillsStatusLine("SDK skills are up to date.");
|
|
7858
8411
|
}
|
|
7859
8412
|
|
|
7860
|
-
// src/cli/trace.ts
|
|
7861
|
-
var cliTraceStartedAt = Date.now();
|
|
7862
|
-
function isTruthyEnv(value) {
|
|
7863
|
-
return value === "1" || value === "true" || value === "yes";
|
|
7864
|
-
}
|
|
7865
|
-
function isCliTraceEnabled() {
|
|
7866
|
-
return isTruthyEnv(process.env.DEEPLINE_CLI_TRACE);
|
|
7867
|
-
}
|
|
7868
|
-
function recordCliTrace(event) {
|
|
7869
|
-
if (!isCliTraceEnabled()) {
|
|
7870
|
-
return;
|
|
7871
|
-
}
|
|
7872
|
-
const now = Date.now();
|
|
7873
|
-
const payload = {
|
|
7874
|
-
ts: now,
|
|
7875
|
-
source: "cli",
|
|
7876
|
-
sinceStartMs: now - cliTraceStartedAt,
|
|
7877
|
-
...event
|
|
7878
|
-
};
|
|
7879
|
-
process.stderr.write(`[cli-trace] ${JSON.stringify(payload)}
|
|
7880
|
-
`);
|
|
7881
|
-
}
|
|
7882
|
-
async function traceCliSpan(phase, fields, run) {
|
|
7883
|
-
if (!isCliTraceEnabled()) {
|
|
7884
|
-
return run();
|
|
7885
|
-
}
|
|
7886
|
-
const startedAt = Date.now();
|
|
7887
|
-
try {
|
|
7888
|
-
const result = await run();
|
|
7889
|
-
recordCliTrace({
|
|
7890
|
-
phase,
|
|
7891
|
-
ms: Date.now() - startedAt,
|
|
7892
|
-
ok: true,
|
|
7893
|
-
...fields
|
|
7894
|
-
});
|
|
7895
|
-
return result;
|
|
7896
|
-
} catch (error) {
|
|
7897
|
-
recordCliTrace({
|
|
7898
|
-
phase,
|
|
7899
|
-
ms: Date.now() - startedAt,
|
|
7900
|
-
ok: false,
|
|
7901
|
-
error: error instanceof Error ? error.message : String(error),
|
|
7902
|
-
...fields
|
|
7903
|
-
});
|
|
7904
|
-
throw error;
|
|
7905
|
-
}
|
|
7906
|
-
}
|
|
7907
|
-
|
|
7908
8413
|
// src/cli/index.ts
|
|
7909
8414
|
function shouldPrintStartupPhase() {
|
|
7910
8415
|
if (process.argv.includes("--json")) {
|
|
@@ -7915,6 +8420,12 @@ function shouldPrintStartupPhase() {
|
|
|
7915
8420
|
const subcommand = args[1];
|
|
7916
8421
|
return (command === "play" || command === "plays") && subcommand === "run";
|
|
7917
8422
|
}
|
|
8423
|
+
function shouldDeferSkillsSyncForCommand() {
|
|
8424
|
+
const args = process.argv.slice(2);
|
|
8425
|
+
const command = args[0];
|
|
8426
|
+
const subcommand = args[1];
|
|
8427
|
+
return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
|
|
8428
|
+
}
|
|
7918
8429
|
async function main() {
|
|
7919
8430
|
const mainStartedAt = Date.now();
|
|
7920
8431
|
recordCliTrace({
|
|
@@ -7959,11 +8470,13 @@ Output:
|
|
|
7959
8470
|
if (printStartupPhase) {
|
|
7960
8471
|
progress?.phase("checking sdk skills");
|
|
7961
8472
|
}
|
|
7962
|
-
|
|
7963
|
-
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
8473
|
+
if (!shouldDeferSkillsSyncForCommand()) {
|
|
8474
|
+
await traceCliSpan(
|
|
8475
|
+
"cli.sdk_skills_sync",
|
|
8476
|
+
{ baseUrl },
|
|
8477
|
+
() => syncSdkSkillsIfNeeded(baseUrl)
|
|
8478
|
+
);
|
|
8479
|
+
}
|
|
7967
8480
|
});
|
|
7968
8481
|
registerAuthCommands(program);
|
|
7969
8482
|
registerToolsCommands(program);
|