@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/sdk/index.js
CHANGED
|
@@ -32371,7 +32371,7 @@ var init_event_sink = __esm(() => {
|
|
|
32371
32371
|
init_dist();
|
|
32372
32372
|
});
|
|
32373
32373
|
// package.json
|
|
32374
|
-
var version = "0.10.
|
|
32374
|
+
var version = "0.10.66";
|
|
32375
32375
|
var package_default = {
|
|
32376
32376
|
name: "@hasna/skills",
|
|
32377
32377
|
version,
|
|
@@ -38326,7 +38326,7 @@ import {
|
|
|
38326
38326
|
writeFileSync as writeFileSync8
|
|
38327
38327
|
} from "fs";
|
|
38328
38328
|
import { homedir as homedir5 } from "os";
|
|
38329
|
-
import { basename as
|
|
38329
|
+
import { basename as basename15, dirname as dirname25, join as join35 } from "path";
|
|
38330
38330
|
|
|
38331
38331
|
// src/lib/sumi-settings-witness.ts
|
|
38332
38332
|
import { createHash as createHash8 } from "crypto";
|
|
@@ -40671,7 +40671,7 @@ function upgradeCodexSettingsWitnessV5(previous, reviewedSettingsPath) {
|
|
|
40671
40671
|
// src/lib/codex-semantic-cache-witness.ts
|
|
40672
40672
|
import { createHash as createHash13 } from "crypto";
|
|
40673
40673
|
import { constants as constants9, closeSync as closeSync12, fstatSync as fstatSync12, lstatSync as lstatSync10, openSync as openSync12, readSync as readSync6, readdirSync as readdirSync4, realpathSync as realpathSync9 } from "fs";
|
|
40674
|
-
import { dirname as dirname9, isAbsolute as isAbsolute8, join as join15, relative as relative6, resolve as resolve8, sep as sep5 } from "path";
|
|
40674
|
+
import { basename as basename5, dirname as dirname9, isAbsolute as isAbsolute8, join as join15, relative as relative6, resolve as resolve8, sep as sep5 } from "path";
|
|
40675
40675
|
var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1";
|
|
40676
40676
|
var identifier4 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value);
|
|
40677
40677
|
var digest2 = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
|
|
@@ -40680,6 +40680,24 @@ var refuse5 = () => {
|
|
|
40680
40680
|
};
|
|
40681
40681
|
var MAX_DOCUMENT_BYTES = 1024 * 1024;
|
|
40682
40682
|
var MAX_RECEIPT_BYTES = 16 * 1024;
|
|
40683
|
+
function codexLocalMarketplaceMapsPlugin(text, marketplace, plugin) {
|
|
40684
|
+
try {
|
|
40685
|
+
hashNativeJsonControls(text);
|
|
40686
|
+
const value = JSON.parse(text);
|
|
40687
|
+
if (!plainObject(value) || !exactKeys2(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)
|
|
40688
|
+
return false;
|
|
40689
|
+
const rows = value.plugins.filter((row2) => plainObject(row2) && row2.name === plugin);
|
|
40690
|
+
if (rows.length !== 1)
|
|
40691
|
+
return false;
|
|
40692
|
+
const row = rows[0];
|
|
40693
|
+
if (!exactKeys2(row, ["name", "source"]) || !plainObject(row.source) || !exactKeys2(row.source, ["source", "path"]) || row.source.source !== "local" || typeof row.source.path !== "string" || !row.source.path.startsWith("./") || row.source.path.includes("\\"))
|
|
40694
|
+
return false;
|
|
40695
|
+
const parts = row.source.path.split("/");
|
|
40696
|
+
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;
|
|
40697
|
+
} catch {
|
|
40698
|
+
return false;
|
|
40699
|
+
}
|
|
40700
|
+
}
|
|
40683
40701
|
function defaultRead(path) {
|
|
40684
40702
|
const before = lstatSync10(path, { throwIfNoEntry: false, bigint: true });
|
|
40685
40703
|
if (before === undefined)
|
|
@@ -40741,7 +40759,7 @@ function validPluginParent(cacheRoot, pluginParent, namespace, pluginId) {
|
|
|
40741
40759
|
return parts.length === 2 && parts.every(identifier4) && parts[1] === namespace && pluginId === `${namespace}@${parts[0]}`;
|
|
40742
40760
|
}
|
|
40743
40761
|
function assertWitnessShape(value) {
|
|
40744
|
-
if (!plainObject(value) || !exactKeys2(value, ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256"]) || value.schema !== CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA || typeof value.cacheRoot !== "string" || !isAbsolute8(value.cacheRoot) || resolve8(value.cacheRoot) !== value.cacheRoot || !digest2(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)
|
|
40762
|
+
if (!plainObject(value) || !exactKeys2(value, ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256"], ["hookParents"]) || value.schema !== CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA || typeof value.cacheRoot !== "string" || !isAbsolute8(value.cacheRoot) || resolve8(value.cacheRoot) !== value.cacheRoot || !digest2(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)
|
|
40745
40763
|
refuse5();
|
|
40746
40764
|
const witness = value;
|
|
40747
40765
|
const controlParents = new Set;
|
|
@@ -40762,6 +40780,20 @@ function assertWitnessShape(value) {
|
|
|
40762
40780
|
refuse5();
|
|
40763
40781
|
appOnlyParentPaths.add(row.pluginParent);
|
|
40764
40782
|
}
|
|
40783
|
+
const hookParentPaths = new Set;
|
|
40784
|
+
const hookParents = witness.hookParents === undefined ? [] : witness.hookParents;
|
|
40785
|
+
if (!Array.isArray(hookParents) || hookParents.length > 4096)
|
|
40786
|
+
refuse5();
|
|
40787
|
+
for (const candidate of hookParents) {
|
|
40788
|
+
if (!plainObject(candidate))
|
|
40789
|
+
refuse5();
|
|
40790
|
+
const row = candidate;
|
|
40791
|
+
const remote = row.installation === "remote-receipt";
|
|
40792
|
+
const local = row.installation === "local-marketplace";
|
|
40793
|
+
if (!exactKeys2(row, ["role", "pluginId", "namespace", "pluginParent", "installation", "manifestSha256", "hooksSha256"], remote ? ["remotePluginId", "receiptSha256"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || row.role !== "reviewed-hook" || !identifier4(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) || !digest2(row.receiptSha256)) || local && (typeof row.marketplaceSourcePath !== "string" || !isAbsolute8(row.marketplaceSourcePath) || resolve8(row.marketplaceSourcePath) !== row.marketplaceSourcePath || basename5(row.marketplaceSourcePath) !== "marketplace.json" || !digest2(row.marketplaceSha256)) || !remote && !local || !digest2(row.manifestSha256) || !digest2(row.hooksSha256) || hookParentPaths.has(row.pluginParent) || controlParents.has(row.pluginParent) || appOnlyParentPaths.has(row.pluginParent))
|
|
40794
|
+
refuse5();
|
|
40795
|
+
hookParentPaths.add(row.pluginParent);
|
|
40796
|
+
}
|
|
40765
40797
|
const skillNames = new Set;
|
|
40766
40798
|
const qualifiedNames = new Set;
|
|
40767
40799
|
for (const candidate of witness.skills) {
|
|
@@ -40781,6 +40813,7 @@ function assertWitnessShape(value) {
|
|
|
40781
40813
|
cacheRoot: witness.cacheRoot,
|
|
40782
40814
|
controls: witness.controls,
|
|
40783
40815
|
appOnlyParents: witness.appOnlyParents,
|
|
40816
|
+
...witness.hookParents === undefined ? {} : { hookParents: witness.hookParents },
|
|
40784
40817
|
skills: witness.skills
|
|
40785
40818
|
};
|
|
40786
40819
|
if (hash2(projection) !== witness.sha256)
|
|
@@ -40971,10 +41004,147 @@ function appOnlyParentProjection(cacheRoot, parents2, read) {
|
|
|
40971
41004
|
}
|
|
40972
41005
|
return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
|
|
40973
41006
|
}
|
|
40974
|
-
|
|
41007
|
+
var codexHookEvents = new Set([
|
|
41008
|
+
"SessionStart",
|
|
41009
|
+
"UserPromptSubmit",
|
|
41010
|
+
"PreToolUse",
|
|
41011
|
+
"PostToolUse",
|
|
41012
|
+
"PostToolUseFailure",
|
|
41013
|
+
"Stop",
|
|
41014
|
+
"SubagentStart",
|
|
41015
|
+
"SubagentStop",
|
|
41016
|
+
"PreCompact",
|
|
41017
|
+
"Notification",
|
|
41018
|
+
"PermissionRequest",
|
|
41019
|
+
"SessionEnd",
|
|
41020
|
+
"ConfigChange",
|
|
41021
|
+
"WorktreeCreate",
|
|
41022
|
+
"WorktreeRemove",
|
|
41023
|
+
"TeammateIdle",
|
|
41024
|
+
"TaskComplete"
|
|
41025
|
+
]);
|
|
41026
|
+
function assertJsonValue(value, depth = 0, budget2 = { members: 0 }) {
|
|
41027
|
+
if (depth > 32 || ++budget2.members > 4096)
|
|
41028
|
+
refuse5();
|
|
41029
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
41030
|
+
return;
|
|
41031
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
41032
|
+
return;
|
|
41033
|
+
if (Array.isArray(value)) {
|
|
41034
|
+
for (const item of value)
|
|
41035
|
+
assertJsonValue(item, depth + 1, budget2);
|
|
41036
|
+
return;
|
|
41037
|
+
}
|
|
41038
|
+
if (!plainObject(value))
|
|
41039
|
+
refuse5();
|
|
41040
|
+
for (const [key, item] of Object.entries(value)) {
|
|
41041
|
+
if (!key || /[\x00-\x1f\x7f]/.test(key))
|
|
41042
|
+
refuse5();
|
|
41043
|
+
assertJsonValue(item, depth + 1, budget2);
|
|
41044
|
+
}
|
|
41045
|
+
}
|
|
41046
|
+
function reviewedHookControls(root, read) {
|
|
41047
|
+
const manifestPath = join15(root, ".codex-plugin/plugin.json"), hooksPath = join15(root, "hooks/hooks.json");
|
|
41048
|
+
let manifest, manifestSha256, hooks, hooksSha256;
|
|
41049
|
+
try {
|
|
41050
|
+
const manifestText = read(manifestPath);
|
|
41051
|
+
manifestSha256 = hashNativeJsonControls(manifestText, "version");
|
|
41052
|
+
manifest = JSON.parse(manifestText);
|
|
41053
|
+
const hooksText = read(hooksPath);
|
|
41054
|
+
hashNativeJsonControls(hooksText);
|
|
41055
|
+
hooksSha256 = createHash13("sha256").update(hooksText).digest("hex");
|
|
41056
|
+
hooks = JSON.parse(hooksText);
|
|
41057
|
+
} catch {
|
|
41058
|
+
return refuse5();
|
|
41059
|
+
}
|
|
41060
|
+
if (!plainObject(manifest) || !exactKeys2(manifest, ["name", "version", "hooks"], ["description"]) || !identifier4(manifest.name) || typeof manifest.version !== "string" || manifest.version !== basename5(root) || manifest.hooks !== "./hooks/hooks.json" || manifest.description !== undefined && (typeof manifest.description !== "string" || !manifest.description.trim() || manifest.description.length > 1024))
|
|
41061
|
+
refuse5();
|
|
41062
|
+
const manifestRecord = manifest;
|
|
41063
|
+
if (!plainObject(hooks) || !exactKeys2(hooks, ["hooks"]) || !plainObject(hooks.hooks))
|
|
41064
|
+
refuse5();
|
|
41065
|
+
const hookTable = hooks.hooks;
|
|
41066
|
+
const events = Object.entries(hookTable);
|
|
41067
|
+
if (!events.length || events.length > 32)
|
|
41068
|
+
refuse5();
|
|
41069
|
+
for (const [event, groups] of events) {
|
|
41070
|
+
if (!codexHookEvents.has(event) || !Array.isArray(groups) || !groups.length || groups.length > 32)
|
|
41071
|
+
refuse5();
|
|
41072
|
+
for (const group of groups) {
|
|
41073
|
+
if (!plainObject(group) || !exactKeys2(group, ["hooks"]) || !Array.isArray(group.hooks) || !group.hooks.length || group.hooks.length > 32)
|
|
41074
|
+
refuse5();
|
|
41075
|
+
const handlers = group.hooks;
|
|
41076
|
+
for (const handler of handlers) {
|
|
41077
|
+
if (!plainObject(handler) || !exactKeys2(handler, ["type", "server", "tool", "input"], ["timeout"]) || handler.type !== "mcp_tool" || !identifier4(handler.server) || !identifier4(handler.tool) || !plainObject(handler.input) || handler.timeout !== undefined && (!Number.isSafeInteger(handler.timeout) || Number(handler.timeout) < 1 || Number(handler.timeout) > 300))
|
|
41078
|
+
refuse5();
|
|
41079
|
+
assertJsonValue(handler.input);
|
|
41080
|
+
}
|
|
41081
|
+
}
|
|
41082
|
+
}
|
|
41083
|
+
return { namespace: manifestRecord.name, manifestSha256, hooksSha256 };
|
|
41084
|
+
}
|
|
41085
|
+
function reviewedHookParentProjection(cacheRoot, parents2, read) {
|
|
41086
|
+
if (!Array.isArray(parents2) || parents2.length > 4096)
|
|
41087
|
+
refuse5();
|
|
41088
|
+
const seen = new Set, rows = [];
|
|
41089
|
+
for (const parent of parents2) {
|
|
41090
|
+
const remote = parent?.installation === "remote-receipt", local = parent?.installation === "local-marketplace";
|
|
41091
|
+
if (!parent || !exactKeys2(parent, ["installation", "namespace", "pluginId", "pluginParent", "role"], remote ? ["remotePluginId"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || parent.role !== "reviewed-hook" || !identifier4(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" || !isAbsolute8(parent.marketplaceSourcePath) || resolve8(parent.marketplaceSourcePath) !== parent.marketplaceSourcePath || basename5(parent.marketplaceSourcePath) !== "marketplace.json" || !digest2(parent.marketplaceSha256)) || !remote && !local)
|
|
41092
|
+
refuse5();
|
|
41093
|
+
const parts = relative6(cacheRoot, parent.pluginParent).split(sep5);
|
|
41094
|
+
if (!isAbsolute8(parent.pluginParent) || resolve8(parent.pluginParent) !== parent.pluginParent || parts.length !== 2 || parts.some((part) => !identifier4(part)) || parts[1] !== parent.namespace || parent.pluginId !== `${parent.namespace}@${parts[0]}` || seen.has(parent.pluginParent))
|
|
41095
|
+
refuse5();
|
|
41096
|
+
seen.add(parent.pluginParent);
|
|
41097
|
+
const parentStat = lstatSync10(parent.pluginParent, { throwIfNoEntry: false });
|
|
41098
|
+
if (!parentStat?.isDirectory() || parentStat.isSymbolicLink() || realpathSync9(parent.pluginParent) !== parent.pluginParent)
|
|
41099
|
+
refuse5();
|
|
41100
|
+
const receiptPath = join15(parent.pluginParent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync10(receiptPath, { throwIfNoEntry: false });
|
|
41101
|
+
let receiptText;
|
|
41102
|
+
if (remote) {
|
|
41103
|
+
if (!receiptStat?.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > MAX_RECEIPT_BYTES)
|
|
41104
|
+
refuse5();
|
|
41105
|
+
try {
|
|
41106
|
+
receiptText = read(receiptPath);
|
|
41107
|
+
hashNativeJsonControls(receiptText);
|
|
41108
|
+
const receipt = JSON.parse(receiptText);
|
|
41109
|
+
if (!plainObject(receipt) || !exactKeys2(receipt, ["schema_version", "remote_plugin_id"]) || receipt.schema_version !== 1 || receipt.remote_plugin_id !== parent.remotePluginId)
|
|
41110
|
+
refuse5();
|
|
41111
|
+
} catch {
|
|
41112
|
+
refuse5();
|
|
41113
|
+
}
|
|
41114
|
+
} else {
|
|
41115
|
+
const marketplaceSourcePath = parent.marketplaceSourcePath ?? refuse5();
|
|
41116
|
+
if (receiptStat !== undefined || !parent.marketplaceSha256)
|
|
41117
|
+
refuse5();
|
|
41118
|
+
let marketplaceText;
|
|
41119
|
+
try {
|
|
41120
|
+
marketplaceText = read(marketplaceSourcePath);
|
|
41121
|
+
} catch {
|
|
41122
|
+
return refuse5();
|
|
41123
|
+
}
|
|
41124
|
+
if (createHash13("sha256").update(marketplaceText).digest("hex") !== parent.marketplaceSha256 || !codexLocalMarketplaceMapsPlugin(marketplaceText, parts[0], parent.namespace))
|
|
41125
|
+
refuse5();
|
|
41126
|
+
}
|
|
41127
|
+
const materializations = readdirSync4(parent.pluginParent).filter((name) => name !== ".codex-remote-plugin-install.json").map((version2) => {
|
|
41128
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
|
|
41129
|
+
refuse5();
|
|
41130
|
+
const root = join15(parent.pluginParent, version2), stat = lstatSync10(root, { throwIfNoEntry: false });
|
|
41131
|
+
if (!stat?.isDirectory() || stat.isSymbolicLink() || realpathSync9(root) !== root)
|
|
41132
|
+
refuse5();
|
|
41133
|
+
const controls = reviewedHookControls(root, read);
|
|
41134
|
+
if (controls.namespace !== parent.namespace)
|
|
41135
|
+
refuse5();
|
|
41136
|
+
return { manifestSha256: controls.manifestSha256, hooksSha256: controls.hooksSha256 };
|
|
41137
|
+
});
|
|
41138
|
+
if (!materializations.length || materializations.some((item) => canonical4(item) !== canonical4(materializations[0])))
|
|
41139
|
+
refuse5();
|
|
41140
|
+
rows.push({ ...parent, ...receiptText === undefined ? {} : { receiptSha256: createHash13("sha256").update(receiptText).digest("hex") }, ...materializations[0] });
|
|
41141
|
+
}
|
|
41142
|
+
return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
|
|
41143
|
+
}
|
|
41144
|
+
function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files, members) {
|
|
40975
41145
|
const expected = new Set;
|
|
40976
41146
|
const expectedMarkets = new Set;
|
|
40977
|
-
for (const control of [...controls, ...appOnlyParents]) {
|
|
41147
|
+
for (const control of [...controls, ...appOnlyParents, ...hookParents]) {
|
|
40978
41148
|
const rel = relative6(cacheRoot, control.pluginParent), parts = rel.split(sep5);
|
|
40979
41149
|
if (resolve8(control.pluginParent) !== control.pluginParent || parts.length !== 2 || parts.some((part) => !identifier4(part)) || control.pluginId !== `${control.namespace}@${parts[0]}` || parts[1] !== control.namespace)
|
|
40980
41150
|
refuse5();
|
|
@@ -41015,7 +41185,9 @@ function assertParents(cacheRoot, controls, appOnlyParents, files, members) {
|
|
|
41015
41185
|
refuse5();
|
|
41016
41186
|
if ([".app.json", ".mcp.json"].includes(base) && (parts.length !== 4 || dirname9(member) !== root))
|
|
41017
41187
|
refuse5();
|
|
41018
|
-
if (
|
|
41188
|
+
if ([".app.json", ".mcp.json"].includes(base) && hookParents.some((reviewed) => reviewed.pluginParent === parent))
|
|
41189
|
+
refuse5();
|
|
41190
|
+
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 === join15(cacheRoot, parts[0], parts[1]))))
|
|
41019
41191
|
refuse5();
|
|
41020
41192
|
}
|
|
41021
41193
|
}
|
|
@@ -41125,13 +41297,14 @@ function captureCodexSemanticCacheWitness(options) {
|
|
|
41125
41297
|
const initialTree = treeSnapshot(options.cacheRoot);
|
|
41126
41298
|
const controls = controlProjection(options.controls, read);
|
|
41127
41299
|
const appOnlyParents = appOnlyParentProjection(options.cacheRoot, options.appOnlyParents ?? [], read);
|
|
41300
|
+
const hookParents = reviewedHookParentProjection(options.cacheRoot, options.reviewedHookParents ?? [], read);
|
|
41128
41301
|
const skillParents = new Set(controls.map((control) => control.pluginParent));
|
|
41129
|
-
if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)))
|
|
41302
|
+
if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)) || hookParents.some((parent) => skillParents.has(parent.pluginParent) || appOnlyParents.some((app) => app.pluginParent === parent.pluginParent)))
|
|
41130
41303
|
refuse5();
|
|
41131
41304
|
if (!reviewedCodexPluginCapabilitiesUnchanged(options.cacheRoot, options.controls, read, options.rules))
|
|
41132
41305
|
refuse5();
|
|
41133
41306
|
const files = initialTree.files;
|
|
41134
|
-
assertParents(options.cacheRoot, controls, appOnlyParents, files, initialTree.state.members);
|
|
41307
|
+
assertParents(options.cacheRoot, controls, appOnlyParents, hookParents, files, initialTree.state.members);
|
|
41135
41308
|
const expectedNamesByRoot = assertSkillMaterializations(options.cacheRoot, options.controls, files, read);
|
|
41136
41309
|
const docs = files.filter((path) => path.endsWith(`${sep5}SKILL.md`));
|
|
41137
41310
|
const skillRows = [];
|
|
@@ -41140,6 +41313,8 @@ function captureCodexSemanticCacheWitness(options) {
|
|
|
41140
41313
|
const rel = relative6(options.cacheRoot, document).split(sep5);
|
|
41141
41314
|
if (appOnlyParents.some((parent) => parent.pluginParent === join15(options.cacheRoot, rel[0], rel[1])))
|
|
41142
41315
|
refuse5();
|
|
41316
|
+
if (hookParents.some((parent) => parent.pluginParent === join15(options.cacheRoot, rel[0], rel[1])))
|
|
41317
|
+
refuse5();
|
|
41143
41318
|
const documentStat = lstatSync10(document, { throwIfNoEntry: false });
|
|
41144
41319
|
if (!documentStat?.isFile() || documentStat.isSymbolicLink() || documentStat.size > MAX_DOCUMENT_BYTES)
|
|
41145
41320
|
refuse5();
|
|
@@ -41203,7 +41378,7 @@ function captureCodexSemanticCacheWitness(options) {
|
|
|
41203
41378
|
tracked.verify();
|
|
41204
41379
|
const finalTree = treeSnapshot(options.cacheRoot);
|
|
41205
41380
|
assertSameTree(initialTree.state, finalTree.state, tracked.paths());
|
|
41206
|
-
const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, skills: uniqueSkills };
|
|
41381
|
+
const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, hookParents, skills: uniqueSkills };
|
|
41207
41382
|
return { ...completeProjection, sha256: hash2(completeProjection) };
|
|
41208
41383
|
} catch (error) {
|
|
41209
41384
|
if (error instanceof Error && error.message.startsWith("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED"))
|
|
@@ -41219,6 +41394,7 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
|
|
|
41219
41394
|
cacheRoot: previous.cacheRoot,
|
|
41220
41395
|
controls: previous.controls,
|
|
41221
41396
|
appOnlyParents: previous.appOnlyParents,
|
|
41397
|
+
...previous.hookParents === undefined ? {} : { hookParents: previous.hookParents },
|
|
41222
41398
|
skills: previous.skills
|
|
41223
41399
|
};
|
|
41224
41400
|
const currentProjection = {
|
|
@@ -41226,9 +41402,11 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
|
|
|
41226
41402
|
cacheRoot: current.cacheRoot,
|
|
41227
41403
|
controls: current.controls,
|
|
41228
41404
|
appOnlyParents: current.appOnlyParents,
|
|
41405
|
+
...current.hookParents === undefined ? {} : { hookParents: current.hookParents },
|
|
41229
41406
|
skills: current.skills
|
|
41230
41407
|
};
|
|
41231
|
-
|
|
41408
|
+
const comparable = (projection) => ({ ...projection, hookParents: projection.hookParents ?? [] });
|
|
41409
|
+
if (hash2(priorProjection) !== previous.sha256 || hash2(currentProjection) !== current.sha256 || canonical4(comparable(priorProjection)) !== canonical4(comparable(currentProjection)))
|
|
41232
41410
|
refuse5();
|
|
41233
41411
|
}
|
|
41234
41412
|
|
|
@@ -41257,7 +41435,7 @@ var NATIVE_SKILL_ROOTS = [
|
|
|
41257
41435
|
import { createHash as createHash28, randomUUID as randomUUID4 } from "crypto";
|
|
41258
41436
|
import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
|
|
41259
41437
|
import { existsSync as existsSync7, lstatSync as lstatSync26, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync18, readdirSync as readdirSync9, opendirSync as opendirSync5, readlinkSync as readlinkSync7, realpathSync as realpathSync13, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync5, unlinkSync as unlinkSync5, chmodSync, openSync as openSync21, closeSync as closeSync21, fsyncSync as fsyncSync7, fstatSync as fstatSync21, readSync as readSync14, constants as constants19, linkSync as linkSync3 } from "fs";
|
|
41260
|
-
import { dirname as dirname21, join as join30, resolve as resolve23, relative as relative8, isAbsolute as isAbsolute25, sep as sep10 } from "path";
|
|
41438
|
+
import { basename as basename11, dirname as dirname21, join as join30, resolve as resolve23, relative as relative8, isAbsolute as isAbsolute25, sep as sep10 } from "path";
|
|
41261
41439
|
import { homedir as homedir3 } from "os";
|
|
41262
41440
|
|
|
41263
41441
|
// src/lib/managed-policy.ts
|
|
@@ -41265,11 +41443,11 @@ import { closeSync as closeSync13, constants as constants10, fstatSync as fstatS
|
|
|
41265
41443
|
import { join as join17 } from "path";
|
|
41266
41444
|
|
|
41267
41445
|
// src/lib/agent-policy-limits.ts
|
|
41268
|
-
import { basename as
|
|
41446
|
+
import { basename as basename7, isAbsolute as isAbsolute10, join as join16, resolve as resolve10, sep as sep6 } from "path";
|
|
41269
41447
|
|
|
41270
41448
|
// src/lib/claude-marketplace-entry-witness.ts
|
|
41271
41449
|
import { createHash as createHash14 } from "crypto";
|
|
41272
|
-
import { basename as
|
|
41450
|
+
import { basename as basename6, dirname as dirname10, isAbsolute as isAbsolute9, resolve as resolve9 } from "path";
|
|
41273
41451
|
var CLAUDE_MARKETPLACE_ENTRY_HASH_MODE = "claude-marketplace-entry-v1";
|
|
41274
41452
|
var DOMAIN = "hasna.skills.claude-marketplace-entry.v1\x00";
|
|
41275
41453
|
var PATH_CHARACTERS = 4096;
|
|
@@ -41334,7 +41512,7 @@ var stringArray = (value) => value?.kind === "array" && value.items.every(isStri
|
|
|
41334
41512
|
var stringObject = (value) => value?.kind === "object" && value.entries.every(([, item]) => isString(item));
|
|
41335
41513
|
function claudeMarketplaceEntrySourceValid(source) {
|
|
41336
41514
|
const path = source?.path;
|
|
41337
|
-
return typeof path === "string" && path.length > 0 && path.length <= PATH_CHARACTERS && !/[\x00-\x1f\x7f]/.test(path) && isAbsolute9(path) && resolve9(path) === path &&
|
|
41515
|
+
return typeof path === "string" && path.length > 0 && path.length <= PATH_CHARACTERS && !/[\x00-\x1f\x7f]/.test(path) && isAbsolute9(path) && resolve9(path) === path && basename6(path) === "marketplace.json" && basename6(dirname10(path)) === ".claude-plugin" && typeof source.marketplace === "string" && NAME.test(source.marketplace) && !source.marketplace.includes("..") && typeof source.plugin === "string" && NAME.test(source.plugin);
|
|
41338
41516
|
}
|
|
41339
41517
|
function canonical5(value) {
|
|
41340
41518
|
if (value.kind === "string")
|
|
@@ -41604,10 +41782,10 @@ function assertAgentPolicyCollections(policy) {
|
|
|
41604
41782
|
}
|
|
41605
41783
|
}
|
|
41606
41784
|
if (value.codexSemanticCache !== undefined) {
|
|
41607
|
-
const proof = record3(value.codexSemanticCache,
|
|
41608
|
-
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && Object.keys(proof).length
|
|
41785
|
+
const proof = record3(value.codexSemanticCache, 9), witness = record3(proof.witness, 7);
|
|
41786
|
+
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));
|
|
41609
41787
|
text(proof.configPath);
|
|
41610
|
-
requireBound(isAbsolute10(proof.configPath) && resolve10(proof.configPath) === proof.configPath &&
|
|
41788
|
+
requireBound(isAbsolute10(proof.configPath) && resolve10(proof.configPath) === proof.configPath && basename7(proof.configPath) === "config.toml");
|
|
41611
41789
|
text(witness.cacheRoot);
|
|
41612
41790
|
requireBound(isAbsolute10(witness.cacheRoot) && resolve10(witness.cacheRoot) === witness.cacheRoot);
|
|
41613
41791
|
if (proof.hookRootAlias !== null) {
|
|
@@ -41624,6 +41802,20 @@ function assertAgentPolicyCollections(policy) {
|
|
|
41624
41802
|
text(parent[key]);
|
|
41625
41803
|
requireBound(isAbsolute10(parent.pluginParent) && resolve10(parent.pluginParent) === parent.pluginParent);
|
|
41626
41804
|
}
|
|
41805
|
+
if (proof.reviewedHookParents !== undefined)
|
|
41806
|
+
for (const parent of array(proof.reviewedHookParents, 4096)) {
|
|
41807
|
+
requireBound(object4(parent) && parent.role === "reviewed-hook" && (parent.installation === "remote-receipt" && Object.keys(parent).length === 6 || parent.installation === "local-marketplace" && Object.keys(parent).length === 7));
|
|
41808
|
+
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");
|
|
41809
|
+
for (const key of ["pluginId", "namespace", "pluginParent", "installation"])
|
|
41810
|
+
text(parent[key]);
|
|
41811
|
+
if (parent.installation === "remote-receipt")
|
|
41812
|
+
text(parent.remotePluginId);
|
|
41813
|
+
else {
|
|
41814
|
+
text(parent.marketplaceSourcePath);
|
|
41815
|
+
requireBound(typeof parent.marketplaceSha256 === "string" && /^[a-f0-9]{64}$/.test(parent.marketplaceSha256) && isAbsolute10(parent.marketplaceSourcePath) && resolve10(parent.marketplaceSourcePath) === parent.marketplaceSourcePath && basename7(parent.marketplaceSourcePath) === "marketplace.json");
|
|
41816
|
+
}
|
|
41817
|
+
requireBound(isAbsolute10(parent.pluginParent) && resolve10(parent.pluginParent) === parent.pluginParent);
|
|
41818
|
+
}
|
|
41627
41819
|
for (const row of [...array(witness.controls, 4096), ...array(witness.appOnlyParents, 4096)]) {
|
|
41628
41820
|
requireBound(object4(row));
|
|
41629
41821
|
for (const key of ["pluginId", "namespace", "pluginParent"])
|
|
@@ -41632,6 +41824,26 @@ function assertAgentPolicyCollections(policy) {
|
|
|
41632
41824
|
if (row[key] !== undefined)
|
|
41633
41825
|
requireBound(typeof row[key] === "string" && /^[a-f0-9]{64}$/.test(row[key]));
|
|
41634
41826
|
}
|
|
41827
|
+
if (witness.hookParents !== undefined)
|
|
41828
|
+
for (const row of array(witness.hookParents, 4096)) {
|
|
41829
|
+
requireBound(object4(row) && row.role === "reviewed-hook" && (row.installation === "remote-receipt" && Object.keys(row).length === 9 || row.installation === "local-marketplace" && Object.keys(row).length === 9));
|
|
41830
|
+
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");
|
|
41831
|
+
for (const key of ["pluginId", "namespace", "pluginParent", "installation"])
|
|
41832
|
+
text(row[key]);
|
|
41833
|
+
if (row.installation === "remote-receipt")
|
|
41834
|
+
text(row.remotePluginId);
|
|
41835
|
+
else {
|
|
41836
|
+
text(row.marketplaceSourcePath);
|
|
41837
|
+
requireBound(typeof row.marketplaceSha256 === "string" && /^[a-f0-9]{64}$/.test(row.marketplaceSha256) && isAbsolute10(row.marketplaceSourcePath) && resolve10(row.marketplaceSourcePath) === row.marketplaceSourcePath && basename7(row.marketplaceSourcePath) === "marketplace.json");
|
|
41838
|
+
}
|
|
41839
|
+
requireBound(isAbsolute10(row.pluginParent) && resolve10(row.pluginParent) === row.pluginParent);
|
|
41840
|
+
for (const key of ["manifestSha256", "hooksSha256"])
|
|
41841
|
+
requireBound(typeof row[key] === "string" && /^[a-f0-9]{64}$/.test(row[key]));
|
|
41842
|
+
if (row.installation === "remote-receipt")
|
|
41843
|
+
requireBound(typeof row.receiptSha256 === "string" && /^[a-f0-9]{64}$/.test(row.receiptSha256));
|
|
41844
|
+
else
|
|
41845
|
+
requireBound(row.receiptSha256 === undefined);
|
|
41846
|
+
}
|
|
41635
41847
|
for (const skill of array(witness.skills, 4096)) {
|
|
41636
41848
|
requireBound(object4(skill));
|
|
41637
41849
|
for (const key of ["name", "pluginId", "namespace", "pluginParent"])
|
|
@@ -41661,13 +41873,13 @@ function assertAgentPolicyCollections(policy) {
|
|
|
41661
41873
|
if (source.hashMode === "claude-plugin-manifest-v1")
|
|
41662
41874
|
requireBound(agent === "claude" && value.agent === "claude" && ["automatic", "reviewed"].includes(value.method) && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && source.path.endsWith(join16(sep6, ".claude-plugin", "plugin.json")) && source.managedPlugins === undefined);
|
|
41663
41875
|
if (source.hashMode === "sumi-settings-v1")
|
|
41664
|
-
requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path &&
|
|
41876
|
+
requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename7(source.path) === "sumi.json");
|
|
41665
41877
|
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"))
|
|
41666
|
-
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path &&
|
|
41878
|
+
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename7(source.path) === "config.toml");
|
|
41667
41879
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4"))
|
|
41668
|
-
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path &&
|
|
41880
|
+
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename7(source.path) === "settings.json");
|
|
41669
41881
|
if (source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2")
|
|
41670
|
-
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path &&
|
|
41882
|
+
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute10(source.path) && resolve10(source.path) === source.path && basename7(source.path) === "known_marketplaces.json");
|
|
41671
41883
|
if (source.hashMode === "claude-marketplace-entry-v1")
|
|
41672
41884
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && claudeMarketplaceEntrySourceValid(source));
|
|
41673
41885
|
if (source.hashMode === "claude-plugin-registry") {
|
|
@@ -41832,7 +42044,7 @@ function isOwnedCliBridge(path, expectedPaths) {
|
|
|
41832
42044
|
// src/lib/agent-discovery.ts
|
|
41833
42045
|
import { createHash as createHash26 } from "crypto";
|
|
41834
42046
|
import { lstatSync as lstatSync24, readFileSync as readFileSync16, readdirSync as readdirSync8, realpathSync as realpathSync11 } from "fs";
|
|
41835
|
-
import { basename as
|
|
42047
|
+
import { basename as basename10, dirname as dirname20, isAbsolute as isAbsolute23, join as join29, relative as relative7, resolve as resolve22, sep as sep9 } from "path";
|
|
41836
42048
|
import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
|
|
41837
42049
|
|
|
41838
42050
|
// node_modules/yaml/dist/index.js
|
|
@@ -42523,7 +42735,7 @@ function projectReviewedClaudePluginManifest(text2, reviewedSha256) {
|
|
|
42523
42735
|
|
|
42524
42736
|
// src/lib/plugin-discovery.ts
|
|
42525
42737
|
import { closeSync as closeSync16, constants as constants13, fstatSync as fstatSync16, lstatSync as lstatSync19, openSync as openSync16, opendirSync as opendirSync4, readSync as readSync10 } from "fs";
|
|
42526
|
-
import { basename as
|
|
42738
|
+
import { basename as basename8, dirname as dirname16, isAbsolute as isAbsolute18, join as join26, resolve as resolve17 } from "path";
|
|
42527
42739
|
|
|
42528
42740
|
// src/lib/plugin-admission.ts
|
|
42529
42741
|
import { homedir as homedir2 } from "os";
|
|
@@ -44004,7 +44216,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
44004
44216
|
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join26(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
44005
44217
|
const approval = (producer) => {
|
|
44006
44218
|
pluginText(producer);
|
|
44007
|
-
const digest3 = `sha256:${
|
|
44219
|
+
const digest3 = `sha256:${basename8(producer)}`;
|
|
44008
44220
|
const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest3);
|
|
44009
44221
|
pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
|
|
44010
44222
|
if (!verified.has(producer)) {
|
|
@@ -44068,7 +44280,7 @@ function captureManagedPluginRegistry(path, managedPlugins) {
|
|
|
44068
44280
|
// src/lib/claude-marketplace-registry.ts
|
|
44069
44281
|
import { createHash as createHash22 } from "crypto";
|
|
44070
44282
|
import { closeSync as closeSync17, constants as constants14, fstatSync as fstatSync17, lstatSync as lstatSync20, openSync as openSync17, readSync as readSync11 } from "fs";
|
|
44071
|
-
import { basename as
|
|
44283
|
+
import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute19, resolve as resolve18 } from "path";
|
|
44072
44284
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
44073
44285
|
function need6(value, reason2) {
|
|
44074
44286
|
if (!value)
|
|
@@ -44090,7 +44302,7 @@ function parents2(path) {
|
|
|
44090
44302
|
}
|
|
44091
44303
|
function readRegistry2(path, budget2) {
|
|
44092
44304
|
absolutePath3(path);
|
|
44093
|
-
need6(
|
|
44305
|
+
need6(basename9(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
44094
44306
|
need6(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
44095
44307
|
const ancestors2 = parents2(path), initial = lstatSync20(path, { bigint: true });
|
|
44096
44308
|
need6(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
@@ -44349,6 +44561,78 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
44349
44561
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
44350
44562
|
import { accessSync as accessSync2, constants as constants16, existsSync as existsSync6, lstatSync as lstatSync22, realpathSync as realpathSync10, statSync as statSync7 } from "fs";
|
|
44351
44563
|
import { delimiter as delimiter2, isAbsolute as isAbsolute21, join as join27, resolve as resolve20 } from "path";
|
|
44564
|
+
|
|
44565
|
+
// src/lib/hook-diagnostics.ts
|
|
44566
|
+
var CONTEXT_ERROR_CODES = new Set([
|
|
44567
|
+
"SKILLS_API_CREDENTIAL_UNAVAILABLE",
|
|
44568
|
+
"SKILLS_API_UNAVAILABLE",
|
|
44569
|
+
"SKILLS_API_UNAUTHORIZED",
|
|
44570
|
+
"SKILLS_API_FORBIDDEN",
|
|
44571
|
+
"SKILLS_API_RESOURCE_UNAVAILABLE",
|
|
44572
|
+
"SESSION_WRITE_BUSY",
|
|
44573
|
+
"SKILLS_CONTEXT_FAILED",
|
|
44574
|
+
"SKILLS_STORAGE_FULL",
|
|
44575
|
+
"PROFILE_LOCK_MISMATCH",
|
|
44576
|
+
"PROFILE_IDENTITY_MISMATCH",
|
|
44577
|
+
"PROFILE_APPLIED_REPORT_FAILED",
|
|
44578
|
+
"CACHED_AUTHORITY_REQUIRED",
|
|
44579
|
+
"CACHED_PROFILE_EXPIRED",
|
|
44580
|
+
"CACHED_PROFILE_MISSING",
|
|
44581
|
+
"CACHED_BUNDLE_MISSING",
|
|
44582
|
+
"INVALID_CONTEXT_INPUT",
|
|
44583
|
+
"CONTEXT_INPUT_TOO_LARGE",
|
|
44584
|
+
"INVALID_CONTEXT_BUDGET",
|
|
44585
|
+
"INVALID_SELECTION",
|
|
44586
|
+
"INVALID_SELECTION_ALIASES",
|
|
44587
|
+
"INVALID_RECEIPT",
|
|
44588
|
+
"INVALID_CACHE_FILE",
|
|
44589
|
+
"UNSAFE_CACHE_PATH",
|
|
44590
|
+
"RECEIPT_TOO_LARGE",
|
|
44591
|
+
"BUNDLE_DIGEST_MISMATCH",
|
|
44592
|
+
"BUNDLE_IDENTITY_MISMATCH",
|
|
44593
|
+
"BUNDLE_UNAVAILABLE",
|
|
44594
|
+
"BUNDLE_TOO_LARGE",
|
|
44595
|
+
"SKILL_NOT_SELECTED",
|
|
44596
|
+
"INVALID_SESSION",
|
|
44597
|
+
"SESSION_PARENT_NOT_FOUND",
|
|
44598
|
+
"SESSION_PARENT_MISMATCH",
|
|
44599
|
+
"SESSION_NOT_FOUND",
|
|
44600
|
+
"SESSION_GENERATION_CHANGED",
|
|
44601
|
+
"SESSION_GENERATION_EXHAUSTED",
|
|
44602
|
+
"SESSION_PARENT_CHANGED",
|
|
44603
|
+
"SESSION_RECEIPT_CHANGED",
|
|
44604
|
+
"SESSION_RECONCILIATION_REQUIRED",
|
|
44605
|
+
"SESSION_RENEWAL_TIMEOUT",
|
|
44606
|
+
"SESSION_CONTEXT_CONFLICT",
|
|
44607
|
+
"SESSION_RECONCILIATION_INCOMPLETE",
|
|
44608
|
+
"SESSION_WRITE_LOCKED",
|
|
44609
|
+
"SESSION_WRITE_LOCK_CHANGED",
|
|
44610
|
+
"SESSION_LOCK_RECOVERY_INCOMPLETE"
|
|
44611
|
+
]);
|
|
44612
|
+
var HOOK_REFUSAL_REASON_CODES = Object.freeze([
|
|
44613
|
+
...CONTEXT_ERROR_CODES,
|
|
44614
|
+
"SKILLS_HOOK_FAILED",
|
|
44615
|
+
"SKILLS_HOOK_TIMEOUT",
|
|
44616
|
+
"SKILLS_HOOK_INVALID_RESPONSE"
|
|
44617
|
+
]);
|
|
44618
|
+
var OPTIONAL_CONTEXT_FAILURES = new Set([
|
|
44619
|
+
"SKILLS_API_CREDENTIAL_UNAVAILABLE",
|
|
44620
|
+
"SKILLS_API_UNAVAILABLE",
|
|
44621
|
+
"SKILLS_API_UNAUTHORIZED",
|
|
44622
|
+
"SKILLS_API_FORBIDDEN",
|
|
44623
|
+
"SKILLS_API_RESOURCE_UNAVAILABLE",
|
|
44624
|
+
"CACHED_PROFILE_EXPIRED",
|
|
44625
|
+
"CACHED_PROFILE_MISSING",
|
|
44626
|
+
"CACHED_BUNDLE_MISSING",
|
|
44627
|
+
"SESSION_RECONCILIATION_REQUIRED",
|
|
44628
|
+
"SESSION_RENEWAL_TIMEOUT",
|
|
44629
|
+
"SESSION_WRITE_BUSY",
|
|
44630
|
+
"SESSION_PARENT_CHANGED",
|
|
44631
|
+
"SESSION_CONTEXT_CONFLICT",
|
|
44632
|
+
"SKILLS_HOOK_TIMEOUT"
|
|
44633
|
+
]);
|
|
44634
|
+
|
|
44635
|
+
// src/lib/agent-sumi.ts
|
|
44352
44636
|
var SUMI_PATH_SELECTORS = ["SUMI_HOME", "SUMI_CONFIG_DIR", "XDG_DATA_HOME", "XDG_CACHE_HOME", "XDG_CONFIG_HOME", "XDG_STATE_HOME"];
|
|
44353
44637
|
var SUMI_PATH_KEYS = ["data", "cache", "config", "state"];
|
|
44354
44638
|
var SUMI_PATH_OUTPUT_LIMIT = 128 * 1024;
|
|
@@ -44490,24 +44774,33 @@ function sumiConfigPath(home, cwd = process.cwd(), env = process.env) {
|
|
|
44490
44774
|
return join27(sumiConfigDirectory(home, env, cwd), "sumi.json");
|
|
44491
44775
|
}
|
|
44492
44776
|
function renderSumiPlugin(command, profile) {
|
|
44493
|
-
return renderSumiPluginVersion(command, profile,
|
|
44777
|
+
return renderSumiPluginVersion(command, profile, 3);
|
|
44494
44778
|
}
|
|
44495
44779
|
function isManagedSumiPlugin(text2, command, profile) {
|
|
44496
|
-
return text2 === renderSumiPlugin(command, profile) || text2 === renderSumiPluginVersion(command, profile,
|
|
44780
|
+
return text2 === renderSumiPlugin(command, profile) || text2 === renderSumiPluginVersion(command, profile, 2) || text2 === renderSumiPluginVersion(command, profile, 1);
|
|
44497
44781
|
}
|
|
44498
|
-
function renderSumiPluginVersion(command, profile,
|
|
44782
|
+
function renderSumiPluginVersion(command, profile, version2) {
|
|
44783
|
+
const legacy = version2 === 1;
|
|
44499
44784
|
const failure = (message) => legacy ? `new Error(${JSON.stringify(message)})` : "refusal()";
|
|
44500
44785
|
return `// Managed by @hasna/skills. Regenerate with skills hook install --agent sumi.
|
|
44501
44786
|
import { spawn } from "node:child_process";
|
|
44502
44787
|
const command = ${JSON.stringify(command)};
|
|
44503
44788
|
const profile = ${JSON.stringify(profile)};
|
|
44504
|
-
${legacy ? "" : `function refusal() {
|
|
44505
|
-
const error = new Error("Skills verification blocked this request. Review the Sumi Skills hook configuration, then retry.");
|
|
44789
|
+
${legacy ? "" : `function refusal(${version2 === 3 ? "reasonCode" : ""}) {
|
|
44790
|
+
const error = new Error("Skills verification blocked this request. Review the Sumi Skills hook configuration, then retry."${version2 === 3 ? ' + (reasonCode ? " [" + reasonCode + "]" : "")' : ""});
|
|
44506
44791
|
error.name = "SkillsHookRefusal";
|
|
44507
|
-
error.skillsHookRefusal = { version: 1, code: "SKILLS_HOOK_REFUSED" };
|
|
44792
|
+
error.skillsHookRefusal = { version: 1, code: "SKILLS_HOOK_REFUSED"${version2 === 3 ? ", ...(reasonCode ? { reasonCode } : {})" : ""} };
|
|
44508
44793
|
return error;
|
|
44509
44794
|
}
|
|
44510
|
-
`}
|
|
44795
|
+
`}${version2 === 3 ? `const reasonCodes = new Set(${JSON.stringify(HOOK_REFUSAL_REASON_CODES)});
|
|
44796
|
+
function refusedResult(result) {
|
|
44797
|
+
const reason = result.reason ?? result.stopReason ?? result.systemMessage;
|
|
44798
|
+
if (typeof reason !== "string" || reason.length > 16384) return refusal();
|
|
44799
|
+
if (reason.startsWith("NATIVE_SKILL_DRIFT:")) return refusal("NATIVE_SKILL_DRIFT");
|
|
44800
|
+
const code = /^Skills context is unavailable \\[([A-Z_]+)\\]/.exec(reason)?.[1];
|
|
44801
|
+
return refusal(reasonCodes.has(code) ? code : undefined);
|
|
44802
|
+
}
|
|
44803
|
+
` : ""}function context(input) {
|
|
44511
44804
|
return new Promise((resolve, reject) => {
|
|
44512
44805
|
const child = spawn(command, ["hook", "user-prompt", "--agent", "sumi", "--selection-profile", profile], { cwd: input.cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
44513
44806
|
const chunks = []; let bytes = 0, failure;
|
|
@@ -44522,12 +44815,12 @@ ${legacy ? "" : `function refusal() {
|
|
|
44522
44815
|
try {
|
|
44523
44816
|
const result = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
44524
44817
|
if (!result || typeof result !== "object" || Array.isArray(result)) throw ${failure("Invalid Skills hook response")};
|
|
44525
|
-
if (result.decision === "block" || result.continue === false) throw ${failure("Skills prompt hook refused")};
|
|
44818
|
+
if (result.decision === "block" || result.continue === false) throw ${version2 === 3 ? "refusedResult(result)" : failure("Skills prompt hook refused")};
|
|
44526
44819
|
if (Object.keys(result).length && (!result.hookSpecificOutput || result.hookSpecificOutput.hookEventName !== input.hook_event_name)) throw ${failure("Invalid Skills hook response")};
|
|
44527
44820
|
const text = result.hookSpecificOutput?.additionalContext ?? "";
|
|
44528
44821
|
if (typeof text !== "string") throw ${failure("Invalid Skills prompt context")};
|
|
44529
44822
|
resolve(text);
|
|
44530
|
-
} catch (error) { reject(${legacy ? "error" : "refusal()"}); }
|
|
44823
|
+
} catch (error) { reject(${legacy ? "error" : version2 === 3 ? 'error instanceof Error && error.name === "SkillsHookRefusal" ? error : refusal()' : "refusal()"}); }
|
|
44531
44824
|
});
|
|
44532
44825
|
child.stdin.end(JSON.stringify(input));
|
|
44533
44826
|
});
|
|
@@ -44560,9 +44853,13 @@ export default {
|
|
|
44560
44853
|
sessions.add(event.sessionID);
|
|
44561
44854
|
}));
|
|
44562
44855
|
registrations.push(await ctx.session.hook("context", async event => {
|
|
44563
|
-
|
|
44856
|
+
${version2 === 3 ? ` // Model messages also contain checkpoints, attachments and synthetic
|
|
44857
|
+
// user-role history, with no owner-prompt provenance. Prompt admission
|
|
44858
|
+
// already matched and persisted Skills; restore that verified state only.
|
|
44859
|
+
const prompt = "";
|
|
44860
|
+
` : ` const last = event.messages.findLast(message => message.role === "user");
|
|
44564
44861
|
const prompt = (last?.content ?? []).filter(part => part.type === "text").map(part => part.text).join("\\n");
|
|
44565
|
-
// Recheck on every primary request, including resumed and synthetic
|
|
44862
|
+
`} // Recheck on every primary request, including resumed and synthetic
|
|
44566
44863
|
// sessions. The CLI owns optional failures versus explicit refusals.
|
|
44567
44864
|
const text = await context(await input(event.sessionID, prompt, !sessions.has(event.sessionID)));
|
|
44568
44865
|
if (text) event.system.push({ type: "text", text });
|
|
@@ -44829,7 +45126,7 @@ function assertReviewedClaudeCacheClosures(home, config, review, canonical9) {
|
|
|
44829
45126
|
throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
|
|
44830
45127
|
}
|
|
44831
45128
|
if ([cacheAliasRoot, cacheRoot].some((root2) => row.installPath === root2 || row.installPath.startsWith(root2 + sep9))) {
|
|
44832
|
-
if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" ||
|
|
45129
|
+
if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename10(row.installPath) !== row.version)) {
|
|
44833
45130
|
throw new Error("Reviewed Claude discovery has a malformed active cache registration");
|
|
44834
45131
|
}
|
|
44835
45132
|
if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" && isAbsolute23(row.projectPath) && resolve22(row.projectPath) === row.projectPath && row.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters) {} else
|
|
@@ -45107,7 +45404,7 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
45107
45404
|
if (!targetValid || !targetScopes.has("user\x00"))
|
|
45108
45405
|
continue;
|
|
45109
45406
|
const active = rows[0]?.installPath;
|
|
45110
|
-
if (typeof active !== "string" || rows[0]?.version !==
|
|
45407
|
+
if (typeof active !== "string" || rows[0]?.version !== basename10(active) || dirname20(active) !== dirname20(root2) || active === root2 || !lstatSync24(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync11(active) !== active)
|
|
45111
45408
|
continue;
|
|
45112
45409
|
const activeManifest = full(join29(active, ".claude-plugin/plugin.json"));
|
|
45113
45410
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
@@ -45116,14 +45413,15 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
45116
45413
|
}
|
|
45117
45414
|
return [...result];
|
|
45118
45415
|
}
|
|
45119
|
-
function codexSemanticCacheSourceRole(source, cacheRoot, parents3) {
|
|
45416
|
+
function codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParents = []) {
|
|
45120
45417
|
if (!isAbsolute23(source.path) || resolve22(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")
|
|
45121
45418
|
return false;
|
|
45122
45419
|
const parts = relative7(cacheRoot, source.path).split(sep9);
|
|
45123
45420
|
if (parts.length < 3 || !parents3.includes(join29(cacheRoot, parts[0], parts[1])))
|
|
45124
45421
|
return false;
|
|
45125
45422
|
const tail = parts.slice(3).join("/");
|
|
45126
|
-
|
|
45423
|
+
const parent = join29(cacheRoot, parts[0], parts[1]);
|
|
45424
|
+
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");
|
|
45127
45425
|
}
|
|
45128
45426
|
function codexSemanticCacheDirectoryRole(path, cacheRoot) {
|
|
45129
45427
|
return isAbsolute23(path) && resolve22(path) === path && !/[\x00-\x1f\x7f]/.test(path) && (path === cacheRoot || path.startsWith(cacheRoot + sep9));
|
|
@@ -45155,20 +45453,28 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
|
|
|
45155
45453
|
const cacheRoot = proof.witness.cacheRoot;
|
|
45156
45454
|
if (controls.some((control) => dirname20(dirname20(control.pluginParent)) !== cacheRoot))
|
|
45157
45455
|
throw new Error("Codex semantic cache names another enrolled cache");
|
|
45158
|
-
const
|
|
45159
|
-
|
|
45456
|
+
const reviewedHookParents = proof.reviewedHookParents ?? [];
|
|
45457
|
+
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 || !isDeepStrictEqual6((proof.witness.hookParents ?? []).map(({ manifestSha256: _manifest, hooksSha256: _hooks, receiptSha256: _receipt, ...parent }) => parent), reviewedHookParents)) {
|
|
45458
|
+
throw new Error("Invalid reviewed native-hook cache role");
|
|
45459
|
+
}
|
|
45460
|
+
for (const parent of reviewedHookParents)
|
|
45461
|
+
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")))
|
|
45462
|
+
throw new Error("Local marketplace hook parent lost its enrolled source witness");
|
|
45463
|
+
const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...proof.appOnlyParents.map((parent) => parent.pluginParent), ...reviewedHookParents.map((parent) => parent.pluginParent)])];
|
|
45464
|
+
const hookParentPaths = reviewedHookParents.map((parent) => parent.pluginParent);
|
|
45465
|
+
const sources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParentPaths));
|
|
45160
45466
|
const directories = (binding.directories ?? []).filter((directory) => codexSemanticCacheDirectoryRole(directory.path, cacheRoot));
|
|
45161
45467
|
if (!directories.length || !isDeepStrictEqual6(sources, proof.supersededSources) || !isDeepStrictEqual6(directories, proof.supersededDirectories))
|
|
45162
45468
|
throw new Error("Codex semantic cache provenance changed");
|
|
45163
45469
|
const configPath = proof.configPath;
|
|
45164
|
-
if (!isAbsolute23(configPath) || resolve22(configPath) !== configPath ||
|
|
45470
|
+
if (!isAbsolute23(configPath) || resolve22(configPath) !== configPath || basename10(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
|
|
45165
45471
|
throw new Error("Invalid semantic cache configuration source");
|
|
45166
45472
|
const configSource = binding.sources.find((source) => source.path === configPath && source.sha256 !== null && source.format === undefined && source.fields === undefined);
|
|
45167
45473
|
if (!configSource || projected(configSource) !== configSource.sha256)
|
|
45168
45474
|
throw new Error("Codex semantic cache requires unchanged reviewed configuration");
|
|
45169
45475
|
assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, proof.hookRootAlias);
|
|
45170
45476
|
const rules = parseConfig(read2(configPath), configPath, true).skills?.config ?? [];
|
|
45171
|
-
const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, rules });
|
|
45477
|
+
const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, reviewedHookParents, rules });
|
|
45172
45478
|
assertCodexSemanticCacheWitnessUnchanged(proof.witness, current);
|
|
45173
45479
|
return proof;
|
|
45174
45480
|
}
|
|
@@ -45252,7 +45558,7 @@ function codexInstallationRoots(binding) {
|
|
|
45252
45558
|
const config = join29(dirname20(dirname20(cache)), "config.toml"), home = dirname20(dirname20(dirname20(cache)));
|
|
45253
45559
|
const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
45254
45560
|
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join29(home, path));
|
|
45255
|
-
if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep9) || input.sourceRoot.startsWith(root2 + sep9)) || binding.sources.some((source) =>
|
|
45561
|
+
if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep9) || input.sourceRoot.startsWith(root2 + sep9)) || binding.sources.some((source) => basename10(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep9)))))
|
|
45256
45562
|
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
45257
45563
|
if (proof.plugins.some((input) => dirname20(dirname20(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join29(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
45258
45564
|
throw new Error("Missing native installation input source witness");
|
|
@@ -45264,13 +45570,13 @@ function codexInstallationRoots(binding) {
|
|
|
45264
45570
|
});
|
|
45265
45571
|
}
|
|
45266
45572
|
function assertMarketplaceBinding(binding, source) {
|
|
45267
|
-
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" ||
|
|
45573
|
+
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename10(source.path) !== "plugin.json" || !source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json"))))
|
|
45268
45574
|
throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
|
|
45269
|
-
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" ||
|
|
45575
|
+
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename10(source.path) !== "sumi.json"))
|
|
45270
45576
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
45271
|
-
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" ||
|
|
45577
|
+
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" || basename10(source.path) !== "config.toml"))
|
|
45272
45578
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
45273
|
-
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" ||
|
|
45579
|
+
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) && (binding.agent !== "claude" || binding.method !== "reviewed" || basename10(source.path) !== "settings.json"))
|
|
45274
45580
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
45275
45581
|
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
45276
45582
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
@@ -45388,7 +45694,7 @@ function verifyAutomaticDiscoveryClosure(binding, options) {
|
|
|
45388
45694
|
const current = resolveAgentDiscovery({ home: options.home, agent: binding.agent, canonical: options.canonical, executable: runtime });
|
|
45389
45695
|
if (JSON.stringify(current) === JSON.stringify(binding))
|
|
45390
45696
|
return;
|
|
45391
|
-
const reviewedWithRuntime = (binding.builtinNames?.length ?? 0) > 0 || binding.sources.some((source) =>
|
|
45697
|
+
const reviewedWithRuntime = (binding.builtinNames?.length ?? 0) > 0 || binding.sources.some((source) => basename10(source.path) === "package.json");
|
|
45392
45698
|
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) => isDeepStrictEqual6(saved, source)));
|
|
45393
45699
|
if (command && gap && runtime === null && reviewedWithRuntime && otherwiseCurrent)
|
|
45394
45700
|
throw discoveryRootUnresolved(binding.agent, command, gap);
|
|
@@ -45531,7 +45837,7 @@ function resolveAgentDiscovery(options) {
|
|
|
45531
45837
|
throw new Error("Discovery review must include the agent configuration source");
|
|
45532
45838
|
const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical9(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical9(configPath), source)) : sources;
|
|
45533
45839
|
const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
|
|
45534
|
-
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" ||
|
|
45840
|
+
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename10(source.path) !== "plugin.json" || !source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json")))
|
|
45535
45841
|
return source;
|
|
45536
45842
|
const pluginRoot = dirname20(dirname20(source.path)), hooksPath = join29(pluginRoot, "hooks/hooks.json");
|
|
45537
45843
|
const hookStat = lstatSync24(hooksPath, { throwIfNoEntry: false });
|
|
@@ -47439,7 +47745,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
47439
47745
|
return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join30(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join30(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 })) } };
|
|
47440
47746
|
}
|
|
47441
47747
|
function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
47442
|
-
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)
|
|
47748
|
+
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))
|
|
47443
47749
|
throw new Error("Invalid Codex semantic cache upgrade request");
|
|
47444
47750
|
const home = resolve23(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
47445
47751
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
@@ -47463,14 +47769,23 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
47463
47769
|
throw new Error("Native settings preimage changed");
|
|
47464
47770
|
const boundedRead = (path) => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024));
|
|
47465
47771
|
const unchangedFullSource = (path) => {
|
|
47466
|
-
const
|
|
47467
|
-
if (
|
|
47468
|
-
throw new Error("Cache upgrade
|
|
47772
|
+
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"));
|
|
47773
|
+
if (sources.length !== 1)
|
|
47774
|
+
throw new Error("Cache upgrade requires one unambiguous prior full identity source");
|
|
47775
|
+
const source = sources[0];
|
|
47469
47776
|
const text2 = boundedRead(path);
|
|
47470
47777
|
if (sha5(text2) !== source.sha256)
|
|
47471
47778
|
throw new Error("Reviewed cache identity source changed");
|
|
47472
47779
|
return text2;
|
|
47473
47780
|
};
|
|
47781
|
+
const unchangedReviewedHookSource = (path) => {
|
|
47782
|
+
const sources = binding.sources.filter((source) => source.path === path);
|
|
47783
|
+
if (!sources.length)
|
|
47784
|
+
throw new Error("Cache upgrade lacks prior full identity source");
|
|
47785
|
+
if (sources.length !== 1)
|
|
47786
|
+
throw new Error("Reviewed hook identity source is ambiguous");
|
|
47787
|
+
return unchangedFullSource(path);
|
|
47788
|
+
};
|
|
47474
47789
|
const appOnlyParents = options.appOnlyParents.map((parent) => {
|
|
47475
47790
|
const parts = relative8(cacheRoot, parent).split(sep10);
|
|
47476
47791
|
if (!isAbsolute25(parent) || resolve23(parent) !== parent || parts.length !== 2 || parts.some((part) => !/^[A-Za-z0-9_-]{1,64}$/.test(part)) || controls.some((control) => control.pluginParent === parent))
|
|
@@ -47485,11 +47800,60 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
47485
47800
|
unchangedFullSource(source.path);
|
|
47486
47801
|
return { role: "app-only", pluginId: `${parts[1]}@${parts[0]}`, namespace: parts[1], pluginParent: parent, remotePluginId: receipt.remote_plugin_id };
|
|
47487
47802
|
}).sort((a, b) => a.pluginParent.localeCompare(b.pluginParent));
|
|
47488
|
-
const
|
|
47803
|
+
const reviewedHookParents = (options.reviewedHookParents ?? []).map((parent) => {
|
|
47804
|
+
const parts = relative8(cacheRoot, parent).split(sep10);
|
|
47805
|
+
if (!isAbsolute25(parent) || resolve23(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))
|
|
47806
|
+
throw new Error("Unsupported reviewed native-hook parent role");
|
|
47807
|
+
const receiptPath = join30(parent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync26(receiptPath, { throwIfNoEntry: false });
|
|
47808
|
+
let identity5;
|
|
47809
|
+
if (receiptStat) {
|
|
47810
|
+
if (!receiptStat.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > 16 * 1024)
|
|
47811
|
+
throw new Error("Invalid reviewed native-hook install receipt");
|
|
47812
|
+
const receiptText = unchangedReviewedHookSource(receiptPath);
|
|
47813
|
+
let receipt;
|
|
47814
|
+
try {
|
|
47815
|
+
hashNativeJsonControls(receiptText);
|
|
47816
|
+
receipt = JSON.parse(receiptText);
|
|
47817
|
+
} catch {
|
|
47818
|
+
throw new Error("Invalid reviewed native-hook install receipt");
|
|
47819
|
+
}
|
|
47820
|
+
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))
|
|
47821
|
+
throw new Error("Invalid reviewed native-hook install receipt");
|
|
47822
|
+
identity5 = { role: "reviewed-hook", pluginId: `${parts[1]}@${parts[0]}`, namespace: parts[1], pluginParent: parent, installation: "remote-receipt", remotePluginId: receipt.remote_plugin_id };
|
|
47823
|
+
} else {
|
|
47824
|
+
const pluginId2 = `${parts[1]}@${parts[0]}`;
|
|
47825
|
+
const marketplaceSources = binding.sources.filter((source2) => basename11(source2.path) === "marketplace.json" && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && source2.reviewArtifact === undefined && (source2.hashMode === undefined || source2.hashMode === "bytes"));
|
|
47826
|
+
const matches = marketplaceSources.flatMap((source2) => {
|
|
47827
|
+
const text2 = unchangedFullSource(source2.path);
|
|
47828
|
+
return codexLocalMarketplaceMapsPlugin(text2, parts[0], parts[1]) ? [{ source: source2, text: text2 }] : [];
|
|
47829
|
+
});
|
|
47830
|
+
if (matches.length !== 1)
|
|
47831
|
+
throw new Error("Local marketplace hook parent lacks one exact enrolled marketplace source");
|
|
47832
|
+
const { source } = matches[0];
|
|
47833
|
+
const config = Bun.TOML.parse(settings);
|
|
47834
|
+
if (config.plugins?.[pluginId2]?.enabled !== true)
|
|
47835
|
+
throw new Error("Local marketplace hook parent is not enabled in the unchanged Codex settings");
|
|
47836
|
+
identity5 = { role: "reviewed-hook", pluginId: pluginId2, namespace: parts[1], pluginParent: parent, installation: "local-marketplace", marketplaceSourcePath: source.path, marketplaceSha256: source.sha256 };
|
|
47837
|
+
}
|
|
47838
|
+
const versions = readdirSync9(parent).filter((name) => name !== ".codex-remote-plugin-install.json");
|
|
47839
|
+
if (!versions.length || versions.length > 4096)
|
|
47840
|
+
throw new Error("Reviewed native-hook parent has no bounded materializations");
|
|
47841
|
+
for (const version2 of versions) {
|
|
47842
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
|
|
47843
|
+
throw new Error("Invalid reviewed native-hook version identity");
|
|
47844
|
+
const root2 = join30(parent, version2), stat2 = lstatSync26(root2, { throwIfNoEntry: false });
|
|
47845
|
+
if (!stat2?.isDirectory() || stat2.isSymbolicLink() || realpathSync13(root2) !== root2)
|
|
47846
|
+
throw new Error("Invalid reviewed native-hook materialization");
|
|
47847
|
+
unchangedReviewedHookSource(join30(root2, ".codex-plugin/plugin.json"));
|
|
47848
|
+
unchangedReviewedHookSource(join30(root2, "hooks/hooks.json"));
|
|
47849
|
+
}
|
|
47850
|
+
return identity5;
|
|
47851
|
+
}).sort((a, b) => a.pluginParent.localeCompare(b.pluginParent));
|
|
47852
|
+
const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...appOnlyParents.map((parent) => parent.pluginParent), ...reviewedHookParents.map((parent) => parent.pluginParent)])];
|
|
47489
47853
|
const reviewedAlias = aliases.find((alias) => alias.agent === "codex");
|
|
47490
47854
|
const hookRootAlias = reviewedAlias ? { alias: reviewedAlias.alias, target: reviewedAlias.target } : null;
|
|
47491
47855
|
assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, hookRootAlias);
|
|
47492
|
-
const supersededSources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3));
|
|
47856
|
+
const supersededSources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3, reviewedHookParents.map((parent) => parent.pluginParent)));
|
|
47493
47857
|
for (const source of supersededSources)
|
|
47494
47858
|
if ([".app.json", ".mcp.json"].includes(source.path.split(sep10).at(-1)))
|
|
47495
47859
|
unchangedFullSource(source.path);
|
|
@@ -47497,7 +47861,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
47497
47861
|
if (!supersededDirectories.some((directory) => directory.path === cacheRoot) || (binding.directories ?? []).some((directory) => cacheRoot.startsWith(directory.path + sep10)))
|
|
47498
47862
|
throw new Error("Cache upgrade requires exact cache directory coverage without an unproved ancestor projection");
|
|
47499
47863
|
const rules = Bun.TOML.parse(settings).skills?.config ?? [];
|
|
47500
|
-
const witness = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents, rules, read: boundedRead });
|
|
47864
|
+
const witness = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents, reviewedHookParents, rules, read: boundedRead });
|
|
47501
47865
|
if (options.expectedCacheWitnessSha256 !== undefined && witness.sha256 !== options.expectedCacheWitnessSha256)
|
|
47502
47866
|
throw new Error("Reviewed semantic cache preimage changed");
|
|
47503
47867
|
const replacement = { ...binding, codexDisabledPluginSkills: controls, codexSemanticCache: {
|
|
@@ -47506,6 +47870,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
47506
47870
|
hookRootAlias,
|
|
47507
47871
|
witness,
|
|
47508
47872
|
appOnlyParents,
|
|
47873
|
+
reviewedHookParents,
|
|
47509
47874
|
previousPolicySha256: options.expectedPolicySha256,
|
|
47510
47875
|
supersededSources,
|
|
47511
47876
|
supersededDirectories
|
|
@@ -47524,7 +47889,7 @@ function planCodexSemanticCacheWitnessUpgrade(options) {
|
|
|
47524
47889
|
rootAliases: aliases,
|
|
47525
47890
|
managedAgentChecks: { home, agents: ["codex"] },
|
|
47526
47891
|
...policy.bridge.discoveryExecutables ? { discoveryExecutables: policy.bridge.discoveryExecutables } : {},
|
|
47527
|
-
cacheWitnessUpgrade: { ...options, home, dataDir: dataDir2, appOnlyParents: appOnlyParents.map((parent) => parent.pluginParent) }
|
|
47892
|
+
cacheWitnessUpgrade: { ...options, home, dataDir: dataDir2, appOnlyParents: appOnlyParents.map((parent) => parent.pluginParent), reviewedHookParents: reviewedHookParents.map((parent) => parent.pluginParent) }
|
|
47528
47893
|
};
|
|
47529
47894
|
}
|
|
47530
47895
|
function planReviewedArtifactMigration(options) {
|
|
@@ -48063,7 +48428,7 @@ import {
|
|
|
48063
48428
|
statSync as statSync11,
|
|
48064
48429
|
writeFileSync as writeFileSync7
|
|
48065
48430
|
} from "fs";
|
|
48066
|
-
import { basename as
|
|
48431
|
+
import { basename as basename14, dirname as dirname24, isAbsolute as isAbsolute26, join as join34, normalize as normalize4, relative as relative10, resolve as resolve25, sep as sep13 } from "path";
|
|
48067
48432
|
|
|
48068
48433
|
// src/lib/registry-data/index.ts
|
|
48069
48434
|
var SKILLS = [];
|
|
@@ -48588,7 +48953,7 @@ import {
|
|
|
48588
48953
|
realpathSync as realpathSync14,
|
|
48589
48954
|
writeFileSync as writeFileSync6
|
|
48590
48955
|
} from "fs";
|
|
48591
|
-
import { basename as
|
|
48956
|
+
import { basename as basename12, dirname as dirname22, join as join32, relative as relative9 } from "path";
|
|
48592
48957
|
var ANY_SEGMENT_COPY_EXCLUDES = new Set([
|
|
48593
48958
|
".git",
|
|
48594
48959
|
".DS_Store",
|
|
@@ -48638,11 +49003,11 @@ function normalizeNewPortableSkillName(name) {
|
|
|
48638
49003
|
throw new Error(`Invalid skill name '${name}'. Include letters or numbers.`);
|
|
48639
49004
|
return normalized;
|
|
48640
49005
|
}
|
|
48641
|
-
function readPortableSkillManifest(skillPath, fallbackName =
|
|
49006
|
+
function readPortableSkillManifest(skillPath, fallbackName = basename12(skillPath)) {
|
|
48642
49007
|
return readManifest(skillPath, fallbackName, normalizePortableSkillName);
|
|
48643
49008
|
}
|
|
48644
49009
|
function readPortableSkillManifestForImport(skillPath) {
|
|
48645
|
-
return readManifest(skillPath,
|
|
49010
|
+
return readManifest(skillPath, basename12(skillPath), normalizeNewPortableSkillName);
|
|
48646
49011
|
}
|
|
48647
49012
|
function readManifest(skillPath, fallbackName, normalizeName) {
|
|
48648
49013
|
const skillJsonPath = join32(skillPath, "skill.json");
|
|
@@ -49196,7 +49561,7 @@ function inferRuntimeFromCommands(commands) {
|
|
|
49196
49561
|
function readJsonObject(path) {
|
|
49197
49562
|
const parsed = JSON.parse(readFileSync20(path, "utf-8"));
|
|
49198
49563
|
if (!isRecord3(parsed))
|
|
49199
|
-
throw new Error(`${
|
|
49564
|
+
throw new Error(`${basename12(path)} must contain a JSON object`);
|
|
49200
49565
|
return parsed;
|
|
49201
49566
|
}
|
|
49202
49567
|
function hasPackageDependencies(pkgPath) {
|
|
@@ -49234,7 +49599,7 @@ function escapeJsString(value) {
|
|
|
49234
49599
|
// src/lib/authoring-path.ts
|
|
49235
49600
|
import { lstatSync as lstatSync28, realpathSync as realpathSync15 } from "fs";
|
|
49236
49601
|
import { homedir as homedir4 } from "os";
|
|
49237
|
-
import { basename as
|
|
49602
|
+
import { basename as basename13, dirname as dirname23, join as join33, resolve as resolve24, sep as sep12 } from "path";
|
|
49238
49603
|
var NATIVE_DISCOVERY_ROOTS = NATIVE_SKILL_ROOTS.map(([, path]) => path.split("/"));
|
|
49239
49604
|
function pathParts(path) {
|
|
49240
49605
|
return resolve24(path).split(sep12).filter(Boolean);
|
|
@@ -49254,7 +49619,7 @@ function physicalPath(path) {
|
|
|
49254
49619
|
let cursor = resolve24(path);
|
|
49255
49620
|
const suffix = [];
|
|
49256
49621
|
while (!lstatSync28(cursor, { throwIfNoEntry: false })) {
|
|
49257
|
-
suffix.unshift(
|
|
49622
|
+
suffix.unshift(basename13(cursor));
|
|
49258
49623
|
const parent = dirname23(cursor);
|
|
49259
49624
|
if (parent === cursor)
|
|
49260
49625
|
return resolve24(path);
|
|
@@ -49473,7 +49838,7 @@ function physicalImportPath(path) {
|
|
|
49473
49838
|
let ancestor = resolve25(path);
|
|
49474
49839
|
const suffix = [];
|
|
49475
49840
|
while (!existsSync10(ancestor)) {
|
|
49476
|
-
suffix.unshift(
|
|
49841
|
+
suffix.unshift(basename14(ancestor));
|
|
49477
49842
|
ancestor = dirname24(ancestor);
|
|
49478
49843
|
}
|
|
49479
49844
|
return join34(realpathSync16(ancestor), ...suffix);
|
|
@@ -49498,8 +49863,8 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
49498
49863
|
const explicitName = options.name != null;
|
|
49499
49864
|
const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
|
|
49500
49865
|
if (isOfficialSkillName(skillName) && !options.allowShadow) {
|
|
49501
|
-
const sourceSlug = safeNormalizeName(
|
|
49502
|
-
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${
|
|
49866
|
+
const sourceSlug = safeNormalizeName(basename14(absoluteSource));
|
|
49867
|
+
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename14(absoluteSource)}')` : ""} matches a bundled official skill.`;
|
|
49503
49868
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
49504
49869
|
}
|
|
49505
49870
|
const readOnlyDestination = join34(resolvePortableSkillsRoot(options, false), skillName);
|
|
@@ -50027,7 +50392,7 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
|
50027
50392
|
return { action, path: skillMdPath };
|
|
50028
50393
|
const parentDir = dirname25(dir);
|
|
50029
50394
|
mkdirSync10(parentDir, { recursive: true });
|
|
50030
|
-
const transactionDir = mkdtempSync2(join35(parentDir, `.hasna-skills-write-${
|
|
50395
|
+
const transactionDir = mkdtempSync2(join35(parentDir, `.hasna-skills-write-${basename15(dir)}-`));
|
|
50031
50396
|
const candidateDir = join35(transactionDir, "candidate");
|
|
50032
50397
|
const backupDir = join35(transactionDir, "backup");
|
|
50033
50398
|
const candidateSkillMdPath = join35(candidateDir, "SKILL.md");
|