deepline 0.1.21 → 0.1.23
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 +552 -237
- package/dist/cli/index.mjs +609 -289
- package/dist/index.d.mts +21 -58
- package/dist/index.d.ts +21 -58
- package/dist/index.js +177 -92
- package/dist/index.mjs +177 -92
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +3 -1
- package/dist/repo/apps/play-runner-workers/src/entry.ts +153 -0
- package/dist/repo/sdk/src/client.ts +243 -124
- 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/execution-plan.ts +27 -2
- package/dist/repo/shared_libs/play-runtime/profiles.ts +4 -14
- package/dist/repo/shared_libs/play-runtime/runtime-actions.ts +1 -1
- 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.23";
|
|
247
247
|
var SDK_API_CONTRACT = "2026-05-runs-v2";
|
|
248
248
|
|
|
249
249
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
@@ -531,11 +531,24 @@ function sleep(ms) {
|
|
|
531
531
|
// src/client.ts
|
|
532
532
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
533
533
|
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
534
|
+
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
535
|
+
function sleep2(ms) {
|
|
536
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
537
|
+
}
|
|
538
|
+
function isTransientCompileManifestError(error) {
|
|
539
|
+
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
540
|
+
return error.statusCode === 408 || error.statusCode === 425 || error.statusCode === 499 || error.statusCode >= 500 && error.statusCode < 600;
|
|
541
|
+
}
|
|
542
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
543
|
+
return /fetch failed|connection (?:closed|reset|terminated)|socket hang up|econnreset|etimedout|eai_again|abort/i.test(
|
|
544
|
+
message
|
|
545
|
+
);
|
|
546
|
+
}
|
|
534
547
|
function isRecord(value) {
|
|
535
548
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
536
549
|
}
|
|
537
550
|
function normalizePlayStatus(raw) {
|
|
538
|
-
const status = typeof raw.status === "string" ? raw.status :
|
|
551
|
+
const status = typeof raw.status === "string" ? raw.status : "running";
|
|
539
552
|
const runId = typeof raw.runId === "string" ? raw.runId : typeof raw.workflowId === "string" ? raw.workflowId : "";
|
|
540
553
|
return {
|
|
541
554
|
...raw,
|
|
@@ -543,23 +556,6 @@ function normalizePlayStatus(raw) {
|
|
|
543
556
|
status
|
|
544
557
|
};
|
|
545
558
|
}
|
|
546
|
-
function mapLegacyTemporalStatus(status) {
|
|
547
|
-
switch (status.trim().toUpperCase()) {
|
|
548
|
-
case "PENDING":
|
|
549
|
-
return "queued";
|
|
550
|
-
case "COMPLETED":
|
|
551
|
-
return "completed";
|
|
552
|
-
case "FAILED":
|
|
553
|
-
return "failed";
|
|
554
|
-
case "CANCELLED":
|
|
555
|
-
case "TERMINATED":
|
|
556
|
-
case "TIMED_OUT":
|
|
557
|
-
return "cancelled";
|
|
558
|
-
case "RUNNING":
|
|
559
|
-
default:
|
|
560
|
-
return "running";
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
559
|
function decodeBase64Bytes(value) {
|
|
564
560
|
const binary = atob(value);
|
|
565
561
|
const bytes = new Uint8Array(binary.length);
|
|
@@ -568,6 +564,79 @@ function decodeBase64Bytes(value) {
|
|
|
568
564
|
}
|
|
569
565
|
return bytes;
|
|
570
566
|
}
|
|
567
|
+
function readStringArray(value) {
|
|
568
|
+
return Array.isArray(value) ? value.filter((line) => typeof line === "string") : [];
|
|
569
|
+
}
|
|
570
|
+
function getPlayLiveEventPayload(event) {
|
|
571
|
+
return event.payload && typeof event.payload === "object" ? event.payload : {};
|
|
572
|
+
}
|
|
573
|
+
function normalizeLiveStatus(value) {
|
|
574
|
+
if (value === "queued" || value === "running" || value === "waiting" || value === "completed" || value === "failed" || value === "cancelled") {
|
|
575
|
+
return value;
|
|
576
|
+
}
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
579
|
+
function updatePlayLiveStatusState(state, event) {
|
|
580
|
+
const payload = getPlayLiveEventPayload(event);
|
|
581
|
+
if (event.type === "play.run.log") {
|
|
582
|
+
state.logs.push(...readStringArray(payload.lines));
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
if (event.type !== "play.run.snapshot" && event.type !== "play.run.status" && event.type !== "play.run.final_status") {
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
const runId = typeof payload.runId === "string" && payload.runId ? payload.runId : state.runId;
|
|
589
|
+
const status = normalizeLiveStatus(payload.status) ?? state.status;
|
|
590
|
+
const logs = readStringArray(payload.logs);
|
|
591
|
+
if (logs.length > 0 || event.type === "play.run.snapshot") {
|
|
592
|
+
state.logs = logs;
|
|
593
|
+
}
|
|
594
|
+
if ("result" in payload) {
|
|
595
|
+
state.result = payload.result;
|
|
596
|
+
}
|
|
597
|
+
if (typeof payload.error === "string" && payload.error.trim()) {
|
|
598
|
+
state.error = payload.error;
|
|
599
|
+
}
|
|
600
|
+
state.runId = runId;
|
|
601
|
+
state.status = status;
|
|
602
|
+
const progressRecord = payload.progress && typeof payload.progress === "object" && !Array.isArray(payload.progress) ? payload.progress : {};
|
|
603
|
+
const next = {
|
|
604
|
+
...payload,
|
|
605
|
+
runId,
|
|
606
|
+
status,
|
|
607
|
+
progress: {
|
|
608
|
+
...progressRecord,
|
|
609
|
+
status: typeof progressRecord.status === "string" ? progressRecord.status : status,
|
|
610
|
+
logs: state.logs,
|
|
611
|
+
...state.error ? { error: state.error } : {}
|
|
612
|
+
},
|
|
613
|
+
..."result" in state ? { result: state.result } : {}
|
|
614
|
+
};
|
|
615
|
+
state.latest = next;
|
|
616
|
+
return next;
|
|
617
|
+
}
|
|
618
|
+
function playRunResultFromStatus(status, startedAt, fallbackRunId) {
|
|
619
|
+
return {
|
|
620
|
+
success: status.status === "completed",
|
|
621
|
+
runId: status.runId || fallbackRunId,
|
|
622
|
+
result: status.result,
|
|
623
|
+
logs: status.progress?.logs ?? [],
|
|
624
|
+
durationMs: Date.now() - startedAt,
|
|
625
|
+
error: status.progress?.error ?? (status.status !== "completed" ? status.status : void 0)
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
function playRunStatusFromState(state) {
|
|
629
|
+
return {
|
|
630
|
+
runId: state.runId,
|
|
631
|
+
status: state.status,
|
|
632
|
+
progress: {
|
|
633
|
+
status: state.status,
|
|
634
|
+
logs: state.logs,
|
|
635
|
+
...state.error ? { error: state.error } : {}
|
|
636
|
+
},
|
|
637
|
+
..."result" in state ? { result: state.result } : {}
|
|
638
|
+
};
|
|
639
|
+
}
|
|
571
640
|
var DeeplineClient = class {
|
|
572
641
|
http;
|
|
573
642
|
config;
|
|
@@ -677,7 +746,7 @@ var DeeplineClient = class {
|
|
|
677
746
|
/**
|
|
678
747
|
* Search available tools using Deepline's ranked backend search.
|
|
679
748
|
*
|
|
680
|
-
* This is the same discovery surface used by the
|
|
749
|
+
* This is the same discovery surface used by the CLI: it ranks across
|
|
681
750
|
* tool metadata, categories, agent guidance, and input schema fields.
|
|
682
751
|
*/
|
|
683
752
|
async searchTools(options = {}) {
|
|
@@ -770,7 +839,7 @@ var DeeplineClient = class {
|
|
|
770
839
|
* `progress.logs`; they are not part of the user output object.
|
|
771
840
|
*
|
|
772
841
|
* @param request - Play run configuration (name, code, input, etc.)
|
|
773
|
-
* @returns
|
|
842
|
+
* @returns Run metadata including the public `workflowId`
|
|
774
843
|
*
|
|
775
844
|
* @example
|
|
776
845
|
* ```typescript
|
|
@@ -880,8 +949,22 @@ var DeeplineClient = class {
|
|
|
880
949
|
});
|
|
881
950
|
}
|
|
882
951
|
async compilePlayManifest(input) {
|
|
883
|
-
const
|
|
884
|
-
|
|
952
|
+
const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
|
|
953
|
+
0,
|
|
954
|
+
Math.max(0, this.config.maxRetries)
|
|
955
|
+
);
|
|
956
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
957
|
+
try {
|
|
958
|
+
const response = await this.http.post("/api/v2/plays/compile-manifest", input);
|
|
959
|
+
return response.compilerManifest;
|
|
960
|
+
} catch (error) {
|
|
961
|
+
const delayMs = retryDelays[attempt];
|
|
962
|
+
if (delayMs === void 0 || !isTransientCompileManifestError(error)) {
|
|
963
|
+
throw error;
|
|
964
|
+
}
|
|
965
|
+
await sleep2(delayMs);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
885
968
|
}
|
|
886
969
|
/**
|
|
887
970
|
* Check a bundled play artifact against the server's current play compiler.
|
|
@@ -1062,9 +1145,6 @@ var DeeplineClient = class {
|
|
|
1062
1145
|
* Internal/advanced primitive. Public callers should usually prefer
|
|
1063
1146
|
* {@link runPlay}, {@link PlayJob.get}, or `deepline play run --watch`.
|
|
1064
1147
|
*
|
|
1065
|
-
* Poll this method until `status` reaches a terminal state:
|
|
1066
|
-
* `'completed'`, `'failed'`, or `'cancelled'`.
|
|
1067
|
-
*
|
|
1068
1148
|
* @param workflowId - Play-run id from {@link startPlayRun}
|
|
1069
1149
|
* @returns Current status with progress logs and partial results
|
|
1070
1150
|
*
|
|
@@ -1086,35 +1166,11 @@ var DeeplineClient = class {
|
|
|
1086
1166
|
);
|
|
1087
1167
|
return normalizePlayStatus(response);
|
|
1088
1168
|
}
|
|
1089
|
-
/**
|
|
1090
|
-
* Get the lightweight tail-polling status for a play execution.
|
|
1091
|
-
*
|
|
1092
|
-
* This is intentionally smaller than {@link getPlayStatus}: it returns the
|
|
1093
|
-
* fields needed for CLI log tailing while the run is in flight, without
|
|
1094
|
-
* forcing the API to rebuild final result views on every poll. Call
|
|
1095
|
-
* {@link getPlayStatus} once after a terminal state for the full result.
|
|
1096
|
-
*/
|
|
1097
|
-
async getPlayTailStatus(workflowId, options) {
|
|
1098
|
-
const params = new URLSearchParams({ mode: "tail" });
|
|
1099
|
-
if (typeof options?.afterLogIndex === "number") {
|
|
1100
|
-
params.set("afterLogIndex", String(options.afterLogIndex));
|
|
1101
|
-
}
|
|
1102
|
-
if (typeof options?.waitMs === "number") {
|
|
1103
|
-
params.set("waitMs", String(options.waitMs));
|
|
1104
|
-
}
|
|
1105
|
-
if (options?.terminalOnly) {
|
|
1106
|
-
params.set("terminalOnly", "true");
|
|
1107
|
-
}
|
|
1108
|
-
const response = await this.http.get(
|
|
1109
|
-
`/api/v2/plays/run/${encodeURIComponent(workflowId)}?${params.toString()}`
|
|
1110
|
-
);
|
|
1111
|
-
return normalizePlayStatus(response);
|
|
1112
|
-
}
|
|
1113
1169
|
/**
|
|
1114
1170
|
* Stream semantic play-run events using the same SSE feed as the dashboard.
|
|
1115
1171
|
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1172
|
+
* The server emits a canonical `play.run.snapshot` event first for every
|
|
1173
|
+
* connection, then incremental live events until terminal state or reconnect.
|
|
1118
1174
|
*/
|
|
1119
1175
|
async *streamPlayRunEvents(workflowId, options) {
|
|
1120
1176
|
const headers = options?.lastEventId && options.lastEventId.trim() ? { "Last-Event-ID": options.lastEventId.trim() } : void 0;
|
|
@@ -1134,7 +1190,7 @@ var DeeplineClient = class {
|
|
|
1134
1190
|
*
|
|
1135
1191
|
* Sends a stop request for the run.
|
|
1136
1192
|
*
|
|
1137
|
-
* @param workflowId -
|
|
1193
|
+
* @param workflowId - Public Deepline play-run id to cancel
|
|
1138
1194
|
*
|
|
1139
1195
|
* @example
|
|
1140
1196
|
* ```typescript
|
|
@@ -1150,7 +1206,7 @@ var DeeplineClient = class {
|
|
|
1150
1206
|
/**
|
|
1151
1207
|
* Stop a running play execution, including open HITL waits.
|
|
1152
1208
|
*
|
|
1153
|
-
* @param workflowId -
|
|
1209
|
+
* @param workflowId - Public Deepline play-run id to stop
|
|
1154
1210
|
* @param options.reason - Optional audit/debug reason
|
|
1155
1211
|
*/
|
|
1156
1212
|
async stopPlay(workflowId, options) {
|
|
@@ -1222,32 +1278,42 @@ var DeeplineClient = class {
|
|
|
1222
1278
|
);
|
|
1223
1279
|
return response.runs ?? [];
|
|
1224
1280
|
}
|
|
1225
|
-
/**
|
|
1226
|
-
* Fetch the lightweight tail status for a run using the public runs resource model.
|
|
1227
|
-
*
|
|
1228
|
-
* This is the SDK equivalent of:
|
|
1229
|
-
*
|
|
1230
|
-
* ```bash
|
|
1231
|
-
* deepline runs tail <run-id> --json
|
|
1232
|
-
* ```
|
|
1233
|
-
*/
|
|
1281
|
+
/** Read the canonical run stream and return the latest run snapshot. */
|
|
1234
1282
|
async tailRun(runId, options) {
|
|
1235
|
-
const
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1283
|
+
const state = {
|
|
1284
|
+
runId,
|
|
1285
|
+
status: "running",
|
|
1286
|
+
logs: [],
|
|
1287
|
+
latest: null
|
|
1288
|
+
};
|
|
1289
|
+
let terminal = false;
|
|
1290
|
+
for await (const event of this.streamPlayRunEvents(runId, {
|
|
1291
|
+
mode: "cli",
|
|
1292
|
+
signal: options?.signal
|
|
1293
|
+
})) {
|
|
1294
|
+
const status = updatePlayLiveStatusState(state, event);
|
|
1295
|
+
if (!status) {
|
|
1296
|
+
continue;
|
|
1297
|
+
}
|
|
1298
|
+
terminal = TERMINAL_PLAY_STATUSES.has(status.status);
|
|
1299
|
+
if (terminal) {
|
|
1300
|
+
break;
|
|
1301
|
+
}
|
|
1239
1302
|
}
|
|
1240
|
-
if (
|
|
1241
|
-
|
|
1303
|
+
if (terminal && state.latest) {
|
|
1304
|
+
return await this.getRunStatus(state.latest.runId || runId).catch(
|
|
1305
|
+
() => state.latest ?? playRunStatusFromState(state)
|
|
1306
|
+
);
|
|
1242
1307
|
}
|
|
1243
|
-
if (
|
|
1244
|
-
|
|
1308
|
+
if (state.latest) {
|
|
1309
|
+
return state.latest;
|
|
1245
1310
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1311
|
+
throw new DeeplineError(
|
|
1312
|
+
`Run stream for ${runId} ended before the initial snapshot.`,
|
|
1313
|
+
void 0,
|
|
1314
|
+
"PLAY_RUN_STREAM_EMPTY",
|
|
1315
|
+
{ runId }
|
|
1249
1316
|
);
|
|
1250
|
-
return normalizePlayStatus(response);
|
|
1251
1317
|
}
|
|
1252
1318
|
/**
|
|
1253
1319
|
* Fetch persisted logs for a run using the public runs resource model.
|
|
@@ -1404,11 +1470,11 @@ var DeeplineClient = class {
|
|
|
1404
1470
|
// Plays — high-level orchestration
|
|
1405
1471
|
// ——————————————————————————————————————————————————————————
|
|
1406
1472
|
/**
|
|
1407
|
-
* Run a play end-to-end: submit,
|
|
1473
|
+
* Run a play end-to-end: submit, stream until terminal, return result.
|
|
1408
1474
|
*
|
|
1409
1475
|
* This is the highest-level play execution method. It submits the play,
|
|
1410
|
-
*
|
|
1411
|
-
* and timing. Supports cancellation via `AbortSignal`.
|
|
1476
|
+
* reads the canonical run stream for status updates, and returns a structured
|
|
1477
|
+
* result with logs and timing. Supports cancellation via `AbortSignal`.
|
|
1412
1478
|
*
|
|
1413
1479
|
* @param code - Source string fallback; pass the bundled artifact in `options.artifact`
|
|
1414
1480
|
* @param csvPath - Input CSV path, or `null`
|
|
@@ -1424,7 +1490,6 @@ var DeeplineClient = class {
|
|
|
1424
1490
|
* const logs = status.progress?.logs ?? [];
|
|
1425
1491
|
* console.log(`[${status.status}] ${logs.length} log lines`);
|
|
1426
1492
|
* },
|
|
1427
|
-
* pollIntervalMs: 1000,
|
|
1428
1493
|
* });
|
|
1429
1494
|
*
|
|
1430
1495
|
* if (result.success) {
|
|
@@ -1455,33 +1520,53 @@ var DeeplineClient = class {
|
|
|
1455
1520
|
packagedFiles: options?.packagedFiles,
|
|
1456
1521
|
force: options?.force
|
|
1457
1522
|
});
|
|
1458
|
-
const pollInterval = options?.pollIntervalMs ?? 500;
|
|
1459
1523
|
const start = Date.now();
|
|
1460
|
-
|
|
1524
|
+
const state = {
|
|
1525
|
+
runId: workflowId,
|
|
1526
|
+
status: "running",
|
|
1527
|
+
logs: [],
|
|
1528
|
+
latest: null
|
|
1529
|
+
};
|
|
1530
|
+
if (options?.signal?.aborted) {
|
|
1531
|
+
await this.cancelPlay(workflowId);
|
|
1532
|
+
return {
|
|
1533
|
+
success: false,
|
|
1534
|
+
runId: workflowId,
|
|
1535
|
+
logs: [],
|
|
1536
|
+
durationMs: Date.now() - start,
|
|
1537
|
+
error: "Cancelled by user"
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
for await (const event of this.streamPlayRunEvents(workflowId, {
|
|
1541
|
+
mode: "cli",
|
|
1542
|
+
signal: options?.signal
|
|
1543
|
+
})) {
|
|
1461
1544
|
if (options?.signal?.aborted) {
|
|
1462
1545
|
await this.cancelPlay(workflowId);
|
|
1463
1546
|
return {
|
|
1464
1547
|
success: false,
|
|
1465
1548
|
runId: workflowId,
|
|
1466
|
-
logs:
|
|
1549
|
+
logs: state.logs,
|
|
1467
1550
|
durationMs: Date.now() - start,
|
|
1468
1551
|
error: "Cancelled by user"
|
|
1469
1552
|
};
|
|
1470
1553
|
}
|
|
1471
|
-
const status =
|
|
1554
|
+
const status = updatePlayLiveStatusState(state, event);
|
|
1555
|
+
if (!status) {
|
|
1556
|
+
continue;
|
|
1557
|
+
}
|
|
1472
1558
|
options?.onProgress?.(status);
|
|
1473
1559
|
if (TERMINAL_PLAY_STATUSES.has(status.status)) {
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
runId: status.runId || workflowId,
|
|
1477
|
-
result: status.result,
|
|
1478
|
-
logs: status.progress?.logs ?? [],
|
|
1479
|
-
durationMs: Date.now() - start,
|
|
1480
|
-
error: status.progress?.error ?? (status.status !== "completed" ? status.status : void 0)
|
|
1481
|
-
};
|
|
1560
|
+
const finalStatus = await this.getPlayStatus(status.runId || workflowId).catch(() => status);
|
|
1561
|
+
return playRunResultFromStatus(finalStatus, start, workflowId);
|
|
1482
1562
|
}
|
|
1483
|
-
await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
|
|
1484
1563
|
}
|
|
1564
|
+
throw new DeeplineError(
|
|
1565
|
+
`Run stream for ${workflowId} ended before the run reached a terminal state.`,
|
|
1566
|
+
void 0,
|
|
1567
|
+
"PLAY_RUN_STREAM_ENDED",
|
|
1568
|
+
{ runId: workflowId, workflowId }
|
|
1569
|
+
);
|
|
1485
1570
|
}
|
|
1486
1571
|
// ——————————————————————————————————————————————————————————
|
|
1487
1572
|
// Health
|
|
@@ -1555,18 +1640,24 @@ async function enforceSdkCompatibility(baseUrl) {
|
|
|
1555
1640
|
}
|
|
1556
1641
|
|
|
1557
1642
|
// src/cli/commands/auth.ts
|
|
1558
|
-
import { writeFileSync as
|
|
1643
|
+
import { writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
1559
1644
|
import { hostname } from "os";
|
|
1560
|
-
import { dirname as
|
|
1645
|
+
import { dirname as dirname3 } from "path";
|
|
1561
1646
|
|
|
1562
1647
|
// src/cli/utils.ts
|
|
1563
|
-
import {
|
|
1648
|
+
import {
|
|
1649
|
+
existsSync as existsSync2,
|
|
1650
|
+
mkdirSync as mkdirSync2,
|
|
1651
|
+
readFileSync as readFileSync2,
|
|
1652
|
+
writeFileSync as writeFileSync2
|
|
1653
|
+
} from "fs";
|
|
1564
1654
|
import { mkdir, writeFile } from "fs/promises";
|
|
1565
1655
|
import { homedir as homedir2 } from "os";
|
|
1566
|
-
import { join as join2, resolve as resolve2 } from "path";
|
|
1567
|
-
import {
|
|
1656
|
+
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
1657
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
1568
1658
|
import { parse } from "csv-parse/sync";
|
|
1569
1659
|
import { stringify } from "csv-stringify/sync";
|
|
1660
|
+
var BROWSER_FOCUS_COOLDOWN_MS = 3e4;
|
|
1570
1661
|
function getAuthedHttpClient() {
|
|
1571
1662
|
const config = resolveConfig();
|
|
1572
1663
|
return { config, http: new HttpClient(config) };
|
|
@@ -1578,12 +1669,215 @@ async function writeOutputFile(filename, content) {
|
|
|
1578
1669
|
await writeFile(fullPath, content, "utf-8");
|
|
1579
1670
|
return fullPath;
|
|
1580
1671
|
}
|
|
1672
|
+
function browserFocusStateFile() {
|
|
1673
|
+
const homeDir = process.env.HOME || homedir2();
|
|
1674
|
+
return join2(
|
|
1675
|
+
homeDir,
|
|
1676
|
+
".local",
|
|
1677
|
+
"deepline",
|
|
1678
|
+
"runtime",
|
|
1679
|
+
"state",
|
|
1680
|
+
"browser-focus.json"
|
|
1681
|
+
);
|
|
1682
|
+
}
|
|
1683
|
+
function claimBrowserFocus(now = Date.now()) {
|
|
1684
|
+
const statePath = browserFocusStateFile();
|
|
1685
|
+
try {
|
|
1686
|
+
mkdirSync2(dirname2(statePath), { recursive: true });
|
|
1687
|
+
let lastFocusedAt = 0;
|
|
1688
|
+
if (existsSync2(statePath)) {
|
|
1689
|
+
const payload = JSON.parse(readFileSync2(statePath, "utf-8"));
|
|
1690
|
+
const value = payload.lastFocusedAt ?? payload.last_focused_at;
|
|
1691
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1692
|
+
lastFocusedAt = value;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
if (lastFocusedAt > now) {
|
|
1696
|
+
lastFocusedAt = 0;
|
|
1697
|
+
}
|
|
1698
|
+
if (now - lastFocusedAt < BROWSER_FOCUS_COOLDOWN_MS) {
|
|
1699
|
+
return false;
|
|
1700
|
+
}
|
|
1701
|
+
writeFileSync2(statePath, JSON.stringify({ lastFocusedAt: now }), "utf-8");
|
|
1702
|
+
return true;
|
|
1703
|
+
} catch {
|
|
1704
|
+
return true;
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
function extractUrlHost(raw) {
|
|
1708
|
+
try {
|
|
1709
|
+
const parsed = new URL(raw.includes("://") ? raw : `https://${raw}`);
|
|
1710
|
+
return parsed.port ? `${parsed.hostname.toLowerCase()}:${parsed.port}` : parsed.hostname.toLowerCase();
|
|
1711
|
+
} catch {
|
|
1712
|
+
return "";
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
function browserAppNameFromBundleId(bundleId) {
|
|
1716
|
+
const names = {
|
|
1717
|
+
"com.google.chrome": "Google Chrome",
|
|
1718
|
+
"com.google.chrome.canary": "Google Chrome Canary",
|
|
1719
|
+
"com.microsoft.edgemac": "Microsoft Edge",
|
|
1720
|
+
"com.brave.browser": "Brave Browser",
|
|
1721
|
+
"com.operasoftware.opera": "Opera",
|
|
1722
|
+
"com.operasoftware.operagx": "Opera GX",
|
|
1723
|
+
"com.vivaldi.vivaldi": "Vivaldi",
|
|
1724
|
+
"company.thebrowser.browser": "Arc",
|
|
1725
|
+
"com.apple.safari": "Safari"
|
|
1726
|
+
};
|
|
1727
|
+
return names[bundleId.toLowerCase()] ?? "";
|
|
1728
|
+
}
|
|
1729
|
+
function readDefaultMacBrowserBundleId() {
|
|
1730
|
+
try {
|
|
1731
|
+
const output = execFileSync(
|
|
1732
|
+
"/usr/bin/defaults",
|
|
1733
|
+
[
|
|
1734
|
+
"read",
|
|
1735
|
+
`${homedir2()}/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist`,
|
|
1736
|
+
"LSHandlers"
|
|
1737
|
+
],
|
|
1738
|
+
{ encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
1739
|
+
);
|
|
1740
|
+
const httpsMatch = output.match(
|
|
1741
|
+
/LSHandlerURLScheme\s*=\s*https;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1742
|
+
);
|
|
1743
|
+
const httpMatch = output.match(
|
|
1744
|
+
/LSHandlerURLScheme\s*=\s*http;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1745
|
+
);
|
|
1746
|
+
return (httpsMatch?.[1] ?? httpMatch?.[1] ?? "").trim();
|
|
1747
|
+
} catch {
|
|
1748
|
+
return "";
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
function browserStrategyForBundleId(bundleId) {
|
|
1752
|
+
const normalized = bundleId.toLowerCase();
|
|
1753
|
+
if ((/* @__PURE__ */ new Set([
|
|
1754
|
+
"com.google.chrome",
|
|
1755
|
+
"com.google.chrome.canary",
|
|
1756
|
+
"com.microsoft.edgemac",
|
|
1757
|
+
"com.brave.browser",
|
|
1758
|
+
"com.operasoftware.opera",
|
|
1759
|
+
"com.operasoftware.operagx",
|
|
1760
|
+
"com.vivaldi.vivaldi",
|
|
1761
|
+
"company.thebrowser.browser"
|
|
1762
|
+
])).has(normalized)) {
|
|
1763
|
+
return "chromium";
|
|
1764
|
+
}
|
|
1765
|
+
return normalized === "com.apple.safari" ? "safari" : "fallback";
|
|
1766
|
+
}
|
|
1767
|
+
function runAppleScript(script, args) {
|
|
1768
|
+
const result = spawnSync("osascript", ["-", ...args], {
|
|
1769
|
+
input: script,
|
|
1770
|
+
encoding: "utf-8",
|
|
1771
|
+
stdio: ["pipe", "ignore", "ignore"],
|
|
1772
|
+
timeout: 5e3
|
|
1773
|
+
});
|
|
1774
|
+
return result.status === 0;
|
|
1775
|
+
}
|
|
1776
|
+
function retargetChromiumMacos(appName, targetUrl, allowFocus) {
|
|
1777
|
+
const host = extractUrlHost(targetUrl);
|
|
1778
|
+
if (!host) return false;
|
|
1779
|
+
const escapedAppName = appName.replace(/"/g, '\\"');
|
|
1780
|
+
const activateBlock = allowFocus ? " activate\n" : "";
|
|
1781
|
+
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";
|
|
1782
|
+
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";
|
|
1783
|
+
const script = `
|
|
1784
|
+
on run argv
|
|
1785
|
+
set targetUrl to item 1 of argv
|
|
1786
|
+
set targetHost to item 2 of argv
|
|
1787
|
+
tell application "${escapedAppName}"
|
|
1788
|
+
${activateBlock} if (count of windows) is 0 then
|
|
1789
|
+
make new window
|
|
1790
|
+
end if
|
|
1791
|
+
set foundTab to false
|
|
1792
|
+
repeat with w in windows
|
|
1793
|
+
set tabCount to count of tabs of w
|
|
1794
|
+
repeat with i from 1 to tabCount
|
|
1795
|
+
set t to tab i of w
|
|
1796
|
+
if (URL of t) contains targetHost then
|
|
1797
|
+
${foundTabBlock} set foundTab to true
|
|
1798
|
+
exit repeat
|
|
1799
|
+
end if
|
|
1800
|
+
end repeat
|
|
1801
|
+
if foundTab then exit repeat
|
|
1802
|
+
end repeat
|
|
1803
|
+
if not foundTab then
|
|
1804
|
+
${newTabBlock} end if
|
|
1805
|
+
end tell
|
|
1806
|
+
end run
|
|
1807
|
+
`;
|
|
1808
|
+
return runAppleScript(script, [targetUrl, host]);
|
|
1809
|
+
}
|
|
1810
|
+
function retargetSafariMacos(appName, targetUrl, allowFocus) {
|
|
1811
|
+
const host = extractUrlHost(targetUrl);
|
|
1812
|
+
if (!host) return false;
|
|
1813
|
+
const escapedAppName = appName.replace(/"/g, '\\"');
|
|
1814
|
+
const activateBlock = allowFocus ? " activate\n" : "";
|
|
1815
|
+
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";
|
|
1816
|
+
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";
|
|
1817
|
+
const script = `
|
|
1818
|
+
on run argv
|
|
1819
|
+
set targetUrl to item 1 of argv
|
|
1820
|
+
set targetHost to item 2 of argv
|
|
1821
|
+
tell application "${escapedAppName}"
|
|
1822
|
+
${activateBlock} if (count of windows) is 0 then
|
|
1823
|
+
make new document
|
|
1824
|
+
end if
|
|
1825
|
+
set foundTab to false
|
|
1826
|
+
repeat with w in windows
|
|
1827
|
+
set tabCount to count of tabs of w
|
|
1828
|
+
repeat with i from 1 to tabCount
|
|
1829
|
+
set t to tab i of w
|
|
1830
|
+
if (URL of t) contains targetHost then
|
|
1831
|
+
${foundTabBlock} set foundTab to true
|
|
1832
|
+
exit repeat
|
|
1833
|
+
end if
|
|
1834
|
+
end repeat
|
|
1835
|
+
if foundTab then exit repeat
|
|
1836
|
+
end repeat
|
|
1837
|
+
if not foundTab then
|
|
1838
|
+
${newTabBlock} end if
|
|
1839
|
+
end tell
|
|
1840
|
+
end run
|
|
1841
|
+
`;
|
|
1842
|
+
return runAppleScript(script, [targetUrl, host]);
|
|
1843
|
+
}
|
|
1844
|
+
function openUrlMacos(targetUrl, allowFocus) {
|
|
1845
|
+
const defaultBundleId = readDefaultMacBrowserBundleId();
|
|
1846
|
+
const appName = defaultBundleId ? browserAppNameFromBundleId(defaultBundleId) : "";
|
|
1847
|
+
const strategy = browserStrategyForBundleId(defaultBundleId);
|
|
1848
|
+
if (appName && strategy === "chromium" && retargetChromiumMacos(appName, targetUrl, allowFocus)) {
|
|
1849
|
+
return true;
|
|
1850
|
+
}
|
|
1851
|
+
if (appName && strategy === "safari" && retargetSafariMacos(appName, targetUrl, allowFocus)) {
|
|
1852
|
+
return true;
|
|
1853
|
+
}
|
|
1854
|
+
if (!allowFocus) {
|
|
1855
|
+
return false;
|
|
1856
|
+
}
|
|
1857
|
+
try {
|
|
1858
|
+
execFileSync("open", [targetUrl], { stdio: "ignore" });
|
|
1859
|
+
return true;
|
|
1860
|
+
} catch {
|
|
1861
|
+
return false;
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1581
1864
|
function openInBrowser(url) {
|
|
1582
1865
|
try {
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1866
|
+
const targetUrl = String(url || "").trim();
|
|
1867
|
+
if (!targetUrl) return;
|
|
1868
|
+
const allowFocus = claimBrowserFocus();
|
|
1869
|
+
if (process.platform === "darwin") {
|
|
1870
|
+
openUrlMacos(targetUrl, allowFocus);
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
if (!allowFocus) return;
|
|
1874
|
+
if (process.platform === "win32") {
|
|
1875
|
+
execFileSync("cmd.exe", ["/c", "start", "", targetUrl], {
|
|
1876
|
+
stdio: "ignore"
|
|
1877
|
+
});
|
|
1878
|
+
return;
|
|
1879
|
+
}
|
|
1880
|
+
execFileSync("xdg-open", [targetUrl], { stdio: "ignore" });
|
|
1587
1881
|
} catch {
|
|
1588
1882
|
}
|
|
1589
1883
|
}
|
|
@@ -1667,14 +1961,14 @@ function envFilePath(baseUrl) {
|
|
|
1667
1961
|
}
|
|
1668
1962
|
function saveEnvValues(values, baseUrl) {
|
|
1669
1963
|
const filePath = envFilePath(baseUrl);
|
|
1670
|
-
const dir =
|
|
1671
|
-
if (!
|
|
1672
|
-
|
|
1964
|
+
const dir = dirname3(filePath);
|
|
1965
|
+
if (!existsSync3(dir)) {
|
|
1966
|
+
mkdirSync3(dir, { recursive: true });
|
|
1673
1967
|
}
|
|
1674
|
-
const existing =
|
|
1968
|
+
const existing = existsSync3(filePath) ? parseEnvFile(filePath) : {};
|
|
1675
1969
|
const merged = { ...existing, ...values };
|
|
1676
1970
|
const lines = Object.entries(merged).filter(([, v]) => v !== "").map(([k, v]) => `${k}=${v}`);
|
|
1677
|
-
|
|
1971
|
+
writeFileSync3(filePath, lines.join("\n") + "\n", "utf-8");
|
|
1678
1972
|
saveProjectDeeplineEnvValues(baseUrl, values);
|
|
1679
1973
|
}
|
|
1680
1974
|
async function httpJson(method, url, apiKey, body) {
|
|
@@ -1728,7 +2022,7 @@ function buildCandidateUrls2(url) {
|
|
|
1728
2022
|
return [url];
|
|
1729
2023
|
}
|
|
1730
2024
|
}
|
|
1731
|
-
function
|
|
2025
|
+
function sleep3(ms) {
|
|
1732
2026
|
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
1733
2027
|
}
|
|
1734
2028
|
function printDeeplineLogo() {
|
|
@@ -1811,7 +2105,7 @@ async function handleRegister(args) {
|
|
|
1811
2105
|
return EXIT_AUTH;
|
|
1812
2106
|
}
|
|
1813
2107
|
if (s >= 500 || s === 0 || s === 400) {
|
|
1814
|
-
await
|
|
2108
|
+
await sleep3(2e3);
|
|
1815
2109
|
continue;
|
|
1816
2110
|
}
|
|
1817
2111
|
if (s >= 400) {
|
|
@@ -1835,7 +2129,7 @@ async function handleRegister(args) {
|
|
|
1835
2129
|
console.log("That approval link expired. Please run: deepline auth register");
|
|
1836
2130
|
return EXIT_AUTH;
|
|
1837
2131
|
}
|
|
1838
|
-
await
|
|
2132
|
+
await sleep3(2e3);
|
|
1839
2133
|
}
|
|
1840
2134
|
}
|
|
1841
2135
|
async function handleWait(args) {
|
|
@@ -1872,7 +2166,7 @@ async function handleWait(args) {
|
|
|
1872
2166
|
return EXIT_AUTH;
|
|
1873
2167
|
}
|
|
1874
2168
|
if (status >= 500 || status === 0 || status === 400) {
|
|
1875
|
-
await
|
|
2169
|
+
await sleep3(2e3);
|
|
1876
2170
|
continue;
|
|
1877
2171
|
}
|
|
1878
2172
|
if (status >= 400) {
|
|
@@ -1896,7 +2190,7 @@ async function handleWait(args) {
|
|
|
1896
2190
|
console.error("That approval link expired. Run: deepline auth register");
|
|
1897
2191
|
return EXIT_AUTH;
|
|
1898
2192
|
}
|
|
1899
|
-
await
|
|
2193
|
+
await sleep3(2e3);
|
|
1900
2194
|
}
|
|
1901
2195
|
console.error("Still pending. Approve the browser link, then run: deepline auth wait");
|
|
1902
2196
|
return EXIT_AUTH;
|
|
@@ -2213,7 +2507,7 @@ function registerBillingCommands(program) {
|
|
|
2213
2507
|
}
|
|
2214
2508
|
|
|
2215
2509
|
// src/cli/dataset-stats.ts
|
|
2216
|
-
import { writeFileSync as
|
|
2510
|
+
import { writeFileSync as writeFileSync4 } from "fs";
|
|
2217
2511
|
import { resolve as resolve3 } from "path";
|
|
2218
2512
|
var CSV_PROJECTED_FIELDS_KEY = "__deeplineCsvProjectedFields";
|
|
2219
2513
|
function csvProjectedFields(row) {
|
|
@@ -2545,7 +2839,7 @@ function writeCanonicalRowsCsv(rowsInfo, outPath) {
|
|
|
2545
2839
|
columns: rowsInfo.columns
|
|
2546
2840
|
});
|
|
2547
2841
|
const resolved = resolve3(outPath);
|
|
2548
|
-
|
|
2842
|
+
writeFileSync4(
|
|
2549
2843
|
resolved,
|
|
2550
2844
|
csvStringFromRows(sanitized.rows, sanitized.columns),
|
|
2551
2845
|
"utf-8"
|
|
@@ -2838,25 +3132,25 @@ function registerOrgCommands(program) {
|
|
|
2838
3132
|
// src/cli/commands/play.ts
|
|
2839
3133
|
import { createHash as createHash3 } from "crypto";
|
|
2840
3134
|
import {
|
|
2841
|
-
existsSync as
|
|
3135
|
+
existsSync as existsSync5,
|
|
2842
3136
|
readFileSync as readFileSync3,
|
|
2843
3137
|
readdirSync,
|
|
2844
3138
|
realpathSync,
|
|
2845
|
-
writeFileSync as
|
|
3139
|
+
writeFileSync as writeFileSync5
|
|
2846
3140
|
} from "fs";
|
|
2847
|
-
import { basename as basename3, dirname as
|
|
3141
|
+
import { basename as basename3, dirname as dirname7, join as join6, resolve as resolve7 } from "path";
|
|
2848
3142
|
|
|
2849
3143
|
// src/plays/bundle-play-file.ts
|
|
2850
3144
|
import { tmpdir as tmpdir2 } from "os";
|
|
2851
|
-
import { dirname as
|
|
3145
|
+
import { dirname as dirname6, join as join5, resolve as resolve6 } from "path";
|
|
2852
3146
|
import { fileURLToPath } from "url";
|
|
2853
|
-
import { existsSync as
|
|
3147
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2854
3148
|
|
|
2855
3149
|
// ../shared_libs/plays/bundling/index.ts
|
|
2856
3150
|
import { createHash } from "crypto";
|
|
2857
3151
|
import { mkdir as mkdir2, readFile, realpath, stat, writeFile as writeFile2 } from "fs/promises";
|
|
2858
3152
|
import { tmpdir } from "os";
|
|
2859
|
-
import { basename, dirname as
|
|
3153
|
+
import { basename, dirname as dirname4, extname, isAbsolute, join as join3, resolve as resolve4 } from "path";
|
|
2860
3154
|
import { builtinModules, createRequire } from "module";
|
|
2861
3155
|
import { build } from "esbuild";
|
|
2862
3156
|
|
|
@@ -2955,7 +3249,7 @@ async function normalizeLocalPath(filePath) {
|
|
|
2955
3249
|
function createPlayWorkspace(entryFile) {
|
|
2956
3250
|
return {
|
|
2957
3251
|
entryFile,
|
|
2958
|
-
rootDir:
|
|
3252
|
+
rootDir: dirname4(entryFile)
|
|
2959
3253
|
};
|
|
2960
3254
|
}
|
|
2961
3255
|
function isPathInsideDirectory(filePath, directory) {
|
|
@@ -3156,7 +3450,7 @@ function workersNamedPlayEntryAliasPlugin(playFilePath, exportName) {
|
|
|
3156
3450
|
contents: `export { ${exportName} as default } from ${JSON.stringify(playFilePath)};
|
|
3157
3451
|
`,
|
|
3158
3452
|
loader: "ts",
|
|
3159
|
-
resolveDir:
|
|
3453
|
+
resolveDir: dirname4(playFilePath)
|
|
3160
3454
|
})
|
|
3161
3455
|
);
|
|
3162
3456
|
}
|
|
@@ -3320,7 +3614,7 @@ function importedPlayProxyPlugin(importedPlayDependencies) {
|
|
|
3320
3614
|
return {
|
|
3321
3615
|
contents: buildImportedPlayProxyModule(dependency.playName),
|
|
3322
3616
|
loader: "ts",
|
|
3323
|
-
resolveDir:
|
|
3617
|
+
resolveDir: dirname4(args.path)
|
|
3324
3618
|
};
|
|
3325
3619
|
});
|
|
3326
3620
|
}
|
|
@@ -3338,7 +3632,7 @@ async function resolveLocalImport(fromFile, specifier) {
|
|
|
3338
3632
|
if (specifier.startsWith("file:")) {
|
|
3339
3633
|
return normalizeLocalPath(new URL(specifier).pathname);
|
|
3340
3634
|
}
|
|
3341
|
-
const base = isAbsolute(specifier) ? resolve4(specifier) : resolve4(
|
|
3635
|
+
const base = isAbsolute(specifier) ? resolve4(specifier) : resolve4(dirname4(fromFile), specifier);
|
|
3342
3636
|
const candidates = [base];
|
|
3343
3637
|
const explicitExtension = extname(base).toLowerCase();
|
|
3344
3638
|
if (!explicitExtension) {
|
|
@@ -3588,7 +3882,7 @@ async function runEsbuildForCjsNode(entryFile, importedPlayDependencies, adapter
|
|
|
3588
3882
|
...namedExportShim ? {
|
|
3589
3883
|
stdin: {
|
|
3590
3884
|
contents: namedExportShim,
|
|
3591
|
-
resolveDir:
|
|
3885
|
+
resolveDir: dirname4(entryFile),
|
|
3592
3886
|
sourcefile: `${basename(entryFile)}.${exportName}.entry.ts`,
|
|
3593
3887
|
loader: "ts"
|
|
3594
3888
|
}
|
|
@@ -3844,13 +4138,6 @@ var PLAY_DEDUP_BACKENDS = {
|
|
|
3844
4138
|
|
|
3845
4139
|
// ../shared_libs/play-runtime/profiles.ts
|
|
3846
4140
|
var PLAY_EXECUTION_PROFILES = {
|
|
3847
|
-
legacy: {
|
|
3848
|
-
id: "legacy",
|
|
3849
|
-
scheduler: PLAY_SCHEDULER_BACKENDS.temporal,
|
|
3850
|
-
runner: PLAY_RUNTIME_BACKENDS.daytona,
|
|
3851
|
-
dedup: PLAY_DEDUP_BACKENDS.inMemory,
|
|
3852
|
-
label: "Daytona + Temporal (production today)"
|
|
3853
|
-
},
|
|
3854
4141
|
workers_edge: {
|
|
3855
4142
|
id: "workers_edge",
|
|
3856
4143
|
scheduler: PLAY_SCHEDULER_BACKENDS.cfWorkflows,
|
|
@@ -3885,7 +4172,7 @@ function resolveExecutionProfile(override) {
|
|
|
3885
4172
|
// src/plays/local-file-discovery.ts
|
|
3886
4173
|
import { createHash as createHash2 } from "crypto";
|
|
3887
4174
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
3888
|
-
import { basename as basename2, dirname as
|
|
4175
|
+
import { basename as basename2, dirname as dirname5, extname as extname2, isAbsolute as isAbsolute2, join as join4, relative, resolve as resolve5 } from "path";
|
|
3889
4176
|
var SOURCE_EXTENSIONS2 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
|
|
3890
4177
|
function sha2562(buffer) {
|
|
3891
4178
|
return createHash2("sha256").update(buffer).digest("hex");
|
|
@@ -4086,7 +4373,7 @@ function isPathInsideDirectory2(filePath, directory) {
|
|
|
4086
4373
|
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute2(relativePath);
|
|
4087
4374
|
}
|
|
4088
4375
|
async function resolveLocalImport2(fromFile, specifier) {
|
|
4089
|
-
const base = isAbsolute2(specifier) ? resolve5(specifier) : resolve5(
|
|
4376
|
+
const base = isAbsolute2(specifier) ? resolve5(specifier) : resolve5(dirname5(fromFile), specifier);
|
|
4090
4377
|
const candidates = [base];
|
|
4091
4378
|
const explicitExtension = extname2(base).toLowerCase();
|
|
4092
4379
|
if (!explicitExtension) {
|
|
@@ -4105,7 +4392,7 @@ async function resolveLocalImport2(fromFile, specifier) {
|
|
|
4105
4392
|
}
|
|
4106
4393
|
async function discoverPackagedLocalFiles(entryFile) {
|
|
4107
4394
|
const absoluteEntryFile = resolve5(entryFile);
|
|
4108
|
-
const packagingRoot =
|
|
4395
|
+
const packagingRoot = dirname5(absoluteEntryFile);
|
|
4109
4396
|
const files = /* @__PURE__ */ new Map();
|
|
4110
4397
|
const unresolved = [];
|
|
4111
4398
|
const visitedFiles = /* @__PURE__ */ new Set();
|
|
@@ -4142,7 +4429,7 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
4142
4429
|
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."
|
|
4143
4430
|
});
|
|
4144
4431
|
} else {
|
|
4145
|
-
const absoluteCsvPath = resolve5(
|
|
4432
|
+
const absoluteCsvPath = resolve5(dirname5(absolutePath), resolvedPath);
|
|
4146
4433
|
if (isAbsolute2(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
|
|
4147
4434
|
unresolved.push({
|
|
4148
4435
|
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
@@ -4181,14 +4468,14 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
4181
4468
|
|
|
4182
4469
|
// src/plays/bundle-play-file.ts
|
|
4183
4470
|
var PLAY_BUNDLE_CACHE_VERSION2 = 26;
|
|
4184
|
-
var MODULE_DIR =
|
|
4471
|
+
var MODULE_DIR = dirname6(fileURLToPath(import.meta.url));
|
|
4185
4472
|
var SDK_PACKAGE_ROOT = resolve6(MODULE_DIR, "..", "..");
|
|
4186
4473
|
var SOURCE_REPO_ROOT = resolve6(SDK_PACKAGE_ROOT, "..");
|
|
4187
|
-
var HAS_SOURCE_BUNDLING_SOURCES =
|
|
4474
|
+
var HAS_SOURCE_BUNDLING_SOURCES = existsSync4(
|
|
4188
4475
|
resolve6(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
4189
4476
|
);
|
|
4190
4477
|
var PACKAGED_REPO_ROOT = resolve6(SDK_PACKAGE_ROOT, "dist", "repo");
|
|
4191
|
-
var HAS_PACKAGED_BUNDLING_SOURCES =
|
|
4478
|
+
var HAS_PACKAGED_BUNDLING_SOURCES = existsSync4(
|
|
4192
4479
|
resolve6(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
4193
4480
|
);
|
|
4194
4481
|
var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : resolve6(SDK_PACKAGE_ROOT, "..");
|
|
@@ -4227,7 +4514,7 @@ function createSdkPlayBundlingAdapter() {
|
|
|
4227
4514
|
sdkSourceRoot: SDK_SOURCE_ROOT,
|
|
4228
4515
|
sdkPackageJson: SDK_PACKAGE_JSON,
|
|
4229
4516
|
sdkEntryFile: SDK_ENTRY_FILE,
|
|
4230
|
-
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !
|
|
4517
|
+
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !existsSync4(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
|
|
4231
4518
|
sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
|
|
4232
4519
|
workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
|
|
4233
4520
|
workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
|
|
@@ -4513,15 +4800,15 @@ function materializeRemotePlaySource(input) {
|
|
|
4513
4800
|
return null;
|
|
4514
4801
|
}
|
|
4515
4802
|
const outputPath = input.outPath ?? defaultMaterializedPlayPath(input.playName);
|
|
4516
|
-
if (
|
|
4803
|
+
if (existsSync5(outputPath)) {
|
|
4517
4804
|
const existingSource = readFileSync3(outputPath, "utf-8");
|
|
4518
4805
|
if (existingSource === input.sourceCode) {
|
|
4519
4806
|
return { path: outputPath, status: "unchanged", created: false };
|
|
4520
4807
|
}
|
|
4521
|
-
|
|
4808
|
+
writeFileSync5(outputPath, input.sourceCode, "utf-8");
|
|
4522
4809
|
return { path: outputPath, status: "updated", created: false };
|
|
4523
4810
|
}
|
|
4524
|
-
|
|
4811
|
+
writeFileSync5(outputPath, input.sourceCode, "utf-8");
|
|
4525
4812
|
return { path: outputPath, status: "created", created: true };
|
|
4526
4813
|
}
|
|
4527
4814
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -4566,7 +4853,7 @@ function extractPlayName(code, filePath) {
|
|
|
4566
4853
|
throw buildMissingDefinePlayError(filePath);
|
|
4567
4854
|
}
|
|
4568
4855
|
function isFileTarget(target) {
|
|
4569
|
-
return
|
|
4856
|
+
return existsSync5(resolve7(target));
|
|
4570
4857
|
}
|
|
4571
4858
|
function looksLikeFilePath(target) {
|
|
4572
4859
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -4695,7 +4982,7 @@ function applyCsvShortcutInput(input) {
|
|
|
4695
4982
|
function isLocalFilePathValue(value) {
|
|
4696
4983
|
if (typeof value !== "string" || !value.trim()) return false;
|
|
4697
4984
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
4698
|
-
return
|
|
4985
|
+
return existsSync5(resolve7(value));
|
|
4699
4986
|
}
|
|
4700
4987
|
function inputContainsLocalFilePath(value) {
|
|
4701
4988
|
if (isLocalFilePathValue(value)) {
|
|
@@ -4900,7 +5187,7 @@ function formatTimestamp(value) {
|
|
|
4900
5187
|
function formatRunLine(run) {
|
|
4901
5188
|
return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)}`;
|
|
4902
5189
|
}
|
|
4903
|
-
function
|
|
5190
|
+
function isTransientPlayStreamError(error) {
|
|
4904
5191
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
4905
5192
|
return error.statusCode >= 500 && error.statusCode < 600;
|
|
4906
5193
|
}
|
|
@@ -4909,12 +5196,6 @@ function isTransientPlayStatusPollError(error) {
|
|
|
4909
5196
|
text
|
|
4910
5197
|
);
|
|
4911
5198
|
}
|
|
4912
|
-
function isTerminalPlayStatusPollError(input) {
|
|
4913
|
-
if (input.error instanceof DeeplineError && input.error.statusCode === 404 && input.hasSeenRun) {
|
|
4914
|
-
return true;
|
|
4915
|
-
}
|
|
4916
|
-
return false;
|
|
4917
|
-
}
|
|
4918
5199
|
var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
4919
5200
|
"completed",
|
|
4920
5201
|
"failed",
|
|
@@ -4980,6 +5261,12 @@ function buildPlayDashboardUrl(baseUrl, playName) {
|
|
|
4980
5261
|
const encodedPlayName = encodeURIComponent(playName);
|
|
4981
5262
|
return `${trimmedBase}/dashboard/plays/${encodedPlayName}`;
|
|
4982
5263
|
}
|
|
5264
|
+
function openPlayDashboard(input) {
|
|
5265
|
+
if (input.jsonOutput || input.noOpen || !input.dashboardUrl) {
|
|
5266
|
+
return;
|
|
5267
|
+
}
|
|
5268
|
+
openInBrowser(input.dashboardUrl);
|
|
5269
|
+
}
|
|
4983
5270
|
function getDashboardUrlFromLiveEvent(event) {
|
|
4984
5271
|
const dashboardUrl = getEventPayload(event).dashboardUrl;
|
|
4985
5272
|
return typeof dashboardUrl === "string" && dashboardUrl.trim() ? dashboardUrl.trim() : null;
|
|
@@ -5016,6 +5303,68 @@ function assertPlayWaitNotTimedOut(input) {
|
|
|
5016
5303
|
);
|
|
5017
5304
|
}
|
|
5018
5305
|
}
|
|
5306
|
+
async function waitForPlayCompletionByStream(input) {
|
|
5307
|
+
const controller = new AbortController();
|
|
5308
|
+
let timedOut = false;
|
|
5309
|
+
let lastPhase = null;
|
|
5310
|
+
const timeout = input.waitTimeoutMs === null ? null : setTimeout(
|
|
5311
|
+
() => {
|
|
5312
|
+
timedOut = true;
|
|
5313
|
+
controller.abort();
|
|
5314
|
+
},
|
|
5315
|
+
Math.max(1, input.waitTimeoutMs - (Date.now() - input.startedAt))
|
|
5316
|
+
);
|
|
5317
|
+
try {
|
|
5318
|
+
for await (const event of input.client.streamPlayRunEvents(
|
|
5319
|
+
input.workflowId,
|
|
5320
|
+
{ signal: controller.signal }
|
|
5321
|
+
)) {
|
|
5322
|
+
assertPlayWaitNotTimedOut({ ...input, lastPhase });
|
|
5323
|
+
const phase = describeLiveEventPhase(event);
|
|
5324
|
+
if (phase) {
|
|
5325
|
+
lastPhase = phase;
|
|
5326
|
+
input.progress.phase(phase);
|
|
5327
|
+
}
|
|
5328
|
+
printPlayLogLines({
|
|
5329
|
+
lines: getLogLinesFromLiveEvent(event),
|
|
5330
|
+
status: null,
|
|
5331
|
+
jsonOutput: input.jsonOutput,
|
|
5332
|
+
emitLogs: input.emitLogs,
|
|
5333
|
+
state: input.state,
|
|
5334
|
+
progress: input.progress
|
|
5335
|
+
});
|
|
5336
|
+
const status = getStatusFromLiveEvent(event);
|
|
5337
|
+
if (status && TERMINAL_PLAY_STATUSES2.has(status)) {
|
|
5338
|
+
const finalStatus = await input.client.getPlayStatus(input.workflowId, {
|
|
5339
|
+
billing: false
|
|
5340
|
+
});
|
|
5341
|
+
if (TERMINAL_PLAY_STATUSES2.has(finalStatus.status)) {
|
|
5342
|
+
return finalStatus;
|
|
5343
|
+
}
|
|
5344
|
+
}
|
|
5345
|
+
}
|
|
5346
|
+
} catch (error) {
|
|
5347
|
+
if (timedOut) {
|
|
5348
|
+
assertPlayWaitNotTimedOut({ ...input, lastPhase });
|
|
5349
|
+
}
|
|
5350
|
+
throw error;
|
|
5351
|
+
} finally {
|
|
5352
|
+
if (timeout) {
|
|
5353
|
+
clearTimeout(timeout);
|
|
5354
|
+
}
|
|
5355
|
+
}
|
|
5356
|
+
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
5357
|
+
throw new DeeplineError(
|
|
5358
|
+
`Play live stream ended before the run reached a terminal state runId=${input.workflowId}${phaseSuffix}.`,
|
|
5359
|
+
void 0,
|
|
5360
|
+
"PLAY_LIVE_STREAM_ENDED",
|
|
5361
|
+
{
|
|
5362
|
+
runId: input.workflowId,
|
|
5363
|
+
workflowId: input.workflowId,
|
|
5364
|
+
...lastPhase ? { phase: lastPhase } : {}
|
|
5365
|
+
}
|
|
5366
|
+
);
|
|
5367
|
+
}
|
|
5019
5368
|
async function startAndWaitForPlayCompletionByStream(input) {
|
|
5020
5369
|
const startedAt = Date.now();
|
|
5021
5370
|
const state = {
|
|
@@ -5049,6 +5398,11 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5049
5398
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
5050
5399
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
5051
5400
|
const dashboardUrl = getDashboardUrlFromLiveEvent(event) ?? buildPlayDashboardUrl(input.client.baseUrl, input.playName);
|
|
5401
|
+
openPlayDashboard({
|
|
5402
|
+
dashboardUrl,
|
|
5403
|
+
jsonOutput: input.jsonOutput,
|
|
5404
|
+
noOpen: input.noOpen
|
|
5405
|
+
});
|
|
5052
5406
|
if (!input.jsonOutput) {
|
|
5053
5407
|
writeStartedPlayRun({
|
|
5054
5408
|
runId: workflowId,
|
|
@@ -5104,21 +5458,21 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5104
5458
|
lastPhase
|
|
5105
5459
|
});
|
|
5106
5460
|
}
|
|
5107
|
-
if (lastKnownWorkflowId &&
|
|
5461
|
+
if (lastKnownWorkflowId && isTransientPlayStreamError(error)) {
|
|
5108
5462
|
if (timeout) {
|
|
5109
5463
|
clearTimeout(timeout);
|
|
5110
5464
|
}
|
|
5111
5465
|
const reason = error instanceof Error ? error.message : String(error);
|
|
5112
5466
|
if (!input.jsonOutput) {
|
|
5113
5467
|
process.stderr.write(
|
|
5114
|
-
`[play watch] start stream failed after run ${lastKnownWorkflowId};
|
|
5468
|
+
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
|
|
5115
5469
|
`
|
|
5116
5470
|
);
|
|
5117
5471
|
}
|
|
5118
5472
|
recordCliTrace({
|
|
5119
|
-
phase: "cli.
|
|
5473
|
+
phase: "cli.play_start_stream_reconnect",
|
|
5120
5474
|
ms: Date.now() - startedAt,
|
|
5121
|
-
ok:
|
|
5475
|
+
ok: true,
|
|
5122
5476
|
playName: input.playName,
|
|
5123
5477
|
workflowId: lastKnownWorkflowId,
|
|
5124
5478
|
eventCount,
|
|
@@ -5126,10 +5480,9 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5126
5480
|
lastPhase,
|
|
5127
5481
|
reason
|
|
5128
5482
|
});
|
|
5129
|
-
return
|
|
5483
|
+
return waitForPlayCompletionByStream({
|
|
5130
5484
|
client: input.client,
|
|
5131
5485
|
workflowId: lastKnownWorkflowId,
|
|
5132
|
-
pollIntervalMs: 500,
|
|
5133
5486
|
jsonOutput: input.jsonOutput,
|
|
5134
5487
|
emitLogs: input.emitLogs,
|
|
5135
5488
|
waitTimeoutMs: input.waitTimeoutMs,
|
|
@@ -5147,13 +5500,13 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5147
5500
|
if (lastKnownWorkflowId) {
|
|
5148
5501
|
if (!input.jsonOutput) {
|
|
5149
5502
|
input.progress.writeLine(
|
|
5150
|
-
`[play watch] start stream ended after run ${lastKnownWorkflowId};
|
|
5503
|
+
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
|
|
5151
5504
|
);
|
|
5152
5505
|
}
|
|
5153
5506
|
recordCliTrace({
|
|
5154
|
-
phase: "cli.
|
|
5507
|
+
phase: "cli.play_start_stream_reconnect",
|
|
5155
5508
|
ms: Date.now() - startedAt,
|
|
5156
|
-
ok:
|
|
5509
|
+
ok: true,
|
|
5157
5510
|
playName: input.playName,
|
|
5158
5511
|
workflowId: lastKnownWorkflowId,
|
|
5159
5512
|
eventCount,
|
|
@@ -5161,10 +5514,9 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5161
5514
|
lastPhase,
|
|
5162
5515
|
reason: "stream ended before terminal event"
|
|
5163
5516
|
});
|
|
5164
|
-
return
|
|
5517
|
+
return waitForPlayCompletionByStream({
|
|
5165
5518
|
client: input.client,
|
|
5166
5519
|
workflowId: lastKnownWorkflowId,
|
|
5167
|
-
pollIntervalMs: 500,
|
|
5168
5520
|
jsonOutput: input.jsonOutput,
|
|
5169
5521
|
emitLogs: input.emitLogs,
|
|
5170
5522
|
waitTimeoutMs: input.waitTimeoutMs,
|
|
@@ -5185,72 +5537,6 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5185
5537
|
}
|
|
5186
5538
|
);
|
|
5187
5539
|
}
|
|
5188
|
-
async function waitForPlayCompletionByPolling(input) {
|
|
5189
|
-
let lastTransientPollWarningAt = 0;
|
|
5190
|
-
let hasSeenRun = false;
|
|
5191
|
-
while (true) {
|
|
5192
|
-
assertPlayWaitNotTimedOut(input);
|
|
5193
|
-
let status;
|
|
5194
|
-
try {
|
|
5195
|
-
status = await input.client.getPlayTailStatus(input.workflowId, {
|
|
5196
|
-
afterLogIndex: input.state.lastLogIndex,
|
|
5197
|
-
// Keep the server-side tail wait close to the caller's requested poll
|
|
5198
|
-
// cadence. A long wait makes tiny remote runs look slow whenever the
|
|
5199
|
-
// terminal update lands just after the held request starts.
|
|
5200
|
-
waitMs: Math.max(50, Math.min(input.pollIntervalMs, 1e3))
|
|
5201
|
-
});
|
|
5202
|
-
} catch (error) {
|
|
5203
|
-
if (isTerminalPlayStatusPollError({ error, hasSeenRun })) {
|
|
5204
|
-
throw new DeeplineError(
|
|
5205
|
-
`Play run ${input.workflowId} no longer exists on the server (404). The run was deleted or the backend lost it.`,
|
|
5206
|
-
404,
|
|
5207
|
-
"PLAY_RUN_NOT_FOUND"
|
|
5208
|
-
);
|
|
5209
|
-
}
|
|
5210
|
-
if (!isTransientPlayStatusPollError(error)) {
|
|
5211
|
-
throw error;
|
|
5212
|
-
}
|
|
5213
|
-
const now = Date.now();
|
|
5214
|
-
if (now - lastTransientPollWarningAt >= 3e4) {
|
|
5215
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
5216
|
-
input.progress.writeLine(
|
|
5217
|
-
`[play tail] transient status poll failed; retrying: ${message}`
|
|
5218
|
-
);
|
|
5219
|
-
lastTransientPollWarningAt = now;
|
|
5220
|
-
}
|
|
5221
|
-
await new Promise(
|
|
5222
|
-
(resolvePromise) => setTimeout(resolvePromise, input.pollIntervalMs)
|
|
5223
|
-
);
|
|
5224
|
-
continue;
|
|
5225
|
-
}
|
|
5226
|
-
hasSeenRun = true;
|
|
5227
|
-
const logs = status.progress?.logs ?? [];
|
|
5228
|
-
input.progress.phase(status.status);
|
|
5229
|
-
printPlayLogLines({
|
|
5230
|
-
lines: logs.slice(input.state.lastLogIndex),
|
|
5231
|
-
status,
|
|
5232
|
-
jsonOutput: input.jsonOutput,
|
|
5233
|
-
emitLogs: input.emitLogs,
|
|
5234
|
-
state: input.state,
|
|
5235
|
-
progress: input.progress
|
|
5236
|
-
});
|
|
5237
|
-
if (TERMINAL_PLAY_STATUSES2.has(status.status)) {
|
|
5238
|
-
return status.result !== void 0 ? status : await input.client.getPlayStatus(input.workflowId, { billing: false });
|
|
5239
|
-
}
|
|
5240
|
-
const authoritativeStatus = await input.client.getPlayStatus(
|
|
5241
|
-
input.workflowId,
|
|
5242
|
-
{ billing: false }
|
|
5243
|
-
);
|
|
5244
|
-
if (TERMINAL_PLAY_STATUSES2.has(authoritativeStatus.status)) {
|
|
5245
|
-
return authoritativeStatus;
|
|
5246
|
-
}
|
|
5247
|
-
if ((status.progress?.logs ?? []).length === input.state.lastLogIndex) {
|
|
5248
|
-
await new Promise(
|
|
5249
|
-
(resolvePromise) => setTimeout(resolvePromise, input.pollIntervalMs)
|
|
5250
|
-
);
|
|
5251
|
-
}
|
|
5252
|
-
}
|
|
5253
|
-
}
|
|
5254
5540
|
function formatInteger(value) {
|
|
5255
5541
|
return typeof value === "number" && Number.isFinite(value) ? value.toLocaleString("en-US") : String(value ?? "-");
|
|
5256
5542
|
}
|
|
@@ -5391,7 +5677,6 @@ function buildRunWarnings(status, rowsInfo) {
|
|
|
5391
5677
|
function buildRunNextCommands(runId, rowsInfo) {
|
|
5392
5678
|
const commands = {
|
|
5393
5679
|
get: `deepline runs get ${runId} --json`,
|
|
5394
|
-
tail: `deepline runs tail ${runId} --json`,
|
|
5395
5680
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
5396
5681
|
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
5397
5682
|
};
|
|
@@ -5507,10 +5792,9 @@ function normalizeErrorsForEnvelope(status, error) {
|
|
|
5507
5792
|
}
|
|
5508
5793
|
function normalizeLogsForEnvelope(status) {
|
|
5509
5794
|
const logs = Array.isArray(status.progress?.logs) ? status.progress.logs : [];
|
|
5510
|
-
const
|
|
5511
|
-
const totalCount = offset + logs.length;
|
|
5795
|
+
const totalCount = logs.length;
|
|
5512
5796
|
const entries = logs.slice(Math.max(0, logs.length - RUN_LOG_PREVIEW_LIMIT));
|
|
5513
|
-
const firstSequence = entries.length === 0 ? null :
|
|
5797
|
+
const firstSequence = entries.length === 0 ? null : logs.length - entries.length + 1;
|
|
5514
5798
|
const lastSequence = totalCount === 0 ? null : totalCount;
|
|
5515
5799
|
return {
|
|
5516
5800
|
totalCount,
|
|
@@ -5756,7 +6040,6 @@ function writeStartedPlayRun(input) {
|
|
|
5756
6040
|
workflowId: input.runId,
|
|
5757
6041
|
name: input.playName,
|
|
5758
6042
|
status: input.status ?? "started",
|
|
5759
|
-
statusUrl: input.statusUrl,
|
|
5760
6043
|
dashboardUrl: input.dashboardUrl
|
|
5761
6044
|
};
|
|
5762
6045
|
if (input.jsonOutput) {
|
|
@@ -5768,7 +6051,7 @@ function writeStartedPlayRun(input) {
|
|
|
5768
6051
|
`Started ${input.playName}`,
|
|
5769
6052
|
` run id: ${input.runId}`,
|
|
5770
6053
|
` get status: deepline runs get ${input.runId} --json`,
|
|
5771
|
-
`
|
|
6054
|
+
` logs: deepline runs logs ${input.runId} --json`,
|
|
5772
6055
|
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`,
|
|
5773
6056
|
` result JSON: deepline runs get ${input.runId} --json`
|
|
5774
6057
|
];
|
|
@@ -5783,7 +6066,7 @@ function writeStartedPlayRun(input) {
|
|
|
5783
6066
|
console.log(output);
|
|
5784
6067
|
}
|
|
5785
6068
|
function parsePlayRunOptions(args) {
|
|
5786
|
-
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]";
|
|
6069
|
+
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.";
|
|
5787
6070
|
let filePath = null;
|
|
5788
6071
|
let playName = null;
|
|
5789
6072
|
let input = null;
|
|
@@ -5793,8 +6076,8 @@ function parsePlayRunOptions(args) {
|
|
|
5793
6076
|
let jsonOutput = watch ? args.includes("--json") : argsWantJson(args);
|
|
5794
6077
|
const emitLogs = !jsonOutput || args.includes("--logs");
|
|
5795
6078
|
const force = args.includes("--force");
|
|
6079
|
+
const noOpen = args.includes("--no-open");
|
|
5796
6080
|
let outPath = null;
|
|
5797
|
-
let pollIntervalMs = 500;
|
|
5798
6081
|
let waitTimeoutMs = null;
|
|
5799
6082
|
for (let index = 0; index < args.length; index += 1) {
|
|
5800
6083
|
const arg = args[index];
|
|
@@ -5826,15 +6109,16 @@ function parsePlayRunOptions(args) {
|
|
|
5826
6109
|
outPath = resolve7(args[++index]);
|
|
5827
6110
|
continue;
|
|
5828
6111
|
}
|
|
5829
|
-
if (
|
|
5830
|
-
|
|
5831
|
-
|
|
6112
|
+
if (arg === "--poll-interval-ms" || arg === "--interval-ms") {
|
|
6113
|
+
throw new Error(
|
|
6114
|
+
`${arg} was removed. --watch uses the canonical run stream directly.`
|
|
6115
|
+
);
|
|
5832
6116
|
}
|
|
5833
6117
|
if ((arg === "--tail-timeout-ms" || arg === "--timeout-ms") && args[index + 1]) {
|
|
5834
6118
|
waitTimeoutMs = parsePositiveInteger2(args[++index], arg);
|
|
5835
6119
|
continue;
|
|
5836
6120
|
}
|
|
5837
|
-
if (arg === "--json" || arg === "--wait" || arg === "--tail" || arg === "--watch" || arg === "--logs" || arg === "--force") {
|
|
6121
|
+
if (arg === "--json" || arg === "--wait" || arg === "--tail" || arg === "--watch" || arg === "--logs" || arg === "--force" || arg === "--no-open") {
|
|
5838
6122
|
if (arg === "--watch") {
|
|
5839
6123
|
continue;
|
|
5840
6124
|
}
|
|
@@ -5903,10 +6187,10 @@ function parsePlayRunOptions(args) {
|
|
|
5903
6187
|
watch,
|
|
5904
6188
|
emitLogs,
|
|
5905
6189
|
jsonOutput,
|
|
5906
|
-
pollIntervalMs,
|
|
5907
6190
|
waitTimeoutMs,
|
|
5908
6191
|
force,
|
|
5909
|
-
outPath
|
|
6192
|
+
outPath,
|
|
6193
|
+
noOpen
|
|
5910
6194
|
};
|
|
5911
6195
|
}
|
|
5912
6196
|
function parsePlayCheckOptions(args) {
|
|
@@ -6081,6 +6365,7 @@ async function handleFileBackedRun(options) {
|
|
|
6081
6365
|
jsonOutput: options.jsonOutput,
|
|
6082
6366
|
emitLogs: options.emitLogs,
|
|
6083
6367
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
6368
|
+
noOpen: options.noOpen,
|
|
6084
6369
|
progress
|
|
6085
6370
|
})
|
|
6086
6371
|
);
|
|
@@ -6108,14 +6393,19 @@ async function handleFileBackedRun(options) {
|
|
|
6108
6393
|
() => client.startPlayRun(startRequest)
|
|
6109
6394
|
);
|
|
6110
6395
|
const dashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
6111
|
-
|
|
6396
|
+
const resolvedDashboardUrl = started.dashboardUrl ?? dashboardUrl;
|
|
6397
|
+
openPlayDashboard({
|
|
6398
|
+
dashboardUrl: resolvedDashboardUrl,
|
|
6399
|
+
jsonOutput: options.jsonOutput,
|
|
6400
|
+
noOpen: options.noOpen
|
|
6401
|
+
});
|
|
6402
|
+
progress.phase(`loading play on ${resolvedDashboardUrl}`);
|
|
6112
6403
|
progress.complete();
|
|
6113
6404
|
writeStartedPlayRun({
|
|
6114
6405
|
runId: started.workflowId,
|
|
6115
6406
|
playName,
|
|
6116
6407
|
status: started.status,
|
|
6117
|
-
|
|
6118
|
-
dashboardUrl: started.dashboardUrl ?? dashboardUrl,
|
|
6408
|
+
dashboardUrl: resolvedDashboardUrl,
|
|
6119
6409
|
jsonOutput: options.jsonOutput,
|
|
6120
6410
|
progress
|
|
6121
6411
|
});
|
|
@@ -6220,6 +6510,7 @@ async function handleNamedRun(options) {
|
|
|
6220
6510
|
jsonOutput: options.jsonOutput,
|
|
6221
6511
|
emitLogs: options.emitLogs,
|
|
6222
6512
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
6513
|
+
noOpen: options.noOpen,
|
|
6223
6514
|
progress
|
|
6224
6515
|
})
|
|
6225
6516
|
);
|
|
@@ -6250,14 +6541,19 @@ async function handleNamedRun(options) {
|
|
|
6250
6541
|
client.baseUrl,
|
|
6251
6542
|
playName
|
|
6252
6543
|
);
|
|
6253
|
-
|
|
6544
|
+
const resolvedDashboardUrl = started.dashboardUrl ?? dashboardUrl;
|
|
6545
|
+
openPlayDashboard({
|
|
6546
|
+
dashboardUrl: resolvedDashboardUrl,
|
|
6547
|
+
jsonOutput: options.jsonOutput,
|
|
6548
|
+
noOpen: options.noOpen
|
|
6549
|
+
});
|
|
6550
|
+
progress.phase(`loading play on ${resolvedDashboardUrl}`);
|
|
6254
6551
|
progress.complete();
|
|
6255
6552
|
writeStartedPlayRun({
|
|
6256
6553
|
runId: started.workflowId,
|
|
6257
6554
|
playName: started.name ?? playName,
|
|
6258
6555
|
status: started.status,
|
|
6259
|
-
|
|
6260
|
-
dashboardUrl: started.dashboardUrl ?? dashboardUrl,
|
|
6556
|
+
dashboardUrl: resolvedDashboardUrl,
|
|
6261
6557
|
jsonOutput: options.jsonOutput,
|
|
6262
6558
|
progress
|
|
6263
6559
|
});
|
|
@@ -6271,8 +6567,8 @@ async function handlePlayRun(args) {
|
|
|
6271
6567
|
}
|
|
6272
6568
|
const resolved = resolve7(options.target.path);
|
|
6273
6569
|
console.error(`File not found: ${resolved}`);
|
|
6274
|
-
const dir =
|
|
6275
|
-
if (
|
|
6570
|
+
const dir = dirname7(resolved);
|
|
6571
|
+
if (existsSync5(dir)) {
|
|
6276
6572
|
const base = basename3(resolved);
|
|
6277
6573
|
try {
|
|
6278
6574
|
const siblings = readdirSync(dir).filter(
|
|
@@ -6300,7 +6596,7 @@ function parseRunIdPositional(args, usage) {
|
|
|
6300
6596
|
}
|
|
6301
6597
|
continue;
|
|
6302
6598
|
}
|
|
6303
|
-
if ((arg === "--out" || arg === "--
|
|
6599
|
+
if ((arg === "--out" || arg === "--reason") && args[index + 1]) {
|
|
6304
6600
|
index += 1;
|
|
6305
6601
|
continue;
|
|
6306
6602
|
}
|
|
@@ -6385,7 +6681,7 @@ async function handleRunsList(args) {
|
|
|
6385
6681
|
return 0;
|
|
6386
6682
|
}
|
|
6387
6683
|
async function handleRunTail(args) {
|
|
6388
|
-
const usage = "Usage: deepline runs tail <run-id> [--json] [--compact]
|
|
6684
|
+
const usage = "Usage: deepline runs tail <run-id> [--json] [--compact]";
|
|
6389
6685
|
let runId;
|
|
6390
6686
|
try {
|
|
6391
6687
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -6393,20 +6689,19 @@ async function handleRunTail(args) {
|
|
|
6393
6689
|
console.error(error instanceof Error ? error.message : usage);
|
|
6394
6690
|
return 1;
|
|
6395
6691
|
}
|
|
6396
|
-
const client = new DeeplineClient();
|
|
6397
|
-
let afterLogIndex;
|
|
6398
6692
|
for (let index = 0; index < args.length; index += 1) {
|
|
6399
6693
|
const arg = args[index];
|
|
6400
|
-
if (arg === "--cursor"
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6694
|
+
if (arg === "--cursor") {
|
|
6695
|
+
console.error("--cursor was removed. deepline runs tail reads the canonical run stream.");
|
|
6696
|
+
return 1;
|
|
6697
|
+
}
|
|
6698
|
+
if (arg.startsWith("--") && arg !== "--json" && arg !== "--compact") {
|
|
6699
|
+
console.error(`${arg} is not supported by deepline runs tail.`);
|
|
6700
|
+
return 1;
|
|
6405
6701
|
}
|
|
6406
6702
|
}
|
|
6407
|
-
const
|
|
6408
|
-
|
|
6409
|
-
});
|
|
6703
|
+
const client = new DeeplineClient();
|
|
6704
|
+
const status = await client.runs.tail(runId);
|
|
6410
6705
|
writePlayResult(status, argsWantJson(args));
|
|
6411
6706
|
return status.status === "failed" ? 1 : 0;
|
|
6412
6707
|
}
|
|
@@ -6435,7 +6730,7 @@ async function handleRunLogs(args) {
|
|
|
6435
6730
|
const status = await client.runs.get(runId);
|
|
6436
6731
|
const logs = status.progress?.logs ?? [];
|
|
6437
6732
|
if (outPath) {
|
|
6438
|
-
|
|
6733
|
+
writeFileSync5(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
6439
6734
|
if (argsWantJson(args)) {
|
|
6440
6735
|
process.stdout.write(
|
|
6441
6736
|
`${JSON.stringify({
|
|
@@ -6947,8 +7242,9 @@ function registerPlayCommands(program) {
|
|
|
6947
7242
|
"after",
|
|
6948
7243
|
`
|
|
6949
7244
|
Concepts:
|
|
6950
|
-
Plays are durable
|
|
6951
|
-
|
|
7245
|
+
Plays are durable cloud workflows.
|
|
7246
|
+
Stable ctx.tools.execute({ id, tool, input }) calls are replay-safe.
|
|
7247
|
+
ctx.map adds row keys and row progress.
|
|
6952
7248
|
|
|
6953
7249
|
Common commands:
|
|
6954
7250
|
deepline plays search email --json
|
|
@@ -6979,17 +7275,42 @@ Examples:
|
|
|
6979
7275
|
"after",
|
|
6980
7276
|
`
|
|
6981
7277
|
Notes:
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
7278
|
+
Local files are bundled, preflighted, then run in Deepline cloud.
|
|
7279
|
+
Named plays run the live saved revision.
|
|
7280
|
+
Unknown --foo and --foo.bar flags are treated as play input args.
|
|
7281
|
+
File args accept local paths; the CLI stages files before submit.
|
|
7282
|
+
--watch prints logs, previews, stats, and next commands.
|
|
7283
|
+
The play page opens in your browser as soon as the run starts; use --no-open
|
|
7284
|
+
to only print the URL.
|
|
7285
|
+
--force supersedes active runs; it does not bypass completed reuse.
|
|
7286
|
+
|
|
7287
|
+
Idempotent execution:
|
|
7288
|
+
Stable tool call ids are the reuse key:
|
|
7289
|
+
|
|
7290
|
+
await ctx.tools.execute({ id: 'company_lookup', tool, input });
|
|
7291
|
+
|
|
7292
|
+
For rows, use ctx.map plus a stable row key:
|
|
7293
|
+
|
|
7294
|
+
const rows = await ctx
|
|
7295
|
+
.map('companies_v1', companies)
|
|
7296
|
+
.step('cto', (row, ctx) => ctx.tools.execute({
|
|
7297
|
+
id: 'find_cto',
|
|
7298
|
+
tool: 'apollo_search_people_with_match',
|
|
7299
|
+
input: { q_organization_domains_list: [row.domain], per_page: 1 },
|
|
7300
|
+
}))
|
|
7301
|
+
.run({ key: 'domain' });
|
|
7302
|
+
|
|
7303
|
+
Reuse needs the same play, tool id, map name, row key, and compatible logic.
|
|
7304
|
+
To refresh, change the id/map key or set staleAfterSeconds:
|
|
7305
|
+
|
|
7306
|
+
.run({ key: 'domain', staleAfterSeconds: 86400 })
|
|
6988
7307
|
|
|
6989
7308
|
Examples:
|
|
6990
7309
|
deepline plays run my.play.ts --input '{"domain":"stripe.com"}' --watch
|
|
6991
7310
|
deepline plays run person-linkedin-to-email --input '{"linkedin_url":"..."}' --watch
|
|
6992
7311
|
deepline plays run enrich.play.ts --csv leads.csv --watch --out leads-enriched.csv
|
|
7312
|
+
deepline plays run cto-search.play.ts --limit 5 --watch
|
|
7313
|
+
deepline runs get <run-id>
|
|
6993
7314
|
`
|
|
6994
7315
|
).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(
|
|
6995
7316
|
"--revision-id <id>",
|
|
@@ -7000,7 +7321,7 @@ Examples:
|
|
|
7000
7321
|
).option("--watch", "Stream logs until completion").option(
|
|
7001
7322
|
"--logs",
|
|
7002
7323
|
"When output is non-interactive, stream play logs to stderr while waiting"
|
|
7003
|
-
).option("--
|
|
7324
|
+
).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) => {
|
|
7004
7325
|
const passthroughArgs = [...command.args];
|
|
7005
7326
|
const explicitTarget = options.file || options.name;
|
|
7006
7327
|
const targetIsInputFlag = typeof target === "string" && target.startsWith("--");
|
|
@@ -7022,9 +7343,9 @@ Examples:
|
|
|
7022
7343
|
...options.out ? ["--out", options.out] : [],
|
|
7023
7344
|
...options.watch ? ["--watch"] : [],
|
|
7024
7345
|
...options.logs ? ["--logs"] : [],
|
|
7025
|
-
...options.pollIntervalMs ? ["--poll-interval-ms", options.pollIntervalMs] : [],
|
|
7026
7346
|
...options.tailTimeoutMs ? ["--tail-timeout-ms", options.tailTimeoutMs] : [],
|
|
7027
7347
|
...options.force ? ["--force"] : [],
|
|
7348
|
+
...options.open === false ? ["--no-open"] : [],
|
|
7028
7349
|
...options.json ? ["--json"] : [],
|
|
7029
7350
|
...passthroughArgs
|
|
7030
7351
|
]);
|
|
@@ -7131,12 +7452,11 @@ Examples:
|
|
|
7131
7452
|
...options.json ? ["--json"] : []
|
|
7132
7453
|
]);
|
|
7133
7454
|
});
|
|
7134
|
-
runs.command("tail <runId>").description("
|
|
7455
|
+
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) => {
|
|
7135
7456
|
process.exitCode = await handleRunTail([
|
|
7136
7457
|
runId,
|
|
7137
7458
|
...options.json ? ["--json"] : [],
|
|
7138
|
-
...options.compact ? ["--compact"] : []
|
|
7139
|
-
...options.cursor ? ["--cursor", options.cursor] : []
|
|
7459
|
+
...options.compact ? ["--compact"] : []
|
|
7140
7460
|
]);
|
|
7141
7461
|
});
|
|
7142
7462
|
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) => {
|
|
@@ -7165,12 +7485,12 @@ Examples:
|
|
|
7165
7485
|
}
|
|
7166
7486
|
|
|
7167
7487
|
// src/cli/commands/tools.ts
|
|
7168
|
-
import { chmodSync, mkdtempSync, writeFileSync as
|
|
7488
|
+
import { chmodSync, mkdtempSync, writeFileSync as writeFileSync7 } from "fs";
|
|
7169
7489
|
import { tmpdir as tmpdir3 } from "os";
|
|
7170
7490
|
import { join as join8 } from "path";
|
|
7171
7491
|
|
|
7172
7492
|
// src/tool-output.ts
|
|
7173
|
-
import { mkdirSync as
|
|
7493
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
7174
7494
|
import { homedir as homedir3 } from "os";
|
|
7175
7495
|
import { join as join7 } from "path";
|
|
7176
7496
|
function isPlainObject(value) {
|
|
@@ -7248,13 +7568,13 @@ function tryConvertToList(payload, options) {
|
|
|
7248
7568
|
}
|
|
7249
7569
|
function ensureOutputDir() {
|
|
7250
7570
|
const outputDir = join7(homedir3(), ".local", "share", "deepline", "data");
|
|
7251
|
-
|
|
7571
|
+
mkdirSync4(outputDir, { recursive: true });
|
|
7252
7572
|
return outputDir;
|
|
7253
7573
|
}
|
|
7254
7574
|
function writeJsonOutputFile(payload, stem) {
|
|
7255
7575
|
const outputDir = ensureOutputDir();
|
|
7256
7576
|
const outputPath = join7(outputDir, `${stem}_${Date.now()}.json`);
|
|
7257
|
-
|
|
7577
|
+
writeFileSync6(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
7258
7578
|
return outputPath;
|
|
7259
7579
|
}
|
|
7260
7580
|
function writeCsvOutputFile(rows, stem) {
|
|
@@ -7282,7 +7602,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
7282
7602
|
for (const row of rows) {
|
|
7283
7603
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
7284
7604
|
}
|
|
7285
|
-
|
|
7605
|
+
writeFileSync6(outputPath, `${lines.join("\n")}
|
|
7286
7606
|
`, "utf-8");
|
|
7287
7607
|
const previewRows = rows.slice(0, 5);
|
|
7288
7608
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -7819,7 +8139,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
7819
8139
|
};
|
|
7820
8140
|
});
|
|
7821
8141
|
`;
|
|
7822
|
-
|
|
8142
|
+
writeFileSync7(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
7823
8143
|
return {
|
|
7824
8144
|
path: scriptPath,
|
|
7825
8145
|
projectDir,
|
|
@@ -7926,10 +8246,10 @@ async function executeTool(args) {
|
|
|
7926
8246
|
}
|
|
7927
8247
|
|
|
7928
8248
|
// src/cli/skills-sync.ts
|
|
7929
|
-
import { spawn, spawnSync } from "child_process";
|
|
7930
|
-
import { existsSync as
|
|
8249
|
+
import { spawn, spawnSync as spawnSync2 } from "child_process";
|
|
8250
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
7931
8251
|
import { homedir as homedir4 } from "os";
|
|
7932
|
-
import { dirname as
|
|
8252
|
+
import { dirname as dirname8, join as join9 } from "path";
|
|
7933
8253
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
7934
8254
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
7935
8255
|
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
@@ -7944,7 +8264,7 @@ function sdkSkillsVersionPath(baseUrl) {
|
|
|
7944
8264
|
}
|
|
7945
8265
|
function readLocalSkillsVersion(baseUrl) {
|
|
7946
8266
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
7947
|
-
if (!
|
|
8267
|
+
if (!existsSync6(path)) return "";
|
|
7948
8268
|
try {
|
|
7949
8269
|
return readFileSync4(path, "utf-8").trim();
|
|
7950
8270
|
} catch {
|
|
@@ -7953,8 +8273,8 @@ function readLocalSkillsVersion(baseUrl) {
|
|
|
7953
8273
|
}
|
|
7954
8274
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
7955
8275
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
7956
|
-
|
|
7957
|
-
|
|
8276
|
+
mkdirSync5(dirname8(path), { recursive: true });
|
|
8277
|
+
writeFileSync8(path, `${version}
|
|
7958
8278
|
`, "utf-8");
|
|
7959
8279
|
}
|
|
7960
8280
|
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
@@ -8018,7 +8338,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
|
|
|
8018
8338
|
];
|
|
8019
8339
|
}
|
|
8020
8340
|
function hasCommand(command) {
|
|
8021
|
-
const result =
|
|
8341
|
+
const result = spawnSync2(command, ["--version"], {
|
|
8022
8342
|
stdio: "ignore",
|
|
8023
8343
|
shell: process.platform === "win32"
|
|
8024
8344
|
});
|