@hasna/skills 0.10.65 → 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/dist/sdk/index.js CHANGED
@@ -32371,7 +32371,7 @@ var init_event_sink = __esm(() => {
32371
32371
  init_dist();
32372
32372
  });
32373
32373
  // package.json
32374
- var version = "0.10.65";
32374
+ var version = "0.10.66";
32375
32375
  var package_default = {
32376
32376
  name: "@hasna/skills",
32377
32377
  version,
@@ -38326,7 +38326,7 @@ import {
38326
38326
  writeFileSync as writeFileSync8
38327
38327
  } from "fs";
38328
38328
  import { homedir as homedir5 } from "os";
38329
- import { basename as basename13, dirname as dirname25, join as join35 } from "path";
38329
+ import { basename as basename15, dirname as dirname25, join as join35 } from "path";
38330
38330
 
38331
38331
  // src/lib/sumi-settings-witness.ts
38332
38332
  import { createHash as createHash8 } from "crypto";
@@ -40671,7 +40671,7 @@ function upgradeCodexSettingsWitnessV5(previous, reviewedSettingsPath) {
40671
40671
  // src/lib/codex-semantic-cache-witness.ts
40672
40672
  import { createHash as createHash13 } from "crypto";
40673
40673
  import { constants as constants9, closeSync as closeSync12, fstatSync as fstatSync12, lstatSync as lstatSync10, openSync as openSync12, readSync as readSync6, readdirSync as readdirSync4, realpathSync as realpathSync9 } from "fs";
40674
- import { dirname as dirname9, isAbsolute as isAbsolute8, join as join15, relative as relative6, resolve as resolve8, sep as sep5 } from "path";
40674
+ import { basename as basename5, dirname as dirname9, isAbsolute as isAbsolute8, join as join15, relative as relative6, resolve as resolve8, sep as sep5 } from "path";
40675
40675
  var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1";
40676
40676
  var identifier4 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value);
40677
40677
  var digest2 = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
@@ -40680,6 +40680,24 @@ var refuse5 = () => {
40680
40680
  };
40681
40681
  var MAX_DOCUMENT_BYTES = 1024 * 1024;
40682
40682
  var MAX_RECEIPT_BYTES = 16 * 1024;
40683
+ function codexLocalMarketplaceMapsPlugin(text, marketplace, plugin) {
40684
+ try {
40685
+ hashNativeJsonControls(text);
40686
+ const value = JSON.parse(text);
40687
+ if (!plainObject(value) || !exactKeys2(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)
40688
+ return false;
40689
+ const rows = value.plugins.filter((row2) => plainObject(row2) && row2.name === plugin);
40690
+ if (rows.length !== 1)
40691
+ return false;
40692
+ const row = rows[0];
40693
+ if (!exactKeys2(row, ["name", "source"]) || !plainObject(row.source) || !exactKeys2(row.source, ["source", "path"]) || row.source.source !== "local" || typeof row.source.path !== "string" || !row.source.path.startsWith("./") || row.source.path.includes("\\"))
40694
+ return false;
40695
+ const parts = row.source.path.split("/");
40696
+ 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;
40697
+ } catch {
40698
+ return false;
40699
+ }
40700
+ }
40683
40701
  function defaultRead(path) {
40684
40702
  const before = lstatSync10(path, { throwIfNoEntry: false, bigint: true });
40685
40703
  if (before === undefined)
@@ -40741,7 +40759,7 @@ function validPluginParent(cacheRoot, pluginParent, namespace, pluginId) {
40741
40759
  return parts.length === 2 && parts.every(identifier4) && parts[1] === namespace && pluginId === `${namespace}@${parts[0]}`;
40742
40760
  }
40743
40761
  function assertWitnessShape(value) {
40744
- if (!plainObject(value) || !exactKeys2(value, ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256"]) || value.schema !== CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA || typeof value.cacheRoot !== "string" || !isAbsolute8(value.cacheRoot) || resolve8(value.cacheRoot) !== value.cacheRoot || !digest2(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)
40762
+ if (!plainObject(value) || !exactKeys2(value, ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256"], ["hookParents"]) || value.schema !== CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA || typeof value.cacheRoot !== "string" || !isAbsolute8(value.cacheRoot) || resolve8(value.cacheRoot) !== value.cacheRoot || !digest2(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)
40745
40763
  refuse5();
40746
40764
  const witness = value;
40747
40765
  const controlParents = new Set;
@@ -40762,6 +40780,20 @@ function assertWitnessShape(value) {
40762
40780
  refuse5();
40763
40781
  appOnlyParentPaths.add(row.pluginParent);
40764
40782
  }
40783
+ const hookParentPaths = new Set;
40784
+ const hookParents = witness.hookParents === undefined ? [] : witness.hookParents;
40785
+ if (!Array.isArray(hookParents) || hookParents.length > 4096)
40786
+ refuse5();
40787
+ for (const candidate of hookParents) {
40788
+ if (!plainObject(candidate))
40789
+ refuse5();
40790
+ const row = candidate;
40791
+ const remote = row.installation === "remote-receipt";
40792
+ const local = row.installation === "local-marketplace";
40793
+ if (!exactKeys2(row, ["role", "pluginId", "namespace", "pluginParent", "installation", "manifestSha256", "hooksSha256"], remote ? ["remotePluginId", "receiptSha256"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || row.role !== "reviewed-hook" || !identifier4(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) || !digest2(row.receiptSha256)) || local && (typeof row.marketplaceSourcePath !== "string" || !isAbsolute8(row.marketplaceSourcePath) || resolve8(row.marketplaceSourcePath) !== row.marketplaceSourcePath || basename5(row.marketplaceSourcePath) !== "marketplace.json" || !digest2(row.marketplaceSha256)) || !remote && !local || !digest2(row.manifestSha256) || !digest2(row.hooksSha256) || hookParentPaths.has(row.pluginParent) || controlParents.has(row.pluginParent) || appOnlyParentPaths.has(row.pluginParent))
40794
+ refuse5();
40795
+ hookParentPaths.add(row.pluginParent);
40796
+ }
40765
40797
  const skillNames = new Set;
40766
40798
  const qualifiedNames = new Set;
40767
40799
  for (const candidate of witness.skills) {
@@ -40781,6 +40813,7 @@ function assertWitnessShape(value) {
40781
40813
  cacheRoot: witness.cacheRoot,
40782
40814
  controls: witness.controls,
40783
40815
  appOnlyParents: witness.appOnlyParents,
40816
+ ...witness.hookParents === undefined ? {} : { hookParents: witness.hookParents },
40784
40817
  skills: witness.skills
40785
40818
  };
40786
40819
  if (hash2(projection) !== witness.sha256)
@@ -40971,10 +41004,147 @@ function appOnlyParentProjection(cacheRoot, parents2, read) {
40971
41004
  }
40972
41005
  return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
40973
41006
  }
40974
- function assertParents(cacheRoot, controls, appOnlyParents, files, members) {
41007
+ var codexHookEvents = new Set([
41008
+ "SessionStart",
41009
+ "UserPromptSubmit",
41010
+ "PreToolUse",
41011
+ "PostToolUse",
41012
+ "PostToolUseFailure",
41013
+ "Stop",
41014
+ "SubagentStart",
41015
+ "SubagentStop",
41016
+ "PreCompact",
41017
+ "Notification",
41018
+ "PermissionRequest",
41019
+ "SessionEnd",
41020
+ "ConfigChange",
41021
+ "WorktreeCreate",
41022
+ "WorktreeRemove",
41023
+ "TeammateIdle",
41024
+ "TaskComplete"
41025
+ ]);
41026
+ function assertJsonValue(value, depth = 0, budget2 = { members: 0 }) {
41027
+ if (depth > 32 || ++budget2.members > 4096)
41028
+ refuse5();
41029
+ if (value === null || typeof value === "string" || typeof value === "boolean")
41030
+ return;
41031
+ if (typeof value === "number" && Number.isFinite(value))
41032
+ return;
41033
+ if (Array.isArray(value)) {
41034
+ for (const item of value)
41035
+ assertJsonValue(item, depth + 1, budget2);
41036
+ return;
41037
+ }
41038
+ if (!plainObject(value))
41039
+ refuse5();
41040
+ for (const [key, item] of Object.entries(value)) {
41041
+ if (!key || /[\x00-\x1f\x7f]/.test(key))
41042
+ refuse5();
41043
+ assertJsonValue(item, depth + 1, budget2);
41044
+ }
41045
+ }
41046
+ function reviewedHookControls(root, read) {
41047
+ const manifestPath = join15(root, ".codex-plugin/plugin.json"), hooksPath = join15(root, "hooks/hooks.json");
41048
+ let manifest, manifestSha256, hooks, hooksSha256;
41049
+ try {
41050
+ const manifestText = read(manifestPath);
41051
+ manifestSha256 = hashNativeJsonControls(manifestText, "version");
41052
+ manifest = JSON.parse(manifestText);
41053
+ const hooksText = read(hooksPath);
41054
+ hashNativeJsonControls(hooksText);
41055
+ hooksSha256 = createHash13("sha256").update(hooksText).digest("hex");
41056
+ hooks = JSON.parse(hooksText);
41057
+ } catch {
41058
+ return refuse5();
41059
+ }
41060
+ if (!plainObject(manifest) || !exactKeys2(manifest, ["name", "version", "hooks"], ["description"]) || !identifier4(manifest.name) || typeof manifest.version !== "string" || manifest.version !== basename5(root) || manifest.hooks !== "./hooks/hooks.json" || manifest.description !== undefined && (typeof manifest.description !== "string" || !manifest.description.trim() || manifest.description.length > 1024))
41061
+ refuse5();
41062
+ const manifestRecord = manifest;
41063
+ if (!plainObject(hooks) || !exactKeys2(hooks, ["hooks"]) || !plainObject(hooks.hooks))
41064
+ refuse5();
41065
+ const hookTable = hooks.hooks;
41066
+ const events = Object.entries(hookTable);
41067
+ if (!events.length || events.length > 32)
41068
+ refuse5();
41069
+ for (const [event, groups] of events) {
41070
+ if (!codexHookEvents.has(event) || !Array.isArray(groups) || !groups.length || groups.length > 32)
41071
+ refuse5();
41072
+ for (const group of groups) {
41073
+ if (!plainObject(group) || !exactKeys2(group, ["hooks"]) || !Array.isArray(group.hooks) || !group.hooks.length || group.hooks.length > 32)
41074
+ refuse5();
41075
+ const handlers = group.hooks;
41076
+ for (const handler of handlers) {
41077
+ if (!plainObject(handler) || !exactKeys2(handler, ["type", "server", "tool", "input"], ["timeout"]) || handler.type !== "mcp_tool" || !identifier4(handler.server) || !identifier4(handler.tool) || !plainObject(handler.input) || handler.timeout !== undefined && (!Number.isSafeInteger(handler.timeout) || Number(handler.timeout) < 1 || Number(handler.timeout) > 300))
41078
+ refuse5();
41079
+ assertJsonValue(handler.input);
41080
+ }
41081
+ }
41082
+ }
41083
+ return { namespace: manifestRecord.name, manifestSha256, hooksSha256 };
41084
+ }
41085
+ function reviewedHookParentProjection(cacheRoot, parents2, read) {
41086
+ if (!Array.isArray(parents2) || parents2.length > 4096)
41087
+ refuse5();
41088
+ const seen = new Set, rows = [];
41089
+ for (const parent of parents2) {
41090
+ const remote = parent?.installation === "remote-receipt", local = parent?.installation === "local-marketplace";
41091
+ if (!parent || !exactKeys2(parent, ["installation", "namespace", "pluginId", "pluginParent", "role"], remote ? ["remotePluginId"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || parent.role !== "reviewed-hook" || !identifier4(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" || !isAbsolute8(parent.marketplaceSourcePath) || resolve8(parent.marketplaceSourcePath) !== parent.marketplaceSourcePath || basename5(parent.marketplaceSourcePath) !== "marketplace.json" || !digest2(parent.marketplaceSha256)) || !remote && !local)
41092
+ refuse5();
41093
+ const parts = relative6(cacheRoot, parent.pluginParent).split(sep5);
41094
+ if (!isAbsolute8(parent.pluginParent) || resolve8(parent.pluginParent) !== parent.pluginParent || parts.length !== 2 || parts.some((part) => !identifier4(part)) || parts[1] !== parent.namespace || parent.pluginId !== `${parent.namespace}@${parts[0]}` || seen.has(parent.pluginParent))
41095
+ refuse5();
41096
+ seen.add(parent.pluginParent);
41097
+ const parentStat = lstatSync10(parent.pluginParent, { throwIfNoEntry: false });
41098
+ if (!parentStat?.isDirectory() || parentStat.isSymbolicLink() || realpathSync9(parent.pluginParent) !== parent.pluginParent)
41099
+ refuse5();
41100
+ const receiptPath = join15(parent.pluginParent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync10(receiptPath, { throwIfNoEntry: false });
41101
+ let receiptText;
41102
+ if (remote) {
41103
+ if (!receiptStat?.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > MAX_RECEIPT_BYTES)
41104
+ refuse5();
41105
+ try {
41106
+ receiptText = read(receiptPath);
41107
+ hashNativeJsonControls(receiptText);
41108
+ const receipt = JSON.parse(receiptText);
41109
+ if (!plainObject(receipt) || !exactKeys2(receipt, ["schema_version", "remote_plugin_id"]) || receipt.schema_version !== 1 || receipt.remote_plugin_id !== parent.remotePluginId)
41110
+ refuse5();
41111
+ } catch {
41112
+ refuse5();
41113
+ }
41114
+ } else {
41115
+ const marketplaceSourcePath = parent.marketplaceSourcePath ?? refuse5();
41116
+ if (receiptStat !== undefined || !parent.marketplaceSha256)
41117
+ refuse5();
41118
+ let marketplaceText;
41119
+ try {
41120
+ marketplaceText = read(marketplaceSourcePath);
41121
+ } catch {
41122
+ return refuse5();
41123
+ }
41124
+ if (createHash13("sha256").update(marketplaceText).digest("hex") !== parent.marketplaceSha256 || !codexLocalMarketplaceMapsPlugin(marketplaceText, parts[0], parent.namespace))
41125
+ refuse5();
41126
+ }
41127
+ const materializations = readdirSync4(parent.pluginParent).filter((name) => name !== ".codex-remote-plugin-install.json").map((version2) => {
41128
+ if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
41129
+ refuse5();
41130
+ const root = join15(parent.pluginParent, version2), stat = lstatSync10(root, { throwIfNoEntry: false });
41131
+ if (!stat?.isDirectory() || stat.isSymbolicLink() || realpathSync9(root) !== root)
41132
+ refuse5();
41133
+ const controls = reviewedHookControls(root, read);
41134
+ if (controls.namespace !== parent.namespace)
41135
+ refuse5();
41136
+ return { manifestSha256: controls.manifestSha256, hooksSha256: controls.hooksSha256 };
41137
+ });
41138
+ if (!materializations.length || materializations.some((item) => canonical4(item) !== canonical4(materializations[0])))
41139
+ refuse5();
41140
+ rows.push({ ...parent, ...receiptText === undefined ? {} : { receiptSha256: createHash13("sha256").update(receiptText).digest("hex") }, ...materializations[0] });
41141
+ }
41142
+ return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
41143
+ }
41144
+ function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files, members) {
40975
41145
  const expected = new Set;
40976
41146
  const expectedMarkets = new Set;
40977
- for (const control of [...controls, ...appOnlyParents]) {
41147
+ for (const control of [...controls, ...appOnlyParents, ...hookParents]) {
40978
41148
  const rel = relative6(cacheRoot, control.pluginParent), parts = rel.split(sep5);
40979
41149
  if (resolve8(control.pluginParent) !== control.pluginParent || parts.length !== 2 || parts.some((part) => !identifier4(part)) || control.pluginId !== `${control.namespace}@${parts[0]}` || parts[1] !== control.namespace)
40980
41150
  refuse5();
@@ -41015,7 +41185,9 @@ function assertParents(cacheRoot, controls, appOnlyParents, files, members) {
41015
41185
  refuse5();
41016
41186
  if ([".app.json", ".mcp.json"].includes(base) && (parts.length !== 4 || dirname9(member) !== root))
41017
41187
  refuse5();
41018
- if (parts.includes("hooks"))
41188
+ if ([".app.json", ".mcp.json"].includes(base) && hookParents.some((reviewed) => reviewed.pluginParent === parent))
41189
+ refuse5();
41190
+ 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 === join15(cacheRoot, parts[0], parts[1]))))
41019
41191
  refuse5();
41020
41192
  }
41021
41193
  }
@@ -41125,13 +41297,14 @@ function captureCodexSemanticCacheWitness(options) {
41125
41297
  const initialTree = treeSnapshot(options.cacheRoot);
41126
41298
  const controls = controlProjection(options.controls, read);
41127
41299
  const appOnlyParents = appOnlyParentProjection(options.cacheRoot, options.appOnlyParents ?? [], read);
41300
+ const hookParents = reviewedHookParentProjection(options.cacheRoot, options.reviewedHookParents ?? [], read);
41128
41301
  const skillParents = new Set(controls.map((control) => control.pluginParent));
41129
- if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)))
41302
+ if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)) || hookParents.some((parent) => skillParents.has(parent.pluginParent) || appOnlyParents.some((app) => app.pluginParent === parent.pluginParent)))
41130
41303
  refuse5();
41131
41304
  if (!reviewedCodexPluginCapabilitiesUnchanged(options.cacheRoot, options.controls, read, options.rules))
41132
41305
  refuse5();
41133
41306
  const files = initialTree.files;
41134
- assertParents(options.cacheRoot, controls, appOnlyParents, files, initialTree.state.members);
41307
+ assertParents(options.cacheRoot, controls, appOnlyParents, hookParents, files, initialTree.state.members);
41135
41308
  const expectedNamesByRoot = assertSkillMaterializations(options.cacheRoot, options.controls, files, read);
41136
41309
  const docs = files.filter((path) => path.endsWith(`${sep5}SKILL.md`));
41137
41310
  const skillRows = [];
@@ -41140,6 +41313,8 @@ function captureCodexSemanticCacheWitness(options) {
41140
41313
  const rel = relative6(options.cacheRoot, document).split(sep5);
41141
41314
  if (appOnlyParents.some((parent) => parent.pluginParent === join15(options.cacheRoot, rel[0], rel[1])))
41142
41315
  refuse5();
41316
+ if (hookParents.some((parent) => parent.pluginParent === join15(options.cacheRoot, rel[0], rel[1])))
41317
+ refuse5();
41143
41318
  const documentStat = lstatSync10(document, { throwIfNoEntry: false });
41144
41319
  if (!documentStat?.isFile() || documentStat.isSymbolicLink() || documentStat.size > MAX_DOCUMENT_BYTES)
41145
41320
  refuse5();
@@ -41203,7 +41378,7 @@ function captureCodexSemanticCacheWitness(options) {
41203
41378
  tracked.verify();
41204
41379
  const finalTree = treeSnapshot(options.cacheRoot);
41205
41380
  assertSameTree(initialTree.state, finalTree.state, tracked.paths());
41206
- const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, skills: uniqueSkills };
41381
+ const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, hookParents, skills: uniqueSkills };
41207
41382
  return { ...completeProjection, sha256: hash2(completeProjection) };
41208
41383
  } catch (error) {
41209
41384
  if (error instanceof Error && error.message.startsWith("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED"))
@@ -41219,6 +41394,7 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
41219
41394
  cacheRoot: previous.cacheRoot,
41220
41395
  controls: previous.controls,
41221
41396
  appOnlyParents: previous.appOnlyParents,
41397
+ ...previous.hookParents === undefined ? {} : { hookParents: previous.hookParents },
41222
41398
  skills: previous.skills
41223
41399
  };
41224
41400
  const currentProjection = {
@@ -41226,9 +41402,11 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
41226
41402
  cacheRoot: current.cacheRoot,
41227
41403
  controls: current.controls,
41228
41404
  appOnlyParents: current.appOnlyParents,
41405
+ ...current.hookParents === undefined ? {} : { hookParents: current.hookParents },
41229
41406
  skills: current.skills
41230
41407
  };
41231
- if (hash2(priorProjection) !== previous.sha256 || hash2(currentProjection) !== current.sha256 || canonical4(priorProjection) !== canonical4(currentProjection))
41408
+ const comparable = (projection) => ({ ...projection, hookParents: projection.hookParents ?? [] });
41409
+ if (hash2(priorProjection) !== previous.sha256 || hash2(currentProjection) !== current.sha256 || canonical4(comparable(priorProjection)) !== canonical4(comparable(currentProjection)))
41232
41410
  refuse5();
41233
41411
  }
41234
41412
 
@@ -41257,7 +41435,7 @@ var NATIVE_SKILL_ROOTS = [
41257
41435
  import { createHash as createHash28, randomUUID as randomUUID4 } from "crypto";
41258
41436
  import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
41259
41437
  import { existsSync as existsSync7, lstatSync as lstatSync26, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync18, readdirSync as readdirSync9, opendirSync as opendirSync5, readlinkSync as readlinkSync7, realpathSync as realpathSync13, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync5, unlinkSync as unlinkSync5, chmodSync, openSync as openSync21, closeSync as closeSync21, fsyncSync as fsyncSync7, fstatSync as fstatSync21, readSync as readSync14, constants as constants19, linkSync as linkSync3 } from "fs";
41260
- import { dirname as dirname21, join as join30, resolve as resolve23, relative as relative8, isAbsolute as isAbsolute25, sep as sep10 } from "path";
41438
+ import { basename as basename11, dirname as dirname21, join as join30, resolve as resolve23, relative as relative8, isAbsolute as isAbsolute25, sep as sep10 } from "path";
41261
41439
  import { homedir as homedir3 } from "os";
41262
41440
 
41263
41441
  // src/lib/managed-policy.ts
@@ -41265,11 +41443,11 @@ import { closeSync as closeSync13, constants as constants10, fstatSync as fstatS
41265
41443
  import { join as join17 } from "path";
41266
41444
 
41267
41445
  // src/lib/agent-policy-limits.ts
41268
- import { basename as basename6, isAbsolute as isAbsolute10, join as join16, resolve as resolve10, sep as sep6 } from "path";
41446
+ import { basename as basename7, isAbsolute as isAbsolute10, join as join16, resolve as resolve10, sep as sep6 } from "path";
41269
41447
 
41270
41448
  // src/lib/claude-marketplace-entry-witness.ts
41271
41449
  import { createHash as createHash14 } from "crypto";
41272
- import { basename as basename5, dirname as dirname10, isAbsolute as isAbsolute9, resolve as resolve9 } from "path";
41450
+ import { basename as basename6, dirname as dirname10, isAbsolute as isAbsolute9, resolve as resolve9 } from "path";
41273
41451
  var CLAUDE_MARKETPLACE_ENTRY_HASH_MODE = "claude-marketplace-entry-v1";
41274
41452
  var DOMAIN = "hasna.skills.claude-marketplace-entry.v1\x00";
41275
41453
  var PATH_CHARACTERS = 4096;
@@ -41334,7 +41512,7 @@ var stringArray = (value) => value?.kind === "array" && value.items.every(isStri
41334
41512
  var stringObject = (value) => value?.kind === "object" && value.entries.every(([, item]) => isString(item));
41335
41513
  function claudeMarketplaceEntrySourceValid(source) {
41336
41514
  const path = source?.path;
41337
- return typeof path === "string" && path.length > 0 && path.length <= PATH_CHARACTERS && !/[\x00-\x1f\x7f]/.test(path) && isAbsolute9(path) && resolve9(path) === path && basename5(path) === "marketplace.json" && basename5(dirname10(path)) === ".claude-plugin" && typeof source.marketplace === "string" && NAME.test(source.marketplace) && !source.marketplace.includes("..") && typeof source.plugin === "string" && NAME.test(source.plugin);
41515
+ return typeof path === "string" && path.length > 0 && path.length <= PATH_CHARACTERS && !/[\x00-\x1f\x7f]/.test(path) && isAbsolute9(path) && resolve9(path) === path && basename6(path) === "marketplace.json" && basename6(dirname10(path)) === ".claude-plugin" && typeof source.marketplace === "string" && NAME.test(source.marketplace) && !source.marketplace.includes("..") && typeof source.plugin === "string" && NAME.test(source.plugin);
41338
41516
  }
41339
41517
  function canonical5(value) {
41340
41518
  if (value.kind === "string")
@@ -41604,10 +41782,10 @@ function assertAgentPolicyCollections(policy) {
41604
41782
  }
41605
41783
  }
41606
41784
  if (value.codexSemanticCache !== undefined) {
41607
- const proof = record3(value.codexSemanticCache, 8), witness = record3(proof.witness, 6);
41608
- 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));
41785
+ const proof = record3(value.codexSemanticCache, 9), witness = record3(proof.witness, 7);
41786
+ 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));
41609
41787
  text(proof.configPath);
41610
- requireBound(isAbsolute10(proof.configPath) && resolve10(proof.configPath) === proof.configPath && basename6(proof.configPath) === "config.toml");
41788
+ requireBound(isAbsolute10(proof.configPath) && resolve10(proof.configPath) === proof.configPath && basename7(proof.configPath) === "config.toml");
41611
41789
  text(witness.cacheRoot);
41612
41790
  requireBound(isAbsolute10(witness.cacheRoot) && resolve10(witness.cacheRoot) === witness.cacheRoot);
41613
41791
  if (proof.hookRootAlias !== null) {
@@ -41624,6 +41802,20 @@ function assertAgentPolicyCollections(policy) {
41624
41802
  text(parent[key]);
41625
41803
  requireBound(isAbsolute10(parent.pluginParent) && resolve10(parent.pluginParent) === parent.pluginParent);
41626
41804
  }
41805
+ if (proof.reviewedHookParents !== undefined)
41806
+ for (const parent of array(proof.reviewedHookParents, 4096)) {
41807
+ requireBound(object4(parent) && parent.role === "reviewed-hook" && (parent.installation === "remote-receipt" && Object.keys(parent).length === 6 || parent.installation === "local-marketplace" && Object.keys(parent).length === 7));
41808
+ 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");
41809
+ for (const key of ["pluginId", "namespace", "pluginParent", "installation"])
41810
+ text(parent[key]);
41811
+ if (parent.installation === "remote-receipt")
41812
+ text(parent.remotePluginId);
41813
+ else {
41814
+ text(parent.marketplaceSourcePath);
41815
+ requireBound(typeof parent.marketplaceSha256 === "string" && /^[a-f0-9]{64}$/.test(parent.marketplaceSha256) && isAbsolute10(parent.marketplaceSourcePath) && resolve10(parent.marketplaceSourcePath) === parent.marketplaceSourcePath && basename7(parent.marketplaceSourcePath) === "marketplace.json");
41816
+ }
41817
+ requireBound(isAbsolute10(parent.pluginParent) && resolve10(parent.pluginParent) === parent.pluginParent);
41818
+ }
41627
41819
  for (const row of [...array(witness.controls, 4096), ...array(witness.appOnlyParents, 4096)]) {
41628
41820
  requireBound(object4(row));
41629
41821
  for (const key of ["pluginId", "namespace", "pluginParent"])
@@ -41632,6 +41824,26 @@ function assertAgentPolicyCollections(policy) {
41632
41824
  if (row[key] !== undefined)
41633
41825
  requireBound(typeof row[key] === "string" && /^[a-f0-9]{64}$/.test(row[key]));
41634
41826
  }
41827
+ if (witness.hookParents !== undefined)
41828
+ for (const row of array(witness.hookParents, 4096)) {
41829
+ requireBound(object4(row) && row.role === "reviewed-hook" && (row.installation === "remote-receipt" && Object.keys(row).length === 9 || row.installation === "local-marketplace" && Object.keys(row).length === 9));
41830
+ 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");
41831
+ for (const key of ["pluginId", "namespace", "pluginParent", "installation"])
41832
+ text(row[key]);
41833
+ if (row.installation === "remote-receipt")
41834
+ text(row.remotePluginId);
41835
+ else {
41836
+ text(row.marketplaceSourcePath);
41837
+ requireBound(typeof row.marketplaceSha256 === "string" && /^[a-f0-9]{64}$/.test(row.marketplaceSha256) && isAbsolute10(row.marketplaceSourcePath) && resolve10(row.marketplaceSourcePath) === row.marketplaceSourcePath && basename7(row.marketplaceSourcePath) === "marketplace.json");
41838
+ }
41839
+ requireBound(isAbsolute10(row.pluginParent) && resolve10(row.pluginParent) === row.pluginParent);
41840
+ for (const key of ["manifestSha256", "hooksSha256"])
41841
+ requireBound(typeof row[key] === "string" && /^[a-f0-9]{64}$/.test(row[key]));
41842
+ if (row.installation === "remote-receipt")
41843
+ requireBound(typeof row.receiptSha256 === "string" && /^[a-f0-9]{64}$/.test(row.receiptSha256));
41844
+ else
41845
+ requireBound(row.receiptSha256 === undefined);
41846
+ }
41635
41847
  for (const skill of array(witness.skills, 4096)) {
41636
41848
  requireBound(object4(skill));
41637
41849
  for (const key of ["name", "pluginId", "namespace", "pluginParent"])
@@ -41661,13 +41873,13 @@ function assertAgentPolicyCollections(policy) {
41661
41873
  if (source.hashMode === "claude-plugin-manifest-v1")
41662
41874
  requireBound(agent === "claude" && value.agent === "claude" && ["automatic", "reviewed"].includes(value.method) && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && source.path.endsWith(join16(sep6, ".claude-plugin", "plugin.json")) && source.managedPlugins === undefined);
41663
41875
  if (source.hashMode === "sumi-settings-v1")
41664
- requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename6(source.path) === "sumi.json");
41876
+ requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename7(source.path) === "sumi.json");
41665
41877
  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"))
41666
- requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename6(source.path) === "config.toml");
41878
+ requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename7(source.path) === "config.toml");
41667
41879
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4"))
41668
- requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename6(source.path) === "settings.json");
41880
+ requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename7(source.path) === "settings.json");
41669
41881
  if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2")
41670
- requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename6(source.path) === "known_marketplaces.json");
41882
+ requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename7(source.path) === "known_marketplaces.json");
41671
41883
  if (source.hashMode === "claude-marketplace-entry-v1")
41672
41884
  requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && claudeMarketplaceEntrySourceValid(source));
41673
41885
  if (source.hashMode === "claude-plugin-registry") {
@@ -41832,7 +42044,7 @@ function isOwnedCliBridge(path, expectedPaths) {
41832
42044
  // src/lib/agent-discovery.ts
41833
42045
  import { createHash as createHash26 } from "crypto";
41834
42046
  import { lstatSync as lstatSync24, readFileSync as readFileSync16, readdirSync as readdirSync8, realpathSync as realpathSync11 } from "fs";
41835
- import { basename as basename9, dirname as dirname20, isAbsolute as isAbsolute23, join as join29, relative as relative7, resolve as resolve22, sep as sep9 } from "path";
42047
+ import { basename as basename10, dirname as dirname20, isAbsolute as isAbsolute23, join as join29, relative as relative7, resolve as resolve22, sep as sep9 } from "path";
41836
42048
  import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
41837
42049
 
41838
42050
  // node_modules/yaml/dist/index.js
@@ -42523,7 +42735,7 @@ function projectReviewedClaudePluginManifest(text2, reviewedSha256) {
42523
42735
 
42524
42736
  // src/lib/plugin-discovery.ts
42525
42737
  import { closeSync as closeSync16, constants as constants13, fstatSync as fstatSync16, lstatSync as lstatSync19, openSync as openSync16, opendirSync as opendirSync4, readSync as readSync10 } from "fs";
42526
- import { basename as basename7, dirname as dirname16, isAbsolute as isAbsolute18, join as join26, resolve as resolve17 } from "path";
42738
+ import { basename as basename8, dirname as dirname16, isAbsolute as isAbsolute18, join as join26, resolve as resolve17 } from "path";
42527
42739
 
42528
42740
  // src/lib/plugin-admission.ts
42529
42741
  import { homedir as homedir2 } from "os";
@@ -44004,7 +44216,7 @@ function hashManagedPluginRegistry(path, managed) {
44004
44216
  pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join26(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
44005
44217
  const approval = (producer) => {
44006
44218
  pluginText(producer);
44007
- const digest3 = `sha256:${basename7(producer)}`;
44219
+ const digest3 = `sha256:${basename8(producer)}`;
44008
44220
  const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest3);
44009
44221
  pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
44010
44222
  if (!verified.has(producer)) {
@@ -44068,7 +44280,7 @@ function captureManagedPluginRegistry(path, managedPlugins) {
44068
44280
  // src/lib/claude-marketplace-registry.ts
44069
44281
  import { createHash as createHash22 } from "crypto";
44070
44282
  import { closeSync as closeSync17, constants as constants14, fstatSync as fstatSync17, lstatSync as lstatSync20, openSync as openSync17, readSync as readSync11 } from "fs";
44071
- import { basename as basename8, dirname as dirname17, isAbsolute as isAbsolute19, resolve as resolve18 } from "path";
44283
+ import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute19, resolve as resolve18 } from "path";
44072
44284
  var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
44073
44285
  function need6(value, reason2) {
44074
44286
  if (!value)
@@ -44090,7 +44302,7 @@ function parents2(path) {
44090
44302
  }
44091
44303
  function readRegistry2(path, budget2) {
44092
44304
  absolutePath3(path);
44093
- need6(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
44305
+ need6(basename9(path) === "known_marketplaces.json", "requires known_marketplaces.json");
44094
44306
  need6(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
44095
44307
  const ancestors2 = parents2(path), initial = lstatSync20(path, { bigint: true });
44096
44308
  need6(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
@@ -44914,7 +45126,7 @@ function assertReviewedClaudeCacheClosures(home, config, review, canonical9) {
44914
45126
  throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
44915
45127
  }
44916
45128
  if ([cacheAliasRoot, cacheRoot].some((root2) => row.installPath === root2 || row.installPath.startsWith(root2 + sep9))) {
44917
- if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename9(row.installPath) !== row.version)) {
45129
+ if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename10(row.installPath) !== row.version)) {
44918
45130
  throw new Error("Reviewed Claude discovery has a malformed active cache registration");
44919
45131
  }
44920
45132
  if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" && isAbsolute23(row.projectPath) && resolve22(row.projectPath) === row.projectPath && row.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters) {} else
@@ -45192,7 +45404,7 @@ function absentRetiredClaudeRoots(binding) {
45192
45404
  if (!targetValid || !targetScopes.has("user\x00"))
45193
45405
  continue;
45194
45406
  const active = rows[0]?.installPath;
45195
- if (typeof active !== "string" || rows[0]?.version !== basename9(active) || dirname20(active) !== dirname20(root2) || active === root2 || !lstatSync24(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync11(active) !== active)
45407
+ if (typeof active !== "string" || rows[0]?.version !== basename10(active) || dirname20(active) !== dirname20(root2) || active === root2 || !lstatSync24(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync11(active) !== active)
45196
45408
  continue;
45197
45409
  const activeManifest = full(join29(active, ".claude-plugin/plugin.json"));
45198
45410
  if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
@@ -45201,14 +45413,15 @@ function absentRetiredClaudeRoots(binding) {
45201
45413
  }
45202
45414
  return [...result];
45203
45415
  }
45204
- function codexSemanticCacheSourceRole(source, cacheRoot, parents3) {
45416
+ function codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParents = []) {
45205
45417
  if (!isAbsolute23(source.path) || resolve22(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")
45206
45418
  return false;
45207
45419
  const parts = relative7(cacheRoot, source.path).split(sep9);
45208
45420
  if (parts.length < 3 || !parents3.includes(join29(cacheRoot, parts[0], parts[1])))
45209
45421
  return false;
45210
45422
  const tail = parts.slice(3).join("/");
45211
- 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");
45423
+ const parent = join29(cacheRoot, parts[0], parts[1]);
45424
+ 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");
45212
45425
  }
45213
45426
  function codexSemanticCacheDirectoryRole(path, cacheRoot) {
45214
45427
  return isAbsolute23(path) && resolve22(path) === path && !/[\x00-\x1f\x7f]/.test(path) && (path === cacheRoot || path.startsWith(cacheRoot + sep9));
@@ -45240,20 +45453,28 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
45240
45453
  const cacheRoot = proof.witness.cacheRoot;
45241
45454
  if (controls.some((control) => dirname20(dirname20(control.pluginParent)) !== cacheRoot))
45242
45455
  throw new Error("Codex semantic cache names another enrolled cache");
45243
- const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...proof.appOnlyParents.map((parent) => parent.pluginParent)])];
45244
- const sources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3));
45456
+ const reviewedHookParents = proof.reviewedHookParents ?? [];
45457
+ 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 || !isDeepStrictEqual6((proof.witness.hookParents ?? []).map(({ manifestSha256: _manifest, hooksSha256: _hooks, receiptSha256: _receipt, ...parent }) => parent), reviewedHookParents)) {
45458
+ throw new Error("Invalid reviewed native-hook cache role");
45459
+ }
45460
+ for (const parent of reviewedHookParents)
45461
+ 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")))
45462
+ throw new Error("Local marketplace hook parent lost its enrolled source witness");
45463
+ const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...proof.appOnlyParents.map((parent) => parent.pluginParent), ...reviewedHookParents.map((parent) => parent.pluginParent)])];
45464
+ const hookParentPaths = reviewedHookParents.map((parent) => parent.pluginParent);
45465
+ const sources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParentPaths));
45245
45466
  const directories = (binding.directories ?? []).filter((directory) => codexSemanticCacheDirectoryRole(directory.path, cacheRoot));
45246
45467
  if (!directories.length || !isDeepStrictEqual6(sources, proof.supersededSources) || !isDeepStrictEqual6(directories, proof.supersededDirectories))
45247
45468
  throw new Error("Codex semantic cache provenance changed");
45248
45469
  const configPath = proof.configPath;
45249
- if (!isAbsolute23(configPath) || resolve22(configPath) !== configPath || basename9(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
45470
+ if (!isAbsolute23(configPath) || resolve22(configPath) !== configPath || basename10(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
45250
45471
  throw new Error("Invalid semantic cache configuration source");
45251
45472
  const configSource = binding.sources.find((source) => source.path === configPath && source.sha256 !== null && source.format === undefined && source.fields === undefined);
45252
45473
  if (!configSource || projected(configSource) !== configSource.sha256)
45253
45474
  throw new Error("Codex semantic cache requires unchanged reviewed configuration");
45254
45475
  assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, proof.hookRootAlias);
45255
45476
  const rules = parseConfig(read2(configPath), configPath, true).skills?.config ?? [];
45256
- const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, rules });
45477
+ const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, reviewedHookParents, rules });
45257
45478
  assertCodexSemanticCacheWitnessUnchanged(proof.witness, current);
45258
45479
  return proof;
45259
45480
  }
@@ -45337,7 +45558,7 @@ function codexInstallationRoots(binding) {
45337
45558
  const config = join29(dirname20(dirname20(cache)), "config.toml"), home = dirname20(dirname20(dirname20(cache)));
45338
45559
  const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
45339
45560
  const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join29(home, path));
45340
- if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep9) || input.sourceRoot.startsWith(root2 + sep9)) || binding.sources.some((source) => basename9(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep9)))))
45561
+ if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep9) || input.sourceRoot.startsWith(root2 + sep9)) || binding.sources.some((source) => basename10(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep9)))))
45341
45562
  throw new Error("Native installation input overlaps configuration or loading roots");
