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.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.21";
|
|
247
247
|
var SDK_API_CONTRACT = "2026-05-runs-v2";
|
|
248
248
|
|
|
249
249
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
@@ -326,7 +326,7 @@ var HttpClient = class {
|
|
|
326
326
|
const response = await fetch(candidateUrl, {
|
|
327
327
|
method,
|
|
328
328
|
headers,
|
|
329
|
-
body: options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
329
|
+
body: options?.formData !== void 0 ? options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
330
330
|
signal: controller.signal
|
|
331
331
|
});
|
|
332
332
|
clearTimeout(timeoutId);
|
|
@@ -445,6 +445,13 @@ var HttpClient = class {
|
|
|
445
445
|
headers
|
|
446
446
|
});
|
|
447
447
|
}
|
|
448
|
+
async postFormData(path, formData, headers) {
|
|
449
|
+
return this.request(path, {
|
|
450
|
+
method: "POST",
|
|
451
|
+
formData,
|
|
452
|
+
headers
|
|
453
|
+
});
|
|
454
|
+
}
|
|
448
455
|
/**
|
|
449
456
|
* Send a DELETE request.
|
|
450
457
|
*
|
|
@@ -553,6 +560,14 @@ function mapLegacyTemporalStatus(status) {
|
|
|
553
560
|
return "running";
|
|
554
561
|
}
|
|
555
562
|
}
|
|
563
|
+
function decodeBase64Bytes(value) {
|
|
564
|
+
const binary = atob(value);
|
|
565
|
+
const bytes = new Uint8Array(binary.length);
|
|
566
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
567
|
+
bytes[index] = binary.charCodeAt(index);
|
|
568
|
+
}
|
|
569
|
+
return bytes;
|
|
570
|
+
}
|
|
556
571
|
var DeeplineClient = class {
|
|
557
572
|
http;
|
|
558
573
|
config;
|
|
@@ -1004,9 +1019,34 @@ var DeeplineClient = class {
|
|
|
1004
1019
|
* ```
|
|
1005
1020
|
*/
|
|
1006
1021
|
async stagePlayFiles(files) {
|
|
1007
|
-
const
|
|
1022
|
+
const formData = new FormData();
|
|
1023
|
+
formData.set(
|
|
1024
|
+
"metadata",
|
|
1025
|
+
JSON.stringify({
|
|
1026
|
+
files: files.map((file, index) => ({
|
|
1027
|
+
index,
|
|
1028
|
+
logicalPath: file.logicalPath,
|
|
1029
|
+
contentHash: file.contentHash,
|
|
1030
|
+
contentType: file.contentType,
|
|
1031
|
+
bytes: file.bytes
|
|
1032
|
+
}))
|
|
1033
|
+
})
|
|
1034
|
+
);
|
|
1035
|
+
for (const [index, file] of files.entries()) {
|
|
1036
|
+
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1037
|
+
const body = bytes.buffer.slice(
|
|
1038
|
+
bytes.byteOffset,
|
|
1039
|
+
bytes.byteOffset + bytes.byteLength
|
|
1040
|
+
);
|
|
1041
|
+
formData.set(
|
|
1042
|
+
`file:${index}`,
|
|
1043
|
+
new Blob([body], { type: file.contentType }),
|
|
1044
|
+
file.logicalPath
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
const response = await this.http.postFormData(
|
|
1008
1048
|
"/api/v2/plays/files/stage",
|
|
1009
|
-
|
|
1049
|
+
formData
|
|
1010
1050
|
);
|
|
1011
1051
|
return response.files;
|
|
1012
1052
|
}
|
|
@@ -1035,9 +1075,14 @@ var DeeplineClient = class {
|
|
|
1035
1075
|
* console.log(`Logs: ${status.progress?.logs.length ?? 0} lines`);
|
|
1036
1076
|
* ```
|
|
1037
1077
|
*/
|
|
1038
|
-
async getPlayStatus(workflowId) {
|
|
1078
|
+
async getPlayStatus(workflowId, options) {
|
|
1079
|
+
const params = new URLSearchParams();
|
|
1080
|
+
if (options?.billing === false) {
|
|
1081
|
+
params.set("billing", "false");
|
|
1082
|
+
}
|
|
1083
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
1039
1084
|
const response = await this.http.get(
|
|
1040
|
-
`/api/v2/plays/run/${encodeURIComponent(workflowId)}`
|
|
1085
|
+
`/api/v2/plays/run/${encodeURIComponent(workflowId)}${query}`
|
|
1041
1086
|
);
|
|
1042
1087
|
return normalizePlayStatus(response);
|
|
1043
1088
|
}
|
|
@@ -4343,7 +4388,77 @@ function createCliProgress(enabled) {
|
|
|
4343
4388
|
return progress;
|
|
4344
4389
|
}
|
|
4345
4390
|
|
|
4391
|
+
// src/cli/trace.ts
|
|
4392
|
+
var cliTraceStartedAt = Date.now();
|
|
4393
|
+
function isTruthyEnv(value) {
|
|
4394
|
+
return value === "1" || value === "true" || value === "yes";
|
|
4395
|
+
}
|
|
4396
|
+
function isCliTraceEnabled() {
|
|
4397
|
+
return isTruthyEnv(process.env.DEEPLINE_CLI_TRACE);
|
|
4398
|
+
}
|
|
4399
|
+
function recordCliTrace(event) {
|
|
4400
|
+
if (!isCliTraceEnabled()) {
|
|
4401
|
+
return;
|
|
4402
|
+
}
|
|
4403
|
+
const now = Date.now();
|
|
4404
|
+
const payload = {
|
|
4405
|
+
ts: now,
|
|
4406
|
+
source: "cli",
|
|
4407
|
+
sinceStartMs: now - cliTraceStartedAt,
|
|
4408
|
+
...event
|
|
4409
|
+
};
|
|
4410
|
+
process.stderr.write(`[cli-trace] ${JSON.stringify(payload)}
|
|
4411
|
+
`);
|
|
4412
|
+
}
|
|
4413
|
+
async function traceCliSpan(phase, fields, run) {
|
|
4414
|
+
if (!isCliTraceEnabled()) {
|
|
4415
|
+
return run();
|
|
4416
|
+
}
|
|
4417
|
+
const startedAt = Date.now();
|
|
4418
|
+
try {
|
|
4419
|
+
const result = await run();
|
|
4420
|
+
recordCliTrace({
|
|
4421
|
+
phase,
|
|
4422
|
+
ms: Date.now() - startedAt,
|
|
4423
|
+
ok: true,
|
|
4424
|
+
...fields
|
|
4425
|
+
});
|
|
4426
|
+
return result;
|
|
4427
|
+
} catch (error) {
|
|
4428
|
+
recordCliTrace({
|
|
4429
|
+
phase,
|
|
4430
|
+
ms: Date.now() - startedAt,
|
|
4431
|
+
ok: false,
|
|
4432
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4433
|
+
...fields
|
|
4434
|
+
});
|
|
4435
|
+
throw error;
|
|
4436
|
+
}
|
|
4437
|
+
}
|
|
4438
|
+
|
|
4346
4439
|
// src/cli/commands/play.ts
|
|
4440
|
+
function traceCliSync(phase, fields, run) {
|
|
4441
|
+
const startedAt = Date.now();
|
|
4442
|
+
try {
|
|
4443
|
+
const result = run();
|
|
4444
|
+
recordCliTrace({
|
|
4445
|
+
phase,
|
|
4446
|
+
ms: Date.now() - startedAt,
|
|
4447
|
+
ok: true,
|
|
4448
|
+
...fields
|
|
4449
|
+
});
|
|
4450
|
+
return result;
|
|
4451
|
+
} catch (error) {
|
|
4452
|
+
recordCliTrace({
|
|
4453
|
+
phase,
|
|
4454
|
+
ms: Date.now() - startedAt,
|
|
4455
|
+
ok: false,
|
|
4456
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4457
|
+
...fields
|
|
4458
|
+
});
|
|
4459
|
+
throw error;
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4347
4462
|
function parseReferencedPlayTarget(target) {
|
|
4348
4463
|
const trimmed = target.trim();
|
|
4349
4464
|
const slashIndex = trimmed.indexOf("/");
|
|
@@ -4582,6 +4697,23 @@ function isLocalFilePathValue(value) {
|
|
|
4582
4697
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
|
|
4583
4698
|
return existsSync4(resolve7(value));
|
|
4584
4699
|
}
|
|
4700
|
+
function inputContainsLocalFilePath(value) {
|
|
4701
|
+
if (isLocalFilePathValue(value)) {
|
|
4702
|
+
return true;
|
|
4703
|
+
}
|
|
4704
|
+
if (Array.isArray(value)) {
|
|
4705
|
+
return value.some((entry) => inputContainsLocalFilePath(entry));
|
|
4706
|
+
}
|
|
4707
|
+
if (value && typeof value === "object") {
|
|
4708
|
+
return Object.values(value).some(
|
|
4709
|
+
(entry) => inputContainsLocalFilePath(entry)
|
|
4710
|
+
);
|
|
4711
|
+
}
|
|
4712
|
+
return false;
|
|
4713
|
+
}
|
|
4714
|
+
function namedRunNeedsPlayDefinition(input) {
|
|
4715
|
+
return input.revisionSelector === "latest" || getDottedInputValue(input.runtimeInput, "csv") != null || inputContainsLocalFilePath(input.runtimeInput);
|
|
4716
|
+
}
|
|
4585
4717
|
async function stageFileInputArgs(input) {
|
|
4586
4718
|
const uniqueBindings = [
|
|
4587
4719
|
...new Map(input.bindings.map((binding) => [binding.inputPath, binding])).values()
|
|
@@ -4894,6 +5026,8 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4894
5026
|
let timedOut = false;
|
|
4895
5027
|
let emittedDashboardUrl = false;
|
|
4896
5028
|
let lastKnownWorkflowId = "";
|
|
5029
|
+
let eventCount = 0;
|
|
5030
|
+
let firstRunIdMs = null;
|
|
4897
5031
|
let lastPhase = null;
|
|
4898
5032
|
const timeout = input.waitTimeoutMs === null ? null : setTimeout(
|
|
4899
5033
|
() => {
|
|
@@ -4906,9 +5040,11 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4906
5040
|
for await (const event of input.client.startPlayRunStream(input.request, {
|
|
4907
5041
|
signal: controller.signal
|
|
4908
5042
|
})) {
|
|
5043
|
+
eventCount += 1;
|
|
4909
5044
|
const eventRunId = getEventPayload(event).runId;
|
|
4910
5045
|
if (typeof eventRunId === "string" && eventRunId && eventRunId !== "pending") {
|
|
4911
5046
|
lastKnownWorkflowId = eventRunId;
|
|
5047
|
+
firstRunIdMs ??= Date.now() - startedAt;
|
|
4912
5048
|
}
|
|
4913
5049
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
4914
5050
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
@@ -4946,6 +5082,16 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4946
5082
|
});
|
|
4947
5083
|
const finalStatus = getFinalStatusFromLiveEvent(event);
|
|
4948
5084
|
if (finalStatus) {
|
|
5085
|
+
recordCliTrace({
|
|
5086
|
+
phase: "cli.play_start_stream_terminal",
|
|
5087
|
+
ms: Date.now() - startedAt,
|
|
5088
|
+
ok: true,
|
|
5089
|
+
playName: input.playName,
|
|
5090
|
+
workflowId: finalStatus.runId || lastKnownWorkflowId || null,
|
|
5091
|
+
eventCount,
|
|
5092
|
+
firstRunIdMs,
|
|
5093
|
+
lastPhase
|
|
5094
|
+
});
|
|
4949
5095
|
return finalStatus;
|
|
4950
5096
|
}
|
|
4951
5097
|
}
|
|
@@ -4969,6 +5115,17 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4969
5115
|
`
|
|
4970
5116
|
);
|
|
4971
5117
|
}
|
|
5118
|
+
recordCliTrace({
|
|
5119
|
+
phase: "cli.play_start_stream_fallback",
|
|
5120
|
+
ms: Date.now() - startedAt,
|
|
5121
|
+
ok: false,
|
|
5122
|
+
playName: input.playName,
|
|
5123
|
+
workflowId: lastKnownWorkflowId,
|
|
5124
|
+
eventCount,
|
|
5125
|
+
firstRunIdMs,
|
|
5126
|
+
lastPhase,
|
|
5127
|
+
reason
|
|
5128
|
+
});
|
|
4972
5129
|
return waitForPlayCompletionByPolling({
|
|
4973
5130
|
client: input.client,
|
|
4974
5131
|
workflowId: lastKnownWorkflowId,
|
|
@@ -4993,6 +5150,17 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
4993
5150
|
`[play watch] start stream ended after run ${lastKnownWorkflowId}; falling back to polling`
|
|
4994
5151
|
);
|
|
4995
5152
|
}
|
|
5153
|
+
recordCliTrace({
|
|
5154
|
+
phase: "cli.play_start_stream_fallback",
|
|
5155
|
+
ms: Date.now() - startedAt,
|
|
5156
|
+
ok: false,
|
|
5157
|
+
playName: input.playName,
|
|
5158
|
+
workflowId: lastKnownWorkflowId,
|
|
5159
|
+
eventCount,
|
|
5160
|
+
firstRunIdMs,
|
|
5161
|
+
lastPhase,
|
|
5162
|
+
reason: "stream ended before terminal event"
|
|
5163
|
+
});
|
|
4996
5164
|
return waitForPlayCompletionByPolling({
|
|
4997
5165
|
client: input.client,
|
|
4998
5166
|
workflowId: lastKnownWorkflowId,
|
|
@@ -5067,10 +5235,11 @@ async function waitForPlayCompletionByPolling(input) {
|
|
|
5067
5235
|
progress: input.progress
|
|
5068
5236
|
});
|
|
5069
5237
|
if (TERMINAL_PLAY_STATUSES2.has(status.status)) {
|
|
5070
|
-
return status.result !== void 0 ? status : await input.client.getPlayStatus(input.workflowId);
|
|
5238
|
+
return status.result !== void 0 ? status : await input.client.getPlayStatus(input.workflowId, { billing: false });
|
|
5071
5239
|
}
|
|
5072
5240
|
const authoritativeStatus = await input.client.getPlayStatus(
|
|
5073
|
-
input.workflowId
|
|
5241
|
+
input.workflowId,
|
|
5242
|
+
{ billing: false }
|
|
5074
5243
|
);
|
|
5075
5244
|
if (TERMINAL_PLAY_STATUSES2.has(authoritativeStatus.status)) {
|
|
5076
5245
|
return authoritativeStatus;
|
|
@@ -5825,11 +5994,24 @@ async function handleFileBackedRun(options) {
|
|
|
5825
5994
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
5826
5995
|
const absolutePlayPath = resolve7(options.target.path);
|
|
5827
5996
|
progress.phase("compiling play");
|
|
5828
|
-
const sourceCode =
|
|
5997
|
+
const sourceCode = traceCliSync(
|
|
5998
|
+
"cli.play_file_read_source",
|
|
5999
|
+
{ targetKind: "file" },
|
|
6000
|
+
() => readFileSync3(absolutePlayPath, "utf-8")
|
|
6001
|
+
);
|
|
6002
|
+
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5829
6003
|
let graph;
|
|
5830
6004
|
try {
|
|
5831
|
-
graph = await
|
|
5832
|
-
|
|
6005
|
+
graph = await traceCliSpan(
|
|
6006
|
+
"cli.play_file_bundle_graph",
|
|
6007
|
+
{ targetKind: "file" },
|
|
6008
|
+
() => collectBundledPlayGraph(absolutePlayPath)
|
|
6009
|
+
);
|
|
6010
|
+
await traceCliSpan(
|
|
6011
|
+
"cli.play_file_compile_manifests",
|
|
6012
|
+
{ targetKind: "file" },
|
|
6013
|
+
() => compileBundledPlayGraphManifests(client, graph)
|
|
6014
|
+
);
|
|
5833
6015
|
progress.phase("compiled play");
|
|
5834
6016
|
} catch (error) {
|
|
5835
6017
|
progress.fail();
|
|
@@ -5840,36 +6022,47 @@ async function handleFileBackedRun(options) {
|
|
|
5840
6022
|
const playName = bundleResult.playName ?? extractPlayName(sourceCode, absolutePlayPath);
|
|
5841
6023
|
try {
|
|
5842
6024
|
progress.phase("publishing imported plays");
|
|
5843
|
-
await
|
|
6025
|
+
await traceCliSpan(
|
|
6026
|
+
"cli.play_file_publish_imports",
|
|
6027
|
+
{ targetKind: "file" },
|
|
6028
|
+
() => publishImportedPlayDependencies(client, graph)
|
|
6029
|
+
);
|
|
5844
6030
|
} catch (error) {
|
|
5845
6031
|
progress.fail();
|
|
5846
6032
|
console.error(error instanceof Error ? error.message : String(error));
|
|
5847
6033
|
return 1;
|
|
5848
6034
|
}
|
|
5849
|
-
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5850
6035
|
const packagedFileUploads = bundleResult.packagedFiles.map(
|
|
5851
6036
|
(file) => stageFile(file.logicalPath, file.absolutePath)
|
|
5852
6037
|
);
|
|
6038
|
+
const compilerManifest = requireCompilerManifest(bundleResult);
|
|
5853
6039
|
const fileInputBindings = fileInputBindingsFromStaticPipeline(
|
|
5854
|
-
|
|
6040
|
+
compilerManifest.staticPipeline
|
|
5855
6041
|
);
|
|
5856
6042
|
applyCsvShortcutInput({
|
|
5857
6043
|
runtimeInput,
|
|
5858
6044
|
bindings: fileInputBindings,
|
|
5859
6045
|
fallbackInputPath: "file"
|
|
5860
6046
|
});
|
|
5861
|
-
const stagedFileInputs = await
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
6047
|
+
const stagedFileInputs = await traceCliSpan(
|
|
6048
|
+
"cli.play_stage_inputs",
|
|
6049
|
+
{
|
|
6050
|
+
targetKind: "file",
|
|
6051
|
+
bindingCount: fileInputBindings.length
|
|
6052
|
+
},
|
|
6053
|
+
() => stageFileInputArgs({
|
|
6054
|
+
client,
|
|
6055
|
+
runtimeInput,
|
|
6056
|
+
bindings: fileInputBindings,
|
|
6057
|
+
progress
|
|
6058
|
+
})
|
|
6059
|
+
);
|
|
5867
6060
|
const startRequest = {
|
|
5868
6061
|
name: playName,
|
|
5869
6062
|
sourceCode: bundleResult.sourceCode,
|
|
5870
6063
|
sourceFiles: bundleResult.sourceFiles,
|
|
5871
6064
|
runtimeArtifact: bundleResult.artifact,
|
|
5872
|
-
compilerManifest
|
|
6065
|
+
compilerManifest,
|
|
5873
6066
|
packagedFileUploads,
|
|
5874
6067
|
...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
|
|
5875
6068
|
...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
|
|
@@ -5878,26 +6071,42 @@ async function handleFileBackedRun(options) {
|
|
|
5878
6071
|
};
|
|
5879
6072
|
if (options.watch) {
|
|
5880
6073
|
progress.phase("starting run");
|
|
5881
|
-
const finalStatus = await
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
6074
|
+
const finalStatus = await traceCliSpan(
|
|
6075
|
+
"cli.play_start_watch",
|
|
6076
|
+
{ targetKind: "file", playName },
|
|
6077
|
+
() => startAndWaitForPlayCompletionByStream({
|
|
6078
|
+
client,
|
|
6079
|
+
request: startRequest,
|
|
6080
|
+
playName,
|
|
6081
|
+
jsonOutput: options.jsonOutput,
|
|
6082
|
+
emitLogs: options.emitLogs,
|
|
6083
|
+
waitTimeoutMs: options.waitTimeoutMs,
|
|
6084
|
+
progress
|
|
6085
|
+
})
|
|
6086
|
+
);
|
|
6087
|
+
const exportedPath = traceCliSync(
|
|
6088
|
+
"cli.play_export_rows",
|
|
6089
|
+
{ targetKind: "file", playName },
|
|
6090
|
+
() => exportPlayStatusRows(finalStatus, options.outPath)
|
|
6091
|
+
);
|
|
5891
6092
|
if (finalStatus.status === "completed") {
|
|
5892
6093
|
progress.complete();
|
|
5893
6094
|
} else {
|
|
5894
6095
|
progress.fail();
|
|
5895
6096
|
}
|
|
5896
|
-
|
|
6097
|
+
traceCliSync(
|
|
6098
|
+
"cli.play_write_result",
|
|
6099
|
+
{ targetKind: "file", playName },
|
|
6100
|
+
() => writePlayResult(finalStatus, options.jsonOutput, { exportedPath })
|
|
6101
|
+
);
|
|
5897
6102
|
return finalStatus.status === "completed" ? 0 : 1;
|
|
5898
6103
|
}
|
|
5899
6104
|
progress.phase("starting run");
|
|
5900
|
-
const started = await
|
|
6105
|
+
const started = await traceCliSpan(
|
|
6106
|
+
"cli.play_start_unwatched",
|
|
6107
|
+
{ targetKind: "file", playName },
|
|
6108
|
+
() => client.startPlayRun(startRequest)
|
|
6109
|
+
);
|
|
5901
6110
|
const dashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
5902
6111
|
progress.phase(`loading play on ${dashboardUrl}`);
|
|
5903
6112
|
progress.complete();
|
|
@@ -5932,32 +6141,67 @@ async function handleNamedRun(options) {
|
|
|
5932
6141
|
}
|
|
5933
6142
|
const client = new DeeplineClient();
|
|
5934
6143
|
const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
|
|
5935
|
-
|
|
5936
|
-
const playDetail = await assertCanonicalNamedPlayReference(client, options.target.name);
|
|
5937
|
-
progress.phase("selecting revision");
|
|
5938
|
-
const selectedRevisionId = await resolveNamedRunRevisionId({
|
|
5939
|
-
client,
|
|
5940
|
-
playName: options.target.name,
|
|
5941
|
-
revisionId: options.revisionId,
|
|
5942
|
-
selector: options.revisionSelector
|
|
5943
|
-
});
|
|
6144
|
+
const playName = options.target.name;
|
|
5944
6145
|
const runtimeInput = options.input ? { ...options.input } : {};
|
|
5945
|
-
const
|
|
6146
|
+
const needsPlayDefinition = namedRunNeedsPlayDefinition({
|
|
6147
|
+
runtimeInput,
|
|
6148
|
+
revisionSelector: options.revisionSelector
|
|
6149
|
+
});
|
|
6150
|
+
const playDetail = needsPlayDefinition ? await (async () => {
|
|
6151
|
+
progress.phase("loading play definition");
|
|
6152
|
+
return traceCliSpan(
|
|
6153
|
+
"cli.play_load_definition",
|
|
6154
|
+
{ targetKind: "name", playName, skipped: false },
|
|
6155
|
+
() => assertCanonicalNamedPlayReference(client, playName)
|
|
6156
|
+
);
|
|
6157
|
+
})() : (recordCliTrace({
|
|
6158
|
+
phase: "cli.play_load_definition",
|
|
6159
|
+
ms: 0,
|
|
6160
|
+
ok: true,
|
|
6161
|
+
targetKind: "name",
|
|
6162
|
+
playName,
|
|
6163
|
+
skipped: true
|
|
6164
|
+
}), null);
|
|
6165
|
+
progress.phase("selecting revision");
|
|
6166
|
+
const selectedRevisionId = await traceCliSpan(
|
|
6167
|
+
"cli.play_select_revision",
|
|
6168
|
+
{
|
|
6169
|
+
targetKind: "name",
|
|
6170
|
+
playName,
|
|
6171
|
+
selector: options.revisionSelector,
|
|
6172
|
+
hasExplicitRevisionId: Boolean(options.revisionId)
|
|
6173
|
+
},
|
|
6174
|
+
() => resolveNamedRunRevisionId({
|
|
6175
|
+
client,
|
|
6176
|
+
playName,
|
|
6177
|
+
revisionId: options.revisionId,
|
|
6178
|
+
selector: options.revisionSelector
|
|
6179
|
+
})
|
|
6180
|
+
);
|
|
6181
|
+
const fileInputBindings = playDetail ? [
|
|
5946
6182
|
...fileInputBindingsFromPlaySchema(playDetail.play.inputSchema),
|
|
5947
6183
|
...fileInputBindingsFromStaticPipeline(playDetail.play.staticPipeline)
|
|
5948
|
-
];
|
|
6184
|
+
] : [];
|
|
5949
6185
|
applyCsvShortcutInput({
|
|
5950
6186
|
runtimeInput,
|
|
5951
6187
|
bindings: fileInputBindings
|
|
5952
6188
|
});
|
|
5953
|
-
const stagedFileInputs = await
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
6189
|
+
const stagedFileInputs = await traceCliSpan(
|
|
6190
|
+
"cli.play_stage_inputs",
|
|
6191
|
+
{
|
|
6192
|
+
targetKind: "name",
|
|
6193
|
+
playName,
|
|
6194
|
+
bindingCount: fileInputBindings.length
|
|
6195
|
+
},
|
|
6196
|
+
() => stageFileInputArgs({
|
|
6197
|
+
client,
|
|
6198
|
+
runtimeInput,
|
|
6199
|
+
bindings: fileInputBindings,
|
|
6200
|
+
progress
|
|
6201
|
+
})
|
|
6202
|
+
);
|
|
5959
6203
|
const startRequest = {
|
|
5960
|
-
name:
|
|
6204
|
+
name: playName,
|
|
5961
6205
|
...selectedRevisionId ? { revisionId: selectedRevisionId } : {},
|
|
5962
6206
|
...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
|
|
5963
6207
|
...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
|
|
@@ -5966,35 +6210,51 @@ async function handleNamedRun(options) {
|
|
|
5966
6210
|
};
|
|
5967
6211
|
if (options.watch) {
|
|
5968
6212
|
progress.phase("starting run");
|
|
5969
|
-
const finalStatus = await
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
6213
|
+
const finalStatus = await traceCliSpan(
|
|
6214
|
+
"cli.play_start_watch",
|
|
6215
|
+
{ targetKind: "name", playName },
|
|
6216
|
+
() => startAndWaitForPlayCompletionByStream({
|
|
6217
|
+
client,
|
|
6218
|
+
request: startRequest,
|
|
6219
|
+
playName,
|
|
6220
|
+
jsonOutput: options.jsonOutput,
|
|
6221
|
+
emitLogs: options.emitLogs,
|
|
6222
|
+
waitTimeoutMs: options.waitTimeoutMs,
|
|
6223
|
+
progress
|
|
6224
|
+
})
|
|
6225
|
+
);
|
|
6226
|
+
const exportedPath = traceCliSync(
|
|
6227
|
+
"cli.play_export_rows",
|
|
6228
|
+
{ targetKind: "name", playName },
|
|
6229
|
+
() => exportPlayStatusRows(finalStatus, options.outPath)
|
|
6230
|
+
);
|
|
5979
6231
|
if (finalStatus.status === "completed") {
|
|
5980
6232
|
progress.complete();
|
|
5981
6233
|
} else {
|
|
5982
6234
|
progress.fail();
|
|
5983
6235
|
}
|
|
5984
|
-
|
|
6236
|
+
traceCliSync(
|
|
6237
|
+
"cli.play_write_result",
|
|
6238
|
+
{ targetKind: "name", playName },
|
|
6239
|
+
() => writePlayResult(finalStatus, options.jsonOutput, { exportedPath })
|
|
6240
|
+
);
|
|
5985
6241
|
return finalStatus.status === "completed" ? 0 : 1;
|
|
5986
6242
|
}
|
|
5987
6243
|
progress.phase("starting run");
|
|
5988
|
-
const started = await
|
|
6244
|
+
const started = await traceCliSpan(
|
|
6245
|
+
"cli.play_start_unwatched",
|
|
6246
|
+
{ targetKind: "name", playName },
|
|
6247
|
+
() => client.startPlayRun(startRequest)
|
|
6248
|
+
);
|
|
5989
6249
|
const dashboardUrl = buildPlayDashboardUrl(
|
|
5990
6250
|
client.baseUrl,
|
|
5991
|
-
|
|
6251
|
+
playName
|
|
5992
6252
|
);
|
|
5993
6253
|
progress.phase(`loading play on ${dashboardUrl}`);
|
|
5994
6254
|
progress.complete();
|
|
5995
6255
|
writeStartedPlayRun({
|
|
5996
6256
|
runId: started.workflowId,
|
|
5997
|
-
playName: started.name ??
|
|
6257
|
+
playName: started.name ?? playName,
|
|
5998
6258
|
status: started.status,
|
|
5999
6259
|
statusUrl: started.statusUrl,
|
|
6000
6260
|
dashboardUrl: started.dashboardUrl ?? dashboardUrl,
|
|
@@ -7857,54 +8117,6 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
7857
8117
|
writeSdkSkillsStatusLine("SDK skills are up to date.");
|
|
7858
8118
|
}
|
|
7859
8119
|
|
|
7860
|
-
// src/cli/trace.ts
|
|
7861
|
-
var cliTraceStartedAt = Date.now();
|
|
7862
|
-
function isTruthyEnv(value) {
|
|
7863
|
-
return value === "1" || value === "true" || value === "yes";
|
|
7864
|
-
}
|
|
7865
|
-
function isCliTraceEnabled() {
|
|
7866
|
-
return isTruthyEnv(process.env.DEEPLINE_CLI_TRACE);
|
|
7867
|
-
}
|
|
7868
|
-
function recordCliTrace(event) {
|
|
7869
|
-
if (!isCliTraceEnabled()) {
|
|
7870
|
-
return;
|
|
7871
|
-
}
|
|
7872
|
-
const now = Date.now();
|
|
7873
|
-
const payload = {
|
|
7874
|
-
ts: now,
|
|
7875
|
-
source: "cli",
|
|
7876
|
-
sinceStartMs: now - cliTraceStartedAt,
|
|
7877
|
-
...event
|
|
7878
|
-
};
|
|
7879
|
-
process.stderr.write(`[cli-trace] ${JSON.stringify(payload)}
|
|
7880
|
-
`);
|
|
7881
|
-
}
|
|
7882
|
-
async function traceCliSpan(phase, fields, run) {
|
|
7883
|
-
if (!isCliTraceEnabled()) {
|
|
7884
|
-
return run();
|
|
7885
|
-
}
|
|
7886
|
-
const startedAt = Date.now();
|
|
7887
|
-
try {
|
|
7888
|
-
const result = await run();
|
|
7889
|
-
recordCliTrace({
|
|
7890
|
-
phase,
|
|
7891
|
-
ms: Date.now() - startedAt,
|
|
7892
|
-
ok: true,
|
|
7893
|
-
...fields
|
|
7894
|
-
});
|
|
7895
|
-
return result;
|
|
7896
|
-
} catch (error) {
|
|
7897
|
-
recordCliTrace({
|
|
7898
|
-
phase,
|
|
7899
|
-
ms: Date.now() - startedAt,
|
|
7900
|
-
ok: false,
|
|
7901
|
-
error: error instanceof Error ? error.message : String(error),
|
|
7902
|
-
...fields
|
|
7903
|
-
});
|
|
7904
|
-
throw error;
|
|
7905
|
-
}
|
|
7906
|
-
}
|
|
7907
|
-
|
|
7908
8120
|
// src/cli/index.ts
|
|
7909
8121
|
function shouldPrintStartupPhase() {
|
|
7910
8122
|
if (process.argv.includes("--json")) {
|
|
@@ -7915,6 +8127,12 @@ function shouldPrintStartupPhase() {
|
|
|
7915
8127
|
const subcommand = args[1];
|
|
7916
8128
|
return (command === "play" || command === "plays") && subcommand === "run";
|
|
7917
8129
|
}
|
|
8130
|
+
function shouldDeferSkillsSyncForCommand() {
|
|
8131
|
+
const args = process.argv.slice(2);
|
|
8132
|
+
const command = args[0];
|
|
8133
|
+
const subcommand = args[1];
|
|
8134
|
+
return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
|
|
8135
|
+
}
|
|
7918
8136
|
async function main() {
|
|
7919
8137
|
const mainStartedAt = Date.now();
|
|
7920
8138
|
recordCliTrace({
|
|
@@ -7959,11 +8177,13 @@ Output:
|
|
|
7959
8177
|
if (printStartupPhase) {
|
|
7960
8178
|
progress?.phase("checking sdk skills");
|
|
7961
8179
|
}
|
|
7962
|
-
|
|
7963
|
-
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
8180
|
+
if (!shouldDeferSkillsSyncForCommand()) {
|
|
8181
|
+
await traceCliSpan(
|
|
8182
|
+
"cli.sdk_skills_sync",
|
|
8183
|
+
{ baseUrl },
|
|
8184
|
+
() => syncSdkSkillsIfNeeded(baseUrl)
|
|
8185
|
+
);
|
|
8186
|
+
}
|
|
7967
8187
|
});
|
|
7968
8188
|
registerAuthCommands(program);
|
|
7969
8189
|
registerToolsCommands(program);
|
package/dist/index.d.mts
CHANGED
|
@@ -1173,7 +1173,9 @@ declare class DeeplineClient {
|
|
|
1173
1173
|
* console.log(`Logs: ${status.progress?.logs.length ?? 0} lines`);
|
|
1174
1174
|
* ```
|
|
1175
1175
|
*/
|
|
1176
|
-
getPlayStatus(workflowId: string
|
|
1176
|
+
getPlayStatus(workflowId: string, options?: {
|
|
1177
|
+
billing?: boolean;
|
|
1178
|
+
}): Promise<PlayStatus>;
|
|
1177
1179
|
/**
|
|
1178
1180
|
* Get the lightweight tail-polling status for a play execution.
|
|
1179
1181
|
*
|
|
@@ -1434,7 +1436,7 @@ declare class DeeplineClient {
|
|
|
1434
1436
|
}>;
|
|
1435
1437
|
}
|
|
1436
1438
|
|
|
1437
|
-
declare const SDK_VERSION = "0.1.
|
|
1439
|
+
declare const SDK_VERSION = "0.1.21";
|
|
1438
1440
|
declare const SDK_API_CONTRACT = "2026-05-runs-v2";
|
|
1439
1441
|
|
|
1440
1442
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1173,7 +1173,9 @@ declare class DeeplineClient {
|
|
|
1173
1173
|
* console.log(`Logs: ${status.progress?.logs.length ?? 0} lines`);
|
|
1174
1174
|
* ```
|
|
1175
1175
|
*/
|
|
1176
|
-
getPlayStatus(workflowId: string
|
|
1176
|
+
getPlayStatus(workflowId: string, options?: {
|
|
1177
|
+
billing?: boolean;
|
|
1178
|
+
}): Promise<PlayStatus>;
|
|
1177
1179
|
/**
|
|
1178
1180
|
* Get the lightweight tail-polling status for a play execution.
|
|
1179
1181
|
*
|
|
@@ -1434,7 +1436,7 @@ declare class DeeplineClient {
|
|
|
1434
1436
|
}>;
|
|
1435
1437
|
}
|
|
1436
1438
|
|
|
1437
|
-
declare const SDK_VERSION = "0.1.
|
|
1439
|
+
declare const SDK_VERSION = "0.1.21";
|
|
1438
1440
|
declare const SDK_API_CONTRACT = "2026-05-runs-v2";
|
|
1439
1441
|
|
|
1440
1442
|
/**
|