@hasna/skills 0.10.20 → 0.10.22

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.22",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -39931,12 +39931,14 @@ 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", "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));
39940
39942
  if (control.appSha256 !== undefined)
39941
39943
  requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
39942
39944
  }
@@ -39959,8 +39961,8 @@ function assertAgentPolicyCollections(policy) {
39959
39961
  text(source.path);
39960
39962
  requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
39961
39963
  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")
39964
+ 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));
39965
+ if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2")
39964
39966
  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
39967
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
39966
39968
  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 +50886,28 @@ var init_claude_settings_witness = __esm(() => {
50884
50886
  PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
50885
50887
  });
50886
50888
 
50889
+ // src/lib/codex-native-compatibility.ts
50890
+ function supportsCodexNativeCapability(version, capability) {
50891
+ return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
50892
+ }
50893
+ var MEASURED_CODEX_CAPABILITIES, SUPPORTED_CODEX_HOOK_VERSIONS;
50894
+ var init_codex_native_compatibility = __esm(() => {
50895
+ MEASURED_CODEX_CAPABILITIES = {
50896
+ "codex-cli 0.153.0": ["hooks"],
50897
+ "codex-cli 0.154.0": ["hooks"],
50898
+ "codex-cli 0.155.0": ["hooks"],
50899
+ "codex-cli 0.155.1": ["hooks"],
50900
+ "codex-cli 0.156.1": ["hooks"],
50901
+ "codex-cli 0.157.0": ["hooks"],
50902
+ "codex-cli 0.157.1": ["hooks"],
50903
+ "codex-cli 0.158.0": ["hooks"],
50904
+ "codex-cli 0.159.0": ["hooks"],
50905
+ "codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
50906
+ "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
50907
+ };
50908
+ SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
50909
+ });
50910
+
50887
50911
  // src/lib/codex-hook-rpc.ts
50888
50912
  import { execFile, spawn as spawn2 } from "child_process";
50889
50913
  import { realpathSync as realpathSync3, statSync as statSync7 } from "fs";
@@ -50906,7 +50930,7 @@ async function connectCodexHookRpc(options) {
50906
50930
  } catch {
50907
50931
  throw new Error("CODEX_HOOK_TRUST_NATIVE_UNAVAILABLE");
50908
50932
  }
50909
- if (!SUPPORTED_CODEX_HOOK_VERSIONS.includes(version))
50933
+ if (!supportsCodexNativeCapability(version, "hooks"))
50910
50934
  throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED_VERSION");
50911
50935
  const current = statSync7(binary);
50912
50936
  if (realpathSync3(found) !== binary || ["dev", "ino", "size", "mtimeMs", "ctimeMs"].some((k) => stat[k] !== current[k]))
@@ -51025,9 +51049,9 @@ async function connectCodexHookRpc(options) {
51025
51049
  throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED: native hooks/list and versioned config writes are required");
51026
51050
  }
51027
51051
  }
51028
- var SUPPORTED_CODEX_HOOK_VERSIONS;
51029
51052
  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"];
51053
+ init_codex_native_compatibility();
51054
+ init_codex_native_compatibility();
51031
51055
  });
51032
51056
 
51033
51057
  // src/lib/codex-native-skill-catalog.ts
@@ -51062,7 +51086,11 @@ function projectCodexInstalledPlugins(response) {
51062
51086
  for (const value of marketplace.plugins) {
51063
51087
  if (!object4(value) || !scalar(value.id, MAX_PLUGIN_ID_BYTES) || !scalar(value.name, MAX_NAME_BYTES) || value.id !== `${value.name}@${marketplace.name}`)
51064
51088
  refuse();
51065
- plugins.push({ ...value, marketplace: marketplace.name });
51089
+ plugins.push({
51090
+ ...value,
51091
+ marketplace: marketplace.name,
51092
+ sourceType: object4(value.source) && value.source.type === "remote" ? "remote" : undefined
51093
+ });
51066
51094
  }
51067
51095
  }
51068
51096
  return projectCodexInstalledPluginEntries(plugins);
@@ -51072,13 +51100,21 @@ function projectCodexInstalledPluginEntries(value) {
51072
51100
  refuse();
51073
51101
  const ids = new Set;
51074
51102
  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))
51103
+ 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
51104
  refuse();
51077
51105
  const at2 = item.id.lastIndexOf("@");
51078
51106
  if (at2 < 1 || item.id.slice(0, at2) !== item.name || at2 === item.id.length - 1 || ids.has(item.id))
51079
51107
  refuse();
51080
51108
  ids.add(item.id);
51081
- return { id: item.id, name: item.name, installed: item.installed, enabled: item.enabled, localVersion: item.localVersion ?? null };
51109
+ return {
51110
+ id: item.id,
51111
+ name: item.name,
51112
+ installed: item.installed,
51113
+ enabled: item.enabled,
51114
+ localVersion: item.localVersion ?? null,
51115
+ ...item.sourceType === "remote" ? { sourceType: "remote" } : {},
51116
+ ...item.remotePluginId == null ? {} : { remotePluginId: item.remotePluginId }
51117
+ };
51082
51118
  });
51083
51119
  }
51084
51120
  async function captureCodexNativeSkillCatalog(options, connect = connectCodexHookRpc) {
@@ -51091,7 +51127,7 @@ async function captureCodexNativeSkillCatalog(options, connect = connectCodexHoo
51091
51127
  ...options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }
51092
51128
  });
51093
51129
  try {
51094
- if (!SUPPORTED_NAME_CONTROL_VERSIONS.has(rpc.version))
51130
+ if (!supportsCodexNativeCapability(rpc.version, "qualified-skill-catalog"))
51095
51131
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_UNSUPPORTED_VERSION");
51096
51132
  const response = await rpc.request("skills/list", { cwds: [options.cwd], forceReload: true });
51097
51133
  const installed = await rpc.request("plugin/installed", { cwds: [options.cwd] });
@@ -51142,10 +51178,10 @@ function isCodexNativeSkillDisabled(skill, rules) {
51142
51178
  }
51143
51179
  return disabled;
51144
51180
  }
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);
51181
+ 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
51182
  var init_codex_native_skill_catalog = __esm(() => {
51147
51183
  init_codex_hook_rpc();
51148
- SUPPORTED_NAME_CONTROL_VERSIONS = new Set(["codex-cli 0.159.2"]);
51184
+ init_codex_native_compatibility();
51149
51185
  });
51150
51186
 
51151
51187
  // src/lib/codex-plugin-skill-controls.ts
@@ -51154,6 +51190,21 @@ import { lstatSync as lstatSync12, readdirSync as readdirSync6, readlinkSync as
51154
51190
  function refuse2() {
51155
51191
  throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
51156
51192
  }
51193
+ function remoteInstallationMatches(parent, remotePluginId, read2) {
51194
+ try {
51195
+ if (!remotePluginIdentifier(remotePluginId) || !lstatSync12(parent).isDirectory() || realpathSync5(parent) !== parent)
51196
+ return false;
51197
+ const path = join18(parent, ".codex-remote-plugin-install.json"), stat = lstatSync12(path, { throwIfNoEntry: false });
51198
+ if (!stat?.isFile() || stat.isSymbolicLink() || stat.size > 16384)
51199
+ return false;
51200
+ const text2 = read2(path);
51201
+ hashNativeJsonControls(text2);
51202
+ const value = JSON.parse(text2);
51203
+ return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 2 && value.schema_version === 1 && value.remote_plugin_id === remotePluginId);
51204
+ } catch {
51205
+ return false;
51206
+ }
51207
+ }
51157
51208
  function appControls(path, read2) {
51158
51209
  const text2 = read2(path);
51159
51210
  let value, sha2562;
@@ -51243,6 +51294,10 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
51243
51294
  for (const parent of new Set(controls.map((control) => control.pluginParent))) {
51244
51295
  if (!parent.startsWith(cache3 + sep4) || !lstatSync12(parent, { throwIfNoEntry: false })?.isDirectory())
51245
51296
  return false;
51297
+ for (const control of controls.filter((control2) => control2.pluginParent === parent)) {
51298
+ if (control.remotePluginId !== undefined && !remoteInstallationMatches(parent, control.remotePluginId, read2))
51299
+ return false;
51300
+ }
51246
51301
  const names = readdirSync6(parent);
51247
51302
  entries += names.length;
51248
51303
  if (entries > 4096)
@@ -51269,7 +51324,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
51269
51324
  }
51270
51325
  }
51271
51326
  function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2, rules) {
51272
- if (catalog?.version !== "codex-cli 0.159.2" || catalog.cwd !== cwd2)
51327
+ if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd2)
51273
51328
  refuse2();
51274
51329
  const skills = projectCodexNativeSkillCatalog({ data: [{ cwd: cwd2, errors: [], skills: catalog.skills }] }, cwd2);
51275
51330
  const allowed = new Set(documents), result2 = [];
@@ -51296,20 +51351,28 @@ function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2,
51296
51351
  const listed = skills.filter((skill) => skill.path === document3);
51297
51352
  if (listed.length > 1)
51298
51353
  refuse2();
51354
+ let remotePluginId;
51299
51355
  if (listed.length === 1) {
51300
51356
  if (listed[0].name !== parsed.name || listed[0].pluginId !== expectedPluginId)
51301
51357
  refuse2();
51302
51358
  } 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)
51359
+ const installed = installedPlugins.filter((plugin2) => plugin2.id === expectedPluginId && plugin2.name === pluginName);
51360
+ if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled)
51305
51361
  refuse2();
51306
- if (installed[0].localVersion !== basename5(dirname10(dirname10(dirname10(document3)))))
51307
- continue;
51362
+ const plugin = installed[0];
51363
+ if (plugin.localVersion !== null) {
51364
+ if (plugin.localVersion !== basename5(dirname10(dirname10(dirname10(document3)))))
51365
+ continue;
51366
+ } else {
51367
+ if (plugin.sourceType !== "remote" || !plugin.remotePluginId || !remoteInstallationMatches(parsed.pluginParent, plugin.remotePluginId, read2) || !lstatSync12(document3).isFile() || realpathSync5(document3) !== document3)
51368
+ refuse2();
51369
+ remotePluginId = plugin.remotePluginId;
51370
+ }
51308
51371
  const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document3 && rule?.enabled === false);
51309
51372
  if (!exactPathDeny || !isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: expectedPluginId, enabled: true }, rules))
51310
51373
  refuse2();
51311
51374
  }
51312
- result2.push({ ...parsed, pluginId: expectedPluginId });
51375
+ result2.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
51313
51376
  }
51314
51377
  if (!result2.length || new Set(result2.map((item) => item.name)).size !== result2.length)
51315
51378
  refuse2();
@@ -51325,7 +51388,7 @@ function isReviewedCodexPluginSkillDisabled(document3, cache3, controls, rules,
51325
51388
  return false;
51326
51389
  }
51327
51390
  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)
51391
+ if (!reviewed || reviewed.remotePluginId !== undefined && !remoteInstallationMatches(reviewed.pluginParent, reviewed.remotePluginId, read2))
51329
51392
  return false;
51330
51393
  return isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: reviewed.pluginId, enabled: true }, rules);
51331
51394
  }
@@ -51346,10 +51409,11 @@ enabled = false
51346
51409
  var identifier2 = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(v), CODEX_DEFAULT_AGENT_PLUGIN_VERSION = "1.0.0";
51347
51410
  var init_codex_plugin_skill_controls = __esm(() => {
51348
51411
  init_claude_settings_witness();
51412
+ init_codex_native_compatibility();
51349
51413
  init_codex_native_skill_catalog();
51350
51414
  });
51351
51415
 
51352
- // src/lib/codex-settings-witness.ts
51416
+ // src/lib/codex-settings-witness-v1.ts
51353
51417
  import { createHash as createHash9 } from "crypto";
51354
51418
  function need3(value) {
51355
51419
  if (!value)
@@ -51440,21 +51504,173 @@ function captureCodexSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
51440
51504
  const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
51441
51505
  return { path, hashMode: "codex-settings-v1", sha256: hashCodexSettingsReplacement(text2) };
51442
51506
  }
51507
+ var sha = (text2) => createHash9("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
51508
+ var init_codex_settings_witness_v1 = __esm(() => {
51509
+ init_claude_settings_witness();
51510
+ EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
51511
+ VERBOSITY = new Set(["low", "medium", "high"]);
51512
+ });
51513
+
51514
+ // src/lib/codex-settings-witness.ts
51515
+ import { createHash as createHash10 } from "crypto";
51516
+ function need4(value) {
51517
+ if (!value)
51518
+ throw new Error("Invalid Codex settings witness");
51519
+ }
51520
+ function isRecord3(value) {
51521
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
51522
+ }
51523
+ function isDate2(value) {
51524
+ return value instanceof Date;
51525
+ }
51526
+ function numericTokens2(text2) {
51527
+ const result2 = [];
51528
+ for (let at2 = 0;at2 < text2.length; ) {
51529
+ const char = text2[at2];
51530
+ if (char === "#") {
51531
+ while (at2 < text2.length && text2[at2] !== `
51532
+ `)
51533
+ at2++;
51534
+ continue;
51535
+ }
51536
+ if (char === '"' || char === "'") {
51537
+ const quote = char, triple = text2.slice(at2, at2 + 3) === quote.repeat(3);
51538
+ at2 += triple ? 3 : 1;
51539
+ while (at2 < text2.length) {
51540
+ if (quote === '"' && text2[at2] === "\\") {
51541
+ at2 += 2;
51542
+ continue;
51543
+ }
51544
+ if (text2.slice(at2, at2 + (triple ? 3 : 1)) === quote.repeat(triple ? 3 : 1)) {
51545
+ at2 += triple ? 3 : 1;
51546
+ break;
51547
+ }
51548
+ at2++;
51549
+ }
51550
+ continue;
51551
+ }
51552
+ if (/[0-9+-]/.test(char)) {
51553
+ const start = at2;
51554
+ while (at2 < text2.length && !/[\s,\]{}#=]/.test(text2[at2]))
51555
+ at2++;
51556
+ if (at2 > start) {
51557
+ result2.push(text2.slice(start, at2));
51558
+ continue;
51559
+ }
51560
+ }
51561
+ at2++;
51562
+ }
51563
+ return result2.sort();
51564
+ }
51565
+ function canonical4(value, depth = 0, budget = { remaining: 65536 }) {
51566
+ need4(depth <= 32 && --budget.remaining >= 0);
51567
+ if (value === null)
51568
+ return ["null"];
51569
+ if (typeof value === "string")
51570
+ return ["string", value];
51571
+ if (typeof value === "boolean")
51572
+ return ["boolean", value];
51573
+ if (typeof value === "number") {
51574
+ need4(Number.isFinite(value));
51575
+ return ["number", String(value)];
51576
+ }
51577
+ if (isDate2(value)) {
51578
+ need4(Number.isFinite(value.getTime()));
51579
+ return ["date", value.toISOString()];
51580
+ }
51581
+ if (Array.isArray(value))
51582
+ return ["array", value.map((child) => canonical4(child, depth + 1, budget))];
51583
+ need4(isRecord3(value));
51584
+ return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical4(child, depth + 1, budget)])];
51585
+ }
51586
+ function normalize3(config) {
51587
+ if (isRecord3(config.hooks)) {
51588
+ delete config.hooks.state;
51589
+ if (!Object.keys(config.hooks).length)
51590
+ delete config.hooks;
51591
+ }
51592
+ if (isRecord3(config.skills) && Array.isArray(config.skills.config)) {
51593
+ const skills = config.skills;
51594
+ const retained = skills.config.filter((entry) => !disablesOneSkill(entry));
51595
+ if (retained.length !== skills.config.length) {
51596
+ if (retained.length)
51597
+ skills.config = retained;
51598
+ else
51599
+ delete skills.config;
51600
+ }
51601
+ if (!Object.keys(skills).length)
51602
+ delete config.skills;
51603
+ }
51604
+ inference(config);
51605
+ if (isRecord3(config.profiles)) {
51606
+ for (const profile of Object.values(config.profiles))
51607
+ if (isRecord3(profile))
51608
+ inference(profile);
51609
+ }
51610
+ }
51611
+ function disablesOneSkill(entry) {
51612
+ if (!isRecord3(entry) || entry.enabled !== false)
51613
+ return false;
51614
+ const keys2 = Object.keys(entry);
51615
+ if (!keys2.every((key) => key === "path" || key === "name" || key === "enabled"))
51616
+ return false;
51617
+ const selector = ["path", "name"].filter((key) => Object.hasOwn(entry, key));
51618
+ return selector.length === 1 && typeof entry[selector[0]] === "string" && entry[selector[0]].length > 0;
51619
+ }
51620
+ function inference(target) {
51621
+ for (const key of INFERENCE)
51622
+ if (Object.hasOwn(target, key)) {
51623
+ const value = target[key];
51624
+ if (key === "model")
51625
+ need4(typeof value === "string" && MODEL.test(value));
51626
+ else
51627
+ need4(typeof value === "string" && (key === "model_reasoning_effort" ? EFFORT2.has(value) : VERBOSITY2.has(value)));
51628
+ delete target[key];
51629
+ }
51630
+ }
51631
+ function settingsDigest2(text2) {
51632
+ let config;
51633
+ try {
51634
+ config = Bun.TOML.parse(text2);
51635
+ } catch {
51636
+ throw new Error("Invalid Codex settings witness");
51637
+ }
51638
+ need4(isRecord3(config));
51639
+ normalize3(config);
51640
+ return sha2(`hasna.skills.codex-settings.v2\x00${JSON.stringify([canonical4(config), numericTokens2(text2)])}`);
51641
+ }
51642
+ function hashCodexSettingsReplacementV2(text2, budget = { remaining: 256 * 1024 * 1024 }) {
51643
+ need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
51644
+ budget.remaining -= Buffer.byteLength(text2);
51645
+ return settingsDigest2(text2);
51646
+ }
51647
+ function captureCodexSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
51648
+ const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
51649
+ return { path, hashMode: "codex-settings-v2", sha256: settingsDigest2(text2) };
51650
+ }
51651
+ function readCodexSettingsPreimage(path, budget = { remaining: 2 * 1024 * 1024 }) {
51652
+ return readNativeSettingsWitnessFile(path, budget, "config.toml");
51653
+ }
51443
51654
  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));
