@hasna/skills 0.9.18 → 0.9.20

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.9.18",
36871
+ version: "0.9.20",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -108504,6 +108504,52 @@ var init_create_sync_config = __esm(() => {
108504
108504
  init_station_snapshot();
108505
108505
  });
108506
108506
 
108507
+ // src/lib/codex-native-config.ts
108508
+ import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
108509
+ function isRecord6(value) {
108510
+ if (!value || typeof value !== "object")
108511
+ return false;
108512
+ const prototype = Object.getPrototypeOf(value);
108513
+ return prototype === Object.prototype || prototype === null;
108514
+ }
108515
+ function decimalIdentity(text4) {
108516
+ if (text4.length > 4096)
108517
+ return;
108518
+ const match = /^(-?)(0|[1-9][0-9]*)(?:\.([0-9]+))?(?:[eE]([+-]?[0-9]+))?$/.exec(text4);
108519
+ if (!match || !Number.isFinite(Number(text4)))
108520
+ return;
108521
+ const fraction = match[3] ?? "";
108522
+ const digits = (match[2] + fraction).replace(/^0+/, "");
108523
+ if (!digits)
108524
+ return match[1] + "0";
108525
+ const coefficient = digits.replace(/0+$/, "");
108526
+ const exponent = BigInt(match[4] ?? "0") - BigInt(fraction.length) + BigInt(digits.length - coefficient.length);
108527
+ return `${match[1]}${coefficient}e${exponent}`;
108528
+ }
108529
+ function codexNativeConfigEqual(native, expected) {
108530
+ if (isDeepStrictEqual9(native, expected))
108531
+ return true;
108532
+ if (typeof expected === "number") {
108533
+ if (!Number.isFinite(expected) || !isRecord6(native))
108534
+ return false;
108535
+ const keys3 = Object.keys(native);
108536
+ const value = native[NUMBER_TAG];
108537
+ if (keys3.length !== 1 || keys3[0] !== NUMBER_TAG || typeof value !== "string")
108538
+ return false;
108539
+ const actual2 = decimalIdentity(value);
108540
+ return actual2 !== undefined && actual2 === decimalIdentity(Object.is(expected, -0) ? "-0" : String(expected));
108541
+ }
108542
+ if (Array.isArray(native) || Array.isArray(expected)) {
108543
+ return Array.isArray(native) && Array.isArray(expected) && native.length === expected.length && native.every((value, index) => codexNativeConfigEqual(value, expected[index]));
108544
+ }
108545
+ if (!isRecord6(native) || !isRecord6(expected))
108546
+ return false;
108547
+ const actual = native, wanted = expected;
108548
+ return Object.keys(actual).length === Object.keys(wanted).length && Object.keys(wanted).every((key) => Object.hasOwn(actual, key) && codexNativeConfigEqual(actual[key], wanted[key]));
108549
+ }
108550
+ var NUMBER_TAG = "$serde_json::private::Number";
108551
+ var init_codex_native_config = () => {};
108552
+
108507
108553
  // src/lib/codex-hook-rpc.ts
108508
108554
  import { execFile, spawn as spawn3 } from "child_process";
108509
108555
  import { realpathSync as realpathSync12, statSync as statSync20 } from "fs";
