@hasna/skills 0.9.9 → 0.9.11

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
@@ -9657,7 +9657,7 @@ import { homedir as homedir5 } from "os";
9657
9657
  import {
9658
9658
  cpSync as cpSync2,
9659
9659
  existsSync as existsSync12,
9660
- lstatSync as lstatSync19,
9660
+ lstatSync as lstatSync20,
9661
9661
  mkdirSync as mkdirSync8,
9662
9662
  mkdtempSync as mkdtempSync2,
9663
9663
  readFileSync as readFileSync15,
@@ -9665,15 +9665,15 @@ import {
9665
9665
  renameSync as renameSync5,
9666
9666
  rmSync as rmSync3,
9667
9667
  statSync as statSync9,
9668
- writeFileSync as writeFileSync6
9668
+ writeFileSync as writeFileSync7
9669
9669
  } from "fs";
9670
9670
  import { homedir as homedir4 } from "os";
9671
- import { basename as basename9, dirname as dirname16, join as join26 } from "path";
9671
+ import { basename as basename9, dirname as dirname17, join as join26 } from "path";
9672
9672
 
9673
9673
  // src/lib/agent-integration.ts
9674
- import { createHash as createHash14, randomUUID as randomUUID3 } from "crypto";
9675
- import { existsSync as existsSync11, lstatSync as lstatSync18, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync14, readdirSync as readdirSync10, opendirSync as opendirSync5, readlinkSync as readlinkSync2, realpathSync as realpathSync5, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4, chmodSync, openSync as openSync11, closeSync as closeSync11, fsyncSync as fsyncSync3, fstatSync as fstatSync11, readSync as readSync9, constants as constants10, linkSync as linkSync2 } from "fs";
9676
- import { dirname as dirname15, join as join25, resolve as resolve15, relative as relative5, isAbsolute as isAbsolute15, sep as sep6 } from "path";
9674
+ import { createHash as createHash16, randomUUID as randomUUID3 } from "crypto";
9675
+ import { existsSync as existsSync11, lstatSync as lstatSync19, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync14, readdirSync as readdirSync10, opendirSync as opendirSync5, readlinkSync as readlinkSync2, realpathSync as realpathSync5, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4, chmodSync, openSync as openSync12, closeSync as closeSync12, fsyncSync as fsyncSync4, fstatSync as fstatSync12, readSync as readSync10, constants as constants11, linkSync as linkSync2 } from "fs";
9676
+ import { dirname as dirname16, join as join25, resolve as resolve15, relative as relative5, isAbsolute as isAbsolute15, sep as sep6 } from "path";
9677
9677
  import { homedir as homedir3 } from "os";
9678
9678
 
9679
9679
  // src/lib/managed-policy.ts
@@ -10970,9 +10970,9 @@ function isOwnedCliBridge(path, expectedPaths) {
10970
10970
  }
10971
10971
 
10972
10972
  // src/lib/agent-discovery.ts
10973
- import { createHash as createHash13 } from "crypto";
10974
- import { lstatSync as lstatSync17, readFileSync as readFileSync13, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
10975
- import { basename as basename8, dirname as dirname14, isAbsolute as isAbsolute14, join as join23, resolve as resolve14, sep as sep5 } from "path";
10973
+ import { createHash as createHash15 } from "crypto";
10974
+ import { lstatSync as lstatSync18, readFileSync as readFileSync13, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
10975
+ import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute14, join as join23, resolve as resolve14, sep as sep5 } from "path";
10976
10976
 
10977
10977
  // node_modules/yaml/dist/index.js
10978
10978
  var composer = require_composer();
@@ -11448,7 +11448,7 @@ import { isAbsolute as isAbsolute10, join as join20, resolve as resolve10 } from
11448
11448
  // package.json
11449
11449
  var package_default = {
11450
11450
  name: "@hasna/skills",
11451
- version: "0.9.9",
11451
+ version: "0.9.11",
11452
11452
  description: "Skills library for AI coding agents",
11453
11453
  type: "module",
11454
11454
  bin: {
@@ -15161,8 +15161,76 @@ function captureClaudeSettings(path, budget = { remaining: 256 * 1024 * 1024 })
15161
15161
  return { path, hashMode: "claude-settings-v1", sha256: settingsDigest(readSettings(path, budget)) };
15162
15162
  }
15163
15163
 
15164
+ // src/lib/codex-hook-discovery-recovery.ts
15165
+ import { createHash as createHash14 } from "crypto";
15166
+
15167
+ // src/lib/codex-hook-trust-files.ts
15168
+ import { closeSync as closeSync11, constants as constants10, fstatSync as fstatSync11, fsyncSync as fsyncSync3, lstatSync as lstatSync17, openSync as openSync11, readSync as readSync9, writeFileSync as writeFileSync5 } from "fs";
15169
+ import { createHash as createHash13 } from "crypto";
15170
+ import { dirname as dirname14 } from "path";
15171
+ function need4(value, code) {
15172
+ if (!value)
15173
+ throw new Error(`CODEX_HOOK_TRUST_${code}`);
15174
+ }
15175
+ var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
15176
+ function safeParents(file) {
15177
+ for (let p = dirname14(file);; p = dirname14(p)) {
15178
+ const s = lstatSync17(p);
15179
+ need4(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
15180
+ need4((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
15181
+ if (dirname14(p) === p)
15182
+ break;
15183
+ }
15184
+ }
15185
+ function snapshot(file, privateFile = false, options = {}) {
15186
+ const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
15187
+ safeParents(file);
15188
+ const initial = lstatSync17(file, { bigint: true });
15189
+ need4(initial.isFile() && initial.uid === BigInt(process.getuid()) && (initial.nlink === 1n || readOnlyPackage && initial.nlink > 1n) && (initial.mode & 0o022n) === 0n && (!privateFile || (initial.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
15190
+ need4(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
15191
+ const fd = openSync11(file, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
15192
+ try {
15193
+ const before = fstatSync11(fd, { bigint: true });
15194
+ need4(sameStat(initial, before), "INPUT_CHANGED");
15195
+ const bytes = Buffer.alloc(Number(before.size) + 1);
15196
+ let length = 0;
15197
+ while (length < bytes.length) {
15198
+ const n2 = readSync9(fd, bytes, length, bytes.length - length, null);
15199
+ if (!n2)
15200
+ break;
15201
+ length += n2;
15202
+ }
15203
+ need4(length === Number(before.size) && sameStat(before, fstatSync11(fd, { bigint: true })) && sameStat(before, lstatSync17(file, { bigint: true })), "INPUT_CHANGED");
15204
+ const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
15205
+ return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash13("sha256").update(content).digest("hex") };
15206
+ } finally {
15207
+ closeSync11(fd);
15208
+ }
15209
+ }
15210
+ function unchanged2(before) {
15211
+ const after = snapshot(before.file, before.privateFile, before.readOnlyPackage ? { readOnlyPackage: true } : {});
15212
+ need4(sameStat(before.stat, after.stat) && after.sha256 === before.sha256, "INPUT_CHANGED");
15213
+ }
15214
+
15215
+ // src/lib/codex-hook-discovery-recovery.ts
15216
+ var sha = (text2) => createHash14("sha256").update(text2).digest("hex");
15217
+ var proofs = new WeakMap;
15218
+ function assertCodexHookDiscoveryRecovery(binding, witness) {
15219
+ const proof = proofs.get(witness);
15220
+ need4(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
15221
+ unchanged2(proof.before);
15222
+ unchanged2(proof.current);
15223
+ }
15224
+ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witness) {
15225
+ if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
15226
+ return false;
15227
+ assertCodexHookDiscoveryRecovery(binding, witness);
15228
+ need4(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
15229
+ return true;
15230
+ }
15231
+
15164
15232
  // src/lib/agent-discovery.ts
15165
- var digest = (text2) => createHash13("sha256").update(text2).digest("hex");
15233
+ var digest = (text2) => createHash15("sha256").update(text2).digest("hex");
15166
15234
  function parseConfig(text2, path, toml = false) {
15167
15235
  try {
15168
15236
  const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
@@ -15176,10 +15244,10 @@ function parseConfig(text2, path, toml = false) {
15176
15244
  function safe4(path) {
15177
15245
  if (!isAbsolute14(path) || path.includes("\x00"))
15178
15246
  throw new Error("Expected an absolute native discovery path");
15179
- for (let cursor = path;; cursor = dirname14(cursor)) {
15180
- if (lstatSync17(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
15247
+ for (let cursor = path;; cursor = dirname15(cursor)) {
15248
+ if (lstatSync18(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
15181
15249
  throw new Error(`Refusing symlink native discovery input: ${cursor}`);
15182
- if (dirname14(cursor) === cursor)
15250
+ if (dirname15(cursor) === cursor)
15183
15251
  break;
15184
15252
  }
15185
15253
  }
@@ -15187,7 +15255,7 @@ function read(path, changes) {
15187
15255
  safe4(path);
15188
15256
  if (changes?.has(path))
15189
15257
  return changes.get(path);
15190
- const stat2 = lstatSync17(path, { throwIfNoEntry: false });
15258
+ const stat2 = lstatSync18(path, { throwIfNoEntry: false });
15191
15259
  if (!stat2)
15192
15260
  return null;
15193
15261
  if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
@@ -15237,7 +15305,9 @@ function projected(source, changes, budget = discoveryByteBudget()) {
15237
15305
  throw new Error("Expected native discovery configuration object");
15238
15306
  return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field2) => [field2, object4[field2] ?? null]))));
15239
15307
  }
15240
- function verifyAgentDiscovery(binding) {
15308
+ function verifyAgentDiscovery(binding, codexRecovery) {
15309
+ if (codexRecovery)
15310
+ assertCodexHookDiscoveryRecovery(binding, codexRecovery);
15241
15311
  if (!binding || !Array.isArray(binding.sources) || !Array.isArray(binding.roots) || binding.sources.length > AGENT_POLICY_LIMITS.discoverySources || binding.roots.length > AGENT_POLICY_LIMITS.discoveryRoots)
15242
15312
  throw new Error("Invalid native discovery binding");
15243
15313
  if (binding.agent === "hermes" && !binding.directories?.length)
@@ -15253,7 +15323,8 @@ function verifyAgentDiscovery(binding) {
15253
15323
  throw new Error("Invalid native discovery projection");
15254
15324
  if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
15255
15325
  throw new Error("Invalid native discovery digest");
15256
- if (projected(source, undefined, budget) !== source.sha256)
15326
+ const current = projected(source, undefined, budget);
15327
+ if (current !== source.sha256 && !verifiesCodexHookDiscoverySource(binding, source, current, codexRecovery))
15257
15328
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
15258
15329
  }
15259
15330
  for (const root2 of binding.roots)
@@ -15325,21 +15396,21 @@ function resolveAgentDiscovery(options) {
15325
15396
  const executable = Bun.which("gemini");
15326
15397
  if (executable) {
15327
15398
  let packageRoot;
15328
- for (let directory = dirname14(realpathSync4(executable)), depth = 0;depth < 8; directory = dirname14(directory), depth++) {
15399
+ for (let directory = dirname15(realpathSync4(executable)), depth = 0;depth < 8; directory = dirname15(directory), depth++) {
15329
15400
  const path = join23(directory, "package.json"), raw = read(path);
15330
15401
  if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
15331
15402
  packageRoot = directory;
15332
15403
  witness(path);
15333
15404
  break;
15334
15405
  }
15335
- if (dirname14(directory) === directory)
15406
+ if (dirname15(directory) === directory)
15336
15407
  break;
15337
15408
  }
15338
15409
  if (!packageRoot)
15339
15410
  unresolved("installed Gemini package layout is not recognized");
15340
15411
  const builtinRoot = join23(packageRoot, "bundle/builtin");
15341
15412
  safe4(builtinRoot);
15342
- if (!lstatSync17(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
15413
+ if (!lstatSync18(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
15343
15414
  unresolved("installed Gemini builtin root is missing");
15344
15415
  for (const name of readdirSync9(builtinRoot).sort()) {
15345
15416
  const text2 = witness(join23(builtinRoot, name, "SKILL.md"));
@@ -15379,7 +15450,7 @@ function resolveAgentDiscovery(options) {
15379
15450
  unresolved("plugin hooks require a separate no-skill-injection review");
15380
15451
  const commands = join23(root2, "commands");
15381
15452
  safe4(commands);
15382
- if (agent === "claude" && (manifest.commands !== undefined || lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
15453
+ if (agent === "claude" && (manifest.commands !== undefined || lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
15383
15454
  unresolved("legacy command discovery requires retirement or a dedicated format adapter");
15384
15455
  const rootSkill = witness(join23(root2, "SKILL.md"));
15385
15456
  if (rootSkill !== null)
@@ -15393,7 +15464,7 @@ function resolveAgentDiscovery(options) {
15393
15464
  const path = resolve14(root2, value);
15394
15465
  if (path !== root2 && !path.startsWith(root2 + sep5))
15395
15466
  unresolved("plugin skill path escapes its root");
15396
- roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname14(path) : path);
15467
+ roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname15(path) : path);
15397
15468
  }
15398
15469
  }
15399
15470
  if (agent === "claude") {
@@ -15401,7 +15472,7 @@ function resolveAgentDiscovery(options) {
15401
15472
  const installed = registrations === null ? {} : parseConfig(registrations, join23(home, ".claude/plugins/installed_plugins.json")).plugins;
15402
15473
  const commands = canonical4(join23(home, ".claude/commands"));
15403
15474
  safe4(commands);
15404
- if (lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
15475
+ if (lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
15405
15476
  unresolved("legacy home command discovery requires a dedicated format adapter");
15406
15477
  for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
15407
15478
  if (enabled === false)
@@ -15443,12 +15514,12 @@ function resolveAgentDiscovery(options) {
15443
15514
  }
15444
15515
  const localPlugins = join23(home, ".config/opencode/plugins");
15445
15516
  safe4(localPlugins);
15446
- if (lstatSync17(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
15517
+ if (lstatSync18(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
15447
15518
  unresolved("additional local plugin hooks require review");
15448
15519
  } else if (agent === "hermes") {
15449
15520
  for (const directory of [join23(home, ".hermes/plugins"), join23(home, ".hermes/hermes-agent")]) {
15450
15521
  safe4(directory);
15451
- if (lstatSync17(directory, { throwIfNoEntry: false }))
15522
+ if (lstatSync18(directory, { throwIfNoEntry: false }))
15452
15523
  unresolved("installed runtime/plugin discovery requires reviewed source bindings");
15453
15524
  }
15454
15525
  if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
@@ -15458,11 +15529,11 @@ function resolveAgentDiscovery(options) {
15458
15529
  unresolved("custom extension or skill paths");
15459
15530
  const directory = join23(home, ".gemini/extensions");
15460
15531
  safe4(directory);
15461
- if (lstatSync17(directory, { throwIfNoEntry: false }))
15532
+ if (lstatSync18(directory, { throwIfNoEntry: false }))
15462
15533
  for (const name of readdirSync9(directory)) {
15463
15534
  const root2 = join23(directory, name);
15464
15535
  safe4(root2);
15465
- if (!lstatSync17(root2)?.isDirectory())
15536
+ if (!lstatSync18(root2)?.isDirectory())
15466
15537
  continue;
15467
15538
  const raw = witness(join23(root2, "gemini-extension.json"));
15468
15539
  if (raw === null)
@@ -15617,7 +15688,7 @@ function disableCodexBundledSkills(text2) {
15617
15688
  }
15618
15689
 
15619
15690
  // src/lib/agent-integration.ts
15620
- var sha = (data) => createHash14("sha256").update(data).digest("hex");
15691
+ var sha2 = (data) => createHash16("sha256").update(data).digest("hex");
15621
15692
  var ROOTS = [
15622
15693
  ["claude", ".claude/skills"],
15623
15694
  ["codex", ".codex/skills"],
@@ -15638,9 +15709,9 @@ var ROOTS = [
15638
15709
  function assertSafePath(path) {
15639
15710
  let cursor = resolve15(path);
15640
15711
  while (true) {
15641
- if (lstatSync18(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
15712
+ if (lstatSync19(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
15642
15713
  throw new Error(`Refusing symlink path: ${cursor}`);
15643
- const parent = dirname15(cursor);
15714
+ const parent = dirname16(cursor);
15644
15715
  if (parent === cursor)
15645
15716
  return;
15646
15717
  cursor = parent;
@@ -15649,12 +15720,12 @@ function assertSafePath(path) {
15649
15720
  function readRootAlias(home, agent) {
15650
15721
  assertSafePath(home);
15651
15722
  const realHome = realpathSync5(home), alias = join25(realHome, `.${agent}`);
15652
- const stat2 = lstatSync18(alias, { throwIfNoEntry: false, bigint: true });
15723
+ const stat2 = lstatSync19(alias, { throwIfNoEntry: false, bigint: true });
15653
15724
  if (!stat2?.isSymbolicLink())
15654
15725
  throw new Error(`Agent root alias changed after planning: ${alias}`);
15655
- const link = readlinkSync2(alias), targetPath = resolve15(dirname15(alias), link);
15726
+ const link = readlinkSync2(alias), targetPath = resolve15(dirname16(alias), link);
15656
15727
  assertSafePath(targetPath);
15657
- const targetStat = lstatSync18(targetPath, { throwIfNoEntry: false });
15728
+ const targetStat = lstatSync19(targetPath, { throwIfNoEntry: false });
15658
15729
  if (!targetStat?.isDirectory())
15659
15730
  throw new Error(`Agent root alias must target an existing directory: ${alias}`);
15660
15731
  const target = realpathSync5(targetPath), inside = relative5(realHome, target);
@@ -15667,7 +15738,7 @@ function rootAliases(home, allowed = false) {
15667
15738
  return [];
15668
15739
  const result = [];
15669
15740
  for (const agent of ["claude", "codex"])
15670
- if (lstatSync18(join25(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
15741
+ if (lstatSync19(join25(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
15671
15742
  result.push(readRootAlias(home, agent));
15672
15743
  if (result.some((item, index) => result.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep6) || other.target.startsWith(item.target + sep6))))
15673
15744
  throw new Error("Agent root alias targets must not overlap");
@@ -15688,35 +15759,35 @@ function recheckRootAliases(aliases) {
15688
15759
  }
15689
15760
  function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
15690
15761
  assertSafePath(path);
15691
- const before = lstatSync18(path);
15762
+ const before = lstatSync19(path);
15692
15763
  if (!before.isFile() || before.size > maximum)
15693
15764
  throw new Error("Unsupported or oversized native skill file");
15694
- const descriptor = openSync11(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
15765
+ const descriptor = openSync12(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
15695
15766
  try {
15696
- const opened = fstatSync11(descriptor);
15767
+ const opened = fstatSync12(descriptor);
15697
15768
  if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino || opened.size !== before.size)
15698
15769
  throw new Error("Native skill file changed while reading");
15699
15770
  const bytes = Buffer.allocUnsafe(before.size + 1);
15700
15771
  let length = 0;
15701
15772
  while (length < bytes.length) {
15702
- const count = readSync9(descriptor, bytes, length, bytes.length - length, null);
15773
+ const count = readSync10(descriptor, bytes, length, bytes.length - length, null);
15703
15774
  if (!count)
15704
15775
  break;
15705
15776
  length += count;
15706
15777
  }
15707
- const after = fstatSync11(descriptor);
15778
+ const after = fstatSync12(descriptor);
15708
15779
  if (length !== before.size || after.size !== before.size || after.mtimeMs !== opened.mtimeMs || after.ctimeMs !== opened.ctimeMs)
15709
15780
  throw new Error("Native skill file changed while reading");
15710
15781
  return bytes.subarray(0, length);
15711
15782
  } finally {
15712
- closeSync11(descriptor);
15783
+ closeSync12(descriptor);
15713
15784
  }
15714
15785
  }
15715
15786
  function treeHash(root2) {
15716
- const hash2 = createHash14("sha256");
15787
+ const hash2 = createHash16("sha256");
15717
15788
  let bytes = 0, files = 0;
15718
15789
  function visit2(path) {
15719
- const stat2 = lstatSync18(path);
15790
+ const stat2 = lstatSync19(path);
15720
15791
  if (stat2.isSymbolicLink())
15721
15792
  throw new Error(`Refusing symlink in skill: ${path}`);
15722
15793
  const rel = relative5(root2, path);
@@ -15746,7 +15817,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
15746
15817
  const selected = [];
15747
15818
  for (const target of manifest.targets) {
15748
15819
  const projectRoot = resolve15(target.projectRoot), normalized = relative5(projectRoot, resolve15(projectRoot, target.path));
15749
- if (!isAbsolute15(target.projectRoot) || projectRoot !== target.projectRoot || !existsSync11(projectRoot) || !lstatSync18(projectRoot).isDirectory())
15820
+ if (!isAbsolute15(target.projectRoot) || projectRoot !== target.projectRoot || !existsSync11(projectRoot) || !lstatSync19(projectRoot).isDirectory())
15750
15821
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
15751
15822
  assertSafePath(projectRoot);
15752
15823
  if (isAbsolute15(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep6}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
@@ -15775,7 +15846,7 @@ function projectAncestorDirectories(projects) {
15775
15846
  if (depth >= 100)
15776
15847
  throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
15777
15848
  directories.add(path);
15778
- const parent = dirname15(path);
15849
+ const parent = dirname16(path);
15779
15850
  if (parent === path)
15780
15851
  break;
15781
15852
  path = parent;
@@ -15806,9 +15877,9 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
15806
15877
  }
15807
15878
  function emptySiblingCacheAlias(path, parent) {
15808
15879
  const link = readlinkSync2(path), target = resolve15(parent, link);
15809
- if (dirname15(target) !== parent || (isAbsolute15(link) ? link !== target : dirname15(link) !== "."))
15880
+ if (dirname16(target) !== parent || (isAbsolute15(link) ? link !== target : dirname16(link) !== "."))
15810
15881
  return false;
15811
- if (!lstatSync18(target, { throwIfNoEntry: false })?.isDirectory())
15882
+ if (!lstatSync19(target, { throwIfNoEntry: false })?.isDirectory())
15812
15883
  return false;
15813
15884
  const scan = cacheScans.get(target);
15814
15885
  return Boolean(scan?.complete && !scan.hasSkills && scan.entries <= maxAliasProofEntries);
@@ -15820,7 +15891,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
15820
15891
  assertSafePath(path);
15821
15892
  if (!existsSync11(path))
15822
15893
  return scan;
15823
- const stat2 = lstatSync18(path);
15894
+ const stat2 = lstatSync19(path);
15824
15895
  if (stat2.isFile())
15825
15896
  return scan;
15826
15897
  if (!stat2.isDirectory())
@@ -15866,7 +15937,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
15866
15937
  if (isVendor && !options.includeVendor)
15867
15938
  continue;
15868
15939
  const child = join25(path, name);
15869
- if (isVendor && lstatSync18(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
15940
+ if (isVendor && lstatSync19(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
15870
15941
  const target = statSync8(child, { throwIfNoEntry: false });
15871
15942
  if (target?.isFile() || pluginCache && target?.isDirectory() && emptySiblingCacheAlias(child, path)) {
15872
15943
  scan.entries++;
@@ -16076,7 +16147,7 @@ function planAgentIntegration(options) {
16076
16147
  throw new Error("Refusing to overwrite an unrecognized Hermes supervisor");
16077
16148
  if (supervisorBefore !== supervisorAfter)
16078
16149
  changes.push({ path: supervisorPath, before: supervisorBefore, after: supervisorAfter });
16079
- const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha(supervisorAfter) };
16150
+ const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha2(supervisorAfter) };
16080
16151
  const after2 = configureHermesHooks(before, supervisor, previous);
16081
16152
  if (before !== after2)
16082
16153
  changes.push({ path, before, after: after2 });
@@ -16123,7 +16194,7 @@ function planAgentIntegration(options) {
16123
16194
  agents: [...new Set([...priorAgents, ...options.agents])].sort(),
16124
16195
  home: resolve15(home),
16125
16196
  includeVendor: true,
16126
- ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join25(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
16197
+ ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join25(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha2(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
16127
16198
  commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
16128
16199
  profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
16129
16200
  disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join25(home, ".codex", "skills", ".system"), aliases) + sep6)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
@@ -16138,10 +16209,10 @@ function planAgentIntegration(options) {
16138
16209
  }
16139
16210
  function atomicWrite2(path, content) {
16140
16211
  assertSafePath(path);
16141
- mkdirSync7(dirname15(path), { recursive: true, mode: 448 });
16212
+ mkdirSync7(dirname16(path), { recursive: true, mode: 448 });
16142
16213
  const temporary = `${path}.skills-${randomUUID3()}`;
16143
16214
  try {
16144
- writeFileSync5(temporary, content, { mode: 384, flag: "wx" });
16215
+ writeFileSync6(temporary, content, { mode: 384, flag: "wx" });
16145
16216
  renameSync4(temporary, path);
16146
16217
  } finally {
16147
16218
  if (existsSync11(temporary))
@@ -16175,8 +16246,8 @@ function applyAgentIntegration(plan) {
16175
16246
  chmodSync(backupRoot, 448);
16176
16247
  for (const [index, change] of plan.changes.entries())
16177
16248
  if (change.before !== null) {
16178
- const backup = join25(backupRoot, `${index}-${sha(change.path).slice(0, 12)}.backup`);
16179
- writeFileSync5(backup, change.before, { mode: 384, flag: "wx" });
16249
+ const backup = join25(backupRoot, `${index}-${sha2(change.path).slice(0, 12)}.backup`);
16250
+ writeFileSync6(backup, change.before, { mode: 384, flag: "wx" });
16180
16251
  backups.push(backup);
16181
16252
  }
16182
16253
  try {
@@ -16184,7 +16255,7 @@ function applyAgentIntegration(plan) {
16184
16255
  recheckRootAliases(aliases);
16185
16256
  if (currentText(change.path) !== change.before)
16186
16257
  throw new Error(`Configuration changed after planning: ${change.path}`);
16187
- for (let directory = dirname15(change.path);!existsSync11(directory); directory = dirname15(directory))
16258
+ for (let directory = dirname16(change.path);!existsSync11(directory); directory = dirname16(directory))
16188
16259
  createdDirectories.add(directory);
16189
16260
  const after = change.after;
16190
16261
  atomicWrite2(change.path, after);
@@ -16193,7 +16264,7 @@ function applyAgentIntegration(plan) {
16193
16264
  recheckRootAliases(aliases);
16194
16265
  for (const binding of plan.discoveryAfter ?? [])
16195
16266
  verifyAgentDiscovery(binding);
16196
- atomicWrite2(join25(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha(change.before), afterHash: sha(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
16267
+ atomicWrite2(join25(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha2(change.before), afterHash: sha2(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
16197
16268
  `);
16198
16269
  } catch (error) {
16199
16270
  for (const change of written.reverse()) {
@@ -16224,11 +16295,11 @@ function applyAgentIntegration(plan) {
16224
16295
  }
16225
16296
  function syncArchiveDirectory(path) {
16226
16297
  assertSafePath(path);
16227
- const descriptor = openSync11(path, constants10.O_RDONLY | constants10.O_DIRECTORY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
16298
+ const descriptor = openSync12(path, constants11.O_RDONLY | constants11.O_DIRECTORY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
16228
16299
  try {
16229
- fsyncSync3(descriptor);
16300
+ fsyncSync4(descriptor);
16230
16301
  } finally {
16231
- closeSync11(descriptor);
16302
+ closeSync12(descriptor);
16232
16303
  }
16233
16304
  }
16234
16305
  function writeArchiveJournal(path, value) {
@@ -16236,18 +16307,18 @@ function writeArchiveJournal(path, value) {
16236
16307
  const temporary = `${path}.skills-${randomUUID3()}`;
16237
16308
  let descriptor;
16238
16309
  try {
16239
- descriptor = openSync11(temporary, constants10.O_WRONLY | constants10.O_CREAT | constants10.O_EXCL | constants10.O_NOFOLLOW, 384);
16240
- writeFileSync5(descriptor, `${JSON.stringify(value)}
16310
+ descriptor = openSync12(temporary, constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
16311
+ writeFileSync6(descriptor, `${JSON.stringify(value)}
16241
16312
  `);
16242
- fsyncSync3(descriptor);
16243
- closeSync11(descriptor);
16313
+ fsyncSync4(descriptor);
16314
+ closeSync12(descriptor);
16244
16315
  descriptor = undefined;
16245
16316
  renameSync4(temporary, path);
16246
- syncArchiveDirectory(dirname15(path));
16317
+ syncArchiveDirectory(dirname16(path));
16247
16318
  } finally {
16248
16319
  if (descriptor !== undefined)
16249
- closeSync11(descriptor);
16250
- if (lstatSync18(temporary, { throwIfNoEntry: false }))
16320
+ closeSync12(descriptor);
16321
+ if (lstatSync19(temporary, { throwIfNoEntry: false }))
16251
16322
  unlinkSync4(temporary);
16252
16323
  }
16253
16324
  }
@@ -16272,8 +16343,8 @@ function archiveNativeSkills(inventory, options) {
16272
16343
  const operationId = randomUUID3(), archiveRoot = join25(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join25(archiveRoot, "receipt.json");
16273
16344
  const entries = selected.map((entry, index) => ({
16274
16345
  source: entry.vendor ? join25(entry.path, "SKILL.md") : entry.path,
16275
- archive: join25(archiveRoot, `${index}-${sha(entry.path).slice(0, 12)}`),
16276
- hash: entry.vendor ? sha(readNativeBytes(join25(entry.path, "SKILL.md"))) : entry.hash,
16346
+ archive: join25(archiveRoot, `${index}-${sha2(entry.path).slice(0, 12)}`),
16347
+ hash: entry.vendor ? sha2(readNativeBytes(join25(entry.path, "SKILL.md"))) : entry.hash,
16277
16348
  ...entry.vendor ? { discoveryOnly: true } : {},
16278
16349
  status: "planned"
16279
16350
  }));
@@ -16281,22 +16352,22 @@ function archiveNativeSkills(inventory, options) {
16281
16352
  const moved = [];
16282
16353
  const verifyArchive = (entry) => {
16283
16354
  assertSafePath(entry.archive);
16284
- const stat2 = lstatSync18(entry.archive);
16355
+ const stat2 = lstatSync19(entry.archive);
16285
16356
  if (entry.discoveryOnly ? !stat2.isFile() : !stat2.isDirectory())
16286
16357
  throw new Error("Archive type changed");
16287
- if ((entry.discoveryOnly ? sha(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
16358
+ if ((entry.discoveryOnly ? sha2(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
16288
16359
  throw new Error("Archive bytes changed");
16289
16360
  };
16290
16361
  assertSafePath(archiveRoot);
16291
16362
  const created = [];
16292
- for (let path = archiveRoot;!existsSync11(path); path = dirname15(path))
16363
+ for (let path = archiveRoot;!existsSync11(path); path = dirname16(path))
16293
16364
  created.push(path);
16294
16365
  mkdirSync7(archiveRoot, { recursive: true, mode: 448 });
16295
16366
  try {
16296
16367
  for (const directory of created)
16297
16368
  syncArchiveDirectory(directory);
16298
16369
  if (created.length)
16299
- syncArchiveDirectory(dirname15(created.at(-1)));
16370
+ syncArchiveDirectory(dirname16(created.at(-1)));
16300
16371
  writeArchiveJournal(receiptPath, journal);
16301
16372
  for (const [index, entry] of selected.entries()) {
16302
16373
  recheckRootAliases(aliases);
@@ -16308,7 +16379,7 @@ function archiveNativeSkills(inventory, options) {
16308
16379
  writeArchiveJournal(receiptPath, journal);
16309
16380
  renameSync4(move.source, move.archive);
16310
16381
  moved.push(move);
16311
- syncArchiveDirectory(dirname15(move.source));
16382
+ syncArchiveDirectory(dirname16(move.source));
16312
16383
  syncArchiveDirectory(archiveRoot);
16313
16384
  verifyArchive(move);
16314
16385
  move.status = "archived";
@@ -16329,7 +16400,7 @@ function archiveNativeSkills(inventory, options) {
16329
16400
  recheckRootAliases(aliases);
16330
16401
  assertSafePath(entry.source);
16331
16402
  assertSafePath(entry.archive);
16332
- if (lstatSync18(entry.source, { throwIfNoEntry: false })) {
16403
+ if (lstatSync19(entry.source, { throwIfNoEntry: false })) {
16333
16404
  entry.status = "recovery-required";
16334
16405
  entry.conflict = "source-occupied";
16335
16406
  continue;
@@ -16343,10 +16414,10 @@ function archiveNativeSkills(inventory, options) {
16343
16414
  }
16344
16415
  if (entry.discoveryOnly) {
16345
16416
  linkSync2(entry.archive, entry.source);
16346
- syncArchiveDirectory(dirname15(entry.source));
16417
+ syncArchiveDirectory(dirname16(entry.source));
16347
16418
  unlinkSync4(entry.archive);
16348
16419
  } else {
16349
- if (lstatSync18(entry.source, { throwIfNoEntry: false })) {
16420
+ if (lstatSync19(entry.source, { throwIfNoEntry: false })) {
16350
16421
  entry.status = "recovery-required";
16351
16422
  entry.conflict = "source-occupied";
16352
16423
  continue;
@@ -16354,7 +16425,7 @@ function archiveNativeSkills(inventory, options) {
16354
16425
  renameSync4(entry.archive, entry.source);
16355
16426
  }
16356
16427
  entry.status = "restored";
16357
- syncArchiveDirectory(dirname15(entry.source));
16428
+ syncArchiveDirectory(dirname16(entry.source));
16358
16429
  syncArchiveDirectory(archiveRoot);
16359
16430
  } catch {
16360
16431
  entry.status = "recovery-required";
@@ -16393,7 +16464,7 @@ function isSkillsOwnershipMarker(marker) {
16393
16464
  function hasSkillsOwnershipMarker(dir) {
16394
16465
  const path = join26(dir, SYNC_MARKER_FILE);
16395
16466
  try {
16396
- if (!lstatSync19(path).isFile())
16467
+ if (!lstatSync20(path).isFile())
16397
16468
  return false;
16398
16469
  const marker = JSON.parse(readFileSync15(path, "utf8"));
16399
16470
  return isSkillsOwnershipMarker(marker);
@@ -16619,7 +16690,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
16619
16690
  const action = dirExists ? "update" : "create";
16620
16691
  if (options.dryRun)
16621
16692
  return { action, path: skillMdPath };
16622
- const parentDir = dirname16(dir);
16693
+ const parentDir = dirname17(dir);
16623
16694
  mkdirSync8(parentDir, { recursive: true });
16624
16695
  const transactionDir = mkdtempSync2(join26(parentDir, `.hasna-skills-write-${basename9(dir)}-`));
16625
16696
  const candidateDir = join26(transactionDir, "candidate");
@@ -16641,10 +16712,10 @@ function writeManagedSkillDir(dir, skillMd, options) {
16641
16712
  } else {
16642
16713
  mkdirSync8(candidateDir, { recursive: true });
16643
16714
  }
16644
- writeFileSync6(candidateSkillMdPath, skillMd.endsWith(`
16715
+ writeFileSync7(candidateSkillMdPath, skillMd.endsWith(`
16645
16716
  `) ? skillMd : `${skillMd}
16646
16717
  `);
16647
- writeFileSync6(candidateMarkerPath, `${JSON.stringify(marker, null, 2)}
16718
+ writeFileSync7(candidateMarkerPath, `${JSON.stringify(marker, null, 2)}
16648
16719
  `);
16649
16720
  if (dirExists) {
16650
16721
  originalMoved = true;
@@ -16709,7 +16780,7 @@ function normalizeRequested(names) {
16709
16780
  }
16710
16781
 
16711
16782
  // src/lib/project-state.ts
16712
- import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as writeFileSync7 } from "fs";
16783
+ import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as writeFileSync8 } from "fs";
16713
16784
  import { join as join27 } from "path";
16714
16785
  var VALID_PIN_SOURCES = [
16715
16786
  "official",
@@ -16758,7 +16829,7 @@ function saveProjectConfig(config, targetDir = process.cwd()) {
16758
16829
  const dir = getProjectStateDir(targetDir);
16759
16830
  mkdirSync9(dir, { recursive: true });
16760
16831
  const normalized = normalizeProjectConfig({ ...config, updatedAt: new Date().toISOString() });
16761
- writeFileSync7(getProjectConfigPath(targetDir), JSON.stringify(normalized, null, 2) + `
16832
+ writeFileSync8(getProjectConfigPath(targetDir), JSON.stringify(normalized, null, 2) + `
16762
16833
  `);
16763
16834
  }
16764
16835
  function pinProjectSkill(name, details = {}, targetDir = process.cwd()) {
@@ -17110,8 +17181,8 @@ function loadProjectConfigCompat(targetDir) {
17110
17181
  return loadProjectConfig(targetDir);
17111
17182
  }
17112
17183
  // src/lib/run-state.ts
17113
- import { createHash as createHash15, randomBytes } from "crypto";
17114
- import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync18, readdirSync as readdirSync12, statSync as statSync10, writeFileSync as writeFileSync8 } from "fs";
17184
+ import { createHash as createHash17, randomBytes } from "crypto";
17185
+ import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync18, readdirSync as readdirSync12, statSync as statSync10, writeFileSync as writeFileSync9 } from "fs";
17115
17186
  import { extname, join as join29, relative as relative6 } from "path";
17116
17187
  function createSkillRun(params, targetDir = process.cwd()) {
17117
17188
  const now = new Date;
@@ -17176,15 +17247,15 @@ function updateSkillRun(context, patch) {
17176
17247
  return context.record;
17177
17248
  }
17178
17249
  function writeRunLogs(context, stdout = "", stderr = "") {
17179
- writeFileSync8(join29(context.logsDir, "stdout.log"), stdout);
17180
- writeFileSync8(join29(context.logsDir, "stderr.log"), stderr);
17250
+ writeFileSync9(join29(context.logsDir, "stdout.log"), stdout);
17251
+ writeFileSync9(join29(context.logsDir, "stderr.log"), stderr);
17181
17252
  }
17182
17253
  function appendRunEvent(context, event, data = {}) {
17183
17254
  const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
17184
17255
  `;
17185
17256
  const path = join29(context.runDir, "events.ndjson");
17186
17257
  const previous = existsSync15(path) ? readFileSync18(path, "utf-8") : "";
17187
- writeFileSync8(path, previous + line);
17258
+ writeFileSync9(path, previous + line);
17188
17259
  }
17189
17260
  function listSkillRuns(targetDir = process.cwd(), limit = 50) {
17190
17261
  const runsRoot = join29(getProjectStateDir(targetDir), "runs");
@@ -17220,11 +17291,11 @@ function getRunExportDir(runId, skill, targetDir = process.cwd()) {
17220
17291
  return join29(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
17221
17292
  }
17222
17293
  function writeRunRecord(context) {
17223
- writeFileSync8(join29(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
17294
+ writeFileSync9(join29(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
17224
17295
  `);
17225
17296
  }
17226
17297
  function writeArtifactsManifest(context, artifacts) {
17227
- writeFileSync8(join29(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
17298
+ writeFileSync9(join29(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
17228
17299
  `);
17229
17300
  }
17230
17301
  function collectRunArtifacts(context) {
@@ -17237,7 +17308,7 @@ function collectRunArtifacts(context) {
17237
17308
  artifacts.push({
17238
17309
  path: toProjectRelative(context.targetDir, path),
17239
17310
  mime: mimeForPath(path),
17240
- sha256: createHash15("sha256").update(bytes).digest("hex"),
17311
+ sha256: createHash17("sha256").update(bytes).digest("hex"),
17241
17312
  sizeBytes: stat2.size
17242
17313
  });
17243
17314
  }
@@ -36656,7 +36727,7 @@ function clone2(value) {
36656
36727
  return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
36657
36728
  }
36658
36729
  // src/lib/canonical-json.ts
36659
- import { createHash as createHash16 } from "crypto";
36730
+ import { createHash as createHash18 } from "crypto";
36660
36731
  function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
36661
36732
  return canonicalJsonAtDepth(value, maximumBytes, 64);
36662
36733
  }
@@ -36700,7 +36771,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
36700
36771
  return visit3(value, 0);
36701
36772
  }
36702
36773
  function canonicalJsonSha256(value, maximumBytes) {
36703
- return createHash16("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
36774
+ return createHash18("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
36704
36775
  }
36705
36776
 
36706
36777
  // src/lib/remote-recurring-contract.ts
@@ -36843,8 +36914,8 @@ var inputs = {
36843
36914
  };
36844
36915
  function recurringInput(action, raw) {
36845
36916
  try {
36846
- const snapshot = JSON.parse(canonicalJson2(raw, action === "preview" ? 1048576 : 4096));
36847
- return inputs[action].parse(snapshot);
36917
+ const snapshot2 = JSON.parse(canonicalJson2(raw, action === "preview" ? 1048576 : 4096));
36918
+ return inputs[action].parse(snapshot2);
36848
36919
  } catch {
36849
36920
  throw new RecurringInputError;
36850
36921
  }
@@ -38750,7 +38821,7 @@ async function createRemoteSkillsClient(env = process.env) {
38750
38821
  return connection ? new RemoteSkillsClient(connection.apiKey, connection.apiOrigin) : null;
38751
38822
  }
38752
38823
  // src/lib/scheduler.ts
38753
- import { existsSync as existsSync16, readFileSync as readFileSync19, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
38824
+ import { existsSync as existsSync16, readFileSync as readFileSync19, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11 } from "fs";
38754
38825
  import { join as join30 } from "path";
38755
38826
  function getSchedulesPath(targetDir = process.cwd()) {
38756
38827
  return join30(targetDir, ".skills", "schedules.json");
@@ -38769,7 +38840,7 @@ function saveSchedules(data, targetDir = process.cwd()) {
38769
38840
  const dir = join30(targetDir, ".skills");
38770
38841
  if (!existsSync16(dir))
38771
38842
  mkdirSync11(dir, { recursive: true });
38772
- writeFileSync9(path, JSON.stringify(data, null, 2));
38843
+ writeFileSync10(path, JSON.stringify(data, null, 2));
38773
38844
  }
38774
38845
  function validateCronField(expr, min, max, label) {
38775
38846
  for (const part of expr.split(",")) {
@@ -38954,7 +39025,7 @@ function recordScheduleRun(id, status, targetDir) {
38954
39025
  saveSchedules(data, targetDir);
38955
39026
  }
38956
39027
  // src/lib/revision.ts
38957
- import { createHash as createHash17 } from "crypto";
39028
+ import { createHash as createHash19 } from "crypto";
38958
39029
  var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
38959
39030
  function revisionIdOf(content) {
38960
39031
  const canonicalContent = {
@@ -38976,14 +39047,14 @@ function revisionIdOf(content) {
38976
39047
  canonicalContent.replacementSlug = content.replacementSlug ?? null;
38977
39048
  }
38978
39049
  const canonical4 = JSON.stringify(canonicalContent);
38979
- return createHash17("sha256").update(canonical4).digest("hex");
39050
+ return createHash19("sha256").update(canonical4).digest("hex");
38980
39051
  }
38981
39052
  function revisionIdOfRecord(record7) {
38982
39053
  return revisionIdOf(record7);
38983
39054
  }
38984
39055
  // src/lib/pull.ts
38985
- import { existsSync as existsSync17, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync20, renameSync as renameSync6, rmSync as rmSync5, writeFileSync as writeFileSync10 } from "fs";
38986
- import { dirname as dirname17, join as join31 } from "path";
39056
+ import { existsSync as existsSync17, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync20, renameSync as renameSync6, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "fs";
39057
+ import { dirname as dirname18, join as join31 } from "path";
38987
39058
 
38988
39059
  // src/lib/skill-bundles.ts
38989
39060
  import { createHmac, timingSafeEqual } from "crypto";
@@ -39325,8 +39396,8 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
39325
39396
  try {
39326
39397
  for (const entry of entries) {
39327
39398
  const destination = join31(staging, entry.path);
39328
- mkdirSync12(dirname17(destination), { recursive: true });
39329
- writeFileSync10(destination, entry.bytes, { mode: entry.mode });
39399
+ mkdirSync12(dirname18(destination), { recursive: true });
39400
+ writeFileSync11(destination, entry.bytes, { mode: entry.mode });
39330
39401
  }
39331
39402
  writePullMarker(staging, {
39332
39403
  skill: name,
@@ -39367,7 +39438,7 @@ function writePullMarker(dir, record7) {
39367
39438
  ...record7.revisionId ? { revisionId: record7.revisionId } : {},
39368
39439
  syncedAt: new Date().toISOString()
39369
39440
  };
39370
- writeFileSync10(join31(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
39441
+ writeFileSync11(join31(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
39371
39442
  `);
39372
39443
  }
39373
39444
  async function safeMeta(client2, slug2) {
@@ -39517,7 +39588,7 @@ async function requestInvitationEmail(origin, action, input2) {
39517
39588
  }
39518
39589
 
39519
39590
  // src/lib/remote-private-publications.ts
39520
- import { createHash as createHash18 } from "crypto";
39591
+ import { createHash as createHash20 } from "crypto";
39521
39592
  var PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
39522
39593
  var failures2 = {
39523
39594
  INVALID_REQUEST: [400, "The publication request is invalid."],
@@ -39564,7 +39635,7 @@ var hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v);
39564
39635
  var record8 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
39565
39636
  var exact = (v, keys) => record8(v) && Object.keys(v).sort().join(",") === keys.sort().join(",");
39566
39637
  var date5 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v));
39567
- var publicationSha256 = (bytes) => createHash18("sha256").update(bytes).digest("hex");
39638
+ var publicationSha256 = (bytes) => createHash20("sha256").update(bytes).digest("hex");
39568
39639
  function checkedPublicationDeclaration(value) {
39569
39640
  if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
39570
39641
  return bad();
@@ -40048,7 +40119,7 @@ class RemoteSkillsAuthClient {
40048
40119
 
40049
40120
  // src/lib/recurring-recovery.ts
40050
40121
  var uuid12 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
40051
- var sha2 = exports_external.string().regex(/^[a-f0-9]{64}$/);
40122
+ var sha3 = exports_external.string().regex(/^[a-f0-9]{64}$/);
40052
40123
  var common = exports_external.object({
40053
40124
  contractVersion: exports_external.literal(1),
40054
40125
  apiOrigin: exports_external.string().min(1).max(4096),
@@ -40061,7 +40132,7 @@ var intentSchema = exports_external.discriminatedUnion("operation", [
40061
40132
  common.extend({
40062
40133
  operation: exports_external.literal("activate"),
40063
40134
  draftId: uuid12,
40064
- termsSha256: sha2,
40135
+ termsSha256: sha3,
40065
40136
  approvalDeadline: exports_external.string().datetime(),
40066
40137
  approval: recurringActivationSchema
40067
40138
  }).strict(),
@@ -40069,7 +40140,7 @@ var intentSchema = exports_external.discriminatedUnion("operation", [
40069
40140
  ]);
40070
40141
  var stateSchema = exports_external.object({
40071
40142
  contractVersion: exports_external.literal(1),
40072
- intentSha256: sha2,
40143
+ intentSha256: sha3,
40073
40144
  phase: exports_external.enum(["prepared", "pending", "observed"]),
40074
40145
  consentId: uuid12.nullable()
40075
40146
  }).strict();
@@ -40228,8 +40299,8 @@ function findSkillsParityForMcpTool(tool) {
40228
40299
  return SKILLS_CLI_MCP_PARITY.find((entry) => entry.mcpTools.includes(tool));
40229
40300
  }
40230
40301
  // src/lib/registry-sync.ts
40231
- import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync11 } from "fs";
40232
- import { dirname as dirname18, relative as relative7 } from "path";
40302
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync12 } from "fs";
40303
+ import { dirname as dirname19, relative as relative7 } from "path";
40233
40304
  function createRegistrySyncArtifact(options = {}) {
40234
40305
  const profile = options.profile ?? "all";
40235
40306
  const includeDocs = options.includeDocs ?? true;
@@ -40286,8 +40357,8 @@ function createRegistrySyncArtifact(options = {}) {
40286
40357
  };
40287
40358
  }
40288
40359
  function writeRegistrySyncArtifact(path, artifact) {
40289
- mkdirSync13(dirname18(path), { recursive: true });
40290
- writeFileSync11(path, `${JSON.stringify(artifact, null, 2)}
40360
+ mkdirSync13(dirname19(path), { recursive: true });
40361
+ writeFileSync12(path, `${JSON.stringify(artifact, null, 2)}
40291
40362
  `);
40292
40363
  }
40293
40364
  function buildDocs(name) {
@@ -41371,14 +41442,14 @@ function clone3(value) {
41371
41442
  }
41372
41443
  // src/lib/feedback.ts
41373
41444
  import { appendFileSync, existsSync as existsSync18, mkdirSync as mkdirSync14 } from "fs";
41374
- import { dirname as dirname19, join as join32 } from "path";
41445
+ import { dirname as dirname20, join as join32 } from "path";
41375
41446
  import { Database } from "bun:sqlite";
41376
41447
  function getFeedbackDbPath() {
41377
41448
  return join32(getDataDir(), "skills.db");
41378
41449
  }
41379
41450
  function getFeedbackDb() {
41380
41451
  const dbPath = getFeedbackDbPath();
41381
- const dir = dirname19(dbPath);
41452
+ const dir = dirname20(dbPath);
41382
41453
  if (!existsSync18(dir))
41383
41454
  mkdirSync14(dir, { recursive: true });
41384
41455
  const db = new Database(dbPath);
@@ -41407,7 +41478,7 @@ function saveFeedback(input2) {
41407
41478
  const category = input2.category ?? "general";
41408
41479
  if (isApiMode()) {
41409
41480
  const path = join32(getDataDir(), "feedback.jsonl");
41410
- const dir = dirname19(path);
41481
+ const dir = dirname20(path);
41411
41482
  if (!existsSync18(dir))
41412
41483
  mkdirSync14(dir, { recursive: true });
41413
41484
  appendFileSync(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
@@ -41430,16 +41501,16 @@ function isApiMode(env = process.env) {
41430
41501
  }
41431
41502
  }
41432
41503
  // src/lib/native-storage.ts
41433
- import { createHash as createHash19, createHmac as createHmac2 } from "crypto";
41504
+ import { createHash as createHash21, createHmac as createHmac2 } from "crypto";
41434
41505
  import {
41435
41506
  existsSync as existsSync19,
41436
41507
  mkdirSync as mkdirSync15,
41437
41508
  readFileSync as readFileSync21,
41438
41509
  readdirSync as readdirSync13,
41439
41510
  statSync as statSync11,
41440
- writeFileSync as writeFileSync12
41511
+ writeFileSync as writeFileSync13
41441
41512
  } from "fs";
41442
- import { dirname as dirname20, join as join33, normalize as normalize3, relative as relative8, sep as sep7 } from "path";
41513
+ import { dirname as dirname21, join as join33, normalize as normalize3, relative as relative8, sep as sep7 } from "path";
41443
41514
  var SKILLS_STORAGE_TABLES = [
41444
41515
  "skills_sync_records",
41445
41516
  "skills_sync_cursors"
@@ -41606,7 +41677,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
41606
41677
  files.push({
41607
41678
  path: relativePath,
41608
41679
  sizeBytes: bytes.byteLength,
41609
- sha256: createHash19("sha256").update(bytes).digest("hex"),
41680
+ sha256: createHash21("sha256").update(bytes).digest("hex"),
41610
41681
  ...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
41611
41682
  });
41612
41683
  }
@@ -41617,10 +41688,10 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
41617
41688
  files: files.sort((a, b) => a.path.localeCompare(b.path))
41618
41689
  };
41619
41690
  }
41620
- function importSkillsLocalSnapshot(snapshot, targetDir = process.cwd(), options = {}) {
41691
+ function importSkillsLocalSnapshot(snapshot2, targetDir = process.cwd(), options = {}) {
41621
41692
  let written = 0;
41622
41693
  let skipped = 0;
41623
- for (const file2 of snapshot.files) {
41694
+ for (const file2 of snapshot2.files) {
41624
41695
  if (!file2.contentBase64) {
41625
41696
  skipped += 1;
41626
41697
  continue;
@@ -41631,12 +41702,12 @@ function importSkillsLocalSnapshot(snapshot, targetDir = process.cwd(), options
41631
41702
  continue;
41632
41703
  }
41633
41704
  const bytes = Buffer.from(file2.contentBase64, "base64");
41634
- const hash4 = createHash19("sha256").update(bytes).digest("hex");
41705
+ const hash4 = createHash21("sha256").update(bytes).digest("hex");
41635
41706
  if (hash4 !== file2.sha256) {
41636
41707
  throw new Error(`Snapshot file checksum mismatch: ${file2.path}`);
41637
41708
  }
41638
- mkdirSync15(dirname20(absolutePath3), { recursive: true });
41639
- writeFileSync12(absolutePath3, bytes);
41709
+ mkdirSync15(dirname21(absolutePath3), { recursive: true });
41710
+ writeFileSync13(absolutePath3, bytes);
41640
41711
  written += 1;
41641
41712
  }
41642
41713
  return { written, skipped };
@@ -41733,14 +41804,14 @@ class SkillsPostgresSyncStore {
41733
41804
  function createSkillsPostgresSyncStore(client2) {
41734
41805
  return new SkillsPostgresSyncStore(client2);
41735
41806
  }
41736
- function createSkillsSnapshotSyncRecord(snapshot, options = {}) {
41807
+ function createSkillsSnapshotSyncRecord(snapshot2, options = {}) {
41737
41808
  return {
41738
41809
  scope: options.scope ?? "default",
41739
41810
  kind: "local-snapshot",
41740
41811
  id: options.id ?? "project-state",
41741
- updatedAt: snapshot.exportedAt,
41812
+ updatedAt: snapshot2.exportedAt,
41742
41813
  source: options.source ?? "skills",
41743
- payload: snapshot
41814
+ payload: snapshot2
41744
41815
  };
41745
41816
  }
41746
41817
 
@@ -41824,18 +41895,18 @@ class SkillsS3ObjectStore {
41824
41895
  function createSkillsS3ObjectStore(options) {
41825
41896
  return new SkillsS3ObjectStore(options);
41826
41897
  }
41827
- function planSkillsS3SnapshotUpload(snapshot, options = {}) {
41898
+ function planSkillsS3SnapshotUpload(snapshot2, options = {}) {
41828
41899
  const prefix = normalizeS3Prefix(options.prefix);
41829
- return snapshot.files.map((file2) => ({
41900
+ return snapshot2.files.map((file2) => ({
41830
41901
  path: file2.path,
41831
41902
  key: [prefix, file2.path.replace(/^\.?\//, "")].filter(Boolean).join("/"),
41832
41903
  sizeBytes: file2.sizeBytes,
41833
41904
  sha256: file2.sha256
41834
41905
  }));
41835
41906
  }
41836
- async function uploadSkillsSnapshotFilesToS3(snapshot, store) {
41907
+ async function uploadSkillsSnapshotFilesToS3(snapshot2, store) {
41837
41908
  const uploaded = [];
41838
- for (const file2 of snapshot.files) {
41909
+ for (const file2 of snapshot2.files) {
41839
41910
  if (!file2.contentBase64)
41840
41911
  continue;
41841
41912
  uploaded.push(await store.putObject({
@@ -41963,7 +42034,7 @@ function toIsoString(value) {
41963
42034
  return Number.isNaN(date6.getTime()) ? value : date6.toISOString();
41964
42035
  }
41965
42036
  function sha256Hex2(value) {
41966
- return createHash19("sha256").update(value).digest("hex");
42037
+ return createHash21("sha256").update(value).digest("hex");
41967
42038
  }
41968
42039
  function normalizeHeaders(headers) {
41969
42040
  const result = {};
@@ -42015,15 +42086,15 @@ function toArrayBuffer(bytes) {
42015
42086
  return buffer;
42016
42087
  }
42017
42088
  // src/lib/station-snapshot.ts
42018
- import { createHash as createHash20 } from "crypto";
42089
+ import { createHash as createHash22 } from "crypto";
42019
42090
  import {
42020
42091
  copyFileSync,
42021
42092
  mkdirSync as mkdirSync16,
42022
42093
  readFileSync as readFileSync23,
42023
42094
  statSync as statSync13,
42024
- writeFileSync as writeFileSync13
42095
+ writeFileSync as writeFileSync14
42025
42096
  } from "fs";
42026
- import { dirname as dirname21, isAbsolute as isAbsolute17, relative as relative9, resolve as resolve16, sep as sep9 } from "path";
42097
+ import { dirname as dirname22, isAbsolute as isAbsolute17, relative as relative9, resolve as resolve16, sep as sep9 } from "path";
42027
42098
 
42028
42099
  // src/lib/portable-snapshot-filter.ts
42029
42100
  import { readdirSync as readdirSync14, statSync as statSync12 } from "fs";
@@ -42190,7 +42261,7 @@ function validateStationId(stationId) {
42190
42261
  }
42191
42262
  }
42192
42263
  function sha256File(filePath) {
42193
- return createHash20("sha256").update(readFileSync23(filePath)).digest("hex");
42264
+ return createHash22("sha256").update(readFileSync23(filePath)).digest("hex");
42194
42265
  }
42195
42266
  function scanHome(definition, homesRoot) {
42196
42267
  const homePath = homePathFor(definition, homesRoot);
@@ -42311,11 +42382,11 @@ function writeStationSnapshot(options) {
42311
42382
  let written = 0;
42312
42383
  for (const plan of untouched) {
42313
42384
  const destination = resolve16(repoRoot, plan.destination);
42314
- mkdirSync16(dirname21(destination), { recursive: true });
42385
+ mkdirSync16(dirname22(destination), { recursive: true });
42315
42386
  copyFileSync(plan.source.fullPath, destination);
42316
42387
  written += 1;
42317
42388
  }
42318
- const unchanged2 = plans.length - untouched.length;
42389
+ const unchanged3 = plans.length - untouched.length;
42319
42390
  const manifest = {
42320
42391
  schema: STATION_SYNC_MANIFEST_SCHEMA,
42321
42392
  stationId: options.stationId,
@@ -42323,34 +42394,34 @@ function writeStationSnapshot(options) {
42323
42394
  producer: STATION_SNAPSHOT_PRODUCER,
42324
42395
  stats: {
42325
42396
  written,
42326
- unchanged: unchanged2,
42397
+ unchanged: unchanged3,
42327
42398
  files: plans.length,
42328
42399
  bytes: totalBytes
42329
42400
  },
42330
42401
  files: manifestFiles
42331
42402
  };
42332
42403
  const manifestPath = resolve16(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
42333
- mkdirSync16(dirname21(manifestPath), { recursive: true });
42334
- writeFileSync13(manifestPath, `${JSON.stringify(manifest, null, 2)}
42404
+ mkdirSync16(dirname22(manifestPath), { recursive: true });
42405
+ writeFileSync14(manifestPath, `${JSON.stringify(manifest, null, 2)}
42335
42406
  `);
42336
42407
  return {
42337
42408
  ...base,
42338
42409
  mode: "populate",
42339
- stats: { files: plans.length, bytes: totalBytes, written, unchanged: unchanged2 },
42410
+ stats: { files: plans.length, bytes: totalBytes, written, unchanged: unchanged3 },
42340
42411
  manifestPath
42341
42412
  };
42342
42413
  }
42343
42414
  // src/lib/station-hydrate.ts
42344
- import { createHash as createHash21 } from "crypto";
42415
+ import { createHash as createHash23 } from "crypto";
42345
42416
  import {
42346
42417
  copyFileSync as copyFileSync2,
42347
42418
  mkdirSync as mkdirSync17,
42348
42419
  readdirSync as readdirSync15,
42349
42420
  readFileSync as readFileSync25,
42350
42421
  statSync as statSync14,
42351
- writeFileSync as writeFileSync14
42422
+ writeFileSync as writeFileSync15
42352
42423
  } from "fs";
42353
- import { dirname as dirname22, join as join35, resolve as resolve17, sep as sep10 } from "path";
42424
+ import { dirname as dirname23, join as join35, resolve as resolve17, sep as sep10 } from "path";
42354
42425
  var STATION_HYDRATION_MANIFEST_SCHEMA = "hasna.fleet-resources.skills-hydration-manifest/v1";
42355
42426
  var STATION_HYDRATION_PRODUCER = { name: "@hasna/skills", version: package_default.version };
42356
42427
  var MANIFEST_HASH_KEY_SEP = String.fromCharCode(0);
@@ -42547,7 +42618,7 @@ function skillSha256(skill) {
42547
42618
  return sha256File(skill.files[0].winner.fullPath);
42548
42619
  }
42549
42620
  const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
42550
- return createHash21("sha256").update(joined.sort().join(`
42621
+ return createHash23("sha256").update(joined.sort().join(`
42551
42622
  `)).digest("hex");
42552
42623
  }
42553
42624
  function writeStationHydration(options) {
@@ -42606,11 +42677,11 @@ function writeStationHydration(options) {
42606
42677
  }
42607
42678
  let written = 0;
42608
42679
  for (const entry of toWrite) {
42609
- mkdirSync17(dirname22(entry.destination), { recursive: true });
42680
+ mkdirSync17(dirname23(entry.destination), { recursive: true });
42610
42681
  copyFileSync2(entry.fullPath, entry.destination);
42611
42682
  written += 1;
42612
42683
  }
42613
- const unchanged2 = plan.totalFiles - written;
42684
+ const unchanged3 = plan.totalFiles - written;
42614
42685
  const hydration = {
42615
42686
  schema: STATION_HYDRATION_MANIFEST_SCHEMA,
42616
42687
  stationId: options.stationId,
@@ -42621,26 +42692,26 @@ function writeStationHydration(options) {
42621
42692
  stats: {
42622
42693
  idents: plan.winners.length,
42623
42694
  written,
42624
- unchanged: unchanged2,
42695
+ unchanged: unchanged3,
42625
42696
  files: plan.totalFiles,
42626
42697
  bytes: plan.totalBytes
42627
42698
  },
42628
42699
  skills: resultSkills
42629
42700
  };
42630
- const hydrationManifestPath = join35(dirname22(cacheRoot), `hydration-${options.stationId}.json`);
42631
- mkdirSync17(dirname22(hydrationManifestPath), { recursive: true });
42632
- writeFileSync14(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
42701
+ const hydrationManifestPath = join35(dirname23(cacheRoot), `hydration-${options.stationId}.json`);
42702
+ mkdirSync17(dirname23(hydrationManifestPath), { recursive: true });
42703
+ writeFileSync15(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
42633
42704
  `);
42634
42705
  return {
42635
42706
  ...base,
42636
42707
  mode: "apply",
42637
- stats: { ...base.stats, written, unchanged: unchanged2 },
42708
+ stats: { ...base.stats, written, unchanged: unchanged3 },
42638
42709
  manifestPath: hydrationManifestPath
42639
42710
  };
42640
42711
  }
42641
42712
  // src/lib/private-publication-recovery.ts
42642
- import { constants as constants11, closeSync as closeSync12, fsyncSync as fsyncSync4, fstatSync as fstatSync12, lstatSync as lstatSync20, mkdirSync as mkdirSync18, openSync as openSync12, readSync as readSync10, realpathSync as realpathSync6, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync15 } from "fs";
42643
- import { dirname as dirname23, isAbsolute as isAbsolute18, join as join36, resolve as resolve18 } from "path";
42713
+ import { constants as constants12, closeSync as closeSync13, fsyncSync as fsyncSync5, fstatSync as fstatSync13, lstatSync as lstatSync21, mkdirSync as mkdirSync18, openSync as openSync13, readSync as readSync11, realpathSync as realpathSync6, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync16 } from "fs";
42714
+ import { dirname as dirname24, isAbsolute as isAbsolute18, join as join36, resolve as resolve18 } from "path";
42644
42715
  import { randomUUID as randomUUID4 } from "crypto";
42645
42716
  var fail2 = () => {
42646
42717
  throw new PrivatePublicationError("PUBLICATION_RECOVERY_INVALID", "The recovery directory is invalid or changed. Preserve it and inspect the existing intent; do not start a replacement automatically.");
@@ -42648,14 +42719,14 @@ var fail2 = () => {
42648
42719
  function safeDirectory(directory2) {
42649
42720
  if (!isAbsolute18(directory2) || directory2 !== resolve18(directory2) || realpathSync6(directory2) !== directory2)
42650
42721
  return fail2();
42651
- for (let path = directory2;; path = dirname23(path)) {
42652
- const stat2 = lstatSync20(path);
42722
+ for (let path = directory2;; path = dirname24(path)) {
42723
+ const stat2 = lstatSync21(path);
42653
42724
  if (!stat2.isDirectory() || stat2.isSymbolicLink())
42654
42725
  return fail2();
42655
- if (path === dirname23(path))
42726
+ if (path === dirname24(path))
42656
42727
  break;
42657
42728
  }
42658
- const own2 = lstatSync20(directory2);
42729
+ const own2 = lstatSync21(directory2);
42659
42730
  if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
42660
42731
  return fail2();
42661
42732
  return { dev: own2.dev, ino: own2.ino };
@@ -42667,35 +42738,35 @@ function unchangedDirectory(directory2, identity3) {
42667
42738
  }
42668
42739
  function readOwned(directory2, name, max) {
42669
42740
  const identity3 = safeDirectory(directory2), file2 = join36(directory2, name);
42670
- const fd = openSync12(file2, constants11.O_RDONLY | constants11.O_NOFOLLOW);
42741
+ const fd = openSync13(file2, constants12.O_RDONLY | constants12.O_NOFOLLOW);
42671
42742
  try {
42672
- const stat2 = fstatSync12(fd);
42743
+ const stat2 = fstatSync13(fd);
42673
42744
  if (!stat2.isFile() || stat2.nlink !== 1 || stat2.size > max || stat2.size < 1 || (stat2.mode & 63) !== 0 || process.getuid && stat2.uid !== process.getuid())
42674
42745
  return fail2();
42675
42746
  const buffer = Buffer.alloc(Math.min(max, stat2.size) + 1);
42676
42747
  let length = 0;
42677
42748
  while (length < buffer.length) {
42678
- const count = readSync10(fd, buffer, length, buffer.length - length, length);
42749
+ const count = readSync11(fd, buffer, length, buffer.length - length, length);
42679
42750
  if (count === 0)
42680
42751
  break;
42681
42752
  length += count;
42682
42753
  }
42683
- const bytes = buffer.subarray(0, length), after = fstatSync12(fd);
42754
+ const bytes = buffer.subarray(0, length), after = fstatSync13(fd);
42684
42755
  unchangedDirectory(directory2, identity3);
42685
42756
  if (bytes.length !== stat2.size || stat2.size !== after.size || stat2.mtimeMs !== after.mtimeMs || stat2.ctimeMs !== after.ctimeMs)
42686
42757
  return fail2();
42687
42758
  return bytes;
42688
42759
  } finally {
42689
- closeSync12(fd);
42760
+ closeSync13(fd);
42690
42761
  }
42691
42762
  }
42692
42763
  function writeOwned(directory2, name, bytes) {
42693
- const fd = openSync12(join36(directory2, name), constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
42764
+ const fd = openSync13(join36(directory2, name), constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
42694
42765
  try {
42695
- writeFileSync15(fd, bytes);
42696
- fsyncSync4(fd);
42766
+ writeFileSync16(fd, bytes);
42767
+ fsyncSync5(fd);
42697
42768
  } finally {
42698
- closeSync12(fd);
42769
+ closeSync13(fd);
42699
42770
  }
42700
42771
  }
42701
42772
  function save(directory2, value) {
@@ -42704,11 +42775,11 @@ function save(directory2, value) {
42704
42775
  `);
42705
42776
  unchangedDirectory(directory2, identity3);
42706
42777
  renameSync7(join36(directory2, temporary), join36(directory2, "receipt.json"));
42707
- const fd = openSync12(directory2, constants11.O_RDONLY | constants11.O_NOFOLLOW);
42778
+ const fd = openSync13(directory2, constants12.O_RDONLY | constants12.O_NOFOLLOW);
42708
42779
  try {
42709
- fsyncSync4(fd);
42780
+ fsyncSync5(fd);
42710
42781
  } finally {
42711
- closeSync12(fd);
42782
+ closeSync13(fd);
42712
42783
  }
42713
42784
  }
42714
42785
  function bind(client2, receipt) {
@@ -42719,20 +42790,20 @@ async function locked(directory2, action) {
42719
42790
  const identity3 = safeDirectory(directory2), file2 = join36(directory2, "operation.lock");
42720
42791
  let fd;
42721
42792
  try {
42722
- fd = openSync12(file2, constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
42793
+ fd = openSync13(file2, constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
42723
42794
  } catch {
42724
42795
  throw new PrivatePublicationError("PUBLICATION_RECOVERY_BUSY", "Another operation holds this recovery directory. If it crashed, confirm that process has stopped before explicitly removing operation.lock and resuming.");
42725
42796
  }
42726
- const lock = fstatSync12(fd);
42797
+ const lock = fstatSync13(fd);
42727
42798
  try {
42728
- writeFileSync15(fd, JSON.stringify({ pid: process.pid }) + `
42799
+ writeFileSync16(fd, JSON.stringify({ pid: process.pid }) + `
42729
42800
  `);
42730
- fsyncSync4(fd);
42801
+ fsyncSync5(fd);
42731
42802
  return await action();
42732
42803
  } finally {
42733
- closeSync12(fd);
42804
+ closeSync13(fd);
42734
42805
  unchangedDirectory(directory2, identity3);
42735
- const now = lstatSync20(file2);
42806
+ const now = lstatSync21(file2);
42736
42807
  if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
42737
42808
  fail2();
42738
42809
  unlinkSync5(file2);
@@ -42784,15 +42855,15 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
42784
42855
  phase: "prepared",
42785
42856
  intent: null
42786
42857
  };
42787
- if (!isAbsolute18(recoveryDirectory) || resolve18(recoveryDirectory) !== recoveryDirectory || realpathSync6(dirname23(recoveryDirectory)) !== dirname23(recoveryDirectory))
42858
+ if (!isAbsolute18(recoveryDirectory) || resolve18(recoveryDirectory) !== recoveryDirectory || realpathSync6(dirname24(recoveryDirectory)) !== dirname24(recoveryDirectory))
42788
42859
  return fail2();
42789
42860
  mkdirSync18(recoveryDirectory, { mode: 448 });
42790
42861
  safeDirectory(recoveryDirectory);
42791
- const parent = openSync12(dirname23(recoveryDirectory), constants11.O_RDONLY | constants11.O_NOFOLLOW);
42862
+ const parent = openSync13(dirname24(recoveryDirectory), constants12.O_RDONLY | constants12.O_NOFOLLOW);
42792
42863
  try {
42793
- fsyncSync4(parent);
42864
+ fsyncSync5(parent);
42794
42865
  } finally {
42795
- closeSync12(parent);
42866
+ closeSync13(parent);
42796
42867
  }
42797
42868
  writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
42798
42869
  save(recoveryDirectory, receipt);
@@ -42875,7 +42946,7 @@ async function inspectLocked(client2, directory2, cancel) {
42875
42946
  return privatePublicationResult(directory2, receipt);
42876
42947
  }
42877
42948
  // src/lib/skill-context.ts
42878
- import { createHash as createHash22 } from "crypto";
42949
+ import { createHash as createHash24 } from "crypto";
42879
42950
  import { resolve as resolve19 } from "path";
42880
42951
  function words(value) {
42881
42952
  return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
@@ -42964,7 +43035,7 @@ ${content}`;
42964
43035
  `);
42965
43036
  const receipt = {
42966
43037
  schemaVersion: 1,
42967
- id: createHash22("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
43038
+ id: createHash24("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
42968
43039
  profileId: profile.profileId,
42969
43040
  profileRevision: profile.profileRevision,
42970
43041
  authority: profile.authority,
@@ -42980,9 +43051,9 @@ ${content}`;
42980
43051
  return { context: context2, selections, omitted, receipt };
42981
43052
  }
42982
43053
  // src/lib/session-reconciliation.ts
42983
- import { createHash as createHash23 } from "crypto";
43054
+ import { createHash as createHash25 } from "crypto";
42984
43055
  var SESSION_RECONCILIATION_PLAN_TTL_MS = 5 * 60 * 1000;
42985
- var digest3 = (value) => createHash23("sha256").update(JSON.stringify(value)).digest("hex");
43056
+ var digest3 = (value) => createHash25("sha256").update(JSON.stringify(value)).digest("hex");
42986
43057
  function exactTimestamp(value) {
42987
43058
  const parsed = value === undefined ? Number.NaN : Date.parse(value);
42988
43059
  if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
@@ -43000,12 +43071,12 @@ function assertPlanWindow(issuedAt, expiresAt, now) {
43000
43071
  }
43001
43072
  }
43002
43073
  function inspectSkillSession(sessionId, options = {}) {
43003
- const snapshot = readSkillSessionSnapshot(sessionId, options), { receipt } = snapshot;
43074
+ const snapshot2 = readSkillSessionSnapshot(sessionId, options), { receipt } = snapshot2;
43004
43075
  return {
43005
43076
  sessionId,
43006
- path: snapshot.path,
43007
- receiptSha256: snapshot.sha256,
43008
- generation: snapshot.generation,
43077
+ path: snapshot2.path,
43078
+ receiptSha256: snapshot2.sha256,
43079
+ generation: snapshot2.generation,
43009
43080
  verifiedAt: receipt.verifiedAt,
43010
43081
  authority: receipt.profile.authority,
43011
43082
  workspaceId: receipt.profile.workspaceId,
@@ -43030,8 +43101,8 @@ async function reconcileSkillSession(input2, options = {}) {
43030
43101
  const expiresAt = input2.apply ? input2.planExpiresAt : new Date(now + SESSION_RECONCILIATION_PLAN_TTL_MS).toISOString();
43031
43102
  if (input2.apply)
43032
43103
  assertPlanWindow(issuedAt, expiresAt, now);
43033
- const snapshot = readSkillSessionSnapshot(input2.sessionId, options), old = snapshot.receipt;
43034
- if (snapshot.sha256 !== input2.receiptSha256 || old.profile.profileId !== input2.fromProfile || old.profile.profileRevision !== input2.fromRevision) {
43104
+ const snapshot2 = readSkillSessionSnapshot(input2.sessionId, options), old = snapshot2.receipt;
43105
+ if (snapshot2.sha256 !== input2.receiptSha256 || old.profile.profileId !== input2.fromProfile || old.profile.profileRevision !== input2.fromRevision) {
43035
43106
  throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The current session receipt does not match the reviewed old bytes, profile and revision.");
43036
43107
  }
43037
43108
  const client2 = options.client ?? await createProfileClient();
@@ -43045,14 +43116,14 @@ async function reconcileSkillSession(input2, options = {}) {
43045
43116
  }
43046
43117
  const targetKeys = new Set(target.selections.map(selectionKey));
43047
43118
  const loaded = old.loaded.filter((key) => targetKeys.has(key));
43048
- const replacementGeneration = nextSkillSessionGeneration(snapshot.generation);
43119
+ const replacementGeneration = nextSkillSessionGeneration(snapshot2.generation);
43049
43120
  const plan = {
43050
43121
  schemaVersion: 1,
43051
43122
  issuedAt,
43052
43123
  expiresAt,
43053
43124
  sessionId: input2.sessionId,
43054
- sessionPath: snapshot.path,
43055
- before: { receiptSha256: snapshot.sha256, generation: snapshot.generation, profileId: old.profile.profileId, profileRevision: old.profile.profileRevision, selectionCount: old.profile.selections.length },
43125
+ sessionPath: snapshot2.path,
43126
+ before: { receiptSha256: snapshot2.sha256, generation: snapshot2.generation, profileId: old.profile.profileId, profileRevision: old.profile.profileRevision, selectionCount: old.profile.selections.length },
43056
43127
  target: { authority: target.authority, workspaceId: target.workspaceId, profileId: target.profileId, profileRevision: target.profileRevision, profileSha256: digest3(target), selectionCount: target.selections.length },
43057
43128
  replacementGeneration,
43058
43129
  retainedLoadedCount: loaded.length,
@@ -43063,7 +43134,7 @@ async function reconcileSkillSession(input2, options = {}) {
43063
43134
  if (input2.planDigest !== undefined && input2.planDigest !== planDigest)
43064
43135
  throw new SkillSelectionError("SESSION_PLAN_CHANGED", "The session reconciliation plan differs from the reviewed plan.");
43065
43136
  if (!input2.apply)
43066
- return { applied: false, plan, planDigest, archivePath: undefined, receiptPath: undefined, beforeSha256: snapshot.sha256, afterSha256: undefined };
43137
+ return { applied: false, plan, planDigest, archivePath: undefined, receiptPath: undefined, beforeSha256: snapshot2.sha256, afterSha256: undefined };
43067
43138
  assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)());
43068
43139
  const replacement = {
43069
43140
  ...old,
@@ -43072,7 +43143,7 @@ async function reconcileSkillSession(input2, options = {}) {
43072
43143
  profile: target,
43073
43144
  loaded
43074
43145
  };
43075
- const result = replaceSkillSession(skillSessionSnapshotBinding(snapshot), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
43146
+ const result = replaceSkillSession(skillSessionSnapshotBinding(snapshot2), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
43076
43147
  return { applied: true, plan, planDigest, ...result };
43077
43148
  }
43078
43149
  export {