deepline 0.2.70 → 0.2.71

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.
@@ -1156,16 +1156,16 @@ function isPrebuiltPlayDescription(
1156
1156
  function preferPrebuiltPlayDescriptions<T extends PlayDescription>(
1157
1157
  plays: T[],
1158
1158
  ): T[] {
1159
- const prebuilt: T[] = [];
1160
- const owned: T[] = [];
1161
- for (const play of plays) {
1162
- if (isPrebuiltPlayDescription(play)) {
1163
- prebuilt.push(play);
1164
- } else {
1165
- owned.push(play);
1166
- }
1167
- }
1168
- return [...prebuilt, ...owned];
1159
+ return plays
1160
+ .map((play, index) => ({ play, index }))
1161
+ .sort(
1162
+ (left, right) =>
1163
+ Number(right.play.pinned) - Number(left.play.pinned) ||
1164
+ Number(isPrebuiltPlayDescription(right.play)) -
1165
+ Number(isPrebuiltPlayDescription(left.play)) ||
1166
+ left.index - right.index,
1167
+ )
1168
+ .map(({ play }) => play);
1169
1169
  }
1170
1170
 
1171
1171
  function isPlayRunPackage(value: unknown): value is PlayRunPackage {
@@ -1775,6 +1775,8 @@ export class DeeplineClient {
1775
1775
  ...(play.reference ? { reference: play.reference } : {}),
1776
1776
  ...(play.displayName ? { displayName: play.displayName } : {}),
1777
1777
  ...(description ? { description } : {}),
1778
+ pinned: Boolean(play.pinned),
1779
+ toolCategories: play.toolCategories ?? [],
1778
1780
  origin: play.origin,
1779
1781
  ownerType: play.ownerType,
1780
1782
  canEdit: play.canEdit,
@@ -3778,9 +3780,24 @@ export class DeeplineClient {
3778
3780
  origin?: 'prebuilt' | 'owned';
3779
3781
  grep?: string;
3780
3782
  grepMode?: 'all' | 'any' | 'phrase';
3783
+ categories?: string | string[];
3784
+ includeToolCategories?: boolean;
3785
+ includeArchived?: boolean;
3781
3786
  }): Promise<PlayListItem[]> {
3782
3787
  const params = new URLSearchParams();
3783
3788
  if (options?.origin) params.set('origin', options.origin);
3789
+ if (options?.categories) {
3790
+ params.set(
3791
+ 'categories',
3792
+ Array.isArray(options.categories)
3793
+ ? options.categories.join(',')
3794
+ : options.categories,
3795
+ );
3796
+ }
3797
+ if (options?.categories || options?.includeToolCategories) {
3798
+ params.set('include_tool_categories', '1');
3799
+ }
3800
+ if (options?.includeArchived) params.set('include_archived', '1');
3784
3801
  if (options?.grep?.trim()) {
3785
3802
  params.set('grep', options.grep.trim());
3786
3803
  params.set('grep_mode', options.grepMode ?? 'all');
@@ -3793,6 +3810,16 @@ export class DeeplineClient {
3793
3810
  return response.plays ?? [];
3794
3811
  }
3795
3812
 
3813
+ /** Set whether an org-owned Play sorts before unpinned Plays. */
3814
+ async setPlayPinned(
3815
+ playName: string,
3816
+ pinned: boolean,
3817
+ ): Promise<{ name: string; pinned: boolean }> {
3818
+ return this.http.post(`/api/v2/plays/${encodeURIComponent(playName)}/pin`, {
3819
+ pinned,
3820
+ });
3821
+ }
3822
+
3796
3823
  /** Read product-notification destinations, subscriptions, event catalog, and DLQ health. */
3797
3824
  async getNotificationSettings(): Promise<ProductNotificationSettings> {
3798
3825
  return this.http.get('/api/v2/settings/notifications');
@@ -183,7 +183,7 @@ export const SDK_RELEASE = {
183
183
  // 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
184
184
  // exposed storage-dependent synchronous access. This deliberate minor
185
185
  // release keeps lazy paging semantics independent of row residency.
186
- version: '0.2.70',
186
+ version: '0.2.71',
187
187
  contracts: {
188
188
  api: {
189
189
  name: 'sdk-http-api',
@@ -1010,6 +1010,10 @@ export interface PlayDefinitionDetail {
1010
1010
  name: string;
1011
1011
  /** Human-friendly display name for UI surfaces. */
1012
1012
  displayName?: string;
1013
+ /** Whether this Play sorts before unpinned Plays. */
1014
+ pinned?: boolean;
1015
+ /** Canonical categories declared by tools used in this Play. */
1016
+ toolCategories?: string[];
1013
1017
  /** Whether this entry comes from the Deepline prebuilt registry or the org-owned catalog. */
1014
1018
  origin?: 'prebuilt' | 'owned';
1015
1019
  /** Ownership class used for permissions and badges. */
@@ -1064,6 +1068,8 @@ export interface PlayListItem {
1064
1068
  name: string;
1065
1069
  displayName?: string;
1066
1070
  description?: string | null;
1071
+ pinned?: boolean;
1072
+ toolCategories?: string[];
1067
1073
  origin?: 'prebuilt' | 'owned';
1068
1074
  ownerType?: 'deepline' | 'org';
1069
1075
  ownerSlug?: string;
@@ -1135,6 +1141,8 @@ export interface PlayDescription {
1135
1141
  reference?: string;
1136
1142
  displayName?: string;
1137
1143
  description?: string | null;
1144
+ pinned?: boolean;
1145
+ toolCategories?: string[];
1138
1146
  origin?: 'prebuilt' | 'owned';
1139
1147
  ownerType?: 'deepline' | 'org';
1140
1148
  canEdit?: boolean;
@@ -38,7 +38,7 @@ export const PLAY_AUTHORING_CONTRACT_CHANGELOG = [
38
38
  changed:
39
39
  'Materializes the declared input schema in the admitted snapshot so launch never reparses current source.',
40
40
  compatibilityOwner: 'Plays Runtime',
41
- newWritesEnd: null,
41
+ newWritesEnd: '2026-08-19',
42
42
  readerRemoval: null,
43
43
  },
44
44
  ] as const;
@@ -691,10 +691,20 @@ export function compileEnrichConfigToPlaySource(
691
691
  const runOptionsSource = options.failFast
692
692
  ? `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart), onRowError: 'fail' as const }`
693
693
  : `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart) }`;
694
+ const describedColumns = config.commands
695
+ .filter((command) => isWaterfall(command) || !command.disabled)
696
+ .map((command) =>
697
+ (isWaterfall(command) ? command.with_waterfall : command.alias)
698
+ .replace(/[_-]+/g, ' ')
699
+ .trim(),
700
+ )
701
+ .filter(Boolean)
702
+ .slice(0, 3);
703
+ const generatedDescription = describedColumns.length
704
+ ? `Enrich CSV rows with ${describedColumns.join(', ')}.`
705
+ : 'Prepare CSV rows for enrichment.';
694
706
  const playOptionsSource = [
695
- `description: ${stringLiteral(
696
- 'Read a CSV file, run the configured Deepline enrich commands, and return enriched rows.',
697
- )}`,
707
+ `description: ${stringLiteral(generatedDescription)}`,
698
708
  ...(options.maxCreditsPerRun === undefined
699
709
  ? []
700
710
  : [`billing: { maxCreditsPerRun: ${String(options.maxCreditsPerRun)} }`]),
@@ -49,3 +49,15 @@ export const TOOL_CATEGORY_DESCRIPTIONS: Readonly<Record<string, string>> = {
49
49
  export function describeToolCategory(category: string): string | null {
50
50
  return TOOL_CATEGORY_DESCRIPTIONS[category] ?? null;
51
51
  }
52
+
53
+ /** Human-readable label for a canonical tool-category slug. */
54
+ export function formatToolCategoryLabel(category: string): string {
55
+ const normalized = category
56
+ .trim()
57
+ .replace(/[_-]+/g, ' ')
58
+ .replace(/\s+/g, ' ')
59
+ .toLowerCase();
60
+ return normalized
61
+ ? `${normalized[0]?.toUpperCase() ?? ''}${normalized.slice(1)}`
62
+ : '';
63
+ }
package/dist/cli/index.js CHANGED
@@ -1044,7 +1044,7 @@ var SDK_RELEASE = {
1044
1044
  // 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
1045
1045
  // exposed storage-dependent synchronous access. This deliberate minor
1046
1046
  // release keeps lazy paging semantics independent of row residency.
1047
- version: "0.2.70",
1047
+ version: "0.2.71",
1048
1048
  contracts: {
1049
1049
  api: {
1050
1050
  name: "sdk-http-api",
@@ -3983,16 +3983,9 @@ function isPrebuiltPlayDescription(play) {
3983
3983
  return play.origin === "prebuilt" || play.ownerType === "deepline";
3984
3984
  }
3985
3985
  function preferPrebuiltPlayDescriptions(plays) {
3986
- const prebuilt = [];
3987
- const owned = [];
3988
- for (const play of plays) {
3989
- if (isPrebuiltPlayDescription(play)) {
3990
- prebuilt.push(play);
3991
- } else {
3992
- owned.push(play);
3993
- }
3994
- }
3995
- return [...prebuilt, ...owned];
3986
+ return plays.map((play, index) => ({ play, index })).sort(
3987
+ (left, right) => Number(right.play.pinned) - Number(left.play.pinned) || Number(isPrebuiltPlayDescription(right.play)) - Number(isPrebuiltPlayDescription(left.play)) || left.index - right.index
3988
+ ).map(({ play }) => play);
3996
3989
  }
3997
3990
  function isPlayRunPackage(value) {
3998
3991
  return Boolean(
@@ -4339,6 +4332,8 @@ var DeeplineClient = class {
4339
4332
  ...play.reference ? { reference: play.reference } : {},
4340
4333
  ...play.displayName ? { displayName: play.displayName } : {},
4341
4334
  ...description ? { description } : {},
4335
+ pinned: Boolean(play.pinned),
4336
+ toolCategories: play.toolCategories ?? [],
4342
4337
  origin: play.origin,
4343
4338
  ownerType: play.ownerType,
4344
4339
  canEdit: play.canEdit,
@@ -5837,6 +5832,16 @@ var DeeplineClient = class {
5837
5832
  async listPlays(options) {
5838
5833
  const params = new URLSearchParams();
5839
5834
  if (options?.origin) params.set("origin", options.origin);
5835
+ if (options?.categories) {
5836
+ params.set(
5837
+ "categories",
5838
+ Array.isArray(options.categories) ? options.categories.join(",") : options.categories
5839
+ );
5840
+ }
5841
+ if (options?.categories || options?.includeToolCategories) {
5842
+ params.set("include_tool_categories", "1");
5843
+ }
5844
+ if (options?.includeArchived) params.set("include_archived", "1");
5840
5845
  if (options?.grep?.trim()) {
5841
5846
  params.set("grep", options.grep.trim());
5842
5847
  params.set("grep_mode", options.grepMode ?? "all");
@@ -5848,6 +5853,12 @@ var DeeplineClient = class {
5848
5853
  );
5849
5854
  return response.plays ?? [];
5850
5855
  }
5856
+ /** Set whether an org-owned Play sorts before unpinned Plays. */
5857
+ async setPlayPinned(playName, pinned) {
5858
+ return this.http.post(`/api/v2/plays/${encodeURIComponent(playName)}/pin`, {
5859
+ pinned
5860
+ });
5861
+ }
5851
5862
  /** Read product-notification destinations, subscriptions, event catalog, and DLQ health. */
5852
5863
  async getNotificationSettings() {
5853
5864
  return this.http.get("/api/v2/settings/notifications");
@@ -22848,6 +22859,29 @@ function resolvePlayCheckExportNames(sourceCode) {
22848
22859
  if (!exports2 || exports2.length === 0) return [PLAY_DEFAULT_EXPORT];
22849
22860
  return exports2.map((entry) => entry.name);
22850
22861
  }
22862
+ function artifactForProductionCompatibilityCheck(artifact) {
22863
+ const rawEdition = process.env.DEEPLINE_PROD_CHECK_AUTHORING_CONTRACT_EDITION?.trim();
22864
+ if (!rawEdition) return artifact;
22865
+ if (!/^\d+$/.test(rawEdition)) {
22866
+ throw new Error(
22867
+ "DEEPLINE_PROD_CHECK_AUTHORING_CONTRACT_EDITION must be a positive integer."
22868
+ );
22869
+ }
22870
+ const edition = Number(rawEdition);
22871
+ if (edition < 1) {
22872
+ throw new Error(
22873
+ "DEEPLINE_PROD_CHECK_AUTHORING_CONTRACT_EDITION must be a positive integer."
22874
+ );
22875
+ }
22876
+ const compatibility = isRecord10(artifact.compatibility) ? artifact.compatibility : {};
22877
+ return {
22878
+ ...artifact,
22879
+ compatibility: {
22880
+ ...compatibility,
22881
+ authoringContractEdition: edition
22882
+ }
22883
+ };
22884
+ }
22851
22885
  async function checkOneExportedPlay(input2) {
22852
22886
  const { absolutePlayPath, sourceCode, exportName } = input2;
22853
22887
  const fallbackName = extractPlayName(sourceCode, absolutePlayPath);
@@ -22887,7 +22921,7 @@ async function checkOneExportedPlay(input2) {
22887
22921
  sourceCode: graph.root.sourceCode,
22888
22922
  sourceFiles: graph.root.sourceFiles,
22889
22923
  description: graph.root.playDescription ?? void 0,
22890
- artifact: graph.root.artifact,
22924
+ artifact: artifactForProductionCompatibilityCheck(graph.root.artifact),
22891
22925
  ...exportName === PLAY_DEFAULT_EXPORT ? {} : { exportName },
22892
22926
  ...importedPlays.length > 0 ? { importedPlays } : {},
22893
22927
  ...integrationMode ? { integrationMode } : {}
@@ -24073,7 +24107,12 @@ async function handlePlayVersions(args) {
24073
24107
  async function handlePlayList(args) {
24074
24108
  const jsonOutput = argsWantJson(args);
24075
24109
  const client2 = new DeeplineClient();
24076
- const plays = await client2.listPlays();
24110
+ const categoriesIndex = args.indexOf("--categories");
24111
+ const categories = categoriesIndex >= 0 ? args[categoriesIndex + 1]?.trim() : void 0;
24112
+ const plays = await client2.listPlays({
24113
+ categories,
24114
+ includeToolCategories: true
24115
+ });
24077
24116
  if (jsonOutput) {
24078
24117
  process.stdout.write(`${JSON.stringify(plays)}
24079
24118
  `);
@@ -24084,6 +24123,8 @@ async function handlePlayList(args) {
24084
24123
  `);
24085
24124
  for (const play of plays) {
24086
24125
  const flags = [
24126
+ play.pinned ? "pinned" : null,
24127
+ ...(play.toolCategories ?? []).map((category) => `category:${category}`),
24087
24128
  play.origin === "prebuilt" || play.ownerType === "deepline" ? "prebuilt" : "owned",
24088
24129
  play.canEdit ? "editable" : "readonly",
24089
24130
  play.isDraftDirty ? "draft-dirty" : null
@@ -24113,6 +24154,36 @@ async function handlePlayList(args) {
24113
24154
  }
24114
24155
  return 0;
24115
24156
  }
24157
+ async function handlePlayPin(args, pinned) {
24158
+ const target = args.find((arg) => !arg.startsWith("-"))?.trim();
24159
+ const jsonOutput = argsWantJson(args);
24160
+ const dryRun = args.includes("--dry-run");
24161
+ if (!target) {
24162
+ console.error(
24163
+ `Usage: deepline plays ${pinned ? "pin" : "unpin"} <play> [--dry-run] [--json]`
24164
+ );
24165
+ return 2;
24166
+ }
24167
+ const parsedTarget = parseReferencedPlayTarget2(target);
24168
+ if (parsedTarget.ownerSlug) {
24169
+ console.error(
24170
+ `deepline plays ${pinned ? "pin" : "unpin"} accepts an org-owned Play identifier without a namespace. Use "${parsedTarget.unqualifiedPlayName}" instead of "${target}".`
24171
+ );
24172
+ return 2;
24173
+ }
24174
+ const name = parsedTarget.playName;
24175
+ const plan = { name, pinned, dryRun };
24176
+ if (dryRun) {
24177
+ process.stdout.write(`${JSON.stringify(plan)}
24178
+ `);
24179
+ return 0;
24180
+ }
24181
+ const result = await new DeeplineClient().setPlayPinned(name, pinned);
24182
+ if (jsonOutput) process.stdout.write(`${JSON.stringify(result)}
24183
+ `);
24184
+ else console.log(`${result.pinned ? "Pinned" : "Unpinned"} ${result.name}.`);
24185
+ return 0;
24186
+ }
24116
24187
  function parsePlaySearchOptions(args) {
24117
24188
  const query = args[0]?.trim();
24118
24189
  if (!query) {
@@ -24147,6 +24218,12 @@ function printPlayDescription(play) {
24147
24218
  if (play.description) {
24148
24219
  console.log(` Description: ${play.description}`);
24149
24220
  }
24221
+ if (play.pinned) {
24222
+ console.log(" Pinned: yes");
24223
+ }
24224
+ if (play.toolCategories?.length) {
24225
+ console.log(` Tool categories: ${play.toolCategories.join(", ")}`);
24226
+ }
24150
24227
  if (play.aliases.length > 0) {
24151
24228
  console.log(` Aliases: ${play.aliases.join(", ")}`);
24152
24229
  }
@@ -24252,6 +24329,8 @@ function summarizePlayListItemForCli(play, options) {
24252
24329
  name: play.name,
24253
24330
  ...play.reference ? { reference: play.reference } : {},
24254
24331
  ...play.displayName ? { displayName: play.displayName } : {},
24332
+ pinned: Boolean(play.pinned),
24333
+ toolCategories: play.toolCategories ?? [],
24255
24334
  origin: play.origin,
24256
24335
  ownerType: play.ownerType,
24257
24336
  canEdit: play.canEdit,
@@ -24382,6 +24461,7 @@ async function handlePlayGrep(args) {
24382
24461
  origin: play.origin,
24383
24462
  ownerType: play.ownerType,
24384
24463
  aliases: play.aliases,
24464
+ toolCategories: play.toolCategories,
24385
24465
  inputSchema: play.inputSchema,
24386
24466
  outputSchema: play.outputSchema
24387
24467
  },
@@ -25045,11 +25125,35 @@ Examples:
25045
25125
  deepline plays list
25046
25126
  deepline plays search email --json
25047
25127
  `
25048
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
25128
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
25129
+ "--categories <categories>",
25130
+ "Filter by comma-separated canonical tool categories"
25131
+ ).action(async (options) => {
25049
25132
  process.exitCode = await handlePlayList([
25133
+ ...options.categories ? ["--categories", options.categories] : [],
25050
25134
  ...options.json ? ["--json"] : []
25051
25135
  ]);
25052
25136
  });
25137
+ 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) => {
25138
+ process.exitCode = await handlePlayPin(
25139
+ [
25140
+ target,
25141
+ ...options.dryRun ? ["--dry-run"] : [],
25142
+ ...options.json ? ["--json"] : []
25143
+ ],
25144
+ true
25145
+ );
25146
+ });
25147
+ 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) => {
25148
+ process.exitCode = await handlePlayPin(
25149
+ [
25150
+ target,
25151
+ ...options.dryRun ? ["--dry-run"] : [],
25152
+ ...options.json ? ["--json"] : []
25153
+ ],
25154
+ false
25155
+ );
25156
+ });
25053
25157
  const addPlaySearchCommand = (command) => command.description("Search Deepline prebuilt plays by task.").option(
25054
25158
  "--prebuilt",
25055
25159
  "Only show Deepline-managed prebuilt plays (default)"
@@ -26404,10 +26508,12 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
26404
26508
  const metadataColumnSource = renderMetadataColumnStep(config);
26405
26509
  const generatedAliases = collectGeneratedAliases(config.commands);
26406
26510
  const runOptionsSource = options.failFast ? `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart), onRowError: 'fail' as const }` : `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart) }`;
26511
+ const describedColumns = config.commands.filter((command) => isWaterfall(command) || !command.disabled).map(
26512
+ (command) => (isWaterfall(command) ? command.with_waterfall : command.alias).replace(/[_-]+/g, " ").trim()
26513
+ ).filter(Boolean).slice(0, 3);
26514
+ const generatedDescription = describedColumns.length ? `Enrich CSV rows with ${describedColumns.join(", ")}.` : "Prepare CSV rows for enrichment.";
26407
26515
  const playOptionsSource = [
26408
- `description: ${stringLiteral(
26409
- "Read a CSV file, run the configured Deepline enrich commands, and return enriched rows."
26410
- )}`,
26516
+ `description: ${stringLiteral(generatedDescription)}`,
26411
26517
  ...options.maxCreditsPerRun === void 0 ? [] : [`billing: { maxCreditsPerRun: ${String(options.maxCreditsPerRun)} }`]
26412
26518
  ].join(", ");
26413
26519
  const body = [
@@ -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.71",
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");
@@ -22900,6 +22911,29 @@ function resolvePlayCheckExportNames(sourceCode) {
22900
22911
  if (!exports || exports.length === 0) return [PLAY_DEFAULT_EXPORT];
22901
22912
  return exports.map((entry) => entry.name);
22902
22913
  }
22914
+ function artifactForProductionCompatibilityCheck(artifact) {
22915
+ const rawEdition = process.env.DEEPLINE_PROD_CHECK_AUTHORING_CONTRACT_EDITION?.trim();
22916
+ if (!rawEdition) return artifact;
22917
+ if (!/^\d+$/.test(rawEdition)) {
22918
+ throw new Error(
22919
+ "DEEPLINE_PROD_CHECK_AUTHORING_CONTRACT_EDITION must be a positive integer."
22920
+ );
22921
+ }
22922
+ const edition = Number(rawEdition);
22923
+ if (edition < 1) {
22924
+ throw new Error(
22925
+ "DEEPLINE_PROD_CHECK_AUTHORING_CONTRACT_EDITION must be a positive integer."
22926
+ );
22927
+ }
22928
+ const compatibility = isRecord10(artifact.compatibility) ? artifact.compatibility : {};
22929
+ return {
22930
+ ...artifact,
22931
+ compatibility: {
22932
+ ...compatibility,
22933
+ authoringContractEdition: edition
22934
+ }
22935
+ };
22936
+ }
22903
22937
  async function checkOneExportedPlay(input2) {
22904
22938
  const { absolutePlayPath, sourceCode, exportName } = input2;
22905
22939
  const fallbackName = extractPlayName(sourceCode, absolutePlayPath);
@@ -22939,7 +22973,7 @@ async function checkOneExportedPlay(input2) {
22939
22973
  sourceCode: graph.root.sourceCode,
22940
22974
  sourceFiles: graph.root.sourceFiles,
22941
22975
  description: graph.root.playDescription ?? void 0,
22942
- artifact: graph.root.artifact,
22976
+ artifact: artifactForProductionCompatibilityCheck(graph.root.artifact),
22943
22977
  ...exportName === PLAY_DEFAULT_EXPORT ? {} : { exportName },
22944
22978
  ...importedPlays.length > 0 ? { importedPlays } : {},
22945
22979
  ...integrationMode ? { integrationMode } : {}
@@ -24125,7 +24159,12 @@ async function handlePlayVersions(args) {
24125
24159
  async function handlePlayList(args) {
24126
24160
  const jsonOutput = argsWantJson(args);
24127
24161
  const client2 = new DeeplineClient();
24128
- const plays = await client2.listPlays();
24162
+ const categoriesIndex = args.indexOf("--categories");
24163
+ const categories = categoriesIndex >= 0 ? args[categoriesIndex + 1]?.trim() : void 0;
24164
+ const plays = await client2.listPlays({
24165
+ categories,
24166
+ includeToolCategories: true
24167
+ });
24129
24168
  if (jsonOutput) {
24130
24169
  process.stdout.write(`${JSON.stringify(plays)}
24131
24170
  `);
@@ -24136,6 +24175,8 @@ async function handlePlayList(args) {
24136
24175
  `);
24137
24176
  for (const play of plays) {
24138
24177
  const flags = [
24178
+ play.pinned ? "pinned" : null,
24179
+ ...(play.toolCategories ?? []).map((category) => `category:${category}`),
24139
24180
  play.origin === "prebuilt" || play.ownerType === "deepline" ? "prebuilt" : "owned",
24140
24181
  play.canEdit ? "editable" : "readonly",
24141
24182
  play.isDraftDirty ? "draft-dirty" : null
@@ -24165,6 +24206,36 @@ async function handlePlayList(args) {
24165
24206
  }
24166
24207
  return 0;
24167
24208
  }
24209
+ async function handlePlayPin(args, pinned) {
24210
+ const target = args.find((arg) => !arg.startsWith("-"))?.trim();
24211
+ const jsonOutput = argsWantJson(args);
24212
+ const dryRun = args.includes("--dry-run");
24213
+ if (!target) {
24214
+ console.error(
24215
+ `Usage: deepline plays ${pinned ? "pin" : "unpin"} <play> [--dry-run] [--json]`
24216
+ );
24217
+ return 2;
24218
+ }
24219
+ const parsedTarget = parseReferencedPlayTarget2(target);
24220
+ if (parsedTarget.ownerSlug) {
24221
+ console.error(
24222
+ `deepline plays ${pinned ? "pin" : "unpin"} accepts an org-owned Play identifier without a namespace. Use "${parsedTarget.unqualifiedPlayName}" instead of "${target}".`
24223
+ );
24224
+ return 2;
24225
+ }
24226
+ const name = parsedTarget.playName;
24227
+ const plan = { name, pinned, dryRun };
24228
+ if (dryRun) {
24229
+ process.stdout.write(`${JSON.stringify(plan)}
24230
+ `);
24231
+ return 0;
24232
+ }
24233
+ const result = await new DeeplineClient().setPlayPinned(name, pinned);
24234
+ if (jsonOutput) process.stdout.write(`${JSON.stringify(result)}
24235
+ `);
24236
+ else console.log(`${result.pinned ? "Pinned" : "Unpinned"} ${result.name}.`);
24237
+ return 0;
24238
+ }
24168
24239
  function parsePlaySearchOptions(args) {
24169
24240
  const query = args[0]?.trim();
24170
24241
  if (!query) {
@@ -24199,6 +24270,12 @@ function printPlayDescription(play) {
24199
24270
  if (play.description) {
24200
24271
  console.log(` Description: ${play.description}`);
24201
24272
  }
24273
+ if (play.pinned) {
24274
+ console.log(" Pinned: yes");
24275
+ }
24276
+ if (play.toolCategories?.length) {
24277
+ console.log(` Tool categories: ${play.toolCategories.join(", ")}`);
24278
+ }
24202
24279
  if (play.aliases.length > 0) {
24203
24280
  console.log(` Aliases: ${play.aliases.join(", ")}`);
24204
24281
  }
@@ -24304,6 +24381,8 @@ function summarizePlayListItemForCli(play, options) {
24304
24381
  name: play.name,
24305
24382
  ...play.reference ? { reference: play.reference } : {},
24306
24383
  ...play.displayName ? { displayName: play.displayName } : {},
24384
+ pinned: Boolean(play.pinned),
24385
+ toolCategories: play.toolCategories ?? [],
24307
24386
  origin: play.origin,
24308
24387
  ownerType: play.ownerType,
24309
24388
  canEdit: play.canEdit,
@@ -24434,6 +24513,7 @@ async function handlePlayGrep(args) {
24434
24513
  origin: play.origin,
24435
24514
  ownerType: play.ownerType,
24436
24515
  aliases: play.aliases,
24516
+ toolCategories: play.toolCategories,
24437
24517
  inputSchema: play.inputSchema,
24438
24518
  outputSchema: play.outputSchema
24439
24519
  },
@@ -25097,11 +25177,35 @@ Examples:
25097
25177
  deepline plays list
25098
25178
  deepline plays search email --json
25099
25179
  `
25100
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
25180
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
25181
+ "--categories <categories>",
25182
+ "Filter by comma-separated canonical tool categories"
25183
+ ).action(async (options) => {
25101
25184
  process.exitCode = await handlePlayList([
25185
+ ...options.categories ? ["--categories", options.categories] : [],
25102
25186
  ...options.json ? ["--json"] : []
25103
25187
  ]);
25104
25188
  });
25189
+ 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) => {
25190
+ process.exitCode = await handlePlayPin(
25191
+ [
25192
+ target,
25193
+ ...options.dryRun ? ["--dry-run"] : [],
25194
+ ...options.json ? ["--json"] : []
25195
+ ],
25196
+ true
25197
+ );
25198
+ });
25199
+ 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) => {
25200
+ process.exitCode = await handlePlayPin(
25201
+ [
25202
+ target,
25203
+ ...options.dryRun ? ["--dry-run"] : [],
25204
+ ...options.json ? ["--json"] : []
25205
+ ],
25206
+ false
25207
+ );
25208
+ });
25105
25209
  const addPlaySearchCommand = (command) => command.description("Search Deepline prebuilt plays by task.").option(
25106
25210
  "--prebuilt",
25107
25211
  "Only show Deepline-managed prebuilt plays (default)"
@@ -26456,10 +26560,12 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
26456
26560
  const metadataColumnSource = renderMetadataColumnStep(config);
26457
26561
  const generatedAliases = collectGeneratedAliases(config.commands);
26458
26562
  const runOptionsSource = options.failFast ? `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart), onRowError: 'fail' as const }` : `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart) }`;
26563
+ const describedColumns = config.commands.filter((command) => isWaterfall(command) || !command.disabled).map(
26564
+ (command) => (isWaterfall(command) ? command.with_waterfall : command.alias).replace(/[_-]+/g, " ").trim()
26565
+ ).filter(Boolean).slice(0, 3);
26566
+ const generatedDescription = describedColumns.length ? `Enrich CSV rows with ${describedColumns.join(", ")}.` : "Prepare CSV rows for enrichment.";
26459
26567
  const playOptionsSource = [
26460
- `description: ${stringLiteral(
26461
- "Read a CSV file, run the configured Deepline enrich commands, and return enriched rows."
26462
- )}`,
26568
+ `description: ${stringLiteral(generatedDescription)}`,
26463
26569
  ...options.maxCreditsPerRun === void 0 ? [] : [`billing: { maxCreditsPerRun: ${String(options.maxCreditsPerRun)} }`]
26464
26570
  ].join(", ");
26465
26571
  const body = [
package/dist/index.d.mts CHANGED
@@ -1108,6 +1108,10 @@ interface PlayDefinitionDetail {
1108
1108
  name: string;
1109
1109
  /** Human-friendly display name for UI surfaces. */
1110
1110
  displayName?: string;
1111
+ /** Whether this Play sorts before unpinned Plays. */
1112
+ pinned?: boolean;
1113
+ /** Canonical categories declared by tools used in this Play. */
1114
+ toolCategories?: string[];
1111
1115
  /** Whether this entry comes from the Deepline prebuilt registry or the org-owned catalog. */
1112
1116
  origin?: 'prebuilt' | 'owned';
1113
1117
  /** Ownership class used for permissions and badges. */
@@ -1161,6 +1165,8 @@ interface PlayListItem {
1161
1165
  name: string;
1162
1166
  displayName?: string;
1163
1167
  description?: string | null;
1168
+ pinned?: boolean;
1169
+ toolCategories?: string[];
1164
1170
  origin?: 'prebuilt' | 'owned';
1165
1171
  ownerType?: 'deepline' | 'org';
1166
1172
  ownerSlug?: string;
@@ -1240,6 +1246,8 @@ interface PlayDescription {
1240
1246
  reference?: string;
1241
1247
  displayName?: string;
1242
1248
  description?: string | null;
1249
+ pinned?: boolean;
1250
+ toolCategories?: string[];
1243
1251
  origin?: 'prebuilt' | 'owned';
1244
1252
  ownerType?: 'deepline' | 'org';
1245
1253
  canEdit?: boolean;
@@ -3278,7 +3286,15 @@ declare class DeeplineClient {
3278
3286
  origin?: 'prebuilt' | 'owned';
3279
3287
  grep?: string;
3280
3288
  grepMode?: 'all' | 'any' | 'phrase';
3289
+ categories?: string | string[];
3290
+ includeToolCategories?: boolean;
3291
+ includeArchived?: boolean;
3281
3292
  }): Promise<PlayListItem[]>;
3293
+ /** Set whether an org-owned Play sorts before unpinned Plays. */
3294
+ setPlayPinned(playName: string, pinned: boolean): Promise<{
3295
+ name: string;
3296
+ pinned: boolean;
3297
+ }>;
3282
3298
  /** Read product-notification destinations, subscriptions, event catalog, and DLQ health. */
3283
3299
  getNotificationSettings(): Promise<ProductNotificationSettings>;
3284
3300
  /** Start the Slack OAuth flow required by product notifications. */
package/dist/index.d.ts CHANGED
@@ -1108,6 +1108,10 @@ interface PlayDefinitionDetail {
1108
1108
  name: string;
1109
1109
  /** Human-friendly display name for UI surfaces. */
1110
1110
  displayName?: string;
1111
+ /** Whether this Play sorts before unpinned Plays. */
1112
+ pinned?: boolean;
1113
+ /** Canonical categories declared by tools used in this Play. */
1114
+ toolCategories?: string[];
1111
1115
  /** Whether this entry comes from the Deepline prebuilt registry or the org-owned catalog. */
1112
1116
  origin?: 'prebuilt' | 'owned';
1113
1117
  /** Ownership class used for permissions and badges. */
@@ -1161,6 +1165,8 @@ interface PlayListItem {
1161
1165
  name: string;
1162
1166
  displayName?: string;
1163
1167
  description?: string | null;
1168
+ pinned?: boolean;
1169
+ toolCategories?: string[];
1164
1170
  origin?: 'prebuilt' | 'owned';
1165
1171
  ownerType?: 'deepline' | 'org';
1166
1172
  ownerSlug?: string;
@@ -1240,6 +1246,8 @@ interface PlayDescription {
1240
1246
  reference?: string;
1241
1247
  displayName?: string;
1242
1248
  description?: string | null;
1249
+ pinned?: boolean;
1250
+ toolCategories?: string[];
1243
1251
  origin?: 'prebuilt' | 'owned';
1244
1252
  ownerType?: 'deepline' | 'org';
1245
1253
  canEdit?: boolean;
@@ -3278,7 +3286,15 @@ declare class DeeplineClient {
3278
3286
  origin?: 'prebuilt' | 'owned';
3279
3287
  grep?: string;
3280
3288
  grepMode?: 'all' | 'any' | 'phrase';
3289
+ categories?: string | string[];
3290
+ includeToolCategories?: boolean;
3291
+ includeArchived?: boolean;
3281
3292
  }): Promise<PlayListItem[]>;
3293
+ /** Set whether an org-owned Play sorts before unpinned Plays. */
3294
+ setPlayPinned(playName: string, pinned: boolean): Promise<{
3295
+ name: string;
3296
+ pinned: boolean;
3297
+ }>;
3282
3298
  /** Read product-notification destinations, subscriptions, event catalog, and DLQ health. */
3283
3299
  getNotificationSettings(): Promise<ProductNotificationSettings>;
3284
3300
  /** Start the Slack OAuth flow required by product notifications. */
package/dist/index.js CHANGED
@@ -780,7 +780,7 @@ var SDK_RELEASE = {
780
780
  // 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
781
781
  // exposed storage-dependent synchronous access. This deliberate minor
782
782
  // release keeps lazy paging semantics independent of row residency.
783
- version: "0.2.70",
783
+ version: "0.2.71",
784
784
  contracts: {
785
785
  api: {
786
786
  name: "sdk-http-api",
@@ -3719,16 +3719,9 @@ function isPrebuiltPlayDescription(play) {
3719
3719
  return play.origin === "prebuilt" || play.ownerType === "deepline";
3720
3720
  }
3721
3721
  function preferPrebuiltPlayDescriptions(plays) {
3722
- const prebuilt = [];
3723
- const owned = [];
3724
- for (const play of plays) {
3725
- if (isPrebuiltPlayDescription(play)) {
3726
- prebuilt.push(play);
3727
- } else {
3728
- owned.push(play);
3729
- }
3730
- }
3731
- return [...prebuilt, ...owned];
3722
+ return plays.map((play, index) => ({ play, index })).sort(
3723
+ (left, right) => Number(right.play.pinned) - Number(left.play.pinned) || Number(isPrebuiltPlayDescription(right.play)) - Number(isPrebuiltPlayDescription(left.play)) || left.index - right.index
3724
+ ).map(({ play }) => play);
3732
3725
  }
3733
3726
  function isPlayRunPackage(value) {
3734
3727
  return Boolean(
@@ -4075,6 +4068,8 @@ var DeeplineClient = class {
4075
4068
  ...play.reference ? { reference: play.reference } : {},
4076
4069
  ...play.displayName ? { displayName: play.displayName } : {},
4077
4070
  ...description ? { description } : {},
4071
+ pinned: Boolean(play.pinned),
4072
+ toolCategories: play.toolCategories ?? [],
4078
4073
  origin: play.origin,
4079
4074
  ownerType: play.ownerType,
4080
4075
  canEdit: play.canEdit,
@@ -5573,6 +5568,16 @@ var DeeplineClient = class {
5573
5568
  async listPlays(options) {
5574
5569
  const params = new URLSearchParams();
5575
5570
  if (options?.origin) params.set("origin", options.origin);
5571
+ if (options?.categories) {
5572
+ params.set(
5573
+ "categories",
5574
+ Array.isArray(options.categories) ? options.categories.join(",") : options.categories
5575
+ );
5576
+ }
5577
+ if (options?.categories || options?.includeToolCategories) {
5578
+ params.set("include_tool_categories", "1");
5579
+ }
5580
+ if (options?.includeArchived) params.set("include_archived", "1");
5576
5581
  if (options?.grep?.trim()) {
5577
5582
  params.set("grep", options.grep.trim());
5578
5583
  params.set("grep_mode", options.grepMode ?? "all");
@@ -5584,6 +5589,12 @@ var DeeplineClient = class {
5584
5589
  );
5585
5590
  return response.plays ?? [];
5586
5591
  }
5592
+ /** Set whether an org-owned Play sorts before unpinned Plays. */
5593
+ async setPlayPinned(playName, pinned) {
5594
+ return this.http.post(`/api/v2/plays/${encodeURIComponent(playName)}/pin`, {
5595
+ pinned
5596
+ });
5597
+ }
5587
5598
  /** Read product-notification destinations, subscriptions, event catalog, and DLQ health. */
5588
5599
  async getNotificationSettings() {
5589
5600
  return this.http.get("/api/v2/settings/notifications");
package/dist/index.mjs CHANGED
@@ -703,7 +703,7 @@ var SDK_RELEASE = {
703
703
  // 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
704
704
  // exposed storage-dependent synchronous access. This deliberate minor
705
705
  // release keeps lazy paging semantics independent of row residency.
706
- version: "0.2.70",
706
+ version: "0.2.71",
707
707
  contracts: {
708
708
  api: {
709
709
  name: "sdk-http-api",
@@ -3642,16 +3642,9 @@ function isPrebuiltPlayDescription(play) {
3642
3642
  return play.origin === "prebuilt" || play.ownerType === "deepline";
3643
3643
  }
3644
3644
  function preferPrebuiltPlayDescriptions(plays) {
3645
- const prebuilt = [];
3646
- const owned = [];
3647
- for (const play of plays) {
3648
- if (isPrebuiltPlayDescription(play)) {
3649
- prebuilt.push(play);
3650
- } else {
3651
- owned.push(play);
3652
- }
3653
- }
3654
- return [...prebuilt, ...owned];
3645
+ return plays.map((play, index) => ({ play, index })).sort(
3646
+ (left, right) => Number(right.play.pinned) - Number(left.play.pinned) || Number(isPrebuiltPlayDescription(right.play)) - Number(isPrebuiltPlayDescription(left.play)) || left.index - right.index
3647
+ ).map(({ play }) => play);
3655
3648
  }
3656
3649
  function isPlayRunPackage(value) {
3657
3650
  return Boolean(
@@ -3998,6 +3991,8 @@ var DeeplineClient = class {
3998
3991
  ...play.reference ? { reference: play.reference } : {},
3999
3992
  ...play.displayName ? { displayName: play.displayName } : {},
4000
3993
  ...description ? { description } : {},
3994
+ pinned: Boolean(play.pinned),
3995
+ toolCategories: play.toolCategories ?? [],
4001
3996
  origin: play.origin,
4002
3997
  ownerType: play.ownerType,
4003
3998
  canEdit: play.canEdit,
@@ -5496,6 +5491,16 @@ var DeeplineClient = class {
5496
5491
  async listPlays(options) {
5497
5492
  const params = new URLSearchParams();
5498
5493
  if (options?.origin) params.set("origin", options.origin);
5494
+ if (options?.categories) {
5495
+ params.set(
5496
+ "categories",
5497
+ Array.isArray(options.categories) ? options.categories.join(",") : options.categories
5498
+ );
5499
+ }
5500
+ if (options?.categories || options?.includeToolCategories) {
5501
+ params.set("include_tool_categories", "1");
5502
+ }
5503
+ if (options?.includeArchived) params.set("include_archived", "1");
5499
5504
  if (options?.grep?.trim()) {
5500
5505
  params.set("grep", options.grep.trim());
5501
5506
  params.set("grep_mode", options.grepMode ?? "all");
@@ -5507,6 +5512,12 @@ var DeeplineClient = class {
5507
5512
  );
5508
5513
  return response.plays ?? [];
5509
5514
  }
5515
+ /** Set whether an org-owned Play sorts before unpinned Plays. */
5516
+ async setPlayPinned(playName, pinned) {
5517
+ return this.http.post(`/api/v2/plays/${encodeURIComponent(playName)}/pin`, {
5518
+ pinned
5519
+ });
5520
+ }
5510
5521
  /** Read product-notification destinations, subscriptions, event catalog, and DLQ health. */
5511
5522
  async getNotificationSettings() {
5512
5523
  return this.http.get("/api/v2/settings/notifications");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.2.70",
3
+ "version": "0.2.71",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",