deepline 0.2.70 → 0.2.72

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.
@@ -1030,7 +1030,7 @@ var SDK_RELEASE = {
1030
1030
  // 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
1031
1031
  // exposed storage-dependent synchronous access. This deliberate minor
1032
1032
  // release keeps lazy paging semantics independent of row residency.
1033
- version: "0.2.70",
1033
+ version: "0.2.72",
1034
1034
  contracts: {
1035
1035
  api: {
1036
1036
  name: "sdk-http-api",
@@ -3969,16 +3969,9 @@ function isPrebuiltPlayDescription(play) {
3969
3969
  return play.origin === "prebuilt" || play.ownerType === "deepline";
3970
3970
  }
3971
3971
  function preferPrebuiltPlayDescriptions(plays) {
3972
- const prebuilt = [];
3973
- const owned = [];
3974
- for (const play of plays) {
3975
- if (isPrebuiltPlayDescription(play)) {
3976
- prebuilt.push(play);
3977
- } else {
3978
- owned.push(play);
3979
- }
3980
- }
3981
- return [...prebuilt, ...owned];
3972
+ return plays.map((play, index) => ({ play, index })).sort(
3973
+ (left, right) => Number(right.play.pinned) - Number(left.play.pinned) || Number(isPrebuiltPlayDescription(right.play)) - Number(isPrebuiltPlayDescription(left.play)) || left.index - right.index
3974
+ ).map(({ play }) => play);
3982
3975
  }
3983
3976
  function isPlayRunPackage(value) {
3984
3977
  return Boolean(
@@ -4325,6 +4318,8 @@ var DeeplineClient = class {
4325
4318
  ...play.reference ? { reference: play.reference } : {},
4326
4319
  ...play.displayName ? { displayName: play.displayName } : {},
4327
4320
  ...description ? { description } : {},
4321
+ pinned: Boolean(play.pinned),
4322
+ toolCategories: play.toolCategories ?? [],
4328
4323
  origin: play.origin,
4329
4324
  ownerType: play.ownerType,
4330
4325
  canEdit: play.canEdit,
@@ -5823,6 +5818,16 @@ var DeeplineClient = class {
5823
5818
  async listPlays(options) {
5824
5819
  const params = new URLSearchParams();
5825
5820
  if (options?.origin) params.set("origin", options.origin);
5821
+ if (options?.categories) {
5822
+ params.set(
5823
+ "categories",
5824
+ Array.isArray(options.categories) ? options.categories.join(",") : options.categories
5825
+ );
5826
+ }
5827
+ if (options?.categories || options?.includeToolCategories) {
5828
+ params.set("include_tool_categories", "1");
5829
+ }
5830
+ if (options?.includeArchived) params.set("include_archived", "1");
5826
5831
  if (options?.grep?.trim()) {
5827
5832
  params.set("grep", options.grep.trim());
5828
5833
  params.set("grep_mode", options.grepMode ?? "all");
@@ -5834,6 +5839,12 @@ var DeeplineClient = class {
5834
5839
  );
5835
5840
  return response.plays ?? [];
5836
5841
  }
5842
+ /** Set whether an org-owned Play sorts before unpinned Plays. */
5843
+ async setPlayPinned(playName, pinned) {
5844
+ return this.http.post(`/api/v2/plays/${encodeURIComponent(playName)}/pin`, {
5845
+ pinned
5846
+ });
5847
+ }
5837
5848
  /** Read product-notification destinations, subscriptions, event catalog, and DLQ health. */
5838
5849
  async getNotificationSettings() {
5839
5850
  return this.http.get("/api/v2/settings/notifications");
@@ -5967,9 +5978,10 @@ var DeeplineClient = class {
5967
5978
  * console.log(`Total runs: ${detail.play.runCount}`);
5968
5979
  * ```
5969
5980
  */
5970
- async getPlay(name) {
5981
+ async getPlay(name, options) {
5971
5982
  const encodedName = encodeURIComponent(name);
5972
- return this.http.get(`/api/v2/plays/${encodedName}`);
5983
+ const query = options?.source ? `?include=source&revision=${encodeURIComponent(options.source)}` : "";
5984
+ return this.http.get(`/api/v2/plays/${encodedName}${query}`);
5973
5985
  }
5974
5986
  /**
5975
5987
  * Get a normalized play description suitable for agents and CLIs.
@@ -11012,6 +11024,7 @@ import { Option } from "commander";
11012
11024
  import { createHash as createHash4, randomUUID as randomUUID3 } from "crypto";
11013
11025
  import {
11014
11026
  existsSync as existsSync9,
11027
+ mkdirSync as mkdirSync6,
11015
11028
  readFileSync as readFileSync8,
11016
11029
  readdirSync as readdirSync2,
11017
11030
  realpathSync as realpathSync2,
@@ -11025,7 +11038,14 @@ import {
11025
11038
  readFile as readFileAsync,
11026
11039
  unlink
11027
11040
  } from "fs/promises";
11028
- import { basename as basename3, dirname as dirname9, join as join10, resolve as resolve11 } from "path";
11041
+ import {
11042
+ basename as basename3,
11043
+ dirname as dirname9,
11044
+ isAbsolute as isAbsolute5,
11045
+ join as join10,
11046
+ relative as relative4,
11047
+ resolve as resolve11
11048
+ } from "path";
11029
11049
  import { parse as parseCsvSync2 } from "csv-parse/sync";
11030
11050
 
11031
11051
  // src/cli/commands/plays/bootstrap.ts
@@ -18632,7 +18652,10 @@ async function assertCanonicalNamedPlayReference(client2, target, options = {})
18632
18652
  const parsed = parseReferencedPlayTarget2(target);
18633
18653
  let detail;
18634
18654
  try {
18635
- detail = await client2.getPlay(parsed.playName);
18655
+ detail = await client2.getPlay(
18656
+ parsed.playName,
18657
+ options.source ? { source: options.source } : void 0
18658
+ );
18636
18659
  } catch (error) {
18637
18660
  if (isPlayNotFoundError(error)) {
18638
18661
  throw await buildPlayReferenceNotFoundError({
@@ -18685,19 +18708,54 @@ function materializeRemotePlaySource(input2) {
18685
18708
  if (isFileTarget(input2.target)) {
18686
18709
  return null;
18687
18710
  }
18688
- if (!input2.sourceCode.trim()) {
18711
+ const entrySource = input2.source.files[input2.source.entryFile];
18712
+ if (!entrySource?.trim()) {
18689
18713
  return null;
18690
18714
  }
18715
+ const files = Object.entries(input2.source.files);
18716
+ if (files.length > 1) {
18717
+ if (!input2.outPath) {
18718
+ throw new Error(
18719
+ `Play ${input2.playName} has ${files.length} source files. Use --out <directory> to write the complete bundle.`
18720
+ );
18721
+ }
18722
+ const outputDirectory = resolve11(input2.outPath);
18723
+ let created = 0;
18724
+ let updated = 0;
18725
+ for (const [logicalPath, sourceCode] of files) {
18726
+ const outputPath2 = resolve11(outputDirectory, logicalPath);
18727
+ const outputRelativePath = relative4(outputDirectory, outputPath2);
18728
+ if (!outputRelativePath || outputRelativePath.startsWith("..") || isAbsolute5(outputRelativePath)) {
18729
+ throw new Error(
18730
+ `Refusing to materialize unsafe Play source path ${JSON.stringify(logicalPath)}.`
18731
+ );
18732
+ }
18733
+ mkdirSync6(dirname9(outputPath2), { recursive: true });
18734
+ if (!existsSync9(outputPath2)) {
18735
+ writeFileSync9(outputPath2, sourceCode, "utf-8");
18736
+ created += 1;
18737
+ } else if (readFileSync8(outputPath2, "utf-8") !== sourceCode) {
18738
+ writeFileSync9(outputPath2, sourceCode, "utf-8");
18739
+ updated += 1;
18740
+ }
18741
+ }
18742
+ return {
18743
+ path: outputDirectory,
18744
+ status: created > 0 ? "created" : updated > 0 ? "updated" : "unchanged",
18745
+ created: created > 0,
18746
+ fileCount: files.length
18747
+ };
18748
+ }
18691
18749
  const outputPath = input2.outPath ?? defaultMaterializedPlayPath(input2.playName);
18692
18750
  if (existsSync9(outputPath)) {
18693
18751
  const existingSource = readFileSync8(outputPath, "utf-8");
18694
- if (existingSource === input2.sourceCode) {
18752
+ if (existingSource === entrySource) {
18695
18753
  return { path: outputPath, status: "unchanged", created: false };
18696
18754
  }
18697
- writeFileSync9(outputPath, input2.sourceCode, "utf-8");
18755
+ writeFileSync9(outputPath, entrySource, "utf-8");
18698
18756
  return { path: outputPath, status: "updated", created: false };
18699
18757
  }
18700
- writeFileSync9(outputPath, input2.sourceCode, "utf-8");
18758
+ writeFileSync9(outputPath, entrySource, "utf-8");
18701
18759
  return { path: outputPath, status: "created", created: true };
18702
18760
  }
18703
18761
  function formatLoadedPlayMessage(materializedFile) {
@@ -22570,6 +22628,47 @@ ${PLAY_PUBLISH_USAGE}`
22570
22628
  jsonOutput: argsWantJson(args)
22571
22629
  };
22572
22630
  }
22631
+ var PLAY_SAVE_USAGE = "Usage: deepline plays save <play-file.ts> [--expected-artifact <hash>] [--dry-run] [--json]";
22632
+ function parsePlaySaveOptions(args) {
22633
+ const target = args[0];
22634
+ if (!target) throw new Error(PLAY_SAVE_USAGE);
22635
+ if (target.startsWith("-")) {
22636
+ throw new Error(`${PLAY_SAVE_USAGE}
22637
+ The Play file is positional.`);
22638
+ }
22639
+ let expectedArtifactHash;
22640
+ let dryRun = false;
22641
+ for (let index = 1; index < args.length; index += 1) {
22642
+ const arg = args[index];
22643
+ if (arg === "--expected-artifact") {
22644
+ expectedArtifactHash = args[++index];
22645
+ if (!expectedArtifactHash) {
22646
+ throw new Error("--expected-artifact requires an artifact hash.");
22647
+ }
22648
+ continue;
22649
+ }
22650
+ if (arg.startsWith("--expected-artifact=")) {
22651
+ expectedArtifactHash = arg.slice("--expected-artifact=".length);
22652
+ if (!expectedArtifactHash) {
22653
+ throw new Error("--expected-artifact requires an artifact hash.");
22654
+ }
22655
+ continue;
22656
+ }
22657
+ if (arg === "--dry-run") {
22658
+ dryRun = true;
22659
+ continue;
22660
+ }
22661
+ if (arg === "--json") continue;
22662
+ throw new Error(`Unknown option: ${arg}
22663
+ ${PLAY_SAVE_USAGE}`);
22664
+ }
22665
+ return {
22666
+ target,
22667
+ expectedArtifactHash,
22668
+ dryRun,
22669
+ jsonOutput: argsWantJson(args)
22670
+ };
22671
+ }
22573
22672
  function formatByteBudget(usedBytes, limitBytes) {
22574
22673
  return `${usedBytes.toLocaleString()} B / ${limitBytes.toLocaleString()} B`;
22575
22674
  }
@@ -22900,6 +22999,29 @@ function resolvePlayCheckExportNames(sourceCode) {
22900
22999
  if (!exports || exports.length === 0) return [PLAY_DEFAULT_EXPORT];
22901
23000
  return exports.map((entry) => entry.name);
22902
23001
  }
23002
+ function artifactForProductionCompatibilityCheck(artifact) {
23003
+ const rawEdition = process.env.DEEPLINE_PROD_CHECK_AUTHORING_CONTRACT_EDITION?.trim();
23004
+ if (!rawEdition) return artifact;
23005
+ if (!/^\d+$/.test(rawEdition)) {
23006
+ throw new Error(
23007
+ "DEEPLINE_PROD_CHECK_AUTHORING_CONTRACT_EDITION must be a positive integer."
23008
+ );
23009
+ }
23010
+ const edition = Number(rawEdition);
23011
+ if (edition < 1) {
23012
+ throw new Error(
23013
+ "DEEPLINE_PROD_CHECK_AUTHORING_CONTRACT_EDITION must be a positive integer."
23014
+ );
23015
+ }
23016
+ const compatibility = isRecord10(artifact.compatibility) ? artifact.compatibility : {};
23017
+ return {
23018
+ ...artifact,
23019
+ compatibility: {
23020
+ ...compatibility,
23021
+ authoringContractEdition: edition
23022
+ }
23023
+ };
23024
+ }
22903
23025
  async function checkOneExportedPlay(input2) {
22904
23026
  const { absolutePlayPath, sourceCode, exportName } = input2;
22905
23027
  const fallbackName = extractPlayName(sourceCode, absolutePlayPath);
@@ -22939,7 +23061,7 @@ async function checkOneExportedPlay(input2) {
22939
23061
  sourceCode: graph.root.sourceCode,
22940
23062
  sourceFiles: graph.root.sourceFiles,
22941
23063
  description: graph.root.playDescription ?? void 0,
22942
- artifact: graph.root.artifact,
23064
+ artifact: artifactForProductionCompatibilityCheck(graph.root.artifact),
22943
23065
  ...exportName === PLAY_DEFAULT_EXPORT ? {} : { exportName },
22944
23066
  ...importedPlays.length > 0 ? { importedPlays } : {},
22945
23067
  ...integrationMode ? { integrationMode } : {}
@@ -24010,24 +24132,63 @@ async function handlePlayGet(args) {
24010
24132
  const explicitJson = args.includes("--json");
24011
24133
  const sourceOutput = args.includes("--source");
24012
24134
  const jsonOutput = sourceOutput ? explicitJson : argsWantJson(args);
24135
+ const requestedRevisionFlags = [
24136
+ args.includes("--working"),
24137
+ args.includes("--live"),
24138
+ args.includes("--revision")
24139
+ ].filter(Boolean).length;
24140
+ if (requestedRevisionFlags > 1) {
24141
+ console.error("Use only one of --working, --live, or --revision <number>.");
24142
+ return 2;
24143
+ }
24144
+ let sourceSelector = "working";
24145
+ if (args.includes("--live")) {
24146
+ sourceSelector = "live";
24147
+ }
24013
24148
  let outPath = null;
24149
+ let requestedVersion = null;
24014
24150
  for (let index = 1; index < args.length; index += 1) {
24015
24151
  const arg = args[index];
24016
24152
  if (arg === "--out" && args[index + 1]) {
24017
24153
  outPath = resolve11(args[++index]);
24018
24154
  }
24155
+ if (arg === "--revision") {
24156
+ const rawVersion = args[++index];
24157
+ const version = Number(rawVersion);
24158
+ if (!rawVersion || !Number.isInteger(version) || version < 1) {
24159
+ console.error("--revision must be a positive integer.");
24160
+ return 2;
24161
+ }
24162
+ requestedVersion = version;
24163
+ }
24164
+ }
24165
+ if (requestedVersion !== null) {
24166
+ sourceSelector = `version:${requestedVersion}`;
24167
+ }
24168
+ if (requestedRevisionFlags > 0 && !sourceOutput && !outPath) {
24169
+ console.error(
24170
+ "--working, --live, and --revision only apply when reading source with --source or --out."
24171
+ );
24172
+ return 2;
24019
24173
  }
24020
24174
  const playName = isFileTarget(target) ? extractPlayName(readFileSync8(resolve11(target), "utf-8"), resolve11(target)) : parseReferencedPlayTarget2(target).playName;
24021
- const detail = isFileTarget(target) ? await client2.getPlay(playName) : await assertCanonicalNamedPlayReference(client2, target, {
24022
- command: "get"
24023
- });
24024
- const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
24025
- const materializedFile = outPath ? materializeRemotePlaySource({
24026
- target,
24175
+ const includeSource = sourceOutput || outPath !== null;
24176
+ const detail = isFileTarget(target) ? await client2.getPlay(
24027
24177
  playName,
24028
- sourceCode: resolvedSource,
24029
- outPath
24030
- }) : null;
24178
+ includeSource ? { source: sourceSelector } : void 0
24179
+ ) : await assertCanonicalNamedPlayReference(client2, target, {
24180
+ command: "get",
24181
+ ...includeSource ? { source: sourceSelector } : {}
24182
+ });
24183
+ const source = detail.source;
24184
+ const resolvedSource = source?.files[source.entryFile] ?? "";
24185
+ let materializedFile = null;
24186
+ try {
24187
+ materializedFile = outPath && source ? materializeRemotePlaySource({ target, playName, source, outPath }) : null;
24188
+ } catch (error) {
24189
+ console.error(error instanceof Error ? error.message : String(error));
24190
+ return 2;
24191
+ }
24031
24192
  const loadedMessage = materializedFile ? formatLoadedPlayMessage(materializedFile) : null;
24032
24193
  if (jsonOutput) {
24033
24194
  process.stdout.write(
@@ -24048,14 +24209,20 @@ async function handlePlayGet(args) {
24048
24209
  return 0;
24049
24210
  }
24050
24211
  if (sourceOutput) {
24051
- if (!resolvedSource.trim()) {
24212
+ if (!source || !resolvedSource.trim()) {
24052
24213
  console.error(`No source code available for ${playName}.`);
24053
- return 1;
24214
+ return 4;
24054
24215
  }
24055
24216
  if (materializedFile) {
24056
24217
  console.log(loadedMessage);
24057
24218
  return 0;
24058
24219
  }
24220
+ if (Object.keys(source.files).length > 1) {
24221
+ console.error(
24222
+ `Play ${playName} has ${Object.keys(source.files).length} source files. Use --out <directory> to write the complete bundle.`
24223
+ );
24224
+ return 2;
24225
+ }
24059
24226
  process.stdout.write(resolvedSource);
24060
24227
  if (!resolvedSource.endsWith("\n")) {
24061
24228
  process.stdout.write("\n");
@@ -24125,7 +24292,12 @@ async function handlePlayVersions(args) {
24125
24292
  async function handlePlayList(args) {
24126
24293
  const jsonOutput = argsWantJson(args);
24127
24294
  const client2 = new DeeplineClient();
24128
- const plays = await client2.listPlays();
24295
+ const categoriesIndex = args.indexOf("--categories");
24296
+ const categories = categoriesIndex >= 0 ? args[categoriesIndex + 1]?.trim() : void 0;
24297
+ const plays = await client2.listPlays({
24298
+ categories,
24299
+ includeToolCategories: true
24300
+ });
24129
24301
  if (jsonOutput) {
24130
24302
  process.stdout.write(`${JSON.stringify(plays)}
24131
24303
  `);
@@ -24136,6 +24308,8 @@ async function handlePlayList(args) {
24136
24308
  `);
24137
24309
  for (const play of plays) {
24138
24310
  const flags = [
24311
+ play.pinned ? "pinned" : null,
24312
+ ...(play.toolCategories ?? []).map((category) => `category:${category}`),
24139
24313
  play.origin === "prebuilt" || play.ownerType === "deepline" ? "prebuilt" : "owned",
24140
24314
  play.canEdit ? "editable" : "readonly",
24141
24315
  play.isDraftDirty ? "draft-dirty" : null
@@ -24165,6 +24339,36 @@ async function handlePlayList(args) {
24165
24339
  }
24166
24340
  return 0;
24167
24341
  }
24342
+ async function handlePlayPin(args, pinned) {
24343
+ const target = args.find((arg) => !arg.startsWith("-"))?.trim();
24344
+ const jsonOutput = argsWantJson(args);
24345
+ const dryRun = args.includes("--dry-run");
24346
+ if (!target) {
24347
+ console.error(
24348
+ `Usage: deepline plays ${pinned ? "pin" : "unpin"} <play> [--dry-run] [--json]`
24349
+ );
24350
+ return 2;
24351
+ }
24352
+ const parsedTarget = parseReferencedPlayTarget2(target);
24353
+ if (parsedTarget.ownerSlug) {
24354
+ console.error(
24355
+ `deepline plays ${pinned ? "pin" : "unpin"} accepts an org-owned Play identifier without a namespace. Use "${parsedTarget.unqualifiedPlayName}" instead of "${target}".`
24356
+ );
24357
+ return 2;
24358
+ }
24359
+ const name = parsedTarget.playName;
24360
+ const plan = { name, pinned, dryRun };
24361
+ if (dryRun) {
24362
+ process.stdout.write(`${JSON.stringify(plan)}
24363
+ `);
24364
+ return 0;
24365
+ }
24366
+ const result = await new DeeplineClient().setPlayPinned(name, pinned);
24367
+ if (jsonOutput) process.stdout.write(`${JSON.stringify(result)}
24368
+ `);
24369
+ else console.log(`${result.pinned ? "Pinned" : "Unpinned"} ${result.name}.`);
24370
+ return 0;
24371
+ }
24168
24372
  function parsePlaySearchOptions(args) {
24169
24373
  const query = args[0]?.trim();
24170
24374
  if (!query) {
@@ -24199,6 +24403,12 @@ function printPlayDescription(play) {
24199
24403
  if (play.description) {
24200
24404
  console.log(` Description: ${play.description}`);
24201
24405
  }
24406
+ if (play.pinned) {
24407
+ console.log(" Pinned: yes");
24408
+ }
24409
+ if (play.toolCategories?.length) {
24410
+ console.log(` Tool categories: ${play.toolCategories.join(", ")}`);
24411
+ }
24202
24412
  if (play.aliases.length > 0) {
24203
24413
  console.log(` Aliases: ${play.aliases.join(", ")}`);
24204
24414
  }
@@ -24304,6 +24514,8 @@ function summarizePlayListItemForCli(play, options) {
24304
24514
  name: play.name,
24305
24515
  ...play.reference ? { reference: play.reference } : {},
24306
24516
  ...play.displayName ? { displayName: play.displayName } : {},
24517
+ pinned: Boolean(play.pinned),
24518
+ toolCategories: play.toolCategories ?? [],
24307
24519
  origin: play.origin,
24308
24520
  ownerType: play.ownerType,
24309
24521
  canEdit: play.canEdit,
@@ -24434,6 +24646,7 @@ async function handlePlayGrep(args) {
24434
24646
  origin: play.origin,
24435
24647
  ownerType: play.ownerType,
24436
24648
  aliases: play.aliases,
24649
+ toolCategories: play.toolCategories,
24437
24650
  inputSchema: play.inputSchema,
24438
24651
  outputSchema: play.outputSchema
24439
24652
  },
@@ -24531,6 +24744,128 @@ async function handlePlayDescribe(args) {
24531
24744
  printPlayDescription(play);
24532
24745
  return 0;
24533
24746
  }
24747
+ async function handlePlaySave(args) {
24748
+ let options;
24749
+ try {
24750
+ options = parsePlaySaveOptions(args);
24751
+ } catch (error) {
24752
+ console.error(error instanceof Error ? error.message : String(error));
24753
+ return 2;
24754
+ }
24755
+ if (!isFileTarget(options.target)) {
24756
+ console.error(
24757
+ "plays save requires a local .play.ts file. Use plays publish <play-name> to promote an existing saved revision."
24758
+ );
24759
+ return 2;
24760
+ }
24761
+ let graph;
24762
+ try {
24763
+ graph = await traceCliSpan(
24764
+ "cli.play_save_bundle_graph",
24765
+ { targetKind: "file" },
24766
+ () => collectBundledPlayGraph(resolve11(options.target))
24767
+ );
24768
+ assertBundledPlayGraphDescriptions(graph);
24769
+ } catch (error) {
24770
+ console.error(error instanceof Error ? error.message : String(error));
24771
+ return 7;
24772
+ }
24773
+ const playName = graph.root.playName ?? extractPlayName(graph.root.sourceCode, graph.root.filePath);
24774
+ const artifactHash = graph.root.artifact.artifactHash;
24775
+ if (options.expectedArtifactHash && options.expectedArtifactHash !== artifactHash) {
24776
+ const result = {
24777
+ ok: false,
24778
+ code: "PLAY_ARTIFACT_HASH_MISMATCH",
24779
+ message: "Refusing to save: the local file no longer produces the artifact checked earlier.",
24780
+ expectedArtifactHash: options.expectedArtifactHash,
24781
+ currentArtifactHash: artifactHash,
24782
+ next: `deepline plays check ${shellQuote2(options.target)}`
24783
+ };
24784
+ if (options.jsonOutput) {
24785
+ process.stdout.write(`${JSON.stringify(result)}
24786
+ `);
24787
+ } else {
24788
+ console.error(result.message);
24789
+ console.error(` checked artifact: ${result.expectedArtifactHash}`);
24790
+ console.error(` current artifact: ${result.currentArtifactHash}`);
24791
+ console.error(` run: ${result.next}`);
24792
+ }
24793
+ return 7;
24794
+ }
24795
+ const dryRun = {
24796
+ ok: true,
24797
+ dryRun: true,
24798
+ name: playName,
24799
+ sourcePath: graph.root.filePath,
24800
+ sourceHash: graph.root.artifact.sourceHash,
24801
+ artifactHash,
24802
+ graphHash: graph.root.artifact.graphHash,
24803
+ sourceFileCount: Object.keys(graph.root.sourceFiles).length,
24804
+ plannedMutation: "save or update the mutable working draft; does not change the live revision"
24805
+ };
24806
+ if (options.dryRun) {
24807
+ if (options.jsonOutput) {
24808
+ process.stdout.write(`${JSON.stringify(dryRun)}
24809
+ `);
24810
+ } else {
24811
+ console.log(`Dry run: ${playName}`);
24812
+ console.log(` source: ${dryRun.sourceHash}`);
24813
+ console.log(` artifact: ${dryRun.artifactHash}`);
24814
+ console.log(` would: ${dryRun.plannedMutation}`);
24815
+ }
24816
+ return 0;
24817
+ }
24818
+ const client2 = new DeeplineClient();
24819
+ try {
24820
+ await traceCliSpan(
24821
+ "cli.play_save_compile_manifests",
24822
+ { targetKind: "file", nodeCount: graph.nodes.size },
24823
+ () => compileBundledPlayGraphManifests(client2, graph)
24824
+ );
24825
+ const saved = await traceCliSpan(
24826
+ "cli.play_save_register_draft",
24827
+ { targetKind: "file", playName, artifactHash },
24828
+ () => client2.registerPlayArtifact({
24829
+ name: playName,
24830
+ sourceCode: graph.root.sourceCode,
24831
+ sourceFiles: graph.root.sourceFiles,
24832
+ description: graph.root.playDescription ?? void 0,
24833
+ artifact: graph.root.artifact,
24834
+ compilerManifest: requireCompilerManifest(graph.root),
24835
+ publish: false
24836
+ })
24837
+ );
24838
+ const result = {
24839
+ success: true,
24840
+ name: playName,
24841
+ draft: true,
24842
+ revisionId: saved.revisionId ?? null,
24843
+ version: saved.version ?? null,
24844
+ sourceHash: graph.root.artifact.sourceHash,
24845
+ artifactHash,
24846
+ graphHash: graph.root.artifact.graphHash,
24847
+ artifactStorageKey: saved.artifactStorageKey,
24848
+ next: {
24849
+ publish: `deepline plays publish ${shellQuote2(options.target)} --expected-artifact ${artifactHash}`,
24850
+ get: `deepline plays get ${playName} --source --out ./${playName}/ --working`
24851
+ }
24852
+ };
24853
+ if (options.jsonOutput) {
24854
+ process.stdout.write(`${JSON.stringify(result)}
24855
+ `);
24856
+ } else {
24857
+ console.log(
24858
+ `\u2713 Saved ${playName} working draft as v${result.version ?? "?"}`
24859
+ );
24860
+ console.log(" Live revision unchanged.");
24861
+ console.log(` publish: ${result.next.publish}`);
24862
+ }
24863
+ return 0;
24864
+ } catch (error) {
24865
+ console.error(error instanceof Error ? error.message : String(error));
24866
+ return 5;
24867
+ }
24868
+ }
24534
24869
  async function handlePlayPublish(args) {
24535
24870
  let options;
24536
24871
  try {
@@ -25061,7 +25396,9 @@ Pass-through input flags:
25061
25396
  ]);
25062
25397
  });
25063
25398
  registerPlayBootstrapCommand(play);
25064
- play.command("get <target>").description("Fetch full play details.").addHelpText(
25399
+ play.command("get <target>").description(
25400
+ "Fetch full play details or materialize a saved source bundle."
25401
+ ).addHelpText(
25065
25402
  "after",
25066
25403
  `
25067
25404
  Notes:
@@ -25073,17 +25410,24 @@ Examples:
25073
25410
  deepline plays get prebuilt/person-linkedin-to-email
25074
25411
  deepline plays get prebuilt/person-linkedin-to-email --json | jq '.play.liveRevision'
25075
25412
  deepline plays get prebuilt/name-and-domain-to-email-waterfall-batch --source > email-waterfall.play.ts
25076
- deepline plays get prebuilt/name-and-domain-to-email-waterfall-batch --source --out ./email-waterfall.play.ts
25413
+ deepline plays get my-play --source --out ./my-play/ --working
25414
+ deepline plays get my-play --source --out ./my-play-v3/ --revision 3
25077
25415
  `
25078
25416
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
25079
25417
  "--source",
25080
- "Print raw source code; combine with --out to write a file"
25081
- ).option("--out <path>", "Write source to a specific path").action(async (target, options) => {
25418
+ "Read source; prints single-file Plays or combines with --out to write the full bundle"
25419
+ ).option(
25420
+ "--out <path>",
25421
+ "Write source to a file or, for multi-file Plays, a directory"
25422
+ ).option("--working", "Read the current working draft source (default)").option("--live", "Read the live revision source").option("--revision <number>", "Read a specific revision source").action(async (target, options) => {
25082
25423
  process.exitCode = await handlePlayGet([
25083
25424
  target,
25084
25425
  ...options.json ? ["--json"] : [],
25085
25426
  ...options.source ? ["--source"] : [],
25086
- ...options.out ? ["--out", options.out] : []
25427
+ ...options.out ? ["--out", options.out] : [],
25428
+ ...options.working ? ["--working"] : [],
25429
+ ...options.live ? ["--live"] : [],
25430
+ ...options.revision ? ["--revision", options.revision] : []
25087
25431
  ]);
25088
25432
  });
25089
25433
  play.command("list").description("List saved and prebuilt plays.").addHelpText(
@@ -25097,11 +25441,35 @@ Examples:
25097
25441
  deepline plays list
25098
25442
  deepline plays search email --json
25099
25443
  `
25100
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
25444
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
25445
+ "--categories <categories>",
25446
+ "Filter by comma-separated canonical tool categories"
25447
+ ).action(async (options) => {
25101
25448
  process.exitCode = await handlePlayList([
25449
+ ...options.categories ? ["--categories", options.categories] : [],
25102
25450
  ...options.json ? ["--json"] : []
25103
25451
  ]);
25104
25452
  });
25453
+ play.command("pin <target>").description("Pin an org-owned play to the top of play listings.").option("--dry-run", "Print the planned change without saving it").option("--json", "Emit JSON output").action(async (target, options) => {
25454
+ process.exitCode = await handlePlayPin(
25455
+ [
25456
+ target,
25457
+ ...options.dryRun ? ["--dry-run"] : [],
25458
+ ...options.json ? ["--json"] : []
25459
+ ],
25460
+ true
25461
+ );
25462
+ });
25463
+ play.command("unpin <target>").description("Remove an org-owned play from the pinned group.").option("--dry-run", "Print the planned change without saving it").option("--json", "Emit JSON output").action(async (target, options) => {
25464
+ process.exitCode = await handlePlayPin(
25465
+ [
25466
+ target,
25467
+ ...options.dryRun ? ["--dry-run"] : [],
25468
+ ...options.json ? ["--json"] : []
25469
+ ],
25470
+ false
25471
+ );
25472
+ });
25105
25473
  const addPlaySearchCommand = (command) => command.description("Search Deepline prebuilt plays by task.").option(
25106
25474
  "--prebuilt",
25107
25475
  "Only show Deepline-managed prebuilt plays (default)"
@@ -25194,6 +25562,32 @@ Examples:
25194
25562
  ...options.json ? ["--json"] : []
25195
25563
  ]);
25196
25564
  });
25565
+ play.command("save <file>").description(
25566
+ "Save or update a local Play working draft without publishing it."
25567
+ ).addHelpText(
25568
+ "after",
25569
+ `
25570
+ Notes:
25571
+ Mutates cloud state, but does not change the live revision or active triggers.
25572
+ Repeated saves update one working draft. Publishing it, or running a named
25573
+ draft revision, freezes it; the next save starts a new revision.
25574
+
25575
+ Examples:
25576
+ deepline plays save ./company-research.play.ts
25577
+ deepline plays save ./company-research.play.ts --dry-run --json
25578
+ deepline plays publish ./company-research.play.ts
25579
+ `
25580
+ ).option("--expected-artifact <hash>", "Require the checked artifact hash").option(
25581
+ "--dry-run",
25582
+ "Bundle and show the planned draft save without mutation"
25583
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (file, options) => {
25584
+ process.exitCode = await handlePlaySave([
25585
+ file,
25586
+ ...options.expectedArtifact ? ["--expected-artifact", options.expectedArtifact] : [],
25587
+ ...options.dryRun ? ["--dry-run"] : [],
25588
+ ...options.json ? ["--json"] : []
25589
+ ]);
25590
+ });
25197
25591
  const addPublishHelp = (command) => command.addHelpText(
25198
25592
  "after",
25199
25593
  `
@@ -26456,10 +26850,12 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
26456
26850
  const metadataColumnSource = renderMetadataColumnStep(config);
26457
26851
  const generatedAliases = collectGeneratedAliases(config.commands);
26458
26852
  const runOptionsSource = options.failFast ? `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart), onRowError: 'fail' as const }` : `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart) }`;
26853
+ const describedColumns = config.commands.filter((command) => isWaterfall(command) || !command.disabled).map(
26854
+ (command) => (isWaterfall(command) ? command.with_waterfall : command.alias).replace(/[_-]+/g, " ").trim()
26855
+ ).filter(Boolean).slice(0, 3);
26856
+ const generatedDescription = describedColumns.length ? `Enrich CSV rows with ${describedColumns.join(", ")}.` : "Prepare CSV rows for enrichment.";
26459
26857
  const playOptionsSource = [
26460
- `description: ${stringLiteral(
26461
- "Read a CSV file, run the configured Deepline enrich commands, and return enriched rows."
26462
- )}`,
26858
+ `description: ${stringLiteral(generatedDescription)}`,
26463
26859
  ...options.maxCreditsPerRun === void 0 ? [] : [`billing: { maxCreditsPerRun: ${String(options.maxCreditsPerRun)} }`]
26464
26860
  ].join(", ");
26465
26861
  const body = [
@@ -31152,7 +31548,7 @@ Examples:
31152
31548
  // src/cli/commands/sessions.ts
31153
31549
  import {
31154
31550
  existsSync as existsSync10,
31155
- mkdirSync as mkdirSync6,
31551
+ mkdirSync as mkdirSync7,
31156
31552
  readdirSync as readdirSync3,
31157
31553
  readFileSync as readFileSync9,
31158
31554
  statSync as statSync4,
@@ -31753,13 +32149,13 @@ async function handleSessionsRender(options) {
31753
32149
  let outputPath = options.output ? resolve13(options.output) : "";
31754
32150
  if (!outputPath) {
31755
32151
  const outputDir = join12(process.cwd(), "deepline", "data");
31756
- mkdirSync6(outputDir, { recursive: true });
32152
+ mkdirSync7(outputDir, { recursive: true });
31757
32153
  outputPath = join12(
31758
32154
  outputDir,
31759
32155
  targets.length > 1 ? "session-viewer.html" : `session-${targets[0]?.sessionId}.html`
31760
32156
  );
31761
32157
  } else {
31762
- mkdirSync6(dirname11(outputPath), { recursive: true });
32158
+ mkdirSync7(dirname11(outputPath), { recursive: true });
31763
32159
  }
31764
32160
  const sessions = targets.map((target) => ({
31765
32161
  label: target.label,
@@ -34013,18 +34409,18 @@ import { spawnSync } from "child_process";
34013
34409
  import {
34014
34410
  existsSync as existsSync12,
34015
34411
  lstatSync,
34016
- mkdirSync as mkdirSync8,
34412
+ mkdirSync as mkdirSync9,
34017
34413
  readFileSync as readFileSync12,
34018
34414
  realpathSync as realpathSync3,
34019
34415
  rmSync as rmSync4,
34020
34416
  writeFileSync as writeFileSync12
34021
34417
  } from "fs";
34022
34418
  import { homedir as homedir10 } from "os";
34023
- import { basename as basename6, dirname as dirname13, join as join14, relative as relative4, resolve as resolve14 } from "path";
34419
+ import { basename as basename6, dirname as dirname13, join as join14, relative as relative5, resolve as resolve14 } from "path";
34024
34420
 
34025
34421
  // src/cli/commands/skills.ts
34026
34422
  import { spawn as spawn2 } from "child_process";
34027
- import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync11 } from "fs";
34423
+ import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync11 } from "fs";
34028
34424
  import { homedir as homedir9 } from "os";
34029
34425
  import { dirname as dirname12, join as join13 } from "path";
34030
34426
 
@@ -34450,7 +34846,7 @@ async function runSkillsCommand(options, dependencies = {}) {
34450
34846
  );
34451
34847
  return 5;
34452
34848
  }
34453
- mkdirSync7(dirname12(plan.statePath), { recursive: true });
34849
+ mkdirSync8(dirname12(plan.statePath), { recursive: true });
34454
34850
  writeFileSync11(
34455
34851
  plan.statePath,
34456
34852
  `${JSON.stringify(
@@ -34713,7 +35109,7 @@ function removeKnownLegacyPaths(baseUrl) {
34713
35109
  const installerCommandPath = safeRead(
34714
35110
  join14(hostDir, "sdk", ".command-path")
34715
35111
  ).trim();
34716
- const relativeInstallerCommandPath = installerCommandPath ? relative4(resolve14(hostDir), resolve14(installerCommandPath)) : "";
35112
+ const relativeInstallerCommandPath = installerCommandPath ? relative5(resolve14(hostDir), resolve14(installerCommandPath)) : "";
34717
35113
  const isOwnedInstallerCommand = Boolean(installerCommandPath) && relativeInstallerCommandPath !== "" && !relativeInstallerCommandPath.startsWith(
34718
35114
  `..${process.platform === "win32" ? "\\" : "/"}`
34719
35115
  ) && relativeInstallerCommandPath !== ".." && basename6(installerCommandPath) === "deepline";
@@ -34827,7 +35223,7 @@ function inspectPathConflict() {
34827
35223
  }
34828
35224
  function writeSetupState(input2) {
34829
35225
  const path = setupStatePath(input2.baseUrl, input2.scope, input2.root);
34830
- mkdirSync8(dirname13(path), { recursive: true });
35226
+ mkdirSync9(dirname13(path), { recursive: true });
34831
35227
  writeFileSync12(
34832
35228
  path,
34833
35229
  `${JSON.stringify(
@@ -36069,7 +36465,7 @@ chooses the connected Slack channel and the events it receives.
36069
36465
  }
36070
36466
 
36071
36467
  // src/cli/commands/switch.ts
36072
- import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "fs";
36468
+ import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "fs";
36073
36469
  import { homedir as homedir11 } from "os";
36074
36470
  import { dirname as dirname14, join as join15 } from "path";
36075
36471
  function hostSlugFromBaseUrl(baseUrl) {
@@ -36111,7 +36507,7 @@ function readActiveFamily() {
36111
36507
  }
36112
36508
  function writeActiveFamily(family) {
36113
36509
  const path = activeFamilyPath();
36114
- mkdirSync9(dirname14(path), { recursive: true });
36510
+ mkdirSync10(dirname14(path), { recursive: true });
36115
36511
  writeFileSync13(path, `${family}
36116
36512
  `, "utf-8");
36117
36513
  return path;
@@ -36242,7 +36638,7 @@ import { join as join17, resolve as resolve15 } from "path";
36242
36638
  // src/tool-output.ts
36243
36639
  import {
36244
36640
  closeSync as closeSync3,
36245
- mkdirSync as mkdirSync10,
36641
+ mkdirSync as mkdirSync11,
36246
36642
  openSync as openSync3,
36247
36643
  writeFileSync as writeFileSync14,
36248
36644
  writeSync
@@ -36376,7 +36772,7 @@ function projectRowOutput(conversion) {
36376
36772
  }
36377
36773
  function ensureOutputDir() {
36378
36774
  const outputDir = join16(homedir12(), ".local", "share", "deepline", "data");
36379
- mkdirSync10(outputDir, { recursive: true });
36775
+ mkdirSync11(outputDir, { recursive: true });
36380
36776
  return outputDir;
36381
36777
  }
36382
36778
  function writeJsonOutputFile(payload, stem) {
@@ -36387,7 +36783,7 @@ function writeJsonOutputFile(payload, stem) {
36387
36783
  }
36388
36784
  function writeCsvOutputFile(rows, stem, options) {
36389
36785
  const outputPath = options?.outPath ? options.outPath : join16(ensureOutputDir(), `${stem}_${Date.now()}.csv`);
36390
- mkdirSync10(dirname15(outputPath), { recursive: true });
36786
+ mkdirSync11(dirname15(outputPath), { recursive: true });
36391
36787
  const columns = columnsForRows(rows);
36392
36788
  const escapeCell = (value) => {
36393
36789
  const normalized = value == null ? "" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
@@ -38865,7 +39261,7 @@ Examples:
38865
39261
  import { spawn as spawn3 } from "child_process";
38866
39262
  import {
38867
39263
  existsSync as existsSync16,
38868
- mkdirSync as mkdirSync11,
39264
+ mkdirSync as mkdirSync12,
38869
39265
  realpathSync as realpathSync4,
38870
39266
  readFileSync as readFileSync16,
38871
39267
  renameSync,
@@ -38874,12 +39270,12 @@ import {
38874
39270
  writeFileSync as writeFileSync16
38875
39271
  } from "fs";
38876
39272
  import { homedir as homedir13 } from "os";
38877
- import { dirname as dirname16, isAbsolute as isAbsolute6, join as join19, relative as relative6, resolve as resolve17 } from "path";
39273
+ import { dirname as dirname16, isAbsolute as isAbsolute7, join as join19, relative as relative7, resolve as resolve17 } from "path";
38878
39274
 
38879
39275
  // src/cli/install-integrity.ts
38880
39276
  import { createRequire } from "module";
38881
39277
  import { existsSync as existsSync15, readFileSync as readFileSync15, statSync as statSync5 } from "fs";
38882
- import { isAbsolute as isAbsolute5, join as join18, relative as relative5, resolve as resolve16 } from "path";
39278
+ import { isAbsolute as isAbsolute6, join as join18, relative as relative6, resolve as resolve16 } from "path";
38883
39279
  var SDK_SIDECAR_CRITICAL_PACKAGE_FILES = [
38884
39280
  "dist/cli/index.mjs",
38885
39281
  "dist/index.mjs",
@@ -38896,7 +39292,7 @@ var SDK_SIDECAR_CRITICAL_DEPENDENCY_FILES = [
38896
39292
  "esbuild/lib/main.js"
38897
39293
  ];
38898
39294
  function safeRelativePath(value) {
38899
- if (typeof value !== "string" || !value || isAbsolute5(value)) return false;
39295
+ if (typeof value !== "string" || !value || isAbsolute6(value)) return false;
38900
39296
  const segments = value.split(/[\\/]+/);
38901
39297
  return segments.every(
38902
39298
  (segment) => Boolean(segment) && segment !== "." && segment !== ".."
@@ -38905,8 +39301,8 @@ function safeRelativePath(value) {
38905
39301
  function resolveContainedPath(root, value) {
38906
39302
  if (!safeRelativePath(value)) return null;
38907
39303
  const target = resolve16(root, value);
38908
- const relativeTarget = relative5(resolve16(root), target);
38909
- if (!relativeTarget || relativeTarget.startsWith("..") || isAbsolute5(relativeTarget)) {
39304
+ const relativeTarget = relative6(resolve16(root), target);
39305
+ if (!relativeTarget || relativeTarget.startsWith("..") || isAbsolute6(relativeTarget)) {
38910
39306
  return null;
38911
39307
  }
38912
39308
  return target;
@@ -39127,11 +39523,11 @@ function readOptionalText(path) {
39127
39523
  function resolvePythonSidecarUpdatePlan(options) {
39128
39524
  const stateDir = sidecarStateDir(options);
39129
39525
  if (!stateDir) return null;
39130
- const relativeEntrypoint = relative6(
39526
+ const relativeEntrypoint = relative7(
39131
39527
  resolve17(stateDir),
39132
39528
  resolve17(options.entrypoint)
39133
39529
  );
39134
- if (!relativeEntrypoint || relativeEntrypoint.startsWith("..") || isAbsolute6(relativeEntrypoint)) {
39530
+ if (!relativeEntrypoint || relativeEntrypoint.startsWith("..") || isAbsolute7(relativeEntrypoint)) {
39135
39531
  return null;
39136
39532
  }
39137
39533
  const installMethod = readOptionalText(join19(stateDir, ".install-method"));
@@ -39298,7 +39694,7 @@ function writeAutoUpdateFailure(plan, exitCode) {
39298
39694
  manualCommand: plan.manualCommand
39299
39695
  };
39300
39696
  try {
39301
- mkdirSync11(dirname16(path), { recursive: true });
39697
+ mkdirSync12(dirname16(path), { recursive: true });
39302
39698
  writeFileSync16(path, `${JSON.stringify(marker, null, 2)}
39303
39699
  `, "utf8");
39304
39700
  } catch {
@@ -39478,7 +39874,7 @@ async function runNpmInstallWithRegistryFallback(input2) {
39478
39874
  return first.exitCode;
39479
39875
  }
39480
39876
  function writeSidecarLauncher(input2) {
39481
- mkdirSync11(dirname16(input2.path), { recursive: true });
39877
+ mkdirSync12(dirname16(input2.path), { recursive: true });
39482
39878
  const packageRoot = dirname16(dirname16(dirname16(input2.entryPath)));
39483
39879
  const versionDir = dirname16(dirname16(packageRoot));
39484
39880
  const esbuildProbe = "const {createRequire}=require('node:module');const path=require('node:path');const req=createRequire(path.join(process.argv[1],'package.json'));const result=req('esbuild').transformSync('const value: number = 1;',{loader:'ts'});if(!result||typeof result.code!=='string')process.exit(3);";
@@ -39547,7 +39943,7 @@ async function runPythonSidecarUpdatePlan(plan) {
39547
39943
  `.tmp-sdk-update-${process.pid}-${Date.now()}`
39548
39944
  );
39549
39945
  rmSync5(tempDir, { recursive: true, force: true });
39550
- mkdirSync11(tempDir, { recursive: true });
39946
+ mkdirSync12(tempDir, { recursive: true });
39551
39947
  writeFileSync16(join19(tempDir, "package.json"), NPM_SDK_SIDECAR_PACKAGE_JSON);
39552
39948
  const env = {
39553
39949
  ...process.env,
@@ -40556,7 +40952,7 @@ async function maybeAutoUpdateAndRelaunch(response) {
40556
40952
  import { spawn as spawn5, spawnSync as spawnSync2 } from "child_process";
40557
40953
  import {
40558
40954
  existsSync as existsSync17,
40559
- mkdirSync as mkdirSync12,
40955
+ mkdirSync as mkdirSync13,
40560
40956
  readFileSync as readFileSync17,
40561
40957
  unlinkSync as unlinkSync2,
40562
40958
  writeFileSync as writeFileSync17
@@ -40609,7 +41005,7 @@ function readSdkSkillsLocalVersion(baseUrl) {
40609
41005
  }
40610
41006
  function writeLocalSkillsVersion(baseUrl, version) {
40611
41007
  const path = sdkSkillsVersionPath(baseUrl);
40612
- mkdirSync12(dirname18(path), { recursive: true });
41008
+ mkdirSync13(dirname18(path), { recursive: true });
40613
41009
  writeFileSync17(path, `${version}
40614
41010
  `, "utf-8");
40615
41011
  }
@@ -40619,7 +41015,7 @@ function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames) {
40619
41015
  if (existsSync17(path) && readFileSync17(path, "utf-8").trim() === remoteVersion) {
40620
41016
  return;
40621
41017
  }
40622
- mkdirSync12(dirname18(path), { recursive: true });
41018
+ mkdirSync13(dirname18(path), { recursive: true });
40623
41019
  writeFileSync17(path, `${remoteVersion}
40624
41020
  `, "utf-8");
40625
41021
  } catch {