@hasna/skills 0.10.64 → 0.10.66

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/mcp.js CHANGED
@@ -23,7 +23,7 @@ var package_default;
23
23
  var init_package = __esm(() => {
24
24
  package_default = {
25
25
  name: "@hasna/skills",
26
- version: "0.10.64",
26
+ version: "0.10.66",
27
27
  description: "Skills library for AI coding agents",
28
28
  type: "module",
29
29
  bin: {
@@ -23089,8 +23089,8 @@ function assertAgentPolicyCollections(policy) {
23089
23089
  }
23090
23090
  }
23091
23091
  if (value.codexSemanticCache !== undefined) {
23092
- const proof = record2(value.codexSemanticCache, 8), witness = record2(proof.witness, 6);
23093
- requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && Object.keys(proof).length === 8 && proof.schema === "hasna.codex-semantic-cache-discovery.v1" && typeof proof.previousPolicySha256 === "string" && /^[a-f0-9]{64}$/.test(proof.previousPolicySha256) && Object.keys(witness).length === 6 && witness.schema === "hasna.codex-semantic-cache-witness.v1" && typeof witness.sha256 === "string" && /^[a-f0-9]{64}$/.test(witness.sha256));
23092
+ const proof = record2(value.codexSemanticCache, 9), witness = record2(proof.witness, 7);
23093
+ requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && [8, 9].includes(Object.keys(proof).length) && Object.keys(proof).every((key) => ["schema", "configPath", "hookRootAlias", "witness", "appOnlyParents", "previousPolicySha256", "supersededSources", "supersededDirectories", "reviewedHookParents"].includes(key)) && proof.schema === "hasna.codex-semantic-cache-discovery.v1" && typeof proof.previousPolicySha256 === "string" && /^[a-f0-9]{64}$/.test(proof.previousPolicySha256) && [6, 7].includes(Object.keys(witness).length) && Object.keys(witness).every((key) => ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256", "hookParents"].includes(key)) && witness.schema === "hasna.codex-semantic-cache-witness.v1" && typeof witness.sha256 === "string" && /^[a-f0-9]{64}$/.test(witness.sha256));
23094
23094
  text(proof.configPath);
23095
23095
  requireBound(isAbsolute5(proof.configPath) && resolve4(proof.configPath) === proof.configPath && basename5(proof.configPath) === "config.toml");
23096
23096
  text(witness.cacheRoot);
@@ -23109,6 +23109,20 @@ function assertAgentPolicyCollections(policy) {
23109
23109
  text(parent[key]);
23110
23110
  requireBound(isAbsolute5(parent.pluginParent) && resolve4(parent.pluginParent) === parent.pluginParent);
23111
23111
  }
23112
+ if (proof.reviewedHookParents !== undefined)
23113
+ for (const parent of array2(proof.reviewedHookParents, 4096)) {
23114
+ requireBound(object2(parent) && parent.role === "reviewed-hook" && (parent.installation === "remote-receipt" && Object.keys(parent).length === 6 || parent.installation === "local-marketplace" && Object.keys(parent).length === 7));
23115
+ requireBound(parent.installation === "remote-receipt" ? Object.keys(parent).sort().join(",") === "installation,namespace,pluginId,pluginParent,remotePluginId,role" : Object.keys(parent).sort().join(",") === "installation,marketplaceSha256,marketplaceSourcePath,namespace,pluginId,pluginParent,role");
23116
+ for (const key of ["pluginId", "namespace", "pluginParent", "installation"])
23117
+ text(parent[key]);
23118
+ if (parent.installation === "remote-receipt")
23119
+ text(parent.remotePluginId);
23120
+ else {
23121
+ text(parent.marketplaceSourcePath);
23122
+ requireBound(typeof parent.marketplaceSha256 === "string" && /^[a-f0-9]{64}$/.test(parent.marketplaceSha256) && isAbsolute5(parent.marketplaceSourcePath) && resolve4(parent.marketplaceSourcePath) === parent.marketplaceSourcePath && basename5(parent.marketplaceSourcePath) === "marketplace.json");
23123
+ }
23124
+ requireBound(isAbsolute5(parent.pluginParent) && resolve4(parent.pluginParent) === parent.pluginParent);
23125
+ }
23112
23126
  for (const row of [...array2(witness.controls, 4096), ...array2(witness.appOnlyParents, 4096)]) {
23113
23127
  requireBound(object2(row));
23114
23128
  for (const key of ["pluginId", "namespace", "pluginParent"])
@@ -23117,6 +23131,26 @@ function assertAgentPolicyCollections(policy) {
23117
23131
  if (row[key] !== undefined)
23118
23132
  requireBound(typeof row[key] === "string" && /^[a-f0-9]{64}$/.test(row[key]));
23119
23133
  }
23134
+ if (witness.hookParents !== undefined)
23135
+ for (const row of array2(witness.hookParents, 4096)) {
23136
+ requireBound(object2(row) && row.role === "reviewed-hook" && (row.installation === "remote-receipt" && Object.keys(row).length === 9 || row.installation === "local-marketplace" && Object.keys(row).length === 9));
23137
+ requireBound(row.installation === "remote-receipt" ? Object.keys(row).sort().join(",") === "hooksSha256,installation,manifestSha256,namespace,pluginId,pluginParent,receiptSha256,remotePluginId,role" : Object.keys(row).sort().join(",") === "hooksSha256,installation,manifestSha256,marketplaceSha256,marketplaceSourcePath,namespace,pluginId,pluginParent,role");
23138
+ for (const key of ["pluginId", "namespace", "pluginParent", "installation"])
23139
+ text(row[key]);
23140
+ if (row.installation === "remote-receipt")
23141
+ text(row.remotePluginId);
23142
+ else {
23143
+ text(row.marketplaceSourcePath);
23144
+ requireBound(typeof row.marketplaceSha256 === "string" && /^[a-f0-9]{64}$/.test(row.marketplaceSha256) && isAbsolute5(row.marketplaceSourcePath) && resolve4(row.marketplaceSourcePath) === row.marketplaceSourcePath && basename5(row.marketplaceSourcePath) === "marketplace.json");
23145
+ }
23146
+ requireBound(isAbsolute5(row.pluginParent) && resolve4(row.pluginParent) === row.pluginParent);
23147
+ for (const key of ["manifestSha256", "hooksSha256"])
23148
+ requireBound(typeof row[key] === "string" && /^[a-f0-9]{64}$/.test(row[key]));
23149
+ if (row.installation === "remote-receipt")
23150
+ requireBound(typeof row.receiptSha256 === "string" && /^[a-f0-9]{64}$/.test(row.receiptSha256));
23151
+ else
23152
+ requireBound(row.receiptSha256 === undefined);
23153
+ }
23120
23154
  for (const skill of array2(witness.skills, 4096)) {
23121
23155
  requireBound(object2(skill));
23122
23156
  for (const key of ["name", "pluginId", "namespace", "pluginParent"])
@@ -33667,7 +33701,25 @@ var init_codex_settings_witness = __esm(() => {
33667
33701
  // src/lib/codex-semantic-cache-witness.ts
33668
33702
  import { createHash as createHash14 } from "crypto";
33669
33703
  import { constants as constants7, closeSync as closeSync10, fstatSync as fstatSync10, lstatSync as lstatSync13, openSync as openSync10, readSync as readSync5, readdirSync as readdirSync7, realpathSync as realpathSync6 } from "fs";
33670
- import { dirname as dirname13, isAbsolute as isAbsolute11, join as join19, relative as relative6, resolve as resolve12, sep as sep7 } from "path";
33704
+ import { basename as basename7, dirname as dirname13, isAbsolute as isAbsolute11, join as join19, relative as relative6, resolve as resolve12, sep as sep7 } from "path";
33705
+ function codexLocalMarketplaceMapsPlugin(text2, marketplace, plugin) {
33706
+ try {
33707
+ hashNativeJsonControls(text2);
33708
+ const value = JSON.parse(text2);
33709
+ if (!plainObject(value) || !exactKeys(value, ["interface", "name", "plugins"]) || value.name !== marketplace || !(typeof value.interface === "string" || Number.isSafeInteger(value.interface)) || !Array.isArray(value.plugins) || value.plugins.length < 1 || value.plugins.length > 4096)
33710
+ return false;
33711
+ const rows = value.plugins.filter((row2) => plainObject(row2) && row2.name === plugin);
33712
+ if (rows.length !== 1)
33713
+ return false;
33714
+ const row = rows[0];
33715
+ if (!exactKeys(row, ["name", "source"]) || !plainObject(row.source) || !exactKeys(row.source, ["source", "path"]) || row.source.source !== "local" || typeof row.source.path !== "string" || !row.source.path.startsWith("./") || row.source.path.includes("\\"))
33716
+ return false;
33717
+ const parts = row.source.path.split("/");
33718
+ return parts[0] === "." && parts.length > 1 && parts.slice(1).every((part) => /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(part)) && parts.at(-1) === plugin;
33719
+ } catch {
33720
+ return false;
33721
+ }
33722
+ }
33671
33723
  function defaultRead(path) {
33672
33724
  const before = lstatSync13(path, { throwIfNoEntry: false, bigint: true });
33673
33725
  if (before === undefined)
@@ -33729,7 +33781,7 @@ function validPluginParent(cacheRoot, pluginParent, namespace, pluginId) {
33729
33781
  return parts.length === 2 && parts.every(identifier3) && parts[1] === namespace && pluginId === `${namespace}@${parts[0]}`;
33730
33782
  }
33731
33783
  function assertWitnessShape(value) {
33732
- if (!plainObject(value) || !exactKeys(value, ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256"]) || value.schema !== CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA || typeof value.cacheRoot !== "string" || !isAbsolute11(value.cacheRoot) || resolve12(value.cacheRoot) !== value.cacheRoot || !digest(value.sha256) || !Array.isArray(value.controls) || value.controls.length === 0 || value.controls.length > 4096 || !Array.isArray(value.appOnlyParents) || value.appOnlyParents.length > 4096 || !Array.isArray(value.skills) || value.skills.length === 0 || value.skills.length > 4096)
33784
+ if (!plainObject(value) || !exactKeys(value, ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256"], ["hookParents"]) || value.schema !== CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA || typeof value.cacheRoot !== "string" || !isAbsolute11(value.cacheRoot) || resolve12(value.cacheRoot) !== value.cacheRoot || !digest(value.sha256) || !Array.isArray(value.controls) || value.controls.length === 0 || value.controls.length > 4096 || !Array.isArray(value.appOnlyParents) || value.appOnlyParents.length > 4096 || !Array.isArray(value.skills) || value.skills.length === 0 || value.skills.length > 4096)
33733
33785
  refuse3();
33734
33786
  const witness = value;
33735
33787
  const controlParents = new Set;
@@ -33750,6 +33802,20 @@ function assertWitnessShape(value) {
33750
33802
  refuse3();
33751
33803
  appOnlyParentPaths.add(row.pluginParent);
33752
33804
  }
33805
+ const hookParentPaths = new Set;
33806
+ const hookParents = witness.hookParents === undefined ? [] : witness.hookParents;
33807
+ if (!Array.isArray(hookParents) || hookParents.length > 4096)
33808
+ refuse3();
33809
+ for (const candidate of hookParents) {
33810
+ if (!plainObject(candidate))
33811
+ refuse3();
33812
+ const row = candidate;
33813
+ const remote = row.installation === "remote-receipt";
33814
+ const local = row.installation === "local-marketplace";
33815
+ if (!exactKeys(row, ["role", "pluginId", "namespace", "pluginParent", "installation", "manifestSha256", "hooksSha256"], remote ? ["remotePluginId", "receiptSha256"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || row.role !== "reviewed-hook" || !identifier3(row.namespace) || typeof row.pluginId !== "string" || !/^[A-Za-z0-9_-]{1,64}@[A-Za-z0-9_-]{1,64}$/.test(row.pluginId) || typeof row.pluginParent !== "string" || !validPluginParent(String(witness.cacheRoot), row.pluginParent, row.namespace, row.pluginId) || remote && (typeof row.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(row.remotePluginId) || !digest(row.receiptSha256)) || local && (typeof row.marketplaceSourcePath !== "string" || !isAbsolute11(row.marketplaceSourcePath) || resolve12(row.marketplaceSourcePath) !== row.marketplaceSourcePath || basename7(row.marketplaceSourcePath) !== "marketplace.json" || !digest(row.marketplaceSha256)) || !remote && !local || !digest(row.manifestSha256) || !digest(row.hooksSha256) || hookParentPaths.has(row.pluginParent) || controlParents.has(row.pluginParent) || appOnlyParentPaths.has(row.pluginParent))
33816
+ refuse3();
33817
+ hookParentPaths.add(row.pluginParent);
33818
+ }
33753
33819
  const skillNames = new Set;
33754
33820
  const qualifiedNames = new Set;
33755
33821
  for (const candidate of witness.skills) {
@@ -33769,6 +33835,7 @@ function assertWitnessShape(value) {
33769
33835
  cacheRoot: witness.cacheRoot,
33770
33836
  controls: witness.controls,
33771
33837
  appOnlyParents: witness.appOnlyParents,
33838
+ ...witness.hookParents === undefined ? {} : { hookParents: witness.hookParents },
33772
33839
  skills: witness.skills
33773
33840
  };
33774
33841
  if (hash3(projection) !== witness.sha256)
@@ -33959,10 +34026,128 @@ function appOnlyParentProjection(cacheRoot, parents2, read) {
33959
34026
  }
33960
34027
  return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
33961
34028
  }
33962
- function assertParents(cacheRoot, controls, appOnlyParents, files, members2) {
34029
+ function assertJsonValue(value, depth = 0, budget2 = { members: 0 }) {
34030
+ if (depth > 32 || ++budget2.members > 4096)
34031
+ refuse3();
34032
+ if (value === null || typeof value === "string" || typeof value === "boolean")
34033
+ return;
34034
+ if (typeof value === "number" && Number.isFinite(value))
34035
+ return;
34036
+ if (Array.isArray(value)) {
34037
+ for (const item of value)
34038
+ assertJsonValue(item, depth + 1, budget2);
34039
+ return;
34040
+ }
34041
+ if (!plainObject(value))
34042
+ refuse3();
34043
+ for (const [key, item] of Object.entries(value)) {
34044
+ if (!key || /[\x00-\x1f\x7f]/.test(key))
34045
+ refuse3();
34046
+ assertJsonValue(item, depth + 1, budget2);
34047
+ }
34048
+ }
34049
+ function reviewedHookControls(root, read) {
34050
+ const manifestPath = join19(root, ".codex-plugin/plugin.json"), hooksPath = join19(root, "hooks/hooks.json");
34051
+ let manifest, manifestSha256, hooks, hooksSha256;
34052
+ try {
34053
+ const manifestText = read(manifestPath);
34054
+ manifestSha256 = hashNativeJsonControls(manifestText, "version");
34055
+ manifest = JSON.parse(manifestText);
34056
+ const hooksText = read(hooksPath);
34057
+ hashNativeJsonControls(hooksText);
34058
+ hooksSha256 = createHash14("sha256").update(hooksText).digest("hex");
34059
+ hooks = JSON.parse(hooksText);
34060
+ } catch {
34061
+ return refuse3();
34062
+ }
34063
+ if (!plainObject(manifest) || !exactKeys(manifest, ["name", "version", "hooks"], ["description"]) || !identifier3(manifest.name) || typeof manifest.version !== "string" || manifest.version !== basename7(root) || manifest.hooks !== "./hooks/hooks.json" || manifest.description !== undefined && (typeof manifest.description !== "string" || !manifest.description.trim() || manifest.description.length > 1024))
34064
+ refuse3();
34065
+ const manifestRecord = manifest;
34066
+ if (!plainObject(hooks) || !exactKeys(hooks, ["hooks"]) || !plainObject(hooks.hooks))
34067
+ refuse3();
34068
+ const hookTable = hooks.hooks;
34069
+ const events = Object.entries(hookTable);
34070
+ if (!events.length || events.length > 32)
34071
+ refuse3();
34072
+ for (const [event, groups] of events) {
34073
+ if (!codexHookEvents.has(event) || !Array.isArray(groups) || !groups.length || groups.length > 32)
34074
+ refuse3();
34075
+ for (const group of groups) {
34076
+ if (!plainObject(group) || !exactKeys(group, ["hooks"]) || !Array.isArray(group.hooks) || !group.hooks.length || group.hooks.length > 32)
34077
+ refuse3();
34078
+ const handlers = group.hooks;
34079
+ for (const handler of handlers) {
34080
+ if (!plainObject(handler) || !exactKeys(handler, ["type", "server", "tool", "input"], ["timeout"]) || handler.type !== "mcp_tool" || !identifier3(handler.server) || !identifier3(handler.tool) || !plainObject(handler.input) || handler.timeout !== undefined && (!Number.isSafeInteger(handler.timeout) || Number(handler.timeout) < 1 || Number(handler.timeout) > 300))
34081
+ refuse3();
34082
+ assertJsonValue(handler.input);
34083
+ }
34084
+ }
34085
+ }
34086
+ return { namespace: manifestRecord.name, manifestSha256, hooksSha256 };
34087
+ }
34088
+ function reviewedHookParentProjection(cacheRoot, parents2, read) {
34089
+ if (!Array.isArray(parents2) || parents2.length > 4096)
34090
+ refuse3();
34091
+ const seen = new Set, rows = [];
34092
+ for (const parent of parents2) {
34093
+ const remote = parent?.installation === "remote-receipt", local = parent?.installation === "local-marketplace";
34094
+ if (!parent || !exactKeys(parent, ["installation", "namespace", "pluginId", "pluginParent", "role"], remote ? ["remotePluginId"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || parent.role !== "reviewed-hook" || !identifier3(parent.namespace) || !/^[A-Za-z0-9_-]{1,64}@[A-Za-z0-9_-]{1,64}$/.test(parent.pluginId) || typeof parent.pluginParent !== "string" || remote && (typeof parent.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(parent.remotePluginId)) || local && (typeof parent.marketplaceSourcePath !== "string" || !isAbsolute11(parent.marketplaceSourcePath) || resolve12(parent.marketplaceSourcePath) !== parent.marketplaceSourcePath || basename7(parent.marketplaceSourcePath) !== "marketplace.json" || !digest(parent.marketplaceSha256)) || !remote && !local)
34095
+ refuse3();
34096
+ const parts = relative6(cacheRoot, parent.pluginParent).split(sep7);
34097
+ if (!isAbsolute11(parent.pluginParent) || resolve12(parent.pluginParent) !== parent.pluginParent || parts.length !== 2 || parts.some((part) => !identifier3(part)) || parts[1] !== parent.namespace || parent.pluginId !== `${parent.namespace}@${parts[0]}` || seen.has(parent.pluginParent))
34098
+ refuse3();
34099
+ seen.add(parent.pluginParent);
34100
+ const parentStat = lstatSync13(parent.pluginParent, { throwIfNoEntry: false });
34101
+ if (!parentStat?.isDirectory() || parentStat.isSymbolicLink() || realpathSync6(parent.pluginParent) !== parent.pluginParent)
34102
+ refuse3();
34103
+ const receiptPath = join19(parent.pluginParent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync13(receiptPath, { throwIfNoEntry: false });
34104
+ let receiptText;
34105
+ if (remote) {
34106
+ if (!receiptStat?.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > MAX_RECEIPT_BYTES)
34107
+ refuse3();
34108
+ try {
34109
+ receiptText = read(receiptPath);
34110
+ hashNativeJsonControls(receiptText);
34111
+ const receipt = JSON.parse(receiptText);
34112
+ if (!plainObject(receipt) || !exactKeys(receipt, ["schema_version", "remote_plugin_id"]) || receipt.schema_version !== 1 || receipt.remote_plugin_id !== parent.remotePluginId)
34113
+ refuse3();
34114
+ } catch {
34115
+ refuse3();
34116
+ }
34117
+ } else {
34118
+ const marketplaceSourcePath = parent.marketplaceSourcePath ?? refuse3();
34119
+ if (receiptStat !== undefined || !parent.marketplaceSha256)
34120
+ refuse3();
34121
+ let marketplaceText;
34122
+ try {
34123
+ marketplaceText = read(marketplaceSourcePath);
34124
+ } catch {
34125
+ return refuse3();
34126
+ }
34127
+ if (createHash14("sha256").update(marketplaceText).digest("hex") !== parent.marketplaceSha256 || !codexLocalMarketplaceMapsPlugin(marketplaceText, parts[0], parent.namespace))
34128
+ refuse3();
34129
+ }
34130
+ const materializations = readdirSync7(parent.pluginParent).filter((name) => name !== ".codex-remote-plugin-install.json").map((version2) => {
34131
+ if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
34132
+ refuse3();
34133
+ const root = join19(parent.pluginParent, version2), stat = lstatSync13(root, { throwIfNoEntry: false });
34134
+ if (!stat?.isDirectory() || stat.isSymbolicLink() || realpathSync6(root) !== root)
34135
+ refuse3();
34136
+ const controls = reviewedHookControls(root, read);
34137
+ if (controls.namespace !== parent.namespace)
34138
+ refuse3();
34139
+ return { manifestSha256: controls.manifestSha256, hooksSha256: controls.hooksSha256 };
34140
+ });
34141
+ if (!materializations.length || materializations.some((item) => canonical7(item) !== canonical7(materializations[0])))
34142
+ refuse3();
34143
+ rows.push({ ...parent, ...receiptText === undefined ? {} : { receiptSha256: createHash14("sha256").update(receiptText).digest("hex") }, ...materializations[0] });
34144
+ }
34145
+ return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
34146
+ }
34147
+ function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files, members2) {
33963
34148
  const expected = new Set;
33964
34149
  const expectedMarkets = new Set;
33965
- for (const control of [...controls, ...appOnlyParents]) {
34150
+ for (const control of [...controls, ...appOnlyParents, ...hookParents]) {
33966
34151
  const rel = relative6(cacheRoot, control.pluginParent), parts = rel.split(sep7);
33967
34152
  if (resolve12(control.pluginParent) !== control.pluginParent || parts.length !== 2 || parts.some((part) => !identifier3(part)) || control.pluginId !== `${control.namespace}@${parts[0]}` || parts[1] !== control.namespace)
33968
34153
  refuse3();
@@ -34003,7 +34188,9 @@ function assertParents(cacheRoot, controls, appOnlyParents, files, members2) {
34003
34188
  refuse3();
34004
34189
  if ([".app.json", ".mcp.json"].includes(base) && (parts.length !== 4 || dirname13(member) !== root))
34005
34190
  refuse3();
34006
- if (parts.includes("hooks"))
34191
+ if ([".app.json", ".mcp.json"].includes(base) && hookParents.some((reviewed) => reviewed.pluginParent === parent))
34192
+ refuse3();
34193
+ if (parts.includes("hooks") && (![4, 5].includes(parts.length) || parts[3] !== "hooks" || (parts.length === 4 ? base !== "hooks" : base !== "hooks.json") || !hookParents.some((reviewed) => reviewed.pluginParent === join19(cacheRoot, parts[0], parts[1]))))
34007
34194
  refuse3();
34008
34195
  }
34009
34196
  }
@@ -34113,13 +34300,14 @@ function captureCodexSemanticCacheWitness(options) {
34113
34300
  const initialTree = treeSnapshot(options.cacheRoot);
34114
34301
  const controls = controlProjection(options.controls, read);
34115
34302
  const appOnlyParents = appOnlyParentProjection(options.cacheRoot, options.appOnlyParents ?? [], read);
34303
+ const hookParents = reviewedHookParentProjection(options.cacheRoot, options.reviewedHookParents ?? [], read);
34116
34304
  const skillParents = new Set(controls.map((control) => control.pluginParent));
34117
- if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)))
34305
+ if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)) || hookParents.some((parent) => skillParents.has(parent.pluginParent) || appOnlyParents.some((app) => app.pluginParent === parent.pluginParent)))
34118
34306
  refuse3();
34119
34307
  if (!reviewedCodexPluginCapabilitiesUnchanged(options.cacheRoot, options.controls, read, options.rules))
34120
34308
  refuse3();
34121
34309
  const files = initialTree.files;
34122
- assertParents(options.cacheRoot, controls, appOnlyParents, files, initialTree.state.members);
34310
+ assertParents(options.cacheRoot, controls, appOnlyParents, hookParents, files, initialTree.state.members);
34123
34311
  const expectedNamesByRoot = assertSkillMaterializations(options.cacheRoot, options.controls, files, read);
34124
34312
  const docs = files.filter((path) => path.endsWith(`${sep7}SKILL.md`));
34125
34313
  const skillRows = [];
@@ -34128,6 +34316,8 @@ function captureCodexSemanticCacheWitness(options) {
34128
34316
  const rel = relative6(options.cacheRoot, document2).split(sep7);
34129
34317
  if (appOnlyParents.some((parent) => parent.pluginParent === join19(options.cacheRoot, rel[0], rel[1])))
34130
34318
  refuse3();
34319
+ if (hookParents.some((parent) => parent.pluginParent === join19(options.cacheRoot, rel[0], rel[1])))
34320
+ refuse3();
34131
34321
  const documentStat = lstatSync13(document2, { throwIfNoEntry: false });
34132
34322
  if (!documentStat?.isFile() || documentStat.isSymbolicLink() || documentStat.size > MAX_DOCUMENT_BYTES)
34133
34323
  refuse3();
@@ -34191,7 +34381,7 @@ function captureCodexSemanticCacheWitness(options) {
34191
34381
  tracked.verify();
34192
34382
  const finalTree = treeSnapshot(options.cacheRoot);
34193
34383
  assertSameTree(initialTree.state, finalTree.state, tracked.paths());
34194
- const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, skills: uniqueSkills };
34384
+ const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, hookParents, skills: uniqueSkills };
34195
34385
  return { ...completeProjection, sha256: hash3(completeProjection) };
34196
34386
  } catch (error61) {
34197
34387
  if (error61 instanceof Error && error61.message.startsWith("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED"))
@@ -34207,6 +34397,7 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
34207
34397
  cacheRoot: previous.cacheRoot,
34208
34398
  controls: previous.controls,
34209
34399
  appOnlyParents: previous.appOnlyParents,
34400
+ ...previous.hookParents === undefined ? {} : { hookParents: previous.hookParents },
34210
34401
  skills: previous.skills
34211
34402
  };
34212
34403
  const currentProjection = {
@@ -34214,20 +34405,41 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
34214
34405
  cacheRoot: current.cacheRoot,
34215
34406
  controls: current.controls,
34216
34407
  appOnlyParents: current.appOnlyParents,
34408
+ ...current.hookParents === undefined ? {} : { hookParents: current.hookParents },
34217
34409
  skills: current.skills
34218
34410
  };
34219
- if (hash3(priorProjection) !== previous.sha256 || hash3(currentProjection) !== current.sha256 || canonical7(priorProjection) !== canonical7(currentProjection))
34411
+ const comparable = (projection) => ({ ...projection, hookParents: projection.hookParents ?? [] });
34412
+ if (hash3(priorProjection) !== previous.sha256 || hash3(currentProjection) !== current.sha256 || canonical7(comparable(priorProjection)) !== canonical7(comparable(currentProjection)))
34220
34413
  refuse3();
34221
34414
  }
34222
34415
  var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1", identifier3 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value), digest = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), refuse3 = () => {
34223
34416
  throw new Error("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED: review Codex plugin cache identity and controls");
34224
- }, MAX_DOCUMENT_BYTES, MAX_RECEIPT_BYTES;
34417
+ }, MAX_DOCUMENT_BYTES, MAX_RECEIPT_BYTES, codexHookEvents;
34225
34418
  var init_codex_semantic_cache_witness = __esm(() => {
34226
34419
  init_claude_settings_witness();
34227
34420
  init_codex_plugin_skill_controls();
34228
34421
  init_codex_native_skill_catalog();
34229
34422
  MAX_DOCUMENT_BYTES = 1024 * 1024;
34230
34423
  MAX_RECEIPT_BYTES = 16 * 1024;
34424
+ codexHookEvents = new Set([
34425
+ "SessionStart",
34426
+ "UserPromptSubmit",
34427
+ "PreToolUse",
34428
+ "PostToolUse",
34429
+ "PostToolUseFailure",
34430
+ "Stop",
34431
+ "SubagentStart",
34432
+ "SubagentStop",
34433
+ "PreCompact",
34434
+ "Notification",
34435
+ "PermissionRequest",
34436
+ "SessionEnd",
34437
+ "ConfigChange",
34438
+ "WorktreeCreate",
34439
+ "WorktreeRemove",
34440
+ "TeammateIdle",
34441
+ "TaskComplete"
34442
+ ]);
34231
34443
  });
34232
34444
 
34233
34445
  // src/lib/managed-policy.ts
@@ -34337,6 +34549,79 @@ var init_agent_bridge = __esm(() => {
34337
34549
  // src/lib/agent-codex.ts
34338
34550
  var init_agent_codex = () => {};
34339
34551
 
34552
+ // src/lib/hook-diagnostics.ts
34553
+ var CONTEXT_ERROR_CODES, HOOK_REFUSAL_REASON_CODES, OPTIONAL_CONTEXT_FAILURES;
34554
+ var init_hook_diagnostics = __esm(() => {
34555
+ CONTEXT_ERROR_CODES = new Set([
34556
+ "SKILLS_API_CREDENTIAL_UNAVAILABLE",
34557
+ "SKILLS_API_UNAVAILABLE",
34558
+ "SKILLS_API_UNAUTHORIZED",
34559
+ "SKILLS_API_FORBIDDEN",
34560
+ "SKILLS_API_RESOURCE_UNAVAILABLE",
34561
+ "SESSION_WRITE_BUSY",
34562
+ "SKILLS_CONTEXT_FAILED",
34563
+ "SKILLS_STORAGE_FULL",
34564
+ "PROFILE_LOCK_MISMATCH",
34565
+ "PROFILE_IDENTITY_MISMATCH",
34566
+ "PROFILE_APPLIED_REPORT_FAILED",
34567
+ "CACHED_AUTHORITY_REQUIRED",
34568
+ "CACHED_PROFILE_EXPIRED",
34569
+ "CACHED_PROFILE_MISSING",
34570
+ "CACHED_BUNDLE_MISSING",
34571
+ "INVALID_CONTEXT_INPUT",
34572
+ "CONTEXT_INPUT_TOO_LARGE",
34573
+ "INVALID_CONTEXT_BUDGET",
34574
+ "INVALID_SELECTION",
34575
+ "INVALID_SELECTION_ALIASES",
34576
+ "INVALID_RECEIPT",
34577
+ "INVALID_CACHE_FILE",
34578
+ "UNSAFE_CACHE_PATH",
34579
+ "RECEIPT_TOO_LARGE",
34580
+ "BUNDLE_DIGEST_MISMATCH",
34581
+ "BUNDLE_IDENTITY_MISMATCH",
34582
+ "BUNDLE_UNAVAILABLE",
34583
+ "BUNDLE_TOO_LARGE",
34584
+ "SKILL_NOT_SELECTED",
34585
+ "INVALID_SESSION",
34586
+ "SESSION_PARENT_NOT_FOUND",
34587
+ "SESSION_PARENT_MISMATCH",
34588
+ "SESSION_NOT_FOUND",
34589
+ "SESSION_GENERATION_CHANGED",
34590
+ "SESSION_GENERATION_EXHAUSTED",
34591
+ "SESSION_PARENT_CHANGED",
34592
+ "SESSION_RECEIPT_CHANGED",
34593
+ "SESSION_RECONCILIATION_REQUIRED",
34594
+ "SESSION_RENEWAL_TIMEOUT",
34595
+ "SESSION_CONTEXT_CONFLICT",
34596
+ "SESSION_RECONCILIATION_INCOMPLETE",
34597
+ "SESSION_WRITE_LOCKED",
34598
+ "SESSION_WRITE_LOCK_CHANGED",
34599
+ "SESSION_LOCK_RECOVERY_INCOMPLETE"
34600
+ ]);
34601
+ HOOK_REFUSAL_REASON_CODES = Object.freeze([
34602
+ ...CONTEXT_ERROR_CODES,
34603
+ "SKILLS_HOOK_FAILED",
34604
+ "SKILLS_HOOK_TIMEOUT",
34605
+ "SKILLS_HOOK_INVALID_RESPONSE"
34606
+ ]);
34607
+ OPTIONAL_CONTEXT_FAILURES = new Set([
34608
+ "SKILLS_API_CREDENTIAL_UNAVAILABLE",
34609
+ "SKILLS_API_UNAVAILABLE",
34610
+ "SKILLS_API_UNAUTHORIZED",
34611
+ "SKILLS_API_FORBIDDEN",
34612
+ "SKILLS_API_RESOURCE_UNAVAILABLE",
34613
+ "CACHED_PROFILE_EXPIRED",
34614
+ "CACHED_PROFILE_MISSING",
34615
+ "CACHED_BUNDLE_MISSING",
34616
+ "SESSION_RECONCILIATION_REQUIRED",
34617
+ "SESSION_RENEWAL_TIMEOUT",
34618
+ "SESSION_WRITE_BUSY",
34619
+ "SESSION_PARENT_CHANGED",
34620
+ "SESSION_CONTEXT_CONFLICT",
34621
+ "SKILLS_HOOK_TIMEOUT"
34622
+ ]);
34623
+ });
34624
+
34340
34625
  // src/lib/agent-sumi.ts
34341
34626
  import { spawnSync as spawnSync4 } from "child_process";
34342
34627
  import { accessSync, constants as constants9, existsSync as existsSync8, lstatSync as lstatSync15, realpathSync as realpathSync7, statSync as statSync7 } from "fs";
@@ -34464,6 +34749,7 @@ function sumiConfigPath(home, cwd = process.cwd(), env = process.env) {
34464
34749
  }
34465
34750
  var SUMI_PATH_SELECTORS, SUMI_PATH_KEYS, SUMI_PATH_OUTPUT_LIMIT, SumiPathResolverError;
34466
34751
  var init_agent_sumi = __esm(() => {
34752
+ init_hook_diagnostics();
34467
34753
  SUMI_PATH_SELECTORS = ["SUMI_HOME", "SUMI_CONFIG_DIR", "XDG_DATA_HOME", "XDG_CACHE_HOME", "XDG_CONFIG_HOME", "XDG_STATE_HOME"];
34468
34754
  SUMI_PATH_KEYS = ["data", "cache", "config", "state"];
34469
34755
  SUMI_PATH_OUTPUT_LIMIT = 128 * 1024;
@@ -35904,7 +36190,7 @@ var init_plugin_admission = __esm(() => {
35904
36190
 
35905
36191
  // src/lib/plugin-discovery.ts
35906
36192
  import { closeSync as closeSync15, constants as constants13, fstatSync as fstatSync15, lstatSync as lstatSync19, openSync as openSync15, opendirSync as opendirSync3, readSync as readSync10 } from "fs";
35907
- import { basename as basename7, dirname as dirname17, isAbsolute as isAbsolute17, join as join28, resolve as resolve18 } from "path";
36193
+ import { basename as basename8, dirname as dirname17, isAbsolute as isAbsolute17, join as join28, resolve as resolve18 } from "path";
35908
36194
  function validateManagedPluginWitnesses(value) {
35909
36195
  pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
35910
36196
  const seen = new Set;
@@ -35987,7 +36273,7 @@ function hashManagedPluginRegistry(path, managed) {
35987
36273
  pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join28(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
35988
36274
  const approval = (producer) => {
35989
36275
  pluginText(producer);
35990
- const digest2 = `sha256:${basename7(producer)}`;
36276
+ const digest2 = `sha256:${basename8(producer)}`;
35991
36277
  const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest2);
35992
36278
  pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
35993
36279
  if (!verified.has(producer)) {
@@ -36053,7 +36339,7 @@ var init_plugin_discovery = __esm(() => {
36053
36339
  // src/lib/claude-marketplace-registry.ts
36054
36340
  import { createHash as createHash19 } from "crypto";
36055
36341
  import { closeSync as closeSync16, constants as constants14, fstatSync as fstatSync16, lstatSync as lstatSync20, openSync as openSync16, readSync as readSync11 } from "fs";
36056
- import { basename as basename8, dirname as dirname18, isAbsolute as isAbsolute18, resolve as resolve19 } from "path";
36342
+ import { basename as basename9, dirname as dirname18, isAbsolute as isAbsolute18, resolve as resolve19 } from "path";
36057
36343
  function need8(value, reason2) {
36058
36344
  if (!value)
36059
36345
  throw new Error(`Claude marketplace registry ${reason2}`);
@@ -36073,7 +36359,7 @@ function parents2(path) {
36073
36359
  }
36074
36360
  function readRegistry2(path, budget2) {
36075
36361
  absolutePath4(path);
36076
- need8(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
36362
+ need8(basename9(path) === "known_marketplaces.json", "requires known_marketplaces.json");
36077
36363
  need8(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
36078
36364
  const ancestors2 = parents2(path), initial = lstatSync20(path, { bigint: true });
36079
36365
  need8(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
@@ -36281,7 +36567,7 @@ var init_codex_hook_discovery_recovery = __esm(() => {
36281
36567
  // src/lib/agent-discovery.ts
36282
36568
  import { createHash as createHash21 } from "crypto";
36283
36569
  import { lstatSync as lstatSync21, readFileSync as readFileSync16, readdirSync as readdirSync8, realpathSync as realpathSync8 } from "fs";
36284
- import { basename as basename9, dirname as dirname19, isAbsolute as isAbsolute19, join as join29, relative as relative7, resolve as resolve20, sep as sep9 } from "path";
36570
+ import { basename as basename10, dirname as dirname19, isAbsolute as isAbsolute19, join as join29, relative as relative7, resolve as resolve20, sep as sep9 } from "path";
36285
36571
  import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
36286
36572
  function discoveryExecutable(agent) {
36287
36573
  const command = DISCOVERY_RUNTIME_COMMANDS[agent];
@@ -36348,7 +36634,7 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical9) {
36348
36634
  throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
36349
36635
  }
36350
36636
  if ([cacheAliasRoot, cacheRoot].some((root) => row.installPath === root || row.installPath.startsWith(root + sep9))) {
36351
- if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename9(row.installPath) !== row.version)) {
36637
+ if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename10(row.installPath) !== row.version)) {
36352
36638
  throw new Error("Reviewed Claude discovery has a malformed active cache registration");
36353
36639
  }
36354
36640
  if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" && isAbsolute19(row.projectPath) && resolve20(row.projectPath) === row.projectPath && row.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters) {} else
@@ -36610,7 +36896,7 @@ function absentRetiredClaudeRoots(binding) {
36610
36896
  if (!targetValid || !targetScopes.has("user\x00"))
36611
36897
  continue;
36612
36898
  const active = rows[0]?.installPath;
36613
- if (typeof active !== "string" || rows[0]?.version !== basename9(active) || dirname19(active) !== dirname19(root) || active === root || !lstatSync21(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync8(active) !== active)
36899
+ if (typeof active !== "string" || rows[0]?.version !== basename10(active) || dirname19(active) !== dirname19(root) || active === root || !lstatSync21(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync8(active) !== active)
36614
36900
  continue;
36615
36901
  const activeManifest = full(join29(active, ".claude-plugin/plugin.json"));
36616
36902
  if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
@@ -36619,14 +36905,15 @@ function absentRetiredClaudeRoots(binding) {
36619
36905
  }
36620
36906
  return [...result];
36621
36907
  }
36622
- function codexSemanticCacheSourceRole(source, cacheRoot, parents3) {
36908
+ function codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParents = []) {
36623
36909
  if (!isAbsolute19(source.path) || resolve20(source.path) !== source.path || /[\x00-\x1f\x7f]/.test(source.path) || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.reviewArtifact !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes")
36624
36910
  return false;
36625
36911
  const parts = relative7(cacheRoot, source.path).split(sep9);
36626
36912
  if (parts.length < 3 || !parents3.includes(join29(cacheRoot, parts[0], parts[1])))
36627
36913
  return false;
36628
36914
  const tail = parts.slice(3).join("/");
36629
- return parts.length === 5 && tail === ".codex-plugin/plugin.json" && source.sha256 !== null || parts.length === 4 && [".app.json", ".mcp.json"].includes(tail) && source.sha256 !== null || source.sha256 === null && (parts.length === 4 && tail === "SKILL.md" || parts.length === 5 && tail === "hooks/hooks.json");
36915
+ const parent = join29(cacheRoot, parts[0], parts[1]);
36916
+ return parts.length === 5 && tail === ".codex-plugin/plugin.json" && source.sha256 !== null || parts.length === 4 && [".app.json", ".mcp.json"].includes(tail) && source.sha256 !== null || parts.length === 5 && tail === "hooks/hooks.json" && hookParents.includes(parent) && source.sha256 !== null || source.sha256 === null && (parts.length === 4 && tail === "SKILL.md" || parts.length === 5 && tail === "hooks/hooks.json");
36630
36917
  }
36631
36918
  function codexSemanticCacheDirectoryRole(path, cacheRoot) {
36632
36919
  return isAbsolute19(path) && resolve20(path) === path && !/[\x00-\x1f\x7f]/.test(path) && (path === cacheRoot || path.startsWith(cacheRoot + sep9));
@@ -36658,20 +36945,28 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
36658
36945
  const cacheRoot = proof.witness.cacheRoot;
36659
36946
  if (controls.some((control) => dirname19(dirname19(control.pluginParent)) !== cacheRoot))
36660
36947
  throw new Error("Codex semantic cache names another enrolled cache");
36661
- const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...proof.appOnlyParents.map((parent) => parent.pluginParent)])];
36662
- const sources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3));
36948
+ const reviewedHookParents = proof.reviewedHookParents ?? [];
36949
+ if (!Array.isArray(reviewedHookParents) || reviewedHookParents.length > 4096 || reviewedHookParents.some((parent) => !parent || !(parent.installation === "remote-receipt" && Object.keys(parent).sort().join(",") === "installation,namespace,pluginId,pluginParent,remotePluginId,role" && typeof parent.remotePluginId === "string" || parent.installation === "local-marketplace" && Object.keys(parent).sort().join(",") === "installation,marketplaceSha256,marketplaceSourcePath,namespace,pluginId,pluginParent,role" && typeof parent.marketplaceSourcePath === "string" && /^[a-f0-9]{64}$/.test(parent.marketplaceSha256 ?? "")) || parent.role !== "reviewed-hook" || typeof parent.pluginId !== "string" || typeof parent.namespace !== "string" || typeof parent.pluginParent !== "string") || new Set(reviewedHookParents.map((parent) => parent.pluginParent)).size !== reviewedHookParents.length || !isDeepStrictEqual4((proof.witness.hookParents ?? []).map(({ manifestSha256: _manifest, hooksSha256: _hooks, receiptSha256: _receipt, ...parent }) => parent), reviewedHookParents)) {
36950
+ throw new Error("Invalid reviewed native-hook cache role");
36951
+ }
36952
+ for (const parent of reviewedHookParents)
36953
+ if (parent.installation === "local-marketplace" && !binding.sources.some((source) => source.path === parent.marketplaceSourcePath && source.sha256 === parent.marketplaceSha256 && source.sha256 !== null && source.format === undefined && source.fields === undefined && source.reviewArtifact === undefined && (source.hashMode === undefined || source.hashMode === "bytes")))
36954
+ throw new Error("Local marketplace hook parent lost its enrolled source witness");
36955
+ const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...proof.appOnlyParents.map((parent) => parent.pluginParent), ...reviewedHookParents.map((parent) => parent.pluginParent)])];
36956
+ const hookParentPaths = reviewedHookParents.map((parent) => parent.pluginParent);
36957
+ const sources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParentPaths));
36663
36958
  const directories = (binding.directories ?? []).filter((directory) => codexSemanticCacheDirectoryRole(directory.path, cacheRoot));
36664
36959
  if (!directories.length || !isDeepStrictEqual4(sources, proof.supersededSources) || !isDeepStrictEqual4(directories, proof.supersededDirectories))
36665
36960
  throw new Error("Codex semantic cache provenance changed");
36666
36961
  const configPath = proof.configPath;
36667
- if (!isAbsolute19(configPath) || resolve20(configPath) !== configPath || basename9(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
36962
+ if (!isAbsolute19(configPath) || resolve20(configPath) !== configPath || basename10(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
36668
36963
  throw new Error("Invalid semantic cache configuration source");
36669
36964
  const configSource = binding.sources.find((source) => source.path === configPath && source.sha256 !== null && source.format === undefined && source.fields === undefined);
36670
36965
  if (!configSource || projected(configSource) !== configSource.sha256)
36671
36966
  throw new Error("Codex semantic cache requires unchanged reviewed configuration");
36672
36967
  assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, proof.hookRootAlias);
36673
36968
  const rules = parseConfig(read(configPath), configPath, true).skills?.config ?? [];
36674
- const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, rules });
36969
+ const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, reviewedHookParents, rules });
36675
36970
  assertCodexSemanticCacheWitnessUnchanged(proof.witness, current);
36676
36971
  return proof;
36677
36972
  }
@@ -36755,7 +37050,7 @@ function codexInstallationRoots(binding) {
36755
37050
  const config2 = join29(dirname19(dirname19(cache)), "config.toml"), home = dirname19(dirname19(dirname19(cache)));
36756
37051
  const configSource = binding.sources.find((source) => source.path === config2 && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
36757
37052
  const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join29(home, path));
36758
- if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot + sep9) || input2.sourceRoot.startsWith(root + sep9)) || binding.sources.some((source) => basename9(source.path) === "config.toml" && (source.path === input2.sourceRoot || source.path.startsWith(input2.sourceRoot + sep9)))))
37053
+ if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot + sep9) || input2.sourceRoot.startsWith(root + sep9)) || binding.sources.some((source) => basename10(source.path) === "config.toml" && (source.path === input2.sourceRoot || source.path.startsWith(input2.sourceRoot + sep9)))))
36759
37054
  throw new Error("Native installation input overlaps configuration or loading roots");
36760
37055
  if (proof.plugins.some((input2) => dirname19(dirname19(input2.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join29(input2.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
36761
37056
  throw new Error("Missing native installation input source witness");
@@ -36767,13 +37062,13 @@ function codexInstallationRoots(binding) {
36767
37062
  });
36768
37063
  }
36769
37064
  function assertMarketplaceBinding(binding, source) {
36770
- if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json"))))
37065
+ if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename10(source.path) !== "plugin.json" || !source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json"))))
36771
37066
  throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
36772
- if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename9(source.path) !== "sumi.json"))
37067
+ if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename10(source.path) !== "sumi.json"))
36773
37068
  throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
36774
- if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4" || source.hashMode === "codex-settings-v5")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
37069
+ if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4" || source.hashMode === "codex-settings-v5")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename10(source.path) !== "config.toml"))
36775
37070
  throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
36776
- if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) && (binding.agent !== "claude" || binding.method !== "reviewed" || basename9(source.path) !== "settings.json"))
37071
+ if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) && (binding.agent !== "claude" || binding.method !== "reviewed" || basename10(source.path) !== "settings.json"))
36777
37072
  throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
36778
37073
  if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
36779
37074
  throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
@@ -36922,7 +37217,7 @@ function resolveAgentDiscovery(options) {
36922
37217
  throw new Error("Discovery review must include the agent configuration source");
36923
37218
  const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical9(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical9(configPath), source)) : sources;
36924
37219
  const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
36925
- if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json")))
37220
+ if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename10(source.path) !== "plugin.json" || !source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json")))
36926
37221
  return source;
36927
37222
  const pluginRoot = dirname19(dirname19(source.path)), hooksPath = join29(pluginRoot, "hooks/hooks.json");
36928
37223
  const hookStat = lstatSync21(hooksPath, { throwIfNoEntry: false });
@@ -37102,7 +37397,7 @@ var init_agent_discovery = __esm(() => {
37102
37397
  // src/lib/authoring-path.ts
37103
37398
  import { lstatSync as lstatSync22, realpathSync as realpathSync9 } from "fs";
37104
37399
  import { homedir as homedir3 } from "os";
37105
- import { basename as basename10, dirname as dirname20, join as join30, resolve as resolve21, sep as sep10 } from "path";
37400
+ import { basename as basename11, dirname as dirname20, join as join30, resolve as resolve21, sep as sep10 } from "path";
37106
37401
  function pathParts(path) {
37107
37402
  return resolve21(path).split(sep10).filter(Boolean);
37108
37403
  }
@@ -37121,7 +37416,7 @@ function physicalPath(path) {
37121
37416
  let cursor = resolve21(path);
37122
37417
  const suffix = [];
37123
37418
  while (!lstatSync22(cursor, { throwIfNoEntry: false })) {
37124
- suffix.unshift(basename10(cursor));
37419
+ suffix.unshift(basename11(cursor));
37125
37420
  const parent = dirname20(cursor);
37126
37421
  if (parent === cursor)
37127
37422
  return resolve21(path);
@@ -37216,7 +37511,7 @@ import {
37216
37511
  statSync as statSync8,
37217
37512
  writeFileSync as writeFileSync6
37218
37513
  } from "fs";
37219
- import { basename as basename11, dirname as dirname21, isAbsolute as isAbsolute20, join as join31, normalize as normalize4, relative as relative8, resolve as resolve22, sep as sep11 } from "path";
37514
+ import { basename as basename12, dirname as dirname21, isAbsolute as isAbsolute20, join as join31, normalize as normalize4, relative as relative8, resolve as resolve22, sep as sep11 } from "path";
37220
37515
  function getPortableSkillsRoot(options = {}) {
37221
37516
  return resolvePortableSkillsRoot(options, true);
37222
37517
  }
@@ -37314,7 +37609,7 @@ function physicalImportPath(path) {
37314
37609
  let ancestor = resolve22(path);
37315
37610
  const suffix = [];
37316
37611
  while (!existsSync12(ancestor)) {
37317
- suffix.unshift(basename11(ancestor));
37612
+ suffix.unshift(basename12(ancestor));
37318
37613
  ancestor = dirname21(ancestor);
37319
37614
  }
37320
37615
  return join31(realpathSync10(ancestor), ...suffix);
@@ -37339,8 +37634,8 @@ function portPortableSkill(sourcePath, options = {}) {
37339
37634
  const explicitName = options.name != null;
37340
37635
  const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
37341
37636
  if (isOfficialSkillName(skillName) && !options.allowShadow) {
37342
- const sourceSlug = safeNormalizeName(basename11(absoluteSource));
37343
- const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename11(absoluteSource)}')` : ""} matches a bundled official skill.`;
37637
+ const sourceSlug = safeNormalizeName(basename12(absoluteSource));
37638
+ const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename12(absoluteSource)}')` : ""} matches a bundled official skill.`;
37344
37639
  throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
37345
37640
  }
37346
37641
  const readOnlyDestination = join31(resolvePortableSkillsRoot(options, false), skillName);
@@ -38969,13 +39264,13 @@ var init_remote_workspace_leave = __esm(() => {
38969
39264
 
38970
39265
  // src/lib/auth-store.ts
38971
39266
  import { chmodSync, existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync18, renameSync as renameSync4, statSync as statSync9, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
38972
- import { basename as basename12, dirname as dirname22, join as join33 } from "path";
39267
+ import { basename as basename13, dirname as dirname22, join as join33 } from "path";
38973
39268
  function getAuthFilePath(env = process.env) {
38974
39269
  return skillsCredentialFilePath(env);
38975
39270
  }
38976
39271
  function getIdentityFilePath(env = process.env) {
38977
39272
  const file2 = skillsCredentialFilePath(env);
38978
- return join33(dirname22(file2), basename12(file2).replace(/^credentials/, "identity") + ".json");
39273
+ return join33(dirname22(file2), basename13(file2).replace(/^credentials/, "identity") + ".json");
38979
39274
  }
38980
39275
  function getApiUrl(action, env = process.env, options = {}) {
38981
39276
  return requireSkillsApiOrigin(action, env, options);