deepline 0.1.19 → 0.1.21
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 +391 -129
- package/dist/cli/index.mjs +391 -129
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +53 -7
- package/dist/index.mjs +53 -7
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +999 -257
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +604 -75
- package/dist/repo/apps/play-runner-workers/src/entry.ts +442 -357
- package/dist/repo/sdk/src/client.ts +46 -4
- package/dist/repo/sdk/src/http.ts +38 -4
- package/dist/repo/sdk/src/plays/harness-stub.ts +12 -0
- package/dist/repo/sdk/src/version.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +3 -6
- package/dist/repo/shared_libs/plays/row-identity.ts +59 -4
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -266,7 +266,7 @@ function saveProjectDeeplineEnvValues(baseUrl, values, startDir = projectEnvStar
|
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
// src/version.ts
|
|
269
|
-
var SDK_VERSION = "0.1.
|
|
269
|
+
var SDK_VERSION = "0.1.21";
|
|
270
270
|
var SDK_API_CONTRACT = "2026-05-runs-v2";
|
|
271
271
|
|
|
272
272
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
@@ -349,7 +349,7 @@ var HttpClient = class {
|
|
|
349
349
|
const response = await fetch(candidateUrl, {
|
|
350
350
|
method,
|
|
351
351
|
headers,
|
|
352
|
-
body: options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
352
|
+
body: options?.formData !== void 0 ? options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
353
353
|
signal: controller.signal
|
|
354
354
|
});
|
|
355
355
|
clearTimeout(timeoutId);
|
|
@@ -373,7 +373,8 @@ var HttpClient = class {
|
|
|
373
373
|
parsed = body;
|
|
374
374
|
}
|
|
375
375
|
if (!response.ok) {
|
|
376
|
-
const
|
|
376
|
+
const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
|
|
377
|
+
const msg = typeof errorValue === "string" ? errorValue : errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string" ? errorValue.message : typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string" ? parsed.message : `HTTP ${response.status}`;
|
|
377
378
|
throw new DeeplineError(msg, response.status, "API_ERROR", {
|
|
378
379
|
response: parsed
|
|
379
380
|
});
|
|
@@ -467,6 +468,13 @@ var HttpClient = class {
|
|
|
467
468
|
headers
|
|
468
469
|
});
|
|
469
470
|
}
|
|
471
|
+
async postFormData(path, formData, headers) {
|
|
472
|
+
return this.request(path, {
|
|
473
|
+
method: "POST",
|
|
474
|
+
formData,
|
|
475
|
+
headers
|
|
476
|
+
});
|
|
477
|
+
}
|
|
470
478
|
/**
|
|
471
479
|
* Send a DELETE request.
|
|
472
480
|
*
|
|
@@ -575,6 +583,14 @@ function mapLegacyTemporalStatus(status) {
|
|
|
575
583
|
return "running";
|
|
576
584
|
}
|
|
577
585
|
}
|
|
586
|
+
function decodeBase64Bytes(value) {
|
|
587
|
+
const binary = atob(value);
|
|
588
|
+
const bytes = new Uint8Array(binary.length);
|
|
589
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
590
|
+
bytes[index] = binary.charCodeAt(index);
|
|
591
|
+
}
|
|
592
|
+
return bytes;
|
|
593
|
+
}
|
|
578
594
|
var DeeplineClient = class {
|
|
579
595
|
http;
|
|
580
596
|
config;
|
|
@@ -1026,9 +1042,34 @@ var DeeplineClient = class {
|
|
|
1026
1042
|
* ```
|
|
1027
1043
|
*/
|
|
1028
1044
|
async stagePlayFiles(files) {
|
|
1029
|
-
const
|
|
1045
|
+
const formData = new FormData();
|
|
1046
|
+
formData.set(
|
|
1047
|
+
"metadata",
|
|
1048
|
+
JSON.stringify({
|
|
1049
|
+
files: files.map((file, index) => ({
|
|
1050
|
+
index,
|
|
1051
|
+
logicalPath: file.logicalPath,
|
|
1052
|
+
contentHash: file.contentHash,
|
|
1053
|
+
contentType: file.contentType,
|
|
1054
|
+
bytes: file.bytes
|
|
1055
|
+
}))
|
|
1056
|
+
})
|
|
1057
|
+
);
|
|
1058
|
+
for (const [index, file] of files.entries()) {
|
|
1059
|
+
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1060
|
+
const body = bytes.buffer.slice(
|
|
1061
|
+
bytes.byteOffset,
|
|
1062
|
+
bytes.byteOffset + bytes.byteLength
|
|
1063
|
+
);
|
|
1064
|
+
formData.set(
|
|
1065
|
+
`file:${index}`,
|
|
1066
|
+
new Blob([body], { type: file.contentType }),
|
|
1067
|
+
file.logicalPath
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
const response = await this.http.postFormData(
|
|
1030
1071
|
"/api/v2/plays/files/stage",
|
|
1031
|
-
|
|
1072
|
+
formData
|
|
1032
1073
|
);
|
|
1033
1074
|
return response.files;
|
|
1034
1075
|
}
|
|
@@ -1057,9 +1098,14 @@ var DeeplineClient = class {
|
|
|
1057
1098
|
* console.log(`Logs: ${status.progress?.logs.length ?? 0} lines`);
|
|
1058
1099
|
* ```
|
|
1059
1100
|
*/
|
|
1060
|
-
async getPlayStatus(workflowId) {
|
|
1101
|
+
async getPlayStatus(workflowId, options) {
|
|
1102
|
+
const params = new URLSearchParams();
|
|
1103
|
+
if (options?.billing === false) {
|
|
1104
|
+
params.set("billing", "false");
|
|
1105
|
+
}
|
|
1106
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
1061
1107
|
const response = await this.http.get(
|
|
1062
|
-
`/api/v2/plays/run/${encodeURIComponent(workflowId)}`
|
|
1108
|
+
`/api/v2/plays/run/${encodeURIComponent(workflowId)}${query}`
|
|
1063
1109
|
);
|
|
1064
1110
|
return normalizePlayStatus(response);
|
|
1065
1111
|
}
|
|
@@ -4361,7 +4407,77 @@ function createCliProgress(enabled) {
|
|
|
4361
4407
|
return progress;
|
|
4362
4408
|
}
|
|
4363
4409
|
|
|
4410
|
+
// src/cli/trace.ts
|
|
4411
|
+
var cliTraceStartedAt = Date.now();
|
|
4412
|
+
function isTruthyEnv(value) {
|
|
4413
|
+
return value === "1" || value === "true" || value === "yes";
|
|
4414
|
+
}
|
|
4415
|
+
function isCliTraceEnabled() {
|
|
4416
|
+
return isTruthyEnv(process.env.DEEPLINE_CLI_TRACE);
|
|
4417
|
+
}
|
|
4418
|
+
function recordCliTrace(event) {
|
|
4419
|
+
if (!isCliTraceEnabled()) {
|
|
4420
|
+
return;
|
|
4421
|
+
}
|
|
4422
|
+
const now = Date.now();
|
|
4423
|
+
const payload = {
|
|
4424
|
+
ts: now,
|
|
4425
|
+
source: "cli",
|
|
4426
|
+
sinceStartMs: now - cliTraceStartedAt,
|
|
4427
|
+
...event
|
|
4428
|
+
};
|
|
4429
|
+
process.stderr.write(`[cli-trace] ${JSON.stringify(payload)}
|
|
4430
|
+
`);
|
|
4431
|
+
}
|
|
4432
|
+
async function traceCliSpan(phase, fields, run) {
|
|
4433
|
+
if (!isCliTraceEnabled()) {
|
|
4434
|
+
return run();
|
|
4435
|
+
}
|
|
4436
|
+
const startedAt = Date.now();
|
|
4437
|
+
try {
|
|
4438
|
+
const result = await run();
|
|
4439
|
+
recordCliTrace({
|
|
4440
|
+
phase,
|
|
4441
|
+
ms: Date.now() - startedAt,
|
|
4442
|
+
ok: true,
|
|
4443
|
+
...fields
|
|
4444
|
+
});
|
|
4445
|
+
return result;
|
|
4446
|
+
} catch (error) {
|
|
4447
|
+
recordCliTrace({
|
|
4448
|
+
phase,
|
|
4449
|
+
ms: Date.now() - startedAt,
|
|
4450
|
+
ok: false,
|
|
4451
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4452
|
+
...fields
|
|
4453
|
+
});
|
|
4454
|
+
throw error;
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
|
|
4364
4458
|
// src/cli/commands/play.ts
|
|
4459
|
+
function traceCliSync(phase, fields, run) {
|
|
4460
|
+
const startedAt = Date.now();
|
|
4461
|
+
try {
|
|
4462
|
+
const result = run();
|
|
4463
|
+
recordCliTrace({
|
|
4464
|
+
phase,
|
|
4465
|
+
ms: Date.now() - startedAt,
|
|
4466
|
+
ok: true,
|
|
4467
|
+
...fields
|
|
4468
|
+
});
|
|
4469
|
+
return result;
|
|
4470
|
+
} catch (error) {
|
|
4471
|
+
recordCliTrace({
|
|
4472
|
+
phase,
|
|
4473
|
+
ms: Date.now() - startedAt,
|
|
4474
|
+
ok: false,
|
|
4475
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4476
|
+
...fields
|
|
4477
|
+
});
|
|
4478
|
+
throw error;
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4365
4481
|
function parseReferencedPlayTarget(target) {
|
|
4366
4482
|
const trimmed = target.trim();
|
|
4367
4483
|
const slashIndex = trimmed.indexOf("/");
|
|
@@ -4600,6 +4716,23 @@ function isLocalFilePathValue(value) {
|
|
|
4600
4716
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
4601
4717
|
return (0, import_node_fs6.existsSync)((0, import_node_path8.resolve)(value));
|
|
4602
4718
|
}
|
|
4719
|
+
function inputContainsLocalFilePath(value) {
|
|
4720
|
+
if (isLocalFilePathValue(value)) {
|
|
4721
|
+
return true;
|
|
4722
|
+
}
|
|
4723
|
+
if (Array.isArray(value)) {
|
|
4724
|
+
return value.some((entry) => inputContainsLocalFilePath(entry));
|
|
4725
|
+
}
|
|
4726
|
+
if (value && typeof value === "object") {
|
|
4727
|
+
return Object.values(value).some(
|
|
4728
|
+
(entry) => inputContainsLocalFilePath(entry)
|
|
4729
|
+
);
|
|
4730
|
+
}
|
|
4731
|
+
return false;
|
|
4732
|
+
}
|
|
4733
|
+
function namedRunNeedsPlayDefinition(input) {
|
|
4734
|
+
return input.revisionSelector === "latest" || getDottedInputValue(input.runtimeInput, "csv") != null || inputContainsLocalFilePath(input.runtimeInput);
|
|
4735
|
+
}
|
|
4603
4736
|
async function stageFileInputArgs(input) {
|
|
4604
4737
|
const uniqueBindings = [
|
|
4605
4738
|
...new Map(input.bindings.map((binding) => [binding.inputPath, binding])).values()
|
|
@@ -4912,6 +5045,8 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4912
5045
|
let timedOut = false;
|
|
4913
5046
|
let emittedDashboardUrl = false;
|
|
4914
5047
|
let lastKnownWorkflowId = "";
|
|
5048
|
+
let eventCount = 0;
|
|
5049
|
+
let firstRunIdMs = null;
|
|
4915
5050
|
let lastPhase = null;
|
|
4916
5051
|
const timeout = input.waitTimeoutMs === null ? null : setTimeout(
|
|
4917
5052
|
() => {
|
|
@@ -4924,9 +5059,11 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4924
5059
|
for await (const event of input.client.startPlayRunStream(input.request, {
|
|
4925
5060
|
signal: controller.signal
|
|
4926
5061
|
})) {
|
|
5062
|
+
eventCount += 1;
|
|
4927
5063
|
const eventRunId = getEventPayload(event).runId;
|
|
4928
5064
|
if (typeof eventRunId === "string" && eventRunId && eventRunId !== "pending") {
|
|
4929
5065
|
lastKnownWorkflowId = eventRunId;
|
|
5066
|
+
firstRunIdMs ??= Date.now() - startedAt;
|
|
4930
5067
|
}
|
|
4931
5068
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
4932
5069
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
@@ -4964,6 +5101,16 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4964
5101
|
});
|
|
4965
5102
|
const finalStatus = getFinalStatusFromLiveEvent(event);
|
|
4966
5103
|
if (finalStatus) {
|
|
5104
|
+
recordCliTrace({
|
|
5105
|
+
phase: "cli.play_start_stream_terminal",
|
|
5106
|
+
ms: Date.now() - startedAt,
|
|
5107
|
+
ok: true,
|
|
5108
|
+
playName: input.playName,
|
|
5109
|
+
workflowId: finalStatus.runId || lastKnownWorkflowId || null,
|
|
5110
|
+
eventCount,
|
|
5111
|
+
firstRunIdMs,
|
|
5112
|
+
lastPhase
|
|
5113
|
+
});
|
|
4967
5114
|
return finalStatus;
|
|
4968
5115
|
}
|
|
4969
5116
|
}
|
|
@@ -4987,6 +5134,17 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4987
5134
|
`
|
|
4988
5135
|
);
|
|
4989
5136
|
}
|
|
5137
|
+
recordCliTrace({
|
|
5138
|
+
phase: "cli.play_start_stream_fallback",
|
|
5139
|
+
ms: Date.now() - startedAt,
|
|
5140
|
+
ok: false,
|
|
5141
|
+
playName: input.playName,
|
|
5142
|
+
workflowId: lastKnownWorkflowId,
|
|
5143
|
+
eventCount,
|
|
5144
|
+
firstRunIdMs,
|
|
5145
|
+
lastPhase,
|
|
5146
|
+
reason
|
|
5147
|
+
});
|
|
4990
5148
|
return waitForPlayCompletionByPolling({
|
|
4991
5149
|
client: input.client,
|
|
4992
5150
|
workflowId: lastKnownWorkflowId,
|
|
@@ -5011,6 +5169,17 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5011
5169
|
`[play watch] start stream ended after run ${lastKnownWorkflowId}; falling back to polling`
|
|
5012
5170
|
);
|
|
5013
5171
|
}
|
|
5172
|
+
recordCliTrace({
|
|
5173
|
+
phase: "cli.play_start_stream_fallback",
|
|
5174
|
+
ms: Date.now() - startedAt,
|
|
5175
|
+
ok: false,
|
|
5176
|
+
playName: input.playName,
|
|
5177
|
+
workflowId: lastKnownWorkflowId,
|
|
5178
|
+
eventCount,
|
|
5179
|
+
firstRunIdMs,
|
|
5180
|
+
lastPhase,
|
|
5181
|
+
reason: "stream ended before terminal event"
|
|
5182
|
+
});
|
|
5014
5183
|
return waitForPlayCompletionByPolling({
|
|
5015
5184
|
client: input.client,
|
|
5016
5185
|
workflowId: lastKnownWorkflowId,
|
|
@@ -5085,10 +5254,11 @@ async function waitForPlayCompletionByPolling(input) {
|
|
|
5085
5254
|
progress: input.progress
|
|
5086
5255
|
});
|
|
5087
5256
|
if (TERMINAL_PLAY_STATUSES2.has(status.status)) {
|
|
5088
|
-
return status.result !== void 0 ? status : await input.client.getPlayStatus(input.workflowId);
|
|
5257
|
+
return status.result !== void 0 ? status : await input.client.getPlayStatus(input.workflowId, { billing: false });
|
|
5089
5258
|
}
|
|
5090
5259
|
const authoritativeStatus = await input.client.getPlayStatus(
|
|
5091
|
-
input.workflowId
|
|
5260
|
+
input.workflowId,
|
|
5261
|
+
{ billing: false }
|
|
5092
5262
|
);
|
|
5093
5263
|
if (TERMINAL_PLAY_STATUSES2.has(authoritativeStatus.status)) {
|
|
5094
5264
|
return authoritativeStatus;
|
|
@@ -5206,14 +5376,20 @@ function formatReturnValue(result) {
|
|
|
5206
5376
|
}
|
|
5207
5377
|
return lines;
|
|
5208
5378
|
}
|
|
5209
|
-
function buildOutputSummary(rowsInfo, exportedPath) {
|
|
5379
|
+
function buildOutputSummary(rowsInfo, runId, exportedPath) {
|
|
5210
5380
|
if (!rowsInfo) {
|
|
5211
5381
|
return exportedPath ? { csv_path: exportedPath } : null;
|
|
5212
5382
|
}
|
|
5383
|
+
const isPartial = !rowsInfo.complete;
|
|
5213
5384
|
return {
|
|
5214
5385
|
kind: "rows",
|
|
5215
5386
|
rowCount: rowsInfo.totalRows,
|
|
5216
5387
|
previewRowCount: rowsInfo.rows.length,
|
|
5388
|
+
...isPartial ? {
|
|
5389
|
+
isPartial: true,
|
|
5390
|
+
previewCount: rowsInfo.rows.length,
|
|
5391
|
+
totalCount: rowsInfo.totalRows
|
|
5392
|
+
} : { isPartial: false },
|
|
5217
5393
|
complete: rowsInfo.complete,
|
|
5218
5394
|
columns: rowsInfo.columns,
|
|
5219
5395
|
source: rowsInfo.source,
|
|
@@ -5224,16 +5400,27 @@ function buildRunWarnings(status, rowsInfo) {
|
|
|
5224
5400
|
if (status.status === "completed" && rowsInfo?.totalRows === 0) {
|
|
5225
5401
|
return ["Run completed with 0 output rows."];
|
|
5226
5402
|
}
|
|
5403
|
+
if (rowsInfo && !rowsInfo.complete) {
|
|
5404
|
+
return [
|
|
5405
|
+
`Run output is partial: showing ${rowsInfo.rows.length} preview row(s) of ${rowsInfo.totalRows}.`
|
|
5406
|
+
];
|
|
5407
|
+
}
|
|
5227
5408
|
return [];
|
|
5228
5409
|
}
|
|
5229
|
-
function buildRunNextCommands(runId) {
|
|
5230
|
-
|
|
5410
|
+
function buildRunNextCommands(runId, rowsInfo) {
|
|
5411
|
+
const commands = {
|
|
5231
5412
|
get: `deepline runs get ${runId} --json`,
|
|
5232
5413
|
tail: `deepline runs tail ${runId} --json`,
|
|
5233
5414
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
5234
|
-
logs: `deepline runs logs ${runId} --out run.log --json
|
|
5235
|
-
exportCsv: `deepline runs export ${runId} --out output.csv`
|
|
5415
|
+
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
5236
5416
|
};
|
|
5417
|
+
if (!rowsInfo || rowsInfo.complete) {
|
|
5418
|
+
commands.exportCsv = buildRunExportCommand(runId);
|
|
5419
|
+
}
|
|
5420
|
+
return commands;
|
|
5421
|
+
}
|
|
5422
|
+
function buildRunExportCommand(runId) {
|
|
5423
|
+
return `deepline runs export ${runId} --out output.csv`;
|
|
5237
5424
|
}
|
|
5238
5425
|
var RUN_LOG_PREVIEW_LIMIT = 20;
|
|
5239
5426
|
function getRecordField(value, key) {
|
|
@@ -5281,10 +5468,11 @@ function normalizeProgressForEnvelope(status, rowsInfo) {
|
|
|
5281
5468
|
wait: status.wait ?? null
|
|
5282
5469
|
};
|
|
5283
5470
|
}
|
|
5284
|
-
function normalizeOutputsForEnvelope(rowsInfo, exportedPath) {
|
|
5471
|
+
function normalizeOutputsForEnvelope(rowsInfo, runId, exportedPath) {
|
|
5285
5472
|
if (!rowsInfo) {
|
|
5286
5473
|
return exportedPath ? [{ name: "output", kind: "file", path: exportedPath }] : [];
|
|
5287
5474
|
}
|
|
5475
|
+
const isPartial = !rowsInfo.complete;
|
|
5288
5476
|
return [
|
|
5289
5477
|
{
|
|
5290
5478
|
name: "rows",
|
|
@@ -5294,6 +5482,11 @@ function normalizeOutputsForEnvelope(rowsInfo, exportedPath) {
|
|
|
5294
5482
|
preview: rowsInfo.rows.slice(0, 5),
|
|
5295
5483
|
previewRowCount: Math.min(rowsInfo.rows.length, 5),
|
|
5296
5484
|
previewLimit: 5,
|
|
5485
|
+
...isPartial ? {
|
|
5486
|
+
isPartial: true,
|
|
5487
|
+
previewCount: rowsInfo.rows.length,
|
|
5488
|
+
totalCount: rowsInfo.totalRows
|
|
5489
|
+
} : { isPartial: false },
|
|
5297
5490
|
complete: rowsInfo.complete,
|
|
5298
5491
|
source: rowsInfo.source,
|
|
5299
5492
|
...exportedPath ? { csv_path: exportedPath } : {}
|
|
@@ -5385,19 +5578,23 @@ function compactPlayStatus(status, options) {
|
|
|
5385
5578
|
status: status.status,
|
|
5386
5579
|
run: normalizeRunStatusForEnvelope(status),
|
|
5387
5580
|
progress: normalizeProgressForEnvelope(status, rowsInfo),
|
|
5388
|
-
outputs: normalizeOutputsForEnvelope(
|
|
5581
|
+
outputs: normalizeOutputsForEnvelope(
|
|
5582
|
+
rowsInfo,
|
|
5583
|
+
status.runId,
|
|
5584
|
+
options?.exportedPath
|
|
5585
|
+
),
|
|
5389
5586
|
steps: normalizeStepsForEnvelope(status),
|
|
5390
5587
|
errors: normalizeErrorsForEnvelope(status, error),
|
|
5391
5588
|
logs: normalizeLogsForEnvelope(status),
|
|
5392
5589
|
...error ? { error } : {},
|
|
5393
5590
|
...warnings.length > 0 ? { warnings } : {},
|
|
5394
|
-
output: buildOutputSummary(rowsInfo, options?.exportedPath) ?? result ?? null,
|
|
5591
|
+
output: buildOutputSummary(rowsInfo, status.runId, options?.exportedPath) ?? result ?? null,
|
|
5395
5592
|
...result !== void 0 ? { result } : {},
|
|
5396
5593
|
...status.resultView ? { resultView: status.resultView } : {},
|
|
5397
5594
|
...datasetStats ? { dataset_stats: datasetStats } : {},
|
|
5398
5595
|
...rowsInfo ? { previewRows: rowsInfo.rows.slice(0, 5) } : {},
|
|
5399
5596
|
...billing ? { billing } : {},
|
|
5400
|
-
next: buildRunNextCommands(status.runId)
|
|
5597
|
+
next: buildRunNextCommands(status.runId, rowsInfo)
|
|
5401
5598
|
};
|
|
5402
5599
|
}
|
|
5403
5600
|
function enrichPlayStatusWithDatasetStats(status) {
|
|
@@ -5457,13 +5654,22 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
5457
5654
|
rowsInfo.columns,
|
|
5458
5655
|
extractDatasetExecutionStats(status)
|
|
5459
5656
|
) : null;
|
|
5460
|
-
const outputSummary = buildOutputSummary(
|
|
5657
|
+
const outputSummary = buildOutputSummary(
|
|
5658
|
+
rowsInfo,
|
|
5659
|
+
runId,
|
|
5660
|
+
options?.exportedPath
|
|
5661
|
+
);
|
|
5461
5662
|
if (outputSummary) {
|
|
5462
5663
|
const columns = Array.isArray(outputSummary.columns) ? outputSummary.columns.length : 0;
|
|
5463
5664
|
const path = typeof outputSummary.csv_path === "string" ? ` file=${outputSummary.csv_path}` : "";
|
|
5464
5665
|
lines.push(
|
|
5465
5666
|
` output: rows=${formatInteger(outputSummary.rowCount)} columns=${formatInteger(columns)}${path}`
|
|
5466
5667
|
);
|
|
5668
|
+
if (outputSummary.isPartial === true) {
|
|
5669
|
+
lines.push(
|
|
5670
|
+
` partial output: showing ${formatInteger(outputSummary.previewCount)} preview row(s) of ${formatInteger(outputSummary.totalCount)}`
|
|
5671
|
+
);
|
|
5672
|
+
}
|
|
5467
5673
|
}
|
|
5468
5674
|
for (const warning of warnings) {
|
|
5469
5675
|
lines.push(` warning: ${warning}`);
|
|
@@ -5493,6 +5699,11 @@ function exportPlayStatusRows(status, outPath) {
|
|
|
5493
5699
|
`Run ${status.runId} did not expose a row-shaped final output to export.`
|
|
5494
5700
|
);
|
|
5495
5701
|
}
|
|
5702
|
+
if (!rowsInfo.complete) {
|
|
5703
|
+
throw new DeeplineError(
|
|
5704
|
+
`Run output only includes ${rowsInfo.rows.length} preview row(s) of ${rowsInfo.totalRows}; full dataset export is not available from this status response yet.`
|
|
5705
|
+
);
|
|
5706
|
+
}
|
|
5496
5707
|
return writeCanonicalRowsCsv(rowsInfo, outPath);
|
|
5497
5708
|
}
|
|
5498
5709
|
function renderServerResultView(value) {
|
|
@@ -5802,11 +6013,24 @@ async function handleFileBackedRun(options) {
|
|
|
5802
6013
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
5803
6014
|
const absolutePlayPath = (0, import_node_path8.resolve)(options.target.path);
|
|
5804
6015
|
progress.phase("compiling play");
|
|
5805
|
-
const sourceCode = (
|
|
6016
|
+
const sourceCode = traceCliSync(
|
|
6017
|
+
"cli.play_file_read_source",
|
|
6018
|
+
{ targetKind: "file" },
|
|
6019
|
+
() => (0, import_node_fs6.readFileSync)(absolutePlayPath, "utf-8")
|
|
6020
|
+
);
|
|
6021
|
+
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5806
6022
|
let graph;
|
|
5807
6023
|
try {
|
|
5808
|
-
graph = await
|
|
5809
|
-
|
|
6024
|
+
graph = await traceCliSpan(
|
|
6025
|
+
"cli.play_file_bundle_graph",
|
|
6026
|
+
{ targetKind: "file" },
|
|
6027
|
+
() => collectBundledPlayGraph(absolutePlayPath)
|
|
6028
|
+
);
|
|
6029
|
+
await traceCliSpan(
|
|
6030
|
+
"cli.play_file_compile_manifests",
|
|
6031
|
+
{ targetKind: "file" },
|
|
6032
|
+
() => compileBundledPlayGraphManifests(client, graph)
|
|
6033
|
+
);
|
|
5810
6034
|
progress.phase("compiled play");
|
|
5811
6035
|
} catch (error) {
|
|
5812
6036
|
progress.fail();
|
|
@@ -5817,36 +6041,47 @@ async function handleFileBackedRun(options) {
|
|
|
5817
6041
|
const playName = bundleResult.playName ?? extractPlayName(sourceCode, absolutePlayPath);
|
|
5818
6042
|
try {
|
|
5819
6043
|
progress.phase("publishing imported plays");
|
|
5820
|
-
await
|
|
6044
|
+
await traceCliSpan(
|
|
6045
|
+
"cli.play_file_publish_imports",
|
|
6046
|
+
{ targetKind: "file" },
|
|
6047
|
+
() => publishImportedPlayDependencies(client, graph)
|
|
6048
|
+
);
|
|
5821
6049
|
} catch (error) {
|
|
5822
6050
|
progress.fail();
|
|
5823
6051
|
console.error(error instanceof Error ? error.message : String(error));
|
|
5824
6052
|
return 1;
|
|
5825
6053
|
}
|
|
5826
|
-
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5827
6054
|
const packagedFileUploads = bundleResult.packagedFiles.map(
|
|
5828
6055
|
(file) => stageFile(file.logicalPath, file.absolutePath)
|
|
5829
6056
|
);
|
|
6057
|
+
const compilerManifest = requireCompilerManifest(bundleResult);
|
|
5830
6058
|
const fileInputBindings = fileInputBindingsFromStaticPipeline(
|
|
5831
|
-
|
|
6059
|
+
compilerManifest.staticPipeline
|
|
5832
6060
|
);
|
|
5833
6061
|
applyCsvShortcutInput({
|
|
5834
6062
|
runtimeInput,
|
|
5835
6063
|
bindings: fileInputBindings,
|
|
5836
6064
|
fallbackInputPath: "file"
|
|
5837
6065
|
});
|
|
5838
|
-
const stagedFileInputs = await
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
6066
|
+
const stagedFileInputs = await traceCliSpan(
|
|
6067
|
+
"cli.play_stage_inputs",
|
|
6068
|
+
{
|
|
6069
|
+
targetKind: "file",
|
|
6070
|
+
bindingCount: fileInputBindings.length
|
|
6071
|
+
},
|
|
6072
|
+
() => stageFileInputArgs({
|
|
6073
|
+
client,
|
|
6074
|
+
runtimeInput,
|
|
6075
|
+
bindings: fileInputBindings,
|
|
6076
|
+
progress
|
|
6077
|
+
})
|
|
6078
|
+
);
|
|
5844
6079
|
const startRequest = {
|
|
5845
6080
|
name: playName,
|
|
5846
6081
|
sourceCode: bundleResult.sourceCode,
|
|
5847
6082
|
sourceFiles: bundleResult.sourceFiles,
|
|
5848
6083
|
runtimeArtifact: bundleResult.artifact,
|
|
5849
|
-
compilerManifest
|
|
6084
|
+
compilerManifest,
|
|
5850
6085
|
packagedFileUploads,
|
|
5851
6086
|
...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
|
|
5852
6087
|
...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
|
|
@@ -5855,26 +6090,42 @@ async function handleFileBackedRun(options) {
|
|
|
5855
6090
|
};
|
|
5856
6091
|
if (options.watch) {
|
|
5857
6092
|
progress.phase("starting run");
|
|
5858
|
-
const finalStatus = await
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
6093
|
+
const finalStatus = await traceCliSpan(
|
|
6094
|
+
"cli.play_start_watch",
|
|
6095
|
+
{ targetKind: "file", playName },
|
|
6096
|
+
() => startAndWaitForPlayCompletionByStream({
|
|
6097
|
+
client,
|
|
6098
|
+
request: startRequest,
|
|
6099
|
+
playName,
|
|
6100
|
+
jsonOutput: options.jsonOutput,
|
|
6101
|
+
emitLogs: options.emitLogs,
|
|
6102
|
+
waitTimeoutMs: options.waitTimeoutMs,
|
|
6103
|
+
progress
|
|
6104
|
+
})
|
|
6105
|
+
);
|
|
6106
|
+
const exportedPath = traceCliSync(
|
|
6107
|
+
"cli.play_export_rows",
|
|
6108
|
+
{ targetKind: "file", playName },
|
|
6109
|
+
() => exportPlayStatusRows(finalStatus, options.outPath)
|
|
6110
|
+
);
|
|
5868
6111
|
if (finalStatus.status === "completed") {
|
|
5869
6112
|
progress.complete();
|
|
5870
6113
|
} else {
|
|
5871
6114
|
progress.fail();
|
|
5872
6115
|
}
|
|
5873
|
-
|
|
6116
|
+
traceCliSync(
|
|
6117
|
+
"cli.play_write_result",
|
|
6118
|
+
{ targetKind: "file", playName },
|
|
6119
|
+
() => writePlayResult(finalStatus, options.jsonOutput, { exportedPath })
|
|
6120
|
+
);
|
|
5874
6121
|
return finalStatus.status === "completed" ? 0 : 1;
|
|
5875
6122
|
}
|
|
5876
6123
|
progress.phase("starting run");
|
|
5877
|
-
const started = await
|
|
6124
|
+
const started = await traceCliSpan(
|
|
6125
|
+
"cli.play_start_unwatched",
|
|
6126
|
+
{ targetKind: "file", playName },
|
|
6127
|
+
() => client.startPlayRun(startRequest)
|
|
6128
|
+
);
|
|
5878
6129
|
const dashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
5879
6130
|
progress.phase(`loading play on ${dashboardUrl}`);
|
|
5880
6131
|
progress.complete();
|
|
@@ -5909,32 +6160,67 @@ async function handleNamedRun(options) {
|
|
|
5909
6160
|
}
|
|
5910
6161
|
const client = new DeeplineClient();
|
|
5911
6162
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
5912
|
-
|
|
5913
|
-
const playDetail = await assertCanonicalNamedPlayReference(client, options.target.name);
|
|
5914
|
-
progress.phase("selecting revision");
|
|
5915
|
-
const selectedRevisionId = await resolveNamedRunRevisionId({
|
|
5916
|
-
client,
|
|
5917
|
-
playName: options.target.name,
|
|
5918
|
-
revisionId: options.revisionId,
|
|
5919
|
-
selector: options.revisionSelector
|
|
5920
|
-
});
|
|
6163
|
+
const playName = options.target.name;
|
|
5921
6164
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5922
|
-
const
|
|
6165
|
+
const needsPlayDefinition = namedRunNeedsPlayDefinition({
|
|
6166
|
+
runtimeInput,
|
|
6167
|
+
revisionSelector: options.revisionSelector
|
|
6168
|
+
});
|
|
6169
|
+
const playDetail = needsPlayDefinition ? await (async () => {
|
|
6170
|
+
progress.phase("loading play definition");
|
|
6171
|
+
return traceCliSpan(
|
|
6172
|
+
"cli.play_load_definition",
|
|
6173
|
+
{ targetKind: "name", playName, skipped: false },
|
|
6174
|
+
() => assertCanonicalNamedPlayReference(client, playName)
|
|
6175
|
+
);
|
|
6176
|
+
})() : (recordCliTrace({
|
|
6177
|
+
phase: "cli.play_load_definition",
|
|
6178
|
+
ms: 0,
|
|
6179
|
+
ok: true,
|
|
6180
|
+
targetKind: "name",
|
|
6181
|
+
playName,
|
|
6182
|
+
skipped: true
|
|
6183
|
+
}), null);
|
|
6184
|
+
progress.phase("selecting revision");
|
|
6185
|
+
const selectedRevisionId = await traceCliSpan(
|
|
6186
|
+
"cli.play_select_revision",
|
|
6187
|
+
{
|
|
6188
|
+
targetKind: "name",
|
|
6189
|
+
playName,
|
|
6190
|
+
selector: options.revisionSelector,
|
|
6191
|
+
hasExplicitRevisionId: Boolean(options.revisionId)
|
|
6192
|
+
},
|
|
6193
|
+
() => resolveNamedRunRevisionId({
|
|
6194
|
+
client,
|
|
6195
|
+
playName,
|
|
6196
|
+
revisionId: options.revisionId,
|
|
6197
|
+
selector: options.revisionSelector
|
|
6198
|
+
})
|
|
6199
|
+
);
|
|
6200
|
+
const fileInputBindings = playDetail ? [
|
|
5923
6201
|
...fileInputBindingsFromPlaySchema(playDetail.play.inputSchema),
|
|
5924
6202
|
...fileInputBindingsFromStaticPipeline(playDetail.play.staticPipeline)
|
|
5925
|
-
];
|
|
6203
|
+
] : [];
|
|
5926
6204
|
applyCsvShortcutInput({
|
|
5927
6205
|
runtimeInput,
|
|
5928
6206
|
bindings: fileInputBindings
|
|
5929
6207
|
});
|
|
5930
|
-
const stagedFileInputs = await
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
6208
|
+
const stagedFileInputs = await traceCliSpan(
|
|
6209
|
+
"cli.play_stage_inputs",
|
|
6210
|
+
{
|
|
6211
|
+
targetKind: "name",
|
|
6212
|
+
playName,
|
|
6213
|
+
bindingCount: fileInputBindings.length
|
|
6214
|
+
},
|
|
6215
|
+
() => stageFileInputArgs({
|
|
6216
|
+
client,
|
|
6217
|
+
runtimeInput,
|
|
6218
|
+
bindings: fileInputBindings,
|
|
6219
|
+
progress
|
|
6220
|
+
})
|
|
6221
|
+
);
|
|
5936
6222
|
const startRequest = {
|
|
5937
|
-
name:
|
|
6223
|
+
name: playName,
|
|
5938
6224
|
...selectedRevisionId ? { revisionId: selectedRevisionId } : {},
|
|
5939
6225
|
...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
|
|
5940
6226
|
...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
|
|
@@ -5943,35 +6229,51 @@ async function handleNamedRun(options) {
|
|
|
5943
6229
|
};
|
|
5944
6230
|
if (options.watch) {
|
|
5945
6231
|
progress.phase("starting run");
|
|
5946
|
-
const finalStatus = await
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
6232
|
+
const finalStatus = await traceCliSpan(
|
|
6233
|
+
"cli.play_start_watch",
|
|
6234
|
+
{ targetKind: "name", playName },
|
|
6235
|
+
() => startAndWaitForPlayCompletionByStream({
|
|
6236
|
+
client,
|
|
6237
|
+
request: startRequest,
|
|
6238
|
+
playName,
|
|
6239
|
+
jsonOutput: options.jsonOutput,
|
|
6240
|
+
emitLogs: options.emitLogs,
|
|
6241
|
+
waitTimeoutMs: options.waitTimeoutMs,
|
|
6242
|
+
progress
|
|
6243
|
+
})
|
|
6244
|
+
);
|
|
6245
|
+
const exportedPath = traceCliSync(
|
|
6246
|
+
"cli.play_export_rows",
|
|
6247
|
+
{ targetKind: "name", playName },
|
|
6248
|
+
() => exportPlayStatusRows(finalStatus, options.outPath)
|
|
6249
|
+
);
|
|
5956
6250
|
if (finalStatus.status === "completed") {
|
|
5957
6251
|
progress.complete();
|
|
5958
6252
|
} else {
|
|
5959
6253
|
progress.fail();
|
|
5960
6254
|
}
|
|
5961
|
-
|
|
6255
|
+
traceCliSync(
|
|
6256
|
+
"cli.play_write_result",
|
|
6257
|
+
{ targetKind: "name", playName },
|
|
6258
|
+
() => writePlayResult(finalStatus, options.jsonOutput, { exportedPath })
|
|
6259
|
+
);
|
|
5962
6260
|
return finalStatus.status === "completed" ? 0 : 1;
|
|
5963
6261
|
}
|
|
5964
6262
|
progress.phase("starting run");
|
|
5965
|
-
const started = await
|
|
6263
|
+
const started = await traceCliSpan(
|
|
6264
|
+
"cli.play_start_unwatched",
|
|
6265
|
+
{ targetKind: "name", playName },
|
|
6266
|
+
() => client.startPlayRun(startRequest)
|
|
6267
|
+
);
|
|
5966
6268
|
const dashboardUrl = buildPlayDashboardUrl(
|
|
5967
6269
|
client.baseUrl,
|
|
5968
|
-
|
|
6270
|
+
playName
|
|
5969
6271
|
);
|
|
5970
6272
|
progress.phase(`loading play on ${dashboardUrl}`);
|
|
5971
6273
|
progress.complete();
|
|
5972
6274
|
writeStartedPlayRun({
|
|
5973
6275
|
runId: started.workflowId,
|
|
5974
|
-
playName: started.name ??
|
|
6276
|
+
playName: started.name ?? playName,
|
|
5975
6277
|
status: started.status,
|
|
5976
6278
|
statusUrl: started.statusUrl,
|
|
5977
6279
|
dashboardUrl: started.dashboardUrl ?? dashboardUrl,
|
|
@@ -7834,54 +8136,6 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
7834
8136
|
writeSdkSkillsStatusLine("SDK skills are up to date.");
|
|
7835
8137
|
}
|
|
7836
8138
|
|
|
7837
|
-
// src/cli/trace.ts
|
|
7838
|
-
var cliTraceStartedAt = Date.now();
|
|
7839
|
-
function isTruthyEnv(value) {
|
|
7840
|
-
return value === "1" || value === "true" || value === "yes";
|
|
7841
|
-
}
|
|
7842
|
-
function isCliTraceEnabled() {
|
|
7843
|
-
return isTruthyEnv(process.env.DEEPLINE_CLI_TRACE);
|
|
7844
|
-
}
|
|
7845
|
-
function recordCliTrace(event) {
|
|
7846
|
-
if (!isCliTraceEnabled()) {
|
|
7847
|
-
return;
|
|
7848
|
-
}
|
|
7849
|
-
const now = Date.now();
|
|
7850
|
-
const payload = {
|
|
7851
|
-
ts: now,
|
|
7852
|
-
source: "cli",
|
|
7853
|
-
sinceStartMs: now - cliTraceStartedAt,
|
|
7854
|
-
...event
|
|
7855
|
-
};
|
|
7856
|
-
process.stderr.write(`[cli-trace] ${JSON.stringify(payload)}
|
|
7857
|
-
`);
|
|
7858
|
-
}
|
|
7859
|
-
async function traceCliSpan(phase, fields, run) {
|
|
7860
|
-
if (!isCliTraceEnabled()) {
|
|
7861
|
-
return run();
|
|
7862
|
-
}
|
|
7863
|
-
const startedAt = Date.now();
|
|
7864
|
-
try {
|
|
7865
|
-
const result = await run();
|
|
7866
|
-
recordCliTrace({
|
|
7867
|
-
phase,
|
|
7868
|
-
ms: Date.now() - startedAt,
|
|
7869
|
-
ok: true,
|
|
7870
|
-
...fields
|
|
7871
|
-
});
|
|
7872
|
-
return result;
|
|
7873
|
-
} catch (error) {
|
|
7874
|
-
recordCliTrace({
|
|
7875
|
-
phase,
|
|
7876
|
-
ms: Date.now() - startedAt,
|
|
7877
|
-
ok: false,
|
|
7878
|
-
error: error instanceof Error ? error.message : String(error),
|
|
7879
|
-
...fields
|
|
7880
|
-
});
|
|
7881
|
-
throw error;
|
|
7882
|
-
}
|
|
7883
|
-
}
|
|
7884
|
-
|
|
7885
8139
|
// src/cli/index.ts
|
|
7886
8140
|
function shouldPrintStartupPhase() {
|
|
7887
8141
|
if (process.argv.includes("--json")) {
|
|
@@ -7892,6 +8146,12 @@ function shouldPrintStartupPhase() {
|
|
|
7892
8146
|
const subcommand = args[1];
|
|
7893
8147
|
return (command === "play" || command === "plays") && subcommand === "run";
|
|
7894
8148
|
}
|
|
8149
|
+
function shouldDeferSkillsSyncForCommand() {
|
|
8150
|
+
const args = process.argv.slice(2);
|
|
8151
|
+
const command = args[0];
|
|
8152
|
+
const subcommand = args[1];
|
|
8153
|
+
return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
|
|
8154
|
+
}
|
|
7895
8155
|
async function main() {
|
|
7896
8156
|
const mainStartedAt = Date.now();
|
|
7897
8157
|
recordCliTrace({
|
|
@@ -7936,11 +8196,13 @@ Output:
|
|
|
7936
8196
|
if (printStartupPhase) {
|
|
7937
8197
|
progress?.phase("checking sdk skills");
|
|
7938
8198
|
}
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
8199
|
+
if (!shouldDeferSkillsSyncForCommand()) {
|
|
8200
|
+
await traceCliSpan(
|
|
8201
|
+
"cli.sdk_skills_sync",
|
|
8202
|
+
{ baseUrl },
|
|
8203
|
+
() => syncSdkSkillsIfNeeded(baseUrl)
|
|
8204
|
+
);
|
|
8205
|
+
}
|
|
7944
8206
|
});
|
|
7945
8207
|
registerAuthCommands(program);
|
|
7946
8208
|
registerToolsCommands(program);
|