@hasna/skills 0.10.41 → 0.10.42

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.41",
36871
+ version: "0.10.42",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -40019,8 +40019,8 @@ function assertAgentPolicyCollections(policy) {
40019
40019
  text(source.path);
40020
40020
  requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
40021
40021
  if (source.hashMode !== undefined)
40022
- 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", "codex-settings-v3"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
40023
- if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3")
40022
+ 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", "codex-settings-v3", "codex-settings-v4"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
40023
+ if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
40024
40024
  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");
40025
40025
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
40026
40026
  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");
@@ -52223,6 +52223,7 @@ var init_codex_mcp_discovery_projection = () => {};
52223
52223
 
52224
52224
  // src/lib/codex-settings-witness.ts
52225
52225
  import { createHash as createHash12 } from "crypto";
52226
+ import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
52226
52227
  function need4(value) {
52227
52228
  if (!value)
52228
52229
  throw new Error("Invalid Codex settings witness");
@@ -52328,7 +52329,7 @@ function disablesOneSkill(entry) {
52328
52329
  return selector.length === 1 && typeof entry[selector[0]] === "string" && entry[selector[0]].length > 0;
52329
52330
  }
52330
52331
  function inference(target, version) {
52331
- const keys2 = version === 3 ? [...INFERENCE, "service_tier", "plan_mode_reasoning_effort", "personality"] : INFERENCE;
52332
+ const keys2 = version >= 3 ? [...INFERENCE, "service_tier", "plan_mode_reasoning_effort", "personality"] : INFERENCE;
52332
52333
  for (const key of keys2)
52333
52334
  if (Object.hasOwn(target, key)) {
52334
52335
  const value = target[key];
@@ -52336,7 +52337,7 @@ function inference(target, version) {
52336
52337
  need4(typeof value === "string" && MODEL.test(value));
52337
52338
  else if (key === "personality")
52338
52339
  need4(typeof value === "string" && ["none", "friendly", "pragmatic"].includes(value));
52339
- else if (version === 3 && key !== "model_verbosity") {
52340
+ else if (version >= 3 && key !== "model_verbosity") {
52340
52341
  need4(typeof value === "string" && value.length <= 128 && !/[\x00-\x1f\x7f]/.test(value));
52341
52342
  if (key !== "service_tier")
52342
52343
  need4(value.length > 0);
@@ -52345,6 +52346,115 @@ function inference(target, version) {
52345
52346
  delete target[key];
52346
52347
  }
52347
52348
  }
52349
+ function projectModelAvailabilityNux(config, text2) {
52350
+ const tui = config.tui, counts = isRecord3(tui) ? tui.model_availability_nux : undefined;
52351
+ if (isRecord3(tui) && !Object.keys(tui).length) {
52352
+ delete config.tui;
52353
+ return { config, numericSource: text2 };
52354
+ }
52355
+ if (!isRecord3(counts) || Object.keys(counts).length > 256 || !Object.values(counts).every((value) => typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 4294967295))
52356
+ return { config, numericSource: text2 };
52357
+ const expected = structuredClone(config);
52358
+ delete expected.tui.model_availability_nux;
52359
+ const stripEmptyTui = (value) => {
52360
+ if (isRecord3(value.tui) && !Object.keys(value.tui).length)
52361
+ delete value.tui;
52362
+ };
52363
+ stripEmptyTui(expected);
52364
+ const headers = [];
52365
+ const spans = [];
52366
+ const integer = /^(?:\+?(?:0|[1-9](?:_?\d)*)|0x[0-9a-fA-F](?:_?[0-9a-fA-F])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*)$/;
52367
+ const counterIntegers = (span) => {
52368
+ let values2 = 0;
52369
+ for (let at2 = 0;at2 < span.length; ) {
52370
+ const char = span[at2];
52371
+ if (char === "#") {
52372
+ while (at2 < span.length && span[at2] !== `
52373
+ `)
52374
+ at2++;
52375
+ continue;
52376
+ }
52377
+ if (char === '"' || char === "'") {
52378
+ const quote = char;
52379
+ at2++;
52380
+ while (at2 < span.length) {
52381
+ if (quote === '"' && span[at2] === "\\") {
52382
+ at2 += 2;
52383
+ continue;
52384
+ }
52385
+ if (span[at2++] === quote)
52386
+ break;
52387
+ }
52388
+ continue;
52389
+ }
52390
+ if (char !== "=") {
52391
+ at2++;
52392
+ continue;
52393
+ }
52394
+ at2++;
52395
+ while (at2 < span.length && /\s/.test(span[at2]))
52396
+ at2++;
52397
+ if (span[at2] === "{") {
52398
+ at2++;
52399
+ continue;
52400
+ }
52401
+ const start = at2;
52402
+ while (at2 < span.length && !/[\s,\]{}#]/.test(span[at2]))
52403
+ at2++;
52404
+ if (!integer.test(span.slice(start, at2)))
52405
+ return false;
52406
+ values2++;
52407
+ }
52408
+ return values2 === Object.keys(counts).length;
52409
+ };
52410
+ let attempts = 0;
52411
+ const realPrefix = (end) => {
52412
+ if (++attempts > 256)
52413
+ return false;
52414
+ try {
52415
+ Bun.TOML.parse(text2.slice(0, end));
52416
+ return true;
52417
+ } catch {
52418
+ return false;
52419
+ }
52420
+ };
52421
+ for (const match of text2.matchAll(/^[ \t]*\[[^\r\n]+\][ \t]*(?:#[^\r\n]*)?(?:\r?\n|$)/gm)) {
52422
+ const start = match.index, end = start + match[0].length;
52423
+ if (realPrefix(end))
52424
+ headers.push({ start, end });
52425
+ }
52426
+ for (let at2 = 0;at2 < headers.length; at2++) {
52427
+ const header = headers[at2];
52428
+ let parsed;
52429
+ try {
52430
+ parsed = Bun.TOML.parse(text2.slice(header.start, header.end));
52431
+ } catch {
52432
+ continue;
52433
+ }
52434
+ if (isRecord3(parsed.tui) && isRecord3(parsed.tui.model_availability_nux) && !Object.keys(parsed.tui.model_availability_nux).length && Object.keys(parsed).length === 1 && Object.keys(parsed.tui).length === 1)
52435
+ spans.push({ start: header.start, end: headers[at2 + 1]?.start ?? text2.length });
52436
+ }
52437
+ for (const match of text2.matchAll(/^[ \t]*(?:(?:tui|"tui"|'tui')[ \t]*\.[ \t]*)?(?:model_availability_nux|"model_availability_nux"|'model_availability_nux')[ \t]*=[ \t]*\{[^\r\n]*(?:\r?\n|$)/gm)) {
52438
+ const start = match.index, end = start + match[0].length;
52439
+ if (realPrefix(end))
52440
+ spans.push({ start, end });
52441
+ }
52442
+ for (const { start, end } of spans) {
52443
+ if (!counterIntegers(text2.slice(start, end)))
52444
+ continue;
52445
+ const remaining = text2.slice(0, start) + text2.slice(end);
52446
+ let parsed;
52447
+ try {
52448
+ parsed = Bun.TOML.parse(remaining);
52449
+ } catch {
52450
+ continue;
52451
+ }
52452
+ stripEmptyTui(parsed);
52453
+ if (isDeepStrictEqual4(parsed, expected))
52454
+ return { config: expected, numericSource: remaining };
52455
+ }
52456
+ return { config, numericSource: text2 };
52457
+ }
52348
52458
  function settingsDigest2(text2, version = 2) {
52349
52459
  let config;
52350
52460
  try {
@@ -52353,7 +52463,8 @@ function settingsDigest2(text2, version = 2) {
52353
52463
  throw new Error("Invalid Codex settings witness");
52354
52464
  }
52355
52465
  need4(isRecord3(config));
52356
- const projected = version === 3 ? projectRegularCodexMcp(config, text2) : { config, numericSource: text2 };
52466
+ const mcp = version >= 3 ? projectRegularCodexMcp(config, text2) : { config, numericSource: text2 };
52467
+ const projected = version === 4 ? projectModelAvailabilityNux(mcp.config, mcp.numericSource) : mcp;
52357
52468
  normalize3(projected.config, version);
52358
52469
  return sha2(`hasna.skills.codex-settings.v${version}\x00${JSON.stringify([canonical4(projected.config), numericTokens2(projected.numericSource)])}`);
52359
52470
  }
@@ -52398,6 +52509,25 @@ function upgradeCodexSettingsWitnessV3(previous, reviewedSettingsPath) {
52398
52509
  throw new Error("Codex settings outside the reviewed V3 contract changed; explicit discovery review required");
52399
52510
  return { path: previous.path, hashMode: "codex-settings-v3", sha256: sha2562 };
52400
52511
  }
52512
+ function hashCodexSettingsReplacementV4(text2, budget = { remaining: 256 * 1024 * 1024 }) {
52513
+ need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
52514
+ budget.remaining -= Buffer.byteLength(text2);
52515
+ return settingsDigest2(text2, 4);
52516
+ }
52517
+ function captureCodexSettingsV4(path, budget = { remaining: 256 * 1024 * 1024 }) {
52518
+ return { path, hashMode: "codex-settings-v4", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget, "config.toml"), 4) };
52519
+ }
52520
+ function upgradeCodexSettingsWitnessV4(previous, reviewedSettingsPath) {
52521
+ need4(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || ["bytes", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3"].includes(previous.hashMode)) && /^[a-f0-9]{64}$/.test(previous.sha256));
52522
+ const budget = { remaining: 2 * 1024 * 1024 };
52523
+ const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
52524
+ const original = previous.hashMode === "codex-settings-v3" ? settingsDigest2(before2, 3) : previous.hashMode === "codex-settings-v2" ? settingsDigest2(before2, 2) : previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before2) : sha2(before2);
52525
+ need4(original === previous.sha256);
52526
+ const sha2562 = settingsDigest2(current, 4);
52527
+ if (settingsDigest2(before2, 4) !== sha2562)
52528
+ throw new Error("Codex settings outside the reviewed V4 contract changed; explicit discovery review required");
52529
+ return { path: previous.path, hashMode: "codex-settings-v4", sha256: sha2562 };
52530
+ }
52401
52531
  var sha2 = (text2) => createHash12("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
52402
52532
  var init_codex_settings_witness = __esm(() => {
52403
52533
  init_codex_settings_witness_v1();
@@ -52540,7 +52670,7 @@ var init_agent_bridge = __esm(() => {
52540
52670
  });
52541
52671
 
52542
52672
  // src/lib/agent-codex.ts
52543
- import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
52673
+ import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
52544
52674
  function splitTopLevel(value, delimiter2) {
52545
52675
  const result2 = [];
52546
52676
  let start = 0, square = 0, curly = 0, quote = null, escaped = false;
@@ -52669,7 +52799,7 @@ function normalizeCodexInlinePathConfig(text2) {
52669
52799
  const expectedWithoutConfig = structuredClone(before2);
52670
52800
  delete expectedWithoutConfig.skills.config;
52671
52801
  try {
52672
- if (isDeepStrictEqual4(Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, "")), expectedWithoutConfig))
52802
+ if (isDeepStrictEqual5(Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, "")), expectedWithoutConfig))
52673
52803
  return text2;
52674
52804
  } catch {}
52675
52805
  const matches2 = [];
@@ -52722,7 +52852,7 @@ function normalizeCodexInlinePathConfig(text2) {
52722
52852
  try {
52723
52853
  const after2 = Bun.TOML.parse(candidate);
52724
52854
  const expected = structuredClone(before2);
52725
- if (isDeepStrictEqual4(after2, expected))
52855
+ if (isDeepStrictEqual5(after2, expected))
52726
52856
  matches2.push(candidate);
52727
52857
  } catch {}
52728
52858
  }
@@ -52738,11 +52868,11 @@ function assertCodexPathConfigEditable(text2) {
52738
52868
  delete expected.skills.config;
52739
52869
  try {
52740
52870
  const withoutSections = Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
52741
- if (isDeepStrictEqual4(withoutSections, expected))
52871
+ if (isDeepStrictEqual5(withoutSections, expected))
52742
52872
  return;
52743
52873
  const normalized = normalizeCodexInlinePathConfig(text2);
52744
52874
  const withoutNormalizedSections = Bun.TOML.parse(normalized.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
52745
- if (isDeepStrictEqual4(withoutNormalizedSections, expected))
52875
+ if (isDeepStrictEqual5(withoutNormalizedSections, expected))
52746
52876
  return;
52747
52877
  } catch {}
52748
52878
  throw codexPathConfigRefusal();
@@ -52780,7 +52910,7 @@ function disableCodexBundledSkills(text2) {
52780
52910
  const candidates = new Set;
52781
52911
  const consider = (candidate) => {
52782
52912
  try {
52783
- if (isDeepStrictEqual4(Bun.TOML.parse(candidate), expected))
52913
+ if (isDeepStrictEqual5(Bun.TOML.parse(candidate), expected))
52784
52914
  candidates.add(candidate);
52785
52915
  } catch {}
52786
52916
  };
@@ -52981,7 +53111,7 @@ var init_codex_hook_trust_files = () => {};
52981
53111
 
52982
53112
  // src/lib/agent-integration.ts
52983
53113
  import { createHash as createHash15, randomUUID as randomUUID5 } from "crypto";
52984
- import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
53114
+ import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
52985
53115
  import { existsSync as existsSync13, lstatSync as lstatSync18, statSync as statSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync14, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync8, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync5, unlinkSync as unlinkSync3, chmodSync, openSync as openSync9, closeSync as closeSync9, fsyncSync as fsyncSync3, fstatSync as fstatSync9, readSync as readSync7, constants as constants10, linkSync as linkSync2 } from "fs";
52986
53116
  import { dirname as dirname13, join as join26, resolve as resolve13, relative as relative6, isAbsolute as isAbsolute12, sep as sep6 } from "path";
52987
53117
  import { homedir as homedir3 } from "os";
@@ -53837,7 +53967,7 @@ function projectedHookExecutable(command, expectedResolved) {
53837
53967
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53838
53968
  const recheck = () => {
53839
53969
  try {
53840
- if (realpathSync8(command) !== resolved || linkIdentity(lstatSync18(command, { bigint: true })) !== linkIdentity(link2) || !isDeepStrictEqual5(parents2(), parentIdentity) || !isDeepStrictEqual5(parents2(resolved), resolvedParentIdentity))
53970
+ if (realpathSync8(command) !== resolved || linkIdentity(lstatSync18(command, { bigint: true })) !== linkIdentity(link2) || !isDeepStrictEqual6(parents2(), parentIdentity) || !isDeepStrictEqual6(parents2(resolved), resolvedParentIdentity))
53841
53971
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
53842
53972
  projectedHookAcl(cli.file, cli.stat);
53843
53973
  projectedHookAcl(manifest.file, manifest.stat);
@@ -53977,7 +54107,7 @@ function atomicWrite2(path, content) {
53977
54107
  }
53978
54108
  }
53979
54109
  function planAgentSettingsWitnessUpgrade(options) {
53980
- if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3].includes(options.targetCodexVersion)))
54110
+ if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3, 4].includes(options.targetCodexVersion)))
53981
54111
  throw new Error("Invalid Codex witness target version");
53982
54112
  const home = resolve13(options.home ?? homedir3()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
53983
54113
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir3);
@@ -54000,21 +54130,21 @@ function planAgentSettingsWitnessUpgrade(options) {
54000
54130
  throw new Error("Settings witness upgrade requires a preserved settings preimage");
54001
54131
  const replaced = [previous];
54002
54132
  if (options.agent === "codex") {
54003
- if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1" && !(options.targetCodexVersion === 3 && previous.hashMode === "codex-settings-v2"))
54133
+ if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1" && !((options.targetCodexVersion === 3 || options.targetCodexVersion === 4) && previous.hashMode === "codex-settings-v2") && !(options.targetCodexVersion === 4 && previous.hashMode === "codex-settings-v3"))
54004
54134
  throw new Error("Codex settings witness upgrade requires an eligible preserved configuration witness");
54005
54135
  const preimage = readCodexSettingsPreimage(options.reviewedPreimage);
54006
54136
  for (const source of binding.sources) {
54007
54137
  if (source === previous || source.path !== configPath)
54008
54138
  continue;
54009
54139
  const fields = source.fields;
54010
- if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields) || !isDeepStrictEqual5(fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
54140
+ if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields) || !isDeepStrictEqual6(fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
54011
54141
  throw new Error("Codex settings witness upgrade found an unrecognized configuration witness");
54012
54142
  if (projectNativeDiscoveryFields(preimage, "toml", fields, configPath) !== source.sha256)
54013
54143
  throw new Error("Reviewed preimage does not explain the Codex discovery projection witness");
54014
54144
  replaced.push(source);
54015
54145
  }
54016
54146
  }
54017
- const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
54147
+ const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 4 ? upgradeCodexSettingsWitnessV4(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
54018
54148
  const rebound = [];
54019
54149
  for (const source of binding.sources) {
54020
54150
  if (!replaced.includes(source)) {
@@ -54060,7 +54190,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
54060
54190
  const upgrade = plan.settingsWitnessUpgrade;
54061
54191
  if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
54062
54192
  throw new Error("Invalid settings witness upgrade plan");
54063
- const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, ...upgrade.agent === "codex" ? { targetCodexVersion: upgrade.toHashMode === "codex-settings-v3" ? 3 : 2 } : {}, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
54193
+ const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, ...upgrade.agent === "codex" ? { targetCodexVersion: upgrade.toHashMode === "codex-settings-v4" ? 4 : upgrade.toHashMode === "codex-settings-v3" ? 3 : 2 } : {}, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
54064
54194
  if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
54065
54195
  throw new Error("Settings witness upgrade plan changed");
54066
54196
  provenDiscovery = verified.discoveryBefore[0];
@@ -57400,7 +57530,7 @@ var init_claude_marketplace_registry = __esm(() => {
57400
57530
  });
57401
57531
 
57402
57532
  // src/lib/codex-hook-trust-layout.ts
57403
- import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
57533
+ import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
57404
57534
  function codexTrustTextWitness(text2, keys2, canonicalize = true) {
57405
57535
  const parsed = Bun.TOML.parse(text2), wanted = new Set(keys2);
57406
57536
  const headers = [...text2.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
@@ -57465,7 +57595,7 @@ function codexTrustTextWitness(text2, keys2, canonicalize = true) {
57465
57595
  if (expected.hooks)
57466
57596
  delete expected.hooks.state;
57467
57597
  try {
57468
- if (!isDeepStrictEqual6(prune(Bun.TOML.parse(noState)), prune(expected)))
57598
+ if (!isDeepStrictEqual7(prune(Bun.TOML.parse(noState)), prune(expected)))
57469
57599
  throw fail3();
57470
57600
  } catch {
57471
57601
  throw fail3();
@@ -57535,13 +57665,13 @@ var init_codex_hook_trust_layout = () => {};
57535
57665
 
57536
57666
  // src/lib/codex-hook-additions-review.ts
57537
57667
  import { isAbsolute as isAbsolute17 } from "path";
57538
- import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
57668
+ import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
57539
57669
  function exactKeys2(value, keys2) {
57540
- need5(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual7(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
57670
+ need5(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual8(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
57541
57671
  }
57542
57672
  function readReviewedAdditionTrustStates(proof, before2, current, journalHooks) {
57543
57673
  const captured = proofs.get(proof);
57544
- need5(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual7(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
57674
+ need5(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual8(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
57545
57675
  captured.recheck();
57546
57676
  unchanged2(before2);
57547
57677
  unchanged2(current);
@@ -57564,7 +57694,7 @@ function reviewNativeHookAdditions(options) {
57564
57694
  expectedProducer.hooks.state ??= {};
57565
57695
  for (const hook of options.journalHooks)
57566
57696
  expectedProducer.hooks.state[hook.key] = { ...expectedProducer.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
57567
- need5(isDeepStrictEqual7(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
57697
+ need5(isDeepStrictEqual8(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
57568
57698
  need5(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
57569
57699
  const expectedHooks = JSON.parse(options.hooksBefore.text), currentHooks = JSON.parse(options.hooksCurrent.text), expectedConfig = structuredClone(producer);
57570
57700
  need5(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
@@ -57593,9 +57723,9 @@ function reviewNativeHookAdditions(options) {
57593
57723
  expectedHooks.hooks[event] = [...groups, { ...event === "PreToolUse" ? { matcher: hook.matcher } : {}, hooks: [{ type: "command", command: hook.command, timeout: hook.timeoutSec }] }];
57594
57724
  expectedConfig.hooks.state[key] = trustState;
57595
57725
  }
57596
- need5(isDeepStrictEqual7(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
57726
+ need5(isDeepStrictEqual8(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
57597
57727
  const keys2 = added.map((hook) => hook.key);
57598
- need5(isDeepStrictEqual7(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");
57728
+ need5(isDeepStrictEqual8(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");
57599
57729
  const inputs = [reviewFile, producerConfig, producerHooks, options.intent, options.policy, options.configBefore, options.configCurrent, options.hooksBefore, options.hooksCurrent];
57600
57730
  const recheck = () => {
57601
57731
  for (const input of inputs)
@@ -57618,7 +57748,7 @@ var init_codex_hook_additions_review = __esm(() => {
57618
57748
 
57619
57749
  // src/lib/codex-hook-discovery-recovery.ts
57620
57750
  import { createHash as createHash19 } from "crypto";
57621
- import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
57751
+ import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
57622
57752
  function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, additions) {
57623
57753
  const journalHooks = hooks.map(({ key, currentHash }) => ({ key, currentHash }));
57624
57754
  const additionStates = additions ? readReviewedAdditionTrustStates(additions, before2, current, journalHooks) : [];
@@ -57632,11 +57762,11 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
57632
57762
  need5(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
57633
57763
  need5(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
57634
57764
  const typed = binding.sources.filter((source) => source.path === current.file && source.format === "toml");
57635
- need5(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual8(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
57765
+ need5(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual9(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
57636
57766
  const original = structure2(before2.text), actual = structure2(current.text);
57637
57767
  const project = (value) => Object.fromEntries(fields.map((field2) => [field2, value[field2] ?? null]));
57638
57768
  const projection = sha4(JSON.stringify(project(original)));
57639
- need5(typed[0].sha256 === projection && sha4(JSON.stringify(project(actual))) === projection && isDeepStrictEqual8(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
57769
+ need5(typed[0].sha256 === projection && sha4(JSON.stringify(project(actual))) === projection && isDeepStrictEqual9(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
57640
57770
  const keys2 = [...journalHooks.map((hook) => hook.key), ...additionStates.map((hook) => hook.key)];
57641
57771
  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");
57642
57772
  const expected = structuredClone(original);
@@ -57646,7 +57776,7 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
57646
57776
  expected.hooks.state[hook.key] = { ...expected.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
57647
57777
  for (const { key, state } of additionStates)
57648
57778
  expected.hooks.state[key] = { ...state };
57649
- need5(isDeepStrictEqual8(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
57779
+ need5(isDeepStrictEqual9(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
57650
57780
  unchanged2(before2);
57651
57781
  unchanged2(current);
57652
57782
  const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha4(JSON.stringify(binding)), typedProjectionSha256: projection });
@@ -57681,7 +57811,7 @@ var init_codex_hook_discovery_recovery = __esm(() => {
57681
57811
  import { createHash as createHash20 } from "crypto";
57682
57812
  import { lstatSync as lstatSync23, readFileSync as readFileSync19, readdirSync as readdirSync11, realpathSync as realpathSync9 } from "fs";
57683
57813
  import { basename as basename10, dirname as dirname18, isAbsolute as isAbsolute18, join as join35, resolve as resolve18, sep as sep7 } from "path";
57684
- import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
57814
+ import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
57685
57815
  function parseConfig(text3, path, toml = false) {
57686
57816
  try {
57687
57817
  const value = toml ? Bun.TOML.parse(text3) : JSON.parse(text3);
@@ -57720,19 +57850,19 @@ function projectNativeDiscoveryFields(text3, format, fields2, path) {
57720
57850
  return digest(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object5[field2] ?? null]))));
57721
57851
  }
57722
57852
  function isSupersededCodexProjection(agent, configPath, source) {
57723
- return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual9(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
57853
+ return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual10(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
57724
57854
  }
57725
57855
  function supersedesCodexProjection(sources, configPath) {
57726
- return sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3"));
57856
+ return sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")));
57727
57857
  }
57728
57858
  function projected(source, changes, budget = discoveryByteBudget()) {
57729
- if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3") {
57859
+ if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) {
57730
57860
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
57731
57861
  throw new Error("Codex settings witnesses require exact typed metadata");
57732
- const current = (source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
57862
+ const current = (source.hashMode === "codex-settings-v4" ? captureCodexSettingsV4 : source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
57733
57863
  if (current !== source.sha256)
57734
57864
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
57735
- return changes?.has(source.path) ? (source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
57865
+ return changes?.has(source.path) ? (source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
57736
57866
  }
57737
57867
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
57738
57868
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
@@ -57828,7 +57958,7 @@ function captureRetiredCodexDiscovery(binding, controls, rules) {
57828
57958
  return current;
57829
57959
  const installation = codexInstallationRoots(binding);
57830
57960
  const directories = (binding.directories ?? []).filter((directory) => !installation.some((root2) => directory.path === root2 || directory.path.startsWith(root2 + sep7) || root2.startsWith(directory.path + sep7)));
57831
- if (previous && isDeepStrictEqual9(previous.roots, roots) && isDeepStrictEqual9(previous.parents, parents3) && isDeepStrictEqual9(previous.directories.map((item) => item.path), directories.map((item) => item.path)))
57961
+ if (previous && isDeepStrictEqual10(previous.roots, roots) && isDeepStrictEqual10(previous.parents, parents3) && isDeepStrictEqual10(previous.directories.map((item) => item.path), directories.map((item) => item.path)))
57832
57962
  return { ...current, codexRetiredMaterializations: previous };
57833
57963
  return { ...current, codexRetiredMaterializations: { roots, parents: parents3, directories: captureDiscoveryDirectoryProjection(directories.map((item) => item.path), roots) } };
57834
57964
  }
@@ -57904,7 +58034,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
57904
58034
  if (omitted.some((root2) => !retiredRoots.includes(root2)))
57905
58035
  throw new Error("Missing reviewed directory membership inventory; provide a fresh discovery review");
57906
58036
  const current = captureDiscoveryDirectoryProjection(ordinary.map((item) => item.path), retiredRoots).map(({ entries, ...item }) => item);
57907
- if (!isDeepStrictEqual9(current, projection))
58037
+ if (!isDeepStrictEqual10(current, projection))
57908
58038
  throw new Error("Native discovery directory membership changed outside retired Codex roots");
57909
58039
  }
57910
58040
  } else
@@ -57963,7 +58093,7 @@ function codexInstallationRoots(binding) {
57963
58093
  });
57964
58094
  }
57965
58095
  function assertMarketplaceBinding(binding, source) {
57966
- if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename10(source.path) !== "config.toml"))
58096
+ if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename10(source.path) !== "config.toml"))
57967
58097
  throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
57968
58098
  if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename10(source.path) !== "settings.json"))
57969
58099
  throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
@@ -58152,10 +58282,10 @@ function resolveAgentDiscovery(options) {
58152
58282
  verifyAgentDiscovery(retained);
58153
58283
  if (!retained.sources.some((source) => source.path === canonical6(configPath) && source.format === undefined && source.fields === undefined))
58154
58284
  unresolved("retained review is missing the full agent configuration source");
58155
- 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.hashMode === "codex-settings-v3"))) && source.path !== canonical6(configPath)))
58285
+ 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.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical6(configPath)))
58156
58286
  unresolved("retained settings witness names another configuration source");
58157
58287
  const covered = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
58158
- if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual9(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
58288
+ if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual10(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
58159
58289
  unresolved("retained review is missing current runtime discovery coverage");
58160
58290
  return retained;
58161
58291
  }
@@ -58169,7 +58299,7 @@ function resolveAgentDiscovery(options) {
58169
58299
  if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
58170
58300
  throw new Error("Explicit discovery reviews require full source-file hashes");
58171
58301
  verifyAgentDiscovery(supplied);
58172
- 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.hashMode === "codex-settings-v3"))) && source.path !== canonical6(configPath)))
58302
+ 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.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical6(configPath)))
58173
58303
  throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
58174
58304
  if (!review.sources.some((source) => source.path === canonical6(configPath)))
58175
58305
  throw new Error("Discovery review must include the agent configuration source");
@@ -84267,7 +84397,7 @@ var init_skill_context = __esm(() => {
84267
84397
 
84268
84398
  // src/lib/session-reconciliation.ts
84269
84399
  import { createHash as createHash26 } from "crypto";
84270
- import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
84400
+ import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
84271
84401
  function exactTimestamp(value) {
84272
84402
  const parsed = value === undefined ? Number.NaN : Date.parse(value);
84273
84403
  if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
@@ -84324,7 +84454,7 @@ async function reconcileSkillSessionIfSafe(sessionId, profileId, options = {}) {
84324
84454
  for (const key of old.loaded) {
84325
84455
  const previous = oldByKey.get(key);
84326
84456
  const current = targetBySlug.get(previous.slug);
84327
- if (!current || !isDeepStrictEqual10({ ...previous, profileRevision: target.profileRevision }, current)) {
84457
+ if (!current || !isDeepStrictEqual11({ ...previous, profileRevision: target.profileRevision }, current)) {
84328
84458
  throw new SkillSelectionError("SESSION_RECONCILIATION_REQUIRED", "A loaded Skills selection was removed or changed; review skills sessions reconcile before changing this session's pin.");
84329
84459
  }
84330
84460
  }
@@ -88966,7 +89096,7 @@ var init_execution_grants = __esm(() => {
88966
89096
  });
88967
89097
 
88968
89098
  // src/lib/execution-grant-client.ts
88969
- import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
89099
+ import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
88970
89100
  function id(value) {
88971
89101
  if (!grantIdentifier(value))
88972
89102
  throw new Error("Invalid execution grant profile or revision identifier.");
@@ -89018,7 +89148,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
89018
89148
  headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
89019
89149
  body: JSON.stringify({ grants: snapshot2 })
89020
89150
  }));
89021
- if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual11(policy.grants, snapshot2)) {
89151
+ if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual12(policy.grants, snapshot2)) {
89022
89152
  throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
89023
89153
  }
89024
89154
  return policy;
@@ -89029,7 +89159,7 @@ async function resolveExecutionGrant(input2) {
89029
89159
  if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
89030
89160
  throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
89031
89161
  }
89032
- if (!isDeepStrictEqual11(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual11(value.bindings.consumer, snapshot2.consumer)) {
89162
+ if (!isDeepStrictEqual12(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual12(value.bindings.consumer, snapshot2.consumer)) {
89033
89163
  throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
89034
89164
  }
89035
89165
  return value;
@@ -113727,7 +113857,7 @@ var init_create_sync_config = __esm(() => {
113727
113857
  });
113728
113858
 
113729
113859
  // src/lib/codex-native-config.ts
113730
- import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
113860
+ import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
113731
113861
  function isRecord8(value) {
113732
113862
  if (!value || typeof value !== "object")
113733
113863
  return false;
@@ -113749,7 +113879,7 @@ function decimalIdentity(text4) {
113749
113879
  return `${match[1]}${coefficient}e${exponent}`;
113750
113880
  }
113751
113881
  function codexNativeConfigEqual(native, expected) {
113752
- if (isDeepStrictEqual12(native, expected))
113882
+ if (isDeepStrictEqual13(native, expected))
113753
113883
  return true;
113754
113884
  if (typeof expected === "number") {
113755
113885
  if (!Number.isFinite(expected) || !isRecord8(native))
@@ -113775,7 +113905,7 @@ var init_codex_native_config = () => {};
113775
113905
  // src/lib/codex-hook-trust-identity.ts
113776
113906
  import { realpathSync as realpathSync18 } from "fs";
113777
113907
  import { dirname as dirname34, isAbsolute as isAbsolute28, join as join62 } from "path";
113778
- import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
113908
+ import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
113779
113909
  function inspectRecordedSkillsCli(command, expected) {
113780
113910
  need5(isAbsolute28(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
113781
113911
  const resolved = realpathSync18(command);
@@ -113785,7 +113915,7 @@ function inspectRecordedSkillsCli(command, expected) {
113785
113915
  need5(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join62(dirname34(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
113786
113916
  need5((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
113787
113917
  const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
113788
- need5(isDeepStrictEqual13(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
113918
+ need5(isDeepStrictEqual14(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
113789
113919
  return { receipt, recheck() {
113790
113920
  need5(realpathSync18(command) === resolved, "SKILLS_COMMAND_CHANGED");
113791
113921
  unchanged2(cli);
@@ -113821,19 +113951,19 @@ var init_codex_hook_trust_identity = __esm(() => {
113821
113951
  });
113822
113952
 
113823
113953
  // src/lib/codex-hook-policy-recovery.ts
113824
- import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
113954
+ import { isDeepStrictEqual as isDeepStrictEqual15 } from "util";
113825
113955
  function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
113826
113956
  need5(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
113827
113957
  need5(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
113828
113958
  const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
113829
113959
  const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
113830
113960
  need5(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
113831
- const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual14(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
113961
+ const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual15(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
113832
113962
  need5(changes.length > 0, "RECONCILE_POLICY_CHANGED");
113833
113963
  const compared = structuredClone(current);
113834
113964
  compared.bridge.discovery.claude.roots = oldDiscovery.roots;
113835
113965
  compared.bridge.discovery.claude.sources = oldDiscovery.sources;
113836
- need5(isDeepStrictEqual14(before2, compared), "RECONCILE_POLICY_CHANGED");
113966
+ need5(isDeepStrictEqual15(before2, compared), "RECONCILE_POLICY_CHANGED");
113837
113967
  verifyAgentDiscovery(newDiscovery);
113838
113968
  return { reason: options.reason, changes };
113839
113969
  }
@@ -113849,7 +113979,7 @@ import { createHash as createHash34, randomUUID as randomUUID11 } from "crypto";
113849
113979
  import { execFileSync as execFileSync2 } from "child_process";
113850
113980
  import { dirname as dirname35, isAbsolute as isAbsolute29, join as join63, resolve as resolve27 } from "path";
113851
113981
  import { homedir as homedir12 } from "os";
113852
- import { isDeepStrictEqual as isDeepStrictEqual15 } from "util";
113982
+ import { isDeepStrictEqual as isDeepStrictEqual16 } from "util";
113853
113983
  function verifyReleaseArtifact(proof, skillsCli) {
113854
113984
  need5(isAbsolute29(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
113855
113985
  const tarPath = realpathSync19(proof.packageTarPath);
@@ -113891,7 +114021,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
113891
114021
  const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
113892
114022
  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 };
113893
114023
  need5(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
113894
- need5(isDeepStrictEqual15(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
114024
+ need5(isDeepStrictEqual16(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
113895
114025
  need5(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
113896
114026
  const policyCurrent = snapshot(join63(dataDir3, "agent-policy.json"), true);
113897
114027
  const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
@@ -113904,7 +114034,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
113904
114034
  if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
113905
114035
  need5(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
113906
114036
  const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
113907
- need5(isDeepStrictEqual15(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
114037
+ need5(isDeepStrictEqual16(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
113908
114038
  supersededBinding = true;
113909
114039
  }
113910
114040
  if (supersededBinding || recovery) {
@@ -113940,7 +114070,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
113940
114070
  need5(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
113941
114071
  }
113942
114072
  } else
113943
- need5(isDeepStrictEqual15(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
114073
+ need5(isDeepStrictEqual16(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
113944
114074
  const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
113945
114075
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
113946
114076
  const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
@@ -113949,14 +114079,14 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
113949
114079
  const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
113950
114080
  if (supersededBinding)
113951
114081
  verifyReleaseArtifact(options.releaseProof, skillsCli);
113952
- const skillsBindingChanged = !isDeepStrictEqual15(skillsCli.receipt, intent.skillsCli);
114082
+ const skillsBindingChanged = !isDeepStrictEqual16(skillsCli.receipt, intent.skillsCli);
113953
114083
  need5(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
113954
114084
  if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
113955
114085
  need5(supersededBinding, "RECONCILE_HOOKS_CHANGED");
113956
114086
  const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
113957
114087
  for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
113958
114088
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
113959
- need5(isDeepStrictEqual15(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
114089
+ need5(isDeepStrictEqual16(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
113960
114090
  }
113961
114091
  }
113962
114092
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
@@ -113979,9 +114109,9 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
113979
114109
  delete identity6.command;
113980
114110
  return identity6;
113981
114111
  };
113982
- need5(isDeepStrictEqual15(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
114112
+ need5(isDeepStrictEqual16(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
113983
114113
  if (!plannedKeys.has(expected.key))
113984
- need5(isDeepStrictEqual15(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
114114
+ need5(isDeepStrictEqual16(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
113985
114115
  }
113986
114116
  for (const wanted of intent.hooks) {
113987
114117
  const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join63(home, ".codex/hooks.json"), hooksPath));
@@ -114000,7 +114130,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
114000
114130
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
114001
114131
  need5(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
114002
114132
  const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
114003
- 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 || isDeepStrictEqual15(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
114133
+ 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 || isDeepStrictEqual16(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
114004
114134
  const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
114005
114135
  const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
114006
114136
  need5(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
@@ -114065,7 +114195,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
114065
114195
  const groups = declarations[event];
114066
114196
  need5(Array.isArray(groups), "DECLARATION_CHANGED");
114067
114197
  const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
114068
- need5(matches2.length === 1 && isDeepStrictEqual15(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
114198
+ need5(matches2.length === 1 && isDeepStrictEqual16(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
114069
114199
  expected.push({ event: nativeEvent, key: `${join63(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
114070
114200
  }
114071
114201
  codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
@@ -114131,7 +114261,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
114131
114261
  save(join63(journal, "hooks.before.json"), hooksFile.bytes);
114132
114262
  save(join63(journal, "policy.before.json"), policyFile.bytes);
114133
114263
  save(join63(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
114134
- need5(isDeepStrictEqual15(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
114264
+ need5(isDeepStrictEqual16(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
114135
114265
  checkInputs();
114136
114266
  let result2;
114137
114267
  try {
@@ -114145,7 +114275,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
114145
114275
  expectedConfig.hooks.state ??= {};
114146
114276
  for (const h of planned)
114147
114277
  expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
114148
- need5(isDeepStrictEqual15(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
114278
+ need5(isDeepStrictEqual16(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
114149
114279
  const savedConfig = snapshot(join63(journal, "config.before.toml"), true);
114150
114280
  need5(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
114151
114281
  const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
@@ -114153,8 +114283,8 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
114153
114283
  unchanged2(hooksFile);
114154
114284
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
114155
114285
  const current = await list2(), confirmed = admit(current);
114156
- need5(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual15(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
114157
- need5(isDeepStrictEqual15(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
114286
+ need5(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual16(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
114287
+ need5(isDeepStrictEqual16(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
114158
114288
  unchanged2(after2);
114159
114289
  unchanged2(savedConfig);
114160
114290
  unchanged2(hooksFile);
@@ -114453,18 +114583,18 @@ function registerAgentIntegration(parent) {
114453
114583
  process.exitCode = 1;
114454
114584
  }
114455
114585
  });
114456
- hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v3, 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) => {
114457
- const capture2 = options.kind === "codex-settings-v3" ? captureCodexSettingsV3 : 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;
114586
+ hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v4, codex-settings-v3, 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) => {
114587
+ const capture2 = options.kind === "codex-settings-v4" ? captureCodexSettingsV4 : options.kind === "codex-settings-v3" ? captureCodexSettingsV3 : 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;
114458
114588
  if (!capture2)
114459
- throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v3, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
114589
+ throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v4, codex-settings-v3, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
114460
114590
  await writeCliOutput(JSON.stringify(capture2(options.path), null, 2));
114461
114591
  });
114462
- 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("--codex-witness-version <version>", "Explicit target: 2 (legacy default) or 3 (service tier and model-advertised effort)").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) => {
114592
+ 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("--codex-witness-version <version>", "Explicit target: 2 (legacy default) 3 (service tier and model-advertised effort), or 4 (native availability UI counts)").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) => {
114463
114593
  try {
114464
114594
  if (!["claude", "codex"].includes(options.agent))
114465
114595
  throw new Error("Settings witness rebind accepts claude or codex");
114466
- if (options.codexWitnessVersion !== undefined && !["2", "3"].includes(options.codexWitnessVersion))
114467
- throw new Error("Codex witness version accepts 2 or 3");
114596
+ if (options.codexWitnessVersion !== undefined && !["2", "3", "4"].includes(options.codexWitnessVersion))
114597
+ throw new Error("Codex witness version accepts 2, 3 or 4");
114468
114598
  const plan = planAgentSettingsWitnessUpgrade({ ...options.codexWitnessVersion !== undefined ? { targetCodexVersion: Number(options.codexWitnessVersion) } : {}, agent: options.agent, reviewedPreimage: options.reviewedPreimage, expectedPolicySha256: options.expectedPolicySha256, expectedSettingsSha256: options.expectedSettingsSha256 });
114469
114599
  const result2 = options.apply ? applyAgentIntegration(plan) : { changed: [], backups: [] };
114470
114600
  const receipt = { applied: options.apply, settingsWitnessUpgrade: plan.settingsWitnessUpgrade, ...result2 };