@hasna/skills 0.10.1 → 0.10.3

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/dist/index.js CHANGED
@@ -6988,7 +6988,7 @@ var require_public_api = __commonJS((exports) => {
6988
6988
  });
6989
6989
 
6990
6990
  // src/lib/registry.ts
6991
- import { existsSync as existsSync14, readFileSync as readFileSync17, readdirSync as readdirSync11 } from "fs";
6991
+ import { existsSync as existsSync14, readFileSync as readFileSync18, readdirSync as readdirSync11 } from "fs";
6992
6992
  import { join as join29 } from "path";
6993
6993
 
6994
6994
  // src/lib/config.ts
@@ -9091,7 +9091,7 @@ function assertAgentPolicyCollections(policy) {
9091
9091
 
9092
9092
  // src/lib/agent-discovery.ts
9093
9093
  import { createHash as createHash16 } from "crypto";
9094
- import { lstatSync as lstatSync20, readFileSync as readFileSync16, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
9094
+ import { lstatSync as lstatSync20, readFileSync as readFileSync17, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
9095
9095
  import { basename as basename8, dirname as dirname16, isAbsolute as isAbsolute14, join as join26, resolve as resolve14, sep as sep5 } from "path";
9096
9096
  import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
9097
9097
 
@@ -9611,7 +9611,7 @@ import { isAbsolute as isAbsolute11, join as join23, resolve as resolve11 } from
9611
9611
  // package.json
9612
9612
  var package_default = {
9613
9613
  name: "@hasna/skills",
9614
- version: "0.10.1",
9614
+ version: "0.10.3",
9615
9615
  description: "Skills library for AI coding agents",
9616
9616
  type: "module",
9617
9617
  bin: {
@@ -11823,7 +11823,9 @@ function tarOctal(field) {
11823
11823
 
11824
11824
  // src/lib/selection-cache.ts
11825
11825
  import { createHash as createHash7, randomUUID } from "crypto";
11826
- import { closeSync as closeSync6, constants as constants3, fstatSync as fstatSync6, fsyncSync, lstatSync as lstatSync9, mkdirSync as mkdirSync3, openSync as openSync6, readSync as readSync3, renameSync, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
11826
+ import { spawnSync as spawnSync2 } from "child_process";
11827
+ import { closeSync as closeSync6, constants as constants3, fstatSync as fstatSync6, fsyncSync, lstatSync as lstatSync9, mkdirSync as mkdirSync3, openSync as openSync6, readFileSync as readFileSync9, readlinkSync as readlinkSync2, readSync as readSync3, renameSync, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
11828
+ import { hostname } from "os";
11827
11829
  import { dirname as dirname8, join as join12, parse as parse2, resolve as resolve7 } from "path";
11828
11830
  import { isDeepStrictEqual } from "util";
11829
11831
 
@@ -12124,6 +12126,166 @@ function readSkillSessionSnapshot(sessionId, options = {}) {
12124
12126
  function skillSessionSnapshotBinding(snapshot) {
12125
12127
  return { sessionId: snapshot.sessionId, generation: snapshot.generation, receiptSha256: snapshot.receiptSha256 };
12126
12128
  }
12129
+ var SESSION_LOCK_MAX_BYTES = 4096;
12130
+ var SESSION_LOCK_MIN_AGE_MS = 30000;
12131
+ function localBootId() {
12132
+ try {
12133
+ if (process.platform === "linux") {
12134
+ const value = readFileSync9("/proc/sys/kernel/random/boot_id", "utf8").trim();
12135
+ return /^[a-f0-9-]{36}$/i.test(value) ? value : null;
12136
+ }
12137
+ if (process.platform === "darwin") {
12138
+ const result = spawnSync2("/usr/sbin/sysctl", ["-n", "kern.boottime"], { encoding: "utf8", timeout: 3000, env: { LC_ALL: "C" } });
12139
+ if (result.status !== 0 || result.error)
12140
+ return null;
12141
+ const seconds = /\bsec\s*=\s*(\d+)\b/.exec(result.stdout)?.[1];
12142
+ return seconds ? `darwin:${seconds}` : null;
12143
+ }
12144
+ } catch {}
12145
+ return null;
12146
+ }
12147
+ function processStart(pid) {
12148
+ if (!Number.isSafeInteger(pid) || pid <= 0)
12149
+ return { state: "unknown" };
12150
+ if (process.platform === "linux") {
12151
+ try {
12152
+ const stat = readFileSync9(`/proc/${pid}/stat`, "utf8");
12153
+ const close = stat.lastIndexOf(")");
12154
+ const start = close < 0 ? undefined : stat.slice(close + 2).trim().split(/\s+/)[19];
12155
+ return start && /^\d+$/.test(start) ? { state: "alive", start: `linux:${start}` } : { state: "unknown" };
12156
+ } catch (error) {
12157
+ return { state: error.code === "ENOENT" ? "absent" : "unknown" };
12158
+ }
12159
+ }
12160
+ if (process.platform === "darwin") {
12161
+ const result = spawnSync2("/bin/ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8", timeout: 3000, env: { LC_ALL: "C" } });
12162
+ if (result.error || result.signal)
12163
+ return { state: "unknown" };
12164
+ const start = result.stdout.trim();
12165
+ if (result.status === 1 && !start && !result.stderr.trim())
12166
+ return { state: "absent" };
12167
+ return result.status === 0 && start ? { state: "alive", start: `darwin:${start}` } : { state: "unknown" };
12168
+ }
12169
+ return { state: "unknown" };
12170
+ }
12171
+ function localLockIdentity() {
12172
+ const bootId = localBootId(), owner = processStart(process.pid);
12173
+ if (!bootId || owner.state !== "alive")
12174
+ return null;
12175
+ let pidNamespace;
12176
+ if (process.platform === "linux") {
12177
+ try {
12178
+ pidNamespace = readlinkSync2("/proc/self/ns/pid");
12179
+ } catch {
12180
+ return null;
12181
+ }
12182
+ if (!/^pid:\[\d+\]$/.test(pidNamespace))
12183
+ return null;
12184
+ }
12185
+ return { host: hostname(), bootId, pidNamespace, processStart: owner.start };
12186
+ }
12187
+ function readSessionLock(sessionId, options) {
12188
+ const path = `${sessionReceiptPath(sessionId, options)}.write-lock`;
12189
+ const before = lstatSync9(path, { throwIfNoEntry: false });
12190
+ if (!before)
12191
+ return null;
12192
+ if (!before.isFile() || before.nlink !== 1 || process.getuid && before.uid !== process.getuid()) {
12193
+ throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock is not a private regular file; recovery requires review.");
12194
+ }
12195
+ const bytes = readRegularFile(path, SESSION_LOCK_MAX_BYTES);
12196
+ const after = lstatSync9(path, { throwIfNoEntry: false });
12197
+ if (!bytes || !after?.isFile() || before.dev !== after.dev || before.ino !== after.ino || before.mtimeMs !== after.mtimeMs) {
12198
+ throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock changed during inspection; recovery requires review.");
12199
+ }
12200
+ let marker;
12201
+ try {
12202
+ marker = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
12203
+ } catch {
12204
+ throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock is unreadable; recovery requires review.");
12205
+ }
12206
+ if (!marker || ![1, 2].includes(marker.schemaVersion) || marker.sessionId !== sessionId || !/^[a-f0-9-]{36}$/i.test(marker.operationId) || !Number.isSafeInteger(marker.pid) || marker.pid <= 0 || marker.schemaVersion === 2 && (!marker.host || !marker.bootId || !marker.processStart || process.platform === "linux" && !marker.pidNamespace)) {
12207
+ throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock has invalid ownership metadata; recovery requires review.");
12208
+ }
12209
+ return { path, bytes, marker, sha256: sha256Hex(bytes), dev: after.dev, ino: after.ino, mtimeMs: after.mtimeMs };
12210
+ }
12211
+ function writerIsGone(lock, explicitLocalHost) {
12212
+ if (Date.now() - lock.mtimeMs < SESSION_LOCK_MIN_AGE_MS)
12213
+ return false;
12214
+ const owner = processStart(lock.marker.pid);
12215
+ if (owner.state === "unknown")
12216
+ return false;
12217
+ if (lock.marker.schemaVersion === 1)
12218
+ return explicitLocalHost && owner.state === "absent";
12219
+ const local = localLockIdentity();
12220
+ if (!local || lock.marker.host !== local.host || lock.marker.bootId !== local.bootId || lock.marker.pidNamespace !== local.pidNamespace)
12221
+ return false;
12222
+ return owner.state === "absent" || owner.state === "alive" && owner.start !== lock.marker.processStart;
12223
+ }
12224
+ function archiveSessionLock(lock, receipt, explicitLocalHost) {
12225
+ const guardPath = `${lock.path}.recovery-guard`;
12226
+ let guardFd;
12227
+ try {
12228
+ guardFd = openSync6(guardPath, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, 384);
12229
+ } catch (error) {
12230
+ if (error.code === "EEXIST")
12231
+ return null;
12232
+ throw error;
12233
+ }
12234
+ const guardStat = fstatSync6(guardFd);
12235
+ try {
12236
+ writeFileSync3(guardFd, `${JSON.stringify({ schemaVersion: 1, pid: process.pid, operationId: randomUUID() })}
12237
+ `);
12238
+ fsyncSync(guardFd);
12239
+ const cacheOptions = { cacheDir: dirname8(dirname8(lock.path)) };
12240
+ const current = readSessionLock(lock.marker.sessionId, cacheOptions);
12241
+ if (!current || current.dev !== lock.dev || current.ino !== lock.ino || current.sha256 !== lock.sha256 || current.mtimeMs !== lock.mtimeMs || !writerIsGone(current, explicitLocalHost))
12242
+ return null;
12243
+ const currentReceipt = readSkillSessionSnapshotIfExists(lock.marker.sessionId, cacheOptions);
12244
+ if (currentReceipt?.sha256 !== receipt?.sha256 || currentReceipt?.generation !== receipt?.generation)
12245
+ return null;
12246
+ const directory = join12(dirname8(dirname8(lock.path)), "session-lock-recoveries", randomUUID());
12247
+ const archivePath = join12(directory, "original.write-lock");
12248
+ const recordPath = join12(directory, "recovery.json");
12249
+ assertRegularPath(archivePath, true);
12250
+ archiveBytes(recordPath, Buffer.from(`${JSON.stringify({
12251
+ schemaVersion: 1,
12252
+ sessionId: lock.marker.sessionId,
12253
+ originalPath: lock.path,
12254
+ lockSha256: lock.sha256,
12255
+ lockMtime: new Date(lock.mtimeMs).toISOString(),
12256
+ lockPid: lock.marker.pid,
12257
+ receiptSha256: receipt?.sha256 ?? null,
12258
+ receiptGeneration: receipt?.generation ?? null,
12259
+ status: "prepared"
12260
+ })}
12261
+ `));
12262
+ syncDirectory(directory);
12263
+ syncDirectory(dirname8(directory));
12264
+ const finalLock = readSessionLock(lock.marker.sessionId, cacheOptions);
12265
+ if (!finalLock || finalLock.dev !== lock.dev || finalLock.ino !== lock.ino || finalLock.sha256 !== lock.sha256 || readSkillSessionSnapshotIfExists(lock.marker.sessionId, cacheOptions)?.sha256 !== receipt?.sha256)
12266
+ return null;
12267
+ let moved = false;
12268
+ try {
12269
+ renameSync(lock.path, archivePath);
12270
+ moved = true;
12271
+ syncDirectory(directory);
12272
+ syncDirectory(dirname8(lock.path));
12273
+ if (sha256Hex(readRegularFile(archivePath, SESSION_LOCK_MAX_BYTES)) !== lock.sha256) {
12274
+ throw new Error("Archived lock bytes changed");
12275
+ }
12276
+ } catch (error) {
12277
+ if (moved)
12278
+ throw new SkillSelectionError("SESSION_LOCK_RECOVERY_INCOMPLETE", "The lock moved, but durable recovery could not be confirmed; inspect the preserved recovery directory and session receipt.");
12279
+ throw error;
12280
+ }
12281
+ return archivePath;
12282
+ } finally {
12283
+ closeSync6(guardFd);
12284
+ const current = lstatSync9(guardPath, { throwIfNoEntry: false });
12285
+ if (current?.isFile() && current.dev === guardStat.dev && current.ino === guardStat.ino)
12286
+ unlinkSync(guardPath);
12287
+ }
12288
+ }
12127
12289
  function withSessionWriteLocks(sessionIds, options, action) {
12128
12290
  const operationId = randomUUID();
12129
12291
  const locks = [...new Set(sessionIds)].map((sessionId) => ({ sessionId, path: `${sessionReceiptPath(sessionId, options)}.write-lock` })).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
@@ -12143,13 +12305,30 @@ function withSessionWriteLocks(sessionIds, options, action) {
12143
12305
  try {
12144
12306
  fd = openSync6(lock.path, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, 384);
12145
12307
  } catch (error) {
12146
- if (error.code === "EEXIST")
12147
- throw new SkillSelectionError("SESSION_WRITE_LOCKED", "Another Skills process owns a required session write lock; retry after it completes. A surviving lock requires explicit recovery review.");
12148
- throw error;
12308
+ if (error.code !== "EEXIST")
12309
+ throw error;
12310
+ try {
12311
+ const stale = readSessionLock(lock.sessionId, options);
12312
+ const receipt = stale && readSkillSessionSnapshotIfExists(lock.sessionId, options);
12313
+ if (stale?.marker.schemaVersion === 2 && writerIsGone(stale, false)) {
12314
+ archiveSessionLock(stale, receipt, false);
12315
+ }
12316
+ } catch (recoveryError) {
12317
+ if (recoveryError instanceof SkillSelectionError && recoveryError.code === "SESSION_LOCK_RECOVERY_INCOMPLETE")
12318
+ throw recoveryError;
12319
+ }
12320
+ try {
12321
+ fd = openSync6(lock.path, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, 384);
12322
+ } catch (retryError) {
12323
+ if (retryError.code === "EEXIST")
12324
+ throw new SkillSelectionError("SESSION_WRITE_LOCKED", "Another Skills process owns a required session write lock; retry after it completes. A surviving legacy lock requires explicit recovery review.");
12325
+ throw retryError;
12326
+ }
12149
12327
  }
12150
12328
  const stat = fstatSync6(fd);
12151
12329
  owned.push({ path: lock.path, fd, dev: stat.dev, ino: stat.ino });
12152
- writeFileSync3(fd, `${JSON.stringify({ schemaVersion: 1, operationId, sessionId: lock.sessionId, pid: process.pid })}
12330
+ const identity3 = localLockIdentity();
12331
+ writeFileSync3(fd, `${JSON.stringify({ schemaVersion: identity3 ? 2 : 1, operationId, sessionId: lock.sessionId, pid: process.pid, ...identity3 })}
12153
12332
  `);
12154
12333
  }
12155
12334
  return action(assertOwned);
@@ -12268,7 +12447,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
12268
12447
  }
12269
12448
 
12270
12449
  // src/lib/dependency-preparation.ts
12271
- import { constants as constants4, closeSync as closeSync7, fstatSync as fstatSync7, lstatSync as lstatSync10, mkdirSync as mkdirSync4, openSync as openSync7, readFileSync as readFileSync9, readdirSync as readdirSync5, rmdirSync, unlinkSync as unlinkSync2, ftruncateSync, writeSync } from "fs";
12450
+ import { constants as constants4, closeSync as closeSync7, fstatSync as fstatSync7, lstatSync as lstatSync10, mkdirSync as mkdirSync4, openSync as openSync7, readFileSync as readFileSync10, readdirSync as readdirSync5, rmdirSync, unlinkSync as unlinkSync2, ftruncateSync, writeSync } from "fs";
12272
12451
  import { join as join13 } from "path";
12273
12452
 
12274
12453
  // src/lib/preparation-process.ts
@@ -12342,7 +12521,7 @@ function claimPreparation(skillPath) {
12342
12521
  return;
12343
12522
  if (!lstatSync10(state).isFile() || lstatSync10(state).isSymbolicLink() || lstatSync10(state).size > 1024)
12344
12523
  return;
12345
- const previous = JSON.parse(readFileSync9(state, "utf8"));
12524
+ const previous = JSON.parse(readFileSync10(state, "utf8"));
12346
12525
  if (previous.version !== 1 || previous.status !== "failed" || Object.keys(previous).length !== 2)
12347
12526
  return;
12348
12527
  }
@@ -12475,11 +12654,11 @@ async function prepareSkillDependencies(skillPath, env, timeoutMs = DEFAULT_PREP
12475
12654
  }
12476
12655
 
12477
12656
  // src/lib/skillinfo.ts
12478
- import { existsSync as existsSync12, readFileSync as readFileSync15 } from "fs";
12657
+ import { existsSync as existsSync12, readFileSync as readFileSync16 } from "fs";
12479
12658
  import { join as join20 } from "path";
12480
12659
 
12481
12660
  // src/lib/installer.ts
12482
- import { existsSync as existsSync11, readFileSync as readFileSync14, rmSync as rmSync2 } from "fs";
12661
+ import { existsSync as existsSync11, readFileSync as readFileSync15, rmSync as rmSync2 } from "fs";
12483
12662
  import { join as join19 } from "path";
12484
12663
  import { homedir as homedir4 } from "os";
12485
12664
 
@@ -12490,7 +12669,7 @@ import {
12490
12669
  lstatSync as lstatSync15,
12491
12670
  mkdirSync as mkdirSync6,
12492
12671
  mkdtempSync,
12493
- readFileSync as readFileSync12,
12672
+ readFileSync as readFileSync13,
12494
12673
  readdirSync as readdirSync8,
12495
12674
  renameSync as renameSync3,
12496
12675
  rmSync,
@@ -12502,7 +12681,7 @@ import { basename as basename5, dirname as dirname11, join as join17 } from "pat
12502
12681
 
12503
12682
  // src/lib/agent-integration.ts
12504
12683
  import { createHash as createHash10, randomUUID as randomUUID2 } from "crypto";
12505
- import { existsSync as existsSync8, lstatSync as lstatSync14, statSync as statSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync11, readdirSync as readdirSync7, opendirSync as opendirSync3, readlinkSync as readlinkSync2, realpathSync as realpathSync3, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync10, closeSync as closeSync10, fsyncSync as fsyncSync2, fstatSync as fstatSync10, readSync as readSync6, constants as constants7, linkSync } from "fs";
12684
+ import { existsSync as existsSync8, lstatSync as lstatSync14, statSync as statSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync12, readdirSync as readdirSync7, opendirSync as opendirSync3, readlinkSync as readlinkSync3, realpathSync as realpathSync3, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync10, closeSync as closeSync10, fsyncSync as fsyncSync2, fstatSync as fstatSync10, readSync as readSync6, constants as constants7, linkSync } from "fs";
12506
12685
  import { dirname as dirname10, join as join16, resolve as resolve9, relative as relative4, isAbsolute as isAbsolute9, sep as sep4 } from "path";
12507
12686
  import { homedir as homedir2 } from "os";
12508
12687
 
@@ -12588,7 +12767,7 @@ function requiresCliSkillLoading(dataDir2 = getDataDirReadOnly()) {
12588
12767
 
12589
12768
  // src/lib/agent-bridge.ts
12590
12769
  import { createHash as createHash8 } from "crypto";
12591
- import { lstatSync as lstatSync12, readFileSync as readFileSync10, readdirSync as readdirSync6 } from "fs";
12770
+ import { lstatSync as lstatSync12, readFileSync as readFileSync11, readdirSync as readdirSync6 } from "fs";
12592
12771
  import { join as join15 } from "path";
12593
12772
  var CLI_BRIDGE_NAME = "skills-cli";
12594
12773
  var CLI_BRIDGE_VERSION = 1;
@@ -12622,7 +12801,7 @@ function isOwnedCliBridge(path, expectedPaths) {
12622
12801
  return false;
12623
12802
  return Object.entries(CLI_BRIDGE_FILES).every(([name, content]) => {
12624
12803
  const file = join15(path, name), stat = lstatSync12(file);
12625
- return stat.isFile() && !stat.isSymbolicLink() && stat.size === Buffer.byteLength(content) && readFileSync10(file, "utf8") === content;
12804
+ return stat.isFile() && !stat.isSymbolicLink() && stat.size === Buffer.byteLength(content) && readFileSync11(file, "utf8") === content;
12626
12805
  });
12627
12806
  } catch {
12628
12807
  return false;
@@ -13022,7 +13201,7 @@ function readRootAlias(home, agent) {
13022
13201
  const stat = lstatSync14(alias, { throwIfNoEntry: false, bigint: true });
13023
13202
  if (!stat?.isSymbolicLink())
13024
13203
  throw new Error(`Agent root alias changed after planning: ${alias}`);
13025
- const link = readlinkSync2(alias), targetPath = resolve9(dirname10(alias), link);
13204
+ const link = readlinkSync3(alias), targetPath = resolve9(dirname10(alias), link);
13026
13205
  assertSafePath(targetPath);
13027
13206
  const targetStat = lstatSync14(targetPath, { throwIfNoEntry: false });
13028
13207
  if (!targetStat?.isDirectory())
@@ -13130,8 +13309,8 @@ function selectNativeMigrationTargets(inventory, manifest) {
13130
13309
  if (matches.length !== 1)
13131
13310
  throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
13132
13311
  const entry = matches[0];
13133
- if (entry.bridge || entry.system || entry.vendor)
13134
- throw new Error(`Native migration target is protected or vendor-owned: ${entry.path}`);
13312
+ if (entry.bridge || entry.system || entry.vendor !== (target.vendor === true))
13313
+ throw new Error(`Native migration target is protected or vendor classification changed: ${entry.path}`);
13135
13314
  if (entry.hash !== target.treeSha256 || treeHash(entry.path) !== target.treeSha256)
13136
13315
  throw new Error(`Native migration target changed after review: ${entry.path}`);
13137
13316
  selected.push(entry);
@@ -13154,6 +13333,8 @@ function projectAncestorDirectories(projects) {
13154
13333
  return [...directories];
13155
13334
  }
13156
13335
  function inventoryNativeSkills(home = homedir2(), options = {}) {
13336
+ if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute9(options.reviewedCacheAlias) || resolve9(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
13337
+ throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
13157
13338
  const aliases = rootAliases(home, options.allowRootAliases);
13158
13339
  const selectedAgents = options.agents ? new Set(options.agents) : undefined;
13159
13340
  const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
@@ -13174,14 +13355,22 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
13174
13355
  if (discoveryPathBytes > 4 * 1024 * 1024)
13175
13356
  throw new Error("Native skill discovery metadata limit exceeded");
13176
13357
  }
13177
- function emptySiblingCacheAlias(path, parent) {
13178
- const link = readlinkSync2(path), target = resolve9(parent, link);
13358
+ let reviewedCacheAliasFound = false;
13359
+ function verifiedSiblingCacheAlias(path, parent) {
13360
+ const link = readlinkSync3(path), target = resolve9(parent, link);
13179
13361
  if (dirname10(target) !== parent || (isAbsolute9(link) ? link !== target : dirname10(link) !== "."))
13180
13362
  return false;
13181
13363
  if (!lstatSync14(target, { throwIfNoEntry: false })?.isDirectory())
13182
13364
  return false;
13183
13365
  const scan = cacheScans.get(target);
13184
- return Boolean(scan?.complete && !scan.hasSkills && scan.entries <= maxAliasProofEntries);
13366
+ if (!scan?.complete || scan.entries > maxAliasProofEntries)
13367
+ return false;
13368
+ if (scan.hasSkills) {
13369
+ if (path !== options.reviewedCacheAlias)
13370
+ return false;
13371
+ reviewedCacheAliasFound = true;
13372
+ }
13373
+ return true;
13185
13374
  }
13186
13375
  function visit2(agent, path, vendor = false, depth = 0, pluginCache = false, admitted = false) {
13187
13376
  if (!admitted)
@@ -13204,7 +13393,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
13204
13393
  const marker = join16(path, ".hasna-skills.json");
13205
13394
  if (existsSync8(marker)) {
13206
13395
  try {
13207
- managed = JSON.parse(readFileSync11(marker, "utf8")).managedBy === "@hasna/skills";
13396
+ managed = JSON.parse(readFileSync12(marker, "utf8")).managedBy === "@hasna/skills";
13208
13397
  } catch {}
13209
13398
  }
13210
13399
  const bridge = !vendor && isOwnedCliBridge(path, bridgePaths);
@@ -13238,7 +13427,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
13238
13427
  const child = join16(path, name);
13239
13428
  if (isVendor && lstatSync14(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
13240
13429
  const target = statSync7(child, { throwIfNoEntry: false });
13241
- if (target?.isFile() || pluginCache && target?.isDirectory() && emptySiblingCacheAlias(child, path)) {
13430
+ if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(child, path)) {
13242
13431
  scan.entries++;
13243
13432
  continue;
13244
13433
  }
@@ -13272,12 +13461,14 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
13272
13461
  for (const root of [...options.agentRoots ?? [], ...configured])
13273
13462
  if (includesAgent(root.agent))
13274
13463
  scanRoot(root.agent, canonicalAgentPath(root.path, aliases), true);
13464
+ if (options.reviewedCacheAlias !== undefined && !reviewedCacheAliasFound)
13465
+ throw new Error("Reviewed cache alias was not an inventoried skill-containing sibling alias");
13275
13466
  recheckRootAliases(aliases);
13276
13467
  return entries;
13277
13468
  }
13278
13469
  function readOptional(path) {
13279
13470
  assertSafePath(path);
13280
- return existsSync8(path) ? readFileSync11(path, "utf8") : null;
13471
+ return existsSync8(path) ? readFileSync12(path, "utf8") : null;
13281
13472
  }
13282
13473
  function jsonObject(text2, path) {
13283
13474
  if (text2 === null)
@@ -13989,7 +14180,7 @@ function hasSkillsOwnershipMarker(dir) {
13989
14180
  try {
13990
14181
  if (!lstatSync15(path).isFile())
13991
14182
  return false;
13992
- const marker = JSON.parse(readFileSync12(path, "utf8"));
14183
+ const marker = JSON.parse(readFileSync13(path, "utf8"));
13993
14184
  return isSkillsOwnershipMarker(marker);
13994
14185
  } catch {
13995
14186
  return false;
@@ -14198,7 +14389,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
14198
14389
  if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
14199
14390
  let existingIsStub = false;
14200
14391
  try {
14201
- existingIsStub = isPointerSkillMd(readFileSync12(skillMdPath, "utf-8"));
14392
+ existingIsStub = isPointerSkillMd(readFileSync13(skillMdPath, "utf-8"));
14202
14393
  } catch {
14203
14394
  existingIsStub = false;
14204
14395
  }
@@ -14278,7 +14469,7 @@ function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = f
14278
14469
  if (kind === undefined || kind === "instruction" || preferBundledDocs) {
14279
14470
  const skillMdPath = join17(skillPath, "SKILL.md");
14280
14471
  if (existsSync9(skillMdPath))
14281
- return readFileSync12(skillMdPath, "utf-8");
14472
+ return readFileSync13(skillMdPath, "utf-8");
14282
14473
  }
14283
14474
  return pointerSkillMd(name, description);
14284
14475
  }
@@ -14318,7 +14509,7 @@ function resolveSkillAlias(name) {
14318
14509
  }
14319
14510
 
14320
14511
  // src/lib/project-state.ts
14321
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "fs";
14512
+ import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync14, writeFileSync as writeFileSync6 } from "fs";
14322
14513
  import { join as join18 } from "path";
14323
14514
  var VALID_PIN_SOURCES = [
14324
14515
  "official",
@@ -14344,7 +14535,7 @@ function loadProjectConfig(targetDir = process.cwd()) {
14344
14535
  if (!existsSync10(path))
14345
14536
  return null;
14346
14537
  try {
14347
- return normalizeProjectConfig(JSON.parse(readFileSync13(path, "utf-8")));
14538
+ return normalizeProjectConfig(JSON.parse(readFileSync14(path, "utf-8")));
14348
14539
  } catch {
14349
14540
  return null;
14350
14541
  }
@@ -14531,7 +14722,7 @@ function createLocalSkillManifest(name, generateSkillMd) {
14531
14722
  let skillMd = "";
14532
14723
  const skillMdPath = join19(sourcePath, "SKILL.md");
14533
14724
  if (existsSync11(skillMdPath)) {
14534
- skillMd = readFileSync14(skillMdPath, "utf-8");
14725
+ skillMd = readFileSync15(skillMdPath, "utf-8");
14535
14726
  } else if (generateSkillMd) {
14536
14727
  skillMd = generateSkillMd(name) ?? "";
14537
14728
  } else {
@@ -14650,7 +14841,7 @@ function resolveAgentSkillMd(name, generateSkillMd) {
14650
14841
  const sourcePath = getSkillPath(name);
14651
14842
  const skillMdPath = join19(sourcePath, "SKILL.md");
14652
14843
  if (existsSync11(skillMdPath))
14653
- return readFileSync14(skillMdPath, "utf-8");
14844
+ return readFileSync15(skillMdPath, "utf-8");
14654
14845
  if (generateSkillMd)
14655
14846
  return generateSkillMd(name);
14656
14847
  return generateMinimalSkillMd(name);
@@ -14706,14 +14897,14 @@ function readBundledSkillVersion(name) {
14706
14897
  if (!existsSync11(pkgPath))
14707
14898
  return "unknown";
14708
14899
  try {
14709
- const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
14900
+ const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
14710
14901
  return pkg.version || "unknown";
14711
14902
  } catch {
14712
14903
  return "unknown";
14713
14904
  }
14714
14905
  }
14715
14906
  function readFileIfExists(path) {
14716
- return existsSync11(path) ? readFileSync14(path, "utf-8") : null;
14907
+ return existsSync11(path) ? readFileSync15(path, "utf-8") : null;
14717
14908
  }
14718
14909
  function loadProjectConfigCompat(targetDir) {
14719
14910
  return loadProjectConfig(targetDir);
@@ -14761,7 +14952,7 @@ function isInstructionSkillDir(skillPath, meta) {
14761
14952
  if (!existsSync12(skillMdPath))
14762
14953
  return false;
14763
14954
  try {
14764
- return parseSkillFrontmatter(readFileSync15(skillMdPath, "utf-8"))?.kind === "instruction";
14955
+ return parseSkillFrontmatter(readFileSync16(skillMdPath, "utf-8"))?.kind === "instruction";
14765
14956
  } catch {
14766
14957
  return false;
14767
14958
  }
@@ -14812,7 +15003,7 @@ function getSkillRequirements(name) {
14812
15003
  const meta = getSkill(name);
14813
15004
  let dependencies = {};
14814
15005
  try {
14815
- dependencies = JSON.parse(readFileSync15(join20(skillPath, "package.json"), "utf8")).dependencies || {};
15006
+ dependencies = JSON.parse(readFileSync16(join20(skillPath, "package.json"), "utf8")).dependencies || {};
14816
15007
  } catch {}
14817
15008
  return getSkillRequirementsFromContent(name, texts, dependencies, meta);
14818
15009
  }
@@ -14880,7 +15071,7 @@ async function runSkill(name, args, options = {}) {
14880
15071
  }
14881
15072
  let entryPoint2;
14882
15073
  try {
14883
- const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
15074
+ const pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
14884
15075
  if (pkg.bin) {
14885
15076
  const binValues = Object.values(pkg.bin);
14886
15077
  entryPoint2 = binValues[0];
@@ -14983,7 +15174,7 @@ function generateSkillMd(name) {
14983
15174
  const pkgPath = join20(skillPath, "package.json");
14984
15175
  if (existsSync12(pkgPath)) {
14985
15176
  try {
14986
- const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
15177
+ const pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
14987
15178
  if (pkg.bin) {
14988
15179
  const binKeys = Object.keys(pkg.bin);
14989
15180
  if (binKeys.length > 0)
@@ -15059,7 +15250,7 @@ function extractEnvVars(text2) {
15059
15250
  function readIfExists(path) {
15060
15251
  try {
15061
15252
  if (existsSync12(path)) {
15062
- return readFileSync15(path, "utf-8");
15253
+ return readFileSync16(path, "utf-8");
15063
15254
  }
15064
15255
  } catch {}
15065
15256
  return null;
@@ -16569,7 +16760,7 @@ function read2(path, changes) {
16569
16760
  return null;
16570
16761
  if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
16571
16762
  throw new Error(`Unsupported or oversized native discovery input: ${path}`);
16572
- return readFileSync16(path, "utf8");
16763
+ return readFileSync17(path, "utf8");
16573
16764
  }
16574
16765
  function projected(source, changes, budget = discoveryByteBudget()) {
16575
16766
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
@@ -17660,7 +17851,7 @@ function discoverSkillsInDir(dir, source = "custom") {
17660
17851
  continue;
17661
17852
  let content;
17662
17853
  try {
17663
- content = readFileSync17(skillMdPath, "utf-8");
17854
+ content = readFileSync18(skillMdPath, "utf-8");
17664
17855
  } catch {
17665
17856
  continue;
17666
17857
  }
@@ -17697,7 +17888,7 @@ function findExtensionSkillPath(name) {
17697
17888
  continue;
17698
17889
  let content;
17699
17890
  try {
17700
- content = readFileSync17(skillMdPath, "utf-8");
17891
+ content = readFileSync18(skillMdPath, "utf-8");
17701
17892
  } catch {
17702
17893
  continue;
17703
17894
  }
@@ -17762,7 +17953,7 @@ function getAllTags() {
17762
17953
  }
17763
17954
  // src/lib/run-state.ts
17764
17955
  import { createHash as createHash17, randomBytes } from "crypto";
17765
- import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync18, readdirSync as readdirSync12, statSync as statSync10, writeFileSync as writeFileSync9 } from "fs";
17956
+ import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync19, readdirSync as readdirSync12, statSync as statSync10, writeFileSync as writeFileSync9 } from "fs";
17766
17957
  import { extname, join as join30, relative as relative6 } from "path";
17767
17958
  function createSkillRun(params, targetDir = process.cwd()) {
17768
17959
  const now = new Date;
@@ -17834,7 +18025,7 @@ function appendRunEvent(context, event, data = {}) {
17834
18025
  const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
17835
18026
  `;
17836
18027
  const path = join30(context.runDir, "events.ndjson");
17837
- const previous = existsSync15(path) ? readFileSync18(path, "utf-8") : "";
18028
+ const previous = existsSync15(path) ? readFileSync19(path, "utf-8") : "";
17838
18029
  writeFileSync9(path, previous + line);
17839
18030
  }
17840
18031
  function listSkillRuns(targetDir = process.cwd(), limit = 50) {
@@ -17884,7 +18075,7 @@ function collectRunArtifacts(context) {
17884
18075
  const artifacts = [];
17885
18076
  for (const path of walkFiles(context.exportDir)) {
17886
18077
  const stat2 = statSync10(path);
17887
- const bytes = readFileSync18(path);
18078
+ const bytes = readFileSync19(path);
17888
18079
  artifacts.push({
17889
18080
  path: toProjectRelative(context.targetDir, path),
17890
18081
  mime: mimeForPath(path),
@@ -17899,7 +18090,7 @@ function readRunRecord(runDir) {
17899
18090
  if (!existsSync15(path))
17900
18091
  return null;
17901
18092
  try {
17902
- return JSON.parse(readFileSync18(path, "utf-8"));
18093
+ return JSON.parse(readFileSync19(path, "utf-8"));
17903
18094
  } catch {
17904
18095
  return null;
17905
18096
  }
@@ -18069,7 +18260,7 @@ __export(exports_external, {
18069
18260
  input: () => input,
18070
18261
  includes: () => _includes,
18071
18262
  httpUrl: () => httpUrl,
18072
- hostname: () => hostname2,
18263
+ hostname: () => hostname3,
18073
18264
  hex: () => hex2,
18074
18265
  hash: () => hash2,
18075
18266
  guid: () => guid2,
@@ -19855,7 +20046,7 @@ __export(exports_regexes, {
19855
20046
  idnEmail: () => idnEmail,
19856
20047
  httpProtocol: () => httpProtocol,
19857
20048
  html5Email: () => html5Email,
19858
- hostname: () => hostname,
20049
+ hostname: () => hostname2,
19859
20050
  hex: () => hex,
19860
20051
  guid: () => guid,
19861
20052
  extendedDuration: () => extendedDuration,
@@ -19917,7 +20108,7 @@ var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]
19917
20108
  var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
19918
20109
  var base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
19919
20110
  var base64url = /^[A-Za-z0-9_-]*$/;
19920
- var hostname = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
20111
+ var hostname2 = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
19921
20112
  var domain = /^(?=.{1,253}$)([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}$/;
19922
20113
  var httpProtocol = /^https?$/;
19923
20114
  var e164 = /^\+[1-9]\d{6,14}$/;
@@ -20754,9 +20945,9 @@ var asciiTabOrNewline = /[\t\n\r]/g;
20754
20945
  function stripTabAndNewline(value) {
20755
20946
  return value.replace(asciiTabOrNewline, "");
20756
20947
  }
20757
- function urlHostnameOk(url, hostname2) {
20758
- hostname2.lastIndex = 0;
20759
- return hostname2.test(url.hostname);
20948
+ function urlHostnameOk(url, hostname3) {
20949
+ hostname3.lastIndex = 0;
20950
+ return hostname3.test(url.hostname);
20760
20951
  }
20761
20952
  function urlProtocolOk(url, protocol) {
20762
20953
  protocol.lastIndex = 0;
@@ -34144,7 +34335,7 @@ __export(exports_schemas2, {
34144
34335
  int: () => int,
34145
34336
  instanceof: () => _instanceof,
34146
34337
  httpUrl: () => httpUrl,
34147
- hostname: () => hostname2,
34338
+ hostname: () => hostname3,
34148
34339
  hex: () => hex2,
34149
34340
  hash: () => hash2,
34150
34341
  guid: () => guid2,
@@ -34854,7 +35045,7 @@ var ZodCustomStringFormat = /* @__PURE__ */ $constructor("ZodCustomStringFormat"
34854
35045
  function stringFormat(format, fnOrRegex, _params = {}) {
34855
35046
  return _stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params);
34856
35047
  }
34857
- function hostname2(_params) {
35048
+ function hostname3(_params) {
34858
35049
  return _stringFormat(ZodCustomStringFormat, "hostname", exports_regexes.hostname, _params);
34859
35050
  }
34860
35051
  function hex2(_params) {
@@ -39414,7 +39605,7 @@ async function createRemoteSkillsClient(env = process.env) {
39414
39605
  return connection ? new RemoteSkillsClient(connection.apiKey, connection.apiOrigin) : null;
39415
39606
  }
39416
39607
  // src/lib/scheduler.ts
39417
- import { existsSync as existsSync16, readFileSync as readFileSync19, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11 } from "fs";
39608
+ import { existsSync as existsSync16, readFileSync as readFileSync20, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11 } from "fs";
39418
39609
  import { join as join31 } from "path";
39419
39610
  function getSchedulesPath(targetDir = process.cwd()) {
39420
39611
  return join31(targetDir, ".skills", "schedules.json");
@@ -39423,7 +39614,7 @@ function loadSchedules(targetDir = process.cwd()) {
39423
39614
  const path = getSchedulesPath(targetDir);
39424
39615
  if (existsSync16(path)) {
39425
39616
  try {
39426
- return JSON.parse(readFileSync19(path, "utf-8"));
39617
+ return JSON.parse(readFileSync20(path, "utf-8"));
39427
39618
  } catch {}
39428
39619
  }
39429
39620
  return { version: 1, schedules: [] };
@@ -39646,7 +39837,7 @@ function revisionIdOfRecord(record7) {
39646
39837
  return revisionIdOf(record7);
39647
39838
  }
39648
39839
  // src/lib/pull.ts
39649
- import { existsSync as existsSync17, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync20, renameSync as renameSync6, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "fs";
39840
+ import { existsSync as existsSync17, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync21, renameSync as renameSync6, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "fs";
39650
39841
  import { dirname as dirname19, join as join32 } from "path";
39651
39842
 
39652
39843
  // src/lib/skill-bundles.ts
@@ -39846,7 +40037,7 @@ function reconcileTombstone(slug2, corpusOptions) {
39846
40037
  }
39847
40038
  function readPullMarker(dir) {
39848
40039
  try {
39849
- return JSON.parse(readFileSync20(join32(dir, PULL_MARKER_FILE), "utf-8"));
40040
+ return JSON.parse(readFileSync21(join32(dir, PULL_MARKER_FILE), "utf-8"));
39850
40041
  } catch {
39851
40042
  return null;
39852
40043
  }
@@ -42098,7 +42289,7 @@ import { createHash as createHash21, createHmac as createHmac2 } from "crypto";
42098
42289
  import {
42099
42290
  existsSync as existsSync19,
42100
42291
  mkdirSync as mkdirSync15,
42101
- readFileSync as readFileSync21,
42292
+ readFileSync as readFileSync23,
42102
42293
  readdirSync as readdirSync13,
42103
42294
  statSync as statSync11,
42104
42295
  writeFileSync as writeFileSync13
@@ -42265,7 +42456,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
42265
42456
  const files = [];
42266
42457
  if (existsSync19(projectStateDir)) {
42267
42458
  for (const filePath of walkFiles2(projectStateDir)) {
42268
- const bytes = readFileSync21(filePath);
42459
+ const bytes = readFileSync23(filePath);
42269
42460
  const relativePath = toPosix(relative8(targetDir, filePath));
42270
42461
  files.push({
42271
42462
  path: relativePath,
@@ -42683,7 +42874,7 @@ import { createHash as createHash22 } from "crypto";
42683
42874
  import {
42684
42875
  copyFileSync,
42685
42876
  mkdirSync as mkdirSync16,
42686
- readFileSync as readFileSync23,
42877
+ readFileSync as readFileSync25,
42687
42878
  statSync as statSync13,
42688
42879
  writeFileSync as writeFileSync14
42689
42880
  } from "fs";
@@ -42854,7 +43045,7 @@ function validateStationId(stationId) {
42854
43045
  }
42855
43046
  }
42856
43047
  function sha256File(filePath) {
42857
- return createHash22("sha256").update(readFileSync23(filePath)).digest("hex");
43048
+ return createHash22("sha256").update(readFileSync25(filePath)).digest("hex");
42858
43049
  }
42859
43050
  function scanHome(definition, homesRoot) {
42860
43051
  const homePath = homePathFor(definition, homesRoot);
@@ -43010,7 +43201,7 @@ import {
43010
43201
  copyFileSync as copyFileSync2,
43011
43202
  mkdirSync as mkdirSync17,
43012
43203
  readdirSync as readdirSync15,
43013
- readFileSync as readFileSync25,
43204
+ readFileSync as readFileSync26,
43014
43205
  statSync as statSync14,
43015
43206
  writeFileSync as writeFileSync15
43016
43207
  } from "fs";
@@ -43029,7 +43220,7 @@ function readSnapshotManifest(repoRoot, stationId) {
43029
43220
  const manifestPath = join36(snapshotRoot, "sync-manifest.json");
43030
43221
  let manifest;
43031
43222
  try {
43032
- manifest = JSON.parse(readFileSync25(manifestPath, "utf8"));
43223
+ manifest = JSON.parse(readFileSync26(manifestPath, "utf8"));
43033
43224
  } catch (error61) {
43034
43225
  fail("MANIFEST_UNREADABLE", `cannot read snapshot manifest: ${manifestPath}: ${error61.message}`);
43035
43226
  }
@@ -43165,7 +43356,7 @@ function planStationHydration(stationId, repoRoot) {
43165
43356
  for (const copy of copies) {
43166
43357
  let isStub = false;
43167
43358
  try {
43168
- isStub = isPointerSkillMd(readFileSync25(copy.fullPath, "utf8"));
43359
+ isStub = isPointerSkillMd(readFileSync26(copy.fullPath, "utf8"));
43169
43360
  } catch {
43170
43361
  isStub = false;
43171
43362
  }