deepline 0.1.85 → 0.1.89

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.85",
209
+ version: "0.1.89",
210
210
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
211
211
  supportPolicy: {
212
- latest: "0.1.85",
212
+ latest: "0.1.89",
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);
@@ -2409,7 +2531,7 @@ function buildCandidateUrls2(url) {
2409
2531
  }
2410
2532
  }
2411
2533
  function sleep3(ms) {
2412
- return new Promise((resolve13) => setTimeout(resolve13, ms));
2534
+ return new Promise((resolve14) => setTimeout(resolve14, ms));
2413
2535
  }
2414
2536
  function printDeeplineLogo() {
2415
2537
  if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
@@ -4677,7 +4799,12 @@ function readPackageVersionFromPackageJson(packageJsonPath, packageName) {
4677
4799
  return null;
4678
4800
  }
4679
4801
  function findPackageJsonPathFrom(startDir, packageName) {
4680
- 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;
4681
4808
  while (true) {
4682
4809
  const packageJsonPath = join4(
4683
4810
  current,
@@ -4697,17 +4824,15 @@ function findPackageJsonPathFrom(startDir, packageName) {
4697
4824
  }
4698
4825
  function findPackageJsonPath(packageName, fromFile, adapter) {
4699
4826
  const startDirs = [
4700
- dirname5(fromFile),
4701
- adapter.projectRoot,
4702
- dirname5(adapter.sdkPackageJson),
4703
- process.cwd()
4827
+ resolve6(dirname5(fromFile)),
4828
+ resolve6(adapter.projectRoot),
4829
+ resolve6(dirname5(adapter.sdkPackageJson))
4704
4830
  ];
4705
4831
  const seen = /* @__PURE__ */ new Set();
4706
4832
  for (const startDir of startDirs) {
4707
- const normalized = resolve6(startDir);
4708
- if (seen.has(normalized)) continue;
4709
- seen.add(normalized);
4710
- const packageJsonPath = findPackageJsonPathFrom(normalized, packageName);
4833
+ if (seen.has(startDir)) continue;
4834
+ seen.add(startDir);
4835
+ const packageJsonPath = findPackageJsonPathFrom(startDir, packageName);
4711
4836
  if (packageJsonPath) return packageJsonPath;
4712
4837
  }
4713
4838
  const adapterNodeModulesPackageJson = join4(
@@ -5165,13 +5290,13 @@ async function writeArtifactCache(artifact, adapter) {
5165
5290
  "utf-8"
5166
5291
  );
5167
5292
  }
5168
- function normalizeSourceMapForRuntime(sourceMapText) {
5293
+ function normalizeSourceMapForRuntime(sourceMapText, projectRoot) {
5169
5294
  const parsed = JSON.parse(sourceMapText);
5170
5295
  parsed.sources = (parsed.sources ?? []).map((sourcePath) => {
5171
5296
  if (sourcePath.startsWith("data:") || sourcePath.startsWith("node:") || sourcePath.startsWith("/") || /^[a-zA-Z]+:\/\//.test(sourcePath)) {
5172
5297
  return sourcePath;
5173
5298
  }
5174
- return resolve6(process.cwd(), sourcePath);
5299
+ return join4(projectRoot, sourcePath);
5175
5300
  });
5176
5301
  parsed.sourceRoot = void 0;
5177
5302
  return JSON.stringify(parsed);
@@ -5437,7 +5562,10 @@ workers-harness:${harnessFingerprint}`
5437
5562
  };
5438
5563
  }
5439
5564
  const { bundledCode, sourceMapText, outputExtension } = buildOutcome;
5440
- const normalizedSourceMap = normalizeSourceMapForRuntime(sourceMapText);
5565
+ const normalizedSourceMap = normalizeSourceMapForRuntime(
5566
+ sourceMapText,
5567
+ resolve6(adapter.projectRoot)
5568
+ );
5441
5569
  const virtualBaseName = exportName === "default" ? basename(absolutePath).replace(/\.[^.]+$/, "") : `${basename(absolutePath).replace(/\.[^.]+$/, "")}.${exportName}`;
5442
5570
  const virtualFilename = `/virtual/deepline-plays/${analysis.graphHash}/${virtualBaseName}.${outputExtension}`;
5443
5571
  const executableCode = `${bundledCode}
@@ -7845,7 +7973,7 @@ function traceCliSync(phase, fields, run) {
7845
7973
  }
7846
7974
  }
7847
7975
  function sleep4(ms) {
7848
- return new Promise((resolve13) => setTimeout(resolve13, ms));
7976
+ return new Promise((resolve14) => setTimeout(resolve14, ms));
7849
7977
  }
7850
7978
  function parseReferencedPlayTarget2(target) {
7851
7979
  const trimmed = target.trim();
@@ -8364,6 +8492,8 @@ var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
8364
8492
  "cancelled"
8365
8493
  ]);
8366
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;
8367
8497
  function getEventPayload(event) {
8368
8498
  return event.payload && typeof event.payload === "object" ? event.payload : {};
8369
8499
  }
@@ -8424,6 +8554,7 @@ function extractTableNamespaceFromLiveEvent(event) {
8424
8554
  const payload = getEventPayload(event);
8425
8555
  const candidates = [
8426
8556
  payload.artifactTableNamespace,
8557
+ payload.activeArtifactTableNamespace,
8427
8558
  payload.tableNamespace,
8428
8559
  payload.mapNodeId
8429
8560
  ];
@@ -8502,6 +8633,20 @@ function formatProgressCounts(input2) {
8502
8633
  const failed = typeof input2.failed === "number" && Number.isFinite(input2.failed) && input2.failed > 0 ? `, failed ${formatInteger(input2.failed)}` : "";
8503
8634
  return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
8504
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
+ }
8505
8650
  function getProgressLinesFromLiveEvent(event) {
8506
8651
  const payload = getEventPayload(event);
8507
8652
  if (event.type === "play.step.progress") {
@@ -8511,7 +8656,13 @@ function getProgressLinesFromLiveEvent(event) {
8511
8656
  failed: payload.failed
8512
8657
  });
8513
8658
  if (!counts) return [];
8514
- 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
+ ];
8515
8666
  }
8516
8667
  if (event.type !== "play.run.snapshot" && event.type !== "play.run.final_status") {
8517
8668
  return [];
@@ -8535,22 +8686,69 @@ function getProgressLinesFromLiveEvent(event) {
8535
8686
  if (!counts) {
8536
8687
  continue;
8537
8688
  }
8689
+ const messageSuffix = formatProgressMessageSuffix({
8690
+ message: progress.message,
8691
+ completed: progress.completed
8692
+ });
8538
8693
  lines.push(
8539
- `progress ${formatProgressLabel(record.nodeId ?? progress.artifactTableNamespace)}: ${counts}`
8694
+ `progress ${formatProgressLabel(record.nodeId ?? progress.artifactTableNamespace)}: ${counts}${messageSuffix}`
8540
8695
  );
8541
8696
  }
8542
8697
  return lines;
8543
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
+ }
8544
8705
  function printPlayProgressLines(input2) {
8545
8706
  for (const line of input2.lines) {
8546
8707
  const signature = line.trim();
8547
- 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
+ })) {
8548
8715
  continue;
8549
8716
  }
8550
8717
  input2.state.lastProgressSignature = signature;
8718
+ input2.state.lastProgressHeartbeatAt = now;
8551
8719
  input2.progress.writeLine(line);
8552
8720
  }
8553
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
+ }
8554
8752
  function buildPlayDashboardUrl(baseUrl, playName) {
8555
8753
  const trimmedBase = baseUrl.replace(/\/$/, "");
8556
8754
  const encodedPlayName = encodeURIComponent(playName);
@@ -8633,11 +8831,20 @@ async function waitForPlayCompletionByStream(input2) {
8633
8831
  progress: input2.progress
8634
8832
  });
8635
8833
  if (!input2.jsonOutput) {
8834
+ const progressLines = getProgressLinesFromLiveEvent(event);
8636
8835
  printPlayProgressLines({
8637
- lines: getProgressLinesFromLiveEvent(event),
8836
+ lines: progressLines,
8638
8837
  state: input2.state,
8639
8838
  progress: input2.progress
8640
8839
  });
8840
+ if (progressLines.length === 0) {
8841
+ printPlayStatusHeartbeat({
8842
+ event,
8843
+ playName: input2.playName,
8844
+ state: input2.state,
8845
+ progress: input2.progress
8846
+ });
8847
+ }
8641
8848
  }
8642
8849
  const finalStatus = getFinalStatusFromLiveEvent(event);
8643
8850
  if (finalStatus) {
@@ -8715,7 +8922,9 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
8715
8922
  const state = {
8716
8923
  lastLogIndex: 0,
8717
8924
  emittedRunnerStarted: false,
8718
- lastProgressSignature: null
8925
+ lastProgressSignature: null,
8926
+ lastProgressHeartbeatAt: 0,
8927
+ lastStatusHeartbeatAt: 0
8719
8928
  };
8720
8929
  const controller = new AbortController();
8721
8930
  let timedOut = false;
@@ -8756,7 +8965,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
8756
8965
  dashboardUrl,
8757
8966
  noOpen: input2.noOpen
8758
8967
  });
8759
- input2.progress.phase(`loading play on ${dashboardUrl}`);
8968
+ input2.progress.phase("running");
8760
8969
  emittedDashboardUrl = true;
8761
8970
  }
