deepline 0.1.0 → 0.1.2

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.
Files changed (97) hide show
  1. package/dist/cli/index.js +212 -54
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/cli/index.mjs +198 -40
  4. package/dist/cli/index.mjs.map +1 -1
  5. package/dist/index.d.mts +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +1 -1
  8. package/dist/index.mjs +1 -1
  9. package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +3256 -0
  10. package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +710 -0
  11. package/dist/repo/apps/play-runner-workers/src/entry.ts +5070 -0
  12. package/dist/repo/apps/play-runner-workers/src/runtime/README.md +21 -0
  13. package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +177 -0
  14. package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +52 -0
  15. package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +100 -0
  16. package/dist/repo/apps/play-runner-workers/src/runtime/tool-result.ts +184 -0
  17. package/dist/repo/sdk/src/cli/commands/auth.ts +482 -0
  18. package/dist/repo/sdk/src/cli/commands/billing.ts +188 -0
  19. package/dist/repo/sdk/src/cli/commands/csv.ts +123 -0
  20. package/dist/repo/sdk/src/cli/commands/db.ts +119 -0
  21. package/dist/repo/sdk/src/cli/commands/feedback.ts +40 -0
  22. package/dist/repo/sdk/src/cli/commands/org.ts +117 -0
  23. package/dist/repo/sdk/src/cli/commands/play.ts +3200 -0
  24. package/dist/repo/sdk/src/cli/commands/tools.ts +687 -0
  25. package/dist/repo/sdk/src/cli/dataset-stats.ts +341 -0
  26. package/dist/repo/sdk/src/cli/index.ts +138 -0
  27. package/dist/repo/sdk/src/cli/progress.ts +135 -0
  28. package/dist/repo/sdk/src/cli/trace.ts +61 -0
  29. package/dist/repo/sdk/src/cli/utils.ts +145 -0
  30. package/dist/repo/sdk/src/client.ts +1188 -0
  31. package/dist/repo/sdk/src/compat.ts +77 -0
  32. package/dist/repo/sdk/src/config.ts +285 -0
  33. package/dist/repo/sdk/src/errors.ts +125 -0
  34. package/dist/repo/sdk/src/http.ts +391 -0
  35. package/dist/repo/sdk/src/index.ts +139 -0
  36. package/dist/repo/sdk/src/play.ts +1330 -0
  37. package/dist/repo/sdk/src/plays/bundle-play-file.ts +133 -0
  38. package/dist/repo/sdk/src/plays/harness-stub.ts +210 -0
  39. package/dist/repo/sdk/src/plays/local-file-discovery.ts +326 -0
  40. package/dist/repo/sdk/src/tool-output.ts +489 -0
  41. package/dist/repo/sdk/src/types.ts +669 -0
  42. package/dist/repo/sdk/src/version.ts +2 -0
  43. package/dist/repo/sdk/src/worker-play-entry.ts +286 -0
  44. package/dist/repo/shared_libs/observability/node-tracing.ts +129 -0
  45. package/dist/repo/shared_libs/observability/tracing.ts +98 -0
  46. package/dist/repo/shared_libs/play-runtime/backend.ts +139 -0
  47. package/dist/repo/shared_libs/play-runtime/batch-runtime.ts +182 -0
  48. package/dist/repo/shared_libs/play-runtime/batching-types.ts +91 -0
  49. package/dist/repo/shared_libs/play-runtime/context.ts +3999 -0
  50. package/dist/repo/shared_libs/play-runtime/coordinator-headers.ts +78 -0
  51. package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +250 -0
  52. package/dist/repo/shared_libs/play-runtime/ctx-types.ts +713 -0
  53. package/dist/repo/shared_libs/play-runtime/dataset-id.ts +10 -0
  54. package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +304 -0
  55. package/dist/repo/shared_libs/play-runtime/db-session.ts +462 -0
  56. package/dist/repo/shared_libs/play-runtime/dedup-backend.ts +0 -0
  57. package/dist/repo/shared_libs/play-runtime/default-batch-strategies.ts +124 -0
  58. package/dist/repo/shared_libs/play-runtime/execution-plan.ts +262 -0
  59. package/dist/repo/shared_libs/play-runtime/live-events.ts +214 -0
  60. package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +50 -0
  61. package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +114 -0
  62. package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +158 -0
  63. package/dist/repo/shared_libs/play-runtime/profiles.ts +90 -0
  64. package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +172 -0
  65. package/dist/repo/shared_libs/play-runtime/protocol.ts +121 -0
  66. package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +42 -0
  67. package/dist/repo/shared_libs/play-runtime/result-normalization.ts +33 -0
  68. package/dist/repo/shared_libs/play-runtime/runtime-actions.ts +208 -0
  69. package/dist/repo/shared_libs/play-runtime/runtime-api.ts +1873 -0
  70. package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +2 -0
  71. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +201 -0
  72. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +48 -0
  73. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +84 -0
  74. package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +174 -0
  75. package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +147 -0
  76. package/dist/repo/shared_libs/play-runtime/suspension.ts +68 -0
  77. package/dist/repo/shared_libs/play-runtime/tool-batch-executor.ts +146 -0
  78. package/dist/repo/shared_libs/play-runtime/tool-result.ts +387 -0
  79. package/dist/repo/shared_libs/play-runtime/tracing.ts +31 -0
  80. package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +75 -0
  81. package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +140 -0
  82. package/dist/repo/shared_libs/plays/artifact-transport.ts +14 -0
  83. package/dist/repo/shared_libs/plays/artifact-types.ts +49 -0
  84. package/dist/repo/shared_libs/plays/bundling/index.ts +1346 -0
  85. package/dist/repo/shared_libs/plays/compiler-manifest.ts +186 -0
  86. package/dist/repo/shared_libs/plays/contracts.ts +51 -0
  87. package/dist/repo/shared_libs/plays/dataset.ts +308 -0
  88. package/dist/repo/shared_libs/plays/definition.ts +264 -0
  89. package/dist/repo/shared_libs/plays/file-refs.ts +11 -0
  90. package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +206 -0
  91. package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +164 -0
  92. package/dist/repo/shared_libs/plays/row-identity.ts +302 -0
  93. package/dist/repo/shared_libs/plays/runtime-validation.ts +415 -0
  94. package/dist/repo/shared_libs/plays/static-pipeline.ts +560 -0
  95. package/dist/repo/shared_libs/temporal/constants.ts +39 -0
  96. package/dist/repo/shared_libs/temporal/preview-config.ts +153 -0
  97. package/package.json +4 -4