51655
+ 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
51656
  const budget = { remaining: 2 * 1024 * 1024 };
51446
51657
  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)
51658
+ need4((previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before2) : sha2(before2)) === previous.sha256);
51659
+ const sha2562 = settingsDigest2(current);
51660
+ if (settingsDigest2(before2) !== sha2562)
51450
51661
  throw new Error("Codex non-preference settings changed; explicit discovery review required");
51451
- return { path: previous.path, hashMode: "codex-settings-v1", sha256: sha2562 };
51662
+ return { path: previous.path, hashMode: "codex-settings-v2", sha256: sha2562 };
51452
51663
  }
51453
- var sha = (text2) => createHash9("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
51664
+ var sha2 = (text2) => createHash10("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
51454
51665
  var init_codex_settings_witness = __esm(() => {
51666
+ init_codex_settings_witness_v1();
51667
+ init_codex_settings_witness_v1();
51455
51668
  init_claude_settings_witness();
51456
- EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
51457
- VERBOSITY = new Set(["low", "medium", "high"]);
51669
+ EFFORT2 = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
51670
+ VERBOSITY2 = new Set(["low", "medium", "high"]);
51671
+ MODEL = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
51672
+ CODEX_DISCOVERY_PROJECTION_FIELDS = ["plugins", "marketplaces", "skills"];
51673
+ INFERENCE = ["model", "model_reasoning_effort", "model_verbosity"];
51458
51674
  });
51459
51675
 
51460
51676
  // src/lib/managed-policy.ts
@@ -51543,7 +51759,7 @@ var init_managed_policy = __esm(() => {
51543
51759
  });
51544
51760
 
51545
51761
  // src/lib/agent-bridge.ts
51546
- import { createHash as createHash10 } from "crypto";
51762
+ import { createHash as createHash11 } from "crypto";
51547
51763
  import { lstatSync as lstatSync14, readFileSync as readFileSync12, readdirSync as readdirSync7 } from "fs";
51548
51764
  import { join as join20 } from "path";
51549
51765
  function isOwnedCliBridge(path, expectedPaths) {
@@ -51577,7 +51793,7 @@ Use the Skills CLI as the skill authority for this station.
51577
51793
  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
51794
  `, CLI_BRIDGE_DIGEST, CLI_BRIDGE_FILES;
51579
51795
  var init_agent_bridge = __esm(() => {
51580
- CLI_BRIDGE_DIGEST = createHash10("sha256").update(markdown).digest("hex");
51796
+ CLI_BRIDGE_DIGEST = createHash11("sha256").update(markdown).digest("hex");
51581
51797
  CLI_BRIDGE_FILES = Object.freeze({
51582
51798
  "SKILL.md": markdown,
51583
51799
  ".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 +52072,8 @@ var init_agent_codex = __esm(() => {
51856
52072
  });
51857
52073
 
51858
52074
  // src/lib/agent-integration.ts
51859
- import { createHash as createHash11, randomUUID as randomUUID5 } from "crypto";
52075
+ import { createHash as createHash12, randomUUID as randomUUID5 } from "crypto";
52076
+ import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
51860
52077
  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
52078
  import { dirname as dirname11, join as join21, resolve as resolve11, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
51862
52079
  import { homedir as homedir3 } from "os";
@@ -51965,7 +52182,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
51965
52182
  }
51966
52183
  }
51967
52184
  function treeHash(root) {
51968
- const hash2 = createHash11("sha256");
52185
+ const hash2 = createHash12("sha256");
51969
52186
  let bytes = 0, files = 0;
51970
52187
  function visit2(path) {
51971
52188
  const stat = lstatSync15(path);
@@ -51992,7 +52209,7 @@ function treeHash(root) {
51992
52209
  return hash2.digest("hex");
51993
52210
  }
51994
52211
  function parseNativeMigrationTargetManifest(input) {
51995
- const digest = sha2(input);
52212
+ const digest = sha3(input);
51996
52213
  let value;
51997
52214
  try {
51998
52215
  value = JSON.parse(input.toString());
@@ -52397,7 +52614,7 @@ function planAgentIntegration(options) {
52397
52614
  const observedNativeSources = [];
52398
52615
  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
52616
  const bytes = readNativeBytes(path, 1024 * 1024);
52400
- observedNativeSources.push({ path, sha256: sha2(bytes) });
52617
+ observedNativeSources.push({ path, sha256: sha3(bytes) });
52401
52618
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
52402
52619
  }, codexConfig.skills?.config ?? []) : policy.bridge?.codexPluginSkills ?? [];
52403
52620
  const changes = [];
@@ -52425,7 +52642,7 @@ function planAgentIntegration(options) {
52425
52642
  throw new Error("Refusing to overwrite an unrecognized Hermes supervisor");
52426
52643
  if (supervisorBefore !== supervisorAfter)
52427
52644
  changes.push({ path: supervisorPath, before: supervisorBefore, after: supervisorAfter });
52428
- const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha2(supervisorAfter) };
52645
+ const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha3(supervisorAfter) };
52429
52646
  const after3 = configureHermesHooks(before2, supervisor, previous);
52430
52647
  if (before2 !== after3)
52431
52648
  changes.push({ path, before: before2, after: after3 });
@@ -52472,12 +52689,12 @@ function planAgentIntegration(options) {
52472
52689
  agents: [...new Set([...priorAgents, ...options.agents])].sort(),
52473
52690
  home: resolve11(home),
52474
52691
  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)) } } } : {},
52692
+ ...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
52693
  commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
52477
52694
  profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
52478
52695
  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
52696
  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 } : {},
52697
+ ...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
52698
  discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
52482
52699
  } };
52483
52700
  const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
@@ -52515,7 +52732,7 @@ function atomicWrite2(path, content) {
52515
52732
  function planAgentSettingsWitnessUpgrade(options) {
52516
52733
  const home = resolve11(options.home ?? homedir3()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
52517
52734
  const snapshot = readManagedSkillPolicySnapshot(dataDir3);
52518
- if (!snapshot || sha2(snapshot.text) !== options.expectedPolicySha256)
52735
+ if (!snapshot || sha3(snapshot.text) !== options.expectedPolicySha256)
52519
52736
  throw new Error("Managed policy preimage changed");
52520
52737
  const policy = snapshot.value, aliases = policy.bridge?.rootAliases ?? [];
52521
52738
  recheckRootAliases(aliases);
@@ -52524,7 +52741,7 @@ function planAgentSettingsWitnessUpgrade(options) {
52524
52741
  throw new Error("Settings witness upgrade requires an existing reviewed native binding");
52525
52742
  const configPath = canonicalAgentPath(join21(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
52526
52743
  const settings = readOptional(configPath);
52527
- if (settings === null || sha2(settings) !== options.expectedSettingsSha256)
52744
+ if (settings === null || sha3(settings) !== options.expectedSettingsSha256)
52528
52745
  throw new Error("Native settings preimage changed");
52529
52746
  const sources = binding.sources.filter((source) => source.path === configPath && source.format === undefined && source.fields === undefined);
52530
52747
  if (sources.length !== 1)
@@ -52532,15 +52749,40 @@ function planAgentSettingsWitnessUpgrade(options) {
52532
52749
  const previous = sources[0];
52533
52750
  if (typeof previous.sha256 !== "string")
52534
52751
  throw new Error("Settings witness upgrade requires a preserved settings preimage");
52752
+ const replaced = [previous];
52753
+ if (options.agent === "codex") {
52754
+ if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1")
52755
+ throw new Error("Codex settings witness upgrade requires a preserved raw or codex-settings-v1 configuration witness");
52756
+ const preimage = readCodexSettingsPreimage(options.reviewedPreimage);
52757
+ for (const source of binding.sources) {
52758
+ if (source === previous || source.path !== configPath)
52759
+ continue;
52760
+ const fields = source.fields;
52761
+ if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields) || !isDeepStrictEqual4(fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
52762
+ throw new Error("Codex settings witness upgrade found an unrecognized configuration witness");
52763
+ if (projectNativeDiscoveryFields(preimage, "toml", fields, configPath) !== source.sha256)
52764
+ throw new Error("Reviewed preimage does not explain the Codex discovery projection witness");
52765
+ replaced.push(source);
52766
+ }
52767
+ }
52535
52768
  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) };
52769
+ const rebound = [];
52770
+ for (const source of binding.sources) {
52771
+ if (!replaced.includes(source)) {
52772
+ rebound.push(source);
52773
+ continue;
52774
+ }
52775
+ if (source === replaced[0])
52776
+ rebound.push(next);
52777
+ }
52778
+ const replacement = { ...binding, sources: rebound };
52537
52779
  verifyAgentDiscovery(replacement);
52538
52780
  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 } };
52781
+ 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
52782
  }
52541
52783
  function applyAgentIntegration(plan) {
52542
52784
  for (const source of plan.observedNativeSources ?? [])
52543
- if (sha2(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52785
+ if (sha3(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52544
52786
  throw new Error("Native identity source changed after planning");
52545
52787
  if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
52546
52788
  throw new Error("Native settings changed after witness planning");
@@ -52560,7 +52802,7 @@ function applyAgentIntegration(plan) {
52560
52802
  const upgrade = plan.settingsWitnessUpgrade;
52561
52803
  if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
52562
52804
  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 });
52805
+ 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
52806
  if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
52565
52807
  throw new Error("Settings witness upgrade plan changed");
52566
52808
  provenDiscovery = verified.discoveryBefore[0];
@@ -52588,7 +52830,7 @@ function applyAgentIntegration(plan) {
52588
52830
  chmodSync(backupRoot, 448);
52589
52831
  for (const [index, change] of plan.changes.entries())
52590
52832
  if (change.before !== null) {
52591
- const backup = join21(backupRoot, `${index}-${sha2(change.path).slice(0, 12)}.backup`);
52833
+ const backup = join21(backupRoot, `${index}-${sha3(change.path).slice(0, 12)}.backup`);
52592
52834
  writeFileSync4(backup, change.before, { mode: 384, flag: "wx" });
52593
52835
  if (readFileSync13(backup, "utf8") !== change.before)
52594
52836
  throw new Error("Native configuration preservation readback failed");
@@ -52607,7 +52849,7 @@ function applyAgentIntegration(plan) {
52607
52849
  }
52608
52850
  recheckRootAliases(aliases);
52609
52851
  for (const source of plan.observedNativeSources ?? [])
52610
- if (sha2(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52852
+ if (sha3(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52611
52853
  throw new Error("Native identity source changed during application");
52612
52854
  if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
52613
52855
  throw new Error("Native settings changed during witness application");
@@ -52619,7 +52861,7 @@ function applyAgentIntegration(plan) {
52619
52861
  }
52620
52862
  for (const agent of plan.managedAgentChecks?.agents ?? [])
52621
52863
  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 } : {} }) + `
52864
+ 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
52865
  `);
52624
52866
  } catch (error) {
52625
52867
  for (const change of written.reverse()) {
@@ -52698,8 +52940,8 @@ function archiveNativeSkills(inventory, options) {
52698
52940
  const operationId = randomUUID5(), archiveRoot = join21(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join21(archiveRoot, "receipt.json");
52699
52941
  const entries = selected.map((entry, index) => ({
52700
52942
  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,
52943
+ archive: join21(archiveRoot, `${index}-${sha3(entry.path).slice(0, 12)}`),
52944
+ hash: entry.vendor ? sha3(readNativeBytes(join21(entry.path, "SKILL.md"))) : entry.hash,
52703
52945
  ...entry.vendor ? { discoveryOnly: true } : {},
52704
52946
  status: "planned"
52705
52947
  }));
@@ -52710,7 +52952,7 @@ function archiveNativeSkills(inventory, options) {
52710
52952
  const stat = lstatSync15(entry.archive);
52711
52953
  if (entry.discoveryOnly ? !stat.isFile() : !stat.isDirectory())
52712
52954
  throw new Error("Archive type changed");
52713
- if ((entry.discoveryOnly ? sha2(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
52955
+ if ((entry.discoveryOnly ? sha3(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
52714
52956
  throw new Error("Archive bytes changed");
52715
52957
  };
52716
52958
  assertSafePath(archiveRoot);
@@ -52830,7 +53072,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
52830
53072
  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
53073
  if (agent === "hermes") {
52832
53074
  const supervisor = binding.supervisors?.hermes;
52833
- if (supervisor?.path !== join21(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha2(renderHermesSupervisor(command, profile)))
53075
+ if (supervisor?.path !== join21(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha3(renderHermesSupervisor(command, profile)))
52834
53076
  throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
52835
53077
  assertHermesProtection(home, config, command, profile, supervisor);
52836
53078
  } else if (agent === "opencode") {
@@ -52946,7 +53188,7 @@ function assertNativeExportAllowed(dataDir3 = getDataDirReadOnly()) {
52946
53188
  if (requiresCliSkillLoading(dataDir3))
52947
53189
  throw new Error("NATIVE_SKILL_EXPORT_DISABLED: this station loads skills through the Skills CLI; use skills sync --selection-profile <id>");
52948
53190
  }
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.";
53191
+ 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
53192
  var init_agent_integration = __esm(() => {
52951
53193
  init_codex_plugin_skill_controls();
52952
53194
  init_codex_native_skill_catalog();
@@ -54528,7 +54770,7 @@ var init_selection_resolver = __esm(() => {
54528
54770
  });
54529
54771
 
54530
54772
  // src/lib/plugin-projection.ts
54531
- import { createHash as createHash12 } from "crypto";
54773
+ import { createHash as createHash13 } from "crypto";
54532
54774
  import { posix } from "path";
54533
54775
  function pluginRefusal(message) {
54534
54776
  throw new SkillSelectionError("PLUGIN_ADMISSION_REFUSED", message);
@@ -54721,7 +54963,7 @@ function buildPluginProjection(entries) {
54721
54963
  files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
54722
54964
  return { manifest, payloads: manifest.payloads, files, witnesses: pluginFileWitnesses(files), originalTreeDigest, projectionTreeDigest: pluginTreeDigest(files), removed: removed.length ? pluginFileWitnesses(removed) : [] };
54723
54965
  }
54724
- var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash12("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
54966
+ var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash13("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
54725
54967
  var init_plugin_projection = __esm(() => {
54726
54968
  init_selection_cache();
54727
54969
  PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
@@ -54729,7 +54971,7 @@ var init_plugin_projection = __esm(() => {
54729
54971
  });
54730
54972
 
54731
54973
  // src/lib/plugin-projection-store.ts
54732
- import { createHash as createHash13, randomUUID as randomUUID6 } from "crypto";
54974
+ import { createHash as createHash14, randomUUID as randomUUID6 } from "crypto";
54733
54975
  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
54976
  import { dirname as dirname13, isAbsolute as isAbsolute12, join as join29, parse as parse5, resolve as resolve12 } from "path";
54735
54977
  function stat(path) {
@@ -54741,7 +54983,7 @@ function stat(path) {
54741
54983
  return pluginRefusal("Cannot inspect plugin filesystem entry");
54742
54984
  }
54743
54985
  }
54744
- function canonical4(path) {
54986
+ function canonical5(path) {
54745
54987
  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
54988
  }
54747
54989
  function owner(stats, system = false) {
@@ -54752,7 +54994,7 @@ function same3(left, right, identityOnly = false) {
54752
54994
  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
54995
  }
54754
54996
  function ancestors(path, create3 = false) {
54755
- canonical4(path);
54997
+ canonical5(path);
54756
54998
  const result2 = [], parent = dirname13(path), filesystemRoot = parse5(parent).root;
54757
54999
  let current = filesystemRoot;
54758
55000
  for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
@@ -55067,7 +55309,7 @@ function pluginExecutableDigest(path) {
55067
55309
  const opened = fstatSync9(fd, { bigint: true });
55068
55310
  same3(before2, opened);
55069
55311
  fileShape(opened, maximum, "executable");
55070
- const hash2 = createHash13("sha256"), buffer = new Uint8Array(64 * 1024);
55312
+ const hash2 = createHash14("sha256"), buffer = new Uint8Array(64 * 1024);
55071
55313
  let remaining = Number(opened.size);
55072
55314
  while (remaining > 0) {
55073
55315
  const count = readSync7(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
@@ -55650,21 +55892,21 @@ var init_plugin_discovery = __esm(() => {
55650
55892
  });
55651
55893
 
55652
55894
  // src/lib/claude-marketplace-registry.ts
55653
- import { createHash as createHash14 } from "crypto";
55895
+ import { createHash as createHash15 } from "crypto";
55654
55896
  import { closeSync as closeSync11, constants as constants11, fstatSync as fstatSync11, lstatSync as lstatSync19, openSync as openSync11, readSync as readSync9 } from "fs";
55655
55897
  import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve15 } from "path";
55656
- function need4(value, reason) {
55898
+ function need5(value, reason) {
55657
55899
  if (!value)
55658
55900
  throw new Error(`Claude marketplace registry ${reason}`);
55659
55901
  }
55660
55902
  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");
55903
+ 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
55904
  }
55663
55905
  function parents2(path) {
55664
55906
  const result2 = [];
55665
55907
  for (let at2 = dirname15(path);; at2 = dirname15(at2)) {
55666
55908
  const stat2 = lstatSync19(at2, { bigint: true });
55667
- need4(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
55909
+ need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
55668
55910
  result2.push([at2, stat2]);
55669
55911
  if (at2 === dirname15(at2))
55670
55912
  return result2;
@@ -55672,15 +55914,15 @@ function parents2(path) {
55672
55914
  }
55673
55915
  function readRegistry2(path, budget) {
55674
55916
  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");
55917
+ need5(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
55918
+ need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
55677
55919
  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");
55920
+ need5(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
55921
+ need5(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
55680
55922
  const fd = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
55681
55923
  try {
55682
55924
  const opened = fstatSync11(fd, { bigint: true });
55683
- need4(opened.isFile() && sameFile2(initial2, opened), "changed during open");
55925
+ need5(opened.isFile() && sameFile2(initial2, opened), "changed during open");
55684
55926
  const bytes = Buffer.alloc(Number(opened.size) + 1);
55685
55927
  let length = 0;
55686
55928
  while (length < bytes.length) {
@@ -55690,10 +55932,10 @@ function readRegistry2(path, budget) {
55690
55932
  length += count;
55691
55933
  }
55692
55934
  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");
55935
+ need5(current.isFile() && sameFile2(opened, after2) && sameFile2(after2, current) && BigInt(length) === opened.size, "changed during read");
55694
55936
  for (const [ancestor, before2] of ancestors2) {
55695
55937
  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");
55938
+ need5(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
55697
55939
  }
55698
55940
  budget.remaining -= length;
55699
55941
  try {
@@ -55713,7 +55955,7 @@ function parse6(text2) {
55713
55955
  at2++;
55714
55956
  };
55715
55957
  function string() {
55716
- need4(text2[at2] === '"', "contains invalid JSON");
55958
+ need5(text2[at2] === '"', "contains invalid JSON");
55717
55959
  const start = at2++;
55718
55960
  while (at2 < text2.length) {
55719
55961
  const character = text2[at2++];
@@ -55724,7 +55966,7 @@ function parse6(text2) {
55724
55966
  } catch {
55725
55967
  throw new Error("Claude marketplace registry contains invalid JSON string");
55726
55968
  }
55727
- need4(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
55969
+ need5(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
55728
55970
  return value2;
55729
55971
  }
55730
55972
  if (character === "\\")
@@ -55733,7 +55975,7 @@ function parse6(text2) {
55733
55975
  throw new Error("Claude marketplace registry contains an unterminated JSON string");
55734
55976
  }
55735
55977
  function value(depth) {
55736
- need4(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
55978
+ need5(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
55737
55979
  space();
55738
55980
  const character = text2[at2];
55739
55981
  if (character === '"')
@@ -55747,17 +55989,17 @@ function parse6(text2) {
55747
55989
  if (object5) {
55748
55990
  space();
55749
55991
  const key = string();
55750
- need4(!keys2.has(key), "contains a duplicate JSON key");
55992
+ need5(!keys2.has(key), "contains a duplicate JSON key");
55751
55993
  keys2.add(key);
55752
55994
  space();
55753
- need4(text2[at2++] === ":", "contains invalid JSON");
55995
+ need5(text2[at2++] === ":", "contains invalid JSON");
55754
55996
  entries.push([key, value(depth + 1)]);
55755
55997
  } else
55756
55998
  items.push(value(depth + 1));
55757
55999
  space();
55758
56000
  if (text2[at2] === end)
55759
56001
  break;
55760
- need4(text2[at2++] === ",", "contains invalid JSON");
56002
+ need5(text2[at2++] === ",", "contains invalid JSON");
55761
56003
  }
55762
56004
  at2++;
55763
56005
  return object5 ? { kind: "object", entries } : { kind: "array", items };
@@ -55769,21 +56011,21 @@ function parse6(text2) {
55769
56011
  }
55770
56012
  numberPattern.lastIndex = at2;
55771
56013
  const number = numberPattern.exec(text2);
55772
- need4(number, "contains invalid JSON");
56014
+ need5(number, "contains invalid JSON");
55773
56015
  at2 += number[0].length;
55774
56016
  return { kind: "number", value: number[0] };
55775
56017
  }
55776
56018
  const root2 = value(0);
55777
56019
  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");
56020
+ need5(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
56021
+ need5(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
55780
56022
  return root2;
55781
56023
  }
55782
56024
  function exactKeys(value, keys2) {
55783
56025
  return value?.kind === "object" && value.entries.length === keys2.length && value.entries.every(([key]) => keys2.includes(key));
55784
56026
  }
55785
56027
  function textField(value) {
55786
- need4(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
56028
+ need5(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
55787
56029
  return value.value;
55788
56030
  }
55789
56031
  function normalizeRow(row, version = 1) {
@@ -55791,7 +56033,7 @@ function normalizeRow(row, version = 1) {
55791
56033
  if (version !== 2 || !exactKeys(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
55792
56034
  return;
55793
56035
  const autoUpdate = field(row, "autoUpdate");
55794
- need4(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
56036
+ need5(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
55795
56037
  }
55796
56038
  const source = field(row, "source");
55797
56039
  if (source?.kind !== "object")
@@ -55807,23 +56049,23 @@ function normalizeRow(row, version = 1) {
55807
56049
  absolutePath3(sourceLocation);
55808
56050
  absolutePath3(textField(field(row, "installLocation")));
55809
56051
  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");
56052
+ 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
56053
  const millis = Date.parse(updated);
55812
- need4(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
56054
+ need5(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
55813
56055
  row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
55814
56056
  }
55815
56057
  function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
55816
56058
  const value = parse6(readRegistry2(path, budget));
55817
56059
  for (const [, row] of value.entries)
55818
56060
  normalizeRow(row);
55819
- const sha2562 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
56061
+ const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
55820
56062
  return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
55821
56063
  }
55822
56064
  function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
55823
56065
  const value = parse6(readRegistry2(path, budget));
55824
56066
  for (const [, row] of value.entries)
55825
56067
  normalizeRow(row, 2);
55826
- const sha2562 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
56068
+ const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
55827
56069
  return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
55828
56070
  }
55829
56071
  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 +56075,17 @@ var init_claude_marketplace_registry = __esm(() => {
55833
56075
 
55834
56076
  // src/lib/codex-hook-trust-files.ts
55835
56077
  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";
56078
+ import { createHash as createHash16 } from "crypto";
55837
56079
  import { dirname as dirname16 } from "path";
55838
- function need5(value, code) {
56080
+ function need6(value, code) {
55839
56081
  if (!value)
55840
56082
  throw new Error(`CODEX_HOOK_TRUST_${code}`);
55841
56083
  }
55842
56084
  function safeParents(file) {
55843
56085
  for (let p = dirname16(file);; p = dirname16(p)) {
55844
56086
  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");
56087
+ need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
56088
+ need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
55847
56089
  if (dirname16(p) === p)
55848
56090
  break;
55849
56091
  }
@@ -55852,12 +56094,12 @@ function snapshot(file, privateFile = false, options = {}) {
55852
56094
  const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
55853
56095
  safeParents(file);
55854
56096
  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");
56097
+ 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");
56098
+ need6(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
55857
56099
  const fd = openSync12(file, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
55858
56100
  try {
55859
56101
  const before2 = fstatSync12(fd, { bigint: true });
55860
- need5(sameStat(initial2, before2), "INPUT_CHANGED");
56102
+ need6(sameStat(initial2, before2), "INPUT_CHANGED");
55861
56103
  const bytes = Buffer.alloc(Number(before2.size) + 1);
55862
56104
  let length = 0;
55863
56105
  while (length < bytes.length) {
@@ -55866,16 +56108,16 @@ function snapshot(file, privateFile = false, options = {}) {
55866
56108
  break;
55867
56109
  length += n2;
55868
56110
  }
55869
- need5(length === Number(before2.size) && sameStat(before2, fstatSync12(fd, { bigint: true })) && sameStat(before2, lstatSync20(file, { bigint: true })), "INPUT_CHANGED");
56111
+ need6(length === Number(before2.size) && sameStat(before2, fstatSync12(fd, { bigint: true })) && sameStat(before2, lstatSync20(file, { bigint: true })), "INPUT_CHANGED");
55870
56112
  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") };
56113
+ return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash16("sha256").update(content).digest("hex") };
55872
56114
  } finally {
55873
56115
  closeSync12(fd);
55874
56116
  }
55875
56117
  }
55876
56118
  function unchanged2(before2) {
55877
56119
  const after2 = snapshot(before2.file, before2.privateFile, before2.readOnlyPackage ? { readOnlyPackage: true } : {});
55878
- need5(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
56120
+ need6(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
55879
56121
  }
55880
56122
  function save(file, content) {
55881
56123
  safeParents(file);
@@ -55891,7 +56133,7 @@ var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs
55891
56133
  var init_codex_hook_trust_files = () => {};
55892
56134
 
55893
56135
  // src/lib/codex-hook-trust-layout.ts
55894
- import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
56136
+ import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
55895
56137
  function codexTrustTextWitness(text2, keys2, canonicalize = true) {
55896
56138
  const parsed = Bun.TOML.parse(text2), wanted = new Set(keys2);
55897
56139
  const headers = [...text2.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
@@ -55956,7 +56198,7 @@ function codexTrustTextWitness(text2, keys2, canonicalize = true) {
55956
56198
  if (expected.hooks)
55957
56199
  delete expected.hooks.state;
55958
56200
  try {
55959
- if (!isDeepStrictEqual4(prune(Bun.TOML.parse(noState)), prune(expected)))
56201
+ if (!isDeepStrictEqual5(prune(Bun.TOML.parse(noState)), prune(expected)))
55960
56202
  throw fail2();
55961
56203
  } catch {
55962
56204
  throw fail2();
@@ -56026,55 +56268,55 @@ var init_codex_hook_trust_layout = () => {};
56026
56268
 
56027
56269
  // src/lib/codex-hook-additions-review.ts
56028
56270
  import { isAbsolute as isAbsolute16 } from "path";
56029
- import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
56271
+ import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
56030
56272
  function exactKeys2(value, keys2) {
56031
- need5(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual5(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56273
+ need6(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual6(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56032
56274
  }
56033
56275
  function readReviewedAdditionTrustStates(proof, before2, current, journalHooks) {
56034
56276
  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");
56277
+ 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
56278
  captured.recheck();
56037
56279
  unchanged2(before2);
56038
56280
  unchanged2(current);
56039
56281
  return captured.states;
56040
56282
  }
56041
56283
  function reviewNativeHookAdditions(options) {
56042
- need5(isAbsolute16(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
56284
+ need6(isAbsolute16(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
56043
56285
  const reviewFile = snapshot(options.path, true), review = JSON.parse(reviewFile.text);
56044
56286
  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");
56287
+ need6((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56046
56288
  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");
56289
+ need6(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
56048
56290
  exactKeys2(review.producerBefore, ["configPath", "configSha256", "hooksPath", "hooksSha256"]);
56049
56291
  const before2 = review.producerBefore;
56050
- need5(isAbsolute16(before2.configPath) && isAbsolute16(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56292
+ need6(isAbsolute16(before2.configPath) && isAbsolute16(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56051
56293
  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");
56294
+ need6(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56053
56295
  const original = structure(options.configBefore.text), producer = structure(producerConfig.text), expectedProducer = structuredClone(original), originalKeys = options.journalHooks.map((hook) => hook.key);
56054
56296
  expectedProducer.hooks ??= {};
56055
56297
  expectedProducer.hooks.state ??= {};
56056
56298
  for (const hook of options.journalHooks)
56057
56299
  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");
56300
+ 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");
56301
+ need6(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56060
56302
  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");
56303
+ need6(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56062
56304
  const added = [], states = [], seen = new Set, commands = new Set(options.recordedNativeHooks.map((hook) => hook.command));
56063
56305
  for (const addition of review.additions) {
56064
56306
  exactKeys2(addition, review.version === 1 ? ["event", "nativeHook"] : ["event", "nativeHook", "trustState"]);
56065
- need5(Object.hasOwn(review.version === 1 ? events : matchedEvents, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
56307
+ need6(Object.hasOwn(review.version === 1 ? events : matchedEvents, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
56066
56308
  const { event, nativeHook: hook } = addition;
56067
56309
  exactKeys2(hook, nativeKeys);
56068
56310
  const groups = expectedHooks.hooks[event] ?? [];
56069
- need5(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
56311
+ need6(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
56070
56312
  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");
56313
+ need6(hook.key === key && !seen.has(key) && !options.recordedNativeHooks.some((originalHook) => originalHook.key === key) && !Object.hasOwn(expectedConfig.hooks.state, key), "RECONCILE_ADDITIONS_IDENTITY");
56314
+ 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
56315
  let trustState = { enabled: true, trusted_hash: hook.currentHash };
56074
56316
  if (review.version === 2) {
56075
56317
  const state = addition.trustState;
56076
56318
  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");
56319
+ need6(state.trusted_hash === hook.currentHash && (!Object.hasOwn(state, "enabled") || state.enabled === true), "RECONCILE_ADDITIONS_TRUST_STATE");
56078
56320
  trustState = { ...state };
56079
56321
  }
56080
56322
  seen.add(key);
@@ -56084,9 +56326,9 @@ function reviewNativeHookAdditions(options) {
56084
56326
  expectedHooks.hooks[event] = [...groups, { ...event === "PreToolUse" ? { matcher: hook.matcher } : {}, hooks: [{ type: "command", command: hook.command, timeout: hook.timeoutSec }] }];
56085
56327
  expectedConfig.hooks.state[key] = trustState;
56086
56328
  }
56087
- need5(isDeepStrictEqual5(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56329
+ need6(isDeepStrictEqual6(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56088
56330
  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");
56331
+ 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
56332
  const inputs = [reviewFile, producerConfig, producerHooks, options.intent, options.policy, options.configBefore, options.configCurrent, options.hooksBefore, options.hooksCurrent];
56091
56333
  const recheck = () => {
56092
56334
  for (const input of inputs)
@@ -56108,8 +56350,8 @@ var init_codex_hook_additions_review = __esm(() => {
56108
56350
  });
56109
56351
 
56110
56352
  // src/lib/codex-hook-discovery-recovery.ts
56111
- import { createHash as createHash16 } from "crypto";
56112
- import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
56353
+ import { createHash as createHash17 } from "crypto";
56354
+ import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
56113
56355
  function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, additions) {
56114
56356
  const journalHooks = hooks.map(({ key, currentHash }) => ({ key, currentHash }));
56115
56357
  const additionStates = additions ? readReviewedAdditionTrustStates(additions, before2, current, journalHooks) : [];
@@ -56120,16 +56362,16 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
56120
56362
  const raw = binding.sources.filter((source) => source.path === current.file && source.hashMode === "bytes");
56121
56363
  if (!raw.some((source) => source.sha256 !== current.sha256))
56122
56364
  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");
56365
+ need6(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
56366
+ need6(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
56125
56367
  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");
56368
+ need6(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual7(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
56127
56369
  const original = structure2(before2.text), actual = structure2(current.text);
56128
56370
  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");
56371
+ const projection = sha4(JSON.stringify(project(original)));
56372
+ need6(typed[0].sha256 === projection && sha4(JSON.stringify(project(actual))) === projection && isDeepStrictEqual7(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
56131
56373
  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");
56374
+ 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
56375
  const expected = structuredClone(original);
56134
56376
  expected.hooks ??= {};
56135
56377
  expected.hooks.state ??= {};
@@ -56137,16 +56379,16 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
56137
56379
  expected.hooks.state[hook.key] = { ...expected.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
56138
56380
  for (const { key, state } of additionStates)
56139
56381
  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");
56382
+ 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
56383
  unchanged2(before2);
56142
56384
  unchanged2(current);
56143
- const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha3(JSON.stringify(binding)), typedProjectionSha256: projection });
56385
+ const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha4(JSON.stringify(binding)), typedProjectionSha256: projection });
56144
56386
  proofs2.set(witness, { before: before2, current, recheckAdditions });
56145
56387
  return witness;
56146
56388
  }
56147
56389
  function assertCodexHookDiscoveryRecovery(binding, witness) {
56148
56390
  const proof = proofs2.get(witness);
56149
- need5(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha3(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56391
+ need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha4(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56150
56392
  unchanged2(proof.before);
56151
56393
  unchanged2(proof.current);
56152
56394
  proof.recheckAdditions();
@@ -56155,23 +56397,24 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
56155
56397
  if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
56156
56398
  return false;
56157
56399
  assertCodexHookDiscoveryRecovery(binding, witness);
56158
- need5(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56400
+ need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56159
56401
  return true;
56160
56402
  }
56161
- var sha3 = (text3) => createHash16("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
56403
+ var sha4 = (text3) => createHash17("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
56162
56404
  var init_codex_hook_discovery_recovery = __esm(() => {
56163
56405
  init_codex_hook_trust_files();
56164
56406
  init_codex_hook_trust_layout();
56165
56407
  init_codex_hook_additions_review();
56166
- fields = ["plugins", "marketplaces", "skills"];
56408
+ init_codex_settings_witness();
56409
+ fields = [...CODEX_DISCOVERY_PROJECTION_FIELDS];
56167
56410
  proofs2 = new WeakMap;
56168
56411
  });
56169
56412
 
56170
56413
  // src/lib/agent-discovery.ts
56171
- import { createHash as createHash17 } from "crypto";
56414
+ import { createHash as createHash18 } from "crypto";
56172
56415
  import { lstatSync as lstatSync21, readFileSync as readFileSync18, readdirSync as readdirSync11, realpathSync as realpathSync7 } from "fs";
56173
56416
  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";
56417
+ import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
56175
56418
  function parseConfig(text3, path, toml = false) {
56176
56419
  try {
56177
56420
  const value = toml ? Bun.TOML.parse(text3) : JSON.parse(text3);
@@ -56203,14 +56446,26 @@ function read2(path, changes) {
56203
56446
  throw new Error(`Unsupported or oversized native discovery input: ${path}`);
56204
56447
  return readFileSync18(path, "utf8");
56205
56448
  }
56449
+ function projectNativeDiscoveryFields(text3, format, fields2, path) {
56450
+ const object5 = format === "yaml" ? parseHermesConfig(text3) : parseConfig(text3, path, format === "toml");
56451
+ if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
56452
+ throw new Error("Expected native discovery configuration object");
56453
+ return digest(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object5[field2] ?? null]))));
56454
+ }
56455
+ function isSupersededCodexProjection(agent, configPath, source) {
56456
+ return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual8(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
56457
+ }
56458
+ function supersedesCodexProjection(sources, configPath) {
56459
+ return sources.some((source) => source.path === configPath && source.hashMode === "codex-settings-v2");
56460
+ }
56206
56461
  function projected(source, changes, budget = discoveryByteBudget()) {
56207
- if (source.hashMode === "codex-settings-v1") {
56462
+ if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") {
56208
56463
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
56209
56464
  throw new Error("Codex settings witnesses require exact typed metadata");
56210
- const current = captureCodexSettings(source.path, budget).sha256;
56465
+ const current = (source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
56211
56466
  if (current !== source.sha256)
56212
56467
  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;
56468
+ return changes?.has(source.path) ? (source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
56214
56469
  }
56215
56470
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
56216
56471
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
@@ -56249,10 +56504,7 @@ function projected(source, changes, budget = discoveryByteBudget()) {
56249
56504
  return null;
56250
56505
  if (!source.format)
56251
56506
  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]))));
56507
+ return projectNativeDiscoveryFields(text3, source.format, source.fields ?? [], source.path);
56256
56508
  }
56257
56509
  function verifyAgentDiscovery(binding, codexRecovery) {
56258
56510
  if (codexRecovery)
@@ -56280,7 +56532,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
56280
56532
  safe4(root2);
56281
56533
  }
56282
56534
  function assertMarketplaceBinding(binding, source) {
56283
- if (source.hashMode === "codex-settings-v1" && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
56535
+ if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
56284
56536
  throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
56285
56537
  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
56538
  throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
@@ -56297,8 +56549,8 @@ function rebindAgentDiscovery(binding, changes) {
56297
56549
  return { ...source, sha256: sha2562 };
56298
56550
  }) };
56299
56551
  }
56300
- function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16, reviewed) {
56301
- const homeConfigPath = canonical5(agentDiscoveryConfigPath(home, agent));
56552
+ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve16, reviewed) {
56553
+ const homeConfigPath = canonical6(agentDiscoveryConfigPath(home, agent));
56302
56554
  for (const directory of directories) {
56303
56555
  const isHome = resolve16(directory) === resolve16(home);
56304
56556
  if (agent === "hermes") {
@@ -56309,7 +56561,7 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16
56309
56561
  continue;
56310
56562
  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
56563
  for (const suffix of paths) {
56312
- const path = canonical5(join32(directory, suffix)), raw = read2(path);
56564
+ const path = canonical6(join32(directory, suffix)), raw = read2(path);
56313
56565
  if (raw === null)
56314
56566
  continue;
56315
56567
  const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
@@ -56325,14 +56577,14 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16
56325
56577
  const managed = reviewed.sources.flatMap((source) => source.hashMode === "claude-plugin-registry" ? source.managedPlugins ?? [] : []);
56326
56578
  if (exact && projected(exact) === exact.sha256 && managed.length) {
56327
56579
  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))));
56580
+ 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
56581
  }
56330
56582
  }
56331
56583
  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
56584
  throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
56333
56585
  }
56334
56586
  if (agent === "claude") {
56335
- const commands = canonical5(join32(directory, ".claude/commands"));
56587
+ const commands = canonical6(join32(directory, ".claude/commands"));
56336
56588
  safe4(commands);
56337
56589
  if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync11(commands).length)
56338
56590
  throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
@@ -56343,10 +56595,10 @@ function agentDiscoveryConfigPath(home, agent) {
56343
56595
  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
56596
  }
56345
56597
  function resolveAgentDiscovery(options) {
56346
- const canonical5 = options.canonical ?? resolve16, home = resolve16(options.home), agent = options.agent;
56598
+ const canonical6 = options.canonical ?? resolve16, home = resolve16(options.home), agent = options.agent;
56347
56599
  const sources = [], roots = new Set, builtinNames = [];
56348
56600
  const witness = (path, format, fields2) => {
56349
- const source = { path: canonical5(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
56601
+ const source = { path: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
56350
56602
  source.sha256 = projected(source);
56351
56603
  sources.push(source);
56352
56604
  return read2(source.path);
@@ -56354,7 +56606,7 @@ function resolveAgentDiscovery(options) {
56354
56606
  if (agent === "hermes")
56355
56607
  assertHermesEnvironment(home);
56356
56608
  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"]);
56609
+ 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
56610
  const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
56359
56611
  const unresolved = (detail) => {
56360
56612
  throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
@@ -56413,11 +56665,12 @@ function resolveAgentDiscovery(options) {
56413
56665
  if (retained.agent !== agent || retained.method !== "reviewed")
56414
56666
  unresolved("invalid retained review");
56415
56667
  verifyAgentDiscovery(retained);
56416
- if (!retained.sources.some((source) => source.path === canonical5(configPath) && source.format === undefined && source.fields === undefined))
56668
+ if (!retained.sources.some((source) => source.path === canonical6(configPath) && source.format === undefined && source.fields === undefined))
56417
56669
  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)))
56670
+ 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
56671
  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))
56672
+ const covered = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
56673
+ 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
56674
  unresolved("retained review is missing current runtime discovery coverage");
56422
56675
  return retained;
56423
56676
  }
@@ -56431,14 +56684,15 @@ function resolveAgentDiscovery(options) {
56431
56684
  if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
56432
56685
  throw new Error("Explicit discovery reviews require full source-file hashes");
56433
56686
  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)))
56687
+ 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
56688
  throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
56436
- if (!review.sources.some((source) => source.path === canonical5(configPath)))
56689
+ if (!review.sources.some((source) => source.path === canonical6(configPath)))
56437
56690
  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 } : {} };
56691
+ const reviewedSources = supersedesCodexProjection(review.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
56692
+ return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...reviewedSources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
56439
56693
  }
56440
56694
  function plugin(root2) {
56441
- root2 = canonical5(root2);
56695
+ root2 = canonical6(root2);
56442
56696
  safe4(root2);
56443
56697
  const manifestPath = join32(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
56444
56698
  const raw = witness(manifestPath);
@@ -56470,7 +56724,7 @@ function resolveAgentDiscovery(options) {
56470
56724
  if (agent === "claude") {
56471
56725
  const registrations = witness(join32(home, ".claude/plugins/installed_plugins.json"));
56472
56726
  const installed = registrations === null ? {} : parseConfig(registrations, join32(home, ".claude/plugins/installed_plugins.json")).plugins;
56473
- const commands = canonical5(join32(home, ".claude/commands"));
56727
+ const commands = canonical6(join32(home, ".claude/commands"));
56474
56728
  safe4(commands);
56475
56729
  if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync11(commands).length)
56476
56730
  unresolved("legacy home command discovery requires a dedicated format adapter");
@@ -56544,9 +56798,9 @@ function resolveAgentDiscovery(options) {
56544
56798
  roots.add(join32(root2, "skills"));
56545
56799
  }
56546
56800
  }
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))) } : {} };
56801
+ 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
56802
  }
56549
- var digest = (text3) => createHash17("sha256").update(text3).digest("hex");
56803
+ var digest = (text3) => createHash18("sha256").update(text3).digest("hex");
56550
56804
  var init_agent_discovery = __esm(() => {
56551
56805
  init_agent_policy_limits();
56552
56806
  init_agent_hermes();
@@ -56679,7 +56933,7 @@ import {
56679
56933
  statSync as statSync11,
56680
56934
  writeFileSync as writeFileSync9
56681
56935
  } 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";
56936
+ 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
56937
  function getPortableSkillsRoot(options = {}) {
56684
56938
  return resolvePortableSkillsRoot(options, true);
56685
56939
  }
@@ -56777,7 +57031,7 @@ function scaffoldPortableSkill(name, options = {}) {
56777
57031
  return { name: skillName, path: skillPath, manifest, created: true };
56778
57032
  }
56779
57033
  function portPortableSkillDirectory(sourceDir, options = {}) {
56780
- const absoluteSource = normalize3(sourceDir);
57034
+ const absoluteSource = normalize4(sourceDir);
56781
57035
  if (!existsSync18(absoluteSource) || !statSync11(absoluteSource).isDirectory()) {
56782
57036
  throw new Error(`Import directory not found: ${sourceDir}`);
56783
57037
  }
@@ -56844,7 +57098,7 @@ function assertDisjointImportPaths(source, destination) {
56844
57098
  }
56845
57099
  }
56846
57100
  function portPortableSkill(sourcePath, options = {}) {
56847
- const absoluteSource = normalize3(sourcePath);
57101
+ const absoluteSource = normalize4(sourcePath);
56848
57102
  if (!existsSync18(absoluteSource) || !statSync11(absoluteSource).isDirectory()) {
56849
57103
  throw new Error(`Skill source directory not found: ${sourcePath}`);
56850
57104
  }
@@ -57056,7 +57310,7 @@ function safeIsDirectory(path) {
57056
57310
  function isSafeRelativePath2(value) {
57057
57311
  if (!value.trim() || isAbsolute18(value))
57058
57312
  return false;
57059
- const normalized = normalize3(value).replace(/\\/g, "/");
57313
+ const normalized = normalize4(value).replace(/\\/g, "/");
57060
57314
  return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
57061
57315
  }
57062
57316
  function add4(target, code, message) {
@@ -59482,7 +59736,7 @@ var init_remote_workspace_selection = __esm(() => {
59482
59736
  });
59483
59737
 
59484
59738
  // src/lib/remote-private-publications.ts
59485
- import { createHash as createHash18 } from "crypto";
59739
+ import { createHash as createHash19 } from "crypto";
59486
59740
  function checkedPublicationDeclaration(value) {
59487
59741
  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
59742
  return bad();
@@ -59743,7 +59997,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures, PrivatePublicationError, bad = () =
59743
59997
  throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
59744
59998
  }, invalid3 = () => {
59745
59999
  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");
60000
+ }, 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
60001
  var init_remote_private_publications = __esm(() => {
59748
60002
  init_fleet_credentials();
59749
60003
  init_remote_workspace_selection();
@@ -63282,15 +63536,15 @@ var init_schemas = __esm(() => {
63282
63536
  } catch (_err) {}
63283
63537
  }
63284
63538
  const input = payload.value;
63285
- const isDate2 = input instanceof Date;
63286
- const isValidDate = isDate2 && !Number.isNaN(input.getTime());
63539
+ const isDate3 = input instanceof Date;
63540
+ const isValidDate = isDate3 && !Number.isNaN(input.getTime());
63287
63541
  if (isValidDate)
63288
63542
  return payload;
63289
63543
  payload.issues.push({
63290
63544
  expected: "date",
63291
63545
  code: "invalid_type",
63292
63546
  input,
63293
- ...isDate2 ? { received: "Invalid Date" } : {},
63547
+ ...isDate3 ? { received: "Invalid Date" } : {},
63294
63548
  inst
63295
63549
  });
63296
63550
  return payload;
@@ -79132,7 +79386,7 @@ var init_v4 = __esm(() => {
79132
79386
  });
79133
79387
 
79134
79388
  // src/lib/canonical-json.ts
79135
- import { createHash as createHash19 } from "crypto";
79389
+ import { createHash as createHash20 } from "crypto";
79136
79390
  function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
79137
79391
  return canonicalJsonAtDepth(value, maximumBytes, 64);
79138
79392
  }
@@ -79176,7 +79430,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
79176
79430
  return visit3(value, 0);
79177
79431
  }
79178
79432
  function canonicalJsonSha256(value, maximumBytes) {
79179
- return createHash19("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
79433
+ return createHash20("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
79180
79434
  }
79181
79435
  var init_canonical_json = () => {};
79182
79436
 
@@ -79511,7 +79765,7 @@ var init_remote_recurring = __esm(() => {
79511
79765
 
79512
79766
  // src/lib/remote-run-contract.ts
79513
79767
  function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
79514
- const record8 = isRecord3(payload) ? payload : {};
79768
+ const record8 = isRecord4(payload) ? payload : {};
79515
79769
  return {
79516
79770
  contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
79517
79771
  ...pickString(record8, "id"),
@@ -79533,7 +79787,7 @@ function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
79533
79787
  ...hasOwn(record8, "details") ? { details: record8.details } : {}
79534
79788
  };
79535
79789
  }
79536
- function isRecord3(value) {
79790
+ function isRecord4(value) {
79537
79791
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
79538
79792
  }
79539
79793
  function hasOwn(record8, key) {
@@ -79672,7 +79926,7 @@ var init_remote_credit_checkout = __esm(() => {
79672
79926
 
79673
79927
  // src/lib/remote-profile.ts
79674
79928
  function customerNamePatch(input2, field2) {
79675
- if (!isRecord4(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
79929
+ if (!isRecord5(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
79676
79930
  throw new Error("Provide only the requested name field.");
79677
79931
  const value = input2[field2];
79678
79932
  if (typeof value !== "string" || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value) || !value.trim() || [...value.trim()].length > 100) {
@@ -79680,22 +79934,22 @@ function customerNamePatch(input2, field2) {
79680
79934
  }
79681
79935
  return { [field2]: value.trim() };
79682
79936
  }
79683
- function isRecord4(value) {
79937
+ function isRecord5(value) {
79684
79938
  return !!value && typeof value === "object" && !Array.isArray(value);
79685
79939
  }
79686
79940
  function string4(value) {
79687
79941
  return typeof value === "string" && value.length > 0;
79688
79942
  }
79689
79943
  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)) {
79944
+ const user = isRecord5(value) && value.user;
79945
+ 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
79946
  throw new Error("The server returned an invalid account profile.");
79693
79947
  }
79694
79948
  return { user: { id: user.id, email: user.email, displayName: user.displayName, role: user.role } };
79695
79949
  }
79696
79950
  function parseUpdatedWorkspace(value) {
79697
- const organization2 = isRecord4(value) && value.organization;
79698
- if (!isRecord4(organization2) || !string4(organization2.id) || !string4(organization2.slug) || !string4(organization2.name)) {
79951
+ const organization2 = isRecord5(value) && value.organization;
79952
+ if (!isRecord5(organization2) || !string4(organization2.id) || !string4(organization2.slug) || !string4(organization2.name)) {
79699
79953
  throw new Error("The server returned an invalid workspace.");
79700
79954
  }
79701
79955
  return { organization: { id: organization2.id, slug: organization2.slug, name: organization2.name } };
@@ -80877,7 +81131,7 @@ async function requestAuthApi(instance, path, options) {
80877
81131
  const text4 = await res.text();
80878
81132
  const body = text4 ? parseJsonBody(text4) : {};
80879
81133
  if (!res.ok) {
80880
- const record9 = isRecord5(body) ? body : {};
81134
+ const record9 = isRecord6(body) ? body : {};
80881
81135
  const detail = typeof record9.detail === "string" ? record9.detail : undefined;
80882
81136
  const error61 = typeof record9.error === "string" ? record9.error : undefined;
80883
81137
  const code = typeof record9.code === "string" ? record9.code : undefined;
@@ -80905,7 +81159,7 @@ function condenseErrorBody(text4) {
80905
81159
  return collapsed;
80906
81160
  return `${collapsed.slice(0, MAX_ERROR_DETAIL_LENGTH - 1).trimEnd()}\u2026`;
80907
81161
  }
80908
- function isRecord5(value) {
81162
+ function isRecord6(value) {
80909
81163
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
80910
81164
  }
80911
81165
 
@@ -81090,10 +81344,10 @@ var init_remote_auth = __esm(() => {
81090
81344
  });
81091
81345
 
81092
81346
  // src/lib/sign-in.ts
81093
- import { createHash as createHash20 } from "crypto";
81347
+ import { createHash as createHash21 } from "crypto";
81094
81348
  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
81349
  import { basename as basename13, dirname as dirname21, join as join37 } from "path";
81096
- function isRecord6(value) {
81350
+ function isRecord7(value) {
81097
81351
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
81098
81352
  }
81099
81353
  function boundedText(value, max2 = 2048) {
@@ -81118,7 +81372,7 @@ function clampIntervalMs(seconds) {
81118
81372
  return Math.min(MAX_INTERVAL_MS, Math.max(MIN_INTERVAL_MS, Math.round(seconds * 1000)));
81119
81373
  }
81120
81374
  function parseDeviceAuthorizationStart(body) {
81121
- const record9 = isRecord6(body) ? body : {};
81375
+ const record9 = isRecord7(body) ? body : {};
81122
81376
  if (typeof record9.error === "string") {
81123
81377
  throw new Error(typeof record9.detail === "string" ? record9.detail : record9.error);
81124
81378
  }
@@ -81152,7 +81406,7 @@ function pollDeviceToken(origin, deviceCode) {
81152
81406
  });
81153
81407
  }
81154
81408
  function deviceErrorCode(error61) {
81155
- if (!(error61 instanceof HostedApiError) && !(isRecord6(error61) && error61.name === "HostedApiError"))
81409
+ if (!(error61 instanceof HostedApiError) && !(isRecord7(error61) && error61.name === "HostedApiError"))
81156
81410
  return;
81157
81411
  const failure = error61;
81158
81412
  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 +81467,7 @@ async function pollDeviceAuthorization(input2) {
81213
81467
  throw error61;
81214
81468
  }
81215
81469
  }
81216
- const record9 = isRecord6(body) ? body : {};
81470
+ const record9 = isRecord7(body) ? body : {};
81217
81471
  const code = typeof record9.error === "string" ? record9.error : undefined;
81218
81472
  if (code === "authorization_pending" || code === undefined && record9.status === "pending") {
81219
81473
  await wait();
@@ -81241,7 +81495,7 @@ function pendingDeviceSignInStem(env3) {
81241
81495
  }
81242
81496
  function pendingDeviceSignInPath(origin, env3 = process.env) {
81243
81497
  const { dir, stem } = pendingDeviceSignInStem(env3);
81244
- return join37(dir, `${stem}-${createHash20("sha256").update(origin).digest("hex").slice(0, 16)}.json`);
81498
+ return join37(dir, `${stem}-${createHash21("sha256").update(origin).digest("hex").slice(0, 16)}.json`);
81245
81499
  }
81246
81500
  function savePendingDeviceSignIn(origin, start, env3 = process.env, now3 = Date.now()) {
81247
81501
  const path = pendingDeviceSignInPath(origin, env3);
@@ -81271,7 +81525,7 @@ function loadPendingDeviceSignIn(origin, env3 = process.env, now3 = Date.now())
81271
81525
  } catch {
81272
81526
  return null;
81273
81527
  }
81274
- if (!isRecord6(parsed))
81528
+ if (!isRecord7(parsed))
81275
81529
  return null;
81276
81530
  const deviceCode = boundedText(parsed.deviceCode, 512);
81277
81531
  const userCode = boundedText(parsed.userCode, 64);
@@ -81313,7 +81567,7 @@ function pendingDeviceSignInOrigins(env3 = process.env, now3 = Date.now()) {
81313
81567
  continue;
81314
81568
  try {
81315
81569
  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))
81570
+ if (isRecord7(parsed) && typeof parsed.origin === "string" && Number(parsed.expiresAt) > now3 && pendingDeviceSignInPath(parsed.origin, env3) === join37(location.dir, entry))
81317
81571
  origins.push(parsed.origin);
81318
81572
  } catch {}
81319
81573
  }
@@ -81355,7 +81609,7 @@ async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "si
81355
81609
  headers: { Authorization: `Bearer ${result2.token}` },
81356
81610
  body: JSON.stringify({ name: "cli" })
81357
81611
  });
81358
- apiKey = isRecord6(created) && typeof created.key === "string" && created.key.trim() ? created.key : undefined;
81612
+ apiKey = isRecord7(created) && typeof created.key === "string" && created.key.trim() ? created.key : undefined;
81359
81613
  }
81360
81614
  if (!apiKey)
81361
81615
  throw new Error("Sign-in succeeded but the server returned no API key");
@@ -81394,7 +81648,7 @@ async function revokeStoredKey(origin, apiKey) {
81394
81648
  }
81395
81649
  return { outcome: "failed", detail: "the server could not be reached" };
81396
81650
  }
81397
- if (isRecord6(body) && body.revoked === true)
81651
+ if (isRecord7(body) && body.revoked === true)
81398
81652
  return { outcome: "revoked" };
81399
81653
  return { outcome: "not_revoked", detail: "the server answered without confirming revocation" };
81400
81654
  }
@@ -81518,10 +81772,10 @@ async function readSignedInAccount(env3 = process.env) {
81518
81772
  const body = await new RemoteSkillsAuthClient(connection.apiOrigin).request("/api/auth/whoami", {
81519
81773
  headers: { Authorization: `Bearer ${connection.apiKey}` }
81520
81774
  });
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 : {};
81775
+ const record9 = isRecord7(body) ? body : {};
81776
+ const data = isRecord7(record9.data) ? record9.data : {};
81777
+ const user = isRecord7(record9.user) ? record9.user : isRecord7(data.user) ? data.user : {};
81778
+ const organization2 = isRecord7(record9.organization) ? record9.organization : isRecord7(data.organization) ? data.organization : {};
81525
81779
  const email4 = boundedText(user.email, 320);
81526
81780
  const org = boundedText(organization2.slug, 200) ?? boundedText(organization2.name, 200);
81527
81781
  return { ...base2, ...email4 ? { email: email4 } : {}, ...org ? { organization: org } : {} };
@@ -81936,7 +82190,7 @@ function optionPrefix(program2, args) {
81936
82190
  }
81937
82191
 
81938
82192
  // src/lib/revision.ts
81939
- import { createHash as createHash21 } from "crypto";
82193
+ import { createHash as createHash22 } from "crypto";
81940
82194
  function revisionIdOf(content) {
81941
82195
  const canonicalContent = {
81942
82196
  slug: content.slug,
@@ -81956,8 +82210,8 @@ function revisionIdOf(content) {
81956
82210
  canonicalContent.archiveReason = content.archiveReason ?? null;
81957
82211
  canonicalContent.replacementSlug = content.replacementSlug ?? null;
81958
82212
  }
81959
- const canonical5 = JSON.stringify(canonicalContent);
81960
- return createHash21("sha256").update(canonical5).digest("hex");
82213
+ const canonical6 = JSON.stringify(canonicalContent);
82214
+ return createHash22("sha256").update(canonical6).digest("hex");
81961
82215
  }
81962
82216
  var REVISION_ID_PATTERN;
81963
82217
  var init_revision = __esm(() => {
@@ -82406,7 +82660,7 @@ var init_pull = __esm(() => {
82406
82660
  });
82407
82661
 
82408
82662
  // src/lib/skill-context.ts
82409
- import { createHash as createHash22 } from "crypto";
82663
+ import { createHash as createHash23 } from "crypto";
82410
82664
  import { resolve as resolve19 } from "path";
82411
82665
  function words2(value) {
82412
82666
  return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
@@ -82495,7 +82749,7 @@ ${content}`;
82495
82749
  `);
82496
82750
  const receipt = {
82497
82751
  schemaVersion: 1,
82498
- id: createHash22("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
82752
+ id: createHash23("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
82499
82753
  profileId: profile.profileId,
82500
82754
  profileRevision: profile.profileRevision,
82501
82755
  authority: profile.authority,
@@ -82517,8 +82771,8 @@ var init_skill_context = __esm(() => {
82517
82771
  });
82518
82772
 
82519
82773
  // src/lib/session-reconciliation.ts
82520
- import { createHash as createHash23 } from "crypto";
82521
- import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
82774
+ import { createHash as createHash24 } from "crypto";
82775
+ import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
82522
82776
  function exactTimestamp(value) {
82523
82777
  const parsed = value === undefined ? Number.NaN : Date.parse(value);
82524
82778
  if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
@@ -82575,7 +82829,7 @@ async function reconcileSkillSessionIfSafe(sessionId, profileId, options = {}) {
82575
82829
  for (const key of old.loaded) {
82576
82830
  const previous = oldByKey.get(key);
82577
82831
  const current = targetBySlug.get(previous.slug);
82578
- if (!current || !isDeepStrictEqual8({ ...previous, profileRevision: target.profileRevision }, current)) {
82832
+ if (!current || !isDeepStrictEqual9({ ...previous, profileRevision: target.profileRevision }, current)) {
82579
82833
  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
82834
  }
82581
82835
  }
@@ -82657,7 +82911,7 @@ async function reconcileSkillSession(input2, options = {}) {
82657
82911
  const result2 = replaceSkillSession(skillSessionSnapshotBinding(snapshot2), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
82658
82912
  return { applied: true, plan, planDigest, ...result2 };
82659
82913
  }
82660
- var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash23("sha256").update(JSON.stringify(value)).digest("hex");
82914
+ var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash24("sha256").update(JSON.stringify(value)).digest("hex");
82661
82915
  var init_session_reconciliation = __esm(() => {
82662
82916
  init_profile_client();
82663
82917
  init_selection_cache();
@@ -83793,7 +84047,7 @@ function handleDiff(name, options) {
83793
84047
  const sourcePath = getSkillPath(bare);
83794
84048
  const canonicalDir = join39(resolveCorpusRoot(), normalized);
83795
84049
  const canonicalSkillMd = join39(canonicalDir, "SKILL.md");
83796
- const canonical5 = {
84050
+ const canonical6 = {
83797
84051
  present: existsSync22(canonicalSkillMd),
83798
84052
  path: canonicalDir,
83799
84053
  ...existsSync22(canonicalSkillMd) ? { hash: hashSkillMarkdownFile(canonicalSkillMd) } : {},
@@ -83825,7 +84079,7 @@ function handleDiff(name, options) {
83825
84079
  stub = undefined;
83826
84080
  }
83827
84081
  }
83828
- const diverged = present && canonical5.present && managed && hash5 !== canonical5.hash;
84082
+ const diverged = present && canonical6.present && managed && hash5 !== canonical6.hash;
83829
84083
  homes.push({
83830
84084
  agent,
83831
84085
  path: dir,
@@ -83840,7 +84094,7 @@ function handleDiff(name, options) {
83840
84094
  if (options.json) {
83841
84095
  console.log(JSON.stringify({
83842
84096
  name: bare,
83843
- canonical: canonical5,
84097
+ canonical: canonical6,
83844
84098
  pinned,
83845
84099
  installedVersion,
83846
84100
  registryVersion,
@@ -83848,10 +84102,10 @@ function handleDiff(name, options) {
83848
84102
  homes
83849
84103
  }, null, 2));
83850
84104
  } else {
83851
- if (!canonical5.present) {
84105
+ if (!canonical6.present) {
83852
84106
  console.log(source_default.yellow(`${bare}: no canonical corpus entry`));
83853
84107
  } else {
83854
- console.log(source_default.dim(`${bare} canonical: ${canonical5.hash?.slice(0, 12)}\u2026`));
84108
+ console.log(source_default.dim(`${bare} canonical: ${canonical6.hash?.slice(0, 12)}\u2026`));
83855
84109
  }
83856
84110
  if (pinned) {
83857
84111
  console.log(upToDate ? source_default.green(`\u2713 pin is up to date (${installedVersion})`) : source_default.yellow(`pin metadata differs: ${installedVersion} \u2192 ${registryVersion}`));
@@ -83862,14 +84116,14 @@ function handleDiff(name, options) {
83862
84116
  } else if (!home.managed) {
83863
84117
  console.log(`${source_default.dim("\u2022")} ${home.agent}: ${source_default.yellow("unmarked (adoption candidate)")}`);
83864
84118
  } 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}`);
84119
+ 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)" : "";
84120
+ 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
84121
  } else {
83868
84122
  console.log(`${source_default.green("\u2713")} ${home.agent}: ${source_default.green("matches canonical")}`);
83869
84123
  }
