@hasna/skills 0.10.64 → 0.10.66
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 +7 -1
- package/bin/index.js +511 -211
- package/bin/mcp.js +335 -40
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +426 -61
- package/dist/lib/agent-discovery.d.ts +3 -2
- package/dist/lib/agent-integration.d.ts +2 -0
- package/dist/lib/codex-semantic-cache-witness.d.ts +23 -0
- package/dist/lib/hook-diagnostics.d.ts +2 -0
- package/dist/runtime-prerequisites.js +133 -14
- package/dist/sdk/index.js +437 -72
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7262,7 +7262,7 @@ import {
|
|
|
7262
7262
|
statSync as statSync12,
|
|
7263
7263
|
writeFileSync as writeFileSync9
|
|
7264
7264
|
} from "fs";
|
|
7265
|
-
import { basename as
|
|
7265
|
+
import { basename as basename15, dirname as dirname25, isAbsolute as isAbsolute25, join as join37, normalize as normalize4, relative as relative10, resolve as resolve25, sep as sep13 } from "path";
|
|
7266
7266
|
|
|
7267
7267
|
// src/lib/registry-data/index.ts
|
|
7268
7268
|
var SKILLS = [];
|
|
@@ -8922,7 +8922,7 @@ var NATIVE_SKILL_ROOTS = [
|
|
|
8922
8922
|
// src/lib/authoring-path.ts
|
|
8923
8923
|
import { lstatSync as lstatSync29, realpathSync as realpathSync14 } from "fs";
|
|
8924
8924
|
import { homedir as homedir6 } from "os";
|
|
8925
|
-
import { basename as
|
|
8925
|
+
import { basename as basename14, dirname as dirname24, join as join36, resolve as resolve24, sep as sep12 } from "path";
|
|
8926
8926
|
|
|
8927
8927
|
// src/lib/agent-adapters.ts
|
|
8928
8928
|
var INTEGRATION_AGENTS = ["claude", "codex", "gemini", "opencode", "cursor", "hermes", "sumi"];
|
|
@@ -9744,8 +9744,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9744
9744
|
}
|
|
9745
9745
|
}
|
|
9746
9746
|
if (value.codexSemanticCache !== undefined) {
|
|
9747
|
-
const proof = record(value.codexSemanticCache,
|
|
9748
|
-
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && Object.keys(proof).length
|
|
9747
|
+
const proof = record(value.codexSemanticCache, 9), witness = record(proof.witness, 7);
|
|
9748
|
+
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && [8, 9].includes(Object.keys(proof).length) && Object.keys(proof).every((key) => ["schema", "configPath", "hookRootAlias", "witness", "appOnlyParents", "previousPolicySha256", "supersededSources", "supersededDirectories", "reviewedHookParents"].includes(key)) && proof.schema === "hasna.codex-semantic-cache-discovery.v1" && typeof proof.previousPolicySha256 === "string" && /^[a-f0-9]{64}$/.test(proof.previousPolicySha256) && [6, 7].includes(Object.keys(witness).length) && Object.keys(witness).every((key) => ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256", "hookParents"].includes(key)) && witness.schema === "hasna.codex-semantic-cache-witness.v1" && typeof witness.sha256 === "string" && /^[a-f0-9]{64}$/.test(witness.sha256));
|
|
9749
9749
|
text(proof.configPath);
|
|
9750
9750
|
requireBound(isAbsolute4(proof.configPath) && resolve4(proof.configPath) === proof.configPath && basename4(proof.configPath) === "config.toml");
|
|
9751
9751
|
text(witness.cacheRoot);
|
|
@@ -9764,6 +9764,20 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9764
9764
|
text(parent[key]);
|
|
9765
9765
|
requireBound(isAbsolute4(parent.pluginParent) && resolve4(parent.pluginParent) === parent.pluginParent);
|
|
9766
9766
|
}
|
|
9767
|
+
if (proof.reviewedHookParents !== undefined)
|
|
9768
|
+
for (const parent of array(proof.reviewedHookParents, 4096)) {
|
|
9769
|
+
requireBound(object(parent) && parent.role === "reviewed-hook" && (parent.installation === "remote-receipt" && Object.keys(parent).length === 6 || parent.installation === "local-marketplace" && Object.keys(parent).length === 7));
|
|
9770
|
+
requireBound(parent.installation === "remote-receipt" ? Object.keys(parent).sort().join(",") === "installation,namespace,pluginId,pluginParent,remotePluginId,role" : Object.keys(parent).sort().join(",") === "installation,marketplaceSha256,marketplaceSourcePath,namespace,pluginId,pluginParent,role");
|
|
9771
|
+
for (const key of ["pluginId", "namespace", "pluginParent", "installation"])
|
|
9772
|
+
text(parent[key]);
|
|
9773
|
+
if (parent.installation === "remote-receipt")
|
|
9774
|
+
text(parent.remotePluginId);
|
|
9775
|
+
else {
|
|
9776
|
+
text(parent.marketplaceSourcePath);
|
|
9777
|
+
requireBound(typeof parent.marketplaceSha256 === "string" && /^[a-f0-9]{64}$/.test(parent.marketplaceSha256) && isAbsolute4(parent.marketplaceSourcePath) && resolve4(parent.marketplaceSourcePath) === parent.marketplaceSourcePath && basename4(parent.marketplaceSourcePath) === "marketplace.json");
|
|
9778
|
+
}
|
|
9779
|
+
requireBound(isAbsolute4(parent.pluginParent) && resolve4(parent.pluginParent) === parent.pluginParent);
|
|
9780
|
+
}
|
|
9767
9781
|
for (const row of [...array(witness.controls, 4096), ...array(witness.appOnlyParents, 4096)]) {
|
|
9768
9782
|
requireBound(object(row));
|
|
9769
9783
|
for (const key of ["pluginId", "namespace", "pluginParent"])
|
|
@@ -9772,6 +9786,26 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9772
9786
|
if (row[key] !== undefined)
|
|
9773
9787
|
requireBound(typeof row[key] === "string" && /^[a-f0-9]{64}$/.test(row[key]));
|
|
9774
9788
|
}
|
|
9789
|
+
if (witness.hookParents !== undefined)
|
|
9790
|
+
for (const row of array(witness.hookParents, 4096)) {
|
|
9791
|
+
requireBound(object(row) && row.role === "reviewed-hook" && (row.installation === "remote-receipt" && Object.keys(row).length === 9 || row.installation === "local-marketplace" && Object.keys(row).length === 9));
|
|
9792
|
+
requireBound(row.installation === "remote-receipt" ? Object.keys(row).sort().join(",") === "hooksSha256,installation,manifestSha256,namespace,pluginId,pluginParent,receiptSha256,remotePluginId,role" : Object.keys(row).sort().join(",") === "hooksSha256,installation,manifestSha256,marketplaceSha256,marketplaceSourcePath,namespace,pluginId,pluginParent,role");
|
|
9793
|
+
for (const key of ["pluginId", "namespace", "pluginParent", "installation"])
|
|
9794
|
+
text(row[key]);
|
|
9795
|
+
if (row.installation === "remote-receipt")
|
|
9796
|
+
text(row.remotePluginId);
|
|
9797
|
+
else {
|
|
9798
|
+
text(row.marketplaceSourcePath);
|
|
9799
|
+
requireBound(typeof row.marketplaceSha256 === "string" && /^[a-f0-9]{64}$/.test(row.marketplaceSha256) && isAbsolute4(row.marketplaceSourcePath) && resolve4(row.marketplaceSourcePath) === row.marketplaceSourcePath && basename4(row.marketplaceSourcePath) === "marketplace.json");
|
|
9800
|
+
}
|
|
9801
|
+
requireBound(isAbsolute4(row.pluginParent) && resolve4(row.pluginParent) === row.pluginParent);
|
|
9802
|
+
for (const key of ["manifestSha256", "hooksSha256"])
|
|
9803
|
+
requireBound(typeof row[key] === "string" && /^[a-f0-9]{64}$/.test(row[key]));
|
|
9804
|
+
if (row.installation === "remote-receipt")
|
|
9805
|
+
requireBound(typeof row.receiptSha256 === "string" && /^[a-f0-9]{64}$/.test(row.receiptSha256));
|
|
9806
|
+
else
|
|
9807
|
+
requireBound(row.receiptSha256 === undefined);
|
|
9808
|
+
}
|
|
9775
9809
|
for (const skill of array(witness.skills, 4096)) {
|
|
9776
9810
|
requireBound(object(skill));
|
|
9777
9811
|
for (const key of ["name", "pluginId", "namespace", "pluginParent"])
|
|
@@ -9851,7 +9885,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
9851
9885
|
// src/lib/agent-discovery.ts
|
|
9852
9886
|
import { createHash as createHash28 } from "crypto";
|
|
9853
9887
|
import { lstatSync as lstatSync28, readFileSync as readFileSync21, readdirSync as readdirSync11, realpathSync as realpathSync13 } from "fs";
|
|
9854
|
-
import { basename as
|
|
9888
|
+
import { basename as basename13, dirname as dirname23, isAbsolute as isAbsolute24, join as join35, relative as relative9, resolve as resolve23, sep as sep11 } from "path";
|
|
9855
9889
|
import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
|
|
9856
9890
|
|
|
9857
9891
|
// node_modules/yaml/dist/index.js
|
|
@@ -10542,7 +10576,7 @@ function projectReviewedClaudePluginManifest(text2, reviewedSha256) {
|
|
|
10542
10576
|
|
|
10543
10577
|
// src/lib/plugin-discovery.ts
|
|
10544
10578
|
import { closeSync as closeSync16, constants as constants17, fstatSync as fstatSync16, lstatSync as lstatSync26, openSync as openSync16, opendirSync as opendirSync5, readSync as readSync12 } from "fs";
|
|
10545
|
-
import { basename as
|
|
10579
|
+
import { basename as basename11, dirname as dirname21, isAbsolute as isAbsolute22, join as join34, resolve as resolve21 } from "path";
|
|
10546
10580
|
|
|
10547
10581
|
// src/lib/plugin-admission.ts
|
|
10548
10582
|
import { homedir as homedir5 } from "os";
|
|
@@ -11888,7 +11922,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
|
|
|
11888
11922
|
});
|
|
11889
11923
|
}
|
|
11890
11924
|
// package.json
|
|
11891
|
-
var version = "0.10.
|
|
11925
|
+
var version = "0.10.66";
|
|
11892
11926
|
var package_default = {
|
|
11893
11927
|
name: "@hasna/skills",
|
|
11894
11928
|
version,
|
|
@@ -14246,7 +14280,7 @@ import {
|
|
|
14246
14280
|
writeFileSync as writeFileSync7
|
|
14247
14281
|
} from "fs";
|
|
14248
14282
|
import { homedir as homedir3 } from "os";
|
|
14249
|
-
import { basename as
|
|
14283
|
+
import { basename as basename10, dirname as dirname19, join as join28 } from "path";
|
|
14250
14284
|
|
|
14251
14285
|
// src/lib/codex-plugin-skill-controls.ts
|
|
14252
14286
|
import { createHash as createHash14 } from "crypto";
|
|
@@ -16178,7 +16212,7 @@ function upgradeCodexSettingsWitnessV5(previous, reviewedSettingsPath) {
|
|
|
16178
16212
|
// src/lib/codex-semantic-cache-witness.ts
|
|
16179
16213
|
import { createHash as createHash18 } from "crypto";
|
|
16180
16214
|
import { constants as constants9, closeSync as closeSync9, fstatSync as fstatSync9, lstatSync as lstatSync16, openSync as openSync9, readSync as readSync6, readdirSync as readdirSync7, realpathSync as realpathSync9 } from "fs";
|
|
16181
|
-
import { dirname as dirname15, isAbsolute as isAbsolute14, join as join20, relative as relative7, resolve as resolve14, sep as sep8 } from "path";
|
|
16215
|
+
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute14, join as join20, relative as relative7, resolve as resolve14, sep as sep8 } from "path";
|
|
16182
16216
|
var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1";
|
|
16183
16217
|
var identifier3 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value);
|
|
16184
16218
|
var digest = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
|
|
@@ -16187,6 +16221,24 @@ var refuse4 = () => {
|
|
|
16187
16221
|
};
|
|
16188
16222
|
var MAX_DOCUMENT_BYTES = 1024 * 1024;
|
|
16189
16223
|
var MAX_RECEIPT_BYTES = 16 * 1024;
|
|
16224
|
+
function codexLocalMarketplaceMapsPlugin(text2, marketplace, plugin) {
|
|
16225
|
+
try {
|
|
16226
|
+
hashNativeJsonControls(text2);
|
|
16227
|
+
const value = JSON.parse(text2);
|
|
16228
|
+
if (!plainObject(value) || !exactKeys(value, ["interface", "name", "plugins"]) || value.name !== marketplace || !(typeof value.interface === "string" || Number.isSafeInteger(value.interface)) || !Array.isArray(value.plugins) || value.plugins.length < 1 || value.plugins.length > 4096)
|
|
16229
|
+
return false;
|
|
16230
|
+
const rows = value.plugins.filter((row2) => plainObject(row2) && row2.name === plugin);
|
|
16231
|
+
if (rows.length !== 1)
|
|
16232
|
+
return false;
|
|
16233
|
+
const row = rows[0];
|
|
16234
|
+
if (!exactKeys(row, ["name", "source"]) || !plainObject(row.source) || !exactKeys(row.source, ["source", "path"]) || row.source.source !== "local" || typeof row.source.path !== "string" || !row.source.path.startsWith("./") || row.source.path.includes("\\"))
|
|
16235
|
+
return false;
|
|
16236
|
+
const parts = row.source.path.split("/");
|
|
16237
|
+
return parts[0] === "." && parts.length > 1 && parts.slice(1).every((part) => /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(part)) && parts.at(-1) === plugin;
|
|
16238
|
+
} catch {
|
|
16239
|
+
return false;
|
|
16240
|
+
}
|
|
16241
|
+
}
|
|
16190
16242
|
function defaultRead(path) {
|
|
16191
16243
|
const before = lstatSync16(path, { throwIfNoEntry: false, bigint: true });
|
|
16192
16244
|
if (before === undefined)
|
|
@@ -16248,7 +16300,7 @@ function validPluginParent(cacheRoot, pluginParent, namespace, pluginId) {
|
|
|
16248
16300
|
return parts.length === 2 && parts.every(identifier3) && parts[1] === namespace && pluginId === `${namespace}@${parts[0]}`;
|
|
16249
16301
|
}
|
|
16250
16302
|
function assertWitnessShape(value) {
|
|
16251
|
-
if (!plainObject(value) || !exactKeys(value, ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256"]) || value.schema !== CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA || typeof value.cacheRoot !== "string" || !isAbsolute14(value.cacheRoot) || resolve14(value.cacheRoot) !== value.cacheRoot || !digest(value.sha256) || !Array.isArray(value.controls) || value.controls.length === 0 || value.controls.length > 4096 || !Array.isArray(value.appOnlyParents) || value.appOnlyParents.length > 4096 || !Array.isArray(value.skills) || value.skills.length === 0 || value.skills.length > 4096)
|
|
16303
|
+
if (!plainObject(value) || !exactKeys(value, ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256"], ["hookParents"]) || value.schema !== CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA || typeof value.cacheRoot !== "string" || !isAbsolute14(value.cacheRoot) || resolve14(value.cacheRoot) !== value.cacheRoot || !digest(value.sha256) || !Array.isArray(value.controls) || value.controls.length === 0 || value.controls.length > 4096 || !Array.isArray(value.appOnlyParents) || value.appOnlyParents.length > 4096 || !Array.isArray(value.skills) || value.skills.length === 0 || value.skills.length > 4096)
|
|
16252
16304
|
refuse4();
|
|
16253
16305
|
const witness = value;
|
|
16254
16306
|
const controlParents = new Set;
|
|
@@ -16269,6 +16321,20 @@ function assertWitnessShape(value) {
|
|
|
16269
16321
|
refuse4();
|
|
16270
16322
|
appOnlyParentPaths.add(row.pluginParent);
|
|
16271
16323
|
}
|
|
16324
|
+
const hookParentPaths = new Set;
|
|
16325
|
+
const hookParents = witness.hookParents === undefined ? [] : witness.hookParents;
|
|
16326
|
+
if (!Array.isArray(hookParents) || hookParents.length > 4096)
|
|
16327
|
+
refuse4();
|
|
16328
|
+
for (const candidate of hookParents) {
|
|
16329
|
+
if (!plainObject(candidate))
|
|
16330
|
+
refuse4();
|
|
16331
|
+
const row = candidate;
|
|
16332
|
+
const remote = row.installation === "remote-receipt";
|
|
16333
|
+
const local = row.installation === "local-marketplace";
|
|
16334
|
+
if (!exactKeys(row, ["role", "pluginId", "namespace", "pluginParent", "installation", "manifestSha256", "hooksSha256"], remote ? ["remotePluginId", "receiptSha256"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || row.role !== "reviewed-hook" || !identifier3(row.namespace) || typeof row.pluginId !== "string" || !/^[A-Za-z0-9_-]{1,64}@[A-Za-z0-9_-]{1,64}$/.test(row.pluginId) || typeof row.pluginParent !== "string" || !validPluginParent(String(witness.cacheRoot), row.pluginParent, row.namespace, row.pluginId) || remote && (typeof row.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(row.remotePluginId) || !digest(row.receiptSha256)) || local && (typeof row.marketplaceSourcePath !== "string" || !isAbsolute14(row.marketplaceSourcePath) || resolve14(row.marketplaceSourcePath) !== row.marketplaceSourcePath || basename8(row.marketplaceSourcePath) !== "marketplace.json" || !digest(row.marketplaceSha256)) || !remote && !local || !digest(row.manifestSha256) || !digest(row.hooksSha256) || hookParentPaths.has(row.pluginParent) || controlParents.has(row.pluginParent) || appOnlyParentPaths.has(row.pluginParent))
|
|
16335
|
+
refuse4();
|
|
16336
|
+
hookParentPaths.add(row.pluginParent);
|
|
16337
|
+
}
|
|
16272
16338
|
const skillNames = new Set;
|
|
16273
16339
|
const qualifiedNames = new Set;
|
|
16274
16340
|
for (const candidate of witness.skills) {
|
|
@@ -16288,6 +16354,7 @@ function assertWitnessShape(value) {
|
|
|
16288
16354
|
cacheRoot: witness.cacheRoot,
|
|
16289
16355
|
controls: witness.controls,
|
|
16290
16356
|
appOnlyParents: witness.appOnlyParents,
|
|
16357
|
+
...witness.hookParents === undefined ? {} : { hookParents: witness.hookParents },
|
|
16291
16358
|
skills: witness.skills
|
|
16292
16359
|
};
|
|
16293
16360
|
if (hash2(projection) !== witness.sha256)
|
|
@@ -16478,10 +16545,147 @@ function appOnlyParentProjection(cacheRoot, parents2, read2) {
|
|
|
16478
16545
|
}
|
|
16479
16546
|
return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
|
|
16480
16547
|
}
|
|
16481
|
-
|
|
16548
|
+
var codexHookEvents = new Set([
|
|
16549
|
+
"SessionStart",
|
|
16550
|
+
"UserPromptSubmit",
|
|
16551
|
+
"PreToolUse",
|
|
16552
|
+
"PostToolUse",
|
|
16553
|
+
"PostToolUseFailure",
|
|
16554
|
+
"Stop",
|
|
16555
|
+
"SubagentStart",
|
|
16556
|
+
"SubagentStop",
|
|
16557
|
+
"PreCompact",
|
|
16558
|
+
"Notification",
|
|
16559
|
+
"PermissionRequest",
|
|
16560
|
+
"SessionEnd",
|
|
16561
|
+
"ConfigChange",
|
|
16562
|
+
"WorktreeCreate",
|
|
16563
|
+
"WorktreeRemove",
|
|
16564
|
+
"TeammateIdle",
|
|
16565
|
+
"TaskComplete"
|
|
16566
|
+
]);
|
|
16567
|
+
function assertJsonValue(value, depth = 0, budget2 = { members: 0 }) {
|
|
16568
|
+
if (depth > 32 || ++budget2.members > 4096)
|
|
16569
|
+
refuse4();
|
|
16570
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
16571
|
+
return;
|
|
16572
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
16573
|
+
return;
|
|
16574
|
+
if (Array.isArray(value)) {
|
|
16575
|
+
for (const item of value)
|
|
16576
|
+
assertJsonValue(item, depth + 1, budget2);
|
|
16577
|
+
return;
|
|
16578
|
+
}
|
|
16579
|
+
if (!plainObject(value))
|
|
16580
|
+
refuse4();
|
|
16581
|
+
for (const [key, item] of Object.entries(value)) {
|
|
16582
|
+
if (!key || /[\x00-\x1f\x7f]/.test(key))
|
|
16583
|
+
refuse4();
|
|
16584
|
+
assertJsonValue(item, depth + 1, budget2);
|
|
16585
|
+
}
|
|
16586
|
+
}
|
|
16587
|
+
function reviewedHookControls(root, read2) {
|
|
16588
|
+
const manifestPath = join20(root, ".codex-plugin/plugin.json"), hooksPath = join20(root, "hooks/hooks.json");
|
|
16589
|
+
let manifest, manifestSha256, hooks, hooksSha256;
|
|
16590
|
+
try {
|
|
16591
|
+
const manifestText = read2(manifestPath);
|
|
16592
|
+
manifestSha256 = hashNativeJsonControls(manifestText, "version");
|
|
16593
|
+
manifest = JSON.parse(manifestText);
|
|
16594
|
+
const hooksText = read2(hooksPath);
|
|
16595
|
+
hashNativeJsonControls(hooksText);
|
|
16596
|
+
hooksSha256 = createHash18("sha256").update(hooksText).digest("hex");
|
|
16597
|
+
hooks = JSON.parse(hooksText);
|
|
16598
|
+
} catch {
|
|
16599
|
+
return refuse4();
|
|
16600
|
+
}
|
|
16601
|
+
if (!plainObject(manifest) || !exactKeys(manifest, ["name", "version", "hooks"], ["description"]) || !identifier3(manifest.name) || typeof manifest.version !== "string" || manifest.version !== basename8(root) || manifest.hooks !== "./hooks/hooks.json" || manifest.description !== undefined && (typeof manifest.description !== "string" || !manifest.description.trim() || manifest.description.length > 1024))
|
|
16602
|
+
refuse4();
|
|
16603
|
+
const manifestRecord = manifest;
|
|
16604
|
+
if (!plainObject(hooks) || !exactKeys(hooks, ["hooks"]) || !plainObject(hooks.hooks))
|
|
16605
|
+
refuse4();
|
|
16606
|
+
const hookTable = hooks.hooks;
|
|
16607
|
+
const events = Object.entries(hookTable);
|
|
16608
|
+
if (!events.length || events.length > 32)
|
|
16609
|
+
refuse4();
|
|
16610
|
+
for (const [event, groups] of events) {
|
|
16611
|
+
if (!codexHookEvents.has(event) || !Array.isArray(groups) || !groups.length || groups.length > 32)
|
|
16612
|
+
refuse4();
|
|
16613
|
+
for (const group of groups) {
|
|
16614
|
+
if (!plainObject(group) || !exactKeys(group, ["hooks"]) || !Array.isArray(group.hooks) || !group.hooks.length || group.hooks.length > 32)
|
|
16615
|
+
refuse4();
|
|
16616
|
+
const handlers = group.hooks;
|
|
16617
|
+
for (const handler of handlers) {
|
|
16618
|
+
if (!plainObject(handler) || !exactKeys(handler, ["type", "server", "tool", "input"], ["timeout"]) || handler.type !== "mcp_tool" || !identifier3(handler.server) || !identifier3(handler.tool) || !plainObject(handler.input) || handler.timeout !== undefined && (!Number.isSafeInteger(handler.timeout) || Number(handler.timeout) < 1 || Number(handler.timeout) > 300))
|
|
16619
|
+
refuse4();
|
|
16620
|
+
assertJsonValue(handler.input);
|
|
16621
|
+
}
|
|
16622
|
+
}
|
|
16623
|
+
}
|
|
16624
|
+
return { namespace: manifestRecord.name, manifestSha256, hooksSha256 };
|
|
16625
|
+
}
|
|
16626
|
+
function reviewedHookParentProjection(cacheRoot, parents2, read2) {
|
|
16627
|
+
if (!Array.isArray(parents2) || parents2.length > 4096)
|
|
16628
|
+
refuse4();
|
|
16629
|
+
const seen = new Set, rows = [];
|
|
16630
|
+
for (const parent of parents2) {
|
|
16631
|
+
const remote = parent?.installation === "remote-receipt", local = parent?.installation === "local-marketplace";
|
|
16632
|
+
if (!parent || !exactKeys(parent, ["installation", "namespace", "pluginId", "pluginParent", "role"], remote ? ["remotePluginId"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || parent.role !== "reviewed-hook" || !identifier3(parent.namespace) || !/^[A-Za-z0-9_-]{1,64}@[A-Za-z0-9_-]{1,64}$/.test(parent.pluginId) || typeof parent.pluginParent !== "string" || remote && (typeof parent.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(parent.remotePluginId)) || local && (typeof parent.marketplaceSourcePath !== "string" || !isAbsolute14(parent.marketplaceSourcePath) || resolve14(parent.marketplaceSourcePath) !== parent.marketplaceSourcePath || basename8(parent.marketplaceSourcePath) !== "marketplace.json" || !digest(parent.marketplaceSha256)) || !remote && !local)
|
|
16633
|
+
refuse4();
|
|
16634
|
+
const parts = relative7(cacheRoot, parent.pluginParent).split(sep8);
|
|
16635
|
+
if (!isAbsolute14(parent.pluginParent) || resolve14(parent.pluginParent) !== parent.pluginParent || parts.length !== 2 || parts.some((part) => !identifier3(part)) || parts[1] !== parent.namespace || parent.pluginId !== `${parent.namespace}@${parts[0]}` || seen.has(parent.pluginParent))
|
|
16636
|
+
refuse4();
|
|
16637
|
+
seen.add(parent.pluginParent);
|
|
16638
|
+
const parentStat = lstatSync16(parent.pluginParent, { throwIfNoEntry: false });
|
|
16639
|
+
if (!parentStat?.isDirectory() || parentStat.isSymbolicLink() || realpathSync9(parent.pluginParent) !== parent.pluginParent)
|
|
16640
|
+
refuse4();
|
|
16641
|
+
const receiptPath = join20(parent.pluginParent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync16(receiptPath, { throwIfNoEntry: false });
|
|
16642
|
+
let receiptText;
|
|
16643
|
+
if (remote) {
|
|
16644
|
+
if (!receiptStat?.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > MAX_RECEIPT_BYTES)
|
|
16645
|
+
refuse4();
|
|
16646
|
+
try {
|
|
16647
|
+
receiptText = read2(receiptPath);
|
|
16648
|
+
hashNativeJsonControls(receiptText);
|
|
16649
|
+
const receipt = JSON.parse(receiptText);
|
|
16650
|
+
if (!plainObject(receipt) || !exactKeys(receipt, ["schema_version", "remote_plugin_id"]) || receipt.schema_version !== 1 || receipt.remote_plugin_id !== parent.remotePluginId)
|
|
16651
|
+
refuse4();
|
|
16652
|
+
} catch {
|
|
16653
|
+
refuse4();
|
|
16654
|
+
}
|
|
16655
|
+
} else {
|
|
16656
|
+
const marketplaceSourcePath = parent.marketplaceSourcePath ?? refuse4();
|
|
16657
|
+
if (receiptStat !== undefined || !parent.marketplaceSha256)
|
|
16658
|
+
refuse4();
|
|
16659
|
+
let marketplaceText;
|
|
16660
|
+
try {
|
|
16661
|
+
marketplaceText = read2(marketplaceSourcePath);
|
|
16662
|
+
} catch {
|
|
16663
|
+
return refuse4();
|
|
16664
|
+
}
|
|
16665
|
+
if (createHash18("sha256").update(marketplaceText).digest("hex") !== parent.marketplaceSha256 || !codexLocalMarketplaceMapsPlugin(marketplaceText, parts[0], parent.namespace))
|
|
16666
|
+
refuse4();
|
|
16667
|
+
}
|
|
16668
|
+
const materializations = readdirSync7(parent.pluginParent).filter((name) => name !== ".codex-remote-plugin-install.json").map((version2) => {
|
|
16669
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
|
|
16670
|
+
refuse4();
|
|
16671
|
+
const root = join20(parent.pluginParent, version2), stat = lstatSync16(root, { throwIfNoEntry: false });
|
|
16672
|
+
if (!stat?.isDirectory() || stat.isSymbolicLink() || realpathSync9(root) !== root)
|
|
16673
|
+
refuse4();
|
|
16674
|
+
const controls = reviewedHookControls(root, read2);
|
|
16675
|
+
if (controls.namespace !== parent.namespace)
|
|
16676
|
+
refuse4();
|
|
16677
|
+
return { manifestSha256: controls.manifestSha256, hooksSha256: controls.hooksSha256 };
|
|
16678
|
+
});
|
|
16679
|
+
if (!materializations.length || materializations.some((item) => canonical7(item) !== canonical7(materializations[0])))
|
|
16680
|
+
refuse4();
|
|
16681
|
+
rows.push({ ...parent, ...receiptText === undefined ? {} : { receiptSha256: createHash18("sha256").update(receiptText).digest("hex") }, ...materializations[0] });
|
|
16682
|
+
}
|
|
16683
|
+
return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
|
|
16684
|
+
}
|
|
16685
|
+
function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files, members) {
|
|
16482
16686
|
const expected = new Set;
|
|
16483
16687
|
const expectedMarkets = new Set;
|
|
16484
|
-
for (const control of [...controls, ...appOnlyParents]) {
|
|
16688
|
+
for (const control of [...controls, ...appOnlyParents, ...hookParents]) {
|
|
16485
16689
|
const rel = relative7(cacheRoot, control.pluginParent), parts = rel.split(sep8);
|
|
16486
16690
|
if (resolve14(control.pluginParent) !== control.pluginParent || parts.length !== 2 || parts.some((part) => !identifier3(part)) || control.pluginId !== `${control.namespace}@${parts[0]}` || parts[1] !== control.namespace)
|
|
16487
16691
|
refuse4();
|
|
@@ -16522,7 +16726,9 @@ function assertParents(cacheRoot, controls, appOnlyParents, files, members) {
|
|
|
16522
16726
|
refuse4();
|
|
16523
16727
|
if ([".app.json", ".mcp.json"].includes(base) && (parts.length !== 4 || dirname15(member) !== root))
|
|
16524
16728
|
refuse4();
|
|
16525
|
-
if (
|
|
16729
|
+
if ([".app.json", ".mcp.json"].includes(base) && hookParents.some((reviewed) => reviewed.pluginParent === parent))
|
|
16730
|
+
refuse4();
|
|
16731
|
+
if (parts.includes("hooks") && (![4, 5].includes(parts.length) || parts[3] !== "hooks" || (parts.length === 4 ? base !== "hooks" : base !== "hooks.json") || !hookParents.some((reviewed) => reviewed.pluginParent === join20(cacheRoot, parts[0], parts[1]))))
|
|
16526
16732
|
refuse4();
|
|
16527
16733
|
}
|
|
16528
16734
|
}
|
|
@@ -16632,13 +16838,14 @@ function captureCodexSemanticCacheWitness(options) {
|
|
|
16632
16838
|
const initialTree = treeSnapshot(options.cacheRoot);
|
|
16633
16839
|
const controls = controlProjection(options.controls, read2);
|
|
16634
16840
|
const appOnlyParents = appOnlyParentProjection(options.cacheRoot, options.appOnlyParents ?? [], read2);
|
|
16841
|
+
const hookParents = reviewedHookParentProjection(options.cacheRoot, options.reviewedHookParents ?? [], read2);
|
|
16635
16842
|
const skillParents = new Set(controls.map((control) => control.pluginParent));
|
|
16636
|
-
if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)))
|
|
16843
|
+
if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)) || hookParents.some((parent) => skillParents.has(parent.pluginParent) || appOnlyParents.some((app) => app.pluginParent === parent.pluginParent)))
|
|
16637
16844
|
refuse4();
|
|
16638
16845
|
if (!reviewedCodexPluginCapabilitiesUnchanged(options.cacheRoot, options.controls, read2, options.rules))
|
|
16639
16846
|
refuse4();
|
|
16640
16847
|
const files = initialTree.files;
|
|
16641
|
-
assertParents(options.cacheRoot, controls, appOnlyParents, files, initialTree.state.members);
|
|
16848
|
+
assertParents(options.cacheRoot, controls, appOnlyParents, hookParents, files, initialTree.state.members);
|
|
16642
16849
|
const expectedNamesByRoot = assertSkillMaterializations(options.cacheRoot, options.controls, files, read2);
|
|
16643
16850
|
const docs = files.filter((path) => path.endsWith(`${sep8}SKILL.md`));
|
|
16644
16851
|
const skillRows = [];
|
|
@@ -16647,6 +16854,8 @@ function captureCodexSemanticCacheWitness(options) {
|
|
|
16647
16854
|
const rel = relative7(options.cacheRoot, document2).split(sep8);
|
|
16648
16855
|
if (appOnlyParents.some((parent) => parent.pluginParent === join20(options.cacheRoot, rel[0], rel[1])))
|
|
16649
16856
|
refuse4();
|
|
16857
|
+
if (hookParents.some((parent) => parent.pluginParent === join20(options.cacheRoot, rel[0], rel[1])))
|
|
16858
|
+
refuse4();
|
|
16650
16859
|
const documentStat = lstatSync16(document2, { throwIfNoEntry: false });
|
|
16651
16860
|
if (!documentStat?.isFile() || documentStat.isSymbolicLink() || documentStat.size > MAX_DOCUMENT_BYTES)
|
|
16652
16861
|
refuse4();
|
|
@@ -16710,7 +16919,7 @@ function captureCodexSemanticCacheWitness(options) {
|
|
|
16710
16919
|
tracked.verify();
|
|
16711
16920
|
const finalTree = treeSnapshot(options.cacheRoot);
|
|
16712
16921
|
assertSameTree(initialTree.state, finalTree.state, tracked.paths());
|
|
16713
|
-
const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, skills: uniqueSkills };
|
|
16922
|
+
const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, hookParents, skills: uniqueSkills };
|
|
16714
16923
|
return { ...completeProjection, sha256: hash2(completeProjection) };
|
|
16715
16924
|
} catch (error) {
|
|
16716
16925
|
if (error instanceof Error && error.message.startsWith("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED"))
|
|
@@ -16726,6 +16935,7 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
|
|
|
16726
16935
|
cacheRoot: previous.cacheRoot,
|
|
16727
16936
|
controls: previous.controls,
|
|
16728
16937
|
appOnlyParents: previous.appOnlyParents,
|
|
16938
|
+
...previous.hookParents === undefined ? {} : { hookParents: previous.hookParents },
|
|
16729
16939
|
skills: previous.skills
|
|
16730
16940
|
};
|
|
16731
16941
|
const currentProjection = {
|
|
@@ -16733,9 +16943,11 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
|
|
|
16733
16943
|
cacheRoot: current.cacheRoot,
|
|
16734
16944
|
controls: current.controls,
|
|
16735
16945
|
appOnlyParents: current.appOnlyParents,
|
|
16946
|
+
...current.hookParents === undefined ? {} : { hookParents: current.hookParents },
|
|
16736
16947
|
skills: current.skills
|
|
16737
16948
|
};
|
|
16738
|
-
|
|
16949
|
+
const comparable = (projection) => ({ ...projection, hookParents: projection.hookParents ?? [] });
|
|
16950
|
+
if (hash2(priorProjection) !== previous.sha256 || hash2(currentProjection) !== current.sha256 || canonical7(comparable(priorProjection)) !== canonical7(comparable(currentProjection)))
|
|
16739
16951
|
refuse4();
|
|
16740
16952
|
}
|
|
16741
16953
|
|
|
@@ -16743,7 +16955,7 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
|
|
|
16743
16955
|
import { createHash as createHash23, randomUUID as randomUUID3 } from "crypto";
|
|
16744
16956
|
import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
|
|
16745
16957
|
import { existsSync as existsSync9, lstatSync as lstatSync23, statSync as statSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync16, readdirSync as readdirSync9, opendirSync as opendirSync3, readlinkSync as readlinkSync7, realpathSync as realpathSync12, renameSync as renameSync3, rmdirSync as rmdirSync2, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4, chmodSync, openSync as openSync14, closeSync as closeSync14, fsyncSync as fsyncSync6, fstatSync as fstatSync14, readSync as readSync10, constants as constants15, linkSync as linkSync2 } from "fs";
|
|
16746
|
-
import { dirname as dirname18, join as join27, resolve as resolve18, relative as relative8, isAbsolute as isAbsolute19, sep as sep10 } from "path";
|
|
16958
|
+
import { basename as basename9, dirname as dirname18, join as join27, resolve as resolve18, relative as relative8, isAbsolute as isAbsolute19, sep as sep10 } from "path";
|
|
16747
16959
|
import { homedir as homedir2 } from "os";
|
|
16748
16960
|
|
|
16749
16961
|
// src/lib/managed-policy.ts
|
|
@@ -17141,6 +17353,78 @@ function disableCodexBundledSkills(text2) {
|
|
|
17141
17353
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
17142
17354
|
import { accessSync as accessSync2, constants as constants11, existsSync as existsSync8, lstatSync as lstatSync19, realpathSync as realpathSync10, statSync as statSync9 } from "fs";
|
|
17143
17355
|
import { delimiter as delimiter2, isAbsolute as isAbsolute15, join as join25, resolve as resolve15 } from "path";
|
|
17356
|
+
|
|
17357
|
+
// src/lib/hook-diagnostics.ts
|
|
17358
|
+
var CONTEXT_ERROR_CODES = new Set([
|
|
17359
|
+
"SKILLS_API_CREDENTIAL_UNAVAILABLE",
|
|
17360
|
+
"SKILLS_API_UNAVAILABLE",
|
|
17361
|
+
"SKILLS_API_UNAUTHORIZED",
|
|
17362
|
+
"SKILLS_API_FORBIDDEN",
|
|
17363
|
+
"SKILLS_API_RESOURCE_UNAVAILABLE",
|
|
17364
|
+
"SESSION_WRITE_BUSY",
|
|
17365
|
+
"SKILLS_CONTEXT_FAILED",
|
|
17366
|
+
"SKILLS_STORAGE_FULL",
|
|
17367
|
+
"PROFILE_LOCK_MISMATCH",
|
|
17368
|
+
"PROFILE_IDENTITY_MISMATCH",
|
|
17369
|
+
"PROFILE_APPLIED_REPORT_FAILED",
|
|
17370
|
+
"CACHED_AUTHORITY_REQUIRED",
|
|
17371
|
+
"CACHED_PROFILE_EXPIRED",
|
|
17372
|
+
"CACHED_PROFILE_MISSING",
|
|
17373
|
+
"CACHED_BUNDLE_MISSING",
|
|
17374
|
+
"INVALID_CONTEXT_INPUT",
|
|
17375
|
+
"CONTEXT_INPUT_TOO_LARGE",
|
|
17376
|
+
"INVALID_CONTEXT_BUDGET",
|
|
17377
|
+
"INVALID_SELECTION",
|
|
17378
|
+
"INVALID_SELECTION_ALIASES",
|
|
17379
|
+
"INVALID_RECEIPT",
|
|
17380
|
+
"INVALID_CACHE_FILE",
|
|
17381
|
+
"UNSAFE_CACHE_PATH",
|
|
17382
|
+
"RECEIPT_TOO_LARGE",
|
|
17383
|
+
"BUNDLE_DIGEST_MISMATCH",
|
|
17384
|
+
"BUNDLE_IDENTITY_MISMATCH",
|
|
17385
|
+
"BUNDLE_UNAVAILABLE",
|
|
17386
|
+
"BUNDLE_TOO_LARGE",
|
|
17387
|
+
"SKILL_NOT_SELECTED",
|
|
17388
|
+
"INVALID_SESSION",
|
|
17389
|
+
"SESSION_PARENT_NOT_FOUND",
|
|
17390
|
+
"SESSION_PARENT_MISMATCH",
|
|
17391
|
+
"SESSION_NOT_FOUND",
|
|
17392
|
+
"SESSION_GENERATION_CHANGED",
|
|
17393
|
+
"SESSION_GENERATION_EXHAUSTED",
|
|
17394
|
+
"SESSION_PARENT_CHANGED",
|
|
17395
|
+
"SESSION_RECEIPT_CHANGED",
|
|
17396
|
+
"SESSION_RECONCILIATION_REQUIRED",
|
|
17397
|
+
"SESSION_RENEWAL_TIMEOUT",
|
|
17398
|
+
"SESSION_CONTEXT_CONFLICT",
|
|
17399
|
+
"SESSION_RECONCILIATION_INCOMPLETE",
|
|
17400
|
+
"SESSION_WRITE_LOCKED",
|
|
17401
|
+
"SESSION_WRITE_LOCK_CHANGED",
|
|
17402
|
+
"SESSION_LOCK_RECOVERY_INCOMPLETE"
|
|
17403
|
+
]);
|
|
17404
|
+
var HOOK_REFUSAL_REASON_CODES = Object.freeze([
|
|
17405
|
+
...CONTEXT_ERROR_CODES,
|
|
17406
|
+
"SKILLS_HOOK_FAILED",
|
|
17407
|
+
"SKILLS_HOOK_TIMEOUT",
|
|
17408
|
+
"SKILLS_HOOK_INVALID_RESPONSE"
|
|
17409
|
+
]);
|
|
17410
|
+
var OPTIONAL_CONTEXT_FAILURES = new Set([
|
|
17411
|
+
"SKILLS_API_CREDENTIAL_UNAVAILABLE",
|
|
17412
|
+
"SKILLS_API_UNAVAILABLE",
|
|
17413
|
+
"SKILLS_API_UNAUTHORIZED",
|
|
17414
|
+
"SKILLS_API_FORBIDDEN",
|
|
17415
|
+
"SKILLS_API_RESOURCE_UNAVAILABLE",
|
|
17416
|
+
"CACHED_PROFILE_EXPIRED",
|
|
17417
|
+
"CACHED_PROFILE_MISSING",
|
|
17418
|
+
"CACHED_BUNDLE_MISSING",
|
|
17419
|
+
"SESSION_RECONCILIATION_REQUIRED",
|
|
17420
|
+
"SESSION_RENEWAL_TIMEOUT",
|
|
17421
|
+
"SESSION_WRITE_BUSY",
|
|
17422
|
+
"SESSION_PARENT_CHANGED",
|
|
17423
|
+
"SESSION_CONTEXT_CONFLICT",
|
|
17424
|
+
"SKILLS_HOOK_TIMEOUT"
|
|
17425
|
+
]);
|
|
17426
|
+
|
|
17427
|
+
// src/lib/agent-sumi.ts
|
|
17144
17428
|
var SUMI_PATH_SELECTORS = ["SUMI_HOME", "SUMI_CONFIG_DIR", "XDG_DATA_HOME", "XDG_CACHE_HOME", "XDG_CONFIG_HOME", "XDG_STATE_HOME"];
|
|
17145
17429
|
var SUMI_PATH_KEYS = ["data", "cache", "config", "state"];
|
|
17146
17430
|
var SUMI_PATH_OUTPUT_LIMIT = 128 * 1024;
|
|
@@ -17282,24 +17566,33 @@ function sumiConfigPath(home, cwd = process.cwd(), env = process.env) {
|
|
|
17282
17566
|
return join25(sumiConfigDirectory(home, env, cwd), "sumi.json");
|
|
17283
17567
|
}
|
|
17284
17568
|
function renderSumiPlugin(command, profile) {
|
|
17285
|
-
return renderSumiPluginVersion(command, profile,
|
|
17569
|
+
return renderSumiPluginVersion(command, profile, 3);
|
|
17286
17570
|
}
|
|
17287
17571
|
function isManagedSumiPlugin(text2, command, profile) {
|
|
17288
|
-
return text2 === renderSumiPlugin(command, profile) || text2 === renderSumiPluginVersion(command, profile,
|
|
17572
|
+
return text2 === renderSumiPlugin(command, profile) || text2 === renderSumiPluginVersion(command, profile, 2) || text2 === renderSumiPluginVersion(command, profile, 1);
|
|
17289
17573
|
}
|
|
17290
|
-
function renderSumiPluginVersion(command, profile,
|
|
17574
|
+
function renderSumiPluginVersion(command, profile, version2) {
|
|
17575
|
+
const legacy = version2 === 1;
|
|
17291
17576
|
const failure = (message) => legacy ? `new Error(${JSON.stringify(message)})` : "refusal()";
|
|
17292
17577
|
return `// Managed by @hasna/skills. Regenerate with skills hook install --agent sumi.
|
|
17293
17578
|
import { spawn } from "node:child_process";
|
|
17294
17579
|
const command = ${JSON.stringify(command)};
|
|
17295
17580
|
const profile = ${JSON.stringify(profile)};
|
|
17296
|
-
${legacy ? "" : `function refusal() {
|
|
17297
|
-
const error = new Error("Skills verification blocked this request. Review the Sumi Skills hook configuration, then retry.");
|
|
17581
|
+
${legacy ? "" : `function refusal(${version2 === 3 ? "reasonCode" : ""}) {
|
|
17582
|
+
const error = new Error("Skills verification blocked this request. Review the Sumi Skills hook configuration, then retry."${version2 === 3 ? ' + (reasonCode ? " [" + reasonCode + "]" : "")' : ""});
|
|
17298
17583
|
error.name = "SkillsHookRefusal";
|
|
17299
|
-
error.skillsHookRefusal = { version: 1, code: "SKILLS_HOOK_REFUSED" };
|
|
17584
|
+
error.skillsHookRefusal = { version: 1, code: "SKILLS_HOOK_REFUSED"${version2 === 3 ? ", ...(reasonCode ? { reasonCode } : {})" : ""} };
|
|
17300
17585
|
return error;
|
|
17301
17586
|
}
|
|
17302
|
-
`}
|
|
17587
|
+
`}${version2 === 3 ? `const reasonCodes = new Set(${JSON.stringify(HOOK_REFUSAL_REASON_CODES)});
|
|
17588
|
+
function refusedResult(result) {
|
|
17589
|
+
const reason = result.reason ?? result.stopReason ?? result.systemMessage;
|
|
17590
|
+
if (typeof reason !== "string" || reason.length > 16384) return refusal();
|
|
17591
|
+
if (reason.startsWith("NATIVE_SKILL_DRIFT:")) return refusal("NATIVE_SKILL_DRIFT");
|
|
17592
|
+
const code = /^Skills context is unavailable \\[([A-Z_]+)\\]/.exec(reason)?.[1];
|
|
17593
|
+
return refusal(reasonCodes.has(code) ? code : undefined);
|
|
17594
|
+
}
|
|
17595
|
+
` : ""}function context(input) {
|
|
17303
17596
|
return new Promise((resolve, reject) => {
|
|
17304
17597
|
const child = spawn(command, ["hook", "user-prompt", "--agent", "sumi", "--selection-profile", profile], { cwd: input.cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
17305
17598
|
const chunks = []; let bytes = 0, failure;
|
|
@@ -17314,12 +17607,12 @@ ${legacy ? "" : `function refusal() {
|
|
|
17314
17607
|
try {
|
|
17315
17608
|
const result = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
17316
17609
|
if (!result || typeof result !== "object" || Array.isArray(result)) throw ${failure("Invalid Skills hook response")};
|
|
17317
|
-
if (result.decision === "block" || result.continue === false) throw ${failure("Skills prompt hook refused")};
|
|
17610
|
+
if (result.decision === "block" || result.continue === false) throw ${version2 === 3 ? "refusedResult(result)" : failure("Skills prompt hook refused")};
|
|
17318
17611
|
if (Object.keys(result).length && (!result.hookSpecificOutput || result.hookSpecificOutput.hookEventName !== input.hook_event_name)) throw ${failure("Invalid Skills hook response")};
|
|
17319
17612
|
const text = result.hookSpecificOutput?.additionalContext ?? "";
|
|
17320
17613
|
if (typeof text !== "string") throw ${failure("Invalid Skills prompt context")};
|
|
17321
17614
|
resolve(text);
|
|
17322
|
-
} catch (error) { reject(${legacy ? "error" : "refusal()"}); }
|
|
17615
|
+
} catch (error) { reject(${legacy ? "error" : version2 === 3 ? 'error instanceof Error && error.name === "SkillsHookRefusal" ? error : refusal()' : "refusal()"}); }
|
|
17323
17616
|
});
|
|
17324
17617
|
child.stdin.end(JSON.stringify(input));
|
|
17325
17618
|
});
|
|
@@ -17352,9 +17645,13 @@ export default {
|
|
|
17352
17645
|
sessions.add(event.sessionID);
|
|
17353
17646
|
}));
|
|
17354
17647
|
registrations.push(await ctx.session.hook("context", async event => {
|
|
17355
|
-
|
|
17648
|
+
${version2 === 3 ? ` // Model messages also contain checkpoints, attachments and synthetic
|
|
17649
|
+
// user-role history, with no owner-prompt provenance. Prompt admission
|
|
17650
|
+
// already matched and persisted Skills; restore that verified state only.
|
|
17651
|
+
const prompt = "";
|
|
17652
|
+
` : ` const last = event.messages.findLast(message => message.role === "user");
|
|
17356
17653
|
const prompt = (last?.content ?? []).filter(part => part.type === "text").map(part => part.text).join("\\n");
|
|
17357
|
-
// Recheck on every primary request, including resumed and synthetic
|
|
17654
|
+
`} // Recheck on every primary request, including resumed and synthetic
|
|
17358
17655
|
// sessions. The CLI owns optional failures versus explicit refusals.
|
|
17359
17656
|
const text = await context(await input(event.sessionID, prompt, !sessions.has(event.sessionID)));
|
|
17360
17657
|
if (text) event.system.push({ type: "text", text });
|
|
@@ -19022,7 +19319,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
19022
19319
|
return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join27(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join27(dataDir2, "agent-policy.json"), before: snapshot2.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], ...policy.bridge.discoveryExecutables ? { discoveryExecutables: policy.bridge.discoveryExecutables } : {}, rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
|
|
19023
19320
|
}
|
|
19024
19321
|
function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
19025
|
-
if (options.agent !== "codex" || !/^[a-f0-9]{64}$/.test(options.expectedPolicySha256) || !/^[a-f0-9]{64}$/.test(options.expectedSettingsSha256) || options.expectedCacheWitnessSha256 !== undefined && !/^[a-f0-9]{64}$/.test(options.expectedCacheWitnessSha256) || !Array.isArray(options.appOnlyParents) || options.appOnlyParents.length > 4096 || new Set(options.appOnlyParents).size !== options.appOnlyParents.length)
|
|
19322
|
+
if (options.agent !== "codex" || !/^[a-f0-9]{64}$/.test(options.expectedPolicySha256) || !/^[a-f0-9]{64}$/.test(options.expectedSettingsSha256) || options.expectedCacheWitnessSha256 !== undefined && !/^[a-f0-9]{64}$/.test(options.expectedCacheWitnessSha256) || !Array.isArray(options.appOnlyParents) || options.appOnlyParents.length > 4096 || new Set(options.appOnlyParents).size !== options.appOnlyParents.length || options.reviewedHookParents !== undefined && (!Array.isArray(options.reviewedHookParents) || options.reviewedHookParents.length > 4096 || new Set(options.reviewedHookParents).size !== options.reviewedHookParents.length))
|
|
19026
19323
|
throw new Error("Invalid Codex semantic cache upgrade request");
|
|
19027
19324
|
const home = resolve18(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
19028
19325
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
@@ -19046,14 +19343,23 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
19046
19343
|
throw new Error("Native settings preimage changed");
|
|
19047
19344
|
const boundedRead = (path) => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024));
|
|
19048
19345
|
const unchangedFullSource = (path) => {
|
|
19049
|
-
const
|
|
19050
|
-
if (
|
|
19051
|
-
throw new Error("Cache upgrade
|
|
19346
|
+
const sources = binding.sources.filter((source2) => source2.path === path && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && source2.reviewArtifact === undefined && (source2.hashMode === undefined || source2.hashMode === "bytes"));
|
|
19347
|
+
if (sources.length !== 1)
|
|
19348
|
+
throw new Error("Cache upgrade requires one unambiguous prior full identity source");
|
|
19349
|
+
const source = sources[0];
|
|
19052
19350
|
const text2 = boundedRead(path);
|
|
19053
19351
|
if (sha4(text2) !== source.sha256)
|
|
19054
19352
|
throw new Error("Reviewed cache identity source changed");
|
|
19055
19353
|
return text2;
|
|
19056
19354
|
};
|
|
19355
|
+
const unchangedReviewedHookSource = (path) => {
|
|
19356
|
+
const sources = binding.sources.filter((source) => source.path === path);
|
|
19357
|
+
if (!sources.length)
|
|
19358
|
+
throw new Error("Cache upgrade lacks prior full identity source");
|
|
19359
|
+
if (sources.length !== 1)
|
|
19360
|
+
throw new Error("Reviewed hook identity source is ambiguous");
|
|
19361
|
+
return unchangedFullSource(path);
|
|
19362
|
+
};
|
|
19057
19363
|
const appOnlyParents = options.appOnlyParents.map((parent) => {
|
|
19058
19364
|
const parts = relative8(cacheRoot, parent).split(sep10);
|
|
19059
19365
|
if (!isAbsolute19(parent) || resolve18(parent) !== parent || parts.length !== 2 || parts.some((part) => !/^[A-Za-z0-9_-]{1,64}$/.test(part)) || controls.some((control) => control.pluginParent === parent))
|
|
@@ -19068,11 +19374,60 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
19068
19374
|
unchangedFullSource(source.path);
|
|
19069
19375
|
return { role: "app-only", pluginId: `${parts[1]}@${parts[0]}`, namespace: parts[1], pluginParent: parent, remotePluginId: receipt.remote_plugin_id };
|
|
19070
19376
|
}).sort((a, b) => a.pluginParent.localeCompare(b.pluginParent));
|
|
19071
|
-
const
|
|
19377
|
+
const reviewedHookParents = (options.reviewedHookParents ?? []).map((parent) => {
|
|
19378
|
+
const parts = relative8(cacheRoot, parent).split(sep10);
|
|
19379
|
+
if (!isAbsolute19(parent) || resolve18(parent) !== parent || parts.length !== 2 || parts.some((part) => !/^[A-Za-z0-9_-]{1,64}$/.test(part)) || controls.some((control) => control.pluginParent === parent) || appOnlyParents.some((role) => role.pluginParent === parent))
|
|
19380
|
+
throw new Error("Unsupported reviewed native-hook parent role");
|
|
19381
|
+
const receiptPath = join27(parent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync23(receiptPath, { throwIfNoEntry: false });
|
|
19382
|
+
let identity5;
|
|
19383
|
+
if (receiptStat) {
|
|
19384
|
+
if (!receiptStat.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > 16 * 1024)
|
|
19385
|
+
throw new Error("Invalid reviewed native-hook install receipt");
|
|
19386
|
+
const receiptText = unchangedReviewedHookSource(receiptPath);
|
|
19387
|
+
let receipt;
|
|
19388
|
+
try {
|
|
19389
|
+
hashNativeJsonControls(receiptText);
|
|
19390
|
+
receipt = JSON.parse(receiptText);
|
|
19391
|
+
} catch {
|
|
19392
|
+
throw new Error("Invalid reviewed native-hook install receipt");
|
|
19393
|
+
}
|
|
19394
|
+
if (!receipt || Array.isArray(receipt) || Object.keys(receipt).length !== 2 || receipt.schema_version !== 1 || typeof receipt.remote_plugin_id !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(receipt.remote_plugin_id))
|
|
19395
|
+
throw new Error("Invalid reviewed native-hook install receipt");
|
|
19396
|
+
identity5 = { role: "reviewed-hook", pluginId: `${parts[1]}@${parts[0]}`, namespace: parts[1], pluginParent: parent, installation: "remote-receipt", remotePluginId: receipt.remote_plugin_id };
|
|
19397
|
+
} else {
|
|
19398
|
+
const pluginId = `${parts[1]}@${parts[0]}`;
|
|
19399
|
+
const marketplaceSources = binding.sources.filter((source2) => basename9(source2.path) === "marketplace.json" && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && source2.reviewArtifact === undefined && (source2.hashMode === undefined || source2.hashMode === "bytes"));
|
|
19400
|
+
const matches = marketplaceSources.flatMap((source2) => {
|
|
19401
|
+
const text2 = unchangedFullSource(source2.path);
|
|
19402
|
+
return codexLocalMarketplaceMapsPlugin(text2, parts[0], parts[1]) ? [{ source: source2, text: text2 }] : [];
|
|
19403
|
+
});
|
|
19404
|
+
if (matches.length !== 1)
|
|
19405
|
+
throw new Error("Local marketplace hook parent lacks one exact enrolled marketplace source");
|
|
19406
|
+
const { source } = matches[0];
|
|
19407
|
+
const config = Bun.TOML.parse(settings);
|
|
19408
|
+
if (config.plugins?.[pluginId]?.enabled !== true)
|
|
19409
|
+
throw new Error("Local marketplace hook parent is not enabled in the unchanged Codex settings");
|
|
19410
|
+
identity5 = { role: "reviewed-hook", pluginId, namespace: parts[1], pluginParent: parent, installation: "local-marketplace", marketplaceSourcePath: source.path, marketplaceSha256: source.sha256 };
|
|
19411
|
+
}
|
|
19412
|
+
const versions = readdirSync9(parent).filter((name) => name !== ".codex-remote-plugin-install.json");
|
|
19413
|
+
if (!versions.length || versions.length > 4096)
|
|
19414
|
+
throw new Error("Reviewed native-hook parent has no bounded materializations");
|
|
19415
|
+
for (const version2 of versions) {
|
|
19416
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
|
|
19417
|
+
throw new Error("Invalid reviewed native-hook version identity");
|
|
19418
|
+
const root = join27(parent, version2), stat = lstatSync23(root, { throwIfNoEntry: false });
|
|
19419
|
+
if (!stat?.isDirectory() || stat.isSymbolicLink() || realpathSync12(root) !== root)
|
|
19420
|
+
throw new Error("Invalid reviewed native-hook materialization");
|
|
19421
|
+
unchangedReviewedHookSource(join27(root, ".codex-plugin/plugin.json"));
|
|
19422
|
+
unchangedReviewedHookSource(join27(root, "hooks/hooks.json"));
|
|
19423
|
+
}
|
|
19424
|
+
return identity5;
|
|
19425
|
+
}).sort((a, b) => a.pluginParent.localeCompare(b.pluginParent));
|
|
19426
|
+
const parents2 = [...new Set([...controls.map((control) => control.pluginParent), ...appOnlyParents.map((parent) => parent.pluginParent), ...reviewedHookParents.map((parent) => parent.pluginParent)])];
|
|
19072
19427
|
const reviewedAlias = aliases.find((alias) => alias.agent === "codex");
|
|
19073
19428
|
const hookRootAlias = reviewedAlias ? { alias: reviewedAlias.alias, target: reviewedAlias.target } : null;
|
|
19074
19429
|
assertCodexSemanticCacheHookSafety(cacheRoot, parents2, configPath, hookRootAlias);
|
|
19075
|
-
const supersededSources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents2));
|
|
19430
|
+
const supersededSources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents2, reviewedHookParents.map((parent) => parent.pluginParent)));
|
|
19076
19431
|
for (const source of supersededSources)
|
|
19077
19432
|
if ([".app.json", ".mcp.json"].includes(source.path.split(sep10).at(-1)))
|
|
19078
19433
|
unchangedFullSource(source.path);
|
|
@@ -19080,7 +19435,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
19080
19435
|
if (!supersededDirectories.some((directory) => directory.path === cacheRoot) || (binding.directories ?? []).some((directory) => cacheRoot.startsWith(directory.path + sep10)))
|
|
19081
19436
|
throw new Error("Cache upgrade requires exact cache directory coverage without an unproved ancestor projection");
|
|
19082
19437
|
const rules = Bun.TOML.parse(settings).skills?.config ?? [];
|
|
19083
|
-
const witness = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents, rules, read: boundedRead });
|
|
19438
|
+
const witness = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents, reviewedHookParents, rules, read: boundedRead });
|
|
19084
19439
|
if (options.expectedCacheWitnessSha256 !== undefined && witness.sha256 !== options.expectedCacheWitnessSha256)
|
|
19085
19440
|
throw new Error("Reviewed semantic cache preimage changed");
|
|
19086
19441
|
const replacement = { ...binding, codexDisabledPluginSkills: controls, codexSemanticCache: {
|
|
@@ -19089,6 +19444,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
19089
19444
|
hookRootAlias,
|
|
19090
19445
|
witness,
|
|
19091
19446
|
appOnlyParents,
|
|
19447
|
+
reviewedHookParents,
|
|
19092
19448
|
previousPolicySha256: options.expectedPolicySha256,
|
|
19093
19449
|
supersededSources,
|
|
19094
19450
|
supersededDirectories
|
|
@@ -19107,7 +19463,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
19107
19463
|
rootAliases: aliases,
|
|
19108
19464
|
managedAgentChecks: { home, agents: ["codex"] },
|
|
19109
19465
|
...policy.bridge.discoveryExecutables ? { discoveryExecutables: policy.bridge.discoveryExecutables } : {},
|
|
19110
|
-
cacheWitnessUpgrade: { ...options, home, dataDir: dataDir2, appOnlyParents: appOnlyParents.map((parent) => parent.pluginParent) }
|
|
19466
|
+
cacheWitnessUpgrade: { ...options, home, dataDir: dataDir2, appOnlyParents: appOnlyParents.map((parent) => parent.pluginParent), reviewedHookParents: reviewedHookParents.map((parent) => parent.pluginParent) }
|
|
19111
19467
|
};
|
|
19112
19468
|
}
|
|
19113
19469
|
function planReviewedArtifactMigration(options) {
|
|
@@ -19885,7 +20241,7 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
|
19885
20241
|
return { action, path: skillMdPath };
|
|
19886
20242
|
const parentDir = dirname19(dir);
|
|
19887
20243
|
mkdirSync8(parentDir, { recursive: true });
|
|
19888
|
-
const transactionDir = mkdtempSync(join28(parentDir, `.hasna-skills-write-${
|
|
20244
|
+
const transactionDir = mkdtempSync(join28(parentDir, `.hasna-skills-write-${basename10(dir)}-`));
|
|
19889
20245
|
const candidateDir = join28(transactionDir, "candidate");
|
|
19890
20246
|
const backupDir = join28(transactionDir, "backup");
|
|
19891
20247
|
const candidateSkillMdPath = join28(candidateDir, "SKILL.md");
|
|
@@ -21915,7 +22271,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
21915
22271
|
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join34(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
21916
22272
|
const approval = (producer) => {
|
|
21917
22273
|
pluginText(producer);
|
|
21918
|
-
const digest2 = `sha256:${
|
|
22274
|
+
const digest2 = `sha256:${basename11(producer)}`;
|
|
21919
22275
|
const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest2);
|
|
21920
22276
|
pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
|
|
21921
22277
|
if (!verified.has(producer)) {
|
|
@@ -21979,7 +22335,7 @@ function captureManagedPluginRegistry(path, managedPlugins) {
|
|
|
21979
22335
|
// src/lib/claude-marketplace-registry.ts
|
|
21980
22336
|
import { createHash as createHash26 } from "crypto";
|
|
21981
22337
|
import { closeSync as closeSync17, constants as constants18, fstatSync as fstatSync17, lstatSync as lstatSync27, openSync as openSync17, readSync as readSync13 } from "fs";
|
|
21982
|
-
import { basename as
|
|
22338
|
+
import { basename as basename12, dirname as dirname22, isAbsolute as isAbsolute23, resolve as resolve22 } from "path";
|
|
21983
22339
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
21984
22340
|
function need8(value, reason2) {
|
|
21985
22341
|
if (!value)
|
|
@@ -22001,7 +22357,7 @@ function parents2(path) {
|
|
|
22001
22357
|
}
|
|
22002
22358
|
function readRegistry2(path, budget2) {
|
|
22003
22359
|
absolutePath4(path);
|
|
22004
|
-
need8(
|
|
22360
|
+
need8(basename12(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
22005
22361
|
need8(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
22006
22362
|
const ancestors2 = parents2(path), initial = lstatSync27(path, { bigint: true });
|
|
22007
22363
|
need8(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
@@ -22282,7 +22638,7 @@ function assertReviewedClaudeCacheClosures(home, config, review, canonical9) {
|
|
|
22282
22638
|
throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
|
|
22283
22639
|
}
|
|
22284
22640
|
if ([cacheAliasRoot, cacheRoot].some((root2) => row.installPath === root2 || row.installPath.startsWith(root2 + sep11))) {
|
|
22285
|
-
if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" ||
|
|
22641
|
+
if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename13(row.installPath) !== row.version)) {
|
|
22286
22642
|
throw new Error("Reviewed Claude discovery has a malformed active cache registration");
|
|
22287
22643
|
}
|
|
22288
22644
|
if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" && isAbsolute24(row.projectPath) && resolve23(row.projectPath) === row.projectPath && row.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters) {} else
|
|
@@ -22560,7 +22916,7 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
22560
22916
|
if (!targetValid || !targetScopes.has("user\x00"))
|
|
22561
22917
|
continue;
|
|
22562
22918
|
const active = rows[0]?.installPath;
|
|
22563
|
-
if (typeof active !== "string" || rows[0]?.version !==
|
|
22919
|
+
if (typeof active !== "string" || rows[0]?.version !== basename13(active) || dirname23(active) !== dirname23(root2) || active === root2 || !lstatSync28(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync13(active) !== active)
|
|
22564
22920
|
continue;
|
|
22565
22921
|
const activeManifest = full(join35(active, ".claude-plugin/plugin.json"));
|
|
22566
22922
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
@@ -22569,14 +22925,15 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
22569
22925
|
}
|
|
22570
22926
|
return [...result];
|
|
22571
22927
|
}
|
|
22572
|
-
function codexSemanticCacheSourceRole(source, cacheRoot, parents3) {
|
|
22928
|
+
function codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParents = []) {
|
|
22573
22929
|
if (!isAbsolute24(source.path) || resolve23(source.path) !== source.path || /[\x00-\x1f\x7f]/.test(source.path) || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.reviewArtifact !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes")
|
|
22574
22930
|
return false;
|
|
22575
22931
|
const parts = relative9(cacheRoot, source.path).split(sep11);
|
|
22576
22932
|
if (parts.length < 3 || !parents3.includes(join35(cacheRoot, parts[0], parts[1])))
|
|
22577
22933
|
return false;
|
|
22578
22934
|
const tail = parts.slice(3).join("/");
|
|
22579
|
-
|
|
22935
|
+
const parent = join35(cacheRoot, parts[0], parts[1]);
|
|
22936
|
+
return parts.length === 5 && tail === ".codex-plugin/plugin.json" && source.sha256 !== null || parts.length === 4 && [".app.json", ".mcp.json"].includes(tail) && source.sha256 !== null || parts.length === 5 && tail === "hooks/hooks.json" && hookParents.includes(parent) && source.sha256 !== null || source.sha256 === null && (parts.length === 4 && tail === "SKILL.md" || parts.length === 5 && tail === "hooks/hooks.json");
|
|
22580
22937
|
}
|
|
22581
22938
|
function codexSemanticCacheDirectoryRole(path, cacheRoot) {
|
|
22582
22939
|
return isAbsolute24(path) && resolve23(path) === path && !/[\x00-\x1f\x7f]/.test(path) && (path === cacheRoot || path.startsWith(cacheRoot + sep11));
|
|
@@ -22608,20 +22965,28 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
|
|
|
22608
22965
|
const cacheRoot = proof.witness.cacheRoot;
|
|
22609
22966
|
if (controls.some((control) => dirname23(dirname23(control.pluginParent)) !== cacheRoot))
|
|
22610
22967
|
throw new Error("Codex semantic cache names another enrolled cache");
|
|
22611
|
-
const
|
|
22612
|
-
|
|
22968
|
+
const reviewedHookParents = proof.reviewedHookParents ?? [];
|
|
22969
|
+
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 || !isDeepStrictEqual7((proof.witness.hookParents ?? []).map(({ manifestSha256: _manifest, hooksSha256: _hooks, receiptSha256: _receipt, ...parent }) => parent), reviewedHookParents)) {
|
|
22970
|
+
throw new Error("Invalid reviewed native-hook cache role");
|
|
22971
|
+
}
|
|
22972
|
+
for (const parent of reviewedHookParents)
|
|
22973
|
+
if (parent.installation === "local-marketplace" && !binding.sources.some((source) => source.path === parent.marketplaceSourcePath && source.sha256 === parent.marketplaceSha256 && source.sha256 !== null && source.format === undefined && source.fields === undefined && source.reviewArtifact === undefined && (source.hashMode === undefined || source.hashMode === "bytes")))
|
|
22974
|
+
throw new Error("Local marketplace hook parent lost its enrolled source witness");
|
|
22975
|
+
const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...proof.appOnlyParents.map((parent) => parent.pluginParent), ...reviewedHookParents.map((parent) => parent.pluginParent)])];
|
|
22976
|
+
const hookParentPaths = reviewedHookParents.map((parent) => parent.pluginParent);
|
|
22977
|
+
const sources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParentPaths));
|
|
22613
22978
|
const directories = (binding.directories ?? []).filter((directory) => codexSemanticCacheDirectoryRole(directory.path, cacheRoot));
|
|
22614
22979
|
if (!directories.length || !isDeepStrictEqual7(sources, proof.supersededSources) || !isDeepStrictEqual7(directories, proof.supersededDirectories))
|
|
22615
22980
|
throw new Error("Codex semantic cache provenance changed");
|
|
22616
22981
|
const configPath = proof.configPath;
|
|
22617
|
-
if (!isAbsolute24(configPath) || resolve23(configPath) !== configPath ||
|
|
22982
|
+
if (!isAbsolute24(configPath) || resolve23(configPath) !== configPath || basename13(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
|
|
22618
22983
|
throw new Error("Invalid semantic cache configuration source");
|
|
22619
22984
|
const configSource = binding.sources.find((source) => source.path === configPath && source.sha256 !== null && source.format === undefined && source.fields === undefined);
|
|
22620
22985
|
if (!configSource || projected(configSource) !== configSource.sha256)
|
|
22621
22986
|
throw new Error("Codex semantic cache requires unchanged reviewed configuration");
|
|
22622
22987
|
assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, proof.hookRootAlias);
|
|
22623
22988
|
const rules = parseConfig(read2(configPath), configPath, true).skills?.config ?? [];
|
|
22624
|
-
const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, rules });
|
|
22989
|
+
const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, reviewedHookParents, rules });
|
|
22625
22990
|
assertCodexSemanticCacheWitnessUnchanged(proof.witness, current);
|
|
22626
22991
|
return proof;
|
|
22627
22992
|
}
|
|
@@ -22705,7 +23070,7 @@ function codexInstallationRoots(binding) {
|
|
|
22705
23070
|
const config = join35(dirname23(dirname23(cache)), "config.toml"), home = dirname23(dirname23(dirname23(cache)));
|
|
22706
23071
|
const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
22707
23072
|
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join35(home, path));
|
|
22708
|
-
if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep11) || input.sourceRoot.startsWith(root2 + sep11)) || binding.sources.some((source) =>
|
|
23073
|
+
if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep11) || input.sourceRoot.startsWith(root2 + sep11)) || binding.sources.some((source) => basename13(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep11)))))
|
|
22709
23074
|
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
22710
23075
|
if (proof.plugins.some((input) => dirname23(dirname23(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join35(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
22711
23076
|
throw new Error("Missing native installation input source witness");
|
|
@@ -22717,13 +23082,13 @@ function codexInstallationRoots(binding) {
|
|
|
22717
23082
|
});
|
|
22718
23083
|
}
|
|
22719
23084
|
function assertMarketplaceBinding(binding, source) {
|
|
22720
|
-
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" ||
|
|
23085
|
+
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename13(source.path) !== "plugin.json" || !source.path.endsWith(join35(sep11, ".claude-plugin", "plugin.json"))))
|
|
22721
23086
|
throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
|
|
22722
|
-
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" ||
|
|
23087
|
+
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename13(source.path) !== "sumi.json"))
|
|
22723
23088
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
22724
|
-
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4" || source.hashMode === "codex-settings-v5")) && (binding.agent !== "codex" || binding.method !== "reviewed" ||
|
|
23089
|
+
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4" || source.hashMode === "codex-settings-v5")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename13(source.path) !== "config.toml"))
|
|
22725
23090
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
22726
|
-
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" ||
|
|
23091
|
+
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" || basename13(source.path) !== "settings.json"))
|
|
22727
23092
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
22728
23093
|
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
22729
23094
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
@@ -22841,7 +23206,7 @@ function verifyAutomaticDiscoveryClosure(binding, options) {
|
|
|
22841
23206
|
const current = resolveAgentDiscovery({ home: options.home, agent: binding.agent, canonical: options.canonical, executable: runtime });
|
|
22842
23207
|
if (JSON.stringify(current) === JSON.stringify(binding))
|
|
22843
23208
|
return;
|
|
22844
|
-
const reviewedWithRuntime = (binding.builtinNames?.length ?? 0) > 0 || binding.sources.some((source) =>
|
|
23209
|
+
const reviewedWithRuntime = (binding.builtinNames?.length ?? 0) > 0 || binding.sources.some((source) => basename13(source.path) === "package.json");
|
|
22845
23210
|
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) => isDeepStrictEqual7(saved, source)));
|
|
22846
23211
|
if (command && gap && runtime === null && reviewedWithRuntime && otherwiseCurrent)
|
|
22847
23212
|
throw discoveryRootUnresolved(binding.agent, command, gap);
|
|
@@ -22984,7 +23349,7 @@ function resolveAgentDiscovery(options) {
|
|
|
22984
23349
|
throw new Error("Discovery review must include the agent configuration source");
|
|
22985
23350
|
const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical9(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical9(configPath), source)) : sources;
|
|
22986
23351
|
const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
|
|
22987
|
-
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" ||
|
|
23352
|
+
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename13(source.path) !== "plugin.json" || !source.path.endsWith(join35(sep11, ".claude-plugin", "plugin.json")))
|
|
22988
23353
|
return source;
|
|
22989
23354
|
const pluginRoot = dirname23(dirname23(source.path)), hooksPath = join35(pluginRoot, "hooks/hooks.json");
|
|
22990
23355
|
const hookStat = lstatSync28(hooksPath, { throwIfNoEntry: false });
|
|
@@ -23150,7 +23515,7 @@ function physicalPath(path) {
|
|
|
23150
23515
|
let cursor = resolve24(path);
|
|
23151
23516
|
const suffix = [];
|
|
23152
23517
|
while (!lstatSync29(cursor, { throwIfNoEntry: false })) {
|
|
23153
|
-
suffix.unshift(
|
|
23518
|
+
suffix.unshift(basename14(cursor));
|
|
23154
23519
|
const parent = dirname24(cursor);
|
|
23155
23520
|
if (parent === cursor)
|
|
23156
23521
|
return resolve24(path);
|
|
@@ -23369,7 +23734,7 @@ function physicalImportPath(path) {
|
|
|
23369
23734
|
let ancestor = resolve25(path);
|
|
23370
23735
|
const suffix = [];
|
|
23371
23736
|
while (!existsSync14(ancestor)) {
|
|
23372
|
-
suffix.unshift(
|
|
23737
|
+
suffix.unshift(basename15(ancestor));
|
|
23373
23738
|
ancestor = dirname25(ancestor);
|
|
23374
23739
|
}
|
|
23375
23740
|
return join37(realpathSync15(ancestor), ...suffix);
|
|
@@ -23394,8 +23759,8 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
23394
23759
|
const explicitName = options.name != null;
|
|
23395
23760
|
const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
|
|
23396
23761
|
if (isOfficialSkillName(skillName) && !options.allowShadow) {
|
|
23397
|
-
const sourceSlug = safeNormalizeName(
|
|
23398
|
-
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${
|
|
23762
|
+
const sourceSlug = safeNormalizeName(basename15(absoluteSource));
|
|
23763
|
+
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename15(absoluteSource)}')` : ""} matches a bundled official skill.`;
|
|
23399
23764
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
23400
23765
|
}
|
|
23401
23766
|
const readOnlyDestination = join37(resolvePortableSkillsRoot(options, false), skillName);
|
|
@@ -49985,7 +50350,7 @@ async function reconcileSkillSession(input2, options = {}) {
|
|
|
49985
50350
|
// src/lib/claude-prospective-review.ts
|
|
49986
50351
|
import { createHash as createHash38 } from "crypto";
|
|
49987
50352
|
import { lstatSync as lstatSync31, readFileSync as readFileSync31, readdirSync as readdirSync18, realpathSync as realpathSync17 } from "fs";
|
|
49988
|
-
import { basename as
|
|
50353
|
+
import { basename as basename16, dirname as dirname33, isAbsolute as isAbsolute29, join as join47, relative as relative15, resolve as resolve30, sep as sep18 } from "path";
|
|
49989
50354
|
var MAX_CANDIDATE_FILES = 16384;
|
|
49990
50355
|
var MAX_CANDIDATE_BYTES = 256 * 1024 * 1024;
|
|
49991
50356
|
var sha7 = (data) => createHash38("sha256").update(data).digest("hex");
|