@hasna/skills 0.10.41 → 0.10.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sdk/index.js CHANGED
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
32373
32373
  // package.json
32374
32374
  var package_default = {
32375
32375
  name: "@hasna/skills",
32376
- version: "0.10.41",
32376
+ version: "0.10.43",
32377
32377
  description: "Skills library for AI coding agents",
32378
32378
  type: "module",
32379
32379
  bin: {
@@ -39217,6 +39217,7 @@ function projectRegularCodexMcp(config, source) {
39217
39217
 
39218
39218
  // src/lib/codex-settings-witness.ts
39219
39219
  import { createHash as createHash9 } from "crypto";
39220
+ import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
39220
39221
  var sha2 = (text) => createHash9("sha256").update(text).digest("hex");
39221
39222
  var EFFORT2 = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
39222
39223
  var VERBOSITY2 = new Set(["low", "medium", "high"]);
@@ -39328,7 +39329,7 @@ function disablesOneSkill(entry) {
39328
39329
  return selector.length === 1 && typeof entry[selector[0]] === "string" && entry[selector[0]].length > 0;
39329
39330
  }
39330
39331
  function inference(target, version) {
39331
- const keys2 = version === 3 ? [...INFERENCE, "service_tier", "plan_mode_reasoning_effort", "personality"] : INFERENCE;
39332
+ const keys2 = version >= 3 ? [...INFERENCE, "service_tier", "plan_mode_reasoning_effort", "personality"] : INFERENCE;
39332
39333
  for (const key of keys2)
39333
39334
  if (Object.hasOwn(target, key)) {
39334
39335
  const value = target[key];
@@ -39336,7 +39337,7 @@ function inference(target, version) {
39336
39337
  need3(typeof value === "string" && MODEL.test(value));
39337
39338
  else if (key === "personality")
39338
39339
  need3(typeof value === "string" && ["none", "friendly", "pragmatic"].includes(value));
39339
- else if (version === 3 && key !== "model_verbosity") {
39340
+ else if (version >= 3 && key !== "model_verbosity") {
39340
39341
  need3(typeof value === "string" && value.length <= 128 && !/[\x00-\x1f\x7f]/.test(value));
39341
39342
  if (key !== "service_tier")
39342
39343
  need3(value.length > 0);
@@ -39345,6 +39346,115 @@ function inference(target, version) {
39345
39346
  delete target[key];
39346
39347
  }
39347
39348
  }
39349
+ function projectModelAvailabilityNux(config, text) {
39350
+ const tui = config.tui, counts = isRecord(tui) ? tui.model_availability_nux : undefined;
39351
+ if (isRecord(tui) && !Object.keys(tui).length) {
39352
+ delete config.tui;
39353
+ return { config, numericSource: text };
39354
+ }
39355
+ if (!isRecord(counts) || Object.keys(counts).length > 256 || !Object.values(counts).every((value) => typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 4294967295))
39356
+ return { config, numericSource: text };
39357
+ const expected = structuredClone(config);
39358
+ delete expected.tui.model_availability_nux;
39359
+ const stripEmptyTui = (value) => {
39360
+ if (isRecord(value.tui) && !Object.keys(value.tui).length)
39361
+ delete value.tui;
39362
+ };
39363
+ stripEmptyTui(expected);
39364
+ const headers = [];
39365
+ const spans = [];
39366
+ const integer = /^(?:\+?(?:0|[1-9](?:_?\d)*)|0x[0-9a-fA-F](?:_?[0-9a-fA-F])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*)$/;
39367
+ const counterIntegers = (span) => {
39368
+ let values = 0;
39369
+ for (let at = 0;at < span.length; ) {
39370
+ const char = span[at];
39371
+ if (char === "#") {
39372
+ while (at < span.length && span[at] !== `
39373
+ `)
39374
+ at++;
39375
+ continue;
39376
+ }
39377
+ if (char === '"' || char === "'") {
39378
+ const quote = char;
39379
+ at++;
39380
+ while (at < span.length) {
39381
+ if (quote === '"' && span[at] === "\\") {
39382
+ at += 2;
39383
+ continue;
39384
+ }
39385
+ if (span[at++] === quote)
39386
+ break;
39387
+ }
39388
+ continue;
39389
+ }
39390
+ if (char !== "=") {
39391
+ at++;
39392
+ continue;
39393
+ }
39394
+ at++;
39395
+ while (at < span.length && /\s/.test(span[at]))
39396
+ at++;
39397
+ if (span[at] === "{") {
39398
+ at++;
39399
+ continue;
39400
+ }
39401
+ const start = at;
39402
+ while (at < span.length && !/[\s,\]{}#]/.test(span[at]))
39403
+ at++;
39404
+ if (!integer.test(span.slice(start, at)))
39405
+ return false;
39406
+ values++;
39407
+ }
39408
+ return values === Object.keys(counts).length;
39409
+ };
39410
+ let attempts = 0;
39411
+ const realPrefix = (end) => {
39412
+ if (++attempts > 256)
39413
+ return false;
39414
+ try {
39415
+ Bun.TOML.parse(text.slice(0, end));
39416
+ return true;
39417
+ } catch {
39418
+ return false;
39419
+ }
39420
+ };
39421
+ for (const match of text.matchAll(/^[ \t]*\[[^\r\n]+\][ \t]*(?:#[^\r\n]*)?(?:\r?\n|$)/gm)) {
39422
+ const start = match.index, end = start + match[0].length;
39423
+ if (realPrefix(end))
39424
+ headers.push({ start, end });
39425
+ }
39426
+ for (let at = 0;at < headers.length; at++) {
39427
+ const header = headers[at];
39428
+ let parsed;
39429
+ try {
39430
+ parsed = Bun.TOML.parse(text.slice(header.start, header.end));
39431
+ } catch {
39432
+ continue;
39433
+ }
39434
+ if (isRecord(parsed.tui) && isRecord(parsed.tui.model_availability_nux) && !Object.keys(parsed.tui.model_availability_nux).length && Object.keys(parsed).length === 1 && Object.keys(parsed.tui).length === 1)
39435
+ spans.push({ start: header.start, end: headers[at + 1]?.start ?? text.length });
39436
+ }
39437
+ for (const match of text.matchAll(/^[ \t]*(?:(?:tui|"tui"|'tui')[ \t]*\.[ \t]*)?(?:model_availability_nux|"model_availability_nux"|'model_availability_nux')[ \t]*=[ \t]*\{[^\r\n]*(?:\r?\n|$)/gm)) {
39438
+ const start = match.index, end = start + match[0].length;
39439
+ if (realPrefix(end))
39440
+ spans.push({ start, end });
39441
+ }
39442
+ for (const { start, end } of spans) {
39443
+ if (!counterIntegers(text.slice(start, end)))
39444
+ continue;
39445
+ const remaining = text.slice(0, start) + text.slice(end);
39446
+ let parsed;
39447
+ try {
39448
+ parsed = Bun.TOML.parse(remaining);
39449
+ } catch {
39450
+ continue;
39451
+ }
39452
+ stripEmptyTui(parsed);
39453
+ if (isDeepStrictEqual4(parsed, expected))
39454
+ return { config: expected, numericSource: remaining };
39455
+ }
39456
+ return { config, numericSource: text };
39457
+ }
39348
39458
  function settingsDigest2(text, version = 2) {
39349
39459
  let config;
39350
39460
  try {
@@ -39353,7 +39463,8 @@ function settingsDigest2(text, version = 2) {
39353
39463
  throw new Error("Invalid Codex settings witness");
39354
39464
  }
39355
39465
  need3(isRecord(config));
39356
- const projected = version === 3 ? projectRegularCodexMcp(config, text) : { config, numericSource: text };
39466
+ const mcp = version >= 3 ? projectRegularCodexMcp(config, text) : { config, numericSource: text };
39467
+ const projected = version === 4 ? projectModelAvailabilityNux(mcp.config, mcp.numericSource) : mcp;
39357
39468
  normalize2(projected.config, version);
39358
39469
  return sha2(`hasna.skills.codex-settings.v${version}\x00${JSON.stringify([canonical3(projected.config), numericTokens2(projected.numericSource)])}`);
39359
39470
  }
@@ -39398,6 +39509,25 @@ function upgradeCodexSettingsWitnessV3(previous, reviewedSettingsPath) {
39398
39509
  throw new Error("Codex settings outside the reviewed V3 contract changed; explicit discovery review required");
39399
39510
  return { path: previous.path, hashMode: "codex-settings-v3", sha256: sha2562 };
39400
39511
  }
39512
+ function hashCodexSettingsReplacementV4(text, budget = { remaining: 256 * 1024 * 1024 }) {
39513
+ need3(Buffer.byteLength(text) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text));
39514
+ budget.remaining -= Buffer.byteLength(text);
39515
+ return settingsDigest2(text, 4);
39516
+ }
39517
+ function captureCodexSettingsV4(path, budget = { remaining: 256 * 1024 * 1024 }) {
39518
+ return { path, hashMode: "codex-settings-v4", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget, "config.toml"), 4) };
39519
+ }
39520
+ function upgradeCodexSettingsWitnessV4(previous, reviewedSettingsPath) {
39521
+ need3(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));
39522
+ const budget = { remaining: 2 * 1024 * 1024 };
39523
+ const before = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
39524
+ const original = previous.hashMode === "codex-settings-v3" ? settingsDigest2(before, 3) : previous.hashMode === "codex-settings-v2" ? settingsDigest2(before, 2) : previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before) : sha2(before);
39525
+ need3(original === previous.sha256);
39526
+ const sha2562 = settingsDigest2(current, 4);
39527
+ if (settingsDigest2(before, 4) !== sha2562)
39528
+ throw new Error("Codex settings outside the reviewed V4 contract changed; explicit discovery review required");
39529
+ return { path: previous.path, hashMode: "codex-settings-v4", sha256: sha2562 };
39530
+ }
39401
39531
 
39402
39532
  // src/lib/native-discovery-roots.ts
39403
39533
  var NATIVE_SKILL_ROOTS = [
@@ -39422,7 +39552,7 @@ var NATIVE_SKILL_ROOTS = [
39422
39552
 
39423
39553
  // src/lib/agent-integration.ts
39424
39554
  import { createHash as createHash20, randomUUID as randomUUID3 } from "crypto";
39425
- import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
39555
+ import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
39426
39556
  import { existsSync as existsSync7, lstatSync as lstatSync21, statSync as statSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync15, readdirSync as readdirSync8, opendirSync as opendirSync5, readlinkSync as readlinkSync4, realpathSync as realpathSync9, renameSync as renameSync3, rmdirSync as rmdirSync3, writeFileSync as writeFileSync4, unlinkSync as unlinkSync4, chmodSync, openSync as openSync16, closeSync as closeSync16, fsyncSync as fsyncSync4, fstatSync as fstatSync16, readSync as readSync11, constants as constants13, linkSync as linkSync3 } from "fs";
39427
39557
  import { dirname as dirname16, join as join25, resolve as resolve17, relative as relative5, isAbsolute as isAbsolute18, sep as sep6 } from "path";
39428
39558
  import { homedir as homedir3 } from "os";
@@ -39566,8 +39696,8 @@ function assertAgentPolicyCollections(policy) {
39566
39696
  text(source.path);
39567
39697
  requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
39568
39698
  if (source.hashMode !== undefined)
39569
- 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));
39570
- if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3")
39699
+ 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));
39700
+ if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
39571
39701
  requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute7(source.path) && resolve6(source.path) === source.path && basename5(source.path) === "config.toml");
39572
39702
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
39573
39703
  requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute7(source.path) && resolve6(source.path) === source.path && basename5(source.path) === "settings.json");
@@ -39727,7 +39857,7 @@ function isOwnedCliBridge(path, expectedPaths) {
39727
39857
  import { createHash as createHash19 } from "crypto";
39728
39858
  import { lstatSync as lstatSync20, readFileSync as readFileSync14, readdirSync as readdirSync7, realpathSync as realpathSync8 } from "fs";
39729
39859
  import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute17, join as join24, resolve as resolve16, sep as sep5 } from "path";
39730
- import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
39860
+ import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
39731
39861
 
39732
39862
  // node_modules/yaml/dist/index.js
39733
39863
  var composer = require_composer();
@@ -42228,19 +42358,19 @@ function projectNativeDiscoveryFields(text2, format, fields2, path) {
42228
42358
  return digest2(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object5[field2] ?? null]))));
42229
42359
  }
