deepline 0.1.21 → 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 +518 -230
- package/dist/cli/index.mjs +575 -282
- package/dist/index.d.mts +21 -58
- package/dist/index.d.ts +21 -58
- package/dist/index.js +148 -90
- package/dist/index.mjs +148 -90
- package/dist/repo/apps/play-runner-workers/src/entry.ts +147 -0
- package/dist/repo/sdk/src/client.ts +205 -120
- 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/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
|
|
@@ -535,7 +535,7 @@ function isRecord(value) {
|
|
|
535
535
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
536
536
|
}
|
|
537
537
|
function normalizePlayStatus(raw) {
|
|
538
|
-
const status = typeof raw.status === "string" ? raw.status :
|
|
538
|
+
const status = typeof raw.status === "string" ? raw.status : "running";
|
|
539
539
|
const runId = typeof raw.runId === "string" ? raw.runId : typeof raw.workflowId === "string" ? raw.workflowId : "";
|
|
540
540
|
return {
|
|
541
541
|
...raw,
|
|
@@ -543,23 +543,6 @@ function normalizePlayStatus(raw) {
|
|
|
543
543
|
status
|
|
544
544
|
};
|
|
545
545
|
}
|
|
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
546
|
function decodeBase64Bytes(value) {
|
|
564
547
|
const binary = atob(value);
|
|
565
548
|
const bytes = new Uint8Array(binary.length);
|
|
@@ -568,6 +551,79 @@ function decodeBase64Bytes(value) {
|
|
|
568
551
|
}
|
|
569
552
|
return bytes;
|
|
570
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;
|
|
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
|
+
};
|
|
626
|
+
}
|
|
571
627
|
var DeeplineClient = class {
|
|
572
628
|
http;
|
|
573
629
|
config;
|
|
@@ -677,7 +733,7 @@ var DeeplineClient = class {
|
|
|
677
733
|
/**
|
|
678
734
|
* Search available tools using Deepline's ranked backend search.
|
|
679
735
|
*
|
|
680
|
-
* This is the same discovery surface used by the
|
|
736
|
+
* This is the same discovery surface used by the CLI: it ranks across
|
|
681
737
|
* tool metadata, categories, agent guidance, and input schema fields.
|
|
682
738
|
*/
|
|
683
739
|
async searchTools(options = {}) {
|
|
@@ -770,7 +826,7 @@ var DeeplineClient = class {
|
|
|
770
826
|
* `progress.logs`; they are not part of the user output object.
|
|
771
827
|
*
|
|
772
828
|
* @param request - Play run configuration (name, code, input, etc.)
|
|
773
|
-
* @returns
|
|
829
|
+
* @returns Run metadata including the public `workflowId`
|
|
774
830
|
*
|
|
775
831
|
* @example
|
|
776
832
|
* ```typescript
|
|
@@ -1062,9 +1118,6 @@ var DeeplineClient = class {
|
|
|
1062
1118
|
* Internal/advanced primitive. Public callers should usually prefer
|
|
1063
1119
|
* {@link runPlay}, {@link PlayJob.get}, or `deepline play run --watch`.
|
|
1064
1120
|
*
|
|
1065
|
-
* Poll this method until `status` reaches a terminal state:
|
|
1066
|
-
* `'completed'`, `'failed'`, or `'cancelled'`.
|
|
1067
|
-
*
|
|
1068
1121
|
* @param workflowId - Play-run id from {@link startPlayRun}
|
|
1069
1122
|
* @returns Current status with progress logs and partial results
|
|
1070
1123
|
*
|
|
@@ -1086,35 +1139,11 @@ var DeeplineClient = class {
|
|
|
1086
1139
|
);
|
|
1087
1140
|
return normalizePlayStatus(response);
|
|
1088
1141
|
}
|
|
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
1142
|
/**
|
|
1114
1143
|
* Stream semantic play-run events using the same SSE feed as the dashboard.
|
|
1115
1144
|
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1145
|
+
* The server emits a canonical `play.run.snapshot` event first for every
|
|
1146
|
+
* connection, then incremental live events until terminal state or reconnect.
|
|
1118
1147
|
*/
|
|
1119
1148
|
async *streamPlayRunEvents(workflowId, options) {
|
|
1120
1149
|
const headers = options?.lastEventId && options.lastEventId.trim() ? { "Last-Event-ID": options.lastEventId.trim() } : void 0;
|
|
@@ -1134,7 +1163,7 @@ var DeeplineClient = class {
|
|
|
1134
1163
|
*
|
|
1135
1164
|
* Sends a stop request for the run.
|
|
1136
1165
|
*
|
|
1137
|
-
* @param workflowId -
|
|
1166
|
+
* @param workflowId - Public Deepline play-run id to cancel
|
|
1138
1167
|
*
|
|
1139
1168
|
* @example
|
|
1140
1169
|
* ```typescript
|
|
@@ -1150,7 +1179,7 @@ var DeeplineClient = class {
|
|
|
1150
1179
|
/**
|
|
1151
1180
|
* Stop a running play execution, including open HITL waits.
|
|
1152
1181
|
*
|
|
1153
|
-
* @param workflowId -
|
|
1182
|
+
* @param workflowId - Public Deepline play-run id to stop
|
|
1154
1183
|
* @param options.reason - Optional audit/debug reason
|
|
1155
1184
|
*/
|
|
1156
1185
|
async stopPlay(workflowId, options) {
|
|
@@ -1222,32 +1251,42 @@ var DeeplineClient = class {
|
|
|
1222
1251
|
);
|
|
1223
1252
|
return response.runs ?? [];
|
|
1224
1253
|
}
|
|
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
|
-
*/
|
|
1254
|
+
/** Read the canonical run stream and return the latest run snapshot. */
|
|
1234
1255
|
async tailRun(runId, options) {
|
|
1235
|
-
const
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
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
|
+
}
|
|
1239
1275
|
}
|
|
1240
|
-
if (
|
|
1241
|
-
|
|
1276
|
+
if (terminal && state.latest) {
|
|
1277
|
+
return await this.getRunStatus(state.latest.runId || runId).catch(
|
|
1278
|
+
() => state.latest ?? playRunStatusFromState(state)
|
|
1279
|
+
);
|
|
1242
1280
|
}
|
|
1243
|
-
if (
|
|
1244
|
-
|
|
1281
|
+
if (state.latest) {
|
|
1282
|
+
return state.latest;
|
|
1245
1283
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1284
|
+
throw new DeeplineError(
|
|
1285
|
+
`Run stream for ${runId} ended before the initial snapshot.`,
|
|
1286
|
+
void 0,
|
|
1287
|
+
"PLAY_RUN_STREAM_EMPTY",
|
|
1288
|
+
{ runId }
|
|
1249
1289
|
);
|
|
1250
|
-
return normalizePlayStatus(response);
|
|
1251
1290
|
}
|
|
1252
1291
|
/**
|
|
1253
1292
|
* Fetch persisted logs for a run using the public runs resource model.
|
|
@@ -1404,11 +1443,11 @@ var DeeplineClient = class {
|
|
|
1404
1443
|
// Plays — high-level orchestration
|
|
1405
1444
|
// ——————————————————————————————————————————————————————————
|
|
1406
1445
|
/**
|
|
1407
|
-
* Run a play end-to-end: submit,
|
|
1446
|
+
* Run a play end-to-end: submit, stream until terminal, return result.
|
|
1408
1447
|
*
|
|
1409
1448
|
* This is the highest-level play execution method. It submits the play,
|
|
1410
|
-
*
|
|
1411
|
-
* 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`.
|
|
1412
1451
|
*
|
|
1413
1452
|
* @param code - Source string fallback; pass the bundled artifact in `options.artifact`
|
|
1414
1453
|
* @param csvPath - Input CSV path, or `null`
|
|
@@ -1424,7 +1463,6 @@ var DeeplineClient = class {
|
|
|
1424
1463
|
* const logs = status.progress?.logs ?? [];
|
|
1425
1464
|
* console.log(`[${status.status}] ${logs.length} log lines`);
|
|
1426
1465
|
* },
|
|
1427
|
-
* pollIntervalMs: 1000,
|
|
1428
1466
|
* });
|
|
1429
1467
|
*
|
|
1430
1468
|
* if (result.success) {
|
|
@@ -1455,33 +1493,53 @@ var DeeplineClient = class {
|
|
|
1455
1493
|
packagedFiles: options?.packagedFiles,
|
|
1456
1494
|
force: options?.force
|
|
1457
1495
|
});
|
|
1458
|
-
const pollInterval = options?.pollIntervalMs ?? 500;
|
|
1459
1496
|
const start = Date.now();
|
|
1460
|
-
|
|
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
|
+
})) {
|
|
1461
1517
|
if (options?.signal?.aborted) {
|
|
1462
1518
|
await this.cancelPlay(workflowId);
|
|
1463
1519
|
return {
|
|
1464
1520
|
success: false,
|
|
1465
1521
|
runId: workflowId,
|
|
1466
|
-
logs:
|
|
1522
|
+
logs: state.logs,
|
|
1467
1523
|
durationMs: Date.now() - start,
|
|
1468
1524
|
error: "Cancelled by user"
|
|
1469
1525
|
};
|
|
1470
1526
|
}
|
|
1471
|
-
const status =
|
|
1527
|
+
const status = updatePlayLiveStatusState(state, event);
|
|
1528
|
+
if (!status) {
|
|
1529
|
+
continue;
|
|
1530
|
+
}
|
|
1472
1531
|
options?.onProgress?.(status);
|
|
1473
1532
|
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
|
-
};
|
|
1533
|
+
const finalStatus = await this.getPlayStatus(status.runId || workflowId).catch(() => status);
|
|
1534
|
+
return playRunResultFromStatus(finalStatus, start, workflowId);
|
|
1482
1535
|
}
|
|
1483
|
-
await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
|
|
1484
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
|
+
);
|
|
1485
1543
|
}
|
|
1486
1544
|
// ——————————————————————————————————————————————————————————
|
|
1487
1545
|
// Health
|
|
@@ -1555,18 +1613,24 @@ async function enforceSdkCompatibility(baseUrl) {
|
|
|
1555
1613
|
}
|
|
1556
1614
|
|
|
1557
1615
|
// src/cli/commands/auth.ts
|
|
1558
|
-
import { writeFileSync as
|
|
1616
|
+
import { writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
1559
1617
|
import { hostname } from "os";
|
|
1560
|
-
import { dirname as
|
|
1618
|
+
import { dirname as dirname3 } from "path";
|
|
1561
1619
|
|
|
1562
1620
|
// src/cli/utils.ts
|
|
1563
|
-
import {
|
|
1621
|
+
import {
|
|
1622
|
+
existsSync as existsSync2,
|
|
1623
|
+
mkdirSync as mkdirSync2,
|
|
1624
|
+
readFileSync as readFileSync2,
|
|
1625
|
+
writeFileSync as writeFileSync2
|
|
1626
|
+
} from "fs";
|
|
1564
1627
|
import { mkdir, writeFile } from "fs/promises";
|
|
1565
1628
|
import { homedir as homedir2 } from "os";
|
|
1566
|
-
import { join as join2, resolve as resolve2 } from "path";
|
|
1567
|
-
import {
|
|
1629
|
+
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
1630
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
1568
1631
|
import { parse } from "csv-parse/sync";
|
|
1569
1632
|
import { stringify } from "csv-stringify/sync";
|
|
1633
|
+
var BROWSER_FOCUS_COOLDOWN_MS = 3e4;
|
|
1570
1634
|
function getAuthedHttpClient() {
|
|
1571
1635
|
const config = resolveConfig();
|
|
1572
1636
|
return { config, http: new HttpClient(config) };
|
|
@@ -1578,12 +1642,215 @@ async function writeOutputFile(filename, content) {
|
|
|
1578
1642
|
await writeFile(fullPath, content, "utf-8");
|
|
1579
1643
|
return fullPath;
|
|
1580
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
|
+
}
|
|
1581
1837
|
function openInBrowser(url) {
|
|
1582
1838
|
try {
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
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" });
|
|
1587
1854
|
} catch {
|
|
1588
1855
|
}
|
|
1589
1856
|
}
|
|
@@ -1667,14 +1934,14 @@ function envFilePath(baseUrl) {
|
|
|
1667
1934
|
}
|
|
1668
1935
|
function saveEnvValues(values, baseUrl) {
|
|
1669
1936
|
const filePath = envFilePath(baseUrl);
|
|
1670
|
-
const dir =
|
|
1671
|
-
if (!
|
|
1672
|
-
|
|
1937
|
+
const dir = dirname3(filePath);
|
|
1938
|
+
if (!existsSync3(dir)) {
|
|
1939
|
+
mkdirSync3(dir, { recursive: true });
|
|
1673
1940
|
}
|
|
1674
|
-
const existing =
|
|
1941
|
+
const existing = existsSync3(filePath) ? parseEnvFile(filePath) : {};
|
|
1675
1942
|
const merged = { ...existing, ...values };
|
|
1676
1943
|
const lines = Object.entries(merged).filter(([, v]) => v !== "").map(([k, v]) => `${k}=${v}`);
|
|
1677
|
-
|
|
1944
|
+
writeFileSync3(filePath, lines.join("\n") + "\n", "utf-8");
|
|
1678
1945
|
saveProjectDeeplineEnvValues(baseUrl, values);
|
|
1679
1946
|
}
|
|
1680
1947
|
async function httpJson(method, url, apiKey, body) {
|
|
@@ -2213,7 +2480,7 @@ function registerBillingCommands(program) {
|
|
|
2213
2480
|
}
|
|
2214
2481
|
|
|
2215
2482
|
// src/cli/dataset-stats.ts
|
|
2216
|
-
import { writeFileSync as
|
|
2483
|
+
import { writeFileSync as writeFileSync4 } from "fs";
|
|
2217
2484
|
import { resolve as resolve3 } from "path";
|
|
2218
2485
|
var CSV_PROJECTED_FIELDS_KEY = "__deeplineCsvProjectedFields";
|
|
2219
2486
|
function csvProjectedFields(row) {
|
|
@@ -2545,7 +2812,7 @@ function writeCanonicalRowsCsv(rowsInfo, outPath) {
|
|
|
2545
2812
|
columns: rowsInfo.columns
|
|
2546
2813
|
});
|
|
2547
2814
|
const resolved = resolve3(outPath);
|
|
2548
|
-
|
|
2815
|
+
writeFileSync4(
|
|
2549
2816
|
resolved,
|
|
2550
2817
|
csvStringFromRows(sanitized.rows, sanitized.columns),
|
|
2551
2818
|
"utf-8"
|
|
@@ -2838,25 +3105,25 @@ function registerOrgCommands(program) {
|
|
|
2838
3105
|
// src/cli/commands/play.ts
|
|
2839
3106
|
import { createHash as createHash3 } from "crypto";
|
|
2840
3107
|
import {
|
|
2841
|
-
existsSync as
|
|
3108
|
+
existsSync as existsSync5,
|
|
2842
3109
|
readFileSync as readFileSync3,
|
|
2843
3110
|
readdirSync,
|
|
2844
3111
|
realpathSync,
|
|
2845
|
-
writeFileSync as
|
|
3112
|
+
writeFileSync as writeFileSync5
|
|
2846
3113
|
} from "fs";
|
|
2847
|
-
import { basename as basename3, dirname as
|
|
3114
|
+
import { basename as basename3, dirname as dirname7, join as join6, resolve as resolve7 } from "path";
|
|
2848
3115
|
|
|
2849
3116
|
// src/plays/bundle-play-file.ts
|
|
2850
3117
|
import { tmpdir as tmpdir2 } from "os";
|
|
2851
|
-
import { dirname as
|
|
3118
|
+
import { dirname as dirname6, join as join5, resolve as resolve6 } from "path";
|
|
2852
3119
|
import { fileURLToPath } from "url";
|
|
2853
|
-
import { existsSync as
|
|
3120
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2854
3121
|
|
|
2855
3122
|
// ../shared_libs/plays/bundling/index.ts
|
|
2856
3123
|
import { createHash } from "crypto";
|
|
2857
3124
|
import { mkdir as mkdir2, readFile, realpath, stat, writeFile as writeFile2 } from "fs/promises";
|
|
2858
3125
|
import { tmpdir } from "os";
|
|
2859
|
-
import { basename, dirname as
|
|
3126
|
+
import { basename, dirname as dirname4, extname, isAbsolute, join as join3, resolve as resolve4 } from "path";
|
|
2860
3127
|
import { builtinModules, createRequire } from "module";
|
|
2861
3128
|
import { build } from "esbuild";
|
|
2862
3129
|
|
|
@@ -2955,7 +3222,7 @@ async function normalizeLocalPath(filePath) {
|
|
|
2955
3222
|
function createPlayWorkspace(entryFile) {
|
|
2956
3223
|
return {
|
|
2957
3224
|
entryFile,
|
|
2958
|
-
rootDir:
|
|
3225
|
+
rootDir: dirname4(entryFile)
|
|
2959
3226
|
};
|
|
2960
3227
|
}
|
|
2961
3228
|
function isPathInsideDirectory(filePath, directory) {
|
|
@@ -3156,7 +3423,7 @@ function workersNamedPlayEntryAliasPlugin(playFilePath, exportName) {
|
|
|
3156
3423
|
contents: `export { ${exportName} as default } from ${JSON.stringify(playFilePath)};
|
|
3157
3424
|
`,
|
|
3158
3425
|
loader: "ts",
|
|
3159
|
-
resolveDir:
|
|
3426
|
+
resolveDir: dirname4(playFilePath)
|
|
3160
3427
|
})
|
|
3161
3428
|
);
|
|
3162
3429
|
}
|
|
@@ -3320,7 +3587,7 @@ function importedPlayProxyPlugin(importedPlayDependencies) {
|
|
|
3320
3587
|
return {
|
|
3321
3588
|
contents: buildImportedPlayProxyModule(dependency.playName),
|
|
3322
3589
|
loader: "ts",
|
|
3323
|
-
resolveDir:
|
|
3590
|
+
resolveDir: dirname4(args.path)
|
|
3324
3591
|
};
|
|
3325
3592
|
});
|
|
3326
3593
|
}
|
|
@@ -3338,7 +3605,7 @@ async function resolveLocalImport(fromFile, specifier) {
|
|
|
3338
3605
|
if (specifier.startsWith("file:")) {
|
|
3339
3606
|
return normalizeLocalPath(new URL(specifier).pathname);
|
|
3340
3607
|
}
|
|
3341
|
-
const base = isAbsolute(specifier) ? resolve4(specifier) : resolve4(
|
|
3608
|
+
const base = isAbsolute(specifier) ? resolve4(specifier) : resolve4(dirname4(fromFile), specifier);
|
|
3342
3609
|
const candidates = [base];
|
|
3343
3610
|
const explicitExtension = extname(base).toLowerCase();
|
|
3344
3611
|
if (!explicitExtension) {
|
|
@@ -3588,7 +3855,7 @@ async function runEsbuildForCjsNode(entryFile, importedPlayDependencies, adapter
|
|
|
3588
3855
|
...namedExportShim ? {
|
|
3589
3856
|
stdin: {
|
|
3590
3857
|
contents: namedExportShim,
|
|
3591
|
-
resolveDir:
|
|
3858
|
+
resolveDir: dirname4(entryFile),
|
|
3592
3859
|
sourcefile: `${basename(entryFile)}.${exportName}.entry.ts`,
|
|
3593
3860
|
loader: "ts"
|
|
3594
3861
|
}
|
|
@@ -3844,13 +4111,6 @@ var PLAY_DEDUP_BACKENDS = {
|
|
|
3844
4111
|
|
|
3845
4112
|
// ../shared_libs/play-runtime/profiles.ts
|
|
3846
4113
|
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
4114
|
workers_edge: {
|
|
3855
4115
|
id: "workers_edge",
|
|
3856
4116
|
scheduler: PLAY_SCHEDULER_BACKENDS.cfWorkflows,
|
|
@@ -3885,7 +4145,7 @@ function resolveExecutionProfile(override) {
|
|
|
3885
4145
|
// src/plays/local-file-discovery.ts
|
|
3886
4146
|
import { createHash as createHash2 } from "crypto";
|
|
3887
4147
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
3888
|
-
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";
|
|
3889
4149
|
var SOURCE_EXTENSIONS2 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
|
|
3890
4150
|
function sha2562(buffer) {
|
|
3891
4151
|
return createHash2("sha256").update(buffer).digest("hex");
|
|
@@ -4086,7 +4346,7 @@ function isPathInsideDirectory2(filePath, directory) {
|
|
|
4086
4346
|
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute2(relativePath);
|
|
4087
4347
|
}
|
|
4088
4348
|
async function resolveLocalImport2(fromFile, specifier) {
|
|
4089
|
-
const base = isAbsolute2(specifier) ? resolve5(specifier) : resolve5(
|
|
4349
|
+
const base = isAbsolute2(specifier) ? resolve5(specifier) : resolve5(dirname5(fromFile), specifier);
|
|
4090
4350
|
const candidates = [base];
|
|
4091
4351
|
const explicitExtension = extname2(base).toLowerCase();
|
|
4092
4352
|
if (!explicitExtension) {
|
|
@@ -4105,7 +4365,7 @@ async function resolveLocalImport2(fromFile, specifier) {
|
|
|
4105
4365
|
}
|
|
4106
4366
|
async function discoverPackagedLocalFiles(entryFile) {
|
|
4107
4367
|
const absoluteEntryFile = resolve5(entryFile);
|
|
4108
|
-
const packagingRoot =
|
|
4368
|
+
const packagingRoot = dirname5(absoluteEntryFile);
|
|
4109
4369
|
const files = /* @__PURE__ */ new Map();
|
|
4110
4370
|
const unresolved = [];
|
|
4111
4371
|
const visitedFiles = /* @__PURE__ */ new Set();
|
|
@@ -4142,7 +4402,7 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
4142
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."
|
|
4143
4403
|
});
|
|
4144
4404
|
} else {
|
|
4145
|
-
const absoluteCsvPath = resolve5(
|
|
4405
|
+
const absoluteCsvPath = resolve5(dirname5(absolutePath), resolvedPath);
|
|
4146
4406
|
if (isAbsolute2(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
|
|
4147
4407
|
unresolved.push({
|
|
4148
4408
|
sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
|
|
@@ -4181,14 +4441,14 @@ async function discoverPackagedLocalFiles(entryFile) {
|
|
|
4181
4441
|
|
|
4182
4442
|
// src/plays/bundle-play-file.ts
|
|
4183
4443
|
var PLAY_BUNDLE_CACHE_VERSION2 = 26;
|
|
4184
|
-
var MODULE_DIR =
|
|
4444
|
+
var MODULE_DIR = dirname6(fileURLToPath(import.meta.url));
|
|
4185
4445
|
var SDK_PACKAGE_ROOT = resolve6(MODULE_DIR, "..", "..");
|
|
4186
4446
|
var SOURCE_REPO_ROOT = resolve6(SDK_PACKAGE_ROOT, "..");
|
|
4187
|
-
var HAS_SOURCE_BUNDLING_SOURCES =
|
|
4447
|
+
var HAS_SOURCE_BUNDLING_SOURCES = existsSync4(
|
|
4188
4448
|
resolve6(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
4189
4449
|
);
|
|
4190
4450
|
var PACKAGED_REPO_ROOT = resolve6(SDK_PACKAGE_ROOT, "dist", "repo");
|
|
4191
|
-
var HAS_PACKAGED_BUNDLING_SOURCES =
|
|
4451
|
+
var HAS_PACKAGED_BUNDLING_SOURCES = existsSync4(
|
|
4192
4452
|
resolve6(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
|
|
4193
4453
|
);
|
|
4194
4454
|
var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : resolve6(SDK_PACKAGE_ROOT, "..");
|
|
@@ -4227,7 +4487,7 @@ function createSdkPlayBundlingAdapter() {
|
|
|
4227
4487
|
sdkSourceRoot: SDK_SOURCE_ROOT,
|
|
4228
4488
|
sdkPackageJson: SDK_PACKAGE_JSON,
|
|
4229
4489
|
sdkEntryFile: SDK_ENTRY_FILE,
|
|
4230
|
-
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !
|
|
4490
|
+
sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !existsSync4(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
|
|
4231
4491
|
sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
|
|
4232
4492
|
workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
|
|
4233
4493
|
workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
|
|
@@ -4513,15 +4773,15 @@ function materializeRemotePlaySource(input) {
|
|
|
4513
4773
|
return null;
|
|
4514
4774
|
}
|
|
4515
4775
|
const outputPath = input.outPath ?? defaultMaterializedPlayPath(input.playName);
|
|
4516
|
-
if (
|
|
4776
|
+
if (existsSync5(outputPath)) {
|
|
4517
4777
|
const existingSource = readFileSync3(outputPath, "utf-8");
|
|
4518
4778
|
if (existingSource === input.sourceCode) {
|
|
4519
4779
|
return { path: outputPath, status: "unchanged", created: false };
|
|
4520
4780
|
}
|
|
4521
|
-
|
|
4781
|
+
writeFileSync5(outputPath, input.sourceCode, "utf-8");
|
|
4522
4782
|
return { path: outputPath, status: "updated", created: false };
|
|
4523
4783
|
}
|
|
4524
|
-
|
|
4784
|
+
writeFileSync5(outputPath, input.sourceCode, "utf-8");
|
|
4525
4785
|
return { path: outputPath, status: "created", created: true };
|
|
4526
4786
|
}
|
|
4527
4787
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -4566,7 +4826,7 @@ function extractPlayName(code, filePath) {
|
|
|
4566
4826
|
throw buildMissingDefinePlayError(filePath);
|
|
4567
4827
|
}
|
|
4568
4828
|
function isFileTarget(target) {
|
|
4569
|
-
return
|
|
4829
|
+
return existsSync5(resolve7(target));
|
|
4570
4830
|
}
|
|
4571
4831
|
function looksLikeFilePath(target) {
|
|
4572
4832
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -4695,7 +4955,7 @@ function applyCsvShortcutInput(input) {
|
|
|
4695
4955
|
function isLocalFilePathValue(value) {
|
|
4696
4956
|
if (typeof value !== "string" || !value.trim()) return false;
|
|
4697
4957
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
4698
|
-
return
|
|
4958
|
+
return existsSync5(resolve7(value));
|
|
4699
4959
|
}
|
|
4700
4960
|
function inputContainsLocalFilePath(value) {
|
|
4701
4961
|
if (isLocalFilePathValue(value)) {
|
|
@@ -4900,7 +5160,7 @@ function formatTimestamp(value) {
|
|
|
4900
5160
|
function formatRunLine(run) {
|
|
4901
5161
|
return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)}`;
|
|
4902
5162
|
}
|
|
4903
|
-
function
|
|
5163
|
+
function isTransientPlayStreamError(error) {
|
|
4904
5164
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
4905
5165
|
return error.statusCode >= 500 && error.statusCode < 600;
|
|
4906
5166
|
}
|
|
@@ -4909,12 +5169,6 @@ function isTransientPlayStatusPollError(error) {
|
|
|
4909
5169
|
text
|
|
4910
5170
|
);
|
|
4911
5171
|
}
|
|
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
5172
|
var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
4919
5173
|
"completed",
|
|
4920
5174
|
"failed",
|
|
@@ -4980,6 +5234,12 @@ function buildPlayDashboardUrl(baseUrl, playName) {
|
|
|
4980
5234
|
const encodedPlayName = encodeURIComponent(playName);
|
|
4981
5235
|
return `${trimmedBase}/dashboard/plays/${encodedPlayName}`;
|
|
4982
5236
|
}
|
|
5237
|
+
function openPlayDashboard(input) {
|
|
5238
|
+
if (input.jsonOutput || input.noOpen || !input.dashboardUrl) {
|
|
5239
|
+
return;
|
|
5240
|
+
}
|
|
5241
|
+
openInBrowser(input.dashboardUrl);
|
|
5242
|
+
}
|
|
4983
5243
|
function getDashboardUrlFromLiveEvent(event) {
|
|
4984
5244
|
const dashboardUrl = getEventPayload(event).dashboardUrl;
|
|
4985
5245
|
return typeof dashboardUrl === "string" && dashboardUrl.trim() ? dashboardUrl.trim() : null;
|
|
@@ -5016,6 +5276,68 @@ function assertPlayWaitNotTimedOut(input) {
|
|
|
5016
5276
|
);
|
|
5017
5277
|
}
|
|
5018
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
|
+
}
|
|
5019
5341
|
async function startAndWaitForPlayCompletionByStream(input) {
|
|
5020
5342
|
const startedAt = Date.now();
|
|
5021
5343
|
const state = {
|
|
@@ -5049,6 +5371,11 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5049
5371
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
5050
5372
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
5051
5373
|
const dashboardUrl = getDashboardUrlFromLiveEvent(event) ?? buildPlayDashboardUrl(input.client.baseUrl, input.playName);
|
|
5374
|
+
openPlayDashboard({
|
|
5375
|
+
dashboardUrl,
|
|
5376
|
+
jsonOutput: input.jsonOutput,
|
|
5377
|
+
noOpen: input.noOpen
|
|
5378
|
+
});
|
|
5052
5379
|
if (!input.jsonOutput) {
|
|
5053
5380
|
writeStartedPlayRun({
|
|
5054
5381
|
runId: workflowId,
|
|
@@ -5104,21 +5431,21 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5104
5431
|
lastPhase
|
|
5105
5432
|
});
|
|
5106
5433
|
}
|
|
5107
|
-
if (lastKnownWorkflowId &&
|
|
5434
|
+
if (lastKnownWorkflowId && isTransientPlayStreamError(error)) {
|
|
5108
5435
|
if (timeout) {
|
|
5109
5436
|
clearTimeout(timeout);
|
|
5110
5437
|
}
|
|
5111
5438
|
const reason = error instanceof Error ? error.message : String(error);
|
|
5112
5439
|
if (!input.jsonOutput) {
|
|
5113
5440
|
process.stderr.write(
|
|
5114
|
-
`[play watch] start stream failed after run ${lastKnownWorkflowId};
|
|
5441
|
+
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
|
|
5115
5442
|
`
|
|
5116
5443
|
);
|
|
5117
5444
|
}
|
|
5118
5445
|
recordCliTrace({
|
|
5119
|
-
phase: "cli.
|
|
5446
|
+
phase: "cli.play_start_stream_reconnect",
|
|
5120
5447
|
ms: Date.now() - startedAt,
|
|
5121
|
-
ok:
|
|
5448
|
+
ok: true,
|
|
5122
5449
|
playName: input.playName,
|
|
5123
5450
|
workflowId: lastKnownWorkflowId,
|
|
5124
5451
|
eventCount,
|
|
@@ -5126,10 +5453,9 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5126
5453
|
lastPhase,
|
|
5127
5454
|
reason
|
|
5128
5455
|
});
|
|
5129
|
-
return
|
|
5456
|
+
return waitForPlayCompletionByStream({
|
|
5130
5457
|
client: input.client,
|
|
5131
5458
|
workflowId: lastKnownWorkflowId,
|
|
5132
|
-
pollIntervalMs: 500,
|
|
5133
5459
|
jsonOutput: input.jsonOutput,
|
|
5134
5460
|
emitLogs: input.emitLogs,
|
|
5135
5461
|
waitTimeoutMs: input.waitTimeoutMs,
|
|
@@ -5147,13 +5473,13 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5147
5473
|
if (lastKnownWorkflowId) {
|
|
5148
5474
|
if (!input.jsonOutput) {
|
|
5149
5475
|
input.progress.writeLine(
|
|
5150
|
-
`[play watch] start stream ended after run ${lastKnownWorkflowId};
|
|
5476
|
+
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
|
|
5151
5477
|
);
|
|
5152
5478
|
}
|
|
5153
5479
|
recordCliTrace({
|
|
5154
|
-
phase: "cli.
|
|
5480
|
+
phase: "cli.play_start_stream_reconnect",
|
|
5155
5481
|
ms: Date.now() - startedAt,
|
|
5156
|
-
ok:
|
|
5482
|
+
ok: true,
|
|
5157
5483
|
playName: input.playName,
|
|
5158
5484
|
workflowId: lastKnownWorkflowId,
|
|
5159
5485
|
eventCount,
|
|
@@ -5161,10 +5487,9 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5161
5487
|
lastPhase,
|
|
5162
5488
|
reason: "stream ended before terminal event"
|
|
5163
5489
|
});
|
|
5164
|
-
return
|
|
5490
|
+
return waitForPlayCompletionByStream({
|
|
5165
5491
|
client: input.client,
|
|
5166
5492
|
workflowId: lastKnownWorkflowId,
|
|
5167
|
-
pollIntervalMs: 500,
|
|
5168
5493
|
jsonOutput: input.jsonOutput,
|
|
5169
5494
|
emitLogs: input.emitLogs,
|
|
5170
5495
|
waitTimeoutMs: input.waitTimeoutMs,
|
|
@@ -5185,72 +5510,6 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5185
5510
|
}
|
|
5186
5511
|
);
|
|
5187
5512
|
}
|
|
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
5513
|
function formatInteger(value) {
|
|
5255
5514
|
return typeof value === "number" && Number.isFinite(value) ? value.toLocaleString("en-US") : String(value ?? "-");
|
|
5256
5515
|
}
|
|
@@ -5391,7 +5650,6 @@ function buildRunWarnings(status, rowsInfo) {
|
|
|
5391
5650
|
function buildRunNextCommands(runId, rowsInfo) {
|
|
5392
5651
|
const commands = {
|
|
5393
5652
|
get: `deepline runs get ${runId} --json`,
|
|
5394
|
-
tail: `deepline runs tail ${runId} --json`,
|
|
5395
5653
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
5396
5654
|
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
5397
5655
|
};
|
|
@@ -5507,10 +5765,9 @@ function normalizeErrorsForEnvelope(status, error) {
|
|
|
5507
5765
|
}
|
|
5508
5766
|
function normalizeLogsForEnvelope(status) {
|
|
5509
5767
|
const logs = Array.isArray(status.progress?.logs) ? status.progress.logs : [];
|
|
5510
|
-
const
|
|
5511
|
-
const totalCount = offset + logs.length;
|
|
5768
|
+
const totalCount = logs.length;
|
|
5512
5769
|
const entries = logs.slice(Math.max(0, logs.length - RUN_LOG_PREVIEW_LIMIT));
|
|
5513
|
-
const firstSequence = entries.length === 0 ? null :
|
|
5770
|
+
const firstSequence = entries.length === 0 ? null : logs.length - entries.length + 1;
|
|
5514
5771
|
const lastSequence = totalCount === 0 ? null : totalCount;
|
|
5515
5772
|
return {
|
|
5516
5773
|
totalCount,
|
|
@@ -5756,7 +6013,6 @@ function writeStartedPlayRun(input) {
|
|
|
5756
6013
|
workflowId: input.runId,
|
|
5757
6014
|
name: input.playName,
|
|
5758
6015
|
status: input.status ?? "started",
|
|
5759
|
-
statusUrl: input.statusUrl,
|
|
5760
6016
|
dashboardUrl: input.dashboardUrl
|
|
5761
6017
|
};
|
|
5762
6018
|
if (input.jsonOutput) {
|
|
@@ -5768,7 +6024,7 @@ function writeStartedPlayRun(input) {
|
|
|
5768
6024
|
`Started ${input.playName}`,
|
|
5769
6025
|
` run id: ${input.runId}`,
|
|
5770
6026
|
` get status: deepline runs get ${input.runId} --json`,
|
|
5771
|
-
`
|
|
6027
|
+
` logs: deepline runs logs ${input.runId} --json`,
|
|
5772
6028
|
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`,
|
|
5773
6029
|
` result JSON: deepline runs get ${input.runId} --json`
|
|
5774
6030
|
];
|
|
@@ -5783,7 +6039,7 @@ function writeStartedPlayRun(input) {
|
|
|
5783
6039
|
console.log(output);
|
|
5784
6040
|
}
|
|
5785
6041
|
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]";
|
|
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.";
|
|
5787
6043
|
let filePath = null;
|
|
5788
6044
|
let playName = null;
|
|
5789
6045
|
let input = null;
|
|
@@ -5793,8 +6049,8 @@ function parsePlayRunOptions(args) {
|
|
|
5793
6049
|
let jsonOutput = watch ? args.includes("--json") : argsWantJson(args);
|
|
5794
6050
|
const emitLogs = !jsonOutput || args.includes("--logs");
|
|
5795
6051
|
const force = args.includes("--force");
|
|
6052
|
+
const noOpen = args.includes("--no-open");
|
|
5796
6053
|
let outPath = null;
|
|
5797
|
-
let pollIntervalMs = 500;
|
|
5798
6054
|
let waitTimeoutMs = null;
|
|
5799
6055
|
for (let index = 0; index < args.length; index += 1) {
|
|
5800
6056
|
const arg = args[index];
|
|
@@ -5826,15 +6082,16 @@ function parsePlayRunOptions(args) {
|
|
|
5826
6082
|
outPath = resolve7(args[++index]);
|
|
5827
6083
|
continue;
|
|
5828
6084
|
}
|
|
5829
|
-
if (
|
|
5830
|
-
|
|
5831
|
-
|
|
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
|
+
);
|
|
5832
6089
|
}
|
|
5833
6090
|
if ((arg === "--tail-timeout-ms" || arg === "--timeout-ms") && args[index + 1]) {
|
|
5834
6091
|
waitTimeoutMs = parsePositiveInteger2(args[++index], arg);
|
|
5835
6092
|
continue;
|
|
5836
6093
|
}
|
|
5837
|
-
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") {
|
|
5838
6095
|
if (arg === "--watch") {
|
|
5839
6096
|
continue;
|
|
5840
6097
|
}
|
|
@@ -5903,10 +6160,10 @@ function parsePlayRunOptions(args) {
|
|
|
5903
6160
|
watch,
|
|
5904
6161
|
emitLogs,
|
|
5905
6162
|
jsonOutput,
|
|
5906
|
-
pollIntervalMs,
|
|
5907
6163
|
waitTimeoutMs,
|
|
5908
6164
|
force,
|
|
5909
|
-
outPath
|
|
6165
|
+
outPath,
|
|
6166
|
+
noOpen
|
|
5910
6167
|
};
|
|
5911
6168
|
}
|
|
5912
6169
|
function parsePlayCheckOptions(args) {
|
|
@@ -6081,6 +6338,7 @@ async function handleFileBackedRun(options) {
|
|
|
6081
6338
|
jsonOutput: options.jsonOutput,
|
|
6082
6339
|
emitLogs: options.emitLogs,
|
|
6083
6340
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
6341
|
+
noOpen: options.noOpen,
|
|
6084
6342
|
progress
|
|
6085
6343
|
})
|
|
6086
6344
|
);
|
|
@@ -6108,14 +6366,19 @@ async function handleFileBackedRun(options) {
|
|
|
6108
6366
|
() => client.startPlayRun(startRequest)
|
|
6109
6367
|
);
|
|
6110
6368
|
const dashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
6111
|
-
|
|
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}`);
|
|
6112
6376
|
progress.complete();
|
|
6113
6377
|
writeStartedPlayRun({
|
|
6114
6378
|
runId: started.workflowId,
|
|
6115
6379
|
playName,
|
|
6116
6380
|
status: started.status,
|
|
6117
|
-
|
|
6118
|
-
dashboardUrl: started.dashboardUrl ?? dashboardUrl,
|
|
6381
|
+
dashboardUrl: resolvedDashboardUrl,
|
|
6119
6382
|
jsonOutput: options.jsonOutput,
|
|
6120
6383
|
progress
|
|
6121
6384
|
});
|
|
@@ -6220,6 +6483,7 @@ async function handleNamedRun(options) {
|
|
|
6220
6483
|
jsonOutput: options.jsonOutput,
|
|
6221
6484
|
emitLogs: options.emitLogs,
|
|
6222
6485
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
6486
|
+
noOpen: options.noOpen,
|
|
6223
6487
|
progress
|
|
6224
6488
|
})
|
|
6225
6489
|
);
|
|
@@ -6250,14 +6514,19 @@ async function handleNamedRun(options) {
|
|
|
6250
6514
|
client.baseUrl,
|
|
6251
6515
|
playName
|
|
6252
6516
|
);
|
|
6253
|
-
|
|
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}`);
|
|
6254
6524
|
progress.complete();
|
|
6255
6525
|
writeStartedPlayRun({
|
|
6256
6526
|
runId: started.workflowId,
|
|
6257
6527
|
playName: started.name ?? playName,
|
|
6258
6528
|
status: started.status,
|
|
6259
|
-
|
|
6260
|
-
dashboardUrl: started.dashboardUrl ?? dashboardUrl,
|
|
6529
|
+
dashboardUrl: resolvedDashboardUrl,
|
|
6261
6530
|
jsonOutput: options.jsonOutput,
|
|
6262
6531
|
progress
|
|
6263
6532
|
});
|
|
@@ -6271,8 +6540,8 @@ async function handlePlayRun(args) {
|
|
|
6271
6540
|
}
|
|
6272
6541
|
const resolved = resolve7(options.target.path);
|
|
6273
6542
|
console.error(`File not found: ${resolved}`);
|
|
6274
|
-
const dir =
|
|
6275
|
-
if (
|
|
6543
|
+
const dir = dirname7(resolved);
|
|
6544
|
+
if (existsSync5(dir)) {
|
|
6276
6545
|
const base = basename3(resolved);
|
|
6277
6546
|
try {
|
|
6278
6547
|
const siblings = readdirSync(dir).filter(
|
|
@@ -6300,7 +6569,7 @@ function parseRunIdPositional(args, usage) {
|
|
|
6300
6569
|
}
|
|
6301
6570
|
continue;
|
|
6302
6571
|
}
|
|
6303
|
-
if ((arg === "--out" || arg === "--
|
|
6572
|
+
if ((arg === "--out" || arg === "--reason") && args[index + 1]) {
|
|
6304
6573
|
index += 1;
|
|
6305
6574
|
continue;
|
|
6306
6575
|
}
|
|
@@ -6385,7 +6654,7 @@ async function handleRunsList(args) {
|
|
|
6385
6654
|
return 0;
|
|
6386
6655
|
}
|
|
6387
6656
|
async function handleRunTail(args) {
|
|
6388
|
-
const usage = "Usage: deepline runs tail <run-id> [--json] [--compact]
|
|
6657
|
+
const usage = "Usage: deepline runs tail <run-id> [--json] [--compact]";
|
|
6389
6658
|
let runId;
|
|
6390
6659
|
try {
|
|
6391
6660
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -6393,20 +6662,19 @@ async function handleRunTail(args) {
|
|
|
6393
6662
|
console.error(error instanceof Error ? error.message : usage);
|
|
6394
6663
|
return 1;
|
|
6395
6664
|
}
|
|
6396
|
-
const client = new DeeplineClient();
|
|
6397
|
-
let afterLogIndex;
|
|
6398
6665
|
for (let index = 0; index < args.length; index += 1) {
|
|
6399
6666
|
const arg = args[index];
|
|
6400
|
-
if (arg === "--cursor"
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
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;
|
|
6405
6674
|
}
|
|
6406
6675
|
}
|
|
6407
|
-
const
|
|
6408
|
-
|
|
6409
|
-
});
|
|
6676
|
+
const client = new DeeplineClient();
|
|
6677
|
+
const status = await client.runs.tail(runId);
|
|
6410
6678
|
writePlayResult(status, argsWantJson(args));
|
|
6411
6679
|
return status.status === "failed" ? 1 : 0;
|
|
6412
6680
|
}
|
|
@@ -6435,7 +6703,7 @@ async function handleRunLogs(args) {
|
|
|
6435
6703
|
const status = await client.runs.get(runId);
|
|
6436
6704
|
const logs = status.progress?.logs ?? [];
|
|
6437
6705
|
if (outPath) {
|
|
6438
|
-
|
|
6706
|
+
writeFileSync5(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
|
|
6439
6707
|
if (argsWantJson(args)) {
|
|
6440
6708
|
process.stdout.write(
|
|
6441
6709
|
`${JSON.stringify({
|
|
@@ -6947,8 +7215,9 @@ function registerPlayCommands(program) {
|
|
|
6947
7215
|
"after",
|
|
6948
7216
|
`
|
|
6949
7217
|
Concepts:
|
|
6950
|
-
Plays are durable
|
|
6951
|
-
|
|
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.
|
|
6952
7221
|
|
|
6953
7222
|
Common commands:
|
|
6954
7223
|
deepline plays search email --json
|
|
@@ -6979,17 +7248,42 @@ Examples:
|
|
|
6979
7248
|
"after",
|
|
6980
7249
|
`
|
|
6981
7250
|
Notes:
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
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 })
|
|
6988
7280
|
|
|
6989
7281
|
Examples:
|
|
6990
7282
|
deepline plays run my.play.ts --input '{"domain":"stripe.com"}' --watch
|
|
6991
7283
|
deepline plays run person-linkedin-to-email --input '{"linkedin_url":"..."}' --watch
|
|
6992
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>
|
|
6993
7287
|
`
|
|
6994
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(
|
|
6995
7289
|
"--revision-id <id>",
|
|
@@ -7000,7 +7294,7 @@ Examples:
|
|
|
7000
7294
|
).option("--watch", "Stream logs until completion").option(
|
|
7001
7295
|
"--logs",
|
|
7002
7296
|
"When output is non-interactive, stream play logs to stderr while waiting"
|
|
7003
|
-
).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) => {
|
|
7004
7298
|
const passthroughArgs = [...command.args];
|
|
7005
7299
|
const explicitTarget = options.file || options.name;
|
|
7006
7300
|
const targetIsInputFlag = typeof target === "string" && target.startsWith("--");
|
|
@@ -7022,9 +7316,9 @@ Examples:
|
|
|
7022
7316
|
...options.out ? ["--out", options.out] : [],
|
|
7023
7317
|
...options.watch ? ["--watch"] : [],
|
|
7024
7318
|
...options.logs ? ["--logs"] : [],
|
|
7025
|
-
...options.pollIntervalMs ? ["--poll-interval-ms", options.pollIntervalMs] : [],
|
|
7026
7319
|
...options.tailTimeoutMs ? ["--tail-timeout-ms", options.tailTimeoutMs] : [],
|
|
7027
7320
|
...options.force ? ["--force"] : [],
|
|
7321
|
+
...options.open === false ? ["--no-open"] : [],
|
|
7028
7322
|
...options.json ? ["--json"] : [],
|
|
7029
7323
|
...passthroughArgs
|
|
7030
7324
|
]);
|
|
@@ -7131,12 +7425,11 @@ Examples:
|
|
|
7131
7425
|
...options.json ? ["--json"] : []
|
|
7132
7426
|
]);
|
|
7133
7427
|
});
|
|
7134
|
-
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) => {
|
|
7135
7429
|
process.exitCode = await handleRunTail([
|
|
7136
7430
|
runId,
|
|
7137
7431
|
...options.json ? ["--json"] : [],
|
|
7138
|
-
...options.compact ? ["--compact"] : []
|
|
7139
|
-
...options.cursor ? ["--cursor", options.cursor] : []
|
|
7432
|
+
...options.compact ? ["--compact"] : []
|
|
7140
7433
|
]);
|
|
7141
7434
|
});
|
|
7142
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) => {
|
|
@@ -7165,12 +7458,12 @@ Examples:
|
|
|
7165
7458
|
}
|
|
7166
7459
|
|
|
7167
7460
|
// src/cli/commands/tools.ts
|
|
7168
|
-
import { chmodSync, mkdtempSync, writeFileSync as
|
|
7461
|
+
import { chmodSync, mkdtempSync, writeFileSync as writeFileSync7 } from "fs";
|
|
7169
7462
|
import { tmpdir as tmpdir3 } from "os";
|
|
7170
7463
|
import { join as join8 } from "path";
|
|
7171
7464
|
|
|
7172
7465
|
// src/tool-output.ts
|
|
7173
|
-
import { mkdirSync as
|
|
7466
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
7174
7467
|
import { homedir as homedir3 } from "os";
|
|
7175
7468
|
import { join as join7 } from "path";
|
|
7176
7469
|
function isPlainObject(value) {
|
|
@@ -7248,13 +7541,13 @@ function tryConvertToList(payload, options) {
|
|
|
7248
7541
|
}
|
|
7249
7542
|
function ensureOutputDir() {
|
|
7250
7543
|
const outputDir = join7(homedir3(), ".local", "share", "deepline", "data");
|
|
7251
|
-
|
|
7544
|
+
mkdirSync4(outputDir, { recursive: true });
|
|
7252
7545
|
return outputDir;
|
|
7253
7546
|
}
|
|
7254
7547
|
function writeJsonOutputFile(payload, stem) {
|
|
7255
7548
|
const outputDir = ensureOutputDir();
|
|
7256
7549
|
const outputPath = join7(outputDir, `${stem}_${Date.now()}.json`);
|
|
7257
|
-
|
|
7550
|
+
writeFileSync6(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
7258
7551
|
return outputPath;
|
|
7259
7552
|
}
|
|
7260
7553
|
function writeCsvOutputFile(rows, stem) {
|
|
@@ -7282,7 +7575,7 @@ function writeCsvOutputFile(rows, stem) {
|
|
|
7282
7575
|
for (const row of rows) {
|
|
7283
7576
|
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
7284
7577
|
}
|
|
7285
|
-
|
|
7578
|
+
writeFileSync6(outputPath, `${lines.join("\n")}
|
|
7286
7579
|
`, "utf-8");
|
|
7287
7580
|
const previewRows = rows.slice(0, 5);
|
|
7288
7581
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -7819,7 +8112,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
7819
8112
|
};
|
|
7820
8113
|
});
|
|
7821
8114
|
`;
|
|
7822
|
-
|
|
8115
|
+
writeFileSync7(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
7823
8116
|
return {
|
|
7824
8117
|
path: scriptPath,
|
|
7825
8118
|
projectDir,
|
|
@@ -7926,10 +8219,10 @@ async function executeTool(args) {
|
|
|
7926
8219
|
}
|
|
7927
8220
|
|
|
7928
8221
|
// src/cli/skills-sync.ts
|
|
7929
|
-
import { spawn, spawnSync } from "child_process";
|
|
7930
|
-
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";
|
|
7931
8224
|
import { homedir as homedir4 } from "os";
|
|
7932
|
-
import { dirname as
|
|
8225
|
+
import { dirname as dirname8, join as join9 } from "path";
|
|
7933
8226
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
7934
8227
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
7935
8228
|
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
@@ -7944,7 +8237,7 @@ function sdkSkillsVersionPath(baseUrl) {
|
|
|
7944
8237
|
}
|
|
7945
8238
|
function readLocalSkillsVersion(baseUrl) {
|
|
7946
8239
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
7947
|
-
if (!
|
|
8240
|
+
if (!existsSync6(path)) return "";
|
|
7948
8241
|
try {
|
|
7949
8242
|
return readFileSync4(path, "utf-8").trim();
|
|
7950
8243
|
} catch {
|
|
@@ -7953,8 +8246,8 @@ function readLocalSkillsVersion(baseUrl) {
|
|
|
7953
8246
|
}
|
|
7954
8247
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
7955
8248
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
7956
|
-
|
|
7957
|
-
|
|
8249
|
+
mkdirSync5(dirname8(path), { recursive: true });
|
|
8250
|
+
writeFileSync8(path, `${version}
|
|
7958
8251
|
`, "utf-8");
|
|
7959
8252
|
}
|
|
7960
8253
|
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
@@ -8018,7 +8311,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
|
|
|
8018
8311
|
];
|
|
8019
8312
|
}
|
|
8020
8313
|
function hasCommand(command) {
|
|
8021
|
-
const result =
|
|
8314
|
+
const result = spawnSync2(command, ["--version"], {
|
|
8022
8315
|
stdio: "ignore",
|
|
8023
8316
|
shell: process.platform === "win32"
|
|
8024
8317
|
});
|