@hasna/skills 0.10.20 → 0.10.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -36868,7 +36868,7 @@ var package_default;
36868
36868
  var init_package = __esm(() => {
36869
36869
  package_default = {
36870
36870
  name: "@hasna/skills",
36871
- version: "0.10.20",
36871
+ version: "0.10.23",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -39931,12 +39931,16 @@ function assertAgentPolicyCollections(policy) {
39931
39931
  }
39932
39932
  if (bridge.codexPluginSkills !== undefined)
39933
39933
  for (const control of array(bridge.codexPluginSkills, 4096)) {
39934
- requireBound(object(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256"].includes(key)));
39934
+ requireBound(object(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "mcpSha256", "remotePluginId"].includes(key)));
39935
39935
  text(control.name, 129);
39936
39936
  text(control.pluginId, 1024);
39937
39937
  text(control.namespace, 64);
39938
39938
  text(control.pluginParent);
39939
39939
  requireBound(isAbsolute2(control.pluginParent) && resolve3(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
39940
+ if (control.remotePluginId !== undefined)
39941
+ requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
39942
+ if (control.mcpSha256 !== undefined)
39943
+ requireBound(typeof control.mcpSha256 === "string" && /^[a-f0-9]{64}$/.test(control.mcpSha256));
39940
39944
  if (control.appSha256 !== undefined)
39941
39945
  requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
39942
39946
  }
@@ -39959,8 +39963,8 @@ function assertAgentPolicyCollections(policy) {
39959
39963
  text(source.path);
39960
39964
  requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
39961
39965
  if (source.hashMode !== undefined)
39962
- requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
39963
- if (source.hashMode === "codex-settings-v1")
39966
+ requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
39967
+ if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2")
39964
39968
  requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "config.toml");
39965
39969
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
39966
39970
  requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "settings.json");
@@ -50884,6 +50888,28 @@ var init_claude_settings_witness = __esm(() => {
50884
50888
  PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
50885
50889
  });
50886
50890
 
50891
+ // src/lib/codex-native-compatibility.ts
50892
+ function supportsCodexNativeCapability(version, capability) {
50893
+ return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
50894
+ }
50895
+ var MEASURED_CODEX_CAPABILITIES, SUPPORTED_CODEX_HOOK_VERSIONS;
50896
+ var init_codex_native_compatibility = __esm(() => {
50897
+ MEASURED_CODEX_CAPABILITIES = {
50898
+ "codex-cli 0.153.0": ["hooks"],
50899
+ "codex-cli 0.154.0": ["hooks"],
50900
+ "codex-cli 0.155.0": ["hooks"],
50901
+ "codex-cli 0.155.1": ["hooks"],
50902
+ "codex-cli 0.156.1": ["hooks"],
50903
+ "codex-cli 0.157.0": ["hooks"],
50904
+ "codex-cli 0.157.1": ["hooks"],
50905
+ "codex-cli 0.158.0": ["hooks"],
50906
+ "codex-cli 0.159.0": ["hooks"],
50907
+ "codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
50908
+ "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
50909
+ };
50910
+ SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
50911
+ });
50912
+
50887
50913
  // src/lib/codex-hook-rpc.ts
50888
50914
  import { execFile, spawn as spawn2 } from "child_process";
50889
50915
  import { realpathSync as realpathSync3, statSync as statSync7 } from "fs";
@@ -50906,7 +50932,7 @@ async function connectCodexHookRpc(options) {
50906
50932
  } catch {
50907
50933
  throw new Error("CODEX_HOOK_TRUST_NATIVE_UNAVAILABLE");
50908
50934
  }
50909
- if (!SUPPORTED_CODEX_HOOK_VERSIONS.includes(version))
50935
+ if (!supportsCodexNativeCapability(version, "hooks"))
50910
50936
  throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED_VERSION");
50911
50937
  const current = statSync7(binary);
50912
50938
  if (realpathSync3(found) !== binary || ["dev", "ino", "size", "mtimeMs", "ctimeMs"].some((k) => stat[k] !== current[k]))
@@ -51025,9 +51051,9 @@ async function connectCodexHookRpc(options) {
51025
51051
  throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED: native hooks/list and versioned config writes are required");
51026
51052
  }
51027
51053
  }
51028
- var SUPPORTED_CODEX_HOOK_VERSIONS;
51029
51054
  var init_codex_hook_rpc = __esm(() => {
51030
- SUPPORTED_CODEX_HOOK_VERSIONS = ["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.155.0", "codex-cli 0.155.1", "codex-cli 0.156.1", "codex-cli 0.157.0", "codex-cli 0.157.1", "codex-cli 0.158.0", "codex-cli 0.159.0", "codex-cli 0.159.2"];
51055
+ init_codex_native_compatibility();
51056
+ init_codex_native_compatibility();
51031
51057
  });
51032
51058
 
51033
51059
  // src/lib/codex-native-skill-catalog.ts
@@ -51062,7 +51088,11 @@ function projectCodexInstalledPlugins(response) {
51062
51088
  for (const value of marketplace.plugins) {
51063
51089
  if (!object4(value) || !scalar(value.id, MAX_PLUGIN_ID_BYTES) || !scalar(value.name, MAX_NAME_BYTES) || value.id !== `${value.name}@${marketplace.name}`)
51064
51090
  refuse();
51065
- plugins.push({ ...value, marketplace: marketplace.name });
51091
+ plugins.push({
51092
+ ...value,
51093
+ marketplace: marketplace.name,
51094
+ sourceType: object4(value.source) && value.source.type === "remote" ? "remote" : undefined
51095
+ });
51066
51096
  }
51067
51097
  }
51068
51098
  return projectCodexInstalledPluginEntries(plugins);
@@ -51072,13 +51102,21 @@ function projectCodexInstalledPluginEntries(value) {
51072
51102
  refuse();
51073
51103
  const ids = new Set;
51074
51104
  return value.map((item) => {
51075
- if (!object4(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES))
51105
+ if (!object4(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES) || item.remotePluginId !== undefined && item.remotePluginId !== null && !remotePluginIdentifier(item.remotePluginId) || item.sourceType !== undefined && item.sourceType !== "remote")
51076
51106
  refuse();
51077
51107
  const at2 = item.id.lastIndexOf("@");
51078
51108
  if (at2 < 1 || item.id.slice(0, at2) !== item.name || at2 === item.id.length - 1 || ids.has(item.id))
51079
51109
  refuse();
51080
51110
  ids.add(item.id);
51081
- return { id: item.id, name: item.name, installed: item.installed, enabled: item.enabled, localVersion: item.localVersion ?? null };
51111
+ return {
51112
+ id: item.id,
51113
+ name: item.name,
51114
+ installed: item.installed,
51115
+ enabled: item.enabled,
51116
+ localVersion: item.localVersion ?? null,
51117
+ ...item.sourceType === "remote" ? { sourceType: "remote" } : {},
51118
+ ...item.remotePluginId == null ? {} : { remotePluginId: item.remotePluginId }
51119
+ };
51082
51120
  });
51083
51121
  }
51084
51122
  async function captureCodexNativeSkillCatalog(options, connect = connectCodexHookRpc) {
@@ -51091,7 +51129,7 @@ async function captureCodexNativeSkillCatalog(options, connect = connectCodexHoo
51091
51129
  ...options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }
51092
51130
  });
51093
51131
  try {
51094
- if (!SUPPORTED_NAME_CONTROL_VERSIONS.has(rpc.version))
51132
+ if (!supportsCodexNativeCapability(rpc.version, "qualified-skill-catalog"))
51095
51133
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_UNSUPPORTED_VERSION");
51096
51134
  const response = await rpc.request("skills/list", { cwds: [options.cwd], forceReload: true });
51097
51135
  const installed = await rpc.request("plugin/installed", { cwds: [options.cwd] });
@@ -51142,10 +51180,10 @@ function isCodexNativeSkillDisabled(skill, rules) {
51142
51180
  }
51143
51181
  return disabled;
51144
51182
  }
51145
- var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, MAX_PLUGIN_ID_BYTES = 1024, SUPPORTED_NAME_CONTROL_VERSIONS, object4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), scalar = (value, max2) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max2 && !/[\u0000-\u001f\u007f]/u.test(value), absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute10(value);
51183
+ var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, MAX_PLUGIN_ID_BYTES = 1024, object4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), scalar = (value, max2) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max2 && !/[\u0000-\u001f\u007f]/u.test(value), remotePluginIdentifier = (value) => typeof value === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(value), absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute10(value);
51146
51184
  var init_codex_native_skill_catalog = __esm(() => {
51147
51185
  init_codex_hook_rpc();
51148
- SUPPORTED_NAME_CONTROL_VERSIONS = new Set(["codex-cli 0.159.2"]);
51186
+ init_codex_native_compatibility();
51149
51187
  });
51150
51188
 
51151
51189
  // src/lib/codex-plugin-skill-controls.ts
@@ -51154,6 +51192,21 @@ import { lstatSync as lstatSync12, readdirSync as readdirSync6, readlinkSync as
51154
51192
  function refuse2() {
51155
51193
  throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
51156
51194
  }
51195
+ function remoteInstallationMatches(parent, remotePluginId, read2) {
51196
+ try {
51197
+ if (!remotePluginIdentifier(remotePluginId) || !lstatSync12(parent).isDirectory() || realpathSync5(parent) !== parent)
51198
+ return false;
51199
+ const path = join18(parent, ".codex-remote-plugin-install.json"), stat = lstatSync12(path, { throwIfNoEntry: false });
51200
+ if (!stat?.isFile() || stat.isSymbolicLink() || stat.size > 16384)
51201
+ return false;
51202
+ const text2 = read2(path);
51203
+ hashNativeJsonControls(text2);
51204
+ const value = JSON.parse(text2);
51205
+ return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 2 && value.schema_version === 1 && value.remote_plugin_id === remotePluginId);
51206
+ } catch {
51207
+ return false;
51208
+ }
51209
+ }
51157
51210
  function appControls(path, read2) {
51158
51211
  const text2 = read2(path);
51159
51212
  let value, sha2562;
@@ -51175,6 +51228,42 @@ function appControls(path, read2) {
51175
51228
  }
51176
51229
  return sha2562;
51177
51230
  }
51231
+ function mcpControls(path, read2) {
51232
+ const text2 = read2(path);
51233
+ let value, sha2562;
51234
+ try {
51235
+ sha2562 = hashNativeJsonControls(text2);
51236
+ value = JSON.parse(text2);
51237
+ } catch {
51238
+ refuse2();
51239
+ }
51240
+ const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
51241
+ const textField = (v, empty = false) => typeof v === "string" && (empty || Boolean(v.trim())) && Buffer.byteLength(v) <= 16384 && !/[\x00-\x1f\x7f]/.test(v);
51242
+ const envName = (v) => typeof v === "string" && /^[A-Za-z_][A-Za-z0-9_]{0,255}$/.test(v);
51243
+ if (!object5(value) || Object.keys(value).length !== 1 || !object5(value.mcpServers))
51244
+ refuse2();
51245
+ const servers = Object.entries(value.mcpServers);
51246
+ if (!servers.length || servers.length > 256)
51247
+ refuse2();
51248
+ for (const [name, server] of servers) {
51249
+ if (!identifier2(name) || !object5(server) || !Object.keys(server).every((key) => ["command", "args", "cwd", "env_vars"].includes(key)) || !textField(server.command) || server.args !== undefined && (!Array.isArray(server.args) || server.args.length > 256 || !server.args.every((arg) => textField(arg, true))) || server.cwd !== undefined && !textField(server.cwd))
51250
+ refuse2();
51251
+ if (server.env_vars !== undefined) {
51252
+ if (!Array.isArray(server.env_vars) || server.env_vars.length > 256)
51253
+ refuse2();
51254
+ const names = server.env_vars.map((entry) => {
51255
+ if (envName(entry))
51256
+ return entry;
51257
+ if (!object5(entry) || !Object.keys(entry).every((key) => ["name", "source"].includes(key)) || !envName(entry.name) || entry.source !== undefined && entry.source !== "local")
51258
+ refuse2();
51259
+ return entry.name;
51260
+ });
51261
+ if (new Set(names).size !== names.length)
51262
+ refuse2();
51263
+ }
51264
+ }
51265
+ return sha2562;
51266
+ }
51178
51267
  function rootControls(root, read2) {
51179
51268
  const manifestPath = join18(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync12(manifestPath, { throwIfNoEntry: false });
51180
51269
  if (!lstatSync12(join18(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
@@ -51192,15 +51281,21 @@ function rootControls(root, read2) {
51192
51281
  const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
51193
51282
  if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
51194
51283
  refuse2();
51195
- if (manifest.hooks !== undefined || manifest.mcpServers !== undefined || manifest.commands !== undefined || manifest.apps !== undefined && manifest.apps !== "./.app.json" || ["hooks", ".mcp.json"].some((path) => lstatSync12(join18(root, path), { throwIfNoEntry: false })))
51284
+ if (manifest.hooks !== undefined || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync12(join18(root, "hooks"), { throwIfNoEntry: false }))
51196
51285
  refuse2();
51286
+ const mcp = join18(root, ".mcp.json"), mcpPresent = lstatSync12(mcp, { throwIfNoEntry: false });
51287
+ if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
51288
+ refuse2();
51289
+ if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
51290
+ refuse2();
51291
+ const mcpSha256 = mcpPresent ? mcpControls(mcp, read2) : undefined;
51197
51292
  const app = join18(root, ".app.json"), present = lstatSync12(app, { throwIfNoEntry: false });
51198
51293
  if (present && (!present.isFile() || present.isSymbolicLink() || present.size > 1024 * 1024))
51199
51294
  refuse2();
51200
51295
  if (manifest.apps !== undefined && !present)
51201
51296
  refuse2();
51202
51297
  const appSha256 = present ? appControls(app, read2) : undefined;
51203
- return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {} };
51298
+ return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
51204
51299
  }
51205
51300
  function identity4(document3, cache3, read2) {
51206
51301
  if (!document3.startsWith(cache3 + sep4) || !document3.endsWith(sep4 + "SKILL.md"))
@@ -51243,6 +51338,10 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
51243
51338
  for (const parent of new Set(controls.map((control) => control.pluginParent))) {
51244
51339
  if (!parent.startsWith(cache3 + sep4) || !lstatSync12(parent, { throwIfNoEntry: false })?.isDirectory())
51245
51340
  return false;
51341
+ for (const control of controls.filter((control2) => control2.pluginParent === parent)) {
51342
+ if (control.remotePluginId !== undefined && !remoteInstallationMatches(parent, control.remotePluginId, read2))
51343
+ return false;
51344
+ }
51246
51345
  const names = readdirSync6(parent);
51247
51346
  entries += names.length;
51248
51347
  if (entries > 4096)
@@ -51259,7 +51358,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
51259
51358
  if (!stat.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) => lstatSync12(join18(root, path), { throwIfNoEntry: false })))
51260
51359
  continue;
51261
51360
  const parsed = rootControls(root, read2);
51262
- if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256))
51361
+ if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256 && control.mcpSha256 === parsed.mcpSha256))
51263
51362
  return false;
51264
51363
  }
51265
51364
  }
@@ -51269,7 +51368,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
51269
51368
  }
51270
51369
  }
51271
51370
  function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2, rules) {
51272
- if (catalog?.version !== "codex-cli 0.159.2" || catalog.cwd !== cwd2)
51371
+ if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd2)
51273
51372
  refuse2();
51274
51373
  const skills = projectCodexNativeSkillCatalog({ data: [{ cwd: cwd2, errors: [], skills: catalog.skills }] }, cwd2);
51275
51374
  const allowed = new Set(documents), result2 = [];
@@ -51296,22 +51395,30 @@ function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2,
51296
51395
  const listed = skills.filter((skill) => skill.path === document3);
51297
51396
  if (listed.length > 1)
51298
51397
  refuse2();
51398
+ let remotePluginId;
51299
51399
  if (listed.length === 1) {
51300
51400
  if (listed[0].name !== parsed.name || listed[0].pluginId !== expectedPluginId)
51301
51401
  refuse2();
51302
51402
  } else {
51303
- const installed = installedPlugins.filter((plugin) => plugin.id === expectedPluginId && plugin.name === pluginName);
51304
- if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled || !installed[0].localVersion)
51403
+ const installed = installedPlugins.filter((plugin2) => plugin2.id === expectedPluginId && plugin2.name === pluginName);
51404
+ if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled)
51305
51405
  refuse2();
51306
- if (installed[0].localVersion !== basename5(dirname10(dirname10(dirname10(document3)))))
51307
- continue;
51406
+ const plugin = installed[0];
51407
+ if (plugin.localVersion !== null) {
51408
+ if (plugin.localVersion !== basename5(dirname10(dirname10(dirname10(document3)))))
51409
+ continue;
51410
+ } else {
51411
+ if (plugin.sourceType !== "remote" || !plugin.remotePluginId || !remoteInstallationMatches(parsed.pluginParent, plugin.remotePluginId, read2) || !lstatSync12(document3).isFile() || realpathSync5(document3) !== document3)
51412
+ refuse2();
51413
+ remotePluginId = plugin.remotePluginId;
51414
+ }
51308
51415
  const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document3 && rule?.enabled === false);
51309
51416
  if (!exactPathDeny || !isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: expectedPluginId, enabled: true }, rules))
51310
51417
  refuse2();
51311
51418
  }
51312
- result2.push({ ...parsed, pluginId: expectedPluginId });
51419
+ result2.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
51313
51420
  }
51314
- if (!result2.length || new Set(result2.map((item) => item.name)).size !== result2.length)
51421
+ if (!result2.length && documents.some((document3) => document3.startsWith(cache3 + sep4)) || new Set(result2.map((item) => item.name)).size !== result2.length)
51315
51422
  refuse2();
51316
51423
  return result2;
51317
51424
  }
@@ -51324,8 +51431,8 @@ function isReviewedCodexPluginSkillDisabled(document3, cache3, controls, rules,
51324
51431
  } catch {
51325
51432
  return false;
51326
51433
  }
51327
- const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256);
51328
- if (!reviewed)
51434
+ const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256 && item.mcpSha256 === parsed.mcpSha256);
51435
+ if (!reviewed || reviewed.remotePluginId !== undefined && !remoteInstallationMatches(reviewed.pluginParent, reviewed.remotePluginId, read2))
51329
51436
  return false;
51330
51437
  return isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: reviewed.pluginId, enabled: true }, rules);
51331
51438
  }
@@ -51346,10 +51453,11 @@ enabled = false
51346
51453
  var identifier2 = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(v), CODEX_DEFAULT_AGENT_PLUGIN_VERSION = "1.0.0";
51347
51454
  var init_codex_plugin_skill_controls = __esm(() => {
51348
51455
  init_claude_settings_witness();
51456
+ init_codex_native_compatibility();
51349
51457
  init_codex_native_skill_catalog();
51350
51458
  });
51351
51459
 
51352
- // src/lib/codex-settings-witness.ts
51460
+ // src/lib/codex-settings-witness-v1.ts
51353
51461
  import { createHash as createHash9 } from "crypto";
51354
51462
  function need3(value) {
51355
51463
  if (!value)
@@ -51440,21 +51548,173 @@ function captureCodexSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
51440
51548
  const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
51441
51549
  return { path, hashMode: "codex-settings-v1", sha256: hashCodexSettingsReplacement(text2) };
51442
51550
  }