83870
84124
  }
83871
84125
  }
83872
- if (divergedHomes.length > 0 || homes.length > 0 && !canonical5.present)
84126
+ if (divergedHomes.length > 0 || homes.length > 0 && !canonical6.present)
83873
84127
  process.exitCode = 1;
83874
84128
  }
83875
84129
  var init_introspect = __esm(() => {
@@ -87175,7 +87429,7 @@ var init_execution_grants = __esm(() => {
87175
87429
  });
87176
87430
 
87177
87431
  // src/lib/execution-grant-client.ts
87178
- import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
87432
+ import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
87179
87433
  function id(value) {
87180
87434
  if (!grantIdentifier(value))
87181
87435
  throw new Error("Invalid execution grant profile or revision identifier.");
@@ -87227,7 +87481,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
87227
87481
  headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
87228
87482
  body: JSON.stringify({ grants: snapshot2 })
87229
87483
  }));
87230
- if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual9(policy.grants, snapshot2)) {
87484
+ if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual10(policy.grants, snapshot2)) {
87231
87485
  throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
87232
87486
  }
87233
87487
  return policy;
@@ -87238,7 +87492,7 @@ async function resolveExecutionGrant(input2) {
87238
87492
  if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
87239
87493
  throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
87240
87494
  }
