@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 +84 -34
- package/bin/mcp.js +1 -1
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/codex-native-config.d.ts +5 -0
- package/dist/sdk/index.js +1 -1
- package/package.json +1 -1
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.
|
|
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
|
|
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(
|
|
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
|
|
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) => !
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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 = !
|
|
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(
|
|
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(
|
|
108900
|
+
need4(isDeepStrictEqual12(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
108855
108901
|
if (!plannedKeys.has(expected.key))
|
|
108856
|
-
need4(
|
|
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 &&
|
|
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 ||
|
|
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 &&
|
|
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 &&
|
|
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
|
-
|
|
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 &&
|
|
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(
|
|
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(
|
|
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") &&
|
|
109022
|
-
need4(
|
|
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 (!
|
|
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 && !
|
|
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" || !
|
|
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
|
|
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 (!
|
|
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" || !
|
|
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
|
|
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 =
|
|
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
|
|
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 ||
|
|
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.
|
|
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
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.
|
|
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.
|
|
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.
|
|
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.
|
|
32376
|
+
version: "0.9.20",
|
|
32377
32377
|
description: "Skills library for AI coding agents",
|
|
32378
32378
|
type: "module",
|
|
32379
32379
|
bin: {
|