@hasna/skills 0.9.11 → 0.9.13

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.
package/bin/migrate.js CHANGED
@@ -7,7 +7,7 @@ import { join as join5 } from "path";
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "@hasna/skills",
10
- version: "0.9.11",
10
+ version: "0.9.13",
11
11
  description: "Skills library for AI coding agents",
12
12
  type: "module",
13
13
  bin: {
@@ -985,6 +985,18 @@ function rowToSkill(row) {
985
985
  ...row.replacement_slug ? { replacementSlug: String(row.replacement_slug) } : {}
986
986
  };
987
987
  }
988
+ function rowToPublishedSelectionState(row) {
989
+ return {
990
+ slug: String(row.slug),
991
+ version: String(row.version),
992
+ current: row.skill_exists ? {
993
+ lifecycle: row.lifecycle === "archived" ? "archived" : "active",
994
+ ...row.tombstoned_at ? { tombstonedAt: dateString(row.tombstoned_at) } : {}
995
+ } : null,
996
+ versionBundleSha256: typeof row.bundle_sha256 === "string" ? row.bundle_sha256 : null,
997
+ bundleAvailable: Boolean(row.bundle_available)
998
+ };
999
+ }
988
1000
  function rowToPin(row) {
989
1001
  return {
990
1002
  orgId: String(row.org_id),
@@ -1057,6 +1069,13 @@ function rowToSkillVersion(row) {
1057
1069
  };
1058
1070
  }
1059
1071
 
1072
+ // src/lib/profile-limits.ts
1073
+ var MAX_PROFILE_SELECTIONS = 4096;
1074
+ var MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
1075
+ var MAX_SKILL_SESSION_ID_CHARS = 256;
1076
+ var PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 12 + 512;
1077
+ var MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
1078
+
1060
1079
  // src/server/types.ts
1061
1080
  class StaleLeaseGenerationError extends Error {
1062
1081
  runId;
@@ -1758,6 +1777,22 @@ class SqliteSkillsStore {
1758
1777
  const row = this.get("SELECT * FROM skills_versions WHERE org_id = ? AND slug = ? AND version = ? LIMIT 1", [principal.orgId, slug, version]);
1759
1778
  return row ? rowToSkillVersion(row) : null;
1760
1779
  }
1780
+ async getPublishedSelectionStates(principal, selections2) {
1781
+ if (selections2.length > MAX_PROFILE_SELECTIONS)
1782
+ throw new RangeError("Published selection lookup exceeds the profile selection limit");
1783
+ if (!selections2.length)
1784
+ return [];
1785
+ const requested = JSON.stringify(selections2.map(({ slug, version }) => ({ slug, version })));
1786
+ return this.all(`SELECT json_extract(q.value, '$.slug') AS slug, json_extract(q.value, '$.version') AS version,
1787
+ r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at,
1788
+ v.bundle_sha256, b.sha256 IS NOT NULL AS bundle_available
1789
+ FROM json_each(?) q
1790
+ LEFT JOIN skills_registry r ON r.org_id = ? AND r.slug = json_extract(q.value, '$.slug')
1791
+ LEFT JOIN skills_versions v ON v.org_id = ?
1792
+ AND v.slug = json_extract(q.value, '$.slug') AND v.version = json_extract(q.value, '$.version')
1793
+ LEFT JOIN skills_bundles b ON b.org_id = ? AND b.sha256 = v.bundle_sha256
1794
+ ORDER BY CAST(q.key AS INTEGER)`, [requested, principal.orgId, principal.orgId, principal.orgId]).map(rowToPublishedSelectionState);
1795
+ }
1761
1796
  async pinSkill(principal, slug, metadata = {}) {
1762
1797
  const row = this.get(`INSERT INTO skills_pins (org_id, principal, slug, pinned_at, metadata_json)
1763
1798
  VALUES (?, ?, ?, ?, ?)
package/bin/server.js CHANGED
@@ -24122,7 +24122,7 @@ var init_dist_es9 = __esm(() => {
24122
24122
  // package.json
24123
24123
  var package_default = {
24124
24124
  name: "@hasna/skills",
24125
- version: "0.9.11",
24125
+ version: "0.9.13",
24126
24126
  description: "Skills library for AI coding agents",
24127
24127
  type: "module",
24128
24128
  bin: {
@@ -35194,6 +35194,18 @@ function rowToSkill(row) {
35194
35194
  ...row.replacement_slug ? { replacementSlug: String(row.replacement_slug) } : {}
35195
35195
  };
35196
35196
  }
35197
+ function rowToPublishedSelectionState(row) {
35198
+ return {
35199
+ slug: String(row.slug),
35200
+ version: String(row.version),
35201
+ current: row.skill_exists ? {
35202
+ lifecycle: row.lifecycle === "archived" ? "archived" : "active",
35203
+ ...row.tombstoned_at ? { tombstonedAt: dateString(row.tombstoned_at) } : {}
35204
+ } : null,
35205
+ versionBundleSha256: typeof row.bundle_sha256 === "string" ? row.bundle_sha256 : null,
35206
+ bundleAvailable: Boolean(row.bundle_available)
35207
+ };
35208
+ }
35197
35209
  function rowToPin(row) {
35198
35210
  return {
35199
35211
  orgId: String(row.org_id),
@@ -35266,6 +35278,25 @@ function rowToSkillVersion(row) {
35266
35278
  };
35267
35279
  }
35268
35280
 
35281
+ // src/lib/profile-limits.ts
35282
+ var MAX_PROFILE_SELECTIONS = 4096;
35283
+ var MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
35284
+ var MAX_SKILL_SESSION_ID_CHARS = 256;
35285
+ var PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 12 + 512;
35286
+ var MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
35287
+ function profileDocumentBytes(value) {
35288
+ return new TextEncoder().encode(JSON.stringify(value)).byteLength;
35289
+ }
35290
+ function resolvedProfileSnapshot(profile2, authority) {
35291
+ return {
35292
+ profileId: profile2.id,
35293
+ workspaceId: profile2.workspaceId,
35294
+ profileRevision: profile2.revision,
35295
+ authority,
35296
+ selections: profile2.selections.map((selection) => ({ ...selection, authority, workspaceId: profile2.workspaceId, profileRevision: profile2.revision }))
35297
+ };
35298
+ }
35299
+
35269
35300
  // src/server/types.ts
35270
35301
  class StaleLeaseGenerationError extends Error {
35271
35302
  runId;
@@ -35968,6 +35999,22 @@ class SqliteSkillsStore {
35968
35999
  const row = this.get("SELECT * FROM skills_versions WHERE org_id = ? AND slug = ? AND version = ? LIMIT 1", [principal.orgId, slug, version2]);
35969
36000
  return row ? rowToSkillVersion(row) : null;
35970
36001
  }
36002
+ async getPublishedSelectionStates(principal, selections2) {
36003
+ if (selections2.length > MAX_PROFILE_SELECTIONS)
36004
+ throw new RangeError("Published selection lookup exceeds the profile selection limit");
36005
+ if (!selections2.length)
36006
+ return [];
36007
+ const requested = JSON.stringify(selections2.map(({ slug, version: version2 }) => ({ slug, version: version2 })));
36008
+ return this.all(`SELECT json_extract(q.value, '$.slug') AS slug, json_extract(q.value, '$.version') AS version,
36009
+ r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at,
36010
+ v.bundle_sha256, b.sha256 IS NOT NULL AS bundle_available
36011
+ FROM json_each(?) q
36012
+ LEFT JOIN skills_registry r ON r.org_id = ? AND r.slug = json_extract(q.value, '$.slug')
36013
+ LEFT JOIN skills_versions v ON v.org_id = ?
36014
+ AND v.slug = json_extract(q.value, '$.slug') AND v.version = json_extract(q.value, '$.version')
36015
+ LEFT JOIN skills_bundles b ON b.org_id = ? AND b.sha256 = v.bundle_sha256
36016
+ ORDER BY CAST(q.key AS INTEGER)`, [requested, principal.orgId, principal.orgId, principal.orgId]).map(rowToPublishedSelectionState);
36017
+ }
35971
36018
  async pinSkill(principal, slug, metadata = {}) {
35972
36019
  const row = this.get(`INSERT INTO skills_pins (org_id, principal, slug, pinned_at, metadata_json)
35973
36020
  VALUES (?, ?, ?, ?, ?)
@@ -36532,25 +36579,6 @@ function selectionAliasError(selections2) {
36532
36579
  }
36533
36580
  }
36534
36581
 
36535
- // src/lib/profile-limits.ts
36536
- var MAX_PROFILE_SELECTIONS = 4096;
36537
- var MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
36538
- var MAX_SKILL_SESSION_ID_CHARS = 256;
36539
- var PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 12 + 512;
36540
- var MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
36541
- function profileDocumentBytes(value) {
36542
- return new TextEncoder().encode(JSON.stringify(value)).byteLength;
36543
- }
36544
- function resolvedProfileSnapshot(profile2, authority) {
36545
- return {
36546
- profileId: profile2.id,
36547
- workspaceId: profile2.workspaceId,
36548
- profileRevision: profile2.revision,
36549
- authority,
36550
- selections: profile2.selections.map((selection) => ({ ...selection, authority, workspaceId: profile2.workspaceId, profileRevision: profile2.revision }))
36551
- };
36552
- }
36553
-
36554
36582
  // src/lib/selection-cache.ts
36555
36583
  class SkillSelectionError extends Error {
36556
36584
  code;
@@ -37601,16 +37629,21 @@ function selected(value) {
37601
37629
  return selections2;
37602
37630
  }
37603
37631
  async function validatePublished(store, principal, selections2) {
37604
- for (const selection2 of selections2) {
37605
- const current = await store.getSkill(principal, selection2.slug);
37632
+ const states = await store.getPublishedSelectionStates(principal, selections2);
37633
+ if (states.length !== selections2.length)
37634
+ throw new SkillRequestError(503, "SELECTION_UNAVAILABLE", "Selected publication state is unavailable");
37635
+ for (const [index, selection2] of selections2.entries()) {
37636
+ const state2 = states[index];
37637
+ if (!state2 || state2.slug !== selection2.slug || state2.version !== selection2.version)
37638
+ throw new SkillRequestError(503, "SELECTION_UNAVAILABLE", "Selected publication state is unavailable");
37639
+ const current = state2.current;
37606
37640
  if (!current || current.tombstonedAt)
37607
37641
  throw new SkillRequestError(current?.tombstonedAt ? 410 : 404, "SELECTION_UNAVAILABLE", `Selected skill '${selection2.slug}' is unavailable`);
37608
37642
  if (current.lifecycle === "archived")
37609
37643
  throw new SkillRequestError(409, "SELECTION_ARCHIVED", `Selected skill '${selection2.slug}' is archived`);
37610
- const version2 = await store.getSkillVersion(principal, selection2.slug, selection2.version);
37611
- if (!version2 || `sha256:${version2.bundleSha256}` !== selection2.bundleDigest)
37644
+ if (!state2.versionBundleSha256 || `sha256:${state2.versionBundleSha256}` !== selection2.bundleDigest)
37612
37645
  throw new SkillRequestError(409, "SELECTION_VERSION_MISMATCH", `Selected version of '${selection2.slug}' does not match its published digest`);
37613
- if (!await store.getSkillBundle(principal, version2.bundleSha256))
37646
+ if (!state2.bundleAvailable)
37614
37647
  throw new SkillRequestError(503, "SELECTION_BUNDLE_UNAVAILABLE", "Selected bundle is unavailable");
37615
37648
  }
37616
37649
  }
@@ -43171,6 +43204,25 @@ class MemorySkillsStore {
43171
43204
  const found = this.versions.get(versionKey(principal.orgId, slug, version2));
43172
43205
  return found && found.orgId === principal.orgId ? found : null;
43173
43206
  }
43207
+ async getPublishedSelectionStates(principal, selections2) {
43208
+ if (selections2.length > MAX_PROFILE_SELECTIONS)
43209
+ throw new RangeError("Published selection lookup exceeds the profile selection limit");
43210
+ return selections2.map(({ slug, version: version2 }) => {
43211
+ const current = this.skills.get(skillKey(principal.orgId, slug));
43212
+ const selectedVersion = this.versions.get(versionKey(principal.orgId, slug, version2));
43213
+ const bundle = selectedVersion && this.bundles.get(skillKey(principal.orgId, selectedVersion.bundleSha256));
43214
+ return {
43215
+ slug,
43216
+ version: version2,
43217
+ current: current?.orgId === principal.orgId ? {
43218
+ lifecycle: current.lifecycle,
43219
+ ...current.tombstonedAt ? { tombstonedAt: current.tombstonedAt } : {}
43220
+ } : null,
43221
+ versionBundleSha256: selectedVersion?.orgId === principal.orgId ? selectedVersion.bundleSha256 : null,
43222
+ bundleAvailable: bundle?.orgId === principal.orgId
43223
+ };
43224
+ });
43225
+ }
43174
43226
  async listSkills(principal) {
43175
43227
  return Array.from(this.skills.values()).filter((skill) => skill.orgId === principal.orgId && !skill.tombstonedAt).sort((a4, b4) => a4.slug.localeCompare(b4.slug));
43176
43228
  }
@@ -43979,6 +44031,25 @@ class PostgresSkillsStore {
43979
44031
  `;
43980
44032
  return rows[0] ? rowToSkillVersion(rows[0]) : null;
43981
44033
  }
44034
+ async getPublishedSelectionStates(principal, selections2) {
44035
+ if (selections2.length > MAX_PROFILE_SELECTIONS)
44036
+ throw new RangeError("Published selection lookup exceeds the profile selection limit");
44037
+ if (!selections2.length)
44038
+ return [];
44039
+ const requested = JSON.stringify(selections2.map(({ slug, version: version2 }) => ({ slug, version: version2 })));
44040
+ const rows = await this.sql`
44041
+ SELECT q.value->>'slug' AS slug, q.value->>'version' AS version,
44042
+ r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at,
44043
+ v.bundle_sha256, b.sha256 IS NOT NULL AS bundle_available
44044
+ FROM jsonb_array_elements(${requested}::text::jsonb) WITH ORDINALITY AS q(value, ordinal)
44045
+ LEFT JOIN skills_registry r ON r.org_id = ${principal.orgId} AND r.slug = q.value->>'slug'
44046
+ LEFT JOIN skills_versions v ON v.org_id = ${principal.orgId}
44047
+ AND v.slug = q.value->>'slug' AND v.version = q.value->>'version'
44048
+ LEFT JOIN skills_bundles b ON b.org_id = ${principal.orgId} AND b.sha256 = v.bundle_sha256
44049
+ ORDER BY q.ordinal
44050
+ `;
44051
+ return rows.map(rowToPublishedSelectionState);
44052
+ }
43982
44053
  async pinSkill(principal, slug, metadata = {}) {
43983
44054
  const rows = await this.sql`
43984
44055
  INSERT INTO skills_pins (org_id, principal, slug, pinned_at, metadata_json)
package/bin/worker.js CHANGED
@@ -24125,7 +24125,7 @@ import { randomUUID as randomUUID6 } from "crypto";
24125
24125
  // package.json
24126
24126
  var package_default = {
24127
24127
  name: "@hasna/skills",
24128
- version: "0.9.11",
24128
+ version: "0.9.13",
24129
24129
  description: "Skills library for AI coding agents",
24130
24130
  type: "module",
24131
24131
  bin: {
@@ -34942,6 +34942,18 @@ function rowToSkill(row) {
34942
34942
  ...row.replacement_slug ? { replacementSlug: String(row.replacement_slug) } : {}
34943
34943
  };
34944
34944
  }
34945
+ function rowToPublishedSelectionState(row) {
34946
+ return {
34947
+ slug: String(row.slug),
34948
+ version: String(row.version),
34949
+ current: row.skill_exists ? {
34950
+ lifecycle: row.lifecycle === "archived" ? "archived" : "active",
34951
+ ...row.tombstoned_at ? { tombstonedAt: dateString(row.tombstoned_at) } : {}
34952
+ } : null,
34953
+ versionBundleSha256: typeof row.bundle_sha256 === "string" ? row.bundle_sha256 : null,
34954
+ bundleAvailable: Boolean(row.bundle_available)
34955
+ };
34956
+ }
34945
34957
  function rowToPin(row) {
34946
34958
  return {
34947
34959
  orgId: String(row.org_id),
@@ -35014,6 +35026,13 @@ function rowToSkillVersion(row) {
35014
35026
  };
35015
35027
  }
35016
35028
 
35029
+ // src/lib/profile-limits.ts
35030
+ var MAX_PROFILE_SELECTIONS = 4096;
35031
+ var MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
35032
+ var MAX_SKILL_SESSION_ID_CHARS = 256;
35033
+ var PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 12 + 512;
35034
+ var MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
35035
+
35017
35036
  // src/server/types.ts
35018
35037
  class StaleLeaseGenerationError extends Error {
35019
35038
  runId;
@@ -35715,6 +35734,22 @@ class SqliteSkillsStore {
35715
35734
  const row = this.get("SELECT * FROM skills_versions WHERE org_id = ? AND slug = ? AND version = ? LIMIT 1", [principal.orgId, slug, version2]);
35716
35735
  return row ? rowToSkillVersion(row) : null;
35717
35736
  }
35737
+ async getPublishedSelectionStates(principal, selections2) {
35738
+ if (selections2.length > MAX_PROFILE_SELECTIONS)
35739
+ throw new RangeError("Published selection lookup exceeds the profile selection limit");
35740
+ if (!selections2.length)
35741
+ return [];
35742
+ const requested = JSON.stringify(selections2.map(({ slug, version: version2 }) => ({ slug, version: version2 })));
35743
+ return this.all(`SELECT json_extract(q.value, '$.slug') AS slug, json_extract(q.value, '$.version') AS version,
35744
+ r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at,
35745
+ v.bundle_sha256, b.sha256 IS NOT NULL AS bundle_available
35746
+ FROM json_each(?) q
35747
+ LEFT JOIN skills_registry r ON r.org_id = ? AND r.slug = json_extract(q.value, '$.slug')
35748
+ LEFT JOIN skills_versions v ON v.org_id = ?
35749
+ AND v.slug = json_extract(q.value, '$.slug') AND v.version = json_extract(q.value, '$.version')
35750
+ LEFT JOIN skills_bundles b ON b.org_id = ? AND b.sha256 = v.bundle_sha256
35751
+ ORDER BY CAST(q.key AS INTEGER)`, [requested, principal.orgId, principal.orgId, principal.orgId]).map(rowToPublishedSelectionState);
35752
+ }
35718
35753
  async pinSkill(principal, slug, metadata = {}) {
35719
35754
  const row = this.get(`INSERT INTO skills_pins (org_id, principal, slug, pinned_at, metadata_json)
35720
35755
  VALUES (?, ?, ?, ?, ?)
@@ -35996,13 +36031,6 @@ var init_client = __esm2(() => {
35996
36031
  init_client();
35997
36032
  init_client();
35998
36033
 
35999
- // src/lib/profile-limits.ts
36000
- var MAX_PROFILE_SELECTIONS = 4096;
36001
- var MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
36002
- var MAX_SKILL_SESSION_ID_CHARS = 256;
36003
- var PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 12 + 512;
36004
- var MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
36005
-
36006
36034
  // src/lib/selection-cache.ts
36007
36035
  var MAX_CACHED_PROFILE_AGE_MS = 24 * 60 * 60 * 1000;
36008
36036
 
@@ -36707,6 +36735,25 @@ class MemorySkillsStore {
36707
36735
  const found = this.versions.get(versionKey(principal.orgId, slug, version2));
36708
36736
  return found && found.orgId === principal.orgId ? found : null;
36709
36737
  }
36738
+ async getPublishedSelectionStates(principal, selections2) {
36739
+ if (selections2.length > MAX_PROFILE_SELECTIONS)
36740
+ throw new RangeError("Published selection lookup exceeds the profile selection limit");
36741
+ return selections2.map(({ slug, version: version2 }) => {
36742
+ const current = this.skills.get(skillKey(principal.orgId, slug));
36743
+ const selectedVersion = this.versions.get(versionKey(principal.orgId, slug, version2));
36744
+ const bundle = selectedVersion && this.bundles.get(skillKey(principal.orgId, selectedVersion.bundleSha256));
36745
+ return {
36746
+ slug,
36747
+ version: version2,
36748
+ current: current?.orgId === principal.orgId ? {
36749
+ lifecycle: current.lifecycle,
36750
+ ...current.tombstonedAt ? { tombstonedAt: current.tombstonedAt } : {}
36751
+ } : null,
36752
+ versionBundleSha256: selectedVersion?.orgId === principal.orgId ? selectedVersion.bundleSha256 : null,
36753
+ bundleAvailable: bundle?.orgId === principal.orgId
36754
+ };
36755
+ });
36756
+ }
36710
36757
  async listSkills(principal) {
36711
36758
  return Array.from(this.skills.values()).filter((skill) => skill.orgId === principal.orgId && !skill.tombstonedAt).sort((a3, b3) => a3.slug.localeCompare(b3.slug));
36712
36759
  }
@@ -37515,6 +37562,25 @@ class PostgresSkillsStore {
37515
37562
  `;
37516
37563
  return rows[0] ? rowToSkillVersion(rows[0]) : null;
37517
37564
  }
37565
+ async getPublishedSelectionStates(principal, selections2) {
37566
+ if (selections2.length > MAX_PROFILE_SELECTIONS)
37567
+ throw new RangeError("Published selection lookup exceeds the profile selection limit");
37568
+ if (!selections2.length)
37569
+ return [];
37570
+ const requested = JSON.stringify(selections2.map(({ slug, version: version2 }) => ({ slug, version: version2 })));
37571
+ const rows = await this.sql`
37572
+ SELECT q.value->>'slug' AS slug, q.value->>'version' AS version,
37573
+ r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at,
37574
+ v.bundle_sha256, b.sha256 IS NOT NULL AS bundle_available
37575
+ FROM jsonb_array_elements(${requested}::text::jsonb) WITH ORDINALITY AS q(value, ordinal)
37576
+ LEFT JOIN skills_registry r ON r.org_id = ${principal.orgId} AND r.slug = q.value->>'slug'
37577
+ LEFT JOIN skills_versions v ON v.org_id = ${principal.orgId}
37578
+ AND v.slug = q.value->>'slug' AND v.version = q.value->>'version'
37579
+ LEFT JOIN skills_bundles b ON b.org_id = ${principal.orgId} AND b.sha256 = v.bundle_sha256
37580
+ ORDER BY q.ordinal
37581
+ `;
37582
+ return rows.map(rowToPublishedSelectionState);
37583
+ }
37518
37584
  async pinSkill(principal, slug, metadata = {}) {
37519
37585
  const rows = await this.sql`
37520
37586
  INSERT INTO skills_pins (org_id, principal, slug, pinned_at, metadata_json)
@@ -5,6 +5,7 @@ export declare function handleProfileSync(options: {
5
5
  profile?: string;
6
6
  project?: boolean;
7
7
  station?: string;
8
+ stationReport?: boolean;
8
9
  check?: boolean;
9
10
  json?: boolean;
10
11
  }, dependencies?: SyncSelectionProfileOptions): Promise<void>;
package/dist/index.d.ts CHANGED
@@ -60,11 +60,12 @@ export type { SkillSelection, SkillProfile, ResolvedSkillSelection, ResolvedSkil
60
60
  export { buildSkillContext } from "./lib/skill-context.js";
61
61
  export { syncSelectionProfile } from "./lib/selection-resolver.js";
62
62
  export { inspectSkillSession, reconcileSkillSession, type SessionReconciliationInput, type SessionReconciliationOptions } from "./lib/session-reconciliation.js";
63
- export { planAgentIntegration, applyAgentIntegration, inventoryNativeSkills, archiveNativeSkills } from "./lib/agent-integration.js";
63
+ export { planAgentIntegration, planClaudeStopHookUpdate, applyAgentIntegration, inventoryNativeSkills, archiveNativeSkills } from "./lib/agent-integration.js";
64
64
  export { captureDiscoveryDirectories, captureDiscoveryByteSources, captureDiscoveryPathSources, type DiscoveryDirectory, type DiscoverySource } from "./lib/agent-discovery.js";
65
- export { captureClaudeMarketplaceRegistry } from "./lib/claude-marketplace-registry.js";
66
- export { captureClaudeSettings } from "./lib/claude-settings-witness.js";
65
+ export { captureClaudeMarketplaceRegistry, captureClaudeMarketplaceRegistryV2 } from "./lib/claude-marketplace-registry.js";
66
+ export { captureClaudeSettings, captureClaudeSettingsV2 } from "./lib/claude-settings-witness.js";
67
67
  export { buildPluginProjection, pluginTreeDigest, type PluginProjectionManifest, type PluginPayloadMapping, type PluginFileWitness } from "./lib/plugin-projection.js";
68
68
  export { planPluginAdmission, admitPlugin, resolveAdmittedPlugin, pluginResolverCommand, type PluginAdmissionTarget, type PluginAdmissionBinding, type PluginAdmissionPrincipal, type PluginAdmissionPlan, type PluginAdmissionIdentity, type PluginBundleIdentity, type PluginRoutingIdentity, type PluginAdmissionReceipt } from "./lib/plugin-admission.js";
69
69
  export { captureManagedPluginRegistry, type ManagedPluginRegistrationWitness } from "./lib/plugin-discovery.js";
70
70
  export type { RemoteCreditCheckoutOptions, RemoteCreditCheckout, RemoteCreditCheckoutErrorCode } from "./lib/remote-credit-checkout.js";
71
+ export { assertPortableAuthoringPath, type PortableAuthoringPathOptions } from "./lib/authoring-path.js";