51551
+ var sha = (text2) => createHash9("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
51552
+ var init_codex_settings_witness_v1 = __esm(() => {
51553
+ init_claude_settings_witness();
51554
+ EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
51555
+ VERBOSITY = new Set(["low", "medium", "high"]);
51556
+ });
51557
+
51558
+ // src/lib/codex-settings-witness.ts
51559
+ import { createHash as createHash10 } from "crypto";
51560
+ function need4(value) {
51561
+ if (!value)
51562
+ throw new Error("Invalid Codex settings witness");
51563
+ }
51564
+ function isRecord3(value) {
51565
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
51566
+ }
51567
+ function isDate2(value) {
51568
+ return value instanceof Date;
51569
+ }
51570
+ function numericTokens2(text2) {
51571
+ const result2 = [];
51572
+ for (let at2 = 0;at2 < text2.length; ) {
51573
+ const char = text2[at2];
51574
+ if (char === "#") {
51575
+ while (at2 < text2.length && text2[at2] !== `
51576
+ `)
51577
+ at2++;
51578
+ continue;
51579
+ }
51580
+ if (char === '"' || char === "'") {
51581
+ const quote = char, triple = text2.slice(at2, at2 + 3) === quote.repeat(3);
51582
+ at2 += triple ? 3 : 1;
51583
+ while (at2 < text2.length) {
51584
+ if (quote === '"' && text2[at2] === "\\") {
51585
+ at2 += 2;
51586
+ continue;
51587
+ }
51588
+ if (text2.slice(at2, at2 + (triple ? 3 : 1)) === quote.repeat(triple ? 3 : 1)) {
51589
+ at2 += triple ? 3 : 1;
51590
+ break;
51591
+ }
51592
+ at2++;
51593
+ }
51594
+ continue;
51595
+ }
51596
+ if (/[0-9+-]/.test(char)) {
51597
+ const start = at2;
51598
+ while (at2 < text2.length && !/[\s,\]{}#=]/.test(text2[at2]))
51599
+ at2++;
51600
+ if (at2 > start) {
51601
+ result2.push(text2.slice(start, at2));
51602
+ continue;
51603
+ }
51604
+ }
51605
+ at2++;
51606
+ }
51607
+ return result2.sort();
51608
+ }
51609
+ function canonical4(value, depth = 0, budget = { remaining: 65536 }) {
51610
+ need4(depth <= 32 && --budget.remaining >= 0);
51611
+ if (value === null)
51612
+ return ["null"];
51613
+ if (typeof value === "string")
51614
+ return ["string", value];
51615
+ if (typeof value === "boolean")
51616
+ return ["boolean", value];
51617
+ if (typeof value === "number") {
51618
+ need4(Number.isFinite(value));
51619
+ return ["number", String(value)];
51620
+ }
51621
+ if (isDate2(value)) {
51622
+ need4(Number.isFinite(value.getTime()));
51623
+ return ["date", value.toISOString()];
51624
+ }
51625
+ if (Array.isArray(value))
51626
+ return ["array", value.map((child) => canonical4(child, depth + 1, budget))];
51627
+ need4(isRecord3(value));
51628
+ return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical4(child, depth + 1, budget)])];
51629
+ }
51630
+ function normalize3(config) {
51631
+ if (isRecord3(config.hooks)) {
51632
+ delete config.hooks.state;
51633
+ if (!Object.keys(config.hooks).length)
51634
+ delete config.hooks;
51635
+ }
51636
+ if (isRecord3(config.skills) && Array.isArray(config.skills.config)) {
51637
+ const skills = config.skills;
51638
+ const retained = skills.config.filter((entry) => !disablesOneSkill(entry));
51639
+ if (retained.length !== skills.config.length) {
51640
+ if (retained.length)
51641
+ skills.config = retained;
51642
+ else
51643
+ delete skills.config;
51644
+ }
51645
+ if (!Object.keys(skills).length)
51646
+ delete config.skills;
51647
+ }
51648
+ inference(config);
51649
+ if (isRecord3(config.profiles)) {
51650
+ for (const profile of Object.values(config.profiles))
51651
+ if (isRecord3(profile))
51652
+ inference(profile);
51653
+ }
51654
+ }
51655
+ function disablesOneSkill(entry) {
51656
+ if (!isRecord3(entry) || entry.enabled !== false)
51657
+ return false;
51658
+ const keys2 = Object.keys(entry);
51659
+ if (!keys2.every((key) => key === "path" || key === "name" || key === "enabled"))
51660
+ return false;
51661
+ const selector = ["path", "name"].filter((key) => Object.hasOwn(entry, key));
51662
+ return selector.length === 1 && typeof entry[selector[0]] === "string" && entry[selector[0]].length > 0;
51663
+ }
51664
+ function inference(target) {
51665
+ for (const key of INFERENCE)
51666
+ if (Object.hasOwn(target, key)) {
51667
+ const value = target[key];
51668
+ if (key === "model")
51669
+ need4(typeof value === "string" && MODEL.test(value));
51670
+ else
51671
+ need4(typeof value === "string" && (key === "model_reasoning_effort" ? EFFORT2.has(value) : VERBOSITY2.has(value)));
51672
+ delete target[key];
51673
+ }
51674
+ }
51675
+ function settingsDigest2(text2) {
51676
+ let config;
51677
+ try {
51678
+ config = Bun.TOML.parse(text2);
51679
+ } catch {
51680
+ throw new Error("Invalid Codex settings witness");
51681
+ }
51682
+ need4(isRecord3(config));
51683
+ normalize3(config);
51684
+ return sha2(`hasna.skills.codex-settings.v2\x00${JSON.stringify([canonical4(config), numericTokens2(text2)])}`);
51685
+ }
51686
+ function hashCodexSettingsReplacementV2(text2, budget = { remaining: 256 * 1024 * 1024 }) {
51687
+ need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
51688
+ budget.remaining -= Buffer.byteLength(text2);
51689
+ return settingsDigest2(text2);
51690
+ }
51691
+ function captureCodexSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
51692
+ const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
51693
+ return { path, hashMode: "codex-settings-v2", sha256: settingsDigest2(text2) };
51694
+ }
51695
+ function readCodexSettingsPreimage(path, budget = { remaining: 2 * 1024 * 1024 }) {
51696
+ return readNativeSettingsWitnessFile(path, budget, "config.toml");
51697
+ }
51443
51698
  function upgradeCodexSettingsWitness(previous, reviewedSettingsPath) {
51444
- need3(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes") && /^[a-f0-9]{64}$/.test(previous.sha256));
51699
+ need4(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes" || previous.hashMode === "codex-settings-v1") && /^[a-f0-9]{64}$/.test(previous.sha256));
51445
51700
  const budget = { remaining: 2 * 1024 * 1024 };
51446
51701
  const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
51447
- need3(sha(before2) === previous.sha256);
51448
- const sha2562 = hashCodexSettingsReplacement(current);
51449
- if (hashCodexSettingsReplacement(before2) !== sha2562)
51702
+ need4((previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before2) : sha2(before2)) === previous.sha256);
51703
+ const sha2562 = settingsDigest2(current);
51704
+ if (settingsDigest2(before2) !== sha2562)
51450
51705
  throw new Error("Codex non-preference settings changed; explicit discovery review required");
51451
- return { path: previous.path, hashMode: "codex-settings-v1", sha256: sha2562 };
51706
+ return { path: previous.path, hashMode: "codex-settings-v2", sha256: sha2562 };
51452
51707
  }
51453
- var sha = (text2) => createHash9("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
51708
+ var sha2 = (text2) => createHash10("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
51454
51709
  var init_codex_settings_witness = __esm(() => {
51710
+ init_codex_settings_witness_v1();
51711
+ init_codex_settings_witness_v1();
51455
51712
  init_claude_settings_witness();
51456
- EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
51457
- VERBOSITY = new Set(["low", "medium", "high"]);
51713
+ EFFORT2 = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
51714
+ VERBOSITY2 = new Set(["low", "medium", "high"]);
51715
+ MODEL = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
51716
+ CODEX_DISCOVERY_PROJECTION_FIELDS = ["plugins", "marketplaces", "skills"];
51717
+ INFERENCE = ["model", "model_reasoning_effort", "model_verbosity"];
51458
51718
  });
51459
51719
 
51460
51720
  // src/lib/managed-policy.ts
@@ -51543,7 +51803,7 @@ var init_managed_policy = __esm(() => {
51543
51803
  });
51544
51804
 
51545
51805
  // src/lib/agent-bridge.ts
51546
- import { createHash as createHash10 } from "crypto";
51806
+ import { createHash as createHash11 } from "crypto";
51547
51807
  import { lstatSync as lstatSync14, readFileSync as readFileSync12, readdirSync as readdirSync7 } from "fs";
51548
51808
  import { join as join20 } from "path";
51549
51809
  function isOwnedCliBridge(path, expectedPaths) {
@@ -51577,7 +51837,7 @@ Use the Skills CLI as the skill authority for this station.
51577
51837
  This bridge contains no skill payloads. Do not copy skill content into agent-native skill directories or load other native skill copies. If a Skills command refuses authority, selection, integrity, or native drift, report that refusal and use its repair guidance; do not substitute bundled or stale local content. Explicit local draft authoring remains available.
51578
51838
  `, CLI_BRIDGE_DIGEST, CLI_BRIDGE_FILES;
51579
51839
  var init_agent_bridge = __esm(() => {
51580
- CLI_BRIDGE_DIGEST = createHash10("sha256").update(markdown).digest("hex");
51840
+ CLI_BRIDGE_DIGEST = createHash11("sha256").update(markdown).digest("hex");
51581
51841
  CLI_BRIDGE_FILES = Object.freeze({
51582
51842
  "SKILL.md": markdown,
51583
51843
  ".hasna-skills.json": `${JSON.stringify({ managedBy: "@hasna/skills", kind: "cli-bridge", version: CLI_BRIDGE_VERSION, protocol: "selection-v1", contentSha256: CLI_BRIDGE_DIGEST }, null, 2)}
@@ -51856,7 +52116,8 @@ var init_agent_codex = __esm(() => {
51856
52116
  });
51857
52117
 
51858
52118
  // src/lib/agent-integration.ts
51859
- import { createHash as createHash11, randomUUID as randomUUID5 } from "crypto";
52119
+ import { createHash as createHash12, randomUUID as randomUUID5 } from "crypto";
52120
+ import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
51860
52121
  import { existsSync as existsSync12, lstatSync as lstatSync15, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync13, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync6, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync8, closeSync as closeSync8, fsyncSync as fsyncSync2, fstatSync as fstatSync8, readSync as readSync6, constants as constants8, linkSync } from "fs";
51861
52122
  import { dirname as dirname11, join as join21, resolve as resolve11, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
51862
52123
  import { homedir as homedir3 } from "os";
@@ -51965,7 +52226,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
51965
52226
  }
51966
52227
  }
51967
52228
  function treeHash(root) {
51968
- const hash2 = createHash11("sha256");
52229
+ const hash2 = createHash12("sha256");
51969
52230
  let bytes = 0, files = 0;
51970
52231
  function visit2(path) {
51971
52232
  const stat = lstatSync15(path);
@@ -51992,7 +52253,7 @@ function treeHash(root) {
51992
52253
  return hash2.digest("hex");
51993
52254
  }
51994
52255
  function parseNativeMigrationTargetManifest(input) {
51995
- const digest = sha2(input);
52256
+ const digest = sha3(input);
51996
52257
  let value;
51997
52258
  try {
51998
52259
  value = JSON.parse(input.toString());
@@ -52397,7 +52658,7 @@ function planAgentIntegration(options) {
52397
52658
  const observedNativeSources = [];
52398
52659
  const codexPluginSkills = options.codexNativeCatalog ? reviewCodexPluginSkillControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join21(entry.path, "SKILL.md")), canonicalAgentPath(join21(home, ".codex/plugins/cache"), aliases), resolve11(options.projectDir ?? home), (path) => {
52399
52660
  const bytes = readNativeBytes(path, 1024 * 1024);
52400
- observedNativeSources.push({ path, sha256: sha2(bytes) });
52661
+ observedNativeSources.push({ path, sha256: sha3(bytes) });
52401
52662
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
52402
52663
  }, codexConfig.skills?.config ?? []) : policy.bridge?.codexPluginSkills ?? [];
52403
52664
  const changes = [];
@@ -52425,7 +52686,7 @@ function planAgentIntegration(options) {
52425
52686
  throw new Error("Refusing to overwrite an unrecognized Hermes supervisor");
52426
52687
  if (supervisorBefore !== supervisorAfter)
52427
52688
  changes.push({ path: supervisorPath, before: supervisorBefore, after: supervisorAfter });
52428
- const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha2(supervisorAfter) };
52689
+ const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha3(supervisorAfter) };
52429
52690
  const after3 = configureHermesHooks(before2, supervisor, previous);
52430
52691
  if (before2 !== after3)
52431
52692
  changes.push({ path, before: before2, after: after3 });
@@ -52472,12 +52733,12 @@ function planAgentIntegration(options) {
52472
52733
  agents: [...new Set([...priorAgents, ...options.agents])].sort(),
52473
52734
  home: resolve11(home),
52474
52735
  includeVendor: true,
52475
- ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join21(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha2(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
52736
+ ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join21(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha3(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
52476
52737
  commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
52477
52738
  profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
52478
52739
  disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join21(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
52479
52740
  rootAliases: aliases,
52480
- ...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha2(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(join21(home, ".codex/config.toml"), aliases))?.before === null ? null : sha2(readOptional(canonicalAgentPath(join21(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview } : {},
52741
+ ...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha3(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(join21(home, ".codex/config.toml"), aliases))?.before === null ? null : sha3(readOptional(canonicalAgentPath(join21(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview } : {},
52481
52742
  discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
52482
52743
  } };
52483
52744
  const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
@@ -52515,7 +52776,7 @@ function atomicWrite2(path, content) {
52515
52776
  function planAgentSettingsWitnessUpgrade(options) {
52516
52777
  const home = resolve11(options.home ?? homedir3()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
52517
52778
  const snapshot = readManagedSkillPolicySnapshot(dataDir3);
52518
- if (!snapshot || sha2(snapshot.text) !== options.expectedPolicySha256)
52779
+ if (!snapshot || sha3(snapshot.text) !== options.expectedPolicySha256)
52519
52780
  throw new Error("Managed policy preimage changed");
52520
52781
  const policy = snapshot.value, aliases = policy.bridge?.rootAliases ?? [];
52521
52782
  recheckRootAliases(aliases);
@@ -52524,7 +52785,7 @@ function planAgentSettingsWitnessUpgrade(options) {
52524
52785
  throw new Error("Settings witness upgrade requires an existing reviewed native binding");
52525
52786
  const configPath = canonicalAgentPath(join21(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
52526
52787
  const settings = readOptional(configPath);
52527
- if (settings === null || sha2(settings) !== options.expectedSettingsSha256)
52788
+ if (settings === null || sha3(settings) !== options.expectedSettingsSha256)
52528
52789
  throw new Error("Native settings preimage changed");
52529
52790
  const sources = binding.sources.filter((source) => source.path === configPath && source.format === undefined && source.fields === undefined);
52530
52791
  if (sources.length !== 1)
@@ -52532,15 +52793,40 @@ function planAgentSettingsWitnessUpgrade(options) {
52532
52793
  const previous = sources[0];
52533
52794
  if (typeof previous.sha256 !== "string")
52534
52795
  throw new Error("Settings witness upgrade requires a preserved settings preimage");
52796
+ const replaced = [previous];
52797
+ if (options.agent === "codex") {
52798
+ if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1")
52799
+ throw new Error("Codex settings witness upgrade requires a preserved raw or codex-settings-v1 configuration witness");
52800
+ const preimage = readCodexSettingsPreimage(options.reviewedPreimage);
52801
+ for (const source of binding.sources) {
52802
+ if (source === previous || source.path !== configPath)
52803
+ continue;
52804
+ const fields = source.fields;
52805
+ if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields) || !isDeepStrictEqual4(fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
52806
+ throw new Error("Codex settings witness upgrade found an unrecognized configuration witness");
52807
+ if (projectNativeDiscoveryFields(preimage, "toml", fields, configPath) !== source.sha256)
52808
+ throw new Error("Reviewed preimage does not explain the Codex discovery projection witness");
52809
+ replaced.push(source);
52810
+ }
52811
+ }
52535
52812
  const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
52536
- const replacement = { ...binding, sources: binding.sources.map((source) => source === previous ? next : source) };
52813
+ const rebound = [];
52814
+ for (const source of binding.sources) {
52815
+ if (!replaced.includes(source)) {
52816
+ rebound.push(source);
52817
+ continue;
52818
+ }
52819
+ if (source === replaced[0])
52820
+ rebound.push(next);
52821
+ }
52822
+ const replacement = { ...binding, sources: rebound };
52537
52823
  verifyAgentDiscovery(replacement);
52538
52824
  const after2 = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
52539
- return { dataDir: dataDir3, profileId: policy.profileId, changes: [{ path: join21(dataDir3, "agent-policy.json"), before: snapshot.text, after: after2 }], nativeSkills: [], observedPolicy: { path: join21(dataDir3, "agent-policy.json"), before: snapshot.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256 } };
52825
+ return { dataDir: dataDir3, profileId: policy.profileId, changes: [{ path: join21(dataDir3, "agent-policy.json"), before: snapshot.text, after: after2 }], nativeSkills: [], observedPolicy: { path: join21(dataDir3, "agent-policy.json"), before: snapshot.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
52540
52826
  }
52541
52827
  function applyAgentIntegration(plan) {
52542
52828
  for (const source of plan.observedNativeSources ?? [])
52543
- if (sha2(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52829
+ if (sha3(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52544
52830
  throw new Error("Native identity source changed after planning");
52545
52831
  if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
52546
52832
  throw new Error("Native settings changed after witness planning");
@@ -52560,7 +52846,7 @@ function applyAgentIntegration(plan) {
52560
52846
  const upgrade = plan.settingsWitnessUpgrade;
52561
52847
  if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
52562
52848
  throw new Error("Invalid settings witness upgrade plan");
52563
- const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha2(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
52849
+ const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
52564
52850
  if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
52565
52851
  throw new Error("Settings witness upgrade plan changed");
52566
52852
  provenDiscovery = verified.discoveryBefore[0];
@@ -52588,7 +52874,7 @@ function applyAgentIntegration(plan) {
52588
52874
  chmodSync(backupRoot, 448);
52589
52875
  for (const [index, change] of plan.changes.entries())
52590
52876
  if (change.before !== null) {
52591
- const backup = join21(backupRoot, `${index}-${sha2(change.path).slice(0, 12)}.backup`);
52877
+ const backup = join21(backupRoot, `${index}-${sha3(change.path).slice(0, 12)}.backup`);
52592
52878
  writeFileSync4(backup, change.before, { mode: 384, flag: "wx" });
52593
52879
  if (readFileSync13(backup, "utf8") !== change.before)
52594
52880
  throw new Error("Native configuration preservation readback failed");
@@ -52607,7 +52893,7 @@ function applyAgentIntegration(plan) {
52607
52893
  }
52608
52894
  recheckRootAliases(aliases);
52609
52895
  for (const source of plan.observedNativeSources ?? [])
52610
- if (sha2(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52896
+ if (sha3(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52611
52897
  throw new Error("Native identity source changed during application");
52612
52898
  if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
52613
52899
  throw new Error("Native settings changed during witness application");
@@ -52619,7 +52905,7 @@ function applyAgentIntegration(plan) {
52619
52905
  }
52620
52906
  for (const agent of plan.managedAgentChecks?.agents ?? [])
52621
52907
  assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
52622
- atomicWrite2(join21(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha2(change.before), afterHash: sha2(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
52908
+ atomicWrite2(join21(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha3(change.before), afterHash: sha3(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
52623
52909
  `);
52624
52910
  } catch (error) {
52625
52911
  for (const change of written.reverse()) {
@@ -52698,8 +52984,8 @@ function archiveNativeSkills(inventory, options) {
52698
52984
  const operationId = randomUUID5(), archiveRoot = join21(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join21(archiveRoot, "receipt.json");
52699
52985
  const entries = selected.map((entry, index) => ({
52700
52986
  source: entry.vendor ? join21(entry.path, "SKILL.md") : entry.path,
52701
- archive: join21(archiveRoot, `${index}-${sha2(entry.path).slice(0, 12)}`),
52702
- hash: entry.vendor ? sha2(readNativeBytes(join21(entry.path, "SKILL.md"))) : entry.hash,
52987
+ archive: join21(archiveRoot, `${index}-${sha3(entry.path).slice(0, 12)}`),
52988
+ hash: entry.vendor ? sha3(readNativeBytes(join21(entry.path, "SKILL.md"))) : entry.hash,
52703
52989
  ...entry.vendor ? { discoveryOnly: true } : {},
52704
52990
  status: "planned"
52705
52991
  }));
@@ -52710,7 +52996,7 @@ function archiveNativeSkills(inventory, options) {
52710
52996
  const stat = lstatSync15(entry.archive);
52711
52997
  if (entry.discoveryOnly ? !stat.isFile() : !stat.isDirectory())
52712
52998
  throw new Error("Archive type changed");
52713
- if ((entry.discoveryOnly ? sha2(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
52999
+ if ((entry.discoveryOnly ? sha3(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
52714
53000
  throw new Error("Archive bytes changed");
52715
53001
  };
52716
53002
  assertSafePath(archiveRoot);
@@ -52830,7 +53116,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
52830
53116
  throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
52831
53117
  if (agent === "hermes") {
52832
53118
  const supervisor = binding.supervisors?.hermes;
52833
- if (supervisor?.path !== join21(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha2(renderHermesSupervisor(command, profile)))
53119
+ if (supervisor?.path !== join21(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha3(renderHermesSupervisor(command, profile)))
52834
53120
  throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
52835
53121
  assertHermesProtection(home, config, command, profile, supervisor);
52836
53122
  } else if (agent === "opencode") {
@@ -52946,7 +53232,7 @@ function assertNativeExportAllowed(dataDir3 = getDataDirReadOnly()) {
52946
53232
  if (requiresCliSkillLoading(dataDir3))
52947
53233
  throw new Error("NATIVE_SKILL_EXPORT_DISABLED: this station loads skills through the Skills CLI; use skills sync --selection-profile <id>");
52948
53234
  }
52949
- var sha2 = (data) => createHash11("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
53235
+ var sha3 = (data) => createHash12("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
52950
53236
  var init_agent_integration = __esm(() => {
52951
53237
  init_codex_plugin_skill_controls();
52952
53238
  init_codex_native_skill_catalog();
@@ -54528,7 +54814,7 @@ var init_selection_resolver = __esm(() => {
54528
54814
  });
54529
54815
 
54530
54816
  // src/lib/plugin-projection.ts
54531
- import { createHash as createHash12 } from "crypto";
54817
+ import { createHash as createHash13 } from "crypto";
54532
54818
  import { posix } from "path";
54533
54819
  function pluginRefusal(message) {
54534
54820
  throw new SkillSelectionError("PLUGIN_ADMISSION_REFUSED", message);
@@ -54721,7 +55007,7 @@ function buildPluginProjection(entries) {
54721
55007
  files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
54722
55008
  return { manifest, payloads: manifest.payloads, files, witnesses: pluginFileWitnesses(files), originalTreeDigest, projectionTreeDigest: pluginTreeDigest(files), removed: removed.length ? pluginFileWitnesses(removed) : [] };
54723
55009
  }
54724
- var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash12("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
55010
+ var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash13("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
54725
55011
  var init_plugin_projection = __esm(() => {
54726
55012
  init_selection_cache();
54727
55013
  PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
@@ -54729,7 +55015,7 @@ var init_plugin_projection = __esm(() => {
54729
55015
  });
54730
55016
 
54731
55017
  // src/lib/plugin-projection-store.ts
54732
- import { createHash as createHash13, randomUUID as randomUUID6 } from "crypto";
55018
+ import { createHash as createHash14, randomUUID as randomUUID6 } from "crypto";
54733
55019
  import { constants as constants9, closeSync as closeSync9, fchmodSync, fstatSync as fstatSync9, fsyncSync as fsyncSync3, linkSync as linkSync2, lstatSync as lstatSync17, mkdirSync as mkdirSync9, openSync as openSync9, opendirSync as opendirSync4, readSync as readSync7, renameSync as renameSync5, rmdirSync as rmdirSync3, rmSync as rmSync4, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
54734
55020
  import { dirname as dirname13, isAbsolute as isAbsolute12, join as join29, parse as parse5, resolve as resolve12 } from "path";
54735
55021
  function stat(path) {
@@ -54741,7 +55027,7 @@ function stat(path) {
54741
55027
  return pluginRefusal("Cannot inspect plugin filesystem entry");
54742
55028
  }
54743
55029
  }
54744
- function canonical4(path) {
55030
+ function canonical5(path) {
54745
55031
  pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute12(path) && resolve12(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
54746
55032
  }
54747
55033
  function owner(stats, system = false) {
@@ -54752,7 +55038,7 @@ function same3(left, right, identityOnly = false) {
54752
55038
  pluginNeed(right && left.dev === right.dev && left.ino === right.ino && left.mode === right.mode && left.uid === right.uid && left.gid === right.gid && (identityOnly || left.size === right.size && left.nlink === right.nlink && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs), "Plugin filesystem entry changed during access");
54753
55039
  }
54754
55040
  function ancestors(path, create3 = false) {
54755
- canonical4(path);
55041
+ canonical5(path);
54756
55042
  const result2 = [], parent = dirname13(path), filesystemRoot = parse5(parent).root;
54757
55043
  let current = filesystemRoot;
54758
55044
  for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
@@ -55067,7 +55353,7 @@ function pluginExecutableDigest(path) {
55067
55353
  const opened = fstatSync9(fd, { bigint: true });
55068
55354
  same3(before2, opened);
55069
55355
  fileShape(opened, maximum, "executable");
55070
- const hash2 = createHash13("sha256"), buffer = new Uint8Array(64 * 1024);
55356
+ const hash2 = createHash14("sha256"), buffer = new Uint8Array(64 * 1024);
55071
55357
  let remaining = Number(opened.size);
55072
55358
  while (remaining > 0) {
55073
55359
  const count = readSync7(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
@@ -55650,21 +55936,21 @@ var init_plugin_discovery = __esm(() => {
55650
55936
  });
55651
55937
 
55652
55938
  // src/lib/claude-marketplace-registry.ts
55653
- import { createHash as createHash14 } from "crypto";
55939
+ import { createHash as createHash15 } from "crypto";
55654
55940
  import { closeSync as closeSync11, constants as constants11, fstatSync as fstatSync11, lstatSync as lstatSync19, openSync as openSync11, readSync as readSync9 } from "fs";
55655
55941
  import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve15 } from "path";
55656
- function need4(value, reason) {
55942
+ function need5(value, reason) {
55657
55943
  if (!value)
55658
55944
  throw new Error(`Claude marketplace registry ${reason}`);
55659
55945
  }
55660
55946
  function absolutePath3(value) {
55661
- need4(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve15(value) === value, "requires a normalized absolute path");
55947
+ need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve15(value) === value, "requires a normalized absolute path");
55662
55948
  }
55663
55949
  function parents2(path) {
55664
55950
  const result2 = [];
55665
55951
  for (let at2 = dirname15(path);; at2 = dirname15(at2)) {
55666
55952
  const stat2 = lstatSync19(at2, { bigint: true });
55667
- need4(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
55953
+ need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
55668
55954
  result2.push([at2, stat2]);
55669
55955
  if (at2 === dirname15(at2))
55670
55956
  return result2;
@@ -55672,15 +55958,15 @@ function parents2(path) {
55672
55958
  }
55673
55959
  function readRegistry2(path, budget) {
55674
55960
  absolutePath3(path);
55675
- need4(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
55676
- need4(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
55961
+ need5(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
55962
+ need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
55677
55963
  const ancestors2 = parents2(path), initial2 = lstatSync19(path, { bigint: true });
55678
- need4(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
55679
- need4(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
55964
+ need5(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
55965
+ need5(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
55680
55966
  const fd = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
55681
55967
  try {
55682
55968
  const opened = fstatSync11(fd, { bigint: true });
55683
- need4(opened.isFile() && sameFile2(initial2, opened), "changed during open");
55969
+ need5(opened.isFile() && sameFile2(initial2, opened), "changed during open");
55684
55970
  const bytes = Buffer.alloc(Number(opened.size) + 1);
55685
55971
  let length = 0;
55686
55972
  while (length < bytes.length) {
@@ -55690,10 +55976,10 @@ function readRegistry2(path, budget) {
55690
55976
  length += count;
55691
55977
  }
55692
55978
  const after2 = fstatSync11(fd, { bigint: true }), current = lstatSync19(path, { bigint: true });
55693
- need4(current.isFile() && sameFile2(opened, after2) && sameFile2(after2, current) && BigInt(length) === opened.size, "changed during read");
55979
+ need5(current.isFile() && sameFile2(opened, after2) && sameFile2(after2, current) && BigInt(length) === opened.size, "changed during read");
55694
55980
  for (const [ancestor, before2] of ancestors2) {
55695
55981
  const now3 = lstatSync19(ancestor, { bigint: true });
55696
- need4(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
55982
+ need5(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
55697
55983
  }
55698
55984
  budget.remaining -= length;
55699
55985
  try {
@@ -55713,7 +55999,7 @@ function parse6(text2) {
55713
55999
  at2++;
55714
56000
  };
55715
56001
  function string() {
55716
- need4(text2[at2] === '"', "contains invalid JSON");
56002
+ need5(text2[at2] === '"', "contains invalid JSON");
55717
56003
  const start = at2++;
55718
56004
  while (at2 < text2.length) {
55719
56005
  const character = text2[at2++];
@@ -55724,7 +56010,7 @@ function parse6(text2) {
55724
56010
  } catch {
55725
56011
  throw new Error("Claude marketplace registry contains invalid JSON string");
55726
56012
  }
55727
- need4(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
56013
+ need5(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
55728
56014
  return value2;
55729
56015
  }
55730
56016
  if (character === "\\")
@@ -55733,7 +56019,7 @@ function parse6(text2) {
55733
56019
  throw new Error("Claude marketplace registry contains an unterminated JSON string");
55734
56020
  }
55735
56021
  function value(depth) {
55736
- need4(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
56022
+ need5(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
55737
56023
  space();
55738
56024
  const character = text2[at2];
55739
56025
  if (character === '"')
@@ -55747,17 +56033,17 @@ function parse6(text2) {
55747
56033
  if (object5) {
55748
56034
  space();
55749
56035
  const key = string();
55750
- need4(!keys2.has(key), "contains a duplicate JSON key");
56036
+ need5(!keys2.has(key), "contains a duplicate JSON key");
55751
56037
  keys2.add(key);
55752
56038
  space();
55753
- need4(text2[at2++] === ":", "contains invalid JSON");
56039
+ need5(text2[at2++] === ":", "contains invalid JSON");
55754
56040
  entries.push([key, value(depth + 1)]);
55755
56041
  } else
55756
56042
  items.push(value(depth + 1));
55757
56043
  space();
55758
56044
  if (text2[at2] === end)
55759
56045
  break;
55760
- need4(text2[at2++] === ",", "contains invalid JSON");
56046
+ need5(text2[at2++] === ",", "contains invalid JSON");
55761
56047
  }
55762
56048
  at2++;
55763
56049
  return object5 ? { kind: "object", entries } : { kind: "array", items };
@@ -55769,21 +56055,21 @@ function parse6(text2) {
55769
56055
  }
55770
56056
  numberPattern.lastIndex = at2;
55771
56057
  const number = numberPattern.exec(text2);
55772
- need4(number, "contains invalid JSON");
56058
+ need5(number, "contains invalid JSON");
55773
56059
  at2 += number[0].length;
55774
56060
  return { kind: "number", value: number[0] };
55775
56061
  }
55776
56062
  const root2 = value(0);
55777
56063
  space();
55778
- need4(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
55779
- need4(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
56064
+ need5(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
56065
+ need5(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
55780
56066
  return root2;
55781
56067
  }
55782
56068
  function exactKeys(value, keys2) {
55783
56069
  return value?.kind === "object" && value.entries.length === keys2.length && value.entries.every(([key]) => keys2.includes(key));
55784
56070
  }
55785
56071
  function textField(value) {
55786
- need4(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
56072
+ need5(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
55787
56073
  return value.value;
55788
56074
  }
55789
56075
  function normalizeRow(row, version = 1) {
@@ -55791,7 +56077,7 @@ function normalizeRow(row, version = 1) {
55791
56077
  if (version !== 2 || !exactKeys(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
55792
56078
  return;
55793
56079
  const autoUpdate = field(row, "autoUpdate");
55794
- need4(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
56080
+ need5(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
55795
56081
  }
55796
56082
  const source = field(row, "source");
55797
56083
  if (source?.kind !== "object")
@@ -55807,23 +56093,23 @@ function normalizeRow(row, version = 1) {
55807
56093
  absolutePath3(sourceLocation);
55808
56094
  absolutePath3(textField(field(row, "installLocation")));
55809
56095
  const updated = textField(field(row, "lastUpdated"));
55810
- need4(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
56096
+ need5(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
55811
56097
  const millis = Date.parse(updated);
55812
- need4(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
56098
+ need5(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
55813
56099
  row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
55814
56100
  }
55815
56101
  function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
55816
56102
  const value = parse6(readRegistry2(path, budget));
55817
56103
  for (const [, row] of value.entries)
55818
56104
  normalizeRow(row);
55819
- const sha2562 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
56105
+ const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
55820
56106
  return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
55821
56107
  }
55822
56108
  function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
55823
56109
  const value = parse6(readRegistry2(path, budget));
55824
56110
  for (const [, row] of value.entries)
55825
56111
  normalizeRow(row, 2);
55826
- const sha2562 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
56112
+ const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
55827
56113
  return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
55828
56114
  }
55829
56115
  var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, field = (object5, key) => object5.entries.find(([name]) => name === key)?.[1];
@@ -55833,17 +56119,17 @@ var init_claude_marketplace_registry = __esm(() => {
55833
56119
 
55834
56120
  // src/lib/codex-hook-trust-files.ts
55835
56121
  import { closeSync as closeSync12, constants as constants12, fstatSync as fstatSync12, fsyncSync as fsyncSync4, lstatSync as lstatSync20, openSync as openSync12, readSync as readSync10, writeFileSync as writeFileSync8 } from "fs";
55836
- import { createHash as createHash15 } from "crypto";
56122
+ import { createHash as createHash16 } from "crypto";
55837
56123
  import { dirname as dirname16 } from "path";
55838
- function need5(value, code) {
56124
+ function need6(value, code) {
55839
56125
  if (!value)
55840
56126
  throw new Error(`CODEX_HOOK_TRUST_${code}`);
55841
56127
  }
55842
56128
  function safeParents(file) {
55843
56129
  for (let p = dirname16(file);; p = dirname16(p)) {
55844
56130
  const s = lstatSync20(p);
55845
- need5(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
55846
- need5((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
56131
+ need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
56132
+ need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
55847
56133
  if (dirname16(p) === p)
55848
56134
  break;
55849
56135
  }
@@ -55852,12 +56138,12 @@ function snapshot(file, privateFile = false, options = {}) {
55852
56138
  const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
55853
56139
  safeParents(file);
55854
56140
  const initial2 = lstatSync20(file, { bigint: true });
55855
- need5(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
55856
- need5(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
56141
+ need6(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
56142
+ need6(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
55857
56143
  const fd = openSync12(file, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
55858
56144
  try {
55859
56145
  const before2 = fstatSync12(fd, { bigint: true });
55860
- need5(sameStat(initial2, before2), "INPUT_CHANGED");
56146
+ need6(sameStat(initial2, before2), "INPUT_CHANGED");
55861
56147
  const bytes = Buffer.alloc(Number(before2.size) + 1);
55862
56148
  let length = 0;
55863
56149
  while (length < bytes.length) {
@@ -55866,16 +56152,16 @@ function snapshot(file, privateFile = false, options = {}) {
55866
56152
  break;
55867
56153
  length += n2;
55868
56154
  }
55869
- need5(length === Number(before2.size) && sameStat(before2, fstatSync12(fd, { bigint: true })) && sameStat(before2, lstatSync20(file, { bigint: true })), "INPUT_CHANGED");
56155
+ need6(length === Number(before2.size) && sameStat(before2, fstatSync12(fd, { bigint: true })) && sameStat(before2, lstatSync20(file, { bigint: true })), "INPUT_CHANGED");
55870
56156
  const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
55871
- return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash15("sha256").update(content).digest("hex") };
56157
+ return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash16("sha256").update(content).digest("hex") };
55872
56158
  } finally {
55873
56159
  closeSync12(fd);
55874
56160
  }
55875
56161
  }
55876
56162
  function unchanged2(before2) {
55877
56163
  const after2 = snapshot(before2.file, before2.privateFile, before2.readOnlyPackage ? { readOnlyPackage: true } : {});
55878
- need5(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
56164
+ need6(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
55879
56165
  }
55880
56166
  function save(file, content) {
55881
56167
  safeParents(file);
@@ -55891,7 +56177,7 @@ var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs
55891
56177
  var init_codex_hook_trust_files = () => {};
55892
56178
 
55893
56179
  // src/lib/codex-hook-trust-layout.ts
55894
- import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
56180
+ import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
55895
56181
  function codexTrustTextWitness(text2, keys2, canonicalize = true) {
55896
56182
  const parsed = Bun.TOML.parse(text2), wanted = new Set(keys2);
55897
56183
  const headers = [...text2.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
@@ -55956,7 +56242,7 @@ function codexTrustTextWitness(text2, keys2, canonicalize = true) {
55956
56242
  if (expected.hooks)
55957
56243
  delete expected.hooks.state;
55958
56244
  try {
55959
- if (!isDeepStrictEqual4(prune(Bun.TOML.parse(noState)), prune(expected)))
56245
+ if (!isDeepStrictEqual5(prune(Bun.TOML.parse(noState)), prune(expected)))
55960
56246
  throw fail2();
55961
56247
  } catch {
55962
56248
  throw fail2();
@@ -56026,55 +56312,55 @@ var init_codex_hook_trust_layout = () => {};
56026
56312
 
56027
56313
  // src/lib/codex-hook-additions-review.ts
56028
56314
  import { isAbsolute as isAbsolute16 } from "path";
56029
- import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
56315
+ import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
56030
56316
  function exactKeys2(value, keys2) {
56031
- need5(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual5(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56317
+ need6(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual6(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56032
56318
  }
56033
56319
  function readReviewedAdditionTrustStates(proof, before2, current, journalHooks) {
56034
56320
  const captured = proofs.get(proof);
56035
- need5(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual5(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
56321
+ need6(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual6(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
56036
56322
  captured.recheck();
56037
56323
  unchanged2(before2);
56038
56324
  unchanged2(current);
56039
56325
  return captured.states;
56040
56326
  }
56041
56327
  function reviewNativeHookAdditions(options) {
56042
- need5(isAbsolute16(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
56328
+ need6(isAbsolute16(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
56043
56329
  const reviewFile = snapshot(options.path, true), review = JSON.parse(reviewFile.text);
56044
56330
  exactKeys2(review, ["version", "kind", "reason", "producerEvidence", "journalIntentSha256", "policySha256", "configCurrentSha256", "hooksCurrentSha256", "producerBefore", "additions"]);
56045
- need5((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56331
+ need6((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56046
56332
  for (const [name, expected] of [["journalIntentSha256", options.intent.sha256], ["policySha256", options.policy.sha256], ["configCurrentSha256", options.configCurrent.sha256], ["hooksCurrentSha256", options.hooksCurrent.sha256]])
56047
- need5(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
56333
+ need6(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
56048
56334
  exactKeys2(review.producerBefore, ["configPath", "configSha256", "hooksPath", "hooksSha256"]);
56049
56335
  const before2 = review.producerBefore;
56050
- need5(isAbsolute16(before2.configPath) && isAbsolute16(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56336
+ need6(isAbsolute16(before2.configPath) && isAbsolute16(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56051
56337
  const producerConfig = snapshot(before2.configPath, true), producerHooks = snapshot(before2.hooksPath, true);
56052
- need5(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56338
+ need6(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56053
56339
  const original = structure(options.configBefore.text), producer = structure(producerConfig.text), expectedProducer = structuredClone(original), originalKeys = options.journalHooks.map((hook) => hook.key);
56054
56340
  expectedProducer.hooks ??= {};
56055
56341
  expectedProducer.hooks.state ??= {};
56056
56342
  for (const hook of options.journalHooks)
56057
56343
  expectedProducer.hooks.state[hook.key] = { ...expectedProducer.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
56058
- need5(isDeepStrictEqual5(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56059
- need5(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56344
+ need6(isDeepStrictEqual6(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56345
+ need6(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56060
56346
  const expectedHooks = JSON.parse(options.hooksBefore.text), currentHooks = JSON.parse(options.hooksCurrent.text), expectedConfig = structuredClone(producer);
56061
- need5(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56347
+ need6(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56062
56348
  const added = [], states = [], seen = new Set, commands = new Set(options.recordedNativeHooks.map((hook) => hook.command));
56063
56349
  for (const addition of review.additions) {
56064
56350
  exactKeys2(addition, review.version === 1 ? ["event", "nativeHook"] : ["event", "nativeHook", "trustState"]);
56065
- need5(Object.hasOwn(review.version === 1 ? events : matchedEvents, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
56351
+ need6(Object.hasOwn(review.version === 1 ? events : matchedEvents, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
56066
56352
  const { event, nativeHook: hook } = addition;
56067
56353
  exactKeys2(hook, nativeKeys);
56068
56354
  const groups = expectedHooks.hooks[event] ?? [];
56069
- need5(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
56355
+ need6(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
56070
56356
  const key = `${options.nativeHooksPath}:${matchedEvents[event][1]}:${groups.length}:0`;
56071
- need5(hook.key === key && !seen.has(key) && !options.recordedNativeHooks.some((originalHook) => originalHook.key === key) && !Object.hasOwn(expectedConfig.hooks.state, key), "RECONCILE_ADDITIONS_IDENTITY");
56072
- need5(hook.eventName === matchedEvents[event][0] && hook.handlerType === "command" && (review.version === 2 ? v2Command(hook.command) : text2(hook.command, 16384)) && !commands.has(hook.command) && Number.isInteger(hook.timeoutSec) && hook.timeoutSec > 0 && hook.timeoutSec <= 60 && (event === "PreToolUse" ? text2(hook.matcher) : hook.matcher === null) && hook.async === false && hook.statusMessage === null && hook.additionalContextLimit === null && hook.sourcePath === options.nativeHooksPath && hook.source === "user" && hook.pluginId === null && hook.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash) && hook.enabled === true && hook.trustStatus === "trusted", "RECONCILE_ADDITIONS_IDENTITY");
56357
+ need6(hook.key === key && !seen.has(key) && !options.recordedNativeHooks.some((originalHook) => originalHook.key === key) && !Object.hasOwn(expectedConfig.hooks.state, key), "RECONCILE_ADDITIONS_IDENTITY");
56358
+ need6(hook.eventName === matchedEvents[event][0] && hook.handlerType === "command" && (review.version === 2 ? v2Command(hook.command) : text2(hook.command, 16384)) && !commands.has(hook.command) && Number.isInteger(hook.timeoutSec) && hook.timeoutSec > 0 && hook.timeoutSec <= 60 && (event === "PreToolUse" ? text2(hook.matcher) : hook.matcher === null) && hook.async === false && hook.statusMessage === null && hook.additionalContextLimit === null && hook.sourcePath === options.nativeHooksPath && hook.source === "user" && hook.pluginId === null && hook.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash) && hook.enabled === true && hook.trustStatus === "trusted", "RECONCILE_ADDITIONS_IDENTITY");
56073
56359
  let trustState = { enabled: true, trusted_hash: hook.currentHash };
56074
56360
  if (review.version === 2) {
56075
56361
  const state = addition.trustState;
56076
56362
  exactKeys2(state, state && Object.hasOwn(state, "enabled") ? ["enabled", "trusted_hash"] : ["trusted_hash"]);
56077
- need5(state.trusted_hash === hook.currentHash && (!Object.hasOwn(state, "enabled") || state.enabled === true), "RECONCILE_ADDITIONS_TRUST_STATE");
56363
+ need6(state.trusted_hash === hook.currentHash && (!Object.hasOwn(state, "enabled") || state.enabled === true), "RECONCILE_ADDITIONS_TRUST_STATE");
56078
56364
  trustState = { ...state };
56079
56365
  }
56080
56366
  seen.add(key);
@@ -56084,9 +56370,9 @@ function reviewNativeHookAdditions(options) {
56084
56370
  expectedHooks.hooks[event] = [...groups, { ...event === "PreToolUse" ? { matcher: hook.matcher } : {}, hooks: [{ type: "command", command: hook.command, timeout: hook.timeoutSec }] }];
56085
56371
  expectedConfig.hooks.state[key] = trustState;
56086
56372
  }
56087
- need5(isDeepStrictEqual5(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56373
+ need6(isDeepStrictEqual6(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56088
56374
  const keys2 = added.map((hook) => hook.key);
56089
- need5(isDeepStrictEqual5(expectedConfig, structure(options.configCurrent.text)) && codexTrustReconcileWitness(producerConfig.text, keys2) === codexTrustReconcileWitness(options.configCurrent.text, keys2) && codexTrustUnmanagedSemantic(producerConfig.text, keys2) === codexTrustUnmanagedSemantic(options.configCurrent.text, keys2), "RECONCILE_ADDITIONS_CONFIG");
56375
+ need6(isDeepStrictEqual6(expectedConfig, structure(options.configCurrent.text)) && codexTrustReconcileWitness(producerConfig.text, keys2) === codexTrustReconcileWitness(options.configCurrent.text, keys2) && codexTrustUnmanagedSemantic(producerConfig.text, keys2) === codexTrustUnmanagedSemantic(options.configCurrent.text, keys2), "RECONCILE_ADDITIONS_CONFIG");
56090
56376
  const inputs = [reviewFile, producerConfig, producerHooks, options.intent, options.policy, options.configBefore, options.configCurrent, options.hooksBefore, options.hooksCurrent];
56091
56377
  const recheck = () => {
56092
56378
  for (const input of inputs)
@@ -56108,8 +56394,8 @@ var init_codex_hook_additions_review = __esm(() => {
56108
56394
  });
56109
56395
 
56110
56396
  // src/lib/codex-hook-discovery-recovery.ts
56111
- import { createHash as createHash16 } from "crypto";
56112
- import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
56397
+ import { createHash as createHash17 } from "crypto";
56398
+ import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
56113
56399
  function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, additions) {
56114
56400
  const journalHooks = hooks.map(({ key, currentHash }) => ({ key, currentHash }));
56115
56401
  const additionStates = additions ? readReviewedAdditionTrustStates(additions, before2, current, journalHooks) : [];
@@ -56120,16 +56406,16 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
56120
56406
  const raw = binding.sources.filter((source) => source.path === current.file && source.hashMode === "bytes");
56121
56407
  if (!raw.some((source) => source.sha256 !== current.sha256))
56122
56408
  return;
56123
- need5(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
56124
- need5(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
56409
+ need6(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
56410
+ need6(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
56125
56411
  const typed = binding.sources.filter((source) => source.path === current.file && source.format === "toml");
56126
- need5(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual6(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
56412
+ need6(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual7(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
56127
56413
  const original = structure2(before2.text), actual = structure2(current.text);
56128
56414
  const project = (value) => Object.fromEntries(fields.map((field2) => [field2, value[field2] ?? null]));
56129
- const projection = sha3(JSON.stringify(project(original)));
56130
- need5(typed[0].sha256 === projection && sha3(JSON.stringify(project(actual))) === projection && isDeepStrictEqual6(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
56415
+ const projection = sha4(JSON.stringify(project(original)));
56416
+ need6(typed[0].sha256 === projection && sha4(JSON.stringify(project(actual))) === projection && isDeepStrictEqual7(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
56131
56417
  const keys2 = [...journalHooks.map((hook) => hook.key), ...additionStates.map((hook) => hook.key)];
56132
- need5(journalHooks.length > 0 && keys2.length <= 100 && new Set(keys2).size === keys2.length && journalHooks.every((hook) => typeof hook.key === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash)), "RECONCILE_DISCOVERY_TRUST_WITNESS");
56418
+ need6(journalHooks.length > 0 && keys2.length <= 100 && new Set(keys2).size === keys2.length && journalHooks.every((hook) => typeof hook.key === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash)), "RECONCILE_DISCOVERY_TRUST_WITNESS");
56133
56419
  const expected = structuredClone(original);
56134
56420
  expected.hooks ??= {};
56135
56421
  expected.hooks.state ??= {};
@@ -56137,16 +56423,16 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
56137
56423
  expected.hooks.state[hook.key] = { ...expected.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
56138
56424
  for (const { key, state } of additionStates)
56139
56425
  expected.hooks.state[key] = { ...state };
56140
- need5(isDeepStrictEqual6(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
56426
+ need6(isDeepStrictEqual7(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
56141
56427
  unchanged2(before2);
56142
56428
  unchanged2(current);
56143
- const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha3(JSON.stringify(binding)), typedProjectionSha256: projection });
56429
+ const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha4(JSON.stringify(binding)), typedProjectionSha256: projection });
56144
56430
  proofs2.set(witness, { before: before2, current, recheckAdditions });
56145
56431
  return witness;
56146
56432
  }
56147
56433
  function assertCodexHookDiscoveryRecovery(binding, witness) {
56148
56434
  const proof = proofs2.get(witness);
56149
- need5(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha3(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56435
+ need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha4(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56150
56436
  unchanged2(proof.before);
56151
56437
  unchanged2(proof.current);
56152
56438
  proof.recheckAdditions();
@@ -56155,23 +56441,24 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
56155
56441
  if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
56156
56442
  return false;
56157
56443
  assertCodexHookDiscoveryRecovery(binding, witness);
56158
- need5(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56444
+ need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56159
56445
  return true;
56160
56446
  }
56161
- var sha3 = (text3) => createHash16("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
56447
+ var sha4 = (text3) => createHash17("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
56162
56448
  var init_codex_hook_discovery_recovery = __esm(() => {
56163
56449
  init_codex_hook_trust_files();
56164
56450
  init_codex_hook_trust_layout();
56165
56451
  init_codex_hook_additions_review();
56166
- fields = ["plugins", "marketplaces", "skills"];
56452
+ init_codex_settings_witness();
56453
+ fields = [...CODEX_DISCOVERY_PROJECTION_FIELDS];
56167
56454
  proofs2 = new WeakMap;
56168
56455
  });
56169
56456
 
56170
56457
  // src/lib/agent-discovery.ts
56171
- import { createHash as createHash17 } from "crypto";
56458
+ import { createHash as createHash18 } from "crypto";
56172
56459
  import { lstatSync as lstatSync21, readFileSync as readFileSync18, readdirSync as readdirSync11, realpathSync as realpathSync7 } from "fs";
56173
56460
  import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute17, join as join32, resolve as resolve16, sep as sep6 } from "path";
56174
- import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
56461
+ import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
56175
56462
  function parseConfig(text3, path, toml = false) {
56176
56463
  try {
56177
56464
  const value = toml ? Bun.TOML.parse(text3) : JSON.parse(text3);
@@ -56203,14 +56490,26 @@ function read2(path, changes) {
56203
56490
  throw new Error(`Unsupported or oversized native discovery input: ${path}`);
56204
56491
  return readFileSync18(path, "utf8");
56205
56492
  }
56493
+ function projectNativeDiscoveryFields(text3, format, fields2, path) {
56494
+ const object5 = format === "yaml" ? parseHermesConfig(text3) : parseConfig(text3, path, format === "toml");
56495
+ if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
56496
+ throw new Error("Expected native discovery configuration object");
56497
+ return digest(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object5[field2] ?? null]))));
56498
+ }
56499
+ function isSupersededCodexProjection(agent, configPath, source) {
56500
+ return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual8(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
56501
+ }
56502
+ function supersedesCodexProjection(sources, configPath) {
56503
+ return sources.some((source) => source.path === configPath && source.hashMode === "codex-settings-v2");
56504
+ }
56206
56505
  function projected(source, changes, budget = discoveryByteBudget()) {
56207
- if (source.hashMode === "codex-settings-v1") {
56506
+ if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") {
56208
56507
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
56209
56508
  throw new Error("Codex settings witnesses require exact typed metadata");
56210
- const current = captureCodexSettings(source.path, budget).sha256;
56509
+ const current = (source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
56211
56510
  if (current !== source.sha256)
56212
56511
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
56213
- return changes?.has(source.path) ? hashCodexSettingsReplacement(changes.get(source.path), budget) : current;
56512
+ return changes?.has(source.path) ? (source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
56214
56513
  }
56215
56514
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
56216
56515
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
@@ -56249,10 +56548,7 @@ function projected(source, changes, budget = discoveryByteBudget()) {
56249
56548
  return null;
56250
56549
  if (!source.format)
56251
56550
  return digest(text3);
56252
- const object5 = source.format === "yaml" ? parseHermesConfig(text3) : parseConfig(text3, source.path, source.format === "toml");
56253
- if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
56254
- throw new Error("Expected native discovery configuration object");
56255
- return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field2) => [field2, object5[field2] ?? null]))));
56551
+ return projectNativeDiscoveryFields(text3, source.format, source.fields ?? [], source.path);
56256
56552
  }
56257
56553
  function verifyAgentDiscovery(binding, codexRecovery) {
56258
56554
  if (codexRecovery)
@@ -56280,7 +56576,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
56280
56576
  safe4(root2);
56281
56577
  }
56282
56578
  function assertMarketplaceBinding(binding, source) {
56283
- if (source.hashMode === "codex-settings-v1" && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
56579
+ if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
56284
56580
  throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
56285
56581
  if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename9(source.path) !== "settings.json"))
56286
56582
  throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
@@ -56297,8 +56593,8 @@ function rebindAgentDiscovery(binding, changes) {
56297
56593
  return { ...source, sha256: sha2562 };
56298
56594
  }) };
56299
56595
  }
56300
- function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16, reviewed) {
56301
- const homeConfigPath = canonical5(agentDiscoveryConfigPath(home, agent));
56596
+ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve16, reviewed) {
56597
+ const homeConfigPath = canonical6(agentDiscoveryConfigPath(home, agent));
56302
56598
  for (const directory of directories) {
56303
56599
  const isHome = resolve16(directory) === resolve16(home);
56304
56600
  if (agent === "hermes") {
@@ -56309,7 +56605,7 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16
56309
56605
  continue;
56310
56606
  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"] : [".cursor/hooks.json"];
56311
56607
  for (const suffix of paths) {
56312
- const path = canonical5(join32(directory, suffix)), raw = read2(path);
56608
+ const path = canonical6(join32(directory, suffix)), raw = read2(path);
56313
56609
  if (raw === null)
56314
56610
  continue;
56315
56611
  const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
@@ -56325,14 +56621,14 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16
56325
56621
  const managed = reviewed.sources.flatMap((source) => source.hashMode === "claude-plugin-registry" ? source.managedPlugins ?? [] : []);
56326
56622
  if (exact && projected(exact) === exact.sha256 && managed.length) {
56327
56623
  const bindings = managed.map((item) => readPluginBinding(item.storeRoot, item.bindingId));
56328
- admittedPlugins = Object.entries(config.enabledPlugins).every(([id, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath === canonical5(directory))));
56624
+ admittedPlugins = Object.entries(config.enabledPlugins).every(([id, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath === canonical6(directory))));
56329
56625
  }
56330
56626
  }
56331
56627
  if (keys2.some((key) => config[key] !== undefined && !(key === "enabledPlugins" && admittedPlugins)) || config.disableAllHooks === true || config.disableBundledSkills === false || config.hooksConfig?.enabled === false || config.permission?.skill !== undefined || config.permissions?.deny?.some((rule) => typeof rule === "string" && /^Skill(?:\(|$)/.test(rule)))
56332
56628
  throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
56333
56629
  }
56334
56630
  if (agent === "claude") {
56335
- const commands = canonical5(join32(directory, ".claude/commands"));
56631
+ const commands = canonical6(join32(directory, ".claude/commands"));
56336
56632
  safe4(commands);
56337
56633
  if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync11(commands).length)
56338
56634
  throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
@@ -56343,10 +56639,10 @@ function agentDiscoveryConfigPath(home, agent) {
56343
56639
  return join32(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
56344
56640
  }
56345
56641
  function resolveAgentDiscovery(options) {
56346
- const canonical5 = options.canonical ?? resolve16, home = resolve16(options.home), agent = options.agent;
56642
+ const canonical6 = options.canonical ?? resolve16, home = resolve16(options.home), agent = options.agent;
56347
56643
  const sources = [], roots = new Set, builtinNames = [];
56348
56644
  const witness = (path, format, fields2) => {
56349
- const source = { path: canonical5(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
56645
+ const source = { path: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
56350
56646
  source.sha256 = projected(source);
56351
56647
  sources.push(source);
56352
56648
  return read2(source.path);
@@ -56354,7 +56650,7 @@ function resolveAgentDiscovery(options) {
56354
56650
  if (agent === "hermes")
56355
56651
  assertHermesEnvironment(home);
56356
56652
  const configPath = agentDiscoveryConfigPath(home, agent);
56357
- const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? ["plugins", "marketplaces", "skills"] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : ["version"]);
56653
+ const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : ["version"]);
56358
56654
  const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
56359
56655
  const unresolved = (detail) => {
56360
56656
  throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
@@ -56413,11 +56709,12 @@ function resolveAgentDiscovery(options) {
56413
56709
  if (retained.agent !== agent || retained.method !== "reviewed")
56414
56710
  unresolved("invalid retained review");
56415
56711
  verifyAgentDiscovery(retained);
56416
- if (!retained.sources.some((source) => source.path === canonical5(configPath) && source.format === undefined && source.fields === undefined))
56712
+ if (!retained.sources.some((source) => source.path === canonical6(configPath) && source.format === undefined && source.fields === undefined))
56417
56713
  unresolved("retained review is missing the full agent configuration source");
56418
- if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "codex-settings-v1")) && source.path !== canonical5(configPath)))
56714
+ if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2"))) && source.path !== canonical6(configPath)))
56419
56715
  unresolved("retained settings witness names another configuration source");
56420
- if (sources.some((source) => !retained.sources.some((saved) => isDeepStrictEqual7(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
56716
+ const covered = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
56717
+ if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual8(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
56421
56718
  unresolved("retained review is missing current runtime discovery coverage");
56422
56719
  return retained;
56423
56720
  }
@@ -56431,14 +56728,15 @@ function resolveAgentDiscovery(options) {
56431
56728
  if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
56432
56729
  throw new Error("Explicit discovery reviews require full source-file hashes");
56433
56730
  verifyAgentDiscovery(supplied);
56434
- if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "codex-settings-v1")) && source.path !== canonical5(configPath)))
56731
+ if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2"))) && source.path !== canonical6(configPath)))
56435
56732
  throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
56436
- if (!review.sources.some((source) => source.path === canonical5(configPath)))
56733
+ if (!review.sources.some((source) => source.path === canonical6(configPath)))
56437
56734
  throw new Error("Discovery review must include the agent configuration source");
56438
- return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...sources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
56735
+ const reviewedSources = supersedesCodexProjection(review.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
56736
+ return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...reviewedSources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
56439
56737
  }
56440
56738
  function plugin(root2) {
56441
- root2 = canonical5(root2);
56739
+ root2 = canonical6(root2);
56442
56740
  safe4(root2);
56443
56741
  const manifestPath = join32(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
56444
56742
  const raw = witness(manifestPath);
@@ -56470,7 +56768,7 @@ function resolveAgentDiscovery(options) {
56470
56768
  if (agent === "claude") {
56471
56769
  const registrations = witness(join32(home, ".claude/plugins/installed_plugins.json"));
56472
56770
  const installed = registrations === null ? {} : parseConfig(registrations, join32(home, ".claude/plugins/installed_plugins.json")).plugins;
56473
- const commands = canonical5(join32(home, ".claude/commands"));
56771
+ const commands = canonical6(join32(home, ".claude/commands"));
56474
56772
  safe4(commands);
56475
56773
  if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync11(commands).length)
56476
56774
  unresolved("legacy home command discovery requires a dedicated format adapter");
@@ -56544,9 +56842,9 @@ function resolveAgentDiscovery(options) {
56544
56842
  roots.add(join32(root2, "skills"));
56545
56843
  }
56546
56844
  }
56547
- return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join32(home, ".hermes/plugins"), join32(home, ".hermes/hermes-agent")].map((path) => canonical5(path))) } : {} };
56845
+ return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join32(home, ".hermes/plugins"), join32(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
56548
56846
  }
56549
- var digest = (text3) => createHash17("sha256").update(text3).digest("hex");
56847
+ var digest = (text3) => createHash18("sha256").update(text3).digest("hex");
56550
56848
  var init_agent_discovery = __esm(() => {
56551
56849
  init_agent_policy_limits();
56552
56850
  init_agent_hermes();
@@ -56679,7 +56977,7 @@ import {
56679
56977
  statSync as statSync11,
56680
56978
  writeFileSync as writeFileSync9
56681
56979
  } from "fs";
56682
- import { basename as basename11, dirname as dirname19, isAbsolute as isAbsolute18, join as join34, normalize as normalize3, relative as relative6, resolve as resolve18, sep as sep8 } from "path";
56980
+ import { basename as basename11, dirname as dirname19, isAbsolute as isAbsolute18, join as join34, normalize as normalize4, relative as relative6, resolve as resolve18, sep as sep8 } from "path";
56683
56981
  function getPortableSkillsRoot(options = {}) {
56684
56982
  return resolvePortableSkillsRoot(options, true);
56685
56983
  }
@@ -56777,7 +57075,7 @@ function scaffoldPortableSkill(name, options = {}) {
56777
57075
  return { name: skillName, path: skillPath, manifest, created: true };
56778
57076
  }
56779
57077
  function portPortableSkillDirectory(sourceDir, options = {}) {
56780
- const absoluteSource = normalize3(sourceDir);
57078
+ const absoluteSource = normalize4(sourceDir);
56781
57079
  if (!existsSync18(absoluteSource) || !statSync11(absoluteSource).isDirectory()) {
56782
57080
  throw new Error(`Import directory not found: ${sourceDir}`);
56783
57081
  }
@@ -56844,7 +57142,7 @@ function assertDisjointImportPaths(source, destination) {
56844
57142
  }
56845
57143
  }
56846
57144
  function portPortableSkill(sourcePath, options = {}) {
56847
- const absoluteSource = normalize3(sourcePath);
57145
+ const absoluteSource = normalize4(sourcePath);
56848
57146
  if (!existsSync18(absoluteSource) || !statSync11(absoluteSource).isDirectory()) {
56849
57147
  throw new Error(`Skill source directory not found: ${sourcePath}`);
56850
57148
  }
@@ -57056,7 +57354,7 @@ function safeIsDirectory(path) {
57056
57354
  function isSafeRelativePath2(value) {
57057
57355
  if (!value.trim() || isAbsolute18(value))
57058
57356
  return false;
57059
- const normalized = normalize3(value).replace(/\\/g, "/");
57357
+ const normalized = normalize4(value).replace(/\\/g, "/");
57060
57358
  return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
57061
57359
  }
57062
57360
  function add4(target, code, message) {
@@ -59482,7 +59780,7 @@ var init_remote_workspace_selection = __esm(() => {
59482
59780
  });
59483
59781
 
59484
59782
  // src/lib/remote-private-publications.ts
59485
- import { createHash as createHash18 } from "crypto";
59783
+ import { createHash as createHash19 } from "crypto";
59486
59784
  function checkedPublicationDeclaration(value) {
59487
59785
  if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
59488
59786
  return bad();
@@ -59743,7 +60041,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures, PrivatePublicationError, bad = () =
59743
60041
  throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
59744
60042
  }, invalid3 = () => {
59745
60043
  throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
59746
- }, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record4 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record4(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash18("sha256").update(bytes).digest("hex");
60044
+ }, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record4 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record4(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash19("sha256").update(bytes).digest("hex");
59747
60045
  var init_remote_private_publications = __esm(() => {
59748
60046
  init_fleet_credentials();
59749
60047
  init_remote_workspace_selection();
@@ -63282,15 +63580,15 @@ var init_schemas = __esm(() => {
63282
63580
  } catch (_err) {}
63283
63581
  }
63284
63582
  const input = payload.value;
63285
- const isDate2 = input instanceof Date;
63286
- const isValidDate = isDate2 && !Number.isNaN(input.getTime());
63583
+ const isDate3 = input instanceof Date;
63584
+ const isValidDate = isDate3 && !Number.isNaN(input.getTime());
63287
63585
  if (isValidDate)
63288
63586
  return payload;
63289
63587
  payload.issues.push({
63290
63588
  expected: "date",
63291
63589
  code: "invalid_type",
63292
63590
  input,
63293
- ...isDate2 ? { received: "Invalid Date" } : {},
63591
+ ...isDate3 ? { received: "Invalid Date" } : {},
63294
63592
  inst
63295
63593
  });
63296
63594
  return payload;
@@ -79132,7 +79430,7 @@ var init_v4 = __esm(() => {
79132
79430
  });
79133
79431
 
79134
79432
  // src/lib/canonical-json.ts
79135
- import { createHash as createHash19 } from "crypto";
79433
+ import { createHash as createHash20 } from "crypto";
79136
79434
  function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
79137
79435
  return canonicalJsonAtDepth(value, maximumBytes, 64);
79138
79436
  }
@@ -79176,7 +79474,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
79176
79474
  return visit3(value, 0);
79177
79475
  }
79178
79476
  function canonicalJsonSha256(value, maximumBytes) {
79179
- return createHash19("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
79477
+ return createHash20("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
79180
79478
  }
79181
79479
  var init_canonical_json = () => {};
79182
79480
 
@@ -79511,7 +79809,7 @@ var init_remote_recurring = __esm(() => {
79511
79809
 
79512
79810
  // src/lib/remote-run-contract.ts
79513
79811
  function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
79514
- const record8 = isRecord3(payload) ? payload : {};
79812
+ const record8 = isRecord4(payload) ? payload : {};
79515
79813
  return {
79516
79814
  contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
79517
79815
  ...pickString(record8, "id"),
@@ -79533,7 +79831,7 @@ function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
79533
79831
  ...hasOwn(record8, "details") ? { details: record8.details } : {}
79534
79832
  };
79535
79833
  }
79536
- function isRecord3(value) {
79834
+ function isRecord4(value) {
79537
79835
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
79538
79836
  }
79539
79837
  function hasOwn(record8, key) {
@@ -79672,7 +79970,7 @@ var init_remote_credit_checkout = __esm(() => {
79672
79970
 
79673
79971
  // src/lib/remote-profile.ts
79674
79972
  function customerNamePatch(input2, field2) {
79675
- if (!isRecord4(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
79973
+ if (!isRecord5(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
79676
79974
  throw new Error("Provide only the requested name field.");
79677
79975
  const value = input2[field2];
79678
79976
  if (typeof value !== "string" || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value) || !value.trim() || [...value.trim()].length > 100) {
@@ -79680,22 +79978,22 @@ function customerNamePatch(input2, field2) {
79680
79978
  }
79681
79979
  return { [field2]: value.trim() };
79682
79980
  }
79683
- function isRecord4(value) {
79981
+ function isRecord5(value) {
79684
79982
  return !!value && typeof value === "object" && !Array.isArray(value);
79685
79983
  }
79686
79984
  function string4(value) {
79687
79985
  return typeof value === "string" && value.length > 0;
79688
79986
  }
79689
79987
  function parseUpdatedProfile(value) {
79690
- const user = isRecord4(value) && value.user;
79691
- if (!isRecord4(user) || !string4(user.id) || !string4(user.email) || !(user.displayName === null || typeof user.displayName === "string") || typeof user.role !== "string" || !["owner", "admin", "member", "viewer"].includes(user.role)) {
79988
+ const user = isRecord5(value) && value.user;
79989
+ if (!isRecord5(user) || !string4(user.id) || !string4(user.email) || !(user.displayName === null || typeof user.displayName === "string") || typeof user.role !== "string" || !["owner", "admin", "member", "viewer"].includes(user.role)) {
79692
79990
  throw new Error("The server returned an invalid account profile.");
79693
79991
  }
79694
79992
  return { user: { id: user.id, email: user.email, displayName: user.displayName, role: user.role } };
79695
79993
  }
79696
79994
  function parseUpdatedWorkspace(value) {
79697
- const organization2 = isRecord4(value) && value.organization;
79698
- if (!isRecord4(organization2) || !string4(organization2.id) || !string4(organization2.slug) || !string4(organization2.name)) {
79995
+ const organization2 = isRecord5(value) && value.organization;
79996
+ if (!isRecord5(organization2) || !string4(organization2.id) || !string4(organization2.slug) || !string4(organization2.name)) {
79699
79997
  throw new Error("The server returned an invalid workspace.");
79700
79998
  }
79701
79999
  return { organization: { id: organization2.id, slug: organization2.slug, name: organization2.name } };
@@ -80877,7 +81175,7 @@ async function requestAuthApi(instance, path, options) {
80877
81175
  const text4 = await res.text();
80878
81176
  const body = text4 ? parseJsonBody(text4) : {};
80879
81177
  if (!res.ok) {
80880
- const record9 = isRecord5(body) ? body : {};
81178
+ const record9 = isRecord6(body) ? body : {};
80881
81179
  const detail = typeof record9.detail === "string" ? record9.detail : undefined;
80882
81180
  const error61 = typeof record9.error === "string" ? record9.error : undefined;
80883
81181
  const code = typeof record9.code === "string" ? record9.code : undefined;
@@ -80905,7 +81203,7 @@ function condenseErrorBody(text4) {
80905
81203
  return collapsed;
80906
81204
  return `${collapsed.slice(0, MAX_ERROR_DETAIL_LENGTH - 1).trimEnd()}\u2026`;
80907
81205
  }
80908
- function isRecord5(value) {
81206
+ function isRecord6(value) {
80909
81207
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
80910
81208
  }
80911
81209
 
@@ -81090,10 +81388,10 @@ var init_remote_auth = __esm(() => {
81090
81388
  });
81091
81389
 
81092
81390
  // src/lib/sign-in.ts
81093
- import { createHash as createHash20 } from "crypto";
81391
+ import { createHash as createHash21 } from "crypto";
81094
81392
  import { chmodSync as chmodSync3, mkdirSync as mkdirSync12, readFileSync as readFileSync21, readdirSync as readdirSync14, renameSync as renameSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
81095
81393
  import { basename as basename13, dirname as dirname21, join as join37 } from "path";
81096
- function isRecord6(value) {
81394
+ function isRecord7(value) {
81097
81395
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
81098
81396
  }
81099
81397
  function boundedText(value, max2 = 2048) {
@@ -81118,7 +81416,7 @@ function clampIntervalMs(seconds) {
81118
81416
  return Math.min(MAX_INTERVAL_MS, Math.max(MIN_INTERVAL_MS, Math.round(seconds * 1000)));
81119
81417
  }
81120
81418
  function parseDeviceAuthorizationStart(body) {
81121
- const record9 = isRecord6(body) ? body : {};
81419
+ const record9 = isRecord7(body) ? body : {};
81122
81420
  if (typeof record9.error === "string") {
81123
81421
  throw new Error(typeof record9.detail === "string" ? record9.detail : record9.error);
81124
81422
  }
@@ -81152,7 +81450,7 @@ function pollDeviceToken(origin, deviceCode) {
81152
81450
  });
81153
81451
  }
81154
81452
  function deviceErrorCode(error61) {
81155
- if (!(error61 instanceof HostedApiError) && !(isRecord6(error61) && error61.name === "HostedApiError"))
81453
+ if (!(error61 instanceof HostedApiError) && !(isRecord7(error61) && error61.name === "HostedApiError"))
81156
81454
  return;
81157
81455
  const failure = error61;
81158
81456
  const named = [failure.code, failure.detail, failure.message].find((value) => value === "slow_down" || value === "authorization_pending" || value === "expired_token" || value === "invalid_device_code" || value === "access_denied");
@@ -81213,7 +81511,7 @@ async function pollDeviceAuthorization(input2) {
81213
81511
  throw error61;
81214
81512
  }
81215
81513
  }
81216
- const record9 = isRecord6(body) ? body : {};
81514
+ const record9 = isRecord7(body) ? body : {};
81217
81515
  const code = typeof record9.error === "string" ? record9.error : undefined;
81218
81516
  if (code === "authorization_pending" || code === undefined && record9.status === "pending") {
81219
81517
  await wait();
@@ -81241,7 +81539,7 @@ function pendingDeviceSignInStem(env3) {
81241
81539
  }
81242
81540
  function pendingDeviceSignInPath(origin, env3 = process.env) {
81243
81541
  const { dir, stem } = pendingDeviceSignInStem(env3);
81244
- return join37(dir, `${stem}-${createHash20("sha256").update(origin).digest("hex").slice(0, 16)}.json`);
81542
+ return join37(dir, `${stem}-${createHash21("sha256").update(origin).digest("hex").slice(0, 16)}.json`);
81245
81543
  }
81246
81544
  function savePendingDeviceSignIn(origin, start, env3 = process.env, now3 = Date.now()) {
81247
81545
  const path = pendingDeviceSignInPath(origin, env3);
@@ -81271,7 +81569,7 @@ function loadPendingDeviceSignIn(origin, env3 = process.env, now3 = Date.now())
81271
81569
  } catch {
81272
81570
  return null;
81273
81571
  }
81274
- if (!isRecord6(parsed))
81572
+ if (!isRecord7(parsed))
81275
81573
  return null;
81276
81574
  const deviceCode = boundedText(parsed.deviceCode, 512);
81277
81575
  const userCode = boundedText(parsed.userCode, 64);
@@ -81313,7 +81611,7 @@ function pendingDeviceSignInOrigins(env3 = process.env, now3 = Date.now()) {
81313
81611
  continue;
81314
81612
  try {
81315
81613
  const parsed = JSON.parse(readFileSync21(join37(location.dir, entry), "utf8"));
81316
- if (isRecord6(parsed) && typeof parsed.origin === "string" && Number(parsed.expiresAt) > now3 && pendingDeviceSignInPath(parsed.origin, env3) === join37(location.dir, entry))
81614
+ if (isRecord7(parsed) && typeof parsed.origin === "string" && Number(parsed.expiresAt) > now3 && pendingDeviceSignInPath(parsed.origin, env3) === join37(location.dir, entry))
81317
81615
  origins.push(parsed.origin);
81318
81616
  } catch {}
81319
81617
  }
@@ -81355,7 +81653,7 @@ async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "si
81355
81653
  headers: { Authorization: `Bearer ${result2.token}` },
81356
81654
  body: JSON.stringify({ name: "cli" })
81357
81655
  });
81358
- apiKey = isRecord6(created) && typeof created.key === "string" && created.key.trim() ? created.key : undefined;
81656
+ apiKey = isRecord7(created) && typeof created.key === "string" && created.key.trim() ? created.key : undefined;
81359
81657
  }
81360
81658
  if (!apiKey)
81361
81659
  throw new Error("Sign-in succeeded but the server returned no API key");
@@ -81394,7 +81692,7 @@ async function revokeStoredKey(origin, apiKey) {
81394
81692
  }
81395
81693
  return { outcome: "failed", detail: "the server could not be reached" };
81396
81694
  }
81397
- if (isRecord6(body) && body.revoked === true)
81695
+ if (isRecord7(body) && body.revoked === true)
81398
81696
  return { outcome: "revoked" };
81399
81697
  return { outcome: "not_revoked", detail: "the server answered without confirming revocation" };
81400
81698
  }
@@ -81518,10 +81816,10 @@ async function readSignedInAccount(env3 = process.env) {
81518
81816
  const body = await new RemoteSkillsAuthClient(connection.apiOrigin).request("/api/auth/whoami", {
81519
81817
  headers: { Authorization: `Bearer ${connection.apiKey}` }
81520
81818
  });
81521
- const record9 = isRecord6(body) ? body : {};
81522
- const data = isRecord6(record9.data) ? record9.data : {};
81523
- const user = isRecord6(record9.user) ? record9.user : isRecord6(data.user) ? data.user : {};
81524
- const organization2 = isRecord6(record9.organization) ? record9.organization : isRecord6(data.organization) ? data.organization : {};
81819
+ const record9 = isRecord7(body) ? body : {};
81820
+ const data = isRecord7(record9.data) ? record9.data : {};
81821
+ const user = isRecord7(record9.user) ? record9.user : isRecord7(data.user) ? data.user : {};
81822
+ const organization2 = isRecord7(record9.organization) ? record9.organization : isRecord7(data.organization) ? data.organization : {};
81525
81823
  const email4 = boundedText(user.email, 320);
81526
81824
  const org = boundedText(organization2.slug, 200) ?? boundedText(organization2.name, 200);
81527
81825
  return { ...base2, ...email4 ? { email: email4 } : {}, ...org ? { organization: org } : {} };
@@ -81936,7 +82234,7 @@ function optionPrefix(program2, args) {
81936
82234
  }
81937
82235
 
81938
82236
  // src/lib/revision.ts
81939
- import { createHash as createHash21 } from "crypto";
82237
+ import { createHash as createHash22 } from "crypto";
81940
82238
  function revisionIdOf(content) {
81941
82239
  const canonicalContent = {
81942
82240
  slug: content.slug,
@@ -81956,8 +82254,8 @@ function revisionIdOf(content) {
81956
82254
  canonicalContent.archiveReason = content.archiveReason ?? null;
81957
82255
  canonicalContent.replacementSlug = content.replacementSlug ?? null;
81958
82256
  }
81959
- const canonical5 = JSON.stringify(canonicalContent);
81960
- return createHash21("sha256").update(canonical5).digest("hex");
82257
+ const canonical6 = JSON.stringify(canonicalContent);
82258
+ return createHash22("sha256").update(canonical6).digest("hex");
81961
82259
  }
81962
82260
  var REVISION_ID_PATTERN;
81963
82261
  var init_revision = __esm(() => {
@@ -82406,7 +82704,7 @@ var init_pull = __esm(() => {
82406
82704
  });
82407
82705
 
82408
82706
  // src/lib/skill-context.ts
82409
- import { createHash as createHash22 } from "crypto";
82707
+ import { createHash as createHash23 } from "crypto";
82410
82708
  import { resolve as resolve19 } from "path";
82411
82709
  function words2(value) {
82412
82710
  return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
@@ -82495,7 +82793,7 @@ ${content}`;
82495
82793
  `);
82496
82794
  const receipt = {
82497
82795
  schemaVersion: 1,
82498
- id: createHash22("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
82796
+ id: createHash23("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
82499
82797
  profileId: profile.profileId,
82500
82798
  profileRevision: profile.profileRevision,
82501
82799
  authority: profile.authority,
@@ -82517,8 +82815,8 @@ var init_skill_context = __esm(() => {
82517
82815
  });
82518
82816
 
82519
82817
  // src/lib/session-reconciliation.ts
82520
- import { createHash as createHash23 } from "crypto";
82521
- import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
82818
+ import { createHash as createHash24 } from "crypto";
82819
+ import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
82522
82820
  function exactTimestamp(value) {
82523
82821
  const parsed = value === undefined ? Number.NaN : Date.parse(value);
82524
82822
  if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
@@ -82575,7 +82873,7 @@ async function reconcileSkillSessionIfSafe(sessionId, profileId, options = {}) {
82575
82873
  for (const key of old.loaded) {
82576
82874
  const previous = oldByKey.get(key);
82577
82875
  const current = targetBySlug.get(previous.slug);
82578
- if (!current || !isDeepStrictEqual8({ ...previous, profileRevision: target.profileRevision }, current)) {
82876
+ if (!current || !isDeepStrictEqual9({ ...previous, profileRevision: target.profileRevision }, current)) {
82579
82877
  throw new SkillSelectionError("SESSION_RECONCILIATION_REQUIRED", "A loaded Skills selection was removed or changed; review skills sessions reconcile before changing this session's pin.");
82580
82878
  }
82581
82879
  }
@@ -82657,7 +82955,7 @@ async function reconcileSkillSession(input2, options = {}) {
82657
82955
  const result2 = replaceSkillSession(skillSessionSnapshotBinding(snapshot2), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
82658
82956
  return { applied: true, plan, planDigest, ...result2 };
82659
82957
  }
82660
- var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash23("sha256").update(JSON.stringify(value)).digest("hex");
82958
+ var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash24("sha256").update(JSON.stringify(value)).digest("hex");
82661
82959
  var init_session_reconciliation = __esm(() => {
82662
82960
  init_profile_client();
82663
82961
  init_selection_cache();
@@ -83793,7 +84091,7 @@ function handleDiff(name, options) {
83793
84091
  const sourcePath = getSkillPath(bare);
83794
84092
  const canonicalDir = join39(resolveCorpusRoot(), normalized);
83795
84093
  const canonicalSkillMd = join39(canonicalDir, "SKILL.md");
83796
- const canonical5 = {
84094
+ const canonical6 = {
83797
84095
  present: existsSync22(canonicalSkillMd),
83798
84096
  path: canonicalDir,
83799
84097
  ...existsSync22(canonicalSkillMd) ? { hash: hashSkillMarkdownFile(canonicalSkillMd) } : {},
@@ -83825,7 +84123,7 @@ function handleDiff(name, options) {
83825
84123
  stub = undefined;
83826
84124
  }
83827
84125
  }
83828
- const diverged = present && canonical5.present && managed && hash5 !== canonical5.hash;
84126
+ const diverged = present && canonical6.present && managed && hash5 !== canonical6.hash;
83829
84127
  homes.push({
83830
84128
  agent,
83831
84129
  path: dir,
@@ -83840,7 +84138,7 @@ function handleDiff(name, options) {
83840
84138
  if (options.json) {
83841
84139
  console.log(JSON.stringify({
83842
84140
  name: bare,
83843
- canonical: canonical5,
84141
+ canonical: canonical6,
83844
84142
  pinned,
83845
84143
  installedVersion,
83846
84144
  registryVersion,
@@ -83848,10 +84146,10 @@ function handleDiff(name, options) {
83848
84146
  homes
83849
84147
  }, null, 2));
83850
84148
  } else {
83851
- if (!canonical5.present) {
84149
+ if (!canonical6.present) {
83852
84150
  console.log(source_default.yellow(`${bare}: no canonical corpus entry`));
83853
84151
  } else {
83854
- console.log(source_default.dim(`${bare} canonical: ${canonical5.hash?.slice(0, 12)}\u2026`));
84152
+ console.log(source_default.dim(`${bare} canonical: ${canonical6.hash?.slice(0, 12)}\u2026`));
83855
84153
  }
83856
84154
  if (pinned) {
83857
84155
  console.log(upToDate ? source_default.green(`\u2713 pin is up to date (${installedVersion})`) : source_default.yellow(`pin metadata differs: ${installedVersion} \u2192 ${registryVersion}`));
@@ -83862,14 +84160,14 @@ function handleDiff(name, options) {
83862
84160
  } else if (!home.managed) {
83863
84161
  console.log(`${source_default.dim("\u2022")} ${home.agent}: ${source_default.yellow("unmarked (adoption candidate)")}`);
83864
84162
  } else if (home.diverged) {
83865
- const stubNote = home.stub === true ? " (home is a pointer stub; canonical holds content)" : canonical5.stub === true ? " (home holds content; canonical renders a pointer stub \u2014 sync refuses to replace it)" : "";
83866
- console.log(`${source_default.red("\u2717")} ${home.agent}: ${source_default.red("diverged")} ${source_default.dim(home.hash?.slice(0, 12))} \u2260 ${source_default.dim(canonical5.hash?.slice(0, 12))}${stubNote}`);
84163
+ const stubNote = home.stub === true ? " (home is a pointer stub; canonical holds content)" : canonical6.stub === true ? " (home holds content; canonical renders a pointer stub \u2014 sync refuses to replace it)" : "";
84164
+ console.log(`${source_default.red("\u2717")} ${home.agent}: ${source_default.red("diverged")} ${source_default.dim(home.hash?.slice(0, 12))} \u2260 ${source_default.dim(canonical6.hash?.slice(0, 12))}${stubNote}`);
83867
84165
  } else {
83868
84166
  console.log(`${source_default.green("\u2713")} ${home.agent}: ${source_default.green("matches canonical")}`);
83869
84167
  }
83870
84168
  }
83871
84169
  }
83872
- if (divergedHomes.length > 0 || homes.length > 0 && !canonical5.present)
84170
+ if (divergedHomes.length > 0 || homes.length > 0 && !canonical6.present)
83873
84171
  process.exitCode = 1;
83874
84172
  }
83875
84173
  var init_introspect = __esm(() => {
@@ -87175,7 +87473,7 @@ var init_execution_grants = __esm(() => {
87175
87473
  });
87176
87474
 
87177
87475
  // src/lib/execution-grant-client.ts
87178
- import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
87476
+ import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
87179
87477
  function id(value) {
87180
87478
  if (!grantIdentifier(value))
87181
87479
  throw new Error("Invalid execution grant profile or revision identifier.");
@@ -87227,7 +87525,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
87227
87525
  headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
87228
87526
  body: JSON.stringify({ grants: snapshot2 })
87229
87527
  }));
87230
- if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual9(policy.grants, snapshot2)) {
87528
+ if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual10(policy.grants, snapshot2)) {
87231
87529
  throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
87232
87530
  }
87233
87531
  return policy;
@@ -87238,7 +87536,7 @@ async function resolveExecutionGrant(input2) {
87238
87536
  if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
87239
87537
  throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
87240
87538
  }
87241
- if (!isDeepStrictEqual9(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual9(value.bindings.consumer, snapshot2.consumer)) {
87539
+ if (!isDeepStrictEqual10(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual10(value.bindings.consumer, snapshot2.consumer)) {
87242
87540
  throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
87243
87541
  }
87244
87542
  return value;
@@ -87257,7 +87555,7 @@ __export(exports_selected_run, {
87257
87555
  prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
87258
87556
  executeSelectedLocal: () => executeSelectedLocal
87259
87557
  });
87260
- import { createHash as createHash24 } from "crypto";
87558
+ import { createHash as createHash25 } from "crypto";
87261
87559
  import { spawn as spawn3 } from "child_process";
87262
87560
  import { mkdirSync as mkdirSync15, mkdtempSync as mkdtempSync4, writeFileSync as writeFileSync15, realpathSync as realpathSync11 } from "fs";
87263
87561
  import { dirname as dirname23, join as join45, resolve as resolve20 } from "path";
@@ -87383,7 +87681,7 @@ async function executeSelectedLocal(selected, options = {}) {
87383
87681
  selection: selection2,
87384
87682
  target: "local",
87385
87683
  runtime: runtimeName,
87386
- inputDigest: `sha256:${createHash24("sha256").update(input2).digest("hex")}`,
87684
+ inputDigest: `sha256:${createHash25("sha256").update(input2).digest("hex")}`,
87387
87685
  runDirectory,
87388
87686
  ...executionGrant ? { executionGrant } : {},
87389
87687
  ...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
@@ -91600,7 +91898,7 @@ var init_runs = __esm(() => {
91600
91898
  });
91601
91899
 
91602
91900
  // src/lib/run-state.ts
91603
- import { createHash as createHash25, randomBytes } from "crypto";
91901
+ import { createHash as createHash26, randomBytes } from "crypto";
91604
91902
  import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync32, readdirSync as readdirSync18, statSync as statSync16, writeFileSync as writeFileSync16 } from "fs";
91605
91903
  import { extname, join as join46, relative as relative7 } from "path";
91606
91904
  function createSkillRun(params, targetDir = process.cwd()) {
@@ -91737,7 +92035,7 @@ function collectRunArtifacts(context) {
91737
92035
  artifacts.push({
91738
92036
  path: toProjectRelative(context.targetDir, path),
91739
92037
  mime: mimeForPath(path),
91740
- sha256: createHash25("sha256").update(bytes).digest("hex"),
92038
+ sha256: createHash26("sha256").update(bytes).digest("hex"),
91741
92039
  sizeBytes: stat2.size
91742
92040
  });
91743
92041
  }
@@ -97463,8 +97761,8 @@ var require_resolve = __commonJS((exports) => {
97463
97761
  }
97464
97762
  return count;
97465
97763
  }
97466
- function getFullPath(resolver, id2 = "", normalize4) {
97467
- if (normalize4 !== false)
97764
+ function getFullPath(resolver, id2 = "", normalize5) {
97765
+ if (normalize5 !== false)
97468
97766
  id2 = normalizeId(id2);
97469
97767
  const p = resolver.parse(id2);
97470
97768
  return _getFullPath(resolver, p);
@@ -99023,7 +99321,7 @@ var require_fast_uri = __commonJS((exports, module) => {
99023
99321
  }
99024
99322
  return decodedScheme;
99025
99323
  }
99026
- function normalize4(uri, options) {
99324
+ function normalize5(uri, options) {
99027
99325
  if (typeof uri === "string") {
99028
99326
  uri = normalizeString(uri, options);
99029
99327
  } else if (typeof uri === "object") {
@@ -99400,7 +99698,7 @@ var require_fast_uri = __commonJS((exports, module) => {
99400
99698
  }
99401
99699
  var fastUri = {
99402
99700
  SCHEMES,
99403
- normalize: normalize4,
99701
+ normalize: normalize5,
99404
99702
  resolve: resolve21,
99405
99703
  resolveComponent,
99406
99704
  equal,
@@ -104410,7 +104708,7 @@ async function continueRecurringRecovery(customer, directory, options) {
104410
104708
  throw error61;
104411
104709
  }
104412
104710
  }
104413
- var uuid11, sha4, common2, intentSchema, stateSchema, invalid6 = () => {
104711
+ var uuid11, sha5, common2, intentSchema, stateSchema, invalid6 = () => {
104414
104712
  throw new RecurringCustomerError("RECURRING_RECOVERY_INVALID", "The original recovery directory or record is invalid or changed. Preserve it; do not create a replacement activation automatically.");
104415
104713
  };
104416
104714
  var init_recurring_recovery = __esm(() => {
@@ -104420,7 +104718,7 @@ var init_recurring_recovery = __esm(() => {
104420
104718
  init_remote_recurring();
104421
104719
  init_recurring_customer();
104422
104720
  uuid11 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
104423
- sha4 = exports_external.string().regex(/^[a-f0-9]{64}$/);
104721
+ sha5 = exports_external.string().regex(/^[a-f0-9]{64}$/);
104424
104722
  common2 = exports_external.object({
104425
104723
  contractVersion: exports_external.literal(1),
104426
104724
  apiOrigin: exports_external.string().min(1).max(4096),
@@ -104433,7 +104731,7 @@ var init_recurring_recovery = __esm(() => {
104433
104731
  common2.extend({
104434
104732
  operation: exports_external.literal("activate"),
104435
104733
  draftId: uuid11,
104436
- termsSha256: sha4,
104734
+ termsSha256: sha5,
104437
104735
  approvalDeadline: exports_external.string().datetime(),
104438
104736
  approval: recurringActivationSchema
104439
104737
  }).strict(),
@@ -104441,7 +104739,7 @@ var init_recurring_recovery = __esm(() => {
104441
104739
  ]);
104442
104740
  stateSchema = exports_external.object({
104443
104741
  contractVersion: exports_external.literal(1),
104444
- intentSha256: sha4,
104742
+ intentSha256: sha5,
104445
104743
  phase: exports_external.enum(["prepared", "pending", "observed"]),
104446
104744
  consentId: uuid11.nullable()
104447
104745
  }).strict();
@@ -106985,7 +107283,7 @@ var init_schedule_tools = __esm(() => {
106985
107283
  });
106986
107284
 
106987
107285
  // src/lib/native-storage.ts
106988
- import { createHash as createHash26, createHmac as createHmac3 } from "crypto";
107286
+ import { createHash as createHash27, createHmac as createHmac3 } from "crypto";
106989
107287
  import {
106990
107288
  existsSync as existsSync31,
106991
107289
  mkdirSync as mkdirSync21,
@@ -106994,7 +107292,7 @@ import {
106994
107292
  statSync as statSync18,
106995
107293
  writeFileSync as writeFileSync20
106996
107294
  } from "fs";
106997
- import { dirname as dirname27, join as join52, normalize as normalize4, relative as relative8, sep as sep9 } from "path";
107295
+ import { dirname as dirname27, join as join52, normalize as normalize5, relative as relative8, sep as sep9 } from "path";
106998
107296
  function resolveSkillsNativeStorageConfig(env3 = process.env) {
106999
107297
  assertNoRetiredModeEnvVars(env3, {
107000
107298
  app: SKILLS_ENV_NAMESPACE,
@@ -107062,7 +107360,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
107062
107360
  files.push({
107063
107361
  path: relativePath,
107064
107362
  sizeBytes: bytes.byteLength,
107065
- sha256: createHash26("sha256").update(bytes).digest("hex"),
107363
+ sha256: createHash27("sha256").update(bytes).digest("hex"),
107066
107364
  ...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
107067
107365
  });
107068
107366
  }
@@ -108244,7 +108542,7 @@ var init_remote_account2 = __esm(() => {
108244
108542
  });
108245
108543
 
108246
108544
  // src/cli/commands/runtime-copyfile.ts
108247
- import { createHash as createHash27, randomUUID as randomUUID9 } from "crypto";
108545
+ import { createHash as createHash28, randomUUID as randomUUID9 } from "crypto";
108248
108546
  import { Readable } from "stream";
108249
108547
  import { createGunzip as createGunzip2 } from "zlib";
108250
108548
  import {
@@ -108268,7 +108566,7 @@ function object9(value, code2) {
108268
108566
  return value;
108269
108567
  }
108270
108568
  function hash5(bytes) {
108271
- return createHash27("sha256").update(bytes).digest("hex");
108569
+ return createHash28("sha256").update(bytes).digest("hex");
108272
108570
  }
108273
108571
  function isWithin(parent, child) {
108274
108572
  const rel = relative9(parent, child);
@@ -108419,7 +108717,7 @@ function verifyIntegrity(bytes, integrity) {
108419
108717
  const match = /^sha512-([A-Za-z0-9+/]+={0,2})$/.exec(integrity);
108420
108718
  if (!match)
108421
108719
  throw new Error("REGISTRY_INTEGRITY_UNSUPPORTED");
108422
- const actual = createHash27("sha512").update(bytes).digest("base64");
108720
+ const actual = createHash28("sha512").update(bytes).digest("base64");
108423
108721
  if (actual !== match[1])
108424
108722
  throw new Error("TARBALL_INTEGRITY_MISMATCH");
108425
108723
  }
@@ -109420,7 +109718,7 @@ var exports_runtime = {};
109420
109718
  __export(exports_runtime, {
109421
109719
  registerRuntime: () => registerRuntime
109422
109720
  });
109423
- import { createHash as createHash28, randomUUID as randomUUID10 } from "crypto";
109721
+ import { createHash as createHash29, randomUUID as randomUUID10 } from "crypto";
109424
109722
  import { lstatSync as lstatSync29, mkdirSync as mkdirSync25, readFileSync as readFileSync38, realpathSync as realpathSync15, writeFileSync as writeFileSync24 } from "fs";
109425
109723
  import { basename as basename15, isAbsolute as isAbsolute25, join as join56 } from "path";
109426
109724
  import { createInterface } from "readline";
@@ -109461,7 +109759,7 @@ function registerRuntime(parent) {
109461
109759
  if (!expected)
109462
109760
  throw new Error("Cloud artifact not found");
109463
109761
  const bytes = await client2.download(id2, name);
109464
- if (bytes.length !== expected.byteSize || createHash28("sha256").update(bytes).digest("hex") !== expected.sha256)
109762
+ if (bytes.length !== expected.byteSize || createHash29("sha256").update(bytes).digest("hex") !== expected.sha256)
109465
109763
  throw new Error("Cloud artifact integrity verification failed");
109466
109764
  writeFileSync24(options.output, bytes, { flag: "wx", mode: 384 });
109467
109765
  console.log(JSON.stringify({ path: options.output, sha256: expected.sha256, byteSize: bytes.length }));
@@ -111104,7 +111402,7 @@ var init_portable_snapshot_filter = __esm(() => {
111104
111402
  });
111105
111403
 
111106
111404
  // src/lib/station-snapshot.ts
111107
- import { createHash as createHash29 } from "crypto";
111405
+ import { createHash as createHash30 } from "crypto";
111108
111406
  import {
111109
111407
  copyFileSync as copyFileSync2,
111110
111408
  mkdirSync as mkdirSync26,
@@ -111119,7 +111417,7 @@ function validateStationId(stationId) {
111119
111417
  }
111120
111418
  }
111121
111419
  function sha256File(filePath) {
111122
- return createHash29("sha256").update(readFileSync39(filePath)).digest("hex");
111420
+ return createHash30("sha256").update(readFileSync39(filePath)).digest("hex");
111123
111421
  }
111124
111422
  function scanHome(definition, homesRoot) {
111125
111423
  const homePath = homePathFor(definition, homesRoot);
@@ -111691,8 +111989,8 @@ var init_create_sync_config = __esm(() => {
111691
111989
  });
111692
111990
 
111693
111991
  // src/lib/codex-native-config.ts
111694
- import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
111695
- function isRecord7(value) {
111992
+ import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
111993
+ function isRecord8(value) {
111696
111994
  if (!value || typeof value !== "object")
111697
111995
  return false;
111698
111996
  const prototype = Object.getPrototypeOf(value);
@@ -111713,10 +112011,10 @@ function decimalIdentity(text4) {
111713
112011
  return `${match[1]}${coefficient}e${exponent}`;
111714
112012
  }
111715
112013
  function codexNativeConfigEqual(native, expected) {
111716
- if (isDeepStrictEqual10(native, expected))
112014
+ if (isDeepStrictEqual11(native, expected))
111717
112015
  return true;
111718
112016
  if (typeof expected === "number") {
111719
- if (!Number.isFinite(expected) || !isRecord7(native))
112017
+ if (!Number.isFinite(expected) || !isRecord8(native))
111720
112018
  return false;
111721
112019
  const keys3 = Object.keys(native);
111722
112020
  const value = native[NUMBER_TAG];
@@ -111728,7 +112026,7 @@ function codexNativeConfigEqual(native, expected) {
111728
112026
  if (Array.isArray(native) || Array.isArray(expected)) {
111729
112027
  return Array.isArray(native) && Array.isArray(expected) && native.length === expected.length && native.every((value, index) => codexNativeConfigEqual(value, expected[index]));
111730
112028
  }
111731
- if (!isRecord7(native) || !isRecord7(expected))
112029
+ if (!isRecord8(native) || !isRecord8(expected))
111732
112030
  return false;
111733
112031
  const actual = native, wanted = expected;
111734
112032
  return Object.keys(actual).length === Object.keys(wanted).length && Object.keys(wanted).every((key) => Object.hasOwn(actual, key) && codexNativeConfigEqual(actual[key], wanted[key]));
@@ -111739,42 +112037,42 @@ var init_codex_native_config = () => {};
111739
112037
  // src/lib/codex-hook-trust-identity.ts
111740
112038
  import { realpathSync as realpathSync16 } from "fs";
111741
112039
  import { dirname as dirname33, isAbsolute as isAbsolute27, join as join59 } from "path";
111742
- import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
112040
+ import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
111743
112041
  function inspectRecordedSkillsCli(command, expected) {
111744
- need5(isAbsolute27(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
112042
+ need6(isAbsolute27(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
111745
112043
  const resolved = realpathSync16(command);
111746
112044
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
111747
112045
  const manifest = snapshot(join59(dirname33(dirname33(resolved)), "package.json"), false, { readOnlyPackage: true });
111748
112046
  const pkg = JSON.parse(manifest.text);
111749
- need5(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join59(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
111750
- need5((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
112047
+ need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join59(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
112048
+ need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
111751
112049
  const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
111752
- need5(isDeepStrictEqual11(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
112050
+ need6(isDeepStrictEqual12(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
111753
112051
  return { receipt, recheck() {
111754
- need5(realpathSync16(command) === resolved, "SKILLS_COMMAND_CHANGED");
112052
+ need6(realpathSync16(command) === resolved, "SKILLS_COMMAND_CHANGED");
111755
112053
  unchanged2(cli);
111756
112054
  unchanged2(manifest);
111757
112055
  } };
111758
112056
  }
111759
112057
  function bindSkillsCli(command, reviewed) {
111760
112058
  const normal = Bun.which("skills", { PATH: process.env.PATH });
111761
- need5(normal, "SKILLS_COMMAND_UNAVAILABLE");
112059
+ need6(normal, "SKILLS_COMMAND_UNAVAILABLE");
111762
112060
  const resolved = realpathSync16(normal);
111763
112061
  const bound = isAbsolute27(command) ? command : command === "skills" ? normal : undefined;
111764
- need5(bound && realpathSync16(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
112062
+ need6(bound && realpathSync16(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
111765
112063
  const entrypoint = reviewed?.path ?? process.argv[1];
111766
- need5(entrypoint && realpathSync16(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
112064
+ need6(entrypoint && realpathSync16(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
111767
112065
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
111768
112066
  const manifest = snapshot(join59(dirname33(dirname33(resolved)), "package.json"), false, { readOnlyPackage: true });
111769
112067
  const pkg = JSON.parse(manifest.text);
111770
- need5(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join59(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
112068
+ need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join59(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
111771
112069
  if (reviewed)
111772
- need5(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
111773
- need5((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
112070
+ need6(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
112071
+ need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
111774
112072
  return {
111775
112073
  receipt: { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 },
111776
112074
  recheck() {
111777
- need5(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync16(normal) === resolved && realpathSync16(bound) === resolved && realpathSync16(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
112075
+ need6(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync16(normal) === resolved && realpathSync16(bound) === resolved && realpathSync16(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
111778
112076
  unchanged2(cli);
111779
112077
  unchanged2(manifest);
111780
112078
  }
@@ -111785,19 +112083,19 @@ var init_codex_hook_trust_identity = __esm(() => {
111785
112083
  });
111786
112084
 
111787
112085
  // src/lib/codex-hook-policy-recovery.ts
111788
- import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
112086
+ import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
111789
112087
  function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
111790
- need5(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
111791
- need5(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
112088
+ need6(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
112089
+ need6(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
111792
112090
  const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
111793
112091
  const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
111794
- need5(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
111795
- const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual12(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
111796
- need5(changes.length > 0, "RECONCILE_POLICY_CHANGED");
112092
+ need6(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
112093
+ const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual13(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
112094
+ need6(changes.length > 0, "RECONCILE_POLICY_CHANGED");
111797
112095
  const compared = structuredClone(current);
111798
112096
  compared.bridge.discovery.claude.roots = oldDiscovery.roots;
111799
112097
  compared.bridge.discovery.claude.sources = oldDiscovery.sources;
111800
- need5(isDeepStrictEqual12(before2, compared), "RECONCILE_POLICY_CHANGED");
112098
+ need6(isDeepStrictEqual13(before2, compared), "RECONCILE_POLICY_CHANGED");
111801
112099
  verifyAgentDiscovery(newDiscovery);
111802
112100
  return { reason: options.reason, changes };
111803
112101
  }
@@ -111809,21 +112107,21 @@ var init_codex_hook_policy_recovery = __esm(() => {
111809
112107
 
111810
112108
  // src/lib/agent-codex-trust.ts
111811
112109
  import { lstatSync as lstatSync31, mkdirSync as mkdirSync27, readdirSync as readdirSync23, readFileSync as readFileSync40, realpathSync as realpathSync17, statSync as statSync21 } from "fs";
111812
- import { createHash as createHash30, randomUUID as randomUUID11 } from "crypto";
112110
+ import { createHash as createHash31, randomUUID as randomUUID11 } from "crypto";
111813
112111
  import { execFileSync } from "child_process";
111814
112112
  import { dirname as dirname34, isAbsolute as isAbsolute28, join as join60, resolve as resolve25 } from "path";
111815
112113
  import { homedir as homedir12 } from "os";
111816
- import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
112114
+ import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
111817
112115
  function verifyReleaseArtifact(proof, skillsCli) {
111818
- need5(isAbsolute28(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
112116
+ need6(isAbsolute28(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
111819
112117
  const tarPath = realpathSync17(proof.packageTarPath);
111820
- need5(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
112118
+ need6(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
111821
112119
  const tarBytes = readFileSync40(tarPath);
111822
- need5(tarBytes.byteLength === proof.packageTarBytes && createHash30("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
112120
+ need6(tarBytes.byteLength === proof.packageTarBytes && createHash31("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
111823
112121
  const packageRoot = dirname34(dirname34(realpathSync17(skillsCli.receipt.path)));
111824
112122
  const manifest = readFileSync40(join60(packageRoot, "package.json"));
111825
- need5(createHash30("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
111826
- need5(createHash30("sha256").update(readFileSync40(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
112123
+ need6(createHash31("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
112124
+ need6(createHash31("sha256").update(readFileSync40(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
111827
112125
  const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync40(skillsCli.receipt.path)]];
111828
112126
  for (const [member, expected] of members2) {
111829
112127
  let actual;
@@ -111832,7 +112130,7 @@ function verifyReleaseArtifact(proof, skillsCli) {
111832
112130
  } catch {
111833
112131
  throw new Error("RECONCILE_RELEASE_ARTIFACT_MEMBER_MISSING");
111834
112132
  }
111835
- need5(Buffer.compare(actual, expected) === 0, "RECONCILE_RELEASE_ARTIFACT_MEMBER_CHANGED");
112133
+ need6(Buffer.compare(actual, expected) === 0, "RECONCILE_RELEASE_ARTIFACT_MEMBER_CHANGED");
111836
112134
  }
111837
112135
  }
111838
112136
  async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc) {
@@ -111840,48 +112138,48 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111840
112138
  try {
111841
112139
  const home = resolve25(options.home ?? homedir12()), dataDir3 = resolve25(options.dataDir ?? getDataDirReadOnly());
111842
112140
  const parent = resolve25(join60(dataDir3, "native-hook-trust")), journal = resolve25(options.journal);
111843
- need5(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
112141
+ need6(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
111844
112142
  const dir = lstatSync31(journal, { throwIfNoEntry: false });
111845
- need5(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
111846
- need5(!lstatSync31(join60(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
111847
- need5(lstatSync31(join60(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
112143
+ need6(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
112144
+ need6(!lstatSync31(join60(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
112145
+ need6(lstatSync31(join60(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
111848
112146
  const stoppedFile = snapshot(join60(journal, "stopped.json"), true);
111849
112147
  const intentFile = snapshot(join60(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
111850
112148
  const configBefore = snapshot(join60(journal, "config.before.toml"), true), hooksBefore = snapshot(join60(journal, "hooks.before.json"), true), policyBefore = snapshot(join60(journal, "policy.before.json"), true);
111851
112149
  const legacyIntent = intent.home === undefined && intent.configSha256 === undefined && intent.configVersion === undefined && intent.declarations === undefined && intent.admitted === undefined && intent.nativeHooks === undefined;
111852
- need5(intent.version === 1 && /^[a-f0-9]{64}$/.test(intent.planDigest) && typeof intent.configPath === "string" && /^[a-f0-9]{64}$/.test(intent.policySha256) && /^[a-f0-9]{64}$/.test(intent.hooksSha256) && Array.isArray(intent.hooks) && intent.hooks.length > 0 && intent.hooks.length <= 100 && (legacyIntent || typeof intent.home === "string" && intent.home === home && /^[a-f0-9]{64}$/.test(intent.configSha256) && typeof intent.configVersion === "string" && Array.isArray(intent.declarations) && Array.isArray(intent.admitted) && Array.isArray(intent.nativeHooks)), "RECONCILE_INTENT_INVALID");
112150
+ need6(intent.version === 1 && /^[a-f0-9]{64}$/.test(intent.planDigest) && typeof intent.configPath === "string" && /^[a-f0-9]{64}$/.test(intent.policySha256) && /^[a-f0-9]{64}$/.test(intent.hooksSha256) && Array.isArray(intent.hooks) && intent.hooks.length > 0 && intent.hooks.length <= 100 && (legacyIntent || typeof intent.home === "string" && intent.home === home && /^[a-f0-9]{64}$/.test(intent.configSha256) && typeof intent.configVersion === "string" && Array.isArray(intent.declarations) && Array.isArray(intent.admitted) && Array.isArray(intent.nativeHooks)), "RECONCILE_INTENT_INVALID");
111853
112151
  const declarations = intent.declarations ?? intent.hooks.map((hook) => ({ event: hook.event, key: `${join60(home, ".codex/hooks.json")}${hook.key.slice(hook.key.indexOf(".codex/hooks.json") + ".codex/hooks.json".length)}`, command: hook.command }));
111854
112152
  const admitted = intent.admitted ?? intent.hooks;
111855
112153
  const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
111856
112154
  const digestInput = { version: 1, home: intent.home ?? home, configPath: intent.configPath, ...intent.nativeConfigPath !== undefined ? { nativeConfigPath: intent.nativeConfigPath } : {}, configSha256, configVersion, policySha256: intent.policySha256, hooksSha256: intent.hooksSha256, skillsCli: intent.skillsCli, nativeVersion: intent.nativeVersion, declarations, admitted };
111857
- need5(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
111858
- need5(isDeepStrictEqual13(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
111859
- need5(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
112155
+ need6(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
112156
+ need6(isDeepStrictEqual14(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
112157
+ need6(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
111860
112158
  const policyCurrent = snapshot(join60(dataDir3, "agent-policy.json"), true);
111861
112159
  const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
111862
112160
  const recovery = claudeRecovery ?? additionsRecovery;
111863
- need5(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
111864
- need5(!claudeRecovery || !additionsRecovery || claudeRecovery.reviewedPlanDigest === additionsRecovery.reviewedPlanDigest, "RECONCILE_RECOVERY_MODE_CONFLICT");
111865
- need5(recovery?.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(recovery.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
112161
+ need6(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
112162
+ need6(!claudeRecovery || !additionsRecovery || claudeRecovery.reviewedPlanDigest === additionsRecovery.reviewedPlanDigest, "RECONCILE_RECOVERY_MODE_CONFLICT");
112163
+ need6(recovery?.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(recovery.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
111866
112164
  const policyChange = claudeRecovery ? reviewedClaudeDiscoveryChange(policyBefore.text, policyCurrent.text, claudeRecovery) : undefined;
111867
112165
  let supersededBinding = false;
111868
112166
  if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
111869
- need5(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
112167
+ need6(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
111870
112168
  const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
111871
- need5(isDeepStrictEqual13(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
112169
+ need6(isDeepStrictEqual14(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
111872
112170
  supersededBinding = true;
111873
112171
  }
111874
112172
  if (supersededBinding || recovery) {
111875
- need5(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
112173
+ need6(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
111876
112174
  const proof = options.releaseProof;
111877
- need5(!!proof && isAbsolute28(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
112175
+ need6(!!proof && isAbsolute28(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
111878
112176
  }
111879
112177
  const currentConfig = snapshot(intent.configPath, true);
111880
112178
  const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
111881
112179
  const alias = binding.rootAliases?.find((item) => item.agent === "codex"), physicalRoot = alias?.target ?? join60(home, ".codex"), hooksPath = join60(physicalRoot, "hooks.json");
111882
- need5(resolve25(intent.configPath) === resolve25(join60(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
112180
+ need6(resolve25(intent.configPath) === resolve25(join60(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
111883
112181
  const nativeConfigPath = intent.nativeConfigPath ?? intent.configPath;
111884
- need5([join60(home, ".codex/config.toml"), join60(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
112182
+ need6([join60(home, ".codex/config.toml"), join60(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
111885
112183
  const codexHome = nativeConfigPath !== intent.configPath ? undefined : dirname34(nativeConfigPath);
111886
112184
  const hooksCurrent = snapshot(hooksPath);
111887
112185
  const additions = additionsRecovery ? reviewNativeHookAdditions({ path: additionsRecovery.path, intent: intentFile, policy: policyCurrent, configBefore, configCurrent: currentConfig, hooksBefore, hooksCurrent, nativeHooksPath: join60(dirname34(nativeConfigPath), "hooks.json"), journalHooks: intent.hooks, recordedNativeHooks: intent.nativeHooks }) : undefined;
@@ -111889,7 +112187,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111889
112187
  const managedKeys = managedHooks.map((h) => h.key);
111890
112188
  const witnessSame = codexTrustReconcileWitness(configBefore.text, managedKeys) === codexTrustReconcileWitness(currentConfig.text, managedKeys);
111891
112189
  const unmanagedSame = codexTrustUnmanagedSemantic(configBefore.text, managedKeys) === codexTrustUnmanagedSemantic(currentConfig.text, managedKeys);
111892
- need5(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
112190
+ need6(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
111893
112191
  const before2 = structure3(configBefore.text), current = structure3(currentConfig.text), expectedConfig = structuredClone(before2);
111894
112192
  expectedConfig.hooks ??= {};
111895
112193
  expectedConfig.hooks.state ??= {};
@@ -111901,10 +112199,10 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111901
112199
  if (supersededBinding) {
111902
112200
  for (const hook of intent.hooks) {
111903
112201
  const state = current.hooks?.state?.[hook.key];
111904
- need5(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
112202
+ need6(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
111905
112203
  }
111906
112204
  } else
111907
- need5(isDeepStrictEqual13(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
112205
+ need6(isDeepStrictEqual14(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
111908
112206
  const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
111909
112207
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
111910
112208
  const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
@@ -111913,29 +112211,29 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111913
112211
  const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
111914
112212
  if (supersededBinding)
111915
112213
  verifyReleaseArtifact(options.releaseProof, skillsCli);
111916
- const skillsBindingChanged = !isDeepStrictEqual13(skillsCli.receipt, intent.skillsCli);
111917
- need5(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
112214
+ const skillsBindingChanged = !isDeepStrictEqual14(skillsCli.receipt, intent.skillsCli);
112215
+ need6(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
111918
112216
  if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
111919
- need5(supersededBinding, "RECONCILE_HOOKS_CHANGED");
112217
+ need6(supersededBinding, "RECONCILE_HOOKS_CHANGED");
111920
112218
  const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
111921
112219
  for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
111922
112220
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
111923
- need5(isDeepStrictEqual13(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
112221
+ need6(isDeepStrictEqual14(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
111924
112222
  }
111925
112223
  }
111926
112224
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
111927
- need5(rpc.version === intent.nativeVersion, "RECONCILE_NATIVE_VERSION_CHANGED");
112225
+ need6(rpc.version === intent.nativeVersion, "RECONCILE_NATIVE_VERSION_CHANGED");
111928
112226
  const discovered = await rpc.request("hooks/list", { cwds: [home] });
111929
- need5(Array.isArray(discovered?.data) && discovered.data.length === 1 && discovered.data[0].cwd === home && !discovered.data[0].errors?.length && !discovered.data[0].warnings?.length, "RECONCILE_NATIVE_DISCOVERY_REFUSED");
112227
+ need6(Array.isArray(discovered?.data) && discovered.data.length === 1 && discovered.data[0].cwd === home && !discovered.data[0].errors?.length && !discovered.data[0].warnings?.length, "RECONCILE_NATIVE_DISCOVERY_REFUSED");
111930
112228
  const nativeHooks = discovered.data[0].hooks;
111931
112229
  const recordedNativeHooks = intent.nativeHooks;
111932
112230
  if (recordedNativeHooks)
111933
- need5(nativeHooks.length === recordedNativeHooks.length + (additions?.hooks.length ?? 0), "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
112231
+ need6(nativeHooks.length === recordedNativeHooks.length + (additions?.hooks.length ?? 0), "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
111934
112232
  const plannedKeys = new Set(intent.hooks.map((hook) => hook.key));
111935
112233
  let nativeTrustPending = false;
111936
112234
  for (const expected of [...recordedNativeHooks ?? [], ...additions?.hooks ?? []]) {
111937
112235
  const matches2 = nativeHooks.filter((hook) => hook.key === expected.key);
111938
- need5(matches2.length === 1, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
112236
+ need6(matches2.length === 1, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
111939
112237
  const actual = safeNativeHook(matches2[0]);
111940
112238
  const stable = (hook) => {
111941
112239
  const { enabled, trustStatus, ...identity5 } = hook;
@@ -111943,35 +112241,35 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111943
112241
  delete identity5.command;
111944
112242
  return identity5;
111945
112243
  };
111946
- need5(isDeepStrictEqual13(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
112244
+ need6(isDeepStrictEqual14(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
111947
112245
  if (!plannedKeys.has(expected.key))
111948
- need5(isDeepStrictEqual13(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
112246
+ need6(isDeepStrictEqual14(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
111949
112247
  }
111950
112248
  for (const wanted of intent.hooks) {
111951
112249
  const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join60(home, ".codex/hooks.json"), hooksPath));
111952
- need5(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
112250
+ need6(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
111953
112251
  const h = matches2[0];
111954
112252
  const trusted = h.trustStatus === "trusted";
111955
- need5(h.enabled === true && (trusted || supersededBinding && h.trustStatus === "modified") && (h.currentHash === wanted.currentHash || supersededBinding && /^sha256:[a-f0-9]{64}$/.test(h.currentHash)), "RECONCILE_NATIVE_STATE_INCOMPLETE");
112253
+ need6(h.enabled === true && (trusted || supersededBinding && h.trustStatus === "modified") && (h.currentHash === wanted.currentHash || supersededBinding && /^sha256:[a-f0-9]{64}$/.test(h.currentHash)), "RECONCILE_NATIVE_STATE_INCOMPLETE");
111956
112254
  if (!trusted)
111957
112255
  nativeTrustPending = true;
111958
112256
  if (supersededBinding) {
111959
112257
  const nativeToCliEvent = { userPromptSubmit: "UserPromptSubmit", sessionStart: "SessionStart", subagentStart: "SubagentStart" };
111960
- need5(h.command === renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, nativeToCliEvent[wanted.event] ?? ""), "RECONCILE_BINDING_HOOK_CHANGED");
112258
+ need6(h.command === renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, nativeToCliEvent[wanted.event] ?? ""), "RECONCILE_BINDING_HOOK_CHANGED");
111961
112259
  }
111962
112260
  }
111963
112261
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
111964
112262
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
111965
- need5(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
112263
+ need6(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
111966
112264
  const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
111967
- need5(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual13(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
112265
+ need6(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual14(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
111968
112266
  const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
111969
112267
  const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
111970
- need5(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
112268
+ need6(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
111971
112269
  if (recovery) {
111972
112270
  for (const response of [config2, finalConfig]) {
111973
112271
  const layerIndex = response.layers.findIndex((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
111974
- need5(response.config && response.config.features?.hooks !== false && response.layers.slice(0, layerIndex).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "RECONCILE_NATIVE_CONFIG_OVERRIDDEN");
112272
+ need6(response.config && response.config.features?.hooks !== false && response.layers.slice(0, layerIndex).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "RECONCILE_NATIVE_CONFIG_OVERRIDDEN");
111975
112273
  }
111976
112274
  recoveryCli.recheck();
111977
112275
  verifyReleaseArtifact(options.releaseProof, recoveryCli);
@@ -111992,7 +112290,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111992
112290
  const recoveryPlan = recovery ? { version: 1, kind: additions ? claudeRecovery ? "claude-discovery-and-native-hook-additions" : "native-hook-additions" : "claude-discovery-only", journal, journalIntentSha256: intentFile.sha256, stoppedSha256: stoppedFile.sha256, originalPlanDigest: intent.planDigest, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, configBeforeSha256: configBefore.sha256, configCurrentSha256: currentConfig.sha256, ...configDiscoveryRecovery ? { configDiscoveryRecovery } : {}, ...additions ? { nativeHookAdditions: additions.receipt } : {}, hooksSha256: hooksCurrent.sha256, nativeConfigPath, nativeVersion: rpc.version, nativeInventorySha256: makePlanDigest(nativeHooks.map(safeNativeHook)), recordedNativeInventorySha256: makePlanDigest(recordedNativeHooks), boundSkillsCli: skillsCli.receipt, recoveryCli: recoveryCli.receipt, releaseProof: options.releaseProof, ...policyChange } : undefined;
111993
112291
  const recoveryPlanDigest = recoveryPlan ? makePlanDigest(recoveryPlan) : undefined;
111994
112292
  if (recovery?.reviewedPlanDigest !== undefined)
111995
- need5(recovery.reviewedPlanDigest === recoveryPlanDigest, "RECONCILE_RECOVERY_PLAN_CHANGED");
112293
+ need6(recovery.reviewedPlanDigest === recoveryPlanDigest, "RECONCILE_RECOVERY_PLAN_CHANGED");
111996
112294
  const preview2 = !!recovery && recovery.reviewedPlanDigest === undefined;
111997
112295
  const receipt = { version: 1, status: preview2 ? "recovery-review-required" : supersededBinding ? "superseded" : "reconciled", reconciled: !preview2, supersededBinding, automaticRollback: false, journal, planDigest: intent.planDigest, nativeVersion: rpc.version, nativeStateVerified: !nativeTrustPending, nativeTrustPending, bindingRefreshRequired: !!configDiscoveryRecovery, nativeExecutionVerified: false, configSha256: currentConfig.sha256, hooksSha256: hooksCurrent.sha256, policySha256: policyBefore.sha256, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, previousSkillsCli: intent.skillsCli, skillsCli: skillsCli.receipt, releaseProof: options.releaseProof, nativeInventoryScope: recordedNativeHooks ? "complete" : "declared-managed-hooks-only", unrelatedNativeHooksPreserved: !!recordedNativeHooks, unrelatedSettingsAndCommentsPreserved: true, ...recoveryPlan ? { recoveryPlan, recoveryPlanDigest } : {} };
111998
112296
  if (preview2)
@@ -112015,7 +112313,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112015
112313
  const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
112016
112314
  const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
112017
112315
  const physicalRoot = alias?.target ?? join60(home, ".codex"), hooksPath = join60(physicalRoot, "hooks.json"), configPath = join60(physicalRoot, "config.toml");
112018
- need5(options.codexHome === undefined || isAbsolute28(options.codexHome) && [join60(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
112316
+ need6(options.codexHome === undefined || isAbsolute28(options.codexHome) && [join60(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
112019
112317
  const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
112020
112318
  const nativeConfigPath = join60(codexHome ?? join60(home, ".codex"), "config.toml");
112021
112319
  const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
@@ -112023,38 +112321,38 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112023
112321
  for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
112024
112322
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
112025
112323
  const groups = declarations[event];
112026
- need5(Array.isArray(groups), "DECLARATION_CHANGED");
112324
+ need6(Array.isArray(groups), "DECLARATION_CHANGED");
112027
112325
  const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
112028
- need5(matches2.length === 1 && isDeepStrictEqual13(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
112326
+ need6(matches2.length === 1 && isDeepStrictEqual14(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
112029
112327
  expected.push({ event: nativeEvent, key: `${join60(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
112030
112328
  }
112031
112329
  codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
112032
112330
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
112033
- need5(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
112331
+ need6(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
112034
112332
  const list2 = async () => {
112035
112333
  const response = await rpc.request("hooks/list", { cwds: [home] });
112036
112334
  const nativeRoots = [...new Set([physicalRoot, join60(home, ".codex")])];
112037
112335
  const coexistenceWarnings = nativeRoots.flatMap((hooksRoot) => nativeRoots.map((configRoot) => `loading hooks from both ${join60(hooksRoot, "hooks.json")} and ${join60(configRoot, "config.toml")}; prefer a single representation for this layer`));
112038
112336
  const entry = response?.data?.[0];
112039
- need5(Array.isArray(response?.data) && response.data.length === 1 && entry.cwd === home && Array.isArray(entry.hooks) && entry.hooks.length <= 1e4 && Array.isArray(entry.errors) && entry.errors.length === 0 && Array.isArray(entry.warnings) && entry.warnings.length <= 1 && entry.warnings.every((warning) => typeof warning === "string" && coexistenceWarnings.includes(warning)), "NATIVE_DISCOVERY_REFUSED");
112337
+ need6(Array.isArray(response?.data) && response.data.length === 1 && entry.cwd === home && Array.isArray(entry.hooks) && entry.hooks.length <= 1e4 && Array.isArray(entry.errors) && entry.errors.length === 0 && Array.isArray(entry.warnings) && entry.warnings.length <= 1 && entry.warnings.every((warning) => typeof warning === "string" && coexistenceWarnings.includes(warning)), "NATIVE_DISCOVERY_REFUSED");
112040
112338
  return response.data[0].hooks;
112041
112339
  };
112042
112340
  const admit = (hooks) => expected.map((wanted) => {
112043
112341
  const canonicalKey = wanted.key.replace(join60(home, ".codex/hooks.json"), hooksPath);
112044
112342
  const matches2 = hooks.filter((h2) => h2.key === wanted.key || h2.key === canonicalKey);
112045
- need5(matches2.length === 1, "AMBIGUOUS_IDENTITY");
112343
+ need6(matches2.length === 1, "AMBIGUOUS_IDENTITY");
112046
112344
  const h = matches2[0];
112047
- need5(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join60(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
112048
- need5(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
112049
- need5(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
112345
+ need6(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join60(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
112346
+ need6(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
112347
+ need6(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
112050
112348
  return { key: h.key, event: wanted.event, command: wanted.command, handlerType: h.handlerType, timeoutSec: h.timeoutSec, sourcePath: h.sourcePath, currentHash: h.currentHash, enabled: h.enabled, trustStatus: h.trustStatus };
112051
112349
  });
112052
112350
  const discovered = await list2(), admitted = admit(discovered);
112053
112351
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
112054
112352
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
112055
- need5(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
112056
- need5(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
112057
- need5(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
112353
+ need6(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
112354
+ need6(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
112355
+ need6(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
112058
112356
  const keys3 = admitted.map((h) => h.key), planned = admitted.filter((h) => !h.enabled || h.trustStatus !== "trusted");
112059
112357
  const preservationText = codexTrustTextWitness(configFile.text, keys3);
112060
112358
  const checkInputs = () => {
@@ -112069,16 +112367,16 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112069
112367
  const planDigest = makePlanDigest(digestInput);
112070
112368
  const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, nativeConfigPath, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, bindingRefreshRequired: false, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
112071
112369
  if (options.apply)
112072
- need5(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
112370
+ need6(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
112073
112371
  const parent = join60(dataDir3, "native-hook-trust");
112074
112372
  const st = lstatSync31(parent, { throwIfNoEntry: false });
112075
112373
  if (st) {
112076
- need5(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
112374
+ need6(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
112077
112375
  const priorJournals = readdirSync23(parent);
112078
- need5(priorJournals.length < 1000, "JOURNAL_BOUND");
112376
+ need6(priorJournals.length < 1000, "JOURNAL_BOUND");
112079
112377
  for (const name of priorJournals) {
112080
- need5(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
112081
- need5(lstatSync31(join60(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
112378
+ need6(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
112379
+ need6(lstatSync31(join60(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
112082
112380
  }
112083
112381
  }
112084
112382
  if (!options.apply || !planned.length)
@@ -112091,7 +112389,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112091
112389
  save(join60(journal, "hooks.before.json"), hooksFile.bytes);
112092
112390
  save(join60(journal, "policy.before.json"), policyFile.bytes);
112093
112391
  save(join60(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
112094
- need5(isDeepStrictEqual13(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
112392
+ need6(isDeepStrictEqual14(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
112095
112393
  checkInputs();
112096
112394
  let result2;
112097
112395
  try {
@@ -112099,22 +112397,22 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112099
112397
  } catch {
112100
112398
  throw new Error("CODEX_HOOK_TRUST_NATIVE_WRITE_FAILED: reconcile the private journal before retrying");
112101
112399
  }
112102
- need5(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
112400
+ need6(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
112103
112401
  const after2 = snapshot(configPath, true), expectedConfig = structuredClone(original);
112104
112402
  expectedConfig.hooks ??= {};
112105
112403
  expectedConfig.hooks.state ??= {};
112106
112404
  for (const h of planned)
112107
112405
  expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
112108
- need5(isDeepStrictEqual13(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
112406
+ need6(isDeepStrictEqual14(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
112109
112407
  const savedConfig = snapshot(join60(journal, "config.before.toml"), true);
112110
- need5(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
112408
+ need6(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
112111
112409
  const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
112112
112410
  unchanged2(policyFile);
112113
112411
  unchanged2(hooksFile);
112114
112412
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
112115
112413
  const current = await list2(), confirmed = admit(current);
112116
- need5(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual13(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
112117
- need5(isDeepStrictEqual13(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
112414
+ need6(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual14(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
112415
+ need6(isDeepStrictEqual14(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
112118
112416
  unchanged2(after2);
112119
112417
  unchanged2(savedConfig);
112120
112418
  unchanged2(hooksFile);
@@ -112137,7 +112435,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112137
112435
  }
112138
112436
  }
112139
112437
  var json2 = (value) => JSON.stringify(value, null, 2) + `
112140
- `, structure3 = (text4) => JSON.parse(JSON.stringify(Bun.TOML.parse(text4))), eventNames, makePlanDigest = (value) => createHash30("sha256").update(json2(value)).digest("hex"), safeNativeHook = (hook) => ({ key: hook.key, eventName: hook.eventName, handlerType: hook.handlerType, command: hook.command, matcher: hook.matcher, timeoutSec: hook.timeoutSec, async: hook.async, statusMessage: hook.statusMessage, additionalContextLimit: hook.additionalContextLimit, sourcePath: hook.sourcePath, source: hook.source, pluginId: hook.pluginId, isManaged: hook.isManaged, currentHash: hook.currentHash, enabled: hook.enabled, trustStatus: hook.trustStatus }), withoutCodexCommand = (value) => {
112438
+ `, structure3 = (text4) => JSON.parse(JSON.stringify(Bun.TOML.parse(text4))), eventNames, makePlanDigest = (value) => createHash31("sha256").update(json2(value)).digest("hex"), safeNativeHook = (hook) => ({ key: hook.key, eventName: hook.eventName, handlerType: hook.handlerType, command: hook.command, matcher: hook.matcher, timeoutSec: hook.timeoutSec, async: hook.async, statusMessage: hook.statusMessage, additionalContextLimit: hook.additionalContextLimit, sourcePath: hook.sourcePath, source: hook.source, pluginId: hook.pluginId, isManaged: hook.isManaged, currentHash: hook.currentHash, enabled: hook.enabled, trustStatus: hook.trustStatus }), withoutCodexCommand = (value) => {
112141
112439
  const copy = structuredClone(value);
112142
112440
  if (copy?.bridge?.commands && Object.hasOwn(copy.bridge.commands, "codex"))
112143
112441
  copy.bridge.commands.codex = "<reviewed-codex-binding>";
@@ -112277,7 +112575,7 @@ __export(exports_agent_integration, {
112277
112575
  registerAgentIntegration: () => registerAgentIntegration
112278
112576
  });
112279
112577
  import { existsSync as existsSync35, lstatSync as lstatSync32, readFileSync as readFileSync41, writeFileSync as writeFileSync26 } from "fs";
112280
- import { createHash as createHash31 } from "crypto";
112578
+ import { createHash as createHash32 } from "crypto";
112281
112579
  import { homedir as homedir13 } from "os";
112282
112580
  import { isAbsolute as isAbsolute29 } from "path";
112283
112581
  function pinnedHookProfile(input3, configuredProfile) {
@@ -112375,7 +112673,7 @@ function registerAgentIntegration(parent) {
112375
112673
  skillCount: catalog.skills.length,
112376
112674
  output: options.output,
112377
112675
  bytes: Buffer.byteLength(bytes),
112378
- sha256: createHash31("sha256").update(bytes).digest("hex")
112676
+ sha256: createHash32("sha256").update(bytes).digest("hex")
112379
112677
  };
112380
112678
  await writeCliOutput(options.json ? JSON.stringify(receipt) : `Captured ${receipt.skillCount} native Codex skill(s) in ${receipt.output}.`);
112381
112679
  } catch (error61) {
@@ -112384,10 +112682,10 @@ function registerAgentIntegration(parent) {
112384
112682
  process.exitCode = 1;
112385
112683
  }
112386
112684
  });
112387
- hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
112388
- const capture2 = options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
112685
+ hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
112686
+ const capture2 = options.kind === "codex-settings-v2" ? captureCodexSettingsV2 : options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
112389
112687
  if (!capture2)
112390
- throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
112688
+ throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
112391
112689
  await writeCliOutput(JSON.stringify(capture2(options.path), null, 2));
112392
112690
  });
112393
112691
  hook.command("rebind-settings").requiredOption("--agent <agent>", "claude or codex").requiredOption("--reviewed-preimage <path>", "Exact preserved legacy settings.json or config.toml").requiredOption("--expected-policy-sha256 <sha256>", "Exact current managed policy bytes").requiredOption("--expected-settings-sha256 <sha256>", "Exact current native settings bytes").option("--apply", "Apply the explicit semantic witness upgrade with preservation and readback", false).option("--json", "Return the metadata-only plan or receipt", false).description("Explicitly migrate a legacy native settings witness after proving only known preferences changed").action(async (options) => {
@@ -112406,7 +112704,7 @@ function registerAgentIntegration(parent) {
112406
112704
  hook.command("agents").option("--json", "Output the adapter capability inventory", false).description("Show maintained native adapters and explicit coverage limits").action(async () => {
112407
112705
  await writeCliOutput(JSON.stringify({ agents: INTEGRATION_AGENTS.map((agent) => ({ agent, bridge: true, ...AGENT_ADAPTERS[agent] })), inventoryOnly: ["codewith", "windsurf", "pi", "amp", "cline", "roo", "copilot"], limitations: ["Cursor prompt hooks gate submission; selected context is injected at session start only.", "Native discovery checks cover known home roots and current project ancestors. External plugin hook injection and arbitrary added directories require separate review.", "Hermes injects selected prompt context, but native pre_llm_call fails open. Exact native hook trust, bundled reseeding opt-out, native payload retirement and a supervised pre-tool guard are required. Child failures block explicitly; native host/supervisor death is not a universal fail-closed guarantee.", "Restart agents and use their normal hook trust controls after installation."] }, null, 2));
112408
112706
  });
112409
- hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--codex-native-catalog <file>", "Reviewed Codex 0.159.2 skill and installed-plugin receipt for exact qualified-name disables").option("--reviewed-cache-alias <path>", "Exact skill-containing vendor cache alias reviewed for this hook plan").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
112707
+ hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--codex-native-catalog <file>", "Reviewed supported Codex skill and installed-plugin receipt for exact qualified-name disables").option("--reviewed-cache-alias <path>", "Exact skill-containing vendor cache alias reviewed for this hook plan").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
112410
112708
  try {
112411
112709
  const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync41(options.discoveryInputs, "utf8")) : undefined;
112412
112710
  const plan = planAgentIntegration({ projectDir: process.cwd(), agents: agents(options.agent), command: options.command, profileId: options.selectionProfile, includeVendor: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, codexNativeCatalog: options.codexNativeCatalog ? JSON.parse(readFileSync41(options.codexNativeCatalog, "utf8")) : undefined });
@@ -112889,7 +113187,7 @@ var init_grants = __esm(() => {
112889
113187
  });
112890
113188
 
112891
113189
  // src/lib/station-hydrate.ts
112892
- import { createHash as createHash32 } from "crypto";
113190
+ import { createHash as createHash33 } from "crypto";
112893
113191
  import {
112894
113192
  copyFileSync as copyFileSync3,
112895
113193
  mkdirSync as mkdirSync28,
@@ -113092,7 +113390,7 @@ function skillSha256(skill) {
113092
113390
  return sha256File(skill.files[0].winner.fullPath);
113093
113391
  }
113094
113392
  const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
113095
- return createHash32("sha256").update(joined.sort().join(`
113393
+ return createHash33("sha256").update(joined.sort().join(`
113096
113394
  `)).digest("hex");
113097
113395
  }
113098
113396
  function writeStationHydration(options) {
@@ -113249,7 +113547,7 @@ var init_hydrate = __esm(() => {
113249
113547
  });
113250
113548
 
113251
113549
  // src/lib/prepare-skill.ts
113252
- import { createHash as createHash33, randomUUID as randomUUID12 } from "crypto";
113550
+ import { createHash as createHash34, randomUUID as randomUUID12 } from "crypto";
113253
113551
  import { chmodSync as chmodSync5, existsSync as existsSync36, lstatSync as lstatSync33, mkdirSync as mkdirSync29, mkdtempSync as mkdtempSync6, readFileSync as readFileSync43, readdirSync as readdirSync25, renameSync as renameSync14, rmSync as rmSync9, writeFileSync as writeFileSync30 } from "fs";
113254
113552
  import { tmpdir as tmpdir2 } from "os";
113255
113553
  import { dirname as dirname36, isAbsolute as isAbsolute30, join as join62, relative as relative11, resolve as resolve27, sep as sep14 } from "path";
@@ -113266,7 +113564,7 @@ function prepareSkill(name, options) {
113266
113564
  let manifest;
113267
113565
  try {
113268
113566
  const parsed = JSON.parse(manifestFile.bytes.toString("utf8"));
113269
- if (!isRecord8(parsed))
113567
+ if (!isRecord9(parsed))
113270
113568
  throw new Error("not an object");
113271
113569
  manifest = parsed;
113272
113570
  } catch {
@@ -113288,7 +113586,7 @@ function prepareSkill(name, options) {
113288
113586
  if (documentKind !== undefined && documentKind !== kind) {
113289
113587
  throw new Error("SKILL.md kind conflicts with the candidate skill.json kind. Review and align both declarations (or remove the optional frontmatter kind), then prepare again; no files were changed.");
113290
113588
  }
113291
- if (manifest.provenance !== undefined && !isRecord8(manifest.provenance))
113589
+ if (manifest.provenance !== undefined && !isRecord9(manifest.provenance))
113292
113590
  throw new Error("skill.json provenance must be an object.");
113293
113591
  const provenance = manifest.provenance;
113294
113592
  const candidate2 = { ...manifest, version: options.version, kind, provenance: { ...provenance } };
@@ -113353,7 +113651,7 @@ function escapedRelativePath(path) {
113353
113651
  return JSON.stringify(bounded);
113354
113652
  }
113355
113653
  function validateRuntimeEntrypoint(candidate2, root2) {
113356
- if (candidate2.kind !== "executable" || !isRecord8(candidate2.runtime))
113654
+ if (candidate2.kind !== "executable" || !isRecord9(candidate2.runtime))
113357
113655
  return;
113358
113656
  const entry = candidate2.runtime.entrypoint;
113359
113657
  if (typeof entry !== "string")
@@ -113363,7 +113661,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
113363
113661
  throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
113364
113662
  }
113365
113663
  }
113366
- function isRecord8(value) {
113664
+ function isRecord9(value) {
113367
113665
  return typeof value === "object" && value !== null && !Array.isArray(value);
113368
113666
  }
113369
113667
  function validateRawCandidate(candidate2) {
@@ -113388,7 +113686,7 @@ function validateRawCandidate(candidate2) {
113388
113686
  if (!Array.isArray(items))
113389
113687
  throw new Error(`skill.json ${field2} must be an array.`);
113390
113688
  for (const item of items) {
113391
- if (!isRecord8(item) || typeof item.name !== "string" || !item.name.trim())
113689
+ if (!isRecord9(item) || typeof item.name !== "string" || !item.name.trim())
113392
113690
  throw new Error(`Invalid skill.json ${field2} name.`);
113393
113691
  if (field2 === "inputs" && (typeof item.type !== "string" || !item.type.trim() || item.required !== undefined && typeof item.required !== "boolean"))
113394
113692
  throw new Error("Invalid skill.json input type or required flag.");
@@ -113407,7 +113705,7 @@ function validateRawCandidate(candidate2) {
113407
113705
  }
113408
113706
  }
113409
113707
  function validateRuntimeEntrypointCompatibility(candidate2) {
113410
- if (candidate2.kind !== "executable" || !isRecord8(candidate2.runtime))
113708
+ if (candidate2.kind !== "executable" || !isRecord9(candidate2.runtime))
113411
113709
  return;
113412
113710
  const runtime = candidate2.runtime.runtime;
113413
113711
  const entrypoint = candidate2.runtime.entrypoint;
@@ -113448,7 +113746,7 @@ function snapshot2(root2) {
113448
113746
  if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
113449
113747
  throw new Error("Skill root must be a real directory, not a symlink.");
113450
113748
  const files = [], directories = [];
113451
- const hash6 = createHash33("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
113749
+ const hash6 = createHash34("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
113452
113750
  let count = 0, bytes = 0;
113453
113751
  const walk2 = (relative12) => {
113454
113752
  for (const name of readdirSync25(join62(root2, relative12)).sort()) {
@@ -114734,7 +115032,7 @@ async function apiRequest(path, options, instance) {
114734
115032
  const origin = instance ?? getApiUrl(`${(options?.method || "GET").toUpperCase()} ${path}`);
114735
115033
  return new RemoteSkillsAuthClient(origin).request(path, options);
114736
115034
  }
114737
- function isRecord9(value) {
115035
+ function isRecord10(value) {
114738
115036
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
114739
115037
  }
114740
115038
  function commandErrorPayload(err, fallback) {
@@ -114748,11 +115046,11 @@ function commandErrorPayload(err, fallback) {
114748
115046
  ...err.apiUrl ? { apiUrl: err.apiUrl } : {}
114749
115047
  };
114750
115048
  }
114751
- const code2 = isRecord9(err) && typeof err.code === "string" ? err.code : undefined;
115049
+ const code2 = isRecord10(err) && typeof err.code === "string" ? err.code : undefined;
114752
115050
  return {
114753
115051
  error: err?.message || fallback,
114754
115052
  ...code2 ? { code: code2 } : {},
114755
- ...isRecord9(err) && Array.isArray(err.next) ? { next: err.next } : {}
115053
+ ...isRecord10(err) && Array.isArray(err.next) ? { next: err.next } : {}
114756
115054
  };
114757
115055
  }
114758
115056
  function writeCommandError(err, fallback, json3) {
@@ -114777,7 +115075,7 @@ function stringField2(value) {
114777
115075
  return typeof value === "string" && value.length > 0 ? value : undefined;
114778
115076
  }
114779
115077
  function recordField(value) {
114780
- return isRecord9(value) ? value : undefined;
115078
+ return isRecord10(value) ? value : undefined;
114781
115079
  }
114782
115080
  function identityApiKey(live) {
114783
115081
  const root2 = recordField(live);
@@ -115250,7 +115548,7 @@ async function runWhoami(options) {
115250
115548
  } catch {}
115251
115549
  payload.permissions = { publish: access?.permissions?.publish ?? null, profilesWrite: access?.permissions?.profilesWrite ?? null };
115252
115550
  const apiKey = identityApiKey(res);
115253
- if (access?.scopes && (apiKey === undefined || isRecord9(apiKey) && !Object.hasOwn(apiKey, "scopes"))) {
115551
+ if (access?.scopes && (apiKey === undefined || isRecord10(apiKey) && !Object.hasOwn(apiKey, "scopes"))) {
115254
115552
  payload.scopes = access.scopes;
115255
115553
  }
115256
115554
  if (options.json) {