@hasna/skills 0.10.34 → 0.10.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -36868,7 +36868,7 @@ var package_default;
36868
36868
  var init_package = __esm(() => {
36869
36869
  package_default = {
36870
36870
  name: "@hasna/skills",
36871
- version: "0.10.34",
36871
+ version: "0.10.36",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -51577,7 +51577,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
51577
51577
  return false;
51578
51578
  }
51579
51579
  }
51580
- function reviewCodexPluginControls(catalog, documents, cache3, cwd2, read2, rules, pluginSettings) {
51580
+ function reviewCodexPluginControls(catalog, documents, cache3, cwd2, read2, rules, pluginSettings, plannedRules) {
51581
51581
  if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd2)
51582
51582
  refuse2();
51583
51583
  const skills = projectCodexNativeSkillCatalog({ data: [{ cwd: cwd2, errors: [], skills: catalog.skills }] }, cwd2);
@@ -51648,7 +51648,9 @@ function reviewCodexPluginControls(catalog, documents, cache3, cwd2, read2, rule
51648
51648
  remotePluginId = plugin.remotePluginId;
51649
51649
  }
51650
51650
  const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document3 && rule?.enabled === false);
51651
- if (!exactPathDeny || !isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: expectedPluginId, enabled: true }, rules))
51651
+ const nativeSkill = { name: parsed.name, path: document3, pluginId: expectedPluginId, enabled: true };
51652
+ const plannedPathDeny = catalog.version === "codex-cli 0.160.0" && remotePluginId !== undefined && Array.isArray(rules) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === parsed.name && rule.enabled === false) && !rules.some((rule) => (rule?.path === document3 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document3 && rule.enabled === false) && isCodexNativeSkillDisabled(nativeSkill, plannedRules);
51653
+ if (!exactPathDeny && !plannedPathDeny || !isCodexNativeSkillDisabled(nativeSkill, rules))
51652
51654
  refuse2();
51653
51655
  }
51654
51656
  result2.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
@@ -52593,18 +52595,80 @@ var init_agent_sumi = __esm(() => {
52593
52595
  ];
52594
52596
  });
52595
52597
 
