@hasna/skills 0.10.63 → 0.10.64
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 +26 -0
- package/bin/index.js +2583 -1748
- package/bin/mcp.js +1398 -586
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1702 -885
- package/dist/lib/agent-discovery.d.ts +26 -2
- package/dist/lib/agent-integration.d.ts +14 -1
- package/dist/lib/codex-plugin-skill-controls.d.ts +9 -0
- package/dist/lib/codex-semantic-cache-witness.d.ts +57 -0
- package/dist/lib/codex-settings-witness.d.ts +14 -0
- package/dist/runtime-prerequisites.js +50 -3
- package/dist/sdk/index.js +1997 -1182
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -23,7 +23,7 @@ var package_default;
|
|
|
23
23
|
var init_package = __esm(() => {
|
|
24
24
|
package_default = {
|
|
25
25
|
name: "@hasna/skills",
|
|
26
|
-
version: "0.10.
|
|
26
|
+
version: "0.10.64",
|
|
27
27
|
description: "Skills library for AI coding agents",
|
|
28
28
|
type: "module",
|
|
29
29
|
bin: {
|
|
@@ -23088,6 +23088,53 @@ function assertAgentPolicyCollections(policy) {
|
|
|
23088
23088
|
requireBound(directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256));
|
|
23089
23089
|
}
|
|
23090
23090
|
}
|
|
23091
|
+
if (value.codexSemanticCache !== undefined) {
|
|
23092
|
+
const proof = record2(value.codexSemanticCache, 8), witness = record2(proof.witness, 6);
|
|
23093
|
+
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && Object.keys(proof).length === 8 && proof.schema === "hasna.codex-semantic-cache-discovery.v1" && typeof proof.previousPolicySha256 === "string" && /^[a-f0-9]{64}$/.test(proof.previousPolicySha256) && Object.keys(witness).length === 6 && witness.schema === "hasna.codex-semantic-cache-witness.v1" && typeof witness.sha256 === "string" && /^[a-f0-9]{64}$/.test(witness.sha256));
|
|
23094
|
+
text(proof.configPath);
|
|
23095
|
+
requireBound(isAbsolute5(proof.configPath) && resolve4(proof.configPath) === proof.configPath && basename5(proof.configPath) === "config.toml");
|
|
23096
|
+
text(witness.cacheRoot);
|
|
23097
|
+
requireBound(isAbsolute5(witness.cacheRoot) && resolve4(witness.cacheRoot) === witness.cacheRoot);
|
|
23098
|
+
if (proof.hookRootAlias !== null) {
|
|
23099
|
+
requireBound(object2(proof.hookRootAlias) && Object.keys(proof.hookRootAlias).length === 2);
|
|
23100
|
+
for (const key of ["alias", "target"]) {
|
|
23101
|
+
text(proof.hookRootAlias[key]);
|
|
23102
|
+
requireBound(isAbsolute5(proof.hookRootAlias[key]) && resolve4(proof.hookRootAlias[key]) === proof.hookRootAlias[key]);
|
|
23103
|
+
}
|
|
23104
|
+
}
|
|
23105
|
+
const parents2 = array2(proof.appOnlyParents, 4096);
|
|
23106
|
+
for (const parent of parents2) {
|
|
23107
|
+
requireBound(object2(parent) && Object.keys(parent).length === 5 && parent.role === "app-only");
|
|
23108
|
+
for (const key of ["pluginId", "namespace", "pluginParent", "remotePluginId"])
|
|
23109
|
+
text(parent[key]);
|
|
23110
|
+
requireBound(isAbsolute5(parent.pluginParent) && resolve4(parent.pluginParent) === parent.pluginParent);
|
|
23111
|
+
}
|
|
23112
|
+
for (const row of [...array2(witness.controls, 4096), ...array2(witness.appOnlyParents, 4096)]) {
|
|
23113
|
+
requireBound(object2(row));
|
|
23114
|
+
for (const key of ["pluginId", "namespace", "pluginParent"])
|
|
23115
|
+
text(row[key]);
|
|
23116
|
+
for (const key of ["manifestSha256", "appSha256", "mcpSha256", "receiptSha256"])
|
|
23117
|
+
if (row[key] !== undefined)
|
|
23118
|
+
requireBound(typeof row[key] === "string" && /^[a-f0-9]{64}$/.test(row[key]));
|
|
23119
|
+
}
|
|
23120
|
+
for (const skill of array2(witness.skills, 4096)) {
|
|
23121
|
+
requireBound(object2(skill));
|
|
23122
|
+
for (const key of ["name", "pluginId", "namespace", "pluginParent"])
|
|
23123
|
+
text(skill[key]);
|
|
23124
|
+
for (const rule of array2(skill.disabledRules, 4096))
|
|
23125
|
+
text(rule);
|
|
23126
|
+
}
|
|
23127
|
+
for (const source of array2(proof.supersededSources, AGENT_POLICY_LIMITS.discoverySources)) {
|
|
23128
|
+
requireBound(object2(source));
|
|
23129
|
+
text(source.path);
|
|
23130
|
+
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
23131
|
+
}
|
|
23132
|
+
for (const directory of array2(proof.supersededDirectories, AGENT_POLICY_LIMITS.discoveryDirectories)) {
|
|
23133
|
+
requireBound(object2(directory));
|
|
23134
|
+
text(directory.path);
|
|
23135
|
+
requireBound(directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256));
|
|
23136
|
+
}
|
|
23137
|
+
}
|
|
23091
23138
|
for (const root of array2(value.roots, AGENT_POLICY_LIMITS.discoveryRoots))
|
|
23092
23139
|
text(root);
|
|
23093
23140
|
for (const source of array2(value.sources, AGENT_POLICY_LIMITS.discoverySources)) {
|
|
@@ -23095,12 +23142,12 @@ function assertAgentPolicyCollections(policy) {
|
|
|
23095
23142
|
text(source.path);
|
|
23096
23143
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
23097
23144
|
if (source.hashMode !== undefined)
|
|
23098
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-settings-v4", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1", "claude-marketplace-entry-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
23145
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-settings-v4", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "codex-settings-v5", "sumi-settings-v1", "claude-marketplace-entry-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
23099
23146
|
if (source.hashMode === "claude-plugin-manifest-v1")
|
|
23100
23147
|
requireBound(agent === "claude" && value.agent === "claude" && ["automatic", "reviewed"].includes(value.method) && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute5(source.path) && resolve4(source.path) === source.path && source.path.endsWith(join10(sep3, ".claude-plugin", "plugin.json")) && source.managedPlugins === undefined);
|
|
23101
23148
|
if (source.hashMode === "sumi-settings-v1")
|
|
23102
23149
|
requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute5(source.path) && resolve4(source.path) === source.path && basename5(source.path) === "sumi.json");
|
|
23103
|
-
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
|
|
23150
|
+
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"))
|
|
23104
23151
|
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute5(source.path) && resolve4(source.path) === source.path && basename5(source.path) === "config.toml");
|
|
23105
23152
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4"))
|
|
23106
23153
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute5(source.path) && resolve4(source.path) === source.path && basename5(source.path) === "settings.json");
|
|
@@ -32731,6 +32778,7 @@ var init_codex_hook_rpc = __esm(() => {
|
|
|
32731
32778
|
});
|
|
32732
32779
|
|
|
32733
32780
|
// src/lib/codex-native-skill-catalog.ts
|
|
32781
|
+
import { realpathSync as realpathSync4 } from "fs";
|
|
32734
32782
|
import { isAbsolute as isAbsolute10, normalize as normalize2 } from "path";
|
|
32735
32783
|
function codexPluginSourceIsConfigControlled(plugin) {
|
|
32736
32784
|
const remoteRealms = ["openai-curated-remote", "created-by-me-remote", "workspace-directory", "workspace-shared-with-me", "workspace-shared-with-me-private", "workspace-shared-with-me-unlisted"];
|
|
@@ -32779,6 +32827,43 @@ function projectCodexInstalledPluginEntries(value) {
|
|
|
32779
32827
|
};
|
|
32780
32828
|
});
|
|
32781
32829
|
}
|
|
32830
|
+
function canonicalPath(path) {
|
|
32831
|
+
try {
|
|
32832
|
+
return realpathSync4(path);
|
|
32833
|
+
} catch {
|
|
32834
|
+
return normalize2(path);
|
|
32835
|
+
}
|
|
32836
|
+
}
|
|
32837
|
+
function isCodexNativeSkillDisabled(skill, rules) {
|
|
32838
|
+
if (!scalar(skill.name, MAX_NAME_BYTES) || !absolutePath2(skill.path))
|
|
32839
|
+
refuse();
|
|
32840
|
+
if (rules === undefined)
|
|
32841
|
+
return false;
|
|
32842
|
+
if (!Array.isArray(rules) || rules.length > MAX_SKILLS)
|
|
32843
|
+
refuse();
|
|
32844
|
+
let disabled = false;
|
|
32845
|
+
for (const rule of rules) {
|
|
32846
|
+
if (!object5(rule) || typeof rule.enabled !== "boolean")
|
|
32847
|
+
refuse();
|
|
32848
|
+
const hasName = rule.name !== undefined && rule.name !== null;
|
|
32849
|
+
const hasPath = rule.path !== undefined && rule.path !== null;
|
|
32850
|
+
if (hasName === hasPath)
|
|
32851
|
+
refuse();
|
|
32852
|
+
let matches;
|
|
32853
|
+
if (hasName) {
|
|
32854
|
+
if (typeof rule.name !== "string" || !scalar(rule.name.trim(), MAX_NAME_BYTES))
|
|
32855
|
+
refuse();
|
|
32856
|
+
matches = rule.name.trim() === skill.name;
|
|
32857
|
+
} else {
|
|
32858
|
+
if (!absolutePath2(rule.path))
|
|
32859
|
+
refuse();
|
|
32860
|
+
matches = canonicalPath(rule.path) === canonicalPath(skill.path);
|
|
32861
|
+
}
|
|
32862
|
+
if (matches)
|
|
32863
|
+
disabled = !rule.enabled;
|
|
32864
|
+
}
|
|
32865
|
+
return disabled;
|
|
32866
|
+
}
|
|
32782
32867
|
var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, MAX_PLUGIN_ID_BYTES = 1024, object5 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), scalar = (value, max) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max && !/[\u0000-\u001f\u007f]/u.test(value), remotePluginIdentifier = (value) => typeof value === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(value), absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute10(value);
|
|
32783
32868
|
var init_codex_native_skill_catalog = __esm(() => {
|
|
32784
32869
|
init_codex_hook_rpc();
|
|
@@ -32788,13 +32873,13 @@ var init_codex_native_skill_catalog = __esm(() => {
|
|
|
32788
32873
|
|
|
32789
32874
|
// src/lib/codex-plugin-skill-controls.ts
|
|
32790
32875
|
import { basename as basename6, dirname as dirname12, join as join18, relative as relative5, resolve as resolve11, sep as sep6 } from "path";
|
|
32791
|
-
import { lstatSync as lstatSync12, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as
|
|
32876
|
+
import { lstatSync as lstatSync12, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as realpathSync5 } from "fs";
|
|
32792
32877
|
function refuse2() {
|
|
32793
32878
|
throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
|
|
32794
32879
|
}
|
|
32795
32880
|
function remoteInstallationMatches(parent, remotePluginId, read) {
|
|
32796
32881
|
try {
|
|
32797
|
-
if (!remotePluginIdentifier(remotePluginId) || !lstatSync12(parent).isDirectory() ||
|
|
32882
|
+
if (!remotePluginIdentifier(remotePluginId) || !lstatSync12(parent).isDirectory() || realpathSync5(parent) !== parent)
|
|
32798
32883
|
return false;
|
|
32799
32884
|
const path = join18(parent, ".codex-remote-plugin-install.json"), stat = lstatSync12(path, { throwIfNoEntry: false });
|
|
32800
32885
|
if (!stat?.isFile() || stat.isSymbolicLink() || stat.size > 16384)
|
|
@@ -32871,6 +32956,9 @@ function isBundledCleanupHooks(root, namespace, value) {
|
|
|
32871
32956
|
}
|
|
32872
32957
|
return true;
|
|
32873
32958
|
}
|
|
32959
|
+
function readCodexPluginRootControls(root, read) {
|
|
32960
|
+
return rootControls(root, read);
|
|
32961
|
+
}
|
|
32874
32962
|
function rootControls(root, read) {
|
|
32875
32963
|
const manifestPath = join18(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync12(manifestPath, { throwIfNoEntry: false });
|
|
32876
32964
|
if (!lstatSync12(join18(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
|
|
@@ -32893,7 +32981,7 @@ function rootControls(root, read) {
|
|
|
32893
32981
|
const mcp = join18(root, ".mcp.json"), mcpPresent = lstatSync12(mcp, { throwIfNoEntry: false });
|
|
32894
32982
|
if (manifest.hooks !== undefined && (manifest.mcpServers !== undefined || mcpPresent))
|
|
32895
32983
|
refuse2();
|
|
32896
|
-
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 ||
|
|
32984
|
+
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
|
|
32897
32985
|
refuse2();
|
|
32898
32986
|
if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
|
|
32899
32987
|
refuse2();
|
|
@@ -32906,6 +32994,76 @@ function rootControls(root, read) {
|
|
|
32906
32994
|
const appSha256 = present ? appControls(app, read) : undefined;
|
|
32907
32995
|
return { namespace: manifest.name, manifestSha256, ...appSha256 ? { appSha256 } : {}, ...mcpSha256 ? { mcpSha256 } : {} };
|
|
32908
32996
|
}
|
|
32997
|
+
function documentIdentity(document2, cache, read) {
|
|
32998
|
+
if (!document2.startsWith(cache + sep6) || !document2.endsWith(sep6 + "SKILL.md"))
|
|
32999
|
+
refuse2();
|
|
33000
|
+
const text2 = read(document2);
|
|
33001
|
+
if (Buffer.byteLength(text2) > 1024 * 1024)
|
|
33002
|
+
refuse2();
|
|
33003
|
+
const lines = text2.split(/\r?\n/);
|
|
33004
|
+
if (lines[0]?.trim() !== "---")
|
|
33005
|
+
refuse2();
|
|
33006
|
+
const end = lines.findIndex((line, i) => i > 0 && line.trim() === "---");
|
|
33007
|
+
if (end < 2)
|
|
33008
|
+
refuse2();
|
|
33009
|
+
const yaml = lines.slice(1, end).join(`
|
|
33010
|
+
`);
|
|
33011
|
+
if (/(?:^|\s)[&*!]|<<\s*:/.test(yaml) || lines.slice(1, end).filter((line) => /^name\s*:/.test(line)).length !== 1)
|
|
33012
|
+
refuse2();
|
|
33013
|
+
let front;
|
|
33014
|
+
try {
|
|
33015
|
+
front = Bun.YAML.parse(yaml);
|
|
33016
|
+
} catch {
|
|
33017
|
+
refuse2();
|
|
33018
|
+
}
|
|
33019
|
+
if (!front || typeof front !== "object" || !identifier2(front.name) || typeof front.description !== "string" || !front.description.trim())
|
|
33020
|
+
refuse2();
|
|
33021
|
+
for (let root = dirname12(document2), depth = 0;root.startsWith(cache + sep6) && depth < 12; root = dirname12(root), depth++) {
|
|
33022
|
+
const path = join18(root, ".codex-plugin", "plugin.json");
|
|
33023
|
+
if (!lstatSync12(path, { throwIfNoEntry: false }))
|
|
33024
|
+
continue;
|
|
33025
|
+
const manifestFile = lstatSync12(path);
|
|
33026
|
+
if (!lstatSync12(join18(root, ".codex-plugin")).isDirectory() || !manifestFile.isFile() || manifestFile.size > 1024 * 1024)
|
|
33027
|
+
refuse2();
|
|
33028
|
+
let manifest;
|
|
33029
|
+
try {
|
|
33030
|
+
const text3 = read(path);
|
|
33031
|
+
hashNativeJsonControls(text3);
|
|
33032
|
+
manifest = JSON.parse(text3);
|
|
33033
|
+
} catch {
|
|
33034
|
+
refuse2();
|
|
33035
|
+
}
|
|
33036
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest) || !identifier2(manifest.name))
|
|
33037
|
+
refuse2();
|
|
33038
|
+
const declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
33039
|
+
if (declaredVersion === null || (declaredVersion ? declaredVersion !== basename6(root) : basename6(root) !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
33040
|
+
refuse2();
|
|
33041
|
+
return { name: `${manifest.name}:${front.name}`, namespace: manifest.name, pluginParent: dirname12(root), root };
|
|
33042
|
+
}
|
|
33043
|
+
refuse2();
|
|
33044
|
+
}
|
|
33045
|
+
function identity3(document2, cache, read) {
|
|
33046
|
+
const parsed = documentIdentity(document2, cache, read);
|
|
33047
|
+
const controls = rootControls(parsed.root, read);
|
|
33048
|
+
if (controls.namespace !== parsed.namespace)
|
|
33049
|
+
refuse2();
|
|
33050
|
+
return { name: parsed.name, pluginParent: parsed.pluginParent, ...controls };
|
|
33051
|
+
}
|
|
33052
|
+
function classifyCodexPluginCacheDocument(document2, cache, read) {
|
|
33053
|
+
if (!document2.startsWith(cache + sep6))
|
|
33054
|
+
return null;
|
|
33055
|
+
try {
|
|
33056
|
+
const located = documentIdentity(document2, cache, read), parsed = identity3(document2, cache, read);
|
|
33057
|
+
if (!lstatSync12(document2).isFile() || realpathSync5(document2) !== document2 || realpathSync5(located.root) !== located.root || realpathSync5(located.pluginParent) !== located.pluginParent || realpathSync5(join18(located.root, ".codex-plugin/plugin.json")) !== join18(located.root, ".codex-plugin/plugin.json"))
|
|
33058
|
+
return null;
|
|
33059
|
+
const parts = relative5(cache, parsed.pluginParent).split(sep6);
|
|
33060
|
+
if (parts.length !== 2 || parts.some((part) => !identifier2(part)) || parts[1] !== parsed.namespace)
|
|
33061
|
+
return null;
|
|
33062
|
+
return { name: parsed.name, namespace: parsed.namespace, pluginId: `${parts[1]}@${parts[0]}`, pluginParent: parsed.pluginParent, root: located.root, manifestSha256: parsed.manifestSha256 };
|
|
33063
|
+
} catch {
|
|
33064
|
+
return null;
|
|
33065
|
+
}
|
|
33066
|
+
}
|
|
32909
33067
|
function reviewedDisabledCodexPluginParent(cache, parent, controls, rules) {
|
|
32910
33068
|
try {
|
|
32911
33069
|
const parts = relative5(cache, parent).split(sep6), enrolled = controls.filter((control) => control.pluginParent === parent);
|
|
@@ -32969,7 +33127,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read, rules)
|
|
|
32969
33127
|
for (const parent of new Set(controls.map((control) => control.pluginParent))) {
|
|
32970
33128
|
if (absentDisabledCodexPluginParent(cache, parent, controls, rules))
|
|
32971
33129
|
continue;
|
|
32972
|
-
if (!parent.startsWith(cache + sep6) || !lstatSync12(parent, { throwIfNoEntry: false })?.isDirectory() ||
|
|
33130
|
+
if (!parent.startsWith(cache + sep6) || !lstatSync12(parent, { throwIfNoEntry: false })?.isDirectory() || realpathSync5(parent) !== parent)
|
|
32973
33131
|
return false;
|
|
32974
33132
|
for (const control of controls.filter((control2) => control2.pluginParent === parent)) {
|
|
32975
33133
|
if (control.remotePluginId !== undefined && !remoteInstallationMatches(parent, control.remotePluginId, read))
|
|
@@ -32983,7 +33141,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read, rules)
|
|
|
32983
33141
|
let root = join18(parent, name), stat = lstatSync12(root);
|
|
32984
33142
|
if (stat.isSymbolicLink()) {
|
|
32985
33143
|
const target = resolve11(parent, readlinkSync3(root));
|
|
32986
|
-
if (name !== "latest" || dirname12(target) !== parent || !lstatSync12(target).isDirectory() ||
|
|
33144
|
+
if (name !== "latest" || dirname12(target) !== parent || !lstatSync12(target).isDirectory() || realpathSync5(target) !== target)
|
|
32987
33145
|
return false;
|
|
32988
33146
|
root = target;
|
|
32989
33147
|
stat = lstatSync12(root);
|
|
@@ -33003,10 +33161,10 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read, rules)
|
|
|
33003
33161
|
function sourceInputUnchanged(input2, cache, read) {
|
|
33004
33162
|
try {
|
|
33005
33163
|
const parts = relative5(cache, input2.pluginParent).split(sep6);
|
|
33006
|
-
if (parts.length !== 2 || parts.some((part) => !identifier2(part)) || parts[1] !== input2.namespace || input2.pluginId !== `${parts[1]}@${parts[0]}` || !codexPluginSourceIsConfigControlled({ id: input2.pluginId, sourceType: "local", sourceSha256: input2.sourceSha256 }) || input2.sourceSha256 !== hashNativeJsonControls(JSON.stringify({ type: "local", path: input2.sourceRoot })) || resolve11(input2.sourceRoot) !== input2.sourceRoot || !lstatSync12(input2.sourceRoot).isDirectory() ||
|
|
33164
|
+
if (parts.length !== 2 || parts.some((part) => !identifier2(part)) || parts[1] !== input2.namespace || input2.pluginId !== `${parts[1]}@${parts[0]}` || !codexPluginSourceIsConfigControlled({ id: input2.pluginId, sourceType: "local", sourceSha256: input2.sourceSha256 }) || input2.sourceSha256 !== hashNativeJsonControls(JSON.stringify({ type: "local", path: input2.sourceRoot })) || resolve11(input2.sourceRoot) !== input2.sourceRoot || !lstatSync12(input2.sourceRoot).isDirectory() || realpathSync5(input2.sourceRoot) !== input2.sourceRoot || input2.sourceRoot === cache || input2.sourceRoot.startsWith(cache + sep6) || cache.startsWith(input2.sourceRoot + sep6))
|
|
33007
33165
|
return false;
|
|
33008
33166
|
const path = join18(input2.sourceRoot, ".codex-plugin/plugin.json"), stat = lstatSync12(path);
|
|
33009
|
-
if (!stat.isFile() || stat.size > 1024 * 1024 ||
|
|
33167
|
+
if (!stat.isFile() || stat.size > 1024 * 1024 || realpathSync5(path) !== path)
|
|
33010
33168
|
return false;
|
|
33011
33169
|
const text2 = read(path);
|
|
33012
33170
|
hashNativeJsonControls(text2);
|
|
@@ -33300,6 +33458,8 @@ function normalize3(config2, version2 = 2) {
|
|
|
33300
33458
|
if (isRecord3(profile))
|
|
33301
33459
|
inference(profile, version2);
|
|
33302
33460
|
}
|
|
33461
|
+
if (version2 === 5)
|
|
33462
|
+
projectStatusLine(config2);
|
|
33303
33463
|
}
|
|
33304
33464
|
function disablesOneSkill(entry) {
|
|
33305
33465
|
if (!isRecord3(entry) || entry.enabled !== false)
|
|
@@ -33437,6 +33597,14 @@ function projectModelAvailabilityNux(config2, text2) {
|
|
|
33437
33597
|
}
|
|
33438
33598
|
return { config: config2, numericSource: text2 };
|
|
33439
33599
|
}
|
|
33600
|
+
function projectStatusLine(config2) {
|
|
33601
|
+
const tui = config2.tui;
|
|
33602
|
+
if (!isRecord3(tui) || !Array.isArray(tui.status_line) || !tui.status_line.every((item) => typeof item === "string"))
|
|
33603
|
+
return;
|
|
33604
|
+
delete tui.status_line;
|
|
33605
|
+
if (!Object.keys(tui).length)
|
|
33606
|
+
delete config2.tui;
|
|
33607
|
+
}
|
|
33440
33608
|
function settingsDigest2(text2, version2 = 2) {
|
|
33441
33609
|
let config2;
|
|
33442
33610
|
try {
|
|
@@ -33446,7 +33614,7 @@ function settingsDigest2(text2, version2 = 2) {
|
|
|
33446
33614
|
}
|
|
33447
33615
|
need5(isRecord3(config2));
|
|
33448
33616
|
const mcp = version2 >= 3 ? projectRegularCodexMcp(config2, text2) : { config: config2, numericSource: text2 };
|
|
33449
|
-
const projected = version2
|
|
33617
|
+
const projected = version2 >= 4 ? projectModelAvailabilityNux(mcp.config, mcp.numericSource) : mcp;
|
|
33450
33618
|
normalize3(projected.config, version2);
|
|
33451
33619
|
return sha2(`hasna.skills.codex-settings.v${version2}\x00${JSON.stringify([canonical6(projected.config), numericTokens2(projected.numericSource)])}`);
|
|
33452
33620
|
}
|
|
@@ -33475,6 +33643,14 @@ function hashCodexSettingsReplacementV4(text2, budget2 = { remaining: 256 * 1024
|
|
|
33475
33643
|
function captureCodexSettingsV4(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33476
33644
|
return { path, hashMode: "codex-settings-v4", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget2, "config.toml"), 4) };
|
|
33477
33645
|
}
|
|
33646
|
+
function hashCodexSettingsReplacementV5(text2, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33647
|
+
need5(Buffer.byteLength(text2) <= 1024 * 1024 && budget2.remaining >= Buffer.byteLength(text2));
|
|
33648
|
+
budget2.remaining -= Buffer.byteLength(text2);
|
|
33649
|
+
return settingsDigest2(text2, 5);
|
|
33650
|
+
}
|
|
33651
|
+
function captureCodexSettingsV5(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
33652
|
+
return { path, hashMode: "codex-settings-v5", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget2, "config.toml"), 5) };
|
|
33653
|
+
}
|
|
33478
33654
|
var sha2 = (text2) => createHash13("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
|
|
33479
33655
|
var init_codex_settings_witness = __esm(() => {
|
|
33480
33656
|
init_codex_settings_witness_v1();
|
|
@@ -33488,9 +33664,575 @@ var init_codex_settings_witness = __esm(() => {
|
|
|
33488
33664
|
INFERENCE = ["model", "model_reasoning_effort", "model_verbosity"];
|
|
33489
33665
|
});
|
|
33490
33666
|
|
|
33667
|
+
// src/lib/codex-semantic-cache-witness.ts
|
|
33668
|
+
import { createHash as createHash14 } from "crypto";
|
|
33669
|
+
import { constants as constants7, closeSync as closeSync10, fstatSync as fstatSync10, lstatSync as lstatSync13, openSync as openSync10, readSync as readSync5, readdirSync as readdirSync7, realpathSync as realpathSync6 } from "fs";
|
|
33670
|
+
import { dirname as dirname13, isAbsolute as isAbsolute11, join as join19, relative as relative6, resolve as resolve12, sep as sep7 } from "path";
|
|
33671
|
+
function defaultRead(path) {
|
|
33672
|
+
const before = lstatSync13(path, { throwIfNoEntry: false, bigint: true });
|
|
33673
|
+
if (before === undefined)
|
|
33674
|
+
return refuse3();
|
|
33675
|
+
if (!before.isFile() || before.isSymbolicLink() || before.size > BigInt(MAX_DOCUMENT_BYTES))
|
|
33676
|
+
refuse3();
|
|
33677
|
+
let fd;
|
|
33678
|
+
try {
|
|
33679
|
+
fd = openSync10(path, constants7.O_RDONLY | (constants7.O_NOFOLLOW ?? 0));
|
|
33680
|
+
} catch {
|
|
33681
|
+
return refuse3();
|
|
33682
|
+
}
|
|
33683
|
+
try {
|
|
33684
|
+
const opened = fstatSync10(fd, { bigint: true });
|
|
33685
|
+
if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino || opened.size !== before.size || opened.size > BigInt(MAX_DOCUMENT_BYTES))
|
|
33686
|
+
refuse3();
|
|
33687
|
+
const chunks = [];
|
|
33688
|
+
let total = 0;
|
|
33689
|
+
while (total <= MAX_DOCUMENT_BYTES) {
|
|
33690
|
+
const chunk = Buffer.alloc(Math.min(64 * 1024, MAX_DOCUMENT_BYTES + 1 - total));
|
|
33691
|
+
const count = readSync5(fd, chunk, 0, chunk.length, null);
|
|
33692
|
+
if (!count)
|
|
33693
|
+
break;
|
|
33694
|
+
total += count;
|
|
33695
|
+
if (total > MAX_DOCUMENT_BYTES)
|
|
33696
|
+
refuse3();
|
|
33697
|
+
chunks.push(chunk.subarray(0, count));
|
|
33698
|
+
}
|
|
33699
|
+
const after = fstatSync10(fd, { bigint: true });
|
|
33700
|
+
if (after.dev !== opened.dev || after.ino !== opened.ino || after.size !== opened.size || after.mtimeNs !== opened.mtimeNs || after.ctimeNs !== opened.ctimeNs || BigInt(total) !== after.size)
|
|
33701
|
+
refuse3();
|
|
33702
|
+
return Buffer.concat(chunks, total).toString("utf8");
|
|
33703
|
+
} finally {
|
|
33704
|
+
closeSync10(fd);
|
|
33705
|
+
}
|
|
33706
|
+
}
|
|
33707
|
+
function canonical7(value) {
|
|
33708
|
+
if (value === null || typeof value !== "object")
|
|
33709
|
+
return JSON.stringify(value);
|
|
33710
|
+
if (Array.isArray(value))
|
|
33711
|
+
return `[${value.map(canonical7).join(",")}]`;
|
|
33712
|
+
const object6 = value;
|
|
33713
|
+
return `{${Object.keys(object6).sort().map((key) => `${JSON.stringify(key)}:${canonical7(object6[key])}`).join(",")}}`;
|
|
33714
|
+
}
|
|
33715
|
+
function hash3(value) {
|
|
33716
|
+
return createHash14("sha256").update(canonical7(value)).digest("hex");
|
|
33717
|
+
}
|
|
33718
|
+
function plainObject(value) {
|
|
33719
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
33720
|
+
}
|
|
33721
|
+
function exactKeys(value, required2, optional2 = []) {
|
|
33722
|
+
const keys = Object.keys(value).sort();
|
|
33723
|
+
return required2.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required2.includes(key) || optional2.includes(key));
|
|
33724
|
+
}
|
|
33725
|
+
function validPluginParent(cacheRoot, pluginParent, namespace, pluginId) {
|
|
33726
|
+
if (!isAbsolute11(pluginParent) || resolve12(pluginParent) !== pluginParent)
|
|
33727
|
+
return false;
|
|
33728
|
+
const parts = relative6(cacheRoot, pluginParent).split(sep7);
|
|
33729
|
+
return parts.length === 2 && parts.every(identifier3) && parts[1] === namespace && pluginId === `${namespace}@${parts[0]}`;
|
|
33730
|
+
}
|
|
33731
|
+
function assertWitnessShape(value) {
|
|
33732
|
+
if (!plainObject(value) || !exactKeys(value, ["schema", "cacheRoot", "controls", "appOnlyParents", "skills", "sha256"]) || value.schema !== CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA || typeof value.cacheRoot !== "string" || !isAbsolute11(value.cacheRoot) || resolve12(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)
|
|
33733
|
+
refuse3();
|
|
33734
|
+
const witness = value;
|
|
33735
|
+
const controlParents = new Set;
|
|
33736
|
+
for (const candidate of witness.controls) {
|
|
33737
|
+
if (!plainObject(candidate))
|
|
33738
|
+
refuse3();
|
|
33739
|
+
const row = candidate;
|
|
33740
|
+
if (!exactKeys(row, ["pluginId", "namespace", "pluginParent", "manifestSha256"], ["remotePluginId", "receiptSha256", "appSha256", "mcpSha256"]) || !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) || !digest(row.manifestSha256) || row.appSha256 !== undefined && !digest(row.appSha256) || row.mcpSha256 !== undefined && !digest(row.mcpSha256) || row.receiptSha256 !== undefined && !digest(row.receiptSha256) || row.remotePluginId !== undefined && (typeof row.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(row.remotePluginId)) || row.remotePluginId === undefined !== (row.receiptSha256 === undefined) || controlParents.has(row.pluginParent))
|
|
33741
|
+
refuse3();
|
|
33742
|
+
controlParents.add(row.pluginParent);
|
|
33743
|
+
}
|
|
33744
|
+
const appOnlyParentPaths = new Set;
|
|
33745
|
+
for (const candidate of witness.appOnlyParents) {
|
|
33746
|
+
if (!plainObject(candidate))
|
|
33747
|
+
refuse3();
|
|
33748
|
+
const row = candidate;
|
|
33749
|
+
if (!exactKeys(row, ["role", "pluginId", "namespace", "pluginParent", "remotePluginId", "receiptSha256", "manifestSha256", "appSha256"], ["mcpSha256"]) || row.role !== "app-only" || !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) || typeof row.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(row.remotePluginId) || !digest(row.receiptSha256) || !digest(row.manifestSha256) || !digest(row.appSha256) || row.mcpSha256 !== undefined && !digest(row.mcpSha256) || appOnlyParentPaths.has(row.pluginParent) || controlParents.has(row.pluginParent))
|
|
33750
|
+
refuse3();
|
|
33751
|
+
appOnlyParentPaths.add(row.pluginParent);
|
|
33752
|
+
}
|
|
33753
|
+
const skillNames = new Set;
|
|
33754
|
+
const qualifiedNames = new Set;
|
|
33755
|
+
for (const candidate of witness.skills) {
|
|
33756
|
+
if (!plainObject(candidate))
|
|
33757
|
+
refuse3();
|
|
33758
|
+
const row = candidate;
|
|
33759
|
+
if (!exactKeys(row, ["name", "pluginId", "namespace", "pluginParent", "disabledRules"]) || typeof row.name !== "string" || !row.name.startsWith(`${String(row.namespace)}:`) || !identifier3(row.name.slice(String(row.namespace).length + 1)) || !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, String(row.namespace), row.pluginId) || !Array.isArray(row.disabledRules) || row.disabledRules.length !== 1 || row.disabledRules.some((rule) => rule !== `name:${String(row.name)}=disabled`) || !controlParents.has(row.pluginParent))
|
|
33760
|
+
refuse3();
|
|
33761
|
+
const qualified = `${row.pluginId}\x00${row.name}`;
|
|
33762
|
+
if (qualifiedNames.has(qualified) || skillNames.has(row.name))
|
|
33763
|
+
refuse3();
|
|
33764
|
+
qualifiedNames.add(qualified);
|
|
33765
|
+
skillNames.add(row.name);
|
|
33766
|
+
}
|
|
33767
|
+
const projection = {
|
|
33768
|
+
schema: witness.schema,
|
|
33769
|
+
cacheRoot: witness.cacheRoot,
|
|
33770
|
+
controls: witness.controls,
|
|
33771
|
+
appOnlyParents: witness.appOnlyParents,
|
|
33772
|
+
skills: witness.skills
|
|
33773
|
+
};
|
|
33774
|
+
if (hash3(projection) !== witness.sha256)
|
|
33775
|
+
refuse3();
|
|
33776
|
+
}
|
|
33777
|
+
function assertCanonicalDirectory(path) {
|
|
33778
|
+
if (resolve12(path) !== path || realpathSync6(path) !== path)
|
|
33779
|
+
refuse3();
|
|
33780
|
+
for (let cursor = path;; cursor = dirname13(cursor)) {
|
|
33781
|
+
const stat = lstatSync13(cursor, { throwIfNoEntry: false });
|
|
33782
|
+
if (stat && (!stat.isDirectory() || stat.isSymbolicLink()))
|
|
33783
|
+
refuse3();
|
|
33784
|
+
if (dirname13(cursor) === cursor)
|
|
33785
|
+
break;
|
|
33786
|
+
}
|
|
33787
|
+
}
|
|
33788
|
+
function walkSafeTree(path, state, depth = 0, root = path) {
|
|
33789
|
+
if (depth > 64 || ++state.entries > 16384)
|
|
33790
|
+
refuse3();
|
|
33791
|
+
const names = readdirSync7(path).sort();
|
|
33792
|
+
const files = [];
|
|
33793
|
+
for (const name of names) {
|
|
33794
|
+
if (!name || name === "." || name === ".." || name.includes(sep7) || ++state.entries > 16384)
|
|
33795
|
+
refuse3();
|
|
33796
|
+
const child2 = join19(path, name), stat = lstatSync13(child2, { bigint: true });
|
|
33797
|
+
state.members.push(child2);
|
|
33798
|
+
state.signature.push(`${relative6(root, child2)}\x00${stat.mode}\x00${stat.dev}\x00${stat.ino}\x00${stat.isDirectory() ? 0 : stat.size}`);
|
|
33799
|
+
state.timestamps.set(child2, `${stat.mtimeNs}\x00${stat.ctimeNs}`);
|
|
33800
|
+
if (stat.isSymbolicLink())
|
|
33801
|
+
refuse3();
|
|
33802
|
+
if (stat.isDirectory())
|
|
33803
|
+
files.push(...walkSafeTree(child2, state, depth + 1, root));
|
|
33804
|
+
else if (stat.isFile())
|
|
33805
|
+
files.push(child2);
|
|
33806
|
+
else
|
|
33807
|
+
refuse3();
|
|
33808
|
+
}
|
|
33809
|
+
return files;
|
|
33810
|
+
}
|
|
33811
|
+
function treeSnapshot(cacheRoot) {
|
|
33812
|
+
const state = { entries: 0, members: [], signature: [], timestamps: new Map };
|
|
33813
|
+
const rootStat = lstatSync13(cacheRoot, { throwIfNoEntry: false, bigint: true });
|
|
33814
|
+
if (rootStat === undefined)
|
|
33815
|
+
return refuse3();
|
|
33816
|
+
if (!rootStat.isDirectory() || rootStat.isSymbolicLink() || realpathSync6(cacheRoot) !== cacheRoot)
|
|
33817
|
+
refuse3();
|
|
33818
|
+
state.signature.push(`.\x00${rootStat.mode}\x00${rootStat.dev}\x00${rootStat.ino}`);
|
|
33819
|
+
state.timestamps.set(cacheRoot, `${rootStat.mtimeNs}\x00${rootStat.ctimeNs}`);
|
|
33820
|
+
const files = walkSafeTree(cacheRoot, state);
|
|
33821
|
+
return { files, state };
|
|
33822
|
+
}
|
|
33823
|
+
function assertSameTree(before, after, semanticPaths) {
|
|
33824
|
+
if (canonical7([...before.members].sort()) !== canonical7([...after.members].sort()) || canonical7([...before.signature].sort()) !== canonical7([...after.signature].sort()))
|
|
33825
|
+
refuse3();
|
|
33826
|
+
for (const path of semanticPaths)
|
|
33827
|
+
if (before.timestamps.get(path) !== after.timestamps.get(path))
|
|
33828
|
+
refuse3();
|
|
33829
|
+
}
|
|
33830
|
+
function trackedBoundedRead(read) {
|
|
33831
|
+
const observed = new Map;
|
|
33832
|
+
const stableStat = (path, max) => {
|
|
33833
|
+
const stat = lstatSync13(path, { throwIfNoEntry: false, bigint: true });
|
|
33834
|
+
if (stat === undefined)
|
|
33835
|
+
return refuse3();
|
|
33836
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > BigInt(max) || realpathSync6(path) !== path)
|
|
33837
|
+
refuse3();
|
|
33838
|
+
return stat;
|
|
33839
|
+
};
|
|
33840
|
+
const guarded = (path) => {
|
|
33841
|
+
const max = path.endsWith(".codex-remote-plugin-install.json") ? MAX_RECEIPT_BYTES : MAX_DOCUMENT_BYTES;
|
|
33842
|
+
const before = stableStat(path, max);
|
|
33843
|
+
const text2 = read(path);
|
|
33844
|
+
if (Buffer.byteLength(text2, "utf8") > max)
|
|
33845
|
+
refuse3();
|
|
33846
|
+
const after = stableStat(path, max);
|
|
33847
|
+
if (after.dev !== before.dev || after.ino !== before.ino || after.size !== before.size || after.mtimeNs !== before.mtimeNs || after.ctimeNs !== before.ctimeNs)
|
|
33848
|
+
refuse3();
|
|
33849
|
+
const sha3 = createHash14("sha256").update(text2).digest("hex");
|
|
33850
|
+
const prior = observed.get(path);
|
|
33851
|
+
if (prior !== undefined && prior !== sha3)
|
|
33852
|
+
refuse3();
|
|
33853
|
+
observed.set(path, sha3);
|
|
33854
|
+
return text2;
|
|
33855
|
+
};
|
|
33856
|
+
return {
|
|
33857
|
+
read: guarded,
|
|
33858
|
+
verify: () => {
|
|
33859
|
+
for (const [path, expected] of observed) {
|
|
33860
|
+
const max = path.endsWith(".codex-remote-plugin-install.json") ? MAX_RECEIPT_BYTES : MAX_DOCUMENT_BYTES;
|
|
33861
|
+
const before = stableStat(path, max);
|
|
33862
|
+
const text2 = read(path);
|
|
33863
|
+
const after = stableStat(path, max);
|
|
33864
|
+
if (Buffer.byteLength(text2, "utf8") > max || createHash14("sha256").update(text2).digest("hex") !== expected || after.dev !== before.dev || after.ino !== before.ino || after.size !== before.size || after.mtimeNs !== before.mtimeNs || after.ctimeNs !== before.ctimeNs)
|
|
33865
|
+
refuse3();
|
|
33866
|
+
}
|
|
33867
|
+
},
|
|
33868
|
+
paths: () => [...observed.keys()]
|
|
33869
|
+
};
|
|
33870
|
+
}
|
|
33871
|
+
function controlProjection(controls, read) {
|
|
33872
|
+
const byPlugin = new Map;
|
|
33873
|
+
for (const control of controls) {
|
|
33874
|
+
if (!control || !identifier3(control.namespace) || typeof control.pluginId !== "string" || !/^[A-Za-z0-9_-]{1,64}@[A-Za-z0-9_-]{1,64}$/.test(control.pluginId) || typeof control.pluginParent !== "string" || !control.name.startsWith(`${control.namespace}:`) || !identifier3(control.name.slice(control.namespace.length + 1)))
|
|
33875
|
+
refuse3();
|
|
33876
|
+
if (!digest(control.manifestSha256) || control.appSha256 !== undefined && !digest(control.appSha256) || control.mcpSha256 !== undefined && !digest(control.mcpSha256) || control.remotePluginId !== undefined && (typeof control.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId)))
|
|
33877
|
+
refuse3();
|
|
33878
|
+
const key = `${control.pluginId}\x00${control.pluginParent}`;
|
|
33879
|
+
const row = {
|
|
33880
|
+
pluginId: control.pluginId,
|
|
33881
|
+
namespace: control.namespace,
|
|
33882
|
+
pluginParent: control.pluginParent,
|
|
33883
|
+
...control.remotePluginId === undefined ? {} : { remotePluginId: control.remotePluginId },
|
|
33884
|
+
manifestSha256: control.manifestSha256,
|
|
33885
|
+
...control.appSha256 === undefined ? {} : { appSha256: control.appSha256 },
|
|
33886
|
+
...control.mcpSha256 === undefined ? {} : { mcpSha256: control.mcpSha256 }
|
|
33887
|
+
};
|
|
33888
|
+
if (row.remotePluginId !== undefined) {
|
|
33889
|
+
const receipt = join19(row.pluginParent, ".codex-remote-plugin-install.json"), stat = lstatSync13(receipt, { throwIfNoEntry: false });
|
|
33890
|
+
if (!stat?.isFile() || stat.isSymbolicLink() || stat.size > 16384)
|
|
33891
|
+
refuse3();
|
|
33892
|
+
try {
|
|
33893
|
+
const receiptText = read(receipt), value = JSON.parse(receiptText);
|
|
33894
|
+
if (!value || Array.isArray(value) || typeof value !== "object" || Object.keys(value).length !== 2 || value.schema_version !== 1 || value.remote_plugin_id !== row.remotePluginId)
|
|
33895
|
+
refuse3();
|
|
33896
|
+
row.receiptSha256 = createHash14("sha256").update(receiptText).digest("hex");
|
|
33897
|
+
} catch {
|
|
33898
|
+
refuse3();
|
|
33899
|
+
}
|
|
33900
|
+
}
|
|
33901
|
+
const previous = byPlugin.get(key);
|
|
33902
|
+
if (previous && canonical7(previous) !== canonical7(row))
|
|
33903
|
+
refuse3();
|
|
33904
|
+
byPlugin.set(key, row);
|
|
33905
|
+
}
|
|
33906
|
+
if (!byPlugin.size || byPlugin.size > 4096)
|
|
33907
|
+
refuse3();
|
|
33908
|
+
return [...byPlugin.values()].sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
|
|
33909
|
+
}
|
|
33910
|
+
function appOnlyParentProjection(cacheRoot, parents2, read) {
|
|
33911
|
+
if (!Array.isArray(parents2) || parents2.length > 4096)
|
|
33912
|
+
refuse3();
|
|
33913
|
+
const seen = new Set, rows = [];
|
|
33914
|
+
for (const parent of parents2) {
|
|
33915
|
+
if (!parent || Object.keys(parent).sort().join(",") !== "namespace,pluginId,pluginParent,remotePluginId,role" || parent.role !== "app-only" || !identifier3(parent.namespace) || !/^[A-Za-z0-9_-]{1,64}@[A-Za-z0-9_-]{1,64}$/.test(parent.pluginId) || typeof parent.pluginParent !== "string" || typeof parent.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(parent.remotePluginId))
|
|
33916
|
+
refuse3();
|
|
33917
|
+
const parts = relative6(cacheRoot, parent.pluginParent).split(sep7);
|
|
33918
|
+
if (resolve12(parent.pluginParent) !== parent.pluginParent || parts.length !== 2 || parts.some((part) => !identifier3(part)) || parent.pluginId !== `${parent.namespace}@${parts[0]}` || parts[1] !== parent.namespace || seen.has(parent.pluginParent))
|
|
33919
|
+
refuse3();
|
|
33920
|
+
seen.add(parent.pluginParent);
|
|
33921
|
+
const parentStat = lstatSync13(parent.pluginParent, { throwIfNoEntry: false });
|
|
33922
|
+
if (!parentStat?.isDirectory() || parentStat.isSymbolicLink() || realpathSync6(parent.pluginParent) !== parent.pluginParent)
|
|
33923
|
+
refuse3();
|
|
33924
|
+
const receipt = join19(parent.pluginParent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync13(receipt, { throwIfNoEntry: false });
|
|
33925
|
+
if (!receiptStat?.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > 16384)
|
|
33926
|
+
refuse3();
|
|
33927
|
+
let receiptText = "";
|
|
33928
|
+
try {
|
|
33929
|
+
receiptText = read(receipt);
|
|
33930
|
+
hashNativeJsonControls(receiptText);
|
|
33931
|
+
const value = JSON.parse(receiptText);
|
|
33932
|
+
if (!value || Array.isArray(value) || typeof value !== "object" || Object.keys(value).length !== 2 || value.schema_version !== 1 || value.remote_plugin_id !== parent.remotePluginId)
|
|
33933
|
+
refuse3();
|
|
33934
|
+
} catch {
|
|
33935
|
+
refuse3();
|
|
33936
|
+
}
|
|
33937
|
+
const versions2 = readdirSync7(parent.pluginParent).filter((name) => name !== ".codex-remote-plugin-install.json");
|
|
33938
|
+
if (!versions2.length || versions2.length > 4096)
|
|
33939
|
+
refuse3();
|
|
33940
|
+
const materializations = versions2.map((version2) => {
|
|
33941
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
|
|
33942
|
+
refuse3();
|
|
33943
|
+
const root = join19(parent.pluginParent, version2), stat = lstatSync13(root, { throwIfNoEntry: false });
|
|
33944
|
+
if (!stat?.isDirectory() || stat.isSymbolicLink() || realpathSync6(root) !== root)
|
|
33945
|
+
refuse3();
|
|
33946
|
+
const rootControls2 = readCodexPluginRootControls(root, read);
|
|
33947
|
+
if (rootControls2.namespace !== parent.namespace || !digest(rootControls2.manifestSha256) || !digest(rootControls2.appSha256) || rootControls2.mcpSha256 !== undefined && !digest(rootControls2.mcpSha256))
|
|
33948
|
+
refuse3();
|
|
33949
|
+
return {
|
|
33950
|
+
manifestSha256: rootControls2.manifestSha256,
|
|
33951
|
+
appSha256: rootControls2.appSha256,
|
|
33952
|
+
...rootControls2.mcpSha256 === undefined ? {} : { mcpSha256: rootControls2.mcpSha256 }
|
|
33953
|
+
};
|
|
33954
|
+
});
|
|
33955
|
+
const first = materializations[0];
|
|
33956
|
+
if (materializations.some((item) => canonical7(item) !== canonical7(first)))
|
|
33957
|
+
refuse3();
|
|
33958
|
+
rows.push({ ...parent, receiptSha256: createHash14("sha256").update(receiptText).digest("hex"), ...first });
|
|
33959
|
+
}
|
|
33960
|
+
return rows.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.pluginParent.localeCompare(b.pluginParent));
|
|
33961
|
+
}
|
|
33962
|
+
function assertParents(cacheRoot, controls, appOnlyParents, files, members2) {
|
|
33963
|
+
const expected = new Set;
|
|
33964
|
+
const expectedMarkets = new Set;
|
|
33965
|
+
for (const control of [...controls, ...appOnlyParents]) {
|
|
33966
|
+
const rel = relative6(cacheRoot, control.pluginParent), parts = rel.split(sep7);
|
|
33967
|
+
if (resolve12(control.pluginParent) !== control.pluginParent || parts.length !== 2 || parts.some((part) => !identifier3(part)) || control.pluginId !== `${control.namespace}@${parts[0]}` || parts[1] !== control.namespace)
|
|
33968
|
+
refuse3();
|
|
33969
|
+
expected.add(control.pluginParent);
|
|
33970
|
+
expectedMarkets.add(parts[0]);
|
|
33971
|
+
}
|
|
33972
|
+
const actual = new Set;
|
|
33973
|
+
for (const file2 of files) {
|
|
33974
|
+
const rel = relative6(cacheRoot, file2), parts = rel.split(sep7);
|
|
33975
|
+
if (parts.length < 3 || !identifier3(parts[0]) || !identifier3(parts[1]))
|
|
33976
|
+
refuse3();
|
|
33977
|
+
actual.add(join19(cacheRoot, parts[0], parts[1]));
|
|
33978
|
+
}
|
|
33979
|
+
const actualMarkets = readdirSync7(cacheRoot);
|
|
33980
|
+
if (actualMarkets.length !== expectedMarkets.size || actualMarkets.some((market) => !expectedMarkets.has(market)))
|
|
33981
|
+
refuse3();
|
|
33982
|
+
for (const market of actualMarkets) {
|
|
33983
|
+
const marketPath = join19(cacheRoot, market), marketStat = lstatSync13(marketPath);
|
|
33984
|
+
if (!identifier3(market) || !marketStat.isDirectory() || marketStat.isSymbolicLink())
|
|
33985
|
+
refuse3();
|
|
33986
|
+
for (const plugin of readdirSync7(marketPath)) {
|
|
33987
|
+
const parent = join19(marketPath, plugin), stat = lstatSync13(parent);
|
|
33988
|
+
if (!identifier3(plugin) || !stat.isDirectory() || stat.isSymbolicLink())
|
|
33989
|
+
refuse3();
|
|
33990
|
+
actual.add(parent);
|
|
33991
|
+
}
|
|
33992
|
+
}
|
|
33993
|
+
if (actual.size !== expected.size || [...actual].some((parent) => !expected.has(parent)))
|
|
33994
|
+
refuse3();
|
|
33995
|
+
for (const member of members2) {
|
|
33996
|
+
const parts = relative6(cacheRoot, member).split(sep7);
|
|
33997
|
+
if (parts.length < 3)
|
|
33998
|
+
continue;
|
|
33999
|
+
const parent = join19(cacheRoot, parts[0], parts[1]);
|
|
34000
|
+
const root = join19(parent, parts[2]);
|
|
34001
|
+
const base = parts[parts.length - 1];
|
|
34002
|
+
if (parts.includes(".codex-plugin") && (parts.length < 4 || parts[3] !== ".codex-plugin" || (parts.length === 4 ? base !== ".codex-plugin" : parts.length !== 5 || base !== "plugin.json")))
|
|
34003
|
+
refuse3();
|
|
34004
|
+
if ([".app.json", ".mcp.json"].includes(base) && (parts.length !== 4 || dirname13(member) !== root))
|
|
34005
|
+
refuse3();
|
|
34006
|
+
if (parts.includes("hooks"))
|
|
34007
|
+
refuse3();
|
|
34008
|
+
}
|
|
34009
|
+
}
|
|
34010
|
+
function assertSkillMaterializations(cacheRoot, controls, files, read) {
|
|
34011
|
+
const expectedByRoot = new Map;
|
|
34012
|
+
const byParent = new Map;
|
|
34013
|
+
for (const control of controls) {
|
|
34014
|
+
const group = byParent.get(control.pluginParent) ?? [];
|
|
34015
|
+
group.push(control);
|
|
34016
|
+
byParent.set(control.pluginParent, group);
|
|
34017
|
+
}
|
|
34018
|
+
for (const [parent, rows] of byParent) {
|
|
34019
|
+
const first = rows[0];
|
|
34020
|
+
const expectedControls = {
|
|
34021
|
+
namespace: first.namespace,
|
|
34022
|
+
manifestSha256: first.manifestSha256,
|
|
34023
|
+
...first.appSha256 === undefined ? {} : { appSha256: first.appSha256 },
|
|
34024
|
+
...first.mcpSha256 === undefined ? {} : { mcpSha256: first.mcpSha256 }
|
|
34025
|
+
};
|
|
34026
|
+
if (rows.some((row) => canonical7({
|
|
34027
|
+
namespace: row.namespace,
|
|
34028
|
+
manifestSha256: row.manifestSha256,
|
|
34029
|
+
...row.appSha256 === undefined ? {} : { appSha256: row.appSha256 },
|
|
34030
|
+
...row.mcpSha256 === undefined ? {} : { mcpSha256: row.mcpSha256 }
|
|
34031
|
+
}) !== canonical7(expectedControls)))
|
|
34032
|
+
refuse3();
|
|
34033
|
+
const expectedNames = new Set(rows.map((row) => row.name));
|
|
34034
|
+
if (expectedNames.size !== rows.length)
|
|
34035
|
+
refuse3();
|
|
34036
|
+
const entries = readdirSync7(parent);
|
|
34037
|
+
let roots = 0;
|
|
34038
|
+
for (const entry of entries) {
|
|
34039
|
+
if (entry === ".codex-remote-plugin-install.json")
|
|
34040
|
+
continue;
|
|
34041
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(entry))
|
|
34042
|
+
refuse3();
|
|
34043
|
+
const root = join19(parent, entry), stat = lstatSync13(root, { throwIfNoEntry: false });
|
|
34044
|
+
if (!stat?.isDirectory() || stat.isSymbolicLink() || realpathSync6(root) !== root)
|
|
34045
|
+
refuse3();
|
|
34046
|
+
const actualControls = readCodexPluginRootControls(root, read);
|
|
34047
|
+
const actualProjection = {
|
|
34048
|
+
namespace: actualControls.namespace,
|
|
34049
|
+
manifestSha256: actualControls.manifestSha256,
|
|
34050
|
+
...actualControls.appSha256 === undefined ? {} : { appSha256: actualControls.appSha256 },
|
|
34051
|
+
...actualControls.mcpSha256 === undefined ? {} : { mcpSha256: actualControls.mcpSha256 }
|
|
34052
|
+
};
|
|
34053
|
+
if (canonical7(actualProjection) !== canonical7(expectedControls))
|
|
34054
|
+
refuse3();
|
|
34055
|
+
const key = `${first.pluginId}\x00${root}`;
|
|
34056
|
+
expectedByRoot.set(key, expectedNames);
|
|
34057
|
+
roots++;
|
|
34058
|
+
}
|
|
34059
|
+
if (!roots)
|
|
34060
|
+
refuse3();
|
|
34061
|
+
}
|
|
34062
|
+
for (const file2 of files) {
|
|
34063
|
+
if (!file2.endsWith(`${sep7}SKILL.md`))
|
|
34064
|
+
continue;
|
|
34065
|
+
const rel = relative6(cacheRoot, file2).split(sep7);
|
|
34066
|
+
if (rel.length < 4)
|
|
34067
|
+
refuse3();
|
|
34068
|
+
const parent = join19(cacheRoot, rel[0], rel[1]);
|
|
34069
|
+
if (!byParent.has(parent) || !expectedByRoot.has(`${byParent.get(parent)[0].pluginId}\x00${join19(parent, rel[2])}`))
|
|
34070
|
+
refuse3();
|
|
34071
|
+
}
|
|
34072
|
+
return expectedByRoot;
|
|
34073
|
+
}
|
|
34074
|
+
function effectiveDisabledRules(skill, rules) {
|
|
34075
|
+
if (!Array.isArray(rules))
|
|
34076
|
+
refuse3();
|
|
34077
|
+
const matching = [];
|
|
34078
|
+
for (const candidate of rules) {
|
|
34079
|
+
if (!plainObject(candidate) || typeof candidate.enabled !== "boolean")
|
|
34080
|
+
refuse3();
|
|
34081
|
+
const rule = candidate;
|
|
34082
|
+
const byName = typeof rule.name === "string" && rule.name.trim() === skill.name;
|
|
34083
|
+
let byPath = false;
|
|
34084
|
+
if (typeof rule.path === "string") {
|
|
34085
|
+
if (resolve12(rule.path) !== rule.path)
|
|
34086
|
+
refuse3();
|
|
34087
|
+
let canonicalPath2;
|
|
34088
|
+
try {
|
|
34089
|
+
canonicalPath2 = realpathSync6(rule.path);
|
|
34090
|
+
} catch {
|
|
34091
|
+
canonicalPath2 = resolve12(rule.path);
|
|
34092
|
+
}
|
|
34093
|
+
if (canonicalPath2 === skill.path && rule.path !== canonicalPath2)
|
|
34094
|
+
refuse3();
|
|
34095
|
+
byPath = canonicalPath2 === skill.path;
|
|
34096
|
+
}
|
|
34097
|
+
if ((byName || byPath) && rule.enabled !== false)
|
|
34098
|
+
refuse3();
|
|
34099
|
+
if (byName)
|
|
34100
|
+
matching.push(`name:${skill.name}=disabled`);
|
|
34101
|
+
}
|
|
34102
|
+
if (!isCodexNativeSkillDisabled(skill, rules))
|
|
34103
|
+
refuse3();
|
|
34104
|
+
if (!matching.length)
|
|
34105
|
+
refuse3();
|
|
34106
|
+
return [...new Set(matching)].sort();
|
|
34107
|
+
}
|
|
34108
|
+
function captureCodexSemanticCacheWitness(options) {
|
|
34109
|
+
const tracked = trackedBoundedRead(options.read ?? defaultRead);
|
|
34110
|
+
const read = tracked.read;
|
|
34111
|
+
try {
|
|
34112
|
+
assertCanonicalDirectory(options.cacheRoot);
|
|
34113
|
+
const initialTree = treeSnapshot(options.cacheRoot);
|
|
34114
|
+
const controls = controlProjection(options.controls, read);
|
|
34115
|
+
const appOnlyParents = appOnlyParentProjection(options.cacheRoot, options.appOnlyParents ?? [], read);
|
|
34116
|
+
const skillParents = new Set(controls.map((control) => control.pluginParent));
|
|
34117
|
+
if (appOnlyParents.some((parent) => skillParents.has(parent.pluginParent)))
|
|
34118
|
+
refuse3();
|
|
34119
|
+
if (!reviewedCodexPluginCapabilitiesUnchanged(options.cacheRoot, options.controls, read, options.rules))
|
|
34120
|
+
refuse3();
|
|
34121
|
+
const files = initialTree.files;
|
|
34122
|
+
assertParents(options.cacheRoot, controls, appOnlyParents, files, initialTree.state.members);
|
|
34123
|
+
const expectedNamesByRoot = assertSkillMaterializations(options.cacheRoot, options.controls, files, read);
|
|
34124
|
+
const docs = files.filter((path) => path.endsWith(`${sep7}SKILL.md`));
|
|
34125
|
+
const skillRows = [];
|
|
34126
|
+
const rootNames = new Map;
|
|
34127
|
+
for (const document2 of docs) {
|
|
34128
|
+
const rel = relative6(options.cacheRoot, document2).split(sep7);
|
|
34129
|
+
if (appOnlyParents.some((parent) => parent.pluginParent === join19(options.cacheRoot, rel[0], rel[1])))
|
|
34130
|
+
refuse3();
|
|
34131
|
+
const documentStat = lstatSync13(document2, { throwIfNoEntry: false });
|
|
34132
|
+
if (!documentStat?.isFile() || documentStat.isSymbolicLink() || documentStat.size > MAX_DOCUMENT_BYTES)
|
|
34133
|
+
refuse3();
|
|
34134
|
+
const identity4 = classifyCodexPluginCacheDocument(document2, options.cacheRoot, read);
|
|
34135
|
+
if (identity4 === null)
|
|
34136
|
+
return refuse3();
|
|
34137
|
+
const row = {
|
|
34138
|
+
name: identity4.name,
|
|
34139
|
+
pluginId: identity4.pluginId,
|
|
34140
|
+
namespace: identity4.namespace,
|
|
34141
|
+
pluginParent: identity4.pluginParent,
|
|
34142
|
+
disabledRules: effectiveDisabledRules({ name: identity4.name, path: document2, enabled: true, pluginId: identity4.pluginId }, options.rules)
|
|
34143
|
+
};
|
|
34144
|
+
const root = identity4.root;
|
|
34145
|
+
const rootKey = `${row.pluginId}\x00${root}`;
|
|
34146
|
+
const names = rootNames.get(rootKey) ?? new Set;
|
|
34147
|
+
if (names.has(row.name))
|
|
34148
|
+
refuse3();
|
|
34149
|
+
names.add(row.name);
|
|
34150
|
+
rootNames.set(rootKey, names);
|
|
34151
|
+
skillRows.push(row);
|
|
34152
|
+
}
|
|
34153
|
+
if (!skillRows.length || skillRows.length > 4096)
|
|
34154
|
+
refuse3();
|
|
34155
|
+
const uniqueNames = new Set(skillRows.map((row) => `${row.pluginId}\x00${row.name}`));
|
|
34156
|
+
const reviewedNames = new Set(options.controls.map((control) => `${control.pluginId}\x00${control.name}`));
|
|
34157
|
+
if (reviewedNames.size !== options.controls.length || new Set(options.controls.map((control) => control.name)).size !== options.controls.length)
|
|
34158
|
+
refuse3();
|
|
34159
|
+
if (uniqueNames.size !== reviewedNames.size || [...uniqueNames].some((name) => !reviewedNames.has(name)))
|
|
34160
|
+
refuse3();
|
|
34161
|
+
if (new Set(skillRows.map((row) => row.name)).size !== reviewedNames.size)
|
|
34162
|
+
refuse3();
|
|
34163
|
+
const byPlugin = new Map;
|
|
34164
|
+
for (const row of skillRows) {
|
|
34165
|
+
const names = byPlugin.get(row.pluginId) ?? new Set;
|
|
34166
|
+
names.add(row.name);
|
|
34167
|
+
byPlugin.set(row.pluginId, names);
|
|
34168
|
+
}
|
|
34169
|
+
for (const [key, expected] of expectedNamesByRoot) {
|
|
34170
|
+
const names = rootNames.get(key);
|
|
34171
|
+
if (!names || names.size !== expected.size || [...expected].some((name) => !names.has(name)))
|
|
34172
|
+
refuse3();
|
|
34173
|
+
}
|
|
34174
|
+
if (rootNames.size !== expectedNamesByRoot.size)
|
|
34175
|
+
refuse3();
|
|
34176
|
+
for (const [key, names] of rootNames) {
|
|
34177
|
+
const pluginId = key.slice(0, key.indexOf("\x00")), expected = byPlugin.get(pluginId);
|
|
34178
|
+
if (!expected || names.size !== expected.size || [...expected].some((name) => !names.has(name)))
|
|
34179
|
+
refuse3();
|
|
34180
|
+
}
|
|
34181
|
+
const skillsByName = new Map;
|
|
34182
|
+
for (const row of skillRows) {
|
|
34183
|
+
const key = `${row.pluginId}\x00${row.name}`, prior = skillsByName.get(key);
|
|
34184
|
+
if (prior && canonical7(prior.disabledRules) !== canonical7(row.disabledRules))
|
|
34185
|
+
refuse3();
|
|
34186
|
+
if (!prior)
|
|
34187
|
+
skillsByName.set(key, row);
|
|
34188
|
+
}
|
|
34189
|
+
const uniqueSkills = [...skillsByName.values()];
|
|
34190
|
+
uniqueSkills.sort((a, b) => a.pluginId.localeCompare(b.pluginId) || a.name.localeCompare(b.name));
|
|
34191
|
+
tracked.verify();
|
|
34192
|
+
const finalTree = treeSnapshot(options.cacheRoot);
|
|
34193
|
+
assertSameTree(initialTree.state, finalTree.state, tracked.paths());
|
|
34194
|
+
const completeProjection = { schema: CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA, cacheRoot: options.cacheRoot, controls, appOnlyParents, skills: uniqueSkills };
|
|
34195
|
+
return { ...completeProjection, sha256: hash3(completeProjection) };
|
|
34196
|
+
} catch (error61) {
|
|
34197
|
+
if (error61 instanceof Error && error61.message.startsWith("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED"))
|
|
34198
|
+
throw error61;
|
|
34199
|
+
return refuse3();
|
|
34200
|
+
}
|
|
34201
|
+
}
|
|
34202
|
+
function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
|
|
34203
|
+
assertWitnessShape(previous);
|
|
34204
|
+
assertWitnessShape(current);
|
|
34205
|
+
const priorProjection = {
|
|
34206
|
+
schema: previous.schema,
|
|
34207
|
+
cacheRoot: previous.cacheRoot,
|
|
34208
|
+
controls: previous.controls,
|
|
34209
|
+
appOnlyParents: previous.appOnlyParents,
|
|
34210
|
+
skills: previous.skills
|
|
34211
|
+
};
|
|
34212
|
+
const currentProjection = {
|
|
34213
|
+
schema: current.schema,
|
|
34214
|
+
cacheRoot: current.cacheRoot,
|
|
34215
|
+
controls: current.controls,
|
|
34216
|
+
appOnlyParents: current.appOnlyParents,
|
|
34217
|
+
skills: current.skills
|
|
34218
|
+
};
|
|
34219
|
+
if (hash3(priorProjection) !== previous.sha256 || hash3(currentProjection) !== current.sha256 || canonical7(priorProjection) !== canonical7(currentProjection))
|
|
34220
|
+
refuse3();
|
|
34221
|
+
}
|
|
34222
|
+
var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1", identifier3 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value), digest = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), refuse3 = () => {
|
|
34223
|
+
throw new Error("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED: review Codex plugin cache identity and controls");
|
|
34224
|
+
}, MAX_DOCUMENT_BYTES, MAX_RECEIPT_BYTES;
|
|
34225
|
+
var init_codex_semantic_cache_witness = __esm(() => {
|
|
34226
|
+
init_claude_settings_witness();
|
|
34227
|
+
init_codex_plugin_skill_controls();
|
|
34228
|
+
init_codex_native_skill_catalog();
|
|
34229
|
+
MAX_DOCUMENT_BYTES = 1024 * 1024;
|
|
34230
|
+
MAX_RECEIPT_BYTES = 16 * 1024;
|
|
34231
|
+
});
|
|
34232
|
+
|
|
33491
34233
|
// src/lib/managed-policy.ts
|
|
33492
|
-
import { closeSync as
|
|
33493
|
-
import { join as
|
|
34234
|
+
import { closeSync as closeSync11, constants as constants8, fstatSync as fstatSync11, lstatSync as lstatSync14, openSync as openSync11, readSync as readSync6 } from "fs";
|
|
34235
|
+
import { join as join20 } from "path";
|
|
33494
34236
|
function refusal(reason2 = "is unreadable") {
|
|
33495
34237
|
return new SkillSelectionError("INVALID_AGENT_POLICY", `The Skills agent loading policy ${reason2}; refusing legacy fallback.`);
|
|
33496
34238
|
}
|
|
@@ -33515,17 +34257,17 @@ function parseManagedSkillPolicy(text2) {
|
|
|
33515
34257
|
return value;
|
|
33516
34258
|
}
|
|
33517
34259
|
function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
|
|
33518
|
-
const path =
|
|
34260
|
+
const path = join20(dataDir2, "agent-policy.json");
|
|
33519
34261
|
let descriptor, observed = false;
|
|
33520
34262
|
try {
|
|
33521
|
-
const stat =
|
|
34263
|
+
const stat = lstatSync14(path);
|
|
33522
34264
|
observed = true;
|
|
33523
34265
|
if (!stat.isFile() || stat.isSymbolicLink())
|
|
33524
34266
|
throw refusal();
|
|
33525
34267
|
if (stat.size > AGENT_POLICY_LIMITS.bytes)
|
|
33526
34268
|
throw refusal("exceeds its size limit");
|
|
33527
|
-
descriptor =
|
|
33528
|
-
const opened =
|
|
34269
|
+
descriptor = openSync11(path, constants8.O_RDONLY | (constants8.O_NOFOLLOW ?? 0) | constants8.O_NONBLOCK);
|
|
34270
|
+
const opened = fstatSync11(descriptor);
|
|
33529
34271
|
if (!opened.isFile())
|
|
33530
34272
|
throw refusal();
|
|
33531
34273
|
if (opened.size > AGENT_POLICY_LIMITS.bytes)
|
|
@@ -33533,7 +34275,7 @@ function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
|
|
|
33533
34275
|
const bytes = Buffer.allocUnsafe(AGENT_POLICY_LIMITS.bytes + 1);
|
|
33534
34276
|
let length = 0;
|
|
33535
34277
|
while (length < bytes.length) {
|
|
33536
|
-
const count =
|
|
34278
|
+
const count = readSync6(descriptor, bytes, length, bytes.length - length, null);
|
|
33537
34279
|
if (count === 0)
|
|
33538
34280
|
break;
|
|
33539
34281
|
length += count;
|
|
@@ -33544,7 +34286,7 @@ function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
|
|
|
33544
34286
|
return { text: text2, value: parseManagedSkillPolicy(text2) };
|
|
33545
34287
|
} catch (error61) {
|
|
33546
34288
|
if (error61.code === "ENOENT" && !observed) {
|
|
33547
|
-
if (
|
|
34289
|
+
if (lstatSync14(path, { throwIfNoEntry: false }) === undefined)
|
|
33548
34290
|
return null;
|
|
33549
34291
|
}
|
|
33550
34292
|
if (error61 instanceof SkillSelectionError)
|
|
@@ -33552,7 +34294,7 @@ function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
|
|
|
33552
34294
|
throw refusal();
|
|
33553
34295
|
} finally {
|
|
33554
34296
|
if (descriptor !== undefined)
|
|
33555
|
-
|
|
34297
|
+
closeSync11(descriptor);
|
|
33556
34298
|
}
|
|
33557
34299
|
}
|
|
33558
34300
|
function readManagedSkillPolicy(dataDir2 = getDataDirReadOnly()) {
|
|
@@ -33568,7 +34310,7 @@ var init_managed_policy = __esm(() => {
|
|
|
33568
34310
|
});
|
|
33569
34311
|
|
|
33570
34312
|
// src/lib/agent-bridge.ts
|
|
33571
|
-
import { createHash as
|
|
34313
|
+
import { createHash as createHash15 } from "crypto";
|
|
33572
34314
|
var CLI_BRIDGE_VERSION = 1, markdown = `---
|
|
33573
34315
|
name: skills-cli
|
|
33574
34316
|
description: Discover, load, author, and run versioned skills through the Skills CLI when a task needs reusable instructions or an executable skill.
|
|
@@ -33584,7 +34326,7 @@ Use the Skills CLI as the skill authority for this station.
|
|
|
33584
34326
|
This bridge contains no skill payloads. Do not copy skill content into agent-native skill directories or load other native skill copies. If a Skills command refuses authority, selection, integrity, or native drift, report that refusal and use its repair guidance; do not substitute bundled or stale local content. Explicit local draft authoring remains available.
|
|
33585
34327
|
`, CLI_BRIDGE_DIGEST, CLI_BRIDGE_FILES;
|
|
33586
34328
|
var init_agent_bridge = __esm(() => {
|
|
33587
|
-
CLI_BRIDGE_DIGEST =
|
|
34329
|
+
CLI_BRIDGE_DIGEST = createHash15("sha256").update(markdown).digest("hex");
|
|
33588
34330
|
CLI_BRIDGE_FILES = Object.freeze({
|
|
33589
34331
|
"SKILL.md": markdown,
|
|
33590
34332
|
".hasna-skills.json": `${JSON.stringify({ managedBy: "@hasna/skills", kind: "cli-bridge", version: CLI_BRIDGE_VERSION, protocol: "selection-v1", contentSha256: CLI_BRIDGE_DIGEST }, null, 2)}
|
|
@@ -33597,16 +34339,16 @@ var init_agent_codex = () => {};
|
|
|
33597
34339
|
|
|
33598
34340
|
// src/lib/agent-sumi.ts
|
|
33599
34341
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
33600
|
-
import { accessSync, constants as
|
|
33601
|
-
import { delimiter, isAbsolute as
|
|
34342
|
+
import { accessSync, constants as constants9, existsSync as existsSync8, lstatSync as lstatSync15, realpathSync as realpathSync7, statSync as statSync7 } from "fs";
|
|
34343
|
+
import { delimiter, isAbsolute as isAbsolute12, join as join21, resolve as resolve13 } from "path";
|
|
33602
34344
|
function recordWithKeys(value, keys) {
|
|
33603
34345
|
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
33604
34346
|
}
|
|
33605
34347
|
function absolutePath3(value) {
|
|
33606
|
-
return typeof value === "string" && value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) &&
|
|
34348
|
+
return typeof value === "string" && value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute12(value) && resolve13(value) === value;
|
|
33607
34349
|
}
|
|
33608
34350
|
function absoluteInput(value) {
|
|
33609
|
-
return value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) &&
|
|
34351
|
+
return value.length > 0 && value.length <= 32768 && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute12(value);
|
|
33610
34352
|
}
|
|
33611
34353
|
function resolveSumiPathsCommand(pathValue) {
|
|
33612
34354
|
if (!pathValue)
|
|
@@ -33614,9 +34356,9 @@ function resolveSumiPathsCommand(pathValue) {
|
|
|
33614
34356
|
for (const directory of pathValue.split(delimiter)) {
|
|
33615
34357
|
if (!directory || /[\x00-\x1f\x7f]/.test(directory))
|
|
33616
34358
|
continue;
|
|
33617
|
-
const candidate =
|
|
34359
|
+
const candidate = resolve13(directory, "sumi-paths");
|
|
33618
34360
|
try {
|
|
33619
|
-
accessSync(candidate,
|
|
34361
|
+
accessSync(candidate, constants9.X_OK);
|
|
33620
34362
|
if (statSync7(candidate).isFile())
|
|
33621
34363
|
return candidate;
|
|
33622
34364
|
} catch {}
|
|
@@ -33626,7 +34368,7 @@ function resolveSumiPathsCommand(pathValue) {
|
|
|
33626
34368
|
function validPathPlan(value, home, cwd) {
|
|
33627
34369
|
if (!recordWithKeys(value, ["schemaVersion", "kind", "home", "cwd", "roots", "legacyRoots", "configFiles", "skillRoots"]))
|
|
33628
34370
|
return false;
|
|
33629
|
-
if (value.schemaVersion !== 1 || value.kind !== "sumi-paths" || value.home !==
|
|
34371
|
+
if (value.schemaVersion !== 1 || value.kind !== "sumi-paths" || value.home !== resolve13(home) || value.cwd !== resolve13(cwd))
|
|
33630
34372
|
return false;
|
|
33631
34373
|
if (!recordWithKeys(value.roots, SUMI_PATH_KEYS) || !recordWithKeys(value.legacyRoots, SUMI_PATH_KEYS))
|
|
33632
34374
|
return false;
|
|
@@ -33648,11 +34390,11 @@ function validPathPlan(value, home, cwd) {
|
|
|
33648
34390
|
const legacyConfigRoot = value.legacyRoots.config;
|
|
33649
34391
|
if (typeof configRoot !== "string" || legacyConfigRoot !== null && typeof legacyConfigRoot !== "string")
|
|
33650
34392
|
return false;
|
|
33651
|
-
if (value.configFiles.canonical !==
|
|
34393
|
+
if (value.configFiles.canonical !== join21(configRoot, "sumi.json") || value.skillRoots.canonical !== join21(configRoot, "skills"))
|
|
33652
34394
|
return false;
|
|
33653
34395
|
if (legacyConfigRoot === null)
|
|
33654
34396
|
return value.configFiles.legacy === null && value.skillRoots.legacy === null;
|
|
33655
|
-
return value.configFiles.legacy ===
|
|
34397
|
+
return value.configFiles.legacy === join21(legacyConfigRoot, "sumi.json") && value.skillRoots.legacy === join21(legacyConfigRoot, "skills");
|
|
33656
34398
|
}
|
|
33657
34399
|
function sumiPathPlan(home, cwd = process.cwd(), env = process.env) {
|
|
33658
34400
|
for (const key of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
|
|
@@ -33662,7 +34404,7 @@ function sumiPathPlan(home, cwd = process.cwd(), env = process.env) {
|
|
|
33662
34404
|
throw new SumiPathResolverError("SUMI_PATH_INPUT_REFUSED");
|
|
33663
34405
|
const runtimePath = process.env.PATH ?? "";
|
|
33664
34406
|
const executable = resolveSumiPathsCommand(runtimePath);
|
|
33665
|
-
if (!executable || !
|
|
34407
|
+
if (!executable || !isAbsolute12(executable))
|
|
33666
34408
|
throw new SumiPathResolverError("SUMI_PATH_RESOLVER_UNAVAILABLE");
|
|
33667
34409
|
const childEnv = { PATH: runtimePath };
|
|
33668
34410
|
for (const key of SUMI_PATH_SELECTORS)
|
|
@@ -33670,8 +34412,8 @@ function sumiPathPlan(home, cwd = process.cwd(), env = process.env) {
|
|
|
33670
34412
|
childEnv[key] = env[key];
|
|
33671
34413
|
let child2;
|
|
33672
34414
|
try {
|
|
33673
|
-
child2 = spawnSync4(executable, ["--json", "--home",
|
|
33674
|
-
cwd:
|
|
34415
|
+
child2 = spawnSync4(executable, ["--json", "--home", resolve13(home), "--cwd", resolve13(cwd)], {
|
|
34416
|
+
cwd: resolve13(cwd),
|
|
33675
34417
|
env: childEnv,
|
|
33676
34418
|
encoding: "buffer",
|
|
33677
34419
|
timeout: 3000,
|
|
@@ -33700,17 +34442,17 @@ function sumiPathPlan(home, cwd = process.cwd(), env = process.env) {
|
|
|
33700
34442
|
return result;
|
|
33701
34443
|
}
|
|
33702
34444
|
function selectedConfigDirectory(plan) {
|
|
33703
|
-
const
|
|
34445
|
+
const canonical8 = plan.roots.config, legacy = plan.legacyRoots.config;
|
|
33704
34446
|
if (legacy === null)
|
|
33705
|
-
return existsSync8(
|
|
33706
|
-
const canonicalStat =
|
|
33707
|
-
if (canonicalStat && legacyStat &&
|
|
34447
|
+
return existsSync8(canonical8) ? realpathSync7(canonical8) : canonical8;
|
|
34448
|
+
const canonicalStat = lstatSync15(canonical8, { throwIfNoEntry: false }), legacyStat = lstatSync15(legacy, { throwIfNoEntry: false });
|
|
34449
|
+
if (canonicalStat && legacyStat && realpathSync7(canonical8) !== realpathSync7(legacy))
|
|
33708
34450
|
throw new Error("Sumi config roots conflict; complete native home adoption before Skills integration");
|
|
33709
|
-
const selected = canonicalStat ?
|
|
34451
|
+
const selected = canonicalStat ? canonical8 : legacyStat ? legacy : canonical8;
|
|
33710
34452
|
if (!existsSync8(selected))
|
|
33711
34453
|
return selected;
|
|
33712
|
-
const physical =
|
|
33713
|
-
if ((canonicalStat?.isSymbolicLink() || legacyStat?.isSymbolicLink()) && ![
|
|
34454
|
+
const physical = realpathSync7(selected);
|
|
34455
|
+
if ((canonicalStat?.isSymbolicLink() || legacyStat?.isSymbolicLink()) && ![canonical8, legacy].includes(physical))
|
|
33714
34456
|
throw new Error("Sumi config alias must resolve to its canonical or legacy root");
|
|
33715
34457
|
return physical;
|
|
33716
34458
|
}
|
|
@@ -33718,7 +34460,7 @@ function sumiConfigDirectory(home, env = process.env, cwd = process.cwd()) {
|
|
|
33718
34460
|
return selectedConfigDirectory(sumiPathPlan(home, cwd, env));
|
|
33719
34461
|
}
|
|
33720
34462
|
function sumiConfigPath(home, cwd = process.cwd(), env = process.env) {
|
|
33721
|
-
return
|
|
34463
|
+
return join21(sumiConfigDirectory(home, env, cwd), "sumi.json");
|
|
33722
34464
|
}
|
|
33723
34465
|
var SUMI_PATH_SELECTORS, SUMI_PATH_KEYS, SUMI_PATH_OUTPUT_LIMIT, SumiPathResolverError;
|
|
33724
34466
|
var init_agent_sumi = __esm(() => {
|
|
@@ -33736,9 +34478,9 @@ var init_agent_sumi = __esm(() => {
|
|
|
33736
34478
|
});
|
|
33737
34479
|
|
|
33738
34480
|
// src/lib/codex-hook-trust-files.ts
|
|
33739
|
-
import { closeSync as
|
|
33740
|
-
import { createHash as
|
|
33741
|
-
import { dirname as
|
|
34481
|
+
import { closeSync as closeSync12, constants as constants10, fstatSync as fstatSync12, fsyncSync as fsyncSync2, lstatSync as lstatSync16, openSync as openSync12, readlinkSync as readlinkSync4, readSync as readSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
34482
|
+
import { createHash as createHash16 } from "crypto";
|
|
34483
|
+
import { dirname as dirname14, isAbsolute as isAbsolute13, resolve as resolve14 } from "path";
|
|
33742
34484
|
function need6(value, code) {
|
|
33743
34485
|
if (!value)
|
|
33744
34486
|
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
@@ -33747,37 +34489,37 @@ function trustedAncestorOwner(uid) {
|
|
|
33747
34489
|
return BigInt(uid) === 0n || BigInt(uid) === BigInt(process.getuid());
|
|
33748
34490
|
}
|
|
33749
34491
|
function safeParents(file2) {
|
|
33750
|
-
for (let p =
|
|
33751
|
-
const s =
|
|
34492
|
+
for (let p = dirname14(file2);; p = dirname14(p)) {
|
|
34493
|
+
const s = lstatSync16(p);
|
|
33752
34494
|
need6(s.isDirectory() && !s.isSymbolicLink() && trustedAncestorOwner(s.uid), "UNSAFE_PARENT");
|
|
33753
34495
|
need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
33754
|
-
if (
|
|
34496
|
+
if (dirname14(p) === p)
|
|
33755
34497
|
break;
|
|
33756
34498
|
}
|
|
33757
34499
|
}
|
|
33758
34500
|
function snapshot(file2, privateFile = false, options = {}) {
|
|
33759
34501
|
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
33760
34502
|
safeParents(file2);
|
|
33761
|
-
const initial =
|
|
34503
|
+
const initial = lstatSync16(file2, { bigint: true });
|
|
33762
34504
|
need6(initial.isFile() && initial.uid === BigInt(process.getuid()) && (initial.nlink === 1n || readOnlyPackage && initial.nlink > 1n) && (initial.mode & 0o022n) === 0n && (!privateFile || (initial.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
|
|
33763
34505
|
need6(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
33764
|
-
const fd =
|
|
34506
|
+
const fd = openSync12(file2, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
33765
34507
|
try {
|
|
33766
|
-
const before =
|
|
34508
|
+
const before = fstatSync12(fd, { bigint: true });
|
|
33767
34509
|
need6(sameStat(initial, before), "INPUT_CHANGED");
|
|
33768
34510
|
const bytes = Buffer.alloc(Number(before.size) + 1);
|
|
33769
34511
|
let length = 0;
|
|
33770
34512
|
while (length < bytes.length) {
|
|
33771
|
-
const n2 =
|
|
34513
|
+
const n2 = readSync7(fd, bytes, length, bytes.length - length, null);
|
|
33772
34514
|
if (!n2)
|
|
33773
34515
|
break;
|
|
33774
34516
|
length += n2;
|
|
33775
34517
|
}
|
|
33776
|
-
need6(length === Number(before.size) && sameStat(before,
|
|
34518
|
+
need6(length === Number(before.size) && sameStat(before, fstatSync12(fd, { bigint: true })) && sameStat(before, lstatSync16(file2, { bigint: true })), "INPUT_CHANGED");
|
|
33777
34519
|
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
33778
|
-
return { file: file2, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256:
|
|
34520
|
+
return { file: file2, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash16("sha256").update(content).digest("hex") };
|
|
33779
34521
|
} finally {
|
|
33780
|
-
|
|
34522
|
+
closeSync12(fd);
|
|
33781
34523
|
}
|
|
33782
34524
|
}
|
|
33783
34525
|
function unchanged2(before) {
|
|
@@ -33839,47 +34581,47 @@ var init_runtime_launcher = __esm(() => {
|
|
|
33839
34581
|
});
|
|
33840
34582
|
|
|
33841
34583
|
// src/lib/retained-review-artifacts.ts
|
|
33842
|
-
import { createHash as
|
|
33843
|
-
import { constants as
|
|
33844
|
-
import { dirname as
|
|
34584
|
+
import { createHash as createHash17 } from "crypto";
|
|
34585
|
+
import { constants as constants11, closeSync as closeSync13, fstatSync as fstatSync13, fsyncSync as fsyncSync3, lstatSync as lstatSync17, mkdirSync as mkdirSync5, openSync as openSync13, readSync as readSync8, writeSync as writeSync2 } from "fs";
|
|
34586
|
+
import { dirname as dirname15, isAbsolute as isAbsolute14, join as join22, resolve as resolve15, sep as sep8 } from "path";
|
|
33845
34587
|
function keys(value, names) {
|
|
33846
34588
|
return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === names.length && names.every((name) => Object.hasOwn(value, name)));
|
|
33847
34589
|
}
|
|
33848
34590
|
function safe3(path) {
|
|
33849
|
-
need7(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters &&
|
|
33850
|
-
for (let cursor = path;; cursor =
|
|
33851
|
-
const stat =
|
|
34591
|
+
need7(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute14(path) && resolve15(path) === path && !/[\x00-\x1f\x7f]/.test(path));
|
|
34592
|
+
for (let cursor = path;; cursor = dirname15(cursor)) {
|
|
34593
|
+
const stat = lstatSync17(cursor, { throwIfNoEntry: false });
|
|
33852
34594
|
need7(!stat?.isSymbolicLink());
|
|
33853
34595
|
if (cursor !== path && stat)
|
|
33854
34596
|
need7(stat.isDirectory());
|
|
33855
|
-
if (
|
|
34597
|
+
if (dirname15(cursor) === cursor)
|
|
33856
34598
|
break;
|
|
33857
34599
|
}
|
|
33858
34600
|
}
|
|
33859
34601
|
function readExact(path) {
|
|
33860
34602
|
safe3(path);
|
|
33861
|
-
const before =
|
|
34603
|
+
const before = lstatSync17(path, { throwIfNoEntry: false });
|
|
33862
34604
|
need7(before?.isFile() && before.nlink === 1 && before.size <= AGENT_POLICY_LIMITS.discoveryRawSourceBytes && (before.mode & 63) === 0 && (process.getuid === undefined || before.uid === process.getuid()));
|
|
33863
|
-
const fd =
|
|
34605
|
+
const fd = openSync13(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
33864
34606
|
try {
|
|
33865
|
-
const opened =
|
|
34607
|
+
const opened = fstatSync13(fd);
|
|
33866
34608
|
need7(opened.dev === before.dev && opened.ino === before.ino && opened.size === before.size && opened.mode === before.mode && opened.uid === before.uid && opened.nlink === 1);
|
|
33867
34609
|
const bytes = Buffer.alloc(opened.size);
|
|
33868
34610
|
let offset = 0;
|
|
33869
34611
|
while (offset < bytes.length) {
|
|
33870
|
-
const count =
|
|
34612
|
+
const count = readSync8(fd, bytes, offset, bytes.length - offset, null);
|
|
33871
34613
|
need7(count > 0);
|
|
33872
34614
|
offset += count;
|
|
33873
34615
|
}
|
|
33874
|
-
need7(
|
|
33875
|
-
const after =
|
|
34616
|
+
need7(readSync8(fd, Buffer.alloc(1), 0, 1, null) === 0);
|
|
34617
|
+
const after = fstatSync13(fd), current = lstatSync17(path, { throwIfNoEntry: false });
|
|
33876
34618
|
safe3(path);
|
|
33877
34619
|
need7(current && opened.dev === current.dev && opened.ino === current.ino && opened.mode === current.mode && opened.uid === current.uid && opened.size === current.size && opened.mtimeMs === current.mtimeMs && opened.ctimeMs === current.ctimeMs && current.nlink === 1 && opened.mode === after.mode && opened.uid === after.uid && after.nlink === 1 && opened.size === after.size && opened.mtimeMs === after.mtimeMs && opened.ctimeMs === after.ctimeMs);
|
|
33878
34620
|
const text2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
33879
34621
|
need7(Buffer.from(text2).equals(bytes));
|
|
33880
34622
|
return text2;
|
|
33881
34623
|
} finally {
|
|
33882
|
-
|
|
34624
|
+
closeSync13(fd);
|
|
33883
34625
|
}
|
|
33884
34626
|
}
|
|
33885
34627
|
function catalogDigest(text2) {
|
|
@@ -33887,7 +34629,7 @@ function catalogDigest(text2) {
|
|
|
33887
34629
|
try {
|
|
33888
34630
|
catalog = JSON.parse(text2);
|
|
33889
34631
|
} catch {
|
|
33890
|
-
return
|
|
34632
|
+
return refuse4();
|
|
33891
34633
|
}
|
|
33892
34634
|
need7(catalog && typeof catalog === "object" && !Array.isArray(catalog) && Object.keys(catalog).every((key) => ["version", "cwd", "skills", "plugins"].includes(key)) && typeof catalog.version === "string" && supportsCodexNativeCapability(catalog.version, "installed-plugin-review"));
|
|
33893
34635
|
const skills = projectCodexNativeSkillCatalog({ data: [{ cwd: catalog.cwd, errors: [], skills: catalog.skills }] }, catalog.cwd);
|
|
@@ -33895,32 +34637,32 @@ function catalogDigest(text2) {
|
|
|
33895
34637
|
return sha3(JSON.stringify({ version: catalog.version, cwd: catalog.cwd, skills, ...plugins === undefined ? {} : { plugins } }));
|
|
33896
34638
|
}
|
|
33897
34639
|
function retainedArtifactPath(metadata) {
|
|
33898
|
-
return
|
|
34640
|
+
return join22(metadata.storeRoot, "agent-discovery", "artifacts", metadata.sha256, "catalog.json");
|
|
33899
34641
|
}
|
|
33900
34642
|
function validRetainedArtifact(value) {
|
|
33901
|
-
return keys(value, ["version", "kind", "storeRoot", "originalPath", "sha256", "catalogSha256"]) && value.version === 1 && value.kind === "codex-native-catalog" && hex3(value.sha256) && hex3(value.catalogSha256) && [value.storeRoot, value.originalPath].every((path) => typeof path === "string" &&
|
|
34643
|
+
return keys(value, ["version", "kind", "storeRoot", "originalPath", "sha256", "catalogSha256"]) && value.version === 1 && value.kind === "codex-native-catalog" && hex3(value.sha256) && hex3(value.catalogSha256) && [value.storeRoot, value.originalPath].every((path) => typeof path === "string" && isAbsolute14(path) && resolve15(path) === path && path.length <= AGENT_POLICY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(path));
|
|
33902
34644
|
}
|
|
33903
34645
|
function privateStore(storeRoot) {
|
|
33904
34646
|
safe3(storeRoot);
|
|
33905
|
-
const stat =
|
|
34647
|
+
const stat = lstatSync17(storeRoot, { throwIfNoEntry: false });
|
|
33906
34648
|
need7(!stat || stat.isDirectory() && (stat.mode & 18) === 0 && (process.getuid === undefined || stat.uid === process.getuid()));
|
|
33907
34649
|
}
|
|
33908
34650
|
function verifyRetainedReviewArtifact(source, storeRoot) {
|
|
33909
34651
|
const artifact = source.reviewArtifact;
|
|
33910
|
-
need7(validRetainedArtifact(artifact) && source.hashMode === "bytes" && source.sha256 === artifact.sha256 && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && source.path === retainedArtifactPath(artifact) && (storeRoot === undefined || artifact.storeRoot ===
|
|
34652
|
+
need7(validRetainedArtifact(artifact) && source.hashMode === "bytes" && source.sha256 === artifact.sha256 && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && source.path === retainedArtifactPath(artifact) && (storeRoot === undefined || artifact.storeRoot === resolve15(storeRoot)));
|
|
33911
34653
|
privateStore(artifact.storeRoot);
|
|
33912
34654
|
const text2 = readExact(source.path);
|
|
33913
34655
|
need7(sha3(text2) === artifact.sha256 && catalogDigest(text2) === artifact.catalogSha256);
|
|
33914
|
-
for (let parent =
|
|
33915
|
-
const stat =
|
|
34656
|
+
for (let parent = dirname15(source.path);parent !== artifact.storeRoot; parent = dirname15(parent)) {
|
|
34657
|
+
const stat = lstatSync17(parent);
|
|
33916
34658
|
need7(stat.isDirectory() && (stat.mode & 63) === 0 && (process.getuid === undefined || stat.uid === process.getuid()));
|
|
33917
34659
|
}
|
|
33918
34660
|
}
|
|
33919
|
-
var sha3 = (bytes) =>
|
|
34661
|
+
var sha3 = (bytes) => createHash17("sha256").update(bytes).digest("hex"), hex3 = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), refuse4 = () => {
|
|
33920
34662
|
throw new Error("REVIEW_ARTIFACT_INVALID");
|
|
33921
34663
|
}, need7 = (condition) => {
|
|
33922
34664
|
if (!condition)
|
|
33923
|
-
|
|
34665
|
+
refuse4();
|
|
33924
34666
|
};
|
|
33925
34667
|
var init_retained_review_artifacts = __esm(() => {
|
|
33926
34668
|
init_agent_policy_limits();
|
|
@@ -33937,6 +34679,8 @@ var init_agent_integration = __esm(() => {
|
|
|
33937
34679
|
init_codex_native_skill_catalog();
|
|
33938
34680
|
init_codex_settings_witness();
|
|
33939
34681
|
init_claude_settings_witness();
|
|
34682
|
+
init_codex_native_compatibility();
|
|
34683
|
+
init_codex_semantic_cache_witness();
|
|
33940
34684
|
init_native_discovery_roots();
|
|
33941
34685
|
init_config();
|
|
33942
34686
|
init_managed_policy();
|
|
@@ -33987,12 +34731,12 @@ var init_skill_aliases = __esm(() => {
|
|
|
33987
34731
|
|
|
33988
34732
|
// src/lib/project-state.ts
|
|
33989
34733
|
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync5 } from "fs";
|
|
33990
|
-
import { join as
|
|
34734
|
+
import { join as join23 } from "path";
|
|
33991
34735
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
33992
|
-
return
|
|
34736
|
+
return join23(targetDir, SKILLS_PROJECT_DIR);
|
|
33993
34737
|
}
|
|
33994
34738
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
33995
|
-
return
|
|
34739
|
+
return join23(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
33996
34740
|
}
|
|
33997
34741
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
33998
34742
|
const path = getProjectConfigPath(targetDir);
|
|
@@ -34108,7 +34852,7 @@ var init_project_state = __esm(() => {
|
|
|
34108
34852
|
|
|
34109
34853
|
// src/lib/installer.ts
|
|
34110
34854
|
import { existsSync as existsSync10, readFileSync as readFileSync14, rmSync } from "fs";
|
|
34111
|
-
import { join as
|
|
34855
|
+
import { join as join24 } from "path";
|
|
34112
34856
|
import { homedir as homedir2 } from "os";
|
|
34113
34857
|
function getSkillPath(name) {
|
|
34114
34858
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
@@ -34118,7 +34862,7 @@ function getSkillPath(name) {
|
|
|
34118
34862
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
34119
34863
|
if (extensionPath)
|
|
34120
34864
|
return extensionPath;
|
|
34121
|
-
return
|
|
34865
|
+
return join24(getPortableSkillsRoot(), skillName);
|
|
34122
34866
|
}
|
|
34123
34867
|
function getCanonicalSkillName(name) {
|
|
34124
34868
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
@@ -34172,11 +34916,11 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
34172
34916
|
const base = projectDir || process.cwd();
|
|
34173
34917
|
switch (agent) {
|
|
34174
34918
|
case "pi":
|
|
34175
|
-
return scope === "project" ?
|
|
34919
|
+
return scope === "project" ? join24(base, ".pi", "skills") : join24(homedir2(), ".pi", "agent", "skills");
|
|
34176
34920
|
case "opencode":
|
|
34177
|
-
return scope === "project" ?
|
|
34921
|
+
return scope === "project" ? join24(base, ".opencode", "skills") : join24(homedir2(), ".config", "opencode", "skills");
|
|
34178
34922
|
default:
|
|
34179
|
-
return scope === "project" ?
|
|
34923
|
+
return scope === "project" ? join24(base, `.${agent}`, "skills") : join24(homedir2(), `.${agent}`, "skills");
|
|
34180
34924
|
}
|
|
34181
34925
|
}
|
|
34182
34926
|
function warnMissingDependencies(name, targetDir) {
|
|
@@ -34191,7 +34935,7 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
34191
34935
|
}
|
|
34192
34936
|
}
|
|
34193
34937
|
function readBundledSkillVersion(name) {
|
|
34194
|
-
const pkgPath =
|
|
34938
|
+
const pkgPath = join24(getSkillPath(name), "package.json");
|
|
34195
34939
|
if (!existsSync10(pkgPath))
|
|
34196
34940
|
return "unknown";
|
|
34197
34941
|
try {
|
|
@@ -34261,11 +35005,11 @@ var init_skill_doc_file = __esm(() => {
|
|
|
34261
35005
|
|
|
34262
35006
|
// src/lib/skillinfo.ts
|
|
34263
35007
|
import { existsSync as existsSync11, readFileSync as readFileSync15 } from "fs";
|
|
34264
|
-
import { join as
|
|
35008
|
+
import { join as join25 } from "path";
|
|
34265
35009
|
function isInstructionSkillDir(skillPath, meta3) {
|
|
34266
35010
|
if (meta3?.kind === "instruction")
|
|
34267
35011
|
return true;
|
|
34268
|
-
const skillMdPath =
|
|
35012
|
+
const skillMdPath = join25(skillPath, "SKILL.md");
|
|
34269
35013
|
if (!existsSync11(skillMdPath))
|
|
34270
35014
|
return false;
|
|
34271
35015
|
try {
|
|
@@ -34279,9 +35023,9 @@ function getSkillDocs(name) {
|
|
|
34279
35023
|
if (!existsSync11(skillPath))
|
|
34280
35024
|
return null;
|
|
34281
35025
|
return {
|
|
34282
|
-
skillMd: readIfExists(
|
|
34283
|
-
readme: readIfExists(
|
|
34284
|
-
claudeMd: readIfExists(
|
|
35026
|
+
skillMd: readIfExists(join25(skillPath, "SKILL.md")),
|
|
35027
|
+
readme: readIfExists(join25(skillPath, "README.md")),
|
|
35028
|
+
claudeMd: readIfExists(join25(skillPath, "CLAUDE.md"))
|
|
34285
35029
|
};
|
|
34286
35030
|
}
|
|
34287
35031
|
function getSkillBestDoc(name, file2) {
|
|
@@ -34297,14 +35041,14 @@ function getSkillRequirements(name) {
|
|
|
34297
35041
|
return null;
|
|
34298
35042
|
const texts = [];
|
|
34299
35043
|
for (const file2 of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
34300
|
-
const content = readIfExists(
|
|
35044
|
+
const content = readIfExists(join25(skillPath, file2));
|
|
34301
35045
|
if (content)
|
|
34302
35046
|
texts.push(content);
|
|
34303
35047
|
}
|
|
34304
35048
|
const meta3 = getSkill(name);
|
|
34305
35049
|
let dependencies = {};
|
|
34306
35050
|
try {
|
|
34307
|
-
dependencies = JSON.parse(readFileSync15(
|
|
35051
|
+
dependencies = JSON.parse(readFileSync15(join25(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
34308
35052
|
} catch {}
|
|
34309
35053
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta3);
|
|
34310
35054
|
}
|
|
@@ -34366,7 +35110,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
34366
35110
|
error: `Skill '${name}' is an instruction skill (kind: instruction) and is not runnable. Instruction skills are consumed by coding agents via SKILL.md, not executed with 'skills run'.`
|
|
34367
35111
|
};
|
|
34368
35112
|
}
|
|
34369
|
-
const pkgPath =
|
|
35113
|
+
const pkgPath = join25(skillPath, "package.json");
|
|
34370
35114
|
if (!existsSync11(pkgPath)) {
|
|
34371
35115
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
34372
35116
|
}
|
|
@@ -34386,12 +35130,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
34386
35130
|
} catch {
|
|
34387
35131
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
34388
35132
|
}
|
|
34389
|
-
const entryPath =
|
|
35133
|
+
const entryPath = join25(skillPath, entryPoint2);
|
|
34390
35134
|
if (!existsSync11(entryPath)) {
|
|
34391
35135
|
return { exitCode: 1, error: `Entry point '${entryPoint2}' not found in skill '${name}'` };
|
|
34392
35136
|
}
|
|
34393
35137
|
const env = { ...process.env, ...options.env };
|
|
34394
|
-
if (!existsSync11(
|
|
35138
|
+
if (!existsSync11(join25(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
|
|
34395
35139
|
const failure = await prepareSkillDependencies(skillPath, env, options.preparationTimeoutMs);
|
|
34396
35140
|
if (failure)
|
|
34397
35141
|
return failure;
|
|
@@ -34417,7 +35161,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
34417
35161
|
function detectProjectSkills(cwd = process.cwd()) {
|
|
34418
35162
|
let pkg;
|
|
34419
35163
|
try {
|
|
34420
|
-
pkg = JSON.parse(readFileSync15(
|
|
35164
|
+
pkg = JSON.parse(readFileSync15(join25(cwd, "package.json"), "utf8"));
|
|
34421
35165
|
} catch {
|
|
34422
35166
|
return { detected: [], recommended: [] };
|
|
34423
35167
|
}
|
|
@@ -34622,7 +35366,7 @@ var init_selection_resolver = __esm(() => {
|
|
|
34622
35366
|
});
|
|
34623
35367
|
|
|
34624
35368
|
// src/lib/plugin-projection.ts
|
|
34625
|
-
import { createHash as
|
|
35369
|
+
import { createHash as createHash18 } from "crypto";
|
|
34626
35370
|
function pluginRefusal(message) {
|
|
34627
35371
|
throw new SkillSelectionError("PLUGIN_ADMISSION_REFUSED", message);
|
|
34628
35372
|
}
|
|
@@ -34700,26 +35444,26 @@ function pluginFileWitnesses(entries) {
|
|
|
34700
35444
|
return { path: item.path, mode: item.mode, size: item.bytes.byteLength, sha256: pluginHash(item.bytes) };
|
|
34701
35445
|
});
|
|
34702
35446
|
}
|
|
34703
|
-
var PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) =>
|
|
35447
|
+
var PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash18("sha256").update(bytes).digest("hex");
|
|
34704
35448
|
var init_plugin_projection = __esm(() => {
|
|
34705
35449
|
init_selection_cache();
|
|
34706
35450
|
PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
|
|
34707
35451
|
});
|
|
34708
35452
|
|
|
34709
35453
|
// src/lib/plugin-projection-store.ts
|
|
34710
|
-
import { constants as
|
|
34711
|
-
import { dirname as
|
|
35454
|
+
import { constants as constants12, closeSync as closeSync14, fchmodSync, fstatSync as fstatSync14, fsyncSync as fsyncSync4, linkSync as linkSync2, lstatSync as lstatSync18, mkdirSync as mkdirSync7, openSync as openSync14, opendirSync as opendirSync2, readSync as readSync9, renameSync as renameSync2, rmdirSync as rmdirSync2, rmSync as rmSync2, unlinkSync as unlinkSync3, writeSync as writeSync3 } from "fs";
|
|
35455
|
+
import { dirname as dirname16, isAbsolute as isAbsolute15, join as join26, parse as parse10, resolve as resolve16 } from "path";
|
|
34712
35456
|
function stat(path) {
|
|
34713
35457
|
try {
|
|
34714
|
-
return
|
|
35458
|
+
return lstatSync18(path, { bigint: true });
|
|
34715
35459
|
} catch (error61) {
|
|
34716
35460
|
if (missing(error61))
|
|
34717
35461
|
return null;
|
|
34718
35462
|
return pluginRefusal("Cannot inspect plugin filesystem entry");
|
|
34719
35463
|
}
|
|
34720
35464
|
}
|
|
34721
|
-
function
|
|
34722
|
-
pluginNeed(typeof path === "string" && path.length <= 8192 &&
|
|
35465
|
+
function canonical8(path) {
|
|
35466
|
+
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute15(path) && resolve16(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
34723
35467
|
}
|
|
34724
35468
|
function owner(stats, system = false) {
|
|
34725
35469
|
const current = uid();
|
|
@@ -34729,12 +35473,12 @@ function same3(left, right, identityOnly = false) {
|
|
|
34729
35473
|
pluginNeed(right && left.dev === right.dev && left.ino === right.ino && left.mode === right.mode && left.uid === right.uid && left.gid === right.gid && (identityOnly || left.size === right.size && left.nlink === right.nlink && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs), "Plugin filesystem entry changed during access");
|
|
34730
35474
|
}
|
|
34731
35475
|
function ancestors(path, create = false) {
|
|
34732
|
-
|
|
34733
|
-
const result = [], parent =
|
|
35476
|
+
canonical8(path);
|
|
35477
|
+
const result = [], parent = dirname16(path), filesystemRoot = parse10(parent).root;
|
|
34734
35478
|
let current = filesystemRoot;
|
|
34735
35479
|
for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
|
|
34736
35480
|
if (segment)
|
|
34737
|
-
current =
|
|
35481
|
+
current = join26(current, segment);
|
|
34738
35482
|
let currentStat = stat(current);
|
|
34739
35483
|
if (!currentStat && create) {
|
|
34740
35484
|
try {
|
|
@@ -34780,19 +35524,19 @@ function readBytes(path, maximum, kind) {
|
|
|
34780
35524
|
fileShape(before, maximum, kind);
|
|
34781
35525
|
let fd;
|
|
34782
35526
|
try {
|
|
34783
|
-
fd =
|
|
34784
|
-
const opened =
|
|
35527
|
+
fd = openSync14(path, READ_FLAGS);
|
|
35528
|
+
const opened = fstatSync14(fd, { bigint: true });
|
|
34785
35529
|
same3(before, opened);
|
|
34786
35530
|
fileShape(opened, maximum, kind);
|
|
34787
35531
|
const bytes = new Uint8Array(Number(opened.size));
|
|
34788
35532
|
let offset = 0;
|
|
34789
35533
|
while (offset < bytes.byteLength) {
|
|
34790
|
-
const count =
|
|
35534
|
+
const count = readSync9(fd, bytes, offset, bytes.byteLength - offset, null);
|
|
34791
35535
|
pluginNeed(count > 0, "Plugin file changed while being read");
|
|
34792
35536
|
offset += count;
|
|
34793
35537
|
}
|
|
34794
|
-
pluginNeed(
|
|
34795
|
-
same3(opened,
|
|
35538
|
+
pluginNeed(readSync9(fd, new Uint8Array(1), 0, 1, null) === 0, "Plugin file grew while being read");
|
|
35539
|
+
same3(opened, fstatSync14(fd, { bigint: true }));
|
|
34796
35540
|
same3(opened, stat(path));
|
|
34797
35541
|
verifyAncestors(chain);
|
|
34798
35542
|
return bytes;
|
|
@@ -34802,7 +35546,7 @@ function readBytes(path, maximum, kind) {
|
|
|
34802
35546
|
return pluginRefusal("Cannot safely read plugin file");
|
|
34803
35547
|
} finally {
|
|
34804
35548
|
if (fd !== undefined)
|
|
34805
|
-
|
|
35549
|
+
closeSync14(fd);
|
|
34806
35550
|
}
|
|
34807
35551
|
}
|
|
34808
35552
|
function exactPaths(entries) {
|
|
@@ -34832,7 +35576,7 @@ function directoryNames(path) {
|
|
|
34832
35576
|
function snapshotPluginTree(root, options = {}) {
|
|
34833
35577
|
const chain = ancestors(root), entries = [], files = [], directories = [];
|
|
34834
35578
|
let bytes = 0, visited = 0;
|
|
34835
|
-
const visit3 = (directory,
|
|
35579
|
+
const visit3 = (directory, relative7) => {
|
|
34836
35580
|
const before = stat(directory);
|
|
34837
35581
|
pluginNeed(before && before.isDirectory() && !before.isSymbolicLink(), "Plugin tree must contain real directories");
|
|
34838
35582
|
const names = directoryNames(directory);
|
|
@@ -34840,18 +35584,18 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
34840
35584
|
directories.push({ path: directory, stat: before, names });
|
|
34841
35585
|
for (const name of names) {
|
|
34842
35586
|
pluginNeed(++visited <= PLUGIN_PROJECTION_LIMITS.files * 50, "Plugin tree membership exceeds its limit");
|
|
34843
|
-
const path =
|
|
35587
|
+
const path = relative7 ? `${relative7}/${name}` : name;
|
|
34844
35588
|
pluginNeed(new TextEncoder().encode(path).byteLength <= 100 && !/[\\:\x00-\x1f\x7f]/u.test(path), "Plugin entry path exceeds its limit or is unsafe");
|
|
34845
|
-
const absolute =
|
|
35589
|
+
const absolute = join26(directory, name), entryStat = stat(absolute);
|
|
34846
35590
|
pluginNeed(entryStat, "Plugin tree member disappeared");
|
|
34847
|
-
if (
|
|
35591
|
+
if (relative7 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
|
|
34848
35592
|
const bytes2 = readBytes(absolute, 32, "native-pin");
|
|
34849
35593
|
pluginNeed(/^[1-9][0-9]{12}$/.test(new TextDecoder().decode(bytes2)), "Malformed native orphan timestamp");
|
|
34850
35594
|
same3(entryStat, stat(absolute));
|
|
34851
35595
|
files.push({ path: absolute, stat: entryStat });
|
|
34852
35596
|
continue;
|
|
34853
35597
|
}
|
|
34854
|
-
if (
|
|
35598
|
+
if (relative7 === "" && name === ".in_use" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
|
|
34855
35599
|
pluginNeed(entryStat.isDirectory() && !entryStat.isSymbolicLink(), "Native plugin pins require a real directory");
|
|
34856
35600
|
owner(entryStat);
|
|
34857
35601
|
const pins = directoryNames(absolute);
|
|
@@ -34859,7 +35603,7 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
34859
35603
|
directories.push({ path: absolute, stat: entryStat, names: pins });
|
|
34860
35604
|
for (const pin of pins) {
|
|
34861
35605
|
pluginNeed(/^[1-9][0-9]{0,9}$/.test(pin) && Number(pin) <= 2147483647, "Unrecognized native plugin pin name");
|
|
34862
|
-
const pinPath =
|
|
35606
|
+
const pinPath = join26(absolute, pin), pinStat = stat(pinPath);
|
|
34863
35607
|
pluginNeed(pinStat, "Native plugin pin disappeared");
|
|
34864
35608
|
const bytes2 = readBytes(pinPath, 4096, "native-pin");
|
|
34865
35609
|
let value;
|
|
@@ -34925,8 +35669,8 @@ function readPluginJson(path) {
|
|
|
34925
35669
|
var READ_FLAGS, WRITE_FLAGS, uid = () => typeof process.getuid === "function" ? BigInt(process.getuid()) : undefined, missing = (error61) => Boolean(error61 && typeof error61 === "object" && "code" in error61 && error61.code === "ENOENT");
|
|
34926
35670
|
var init_plugin_projection_store = __esm(() => {
|
|
34927
35671
|
init_plugin_projection();
|
|
34928
|
-
READ_FLAGS =
|
|
34929
|
-
WRITE_FLAGS =
|
|
35672
|
+
READ_FLAGS = constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK;
|
|
35673
|
+
WRITE_FLAGS = constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW | constants12.O_NONBLOCK;
|
|
34930
35674
|
});
|
|
34931
35675
|
|
|
34932
35676
|
// src/lib/selected-manifest.ts
|
|
@@ -34956,7 +35700,7 @@ var init_selected_manifest = __esm(() => {
|
|
|
34956
35700
|
});
|
|
34957
35701
|
|
|
34958
35702
|
// src/lib/plugin-admission.ts
|
|
34959
|
-
import { isAbsolute as
|
|
35703
|
+
import { isAbsolute as isAbsolute16, join as join27, resolve as resolve17 } from "path";
|
|
34960
35704
|
function validatePluginTarget(value) {
|
|
34961
35705
|
pluginKeys(value, ["schemaVersion", "pluginId", "registrations", "native", "resolver"]);
|
|
34962
35706
|
pluginNeed(value.schemaVersion === 1, "Invalid plugin admission target");
|
|
@@ -34966,7 +35710,7 @@ function validatePluginTarget(value) {
|
|
|
34966
35710
|
for (const registration of value.registrations) {
|
|
34967
35711
|
pluginKeys(registration, ["scope", "projectPath"]);
|
|
34968
35712
|
pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
|
|
34969
|
-
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" &&
|
|
35713
|
+
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute16(registration.projectPath) && resolve17(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
|
|
34970
35714
|
const key = JSON.stringify([registration.scope, registration.projectPath]);
|
|
34971
35715
|
pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
|
|
34972
35716
|
scopes.add(key);
|
|
@@ -34974,7 +35718,7 @@ function validatePluginTarget(value) {
|
|
|
34974
35718
|
for (const key of ["native", "resolver"]) {
|
|
34975
35719
|
pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
|
|
34976
35720
|
pluginText(value[key].executable);
|
|
34977
|
-
pluginNeed(
|
|
35721
|
+
pluginNeed(isAbsolute16(value[key].executable) && resolve17(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
|
|
34978
35722
|
pluginDigest(value[key].digest);
|
|
34979
35723
|
}
|
|
34980
35724
|
pluginNeed(["2.1.274", "2.1.276"].includes(value.native.version), "Plugin admission requires a certified Claude command-source runtime (2.1.274 or 2.1.276)");
|
|
@@ -35117,12 +35861,12 @@ function pluginResolverCommand(binding) {
|
|
|
35117
35861
|
}
|
|
35118
35862
|
function pluginBindingPath(storeRoot, id) {
|
|
35119
35863
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
35120
|
-
return
|
|
35864
|
+
return join27(storeRoot, "bindings", `${id}.json`);
|
|
35121
35865
|
}
|
|
35122
|
-
function pluginReceiptPath(storeRoot, id,
|
|
35866
|
+
function pluginReceiptPath(storeRoot, id, digest2) {
|
|
35123
35867
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
35124
|
-
pluginDigest(
|
|
35125
|
-
return
|
|
35868
|
+
pluginDigest(digest2);
|
|
35869
|
+
return join27(storeRoot, "receipts", id, `${digest2.slice(7)}.json`);
|
|
35126
35870
|
}
|
|
35127
35871
|
function readPluginBinding(storeRoot, id) {
|
|
35128
35872
|
const value = readPluginJson(pluginBindingPath(storeRoot, id));
|
|
@@ -35131,18 +35875,18 @@ function readPluginBinding(storeRoot, id) {
|
|
|
35131
35875
|
pluginNeed(bindingId(binding) === id, "Plugin admission binding changed");
|
|
35132
35876
|
return binding;
|
|
35133
35877
|
}
|
|
35134
|
-
function readPluginAdmissionReceipt(storeRoot, id,
|
|
35135
|
-
const value = readPluginJson(pluginReceiptPath(storeRoot, id,
|
|
35878
|
+
function readPluginAdmissionReceipt(storeRoot, id, digest2) {
|
|
35879
|
+
const value = readPluginJson(pluginReceiptPath(storeRoot, id, digest2));
|
|
35136
35880
|
pluginKeys(value, ["schemaVersion", "plan", "materializedPath", "admittedAt"]);
|
|
35137
35881
|
pluginNeed(value.schemaVersion === 3, "Unsupported plugin admission receipt; schema version 3 is required");
|
|
35138
35882
|
validatePlan(value.plan);
|
|
35139
35883
|
const receipt = value;
|
|
35140
35884
|
receipt.plan.files = normalizedWitnesses(receipt.plan.files);
|
|
35141
35885
|
receipt.plan.removed = normalizedWitnesses(receipt.plan.removed);
|
|
35142
|
-
pluginNeed(receipt.plan.bindingId === id && receipt.plan.planDigest ===
|
|
35886
|
+
pluginNeed(receipt.plan.bindingId === id && receipt.plan.planDigest === digest2, "Plugin receipt identity differs from its filename");
|
|
35143
35887
|
const binding = readPluginBinding(storeRoot, id);
|
|
35144
35888
|
pluginNeed(canonicalJson(binding) === canonicalJson(receipt.plan.binding) && receipt.plan.sourceCommand === pluginResolverCommand(binding), "Plugin receipt binding changed");
|
|
35145
|
-
pluginNeed(receipt.materializedPath ===
|
|
35889
|
+
pluginNeed(receipt.materializedPath === join27(storeRoot, "objects", id, digest2.slice(7)), "Plugin receipt points outside its immutable materialization");
|
|
35146
35890
|
pluginText(receipt.admittedAt, 64);
|
|
35147
35891
|
pluginNeed(Number.isFinite(Date.parse(receipt.admittedAt)), "Invalid plugin admission time");
|
|
35148
35892
|
return receipt;
|
|
@@ -35159,8 +35903,8 @@ var init_plugin_admission = __esm(() => {
|
|
|
35159
35903
|
});
|
|
35160
35904
|
|
|
35161
35905
|
// src/lib/plugin-discovery.ts
|
|
35162
|
-
import { closeSync as
|
|
35163
|
-
import { basename as basename7, dirname as
|
|
35906
|
+
import { closeSync as closeSync15, constants as constants13, fstatSync as fstatSync15, lstatSync as lstatSync19, openSync as openSync15, opendirSync as opendirSync3, readSync as readSync10 } from "fs";
|
|
35907
|
+
import { basename as basename7, dirname as dirname17, isAbsolute as isAbsolute17, join as join28, resolve as resolve18 } from "path";
|
|
35164
35908
|
function validateManagedPluginWitnesses(value) {
|
|
35165
35909
|
pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
|
|
35166
35910
|
const seen = new Set;
|
|
@@ -35169,35 +35913,35 @@ function validateManagedPluginWitnesses(value) {
|
|
|
35169
35913
|
pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
|
|
35170
35914
|
seen.add(item.bindingId);
|
|
35171
35915
|
pluginText(item.storeRoot);
|
|
35172
|
-
pluginNeed(
|
|
35916
|
+
pluginNeed(isAbsolute17(item.storeRoot) && resolve18(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
|
|
35173
35917
|
}
|
|
35174
35918
|
}
|
|
35175
35919
|
function safe4(path) {
|
|
35176
35920
|
pluginText(path);
|
|
35177
|
-
pluginNeed(
|
|
35178
|
-
for (let at = path;; at =
|
|
35179
|
-
pluginNeed(!
|
|
35180
|
-
if (at ===
|
|
35921
|
+
pluginNeed(isAbsolute17(path) && resolve18(path) === path, "Invalid plugin registry path");
|
|
35922
|
+
for (let at = path;; at = dirname17(at)) {
|
|
35923
|
+
pluginNeed(!lstatSync19(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
35924
|
+
if (at === dirname17(at))
|
|
35181
35925
|
break;
|
|
35182
35926
|
}
|
|
35183
35927
|
}
|
|
35184
35928
|
function readRegistry(path) {
|
|
35185
35929
|
safe4(path);
|
|
35186
|
-
const initial =
|
|
35930
|
+
const initial = lstatSync19(path);
|
|
35187
35931
|
pluginNeed(initial.isFile() && initial.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
|
|
35188
|
-
const fd =
|
|
35932
|
+
const fd = openSync15(path, constants13.O_RDONLY | constants13.O_NOFOLLOW | constants13.O_NONBLOCK);
|
|
35189
35933
|
try {
|
|
35190
|
-
const opened =
|
|
35934
|
+
const opened = fstatSync15(fd);
|
|
35191
35935
|
pluginNeed(opened.isFile() && opened.ino === initial.ino && opened.dev === initial.dev, "Plugin registry changed during open");
|
|
35192
35936
|
const bytes = Buffer.alloc(1024 * 1024 + 1);
|
|
35193
35937
|
let length = 0;
|
|
35194
35938
|
while (length < bytes.length) {
|
|
35195
|
-
const count =
|
|
35939
|
+
const count = readSync10(fd, bytes, length, bytes.length - length, null);
|
|
35196
35940
|
if (!count)
|
|
35197
35941
|
break;
|
|
35198
35942
|
length += count;
|
|
35199
35943
|
}
|
|
35200
|
-
const after =
|
|
35944
|
+
const after = fstatSync15(fd), current = lstatSync19(path);
|
|
35201
35945
|
safe4(path);
|
|
35202
35946
|
pluginNeed(length <= 1024 * 1024 && length === opened.size && after.size === opened.size && after.mtimeMs === opened.mtimeMs && after.ctimeMs === opened.ctimeMs && current.dev === opened.dev && current.ino === opened.ino && current.mtimeMs === opened.mtimeMs && current.ctimeMs === opened.ctimeMs, "Plugin registry changed during read");
|
|
35203
35947
|
let value;
|
|
@@ -35209,7 +35953,7 @@ function readRegistry(path) {
|
|
|
35209
35953
|
pluginNeed(pluginObject(value) && value.version === 2 && pluginObject(value.plugins), "Unsupported native plugin registry schema");
|
|
35210
35954
|
return { value, rawDigest: pluginHash(bytes.subarray(0, length)) };
|
|
35211
35955
|
} finally {
|
|
35212
|
-
|
|
35956
|
+
closeSync15(fd);
|
|
35213
35957
|
}
|
|
35214
35958
|
}
|
|
35215
35959
|
function nativeVersionMatches(version2, receipt) {
|
|
@@ -35227,7 +35971,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
35227
35971
|
seen.add(target.pluginId);
|
|
35228
35972
|
const rows = plugins[target.pluginId];
|
|
35229
35973
|
pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
|
|
35230
|
-
const [name, market] = target.pluginId.split("@"), cacheRoot =
|
|
35974
|
+
const [name, market] = target.pluginId.split("@"), cacheRoot = join28(dirname17(path), "cache", market, name);
|
|
35231
35975
|
const scopes = new Set, approvals = new Map, currentFiles = new Map;
|
|
35232
35976
|
plugins[target.pluginId] = rows.map((row) => {
|
|
35233
35977
|
pluginNeed(pluginObject(row), "Invalid managed plugin registration");
|
|
@@ -35240,11 +35984,11 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
35240
35984
|
pluginText(row.sourceProducerPath);
|
|
35241
35985
|
pluginText(row.lastUpdated, 64);
|
|
35242
35986
|
pluginNeed(Number.isFinite(Date.parse(row.lastUpdated)), "Invalid managed plugin update timestamp");
|
|
35243
|
-
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath ===
|
|
35987
|
+
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join28(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
35244
35988
|
const approval = (producer) => {
|
|
35245
35989
|
pluginText(producer);
|
|
35246
|
-
const
|
|
35247
|
-
const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId,
|
|
35990
|
+
const digest2 = `sha256:${basename7(producer)}`;
|
|
35991
|
+
const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest2);
|
|
35248
35992
|
pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
|
|
35249
35993
|
if (!verified.has(producer)) {
|
|
35250
35994
|
verifiedBytes += receipt2.plan.files.reduce((total, file2) => total + file2.size, 0);
|
|
@@ -35270,7 +36014,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
35270
36014
|
return Object.fromEntries(Object.entries(row).filter(([key]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key)));
|
|
35271
36015
|
});
|
|
35272
36016
|
safe4(cacheRoot);
|
|
35273
|
-
const before =
|
|
36017
|
+
const before = lstatSync19(cacheRoot);
|
|
35274
36018
|
pluginNeed(before.isDirectory(), "Invalid managed plugin cache root");
|
|
35275
36019
|
const directory = opendirSync3(cacheRoot), names = [];
|
|
35276
36020
|
try {
|
|
@@ -35283,17 +36027,17 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
35283
36027
|
directory.closeSync();
|
|
35284
36028
|
}
|
|
35285
36029
|
for (const version2 of names.sort()) {
|
|
35286
|
-
const files = pluginFileWitnesses(snapshotPluginTree(
|
|
36030
|
+
const files = pluginFileWitnesses(snapshotPluginTree(join28(cacheRoot, version2), { nativeRuntime: `claude-${target.native.version}` }));
|
|
35287
36031
|
verifiedBytes += files.reduce((total, file2) => total + file2.size, 0);
|
|
35288
36032
|
pluginNeed(verifiedBytes <= 256 * 1024 * 1024, "Managed plugin verification exceeds its aggregate byte budget");
|
|
35289
36033
|
const serialized = JSON.stringify(files);
|
|
35290
|
-
const expected = currentFiles.get(
|
|
36034
|
+
const expected = currentFiles.get(join28(cacheRoot, version2));
|
|
35291
36035
|
pluginNeed(expected === undefined || serialized === expected, "Current native cache differs from its exact registered producer receipt");
|
|
35292
36036
|
pluginNeed([...approvals.values()].some((receipt) => nativeVersionMatches(version2, receipt) && JSON.stringify(receipt.plan.files) === serialized), "A retained native plugin cache version differs from every approved projection");
|
|
35293
36037
|
}
|
|
35294
36038
|
for (const row of rows)
|
|
35295
36039
|
pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
|
|
35296
|
-
const after =
|
|
36040
|
+
const after = lstatSync19(cacheRoot);
|
|
35297
36041
|
safe4(cacheRoot);
|
|
35298
36042
|
pluginNeed(before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs, "Managed cache version membership changed during verification");
|
|
35299
36043
|
}
|
|
@@ -35307,23 +36051,23 @@ var init_plugin_discovery = __esm(() => {
|
|
|
35307
36051
|
});
|
|
35308
36052
|
|
|
35309
36053
|
// src/lib/claude-marketplace-registry.ts
|
|
35310
|
-
import { createHash as
|
|
35311
|
-
import { closeSync as
|
|
35312
|
-
import { basename as basename8, dirname as
|
|
36054
|
+
import { createHash as createHash19 } from "crypto";
|
|
36055
|
+
import { closeSync as closeSync16, constants as constants14, fstatSync as fstatSync16, lstatSync as lstatSync20, openSync as openSync16, readSync as readSync11 } from "fs";
|
|
36056
|
+
import { basename as basename8, dirname as dirname18, isAbsolute as isAbsolute18, resolve as resolve19 } from "path";
|
|
35313
36057
|
function need8(value, reason2) {
|
|
35314
36058
|
if (!value)
|
|
35315
36059
|
throw new Error(`Claude marketplace registry ${reason2}`);
|
|
35316
36060
|
}
|
|
35317
36061
|
function absolutePath4(value) {
|
|
35318
|
-
need8(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) &&
|
|
36062
|
+
need8(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute18(value) && resolve19(value) === value, "requires a normalized absolute path");
|
|
35319
36063
|
}
|
|
35320
36064
|
function parents2(path) {
|
|
35321
36065
|
const result = [];
|
|
35322
|
-
for (let at =
|
|
35323
|
-
const stat2 =
|
|
36066
|
+
for (let at = dirname18(path);; at = dirname18(at)) {
|
|
36067
|
+
const stat2 = lstatSync20(at, { bigint: true });
|
|
35324
36068
|
need8(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
35325
36069
|
result.push([at, stat2]);
|
|
35326
|
-
if (at ===
|
|
36070
|
+
if (at === dirname18(at))
|
|
35327
36071
|
return result;
|
|
35328
36072
|
}
|
|
35329
36073
|
}
|
|
@@ -35331,25 +36075,25 @@ function readRegistry2(path, budget2) {
|
|
|
35331
36075
|
absolutePath4(path);
|
|
35332
36076
|
need8(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
35333
36077
|
need8(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
35334
|
-
const ancestors2 = parents2(path), initial =
|
|
36078
|
+
const ancestors2 = parents2(path), initial = lstatSync20(path, { bigint: true });
|
|
35335
36079
|
need8(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
35336
36080
|
need8(initial.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
|
|
35337
|
-
const fd =
|
|
36081
|
+
const fd = openSync16(path, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
|
|
35338
36082
|
try {
|
|
35339
|
-
const opened =
|
|
36083
|
+
const opened = fstatSync16(fd, { bigint: true });
|
|
35340
36084
|
need8(opened.isFile() && sameFile2(initial, opened), "changed during open");
|
|
35341
36085
|
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
35342
36086
|
let length = 0;
|
|
35343
36087
|
while (length < bytes.length) {
|
|
35344
|
-
const count =
|
|
36088
|
+
const count = readSync11(fd, bytes, length, bytes.length - length, null);
|
|
35345
36089
|
if (!count)
|
|
35346
36090
|
break;
|
|
35347
36091
|
length += count;
|
|
35348
36092
|
}
|
|
35349
|
-
const after =
|
|
36093
|
+
const after = fstatSync16(fd, { bigint: true }), current = lstatSync20(path, { bigint: true });
|
|
35350
36094
|
need8(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
35351
36095
|
for (const [ancestor, before] of ancestors2) {
|
|
35352
|
-
const now =
|
|
36096
|
+
const now = lstatSync20(ancestor, { bigint: true });
|
|
35353
36097
|
need8(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
35354
36098
|
}
|
|
35355
36099
|
budget2.remaining -= length;
|
|
@@ -35359,7 +36103,7 @@ function readRegistry2(path, budget2) {
|
|
|
35359
36103
|
throw new Error("Claude marketplace registry is not strict UTF-8");
|
|
35360
36104
|
}
|
|
35361
36105
|
} finally {
|
|
35362
|
-
|
|
36106
|
+
closeSync16(fd);
|
|
35363
36107
|
}
|
|
35364
36108
|
}
|
|
35365
36109
|
function parse11(text2) {
|
|
@@ -35436,7 +36180,7 @@ function parse11(text2) {
|
|
|
35436
36180
|
need8(root.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
|
|
35437
36181
|
return root;
|
|
35438
36182
|
}
|
|
35439
|
-
function
|
|
36183
|
+
function exactKeys2(value, keys2) {
|
|
35440
36184
|
return value?.kind === "object" && value.entries.length === keys2.length && value.entries.every(([key]) => keys2.includes(key));
|
|
35441
36185
|
}
|
|
35442
36186
|
function textField(value) {
|
|
@@ -35444,8 +36188,8 @@ function textField(value) {
|
|
|
35444
36188
|
return value.value;
|
|
35445
36189
|
}
|
|
35446
36190
|
function normalizeRow(row, version2 = 1) {
|
|
35447
|
-
if (!
|
|
35448
|
-
if (version2 !== 2 || !
|
|
36191
|
+
if (!exactKeys2(row, ["source", "installLocation", "lastUpdated"])) {
|
|
36192
|
+
if (version2 !== 2 || !exactKeys2(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
|
|
35449
36193
|
return;
|
|
35450
36194
|
const autoUpdate = field2(row, "autoUpdate");
|
|
35451
36195
|
need8(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
|
|
@@ -35457,7 +36201,7 @@ function normalizeRow(row, version2 = 1) {
|
|
|
35457
36201
|
if (type?.kind !== "string" || !["github", "directory"].includes(type.value))
|
|
35458
36202
|
return;
|
|
35459
36203
|
const location = type.value === "github" ? "repo" : "path";
|
|
35460
|
-
if (!
|
|
36204
|
+
if (!exactKeys2(source, ["source", location]))
|
|
35461
36205
|
return;
|
|
35462
36206
|
const sourceLocation = textField(field2(source, location));
|
|
35463
36207
|
if (type.value === "directory")
|
|
@@ -35473,14 +36217,14 @@ function captureClaudeMarketplaceRegistry(path, budget2 = { remaining: 256 * 102
|
|
|
35473
36217
|
const value = parse11(readRegistry2(path, budget2));
|
|
35474
36218
|
for (const [, row] of value.entries)
|
|
35475
36219
|
normalizeRow(row);
|
|
35476
|
-
const sha2562 =
|
|
36220
|
+
const sha2562 = createHash19("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
35477
36221
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
35478
36222
|
}
|
|
35479
36223
|
function captureClaudeMarketplaceRegistryV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
35480
36224
|
const value = parse11(readRegistry2(path, budget2));
|
|
35481
36225
|
for (const [, row] of value.entries)
|
|
35482
36226
|
normalizeRow(row, 2);
|
|
35483
|
-
const sha2562 =
|
|
36227
|
+
const sha2562 = createHash19("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
35484
36228
|
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
|
|
35485
36229
|
}
|
|
35486
36230
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, field2 = (object6, key) => object6.entries.find(([name]) => name === key)?.[1];
|
|
@@ -35502,7 +36246,7 @@ var init_codex_hook_additions_review = __esm(() => {
|
|
|
35502
36246
|
});
|
|
35503
36247
|
|
|
35504
36248
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
35505
|
-
import { createHash as
|
|
36249
|
+
import { createHash as createHash20 } from "crypto";
|
|
35506
36250
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
35507
36251
|
const proof = proofs2.get(witness);
|
|
35508
36252
|
need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === discoveryDigest(binding), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
@@ -35517,7 +36261,7 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
35517
36261
|
need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
35518
36262
|
return true;
|
|
35519
36263
|
}
|
|
35520
|
-
var sha4 = (text2) =>
|
|
36264
|
+
var sha4 = (text2) => createHash20("sha256").update(text2).digest("hex"), fields, discoveryDigest = (binding) => {
|
|
35521
36265
|
const controls = binding.codexDisabledPluginSkills;
|
|
35522
36266
|
if (!Object.hasOwn(binding, "codexDisabledPluginSkills") || Array.isArray(controls) && controls.length === 0) {
|
|
35523
36267
|
const { codexDisabledPluginSkills: _controls, ...withoutControls } = binding;
|
|
@@ -35535,16 +36279,16 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
35535
36279
|
});
|
|
35536
36280
|
|
|
35537
36281
|
// src/lib/agent-discovery.ts
|
|
35538
|
-
import { createHash as
|
|
35539
|
-
import { lstatSync as
|
|
35540
|
-
import { basename as basename9, dirname as
|
|
36282
|
+
import { createHash as createHash21 } from "crypto";
|
|
36283
|
+
import { lstatSync as lstatSync21, readFileSync as readFileSync16, readdirSync as readdirSync8, realpathSync as realpathSync8 } from "fs";
|
|
36284
|
+
import { basename as basename9, dirname as dirname19, isAbsolute as isAbsolute19, join as join29, relative as relative7, resolve as resolve20, sep as sep9 } from "path";
|
|
35541
36285
|
import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
35542
36286
|
function discoveryExecutable(agent) {
|
|
35543
36287
|
const command = DISCOVERY_RUNTIME_COMMANDS[agent];
|
|
35544
36288
|
const found = command ? Bun.which(command) : null;
|
|
35545
36289
|
if (!command || !found)
|
|
35546
36290
|
return null;
|
|
35547
|
-
const path =
|
|
36291
|
+
const path = resolve20(found), target = realpathOrNull(path);
|
|
35548
36292
|
return target === null ? null : { command, path, target };
|
|
35549
36293
|
}
|
|
35550
36294
|
function parseConfig(text2, path, toml = false) {
|
|
@@ -35558,12 +36302,12 @@ function parseConfig(text2, path, toml = false) {
|
|
|
35558
36302
|
}
|
|
35559
36303
|
}
|
|
35560
36304
|
function safe5(path) {
|
|
35561
|
-
if (!
|
|
36305
|
+
if (!isAbsolute19(path) || path.includes("\x00"))
|
|
35562
36306
|
throw new Error("Expected an absolute native discovery path");
|
|
35563
|
-
for (let cursor = path;; cursor =
|
|
35564
|
-
if (
|
|
36307
|
+
for (let cursor = path;; cursor = dirname19(cursor)) {
|
|
36308
|
+
if (lstatSync21(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
35565
36309
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
35566
|
-
if (
|
|
36310
|
+
if (dirname19(cursor) === cursor)
|
|
35567
36311
|
break;
|
|
35568
36312
|
}
|
|
35569
36313
|
}
|
|
@@ -35571,27 +36315,27 @@ function read(path, changes) {
|
|
|
35571
36315
|
safe5(path);
|
|
35572
36316
|
if (changes?.has(path))
|
|
35573
36317
|
return changes.get(path);
|
|
35574
|
-
const stat2 =
|
|
36318
|
+
const stat2 = lstatSync21(path, { throwIfNoEntry: false });
|
|
35575
36319
|
if (!stat2)
|
|
35576
36320
|
return null;
|
|
35577
36321
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
35578
36322
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
35579
36323
|
return readFileSync16(path, "utf8");
|
|
35580
36324
|
}
|
|
35581
|
-
function assertReviewedClaudeCacheClosures(home, config2, review,
|
|
36325
|
+
function assertReviewedClaudeCacheClosures(home, config2, review, canonical9) {
|
|
35582
36326
|
const enabledIds = Object.entries(config2.enabledPlugins ?? {}).filter(([, enabled]) => enabled === true).map(([id]) => id);
|
|
35583
36327
|
if (enabledIds.length === 0)
|
|
35584
36328
|
return;
|
|
35585
|
-
const registryPath =
|
|
35586
|
-
const cacheAliasRoot =
|
|
35587
|
-
const cacheRoot =
|
|
36329
|
+
const registryPath = canonical9(join29(home, ".claude/plugins/installed_plugins.json"));
|
|
36330
|
+
const cacheAliasRoot = join29(home, ".claude/plugins/cache");
|
|
36331
|
+
const cacheRoot = canonical9(cacheAliasRoot);
|
|
35588
36332
|
const registryText = read(registryPath);
|
|
35589
36333
|
if (registryText === null)
|
|
35590
36334
|
return;
|
|
35591
36335
|
const registry2 = parseConfig(registryText, registryPath);
|
|
35592
36336
|
if (registry2.version !== 2 || !registry2.plugins || typeof registry2.plugins !== "object" || Array.isArray(registry2.plugins))
|
|
35593
36337
|
throw new Error("Reviewed Claude installed plugin registrations are invalid");
|
|
35594
|
-
const cachePath = (path) => typeof path === "string" &&
|
|
36338
|
+
const cachePath = (path) => typeof path === "string" && isAbsolute19(path) && resolve20(path) === path && [cacheAliasRoot, cacheRoot].some((root) => path === root || path.startsWith(root + sep9));
|
|
35595
36339
|
const activeRoots = new Set;
|
|
35596
36340
|
for (const id of enabledIds) {
|
|
35597
36341
|
const rows = registry2.plugins[id];
|
|
@@ -35603,13 +36347,13 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical8) {
|
|
|
35603
36347
|
if (!row || typeof row !== "object" || Array.isArray(row) || typeof row.installPath !== "string") {
|
|
35604
36348
|
throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
|
|
35605
36349
|
}
|
|
35606
|
-
if ([cacheAliasRoot, cacheRoot].some((root) => row.installPath === root || row.installPath.startsWith(root +
|
|
36350
|
+
if ([cacheAliasRoot, cacheRoot].some((root) => row.installPath === root || row.installPath.startsWith(root + sep9))) {
|
|
35607
36351
|
if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename9(row.installPath) !== row.version)) {
|
|
35608
36352
|
throw new Error("Reviewed Claude discovery has a malformed active cache registration");
|
|
35609
36353
|
}
|
|
35610
|
-
if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" &&
|
|
36354
|
+
if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" && isAbsolute19(row.projectPath) && resolve20(row.projectPath) === row.projectPath && row.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters) {} else
|
|
35611
36355
|
throw new Error("Reviewed Claude discovery has an unsupported active cache registration scope");
|
|
35612
|
-
activeRoots.add(
|
|
36356
|
+
activeRoots.add(canonical9(row.installPath));
|
|
35613
36357
|
}
|
|
35614
36358
|
}
|
|
35615
36359
|
}
|
|
@@ -35625,11 +36369,11 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical8) {
|
|
|
35625
36369
|
};
|
|
35626
36370
|
for (const root of activeRoots) {
|
|
35627
36371
|
safe5(root);
|
|
35628
|
-
const rootStat =
|
|
35629
|
-
if (!rootStat?.isDirectory() ||
|
|
36372
|
+
const rootStat = lstatSync21(root, { throwIfNoEntry: false });
|
|
36373
|
+
if (!rootStat?.isDirectory() || realpathSync8(root) !== root)
|
|
35630
36374
|
throw new Error("Reviewed Claude active cache plugin root is missing or unsafe");
|
|
35631
|
-
const manifestPath =
|
|
35632
|
-
const manifestStat =
|
|
36375
|
+
const manifestPath = join29(root, ".claude-plugin/plugin.json");
|
|
36376
|
+
const manifestStat = lstatSync21(manifestPath, { throwIfNoEntry: false });
|
|
35633
36377
|
let manifest;
|
|
35634
36378
|
if (manifestStat) {
|
|
35635
36379
|
if (!manifestStat.isFile())
|
|
@@ -35644,37 +36388,37 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical8) {
|
|
|
35644
36388
|
} else if (!review.sources.some((source) => source.path === manifestPath && source.hashMode === "path-bytes" && source.sha256 !== null && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined)) {
|
|
35645
36389
|
throw new Error("Reviewed Claude active cache plugin manifest absence requires a path-bytes witness");
|
|
35646
36390
|
}
|
|
35647
|
-
const roots = new Set([
|
|
35648
|
-
if (
|
|
36391
|
+
const roots = new Set([join29(root, "skills")]);
|
|
36392
|
+
if (lstatSync21(join29(root, "SKILL.md"), { throwIfNoEntry: false })?.isFile())
|
|
35649
36393
|
roots.add(root);
|
|
35650
36394
|
const declared = manifest?.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
35651
36395
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
35652
36396
|
throw new Error("Reviewed Claude active cache plugin has unsupported skill paths");
|
|
35653
36397
|
for (const value of declared) {
|
|
35654
|
-
const path =
|
|
35655
|
-
if (path !== root && !path.startsWith(root +
|
|
36398
|
+
const path = resolve20(root, value);
|
|
36399
|
+
if (path !== root && !path.startsWith(root + sep9))
|
|
35656
36400
|
throw new Error("Reviewed Claude active cache plugin skill path escapes its root");
|
|
35657
|
-
roots.add(path.endsWith(`${
|
|
36401
|
+
roots.add(path.endsWith(`${sep9}SKILL.md`) ? dirname19(path) : path);
|
|
35658
36402
|
}
|
|
35659
36403
|
for (const skillRoot of roots)
|
|
35660
36404
|
if (!review.roots.includes(skillRoot))
|
|
35661
36405
|
throw new Error("Reviewed Claude active cache plugin skill root is not covered");
|
|
35662
|
-
const hooksPath =
|
|
35663
|
-
const hooksStat =
|
|
36406
|
+
const hooksPath = join29(root, "hooks/hooks.json");
|
|
36407
|
+
const hooksStat = lstatSync21(hooksPath, { throwIfNoEntry: false });
|
|
35664
36408
|
if (hooksStat) {
|
|
35665
36409
|
if (!hooksStat.isFile())
|
|
35666
36410
|
throw new Error("Reviewed Claude plugin hook manifest is unsupported");
|
|
35667
36411
|
requireSource(hooksPath, "hook manifest");
|
|
35668
36412
|
}
|
|
35669
36413
|
if (typeof manifest?.hooks === "string")
|
|
35670
|
-
requireSource(
|
|
36414
|
+
requireSource(resolve20(root, manifest.hooks), "manifest-declared hook source");
|
|
35671
36415
|
}
|
|
35672
36416
|
}
|
|
35673
36417
|
function projectNativeDiscoveryFields(text2, format, fields2, path) {
|
|
35674
36418
|
const object6 = format === "yaml" ? parseHermesConfig(text2) : parseConfig(text2, path, format === "toml");
|
|
35675
36419
|
if (!object6 || typeof object6 !== "object" || Array.isArray(object6))
|
|
35676
36420
|
throw new Error("Expected native discovery configuration object");
|
|
35677
|
-
return
|
|
36421
|
+
return digest2(JSON.stringify(Object.fromEntries(fields2.map((field3) => [field3, object6[field3] ?? null]))));
|
|
35678
36422
|
}
|
|
35679
36423
|
function isSupersededSettingsProjection(agent, configPath, source) {
|
|
35680
36424
|
if (agent === "sumi")
|
|
@@ -35684,7 +36428,7 @@ function isSupersededSettingsProjection(agent, configPath, source) {
|
|
|
35684
36428
|
function supersedesSettingsProjection(agent, sources, configPath) {
|
|
35685
36429
|
if (agent === "sumi")
|
|
35686
36430
|
return sources.some((source) => source.path === configPath && source.hashMode === "sumi-settings-v1");
|
|
35687
|
-
return agent === "codex" && sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")));
|
|
36431
|
+
return agent === "codex" && sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4" || source.hashMode === "codex-settings-v5")));
|
|
35688
36432
|
}
|
|
35689
36433
|
function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
35690
36434
|
if (source.reviewArtifact !== undefined)
|
|
@@ -35697,13 +36441,13 @@ function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
|
35697
36441
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
35698
36442
|
return changes?.has(source.path) ? hashSumiSettingsReplacement(changes.get(source.path), budget2) : current;
|
|
35699
36443
|
}
|
|
35700
|
-
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) {
|
|
36444
|
+
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")) {
|
|
35701
36445
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
35702
36446
|
throw new Error("Codex settings witnesses require exact typed metadata");
|
|
35703
|
-
const current = (source.hashMode === "codex-settings-v4" ? captureCodexSettingsV4 : source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget2).sha256;
|
|
36447
|
+
const current = (source.hashMode === "codex-settings-v5" ? captureCodexSettingsV5 : source.hashMode === "codex-settings-v4" ? captureCodexSettingsV4 : source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget2).sha256;
|
|
35704
36448
|
if (current !== source.sha256)
|
|
35705
36449
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
35706
|
-
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
36450
|
+
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v5" ? hashCodexSettingsReplacementV5 : source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget2) : current;
|
|
35707
36451
|
}
|
|
35708
36452
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) {
|
|
35709
36453
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
@@ -35755,7 +36499,7 @@ function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
|
35755
36499
|
if (text2 === null)
|
|
35756
36500
|
return null;
|
|
35757
36501
|
if (!source.format)
|
|
35758
|
-
return
|
|
36502
|
+
return digest2(text2);
|
|
35759
36503
|
return projectNativeDiscoveryFields(text2, source.format, source.fields ?? [], source.path);
|
|
35760
36504
|
}
|
|
35761
36505
|
function absentCodexSkillRoots(binding) {
|
|
@@ -35764,18 +36508,18 @@ function absentCodexSkillRoots(binding) {
|
|
|
35764
36508
|
return [];
|
|
35765
36509
|
if (binding.agent !== "codex" || !Array.isArray(controls) || controls.length > 4096)
|
|
35766
36510
|
throw new Error("Invalid disabled Codex discovery proof");
|
|
35767
|
-
if (binding.method !== "reviewed" || controls.every((control) =>
|
|
36511
|
+
if (binding.method !== "reviewed" || controls.every((control) => lstatSync21(control.pluginParent, { throwIfNoEntry: false })))
|
|
35768
36512
|
return [];
|
|
35769
|
-
const cache =
|
|
36513
|
+
const cache = dirname19(dirname19(controls[0].pluginParent)), config2 = join29(dirname19(dirname19(cache)), "config.toml");
|
|
35770
36514
|
const source = binding.sources.find((source2) => source2.path === config2 && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
35771
36515
|
if (!source || projected(source) !== source.sha256)
|
|
35772
36516
|
throw new Error("Missing current disabled Codex configuration witness");
|
|
35773
36517
|
const rules = Bun.TOML.parse(read(config2)).skills?.config ?? [];
|
|
35774
36518
|
return [...new Set(controls.map((control) => control.pluginParent))].filter((parent) => !codexDirectHookSelects(cache, parent) && absentDisabledCodexPluginParent(cache, parent, controls, rules));
|
|
35775
36519
|
}
|
|
35776
|
-
function codexDirectHookSelects(cache, root) {
|
|
35777
|
-
const codex =
|
|
35778
|
-
const hooks = read(
|
|
36520
|
+
function codexDirectHookSelects(cache, root, configPath = join29(dirname19(dirname19(cache)), "config.toml")) {
|
|
36521
|
+
const codex = dirname19(configPath), config2 = Bun.TOML.parse(read(configPath) ?? "");
|
|
36522
|
+
const hooks = read(join29(codex, "hooks.json"));
|
|
35779
36523
|
if (hooks !== null)
|
|
35780
36524
|
hashNativeJsonControls(hooks);
|
|
35781
36525
|
return JSON.stringify(config2.hooks ?? {}).includes(root) || hooks !== null && JSON.stringify(JSON.parse(hooks)).includes(root);
|
|
@@ -35787,7 +36531,7 @@ function retiredCodexRoots(binding) {
|
|
|
35787
36531
|
const controls = binding.codexDisabledPluginSkills;
|
|
35788
36532
|
if (binding.agent !== "codex" || binding.method !== "reviewed" || !Array.isArray(controls) || !controls.length || !Array.isArray(proof.roots) || proof.roots.length > AGENT_POLICY_LIMITS.discoveryRoots || new Set(proof.roots).size !== proof.roots.length || !Array.isArray(proof.directories) || proof.parents !== undefined && (!Array.isArray(proof.parents) || proof.parents.length > AGENT_POLICY_LIMITS.discoveryRoots || new Set(proof.parents).size !== proof.parents.length) || !proof.roots.length && !proof.parents?.length)
|
|
35789
36533
|
throw new Error("Invalid retired Codex materialization proof");
|
|
35790
|
-
const cache =
|
|
36534
|
+
const cache = dirname19(dirname19(controls[0].pluginParent)), config2 = join29(dirname19(dirname19(cache)), "config.toml");
|
|
35791
36535
|
const source = binding.sources.find((source2) => source2.path === config2 && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
35792
36536
|
if (!source || projected(source) !== source.sha256)
|
|
35793
36537
|
throw new Error("Missing current retired Codex configuration witness");
|
|
@@ -35795,7 +36539,7 @@ function retiredCodexRoots(binding) {
|
|
|
35795
36539
|
if ((proof.parents ?? []).some((parent) => codexDirectHookSelects(cache, parent) || !reviewedDisabledCodexPluginParent(cache, parent, controls, rules)) || !reviewedCodexPluginCapabilitiesUnchanged(cache, controls, (path) => read(path), rules))
|
|
35796
36540
|
throw new Error("Retired Codex parent capabilities changed");
|
|
35797
36541
|
for (const root of proof.roots) {
|
|
35798
|
-
const manifest = binding.sources.find((source2) => source2.path ===
|
|
36542
|
+
const manifest = binding.sources.find((source2) => source2.path === join29(root, ".codex-plugin/plugin.json") && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && [undefined, "bytes"].includes(source2.hashMode));
|
|
35799
36543
|
if (!manifest || codexDirectHookSelects(cache, root) || !reviewedRetiredCodexRoot(cache, root, controls, rules, (path) => read(path), true))
|
|
35800
36544
|
throw new Error("Retired Codex materialization changed");
|
|
35801
36545
|
}
|
|
@@ -35804,7 +36548,7 @@ function retiredCodexRoots(binding) {
|
|
|
35804
36548
|
function retainableAbsentSource(source) {
|
|
35805
36549
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined)
|
|
35806
36550
|
return false;
|
|
35807
|
-
return [undefined, "bytes"].includes(source.hashMode) || source.hashMode === "claude-plugin-manifest-v1" && source.sha256 !== null && source.path.endsWith(
|
|
36551
|
+
return [undefined, "bytes"].includes(source.hashMode) || source.hashMode === "claude-plugin-manifest-v1" && source.sha256 !== null && source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json"));
|
|
35808
36552
|
}
|
|
35809
36553
|
function absentRetiredClaudeRoots(binding) {
|
|
35810
36554
|
if (binding.agent !== "claude" || binding.method !== "reviewed")
|
|
@@ -35813,17 +36557,17 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
35813
36557
|
for (const source of binding.sources) {
|
|
35814
36558
|
if (!retainableAbsentSource(source) || source.sha256 === null)
|
|
35815
36559
|
continue;
|
|
35816
|
-
const marker =
|
|
36560
|
+
const marker = sep9 + ".claude" + sep9 + "plugins" + sep9 + "cache" + sep9, at = source.path.indexOf(marker);
|
|
35817
36561
|
if (at < 0 || source.path.indexOf(marker, at + 1) >= 0)
|
|
35818
36562
|
continue;
|
|
35819
|
-
const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(
|
|
36563
|
+
const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(sep9);
|
|
35820
36564
|
if (parts.length < 4 || parts.slice(0, 3).some((part) => !part || part === "." || part === ".."))
|
|
35821
36565
|
continue;
|
|
35822
|
-
const root =
|
|
36566
|
+
const root = join29(cache, ...parts.slice(0, 3));
|
|
35823
36567
|
safe5(root);
|
|
35824
|
-
if (
|
|
36568
|
+
if (lstatSync21(root, { throwIfNoEntry: false }))
|
|
35825
36569
|
continue;
|
|
35826
|
-
const claude =
|
|
36570
|
+
const claude = dirname19(dirname19(cache)), settings = join29(claude, "settings.json"), registry2 = join29(claude, "plugins/installed_plugins.json");
|
|
35827
36571
|
const full = (path) => binding.sources.find((item) => item.path === path && item.sha256 !== null && item.format === undefined && item.fields === undefined);
|
|
35828
36572
|
const configSource = full(settings), registrySource = full(registry2);
|
|
35829
36573
|
if (!configSource || !registrySource || projected(configSource) !== configSource.sha256 || projected(registrySource) !== registrySource.sha256)
|
|
@@ -35840,15 +36584,15 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
35840
36584
|
if (!row || typeof row !== "object" || Array.isArray(row))
|
|
35841
36585
|
return null;
|
|
35842
36586
|
const value = row;
|
|
35843
|
-
if (typeof value.installPath !== "string" || /[\x00-\x1f\x7f]/.test(value.installPath) || !
|
|
36587
|
+
if (typeof value.installPath !== "string" || /[\x00-\x1f\x7f]/.test(value.installPath) || !isAbsolute19(value.installPath) || resolve20(value.installPath) !== value.installPath || value.installPath.length > AGENT_POLICY_LIMITS.pathCharacters)
|
|
35844
36588
|
return null;
|
|
35845
36589
|
if (value.scope === "user")
|
|
35846
36590
|
return value.projectPath === undefined || value.projectPath === null ? "user\x00" : null;
|
|
35847
36591
|
if (value.scope === "project")
|
|
35848
|
-
return typeof value.projectPath === "string" && !/[\x00-\x1f\x7f]/.test(value.projectPath) && value.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters &&
|
|
36592
|
+
return typeof value.projectPath === "string" && !/[\x00-\x1f\x7f]/.test(value.projectPath) && value.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute19(value.projectPath) && resolve20(value.projectPath) === value.projectPath ? `project\x00${value.projectPath}` : null;
|
|
35849
36593
|
return null;
|
|
35850
36594
|
};
|
|
35851
|
-
if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root || row.installPath.startsWith(root +
|
|
36595
|
+
if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root || row.installPath.startsWith(root + sep9) || root.startsWith(row.installPath + sep9))))
|
|
35852
36596
|
continue;
|
|
35853
36597
|
const rows = installed.plugins[id];
|
|
35854
36598
|
if (!Array.isArray(rows) || rows.length < 1)
|
|
@@ -35866,36 +36610,94 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
35866
36610
|
if (!targetValid || !targetScopes.has("user\x00"))
|
|
35867
36611
|
continue;
|
|
35868
36612
|
const active = rows[0]?.installPath;
|
|
35869
|
-
if (typeof active !== "string" || rows[0]?.version !== basename9(active) ||
|
|
36613
|
+
if (typeof active !== "string" || rows[0]?.version !== basename9(active) || dirname19(active) !== dirname19(root) || active === root || !lstatSync21(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync8(active) !== active)
|
|
35870
36614
|
continue;
|
|
35871
|
-
const activeManifest = full(
|
|
36615
|
+
const activeManifest = full(join29(active, ".claude-plugin/plugin.json"));
|
|
35872
36616
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
35873
36617
|
continue;
|
|
35874
36618
|
result.add(root);
|
|
35875
36619
|
}
|
|
35876
36620
|
return [...result];
|
|
35877
36621
|
}
|
|
35878
|
-
function
|
|
36622
|
+
function codexSemanticCacheSourceRole(source, cacheRoot, parents3) {
|
|
36623
|
+
if (!isAbsolute19(source.path) || resolve20(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")
|
|
36624
|
+
return false;
|
|
36625
|
+
const parts = relative7(cacheRoot, source.path).split(sep9);
|
|
36626
|
+
if (parts.length < 3 || !parents3.includes(join29(cacheRoot, parts[0], parts[1])))
|
|
36627
|
+
return false;
|
|
36628
|
+
const tail = parts.slice(3).join("/");
|
|
36629
|
+
return parts.length === 5 && tail === ".codex-plugin/plugin.json" && source.sha256 !== null || parts.length === 4 && [".app.json", ".mcp.json"].includes(tail) && source.sha256 !== null || source.sha256 === null && (parts.length === 4 && tail === "SKILL.md" || parts.length === 5 && tail === "hooks/hooks.json");
|
|
36630
|
+
}
|
|
36631
|
+
function codexSemanticCacheDirectoryRole(path, cacheRoot) {
|
|
36632
|
+
return isAbsolute19(path) && resolve20(path) === path && !/[\x00-\x1f\x7f]/.test(path) && (path === cacheRoot || path.startsWith(cacheRoot + sep9));
|
|
36633
|
+
}
|
|
36634
|
+
function assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, hookRootAlias = null) {
|
|
36635
|
+
const selectionRoots = [cacheRoot, ...parents3];
|
|
36636
|
+
if (hookRootAlias !== null) {
|
|
36637
|
+
if (!hookRootAlias || Object.keys(hookRootAlias).length !== 2 || [hookRootAlias.alias, hookRootAlias.target].some((path) => typeof path !== "string" || !isAbsolute19(path) || resolve20(path) !== path || /[\x00-\x1f\x7f]/.test(path)) || hookRootAlias.target !== dirname19(configPath) || cacheRoot !== join29(hookRootAlias.target, "plugins/cache") || !lstatSync21(hookRootAlias.alias, { throwIfNoEntry: false })?.isSymbolicLink() || realpathSync8(hookRootAlias.alias) !== hookRootAlias.target || realpathSync8(hookRootAlias.target) !== hookRootAlias.target)
|
|
36638
|
+
throw new Error("Reviewed semantic cache hook alias changed");
|
|
36639
|
+
selectionRoots.push(...selectionRoots.map((root) => join29(hookRootAlias.alias, relative7(hookRootAlias.target, root))));
|
|
36640
|
+
}
|
|
36641
|
+
selectionRoots.push("plugins/cache");
|
|
36642
|
+
if (selectionRoots.some((parent) => codexDirectHookSelects(cacheRoot, parent, configPath)))
|
|
36643
|
+
throw new Error("Direct native hooks select a projected Codex cache input");
|
|
36644
|
+
}
|
|
36645
|
+
function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
|
|
36646
|
+
const proof = binding.codexSemanticCache;
|
|
36647
|
+
if (!proof)
|
|
36648
|
+
return;
|
|
36649
|
+
if (reviewedRootAliases !== undefined) {
|
|
36650
|
+
const alias = reviewedRootAliases.find((alias2) => alias2.agent === "codex");
|
|
36651
|
+
const expected = alias ? { alias: alias.alias, target: alias.target } : null;
|
|
36652
|
+
if (!isDeepStrictEqual4(proof.hookRootAlias, expected))
|
|
36653
|
+
throw new Error("Semantic cache hook alias differs from reviewed root binding");
|
|
36654
|
+
}
|
|
36655
|
+
const controls = binding.codexDisabledPluginSkills;
|
|
36656
|
+
if (binding.agent !== "codex" || binding.method !== "reviewed" || !controls?.length || proof.schema !== "hasna.codex-semantic-cache-discovery.v1" || !/^[a-f0-9]{64}$/.test(proof.previousPolicySha256) || !Array.isArray(proof.appOnlyParents) || !Array.isArray(proof.supersededSources) || !Array.isArray(proof.supersededDirectories))
|
|
36657
|
+
throw new Error("Invalid Codex semantic cache discovery proof");
|
|
36658
|
+
const cacheRoot = proof.witness.cacheRoot;
|
|
36659
|
+
if (controls.some((control) => dirname19(dirname19(control.pluginParent)) !== cacheRoot))
|
|
36660
|
+
throw new Error("Codex semantic cache names another enrolled cache");
|
|
36661
|
+
const parents3 = [...new Set([...controls.map((control) => control.pluginParent), ...proof.appOnlyParents.map((parent) => parent.pluginParent)])];
|
|
36662
|
+
const sources = binding.sources.filter((source) => codexSemanticCacheSourceRole(source, cacheRoot, parents3));
|
|
36663
|
+
const directories = (binding.directories ?? []).filter((directory) => codexSemanticCacheDirectoryRole(directory.path, cacheRoot));
|
|
36664
|
+
if (!directories.length || !isDeepStrictEqual4(sources, proof.supersededSources) || !isDeepStrictEqual4(directories, proof.supersededDirectories))
|
|
36665
|
+
throw new Error("Codex semantic cache provenance changed");
|
|
36666
|
+
const configPath = proof.configPath;
|
|
36667
|
+
if (!isAbsolute19(configPath) || resolve20(configPath) !== configPath || basename9(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
|
|
36668
|
+
throw new Error("Invalid semantic cache configuration source");
|
|
36669
|
+
const configSource = binding.sources.find((source) => source.path === configPath && source.sha256 !== null && source.format === undefined && source.fields === undefined);
|
|
36670
|
+
if (!configSource || projected(configSource) !== configSource.sha256)
|
|
36671
|
+
throw new Error("Codex semantic cache requires unchanged reviewed configuration");
|
|
36672
|
+
assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, proof.hookRootAlias);
|
|
36673
|
+
const rules = parseConfig(read(configPath), configPath, true).skills?.config ?? [];
|
|
36674
|
+
const current = captureCodexSemanticCacheWitness({ cacheRoot, controls, appOnlyParents: proof.appOnlyParents, rules });
|
|
36675
|
+
assertCodexSemanticCacheWitnessUnchanged(proof.witness, current);
|
|
36676
|
+
return proof;
|
|
36677
|
+
}
|
|
36678
|
+
function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases) {
|
|
35879
36679
|
if (codexRecovery)
|
|
35880
36680
|
assertCodexHookDiscoveryRecovery(binding, codexRecovery);
|
|
35881
36681
|
if (!binding || !Array.isArray(binding.sources) || !Array.isArray(binding.roots) || binding.sources.length > AGENT_POLICY_LIMITS.discoverySources || binding.roots.length > AGENT_POLICY_LIMITS.discoveryRoots)
|
|
35882
36682
|
throw new Error("Invalid native discovery binding");
|
|
35883
36683
|
if (binding.agent === "hermes" && !binding.directories?.length)
|
|
35884
36684
|
throw new Error("Hermes discovery requires directory membership coverage; run skills hook install with a fresh discovery review");
|
|
36685
|
+
const semanticCache = verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases);
|
|
36686
|
+
const semanticDirectory = (path) => Boolean(semanticCache && codexSemanticCacheDirectoryRole(path, semanticCache.witness.cacheRoot));
|
|
35885
36687
|
const installationRoots = codexInstallationRoots(binding);
|
|
35886
36688
|
const retiredRoots = retiredCodexRoots(binding);
|
|
35887
|
-
const installationInput = (path) => installationRoots.some((root) => path === root || path.startsWith(root +
|
|
36689
|
+
const installationInput = (path) => installationRoots.some((root) => path === root || path.startsWith(root + sep9));
|
|
35888
36690
|
if (binding.directories !== undefined) {
|
|
35889
36691
|
const projected2 = binding.codexInstallationInputs?.directories ?? [];
|
|
35890
|
-
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root) => root.startsWith(directory.path +
|
|
36692
|
+
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root) => root.startsWith(directory.path + sep9)));
|
|
35891
36693
|
if (projected2.length !== ancestors2.length || projected2.some((directory) => !ancestors2.some((original) => original.path === directory.path)))
|
|
35892
36694
|
throw new Error("Missing installation input directory projection");
|
|
35893
|
-
const ordinary = binding.directories.filter((directory) => !installationInput(directory.path) && !ancestors2.includes(directory));
|
|
36695
|
+
const ordinary = binding.directories.filter((directory) => !installationInput(directory.path) && !ancestors2.includes(directory) && !semanticDirectory(directory.path));
|
|
35894
36696
|
if (binding.codexRetiredMaterializations) {
|
|
35895
|
-
const projection = binding.codexRetiredMaterializations.directories;
|
|
36697
|
+
const projection = binding.codexRetiredMaterializations.directories.filter((directory) => !semanticDirectory(directory.path));
|
|
35896
36698
|
if (projection.length !== ordinary.length || projection.some((item, index) => item.path !== ordinary[index]?.path))
|
|
35897
36699
|
throw new Error("Missing retired Codex directory projection");
|
|
35898
|
-
const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !
|
|
36700
|
+
const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !lstatSync21(parent, { throwIfNoEntry: false }))];
|
|
35899
36701
|
if (projection.every((item) => Array.isArray(item.entries)))
|
|
35900
36702
|
verifyDiscoveryDirectoryProjection(projection, omitted);
|
|
35901
36703
|
else {
|
|
@@ -35909,7 +36711,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
35909
36711
|
verifyDiscoveryDirectories(ordinary);
|
|
35910
36712
|
verifyDiscoveryDirectories(projected2, installationRoots);
|
|
35911
36713
|
}
|
|
35912
|
-
const absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root) => !
|
|
36714
|
+
const absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root) => !lstatSync21(root, { throwIfNoEntry: false }))];
|
|
35913
36715
|
const budget2 = discoveryByteBudget();
|
|
35914
36716
|
for (const source of binding.sources) {
|
|
35915
36717
|
assertMarketplaceBinding(binding, source);
|
|
@@ -35919,11 +36721,15 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
35919
36721
|
throw new Error("Invalid native discovery projection");
|
|
35920
36722
|
if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
35921
36723
|
throw new Error("Invalid native discovery digest");
|
|
36724
|
+
if (semanticCache?.supersededSources.some((previous) => isDeepStrictEqual4(previous, source))) {
|
|
36725
|
+
safe5(source.path);
|
|
36726
|
+
continue;
|
|
36727
|
+
}
|
|
35922
36728
|
if (installationInput(source.path)) {
|
|
35923
36729
|
safe5(source.path);
|
|
35924
36730
|
continue;
|
|
35925
36731
|
}
|
|
35926
|
-
if (absentRoots.some((root) => source.path.startsWith(root +
|
|
36732
|
+
if (absentRoots.some((root) => source.path.startsWith(root + sep9)) && retainableAbsentSource(source)) {
|
|
35927
36733
|
safe5(source.path);
|
|
35928
36734
|
continue;
|
|
35929
36735
|
}
|
|
@@ -35935,7 +36741,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
35935
36741
|
safe5(root);
|
|
35936
36742
|
for (const root of absentRoots) {
|
|
35937
36743
|
safe5(root);
|
|
35938
|
-
if (
|
|
36744
|
+
if (lstatSync21(root, { throwIfNoEntry: false }))
|
|
35939
36745
|
throw new Error("Retired native materialization changed during discovery verification");
|
|
35940
36746
|
}
|
|
35941
36747
|
}
|
|
@@ -35945,13 +36751,13 @@ function codexInstallationRoots(binding) {
|
|
|
35945
36751
|
return [];
|
|
35946
36752
|
if (binding.agent !== "codex" || binding.method !== "reviewed" || !supportsCodexNativeCapability(proof.version, "installed-plugin-review") || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
|
|
35947
36753
|
throw new Error("Invalid native installation input proof");
|
|
35948
|
-
const cache =
|
|
35949
|
-
const config2 =
|
|
36754
|
+
const cache = dirname19(dirname19(proof.plugins[0].pluginParent));
|
|
36755
|
+
const config2 = join29(dirname19(dirname19(cache)), "config.toml"), home = dirname19(dirname19(dirname19(cache)));
|
|
35950
36756
|
const configSource = binding.sources.find((source) => source.path === config2 && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
35951
|
-
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) =>
|
|
35952
|
-
if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot +
|
|
36757
|
+
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join29(home, path));
|
|
36758
|
+
if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot + sep9) || input2.sourceRoot.startsWith(root + sep9)) || binding.sources.some((source) => basename9(source.path) === "config.toml" && (source.path === input2.sourceRoot || source.path.startsWith(input2.sourceRoot + sep9)))))
|
|
35953
36759
|
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
35954
|
-
if (proof.plugins.some((input2) =>
|
|
36760
|
+
if (proof.plugins.some((input2) => dirname19(dirname19(input2.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join29(input2.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
35955
36761
|
throw new Error("Missing native installation input source witness");
|
|
35956
36762
|
return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
|
|
35957
36763
|
const text2 = read(path);
|
|
@@ -35961,11 +36767,11 @@ function codexInstallationRoots(binding) {
|
|
|
35961
36767
|
});
|
|
35962
36768
|
}
|
|
35963
36769
|
function assertMarketplaceBinding(binding, source) {
|
|
35964
|
-
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(
|
|
36770
|
+
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json"))))
|
|
35965
36771
|
throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
|
|
35966
36772
|
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename9(source.path) !== "sumi.json"))
|
|
35967
36773
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
35968
|
-
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
|
|
36774
|
+
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" || basename9(source.path) !== "config.toml"))
|
|
35969
36775
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
35970
36776
|
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" || basename9(source.path) !== "settings.json"))
|
|
35971
36777
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
@@ -35977,13 +36783,13 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
35977
36783
|
function agentDiscoveryConfigPath(home, agent) {
|
|
35978
36784
|
if (agent === "sumi")
|
|
35979
36785
|
return sumiConfigPath(home);
|
|
35980
|
-
return
|
|
36786
|
+
return join29(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
35981
36787
|
}
|
|
35982
36788
|
function resolveAgentDiscovery(options) {
|
|
35983
|
-
const
|
|
36789
|
+
const canonical9 = options.canonical ?? resolve20, home = resolve20(options.home), agent = options.agent;
|
|
35984
36790
|
const sources = [], roots = new Set, builtinNames = [];
|
|
35985
36791
|
const witness = (path, format, fields2, hashMode) => {
|
|
35986
|
-
const source = { path:
|
|
36792
|
+
const source = { path: canonical9(path), sha256: null, ...format ? { format, fields: fields2 } : {}, ...hashMode ? { hashMode } : {} };
|
|
35987
36793
|
source.sha256 = projected(source);
|
|
35988
36794
|
sources.push(source);
|
|
35989
36795
|
return read(source.path);
|
|
@@ -36001,42 +36807,42 @@ function resolveAgentDiscovery(options) {
|
|
|
36001
36807
|
const review = options.reviewed?.agents.find((item) => item.agent === agent);
|
|
36002
36808
|
if (agent === "sumi") {
|
|
36003
36809
|
const directory = sumiConfigDirectory(home);
|
|
36004
|
-
if (witness(
|
|
36810
|
+
if (witness(join29(directory, "sumi.jsonc")) !== null)
|
|
36005
36811
|
unresolved("JSONC configuration requires a supported format adapter");
|
|
36006
|
-
for (const root of [directory,
|
|
36812
|
+
for (const root of [directory, join29(home, ".claude"), join29(home, ".agents")])
|
|
36007
36813
|
for (const name of ["skill", "skills"])
|
|
36008
|
-
roots.add(
|
|
36814
|
+
roots.add(canonical9(join29(root, name)));
|
|
36009
36815
|
if (config2.skills !== undefined && (!Array.isArray(config2.skills) || config2.skills.some((path) => typeof path !== "string")))
|
|
36010
36816
|
unresolved("skills must be a string array");
|
|
36011
36817
|
for (const value of config2.skills ?? []) {
|
|
36012
|
-
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(
|
|
36818
|
+
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute19(value) || value.startsWith("~/")))
|
|
36013
36819
|
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
36014
|
-
roots.add(
|
|
36820
|
+
roots.add(canonical9(value.startsWith("~/") ? join29(home, value.slice(2)) : value));
|
|
36015
36821
|
}
|
|
36016
36822
|
for (const key of ["plugin", "plugins"])
|
|
36017
36823
|
if (config2[key] !== undefined && !Array.isArray(config2[key]))
|
|
36018
36824
|
unresolved(`${key} must be an array`);
|
|
36019
|
-
const plugins = [
|
|
36825
|
+
const plugins = [join29(directory, "plugin"), join29(directory, "plugins")];
|
|
36020
36826
|
for (const path of plugins) {
|
|
36021
36827
|
safe5(path);
|
|
36022
|
-
if (
|
|
36023
|
-
for (const name of
|
|
36828
|
+
if (lstatSync21(path, { throwIfNoEntry: false })?.isDirectory())
|
|
36829
|
+
for (const name of readdirSync8(path).sort()) {
|
|
36024
36830
|
if (name === "skills-cli.js" && path === plugins[1])
|
|
36025
36831
|
continue;
|
|
36026
|
-
const target =
|
|
36027
|
-
if (!
|
|
36832
|
+
const target = join29(path, name);
|
|
36833
|
+
if (!lstatSync21(target).isFile())
|
|
36028
36834
|
unresolved("local plugin packages need a dedicated discovery adapter");
|
|
36029
36835
|
witness(target);
|
|
36030
36836
|
}
|
|
36031
36837
|
}
|
|
36032
36838
|
for (const root of roots) {
|
|
36033
36839
|
safe5(root);
|
|
36034
|
-
if (
|
|
36840
|
+
if (lstatSync21(root, { throwIfNoEntry: false })?.isDirectory() && readdirSync8(root).some((name) => name.endsWith(".md")))
|
|
36035
36841
|
unresolved("flat markdown skills require a dedicated native migration adapter");
|
|
36036
36842
|
}
|
|
36037
36843
|
}
|
|
36038
36844
|
if (agent === "hermes") {
|
|
36039
|
-
const profile = witness(
|
|
36845
|
+
const profile = witness(join29(home, ".hermes/active_profile"));
|
|
36040
36846
|
if (profile?.trim() && profile.trim() !== "default")
|
|
36041
36847
|
unresolved("a non-default profile is active");
|
|
36042
36848
|
const declared = config2.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
|
|
@@ -36050,7 +36856,7 @@ function resolveAgentDiscovery(options) {
|
|
|
36050
36856
|
continue;
|
|
36051
36857
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
36052
36858
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
36053
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ?
|
|
36859
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join29(home, normalized.slice(2)) : resolve20(home, ".hermes", normalized);
|
|
36054
36860
|
safe5(path);
|
|
36055
36861
|
roots.add(path);
|
|
36056
36862
|
}
|
|
@@ -36059,24 +36865,24 @@ function resolveAgentDiscovery(options) {
|
|
|
36059
36865
|
const executable = options.executable === undefined ? discoveryExecutable(agent) : options.executable;
|
|
36060
36866
|
if (executable) {
|
|
36061
36867
|
let packageRoot;
|
|
36062
|
-
for (let directory =
|
|
36063
|
-
const path =
|
|
36868
|
+
for (let directory = dirname19(executable.target), depth = 0;depth < 8; directory = dirname19(directory), depth++) {
|
|
36869
|
+
const path = join29(directory, "package.json"), raw = read(path);
|
|
36064
36870
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
36065
36871
|
packageRoot = directory;
|
|
36066
36872
|
witness(path);
|
|
36067
36873
|
break;
|
|
36068
36874
|
}
|
|
36069
|
-
if (
|
|
36875
|
+
if (dirname19(directory) === directory)
|
|
36070
36876
|
break;
|
|
36071
36877
|
}
|
|
36072
36878
|
if (!packageRoot)
|
|
36073
36879
|
unresolved("installed Gemini package layout is not recognized");
|
|
36074
|
-
const builtinRoot =
|
|
36880
|
+
const builtinRoot = join29(packageRoot, "bundle/builtin");
|
|
36075
36881
|
safe5(builtinRoot);
|
|
36076
|
-
if (!
|
|
36882
|
+
if (!lstatSync21(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
36077
36883
|
unresolved("installed Gemini builtin root is missing");
|
|
36078
|
-
for (const name of
|
|
36079
|
-
const text2 = witness(
|
|
36884
|
+
for (const name of readdirSync8(builtinRoot).sort()) {
|
|
36885
|
+
const text2 = witness(join29(builtinRoot, name, "SKILL.md"));
|
|
36080
36886
|
const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
|
|
36081
36887
|
if (!match?.[1] || builtinNames.includes(match[1]))
|
|
36082
36888
|
unresolved("installed Gemini builtin name is missing or ambiguous");
|
|
@@ -36089,11 +36895,16 @@ function resolveAgentDiscovery(options) {
|
|
|
36089
36895
|
if (retained.agent !== agent || retained.method !== "reviewed")
|
|
36090
36896
|
unresolved("invalid retained review");
|
|
36091
36897
|
verifyAgentDiscovery(retained);
|
|
36092
|
-
if (!retained.sources.some((source) => source.path ===
|
|
36898
|
+
if (!retained.sources.some((source) => source.path === canonical9(configPath) && source.format === undefined && source.fields === undefined))
|
|
36093
36899
|
unresolved("retained review is missing the full agent configuration source");
|
|
36094
|
-
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !==
|
|
36900
|
+
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4" || source.hashMode === "codex-settings-v5")))) && source.path !== canonical9(configPath)))
|
|
36095
36901
|
unresolved("retained settings witness names another configuration source");
|
|
36096
|
-
|
|
36902
|
+
let covered = supersedesSettingsProjection(agent, retained.sources, canonical9(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical9(configPath), source)) : sources;
|
|
36903
|
+
if (retained.codexSemanticCache) {
|
|
36904
|
+
const proof = retained.codexSemanticCache;
|
|
36905
|
+
const parents3 = [...new Set([...(retained.codexDisabledPluginSkills ?? []).map((control) => control.pluginParent), ...proof.appOnlyParents.map((parent) => parent.pluginParent)])];
|
|
36906
|
+
covered = covered.filter((source) => !codexSemanticCacheSourceRole(source, proof.witness.cacheRoot, parents3));
|
|
36907
|
+
}
|
|
36097
36908
|
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual4(saved, source))) || [...roots].some((root) => !retained.roots.includes(root)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
36098
36909
|
unresolved("retained review is missing current runtime discovery coverage");
|
|
36099
36910
|
return retained;
|
|
@@ -36105,16 +36916,16 @@ function resolveAgentDiscovery(options) {
|
|
|
36105
36916
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
36106
36917
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
36107
36918
|
verifyAgentDiscovery(supplied);
|
|
36108
|
-
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !==
|
|
36919
|
+
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4" || source.hashMode === "codex-settings-v5")))) && source.path !== canonical9(configPath)))
|
|
36109
36920
|
throw new Error("Semantic settings witnesses must name the configured agent configuration source");
|
|
36110
|
-
if (!review.sources.some((source) => source.path ===
|
|
36921
|
+
if (!review.sources.some((source) => source.path === canonical9(configPath)))
|
|
36111
36922
|
throw new Error("Discovery review must include the agent configuration source");
|
|
36112
|
-
const reviewedSources = supersedesSettingsProjection(agent, review.sources,
|
|
36923
|
+
const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical9(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical9(configPath), source)) : sources;
|
|
36113
36924
|
const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
|
|
36114
|
-
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(
|
|
36925
|
+
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename9(source.path) !== "plugin.json" || !source.path.endsWith(join29(sep9, ".claude-plugin", "plugin.json")))
|
|
36115
36926
|
return source;
|
|
36116
|
-
const pluginRoot =
|
|
36117
|
-
const hookStat =
|
|
36927
|
+
const pluginRoot = dirname19(dirname19(source.path)), hooksPath = join29(pluginRoot, "hooks/hooks.json");
|
|
36928
|
+
const hookStat = lstatSync21(hooksPath, { throwIfNoEntry: false });
|
|
36118
36929
|
const text2 = read(source.path);
|
|
36119
36930
|
if (text2 === null)
|
|
36120
36931
|
throw new Error("Reviewed Claude plugin manifest is missing");
|
|
@@ -36128,58 +36939,58 @@ function resolveAgentDiscovery(options) {
|
|
|
36128
36939
|
if (manifest.hooks !== undefined) {
|
|
36129
36940
|
if (typeof manifest.hooks !== "string")
|
|
36130
36941
|
throw new Error("Reviewed Claude plugin manifest has an unsupported hooks target");
|
|
36131
|
-
const declaredHookPath =
|
|
36132
|
-
if (!declaredHookPath.startsWith(pluginRoot +
|
|
36942
|
+
const declaredHookPath = resolve20(pluginRoot, manifest.hooks);
|
|
36943
|
+
if (!declaredHookPath.startsWith(pluginRoot + sep9))
|
|
36133
36944
|
throw new Error("Reviewed Claude plugin hooks target escapes its root");
|
|
36134
36945
|
reviewedHookPaths.add(declaredHookPath);
|
|
36135
36946
|
}
|
|
36136
36947
|
for (const hooksFile of reviewedHookPaths)
|
|
36137
|
-
if (!review.sources.some((hook) => hook.path ===
|
|
36948
|
+
if (!review.sources.some((hook) => hook.path === canonical9(hooksFile) && hook.sha256 !== null && hook.format === undefined && hook.fields === undefined && hook.managedPlugins === undefined && (hook.hashMode === undefined || hook.hashMode === "bytes")))
|
|
36138
36949
|
throw new Error("Reviewed Claude plugin manifest requires separately reviewed exact hook file sources");
|
|
36139
36950
|
return { path: source.path, sha256: manifestSha256, hashMode: "claude-plugin-manifest-v1" };
|
|
36140
36951
|
});
|
|
36141
36952
|
if (agent === "claude")
|
|
36142
|
-
assertReviewedClaudeCacheClosures(home, config2, review,
|
|
36953
|
+
assertReviewedClaudeCacheClosures(home, config2, review, canonical9);
|
|
36143
36954
|
const combined = [...reviewedSources, ...reviewedSourcesWithManifestProjection];
|
|
36144
36955
|
const unique = combined.filter((source, index) => combined.findIndex((candidate) => isDeepStrictEqual4(candidate, source)) === index);
|
|
36145
36956
|
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: unique, ...agent === "gemini" ? { builtinNames } : {} };
|
|
36146
36957
|
}
|
|
36147
36958
|
function plugin(root) {
|
|
36148
|
-
root =
|
|
36959
|
+
root = canonical9(root);
|
|
36149
36960
|
safe5(root);
|
|
36150
|
-
const manifestPath =
|
|
36961
|
+
const manifestPath = join29(root, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
36151
36962
|
const raw = witness(manifestPath, undefined, undefined, agent === "claude" ? "claude-plugin-manifest-v1" : undefined);
|
|
36152
36963
|
if (raw === null)
|
|
36153
36964
|
unresolved("plugin manifest missing");
|
|
36154
36965
|
const manifest = parseConfig(raw, manifestPath);
|
|
36155
|
-
const hooks = witness(
|
|
36966
|
+
const hooks = witness(join29(root, "hooks/hooks.json"));
|
|
36156
36967
|
if (manifest.hooks !== undefined || hooks !== null)
|
|
36157
36968
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
36158
|
-
const commands =
|
|
36969
|
+
const commands = join29(root, "commands");
|
|
36159
36970
|
safe5(commands);
|
|
36160
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
36971
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync8(commands).length))
|
|
36161
36972
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
36162
|
-
const rootSkill = witness(
|
|
36973
|
+
const rootSkill = witness(join29(root, "SKILL.md"));
|
|
36163
36974
|
if (rootSkill !== null)
|
|
36164
36975
|
roots.add(root);
|
|
36165
36976
|
const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
36166
36977
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
36167
36978
|
unresolved("unsupported plugin skill paths");
|
|
36168
36979
|
if (agent === "claude")
|
|
36169
|
-
roots.add(
|
|
36980
|
+
roots.add(join29(root, "skills"));
|
|
36170
36981
|
for (const value of declared) {
|
|
36171
|
-
const path =
|
|
36172
|
-
if (path !== root && !path.startsWith(root +
|
|
36982
|
+
const path = resolve20(root, value);
|
|
36983
|
+
if (path !== root && !path.startsWith(root + sep9))
|
|
36173
36984
|
unresolved("plugin skill path escapes its root");
|
|
36174
|
-
roots.add(path.endsWith(`${
|
|
36985
|
+
roots.add(path.endsWith(`${sep9}SKILL.md`) ? dirname19(path) : path);
|
|
36175
36986
|
}
|
|
36176
36987
|
}
|
|
36177
36988
|
if (agent === "claude") {
|
|
36178
|
-
const registrations = witness(
|
|
36179
|
-
const installed = registrations === null ? {} : parseConfig(registrations,
|
|
36180
|
-
const commands =
|
|
36989
|
+
const registrations = witness(join29(home, ".claude/plugins/installed_plugins.json"));
|
|
36990
|
+
const installed = registrations === null ? {} : parseConfig(registrations, join29(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
36991
|
+
const commands = canonical9(join29(home, ".claude/commands"));
|
|
36181
36992
|
safe5(commands);
|
|
36182
|
-
if (
|
|
36993
|
+
if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync8(commands).length)
|
|
36183
36994
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
36184
36995
|
for (const [id, enabled] of Object.entries(config2.enabledPlugins ?? {})) {
|
|
36185
36996
|
if (enabled === false)
|
|
@@ -36199,37 +37010,37 @@ function resolveAgentDiscovery(options) {
|
|
|
36199
37010
|
unresolved("unsupported plugin enablement");
|
|
36200
37011
|
const split = id.lastIndexOf("@"), name = id.slice(0, split), marketplace = id.slice(split + 1);
|
|
36201
37012
|
const market = config2.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
36202
|
-
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !
|
|
37013
|
+
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute19(market.source))
|
|
36203
37014
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
36204
|
-
const catalogText = witness(
|
|
37015
|
+
const catalogText = witness(join29(market.source, ".agents/plugins/marketplace.json"));
|
|
36205
37016
|
if (catalogText === null)
|
|
36206
37017
|
unresolved("marketplace catalog missing");
|
|
36207
|
-
const catalog = parseConfig(catalogText,
|
|
37018
|
+
const catalog = parseConfig(catalogText, join29(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
36208
37019
|
if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
|
|
36209
37020
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
36210
|
-
plugin(
|
|
37021
|
+
plugin(resolve20(market.source, matches[0].source.path));
|
|
36211
37022
|
}
|
|
36212
37023
|
} else if (agent === "opencode") {
|
|
36213
|
-
if (witness(
|
|
37024
|
+
if (witness(join29(home, ".config/opencode/opencode.jsonc")) !== null || witness(join29(home, ".config/opencode/config.json")) !== null)
|
|
36214
37025
|
unresolved("additional config layers require review");
|
|
36215
37026
|
if ((config2.plugin?.length ?? 0) > 0 || config2.skills?.urls?.length)
|
|
36216
37027
|
unresolved("external plugin or remote skill source");
|
|
36217
37028
|
for (const path of config2.skills?.paths ?? []) {
|
|
36218
|
-
if (typeof path !== "string" || !
|
|
37029
|
+
if (typeof path !== "string" || !isAbsolute19(path))
|
|
36219
37030
|
unresolved("relative or malformed added skill root");
|
|
36220
37031
|
roots.add(path);
|
|
36221
37032
|
}
|
|
36222
|
-
const localPlugins =
|
|
37033
|
+
const localPlugins = join29(home, ".config/opencode/plugins");
|
|
36223
37034
|
safe5(localPlugins);
|
|
36224
|
-
if (
|
|
37035
|
+
if (lstatSync21(localPlugins, { throwIfNoEntry: false }) && readdirSync8(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
36225
37036
|
unresolved("additional local plugin hooks require review");
|
|
36226
37037
|
} else if (agent === "sumi") {
|
|
36227
|
-
if ((config2.plugin?.length ?? 0) > 0 || (config2.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !==
|
|
37038
|
+
if ((config2.plugin?.length ?? 0) > 0 || (config2.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical9(configPath) && source.path !== canonical9(join29(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
|
|
36228
37039
|
unresolved("external or foreign local plugins require review");
|
|
36229
37040
|
} else if (agent === "hermes") {
|
|
36230
|
-
for (const directory of [
|
|
37041
|
+
for (const directory of [join29(home, ".hermes/plugins"), join29(home, ".hermes/hermes-agent")]) {
|
|
36231
37042
|
safe5(directory);
|
|
36232
|
-
if (
|
|
37043
|
+
if (lstatSync21(directory, { throwIfNoEntry: false }))
|
|
36233
37044
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
36234
37045
|
}
|
|
36235
37046
|
if (Bun.which("hermes") || Object.keys(config2.plugins ?? {}).length)
|
|
@@ -36237,32 +37048,32 @@ function resolveAgentDiscovery(options) {
|
|
|
36237
37048
|
} else if (agent === "gemini") {
|
|
36238
37049
|
if (Object.keys(config2.extensions ?? {}).length || config2.skills?.paths?.length)
|
|
36239
37050
|
unresolved("custom extension or skill paths");
|
|
36240
|
-
const directory =
|
|
37051
|
+
const directory = join29(home, ".gemini/extensions");
|
|
36241
37052
|
safe5(directory);
|
|
36242
|
-
if (
|
|
36243
|
-
for (const name of
|
|
36244
|
-
const root =
|
|
37053
|
+
if (lstatSync21(directory, { throwIfNoEntry: false }))
|
|
37054
|
+
for (const name of readdirSync8(directory)) {
|
|
37055
|
+
const root = join29(directory, name);
|
|
36245
37056
|
safe5(root);
|
|
36246
|
-
if (!
|
|
37057
|
+
if (!lstatSync21(root)?.isDirectory())
|
|
36247
37058
|
continue;
|
|
36248
|
-
const raw = witness(
|
|
37059
|
+
const raw = witness(join29(root, "gemini-extension.json"));
|
|
36249
37060
|
if (raw === null)
|
|
36250
37061
|
unresolved("extension registration missing");
|
|
36251
|
-
const manifest = parseConfig(raw,
|
|
36252
|
-
if (manifest.hooks !== undefined || witness(
|
|
37062
|
+
const manifest = parseConfig(raw, join29(root, "gemini-extension.json"));
|
|
37063
|
+
if (manifest.hooks !== undefined || witness(join29(root, "hooks/hooks.json")) !== null || witness(join29(root, ".gemini-extension-install.json")) !== null)
|
|
36253
37064
|
unresolved("extension hooks or linked registration require review");
|
|
36254
|
-
roots.add(
|
|
37065
|
+
roots.add(join29(root, "skills"));
|
|
36255
37066
|
}
|
|
36256
37067
|
}
|
|
36257
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([
|
|
37068
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join29(home, ".hermes/plugins"), join29(home, ".hermes/hermes-agent")].map((path) => canonical9(path))) } : {} };
|
|
36258
37069
|
}
|
|
36259
37070
|
var DISCOVERY_RUNTIME_COMMANDS, realpathOrNull = (path) => {
|
|
36260
37071
|
try {
|
|
36261
|
-
return
|
|
37072
|
+
return realpathSync8(path);
|
|
36262
37073
|
} catch {
|
|
36263
37074
|
return null;
|
|
36264
37075
|
}
|
|
36265
|
-
},
|
|
37076
|
+
}, digest2 = (text2) => createHash21("sha256").update(text2).digest("hex");
|
|
36266
37077
|
var init_agent_discovery = __esm(() => {
|
|
36267
37078
|
init_sumi_settings_witness();
|
|
36268
37079
|
init_agent_policy_limits();
|
|
@@ -36283,16 +37094,17 @@ var init_agent_discovery = __esm(() => {
|
|
|
36283
37094
|
init_native_discovery_roots();
|
|
36284
37095
|
init_codex_native_compatibility();
|
|
36285
37096
|
init_retained_review_artifacts();
|
|
37097
|
+
init_codex_semantic_cache_witness();
|
|
36286
37098
|
init_agent_discovery_directories();
|
|
36287
37099
|
DISCOVERY_RUNTIME_COMMANDS = Object.freeze({ gemini: "gemini" });
|
|
36288
37100
|
});
|
|
36289
37101
|
|
|
36290
37102
|
// src/lib/authoring-path.ts
|
|
36291
|
-
import { lstatSync as
|
|
37103
|
+
import { lstatSync as lstatSync22, realpathSync as realpathSync9 } from "fs";
|
|
36292
37104
|
import { homedir as homedir3 } from "os";
|
|
36293
|
-
import { basename as basename10, dirname as
|
|
37105
|
+
import { basename as basename10, dirname as dirname20, join as join30, resolve as resolve21, sep as sep10 } from "path";
|
|
36294
37106
|
function pathParts(path) {
|
|
36295
|
-
return
|
|
37107
|
+
return resolve21(path).split(sep10).filter(Boolean);
|
|
36296
37108
|
}
|
|
36297
37109
|
function nativeRootMatch(path) {
|
|
36298
37110
|
const parts = pathParts(path);
|
|
@@ -36306,24 +37118,24 @@ function nativeRootMatch(path) {
|
|
|
36306
37118
|
return;
|
|
36307
37119
|
}
|
|
36308
37120
|
function physicalPath(path) {
|
|
36309
|
-
let cursor =
|
|
37121
|
+
let cursor = resolve21(path);
|
|
36310
37122
|
const suffix = [];
|
|
36311
|
-
while (!
|
|
37123
|
+
while (!lstatSync22(cursor, { throwIfNoEntry: false })) {
|
|
36312
37124
|
suffix.unshift(basename10(cursor));
|
|
36313
|
-
const parent =
|
|
37125
|
+
const parent = dirname20(cursor);
|
|
36314
37126
|
if (parent === cursor)
|
|
36315
|
-
return
|
|
37127
|
+
return resolve21(path);
|
|
36316
37128
|
cursor = parent;
|
|
36317
37129
|
}
|
|
36318
|
-
return
|
|
37130
|
+
return resolve21(realpathSync9(cursor), ...suffix);
|
|
36319
37131
|
}
|
|
36320
37132
|
function contains(root, path) {
|
|
36321
|
-
return path === root || path.startsWith(root +
|
|
37133
|
+
return path === root || path.startsWith(root + sep10);
|
|
36322
37134
|
}
|
|
36323
37135
|
function configuredRoots(home, explicitHome) {
|
|
36324
|
-
const homeData =
|
|
37136
|
+
const homeData = join30(home, ".hasna", "skills");
|
|
36325
37137
|
const homePolicy = readManagedSkillPolicySnapshot(homeData);
|
|
36326
|
-
const configuredPolicy = !explicitHome &&
|
|
37138
|
+
const configuredPolicy = !explicitHome && resolve21(getDataDirReadOnly()) !== resolve21(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
|
|
36327
37139
|
const policy = homePolicy ?? configuredPolicy;
|
|
36328
37140
|
const bridge = policy?.value.bridge;
|
|
36329
37141
|
if (bridge && (typeof bridge.home !== "string" || physicalPath(bridge.home) !== physicalPath(home))) {
|
|
@@ -36352,8 +37164,8 @@ function configuredRoots(home, explicitHome) {
|
|
|
36352
37164
|
admitBinding(binding);
|
|
36353
37165
|
continue;
|
|
36354
37166
|
}
|
|
36355
|
-
const nativeHome =
|
|
36356
|
-
if (!
|
|
37167
|
+
const nativeHome = join30(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
|
|
37168
|
+
if (!lstatSync22(nativeHome, { throwIfNoEntry: false }))
|
|
36357
37169
|
continue;
|
|
36358
37170
|
roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
|
|
36359
37171
|
}
|
|
@@ -36362,22 +37174,22 @@ function configuredRoots(home, explicitHome) {
|
|
|
36362
37174
|
function assertPortableAuthoringPath(path, options = {}) {
|
|
36363
37175
|
if (typeof path !== "string" || !path || path.includes("\x00"))
|
|
36364
37176
|
throw new Error("Invalid portable authoring path");
|
|
36365
|
-
const lexical =
|
|
37177
|
+
const lexical = resolve21(path);
|
|
36366
37178
|
const physical = physicalPath(lexical);
|
|
36367
37179
|
const candidates = [lexical, physical];
|
|
36368
37180
|
let native = candidates.map(nativeRootMatch).find(Boolean);
|
|
36369
|
-
const home =
|
|
36370
|
-
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) =>
|
|
36371
|
-
defaults.push(
|
|
37181
|
+
const home = resolve21(options.homeDir ?? homedir3());
|
|
37182
|
+
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join30(home, ...parts));
|
|
37183
|
+
defaults.push(join30(home, ".codex/plugins/cache"), join30(home, ".claude/plugins/cache"), join30(home, ".claude/plugins/synced"), join30(home, ".gemini/extensions"));
|
|
36372
37184
|
for (const root of defaults) {
|
|
36373
|
-
if (candidates.some((candidate) => contains(
|
|
37185
|
+
if (candidates.some((candidate) => contains(resolve21(root), candidate) || contains(physicalPath(root), candidate)))
|
|
36374
37186
|
native ??= root;
|
|
36375
37187
|
}
|
|
36376
37188
|
if (native) {
|
|
36377
37189
|
throw new Error(`Refusing portable Skills authoring below native discovery root '${native}': ${lexical}. Set HASNA_SKILLS_DIR to a private authoring corpus outside native roots.`);
|
|
36378
37190
|
}
|
|
36379
37191
|
for (const root of configuredRoots(home, options.homeDir !== undefined)) {
|
|
36380
|
-
if (candidates.some((candidate) => contains(
|
|
37192
|
+
if (candidates.some((candidate) => contains(resolve21(root), candidate) || contains(physicalPath(root), candidate))) {
|
|
36381
37193
|
throw new Error(`Refusing portable Skills authoring below configured native discovery root: ${lexical}`);
|
|
36382
37194
|
}
|
|
36383
37195
|
}
|
|
@@ -36397,29 +37209,29 @@ import {
|
|
|
36397
37209
|
existsSync as existsSync12,
|
|
36398
37210
|
mkdirSync as mkdirSync8,
|
|
36399
37211
|
mkdtempSync,
|
|
36400
|
-
readdirSync as
|
|
36401
|
-
realpathSync as
|
|
37212
|
+
readdirSync as readdirSync9,
|
|
37213
|
+
realpathSync as realpathSync10,
|
|
36402
37214
|
renameSync as renameSync3,
|
|
36403
37215
|
rmSync as rmSync3,
|
|
36404
37216
|
statSync as statSync8,
|
|
36405
37217
|
writeFileSync as writeFileSync6
|
|
36406
37218
|
} from "fs";
|
|
36407
|
-
import { basename as basename11, dirname as
|
|
37219
|
+
import { basename as basename11, dirname as dirname21, isAbsolute as isAbsolute20, join as join31, normalize as normalize4, relative as relative8, resolve as resolve22, sep as sep11 } from "path";
|
|
36408
37220
|
function getPortableSkillsRoot(options = {}) {
|
|
36409
37221
|
return resolvePortableSkillsRoot(options, true);
|
|
36410
37222
|
}
|
|
36411
37223
|
function resolvePortableSkillsRoot(options, migrate) {
|
|
36412
37224
|
if (options.rootDir)
|
|
36413
37225
|
return options.rootDir;
|
|
36414
|
-
const appDir = options.homeDir ?
|
|
36415
|
-
const cache =
|
|
37226
|
+
const appDir = options.homeDir ? join31(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
|
|
37227
|
+
const cache = join31(appDir, SKILLS_CACHE_DIRNAME);
|
|
36416
37228
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
|
|
36417
37229
|
return cache;
|
|
36418
|
-
const installed =
|
|
37230
|
+
const installed = join31(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
36419
37231
|
return installed;
|
|
36420
37232
|
}
|
|
36421
37233
|
function getPortableSkillPath(name, options = {}) {
|
|
36422
|
-
return
|
|
37234
|
+
return join31(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
36423
37235
|
}
|
|
36424
37236
|
function findPortableSkill(name, options = {}) {
|
|
36425
37237
|
let normalized;
|
|
@@ -36442,10 +37254,10 @@ function listPortableSkills(options = {}) {
|
|
|
36442
37254
|
if (!safeIsDirectory(root))
|
|
36443
37255
|
return [];
|
|
36444
37256
|
const skills = [];
|
|
36445
|
-
for (const entry of
|
|
37257
|
+
for (const entry of readdirSync9(root).sort()) {
|
|
36446
37258
|
if (entry.startsWith("."))
|
|
36447
37259
|
continue;
|
|
36448
|
-
const path =
|
|
37260
|
+
const path = join31(root, entry);
|
|
36449
37261
|
if (!safeIsDirectory(path))
|
|
36450
37262
|
continue;
|
|
36451
37263
|
try {
|
|
@@ -36478,9 +37290,9 @@ function isOfficialSkillName(name) {
|
|
|
36478
37290
|
function scaffoldPortableSkill(name, options = {}) {
|
|
36479
37291
|
const skillName = normalizeNewPortableSkillName(name);
|
|
36480
37292
|
const readOnlyRoot = resolvePortableSkillsRoot(options, false);
|
|
36481
|
-
assertPortableAuthoringPath(
|
|
37293
|
+
assertPortableAuthoringPath(join31(readOnlyRoot, skillName), options);
|
|
36482
37294
|
const root = getPortableSkillsRoot(options);
|
|
36483
|
-
const skillPath =
|
|
37295
|
+
const skillPath = join31(root, skillName);
|
|
36484
37296
|
assertPortableAuthoringPath(skillPath, options);
|
|
36485
37297
|
if (existsSync12(skillPath)) {
|
|
36486
37298
|
if (!options.overwrite)
|
|
@@ -36499,20 +37311,20 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
36499
37311
|
return { name: skillName, path: skillPath, manifest, created: true };
|
|
36500
37312
|
}
|
|
36501
37313
|
function physicalImportPath(path) {
|
|
36502
|
-
let ancestor =
|
|
37314
|
+
let ancestor = resolve22(path);
|
|
36503
37315
|
const suffix = [];
|
|
36504
37316
|
while (!existsSync12(ancestor)) {
|
|
36505
37317
|
suffix.unshift(basename11(ancestor));
|
|
36506
|
-
ancestor =
|
|
37318
|
+
ancestor = dirname21(ancestor);
|
|
36507
37319
|
}
|
|
36508
|
-
return
|
|
37320
|
+
return join31(realpathSync10(ancestor), ...suffix);
|
|
36509
37321
|
}
|
|
36510
37322
|
function assertDisjointImportPaths(source, destination) {
|
|
36511
|
-
const sourcePath =
|
|
37323
|
+
const sourcePath = realpathSync10(source);
|
|
36512
37324
|
const destinationPath = physicalImportPath(destination);
|
|
36513
37325
|
const contains2 = (parent, child2) => {
|
|
36514
|
-
const path =
|
|
36515
|
-
return path === "" || !
|
|
37326
|
+
const path = relative8(parent, child2);
|
|
37327
|
+
return path === "" || !isAbsolute20(path) && path !== ".." && !path.startsWith(`..${sep11}`);
|
|
36516
37328
|
};
|
|
36517
37329
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
36518
37330
|
throw new Error("Source and destination skill directories must not overlap");
|
|
@@ -36531,11 +37343,11 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
36531
37343
|
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename11(absoluteSource)}')` : ""} matches a bundled official skill.`;
|
|
36532
37344
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
36533
37345
|
}
|
|
36534
|
-
const readOnlyDestination =
|
|
37346
|
+
const readOnlyDestination = join31(resolvePortableSkillsRoot(options, false), skillName);
|
|
36535
37347
|
assertPortableAuthoringPath(readOnlyDestination, options);
|
|
36536
37348
|
assertDisjointImportPaths(absoluteSource, readOnlyDestination);
|
|
36537
37349
|
const root = getPortableSkillsRoot(options);
|
|
36538
|
-
const destination =
|
|
37350
|
+
const destination = join31(root, skillName);
|
|
36539
37351
|
assertPortableAuthoringPath(destination, options);
|
|
36540
37352
|
assertDisjointImportPaths(absoluteSource, destination);
|
|
36541
37353
|
if (existsSync12(destination)) {
|
|
@@ -36543,7 +37355,7 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
36543
37355
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
36544
37356
|
rmSync3(destination, { recursive: true, force: true });
|
|
36545
37357
|
}
|
|
36546
|
-
mkdirSync8(
|
|
37358
|
+
mkdirSync8(dirname21(destination), { recursive: true });
|
|
36547
37359
|
copySkillDirectory(absoluteSource, destination);
|
|
36548
37360
|
const base = {
|
|
36549
37361
|
...inferred,
|
|
@@ -36567,8 +37379,8 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
36567
37379
|
const warnings = [...base.warnings];
|
|
36568
37380
|
let manifest;
|
|
36569
37381
|
if (existsSync12(skillPath)) {
|
|
36570
|
-
const skillJsonPath =
|
|
36571
|
-
const skillMdPath =
|
|
37382
|
+
const skillJsonPath = join31(skillPath, "skill.json");
|
|
37383
|
+
const skillMdPath = join31(skillPath, "SKILL.md");
|
|
36572
37384
|
if (!existsSync12(skillJsonPath) && !existsSync12(skillMdPath)) {
|
|
36573
37385
|
add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
36574
37386
|
}
|
|
@@ -36588,7 +37400,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
36588
37400
|
add3(issues, "portable.version_missing", "Portable manifest missing version");
|
|
36589
37401
|
}
|
|
36590
37402
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
36591
|
-
strict: existsSync12(
|
|
37403
|
+
strict: existsSync12(join31(skillPath, "skill.json")),
|
|
36592
37404
|
skillPath
|
|
36593
37405
|
});
|
|
36594
37406
|
for (const issue2 of contractIssues)
|
|
@@ -36628,7 +37440,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
36628
37440
|
add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
36629
37441
|
continue;
|
|
36630
37442
|
}
|
|
36631
|
-
const entryPath =
|
|
37443
|
+
const entryPath = join31(skillPath, command.entry);
|
|
36632
37444
|
if (!existsSync12(entryPath))
|
|
36633
37445
|
add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
36634
37446
|
else if (statSync8(entryPath).isDirectory())
|
|
@@ -36639,7 +37451,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
36639
37451
|
} catch (error61) {
|
|
36640
37452
|
add3(issues, "portable.manifest_invalid", error61.message);
|
|
36641
37453
|
}
|
|
36642
|
-
if (manifest?.kind !== "instruction" && !existsSync12(
|
|
37454
|
+
if (manifest?.kind !== "instruction" && !existsSync12(join31(skillPath, "AGENTS.md"))) {
|
|
36643
37455
|
add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
36644
37456
|
}
|
|
36645
37457
|
}
|
|
@@ -36677,7 +37489,7 @@ function safeIsDirectory(path) {
|
|
|
36677
37489
|
}
|
|
36678
37490
|
}
|
|
36679
37491
|
function isSafeRelativePath2(value) {
|
|
36680
|
-
if (!value.trim() ||
|
|
37492
|
+
if (!value.trim() || isAbsolute20(value))
|
|
36681
37493
|
return false;
|
|
36682
37494
|
const normalized = normalize4(value).replace(/\\/g, "/");
|
|
36683
37495
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
@@ -36866,8 +37678,8 @@ var init_search = __esm(() => {
|
|
|
36866
37678
|
});
|
|
36867
37679
|
|
|
36868
37680
|
// src/lib/registry.ts
|
|
36869
|
-
import { existsSync as existsSync13, readFileSync as readFileSync17, readdirSync as
|
|
36870
|
-
import { join as
|
|
37681
|
+
import { existsSync as existsSync13, readFileSync as readFileSync17, readdirSync as readdirSync10 } from "fs";
|
|
37682
|
+
import { join as join32 } from "path";
|
|
36871
37683
|
function parseSkillMdFrontmatter(content) {
|
|
36872
37684
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
36873
37685
|
if (!match)
|
|
@@ -36904,11 +37716,11 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
36904
37716
|
return [];
|
|
36905
37717
|
const result = [];
|
|
36906
37718
|
try {
|
|
36907
|
-
const entries =
|
|
37719
|
+
const entries = readdirSync10(dir, { withFileTypes: true });
|
|
36908
37720
|
for (const entry of entries) {
|
|
36909
37721
|
if (!entry.isDirectory())
|
|
36910
37722
|
continue;
|
|
36911
|
-
const skillMdPath =
|
|
37723
|
+
const skillMdPath = join32(dir, entry.name, "SKILL.md");
|
|
36912
37724
|
if (!existsSync13(skillMdPath))
|
|
36913
37725
|
continue;
|
|
36914
37726
|
let content;
|
|
@@ -36928,7 +37740,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
36928
37740
|
category: fm.category || "Development Tools",
|
|
36929
37741
|
tags: fm.tags || [],
|
|
36930
37742
|
...fm.kind ? { kind: fm.kind } : {},
|
|
36931
|
-
...isHostedMetadataSkillDir(
|
|
37743
|
+
...isHostedMetadataSkillDir(join32(dir, entry.name)) ? { serverOwned: true } : {},
|
|
36932
37744
|
source
|
|
36933
37745
|
});
|
|
36934
37746
|
}
|
|
@@ -36940,12 +37752,12 @@ function findExtensionSkillPath(name) {
|
|
|
36940
37752
|
if (!config2.extensionsDir || !existsSync13(config2.extensionsDir))
|
|
36941
37753
|
return null;
|
|
36942
37754
|
try {
|
|
36943
|
-
const entries =
|
|
37755
|
+
const entries = readdirSync10(config2.extensionsDir, { withFileTypes: true });
|
|
36944
37756
|
for (const entry of entries) {
|
|
36945
37757
|
if (!entry.isDirectory())
|
|
36946
37758
|
continue;
|
|
36947
|
-
const skillDir =
|
|
36948
|
-
const skillMdPath =
|
|
37759
|
+
const skillDir = join32(config2.extensionsDir, entry.name);
|
|
37760
|
+
const skillMdPath = join32(skillDir, "SKILL.md");
|
|
36949
37761
|
if (!existsSync13(skillMdPath))
|
|
36950
37762
|
continue;
|
|
36951
37763
|
let content;
|
|
@@ -37362,7 +38174,7 @@ var init_v4 = __esm(() => {
|
|
|
37362
38174
|
});
|
|
37363
38175
|
|
|
37364
38176
|
// src/lib/canonical-json.ts
|
|
37365
|
-
import { createHash as
|
|
38177
|
+
import { createHash as createHash22 } from "crypto";
|
|
37366
38178
|
function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
|
|
37367
38179
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
37368
38180
|
}
|
|
@@ -37406,7 +38218,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
37406
38218
|
return visit3(value, 0);
|
|
37407
38219
|
}
|
|
37408
38220
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
37409
|
-
return
|
|
38221
|
+
return createHash22("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
|
|
37410
38222
|
}
|
|
37411
38223
|
var init_canonical_json = () => {};
|
|
37412
38224
|
|
|
@@ -37516,14 +38328,14 @@ function requireResult(value) {
|
|
|
37516
38328
|
if (!value)
|
|
37517
38329
|
throw new RemoteRecurringReadError;
|
|
37518
38330
|
}
|
|
37519
|
-
function termsIntegrity(terms,
|
|
37520
|
-
requireResult(terms.organizationId ===
|
|
37521
|
-
requireResult(canonicalJsonSha256(terms) ===
|
|
38331
|
+
function termsIntegrity(terms, hash4, identity4, own2) {
|
|
38332
|
+
requireResult(terms.organizationId === identity4.organization.id && (!own2 || terms.approvedByUserId === identity4.user.id && terms.approvedMembershipId === identity4.user.membershipId));
|
|
38333
|
+
requireResult(canonicalJsonSha256(terms) === hash4);
|
|
37522
38334
|
requireResult(canonicalJsonSha256({ skill: terms.skill, input: terms.input, args: terms.args, runtime: terms.runtime }) === terms.payloadSha256);
|
|
37523
38335
|
requireResult(Date.parse(terms.expiresAt) > Date.parse(terms.startsAt));
|
|
37524
38336
|
}
|
|
37525
|
-
function previewIntegrity(value,
|
|
37526
|
-
termsIntegrity(value.terms, value.termsSha256,
|
|
38337
|
+
function previewIntegrity(value, identity4) {
|
|
38338
|
+
termsIntegrity(value.terms, value.termsSha256, identity4, true);
|
|
37527
38339
|
requireResult(Date.parse(value.approvalDeadline) > Date.parse(value.quote.quotedAt));
|
|
37528
38340
|
const anchor2 = Date.parse(value.terms.startsAt), end = Date.parse(value.terms.expiresAt), cadence = value.terms.everyMinutes * 60000;
|
|
37529
38341
|
requireResult(value.firstDueInstants.every((at, i) => Date.parse(at) === anchor2 + i * cadence && Date.parse(at) < end));
|
|
@@ -37531,7 +38343,7 @@ function previewIntegrity(value, identity3) {
|
|
|
37531
38343
|
const day = Date.parse(value.firstPeriod.startsAt);
|
|
37532
38344
|
requireResult(day % 86400000 === 0 && day <= anchor2 && anchor2 < Date.parse(value.firstPeriod.endsAt) && Date.parse(value.firstPeriod.endsAt) === day + 86400000);
|
|
37533
38345
|
}
|
|
37534
|
-
function parseRecurringResult(action, value, input2,
|
|
38346
|
+
function parseRecurringResult(action, value, input2, identity4) {
|
|
37535
38347
|
const wrappers = { preview: 1, draft: 1, activate: 2, list: 3, get: 1, occurrences: 0, revoke: 0 };
|
|
37536
38348
|
canonicalJsonAtDepth(value, 64 * 1024 * 1024, 64 + wrappers[action]);
|
|
37537
38349
|
const result = results[action].parse(value);
|
|
@@ -37540,7 +38352,7 @@ function parseRecurringResult(action, value, input2, identity3) {
|
|
|
37540
38352
|
const row = input2;
|
|
37541
38353
|
if (action === "preview" || action === "draft") {
|
|
37542
38354
|
const p = result;
|
|
37543
|
-
previewIntegrity(p,
|
|
38355
|
+
previewIntegrity(p, identity4);
|
|
37544
38356
|
if (action === "draft")
|
|
37545
38357
|
requireResult(p.draftId === row.draftId);
|
|
37546
38358
|
else {
|
|
@@ -37559,7 +38371,7 @@ function parseRecurringResult(action, value, input2, identity3) {
|
|
|
37559
38371
|
}
|
|
37560
38372
|
const views = action === "list" ? result.items : action === "get" ? [result] : action === "activate" ? [result.consent] : [];
|
|
37561
38373
|
for (const view of views) {
|
|
37562
|
-
termsIntegrity(view.terms, view.termsSha256,
|
|
38374
|
+
termsIntegrity(view.terms, view.termsSha256, identity4, action === "activate");
|
|
37563
38375
|
requireResult(view.state === "revoked" === (view.revokedAt !== null));
|
|
37564
38376
|
if (action === "get")
|
|
37565
38377
|
requireResult(view.consentId === row.consentId);
|
|
@@ -37585,7 +38397,7 @@ function parseRecurringResult(action, value, input2, identity3) {
|
|
|
37585
38397
|
}
|
|
37586
38398
|
return result;
|
|
37587
38399
|
}
|
|
37588
|
-
var RecurringInputError, RemoteRecurringUnavailableError, RemoteRecurringReadError, RemoteRecurringUnconfirmedError, failures, RemoteRecurringError, uuid3, instant2, integer2,
|
|
38400
|
+
var RecurringInputError, RemoteRecurringUnavailableError, RemoteRecurringReadError, RemoteRecurringUnconfirmedError, failures, RemoteRecurringError, uuid3, instant2, integer2, digest3, list, inputs, capabilityNames, budget2, period, preview, consent, refusal2, occurrence, revocation, page = (item) => exports_external.object({ contractVersion: exports_external.literal(1), items: exports_external.array(item).max(100), nextCursor: exports_external.string().min(1).max(2048).nullable() }), results;
|
|
37589
38401
|
var init_remote_recurring = __esm(() => {
|
|
37590
38402
|
init_v4();
|
|
37591
38403
|
init_canonical_json();
|
|
@@ -37651,7 +38463,7 @@ var init_remote_recurring = __esm(() => {
|
|
|
37651
38463
|
uuid3 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
37652
38464
|
instant2 = exports_external.string().max(32).datetime();
|
|
37653
38465
|
integer2 = exports_external.number().int().min(0).max(MAX_RECURRING_CREDITS);
|
|
37654
|
-
|
|
38466
|
+
digest3 = exports_external.string().regex(/^[a-f0-9]{64}$/);
|
|
37655
38467
|
list = exports_external.object({ limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() }).strict();
|
|
37656
38468
|
inputs = {
|
|
37657
38469
|
preview: recurringRequestSchema,
|
|
@@ -37677,7 +38489,7 @@ var init_remote_recurring = __esm(() => {
|
|
|
37677
38489
|
contractVersion: exports_external.literal(1),
|
|
37678
38490
|
draftId: uuid3,
|
|
37679
38491
|
terms: recurringTermsSchema,
|
|
37680
|
-
termsSha256:
|
|
38492
|
+
termsSha256: digest3,
|
|
37681
38493
|
quote: exports_external.object({ costCredits: integer2, quotedAt: instant2, admissionReprices: exports_external.literal(true) }),
|
|
37682
38494
|
approvalDeadline: instant2,
|
|
37683
38495
|
firstDueInstants: exports_external.array(instant2).min(1).max(5),
|
|
@@ -37689,7 +38501,7 @@ var init_remote_recurring = __esm(() => {
|
|
|
37689
38501
|
consentId: uuid3,
|
|
37690
38502
|
scheduleId: uuid3,
|
|
37691
38503
|
terms: recurringTermsSchema,
|
|
37692
|
-
termsSha256:
|
|
38504
|
+
termsSha256: digest3,
|
|
37693
38505
|
state: exports_external.enum(["active", "revoked", "expired"]),
|
|
37694
38506
|
activatedAt: instant2,
|
|
37695
38507
|
revokedAt: instant2.nullable(),
|
|
@@ -37943,10 +38755,10 @@ function sessionToken(value) {
|
|
|
37943
38755
|
return value;
|
|
37944
38756
|
}
|
|
37945
38757
|
function parseWorkspaceSession(value, expected) {
|
|
37946
|
-
const
|
|
37947
|
-
if (
|
|
38758
|
+
const identity4 = parseWorkspaceIdentity(value, expected.userId);
|
|
38759
|
+
if (identity4.user.membershipId !== expected.membershipId)
|
|
37948
38760
|
throw new WorkspaceIdentityMismatchError;
|
|
37949
|
-
return { token: sessionToken(value.token), ...
|
|
38761
|
+
return { token: sessionToken(value.token), ...identity4 };
|
|
37950
38762
|
}
|
|
37951
38763
|
function parseWorkspaceLogin(value, expectedUserId) {
|
|
37952
38764
|
const user = record5(value) && value.user;
|
|
@@ -38157,13 +38969,13 @@ var init_remote_workspace_leave = __esm(() => {
|
|
|
38157
38969
|
|
|
38158
38970
|
// src/lib/auth-store.ts
|
|
38159
38971
|
import { chmodSync, existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync18, renameSync as renameSync4, statSync as statSync9, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
38160
|
-
import { basename as basename12, dirname as
|
|
38972
|
+
import { basename as basename12, dirname as dirname22, join as join33 } from "path";
|
|
38161
38973
|
function getAuthFilePath(env = process.env) {
|
|
38162
38974
|
return skillsCredentialFilePath(env);
|
|
38163
38975
|
}
|
|
38164
38976
|
function getIdentityFilePath(env = process.env) {
|
|
38165
38977
|
const file2 = skillsCredentialFilePath(env);
|
|
38166
|
-
return
|
|
38978
|
+
return join33(dirname22(file2), basename12(file2).replace(/^credentials/, "identity") + ".json");
|
|
38167
38979
|
}
|
|
38168
38980
|
function getApiUrl(action, env = process.env, options = {}) {
|
|
38169
38981
|
return requireSkillsApiOrigin(action, env, options);
|
|
@@ -38391,10 +39203,10 @@ async function readQuoteUnavailableCode(response) {
|
|
|
38391
39203
|
let timer;
|
|
38392
39204
|
let deadlineExceeded = false;
|
|
38393
39205
|
const expired = Symbol("quote body deadline");
|
|
38394
|
-
const deadline = new Promise((
|
|
39206
|
+
const deadline = new Promise((resolve23) => {
|
|
38395
39207
|
timer = setTimeout(() => {
|
|
38396
39208
|
deadlineExceeded = true;
|
|
38397
|
-
|
|
39209
|
+
resolve23(expired);
|
|
38398
39210
|
reader.cancel().catch(() => {});
|
|
38399
39211
|
}, 1500);
|
|
38400
39212
|
});
|
|
@@ -38697,16 +39509,16 @@ class RemoteSkillsClient {
|
|
|
38697
39509
|
async listAccountWorkspaces(expectedUserId) {
|
|
38698
39510
|
const expected = expectedUserId === undefined ? undefined : workspaceExpectedUserId(expectedUserId);
|
|
38699
39511
|
const connection = new RemoteSkillsClient(this.apiKey, this.apiUrl);
|
|
38700
|
-
let
|
|
39512
|
+
let identity4;
|
|
38701
39513
|
if (expected !== undefined) {
|
|
38702
39514
|
const value = await connection.requestWorkspaceSelection("/api/auth/whoami");
|
|
38703
39515
|
if (!value || typeof value !== "object" || value.authMethod !== "jwt")
|
|
38704
39516
|
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces", "INTERACTIVE_SESSION_REQUIRED");
|
|
38705
|
-
|
|
39517
|
+
identity4 = parseWorkspaceIdentity(value, expected);
|
|
38706
39518
|
}
|
|
38707
39519
|
const result = parseAccountWorkspaces(await connection.requestWorkspaceSelection("/api/v1/account/workspaces"));
|
|
38708
39520
|
const current = result.workspaces.find((workspace) => workspace.current);
|
|
38709
|
-
if (
|
|
39521
|
+
if (identity4 && (current.membershipId !== identity4.user.membershipId || current.organization.id !== identity4.organization.id))
|
|
38710
39522
|
throw new WorkspaceIdentityMismatchError;
|
|
38711
39523
|
return result;
|
|
38712
39524
|
}
|
|
@@ -38724,10 +39536,10 @@ class RemoteSkillsClient {
|
|
|
38724
39536
|
const verified = await new RemoteSkillsClient(selected.token, connection.apiUrl).requestWorkspaceSelection("/api/auth/whoami");
|
|
38725
39537
|
if (!verified || typeof verified !== "object" || verified.authMethod !== "jwt")
|
|
38726
39538
|
throw new RemoteWorkspaceSelectionError("/api/v1/account/workspaces/switch", "INTERACTIVE_SESSION_REQUIRED");
|
|
38727
|
-
const
|
|
38728
|
-
if (
|
|
39539
|
+
const identity4 = parseWorkspaceIdentity(verified, target.userId);
|
|
39540
|
+
if (identity4.user.membershipId !== target.membershipId || identity4.organization.id !== selected.organization.id)
|
|
38729
39541
|
throw new WorkspaceIdentityMismatchError;
|
|
38730
|
-
return { token: selected.token, ...
|
|
39542
|
+
return { token: selected.token, ...identity4 };
|
|
38731
39543
|
}
|
|
38732
39544
|
async requestWorkspaceSelection(path, options) {
|
|
38733
39545
|
let response;
|
|
@@ -38811,8 +39623,8 @@ class RemoteSkillsClient {
|
|
|
38811
39623
|
const value = await connection.requestWorkspaceSelection("/api/auth/whoami");
|
|
38812
39624
|
if (!value || typeof value !== "object" || value.authMethod !== "jwt")
|
|
38813
39625
|
throw new RemoteWorkspaceLeaveError("INTERACTIVE_SESSION_REQUIRED");
|
|
38814
|
-
const
|
|
38815
|
-
if (
|
|
39626
|
+
const identity4 = parseWorkspaceIdentity(value, captured.context.userId);
|
|
39627
|
+
if (identity4.user.membershipId !== captured.context.membershipId)
|
|
38816
39628
|
throw new WorkspaceIdentityMismatchError;
|
|
38817
39629
|
let response, body;
|
|
38818
39630
|
try {
|
|
@@ -38827,7 +39639,7 @@ class RemoteSkillsClient {
|
|
|
38827
39639
|
throw new RemoteWorkspaceLeaveError(code);
|
|
38828
39640
|
throw new RemoteWorkspaceLeaveUnconfirmedError;
|
|
38829
39641
|
}
|
|
38830
|
-
return parseWorkspaceLeaveResult(body, captured.context.membershipId,
|
|
39642
|
+
return parseWorkspaceLeaveResult(body, captured.context.membershipId, identity4.organization.id);
|
|
38831
39643
|
}
|
|
38832
39644
|
listWorkspaceInvitations(context, options = {}) {
|
|
38833
39645
|
return this.requestWorkspaceInvitation(context, "list", options);
|
|
@@ -38853,8 +39665,8 @@ class RemoteSkillsClient {
|
|
|
38853
39665
|
const identityValue = await connection.requestWorkspaceSelection("/api/auth/whoami");
|
|
38854
39666
|
if (!identityValue || typeof identityValue !== "object" || identityValue.authMethod !== "jwt")
|
|
38855
39667
|
throw new RemoteWorkspaceInvitationError("INTERACTIVE_SESSION_REQUIRED");
|
|
38856
|
-
const
|
|
38857
|
-
if (
|
|
39668
|
+
const identity4 = parseWorkspaceIdentity(identityValue, target.userId);
|
|
39669
|
+
if (identity4.user.membershipId !== target.membershipId)
|
|
38858
39670
|
throw new WorkspaceIdentityMismatchError;
|
|
38859
39671
|
const request = invitationRequest(action, captured), read2 = action === "list" || action === "get";
|
|
38860
39672
|
let response, value;
|
|
@@ -38871,7 +39683,7 @@ class RemoteSkillsClient {
|
|
|
38871
39683
|
throw read2 ? new RemoteWorkspaceInvitationReadError : new RemoteWorkspaceInvitationUnconfirmedError;
|
|
38872
39684
|
}
|
|
38873
39685
|
try {
|
|
38874
|
-
return parseInvitationResult(action, value, captured,
|
|
39686
|
+
return parseInvitationResult(action, value, captured, identity4.organization.id);
|
|
38875
39687
|
} catch {
|
|
38876
39688
|
throw read2 ? new RemoteWorkspaceInvitationReadError : new RemoteWorkspaceInvitationUnconfirmedError;
|
|
38877
39689
|
}
|
|
@@ -38912,7 +39724,7 @@ class RemoteSkillsClient {
|
|
|
38912
39724
|
} catch {
|
|
38913
39725
|
throw new RemoteRecurringUnavailableError;
|
|
38914
39726
|
}
|
|
38915
|
-
let
|
|
39727
|
+
let identity4, identityValue;
|
|
38916
39728
|
try {
|
|
38917
39729
|
const response = await connection.request("/api/auth/whoami");
|
|
38918
39730
|
if (!response.ok) {
|
|
@@ -38921,8 +39733,8 @@ class RemoteSkillsClient {
|
|
|
38921
39733
|
}
|
|
38922
39734
|
identityValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readBoundedResponse(response, 64 * 1024)));
|
|
38923
39735
|
const observedUser = identityValue.user?.id;
|
|
38924
|
-
|
|
38925
|
-
if (target &&
|
|
39736
|
+
identity4 = parseWorkspaceIdentity(identityValue, target?.userId ?? workspaceExpectedUserId(observedUser));
|
|
39737
|
+
if (target && identity4.user.membershipId !== target.membershipId)
|
|
38926
39738
|
throw new WorkspaceIdentityMismatchError;
|
|
38927
39739
|
} catch {
|
|
38928
39740
|
throw new RemoteRecurringReadError;
|
|
@@ -38932,16 +39744,16 @@ class RemoteSkillsClient {
|
|
|
38932
39744
|
throw new RemoteRecurringError("RECURRING_HUMAN_APPROVAL_REQUIRED");
|
|
38933
39745
|
assertRecurringCapability(capability, "draft");
|
|
38934
39746
|
const selected = captured;
|
|
38935
|
-
const draft = await connection.dispatchRecurring("draft", { draftId: selected.draftId },
|
|
39747
|
+
const draft = await connection.dispatchRecurring("draft", { draftId: selected.draftId }, identity4);
|
|
38936
39748
|
if (!draft || draft.termsSha256 !== selected.approval.acceptedTermsSha256)
|
|
38937
39749
|
throw new RemoteRecurringError("RECURRING_TERMS_UNAVAILABLE");
|
|
38938
39750
|
}
|
|
38939
39751
|
let selectedConsent;
|
|
38940
39752
|
if (action === "occurrences") {
|
|
38941
39753
|
assertRecurringCapability(capability, "get");
|
|
38942
|
-
selectedConsent = await connection.dispatchRecurring("get", { consentId: captured.consentId },
|
|
39754
|
+
selectedConsent = await connection.dispatchRecurring("get", { consentId: captured.consentId }, identity4);
|
|
38943
39755
|
}
|
|
38944
|
-
const result = await connection.dispatchRecurring(action, captured,
|
|
39756
|
+
const result = await connection.dispatchRecurring(action, captured, identity4);
|
|
38945
39757
|
if (action === "occurrences") {
|
|
38946
39758
|
const items = result.items;
|
|
38947
39759
|
if (items.length && (!selectedConsent || items.some((item) => item.scheduleId !== selectedConsent.scheduleId)))
|
|
@@ -38949,7 +39761,7 @@ class RemoteSkillsClient {
|
|
|
38949
39761
|
}
|
|
38950
39762
|
return result;
|
|
38951
39763
|
}
|
|
38952
|
-
async dispatchRecurring(action, input2,
|
|
39764
|
+
async dispatchRecurring(action, input2, identity4) {
|
|
38953
39765
|
const request = recurringRequest(action, input2);
|
|
38954
39766
|
let response, value;
|
|
38955
39767
|
try {
|
|
@@ -38969,7 +39781,7 @@ class RemoteSkillsClient {
|
|
|
38969
39781
|
try {
|
|
38970
39782
|
if (response.status !== 200 || value === null)
|
|
38971
39783
|
throw new RemoteRecurringReadError;
|
|
38972
|
-
return parseRecurringResult(action, value, input2,
|
|
39784
|
+
return parseRecurringResult(action, value, input2, identity4);
|
|
38973
39785
|
} catch {
|
|
38974
39786
|
throw request.read ? new RemoteRecurringReadError : new RemoteRecurringUnconfirmedError;
|
|
38975
39787
|
}
|
|
@@ -39632,13 +40444,13 @@ var init_remote_invitation_recovery = __esm(() => {
|
|
|
39632
40444
|
});
|
|
39633
40445
|
|
|
39634
40446
|
// src/lib/remote-private-publications.ts
|
|
39635
|
-
import { createHash as
|
|
40447
|
+
import { createHash as createHash23 } from "crypto";
|
|
39636
40448
|
function checkedPublicationDeclaration(value) {
|
|
39637
|
-
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !
|
|
40449
|
+
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash4(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
39638
40450
|
return bad();
|
|
39639
40451
|
try {
|
|
39640
40452
|
const manifest = JSON.parse(value.manifestText);
|
|
39641
|
-
if (!record9(manifest) || manifest.version !== value.version || validatePortableManifestContract(manifest, { strict: true }).length || !
|
|
40453
|
+
if (!record9(manifest) || manifest.version !== value.version || validatePortableManifestContract(manifest, { strict: true }).length || !hash4(manifest.provenance?.content_hash))
|
|
39642
40454
|
return bad();
|
|
39643
40455
|
} catch {
|
|
39644
40456
|
return bad();
|
|
@@ -39646,7 +40458,7 @@ function checkedPublicationDeclaration(value) {
|
|
|
39646
40458
|
return Object.freeze({ ...value });
|
|
39647
40459
|
}
|
|
39648
40460
|
function checkedPublicationView(value, skillId, intentId, declaration) {
|
|
39649
|
-
if (!exact(value, ["id", "skillId", "version", "expectedCurrentVersionId", "archiveSha256", "archiveByteSize", "state", "expiresAt", "createdAt", "versionId"]) || !publicationUuid(value.id) || value.skillId !== skillId || intentId !== undefined && value.id !== intentId || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || !
|
|
40461
|
+
if (!exact(value, ["id", "skillId", "version", "expectedCurrentVersionId", "archiveSha256", "archiveByteSize", "state", "expiresAt", "createdAt", "versionId"]) || !publicationUuid(value.id) || value.skillId !== skillId || intentId !== undefined && value.id !== intentId || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || !hash4(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES || typeof value.state !== "string" || !["awaiting_upload", "queued", "verifying", "needs_attention", "committed", "rejected", "cancelled", "expired"].includes(value.state) || !date5(value.expiresAt) || !date5(value.createdAt) || !(value.versionId === null || publicationUuid(value.versionId)) || value.state === "committed" && value.versionId === null)
|
|
39650
40462
|
return invalid4();
|
|
39651
40463
|
if (declaration && ["version", "expectedCurrentVersionId", "archiveSha256", "archiveByteSize"].some((k) => value[k] !== declaration[k]))
|
|
39652
40464
|
return invalid4();
|
|
@@ -39877,12 +40689,12 @@ class RemotePrivatePublicationsClient {
|
|
|
39877
40689
|
previous = view;
|
|
39878
40690
|
if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
|
|
39879
40691
|
return view;
|
|
39880
|
-
await new Promise((
|
|
40692
|
+
await new Promise((resolve23) => {
|
|
39881
40693
|
const timer = setTimeout(done, Math.min(1000, until - Date.now()));
|
|
39882
40694
|
function done() {
|
|
39883
40695
|
clearTimeout(timer);
|
|
39884
40696
|
options.signal?.removeEventListener("abort", done);
|
|
39885
|
-
|
|
40697
|
+
resolve23();
|
|
39886
40698
|
}
|
|
39887
40699
|
options.signal?.addEventListener("abort", done, { once: true });
|
|
39888
40700
|
});
|
|
@@ -39893,7 +40705,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures2, PrivatePublicationError, bad = ()
|
|
|
39893
40705
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
39894
40706
|
}, invalid4 = () => {
|
|
39895
40707
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
39896
|
-
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v),
|
|
40708
|
+
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash4 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record9 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record9(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date5 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash23("sha256").update(bytes).digest("hex");
|
|
39897
40709
|
var init_remote_private_publications = __esm(() => {
|
|
39898
40710
|
init_fleet_credentials();
|
|
39899
40711
|
init_remote_workspace_selection();
|
|
@@ -40170,10 +40982,10 @@ var init_remote_auth = __esm(() => {
|
|
|
40170
40982
|
});
|
|
40171
40983
|
|
|
40172
40984
|
// src/lib/workspace-profile.ts
|
|
40173
|
-
import { constants as
|
|
40985
|
+
import { constants as constants15, closeSync as closeSync17, fstatSync as fstatSync17, lstatSync as lstatSync23, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync2, openSync as openSync17, readFileSync as readFileSync19, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
40174
40986
|
function stat2(path) {
|
|
40175
40987
|
try {
|
|
40176
|
-
return
|
|
40988
|
+
return lstatSync23(path);
|
|
40177
40989
|
} catch (error61) {
|
|
40178
40990
|
if (error61.code === "ENOENT")
|
|
40179
40991
|
return null;
|
|
@@ -40183,17 +40995,17 @@ function stat2(path) {
|
|
|
40183
40995
|
function safeText(file2) {
|
|
40184
40996
|
if (stat2(file2) === null)
|
|
40185
40997
|
return null;
|
|
40186
|
-
const fd =
|
|
40998
|
+
const fd = openSync17(file2, constants15.O_RDONLY | constants15.O_NOFOLLOW | constants15.O_NONBLOCK);
|
|
40187
40999
|
try {
|
|
40188
|
-
const s =
|
|
41000
|
+
const s = fstatSync17(fd);
|
|
40189
41001
|
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
40190
41002
|
return fail("The selected profile must use bounded owner-only regular files.");
|
|
40191
41003
|
return readFileSync19(fd, "utf8");
|
|
40192
41004
|
} finally {
|
|
40193
|
-
|
|
41005
|
+
closeSync17(fd);
|
|
40194
41006
|
}
|
|
40195
41007
|
}
|
|
40196
|
-
function checkIdentityMetadata(file2,
|
|
41008
|
+
function checkIdentityMetadata(file2, identity4) {
|
|
40197
41009
|
const text3 = safeText(file2);
|
|
40198
41010
|
if (text3 === null)
|
|
40199
41011
|
return;
|
|
@@ -40205,7 +41017,7 @@ function checkIdentityMetadata(file2, identity3) {
|
|
|
40205
41017
|
}
|
|
40206
41018
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
40207
41019
|
return fail("The profile identity metadata is invalid.");
|
|
40208
|
-
for (const [key, expected] of Object.entries({ userId:
|
|
41020
|
+
for (const [key, expected] of Object.entries({ userId: identity4.user.id, orgId: identity4.organization.id })) {
|
|
40209
41021
|
if (value[key] !== undefined && value[key] !== expected)
|
|
40210
41022
|
return fail("The profile identity metadata does not match its authenticated key. Sign in again before managing this workspace.");
|
|
40211
41023
|
}
|
|
@@ -40227,10 +41039,10 @@ function prepareProfileWorkspace(action, source = process.env) {
|
|
|
40227
41039
|
const connection = await resolveSkillsConnection(env);
|
|
40228
41040
|
if (!connection || connection.apiOrigin !== origin)
|
|
40229
41041
|
return fail("The selected profile has no usable credential for this server.");
|
|
40230
|
-
const
|
|
40231
|
-
checkIdentityMetadata(getIdentityFilePath(env),
|
|
41042
|
+
const identity4 = await keyIdentity(connection.apiKey, origin);
|
|
41043
|
+
checkIdentityMetadata(getIdentityFilePath(env), identity4);
|
|
40232
41044
|
unchanged3();
|
|
40233
|
-
const context = { userId:
|
|
41045
|
+
const context = { userId: identity4.user.id, membershipId: identity4.user.membershipId };
|
|
40234
41046
|
return { origin, context, unchanged: unchanged3 };
|
|
40235
41047
|
} };
|
|
40236
41048
|
}
|
|
@@ -40311,15 +41123,15 @@ async function prepareRecurringCustomer(requested, source = process.env) {
|
|
|
40311
41123
|
await assertCurrent();
|
|
40312
41124
|
const value = await new RemoteSkillsClient(connection.apiKey, connection.apiOrigin).getIdentity();
|
|
40313
41125
|
const user = value.user;
|
|
40314
|
-
const
|
|
41126
|
+
const identity4 = parseWorkspaceIdentity(value, context?.userId ?? workspaceExpectedUserId(user?.id));
|
|
40315
41127
|
await assertCurrent();
|
|
40316
|
-
if (value.authMethod !== "api_key" || context &&
|
|
41128
|
+
if (value.authMethod !== "api_key" || context && identity4.user.membershipId !== context.membershipId)
|
|
40317
41129
|
changed();
|
|
40318
|
-
const binding = JSON.stringify([
|
|
41130
|
+
const binding = JSON.stringify([identity4.user.id, identity4.user.membershipId, identity4.organization.id]);
|
|
40319
41131
|
if (originalIdentity !== undefined && originalIdentity !== binding)
|
|
40320
41132
|
changed();
|
|
40321
41133
|
originalIdentity = binding;
|
|
40322
|
-
if (verification(
|
|
41134
|
+
if (verification(identity4.user.email) !== normalized)
|
|
40323
41135
|
throw new RecurringCustomerError("RECURRING_ACCOUNT_EMAIL_MISMATCH", "Use the selected account's current email. No verification request or recurring activation was submitted.");
|
|
40324
41136
|
return normalized;
|
|
40325
41137
|
}
|
|
@@ -40402,8 +41214,8 @@ var init_recurring_customer = __esm(() => {
|
|
|
40402
41214
|
});
|
|
40403
41215
|
|
|
40404
41216
|
// src/lib/recurring-recovery.ts
|
|
40405
|
-
import { constants as
|
|
40406
|
-
import { dirname as
|
|
41217
|
+
import { constants as constants16, closeSync as closeSync18, fsyncSync as fsyncSync5, fstatSync as fstatSync18, lstatSync as lstatSync24, mkdirSync as mkdirSync11, openSync as openSync18, readSync as readSync12, realpathSync as realpathSync11, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync9 } from "fs";
|
|
41218
|
+
import { dirname as dirname23, isAbsolute as isAbsolute21, join as join34, resolve as resolve23 } from "path";
|
|
40407
41219
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
40408
41220
|
|
|
40409
41221
|
class RecoveryOwner {
|
|
@@ -40411,75 +41223,75 @@ class RecoveryOwner {
|
|
|
40411
41223
|
parents = [];
|
|
40412
41224
|
constructor(directory) {
|
|
40413
41225
|
this.directory = directory;
|
|
40414
|
-
if (!
|
|
41226
|
+
if (!isAbsolute21(directory) || resolve23(directory) !== directory || realpathSync11(directory) !== directory)
|
|
40415
41227
|
invalid5();
|
|
40416
|
-
for (let path = directory;; path =
|
|
40417
|
-
const stat3 =
|
|
41228
|
+
for (let path = directory;; path = dirname23(path)) {
|
|
41229
|
+
const stat3 = lstatSync24(path);
|
|
40418
41230
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
40419
41231
|
invalid5();
|
|
40420
41232
|
this.parents.push({ path, dev: stat3.dev, ino: stat3.ino });
|
|
40421
|
-
if (path ===
|
|
41233
|
+
if (path === dirname23(path))
|
|
40422
41234
|
break;
|
|
40423
41235
|
}
|
|
40424
41236
|
this.assert();
|
|
40425
41237
|
}
|
|
40426
41238
|
assert() {
|
|
40427
|
-
if (
|
|
41239
|
+
if (realpathSync11(this.directory) !== this.directory)
|
|
40428
41240
|
invalid5();
|
|
40429
41241
|
for (const prior of this.parents) {
|
|
40430
|
-
const now =
|
|
41242
|
+
const now = lstatSync24(prior.path);
|
|
40431
41243
|
if (!now.isDirectory() || now.isSymbolicLink() || now.dev !== prior.dev || now.ino !== prior.ino)
|
|
40432
41244
|
invalid5();
|
|
40433
41245
|
}
|
|
40434
|
-
const own2 =
|
|
41246
|
+
const own2 = lstatSync24(this.directory);
|
|
40435
41247
|
if ((own2.mode & 511) !== 448 || (own2.mode & 3584) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
40436
41248
|
invalid5();
|
|
40437
41249
|
}
|
|
40438
41250
|
read(name) {
|
|
40439
41251
|
this.assert();
|
|
40440
|
-
const fd =
|
|
41252
|
+
const fd = openSync18(join34(this.directory, name), constants16.O_RDONLY | constants16.O_NOFOLLOW | constants16.O_NONBLOCK);
|
|
40441
41253
|
try {
|
|
40442
|
-
const before =
|
|
41254
|
+
const before = fstatSync18(fd);
|
|
40443
41255
|
if (!before.isFile() || before.nlink !== 1 || (before.mode & 4095) !== 384 || before.size < 1 || before.size > 8192 || process.getuid && before.uid !== process.getuid())
|
|
40444
41256
|
invalid5();
|
|
40445
41257
|
const bytes = Buffer.alloc(before.size + 1);
|
|
40446
41258
|
let size = 0;
|
|
40447
41259
|
while (size < bytes.length) {
|
|
40448
|
-
const n2 =
|
|
41260
|
+
const n2 = readSync12(fd, bytes, size, bytes.length - size, size);
|
|
40449
41261
|
if (!n2)
|
|
40450
41262
|
break;
|
|
40451
41263
|
size += n2;
|
|
40452
41264
|
}
|
|
40453
|
-
const after =
|
|
41265
|
+
const after = fstatSync18(fd), path = lstatSync24(join34(this.directory, name));
|
|
40454
41266
|
if (size !== before.size || after.size !== before.size || before.mtimeMs !== after.mtimeMs || before.ctimeMs !== after.ctimeMs || path.dev !== before.dev || path.ino !== before.ino || !path.isFile() || path.isSymbolicLink())
|
|
40455
41267
|
invalid5();
|
|
40456
41268
|
this.assert();
|
|
40457
41269
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size));
|
|
40458
41270
|
} finally {
|
|
40459
|
-
|
|
41271
|
+
closeSync18(fd);
|
|
40460
41272
|
}
|
|
40461
41273
|
}
|
|
40462
41274
|
write(name, value) {
|
|
40463
41275
|
this.assert();
|
|
40464
41276
|
const bytes = canonicalJson2(value, 8192) + `
|
|
40465
41277
|
`;
|
|
40466
|
-
const fd =
|
|
41278
|
+
const fd = openSync18(join34(this.directory, name), constants16.O_WRONLY | constants16.O_CREAT | constants16.O_EXCL | constants16.O_NOFOLLOW, 384);
|
|
40467
41279
|
try {
|
|
40468
41280
|
writeFileSync9(fd, bytes);
|
|
40469
41281
|
fsyncSync5(fd);
|
|
40470
41282
|
} finally {
|
|
40471
|
-
|
|
41283
|
+
closeSync18(fd);
|
|
40472
41284
|
}
|
|
40473
41285
|
this.assert();
|
|
40474
41286
|
this.sync();
|
|
40475
41287
|
}
|
|
40476
41288
|
sync() {
|
|
40477
41289
|
this.assert();
|
|
40478
|
-
const fd =
|
|
41290
|
+
const fd = openSync18(this.directory, constants16.O_RDONLY | constants16.O_NOFOLLOW);
|
|
40479
41291
|
try {
|
|
40480
41292
|
fsyncSync5(fd);
|
|
40481
41293
|
} finally {
|
|
40482
|
-
|
|
41294
|
+
closeSync18(fd);
|
|
40483
41295
|
}
|
|
40484
41296
|
}
|
|
40485
41297
|
saveState(state, expected) {
|
|
@@ -40490,30 +41302,30 @@ class RecoveryOwner {
|
|
|
40490
41302
|
if (this.read("state.json") !== expected)
|
|
40491
41303
|
invalid5();
|
|
40492
41304
|
this.assert();
|
|
40493
|
-
renameSync6(
|
|
41305
|
+
renameSync6(join34(this.directory, name), join34(this.directory, "state.json"));
|
|
40494
41306
|
this.sync();
|
|
40495
41307
|
}
|
|
40496
41308
|
async locked(action) {
|
|
40497
41309
|
this.assert();
|
|
40498
41310
|
let fd;
|
|
40499
41311
|
try {
|
|
40500
|
-
fd =
|
|
41312
|
+
fd = openSync18(join34(this.directory, "operation.lock"), constants16.O_WRONLY | constants16.O_CREAT | constants16.O_EXCL | constants16.O_NOFOLLOW, 384);
|
|
40501
41313
|
} catch {
|
|
40502
41314
|
throw new RecurringCustomerError("RECURRING_RECOVERY_BUSY", "Recovery is locked. Confirm the original process has stopped before explicitly reconciling the retained lock; no request was retried.");
|
|
40503
41315
|
}
|
|
40504
|
-
const owner2 =
|
|
41316
|
+
const owner2 = fstatSync18(fd);
|
|
40505
41317
|
try {
|
|
40506
41318
|
writeFileSync9(fd, JSON.stringify({ pid: process.pid }));
|
|
40507
41319
|
fsyncSync5(fd);
|
|
40508
41320
|
this.sync();
|
|
40509
41321
|
return await action();
|
|
40510
41322
|
} finally {
|
|
40511
|
-
|
|
41323
|
+
closeSync18(fd);
|
|
40512
41324
|
this.assert();
|
|
40513
|
-
const now =
|
|
41325
|
+
const now = lstatSync24(join34(this.directory, "operation.lock"));
|
|
40514
41326
|
if (owner2.dev !== now.dev || owner2.ino !== now.ino || !now.isFile() || now.isSymbolicLink())
|
|
40515
41327
|
invalid5();
|
|
40516
|
-
unlinkSync5(
|
|
41328
|
+
unlinkSync5(join34(this.directory, "operation.lock"));
|
|
40517
41329
|
this.sync();
|
|
40518
41330
|
}
|
|
40519
41331
|
}
|
|
@@ -40546,7 +41358,7 @@ function base(customer, organizationId) {
|
|
|
40546
41358
|
};
|
|
40547
41359
|
}
|
|
40548
41360
|
function create(directory, intent) {
|
|
40549
|
-
if (!
|
|
41361
|
+
if (!isAbsolute21(directory) || resolve23(directory) !== directory || realpathSync11(dirname23(directory)) !== dirname23(directory))
|
|
40550
41362
|
invalid5();
|
|
40551
41363
|
mkdirSync11(directory, { mode: 448 });
|
|
40552
41364
|
const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -40709,12 +41521,12 @@ var init_recurring_recovery = __esm(() => {
|
|
|
40709
41521
|
});
|
|
40710
41522
|
|
|
40711
41523
|
// src/lib/recurring-surface.ts
|
|
40712
|
-
import { isAbsolute as
|
|
41524
|
+
import { isAbsolute as isAbsolute22 } from "path";
|
|
40713
41525
|
function recurringMcpSchema(action) {
|
|
40714
41526
|
return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
|
|
40715
41527
|
}
|
|
40716
|
-
function expectedDraft(draft,
|
|
40717
|
-
if (!draft || draft.termsSha256 !==
|
|
41528
|
+
function expectedDraft(draft, hash5) {
|
|
41529
|
+
if (!draft || draft.termsSha256 !== hash5)
|
|
40718
41530
|
throw new RemoteRecurringError("RECURRING_TERMS_UNAVAILABLE");
|
|
40719
41531
|
return draft;
|
|
40720
41532
|
}
|
|
@@ -40814,7 +41626,7 @@ var init_recurring_surface = __esm(() => {
|
|
|
40814
41626
|
uuid13 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
40815
41627
|
context = { userId: uuid13.optional(), membershipId: uuid13.optional() };
|
|
40816
41628
|
page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
|
|
40817
|
-
directory = exports_external.string().max(4096).refine(
|
|
41629
|
+
directory = exports_external.string().max(4096).refine(isAbsolute22, "Use an absolute recovery directory");
|
|
40818
41630
|
email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
40819
41631
|
code = exports_external.string().regex(/^\d{6}$/);
|
|
40820
41632
|
recurringSurfaceSchemas = {
|
|
@@ -42643,21 +43455,21 @@ var init_credential_state = __esm(() => {
|
|
|
42643
43455
|
});
|
|
42644
43456
|
|
|
42645
43457
|
// src/lib/run-state.ts
|
|
42646
|
-
import { createHash as
|
|
42647
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync20, readdirSync as
|
|
42648
|
-
import { extname, join as
|
|
43458
|
+
import { createHash as createHash24, randomBytes } from "crypto";
|
|
43459
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync20, readdirSync as readdirSync11, statSync as statSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
43460
|
+
import { extname, join as join35, relative as relative9 } from "path";
|
|
42649
43461
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
42650
43462
|
const now = new Date;
|
|
42651
43463
|
const id = createRunId(now);
|
|
42652
43464
|
const day = now.toISOString().slice(0, 10);
|
|
42653
43465
|
const skillName = normalizeSkillName(params.skill);
|
|
42654
43466
|
const root = getProjectStateDir(targetDir);
|
|
42655
|
-
const runDir =
|
|
42656
|
-
const logsDir =
|
|
42657
|
-
const exportDir =
|
|
43467
|
+
const runDir = join35(root, "runs", day, id);
|
|
43468
|
+
const logsDir = join35(runDir, "logs");
|
|
43469
|
+
const exportDir = join35(root, "exports", skillName, id);
|
|
42658
43470
|
mkdirSync12(logsDir, { recursive: true });
|
|
42659
43471
|
mkdirSync12(exportDir, { recursive: true });
|
|
42660
|
-
mkdirSync12(
|
|
43472
|
+
mkdirSync12(join35(root, "tmp"), { recursive: true });
|
|
42661
43473
|
const record10 = {
|
|
42662
43474
|
id,
|
|
42663
43475
|
skill: skillName,
|
|
@@ -42709,22 +43521,22 @@ function updateSkillRun(context2, patch) {
|
|
|
42709
43521
|
return context2.record;
|
|
42710
43522
|
}
|
|
42711
43523
|
function writeRunLogs(context2, stdout = "", stderr = "") {
|
|
42712
|
-
writeFileSync10(
|
|
42713
|
-
writeFileSync10(
|
|
43524
|
+
writeFileSync10(join35(context2.logsDir, "stdout.log"), stdout);
|
|
43525
|
+
writeFileSync10(join35(context2.logsDir, "stderr.log"), stderr);
|
|
42714
43526
|
}
|
|
42715
43527
|
function appendRunEvent(context2, event, data = {}) {
|
|
42716
43528
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
42717
43529
|
`;
|
|
42718
|
-
const path =
|
|
43530
|
+
const path = join35(context2.runDir, "events.ndjson");
|
|
42719
43531
|
const previous = existsSync15(path) ? readFileSync20(path, "utf-8") : "";
|
|
42720
43532
|
writeFileSync10(path, previous + line);
|
|
42721
43533
|
}
|
|
42722
43534
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
42723
|
-
const runsRoot =
|
|
43535
|
+
const runsRoot = join35(getProjectStateDir(targetDir), "runs");
|
|
42724
43536
|
if (!existsSync15(runsRoot))
|
|
42725
43537
|
return null;
|
|
42726
|
-
for (const day of
|
|
42727
|
-
const record10 = readRunRecord(
|
|
43538
|
+
for (const day of readdirSync11(runsRoot)) {
|
|
43539
|
+
const record10 = readRunRecord(join35(runsRoot, day, runId));
|
|
42728
43540
|
if (record10)
|
|
42729
43541
|
return record10;
|
|
42730
43542
|
}
|
|
@@ -42741,11 +43553,11 @@ function skillRunEnv(context2) {
|
|
|
42741
43553
|
};
|
|
42742
43554
|
}
|
|
42743
43555
|
function writeRunRecord(context2) {
|
|
42744
|
-
writeFileSync10(
|
|
43556
|
+
writeFileSync10(join35(context2.runDir, "run.json"), JSON.stringify(context2.record, null, 2) + `
|
|
42745
43557
|
`);
|
|
42746
43558
|
}
|
|
42747
43559
|
function writeArtifactsManifest(context2, artifacts) {
|
|
42748
|
-
writeFileSync10(
|
|
43560
|
+
writeFileSync10(join35(context2.runDir, "artifacts.json"), JSON.stringify({ runId: context2.record.id, artifacts }, null, 2) + `
|
|
42749
43561
|
`);
|
|
42750
43562
|
}
|
|
42751
43563
|
function collectRunArtifacts(context2) {
|
|
@@ -42758,14 +43570,14 @@ function collectRunArtifacts(context2) {
|
|
|
42758
43570
|
artifacts.push({
|
|
42759
43571
|
path: toProjectRelative(context2.targetDir, path),
|
|
42760
43572
|
mime: mimeForPath(path),
|
|
42761
|
-
sha256:
|
|
43573
|
+
sha256: createHash24("sha256").update(bytes).digest("hex"),
|
|
42762
43574
|
sizeBytes: stat3.size
|
|
42763
43575
|
});
|
|
42764
43576
|
}
|
|
42765
43577
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
42766
43578
|
}
|
|
42767
43579
|
function readRunRecord(runDir) {
|
|
42768
|
-
const path =
|
|
43580
|
+
const path = join35(runDir, "run.json");
|
|
42769
43581
|
if (!existsSync15(path))
|
|
42770
43582
|
return null;
|
|
42771
43583
|
try {
|
|
@@ -42776,8 +43588,8 @@ function readRunRecord(runDir) {
|
|
|
42776
43588
|
}
|
|
42777
43589
|
function walkFiles(dir) {
|
|
42778
43590
|
const files = [];
|
|
42779
|
-
for (const entry of
|
|
42780
|
-
const full =
|
|
43591
|
+
for (const entry of readdirSync11(dir)) {
|
|
43592
|
+
const full = join35(dir, entry);
|
|
42781
43593
|
if (statSync10(full).isDirectory())
|
|
42782
43594
|
files.push(...walkFiles(full));
|
|
42783
43595
|
else
|
|
@@ -42789,7 +43601,7 @@ function createRunId(now) {
|
|
|
42789
43601
|
return `run_${now.getTime().toString(36)}_${randomBytes(4).toString("hex")}`;
|
|
42790
43602
|
}
|
|
42791
43603
|
function toProjectRelative(targetDir, path) {
|
|
42792
|
-
const rel =
|
|
43604
|
+
const rel = relative9(targetDir, path).split(/[\\/]/).join("/");
|
|
42793
43605
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
42794
43606
|
}
|
|
42795
43607
|
function mimeForPath(path) {
|
|
@@ -43030,11 +43842,11 @@ var init_cloud_executions = __esm(() => {
|
|
|
43030
43842
|
// node_modules/@hasna/secrets/dist/sdk.js
|
|
43031
43843
|
import { isIP as isIP2 } from "net";
|
|
43032
43844
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
43033
|
-
import { closeSync as
|
|
43845
|
+
import { closeSync as closeSync19, fstatSync as fstatSync19, openSync as openSync19, readFileSync as readFileSync21 } from "fs";
|
|
43034
43846
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
43035
43847
|
import { createRequire as createRequire2 } from "module";
|
|
43036
43848
|
import { hostname as osHostname2 } from "os";
|
|
43037
|
-
import { isAbsolute as
|
|
43849
|
+
import { isAbsolute as isAbsolute23, join as join36 } from "path";
|
|
43038
43850
|
import { createRequire as createRequire22 } from "module";
|
|
43039
43851
|
function envToken2(name) {
|
|
43040
43852
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -43058,21 +43870,21 @@ function homeDir2(env) {
|
|
|
43058
43870
|
}
|
|
43059
43871
|
function absoluteOverride2(env, key) {
|
|
43060
43872
|
const value = env[key]?.trim();
|
|
43061
|
-
return value &&
|
|
43873
|
+
return value && isAbsolute23(value) ? value : null;
|
|
43062
43874
|
}
|
|
43063
43875
|
function hasnaHomeDir2(env) {
|
|
43064
43876
|
const override = absoluteOverride2(env, HASNA_HOME_ENV_KEY2);
|
|
43065
43877
|
if (override)
|
|
43066
43878
|
return override;
|
|
43067
43879
|
const home = homeDir2(env);
|
|
43068
|
-
return home ?
|
|
43880
|
+
return home ? join36(home, HASNA_HOME_DIR2) : null;
|
|
43069
43881
|
}
|
|
43070
43882
|
function appConfigDir2(name, env) {
|
|
43071
43883
|
const configRoot = absoluteOverride2(env, HASNA_CONFIG_HOME_ENV_KEY2);
|
|
43072
43884
|
if (configRoot)
|
|
43073
|
-
return
|
|
43885
|
+
return join36(configRoot, name);
|
|
43074
43886
|
const root = hasnaHomeDir2(env);
|
|
43075
|
-
return root ?
|
|
43887
|
+
return root ? join36(root, name, CONFIG_SUBDIR2) : null;
|
|
43076
43888
|
}
|
|
43077
43889
|
function credentialDiskSourceList2(name, env, profile = null) {
|
|
43078
43890
|
if (!SAFE_APP_SLUG2.test(name))
|
|
@@ -43081,7 +43893,7 @@ function credentialDiskSourceList2(name, env, profile = null) {
|
|
|
43081
43893
|
if (!directory2)
|
|
43082
43894
|
return [];
|
|
43083
43895
|
const file2 = profile ? `${CREDENTIALS_FILE2}-${profile}` : CREDENTIALS_FILE2;
|
|
43084
|
-
return [{ path:
|
|
43896
|
+
return [{ path: join36(directory2, file2), tier: "disk" }];
|
|
43085
43897
|
}
|
|
43086
43898
|
function credentialDiskSources2(name, env) {
|
|
43087
43899
|
return credentialDiskSourceList2(name, env, null).map((s) => s.path);
|
|
@@ -43135,7 +43947,7 @@ function readAppConfigFile2(path) {
|
|
|
43135
43947
|
};
|
|
43136
43948
|
let fd = -1;
|
|
43137
43949
|
try {
|
|
43138
|
-
fd =
|
|
43950
|
+
fd = openSync19(path, O_RDONLY3 | O_NOFOLLOW3 | O_NONBLOCK3);
|
|
43139
43951
|
} catch (error61) {
|
|
43140
43952
|
const code2 = error61.code;
|
|
43141
43953
|
if (code2 === "ENOENT" || code2 === "ENOTDIR")
|
|
@@ -43145,7 +43957,7 @@ function readAppConfigFile2(path) {
|
|
|
43145
43957
|
unsafe(`the path could not be opened (${code2 ?? "unknown error"})`);
|
|
43146
43958
|
}
|
|
43147
43959
|
try {
|
|
43148
|
-
const before =
|
|
43960
|
+
const before = fstatSync19(fd);
|
|
43149
43961
|
if (!before.isFile())
|
|
43150
43962
|
unsafe("the path is not a regular file");
|
|
43151
43963
|
if (!configFileModeAllowed2(before.mode)) {
|
|
@@ -43157,14 +43969,14 @@ function readAppConfigFile2(path) {
|
|
|
43157
43969
|
if (before.size > MAX_CREDENTIAL_FILE_BYTES2)
|
|
43158
43970
|
unsafe("the file exceeds the size limit");
|
|
43159
43971
|
const bytes = readFileSync21(fd);
|
|
43160
|
-
const after =
|
|
43972
|
+
const after = fstatSync19(fd);
|
|
43161
43973
|
if (!configFileReadsCoherent2(before, after)) {
|
|
43162
43974
|
unsafe("the file changed while being read");
|
|
43163
43975
|
}
|
|
43164
43976
|
return parseEnvFile2(bytes.toString("utf8"));
|
|
43165
43977
|
} finally {
|
|
43166
43978
|
if (fd !== -1)
|
|
43167
|
-
|
|
43979
|
+
closeSync19(fd);
|
|
43168
43980
|
}
|
|
43169
43981
|
}
|
|
43170
43982
|
function readCredentialFile2(path, apiKeyKeys) {
|
|
@@ -44195,7 +45007,7 @@ function createSecretsClientFromEnv(env = process.env, overrides = {}) {
|
|
|
44195
45007
|
});
|
|
44196
45008
|
return new SecretsClient({ ...clientOverrides, baseUrl, apiKey });
|
|
44197
45009
|
}
|
|
44198
|
-
var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE", CredentialResolutionError2, CredentialFileUnsafeError2, HASNA_HOME_ENV_KEY2 = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY2 = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY2 = "HASNA_STATION", HASNA_HOME_DIR2 = ".hasna", CONFIG_SUBDIR2 = "config", CREDENTIALS_FILE2 = "credentials", KEYCHAIN_SECURITY_BIN2 = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX2 = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS2 = 44, KEYCHAIN_SPAWN_TIMEOUT_MS2 = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG2, SAFE_PROFILE2, ILLEGAL_IN_HEADER_VALUE2, VAULT_POINTER_SHAPE2, CREDENTIAL_SHAPED_KEY2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", AMBIENT_ENVIRONMENT2, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN2 = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN2, DNS_LABEL_PATTERN2, ClientTransportConfigurationError2, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, defaultSleep = (ms) => new Promise((
|
|
45010
|
+
var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE", CredentialResolutionError2, CredentialFileUnsafeError2, HASNA_HOME_ENV_KEY2 = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY2 = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY2 = "HASNA_STATION", HASNA_HOME_DIR2 = ".hasna", CONFIG_SUBDIR2 = "config", CREDENTIALS_FILE2 = "credentials", KEYCHAIN_SECURITY_BIN2 = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX2 = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS2 = 44, KEYCHAIN_SPAWN_TIMEOUT_MS2 = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG2, SAFE_PROFILE2, ILLEGAL_IN_HEADER_VALUE2, VAULT_POINTER_SHAPE2, CREDENTIAL_SHAPED_KEY2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", AMBIENT_ENVIRONMENT2, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN2 = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN2, DNS_LABEL_PATTERN2, ClientTransportConfigurationError2, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, defaultSleep = (ms) => new Promise((resolve24) => setTimeout(resolve24, ms)), init_transport2, MAX_CREDENTIAL_FILE_BYTES22, INSPECT_CUSTOM22, CREDENTIAL_SEAL22, AMBIENT_ENVIRONMENT22, SECRETS_PACKAGE_SPECIFIER2, requireSecretsSdk22, IDEMPOTENT_METHODS22, AUTHORITY_OVERRIDE_HEADERS22, init_storage, PATHS_RESOLVER_APP_SLUG_RE2, SQLITE_SIDECAR_FILES, LEGACY_SERVICE_FILES, init_data_dir, SecretsTestIsolationError, TEST_ENTRYPOINT_RE, init_test_isolation, init_client, ApiError;
|
|
44199
45011
|
var init_sdk = __esm(() => {
|
|
44200
45012
|
init_transport2 = __esm2(() => {
|
|
44201
45013
|
CredentialResolutionError2 = class CredentialResolutionError3 extends Error {
|
|
@@ -44330,75 +45142,75 @@ var init_sdk = __esm(() => {
|
|
|
44330
45142
|
});
|
|
44331
45143
|
|
|
44332
45144
|
// src/lib/execution-secrets.ts
|
|
44333
|
-
import { constants as
|
|
45145
|
+
import { constants as constants17, closeSync as closeSync20, fstatSync as fstatSync20, openSync as openSync20, readSync as readSync13, realpathSync as realpathSync12 } from "fs";
|
|
44334
45146
|
import { hostname as stationHostname } from "os";
|
|
44335
45147
|
function selectedSecretBindingsTemplate(scope, names, createClient = createSecretsClientFromEnv) {
|
|
44336
45148
|
let secretsAuthority;
|
|
44337
45149
|
try {
|
|
44338
45150
|
secretsAuthority = createClient().baseUrl;
|
|
44339
45151
|
} catch {
|
|
44340
|
-
return
|
|
45152
|
+
return refuse5("LOCAL_SECRET_UNAVAILABLE", "Configure the Secrets CLI authority and authentication before preparing execution bindings.");
|
|
44341
45153
|
}
|
|
44342
45154
|
const { authority, workspaceId, profileRevision, slug: slug2, version: version2, bundleDigest } = scope.selection;
|
|
44343
45155
|
return {
|
|
44344
45156
|
schema: "hasna.skills-secret-bindings.v1",
|
|
44345
45157
|
selection: { authority, workspaceId, profileId: scope.profileId, profileRevision, slug: slug2, version: version2, bundleDigest },
|
|
44346
|
-
consumer: { stationId: process.env.HASNA_STATION || stationHostname(), workspaceDirectory:
|
|
45158
|
+
consumer: { stationId: process.env.HASNA_STATION || stationHostname(), workspaceDirectory: realpathSync12(scope.cwd) },
|
|
44347
45159
|
secretsAuthority,
|
|
44348
45160
|
bindings: Object.fromEntries(names.map((name) => [name, ""]))
|
|
44349
45161
|
};
|
|
44350
45162
|
}
|
|
44351
|
-
function
|
|
45163
|
+
function refuse5(code2, message) {
|
|
44352
45164
|
throw new SkillSelectionError(code2, message);
|
|
44353
45165
|
}
|
|
44354
45166
|
function record10(value) {
|
|
44355
45167
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
44356
45168
|
}
|
|
44357
|
-
function
|
|
45169
|
+
function exactKeys3(value, keys2) {
|
|
44358
45170
|
return Object.keys(value).length === keys2.length && keys2.every((key) => Object.hasOwn(value, key));
|
|
44359
45171
|
}
|
|
44360
|
-
function
|
|
45172
|
+
function identifier4(value) {
|
|
44361
45173
|
return typeof value === "string" && value.length > 0 && value.length <= 2048 && !/[\x00-\x20\x7f]/.test(value);
|
|
44362
45174
|
}
|
|
44363
45175
|
function declaredSecretNames(value) {
|
|
44364
45176
|
if (value === undefined)
|
|
44365
45177
|
return [];
|
|
44366
45178
|
if (!Array.isArray(value) || value.length > 32 || value.some((name) => typeof name !== "string" || !/^[A-Z][A-Z0-9_]{0,127}$/.test(name)) || new Set(value).size !== value.length) {
|
|
44367
|
-
return
|
|
45179
|
+
return refuse5("INVALID_SKILL_MANIFEST", "Runtime environment references must be unique uppercase identifiers (at most 32).");
|
|
44368
45180
|
}
|
|
44369
45181
|
if (value.some((name) => /^(?:PATH|HOME|TMPDIR|TEMP|TMP|LANG|LC_ALL|TERM|SHELL|ENV|BASH_ENV|IFS|NODE_OPTIONS|NODE_PATH)$/.test(name) || /^(?:SKILLS_|BUN_|PYTHON|LD_|DYLD_)/.test(name))) {
|
|
44370
|
-
return
|
|
45182
|
+
return refuse5("INVALID_SKILL_MANIFEST", "Runtime environment references cannot override execution controls.");
|
|
44371
45183
|
}
|
|
44372
45184
|
return value;
|
|
44373
45185
|
}
|
|
44374
45186
|
function validateSelectedSecretBindings(value, scope, names) {
|
|
44375
|
-
if (!record10(value) || !
|
|
44376
|
-
return
|
|
45187
|
+
if (!record10(value) || !exactKeys3(value, ["schema", "selection", "consumer", "secretsAuthority", "bindings"]) || value.schema !== "hasna.skills-secret-bindings.v1" || !record10(value.selection) || !exactKeys3(value.selection, ["authority", "workspaceId", "profileId", "profileRevision", "slug", "version", "bundleDigest"]) || !record10(value.consumer) || !exactKeys3(value.consumer, ["stationId", "workspaceDirectory"]) || !record10(value.bindings)) {
|
|
45188
|
+
return refuse5("INVALID_SECRET_BINDINGS", "Secret bindings do not match the hasna.skills-secret-bindings.v1 contract.");
|
|
44377
45189
|
}
|
|
44378
45190
|
for (const [key, expected] of Object.entries({ authority: scope.selection.authority, workspaceId: scope.selection.workspaceId, profileId: scope.profileId, profileRevision: scope.selection.profileRevision, slug: scope.selection.slug, version: scope.selection.version, bundleDigest: scope.selection.bundleDigest })) {
|
|
44379
45191
|
if (value.selection[key] !== expected)
|
|
44380
|
-
return
|
|
45192
|
+
return refuse5("SECRET_BINDING_SCOPE_MISMATCH", "Secret bindings do not match the exact selected authority, workspace, profile, revision, version and digest.");
|
|
44381
45193
|
}
|
|
44382
45194
|
let workspaceDirectory;
|
|
44383
45195
|
try {
|
|
44384
|
-
workspaceDirectory =
|
|
45196
|
+
workspaceDirectory = realpathSync12(scope.cwd);
|
|
44385
45197
|
} catch {
|
|
44386
|
-
return
|
|
45198
|
+
return refuse5("SECRET_BINDING_CONSUMER_MISMATCH", "The execution workspace cannot be resolved.");
|
|
44387
45199
|
}
|
|
44388
45200
|
if (value.consumer.stationId !== (process.env.HASNA_STATION || stationHostname()) || value.consumer.workspaceDirectory !== workspaceDirectory) {
|
|
44389
|
-
return
|
|
45201
|
+
return refuse5("SECRET_BINDING_CONSUMER_MISMATCH", "Secret bindings do not match this station and canonical workspace directory.");
|
|
44390
45202
|
}
|
|
44391
45203
|
try {
|
|
44392
|
-
if (!
|
|
45204
|
+
if (!identifier4(value.secretsAuthority))
|
|
44393
45205
|
throw new Error;
|
|
44394
45206
|
const url2 = new URL(value.secretsAuthority);
|
|
44395
45207
|
if (url2.protocol !== "https:" && !(url2.protocol === "http:" && ["127.0.0.1", "[::1]", "localhost"].includes(url2.hostname)) || url2.username || url2.password || url2.search || url2.hash || !url2.pathname.endsWith("/v1") || url2.href !== value.secretsAuthority)
|
|
44396
45208
|
throw new Error;
|
|
44397
45209
|
} catch {
|
|
44398
|
-
return
|
|
45210
|
+
return refuse5("INVALID_SECRET_BINDINGS", "Secret bindings require a canonical HTTPS Secrets /v1 authority (loopback HTTP is allowed).");
|
|
44399
45211
|
}
|
|
44400
|
-
if (!
|
|
44401
|
-
return
|
|
45212
|
+
if (!exactKeys3(value.bindings, names) || Object.values(value.bindings).some((key) => !identifier4(key) || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(key) || key.split("/").some((part) => !part || part === "." || part === ".."))) {
|
|
45213
|
+
return refuse5("INVALID_SECRET_BINDINGS", "Bind every declared environment name exactly once to a vault key; undeclared bindings and values are refused.");
|
|
44402
45214
|
}
|
|
44403
45215
|
return structuredClone(value);
|
|
44404
45216
|
}
|
|
@@ -44409,10 +45221,10 @@ async function resolveSelectedSecrets(bindings, createClient = createSecretsClie
|
|
|
44409
45221
|
try {
|
|
44410
45222
|
client = createClient();
|
|
44411
45223
|
} catch {
|
|
44412
|
-
return
|
|
45224
|
+
return refuse5("LOCAL_SECRET_UNAVAILABLE", "The configured Secrets client could not authenticate. No ambient credential fallback was attempted.");
|
|
44413
45225
|
}
|
|
44414
45226
|
if (client.baseUrl !== bindings.secretsAuthority)
|
|
44415
|
-
return
|
|
45227
|
+
return refuse5("SECRET_BINDING_AUTHORITY_MISMATCH", "The configured Secrets authority differs from the reviewed binding. No secret was requested.");
|
|
44416
45228
|
const env = {};
|
|
44417
45229
|
const signal = AbortSignal.timeout(15000);
|
|
44418
45230
|
try {
|
|
@@ -44424,7 +45236,7 @@ async function resolveSelectedSecrets(bindings, createClient = createSecretsClie
|
|
|
44424
45236
|
}
|
|
44425
45237
|
return env;
|
|
44426
45238
|
} catch {
|
|
44427
|
-
return
|
|
45239
|
+
return refuse5("LOCAL_SECRET_UNAVAILABLE", "A declared secret could not be resolved, was invalid, or has expired. The skill was not started; no fallback was attempted.");
|
|
44428
45240
|
}
|
|
44429
45241
|
}
|
|
44430
45242
|
function redactExecutionSecrets(text3, env) {
|
|
@@ -44572,10 +45384,10 @@ __export(exports_selected_run, {
|
|
|
44572
45384
|
prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
|
|
44573
45385
|
executeSelectedLocal: () => executeSelectedLocal
|
|
44574
45386
|
});
|
|
44575
|
-
import { createHash as
|
|
45387
|
+
import { createHash as createHash25 } from "crypto";
|
|
44576
45388
|
import { spawn as spawn2 } from "child_process";
|
|
44577
|
-
import { mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync11, realpathSync as
|
|
44578
|
-
import { dirname as
|
|
45389
|
+
import { mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync11, realpathSync as realpathSync13 } from "fs";
|
|
45390
|
+
import { dirname as dirname24, join as join37, resolve as resolve24 } from "path";
|
|
44579
45391
|
import { tmpdir, hostname as stationHostname2 } from "os";
|
|
44580
45392
|
async function resolveSelectedRun(spec, profileId, options = {}) {
|
|
44581
45393
|
const context2 = await resolveSelectionContext(profileId, options);
|
|
@@ -44655,7 +45467,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
44655
45467
|
throw new SkillSelectionError("INVALID_SECRET_BINDINGS", "Explicit environment values must be bounded strings without NUL bytes.");
|
|
44656
45468
|
secretEnv[name] = value;
|
|
44657
45469
|
}
|
|
44658
|
-
const runDirectory = mkdtempSync3(
|
|
45470
|
+
const runDirectory = mkdtempSync3(join37(tmpdir(), "skills-execution-"));
|
|
44659
45471
|
const paths = new SkillEntryPaths;
|
|
44660
45472
|
for (const entry of entries) {
|
|
44661
45473
|
paths.add(entry.path, 100, () => {
|
|
@@ -44663,12 +45475,12 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
44663
45475
|
}, () => {
|
|
44664
45476
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
44665
45477
|
});
|
|
44666
|
-
const destination =
|
|
44667
|
-
mkdirSync13(
|
|
45478
|
+
const destination = join37(runDirectory, entry.path);
|
|
45479
|
+
mkdirSync13(dirname24(destination), { recursive: true, mode: 448 });
|
|
44668
45480
|
writeFileSync11(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
44669
45481
|
}
|
|
44670
45482
|
env.SKILLS_INPUT_JSON = input2;
|
|
44671
|
-
env.SKILLS_WORKSPACE_DIR =
|
|
45483
|
+
env.SKILLS_WORKSPACE_DIR = resolve24(options.cwd ?? process.cwd());
|
|
44672
45484
|
env.SKILLS_RUN_DIR = runDirectory;
|
|
44673
45485
|
if (runtime.version) {
|
|
44674
45486
|
const version2 = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], "--version"], runDirectory, env, "", Math.min(timeoutMs, 5000));
|
|
@@ -44681,7 +45493,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
44681
45493
|
const { authority: authority2, workspaceId, profileRevision, slug: slug2, version: version2, bundleDigest } = selection2;
|
|
44682
45494
|
const request2 = {
|
|
44683
45495
|
selection: { authority: authority2, workspaceId, profileId, profileRevision, slug: slug2, version: version2, bundleDigest },
|
|
44684
|
-
consumer: { stationId: process.env.HASNA_STATION || stationHostname2(), workspaceDirectory:
|
|
45496
|
+
consumer: { stationId: process.env.HASNA_STATION || stationHostname2(), workspaceDirectory: realpathSync13(options.cwd ?? process.cwd()) }
|
|
44685
45497
|
};
|
|
44686
45498
|
const grant = await (options.resolveExecutionGrant ?? resolveExecutionGrant)(request2);
|
|
44687
45499
|
if (!grant || !grantIdentifier(grant.policyRevision) || !grantIdentifier(grant.grantId))
|
|
@@ -44691,20 +45503,20 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
44691
45503
|
}
|
|
44692
45504
|
if (bindings)
|
|
44693
45505
|
secretEnv = await resolveSelectedSecrets(bindings, options.createSecretsClient);
|
|
44694
|
-
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [],
|
|
45506
|
+
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], join37(runDirectory, declaredEntry), ...args], runDirectory, { ...env, ...secretEnv }, input2, timeoutMs);
|
|
44695
45507
|
result.stdout = redactExecutionSecrets(result.stdout, secretEnv);
|
|
44696
45508
|
result.stderr = redactExecutionSecrets(result.stderr, secretEnv);
|
|
44697
45509
|
const receipt = {
|
|
44698
45510
|
selection: selection2,
|
|
44699
45511
|
target: "local",
|
|
44700
45512
|
runtime: runtimeName,
|
|
44701
|
-
inputDigest: `sha256:${
|
|
45513
|
+
inputDigest: `sha256:${createHash25("sha256").update(input2).digest("hex")}`,
|
|
44702
45514
|
runDirectory,
|
|
44703
45515
|
...executionGrant ? { executionGrant } : {},
|
|
44704
45516
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
44705
45517
|
...result
|
|
44706
45518
|
};
|
|
44707
|
-
writeFileSync11(
|
|
45519
|
+
writeFileSync11(join37(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
|
|
44708
45520
|
return receipt;
|
|
44709
45521
|
}
|
|
44710
45522
|
async function subprocess(command, cwd, env, input2, timeoutMs) {
|
|
@@ -44893,8 +45705,8 @@ var init_blog_article = __esm(() => {
|
|
|
44893
45705
|
});
|
|
44894
45706
|
|
|
44895
45707
|
// src/mcp/operation-tools.ts
|
|
44896
|
-
import { existsSync as existsSync16, readdirSync as
|
|
44897
|
-
import { join as
|
|
45708
|
+
import { existsSync as existsSync16, readdirSync as readdirSync12, statSync as statSync11 } from "fs";
|
|
45709
|
+
import { join as join38 } from "path";
|
|
44898
45710
|
function registerOperationTools(server) {
|
|
44899
45711
|
server.registerTool("cloud_skill_eligibility", {
|
|
44900
45712
|
title: "Cloud Skill Eligibility",
|
|
@@ -45370,8 +46182,8 @@ function registerOperationTools(server) {
|
|
|
45370
46182
|
let skillCount = 0;
|
|
45371
46183
|
if (exists) {
|
|
45372
46184
|
try {
|
|
45373
|
-
skillCount =
|
|
45374
|
-
const full =
|
|
46185
|
+
skillCount = readdirSync12(agentSkillsPath).filter((f) => {
|
|
46186
|
+
const full = join38(agentSkillsPath, f);
|
|
45375
46187
|
return !f.startsWith(".") && statSync11(full).isDirectory();
|
|
45376
46188
|
}).length;
|
|
45377
46189
|
} catch {}
|
|
@@ -45439,14 +46251,14 @@ var init_operation_tools = __esm(() => {
|
|
|
45439
46251
|
|
|
45440
46252
|
// src/lib/feedback.ts
|
|
45441
46253
|
import { appendFileSync, existsSync as existsSync17, mkdirSync as mkdirSync14 } from "fs";
|
|
45442
|
-
import { dirname as
|
|
46254
|
+
import { dirname as dirname25, join as join39 } from "path";
|
|
45443
46255
|
import { Database } from "bun:sqlite";
|
|
45444
46256
|
function getFeedbackDbPath() {
|
|
45445
|
-
return
|
|
46257
|
+
return join39(getDataDir(), "skills.db");
|
|
45446
46258
|
}
|
|
45447
46259
|
function getFeedbackDb() {
|
|
45448
46260
|
const dbPath = getFeedbackDbPath();
|
|
45449
|
-
const dir =
|
|
46261
|
+
const dir = dirname25(dbPath);
|
|
45450
46262
|
if (!existsSync17(dir))
|
|
45451
46263
|
mkdirSync14(dir, { recursive: true });
|
|
45452
46264
|
const db = new Database(dbPath);
|
|
@@ -45474,8 +46286,8 @@ function saveFeedback(input2) {
|
|
|
45474
46286
|
throw new Error("Feedback message is required");
|
|
45475
46287
|
const category = input2.category ?? "general";
|
|
45476
46288
|
if (isApiMode()) {
|
|
45477
|
-
const path =
|
|
45478
|
-
const dir =
|
|
46289
|
+
const path = join39(getDataDir(), "feedback.jsonl");
|
|
46290
|
+
const dir = dirname25(path);
|
|
45479
46291
|
if (!existsSync17(dir))
|
|
45480
46292
|
mkdirSync14(dir, { recursive: true });
|
|
45481
46293
|
appendFileSync(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
|
|
@@ -45639,9 +46451,9 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
45639
46451
|
|
|
45640
46452
|
// src/lib/scheduler.ts
|
|
45641
46453
|
import { existsSync as existsSync18, readFileSync as readFileSync22, writeFileSync as writeFileSync12, mkdirSync as mkdirSync15 } from "fs";
|
|
45642
|
-
import { join as
|
|
46454
|
+
import { join as join40 } from "path";
|
|
45643
46455
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
45644
|
-
return
|
|
46456
|
+
return join40(targetDir, ".skills", "schedules.json");
|
|
45645
46457
|
}
|
|
45646
46458
|
function loadSchedules(targetDir = process.cwd()) {
|
|
45647
46459
|
const path = getSchedulesPath(targetDir);
|
|
@@ -45654,7 +46466,7 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
45654
46466
|
}
|
|
45655
46467
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
45656
46468
|
const path = getSchedulesPath(targetDir);
|
|
45657
|
-
const dir =
|
|
46469
|
+
const dir = join40(targetDir, ".skills");
|
|
45658
46470
|
if (!existsSync18(dir))
|
|
45659
46471
|
mkdirSync15(dir, { recursive: true });
|
|
45660
46472
|
writeFileSync12(path, JSON.stringify(data, null, 2));
|
|
@@ -45926,16 +46738,16 @@ var init_schedule_tools = __esm(() => {
|
|
|
45926
46738
|
});
|
|
45927
46739
|
|
|
45928
46740
|
// src/lib/native-storage.ts
|
|
45929
|
-
import { createHash as
|
|
46741
|
+
import { createHash as createHash26, createHmac } from "crypto";
|
|
45930
46742
|
import {
|
|
45931
46743
|
existsSync as existsSync19,
|
|
45932
46744
|
mkdirSync as mkdirSync16,
|
|
45933
46745
|
readFileSync as readFileSync23,
|
|
45934
|
-
readdirSync as
|
|
46746
|
+
readdirSync as readdirSync13,
|
|
45935
46747
|
statSync as statSync12,
|
|
45936
46748
|
writeFileSync as writeFileSync13
|
|
45937
46749
|
} from "fs";
|
|
45938
|
-
import { dirname as
|
|
46750
|
+
import { dirname as dirname26, join as join41, normalize as normalize5, relative as relative10, sep as sep12 } from "path";
|
|
45939
46751
|
function resolveSkillsNativeStorageConfig(env = process.env) {
|
|
45940
46752
|
assertNoRetiredModeEnvVars(env, {
|
|
45941
46753
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -45976,7 +46788,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
45976
46788
|
local: {
|
|
45977
46789
|
dataDir: getDataDir(),
|
|
45978
46790
|
projectStateDir: getProjectStateDir(targetDir),
|
|
45979
|
-
feedbackDbPath:
|
|
46791
|
+
feedbackDbPath: join41(getDataDir(), "skills.db")
|
|
45980
46792
|
},
|
|
45981
46793
|
remote: {
|
|
45982
46794
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -45999,11 +46811,11 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
45999
46811
|
if (existsSync19(projectStateDir)) {
|
|
46000
46812
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
46001
46813
|
const bytes = readFileSync23(filePath);
|
|
46002
|
-
const relativePath = toPosix(
|
|
46814
|
+
const relativePath = toPosix(relative10(targetDir, filePath));
|
|
46003
46815
|
files.push({
|
|
46004
46816
|
path: relativePath,
|
|
46005
46817
|
sizeBytes: bytes.byteLength,
|
|
46006
|
-
sha256:
|
|
46818
|
+
sha256: createHash26("sha256").update(bytes).digest("hex"),
|
|
46007
46819
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
46008
46820
|
});
|
|
46009
46821
|
}
|
|
@@ -46056,8 +46868,8 @@ function parsePositiveInteger(value) {
|
|
|
46056
46868
|
}
|
|
46057
46869
|
function walkFiles2(dir) {
|
|
46058
46870
|
const files = [];
|
|
46059
|
-
for (const entry of
|
|
46060
|
-
const full =
|
|
46871
|
+
for (const entry of readdirSync13(dir)) {
|
|
46872
|
+
const full = join41(dir, entry);
|
|
46061
46873
|
const stats = statSync12(full);
|
|
46062
46874
|
if (stats.isDirectory())
|
|
46063
46875
|
files.push(...walkFiles2(full));
|
|
@@ -46295,73 +47107,73 @@ var init_private_publication_customer = __esm(() => {
|
|
|
46295
47107
|
});
|
|
46296
47108
|
|
|
46297
47109
|
// src/lib/private-publication-recovery.ts
|
|
46298
|
-
import { constants as
|
|
46299
|
-
import { dirname as
|
|
47110
|
+
import { constants as constants18, closeSync as closeSync21, fsyncSync as fsyncSync6, fstatSync as fstatSync21, lstatSync as lstatSync25, mkdirSync as mkdirSync17, openSync as openSync21, readSync as readSync14, realpathSync as realpathSync14, renameSync as renameSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
|
|
47111
|
+
import { dirname as dirname27, isAbsolute as isAbsolute24, join as join42, resolve as resolve25 } from "path";
|
|
46300
47112
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
46301
47113
|
function safeDirectory(directory2) {
|
|
46302
|
-
if (!
|
|
47114
|
+
if (!isAbsolute24(directory2) || directory2 !== resolve25(directory2) || realpathSync14(directory2) !== directory2)
|
|
46303
47115
|
return fail2();
|
|
46304
|
-
for (let path = directory2;; path =
|
|
46305
|
-
const stat3 =
|
|
47116
|
+
for (let path = directory2;; path = dirname27(path)) {
|
|
47117
|
+
const stat3 = lstatSync25(path);
|
|
46306
47118
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
46307
47119
|
return fail2();
|
|
46308
|
-
if (path ===
|
|
47120
|
+
if (path === dirname27(path))
|
|
46309
47121
|
break;
|
|
46310
47122
|
}
|
|
46311
|
-
const own2 =
|
|
47123
|
+
const own2 = lstatSync25(directory2);
|
|
46312
47124
|
if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
46313
47125
|
return fail2();
|
|
46314
47126
|
return { dev: own2.dev, ino: own2.ino };
|
|
46315
47127
|
}
|
|
46316
|
-
function unchangedDirectory(directory2,
|
|
47128
|
+
function unchangedDirectory(directory2, identity4) {
|
|
46317
47129
|
const now = safeDirectory(directory2);
|
|
46318
|
-
if (now.dev !==
|
|
47130
|
+
if (now.dev !== identity4.dev || now.ino !== identity4.ino)
|
|
46319
47131
|
return fail2();
|
|
46320
47132
|
}
|
|
46321
47133
|
function readOwned(directory2, name, max) {
|
|
46322
|
-
const
|
|
46323
|
-
const fd =
|
|
47134
|
+
const identity4 = safeDirectory(directory2), file2 = join42(directory2, name);
|
|
47135
|
+
const fd = openSync21(file2, constants18.O_RDONLY | constants18.O_NOFOLLOW);
|
|
46324
47136
|
try {
|
|
46325
|
-
const stat3 =
|
|
47137
|
+
const stat3 = fstatSync21(fd);
|
|
46326
47138
|
if (!stat3.isFile() || stat3.nlink !== 1 || stat3.size > max || stat3.size < 1 || (stat3.mode & 63) !== 0 || process.getuid && stat3.uid !== process.getuid())
|
|
46327
47139
|
return fail2();
|
|
46328
47140
|
const buffer = Buffer.alloc(Math.min(max, stat3.size) + 1);
|
|
46329
47141
|
let length = 0;
|
|
46330
47142
|
while (length < buffer.length) {
|
|
46331
|
-
const count =
|
|
47143
|
+
const count = readSync14(fd, buffer, length, buffer.length - length, length);
|
|
46332
47144
|
if (count === 0)
|
|
46333
47145
|
break;
|
|
46334
47146
|
length += count;
|
|
46335
47147
|
}
|
|
46336
|
-
const bytes = buffer.subarray(0, length), after =
|
|
46337
|
-
unchangedDirectory(directory2,
|
|
47148
|
+
const bytes = buffer.subarray(0, length), after = fstatSync21(fd);
|
|
47149
|
+
unchangedDirectory(directory2, identity4);
|
|
46338
47150
|
if (bytes.length !== stat3.size || stat3.size !== after.size || stat3.mtimeMs !== after.mtimeMs || stat3.ctimeMs !== after.ctimeMs)
|
|
46339
47151
|
return fail2();
|
|
46340
47152
|
return bytes;
|
|
46341
47153
|
} finally {
|
|
46342
|
-
|
|
47154
|
+
closeSync21(fd);
|
|
46343
47155
|
}
|
|
46344
47156
|
}
|
|
46345
47157
|
function writeOwned(directory2, name, bytes) {
|
|
46346
|
-
const fd =
|
|
47158
|
+
const fd = openSync21(join42(directory2, name), constants18.O_WRONLY | constants18.O_CREAT | constants18.O_EXCL | constants18.O_NOFOLLOW, 384);
|
|
46347
47159
|
try {
|
|
46348
47160
|
writeFileSync14(fd, bytes);
|
|
46349
47161
|
fsyncSync6(fd);
|
|
46350
47162
|
} finally {
|
|
46351
|
-
|
|
47163
|
+
closeSync21(fd);
|
|
46352
47164
|
}
|
|
46353
47165
|
}
|
|
46354
47166
|
function save(directory2, value) {
|
|
46355
|
-
const
|
|
47167
|
+
const identity4 = safeDirectory(directory2), temporary = `.receipt-${randomUUID3()}.json`;
|
|
46356
47168
|
writeOwned(directory2, temporary, JSON.stringify(value) + `
|
|
46357
47169
|
`);
|
|
46358
|
-
unchangedDirectory(directory2,
|
|
46359
|
-
renameSync7(
|
|
46360
|
-
const fd =
|
|
47170
|
+
unchangedDirectory(directory2, identity4);
|
|
47171
|
+
renameSync7(join42(directory2, temporary), join42(directory2, "receipt.json"));
|
|
47172
|
+
const fd = openSync21(directory2, constants18.O_RDONLY | constants18.O_NOFOLLOW);
|
|
46361
47173
|
try {
|
|
46362
47174
|
fsyncSync6(fd);
|
|
46363
47175
|
} finally {
|
|
46364
|
-
|
|
47176
|
+
closeSync21(fd);
|
|
46365
47177
|
}
|
|
46366
47178
|
}
|
|
46367
47179
|
function bind(client, receipt) {
|
|
@@ -46369,23 +47181,23 @@ function bind(client, receipt) {
|
|
|
46369
47181
|
throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
|
|
46370
47182
|
}
|
|
46371
47183
|
async function locked(directory2, action) {
|
|
46372
|
-
const
|
|
47184
|
+
const identity4 = safeDirectory(directory2), file2 = join42(directory2, "operation.lock");
|
|
46373
47185
|
let fd;
|
|
46374
47186
|
try {
|
|
46375
|
-
fd =
|
|
47187
|
+
fd = openSync21(file2, constants18.O_WRONLY | constants18.O_CREAT | constants18.O_EXCL | constants18.O_NOFOLLOW, 384);
|
|
46376
47188
|
} catch {
|
|
46377
47189
|
throw new PrivatePublicationError("PUBLICATION_RECOVERY_BUSY", "Another operation holds this recovery directory. If it crashed, confirm that process has stopped before explicitly removing operation.lock and resuming.");
|
|
46378
47190
|
}
|
|
46379
|
-
const lock =
|
|
47191
|
+
const lock = fstatSync21(fd);
|
|
46380
47192
|
try {
|
|
46381
47193
|
writeFileSync14(fd, JSON.stringify({ pid: process.pid }) + `
|
|
46382
47194
|
`);
|
|
46383
47195
|
fsyncSync6(fd);
|
|
46384
47196
|
return await action();
|
|
46385
47197
|
} finally {
|
|
46386
|
-
|
|
46387
|
-
unchangedDirectory(directory2,
|
|
46388
|
-
const now =
|
|
47198
|
+
closeSync21(fd);
|
|
47199
|
+
unchangedDirectory(directory2, identity4);
|
|
47200
|
+
const now = lstatSync25(file2);
|
|
46389
47201
|
if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
|
|
46390
47202
|
fail2();
|
|
46391
47203
|
unlinkSync6(file2);
|
|
@@ -46437,15 +47249,15 @@ async function preparePrivatePublication(client, sourceDirectory, recoveryDirect
|
|
|
46437
47249
|
phase: "prepared",
|
|
46438
47250
|
intent: null
|
|
46439
47251
|
};
|
|
46440
|
-
if (!
|
|
47252
|
+
if (!isAbsolute24(recoveryDirectory) || resolve25(recoveryDirectory) !== recoveryDirectory || realpathSync14(dirname27(recoveryDirectory)) !== dirname27(recoveryDirectory))
|
|
46441
47253
|
return fail2();
|
|
46442
47254
|
mkdirSync17(recoveryDirectory, { mode: 448 });
|
|
46443
47255
|
safeDirectory(recoveryDirectory);
|
|
46444
|
-
const parent =
|
|
47256
|
+
const parent = openSync21(dirname27(recoveryDirectory), constants18.O_RDONLY | constants18.O_NOFOLLOW);
|
|
46445
47257
|
try {
|
|
46446
47258
|
fsyncSync6(parent);
|
|
46447
47259
|
} finally {
|
|
46448
|
-
|
|
47260
|
+
closeSync21(parent);
|
|
46449
47261
|
}
|
|
46450
47262
|
writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
|
|
46451
47263
|
save(recoveryDirectory, receipt);
|
|
@@ -46538,10 +47350,10 @@ var init_private_publication_recovery = __esm(() => {
|
|
|
46538
47350
|
});
|
|
46539
47351
|
|
|
46540
47352
|
// src/mcp/private-publication-tools.ts
|
|
46541
|
-
import { isAbsolute as
|
|
47353
|
+
import { isAbsolute as isAbsolute25 } from "path";
|
|
46542
47354
|
function registerPrivatePublicationTools(server) {
|
|
46543
47355
|
const uuid9 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
46544
|
-
const directory2 = exports_external.string().max(4096).refine(
|
|
47356
|
+
const directory2 = exports_external.string().max(4096).refine(isAbsolute25, "Use an absolute local directory");
|
|
46545
47357
|
const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory2 };
|
|
46546
47358
|
const description = "Manage a private source publication using fresh workspace-bound verification and a host-local recovery directory. Publishing requires explicit UUID current-version comparison and upload consent. Resume reuses immutable saved bytes and intent; an uncertain PUT is finalized for server verification, never uploaded twice. Sessions and signed URLs are not returned or persisted. Private execution is unavailable. Host request history may contain the supplied verification code.";
|
|
46547
47359
|
const handler = (action) => async (value) => {
|
|
@@ -46974,19 +47786,19 @@ async function connectMcpForNode() {
|
|
|
46974
47786
|
return { server: server2, transport };
|
|
46975
47787
|
}
|
|
46976
47788
|
function readBody(req) {
|
|
46977
|
-
return new Promise((
|
|
47789
|
+
return new Promise((resolve26, reject) => {
|
|
46978
47790
|
const chunks = [];
|
|
46979
47791
|
req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
46980
47792
|
req.on("end", () => {
|
|
46981
47793
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
46982
47794
|
if (!raw.trim()) {
|
|
46983
|
-
|
|
47795
|
+
resolve26(undefined);
|
|
46984
47796
|
return;
|
|
46985
47797
|
}
|
|
46986
47798
|
try {
|
|
46987
|
-
|
|
47799
|
+
resolve26(JSON.parse(raw));
|
|
46988
47800
|
} catch {
|
|
46989
|
-
|
|
47801
|
+
resolve26(undefined);
|
|
46990
47802
|
}
|
|
46991
47803
|
});
|
|
46992
47804
|
req.on("error", reject);
|
|
@@ -47028,9 +47840,9 @@ async function startSkillsMcpHttpServer(options = {}) {
|
|
|
47028
47840
|
}
|
|
47029
47841
|
}
|
|
47030
47842
|
});
|
|
47031
|
-
await new Promise((
|
|
47843
|
+
await new Promise((resolve26, reject) => {
|
|
47032
47844
|
httpServer.once("error", reject);
|
|
47033
|
-
httpServer.listen(port, hostname4, () =>
|
|
47845
|
+
httpServer.listen(port, hostname4, () => resolve26());
|
|
47034
47846
|
});
|
|
47035
47847
|
const address = httpServer.address();
|
|
47036
47848
|
const listenPort = typeof address === "object" && address ? address.port : port;
|