45342
45563
  if (proof.plugins.some((input) => dirname20(dirname20(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join29(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
45343
45564
  throw new Error("Missing native installation input source witness");
@@ -45349,13 +45570,13 @@ function codexInstallationRoots(binding) {
45349
45570
  });
45350
45571
  }
45351
45572
  function assertMarketplaceBinding(binding, source) {
45352
- if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json"))))
45573
+ if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename10(source.path) !== "plugin.json" || !source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json"))))
45353
45574
  throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
45354
- if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename9(source.path) !== "sumi.json"))
45575
+ if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename10(source.path) !== "sumi.json"))
45355
45576
  throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
45356
- 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"))
45577
+ 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"))
45357
45578
  throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
45358
- 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"))
45579
+ 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"))
45359
45580
  throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
45360
45581
  if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
45361
45582
  throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
@@ -45473,7 +45694,7 @@ function verifyAutomaticDiscoveryClosure(binding, options) {
45473
45694
  const current = resolveAgentDiscovery({ home: options.home, agent: binding.agent, canonical: options.canonical, executable: runtime });
45474
45695
  if (JSON.stringify(current) === JSON.stringify(binding))
45475
45696
  return;
45476
- const reviewedWithRuntime = (binding.builtinNames?.length ?? 0) > 0 || binding.sources.some((source) => basename9(source.path) === "package.json");
45697
+ const reviewedWithRuntime = (binding.builtinNames?.length ?? 0) > 0 || binding.sources.some((source) => basename10(source.path) === "package.json");
45477
45698
  const otherwiseCurrent = current.method === binding.method && JSON.stringify(current.roots) === JSON.stringify(binding.roots) && JSON.stringify(current.directories) === JSON.stringify(binding.directories) && current.sources.every((source) => binding.sources.some((saved) => isDeepStrictEqual6(saved, source)));
45478
45699
  if (command && gap && runtime === null && reviewedWithRuntime && otherwiseCurrent)
45479
45700
  throw discoveryRootUnresolved(binding.agent, command, gap);
@@ -45616,7 +45837,7 @@ function resolveAgentDiscovery(options) {
45616
45837
  throw new Error("Discovery review must include the agent configuration source");
45617
45838
  const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical9(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical9(configPath), source)) : sources;
45618
45839
  const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
45619
- 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")))
45840
+ 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")))
45620
45841
  return source;
45621
45842
  const pluginRoot = dirname20(dirname20(source.path)), hooksPath = join29(pluginRoot, "hooks/hooks.json");
45622
45843
  const hookStat = lstatSync24(hooksPath, { throwIfNoEntry: false });
@@ -47524,7 +47745,7 @@ function planAgentSettingsWitnessUpgrade(options) {
47524
47745
  return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join30(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join30(dataDir2, "agent-policy.json"), before: snapshot2.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], ...policy.bridge.discoveryExecutables ? { discoveryExecutables: policy.bridge.discoveryExecutables } : {}, rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
47525
47746
  }
47526
47747
  function planCodexSemanticCacheWitnessUpgrade(options) {
47527
- if (options.agent !== "codex" || !/^[a-f0-9]{64}$/.test(options.expectedPolicySha256) || !/^[a-f0-9]{64}$/.test(options.expectedSettingsSha256) || options.expectedCacheWitnessSha256 !== undefined && !/^[a-f0-9]{64}$/.test(options.expectedCacheWitnessSha256) || !Array.isArray(options.appOnlyParents) || options.appOnlyParents.length > 4096 || new Set(options.appOnlyParents).size !== options.appOnlyParents.length)
47748
+ if (options.agent !== "codex" || !/^[a-f0-9]{64}$/.test(options.expectedPolicySha256) || !/^[a-f0-9]{64}$/.test(options.expectedSettingsSha256) || options.expectedCacheWitnessSha256 !== undefined && !/^[a-f0-9]{64}$/.test(options.expectedCacheWitnessSha256) || !Array.isArray(options.appOnlyParents) || options.appOnlyParents.length > 4096 || new Set(options.appOnlyParents).size !== options.appOnlyParents.length || options.reviewedHookParents !== undefined && (!Array.isArray(options.reviewedHookParents) || options.reviewedHookParents.length > 4096 || new Set(options.reviewedHookParents).size !== options.reviewedHookParents.length))
47528
47749
  throw new Error("Invalid Codex semantic cache upgrade request");
47529
47750
  const home = resolve23(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
47530
47751
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
@@ -47548,14 +47769,23 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
47548
47769
  throw new Error("Native settings preimage changed");
47549
47770
  const boundedRead = (path) => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024));
47550
47771
  const unchangedFullSource = (path) => {
47551
- const source = binding.sources.find((source2) => source2.path === path && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && source2.reviewArtifact === undefined && (source2.hashMode === undefined || source2.hashMode === "bytes"));
47552
- if (!source)
47553
- throw new Error("Cache upgrade lacks prior full identity source");
47772
+ const sources = binding.sources.filter((source2) => source2.path === path && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && source2.reviewArtifact === undefined && (source2.hashMode === undefined || source2.hashMode === "bytes"));
47773
+ if (sources.length !== 1)
47774
+ throw new Error("Cache upgrade requires one unambiguous prior full identity source");
47775
+ const source = sources[0];
47554
47776
  const text2 = boundedRead(path);
47555
47777
  if (sha5(text2) !== source.sha256)
47556
47778
  throw new Error("Reviewed cache identity source changed");
47557
47779
  return text2;
47558
47780
  };
47781
+ const unchangedReviewedHookSource = (path) => {
47782
+ const sources = binding.sources.filter((source) => source.path === path);
47783
+ if (!sources.length)
47784
+ throw new Error("Cache upgrade lacks prior full identity source");
47785
+ if (sources.length !== 1)
47786
+ throw new Error("Reviewed hook identity source is ambiguous");
47787
+ return unchangedFullSource(path);
47788
+ };
47559
47789
  const appOnlyParents = options.appOnlyParents.map((parent) => {
47560
47790
  const parts = relative8(cacheRoot, parent).split(sep10);
47561
47791
  if (!isAbsolute25(parent) || resolve23(parent) !== parent || parts.length !== 2 || parts.some((part) => !/^[A-Za-z0-9_-]{1,64}$/.test(part)) || controls.some((control) => control.pluginParent === parent))
@@ -47570,11 +47800,60 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
47570
47800
  unchangedFullSource(source.path);
47571
47801
  return { role: "app-only", pluginId: `${parts[1]}@${parts[0]}`, namespace: parts[1], pluginParent: parent, remotePluginId: receipt.remote_plugin_id };
47572
47802
  }).sort((a, b) => a.pluginParent.localeCompare(b.pluginParent));
47573
- const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...appOnlyParents.map((parent) => parent.pluginParent)])];
47803
+ const reviewedHookParents = (options.reviewedHookParents ?? []).map((parent) => {
47804
+ const parts = relative8(cacheRoot, parent).split(sep10);
47805
+ if (!isAbsolute25(parent) || resolve23(parent) !== parent || parts.length !== 2 || parts.some((part) => !/^[A-Za-z0-9_-]{1,64}$/.test(part)) || controls.some((control) => control.pluginParent === parent) || appOnlyParents.some((role) => role.pluginParent === parent))
47806
+ throw new Error("Unsupported reviewed native-hook parent role");
47807
+ const receiptPath = join30(parent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync26(receiptPath, { throwIfNoEntry: false });
47808
+ let identity5;
47809
+ if (receiptStat) {
47810
+ if (!receiptStat.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > 16 * 1024)
47811
+ throw new Error("Invalid reviewed native-hook install receipt");
47812
+ const receiptText = unchangedReviewedHookSource(receiptPath);
47813
+ let receipt;
47814
+ try {
47815
+ hashNativeJsonControls(receiptText);
47816
+ receipt = JSON.parse(receiptText);
47817
+ } catch {
47818
+ throw new Error("Invalid reviewed native-hook install receipt");
47819
+ }
47820
+ if (!receipt || Array.isArray(receipt) || Object.keys(receipt).length !== 2 || receipt.schema_version !== 1 || typeof receipt.remote_plugin_id !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(receipt.remote_plugin_id))
47821
+ throw new Error("Invalid reviewed native-hook install receipt");
47822
+ identity5 = { role: "reviewed-hook", pluginId: `${parts[1]}@${parts[0]}`, namespace: parts[1], pluginParent: parent, installation: "remote-receipt", remotePluginId: receipt.remote_plugin_id };
47823
+ } else {
47824
+ const pluginId2 = `${parts[1]}@${parts[0]}`;
47825
+ const marketplaceSources = binding.sources.filter((source2) => basename11(source2.path) === "marketplace.json" && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && source2.reviewArtifact === undefined && (source2.hashMode === undefined || source2.hashMode === "bytes"));
47826
+ const matches = marketplaceSources.flatMap((source2) => {
47827
+ const text2 = unchangedFullSource(source2.path);
47828
+ return codexLocalMarketplaceMapsPlugin(text2, parts[0], parts[1]) ? [{ source: source2, text: text2 }] : [];
47829
+ });
47830
+ if (matches.length !== 1)
47831
+ throw new Error("Local marketplace hook parent lacks one exact enrolled marketplace source");
47832
+ const { source } = matches[0];
47833
+ const config = Bun.TOML.parse(settings);
47834
+ if (config.plugins?.[pluginId2]?.enabled !== true)
47835
+ throw new Error("Local marketplace hook parent is not enabled in the unchanged Codex settings");
47836
+ identity5 = { role: "reviewed-hook", pluginId: pluginId2, namespace: parts[1], pluginParent: parent, installation: "local-marketplace", marketplaceSourcePath: source.path, marketplaceSha256: source.sha256 };
47837
+ }
47838
+ const versions = readdirSync9(parent).filter((name) => name !== ".codex-remote-plugin-install.json");
47839
+ if (!versions.length || versions.length > 4096)
47840
+ throw new Error("Reviewed native-hook parent has no bounded materializations");
47841
+ for (const version2 of versions) {
47842
+ if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
47843
+ throw new Error("Invalid reviewed native-hook version identity");
47844
+ const root2 = join30(parent, version2), stat2 = lstatSync26(root2, { throwIfNoEntry: false });
47845
+ if (!stat2?.isDirectory() || stat2.isSymbolicLink() || realpathSync13(root2) !== root2)
47846
+ throw new Error("Invalid reviewed native-hook materialization");
47847
+ unchangedReviewedHookSource(join30(root2, ".codex-plugin/plugin.json"));
47848
+ unchangedReviewedHookSource(join30(root2, "hooks/hooks.json"));
47849
+ }
47850
+ return identity5;
47851
+ }).sort((a, b) => a.pluginParent.localeCompare(b.pluginParent));
47852
+ const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...appOnlyParents.map((parent) => parent.pluginParent), ...reviewedHookParents.map((parent) => parent.pluginParent)])];
47574
47853
  const reviewedAlias = aliases.find((alias) => alias.agent === "codex");
