@hasna/skills 0.10.18 → 0.10.19

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/README.md CHANGED
@@ -466,8 +466,18 @@ preserves and reads back the original policy before writing. Claude upgrades to
466
466
  verbosity preferences. Provider mappings, environment, hooks, plugins, skill rules
467
467
  and all unknown settings stay bound. Runtime hooks never silently upgrade a witness.
468
468
 
469
- A reviewed Codex 0.159.2 native `skills/list` receipt can be passed to `hook install`
470
- with `--codex-native-catalog <file>`. Its safe shape is `{version,cwd,skills}`;
469
+ A Codex 0.159.2 native `skills/list` receipt can be captured through the
470
+ package-owned client into a new private file, then reviewed and passed to
471
+ `hook install` with `--codex-native-catalog <file>`:
472
+
473
+ ```bash
474
+ skills hook native-catalog --cwd /absolute/project --output /private/catalog.json --json
475
+ skills hook install --agent codex --codex-native-catalog /private/catalog.json --json
476
+ ```
477
+
478
+ The capture refuses an existing output file, writes mode `0600`, verifies the
479
+ exact bytes, and reports only version, directory, count, file path and SHA-256.
480
+ Its safe catalog shape is `{version,cwd,skills}`;
471
481
  each skill has `{name,path,enabled,pluginId}`. The installer matches the native
472
482
  qualified name against a bounded explicit frontmatter name and owning plugin
473
483
  manifest. It preserves path disables and adds exact qualified name disables.
@@ -480,8 +490,9 @@ Only manifest version metadata may vary. Reviewed app declarations use the impli
480
490
  file and its presence stay bound; it preserves existing connector availability and
481
491
  native capability hints. Changed or unknown app fields, custom references, native
482
492
  hooks, commands and MCP controls refuse. Name controls suppress Skills, not every
483
- plugin capability. No prompt hook starts an app server to obtain this receipt: native
484
- startup can maintain caches. Capture it through an authorized isolated consumer.
493
+ plugin capability. No prompt hook starts an app server to obtain this receipt:
494
+ native startup can maintain caches. The explicit capture starts and closes only its
495
+ own bounded native client; it does not reload an existing agent session.
485
496
  Neither a receipt nor a config write proves an existing session adopted new rules;
486
497
  use the actual native session's supported acceptance path separately.
487
498
 