@@ -169,7 +169,7 @@ function resolveConfig(options) {
169
169
  }
170
170
 
171
171
  // src/version.ts
172
- var SDK_VERSION = "0.1.0";
172
+ var SDK_VERSION = "0.1.2";
173
173
  var SDK_API_CONTRACT = "2026-04-plays-v1";
174
174
 
175
175
  // ../shared_libs/play-runtime/coordinator-headers.ts
@@ -2466,7 +2466,7 @@ function registerOrgCommands(program) {
2466
2466
  // src/cli/commands/play.ts
2467
2467
  import { createHash as createHash3 } from "crypto";
2468
2468
  import {
2469
- existsSync as existsSync3,
2469
+ existsSync as existsSync4,
2470
2470
  readFileSync as readFileSync3,
2471
2471
  readdirSync,
2472
2472
  realpathSync,
@@ -2479,6 +2479,7 @@ import { Option } from "commander";
2479
2479
  import { tmpdir as tmpdir2 } from "os";
2480
2480
  import { dirname as dirname5, join as join5, resolve as resolve6 } from "path";
2481
2481
  import { fileURLToPath } from "url";
2482
+ import { existsSync as existsSync3 } from "fs";
2482
2483
 
2483
2484
  // ../shared_libs/plays/bundling/index.ts
2484
2485
  import { createHash } from "crypto";
@@ -2583,7 +2584,7 @@ function typecheckPlaySource(input, adapter) {
2583
2584
  ...input.importedPlayDependencies.map((dependency) => dependency.filePath)
2584
2585
  ])
2585
2586
  );
