@hasna/skills 0.10.49 → 0.10.51
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 +40 -6
- package/bin/index.js +82 -50
- package/bin/maintenance.js +199 -2
- package/bin/mcp.js +53 -36
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +71 -39
- package/dist/lib/agent-discovery.d.ts +2 -2
- package/dist/lib/agent-integration.d.ts +1 -0
- package/dist/lib/claude-settings-witness.d.ts +19 -0
- package/dist/lib/codex-native-compatibility.d.ts +4 -1
- package/dist/sdk/index.js +49 -21
- package/dist/server/maintenance-entry.d.ts +14 -0
- package/dist/server/schema-census.d.ts +77 -0
- package/docs/plugin-admission.md +44 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9177,6 +9177,8 @@ var BUILTIN_MODEL_SELECTIONS = new Set([
|
|
|
9177
9177
|
"claude-opus-4-6[1m]",
|
|
9178
9178
|
"claude-sonnet-4-6[1m]"
|
|
9179
9179
|
]);
|
|
9180
|
+
var CLAUDE_BUILTIN_THEMES = Object.freeze(["auto", "dark", "light", "dark-daltonized", "light-daltonized", "dark-ansi", "light-ansi"]);
|
|
9181
|
+
var BUILTIN_THEMES = new Set(CLAUDE_BUILTIN_THEMES);
|
|
9180
9182
|
function canonical(value) {
|
|
9181
9183
|
if (value.kind === "object")
|
|
9182
9184
|
return { kind: "object", entries: value.entries.map(([key, child]) => [key, canonical(child)]).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0) };
|
|
@@ -9235,7 +9237,9 @@ function inferencePreference(key, child, version) {
|
|
|
9235
9237
|
function settingsDigest(text, version = 1) {
|
|
9236
9238
|
const value = parse(text);
|
|
9237
9239
|
value.entries = value.entries.filter(([key, child]) => {
|
|
9238
|
-
if (version
|
|
9240
|
+
if (version === 4 && key === "theme" && child.kind === "string" && BUILTIN_THEMES.has(child.value))
|
|
9241
|
+
return false;
|
|
9242
|
+
if (version !== 1 && inferencePreference(key, child, version === 4 ? 3 : version))
|
|
9239
9243
|
return false;
|
|
9240
9244
|
if (key === "model") {
|
|
9241
9245
|
need(child.kind === "string", "contains an invalid model selection");
|
|
@@ -9293,6 +9297,26 @@ function upgradeClaudeSettingsWitness(previous, reviewedSettingsPath) {
|
|
|
9293
9297
|
need(settingsDigest(before, 3) === sha256, "non-preference settings changed; explicit discovery review required");
|
|
9294
9298
|
return { path: previous.path, hashMode: "claude-settings-v3", sha256 };
|
|
9295
9299
|
}
|
|
9300
|
+
function captureClaudeSettingsV4(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
9301
|
+
return { path, hashMode: "claude-settings-v4", sha256: settingsDigest(readNativeSettingsWitnessFile(path, budget), 4) };
|
|
9302
|
+
}
|
|
9303
|
+
function hashClaudeSettingsReplacementV4(text, budget) {
|
|
9304
|
+
need(typeof text === "string", "requires settings text");
|
|
9305
|
+
const bytes = Buffer.byteLength(text);
|
|
9306
|
+
need(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
9307
|
+
budget.remaining -= bytes;
|
|
9308
|
+
return settingsDigest(text, 4);
|
|
9309
|
+
}
|
|
9310
|
+
function upgradeClaudeSettingsWitnessV4(previous, reviewedSettingsPath) {
|
|
9311
|
+
need(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes" || previous.hashMode === "claude-settings-v1" || previous.hashMode === "claude-settings-v2" || previous.hashMode === "claude-settings-v3") && typeof previous.sha256 === "string" && /^[a-f0-9]{64}$/.test(previous.sha256), "requires an exact prior settings witness");
|
|
9312
|
+
const budget = { remaining: 2 * CLAUDE_SETTINGS_WITNESS_LIMITS.bytes };
|
|
9313
|
+
const before = readNativeSettingsWitnessFile(reviewedSettingsPath, budget), current = readNativeSettingsWitnessFile(previous.path, budget);
|
|
9314
|
+
const beforeDigest = previous.hashMode === undefined || previous.hashMode === "bytes" ? createHash2("sha256").update(before).digest("hex") : settingsDigest(before, previous.hashMode === "claude-settings-v1" ? 1 : previous.hashMode === "claude-settings-v2" ? 2 : 3);
|
|
9315
|
+
need(beforeDigest === previous.sha256, "reviewed preimage does not match the prior witness");
|
|
9316
|
+
const sha256 = settingsDigest(current, 4);
|
|
9317
|
+
need(settingsDigest(before, 4) === sha256, "non-preference settings changed; explicit discovery review required");
|
|
9318
|
+
return { path: previous.path, hashMode: "claude-settings-v4", sha256 };
|
|
9319
|
+
}
|
|
9296
9320
|
function hashNativeJsonControls(text, excludedMetadata) {
|
|
9297
9321
|
need(Buffer.byteLength(text) <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes, "exceeds its byte limit");
|
|
9298
9322
|
const value = parse(text);
|
|
@@ -9356,6 +9380,28 @@ function upgradeSumiSettingsWitness(previous, reviewedSettingsPath) {
|
|
|
9356
9380
|
|
|
9357
9381
|
// src/lib/agent-policy-limits.ts
|
|
9358
9382
|
import { basename as basename3, isAbsolute as isAbsolute3, join as join7, resolve as resolve3, sep as sep2 } from "path";
|
|
9383
|
+
|
|
9384
|
+
// src/lib/codex-native-compatibility.ts
|
|
9385
|
+
var MEASURED_CODEX_CAPABILITIES = {
|
|
9386
|
+
"codex-cli 0.153.0": ["hooks"],
|
|
9387
|
+
"codex-cli 0.154.0": ["hooks"],
|
|
9388
|
+
"codex-cli 0.155.0": ["hooks"],
|
|
9389
|
+
"codex-cli 0.155.1": ["hooks"],
|
|
9390
|
+
"codex-cli 0.156.1": ["hooks"],
|
|
9391
|
+
"codex-cli 0.157.0": ["hooks"],
|
|
9392
|
+
"codex-cli 0.157.1": ["hooks"],
|
|
9393
|
+
"codex-cli 0.158.0": ["hooks"],
|
|
9394
|
+
"codex-cli 0.159.0": ["hooks"],
|
|
9395
|
+
"codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
|
|
9396
|
+
"codex-cli 0.160.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
9397
|
+
"codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
9398
|
+
};
|
|
9399
|
+
function supportsCodexNativeCapability(version, capability) {
|
|
9400
|
+
return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
|
|
9401
|
+
}
|
|
9402
|
+
var SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
|
|
9403
|
+
|
|
9404
|
+
// src/lib/agent-policy-limits.ts
|
|
9359
9405
|
var AGENT_POLICY_LIMITS = Object.freeze({ bytes: 1024 * 1024, agents: 16, discoverySources: 2048, discoveryRawSourceBytes: 64 * 1024 * 1024, discoveryRawTotalBytes: 256 * 1024 * 1024, discoveryPathLinks: 40, discoveryPathSteps: 256, discoveryPathSourceMetadataBytes: 64 * 1024, discoveryPathTotalMetadataBytes: 8 * 1024 * 1024, discoveryRoots: 512, discoveryDirectories: 64, discoveryDirectoryEntries: 20000, discoveryDirectoryBytes: 8 * 1024 * 1024, builtinNames: 2048, rootAliases: 2, fields: 64, pathCharacters: 4096 });
|
|
9360
9406
|
function object(value) {
|
|
9361
9407
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -9421,7 +9467,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9421
9467
|
}
|
|
9422
9468
|
if (bridge.codexInactivePlugins !== undefined) {
|
|
9423
9469
|
const controls = array(bridge.codexInactivePlugins, 4096), ids = new Set;
|
|
9424
|
-
requireBound(controls.length === 0 || object(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version
|
|
9470
|
+
requireBound(controls.length === 0 || object(bridge.codexPluginSkillReview) && supportsCodexNativeCapability(bridge.codexPluginSkillReview.version, "installed-plugin-review") && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
|
|
9425
9471
|
for (const control of controls) {
|
|
9426
9472
|
requireBound(object(control) && Object.keys(control).every((key) => ["pluginId", "namespace", "pluginParent", "sourceType", "sourceSha256"].includes(key)));
|
|
9427
9473
|
text(control.pluginId, 1024);
|
|
@@ -9473,7 +9519,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9473
9519
|
}
|
|
9474
9520
|
if (value.codexInstallationInputs !== undefined) {
|
|
9475
9521
|
const proof = record(value.codexInstallationInputs, 4), inputs = array(proof.plugins, 4096), ids = new Set;
|
|
9476
|
-
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && proof.version
|
|
9522
|
+
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && supportsCodexNativeCapability(proof.version, "installed-plugin-review") && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
|
|
9477
9523
|
for (const input of inputs) {
|
|
9478
9524
|
requireBound(object(input) && Object.keys(input).every((key) => ["pluginId", "namespace", "pluginParent", "sourceRoot", "sourceSha256"].includes(key)));
|
|
9479
9525
|
text(input.pluginId, 1024);
|
|
@@ -9497,14 +9543,14 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9497
9543
|
text(source.path);
|
|
9498
9544
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
9499
9545
|
if (source.hashMode !== undefined)
|
|
9500
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
9546
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-settings-v4", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
9501
9547
|
if (source.hashMode === "claude-plugin-manifest-v1")
|
|
9502
9548
|
requireBound(agent === "claude" && value.agent === "claude" && ["automatic", "reviewed"].includes(value.method) && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve3(source.path) === source.path && source.path.endsWith(join7(sep2, ".claude-plugin", "plugin.json")) && source.managedPlugins === undefined);
|
|
9503
9549
|
if (source.hashMode === "sumi-settings-v1")
|
|
9504
9550
|
requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve3(source.path) === source.path && basename3(source.path) === "sumi.json");
|
|
9505
9551
|
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
|
|
9506
9552
|
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve3(source.path) === source.path && basename3(source.path) === "config.toml");
|
|
9507
|
-
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
|
|
9553
|
+
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4"))
|
|
9508
9554
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve3(source.path) === source.path && basename3(source.path) === "settings.json");
|
|
9509
9555
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2")
|
|
9510
9556
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve3(source.path) === source.path && basename3(source.path) === "known_marketplaces.json");
|
|
@@ -11572,7 +11618,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
|
|
|
11572
11618
|
// package.json
|
|
11573
11619
|
var package_default = {
|
|
11574
11620
|
name: "@hasna/skills",
|
|
11575
|
-
version: "0.10.
|
|
11621
|
+
version: "0.10.51",
|
|
11576
11622
|
description: "Skills library for AI coding agents",
|
|
11577
11623
|
type: "module",
|
|
11578
11624
|
bin: {
|
|
@@ -13660,25 +13706,6 @@ function isCodexLocalStdioMcpServer(name, server) {
|
|
|
13660
13706
|
import { basename as basename6, dirname as dirname11, join as join17, relative as relative5, resolve as resolve10, sep as sep6 } from "path";
|
|
13661
13707
|
import { lstatSync as lstatSync13, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as realpathSync6 } from "fs";
|
|
13662
13708
|
|
|
13663
|
-
// src/lib/codex-native-compatibility.ts
|
|
13664
|
-
var MEASURED_CODEX_CAPABILITIES = {
|
|
13665
|
-
"codex-cli 0.153.0": ["hooks"],
|
|
13666
|
-
"codex-cli 0.154.0": ["hooks"],
|
|
13667
|
-
"codex-cli 0.155.0": ["hooks"],
|
|
13668
|
-
"codex-cli 0.155.1": ["hooks"],
|
|
13669
|
-
"codex-cli 0.156.1": ["hooks"],
|
|
13670
|
-
"codex-cli 0.157.0": ["hooks"],
|
|
13671
|
-
"codex-cli 0.157.1": ["hooks"],
|
|
13672
|
-
"codex-cli 0.158.0": ["hooks"],
|
|
13673
|
-
"codex-cli 0.159.0": ["hooks"],
|
|
13674
|
-
"codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
|
|
13675
|
-
"codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
|
|
13676
|
-
};
|
|
13677
|
-
function supportsCodexNativeCapability(version, capability) {
|
|
13678
|
-
return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
|
|
13679
|
-
}
|
|
13680
|
-
var SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
|
|
13681
|
-
|
|
13682
13709
|
// src/lib/codex-native-skill-catalog.ts
|
|
13683
13710
|
import { realpathSync as realpathSync5 } from "fs";
|
|
13684
13711
|
import { isAbsolute as isAbsolute11, normalize as normalize2 } from "path";
|
|
@@ -14273,6 +14300,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read2, rules)
|
|
|
14273
14300
|
function reviewCodexPluginControls(catalog, documents, cache, cwd, read2, rules, pluginSettings, plannedRules, denials = []) {
|
|
14274
14301
|
if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd)
|
|
14275
14302
|
refuse2();
|
|
14303
|
+
const installedPluginReview = supportsCodexNativeCapability(catalog.version, "installed-plugin-review");
|
|
14276
14304
|
if (!Array.isArray(denials) || denials.length > 4096 || new Set(denials.map((item) => item?.path)).size !== denials.length || denials.some((item) => !item || Object.keys(item).sort().join(",") !== "name,path,sha256" || typeof item.name !== "string" || typeof item.path !== "string" || !/^[a-f0-9]{64}$/.test(item.sha256)))
|
|
14277
14305
|
refuse2();
|
|
14278
14306
|
const usedDenials = new Set;
|
|
@@ -14304,7 +14332,7 @@ function reviewCodexPluginControls(catalog, documents, cache, cwd, read2, rules,
|
|
|
14304
14332
|
if (listed.length > 1)
|
|
14305
14333
|
refuse2();
|
|
14306
14334
|
const installed = installedPlugins.filter((plugin) => plugin.id === expectedPluginId && plugin.name === pluginName);
|
|
14307
|
-
if (
|
|
14335
|
+
if (installedPluginReview && installed.length === 1 && installed[0].installed && installed[0].localVersion === basename6(located.root) && installed[0].sourceType === "local" && codexPluginSourceIsConfigControlled(installed[0])) {
|
|
14308
14336
|
const plugin = installed[0], input = { pluginId: expectedPluginId, namespace: located.namespace, pluginParent: located.pluginParent, sourceRoot: plugin.sourcePath, sourceSha256: plugin.sourceSha256 };
|
|
14309
14337
|
if (input.sourceRoot !== located.root && !input.sourceRoot.startsWith(cache + sep6) && (lstatSync13(input.sourceRoot, { throwIfNoEntry: false }) || documents.some((path) => path.startsWith(input.sourceRoot + sep6)))) {
|
|
14310
14338
|
if (skills.some((skill) => skill.path === input.sourceRoot || skill.path.startsWith(input.sourceRoot + sep6)) || !sourceInputUnchanged(input, cache, read2))
|
|
@@ -14313,7 +14341,7 @@ function reviewCodexPluginControls(catalog, documents, cache, cwd, read2, rules,
|
|
|
14313
14341
|
}
|
|
14314
14342
|
}
|
|
14315
14343
|
const settings = pluginSettings && typeof pluginSettings === "object" && !Array.isArray(pluginSettings) ? pluginSettings : undefined;
|
|
14316
|
-
if (
|
|
14344
|
+
if (installedPluginReview && !listed.length && !skills.some((skill) => skill.pluginId === expectedPluginId) && installed.length === 1 && installed[0].installed && !installed[0].enabled && codexPluginSourceIsConfigControlled(installed[0]) && settings && Object.hasOwn(settings, expectedPluginId) && settings[expectedPluginId]?.enabled === false) {
|
|
14317
14345
|
if (!Array.isArray(rules))
|
|
14318
14346
|
refuse2();
|
|
14319
14347
|
const exactPathDeny = rules.some((rule) => rule?.path === document2 && rule?.enabled === false);
|
|
@@ -14346,12 +14374,12 @@ function reviewCodexPluginControls(catalog, documents, cache, cwd, read2, rules,
|
|
|
14346
14374
|
const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document2 && rule?.enabled === false);
|
|
14347
14375
|
const nativeSkill = { name: parsed.name, path: document2, pluginId: expectedPluginId, enabled: true };
|
|
14348
14376
|
const denial = denials.find((item) => item.path === document2);
|
|
14349
|
-
const explicitDeny = denial !== undefined && remotePluginId !== undefined &&
|
|
14377
|
+
const explicitDeny = denial !== undefined && remotePluginId !== undefined && installedPluginReview && denial.name === parsed.name && denial.sha256 === createHash12("sha256").update(read2(document2)).digest("hex") && Array.isArray(rules) && !rules.some((rule) => (rule?.path === document2 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document2 && rule.enabled === false);
|
|
14350
14378
|
if (denial && !explicitDeny)
|
|
14351
14379
|
refuse2();
|
|
14352
14380
|
if (explicitDeny)
|
|
14353
14381
|
usedDenials.add(document2);
|
|
14354
|
-
const plannedPathDeny =
|
|
14382
|
+
const plannedPathDeny = installedPluginReview && remotePluginId !== undefined && Array.isArray(rules) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === parsed.name && rule.enabled === false) && !rules.some((rule) => (rule?.path === document2 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document2 && rule.enabled === false) && isCodexNativeSkillDisabled(nativeSkill, plannedRules);
|
|
14355
14383
|
if (!explicitDeny && (!exactPathDeny && !plannedPathDeny || !isCodexNativeSkillDisabled(nativeSkill, rules)))
|
|
14356
14384
|
refuse2();
|
|
14357
14385
|
}
|
|
@@ -16939,7 +16967,7 @@ function planAgentIntegration(options) {
|
|
|
16939
16967
|
const { codexInstallationInputs: previousInputs, ...current } = rebound;
|
|
16940
16968
|
const inputs = codexPluginSourceInputs.map((input) => input.sourceRoot);
|
|
16941
16969
|
const directories = options.codexNativeCatalog || !previousInputs ? captureDiscoveryDirectories((binding.directories ?? []).filter((directory) => inputs.some((root) => root.startsWith(directory.path + sep7))).map((directory) => directory.path), inputs) : previousInputs.directories;
|
|
16942
|
-
const installed = codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version:
|
|
16970
|
+
const installed = codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: codexPluginSkillReview.version, catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
|
|
16943
16971
|
return captureRetiredCodexDiscovery(installed, codexPluginSkills, Bun.TOML.parse(changes.find((change) => change.path === canonicalAgentPath(join23(home, ".codex/config.toml"), aliases))?.after ?? codexConfigBefore ?? "").skills?.config ?? []);
|
|
16944
16972
|
});
|
|
16945
16973
|
const nextPolicy = { ...policy, version: 1, loading: "cli", profileId, bridge: {
|
|
@@ -17254,6 +17282,8 @@ function atomicWrite2(path, content) {
|
|
|
17254
17282
|
function planAgentSettingsWitnessUpgrade(options) {
|
|
17255
17283
|
if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3, 4].includes(options.targetCodexVersion)))
|
|
17256
17284
|
throw new Error("Invalid Codex witness target version");
|
|
17285
|
+
if (options.targetClaudeVersion !== undefined && (options.agent !== "claude" || ![3, 4].includes(options.targetClaudeVersion)))
|
|
17286
|
+
throw new Error("Invalid Claude witness target version");
|
|
17257
17287
|
const home = resolve13(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
17258
17288
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
17259
17289
|
if (!snapshot2 || sha3(snapshot2.text) !== options.expectedPolicySha256)
|
|
@@ -17301,7 +17331,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
17301
17331
|
replaced.push(source);
|
|
17302
17332
|
}
|
|
17303
17333
|
}
|
|
17304
|
-
const next = options.agent === "sumi" ? upgradeSumiSettingsWitness(previous, options.reviewedPreimage) : options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 4 ? upgradeCodexSettingsWitnessV4(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
|
|
17334
|
+
const next = options.agent === "sumi" ? upgradeSumiSettingsWitness(previous, options.reviewedPreimage) : options.agent === "claude" ? options.targetClaudeVersion === 4 ? upgradeClaudeSettingsWitnessV4(previous, options.reviewedPreimage) : upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 4 ? upgradeCodexSettingsWitnessV4(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
|
|
17305
17335
|
const rebound = [];
|
|
17306
17336
|
for (const source of binding.sources) {
|
|
17307
17337
|
if (!replaced.includes(source)) {
|
|
@@ -17347,7 +17377,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
17347
17377
|
const upgrade = plan.settingsWitnessUpgrade;
|
|
17348
17378
|
if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
|
|
17349
17379
|
throw new Error("Invalid settings witness upgrade plan");
|
|
17350
|
-
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, ...upgrade.agent === "codex" ? { targetCodexVersion: upgrade.toHashMode === "codex-settings-v4" ? 4 : upgrade.toHashMode === "codex-settings-v3" ? 3 : 2 } : {}, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
|
|
17380
|
+
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, ...upgrade.agent === "codex" ? { targetCodexVersion: upgrade.toHashMode === "codex-settings-v4" ? 4 : upgrade.toHashMode === "codex-settings-v3" ? 3 : 2 } : {}, ...upgrade.agent === "claude" && upgrade.toHashMode === "claude-settings-v4" ? { targetClaudeVersion: 4 } : {}, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
|
|
17351
17381
|
if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
|
|
17352
17382
|
throw new Error("Settings witness upgrade plan changed");
|
|
17353
17383
|
provenDiscovery = verified.discoveryBefore[0];
|
|
@@ -20394,13 +20424,13 @@ function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
|
20394
20424
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
20395
20425
|
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
20396
20426
|
}
|
|
20397
|
-
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
|
|
20427
|
+
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) {
|
|
20398
20428
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
20399
20429
|
throw new Error("Claude settings witnesses require exact typed metadata");
|
|
20400
|
-
const current = (source.hashMode === "claude-settings-v3" ? captureClaudeSettingsV3 : source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget2).sha256;
|
|
20430
|
+
const current = (source.hashMode === "claude-settings-v4" ? captureClaudeSettingsV4 : source.hashMode === "claude-settings-v3" ? captureClaudeSettingsV3 : source.hashMode === "claude-settings-v2" ? captureClaudeSettingsV2 : captureClaudeSettings)(source.path, budget2).sha256;
|
|
20401
20431
|
if (current !== source.sha256)
|
|
20402
20432
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
20403
|
-
return changes?.has(source.path) ? (source.hashMode === "claude-settings-v3" ? hashClaudeSettingsReplacementV3 : source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
20433
|
+
return changes?.has(source.path) ? (source.hashMode === "claude-settings-v4" ? hashClaudeSettingsReplacementV4 : source.hashMode === "claude-settings-v3" ? hashClaudeSettingsReplacementV3 : source.hashMode === "claude-settings-v2" ? hashClaudeSettingsReplacementV2 : hashClaudeSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
20404
20434
|
}
|
|
20405
20435
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") {
|
|
20406
20436
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256) || changes?.has(source.path))
|
|
@@ -20611,7 +20641,7 @@ function codexInstallationRoots(binding) {
|
|
|
20611
20641
|
const proof = binding.codexInstallationInputs;
|
|
20612
20642
|
if (proof === undefined)
|
|
20613
20643
|
return [];
|
|
20614
|
-
if (binding.agent !== "codex" || binding.method !== "reviewed" || proof.version
|
|
20644
|
+
if (binding.agent !== "codex" || binding.method !== "reviewed" || !supportsCodexNativeCapability(proof.version, "installed-plugin-review") || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
|
|
20615
20645
|
throw new Error("Invalid native installation input proof");
|
|
20616
20646
|
const cache = dirname19(dirname19(proof.plugins[0].pluginParent));
|
|
20617
20647
|
const config = join32(dirname19(dirname19(cache)), "config.toml"), home = dirname19(dirname19(dirname19(cache)));
|
|
@@ -20635,7 +20665,7 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
20635
20665
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
20636
20666
|
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename10(source.path) !== "config.toml"))
|
|
20637
20667
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
20638
|
-
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename10(source.path) !== "settings.json"))
|
|
20668
|
+
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) && (binding.agent !== "claude" || binding.method !== "reviewed" || basename10(source.path) !== "settings.json"))
|
|
20639
20669
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
20640
20670
|
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
20641
20671
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
@@ -20837,7 +20867,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20837
20867
|
verifyAgentDiscovery(retained);
|
|
20838
20868
|
if (!retained.sources.some((source) => source.path === canonical7(configPath) && source.format === undefined && source.fields === undefined))
|
|
20839
20869
|
unresolved("retained review is missing the full agent configuration source");
|
|
20840
|
-
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
20870
|
+
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
20841
20871
|
unresolved("retained settings witness names another configuration source");
|
|
20842
20872
|
const covered = supersedesSettingsProjection(agent, retained.sources, canonical7(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical7(configPath), source)) : sources;
|
|
20843
20873
|
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual7(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
@@ -20851,7 +20881,7 @@ function resolveAgentDiscovery(options) {
|
|
|
20851
20881
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
20852
20882
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
20853
20883
|
verifyAgentDiscovery(supplied);
|
|
20854
|
-
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
20884
|
+
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
20855
20885
|
throw new Error("Semantic settings witnesses must name the configured agent configuration source");
|
|
20856
20886
|
if (!review.sources.some((source) => source.path === canonical7(configPath)))
|
|
20857
20887
|
throw new Error("Discovery review must include the agent configuration source");
|
|
@@ -47854,6 +47884,7 @@ export {
|
|
|
47854
47884
|
upgradeCodexSettingsWitnessV4,
|
|
47855
47885
|
upgradeCodexSettingsWitnessV3,
|
|
47856
47886
|
upgradeCodexSettingsWitness,
|
|
47887
|
+
upgradeClaudeSettingsWitnessV4,
|
|
47857
47888
|
upgradeClaudeSettingsWitness,
|
|
47858
47889
|
updateSkillRun,
|
|
47859
47890
|
unsetConfig,
|
|
@@ -48045,6 +48076,7 @@ export {
|
|
|
48045
48076
|
captureCodexSettingsV2,
|
|
48046
48077
|
captureCodexSettings,
|
|
48047
48078
|
captureCodexNativeSkillCatalog,
|
|
48079
|
+
captureClaudeSettingsV4,
|
|
48048
48080
|
captureClaudeSettingsV3,
|
|
48049
48081
|
captureClaudeSettingsV2,
|
|
48050
48082
|
captureClaudeSettings,
|
|
@@ -7,7 +7,7 @@ export { captureDiscoveryDirectories, type DiscoveryDirectory } from "./agent-di
|
|
|
7
7
|
export interface DiscoverySource {
|
|
8
8
|
path: string;
|
|
9
9
|
sha256: string | null;
|
|
10
|
-
hashMode?: "bytes" | "path-bytes" | "claude-plugin-manifest-v1" | "claude-plugin-registry" | "claude-marketplace-registry" | "claude-settings-v1" | "claude-settings-v2" | "claude-settings-v3" | "claude-marketplace-registry-v2" | "codex-settings-v1" | "codex-settings-v2" | "codex-settings-v3" | "codex-settings-v4" | "sumi-settings-v1";
|
|
10
|
+
hashMode?: "bytes" | "path-bytes" | "claude-plugin-manifest-v1" | "claude-plugin-registry" | "claude-marketplace-registry" | "claude-settings-v1" | "claude-settings-v2" | "claude-settings-v3" | "claude-settings-v4" | "claude-marketplace-registry-v2" | "codex-settings-v1" | "codex-settings-v2" | "codex-settings-v3" | "codex-settings-v4" | "sumi-settings-v1";
|
|
11
11
|
managedPlugins?: ManagedPluginRegistrationWitness[];
|
|
12
12
|
format?: "json" | "toml" | "yaml";
|
|
13
13
|
fields?: string[];
|
|
@@ -28,7 +28,7 @@ export interface AgentDiscoveryBinding {
|
|
|
28
28
|
}>;
|
|
29
29
|
};
|
|
30
30
|
codexInstallationInputs?: {
|
|
31
|
-
version:
|
|
31
|
+
version: string;
|
|
32
32
|
catalogSha256: string;
|
|
33
33
|
plugins: CodexPluginSourceInput[];
|
|
34
34
|
directories?: DiscoveryDirectory[];
|
|
@@ -190,6 +190,7 @@ export declare function planClaudeHookEventsUpdate(options: ClaudeHookUpdateOpti
|
|
|
190
190
|
export declare function planAgentSettingsWitnessUpgrade(options: {
|
|
191
191
|
agent: "claude" | "codex" | "sumi";
|
|
192
192
|
targetCodexVersion?: 2 | 3 | 4;
|
|
193
|
+
targetClaudeVersion?: 3 | 4;
|
|
193
194
|
reviewedPreimage: string;
|
|
194
195
|
home?: string;
|
|
195
196
|
dataDir?: string;
|
|
@@ -10,6 +10,7 @@ export interface ClaudeSettingsWitnessBudget {
|
|
|
10
10
|
remaining: number;
|
|
11
11
|
}
|
|
12
12
|
export declare function readNativeSettingsWitnessFile(path: string, budget: ClaudeSettingsWitnessBudget, filename?: "settings.json" | "config.toml" | "sumi.json"): string;
|
|
13
|
+
export declare const CLAUDE_BUILTIN_THEMES: readonly ["auto", "dark", "light", "dark-daltonized", "light-daltonized", "dark-ansi", "light-ansi"];
|
|
13
14
|
/** Cooperating installers may replace only their explicitly selected event. Compare the strict syntax
|
|
14
15
|
* trees, not JSON.parse values or the preference-tolerant witness digest: all
|
|
15
16
|
* other hooks, discovery settings, unknown values and number spellings remain
|
|
@@ -51,6 +52,24 @@ export declare function upgradeClaudeSettingsWitness(previous: {
|
|
|
51
52
|
hashMode?: "bytes" | "claude-settings-v1" | "claude-settings-v2";
|
|
52
53
|
sha256: string;
|
|
53
54
|
}, reviewedSettingsPath: string): ReturnType<typeof captureClaudeSettingsV3>;
|
|
55
|
+
/** Explicit review that additionally permits a built-in top-level theme.
|
|
56
|
+
* v1/v2/v3 witnesses keep their meaning; nothing selects v4 implicitly. */
|
|
57
|
+
export declare function captureClaudeSettingsV4(path: string, budget?: ClaudeSettingsWitnessBudget): {
|
|
58
|
+
path: string;
|
|
59
|
+
hashMode: "claude-settings-v4";
|
|
60
|
+
sha256: string;
|
|
61
|
+
};
|
|
62
|
+
export declare function hashClaudeSettingsReplacementV4(text: string, budget: ClaudeSettingsWitnessBudget): string;
|
|
63
|
+
/** Explicit opt-in upgrade to v4 with an exact preserved preimage of the prior
|
|
64
|
+
* review (raw bytes, v1, v2 or v3). It proves that every setting v4 binds is
|
|
65
|
+
* unchanged; any other drift, including skipDangerousModePermissionPrompt,
|
|
66
|
+
* refuses. A stored witness is never rewritten without this call.
|
|
67
|
+
*/
|
|
68
|
+
export declare function upgradeClaudeSettingsWitnessV4(previous: {
|
|
69
|
+
path: string;
|
|
70
|
+
hashMode?: "bytes" | "claude-settings-v1" | "claude-settings-v2" | "claude-settings-v3";
|
|
71
|
+
sha256: string;
|
|
72
|
+
}, reviewedSettingsPath: string): ReturnType<typeof captureClaudeSettingsV4>;
|
|
54
73
|
/** Strict bounded JSON control witness; metadata exclusion must be explicit. */
|
|
55
74
|
export declare function hashNativeJsonControls(text: string, excludedMetadata?: "version"): string;
|
|
56
75
|
/** Sumi's versioned review uses the same strict JSON parser and bounded syntax
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** `installed-plugin-review`: the 0.160 `plugin/installed` source identities and
|
|
2
|
+
* plugin loader semantics behind local installation inputs, inert disabled
|
|
3
|
+
* nonremote plugins and remote refresh denials. */
|
|
4
|
+
export type CodexNativeCapability = "hooks" | "qualified-skill-catalog" | "installed-plugin-review";
|
|
2
5
|
export declare function supportsCodexNativeCapability(version: unknown, capability: CodexNativeCapability): boolean;
|
|
3
6
|
export declare const SUPPORTED_CODEX_HOOK_VERSIONS: readonly string[];
|