42230
42360
  function isSupersededCodexProjection(agent, configPath, source) {
42231
- return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual4(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
42361
+ return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual5(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
42232
42362
  }
42233
42363
  function supersedesCodexProjection(sources, configPath) {
42234
- return sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3"));
42364
+ return sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")));
42235
42365
  }
42236
42366
  function projected(source, changes, budget = discoveryByteBudget()) {
42237
- if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3") {
42367
+ if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) {
42238
42368
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
42239
42369
  throw new Error("Codex settings witnesses require exact typed metadata");
42240
- const current = (source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
42370
+ 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;
42241
42371
  if (current !== source.sha256)
42242
42372
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
42243
- return changes?.has(source.path) ? (source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
42373
+ 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;
42244
42374
  }
42245
42375
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
42246
42376
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
@@ -42336,7 +42466,7 @@ function captureRetiredCodexDiscovery(binding, controls, rules) {
42336
42466
  return current;
42337
42467
  const installation = codexInstallationRoots(binding);
42338
42468
  const directories = (binding.directories ?? []).filter((directory) => !installation.some((root2) => directory.path === root2 || directory.path.startsWith(root2 + sep5) || root2.startsWith(directory.path + sep5)));
42339
- if (previous && isDeepStrictEqual4(previous.roots, roots) && isDeepStrictEqual4(previous.parents, parents3) && isDeepStrictEqual4(previous.directories.map((item) => item.path), directories.map((item) => item.path)))
42469
+ if (previous && isDeepStrictEqual5(previous.roots, roots) && isDeepStrictEqual5(previous.parents, parents3) && isDeepStrictEqual5(previous.directories.map((item) => item.path), directories.map((item) => item.path)))
42340
42470
  return { ...current, codexRetiredMaterializations: previous };
42341
42471
  return { ...current, codexRetiredMaterializations: { roots, parents: parents3, directories: captureDiscoveryDirectoryProjection(directories.map((item) => item.path), roots) } };
42342
42472
  }
@@ -42412,7 +42542,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
42412
42542
  if (omitted.some((root2) => !retiredRoots.includes(root2)))
42413
42543
  throw new Error("Missing reviewed directory membership inventory; provide a fresh discovery review");
42414
42544
  const current = captureDiscoveryDirectoryProjection(ordinary.map((item) => item.path), retiredRoots).map(({ entries, ...item }) => item);
42415
- if (!isDeepStrictEqual4(current, projection))
42545
+ if (!isDeepStrictEqual5(current, projection))
42416
42546
  throw new Error("Native discovery directory membership changed outside retired Codex roots");
42417
42547
  }
42418
42548
  } else
@@ -42471,7 +42601,7 @@ function codexInstallationRoots(binding) {
42471
42601
  });
42472
42602
  }