2586
- const sdkTypesPath = adapter.sdkEntryFile;
2587
+ const sdkTypesPath = adapter.sdkTypesEntryFile ?? adapter.sdkEntryFile;
2587
2588
  const program = ts.createProgram(rootNames, {
2588
2589
  target: ts.ScriptTarget.ES2023,
2589
2590
  // SDK source uses fetch/RequestInit/URL and node-aware config helpers.
@@ -3681,24 +3682,24 @@ async function discoverPackagedLocalFiles(entryFile) {
3681
3682
 
3682
3683
  // src/plays/bundle-play-file.ts
3683
3684
  var PLAY_BUNDLE_CACHE_VERSION2 = 24;
3684
- var SDK_SOURCE_ROOT = resolve6(dirname5(fileURLToPath(import.meta.url)), "..");
3685
- var PROJECT_ROOT = resolve6(SDK_SOURCE_ROOT, "..", "..");
3686
- var SDK_PACKAGE_JSON = resolve6(SDK_SOURCE_ROOT, "..", "package.json");
3687
- var SDK_ENTRY_FILE = resolve6(SDK_SOURCE_ROOT, "index.ts");
3688
- var SDK_WORKERS_ENTRY_FILE = resolve6(SDK_SOURCE_ROOT, "worker-play-entry.ts");
3689
- var WORKERS_HARNESS_ENTRY_FILE = resolve6(
3690
- PROJECT_ROOT,
3691
- "apps",
3692
- "play-runner-workers",
3693
- "src",
3694
- "entry.ts"
3685
+ var MODULE_DIR = dirname5(fileURLToPath(import.meta.url));
3686
+ var SDK_PACKAGE_ROOT = resolve6(MODULE_DIR, "..", "..");
3687
+ var SOURCE_REPO_ROOT = resolve6(SDK_PACKAGE_ROOT, "..");
3688
+ var HAS_SOURCE_BUNDLING_SOURCES = existsSync3(
3689
+ resolve6(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
3695
3690
  );
3696
- var WORKERS_HARNESS_FILES_DIR = resolve6(
3697
- PROJECT_ROOT,
3698
- "apps",
3699
- "play-runner-workers",
3700
- "src"
3691
+ var PACKAGED_REPO_ROOT = resolve6(SDK_PACKAGE_ROOT, "dist", "repo");
3692
+ var HAS_PACKAGED_BUNDLING_SOURCES = existsSync3(
3693
+ resolve6(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
3701
3694
  );
3695
+ var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : resolve6(SDK_PACKAGE_ROOT, "..");
3696
+ var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? resolve6(SOURCE_REPO_ROOT, "sdk", "src") : HAS_PACKAGED_BUNDLING_SOURCES ? resolve6(PACKAGED_REPO_ROOT, "sdk", "src") : resolve6(SDK_PACKAGE_ROOT, "src");
3697
+ var SDK_PACKAGE_JSON = resolve6(SDK_PACKAGE_ROOT, "package.json");
3698
+ var SDK_ENTRY_FILE = resolve6(SDK_SOURCE_ROOT, "index.ts");
3699
+ var SDK_TYPES_ENTRY_FILE = resolve6(SDK_PACKAGE_ROOT, "dist", "index.d.ts");
3700
+ var SDK_WORKERS_ENTRY_FILE = resolve6(SDK_SOURCE_ROOT, "worker-play-entry.ts");
3701
+ var WORKERS_HARNESS_ENTRY_FILE = resolve6(PROJECT_ROOT, "apps", "play-runner-workers", "src", "entry.ts");
3702
+ var WORKERS_HARNESS_FILES_DIR = resolve6(PROJECT_ROOT, "apps", "play-runner-workers", "src");
3702
3703
  var hasWarnedAboutNonDevelopmentBundling = false;
3703
3704
  function warnAboutNonDevelopmentBundling(filePath) {
3704
3705
  if (hasWarnedAboutNonDevelopmentBundling) {
@@ -3727,6 +3728,7 @@ function createSdkPlayBundlingAdapter() {
3727
3728
  sdkSourceRoot: SDK_SOURCE_ROOT,
3728
3729
  sdkPackageJson: SDK_PACKAGE_JSON,
3729
3730
  sdkEntryFile: SDK_ENTRY_FILE,
3731
+ sdkTypesEntryFile: existsSync3(SDK_TYPES_ENTRY_FILE) ? SDK_TYPES_ENTRY_FILE : SDK_ENTRY_FILE,
3730
3732
  sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
3731
3733
  workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
3732
3734
  workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
@@ -3871,6 +3873,54 @@ function createCliProgress(enabled) {
3871
3873
  return progress;
3872
3874
  }
3873
3875
 
3876
+ // src/cli/trace.ts
3877
+ var cliTraceStartedAt = Date.now();
3878
+ function isTruthyEnv(value) {
3879
+ return value === "1" || value === "true" || value === "yes";
3880
+ }
3881
+ function isCliTraceEnabled() {
3882
+ return isTruthyEnv(process.env.DEEPLINE_CLI_TRACE);
3883
+ }
3884
+ function recordCliTrace(event) {
3885
+ if (!isCliTraceEnabled()) {
3886
+ return;
3887
+ }
3888
+ const now = Date.now();
3889
+ const payload = {
3890
+ ts: now,
3891
+ source: "cli",
3892
+ sinceStartMs: now - cliTraceStartedAt,
3893
+ ...event
3894
+ };
3895
+ process.stderr.write(`[cli-trace] ${JSON.stringify(payload)}
3896
+ `);
3897
+ }
3898
+ async function traceCliSpan(phase, fields, run) {
3899
+ if (!isCliTraceEnabled()) {
3900
+ return run();
3901
+ }
3902
+ const startedAt = Date.now();
3903
+ try {
3904
+ const result = await run();
3905
+ recordCliTrace({
3906
+ phase,
3907
+ ms: Date.now() - startedAt,
3908
+ ok: true,
3909
+ ...fields
3910
+ });
3911
+ return result;
3912
+ } catch (error) {
3913
+ recordCliTrace({
3914
+ phase,
3915
+ ms: Date.now() - startedAt,
3916
+ ok: false,
3917
+ error: error instanceof Error ? error.message : String(error),
3918
+ ...fields
3919
+ });
3920
+ throw error;
3921
+ }
3922
+ }
3923
+
3874
3924
  // src/cli/commands/play.ts
3875
3925
  function parseReferencedPlayTarget(target) {
3876
3926
  const trimmed = target.trim();
@@ -3926,7 +3976,7 @@ function materializeRemotePlaySource(input) {
3926
3976
  return null;
3927
3977
  }
3928
3978
  const outputPath = input.outPath ?? defaultMaterializedPlayPath(input.playName);
3929
- if (existsSync3(outputPath)) {
3979
+ if (existsSync4(outputPath)) {
3930
3980
  const existingSource = readFileSync3(outputPath, "utf-8");
3931
3981
  if (existingSource === input.sourceCode) {
3932
3982
  return { path: outputPath, status: "unchanged", created: false };
@@ -3977,7 +4027,7 @@ function extractPlayName(code, filePath) {
3977
4027
  throw buildMissingDefinePlayError(filePath);
3978
4028
  }
3979
4029
  function isFileTarget(target) {
3980
- return existsSync3(resolve7(target));
4030
+ return existsSync4(resolve7(target));
3981
4031
  }
3982
4032
  function looksLikeFilePath(target) {
3983
4033
  if (target.trim().toLowerCase().startsWith("prebuilt/")) {
@@ -4294,6 +4344,10 @@ function buildPlayDashboardUrl(baseUrl, playName) {
4294
4344
  const encodedPlayName = encodeURIComponent(playName);
4295
4345
  return `${trimmedBase}/dashboard/plays/${encodedPlayName}`;
4296
4346
  }
4347
+ function getDashboardUrlFromLiveEvent(event) {
4348
+ const dashboardUrl = getEventPayload(event).dashboardUrl;
4349
+ return typeof dashboardUrl === "string" && dashboardUrl.trim() ? dashboardUrl.trim() : null;
4350
+ }
4297
4351
  function printPlayLogLines(input) {
4298
4352
  for (const line of input.lines) {
4299
4353
  if (input.emitLogs) {
@@ -4404,18 +4458,33 @@ async function startAndWaitForPlayCompletionByStream(input) {
4404
4458
  },
4405
4459
  Math.max(1, input.waitTimeoutMs)
4406
4460
  );
4461
+ recordCliTrace({
4462
+ phase: "cli.start_stream_request",
4463
+ playName: input.playName
4464
+ });
4407
4465
  try {
4466
+ let eventCount = 0;
4408
4467
  for await (const event of input.client.startPlayRunStream(input.request, {
4409
4468
  signal: controller.signal
4410
4469
  })) {
4470
+ eventCount += 1;
4471
+ if (eventCount === 1) {
4472
+ recordCliTrace({
4473
+ phase: "cli.start_stream_first_event",
4474
+ ms: Date.now() - startedAt,
4475
+ playName: input.playName,
4476
+ eventType: event.type
4477
+ });
4478
+ }
4411
4479
  const eventRunId = getEventPayload(event).runId;
4412
4480
  if (typeof eventRunId === "string" && eventRunId && eventRunId !== "pending") {
4413
4481
  lastKnownWorkflowId = eventRunId;
4414
4482
  }
4415
4483
  const workflowId = lastKnownWorkflowId || "pending";
4416
4484
  if (workflowId !== "pending" && !emittedDashboardUrl) {
4485
+ const dashboardUrl = getDashboardUrlFromLiveEvent(event) ?? buildPlayDashboardUrl(input.client.baseUrl, input.playName);
4417
4486
  input.progress.phase(
4418
- `loading play on ${buildPlayDashboardUrl(input.client.baseUrl, input.playName)}`
4487
+ `loading play on ${dashboardUrl}`
4419
4488
  );
4420
4489
  emittedDashboardUrl = true;
4421
4490
  }
@@ -4440,6 +4509,14 @@ async function startAndWaitForPlayCompletionByStream(input) {
4440
4509
  });
4441
4510
  const finalStatus = getFinalStatusFromLiveEvent(event);
4442
4511
  if (finalStatus) {
4512
+ recordCliTrace({
4513
+ phase: "cli.start_stream_final_event",
4514
+ ms: Date.now() - startedAt,
4515
+ playName: input.playName,
4516
+ runId: finalStatus.runId,
4517
+ status: finalStatus.status,
4518
+ eventCount
4519
+ });
4443
4520
  return finalStatus;
4444
4521
  }
4445
4522
  }
@@ -5103,12 +5180,34 @@ async function handleFileBackedRun(options) {
5103
5180
  const client = new DeeplineClient();
5104
5181
  const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
5105
5182
  const absolutePlayPath = resolve7(options.target.path);
5183
+ recordCliTrace({
5184
+ phase: "cli.play_run_file_start",
5185
+ playPath: absolutePlayPath,
5186
+ watch: options.watch,
5187
+ hasCsv: Boolean(options.csvPath),
5188
+ force: options.force
5189
+ });
5106
5190
  progress.phase("compiling play");
5191
+ const readSourceStartedAt = Date.now();
5107
5192
  const sourceCode = readFileSync3(absolutePlayPath, "utf-8");
5193
+ recordCliTrace({
5194
+ phase: "cli.read_play_source",
5195
+ ms: Date.now() - readSourceStartedAt,
5196
+ bytes: sourceCode.length,
5197
+ playPath: absolutePlayPath
5198
+ });
5108
5199
  let graph;
5109
5200
  try {
5110
- graph = await collectBundledPlayGraph(absolutePlayPath);
5111
- await compileBundledPlayGraphManifests(client, graph);
5201
+ graph = await traceCliSpan(
5202
+ "cli.bundle_play_graph",
5203
+ { playPath: absolutePlayPath },
5204
+ () => collectBundledPlayGraph(absolutePlayPath)
5205
+ );
5206
+ await traceCliSpan(
5207
+ "cli.compile_play_manifest",
5208
+ { playPath: absolutePlayPath, nodeCount: graph.nodes.size },
5209
+ () => compileBundledPlayGraphManifests(client, graph)
5210
+ );
5112
5211
  progress.phase("compiled play");
5113
5212
  } catch (error) {
5114
5213
  progress.fail();
@@ -5119,17 +5218,32 @@ async function handleFileBackedRun(options) {
5119
5218
  const playName = bundleResult.playName ?? extractPlayName(sourceCode, absolutePlayPath);
5120
5219
  try {
5121
5220
  progress.phase("publishing imported plays");
5122
- await publishImportedPlayDependencies(client, graph);
5221
+ await traceCliSpan(
5222
+ "cli.publish_imported_plays",
5223
+ { playName, nodeCount: graph.nodes.size },
5224
+ () => publishImportedPlayDependencies(client, graph)
5225
+ );
5123
5226
  } catch (error) {
5124
5227
  progress.fail();
5125
5228
  console.error(error instanceof Error ? error.message : String(error));
5126
5229
  return 1;
5127
5230
  }
5128
5231
  const runtimeInput = options.input ? { ...options.input } : {};
5232
+ const prepareFilesStartedAt = Date.now();
5129
5233
  const packagedFileUploads = bundleResult.packagedFiles.map(
5130
5234
  (file) => stageFile(file.logicalPath, file.absolutePath)
5131
5235
  );
5132
5236
  const inputFileUpload = options.csvPath ? stageFile(basename3(options.csvPath), options.csvPath) : packagedFileUploads[0] ?? null;
5237
+ if (options.csvPath && typeof runtimeInput.file !== "string" && typeof runtimeInput.csv !== "string") {
5238
+ runtimeInput.file = basename3(options.csvPath);
5239
+ }
5240
+ recordCliTrace({
5241
+ phase: "cli.prepare_input_files",
5242
+ ms: Date.now() - prepareFilesStartedAt,
5243
+ playName,
5244
+ packagedFileCount: packagedFileUploads.length,
5245
+ hasInputFile: Boolean(inputFileUpload)
5246
+ });
5133
5247
  const startRequest = {
5134
5248
  name: playName,
5135
5249
  sourceCode: bundleResult.sourceCode,
@@ -5142,27 +5256,49 @@ async function handleFileBackedRun(options) {
5142
5256
  };
5143
5257
  if (options.watch) {
5144
5258
  progress.phase("starting run");
5145
- const finalStatus = await startAndWaitForPlayCompletionByStream({
5146
- client,
5147
- request: startRequest,
5259
+ const finalStatus = await traceCliSpan(
5260
+ "cli.start_and_watch",
5261
+ { playName },
5262
+ () => startAndWaitForPlayCompletionByStream({
5263
+ client,
5264
+ request: startRequest,
5265
+ playName,
5266
+ jsonOutput: options.jsonOutput,
5267
+ emitLogs: options.emitLogs,
5268
+ waitTimeoutMs: options.waitTimeoutMs,
5269
+ progress
5270
+ })
5271
+ );
5272
+ const exportStartedAt = Date.now();
5273
+ const exportedPath = exportPlayStatusRows(finalStatus, options.outPath);
5274
+ recordCliTrace({
5275
+ phase: "cli.export_rows",
5276
+ ms: Date.now() - exportStartedAt,
5148
5277
  playName,
5149
- jsonOutput: options.jsonOutput,
5150
- emitLogs: options.emitLogs,
5151
- waitTimeoutMs: options.waitTimeoutMs,
5152
- progress
5278
+ exported: Boolean(exportedPath)
5153
5279
  });
5154
- const exportedPath = exportPlayStatusRows(finalStatus, options.outPath);
5155
5280
  if (finalStatus.status === "completed") {
5156
5281
  progress.complete();
5157
5282
  } else {
5158
5283
  progress.fail();
5159
5284
  }
5285
+ recordCliTrace({
5286
+ phase: "cli.write_play_result",
5287
+ playName,
5288
+ status: finalStatus.status,
5289
+ runId: finalStatus.runId
5290
+ });
5160
5291
  writePlayResult(finalStatus, options.jsonOutput, { exportedPath });
5161
5292
  return finalStatus.status === "completed" ? 0 : 1;
5162
5293
  }
5163
5294
  progress.phase("starting run");
5164
- const started = await client.startPlayRun(startRequest);
5165
- const dashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
5295
+ const started = await traceCliSpan(
5296
+ "cli.start_run",
5297
+ { playName },
5298
+ () => client.startPlayRun(startRequest)
5299
+ );
5300
+ const fallbackDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
5301
+ const dashboardUrl = started.dashboardUrl ?? fallbackDashboardUrl;
5166
5302
  progress.phase(`loading play on ${dashboardUrl}`);
5167
5303
  progress.complete();
5168
5304
  writeStartedPlayRun({
@@ -5170,7 +5306,7 @@ async function handleFileBackedRun(options) {
5170
5306
  playName,
5171
5307
  status: started.status,
5172
5308
  statusUrl: started.statusUrl,
5173
- dashboardUrl: started.dashboardUrl ?? dashboardUrl,
5309
+ dashboardUrl,
5174
5310
  jsonOutput: options.jsonOutput
5175
5311
  });
5176
5312
  return 0;
@@ -5242,10 +5378,11 @@ async function handleNamedRun(options) {
5242
5378
  }
5243
5379
  progress.phase("starting run");
5244
5380
  const started = await client.startPlayRun(startRequest);
5245
- const dashboardUrl = buildPlayDashboardUrl(
5381
+ const fallbackDashboardUrl = buildPlayDashboardUrl(
5246
5382
  client.baseUrl,
5247
5383
  options.target.name
5248
5384
  );
5385
+ const dashboardUrl = started.dashboardUrl ?? fallbackDashboardUrl;
5249
5386
  progress.phase(`loading play on ${dashboardUrl}`);
5250
5387
  progress.complete();
5251
5388
  writeStartedPlayRun({
@@ -5253,7 +5390,7 @@ async function handleNamedRun(options) {
5253
5390
  playName: started.name ?? options.target.name,
5254
5391
  status: started.status,
5255
5392
  statusUrl: started.statusUrl,
5256
- dashboardUrl: started.dashboardUrl ?? dashboardUrl,
5393
+ dashboardUrl,
5257
5394
  jsonOutput: options.jsonOutput
5258
5395
  });
5259
5396
  return 0;
@@ -5267,7 +5404,7 @@ async function handlePlayRun(args) {
5267
5404
  const resolved = resolve7(options.target.path);
5268
5405
  console.error(`File not found: ${resolved}`);
5269
5406
  const dir = dirname6(resolved);
5270
- if (existsSync3(dir)) {
5407
+ if (existsSync4(dir)) {
5271
5408
  const base = basename3(resolved);
5272
5409
  try {
5273
5410
  const siblings = readdirSync(dir).filter(
@@ -6742,6 +6879,11 @@ function shouldPrintStartupPhase() {
6742
6879
  return (command === "play" || command === "plays") && subcommand === "run";
6743
6880
  }
6744
6881
  async function main() {
6882
+ const mainStartedAt = Date.now();
6883
+ recordCliTrace({
6884
+ phase: "cli.main_start",
6885
+ argv: process.argv.slice(2)
6886
+ });
6745
6887
  const printStartupPhase = shouldPrintStartupPhase();
6746
6888
  const progress = printStartupPhase ? createCliProgress(true) : null;
6747
6889
  if (printStartupPhase) {
@@ -6771,7 +6913,12 @@ Output:
6771
6913
  if (printStartupPhase) {
6772
6914
  progress?.phase("checking sdk compatibility");
6773
6915
  }
6774
- await enforceSdkCompatibility(autoDetectBaseUrl().replace(/\/$/, ""));
6916
+ const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
6917
+ await traceCliSpan(
6918
+ "cli.sdk_compatibility",
6919
+ { baseUrl },
6920
+ () => enforceSdkCompatibility(baseUrl)
6921
+ );
6775
6922
  });
6776
6923
  registerAuthCommands(program);
6777
6924
  registerToolsCommands(program);
@@ -6799,7 +6946,18 @@ Output:
6799
6946
  });
6800
6947
  try {
6801
6948
  await program.parseAsync(process.argv);
6949
+ recordCliTrace({
6950
+ phase: "cli.main_total",
6951
+ ms: Date.now() - mainStartedAt,
6952
+ ok: true
6953
+ });
6802
6954
  } catch (error) {
6955
+ recordCliTrace({
6956
+ phase: "cli.main_total",
6957
+ ms: Date.now() - mainStartedAt,
6958
+ ok: false,
6959
+ error: error instanceof Error ? error.message : String(error)
6960
+ });
6803
6961
  if (process.argv.includes("--json")) {
6804
6962
  printJsonError(error);
6805
6963
  } else if (error instanceof Error) {