@hasna/skills 0.10.72 → 0.10.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6988,8 +6988,8 @@ var require_public_api = __commonJS((exports) => {
6988
6988
  });
6989
6989
 
6990
6990
  // src/lib/registry.ts
6991
- import { existsSync as existsSync15, readFileSync as readFileSync26, readdirSync as readdirSync14 } from "fs";
6992
- import { join as join40 } from "path";
6991
+ import { existsSync as existsSync15, readFileSync as readFileSync27, readdirSync as readdirSync14 } from "fs";
6992
+ import { join as join41 } from "path";
6993
6993
 
6994
6994
  // src/lib/config.ts
6995
6995
  import { closeSync, constants, existsSync as existsSync2, fstatSync, lstatSync, openSync, readFileSync, statSync, writeFileSync, mkdirSync } from "fs";
@@ -7266,7 +7266,7 @@ import {
7266
7266
  statSync as statSync13,
7267
7267
  writeFileSync as writeFileSync9
7268
7268
  } from "fs";
7269
- import { basename as basename17, dirname as dirname27, isAbsolute as isAbsolute29, join as join39, normalize as normalize4, relative as relative11, resolve as resolve28, sep as sep16 } from "path";
7269
+ import { basename as basename17, dirname as dirname28, isAbsolute as isAbsolute29, join as join40, normalize as normalize4, relative as relative11, resolve as resolve29, sep as sep17 } from "path";
7270
7270
 
7271
7271
  // src/lib/registry-data/index.ts
7272
7272
  var SKILLS = [];
@@ -8924,9 +8924,9 @@ var NATIVE_SKILL_ROOTS = [
8924
8924
  ];
8925
8925
 
8926
8926
  // src/lib/authoring-path.ts
8927
- import { lstatSync as lstatSync32, realpathSync as realpathSync14 } from "fs";
8927
+ import { lstatSync as lstatSync33, realpathSync as realpathSync14 } from "fs";
8928
8928
  import { homedir as homedir6 } from "os";
8929
- import { basename as basename16, dirname as dirname26, join as join38, resolve as resolve27, sep as sep15 } from "path";
8929
+ import { basename as basename16, dirname as dirname27, join as join39, resolve as resolve28, sep as sep16 } from "path";
8930
8930
 
8931
8931
  // src/lib/agent-adapters.ts
8932
8932
  var INTEGRATION_AGENTS = ["claude", "codex", "gemini", "opencode", "cursor", "hermes", "sumi"];
@@ -9973,8 +9973,8 @@ function assertAgentPolicyCollections(policy) {
9973
9973
 
9974
9974
  // src/lib/agent-discovery.ts
9975
9975
  import { createHash as createHash30 } from "crypto";
9976
- import { lstatSync as lstatSync31, readFileSync as readFileSync25, readdirSync as readdirSync12, realpathSync as realpathSync13 } from "fs";
9977
- import { basename as basename15, dirname as dirname25, isAbsolute as isAbsolute28, join as join37, relative as relative10, resolve as resolve26, sep as sep14 } from "path";
9976
+ import { lstatSync as lstatSync32, readFileSync as readFileSync26, readdirSync as readdirSync12, realpathSync as realpathSync13 } from "fs";
9977
+ import { basename as basename15, dirname as dirname26, isAbsolute as isAbsolute28, join as join38, relative as relative10, resolve as resolve27, sep as sep15 } from "path";
9978
9978
  import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
9979
9979
 
9980
9980
  // node_modules/yaml/dist/index.js
@@ -12430,6 +12430,10 @@ function canonical4(value, depth = 0, budget2 = { remaining: 65536 }) {
12430
12430
  function hashCodexSettingsReplacement(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
12431
12431
  need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
12432
12432
  budget2.remaining -= Buffer.byteLength(text2);
12433
+ const prepared = prepareCodexSettingsV1(text2);
12434
+ return finishCodexSettingsV1(prepared.config, prepared.tokens);
12435
+ }
12436
+ function prepareCodexSettingsV1(text2) {
12433
12437
  let config;
12434
12438
  try {
12435
12439
  config = Bun.TOML.parse(text2);
@@ -12437,6 +12441,9 @@ function hashCodexSettingsReplacement(text2, budget2 = { remaining: 256 * 1024 *
12437
12441
  throw new Error("Invalid Codex settings witness");
12438
12442
  }
12439
12443
  need4(config && typeof config === "object" && !Array.isArray(config));
12444
+ return { config, tokens: numericTokens(text2) };
12445
+ }
12446
+ function finishCodexSettingsV1(config, tokens) {
12440
12447
  if (Object.hasOwn(config, "model")) {
12441
12448
  need4(typeof config.model === "string" && /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/.test(config.model));
12442
12449
  delete config.model;
@@ -12446,7 +12453,7 @@ function hashCodexSettingsReplacement(text2, budget2 = { remaining: 256 * 1024 *
12446
12453
  need4(typeof config[key] === "string" && values.has(config[key]));
12447
12454
  delete config[key];
12448
12455
  }
12449
- return sha(`hasna.skills.codex-settings.v1\x00${JSON.stringify([canonical4(config), numericTokens(text2)])}`);
12456
+ return sha(`hasna.skills.codex-settings.v1\x00${JSON.stringify([canonical4(config), tokens])}`);
12450
12457
  }
12451
12458
  function captureCodexSettings(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
12452
12459
  const text2 = readNativeSettingsWitnessFile(path, budget2, "config.toml");
@@ -13160,7 +13167,7 @@ function projectStatusLine(config) {
13160
13167
  if (!Object.keys(tui).length)
13161
13168
  delete config.tui;
13162
13169
  }
13163
- function settingsDigest2(text2, version = 2, dependencies) {
13170
+ function prepareSettings(text2, version, dependencies) {
13164
13171
  let config;
13165
13172
  try {
13166
13173
  config = Bun.TOML.parse(text2);
@@ -13199,18 +13206,87 @@ function settingsDigest2(text2, version = 2, dependencies) {
13199
13206
  delete config.tui.model_availability_nux;
13200
13207
  if (isRecord3(config.tui) && typeof config.tui.screen_reader_detection_done === "boolean")
13201
13208
  delete config.tui.screen_reader_detection_done;
13202
- config = embedCodexNumericTokens(config, tokens);
13209
+ return { config: embedCodexNumericTokens(config, tokens), numericSource: text2, dependencies };
13210
+ }
13211
+ const mcp = version >= 3 ? projectRegularCodexMcp(config, text2) : { config, numericSource: text2 };
13212
+ return version >= 4 ? projectModelAvailabilityNux(mcp.config, mcp.numericSource) : mcp;
13213
+ }
13214
+ function finishSettings(prepared, version) {
13215
+ const config = prepared.config;
13216
+ if (version === 6) {
13203
13217
  normalize2(config, 6);
13204
13218
  if (isRecord3(config.tui) && !Object.keys(config.tui).length)
13205
13219
  delete config.tui;
13206
- return sha2(`hasna.skills.codex-settings.v6\x00${JSON.stringify([canonical5(config), canonical5(dependencies)])}`);
13220
+ return sha2(`hasna.skills.codex-settings.v6\x00${JSON.stringify([canonical5(config), canonical5(prepared.dependencies)])}`);
13207
13221
  }
13208
- const mcp = version >= 3 ? projectRegularCodexMcp(config, text2) : { config, numericSource: text2 };
13209
- const projected = version >= 4 ? projectModelAvailabilityNux(mcp.config, mcp.numericSource) : mcp;
13210
- normalize2(projected.config, version);
13211
- const values = [canonical5(projected.config), numericTokens2(projected.numericSource)];
13222
+ normalize2(config, version);
13223
+ const values = [canonical5(config), numericTokens2(prepared.numericSource)];
13212
13224
  return sha2(`hasna.skills.codex-settings.v${version}\x00${JSON.stringify(values)}`);
13213
13225
  }
13226
+ function settingsDigest2(text2, version = 2, dependencies) {
13227
+ return finishSettings(prepareSettings(text2, version, dependencies), version);
13228
+ }
13229
+ var SCREEN_READER_RECEIPT = "screen_reader_detection_done";
13230
+ function cloneTree(value) {
13231
+ if (Array.isArray(value))
13232
+ return value.map(cloneTree);
13233
+ if (isRecord3(value) && [Object.prototype, null].includes(Object.getPrototypeOf(value)))
13234
+ return Object.fromEntries(Object.entries(value).map(([key2, child2]) => [key2, cloneTree(child2)]));
13235
+ return value;
13236
+ }
13237
+ function receiptEdits(config) {
13238
+ const tui = config.tui;
13239
+ const set = (value) => (target) => {
13240
+ if (!isRecord3(target.tui))
13241
+ target.tui = {};
13242
+ target.tui[SCREEN_READER_RECEIPT] = value;
13243
+ };
13244
+ if (tui === undefined || isRecord3(tui) && !Object.hasOwn(tui, SCREEN_READER_RECEIPT))
13245
+ return [set(true), set(false)];
13246
+ if (!isRecord3(tui) || typeof tui[SCREEN_READER_RECEIPT] !== "boolean")
13247
+ return [];
13248
+ const remove = (dropEmpty) => (target) => {
13249
+ delete target.tui[SCREEN_READER_RECEIPT];
13250
+ if (dropEmpty && !Object.keys(target.tui).length)
13251
+ delete target.tui;
13252
+ };
13253
+ return [remove(true), ...Object.keys(tui).length === 1 ? [remove(false)] : [], set(!tui[SCREEN_READER_RECEIPT])];
13254
+ }
13255
+ function codexSettingsToleratesScreenReaderReceipt(text2, hashMode, expected) {
13256
+ try {
13257
+ if (Buffer.byteLength(text2) > 1024 * 1024 || !/^[a-f0-9]{64}$/.test(expected))
13258
+ return false;
13259
+ if (hashMode === "codex-settings-v1") {
13260
+ const prepared2 = prepareCodexSettingsV1(text2);
13261
+ return receiptEdits(prepared2.config).some((edit) => {
13262
+ const candidate = cloneTree(prepared2.config);
13263
+ edit(candidate);
13264
+ return finishCodexSettingsV1(candidate, prepared2.tokens) === expected;
13265
+ });
13266
+ }
13267
+ const version = Number(hashMode.slice("codex-settings-v".length));
13268
+ if (![2, 3, 4, 5].includes(version))
13269
+ return false;
13270
+ const prepared = prepareSettings(text2, version);
13271
+ return receiptEdits(prepared.config).some((edit) => {
13272
+ const candidate = cloneTree(prepared.config);
13273
+ edit(candidate);
13274
+ if (version >= 4 && isRecord3(candidate.tui) && !Object.keys(candidate.tui).length)
13275
+ delete candidate.tui;
13276
+ return finishSettings({ ...prepared, config: candidate }, version) === expected;
13277
+ });
13278
+ } catch {
13279
+ return false;
13280
+ }
13281
+ }
13282
+ function codexSettingsWitnessMatch(path, hashMode, expected, budget2 = { remaining: 256 * 1024 * 1024 }) {
13283
+ const text2 = readNativeSettingsWitnessFile(path, budget2, "config.toml");
13284
+ need7(Buffer.byteLength(text2) <= 1024 * 1024);
13285
+ const exact = hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(text2) : settingsDigest2(text2, Number(hashMode.slice("codex-settings-v".length)));
13286
+ if (exact === expected)
13287
+ return "exact";
13288
+ return codexSettingsToleratesScreenReaderReceipt(text2, hashMode, expected) ? "screen-reader-receipt" : null;
13289
+ }
13214
13290
  function hashCodexSettingsReplacementV2(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
13215
13291
  need7(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
13216
13292
  budget2.remaining -= Buffer.byteLength(text2);
@@ -13925,6 +14001,8 @@ import { execFile, spawn as spawn2 } from "child_process";
13925
14001
  import { realpathSync as realpathSync4, statSync as statSync8 } from "fs";
13926
14002
  import { isAbsolute as isAbsolute14 } from "path";
13927
14003
  import { promisify } from "util";
14004
+ var CODEX_CONFIG_FALLBACK_SUMMARY = "Invalid configuration; using defaults.";
14005
+ var CODEX_CONFIG_INVALID = "CODEX_HOOK_TRUST_NATIVE_CONFIG_INVALID: Codex could not load its configuration and fell back to defaults; repair config.toml (run codex once to see the error) and retry";
13928
14006
  async function connectCodexHookRpc(options) {
13929
14007
  const timeoutMs = options.timeoutMs ?? 20000;
13930
14008
  if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 20000)
@@ -13953,7 +14031,7 @@ async function connectCodexHookRpc(options) {
13953
14031
  else
13954
14032
  env.CODEX_HOME = options.codexHome;
13955
14033
  const corpusLease = acquireCodexCorpusWrite([options.codexHome ?? join17(options.home, ".codex")], { codexCommand: binary });
13956
- const child2 = spawn2(binary, ["app-server", "--strict-config", "--stdio"], {
14034
+ const child2 = spawn2(binary, ["app-server", "--stdio"], {
13957
14035
  cwd: options.home,
13958
14036
  env,
13959
14037
  stdio: ["pipe", "pipe", "pipe"]
@@ -13965,12 +14043,12 @@ async function connectCodexHookRpc(options) {
13965
14043
  resolve15();
13966
14044
  }));
13967
14045
  const pending = new Map;
13968
- let nextId = 1, buffer = Buffer.alloc(0), stopped = false, diagnosticBytes = 0;
14046
+ let nextId = 1, buffer = Buffer.alloc(0), stopped = false, diagnosticBytes = 0, configInvalid = false;
13969
14047
  const fail2 = () => {
13970
14048
  stopped = true;
13971
14049
  for (const value of pending.values()) {
13972
14050
  clearTimeout(value.timer);
13973
- value.reject(new Error("CODEX_HOOK_TRUST_NATIVE_RPC_FAILED"));
14051
+ value.reject(new Error(configInvalid ? CODEX_CONFIG_INVALID : "CODEX_HOOK_TRUST_NATIVE_RPC_FAILED"));
13974
14052
  }
13975
14053
  pending.clear();
13976
14054
  };
@@ -14010,6 +14088,12 @@ async function connectCodexHookRpc(options) {
14010
14088
  child2.kill();
14011
14089
  return;
14012
14090
  }
14091
+ if (!("id" in value) && value.method === "configWarning" && value.params?.summary === CODEX_CONFIG_FALLBACK_SUMMARY) {
14092
+ configInvalid = true;
14093
+ fail2();
14094
+ child2.kill();
14095
+ return;
14096
+ }
14013
14097
  const waiting = pending.get(value.id);
14014
14098
  if (!waiting)
14015
14099
  continue;
@@ -14026,7 +14110,7 @@ async function connectCodexHookRpc(options) {
14026
14110
  processId: child2.pid,
14027
14111
  request(method, params) {
14028
14112
  if (stopped)
14029
- return Promise.reject(new Error("CODEX_HOOK_TRUST_NATIVE_RPC_CLOSED"));
14113
+ return Promise.reject(new Error(configInvalid ? CODEX_CONFIG_INVALID : "CODEX_HOOK_TRUST_NATIVE_RPC_CLOSED"));
14030
14114
  return new Promise((resolve15, reject) => {
14031
14115
  const id = nextId++;
14032
14116
  const timer = setTimeout(() => {
@@ -14069,7 +14153,7 @@ async function connectCodexHookRpc(options) {
14069
14153
  return rpc;
14070
14154
  } catch {
14071
14155
  await rpc.close();
14072
- throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED: native hooks/list and versioned config writes are required");
14156
+ throw new Error(configInvalid ? CODEX_CONFIG_INVALID : "CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED: native hooks/list and versioned config writes are required");
14073
14157
  }
14074
14158
  }
14075
14159
 
@@ -15053,14 +15137,14 @@ function projectReviewedClaudePluginManifest(text2, reviewedSha256) {
15053
15137
  }
15054
15138
 
15055
15139
  // src/lib/plugin-discovery.ts
15056
- import { closeSync as closeSync18, constants as constants19, fstatSync as fstatSync18, lstatSync as lstatSync29, openSync as openSync18, opendirSync as opendirSync5, readSync as readSync13 } from "fs";
15057
- import { basename as basename13, dirname as dirname23, isAbsolute as isAbsolute26, join as join36, resolve as resolve24 } from "path";
15140
+ import { closeSync as closeSync18, constants as constants19, fstatSync as fstatSync18, lstatSync as lstatSync30, openSync as openSync18, opendirSync as opendirSync5, readSync as readSync13 } from "fs";
15141
+ import { basename as basename13, dirname as dirname24, isAbsolute as isAbsolute26, join as join37, resolve as resolve25 } from "path";
15058
15142
 
15059
15143
  // src/lib/plugin-admission.ts
15060
15144
  import { homedir as homedir5 } from "os";
15061
- import { isAbsolute as isAbsolute25, join as join35, resolve as resolve23 } from "path";
15145
+ import { isAbsolute as isAbsolute25, join as join36, resolve as resolve24 } from "path";
15062
15146
  // package.json
15063
- var version = "0.10.72";
15147
+ var version = "0.10.73";
15064
15148
  var package_default = {
15065
15149
  name: "@hasna/skills",
15066
15150
  version,
@@ -16905,22 +16989,22 @@ async function prepareSkillDependencies(skillPath, env, timeoutMs = DEFAULT_PREP
16905
16989
  }
16906
16990
 
16907
16991
  // src/lib/skillinfo.ts
16908
- import { existsSync as existsSync13, readFileSync as readFileSync23 } from "fs";
16909
- import { join as join34 } from "path";
16992
+ import { existsSync as existsSync13, readFileSync as readFileSync25 } from "fs";
16993
+ import { join as join35 } from "path";
16910
16994
 
16911
16995
  // src/lib/installer.ts
16912
- import { existsSync as existsSync12, readFileSync as readFileSync21, rmSync as rmSync3 } from "fs";
16913
- import { join as join33 } from "path";
16996
+ import { existsSync as existsSync12, readFileSync as readFileSync23, rmSync as rmSync3 } from "fs";
16997
+ import { join as join34 } from "path";
16914
16998
  import { homedir as homedir4 } from "os";
16915
16999
 
16916
17000
  // src/lib/agent-sync.ts
16917
17001
  import {
16918
17002
  cpSync as cpSync2,
16919
17003
  existsSync as existsSync10,
16920
- lstatSync as lstatSync28,
17004
+ lstatSync as lstatSync29,
16921
17005
  mkdirSync as mkdirSync9,
16922
17006
  mkdtempSync,
16923
- readFileSync as readFileSync19,
17007
+ readFileSync as readFileSync20,
16924
17008
  readdirSync as readdirSync11,
16925
17009
  renameSync as renameSync5,
16926
17010
  rmSync as rmSync2,
@@ -16928,7 +17012,7 @@ import {
16928
17012
  writeFileSync as writeFileSync7
16929
17013
  } from "fs";
16930
17014
  import { homedir as homedir3 } from "os";
16931
- import { basename as basename12, dirname as dirname22, join as join31 } from "path";
17015
+ import { basename as basename12, dirname as dirname23, join as join32 } from "path";
16932
17016
 
16933
17017
  // src/lib/codex-native-skill-policy.ts
16934
17018
  import { createHash as createHash21, randomUUID as randomUUID3 } from "crypto";
@@ -18270,16 +18354,59 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
18270
18354
  refuse4();
18271
18355
  }
18272
18356
 
18357
+ // src/lib/codex-node-modules.ts
18358
+ import { lstatSync as lstatSync21, readFileSync as readFileSync16 } from "fs";
18359
+ import { dirname as dirname19, join as join26, resolve as resolve19, sep as sep12 } from "path";
18360
+ var PLUGIN_MANIFESTS = Object.freeze(["plugin.json", ".codex-plugin/plugin.json", ".claude-plugin/plugin.json", ".cursor-plugin/plugin.json"]);
18361
+ var PLUGIN_ROOT_DEPTH = 3;
18362
+ function codexPluginCacheSkillTree(path, depth) {
18363
+ if (depth <= PLUGIN_ROOT_DEPTH)
18364
+ return true;
18365
+ let root = path;
18366
+ for (let level = depth;level > PLUGIN_ROOT_DEPTH; level--)
18367
+ root = dirname19(root);
18368
+ try {
18369
+ const skillRoots = [join26(root, "skills")];
18370
+ for (const name of PLUGIN_MANIFESTS) {
18371
+ const manifest = join26(root, name), stat2 = lstatSync21(manifest, { throwIfNoEntry: false });
18372
+ if (!stat2)
18373
+ continue;
18374
+ if (!stat2.isFile() || stat2.size > 1024 * 1024)
18375
+ return true;
18376
+ const text2 = new TextDecoder("utf-8", { fatal: true }).decode(readFileSync16(manifest));
18377
+ hashNativeJsonControls(text2);
18378
+ const value = JSON.parse(text2);
18379
+ if (!value || typeof value !== "object" || Array.isArray(value))
18380
+ return true;
18381
+ const declared = value.skills;
18382
+ if (declared === undefined)
18383
+ continue;
18384
+ const paths = typeof declared === "string" ? [declared] : declared;
18385
+ if (!Array.isArray(paths) || paths.some((item) => typeof item !== "string"))
18386
+ return true;
18387
+ for (const item of paths) {
18388
+ const target = resolve19(root, item);
18389
+ if (target !== root && !target.startsWith(root + sep12))
18390
+ return true;
18391
+ skillRoots.push(target.endsWith(`${sep12}SKILL.md`) ? dirname19(target) : target);
18392
+ }
18393
+ }
18394
+ return skillRoots.some((skillRoot) => path === skillRoot || path.startsWith(skillRoot + sep12) || skillRoot.startsWith(path + sep12));
18395
+ } catch {
18396
+ return true;
18397
+ }
18398
+ }
18399
+
18273
18400
  // src/lib/agent-integration.ts
18274
18401
  import { createHash as createHash27, randomUUID as randomUUID4 } from "crypto";
18275
18402
  import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
18276
- import { existsSync as existsSync9, lstatSync as lstatSync27, statSync as statSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync18, readdirSync as readdirSync10, opendirSync as opendirSync4, readlinkSync as readlinkSync7, realpathSync as realpathSync12, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync6, unlinkSync as unlinkSync5, chmodSync, openSync as openSync17, closeSync as closeSync17, fsyncSync as fsyncSync7, fstatSync as fstatSync17, readSync as readSync12, constants as constants18, linkSync as linkSync3 } from "fs";
18277
- import { basename as basename11, dirname as dirname21, join as join30, resolve as resolve22, relative as relative9, isAbsolute as isAbsolute24, sep as sep13 } from "path";
18403
+ import { existsSync as existsSync9, lstatSync as lstatSync28, statSync as statSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync19, readdirSync as readdirSync10, opendirSync as opendirSync4, readlinkSync as readlinkSync7, realpathSync as realpathSync12, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync6, unlinkSync as unlinkSync5, chmodSync, openSync as openSync17, closeSync as closeSync17, fsyncSync as fsyncSync7, fstatSync as fstatSync17, readSync as readSync12, constants as constants18, linkSync as linkSync3 } from "fs";
18404
+ import { basename as basename11, dirname as dirname22, join as join31, resolve as resolve23, relative as relative9, isAbsolute as isAbsolute24, sep as sep14 } from "path";
18278
18405
  import { homedir as homedir2 } from "os";
18279
18406
 
18280
18407
  // src/lib/managed-policy.ts
18281
- import { closeSync as closeSync13, constants as constants13, fstatSync as fstatSync13, lstatSync as lstatSync21, openSync as openSync13, readSync as readSync9 } from "fs";
18282
- import { join as join26 } from "path";
18408
+ import { closeSync as closeSync13, constants as constants13, fstatSync as fstatSync13, lstatSync as lstatSync22, openSync as openSync13, readSync as readSync9 } from "fs";
18409
+ import { join as join27 } from "path";
18283
18410
  function refusal(reason2 = "is unreadable") {
18284
18411
  return new SkillSelectionError("INVALID_AGENT_POLICY", `The Skills agent loading policy ${reason2}; refusing legacy fallback.`);
18285
18412
  }
@@ -18310,10 +18437,10 @@ function serializeManagedSkillPolicy(value) {
18310
18437
  return text2;
18311
18438
  }
18312
18439
  function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
18313
- const path = join26(dataDir2, "agent-policy.json");
18440
+ const path = join27(dataDir2, "agent-policy.json");
18314
18441
  let descriptor, observed = false;
18315
18442
  try {
18316
- const stat2 = lstatSync21(path);
18443
+ const stat2 = lstatSync22(path);
18317
18444
  observed = true;
18318
18445
  if (!stat2.isFile() || stat2.isSymbolicLink())
18319
18446
  throw refusal();
@@ -18339,7 +18466,7 @@ function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
18339
18466
  return { text: text2, value: parseManagedSkillPolicy(text2) };
18340
18467
  } catch (error) {
18341
18468
  if (error.code === "ENOENT" && !observed) {
18342
- if (lstatSync21(path, { throwIfNoEntry: false }) === undefined)
18469
+ if (lstatSync22(path, { throwIfNoEntry: false }) === undefined)
18343
18470
  return null;
18344
18471
  }
18345
18472
  if (error instanceof SkillSelectionError)
@@ -18359,8 +18486,8 @@ function requiresCliSkillLoading(dataDir2 = getDataDirReadOnly()) {
18359
18486
 
18360
18487
  // src/lib/agent-bridge.ts
18361
18488
  import { createHash as createHash23 } from "crypto";
18362
- import { lstatSync as lstatSync22, readFileSync as readFileSync16, readdirSync as readdirSync9 } from "fs";
18363
- import { join as join27 } from "path";
18489
+ import { lstatSync as lstatSync23, readFileSync as readFileSync17, readdirSync as readdirSync9 } from "fs";
18490
+ import { join as join28 } from "path";
18364
18491
  var CLI_BRIDGE_NAME = "skills-cli";
18365
18492
  var CLI_BRIDGE_VERSION = 1;
18366
18493
  var markdown = `---
@@ -18387,13 +18514,13 @@ function isOwnedCliBridge(path, expectedPaths) {
18387
18514
  if (!expectedPaths.includes(path))
18388
18515
  return false;
18389
18516
  try {
18390
- if (!lstatSync22(path).isDirectory())
18517
+ if (!lstatSync23(path).isDirectory())
18391
18518
  return false;
18392
18519
  if (JSON.stringify(readdirSync9(path).sort()) !== JSON.stringify(Object.keys(CLI_BRIDGE_FILES).sort()))
18393
18520
  return false;
18394
18521
  return Object.entries(CLI_BRIDGE_FILES).every(([name, content]) => {
18395
- const file = join27(path, name), stat2 = lstatSync22(file);
18396
- return stat2.isFile() && !stat2.isSymbolicLink() && stat2.size === Buffer.byteLength(content) && readFileSync16(file, "utf8") === content;
18522
+ const file = join28(path, name), stat2 = lstatSync23(file);
18523
+ return stat2.isFile() && !stat2.isSymbolicLink() && stat2.size === Buffer.byteLength(content) && readFileSync17(file, "utf8") === content;
18397
18524
  });
18398
18525
  } catch {
18399
18526
  return false;
@@ -18670,8 +18797,8 @@ function disableCodexBundledSkills(text2) {
18670
18797
 
18671
18798
  // src/lib/agent-sumi.ts
18672
18799
  import { spawnSync as spawnSync4 } from "child_process";
18673
- import { accessSync as accessSync2, constants as constants14, existsSync as existsSync8, lstatSync as lstatSync23, realpathSync as realpathSync10, statSync as statSync10 } from "fs";
18674
- import { delimiter as delimiter2, isAbsolute as isAbsolute20, join as join28, resolve as resolve19 } from "path";
18800
+ import { accessSync as accessSync2, constants as constants14, existsSync as existsSync8, lstatSync as lstatSync24, realpathSync as realpathSync10, statSync as statSync10 } from "fs";
18801
+ import { delimiter as delimiter2, isAbsolute as isAbsolute20, join as join29, resolve as resolve20 } from "path";
18675
18802
 
18676
18803
  // src/lib/hook-diagnostics.ts
18677
18804
  var CONTEXT_ERROR_CODES = new Set([
@@ -18760,7 +18887,7 @@ function recordWithKeys(value, keys) {
18760
18887
  return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key2) => Object.hasOwn(value, key2));
18761
18888
  }
18762
18889
  function absolutePath3(value) {
18763
- return typeof value === "string" && value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute20(value) && resolve19(value) === value;
18890
+ return typeof value === "string" && value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute20(value) && resolve20(value) === value;
18764
18891
  }
18765
18892
  function absoluteInput(value) {
18766
18893
  return value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute20(value);
@@ -18771,7 +18898,7 @@ function resolveSumiPathsCommand(pathValue) {
18771
18898
  for (const directory2 of pathValue.split(delimiter2)) {
18772
18899
  if (!directory2 || /[\x00-\x1f\x7f]/.test(directory2))
18773
18900
  continue;
18774
- const candidate = resolve19(directory2, "sumi-paths");
18901
+ const candidate = resolve20(directory2, "sumi-paths");
18775
18902
  try {
18776
18903
  accessSync2(candidate, constants14.X_OK);
18777
18904
  if (statSync10(candidate).isFile())
@@ -18783,7 +18910,7 @@ function resolveSumiPathsCommand(pathValue) {
18783
18910
  function validPathPlan(value, home, cwd) {
18784
18911
  if (!recordWithKeys(value, ["schemaVersion", "kind", "home", "cwd", "roots", "legacyRoots", "configFiles", "skillRoots"]))
18785
18912
  return false;
18786
- if (value.schemaVersion !== 1 || value.kind !== "sumi-paths" || value.home !== resolve19(home) || value.cwd !== resolve19(cwd))
18913
+ if (value.schemaVersion !== 1 || value.kind !== "sumi-paths" || value.home !== resolve20(home) || value.cwd !== resolve20(cwd))
18787
18914
  return false;
18788
18915
  if (!recordWithKeys(value.roots, SUMI_PATH_KEYS) || !recordWithKeys(value.legacyRoots, SUMI_PATH_KEYS))
18789
18916
  return false;
@@ -18805,11 +18932,11 @@ function validPathPlan(value, home, cwd) {
18805
18932
  const legacyConfigRoot = value.legacyRoots.config;
18806
18933
  if (typeof configRoot !== "string" || legacyConfigRoot !== null && typeof legacyConfigRoot !== "string")
18807
18934
  return false;
18808
- if (value.configFiles.canonical !== join28(configRoot, "sumi.json") || value.skillRoots.canonical !== join28(configRoot, "skills"))
18935
+ if (value.configFiles.canonical !== join29(configRoot, "sumi.json") || value.skillRoots.canonical !== join29(configRoot, "skills"))
18809
18936
  return false;
18810
18937
  if (legacyConfigRoot === null)
18811
18938
  return value.configFiles.legacy === null && value.skillRoots.legacy === null;
18812
- return value.configFiles.legacy === join28(legacyConfigRoot, "sumi.json") && value.skillRoots.legacy === join28(legacyConfigRoot, "skills");
18939
+ return value.configFiles.legacy === join29(legacyConfigRoot, "sumi.json") && value.skillRoots.legacy === join29(legacyConfigRoot, "skills");
18813
18940
  }
18814
18941
  function sumiPathPlan(home, cwd = process.cwd(), env = process.env) {
18815
18942
  for (const key2 of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
@@ -18827,8 +18954,8 @@ function sumiPathPlan(home, cwd = process.cwd(), env = process.env) {
18827
18954
  childEnv[key2] = env[key2];
18828
18955
  let child2;
18829
18956
  try {
18830
- child2 = spawnSync4(executable2, ["--json", "--home", resolve19(home), "--cwd", resolve19(cwd)], {
18831
- cwd: resolve19(cwd),
18957
+ child2 = spawnSync4(executable2, ["--json", "--home", resolve20(home), "--cwd", resolve20(cwd)], {
18958
+ cwd: resolve20(cwd),
18832
18959
  env: childEnv,
18833
18960
  encoding: "buffer",
18834
18961
  timeout: 3000,
@@ -18860,7 +18987,7 @@ function selectedConfigDirectory(plan) {
18860
18987
  const canonical9 = plan.roots.config, legacy = plan.legacyRoots.config;
18861
18988
  if (legacy === null)
18862
18989
  return existsSync8(canonical9) ? realpathSync10(canonical9) : canonical9;
18863
- const canonicalStat = lstatSync23(canonical9, { throwIfNoEntry: false }), legacyStat = lstatSync23(legacy, { throwIfNoEntry: false });
18990
+ const canonicalStat = lstatSync24(canonical9, { throwIfNoEntry: false }), legacyStat = lstatSync24(legacy, { throwIfNoEntry: false });
18864
18991
  if (canonicalStat && legacyStat && realpathSync10(canonical9) !== realpathSync10(legacy))
18865
18992
  throw new Error("Sumi config roots conflict; complete native home adoption before Skills integration");
18866
18993
  const selected = canonicalStat ? canonical9 : legacyStat ? legacy : canonical9;
@@ -18876,13 +19003,13 @@ function sumiConfigDirectory(home, env = process.env, cwd = process.cwd()) {
18876
19003
  }
18877
19004
  function sumiSkillRoots(home, cwd = process.cwd(), env = process.env) {
18878
19005
  const plan = sumiPathPlan(home, cwd, env);
18879
- return [join28(selectedConfigDirectory(plan), "skills")];
19006
+ return [join29(selectedConfigDirectory(plan), "skills")];
18880
19007
  }
18881
19008
  function sumiBridgeRoot(home, cwd = process.cwd(), env = process.env) {
18882
19009
  return sumiSkillRoots(home, cwd, env)[0];
18883
19010
  }
18884
19011
  function sumiConfigPath(home, cwd = process.cwd(), env = process.env) {
18885
- return join28(sumiConfigDirectory(home, env, cwd), "sumi.json");
19012
+ return join29(sumiConfigDirectory(home, env, cwd), "sumi.json");
18886
19013
  }
18887
19014
  function renderSumiPlugin(command, profile) {
18888
19015
  return renderSumiPluginVersion(command, profile, 3);
@@ -18987,9 +19114,9 @@ var SUMI_SKILL_PERMISSIONS = [
18987
19114
  ];
18988
19115
 
18989
19116
  // src/lib/codex-hook-trust-files.ts
18990
- import { closeSync as closeSync14, constants as constants15, fstatSync as fstatSync14, fsyncSync as fsyncSync4, lstatSync as lstatSync24, openSync as openSync14, readlinkSync as readlinkSync5, readSync as readSync10, writeFileSync as writeFileSync5 } from "fs";
19117
+ import { closeSync as closeSync14, constants as constants15, fstatSync as fstatSync14, fsyncSync as fsyncSync4, lstatSync as lstatSync25, openSync as openSync14, readlinkSync as readlinkSync5, readSync as readSync10, writeFileSync as writeFileSync5 } from "fs";
18991
19118
  import { createHash as createHash24 } from "crypto";
18992
- import { dirname as dirname19, isAbsolute as isAbsolute21, resolve as resolve20 } from "path";
19119
+ import { dirname as dirname20, isAbsolute as isAbsolute21, resolve as resolve21 } from "path";
18993
19120
  function need8(value, code) {
18994
19121
  if (!value)
18995
19122
  throw new Error(`CODEX_HOOK_TRUST_${code}`);
@@ -18999,11 +19126,11 @@ function trustedAncestorOwner(uid2) {
18999
19126
  return BigInt(uid2) === 0n || BigInt(uid2) === BigInt(process.getuid());
19000
19127
  }
19001
19128
  function safeParents(file) {
19002
- for (let p = dirname19(file);; p = dirname19(p)) {
19003
- const s = lstatSync24(p);
19129
+ for (let p = dirname20(file);; p = dirname20(p)) {
19130
+ const s = lstatSync25(p);
19004
19131
  need8(s.isDirectory() && !s.isSymbolicLink() && trustedAncestorOwner(s.uid), "UNSAFE_PARENT");
19005
19132
  need8((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
19006
- if (dirname19(p) === p)
19133
+ if (dirname20(p) === p)
19007
19134
  break;
19008
19135
  }
19009
19136
  }
@@ -19018,12 +19145,12 @@ function directAliasTarget(link) {
19018
19145
  const names = parts.slice(first);
19019
19146
  if (!names.length || names.some((part) => part === "" || part === "." || part === ".."))
19020
19147
  return;
19021
- return resolve20(dirname19(link), text2);
19148
+ return resolve21(dirname20(link), text2);
19022
19149
  }
19023
19150
  function snapshot(file, privateFile = false, options = {}) {
19024
19151
  const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
19025
19152
  safeParents(file);
19026
- const initial = lstatSync24(file, { bigint: true });
19153
+ const initial = lstatSync25(file, { bigint: true });
19027
19154
  need8(initial.isFile() && initial.uid === BigInt(process.getuid()) && (initial.nlink === 1n || readOnlyPackage && initial.nlink > 1n) && (initial.mode & 0o022n) === 0n && (!privateFile || (initial.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
19028
19155
  need8(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
19029
19156
  const fd = openSync14(file, constants15.O_RDONLY | constants15.O_NOFOLLOW | constants15.O_NONBLOCK);
@@ -19038,7 +19165,7 @@ function snapshot(file, privateFile = false, options = {}) {
19038
19165
  break;
19039
19166
  length += n2;
19040
19167
  }
19041
- need8(length === Number(before.size) && sameStat(before, fstatSync14(fd, { bigint: true })) && sameStat(before, lstatSync24(file, { bigint: true })), "INPUT_CHANGED");
19168
+ need8(length === Number(before.size) && sameStat(before, fstatSync14(fd, { bigint: true })) && sameStat(before, lstatSync25(file, { bigint: true })), "INPUT_CHANGED");
19042
19169
  const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
19043
19170
  return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash24("sha256").update(content).digest("hex") };
19044
19171
  } finally {
@@ -19052,7 +19179,7 @@ function unchanged2(before) {
19052
19179
 
19053
19180
  // src/cli/commands/runtime-launcher.ts
19054
19181
  import { createHash as createHash25 } from "crypto";
19055
- import { closeSync as closeSync15, constants as constants16, fchmodSync as fchmodSync2, fstatSync as fstatSync15, fsyncSync as fsyncSync5, lstatSync as lstatSync25, openSync as openSync15, readFileSync as readFileSync17, readlinkSync as readlinkSync6, realpathSync as realpathSync11, symlinkSync, writeSync as writeSync3 } from "fs";
19182
+ import { closeSync as closeSync15, constants as constants16, fchmodSync as fchmodSync2, fstatSync as fstatSync15, fsyncSync as fsyncSync5, lstatSync as lstatSync26, openSync as openSync15, readFileSync as readFileSync18, readlinkSync as readlinkSync6, realpathSync as realpathSync11, symlinkSync, writeSync as writeSync3 } from "fs";
19056
19183
  import { isAbsolute as isAbsolute22 } from "path";
19057
19184
 
19058
19185
  // src/server/launcher-environment-policy.ts
@@ -19259,9 +19386,9 @@ function parsePinnedLauncher(text2) {
19259
19386
  var PINNED_LAUNCHER_MAX_BYTES = 16 * 1024;
19260
19387
  function resolveLauncherCommand(path) {
19261
19388
  const physical = realpathSync11(path);
19262
- const stat2 = lstatSync25(physical);
19389
+ const stat2 = lstatSync26(physical);
19263
19390
  if (stat2.isFile() && stat2.size <= PINNED_LAUNCHER_MAX_BYTES) {
19264
- const text2 = readFileSync17(physical, "utf8");
19391
+ const text2 = readFileSync18(physical, "utf8");
19265
19392
  const binding = parsePinnedLauncher(text2);
19266
19393
  if (binding) {
19267
19394
  let entry;
@@ -19281,7 +19408,7 @@ function assertPinnedLauncherRuntimeSafe(runtime) {
19281
19408
  assertLauncherPath(runtime, "LAUNCHER_RUNTIME_PATH_INVALID");
19282
19409
  let stat2;
19283
19410
  try {
19284
- stat2 = lstatSync25(runtime);
19411
+ stat2 = lstatSync26(runtime);
19285
19412
  } catch {
19286
19413
  throw new Error("LAUNCHER_RUNTIME_UNSAFE");
19287
19414
  }
@@ -19293,8 +19420,8 @@ function assertPinnedLauncherRuntimeSafe(runtime) {
19293
19420
 
19294
19421
  // src/lib/retained-review-artifacts.ts
19295
19422
  import { createHash as createHash26 } from "crypto";
19296
- import { constants as constants17, closeSync as closeSync16, fstatSync as fstatSync16, fsyncSync as fsyncSync6, lstatSync as lstatSync26, mkdirSync as mkdirSync7, openSync as openSync16, readSync as readSync11, writeSync as writeSync4 } from "fs";
19297
- import { dirname as dirname20, isAbsolute as isAbsolute23, join as join29, resolve as resolve21, sep as sep12 } from "path";
19423
+ import { constants as constants17, closeSync as closeSync16, fstatSync as fstatSync16, fsyncSync as fsyncSync6, lstatSync as lstatSync27, mkdirSync as mkdirSync7, openSync as openSync16, readSync as readSync11, writeSync as writeSync4 } from "fs";
19424
+ import { dirname as dirname21, isAbsolute as isAbsolute23, join as join30, resolve as resolve22, sep as sep13 } from "path";
19298
19425
  var sha3 = (bytes) => createHash26("sha256").update(bytes).digest("hex");
19299
19426
  var hex = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
19300
19427
  var refuse5 = () => {
@@ -19308,19 +19435,19 @@ function keys(value, names) {
19308
19435
  return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === names.length && names.every((name) => Object.hasOwn(value, name)));
19309
19436
  }
19310
19437
  function safe4(path) {
19311
- need9(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute23(path) && resolve21(path) === path && !/[\x00-\x1f\x7f]/.test(path));
19312
- for (let cursor = path;; cursor = dirname20(cursor)) {
19313
- const stat2 = lstatSync26(cursor, { throwIfNoEntry: false });
19438
+ need9(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute23(path) && resolve22(path) === path && !/[\x00-\x1f\x7f]/.test(path));
19439
+ for (let cursor = path;; cursor = dirname21(cursor)) {
19440
+ const stat2 = lstatSync27(cursor, { throwIfNoEntry: false });
19314
19441
  need9(!stat2?.isSymbolicLink());
19315
19442
  if (cursor !== path && stat2)
19316
19443
  need9(stat2.isDirectory());
19317
- if (dirname20(cursor) === cursor)
19444
+ if (dirname21(cursor) === cursor)
19318
19445
  break;
19319
19446
  }
19320
19447
  }
19321
19448
  function readExact(path) {
19322
19449
  safe4(path);
19323
- const before = lstatSync26(path, { throwIfNoEntry: false });
19450
+ const before = lstatSync27(path, { throwIfNoEntry: false });
19324
19451
  need9(before?.isFile() && before.nlink === 1 && before.size <= AGENT_POLICY_LIMITS.discoveryRawSourceBytes && (before.mode & 63) === 0 && (process.getuid === undefined || before.uid === process.getuid()));
19325
19452
  const fd = openSync16(path, constants17.O_RDONLY | constants17.O_NOFOLLOW | constants17.O_NONBLOCK);
19326
19453
  try {
@@ -19334,7 +19461,7 @@ function readExact(path) {
19334
19461
  offset += count;
19335
19462
  }
19336
19463
  need9(readSync11(fd, Buffer.alloc(1), 0, 1, null) === 0);
19337
- const after = fstatSync16(fd), current = lstatSync26(path, { throwIfNoEntry: false });
19464
+ const after = fstatSync16(fd), current = lstatSync27(path, { throwIfNoEntry: false });
19338
19465
  safe4(path);
19339
19466
  need9(current && opened.dev === current.dev && opened.ino === current.ino && opened.mode === current.mode && opened.uid === current.uid && opened.size === current.size && opened.mtimeMs === current.mtimeMs && opened.ctimeMs === current.ctimeMs && current.nlink === 1 && opened.mode === after.mode && opened.uid === after.uid && after.nlink === 1 && opened.size === after.size && opened.mtimeMs === after.mtimeMs && opened.ctimeMs === after.ctimeMs);
19340
19467
  const text2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
@@ -19360,24 +19487,24 @@ function verifyReviewArtifactOriginal(path, expectedSha256) {
19360
19487
  need9(hex(expectedSha256) && sha3(readExact(path)) === expectedSha256);
19361
19488
  }
19362
19489
  function retainedArtifactPath(metadata) {
19363
- return join29(metadata.storeRoot, "agent-discovery", "artifacts", metadata.sha256, "catalog.json");
19490
+ return join30(metadata.storeRoot, "agent-discovery", "artifacts", metadata.sha256, "catalog.json");
19364
19491
  }
19365
19492
  function validRetainedArtifact(value) {
19366
- return keys(value, ["version", "kind", "storeRoot", "originalPath", "sha256", "catalogSha256"]) && value.version === 1 && value.kind === "codex-native-catalog" && hex(value.sha256) && hex(value.catalogSha256) && [value.storeRoot, value.originalPath].every((path) => typeof path === "string" && isAbsolute23(path) && resolve21(path) === path && path.length <= AGENT_POLICY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(path));
19493
+ return keys(value, ["version", "kind", "storeRoot", "originalPath", "sha256", "catalogSha256"]) && value.version === 1 && value.kind === "codex-native-catalog" && hex(value.sha256) && hex(value.catalogSha256) && [value.storeRoot, value.originalPath].every((path) => typeof path === "string" && isAbsolute23(path) && resolve22(path) === path && path.length <= AGENT_POLICY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(path));
19367
19494
  }
19368
19495
  function privateStore(storeRoot) {
19369
19496
  safe4(storeRoot);
19370
- const stat2 = lstatSync26(storeRoot, { throwIfNoEntry: false });
19497
+ const stat2 = lstatSync27(storeRoot, { throwIfNoEntry: false });
19371
19498
  need9(!stat2 || stat2.isDirectory() && (stat2.mode & 18) === 0 && (process.getuid === undefined || stat2.uid === process.getuid()));
19372
19499
  }
19373
19500
  function verifyRetainedReviewArtifact(source, storeRoot) {
19374
19501
  const artifact = source.reviewArtifact;
19375
- need9(validRetainedArtifact(artifact) && source.hashMode === "bytes" && source.sha256 === artifact.sha256 && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && source.path === retainedArtifactPath(artifact) && (storeRoot === undefined || artifact.storeRoot === resolve21(storeRoot)));
19502
+ need9(validRetainedArtifact(artifact) && source.hashMode === "bytes" && source.sha256 === artifact.sha256 && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && source.path === retainedArtifactPath(artifact) && (storeRoot === undefined || artifact.storeRoot === resolve22(storeRoot)));
19376
19503
  privateStore(artifact.storeRoot);
19377
19504
  const text2 = readExact(source.path);
19378
19505
  need9(sha3(text2) === artifact.sha256 && catalogDigest(text2) === artifact.catalogSha256);
19379
- for (let parent = dirname20(source.path);parent !== artifact.storeRoot; parent = dirname20(parent)) {
19380
- const stat2 = lstatSync26(parent);
19506
+ for (let parent = dirname21(source.path);parent !== artifact.storeRoot; parent = dirname21(parent)) {
19507
+ const stat2 = lstatSync27(parent);
19381
19508
  need9(stat2.isDirectory() && (stat2.mode & 63) === 0 && (process.getuid === undefined || stat2.uid === process.getuid()));
19382
19509
  }
19383
19510
  }
@@ -19385,7 +19512,7 @@ function planReviewArtifactRetention(binding, artifacts, dataDir2, home) {
19385
19512
  if (artifacts === undefined)
19386
19513
  return { binding, changes: [], observed: [] };
19387
19514
  need9(binding.agent === "codex" && binding.method === "reviewed" && Array.isArray(artifacts) && artifacts.length > 0 && artifacts.length <= 32);
19388
- privateStore(resolve21(dataDir2));
19515
+ privateStore(resolve22(dataDir2));
19389
19516
  const paths = new Set;
19390
19517
  const changes = [], observed = [];
19391
19518
  let totalBytes = 0;
@@ -19394,19 +19521,19 @@ function planReviewArtifactRetention(binding, artifacts, dataDir2, home) {
19394
19521
  need9(keys(declaration, ["kind", "path", "sha256"]) && declaration.kind === "codex-native-catalog" && hex(declaration.sha256) && !paths.has(declaration.path));
19395
19522
  paths.add(declaration.path);
19396
19523
  safe4(declaration.path);
19397
- const liveRoots = [join29(home, ".codex"), ...binding.roots, ...(binding.directories ?? []).map((item) => item.path)];
19398
- need9(!liveRoots.some((root) => declaration.path === root || declaration.path.startsWith(root + sep12)));
19524
+ const liveRoots = [join30(home, ".codex"), ...binding.roots, ...(binding.directories ?? []).map((item) => item.path)];
19525
+ need9(!liveRoots.some((root) => declaration.path === root || declaration.path.startsWith(root + sep13)));
19399
19526
  const matches = sources.filter((source2) => source2.path === declaration.path);
19400
19527
  need9(matches.length === 1 && matches[0].sha256 === declaration.sha256 && matches[0].reviewArtifact === undefined && [undefined, "bytes"].includes(matches[0].hashMode) && matches[0].format === undefined && matches[0].fields === undefined && matches[0].managedPlugins === undefined);
19401
19528
  const text2 = readExact(declaration.path);
19402
19529
  need9(sha3(text2) === declaration.sha256);
19403
19530
  totalBytes += Buffer.byteLength(text2);
19404
19531
  need9(totalBytes <= AGENT_POLICY_LIMITS.discoveryRawTotalBytes);
19405
- const metadata = { version: 1, kind: declaration.kind, storeRoot: resolve21(dataDir2), originalPath: declaration.path, sha256: declaration.sha256, catalogSha256: catalogDigest(text2) };
19532
+ const metadata = { version: 1, kind: declaration.kind, storeRoot: resolve22(dataDir2), originalPath: declaration.path, sha256: declaration.sha256, catalogSha256: catalogDigest(text2) };
19406
19533
  const path = retainedArtifactPath(metadata);
19407
19534
  safe4(path);
19408
19535
  const source = { path, sha256: metadata.sha256, hashMode: "bytes", reviewArtifact: metadata };
19409
- if (lstatSync26(path, { throwIfNoEntry: false }))
19536
+ if (lstatSync27(path, { throwIfNoEntry: false }))
19410
19537
  verifyRetainedReviewArtifact(source, dataDir2);
19411
19538
  else if (!changes.some((change) => change.path === path))
19412
19539
  changes.push({ path, before: null, after: text2, artifact: metadata });
@@ -19420,14 +19547,14 @@ function writeReviewArtifactExclusive(change) {
19420
19547
  need9(change.before === null && validRetainedArtifact(change.artifact) && change.path === retainedArtifactPath(change.artifact) && sha3(change.after) === change.artifact.sha256 && catalogDigest(change.after) === change.artifact.catalogSha256);
19421
19548
  privateStore(change.artifact.storeRoot);
19422
19549
  const missing2 = [];
19423
- for (let parent = dirname20(change.path);!lstatSync26(parent, { throwIfNoEntry: false }); parent = dirname20(parent))
19550
+ for (let parent = dirname21(change.path);!lstatSync27(parent, { throwIfNoEntry: false }); parent = dirname21(parent))
19424
19551
  missing2.push(parent);
19425
19552
  for (const parent of missing2.reverse())
19426
19553
  mkdirSync7(parent, { mode: 448 });
19427
19554
  safe4(change.path);
19428
19555
  privateStore(change.artifact.storeRoot);
19429
- for (let parent = dirname20(change.path);parent !== change.artifact.storeRoot; parent = dirname20(parent)) {
19430
- const stat2 = lstatSync26(parent);
19556
+ for (let parent = dirname21(change.path);parent !== change.artifact.storeRoot; parent = dirname21(parent)) {
19557
+ const stat2 = lstatSync27(parent);
19431
19558
  need9(stat2.isDirectory() && (stat2.mode & 63) === 0 && (process.getuid === undefined || stat2.uid === process.getuid()));
19432
19559
  }
19433
19560
  const fd = openSync16(change.path, constants17.O_WRONLY | constants17.O_CREAT | constants17.O_EXCL | constants17.O_NOFOLLOW, 384);
@@ -19444,7 +19571,7 @@ function writeReviewArtifactExclusive(change) {
19444
19571
  closeSync16(fd);
19445
19572
  }
19446
19573
  need9(readExact(change.path) === change.after);
19447
- const directory2 = openSync16(dirname20(change.path), constants17.O_RDONLY | constants17.O_DIRECTORY | constants17.O_NOFOLLOW);
19574
+ const directory2 = openSync16(dirname21(change.path), constants17.O_RDONLY | constants17.O_DIRECTORY | constants17.O_NOFOLLOW);
19448
19575
  try {
19449
19576
  fsyncSync6(directory2);
19450
19577
  } finally {
@@ -19461,7 +19588,7 @@ function nativeAgentRoot(home, agent, cwd = process.cwd()) {
19461
19588
  const root = AGENT_ADAPTERS[agent].root;
19462
19589
  if (typeof root !== "string")
19463
19590
  throw new Error(`Native skill root is unavailable for ${agent}`);
19464
- return join30(home, root);
19591
+ return join31(home, root);
19465
19592
  }
19466
19593
  function nativeAgentConfig(home, agent, cwd = process.cwd()) {
19467
19594
  if (agent === "sumi")
@@ -19469,7 +19596,7 @@ function nativeAgentConfig(home, agent, cwd = process.cwd()) {
19469
19596
  const config = AGENT_ADAPTERS[agent].config;
19470
19597
  if (typeof config !== "string")
19471
19598
  throw new Error(`Native configuration path is unavailable for ${agent}`);
19472
- return join30(home, config);
19599
+ return join31(home, config);
19473
19600
  }
19474
19601
  function hasTrustedDarwinAcl(fd, allowDenyOnly = false) {
19475
19602
  try {
@@ -19521,11 +19648,11 @@ function isSystemRootAlias(path) {
19521
19648
  const identity5 = (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}:${stat2.uid}:${stat2.mode}`;
19522
19649
  const directoryIdentity = (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.uid}:${stat2.mode}`;
19523
19650
  try {
19524
- const before = lstatSync27(path, { bigint: true });
19651
+ const before = lstatSync28(path, { bigint: true });
19525
19652
  if (!before.isSymbolicLink() || before.uid !== 0n || readlinkSync7(path) !== link)
19526
19653
  return false;
19527
19654
  const directories = ["/", "/private", target].map((directory2) => {
19528
- const stat2 = lstatSync27(directory2, { bigint: true });
19655
+ const stat2 = lstatSync28(directory2, { bigint: true });
19529
19656
  if (!stat2.isDirectory() || stat2.uid !== 0n)
19530
19657
  throw new Error("Untrusted system alias directory");
19531
19658
  if (directory2 !== "/private/tmp") {
@@ -19542,25 +19669,25 @@ function isSystemRootAlias(path) {
19542
19669
  }
19543
19670
  return { directory: directory2, identity: directoryIdentity(stat2) };
19544
19671
  });
19545
- return realpathSync12(path) === target && readlinkSync7(path) === link && identity5(lstatSync27(path, { bigint: true })) === identity5(before) && directories.every((item) => directoryIdentity(lstatSync27(item.directory, { bigint: true })) === item.identity);
19672
+ return realpathSync12(path) === target && readlinkSync7(path) === link && identity5(lstatSync28(path, { bigint: true })) === identity5(before) && directories.every((item) => directoryIdentity(lstatSync28(item.directory, { bigint: true })) === item.identity);
19546
19673
  } catch {
19547
19674
  return false;
19548
19675
  }
19549
19676
  }
19550
19677
  function canonicalSystemPath(path) {
19551
- const absolute = resolve22(path), root = `/${absolute.split(sep13)[1]}`;
19552
- if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync27(root, { throwIfNoEntry: false })?.isSymbolicLink())
19678
+ const absolute = resolve23(path), root = `/${absolute.split(sep14)[1]}`;
19679
+ if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root) || !lstatSync28(root, { throwIfNoEntry: false })?.isSymbolicLink())
19553
19680
  return absolute;
19554
19681
  if (!isSystemRootAlias(root))
19555
19682
  throw new Error(`Refusing symlink path: ${root}`);
19556
19683
  return `/private${absolute}`;
19557
19684
  }
19558
19685
  function assertSafePath(path) {
19559
- let cursor = resolve22(path);
19686
+ let cursor = resolve23(path);
19560
19687
  while (true) {
19561
- if (lstatSync27(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
19688
+ if (lstatSync28(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
19562
19689
  throw new Error(`Refusing symlink path: ${cursor}`);
19563
- const parent = dirname21(cursor);
19690
+ const parent = dirname22(cursor);
19564
19691
  if (parent === cursor)
19565
19692
  return;
19566
19693
  cursor = parent;
@@ -19568,17 +19695,17 @@ function assertSafePath(path) {
19568
19695
  }
19569
19696
  function readRootAlias(home, agent) {
19570
19697
  assertSafePath(home);
19571
- const realHome = realpathSync12(home), alias = join30(realHome, `.${agent}`);
19572
- const stat2 = lstatSync27(alias, { throwIfNoEntry: false, bigint: true });
19698
+ const realHome = realpathSync12(home), alias = join31(realHome, `.${agent}`);
19699
+ const stat2 = lstatSync28(alias, { throwIfNoEntry: false, bigint: true });
19573
19700
  if (!stat2?.isSymbolicLink())
19574
19701
  throw new Error(`Agent root alias changed after planning: ${alias}`);
19575
- const link = readlinkSync7(alias), targetPath = resolve22(dirname21(alias), link);
19702
+ const link = readlinkSync7(alias), targetPath = resolve23(dirname22(alias), link);
19576
19703
  assertSafePath(targetPath);
19577
- const targetStat = lstatSync27(targetPath, { throwIfNoEntry: false });
19704
+ const targetStat = lstatSync28(targetPath, { throwIfNoEntry: false });
19578
19705
  if (!targetStat?.isDirectory())
19579
19706
  throw new Error(`Agent root alias must target an existing directory: ${alias}`);
19580
19707
  const target = realpathSync12(targetPath), inside = relative9(realHome, target);
19581
- if (!inside || inside === ".." || inside.startsWith(`..${sep13}`) || isAbsolute24(inside))
19708
+ if (!inside || inside === ".." || inside.startsWith(`..${sep14}`) || isAbsolute24(inside))
19582
19709
  throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
19583
19710
  return { agent, home: realHome, alias, target, link, aliasIdentity: `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
19584
19711
  }
@@ -19587,15 +19714,15 @@ function rootAliases(home, allowed = false) {
19587
19714
  return [];
19588
19715
  const result = [];
19589
19716
  for (const agent of ["claude", "codex"])
19590
- if (lstatSync27(join30(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
19717
+ if (lstatSync28(join31(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
19591
19718
  result.push(readRootAlias(home, agent));
19592
- if (result.some((item, index) => result.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep13) || other.target.startsWith(item.target + sep13))))
19719
+ if (result.some((item, index) => result.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep14) || other.target.startsWith(item.target + sep14))))
19593
19720
  throw new Error("Agent root alias targets must not overlap");
19594
19721
  return result;
19595
19722
  }
19596
19723
  function canonicalAgentPath(path, aliases) {
19597
- const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep13));
19598
- return binding ? join30(binding.target, relative9(binding.alias, absolute)) : absolute;
19724
+ const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep14));
19725
+ return binding ? join31(binding.target, relative9(binding.alias, absolute)) : absolute;
19599
19726
  }
19600
19727
  function disabledCodexSkillPaths(config, aliases) {
19601
19728
  const skills = config.skills;
@@ -19618,15 +19745,15 @@ function disabledCodexSkillPaths(config, aliases) {
19618
19745
  } catch {
19619
19746
  continue;
19620
19747
  }
19621
- if (!document2.endsWith(`${sep13}SKILL.md`))
19748
+ if (!document2.endsWith(`${sep14}SKILL.md`))
19622
19749
  continue;
19623
19750
  settings.set(document2, [...settings.get(document2) ?? [], entry.enabled === false]);
19624
19751
  }
19625
- return [...settings].filter(([, values]) => values.length === 1 && values[0] === true).map(([document2]) => dirname21(document2));
19752
+ return [...settings].filter(([, values]) => values.length === 1 && values[0] === true).map(([document2]) => dirname22(document2));
19626
19753
  }
19627
19754
  function recheckRootAliases(aliases) {
19628
19755
  for (const binding of aliases) {
19629
- if (!["claude", "codex"].includes(binding.agent) || binding.alias !== join30(binding.home, `.${binding.agent}`))
19756
+ if (!["claude", "codex"].includes(binding.agent) || binding.alias !== join31(binding.home, `.${binding.agent}`))
19630
19757
  throw new Error("Invalid agent root alias binding");
19631
19758
  const current = readRootAlias(binding.home, binding.agent);
19632
19759
  if (JSON.stringify(current) !== JSON.stringify(binding))
@@ -19635,11 +19762,11 @@ function recheckRootAliases(aliases) {
19635
19762
  }
19636
19763
  function nativeSourceDigest(path) {
19637
19764
  assertSafePath(path);
19638
- return lstatSync27(path, { throwIfNoEntry: false }) ? sha4(readNativeBytes(path, 1024 * 1024)) : null;
19765
+ return lstatSync28(path, { throwIfNoEntry: false }) ? sha4(readNativeBytes(path, 1024 * 1024)) : null;
19639
19766
  }
19640
19767
  function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
19641
19768
  assertSafePath(path);
19642
- const before = lstatSync27(path);
19769
+ const before = lstatSync28(path);
19643
19770
  if (!before.isFile() || before.size > maximum)
19644
19771
  throw new Error("Unsupported or oversized native skill file");
19645
19772
  const descriptor = openSync17(path, constants18.O_RDONLY | constants18.O_NOFOLLOW | constants18.O_NONBLOCK);
@@ -19655,7 +19782,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
19655
19782
  break;
19656
19783
  length += count;
19657
19784
  }
19658
- const after = fstatSync17(descriptor), current = lstatSync27(path);
19785
+ const after = fstatSync17(descriptor), current = lstatSync28(path);
19659
19786
  if (current.dev !== opened.dev || current.ino !== opened.ino || current.size !== after.size || current.mtimeMs !== after.mtimeMs || current.ctimeMs !== after.ctimeMs || length !== before.size || after.size !== before.size || after.mtimeMs !== opened.mtimeMs || after.ctimeMs !== opened.ctimeMs)
19660
19787
  throw new Error("Native skill file changed while reading");
19661
19788
  return bytes.subarray(0, length);
@@ -19667,14 +19794,14 @@ function treeHash(root) {
19667
19794
  const hash3 = createHash27("sha256");
19668
19795
  let bytes = 0, files = 0;
19669
19796
  function visit2(path) {
19670
- const stat2 = lstatSync27(path);
19797
+ const stat2 = lstatSync28(path);
19671
19798
  if (stat2.isSymbolicLink())
19672
19799
  throw new Error(`Refusing symlink in skill: ${path}`);
19673
19800
  const rel = relative9(root, path);
19674
19801
  if (stat2.isDirectory()) {
19675
19802
  hash3.update(`d\x00${rel}\x00`);
19676
19803
  for (const name of readdirSync10(path).sort())
19677
- visit2(join30(path, name));
19804
+ visit2(join31(path, name));
19678
19805
  return;
19679
19806
  }
19680
19807
  if (!stat2.isFile())
@@ -19696,20 +19823,20 @@ function selectNativeMigrationTargets(inventory, manifest) {
19696
19823
  const identities = new Set;
19697
19824
  const selected = [];
19698
19825
  for (const target of manifest.targets) {
19699
- if (!isAbsolute24(target.projectRoot) || resolve22(target.projectRoot) !== target.projectRoot)
19826
+ if (!isAbsolute24(target.projectRoot) || resolve23(target.projectRoot) !== target.projectRoot)
19700
19827
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
19701
- const projectRoot = canonicalSystemPath(target.projectRoot), normalized2 = relative9(projectRoot, resolve22(projectRoot, target.path));
19702
- if (!existsSync9(projectRoot) || !lstatSync27(projectRoot).isDirectory())
19828
+ const projectRoot = canonicalSystemPath(target.projectRoot), normalized2 = relative9(projectRoot, resolve23(projectRoot, target.path));
19829
+ if (!existsSync9(projectRoot) || !lstatSync28(projectRoot).isDirectory())
19703
19830
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
19704
19831
  assertSafePath(projectRoot);
19705
- if (isAbsolute24(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized2 || normalized2 === ".." || normalized2.startsWith(`..${sep13}`) || normalized2 !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
19832
+ if (isAbsolute24(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized2 || normalized2 === ".." || normalized2.startsWith(`..${sep14}`) || normalized2 !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
19706
19833
  throw new Error(`Invalid native migration target: ${target.path}`);
19707
19834
  const identity5 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized2}`;
19708
19835
  if (identities.has(identity5))
19709
19836
  throw new Error(`Duplicate native migration target: ${target.path}`);
19710
19837
  identities.add(identity5);
19711
- const expected = canonicalSystemPath(resolve22(target.projectRoot, target.path));
19712
- const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve22(entry2.path) === expected);
19838
+ const expected = canonicalSystemPath(resolve23(target.projectRoot, target.path));
19839
+ const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve23(entry2.path) === expected);
19713
19840
  if (matches.length !== 1)
19714
19841
  throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
19715
19842
  const entry = matches[0];
@@ -19728,7 +19855,7 @@ function projectAncestorDirectories(projects) {
19728
19855
  if (depth >= 100)
19729
19856
  throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
19730
19857
  directories.add(path);
19731
- const parent = dirname21(path);
19858
+ const parent = dirname22(path);
19732
19859
  if (parent === path)
19733
19860
  break;
19734
19861
  path = parent;
@@ -19737,17 +19864,17 @@ function projectAncestorDirectories(projects) {
19737
19864
  return [...directories];
19738
19865
  }
19739
19866
  function isCodexSkillDiscoveryInput(path) {
19740
- for (let cursor = canonicalSystemPath(path);cursor !== dirname21(cursor); cursor = dirname21(cursor)) {
19741
- if (ROOTS.some(([agent, root]) => agent === "codex" && cursor.endsWith(join30(sep13, root))))
19867
+ for (let cursor = canonicalSystemPath(path);cursor !== dirname22(cursor); cursor = dirname22(cursor)) {
19868
+ if (ROOTS.some(([agent, root]) => agent === "codex" && cursor.endsWith(join31(sep14, root))))
19742
19869
  return true;
19743
19870
  }
19744
19871
  return false;
19745
19872
  }
19746
19873
  function inventoryNativeSkills(home = homedir2(), options = {}) {
19747
19874
  home = canonicalSystemPath(home);
19748
- if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute24(options.reviewedCacheAlias) || resolve22(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
19875
+ if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute24(options.reviewedCacheAlias) || resolve23(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
19749
19876
  throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
19750
- if (options.disabledVendorPaths?.some((path) => !isAbsolute24(path) || resolve22(path) !== path))
19877
+ if (options.disabledVendorPaths?.some((path) => !isAbsolute24(path) || resolve23(path) !== path))
19751
19878
  throw new Error("Disabled vendor paths must be exact absolute paths");
19752
19879
  const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
19753
19880
  const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
@@ -19755,25 +19882,25 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
19755
19882
  const selectedAgents = options.agents ? new Set(options.agents) : undefined;
19756
19883
  const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
19757
19884
  const rootDefinitions = selectedAgents ? ROOTS.filter(([agent, path]) => agent !== "sumi" && selectedAgents.has(agent) || selectedAgents.has("hermes") && agent === "codex" && path === ".agents/skills") : ROOTS.filter(([agent]) => agent !== "sumi");
19758
- const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join30(home, path), aliases)]);
19885
+ const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join31(home, path), aliases)]);
19759
19886
  const includesSumi = !selectedAgents || selectedAgents.has("sumi");
19760
19887
  if (includesSumi)
19761
19888
  for (const path of sumiSkillRoots(home))
19762
19889
  roots.push(["sumi", canonicalAgentPath(path, aliases)]);
19763
- const bridgePaths = Object.entries(AGENT_ADAPTERS).filter(([agent]) => agent !== "sumi" || includesSumi).map(([agent]) => canonicalAgentPath(join30(nativeAgentRoot(home, agent), CLI_BRIDGE_NAME), aliases));
19890
+ const bridgePaths = Object.entries(AGENT_ADAPTERS).filter(([agent]) => agent !== "sumi" || includesSumi).map(([agent]) => canonicalAgentPath(join31(nativeAgentRoot(home, agent), CLI_BRIDGE_NAME), aliases));
19764
19891
  for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
19765
19892
  for (const [agent, path] of rootDefinitions)
19766
- roots.push([agent, canonicalAgentPath(join30(project, path), aliases)]);
19893
+ roots.push([agent, canonicalAgentPath(join31(project, path), aliases)]);
19767
19894
  if (selectedAgents?.has("sumi")) {
19768
19895
  for (const path of sumiSkillRoots(home, project))
19769
19896
  roots.push(["sumi", canonicalAgentPath(path, aliases)]);
19770
19897
  for (const directory2 of [".claude", ".agents"])
19771
19898
  for (const name of ["skill", "skills"])
19772
- roots.push(["sumi", canonicalAgentPath(join30(project, directory2, name), aliases)]);
19899
+ roots.push(["sumi", canonicalAgentPath(join31(project, directory2, name), aliases)]);
19773
19900
  }
19774
19901
  }
19775
19902
  const installationInputs = options.codexInstallationInputRoots ?? [];
19776
- if (installationInputs.some((input) => resolve22(input) !== input || realpathSync12(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep13) || input.startsWith(path + sep13)))))
19903
+ if (installationInputs.some((input) => resolve23(input) !== input || realpathSync12(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep14) || input.startsWith(path + sep14)))))
19777
19904
  throw new Error("Native installation input overlaps an unconditional skill-loading root");
19778
19905
  const entries = [], seen = new Set;
19779
19906
  const cacheScans = new Map, maxAliasProofEntries = 1e4;
@@ -19787,19 +19914,19 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
19787
19914
  }
19788
19915
  let reviewedCacheAliasFound = false;
19789
19916
  function verifiedSiblingCacheAlias(agent, path, parent) {
19790
- const link = readlinkSync7(path), lexicalTarget = resolve22(parent, link);
19791
- if (isAbsolute24(link) ? link !== lexicalTarget : dirname21(link) !== ".")
19917
+ const link = readlinkSync7(path), lexicalTarget = resolve23(parent, link);
19918
+ if (isAbsolute24(link) ? link !== lexicalTarget : dirname22(link) !== ".")
19792
19919
  return false;
19793
19920
  const target = canonicalSystemPath(lexicalTarget);
19794
- if (dirname21(target) !== parent)
19921
+ if (dirname22(target) !== parent)
19795
19922
  return false;
19796
- if (!lstatSync27(target, { throwIfNoEntry: false })?.isDirectory())
19923
+ if (!lstatSync28(target, { throwIfNoEntry: false })?.isDirectory())
19797
19924
  return false;
19798
19925
  const scan = cacheScans.get(target);
19799
19926
  if (!scan?.complete || scan.entries > maxAliasProofEntries)
19800
19927
  return false;
19801
19928
  if (scan.hasSkills) {
19802
- const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep13)));
19929
+ const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep14)));
19803
19930
  if (path === reviewedCacheAlias && targetSkills.length > 0)
19804
19931
  reviewedCacheAliasFound = true;
19805
19932
  if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path) || options.disabledVendorSkill?.(entry) === true))
@@ -19814,11 +19941,11 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
19814
19941
  admit(path);
19815
19942
  const scan = { complete: true, hasSkills: false, entries: 1 };
19816
19943
  assertSafePath(path);
19817
- if (configuredRoot && agent === "codex" && installationInputs.some((root) => path === root || path.startsWith(`${root}${sep13}`)))
19944
+ if (configuredRoot && agent === "codex" && installationInputs.some((root) => path === root || path.startsWith(`${root}${sep14}`)))
19818
19945
  return scan;
19819
19946
  if (!existsSync9(path))
19820
19947
  return scan;
19821
- const stat2 = lstatSync27(path);
19948
+ const stat2 = lstatSync28(path);
19822
19949
  if (stat2.isFile()) {
19823
19950
  if (agent === "sumi" && depth === 1 && path.endsWith(".md"))
19824
19951
  throw new Error("NATIVE_SKILL_DRIFT: flat Sumi skill documents require a dedicated migration adapter");
@@ -19826,21 +19953,21 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
19826
19953
  }
19827
19954
  if (!stat2.isDirectory())
19828
19955
  throw new Error(`Unsupported native discovery entry: ${path}`);
19829
- if (existsSync9(join30(path, "SKILL.md"))) {
19956
+ if (existsSync9(join31(path, "SKILL.md"))) {
19830
19957
  scan.hasSkills = true;
19831
19958
  if (seen.has(path))
19832
19959
  return scan;
19833
19960
  seen.add(path);
19834
19961
  let managed = false;
19835
- const marker = join30(path, ".hasna-skills.json");
19962
+ const marker = join31(path, ".hasna-skills.json");
19836
19963
  if (existsSync9(marker)) {
19837
19964
  try {
19838
- managed = JSON.parse(readFileSync18(marker, "utf8")).managedBy === "@hasna/skills";
19965
+ managed = JSON.parse(readFileSync19(marker, "utf8")).managedBy === "@hasna/skills";
19839
19966
  } catch {}
19840
19967
  }
19841
19968
  const bridge = (!vendor || agent === "sumi") && isOwnedCliBridge(path, bridgePaths);
19842
- const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep13));
19843
- entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" || isCodexSkillDiscoveryInput(path) ? { codexHome: process.env.CODEX_HOME ?? join30(home, ".codex") } : {}, ...agent === "codex" && path.startsWith(canonicalAgentPath(join30(home, ".codex", "skills", ".system"), aliases) + sep13) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve22(home) } : {}, ...rootAlias ? { rootAlias } : {} });
19969
+ const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep14));
19970
+ entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" || isCodexSkillDiscoveryInput(path) ? { codexHome: process.env.CODEX_HOME ?? join31(home, ".codex") } : {}, ...agent === "codex" && path.startsWith(canonicalAgentPath(join31(home, ".codex", "skills", ".system"), aliases) + sep14) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve23(home) } : {}, ...rootAlias ? { rootAlias } : {} });
19844
19971
  return scan;
19845
19972
  }
19846
19973
  if (depth > (agent === "sumi" ? 32 : vendor ? 32 : 3))
@@ -19849,7 +19976,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
19849
19976
  try {
19850
19977
  let child2;
19851
19978
  while ((child2 = directory2.readSync()) !== null) {
19852
- admit(join30(path, child2.name));
19979
+ admit(join31(path, child2.name));
19853
19980
  children.push(child2);
19854
19981
  }
19855
19982
  } finally {
@@ -19859,15 +19986,15 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
19859
19986
  if (pluginCache)
19860
19987
  children.sort((a, b) => Number(a.isSymbolicLink()) - Number(b.isSymbolicLink()));
19861
19988
  for (const { name } of children) {
19862
- if (name === "node_modules")
19989
+ if (name === "node_modules" && !(agent === "codex" && (!pluginCache || codexPluginCacheSkillTree(join31(path, name), depth + 1))))
19863
19990
  continue;
19864
- if (name.startsWith(".") && name !== ".system" && agent !== "hermes" && agent !== "sumi" && !(options.guardHermes && `${path}${sep13}`.includes(`${sep13}.agents${sep13}skills${sep13}`)))
19991
+ if (name.startsWith(".") && name !== ".system" && agent !== "hermes" && agent !== "sumi" && !(options.guardHermes && `${path}${sep14}`.includes(`${sep14}.agents${sep14}skills${sep14}`)))
19865
19992
  continue;
19866
19993
  const isVendor = vendor || name === ".system";
19867
19994
  if (isVendor && !options.includeVendor)
19868
19995
  continue;
19869
- const child2 = join30(path, name);
19870
- if (isVendor && lstatSync27(child2, { throwIfNoEntry: false })?.isSymbolicLink()) {
19996
+ const child2 = join31(path, name);
19997
+ if (isVendor && lstatSync28(child2, { throwIfNoEntry: false })?.isSymbolicLink()) {
19871
19998
  const target = statSync11(child2, { throwIfNoEntry: false });
19872
19999
  if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent, child2, path)) {
19873
20000
  scan.entries++;
@@ -19884,7 +20011,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
19884
20011
  return scan;
19885
20012
  }
19886
20013
  function scanRoot(agent, path, vendor = false, pluginCache = false, configuredRoot = false) {
19887
- if (agent === "hermes" || options.guardHermes && `${path}${sep13}`.includes(`${sep13}.agents${sep13}skills${sep13}`))
20014
+ if (agent === "hermes" || options.guardHermes && `${path}${sep14}`.includes(`${sep14}.agents${sep14}skills${sep14}`))
19888
20015
  assertNoHermesLegacyShadow(path);
19889
20016
  if (!visit2(agent, path, vendor, 0, pluginCache, false, configuredRoot).complete)
19890
20017
  throw new Error(`Native skill discovery limit exceeded; review this root before continuing: ${path}`);
@@ -19893,11 +20020,11 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
19893
20020
  scanRoot(agent, path);
19894
20021
  if (options.includeVendor) {
19895
20022
  for (const agent of ["codex", "claude"].filter(includesAgent))
19896
- scanRoot(agent, canonicalAgentPath(join30(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
20023
+ scanRoot(agent, canonicalAgentPath(join31(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
19897
20024
  if (includesAgent("claude"))
19898
- scanRoot("claude", canonicalAgentPath(join30(home, ".claude", "plugins", "synced"), aliases), true);
20025
+ scanRoot("claude", canonicalAgentPath(join31(home, ".claude", "plugins", "synced"), aliases), true);
19899
20026
  if (includesAgent("gemini"))
19900
- scanRoot("gemini", join30(home, ".gemini", "extensions"), true);
20027
+ scanRoot("gemini", join31(home, ".gemini", "extensions"), true);
19901
20028
  }
19902
20029
  const configured = options.configured ? INTEGRATION_AGENTS.filter(includesAgent).flatMap((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }).roots.map((path) => ({ agent, path }))) : [];
19903
20030
  for (const root of [...options.agentRoots ?? [], ...configured])
@@ -19910,7 +20037,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
19910
20037
  }
19911
20038
  function readOptional(path) {
19912
20039
  assertSafePath(path);
19913
- return existsSync9(path) ? readFileSync18(path, "utf8") : null;
20040
+ return existsSync9(path) ? readFileSync19(path, "utf8") : null;
19914
20041
  }
19915
20042
  function jsonObject(text2, path) {
19916
20043
  if (text2 === null)
@@ -20010,19 +20137,19 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
20010
20137
  function disableCodexSkills(text2, skills, aliases, bridgePath) {
20011
20138
  const bundled = disableCodexBundledSkills(text2);
20012
20139
  let result = normalizeCodexInlinePathConfig(bundled);
20013
- const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve22(bridgePath), resolve22(join30(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
20140
+ const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve23(bridgePath), resolve23(join31(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
20014
20141
  const previousConfig = Bun.TOML.parse(bundled).skills?.config;
20015
20142
  if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
20016
20143
  throw new Error("Codex skill controls require one path or name selector per [[skills.config]] entry; review ambiguous entries before running skills hook install");
20017
20144
  const bridgeNeedsRepair = previousConfig?.some((entry) => entry.enabled === false && bridgeSelector(entry));
20018
20145
  const selections = [...skills.filter((entry) => entry.agent === "codex" && !entry.bridge).map((skill) => ({ path: skill.path, enabled: false })), { path: bridgePath, enabled: true }];
20019
20146
  for (const skill of selections) {
20020
- const path = join30(skill.path, "SKILL.md");
20147
+ const path = join31(skill.path, "SKILL.md");
20021
20148
  let found = false;
20022
20149
  result = result.replace(CODEX_SKILL_CONFIG_SECTIONS, (section) => {
20023
20150
  const parsed = Bun.TOML.parse(section);
20024
20151
  const declared = parsed.skills?.config?.[0];
20025
- if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve22(path), resolve22(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
20152
+ if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve23(path), resolve23(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
20026
20153
  return section;
20027
20154
  found = true;
20028
20155
  return /^\s*enabled\s*=/m.test(section) ? section.replace(/^\s*enabled\s*=.*$/m, `enabled = ${skill.enabled}`) : `${section.trimEnd()}
@@ -20043,8 +20170,8 @@ enabled = false
20043
20170
  return result;
20044
20171
  }
20045
20172
  function assertCodexInstallationInputs(home, projectDirs, inputs) {
20046
- const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory2) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => resolve22(directory2, path)));
20047
- if (inputs.some((input) => nativeRoots.some((root) => root === input || root.startsWith(input + sep13) || input.startsWith(root + sep13))))
20173
+ const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory2) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => resolve23(directory2, path)));
20174
+ if (inputs.some((input) => nativeRoots.some((root) => root === input || root.startsWith(input + sep14) || input.startsWith(root + sep14))))
20048
20175
  throw new Error("Native installation input overlaps an unconditional skill-loading root");
20049
20176
  }
20050
20177
  function planAgentIntegration(options) {
@@ -20054,7 +20181,7 @@ function planAgentIntegration(options) {
20054
20181
  throw new Error("Explicit Codex skill denials require a fresh native catalog and discovery review");
20055
20182
  const home = options.home ?? homedir2(), dataDir2 = options.dataDir ?? getDataDirReadOnly();
20056
20183
  const aliases = rootAliases(home, options.allowRootAliases);
20057
- const policyPath = join30(dataDir2, "agent-policy.json");
20184
+ const policyPath = join31(dataDir2, "agent-policy.json");
20058
20185
  assertSafePath(policyPath);
20059
20186
  const priorSnapshot = readManagedSkillPolicySnapshot(dataDir2), previousPolicy = priorSnapshot?.text ?? null, policy = priorSnapshot?.value ?? {};
20060
20187
  if (policy.bridge !== undefined && (!policy.bridge || typeof policy.bridge !== "object" || Array.isArray(policy.bridge)))
@@ -20091,28 +20218,28 @@ function planAgentIntegration(options) {
20091
20218
  }
20092
20219
  return resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, retainedReview, canonical: (path) => canonicalAgentPath(path, aliases), executable: executable2 });
20093
20220
  });
20094
- const codexConfigBefore = options.agents.includes("codex") ? readOptional(canonicalAgentPath(join30(home, ".codex", "config.toml"), aliases)) : null;
20221
+ const codexConfigBefore = options.agents.includes("codex") ? readOptional(canonicalAgentPath(join31(home, ".codex", "config.toml"), aliases)) : null;
20095
20222
  const codexConfig = Bun.TOML.parse(codexConfigBefore ?? "");
20096
20223
  const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, disabledVendorPaths: disabledCodexSkillPaths(codexConfig, aliases) });
20097
- const codexPathConfig = options.agents.includes("codex") ? disableCodexSkills(codexConfigBefore ?? "", nativeSkills, aliases, canonicalAgentPath(join30(home, ".codex/skills", CLI_BRIDGE_NAME), aliases)) : undefined;
20224
+ const codexPathConfig = options.agents.includes("codex") ? disableCodexSkills(codexConfigBefore ?? "", nativeSkills, aliases, canonicalAgentPath(join31(home, ".codex/skills", CLI_BRIDGE_NAME), aliases)) : undefined;
20098
20225
  const plannedCodexRules = codexPathConfig === undefined ? undefined : Bun.TOML.parse(codexPathConfig).skills?.config ?? [];
20099
20226
  const observedNativeSources = [];
20100
- const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join30(entry.path, "SKILL.md")), canonicalAgentPath(join30(home, ".codex/plugins/cache"), aliases), resolve22(options.projectDir ?? home), (path) => {
20227
+ const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join31(entry.path, "SKILL.md")), canonicalAgentPath(join31(home, ".codex/plugins/cache"), aliases), resolve23(options.projectDir ?? home), (path) => {
20101
20228
  const bytes = readNativeBytes(path, 1024 * 1024);
20102
20229
  observedNativeSources.push({ path, sha256: sha4(bytes) });
20103
20230
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
20104
20231
  }, codexConfig.skills?.config ?? [], codexConfig.plugins, plannedCodexRules, options.codexSkillDenials) : { skills: policy.bridge?.codexPluginSkills ?? [], inactivePlugins: policy.bridge?.codexInactivePlugins ?? [], sourceInputs: policy.bridge?.discovery?.codex?.codexInstallationInputs?.plugins ?? [] };
20105
- const cache = canonicalAgentPath(join30(home, ".codex/plugins/cache"), aliases);
20232
+ const cache = canonicalAgentPath(join31(home, ".codex/plugins/cache"), aliases);
20106
20233
  const retired = (policy.bridge?.codexPluginSkills ?? []).filter((control) => absentDisabledCodexPluginParent(cache, control.pluginParent, policy.bridge.codexPluginSkills, codexConfig.skills?.config ?? []));
20107
20234
  for (const denial of options.codexSkillDenials ?? []) {
20108
20235
  const control = codexPluginControls.skills.find((item) => item.name === denial.name);
20109
20236
  if (!control)
20110
20237
  throw new Error("Explicit Codex denial did not resolve a reviewed identity");
20111
- const root = join30(control.pluginParent, relative9(control.pluginParent, denial.path).split(sep13)[0]);
20238
+ const root = join31(control.pluginParent, relative9(control.pluginParent, denial.path).split(sep14)[0]);
20112
20239
  const review = options.discoveryInputs.agents.find((item) => item.agent === "codex");
20113
- for (const path of [join30(root, ".app.json"), join30(root, ".mcp.json"), join30(root, "hooks")])
20240
+ for (const path of [join31(root, ".app.json"), join31(root, ".mcp.json"), join31(root, "hooks")])
20114
20241
  observedNativeSources.push({ path, sha256: nativeSourceDigest(path) });
20115
- const files = [join30(root, ".codex-plugin/plugin.json"), ...control.appSha256 ? [join30(root, ".app.json")] : [], ...control.mcpSha256 ? [join30(root, ".mcp.json")] : []];
20242
+ const files = [join31(root, ".codex-plugin/plugin.json"), ...control.appSha256 ? [join31(root, ".app.json")] : [], ...control.mcpSha256 ? [join31(root, ".mcp.json")] : []];
20116
20243
  for (const path of files)
20117
20244
  if (!review?.sources.some((source) => source.path === path && source.format === undefined && source.fields === undefined && [undefined, "bytes"].includes(source.hashMode) && source.sha256 === sha4(readNativeBytes(path, 1024 * 1024))))
20118
20245
  throw new Error("Explicit Codex denial requires current full manifest and capability discovery witnesses");
@@ -20121,12 +20248,12 @@ function planAgentIntegration(options) {
20121
20248
  for (const discovery of discoveries)
20122
20249
  if (discovery.agent === "codex" && discovery.method === "reviewed")
20123
20250
  discovery.codexDisabledPluginSkills = codexPluginSkills;
20124
- if (options.agents.includes("codex") && !options.codexNativeCatalog && codexPluginSkills.length && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join30(home, ".codex/plugins/cache"), aliases), codexPluginSkills, (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)), codexConfig.skills?.config ?? [])) {
20251
+ if (options.agents.includes("codex") && !options.codexNativeCatalog && codexPluginSkills.length && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join31(home, ".codex/plugins/cache"), aliases), codexPluginSkills, (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)), codexConfig.skills?.config ?? [])) {
20125
20252
  throw new Error("NATIVE_SKILL_DRIFT: reviewed native plugin capability controls changed; provide a fresh native catalog and discovery review");
20126
20253
  }
20127
20254
  const codexInactivePlugins = codexPluginControls.inactivePlugins;
20128
20255
  const codexDiscovery = discoveries.find((binding) => binding.agent === "codex");
20129
- const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root) => root === input.sourceRoot || root.startsWith(input.sourceRoot + sep13) || input.sourceRoot.startsWith(root + sep13)) && codexDiscovery.sources.some((source) => source.path === join30(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
20256
+ const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root) => root === input.sourceRoot || root.startsWith(input.sourceRoot + sep14) || input.sourceRoot.startsWith(root + sep14)) && codexDiscovery.sources.some((source) => source.path === join31(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
20130
20257
  assertCodexInstallationInputs(home, [options.projectDir ?? home], codexPluginSourceInputs.map((input) => input.sourceRoot));
20131
20258
  const changes = [];
20132
20259
  let observedSettings;
@@ -20134,19 +20261,19 @@ function planAgentIntegration(options) {
20134
20261
  if (!INTEGRATION_AGENTS.includes(agent))
20135
20262
  throw new Error(`Unsupported agent: ${agent}`);
20136
20263
  const { command, profileId: profileId2 } = bindings.get(agent);
20137
- const bridgePath = canonicalAgentPath(join30(nativeAgentRoot(home, agent, options.projectDir ?? process.cwd()), CLI_BRIDGE_NAME), aliases);
20264
+ const bridgePath = canonicalAgentPath(join31(nativeAgentRoot(home, agent, options.projectDir ?? process.cwd()), CLI_BRIDGE_NAME), aliases);
20138
20265
  assertSafePath(bridgePath);
20139
20266
  if (existsSync9(bridgePath) && !isOwnedCliBridge(bridgePath, [bridgePath]))
20140
20267
  throw new Error(`Refusing to overwrite an unrecognized or modified Skills bridge: ${bridgePath}`);
20141
20268
  for (const [name, after2] of Object.entries(CLI_BRIDGE_FILES)) {
20142
- const path2 = join30(bridgePath, name), before2 = readOptional(path2);
20269
+ const path2 = join31(bridgePath, name), before2 = readOptional(path2);
20143
20270
  if (before2 !== after2)
20144
20271
  changes.push({ path: path2, before: before2, after: after2 });
20145
20272
  }
20146
20273
  const path = canonicalAgentPath(nativeAgentConfig(home, agent, options.projectDir ?? process.cwd()), aliases);
20147
20274
  const before = readOptional(path);
20148
20275
  if (agent === "hermes") {
20149
- const supervisorPath = join30(dataDir2, "agent-hooks", "hermes.js"), supervisorBefore = readOptional(supervisorPath), supervisorAfter = renderHermesSupervisor(command, profileId2);
20276
+ const supervisorPath = join31(dataDir2, "agent-hooks", "hermes.js"), supervisorBefore = readOptional(supervisorPath), supervisorAfter = renderHermesSupervisor(command, profileId2);
20150
20277
  const priorCommand = policy.bridge?.commands?.hermes, priorProfile = policy.bridge?.profiles?.hermes ?? policy.profileId;
20151
20278
  const previous = policy.bridge?.supervisors?.hermes;
20152
20279
  if (supervisorBefore !== null && supervisorBefore !== supervisorAfter && !(previous?.path === supervisorPath && typeof priorCommand === "string" && typeof priorProfile === "string" && supervisorBefore === renderHermesSupervisor(priorCommand, priorProfile)))
@@ -20157,7 +20284,7 @@ function planAgentIntegration(options) {
20157
20284
  const after2 = configureHermesHooks(before, supervisor, previous);
20158
20285
  if (before !== after2)
20159
20286
  changes.push({ path, before, after: after2 });
20160
- const optOut = join30(home, ".hermes", HERMES_OPT_OUT), optOutBefore = readOptional(optOut);
20287
+ const optOut = join31(home, ".hermes", HERMES_OPT_OUT), optOutBefore = readOptional(optOut);
20161
20288
  if (optOutBefore === null)
20162
20289
  changes.push({ path: optOut, before: null, after: `Managed by @hasna/skills: bundled native skill reseeding is disabled.
20163
20290
  ` });
@@ -20168,7 +20295,7 @@ function planAgentIntegration(options) {
20168
20295
  if (config.permissions !== undefined && (!Array.isArray(config.permissions) || config.permissions.some((rule) => !rule || typeof rule.action !== "string" || typeof rule.resource !== "string" || !["allow", "deny", "ask"].includes(rule.effect))))
20169
20296
  throw new Error("Expected Sumi native permission rules");
20170
20297
  config.permissions = [...(config.permissions ?? []).filter((rule) => rule.action !== "skill"), ...SUMI_SKILL_PERMISSIONS];
20171
- const pluginPath = join30(sumiConfigDirectory(home, process.env, options.projectDir ?? process.cwd()), "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
20298
+ const pluginPath = join31(sumiConfigDirectory(home, process.env, options.projectDir ?? process.cwd()), "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
20172
20299
  const pluginAfter = renderSumiPlugin(command, profileId2);
20173
20300
  const priorCommand = policy.bridge?.commands?.sumi, priorProfile = policy.bridge?.profiles?.sumi ?? policy.profileId;
20174
20301
  if (pluginBefore !== null && pluginBefore !== pluginAfter && !(typeof priorCommand === "string" && typeof priorProfile === "string" && isManagedSumiPlugin(pluginBefore, priorCommand, priorProfile)))
@@ -20180,7 +20307,7 @@ function planAgentIntegration(options) {
20180
20307
  if (!permission || typeof permission !== "object" || Array.isArray(permission))
20181
20308
  throw new Error("Expected OpenCode permission object");
20182
20309
  config.permission = { ...permission, skill: { "*": "deny", [CLI_BRIDGE_NAME]: "allow" } };
20183
- const pluginPath = join30(home, ".config", "opencode", "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
20310
+ const pluginPath = join31(home, ".config", "opencode", "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
20184
20311
  const pluginAfter = renderOpenCodePlugin(command, profileId2);
20185
20312
  const priorCommand = policy.bridge?.commands?.opencode;
20186
20313
  const ownedPrevious = typeof priorCommand === "string" && typeof policy.profileId === "string" && pluginBefore === renderOpenCodePlugin(priorCommand, policy.bridge?.profiles?.opencode ?? policy.profileId);
@@ -20197,7 +20324,7 @@ function planAgentIntegration(options) {
20197
20324
  if (before !== after)
20198
20325
  changes.push({ path, before, after });
20199
20326
  if (agent === "codex") {
20200
- const configPath = canonicalAgentPath(join30(home, ".codex", "config.toml"), aliases), previous = readOptional(configPath);
20327
+ const configPath = canonicalAgentPath(join31(home, ".codex", "config.toml"), aliases), previous = readOptional(configPath);
20201
20328
  if (previous !== codexConfigBefore)
20202
20329
  throw new Error(`Configuration changed during planning: ${configPath}`);
20203
20330
  const next = disableReviewedCodexPluginNames(codexPathConfig, codexPluginSkills);
@@ -20209,28 +20336,28 @@ function planAgentIntegration(options) {
20209
20336
  }
20210
20337
  }
20211
20338
  }
20212
- const codexPluginSkillReview = options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha4(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join30(home, ".codex/config.toml"), aliases))?.before === null ? null : sha4(readOptional(canonicalAgentPath(join30(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview;
20339
+ const codexPluginSkillReview = options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha4(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join31(home, ".codex/config.toml"), aliases))?.before === null ? null : sha4(readOptional(canonicalAgentPath(join31(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview;
20213
20340
  const discoveryAfter = discoveries.map((binding) => {
20214
20341
  const rebound = rebindAgentDiscovery(binding, new Map(changes.map((change) => [change.path, change.after])));
20215
20342
  if (binding.agent !== "codex")
20216
20343
  return rebound;
20217
20344
  const { codexInstallationInputs: previousInputs, ...current } = rebound;
20218
20345
  const inputs = codexPluginSourceInputs.map((input) => input.sourceRoot);
20219
- const directories = options.codexNativeCatalog || !previousInputs ? captureDiscoveryDirectories((binding.directories ?? []).filter((directory2) => inputs.some((root) => root.startsWith(directory2.path + sep13))).map((directory2) => directory2.path), inputs) : previousInputs.directories;
20346
+ const directories = options.codexNativeCatalog || !previousInputs ? captureDiscoveryDirectories((binding.directories ?? []).filter((directory2) => inputs.some((root) => root.startsWith(directory2.path + sep14))).map((directory2) => directory2.path), inputs) : previousInputs.directories;
20220
20347
  const installed = codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: codexPluginSkillReview.version, catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
20221
- return captureRetiredCodexDiscovery(installed, codexPluginSkills, Bun.TOML.parse(changes.find((change) => change.path === canonicalAgentPath(join30(home, ".codex/config.toml"), aliases))?.after ?? codexConfigBefore ?? "").skills?.config ?? []);
20348
+ return captureRetiredCodexDiscovery(installed, codexPluginSkills, Bun.TOML.parse(changes.find((change) => change.path === canonicalAgentPath(join31(home, ".codex/config.toml"), aliases))?.after ?? codexConfigBefore ?? "").skills?.config ?? []);
20222
20349
  });
20223
20350
  const nextPolicy = { ...policy, version: 1, loading: "cli", profileId, bridge: {
20224
20351
  ...policy.bridge,
20225
20352
  version: CLI_BRIDGE_VERSION,
20226
20353
  digest: CLI_BRIDGE_DIGEST,
20227
20354
  agents: [...new Set([...priorAgents, ...options.agents])].sort(),
20228
- home: resolve22(home),
20355
+ home: resolve23(home),
20229
20356
  includeVendor: true,
20230
- ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join30(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha4(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
20357
+ ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join31(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha4(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
20231
20358
  commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
20232
20359
  profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
20233
- disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join30(home, ".codex", "skills", ".system"), aliases) + sep13)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
20360
+ disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join31(home, ".codex", "skills", ".system"), aliases) + sep14)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
20234
20361
  rootAliases: aliases,
20235
20362
  ...options.codexNativeCatalog || codexPluginSkills.length || codexInactivePlugins.length || codexPluginSourceInputs.length ? { codexPluginSkills, codexInactivePlugins, codexPluginSkillReview } : {},
20236
20363
  discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
@@ -20273,7 +20400,7 @@ function projectedHookAcl(path, observed) {
20273
20400
  const identity5 = observed.isDirectory() ? (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.uid}:${stat2.mode}` : (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}:${stat2.uid}:${stat2.mode}:${stat2.nlink}:${stat2.size}:${stat2.mtimeNs}`;
20274
20401
  const fd = openSync17(path, constants18.O_RDONLY | constants18.O_NOFOLLOW | constants18.O_NONBLOCK | (observed.isDirectory() ? constants18.O_DIRECTORY : 0));
20275
20402
  try {
20276
- if (identity5(fstatSync17(fd, { bigint: true })) !== identity5(observed) || !hasTrustedDarwinAcl(fd, true) || identity5(fstatSync17(fd, { bigint: true })) !== identity5(observed) || identity5(lstatSync27(path, { bigint: true })) !== identity5(observed))
20403
+ if (identity5(fstatSync17(fd, { bigint: true })) !== identity5(observed) || !hasTrustedDarwinAcl(fd, true) || identity5(fstatSync17(fd, { bigint: true })) !== identity5(observed) || identity5(lstatSync28(path, { bigint: true })) !== identity5(observed))
20277
20404
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
20278
20405
  } finally {
20279
20406
  closeSync17(fd);
@@ -20281,23 +20408,23 @@ function projectedHookAcl(path, observed) {
20281
20408
  }
20282
20409
  function projectedHookExecutable(command, expectedResolved) {
20283
20410
  try {
20284
- if (!isAbsolute24(command) || /[\0\r\n]/.test(command) || resolve22(command) !== command)
20411
+ if (!isAbsolute24(command) || /[\0\r\n]/.test(command) || resolve23(command) !== command)
20285
20412
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
20286
20413
  command = canonicalSystemPath(command);
20287
20414
  const parents2 = (file = command) => {
20288
20415
  const result = [];
20289
- for (let path = dirname21(file);; path = dirname21(path)) {
20290
- const stat2 = lstatSync27(path, { bigint: true });
20416
+ for (let path = dirname22(file);; path = dirname22(path)) {
20417
+ const stat2 = lstatSync28(path, { bigint: true });
20291
20418
  if (!stat2.isDirectory() || !trustedAncestorOwner(stat2.uid) || (stat2.mode & 0o022n) !== 0n && !(stat2.uid === 0n && (stat2.mode & 0o1000n) !== 0n))
20292
20419
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
20293
20420
  projectedHookAcl(path, stat2);
20294
20421
  result.push(`${path}:${stat2.dev}:${stat2.ino}:${stat2.uid}:${stat2.mode}`);
20295
- if (dirname21(path) === path)
20422
+ if (dirname22(path) === path)
20296
20423
  break;
20297
20424
  }
20298
20425
  return result;
20299
20426
  };
20300
- const parentIdentity = parents2(), link = lstatSync27(command, { bigint: true });
20427
+ const parentIdentity = parents2(), link = lstatSync28(command, { bigint: true });
20301
20428
  if (link.uid !== BigInt(process.getuid()) || !link.isFile() && !link.isSymbolicLink())
20302
20429
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
20303
20430
  const linkIdentity = (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.mode}:${stat2.uid}:${stat2.ctimeNs}`;
@@ -20317,18 +20444,18 @@ function projectedHookExecutable(command, expectedResolved) {
20317
20444
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
20318
20445
  const path = target.pinned.runtime;
20319
20446
  assertPinnedLauncherRuntimeSafe(path);
20320
- if (resolve22(path) !== path)
20447
+ if (resolve23(path) !== path)
20321
20448
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
20322
- runtime = { path, parents: parents2(path), stat: lstatSync27(path, { bigint: true }) };
20449
+ runtime = { path, parents: parents2(path), stat: lstatSync28(path, { bigint: true }) };
20323
20450
  if (!runtime.stat.isFile())
20324
20451
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
20325
20452
  projectedHookAcl(path, runtime.stat);
20326
20453
  }
20327
20454
  const resolvedParentIdentity = parents2(resolved);
20328
- const manifest = snapshot(join30(dirname21(dirname21(resolved)), "package.json"), false, { readOnlyPackage: true });
20455
+ const manifest = snapshot(join31(dirname22(dirname22(resolved)), "package.json"), false, { readOnlyPackage: true });
20329
20456
  projectedHookAcl(manifest.file, manifest.stat);
20330
20457
  const pkg = JSON.parse(manifest.text);
20331
- if (pkg.name !== "@hasna/skills" || !/^\d+\.\d+\.\d+$/.test(pkg.version) || pkg.bin?.skills !== "bin/index.js" || resolved !== join30(dirname21(manifest.file), "bin/index.js"))
20458
+ if (pkg.name !== "@hasna/skills" || !/^\d+\.\d+\.\d+$/.test(pkg.version) || pkg.bin?.skills !== "bin/index.js" || resolved !== join31(dirname22(manifest.file), "bin/index.js"))
20332
20459
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
20333
20460
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
20334
20461
  projectedHookAcl(cli.file, cli.stat);
@@ -20337,7 +20464,7 @@ function projectedHookExecutable(command, expectedResolved) {
20337
20464
  const recheck = () => {
20338
20465
  try {
20339
20466
  const again = resolveLauncherCommand(command);
20340
- if (again.entry !== resolved || again.physical !== target.physical || linkIdentity(lstatSync27(command, { bigint: true })) !== linkIdentity(link) || !direct() || !isDeepStrictEqual8(parents2(), parentIdentity) || !isDeepStrictEqual8(parents2(resolved), resolvedParentIdentity))
20467
+ if (again.entry !== resolved || again.physical !== target.physical || linkIdentity(lstatSync28(command, { bigint: true })) !== linkIdentity(link) || !direct() || !isDeepStrictEqual8(parents2(), parentIdentity) || !isDeepStrictEqual8(parents2(resolved), resolvedParentIdentity))
20341
20468
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
20342
20469
  if (launcher) {
20343
20470
  if (!isDeepStrictEqual8(parents2(target.physical), launcherParentIdentity))
@@ -20377,8 +20504,8 @@ function planClaudeManagedHookProjection(options) {
20377
20504
  } catch {
20378
20505
  hookProjectionRefusal("TARGET_INVALID");
20379
20506
  }
20380
- const home = resolve22(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
20381
- const policyPath = join30(dataDir2, "agent-policy.json");
20507
+ const home = resolve23(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
20508
+ const policyPath = join31(dataDir2, "agent-policy.json");
20382
20509
  let policyBytes, settingsBytes, settingsPath, command, profile;
20383
20510
  try {
20384
20511
  policyBytes = readNativeBytes(policyPath, 1024 * 1024);
@@ -20386,7 +20513,7 @@ function planClaudeManagedHookProjection(options) {
20386
20513
  if (!snapshot2 || snapshot2.text !== policyBytes.toString("utf8"))
20387
20514
  hookProjectionRefusal("SOURCE_UNVERIFIED");
20388
20515
  const binding = snapshot2.value.bridge;
20389
- settingsPath = canonicalAgentPath(join30(home, AGENT_ADAPTERS.claude.config), binding?.rootAliases ?? []);
20516
+ settingsPath = canonicalAgentPath(join31(home, AGENT_ADAPTERS.claude.config), binding?.rootAliases ?? []);
20390
20517
  settingsBytes = readNativeBytes(settingsPath, 1024 * 1024);
20391
20518
  command = binding?.commands?.claude;
20392
20519
  profile = binding?.profiles?.claude;
@@ -20472,7 +20599,7 @@ function claudeSettingsConsumers(home, path, discoveries, aliases) {
20472
20599
  const canonical9 = (value) => canonicalAgentPath(value, aliases);
20473
20600
  const containsSettings = (root) => {
20474
20601
  const distance = relative9(canonical9(root), path);
20475
- return distance === "" || distance !== ".." && !distance.startsWith(`..${sep13}`) && !isAbsolute24(distance);
20602
+ return distance === "" || distance !== ".." && !distance.startsWith(`..${sep14}`) && !isAbsolute24(distance);
20476
20603
  };
20477
20604
  return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" || binding.agent !== "sumi" && canonical9(nativeAgentConfig(home, binding.agent)) === path || binding.sources.some((source) => canonical9(source.path) === path) || binding.roots.some(containsSettings) || binding.directories?.some((directory2) => containsSettings(directory2.path))).map((binding) => binding.agent);
20478
20605
  }
@@ -20490,8 +20617,8 @@ function verifyCoordinatedDiscovery(binding, home, aliases, executable2) {
20490
20617
  }
20491
20618
  }
20492
20619
  function planClaudeHookEventsUpdate(options) {
20493
- const home = resolve22(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
20494
- const policyPath = join30(dataDir2, "agent-policy.json");
20620
+ const home = resolve23(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
20621
+ const policyPath = join31(dataDir2, "agent-policy.json");
20495
20622
  assertSafePath(policyPath);
20496
20623
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
20497
20624
  if (!snapshot2)
@@ -20502,9 +20629,9 @@ function planClaudeHookEventsUpdate(options) {
20502
20629
  }
20503
20630
  const aliases = bridge.rootAliases ?? [];
20504
20631
  recheckRootAliases(aliases);
20505
- const path = canonicalAgentPath(join30(home, ".claude", "settings.json"), aliases);
20632
+ const path = canonicalAgentPath(join31(home, ".claude", "settings.json"), aliases);
20506
20633
  assertSafePath(path);
20507
- const before = lstatSync27(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
20634
+ const before = lstatSync28(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
20508
20635
  if ((before === null ? "absent" : sha4(before)) !== options.expectedSettingsSha256)
20509
20636
  throw new Error("Claude settings preimage changed");
20510
20637
  assertClaudeHookEventsReplacement(before, options.replacement, options.events);
@@ -20560,7 +20687,7 @@ function planClaudeHookEventsUpdate(options) {
20560
20687
  }
20561
20688
  function atomicWrite2(path, content) {
20562
20689
  assertSafePath(path);
20563
- mkdirSync8(dirname21(path), { recursive: true, mode: 448 });
20690
+ mkdirSync8(dirname22(path), { recursive: true, mode: 448 });
20564
20691
  const temporary = `${path}.skills-${randomUUID4()}`;
20565
20692
  try {
20566
20693
  writeFileSync6(temporary, content, { mode: 384, flag: "wx" });
@@ -20575,7 +20702,7 @@ function planAgentSettingsWitnessUpgrade(options) {
20575
20702
  throw new Error("Invalid Codex witness target version");
20576
20703
  if (options.targetClaudeVersion !== undefined && (options.agent !== "claude" || ![3, 4].includes(options.targetClaudeVersion)))
20577
20704
  throw new Error("Invalid Claude witness target version");
20578
- const home = resolve22(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
20705
+ const home = resolve23(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
20579
20706
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
20580
20707
  if (!snapshot2 || sha4(snapshot2.text) !== options.expectedPolicySha256)
20581
20708
  throw new Error("Managed policy preimage changed");
@@ -20584,7 +20711,7 @@ function planAgentSettingsWitnessUpgrade(options) {
20584
20711
  const binding = policy.bridge?.discovery?.[options.agent];
20585
20712
  if (!binding || binding.agent !== options.agent || binding.method !== "reviewed")
20586
20713
  throw new Error("Settings witness upgrade requires an existing reviewed native binding");
20587
- const configPath = canonicalAgentPath(options.agent === "sumi" ? nativeAgentConfig(home, "sumi", options.projectDir ?? process.cwd()) : join30(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
20714
+ const configPath = canonicalAgentPath(options.agent === "sumi" ? nativeAgentConfig(home, "sumi", options.projectDir ?? process.cwd()) : join31(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
20588
20715
  const settings = readOptional(configPath);
20589
20716
  if (settings === null || sha4(settings) !== options.expectedSettingsSha256)
20590
20717
  throw new Error("Native settings preimage changed");
@@ -20635,12 +20762,12 @@ function planAgentSettingsWitnessUpgrade(options) {
20635
20762
  const replacement = { ...binding, sources: rebound };
20636
20763
  verifyAgentDiscovery(replacement, undefined, aliases);
20637
20764
  const after = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
20638
- 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 })) } };
20765
+ return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join31(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join31(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 })) } };
20639
20766
  }
20640
20767
  function planCodexSemanticCacheWitnessUpgrade(options) {
20641
20768
  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))
20642
20769
  throw new Error("Invalid Codex semantic cache upgrade request");
20643
- const home = resolve22(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
20770
+ const home = resolve23(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
20644
20771
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
20645
20772
  if (!snapshot2 || sha4(snapshot2.text) !== options.expectedPolicySha256)
20646
20773
  throw new Error("Managed policy preimage changed");
@@ -20654,10 +20781,10 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
20654
20781
  throw new Error("Cache upgrade requires prior installed-plugin review");
20655
20782
  if (!controls.length || !isDeepStrictEqual8(controls, binding.codexDisabledPluginSkills ?? controls))
20656
20783
  throw new Error("Cache upgrade requires unchanged enrolled plugin controls");
20657
- const cacheRoot = canonicalAgentPath(join30(home, ".codex/plugins/cache"), aliases);
20658
- if (controls.some((control) => dirname21(dirname21(control.pluginParent)) !== cacheRoot))
20784
+ const cacheRoot = canonicalAgentPath(join31(home, ".codex/plugins/cache"), aliases);
20785
+ if (controls.some((control) => dirname22(dirname22(control.pluginParent)) !== cacheRoot))
20659
20786
  throw new Error("Cache upgrade names another enrolled cache");
20660
- const configPath = canonicalAgentPath(join30(home, ".codex/config.toml"), aliases), settings = readOptional(configPath);
20787
+ const configPath = canonicalAgentPath(join31(home, ".codex/config.toml"), aliases), settings = readOptional(configPath);
20661
20788
  if (settings === null || sha4(settings) !== options.expectedSettingsSha256)
20662
20789
  throw new Error("Native settings preimage changed");
20663
20790
  const boundedRead = (path) => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024));
@@ -20680,13 +20807,13 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
20680
20807
  return unchangedFullSource(path);
20681
20808
  };
20682
20809
  const appOnlyParents = options.appOnlyParents.map((parent) => {
20683
- const parts = relative9(cacheRoot, parent).split(sep13);
20684
- if (!isAbsolute24(parent) || resolve22(parent) !== parent || parts.length !== 2 || parts.some((part) => !/^[A-Za-z0-9_-]{1,64}$/.test(part)) || controls.some((control) => control.pluginParent === parent))
20810
+ const parts = relative9(cacheRoot, parent).split(sep14);
20811
+ if (!isAbsolute24(parent) || resolve23(parent) !== parent || parts.length !== 2 || parts.some((part) => !/^[A-Za-z0-9_-]{1,64}$/.test(part)) || controls.some((control) => control.pluginParent === parent))
20685
20812
  throw new Error("Unsupported app-only parent role");
20686
- const receipt = JSON.parse(unchangedFullSource(join30(parent, ".codex-remote-plugin-install.json")));
20813
+ const receipt = JSON.parse(unchangedFullSource(join31(parent, ".codex-remote-plugin-install.json")));
20687
20814
  if (!receipt || Object.keys(receipt).length !== 2 || receipt.schema_version !== 1 || typeof receipt.remote_plugin_id !== "string")
20688
20815
  throw new Error("Invalid reviewed app-only parent identity");
20689
- const manifests = binding.sources.filter((source) => source.path.startsWith(parent + sep13) && source.path.endsWith(join30(sep13, ".codex-plugin/plugin.json")));
20816
+ const manifests = binding.sources.filter((source) => source.path.startsWith(parent + sep14) && source.path.endsWith(join31(sep14, ".codex-plugin/plugin.json")));
20690
20817
  if (!manifests.length)
20691
20818
  throw new Error("App-only bootstrap lacks prior full manifests");
20692
20819
  for (const source of manifests)
@@ -20694,10 +20821,10 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
20694
20821
  return { role: "app-only", pluginId: `${parts[1]}@${parts[0]}`, namespace: parts[1], pluginParent: parent, remotePluginId: receipt.remote_plugin_id };
20695
20822
  }).sort((a, b) => a.pluginParent.localeCompare(b.pluginParent));
20696
20823
  const reviewedHookParents = (options.reviewedHookParents ?? []).map((parent) => {
20697
- const parts = relative9(cacheRoot, parent).split(sep13);
20698
- if (!isAbsolute24(parent) || resolve22(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))
20824
+ const parts = relative9(cacheRoot, parent).split(sep14);
20825
+ if (!isAbsolute24(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))
20699
20826
  throw new Error("Unsupported reviewed native-hook parent role");
20700
- const receiptPath = join30(parent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync27(receiptPath, { throwIfNoEntry: false });
20827
+ const receiptPath = join31(parent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync28(receiptPath, { throwIfNoEntry: false });
20701
20828
  let identity5;
20702
20829
  if (receiptStat) {
20703
20830
  if (!receiptStat.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > 16 * 1024)
@@ -20734,11 +20861,11 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
20734
20861
  for (const version2 of versions) {
20735
20862
  if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
20736
20863
  throw new Error("Invalid reviewed native-hook version identity");
20737
- const root = join30(parent, version2), stat2 = lstatSync27(root, { throwIfNoEntry: false });
20864
+ const root = join31(parent, version2), stat2 = lstatSync28(root, { throwIfNoEntry: false });
20738
20865
  if (!stat2?.isDirectory() || stat2.isSymbolicLink() || realpathSync12(root) !== root)
20739
20866
  throw new Error("Invalid reviewed native-hook materialization");
20740
- unchangedReviewedHookSource(join30(root, ".codex-plugin/plugin.json"));
20741
- unchangedReviewedHookSource(join30(root, "hooks/hooks.json"));
20867
+ unchangedReviewedHookSource(join31(root, ".codex-plugin/plugin.json"));
20868
+ unchangedReviewedHookSource(join31(root, "hooks/hooks.json"));
20742
20869
  }
20743
20870
  return identity5;
20744
20871
  }).sort((a, b) => a.pluginParent.localeCompare(b.pluginParent));
@@ -20748,10 +20875,10 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
20748
20875
  assertCodexSemanticCacheHookSafety(cacheRoot, parents2, configPath, hookRootAlias);
20749
20876
  const supersededSources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents2, reviewedHookParents.map((parent) => parent.pluginParent)));
20750
20877
  for (const source of supersededSources)
20751
- if ([".app.json", ".mcp.json"].includes(source.path.split(sep13).at(-1)))
20878
+ if ([".app.json", ".mcp.json"].includes(source.path.split(sep14).at(-1)))
20752
20879
  unchangedFullSource(source.path);
20753
20880
  const supersededDirectories = (binding.directories ?? []).filter((directory2) => codexSemanticCacheDirectoryRole(directory2.path, cacheRoot));
20754
- if (!supersededDirectories.some((directory2) => directory2.path === cacheRoot) || (binding.directories ?? []).some((directory2) => cacheRoot.startsWith(directory2.path + sep13)))
20881
+ if (!supersededDirectories.some((directory2) => directory2.path === cacheRoot) || (binding.directories ?? []).some((directory2) => cacheRoot.startsWith(directory2.path + sep14)))
20755
20882
  throw new Error("Cache upgrade requires exact cache directory coverage without an unproved ancestor projection");
20756
20883
  const rules = Bun.TOML.parse(settings).skills?.config ?? [];
20757
20884
  const witness = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents, reviewedHookParents, rules, read: boundedRead });
@@ -20774,8 +20901,8 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
20774
20901
  dataDir: dataDir2,
20775
20902
  profileId: policy.profileId,
20776
20903
  nativeSkills: [],
20777
- changes: [{ path: join30(dataDir2, "agent-policy.json"), before: snapshot2.text, after }],
20778
- observedPolicy: { path: join30(dataDir2, "agent-policy.json"), before: snapshot2.text },
20904
+ changes: [{ path: join31(dataDir2, "agent-policy.json"), before: snapshot2.text, after }],
20905
+ observedPolicy: { path: join31(dataDir2, "agent-policy.json"), before: snapshot2.text },
20779
20906
  observedSettings: { path: configPath, before: settings },
20780
20907
  discoveryBefore: [replacement],
20781
20908
  discoveryAfter: [replacement],
@@ -20788,7 +20915,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
20788
20915
  function planReviewedArtifactMigration(options) {
20789
20916
  if (options.kind !== "codex-native-catalog" || !/^[a-f0-9]{64}$/.test(options.expectedPolicySha256) || !/^[a-f0-9]{64}$/.test(options.expectedSourceSha256))
20790
20917
  throw new Error("REVIEW_ARTIFACT_INVALID");
20791
- const home = resolve22(options.home ?? homedir2()), dataDir2 = resolve22(options.dataDir ?? getDataDirReadOnly());
20918
+ const home = resolve23(options.home ?? homedir2()), dataDir2 = resolve23(options.dataDir ?? getDataDirReadOnly());
20792
20919
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
20793
20920
  if (!snapshot2 || sha4(snapshot2.text) !== options.expectedPolicySha256)
20794
20921
  throw new Error("REVIEW_ARTIFACT_POLICY_CHANGED");
@@ -20805,8 +20932,8 @@ function planReviewedArtifactMigration(options) {
20805
20932
  dataDir: dataDir2,
20806
20933
  profileId: snapshot2.value.profileId,
20807
20934
  nativeSkills: [],
20808
- changes: [...retained.changes, { path: join30(dataDir2, "agent-policy.json"), before: snapshot2.text, after: serializeManagedSkillPolicy(next) }],
20809
- observedPolicy: { path: join30(dataDir2, "agent-policy.json"), before: snapshot2.text },
20935
+ changes: [...retained.changes, { path: join31(dataDir2, "agent-policy.json"), before: snapshot2.text, after: serializeManagedSkillPolicy(next) }],
20936
+ observedPolicy: { path: join31(dataDir2, "agent-policy.json"), before: snapshot2.text },
20810
20937
  reviewArtifactSources: retained.observed,
20811
20938
  retainedReviewArtifacts: retained.changes,
20812
20939
  reviewArtifactMigration: { ...options, home, dataDir: dataDir2 },
@@ -20832,12 +20959,12 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
20832
20959
  throw new Error("Native identity source changed after planning");
20833
20960
  if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
20834
20961
  throw new Error("Native settings changed after witness planning");
20835
- const policyPath = join30(plan.dataDir, "agent-policy.json");
20962
+ const policyPath = join31(plan.dataDir, "agent-policy.json");
20836
20963
  assertSafePath(policyPath);
20837
- const currentText = (path) => resolve22(path) === resolve22(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
20964
+ const currentText = (path) => resolve23(path) === resolve23(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
20838
20965
  readManagedSkillPolicySnapshot(plan.dataDir);
20839
20966
  for (const change of plan.changes)
20840
- if (resolve22(change.path) === resolve22(policyPath))
20967
+ if (resolve23(change.path) === resolve23(policyPath))
20841
20968
  parseManagedSkillPolicy(change.after);
20842
20969
  const aliases = plan.rootAliases ?? [];
20843
20970
  assertCurrent();
@@ -20882,7 +21009,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
20882
21009
  for (const change of plan.changes)
20883
21010
  if (currentText(change.path) !== change.before)
20884
21011
  throw new Error(`Configuration changed after planning: ${change.path}`);
20885
- const backupRoot = join30(plan.dataDir, "migration", randomUUID4()), backups = [], written = [], createdDirectories = new Set;
21012
+ const backupRoot = join31(plan.dataDir, "migration", randomUUID4()), backups = [], written = [], createdDirectories = new Set;
20886
21013
  if (!plan.changes.length) {
20887
21014
  assertCurrent();
20888
21015
  recheckRootAliases(aliases);
@@ -20893,9 +21020,9 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
20893
21020
  chmodSync(backupRoot, 448);
20894
21021
  for (const [index, change] of plan.changes.entries())
20895
21022
  if (change.before !== null) {
20896
- const backup = join30(backupRoot, `${index}-${sha4(change.path).slice(0, 12)}.backup`);
21023
+ const backup = join31(backupRoot, `${index}-${sha4(change.path).slice(0, 12)}.backup`);
20897
21024
  writeFileSync6(backup, change.before, { mode: 384, flag: "wx" });
20898
- if (readFileSync18(backup, "utf8") !== change.before)
21025
+ if (readFileSync19(backup, "utf8") !== change.before)
20899
21026
  throw new Error("Native configuration preservation readback failed");
20900
21027
  backups.push(backup);
20901
21028
  }
@@ -20905,7 +21032,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
20905
21032
  recheckRootAliases(aliases);
20906
21033
  if (currentText(change.path) !== change.before)
20907
21034
  throw new Error(`Configuration changed after planning: ${change.path}`);
20908
- for (let directory2 = dirname21(change.path);!existsSync9(directory2); directory2 = dirname21(directory2))
21035
+ for (let directory2 = dirname22(change.path);!existsSync9(directory2); directory2 = dirname22(directory2))
20909
21036
  createdDirectories.add(directory2);
20910
21037
  const after = change.after;
20911
21038
  const immutable = plan.retainedReviewArtifacts?.find((item) => item.path === change.path);
@@ -20935,7 +21062,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
20935
21062
  }
20936
21063
  for (const agent of plan.managedAgentChecks?.agents ?? [])
20937
21064
  assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.projectDir ?? plan.managedAgentChecks.home });
20938
- atomicWrite2(join30(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha4(change.before), afterHash: sha4(change.after) })), backups, ...plan.cacheWitnessUpgrade ? { cacheWitnessUpgrade: plan.cacheWitnessUpgrade } : {}, ...plan.retainedReviewArtifacts?.length ? { retainedReviewArtifacts: plan.retainedReviewArtifacts.map((item) => ({ path: item.path, ...item.artifact })) } : {}, ...aliases.length ? { rootAliases: aliases } : {} }) + `
21065
+ atomicWrite2(join31(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha4(change.before), afterHash: sha4(change.after) })), backups, ...plan.cacheWitnessUpgrade ? { cacheWitnessUpgrade: plan.cacheWitnessUpgrade } : {}, ...plan.retainedReviewArtifacts?.length ? { retainedReviewArtifacts: plan.retainedReviewArtifacts.map((item) => ({ path: item.path, ...item.artifact })) } : {}, ...aliases.length ? { rootAliases: aliases } : {} }) + `
20939
21066
  `);
20940
21067
  } catch (error) {
20941
21068
  assertCurrent();
@@ -20986,11 +21113,11 @@ function writeArchiveJournal(path, value) {
20986
21113
  closeSync17(descriptor);
20987
21114
  descriptor = undefined;
20988
21115
  renameSync4(temporary, path);
20989
- syncArchiveDirectory(dirname21(path));
21116
+ syncArchiveDirectory(dirname22(path));
20990
21117
  } finally {
20991
21118
  if (descriptor !== undefined)
20992
21119
  closeSync17(descriptor);
20993
- if (lstatSync27(temporary, { throwIfNoEntry: false }))
21120
+ if (lstatSync28(temporary, { throwIfNoEntry: false }))
20994
21121
  unlinkSync5(temporary);
20995
21122
  }
20996
21123
  }
@@ -20998,7 +21125,7 @@ function archiveNativeSkills(inventory, options) {
20998
21125
  const selected = options.targetManifest ? selectNativeMigrationTargets(inventory, options.targetManifest) : inventory.filter((entry) => !entry.bridge && !entry.system && (entry.vendor ? options.includeVendor : entry.managed || options.includeUnmanaged));
20999
21126
  const roots = selected.flatMap((entry) => {
21000
21127
  const root = (entry.rootAlias?.agent === "codex" ? entry.rootAlias.alias : undefined) ?? codexCorpusRootForPath(entry.path);
21001
- const owner2 = entry.codexHome ?? (entry.agent === "codex" && entry.bridgeHome ? join30(entry.bridgeHome, ".codex") : undefined);
21128
+ const owner2 = entry.codexHome ?? (entry.agent === "codex" && entry.bridgeHome ? join31(entry.bridgeHome, ".codex") : undefined);
21002
21129
  if (!root && !owner2 && (entry.agent === "codex" || isCodexSkillDiscoveryInput(entry.path)))
21003
21130
  throw new Error("CODEX_CORPUS_ROOT_UNVERIFIED");
21004
21131
  return [...new Set([root, owner2].filter((value) => value !== undefined))];
@@ -21013,7 +21140,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
21013
21140
  recheckRootAliases(aliases);
21014
21141
  for (const entry of inventory.filter((entry2) => entry2.bridge)) {
21015
21142
  const adapter = AGENT_ADAPTERS[entry.agent];
21016
- const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join30(nativeAgentRoot(entry.bridgeHome, entry.agent), CLI_BRIDGE_NAME), aliases) : undefined;
21143
+ const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join31(nativeAgentRoot(entry.bridgeHome, entry.agent), CLI_BRIDGE_NAME), aliases) : undefined;
21017
21144
  if (!expected || treeHash(entry.path) !== entry.hash || !isOwnedCliBridge(entry.path, [expected]))
21018
21145
  throw new Error(`Skills bridge changed after planning: ${entry.path}`);
21019
21146
  }
@@ -21024,11 +21151,11 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
21024
21151
  const targetManifest = options.targetManifest ? { schema: options.targetManifest.schema, digest: options.targetManifest.digest, targetCount: options.targetManifest.targets.length } : undefined;
21025
21152
  if (!selected.length)
21026
21153
  return { entries: [], ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
21027
- const operationId = randomUUID4(), archiveRoot = join30(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join30(archiveRoot, "receipt.json");
21154
+ const operationId = randomUUID4(), archiveRoot = join31(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join31(archiveRoot, "receipt.json");
21028
21155
  const entries = selected.map((entry, index) => ({
21029
- source: entry.vendor ? join30(entry.path, "SKILL.md") : entry.path,
21030
- archive: join30(archiveRoot, `${index}-${sha4(entry.path).slice(0, 12)}`),
21031
- hash: entry.vendor ? sha4(readNativeBytes(join30(entry.path, "SKILL.md"))) : entry.hash,
21156
+ source: entry.vendor ? join31(entry.path, "SKILL.md") : entry.path,
21157
+ archive: join31(archiveRoot, `${index}-${sha4(entry.path).slice(0, 12)}`),
21158
+ hash: entry.vendor ? sha4(readNativeBytes(join31(entry.path, "SKILL.md"))) : entry.hash,
21032
21159
  ...entry.vendor ? { discoveryOnly: true } : {},
21033
21160
  status: "planned"
21034
21161
  }));
@@ -21036,7 +21163,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
21036
21163
  const moved = [];
21037
21164
  const verifyArchive = (entry) => {
21038
21165
  assertSafePath(entry.archive);
21039
- const stat2 = lstatSync27(entry.archive);
21166
+ const stat2 = lstatSync28(entry.archive);
21040
21167
  if (entry.discoveryOnly ? !stat2.isFile() : !stat2.isDirectory())
21041
21168
  throw new Error("Archive type changed");
21042
21169
  if ((entry.discoveryOnly ? sha4(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
@@ -21044,14 +21171,14 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
21044
21171
  };
21045
21172
  assertSafePath(archiveRoot);
21046
21173
  const created = [];
21047
- for (let path = archiveRoot;!existsSync9(path); path = dirname21(path))
21174
+ for (let path = archiveRoot;!existsSync9(path); path = dirname22(path))
21048
21175
  created.push(path);
21049
21176
  mkdirSync8(archiveRoot, { recursive: true, mode: 448 });
21050
21177
  try {
21051
21178
  for (const directory2 of created)
21052
21179
  syncArchiveDirectory(directory2);
21053
21180
  if (created.length)
21054
- syncArchiveDirectory(dirname21(created.at(-1)));
21181
+ syncArchiveDirectory(dirname22(created.at(-1)));
21055
21182
  writeArchiveJournal(receiptPath, journal);
21056
21183
  for (const [index, entry] of selected.entries()) {
21057
21184
  assertCurrent();
@@ -21064,7 +21191,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
21064
21191
  writeArchiveJournal(receiptPath, journal);
21065
21192
  renameSync4(move.source, move.archive);
21066
21193
  moved.push(move);
21067
- syncArchiveDirectory(dirname21(move.source));
21194
+ syncArchiveDirectory(dirname22(move.source));
21068
21195
  syncArchiveDirectory(archiveRoot);
21069
21196
  verifyArchive(move);
21070
21197
  move.status = "archived";
@@ -21087,7 +21214,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
21087
21214
  recheckRootAliases(aliases);
21088
21215
  assertSafePath(entry.source);
21089
21216
  assertSafePath(entry.archive);
21090
- if (lstatSync27(entry.source, { throwIfNoEntry: false })) {
21217
+ if (lstatSync28(entry.source, { throwIfNoEntry: false })) {
21091
21218
  entry.status = "recovery-required";
21092
21219
  entry.conflict = "source-occupied";
21093
21220
  continue;
@@ -21101,10 +21228,10 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
21101
21228
  }
21102
21229
  if (entry.discoveryOnly) {
21103
21230
  linkSync3(entry.archive, entry.source);
21104
- syncArchiveDirectory(dirname21(entry.source));
21231
+ syncArchiveDirectory(dirname22(entry.source));
21105
21232
  unlinkSync5(entry.archive);
21106
21233
  } else {
21107
- if (lstatSync27(entry.source, { throwIfNoEntry: false })) {
21234
+ if (lstatSync28(entry.source, { throwIfNoEntry: false })) {
21108
21235
  entry.status = "recovery-required";
21109
21236
  entry.conflict = "source-occupied";
21110
21237
  continue;
@@ -21112,7 +21239,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
21112
21239
  renameSync4(entry.archive, entry.source);
21113
21240
  }
21114
21241
  entry.status = "restored";
21115
- syncArchiveDirectory(dirname21(entry.source));
21242
+ syncArchiveDirectory(dirname22(entry.source));
21116
21243
  syncArchiveDirectory(archiveRoot);
21117
21244
  } catch {
21118
21245
  entry.status = "recovery-required";
@@ -21135,12 +21262,12 @@ function classifiedCodexPluginCacheCopy(entry, cache, read2, admit) {
21135
21262
  try {
21136
21263
  if (entry.agent !== "codex" || !entry.vendor || entry.bridge || entry.system)
21137
21264
  return false;
21138
- const document2 = join30(entry.path, "SKILL.md");
21265
+ const document2 = join31(entry.path, "SKILL.md");
21139
21266
  const inside = relative9(cache, entry.path);
21140
- if (!inside || isAbsolute24(inside) || inside.split(sep13).some((segment) => segment === ".."))
21267
+ if (!inside || isAbsolute24(inside) || inside.split(sep14).some((segment) => segment === ".."))
21141
21268
  return false;
21142
21269
  assertSafePath(entry.path);
21143
- if (!lstatSync27(cache).isDirectory() || !lstatSync27(entry.path).isDirectory() || !lstatSync27(document2).isFile())
21270
+ if (!lstatSync28(cache).isDirectory() || !lstatSync28(entry.path).isDirectory() || !lstatSync28(document2).isFile())
21144
21271
  return false;
21145
21272
  if (realpathSync12.native(cache) !== cache || realpathSync12.native(entry.path) !== entry.path || realpathSync12.native(document2) !== document2)
21146
21273
  return false;
@@ -21159,7 +21286,7 @@ function isInertCodexPluginCacheCopy(entry, cache, allowedHostPaths, read2) {
21159
21286
  }
21160
21287
  function isInertCodexVendorPluginCopy(entry, cache, rules, read2) {
21161
21288
  try {
21162
- if (entry.managed || lstatSync27(join30(entry.path, ".hasna-skills.json"), { throwIfNoEntry: false }))
21289
+ if (entry.managed || lstatSync28(join31(entry.path, ".hasna-skills.json"), { throwIfNoEntry: false }))
21163
21290
  return false;
21164
21291
  const marketplace = codexVendorMarketplace(cache, entry.path);
21165
21292
  if (!marketplace)
@@ -21177,7 +21304,7 @@ function isInertCodexVendorPluginCopy(entry, cache, rules, read2) {
21177
21304
  try {
21178
21305
  return realpathSync12.native(path);
21179
21306
  } catch {
21180
- return resolve22(path);
21307
+ return resolve23(path);
21181
21308
  }
21182
21309
  };
21183
21310
  const matches = (rule) => typeof rule?.name === "string" && rule.name.trim() === identity5.name || typeof rule?.path === "string" && [document2, entry.path].includes(canonical9(rule.path));
@@ -21197,12 +21324,78 @@ function nativeSkillPathList(paths, invisible = false) {
21197
21324
  const remaining = paths.length - shown.length;
21198
21325
  return `${shown.join(", ")}${remaining ? `; ${remaining} more` : ""}`;
21199
21326
  }
21327
+ function nativeSkillRemediation(agent, blocking, context) {
21328
+ const quote2 = (value) => nativeSkillPathList([value], true);
21329
+ const codex = agent === "codex";
21330
+ const system = blocking.filter((entry) => codex && entry.system === true);
21331
+ const cacheCopies = blocking.filter((entry) => codex && !system.includes(entry) && entry.path.startsWith(context.cache + sep14));
21332
+ const nameRule = (entry) => {
21333
+ if (context.strict || codexVendorMarketplace(context.cache, entry.path) === null)
21334
+ return null;
21335
+ if (context.rules !== undefined && !Array.isArray(context.rules))
21336
+ return null;
21337
+ try {
21338
+ const identity5 = classifyCodexPluginCacheDocument(join31(entry.path, "SKILL.md"), context.cache, context.read);
21339
+ if (!identity5)
21340
+ return null;
21341
+ const rules = [...context.rules ?? [], { name: identity5.name, enabled: false }];
21342
+ return isInertCodexVendorPluginCopy(entry, context.cache, rules, context.read) ? identity5.name : null;
21343
+ } catch {
21344
+ return null;
21345
+ }
21346
+ };
21347
+ const named = cacheCopies.flatMap((entry) => {
21348
+ const name = nameRule(entry);
21349
+ return name ? [{ entry, name }] : [];
21350
+ });
21351
+ const unnamed = cacheCopies.filter((entry) => !named.some((item) => item.entry === entry));
21352
+ const refresh = unnamed.filter((entry) => context.strict || context.toleratedChange || context.enrolled(entry));
21353
+ const byPath = unnamed.filter((entry) => !refresh.includes(entry));
21354
+ const otherVendor = blocking.filter((entry) => entry.vendor && !system.includes(entry) && !cacheCopies.includes(entry));
21355
+ const user = blocking.filter((entry) => !entry.vendor && !system.includes(entry) && !cacheCopies.includes(entry));
21356
+ const install = (catalog) => {
21357
+ const fresh = [...context.automatic ? [] : ["discovery review"], ...catalog ? ["native catalog"] : []];
21358
+ return `skills hook install --agent codex${catalog ? " --codex-native-catalog <reviewed-catalog>" : ""}${context.automatic ? "" : " --discovery-inputs <reviewed-file>"} --apply${fresh.length ? `, with a fresh ${fresh.join(" and ")}` : ""}`;
21359
+ };
21360
+ const followUp = (rows, entries, removesRules = false) => context.automatic || removesRules || !context.keepsConfig(rows) ? ` ${context.automatic ? "This automatic binding" : "The reviewed binding"} records that file, so follow the edit with ${install(entries.some(context.enrolled))}.` : "";
21361
+ const row = (selector) => `[[skills.config]]
21362
+ ${selector}
21363
+ enabled = false
21364
+ `;
21365
+ const steps = [];
21366
+ if (user.length)
21367
+ steps.push(`For user and project copies, review skills migrate native --agent ${agent} --project <working-directory> --include-unmanaged${context.aliases ? " --allow-root-aliases" : ""} --json before continuing; it inventories that directory and its ancestors. Use --apply after reviewing the archive plan.`);
21368
+ if (named.length) {
21369
+ const names = [...new Set(named.map((item) => item.name))];
21370
+ const rows = names.map((name) => row(`name = ${JSON.stringify(name)}`));
21371
+ steps.push(`Codex refreshes OpenAI marketplace copies on its own, so disable each in Codex instead: add [[skills.config]] with name = ${nativeSkillPathList(names, true)}${names.length > 1 ? " (one rule per name)" : ""} and enabled = false to ${quote2(context.config)}. Codex then never loads it and the Codex prompt hook accepts it.${followUp(rows, named.map((item) => item.entry))}`);
21372
+ }
21373
+ if (byPath.length) {
21374
+ const rules = Array.isArray(context.rules) ? context.rules : [];
21375
+ const enabling = rules.some((rule) => rule?.enabled !== false && (typeof rule?.name === "string" || typeof rule?.path === "string" && byPath.some((entry) => [entry.path, join31(entry.path, "SKILL.md")].includes(resolve23(rule.path)))));
21376
+ const rows = byPath.map((entry) => row(`path = ${JSON.stringify(join31(entry.path, "SKILL.md"))}`));
21377
+ steps.push(`For other Codex plugin-cache copies, add [[skills.config]] with the exact path of each SKILL.md and enabled = false to ${quote2(context.config)}, or remove the plugin in Codex.${enabling ? " First remove the [[skills.config]] rules there that enable skills; no path rule counts while one does." : ""}${followUp(rows, byPath, enabling)}`);
21378
+ }
21379
+ if (system.length || refresh.length) {
21380
+ const reasons = [
21381
+ ...system.length ? ["Codex system skills are never archived by skills migrate native"] : [],
21382
+ ...context.strict && refresh.length ? ["this check, unlike the live Codex prompt hook, does not accept a hand-added Codex name rule for a plugin-cache copy"] : [],
21383
+ ...!context.strict && context.toleratedChange && refresh.length ? ["plugin-cache copies keep their exact-path exemption only while the recorded configuration is unchanged"] : [],
21384
+ ...refresh.some(context.enrolled) ? ["only a fresh native catalog review exempts a skill of a plugin Skills has enrolled"] : []
21385
+ ];
21386
+ const sentence = reasons.join("; ");
21387
+ steps.push(`${sentence[0].toUpperCase()}${sentence.slice(1)}, so refresh the binding instead: ${install(refresh.some(context.enrolled))}. It disables and records each copy.`);
21388
+ }
21389
+ if (otherVendor.length)
21390
+ steps.push(`For other vendor copies, review skills migrate native --agent ${agent} --project <working-directory> --include-vendor --discovery-inputs <reviewed-file> --json; --include-vendor requires a reviewed --discovery-inputs file when a configured plugin declares hooks.`);
21391
+ return steps.join(" ");
21392
+ }
21200
21393
  function assertManagedAgentBridge(agent, options = {}) {
21201
21394
  return assertManagedAgentBridgeWithDiscovery(agent, options);
21202
21395
  }
21203
21396
  function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscovery) {
21204
- const home = resolve22(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
21205
- assertSafePath(join30(dataDir2, "agent-policy.json"));
21397
+ const home = resolve23(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
21398
+ assertSafePath(join31(dataDir2, "agent-policy.json"));
21206
21399
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
21207
21400
  if (!snapshot2)
21208
21401
  throw new Error("NATIVE_SKILL_DRIFT: install the Skills bridge with skills hook install");
@@ -21213,11 +21406,11 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
21213
21406
  if (!Array.isArray(aliases))
21214
21407
  throw new Error("NATIVE_SKILL_DRIFT: invalid root alias binding");
21215
21408
  recheckRootAliases(aliases);
21216
- const expected = canonicalAgentPath(join30(nativeAgentRoot(home, agent, options.projectDir ?? process.cwd()), CLI_BRIDGE_NAME), aliases);
21409
+ const expected = canonicalAgentPath(join31(nativeAgentRoot(home, agent, options.projectDir ?? process.cwd()), CLI_BRIDGE_NAME), aliases);
21217
21410
  if (!isOwnedCliBridge(expected, [expected]))
21218
21411
  throw new Error("NATIVE_SKILL_DRIFT: the native Skills bridge is missing or modified; repair it before continuing");
21219
21412
  const roots = projectAncestorDirectories([options.projectDir ?? process.cwd(), ...options.projectDirs ?? [], ...agent === "hermes" && process.env.TERMINAL_CWD ? [process.cwd()] : []]);
21220
- const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes", "sumi"].includes(agent) && entry.path.includes(`${sep13}.agents${sep13}skills${sep13}`) || ["opencode", "sumi"].includes(agent) && entry.agent === "claude";
21413
+ const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes", "sumi"].includes(agent) && entry.path.includes(`${sep14}.agents${sep14}skills${sep14}`) || ["opencode", "sumi"].includes(agent) && entry.agent === "claude";
21221
21414
  const discovery = provenDiscovery ?? binding.discovery?.[agent];
21222
21415
  assertProjectDiscovery(agent, [...roots], home, (path) => canonicalAgentPath(path, aliases), discovery);
21223
21416
  for (const source of discovery?.sources ?? [])
@@ -21234,14 +21427,14 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
21234
21427
  throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
21235
21428
  if (agent === "hermes") {
21236
21429
  const supervisor = binding.supervisors?.hermes;
21237
- if (supervisor?.path !== join30(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha4(renderHermesSupervisor(command, profile)))
21430
+ if (supervisor?.path !== join31(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha4(renderHermesSupervisor(command, profile)))
21238
21431
  throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
21239
21432
  assertHermesProtection(home, config, command, profile, supervisor);
21240
21433
  } else if (agent === "sumi") {
21241
- if (JSON.stringify(config.permissions?.filter((rule) => rule.action === "skill")) !== JSON.stringify(SUMI_SKILL_PERMISSIONS) || !isManagedSumiPlugin(readOptional(join30(sumiConfigDirectory(home, process.env, options.projectDir ?? process.cwd()), "plugins", "skills-cli.js")), command, profile))
21434
+ if (JSON.stringify(config.permissions?.filter((rule) => rule.action === "skill")) !== JSON.stringify(SUMI_SKILL_PERMISSIONS) || !isManagedSumiPlugin(readOptional(join31(sumiConfigDirectory(home, process.env, options.projectDir ?? process.cwd()), "plugins", "skills-cli.js")), command, profile))
21242
21435
  throw new Error("NATIVE_SKILL_DRIFT: Sumi bridge protection changed; run skills hook install");
21243
21436
  } else if (agent === "opencode") {
21244
- if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(join30(home, ".config", "opencode", "plugins", "skills-cli.js")) !== renderOpenCodePlugin(command, profile))
21437
+ if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(join31(home, ".config", "opencode", "plugins", "skills-cli.js")) !== renderOpenCodePlugin(command, profile))
21245
21438
  throw new Error("NATIVE_SKILL_DRIFT: OpenCode bridge protection changed; run skills hook install");
21246
21439
  } else {
21247
21440
  const required = {};
@@ -21258,8 +21451,8 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
21258
21451
  if (agent === "gemini" && (config.hooksConfig?.enabled === false || config.skills?.enabled !== true || !["antigravity-support", "skill-creator"].every((name) => config.skills?.disabled?.includes(name)) || config.skills?.disabled?.includes(CLI_BRIDGE_NAME)))
21259
21452
  throw new Error("NATIVE_SKILL_DRIFT: Gemini bridge or bundled-skill protection changed; run skills hook install");
21260
21453
  }
21261
- const codexPath = canonicalAgentPath(join30(home, ".codex", "config.toml"), aliases);
21262
- const vendorCache = canonicalAgentPath(join30(home, ".codex", "plugins", "cache"), aliases);
21454
+ const codexPath = canonicalAgentPath(join31(home, ".codex", "config.toml"), aliases);
21455
+ const vendorCache = canonicalAgentPath(join31(home, ".codex", "plugins", "cache"), aliases);
21263
21456
  const witnessTolerance = agent === "codex" && options.codexPromptHook === true ? {
21264
21457
  changes: [],
21265
21458
  acceptsInput: (source) => source.path === codexPath && codexVendorConfigChangeOnly(source, vendorCache),
@@ -21270,40 +21463,40 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
21270
21463
  const codexConfig = agent === "codex" ? Bun.TOML.parse(readOptional(codexPath) ?? "") : {};
21271
21464
  if (agent === "codex" && codexConfig.skills?.bundled?.enabled !== false)
21272
21465
  throw new Error("NATIVE_SKILL_DRIFT: Codex bundled skill reseeding is not disabled (skills.bundled.enabled); run skills hook install");
21273
- const setting = (path) => (codexConfig.skills?.config ?? []).filter((entry) => typeof entry.path === "string" && [path, join30(path, "SKILL.md")].includes(canonicalAgentPath(entry.path, aliases)));
21466
+ const setting = (path) => (codexConfig.skills?.config ?? []).filter((entry) => typeof entry.path === "string" && [path, join31(path, "SKILL.md")].includes(canonicalAgentPath(entry.path, aliases)));
21274
21467
  if (agent === "codex" && [...setting(expected), ...(codexConfig.skills?.config ?? []).filter((entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME)].some((entry) => entry.enabled === false))
21275
21468
  throw new Error("NATIVE_SKILL_DRIFT: the Codex CLI bridge is disabled; run skills hook install");
21276
- if (agent === "codex" && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join30(home, ".codex/plugins/cache"), aliases), binding.codexPluginSkills ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)), codexConfig.skills?.config ?? []))
21469
+ if (agent === "codex" && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join31(home, ".codex/plugins/cache"), aliases), binding.codexPluginSkills ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)), codexConfig.skills?.config ?? []))
21277
21470
  throw new Error("NATIVE_SKILL_DRIFT: reviewed native plugin capability controls changed; run skills hook install with a fresh discovery review");
21278
21471
  const disabledPlugin = (entry) => {
21279
21472
  if (agent !== "codex" || !entry.vendor)
21280
21473
  return false;
21281
- const document2 = join30(entry.path, "SKILL.md"), cache = canonicalAgentPath(join30(home, ".codex/plugins/cache"), aliases), read2 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024));
21474
+ const document2 = join31(entry.path, "SKILL.md"), cache = canonicalAgentPath(join31(home, ".codex/plugins/cache"), aliases), read2 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024));
21282
21475
  return isReviewedCodexPluginInactive(document2, cache, binding.codexInactivePlugins ?? [], codexConfig.plugins, codexConfig.skills?.config ?? [], read2) || isReviewedCodexPluginSkillDisabled(document2, cache, binding.codexPluginSkills ?? [], codexConfig.skills?.config, read2);
21283
21476
  };
21284
- const inertVendorCopy = (entry) => agent === "codex" && options.codexPromptHook === true && entry.vendor && entry.path.startsWith(vendorCache + sep13) && isInertCodexVendorPluginCopy(entry, vendorCache, codexConfig.skills?.config, (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
21285
- const vendorOnlyCacheCopy = (entry) => (witnessTolerance?.changes.length ?? 0) > 0 && entry.path.startsWith(vendorCache + sep13);
21477
+ const inertVendorCopy = (entry) => agent === "codex" && options.codexPromptHook === true && entry.vendor && entry.path.startsWith(vendorCache + sep14) && isInertCodexVendorPluginCopy(entry, vendorCache, codexConfig.skills?.config, (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
21478
+ const vendorOnlyCacheCopy = (entry) => (witnessTolerance?.changes.length ?? 0) > 0 && entry.path.startsWith(vendorCache + sep14);
21286
21479
  const disabledPaths = new Set(disabledCodexSkillPaths(codexConfig, aliases));
21287
21480
  const disabledVendorSkill = (entry) => {
21288
21481
  if (agent !== "codex" || !entry.vendor)
21289
21482
  return false;
21290
21483
  if (vendorOnlyCacheCopy(entry))
21291
21484
  return false;
21292
- if ((binding.codexPluginSkills ?? []).some((control) => entry.path.startsWith(control.pluginParent + sep13)))
21485
+ if ((binding.codexPluginSkills ?? []).some((control) => entry.path.startsWith(control.pluginParent + sep14)))
21293
21486
  return disabledPlugin(entry);
21294
21487
  if (disabledPlugin(entry))
21295
21488
  return true;
21296
21489
  if (!disabledPaths.has(entry.path))
21297
21490
  return false;
21298
- if (entry.path.startsWith(canonicalAgentPath(join30(home, ".codex", "plugins", "cache"), aliases) + sep13))
21491
+ if (entry.path.startsWith(canonicalAgentPath(join31(home, ".codex", "plugins", "cache"), aliases) + sep14))
21299
21492
  return true;
21300
- const runtimeCache = canonicalAgentPath(join30(home, ".cache", "codex-runtimes"), aliases);
21301
- if (entry.path.startsWith(runtimeCache + sep13) && discovery?.method === "automatic" && discovery.roots.some((root) => entry.path.startsWith(root + sep13)))
21493
+ const runtimeCache = canonicalAgentPath(join31(home, ".cache", "codex-runtimes"), aliases);
21494
+ if (entry.path.startsWith(runtimeCache + sep14) && discovery?.method === "automatic" && discovery.roots.some((root) => entry.path.startsWith(root + sep14)))
21302
21495
  return true;
21303
- const bundledMarketplaces = canonicalAgentPath(join30(home, ".codex", ".tmp", "bundled-marketplaces"), aliases);
21304
- if (entry.path.startsWith(bundledMarketplaces + sep13) && discovery?.method === "automatic" && discovery.roots.some((root) => entry.path.startsWith(root + sep13)))
21496
+ const bundledMarketplaces = canonicalAgentPath(join31(home, ".codex", ".tmp", "bundled-marketplaces"), aliases);
21497
+ if (entry.path.startsWith(bundledMarketplaces + sep14) && discovery?.method === "automatic" && discovery.roots.some((root) => entry.path.startsWith(root + sep14)))
21305
21498
  return true;
21306
- if (!entry.path.startsWith(canonicalAgentPath(join30(home, ".codex", "skills", ".system"), aliases) + sep13))
21499
+ if (!entry.path.startsWith(canonicalAgentPath(join31(home, ".codex", "skills", ".system"), aliases) + sep14))
21307
21500
  return false;
21308
21501
  return Array.isArray(binding.disabledBuiltins) && binding.disabledBuiltins.some((item) => item.path === entry.path && item.hash === entry.hash);
21309
21502
  };
@@ -21325,7 +21518,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
21325
21518
  let installationInputRoots = [];
21326
21519
  if (agent === "codex") {
21327
21520
  try {
21328
- installationInputRoots = reviewedCodexPluginSourceRoots(canonicalAgentPath(join30(home, ".codex/plugins/cache"), aliases), discovery.codexInstallationInputs?.plugins ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
21521
+ installationInputRoots = reviewedCodexPluginSourceRoots(canonicalAgentPath(join31(home, ".codex/plugins/cache"), aliases), discovery.codexInstallationInputs?.plugins ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
21329
21522
  } catch {
21330
21523
  throw new Error("NATIVE_SKILL_DRIFT: native installation input identity changed; review discovery and catalog");
21331
21524
  }
@@ -21335,7 +21528,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
21335
21528
  let adapterRefusal, inert = [];
21336
21529
  if (agent === "codex" && unexpected.length && options.codexNativePolicy) {
21337
21530
  const { inspector, helperRunner, deadlineMs, ...envelope } = options.codexNativePolicy;
21338
- const cache = canonicalAgentPath(join30(home, ".codex", "plugins", "cache"), aliases), read2 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)), bridgeDocument = join30(expected, "SKILL.md");
21531
+ const cache = canonicalAgentPath(join31(home, ".codex", "plugins", "cache"), aliases), read2 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)), bridgeDocument = join31(expected, "SKILL.md");
21339
21532
  try {
21340
21533
  const claimed = parseCodexNativeHookEnvelope(envelope, bridgeDocument).policy;
21341
21534
  inert = unexpected.filter((entry) => isInertCodexPluginCacheCopy(entry, cache, claimed.allowedHostPaths, read2));
@@ -21354,7 +21547,18 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
21354
21547
  }
21355
21548
  if (unexpected.length > inert.length + inertVendor.length) {
21356
21549
  const blocking = unexpected.filter((entry) => !inertVendor.includes(entry));
21357
- throw new Error(`NATIVE_SKILL_DRIFT: ${blocking.length} unexpected native skill copies were found: ${nativeSkillPathList(blocking.map((entry) => entry.path))}. Review skills migrate native --agent ${agent} --project <working-directory> --include-unmanaged --include-vendor --json before continuing; it inventories that directory and its ancestors. Use --apply after reviewing the archive plan.${adapterRefusal ? ` Native policy adapter refused: ${adapterRefusal}` : ""}`);
21550
+ const remediation = nativeSkillRemediation(agent, blocking, { cache: vendorCache, config: codexPath, aliases: aliases.length > 0, strict: options.codexPromptHook !== true, automatic: discovery.method === "automatic", toleratedChange: (witnessTolerance?.changes.length ?? 0) > 0, rules: codexConfig.skills?.config, enrolled: (entry) => (binding.codexPluginSkills ?? []).some((control) => entry.path.startsWith(control.pluginParent + sep14)), keepsConfig: (rows) => {
21551
+ try {
21552
+ const text2 = readOptional(codexPath) ?? "";
21553
+ return discoveryTextKeepsWitness(discovery, codexPath, `${text2.trimEnd()}${text2.trim() ? `
21554
+
21555
+ ` : ""}${rows.join(`
21556
+ `)}`);
21557
+ } catch {
21558
+ return false;
21559
+ }
21560
+ }, read: (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)) });
21561
+ throw new Error(`NATIVE_SKILL_DRIFT: ${blocking.length} unexpected native skill copies were found: ${nativeSkillPathList(blocking.map((entry) => entry.path))}. ${remediation}${adapterRefusal ? ` Native policy adapter refused: ${adapterRefusal}` : ""}`);
21358
21562
  }
21359
21563
  recheckRootAliases(aliases);
21360
21564
  const discoveryChanges = (witnessTolerance?.changes ?? []).filter((change, index, all) => all.findIndex((other) => other.kind === change.kind && other.path === change.path) === index);
@@ -21378,11 +21582,11 @@ function isSkillsOwnershipMarker(marker) {
21378
21582
  return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
21379
21583
  }
21380
21584
  function hasSkillsOwnershipMarker(dir) {
21381
- const path = join31(dir, SYNC_MARKER_FILE);
21585
+ const path = join32(dir, SYNC_MARKER_FILE);
21382
21586
  try {
21383
- if (!lstatSync28(path).isFile())
21587
+ if (!lstatSync29(path).isFile())
21384
21588
  return false;
21385
- const marker = JSON.parse(readFileSync19(path, "utf8"));
21589
+ const marker = JSON.parse(readFileSync20(path, "utf8"));
21386
21590
  return isSkillsOwnershipMarker(marker);
21387
21591
  } catch {
21388
21592
  return false;
@@ -21402,9 +21606,9 @@ function resolveSyncAgents(arg) {
21402
21606
  function agentGlobalSkillsDir(agent, homeDir2 = homedir3()) {
21403
21607
  switch (agent) {
21404
21608
  case "opencode":
21405
- return join31(homeDir2, ".config", "opencode", "skills");
21609
+ return join32(homeDir2, ".config", "opencode", "skills");
21406
21610
  default:
21407
- return join31(homeDir2, `.${agent}`, "skills");
21611
+ return join32(homeDir2, `.${agent}`, "skills");
21408
21612
  }
21409
21613
  }
21410
21614
  function adaptSkillMdForAgent(skillMd, agent) {
@@ -21463,7 +21667,7 @@ function resolveSyncCorpus(options = {}) {
21463
21667
  function packageSourceRoots(source) {
21464
21668
  const roots = [];
21465
21669
  for (const sub of ["skills"]) {
21466
- const candidate = join31(source, sub);
21670
+ const candidate = join32(source, sub);
21467
21671
  if (existsSync10(candidate) && isDirectory(candidate))
21468
21672
  roots.push(candidate);
21469
21673
  }
@@ -21479,10 +21683,10 @@ function containsSkillDirectories(path) {
21479
21683
  return false;
21480
21684
  }
21481
21685
  return entries.some((entry) => {
21482
- const candidate = join31(path, entry);
21686
+ const candidate = join32(path, entry);
21483
21687
  if (!isDirectory(candidate))
21484
21688
  return false;
21485
- return existsSync10(join31(candidate, "SKILL.md")) || existsSync10(join31(candidate, "skill.json")) || existsSync10(join31(candidate, "package.json"));
21689
+ return existsSync10(join32(candidate, "SKILL.md")) || existsSync10(join32(candidate, "skill.json")) || existsSync10(join32(candidate, "package.json"));
21486
21690
  });
21487
21691
  }
21488
21692
  function isDirectory(path) {
@@ -21522,7 +21726,7 @@ function syncSkillsToAgents(options = {}) {
21522
21726
  actions.push({
21523
21727
  skill: name,
21524
21728
  agent,
21525
- path: join31(agentGlobalSkillsDir(agent, homeDir2), name, "SKILL.md"),
21729
+ path: join32(agentGlobalSkillsDir(agent, homeDir2), name, "SKILL.md"),
21526
21730
  action: "skip",
21527
21731
  reason: "not found in this machine's corpus"
21528
21732
  });
@@ -21554,7 +21758,7 @@ function syncSkillsToAgents(options = {}) {
21554
21758
  }
21555
21759
  function writeManagedAgentSkill(params) {
21556
21760
  const homeDir2 = params.homeDir ?? homedir3();
21557
- const dir = join31(agentGlobalSkillsDir(params.agent, homeDir2), params.skill);
21761
+ const dir = join32(agentGlobalSkillsDir(params.agent, homeDir2), params.skill);
21558
21762
  const result = writeManagedSkillDir(dir, params.skillMd, {
21559
21763
  skill: params.skill,
21560
21764
  source: params.source,
@@ -21577,8 +21781,8 @@ function writeManagedSkillDir(dir, skillMd, options) {
21577
21781
  return withCodexCorpusWrite(root ? [root] : [], (assertCurrent) => writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent), options);
21578
21782
  }
21579
21783
  function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
21580
- const skillMdPath = join31(dir, "SKILL.md");
21581
- const markerPath = join31(dir, SYNC_MARKER_FILE);
21784
+ const skillMdPath = join32(dir, "SKILL.md");
21785
+ const markerPath = join32(dir, SYNC_MARKER_FILE);
21582
21786
  const dirExists = existsSync10(dir);
21583
21787
  const managed = hasSkillsOwnershipMarker(dir);
21584
21788
  const hasSkillMd = existsSync10(skillMdPath);
@@ -21599,7 +21803,7 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
21599
21803
  if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
21600
21804
  let existingIsStub = false;
21601
21805
  try {
21602
- existingIsStub = isPointerSkillMd(readFileSync19(skillMdPath, "utf-8"));
21806
+ existingIsStub = isPointerSkillMd(readFileSync20(skillMdPath, "utf-8"));
21603
21807
  } catch {
21604
21808
  existingIsStub = false;
21605
21809
  }
@@ -21614,13 +21818,13 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
21614
21818
  const action = dirExists ? "update" : "create";
21615
21819
  if (options.dryRun)
21616
21820
  return { action, path: skillMdPath };
21617
- const parentDir = dirname22(dir);
21821
+ const parentDir = dirname23(dir);
21618
21822
  mkdirSync9(parentDir, { recursive: true });
21619
- const transactionDir = mkdtempSync(join31(parentDir, `.hasna-skills-write-${basename12(dir)}-`));
21620
- const candidateDir = join31(transactionDir, "candidate");
21621
- const backupDir = join31(transactionDir, "backup");
21622
- const candidateSkillMdPath = join31(candidateDir, "SKILL.md");
21623
- const candidateMarkerPath = join31(candidateDir, SYNC_MARKER_FILE);
21823
+ const transactionDir = mkdtempSync(join32(parentDir, `.hasna-skills-write-${basename12(dir)}-`));
21824
+ const candidateDir = join32(transactionDir, "candidate");
21825
+ const backupDir = join32(transactionDir, "backup");
21826
+ const candidateSkillMdPath = join32(candidateDir, "SKILL.md");
21827
+ const candidateMarkerPath = join32(candidateDir, SYNC_MARKER_FILE);
21624
21828
  const marker = {
21625
21829
  managedBy: SYNC_MARKER_MANAGED_BY,
21626
21830
  skill: options.skill,
@@ -21649,7 +21853,7 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
21649
21853
  assertCurrent();
21650
21854
  renameDirectory(candidateDir, dir);
21651
21855
  assertCurrent();
21652
- if (readFileSync19(skillMdPath, "utf8") !== (skillMd.endsWith(`
21856
+ if (readFileSync20(skillMdPath, "utf8") !== (skillMd.endsWith(`
21653
21857
  `) ? skillMd : `${skillMd}
21654
21858
  `))
21655
21859
  throw new Error("Managed skill readback failed");
@@ -21678,12 +21882,12 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
21678
21882
  return { action, path: skillMdPath };
21679
21883
  }
21680
21884
  function removeManagedAgentSkill(skill, agent, homeDir2 = homedir3(), options = {}) {
21681
- const dir = join31(agentGlobalSkillsDir(agent, homeDir2), skill);
21885
+ const dir = join32(agentGlobalSkillsDir(agent, homeDir2), skill);
21682
21886
  const root = codexCorpusRootForPath(dir);
21683
21887
  return withCodexCorpusWrite(root ? [root] : [], () => removeManagedAgentSkillUnlocked(skill, agent, homeDir2, options), options);
21684
21888
  }
21685
21889
  function removeManagedAgentSkillUnlocked(skill, agent, homeDir2 = homedir3(), options = {}) {
21686
- const dir = join31(agentGlobalSkillsDir(agent, homeDir2), skill);
21890
+ const dir = join32(agentGlobalSkillsDir(agent, homeDir2), skill);
21687
21891
  if (!hasSkillsOwnershipMarker(dir))
21688
21892
  return false;
21689
21893
  rmSync2(dir, { recursive: true, force: true });
@@ -21691,9 +21895,9 @@ function removeManagedAgentSkillUnlocked(skill, agent, homeDir2 = homedir3(), op
21691
21895
  }
21692
21896
  function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = false) {
21693
21897
  if (kind === undefined || kind === "instruction" || preferBundledDocs) {
21694
- const skillMdPath = join31(skillPath, "SKILL.md");
21898
+ const skillMdPath = join32(skillPath, "SKILL.md");
21695
21899
  if (existsSync10(skillMdPath))
21696
- return readFileSync19(skillMdPath, "utf-8");
21900
+ return readFileSync20(skillMdPath, "utf-8");
21697
21901
  }
21698
21902
  return pointerSkillMd(name, description);
21699
21903
  }
@@ -21733,8 +21937,8 @@ function resolveSkillAlias(name) {
21733
21937
  }
21734
21938
 
21735
21939
  // src/lib/project-state.ts
21736
- import { existsSync as existsSync11, mkdirSync as mkdirSync10, readFileSync as readFileSync20, writeFileSync as writeFileSync8 } from "fs";
21737
- import { join as join32 } from "path";
21940
+ import { existsSync as existsSync11, mkdirSync as mkdirSync10, readFileSync as readFileSync21, writeFileSync as writeFileSync8 } from "fs";
21941
+ import { join as join33 } from "path";
21738
21942
  var VALID_PIN_SOURCES = [
21739
21943
  "official",
21740
21944
  "custom",
@@ -21749,17 +21953,17 @@ var SKILLS_PROJECT_DIR = ".skills";
21749
21953
  var PROJECT_CONFIG_FILE = "project.json";
21750
21954
  var DEFAULT_EXPORT_DIR = ".skills/exports";
21751
21955
  function getProjectStateDir(targetDir = process.cwd()) {
21752
- return join32(targetDir, SKILLS_PROJECT_DIR);
21956
+ return join33(targetDir, SKILLS_PROJECT_DIR);
21753
21957
  }
21754
21958
  function getProjectConfigPath(targetDir = process.cwd()) {
21755
- return join32(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
21959
+ return join33(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
21756
21960
  }
21757
21961
  function loadProjectConfig(targetDir = process.cwd()) {
21758
21962
  const path = getProjectConfigPath(targetDir);
21759
21963
  if (!existsSync11(path))
21760
21964
  return null;
21761
21965
  try {
21762
- return normalizeProjectConfig(JSON.parse(readFileSync20(path, "utf-8")));
21966
+ return normalizeProjectConfig(JSON.parse(readFileSync21(path, "utf-8")));
21763
21967
  } catch {
21764
21968
  return null;
21765
21969
  }
@@ -21881,7 +22085,7 @@ function getSkillPath(name) {
21881
22085
  const extensionPath = findExtensionSkillPath(skillName);
21882
22086
  if (extensionPath)
21883
22087
  return extensionPath;
21884
- return join33(getPortableSkillsRoot(), skillName);
22088
+ return join34(getPortableSkillsRoot(), skillName);
21885
22089
  }
21886
22090
  function getCanonicalSkillName(name) {
21887
22091
  return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
@@ -21944,9 +22148,9 @@ function createLocalSkillManifest(name, generateSkillMd) {
21944
22148
  if (!existsSync12(sourcePath))
21945
22149
  return null;
21946
22150
  let skillMd = "";
21947
- const skillMdPath = join33(sourcePath, "SKILL.md");
22151
+ const skillMdPath = join34(sourcePath, "SKILL.md");
21948
22152
  if (existsSync12(skillMdPath)) {
21949
- skillMd = readFileSync21(skillMdPath, "utf-8");
22153
+ skillMd = readFileSync23(skillMdPath, "utf-8");
21950
22154
  } else if (generateSkillMd) {
21951
22155
  skillMd = generateSkillMd(name) ?? "";
21952
22156
  } else {
@@ -22018,16 +22222,16 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
22018
22222
  const base = projectDir || process.cwd();
22019
22223
  switch (agent) {
22020
22224
  case "pi":
22021
- return scope === "project" ? join33(base, ".pi", "skills") : join33(homedir4(), ".pi", "agent", "skills");
22225
+ return scope === "project" ? join34(base, ".pi", "skills") : join34(homedir4(), ".pi", "agent", "skills");
22022
22226
  case "opencode":
22023
- return scope === "project" ? join33(base, ".opencode", "skills") : join33(homedir4(), ".config", "opencode", "skills");
22227
+ return scope === "project" ? join34(base, ".opencode", "skills") : join34(homedir4(), ".config", "opencode", "skills");
22024
22228
  default:
22025
- return scope === "project" ? join33(base, `.${agent}`, "skills") : join33(homedir4(), `.${agent}`, "skills");
22229
+ return scope === "project" ? join34(base, `.${agent}`, "skills") : join34(homedir4(), `.${agent}`, "skills");
22026
22230
  }
22027
22231
  }
22028
22232
  function getAgentSkillPath(name, agent, scope = "global", projectDir) {
22029
22233
  const skillName = normalizeSkillName(getCanonicalSkillName(name));
22030
- return join33(getAgentSkillsDir(agent, scope, projectDir), skillName);
22234
+ return join34(getAgentSkillsDir(agent, scope, projectDir), skillName);
22031
22235
  }
22032
22236
  function installSkillForAgent(name, options, generateSkillMd) {
22033
22237
  assertNativeExportAllowed();
@@ -22070,9 +22274,9 @@ function removeSkillForAgentUnlocked(name, options) {
22070
22274
  }
22071
22275
  function resolveAgentSkillMd(name, generateSkillMd) {
22072
22276
  const sourcePath = getSkillPath(name);
22073
- const skillMdPath = join33(sourcePath, "SKILL.md");
22277
+ const skillMdPath = join34(sourcePath, "SKILL.md");
22074
22278
  if (existsSync12(skillMdPath))
22075
- return readFileSync21(skillMdPath, "utf-8");
22279
+ return readFileSync23(skillMdPath, "utf-8");
22076
22280
  if (generateSkillMd)
22077
22281
  return generateSkillMd(name);
22078
22282
  return generateMinimalSkillMd(name);
@@ -22105,7 +22309,7 @@ function generateMinimalSkillMd(name) {
22105
22309
  "---",
22106
22310
  ""
22107
22311
  ].filter(Boolean);
22108
- const fallbackDoc = readFileIfExists(join33(sourcePath, "README.md")) || readFileIfExists(join33(sourcePath, "CLAUDE.md"));
22312
+ const fallbackDoc = readFileIfExists(join34(sourcePath, "README.md")) || readFileIfExists(join34(sourcePath, "CLAUDE.md"));
22109
22313
  if (fallbackDoc)
22110
22314
  return `${frontmatter.join(`
22111
22315
  `)}${fallbackDoc.trim()}
@@ -22124,18 +22328,18 @@ skills run ${canonicalName}
22124
22328
  `;
22125
22329
  }
22126
22330
  function readBundledSkillVersion(name) {
22127
- const pkgPath = join33(getSkillPath(name), "package.json");
22331
+ const pkgPath = join34(getSkillPath(name), "package.json");
22128
22332
  if (!existsSync12(pkgPath))
22129
22333
  return "unknown";
22130
22334
  try {
22131
- const pkg = JSON.parse(readFileSync21(pkgPath, "utf-8"));
22335
+ const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
22132
22336
  return pkg.version || "unknown";
22133
22337
  } catch {
22134
22338
  return "unknown";
22135
22339
  }
22136
22340
  }
22137
22341
  function readFileIfExists(path) {
22138
- return existsSync12(path) ? readFileSync21(path, "utf-8") : null;
22342
+ return existsSync12(path) ? readFileSync23(path, "utf-8") : null;
22139
22343
  }
22140
22344
  function loadProjectConfigCompat(targetDir) {
22141
22345
  return loadProjectConfig(targetDir);
@@ -22179,11 +22383,11 @@ function selectSkillDoc(docs, file) {
22179
22383
  function isInstructionSkillDir(skillPath, meta) {
22180
22384
  if (meta?.kind === "instruction")
22181
22385
  return true;
22182
- const skillMdPath = join34(skillPath, "SKILL.md");
22386
+ const skillMdPath = join35(skillPath, "SKILL.md");
22183
22387
  if (!existsSync13(skillMdPath))
22184
22388
  return false;
22185
22389
  try {
22186
- return parseSkillFrontmatter(readFileSync23(skillMdPath, "utf-8"))?.kind === "instruction";
22390
+ return parseSkillFrontmatter(readFileSync25(skillMdPath, "utf-8"))?.kind === "instruction";
22187
22391
  } catch {
22188
22392
  return false;
22189
22393
  }
@@ -22209,9 +22413,9 @@ function getSkillDocs(name) {
22209
22413
  if (!existsSync13(skillPath))
22210
22414
  return null;
22211
22415
  return {
22212
- skillMd: readIfExists(join34(skillPath, "SKILL.md")),
22213
- readme: readIfExists(join34(skillPath, "README.md")),
22214
- claudeMd: readIfExists(join34(skillPath, "CLAUDE.md"))
22416
+ skillMd: readIfExists(join35(skillPath, "SKILL.md")),
22417
+ readme: readIfExists(join35(skillPath, "README.md")),
22418
+ claudeMd: readIfExists(join35(skillPath, "CLAUDE.md"))
22215
22419
  };
22216
22420
  }
22217
22421
  function getSkillBestDoc(name, file) {
@@ -22227,14 +22431,14 @@ function getSkillRequirements(name) {
22227
22431
  return null;
22228
22432
  const texts = [];
22229
22433
  for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
22230
- const content = readIfExists(join34(skillPath, file));
22434
+ const content = readIfExists(join35(skillPath, file));
22231
22435
  if (content)
22232
22436
  texts.push(content);
22233
22437
  }
22234
22438
  const meta = getSkill(name);
22235
22439
  let dependencies = {};
22236
22440
  try {
22237
- dependencies = JSON.parse(readFileSync23(join34(skillPath, "package.json"), "utf8")).dependencies || {};
22441
+ dependencies = JSON.parse(readFileSync25(join35(skillPath, "package.json"), "utf8")).dependencies || {};
22238
22442
  } catch {}
22239
22443
  return getSkillRequirementsFromContent(name, texts, dependencies, meta);
22240
22444
  }
@@ -22296,13 +22500,13 @@ async function runSkill(name, args, options = {}) {
22296
22500
  error: `Skill '${name}' is an instruction skill (kind: instruction) and is not runnable. Instruction skills are consumed by coding agents via SKILL.md, not executed with 'skills run'.`
22297
22501
  };
22298
22502
  }
22299
- const pkgPath = join34(skillPath, "package.json");
22503
+ const pkgPath = join35(skillPath, "package.json");
22300
22504
  if (!existsSync13(pkgPath)) {
22301
22505
  return { exitCode: 1, error: `No package.json in skill '${name}'` };
22302
22506
  }
22303
22507
  let entryPoint2;
22304
22508
  try {
22305
- const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
22509
+ const pkg = JSON.parse(readFileSync25(pkgPath, "utf-8"));
22306
22510
  if (pkg.bin) {
22307
22511
  const binValues = Object.values(pkg.bin);
22308
22512
  entryPoint2 = binValues[0];
@@ -22316,12 +22520,12 @@ async function runSkill(name, args, options = {}) {
22316
22520
  } catch {
22317
22521
  return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
22318
22522
  }
22319
- const entryPath = join34(skillPath, entryPoint2);
22523
+ const entryPath = join35(skillPath, entryPoint2);
22320
22524
  if (!existsSync13(entryPath)) {
22321
22525
  return { exitCode: 1, error: `Entry point '${entryPoint2}' not found in skill '${name}'` };
22322
22526
  }
22323
22527
  const env = { ...process.env, ...options.env };
22324
- if (!existsSync13(join34(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
22528
+ if (!existsSync13(join35(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
22325
22529
  const failure = await prepareSkillDependencies(skillPath, env, options.preparationTimeoutMs);
22326
22530
  if (failure)
22327
22531
  return failure;
@@ -22399,13 +22603,13 @@ function generateSkillMd(name) {
22399
22603
  "---"
22400
22604
  ].join(`
22401
22605
  `);
22402
- const readme = readIfExists(join34(skillPath, "README.md"));
22403
- const claudeMd = readIfExists(join34(skillPath, "CLAUDE.md"));
22606
+ const readme = readIfExists(join35(skillPath, "README.md"));
22607
+ const claudeMd = readIfExists(join35(skillPath, "CLAUDE.md"));
22404
22608
  let cliCommand = null;
22405
- const pkgPath = join34(skillPath, "package.json");
22609
+ const pkgPath = join35(skillPath, "package.json");
22406
22610
  if (existsSync13(pkgPath)) {
22407
22611
  try {
22408
- const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
22612
+ const pkg = JSON.parse(readFileSync25(pkgPath, "utf-8"));
22409
22613
  if (pkg.bin) {
22410
22614
  const binKeys = Object.keys(pkg.bin);
22411
22615
  if (binKeys.length > 0)
@@ -22479,7 +22683,7 @@ function extractEnvVars(text2) {
22479
22683
  function readIfExists(path) {
22480
22684
  try {
22481
22685
  if (existsSync13(path)) {
22482
- return readFileSync23(path, "utf-8");
22686
+ return readFileSync25(path, "utf-8");
22483
22687
  }
22484
22688
  } catch {}
22485
22689
  return null;
@@ -22631,7 +22835,7 @@ function describeEntries(entries) {
22631
22835
 
22632
22836
  // src/lib/plugin-admission.ts
22633
22837
  function pluginAdmissionRoot() {
22634
- return join35(homedir5(), ".hasna", "skills", "plugin-admission");
22838
+ return join36(homedir5(), ".hasna", "skills", "plugin-admission");
22635
22839
  }
22636
22840
  function validatePluginTarget(value) {
22637
22841
  pluginKeys(value, ["schemaVersion", "pluginId", "registrations", "native", "resolver"]);
@@ -22642,7 +22846,7 @@ function validatePluginTarget(value) {
22642
22846
  for (const registration of value.registrations) {
22643
22847
  pluginKeys(registration, ["scope", "projectPath"]);
22644
22848
  pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
22645
- pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute25(registration.projectPath) && resolve23(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
22849
+ pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute25(registration.projectPath) && resolve24(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
22646
22850
  const key2 = JSON.stringify([registration.scope, registration.projectPath]);
22647
22851
  pluginNeed(!scopes.has(key2), "Duplicate plugin registration scope");
22648
22852
  scopes.add(key2);
@@ -22650,7 +22854,7 @@ function validatePluginTarget(value) {
22650
22854
  for (const key2 of ["native", "resolver"]) {
22651
22855
  pluginKeys(value[key2], key2 === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
22652
22856
  pluginText(value[key2].executable);
22653
- pluginNeed(isAbsolute25(value[key2].executable) && resolve23(value[key2].executable) === value[key2].executable, "Plugin executable must have a canonical absolute path");
22857
+ pluginNeed(isAbsolute25(value[key2].executable) && resolve24(value[key2].executable) === value[key2].executable, "Plugin executable must have a canonical absolute path");
22654
22858
  pluginDigest(value[key2].digest);
22655
22859
  }
22656
22860
  pluginNeed(["2.1.274", "2.1.276"].includes(value.native.version), "Plugin admission requires a certified Claude command-source runtime (2.1.274 or 2.1.276)");
@@ -22802,17 +23006,17 @@ function pluginResolverCommand(binding) {
22802
23006
  }
22803
23007
  function root(options) {
22804
23008
  const path = options.storeRoot ?? pluginAdmissionRoot();
22805
- pluginNeed(isAbsolute25(path) && resolve23(path) === path, "Invalid plugin admission store root");
23009
+ pluginNeed(isAbsolute25(path) && resolve24(path) === path, "Invalid plugin admission store root");
22806
23010
  return path;
22807
23011
  }
22808
23012
  function pluginBindingPath(storeRoot, id) {
22809
23013
  pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
22810
- return join35(storeRoot, "bindings", `${id}.json`);
23014
+ return join36(storeRoot, "bindings", `${id}.json`);
22811
23015
  }
22812
23016
  function pluginReceiptPath(storeRoot, id, digest2) {
22813
23017
  pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
22814
23018
  pluginDigest(digest2);
22815
- return join35(storeRoot, "receipts", id, `${digest2.slice(7)}.json`);
23019
+ return join36(storeRoot, "receipts", id, `${digest2.slice(7)}.json`);
22816
23020
  }
22817
23021
  function readPluginBinding(storeRoot, id) {
22818
23022
  const value = readPluginJson(pluginBindingPath(storeRoot, id));
@@ -22832,7 +23036,7 @@ function readPluginAdmissionReceipt(storeRoot, id, digest2) {
22832
23036
  pluginNeed(receipt.plan.bindingId === id && receipt.plan.planDigest === digest2, "Plugin receipt identity differs from its filename");
22833
23037
  const binding = readPluginBinding(storeRoot, id);
22834
23038
  pluginNeed(canonicalJson(binding) === canonicalJson(receipt.plan.binding) && receipt.plan.sourceCommand === pluginResolverCommand(binding), "Plugin receipt binding changed");
22835
- pluginNeed(receipt.materializedPath === join35(storeRoot, "objects", id, digest2.slice(7)), "Plugin receipt points outside its immutable materialization");
23039
+ pluginNeed(receipt.materializedPath === join36(storeRoot, "objects", id, digest2.slice(7)), "Plugin receipt points outside its immutable materialization");
22836
23040
  pluginText(receipt.admittedAt, 64);
22837
23041
  pluginNeed(Number.isFinite(Date.parse(receipt.admittedAt)), "Invalid plugin admission time");
22838
23042
  return receipt;
@@ -22973,7 +23177,7 @@ async function admitPlugin(spec, profileId, target, approvedDigest, approvedEvid
22973
23177
  const { plan, projection } = await candidate(spec, profileId, target, options);
22974
23178
  pluginNeed(plan.planDigest === approvedDigest, "The plugin plan changed since review; obtain and review a new plan");
22975
23179
  pluginNeed(plan.evidenceDigest === approvedEvidenceDigest, "The plugin routing evidence changed since review; obtain and review a new plan");
22976
- const store = root(options), materializedPath = join35(store, "objects", plan.bindingId, plan.planDigest.slice(7));
23180
+ const store = root(options), materializedPath = join36(store, "objects", plan.bindingId, plan.planDigest.slice(7));
22977
23181
  materializePluginTree(materializedPath, projection.files);
22978
23182
  writePluginJsonImmutable(pluginBindingPath(store, plan.bindingId), plan.binding);
22979
23183
  const path = pluginReceiptPath(store, plan.bindingId, plan.planDigest), existing = readPluginJson(path);
@@ -23007,21 +23211,21 @@ function validateManagedPluginWitnesses(value) {
23007
23211
  pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
23008
23212
  seen.add(item.bindingId);
23009
23213
  pluginText(item.storeRoot);
23010
- pluginNeed(isAbsolute26(item.storeRoot) && resolve24(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
23214
+ pluginNeed(isAbsolute26(item.storeRoot) && resolve25(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
23011
23215
  }
23012
23216
  }
23013
23217
  function safe5(path) {
23014
23218
  pluginText(path);
23015
- pluginNeed(isAbsolute26(path) && resolve24(path) === path, "Invalid plugin registry path");
23016
- for (let at = path;; at = dirname23(at)) {
23017
- pluginNeed(!lstatSync29(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
23018
- if (at === dirname23(at))
23219
+ pluginNeed(isAbsolute26(path) && resolve25(path) === path, "Invalid plugin registry path");
23220
+ for (let at = path;; at = dirname24(at)) {
23221
+ pluginNeed(!lstatSync30(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
23222
+ if (at === dirname24(at))
23019
23223
  break;
23020
23224
  }
23021
23225
  }
23022
23226
  function readRegistry(path) {
23023
23227
  safe5(path);
23024
- const initial = lstatSync29(path);
23228
+ const initial = lstatSync30(path);
23025
23229
  pluginNeed(initial.isFile() && initial.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
23026
23230
  const fd = openSync18(path, constants19.O_RDONLY | constants19.O_NOFOLLOW | constants19.O_NONBLOCK);
23027
23231
  try {
@@ -23035,7 +23239,7 @@ function readRegistry(path) {
23035
23239
  break;
23036
23240
  length += count;
23037
23241
  }
23038
- const after = fstatSync18(fd), current = lstatSync29(path);
23242
+ const after = fstatSync18(fd), current = lstatSync30(path);
23039
23243
  safe5(path);
23040
23244
  pluginNeed(length <= 1024 * 1024 && length === opened.size && after.size === opened.size && after.mtimeMs === opened.mtimeMs && after.ctimeMs === opened.ctimeMs && current.dev === opened.dev && current.ino === opened.ino && current.mtimeMs === opened.mtimeMs && current.ctimeMs === opened.ctimeMs, "Plugin registry changed during read");
23041
23245
  let value;
@@ -23065,7 +23269,7 @@ function hashManagedPluginRegistry(path, managed) {
23065
23269
  seen.add(target.pluginId);
23066
23270
  const rows = plugins[target.pluginId];
23067
23271
  pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
23068
- const [name, market] = target.pluginId.split("@"), cacheRoot = join36(dirname23(path), "cache", market, name);
23272
+ const [name, market] = target.pluginId.split("@"), cacheRoot = join37(dirname24(path), "cache", market, name);
23069
23273
  const scopes = new Set, approvals = new Map, currentFiles = new Map;
23070
23274
  plugins[target.pluginId] = rows.map((row) => {
23071
23275
  pluginNeed(pluginObject(row), "Invalid managed plugin registration");
@@ -23078,7 +23282,7 @@ function hashManagedPluginRegistry(path, managed) {
23078
23282
  pluginText(row.sourceProducerPath);
23079
23283
  pluginText(row.lastUpdated, 64);
23080
23284
  pluginNeed(Number.isFinite(Date.parse(row.lastUpdated)), "Invalid managed plugin update timestamp");
23081
- pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join36(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
23285
+ pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join37(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
23082
23286
  const approval = (producer) => {
23083
23287
  pluginText(producer);
23084
23288
  const digest2 = `sha256:${basename13(producer)}`;
@@ -23108,7 +23312,7 @@ function hashManagedPluginRegistry(path, managed) {
23108
23312
  return Object.fromEntries(Object.entries(row).filter(([key2]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key2)));
23109
23313
  });
23110
23314
  safe5(cacheRoot);
23111
- const before = lstatSync29(cacheRoot);
23315
+ const before = lstatSync30(cacheRoot);
23112
23316
  pluginNeed(before.isDirectory(), "Invalid managed plugin cache root");
23113
23317
  const directory2 = opendirSync5(cacheRoot), names = [];
23114
23318
  try {
@@ -23121,17 +23325,17 @@ function hashManagedPluginRegistry(path, managed) {
23121
23325
  directory2.closeSync();
23122
23326
  }
23123
23327
  for (const version2 of names.sort()) {
23124
- const files = pluginFileWitnesses(snapshotPluginTree(join36(cacheRoot, version2), { nativeRuntime: `claude-${target.native.version}` }));
23328
+ const files = pluginFileWitnesses(snapshotPluginTree(join37(cacheRoot, version2), { nativeRuntime: `claude-${target.native.version}` }));
23125
23329
  verifiedBytes += files.reduce((total, file) => total + file.size, 0);
23126
23330
  pluginNeed(verifiedBytes <= 256 * 1024 * 1024, "Managed plugin verification exceeds its aggregate byte budget");
23127
23331
  const serialized = JSON.stringify(files);
23128
- const expected = currentFiles.get(join36(cacheRoot, version2));
23332
+ const expected = currentFiles.get(join37(cacheRoot, version2));
23129
23333
  pluginNeed(expected === undefined || serialized === expected, "Current native cache differs from its exact registered producer receipt");
23130
23334
  pluginNeed([...approvals.values()].some((receipt) => nativeVersionMatches(version2, receipt) && JSON.stringify(receipt.plan.files) === serialized), "A retained native plugin cache version differs from every approved projection");
23131
23335
  }
23132
23336
  for (const row of rows)
23133
23337
  pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
23134
- const after = lstatSync29(cacheRoot);
23338
+ const after = lstatSync30(cacheRoot);
23135
23339
  safe5(cacheRoot);
23136
23340
  pluginNeed(before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs, "Managed cache version membership changed during verification");
23137
23341
  }
@@ -23144,24 +23348,24 @@ function captureManagedPluginRegistry(path, managedPlugins) {
23144
23348
 
23145
23349
  // src/lib/claude-marketplace-registry.ts
23146
23350
  import { createHash as createHash28 } from "crypto";
23147
- import { closeSync as closeSync19, constants as constants20, fstatSync as fstatSync19, lstatSync as lstatSync30, openSync as openSync19, readSync as readSync14 } from "fs";
23148
- import { basename as basename14, dirname as dirname24, isAbsolute as isAbsolute27, resolve as resolve25 } from "path";
23351
+ import { closeSync as closeSync19, constants as constants20, fstatSync as fstatSync19, lstatSync as lstatSync31, openSync as openSync19, readSync as readSync14 } from "fs";
23352
+ import { basename as basename14, dirname as dirname25, isAbsolute as isAbsolute27, resolve as resolve26 } from "path";
23149
23353
  var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
23150
23354
  function need10(value, reason2) {
23151
23355
  if (!value)
23152
23356
  throw new Error(`Claude marketplace registry ${reason2}`);
23153
23357
  }
23154
23358
  function absolutePath4(value) {
23155
- need10(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute27(value) && resolve25(value) === value, "requires a normalized absolute path");
23359
+ need10(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute27(value) && resolve26(value) === value, "requires a normalized absolute path");
23156
23360
  }
23157
23361
  var sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs;
23158
23362
  function parents2(path) {
23159
23363
  const result = [];
23160
- for (let at = dirname24(path);; at = dirname24(at)) {
23161
- const stat2 = lstatSync30(at, { bigint: true });
23364
+ for (let at = dirname25(path);; at = dirname25(at)) {
23365
+ const stat2 = lstatSync31(at, { bigint: true });
23162
23366
  need10(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
23163
23367
  result.push([at, stat2]);
23164
- if (at === dirname24(at))
23368
+ if (at === dirname25(at))
23165
23369
  return result;
23166
23370
  }
23167
23371
  }
@@ -23169,7 +23373,7 @@ function readRegistry2(path, budget2) {
23169
23373
  absolutePath4(path);
23170
23374
  need10(basename14(path) === "known_marketplaces.json", "requires known_marketplaces.json");
23171
23375
  need10(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
23172
- const ancestors2 = parents2(path), initial = lstatSync30(path, { bigint: true });
23376
+ const ancestors2 = parents2(path), initial = lstatSync31(path, { bigint: true });
23173
23377
  need10(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
23174
23378
  need10(initial.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
23175
23379
  const fd = openSync19(path, constants20.O_RDONLY | constants20.O_NOFOLLOW | constants20.O_NONBLOCK);
@@ -23184,10 +23388,10 @@ function readRegistry2(path, budget2) {
23184
23388
  break;
23185
23389
  length += count;
23186
23390
  }
23187
- const after = fstatSync19(fd, { bigint: true }), current = lstatSync30(path, { bigint: true });
23391
+ const after = fstatSync19(fd, { bigint: true }), current = lstatSync31(path, { bigint: true });
23188
23392
  need10(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
23189
23393
  for (const [ancestor, before] of ancestors2) {
23190
- const now = lstatSync30(ancestor, { bigint: true });
23394
+ const now = lstatSync31(ancestor, { bigint: true });
23191
23395
  need10(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
23192
23396
  }
23193
23397
  budget2.remaining -= length;
@@ -23380,7 +23584,7 @@ function discoveryExecutable(agent) {
23380
23584
  const found = command ? Bun.which(command) : null;
23381
23585
  if (!command || !found)
23382
23586
  return null;
23383
- const path = resolve26(found), target = realpathOrNull(path);
23587
+ const path = resolve27(found), target = realpathOrNull(path);
23384
23588
  return target === null ? null : { command, path, target };
23385
23589
  }
23386
23590
  function recordedDiscoveryExecutable(agent, recorded) {
@@ -23404,10 +23608,10 @@ function parseConfig(text2, path, toml = false) {
23404
23608
  function safe6(path) {
23405
23609
  if (!isAbsolute28(path) || path.includes("\x00"))
23406
23610
  throw new Error("Expected an absolute native discovery path");
23407
- for (let cursor = path;; cursor = dirname25(cursor)) {
23408
- if (lstatSync31(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
23611
+ for (let cursor = path;; cursor = dirname26(cursor)) {
23612
+ if (lstatSync32(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
23409
23613
  throw new Error(`Refusing symlink native discovery input: ${cursor}`);
23410
- if (dirname25(cursor) === cursor)
23614
+ if (dirname26(cursor) === cursor)
23411
23615
  break;
23412
23616
  }
23413
23617
  }
@@ -23415,19 +23619,19 @@ function read2(path, changes) {
23415
23619
  safe6(path);
23416
23620
  if (changes?.has(path))
23417
23621
  return changes.get(path);
23418
- const stat2 = lstatSync31(path, { throwIfNoEntry: false });
23622
+ const stat2 = lstatSync32(path, { throwIfNoEntry: false });
23419
23623
  if (!stat2)
23420
23624
  return null;
23421
23625
  if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
23422
23626
  throw new Error(`Unsupported or oversized native discovery input: ${path}`);
23423
- return readFileSync25(path, "utf8");
23627
+ return readFileSync26(path, "utf8");
23424
23628
  }
23425
23629
  function assertReviewedClaudeCacheClosures(home, config, review, canonical9) {
23426
23630
  const enabledIds = Object.entries(config.enabledPlugins ?? {}).filter(([, enabled]) => enabled === true).map(([id]) => id);
23427
23631
  if (enabledIds.length === 0)
23428
23632
  return;
23429
- const registryPath = canonical9(join37(home, ".claude/plugins/installed_plugins.json"));
23430
- const cacheAliasRoot = join37(home, ".claude/plugins/cache");
23633
+ const registryPath = canonical9(join38(home, ".claude/plugins/installed_plugins.json"));
23634
+ const cacheAliasRoot = join38(home, ".claude/plugins/cache");
23431
23635
  const cacheRoot = canonical9(cacheAliasRoot);
23432
23636
  const registryText = read2(registryPath);
23433
23637
  if (registryText === null)
@@ -23435,7 +23639,7 @@ function assertReviewedClaudeCacheClosures(home, config, review, canonical9) {
23435
23639
  const registry = parseConfig(registryText, registryPath);
23436
23640
  if (registry.version !== 2 || !registry.plugins || typeof registry.plugins !== "object" || Array.isArray(registry.plugins))
23437
23641
  throw new Error("Reviewed Claude installed plugin registrations are invalid");
23438
- const cachePath = (path) => typeof path === "string" && isAbsolute28(path) && resolve26(path) === path && [cacheAliasRoot, cacheRoot].some((root2) => path === root2 || path.startsWith(root2 + sep14));
23642
+ const cachePath = (path) => typeof path === "string" && isAbsolute28(path) && resolve27(path) === path && [cacheAliasRoot, cacheRoot].some((root2) => path === root2 || path.startsWith(root2 + sep15));
23439
23643
  const activeRoots = new Set;
23440
23644
  for (const id of enabledIds) {
23441
23645
  const rows = registry.plugins[id];
@@ -23447,11 +23651,11 @@ function assertReviewedClaudeCacheClosures(home, config, review, canonical9) {
23447
23651
  if (!row || typeof row !== "object" || Array.isArray(row) || typeof row.installPath !== "string") {
23448
23652
  throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
23449
23653
  }
23450
- if ([cacheAliasRoot, cacheRoot].some((root2) => row.installPath === root2 || row.installPath.startsWith(root2 + sep14))) {
23654
+ if ([cacheAliasRoot, cacheRoot].some((root2) => row.installPath === root2 || row.installPath.startsWith(root2 + sep15))) {
23451
23655
  if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename15(row.installPath) !== row.version)) {
23452
23656
  throw new Error("Reviewed Claude discovery has a malformed active cache registration");
23453
23657
  }
23454
- if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" && isAbsolute28(row.projectPath) && resolve26(row.projectPath) === row.projectPath && row.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters) {} else
23658
+ if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" && isAbsolute28(row.projectPath) && resolve27(row.projectPath) === row.projectPath && row.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters) {} else
23455
23659
  throw new Error("Reviewed Claude discovery has an unsupported active cache registration scope");
23456
23660
  activeRoots.add(canonical9(row.installPath));
23457
23661
  }
@@ -23469,11 +23673,11 @@ function assertReviewedClaudeCacheClosures(home, config, review, canonical9) {
23469
23673
  };
23470
23674
  for (const root2 of activeRoots) {
23471
23675
  safe6(root2);
23472
- const rootStat = lstatSync31(root2, { throwIfNoEntry: false });
23676
+ const rootStat = lstatSync32(root2, { throwIfNoEntry: false });
23473
23677
  if (!rootStat?.isDirectory() || realpathSync13(root2) !== root2)
23474
23678
  throw new Error("Reviewed Claude active cache plugin root is missing or unsafe");
23475
- const manifestPath = join37(root2, ".claude-plugin/plugin.json");
23476
- const manifestStat = lstatSync31(manifestPath, { throwIfNoEntry: false });
23679
+ const manifestPath = join38(root2, ".claude-plugin/plugin.json");
23680
+ const manifestStat = lstatSync32(manifestPath, { throwIfNoEntry: false });
23477
23681
  let manifest;
23478
23682
  if (manifestStat) {
23479
23683
  if (!manifestStat.isFile())
@@ -23488,30 +23692,30 @@ function assertReviewedClaudeCacheClosures(home, config, review, canonical9) {
23488
23692
  } else if (!review.sources.some((source) => source.path === manifestPath && source.hashMode === "path-bytes" && source.sha256 !== null && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined)) {
23489
23693
  throw new Error("Reviewed Claude active cache plugin manifest absence requires a path-bytes witness");
23490
23694
  }
23491
- const roots = new Set([join37(root2, "skills")]);
23492
- if (lstatSync31(join37(root2, "SKILL.md"), { throwIfNoEntry: false })?.isFile())
23695
+ const roots = new Set([join38(root2, "skills")]);
23696
+ if (lstatSync32(join38(root2, "SKILL.md"), { throwIfNoEntry: false })?.isFile())
23493
23697
  roots.add(root2);
23494
23698
  const declared = manifest?.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
23495
23699
  if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
23496
23700
  throw new Error("Reviewed Claude active cache plugin has unsupported skill paths");
23497
23701
  for (const value of declared) {
23498
- const path = resolve26(root2, value);
23499
- if (path !== root2 && !path.startsWith(root2 + sep14))
23702
+ const path = resolve27(root2, value);
23703
+ if (path !== root2 && !path.startsWith(root2 + sep15))
23500
23704
  throw new Error("Reviewed Claude active cache plugin skill path escapes its root");
23501
- roots.add(path.endsWith(`${sep14}SKILL.md`) ? dirname25(path) : path);
23705
+ roots.add(path.endsWith(`${sep15}SKILL.md`) ? dirname26(path) : path);
23502
23706
  }
23503
23707
  for (const skillRoot of roots)
23504
23708
  if (!review.roots.includes(skillRoot))
23505
23709
  throw new Error("Reviewed Claude active cache plugin skill root is not covered");
23506
- const hooksPath = join37(root2, "hooks/hooks.json");
23507
- const hooksStat = lstatSync31(hooksPath, { throwIfNoEntry: false });
23710
+ const hooksPath = join38(root2, "hooks/hooks.json");
23711
+ const hooksStat = lstatSync32(hooksPath, { throwIfNoEntry: false });
23508
23712
  if (hooksStat) {
23509
23713
  if (!hooksStat.isFile())
23510
23714
  throw new Error("Reviewed Claude plugin hook manifest is unsupported");
23511
23715
  requireSource(hooksPath, "hook manifest");
23512
23716
  }
23513
23717
  if (typeof manifest?.hooks === "string")
23514
- requireSource(resolve26(root2, manifest.hooks), "manifest-declared hook source");
23718
+ requireSource(resolve27(root2, manifest.hooks), "manifest-declared hook source");
23515
23719
  }
23516
23720
  }
23517
23721
  function projectNativeDiscoveryFields(text2, format, fields2, path) {
@@ -23564,10 +23768,9 @@ function projected(source, changes, budget2 = discoveryByteBudget()) {
23564
23768
  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")) {
23565
23769
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
23566
23770
  throw new Error("Codex settings witnesses require exact typed metadata");
23567
- const current = (source.hashMode === "codex-settings-v5" ? captureCodexSettingsV5 : source.hashMode === "codex-settings-v4" ? captureCodexSettingsV4 : source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget2).sha256;
23568
- if (current !== source.sha256)
23771
+ if (codexSettingsWitnessMatch(source.path, source.hashMode, source.sha256, budget2) === null)
23569
23772
  throw new NativeDiscoveryWitnessChange("input", source.path, `Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
23570
- return changes?.has(source.path) ? (source.hashMode === "codex-settings-v5" ? hashCodexSettingsReplacementV5 : source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget2) : current;
23773
+ return changes?.has(source.path) ? (source.hashMode === "codex-settings-v5" ? hashCodexSettingsReplacementV5 : source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget2) : source.sha256;
23571
23774
  }
23572
23775
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) {
23573
23776
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
@@ -23643,18 +23846,18 @@ function absentCodexSkillRoots(binding, tolerance) {
23643
23846
  return [];
23644
23847
  if (binding.agent !== "codex" || !Array.isArray(controls) || controls.length > 4096)
23645
23848
  throw new Error("Invalid disabled Codex discovery proof");
23646
- if (binding.method !== "reviewed" || controls.every((control) => lstatSync31(control.pluginParent, { throwIfNoEntry: false })))
23849
+ if (binding.method !== "reviewed" || controls.every((control) => lstatSync32(control.pluginParent, { throwIfNoEntry: false })))
23647
23850
  return [];
23648
- const cache = dirname25(dirname25(controls[0].pluginParent)), config = join37(dirname25(dirname25(cache)), "config.toml");
23851
+ const cache = dirname26(dirname26(controls[0].pluginParent)), config = join38(dirname26(dirname26(cache)), "config.toml");
23649
23852
  const source = binding.sources.find((source2) => source2.path === config && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
23650
23853
  if (!source || !codexConfigWitnessCurrent(source, tolerance))
23651
23854
  throw new Error("Missing current disabled Codex configuration witness");
23652
23855
  const rules = Bun.TOML.parse(read2(config)).skills?.config ?? [];
23653
23856
  return [...new Set(controls.map((control) => control.pluginParent))].filter((parent) => !codexDirectHookSelects(cache, parent) && absentDisabledCodexPluginParent(cache, parent, controls, rules));
23654
23857
  }
23655
- function codexDirectHookSelects(cache, root2, configPath = join37(dirname25(dirname25(cache)), "config.toml")) {
23656
- const codex = dirname25(configPath), config = Bun.TOML.parse(read2(configPath) ?? "");
23657
- const hooks = read2(join37(codex, "hooks.json"));
23858
+ function codexDirectHookSelects(cache, root2, configPath = join38(dirname26(dirname26(cache)), "config.toml")) {
23859
+ const codex = dirname26(configPath), config = Bun.TOML.parse(read2(configPath) ?? "");
23860
+ const hooks = read2(join38(codex, "hooks.json"));
23658
23861
  if (hooks !== null)
23659
23862
  hashNativeJsonControls(hooks);
23660
23863
  return JSON.stringify(config.hooks ?? {}).includes(root2) || hooks !== null && JSON.stringify(JSON.parse(hooks)).includes(root2);
@@ -23666,7 +23869,7 @@ function retiredCodexRoots(binding, tolerance) {
23666
23869
  const controls = binding.codexDisabledPluginSkills;
23667
23870
  if (binding.agent !== "codex" || binding.method !== "reviewed" || !Array.isArray(controls) || !controls.length || !Array.isArray(proof.roots) || proof.roots.length > AGENT_POLICY_LIMITS.discoveryRoots || new Set(proof.roots).size !== proof.roots.length || !Array.isArray(proof.directories) || proof.parents !== undefined && (!Array.isArray(proof.parents) || proof.parents.length > AGENT_POLICY_LIMITS.discoveryRoots || new Set(proof.parents).size !== proof.parents.length) || !proof.roots.length && !proof.parents?.length)
23668
23871
  throw new Error("Invalid retired Codex materialization proof");
23669
- const cache = dirname25(dirname25(controls[0].pluginParent)), config = join37(dirname25(dirname25(cache)), "config.toml");
23872
+ const cache = dirname26(dirname26(controls[0].pluginParent)), config = join38(dirname26(dirname26(cache)), "config.toml");
23670
23873
  const source = binding.sources.find((source2) => source2.path === config && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
23671
23874
  if (!source || !codexConfigWitnessCurrent(source, tolerance))
23672
23875
  throw new Error("Missing current retired Codex configuration witness");
@@ -23674,7 +23877,7 @@ function retiredCodexRoots(binding, tolerance) {
23674
23877
  if ((proof.parents ?? []).some((parent) => codexDirectHookSelects(cache, parent) || !reviewedDisabledCodexPluginParent(cache, parent, controls, rules)) || !reviewedCodexPluginCapabilitiesUnchanged(cache, controls, (path) => read2(path), rules))
23675
23878
  throw new Error("Retired Codex parent capabilities changed");
23676
23879
  for (const root2 of proof.roots) {
23677
- const manifest = binding.sources.find((source2) => source2.path === join37(root2, ".codex-plugin/plugin.json") && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && [undefined, "bytes"].includes(source2.hashMode));
23880
+ const manifest = binding.sources.find((source2) => source2.path === join38(root2, ".codex-plugin/plugin.json") && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && [undefined, "bytes"].includes(source2.hashMode));
23678
23881
  if (!manifest || codexDirectHookSelects(cache, root2) || !reviewedRetiredCodexRoot(cache, root2, controls, rules, (path) => read2(path), true))
23679
23882
  throw new Error("Retired Codex materialization changed");
23680
23883
  }
@@ -23683,23 +23886,35 @@ function retiredCodexRoots(binding, tolerance) {
23683
23886
  function captureRetiredCodexDiscovery(binding, controls, rules) {
23684
23887
  if (binding.agent !== "codex" || binding.method !== "reviewed" || !controls.length)
23685
23888
  return binding;
23686
- const cache = dirname25(dirname25(controls[0].pluginParent));
23687
- const candidates = binding.sources.filter((source) => source.path.endsWith(sep14 + ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined && [undefined, "bytes"].includes(source.hashMode)).map((source) => dirname25(dirname25(source.path)));
23889
+ const cache = dirname26(dirname26(controls[0].pluginParent));
23890
+ const candidates = binding.sources.filter((source) => source.path.endsWith(sep15 + ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined && [undefined, "bytes"].includes(source.hashMode)).map((source) => dirname26(dirname26(source.path)));
23688
23891
  const roots = [...new Set(candidates)].filter((root2) => !codexDirectHookSelects(cache, root2) && reviewedRetiredCodexRoot(cache, root2, controls, rules, (path) => read2(path), binding.codexRetiredMaterializations?.roots.includes(root2) ?? false)).sort();
23689
23892
  const parents3 = reviewedCodexPluginCapabilitiesUnchanged(cache, controls, (path) => read2(path), rules) ? [...new Set(controls.map((control) => control.pluginParent))].filter((parent) => !codexDirectHookSelects(cache, parent) && reviewedDisabledCodexPluginParent(cache, parent, controls, rules)).sort() : [];
23690
23893
  const { codexRetiredMaterializations: previous, ...current } = binding;
23691
23894
  if (!roots.length && !parents3.length)
23692
23895
  return current;
23693
23896
  const installation = codexInstallationRoots(binding);
23694
- const directories = (binding.directories ?? []).filter((directory2) => !installation.some((root2) => directory2.path === root2 || directory2.path.startsWith(root2 + sep14) || root2.startsWith(directory2.path + sep14)));
23897
+ const directories = (binding.directories ?? []).filter((directory2) => !installation.some((root2) => directory2.path === root2 || directory2.path.startsWith(root2 + sep15) || root2.startsWith(directory2.path + sep15)));
23695
23898
  if (previous && isDeepStrictEqual9(previous.roots, roots) && isDeepStrictEqual9(previous.parents, parents3) && isDeepStrictEqual9(previous.directories.map((item) => item.path), directories.map((item) => item.path)))
23696
23899
  return { ...current, codexRetiredMaterializations: previous };
23697
23900
  return { ...current, codexRetiredMaterializations: { roots, parents: parents3, directories: captureDiscoveryDirectoryProjection(directories.map((item) => item.path), roots) } };
23698
23901
  }
23699
- function retainableAbsentSource(source) {
23902
+ function retainableAbsentWitness(source) {
23700
23903
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined)
23701
- return false;
23702
- return [undefined, "bytes"].includes(source.hashMode) || source.hashMode === "claude-plugin-manifest-v1" && source.sha256 !== null && source.path.endsWith(join37(sep14, ".claude-plugin", "plugin.json")) || source.hashMode === CLAUDE_ORPHAN_MARKER_MODE && source.sha256 !== null && isClaudePluginCacheOrphanMarker(source.path);
23904
+ return null;
23905
+ if ([undefined, "bytes"].includes(source.hashMode))
23906
+ return "bytes";
23907
+ if (source.hashMode === "claude-plugin-manifest-v1" && source.sha256 !== null && source.path.endsWith(join38(sep15, ".claude-plugin", "plugin.json")))
23908
+ return "claude-plugin-manifest-v1";
23909
+ if (source.hashMode === CLAUDE_ORPHAN_MARKER_MODE && source.sha256 !== null && isClaudePluginCacheOrphanMarker(source.path))
23910
+ return CLAUDE_ORPHAN_MARKER_MODE;
23911
+ return null;
23912
+ }
23913
+ function retainableAbsentSource(source) {
23914
+ return retainableAbsentWitness(source) !== null;
23915
+ }
23916
+ function retainedAbsentRoot(absentRoots, source) {
23917
+ return retainableAbsentSource(source) ? absentRoots.find((root2) => source.path.startsWith(root2 + sep15)) : undefined;
23703
23918
  }
23704
23919
  function absentRetiredClaudeRoots(binding) {
23705
23920
  if (binding.agent !== "claude" || binding.method !== "reviewed")
@@ -23708,17 +23923,17 @@ function absentRetiredClaudeRoots(binding) {
23708
23923
  for (const source of binding.sources) {
23709
23924
  if (!retainableAbsentSource(source) || source.sha256 === null)
23710
23925
  continue;
23711
- const marker = sep14 + ".claude" + sep14 + "plugins" + sep14 + "cache" + sep14, at = source.path.indexOf(marker);
23926
+ const marker = sep15 + ".claude" + sep15 + "plugins" + sep15 + "cache" + sep15, at = source.path.indexOf(marker);
23712
23927
  if (at < 0 || source.path.indexOf(marker, at + 1) >= 0)
23713
23928
  continue;
23714
- const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(sep14);
23929
+ const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(sep15);
23715
23930
  if (parts.length < 4 || parts.slice(0, 3).some((part) => !part || part === "." || part === ".."))
23716
23931
  continue;
23717
- const root2 = join37(cache, ...parts.slice(0, 3));
23932
+ const root2 = join38(cache, ...parts.slice(0, 3));
23718
23933
  safe6(root2);
23719
- if (lstatSync31(root2, { throwIfNoEntry: false }))
23934
+ if (lstatSync32(root2, { throwIfNoEntry: false }))
23720
23935
  continue;
23721
- const claude = dirname25(dirname25(cache)), settings = join37(claude, "settings.json"), registry = join37(claude, "plugins/installed_plugins.json");
23936
+ const claude = dirname26(dirname26(cache)), settings = join38(claude, "settings.json"), registry = join38(claude, "plugins/installed_plugins.json");
23722
23937
  const full = (path) => binding.sources.find((item) => item.path === path && item.sha256 !== null && item.format === undefined && item.fields === undefined);
23723
23938
  const configSource = full(settings), registrySource = full(registry);
23724
23939
  if (!configSource || !registrySource || projected(configSource) !== configSource.sha256 || projected(registrySource) !== registrySource.sha256)
@@ -23735,15 +23950,15 @@ function absentRetiredClaudeRoots(binding) {
23735
23950
  if (!row || typeof row !== "object" || Array.isArray(row))
23736
23951
  return null;
23737
23952
  const value = row;
23738
- if (typeof value.installPath !== "string" || /[\x00-\x1f\x7f]/.test(value.installPath) || !isAbsolute28(value.installPath) || resolve26(value.installPath) !== value.installPath || value.installPath.length > AGENT_POLICY_LIMITS.pathCharacters)
23953
+ if (typeof value.installPath !== "string" || /[\x00-\x1f\x7f]/.test(value.installPath) || !isAbsolute28(value.installPath) || resolve27(value.installPath) !== value.installPath || value.installPath.length > AGENT_POLICY_LIMITS.pathCharacters)
23739
23954
  return null;
23740
23955
  if (value.scope === "user")
23741
23956
  return value.projectPath === undefined || value.projectPath === null ? "user\x00" : null;
23742
23957
  if (value.scope === "project")
23743
- return typeof value.projectPath === "string" && !/[\x00-\x1f\x7f]/.test(value.projectPath) && value.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute28(value.projectPath) && resolve26(value.projectPath) === value.projectPath ? `project\x00${value.projectPath}` : null;
23958
+ return typeof value.projectPath === "string" && !/[\x00-\x1f\x7f]/.test(value.projectPath) && value.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute28(value.projectPath) && resolve27(value.projectPath) === value.projectPath ? `project\x00${value.projectPath}` : null;
23744
23959
  return null;
23745
23960
  };
23746
- if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root2 || row.installPath.startsWith(root2 + sep14) || root2.startsWith(row.installPath + sep14))))
23961
+ if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root2 || row.installPath.startsWith(root2 + sep15) || root2.startsWith(row.installPath + sep15))))
23747
23962
  continue;
23748
23963
  const rows = installed.plugins[id];
23749
23964
  if (!Array.isArray(rows) || rows.length < 1)
@@ -23761,9 +23976,9 @@ function absentRetiredClaudeRoots(binding) {
23761
23976
  if (!targetValid || !targetScopes.has("user\x00"))
23762
23977
  continue;
23763
23978
  const active = rows[0]?.installPath;
23764
- if (typeof active !== "string" || rows[0]?.version !== basename15(active) || dirname25(active) !== dirname25(root2) || active === root2 || !lstatSync31(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync13(active) !== active)
23979
+ if (typeof active !== "string" || rows[0]?.version !== basename15(active) || dirname26(active) !== dirname26(root2) || active === root2 || !lstatSync32(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync13(active) !== active)
23765
23980
  continue;
23766
- const activeManifest = full(join37(active, ".claude-plugin/plugin.json"));
23981
+ const activeManifest = full(join38(active, ".claude-plugin/plugin.json"));
23767
23982
  if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
23768
23983
  continue;
23769
23984
  result.add(root2);
@@ -23771,24 +23986,24 @@ function absentRetiredClaudeRoots(binding) {
23771
23986
  return [...result];
23772
23987
  }
23773
23988
  function codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParents = []) {
23774
- if (!isAbsolute28(source.path) || resolve26(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")
23989
+ if (!isAbsolute28(source.path) || resolve27(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")
23775
23990
  return false;
23776
- const parts = relative10(cacheRoot, source.path).split(sep14);
23777
- if (parts.length < 3 || !parents3.includes(join37(cacheRoot, parts[0], parts[1])))
23991
+ const parts = relative10(cacheRoot, source.path).split(sep15);
23992
+ if (parts.length < 3 || !parents3.includes(join38(cacheRoot, parts[0], parts[1])))
23778
23993
  return false;
23779
23994
  const tail = parts.slice(3).join("/");
23780
- const parent = join37(cacheRoot, parts[0], parts[1]);
23995
+ const parent = join38(cacheRoot, parts[0], parts[1]);
23781
23996
  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");
23782
23997
  }
23783
23998
  function codexSemanticCacheDirectoryRole(path, cacheRoot) {
23784
- return isAbsolute28(path) && resolve26(path) === path && !/[\x00-\x1f\x7f]/.test(path) && (path === cacheRoot || path.startsWith(cacheRoot + sep14));
23999
+ return isAbsolute28(path) && resolve27(path) === path && !/[\x00-\x1f\x7f]/.test(path) && (path === cacheRoot || path.startsWith(cacheRoot + sep15));
23785
24000
  }
23786
24001
  function assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, hookRootAlias = null) {
23787
24002
  const selectionRoots = [cacheRoot, ...parents3];
23788
24003
  if (hookRootAlias !== null) {
23789
- if (!hookRootAlias || Object.keys(hookRootAlias).length !== 2 || [hookRootAlias.alias, hookRootAlias.target].some((path) => typeof path !== "string" || !isAbsolute28(path) || resolve26(path) !== path || /[\x00-\x1f\x7f]/.test(path)) || hookRootAlias.target !== dirname25(configPath) || cacheRoot !== join37(hookRootAlias.target, "plugins/cache") || !lstatSync31(hookRootAlias.alias, { throwIfNoEntry: false })?.isSymbolicLink() || realpathSync13(hookRootAlias.alias) !== hookRootAlias.target || realpathSync13(hookRootAlias.target) !== hookRootAlias.target)
24004
+ if (!hookRootAlias || Object.keys(hookRootAlias).length !== 2 || [hookRootAlias.alias, hookRootAlias.target].some((path) => typeof path !== "string" || !isAbsolute28(path) || resolve27(path) !== path || /[\x00-\x1f\x7f]/.test(path)) || hookRootAlias.target !== dirname26(configPath) || cacheRoot !== join38(hookRootAlias.target, "plugins/cache") || !lstatSync32(hookRootAlias.alias, { throwIfNoEntry: false })?.isSymbolicLink() || realpathSync13(hookRootAlias.alias) !== hookRootAlias.target || realpathSync13(hookRootAlias.target) !== hookRootAlias.target)
23790
24005
  throw new Error("Reviewed semantic cache hook alias changed");
23791
- selectionRoots.push(...selectionRoots.map((root2) => join37(hookRootAlias.alias, relative10(hookRootAlias.target, root2))));
24006
+ selectionRoots.push(...selectionRoots.map((root2) => join38(hookRootAlias.alias, relative10(hookRootAlias.target, root2))));
23792
24007
  }
23793
24008
  selectionRoots.push("plugins/cache");
23794
24009
  if (selectionRoots.some((parent) => codexDirectHookSelects(cacheRoot, parent, configPath)))
@@ -23808,7 +24023,7 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
23808
24023
  if (binding.agent !== "codex" || binding.method !== "reviewed" || !controls?.length || proof.schema !== "hasna.codex-semantic-cache-discovery.v1" || !/^[a-f0-9]{64}$/.test(proof.previousPolicySha256) || !Array.isArray(proof.appOnlyParents) || !Array.isArray(proof.supersededSources) || !Array.isArray(proof.supersededDirectories))
23809
24024
  throw new Error("Invalid Codex semantic cache discovery proof");
23810
24025
  const cacheRoot = proof.witness.cacheRoot;
23811
- if (controls.some((control) => dirname25(dirname25(control.pluginParent)) !== cacheRoot))
24026
+ if (controls.some((control) => dirname26(dirname26(control.pluginParent)) !== cacheRoot))
23812
24027
  throw new Error("Codex semantic cache names another enrolled cache");
23813
24028
  const reviewedHookParents = proof.reviewedHookParents ?? [];
23814
24029
  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 || !isDeepStrictEqual9((proof.witness.hookParents ?? []).map(({ manifestSha256: _manifest, hooksSha256: _hooks, receiptSha256: _receipt, ...parent }) => parent), reviewedHookParents)) {
@@ -23824,7 +24039,7 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
23824
24039
  if (!directories.length || !isDeepStrictEqual9(sources, proof.supersededSources) || !isDeepStrictEqual9(directories, proof.supersededDirectories))
23825
24040
  throw new Error("Codex semantic cache provenance changed");
23826
24041
  const configPath = proof.configPath;
23827
- if (!isAbsolute28(configPath) || resolve26(configPath) !== configPath || basename15(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
24042
+ if (!isAbsolute28(configPath) || resolve27(configPath) !== configPath || basename15(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
23828
24043
  throw new Error("Invalid semantic cache configuration source");
23829
24044
  const configSource = binding.sources.find((source) => source.path === configPath && source.sha256 !== null && source.format === undefined && source.fields === undefined);
23830
24045
  if (!configSource || projected(configSource) !== configSource.sha256)
@@ -23846,10 +24061,10 @@ function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases, witne
23846
24061
  const semanticDirectory = (path) => Boolean(semanticCache && codexSemanticCacheDirectoryRole(path, semanticCache.witness.cacheRoot));
23847
24062
  const installationRoots = codexInstallationRoots(binding);
23848
24063
  const retiredRoots = retiredCodexRoots(binding, witnessTolerance);
23849
- const installationInput = (path) => installationRoots.some((root2) => path === root2 || path.startsWith(root2 + sep14));
24064
+ const installationInput = (path) => installationRoots.some((root2) => path === root2 || path.startsWith(root2 + sep15));
23850
24065
  if (binding.directories !== undefined) {
23851
24066
  const projected2 = binding.codexInstallationInputs?.directories ?? [];
23852
- const ancestors2 = binding.directories.filter((directory2) => installationRoots.some((root2) => root2.startsWith(directory2.path + sep14)));
24067
+ const ancestors2 = binding.directories.filter((directory2) => installationRoots.some((root2) => root2.startsWith(directory2.path + sep15)));
23853
24068
  if (projected2.length !== ancestors2.length || projected2.some((directory2) => !ancestors2.some((original) => original.path === directory2.path)))
23854
24069
  throw new Error("Missing installation input directory projection");
23855
24070
  const ordinary = binding.directories.filter((directory2) => !installationInput(directory2.path) && !ancestors2.includes(directory2) && !semanticDirectory(directory2.path));
@@ -23857,7 +24072,7 @@ function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases, witne
23857
24072
  const projection = binding.codexRetiredMaterializations.directories.filter((directory2) => !semanticDirectory(directory2.path));
23858
24073
  if (projection.length !== ordinary.length || projection.some((item, index) => item.path !== ordinary[index]?.path))
23859
24074
  throw new Error("Missing retired Codex directory projection");
23860
- const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !lstatSync31(parent, { throwIfNoEntry: false }))];
24075
+ const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !lstatSync32(parent, { throwIfNoEntry: false }))];
23861
24076
  if (projection.every((item) => Array.isArray(item.entries)))
23862
24077
  verifyDiscoveryDirectoryProjection(projection, omitted, witnessTolerance);
23863
24078
  else {
@@ -23874,7 +24089,7 @@ function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases, witne
23874
24089
  verifyDiscoveryDirectories(ordinary, [], witnessTolerance);
23875
24090
  verifyDiscoveryDirectories(projected2, installationRoots, witnessTolerance);
23876
24091
  }
23877
- const absentRoots = [...absentCodexSkillRoots(binding, witnessTolerance), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root2) => !lstatSync31(root2, { throwIfNoEntry: false }))];
24092
+ const absentRoots = [...absentCodexSkillRoots(binding, witnessTolerance), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root2) => !lstatSync32(root2, { throwIfNoEntry: false }))];
23878
24093
  const budget2 = discoveryByteBudget();
23879
24094
  for (const source of binding.sources) {
23880
24095
  assertMarketplaceBinding(binding, source);
@@ -23892,7 +24107,7 @@ function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases, witne
23892
24107
  safe6(source.path);
23893
24108
  continue;
23894
24109
  }
23895
- if (absentRoots.some((root2) => source.path.startsWith(root2 + sep14)) && retainableAbsentSource(source)) {
24110
+ if (retainedAbsentRoot(absentRoots, source) !== undefined) {
23896
24111
  safe6(source.path);
23897
24112
  continue;
23898
24113
  }
@@ -23912,23 +24127,25 @@ function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases, witne
23912
24127
  safe6(root2);
23913
24128
  for (const root2 of absentRoots) {
23914
24129
  safe6(root2);
23915
- if (lstatSync31(root2, { throwIfNoEntry: false }))
24130
+ if (lstatSync32(root2, { throwIfNoEntry: false }))
23916
24131
  throw new Error("Retired native materialization changed during discovery verification");
23917
24132
  }
23918
24133
  }
24134
+ var CLAUDE_CONTROL_WITNESS_MODES = new Set(["claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-settings-v4", "claude-marketplace-registry", "claude-marketplace-registry-v2", "claude-marketplace-entry-v1", "claude-plugin-registry"]);
24135
+ var CLAUDE_CONTROL_FILES = new Set(["settings.json", "settings.local.json", "installed_plugins.json", "known_marketplaces.json"]);
23919
24136
  function codexInstallationRoots(binding) {
23920
24137
  const proof = binding.codexInstallationInputs;
23921
24138
  if (proof === undefined)
23922
24139
  return [];
23923
24140
  if (binding.agent !== "codex" || binding.method !== "reviewed" || !supportsCodexNativeCapability(proof.version, "installed-plugin-review") || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
23924
24141
  throw new Error("Invalid native installation input proof");
23925
- const cache = dirname25(dirname25(proof.plugins[0].pluginParent));
23926
- const config = join37(dirname25(dirname25(cache)), "config.toml"), home = dirname25(dirname25(dirname25(cache)));
24142
+ const cache = dirname26(dirname26(proof.plugins[0].pluginParent));
24143
+ const config = join38(dirname26(dirname26(cache)), "config.toml"), home = dirname26(dirname26(dirname26(cache)));
23927
24144
  const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
23928
- const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join37(home, path));
23929
- if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep14) || input.sourceRoot.startsWith(root2 + sep14)) || binding.sources.some((source) => basename15(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep14)))))
24145
+ const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join38(home, path));
24146
+ if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep15) || input.sourceRoot.startsWith(root2 + sep15)) || binding.sources.some((source) => basename15(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep15)))))
23930
24147
  throw new Error("Native installation input overlaps configuration or loading roots");
23931
- if (proof.plugins.some((input) => dirname25(dirname25(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join37(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
24148
+ if (proof.plugins.some((input) => dirname26(dirname26(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join38(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
23932
24149
  throw new Error("Missing native installation input source witness");
23933
24150
  return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
23934
24151
  const text2 = read2(path);
@@ -23944,7 +24161,7 @@ function assertMarketplaceBinding(binding, source) {
23944
24161
  throw new Error("Provider executable witnesses require explicit reviewed Codex V6");
23945
24162
  if (source.hashMode === "codex-settings-v6" && (new Set(binding.sources.map((row) => row.path)).size !== binding.sources.length || !Array.isArray(source.hookSources) || source.hookSources.some((hook) => !binding.sources.some((row) => row.path === hook.path && row.sha256 === hook.sha256 && [undefined, "bytes"].includes(row.hashMode) && row.format === undefined && row.fields === undefined))))
23946
24163
  throw new Error("Missing independently reviewed Codex hook source population");
23947
- if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename15(source.path) !== "plugin.json" || !source.path.endsWith(join37(sep14, ".claude-plugin", "plugin.json"))))
24164
+ if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename15(source.path) !== "plugin.json" || !source.path.endsWith(join38(sep15, ".claude-plugin", "plugin.json"))))
23948
24165
  throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
23949
24166
  if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename15(source.path) !== "sumi.json"))
23950
24167
  throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
@@ -23957,10 +24174,11 @@ function assertMarketplaceBinding(binding, source) {
23957
24174
  if (source.hashMode === "claude-marketplace-entry-v1" && (binding.agent !== "claude" || binding.method !== "reviewed" || !claudeMarketplaceEntrySourceValid(source)))
23958
24175
  throw new Error("Claude marketplace entry witnesses require explicit reviewed Claude discovery of one named entry");
23959
24176
  }
24177
+ var ADOPTABLE_SETTINGS_MATCHES = Object.freeze(["exact", "screen-reader-receipt"]);
23960
24178
  function rebindAgentDiscovery(binding, changes) {
23961
24179
  const semanticCache = verifyCodexSemanticCacheDiscovery(binding);
23962
24180
  const budget2 = discoveryByteBudget();
23963
- const installationRoots = codexInstallationRoots(binding), absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredCodexRoots(binding).filter((root2) => !lstatSync31(root2, { throwIfNoEntry: false }))];
24181
+ const installationRoots = codexInstallationRoots(binding), absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredCodexRoots(binding).filter((root2) => !lstatSync32(root2, { throwIfNoEntry: false }))];
23964
24182
  const rebound = { ...binding, sources: binding.sources.map((source) => {
23965
24183
  assertMarketplaceBinding(binding, source);
23966
24184
  if (semanticCache?.supersededSources.some((previous) => isDeepStrictEqual9(previous, source))) {
@@ -23968,26 +24186,28 @@ function rebindAgentDiscovery(binding, changes) {
23968
24186
  throw new Error("Codex semantic cache sources cannot be written by hook rendering");
23969
24187
  return source;
23970
24188
  }
23971
- if (!changes.has(source.path) && (installationRoots.some((root2) => source.path.startsWith(root2 + sep14)) || absentRoots.some((root2) => source.path.startsWith(root2 + sep14)) && retainableAbsentSource(source)))
24189
+ if (!changes.has(source.path) && (installationRoots.some((root2) => source.path.startsWith(root2 + sep15)) || retainedAbsentRoot(absentRoots, source) !== undefined))
23972
24190
  return source;
23973
24191
  const sha2563 = projected(source, changes, budget2);
23974
24192
  if (!changes.has(source.path) && !(source.hashMode === "codex-settings-v6" && source.hookSources.some((hook) => changes.has(hook.path))) && sha2563 !== source.sha256)
23975
24193
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
24194
+ if (changes.has(source.path) && (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") && !ADOPTABLE_SETTINGS_MATCHES.includes(codexSettingsWitnessMatch(source.path, source.hashMode, source.sha256, budget2)))
24195
+ throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
23976
24196
  return source.hashMode === "codex-settings-v6" ? { ...source, ...captureCodexSettingsV6(source.path, source.hookSources, budget2, changes) } : { ...source, sha256: sha2563 };
23977
24197
  }) };
23978
24198
  for (const root2 of absentRoots) {
23979
24199
  safe6(root2);
23980
- if (lstatSync31(root2, { throwIfNoEntry: false }))
24200
+ if (lstatSync32(root2, { throwIfNoEntry: false }))
23981
24201
  throw new Error("Retired native materialization changed during discovery rebinding");
23982
24202
  }
23983
24203
  return rebound;
23984
24204
  }
23985
24205
  function hashReviewedExecutable(path, budget2) {
23986
- const before = lstatSync31(path, { bigint: true });
24206
+ const before = lstatSync32(path, { bigint: true });
23987
24207
  if (before.size < 0n || before.size > BigInt(budget2.remaining))
23988
24208
  throw new Error("Discovery aggregate executable byte limit exceeded");
23989
24209
  const digest3 = pluginExecutableDigest(path).slice(7);
23990
- const after = lstatSync31(path, { bigint: true });
24210
+ const after = lstatSync32(path, { bigint: true });
23991
24211
  for (const key2 of ["dev", "ino", "size", "mode", "uid", "gid", "nlink", "mtimeNs", "ctimeNs"]) {
23992
24212
  if (before[key2] !== after[key2])
23993
24213
  throw new Error("Discovery executable changed during budgeted capture");
@@ -24013,12 +24233,13 @@ function captureDiscoveryPathSources(paths) {
24013
24233
  const budget2 = discoveryByteBudget();
24014
24234
  return paths.map((path) => isClaudePluginCacheOrphanMarker(path) ? { path, hashMode: CLAUDE_ORPHAN_MARKER_MODE, sha256: hashClaudePluginCacheOrphanMarker(path, budget2) } : { path, hashMode: "path-bytes", sha256: hashDiscoveryPathFile(path, budget2) });
24015
24235
  }
24016
- function assertProjectDiscovery(agent, directories, home, canonical9 = resolve26, reviewed) {
24236
+ var CLAUDE_PROJECT_DISCOVERY_KEYS = Object.freeze(["enabledPlugins", "extraKnownMarketplaces", "additionalMarketplaces", "skillOverrides"]);
24237
+ function assertProjectDiscovery(agent, directories, home, canonical9 = resolve27, reviewed) {
24017
24238
  const homeConfigPath = canonical9(agentDiscoveryConfigPath(home, agent));
24018
24239
  const v6 = agent === "codex" && reviewed?.agent === "codex" && reviewed.method === "reviewed" ? reviewed.sources.find((source) => source.hashMode === "codex-settings-v6" && source.path === homeConfigPath) : undefined;
24019
24240
  const referenced = v6 ? new Set(captureCodexHookMcpDependencies(v6.path, v6.hookSources).servers) : undefined;
24020
24241
  for (const directory2 of directories) {
24021
- const isHome = resolve26(directory2) === resolve26(home);
24242
+ const isHome = resolve27(directory2) === resolve27(home);
24022
24243
  if (agent === "hermes") {
24023
24244
  assertHermesEnvironment(home);
24024
24245
  continue;
@@ -24027,7 +24248,7 @@ function assertProjectDiscovery(agent, directories, home, canonical9 = resolve26
24027
24248
  continue;
24028
24249
  const paths = agent === "claude" ? [...isHome ? [] : [".claude/settings.json"], ".claude/settings.local.json"] : agent === "codex" ? [".codex/config.toml"] : agent === "gemini" ? [".gemini/settings.json"] : agent === "opencode" ? ["opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc"] : agent === "sumi" ? ["sumi.json", "sumi.jsonc", ".sumi/sumi.json", ".sumi/sumi.jsonc"] : [".cursor/hooks.json"];
24029
24250
  for (const suffix of paths) {
24030
- const path = canonical9(join37(directory2, suffix)), raw = read2(path);
24251
+ const path = canonical9(join38(directory2, suffix)), raw = read2(path);
24031
24252
  if (raw === null)
24032
24253
  continue;
24033
24254
  const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
@@ -24042,7 +24263,7 @@ function assertProjectDiscovery(agent, directories, home, canonical9 = resolve26
24042
24263
  if (declaredHooks || providerOverride)
24043
24264
  throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project hook dependency requires review: ${path}`);
24044
24265
  }
24045
- const keys2 = agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces", "skillOverrides"] : agent === "codex" ? ["plugins", "marketplaces", "skills"] : agent === "gemini" ? ["skills", "extensions"] : agent === "opencode" ? ["plugin", "skills"] : agent === "sumi" ? ["plugin", "plugins", "skills", "permissions"] : ["hooks"];
24266
+ const keys2 = agent === "claude" ? CLAUDE_PROJECT_DISCOVERY_KEYS : agent === "codex" ? ["plugins", "marketplaces", "skills"] : agent === "gemini" ? ["skills", "extensions"] : agent === "opencode" ? ["plugin", "skills"] : agent === "sumi" ? ["plugin", "plugins", "skills", "permissions"] : ["hooks"];
24046
24267
  let admittedPlugins = false;
24047
24268
  if (agent === "claude" && reviewed?.agent === agent && reviewed.method === "reviewed" && config.enabledPlugins && typeof config.enabledPlugins === "object" && !Array.isArray(config.enabledPlugins)) {
24048
24269
  const exact = reviewed.sources.find((source) => source.path === path && source.format === undefined && source.fields === undefined && (source.hashMode === undefined || source.hashMode === "bytes"));
@@ -24056,8 +24277,8 @@ function assertProjectDiscovery(agent, directories, home, canonical9 = resolve26
24056
24277
  throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
24057
24278
  }
24058
24279
  if (referenced) {
24059
- const path = canonical9(join37(directory2, ".codex/hooks.json"));
24060
- if (path !== canonical9(join37(dirname25(homeConfigPath), "hooks.json"))) {
24280
+ const path = canonical9(join38(directory2, ".codex/hooks.json"));
24281
+ if (path !== canonical9(join38(dirname26(homeConfigPath), "hooks.json"))) {
24061
24282
  const raw = read2(path);
24062
24283
  if (raw !== null) {
24063
24284
  const hooks = parseConfig(raw, path, false);
@@ -24069,15 +24290,15 @@ function assertProjectDiscovery(agent, directories, home, canonical9 = resolve26
24069
24290
  }
24070
24291
  if (agent === "sumi")
24071
24292
  for (const name of ["plugin", "plugins"]) {
24072
- const path = canonical9(join37(directory2, ".sumi", name));
24293
+ const path = canonical9(join38(directory2, ".sumi", name));
24073
24294
  safe6(path);
24074
- if (lstatSync31(path, { throwIfNoEntry: false })?.isDirectory() && readdirSync12(path).length)
24295
+ if (lstatSync32(path, { throwIfNoEntry: false })?.isDirectory() && readdirSync12(path).length)
24075
24296
  throw new Error(`NATIVE_SKILL_DRIFT: project Sumi plugins require a dedicated discovery review: ${path}`);
24076
24297
  }
24077
24298
  if (agent === "claude") {
24078
- const commands = canonical9(join37(directory2, ".claude/commands"));
24299
+ const commands = canonical9(join38(directory2, ".claude/commands"));
24079
24300
  safe6(commands);
24080
- if (lstatSync31(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync12(commands).length)
24301
+ if (lstatSync32(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync12(commands).length)
24081
24302
  throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
24082
24303
  }
24083
24304
  }
@@ -24085,7 +24306,7 @@ function assertProjectDiscovery(agent, directories, home, canonical9 = resolve26
24085
24306
  function agentDiscoveryConfigPath(home, agent) {
24086
24307
  if (agent === "sumi")
24087
24308
  return sumiConfigPath(home);
24088
- return join37(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
24309
+ return join38(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
24089
24310
  }
24090
24311
  function verifyAutomaticDiscoveryClosure(binding, options) {
24091
24312
  const command = DISCOVERY_RUNTIME_COMMANDS[binding.agent], recorded = options.executable;
@@ -24145,7 +24366,8 @@ function codexVendorConfigChangeOnly(source, cache) {
24145
24366
  if (text2 === null)
24146
24367
  return false;
24147
24368
  const rowsAffectDigest = !["codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "codex-settings-v5"].includes(source.hashMode ?? "");
24148
- return codexVendorConfigCandidates(text2, cache, { rowsAffectDigest }).some((candidate2) => replacementDigest(source, candidate2) === source.sha256);
24369
+ const typed = 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" ? source.hashMode : undefined;
24370
+ return codexVendorConfigCandidates(text2, cache, { rowsAffectDigest }).some((candidate2) => replacementDigest(source, candidate2) === source.sha256 || typed !== undefined && codexSettingsToleratesScreenReaderReceipt(candidate2, typed, source.sha256));
24149
24371
  } catch {
24150
24372
  return false;
24151
24373
  }
@@ -24170,8 +24392,22 @@ function replacementDigest(source, text2) {
24170
24392
  return hashCodexSettingsReplacementV5(text2, budget2);
24171
24393
  return null;
24172
24394
  }
24395
+ function discoveryTextKeepsWitness(binding, path, text2) {
24396
+ if (binding.codexSemanticCache?.configPath === path)
24397
+ return false;
24398
+ return binding.sources.filter((source) => source.path === path).every((source) => {
24399
+ if (source.reviewArtifact !== undefined || source.managedPlugins !== undefined || source.hookSources !== undefined || typeof source.sha256 !== "string")
24400
+ return false;
24401
+ const typed = 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" ? source.hashMode : undefined;
24402
+ try {
24403
+ return replacementDigest(source, text2) === source.sha256 || typed !== undefined && codexSettingsToleratesScreenReaderReceipt(text2, typed, source.sha256);
24404
+ } catch {
24405
+ return false;
24406
+ }
24407
+ });
24408
+ }
24173
24409
  function resolveAgentDiscovery(options) {
24174
- const canonical9 = options.canonical ?? resolve26, home = resolve26(options.home), agent = options.agent;
24410
+ const canonical9 = options.canonical ?? resolve27, home = resolve27(options.home), agent = options.agent;
24175
24411
  const sources = [], roots = new Set, builtinNames = [];
24176
24412
  const witness = (path, format, fields2, hashMode) => {
24177
24413
  const source = { path: canonical9(path), sha256: null, ...format ? { format, fields: fields2 } : {}, ...hashMode ? { hashMode } : {} };
@@ -24192,42 +24428,42 @@ function resolveAgentDiscovery(options) {
24192
24428
  const review = options.reviewed?.agents.find((item) => item.agent === agent);
24193
24429
  if (agent === "sumi") {
24194
24430
  const directory2 = sumiConfigDirectory(home);
24195
- if (witness(join37(directory2, "sumi.jsonc")) !== null)
24431
+ if (witness(join38(directory2, "sumi.jsonc")) !== null)
24196
24432
  unresolved("JSONC configuration requires a supported format adapter");
24197
- for (const root2 of [directory2, join37(home, ".claude"), join37(home, ".agents")])
24433
+ for (const root2 of [directory2, join38(home, ".claude"), join38(home, ".agents")])
24198
24434
  for (const name of ["skill", "skills"])
24199
- roots.add(canonical9(join37(root2, name)));
24435
+ roots.add(canonical9(join38(root2, name)));
24200
24436
  if (config.skills !== undefined && (!Array.isArray(config.skills) || config.skills.some((path) => typeof path !== "string")))
24201
24437
  unresolved("skills must be a string array");
24202
24438
  for (const value of config.skills ?? []) {
24203
24439
  if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute28(value) || value.startsWith("~/")))
24204
24440
  unresolved("remote or relative skill sources need a dedicated discovery adapter");
24205
- roots.add(canonical9(value.startsWith("~/") ? join37(home, value.slice(2)) : value));
24441
+ roots.add(canonical9(value.startsWith("~/") ? join38(home, value.slice(2)) : value));
24206
24442
  }
24207
24443
  for (const key2 of ["plugin", "plugins"])
24208
24444
  if (config[key2] !== undefined && !Array.isArray(config[key2]))
24209
24445
  unresolved(`${key2} must be an array`);
24210
- const plugins = [join37(directory2, "plugin"), join37(directory2, "plugins")];
24446
+ const plugins = [join38(directory2, "plugin"), join38(directory2, "plugins")];
24211
24447
  for (const path of plugins) {
24212
24448
  safe6(path);
24213
- if (lstatSync31(path, { throwIfNoEntry: false })?.isDirectory())
24449
+ if (lstatSync32(path, { throwIfNoEntry: false })?.isDirectory())
24214
24450
  for (const name of readdirSync12(path).sort()) {
24215
24451
  if (name === "skills-cli.js" && path === plugins[1])
24216
24452
  continue;
24217
- const target = join37(path, name);
24218
- if (!lstatSync31(target).isFile())
24453
+ const target = join38(path, name);
24454
+ if (!lstatSync32(target).isFile())
24219
24455
  unresolved("local plugin packages need a dedicated discovery adapter");
24220
24456
  witness(target);
24221
24457
  }
24222
24458
  }
24223
24459
  for (const root2 of roots) {
24224
24460
  safe6(root2);
24225
- if (lstatSync31(root2, { throwIfNoEntry: false })?.isDirectory() && readdirSync12(root2).some((name) => name.endsWith(".md")))
24461
+ if (lstatSync32(root2, { throwIfNoEntry: false })?.isDirectory() && readdirSync12(root2).some((name) => name.endsWith(".md")))
24226
24462
  unresolved("flat markdown skills require a dedicated native migration adapter");
24227
24463
  }
24228
24464
  }
24229
24465
  if (agent === "hermes") {
24230
- const profile = witness(join37(home, ".hermes/active_profile"));
24466
+ const profile = witness(join38(home, ".hermes/active_profile"));
24231
24467
  if (profile?.trim() && profile.trim() !== "default")
24232
24468
  unresolved("a non-default profile is active");
24233
24469
  const declared = config.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
@@ -24241,7 +24477,7 @@ function resolveAgentDiscovery(options) {
24241
24477
  continue;
24242
24478
  if (normalized2.startsWith("~") && normalized2 !== "~" && !normalized2.startsWith("~/"))
24243
24479
  unresolved("user-specific tilde expansion requires a separate discovery adapter");
24244
- const path = normalized2 === "~" ? home : normalized2.startsWith("~/") ? join37(home, normalized2.slice(2)) : resolve26(home, ".hermes", normalized2);
24480
+ const path = normalized2 === "~" ? home : normalized2.startsWith("~/") ? join38(home, normalized2.slice(2)) : resolve27(home, ".hermes", normalized2);
24245
24481
  safe6(path);
24246
24482
  roots.add(path);
24247
24483
  }
@@ -24250,24 +24486,24 @@ function resolveAgentDiscovery(options) {
24250
24486
  const executable2 = options.executable === undefined ? discoveryExecutable(agent) : options.executable;
24251
24487
  if (executable2) {
24252
24488
  let packageRoot;
24253
- for (let directory2 = dirname25(executable2.target), depth = 0;depth < 8; directory2 = dirname25(directory2), depth++) {
24254
- const path = join37(directory2, "package.json"), raw = read2(path);
24489
+ for (let directory2 = dirname26(executable2.target), depth = 0;depth < 8; directory2 = dirname26(directory2), depth++) {
24490
+ const path = join38(directory2, "package.json"), raw = read2(path);
24255
24491
  if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
24256
24492
  packageRoot = directory2;
24257
24493
  witness(path);
24258
24494
  break;
24259
24495
  }
24260
- if (dirname25(directory2) === directory2)
24496
+ if (dirname26(directory2) === directory2)
24261
24497
  break;
24262
24498
  }
24263
24499
  if (!packageRoot)
24264
24500
  unresolved("installed Gemini package layout is not recognized");
24265
- const builtinRoot = join37(packageRoot, "bundle/builtin");
24501
+ const builtinRoot = join38(packageRoot, "bundle/builtin");
24266
24502
  safe6(builtinRoot);
24267
- if (!lstatSync31(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
24503
+ if (!lstatSync32(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
24268
24504
  unresolved("installed Gemini builtin root is missing");
24269
24505
  for (const name of readdirSync12(builtinRoot).sort()) {
24270
- const text2 = witness(join37(builtinRoot, name, "SKILL.md"));
24506
+ const text2 = witness(join38(builtinRoot, name, "SKILL.md"));
24271
24507
  const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
24272
24508
  if (!match?.[1] || builtinNames.includes(match[1]))
24273
24509
  unresolved("installed Gemini builtin name is missing or ambiguous");
@@ -24310,10 +24546,10 @@ function resolveAgentDiscovery(options) {
24310
24546
  if (agent === "claude" && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && source.reviewArtifact === undefined && [undefined, "bytes", "path-bytes"].includes(source.hashMode) && isClaudePluginCacheOrphanMarker(source.path)) {
24311
24547
  return { path: source.path, hashMode: CLAUDE_ORPHAN_MARKER_MODE, sha256: hashClaudePluginCacheOrphanMarker(source.path) };
24312
24548
  }
24313
- if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename15(source.path) !== "plugin.json" || !source.path.endsWith(join37(sep14, ".claude-plugin", "plugin.json")))
24549
+ if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename15(source.path) !== "plugin.json" || !source.path.endsWith(join38(sep15, ".claude-plugin", "plugin.json")))
24314
24550
  return source;
24315
- const pluginRoot = dirname25(dirname25(source.path)), hooksPath = join37(pluginRoot, "hooks/hooks.json");
24316
- const hookStat = lstatSync31(hooksPath, { throwIfNoEntry: false });
24551
+ const pluginRoot = dirname26(dirname26(source.path)), hooksPath = join38(pluginRoot, "hooks/hooks.json");
24552
+ const hookStat = lstatSync32(hooksPath, { throwIfNoEntry: false });
24317
24553
  const text2 = read2(source.path);
24318
24554
  if (text2 === null)
24319
24555
  throw new Error("Reviewed Claude plugin manifest is missing");
@@ -24327,8 +24563,8 @@ function resolveAgentDiscovery(options) {
24327
24563
  if (manifest.hooks !== undefined) {
24328
24564
  if (typeof manifest.hooks !== "string")
24329
24565
  throw new Error("Reviewed Claude plugin manifest has an unsupported hooks target");
24330
- const declaredHookPath = resolve26(pluginRoot, manifest.hooks);
24331
- if (!declaredHookPath.startsWith(pluginRoot + sep14))
24566
+ const declaredHookPath = resolve27(pluginRoot, manifest.hooks);
24567
+ if (!declaredHookPath.startsWith(pluginRoot + sep15))
24332
24568
  throw new Error("Reviewed Claude plugin hooks target escapes its root");
24333
24569
  reviewedHookPaths.add(declaredHookPath);
24334
24570
  }
@@ -24346,39 +24582,39 @@ function resolveAgentDiscovery(options) {
24346
24582
  function plugin(root2) {
24347
24583
  root2 = canonical9(root2);
24348
24584
  safe6(root2);
24349
- const manifestPath = join37(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
24585
+ const manifestPath = join38(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
24350
24586
  const raw = witness(manifestPath, undefined, undefined, agent === "claude" ? "claude-plugin-manifest-v1" : undefined);
24351
24587
  if (raw === null)
24352
24588
  unresolved("plugin manifest missing");
24353
24589
  const manifest = parseConfig(raw, manifestPath);
24354
- const hooks = witness(join37(root2, "hooks/hooks.json"));
24590
+ const hooks = witness(join38(root2, "hooks/hooks.json"));
24355
24591
  if (manifest.hooks !== undefined || hooks !== null)
24356
24592
  unresolved("plugin hooks require a separate no-skill-injection review");
24357
- const commands = join37(root2, "commands");
24593
+ const commands = join38(root2, "commands");
24358
24594
  safe6(commands);
24359
- if (agent === "claude" && (manifest.commands !== undefined || lstatSync31(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync12(commands).length))
24595
+ if (agent === "claude" && (manifest.commands !== undefined || lstatSync32(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync12(commands).length))
24360
24596
  unresolved("legacy command discovery requires retirement or a dedicated format adapter");
24361
- const rootSkill = witness(join37(root2, "SKILL.md"));
24597
+ const rootSkill = witness(join38(root2, "SKILL.md"));
24362
24598
  if (rootSkill !== null)
24363
24599
  roots.add(root2);
24364
24600
  const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
24365
24601
  if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
24366
24602
  unresolved("unsupported plugin skill paths");
24367
24603
  if (agent === "claude")
24368
- roots.add(join37(root2, "skills"));
24604
+ roots.add(join38(root2, "skills"));
24369
24605
  for (const value of declared) {
24370
- const path = resolve26(root2, value);
24371
- if (path !== root2 && !path.startsWith(root2 + sep14))
24606
+ const path = resolve27(root2, value);
24607
+ if (path !== root2 && !path.startsWith(root2 + sep15))
24372
24608
  unresolved("plugin skill path escapes its root");
24373
- roots.add(path.endsWith(`${sep14}SKILL.md`) ? dirname25(path) : path);
24609
+ roots.add(path.endsWith(`${sep15}SKILL.md`) ? dirname26(path) : path);
24374
24610
  }
24375
24611
  }
24376
24612
  if (agent === "claude") {
24377
- const registrations = witness(join37(home, ".claude/plugins/installed_plugins.json"));
24378
- const installed = registrations === null ? {} : parseConfig(registrations, join37(home, ".claude/plugins/installed_plugins.json")).plugins;
24379
- const commands = canonical9(join37(home, ".claude/commands"));
24613
+ const registrations = witness(join38(home, ".claude/plugins/installed_plugins.json"));
24614
+ const installed = registrations === null ? {} : parseConfig(registrations, join38(home, ".claude/plugins/installed_plugins.json")).plugins;
24615
+ const commands = canonical9(join38(home, ".claude/commands"));
24380
24616
  safe6(commands);
24381
- if (lstatSync31(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync12(commands).length)
24617
+ if (lstatSync32(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync12(commands).length)
24382
24618
  unresolved("legacy home command discovery requires a dedicated format adapter");
24383
24619
  for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
24384
24620
  if (enabled === false)
@@ -24400,16 +24636,16 @@ function resolveAgentDiscovery(options) {
24400
24636
  const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
24401
24637
  if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute28(market.source))
24402
24638
  unresolved("enabled plugin marketplace is not an explicit local source");
24403
- const catalogText = witness(join37(market.source, ".agents/plugins/marketplace.json"));
24639
+ const catalogText = witness(join38(market.source, ".agents/plugins/marketplace.json"));
24404
24640
  if (catalogText === null)
24405
24641
  unresolved("marketplace catalog missing");
24406
- const catalog = parseConfig(catalogText, join37(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
24642
+ const catalog = parseConfig(catalogText, join38(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
24407
24643
  if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
24408
24644
  unresolved("plugin catalog source is missing or ambiguous");
24409
- plugin(resolve26(market.source, matches[0].source.path));
24645
+ plugin(resolve27(market.source, matches[0].source.path));
24410
24646
  }
24411
24647
  } else if (agent === "opencode") {
24412
- if (witness(join37(home, ".config/opencode/opencode.jsonc")) !== null || witness(join37(home, ".config/opencode/config.json")) !== null)
24648
+ if (witness(join38(home, ".config/opencode/opencode.jsonc")) !== null || witness(join38(home, ".config/opencode/config.json")) !== null)
24413
24649
  unresolved("additional config layers require review");
24414
24650
  if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
24415
24651
  unresolved("external plugin or remote skill source");
@@ -24418,17 +24654,17 @@ function resolveAgentDiscovery(options) {
24418
24654
  unresolved("relative or malformed added skill root");
24419
24655
  roots.add(path);
24420
24656
  }
24421
- const localPlugins = join37(home, ".config/opencode/plugins");
24657
+ const localPlugins = join38(home, ".config/opencode/plugins");
24422
24658
  safe6(localPlugins);
24423
- if (lstatSync31(localPlugins, { throwIfNoEntry: false }) && readdirSync12(localPlugins).some((name) => name !== "skills-cli.js"))
24659
+ if (lstatSync32(localPlugins, { throwIfNoEntry: false }) && readdirSync12(localPlugins).some((name) => name !== "skills-cli.js"))
24424
24660
  unresolved("additional local plugin hooks require review");
24425
24661
  } else if (agent === "sumi") {
24426
- if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical9(configPath) && source.path !== canonical9(join37(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
24662
+ if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical9(configPath) && source.path !== canonical9(join38(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
24427
24663
  unresolved("external or foreign local plugins require review");
24428
24664
  } else if (agent === "hermes") {
24429
- for (const directory2 of [join37(home, ".hermes/plugins"), join37(home, ".hermes/hermes-agent")]) {
24665
+ for (const directory2 of [join38(home, ".hermes/plugins"), join38(home, ".hermes/hermes-agent")]) {
24430
24666
  safe6(directory2);
24431
- if (lstatSync31(directory2, { throwIfNoEntry: false }))
24667
+ if (lstatSync32(directory2, { throwIfNoEntry: false }))
24432
24668
  unresolved("installed runtime/plugin discovery requires reviewed source bindings");
24433
24669
  }
24434
24670
  if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
@@ -24436,30 +24672,30 @@ function resolveAgentDiscovery(options) {
24436
24672
  } else if (agent === "gemini") {
24437
24673
  if (Object.keys(config.extensions ?? {}).length || config.skills?.paths?.length)
24438
24674
  unresolved("custom extension or skill paths");
24439
- const directory2 = join37(home, ".gemini/extensions");
24675
+ const directory2 = join38(home, ".gemini/extensions");
24440
24676
  safe6(directory2);
24441
- if (lstatSync31(directory2, { throwIfNoEntry: false }))
24677
+ if (lstatSync32(directory2, { throwIfNoEntry: false }))
24442
24678
  for (const name of readdirSync12(directory2)) {
24443
- const root2 = join37(directory2, name);
24679
+ const root2 = join38(directory2, name);
24444
24680
  safe6(root2);
24445
- if (!lstatSync31(root2)?.isDirectory())
24681
+ if (!lstatSync32(root2)?.isDirectory())
24446
24682
  continue;
24447
- const raw = witness(join37(root2, "gemini-extension.json"));
24683
+ const raw = witness(join38(root2, "gemini-extension.json"));
24448
24684
  if (raw === null)
24449
24685
  unresolved("extension registration missing");
24450
- const manifest = parseConfig(raw, join37(root2, "gemini-extension.json"));
24451
- if (manifest.hooks !== undefined || witness(join37(root2, "hooks/hooks.json")) !== null || witness(join37(root2, ".gemini-extension-install.json")) !== null)
24686
+ const manifest = parseConfig(raw, join38(root2, "gemini-extension.json"));
24687
+ if (manifest.hooks !== undefined || witness(join38(root2, "hooks/hooks.json")) !== null || witness(join38(root2, ".gemini-extension-install.json")) !== null)
24452
24688
  unresolved("extension hooks or linked registration require review");
24453
- roots.add(join37(root2, "skills"));
24689
+ roots.add(join38(root2, "skills"));
24454
24690
  }
24455
24691
  }
24456
- return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join37(home, ".hermes/plugins"), join37(home, ".hermes/hermes-agent")].map((path) => canonical9(path))) } : {} };
24692
+ return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join38(home, ".hermes/plugins"), join38(home, ".hermes/hermes-agent")].map((path) => canonical9(path))) } : {} };
24457
24693
  }
24458
24694
 
24459
24695
  // src/lib/authoring-path.ts
24460
24696
  var NATIVE_DISCOVERY_ROOTS = NATIVE_SKILL_ROOTS.map(([, path]) => path.split("/"));
24461
24697
  function pathParts(path) {
24462
- return resolve27(path).split(sep15).filter(Boolean);
24698
+ return resolve28(path).split(sep16).filter(Boolean);
24463
24699
  }
24464
24700
  function nativeRootMatch(path) {
24465
24701
  const parts = pathParts(path);
@@ -24473,24 +24709,24 @@ function nativeRootMatch(path) {
24473
24709
  return;
24474
24710
  }
24475
24711
  function physicalPath(path) {
24476
- let cursor = resolve27(path);
24712
+ let cursor = resolve28(path);
24477
24713
  const suffix = [];
24478
- while (!lstatSync32(cursor, { throwIfNoEntry: false })) {
24714
+ while (!lstatSync33(cursor, { throwIfNoEntry: false })) {
24479
24715
  suffix.unshift(basename16(cursor));
24480
- const parent = dirname26(cursor);
24716
+ const parent = dirname27(cursor);
24481
24717
  if (parent === cursor)
24482
- return resolve27(path);
24718
+ return resolve28(path);
24483
24719
  cursor = parent;
24484
24720
  }
24485
- return resolve27(realpathSync14(cursor), ...suffix);
24721
+ return resolve28(realpathSync14(cursor), ...suffix);
24486
24722
  }
24487
24723
  function contains(root2, path) {
24488
- return path === root2 || path.startsWith(root2 + sep15);
24724
+ return path === root2 || path.startsWith(root2 + sep16);
24489
24725
  }
24490
24726
  function configuredRoots(home, explicitHome) {
24491
- const homeData = join38(home, ".hasna", "skills");
24727
+ const homeData = join39(home, ".hasna", "skills");
24492
24728
  const homePolicy = readManagedSkillPolicySnapshot(homeData);
24493
- const configuredPolicy = !explicitHome && resolve27(getDataDirReadOnly()) !== resolve27(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
24729
+ const configuredPolicy = !explicitHome && resolve28(getDataDirReadOnly()) !== resolve28(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
24494
24730
  const policy = homePolicy ?? configuredPolicy;
24495
24731
  const bridge = policy?.value.bridge;
24496
24732
  if (bridge && (typeof bridge.home !== "string" || physicalPath(bridge.home) !== physicalPath(home))) {
@@ -24519,8 +24755,8 @@ function configuredRoots(home, explicitHome) {
24519
24755
  admitBinding(binding);
24520
24756
  continue;
24521
24757
  }
24522
- const nativeHome = join38(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
24523
- if (!lstatSync32(nativeHome, { throwIfNoEntry: false }))
24758
+ const nativeHome = join39(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
24759
+ if (!lstatSync33(nativeHome, { throwIfNoEntry: false }))
24524
24760
  continue;
24525
24761
  roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
24526
24762
  }
@@ -24529,22 +24765,22 @@ function configuredRoots(home, explicitHome) {
24529
24765
  function assertPortableAuthoringPath(path, options = {}) {
24530
24766
  if (typeof path !== "string" || !path || path.includes("\x00"))
24531
24767
  throw new Error("Invalid portable authoring path");
24532
- const lexical = resolve27(path);
24768
+ const lexical = resolve28(path);
24533
24769
  const physical = physicalPath(lexical);
24534
24770
  const candidates = [lexical, physical];
24535
24771
  let native = candidates.map(nativeRootMatch).find(Boolean);
24536
- const home = resolve27(options.homeDir ?? homedir6());
24537
- const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join38(home, ...parts));
24538
- defaults.push(join38(home, ".codex/plugins/cache"), join38(home, ".claude/plugins/cache"), join38(home, ".claude/plugins/synced"), join38(home, ".gemini/extensions"));
24772
+ const home = resolve28(options.homeDir ?? homedir6());
24773
+ const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join39(home, ...parts));
24774
+ defaults.push(join39(home, ".codex/plugins/cache"), join39(home, ".claude/plugins/cache"), join39(home, ".claude/plugins/synced"), join39(home, ".gemini/extensions"));
24539
24775
  for (const root2 of defaults) {
24540
- if (candidates.some((candidate2) => contains(resolve27(root2), candidate2) || contains(physicalPath(root2), candidate2)))
24776
+ if (candidates.some((candidate2) => contains(resolve28(root2), candidate2) || contains(physicalPath(root2), candidate2)))
24541
24777
  native ??= root2;
24542
24778
  }
24543
24779
  if (native) {
24544
24780
  throw new Error(`Refusing portable Skills authoring below native discovery root '${native}': ${lexical}. Set HASNA_SKILLS_DIR to a private authoring corpus outside native roots.`);
24545
24781
  }
24546
24782
  for (const root2 of configuredRoots(home, options.homeDir !== undefined)) {
24547
- if (candidates.some((candidate2) => contains(resolve27(root2), candidate2) || contains(physicalPath(root2), candidate2))) {
24783
+ if (candidates.some((candidate2) => contains(resolve28(root2), candidate2) || contains(physicalPath(root2), candidate2))) {
24548
24784
  throw new Error(`Refusing portable Skills authoring below configured native discovery root: ${lexical}`);
24549
24785
  }
24550
24786
  }
@@ -24556,15 +24792,15 @@ function getPortableSkillsRoot(options = {}) {
24556
24792
  function resolvePortableSkillsRoot(options, migrate) {
24557
24793
  if (options.rootDir)
24558
24794
  return options.rootDir;
24559
- const appDir = options.homeDir ? join39(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
24560
- const cache = join39(appDir, SKILLS_CACHE_DIRNAME);
24795
+ const appDir = options.homeDir ? join40(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
24796
+ const cache = join40(appDir, SKILLS_CACHE_DIRNAME);
24561
24797
  if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
24562
24798
  return cache;
24563
- const installed = join39(appDir, INSTALLED_SKILLS_DIRNAME);
24799
+ const installed = join40(appDir, INSTALLED_SKILLS_DIRNAME);
24564
24800
  return installed;
24565
24801
  }
24566
24802
  function getPortableSkillPath(name, options = {}) {
24567
- return join39(getPortableSkillsRoot(options), normalizePortableSkillName(name));
24803
+ return join40(getPortableSkillsRoot(options), normalizePortableSkillName(name));
24568
24804
  }
24569
24805
  function findPortableSkill(name, options = {}) {
24570
24806
  let normalized2;
@@ -24590,7 +24826,7 @@ function listPortableSkills(options = {}) {
24590
24826
  for (const entry of readdirSync13(root2).sort()) {
24591
24827
  if (entry.startsWith("."))
24592
24828
  continue;
24593
- const path = join39(root2, entry);
24829
+ const path = join40(root2, entry);
24594
24830
  if (!safeIsDirectory(path))
24595
24831
  continue;
24596
24832
  try {
@@ -24624,9 +24860,9 @@ function isOfficialSkillName(name) {
24624
24860
  function scaffoldPortableSkill(name, options = {}) {
24625
24861
  const skillName = normalizeNewPortableSkillName(name);
24626
24862
  const readOnlyRoot = resolvePortableSkillsRoot(options, false);
24627
- assertPortableAuthoringPath(join39(readOnlyRoot, skillName), options);
24863
+ assertPortableAuthoringPath(join40(readOnlyRoot, skillName), options);
24628
24864
  const root2 = getPortableSkillsRoot(options);
24629
- const skillPath = join39(root2, skillName);
24865
+ const skillPath = join40(root2, skillName);
24630
24866
  assertPortableAuthoringPath(skillPath, options);
24631
24867
  if (existsSync14(skillPath)) {
24632
24868
  if (!options.overwrite)
@@ -24660,7 +24896,7 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
24660
24896
  const skipped = [];
24661
24897
  const entries = readdirSync13(absoluteSource, { withFileTypes: true }).map((entry) => entry.name).filter((entryName) => !entryName.startsWith(".")).sort();
24662
24898
  for (const entryName of entries) {
24663
- const childPath = join39(absoluteSource, entryName);
24899
+ const childPath = join40(absoluteSource, entryName);
24664
24900
  if (!safeIsDirectory(childPath))
24665
24901
  continue;
24666
24902
  if (!isSkillCandidate(childPath)) {
@@ -24689,23 +24925,23 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
24689
24925
  };
24690
24926
  }
24691
24927
  function isSkillCandidate(dir) {
24692
- return existsSync14(join39(dir, "SKILL.md")) || existsSync14(join39(dir, "skill.json")) || existsSync14(join39(dir, "package.json"));
24928
+ return existsSync14(join40(dir, "SKILL.md")) || existsSync14(join40(dir, "skill.json")) || existsSync14(join40(dir, "package.json"));
24693
24929
  }
24694
24930
  function physicalImportPath(path) {
24695
- let ancestor = resolve28(path);
24931
+ let ancestor = resolve29(path);
24696
24932
  const suffix = [];
24697
24933
  while (!existsSync14(ancestor)) {
24698
24934
  suffix.unshift(basename17(ancestor));
24699
- ancestor = dirname27(ancestor);
24935
+ ancestor = dirname28(ancestor);
24700
24936
  }
24701
- return join39(realpathSync15(ancestor), ...suffix);
24937
+ return join40(realpathSync15(ancestor), ...suffix);
24702
24938
  }
24703
24939
  function assertDisjointImportPaths(source, destination) {
24704
24940
  const sourcePath = realpathSync15(source);
24705
24941
  const destinationPath = physicalImportPath(destination);
24706
24942
  const contains2 = (parent, child2) => {
24707
24943
  const path = relative11(parent, child2);
24708
- return path === "" || !isAbsolute29(path) && path !== ".." && !path.startsWith(`..${sep16}`);
24944
+ return path === "" || !isAbsolute29(path) && path !== ".." && !path.startsWith(`..${sep17}`);
24709
24945
  };
24710
24946
  if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
24711
24947
  throw new Error("Source and destination skill directories must not overlap");
@@ -24724,11 +24960,11 @@ function portPortableSkill(sourcePath, options = {}) {
24724
24960
  const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename17(absoluteSource)}')` : ""} matches a bundled official skill.`;
24725
24961
  throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
24726
24962
  }
24727
- const readOnlyDestination = join39(resolvePortableSkillsRoot(options, false), skillName);
24963
+ const readOnlyDestination = join40(resolvePortableSkillsRoot(options, false), skillName);
24728
24964
  assertPortableAuthoringPath(readOnlyDestination, options);
24729
24965
  assertDisjointImportPaths(absoluteSource, readOnlyDestination);
24730
24966
  const root2 = getPortableSkillsRoot(options);
24731
- const destination = join39(root2, skillName);
24967
+ const destination = join40(root2, skillName);
24732
24968
  assertPortableAuthoringPath(destination, options);
24733
24969
  assertDisjointImportPaths(absoluteSource, destination);
24734
24970
  if (existsSync14(destination)) {
@@ -24736,7 +24972,7 @@ function portPortableSkill(sourcePath, options = {}) {
24736
24972
  throw new Error(`Skill '${skillName}' already exists at ${destination}`);
24737
24973
  rmSync4(destination, { recursive: true, force: true });
24738
24974
  }
24739
- mkdirSync11(dirname27(destination), { recursive: true });
24975
+ mkdirSync11(dirname28(destination), { recursive: true });
24740
24976
  copySkillDirectory(absoluteSource, destination);
24741
24977
  const base = {
24742
24978
  ...inferred,
@@ -24773,13 +25009,13 @@ function buildCorpusManifest(input, name) {
24773
25009
  function writeCorpusSkill(input, options = {}) {
24774
25010
  const name = normalizePortableSkillName(input.name);
24775
25011
  const readOnlyRoot = resolvePortableSkillsRoot(options, false);
24776
- assertPortableAuthoringPath(join39(readOnlyRoot, name), options);
25012
+ assertPortableAuthoringPath(join40(readOnlyRoot, name), options);
24777
25013
  const root2 = getPortableSkillsRoot(options);
24778
- const skillPath = join39(root2, name);
25014
+ const skillPath = join40(root2, name);
24779
25015
  assertPortableAuthoringPath(skillPath, options);
24780
25016
  const created = !existsSync14(skillPath);
24781
25017
  mkdirSync11(skillPath, { recursive: true });
24782
- writeFileSync9(join39(skillPath, "SKILL.md"), input.skillMd);
25018
+ writeFileSync9(join40(skillPath, "SKILL.md"), input.skillMd);
24783
25019
  const manifest = buildCorpusManifest(input, name);
24784
25020
  writeSkillJsonWithHash(skillPath, manifest);
24785
25021
  return { name, path: skillPath, manifest, created };
@@ -24787,22 +25023,22 @@ function writeCorpusSkill(input, options = {}) {
24787
25023
  function installCorpusSkillAtomically(input, options = {}) {
24788
25024
  const name = normalizePortableSkillName(input.name);
24789
25025
  const readOnlyRoot = resolvePortableSkillsRoot(options, false);
24790
- assertPortableAuthoringPath(join39(readOnlyRoot, name), options);
25026
+ assertPortableAuthoringPath(join40(readOnlyRoot, name), options);
24791
25027
  const root2 = getPortableSkillsRoot(options);
24792
- const target = join39(root2, name);
25028
+ const target = join40(root2, name);
24793
25029
  assertPortableAuthoringPath(target, options);
24794
25030
  const created = !existsSync14(target);
24795
25031
  mkdirSync11(root2, { recursive: true });
24796
- const staging = mkdtempSync2(join39(root2, `.pull-${name}-`));
25032
+ const staging = mkdtempSync2(join40(root2, `.pull-${name}-`));
24797
25033
  let moved = false;
24798
25034
  let backup = null;
24799
25035
  try {
24800
- writeFileSync9(join39(staging, "SKILL.md"), input.skillMd);
25036
+ writeFileSync9(join40(staging, "SKILL.md"), input.skillMd);
24801
25037
  const manifest = buildCorpusManifest(input, name);
24802
25038
  writeSkillJsonWithHash(staging, manifest);
24803
25039
  if (existsSync14(target)) {
24804
- backup = mkdtempSync2(join39(root2, `.pull-backup-${name}-`));
24805
- renameSync6(target, join39(backup, name));
25040
+ backup = mkdtempSync2(join40(root2, `.pull-backup-${name}-`));
25041
+ renameSync6(target, join40(backup, name));
24806
25042
  moved = true;
24807
25043
  }
24808
25044
  renameSync6(staging, target);
@@ -24811,9 +25047,9 @@ function installCorpusSkillAtomically(input, options = {}) {
24811
25047
  return { name, path: target, manifest, created };
24812
25048
  } catch (error) {
24813
25049
  rmSync4(staging, { recursive: true, force: true });
24814
- if (moved && backup && existsSync14(join39(backup, name))) {
25050
+ if (moved && backup && existsSync14(join40(backup, name))) {
24815
25051
  try {
24816
- renameSync6(join39(backup, name), target);
25052
+ renameSync6(join40(backup, name), target);
24817
25053
  } catch {}
24818
25054
  }
24819
25055
  throw error;
@@ -24826,8 +25062,8 @@ function validatePortableSkillDirectory(name, skillPath) {
24826
25062
  const warnings = [...base.warnings];
24827
25063
  let manifest;
24828
25064
  if (existsSync14(skillPath)) {
24829
- const skillJsonPath = join39(skillPath, "skill.json");
24830
- const skillMdPath = join39(skillPath, "SKILL.md");
25065
+ const skillJsonPath = join40(skillPath, "skill.json");
25066
+ const skillMdPath = join40(skillPath, "SKILL.md");
24831
25067
  if (!existsSync14(skillJsonPath) && !existsSync14(skillMdPath)) {
24832
25068
  add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
24833
25069
  }
@@ -24847,7 +25083,7 @@ function validatePortableSkillDirectory(name, skillPath) {
24847
25083
  add3(issues, "portable.version_missing", "Portable manifest missing version");
24848
25084
  }
24849
25085
  const contractIssues = validatePortableManifestContract(manifest, {
24850
- strict: existsSync14(join39(skillPath, "skill.json")),
25086
+ strict: existsSync14(join40(skillPath, "skill.json")),
24851
25087
  skillPath
24852
25088
  });
24853
25089
  for (const issue of contractIssues)
@@ -24887,7 +25123,7 @@ function validatePortableSkillDirectory(name, skillPath) {
24887
25123
  add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
24888
25124
  continue;
24889
25125
  }
24890
- const entryPath = join39(skillPath, command.entry);
25126
+ const entryPath = join40(skillPath, command.entry);
24891
25127
  if (!existsSync14(entryPath))
24892
25128
  add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
24893
25129
  else if (statSync13(entryPath).isDirectory())
@@ -24898,7 +25134,7 @@ function validatePortableSkillDirectory(name, skillPath) {
24898
25134
  } catch (error) {
24899
25135
  add3(issues, "portable.manifest_invalid", error.message);
24900
25136
  }
24901
- if (manifest?.kind !== "instruction" && !existsSync14(join39(skillPath, "AGENTS.md"))) {
25137
+ if (manifest?.kind !== "instruction" && !existsSync14(join40(skillPath, "AGENTS.md"))) {
24902
25138
  add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
24903
25139
  }
24904
25140
  }
@@ -24934,12 +25170,12 @@ async function runPortableSkill(name, args, options = {}) {
24934
25170
  if (!isSafeRelativePath2(command.entry)) {
24935
25171
  return { exitCode: 1, error: `Portable skill '${name}' command entry is unsafe` };
24936
25172
  }
24937
- const entryPath = join39(skill.path, command.entry);
25173
+ const entryPath = join40(skill.path, command.entry);
24938
25174
  if (!existsSync14(entryPath)) {
24939
25175
  return { exitCode: 1, error: `Entry point '${command.entry}' not found in portable skill '${name}'` };
24940
25176
  }
24941
- const pkgPath = join39(skill.path, "package.json");
24942
- const nodeModules = join39(skill.path, "node_modules");
25177
+ const pkgPath = join40(skill.path, "package.json");
25178
+ const nodeModules = join40(skill.path, "node_modules");
24943
25179
  if (existsSync14(pkgPath) && !existsSync14(nodeModules) && hasPackageDependencies(pkgPath)) {
24944
25180
  const install = Bun.spawn(["bun", "install", "--no-save"], {
24945
25181
  cwd: skill.path,
@@ -25196,12 +25432,12 @@ function discoverSkillsInDir(dir, source = "custom") {
25196
25432
  for (const entry of entries) {
25197
25433
  if (!entry.isDirectory())
25198
25434
  continue;
25199
- const skillMdPath = join40(dir, entry.name, "SKILL.md");
25435
+ const skillMdPath = join41(dir, entry.name, "SKILL.md");
25200
25436
  if (!existsSync15(skillMdPath))
25201
25437
  continue;
25202
25438
  let content;
25203
25439
  try {
25204
- content = readFileSync26(skillMdPath, "utf-8");
25440
+ content = readFileSync27(skillMdPath, "utf-8");
25205
25441
  } catch {
25206
25442
  continue;
25207
25443
  }
@@ -25216,7 +25452,7 @@ function discoverSkillsInDir(dir, source = "custom") {
25216
25452
  category: fm.category || "Development Tools",
25217
25453
  tags: fm.tags || [],
25218
25454
  ...fm.kind ? { kind: fm.kind } : {},
25219
- ...isHostedMetadataSkillDir(join40(dir, entry.name)) ? { serverOwned: true } : {},
25455
+ ...isHostedMetadataSkillDir(join41(dir, entry.name)) ? { serverOwned: true } : {},
25220
25456
  source
25221
25457
  });
25222
25458
  }
@@ -25232,13 +25468,13 @@ function findExtensionSkillPath(name) {
25232
25468
  for (const entry of entries) {
25233
25469
  if (!entry.isDirectory())
25234
25470
  continue;
25235
- const skillDir = join40(config.extensionsDir, entry.name);
25236
- const skillMdPath = join40(skillDir, "SKILL.md");
25471
+ const skillDir = join41(config.extensionsDir, entry.name);
25472
+ const skillMdPath = join41(skillDir, "SKILL.md");
25237
25473
  if (!existsSync15(skillMdPath))
25238
25474
  continue;
25239
25475
  let content;
25240
25476
  try {
25241
- content = readFileSync26(skillMdPath, "utf-8");
25477
+ content = readFileSync27(skillMdPath, "utf-8");
25242
25478
  } catch {
25243
25479
  continue;
25244
25480
  }
@@ -25303,20 +25539,20 @@ function getAllTags(catalog) {
25303
25539
  }
25304
25540
  // src/lib/run-state.ts
25305
25541
  import { createHash as createHash31, randomBytes } from "crypto";
25306
- import { existsSync as existsSync16, mkdirSync as mkdirSync12, readFileSync as readFileSync27, readdirSync as readdirSync15, statSync as statSync14, writeFileSync as writeFileSync10 } from "fs";
25307
- import { extname, join as join41, relative as relative12 } from "path";
25542
+ import { existsSync as existsSync16, mkdirSync as mkdirSync12, readFileSync as readFileSync28, readdirSync as readdirSync15, statSync as statSync14, writeFileSync as writeFileSync10 } from "fs";
25543
+ import { extname, join as join42, relative as relative12 } from "path";
25308
25544
  function createSkillRun(params, targetDir = process.cwd()) {
25309
25545
  const now = new Date;
25310
25546
  const id = createRunId(now);
25311
25547
  const day = now.toISOString().slice(0, 10);
25312
25548
  const skillName = normalizeSkillName(params.skill);
25313
25549
  const root2 = getProjectStateDir(targetDir);
25314
- const runDir = join41(root2, "runs", day, id);
25315
- const logsDir = join41(runDir, "logs");
25316
- const exportDir = join41(root2, "exports", skillName, id);
25550
+ const runDir = join42(root2, "runs", day, id);
25551
+ const logsDir = join42(runDir, "logs");
25552
+ const exportDir = join42(root2, "exports", skillName, id);
25317
25553
  mkdirSync12(logsDir, { recursive: true });
25318
25554
  mkdirSync12(exportDir, { recursive: true });
25319
- mkdirSync12(join41(root2, "tmp"), { recursive: true });
25555
+ mkdirSync12(join42(root2, "tmp"), { recursive: true });
25320
25556
  const record5 = {
25321
25557
  id,
25322
25558
  skill: skillName,
@@ -25368,27 +25604,27 @@ function updateSkillRun(context, patch) {
25368
25604
  return context.record;
25369
25605
  }
25370
25606
  function writeRunLogs(context, stdout = "", stderr = "") {
25371
- writeFileSync10(join41(context.logsDir, "stdout.log"), stdout);
25372
- writeFileSync10(join41(context.logsDir, "stderr.log"), stderr);
25607
+ writeFileSync10(join42(context.logsDir, "stdout.log"), stdout);
25608
+ writeFileSync10(join42(context.logsDir, "stderr.log"), stderr);
25373
25609
  }
25374
25610
  function appendRunEvent(context, event, data = {}) {
25375
25611
  const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
25376
25612
  `;
25377
- const path = join41(context.runDir, "events.ndjson");
25378
- const previous = existsSync16(path) ? readFileSync27(path, "utf-8") : "";
25613
+ const path = join42(context.runDir, "events.ndjson");
25614
+ const previous = existsSync16(path) ? readFileSync28(path, "utf-8") : "";
25379
25615
  writeFileSync10(path, previous + line);
25380
25616
  }
25381
25617
  function listSkillRuns(targetDir = process.cwd(), limit = 50) {
25382
- const runsRoot = join41(getProjectStateDir(targetDir), "runs");
25618
+ const runsRoot = join42(getProjectStateDir(targetDir), "runs");
25383
25619
  if (!existsSync16(runsRoot))
25384
25620
  return [];
25385
25621
  const records = [];
25386
25622
  for (const day of readdirSync15(runsRoot).sort().reverse()) {
25387
- const dayDir = join41(runsRoot, day);
25623
+ const dayDir = join42(runsRoot, day);
25388
25624
  if (!statSync14(dayDir).isDirectory())
25389
25625
  continue;
25390
25626
  for (const runId of readdirSync15(dayDir).sort().reverse()) {
25391
- const record5 = readRunRecord(join41(dayDir, runId));
25627
+ const record5 = readRunRecord(join42(dayDir, runId));
25392
25628
  if (record5)
25393
25629
  records.push(record5);
25394
25630
  if (records.length >= limit)
@@ -25398,25 +25634,25 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
25398
25634
  return records;
25399
25635
  }
25400
25636
  function findSkillRun(runId, targetDir = process.cwd()) {
25401
- const runsRoot = join41(getProjectStateDir(targetDir), "runs");
25637
+ const runsRoot = join42(getProjectStateDir(targetDir), "runs");
25402
25638
  if (!existsSync16(runsRoot))
25403
25639
  return null;
25404
25640
  for (const day of readdirSync15(runsRoot)) {
25405
- const record5 = readRunRecord(join41(runsRoot, day, runId));
25641
+ const record5 = readRunRecord(join42(runsRoot, day, runId));
25406
25642
  if (record5)
25407
25643
  return record5;
25408
25644
  }
25409
25645
  return null;
25410
25646
  }
25411
25647
  function getRunExportDir(runId, skill, targetDir = process.cwd()) {
25412
- return join41(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
25648
+ return join42(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
25413
25649
  }
25414
25650
  function writeRunRecord(context) {
25415
- writeFileSync10(join41(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
25651
+ writeFileSync10(join42(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
25416
25652
  `);
25417
25653
  }
25418
25654
  function writeArtifactsManifest(context, artifacts) {
25419
- writeFileSync10(join41(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
25655
+ writeFileSync10(join42(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
25420
25656
  `);
25421
25657
  }
25422
25658
  function collectRunArtifacts(context) {
@@ -25425,7 +25661,7 @@ function collectRunArtifacts(context) {
25425
25661
  const artifacts = [];
25426
25662
  for (const path of walkFiles(context.exportDir)) {
25427
25663
  const stat2 = statSync14(path);
25428
- const bytes = readFileSync27(path);
25664
+ const bytes = readFileSync28(path);
25429
25665
  artifacts.push({
25430
25666
  path: toProjectRelative(context.targetDir, path),
25431
25667
  mime: mimeForPath(path),
@@ -25436,11 +25672,11 @@ function collectRunArtifacts(context) {
25436
25672
  return artifacts.sort((a, b) => a.path.localeCompare(b.path));
25437
25673
  }
25438
25674
  function readRunRecord(runDir) {
25439
- const path = join41(runDir, "run.json");
25675
+ const path = join42(runDir, "run.json");
25440
25676
  if (!existsSync16(path))
25441
25677
  return null;
25442
25678
  try {
25443
- return JSON.parse(readFileSync27(path, "utf-8"));
25679
+ return JSON.parse(readFileSync28(path, "utf-8"));
25444
25680
  } catch {
25445
25681
  return null;
25446
25682
  }
@@ -25448,7 +25684,7 @@ function readRunRecord(runDir) {
25448
25684
  function walkFiles(dir) {
25449
25685
  const files = [];
25450
25686
  for (const entry of readdirSync15(dir)) {
25451
- const full = join41(dir, entry);
25687
+ const full = join42(dir, entry);
25452
25688
  if (statSync14(full).isDirectory())
25453
25689
  files.push(...walkFiles(full));
25454
25690
  else
@@ -45853,10 +46089,10 @@ async function readQuoteUnavailableCode(response) {
45853
46089
  let timer;
45854
46090
  let deadlineExceeded = false;
45855
46091
  const expired = Symbol("quote body deadline");
45856
- const deadline = new Promise((resolve29) => {
46092
+ const deadline = new Promise((resolve30) => {
45857
46093
  timer = setTimeout(() => {
45858
46094
  deadlineExceeded = true;
45859
- resolve29(expired);
46095
+ resolve30(expired);
45860
46096
  reader.cancel().catch(() => {});
45861
46097
  }, 1500);
45862
46098
  });
@@ -46955,23 +47191,23 @@ async function createRemoteSkillsClient(env = process.env) {
46955
47191
  return connection ? new RemoteSkillsClient(connection.apiKey, connection.apiOrigin) : null;
46956
47192
  }
46957
47193
  // src/lib/scheduler.ts
46958
- import { existsSync as existsSync17, readFileSync as readFileSync28, writeFileSync as writeFileSync11, mkdirSync as mkdirSync13 } from "fs";
46959
- import { join as join42 } from "path";
47194
+ import { existsSync as existsSync17, readFileSync as readFileSync29, writeFileSync as writeFileSync11, mkdirSync as mkdirSync13 } from "fs";
47195
+ import { join as join43 } from "path";
46960
47196
  function getSchedulesPath(targetDir = process.cwd()) {
46961
- return join42(targetDir, ".skills", "schedules.json");
47197
+ return join43(targetDir, ".skills", "schedules.json");
46962
47198
  }
46963
47199
  function loadSchedules(targetDir = process.cwd()) {
46964
47200
  const path = getSchedulesPath(targetDir);
46965
47201
  if (existsSync17(path)) {
46966
47202
  try {
46967
- return JSON.parse(readFileSync28(path, "utf-8"));
47203
+ return JSON.parse(readFileSync29(path, "utf-8"));
46968
47204
  } catch {}
46969
47205
  }
46970
47206
  return { version: 1, schedules: [] };
46971
47207
  }
46972
47208
  function saveSchedules(data, targetDir = process.cwd()) {
46973
47209
  const path = getSchedulesPath(targetDir);
46974
- const dir = join42(targetDir, ".skills");
47210
+ const dir = join43(targetDir, ".skills");
46975
47211
  if (!existsSync17(dir))
46976
47212
  mkdirSync13(dir, { recursive: true });
46977
47213
  writeFileSync11(path, JSON.stringify(data, null, 2));
@@ -47187,8 +47423,8 @@ function revisionIdOfRecord(record10) {
47187
47423
  return revisionIdOf(record10);
47188
47424
  }
47189
47425
  // src/lib/pull.ts
47190
- import { existsSync as existsSync18, mkdirSync as mkdirSync14, mkdtempSync as mkdtempSync3, readFileSync as readFileSync29, renameSync as renameSync7, rmSync as rmSync5, writeFileSync as writeFileSync12 } from "fs";
47191
- import { dirname as dirname28, join as join43 } from "path";
47426
+ import { existsSync as existsSync18, mkdirSync as mkdirSync14, mkdtempSync as mkdtempSync3, readFileSync as readFileSync30, renameSync as renameSync7, rmSync as rmSync5, writeFileSync as writeFileSync12 } from "fs";
47427
+ import { dirname as dirname29, join as join44 } from "path";
47192
47428
 
47193
47429
  // src/lib/skill-bundles.ts
47194
47430
  import { createHmac, timingSafeEqual } from "crypto";
@@ -47282,7 +47518,7 @@ async function pullOne(client2, rawName, corpusOptions, verify) {
47282
47518
  return reconcileTombstone(slug2, corpusOptions);
47283
47519
  }
47284
47520
  if (bundleResponse.status === 404) {
47285
- const marker = readPullMarker(join43(getPortableSkillsRoot(corpusOptions), slug2));
47521
+ const marker = readPullMarker(join44(getPortableSkillsRoot(corpusOptions), slug2));
47286
47522
  if (isPublishedInstallMarker(marker)) {
47287
47523
  return { name: slug2, success: true, purged: true, removed: false };
47288
47524
  }
@@ -47321,7 +47557,7 @@ async function pullOne(client2, rawName, corpusOptions, verify) {
47321
47557
  return { name: slug2, success: false, error: `Skill '${slug2}' was not found on the configured Skills instance.` };
47322
47558
  }
47323
47559
  if (!meta3?.revisionId) {
47324
- const marker = readPullMarker(join43(getPortableSkillsRoot(corpusOptions), slug2));
47560
+ const marker = readPullMarker(join44(getPortableSkillsRoot(corpusOptions), slug2));
47325
47561
  if (isPublishedInstallMarker(marker)) {
47326
47562
  return { name: slug2, success: true, purged: true, removed: false };
47327
47563
  }
@@ -47378,7 +47614,7 @@ function provenRevision(meta3, slug2, bundle2) {
47378
47614
  return declared;
47379
47615
  }
47380
47616
  function reconcileTombstone(slug2, corpusOptions) {
47381
- const target = join43(getPortableSkillsRoot(corpusOptions), slug2);
47617
+ const target = join44(getPortableSkillsRoot(corpusOptions), slug2);
47382
47618
  if (!hasSkillsOwnershipMarker(target)) {
47383
47619
  return { name: slug2, success: true, tombstoned: true, removed: false, leftInPlace: true };
47384
47620
  }
@@ -47387,7 +47623,7 @@ function reconcileTombstone(slug2, corpusOptions) {
47387
47623
  }
47388
47624
  function readPullMarker(dir) {
47389
47625
  try {
47390
- return JSON.parse(readFileSync29(join43(dir, PULL_MARKER_FILE), "utf-8"));
47626
+ return JSON.parse(readFileSync30(join44(dir, PULL_MARKER_FILE), "utf-8"));
47391
47627
  } catch {
47392
47628
  return null;
47393
47629
  }
@@ -47522,15 +47758,15 @@ function verifyBundleResponseBytes(buffer, response, verify = {}) {
47522
47758
  function installBundleAtomically(name, entries, options = {}, marker = {}) {
47523
47759
  const root2 = getPortableSkillsRoot(options);
47524
47760
  mkdirSync14(root2, { recursive: true });
47525
- const target = join43(root2, name);
47761
+ const target = join44(root2, name);
47526
47762
  const created = !existsSync18(target);
47527
- const staging = mkdtempSync3(join43(root2, `.pull-${name}-`));
47763
+ const staging = mkdtempSync3(join44(root2, `.pull-${name}-`));
47528
47764
  let moved = false;
47529
47765
  let backup = null;
47530
47766
  try {
47531
47767
  for (const entry of entries) {
47532
- const destination = join43(staging, entry.path);
47533
- mkdirSync14(dirname28(destination), { recursive: true });
47768
+ const destination = join44(staging, entry.path);
47769
+ mkdirSync14(dirname29(destination), { recursive: true });
47534
47770
  writeFileSync12(destination, entry.bytes, { mode: entry.mode });
47535
47771
  }
47536
47772
  writePullMarker(staging, {
@@ -47542,8 +47778,8 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
47542
47778
  ...marker.revisionId ? { revisionId: marker.revisionId } : {}
47543
47779
  });
47544
47780
  if (existsSync18(target)) {
47545
- backup = mkdtempSync3(join43(root2, `.pull-backup-${name}-`));
47546
- renameSync7(target, join43(backup, name));
47781
+ backup = mkdtempSync3(join44(root2, `.pull-backup-${name}-`));
47782
+ renameSync7(target, join44(backup, name));
47547
47783
  moved = true;
47548
47784
  }
47549
47785
  renameSync7(staging, target);
@@ -47551,9 +47787,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
47551
47787
  rmSync5(backup, { recursive: true, force: true });
47552
47788
  } catch (error61) {
47553
47789
  rmSync5(staging, { recursive: true, force: true });
47554
- if (moved && backup && existsSync18(join43(backup, name))) {
47790
+ if (moved && backup && existsSync18(join44(backup, name))) {
47555
47791
  try {
47556
- renameSync7(join43(backup, name), target);
47792
+ renameSync7(join44(backup, name), target);
47557
47793
  } catch {}
47558
47794
  }
47559
47795
  throw error61;
@@ -47572,7 +47808,7 @@ function writePullMarker(dir, record10) {
47572
47808
  ...record10.revisionId ? { revisionId: record10.revisionId } : {},
47573
47809
  syncedAt: new Date().toISOString()
47574
47810
  };
47575
- writeFileSync12(join43(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
47811
+ writeFileSync12(join44(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
47576
47812
  `);
47577
47813
  }
47578
47814
  async function safeMeta(client2, slug2) {
@@ -48014,12 +48250,12 @@ class RemotePrivatePublicationsClient {
48014
48250
  previous = view;
48015
48251
  if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
48016
48252
  return view;
48017
- await new Promise((resolve29) => {
48253
+ await new Promise((resolve30) => {
48018
48254
  const timer = setTimeout(done, Math.min(1000, until - Date.now()));
48019
48255
  function done() {
48020
48256
  clearTimeout(timer);
48021
48257
  options.signal?.removeEventListener("abort", done);
48022
- resolve29();
48258
+ resolve30();
48023
48259
  }
48024
48260
  options.signal?.addEventListener("abort", done, { once: true });
48025
48261
  });
@@ -48434,7 +48670,7 @@ function findSkillsParityForMcpTool(tool) {
48434
48670
  }
48435
48671
  // src/lib/registry-sync.ts
48436
48672
  import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync13 } from "fs";
48437
- import { dirname as dirname29, relative as relative13 } from "path";
48673
+ import { dirname as dirname30, relative as relative13 } from "path";
48438
48674
  function createRegistrySyncArtifact(options = {}) {
48439
48675
  const profile = options.profile ?? "all";
48440
48676
  const includeDocs = options.includeDocs ?? true;
@@ -48491,7 +48727,7 @@ function createRegistrySyncArtifact(options = {}) {
48491
48727
  };
48492
48728
  }
48493
48729
  function writeRegistrySyncArtifact(path, artifact) {
48494
- mkdirSync15(dirname29(path), { recursive: true });
48730
+ mkdirSync15(dirname30(path), { recursive: true });
48495
48731
  writeFileSync13(path, `${JSON.stringify(artifact, null, 2)}
48496
48732
  `);
48497
48733
  }
@@ -49576,14 +49812,14 @@ function clone3(value) {
49576
49812
  }
49577
49813
  // src/lib/feedback.ts
49578
49814
  import { appendFileSync, existsSync as existsSync19, mkdirSync as mkdirSync16 } from "fs";
49579
- import { dirname as dirname30, join as join44 } from "path";
49815
+ import { dirname as dirname31, join as join45 } from "path";
49580
49816
  import { Database } from "bun:sqlite";
49581
49817
  function getFeedbackDbPath() {
49582
- return join44(getDataDir(), "skills.db");
49818
+ return join45(getDataDir(), "skills.db");
49583
49819
  }
49584
49820
  function getFeedbackDb() {
49585
49821
  const dbPath = getFeedbackDbPath();
49586
- const dir = dirname30(dbPath);
49822
+ const dir = dirname31(dbPath);
49587
49823
  if (!existsSync19(dir))
49588
49824
  mkdirSync16(dir, { recursive: true });
49589
49825
  const db = new Database(dbPath);
@@ -49611,8 +49847,8 @@ function saveFeedback(input2) {
49611
49847
  throw new Error("Feedback message is required");
49612
49848
  const category = input2.category ?? "general";
49613
49849
  if (isApiMode()) {
49614
- const path = join44(getDataDir(), "feedback.jsonl");
49615
- const dir = dirname30(path);
49850
+ const path = join45(getDataDir(), "feedback.jsonl");
49851
+ const dir = dirname31(path);
49616
49852
  if (!existsSync19(dir))
49617
49853
  mkdirSync16(dir, { recursive: true });
49618
49854
  appendFileSync(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
@@ -49639,12 +49875,12 @@ import { createHash as createHash35, createHmac as createHmac2 } from "crypto";
49639
49875
  import {
49640
49876
  existsSync as existsSync20,
49641
49877
  mkdirSync as mkdirSync17,
49642
- readFileSync as readFileSync30,
49878
+ readFileSync as readFileSync31,
49643
49879
  readdirSync as readdirSync16,
49644
49880
  statSync as statSync15,
49645
49881
  writeFileSync as writeFileSync14
49646
49882
  } from "fs";
49647
- import { dirname as dirname31, join as join45, normalize as normalize5, relative as relative14, sep as sep17 } from "path";
49883
+ import { dirname as dirname32, join as join46, normalize as normalize5, relative as relative14, sep as sep18 } from "path";
49648
49884
  var SKILLS_STORAGE_TABLES = [
49649
49885
  "skills_sync_records",
49650
49886
  "skills_sync_cursors"
@@ -49781,7 +50017,7 @@ function getSkillsNativeStorageStatus(options = {}) {
49781
50017
  local: {
49782
50018
  dataDir: getDataDir(),
49783
50019
  projectStateDir: getProjectStateDir(targetDir),
49784
- feedbackDbPath: join45(getDataDir(), "skills.db")
50020
+ feedbackDbPath: join46(getDataDir(), "skills.db")
49785
50021
  },
49786
50022
  remote: {
49787
50023
  databaseConfigured: Boolean(config2.databaseUrl),
@@ -49806,7 +50042,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
49806
50042
  const files = [];
49807
50043
  if (existsSync20(projectStateDir)) {
49808
50044
  for (const filePath of walkFiles2(projectStateDir)) {
49809
- const bytes = readFileSync30(filePath);
50045
+ const bytes = readFileSync31(filePath);
49810
50046
  const relativePath = toPosix(relative14(targetDir, filePath));
49811
50047
  files.push({
49812
50048
  path: relativePath,
@@ -49840,7 +50076,7 @@ function importSkillsLocalSnapshot(snapshot2, targetDir = process.cwd(), options
49840
50076
  if (hash5 !== file2.sha256) {
49841
50077
  throw new Error(`Snapshot file checksum mismatch: ${file2.path}`);
49842
50078
  }
49843
- mkdirSync17(dirname31(absolutePath5), { recursive: true });
50079
+ mkdirSync17(dirname32(absolutePath5), { recursive: true });
49844
50080
  writeFileSync14(absolutePath5, bytes);
49845
50081
  written += 1;
49846
50082
  }
@@ -50138,7 +50374,7 @@ function parsePositiveInteger(value) {
50138
50374
  function walkFiles2(dir) {
50139
50375
  const files = [];
50140
50376
  for (const entry of readdirSync16(dir)) {
50141
- const full = join45(dir, entry);
50377
+ const full = join46(dir, entry);
50142
50378
  const stats = statSync15(full);
50143
50379
  if (stats.isDirectory())
50144
50380
  files.push(...walkFiles2(full));
@@ -50149,13 +50385,13 @@ function walkFiles2(dir) {
50149
50385
  }
50150
50386
  function resolveSnapshotPath(targetDir, snapshotPath) {
50151
50387
  const normalizedPath = normalize5(snapshotPath);
50152
- if (normalizedPath.startsWith("..") || normalizedPath.includes(`${sep17}..${sep17}`) || normalizedPath.startsWith(sep17)) {
50388
+ if (normalizedPath.startsWith("..") || normalizedPath.includes(`${sep18}..${sep18}`) || normalizedPath.startsWith(sep18)) {
50153
50389
  throw new Error(`Unsafe snapshot path: ${snapshotPath}`);
50154
50390
  }
50155
50391
  if (!toPosix(normalizedPath).startsWith(".skills/")) {
50156
50392
  throw new Error(`Snapshot path must stay inside .skills: ${snapshotPath}`);
50157
50393
  }
50158
- return join45(targetDir, normalizedPath);
50394
+ return join46(targetDir, normalizedPath);
50159
50395
  }
50160
50396
  function normalizeS3Prefix(prefix) {
50161
50397
  return (prefix ?? "").trim().replace(/^\/+|\/+$/g, "");
@@ -50224,16 +50460,16 @@ import { createHash as createHash36 } from "crypto";
50224
50460
  import {
50225
50461
  copyFileSync,
50226
50462
  mkdirSync as mkdirSync18,
50227
- readFileSync as readFileSync31,
50463
+ readFileSync as readFileSync32,
50228
50464
  statSync as statSync17,
50229
50465
  writeFileSync as writeFileSync15
50230
50466
  } from "fs";
50231
- import { dirname as dirname32, isAbsolute as isAbsolute31, relative as relative15, resolve as resolve29, sep as sep19 } from "path";
50467
+ import { dirname as dirname33, isAbsolute as isAbsolute31, relative as relative15, resolve as resolve30, sep as sep20 } from "path";
50232
50468
 
50233
50469
  // src/lib/portable-snapshot-filter.ts
50234
50470
  import { readdirSync as readdirSync17, statSync as statSync16 } from "fs";
50235
50471
  import { homedir as homedir7 } from "os";
50236
- import { join as join46, sep as sep18 } from "path";
50472
+ import { join as join47, sep as sep19 } from "path";
50237
50473
  var SYNC_HOMES = [
50238
50474
  { name: "skills", subClass: "skills", agent: null },
50239
50475
  { name: "custom", subClass: "custom", agent: null },
@@ -50326,16 +50562,16 @@ function isPortableWithinSkill(relativeParts) {
50326
50562
  function homePathFor(definition, homesRoot) {
50327
50563
  const home = homesRoot ?? homedir7();
50328
50564
  if (definition.subClass === "skills" || definition.subClass === "custom") {
50329
- return join46(skillsDataRootForHome(home), definition.name);
50565
+ return join47(skillsDataRootForHome(home), definition.name);
50330
50566
  }
50331
50567
  if (definition.agent === "opencode") {
50332
- return join46(home, ".config", "opencode", "skills");
50568
+ return join47(home, ".config", "opencode", "skills");
50333
50569
  }
50334
- return join46(home, `.${definition.agent}`, "skills");
50570
+ return join47(home, `.${definition.agent}`, "skills");
50335
50571
  }
50336
50572
  function destinationFor(definition, stationId, relativePath) {
50337
- const category = definition.subClass === "agent-homes" ? join46("agent-homes", definition.agent ?? "") : definition.name;
50338
- return join46("resources", stationId, "skills", category, ...relativePath.split(sep18));
50573
+ const category = definition.subClass === "agent-homes" ? join47("agent-homes", definition.agent ?? "") : definition.name;
50574
+ return join47("resources", stationId, "skills", category, ...relativePath.split(sep19));
50339
50575
  }
50340
50576
  function walkEntries(absoluteRoot) {
50341
50577
  let entries;
@@ -50346,7 +50582,7 @@ function walkEntries(absoluteRoot) {
50346
50582
  }
50347
50583
  const output2 = [];
50348
50584
  for (const entry of entries) {
50349
- const childFull = join46(absoluteRoot, entry.name);
50585
+ const childFull = join47(absoluteRoot, entry.name);
50350
50586
  if (entry.isSymbolicLink()) {
50351
50587
  output2.push({ kind: "symlink", relativePath: entry.name, fullPath: childFull });
50352
50588
  continue;
@@ -50357,7 +50593,7 @@ function walkEntries(absoluteRoot) {
50357
50593
  }
50358
50594
  const nested = walkEntries(childFull);
50359
50595
  for (const item of nested) {
50360
- output2.push({ ...item, relativePath: join46(entry.name, item.relativePath) });
50596
+ output2.push({ ...item, relativePath: join47(entry.name, item.relativePath) });
50361
50597
  }
50362
50598
  continue;
50363
50599
  }
@@ -50395,7 +50631,7 @@ function validateStationId(stationId) {
50395
50631
  }
50396
50632
  }
50397
50633
  function sha256File(filePath) {
50398
- return createHash36("sha256").update(readFileSync31(filePath)).digest("hex");
50634
+ return createHash36("sha256").update(readFileSync32(filePath)).digest("hex");
50399
50635
  }
50400
50636
  function scanHome(definition, homesRoot) {
50401
50637
  const homePath = homePathFor(definition, homesRoot);
@@ -50403,7 +50639,7 @@ function scanHome(definition, homesRoot) {
50403
50639
  const portable = [];
50404
50640
  const skipped = [];
50405
50641
  for (const entry of entries) {
50406
- const relativeParts = entry.relativePath.split(sep19);
50642
+ const relativeParts = entry.relativePath.split(sep20);
50407
50643
  const fileName = relativeParts[relativeParts.length - 1];
50408
50644
  if (entry.kind === "symlink") {
50409
50645
  skipped.push({ relativePath: entry.relativePath, reason: "symlink" });
@@ -50466,7 +50702,7 @@ function humanHomes(scanned) {
50466
50702
  }));
50467
50703
  }
50468
50704
  function writeStationSnapshot(options) {
50469
- const repoRoot = resolve29(options.repoRoot ?? process.cwd());
50705
+ const repoRoot = resolve30(options.repoRoot ?? process.cwd());
50470
50706
  const { scanned, plans, totalBytes } = planStationSnapshot(options);
50471
50707
  const manifestFiles = plans.map((plan) => ({
50472
50708
  relativePath: plan.source.relativePath,
@@ -50492,9 +50728,9 @@ function writeStationSnapshot(options) {
50492
50728
  const conflicts = [];
50493
50729
  const untouched = [];
50494
50730
  for (const plan of plans) {
50495
- const destination = resolve29(repoRoot, plan.destination);
50731
+ const destination = resolve30(repoRoot, plan.destination);
50496
50732
  const destinationRelative = relative15(repoRoot, destination);
50497
- if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep19) || isAbsolute31(destinationRelative)) {
50733
+ if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep20) || isAbsolute31(destinationRelative)) {
50498
50734
  throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
50499
50735
  }
50500
50736
  let existingDigest = null;
@@ -50515,8 +50751,8 @@ function writeStationSnapshot(options) {
50515
50751
  }
50516
50752
  let written = 0;
50517
50753
  for (const plan of untouched) {
50518
- const destination = resolve29(repoRoot, plan.destination);
50519
- mkdirSync18(dirname32(destination), { recursive: true });
50754
+ const destination = resolve30(repoRoot, plan.destination);
50755
+ mkdirSync18(dirname33(destination), { recursive: true });
50520
50756
  copyFileSync(plan.source.fullPath, destination);
50521
50757
  written += 1;
50522
50758
  }
@@ -50534,8 +50770,8 @@ function writeStationSnapshot(options) {
50534
50770
  },
50535
50771
  files: manifestFiles
50536
50772
  };
50537
- const manifestPath = resolve29(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
50538
- mkdirSync18(dirname32(manifestPath), { recursive: true });
50773
+ const manifestPath = resolve30(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
50774
+ mkdirSync18(dirname33(manifestPath), { recursive: true });
50539
50775
  writeFileSync15(manifestPath, `${JSON.stringify(manifest, null, 2)}
50540
50776
  `);
50541
50777
  return {
@@ -50551,11 +50787,11 @@ import {
50551
50787
  copyFileSync as copyFileSync2,
50552
50788
  mkdirSync as mkdirSync19,
50553
50789
  readdirSync as readdirSync18,
50554
- readFileSync as readFileSync32,
50790
+ readFileSync as readFileSync33,
50555
50791
  statSync as statSync18,
50556
50792
  writeFileSync as writeFileSync16
50557
50793
  } from "fs";
50558
- import { dirname as dirname33, join as join47, resolve as resolve30, sep as sep20 } from "path";
50794
+ import { dirname as dirname34, join as join48, resolve as resolve31, sep as sep21 } from "path";
50559
50795
  var STATION_HYDRATION_MANIFEST_SCHEMA = "hasna.fleet-resources.skills-hydration-manifest/v1";
50560
50796
  var STATION_HYDRATION_PRODUCER = { name: "@hasna/skills", version: package_default.version };
50561
50797
  var MANIFEST_HASH_KEY_SEP = String.fromCharCode(0);
@@ -50563,14 +50799,14 @@ function fail2(code2, message, detail = []) {
50563
50799
  throw new StationSnapshotError(code2, message, detail);
50564
50800
  }
50565
50801
  function snapshotRootFor(repoRoot, stationId) {
50566
- return join47(repoRoot, "resources", stationId, "skills");
50802
+ return join48(repoRoot, "resources", stationId, "skills");
50567
50803
  }
50568
50804
  function readSnapshotManifest(repoRoot, stationId) {
50569
50805
  const snapshotRoot = snapshotRootFor(repoRoot, stationId);
50570
- const manifestPath = join47(snapshotRoot, "sync-manifest.json");
50806
+ const manifestPath = join48(snapshotRoot, "sync-manifest.json");
50571
50807
  let manifest;
50572
50808
  try {
50573
- manifest = JSON.parse(readFileSync32(manifestPath, "utf8"));
50809
+ manifest = JSON.parse(readFileSync33(manifestPath, "utf8"));
50574
50810
  } catch (error61) {
50575
50811
  fail2("MANIFEST_UNREADABLE", `cannot read snapshot manifest: ${manifestPath}: ${error61.message}`);
50576
50812
  }
@@ -50594,7 +50830,7 @@ function planStationHydration(stationId, repoRoot) {
50594
50830
  const hashMismatches = [];
50595
50831
  const skippedByRule = [];
50596
50832
  for (const agent of SYNC_AGENTS) {
50597
- const agentRoot = join47(snapshotRoot, "agent-homes", agent);
50833
+ const agentRoot = join48(snapshotRoot, "agent-homes", agent);
50598
50834
  let identEntries;
50599
50835
  try {
50600
50836
  identEntries = readdirSync18(agentRoot, { withFileTypes: true });
@@ -50605,10 +50841,10 @@ function planStationHydration(stationId, repoRoot) {
50605
50841
  if (!identEntry.isDirectory() || identEntry.name.startsWith(".")) {
50606
50842
  continue;
50607
50843
  }
50608
- const identRoot = join47(agentRoot, identEntry.name);
50844
+ const identRoot = join48(agentRoot, identEntry.name);
50609
50845
  const entries = walkEntries(identRoot);
50610
50846
  for (const entry of entries) {
50611
- const relativeParts = [identEntry.name, ...entry.relativePath.split(sep20)];
50847
+ const relativeParts = [identEntry.name, ...entry.relativePath.split(sep21)];
50612
50848
  if (entry.kind === "symlink") {
50613
50849
  symlinks.push({ ident: identEntry.name, agent, relativePath: entry.relativePath });
50614
50850
  continue;
@@ -50632,8 +50868,8 @@ function planStationHydration(stationId, repoRoot) {
50632
50868
  });
50633
50869
  continue;
50634
50870
  }
50635
- const withinIdent = relativeParts.slice(1).join(sep20);
50636
- const homeRelative = relativeParts.join(sep20);
50871
+ const withinIdent = relativeParts.slice(1).join(sep21);
50872
+ const homeRelative = relativeParts.join(sep21);
50637
50873
  if (REFUSED_SCANNER_FLAGGED.has(homeRelative)) {
50638
50874
  skippedByRule.push({
50639
50875
  ident: identEntry.name,
@@ -50706,7 +50942,7 @@ function planStationHydration(stationId, repoRoot) {
50706
50942
  for (const copy of copies) {
50707
50943
  let isStub = false;
50708
50944
  try {
50709
- isStub = isPointerSkillMd(readFileSync32(copy.fullPath, "utf8"));
50945
+ isStub = isPointerSkillMd(readFileSync33(copy.fullPath, "utf8"));
50710
50946
  } catch {
50711
50947
  isStub = false;
50712
50948
  }
@@ -50756,8 +50992,8 @@ function skillSha256(skill) {
50756
50992
  `)).digest("hex");
50757
50993
  }
50758
50994
  function writeStationHydration(options) {
50759
- const repoRoot = resolve30(options.repoRoot ?? process.cwd());
50760
- const cacheRoot = resolve30(options.cacheRoot ?? resolveCorpusRoot());
50995
+ const repoRoot = resolve31(options.repoRoot ?? process.cwd());
50996
+ const cacheRoot = resolve31(options.cacheRoot ?? resolveCorpusRoot());
50761
50997
  const plan = planStationHydration(options.stationId, repoRoot);
50762
50998
  const resultSkills = plan.winners.map((skill) => ({
50763
50999
  ident: skill.ident,
@@ -50790,7 +51026,7 @@ function writeStationHydration(options) {
50790
51026
  const toWrite = [];
50791
51027
  for (const skill of plan.winners) {
50792
51028
  for (const file2 of skill.files) {
50793
- const destination = join47(cacheRoot, skill.ident, file2.withinIdent);
51029
+ const destination = join48(cacheRoot, skill.ident, file2.withinIdent);
50794
51030
  const digest4 = sha256File(file2.winner.fullPath);
50795
51031
  let existingDigest = null;
50796
51032
  try {
@@ -50811,7 +51047,7 @@ function writeStationHydration(options) {
50811
51047
  }
50812
51048
  let written = 0;
50813
51049
  for (const entry of toWrite) {
50814
- mkdirSync19(dirname33(entry.destination), { recursive: true });
51050
+ mkdirSync19(dirname34(entry.destination), { recursive: true });
50815
51051
  copyFileSync2(entry.fullPath, entry.destination);
50816
51052
  written += 1;
50817
51053
  }
@@ -50832,8 +51068,8 @@ function writeStationHydration(options) {
50832
51068
  },
50833
51069
  skills: resultSkills
50834
51070
  };
50835
- const hydrationManifestPath = join47(dirname33(cacheRoot), `hydration-${options.stationId}.json`);
50836
- mkdirSync19(dirname33(hydrationManifestPath), { recursive: true });
51071
+ const hydrationManifestPath = join48(dirname34(cacheRoot), `hydration-${options.stationId}.json`);
51072
+ mkdirSync19(dirname34(hydrationManifestPath), { recursive: true });
50837
51073
  writeFileSync16(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
50838
51074
  `);
50839
51075
  return {
@@ -50844,23 +51080,23 @@ function writeStationHydration(options) {
50844
51080
  };
50845
51081
  }
50846
51082
  // src/lib/private-publication-recovery.ts
50847
- import { constants as constants21, closeSync as closeSync20, fsyncSync as fsyncSync8, fstatSync as fstatSync20, lstatSync as lstatSync33, mkdirSync as mkdirSync20, openSync as openSync20, readSync as readSync15, realpathSync as realpathSync16, renameSync as renameSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync17 } from "fs";
50848
- import { dirname as dirname34, isAbsolute as isAbsolute32, join as join48, resolve as resolve31 } from "path";
51083
+ import { constants as constants21, closeSync as closeSync20, fsyncSync as fsyncSync8, fstatSync as fstatSync20, lstatSync as lstatSync34, mkdirSync as mkdirSync20, openSync as openSync20, readSync as readSync15, realpathSync as realpathSync16, renameSync as renameSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync17 } from "fs";
51084
+ import { dirname as dirname35, isAbsolute as isAbsolute32, join as join49, resolve as resolve32 } from "path";
50849
51085
  import { randomUUID as randomUUID5 } from "crypto";
50850
51086
  var fail3 = () => {
50851
51087
  throw new PrivatePublicationError("PUBLICATION_RECOVERY_INVALID", "The recovery directory is invalid or changed. Preserve it and inspect the existing intent; do not start a replacement automatically.");
50852
51088
  };
50853
51089
  function safeDirectory(directory3) {
50854
- if (!isAbsolute32(directory3) || directory3 !== resolve31(directory3) || realpathSync16(directory3) !== directory3)
51090
+ if (!isAbsolute32(directory3) || directory3 !== resolve32(directory3) || realpathSync16(directory3) !== directory3)
50855
51091
  return fail3();
50856
- for (let path = directory3;; path = dirname34(path)) {
50857
- const stat2 = lstatSync33(path);
51092
+ for (let path = directory3;; path = dirname35(path)) {
51093
+ const stat2 = lstatSync34(path);
50858
51094
  if (!stat2.isDirectory() || stat2.isSymbolicLink())
50859
51095
  return fail3();
50860
- if (path === dirname34(path))
51096
+ if (path === dirname35(path))
50861
51097
  break;
50862
51098
  }
50863
- const own2 = lstatSync33(directory3);
51099
+ const own2 = lstatSync34(directory3);
50864
51100
  if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
50865
51101
  return fail3();
50866
51102
  return { dev: own2.dev, ino: own2.ino };
@@ -50871,7 +51107,7 @@ function unchangedDirectory(directory3, identity5) {
50871
51107
  return fail3();
50872
51108
  }
50873
51109
  function readOwned(directory3, name, max) {
50874
- const identity5 = safeDirectory(directory3), file2 = join48(directory3, name);
51110
+ const identity5 = safeDirectory(directory3), file2 = join49(directory3, name);
50875
51111
  const fd = openSync20(file2, constants21.O_RDONLY | constants21.O_NOFOLLOW);
50876
51112
  try {
50877
51113
  const stat2 = fstatSync20(fd);
@@ -50895,7 +51131,7 @@ function readOwned(directory3, name, max) {
50895
51131
  }
50896
51132
  }
50897
51133
  function writeOwned(directory3, name, bytes) {
50898
- const fd = openSync20(join48(directory3, name), constants21.O_WRONLY | constants21.O_CREAT | constants21.O_EXCL | constants21.O_NOFOLLOW, 384);
51134
+ const fd = openSync20(join49(directory3, name), constants21.O_WRONLY | constants21.O_CREAT | constants21.O_EXCL | constants21.O_NOFOLLOW, 384);
50899
51135
  try {
50900
51136
  writeFileSync17(fd, bytes);
50901
51137
  fsyncSync8(fd);
@@ -50908,7 +51144,7 @@ function save(directory3, value) {
50908
51144
  writeOwned(directory3, temporary, JSON.stringify(value) + `
50909
51145
  `);
50910
51146
  unchangedDirectory(directory3, identity5);
50911
- renameSync8(join48(directory3, temporary), join48(directory3, "receipt.json"));
51147
+ renameSync8(join49(directory3, temporary), join49(directory3, "receipt.json"));
50912
51148
  const fd = openSync20(directory3, constants21.O_RDONLY | constants21.O_NOFOLLOW);
50913
51149
  try {
50914
51150
  fsyncSync8(fd);
@@ -50921,7 +51157,7 @@ function bind(client2, receipt) {
50921
51157
  throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
50922
51158
  }
50923
51159
  async function locked(directory3, action) {
50924
- const identity5 = safeDirectory(directory3), file2 = join48(directory3, "operation.lock");
51160
+ const identity5 = safeDirectory(directory3), file2 = join49(directory3, "operation.lock");
50925
51161
  let fd;
50926
51162
  try {
50927
51163
  fd = openSync20(file2, constants21.O_WRONLY | constants21.O_CREAT | constants21.O_EXCL | constants21.O_NOFOLLOW, 384);
@@ -50937,7 +51173,7 @@ async function locked(directory3, action) {
50937
51173
  } finally {
50938
51174
  closeSync20(fd);
50939
51175
  unchangedDirectory(directory3, identity5);
50940
- const now = lstatSync33(file2);
51176
+ const now = lstatSync34(file2);
50941
51177
  if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
50942
51178
  fail3();
50943
51179
  unlinkSync6(file2);
@@ -50989,11 +51225,11 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
50989
51225
  phase: "prepared",
50990
51226
  intent: null
50991
51227
  };
50992
- if (!isAbsolute32(recoveryDirectory) || resolve31(recoveryDirectory) !== recoveryDirectory || realpathSync16(dirname34(recoveryDirectory)) !== dirname34(recoveryDirectory))
51228
+ if (!isAbsolute32(recoveryDirectory) || resolve32(recoveryDirectory) !== recoveryDirectory || realpathSync16(dirname35(recoveryDirectory)) !== dirname35(recoveryDirectory))
50993
51229
  return fail3();
50994
51230
  mkdirSync20(recoveryDirectory, { mode: 448 });
50995
51231
  safeDirectory(recoveryDirectory);
50996
- const parent = openSync20(dirname34(recoveryDirectory), constants21.O_RDONLY | constants21.O_NOFOLLOW);
51232
+ const parent = openSync20(dirname35(recoveryDirectory), constants21.O_RDONLY | constants21.O_NOFOLLOW);
50997
51233
  try {
50998
51234
  fsyncSync8(parent);
50999
51235
  } finally {
@@ -51081,7 +51317,7 @@ async function inspectLocked(client2, directory3, cancel) {
51081
51317
  }
51082
51318
  // src/lib/skill-context.ts
51083
51319
  import { createHash as createHash38 } from "crypto";
51084
- import { resolve as resolve32 } from "path";
51320
+ import { resolve as resolve33 } from "path";
51085
51321
  function words(value) {
51086
51322
  return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
51087
51323
  }
@@ -51120,7 +51356,7 @@ async function buildSkillContext(input2, options = {}) {
51120
51356
  const promptWords = words(prompt);
51121
51357
  const promptNames = new Set(prompt.toLowerCase().match(/[a-z0-9]+(?:-[a-z0-9]+)*/g) ?? []);
51122
51358
  const loaded = new Set(resolved.session?.loaded ?? []);
51123
- const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd, resolve32(input2.cwd)] : []];
51359
+ const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd, resolve33(input2.cwd)] : []];
51124
51360
  const candidates = profile.selections.map((selection) => {
51125
51361
  const key2 = selectionKey(selection);
51126
51362
  if (input2.restore && loaded.has(key2))
@@ -51315,8 +51551,8 @@ function applySessionReconciliation(snapshot2, target, planned, record12, verifi
51315
51551
  }
51316
51552
  // src/lib/claude-prospective-review.ts
51317
51553
  import { createHash as createHash40 } from "crypto";
51318
- import { lstatSync as lstatSync34, readFileSync as readFileSync33, readdirSync as readdirSync19, realpathSync as realpathSync17 } from "fs";
51319
- import { basename as basename18, dirname as dirname35, isAbsolute as isAbsolute33, join as join49, relative as relative16, resolve as resolve33, sep as sep21 } from "path";
51554
+ import { lstatSync as lstatSync35, readFileSync as readFileSync34, readdirSync as readdirSync19, realpathSync as realpathSync17 } from "fs";
51555
+ import { basename as basename18, dirname as dirname36, isAbsolute as isAbsolute33, join as join50, relative as relative16, resolve as resolve34, sep as sep22 } from "path";
51320
51556
  var MAX_CANDIDATE_FILES = 16384;
51321
51557
  var MAX_CANDIDATE_BYTES = 256 * 1024 * 1024;
51322
51558
  var sha7 = (data) => createHash40("sha256").update(data).digest("hex");
@@ -51327,32 +51563,32 @@ var GENERATED_MARKETPLACE_TIME = Object.freeze({ $generated: "claude-utc-timesta
51327
51563
  var GENERATED_FRESH_PLUGIN_INSTALLED_AT = Object.freeze({ $generated: "claude-utc-timestamp", field: "installed_plugins.fresh-row.installedAt" });
51328
51564
  var GENERATED_PLUGIN_UPDATE_TIME = Object.freeze({ $generated: "claude-utc-timestamp", field: "installed_plugins.selected-row.lastUpdated" });
51329
51565
  function abs(path, name) {
51330
- if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !isAbsolute33(path) || resolve33(path) !== path)
51566
+ if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !isAbsolute33(path) || resolve34(path) !== path)
51331
51567
  refuse6(`${name} must be a normalized absolute path`);
51332
51568
  }
51333
51569
  function safeFile(path, name) {
51334
51570
  abs(path, name);
51335
- for (let at = dirname35(path);; at = dirname35(at)) {
51336
- const stat3 = lstatSync34(at, { throwIfNoEntry: false });
51571
+ for (let at = dirname36(path);; at = dirname36(at)) {
51572
+ const stat3 = lstatSync35(at, { throwIfNoEntry: false });
51337
51573
  if (!stat3?.isDirectory() || stat3.isSymbolicLink())
51338
51574
  refuse6(`${name} traverses a symlink or non-directory`);
51339
- if (at === dirname35(at))
51575
+ if (at === dirname36(at))
51340
51576
  break;
51341
51577
  }
51342
- const stat2 = lstatSync34(path, { throwIfNoEntry: false });
51578
+ const stat2 = lstatSync35(path, { throwIfNoEntry: false });
51343
51579
  if (!stat2?.isFile() || stat2.isSymbolicLink() || stat2.size > MAX_CANDIDATE_BYTES)
51344
51580
  refuse6(`${name} is not a bounded regular file`);
51345
- return readFileSync33(path);
51581
+ return readFileSync34(path);
51346
51582
  }
51347
51583
  function canonicalDir(path, name) {
51348
51584
  abs(path, name);
51349
- if (realpathSync17(path) !== path || !lstatSync34(path).isDirectory())
51585
+ if (realpathSync17(path) !== path || !lstatSync35(path).isDirectory())
51350
51586
  refuse6(`${name} is not a canonical directory`);
51351
- for (let at = path;; at = dirname35(at)) {
51352
- const stat2 = lstatSync34(at);
51587
+ for (let at = path;; at = dirname36(at)) {
51588
+ const stat2 = lstatSync35(at);
51353
51589
  if (!stat2.isDirectory() || stat2.isSymbolicLink())
51354
51590
  refuse6(`${name} traverses a symlink`);
51355
- if (at === dirname35(at))
51591
+ if (at === dirname36(at))
51356
51592
  break;
51357
51593
  }
51358
51594
  }
@@ -51361,17 +51597,17 @@ function captureClaudeProspectiveCandidateClosure(root2) {
51361
51597
  const entries = [];
51362
51598
  let bytes = 0;
51363
51599
  const walk2 = (directory3) => {
51364
- const beforeDirectory = lstatSync34(directory3);
51600
+ const beforeDirectory = lstatSync35(directory3);
51365
51601
  const names = readdirSync19(directory3).sort();
51366
51602
  if (new Set(names).size !== names.length)
51367
51603
  refuse6("candidate contains ambiguous directory entries");
51368
51604
  for (const name of names) {
51369
51605
  if (!name || name === "." || name === ".." || name.includes("/") || name.includes("\\") || /[\x00-\x1f\x7f]/.test(name))
51370
51606
  refuse6("candidate contains an unsupported path member");
51371
- const path = join49(directory3, name), rel = relative16(root2, path).split(sep21).join("/");
51607
+ const path = join50(directory3, name), rel = relative16(root2, path).split(sep22).join("/");
51372
51608
  if (entries.length >= MAX_CANDIDATE_FILES)
51373
51609
  refuse6("candidate closure exceeds its member limit");
51374
- const stat2 = lstatSync34(path);
51610
+ const stat2 = lstatSync35(path);
51375
51611
  if (stat2.isSymbolicLink())
51376
51612
  refuse6("candidate closure contains a symlink");
51377
51613
  if (stat2.isDirectory()) {
@@ -51381,14 +51617,14 @@ function captureClaudeProspectiveCandidateClosure(root2) {
51381
51617
  bytes += stat2.size;
51382
51618
  if (bytes > MAX_CANDIDATE_BYTES)
51383
51619
  refuse6("candidate closure exceeds its byte limit");
51384
- const content = safeFile(path, "candidate member"), after = lstatSync34(path);
51620
+ const content = safeFile(path, "candidate member"), after = lstatSync35(path);
51385
51621
  if (!after.isFile() || after.dev !== stat2.dev || after.ino !== stat2.ino || after.size !== stat2.size || after.mtimeMs !== stat2.mtimeMs || after.ctimeMs !== stat2.ctimeMs)
51386
51622
  refuse6("candidate member changed while being read");
51387
51623
  entries.push([rel, "file", sha7(content)]);
51388
51624
  } else
51389
51625
  refuse6("candidate closure contains a special file");
51390
51626
  }
51391
- const afterDirectory = lstatSync34(directory3);
51627
+ const afterDirectory = lstatSync35(directory3);
51392
51628
  if (!afterDirectory.isDirectory() || afterDirectory.dev !== beforeDirectory.dev || afterDirectory.ino !== beforeDirectory.ino || afterDirectory.mtimeMs !== beforeDirectory.mtimeMs || afterDirectory.ctimeMs !== beforeDirectory.ctimeMs)
51393
51629
  refuse6("candidate directory changed while being read");
51394
51630
  };
@@ -51396,6 +51632,21 @@ function captureClaudeProspectiveCandidateClosure(root2) {
51396
51632
  entries.sort((a, b) => a[0].localeCompare(b[0]));
51397
51633
  return sha7(JSON.stringify(entries));
51398
51634
  }
51635
+ var EXEMPT_PROJECT_SETTINGS = new Map([
51636
+ ["permissions", "object"],
51637
+ ["outputStyle", "string"],
51638
+ ["model", "string"],
51639
+ ["theme", "string"],
51640
+ ["effortLevel", "string"],
51641
+ ["verbose", "boolean"],
51642
+ ["spinnerTipsEnabled", "boolean"]
51643
+ ]);
51644
+ var EXEMPT_PROJECT_PERMISSIONS = new Map([
51645
+ ["allow", "strings"],
51646
+ ["deny", "strings"],
51647
+ ["ask", "strings"],
51648
+ ["defaultMode", "string"]
51649
+ ]);
51399
51650
  export {
51400
51651
  writeStationSnapshot,
51401
51652
  writeStationHydration,