87241
- if (!isDeepStrictEqual9(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual9(value.bindings.consumer, snapshot2.consumer)) {
87495
+ if (!isDeepStrictEqual10(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual10(value.bindings.consumer, snapshot2.consumer)) {
87242
87496
  throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
87243
87497
  }
87244
87498
  return value;
@@ -87257,7 +87511,7 @@ __export(exports_selected_run, {
87257
87511
  prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
87258
87512
  executeSelectedLocal: () => executeSelectedLocal
87259
87513
  });
87260
- import { createHash as createHash24 } from "crypto";
87514
+ import { createHash as createHash25 } from "crypto";
87261
87515
  import { spawn as spawn3 } from "child_process";
87262
87516
  import { mkdirSync as mkdirSync15, mkdtempSync as mkdtempSync4, writeFileSync as writeFileSync15, realpathSync as realpathSync11 } from "fs";
87263
87517
  import { dirname as dirname23, join as join45, resolve as resolve20 } from "path";
@@ -87383,7 +87637,7 @@ async function executeSelectedLocal(selected, options = {}) {
87383
87637
  selection: selection2,
87384
87638
  target: "local",
87385
87639
  runtime: runtimeName,
87386
- inputDigest: `sha256:${createHash24("sha256").update(input2).digest("hex")}`,
87640
+ inputDigest: `sha256:${createHash25("sha256").update(input2).digest("hex")}`,
87387
87641
  runDirectory,
87388
87642
  ...executionGrant ? { executionGrant } : {},
87389
87643
  ...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
@@ -91600,7 +91854,7 @@ var init_runs = __esm(() => {
91600
91854
  });
91601
91855
 
91602
91856
  // src/lib/run-state.ts
91603
- import { createHash as createHash25, randomBytes } from "crypto";
91857
+ import { createHash as createHash26, randomBytes } from "crypto";
91604
91858
  import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync32, readdirSync as readdirSync18, statSync as statSync16, writeFileSync as writeFileSync16 } from "fs";
91605
91859
  import { extname, join as join46, relative as relative7 } from "path";
91606
91860
  function createSkillRun(params, targetDir = process.cwd()) {
@@ -91737,7 +91991,7 @@ function collectRunArtifacts(context) {
91737
91991
  artifacts.push({
91738
91992
  path: toProjectRelative(context.targetDir, path),
91739
91993
  mime: mimeForPath(path),
91740
- sha256: createHash25("sha256").update(bytes).digest("hex"),
91994
+ sha256: createHash26("sha256").update(bytes).digest("hex"),
91741
91995
  sizeBytes: stat2.size
91742
91996
  });
91743
91997
  }
@@ -97463,8 +97717,8 @@ var require_resolve = __commonJS((exports) => {
97463
97717
  }
97464
97718
  return count;
97465
97719
  }
97466
- function getFullPath(resolver, id2 = "", normalize4) {
97467
- if (normalize4 !== false)
97720
+ function getFullPath(resolver, id2 = "", normalize5) {
97721
+ if (normalize5 !== false)
97468
97722
  id2 = normalizeId(id2);
97469
97723
  const p = resolver.parse(id2);
97470
97724
  return _getFullPath(resolver, p);
@@ -99023,7 +99277,7 @@ var require_fast_uri = __commonJS((exports, module) => {
99023
99277
  }
99024
99278
  return decodedScheme;
99025
99279
  }
99026
- function normalize4(uri, options) {
99280
+ function normalize5(uri, options) {
99027
99281
  if (typeof uri === "string") {
99028
99282
  uri = normalizeString(uri, options);
99029
99283
  } else if (typeof uri === "object") {
@@ -99400,7 +99654,7 @@ var require_fast_uri = __commonJS((exports, module) => {
99400
99654
  }
99401
99655
  var fastUri = {
99402
99656
  SCHEMES,
99403
- normalize: normalize4,
99657
+ normalize: normalize5,
99404
99658
  resolve: resolve21,
99405
99659
  resolveComponent,
99406
99660
  equal,
@@ -104410,7 +104664,7 @@ async function continueRecurringRecovery(customer, directory, options) {
104410
104664
  throw error61;
104411
104665
  }
104412
104666
  }
104413
- var uuid11, sha4, common2, intentSchema, stateSchema, invalid6 = () => {
104667
+ var uuid11, sha5, common2, intentSchema, stateSchema, invalid6 = () => {
104414
104668
  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
104669
  };
104416
104670
  var init_recurring_recovery = __esm(() => {
@@ -104420,7 +104674,7 @@ var init_recurring_recovery = __esm(() => {
104420
104674
  init_remote_recurring();
104421
104675
  init_recurring_customer();
104422
104676
  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}$/);
104677
+ sha5 = exports_external.string().regex(/^[a-f0-9]{64}$/);
104424
104678
  common2 = exports_external.object({
104425
104679
  contractVersion: exports_external.literal(1),
104426
104680
  apiOrigin: exports_external.string().min(1).max(4096),
@@ -104433,7 +104687,7 @@ var init_recurring_recovery = __esm(() => {
104433
104687
  common2.extend({
104434
104688
  operation: exports_external.literal("activate"),
104435
104689
  draftId: uuid11,
104436
- termsSha256: sha4,
104690
+ termsSha256: sha5,
104437
104691
  approvalDeadline: exports_external.string().datetime(),
104438
104692
  approval: recurringActivationSchema
104439
104693
  }).strict(),
@@ -104441,7 +104695,7 @@ var init_recurring_recovery = __esm(() => {
104441
104695
  ]);
104442
104696
  stateSchema = exports_external.object({
104443
104697
  contractVersion: exports_external.literal(1),
104444
- intentSha256: sha4,
104698
+ intentSha256: sha5,
104445
104699
  phase: exports_external.enum(["prepared", "pending", "observed"]),
104446
104700
  consentId: uuid11.nullable()
104447
104701
  }).strict();
@@ -106985,7 +107239,7 @@ var init_schedule_tools = __esm(() => {
106985
107239
  });
106986
107240
 
106987
107241
  // src/lib/native-storage.ts
106988
- import { createHash as createHash26, createHmac as createHmac3 } from "crypto";
107242
+ import { createHash as createHash27, createHmac as createHmac3 } from "crypto";
106989
107243
  import {
106990
107244
  existsSync as existsSync31,
106991
107245
  mkdirSync as mkdirSync21,
@@ -106994,7 +107248,7 @@ import {
106994
107248
  statSync as statSync18,
106995
107249
  writeFileSync as writeFileSync20
106996
107250
  } from "fs";
106997
- import { dirname as dirname27, join as join52, normalize as normalize4, relative as relative8, sep as sep9 } from "path";
107251
+ import { dirname as dirname27, join as join52, normalize as normalize5, relative as relative8, sep as sep9 } from "path";
106998
107252
  function resolveSkillsNativeStorageConfig(env3 = process.env) {
106999
107253
  assertNoRetiredModeEnvVars(env3, {
107000
107254
  app: SKILLS_ENV_NAMESPACE,
@@ -107062,7 +107316,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
107062
107316
  files.push({
107063
107317
  path: relativePath,
107064
107318
  sizeBytes: bytes.byteLength,
107065
- sha256: createHash26("sha256").update(bytes).digest("hex"),
107319
+ sha256: createHash27("sha256").update(bytes).digest("hex"),
107066
107320
  ...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
107067
107321
  });
107068
107322
  }
@@ -108244,7 +108498,7 @@ var init_remote_account2 = __esm(() => {
108244
108498
  });
108245
108499
 
108246
108500
  // src/cli/commands/runtime-copyfile.ts
108247
- import { createHash as createHash27, randomUUID as randomUUID9 } from "crypto";
108501
+ import { createHash as createHash28, randomUUID as randomUUID9 } from "crypto";
108248
108502
  import { Readable } from "stream";
108249
108503
  import { createGunzip as createGunzip2 } from "zlib";
108250
108504
  import {
@@ -108268,7 +108522,7 @@ function object9(value, code2) {
108268
108522
  return value;
108269
108523
  }
108270
108524
  function hash5(bytes) {
108271
- return createHash27("sha256").update(bytes).digest("hex");
108525
+ return createHash28("sha256").update(bytes).digest("hex");
108272
108526
  }
108273
108527
  function isWithin(parent, child) {
108274
108528
  const rel = relative9(parent, child);
@@ -108419,7 +108673,7 @@ function verifyIntegrity(bytes, integrity) {
108419
108673
  const match = /^sha512-([A-Za-z0-9+/]+={0,2})$/.exec(integrity);
108420
108674
  if (!match)
108421
108675
  throw new Error("REGISTRY_INTEGRITY_UNSUPPORTED");
108422
- const actual = createHash27("sha512").update(bytes).digest("base64");
108676
+ const actual = createHash28("sha512").update(bytes).digest("base64");
108423
108677
  if (actual !== match[1])
108424
108678
  throw new Error("TARBALL_INTEGRITY_MISMATCH");
108425
108679
  }
@@ -109420,7 +109674,7 @@ var exports_runtime = {};
109420
109674
  __export(exports_runtime, {
109421
109675
  registerRuntime: () => registerRuntime
109422
109676
  });
109423
- import { createHash as createHash28, randomUUID as randomUUID10 } from "crypto";
109677
+ import { createHash as createHash29, randomUUID as randomUUID10 } from "crypto";
109424
109678
  import { lstatSync as lstatSync29, mkdirSync as mkdirSync25, readFileSync as readFileSync38, realpathSync as realpathSync15, writeFileSync as writeFileSync24 } from "fs";
109425
109679
  import { basename as basename15, isAbsolute as isAbsolute25, join as join56 } from "path";
109426
109680
  import { createInterface } from "readline";
@@ -109461,7 +109715,7 @@ function registerRuntime(parent) {
109461
109715
  if (!expected)
109462
109716
  throw new Error("Cloud artifact not found");
109463
109717
  const bytes = await client2.download(id2, name);
109464
- if (bytes.length !== expected.byteSize || createHash28("sha256").update(bytes).digest("hex") !== expected.sha256)
109718
+ if (bytes.length !== expected.byteSize || createHash29("sha256").update(bytes).digest("hex") !== expected.sha256)
109465
109719
  throw new Error("Cloud artifact integrity verification failed");
109466
109720
  writeFileSync24(options.output, bytes, { flag: "wx", mode: 384 });
109467
109721
  console.log(JSON.stringify({ path: options.output, sha256: expected.sha256, byteSize: bytes.length }));
@@ -111104,7 +111358,7 @@ var init_portable_snapshot_filter = __esm(() => {
111104
111358
  });
111105
111359
 
111106
111360
  // src/lib/station-snapshot.ts
111107
- import { createHash as createHash29 } from "crypto";
111361
+ import { createHash as createHash30 } from "crypto";
111108
111362
  import {
111109
111363
  copyFileSync as copyFileSync2,
111110
111364
  mkdirSync as mkdirSync26,
@@ -111119,7 +111373,7 @@ function validateStationId(stationId) {
111119
111373
  }
111120
111374
  }
111121
111375
  function sha256File(filePath) {
111122
- return createHash29("sha256").update(readFileSync39(filePath)).digest("hex");
111376
+ return createHash30("sha256").update(readFileSync39(filePath)).digest("hex");
111123
111377
  }
111124
111378
  function scanHome(definition, homesRoot) {
111125
111379
  const homePath = homePathFor(definition, homesRoot);
@@ -111691,8 +111945,8 @@ var init_create_sync_config = __esm(() => {
111691
111945
  });
111692
111946
 
111693
111947
  // src/lib/codex-native-config.ts
111694
- import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
111695
- function isRecord7(value) {
111948
+ import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
111949
+ function isRecord8(value) {
111696
111950
  if (!value || typeof value !== "object")
111697
111951
  return false;
111698
111952
  const prototype = Object.getPrototypeOf(value);
@@ -111713,10 +111967,10 @@ function decimalIdentity(text4) {
111713
111967
  return `${match[1]}${coefficient}e${exponent}`;
111714
111968
  }
111715
111969
  function codexNativeConfigEqual(native, expected) {
111716
- if (isDeepStrictEqual10(native, expected))
111970
+ if (isDeepStrictEqual11(native, expected))
111717
111971
  return true;
111718
111972
  if (typeof expected === "number") {
111719
- if (!Number.isFinite(expected) || !isRecord7(native))
111973
+ if (!Number.isFinite(expected) || !isRecord8(native))
111720
111974
  return false;
111721
111975
  const keys3 = Object.keys(native);
111722
111976
  const value = native[NUMBER_TAG];
@@ -111728,7 +111982,7 @@ function codexNativeConfigEqual(native, expected) {
111728
111982
  if (Array.isArray(native) || Array.isArray(expected)) {
111729
111983
  return Array.isArray(native) && Array.isArray(expected) && native.length === expected.length && native.every((value, index) => codexNativeConfigEqual(value, expected[index]));
111730
111984
  }
111731
- if (!isRecord7(native) || !isRecord7(expected))
111985
+ if (!isRecord8(native) || !isRecord8(expected))
111732
111986
  return false;
111733
111987
  const actual = native, wanted = expected;
111734
111988
  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 +111993,42 @@ var init_codex_native_config = () => {};
111739
111993
  // src/lib/codex-hook-trust-identity.ts
111740
111994
  import { realpathSync as realpathSync16 } from "fs";
111741
111995
  import { dirname as dirname33, isAbsolute as isAbsolute27, join as join59 } from "path";
111742
- import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
111996
+ import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
111743
111997
  function inspectRecordedSkillsCli(command, expected) {
111744
- need5(isAbsolute27(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
111998
+ need6(isAbsolute27(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
111745
111999
  const resolved = realpathSync16(command);
111746
112000
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
111747
112001
  const manifest = snapshot(join59(dirname33(dirname33(resolved)), "package.json"), false, { readOnlyPackage: true });
111748
112002
  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");
112003
+ 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");
112004
+ need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
111751
112005
  const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
111752
- need5(isDeepStrictEqual11(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
112006
+ need6(isDeepStrictEqual12(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
111753
112007
  return { receipt, recheck() {
111754
- need5(realpathSync16(command) === resolved, "SKILLS_COMMAND_CHANGED");
112008
+ need6(realpathSync16(command) === resolved, "SKILLS_COMMAND_CHANGED");
111755
112009
  unchanged2(cli);
111756
112010
  unchanged2(manifest);
111757
112011
  } };
111758
112012
  }
111759
112013
  function bindSkillsCli(command, reviewed) {
111760
112014
  const normal = Bun.which("skills", { PATH: process.env.PATH });
111761
- need5(normal, "SKILLS_COMMAND_UNAVAILABLE");
112015
+ need6(normal, "SKILLS_COMMAND_UNAVAILABLE");
111762
112016
  const resolved = realpathSync16(normal);
111763
112017
  const bound = isAbsolute27(command) ? command : command === "skills" ? normal : undefined;
111764
- need5(bound && realpathSync16(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
112018
+ need6(bound && realpathSync16(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
111765
112019
  const entrypoint = reviewed?.path ?? process.argv[1];
111766
- need5(entrypoint && realpathSync16(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
112020
+ need6(entrypoint && realpathSync16(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
111767
112021
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
111768
112022
  const manifest = snapshot(join59(dirname33(dirname33(resolved)), "package.json"), false, { readOnlyPackage: true });
111769
112023
  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");
112024
+ 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
112025
  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");
112026
+ need6(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
112027
+ need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
111774
112028
  return {
111775
112029
  receipt: { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 },
111776
112030
  recheck() {
111777
- need5(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync16(normal) === resolved && realpathSync16(bound) === resolved && realpathSync16(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
112031
+ need6(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync16(normal) === resolved && realpathSync16(bound) === resolved && realpathSync16(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
111778
112032
  unchanged2(cli);
111779
112033
  unchanged2(manifest);
111780
112034
  }
@@ -111785,19 +112039,19 @@ var init_codex_hook_trust_identity = __esm(() => {
111785
112039
  });
111786
112040
 
111787
112041
  // src/lib/codex-hook-policy-recovery.ts
111788
- import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
112042
+ import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
111789
112043
  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");
112044
+ need6(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
112045
+ need6(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
111792
112046
  const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
111793
112047
  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");
112048
+ need6(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
112049
+ const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual13(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
112050
+ need6(changes.length > 0, "RECONCILE_POLICY_CHANGED");
111797
112051
  const compared = structuredClone(current);
111798
112052
  compared.bridge.discovery.claude.roots = oldDiscovery.roots;
111799
112053
  compared.bridge.discovery.claude.sources = oldDiscovery.sources;
111800
- need5(isDeepStrictEqual12(before2, compared), "RECONCILE_POLICY_CHANGED");
112054
+ need6(isDeepStrictEqual13(before2, compared), "RECONCILE_POLICY_CHANGED");
111801
112055
  verifyAgentDiscovery(newDiscovery);
111802
112056
  return { reason: options.reason, changes };
111803
112057
  }
@@ -111809,21 +112063,21 @@ var init_codex_hook_policy_recovery = __esm(() => {
111809
112063
 
111810
112064
  // src/lib/agent-codex-trust.ts
111811
112065
  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";
112066
+ import { createHash as createHash31, randomUUID as randomUUID11 } from "crypto";
111813
112067
  import { execFileSync } from "child_process";
111814
112068
  import { dirname as dirname34, isAbsolute as isAbsolute28, join as join60, resolve as resolve25 } from "path";
111815
112069
  import { homedir as homedir12 } from "os";
111816
- import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
112070
+ import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
111817
112071
  function verifyReleaseArtifact(proof, skillsCli) {
111818
- need5(isAbsolute28(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
112072
+ need6(isAbsolute28(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
111819
112073
  const tarPath = realpathSync17(proof.packageTarPath);
111820
- need5(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
112074
+ need6(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
111821
112075
  const tarBytes = readFileSync40(tarPath);
111822
- need5(tarBytes.byteLength === proof.packageTarBytes && createHash30("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
112076
+ need6(tarBytes.byteLength === proof.packageTarBytes && createHash31("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
111823
112077
  const packageRoot = dirname34(dirname34(realpathSync17(skillsCli.receipt.path)));
111824
112078
  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");
112079
+ need6(createHash31("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
112080
+ need6(createHash31("sha256").update(readFileSync40(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
111827
112081
  const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync40(skillsCli.receipt.path)]];
111828
112082
  for (const [member, expected] of members2) {
111829
112083
  let actual;
@@ -111832,7 +112086,7 @@ function verifyReleaseArtifact(proof, skillsCli) {
111832
112086
  } catch {
111833
112087
  throw new Error("RECONCILE_RELEASE_ARTIFACT_MEMBER_MISSING");
111834
112088
  }
111835
- need5(Buffer.compare(actual, expected) === 0, "RECONCILE_RELEASE_ARTIFACT_MEMBER_CHANGED");
112089
+ need6(Buffer.compare(actual, expected) === 0, "RECONCILE_RELEASE_ARTIFACT_MEMBER_CHANGED");
111836
112090
  }
111837
112091
  }
111838
112092
  async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc) {
@@ -111840,48 +112094,48 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111840
112094
  try {
111841
112095
  const home = resolve25(options.home ?? homedir12()), dataDir3 = resolve25(options.dataDir ?? getDataDirReadOnly());
111842
112096
  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");
112097
+ need6(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
111844
112098
  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");
112099
+ need6(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
112100
+ need6(!lstatSync31(join60(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
112101
+ need6(lstatSync31(join60(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
111848
112102
  const stoppedFile = snapshot(join60(journal, "stopped.json"), true);
111849
112103
  const intentFile = snapshot(join60(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
111850
112104
  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
112105
  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");
112106
+ 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
112107
  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
112108
  const admitted = intent.admitted ?? intent.hooks;
111855
112109
  const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
111856
112110
  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");
112111
+ need6(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
112112
+ need6(isDeepStrictEqual14(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
112113
+ need6(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
111860
112114
  const policyCurrent = snapshot(join60(dataDir3, "agent-policy.json"), true);
111861
112115
  const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
111862
112116
  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");
112117
+ need6(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
112118
+ need6(!claudeRecovery || !additionsRecovery || claudeRecovery.reviewedPlanDigest === additionsRecovery.reviewedPlanDigest, "RECONCILE_RECOVERY_MODE_CONFLICT");
112119
+ need6(recovery?.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(recovery.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
111866
112120
  const policyChange = claudeRecovery ? reviewedClaudeDiscoveryChange(policyBefore.text, policyCurrent.text, claudeRecovery) : undefined;
111867
112121
  let supersededBinding = false;
111868
112122
  if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
111869
- need5(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
112123
+ need6(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
111870
112124
  const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
111871
- need5(isDeepStrictEqual13(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
112125
+ need6(isDeepStrictEqual14(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
111872
112126
  supersededBinding = true;
111873
112127
  }
111874
112128
  if (supersededBinding || recovery) {
111875
- need5(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
112129
+ need6(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
111876
112130
  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");
112131
+ 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
112132
  }
111879
112133
  const currentConfig = snapshot(intent.configPath, true);
111880
112134
  const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
111881
112135
  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");
112136
+ need6(resolve25(intent.configPath) === resolve25(join60(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
111883
112137
  const nativeConfigPath = intent.nativeConfigPath ?? intent.configPath;
111884
- need5([join60(home, ".codex/config.toml"), join60(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
112138
+ need6([join60(home, ".codex/config.toml"), join60(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
111885
112139
  const codexHome = nativeConfigPath !== intent.configPath ? undefined : dirname34(nativeConfigPath);
111886
112140
  const hooksCurrent = snapshot(hooksPath);
111887
112141
  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 +112143,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111889
112143
  const managedKeys = managedHooks.map((h) => h.key);
111890
112144
  const witnessSame = codexTrustReconcileWitness(configBefore.text, managedKeys) === codexTrustReconcileWitness(currentConfig.text, managedKeys);
111891
112145
  const unmanagedSame = codexTrustUnmanagedSemantic(configBefore.text, managedKeys) === codexTrustUnmanagedSemantic(currentConfig.text, managedKeys);
111892
- need5(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
112146
+ need6(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
111893
112147
  const before2 = structure3(configBefore.text), current = structure3(currentConfig.text), expectedConfig = structuredClone(before2);
111894
112148
  expectedConfig.hooks ??= {};
111895
112149
  expectedConfig.hooks.state ??= {};
@@ -111901,10 +112155,10 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111901
112155
  if (supersededBinding) {
111902
112156
  for (const hook of intent.hooks) {
111903
112157
  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");
112158
+ need6(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
111905
112159
  }
111906
112160
  } else
111907
- need5(isDeepStrictEqual13(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
112161
+ need6(isDeepStrictEqual14(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
111908
112162
  const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
111909
112163
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
111910
112164
  const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
@@ -111913,29 +112167,29 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111913
112167
  const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
111914
112168
  if (supersededBinding)
111915
112169
  verifyReleaseArtifact(options.releaseProof, skillsCli);
111916
- const skillsBindingChanged = !isDeepStrictEqual13(skillsCli.receipt, intent.skillsCli);
111917
- need5(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
112170
+ const skillsBindingChanged = !isDeepStrictEqual14(skillsCli.receipt, intent.skillsCli);
112171
+ need6(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
111918
112172
  if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
111919
- need5(supersededBinding, "RECONCILE_HOOKS_CHANGED");
112173
+ need6(supersededBinding, "RECONCILE_HOOKS_CHANGED");
111920
112174
  const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
111921
112175
  for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
111922
112176
  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");
112177
+ need6(isDeepStrictEqual14(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
111924
112178
  }
111925
112179
  }
111926
112180
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
111927
- need5(rpc.version === intent.nativeVersion, "RECONCILE_NATIVE_VERSION_CHANGED");
112181
+ need6(rpc.version === intent.nativeVersion, "RECONCILE_NATIVE_VERSION_CHANGED");
111928
112182
  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");
112183
+ 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
112184
  const nativeHooks = discovered.data[0].hooks;
111931
112185
  const recordedNativeHooks = intent.nativeHooks;
111932
112186
  if (recordedNativeHooks)
111933
- need5(nativeHooks.length === recordedNativeHooks.length + (additions?.hooks.length ?? 0), "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
112187
+ need6(nativeHooks.length === recordedNativeHooks.length + (additions?.hooks.length ?? 0), "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
111934
112188
  const plannedKeys = new Set(intent.hooks.map((hook) => hook.key));
111935
112189
  let nativeTrustPending = false;
111936
112190
  for (const expected of [...recordedNativeHooks ?? [], ...additions?.hooks ?? []]) {
111937
112191
  const matches2 = nativeHooks.filter((hook) => hook.key === expected.key);
111938
- need5(matches2.length === 1, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
112192
+ need6(matches2.length === 1, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
111939
112193
  const actual = safeNativeHook(matches2[0]);
111940
112194
  const stable = (hook) => {
111941
112195
  const { enabled, trustStatus, ...identity5 } = hook;
@@ -111943,35 +112197,35 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111943
112197
  delete identity5.command;
111944
112198
  return identity5;
111945
112199
  };
111946
- need5(isDeepStrictEqual13(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
112200
+ need6(isDeepStrictEqual14(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
111947
112201
  if (!plannedKeys.has(expected.key))
111948
- need5(isDeepStrictEqual13(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
112202
+ need6(isDeepStrictEqual14(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
111949
112203
  }
111950
112204
  for (const wanted of intent.hooks) {
111951
112205
  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");
112206
+ need6(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
111953
112207
  const h = matches2[0];
111954
112208
  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");
112209
+ 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
112210
  if (!trusted)
111957
112211
  nativeTrustPending = true;
111958
112212
  if (supersededBinding) {
111959
112213
  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");
112214
+ need6(h.command === renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, nativeToCliEvent[wanted.event] ?? ""), "RECONCILE_BINDING_HOOK_CHANGED");
111961
112215
  }
111962
112216
  }
111963
112217
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
111964
112218
  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");
112219
+ need6(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
111966
112220
  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");
112221
+ 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
112222
  const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
111969
112223
  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");
112224
+ need6(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
111971
112225
  if (recovery) {
111972
112226
  for (const response of [config2, finalConfig]) {
111973
112227
  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");
112228
+ 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
112229
  }
111976
112230
  recoveryCli.recheck();
111977
112231
  verifyReleaseArtifact(options.releaseProof, recoveryCli);
@@ -111992,7 +112246,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111992
112246
  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
112247
  const recoveryPlanDigest = recoveryPlan ? makePlanDigest(recoveryPlan) : undefined;
111994
112248
  if (recovery?.reviewedPlanDigest !== undefined)
111995
- need5(recovery.reviewedPlanDigest === recoveryPlanDigest, "RECONCILE_RECOVERY_PLAN_CHANGED");
112249
+ need6(recovery.reviewedPlanDigest === recoveryPlanDigest, "RECONCILE_RECOVERY_PLAN_CHANGED");
111996
112250
  const preview2 = !!recovery && recovery.reviewedPlanDigest === undefined;
111997
112251
  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
112252
  if (preview2)
@@ -112015,7 +112269,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112015
112269
  const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
112016
112270
  const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
112017
112271
  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");
112272
+ need6(options.codexHome === undefined || isAbsolute28(options.codexHome) && [join60(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
112019
112273
  const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
112020
112274
  const nativeConfigPath = join60(codexHome ?? join60(home, ".codex"), "config.toml");
112021
112275
  const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
@@ -112023,38 +112277,38 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112023
112277
  for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
112024
112278
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
112025
112279
  const groups = declarations[event];
112026
- need5(Array.isArray(groups), "DECLARATION_CHANGED");
112280
+ need6(Array.isArray(groups), "DECLARATION_CHANGED");
112027
112281
  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");
112282
+ need6(matches2.length === 1 && isDeepStrictEqual14(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
112029
112283
  expected.push({ event: nativeEvent, key: `${join60(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
112030
112284
  }
112031
112285
  codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
112032
112286
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
112033
- need5(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
112287
+ need6(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
112034
112288
  const list2 = async () => {
112035
112289
  const response = await rpc.request("hooks/list", { cwds: [home] });
112036
112290
  const nativeRoots = [...new Set([physicalRoot, join60(home, ".codex")])];
112037
112291
  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
112292
  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");
112293
+ 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
112294
  return response.data[0].hooks;
112041
112295
  };
112042
112296
  const admit = (hooks) => expected.map((wanted) => {
112043
112297
  const canonicalKey = wanted.key.replace(join60(home, ".codex/hooks.json"), hooksPath);
112044
112298
  const matches2 = hooks.filter((h2) => h2.key === wanted.key || h2.key === canonicalKey);
112045
- need5(matches2.length === 1, "AMBIGUOUS_IDENTITY");
112299
+ need6(matches2.length === 1, "AMBIGUOUS_IDENTITY");
112046
112300
  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");
112301
+ 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");
112302
+ need6(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
112303
+ need6(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
112050
112304
  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
112305
  });
112052
112306
  const discovered = await list2(), admitted = admit(discovered);
112053
112307
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
112054
112308
  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");
112309
+ need6(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
112310
+ need6(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
112311
+ 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
112312
  const keys3 = admitted.map((h) => h.key), planned = admitted.filter((h) => !h.enabled || h.trustStatus !== "trusted");
112059
112313
  const preservationText = codexTrustTextWitness(configFile.text, keys3);
112060
112314
  const checkInputs = () => {
@@ -112069,16 +112323,16 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112069
112323
  const planDigest = makePlanDigest(digestInput);
112070
112324
  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
112325
  if (options.apply)
112072
- need5(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
112326
+ need6(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
112073
112327
  const parent = join60(dataDir3, "native-hook-trust");
112074
112328
  const st = lstatSync31(parent, { throwIfNoEntry: false });
112075
112329
  if (st) {
112076
- need5(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
112330
+ need6(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
112077
112331
  const priorJournals = readdirSync23(parent);
112078
- need5(priorJournals.length < 1000, "JOURNAL_BOUND");
112332
+ need6(priorJournals.length < 1000, "JOURNAL_BOUND");
112079
112333
  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");
112334
+ need6(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
112335
+ need6(lstatSync31(join60(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
112082
112336
  }
112083
112337
  }
112084
112338
  if (!options.apply || !planned.length)
@@ -112091,7 +112345,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112091
112345
  save(join60(journal, "hooks.before.json"), hooksFile.bytes);
112092
112346
  save(join60(journal, "policy.before.json"), policyFile.bytes);
112093
112347
  save(join60(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
112094
- need5(isDeepStrictEqual13(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
112348
+ need6(isDeepStrictEqual14(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
112095
112349
  checkInputs();
112096
112350
  let result2;
112097
112351
  try {
@@ -112099,22 +112353,22 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112099
112353
  } catch {
112100
112354
  throw new Error("CODEX_HOOK_TRUST_NATIVE_WRITE_FAILED: reconcile the private journal before retrying");
112101
112355
  }
112102
- need5(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
112356
+ need6(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
112103
112357
  const after2 = snapshot(configPath, true), expectedConfig = structuredClone(original);
112104
112358
  expectedConfig.hooks ??= {};
112105
112359
  expectedConfig.hooks.state ??= {};
112106
112360
  for (const h of planned)
112107
112361
  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");
112362
+ need6(isDeepStrictEqual14(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
112109
112363
  const savedConfig = snapshot(join60(journal, "config.before.toml"), true);
112110
- need5(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
112364
+ need6(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
112111
112365
  const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
112112
112366
  unchanged2(policyFile);
112113
112367
  unchanged2(hooksFile);
112114
112368
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
112115
112369
  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");
112370
+ 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");
112371
+ need6(isDeepStrictEqual14(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
112118
112372
  unchanged2(after2);
112119
112373
  unchanged2(savedConfig);
112120
112374
  unchanged2(hooksFile);
@@ -112137,7 +112391,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112137
112391
  }
112138
112392
  }
112139
112393
  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) => {
112394
+ `, 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
112395
  const copy = structuredClone(value);
112142
112396
  if (copy?.bridge?.commands && Object.hasOwn(copy.bridge.commands, "codex"))
112143
112397
  copy.bridge.commands.codex = "<reviewed-codex-binding>";
@@ -112277,7 +112531,7 @@ __export(exports_agent_integration, {
112277
112531
  registerAgentIntegration: () => registerAgentIntegration
112278
112532
  });
112279
112533
  import { existsSync as existsSync35, lstatSync as lstatSync32, readFileSync as readFileSync41, writeFileSync as writeFileSync26 } from "fs";
112280
- import { createHash as createHash31 } from "crypto";
112534
+ import { createHash as createHash32 } from "crypto";
112281
112535
  import { homedir as homedir13 } from "os";
112282
112536
  import { isAbsolute as isAbsolute29 } from "path";
112283
112537
  function pinnedHookProfile(input3, configuredProfile) {
@@ -112375,7 +112629,7 @@ function registerAgentIntegration(parent) {
112375
112629
  skillCount: catalog.skills.length,
112376
112630
  output: options.output,
112377
112631
  bytes: Buffer.byteLength(bytes),
112378
- sha256: createHash31("sha256").update(bytes).digest("hex")
112632
+ sha256: createHash32("sha256").update(bytes).digest("hex")
112379
112633
  };
112380
112634
  await writeCliOutput(options.json ? JSON.stringify(receipt) : `Captured ${receipt.skillCount} native Codex skill(s) in ${receipt.output}.`);
112381
112635
  } catch (error61) {
@@ -112384,10 +112638,10 @@ function registerAgentIntegration(parent) {
112384
112638
  process.exitCode = 1;
112385
112639
  }
112386
112640
  });
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;
112641
+ 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) => {
112642
+ 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
112643
  if (!capture2)
112390
- throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
112644
+ 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
112645
  await writeCliOutput(JSON.stringify(capture2(options.path), null, 2));
112392
112646
  });
112393
112647
  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 +112660,7 @@ function registerAgentIntegration(parent) {
112406
112660
  hook.command("agents").option("--json", "Output the adapter capability inventory", false).description("Show maintained native adapters and explicit coverage limits").action(async () => {
112407
112661
  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
112662
  });
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) => {
112663
+ 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
112664
  try {
112411
112665
  const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync41(options.discoveryInputs, "utf8")) : undefined;
112412
112666
  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 +113143,7 @@ var init_grants = __esm(() => {
112889
113143
  });
112890
113144
 
112891
113145
  // src/lib/station-hydrate.ts
112892
- import { createHash as createHash32 } from "crypto";
113146
+ import { createHash as createHash33 } from "crypto";
112893
113147
  import {
112894
113148
  copyFileSync as copyFileSync3,
112895
113149
  mkdirSync as mkdirSync28,
@@ -113092,7 +113346,7 @@ function skillSha256(skill) {
113092
113346
  return sha256File(skill.files[0].winner.fullPath);
113093
113347
  }
113094
113348
  const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
113095
- return createHash32("sha256").update(joined.sort().join(`
113349
+ return createHash33("sha256").update(joined.sort().join(`
113096
113350
  `)).digest("hex");
113097
113351
  }
113098
113352
  function writeStationHydration(options) {
@@ -113249,7 +113503,7 @@ var init_hydrate = __esm(() => {
113249
113503
  });
113250
113504
 
113251
113505
  // src/lib/prepare-skill.ts
113252
- import { createHash as createHash33, randomUUID as randomUUID12 } from "crypto";
113506
+ import { createHash as createHash34, randomUUID as randomUUID12 } from "crypto";
113253
113507
  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
113508
  import { tmpdir as tmpdir2 } from "os";
113255
113509
  import { dirname as dirname36, isAbsolute as isAbsolute30, join as join62, relative as relative11, resolve as resolve27, sep as sep14 } from "path";
@@ -113266,7 +113520,7 @@ function prepareSkill(name, options) {
113266
113520
  let manifest;
113267
113521
  try {
113268
113522
  const parsed = JSON.parse(manifestFile.bytes.toString("utf8"));
113269
- if (!isRecord8(parsed))
113523
+ if (!isRecord9(parsed))
113270
113524
  throw new Error("not an object");
113271
113525
  manifest = parsed;
113272
113526
  } catch {
@@ -113288,7 +113542,7 @@ function prepareSkill(name, options) {
113288
113542
  if (documentKind !== undefined && documentKind !== kind) {
113289
113543
  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
113544
  }
113291
- if (manifest.provenance !== undefined && !isRecord8(manifest.provenance))
113545
+ if (manifest.provenance !== undefined && !isRecord9(manifest.provenance))
113292
113546
  throw new Error("skill.json provenance must be an object.");
113293
113547
  const provenance = manifest.provenance;
113294
113548
  const candidate2 = { ...manifest, version: options.version, kind, provenance: { ...provenance } };
@@ -113353,7 +113607,7 @@ function escapedRelativePath(path) {
113353
113607
  return JSON.stringify(bounded);
113354
113608
  }
113355
113609
  function validateRuntimeEntrypoint(candidate2, root2) {
113356
- if (candidate2.kind !== "executable" || !isRecord8(candidate2.runtime))
113610
+ if (candidate2.kind !== "executable" || !isRecord9(candidate2.runtime))
113357
113611
  return;
113358
113612
  const entry = candidate2.runtime.entrypoint;
113359
113613
  if (typeof entry !== "string")
@@ -113363,7 +113617,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
113363
113617
  throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
113364
113618
  }
113365
113619
  }
113366
- function isRecord8(value) {
113620
+ function isRecord9(value) {
113367
113621
  return typeof value === "object" && value !== null && !Array.isArray(value);
113368
113622
  }
113369
113623
  function validateRawCandidate(candidate2) {
@@ -113388,7 +113642,7 @@ function validateRawCandidate(candidate2) {
113388
113642
  if (!Array.isArray(items))
113389
113643
  throw new Error(`skill.json ${field2} must be an array.`);
113390
113644
  for (const item of items) {
113391
- if (!isRecord8(item) || typeof item.name !== "string" || !item.name.trim())
113645
+ if (!isRecord9(item) || typeof item.name !== "string" || !item.name.trim())
113392
113646
  throw new Error(`Invalid skill.json ${field2} name.`);
113393
113647
  if (field2 === "inputs" && (typeof item.type !== "string" || !item.type.trim() || item.required !== undefined && typeof item.required !== "boolean"))
113394
113648
  throw new Error("Invalid skill.json input type or required flag.");
@@ -113407,7 +113661,7 @@ function validateRawCandidate(candidate2) {
113407
113661
  }
113408
113662
  }
113409
113663
  function validateRuntimeEntrypointCompatibility(candidate2) {
113410
- if (candidate2.kind !== "executable" || !isRecord8(candidate2.runtime))
113664
+ if (candidate2.kind !== "executable" || !isRecord9(candidate2.runtime))
113411
113665
  return;
113412
113666
  const runtime = candidate2.runtime.runtime;
113413
113667
  const entrypoint = candidate2.runtime.entrypoint;
@@ -113448,7 +113702,7 @@ function snapshot2(root2) {
113448
113702
  if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
113449
113703
  throw new Error("Skill root must be a real directory, not a symlink.");
113450
113704
  const files = [], directories = [];
113451
- const hash6 = createHash33("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
113705
+ const hash6 = createHash34("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
113452
113706
  let count = 0, bytes = 0;
113453
113707
  const walk2 = (relative12) => {
113454
113708
  for (const name of readdirSync25(join62(root2, relative12)).sort()) {
@@ -114734,7 +114988,7 @@ async function apiRequest(path, options, instance) {
114734
114988
  const origin = instance ?? getApiUrl(`${(options?.method || "GET").toUpperCase()} ${path}`);
114735
114989
  return new RemoteSkillsAuthClient(origin).request(path, options);
114736
114990
  }
114737
- function isRecord9(value) {
114991
+ function isRecord10(value) {
114738
114992
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
114739
114993
  }
114740
114994
  function commandErrorPayload(err, fallback) {
@@ -114748,11 +115002,11 @@ function commandErrorPayload(err, fallback) {
114748
115002
  ...err.apiUrl ? { apiUrl: err.apiUrl } : {}
114749
115003
  };
114750
115004
  }
114751
- const code2 = isRecord9(err) && typeof err.code === "string" ? err.code : undefined;
115005
+ const code2 = isRecord10(err) && typeof err.code === "string" ? err.code : undefined;
114752
115006
  return {
114753
115007
  error: err?.message || fallback,
114754
115008
  ...code2 ? { code: code2 } : {},
114755
- ...isRecord9(err) && Array.isArray(err.next) ? { next: err.next } : {}
115009
+ ...isRecord10(err) && Array.isArray(err.next) ? { next: err.next } : {}
114756
115010
  };
114757
115011
  }
114758
115012
  function writeCommandError(err, fallback, json3) {
@@ -114777,7 +115031,7 @@ function stringField2(value) {
114777
115031
  return typeof value === "string" && value.length > 0 ? value : undefined;
114778
115032
  }
114779
115033
  function recordField(value) {
114780
- return isRecord9(value) ? value : undefined;
115034
+ return isRecord10(value) ? value : undefined;
114781
115035
  }
114782
115036
  function identityApiKey(live) {
114783
115037
  const root2 = recordField(live);
@@ -115250,7 +115504,7 @@ async function runWhoami(options) {
115250
115504
  } catch {}
115251
115505
  payload.permissions = { publish: access?.permissions?.publish ?? null, profilesWrite: access?.permissions?.profilesWrite ?? null };
115252
115506
  const apiKey = identityApiKey(res);
115253
- if (access?.scopes && (apiKey === undefined || isRecord9(apiKey) && !Object.hasOwn(apiKey, "scopes"))) {
115507
+ if (access?.scopes && (apiKey === undefined || isRecord10(apiKey) && !Object.hasOwn(apiKey, "scopes"))) {
115254
115508
  payload.scopes = access.scopes;
115255
115509
  }
115256
115510
  if (options.json) {