42473
42603
  function assertMarketplaceBinding(binding, source) {
42474
- if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename8(source.path) !== "config.toml"))
42604
+ 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" || basename8(source.path) !== "config.toml"))
42475
42605
  throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
42476
42606
  if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
42477
42607
  throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
@@ -42672,10 +42802,10 @@ function resolveAgentDiscovery(options) {
42672
42802
  verifyAgentDiscovery(retained);
42673
42803
  if (!retained.sources.some((source) => source.path === canonical6(configPath) && source.format === undefined && source.fields === undefined))
42674
42804
  unresolved("retained review is missing the full agent configuration source");
42675
- 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)))
42805
+ 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)))
42676
42806
  unresolved("retained settings witness names another configuration source");
42677
42807
  const covered = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
42678
- if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual4(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
42808
+ if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual5(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
42679
42809
  unresolved("retained review is missing current runtime discovery coverage");
42680
42810
  return retained;
42681
42811
  }
@@ -42689,7 +42819,7 @@ function resolveAgentDiscovery(options) {
42689
42819
  if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
42690
42820
  throw new Error("Explicit discovery reviews require full source-file hashes");
42691
42821
  verifyAgentDiscovery(supplied);
42692
- 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)))
42822
+ 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)))
42693
42823
  throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