52598
+ // src/lib/codex-hook-trust-files.ts
52599
+ import { closeSync as closeSync8, constants as constants8, fstatSync as fstatSync8, fsyncSync as fsyncSync2, lstatSync as lstatSync16, openSync as openSync8, readSync as readSync6, writeFileSync as writeFileSync4 } from "fs";
52600
+ import { createHash as createHash12 } from "crypto";
52601
+ import { dirname as dirname11 } from "path";
52602
+ function need5(value, code) {
52603
+ if (!value)
52604
+ throw new Error(`CODEX_HOOK_TRUST_${code}`);
52605
+ }
52606
+ function safeParents(file) {
52607
+ for (let p = dirname11(file);; p = dirname11(p)) {
52608
+ const s = lstatSync16(p);
52609
+ need5(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
52610
+ need5((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
52611
+ if (dirname11(p) === p)
52612
+ break;
52613
+ }
52614
+ }
52615
+ function snapshot(file, privateFile = false, options = {}) {
52616
+ const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
52617
+ safeParents(file);
52618
+ const initial2 = lstatSync16(file, { bigint: true });
52619
+ need5(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
52620
+ need5(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
52621
+ const fd = openSync8(file, constants8.O_RDONLY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK);
52622
+ try {
52623
+ const before2 = fstatSync8(fd, { bigint: true });
52624
+ need5(sameStat(initial2, before2), "INPUT_CHANGED");
52625
+ const bytes = Buffer.alloc(Number(before2.size) + 1);
52626
+ let length = 0;
52627
+ while (length < bytes.length) {
52628
+ const n2 = readSync6(fd, bytes, length, bytes.length - length, null);
52629
+ if (!n2)
52630
+ break;
52631
+ length += n2;
52632
+ }
52633
+ need5(length === Number(before2.size) && sameStat(before2, fstatSync8(fd, { bigint: true })) && sameStat(before2, lstatSync16(file, { bigint: true })), "INPUT_CHANGED");
52634
+ const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
52635
+ return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash12("sha256").update(content).digest("hex") };
52636
+ } finally {
52637
+ closeSync8(fd);
52638
+ }
52639
+ }
52640
+ function unchanged2(before2) {
52641
+ const after2 = snapshot(before2.file, before2.privateFile, before2.readOnlyPackage ? { readOnlyPackage: true } : {});
52642
+ need5(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
52643
+ }
52644
+ function save(file, content) {
52645
+ safeParents(file);
52646
+ const fd = openSync8(file, constants8.O_WRONLY | constants8.O_CREAT | constants8.O_EXCL | constants8.O_NOFOLLOW, 384);
52647
+ try {
52648
+ writeFileSync4(fd, content);
52649
+ fsyncSync2(fd);
52650
+ } finally {
52651
+ closeSync8(fd);
52652
+ }
52653
+ }
52654
+ var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
52655
+ var init_codex_hook_trust_files = () => {};
52656
+
52596
52657
  // src/lib/agent-integration.ts
52597
- import { createHash as createHash12, randomUUID as randomUUID5 } from "crypto";
52658
+ import { createHash as createHash13, randomUUID as randomUUID5 } from "crypto";
52598
52659
  import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
52599
- import { existsSync as existsSync13, lstatSync as lstatSync16, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync13, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync7, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync8, closeSync as closeSync8, fsyncSync as fsyncSync2, fstatSync as fstatSync8, readSync as readSync6, constants as constants8, linkSync as linkSync2 } from "fs";
52600
- import { dirname as dirname11, join as join23, resolve as resolve12, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
52660
+ import { existsSync as existsSync13, lstatSync as lstatSync17, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync13, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync7, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync5, unlinkSync as unlinkSync3, chmodSync, openSync as openSync9, closeSync as closeSync9, fsyncSync as fsyncSync3, fstatSync as fstatSync9, readSync as readSync7, constants as constants9, linkSync as linkSync2 } from "fs";
52661
+ import { dirname as dirname12, join as join23, resolve as resolve12, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
52601
52662
  import { homedir as homedir3 } from "os";
52602
- function hasNoDarwinAcl(fd) {
52663
+ function hasTrustedDarwinAcl(fd, allowDenyOnly = false) {
52603
52664
  try {
52604
- const { dlopen, read: read2 } = __require("bun:ffi");
52665
+ const { dlopen, read: read2, ptr } = __require("bun:ffi");
52605
52666
  const library = dlopen("/usr/lib/libSystem.B.dylib", {
52606
52667
  acl_get_fd: { args: ["i32"], returns: "ptr" },
52607
52668
  acl_free: { args: ["ptr"], returns: "i32" },
52669
+ acl_valid: { args: ["ptr"], returns: "i32" },
52670
+ acl_get_entry: { args: ["ptr", "i32", "ptr"], returns: "i32" },
52671
+ acl_get_tag_type: { args: ["ptr", "ptr"], returns: "i32" },
52608
52672
  __error: { args: [], returns: "ptr" }
52609
52673
  });
52610
52674
  try {
@@ -52613,8 +52677,23 @@ function hasNoDarwinAcl(fd) {
52613
52677
  return false;
52614
52678
  const acl = library.symbols.acl_get_fd(fd);
52615
52679
  if (acl) {
52616
- library.symbols.acl_free(acl);
52617
- return false;
52680
+ try {
52681
+ if (!allowDenyOnly || library.symbols.acl_valid(acl) !== 0)
52682
+ return false;
52683
+ const entry = new BigUint64Array(1), tag = new Int32Array(1);
52684
+ for (let count = 0;count <= 128; count++) {
52685
+ const status = library.symbols.acl_get_entry(acl, count === 0 ? 0 : -1, ptr(entry));
52686
+ if (status !== 0) {
52687
+ return status === -1 && read2.i32(errno) === 22 && library.symbols.acl_valid(acl) === 0;
52688
+ }
52689
+ const value = read2.ptr(ptr(entry));
52690
+ if (count === 128 || !value || library.symbols.acl_get_tag_type(value, ptr(tag)) !== 0 || tag[0] !== 2)
52691
+ return false;
52692
+ }
52693
+ return false;
52694
+ } finally {
52695
+ library.symbols.acl_free(acl);
52696
+ }
52618
52697
  }
52619
52698
  return (acl === null || acl === 0) && read2.i32(errno) === 2;
52620
52699
  } finally {
@@ -52630,11 +52709,11 @@ function isSystemRootAlias(path) {
52630
52709
  const target = `/private${path}`, link2 = `private${path}`;
52631
52710
  const identity5 = (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}`;
52632
52711
  try {
52633
- const before2 = lstatSync16(path, { bigint: true });
52712
+ const before2 = lstatSync17(path, { bigint: true });
52634
52713
  if (!before2.isSymbolicLink() || before2.uid !== 0n || readlinkSync4(path) !== link2)
52635
52714
  return false;
52636
52715
  const directories = ["/", "/private", target].map((directory) => {
52637
- const stat = lstatSync16(directory, { bigint: true });
52716
+ const stat = lstatSync17(directory, { bigint: true });
52638
52717
  if (!stat.isDirectory() || stat.uid !== 0n)
52639
52718
  throw new Error("Untrusted system alias directory");
52640
52719
  if (directory !== "/private/tmp") {
@@ -52642,23 +52721,23 @@ function isSystemRootAlias(path) {
52642
52721
  throw new Error("Writable system alias directory");
52643
52722
  } else if ((stat.mode & 0o1000n) === 0n)
52644
52723
  throw new Error("Unprotected system temporary directory");
52645
- const fd = openSync8(directory, constants8.O_RDONLY | constants8.O_DIRECTORY | constants8.O_NOFOLLOW);
52724
+ const fd = openSync9(directory, constants9.O_RDONLY | constants9.O_DIRECTORY | constants9.O_NOFOLLOW);
52646
52725
  try {
52647
- if (identity5(fstatSync8(fd, { bigint: true })) !== identity5(stat) || !hasNoDarwinAcl(fd) || identity5(fstatSync8(fd, { bigint: true })) !== identity5(stat))
52726
+ if (identity5(fstatSync9(fd, { bigint: true })) !== identity5(stat) || !hasTrustedDarwinAcl(fd) || identity5(fstatSync9(fd, { bigint: true })) !== identity5(stat))
52648
52727
  throw new Error("Unverified system alias directory ACL");
52649
52728
  } finally {
52650
- closeSync8(fd);
52729
+ closeSync9(fd);
52651
52730
  }
52652
52731
  return { directory, identity: identity5(stat) };
52653
52732
  });
52654
- return realpathSync7(path) === target && readlinkSync4(path) === link2 && identity5(lstatSync16(path, { bigint: true })) === identity5(before2) && directories.every((item) => identity5(lstatSync16(item.directory, { bigint: true })) === item.identity);
52733
+ return realpathSync7(path) === target && readlinkSync4(path) === link2 && identity5(lstatSync17(path, { bigint: true })) === identity5(before2) && directories.every((item) => identity5(lstatSync17(item.directory, { bigint: true })) === item.identity);
52655
52734
  } catch {
52656
52735
  return false;
52657
52736
  }
52658
52737
  }
52659
52738
  function canonicalSystemPath(path) {
52660
52739
  const absolute = resolve12(path), root = `/${absolute.split(sep5)[1]}`;
52661
- if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync16(root, { throwIfNoEntry: false })?.isSymbolicLink())
52740
+ if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync17(root, { throwIfNoEntry: false })?.isSymbolicLink())
52662
52741
  return absolute;
52663
52742
  if (!isSystemRootAlias(root))
52664
52743
  throw new Error(`Refusing symlink path: ${root}`);
@@ -52667,9 +52746,9 @@ function canonicalSystemPath(path) {
52667
52746
  function assertSafePath(path) {
52668
52747
  let cursor = resolve12(path);
52669
52748
  while (true) {
52670
- if (lstatSync16(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
52749
+ if (lstatSync17(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
52671
52750
  throw new Error(`Refusing symlink path: ${cursor}`);
52672
- const parent = dirname11(cursor);
52751
+ const parent = dirname12(cursor);
52673
52752
  if (parent === cursor)
52674
52753
  return;
52675
52754
  cursor = parent;
@@ -52678,12 +52757,12 @@ function assertSafePath(path) {
52678
52757
  function readRootAlias(home, agent) {
52679
52758
  assertSafePath(home);
52680
52759
  const realHome = realpathSync7(home), alias = join23(realHome, `.${agent}`);
52681
- const stat = lstatSync16(alias, { throwIfNoEntry: false, bigint: true });
52760
+ const stat = lstatSync17(alias, { throwIfNoEntry: false, bigint: true });
52682
52761
  if (!stat?.isSymbolicLink())
52683
52762
  throw new Error(`Agent root alias changed after planning: ${alias}`);
52684
- const link2 = readlinkSync4(alias), targetPath = resolve12(dirname11(alias), link2);
52763
+ const link2 = readlinkSync4(alias), targetPath = resolve12(dirname12(alias), link2);
52685
52764
  assertSafePath(targetPath);
52686
- const targetStat = lstatSync16(targetPath, { throwIfNoEntry: false });
52765
+ const targetStat = lstatSync17(targetPath, { throwIfNoEntry: false });
52687
52766
  if (!targetStat?.isDirectory())
52688
52767
  throw new Error(`Agent root alias must target an existing directory: ${alias}`);
52689
52768
  const target = realpathSync7(targetPath), inside = relative5(realHome, target);
@@ -52696,7 +52775,7 @@ function rootAliases(home, allowed = false) {
52696
52775
  return [];
52697
52776
  const result2 = [];
52698
52777
  for (const agent of ["claude", "codex"])
52699
- if (lstatSync16(join23(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
52778
+ if (lstatSync17(join23(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
52700
52779
  result2.push(readRootAlias(home, agent));
52701
52780
  if (result2.some((item, index) => result2.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep5) || other.target.startsWith(item.target + sep5))))
52702
52781
  throw new Error("Agent root alias targets must not overlap");
@@ -52731,7 +52810,7 @@ function disabledCodexSkillPaths(config, aliases) {
52731
52810
  continue;
52732
52811
  settings.set(document3, [...settings.get(document3) ?? [], entry.enabled === false]);
52733
52812
  }
52734
- return [...settings].filter(([, values2]) => values2.length === 1 && values2[0] === true).map(([document3]) => dirname11(document3));
52813
+ return [...settings].filter(([, values2]) => values2.length === 1 && values2[0] === true).map(([document3]) => dirname12(document3));
52735
52814
  }
52736
52815
  function recheckRootAliases(aliases) {
52737
52816
  for (const binding of aliases) {
@@ -52744,35 +52823,35 @@ function recheckRootAliases(aliases) {
52744
52823
  }
52745
52824
  function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
52746
52825
  assertSafePath(path);
52747
- const before2 = lstatSync16(path);
52826
+ const before2 = lstatSync17(path);
52748
52827
  if (!before2.isFile() || before2.size > maximum)
52749
52828
  throw new Error("Unsupported or oversized native skill file");
52750
- const descriptor = openSync8(path, constants8.O_RDONLY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK);
52829
+ const descriptor = openSync9(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
52751
52830
  try {
52752
- const opened = fstatSync8(descriptor);
52831
+ const opened = fstatSync9(descriptor);
52753
52832
  if (!opened.isFile() || opened.dev !== before2.dev || opened.ino !== before2.ino || opened.size !== before2.size)
52754
52833
  throw new Error("Native skill file changed while reading");
52755
52834
  const bytes = Buffer.allocUnsafe(before2.size + 1);
52756
52835
  let length = 0;
52757
52836
  while (length < bytes.length) {
52758
- const count = readSync6(descriptor, bytes, length, bytes.length - length, null);
52837
+ const count = readSync7(descriptor, bytes, length, bytes.length - length, null);
52759
52838
  if (!count)
52760
52839
  break;
52761
52840
  length += count;
52762
52841
  }
52763
- const after2 = fstatSync8(descriptor), current = lstatSync16(path);
52842
+ const after2 = fstatSync9(descriptor), current = lstatSync17(path);
52764
52843
  if (current.dev !== opened.dev || current.ino !== opened.ino || current.size !== after2.size || current.mtimeMs !== after2.mtimeMs || current.ctimeMs !== after2.ctimeMs || length !== before2.size || after2.size !== before2.size || after2.mtimeMs !== opened.mtimeMs || after2.ctimeMs !== opened.ctimeMs)
52765
52844
  throw new Error("Native skill file changed while reading");
52766
52845
  return bytes.subarray(0, length);
52767
52846
  } finally {
52768
- closeSync8(descriptor);
52847
+ closeSync9(descriptor);
52769
52848
  }
52770
52849
  }
52771
52850
  function treeHash(root) {
52772
- const hash2 = createHash12("sha256");
52851
+ const hash2 = createHash13("sha256");
52773
52852
  let bytes = 0, files = 0;
52774
52853
  function visit2(path) {
52775
- const stat = lstatSync16(path);
52854
+ const stat = lstatSync17(path);
52776
52855
  if (stat.isSymbolicLink())
52777
52856
  throw new Error(`Refusing symlink in skill: ${path}`);
52778
52857
  const rel = relative5(root, path);
@@ -52823,7 +52902,7 @@ function parseNativeMigrationTargetManifest(input) {
52823
52902
  if (!isAbsolute11(item.projectRoot) || resolve12(item.projectRoot) !== item.projectRoot)
52824
52903
  throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
52825
52904
  const projectRoot = canonicalSystemPath(item.projectRoot);
52826
- if (!existsSync13(projectRoot) || !lstatSync16(projectRoot).isDirectory())
52905
+ if (!existsSync13(projectRoot) || !lstatSync17(projectRoot).isDirectory())
52827
52906
  throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
52828
52907
  assertSafePath(projectRoot);
52829
52908
  if (isAbsolute11(item.path) || item.path.includes("\\") || item.path.length === 0 || item.path.includes("\x00"))
@@ -52853,7 +52932,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
52853
52932
  if (!isAbsolute11(target.projectRoot) || resolve12(target.projectRoot) !== target.projectRoot)
52854
52933
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
52855
52934
  const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative5(projectRoot, resolve12(projectRoot, target.path));
52856
- if (!existsSync13(projectRoot) || !lstatSync16(projectRoot).isDirectory())
52935
+ if (!existsSync13(projectRoot) || !lstatSync17(projectRoot).isDirectory())
52857
52936
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
52858
52937
  assertSafePath(projectRoot);
52859
52938
  if (isAbsolute11(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep5}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
@@ -52882,7 +52961,7 @@ function projectAncestorDirectories(projects) {
52882
52961
  if (depth >= 100)
52883
52962
  throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
52884
52963
  directories.add(path);
52885
- const parent = dirname11(path);
52964
+ const parent = dirname12(path);
52886
52965
  if (parent === path)
52887
52966
  break;
52888
52967
  path = parent;
@@ -52928,12 +53007,12 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
52928
53007
  let reviewedCacheAliasFound = false;
52929
53008
  function verifiedSiblingCacheAlias(agent, path, parent) {
52930
53009
  const link2 = readlinkSync4(path), lexicalTarget = resolve12(parent, link2);
52931
- if (isAbsolute11(link2) ? link2 !== lexicalTarget : dirname11(link2) !== ".")
53010
+ if (isAbsolute11(link2) ? link2 !== lexicalTarget : dirname12(link2) !== ".")
52932
53011
  return false;
52933
53012
  const target = canonicalSystemPath(lexicalTarget);
52934
- if (dirname11(target) !== parent)
53013
+ if (dirname12(target) !== parent)
52935
53014
  return false;
52936
- if (!lstatSync16(target, { throwIfNoEntry: false })?.isDirectory())
53015
+ if (!lstatSync17(target, { throwIfNoEntry: false })?.isDirectory())
52937
53016
  return false;
52938
53017
  const scan = cacheScans.get(target);
52939
53018
  if (!scan?.complete || scan.entries > maxAliasProofEntries)
@@ -52958,7 +53037,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
52958
53037
  return scan;
52959
53038
  if (!existsSync13(path))
52960
53039
  return scan;
52961
- const stat = lstatSync16(path);
53040
+ const stat = lstatSync17(path);
52962
53041
  if (stat.isFile()) {
52963
53042
  if (agent === "sumi" && depth === 1 && path.endsWith(".md"))
52964
53043
  throw new Error("NATIVE_SKILL_DRIFT: flat Sumi skill documents require a dedicated migration adapter");
@@ -53007,7 +53086,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
53007
53086
  if (isVendor && !options.includeVendor)
53008
53087
  continue;
53009
53088
  const child = join23(path, name);
53010
- if (isVendor && lstatSync16(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
53089
+ if (isVendor && lstatSync17(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
53011
53090
  const target = statSync8(child, { throwIfNoEntry: false });
53012
53091
  if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent, child, path)) {
53013
53092
  scan.entries++;
@@ -53222,15 +53301,21 @@ function planAgentIntegration(options) {
53222
53301
  }
53223
53302
  return resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, retainedReview, canonical: (path) => canonicalAgentPath(path, aliases) });
53224
53303
  });
53225
- const codexConfig = options.agents.includes("codex") ? Bun.TOML.parse(readOptional(canonicalAgentPath(join23(home, ".codex", "config.toml"), aliases)) ?? "") : {};
53304
+ const codexConfigBefore = options.agents.includes("codex") ? readOptional(canonicalAgentPath(join23(home, ".codex", "config.toml"), aliases)) : null;
53305
+ const codexConfig = Bun.TOML.parse(codexConfigBefore ?? "");
53226
53306
  const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, disabledVendorPaths: disabledCodexSkillPaths(codexConfig, aliases) });
53307
+ const codexPathConfig = options.agents.includes("codex") ? disableCodexSkills(codexConfigBefore ?? "", nativeSkills, aliases, canonicalAgentPath(join23(home, ".codex/skills", CLI_BRIDGE_NAME), aliases)) : undefined;
53308
+ const plannedCodexRules = codexPathConfig === undefined ? undefined : Bun.TOML.parse(codexPathConfig).skills?.config ?? [];
53227
53309
  const observedNativeSources = [];
53228
53310
  const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join23(entry.path, "SKILL.md")), canonicalAgentPath(join23(home, ".codex/plugins/cache"), aliases), resolve12(options.projectDir ?? home), (path) => {
53229
53311
  const bytes = readNativeBytes(path, 1024 * 1024);
53230
53312
  observedNativeSources.push({ path, sha256: sha3(bytes) });
53231
53313
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
53232
- }, codexConfig.skills?.config ?? [], codexConfig.plugins) : { skills: policy.bridge?.codexPluginSkills ?? [], inactivePlugins: policy.bridge?.codexInactivePlugins ?? [], sourceInputs: policy.bridge?.discovery?.codex?.codexInstallationInputs?.plugins ?? [] };
53314
+ }, codexConfig.skills?.config ?? [], codexConfig.plugins, plannedCodexRules) : { skills: policy.bridge?.codexPluginSkills ?? [], inactivePlugins: policy.bridge?.codexInactivePlugins ?? [], sourceInputs: policy.bridge?.discovery?.codex?.codexInstallationInputs?.plugins ?? [] };
53233
53315
  const codexPluginSkills = codexPluginControls.skills;
53316
+ if (options.agents.includes("codex") && !options.codexNativeCatalog && codexPluginSkills.length && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join23(home, ".codex/plugins/cache"), aliases), codexPluginSkills, (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)))) {
53317
+ throw new Error("NATIVE_SKILL_DRIFT: reviewed native plugin capability controls changed; provide a fresh native catalog and discovery review");
53318
+ }
53234
53319
  const codexInactivePlugins = codexPluginControls.inactivePlugins;
53235
53320
  const codexDiscovery = discoveries.find((binding) => binding.agent === "codex");
53236
53321
  const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root) => root === input.sourceRoot || root.startsWith(input.sourceRoot + sep5) || input.sourceRoot.startsWith(root + sep5)) && codexDiscovery.sources.some((source) => source.path === join23(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
@@ -53305,7 +53390,9 @@ function planAgentIntegration(options) {
53305
53390
  changes.push({ path, before: before2, after: after2 });
53306
53391
  if (agent === "codex") {
53307
53392
  const configPath = canonicalAgentPath(join23(home, ".codex", "config.toml"), aliases), previous = readOptional(configPath);
53308
- const next = disableReviewedCodexPluginNames(disableCodexSkills(previous ?? "", nativeSkills, aliases, bridgePath), codexPluginSkills);
53393
+ if (previous !== codexConfigBefore)
53394
+ throw new Error(`Configuration changed during planning: ${configPath}`);
53395
+ const next = disableReviewedCodexPluginNames(codexPathConfig, codexPluginSkills);
53309
53396
  if (next !== (previous ?? ""))
53310
53397
  changes.push({ path: configPath, before: previous, after: next });
53311
53398
  }
@@ -53341,6 +53428,171 @@ function planAgentIntegration(options) {
53341
53428
  recheckRootAliases(aliases);
53342
53429
  return { dataDir: dataDir3, profileId, changes, nativeSkills, ...observedNativeSources.length ? { observedNativeSources } : {}, ...nextPolicy.bridge.codexPluginSkillReview ? { codexPluginSkillReview: nextPolicy.bridge.codexPluginSkillReview } : {}, observedPolicy: { path: policyPath, before: previousPolicy }, discoveryBefore: discoveries, discoveryAfter, ...aliases.length ? { rootAliases: aliases } : {}, ...retainedAgents.length ? { retainedReviewChecks: { home, projectDir: options.projectDir ?? home, agents: retainedAgents } } : {} };
53343
53430
  }
53431
+ function hookProjectionRefusal(reason) {
53432
+ throw new Error(`CLAUDE_MANAGED_HOOK_${reason}`);
53433
+ }
53434
+ function projectedHookAcl(path, observed) {
53435
+ if (process.platform !== "darwin")
53436
+ return;
53437
+ const identity5 = (stat) => `${stat.dev}:${stat.ino}:${stat.ctimeNs}:${stat.uid}:${stat.mode}:${stat.nlink}:${stat.size}:${stat.mtimeNs}`;
53438
+ const fd = openSync9(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK | (observed.isDirectory() ? constants9.O_DIRECTORY : 0));
53439
+ try {
53440
+ if (identity5(fstatSync9(fd, { bigint: true })) !== identity5(observed) || !hasTrustedDarwinAcl(fd, true) || identity5(fstatSync9(fd, { bigint: true })) !== identity5(observed) || identity5(lstatSync17(path, { bigint: true })) !== identity5(observed))
53441
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53442
+ } finally {
53443
+ closeSync9(fd);
53444
+ }
53445
+ }
53446
+ function projectedHookExecutable(command, expectedResolved) {
53447
+ try {
53448
+ if (!isAbsolute11(command) || /[\0\r\n]/.test(command) || resolve12(command) !== command)
53449
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53450
+ command = canonicalSystemPath(command);
53451
+ const parents2 = (file = command) => {
53452
+ const result2 = [];
53453
+ for (let path = dirname12(file);; path = dirname12(path)) {
53454
+ const stat = lstatSync17(path, { bigint: true });
53455
+ if (!stat.isDirectory() || (stat.mode & 0o022n) !== 0n && !(stat.uid === 0n && (stat.mode & 0o1000n) !== 0n))
53456
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53457
+ projectedHookAcl(path, stat);
53458
+ result2.push(`${path}:${stat.dev}:${stat.ino}:${stat.uid}:${stat.mode}`);
53459
+ if (dirname12(path) === path)
53460
+ break;
53461
+ }
53462
+ return result2;
53463
+ };
53464
+ const parentIdentity = parents2(), link2 = lstatSync17(command, { bigint: true });
53465
+ if (link2.uid !== BigInt(process.getuid()) || !link2.isFile() && !link2.isSymbolicLink())
53466
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53467
+ const linkIdentity = (stat) => `${stat.dev}:${stat.ino}:${stat.mode}:${stat.uid}:${stat.ctimeNs}`;
53468
+ const resolved = realpathSync7(command);
53469
+ if (expectedResolved !== undefined && resolved !== expectedResolved)
53470
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53471
+ const resolvedParentIdentity = parents2(resolved);
53472
+ const manifest = snapshot(join23(dirname12(dirname12(resolved)), "package.json"), false, { readOnlyPackage: true });
53473
+ projectedHookAcl(manifest.file, manifest.stat);
53474
+ const pkg = JSON.parse(manifest.text);
53475
+ if (pkg.name !== "@hasna/skills" || !/^\d+\.\d+\.\d+$/.test(pkg.version) || pkg.bin?.skills !== "bin/index.js" || resolved !== join23(dirname12(manifest.file), "bin/index.js"))
53476
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53477
+ const cli = snapshot(resolved, false, { readOnlyPackage: true });
53478
+ projectedHookAcl(cli.file, cli.stat);
53479
+ if ((cli.stat.mode & 0o100n) === 0n)
53480
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53481
+ const recheck = () => {
53482
+ try {
53483
+ if (realpathSync7(command) !== resolved || linkIdentity(lstatSync17(command, { bigint: true })) !== linkIdentity(link2) || !isDeepStrictEqual5(parents2(), parentIdentity) || !isDeepStrictEqual5(parents2(resolved), resolvedParentIdentity))
53484
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53485
+ projectedHookAcl(cli.file, cli.stat);
53486
+ projectedHookAcl(manifest.file, manifest.stat);
53487
+ unchanged2(cli);
53488
+ unchanged2(manifest);
53489
+ } catch {
53490
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53491
+ }
53492
+ };
53493
+ recheck();
53494
+ return { resolved, sha256: cli.sha256, manifestSha256: manifest.sha256, recheck };
53495
+ } catch {
53496
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53497
+ }
53498
+ }
53499
+ function planClaudeManagedHookProjection(options) {
53500
+ if (typeof options.targetSettings !== "string" || Buffer.byteLength(options.targetSettings) > 1024 * 1024)
53501
+ hookProjectionRefusal("TARGET_INVALID");
53502
+ const targetSha256 = sha3(options.targetSettings);
53503
+ if (!/^[a-f0-9]{64}$/.test(options.expectedTargetSha256) || options.expectedTargetSha256 !== targetSha256)
53504
+ hookProjectionRefusal("TARGET_CHANGED");
53505
+ let target;
53506
+ try {
53507
+ target = jsonObject(options.targetSettings, "target");
53508
+ } catch {
53509
+ hookProjectionRefusal("TARGET_INVALID");
53510
+ }
53511
+ const home = resolve12(options.home ?? homedir3()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
53512
+ const policyPath = join23(dataDir3, "agent-policy.json");
53513
+ let policyBytes, settingsBytes, settingsPath, command, profile;
53514
+ try {
53515
+ policyBytes = readNativeBytes(policyPath, 1024 * 1024);
53516
+ const snapshot2 = readManagedSkillPolicySnapshot(dataDir3);
53517
+ if (!snapshot2 || snapshot2.text !== policyBytes.toString("utf8"))
53518
+ hookProjectionRefusal("SOURCE_UNVERIFIED");
53519
+ const binding = snapshot2.value.bridge;
53520
+ settingsPath = canonicalAgentPath(join23(home, AGENT_ADAPTERS.claude.config), binding?.rootAliases ?? []);
53521
+ settingsBytes = readNativeBytes(settingsPath, 1024 * 1024);
53522
+ command = binding?.commands?.claude;
53523
+ profile = binding?.profiles?.claude;
53524
+ if (typeof command !== "string" || typeof profile !== "string")
53525
+ hookProjectionRefusal("SOURCE_UNVERIFIED");
53526
+ assertManagedAgentBridge("claude", { home, dataDir: dataDir3, projectDir: options.projectDir, profileId: profile });
53527
+ } catch {
53528
+ hookProjectionRefusal("SOURCE_UNVERIFIED");
53529
+ }
53530
+ const executable = projectedHookExecutable(command);
53531
+ const sourceSha256 = sha3(JSON.stringify({
53532
+ home,
53533
+ policyPath,
53534
+ policy: sha3(policyBytes),
53535
+ settingsPath,
53536
+ settings: sha3(settingsBytes),
53537
+ executable: { path: executable.resolved, sha256: executable.sha256, manifestSha256: executable.manifestSha256 }
53538
+ }));
53539
+ if (options.expectedSourceSha256 !== undefined && options.expectedSourceSha256 !== sourceSha256)
53540
+ hookProjectionRefusal("SOURCE_CHANGED");
53541
+ const replacements2 = [];
53542
+ const observed = [executable];
53543
+ if (target.hooks !== undefined) {
53544
+ if (!target.hooks || typeof target.hooks !== "object" || Array.isArray(target.hooks))
53545
+ hookProjectionRefusal("TARGET_INVALID");
53546
+ for (const event of [...AGENT_ADAPTERS.claude.events, "PreToolUse"]) {
53547
+ const groups = target.hooks[event];
53548
+ if (groups === undefined)
53549
+ continue;
53550
+ if (!Array.isArray(groups))
53551
+ hookProjectionRefusal("TARGET_INVALID");
53552
+ let recognized = 0;
53553
+ for (const [groupIndex, group] of groups.entries()) {
53554
+ if (!group || !Array.isArray(group.hooks))
53555
+ hookProjectionRefusal("TARGET_INVALID");
53556
+ for (const [hookIndex, hook] of group.hooks.entries()) {
53557
+ if (hook?.type !== "command" || typeof hook.command !== "string")
53558
+ continue;
53559
+ if (!hook.command.includes("hook user-prompt --agent claude"))
53560
+ continue;
53561
+ const match = /^('(?:[^']|'\\'')*') hook user-prompt --agent claude --selection-profile ([A-Za-z0-9][A-Za-z0-9._-]{0,127}) --event ([A-Za-z]+)$/.exec(hook.command);
53562
+ if (!match || match[3] !== event)
53563
+ hookProjectionRefusal("UNRECOGNIZED");
53564
+ const oldCommand = match[1].slice(1, -1).replaceAll("'\\''", "'");
53565
+ let rendered;
53566
+ try {
53567
+ rendered = renderAgentHookCommand(oldCommand, "claude", match[2], event);
53568
+ } catch {
53569
+ hookProjectionRefusal("UNRECOGNIZED");
53570
+ }
53571
+ if (rendered !== hook.command)
53572
+ hookProjectionRefusal("UNRECOGNIZED");
53573
+ const legacy = projectedHookExecutable(oldCommand, executable.resolved);
53574
+ if (legacy.resolved !== executable.resolved || legacy.sha256 !== executable.sha256 || legacy.manifestSha256 !== executable.manifestSha256)
53575
+ hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53576
+ observed.push(legacy);
53577
+ if (++recognized > 1)
53578
+ hookProjectionRefusal("AMBIGUOUS");
53579
+ const replacement = renderAgentHookCommand(command, "claude", profile, event);
53580
+ if (replacement !== hook.command)
53581
+ replacements2.push({ event, groupIndex, hookIndex, beforeSha256: sha3(hook.command), command: replacement });
53582
+ }
53583
+ }
53584
+ }
53585
+ }
53586
+ try {
53587
+ if (!readNativeBytes(policyPath, 1024 * 1024).equals(policyBytes) || !readNativeBytes(settingsPath, 1024 * 1024).equals(settingsBytes))
53588
+ hookProjectionRefusal("SOURCE_CHANGED");
53589
+ } catch {
53590
+ hookProjectionRefusal("SOURCE_CHANGED");
53591
+ }
53592
+ for (const item of observed)
53593
+ item.recheck();
53594
+ return { schema: "hasna.claude-managed-hook-projection.v1", targetSha256, sourceSha256, replacements: replacements2 };
53595
+ }
53344
53596
  function verifyCoordinatedDiscovery(binding, home, aliases) {
53345
53597
  try {
53346
53598
  if (binding.method !== "automatic" && binding.method !== "reviewed")
@@ -53357,10 +53609,10 @@ function verifyCoordinatedDiscovery(binding, home, aliases) {
53357
53609
  }
53358
53610
  function atomicWrite2(path, content) {
53359
53611
  assertSafePath(path);
53360
- mkdirSync5(dirname11(path), { recursive: true, mode: 448 });
53612
+ mkdirSync5(dirname12(path), { recursive: true, mode: 448 });
53361
53613
  const temporary = `${path}.skills-${randomUUID5()}`;
53362
53614
  try {
53363
- writeFileSync4(temporary, content, { mode: 384, flag: "wx" });
53615
+ writeFileSync5(temporary, content, { mode: 384, flag: "wx" });
53364
53616
  renameSync2(temporary, path);
53365
53617
  } finally {
53366
53618
  if (existsSync13(temporary))
@@ -53371,10 +53623,10 @@ function planAgentSettingsWitnessUpgrade(options) {
53371
53623
  if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3].includes(options.targetCodexVersion)))
53372
53624
  throw new Error("Invalid Codex witness target version");
53373
53625
  const home = resolve12(options.home ?? homedir3()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
53374
- const snapshot = readManagedSkillPolicySnapshot(dataDir3);
53375
- if (!snapshot || sha3(snapshot.text) !== options.expectedPolicySha256)
53626
+ const snapshot2 = readManagedSkillPolicySnapshot(dataDir3);
53627
+ if (!snapshot2 || sha3(snapshot2.text) !== options.expectedPolicySha256)
53376
53628
  throw new Error("Managed policy preimage changed");
53377
- const policy = snapshot.value, aliases = policy.bridge?.rootAliases ?? [];
53629
+ const policy = snapshot2.value, aliases = policy.bridge?.rootAliases ?? [];
53378
53630
  recheckRootAliases(aliases);
53379
53631
  const binding = policy.bridge?.discovery?.[options.agent];
53380
53632
  if (!binding || binding.agent !== options.agent || binding.method !== "reviewed")
@@ -53418,7 +53670,7 @@ function planAgentSettingsWitnessUpgrade(options) {
53418
53670
  const replacement = { ...binding, sources: rebound };
53419
53671
  verifyAgentDiscovery(replacement);
53420
53672
  const after2 = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
53421
- return { dataDir: dataDir3, profileId: policy.profileId, changes: [{ path: join23(dataDir3, "agent-policy.json"), before: snapshot.text, after: after2 }], nativeSkills: [], observedPolicy: { path: join23(dataDir3, "agent-policy.json"), before: snapshot.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
53673
+ return { dataDir: dataDir3, profileId: policy.profileId, changes: [{ path: join23(dataDir3, "agent-policy.json"), before: snapshot2.text, after: after2 }], nativeSkills: [], observedPolicy: { path: join23(dataDir3, "agent-policy.json"), before: snapshot2.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
53422
53674
  }
53423
53675
  function applyAgentIntegration(plan) {
53424
53676
  for (const source of plan.observedNativeSources ?? [])
@@ -53471,7 +53723,7 @@ function applyAgentIntegration(plan) {
53471
53723
  for (const [index, change] of plan.changes.entries())
53472
53724
  if (change.before !== null) {
53473
53725
  const backup = join23(backupRoot, `${index}-${sha3(change.path).slice(0, 12)}.backup`);
53474
- writeFileSync4(backup, change.before, { mode: 384, flag: "wx" });
53726
+ writeFileSync5(backup, change.before, { mode: 384, flag: "wx" });
53475
53727
  if (readFileSync13(backup, "utf8") !== change.before)
53476
53728
  throw new Error("Native configuration preservation readback failed");
53477
53729
  backups.push(backup);
@@ -53481,7 +53733,7 @@ function applyAgentIntegration(plan) {
53481
53733
  recheckRootAliases(aliases);
53482
53734
  if (currentText(change.path) !== change.before)
53483
53735
  throw new Error(`Configuration changed after planning: ${change.path}`);
53484
- for (let directory = dirname11(change.path);!existsSync13(directory); directory = dirname11(directory))
53736
+ for (let directory = dirname12(change.path);!existsSync13(directory); directory = dirname12(directory))
53485
53737
  createdDirectories.add(directory);
53486
53738
  const after2 = change.after;
53487
53739
  atomicWrite2(change.path, after2);
@@ -53532,11 +53784,11 @@ function applyAgentIntegration(plan) {
53532
53784
  }
53533
53785
  function syncArchiveDirectory(path) {
53534
53786
  assertSafePath(path);
53535
- const descriptor = openSync8(path, constants8.O_RDONLY | constants8.O_DIRECTORY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK);
53787
+ const descriptor = openSync9(path, constants9.O_RDONLY | constants9.O_DIRECTORY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
53536
53788
  try {
53537
- fsyncSync2(descriptor);
53789
+ fsyncSync3(descriptor);
53538
53790
  } finally {
53539
- closeSync8(descriptor);
53791
+ closeSync9(descriptor);
53540
53792
  }
53541
53793
  }
53542
53794
  function writeArchiveJournal(path, value) {
@@ -53544,18 +53796,18 @@ function writeArchiveJournal(path, value) {
53544
53796
  const temporary = `${path}.skills-${randomUUID5()}`;
53545
53797
  let descriptor;
53546
53798
  try {
53547
- descriptor = openSync8(temporary, constants8.O_WRONLY | constants8.O_CREAT | constants8.O_EXCL | constants8.O_NOFOLLOW, 384);
53548
- writeFileSync4(descriptor, `${JSON.stringify(value)}
53799
+ descriptor = openSync9(temporary, constants9.O_WRONLY | constants9.O_CREAT | constants9.O_EXCL | constants9.O_NOFOLLOW, 384);
53800
+ writeFileSync5(descriptor, `${JSON.stringify(value)}
53549
53801
  `);
53550
- fsyncSync2(descriptor);
53551
- closeSync8(descriptor);
53802
+ fsyncSync3(descriptor);
53803
+ closeSync9(descriptor);
53552
53804
  descriptor = undefined;
53553
53805
  renameSync2(temporary, path);
53554
- syncArchiveDirectory(dirname11(path));
53806
+ syncArchiveDirectory(dirname12(path));
53555
53807
  } finally {
53556
53808
  if (descriptor !== undefined)
53557
- closeSync8(descriptor);
53558
- if (lstatSync16(temporary, { throwIfNoEntry: false }))
53809
+ closeSync9(descriptor);
53810
+ if (lstatSync17(temporary, { throwIfNoEntry: false }))
53559
53811
  unlinkSync3(temporary);
53560
53812
  }
53561
53813
  }
@@ -53589,7 +53841,7 @@ function archiveNativeSkills(inventory, options) {
53589
53841
  const moved = [];
53590
53842
  const verifyArchive = (entry) => {
53591
53843
  assertSafePath(entry.archive);
53592
- const stat = lstatSync16(entry.archive);
53844
+ const stat = lstatSync17(entry.archive);
53593
53845
  if (entry.discoveryOnly ? !stat.isFile() : !stat.isDirectory())
53594
53846
  throw new Error("Archive type changed");
53595
53847
  if ((entry.discoveryOnly ? sha3(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
@@ -53597,14 +53849,14 @@ function archiveNativeSkills(inventory, options) {
53597
53849
  };
53598
53850
  assertSafePath(archiveRoot);
53599
53851
  const created = [];
53600
- for (let path = archiveRoot;!existsSync13(path); path = dirname11(path))
53852
+ for (let path = archiveRoot;!existsSync13(path); path = dirname12(path))
53601
53853
  created.push(path);
53602
53854
  mkdirSync5(archiveRoot, { recursive: true, mode: 448 });
53603
53855
  try {
53604
53856
  for (const directory of created)
53605
53857
  syncArchiveDirectory(directory);
53606
53858
  if (created.length)
53607
- syncArchiveDirectory(dirname11(created.at(-1)));
53859
+ syncArchiveDirectory(dirname12(created.at(-1)));
53608
53860
  writeArchiveJournal(receiptPath, journal);
53609
53861
  for (const [index, entry] of selected.entries()) {
53610
53862
  recheckRootAliases(aliases);
@@ -53616,7 +53868,7 @@ function archiveNativeSkills(inventory, options) {
53616
53868
  writeArchiveJournal(receiptPath, journal);
53617
53869
  renameSync2(move.source, move.archive);
53618
53870
  moved.push(move);
53619
- syncArchiveDirectory(dirname11(move.source));
53871
+ syncArchiveDirectory(dirname12(move.source));
53620
53872
  syncArchiveDirectory(archiveRoot);
53621
53873
  verifyArchive(move);
53622
53874
  move.status = "archived";
@@ -53637,7 +53889,7 @@ function archiveNativeSkills(inventory, options) {
53637
53889
  recheckRootAliases(aliases);
53638
53890
  assertSafePath(entry.source);
53639
53891
  assertSafePath(entry.archive);
53640
- if (lstatSync16(entry.source, { throwIfNoEntry: false })) {
53892
+ if (lstatSync17(entry.source, { throwIfNoEntry: false })) {
53641
53893
  entry.status = "recovery-required";
53642
53894
  entry.conflict = "source-occupied";
53643
53895
  continue;
@@ -53651,10 +53903,10 @@ function archiveNativeSkills(inventory, options) {
53651
53903
  }
53652
53904
  if (entry.discoveryOnly) {
53653
53905
  linkSync2(entry.archive, entry.source);
53654
- syncArchiveDirectory(dirname11(entry.source));
53906
+ syncArchiveDirectory(dirname12(entry.source));
53655
53907
  unlinkSync3(entry.archive);
53656
53908
  } else {
53657
- if (lstatSync16(entry.source, { throwIfNoEntry: false })) {
53909
+ if (lstatSync17(entry.source, { throwIfNoEntry: false })) {
53658
53910
  entry.status = "recovery-required";
53659
53911
  entry.conflict = "source-occupied";
53660
53912
  continue;
@@ -53662,7 +53914,7 @@ function archiveNativeSkills(inventory, options) {
53662
53914
  renameSync2(entry.archive, entry.source);
53663
53915
  }
53664
53916
  entry.status = "restored";
53665
- syncArchiveDirectory(dirname11(entry.source));
53917
+ syncArchiveDirectory(dirname12(entry.source));
53666
53918
  syncArchiveDirectory(archiveRoot);
53667
53919
  } catch {
53668
53920
  entry.status = "recovery-required";
@@ -53687,10 +53939,10 @@ function assertManagedAgentBridge(agent, options = {}) {
53687
53939
  function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscovery) {
53688
53940
  const home = resolve12(options.home ?? homedir3()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
53689
53941
  assertSafePath(join23(dataDir3, "agent-policy.json"));
53690
- const snapshot = readManagedSkillPolicySnapshot(dataDir3);
53691
- if (!snapshot)
53942
+ const snapshot2 = readManagedSkillPolicySnapshot(dataDir3);
53943
+ if (!snapshot2)
53692
53944
  throw new Error("NATIVE_SKILL_DRIFT: install the Skills bridge with skills hook install");
53693
- const binding = snapshot.value.bridge;
53945
+ const binding = snapshot2.value.bridge;
53694
53946
  if (!binding || binding.version !== CLI_BRIDGE_VERSION || binding.digest !== CLI_BRIDGE_DIGEST || binding.home !== home || !Array.isArray(binding.agents) || !binding.agents.includes(agent))
53695
53947
  throw new Error("NATIVE_SKILL_DRIFT: the managed Skills bridge binding is missing or incompatible; run skills hook install");
53696
53948
  const aliases = binding.rootAliases ?? [];
@@ -53846,7 +54098,7 @@ function assertNativeExportAllowed(dataDir3 = getDataDirReadOnly()) {
53846
54098
  if (requiresCliSkillLoading(dataDir3))
53847
54099
  throw new Error("NATIVE_SKILL_EXPORT_DISABLED: this station loads skills through the Skills CLI; use skills sync --selection-profile <id>");
53848
54100
  }
53849
- var sha3 = (data) => createHash12("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
54101
+ var sha3 = (data) => createHash13("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
53850
54102
  var init_agent_integration = __esm(() => {
53851
54103
  init_codex_plugin_skill_controls();
53852
54104
  init_codex_native_skill_catalog();
@@ -53862,12 +54114,13 @@ var init_agent_integration = __esm(() => {
53862
54114
  init_agent_sumi();
53863
54115
  init_agent_hermes();
53864
54116
  init_claude_settings_witness();
54117
+ init_codex_hook_trust_files();
53865
54118
  HOOK_EVENTS = ["UserPromptSubmit", "SessionStart", "SubagentStart"];
53866
54119
  ROOTS = NATIVE_SKILL_ROOTS;
53867
54120
  });
53868
54121
 
53869
54122
  // src/lib/home-migration.ts
53870
- import { existsSync as existsSync14, mkdirSync as mkdirSync6, readdirSync as readdirSync9, renameSync as renameSync3, rmSync, statSync as statSync9, writeFileSync as writeFileSync5 } from "fs";
54123
+ import { existsSync as existsSync14, mkdirSync as mkdirSync6, readdirSync as readdirSync9, renameSync as renameSync3, rmSync, statSync as statSync9, writeFileSync as writeFileSync6 } from "fs";
53871
54124
  import { join as join25 } from "path";
53872
54125
  function layoutMigrationRecordPath(appDir) {
53873
54126
  return join25(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD);
@@ -53990,7 +54243,7 @@ function migrateOwnerLayout(options = {}) {
53990
54243
  moved,
53991
54244
  note: "installed/ and legacy flat skill dirs moved into skills/; custom/ retained"
53992
54245
  };
53993
- writeFileSync5(layoutMigrationRecordPath(appDir), `${JSON.stringify(record3, null, 2)}
54246
+ writeFileSync6(layoutMigrationRecordPath(appDir), `${JSON.stringify(record3, null, 2)}
53994
54247
  `);
53995
54248
  return { status: "migrated", moved, created, record: record3 };
53996
54249
  }
@@ -54005,7 +54258,7 @@ var init_home_migration = __esm(() => {
54005
54258
  import {
54006
54259
  cpSync as cpSync2,
54007
54260
  existsSync as existsSync15,
54008
- lstatSync as lstatSync17,
54261
+ lstatSync as lstatSync18,
54009
54262
  mkdirSync as mkdirSync7,
54010
54263
  mkdtempSync,
54011
54264
  readFileSync as readFileSync14,
@@ -54013,17 +54266,17 @@ import {
54013
54266
  renameSync as renameSync4,
54014
54267
  rmSync as rmSync2,
54015
54268
  statSync as statSync10,
54016
- writeFileSync as writeFileSync6
54269
+ writeFileSync as writeFileSync7
54017
54270
  } from "fs";
54018
54271
  import { homedir as homedir4 } from "os";
54019
- import { basename as basename6, dirname as dirname12, join as join26 } from "path";
54272
+ import { basename as basename6, dirname as dirname13, join as join26 } from "path";
54020
54273
  function isSkillsOwnershipMarker(marker) {
54021
54274
  return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
54022
54275
  }
54023
54276
  function hasSkillsOwnershipMarker(dir) {
54024
54277
  const path = join26(dir, SYNC_MARKER_FILE);
54025
54278
  try {
54026
- if (!lstatSync17(path).isFile())
54279
+ if (!lstatSync18(path).isFile())
54027
54280
  return false;
54028
54281
  const marker = JSON.parse(readFileSync14(path, "utf8"));
54029
54282
  return isSkillsOwnershipMarker(marker);
@@ -54248,7 +54501,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
54248
54501
  const action = dirExists ? "update" : "create";
54249
54502
  if (options.dryRun)
54250
54503
  return { action, path: skillMdPath };
54251
- const parentDir = dirname12(dir);
54504
+ const parentDir = dirname13(dir);
54252
54505
  mkdirSync7(parentDir, { recursive: true });
54253
54506
  const transactionDir = mkdtempSync(join26(parentDir, `.hasna-skills-write-${basename6(dir)}-`));
54254
54507
  const candidateDir = join26(transactionDir, "candidate");
@@ -54270,10 +54523,10 @@ function writeManagedSkillDir(dir, skillMd, options) {
54270
54523
  } else {
54271
54524
  mkdirSync7(candidateDir, { recursive: true });
54272
54525
  }
54273
- writeFileSync6(candidateSkillMdPath, skillMd.endsWith(`
54526
+ writeFileSync7(candidateSkillMdPath, skillMd.endsWith(`
54274
54527
  `) ? skillMd : `${skillMd}
54275
54528
  `);
54276
- writeFileSync6(candidateMarkerPath, `${JSON.stringify(marker, null, 2)}
54529
+ writeFileSync7(candidateMarkerPath, `${JSON.stringify(marker, null, 2)}
54277
54530
  `);
54278
54531
  if (dirExists) {
54279
54532
  originalMoved = true;
@@ -54356,7 +54609,7 @@ var init_skill_aliases = __esm(() => {
54356
54609
  });
54357
54610
 
54358
54611
  // src/lib/project-state.ts
54359
- import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync15, writeFileSync as writeFileSync7 } from "fs";
54612
+ import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
54360
54613
  import { join as join27 } from "path";
54361
54614
  function getProjectStateDir(targetDir = process.cwd()) {
54362
54615
  return join27(targetDir, SKILLS_PROJECT_DIR);
@@ -54392,7 +54645,7 @@ function saveProjectConfig(config, targetDir = process.cwd()) {
54392
54645
  const dir = getProjectStateDir(targetDir);
54393
54646
  mkdirSync8(dir, { recursive: true });
54394
54647
  const normalized = normalizeProjectConfig({ ...config, updatedAt: new Date().toISOString() });
54395
- writeFileSync7(getProjectConfigPath(targetDir), JSON.stringify(normalized, null, 2) + `
54648
+ writeFileSync8(getProjectConfigPath(targetDir), JSON.stringify(normalized, null, 2) + `
54396
54649
  `);
54397
54650
  }
54398
54651
  function pinProjectSkill(name, details = {}, targetDir = process.cwd()) {
@@ -55431,7 +55684,7 @@ var init_selection_resolver = __esm(() => {
55431
55684
  });
55432
55685
 
55433
55686
  // src/lib/plugin-projection.ts
55434
- import { createHash as createHash13 } from "crypto";
55687
+ import { createHash as createHash14 } from "crypto";
55435
55688
  import { posix } from "path";
55436
55689
  function pluginRefusal(message) {
55437
55690
  throw new SkillSelectionError("PLUGIN_ADMISSION_REFUSED", message);
@@ -55624,7 +55877,7 @@ function buildPluginProjection(entries) {
55624
55877
  files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
55625
55878
  return { manifest, payloads: manifest.payloads, files, witnesses: pluginFileWitnesses(files), originalTreeDigest, projectionTreeDigest: pluginTreeDigest(files), removed: removed.length ? pluginFileWitnesses(removed) : [] };
55626
55879
  }
55627
- var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash13("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
55880
+ var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash14("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
55628
55881
  var init_plugin_projection = __esm(() => {
55629
55882
  init_selection_cache();
55630
55883
  PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
@@ -55632,12 +55885,12 @@ var init_plugin_projection = __esm(() => {
55632
55885
  });
55633
55886
 
55634
55887
  // src/lib/plugin-projection-store.ts
55635
- import { createHash as createHash14, randomUUID as randomUUID6 } from "crypto";
55636
- import { constants as constants9, closeSync as closeSync9, fchmodSync, fstatSync as fstatSync9, fsyncSync as fsyncSync3, linkSync as linkSync3, lstatSync as lstatSync18, mkdirSync as mkdirSync9, openSync as openSync9, opendirSync as opendirSync4, readSync as readSync7, renameSync as renameSync5, rmdirSync as rmdirSync3, rmSync as rmSync4, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
55637
- import { dirname as dirname13, isAbsolute as isAbsolute12, join as join30, parse as parse5, resolve as resolve13 } from "path";
55888
+ import { createHash as createHash15, randomUUID as randomUUID6 } from "crypto";
55889
+ import { constants as constants10, closeSync as closeSync10, fchmodSync, fstatSync as fstatSync10, fsyncSync as fsyncSync4, linkSync as linkSync3, lstatSync as lstatSync19, mkdirSync as mkdirSync9, openSync as openSync10, opendirSync as opendirSync4, readSync as readSync8, renameSync as renameSync5, rmdirSync as rmdirSync3, rmSync as rmSync4, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
55890
+ import { dirname as dirname14, isAbsolute as isAbsolute12, join as join30, parse as parse5, resolve as resolve13 } from "path";
55638
55891
  function stat(path) {
55639
55892
  try {
55640
- return lstatSync18(path, { bigint: true });
55893
+ return lstatSync19(path, { bigint: true });
55641
55894
  } catch (error) {
55642
55895
  if (missing(error))
55643
55896
  return null;
@@ -55656,7 +55909,7 @@ function same3(left, right, identityOnly = false) {
55656
55909
  }
55657
55910
  function ancestors(path, create3 = false) {
55658
55911
  canonical5(path);
55659
- const result2 = [], parent = dirname13(path), filesystemRoot = parse5(parent).root;
55912
+ const result2 = [], parent = dirname14(path), filesystemRoot = parse5(parent).root;
55660
55913
  let current = filesystemRoot;
55661
55914
  for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
55662
55915
  if (segment)
@@ -55684,7 +55937,7 @@ function verifyAncestors(chain, identityOnly = true) {
55684
55937
  }
55685
55938
  function privateParent(path) {
55686
55939
  const chain = ancestors(path, true), parent = chain.at(-1);
55687
- pluginNeed(parent && parent.path === dirname13(path), "Plugin storage parent is unavailable");
55940
+ pluginNeed(parent && parent.path === dirname14(path), "Plugin storage parent is unavailable");
55688
55941
  owner(parent.stat);
55689
55942
  pluginNeed((parent.stat.mode & 0o7777n) === 0o700n, "Plugin storage parent must have mode 0700");
55690
55943
  return chain;
@@ -55713,19 +55966,19 @@ function readBytes(path, maximum, kind) {
55713
55966
  fileShape(before2, maximum, kind);
55714
55967
  let fd;
55715
55968
  try {
55716
- fd = openSync9(path, READ_FLAGS);
55717
- const opened = fstatSync9(fd, { bigint: true });
55969
+ fd = openSync10(path, READ_FLAGS);
55970
+ const opened = fstatSync10(fd, { bigint: true });
55718
55971
  same3(before2, opened);
55719
55972
  fileShape(opened, maximum, kind);
55720
55973
  const bytes = new Uint8Array(Number(opened.size));
55721
55974
  let offset = 0;
55722
55975
  while (offset < bytes.byteLength) {
55723
- const count = readSync7(fd, bytes, offset, bytes.byteLength - offset, null);
55976
+ const count = readSync8(fd, bytes, offset, bytes.byteLength - offset, null);
55724
55977
  pluginNeed(count > 0, "Plugin file changed while being read");
55725
55978
  offset += count;
55726
55979
  }
55727
- pluginNeed(readSync7(fd, new Uint8Array(1), 0, 1, null) === 0, "Plugin file grew while being read");
55728
- same3(opened, fstatSync9(fd, { bigint: true }));
55980
+ pluginNeed(readSync8(fd, new Uint8Array(1), 0, 1, null) === 0, "Plugin file grew while being read");
55981
+ same3(opened, fstatSync10(fd, { bigint: true }));
55729
55982
  same3(opened, stat(path));
55730
55983
  verifyAncestors(chain);
55731
55984
  return bytes;
@@ -55735,7 +55988,7 @@ function readBytes(path, maximum, kind) {
55735
55988
  return pluginRefusal("Cannot safely read plugin file");
55736
55989
  } finally {
55737
55990
  if (fd !== undefined)
55738
- closeSync9(fd);
55991
+ closeSync10(fd);
55739
55992
  }
55740
55993
  }
55741
55994
  function exactPaths(entries) {
@@ -55845,16 +56098,16 @@ function verifyPluginTree(root, witnesses) {
55845
56098
  function writeExclusive(path, bytes, mode) {
55846
56099
  let fd, created;
55847
56100
  try {
55848
- fd = openSync9(path, WRITE_FLAGS, mode);
56101
+ fd = openSync10(path, WRITE_FLAGS, mode);
55849
56102
  fchmodSync(fd, mode);
55850
- created = fstatSync9(fd, { bigint: true });
56103
+ created = fstatSync10(fd, { bigint: true });
55851
56104
  let offset = 0;
55852
56105
  while (offset < bytes.byteLength) {
55853
56106
  const count = writeSync2(fd, bytes, offset, bytes.byteLength - offset);
55854
56107
  pluginNeed(count > 0, "Plugin file write did not progress");
55855
56108
  offset += count;
55856
56109
  }
55857
- fsyncSync3(fd);
56110
+ fsyncSync4(fd);
55858
56111
  } catch (error) {
55859
56112
  if (created) {
55860
56113
  same3(created, stat(path), true);
@@ -55863,7 +56116,7 @@ function writeExclusive(path, bytes, mode) {
55863
56116
  throw error;
55864
56117
  } finally {
55865
56118
  if (fd !== undefined)
55866
- closeSync9(fd);
56119
+ closeSync10(fd);
55867
56120
  }
55868
56121
  }
55869
56122
  function materializePluginTree(root, entries) {
@@ -55966,20 +56219,20 @@ function pluginExecutableDigest(path) {
55966
56219
  fileShape(before2, maximum, "executable");
55967
56220
  let fd;
55968
56221
  try {
55969
- fd = openSync9(path, READ_FLAGS);
55970
- const opened = fstatSync9(fd, { bigint: true });
56222
+ fd = openSync10(path, READ_FLAGS);
56223
+ const opened = fstatSync10(fd, { bigint: true });
55971
56224
  same3(before2, opened);
55972
56225
  fileShape(opened, maximum, "executable");
55973
- const hash2 = createHash14("sha256"), buffer = new Uint8Array(64 * 1024);
56226
+ const hash2 = createHash15("sha256"), buffer = new Uint8Array(64 * 1024);
55974
56227
  let remaining = Number(opened.size);
55975
56228
  while (remaining > 0) {
55976
- const count = readSync7(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
56229
+ const count = readSync8(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
55977
56230
  pluginNeed(count > 0, "Plugin executable changed during hashing");
55978
56231
  hash2.update(buffer.subarray(0, count));
55979
56232
  remaining -= count;
55980
56233
  }
55981
- pluginNeed(readSync7(fd, buffer, 0, 1, null) === 0, "Plugin executable grew during hashing");
55982
- same3(opened, fstatSync9(fd, { bigint: true }));
56234
+ pluginNeed(readSync8(fd, buffer, 0, 1, null) === 0, "Plugin executable grew during hashing");
56235
+ same3(opened, fstatSync10(fd, { bigint: true }));
55983
56236
  same3(opened, stat(path));
55984
56237
  verifyAncestors(chain);
55985
56238
  return `sha256:${hash2.digest("hex")}`;
@@ -55989,14 +56242,14 @@ function pluginExecutableDigest(path) {
55989
56242
  return pluginRefusal("Cannot safely hash plugin executable");
55990
56243
  } finally {
55991
56244
  if (fd !== undefined)
55992
- closeSync9(fd);
56245
+ closeSync10(fd);
55993
56246
  }
55994
56247
  }
55995
56248
  var READ_FLAGS, WRITE_FLAGS, uid = () => typeof process.getuid === "function" ? BigInt(process.getuid()) : undefined, missing = (error) => Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
55996
56249
  var init_plugin_projection_store = __esm(() => {
55997
56250
  init_plugin_projection();
55998
- READ_FLAGS = constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK;
55999
- WRITE_FLAGS = constants9.O_WRONLY | constants9.O_CREAT | constants9.O_EXCL | constants9.O_NOFOLLOW | constants9.O_NONBLOCK;
56251
+ READ_FLAGS = constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK;
56252
+ WRITE_FLAGS = constants10.O_WRONLY | constants10.O_CREAT | constants10.O_EXCL | constants10.O_NOFOLLOW | constants10.O_NONBLOCK;
56000
56253
  });
56001
56254
 
56002
56255
  // src/lib/selected-manifest.ts
@@ -56405,8 +56658,8 @@ var init_plugin_admission = __esm(() => {
56405
56658
  });
56406
56659
 
56407
56660
  // src/lib/plugin-discovery.ts
56408
- import { closeSync as closeSync10, constants as constants10, fstatSync as fstatSync10, lstatSync as lstatSync19, openSync as openSync10, opendirSync as opendirSync5, readSync as readSync8 } from "fs";
56409
- import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute14, join as join32, resolve as resolve15 } from "path";
56661
+ import { closeSync as closeSync11, constants as constants11, fstatSync as fstatSync11, lstatSync as lstatSync20, openSync as openSync11, opendirSync as opendirSync5, readSync as readSync9 } from "fs";
56662
+ import { basename as basename7, dirname as dirname15, isAbsolute as isAbsolute14, join as join32, resolve as resolve15 } from "path";
56410
56663
  function validateManagedPluginWitnesses(value) {
56411
56664
  pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
56412
56665
  const seen = new Set;
@@ -56421,29 +56674,29 @@ function validateManagedPluginWitnesses(value) {
56421
56674
  function safe3(path) {
56422
56675
  pluginText(path);
56423
56676
  pluginNeed(isAbsolute14(path) && resolve15(path) === path, "Invalid plugin registry path");
56424
- for (let at2 = path;; at2 = dirname14(at2)) {
56425
- pluginNeed(!lstatSync19(at2, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
56426
- if (at2 === dirname14(at2))
56677
+ for (let at2 = path;; at2 = dirname15(at2)) {
56678
+ pluginNeed(!lstatSync20(at2, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
56679
+ if (at2 === dirname15(at2))
56427
56680
  break;
56428
56681
  }
56429
56682
  }
56430
56683
  function readRegistry(path) {
56431
56684
  safe3(path);
56432
- const initial2 = lstatSync19(path);
56685
+ const initial2 = lstatSync20(path);
56433
56686
  pluginNeed(initial2.isFile() && initial2.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
56434
- const fd = openSync10(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
56687
+ const fd = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
56435
56688
  try {
56436
- const opened = fstatSync10(fd);
56689
+ const opened = fstatSync11(fd);
56437
56690
  pluginNeed(opened.isFile() && opened.ino === initial2.ino && opened.dev === initial2.dev, "Plugin registry changed during open");
56438
56691
  const bytes = Buffer.alloc(1024 * 1024 + 1);
56439
56692
  let length = 0;
56440
56693
  while (length < bytes.length) {
56441
- const count = readSync8(fd, bytes, length, bytes.length - length, null);
56694
+ const count = readSync9(fd, bytes, length, bytes.length - length, null);
56442
56695
  if (!count)
56443
56696
  break;
56444
56697
  length += count;
56445
56698
  }
56446
- const after2 = fstatSync10(fd), current = lstatSync19(path);
56699
+ const after2 = fstatSync11(fd), current = lstatSync20(path);
56447
56700
  safe3(path);
56448
56701
  pluginNeed(length <= 1024 * 1024 && length === opened.size && after2.size === opened.size && after2.mtimeMs === opened.mtimeMs && after2.ctimeMs === opened.ctimeMs && current.dev === opened.dev && current.ino === opened.ino && current.mtimeMs === opened.mtimeMs && current.ctimeMs === opened.ctimeMs, "Plugin registry changed during read");
56449
56702
  let value;
@@ -56455,7 +56708,7 @@ function readRegistry(path) {
56455
56708
  pluginNeed(pluginObject(value) && value.version === 2 && pluginObject(value.plugins), "Unsupported native plugin registry schema");
56456
56709
  return { value, rawDigest: pluginHash(bytes.subarray(0, length)) };
56457
56710
  } finally {
56458
- closeSync10(fd);
56711
+ closeSync11(fd);
56459
56712
  }
56460
56713
  }
56461
56714
  function nativeVersionMatches(version, receipt) {
@@ -56464,7 +56717,7 @@ function nativeVersionMatches(version, receipt) {
56464
56717
  }
56465
56718
  function hashManagedPluginRegistry(path, managed) {
56466
56719
  validateManagedPluginWitnesses(managed);
56467
- const snapshot = readRegistry(path), plugins = snapshot.value.plugins;
56720
+ const snapshot2 = readRegistry(path), plugins = snapshot2.value.plugins;
56468
56721
  const seen = new Set, verified = new Set;
56469
56722
  let verifiedBytes = 0;
56470
56723
  for (const witness of managed) {
@@ -56473,7 +56726,7 @@ function hashManagedPluginRegistry(path, managed) {
56473
56726
  seen.add(target.pluginId);
56474
56727
  const rows = plugins[target.pluginId];
56475
56728
  pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
56476
- const [name, market] = target.pluginId.split("@"), cacheRoot = join32(dirname14(path), "cache", market, name);
56729
+ const [name, market] = target.pluginId.split("@"), cacheRoot = join32(dirname15(path), "cache", market, name);
56477
56730
  const scopes = new Set, approvals = new Map, currentFiles = new Map;
56478
56731
  plugins[target.pluginId] = rows.map((row) => {
56479
56732
  pluginNeed(pluginObject(row), "Invalid managed plugin registration");
@@ -56516,7 +56769,7 @@ function hashManagedPluginRegistry(path, managed) {
56516
56769
  return Object.fromEntries(Object.entries(row).filter(([key]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key)));
56517
56770
  });
56518
56771
  safe3(cacheRoot);
56519
- const before2 = lstatSync19(cacheRoot);
56772
+ const before2 = lstatSync20(cacheRoot);
56520
56773
  pluginNeed(before2.isDirectory(), "Invalid managed plugin cache root");
56521
56774
  const directory = opendirSync5(cacheRoot), names = [];
56522
56775
  try {
@@ -56539,12 +56792,12 @@ function hashManagedPluginRegistry(path, managed) {
56539
56792
  }
56540
56793
  for (const row of rows)
56541
56794
  pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
56542
- const after2 = lstatSync19(cacheRoot);
56795
+ const after2 = lstatSync20(cacheRoot);
56543
56796
  safe3(cacheRoot);
56544
56797
  pluginNeed(before2.dev === after2.dev && before2.ino === after2.ino && before2.mtimeMs === after2.mtimeMs && before2.ctimeMs === after2.ctimeMs, "Managed cache version membership changed during verification");
56545
56798
  }
56546
- pluginNeed(readRegistry(path).rawDigest === snapshot.rawDigest, "Native plugin registry changed during content verification");
56547
- return pluginHash(JSON.stringify(snapshot.value));
56799
+ pluginNeed(readRegistry(path).rawDigest === snapshot2.rawDigest, "Native plugin registry changed during content verification");
56800
+ return pluginHash(JSON.stringify(snapshot2.value));
56548
56801
  }
56549
56802
  var init_plugin_discovery = __esm(() => {
56550
56803
  init_plugin_admission();
@@ -56553,50 +56806,50 @@ var init_plugin_discovery = __esm(() => {
56553
56806
  });
56554
56807
 
56555
56808
  // src/lib/claude-marketplace-registry.ts
56556
- import { createHash as createHash15 } from "crypto";
56557
- import { closeSync as closeSync11, constants as constants11, fstatSync as fstatSync11, lstatSync as lstatSync20, openSync as openSync11, readSync as readSync9 } from "fs";
56558
- import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve16 } from "path";
56559
- function need5(value, reason) {
56809
+ import { createHash as createHash16 } from "crypto";
56810
+ import { closeSync as closeSync12, constants as constants12, fstatSync as fstatSync12, lstatSync as lstatSync21, openSync as openSync12, readSync as readSync10 } from "fs";
56811
+ import { basename as basename8, dirname as dirname16, isAbsolute as isAbsolute15, resolve as resolve16 } from "path";
56812
+ function need6(value, reason) {
56560
56813
  if (!value)
56561
56814
  throw new Error(`Claude marketplace registry ${reason}`);
56562
56815
  }
56563
56816
  function absolutePath3(value) {
56564
- need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve16(value) === value, "requires a normalized absolute path");
56817
+ need6(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve16(value) === value, "requires a normalized absolute path");
56565
56818
  }
56566
56819
  function parents2(path) {
56567
56820
  const result2 = [];
56568
- for (let at2 = dirname15(path);; at2 = dirname15(at2)) {
56569
- const stat2 = lstatSync20(at2, { bigint: true });
56570
- need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
56821
+ for (let at2 = dirname16(path);; at2 = dirname16(at2)) {
56822
+ const stat2 = lstatSync21(at2, { bigint: true });
56823
+ need6(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
56571
56824
  result2.push([at2, stat2]);
56572
- if (at2 === dirname15(at2))
56825
+ if (at2 === dirname16(at2))
56573
56826
  return result2;
56574
56827
  }
56575
56828
  }
56576
56829
  function readRegistry2(path, budget) {
56577
56830
  absolutePath3(path);
56578
- need5(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
56579
- need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
56580
- const ancestors2 = parents2(path), initial2 = lstatSync20(path, { bigint: true });
56581
- need5(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
56582
- need5(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
56583
- const fd = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
56831
+ need6(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
56832
+ need6(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
56833
+ const ancestors2 = parents2(path), initial2 = lstatSync21(path, { bigint: true });
56834
+ need6(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
56835
+ need6(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
56836
+ const fd = openSync12(path, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
56584
56837
  try {
56585
- const opened = fstatSync11(fd, { bigint: true });
56586
- need5(opened.isFile() && sameFile2(initial2, opened), "changed during open");
56838
+ const opened = fstatSync12(fd, { bigint: true });
56839
+ need6(opened.isFile() && sameFile2(initial2, opened), "changed during open");
56587
56840
  const bytes = Buffer.alloc(Number(opened.size) + 1);
56588
56841
  let length = 0;
56589
56842
  while (length < bytes.length) {
56590
- const count = readSync9(fd, bytes, length, bytes.length - length, null);
56843
+ const count = readSync10(fd, bytes, length, bytes.length - length, null);
56591
56844
  if (!count)
56592
56845
  break;
56593
56846
  length += count;
56594
56847
  }
56595
- const after2 = fstatSync11(fd, { bigint: true }), current = lstatSync20(path, { bigint: true });
56596
- need5(current.isFile() && sameFile2(opened, after2) && sameFile2(after2, current) && BigInt(length) === opened.size, "changed during read");
56848
+ const after2 = fstatSync12(fd, { bigint: true }), current = lstatSync21(path, { bigint: true });
56849
+ need6(current.isFile() && sameFile2(opened, after2) && sameFile2(after2, current) && BigInt(length) === opened.size, "changed during read");
56597
56850
  for (const [ancestor, before2] of ancestors2) {
56598
- const now3 = lstatSync20(ancestor, { bigint: true });
56599
- need5(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
56851
+ const now3 = lstatSync21(ancestor, { bigint: true });
56852
+ need6(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
56600
56853
  }
56601
56854
  budget.remaining -= length;
56602
56855
  try {
@@ -56605,7 +56858,7 @@ function readRegistry2(path, budget) {
56605
56858
  throw new Error("Claude marketplace registry is not strict UTF-8");
56606
56859
  }
56607
56860
  } finally {
56608
- closeSync11(fd);
56861
+ closeSync12(fd);
56609
56862
  }
56610
56863
  }
56611
56864
  function parse6(text2) {
@@ -56616,7 +56869,7 @@ function parse6(text2) {
56616
56869
  at2++;
56617
56870
  };
56618
56871
  function string() {
56619
- need5(text2[at2] === '"', "contains invalid JSON");
56872
+ need6(text2[at2] === '"', "contains invalid JSON");
56620
56873
  const start = at2++;
56621
56874
  while (at2 < text2.length) {
56622
56875
  const character = text2[at2++];
@@ -56627,7 +56880,7 @@ function parse6(text2) {
56627
56880
  } catch {
56628
56881
  throw new Error("Claude marketplace registry contains invalid JSON string");
56629
56882
  }
56630
- need5(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
56883
+ need6(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
56631
56884
  return value2;
56632
56885
  }
56633
56886
  if (character === "\\")
@@ -56636,7 +56889,7 @@ function parse6(text2) {
56636
56889
  throw new Error("Claude marketplace registry contains an unterminated JSON string");
56637
56890
  }
56638
56891
  function value(depth) {
56639
- need5(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
56892
+ need6(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
56640
56893
  space();
56641
56894
  const character = text2[at2];
56642
56895
  if (character === '"')
@@ -56650,17 +56903,17 @@ function parse6(text2) {
56650
56903
  if (object5) {
56651
56904
  space();
56652
56905
  const key = string();
56653
- need5(!keys2.has(key), "contains a duplicate JSON key");
56906
+ need6(!keys2.has(key), "contains a duplicate JSON key");
56654
56907
  keys2.add(key);
56655
56908
  space();
56656
- need5(text2[at2++] === ":", "contains invalid JSON");
56909
+ need6(text2[at2++] === ":", "contains invalid JSON");
56657
56910
  entries.push([key, value(depth + 1)]);
56658
56911
  } else
56659
56912
  items.push(value(depth + 1));
56660
56913
  space();
56661
56914
  if (text2[at2] === end)
56662
56915
  break;
56663
- need5(text2[at2++] === ",", "contains invalid JSON");
56916
+ need6(text2[at2++] === ",", "contains invalid JSON");
56664
56917
  }
56665
56918
  at2++;
56666
56919
  return object5 ? { kind: "object", entries } : { kind: "array", items };
@@ -56672,21 +56925,21 @@ function parse6(text2) {
56672
56925
  }
56673
56926
  numberPattern.lastIndex = at2;
56674
56927
  const number = numberPattern.exec(text2);
56675
- need5(number, "contains invalid JSON");
56928
+ need6(number, "contains invalid JSON");
56676
56929
  at2 += number[0].length;
56677
56930
  return { kind: "number", value: number[0] };
56678
56931
  }
56679
56932
  const root2 = value(0);
56680
56933
  space();
56681
- need5(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
56682
- need5(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
56934
+ need6(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
56935
+ need6(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
56683
56936
  return root2;
56684
56937
  }
56685
56938
  function exactKeys(value, keys2) {
56686
56939
  return value?.kind === "object" && value.entries.length === keys2.length && value.entries.every(([key]) => keys2.includes(key));
56687
56940
  }
56688
56941
  function textField(value) {
56689
- need5(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
56942
+ need6(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
56690
56943
  return value.value;
56691
56944
  }
56692
56945
  function normalizeRow(row, version = 1) {
@@ -56694,7 +56947,7 @@ function normalizeRow(row, version = 1) {
56694
56947
  if (version !== 2 || !exactKeys(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
56695
56948
  return;
56696
56949
  const autoUpdate = field(row, "autoUpdate");
56697
- need5(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
56950
+ need6(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
56698
56951
  }
56699
56952
  const source = field(row, "source");
56700
56953
  if (source?.kind !== "object")
@@ -56710,23 +56963,23 @@ function normalizeRow(row, version = 1) {
56710
56963
  absolutePath3(sourceLocation);
56711
56964
  absolutePath3(textField(field(row, "installLocation")));
56712
56965
  const updated = textField(field(row, "lastUpdated"));
56713
- need5(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
56966
+ need6(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
56714
56967
  const millis = Date.parse(updated);
56715
- need5(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
56968
+ need6(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
56716
56969
  row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
56717
56970
  }
56718
56971
  function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
56719
56972
  const value = parse6(readRegistry2(path, budget));
56720
56973
  for (const [, row] of value.entries)
56721
56974
  normalizeRow(row);
56722
- const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
56975
+ const sha2562 = createHash16("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
56723
56976
  return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
56724
56977
  }
56725
56978
  function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
56726
56979
  const value = parse6(readRegistry2(path, budget));
56727
56980
  for (const [, row] of value.entries)
56728
56981
  normalizeRow(row, 2);
56729
- const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
56982
+ const sha2562 = createHash16("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
56730
56983
  return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
56731
56984
  }
56732
56985
  var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, field = (object5, key) => object5.entries.find(([name]) => name === key)?.[1];
@@ -56734,65 +56987,6 @@ var init_claude_marketplace_registry = __esm(() => {
56734
56987
  CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
56735
56988
  });
56736
56989
 
56737
- // src/lib/codex-hook-trust-files.ts
56738
- import { closeSync as closeSync12, constants as constants12, fstatSync as fstatSync12, fsyncSync as fsyncSync4, lstatSync as lstatSync21, openSync as openSync12, readSync as readSync10, writeFileSync as writeFileSync8 } from "fs";
56739
- import { createHash as createHash16 } from "crypto";
56740
- import { dirname as dirname16 } from "path";
56741
- function need6(value, code) {
56742
- if (!value)
56743
- throw new Error(`CODEX_HOOK_TRUST_${code}`);
56744
- }
56745
- function safeParents(file) {
56746
- for (let p = dirname16(file);; p = dirname16(p)) {
56747
- const s = lstatSync21(p);
56748
- need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
56749
- need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
56750
- if (dirname16(p) === p)
56751
- break;
56752
- }
56753
- }
56754
- function snapshot(file, privateFile = false, options = {}) {
56755
- const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
56756
- safeParents(file);
56757
- const initial2 = lstatSync21(file, { bigint: true });
56758
- need6(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
56759
- need6(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
56760
- const fd = openSync12(file, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
56761
- try {
56762
- const before2 = fstatSync12(fd, { bigint: true });
56763
- need6(sameStat(initial2, before2), "INPUT_CHANGED");
56764
- const bytes = Buffer.alloc(Number(before2.size) + 1);
56765
- let length = 0;
56766
- while (length < bytes.length) {
56767
- const n2 = readSync10(fd, bytes, length, bytes.length - length, null);
56768
- if (!n2)
56769
- break;
56770
- length += n2;
56771
- }
56772
- need6(length === Number(before2.size) && sameStat(before2, fstatSync12(fd, { bigint: true })) && sameStat(before2, lstatSync21(file, { bigint: true })), "INPUT_CHANGED");
56773
- const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
56774
- return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash16("sha256").update(content).digest("hex") };
56775
- } finally {
56776
- closeSync12(fd);
56777
- }
56778
- }
56779
- function unchanged2(before2) {
56780
- const after2 = snapshot(before2.file, before2.privateFile, before2.readOnlyPackage ? { readOnlyPackage: true } : {});
56781
- need6(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
56782
- }
56783
- function save(file, content) {
56784
- safeParents(file);
56785
- const fd = openSync12(file, constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
56786
- try {
56787
- writeFileSync8(fd, content);
56788
- fsyncSync4(fd);
56789
- } finally {
56790
- closeSync12(fd);
56791
- }
56792
- }
56793
- var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
56794
- var init_codex_hook_trust_files = () => {};
56795
-
56796
56990
  // src/lib/codex-hook-trust-layout.ts
56797
56991
  import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
56798
56992
  function codexTrustTextWitness(text2, keys2, canonicalize = true) {
@@ -56931,53 +57125,53 @@ var init_codex_hook_trust_layout = () => {};
56931
57125
  import { isAbsolute as isAbsolute16 } from "path";
56932
57126
  import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
56933
57127
  function exactKeys2(value, keys2) {
56934
- need6(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual7(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
57128
+ need5(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual7(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56935
57129
  }
56936
57130
  function readReviewedAdditionTrustStates(proof, before2, current, journalHooks) {
56937
57131
  const captured = proofs.get(proof);
56938
- need6(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual7(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
57132
+ need5(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual7(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
56939
57133
  captured.recheck();
56940
57134
  unchanged2(before2);
56941
57135
  unchanged2(current);
56942
57136
  return captured.states;
56943
57137
  }
56944
57138
  function reviewNativeHookAdditions(options) {
56945
- need6(isAbsolute16(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
57139
+ need5(isAbsolute16(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
56946
57140
  const reviewFile = snapshot(options.path, true), review = JSON.parse(reviewFile.text);
56947
57141
  exactKeys2(review, ["version", "kind", "reason", "producerEvidence", "journalIntentSha256", "policySha256", "configCurrentSha256", "hooksCurrentSha256", "producerBefore", "additions"]);
56948
- need6((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
57142
+ need5((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56949
57143
  for (const [name, expected] of [["journalIntentSha256", options.intent.sha256], ["policySha256", options.policy.sha256], ["configCurrentSha256", options.configCurrent.sha256], ["hooksCurrentSha256", options.hooksCurrent.sha256]])
56950
- need6(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
57144
+ need5(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
56951
57145
  exactKeys2(review.producerBefore, ["configPath", "configSha256", "hooksPath", "hooksSha256"]);
56952
57146
  const before2 = review.producerBefore;
56953
- need6(isAbsolute16(before2.configPath) && isAbsolute16(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
57147
+ need5(isAbsolute16(before2.configPath) && isAbsolute16(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56954
57148
  const producerConfig = snapshot(before2.configPath, true), producerHooks = snapshot(before2.hooksPath, true);
56955
- need6(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
57149
+ need5(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56956
57150
  const original = structure(options.configBefore.text), producer = structure(producerConfig.text), expectedProducer = structuredClone(original), originalKeys = options.journalHooks.map((hook) => hook.key);
56957
57151
  expectedProducer.hooks ??= {};
56958
57152
  expectedProducer.hooks.state ??= {};
56959
57153
  for (const hook of options.journalHooks)
56960
57154
  expectedProducer.hooks.state[hook.key] = { ...expectedProducer.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
56961
- need6(isDeepStrictEqual7(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56962
- need6(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
57155
+ need5(isDeepStrictEqual7(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
57156
+ need5(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56963
57157
  const expectedHooks = JSON.parse(options.hooksBefore.text), currentHooks = JSON.parse(options.hooksCurrent.text), expectedConfig = structuredClone(producer);
56964
- need6(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
57158
+ need5(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56965
57159
  const added = [], states = [], seen = new Set, commands = new Set(options.recordedNativeHooks.map((hook) => hook.command));
56966
57160
  for (const addition of review.additions) {
56967
57161
  exactKeys2(addition, review.version === 1 ? ["event", "nativeHook"] : ["event", "nativeHook", "trustState"]);
56968
- need6(Object.hasOwn(review.version === 1 ? events : matchedEvents, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
57162
+ need5(Object.hasOwn(review.version === 1 ? events : matchedEvents, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
56969
57163
  const { event, nativeHook: hook } = addition;
56970
57164
  exactKeys2(hook, nativeKeys);
56971
57165
  const groups = expectedHooks.hooks[event] ?? [];
56972
- need6(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
57166
+ need5(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
56973
57167
  const key = `${options.nativeHooksPath}:${matchedEvents[event][1]}:${groups.length}:0`;
56974
- need6(hook.key === key && !seen.has(key) && !options.recordedNativeHooks.some((originalHook) => originalHook.key === key) && !Object.hasOwn(expectedConfig.hooks.state, key), "RECONCILE_ADDITIONS_IDENTITY");
56975
- need6(hook.eventName === matchedEvents[event][0] && hook.handlerType === "command" && (review.version === 2 ? v2Command(hook.command) : text2(hook.command, 16384)) && !commands.has(hook.command) && Number.isInteger(hook.timeoutSec) && hook.timeoutSec > 0 && hook.timeoutSec <= 60 && (event === "PreToolUse" ? text2(hook.matcher) : hook.matcher === null) && hook.async === false && hook.statusMessage === null && hook.additionalContextLimit === null && hook.sourcePath === options.nativeHooksPath && hook.source === "user" && hook.pluginId === null && hook.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash) && hook.enabled === true && hook.trustStatus === "trusted", "RECONCILE_ADDITIONS_IDENTITY");
57168
+ need5(hook.key === key && !seen.has(key) && !options.recordedNativeHooks.some((originalHook) => originalHook.key === key) && !Object.hasOwn(expectedConfig.hooks.state, key), "RECONCILE_ADDITIONS_IDENTITY");
57169
+ need5(hook.eventName === matchedEvents[event][0] && hook.handlerType === "command" && (review.version === 2 ? v2Command(hook.command) : text2(hook.command, 16384)) && !commands.has(hook.command) && Number.isInteger(hook.timeoutSec) && hook.timeoutSec > 0 && hook.timeoutSec <= 60 && (event === "PreToolUse" ? text2(hook.matcher) : hook.matcher === null) && hook.async === false && hook.statusMessage === null && hook.additionalContextLimit === null && hook.sourcePath === options.nativeHooksPath && hook.source === "user" && hook.pluginId === null && hook.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash) && hook.enabled === true && hook.trustStatus === "trusted", "RECONCILE_ADDITIONS_IDENTITY");
56976
57170
  let trustState = { enabled: true, trusted_hash: hook.currentHash };
56977
57171
  if (review.version === 2) {
56978
57172
  const state = addition.trustState;
56979
57173
  exactKeys2(state, state && Object.hasOwn(state, "enabled") ? ["enabled", "trusted_hash"] : ["trusted_hash"]);
56980
- need6(state.trusted_hash === hook.currentHash && (!Object.hasOwn(state, "enabled") || state.enabled === true), "RECONCILE_ADDITIONS_TRUST_STATE");
57174
+ need5(state.trusted_hash === hook.currentHash && (!Object.hasOwn(state, "enabled") || state.enabled === true), "RECONCILE_ADDITIONS_TRUST_STATE");
56981
57175
  trustState = { ...state };
56982
57176
  }
56983
57177
  seen.add(key);
@@ -56987,9 +57181,9 @@ function reviewNativeHookAdditions(options) {
56987
57181
  expectedHooks.hooks[event] = [...groups, { ...event === "PreToolUse" ? { matcher: hook.matcher } : {}, hooks: [{ type: "command", command: hook.command, timeout: hook.timeoutSec }] }];
56988
57182
  expectedConfig.hooks.state[key] = trustState;
56989
57183
  }
56990
- need6(isDeepStrictEqual7(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
57184
+ need5(isDeepStrictEqual7(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56991
57185
  const keys2 = added.map((hook) => hook.key);
56992
- need6(isDeepStrictEqual7(expectedConfig, structure(options.configCurrent.text)) && codexTrustReconcileWitness(producerConfig.text, keys2) === codexTrustReconcileWitness(options.configCurrent.text, keys2) && codexTrustUnmanagedSemantic(producerConfig.text, keys2) === codexTrustUnmanagedSemantic(options.configCurrent.text, keys2), "RECONCILE_ADDITIONS_CONFIG");
57186
+ need5(isDeepStrictEqual7(expectedConfig, structure(options.configCurrent.text)) && codexTrustReconcileWitness(producerConfig.text, keys2) === codexTrustReconcileWitness(options.configCurrent.text, keys2) && codexTrustUnmanagedSemantic(producerConfig.text, keys2) === codexTrustUnmanagedSemantic(options.configCurrent.text, keys2), "RECONCILE_ADDITIONS_CONFIG");
56993
57187
  const inputs = [reviewFile, producerConfig, producerHooks, options.intent, options.policy, options.configBefore, options.configCurrent, options.hooksBefore, options.hooksCurrent];
56994
57188
  const recheck = () => {
56995
57189
  for (const input of inputs)
@@ -57023,16 +57217,16 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
57023
57217
  const raw = binding.sources.filter((source) => source.path === current.file && source.hashMode === "bytes");
57024
57218
  if (!raw.some((source) => source.sha256 !== current.sha256))
57025
57219
  return;
57026
- need6(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
57027
- need6(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
57220
+ need5(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
57221
+ need5(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
57028
57222
  const typed = binding.sources.filter((source) => source.path === current.file && source.format === "toml");
57029
- need6(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual8(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
57223
+ need5(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual8(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
57030
57224
  const original = structure2(before2.text), actual = structure2(current.text);
57031
57225
  const project = (value) => Object.fromEntries(fields.map((field2) => [field2, value[field2] ?? null]));
57032
57226
  const projection = sha4(JSON.stringify(project(original)));
57033
- need6(typed[0].sha256 === projection && sha4(JSON.stringify(project(actual))) === projection && isDeepStrictEqual8(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
57227
+ need5(typed[0].sha256 === projection && sha4(JSON.stringify(project(actual))) === projection && isDeepStrictEqual8(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
57034
57228
  const keys2 = [...journalHooks.map((hook) => hook.key), ...additionStates.map((hook) => hook.key)];
57035
- need6(journalHooks.length > 0 && keys2.length <= 100 && new Set(keys2).size === keys2.length && journalHooks.every((hook) => typeof hook.key === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash)), "RECONCILE_DISCOVERY_TRUST_WITNESS");
57229
+ need5(journalHooks.length > 0 && keys2.length <= 100 && new Set(keys2).size === keys2.length && journalHooks.every((hook) => typeof hook.key === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash)), "RECONCILE_DISCOVERY_TRUST_WITNESS");
57036
57230
  const expected = structuredClone(original);
57037
57231
  expected.hooks ??= {};
57038
57232
  expected.hooks.state ??= {};
@@ -57040,7 +57234,7 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
57040
57234
  expected.hooks.state[hook.key] = { ...expected.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
57041
57235
  for (const { key, state } of additionStates)
57042
57236
  expected.hooks.state[key] = { ...state };
57043
- need6(isDeepStrictEqual8(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
57237
+ need5(isDeepStrictEqual8(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
57044
57238
  unchanged2(before2);
57045
57239
  unchanged2(current);
57046
57240
  const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha4(JSON.stringify(binding)), typedProjectionSha256: projection });
@@ -57049,7 +57243,7 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
57049
57243
  }
57050
57244
  function assertCodexHookDiscoveryRecovery(binding, witness) {
57051
57245
  const proof = proofs2.get(witness);
57052
- need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha4(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
57246
+ need5(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha4(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
57053
57247
  unchanged2(proof.before);
57054
57248
  unchanged2(proof.current);
57055
57249
  proof.recheckAdditions();
@@ -57058,7 +57252,7 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
57058
57252
  if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
57059
57253
  return false;
57060
57254
  assertCodexHookDiscoveryRecovery(binding, witness);
57061
- need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
57255
+ need5(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
57062
57256
  return true;
57063
57257
  }
57064
57258
  var sha4 = (text3) => createHash17("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
@@ -112810,40 +113004,40 @@ import { realpathSync as realpathSync17 } from "fs";
112810
113004
  import { dirname as dirname33, isAbsolute as isAbsolute27, join as join60 } from "path";
112811
113005
  import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
112812
113006
  function inspectRecordedSkillsCli(command, expected) {
112813
- need6(isAbsolute27(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
113007
+ need5(isAbsolute27(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
112814
113008
  const resolved = realpathSync17(command);
112815
113009
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
112816
113010
  const manifest = snapshot(join60(dirname33(dirname33(resolved)), "package.json"), false, { readOnlyPackage: true });
112817
113011
  const pkg = JSON.parse(manifest.text);
112818
- need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join60(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
112819
- need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
113012
+ need5(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join60(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
113013
+ need5((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
112820
113014
  const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
112821
- need6(isDeepStrictEqual13(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
113015
+ need5(isDeepStrictEqual13(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
112822
113016
  return { receipt, recheck() {
112823
- need6(realpathSync17(command) === resolved, "SKILLS_COMMAND_CHANGED");
113017
+ need5(realpathSync17(command) === resolved, "SKILLS_COMMAND_CHANGED");
112824
113018
  unchanged2(cli);
112825
113019
  unchanged2(manifest);
112826
113020
  } };
112827
113021
  }
112828
113022
  function bindSkillsCli(command, reviewed) {
112829
113023
  const normal = Bun.which("skills", { PATH: process.env.PATH });
112830
- need6(normal, "SKILLS_COMMAND_UNAVAILABLE");
113024
+ need5(normal, "SKILLS_COMMAND_UNAVAILABLE");
112831
113025
  const resolved = realpathSync17(normal);
112832
113026
  const bound = isAbsolute27(command) ? command : command === "skills" ? normal : undefined;
112833
- need6(bound && realpathSync17(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
113027
+ need5(bound && realpathSync17(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
112834
113028
  const entrypoint = reviewed?.path ?? process.argv[1];
112835
- need6(entrypoint && realpathSync17(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
113029
+ need5(entrypoint && realpathSync17(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
112836
113030
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
112837
113031
  const manifest = snapshot(join60(dirname33(dirname33(resolved)), "package.json"), false, { readOnlyPackage: true });
112838
113032
  const pkg = JSON.parse(manifest.text);
112839
- need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join60(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
113033
+ need5(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join60(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
112840
113034
  if (reviewed)
112841
- need6(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
112842
- need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
113035
+ need5(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
113036
+ need5((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
112843
113037
  return {
112844
113038
  receipt: { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 },
112845
113039
  recheck() {
112846
- need6(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync17(normal) === resolved && realpathSync17(bound) === resolved && realpathSync17(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
113040
+ need5(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync17(normal) === resolved && realpathSync17(bound) === resolved && realpathSync17(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
112847
113041
  unchanged2(cli);
112848
113042
  unchanged2(manifest);
112849
113043
  }
@@ -112856,17 +113050,17 @@ var init_codex_hook_trust_identity = __esm(() => {
112856
113050
  // src/lib/codex-hook-policy-recovery.ts
112857
113051
  import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
112858
113052
  function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
112859
- need6(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
112860
- need6(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
113053
+ need5(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
113054
+ need5(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
112861
113055
  const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
112862
113056
  const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
112863
- need6(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
113057
+ need5(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
112864
113058
  const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual14(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
112865
- need6(changes.length > 0, "RECONCILE_POLICY_CHANGED");
113059
+ need5(changes.length > 0, "RECONCILE_POLICY_CHANGED");
112866
113060
  const compared = structuredClone(current);
112867
113061
  compared.bridge.discovery.claude.roots = oldDiscovery.roots;
112868
113062
  compared.bridge.discovery.claude.sources = oldDiscovery.sources;
112869
- need6(isDeepStrictEqual14(before2, compared), "RECONCILE_POLICY_CHANGED");
113063
+ need5(isDeepStrictEqual14(before2, compared), "RECONCILE_POLICY_CHANGED");
112870
113064
  verifyAgentDiscovery(newDiscovery);
112871
113065
  return { reason: options.reason, changes };
112872
113066
  }
@@ -112884,15 +113078,15 @@ import { dirname as dirname34, isAbsolute as isAbsolute28, join as join61, resol
112884
113078
  import { homedir as homedir12 } from "os";
112885
113079
  import { isDeepStrictEqual as isDeepStrictEqual15 } from "util";
112886
113080
  function verifyReleaseArtifact(proof, skillsCli) {
112887
- need6(isAbsolute28(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
113081
+ need5(isAbsolute28(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
112888
113082
  const tarPath = realpathSync18(proof.packageTarPath);
112889
- need6(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
113083
+ need5(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
112890
113084
  const tarBytes = readFileSync40(tarPath);
112891
- need6(tarBytes.byteLength === proof.packageTarBytes && createHash31("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
113085
+ need5(tarBytes.byteLength === proof.packageTarBytes && createHash31("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
112892
113086
  const packageRoot = dirname34(dirname34(realpathSync18(skillsCli.receipt.path)));
112893
113087
  const manifest = readFileSync40(join61(packageRoot, "package.json"));
112894
- need6(createHash31("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
112895
- need6(createHash31("sha256").update(readFileSync40(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
113088
+ need5(createHash31("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
113089
+ need5(createHash31("sha256").update(readFileSync40(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
112896
113090
  const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync40(skillsCli.receipt.path)]];
112897
113091
  for (const [member, expected] of members2) {
112898
113092
  let actual;
@@ -112901,7 +113095,7 @@ function verifyReleaseArtifact(proof, skillsCli) {
112901
113095
  } catch {
112902
113096
  throw new Error("RECONCILE_RELEASE_ARTIFACT_MEMBER_MISSING");
112903
113097
  }
112904
- need6(Buffer.compare(actual, expected) === 0, "RECONCILE_RELEASE_ARTIFACT_MEMBER_CHANGED");
113098
+ need5(Buffer.compare(actual, expected) === 0, "RECONCILE_RELEASE_ARTIFACT_MEMBER_CHANGED");
112905
113099
  }
112906
113100
  }
112907
113101
  async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc) {
@@ -112909,48 +113103,48 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
112909
113103
  try {
112910
113104
  const home = resolve26(options.home ?? homedir12()), dataDir3 = resolve26(options.dataDir ?? getDataDirReadOnly());
112911
113105
  const parent = resolve26(join61(dataDir3, "native-hook-trust")), journal = resolve26(options.journal);
112912
- need6(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
113106
+ need5(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
112913
113107
  const dir = lstatSync32(journal, { throwIfNoEntry: false });
112914
- need6(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
112915
- need6(!lstatSync32(join61(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
112916
- need6(lstatSync32(join61(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
113108
+ need5(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
113109
+ need5(!lstatSync32(join61(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
113110
+ need5(lstatSync32(join61(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
112917
113111
  const stoppedFile = snapshot(join61(journal, "stopped.json"), true);
112918
113112
  const intentFile = snapshot(join61(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
112919
113113
  const configBefore = snapshot(join61(journal, "config.before.toml"), true), hooksBefore = snapshot(join61(journal, "hooks.before.json"), true), policyBefore = snapshot(join61(journal, "policy.before.json"), true);
112920
113114
  const legacyIntent = intent.home === undefined && intent.configSha256 === undefined && intent.configVersion === undefined && intent.declarations === undefined && intent.admitted === undefined && intent.nativeHooks === undefined;
112921
- need6(intent.version === 1 && /^[a-f0-9]{64}$/.test(intent.planDigest) && typeof intent.configPath === "string" && /^[a-f0-9]{64}$/.test(intent.policySha256) && /^[a-f0-9]{64}$/.test(intent.hooksSha256) && Array.isArray(intent.hooks) && intent.hooks.length > 0 && intent.hooks.length <= 100 && (legacyIntent || typeof intent.home === "string" && intent.home === home && /^[a-f0-9]{64}$/.test(intent.configSha256) && typeof intent.configVersion === "string" && Array.isArray(intent.declarations) && Array.isArray(intent.admitted) && Array.isArray(intent.nativeHooks)), "RECONCILE_INTENT_INVALID");
113115
+ need5(intent.version === 1 && /^[a-f0-9]{64}$/.test(intent.planDigest) && typeof intent.configPath === "string" && /^[a-f0-9]{64}$/.test(intent.policySha256) && /^[a-f0-9]{64}$/.test(intent.hooksSha256) && Array.isArray(intent.hooks) && intent.hooks.length > 0 && intent.hooks.length <= 100 && (legacyIntent || typeof intent.home === "string" && intent.home === home && /^[a-f0-9]{64}$/.test(intent.configSha256) && typeof intent.configVersion === "string" && Array.isArray(intent.declarations) && Array.isArray(intent.admitted) && Array.isArray(intent.nativeHooks)), "RECONCILE_INTENT_INVALID");
112922
113116
  const declarations = intent.declarations ?? intent.hooks.map((hook) => ({ event: hook.event, key: `${join61(home, ".codex/hooks.json")}${hook.key.slice(hook.key.indexOf(".codex/hooks.json") + ".codex/hooks.json".length)}`, command: hook.command }));
112923
113117
  const admitted = intent.admitted ?? intent.hooks;
112924
113118
  const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
112925
113119
  const digestInput = { version: 1, home: intent.home ?? home, configPath: intent.configPath, ...intent.nativeConfigPath !== undefined ? { nativeConfigPath: intent.nativeConfigPath } : {}, configSha256, configVersion, policySha256: intent.policySha256, hooksSha256: intent.hooksSha256, skillsCli: intent.skillsCli, nativeVersion: intent.nativeVersion, declarations, admitted };
112926
- need6(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
112927
- need6(isDeepStrictEqual15(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
112928
- need6(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
113120
+ need5(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
113121
+ need5(isDeepStrictEqual15(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
113122
+ need5(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
112929
113123
  const policyCurrent = snapshot(join61(dataDir3, "agent-policy.json"), true);
112930
113124
  const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
112931
113125
  const recovery = claudeRecovery ?? additionsRecovery;
112932
- need6(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
112933
- need6(!claudeRecovery || !additionsRecovery || claudeRecovery.reviewedPlanDigest === additionsRecovery.reviewedPlanDigest, "RECONCILE_RECOVERY_MODE_CONFLICT");
112934
- need6(recovery?.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(recovery.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
113126
+ need5(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
113127
+ need5(!claudeRecovery || !additionsRecovery || claudeRecovery.reviewedPlanDigest === additionsRecovery.reviewedPlanDigest, "RECONCILE_RECOVERY_MODE_CONFLICT");
113128
+ need5(recovery?.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(recovery.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
112935
113129
  const policyChange = claudeRecovery ? reviewedClaudeDiscoveryChange(policyBefore.text, policyCurrent.text, claudeRecovery) : undefined;
112936
113130
  let supersededBinding = false;
112937
113131
  if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
112938
- need6(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
113132
+ need5(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
112939
113133
  const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
112940
- need6(isDeepStrictEqual15(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
113134
+ need5(isDeepStrictEqual15(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
112941
113135
  supersededBinding = true;
112942
113136
  }
112943
113137
  if (supersededBinding || recovery) {
112944
- need6(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
113138
+ need5(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
112945
113139
  const proof = options.releaseProof;
112946
- need6(!!proof && isAbsolute28(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
113140
+ need5(!!proof && isAbsolute28(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
112947
113141
  }
112948
113142
  const currentConfig = snapshot(intent.configPath, true);
112949
113143
  const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
112950
113144
  const alias = binding.rootAliases?.find((item) => item.agent === "codex"), physicalRoot = alias?.target ?? join61(home, ".codex"), hooksPath = join61(physicalRoot, "hooks.json");
112951
- need6(resolve26(intent.configPath) === resolve26(join61(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
113145
+ need5(resolve26(intent.configPath) === resolve26(join61(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
112952
113146
  const nativeConfigPath = intent.nativeConfigPath ?? intent.configPath;
112953
- need6([join61(home, ".codex/config.toml"), join61(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
113147
+ need5([join61(home, ".codex/config.toml"), join61(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
112954
113148
  const codexHome = nativeConfigPath !== intent.configPath ? undefined : dirname34(nativeConfigPath);
112955
113149
  const hooksCurrent = snapshot(hooksPath);
112956
113150
  const additions = additionsRecovery ? reviewNativeHookAdditions({ path: additionsRecovery.path, intent: intentFile, policy: policyCurrent, configBefore, configCurrent: currentConfig, hooksBefore, hooksCurrent, nativeHooksPath: join61(dirname34(nativeConfigPath), "hooks.json"), journalHooks: intent.hooks, recordedNativeHooks: intent.nativeHooks }) : undefined;
@@ -112958,7 +113152,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
112958
113152
  const managedKeys = managedHooks.map((h) => h.key);
112959
113153
  const witnessSame = codexTrustReconcileWitness(configBefore.text, managedKeys) === codexTrustReconcileWitness(currentConfig.text, managedKeys);
112960
113154
  const unmanagedSame = codexTrustUnmanagedSemantic(configBefore.text, managedKeys) === codexTrustUnmanagedSemantic(currentConfig.text, managedKeys);
112961
- need6(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
113155
+ need5(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
112962
113156
  const before2 = structure3(configBefore.text), current = structure3(currentConfig.text), expectedConfig = structuredClone(before2);
112963
113157
  expectedConfig.hooks ??= {};
112964
113158
  expectedConfig.hooks.state ??= {};
@@ -112970,10 +113164,10 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
112970
113164
  if (supersededBinding) {
112971
113165
  for (const hook of intent.hooks) {
112972
113166
  const state = current.hooks?.state?.[hook.key];
112973
- need6(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
113167
+ need5(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
112974
113168
  }
112975
113169
  } else
112976
- need6(isDeepStrictEqual15(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
113170
+ need5(isDeepStrictEqual15(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
112977
113171
  const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
112978
113172
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
112979
113173
  const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
@@ -112983,28 +113177,28 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
112983
113177
  if (supersededBinding)
112984
113178
  verifyReleaseArtifact(options.releaseProof, skillsCli);
112985
113179
  const skillsBindingChanged = !isDeepStrictEqual15(skillsCli.receipt, intent.skillsCli);
112986
- need6(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
113180
+ need5(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
112987
113181
  if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
112988
- need6(supersededBinding, "RECONCILE_HOOKS_CHANGED");
113182
+ need5(supersededBinding, "RECONCILE_HOOKS_CHANGED");
112989
113183
  const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
112990
113184
  for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
112991
113185
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
112992
- need6(isDeepStrictEqual15(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
113186
+ need5(isDeepStrictEqual15(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
112993
113187
  }
112994
113188
  }
112995
113189
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
112996
- need6(rpc.version === intent.nativeVersion, "RECONCILE_NATIVE_VERSION_CHANGED");
113190
+ need5(rpc.version === intent.nativeVersion, "RECONCILE_NATIVE_VERSION_CHANGED");
112997
113191
  const discovered = await rpc.request("hooks/list", { cwds: [home] });
112998
- need6(Array.isArray(discovered?.data) && discovered.data.length === 1 && discovered.data[0].cwd === home && !discovered.data[0].errors?.length && !discovered.data[0].warnings?.length, "RECONCILE_NATIVE_DISCOVERY_REFUSED");
113192
+ need5(Array.isArray(discovered?.data) && discovered.data.length === 1 && discovered.data[0].cwd === home && !discovered.data[0].errors?.length && !discovered.data[0].warnings?.length, "RECONCILE_NATIVE_DISCOVERY_REFUSED");
112999
113193
  const nativeHooks = discovered.data[0].hooks;
113000
113194
  const recordedNativeHooks = intent.nativeHooks;
113001
113195
  if (recordedNativeHooks)
113002
- need6(nativeHooks.length === recordedNativeHooks.length + (additions?.hooks.length ?? 0), "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
113196
+ need5(nativeHooks.length === recordedNativeHooks.length + (additions?.hooks.length ?? 0), "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
113003
113197
  const plannedKeys = new Set(intent.hooks.map((hook) => hook.key));
113004
113198
  let nativeTrustPending = false;
113005
113199
  for (const expected of [...recordedNativeHooks ?? [], ...additions?.hooks ?? []]) {
113006
113200
  const matches2 = nativeHooks.filter((hook) => hook.key === expected.key);
113007
- need6(matches2.length === 1, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
113201
+ need5(matches2.length === 1, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
113008
113202
  const actual = safeNativeHook(matches2[0]);
113009
113203
  const stable = (hook) => {
113010
113204
  const { enabled, trustStatus, ...identity5 } = hook;
@@ -113012,35 +113206,35 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
113012
113206
  delete identity5.command;
113013
113207
  return identity5;
113014
113208
  };
113015
- need6(isDeepStrictEqual15(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
113209
+ need5(isDeepStrictEqual15(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
113016
113210
  if (!plannedKeys.has(expected.key))
113017
- need6(isDeepStrictEqual15(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
113211
+ need5(isDeepStrictEqual15(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
113018
113212
  }
113019
113213
  for (const wanted of intent.hooks) {
113020
113214
  const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join61(home, ".codex/hooks.json"), hooksPath));
113021
- need6(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
113215
+ need5(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
113022
113216
  const h = matches2[0];
113023
113217
  const trusted = h.trustStatus === "trusted";
113024
- need6(h.enabled === true && (trusted || supersededBinding && h.trustStatus === "modified") && (h.currentHash === wanted.currentHash || supersededBinding && /^sha256:[a-f0-9]{64}$/.test(h.currentHash)), "RECONCILE_NATIVE_STATE_INCOMPLETE");
113218
+ need5(h.enabled === true && (trusted || supersededBinding && h.trustStatus === "modified") && (h.currentHash === wanted.currentHash || supersededBinding && /^sha256:[a-f0-9]{64}$/.test(h.currentHash)), "RECONCILE_NATIVE_STATE_INCOMPLETE");
113025
113219
  if (!trusted)
113026
113220
  nativeTrustPending = true;
113027
113221
  if (supersededBinding) {
113028
113222
  const nativeToCliEvent = { userPromptSubmit: "UserPromptSubmit", sessionStart: "SessionStart", subagentStart: "SubagentStart" };
113029
- need6(h.command === renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, nativeToCliEvent[wanted.event] ?? ""), "RECONCILE_BINDING_HOOK_CHANGED");
113223
+ need5(h.command === renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, nativeToCliEvent[wanted.event] ?? ""), "RECONCILE_BINDING_HOOK_CHANGED");
113030
113224
  }
113031
113225
  }
113032
113226
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
113033
113227
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
113034
- need6(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
113228
+ need5(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
113035
113229
  const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
113036
- need6(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual15(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
113230
+ need5(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual15(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
113037
113231
  const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
113038
113232
  const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
113039
- need6(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
113233
+ need5(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
113040
113234
  if (recovery) {
113041
113235
  for (const response of [config2, finalConfig]) {
113042
113236
  const layerIndex = response.layers.findIndex((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
113043
- need6(response.config && response.config.features?.hooks !== false && response.layers.slice(0, layerIndex).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "RECONCILE_NATIVE_CONFIG_OVERRIDDEN");
113237
+ need5(response.config && response.config.features?.hooks !== false && response.layers.slice(0, layerIndex).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "RECONCILE_NATIVE_CONFIG_OVERRIDDEN");
113044
113238
  }
113045
113239
  recoveryCli.recheck();
113046
113240
  verifyReleaseArtifact(options.releaseProof, recoveryCli);
@@ -113061,7 +113255,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
113061
113255
  const recoveryPlan = recovery ? { version: 1, kind: additions ? claudeRecovery ? "claude-discovery-and-native-hook-additions" : "native-hook-additions" : "claude-discovery-only", journal, journalIntentSha256: intentFile.sha256, stoppedSha256: stoppedFile.sha256, originalPlanDigest: intent.planDigest, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, configBeforeSha256: configBefore.sha256, configCurrentSha256: currentConfig.sha256, ...configDiscoveryRecovery ? { configDiscoveryRecovery } : {}, ...additions ? { nativeHookAdditions: additions.receipt } : {}, hooksSha256: hooksCurrent.sha256, nativeConfigPath, nativeVersion: rpc.version, nativeInventorySha256: makePlanDigest(nativeHooks.map(safeNativeHook)), recordedNativeInventorySha256: makePlanDigest(recordedNativeHooks), boundSkillsCli: skillsCli.receipt, recoveryCli: recoveryCli.receipt, releaseProof: options.releaseProof, ...policyChange } : undefined;
113062
113256
  const recoveryPlanDigest = recoveryPlan ? makePlanDigest(recoveryPlan) : undefined;
113063
113257
  if (recovery?.reviewedPlanDigest !== undefined)
113064
- need6(recovery.reviewedPlanDigest === recoveryPlanDigest, "RECONCILE_RECOVERY_PLAN_CHANGED");
113258
+ need5(recovery.reviewedPlanDigest === recoveryPlanDigest, "RECONCILE_RECOVERY_PLAN_CHANGED");
113065
113259
  const preview2 = !!recovery && recovery.reviewedPlanDigest === undefined;
113066
113260
  const receipt = { version: 1, status: preview2 ? "recovery-review-required" : supersededBinding ? "superseded" : "reconciled", reconciled: !preview2, supersededBinding, automaticRollback: false, journal, planDigest: intent.planDigest, nativeVersion: rpc.version, nativeStateVerified: !nativeTrustPending, nativeTrustPending, bindingRefreshRequired: !!configDiscoveryRecovery, nativeExecutionVerified: false, configSha256: currentConfig.sha256, hooksSha256: hooksCurrent.sha256, policySha256: policyBefore.sha256, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, previousSkillsCli: intent.skillsCli, skillsCli: skillsCli.receipt, releaseProof: options.releaseProof, nativeInventoryScope: recordedNativeHooks ? "complete" : "declared-managed-hooks-only", unrelatedNativeHooksPreserved: !!recordedNativeHooks, unrelatedSettingsAndCommentsPreserved: true, ...recoveryPlan ? { recoveryPlan, recoveryPlanDigest } : {} };
113067
113261
  if (preview2)
@@ -113084,7 +113278,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
113084
113278
  const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
113085
113279
  const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
113086
113280
  const physicalRoot = alias?.target ?? join61(home, ".codex"), hooksPath = join61(physicalRoot, "hooks.json"), configPath = join61(physicalRoot, "config.toml");
113087
- need6(options.codexHome === undefined || isAbsolute28(options.codexHome) && [join61(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
113281
+ need5(options.codexHome === undefined || isAbsolute28(options.codexHome) && [join61(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
113088
113282
  const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
113089
113283
  const nativeConfigPath = join61(codexHome ?? join61(home, ".codex"), "config.toml");
113090
113284
  const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
@@ -113092,38 +113286,38 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
113092
113286
  for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
113093
113287
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
113094
113288
  const groups = declarations[event];
113095
- need6(Array.isArray(groups), "DECLARATION_CHANGED");
113289
+ need5(Array.isArray(groups), "DECLARATION_CHANGED");
113096
113290
  const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
113097
- need6(matches2.length === 1 && isDeepStrictEqual15(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
113291
+ need5(matches2.length === 1 && isDeepStrictEqual15(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
113098
113292
  expected.push({ event: nativeEvent, key: `${join61(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
113099
113293
  }
113100
113294
  codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
113101
113295
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
113102
- need6(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
113296
+ need5(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
113103
113297
  const list2 = async () => {
113104
113298
  const response = await rpc.request("hooks/list", { cwds: [home] });
113105
113299
  const nativeRoots = [...new Set([physicalRoot, join61(home, ".codex")])];
113106
113300
  const coexistenceWarnings = nativeRoots.flatMap((hooksRoot) => nativeRoots.map((configRoot) => `loading hooks from both ${join61(hooksRoot, "hooks.json")} and ${join61(configRoot, "config.toml")}; prefer a single representation for this layer`));
113107
113301
  const entry = response?.data?.[0];
113108
- need6(Array.isArray(response?.data) && response.data.length === 1 && entry.cwd === home && Array.isArray(entry.hooks) && entry.hooks.length <= 1e4 && Array.isArray(entry.errors) && entry.errors.length === 0 && Array.isArray(entry.warnings) && entry.warnings.length <= 1 && entry.warnings.every((warning) => typeof warning === "string" && coexistenceWarnings.includes(warning)), "NATIVE_DISCOVERY_REFUSED");
113302
+ need5(Array.isArray(response?.data) && response.data.length === 1 && entry.cwd === home && Array.isArray(entry.hooks) && entry.hooks.length <= 1e4 && Array.isArray(entry.errors) && entry.errors.length === 0 && Array.isArray(entry.warnings) && entry.warnings.length <= 1 && entry.warnings.every((warning) => typeof warning === "string" && coexistenceWarnings.includes(warning)), "NATIVE_DISCOVERY_REFUSED");
113109
113303
  return response.data[0].hooks;
113110
113304
  };
113111
113305
  const admit = (hooks) => expected.map((wanted) => {
113112
113306
  const canonicalKey = wanted.key.replace(join61(home, ".codex/hooks.json"), hooksPath);
113113
113307
  const matches2 = hooks.filter((h2) => h2.key === wanted.key || h2.key === canonicalKey);
113114
- need6(matches2.length === 1, "AMBIGUOUS_IDENTITY");
113308
+ need5(matches2.length === 1, "AMBIGUOUS_IDENTITY");
113115
113309
  const h = matches2[0];
113116
- need6(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join61(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
113117
- need6(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
113118
- need6(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
113310
+ need5(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join61(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
113311
+ need5(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
113312
+ need5(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
113119
113313
  return { key: h.key, event: wanted.event, command: wanted.command, handlerType: h.handlerType, timeoutSec: h.timeoutSec, sourcePath: h.sourcePath, currentHash: h.currentHash, enabled: h.enabled, trustStatus: h.trustStatus };
113120
113314
  });
113121
113315
  const discovered = await list2(), admitted = admit(discovered);
113122
113316
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
113123
113317
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
113124
- need6(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
113125
- need6(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
113126
- need6(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
113318
+ need5(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
113319
+ need5(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
113320
+ need5(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
113127
113321
  const keys3 = admitted.map((h) => h.key), planned = admitted.filter((h) => !h.enabled || h.trustStatus !== "trusted");
113128
113322
  const preservationText = codexTrustTextWitness(configFile.text, keys3);
113129
113323
  const checkInputs = () => {
@@ -113138,16 +113332,16 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
113138
113332
  const planDigest = makePlanDigest(digestInput);
113139
113333
  const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, nativeConfigPath, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, bindingRefreshRequired: false, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
113140
113334
  if (options.apply)
113141
- need6(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
113335
+ need5(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
113142
113336
  const parent = join61(dataDir3, "native-hook-trust");
113143
113337
  const st = lstatSync32(parent, { throwIfNoEntry: false });
113144
113338
  if (st) {
113145
- need6(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
113339
+ need5(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
113146
113340
  const priorJournals = readdirSync23(parent);
113147
- need6(priorJournals.length < 1000, "JOURNAL_BOUND");
113341
+ need5(priorJournals.length < 1000, "JOURNAL_BOUND");
113148
113342
  for (const name of priorJournals) {
113149
- need6(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
113150
- need6(lstatSync32(join61(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
113343
+ need5(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
113344
+ need5(lstatSync32(join61(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
113151
113345
  }
113152
113346
  }
113153
113347
  if (!options.apply || !planned.length)
@@ -113160,7 +113354,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
113160
113354
  save(join61(journal, "hooks.before.json"), hooksFile.bytes);
113161
113355
  save(join61(journal, "policy.before.json"), policyFile.bytes);
113162
113356
  save(join61(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
113163
- need6(isDeepStrictEqual15(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
113357
+ need5(isDeepStrictEqual15(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
113164
113358
  checkInputs();
113165
113359
  let result2;
113166
113360
  try {
@@ -113168,22 +113362,22 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
113168
113362
  } catch {
113169
113363
  throw new Error("CODEX_HOOK_TRUST_NATIVE_WRITE_FAILED: reconcile the private journal before retrying");
113170
113364
  }
113171
- need6(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
113365
+ need5(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
113172
113366
  const after2 = snapshot(configPath, true), expectedConfig = structuredClone(original);
113173
113367
  expectedConfig.hooks ??= {};
113174
113368
  expectedConfig.hooks.state ??= {};
113175
113369
  for (const h of planned)
113176
113370
  expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
113177
- need6(isDeepStrictEqual15(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
113371
+ need5(isDeepStrictEqual15(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
113178
113372
  const savedConfig = snapshot(join61(journal, "config.before.toml"), true);
113179
- need6(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
113373
+ need5(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
113180
113374
  const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
113181
113375
  unchanged2(policyFile);
113182
113376
  unchanged2(hooksFile);
113183
113377
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
113184
113378
  const current = await list2(), confirmed = admit(current);
113185
- need6(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual15(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
113186
- need6(isDeepStrictEqual15(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
113379
+ need5(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual15(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
113380
+ need5(isDeepStrictEqual15(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
113187
113381
  unchanged2(after2);
113188
113382
  unchanged2(savedConfig);
113189
113383
  unchanged2(hooksFile);
@@ -113346,7 +113540,7 @@ var exports_agent_integration = {};
113346
113540
  __export(exports_agent_integration, {
113347
113541
  registerAgentIntegration: () => registerAgentIntegration
113348
113542
  });
113349
- import { existsSync as existsSync36, lstatSync as lstatSync33, readFileSync as readFileSync41, writeFileSync as writeFileSync26 } from "fs";
113543
+ import { existsSync as existsSync36, lstatSync as lstatSync33, readFileSync as readFileSync41, readSync as readSync17, writeFileSync as writeFileSync26 } from "fs";
113350
113544
  import { createHash as createHash32 } from "crypto";
113351
113545
  import { homedir as homedir13 } from "os";
113352
113546
  import { isAbsolute as isAbsolute29 } from "path";
@@ -113416,6 +113610,32 @@ function agents(value) {
113416
113610
  }
113417
113611
  function registerAgentIntegration(parent) {
113418
113612
  const hook = parent.command("hook").description("Load selected Skills context through agent lifecycle hooks");
113613
+ hook.command("project-claude-settings").requiredOption("--expected-target-sha256 <sha256>", "SHA-256 of the exact target settings bytes supplied on stdin").option("--expected-source-sha256 <sha256>", "Source witness from the preceding projection, for revalidation").option("--json", "Return only command-leaf replacements and content witnesses", false).description("Read-only projection of verified Skills hooks into copied Claude settings supplied on stdin").action(async (options) => {
113614
+ try {
113615
+ const bytes = Buffer.alloc(1024 * 1024 + 1);
113616
+ let length = 0;
113617
+ while (length < bytes.length) {
113618
+ const count = readSync17(0, bytes, length, bytes.length - length, null);
113619
+ if (!count)
113620
+ break;
113621
+ length += count;
113622
+ }
113623
+ if (length > 1024 * 1024)
113624
+ throw new Error("CLAUDE_MANAGED_HOOK_TARGET_INVALID");
113625
+ const targetSettings = new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length));
113626
+ const plan = planClaudeManagedHookProjection({
113627
+ targetSettings,
113628
+ expectedTargetSha256: options.expectedTargetSha256,
113629
+ expectedSourceSha256: options.expectedSourceSha256,
113630
+ projectDir: process.cwd()
113631
+ });
113632
+ await writeCliOutput(JSON.stringify(plan));
113633
+ } catch (error61) {
113634
+ const code2 = error61 instanceof Error && /^CLAUDE_MANAGED_HOOK_[A-Z_]+$/.test(error61.message) ? error61.message : "CLAUDE_MANAGED_HOOK_PROJECTION_FAILED";
113635
+ console.error(code2);
113636
+ process.exitCode = 1;
113637
+ }
113638
+ });
113419
113639
  hook.command("native-catalog").requiredOption("--cwd <path>", "Absolute project directory observed by native Codex skills/list").requiredOption("--output <file>", "New private file for the projected native catalog").option("--codex-command <path>", "Installed Codex executable used by the native client", "codex").option("--json", "Output bounded capture metadata as JSON", false).description("Capture a reviewed Codex native skill catalog for exact hook enrollment").action(async (options) => {
113420
113640
  try {
113421
113641
  if (!isAbsolute29(options.cwd) || !isAbsolute29(options.output))
@@ -113827,7 +114047,7 @@ var exports_profiles = {};
113827
114047
  __export(exports_profiles, {
113828
114048
  registerProfiles: () => registerProfiles
113829
114049
  });
113830
- import { closeSync as closeSync21, constants as constants20, fstatSync as fstatSync21, openSync as openSync21, readSync as readSync17, writeFileSync as writeFileSync27 } from "fs";
114050
+ import { closeSync as closeSync21, constants as constants20, fstatSync as fstatSync21, openSync as openSync21, readSync as readSync18, writeFileSync as writeFileSync27 } from "fs";
113831
114051
  function readProfileInput(path) {
113832
114052
  const fd = openSync21(path, constants20.O_RDONLY | constants20.O_NONBLOCK);
113833
114053
  try {
@@ -113837,7 +114057,7 @@ function readProfileInput(path) {
113837
114057
  const bytes = Buffer.alloc(MAX_PROFILE_DOCUMENT_BYTES + 1);
113838
114058
  let size2 = 0;
113839
114059
  while (size2 < bytes.length) {
113840
- const read3 = readSync17(fd, bytes, size2, bytes.length - size2, null);
114060
+ const read3 = readSync18(fd, bytes, size2, bytes.length - size2, null);
113841
114061
  if (!read3)
113842
114062
  break;
113843
114063
  size2 += read3;
@@ -113901,7 +114121,7 @@ import {
113901
114121
  closeSync as closeSync23,
113902
114122
  fstatSync as fstatSync23,
113903
114123
  openSync as openSync23,
113904
- readSync as readSync18,
114124
+ readSync as readSync19,
113905
114125
  writeFileSync as writeFileSync28
113906
114126
  } from "fs";
113907
114127
  function readInput(path) {
@@ -113913,7 +114133,7 @@ function readInput(path) {
113913
114133
  const bytes = Buffer.alloc(MAX_EXECUTION_GRANT_BYTES + 1);
113914
114134
  let size2 = 0;
113915
114135
  while (size2 < bytes.length) {
113916
- const count = readSync18(fd, bytes, size2, bytes.length - size2, null);
114136
+ const count = readSync19(fd, bytes, size2, bytes.length - size2, null);
113917
114137
  if (!count)
113918
114138
  break;
113919
114139
  size2 += count;