8762
8971
  assertPlayWaitNotTimedOut({
@@ -8787,11 +8996,20 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
8787
8996
  progress: input2.progress
8788
8997
  });
8789
8998
  if (!input2.jsonOutput) {
8999
+ const progressLines = getProgressLinesFromLiveEvent(event);
8790
9000
  printPlayProgressLines({
8791
- lines: getProgressLinesFromLiveEvent(event),
9001
+ lines: progressLines,
8792
9002
  state,
8793
9003
  progress: input2.progress
8794
9004
  });
9005
+ if (progressLines.length === 0) {
9006
+ printPlayStatusHeartbeat({
9007
+ event,
9008
+ playName: input2.playName,
9009
+ state,
9010
+ progress: input2.progress
9011
+ });
9012
+ }
8795
9013
  }
8796
9014
  const finalStatus = getFinalStatusFromLiveEvent(event);
8797
9015
  if (finalStatus) {
@@ -9391,6 +9609,17 @@ function getPlayRunPackage(status) {
9391
9609
  const packaged = status.package;
9392
9610
  return isPlayRunPackageValue(packaged) ? packaged : null;
9393
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
+ }
9394
9623
  function compactPlayStatus(status) {
9395
9624
  const packaged = getPlayRunPackage(status);
9396
9625
  if (packaged) {
@@ -9567,6 +9796,9 @@ function actionToCommand(action) {
9567
9796
  if (record.kind === "deepline_run_inspect" && typeof record.runId === "string") {
9568
9797
  return `deepline runs get ${record.runId} --json`;
9569
9798
  }
9799
+ if (record.kind === "deepline_run_billing" && typeof record.runId === "string") {
9800
+ return `deepline runs get ${record.runId} --full --json | jq '.billing'`;
9801
+ }
9570
9802
  if (record.kind === "deepline_run_export" && typeof record.runId === "string" && typeof record.datasetPath === "string") {
9571
9803
  return `deepline runs export ${record.runId} --dataset ${shellSingleQuote(
9572
9804
  record.datasetPath
@@ -9599,6 +9831,12 @@ function buildRunPackageTextLines(packaged) {
9599
9831
  if (playName) {
9600
9832
  lines.push(` play: ${playName}`);
9601
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
+ }
9602
9840
  for (const step of readRecordArray(packaged.steps).slice(0, 8)) {
9603
9841
  const id = typeof step.id === "string" ? step.id : "step";
9604
9842
  const kind = typeof step.kind === "string" ? step.kind : "step";
@@ -9615,12 +9853,12 @@ function buildRunPackageTextLines(packaged) {
9615
9853
  );
9616
9854
  }
9617
9855
  }
9618
- const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
9619
9856
  const datasetActions = readFirstDatasetActions(packaged);
9620
9857
  const inspectCommand = actionToCommand(next.inspect);
9621
9858
  const queryCommand = actionToCommand(next.query) ?? actionToCommand(datasetActions.query);
9622
9859
  const exportCommand = actionToCommand(next.export) ?? actionToCommand(datasetActions.exportCsv);
9623
9860
  if (inspectCommand) lines.push(` inspect: ${inspectCommand}`);
9861
+ if (billingCommand) lines.push(` billing: ${billingCommand}`);
9624
9862
  if (queryCommand) lines.push(` query: ${queryCommand}`);
9625
9863
  if (exportCommand) lines.push(` export CSV: ${exportCommand}`);
9626
9864
  return lines;
@@ -10662,11 +10900,14 @@ async function handleFileBackedRun(options) {
10662
10900
  } else {
10663
10901
  progress.fail();
10664
10902
  }
10665
- const outputStatus = await resolvePlayRunOutputStatus({
10666
- client,
10667
- status: finalStatus,
10668
- fullJson: options.fullJson
10669
- });
10903
+ const outputStatus = withTerminalPlayIdentity(
10904
+ await resolvePlayRunOutputStatus({
10905
+ client,
10906
+ status: finalStatus,
10907
+ fullJson: options.fullJson
10908
+ }),
10909
+ playName
10910
+ );
10670
10911
  traceCliSync(
10671
10912
  "cli.play_write_result",
10672
10913
  { targetKind: "file", playName },
@@ -10689,7 +10930,7 @@ async function handleFileBackedRun(options) {
10689
10930
  dashboardUrl: resolvedDashboardUrl,
10690
10931
  noOpen: options.noOpen
10691
10932
  });
10692
- progress.phase(`loading play on ${resolvedDashboardUrl}`);
10933
+ progress.phase("started run");
10693
10934
  progress.complete();
10694
10935
  writeStartedPlayRun({
10695
10936
  runId: started.workflowId,
@@ -10809,11 +11050,14 @@ async function handleNamedRun(options) {
10809
11050
  } else {
10810
11051
  progress.fail();
10811
11052
  }
10812
- const outputStatus = await resolvePlayRunOutputStatus({
10813
- client,
10814
- status: finalStatus,
10815
- fullJson: options.fullJson
10816
- });
11053
+ const outputStatus = withTerminalPlayIdentity(
11054
+ await resolvePlayRunOutputStatus({
11055
+ client,
11056
+ status: finalStatus,
11057
+ fullJson: options.fullJson
11058
+ }),
11059
+ playName
11060
+ );
10817
11061
  traceCliSync(
10818
11062
  "cli.play_write_result",
10819
11063
  { targetKind: "name", playName },
@@ -10836,7 +11080,7 @@ async function handleNamedRun(options) {
10836
11080
  dashboardUrl: resolvedDashboardUrl,
10837
11081
  noOpen: options.noOpen
10838
11082
  });
10839
- progress.phase(`loading play on ${resolvedDashboardUrl}`);
11083
+ progress.phase("started run");
10840
11084
  progress.complete();
10841
11085
  writeStartedPlayRun({
10842
11086
  runId: started.workflowId,
@@ -11324,16 +11568,19 @@ function parsePlaySearchOptions(args) {
11324
11568
  const query = args[0]?.trim();
11325
11569
  if (!query) {
11326
11570
  throw new Error(
11327
- "Usage: deepline plays search <query> [--compact] [--json]"
11571
+ "Usage: deepline plays search <query> [--all] [--compact] [--json]"
11328
11572
  );
11329
11573
  }
11330
11574
  return {
11331
11575
  query,
11332
11576
  jsonOutput: argsWantJson(args),
11333
11577
  compact: args.includes("--compact"),
11334
- prebuiltOnly: args.includes("--prebuilt")
11578
+ scope: args.includes("--all") && !args.includes("--prebuilt") ? "all" : "prebuilt"
11335
11579
  };
11336
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
+ }
11337
11584
  function printPlayDescription(play) {
11338
11585
  const reference = formatPlayListReference(play);
11339
11586
  const labels = [
@@ -11475,19 +11722,26 @@ async function handlePlaySearch(args) {
11475
11722
  return 1;
11476
11723
  }
11477
11724
  const client = new DeeplineClient();
11478
- const plays = (await client.searchPlays({
11725
+ const plays = await client.searchPlays({
11479
11726
  query: options.query,
11480
- compact: options.compact
11481
- })).filter(
11482
- (play) => options.prebuiltOnly ? play.origin === "prebuilt" || play.ownerType === "deepline" : true
11483
- );
11727
+ compact: options.compact,
11728
+ scope: options.scope
11729
+ });
11730
+ const disclaimer = playSearchDisclaimer(options.scope);
11484
11731
  if (options.jsonOutput) {
11485
- const jsonPlays = options.prebuiltOnly ? plays.map((play) => ({
11732
+ const jsonPlays = options.scope === "prebuilt" ? plays.map((play) => ({
11486
11733
  ...play,
11487
11734
  inputSchema: compactPlaySchema(play.inputSchema)
11488
11735
  })) : plays;
11489
11736
  process.stdout.write(
11490
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
+ },
11491
11745
  plays: jsonPlays,
11492
11746
  total: jsonPlays.length,
11493
11747
  truncated: false
@@ -11496,21 +11750,23 @@ async function handlePlaySearch(args) {
11496
11750
  );
11497
11751
  return 0;
11498
11752
  }
11499
- 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
+ `);
11500
11756
  process.stdout.write(
11501
- `${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}` : ""}:
11502
11758
 
11503
11759
  `
11504
11760
  );
11505
11761
  for (const play of displayPlays) {
11506
- if (options.prebuiltOnly) {
11762
+ if (options.scope === "prebuilt") {
11507
11763
  printCompactPlaySearchResult(play);
11508
11764
  } else {
11509
11765
  printPlayDescription(play);
11510
11766
  }
11511
11767
  console.log("");
11512
11768
  }
11513
- if (options.prebuiltOnly && plays.length > displayPlays.length) {
11769
+ if (options.scope === "prebuilt" && plays.length > displayPlays.length) {
11514
11770
  console.log("Use --json for the full machine-readable result set.");
11515
11771
  }
11516
11772
  return 0;
@@ -11964,18 +12220,26 @@ Examples:
11964
12220
  ...options.json ? ["--json"] : []
11965
12221
  ]);
11966
12222
  });
11967
- 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(
11968
12230
  "after",
11969
12231
  `
11970
12232
  Notes:
11971
- Ranked discovery for workflows. Use describe on a result before running it.
11972
- Prefer --prebuilt for new GTM tasks so old workspace scratchpads do not
11973
- 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.
11974
12237
  The grep alias is the same ranked retrieval surface with a more literal name
11975
12238
  for agents that are filtering the play registry.
11976
12239
 
11977
12240
  Examples:
11978
12241
  deepline plays search email
12242
+ deepline plays search email --all
11979
12243
  deepline plays grep "linkedin to email" --compact --json
11980
12244
  deepline plays describe person-linkedin-to-email --json
11981
12245
  `
@@ -11983,6 +12247,7 @@ Examples:
11983
12247
  process.exitCode = await handlePlaySearch([
11984
12248
  query,
11985
12249
  ...options.prebuilt ? ["--prebuilt"] : [],
12250
+ ...options.all ? ["--all"] : [],
11986
12251
  ...options.compact ? ["--compact"] : [],
11987
12252
  ...options.json ? ["--json"] : []
11988
12253
  ]);
@@ -13750,7 +14015,7 @@ async function readHiddenLine(prompt) {
13750
14015
  if (typeof input.setRawMode === "function") input.setRawMode(true);
13751
14016
  let value = "";
13752
14017
  input.resume();
13753
- return await new Promise((resolve13, reject) => {
14018
+ return await new Promise((resolve14, reject) => {
13754
14019
  let settled = false;
13755
14020
  const cleanup = () => {
13756
14021
  input.off("data", onData);
@@ -13765,7 +14030,7 @@ async function readHiddenLine(prompt) {
13765
14030
  settled = true;
13766
14031
  output.write("\n");
13767
14032
  cleanup();
13768
- resolve13(line);
14033
+ resolve14(line);
13769
14034
  };
13770
14035
  const fail = (error) => {
13771
14036
  if (settled) return;
@@ -13937,9 +14202,15 @@ Examples:
13937
14202
 
13938
14203
  // src/cli/commands/tools.ts
13939
14204
  import { Option } from "commander";
13940
- 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";
13941
14212
  import { tmpdir as tmpdir4 } from "os";
13942
- import { join as join10 } from "path";
14213
+ import { join as join10, resolve as resolve12 } from "path";
13943
14214
 
13944
14215
  // src/tool-output.ts
13945
14216
  import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync8 } from "fs";
@@ -14530,7 +14801,13 @@ Examples:
14530
14801
  ).option(
14531
14802
  "--json [payload]",
14532
14803
  "Emit JSON output. Use `--input` or `--payload` for passing JSON params."
14533
- ).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(
14534
14811
  "--output-format <format>",
14535
14812
  "Output format: auto, csv, csv_file, json, or json_file"
14536
14813
  ).option(
@@ -15101,6 +15378,57 @@ function normalizeOutputFormat(raw) {
15101
15378
  throw new Error(`Invalid value for --output-format: ${raw}`);
15102
15379
  }
15103
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
+ }
15104
15432
  function parseExecuteOptions(args) {
15105
15433
  const toolId = args[0];
15106
15434
  if (!toolId) {
@@ -15123,12 +15451,15 @@ function parseExecuteOptions(args) {
15123
15451
  const next = args[index + 1];
15124
15452
  outputFormat = "json";
15125
15453
  if (next && !next.startsWith("--")) {
15126
- Object.assign(params, JSON.parse(args[++index]));
15454
+ Object.assign(
15455
+ params,
15456
+ parseJsonObjectArgument(args[++index], "--json")
15457
+ );
15127
15458
  }
15128
15459
  continue;
15129
15460
  }
15130
15461
  if ((arg === "--input" || arg === "--payload") && args[index + 1]) {
15131
- Object.assign(params, JSON.parse(args[++index]));
15462
+ Object.assign(params, parseJsonObjectArgument(args[++index], arg));
15132
15463
  continue;
15133
15464
  }
15134
15465
  if (arg === "--output-format" && args[index + 1]) {
@@ -15448,8 +15779,8 @@ async function executeTool(args) {
15448
15779
 
15449
15780
  // src/cli/commands/update.ts
15450
15781
  import { spawn } from "child_process";
15451
- import { existsSync as existsSync8 } from "fs";
15452
- 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";
15453
15784
  function posixShellQuote(value) {
15454
15785
  return `'${value.replace(/'/g, `'\\''`)}'`;
15455
15786
  }
@@ -15468,9 +15799,9 @@ function buildSourceUpdateCommand(sourceRoot) {
15468
15799
  return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
15469
15800
  }
15470
15801
  function findRepoBackedSdkRoot(startPath) {
15471
- let current = resolve12(startPath);
15802
+ let current = resolve13(startPath);
15472
15803
  while (true) {
15473
- 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"))) {
15474
15805
  return current;
15475
15806
  }
15476
15807
  const parent = dirname9(current);
@@ -15479,7 +15810,7 @@ function findRepoBackedSdkRoot(startPath) {
15479
15810
  }
15480
15811
  }
15481
15812
  function resolveUpdatePlan() {
15482
- const entrypoint = process.argv[1] ? resolve12(process.argv[1]) : "";
15813
+ const entrypoint = process.argv[1] ? resolve13(process.argv[1]) : "";
15483
15814
  const sourceRoot = entrypoint ? findRepoBackedSdkRoot(dirname9(entrypoint)) : null;
15484
15815
  if (sourceRoot) {
15485
15816
  return {
@@ -15713,7 +16044,7 @@ function commandCompatibilityHint(currentFamily, commandName, baseUrl) {
15713
16044
  lines.push(
15714
16045
  "",
15715
16046
  " To stay on the SDK CLI, install the SDK agent skill:",
15716
- ` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
16047
+ ` ${skillsInstallCommand(baseUrl, "deepline-plays")}`,
15717
16048
  " To use the legacy Python CLI instead:",
15718
16049
  ` ${legacyPythonInstallCommand(baseUrl)}`,
15719
16050
  " `deepline update` updates this SDK CLI, but it will not switch CLI families."
@@ -15726,7 +16057,7 @@ function commandCompatibilityHint(currentFamily, commandName, baseUrl) {
15726
16057
  "",
15727
16058
  " To use SDK commands, install the SDK CLI and SDK agent skill:",
15728
16059
  ` ${sdkNpmGlobalInstallCommand()}`,
15729
- ` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
16060
+ ` ${skillsInstallCommand(baseUrl, "deepline-plays")}`,
15730
16061
  " `deepline update` updates this Python CLI and its skills, but it will not switch CLI families."
15731
16062
  );
15732
16063
  if (compatibility.python_alternative) {
@@ -15744,22 +16075,39 @@ function unknownCommandNameFromMessage(message) {
15744
16075
  // src/cli/skills-sync.ts
15745
16076
  import { spawn as spawn2, spawnSync } from "child_process";
15746
16077
  import {
15747
- existsSync as existsSync9,
16078
+ existsSync as existsSync10,
15748
16079
  mkdirSync as mkdirSync5,
15749
16080
  readdirSync as readdirSync2,
15750
- readFileSync as readFileSync7,
16081
+ readFileSync as readFileSync8,
15751
16082
  statSync as statSync2,
15752
16083
  writeFileSync as writeFileSync10
15753
16084
  } from "fs";
15754
16085
  import { homedir as homedir6 } from "os";
15755
16086
  import { dirname as dirname10, join as join12 } from "path";
15756
16087
  var CHECK_TIMEOUT_MS2 = 3e3;
15757
- var SDK_SKILL_NAME = "deepline-sdk";
16088
+ var SDK_SKILL_NAME = "deepline-plays";
15758
16089
  var attemptedSync = false;
15759
16090
  function shouldSkipSkillsSync() {
15760
16091
  const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
15761
16092
  return value === "1" || value === "true" || value === "yes" || value === "on";
15762
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
+ }
15763
16111
  function sdkSkillsVersionPath(baseUrl) {
15764
16112
  const home = process.env.HOME?.trim() || homedir6();
15765
16113
  return join12(
@@ -15772,10 +16120,12 @@ function sdkSkillsVersionPath(baseUrl) {
15772
16120
  );
15773
16121
  }
15774
16122
  function readLocalSkillsVersion(baseUrl) {
16123
+ const pluginVersion = readPluginSkillsVersion();
16124
+ if (pluginVersion) return pluginVersion;
15775
16125
  const path = sdkSkillsVersionPath(baseUrl);
15776
- if (!existsSync9(path)) return "";
16126
+ if (!existsSync10(path)) return "";
15777
16127
  try {
15778
- return readFileSync7(path, "utf-8").trim();
16128
+ return readFileSync8(path, "utf-8").trim();
15779
16129
  } catch {
15780
16130
  return "";
15781
16131
  }
@@ -15788,7 +16138,8 @@ function writeLocalSkillsVersion(baseUrl, version) {
15788
16138
  }
15789
16139
  function installedSdkSkillHasStalePositionalExecuteExamples() {
15790
16140
  const home = process.env.HOME?.trim() || homedir6();
15791
- const roots = [
16141
+ const pluginSkillsDir = activePluginSkillsDir();
16142
+ const roots = pluginSkillsDir ? [join12(pluginSkillsDir, SDK_SKILL_NAME)] : [
15792
16143
  join12(home, ".claude", "skills", SDK_SKILL_NAME),
15793
16144
  join12(home, ".agents", "skills", SDK_SKILL_NAME)
15794
16145
  ];
@@ -15808,14 +16159,14 @@ function installedSdkSkillHasStalePositionalExecuteExamples() {
15808
16159
  continue;
15809
16160
  }
15810
16161
  if (!entry.endsWith(".md")) continue;
15811
- const text = readFileSync7(path, "utf-8");
16162
+ const text = readFileSync8(path, "utf-8");
15812
16163
  if (staleMarkers.some((marker) => text.includes(marker))) return true;
15813
16164
  }
15814
16165
  return false;
15815
16166
  };
15816
16167
  for (const root of roots) {
15817
16168
  try {
15818
- if (existsSync9(root) && scan(root)) return true;
16169
+ if (existsSync10(root) && scan(root)) return true;
15819
16170
  } catch {
15820
16171
  continue;
15821
16172
  }
@@ -15887,7 +16238,7 @@ function resolveSkillsInstallCommands(baseUrl) {
15887
16238
  return [npxInstall];
15888
16239
  }
15889
16240
  function runOneSkillsInstall(install) {
15890
- return new Promise((resolve13) => {
16241
+ return new Promise((resolve14) => {
15891
16242
  const child = spawn2(install.command, install.args, {
15892
16243
  stdio: ["ignore", "ignore", "pipe"],
15893
16244
  env: process.env
@@ -15897,7 +16248,7 @@ function runOneSkillsInstall(install) {
15897
16248
  stderr += chunk.toString("utf-8");
15898
16249
  });
15899
16250
  child.on("error", (error) => {
15900
- resolve13({
16251
+ resolve14({
15901
16252
  ok: false,
15902
16253
  detail: `failed to start ${install.command}: ${error.message}`,
15903
16254
  manualCommand: install.manualCommand
@@ -15905,11 +16256,11 @@ function runOneSkillsInstall(install) {
15905
16256
  });
15906
16257
  child.on("close", (code) => {
15907
16258
  if (code === 0) {
15908
- resolve13({ ok: true, detail: "", manualCommand: install.manualCommand });
16259
+ resolve14({ ok: true, detail: "", manualCommand: install.manualCommand });
15909
16260
  return;
15910
16261
  }
15911
16262
  const detail = stderr.trim();
15912
- resolve13({
16263
+ resolve14({
15913
16264
  ok: false,
15914
16265
  detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
15915
16266
  manualCommand: install.manualCommand
@@ -15946,18 +16297,22 @@ function writeSdkSkillsStatusLine(line) {
15946
16297
  async function syncSdkSkillsIfNeeded(baseUrl) {
15947
16298
  if (attemptedSync || shouldSkipSkillsSync()) return;
15948
16299
  attemptedSync = true;
16300
+ const usingPluginSkills = Boolean(activePluginSkillsDir());
15949
16301
  const localVersion = readLocalSkillsVersion(baseUrl);
15950
16302
  const update = await fetchSkillsUpdate(baseUrl, localVersion);
15951
16303
  const hasStaleInstalledSkill = installedSdkSkillHasStalePositionalExecuteExamples();
16304
+ if (usingPluginSkills) {
16305
+ return;
16306
+ }
15952
16307
  if (!update?.needsUpdate && !hasStaleInstalledSkill || !update?.remoteVersion) {
15953
16308
  return;
15954
16309
  }
15955
- writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-sdk skill...");
16310
+ writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-plays skill...");
15956
16311
  const installed = await runSkillsInstall(baseUrl);
15957
16312
  if (!installed) return;
15958
16313
  if (installedSdkSkillHasStalePositionalExecuteExamples()) {
15959
16314
  process.stderr.write(
15960
- "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"
15961
16316
  );
15962
16317
  return;
15963
16318
  }