@@ -108647,7 +108693,7 @@ var init_codex_hook_rpc = __esm(() => {
108647
108693
  // src/lib/codex-hook-trust-identity.ts
108648
108694
  import { realpathSync as realpathSync13 } from "fs";
108649
108695
  import { dirname as dirname30, isAbsolute as isAbsolute25, join as join56 } from "path";
108650
- import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
108696
+ import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
108651
108697
  function inspectRecordedSkillsCli(command, expected) {
108652
108698
  need4(isAbsolute25(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
108653
108699
  const resolved = realpathSync13(command);
@@ -108657,7 +108703,7 @@ function inspectRecordedSkillsCli(command, expected) {
108657
108703
  need4(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join56(dirname30(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
108658
108704
  need4((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
108659
108705
  const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
108660
- need4(isDeepStrictEqual9(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
108706
+ need4(isDeepStrictEqual10(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
108661
108707
  return { receipt, recheck() {
108662
108708
  need4(realpathSync13(command) === resolved, "SKILLS_COMMAND_CHANGED");
108663
108709
  unchanged2(cli);
@@ -108693,19 +108739,19 @@ var init_codex_hook_trust_identity = __esm(() => {
108693
108739
  });
108694
108740
 
108695
108741
  // src/lib/codex-hook-policy-recovery.ts
108696
- import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
108742
+ import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
108697
108743
  function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
108698
108744
  need4(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
108699
108745
  need4(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
108700
108746
  const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
108701
108747
  const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
108702
108748
  need4(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
108703
- const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual10(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
108749
+ const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual11(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
108704
108750
  need4(changes.length > 0, "RECONCILE_POLICY_CHANGED");
108705
108751
  const compared = structuredClone(current);
108706
108752
  compared.bridge.discovery.claude.roots = oldDiscovery.roots;
108707
108753
  compared.bridge.discovery.claude.sources = oldDiscovery.sources;
108708
- need4(isDeepStrictEqual10(before2, compared), "RECONCILE_POLICY_CHANGED");
108754
+ need4(isDeepStrictEqual11(before2, compared), "RECONCILE_POLICY_CHANGED");
108709
108755
  verifyAgentDiscovery(newDiscovery);
108710
108756
  return { reason: options.reason, changes };
108711
108757
  }
@@ -108721,7 +108767,7 @@ import { createHash as createHash27, randomUUID as randomUUID10 } from "crypto";
108721
108767
  import { execFileSync } from "child_process";
108722
108768
  import { dirname as dirname31, isAbsolute as isAbsolute26, join as join57, resolve as resolve23 } from "path";
108723
108769
  import { homedir as homedir12 } from "os";
108724
- import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
108770
+ import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
108725
108771
  function verifyReleaseArtifact(proof, skillsCli) {
108726
108772
  need4(isAbsolute26(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
108727
108773
  const tarPath = realpathSync14(proof.packageTarPath);
@@ -108763,7 +108809,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108763
108809
  const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
108764
108810
  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 };
108765
108811
  need4(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
108766
- need4(isDeepStrictEqual11(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
108812
+ need4(isDeepStrictEqual12(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
108767
108813
  need4(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
108768
108814
  const policyCurrent = snapshot(join57(dataDir3, "agent-policy.json"), true);
108769
108815
  const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
@@ -108776,7 +108822,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108776
108822
  if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
108777
108823
  need4(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
108778
108824
  const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
108779
- need4(isDeepStrictEqual11(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
108825
+ need4(isDeepStrictEqual12(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
108780
108826
  supersededBinding = true;
108781
108827
  }
108782
108828
  if (supersededBinding || recovery) {
@@ -108812,7 +108858,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108812
108858
  need4(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
108813
108859
  }
108814
108860
  } else
108815
- need4(isDeepStrictEqual11(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
108861
+ need4(isDeepStrictEqual12(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
108816
108862
  const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
108817
108863
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
108818
108864
  const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
@@ -108821,14 +108867,14 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108821
108867
  const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
108822
108868
  if (supersededBinding)
108823
108869
  verifyReleaseArtifact(options.releaseProof, skillsCli);
108824
- const skillsBindingChanged = !isDeepStrictEqual11(skillsCli.receipt, intent.skillsCli);
108870
+ const skillsBindingChanged = !isDeepStrictEqual12(skillsCli.receipt, intent.skillsCli);
108825
108871
  need4(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
108826
108872
  if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
108827
108873
  need4(supersededBinding, "RECONCILE_HOOKS_CHANGED");
108828
108874
  const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
108829
108875
  for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
108830
108876
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
108831
- need4(isDeepStrictEqual11(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
108877
+ need4(isDeepStrictEqual12(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
108832
108878
  }
108833
108879
  }
108834
108880
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
@@ -108851,9 +108897,9 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108851
108897
  delete identity4.command;
108852
108898
  return identity4;
108853
108899
  };
108854
- need4(isDeepStrictEqual11(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
108900
+ need4(isDeepStrictEqual12(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
108855
108901
  if (!plannedKeys.has(expected.key))
108856
- need4(isDeepStrictEqual11(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
108902
+ need4(isDeepStrictEqual12(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
108857
108903
  }
108858
108904
  for (const wanted of intent.hooks) {
108859
108905
  const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join57(home, ".codex/hooks.json"), hooksPath));
@@ -108870,12 +108916,12 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108870
108916
  }
108871
108917
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
108872
108918
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
108873
- need4(layers?.length === 1 && !layers[0].disabledReason && isDeepStrictEqual11(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
108919
+ need4(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
108874
108920
  const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
108875
- need4(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual11(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
108921
+ need4(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual12(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
108876
108922
  const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
108877
108923
  const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
108878
- need4(finalLayers?.length === 1 && !finalLayers[0].disabledReason && isDeepStrictEqual11(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
108924
+ need4(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
108879
108925
  if (recovery) {
108880
108926
  for (const response of [config2, finalConfig]) {
108881
108927
  const layerIndex = response.layers.findIndex((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
@@ -108933,7 +108979,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108933
108979
  const groups = declarations[event];
108934
108980
  need4(Array.isArray(groups), "DECLARATION_CHANGED");
108935
108981
  const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
108936
- need4(matches2.length === 1 && isDeepStrictEqual11(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
108982
+ need4(matches2.length === 1 && isDeepStrictEqual12(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
108937
108983
  expected.push({ event: nativeEvent, key: `${join57(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
108938
108984
  }
108939
108985
  codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
@@ -108941,7 +108987,10 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108941
108987
  need4(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
108942
108988
  const list2 = async () => {
108943
108989
  const response = await rpc.request("hooks/list", { cwds: [home] });
108944
- need4(Array.isArray(response?.data) && response.data.length === 1 && response.data[0].cwd === home && Array.isArray(response.data[0].hooks) && response.data[0].hooks.length <= 1e4 && !response.data[0].errors?.length && !response.data[0].warnings?.length, "NATIVE_DISCOVERY_REFUSED");
108990
+ const nativeRoots = [...new Set([physicalRoot, join57(home, ".codex")])];
108991
+ const coexistenceWarnings = nativeRoots.flatMap((hooksRoot) => nativeRoots.map((configRoot) => `loading hooks from both ${join57(hooksRoot, "hooks.json")} and ${join57(configRoot, "config.toml")}; prefer a single representation for this layer`));
108992
+ const entry = response?.data?.[0];
108993
+ need4(Array.isArray(response?.data) && response.data.length === 1 && entry.cwd === home && Array.isArray(entry.hooks) && entry.hooks.length <= 1e4 && Array.isArray(entry.errors) && entry.errors.length === 0 && Array.isArray(entry.warnings) && entry.warnings.length <= 1 && entry.warnings.every((warning) => typeof warning === "string" && coexistenceWarnings.includes(warning)), "NATIVE_DISCOVERY_REFUSED");
108945
108994
  return response.data[0].hooks;
108946
108995
  };
108947
108996
  const admit = (hooks) => expected.map((wanted) => {
@@ -108957,7 +109006,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108957
109006
  const discovered = await list2(), admitted = admit(discovered);
108958
109007
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
108959
109008
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
108960
- need4(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && isDeepStrictEqual11(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
109009
+ need4(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
108961
109010
  need4(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
108962
109011
  need4(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
108963
109012
  const keys3 = admitted.map((h) => h.key), planned = admitted.filter((h) => !h.enabled || h.trustStatus !== "trusted");
@@ -108996,7 +109045,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108996
109045
  save(join57(journal, "hooks.before.json"), hooksFile.bytes);
108997
109046
  save(join57(journal, "policy.before.json"), policyFile.bytes);
108998
109047
  save(join57(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
108999
- need4(isDeepStrictEqual11(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
109048
+ need4(isDeepStrictEqual12(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
109000
109049
  checkInputs();
109001
109050
  let result2;
109002
109051
  try {
@@ -109010,7 +109059,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
109010
109059
  expectedConfig.hooks.state ??= {};
109011
109060
  for (const h of planned)
109012
109061
  expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
109013
- need4(isDeepStrictEqual11(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
109062
+ need4(isDeepStrictEqual12(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
109014
109063
  const savedConfig = snapshot(join57(journal, "config.before.toml"), true);
109015
109064
  need4(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
109016
109065
  const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
@@ -109018,8 +109067,8 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
109018
109067
  unchanged2(hooksFile);
109019
109068
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
109020
109069
  const current = await list2(), confirmed = admit(current);
109021
- need4(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual11(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
109022
- need4(isDeepStrictEqual11(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
109070
+ need4(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual12(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
109071
+ need4(isDeepStrictEqual12(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
109023
109072
  unchanged2(after2);
109024
109073
  unchanged2(savedConfig);
109025
109074
  unchanged2(hooksFile);
@@ -109049,6 +109098,7 @@ var json2 = (value) => JSON.stringify(value, null, 2) + `
109049
109098
  return copy;
109050
109099
  };
109051
109100
  var init_agent_codex_trust = __esm(() => {
109101
+ init_codex_native_config();
109052
109102
  init_config();
109053
109103
  init_managed_policy();
109054
109104
  init_agent_integration();
@@ -110058,7 +110108,7 @@ function prepareSkill(name, options) {
110058
110108
  let manifest;
110059
110109
  try {
110060
110110
  const parsed = JSON.parse(manifestFile.bytes.toString("utf8"));
110061
- if (!isRecord6(parsed))
110111
+ if (!isRecord7(parsed))
110062
110112
  throw new Error("not an object");
110063
110113
  manifest = parsed;
110064
110114
  } catch {
@@ -110080,7 +110130,7 @@ function prepareSkill(name, options) {
110080
110130
  if (documentKind !== undefined && documentKind !== kind) {
110081
110131
  throw new Error("SKILL.md kind conflicts with the candidate skill.json kind. Review and align both declarations (or remove the optional frontmatter kind), then prepare again; no files were changed.");
110082
110132
  }
110083
- if (manifest.provenance !== undefined && !isRecord6(manifest.provenance))
110133
+ if (manifest.provenance !== undefined && !isRecord7(manifest.provenance))
110084
110134
  throw new Error("skill.json provenance must be an object.");
110085
110135
  const provenance = manifest.provenance;
110086
110136
  const candidate2 = { ...manifest, version: options.version, kind, provenance: { ...provenance } };
@@ -110145,7 +110195,7 @@ function escapedRelativePath(path) {
110145
110195
  return JSON.stringify(bounded);
110146
110196
  }
110147
110197
  function validateRuntimeEntrypoint(candidate2, root2) {
110148
- if (candidate2.kind !== "executable" || !isRecord6(candidate2.runtime))
110198
+ if (candidate2.kind !== "executable" || !isRecord7(candidate2.runtime))
110149
110199
  return;
110150
110200
  const entry = candidate2.runtime.entrypoint;
110151
110201
  if (typeof entry !== "string")
@@ -110155,7 +110205,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
110155
110205
  throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
110156
110206
  }
110157
110207
  }
110158
- function isRecord6(value) {
110208
+ function isRecord7(value) {
110159
110209
  return typeof value === "object" && value !== null && !Array.isArray(value);
110160
110210
  }
110161
110211
  function validateRawCandidate(candidate2) {
@@ -110180,7 +110230,7 @@ function validateRawCandidate(candidate2) {
110180
110230
  if (!Array.isArray(items))
110181
110231
  throw new Error(`skill.json ${field2} must be an array.`);
110182
110232
  for (const item of items) {
110183
- if (!isRecord6(item) || typeof item.name !== "string" || !item.name.trim())
110233
+ if (!isRecord7(item) || typeof item.name !== "string" || !item.name.trim())
110184
110234
  throw new Error(`Invalid skill.json ${field2} name.`);
110185
110235
  if (field2 === "inputs" && (typeof item.type !== "string" || !item.type.trim() || item.required !== undefined && typeof item.required !== "boolean"))
110186
110236
  throw new Error("Invalid skill.json input type or required flag.");
@@ -110199,7 +110249,7 @@ function validateRawCandidate(candidate2) {
110199
110249
  }
110200
110250
  }
110201
110251
  function validateRuntimeEntrypointCompatibility(candidate2) {
110202
- if (candidate2.kind !== "executable" || !isRecord6(candidate2.runtime))
110252
+ if (candidate2.kind !== "executable" || !isRecord7(candidate2.runtime))
110203
110253
  return;
110204
110254
  const runtime = candidate2.runtime.runtime;
110205
110255
  const entrypoint = candidate2.runtime.entrypoint;
@@ -111414,7 +111464,7 @@ async function apiRequest(path, options, instance) {
111414
111464
  const origin = instance ?? getApiUrl(`${(options?.method || "GET").toUpperCase()} ${path}`);
111415
111465
  return new RemoteSkillsAuthClient(origin).request(path, options);
111416
111466
  }
111417
- function isRecord7(value) {
111467
+ function isRecord8(value) {
111418
111468
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
111419
111469
  }
111420
111470
  function commandErrorPayload(err, fallback) {
@@ -111428,7 +111478,7 @@ function commandErrorPayload(err, fallback) {
111428
111478
  ...err.apiUrl ? { apiUrl: err.apiUrl } : {}
111429
111479
  };
111430
111480
  }
111431
- const code2 = isRecord7(err) && typeof err.code === "string" ? err.code : undefined;
111481
+ const code2 = isRecord8(err) && typeof err.code === "string" ? err.code : undefined;
111432
111482
  return {
111433
111483
  error: err?.message || fallback,
111434
111484
  ...code2 ? { code: code2 } : {}
@@ -111456,7 +111506,7 @@ function stringField2(value) {
111456
111506
  return typeof value === "string" && value.length > 0 ? value : undefined;
111457
111507
  }
111458
111508
  function recordField(value) {
111459
- return isRecord7(value) ? value : undefined;
111509
+ return isRecord8(value) ? value : undefined;
111460
111510
  }
111461
111511
  function identityApiKey(live) {
111462
111512
  const root2 = recordField(live);
@@ -111946,7 +111996,7 @@ function registerAuth(parent) {
111946
111996
  } catch {}
111947
111997
  payload.permissions = { publish: access?.permissions?.publish ?? null, profilesWrite: access?.permissions?.profilesWrite ?? null };
111948
111998
  const apiKey = identityApiKey(res);
111949
- if (access?.scopes && (apiKey === undefined || isRecord7(apiKey) && !Object.hasOwn(apiKey, "scopes"))) {
111999
+ if (access?.scopes && (apiKey === undefined || isRecord8(apiKey) && !Object.hasOwn(apiKey, "scopes"))) {
111950
112000
  payload.scopes = access.scopes;
111951
112001
  }
111952
112002
  if (options.json) {
package/bin/mcp.js CHANGED
@@ -20019,7 +20019,7 @@ var package_default;
20019
20019
  var init_package = __esm(() => {
20020
20020
  package_default = {
20021
20021
  name: "@hasna/skills",
20022
- version: "0.9.18",
20022
+ version: "0.9.20",
20023
20023
  description: "Skills library for AI coding agents",
20024
20024
  type: "module",
20025
20025
  bin: {
package/bin/migrate.js CHANGED
@@ -7,7 +7,7 @@ import { join as join5 } from "path";
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "@hasna/skills",
10
- version: "0.9.18",
10
+ version: "0.9.20",
11
11
  description: "Skills library for AI coding agents",
12
12
  type: "module",
13
13
  bin: {
package/bin/server.js CHANGED
@@ -24122,7 +24122,7 @@ var init_dist_es9 = __esm(() => {
24122
24122
  // package.json
24123
24123
  var package_default = {
24124
24124
  name: "@hasna/skills",
24125
- version: "0.9.18",
24125
+ version: "0.9.20",
24126
24126
  description: "Skills library for AI coding agents",
24127
24127
  type: "module",
24128
24128
  bin: {
package/bin/worker.js CHANGED
@@ -24125,7 +24125,7 @@ import { randomUUID as randomUUID6 } from "crypto";
24125
24125
  // package.json
24126
24126
  var package_default = {
24127
24127
  name: "@hasna/skills",
24128
- version: "0.9.18",
24128
+ version: "0.9.20",
24129
24129
  description: "Skills library for AI coding agents",
24130
24130
  type: "module",
24131
24131
  bin: {
package/dist/index.js CHANGED
@@ -9611,7 +9611,7 @@ import { isAbsolute as isAbsolute11, join as join23, resolve as resolve11 } from
9611
9611
  // package.json
9612
9612
  var package_default = {
9613
9613
  name: "@hasna/skills",
9614
- version: "0.9.18",
9614
+ version: "0.9.20",
9615
9615
  description: "Skills library for AI coding agents",
9616
9616
  type: "module",
9617
9617
  bin: {
@@ -0,0 +1,5 @@
1
+ /** Codex config/read can expose serde_json's numeric wrapper for TOML floats.
2
+ * Admit it only against an equal numeric value from the complete disk parse.
3
+ * Ordinary objects, strings, native trust state and unknown fields stay exact.
4
+ */
5
+ export declare function codexNativeConfigEqual(native: unknown, expected: unknown): boolean;
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.9.18",
32376
+ version: "0.9.20",
32377
32377
  description: "Skills library for AI coding agents",
32378
32378
  type: "module",
32379
32379
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.9.18",
3
+ "version": "0.9.20",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {