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 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.19";
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 msg = typeof parsed === "object" && parsed && "error" in parsed ? String(parsed.error) : `HTTP ${response.status}`;
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 response = await this.http.post(
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
- { files }
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
- return {
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(rowsInfo, options?.exportedPath),
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(rowsInfo, options?.exportedPath);
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 = (0, import_node_fs6.readFileSync)(absolutePlayPath, "utf-8");
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 collectBundledPlayGraph(absolutePlayPath);
5809
- await compileBundledPlayGraphManifests(client, graph);
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 publishImportedPlayDependencies(client, graph);
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
- requireCompilerManifest(bundleResult).staticPipeline
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 stageFileInputArgs({
5839
- client,
5840
- runtimeInput,
5841
- bindings: fileInputBindings,
5842
- progress
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: requireCompilerManifest(bundleResult),
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 startAndWaitForPlayCompletionByStream({
5859
- client,
5860
- request: startRequest,
5861
- playName,
5862
- jsonOutput: options.jsonOutput,
5863
- emitLogs: options.emitLogs,
5864
- waitTimeoutMs: options.waitTimeoutMs,
5865
- progress
5866
- });
5867
- const exportedPath = exportPlayStatusRows(finalStatus, options.outPath);
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
- writePlayResult(finalStatus, options.jsonOutput, { exportedPath });
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 client.startPlayRun(startRequest);
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
- progress.phase("loading play definition");
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 fileInputBindings = [
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 stageFileInputArgs({
5931
- client,
5932
- runtimeInput,
5933
- bindings: fileInputBindings,
5934
- progress
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: options.target.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 startAndWaitForPlayCompletionByStream({
5947
- client,
5948
- request: startRequest,
5949
- playName: options.target.name,
5950
- jsonOutput: options.jsonOutput,
5951
- emitLogs: options.emitLogs,
5952
- waitTimeoutMs: options.waitTimeoutMs,
5953
- progress
5954
- });
5955
- const exportedPath = exportPlayStatusRows(finalStatus, options.outPath);
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
- writePlayResult(finalStatus, options.jsonOutput, { exportedPath });
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 client.startPlayRun(startRequest);
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
- options.target.name
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 ?? options.target.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
- await traceCliSpan(
7940
- "cli.sdk_skills_sync",
7941
- { baseUrl },
7942
- () => syncSdkSkillsIfNeeded(baseUrl)
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);