package/bin/index.js CHANGED
@@ -36868,7 +36868,7 @@ var package_default;
36868
36868
  var init_package = __esm(() => {
36869
36869
  package_default = {
36870
36870
  name: "@hasna/skills",
36871
- version: "0.10.18",
36871
+ version: "0.10.19",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -51052,6 +51052,24 @@ function projectCodexNativeSkillCatalog(response, cwd2) {
51052
51052
  return { name: value.name, path: value.path, enabled: value.enabled, pluginId: value.pluginId ?? null };
51053
51053
  });
51054
51054
  }
51055
+ async function captureCodexNativeSkillCatalog(options, connect = connectCodexHookRpc) {
51056
+ if (!absolutePath2(options.cwd) || !absolutePath2(options.home))
51057
+ refuse();
51058
+ const rpc = await connect({
51059
+ command: options.command,
51060
+ home: options.home,
51061
+ ...options.codexHome === undefined ? {} : { codexHome: options.codexHome },
51062
+ ...options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }
51063
+ });
51064
+ try {
51065
+ if (!SUPPORTED_NAME_CONTROL_VERSIONS.has(rpc.version))
51066
+ throw new Error("CODEX_NATIVE_SKILL_CATALOG_UNSUPPORTED_VERSION");
51067
+ const response = await rpc.request("skills/list", { cwds: [options.cwd], forceReload: true });
51068
+ return { version: rpc.version, cwd: options.cwd, skills: projectCodexNativeSkillCatalog(response, options.cwd) };
51069
+ } finally {
51070
+ await rpc.close();
51071
+ }
51072
+ }
51055
51073
  function canonicalPath(path) {
51056
51074
  try {
51057
51075
  return realpathSync4(path);
@@ -112194,7 +112212,9 @@ var exports_agent_integration = {};
112194
112212
  __export(exports_agent_integration, {
112195
112213
  registerAgentIntegration: () => registerAgentIntegration
112196
112214
  });
112197
- import { readFileSync as readFileSync41 } from "fs";
112215
+ import { existsSync as existsSync35, lstatSync as lstatSync32, readFileSync as readFileSync41, writeFileSync as writeFileSync26 } from "fs";
112216
+ import { createHash as createHash31 } from "crypto";
112217
+ import { homedir as homedir13 } from "os";
112198
112218
  import { isAbsolute as isAbsolute29 } from "path";
112199
112219
  function pinnedHookProfile(input3, configuredProfile) {
112200
112220
  try {
@@ -112261,6 +112281,45 @@ function agents(value) {
112261
112281
  }
112262
112282
  function registerAgentIntegration(parent) {
112263
112283
  const hook = parent.command("hook").description("Load selected Skills context through agent lifecycle hooks");
112284
+ hook.command("native-catalog").requiredOption("--cwd <path>", "Absolute project directory observed by native Codex skills/list").requiredOption("--output <file>", "New private file for the projected native catalog").option("--codex-command <path>", "Installed Codex executable used by the native client", "codex").option("--json", "Output bounded capture metadata as JSON", false).description("Capture a reviewed Codex native skill catalog for exact hook enrollment").action(async (options) => {
112285
+ try {
112286
+ if (!isAbsolute29(options.cwd) || !isAbsolute29(options.output))
112287
+ throw new Error("CODEX_NATIVE_SKILL_CATALOG_ABSOLUTE_PATH_REQUIRED");
112288
+ if (existsSync35(options.output))
112289
+ throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
112290
+ const catalog = await captureCodexNativeSkillCatalog({
112291
+ command: options.codexCommand,
112292
+ home: homedir13(),
112293
+ ...process.env.CODEX_HOME === undefined ? {} : { codexHome: process.env.CODEX_HOME },
112294
+ cwd: options.cwd
112295
+ });
112296
+ const bytes = JSON.stringify(catalog, null, 2) + `
112297
+ `;
112298
+ try {
112299
+ writeFileSync26(options.output, bytes, { flag: "wx", mode: 384 });
112300
+ } catch (error61) {
112301
+ if (error61 && typeof error61 === "object" && "code" in error61 && error61.code === "EEXIST")
112302
+ throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
112303
+ throw error61;
112304
+ }
112305
+ const written = lstatSync32(options.output);
112306
+ if (!written.isFile() || written.isSymbolicLink() || (written.mode & 63) !== 0 || readFileSync41(options.output, "utf8") !== bytes)
112307
+ throw new Error("CODEX_NATIVE_SKILL_CATALOG_READBACK_FAILED");
112308
+ const receipt = {
112309
+ version: catalog.version,
112310
+ cwd: catalog.cwd,
112311
+ skillCount: catalog.skills.length,
112312
+ output: options.output,
112313
+ bytes: Buffer.byteLength(bytes),
112314
+ sha256: createHash31("sha256").update(bytes).digest("hex")
112315
+ };
112316
+ await writeCliOutput(options.json ? JSON.stringify(receipt) : `Captured ${receipt.skillCount} native Codex skill(s) in ${receipt.output}.`);
112317
+ } catch (error61) {
112318
+ const message = error61 instanceof Error && /^[A-Z][A-Z0-9_]{2,120}$/.test(error61.message) ? error61.message : "CODEX_NATIVE_SKILL_CATALOG_CAPTURE_FAILED";
112319
+ console.error(message);
112320
+ process.exitCode = 1;
112321
+ }
112322
+ });
112264
112323
  hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
112265
112324
  const capture2 = options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
112266
112325
  if (!capture2)
@@ -112492,6 +112551,7 @@ var init_agent_integration2 = __esm(() => {
112492
112551
  init_claude_settings_witness();
112493
112552
  init_codex_settings_witness();
112494
112553
  init_claude_marketplace_registry();
112554
+ init_codex_native_skill_catalog();
112495
112555
  RECOVERABLE_CONTEXT_CACHE_ERRORS = new Set(["CACHED_PROFILE_EXPIRED", "CACHED_PROFILE_MISSING", "CACHED_BUNDLE_MISSING"]);
112496
112556
  });
112497
112557
 
@@ -112630,7 +112690,7 @@ var exports_profiles = {};
112630
112690
  __export(exports_profiles, {
112631
112691
  registerProfiles: () => registerProfiles
112632
112692
  });
112633
- import { closeSync as closeSync21, constants as constants20, fstatSync as fstatSync21, openSync as openSync21, readSync as readSync17, writeFileSync as writeFileSync26 } from "fs";
112693
+ import { closeSync as closeSync21, constants as constants20, fstatSync as fstatSync21, openSync as openSync21, readSync as readSync17, writeFileSync as writeFileSync27 } from "fs";
112634
112694
  function readProfileInput(path) {
112635
112695
  const fd = openSync21(path, constants20.O_RDONLY | constants20.O_NONBLOCK);
112636
112696
  try {
@@ -112658,7 +112718,7 @@ function registerProfiles(parent) {
112658
112718
  try {
112659
112719
  const profile = await readSkillProfile(id3), text4 = JSON.stringify(profile, null, 2);
112660
112720
  if (options.save)
112661
- writeFileSync26(options.save, JSON.stringify(profile), { mode: 384, flag: "wx" });
112721
+ writeFileSync27(options.save, JSON.stringify(profile), { mode: 384, flag: "wx" });
112662
112722
  await writeCliOutput(options.json ? text4 : `${profile.id} at ${profile.revision}: ${profile.selections.map((skill) => `${skill.slug}@${skill.version}`).join(", ")}`);
112663
112723
  } catch (error61) {
112664
112724
  console.error(error61.message);
@@ -112705,7 +112765,7 @@ import {
112705
112765
  fstatSync as fstatSync23,
112706
112766
  openSync as openSync23,
112707
112767
  readSync as readSync18,
112708
- writeFileSync as writeFileSync27
112768
+ writeFileSync as writeFileSync28
112709
112769
  } from "fs";
112710
112770
  function readInput(path) {
112711
112771
  const fd = openSync23(path, constants21.O_RDONLY | constants21.O_NONBLOCK);
@@ -112738,7 +112798,7 @@ function registerGrants(parent) {
112738
112798
  try {
112739
112799
  const policy = await readExecutionGrantPolicy(profile, options.revision);
112740
112800
  if (options.save)
112741
- writeFileSync27(options.save, JSON.stringify(policy, null, 2), {
112801
+ writeFileSync28(options.save, JSON.stringify(policy, null, 2), {
112742
112802
  mode: 384,
112743
112803
  flag: "wx"
112744
112804
  });
@@ -112765,14 +112825,14 @@ var init_grants = __esm(() => {
112765
112825
  });
112766
112826
 
112767
112827
  // src/lib/station-hydrate.ts
112768
- import { createHash as createHash31 } from "crypto";
112828
+ import { createHash as createHash32 } from "crypto";
112769
112829
  import {
112770
112830
  copyFileSync as copyFileSync3,
112771
112831
  mkdirSync as mkdirSync28,
112772
112832
  readdirSync as readdirSync24,
112773
112833
  readFileSync as readFileSync42,
112774
112834
  statSync as statSync22,
112775
- writeFileSync as writeFileSync28
112835
+ writeFileSync as writeFileSync29
112776
112836
  } from "fs";
112777
112837
  import { dirname as dirname35, join as join61, resolve as resolve26, sep as sep13 } from "path";
112778
112838
  function fail5(code2, message, detail = []) {
@@ -112968,7 +113028,7 @@ function skillSha256(skill) {
112968
113028
  return sha256File(skill.files[0].winner.fullPath);
112969
113029
  }
112970
113030
  const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
112971
- return createHash31("sha256").update(joined.sort().join(`
113031
+ return createHash32("sha256").update(joined.sort().join(`
112972
113032
  `)).digest("hex");
112973
113033
  }
112974
113034
  function writeStationHydration(options) {
@@ -113050,7 +113110,7 @@ function writeStationHydration(options) {
113050
113110
  };
113051
113111
  const hydrationManifestPath = join61(dirname35(cacheRoot), `hydration-${options.stationId}.json`);
113052
113112
  mkdirSync28(dirname35(hydrationManifestPath), { recursive: true });
113053
- writeFileSync28(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
113113
+ writeFileSync29(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
113054
113114
  `);
113055
113115
  return {
113056
113116
  ...base3,
@@ -113125,8 +113185,8 @@ var init_hydrate = __esm(() => {
113125
113185
  });
113126
113186
 
113127
113187
  // src/lib/prepare-skill.ts
113128
- import { createHash as createHash32, randomUUID as randomUUID12 } from "crypto";
113129
- import { chmodSync as chmodSync5, existsSync as existsSync35, lstatSync as lstatSync32, mkdirSync as mkdirSync29, mkdtempSync as mkdtempSync6, readFileSync as readFileSync43, readdirSync as readdirSync25, renameSync as renameSync14, rmSync as rmSync9, writeFileSync as writeFileSync29 } from "fs";
113188
+ import { createHash as createHash33, randomUUID as randomUUID12 } from "crypto";
113189
+ import { chmodSync as chmodSync5, existsSync as existsSync36, lstatSync as lstatSync33, mkdirSync as mkdirSync29, mkdtempSync as mkdtempSync6, readFileSync as readFileSync43, readdirSync as readdirSync25, renameSync as renameSync14, rmSync as rmSync9, writeFileSync as writeFileSync30 } from "fs";
113130
113190
  import { tmpdir as tmpdir2 } from "os";
113131
113191
  import { dirname as dirname36, isAbsolute as isAbsolute30, join as join62, relative as relative10, resolve as resolve27, sep as sep14 } from "path";
113132
113192
  function prepareSkill(name, options) {
@@ -113175,10 +113235,10 @@ function prepareSkill(name, options) {
113175
113235
  for (const file2 of before2.files) {
113176
113236
  const destination = join62(staging, file2.path);
113177
113237
  mkdirSync29(dirname36(destination), { recursive: true });
113178
- writeFileSync29(destination, file2.bytes, { mode: file2.mode });
113238
+ writeFileSync30(destination, file2.bytes, { mode: file2.mode });
113179
113239
  }
113180
113240
  const stagedManifest = join62(staging, "skill.json");
113181
- writeFileSync29(stagedManifest, `${JSON.stringify(candidate2, null, 2)}
113241
+ writeFileSync30(stagedManifest, `${JSON.stringify(candidate2, null, 2)}
113182
113242
  `);
113183
113243
  const contentHash = computeContentHash(staging);
113184
113244
  const changed3 = options.version !== previousVersion || kind !== manifest.kind || contentHash !== provenance?.content_hash;
@@ -113188,7 +113248,7 @@ function prepareSkill(name, options) {
113188
113248
  candidate2.provenance.content_hash = contentHash;
113189
113249
  const candidateBytes = `${JSON.stringify(candidate2, null, 2)}
113190
113250
  `;
113191
- writeFileSync29(stagedManifest, candidateBytes);
113251
+ writeFileSync30(stagedManifest, candidateBytes);
113192
113252
  validateRawCandidate(candidate2);
113193
113253
  validateRuntimeEntrypoint(candidate2, staging);
113194
113254
  const validation = validatePortableSkillDirectory(normalized, staging);
@@ -113202,7 +113262,7 @@ ${validation.issues.map((issue2) => `${issue2.code}: ${issue2.message}`).join(`
113202
113262
  if (changed3 && !options.dryRun) {
113203
113263
  const temporary = join62(path, `.skill-prepare-${randomUUID12()}.tmp`);
113204
113264
  try {
113205
- writeFileSync29(temporary, candidateBytes, { flag: "wx", mode: manifestFile.mode });
113265
+ writeFileSync30(temporary, candidateBytes, { flag: "wx", mode: manifestFile.mode });
113206
113266
  chmodSync5(temporary, manifestFile.mode);
113207
113267
  renameSync14(temporary, join62(path, "skill.json"));
113208
113268
  } finally {
@@ -113235,7 +113295,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
113235
113295
  if (typeof entry !== "string")
113236
113296
  return;
113237
113297
  const target = resolve27(root2, entry), rel = relative10(root2, target);
113238
- if (isAbsolute30(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep14}`) || isAbsolute30(rel) || !existsSync35(target) || !lstatSync32(target).isFile()) {
113298
+ if (isAbsolute30(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep14}`) || isAbsolute30(rel) || !existsSync36(target) || !lstatSync33(target).isFile()) {
113239
113299
  throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
113240
113300
  }
113241
113301
  }
@@ -113320,11 +113380,11 @@ function compareVersions(left, right) {
113320
113380
  return 0;
113321
113381
  }
113322
113382
  function snapshot2(root2) {
113323
- const rootStat = lstatSync32(root2);
113383
+ const rootStat = lstatSync33(root2);
113324
113384
  if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
113325
113385
  throw new Error("Skill root must be a real directory, not a symlink.");
113326
113386
  const files = [], directories = [];
113327
- const hash6 = createHash32("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
113387
+ const hash6 = createHash33("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
113328
113388
  let count = 0, bytes = 0;
113329
113389
  const walk2 = (relative11) => {
113330
113390
  for (const name of readdirSync25(join62(root2, relative11)).sort()) {
@@ -113333,7 +113393,7 @@ function snapshot2(root2) {
113333
113393
  const path = relative11 ? `${relative11}/${name}` : name;
113334
113394
  if (++count > 20000)
113335
113395
  throw new Error("Skill exceeds the preparation entry limit (20000).");
113336
- const absolute = join62(root2, path), stat3 = lstatSync32(absolute);
113396
+ const absolute = join62(root2, path), stat3 = lstatSync33(absolute);
113337
113397
  if (stat3.isSymbolicLink())
113338
113398
  throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
113339
113399
  if (stat3.isDirectory() && name === "node_modules")
@@ -113748,7 +113808,7 @@ var init_schedule = __esm(() => {
113748
113808
  });
113749
113809
 
113750
113810
  // src/lib/registry-sync.ts
113751
- import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync30 } from "fs";
113811
+ import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync31 } from "fs";
113752
113812
  import { dirname as dirname37, relative as relative11 } from "path";
113753
113813
  function createRegistrySyncArtifact(options = {}) {
113754
113814
  const profile = options.profile ?? "all";
@@ -113807,7 +113867,7 @@ function createRegistrySyncArtifact(options = {}) {
113807
113867
  }
113808
113868
  function writeRegistrySyncArtifact(path, artifact) {
113809
113869
  mkdirSync30(dirname37(path), { recursive: true });
113810
- writeFileSync30(path, `${JSON.stringify(artifact, null, 2)}
113870
+ writeFileSync31(path, `${JSON.stringify(artifact, null, 2)}
113811
113871
  `);
113812
113872
  }
113813
113873
  function buildDocs(name) {
@@ -113826,7 +113886,7 @@ var init_registry_sync = __esm(() => {
113826
113886
  });
113827
113887
 
113828
113888
  // src/lib/review-export.ts
113829
- import { constants as constants22, closeSync as closeSync25, existsSync as existsSync36, fstatSync as fstatSync25, fsyncSync as fsyncSync7, lstatSync as lstatSync33, openSync as openSync25, realpathSync as realpathSync18, statSync as statSync23, writeFileSync as writeFileSync31 } from "fs";
113889
+ import { constants as constants22, closeSync as closeSync25, existsSync as existsSync37, fstatSync as fstatSync25, fsyncSync as fsyncSync7, lstatSync as lstatSync34, openSync as openSync25, realpathSync as realpathSync18, statSync as statSync23, writeFileSync as writeFileSync32 } from "fs";
113830
113890
  import { basename as basename15, dirname as dirname38, isAbsolute as isAbsolute31, join as join63, parse as parse12, resolve as resolve28, sep as sep15 } from "path";
113831
113891
  function exactVersion(spec) {
113832
113892
  const at2 = spec.indexOf("@");
@@ -113842,7 +113902,7 @@ function assertPrivateDestination(output2) {
113842
113902
  throw new Error("Review output must be an absolute, normalized .tar.gz path.");
113843
113903
  }
113844
113904
  const parent = dirname38(output2);
113845
- if (realpathSync18(parent) !== parent || lstatSync33(parent).isSymbolicLink()) {
113905
+ if (realpathSync18(parent) !== parent || lstatSync34(parent).isSymbolicLink()) {
113846
113906
  throw new Error("Review output parent must be a real directory, not a symlink.");
113847
113907
  }
113848
113908
  const parentStat = statSync23(parent);
@@ -113854,7 +113914,7 @@ function assertPrivateDestination(output2) {
113854
113914
  throw new Error("Review output cannot be placed in agent-native discovery or Skills installation paths.");
113855
113915
  }
113856
113916
  for (let current = parent;; current = dirname38(current)) {
113857
- if (existsSync36(join63(current, ".git"))) {
113917
+ if (existsSync37(join63(current, ".git"))) {
113858
113918
  throw new Error("Review output cannot be placed inside a Git worktree.");
113859
113919
  }
113860
113920
  if (current === parse12(current).root)
@@ -113865,7 +113925,7 @@ function assertPrivateDestination(output2) {
113865
113925
  async function exportSkillVersionForReview(spec, output2, client2) {
113866
113926
  const { slug: slug2, version: version2 } = exactVersion(spec);
113867
113927
  const target = assertPrivateDestination(output2);
113868
- if (existsSync36(target))
113928
+ if (existsSync37(target))
113869
113929
  throw new Error("Review output already exists; choose a new filename.");
113870
113930
  const metadata = await client2.getSkillVersion(slug2, version2);
113871
113931
  if (!metadata)
@@ -113892,7 +113952,7 @@ async function exportSkillVersionForReview(spec, output2, client2) {
113892
113952
  }
113893
113953
  const fd = openSync25(target, constants22.O_WRONLY | constants22.O_CREAT | constants22.O_EXCL | constants22.O_NOFOLLOW, 384);
113894
113954
  try {
113895
- writeFileSync31(fd, bytes);
113955
+ writeFileSync32(fd, bytes);
113896
113956
  fsyncSync7(fd);
113897
113957
  if (fstatSync25(fd).size !== bytes.byteLength)
113898
113958
  throw new Error("Incomplete review output write.");
@@ -114139,7 +114199,7 @@ __export(exports_publish, {
114139
114199
  PushSkillError: () => PushSkillError
114140
114200
  });
114141
114201
  import { execFileSync as execFileSync2 } from "child_process";
114142
- import { existsSync as existsSync37, readFileSync as readFileSync44 } from "fs";
114202
+ import { existsSync as existsSync38, readFileSync as readFileSync44 } from "fs";
114143
114203
  import { hostname as hostname5 } from "os";
114144
114204
  import { join as join64 } from "path";
114145
114205
  function registerPublish(parent) {
@@ -114194,7 +114254,7 @@ async function pushSkill(name, options = {}) {
114194
114254
  await verifyPackedCanonicalHash(skill.name, packed);
114195
114255
  const versionManifest = buildVersionManifest(skill.path, packed);
114196
114256
  const skillMdPath = join64(skill.path, "SKILL.md");
114197
- const skillMd = existsSync37(skillMdPath) ? readFileSync44(skillMdPath, "utf-8") : undefined;
114257
+ const skillMd = existsSync38(skillMdPath) ? readFileSync44(skillMdPath, "utf-8") : undefined;
114198
114258
  const base3 = {
114199
114259
  slug: skill.name,
114200
114260
  path: skill.path,
@@ -115913,7 +115973,7 @@ var init_storage2 = __esm(() => {
115913
115973
  });
115914
115974
 
115915
115975
  // src/lib/registry-reconcile.ts
115916
- import { existsSync as existsSync38, readFileSync as readFileSync45, statSync as statSync24, writeFileSync as writeFileSync32 } from "fs";
115976
+ import { existsSync as existsSync39, readFileSync as readFileSync45, statSync as statSync24, writeFileSync as writeFileSync33 } from "fs";
115917
115977
  import { join as join65 } from "path";
115918
115978
  function isDirectory2(path) {
115919
115979
  try {
@@ -115930,7 +115990,7 @@ function migrationNeeded(options) {
115930
115990
  }
115931
115991
  function readBaseline(skillDir) {
115932
115992
  const markerPath = join65(skillDir, PULL_MARKER_FILE);
115933
- if (!existsSync38(markerPath))
115993
+ if (!existsSync39(markerPath))
115934
115994
  return;
115935
115995
  try {
115936
115996
  const marker = JSON.parse(readFileSync45(markerPath, "utf-8"));
@@ -115946,7 +116006,7 @@ function readBaseline(skillDir) {
115946
116006
  }
115947
116007
  function readCursor(root2) {
115948
116008
  const path = join65(root2, SYNC_CURSOR_FILE);
115949
- if (!existsSync38(path))
116009
+ if (!existsSync39(path))
115950
116010
  return { runCount: 0 };
115951
116011
  try {
115952
116012
  const cursor2 = JSON.parse(readFileSync45(path, "utf-8"));
@@ -115977,7 +116037,7 @@ function remoteRowToSkill(record11) {
115977
116037
  }
115978
116038
  function recheckLocalSide(plannedLocal, localDir, ops = {
115979
116039
  pack: (dir) => packSkillBundle(dir).sha256,
115980
- exists: existsSync38
116040
+ exists: existsSync39
115981
116041
  }) {
115982
116042
  let localNow;
115983
116043
  try {
@@ -116228,7 +116288,7 @@ async function reconcileRegistry(options = {}) {
116228
116288
  runCount: readCursor(root2).runCount + 1,
116229
116289
  summary
116230
116290
  };
116231
- writeFileSync32(join65(root2, SYNC_CURSOR_FILE), `${JSON.stringify(cursor2, null, 2)}
116291
+ writeFileSync33(join65(root2, SYNC_CURSOR_FILE), `${JSON.stringify(cursor2, null, 2)}
116232
116292
  `);
116233
116293
  return {
116234
116294
  corpusRoot: root2,
package/bin/mcp.js CHANGED
@@ -20019,7 +20019,7 @@ var package_default;
20019
20019
  var init_package = __esm(() => {
20020
20020
  package_default = {
20021
20021
  name: "@hasna/skills",
20022
- version: "0.10.18",
20022
+ version: "0.10.19",
20023
20023
  description: "Skills library for AI coding agents",
20024
20024
  type: "module",
20025
20025
  bin: {
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.10.18",
10
+ version: "0.10.19",
11
11
  description: "Skills library for AI coding agents",
12
12
  type: "module",
13
13
  bin: {
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.10.18",
24125
+ version: "0.10.19",
24126
24126
  description: "Skills library for AI coding agents",
24127
24127
  type: "module",
24128
24128
  bin: {
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.10.18",
24128
+ version: "0.10.19",
24129
24129
  description: "Skills library for AI coding agents",
24130
24130
  type: "module",
24131
24131
  bin: {
package/dist/index.js CHANGED
@@ -10877,7 +10877,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
10877
10877
  // package.json
10878
10878
  var package_default = {
10879
10879
  name: "@hasna/skills",
10880
- version: "0.10.18",
10880
+ version: "0.10.19",
10881
10881
  description: "Skills library for AI coding agents",
10882
10882
  type: "module",
10883
10883
  bin: {
package/dist/sdk/index.js CHANGED
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
32373
32373
  // package.json
32374
32374
  var package_default = {
32375
32375
  name: "@hasna/skills",
32376
- version: "0.10.18",
32376
+ version: "0.10.19",
32377
32377
  description: "Skills library for AI coding agents",
32378
32378
  type: "module",
32379
32379
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.10.18",
3
+ "version": "0.10.19",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {