@hasna/skills 0.10.65 → 0.10.67

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.65",
26
+ version: "0.10.67",
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,27 @@ 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
+ const marketplaceInterface = plainObject(value) ? value.interface : undefined;
33710
+ const validInterface = typeof marketplaceInterface === "string" || Number.isSafeInteger(marketplaceInterface) || plainObject(marketplaceInterface) && exactKeys(marketplaceInterface, [], ["displayName"]) && typeof marketplaceInterface.displayName === "string" && marketplaceInterface.displayName.trim().length > 0;
33711
+ if (!plainObject(value) || !exactKeys(value, ["interface", "name", "plugins"]) || value.name !== marketplace || !validInterface || !Array.isArray(value.plugins) || value.plugins.length < 1 || value.plugins.length > 4096)
33712
+ return false;
33713
+ const rows = value.plugins.filter((row2) => plainObject(row2) && row2.name === plugin);
33714
+ if (rows.length !== 1)
33715
+ return false;
33716
+ const row = rows[0];
33717
+ 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("\\"))
33718
+ return false;
33719
+ const parts = row.source.path.split("/");
33720
+ 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;
33721
+ } catch {
33722
+ return false;
33723
+ }
33724
+ }
33671
33725
  function defaultRead(path) {
33672
33726
  const before = lstatSync13(path, { throwIfNoEntry: false, bigint: true });
33673
33727
  if (before === undefined)
@@ -33729,7 +33783,7 @@ function validPluginParent(cacheRoot, pluginParent, namespace, pluginId) {
33729
33783
  return parts.length === 2 && parts.every(identifier3) && parts[1] === namespace && pluginId === `${namespace}@${parts[0]}`;
33730
33784
  }
33731
33785
  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)
33786
+ 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
33787
  refuse3();
33734
33788
  const witness = value;
33735
33789
  const controlParents = new Set;
@@ -33750,6 +33804,20 @@ function assertWitnessShape(value) {
33750
33804
  refuse3();
33751
33805
  appOnlyParentPaths.add(row.pluginParent);
33752
33806
  }
33807
+ const hookParentPaths = new Set;
33808
+ const hookParents = witness.hookParents === undefined ? [] : witness.hookParents;
33809
+ if (!Array.isArray(hookParents) || hookParents.length > 4096)
33810
+ refuse3();
33811
+ for (const candidate of hookParents) {
33812
+ if (!plainObject(candidate))
33813
+ refuse3();
33814
+ const row = candidate;
33815
+ const remote = row.installation === "remote-receipt";
33816
+ const local = row.installation === "local-marketplace";
33817
+ 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))
33818
+ refuse3();
33819
+ hookParentPaths.add(row.pluginParent);
33820
+ }
33753
33821
  const skillNames = new Set;
33754
33822
  const qualifiedNames = new Set;
33755
33823
  for (const candidate of witness.skills) {
@@ -33769,6 +33837,7 @@ function assertWitnessShape(value) {
33769
33837
  cacheRoot: witness.cacheRoot,
33770
33838
  controls: witness.controls,
33771
33839
  appOnlyParents: witness.appOnlyParents,
33840
+ ...witness.hookParents === undefined ? {} : { hookParents: witness.hookParents },
33772
33841
  skills: witness.skills
33773
33842
  };
33774
33843
  if (hash3(projection) !== witness.sha256)
@@ -33959,10 +34028,128 @@ function appOnlyParentProjection(cacheRoot, parents2, read) {
33959
34028
  }
33960
34029
  return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
33961
34030
  }
33962
- function assertParents(cacheRoot, controls, appOnlyParents, files, members2) {
34031
+ function assertJsonValue(value, depth = 0, budget2 = { members: 0 }) {
34032
+ if (depth > 32 || ++budget2.members > 4096)
34033
+ refuse3();
34034
+ if (value === null || typeof value === "string" || typeof value === "boolean")
34035
+ return;
34036
+ if (typeof value === "number" && Number.isFinite(value))
34037
+ return;
34038
+ if (Array.isArray(value)) {
34039
+ for (const item of value)
34040
+ assertJsonValue(item, depth + 1, budget2);
34041
+ return;
34042
+ }
34043
+ if (!plainObject(value))
34044
+ refuse3();
34045
+ for (const [key, item] of Object.entries(value)) {
34046
+ if (!key || /[\x00-\x1f\x7f]/.test(key))
34047
+ refuse3();
34048
+ assertJsonValue(item, depth + 1, budget2);
34049
+ }
34050
+ }
34051
+ function reviewedHookControls(root, read) {
34052
+ const manifestPath = join19(root, ".codex-plugin/plugin.json"), hooksPath = join19(root, "hooks/hooks.json");
34053
+ let manifest, manifestSha256, hooks, hooksSha256;
34054
+ try {
34055
+ const manifestText = read(manifestPath);
34056
+ manifestSha256 = hashNativeJsonControls(manifestText, "version");
34057
+ manifest = JSON.parse(manifestText);
34058
+ const hooksText = read(hooksPath);
34059
+ hashNativeJsonControls(hooksText);
34060
+ hooksSha256 = createHash14("sha256").update(hooksText).digest("hex");
34061
+ hooks = JSON.parse(hooksText);
34062
+ } catch {
34063
+ return refuse3();
34064
+ }
34065
+ 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))
34066
+ refuse3();
34067
+ const manifestRecord = manifest;
34068
+ if (!plainObject(hooks) || !exactKeys(hooks, ["hooks"], ["description"]) || !plainObject(hooks.hooks) || hooks.description !== undefined && typeof hooks.description !== "string")
34069
+ refuse3();
34070
+ const hookTable = hooks.hooks;
34071
+ const events = Object.entries(hookTable);
34072
+ if (!events.length || events.length > 32)
34073
+ refuse3();
34074
+ for (const [event, groups] of events) {
34075
+ if (!codexHookEvents.has(event) || !Array.isArray(groups) || !groups.length || groups.length > 32)
34076
+ refuse3();
34077
+ for (const group of groups) {
34078
+ if (!plainObject(group) || !exactKeys(group, ["hooks"]) || !Array.isArray(group.hooks) || !group.hooks.length || group.hooks.length > 32)
34079
+ refuse3();
34080
+ const handlers = group.hooks;
34081
+ for (const handler of handlers) {
34082
+ 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))
34083
+ refuse3();
34084
+ assertJsonValue(handler.input);
34085
+ }
34086
+ }
34087
+ }
34088
+ return { namespace: manifestRecord.name, manifestSha256, hooksSha256 };
34089
+ }
34090
+ function reviewedHookParentProjection(cacheRoot, parents2, read) {
34091
+ if (!Array.isArray(parents2) || parents2.length > 4096)
34092
+ refuse3();
34093
+ const seen = new Set, rows = [];
34094
+ for (const parent of parents2) {
34095
+ const remote = parent?.installation === "remote-receipt", local = parent?.installation === "local-marketplace";
34096
+ 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)
34097
+ refuse3();
34098
+ const parts = relative6(cacheRoot, parent.pluginParent).split(sep7);
34099
+ 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))
34100
+ refuse3();
34101
+ seen.add(parent.pluginParent);
34102
+ const parentStat = lstatSync13(parent.pluginParent, { throwIfNoEntry: false });
34103
+ if (!parentStat?.isDirectory() || parentStat.isSymbolicLink() || realpathSync6(parent.pluginParent) !== parent.pluginParent)
34104
+ refuse3();
34105
+ const receiptPath = join19(parent.pluginParent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync13(receiptPath, { throwIfNoEntry: false });
34106
+ let receiptText;
34107
+ if (remote) {
34108
+ if (!receiptStat?.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > MAX_RECEIPT_BYTES)
34109
+ refuse3();
34110
+ try {
34111
+ receiptText = read(receiptPath);
34112
+ hashNativeJsonControls(receiptText);
34113
+ const receipt = JSON.parse(receiptText);
34114
+ if (!plainObject(receipt) || !exactKeys(receipt, ["schema_version", "remote_plugin_id"]) || receipt.schema_version !== 1 || receipt.remote_plugin_id !== parent.remotePluginId)
34115
+ refuse3();
34116
+ } catch {
34117
+ refuse3();
34118
+ }
34119
+ } else {
34120
+ const marketplaceSourcePath = parent.marketplaceSourcePath ?? refuse3();
34121
+ if (receiptStat !== undefined || !parent.marketplaceSha256)
34122
+ refuse3();
34123
+ let marketplaceText;
34124
+ try {
34125
+ marketplaceText = read(marketplaceSourcePath);
34126
+ } catch {
34127
+ return refuse3();
34128
+ }
34129
+ if (createHash14("sha256").update(marketplaceText).digest("hex") !== parent.marketplaceSha256 || !codexLocalMarketplaceMapsPlugin(marketplaceText, parts[0], parent.namespace))
34130
+ refuse3();
34131
+ }
34132
+ const materializations = readdirSync7(parent.pluginParent).filter((name) => name !== ".codex-remote-plugin-install.json").map((version2) => {
34133
+ if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
34134
+ refuse3();
34135
+ const root = join19(parent.pluginParent, version2), stat = lstatSync13(root, { throwIfNoEntry: false });
34136
+ if (!stat?.isDirectory() || stat.isSymbolicLink() || realpathSync6(root) !== root)
34137
+ refuse3();
34138
+ const controls = reviewedHookControls(root, read);
34139
+ if (controls.namespace !== parent.namespace)
34140
+ refuse3();
34141
+ return { manifestSha256: controls.manifestSha256, hooksSha256: controls.hooksSha256 };
34142
+ });
34143
+ if (!materializations.length || materializations.some((item) => canonical7(item) !== canonical7(materializations[0])))
34144
+ refuse3();
34145
+ rows.push({ ...parent, ...receiptText === undefined ? {} : { receiptSha256: createHash14("sha256").update(receiptText).digest("hex") }, ...materializations[0] });
34146
+ }
34147
+ return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
34148
+ }
34149
+ function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files, members2) {
33963
34150
  const expected = new Set;
33964
34151
  const expectedMarkets = new Set;
33965
- for (const control of [...controls, ...appOnlyParents]) {
34152
+ for (const control of [...controls, ...appOnlyParents, ...hookParents]) {
33966
34153
  const rel = relative6(cacheRoot, control.pluginParent), parts = rel.split(sep7);
33967
34154
  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
34155
  refuse3();
@@ -34003,7 +34190,9 @@ function assertParents(cacheRoot, controls, appOnlyParents, files, members2) {
34003
34190
  refuse3();
34004
34191
  if ([".app.json", ".mcp.json"].includes(base) && (parts.length !== 4 || dirname13(member) !== root))
34005
34192
  refuse3();
34006
- if (parts.includes("hooks"))
34193
+ if ([".app.json", ".mcp.json"].includes(base) && hookParents.some((reviewed) => reviewed.pluginParent === parent))
34194
+ refuse3();
34195
+ if ((parts[3] === "hooks" || base === "hooks.json") && (![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
34196
  refuse3();
34008
34197
  }
34009
34198
  }
@@ -34113,13 +34302,14 @@ function captureCodexSemanticCacheWitness(options) {
34113
34302
  const initialTree = treeSnapshot(options.cacheRoot);
34114
34303
  const controls = controlProjection(options.controls, read);
34115
34304
  const appOnlyParents = appOnlyParentProjection(options.cacheRoot, options.appOnlyParents ?? [], read);
34305
+ const hookParents = reviewedHookParentProjection(options.cacheRoot, options.reviewedHookParents ?? [], read);
34116
34306
  const skillParents = new Set(controls.map((control) => control.pluginParent));
34117
- if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)))
34307
+ if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)) || hookParents.some((parent) => skillParents.has(parent.pluginParent) || appOnlyParents.some((app) => app.pluginParent === parent.pluginParent)))
34118
34308
  refuse3();
34119
34309
  if (!reviewedCodexPluginCapabilitiesUnchanged(options.cacheRoot, options.controls, read, options.rules))
34120
34310
  refuse3();
34121
34311
  const files = initialTree.files;
34122
- assertParents(options.cacheRoot, controls, appOnlyParents, files, initialTree.state.members);
34312
+ assertParents(options.cacheRoot, controls, appOnlyParents, hookParents, files, initialTree.state.members);
34123
34313
  const expectedNamesByRoot = assertSkillMaterializations(options.cacheRoot, options.controls, files, read);
34124
34314
  const docs = files.filter((path) => path.endsWith(`${sep7}SKILL.md`));
34125
34315
  const skillRows = [];
@@ -34128,6 +34318,8 @@ function captureCodexSemanticCacheWitness(options) {
34128
34318
  const rel = relative6(options.cacheRoot, document2).split(sep7);
34129
34319
  if (appOnlyParents.some((parent) => parent.pluginParent === join19(options.cacheRoot, rel[0], rel[1])))
34130
34320
  refuse3();
34321
+ if (hookParents.some((parent) => parent.pluginParent === join19(options.cacheRoot, rel[0], rel[1])))
34322
+ refuse3();
34131
34323
  const documentStat = lstatSync13(document2, { throwIfNoEntry: false });
34132
34324
  if (!documentStat?.isFile() || documentStat.isSymbolicLink() || documentStat.size > MAX_DOCUMENT_BYTES)
34133
34325
  refuse3();
@@ -34191,7 +34383,7 @@ function captureCodexSemanticCacheWitness(options) {
34191
34383
  tracked.verify();
34192
34384
  const finalTree = treeSnapshot(options.cacheRoot);
34193
34385
  assertSameTree(initialTree.state, finalTree.state, tracked.paths());
34194
- const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, skills: uniqueSkills };
34386
+ const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, hookParents, skills: uniqueSkills };
34195
34387
  return { ...completeProjection, sha256: hash3(completeProjection) };
34196
34388
  } catch (error61) {
34197
34389
  if (error61 instanceof Error && error61.message.startsWith("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED"))
@@ -34207,6 +34399,7 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
34207
34399
  cacheRoot: previous.cacheRoot,
34208
34400
  controls: previous.controls,
34209
34401
  appOnlyParents: previous.appOnlyParents,
34402
+ ...previous.hookParents === undefined ? {} : { hookParents: previous.hookParents },
34210
34403
  skills: previous.skills
34211
34404
  };
34212
34405
  const currentProjection = {
@@ -34214,20 +34407,41 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
34214
34407
  cacheRoot: current.cacheRoot,
34215
34408
  controls: current.controls,
34216
34409
  appOnlyParents: current.appOnlyParents,
34410
+ ...current.hookParents === undefined ? {} : { hookParents: current.hookParents },
34217
34411
  skills: current.skills
34218
34412
  };
34219
- if (hash3(priorProjection) !== previous.sha256 || hash3(currentProjection) !== current.sha256 || canonical7(priorProjection) !== canonical7(currentProjection))
34413
+ const comparable = (projection) => ({ ...projection, hookParents: projection.hookParents ?? [] });
34414
+ if (hash3(priorProjection) !== previous.sha256 || hash3(currentProjection) !== current.sha256 || canonical7(comparable(priorProjection)) !== canonical7(comparable(currentProjection)))
34220
34415
  refuse3();
34221
34416
  }
34222
34417
  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
34418
  throw new Error("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED: review Codex plugin cache identity and controls");
34224
- }, MAX_DOCUMENT_BYTES, MAX_RECEIPT_BYTES;
34419
+ }, MAX_DOCUMENT_BYTES, MAX_RECEIPT_BYTES, codexHookEvents;
34225
34420
  var init_codex_semantic_cache_witness = __esm(() => {
34226
34421
  init_claude_settings_witness();
34227
34422
  init_codex_plugin_skill_controls();
34228
34423
  init_codex_native_skill_catalog();
34229
34424
  MAX_DOCUMENT_BYTES = 1024 * 1024;
34230
34425
  MAX_RECEIPT_BYTES = 16 * 1024;
34426
+ codexHookEvents = new Set([
34427
+ "SessionStart",
34428
+ "UserPromptSubmit",
34429
+ "PreToolUse",
34430
+ "PostToolUse",
34431
+ "PostToolUseFailure",
34432
+ "Stop",
34433
+ "SubagentStart",
34434
+ "SubagentStop",
34435
+ "PreCompact",
34436
+ "Notification",
34437
+ "PermissionRequest",
34438
+ "SessionEnd",
34439
+ "ConfigChange",
34440
+ "WorktreeCreate",
34441
+ "WorktreeRemove",
34442
+ "TeammateIdle",
34443
+ "TaskComplete"
34444
+ ]);
34231
34445
  });
34232
34446
 
34233
34447
  // src/lib/managed-policy.ts
@@ -35263,9 +35477,7 @@ function detectProjectSkills(cwd = process.cwd()) {
35263
35477
  function extractEnvVars(text2) {
35264
35478
  const envVars = new Set;
35265
35479
  for (const pattern of [ENV_VAR_PATTERN, GENERIC_ENV_PATTERN]) {
35266
- pattern.lastIndex = 0;
35267
- let match;
35268
- while ((match = pattern.exec(text2)) !== null) {
35480
+ for (const match of text2.matchAll(pattern)) {
35269
35481
  envVars.add(match[1]);
35270
35482
  }
35271
35483
  }
@@ -35978,7 +36190,7 @@ var init_plugin_admission = __esm(() => {
35978
36190
 
35979
36191
  // src/lib/plugin-discovery.ts
35980
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";
35981
- 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";
35982
36194
  function validateManagedPluginWitnesses(value) {
35983
36195
  pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
35984
36196
  const seen = new Set;
@@ -36061,7 +36273,7 @@ function hashManagedPluginRegistry(path, managed) {
36061
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");
36062
36274
  const approval = (producer) => {
36063
36275
  pluginText(producer);
36064
- const digest2 = `sha256:${basename7(producer)}`;
36276
+ const digest2 = `sha256:${basename8(producer)}`;
36065
36277
  const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest2);
36066
36278
  pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
36067
36279
  if (!verified.has(producer)) {
@@ -36127,7 +36339,7 @@ var init_plugin_discovery = __esm(() => {
36127
36339
  // src/lib/claude-marketplace-registry.ts
36128
36340
  import { createHash as createHash19 } from "crypto";
36129
36341
  import { closeSync as closeSync16, constants as constants14, fstatSync as fstatSync16, lstatSync as lstatSync20, openSync as openSync16, readSync as readSync11 } from "fs";
36130
- 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";
36131
36343
  function need8(value, reason2) {
36132
36344
  if (!value)
36133
36345
  throw new Error(`Claude marketplace registry ${reason2}`);
@@ -36147,7 +36359,7 @@ function parents2(path) {
36147
36359
  }
36148
36360
  function readRegistry2(path, budget2) {
36149
36361
  absolutePath4(path);
36150
- need8(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
36362
+ need8(basename9(path) === "known_marketplaces.json", "requires known_marketplaces.json");
36151
36363
  need8(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
36152
36364
  const ancestors2 = parents2(path), initial = lstatSync20(path, { bigint: true });
36153
36365
  need8(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
@@ -36355,7 +36567,7 @@ var init_codex_hook_discovery_recovery = __esm(() => {
36355
36567
  // src/lib/agent-discovery.ts
36356
36568
  import { createHash as createHash21 } from "crypto";
36357
36569
  import { lstatSync as lstatSync21, readFileSync as readFileSync16, readdirSync as readdirSync8, realpathSync as realpathSync8 } from "fs";
36358
- 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";
36359
36571
  import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
36360
36572
  function discoveryExecutable(agent) {
36361
36573
  const command = DISCOVERY_RUNTIME_COMMANDS[agent];
@@ -36422,7 +36634,7 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical9) {
36422
36634
  throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
36423
36635
  }
36424
36636
  if ([cacheAliasRoot, cacheRoot].some((root) => row.installPath === root || row.installPath.startsWith(root + sep9))) {
36425
- 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)) {
36426
36638
  throw new Error("Reviewed Claude discovery has a malformed active cache registration");
36427
36639
  }
36428
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
@@ -36684,7 +36896,7 @@ function absentRetiredClaudeRoots(binding) {
36684
36896
  if (!targetValid || !targetScopes.has("user\x00"))
36685
36897
  continue;
36686
36898
  const active = rows[0]?.installPath;
36687
- 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)
36688
36900
  continue;
36689
36901
  const activeManifest = full(join29(active, ".claude-plugin/plugin.json"));
36690
36902
  if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
@@ -36693,14 +36905,15 @@ function absentRetiredClaudeRoots(binding) {
36693
36905
  }
36694
36906
  return [...result];
36695
36907
  }
36696
- function codexSemanticCacheSourceRole(source, cacheRoot, parents3) {
36908
+ function codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParents = []) {
36697
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")
36698
36910
  return false;
36699
36911
  const parts = relative7(cacheRoot, source.path).split(sep9);
36700
36912
  if (parts.length < 3 || !parents3.includes(join29(cacheRoot, parts[0], parts[1])))
36701
36913
  return false;
36702
36914
  const tail = parts.slice(3).join("/");
36703
- 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");
36704
36917
  }
36705
36918
  function codexSemanticCacheDirectoryRole(path, cacheRoot) {
36706
36919
  return isAbsolute19(path) && resolve20(path) === path && !/[\x00-\x1f\x7f]/.test(path) && (path === cacheRoot || path.startsWith(cacheRoot + sep9));
@@ -36732,20 +36945,28 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
36732
36945
  const cacheRoot = proof.witness.cacheRoot;
36733
36946
  if (controls.some((control) => dirname19(dirname19(control.pluginParent)) !== cacheRoot))
36734
36947
  throw new Error("Codex semantic cache names another enrolled cache");
36735
- const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...proof.appOnlyParents.map((parent) => parent.pluginParent)])];
36736
- 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));
36737
36958
  const directories = (binding.directories ?? []).filter((directory) => codexSemanticCacheDirectoryRole(directory.path, cacheRoot));
36738
36959
  if (!directories.length || !isDeepStrictEqual4(sources, proof.supersededSources) || !isDeepStrictEqual4(directories, proof.supersededDirectories))
36739
36960
  throw new Error("Codex semantic cache provenance changed");
36740
36961
  const configPath = proof.configPath;
36741
- 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))
36742
36963
  throw new Error("Invalid semantic cache configuration source");
36743
36964
  const configSource = binding.sources.find((source) => source.path === configPath && source.sha256 !== null && source.format === undefined && source.fields === undefined);
36744
36965
  if (!configSource || projected(configSource) !== configSource.sha256)
36745
36966
  throw new Error("Codex semantic cache requires unchanged reviewed configuration");
36746
36967
  assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, proof.hookRootAlias);
36747
36968
  const rules = parseConfig(read(configPath), configPath, true).skills?.config ?? [];
36748
- const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, rules });
36969
+ const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, reviewedHookParents, rules });
36749
36970
  assertCodexSemanticCacheWitnessUnchanged(proof.witness, current);
36750
36971
  return proof;
36751
36972
  }
@@ -36829,7 +37050,7 @@ function codexInstallationRoots(binding) {
36829
37050
  const config2 = join29(dirname19(dirname19(cache)), "config.toml"), home = dirname19(dirname19(dirname19(cache)));
36830
37051
  const configSource = binding.sources.find((source) => source.path === config2 && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
36831
37052
  const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join29(home, path));
36832
- 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)))))
36833
37054
  throw new Error("Native installation input overlaps configuration or loading roots");
36834
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)))
36835
37056
  throw new Error("Missing native installation input source witness");
@@ -36841,13 +37062,13 @@ function codexInstallationRoots(binding) {
36841
37062
  });
36842
37063
  }
36843
37064
  function assertMarketplaceBinding(binding, source) {
36844
- 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"))))
36845
37066
  throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
36846
- 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"))
36847
37068
  throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
36848
- 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"))
36849
37070
  throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
36850
- 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"))
36851
37072
  throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
36852
37073
  if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
36853
37074
  throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
@@ -36996,7 +37217,7 @@ function resolveAgentDiscovery(options) {
36996
37217
  throw new Error("Discovery review must include the agent configuration source");
36997
37218
  const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical9(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical9(configPath), source)) : sources;
36998
37219
  const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
36999
- 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")))
37000
37221
  return source;
37001
37222
  const pluginRoot = dirname19(dirname19(source.path)), hooksPath = join29(pluginRoot, "hooks/hooks.json");
37002
37223
  const hookStat = lstatSync21(hooksPath, { throwIfNoEntry: false });
@@ -37176,7 +37397,7 @@ var init_agent_discovery = __esm(() => {
37176
37397
  // src/lib/authoring-path.ts
37177
37398
  import { lstatSync as lstatSync22, realpathSync as realpathSync9 } from "fs";
37178
37399
  import { homedir as homedir3 } from "os";
37179
- 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";
37180
37401
  function pathParts(path) {
37181
37402
  return resolve21(path).split(sep10).filter(Boolean);
37182
37403
  }
@@ -37195,7 +37416,7 @@ function physicalPath(path) {
37195
37416
  let cursor = resolve21(path);
37196
37417
  const suffix = [];
37197
37418
  while (!lstatSync22(cursor, { throwIfNoEntry: false })) {
37198
- suffix.unshift(basename10(cursor));
37419
+ suffix.unshift(basename11(cursor));
37199
37420
  const parent = dirname20(cursor);
37200
37421
  if (parent === cursor)
37201
37422
  return resolve21(path);
@@ -37290,7 +37511,7 @@ import {
37290
37511
  statSync as statSync8,
37291
37512
  writeFileSync as writeFileSync6
37292
37513
  } from "fs";
37293
- 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";
37294
37515
  function getPortableSkillsRoot(options = {}) {
37295
37516
  return resolvePortableSkillsRoot(options, true);
37296
37517
  }
@@ -37388,7 +37609,7 @@ function physicalImportPath(path) {
37388
37609
  let ancestor = resolve22(path);
37389
37610
  const suffix = [];
37390
37611
  while (!existsSync12(ancestor)) {
37391
- suffix.unshift(basename11(ancestor));
37612
+ suffix.unshift(basename12(ancestor));
37392
37613
  ancestor = dirname21(ancestor);
37393
37614
  }
37394
37615
  return join31(realpathSync10(ancestor), ...suffix);
@@ -37413,8 +37634,8 @@ function portPortableSkill(sourcePath, options = {}) {
37413
37634
  const explicitName = options.name != null;
37414
37635
  const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
37415
37636
  if (isOfficialSkillName(skillName) && !options.allowShadow) {
37416
- const sourceSlug = safeNormalizeName(basename11(absoluteSource));
37417
- 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.`;
37418
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.`);
37419
37640
  }
37420
37641
  const readOnlyDestination = join31(resolvePortableSkillsRoot(options, false), skillName);
@@ -39043,13 +39264,13 @@ var init_remote_workspace_leave = __esm(() => {
39043
39264
 
39044
39265
  // src/lib/auth-store.ts
39045
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";
39046
- 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";
39047
39268
  function getAuthFilePath(env = process.env) {
39048
39269
  return skillsCredentialFilePath(env);
39049
39270
  }
39050
39271
  function getIdentityFilePath(env = process.env) {
39051
39272
  const file2 = skillsCredentialFilePath(env);
39052
- return join33(dirname22(file2), basename12(file2).replace(/^credentials/, "identity") + ".json");
39273
+ return join33(dirname22(file2), basename13(file2).replace(/^credentials/, "identity") + ".json");
39053
39274
  }
39054
39275
  function getApiUrl(action, env = process.env, options = {}) {
39055
39276
  return requireSkillsApiOrigin(action, env, options);
package/bin/migrate.js CHANGED
@@ -25,7 +25,7 @@ import { join as join5 } from "path";
25
25
  // package.json
26
26
  var package_default = {
27
27
  name: "@hasna/skills",
28
- version: "0.10.65",
28
+ version: "0.10.67",
29
29
  description: "Skills library for AI coding agents",
30
30
  type: "module",
31
31
  bin: {
package/bin/server.js CHANGED
@@ -24140,7 +24140,7 @@ restoreLaunchCwd();
24140
24140
  // package.json
24141
24141
  var package_default = {
24142
24142
  name: "@hasna/skills",
24143
- version: "0.10.65",
24143
+ version: "0.10.67",
24144
24144
  description: "Skills library for AI coding agents",
24145
24145
  type: "module",
24146
24146
  bin: {
package/bin/worker.js CHANGED
@@ -24143,7 +24143,7 @@ import { randomUUID as randomUUID6 } from "crypto";
24143
24143
  // package.json
24144
24144
  var package_default = {
24145
24145
  name: "@hasna/skills",
24146
- version: "0.10.65",
24146
+ version: "0.10.67",
24147
24147
  description: "Skills library for AI coding agents",
24148
24148
  type: "module",
24149
24149
  bin: {