42694
42824
  if (!review.sources.some((source) => source.path === canonical6(configPath)))
42695
42825
  throw new Error("Discovery review must include the agent configuration source");
@@ -42877,7 +43007,7 @@ export default async ({ directory }) => {
42877
43007
  }
42878
43008
 
42879
43009
  // src/lib/agent-codex.ts
42880
- import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
43010
+ import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
42881
43011
  var CODEX_SKILL_CONFIG_SECTIONS = /^\[\[skills\.config\]\][^\n]*(?:\n(?!\s*\[)[^\n]*)*/gm;
42882
43012
  var codexPathConfigRefusal = () => new Error("Codex skill path controls require ordinary [[skills.config]] TOML tables or a native single-line inline array; preserve and review unsupported inline, dotted, or malformed definitions before running skills hook install");
42883
43013
  function splitTopLevel(value, delimiter2) {
@@ -43008,7 +43138,7 @@ function normalizeCodexInlinePathConfig(text2) {
43008
43138
  const expectedWithoutConfig = structuredClone(before);
43009
43139
  delete expectedWithoutConfig.skills.config;
43010
43140
  try {
43011
- if (isDeepStrictEqual5(Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, "")), expectedWithoutConfig))
43141
+ if (isDeepStrictEqual6(Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, "")), expectedWithoutConfig))
43012
43142
  return text2;
43013
43143
  } catch {}
43014
43144
  const matches = [];
@@ -43061,7 +43191,7 @@ function normalizeCodexInlinePathConfig(text2) {
43061
43191
  try {
43062
43192
  const after = Bun.TOML.parse(candidate2);
43063
43193
  const expected = structuredClone(before);
43064
- if (isDeepStrictEqual5(after, expected))
43194
+ if (isDeepStrictEqual6(after, expected))
43065
43195
  matches.push(candidate2);
43066
43196
  } catch {}
43067
43197
  }
@@ -43077,11 +43207,11 @@ function assertCodexPathConfigEditable(text2) {
43077
43207
  delete expected.skills.config;
43078
43208
  try {
43079
43209
  const withoutSections = Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
43080
- if (isDeepStrictEqual5(withoutSections, expected))
43210
+ if (isDeepStrictEqual6(withoutSections, expected))
43081
43211
  return;
43082
43212
  const normalized = normalizeCodexInlinePathConfig(text2);
43083
43213
  const withoutNormalizedSections = Bun.TOML.parse(normalized.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
43084
- if (isDeepStrictEqual5(withoutNormalizedSections, expected))
43214
+ if (isDeepStrictEqual6(withoutNormalizedSections, expected))
43085
43215
  return;
43086
43216
  } catch {}
43087
43217
  throw codexPathConfigRefusal();
@@ -43119,7 +43249,7 @@ function disableCodexBundledSkills(text2) {
43119
43249
  const candidates = new Set;
43120
43250
  const consider = (candidate2) => {
43121
43251
  try {
43122
- if (isDeepStrictEqual5(Bun.TOML.parse(candidate2), expected))
43252
+ if (isDeepStrictEqual6(Bun.TOML.parse(candidate2), expected))
43123
43253
  candidates.add(candidate2);
43124
43254
  } catch {}
43125
43255
  };
@@ -43950,7 +44080,7 @@ function projectedHookExecutable(command, expectedResolved) {
43950
44080
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
43951
44081
  const recheck = () => {
43952
44082
  try {
43953
- if (realpathSync9(command) !== resolved || linkIdentity(lstatSync21(command, { bigint: true })) !== linkIdentity(link) || !isDeepStrictEqual6(parents3(), parentIdentity) || !isDeepStrictEqual6(parents3(resolved), resolvedParentIdentity))
44083
+ if (realpathSync9(command) !== resolved || linkIdentity(lstatSync21(command, { bigint: true })) !== linkIdentity(link) || !isDeepStrictEqual7(parents3(), parentIdentity) || !isDeepStrictEqual7(parents3(resolved), resolvedParentIdentity))
43954
44084
  hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
43955
44085
  projectedHookAcl(cli.file, cli.stat);
43956
44086
  projectedHookAcl(manifest.file, manifest.stat);
@@ -44171,7 +44301,7 @@ function atomicWrite2(path, content) {
44171
44301
  }
44172
44302
  }
44173
44303
  function planAgentSettingsWitnessUpgrade(options) {
44174
- if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3].includes(options.targetCodexVersion)))
44304
+ if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3, 4].includes(options.targetCodexVersion)))
44175
44305
  throw new Error("Invalid Codex witness target version");
