@hasna/skills 0.10.65 → 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 +1 -1
- package/bin/index.js +362 -82
- package/bin/mcp.js +261 -40
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +330 -50
- 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/runtime-prerequisites.js +37 -3
- package/dist/sdk/index.js +341 -61
- 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
|
|
@@ -19107,7 +19319,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
19107
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 })) } };
|
|
19108
19320
|
}
|
|
19109
19321
|
function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
19110
|
-
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))
|
|
19111
19323
|
throw new Error("Invalid Codex semantic cache upgrade request");
|
|
19112
19324
|
const home = resolve18(options.home ?? homedir2()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
19113
19325
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
@@ -19131,14 +19343,23 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
19131
19343
|
throw new Error("Native settings preimage changed");
|
|
19132
19344
|
const boundedRead = (path) => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024));
|
|
19133
19345
|
const unchangedFullSource = (path) => {
|
|
19134
|
-
const
|
|
19135
|
-
if (
|
|
19136
|
-
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];
|
|
19137
19350
|
const text2 = boundedRead(path);
|
|
19138
19351
|
if (sha4(text2) !== source.sha256)
|
|
19139
19352
|
throw new Error("Reviewed cache identity source changed");
|
|
19140
19353
|
return text2;
|
|
19141
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
|
+
};
|
|
19142
19363
|
const appOnlyParents = options.appOnlyParents.map((parent) => {
|
|
19143
19364
|
const parts = relative8(cacheRoot, parent).split(sep10);
|
|
19144
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))
|
|
@@ -19153,11 +19374,60 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
19153
19374
|
unchangedFullSource(source.path);
|
|
19154
19375
|
return { role: "app-only", pluginId: `${parts[1]}@${parts[0]}`, namespace: parts[1], pluginParent: parent, remotePluginId: receipt.remote_plugin_id };
|
|
19155
19376
|
}).sort((a, b) => a.pluginParent.localeCompare(b.pluginParent));
|
|
19156
|
-
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)])];
|
|
19157
19427
|
const reviewedAlias = aliases.find((alias) => alias.agent === "codex");
|
|
19158
19428
|
const hookRootAlias = reviewedAlias ? { alias: reviewedAlias.alias, target: reviewedAlias.target } : null;
|
|
19159
19429
|
assertCodexSemanticCacheHookSafety(cacheRoot, parents2, configPath, hookRootAlias);
|
|
19160
|
-
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)));
|
|
19161
19431
|
for (const source of supersededSources)
|
|
19162
19432
|
if ([".app.json", ".mcp.json"].includes(source.path.split(sep10).at(-1)))
|
|
19163
19433
|
unchangedFullSource(source.path);
|
|
@@ -19165,7 +19435,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
19165
19435
|
if (!supersededDirectories.some((directory) => directory.path === cacheRoot) || (binding.directories ?? []).some((directory) => cacheRoot.startsWith(directory.path + sep10)))
|
|
19166
19436
|
throw new Error("Cache upgrade requires exact cache directory coverage without an unproved ancestor projection");
|
|
19167
19437
|
const rules = Bun.TOML.parse(settings).skills?.config ?? [];
|
|
19168
|
-
const witness = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents, rules, read: boundedRead });
|
|
19438
|
+
const witness = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents, reviewedHookParents, rules, read: boundedRead });
|
|
19169
19439
|
if (options.expectedCacheWitnessSha256 !== undefined && witness.sha256 !== options.expectedCacheWitnessSha256)
|
|
19170
19440
|
throw new Error("Reviewed semantic cache preimage changed");
|
|
19171
19441
|
const replacement = { ...binding, codexDisabledPluginSkills: controls, codexSemanticCache: {
|
|
@@ -19174,6 +19444,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
19174
19444
|
hookRootAlias,
|
|
19175
19445
|
witness,
|
|
19176
19446
|
appOnlyParents,
|
|
19447
|
+
reviewedHookParents,
|
|
19177
19448
|
previousPolicySha256: options.expectedPolicySha256,
|
|
19178
19449
|
supersededSources,
|
|
19179
19450
|
supersededDirectories
|
|
@@ -19192,7 +19463,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
19192
19463
|
rootAliases: aliases,
|
|
19193
19464
|
managedAgentChecks: { home, agents: ["codex"] },
|
|
19194
19465
|
...policy.bridge.discoveryExecutables ? { discoveryExecutables: policy.bridge.discoveryExecutables } : {},
|
|
19195
|
-
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) }
|
|
19196
19467
|
};
|
|
19197
19468
|
}
|
|
19198
19469
|
function planReviewedArtifactMigration(options) {
|
|
@@ -19970,7 +20241,7 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
|
19970
20241
|
return { action, path: skillMdPath };
|
|
19971
20242
|
const parentDir = dirname19(dir);
|
|
19972
20243
|
mkdirSync8(parentDir, { recursive: true });
|
|
19973
|
-
const transactionDir = mkdtempSync(join28(parentDir, `.hasna-skills-write-${
|
|
20244
|
+
const transactionDir = mkdtempSync(join28(parentDir, `.hasna-skills-write-${basename10(dir)}-`));
|
|
19974
20245
|
const candidateDir = join28(transactionDir, "candidate");
|
|
19975
20246
|
const backupDir = join28(transactionDir, "backup");
|
|
19976
20247
|
const candidateSkillMdPath = join28(candidateDir, "SKILL.md");
|
|
@@ -22000,7 +22271,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
22000
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");
|
|
22001
22272
|
const approval = (producer) => {
|
|
22002
22273
|
pluginText(producer);
|
|
22003
|
-
const digest2 = `sha256:${
|
|
22274
|
+
const digest2 = `sha256:${basename11(producer)}`;
|
|
22004
22275
|
const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest2);
|
|
22005
22276
|
pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
|
|
22006
22277
|
if (!verified.has(producer)) {
|
|
@@ -22064,7 +22335,7 @@ function captureManagedPluginRegistry(path, managedPlugins) {
|
|
|
22064
22335
|
// src/lib/claude-marketplace-registry.ts
|
|
22065
22336
|
import { createHash as createHash26 } from "crypto";
|
|
22066
22337
|
import { closeSync as closeSync17, constants as constants18, fstatSync as fstatSync17, lstatSync as lstatSync27, openSync as openSync17, readSync as readSync13 } from "fs";
|
|
22067
|
-
import { basename as
|
|
22338
|
+
import { basename as basename12, dirname as dirname22, isAbsolute as isAbsolute23, resolve as resolve22 } from "path";
|
|
22068
22339
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
22069
22340
|
function need8(value, reason2) {
|
|
22070
22341
|
if (!value)
|
|
@@ -22086,7 +22357,7 @@ function parents2(path) {
|
|
|
22086
22357
|
}
|
|
22087
22358
|
function readRegistry2(path, budget2) {
|
|
22088
22359
|
absolutePath4(path);
|
|
22089
|
-
need8(
|
|
22360
|
+
need8(basename12(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
22090
22361
|
need8(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
22091
22362
|
const ancestors2 = parents2(path), initial = lstatSync27(path, { bigint: true });
|
|
22092
22363
|
need8(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
@@ -22367,7 +22638,7 @@ function assertReviewedClaudeCacheClosures(home, config, review, canonical9) {
|
|
|
22367
22638
|
throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
|
|
22368
22639
|
}
|
|
22369
22640
|
if ([cacheAliasRoot, cacheRoot].some((root2) => row.installPath === root2 || row.installPath.startsWith(root2 + sep11))) {
|
|
22370
|
-
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)) {
|
|
22371
22642
|
throw new Error("Reviewed Claude discovery has a malformed active cache registration");
|
|
22372
22643
|
}
|
|
22373
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
|
|
@@ -22645,7 +22916,7 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
22645
22916
|
if (!targetValid || !targetScopes.has("user\x00"))
|
|
22646
22917
|
continue;
|
|
22647
22918
|
const active = rows[0]?.installPath;
|
|
22648
|
-
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)
|
|
22649
22920
|
continue;
|
|
22650
22921
|
const activeManifest = full(join35(active, ".claude-plugin/plugin.json"));
|
|
22651
22922
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
@@ -22654,14 +22925,15 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
22654
22925
|
}
|
|
22655
22926
|
return [...result];
|
|
22656
22927
|
}
|
|
22657
|
-
function codexSemanticCacheSourceRole(source, cacheRoot, parents3) {
|
|
22928
|
+
function codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParents = []) {
|
|
22658
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")
|
|
22659
22930
|
return false;
|
|
22660
22931
|
const parts = relative9(cacheRoot, source.path).split(sep11);
|
|
22661
22932
|
if (parts.length < 3 || !parents3.includes(join35(cacheRoot, parts[0], parts[1])))
|
|
22662
22933
|
return false;
|
|
22663
22934
|
const tail = parts.slice(3).join("/");
|
|
22664
|
-
|
|
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");
|
|
22665
22937
|
}
|
|
22666
22938
|
function codexSemanticCacheDirectoryRole(path, cacheRoot) {
|
|
22667
22939
|
return isAbsolute24(path) && resolve23(path) === path && !/[\x00-\x1f\x7f]/.test(path) && (path === cacheRoot || path.startsWith(cacheRoot + sep11));
|
|
@@ -22693,20 +22965,28 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
|
|
|
22693
22965
|
const cacheRoot = proof.witness.cacheRoot;
|
|
22694
22966
|
if (controls.some((control) => dirname23(dirname23(control.pluginParent)) !== cacheRoot))
|
|
22695
22967
|
throw new Error("Codex semantic cache names another enrolled cache");
|
|
22696
|
-
const
|
|
22697
|
-
|
|
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));
|
|
22698
22978
|
const directories = (binding.directories ?? []).filter((directory) => codexSemanticCacheDirectoryRole(directory.path, cacheRoot));
|
|
22699
22979
|
if (!directories.length || !isDeepStrictEqual7(sources, proof.supersededSources) || !isDeepStrictEqual7(directories, proof.supersededDirectories))
|
|
22700
22980
|
throw new Error("Codex semantic cache provenance changed");
|
|
22701
22981
|
const configPath = proof.configPath;
|
|
22702
|
-
if (!isAbsolute24(configPath) || resolve23(configPath) !== configPath ||
|
|
22982
|
+
if (!isAbsolute24(configPath) || resolve23(configPath) !== configPath || basename13(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
|
|
22703
22983
|
throw new Error("Invalid semantic cache configuration source");
|
|
22704
22984
|
const configSource = binding.sources.find((source) => source.path === configPath && source.sha256 !== null && source.format === undefined && source.fields === undefined);
|
|
22705
22985
|
if (!configSource || projected(configSource) !== configSource.sha256)
|
|
22706
22986
|
throw new Error("Codex semantic cache requires unchanged reviewed configuration");
|
|
22707
22987
|
assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, proof.hookRootAlias);
|
|
22708
22988
|
const rules = parseConfig(read2(configPath), configPath, true).skills?.config ?? [];
|
|
22709
|
-
const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, rules });
|
|
22989
|
+
const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, reviewedHookParents, rules });
|
|
22710
22990
|
assertCodexSemanticCacheWitnessUnchanged(proof.witness, current);
|
|
22711
22991
|
return proof;
|
|
22712
22992
|
}
|
|
@@ -22790,7 +23070,7 @@ function codexInstallationRoots(binding) {
|
|
|
22790
23070
|
const config = join35(dirname23(dirname23(cache)), "config.toml"), home = dirname23(dirname23(dirname23(cache)));
|
|
22791
23071
|
const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
22792
23072
|
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join35(home, path));
|
|
22793
|
-
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)))))
|
|
22794
23074
|
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
22795
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)))
|
|
22796
23076
|
throw new Error("Missing native installation input source witness");
|
|
@@ -22802,13 +23082,13 @@ function codexInstallationRoots(binding) {
|
|
|
22802
23082
|
});
|
|
22803
23083
|
}
|
|
22804
23084
|
function assertMarketplaceBinding(binding, source) {
|
|
22805
|
-
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"))))
|
|
22806
23086
|
throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
|
|
22807
|
-
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"))
|
|
22808
23088
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
22809
|
-
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"))
|
|
22810
23090
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
22811
|
-
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"))
|
|
22812
23092
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
22813
23093
|
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
22814
23094
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
@@ -22926,7 +23206,7 @@ function verifyAutomaticDiscoveryClosure(binding, options) {
|
|
|
22926
23206
|
const current = resolveAgentDiscovery({ home: options.home, agent: binding.agent, canonical: options.canonical, executable: runtime });
|
|
22927
23207
|
if (JSON.stringify(current) === JSON.stringify(binding))
|
|
22928
23208
|
return;
|
|
22929
|
-
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");
|
|
22930
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)));
|
|
22931
23211
|
if (command && gap && runtime === null && reviewedWithRuntime && otherwiseCurrent)
|
|
22932
23212
|
throw discoveryRootUnresolved(binding.agent, command, gap);
|
|
@@ -23069,7 +23349,7 @@ function resolveAgentDiscovery(options) {
|
|
|
23069
23349
|
throw new Error("Discovery review must include the agent configuration source");
|
|
23070
23350
|
const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical9(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical9(configPath), source)) : sources;
|
|
23071
23351
|
const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
|
|
23072
|
-
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")))
|
|
23073
23353
|
return source;
|
|
23074
23354
|
const pluginRoot = dirname23(dirname23(source.path)), hooksPath = join35(pluginRoot, "hooks/hooks.json");
|
|
23075
23355
|
const hookStat = lstatSync28(hooksPath, { throwIfNoEntry: false });
|
|
@@ -23235,7 +23515,7 @@ function physicalPath(path) {
|
|
|
23235
23515
|
let cursor = resolve24(path);
|
|
23236
23516
|
const suffix = [];
|
|
23237
23517
|
while (!lstatSync29(cursor, { throwIfNoEntry: false })) {
|
|
23238
|
-
suffix.unshift(
|
|
23518
|
+
suffix.unshift(basename14(cursor));
|
|
23239
23519
|
const parent = dirname24(cursor);
|
|
23240
23520
|
if (parent === cursor)
|
|
23241
23521
|
return resolve24(path);
|
|
@@ -23454,7 +23734,7 @@ function physicalImportPath(path) {
|
|
|
23454
23734
|
let ancestor = resolve25(path);
|
|
23455
23735
|
const suffix = [];
|
|
23456
23736
|
while (!existsSync14(ancestor)) {
|
|
23457
|
-
suffix.unshift(
|
|
23737
|
+
suffix.unshift(basename15(ancestor));
|
|
23458
23738
|
ancestor = dirname25(ancestor);
|
|
23459
23739
|
}
|
|
23460
23740
|
return join37(realpathSync15(ancestor), ...suffix);
|
|
@@ -23479,8 +23759,8 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
23479
23759
|
const explicitName = options.name != null;
|
|
23480
23760
|
const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
|
|
23481
23761
|
if (isOfficialSkillName(skillName) && !options.allowShadow) {
|
|
23482
|
-
const sourceSlug = safeNormalizeName(
|
|
23483
|
-
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.`;
|
|
23484
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.`);
|
|
23485
23765
|
}
|
|
23486
23766
|
const readOnlyDestination = join37(resolvePortableSkillsRoot(options, false), skillName);
|
|
@@ -50070,7 +50350,7 @@ async function reconcileSkillSession(input2, options = {}) {
|
|
|
50070
50350
|
// src/lib/claude-prospective-review.ts
|
|
50071
50351
|
import { createHash as createHash38 } from "crypto";
|
|
50072
50352
|
import { lstatSync as lstatSync31, readFileSync as readFileSync31, readdirSync as readdirSync18, realpathSync as realpathSync17 } from "fs";
|
|
50073
|
-
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";
|
|
50074
50354
|
var MAX_CANDIDATE_FILES = 16384;
|
|
50075
50355
|
var MAX_CANDIDATE_BYTES = 256 * 1024 * 1024;
|
|
50076
50356
|
var sha7 = (data) => createHash38("sha256").update(data).digest("hex");
|