47575
47854
  const hookRootAlias = reviewedAlias ? { alias: reviewedAlias.alias, target: reviewedAlias.target } : null;
47576
47855
  assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, hookRootAlias);
47577
- const supersededSources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3));
47856
+ const supersededSources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3, reviewedHookParents.map((parent) => parent.pluginParent)));
47578
47857
  for (const source of supersededSources)
47579
47858
  if ([".app.json", ".mcp.json"].includes(source.path.split(sep10).at(-1)))
47580
47859
  unchangedFullSource(source.path);
@@ -47582,7 +47861,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
47582
47861
  if (!supersededDirectories.some((directory) => directory.path === cacheRoot) || (binding.directories ?? []).some((directory) => cacheRoot.startsWith(directory.path + sep10)))
47583
47862
  throw new Error("Cache upgrade requires exact cache directory coverage without an unproved ancestor projection");
47584
47863
  const rules = Bun.TOML.parse(settings).skills?.config ?? [];
47585
- const witness = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents, rules, read: boundedRead });
47864
+ const witness = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents, reviewedHookParents, rules, read: boundedRead });
47586
47865
  if (options.expectedCacheWitnessSha256 !== undefined && witness.sha256 !== options.expectedCacheWitnessSha256)
47587
47866
  throw new Error("Reviewed semantic cache preimage changed");
