deepline 0.1.20 → 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 +338 -118
- package/dist/cli/index.mjs +338 -118
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +51 -6
- package/dist/index.mjs +51 -6
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +888 -227
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +540 -36
- package/dist/repo/apps/play-runner-workers/src/entry.ts +330 -374
- package/dist/repo/sdk/src/client.ts +46 -4
- package/dist/repo/sdk/src/http.ts +19 -1
- package/dist/repo/sdk/src/plays/harness-stub.ts +12 -0
- package/dist/repo/sdk/src/version.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +3 -6
- 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);
|
|
@@ -468,6 +468,13 @@ var HttpClient = class {
|
|
|
468
468
|
headers
|
|
469
469
|
});
|
|
470
470
|
}
|
|
471
|
+
async postFormData(path, formData, headers) {
|
|
472
|
+
return this.request(path, {
|
|
473
|
+
method: "POST",
|
|
474
|
+
formData,
|
|
475
|
+
headers
|
|
476
|
+
});
|
|
477
|
+
}
|
|
471
478
|
/**
|
|
472
479
|
* Send a DELETE request.
|
|
473
480
|
*
|
|
@@ -576,6 +583,14 @@ function mapLegacyTemporalStatus(status) {
|
|
|
576
583
|
return "running";
|
|
577
584
|
}
|
|
578
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
|
+
}
|
|
579
594
|
var DeeplineClient = class {
|
|
580
595
|
http;
|
|
581
596
|
config;
|
|
@@ -1027,9 +1042,34 @@ var DeeplineClient = class {
|
|
|
1027
1042
|
* ```
|
|
1028
1043
|
*/
|
|
1029
1044
|
async stagePlayFiles(files) {
|
|
1030
|
-
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(
|
|
1031
1071
|
"/api/v2/plays/files/stage",
|
|
1032
|
-
|
|
1072
|
+
formData
|
|
1033
1073
|
);
|
|
1034
1074
|
return response.files;
|
|
1035
1075
|
}
|
|
@@ -1058,9 +1098,14 @@ var DeeplineClient = class {
|
|
|
1058
1098
|
* console.log(`Logs: ${status.progress?.logs.length ?? 0} lines`);
|
|
1059
1099
|
* ```
|
|
1060
1100
|
*/
|
|
1061
|
-
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()}` : "";
|
|
1062
1107
|
const response = await this.http.get(
|
|
1063
|
-
`/api/v2/plays/run/${encodeURIComponent(workflowId)}`
|
|
1108
|
+
`/api/v2/plays/run/${encodeURIComponent(workflowId)}${query}`
|
|
1064
1109
|
);
|
|
1065
1110
|
return normalizePlayStatus(response);
|
|
1066
1111
|
}
|
|
@@ -4362,7 +4407,77 @@ function createCliProgress(enabled) {
|
|
|
4362
4407
|
return progress;
|
|
4363
4408
|
}
|
|
4364
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
|
+
|
|
4365
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
|
+
}
|
|
4366
4481
|
function parseReferencedPlayTarget(target) {
|
|
4367
4482
|
const trimmed = target.trim();
|
|
4368
4483
|
const slashIndex = trimmed.indexOf("/");
|
|
@@ -4601,6 +4716,23 @@ function isLocalFilePathValue(value) {
|
|
|
4601
4716
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
4602
4717
|
return (0, import_node_fs6.existsSync)((0, import_node_path8.resolve)(value));
|
|
4603
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
|
+
}
|
|
4604
4736
|
async function stageFileInputArgs(input) {
|
|
4605
4737
|
const uniqueBindings = [
|
|
4606
4738
|
...new Map(input.bindings.map((binding) => [binding.inputPath, binding])).values()
|
|
@@ -4913,6 +5045,8 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4913
5045
|
let timedOut = false;
|
|
4914
5046
|
let emittedDashboardUrl = false;
|
|
4915
5047
|
let lastKnownWorkflowId = "";
|
|
5048
|
+
let eventCount = 0;
|
|
5049
|
+
let firstRunIdMs = null;
|
|
4916
5050
|
let lastPhase = null;
|
|
4917
5051
|
const timeout = input.waitTimeoutMs === null ? null : setTimeout(
|
|
4918
5052
|
() => {
|
|
@@ -4925,9 +5059,11 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4925
5059
|
for await (const event of input.client.startPlayRunStream(input.request, {
|
|
4926
5060
|
signal: controller.signal
|
|
4927
5061
|
})) {
|
|
5062
|
+
eventCount += 1;
|
|
4928
5063
|
const eventRunId = getEventPayload(event).runId;
|
|
4929
5064
|
if (typeof eventRunId === "string" && eventRunId && eventRunId !== "pending") {
|
|
4930
5065
|
lastKnownWorkflowId = eventRunId;
|
|
5066
|
+
firstRunIdMs ??= Date.now() - startedAt;
|
|
4931
5067
|
}
|
|
4932
5068
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
4933
5069
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
@@ -4965,6 +5101,16 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4965
5101
|
});
|
|
4966
5102
|
const finalStatus = getFinalStatusFromLiveEvent(event);
|
|
4967
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
|
+
});
|
|
4968
5114
|
return finalStatus;
|
|
4969
5115
|
}
|
|
4970
5116
|
}
|
|
@@ -4988,6 +5134,17 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4988
5134
|
`
|
|
4989
5135
|
);
|
|
4990
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
|
+
});
|
|
4991
5148
|
return waitForPlayCompletionByPolling({
|
|
4992
5149
|
client: input.client,
|
|
4993
5150
|
workflowId: lastKnownWorkflowId,
|
|
@@ -5012,6 +5169,17 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5012
5169
|
`[play watch] start stream ended after run ${lastKnownWorkflowId}; falling back to polling`
|
|
5013
5170
|
);
|
|
5014
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
|
+
});
|
|
5015
5183
|
return waitForPlayCompletionByPolling({
|
|
5016
5184
|
client: input.client,
|
|
5017
5185
|
workflowId: lastKnownWorkflowId,
|
|
@@ -5086,10 +5254,11 @@ async function waitForPlayCompletionByPolling(input) {
|
|
|
5086
5254
|
progress: input.progress
|
|
5087
5255
|
});
|
|
5088
5256
|
if (TERMINAL_PLAY_STATUSES2.has(status.status)) {
|
|
5089
|
-
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 });
|
|
5090
5258
|
}
|
|
5091
5259
|
const authoritativeStatus = await input.client.getPlayStatus(
|
|
5092
|
-
input.workflowId
|
|
5260
|
+
input.workflowId,
|
|
5261
|
+
{ billing: false }
|
|
5093
5262
|
);
|
|
5094
5263
|
if (TERMINAL_PLAY_STATUSES2.has(authoritativeStatus.status)) {
|
|
5095
5264
|
return authoritativeStatus;
|
|
@@ -5844,11 +6013,24 @@ async function handleFileBackedRun(options) {
|
|
|
5844
6013
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
5845
6014
|
const absolutePlayPath = (0, import_node_path8.resolve)(options.target.path);
|
|
5846
6015
|
progress.phase("compiling play");
|
|
5847
|
-
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 } : {};
|
|
5848
6022
|
let graph;
|
|
5849
6023
|
try {
|
|
5850
|
-
graph = await
|
|
5851
|
-
|
|
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
|
+
);
|
|
5852
6034
|
progress.phase("compiled play");
|
|
5853
6035
|
} catch (error) {
|
|
5854
6036
|
progress.fail();
|
|
@@ -5859,36 +6041,47 @@ async function handleFileBackedRun(options) {
|
|
|
5859
6041
|
const playName = bundleResult.playName ?? extractPlayName(sourceCode, absolutePlayPath);
|
|
5860
6042
|
try {
|
|
5861
6043
|
progress.phase("publishing imported plays");
|
|
5862
|
-
await
|
|
6044
|
+
await traceCliSpan(
|
|
6045
|
+
"cli.play_file_publish_imports",
|
|
6046
|
+
{ targetKind: "file" },
|
|
6047
|
+
() => publishImportedPlayDependencies(client, graph)
|
|
6048
|
+
);
|
|
5863
6049
|
} catch (error) {
|
|
5864
6050
|
progress.fail();
|
|
5865
6051
|
console.error(error instanceof Error ? error.message : String(error));
|
|
5866
6052
|
return 1;
|
|
5867
6053
|
}
|
|
5868
|
-
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5869
6054
|
const packagedFileUploads = bundleResult.packagedFiles.map(
|
|
5870
6055
|
(file) => stageFile(file.logicalPath, file.absolutePath)
|
|
5871
6056
|
);
|
|
6057
|
+
const compilerManifest = requireCompilerManifest(bundleResult);
|
|
5872
6058
|
const fileInputBindings = fileInputBindingsFromStaticPipeline(
|
|
5873
|
-
|
|
6059
|
+
compilerManifest.staticPipeline
|
|
5874
6060
|
);
|
|
5875
6061
|
applyCsvShortcutInput({
|
|
5876
6062
|
runtimeInput,
|
|
5877
6063
|
bindings: fileInputBindings,
|
|
5878
6064
|
fallbackInputPath: "file"
|
|
5879
6065
|
});
|
|
5880
|
-
const stagedFileInputs = await
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
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
|
+
);
|
|
5886
6079
|
const startRequest = {
|
|
5887
6080
|
name: playName,
|
|
5888
6081
|
sourceCode: bundleResult.sourceCode,
|
|
5889
6082
|
sourceFiles: bundleResult.sourceFiles,
|
|
5890
6083
|
runtimeArtifact: bundleResult.artifact,
|
|
5891
|
-
compilerManifest
|
|
6084
|
+
compilerManifest,
|
|
5892
6085
|
packagedFileUploads,
|
|
5893
6086
|
...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
|
|
5894
6087
|
...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
|
|
@@ -5897,26 +6090,42 @@ async function handleFileBackedRun(options) {
|
|
|
5897
6090
|
};
|
|
5898
6091
|
if (options.watch) {
|
|
5899
6092
|
progress.phase("starting run");
|
|
5900
|
-
const finalStatus = await
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
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
|
+
);
|
|
5910
6111
|
if (finalStatus.status === "completed") {
|
|
5911
6112
|
progress.complete();
|
|
5912
6113
|
} else {
|
|
5913
6114
|
progress.fail();
|
|
5914
6115
|
}
|
|
5915
|
-
|
|
6116
|
+
traceCliSync(
|
|
6117
|
+
"cli.play_write_result",
|
|
6118
|
+
{ targetKind: "file", playName },
|
|
6119
|
+
() => writePlayResult(finalStatus, options.jsonOutput, { exportedPath })
|
|
6120
|
+
);
|
|
5916
6121
|
return finalStatus.status === "completed" ? 0 : 1;
|
|
5917
6122
|
}
|
|
5918
6123
|
progress.phase("starting run");
|
|
5919
|
-
const started = await
|
|
6124
|
+
const started = await traceCliSpan(
|
|
6125
|
+
"cli.play_start_unwatched",
|
|
6126
|
+
{ targetKind: "file", playName },
|
|
6127
|
+
() => client.startPlayRun(startRequest)
|
|
6128
|
+
);
|
|
5920
6129
|
const dashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
5921
6130
|
progress.phase(`loading play on ${dashboardUrl}`);
|
|
5922
6131
|
progress.complete();
|
|
@@ -5951,32 +6160,67 @@ async function handleNamedRun(options) {
|
|
|
5951
6160
|
}
|
|
5952
6161
|
const client = new DeeplineClient();
|
|
5953
6162
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
5954
|
-
|
|
5955
|
-
const playDetail = await assertCanonicalNamedPlayReference(client, options.target.name);
|
|
5956
|
-
progress.phase("selecting revision");
|
|
5957
|
-
const selectedRevisionId = await resolveNamedRunRevisionId({
|
|
5958
|
-
client,
|
|
5959
|
-
playName: options.target.name,
|
|
5960
|
-
revisionId: options.revisionId,
|
|
5961
|
-
selector: options.revisionSelector
|
|
5962
|
-
});
|
|
6163
|
+
const playName = options.target.name;
|
|
5963
6164
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5964
|
-
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 ? [
|
|
5965
6201
|
...fileInputBindingsFromPlaySchema(playDetail.play.inputSchema),
|
|
5966
6202
|
...fileInputBindingsFromStaticPipeline(playDetail.play.staticPipeline)
|
|
5967
|
-
];
|
|
6203
|
+
] : [];
|
|
5968
6204
|
applyCsvShortcutInput({
|
|
5969
6205
|
runtimeInput,
|
|
5970
6206
|
bindings: fileInputBindings
|
|
5971
6207
|
});
|
|
5972
|
-
const stagedFileInputs = await
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
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
|
+
);
|
|
5978
6222
|
const startRequest = {
|
|
5979
|
-
name:
|
|
6223
|
+
name: playName,
|
|
5980
6224
|
...selectedRevisionId ? { revisionId: selectedRevisionId } : {},
|
|
5981
6225
|
...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
|
|
5982
6226
|
...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
|
|
@@ -5985,35 +6229,51 @@ async function handleNamedRun(options) {
|
|
|
5985
6229
|
};
|
|
5986
6230
|
if (options.watch) {
|
|
5987
6231
|
progress.phase("starting run");
|
|
5988
|
-
const finalStatus = await
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
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
|
+
);
|
|
5998
6250
|
if (finalStatus.status === "completed") {
|
|
5999
6251
|
progress.complete();
|
|
6000
6252
|
} else {
|
|
6001
6253
|
progress.fail();
|
|
6002
6254
|
}
|
|
6003
|
-
|
|
6255
|
+
traceCliSync(
|
|
6256
|
+
"cli.play_write_result",
|
|
6257
|
+
{ targetKind: "name", playName },
|
|
6258
|
+
() => writePlayResult(finalStatus, options.jsonOutput, { exportedPath })
|
|
6259
|
+
);
|
|
6004
6260
|
return finalStatus.status === "completed" ? 0 : 1;
|
|
6005
6261
|
}
|
|
6006
6262
|
progress.phase("starting run");
|
|
6007
|
-
const started = await
|
|
6263
|
+
const started = await traceCliSpan(
|
|
6264
|
+
"cli.play_start_unwatched",
|
|
6265
|
+
{ targetKind: "name", playName },
|
|
6266
|
+
() => client.startPlayRun(startRequest)
|
|
6267
|
+
);
|
|
6008
6268
|
const dashboardUrl = buildPlayDashboardUrl(
|
|
6009
6269
|
client.baseUrl,
|
|
6010
|
-
|
|
6270
|
+
playName
|
|
6011
6271
|
);
|
|
6012
6272
|
progress.phase(`loading play on ${dashboardUrl}`);
|
|
6013
6273
|
progress.complete();
|
|
6014
6274
|
writeStartedPlayRun({
|
|
6015
6275
|
runId: started.workflowId,
|
|
6016
|
-
playName: started.name ??
|
|
6276
|
+
playName: started.name ?? playName,
|
|
6017
6277
|
status: started.status,
|
|
6018
6278
|
statusUrl: started.statusUrl,
|
|
6019
6279
|
dashboardUrl: started.dashboardUrl ?? dashboardUrl,
|
|
@@ -7876,54 +8136,6 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
7876
8136
|
writeSdkSkillsStatusLine("SDK skills are up to date.");
|
|
7877
8137
|
}
|
|
7878
8138
|
|
|
7879
|
-
// src/cli/trace.ts
|
|
7880
|
-
var cliTraceStartedAt = Date.now();
|
|
7881
|
-
function isTruthyEnv(value) {
|
|
7882
|
-
return value === "1" || value === "true" || value === "yes";
|
|
7883
|
-
}
|
|
7884
|
-
function isCliTraceEnabled() {
|
|
7885
|
-
return isTruthyEnv(process.env.DEEPLINE_CLI_TRACE);
|
|
7886
|
-
}
|
|
7887
|
-
function recordCliTrace(event) {
|
|
7888
|
-
if (!isCliTraceEnabled()) {
|
|
7889
|
-
return;
|
|
7890
|
-
}
|
|
7891
|
-
const now = Date.now();
|
|
7892
|
-
const payload = {
|
|
7893
|
-
ts: now,
|
|
7894
|
-
source: "cli",
|
|
7895
|
-
sinceStartMs: now - cliTraceStartedAt,
|
|
7896
|
-
...event
|
|
7897
|
-
};
|
|
7898
|
-
process.stderr.write(`[cli-trace] ${JSON.stringify(payload)}
|
|
7899
|
-
`);
|
|
7900
|
-
}
|
|
7901
|
-
async function traceCliSpan(phase, fields, run) {
|
|
7902
|
-
if (!isCliTraceEnabled()) {
|
|
7903
|
-
return run();
|
|
7904
|
-
}
|
|
7905
|
-
const startedAt = Date.now();
|
|
7906
|
-
try {
|
|
7907
|
-
const result = await run();
|
|
7908
|
-
recordCliTrace({
|
|
7909
|
-
phase,
|
|
7910
|
-
ms: Date.now() - startedAt,
|
|
7911
|
-
ok: true,
|
|
7912
|
-
...fields
|
|
7913
|
-
});
|
|
7914
|
-
return result;
|
|
7915
|
-
} catch (error) {
|
|
7916
|
-
recordCliTrace({
|
|
7917
|
-
phase,
|
|
7918
|
-
ms: Date.now() - startedAt,
|
|
7919
|
-
ok: false,
|
|
7920
|
-
error: error instanceof Error ? error.message : String(error),
|
|
7921
|
-
...fields
|
|
7922
|
-
});
|
|
7923
|
-
throw error;
|
|
7924
|
-
}
|
|
7925
|
-
}
|
|
7926
|
-
|
|
7927
8139
|
// src/cli/index.ts
|
|
7928
8140
|
function shouldPrintStartupPhase() {
|
|
7929
8141
|
if (process.argv.includes("--json")) {
|
|
@@ -7934,6 +8146,12 @@ function shouldPrintStartupPhase() {
|
|
|
7934
8146
|
const subcommand = args[1];
|
|
7935
8147
|
return (command === "play" || command === "plays") && subcommand === "run";
|
|
7936
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
|
+
}
|
|
7937
8155
|
async function main() {
|
|
7938
8156
|
const mainStartedAt = Date.now();
|
|
7939
8157
|
recordCliTrace({
|
|
@@ -7978,11 +8196,13 @@ Output:
|
|
|
7978
8196
|
if (printStartupPhase) {
|
|
7979
8197
|
progress?.phase("checking sdk skills");
|
|
7980
8198
|
}
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
8199
|
+
if (!shouldDeferSkillsSyncForCommand()) {
|
|
8200
|
+
await traceCliSpan(
|
|
8201
|
+
"cli.sdk_skills_sync",
|
|
8202
|
+
{ baseUrl },
|
|
8203
|
+
() => syncSdkSkillsIfNeeded(baseUrl)
|
|
8204
|
+
);
|
|
8205
|
+
}
|
|
7986
8206
|
});
|
|
7987
8207
|
registerAuthCommands(program);
|
|
7988
8208
|
registerToolsCommands(program);
|