@hasna/skills 0.10.88 → 0.10.90
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/README.md +36 -3
- package/bin/index.js +196 -102
- package/bin/mcp.js +80 -27
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/cli/commands/agent-integration.d.ts +20 -0
- package/dist/cli/commands/context.d.ts +4 -0
- package/dist/index.js +30 -13
- package/dist/lib/selection-resolver.d.ts +13 -1
- package/dist/lib/skill-context.d.ts +11 -0
- package/dist/runtime-prerequisites.js +3 -2
- package/dist/sdk/index.js +5 -2
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -36888,7 +36888,7 @@ var package_default;
|
|
|
36888
36888
|
var init_package = __esm(() => {
|
|
36889
36889
|
package_default = {
|
|
36890
36890
|
name: "@hasna/skills",
|
|
36891
|
-
version: "0.10.
|
|
36891
|
+
version: "0.10.90",
|
|
36892
36892
|
description: "Skills library for AI coding agents",
|
|
36893
36893
|
type: "module",
|
|
36894
36894
|
bin: {
|
|
@@ -40737,7 +40737,8 @@ var init_codex_native_compatibility = __esm(() => {
|
|
|
40737
40737
|
"codex-cli 0.162.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40738
40738
|
"codex-cli 0.163.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40739
40739
|
"codex-cli 0.164.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40740
|
-
"codex-cli 0.165.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
40740
|
+
"codex-cli 0.165.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40741
|
+
"codex-cli 0.166.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
40741
40742
|
};
|
|
40742
40743
|
SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
|
|
40743
40744
|
});
|
|
@@ -63619,6 +63620,7 @@ var init_selected_document = __esm(() => {
|
|
|
63619
63620
|
});
|
|
63620
63621
|
|
|
63621
63622
|
// src/lib/selection-resolver.ts
|
|
63623
|
+
import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
|
|
63622
63624
|
async function syncSelectionProfile(profileId, options = {}) {
|
|
63623
63625
|
const client = options.client ?? await createProfileClient();
|
|
63624
63626
|
const profile = await client.resolveProfile(profileId);
|
|
@@ -63743,21 +63745,70 @@ function unknownNameRefusal(slug, profile) {
|
|
|
63743
63745
|
return `Skill '${slug}' is not selected by this Skills profile or project lock.${hint} ` + `Read the accepted names with 'skills search <term>' or 'skills list --all --json'; accept one with 'skills pin <name>'. ${ACCEPTED_FORM}`;
|
|
63744
63746
|
}
|
|
63745
63747
|
async function loadSelectedSkill(spec, profileId, options = {}) {
|
|
63746
|
-
|
|
63748
|
+
if (!options.cacheFirst)
|
|
63749
|
+
return readSelectedSkill(spec, profileId, options);
|
|
63750
|
+
const { cacheFirst: _cacheFirst, cached: _cached, authority, ...service } = options;
|
|
63751
|
+
try {
|
|
63752
|
+
return await readSelectedSkill(spec, profileId, { ...service, authority, cached: true });
|
|
63753
|
+
} catch (cacheError) {
|
|
63754
|
+
if (!(cacheError instanceof SkillSelectionError) || !RECOVERABLE_CACHE_ERRORS.has(cacheError.code))
|
|
63755
|
+
throw cacheError;
|
|
63756
|
+
try {
|
|
63757
|
+
return await readSelectedSkill(spec, profileId, service);
|
|
63758
|
+
} catch (serviceError) {
|
|
63759
|
+
if (!(serviceError instanceof SkillSelectionError) || serviceError.code !== "SKILLS_API_UNAVAILABLE")
|
|
63760
|
+
throw serviceError;
|
|
63761
|
+
throw new SkillSelectionError(cacheError.code, "The verified cache can't serve this load and the Skills service can't be reached from here, so it has to run where the network is available. `skills sync` doesn't renew a session's pin.");
|
|
63762
|
+
}
|
|
63763
|
+
}
|
|
63764
|
+
}
|
|
63765
|
+
async function readSelectedSkill(spec, profileId, options) {
|
|
63766
|
+
const context = await resolveSelectionContext(profileId, options).catch((error) => {
|
|
63767
|
+
if (options.cached && options.sessionId && error instanceof SkillSelectionError && error.code === "CACHED_PROFILE_EXPIRED" && readSkillSessionSnapshotIfExists(options.sessionId, options)) {
|
|
63768
|
+
throw new SkillSelectionError("CACHED_PROFILE_EXPIRED", "This session's Skills pin was verified too long ago to read from the cache. Run the same command without --cached: that keeps the pin but needs the network and sign-in. `skills sync` doesn't renew a session's pin.");
|
|
63769
|
+
}
|
|
63770
|
+
throw error;
|
|
63771
|
+
});
|
|
63747
63772
|
const selection = exactProfileSelection(spec, context.receipt.profile);
|
|
63748
63773
|
const entries = await readSelectedEntries(selection, context, options);
|
|
63749
63774
|
const { file, content } = readSelectedDocument(entries, options.file);
|
|
63750
63775
|
const receipt = { ...selection, file, source: options.cached ? "verified-cache" : "api", verifiedAt: context.receipt.verifiedAt };
|
|
63751
|
-
|
|
63752
|
-
|
|
63753
|
-
|
|
63754
|
-
|
|
63755
|
-
|
|
63756
|
-
|
|
63757
|
-
|
|
63758
|
-
|
|
63776
|
+
const sessionRecorded = options.sessionId ? recordSessionLoad(options.sessionId, selection, context, options) : undefined;
|
|
63777
|
+
return { content, selection, receipt, ...sessionRecorded === undefined ? {} : { sessionRecorded } };
|
|
63778
|
+
}
|
|
63779
|
+
function isUnwritableStore(error) {
|
|
63780
|
+
for (let cause = error, depth = 0;cause && depth < 4; cause = cause.cause, depth++)
|
|
63781
|
+
if (UNWRITABLE_CODES.has(cause.code))
|
|
63782
|
+
return true;
|
|
63783
|
+
return false;
|
|
63784
|
+
}
|
|
63785
|
+
function recordSessionLoad(sessionId, selection, context, options) {
|
|
63786
|
+
const key2 = selectionKey(selection);
|
|
63787
|
+
let snapshot2 = context.sessionSnapshot;
|
|
63788
|
+
for (let attempt2 = 0;attempt2 < SESSION_LOAD_RECORD_ATTEMPTS; attempt2++) {
|
|
63789
|
+
try {
|
|
63790
|
+
const session = {
|
|
63791
|
+
...context.receipt,
|
|
63792
|
+
sessionId,
|
|
63793
|
+
loaded: [...new Set([...context.session?.loaded ?? [], key2])],
|
|
63794
|
+
...context.projectLock ? { projectLock: context.projectLock } : {}
|
|
63795
|
+
};
|
|
63796
|
+
writeSkillSession(session, { current: snapshot2, parent: context.parentSnapshot }, options);
|
|
63797
|
+
return true;
|
|
63798
|
+
} catch (error) {
|
|
63799
|
+
const blocked = isUnwritableStore(error) || error instanceof SkillSelectionError && error.code === "SESSION_WRITE_BUSY";
|
|
63800
|
+
if (!blocked && !(error instanceof SkillSelectionError && error.code === "SESSION_CONTEXT_CONFLICT"))
|
|
63801
|
+
throw error;
|
|
63802
|
+
const current = readSkillSessionSnapshotIfExists(sessionId, options);
|
|
63803
|
+
if (current ? !isDeepStrictEqual11(current.receipt.profile, context.receipt.profile) : !blocked) {
|
|
63804
|
+
throw new SkillSelectionError("SESSION_CONTEXT_CONFLICT", "The Skills session's pin changed while this skill was loading, so its content no longer belongs to that pin. Load it again.");
|
|
63805
|
+
}
|
|
63806
|
+
if (blocked)
|
|
63807
|
+
return false;
|
|
63808
|
+
snapshot2 = skillSessionSnapshotBinding(current);
|
|
63809
|
+
}
|
|
63759
63810
|
}
|
|
63760
|
-
return
|
|
63811
|
+
return false;
|
|
63761
63812
|
}
|
|
63762
63813
|
async function pinSelectedSkillVersion(spec, profileId, options) {
|
|
63763
63814
|
const context = await resolveSelectionContext(profileId, options);
|
|
@@ -63786,13 +63837,15 @@ async function selectedSkillRequirements(spec, profileId, options = {}) {
|
|
|
63786
63837
|
}
|
|
63787
63838
|
return { ...getSkillRequirementsFromContent(selection.slug, texts, dependencies), selection };
|
|
63788
63839
|
}
|
|
63789
|
-
var ACCEPTED_FORM = "Accepted form: '<slug>' or '<slug>@<version>'.";
|
|
63840
|
+
var ACCEPTED_FORM = "Accepted form: '<slug>' or '<slug>@<version>'.", RECOVERABLE_CACHE_ERRORS, SESSION_LOAD_RECORD_ATTEMPTS = 8, UNWRITABLE_CODES;
|
|
63790
63841
|
var init_selection_resolver = __esm(() => {
|
|
63791
63842
|
init_profile_client();
|
|
63792
63843
|
init_skillinfo();
|
|
63793
63844
|
init_search();
|
|
63794
63845
|
init_selected_document();
|
|
63795
63846
|
init_selection_cache();
|
|
63847
|
+
RECOVERABLE_CACHE_ERRORS = new Set(["CACHED_PROFILE_EXPIRED", "CACHED_PROFILE_MISSING", "CACHED_BUNDLE_MISSING"]);
|
|
63848
|
+
UNWRITABLE_CODES = new Set(["EACCES", "EPERM", "EROFS", "ENOSPC", "EDQUOT"]);
|
|
63796
63849
|
});
|
|
63797
63850
|
|
|
63798
63851
|
// src/lib/selected-manifest.ts
|
|
@@ -64534,7 +64587,7 @@ var init_claude_marketplace_registry = __esm(() => {
|
|
|
64534
64587
|
});
|
|
64535
64588
|
|
|
64536
64589
|
// src/lib/codex-hook-trust-layout.ts
|
|
64537
|
-
import { isDeepStrictEqual as
|
|
64590
|
+
import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
|
|
64538
64591
|
function codexTrustTextWitness(text2, keys3, canonicalize = true) {
|
|
64539
64592
|
const parsed = Bun.TOML.parse(text2), wanted = new Set(keys3);
|
|
64540
64593
|
const headers = [...text2.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
|
|
@@ -64599,7 +64652,7 @@ function codexTrustTextWitness(text2, keys3, canonicalize = true) {
|
|
|
64599
64652
|
if (expected.hooks)
|
|
64600
64653
|
delete expected.hooks.state;
|
|
64601
64654
|
try {
|
|
64602
|
-
if (!
|
|
64655
|
+
if (!isDeepStrictEqual12(prune(Bun.TOML.parse(noState)), prune(expected)))
|
|
64603
64656
|
throw fail3();
|
|
64604
64657
|
} catch {
|
|
64605
64658
|
throw fail3();
|
|
@@ -64669,13 +64722,13 @@ var init_codex_hook_trust_layout = () => {};
|
|
|
64669
64722
|
|
|
64670
64723
|
// src/lib/codex-hook-additions-review.ts
|
|
64671
64724
|
import { isAbsolute as isAbsolute29 } from "path";
|
|
64672
|
-
import { isDeepStrictEqual as
|
|
64725
|
+
import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
|
|
64673
64726
|
function exactKeys3(value, keys3) {
|
|
64674
|
-
need8(value && typeof value === "object" && !Array.isArray(value) &&
|
|
64727
|
+
need8(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual13(Object.keys(value).sort(), [...keys3].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
64675
64728
|
}
|
|
64676
64729
|
function readReviewedAdditionTrustStates(proof, before2, current, journalHooks) {
|
|
64677
64730
|
const captured = proofs.get(proof);
|
|
64678
|
-
need8(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 &&
|
|
64731
|
+
need8(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual13(captured.journalHooks, journalHooks.map(({ key: key2, currentHash }) => ({ key: key2, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
|
|
64679
64732
|
captured.recheck();
|
|
64680
64733
|
unchanged2(before2);
|
|
64681
64734
|
unchanged2(current);
|
|
@@ -64698,7 +64751,7 @@ function reviewNativeHookAdditions(options) {
|
|
|
64698
64751
|
expectedProducer.hooks.state ??= {};
|
|
64699
64752
|
for (const hook of options.journalHooks)
|
|
64700
64753
|
expectedProducer.hooks.state[hook.key] = { ...expectedProducer.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
64701
|
-
need8(
|
|
64754
|
+
need8(isDeepStrictEqual13(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
64702
64755
|
need8(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
64703
64756
|
const expectedHooks = JSON.parse(options.hooksBefore.text), currentHooks = JSON.parse(options.hooksCurrent.text), expectedConfig = structuredClone(producer);
|
|
64704
64757
|
need8(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
@@ -64727,9 +64780,9 @@ function reviewNativeHookAdditions(options) {
|
|
|
64727
64780
|
expectedHooks.hooks[event] = [...groups, { ...event === "PreToolUse" ? { matcher: hook.matcher } : {}, hooks: [{ type: "command", command: hook.command, timeout: hook.timeoutSec }] }];
|
|
64728
64781
|
expectedConfig.hooks.state[key2] = trustState;
|
|
64729
64782
|
}
|
|
64730
|
-
need8(
|
|
64783
|
+
need8(isDeepStrictEqual13(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
64731
64784
|
const keys3 = added.map((hook) => hook.key);
|
|
64732
|
-
need8(
|
|
64785
|
+
need8(isDeepStrictEqual13(expectedConfig, structure(options.configCurrent.text)) && codexTrustReconcileWitness(producerConfig.text, keys3) === codexTrustReconcileWitness(options.configCurrent.text, keys3) && codexTrustUnmanagedSemantic(producerConfig.text, keys3) === codexTrustUnmanagedSemantic(options.configCurrent.text, keys3), "RECONCILE_ADDITIONS_CONFIG");
|
|
64733
64786
|
const inputs = [reviewFile, producerConfig, producerHooks, options.intent, options.policy, options.configBefore, options.configCurrent, options.hooksBefore, options.hooksCurrent];
|
|
64734
64787
|
const recheck = () => {
|
|
64735
64788
|
for (const input of inputs)
|
|
@@ -64752,7 +64805,7 @@ var init_codex_hook_additions_review = __esm(() => {
|
|
|
64752
64805
|
|
|
64753
64806
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
64754
64807
|
import { createHash as createHash32 } from "crypto";
|
|
64755
|
-
import { isDeepStrictEqual as
|
|
64808
|
+
import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
|
|
64756
64809
|
function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, additions) {
|
|
64757
64810
|
const journalHooks = hooks.map(({ key: key2, currentHash }) => ({ key: key2, currentHash }));
|
|
64758
64811
|
const additionStates = additions ? readReviewedAdditionTrustStates(additions, before2, current, journalHooks) : [];
|
|
@@ -64766,11 +64819,11 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
|
|
|
64766
64819
|
need8(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
|
|
64767
64820
|
need8(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
|
|
64768
64821
|
const typed = binding.sources.filter((source) => source.path === current.file && source.format === "toml");
|
|
64769
|
-
need8(typed.length === 1 && typed[0].hashMode === undefined &&
|
|
64822
|
+
need8(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual14(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
|
|
64770
64823
|
const original = structure2(before2.text), actual = structure2(current.text);
|
|
64771
64824
|
const project = (value) => Object.fromEntries(fields.map((field3) => [field3, value[field3] ?? null]));
|
|
64772
64825
|
const projection = sha5(JSON.stringify(project(original)));
|
|
64773
|
-
need8(typed[0].sha256 === projection && sha5(JSON.stringify(project(actual))) === projection &&
|
|
64826
|
+
need8(typed[0].sha256 === projection && sha5(JSON.stringify(project(actual))) === projection && isDeepStrictEqual14(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
|
|
64774
64827
|
const keys3 = [...journalHooks.map((hook) => hook.key), ...additionStates.map((hook) => hook.key)];
|
|
64775
64828
|
need8(journalHooks.length > 0 && keys3.length <= 100 && new Set(keys3).size === keys3.length && journalHooks.every((hook) => typeof hook.key === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash)), "RECONCILE_DISCOVERY_TRUST_WITNESS");
|
|
64776
64829
|
const expected = structuredClone(original);
|
|
@@ -64780,7 +64833,7 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
|
|
|
64780
64833
|
expected.hooks.state[hook.key] = { ...expected.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
64781
64834
|
for (const { key: key2, state } of additionStates)
|
|
64782
64835
|
expected.hooks.state[key2] = { ...state };
|
|
64783
|
-
need8(
|
|
64836
|
+
need8(isDeepStrictEqual14(expected, actual) && codexTrustReconcileWitness(before2.text, keys3) === codexTrustReconcileWitness(current.text, keys3) && codexTrustUnmanagedSemantic(before2.text, keys3) === codexTrustUnmanagedSemantic(current.text, keys3), "RECONCILE_DISCOVERY_TRUST_WITNESS");
|
|
64784
64837
|
unchanged2(before2);
|
|
64785
64838
|
unchanged2(current);
|
|
64786
64839
|
const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: discoveryDigest(binding), typedProjectionSha256: projection });
|
|
@@ -64822,7 +64875,7 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
64822
64875
|
import { createHash as createHash33 } from "crypto";
|
|
64823
64876
|
import { lstatSync as lstatSync35, opendirSync as opendirSync6, readFileSync as readFileSync27, readdirSync as readdirSync16, realpathSync as realpathSync12 } from "fs";
|
|
64824
64877
|
import { basename as basename18, dirname as dirname29, isAbsolute as isAbsolute30, join as join46, relative as relative9, resolve as resolve29, sep as sep14 } from "path";
|
|
64825
|
-
import { isDeepStrictEqual as
|
|
64878
|
+
import { isDeepStrictEqual as isDeepStrictEqual15 } from "util";
|
|
64826
64879
|
function discoveryRootUnresolved(agent, command, detail) {
|
|
64827
64880
|
return new Error(`${DISCOVERY_ROOT_UNRESOLVED}: ${agent} discovery cannot resolve its "${command}" executable: ${detail}. The reviewed discovery is unchanged; this is an environment gap, not drift.`);
|
|
64828
64881
|
}
|
|
@@ -64975,8 +65028,8 @@ function projectNativeDiscoveryFields(text3, format, fields2, path) {
|
|
|
64975
65028
|
}
|
|
64976
65029
|
function isSupersededSettingsProjection(agent, configPath, source) {
|
|
64977
65030
|
if (agent === "sumi")
|
|
64978
|
-
return source.path === configPath && source.format === "json" &&
|
|
64979
|
-
return agent === "codex" && source.path === configPath && source.format === "toml" &&
|
|
65031
|
+
return source.path === configPath && source.format === "json" && isDeepStrictEqual15(source.fields, [...SUMI_DISCOVERY_PROJECTION_FIELDS]);
|
|
65032
|
+
return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual15(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
|
|
64980
65033
|
}
|
|
64981
65034
|
function supersedesSettingsProjection(agent, sources, configPath) {
|
|
64982
65035
|
if (agent === "sumi")
|
|
@@ -64997,7 +65050,7 @@ function projected(source, changes, budget3 = discoveryByteBudget()) {
|
|
|
64997
65050
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || !Array.isArray(source.hookSources))
|
|
64998
65051
|
throw new Error("Codex V6 requires exact reviewed hook sources");
|
|
64999
65052
|
const current = captureCodexSettingsV6(source.path, source.hookSources, budget3);
|
|
65000
|
-
if (current.sha256 !== source.sha256 || !
|
|
65053
|
+
if (current.sha256 !== source.sha256 || !isDeepStrictEqual15(current.hookSources, source.hookSources))
|
|
65001
65054
|
throw new Error("Codex hook provider or dependency changed; explicit discovery review required");
|
|
65002
65055
|
return changes ? captureCodexSettingsV6(source.path, source.hookSources, budget3, changes).sha256 : current.sha256;
|
|
65003
65056
|
}
|
|
@@ -65201,7 +65254,7 @@ function captureRetiredCodexDiscovery(binding, controls, rules) {
|
|
|
65201
65254
|
return current;
|
|
65202
65255
|
const installation = codexInstallationRoots(binding);
|
|
65203
65256
|
const directories = (binding.directories ?? []).filter((directory2) => !installation.some((root2) => directory2.path === root2 || directory2.path.startsWith(root2 + sep14) || root2.startsWith(directory2.path + sep14)));
|
|
65204
|
-
if (previous &&
|
|
65257
|
+
if (previous && isDeepStrictEqual15(previous.roots, roots) && isDeepStrictEqual15(previous.parents, parents3) && isDeepStrictEqual15(previous.directories.map((item) => item.path), directories.map((item) => item.path)))
|
|
65205
65258
|
return { ...current, codexRetiredMaterializations: previous };
|
|
65206
65259
|
return { ...current, codexRetiredMaterializations: { roots, parents: parents3, directories: captureDiscoveryDirectoryProjection(directories.map((item) => item.path), roots) } };
|
|
65207
65260
|
}
|
|
@@ -65322,7 +65375,7 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases, narrowe
|
|
|
65322
65375
|
if (reviewedRootAliases !== undefined) {
|
|
65323
65376
|
const alias = reviewedRootAliases.find((alias2) => alias2.agent === "codex");
|
|
65324
65377
|
const expected = alias ? { alias: alias.alias, target: alias.target } : null;
|
|
65325
|
-
if (!
|
|
65378
|
+
if (!isDeepStrictEqual15(proof.hookRootAlias, expected))
|
|
65326
65379
|
throw new Error("Semantic cache hook alias differs from reviewed root binding");
|
|
65327
65380
|
}
|
|
65328
65381
|
const controls = binding.codexDisabledPluginSkills;
|
|
@@ -65332,7 +65385,7 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases, narrowe
|
|
|
65332
65385
|
if (controls.some((control) => dirname29(dirname29(control.pluginParent)) !== cacheRoot))
|
|
65333
65386
|
throw new Error("Codex semantic cache names another enrolled cache");
|
|
65334
65387
|
const reviewedHookParents = proof.reviewedHookParents ?? [];
|
|
65335
|
-
if (!Array.isArray(reviewedHookParents) || reviewedHookParents.length > 4096 || reviewedHookParents.some((parent) => !parent || !(parent.installation === "remote-receipt" && Object.keys(parent).sort().join(",") === "installation,namespace,pluginId,pluginParent,remotePluginId,role" && typeof parent.remotePluginId === "string" || parent.installation === "local-marketplace" && Object.keys(parent).sort().join(",") === "installation,marketplaceSha256,marketplaceSourcePath,namespace,pluginId,pluginParent,role" && typeof parent.marketplaceSourcePath === "string" && /^[a-f0-9]{64}$/.test(parent.marketplaceSha256 ?? "")) || parent.role !== "reviewed-hook" || typeof parent.pluginId !== "string" || typeof parent.namespace !== "string" || typeof parent.pluginParent !== "string") || new Set(reviewedHookParents.map((parent) => parent.pluginParent)).size !== reviewedHookParents.length || !
|
|
65388
|
+
if (!Array.isArray(reviewedHookParents) || reviewedHookParents.length > 4096 || reviewedHookParents.some((parent) => !parent || !(parent.installation === "remote-receipt" && Object.keys(parent).sort().join(",") === "installation,namespace,pluginId,pluginParent,remotePluginId,role" && typeof parent.remotePluginId === "string" || parent.installation === "local-marketplace" && Object.keys(parent).sort().join(",") === "installation,marketplaceSha256,marketplaceSourcePath,namespace,pluginId,pluginParent,role" && typeof parent.marketplaceSourcePath === "string" && /^[a-f0-9]{64}$/.test(parent.marketplaceSha256 ?? "")) || parent.role !== "reviewed-hook" || typeof parent.pluginId !== "string" || typeof parent.namespace !== "string" || typeof parent.pluginParent !== "string") || new Set(reviewedHookParents.map((parent) => parent.pluginParent)).size !== reviewedHookParents.length || !isDeepStrictEqual15((proof.witness.hookParents ?? []).map(({ manifestSha256: _manifest, hooksSha256: _hooks, receiptSha256: _receipt, ...parent }) => parent), reviewedHookParents)) {
|
|
65336
65389
|
throw new Error("Invalid reviewed native-hook cache role");
|
|
65337
65390
|
}
|
|
65338
65391
|
for (const parent of reviewedHookParents)
|
|
@@ -65342,7 +65395,7 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases, narrowe
|
|
|
65342
65395
|
const hookParentPaths = reviewedHookParents.map((parent) => parent.pluginParent);
|
|
65343
65396
|
const sources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParentPaths));
|
|
65344
65397
|
const directories = (binding.directories ?? []).filter((directory2) => codexSemanticCacheDirectoryRole(directory2.path, cacheRoot));
|
|
65345
|
-
if (!directories.length || !
|
|
65398
|
+
if (!directories.length || !isDeepStrictEqual15(sources, proof.supersededSources) || !isDeepStrictEqual15(directories, proof.supersededDirectories))
|
|
65346
65399
|
throw new Error("Codex semantic cache provenance changed");
|
|
65347
65400
|
const configPath = proof.configPath;
|
|
65348
65401
|
if (!isAbsolute30(configPath) || resolve29(configPath) !== configPath || basename18(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
|
|
@@ -65388,8 +65441,8 @@ function verifyDiscovery(binding, codexRecovery, reviewedRootAliases, witnessTol
|
|
|
65388
65441
|
if (omitted.some((root2) => !retiredRoots.includes(root2)))
|
|
65389
65442
|
throw new Error("Missing reviewed directory membership inventory; provide a fresh discovery review");
|
|
65390
65443
|
const current = captureDiscoveryDirectoryProjection(ordinary.map((item) => item.path), retiredRoots).map(({ entries, ...item }) => item);
|
|
65391
|
-
if (!
|
|
65392
|
-
const changed = projection.filter((item, index) => !
|
|
65444
|
+
if (!isDeepStrictEqual15(current, projection)) {
|
|
65445
|
+
const changed = projection.filter((item, index) => !isDeepStrictEqual15(current[index], item));
|
|
65393
65446
|
for (const item of changed.length && current.length === projection.length ? changed : [null])
|
|
65394
65447
|
witnessChanged(new NativeDiscoveryWitnessChange("membership", item?.path ?? null, "Native discovery directory membership changed outside retired Codex roots"), witnessTolerance, item !== null && witnessTolerance?.acceptsMembership(item.path) === true);
|
|
65395
65448
|
}
|
|
@@ -65412,7 +65465,7 @@ function verifyDiscovery(binding, codexRecovery, reviewedRootAliases, witnessTol
|
|
|
65412
65465
|
safe6(source.path);
|
|
65413
65466
|
continue;
|
|
65414
65467
|
}
|
|
65415
|
-
if (semanticCache?.supersededSources.some((previous) =>
|
|
65468
|
+
if (semanticCache?.supersededSources.some((previous) => isDeepStrictEqual15(previous, source))) {
|
|
65416
65469
|
safe6(source.path);
|
|
65417
65470
|
continue;
|
|
65418
65471
|
}
|
|
@@ -65537,7 +65590,7 @@ function rebindAgentDiscovery(binding, changes) {
|
|
|
65537
65590
|
const installationRoots = codexInstallationRoots(binding), absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredCodexRoots(binding).filter((root2) => !lstatSync35(root2, { throwIfNoEntry: false }))];
|
|
65538
65591
|
const rebound = { ...binding, sources: binding.sources.map((source) => {
|
|
65539
65592
|
assertMarketplaceBinding(binding, source);
|
|
65540
|
-
if (semanticCache?.supersededSources.some((previous) =>
|
|
65593
|
+
if (semanticCache?.supersededSources.some((previous) => isDeepStrictEqual15(previous, source))) {
|
|
65541
65594
|
if (changes.has(source.path))
|
|
65542
65595
|
throw new Error("Codex semantic cache sources cannot be written by hook rendering");
|
|
65543
65596
|
return source;
|
|
@@ -65678,7 +65731,7 @@ function verifyAutomaticDiscoveryClosure(binding, options) {
|
|
|
65678
65731
|
if (JSON.stringify(current) === JSON.stringify(binding))
|
|
65679
65732
|
return;
|
|
65680
65733
|
const reviewedWithRuntime = (binding.builtinNames?.length ?? 0) > 0 || binding.sources.some((source) => basename18(source.path) === "package.json");
|
|
65681
|
-
const otherwiseCurrent = current.method === binding.method && JSON.stringify(current.roots) === JSON.stringify(binding.roots) && JSON.stringify(current.directories) === JSON.stringify(binding.directories) && current.sources.every((source) => binding.sources.some((saved) =>
|
|
65734
|
+
const otherwiseCurrent = current.method === binding.method && JSON.stringify(current.roots) === JSON.stringify(binding.roots) && JSON.stringify(current.directories) === JSON.stringify(binding.directories) && current.sources.every((source) => binding.sources.some((saved) => isDeepStrictEqual15(saved, source)));
|
|
65682
65735
|
if (command && gap && runtime === null && reviewedWithRuntime && otherwiseCurrent)
|
|
65683
65736
|
throw discoveryRootUnresolved(binding.agent, command, gap);
|
|
65684
65737
|
if (options.witnessTolerance && collectAutomaticWitnessChanges(binding, current, options.witnessTolerance))
|
|
@@ -66156,7 +66209,7 @@ function resolveDiscovery(options, exclusion) {
|
|
|
66156
66209
|
const parents3 = [...new Set([...(retained.codexDisabledPluginSkills ?? []).map((control) => control.pluginParent), ...proof.appOnlyParents.map((parent) => parent.pluginParent)])];
|
|
66157
66210
|
covered = covered.filter((source) => !codexSemanticCacheSourceRole(source, proof.witness.cacheRoot, parents3));
|
|
66158
66211
|
}
|
|
66159
|
-
if (covered.some((source) => !retained.sources.some((saved) =>
|
|
66212
|
+
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual15(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
66160
66213
|
unresolved("retained review is missing current runtime discovery coverage");
|
|
66161
66214
|
return retained;
|
|
66162
66215
|
}
|
|
@@ -66214,7 +66267,7 @@ function resolveDiscovery(options, exclusion) {
|
|
|
66214
66267
|
throw new Error("Retired native materialization changed during discovery review");
|
|
66215
66268
|
}
|
|
66216
66269
|
const combined = [...reviewedSources, ...reviewedSourcesWithManifestProjection];
|
|
66217
|
-
const unique = combined.filter((source, index) => combined.findIndex((candidate2) =>
|
|
66270
|
+
const unique = combined.filter((source, index) => combined.findIndex((candidate2) => isDeepStrictEqual15(candidate2, source)) === index);
|
|
66218
66271
|
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: unique, ...agent === "gemini" ? { builtinNames } : {} };
|
|
66219
66272
|
}
|
|
66220
66273
|
function plugin(root2) {
|
|
@@ -92729,7 +92782,7 @@ var init_skill_relevance = __esm(() => {
|
|
|
92729
92782
|
// src/lib/skill-context.ts
|
|
92730
92783
|
import { createHash as createHash38 } from "crypto";
|
|
92731
92784
|
import { resolve as resolve32 } from "path";
|
|
92732
|
-
import { isDeepStrictEqual as
|
|
92785
|
+
import { isDeepStrictEqual as isDeepStrictEqual16 } from "util";
|
|
92733
92786
|
function pathMatch(pattern, path) {
|
|
92734
92787
|
if (!pattern || pattern.length > 512)
|
|
92735
92788
|
return false;
|
|
@@ -92755,6 +92808,12 @@ async function buildSkillContextOnce(input2, options, mayResolveAgain) {
|
|
|
92755
92808
|
if (maxChars !== undefined && (!Number.isInteger(maxChars) || maxChars < 512 || maxChars > 64000) || !Number.isInteger(maxSkills) || maxSkills < 1 || maxSkills > 20) {
|
|
92756
92809
|
throw new SkillSelectionError("INVALID_CONTEXT_BUDGET", "Context limits must be 512\u201364000 characters and 1\u201320 skills.");
|
|
92757
92810
|
}
|
|
92811
|
+
const minPromptPhraseWords = options.minPromptPhraseWords ?? 0;
|
|
92812
|
+
const inheritedBodies = options.inheritedBodies ?? HISTORY_BODY_LIMITS["subagent-inherit"];
|
|
92813
|
+
if (!Number.isInteger(minPromptPhraseWords) || minPromptPhraseWords < 0 || !Number.isInteger(inheritedBodies) || inheritedBodies < 0) {
|
|
92814
|
+
throw new SkillSelectionError("INVALID_CONTEXT_BUDGET", "The prompt phrase and inherited body limits must be whole numbers of 0 or more.");
|
|
92815
|
+
}
|
|
92816
|
+
const historyBodyLimits = { ...HISTORY_BODY_LIMITS, "subagent-inherit": inheritedBodies };
|
|
92758
92817
|
const profileId = input2.profileId ?? "default";
|
|
92759
92818
|
const sessionId = input2.sessionId ? input2.agentId ? `${input2.sessionId}:${input2.agentId}` : input2.sessionId : undefined;
|
|
92760
92819
|
if (input2.parentSessionId !== undefined) {
|
|
@@ -92784,8 +92843,9 @@ async function buildSkillContextOnce(input2, options, mayResolveAgain) {
|
|
|
92784
92843
|
const key2 = selectionKey(selection);
|
|
92785
92844
|
if (restoredOrder.has(key2))
|
|
92786
92845
|
return [{ selection, reason: "session-restore", priority: 6, score: 2000, recency: restoredOrder.get(key2) }];
|
|
92787
|
-
|
|
92788
|
-
|
|
92846
|
+
const inherited = inheritedOrder.has(key2) ? { selection, reason: "subagent-inherit", priority: 6, score: 2000, recency: inheritedOrder.get(key2) } : undefined;
|
|
92847
|
+
if (inherited && inheritedBodies > 0)
|
|
92848
|
+
return [inherited];
|
|
92789
92849
|
if (explicit.has(key2))
|
|
92790
92850
|
return [{ selection, reason: "explicit", priority: 5, score: 1000 }];
|
|
92791
92851
|
if (selection.triggers?.always)
|
|
@@ -92794,7 +92854,10 @@ async function buildSkillContextOnce(input2, options, mayResolveAgain) {
|
|
|
92794
92854
|
if (matchedPath)
|
|
92795
92855
|
return [{ selection, reason: "path", priority: 3, score: 500 }];
|
|
92796
92856
|
const match = relevance.get(key2);
|
|
92797
|
-
|
|
92857
|
+
const weak = match !== undefined && (match.weak || match.priority === 1 && !match.phrases.some((phrase) => phrase.split(" ").length >= minPromptPhraseWords));
|
|
92858
|
+
if (match && !(inherited && weak))
|
|
92859
|
+
return [{ selection, reason: "prompt", priority: match.priority, score: match.score, weak }];
|
|
92860
|
+
return inherited ? [inherited] : [];
|
|
92798
92861
|
}).sort((a, b) => b.priority - a.priority || (b.recency ?? -1) - (a.recency ?? -1) || b.score - a.score || a.selection.slug.localeCompare(b.selection.slug));
|
|
92799
92862
|
const historyOffered = new Map;
|
|
92800
92863
|
const candidates = ranked.filter((candidate2) => {
|
|
@@ -92804,6 +92867,9 @@ async function buildSkillContextOnce(input2, options, mayResolveAgain) {
|
|
|
92804
92867
|
historyOffered.set(candidate2.reason, count + 1);
|
|
92805
92868
|
return count < HISTORY_CANDIDATE_LIMIT;
|
|
92806
92869
|
});
|
|
92870
|
+
const pointerSession = sessionId && /^[A-Za-z0-9._:@][A-Za-z0-9._:@-]{0,255}$/.test(sessionId) ? ` --session ${sessionId}` : "";
|
|
92871
|
+
const pointerCache = options.cached || options.pointerCacheFirst ? " --cache-first" : "";
|
|
92872
|
+
const loadCommandFor = (selection) => `skills load ${selection.slug}@${selection.version} --selection-profile ${profile.profileId}${pointerCache}${pointerSession}`;
|
|
92807
92873
|
const delivered = [];
|
|
92808
92874
|
let selections = [];
|
|
92809
92875
|
const omitted = [];
|
|
@@ -92813,7 +92879,7 @@ async function buildSkillContextOnce(input2, options, mayResolveAgain) {
|
|
|
92813
92879
|
const { selection, reason: reason2 } = candidates[index];
|
|
92814
92880
|
if (!input2.restore && !explicit.has(selectionKey(selection)) && loaded.has(selectionKey(selection)))
|
|
92815
92881
|
continue;
|
|
92816
|
-
const loadCommand =
|
|
92882
|
+
const loadCommand = loadCommandFor(selection);
|
|
92817
92883
|
if (selections.length >= maxSkills || ambiguous && reason2 === "prompt") {
|
|
92818
92884
|
omitted.push({ slug: selection.slug, version: selection.version, reason: "skill-limit", loadCommand });
|
|
92819
92885
|
continue;
|
|
@@ -92822,7 +92888,7 @@ async function buildSkillContextOnce(input2, options, mayResolveAgain) {
|
|
|
92822
92888
|
omitted.push({ slug: selection.slug, version: selection.version, reason: "weak-match", loadCommand });
|
|
92823
92889
|
continue;
|
|
92824
92890
|
}
|
|
92825
|
-
const historyLimit =
|
|
92891
|
+
const historyLimit = historyBodyLimits[reason2];
|
|
92826
92892
|
if (historyLimit !== undefined) {
|
|
92827
92893
|
const delivered2 = historyBodies.get(reason2) ?? 0;
|
|
92828
92894
|
if (delivered2 >= historyLimit) {
|
|
@@ -92833,12 +92899,13 @@ async function buildSkillContextOnce(input2, options, mayResolveAgain) {
|
|
|
92833
92899
|
if (reason2 === "prompt") {
|
|
92834
92900
|
const candidate2 = candidates[index];
|
|
92835
92901
|
let end = index;
|
|
92836
|
-
while (end + 1 < candidates.length && candidates[end + 1].reason === "prompt" && candidates[end + 1].priority === candidate2.priority && candidates[end + 1].score === candidate2.score
|
|
92902
|
+
while (end + 1 < candidates.length && candidates[end + 1].reason === "prompt" && candidates[end + 1].priority === candidate2.priority && candidates[end + 1].score === candidate2.score)
|
|
92837
92903
|
end++;
|
|
92838
|
-
const
|
|
92904
|
+
const block = candidates.slice(index, end + 1).filter((entry) => explicit.has(selectionKey(entry.selection)) || !loaded.has(selectionKey(entry.selection)));
|
|
92905
|
+
const tied = block.filter((entry) => !entry.weak);
|
|
92839
92906
|
if (tied.length > maxSkills - selections.length) {
|
|
92840
|
-
for (const entry of
|
|
92841
|
-
omitted.push({ slug: entry.selection.slug, version: entry.selection.version, reason: "ambiguous-match", loadCommand:
|
|
92907
|
+
for (const entry of block)
|
|
92908
|
+
omitted.push({ slug: entry.selection.slug, version: entry.selection.version, reason: entry.weak ? "weak-match" : "ambiguous-match", loadCommand: loadCommandFor(entry.selection) });
|
|
92842
92909
|
ambiguous = true;
|
|
92843
92910
|
index = end;
|
|
92844
92911
|
continue;
|
|
@@ -92865,7 +92932,7 @@ ${content}`;
|
|
|
92865
92932
|
return considered.has(key2) || !explicit.has(key2) && loaded.has(key2);
|
|
92866
92933
|
});
|
|
92867
92934
|
for (const offer of offers)
|
|
92868
|
-
omitted.push({ slug: offer.selection.slug, version: offer.selection.version, reason: offer.reason, loadCommand:
|
|
92935
|
+
omitted.push({ slug: offer.selection.slug, version: offer.selection.version, reason: offer.reason, loadCommand: loadCommandFor(offer.selection) });
|
|
92869
92936
|
let notice;
|
|
92870
92937
|
if (sessionId) {
|
|
92871
92938
|
if (!resolved.session || [...loaded].some((key2) => !previouslyLoaded.has(key2))) {
|
|
@@ -92881,7 +92948,7 @@ ${content}`;
|
|
|
92881
92948
|
slug: selection.slug,
|
|
92882
92949
|
version: selection.version,
|
|
92883
92950
|
reason: "write-busy",
|
|
92884
|
-
loadCommand:
|
|
92951
|
+
loadCommand: loadCommandFor(selection)
|
|
92885
92952
|
})));
|
|
92886
92953
|
selections = selections.filter((selection) => !unrecorded.has(selectionKey(selection)));
|
|
92887
92954
|
delivered.splice(0, delivered.length, ...delivered.filter((entry) => !unrecorded.has(entry.key)));
|
|
@@ -92916,7 +92983,7 @@ function parentPinUnchanged(resolved, options) {
|
|
|
92916
92983
|
return false;
|
|
92917
92984
|
try {
|
|
92918
92985
|
const current = readSkillSessionSnapshotIfExists(resolved.parentSnapshot.sessionId, options);
|
|
92919
|
-
return current !== null &&
|
|
92986
|
+
return current !== null && isDeepStrictEqual16(current.receipt.profile, resolved.receipt.profile);
|
|
92920
92987
|
} catch {
|
|
92921
92988
|
return false;
|
|
92922
92989
|
}
|
|
@@ -92928,7 +92995,7 @@ function pinUnchanged(sessionId, resolved, options) {
|
|
|
92928
92995
|
if (readSelectionFileSnapshot(sessionReceiptPath(sessionId, options), MAX_PROFILE_DOCUMENT_BYTES)?.sha256 === resolved.sessionSnapshot.receiptSha256)
|
|
92929
92996
|
return true;
|
|
92930
92997
|
const current = readSkillSessionSnapshotIfExists(sessionId, options);
|
|
92931
|
-
return current !== null &&
|
|
92998
|
+
return current !== null && isDeepStrictEqual16(current.receipt.profile, resolved.session.profile);
|
|
92932
92999
|
} catch {
|
|
92933
93000
|
return false;
|
|
92934
93001
|
}
|
|
@@ -92947,7 +93014,7 @@ var init_skill_context = __esm(() => {
|
|
|
92947
93014
|
// src/lib/session-reconciliation.ts
|
|
92948
93015
|
import { createHash as createHash39 } from "crypto";
|
|
92949
93016
|
import { dirname as dirname35, join as join53, resolve as resolve33 } from "path";
|
|
92950
|
-
import { isDeepStrictEqual as
|
|
93017
|
+
import { isDeepStrictEqual as isDeepStrictEqual17 } from "util";
|
|
92951
93018
|
function exactTimestamp(value) {
|
|
92952
93019
|
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
92953
93020
|
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
|
|
@@ -93238,7 +93305,7 @@ async function renewSkillSessionPin(sessionId, profileId, options = {}) {
|
|
|
93238
93305
|
profileRevision: target.profileRevision,
|
|
93239
93306
|
...!previous.authorizationEpoch && current.authorizationEpoch ? { authorizationEpoch: current.authorizationEpoch } : {}
|
|
93240
93307
|
};
|
|
93241
|
-
if (!
|
|
93308
|
+
if (!isDeepStrictEqual17(expected, current)) {
|
|
93242
93309
|
throw new SkillSelectionError("SESSION_RECONCILIATION_REQUIRED", "A pinned skill's selection policy changed; review skills sessions reconcile before changing this session's pin.");
|
|
93243
93310
|
}
|
|
93244
93311
|
if (changedVersion)
|
|
@@ -93258,7 +93325,7 @@ async function renewSkillSessionPin(sessionId, profileId, options = {}) {
|
|
|
93258
93325
|
const confirmed = await client2.resolveProfile(profileId);
|
|
93259
93326
|
assertActive();
|
|
93260
93327
|
validateResolvedProfile(confirmed, client2.authority);
|
|
93261
|
-
if (!
|
|
93328
|
+
if (!isDeepStrictEqual17(target, confirmed))
|
|
93262
93329
|
throw new SkillSelectionError("SESSION_TARGET_CHANGED", "The authenticated Skills profile changed during session authorization; the existing pin is unchanged.");
|
|
93263
93330
|
const replacement = {
|
|
93264
93331
|
...old,
|
|
@@ -93330,7 +93397,7 @@ async function renewSkillSessionPin(sessionId, profileId, options = {}) {
|
|
|
93330
93397
|
function holdsReplacement(generation, target) {
|
|
93331
93398
|
try {
|
|
93332
93399
|
const current = readSkillSessionSnapshotIfExists(sessionId, options);
|
|
93333
|
-
return current !== null && current.generation === generation && current.receipt.verifiedAt === new Date(now3).toISOString() &&
|
|
93400
|
+
return current !== null && current.generation === generation && current.receipt.verifiedAt === new Date(now3).toISOString() && isDeepStrictEqual17(current.receipt.profile, target);
|
|
93334
93401
|
} catch {
|
|
93335
93402
|
return false;
|
|
93336
93403
|
}
|
|
@@ -93855,20 +93922,24 @@ Preserved original receipt: ${result2.archivePath}` : [
|
|
|
93855
93922
|
reportContextError(error61, options.json);
|
|
93856
93923
|
}
|
|
93857
93924
|
});
|
|
93858
|
-
parent.command("load <skill>").description("Load an exact API-selected skill and return its version/digest receipt").option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--session <id>", "Pin this load to a session").option("--file <path>", "Read an exact bundle file (default: SKILL.md, README.md, then CLAUDE.md)").option("--json", "Return content and provenance as JSON", false).action(async (skill, options) => {
|
|
93925
|
+
parent.command("load <skill>").description("Load an exact API-selected skill and return its version/digest receipt").option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--cache-first", "Read the verified cache while it can serve this load, and the Skills service after that", false).option("--session <id>", "Pin this load to a session").option("--file <path>", "Read an exact bundle file (default: SKILL.md, README.md, then CLAUDE.md)").option("--json", "Return content and provenance as JSON", false).action(async (skill, options) => {
|
|
93859
93926
|
try {
|
|
93860
93927
|
const result2 = await loadSelectedSkill(skill, selectedProfileId(options.selectionProfile), {
|
|
93861
|
-
...contextResolverOptions(options),
|
|
93928
|
+
...contextResolverOptions({ ...options, cached: options.cached || options.cacheFirst }),
|
|
93929
|
+
cacheFirst: options.cacheFirst && !options.cached,
|
|
93862
93930
|
projectDir: process.cwd(),
|
|
93863
93931
|
sessionId: options.session,
|
|
93864
93932
|
file: options.file
|
|
93865
93933
|
});
|
|
93934
|
+
if (result2.sessionRecorded === false)
|
|
93935
|
+
process.stderr.write(`Skills: this load was not recorded on its session, because the session store could not be updated here. The content is complete, but compaction won't restore it and this session won't be told if the skill is retired.
|
|
93936
|
+
`);
|
|
93866
93937
|
await writeCliOutput(options.json ? JSON.stringify(result2) : result2.content);
|
|
93867
93938
|
} catch (error61) {
|
|
93868
93939
|
reportContextError(error61, options.json);
|
|
93869
93940
|
}
|
|
93870
93941
|
});
|
|
93871
|
-
parent.command("context [prompt]").description("Select bounded, versioned skill context for this prompt without running skills").option("--stdin", "Read native hook JSON or a prompt from stdin", false).option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--auto-reconcile-safe", "For managed hooks, renew authorized immutable session pins without adopting newer selected versions", false).option("--auto-migrate-session-pin", "With --auto-reconcile-safe: when renewal is refused because the same profile moved on, migrate the pin to the current revision and retire changed or removed loaded skills; managed hooks name them once. A project lock at the input cwd keeps the refusal", false).option("--renewal-budget-ms <ms>", "With --auto-reconcile-safe: milliseconds this command may spend before its session pin renewal must finish, counted from when the command starts; the renewal never exceeds its own budget either").option("--background-renewal", "With --auto-reconcile-safe (managed hooks): renew session pins in a detached background worker, ahead of expiry for root sessions; an expired pin waits a few seconds for it and otherwise delivers no payload", false).option("--session <id>", "Keep the same skill versions across this session").option("--restore", "Re-emit loaded session context after compaction or resume", false).option("--max-chars <count>", "Optional maximum injected characters").option("--max-skills <count>", "Maximum loaded skills", "3").option("--json", "Return context and selection receipts as JSON", false).action(async (prompt, options) => {
|
|
93942
|
+
parent.command("context [prompt]").description("Select bounded, versioned skill context for this prompt without running skills").option("--stdin", "Read native hook JSON or a prompt from stdin", false).option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--auto-reconcile-safe", "For managed hooks, renew authorized immutable session pins without adopting newer selected versions", false).option("--auto-migrate-session-pin", "With --auto-reconcile-safe: when renewal is refused because the same profile moved on, migrate the pin to the current revision and retire changed or removed loaded skills; managed hooks name them once. A project lock at the input cwd keeps the refusal", false).option("--renewal-budget-ms <ms>", "With --auto-reconcile-safe: milliseconds this command may spend before its session pin renewal must finish, counted from when the command starts; the renewal never exceeds its own budget either").option("--background-renewal", "With --auto-reconcile-safe (managed hooks): renew session pins in a detached background worker, ahead of expiry for root sessions; an expired pin waits a few seconds for it and otherwise delivers no payload", false).option("--session <id>", "Keep the same skill versions across this session").option("--restore", "Re-emit loaded session context after compaction or resume", false).option("--max-chars <count>", "Optional maximum injected characters").option("--max-skills <count>", "Maximum loaded skills", "3").option("--min-prompt-phrase-words <count>", "Offer an unnamed prompt match as a load command instead of injecting it unless a matched phrase has at least this many words").option("--inherited-bodies <count>", "Skill bodies a subagent receives from its parent's loaded skills; the rest are offered as load commands").option("--pointer-cache-first", "Print load commands with --cache-first even when this context isn't read from the cache", false).option("--json", "Return context and selection receipts as JSON", false).action(async (prompt, options) => {
|
|
93872
93943
|
const started = performance.now();
|
|
93873
93944
|
try {
|
|
93874
93945
|
if (options.autoReconcileSafe && !options.cached)
|
|
@@ -93882,6 +93953,10 @@ Preserved original receipt: ${result2.archivePath}` : [
|
|
|
93882
93953
|
throw new SkillSelectionError("INVALID_CONTEXT_INPUT", "--auto-migrate-session-pin requires --auto-reconcile-safe.");
|
|
93883
93954
|
if (options.backgroundRenewal && !options.autoReconcileSafe)
|
|
93884
93955
|
throw new SkillSelectionError("INVALID_CONTEXT_INPUT", "--background-renewal requires --auto-reconcile-safe.");
|
|
93956
|
+
for (const [flag, value] of [["--min-prompt-phrase-words", options.minPromptPhraseWords], ["--inherited-bodies", options.inheritedBodies]]) {
|
|
93957
|
+
if (value !== undefined && !/^\d{1,6}$/.test(value))
|
|
93958
|
+
throw new SkillSelectionError("INVALID_CONTEXT_INPUT", `${flag} must be a whole number of at most six digits.`);
|
|
93959
|
+
}
|
|
93885
93960
|
const input2 = options.stdin ? parseSkillContextInput(await readContextStdin()) : { prompt: prompt ?? "" };
|
|
93886
93961
|
input2.profileId = selectedProfileId(options.selectionProfile ?? input2.profileId);
|
|
93887
93962
|
input2.cwd ??= process.cwd();
|
|
@@ -93892,6 +93967,9 @@ Preserved original receipt: ${result2.archivePath}` : [
|
|
|
93892
93967
|
...contextResolverOptions(options),
|
|
93893
93968
|
...options.maxChars === undefined ? {} : { maxChars: Number(options.maxChars) },
|
|
93894
93969
|
maxSkills: Number(options.maxSkills),
|
|
93970
|
+
...options.minPromptPhraseWords === undefined ? {} : { minPromptPhraseWords: Number(options.minPromptPhraseWords) },
|
|
93971
|
+
...options.inheritedBodies === undefined ? {} : { inheritedBodies: Number(options.inheritedBodies) },
|
|
93972
|
+
...options.pointerCacheFirst ? { pointerCacheFirst: true } : {},
|
|
93895
93973
|
...renewalDeadline === undefined ? {} : { resolveAgainBefore: renewalDeadline },
|
|
93896
93974
|
...options.backgroundRenewal ? { onResolved: (resolved) => {
|
|
93897
93975
|
pinned = resolved.session && resolved.sessionSnapshot ? { receipt: resolved.session, receiptSha256: resolved.sessionSnapshot.receiptSha256 } : null;
|
|
@@ -98440,7 +98518,7 @@ var init_execution_grants = __esm(() => {
|
|
|
98440
98518
|
});
|
|
98441
98519
|
|
|
98442
98520
|
// src/lib/execution-grant-client.ts
|
|
98443
|
-
import { isDeepStrictEqual as
|
|
98521
|
+
import { isDeepStrictEqual as isDeepStrictEqual18 } from "util";
|
|
98444
98522
|
function id(value) {
|
|
98445
98523
|
if (!grantIdentifier(value))
|
|
98446
98524
|
throw new Error("Invalid execution grant profile or revision identifier.");
|
|
@@ -98492,7 +98570,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
|
|
|
98492
98570
|
headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
|
|
98493
98571
|
body: JSON.stringify({ grants: snapshot2 })
|
|
98494
98572
|
}));
|
|
98495
|
-
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !
|
|
98573
|
+
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual18(policy.grants, snapshot2)) {
|
|
98496
98574
|
throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
|
|
98497
98575
|
}
|
|
98498
98576
|
return policy;
|
|
@@ -98503,7 +98581,7 @@ async function resolveExecutionGrant(input2) {
|
|
|
98503
98581
|
if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
|
|
98504
98582
|
throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
|
|
98505
98583
|
}
|
|
98506
|
-
if (!
|
|
98584
|
+
if (!isDeepStrictEqual18(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual18(value.bindings.consumer, snapshot2.consumer)) {
|
|
98507
98585
|
throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
|
|
98508
98586
|
}
|
|
98509
98587
|
return value;
|
|
@@ -119642,7 +119720,7 @@ import { closeSync as closeSync31, constants as constants30, existsSync as exist
|
|
|
119642
119720
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
119643
119721
|
import { homedir as homedir11 } from "os";
|
|
119644
119722
|
import { dirname as dirname44, isAbsolute as isAbsolute41, join as join71 } from "path";
|
|
119645
|
-
import { isDeepStrictEqual as
|
|
119723
|
+
import { isDeepStrictEqual as isDeepStrictEqual19, stripVTControlCharacters } from "util";
|
|
119646
119724
|
async function handleMcp(options) {
|
|
119647
119725
|
if (options.register) {
|
|
119648
119726
|
let agents;
|
|
@@ -119764,7 +119842,7 @@ async function registerClaudeMcp(command, server2, environment) {
|
|
|
119764
119842
|
}
|
|
119765
119843
|
if (exitCode === 0) {
|
|
119766
119844
|
const actual = isPlainObject4(data.mcpServers) ? data.mcpServers[MCP_SERVER_NAME] : undefined;
|
|
119767
|
-
if (!claudeNativeConfigPreserved(previous, data, firstRun !== undefined && before2 === null) || !isPlainObject4(actual) || !
|
|
119845
|
+
if (!claudeNativeConfigPreserved(previous, data, firstRun !== undefined && before2 === null) || !isPlainObject4(actual) || !isDeepStrictEqual19({ ...actual, env: actual.env ?? {} }, desired)) {
|
|
119768
119846
|
if (!preimage || current !== null && current.equals(preimage.bytes))
|
|
119769
119847
|
throw new Error;
|
|
119770
119848
|
if (current === null || actual === undefined || !claudeRewriteExplainedByNativeAdd(previous, data))
|
|
@@ -119860,12 +119938,12 @@ function restoreClaudePreimage(path, preimage, observed, command) {
|
|
|
119860
119938
|
}
|
|
119861
119939
|
function claudeRewriteExplainedByNativeAdd(before2, after2) {
|
|
119862
119940
|
const skills = (data) => isPlainObject4(data.mcpServers) ? data.mcpServers[MCP_SERVER_NAME] : undefined;
|
|
119863
|
-
if (skills(after2) === undefined ||
|
|
119941
|
+
if (skills(after2) === undefined || isDeepStrictEqual19(skills(before2), skills(after2)))
|
|
119864
119942
|
return false;
|
|
119865
119943
|
const previous = withoutClaudeSkills(before2), current = withoutClaudeSkills(after2);
|
|
119866
119944
|
for (const [key2, value] of Object.entries(current)) {
|
|
119867
119945
|
if (Object.hasOwn(previous, key2)) {
|
|
119868
|
-
if (!
|
|
119946
|
+
if (!isDeepStrictEqual19(previous[key2], value))
|
|
119869
119947
|
return false;
|
|
119870
119948
|
} else if (!CLAUDE_NATIVE_FIRST_START_KEYS.has(key2))
|
|
119871
119949
|
return false;
|
|
@@ -119989,7 +120067,7 @@ function claudeNativeConfigPreserved(before2, after2, firstRun = false) {
|
|
|
119989
120067
|
return false;
|
|
119990
120068
|
delete current[key2];
|
|
119991
120069
|
}
|
|
119992
|
-
return
|
|
120070
|
+
return isDeepStrictEqual19(previous, current);
|
|
119993
120071
|
}
|
|
119994
120072
|
function isClaudeBootstrapAddition(key2, value) {
|
|
119995
120073
|
switch (key2) {
|
|
@@ -120047,7 +120125,7 @@ ${body}`;
|
|
|
120047
120125
|
const before2 = Bun.TOML.parse(current);
|
|
120048
120126
|
const next = upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, body);
|
|
120049
120127
|
const after2 = Bun.TOML.parse(next);
|
|
120050
|
-
if (!
|
|
120128
|
+
if (!isDeepStrictEqual19(withoutSkillsMcp(before2), withoutSkillsMcp(after2)))
|
|
120051
120129
|
throw new Error;
|
|
120052
120130
|
return next;
|
|
120053
120131
|
});
|
|
@@ -124456,7 +124534,7 @@ var init_agent_install_selection = __esm(() => {
|
|
|
124456
124534
|
// src/lib/codex-hook-trust-identity.ts
|
|
124457
124535
|
import { lstatSync as lstatSync49, realpathSync as realpathSync22 } from "fs";
|
|
124458
124536
|
import { dirname as dirname50, isAbsolute as isAbsolute46, join as join78, resolve as resolve42 } from "path";
|
|
124459
|
-
import { isDeepStrictEqual as
|
|
124537
|
+
import { isDeepStrictEqual as isDeepStrictEqual20 } from "util";
|
|
124460
124538
|
function commandPhysical(command) {
|
|
124461
124539
|
need8(typeof command === "string" && isAbsolute46(command) && !command.includes("\x00") && resolve42(command) === command, COMMAND_NOT_CANONICAL);
|
|
124462
124540
|
const physical = realpathSync22(command);
|
|
@@ -124521,7 +124599,7 @@ function inspectRecordedSkillsCli(command, expected) {
|
|
|
124521
124599
|
need8(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join78(dirname50(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
124522
124600
|
need8((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
124523
124601
|
const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
|
|
124524
|
-
need8(
|
|
124602
|
+
need8(isDeepStrictEqual20(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
124525
124603
|
return { receipt, recheck() {
|
|
124526
124604
|
targetUnchanged(command, target);
|
|
124527
124605
|
unchanged2(cli);
|
|
@@ -124591,19 +124669,19 @@ var init_codex_hook_trust_identity = __esm(() => {
|
|
|
124591
124669
|
});
|
|
124592
124670
|
|
|
124593
124671
|
// src/lib/codex-hook-policy-recovery.ts
|
|
124594
|
-
import { isDeepStrictEqual as
|
|
124672
|
+
import { isDeepStrictEqual as isDeepStrictEqual21 } from "util";
|
|
124595
124673
|
function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
|
|
124596
124674
|
need8(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
|
|
124597
124675
|
need8(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
124598
124676
|
const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
|
|
124599
124677
|
const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
|
|
124600
124678
|
need8(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
|
|
124601
|
-
const changes = ["roots", "sources"].filter((key2) => !
|
|
124679
|
+
const changes = ["roots", "sources"].filter((key2) => !isDeepStrictEqual21(oldDiscovery[key2], newDiscovery[key2])).map((key2) => ({ path: `bridge.discovery.claude.${key2}`, before: oldDiscovery[key2], after: newDiscovery[key2] }));
|
|
124602
124680
|
need8(changes.length > 0, "RECONCILE_POLICY_CHANGED");
|
|
124603
124681
|
const compared = structuredClone(current);
|
|
124604
124682
|
compared.bridge.discovery.claude.roots = oldDiscovery.roots;
|
|
124605
124683
|
compared.bridge.discovery.claude.sources = oldDiscovery.sources;
|
|
124606
|
-
need8(
|
|
124684
|
+
need8(isDeepStrictEqual21(before2, compared), "RECONCILE_POLICY_CHANGED");
|
|
124607
124685
|
verifyAgentDiscovery(newDiscovery);
|
|
124608
124686
|
return { reason: options.reason, changes };
|
|
124609
124687
|
}
|
|
@@ -124619,7 +124697,7 @@ import { createHash as createHash49, randomUUID as randomUUID16 } from "crypto";
|
|
|
124619
124697
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
124620
124698
|
import { dirname as dirname51, isAbsolute as isAbsolute47, join as join79, resolve as resolve43 } from "path";
|
|
124621
124699
|
import { homedir as homedir14 } from "os";
|
|
124622
|
-
import { isDeepStrictEqual as
|
|
124700
|
+
import { isDeepStrictEqual as isDeepStrictEqual22 } from "util";
|
|
124623
124701
|
function verifyReleaseArtifact(proof, skillsCli) {
|
|
124624
124702
|
need8(isAbsolute47(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
124625
124703
|
const tarPath = realpathSync23(proof.packageTarPath);
|
|
@@ -124661,7 +124739,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
124661
124739
|
const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
|
|
124662
124740
|
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 };
|
|
124663
124741
|
need8(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
|
|
124664
|
-
need8(
|
|
124742
|
+
need8(isDeepStrictEqual22(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
|
|
124665
124743
|
need8(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
|
|
124666
124744
|
const policyCurrent = snapshot(join79(dataDir3, "agent-policy.json"), true);
|
|
124667
124745
|
const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
|
|
@@ -124674,7 +124752,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
124674
124752
|
if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
|
|
124675
124753
|
need8(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
|
|
124676
124754
|
const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
|
|
124677
|
-
need8(
|
|
124755
|
+
need8(isDeepStrictEqual22(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
|
|
124678
124756
|
supersededBinding = true;
|
|
124679
124757
|
}
|
|
124680
124758
|
if (supersededBinding || recovery) {
|
|
@@ -124710,7 +124788,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
124710
124788
|
need8(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
|
|
124711
124789
|
}
|
|
124712
124790
|
} else
|
|
124713
|
-
need8(
|
|
124791
|
+
need8(isDeepStrictEqual22(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
|
|
124714
124792
|
const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
|
|
124715
124793
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
|
|
124716
124794
|
const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
|
|
@@ -124719,14 +124797,14 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
124719
124797
|
const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
124720
124798
|
if (supersededBinding)
|
|
124721
124799
|
verifyReleaseArtifact(options.releaseProof, skillsCli);
|
|
124722
|
-
const skillsBindingChanged = !
|
|
124800
|
+
const skillsBindingChanged = !isDeepStrictEqual22(skillsCli.receipt, intent.skillsCli);
|
|
124723
124801
|
need8(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
124724
124802
|
if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
|
|
124725
124803
|
need8(supersededBinding, "RECONCILE_HOOKS_CHANGED");
|
|
124726
124804
|
const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
|
|
124727
124805
|
for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
|
|
124728
124806
|
const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
|
|
124729
|
-
need8(
|
|
124807
|
+
need8(isDeepStrictEqual22(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
|
|
124730
124808
|
}
|
|
124731
124809
|
}
|
|
124732
124810
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
@@ -124749,9 +124827,9 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
124749
124827
|
delete identity7.command;
|
|
124750
124828
|
return identity7;
|
|
124751
124829
|
};
|
|
124752
|
-
need8(
|
|
124830
|
+
need8(isDeepStrictEqual22(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
124753
124831
|
if (!plannedKeys.has(expected.key))
|
|
124754
|
-
need8(
|
|
124832
|
+
need8(isDeepStrictEqual22(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
|
|
124755
124833
|
}
|
|
124756
124834
|
for (const wanted of intent.hooks) {
|
|
124757
124835
|
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join79(home, ".codex/hooks.json"), hooksPath));
|
|
@@ -124770,7 +124848,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
124770
124848
|
const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
124771
124849
|
need8(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
|
|
124772
124850
|
const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
|
|
124773
|
-
need8(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks ||
|
|
124851
|
+
need8(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual22(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
|
|
124774
124852
|
const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
124775
124853
|
const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
124776
124854
|
need8(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
|
|
@@ -124835,7 +124913,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
124835
124913
|
const groups = declarations[event];
|
|
124836
124914
|
need8(Array.isArray(groups), "DECLARATION_CHANGED");
|
|
124837
124915
|
const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
|
|
124838
|
-
need8(matches2.length === 1 &&
|
|
124916
|
+
need8(matches2.length === 1 && isDeepStrictEqual22(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
|
|
124839
124917
|
expected.push({ event: nativeEvent, key: `${join79(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
|
|
124840
124918
|
}
|
|
124841
124919
|
codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
|
|
@@ -124901,7 +124979,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
124901
124979
|
save(join79(journal, "hooks.before.json"), hooksFile.bytes);
|
|
124902
124980
|
save(join79(journal, "policy.before.json"), policyFile.bytes);
|
|
124903
124981
|
save(join79(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook), ...codexAdmissionReceipt(admission) }));
|
|
124904
|
-
need8(
|
|
124982
|
+
need8(isDeepStrictEqual22(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
|
|
124905
124983
|
checkInputs();
|
|
124906
124984
|
let result2;
|
|
124907
124985
|
try {
|
|
@@ -124915,7 +124993,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
124915
124993
|
expectedConfig.hooks.state ??= {};
|
|
124916
124994
|
for (const h of planned)
|
|
124917
124995
|
expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
|
|
124918
|
-
need8(
|
|
124996
|
+
need8(isDeepStrictEqual22(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys4) === preservationText, "PRESERVATION_FAILED");
|
|
124919
124997
|
const savedConfig = snapshot(join79(journal, "config.before.toml"), true);
|
|
124920
124998
|
need8(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
|
|
124921
124999
|
const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
|
|
@@ -124923,8 +125001,8 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
124923
125001
|
unchanged2(hooksFile);
|
|
124924
125002
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
|
|
124925
125003
|
const current = await list2(), confirmed = admit(current);
|
|
124926
|
-
need8(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") &&
|
|
124927
|
-
need8(
|
|
125004
|
+
need8(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual22(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
|
|
125005
|
+
need8(isDeepStrictEqual22(current.filter((h) => !keys4.includes(h.key)), discovered.filter((h) => !keys4.includes(h.key))), "UNRELATED_HOOK_CHANGED");
|
|
124928
125006
|
unchanged2(after2);
|
|
124929
125007
|
unchanged2(savedConfig);
|
|
124930
125008
|
unchanged2(hooksFile);
|
|
@@ -125059,7 +125137,7 @@ var init_codex_native_trust = __esm(() => {
|
|
|
125059
125137
|
import { createHash as createHash51 } from "crypto";
|
|
125060
125138
|
import { lstatSync as lstatSync51, readFileSync as readFileSync49, readdirSync as readdirSync29, realpathSync as realpathSync24 } from "fs";
|
|
125061
125139
|
import { basename as basename26, dirname as dirname52, isAbsolute as isAbsolute48, join as join81, relative as relative16, resolve as resolve45, sep as sep23 } from "path";
|
|
125062
|
-
import { isDeepStrictEqual as
|
|
125140
|
+
import { isDeepStrictEqual as isDeepStrictEqual23 } from "util";
|
|
125063
125141
|
function hashClaudeDiscoveryBinding(binding) {
|
|
125064
125142
|
return sha8(JSON.stringify(binding));
|
|
125065
125143
|
}
|
|
@@ -125382,7 +125460,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
125382
125460
|
refuse8("candidate must select between one and 32 plugins from one marketplace");
|
|
125383
125461
|
if (candidate2.functionHooksEnv !== undefined && candidate2.functionHooksEnv !== "1")
|
|
125384
125462
|
refuse8("function-hook environment mutation only supports the explicit value 1");
|
|
125385
|
-
const settingsMarketplaceWriterVersions = ["2.1.276", "2.1.278", "2.1.282", "2.1.287", "2.1.293", "2.1.296", "2.1.299", "2.1.300", "2.1.301", "2.1.302"];
|
|
125463
|
+
const settingsMarketplaceWriterVersions = ["2.1.276", "2.1.278", "2.1.282", "2.1.287", "2.1.293", "2.1.296", "2.1.299", "2.1.300", "2.1.301", "2.1.302", "2.1.314", "2.1.316"];
|
|
125386
125464
|
const nativeVersion = request2.native.executable.version;
|
|
125387
125465
|
const measuredSettingsWriter = settingsMarketplaceWriterVersions.some((version2) => nativeVersion === version2 || nativeVersion === `${version2} (Claude Code)`);
|
|
125388
125466
|
if (hasOwn2(candidate2, "settingsMarketplaceSource") && (candidate2.settingsMarketplaceSource !== "directory" || request2.scope.kind !== "user" || !measuredSettingsWriter))
|
|
@@ -125531,7 +125609,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
125531
125609
|
refuse8("Skills discovery preimage differs from its reviewed binding");
|
|
125532
125610
|
assertProjectDiscovery("claude", [request2.scope.projectPath], request2.native.home, canonical9, binding);
|
|
125533
125611
|
const stored = snapshot2.value.bridge?.discovery?.claude;
|
|
125534
|
-
if (!stored || !
|
|
125612
|
+
if (!stored || !isDeepStrictEqual23(stored, binding) || snapshot2.value.bridge?.home !== request2.native.home)
|
|
125535
125613
|
refuse8("Skills policy does not bind the reviewed current Claude discovery");
|
|
125536
125614
|
assertExemptUnchanged();
|
|
125537
125615
|
const delta = request2.delta;
|
|
@@ -125689,7 +125767,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
125689
125767
|
refuse8("current known marketplace autoUpdate is not a boolean");
|
|
125690
125768
|
}
|
|
125691
125769
|
}
|
|
125692
|
-
if (!
|
|
125770
|
+
if (!isDeepStrictEqual23(delta.settingsAfter, settingsAfter))
|
|
125693
125771
|
refuse8("complete settings document differs from the exact selected plugin/options/environment/marketplace operations");
|
|
125694
125772
|
const marketplaceRowBefore = marketplaces?.[candidate2.marketplace];
|
|
125695
125773
|
if (marketplaceRowBefore !== undefined && !object13(marketplaceRowBefore))
|
|
@@ -125701,7 +125779,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
125701
125779
|
if (marketplaceRowBefore?.lastUpdated !== undefined && !validUtcTimestamp(marketplaceRowBefore.lastUpdated))
|
|
125702
125780
|
refuse8("current marketplace update timestamp is invalid");
|
|
125703
125781
|
const targetMarketplaceLocation = candidate2.root;
|
|
125704
|
-
const sameMarketplaceSource =
|
|
125782
|
+
const sameMarketplaceSource = isDeepStrictEqual23(marketplaceRowBefore?.source, { source: "directory", path: candidate2.root }) && marketplaceRowBefore?.installLocation === targetMarketplaceLocation;
|
|
125705
125783
|
const afterMarketplace = {
|
|
125706
125784
|
source: { source: "directory", path: candidate2.root },
|
|
125707
125785
|
installLocation: targetMarketplaceLocation,
|
|
@@ -125710,7 +125788,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
125710
125788
|
};
|
|
125711
125789
|
const marketplacesAfter = marketplaces ? structuredClone(marketplaces) : {};
|
|
125712
125790
|
marketplacesAfter[candidate2.marketplace] = afterMarketplace;
|
|
125713
|
-
if (!
|
|
125791
|
+
if (!isDeepStrictEqual23(delta.knownMarketplacesAfter, marketplacesAfter))
|
|
125714
125792
|
refuse8("complete marketplace document differs from the exact selected-directory marketplace operation");
|
|
125715
125793
|
const installedAfter = registrations ? structuredClone(registrations) : { version: 2, plugins: {} };
|
|
125716
125794
|
if (installedAfter.plugins === undefined)
|
|
@@ -125730,7 +125808,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
125730
125808
|
nextRows[index] = targetRegistration;
|
|
125731
125809
|
installedAfter.plugins[pluginId2] = nextRows;
|
|
125732
125810
|
}
|
|
125733
|
-
if (!
|
|
125811
|
+
if (!isDeepStrictEqual23(delta.installedPluginsAfter, installedAfter))
|
|
125734
125812
|
refuse8("complete installed plugin document changes an unrelated registration or has target rows not derived from every selected candidate");
|
|
125735
125813
|
assertExemptUnchanged();
|
|
125736
125814
|
const semanticDocumentsSha256 = sha8(canonicalJson3({ settings: settingsAfter, knownMarketplaces: marketplacesAfter, installedPlugins: installedAfter }));
|
|
@@ -126195,8 +126273,12 @@ var exports_agent_integration = {};
|
|
|
126195
126273
|
__export(exports_agent_integration, {
|
|
126196
126274
|
withSessionPinMigrationNotice: () => withSessionPinMigrationNotice,
|
|
126197
126275
|
registerAgentIntegration: () => registerAgentIntegration,
|
|
126276
|
+
managedHookSelectionArgs: () => managedHookSelectionArgs,
|
|
126277
|
+
managedHookPromptMinPhraseWords: () => managedHookPromptMinPhraseWords,
|
|
126198
126278
|
managedHookContextLimits: () => managedHookContextLimits,
|
|
126199
126279
|
capManagedHookContext: () => capManagedHookContext,
|
|
126280
|
+
MANAGED_HOOK_PROMPT_MIN_PHRASE_WORDS: () => MANAGED_HOOK_PROMPT_MIN_PHRASE_WORDS,
|
|
126281
|
+
MANAGED_HOOK_INHERITED_BODIES: () => MANAGED_HOOK_INHERITED_BODIES,
|
|
126200
126282
|
MANAGED_HOOK_CONTEXT_RESERVE_CHARS: () => MANAGED_HOOK_CONTEXT_RESERVE_CHARS,
|
|
126201
126283
|
MANAGED_HOOK_CONTEXT_MAX_SKILLS: () => MANAGED_HOOK_CONTEXT_MAX_SKILLS,
|
|
126202
126284
|
MANAGED_HOOK_CONTEXT_MAX_CHARS: () => MANAGED_HOOK_CONTEXT_MAX_CHARS
|
|
@@ -126217,6 +126299,14 @@ function managedHookContextLimits() {
|
|
|
126217
126299
|
const maxSkills = boundedEnvInteger("SKILLS_HOOK_CONTEXT_MAX_SKILLS", MANAGED_HOOK_CONTEXT_MAX_SKILLS, HOOK_CONTEXT_SKILLS_RANGE);
|
|
126218
126300
|
return { maxChars, maxSkills, bodyChars: maxChars - MANAGED_HOOK_CONTEXT_RESERVE_CHARS };
|
|
126219
126301
|
}
|
|
126302
|
+
function managedHookPromptMinPhraseWords() {
|
|
126303
|
+
return boundedEnvInteger("SKILLS_HOOK_PROMPT_MIN_PHRASE_WORDS", MANAGED_HOOK_PROMPT_MIN_PHRASE_WORDS, HOOK_PROMPT_PHRASE_WORDS_RANGE);
|
|
126304
|
+
}
|
|
126305
|
+
function managedHookSelectionArgs(agent) {
|
|
126306
|
+
if (agent === "sumi" || agent === "cursor")
|
|
126307
|
+
return [];
|
|
126308
|
+
return ["--min-prompt-phrase-words", String(managedHookPromptMinPhraseWords()), "--inherited-bodies", String(MANAGED_HOOK_INHERITED_BODIES)];
|
|
126309
|
+
}
|
|
126220
126310
|
function capManagedHookContext(context2, maxChars = managedHookContextLimits().maxChars) {
|
|
126221
126311
|
if (context2.length <= maxChars)
|
|
126222
126312
|
return context2;
|
|
@@ -126255,14 +126345,16 @@ function withSessionPinMigrationNotice(agent, event, input3, result2) {
|
|
|
126255
126345
|
`);
|
|
126256
126346
|
} catch {}
|
|
126257
126347
|
}
|
|
126258
|
-
async function contextForHook(input3, profileId, cached2, deadline) {
|
|
126348
|
+
async function contextForHook(agent, input3, profileId, cached2, deadline) {
|
|
126259
126349
|
const { childMs, renewalBudgetMs } = managedContextChildLimits(deadline - Date.now());
|
|
126260
126350
|
if (childMs <= 0)
|
|
126261
126351
|
throw new HookDiagnosticError("SKILLS_HOOK_TIMEOUT", "context");
|
|
126262
126352
|
const limits = managedHookContextLimits();
|
|
126263
|
-
const args2 = ["context", "--stdin", "--json", "--selection-profile", profileId, "--max-chars", String(limits.bodyChars), "--max-skills", String(limits.maxSkills)];
|
|
126353
|
+
const args2 = ["context", "--stdin", "--json", "--selection-profile", profileId, "--max-chars", String(limits.bodyChars), "--max-skills", String(limits.maxSkills), ...managedHookSelectionArgs(agent)];
|
|
126264
126354
|
if (cached2)
|
|
126265
126355
|
args2.push("--cached", "--auto-reconcile-safe");
|
|
126356
|
+
else
|
|
126357
|
+
args2.push("--pointer-cache-first");
|
|
126266
126358
|
if (cached2 && sessionPinMigrationEnabled())
|
|
126267
126359
|
args2.push("--auto-migrate-session-pin");
|
|
126268
126360
|
if (cached2)
|
|
@@ -126291,7 +126383,7 @@ async function contextForHook(input3, profileId, cached2, deadline) {
|
|
|
126291
126383
|
if (status !== 0) {
|
|
126292
126384
|
const failure = hookChildError(output2, "context");
|
|
126293
126385
|
if (cached2 && RECOVERABLE_CONTEXT_CACHE_ERRORS.has(failure.code)) {
|
|
126294
|
-
return contextForHook(input3, profileId, false, deadline);
|
|
126386
|
+
return contextForHook(agent, input3, profileId, false, deadline);
|
|
126295
126387
|
}
|
|
126296
126388
|
throw failure;
|
|
126297
126389
|
}
|
|
@@ -126725,7 +126817,7 @@ function registerAgentIntegration(parent) {
|
|
|
126725
126817
|
}
|
|
126726
126818
|
}
|
|
126727
126819
|
selectionProfile = pinnedHookProfile(input3, selectionProfile);
|
|
126728
|
-
const result2 = await contextForHook(input3, selectionProfile, true, deadline);
|
|
126820
|
+
const result2 = await contextForHook(options.agent, input3, selectionProfile, true, deadline);
|
|
126729
126821
|
withSessionPinMigrationNotice(options.agent, event, input3, result2);
|
|
126730
126822
|
if (syncNotice)
|
|
126731
126823
|
result2.context = [syncNotice, result2.context].filter(Boolean).join(`
|
|
@@ -126809,8 +126901,9 @@ ${driftWarning}` : unavailable2, ...output2 }));
|
|
|
126809
126901
|
}
|
|
126810
126902
|
});
|
|
126811
126903
|
}
|
|
126812
|
-
var RECOVERABLE_CONTEXT_CACHE_ERRORS, MANAGED_HOOK_CONTEXT_MAX_CHARS = 12000, MANAGED_HOOK_CONTEXT_MAX_SKILLS = 2, MANAGED_HOOK_CONTEXT_RESERVE_CHARS = 2500, HOOK_CONTEXT_CHARS_RANGE, HOOK_CONTEXT_SKILLS_RANGE, HOOK_CONTEXT_TRUNCATED = "[Skills context truncated at the hook limit; read the rest with `skills load <slug>`.]", SESSION_START_SYNC_CONTINUES;
|
|
126904
|
+
var RECOVERABLE_CONTEXT_CACHE_ERRORS, MANAGED_HOOK_CONTEXT_MAX_CHARS = 12000, MANAGED_HOOK_CONTEXT_MAX_SKILLS = 2, MANAGED_HOOK_CONTEXT_RESERVE_CHARS = 2500, MANAGED_HOOK_PROMPT_MIN_PHRASE_WORDS = 2, MANAGED_HOOK_INHERITED_BODIES = 0, HOOK_PROMPT_PHRASE_WORDS_RANGE, HOOK_CONTEXT_CHARS_RANGE, HOOK_CONTEXT_SKILLS_RANGE, HOOK_CONTEXT_TRUNCATED = "[Skills context truncated at the hook limit; read the rest with `skills load <slug>`.]", SESSION_START_SYNC_CONTINUES;
|
|
126813
126905
|
var init_agent_integration2 = __esm(() => {
|
|
126906
|
+
init_selection_resolver();
|
|
126814
126907
|
init_claude_hook_disable();
|
|
126815
126908
|
init_opencode_hook_protocol();
|
|
126816
126909
|
init_sumi_settings_witness();
|
|
@@ -126840,7 +126933,8 @@ var init_agent_integration2 = __esm(() => {
|
|
|
126840
126933
|
init_self_spawn();
|
|
126841
126934
|
init_config();
|
|
126842
126935
|
init_claude_installer_capture();
|
|
126843
|
-
RECOVERABLE_CONTEXT_CACHE_ERRORS =
|
|
126936
|
+
RECOVERABLE_CONTEXT_CACHE_ERRORS = RECOVERABLE_CACHE_ERRORS;
|
|
126937
|
+
HOOK_PROMPT_PHRASE_WORDS_RANGE = [MANAGED_HOOK_PROMPT_MIN_PHRASE_WORDS, 16];
|
|
126844
126938
|
HOOK_CONTEXT_CHARS_RANGE = [MANAGED_HOOK_CONTEXT_RESERVE_CHARS + 512, MANAGED_HOOK_CONTEXT_MAX_CHARS];
|
|
126845
126939
|
HOOK_CONTEXT_SKILLS_RANGE = [1, MANAGED_HOOK_CONTEXT_MAX_SKILLS];
|
|
126846
126940
|
SESSION_START_SYNC_CONTINUES = new Set(["SKILLS_HOOK_TIMEOUT", "SKILLS_API_UNAVAILABLE"]);
|