deepline 0.1.83 → 0.1.88

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.
@@ -206,10 +206,10 @@ import { join as join2 } from "path";
206
206
 
207
207
  // src/release.ts
208
208
  var SDK_RELEASE = {
209
- version: "0.1.83",
209
+ version: "0.1.88",
210
210
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
211
211
  supportPolicy: {
212
- latest: "0.1.83",
212
+ latest: "0.1.88",
213
213
  minimumSupported: "0.1.53",
214
214
  deprecatedBelow: "0.1.53"
215
215
  }
@@ -223,6 +223,7 @@ var SDK_API_CONTRACT = SDK_RELEASE.apiContract;
223
223
  var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
224
224
  var COORDINATOR_URL_OVERRIDE_HEADER = "x-deepline-coordinator-url";
225
225
  var WORKER_CALLBACK_URL_OVERRIDE_HEADER = "x-deepline-worker-callback-url";
226
+ var SYNTHETIC_RUN_HEADER = "x-deepline-synthetic-run";
226
227
 
227
228
  // src/http.ts
228
229
  var MAX_DIAGNOSTIC_HEADER_LENGTH = 120;
@@ -290,6 +291,10 @@ var HttpClient = class {
290
291
  if (workerCallbackUrl?.trim()) {
291
292
  headers[WORKER_CALLBACK_URL_OVERRIDE_HEADER] = workerCallbackUrl.trim();
292
293
  }
294
+ const syntheticRun = typeof process !== "undefined" ? process.env?.DEEPLINE_SYNTHETIC_RUN : void 0;
295
+ if (syntheticRun && syntheticRun.trim() && syntheticRun.trim() !== "0") {
296
+ headers[SYNTHETIC_RUN_HEADER] = "1";
297
+ }
293
298
  return headers;
294
299
  }
295
300
  /**
@@ -556,7 +561,7 @@ function decodeSseFrame(frame) {
556
561
  return parsed;
557
562
  }
558
563
  function sleep(ms) {
559
- return new Promise((resolve13) => setTimeout(resolve13, ms));
564
+ return new Promise((resolve14) => setTimeout(resolve14, ms));
560
565
  }
561
566
 
562
567
  // src/client.ts
@@ -566,7 +571,7 @@ var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
566
571
  var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
567
572
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
568
573
  function sleep2(ms) {
569
- return new Promise((resolve13) => setTimeout(resolve13, ms));
574
+ return new Promise((resolve14) => setTimeout(resolve14, ms));
570
575
  }
571
576
  function isTransientCompileManifestError(error) {
572
577
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -580,6 +585,21 @@ function isTransientCompileManifestError(error) {
580
585
  function isRecord(value) {
581
586
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
582
587
  }
588
+ function isPrebuiltPlayDescription(play) {
589
+ return play.origin === "prebuilt" || play.ownerType === "deepline";
590
+ }
591
+ function preferPrebuiltPlayDescriptions(plays) {
592
+ const prebuilt = [];
593
+ const owned = [];
594
+ for (const play of plays) {
595
+ if (isPrebuiltPlayDescription(play)) {
596
+ prebuilt.push(play);
597
+ } else {
598
+ owned.push(play);
599
+ }
600
+ }
601
+ return [...prebuilt, ...owned];
602
+ }
583
603
  function isPlayRunPackage(value) {
584
604
  return Boolean(
585
605
  value && typeof value === "object" && !Array.isArray(value) && value.kind === "play_run" && value.run && typeof value.run?.id === "string"
@@ -703,8 +723,14 @@ function playRunStatusFromState(state) {
703
723
  var DeeplineClient = class {
704
724
  http;
705
725
  config;
726
+ /** Canonical run lifecycle namespace backed by `/api/v2/runs`. */
706
727
  runs;
707
728
  /**
729
+ * Create a low-level SDK client.
730
+ *
731
+ * Most callers can omit options and let the SDK resolve auth/config from
732
+ * environment variables and CLI-managed credentials.
733
+ *
708
734
  * @param options - Optional overrides for API key, base URL, timeout, and retries.
709
735
  * @throws {@link ConfigError} if no API key can be resolved from any source.
710
736
  */
@@ -806,12 +832,19 @@ var DeeplineClient = class {
806
832
  // ——————————————————————————————————————————————————————————
807
833
  // Secrets
808
834
  // ——————————————————————————————————————————————————————————
835
+ /** List secret metadata visible to the current workspace. */
809
836
  async listSecrets() {
810
837
  const response = await this.http.get(
811
838
  "/api/v2/secrets"
812
839
  );
813
840
  return Array.isArray(response.secrets) ? response.secrets : [];
814
841
  }
842
+ /**
843
+ * Check whether a named secret exists, is active, and has a stored value.
844
+ *
845
+ * @param name - Secret name. It is normalized to uppercase before lookup.
846
+ * @returns Matching active secret metadata, or `null`.
847
+ */
815
848
  async checkSecret(name) {
816
849
  const normalized = name.trim().toUpperCase();
817
850
  const secrets = await this.listSecrets();
@@ -924,9 +957,21 @@ var DeeplineClient = class {
924
957
  headers
925
958
  );
926
959
  }
960
+ /**
961
+ * Back-compatible alias for {@link executeTool}.
962
+ *
963
+ * Retained for callers that still use the older raw naming while the response
964
+ * envelope remains the same.
965
+ */
927
966
  async executeToolRaw(toolId, input2, options) {
928
967
  return this.executeTool(toolId, input2, options);
929
968
  }
969
+ /**
970
+ * Run a bounded SQL query against the customer data plane.
971
+ *
972
+ * Use this from trusted backend or agent contexts only. The API enforces
973
+ * workspace scoping and row limits.
974
+ */
930
975
  async queryCustomerDb(input2) {
931
976
  return this.http.post("/api/v2/db/query", {
932
977
  sql: input2.sql,
@@ -998,6 +1043,17 @@ var DeeplineClient = class {
998
1043
  );
999
1044
  return normalizePlayRunStart(response);
1000
1045
  }
1046
+ /**
1047
+ * Start a play run and stream live runtime events from the same request.
1048
+ *
1049
+ * Use this when a caller wants low-level event handling instead of submitting
1050
+ * first and then connecting to `streamPlayRunEvents(runId)`.
1051
+ *
1052
+ * @param request - Play run configuration.
1053
+ * @param options - Optional streaming options.
1054
+ * @param options.signal - Optional abort signal for the streaming request.
1055
+ * @returns Async stream of play-scoped live events.
1056
+ */
1001
1057
  async *startPlayRunStream(request, options) {
1002
1058
  const body = {
1003
1059
  ...request.name ? { name: request.name } : {},
@@ -1050,6 +1106,12 @@ var DeeplineClient = class {
1050
1106
  compilerManifest
1051
1107
  });
1052
1108
  }
1109
+ /**
1110
+ * Register multiple bundled play artifacts in one request.
1111
+ *
1112
+ * Used by packaging and prebuilt publication flows. Each artifact is compiled
1113
+ * first when a compiler manifest is not already supplied.
1114
+ */
1053
1115
  async registerPlayArtifacts(artifacts) {
1054
1116
  const compiledArtifacts = await Promise.all(
1055
1117
  artifacts.map(async (artifact) => ({
@@ -1066,6 +1128,13 @@ var DeeplineClient = class {
1066
1128
  artifacts: compiledArtifacts
1067
1129
  });
1068
1130
  }
1131
+ /**
1132
+ * Compile a bundled play artifact into the server-side compiler manifest.
1133
+ *
1134
+ * The manifest records imports, trigger bindings, static pipeline shape, and
1135
+ * runtime metadata needed before a play artifact can be checked, registered,
1136
+ * or run.
1137
+ */
1069
1138
  async compilePlayManifest(input2) {
1070
1139
  const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
1071
1140
  0,
@@ -1094,9 +1163,21 @@ var DeeplineClient = class {
1094
1163
  async checkPlayArtifact(input2) {
1095
1164
  return this.http.post("/api/v2/plays/check", input2);
1096
1165
  }
1166
+ /**
1167
+ * Compile legacy enrich command arguments into a runtime plan.
1168
+ *
1169
+ * This is primarily used by CLI compatibility paths that translate older
1170
+ * enrichment commands onto the play runtime.
1171
+ */
1097
1172
  async compileEnrichPlan(input2) {
1098
1173
  return this.http.post("/api/v2/enrich/compile", input2);
1099
1174
  }
1175
+ /**
1176
+ * Register an already-bundled play artifact and start a run from it.
1177
+ *
1178
+ * This is the low-level file-backed run path used by SDK/CLI packaging
1179
+ * wrappers after local bundling has produced the runtime artifact.
1180
+ */
1100
1181
  async startPlayRunFromBundle(input2) {
1101
1182
  const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
1102
1183
  name: input2.name,
@@ -1254,6 +1335,12 @@ var DeeplineClient = class {
1254
1335
  const response = await this.http.postFormData("/api/v2/plays/files/stage", buildFormData);
1255
1336
  return response.files;
1256
1337
  }
1338
+ /**
1339
+ * Resolve staged play files by content hash without uploading bytes.
1340
+ *
1341
+ * Missing files are returned so callers can upload only the files the server
1342
+ * does not already have.
1343
+ */
1257
1344
  async resolveStagedPlayFiles(files) {
1258
1345
  return this.http.post("/api/v2/plays/files/stage", { files });
1259
1346
  }
@@ -1470,6 +1557,12 @@ var DeeplineClient = class {
1470
1557
  entries
1471
1558
  };
1472
1559
  }
1560
+ /**
1561
+ * Export persisted runtime-sheet rows for a play dataset/table namespace.
1562
+ *
1563
+ * This is the SDK form of exporting `ctx.dataset(...).run()` output for a
1564
+ * specific play and optional run id.
1565
+ */
1473
1566
  async getPlaySheetRows(input2) {
1474
1567
  const params = new URLSearchParams({
1475
1568
  tableNamespace: input2.tableNamespace,
@@ -1498,6 +1591,12 @@ var DeeplineClient = class {
1498
1591
  options?.reason ? { reason: options.reason } : {}
1499
1592
  );
1500
1593
  }
1594
+ /**
1595
+ * List callable plays visible to the workspace.
1596
+ *
1597
+ * Pass `origin: "prebuilt"` for Deepline-managed prebuilts or
1598
+ * `origin: "owned"` for org-owned plays.
1599
+ */
1501
1600
  async listPlays(options) {
1502
1601
  const params = new URLSearchParams();
1503
1602
  if (options?.origin) params.set("origin", options.origin);
@@ -1512,15 +1611,32 @@ var DeeplineClient = class {
1512
1611
  );
1513
1612
  return response.plays ?? [];
1514
1613
  }
1614
+ /**
1615
+ * Search callable plays and return compact play descriptions.
1616
+ *
1617
+ * Prebuilt plays are preferred by default because they have maintained
1618
+ * contracts and stable run behavior.
1619
+ */
1515
1620
  async searchPlays(options) {
1516
1621
  const params = new URLSearchParams();
1517
1622
  params.set("search", options.query.trim());
1623
+ const scope = options.scope ?? "prebuilt";
1624
+ if (scope !== "all") {
1625
+ params.set("origin", scope);
1626
+ }
1518
1627
  const response = await this.http.get(
1519
1628
  `/api/v2/plays?${params.toString()}`
1520
1629
  );
1521
- return (response.plays ?? []).map(
1630
+ const plays = (response.plays ?? []).map(
1522
1631
  (play) => this.summarizePlayListItem(play, options)
1523
1632
  );
1633
+ if (scope === "prebuilt") {
1634
+ return plays.filter(isPrebuiltPlayDescription);
1635
+ }
1636
+ if (scope === "owned") {
1637
+ return plays.filter((play) => !isPrebuiltPlayDescription(play));
1638
+ }
1639
+ return preferPrebuiltPlayDescriptions(plays);
1524
1640
  }
1525
1641
  /**
1526
1642
  * Get the full definition and state of a named play.
@@ -1543,6 +1659,12 @@ var DeeplineClient = class {
1543
1659
  const encodedName = encodeURIComponent(name);
1544
1660
  return this.http.get(`/api/v2/plays/${encodedName}`);
1545
1661
  }
1662
+ /**
1663
+ * Get a normalized play description suitable for agents and CLIs.
1664
+ *
1665
+ * The description includes runnable examples, input/output summaries, clone
1666
+ * guidance, revision state, and latest run metadata when available.
1667
+ */
1546
1668
  async describePlay(name, options) {
1547
1669
  const detail = await this.getPlay(name);
1548
1670
  return this.summarizePlayDetail(detail, options);
@@ -2125,6 +2247,9 @@ function readCsvRows(csvPath) {
2125
2247
  function csvStringFromRows(rows, columns) {
2126
2248
  return stringify(rows, {
2127
2249
  header: true,
2250
+ cast: {
2251
+ boolean: (value) => value ? "true" : "false"
2252
+ },
2128
2253
  ...columns?.length ? { columns } : {}
2129
2254
  });
2130
2255
  }
@@ -2406,7 +2531,7 @@ function buildCandidateUrls2(url) {
2406
2531
  }
2407
2532
  }
2408
2533
  function sleep3(ms) {
2409
- return new Promise((resolve13) => setTimeout(resolve13, ms));
2534
+ return new Promise((resolve14) => setTimeout(resolve14, ms));
2410
2535
  }
2411
2536
  function printDeeplineLogo() {
2412
2537
  if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
@@ -4674,7 +4799,12 @@ function readPackageVersionFromPackageJson(packageJsonPath, packageName) {
4674
4799
  return null;
4675
4800
  }
4676
4801
  function findPackageJsonPathFrom(startDir, packageName) {
4677
- let current = resolve6(startDir);
4802
+ if (!isAbsolute(startDir)) {
4803
+ throw new Error(
4804
+ `Package resolution requires an absolute start directory, got ${startDir}`
4805
+ );
4806
+ }
4807
+ let current = startDir;
4678
4808
  while (true) {
4679
4809
  const packageJsonPath = join4(
4680
4810
  current,
@@ -4694,17 +4824,15 @@ function findPackageJsonPathFrom(startDir, packageName) {
4694
4824
  }
4695
4825
  function findPackageJsonPath(packageName, fromFile, adapter) {
4696
4826
  const startDirs = [
4697
- dirname5(fromFile),
4698
- adapter.projectRoot,
4699
- dirname5(adapter.sdkPackageJson),
4700
- process.cwd()
4827
+ resolve6(dirname5(fromFile)),
4828
+ resolve6(adapter.projectRoot),
4829
+ resolve6(dirname5(adapter.sdkPackageJson))
4701
4830
  ];
4702
4831
  const seen = /* @__PURE__ */ new Set();
4703
4832
  for (const startDir of startDirs) {
4704
- const normalized = resolve6(startDir);
4705
- if (seen.has(normalized)) continue;
4706
- seen.add(normalized);
4707
- const packageJsonPath = findPackageJsonPathFrom(normalized, packageName);
4833
+ if (seen.has(startDir)) continue;
4834
+ seen.add(startDir);
4835
+ const packageJsonPath = findPackageJsonPathFrom(startDir, packageName);
4708
4836
  if (packageJsonPath) return packageJsonPath;
4709
4837
  }
4710
4838
  const adapterNodeModulesPackageJson = join4(
@@ -5162,13 +5290,13 @@ async function writeArtifactCache(artifact, adapter) {
5162
5290
  "utf-8"
5163
5291
  );
5164
5292
  }
5165
- function normalizeSourceMapForRuntime(sourceMapText) {
5293
+ function normalizeSourceMapForRuntime(sourceMapText, projectRoot) {
5166
5294
  const parsed = JSON.parse(sourceMapText);
5167
5295
  parsed.sources = (parsed.sources ?? []).map((sourcePath) => {
5168
5296
  if (sourcePath.startsWith("data:") || sourcePath.startsWith("node:") || sourcePath.startsWith("/") || /^[a-zA-Z]+:\/\//.test(sourcePath)) {
5169
5297
  return sourcePath;
5170
5298
  }
5171
- return resolve6(process.cwd(), sourcePath);
5299
+ return join4(projectRoot, sourcePath);
5172
5300
  });
5173
5301
  parsed.sourceRoot = void 0;
5174
5302
  return JSON.stringify(parsed);
@@ -5434,7 +5562,10 @@ workers-harness:${harnessFingerprint}`
5434
5562
  };
5435
5563
  }
5436
5564
  const { bundledCode, sourceMapText, outputExtension } = buildOutcome;
5437
- const normalizedSourceMap = normalizeSourceMapForRuntime(sourceMapText);
5565
+ const normalizedSourceMap = normalizeSourceMapForRuntime(
5566
+ sourceMapText,
5567
+ resolve6(adapter.projectRoot)
5568
+ );
5438
5569
  const virtualBaseName = exportName === "default" ? basename(absolutePath).replace(/\.[^.]+$/, "") : `${basename(absolutePath).replace(/\.[^.]+$/, "")}.${exportName}`;
5439
5570
  const virtualFilename = `/virtual/deepline-plays/${analysis.graphHash}/${virtualBaseName}.${outputExtension}`;
5440
5571
  const executableCode = `${bundledCode}
@@ -5508,12 +5639,16 @@ var PLAY_DEDUP_BACKENDS = {
5508
5639
  var PLAY_SCHEDULER_BACKENDS = {
5509
5640
  temporal: "temporal",
5510
5641
  cfWorkflows: "cf-workflows",
5642
+ postgres: "postgres",
5511
5643
  inProcess: "in-process"
5512
5644
  };
5513
5645
 
5514
5646
  // ../shared_libs/play-runtime/providers.ts
5515
5647
  var PLAY_RUNTIME_PROVIDER_IDS = {
5516
5648
  workersEdge: "workers_edge",
5649
+ postgresFast: "postgres_fast",
5650
+ postgresFastSandbox: "postgres_fast_sandbox",
5651
+ postgresFastWorkers: "postgres_fast_workers",
5517
5652
  local: "local"
5518
5653
  };
5519
5654
  var PLAY_RUNTIME_PROVIDERS = {
@@ -5525,6 +5660,30 @@ var PLAY_RUNTIME_PROVIDERS = {
5525
5660
  artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
5526
5661
  label: "Cloudflare Dynamic Workflows + Dynamic Workers + DO dedup"
5527
5662
  },
5663
+ postgres_fast: {
5664
+ id: PLAY_RUNTIME_PROVIDER_IDS.postgresFast,
5665
+ scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
5666
+ runner: PLAY_RUNTIME_BACKENDS.daytona,
5667
+ dedup: PLAY_DEDUP_BACKENDS.durableObject,
5668
+ artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
5669
+ label: "Experimental Postgres Scheduler + warm sandbox runner + DO dedup"
5670
+ },
5671
+ postgres_fast_sandbox: {
5672
+ id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastSandbox,
5673
+ scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
5674
+ runner: PLAY_RUNTIME_BACKENDS.daytona,
5675
+ dedup: PLAY_DEDUP_BACKENDS.durableObject,
5676
+ artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
5677
+ label: "Experimental Postgres Scheduler + warm sandbox runner + DO dedup"
5678
+ },
5679
+ postgres_fast_workers: {
5680
+ id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastWorkers,
5681
+ scheduler: PLAY_SCHEDULER_BACKENDS.postgres,
5682
+ runner: PLAY_RUNTIME_BACKENDS.cloudflareWorkers,
5683
+ dedup: PLAY_DEDUP_BACKENDS.durableObject,
5684
+ artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
5685
+ label: "Experimental Postgres Scheduler + Queue/DO-woken Workers + DO dedup"
5686
+ },
5528
5687
  local: {
5529
5688
  id: PLAY_RUNTIME_PROVIDER_IDS.local,
5530
5689
  scheduler: PLAY_SCHEDULER_BACKENDS.temporal,
@@ -7814,7 +7973,7 @@ function traceCliSync(phase, fields, run) {
7814
7973
  }
7815
7974
  }
7816
7975
  function sleep4(ms) {
7817
- return new Promise((resolve13) => setTimeout(resolve13, ms));
7976
+ return new Promise((resolve14) => setTimeout(resolve14, ms));
7818
7977
  }
7819
7978
  function parseReferencedPlayTarget2(target) {
7820
7979
  const trimmed = target.trim();
@@ -8152,9 +8311,10 @@ function formatUnresolvedPackagedFiles(filePath, unresolvedFileReferences) {
8152
8311
  const details = unresolvedFileReferences.map((unresolved) => `${unresolved.sourceFragment}: ${unresolved.message}`).join("; ");
8153
8312
  return `Failed to package local ctx.csv(...) files in ${filePath}: ${details}`;
8154
8313
  }
8155
- async function collectBundledPlayGraph(entryFile) {
8314
+ async function collectBundledPlayGraph(entryFile, profile = null) {
8156
8315
  const nodes = /* @__PURE__ */ new Map();
8157
8316
  const visiting = /* @__PURE__ */ new Set();
8317
+ const artifactKind = resolveExecutionProfile(profile).artifactKind;
8158
8318
  const visit = async (filePath) => {
8159
8319
  const absolutePath = normalizePlayPath(filePath);
8160
8320
  const cached = nodes.get(absolutePath);
@@ -8169,7 +8329,7 @@ async function collectBundledPlayGraph(entryFile) {
8169
8329
  visiting.add(absolutePath);
8170
8330
  try {
8171
8331
  const bundleResult = await bundlePlayFile2(absolutePath, {
8172
- target: "esm_workers"
8332
+ target: artifactKind
8173
8333
  });
8174
8334
  if (bundleResult.success === false) {
8175
8335
  throw new Error(
@@ -8284,7 +8444,8 @@ function formatTimestamp(value) {
8284
8444
  return date.toISOString();
8285
8445
  }
8286
8446
  function formatRunLine(run) {
8287
- return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)}`;
8447
+ const credits = typeof run.billingTotalCredits === "number" && Number.isFinite(run.billingTotalCredits) ? `${formatCreditAmount(run.billingTotalCredits)} credits` : "\u2014";
8448
+ return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)} ${credits}`;
8288
8449
  }
8289
8450
  function isTransientPlayStreamError(error) {
8290
8451
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -8331,6 +8492,8 @@ var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
8331
8492
  "cancelled"
8332
8493
  ]);
8333
8494
  var PLAY_START_TRANSIENT_RETRY_DELAYS_MS = [500, 1500];
8495
+ var PLAY_PROGRESS_HEARTBEAT_INTERVAL_MS = 15e3;
8496
+ var PLAY_STATUS_HEARTBEAT_INTERVAL_MS = 15e3;
8334
8497
  function getEventPayload(event) {
8335
8498
  return event.payload && typeof event.payload === "object" ? event.payload : {};
8336
8499
  }
@@ -8391,6 +8554,7 @@ function extractTableNamespaceFromLiveEvent(event) {
8391
8554
  const payload = getEventPayload(event);
8392
8555
  const candidates = [
8393
8556
  payload.artifactTableNamespace,
8557
+ payload.activeArtifactTableNamespace,
8394
8558
  payload.tableNamespace,
8395
8559
  payload.mapNodeId
8396
8560
  ];
@@ -8469,6 +8633,20 @@ function formatProgressCounts(input2) {
8469
8633
  const failed = typeof input2.failed === "number" && Number.isFinite(input2.failed) && input2.failed > 0 ? `, failed ${formatInteger(input2.failed)}` : "";
8470
8634
  return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
8471
8635
  }
8636
+ function formatProgressMessageSuffix(input2) {
8637
+ const message = typeof input2.message === "string" ? input2.message.trim() : "";
8638
+ if (!message) {
8639
+ return "";
8640
+ }
8641
+ const completed = typeof input2.completed === "number" && Number.isFinite(input2.completed) ? input2.completed : null;
8642
+ if (/^[\d,]+\s*\/\s*[\d,]+\s+rows processed$/i.test(message)) {
8643
+ return "";
8644
+ }
8645
+ if (completed !== null && completed > 0 && /rows?\s+queued\b/i.test(message)) {
8646
+ return "";
8647
+ }
8648
+ return ` - ${message}`;
8649
+ }
8472
8650
  function getProgressLinesFromLiveEvent(event) {
8473
8651
  const payload = getEventPayload(event);
8474
8652
  if (event.type === "play.step.progress") {
@@ -8478,7 +8656,13 @@ function getProgressLinesFromLiveEvent(event) {
8478
8656
  failed: payload.failed
8479
8657
  });
8480
8658
  if (!counts) return [];
8481
- return [`progress ${formatProgressLabel(payload.stepId)}: ${counts}`];
8659
+ const messageSuffix = formatProgressMessageSuffix({
8660
+ message: payload.message,
8661
+ completed: payload.completed
8662
+ });
8663
+ return [
8664
+ `progress ${formatProgressLabel(payload.stepId)}: ${counts}${messageSuffix}`
8665
+ ];
8482
8666
  }
8483
8667
  if (event.type !== "play.run.snapshot" && event.type !== "play.run.final_status") {
8484
8668
  return [];
@@ -8502,22 +8686,69 @@ function getProgressLinesFromLiveEvent(event) {
8502
8686
  if (!counts) {
8503
8687
  continue;
8504
8688
  }
8689
+ const messageSuffix = formatProgressMessageSuffix({
8690
+ message: progress.message,
8691
+ completed: progress.completed
8692
+ });
8505
8693
  lines.push(
8506
- `progress ${formatProgressLabel(record.nodeId ?? progress.artifactTableNamespace)}: ${counts}`
8694
+ `progress ${formatProgressLabel(record.nodeId ?? progress.artifactTableNamespace)}: ${counts}${messageSuffix}`
8507
8695
  );
8508
8696
  }
8509
8697
  return lines;
8510
8698
  }
8699
+ function shouldPrintPlayProgressLine(input2) {
8700
+ if (!input2.signature) {
8701
+ return false;
8702
+ }
8703
+ return input2.lastProgressSignature !== input2.signature || input2.nowMs - input2.lastProgressHeartbeatAt >= PLAY_PROGRESS_HEARTBEAT_INTERVAL_MS;
8704
+ }
8511
8705
  function printPlayProgressLines(input2) {
8512
8706
  for (const line of input2.lines) {
8513
8707
  const signature = line.trim();
8514
- if (!signature || input2.state.lastProgressSignature === signature) {
8708
+ const now = Date.now();
8709
+ if (!shouldPrintPlayProgressLine({
8710
+ signature,
8711
+ lastProgressSignature: input2.state.lastProgressSignature,
8712
+ lastProgressHeartbeatAt: input2.state.lastProgressHeartbeatAt,
8713
+ nowMs: now
8714
+ })) {
8515
8715
  continue;
8516
8716
  }
8517
8717
  input2.state.lastProgressSignature = signature;
8718
+ input2.state.lastProgressHeartbeatAt = now;
8518
8719
  input2.progress.writeLine(line);
8519
8720
  }
8520
8721
  }
8722
+ function getRunningHeartbeatLine(input2) {
8723
+ const status = getStatusFromLiveEvent(input2.event);
8724
+ if (status !== "queued" && status !== "running" && status !== "waiting") {
8725
+ return null;
8726
+ }
8727
+ const tableNamespace = extractTableNamespaceFromLiveEvent(input2.event);
8728
+ const target = tableNamespace ? formatProgressLabel(tableNamespace) : input2.playName;
8729
+ if (status === "queued") {
8730
+ return `queued ${target}: waiting for worker capacity`;
8731
+ }
8732
+ if (status === "waiting") {
8733
+ return `waiting ${target}: waiting on external work`;
8734
+ }
8735
+ return `running ${target}: still processing`;
8736
+ }
8737
+ function printPlayStatusHeartbeat(input2) {
8738
+ const now = Date.now();
8739
+ if (now - input2.state.lastStatusHeartbeatAt < PLAY_STATUS_HEARTBEAT_INTERVAL_MS) {
8740
+ return;
8741
+ }
8742
+ const line = getRunningHeartbeatLine({
8743
+ event: input2.event,
8744
+ playName: input2.playName
8745
+ });
8746
+ if (!line) {
8747
+ return;
8748
+ }
8749
+ input2.state.lastStatusHeartbeatAt = now;
8750
+ input2.progress.writeLine(line);
8751
+ }
8521
8752
  function buildPlayDashboardUrl(baseUrl, playName) {
8522
8753
  const trimmedBase = baseUrl.replace(/\/$/, "");
8523
8754
  const encodedPlayName = encodeURIComponent(playName);
@@ -8600,11 +8831,20 @@ async function waitForPlayCompletionByStream(input2) {
8600
8831
  progress: input2.progress
8601
8832
  });
8602
8833
  if (!input2.jsonOutput) {
8834
+ const progressLines = getProgressLinesFromLiveEvent(event);
8603
8835
  printPlayProgressLines({
8604
- lines: getProgressLinesFromLiveEvent(event),
8836
+ lines: progressLines,
8605
8837
  state: input2.state,
8606
8838
  progress: input2.progress
8607
8839
  });
8840
+ if (progressLines.length === 0) {
8841
+ printPlayStatusHeartbeat({
8842
+ event,
8843
+ playName: input2.playName,
8844
+ state: input2.state,
8845
+ progress: input2.progress
8846
+ });
8847
+ }
8608
8848
  }
8609
8849
  const finalStatus = getFinalStatusFromLiveEvent(event);
8610
8850
  if (finalStatus) {
@@ -8682,7 +8922,9 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
8682
8922
  const state = {
8683
8923
  lastLogIndex: 0,
8684
8924
  emittedRunnerStarted: false,
8685
- lastProgressSignature: null
8925
+ lastProgressSignature: null,
8926
+ lastProgressHeartbeatAt: 0,
8927
+ lastStatusHeartbeatAt: 0
8686
8928
  };
8687
8929
  const controller = new AbortController();
8688
8930
  let timedOut = false;
@@ -8723,7 +8965,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
8723
8965
  dashboardUrl,
8724
8966
  noOpen: input2.noOpen
8725
8967
  });
8726
- input2.progress.phase(`loading play on ${dashboardUrl}`);
8968
+ input2.progress.phase("running");
8727
8969
  emittedDashboardUrl = true;
8728
8970
  }
8729
8971
  assertPlayWaitNotTimedOut({
@@ -8754,11 +8996,20 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
8754
8996
  progress: input2.progress
8755
8997
  });
8756
8998
  if (!input2.jsonOutput) {
8999
+ const progressLines = getProgressLinesFromLiveEvent(event);
8757
9000
  printPlayProgressLines({
8758
- lines: getProgressLinesFromLiveEvent(event),
9001
+ lines: progressLines,
8759
9002
  state,
8760
9003
  progress: input2.progress
8761
9004
  });
9005
+ if (progressLines.length === 0) {
9006
+ printPlayStatusHeartbeat({
9007
+ event,
9008
+ playName: input2.playName,
9009
+ state,
9010
+ progress: input2.progress
9011
+ });
9012
+ }
8762
9013
  }
8763
9014
  const finalStatus = getFinalStatusFromLiveEvent(event);
8764
9015
  if (finalStatus) {
@@ -9358,6 +9609,17 @@ function getPlayRunPackage(status) {
9358
9609
  const packaged = status.package;
9359
9610
  return isPlayRunPackageValue(packaged) ? packaged : null;
9360
9611
  }
9612
+ function withTerminalPlayIdentity(status, playName) {
9613
+ if (!playName.trim() || getPlayRunPackage(status)) {
9614
+ return status;
9615
+ }
9616
+ const record = status;
9617
+ const hasIdentity = typeof record.playName === "string" && record.playName.trim().length > 0 || typeof record.name === "string" && record.name.trim().length > 0 || Boolean(getStringField(record.run, "playName"));
9618
+ if (hasIdentity) {
9619
+ return status;
9620
+ }
9621
+ return { ...status, playName };
9622
+ }
9361
9623
  function compactPlayStatus(status) {
9362
9624
  const packaged = getPlayRunPackage(status);
9363
9625
  if (packaged) {
@@ -9534,6 +9796,9 @@ function actionToCommand(action) {
9534
9796
  if (record.kind === "deepline_run_inspect" && typeof record.runId === "string") {
9535
9797
  return `deepline runs get ${record.runId} --json`;
9536
9798
  }
9799
+ if (record.kind === "deepline_run_billing" && typeof record.runId === "string") {
9800
+ return `deepline runs get ${record.runId} --full --json | jq '.billing'`;
9801
+ }
9537
9802
  if (record.kind === "deepline_run_export" && typeof record.runId === "string" && typeof record.datasetPath === "string") {
9538
9803
  return `deepline runs export ${record.runId} --dataset ${shellSingleQuote(
9539
9804
  record.datasetPath
@@ -9566,6 +9831,12 @@ function buildRunPackageTextLines(packaged) {
9566
9831
  if (playName) {
9567
9832
  lines.push(` play: ${playName}`);
9568
9833
  }
9834
+ const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
9835
+ const billingCommand = actionToCommand(next.billing);
9836
+ if (billingCommand) {
9837
+ const costState = status === "completed" || status === "failed" || status === "cancelled" ? "finalizing" : "pending";
9838
+ lines.push(` cost: ${costState}`);
9839
+ }
9569
9840
  for (const step of readRecordArray(packaged.steps).slice(0, 8)) {
9570
9841
  const id = typeof step.id === "string" ? step.id : "step";
9571
9842
  const kind = typeof step.kind === "string" ? step.kind : "step";
@@ -9582,12 +9853,12 @@ function buildRunPackageTextLines(packaged) {
9582
9853
  );
9583
9854
  }
9584
9855
  }
9585
- const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
9586
9856
  const datasetActions = readFirstDatasetActions(packaged);
9587
9857
  const inspectCommand = actionToCommand(next.inspect);
9588
9858
  const queryCommand = actionToCommand(next.query) ?? actionToCommand(datasetActions.query);
9589
9859
  const exportCommand = actionToCommand(next.export) ?? actionToCommand(datasetActions.exportCsv);
9590
9860
  if (inspectCommand) lines.push(` inspect: ${inspectCommand}`);
9861
+ if (billingCommand) lines.push(` billing: ${billingCommand}`);
9591
9862
  if (queryCommand) lines.push(` query: ${queryCommand}`);
9592
9863
  if (exportCommand) lines.push(` export CSV: ${exportCommand}`);
9593
9864
  return lines;
@@ -10136,7 +10407,7 @@ function writeStartedPlayRun(input2) {
10136
10407
  );
10137
10408
  }
10138
10409
  function parsePlayRunOptions(args) {
10139
- const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotency, tool call id, and ctx.dataset guidance.";
10410
+ const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--profile <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--profile <id>] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotency, tool call id, and ctx.dataset guidance.";
10140
10411
  let filePath = null;
10141
10412
  let playName = null;
10142
10413
  let input2 = null;
@@ -10149,6 +10420,7 @@ function parsePlayRunOptions(args) {
10149
10420
  const force = args.includes("--force");
10150
10421
  const noOpen = args.includes("--no-open");
10151
10422
  let waitTimeoutMs = null;
10423
+ let profile = null;
10152
10424
  for (let index = 0; index < args.length; index += 1) {
10153
10425
  const arg = args[index];
10154
10426
  if (arg === "--file" && args[index + 1]) {
@@ -10167,6 +10439,16 @@ function parsePlayRunOptions(args) {
10167
10439
  revisionId = args[++index];
10168
10440
  continue;
10169
10441
  }
10442
+ if (arg === "--profile") {
10443
+ const value = args[index + 1];
10444
+ if (!value) {
10445
+ throw new Error("--profile requires an execution profile id.");
10446
+ }
10447
+ profile = value.trim();
10448
+ resolveExecutionProfile(profile);
10449
+ index += 1;
10450
+ continue;
10451
+ }
10170
10452
  if (arg === "--live") {
10171
10453
  revisionSelector = "live";
10172
10454
  continue;
@@ -10254,7 +10536,8 @@ function parsePlayRunOptions(args) {
10254
10536
  fullJson,
10255
10537
  waitTimeoutMs,
10256
10538
  force,
10257
- noOpen
10539
+ noOpen,
10540
+ profile
10258
10541
  };
10259
10542
  }
10260
10543
  function parsePlayCheckOptions(args) {
@@ -10531,7 +10814,7 @@ async function handleFileBackedRun(options) {
10531
10814
  graph = await traceCliSpan(
10532
10815
  "cli.play_file_bundle_graph",
10533
10816
  { targetKind: "file" },
10534
- () => collectBundledPlayGraph(absolutePlayPath)
10817
+ () => collectBundledPlayGraph(absolutePlayPath, options.profile)
10535
10818
  );
10536
10819
  await traceCliSpan(
10537
10820
  "cli.play_file_compile_manifests",
@@ -10591,7 +10874,8 @@ async function handleFileBackedRun(options) {
10591
10874
  ...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
10592
10875
  ...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
10593
10876
  ...stagedFileInputs.packagedFiles.length ? { packagedFiles: stagedFileInputs.packagedFiles } : {},
10594
- ...options.force ? { force: true } : {}
10877
+ ...options.force ? { force: true } : {},
10878
+ ...options.profile ? { profile: options.profile } : {}
10595
10879
  };
10596
10880
  if (options.watch) {
10597
10881
  progress.phase("starting run");
@@ -10616,11 +10900,14 @@ async function handleFileBackedRun(options) {
10616
10900
  } else {
10617
10901
  progress.fail();
10618
10902
  }
10619
- const outputStatus = await resolvePlayRunOutputStatus({
10620
- client,
10621
- status: finalStatus,
10622
- fullJson: options.fullJson
10623
- });
10903
+ const outputStatus = withTerminalPlayIdentity(
10904
+ await resolvePlayRunOutputStatus({
10905
+ client,
10906
+ status: finalStatus,
10907
+ fullJson: options.fullJson
10908
+ }),
10909
+ playName
10910
+ );
10624
10911
  traceCliSync(
10625
10912
  "cli.play_write_result",
10626
10913
  { targetKind: "file", playName },
@@ -10643,7 +10930,7 @@ async function handleFileBackedRun(options) {
10643
10930
  dashboardUrl: resolvedDashboardUrl,
10644
10931
  noOpen: options.noOpen
10645
10932
  });
10646
- progress.phase(`loading play on ${resolvedDashboardUrl}`);
10933
+ progress.phase("started run");
10647
10934
  progress.complete();
10648
10935
  writeStartedPlayRun({
10649
10936
  runId: started.workflowId,
@@ -10737,7 +11024,8 @@ async function handleNamedRun(options) {
10737
11024
  ...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
10738
11025
  ...stagedFileInputs.inputFile ? { inputFile: stagedFileInputs.inputFile } : {},
10739
11026
  ...stagedFileInputs.packagedFiles.length ? { packagedFiles: stagedFileInputs.packagedFiles } : {},
10740
- ...options.force ? { force: true } : {}
11027
+ ...options.force ? { force: true } : {},
11028
+ ...options.profile ? { profile: options.profile } : {}
10741
11029
  };
10742
11030
  if (options.watch) {
10743
11031
  progress.phase("starting run");
@@ -10762,11 +11050,14 @@ async function handleNamedRun(options) {
10762
11050
  } else {
10763
11051
  progress.fail();
10764
11052
  }
10765
- const outputStatus = await resolvePlayRunOutputStatus({
10766
- client,
10767
- status: finalStatus,
10768
- fullJson: options.fullJson
10769
- });
11053
+ const outputStatus = withTerminalPlayIdentity(
11054
+ await resolvePlayRunOutputStatus({
11055
+ client,
11056
+ status: finalStatus,
11057
+ fullJson: options.fullJson
11058
+ }),
11059
+ playName
11060
+ );
10770
11061
  traceCliSync(
10771
11062
  "cli.play_write_result",
10772
11063
  { targetKind: "name", playName },
@@ -10789,7 +11080,7 @@ async function handleNamedRun(options) {
10789
11080
  dashboardUrl: resolvedDashboardUrl,
10790
11081
  noOpen: options.noOpen
10791
11082
  });
10792
- progress.phase(`loading play on ${resolvedDashboardUrl}`);
11083
+ progress.phase("started run");
10793
11084
  progress.complete();
10794
11085
  writeStartedPlayRun({
10795
11086
  runId: started.workflowId,
@@ -10901,10 +11192,12 @@ async function handleRunsList(args) {
10901
11192
  startedAt: run.startTime,
10902
11193
  finishedAt: run.closeTime,
10903
11194
  executionTime: run.executionTime,
11195
+ billingTotalCredits: run.billingTotalCredits,
11196
+ billingMaxCreditsPerRun: run.billingMaxCreditsPerRun,
10904
11197
  playName: run.memo?.playName ?? playName
10905
11198
  }));
10906
11199
  const lines = runs.length === 0 ? [`No runs found for ${playName}.`] : runs.map(
10907
- (run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)}`
11200
+ (run) => `${run.runId} ${run.status} ${formatTimestamp(run.startedAt)} ${typeof run.billingTotalCredits === "number" && Number.isFinite(run.billingTotalCredits) ? `${formatCreditAmount(run.billingTotalCredits)} credits` : "\u2014"}`
10908
11201
  );
10909
11202
  printCommandEnvelope(
10910
11203
  {
@@ -11275,16 +11568,19 @@ function parsePlaySearchOptions(args) {
11275
11568
  const query = args[0]?.trim();
11276
11569
  if (!query) {
11277
11570
  throw new Error(
11278
- "Usage: deepline plays search <query> [--compact] [--json]"
11571
+ "Usage: deepline plays search <query> [--all] [--compact] [--json]"
11279
11572
  );
11280
11573
  }
11281
11574
  return {
11282
11575
  query,
11283
11576
  jsonOutput: argsWantJson(args),
11284
11577
  compact: args.includes("--compact"),
11285
- prebuiltOnly: args.includes("--prebuilt")
11578
+ scope: args.includes("--all") && !args.includes("--prebuilt") ? "all" : "prebuilt"
11286
11579
  };
11287
11580
  }
11581
+ function playSearchDisclaimer(scope) {
11582
+ return scope === "all" ? "Prebuilt-first search: Deepline-managed prebuilts are trusted, robust plays with maintained contracts, so they are listed before plays you created. Use created-play results only when you are specifically looking for one." : "Prebuilt-first search: Deepline-managed prebuilts are trusted, robust plays with maintained contracts. Plays you created are omitted by default; add --all only when you are specifically looking for one.";
11583
+ }
11288
11584
  function printPlayDescription(play) {
11289
11585
  const reference = formatPlayListReference(play);
11290
11586
  const labels = [
@@ -11426,19 +11722,26 @@ async function handlePlaySearch(args) {
11426
11722
  return 1;
11427
11723
  }
11428
11724
  const client = new DeeplineClient();
11429
- const plays = (await client.searchPlays({
11725
+ const plays = await client.searchPlays({
11430
11726
  query: options.query,
11431
- compact: options.compact
11432
- })).filter(
11433
- (play) => options.prebuiltOnly ? play.origin === "prebuilt" || play.ownerType === "deepline" : true
11434
- );
11727
+ compact: options.compact,
11728
+ scope: options.scope
11729
+ });
11730
+ const disclaimer = playSearchDisclaimer(options.scope);
11435
11731
  if (options.jsonOutput) {
11436
- const jsonPlays = options.prebuiltOnly ? plays.map((play) => ({
11732
+ const jsonPlays = options.scope === "prebuilt" ? plays.map((play) => ({
11437
11733
  ...play,
11438
11734
  inputSchema: compactPlaySchema(play.inputSchema)
11439
11735
  })) : plays;
11440
11736
  process.stdout.write(
11441
11737
  `${JSON.stringify({
11738
+ disclaimer,
11739
+ search_policy: {
11740
+ default_scope: "prebuilt",
11741
+ included_origins: options.scope === "all" ? ["prebuilt", "owned"] : ["prebuilt"],
11742
+ owned_plays_omitted: options.scope === "prebuilt",
11743
+ include_owned_flag: "--all"
11744
+ },
11442
11745
  plays: jsonPlays,
11443
11746
  total: jsonPlays.length,
11444
11747
  truncated: false
@@ -11447,21 +11750,23 @@ async function handlePlaySearch(args) {
11447
11750
  );
11448
11751
  return 0;
11449
11752
  }
11450
- const displayPlays = options.prebuiltOnly ? plays.slice(0, 5) : plays;
11753
+ const displayPlays = options.scope === "prebuilt" ? plays.slice(0, 5) : plays;
11754
+ process.stdout.write(`${disclaimer}
11755
+ `);
11451
11756
  process.stdout.write(
11452
- `${plays.length} plays found${options.prebuiltOnly && plays.length > displayPlays.length ? `; showing top ${displayPlays.length}` : ""}:
11757
+ `${plays.length} plays found${options.scope === "prebuilt" && plays.length > displayPlays.length ? `; showing top ${displayPlays.length}` : ""}:
11453
11758
 
11454
11759
  `
11455
11760
  );
11456
11761
  for (const play of displayPlays) {
11457
- if (options.prebuiltOnly) {
11762
+ if (options.scope === "prebuilt") {
11458
11763
  printCompactPlaySearchResult(play);
11459
11764
  } else {
11460
11765
  printPlayDescription(play);
11461
11766
  }
11462
11767
  console.log("");
11463
11768
  }
11464
- if (options.prebuiltOnly && plays.length > displayPlays.length) {
11769
+ if (options.scope === "prebuilt" && plays.length > displayPlays.length) {
11465
11770
  console.log("Use --json for the full machine-readable result set.");
11466
11771
  }
11467
11772
  return 0;
@@ -11825,6 +12130,9 @@ Examples:
11825
12130
  ).option("--file <path>", "Local play file to run").option("--name <name>", "Saved play name to run").option("-i, --input <json>", "Input JSON object or @file path").option("--live", "Run the current live revision explicitly").option("--latest", "Run the newest saved revision, even if it is not live").option(
11826
12131
  "--revision-id <id>",
11827
12132
  "Run a specific saved revision instead of the live revision"
12133
+ ).option(
12134
+ "--profile <id>",
12135
+ "Internal/testing: override the execution profile for this run"
11828
12136
  ).option("--watch", "Compatibility alias; run waits by default").option("--wait", "Compatibility alias; run waits by default").option("--no-wait", "Start the run and return immediately").option(
11829
12137
  "--logs",
11830
12138
  "When output is non-interactive, stream play logs to stderr while waiting"
@@ -11858,6 +12166,7 @@ Pass-through input flags:
11858
12166
  ...options.live ? ["--live"] : [],
11859
12167
  ...options.latest ? ["--latest"] : [],
11860
12168
  ...options.revisionId ? ["--revision-id", options.revisionId] : [],
12169
+ ...options.profile ? ["--profile", options.profile] : [],
11861
12170
  ...options.wait === false ? ["--no-wait"] : [],
11862
12171
  ...options.watch || options.wait ? ["--watch"] : [],
11863
12172
  ...options.logs ? ["--logs"] : [],
@@ -11911,18 +12220,26 @@ Examples:
11911
12220
  ...options.json ? ["--json"] : []
11912
12221
  ]);
11913
12222
  });
11914
- const addPlaySearchCommand = (command) => command.description("Search saved and prebuilt plays.").option("--prebuilt", "Only show Deepline-managed prebuilt plays").addHelpText(
12223
+ const addPlaySearchCommand = (command) => command.description("Search Deepline prebuilt plays by task.").option(
12224
+ "--prebuilt",
12225
+ "Only show Deepline-managed prebuilt plays (default)"
12226
+ ).option(
12227
+ "--all",
12228
+ "Also include plays you created after Deepline-managed prebuilts"
12229
+ ).addHelpText(
11915
12230
  "after",
11916
12231
  `
11917
12232
  Notes:
11918
- Ranked discovery for workflows. Use describe on a result before running it.
11919
- Prefer --prebuilt for new GTM tasks so old workspace scratchpads do not
11920
- outrank Deepline-managed routes unless the user names one explicitly.
12233
+ Ranked discovery for workflows. Search defaults to Deepline-managed prebuilts
12234
+ because they are trusted, robust plays with maintained contracts. Use describe
12235
+ on a result before running it.
12236
+ Add --all only when you are specifically looking for a play you created.
11921
12237
  The grep alias is the same ranked retrieval surface with a more literal name
11922
12238
  for agents that are filtering the play registry.
11923
12239
 
11924
12240
  Examples:
11925
12241
  deepline plays search email
12242
+ deepline plays search email --all
11926
12243
  deepline plays grep "linkedin to email" --compact --json
11927
12244
  deepline plays describe person-linkedin-to-email --json
11928
12245
  `
@@ -11930,6 +12247,7 @@ Examples:
11930
12247
  process.exitCode = await handlePlaySearch([
11931
12248
  query,
11932
12249
  ...options.prebuilt ? ["--prebuilt"] : [],
12250
+ ...options.all ? ["--all"] : [],
11933
12251
  ...options.compact ? ["--compact"] : [],
11934
12252
  ...options.json ? ["--json"] : []
11935
12253
  ]);
@@ -13697,7 +14015,7 @@ async function readHiddenLine(prompt) {
13697
14015
  if (typeof input.setRawMode === "function") input.setRawMode(true);
13698
14016
  let value = "";
13699
14017
  input.resume();
13700
- return await new Promise((resolve13, reject) => {
14018
+ return await new Promise((resolve14, reject) => {
13701
14019
  let settled = false;
13702
14020
  const cleanup = () => {
13703
14021
  input.off("data", onData);
@@ -13712,7 +14030,7 @@ async function readHiddenLine(prompt) {
13712
14030
  settled = true;
13713
14031
  output.write("\n");
13714
14032
  cleanup();
13715
- resolve13(line);
14033
+ resolve14(line);
13716
14034
  };
13717
14035
  const fail = (error) => {
13718
14036
  if (settled) return;
@@ -13884,9 +14202,15 @@ Examples:
13884
14202
 
13885
14203
  // src/cli/commands/tools.ts
13886
14204
  import { Option } from "commander";
13887
- import { chmodSync, mkdtempSync, writeFileSync as writeFileSync9 } from "fs";
14205
+ import {
14206
+ chmodSync,
14207
+ existsSync as existsSync8,
14208
+ mkdtempSync,
14209
+ readFileSync as readFileSync7,
14210
+ writeFileSync as writeFileSync9
14211
+ } from "fs";
13888
14212
  import { tmpdir as tmpdir4 } from "os";
13889
- import { join as join10 } from "path";
14213
+ import { join as join10, resolve as resolve12 } from "path";
13890
14214
 
13891
14215
  // src/tool-output.ts
13892
14216
  import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync8 } from "fs";
@@ -14477,7 +14801,13 @@ Examples:
14477
14801
  ).option(
14478
14802
  "--json [payload]",
14479
14803
  "Emit JSON output. Use `--input` or `--payload` for passing JSON params."
14480
- ).option("--input <payload>", "Merge a JSON object into the tool params").option("--payload <payload>", "Merge a JSON object into the tool params").option(
14804
+ ).option(
14805
+ "--input <payload>",
14806
+ "Merge a JSON object or @file path into the tool params"
14807
+ ).option(
14808
+ "--payload <payload>",
14809
+ "Merge a JSON object or @file path into the tool params"
14810
+ ).option(
14481
14811
  "--output-format <format>",
14482
14812
  "Output format: auto, csv, csv_file, json, or json_file"
14483
14813
  ).option(
@@ -15048,6 +15378,57 @@ function normalizeOutputFormat(raw) {
15048
15378
  throw new Error(`Invalid value for --output-format: ${raw}`);
15049
15379
  }
15050
15380
  }
15381
+ function resolveAtFilePath(rawPath) {
15382
+ const trimmed = rawPath.trim();
15383
+ const resolved = resolve12(trimmed);
15384
+ if (existsSync8(resolved)) return resolved;
15385
+ if (process.platform !== "win32" && trimmed.includes("\\")) {
15386
+ const normalized = resolve12(trimmed.replace(/\\/g, "/"));
15387
+ if (existsSync8(normalized)) return normalized;
15388
+ }
15389
+ return resolved;
15390
+ }
15391
+ function readJsonArgument(raw, flagName) {
15392
+ if (!raw.startsWith("@")) return raw.replace(/^\uFEFF/, "");
15393
+ const filePath = raw.slice(1).trim();
15394
+ if (!filePath) {
15395
+ throw new Error(`Invalid ${flagName} value: empty @file path.`);
15396
+ }
15397
+ try {
15398
+ return readFileSync7(resolveAtFilePath(filePath), "utf8").replace(
15399
+ /^\uFEFF/,
15400
+ ""
15401
+ );
15402
+ } catch (error) {
15403
+ const message = error instanceof Error ? error.message : String(error);
15404
+ throw new Error(
15405
+ `Failed to read ${flagName} file '${filePath}': ${message}`
15406
+ );
15407
+ }
15408
+ }
15409
+ function invalidJsonError(flagName, message) {
15410
+ const error = new Error(
15411
+ `Invalid JSON in ${flagName}: ${message}`
15412
+ );
15413
+ error.code = "INVALID_JSON";
15414
+ return error;
15415
+ }
15416
+ function parseJsonObjectArgument(raw, flagName) {
15417
+ let parsed;
15418
+ try {
15419
+ parsed = JSON.parse(readJsonArgument(raw, flagName));
15420
+ } catch (error) {
15421
+ const message = error instanceof Error ? error.message : String(error);
15422
+ if (message.startsWith("Failed to read ") || message.startsWith("Invalid ")) {
15423
+ throw error;
15424
+ }
15425
+ throw invalidJsonError(flagName, message);
15426
+ }
15427
+ if (!isRecord5(parsed)) {
15428
+ throw invalidJsonError(flagName, "expected an object.");
15429
+ }
15430
+ return parsed;
15431
+ }
15051
15432
  function parseExecuteOptions(args) {
15052
15433
  const toolId = args[0];
15053
15434
  if (!toolId) {
@@ -15070,12 +15451,15 @@ function parseExecuteOptions(args) {
15070
15451
  const next = args[index + 1];
15071
15452
  outputFormat = "json";
15072
15453
  if (next && !next.startsWith("--")) {
15073
- Object.assign(params, JSON.parse(args[++index]));
15454
+ Object.assign(
15455
+ params,
15456
+ parseJsonObjectArgument(args[++index], "--json")
15457
+ );
15074
15458
  }
15075
15459
  continue;
15076
15460
  }
15077
15461
  if ((arg === "--input" || arg === "--payload") && args[index + 1]) {
15078
- Object.assign(params, JSON.parse(args[++index]));
15462
+ Object.assign(params, parseJsonObjectArgument(args[++index], arg));
15079
15463
  continue;
15080
15464
  }
15081
15465
  if (arg === "--output-format" && args[index + 1]) {
@@ -15395,8 +15779,8 @@ async function executeTool(args) {
15395
15779
 
15396
15780
  // src/cli/commands/update.ts
15397
15781
  import { spawn } from "child_process";
15398
- import { existsSync as existsSync8 } from "fs";
15399
- import { dirname as dirname9, join as join11, resolve as resolve12 } from "path";
15782
+ import { existsSync as existsSync9 } from "fs";
15783
+ import { dirname as dirname9, join as join11, resolve as resolve13 } from "path";
15400
15784
  function posixShellQuote(value) {
15401
15785
  return `'${value.replace(/'/g, `'\\''`)}'`;
15402
15786
  }
@@ -15415,9 +15799,9 @@ function buildSourceUpdateCommand(sourceRoot) {
15415
15799
  return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
15416
15800
  }
15417
15801
  function findRepoBackedSdkRoot(startPath) {
15418
- let current = resolve12(startPath);
15802
+ let current = resolve13(startPath);
15419
15803
  while (true) {
15420
- if (existsSync8(join11(current, "sdk", "package.json")) && existsSync8(join11(current, "sdk", "bin", "deepline-dev.ts"))) {
15804
+ if (existsSync9(join11(current, "sdk", "package.json")) && existsSync9(join11(current, "sdk", "bin", "deepline-dev.ts"))) {
15421
15805
  return current;
15422
15806
  }
15423
15807
  const parent = dirname9(current);
@@ -15426,7 +15810,7 @@ function findRepoBackedSdkRoot(startPath) {
15426
15810
  }
15427
15811
  }
15428
15812
  function resolveUpdatePlan() {
15429
- const entrypoint = process.argv[1] ? resolve12(process.argv[1]) : "";
15813
+ const entrypoint = process.argv[1] ? resolve13(process.argv[1]) : "";
15430
15814
  const sourceRoot = entrypoint ? findRepoBackedSdkRoot(dirname9(entrypoint)) : null;
15431
15815
  if (sourceRoot) {
15432
15816
  return {
@@ -15660,7 +16044,7 @@ function commandCompatibilityHint(currentFamily, commandName, baseUrl) {
15660
16044
  lines.push(
15661
16045
  "",
15662
16046
  " To stay on the SDK CLI, install the SDK agent skill:",
15663
- ` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
16047
+ ` ${skillsInstallCommand(baseUrl, "deepline-plays")}`,
15664
16048
  " To use the legacy Python CLI instead:",
15665
16049
  ` ${legacyPythonInstallCommand(baseUrl)}`,
15666
16050
  " `deepline update` updates this SDK CLI, but it will not switch CLI families."
@@ -15673,7 +16057,7 @@ function commandCompatibilityHint(currentFamily, commandName, baseUrl) {
15673
16057
  "",
15674
16058
  " To use SDK commands, install the SDK CLI and SDK agent skill:",
15675
16059
  ` ${sdkNpmGlobalInstallCommand()}`,
15676
- ` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
16060
+ ` ${skillsInstallCommand(baseUrl, "deepline-plays")}`,
15677
16061
  " `deepline update` updates this Python CLI and its skills, but it will not switch CLI families."
15678
16062
  );
15679
16063
  if (compatibility.python_alternative) {
@@ -15691,22 +16075,39 @@ function unknownCommandNameFromMessage(message) {
15691
16075
  // src/cli/skills-sync.ts
15692
16076
  import { spawn as spawn2, spawnSync } from "child_process";
15693
16077
  import {
15694
- existsSync as existsSync9,
16078
+ existsSync as existsSync10,
15695
16079
  mkdirSync as mkdirSync5,
15696
16080
  readdirSync as readdirSync2,
15697
- readFileSync as readFileSync7,
16081
+ readFileSync as readFileSync8,
15698
16082
  statSync as statSync2,
15699
16083
  writeFileSync as writeFileSync10
15700
16084
  } from "fs";
15701
16085
  import { homedir as homedir6 } from "os";
15702
16086
  import { dirname as dirname10, join as join12 } from "path";
15703
16087
  var CHECK_TIMEOUT_MS2 = 3e3;
15704
- var SDK_SKILL_NAME = "deepline-sdk";
16088
+ var SDK_SKILL_NAME = "deepline-plays";
15705
16089
  var attemptedSync = false;
15706
16090
  function shouldSkipSkillsSync() {
15707
16091
  const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
15708
16092
  return value === "1" || value === "true" || value === "yes" || value === "on";
15709
16093
  }
16094
+ function activePluginSkillsDir() {
16095
+ const pluginMode = process.env.DEEPLINE_PLUGIN_MODE?.trim().toLowerCase();
16096
+ if (pluginMode !== "true" && pluginMode !== "1" && pluginMode !== "yes" && pluginMode !== "on") {
16097
+ return "";
16098
+ }
16099
+ const dir = process.env.DEEPLINE_PLUGIN_SKILLS_DIR?.trim() ?? "";
16100
+ return dir && existsSync10(dir) ? dir : "";
16101
+ }
16102
+ function readPluginSkillsVersion() {
16103
+ const dir = activePluginSkillsDir();
16104
+ if (!dir) return "";
16105
+ try {
16106
+ return readFileSync8(join12(dir, ".version"), "utf-8").trim();
16107
+ } catch {
16108
+ return "";
16109
+ }
16110
+ }
15710
16111
  function sdkSkillsVersionPath(baseUrl) {
15711
16112
  const home = process.env.HOME?.trim() || homedir6();
15712
16113
  return join12(
@@ -15719,10 +16120,12 @@ function sdkSkillsVersionPath(baseUrl) {
15719
16120
  );
15720
16121
  }
15721
16122
  function readLocalSkillsVersion(baseUrl) {
16123
+ const pluginVersion = readPluginSkillsVersion();
16124
+ if (pluginVersion) return pluginVersion;
15722
16125
  const path = sdkSkillsVersionPath(baseUrl);
15723
- if (!existsSync9(path)) return "";
16126
+ if (!existsSync10(path)) return "";
15724
16127
  try {
15725
- return readFileSync7(path, "utf-8").trim();
16128
+ return readFileSync8(path, "utf-8").trim();
15726
16129
  } catch {
15727
16130
  return "";
15728
16131
  }
@@ -15735,7 +16138,8 @@ function writeLocalSkillsVersion(baseUrl, version) {
15735
16138
  }
15736
16139
  function installedSdkSkillHasStalePositionalExecuteExamples() {
15737
16140
  const home = process.env.HOME?.trim() || homedir6();
15738
- const roots = [
16141
+ const pluginSkillsDir = activePluginSkillsDir();
16142
+ const roots = pluginSkillsDir ? [join12(pluginSkillsDir, SDK_SKILL_NAME)] : [
15739
16143
  join12(home, ".claude", "skills", SDK_SKILL_NAME),
15740
16144
  join12(home, ".agents", "skills", SDK_SKILL_NAME)
15741
16145
  ];
@@ -15755,14 +16159,14 @@ function installedSdkSkillHasStalePositionalExecuteExamples() {
15755
16159
  continue;
15756
16160
  }
15757
16161
  if (!entry.endsWith(".md")) continue;
15758
- const text = readFileSync7(path, "utf-8");
16162
+ const text = readFileSync8(path, "utf-8");
15759
16163
  if (staleMarkers.some((marker) => text.includes(marker))) return true;
15760
16164
  }
15761
16165
  return false;
15762
16166
  };
15763
16167
  for (const root of roots) {
15764
16168
  try {
15765
- if (existsSync9(root) && scan(root)) return true;
16169
+ if (existsSync10(root) && scan(root)) return true;
15766
16170
  } catch {
15767
16171
  continue;
15768
16172
  }
@@ -15834,7 +16238,7 @@ function resolveSkillsInstallCommands(baseUrl) {
15834
16238
  return [npxInstall];
15835
16239
  }
15836
16240
  function runOneSkillsInstall(install) {
15837
- return new Promise((resolve13) => {
16241
+ return new Promise((resolve14) => {
15838
16242
  const child = spawn2(install.command, install.args, {
15839
16243
  stdio: ["ignore", "ignore", "pipe"],
15840
16244
  env: process.env
@@ -15844,7 +16248,7 @@ function runOneSkillsInstall(install) {
15844
16248
  stderr += chunk.toString("utf-8");
15845
16249
  });
15846
16250
  child.on("error", (error) => {
15847
- resolve13({
16251
+ resolve14({
15848
16252
  ok: false,
15849
16253
  detail: `failed to start ${install.command}: ${error.message}`,
15850
16254
  manualCommand: install.manualCommand
@@ -15852,11 +16256,11 @@ function runOneSkillsInstall(install) {
15852
16256
  });
15853
16257
  child.on("close", (code) => {
15854
16258
  if (code === 0) {
15855
- resolve13({ ok: true, detail: "", manualCommand: install.manualCommand });
16259
+ resolve14({ ok: true, detail: "", manualCommand: install.manualCommand });
15856
16260
  return;
15857
16261
  }
15858
16262
  const detail = stderr.trim();
15859
- resolve13({
16263
+ resolve14({
15860
16264
  ok: false,
15861
16265
  detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
15862
16266
  manualCommand: install.manualCommand
@@ -15893,18 +16297,22 @@ function writeSdkSkillsStatusLine(line) {
15893
16297
  async function syncSdkSkillsIfNeeded(baseUrl) {
15894
16298
  if (attemptedSync || shouldSkipSkillsSync()) return;
15895
16299
  attemptedSync = true;
16300
+ const usingPluginSkills = Boolean(activePluginSkillsDir());
15896
16301
  const localVersion = readLocalSkillsVersion(baseUrl);
15897
16302
  const update = await fetchSkillsUpdate(baseUrl, localVersion);
15898
16303
  const hasStaleInstalledSkill = installedSdkSkillHasStalePositionalExecuteExamples();
16304
+ if (usingPluginSkills) {
16305
+ return;
16306
+ }
15899
16307
  if (!update?.needsUpdate && !hasStaleInstalledSkill || !update?.remoteVersion) {
15900
16308
  return;
15901
16309
  }
15902
- writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-sdk skill...");
16310
+ writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-plays skill...");
15903
16311
  const installed = await runSkillsInstall(baseUrl);
15904
16312
  if (!installed) return;
15905
16313
  if (installedSdkSkillHasStalePositionalExecuteExamples()) {
15906
16314
  process.stderr.write(
15907
- "SDK skills sync completed, but installed deepline-sdk docs still contain stale positional ctx.tools.execute examples.\n"
16315
+ "SDK skills sync completed, but installed deepline-plays docs still contain stale positional ctx.tools.execute examples.\n"
15908
16316
  );
15909
16317
  return;
15910
16318
  }