47588
47867
  const replacement = { ...binding, codexDisabledPluginSkills: controls, codexSemanticCache: {
@@ -47591,6 +47870,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
47591
47870
  hookRootAlias,
47592
47871
  witness,
47593
47872
  appOnlyParents,
47873
+ reviewedHookParents,
47594
47874
  previousPolicySha256: options.expectedPolicySha256,
47595
47875
  supersededSources,
47596
47876
  supersededDirectories
@@ -47609,7 +47889,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
47609
47889
  rootAliases: aliases,
47610
47890
  managedAgentChecks: { home, agents: ["codex"] },
47611
47891
  ...policy.bridge.discoveryExecutables ? { discoveryExecutables: policy.bridge.discoveryExecutables } : {},
47612
- cacheWitnessUpgrade: { ...options, home, dataDir: dataDir2, appOnlyParents: appOnlyParents.map((parent) => parent.pluginParent) }
47892
+ cacheWitnessUpgrade: { ...options, home, dataDir: dataDir2, appOnlyParents: appOnlyParents.map((parent) => parent.pluginParent), reviewedHookParents: reviewedHookParents.map((parent) => parent.pluginParent) }
47613
47893
  };
47614
47894
  }
47615
47895
  function planReviewedArtifactMigration(options) {
@@ -48148,7 +48428,7 @@ import {
48148
48428
  statSync as statSync11,
48149
48429
  writeFileSync as writeFileSync7
48150
48430
  } from "fs";
48151
- import { basename as basename12, dirname as dirname24, isAbsolute as isAbsolute26, join as join34, normalize as normalize4, relative as relative10, resolve as resolve25, sep as sep13 } from "path";
48431
+ import { basename as basename14, dirname as dirname24, isAbsolute as isAbsolute26, join as join34, normalize as normalize4, relative as relative10, resolve as resolve25, sep as sep13 } from "path";
48152
48432
 
48153
48433
  // src/lib/registry-data/index.ts
48154
48434
  var SKILLS = [];
@@ -48673,7 +48953,7 @@ import {
48673
48953
  realpathSync as realpathSync14,
48674
48954
  writeFileSync as writeFileSync6
48675
48955
  } from "fs";
48676
- import { basename as basename10, dirname as dirname22, join as join32, relative as relative9 } from "path";
48956
+ import { basename as basename12, dirname as dirname22, join as join32, relative as relative9 } from "path";
48677
48957
  var ANY_SEGMENT_COPY_EXCLUDES = new Set([
48678
48958
  ".git",
48679
48959
  ".DS_Store",
@@ -48723,11 +49003,11 @@ function normalizeNewPortableSkillName(name) {
48723
49003
  throw new Error(`Invalid skill name '${name}'. Include letters or numbers.`);
48724
49004
  return normalized;
48725
49005
  }
48726
- function readPortableSkillManifest(skillPath, fallbackName = basename10(skillPath)) {
49006
+ function readPortableSkillManifest(skillPath, fallbackName = basename12(skillPath)) {
48727
49007
  return readManifest(skillPath, fallbackName, normalizePortableSkillName);
48728
49008
  }
48729
49009
  function readPortableSkillManifestForImport(skillPath) {
48730
- return readManifest(skillPath, basename10(skillPath), normalizeNewPortableSkillName);
49010
+ return readManifest(skillPath, basename12(skillPath), normalizeNewPortableSkillName);
48731
49011
  }
48732
49012
  function readManifest(skillPath, fallbackName, normalizeName) {
48733
49013
  const skillJsonPath = join32(skillPath, "skill.json");
@@ -49281,7 +49561,7 @@ function inferRuntimeFromCommands(commands) {
49281
49561
  function readJsonObject(path) {
49282
49562
  const parsed = JSON.parse(readFileSync20(path, "utf-8"));
49283
49563
  if (!isRecord3(parsed))
49284
- throw new Error(`${basename10(path)} must contain a JSON object`);
49564
+ throw new Error(`${basename12(path)} must contain a JSON object`);
49285
49565
  return parsed;
49286
49566
  }
49287
49567
  function hasPackageDependencies(pkgPath) {
@@ -49319,7 +49599,7 @@ function escapeJsString(value) {
49319
49599
  // src/lib/authoring-path.ts
49320
49600
  import { lstatSync as lstatSync28, realpathSync as realpathSync15 } from "fs";
49321
49601
  import { homedir as homedir4 } from "os";
49322
- import { basename as basename11, dirname as dirname23, join as join33, resolve as resolve24, sep as sep12 } from "path";
49602
+ import { basename as basename13, dirname as dirname23, join as join33, resolve as resolve24, sep as sep12 } from "path";
49323
49603
  var NATIVE_DISCOVERY_ROOTS = NATIVE_SKILL_ROOTS.map(([, path]) => path.split("/"));
49324
49604
  function pathParts(path) {
49325
49605
  return resolve24(path).split(sep12).filter(Boolean);
@@ -49339,7 +49619,7 @@ function physicalPath(path) {
49339
49619
  let cursor = resolve24(path);
49340
49620
  const suffix = [];
49341
49621
  while (!lstatSync28(cursor, { throwIfNoEntry: false })) {
49342
- suffix.unshift(basename11(cursor));
49622
+ suffix.unshift(basename13(cursor));
49343
49623
  const parent = dirname23(cursor);
49344
49624
  if (parent === cursor)
49345
49625
  return resolve24(path);
@@ -49558,7 +49838,7 @@ function physicalImportPath(path) {
49558
49838
  let ancestor = resolve25(path);
49559
49839
  const suffix = [];
49560
49840
  while (!existsSync10(ancestor)) {
49561
- suffix.unshift(basename12(ancestor));
49841
+ suffix.unshift(basename14(ancestor));
49562
49842
  ancestor = dirname24(ancestor);
49563
49843
  }
49564
49844
  return join34(realpathSync16(ancestor), ...suffix);
@@ -49583,8 +49863,8 @@ function portPortableSkill(sourcePath, options = {}) {
49583
49863
  const explicitName = options.name != null;
49584
49864
  const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
49585
49865
  if (isOfficialSkillName(skillName) && !options.allowShadow) {
49586
- const sourceSlug = safeNormalizeName(basename12(absoluteSource));
49587
- 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.`;
49866
+ const sourceSlug = safeNormalizeName(basename14(absoluteSource));
49867
+ const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename14(absoluteSource)}')` : ""} matches a bundled official skill.`;
49588
49868
  throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
49589
49869
  }
49590
49870
  const readOnlyDestination = join34(resolvePortableSkillsRoot(options, false), skillName);
@@ -50112,7 +50392,7 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
50112
50392
  return { action, path: skillMdPath };
50113
50393
  const parentDir = dirname25(dir);
50114
50394
  mkdirSync10(parentDir, { recursive: true });
50115
- const transactionDir = mkdtempSync2(join35(parentDir, `.hasna-skills-write-${basename13(dir)}-`));
50395
+ const transactionDir = mkdtempSync2(join35(parentDir, `.hasna-skills-write-${basename15(dir)}-`));
50116
50396
  const candidateDir = join35(transactionDir, "candidate");
50117
50397
  const backupDir = join35(transactionDir, "backup");
50118
50398
  const candidateSkillMdPath = join35(candidateDir, "SKILL.md");