44176
44306
  const home = resolve17(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
44177
44307
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
@@ -44194,21 +44324,21 @@ function planAgentSettingsWitnessUpgrade(options) {
44194
44324
  throw new Error("Settings witness upgrade requires a preserved settings preimage");
44195
44325
  const replaced = [previous];
44196
44326
  if (options.agent === "codex") {
44197
- if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1" && !(options.targetCodexVersion === 3 && previous.hashMode === "codex-settings-v2"))
44327
+ 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"))
44198
44328
  throw new Error("Codex settings witness upgrade requires an eligible preserved configuration witness");
44199
44329
  const preimage = readCodexSettingsPreimage(options.reviewedPreimage);
44200
44330
  for (const source of binding.sources) {
44201
44331
  if (source === previous || source.path !== configPath)
44202
44332
  continue;
44203
44333
  const fields2 = source.fields;
44204
- if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields2) || !isDeepStrictEqual6(fields2, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
44334
+ if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields2) || !isDeepStrictEqual7(fields2, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
44205
44335
  throw new Error("Codex settings witness upgrade found an unrecognized configuration witness");
44206
44336
  if (projectNativeDiscoveryFields(preimage, "toml", fields2, configPath) !== source.sha256)
44207
44337
  throw new Error("Reviewed preimage does not explain the Codex discovery projection witness");
44208
44338
  replaced.push(source);
44209
44339
  }
44210
44340
  }
44211
- const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
44341
+ 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);
44212
44342
  const rebound = [];
44213
44343
  for (const source of binding.sources) {
44214
44344
  if (!replaced.includes(source)) {
@@ -44254,7 +44384,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
44254
44384
  const upgrade = plan.settingsWitnessUpgrade;
44255
44385
  if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
44256
44386
  throw new Error("Invalid settings witness upgrade plan");
44257
- 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: sha4(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
44387
+ 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: sha4(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
44258
44388
  if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
44259
44389
  throw new Error("Settings witness upgrade plan changed");
44260
44390
  provenDiscovery = verified.discoveryBefore[0];
@@ -1 +1,2 @@
1
+ #!/usr/bin/env bun
1
2
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.10.41",
3
+ "version": "0.10.43",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {