@hasna/skills 0.10.79 → 0.10.81
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 +225 -0
- package/bin/index.js +3170 -1733
- package/bin/mcp.js +698 -484
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/cli/commands/metadata.d.ts +2 -0
- package/dist/index.js +1962 -912
- package/dist/lib/agent-discovery.d.ts +11 -0
- package/dist/lib/agent-integration.d.ts +119 -1
- package/dist/lib/codex-native-skill-catalog.d.ts +38 -0
- package/dist/lib/codex-plugin-capability-paths.d.ts +8 -0
- package/dist/lib/codex-plugin-reconcile.d.ts +74 -0
- package/dist/lib/codex-plugin-skill-controls.d.ts +68 -1
- package/dist/lib/remote-client.d.ts +10 -0
- package/dist/lib/skill-metadata-update.d.ts +46 -0
- package/dist/lib/skill-validation.d.ts +3 -1
- package/dist/runtime-prerequisites.js +1 -1
- package/dist/sdk/index.d.ts +1 -0
- package/dist/sdk/index.js +2146 -1095
- 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.81",
|
|
27
27
|
description: "Skills library for AI coding agents",
|
|
28
28
|
type: "module",
|
|
29
29
|
bin: {
|
|
@@ -20974,13 +20974,13 @@ function parseSkillFrontmatter(content) {
|
|
|
20974
20974
|
}
|
|
20975
20975
|
return Object.keys(result).length > 0 ? result : null;
|
|
20976
20976
|
}
|
|
20977
|
-
function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
20977
|
+
function validateSkillDirectory(name, skillPath, registryMeta, options = {}) {
|
|
20978
20978
|
const bareName = name;
|
|
20979
20979
|
const issues = [];
|
|
20980
20980
|
const warnings = [];
|
|
20981
20981
|
let packageDeclaresHosted = false;
|
|
20982
20982
|
let packageSkillSource;
|
|
20983
|
-
let resolvedKind = "executable";
|
|
20983
|
+
let resolvedKind = options.kind ?? "executable";
|
|
20984
20984
|
const metadata = {
|
|
20985
20985
|
binCommands: [],
|
|
20986
20986
|
docFiles: []
|
|
@@ -21042,7 +21042,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21042
21042
|
}
|
|
21043
21043
|
if (frontmatter.kind !== undefined) {
|
|
21044
21044
|
if (VALID_SKILL_KINDS.includes(frontmatter.kind)) {
|
|
21045
|
-
|
|
21045
|
+
if (options.kind === undefined)
|
|
21046
|
+
resolvedKind = frontmatter.kind;
|
|
21046
21047
|
} else {
|
|
21047
21048
|
add(issues, "skill.kind_invalid", `SKILL.md kind '${frontmatter.kind}' is not one of: ${VALID_SKILL_KINDS.join(", ")}`);
|
|
21048
21049
|
}
|
|
@@ -32310,7 +32311,7 @@ function codexPluginRootCapabilityEntry(name) {
|
|
|
32310
32311
|
function isCodexSkillDocumentName(name) {
|
|
32311
32312
|
return foldCodexPluginEntryName(name) === "skill.md";
|
|
32312
32313
|
}
|
|
32313
|
-
var CODEX_PLUGIN_MANIFEST_LOCATIONS, CODEX_PLUGIN_MANIFEST_DIRECTORIES, CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES;
|
|
32314
|
+
var CODEX_PLUGIN_MANIFEST_LOCATIONS, CODEX_PLUGIN_MANIFEST_DIRECTORIES, CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES, CODEX_PLUGIN_MANIFEST_KNOWN_KEYS, CODEX_PLUGIN_DEFAULT_SKILLS_PATHS;
|
|
32314
32315
|
var init_codex_plugin_capability_paths = __esm(() => {
|
|
32315
32316
|
CODEX_PLUGIN_MANIFEST_LOCATIONS = Object.freeze([
|
|
32316
32317
|
"plugin.json",
|
|
@@ -32331,6 +32332,8 @@ var init_codex_plugin_capability_paths = __esm(() => {
|
|
|
32331
32332
|
"commands",
|
|
32332
32333
|
"agents"
|
|
32333
32334
|
]);
|
|
32335
|
+
CODEX_PLUGIN_MANIFEST_KNOWN_KEYS = Object.freeze(["name", "version", "description", "author", "homepage", "repository", "license", "keywords", "interface", "skills", "apps"]);
|
|
32336
|
+
CODEX_PLUGIN_DEFAULT_SKILLS_PATHS = Object.freeze(["./skills", "./skills/"]);
|
|
32334
32337
|
});
|
|
32335
32338
|
|
|
32336
32339
|
// src/lib/codex-hook-mcp-dependencies.ts
|
|
@@ -33665,11 +33668,14 @@ var init_codex_hook_rpc = __esm(() => {
|
|
|
33665
33668
|
});
|
|
33666
33669
|
|
|
33667
33670
|
// src/lib/codex-native-skill-catalog.ts
|
|
33668
|
-
import { realpathSync as realpathSync4 } from "fs";
|
|
33669
|
-
import { isAbsolute as isAbsolute14, normalize as normalize3 } from "path";
|
|
33671
|
+
import { lstatSync as lstatSync14, readdirSync as readdirSync5, readFileSync as readFileSync12, realpathSync as realpathSync4 } from "fs";
|
|
33672
|
+
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute14, join as join19, normalize as normalize3 } from "path";
|
|
33673
|
+
function codexPluginIsRemote(plugin) {
|
|
33674
|
+
return plugin !== undefined && (plugin.sourceType === "remote" || plugin.remotePluginId !== undefined);
|
|
33675
|
+
}
|
|
33670
33676
|
function codexPluginSourceIsConfigControlled(plugin) {
|
|
33671
33677
|
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"];
|
|
33672
|
-
return Boolean(plugin.sourceType && ["local", "git", "npm"].includes(plugin.sourceType) && plugin.sourceSha256 && /^[a-f0-9]{64}$/.test(plugin.sourceSha256) && !plugin
|
|
33678
|
+
return Boolean(plugin.sourceType && ["local", "git", "npm"].includes(plugin.sourceType) && plugin.sourceSha256 && /^[a-f0-9]{64}$/.test(plugin.sourceSha256) && !codexPluginIsRemote(plugin) && !remoteRealms.includes(plugin.id.slice(plugin.id.lastIndexOf("@") + 1)));
|
|
33673
33679
|
}
|
|
33674
33680
|
function refuse() {
|
|
33675
33681
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_INVALID");
|
|
@@ -33759,16 +33765,16 @@ var init_codex_native_skill_catalog = __esm(() => {
|
|
|
33759
33765
|
});
|
|
33760
33766
|
|
|
33761
33767
|
// src/lib/codex-plugin-skill-controls.ts
|
|
33762
|
-
import { basename as
|
|
33763
|
-
import { lstatSync as
|
|
33768
|
+
import { basename as basename9, dirname as dirname16, join as join20, relative as relative5, resolve as resolve14, sep as sep8 } from "path";
|
|
33769
|
+
import { lstatSync as lstatSync15, readdirSync as readdirSync6, readFileSync as readFileSync13, readlinkSync as readlinkSync3, realpathSync as realpathSync5 } from "fs";
|
|
33764
33770
|
function refuse2() {
|
|
33765
33771
|
throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
|
|
33766
33772
|
}
|
|
33767
33773
|
function codexRemoteInstallReceipt(parent, read) {
|
|
33768
33774
|
try {
|
|
33769
|
-
if (!
|
|
33775
|
+
if (!lstatSync15(parent).isDirectory() || realpathSync5(parent) !== parent)
|
|
33770
33776
|
return null;
|
|
33771
|
-
const path =
|
|
33777
|
+
const path = join20(parent, ".codex-remote-plugin-install.json"), stat2 = lstatSync15(path, { throwIfNoEntry: false });
|
|
33772
33778
|
if (!stat2?.isFile() || stat2.isSymbolicLink() || stat2.size > 16384)
|
|
33773
33779
|
return null;
|
|
33774
33780
|
const text2 = read(path);
|
|
@@ -33830,7 +33836,7 @@ function mcpControls(path, read) {
|
|
|
33830
33836
|
function isBundledCleanupHooks(root, namespace, value) {
|
|
33831
33837
|
const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
|
|
33832
33838
|
const exactKeys = (v, keys) => Object.keys(v).length === keys.length && keys.every((key2) => Object.hasOwn(v, key2));
|
|
33833
|
-
if (
|
|
33839
|
+
if (basename9(dirname16(root)) !== namespace || basename9(dirname16(dirname16(root))) !== "openai-bundled")
|
|
33834
33840
|
return false;
|
|
33835
33841
|
const server = namespace === "unified-computer-use" ? "cua_repl" : ["browser", "chrome", "chrome-dev", "chrome-internal", "computer-use"].includes(namespace) ? "node_repl" : undefined;
|
|
33836
33842
|
if (!server || !object5(value) || !exactKeys(value, ["hooks"]) || !object5(value.hooks))
|
|
@@ -33854,8 +33860,8 @@ function readCodexPluginRootControls(root, read) {
|
|
|
33854
33860
|
return rootControls(root, read);
|
|
33855
33861
|
}
|
|
33856
33862
|
function rootControls(root, read) {
|
|
33857
|
-
const manifestPath =
|
|
33858
|
-
if (!
|
|
33863
|
+
const manifestPath = join20(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync15(manifestPath, { throwIfNoEntry: false });
|
|
33864
|
+
if (!lstatSync15(join20(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
|
|
33859
33865
|
refuse2();
|
|
33860
33866
|
let manifest, manifestSha256;
|
|
33861
33867
|
try {
|
|
@@ -33867,12 +33873,12 @@ function rootControls(root, read) {
|
|
|
33867
33873
|
}
|
|
33868
33874
|
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest) || !identifier2(manifest.name))
|
|
33869
33875
|
refuse2();
|
|
33870
|
-
const cacheVersion =
|
|
33876
|
+
const cacheVersion = basename9(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
33871
33877
|
if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
33872
33878
|
refuse2();
|
|
33873
|
-
if (manifest.hooks !== undefined && !isBundledCleanupHooks(root, manifest.name, manifest.hooks) || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" ||
|
|
33879
|
+
if (manifest.hooks !== undefined && !isBundledCleanupHooks(root, manifest.name, manifest.hooks) || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync15(join20(root, "hooks"), { throwIfNoEntry: false }))
|
|
33874
33880
|
refuse2();
|
|
33875
|
-
const mcp =
|
|
33881
|
+
const mcp = join20(root, ".mcp.json"), mcpPresent = lstatSync15(mcp, { throwIfNoEntry: false });
|
|
33876
33882
|
if (manifest.hooks !== undefined && (manifest.mcpServers !== undefined || mcpPresent))
|
|
33877
33883
|
refuse2();
|
|
33878
33884
|
if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
|
|
@@ -33880,7 +33886,7 @@ function rootControls(root, read) {
|
|
|
33880
33886
|
if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
|
|
33881
33887
|
refuse2();
|
|
33882
33888
|
const mcpSha256 = mcpPresent ? mcpControls(mcp, read) : undefined;
|
|
33883
|
-
const app =
|
|
33889
|
+
const app = join20(root, ".app.json"), present = lstatSync15(app, { throwIfNoEntry: false });
|
|
33884
33890
|
if (present && (!present.isFile() || present.isSymbolicLink() || present.size > 1024 * 1024))
|
|
33885
33891
|
refuse2();
|
|
33886
33892
|
if (manifest.apps !== undefined && !present)
|
|
@@ -33912,12 +33918,12 @@ function documentIdentity(document2, cache, read) {
|
|
|
33912
33918
|
}
|
|
33913
33919
|
if (!front || typeof front !== "object" || !identifier2(front.name) || typeof front.description !== "string" || !front.description.trim())
|
|
33914
33920
|
refuse2();
|
|
33915
|
-
for (let root =
|
|
33916
|
-
const path =
|
|
33917
|
-
if (!
|
|
33921
|
+
for (let root = dirname16(document2), depth = 0;root.startsWith(cache + sep8) && depth < 12; root = dirname16(root), depth++) {
|
|
33922
|
+
const path = join20(root, ".codex-plugin", "plugin.json");
|
|
33923
|
+
if (!lstatSync15(path, { throwIfNoEntry: false }))
|
|
33918
33924
|
continue;
|
|
33919
|
-
const manifestFile =
|
|
33920
|
-
if (!
|
|
33925
|
+
const manifestFile = lstatSync15(path);
|
|
33926
|
+
if (!lstatSync15(join20(root, ".codex-plugin")).isDirectory() || !manifestFile.isFile() || manifestFile.size > 1024 * 1024)
|
|
33921
33927
|
refuse2();
|
|
33922
33928
|
let manifest;
|
|
33923
33929
|
try {
|
|
@@ -33930,9 +33936,9 @@ function documentIdentity(document2, cache, read) {
|
|
|
33930
33936
|
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest) || !identifier2(manifest.name))
|
|
33931
33937
|
refuse2();
|
|
33932
33938
|
const declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
|
|
33933
|
-
if (declaredVersion === null || (declaredVersion ? declaredVersion !==
|
|
33939
|
+
if (declaredVersion === null || (declaredVersion ? declaredVersion !== basename9(root) : basename9(root) !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
|
|
33934
33940
|
refuse2();
|
|
33935
|
-
return { name: `${manifest.name}:${front.name}`, namespace: manifest.name, pluginParent:
|
|
33941
|
+
return { name: `${manifest.name}:${front.name}`, namespace: manifest.name, pluginParent: dirname16(root), root };
|
|
33936
33942
|
}
|
|
33937
33943
|
refuse2();
|
|
33938
33944
|
}
|
|
@@ -33948,7 +33954,7 @@ function classifyCodexPluginCacheDocument(document2, cache, read) {
|
|
|
33948
33954
|
return null;
|
|
33949
33955
|
try {
|
|
33950
33956
|
const located = documentIdentity(document2, cache, read), parsed = identity3(document2, cache, read);
|
|
33951
|
-
if (!
|
|
33957
|
+
if (!lstatSync15(document2).isFile() || realpathSync5(document2) !== document2 || realpathSync5(located.root) !== located.root || realpathSync5(located.pluginParent) !== located.pluginParent || realpathSync5(join20(located.root, ".codex-plugin/plugin.json")) !== join20(located.root, ".codex-plugin/plugin.json"))
|
|
33952
33958
|
return null;
|
|
33953
33959
|
const parts = relative5(cache, parsed.pluginParent).split(sep8);
|
|
33954
33960
|
if (parts.length !== 2 || parts.some((part) => !identifier2(part)) || parts[1] !== parsed.namespace)
|
|
@@ -33963,11 +33969,11 @@ function reviewedDisabledCodexPluginParent(cache, parent, controls, rules) {
|
|
|
33963
33969
|
const parts = relative5(cache, parent).split(sep8), enrolled = controls.filter((control) => control.pluginParent === parent);
|
|
33964
33970
|
if (resolve14(parent) !== parent || parts.length !== 2 || parts.some((part) => !identifier2(part)) || !enrolled.length || !Array.isArray(rules))
|
|
33965
33971
|
return false;
|
|
33966
|
-
for (let cursor = parent;; cursor =
|
|
33967
|
-
const stat2 =
|
|
33972
|
+
for (let cursor = parent;; cursor = dirname16(cursor)) {
|
|
33973
|
+
const stat2 = lstatSync15(cursor, { throwIfNoEntry: false });
|
|
33968
33974
|
if (stat2 && (!stat2.isDirectory() || stat2.isSymbolicLink()))
|
|
33969
33975
|
return false;
|
|
33970
|
-
if (
|
|
33976
|
+
if (dirname16(cursor) === cursor)
|
|
33971
33977
|
break;
|
|
33972
33978
|
}
|
|
33973
33979
|
return enrolled.every((control) => control.namespace === parts[1] && control.pluginId === `${parts[1]}@${parts[0]}` && remotePluginIdentifier(control.remotePluginId) && control.skillsOnly === true && !control.appSha256 && !control.mcpSha256 && control.name.startsWith(control.namespace + ":") && /^[a-f0-9]{64}$/.test(control.manifestSha256) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === control.name && rule.enabled === false) && !rules.some((rule) => (typeof rule?.name === "string" && rule.name.trim() === control.name || typeof rule?.path === "string" && (rule.path === parent || rule.path.startsWith(parent + sep8))) && rule.enabled !== false));
|
|
@@ -33976,36 +33982,36 @@ function reviewedDisabledCodexPluginParent(cache, parent, controls, rules) {
|
|
|
33976
33982
|
}
|
|
33977
33983
|
}
|
|
33978
33984
|
function absentDisabledCodexPluginParent(cache, parent, controls, rules) {
|
|
33979
|
-
return reviewedDisabledCodexPluginParent(cache, parent, controls, rules) && !
|
|
33985
|
+
return reviewedDisabledCodexPluginParent(cache, parent, controls, rules) && !lstatSync15(parent, { throwIfNoEntry: false });
|
|
33980
33986
|
}
|
|
33981
33987
|
function reviewedRetiredCodexRoot(cache, root, controls, rules, read, allowAbsent = false) {
|
|
33982
33988
|
try {
|
|
33983
|
-
const parent =
|
|
33984
|
-
if (resolve14(root) !== root || parts.length !== 2 || parts.some((part) => !identifier2(part)) || !
|
|
33989
|
+
const parent = dirname16(root), parts = relative5(cache, parent).split(sep8), enrolled = controls.filter((control) => control.pluginParent === parent);
|
|
33990
|
+
if (resolve14(root) !== root || parts.length !== 2 || parts.some((part) => !identifier2(part)) || !basename9(root) || basename9(root) === "latest" || !enrolled.length || !Array.isArray(rules))
|
|
33985
33991
|
return false;
|
|
33986
|
-
for (let cursor = root;; cursor =
|
|
33987
|
-
const stat2 =
|
|
33992
|
+
for (let cursor = root;; cursor = dirname16(cursor)) {
|
|
33993
|
+
const stat2 = lstatSync15(cursor, { throwIfNoEntry: false });
|
|
33988
33994
|
if (stat2 && (!stat2.isDirectory() || stat2.isSymbolicLink()))
|
|
33989
33995
|
return false;
|
|
33990
|
-
if (
|
|
33996
|
+
if (dirname16(cursor) === cursor)
|
|
33991
33997
|
break;
|
|
33992
33998
|
}
|
|
33993
33999
|
if (!enrolled.every((control) => control.namespace === parts[1] && control.pluginId === `${parts[1]}@${parts[0]}` && remotePluginIdentifier(control.remotePluginId) && control.skillsOnly === true && !control.appSha256 && !control.mcpSha256 && control.name.startsWith(control.namespace + ":") && /^[a-f0-9]{64}$/.test(control.manifestSha256) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === control.name && rule.enabled === false) && !rules.some((rule) => (typeof rule?.name === "string" && rule.name.trim() === control.name || typeof rule?.path === "string" && (rule.path === parent || rule.path === root || rule.path.startsWith(root + sep8))) && rule.enabled !== false)))
|
|
33994
34000
|
return false;
|
|
33995
|
-
if (!
|
|
33996
|
-
return allowAbsent && (
|
|
34001
|
+
if (!lstatSync15(root, { throwIfNoEntry: false }))
|
|
34002
|
+
return allowAbsent && (lstatSync15(parent, { throwIfNoEntry: false }) ? enrolled.every((control) => remoteInstallationMatches(parent, control.remotePluginId, read)) : absentDisabledCodexPluginParent(cache, parent, controls, rules));
|
|
33997
34003
|
if (!enrolled.every((control) => remoteInstallationMatches(parent, control.remotePluginId, read)))
|
|
33998
34004
|
return false;
|
|
33999
34005
|
const parsed = rootControls(root, read);
|
|
34000
|
-
if (JSON.parse(read(
|
|
34006
|
+
if (JSON.parse(read(join20(root, ".codex-plugin/plugin.json"))).hooks !== undefined)
|
|
34001
34007
|
return false;
|
|
34002
34008
|
if (!enrolled.some((control) => control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && !parsed.appSha256 && !parsed.mcpSha256))
|
|
34003
34009
|
return false;
|
|
34004
34010
|
let entries = 0;
|
|
34005
|
-
const emptySkills = (directory, depth) => depth <= 64 &&
|
|
34011
|
+
const emptySkills = (directory, depth) => depth <= 64 && readdirSync6(directory).every((name) => {
|
|
34006
34012
|
if (++entries > 4096 || name === "SKILL.md")
|
|
34007
34013
|
return false;
|
|
34008
|
-
const path =
|
|
34014
|
+
const path = join20(directory, name), stat2 = lstatSync15(path);
|
|
34009
34015
|
return !stat2.isSymbolicLink() && (stat2.isFile() || stat2.isDirectory() && emptySkills(path, depth + 1));
|
|
34010
34016
|
});
|
|
34011
34017
|
return emptySkills(root, 0);
|
|
@@ -34021,26 +34027,26 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read, rules)
|
|
|
34021
34027
|
for (const parent of new Set(controls.map((control) => control.pluginParent))) {
|
|
34022
34028
|
if (absentDisabledCodexPluginParent(cache, parent, controls, rules))
|
|
34023
34029
|
continue;
|
|
34024
|
-
if (!parent.startsWith(cache + sep8) || !
|
|
34030
|
+
if (!parent.startsWith(cache + sep8) || !lstatSync15(parent, { throwIfNoEntry: false })?.isDirectory() || realpathSync5(parent) !== parent)
|
|
34025
34031
|
return false;
|
|
34026
34032
|
for (const control of controls.filter((control2) => control2.pluginParent === parent)) {
|
|
34027
34033
|
if (control.remotePluginId !== undefined && !remoteInstallationMatches(parent, control.remotePluginId, read))
|
|
34028
34034
|
return false;
|
|
34029
34035
|
}
|
|
34030
|
-
const names =
|
|
34036
|
+
const names = readdirSync6(parent);
|
|
34031
34037
|
entries += names.length;
|
|
34032
34038
|
if (entries > 4096)
|
|
34033
34039
|
return false;
|
|
34034
34040
|
for (const name of names) {
|
|
34035
|
-
let root =
|
|
34041
|
+
let root = join20(parent, name), stat2 = lstatSync15(root);
|
|
34036
34042
|
if (stat2.isSymbolicLink()) {
|
|
34037
34043
|
const target = resolve14(parent, readlinkSync3(root));
|
|
34038
|
-
if (name !== "latest" ||
|
|
34044
|
+
if (name !== "latest" || dirname16(target) !== parent || !lstatSync15(target).isDirectory() || realpathSync5(target) !== target)
|
|
34039
34045
|
return false;
|
|
34040
34046
|
root = target;
|
|
34041
|
-
stat2 =
|
|
34047
|
+
stat2 = lstatSync15(root);
|
|
34042
34048
|
}
|
|
34043
|
-
if (!stat2.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) =>
|
|
34049
|
+
if (!stat2.isDirectory() || ![".codex-plugin/plugin.json", ".app.json", "hooks", ".mcp.json"].some((path) => lstatSync15(join20(root, path), { throwIfNoEntry: false })))
|
|
34044
34050
|
continue;
|
|
34045
34051
|
const parsed = rootControls(root, read);
|
|
34046
34052
|
if (!controls.some((control) => control.pluginParent === parent && control.namespace === parsed.namespace && control.manifestSha256 === parsed.manifestSha256 && control.appSha256 === parsed.appSha256 && control.mcpSha256 === parsed.mcpSha256))
|
|
@@ -34055,9 +34061,9 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read, rules)
|
|
|
34055
34061
|
function sourceInputUnchanged(input2, cache, read) {
|
|
34056
34062
|
try {
|
|
34057
34063
|
const parts = relative5(cache, input2.pluginParent).split(sep8);
|
|
34058
|
-
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 })) || resolve14(input2.sourceRoot) !== input2.sourceRoot || !
|
|
34064
|
+
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 })) || resolve14(input2.sourceRoot) !== input2.sourceRoot || !lstatSync15(input2.sourceRoot).isDirectory() || realpathSync5(input2.sourceRoot) !== input2.sourceRoot || input2.sourceRoot === cache || input2.sourceRoot.startsWith(cache + sep8) || cache.startsWith(input2.sourceRoot + sep8))
|
|
34059
34065
|
return false;
|
|
34060
|
-
const path =
|
|
34066
|
+
const path = join20(input2.sourceRoot, ".codex-plugin/plugin.json"), stat2 = lstatSync15(path);
|
|
34061
34067
|
if (!stat2.isFile() || stat2.size > 1024 * 1024 || realpathSync5(path) !== path)
|
|
34062
34068
|
return false;
|
|
34063
34069
|
const text2 = read(path);
|
|
@@ -34080,11 +34086,12 @@ var identifier2 = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(v
|
|
|
34080
34086
|
var init_codex_plugin_skill_controls = __esm(() => {
|
|
34081
34087
|
init_claude_settings_witness();
|
|
34082
34088
|
init_codex_native_compatibility();
|
|
34089
|
+
init_codex_plugin_capability_paths();
|
|
34083
34090
|
init_codex_native_skill_catalog();
|
|
34084
34091
|
});
|
|
34085
34092
|
|
|
34086
34093
|
// src/lib/codex-vendor-refresh.ts
|
|
34087
|
-
var CODEX_VENDOR_MARKETPLACES, CODEX_REMOTE_VENDOR_MARKETPLACES, OTHER_PLUGIN_CONTROLS
|
|
34094
|
+
var CODEX_VENDOR_MARKETPLACES, CODEX_REMOTE_VENDOR_MARKETPLACES, OTHER_PLUGIN_CONTROLS;
|
|
34088
34095
|
var init_codex_vendor_refresh = __esm(() => {
|
|
34089
34096
|
init_claude_settings_witness();
|
|
34090
34097
|
init_codex_plugin_skill_controls();
|
|
@@ -34092,8 +34099,6 @@ var init_codex_vendor_refresh = __esm(() => {
|
|
|
34092
34099
|
CODEX_VENDOR_MARKETPLACES = Object.freeze(["openai-bundled", "openai-curated", "openai-curated-remote"]);
|
|
34093
34100
|
CODEX_REMOTE_VENDOR_MARKETPLACES = Object.freeze(["openai-curated-remote"]);
|
|
34094
34101
|
OTHER_PLUGIN_CONTROLS = Object.freeze(CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES.filter((entry) => entry !== ".codex-plugin" && entry !== ".app.json"));
|
|
34095
|
-
VENDOR_MANIFEST_KEYS = Object.freeze(["name", "version", "description", "author", "homepage", "repository", "license", "keywords", "interface", "skills", "apps"]);
|
|
34096
|
-
DEFAULT_SKILLS_PATHS = Object.freeze(["./skills", "./skills/"]);
|
|
34097
34102
|
});
|
|
34098
34103
|
|
|
34099
34104
|
// src/lib/claude-plugin-manifest-witness.ts
|
|
@@ -34537,19 +34542,19 @@ function capturePreparationProcess(child2, platform = process.platform, signalGr
|
|
|
34537
34542
|
}
|
|
34538
34543
|
|
|
34539
34544
|
// src/lib/dependency-preparation.ts
|
|
34540
|
-
import { constants as constants9, closeSync as closeSync12, fstatSync as fstatSync12, lstatSync as
|
|
34541
|
-
import { join as
|
|
34545
|
+
import { constants as constants9, closeSync as closeSync12, fstatSync as fstatSync12, lstatSync as lstatSync16, mkdirSync as mkdirSync5, openSync as openSync12, readFileSync as readFileSync14, readdirSync as readdirSync7, rmdirSync as rmdirSync2, unlinkSync as unlinkSync3, ftruncateSync, writeSync as writeSync2 } from "fs";
|
|
34546
|
+
import { join as join21 } from "path";
|
|
34542
34547
|
function hasDependencyPreparationMarker(skillPath) {
|
|
34543
34548
|
try {
|
|
34544
|
-
|
|
34549
|
+
lstatSync16(join21(skillPath, DEPENDENCY_PREPARATION_MARKER));
|
|
34545
34550
|
return true;
|
|
34546
34551
|
} catch (error61) {
|
|
34547
34552
|
return error61.code !== "ENOENT";
|
|
34548
34553
|
}
|
|
34549
34554
|
}
|
|
34550
34555
|
function claimPreparation(skillPath) {
|
|
34551
|
-
const marker =
|
|
34552
|
-
const state =
|
|
34556
|
+
const marker = join21(skillPath, DEPENDENCY_PREPARATION_MARKER);
|
|
34557
|
+
const state = join21(marker, "state.json"), active = join21(marker, "active");
|
|
34553
34558
|
let created = false;
|
|
34554
34559
|
try {
|
|
34555
34560
|
mkdirSync5(marker, { mode: 448 });
|
|
@@ -34560,14 +34565,14 @@ function claimPreparation(skillPath) {
|
|
|
34560
34565
|
}
|
|
34561
34566
|
let fd;
|
|
34562
34567
|
try {
|
|
34563
|
-
if (!
|
|
34568
|
+
if (!lstatSync16(marker).isDirectory() || lstatSync16(marker).isSymbolicLink())
|
|
34564
34569
|
return;
|
|
34565
34570
|
if (!created) {
|
|
34566
|
-
if (
|
|
34571
|
+
if (readdirSync7(marker).some((name) => name !== "state.json"))
|
|
34567
34572
|
return;
|
|
34568
|
-
if (!
|
|
34573
|
+
if (!lstatSync16(state).isFile() || lstatSync16(state).isSymbolicLink() || lstatSync16(state).size > 1024)
|
|
34569
34574
|
return;
|
|
34570
|
-
const previous = JSON.parse(
|
|
34575
|
+
const previous = JSON.parse(readFileSync14(state, "utf8"));
|
|
34571
34576
|
if (previous.version !== 1 || previous.status !== "failed" || Object.keys(previous).length !== 2)
|
|
34572
34577
|
return;
|
|
34573
34578
|
}
|
|
@@ -34700,6 +34705,9 @@ async function prepareSkillDependencies(skillPath, env, timeoutMs = DEFAULT_PREP
|
|
|
34700
34705
|
var DEPENDENCY_PREPARATION_MARKER = ".skills-dependency-preparation", RECOVERY = "Skill dependency preparation is incomplete. Confirm no installer is running, successfully run bun install --no-save in the skill directory, then remove only .skills-dependency-preparation. See docs/skill-standard.md#recovering-interrupted-dependency-preparation.", DEFAULT_PREPARATION_TIMEOUT_MS = 60000;
|
|
34701
34706
|
var init_dependency_preparation = () => {};
|
|
34702
34707
|
|
|
34708
|
+
// src/lib/codex-native-config.ts
|
|
34709
|
+
var init_codex_native_config = () => {};
|
|
34710
|
+
|
|
34703
34711
|
// src/lib/codex-native-skill-policy.ts
|
|
34704
34712
|
var MAX_EXECUTABLE_BYTES, MAX_BRIDGE_DOCUMENT_BYTES, CODEX_NATIVE_POLICY_HELPER_MAX_OUTPUT_BYTES, executableDigestMemory;
|
|
34705
34713
|
var init_codex_native_skill_policy = __esm(() => {
|
|
@@ -34711,8 +34719,8 @@ var init_codex_native_skill_policy = __esm(() => {
|
|
|
34711
34719
|
|
|
34712
34720
|
// src/lib/codex-semantic-cache-witness.ts
|
|
34713
34721
|
import { createHash as createHash18 } from "crypto";
|
|
34714
|
-
import { constants as constants10, closeSync as closeSync13, fstatSync as fstatSync13, lstatSync as
|
|
34715
|
-
import { basename as
|
|
34722
|
+
import { constants as constants10, closeSync as closeSync13, fstatSync as fstatSync13, lstatSync as lstatSync17, openSync as openSync13, readSync as readSync7, readdirSync as readdirSync8, realpathSync as realpathSync6 } from "fs";
|
|
34723
|
+
import { basename as basename10, dirname as dirname17, isAbsolute as isAbsolute15, join as join22, relative as relative6, resolve as resolve15, sep as sep9 } from "path";
|
|
34716
34724
|
function codexLocalMarketplaceMapsPlugin(text2, marketplace, plugin) {
|
|
34717
34725
|
try {
|
|
34718
34726
|
hashNativeJsonControls(text2);
|
|
@@ -34734,7 +34742,7 @@ function codexLocalMarketplaceMapsPlugin(text2, marketplace, plugin) {
|
|
|
34734
34742
|
}
|
|
34735
34743
|
}
|
|
34736
34744
|
function defaultRead(path) {
|
|
34737
|
-
const before =
|
|
34745
|
+
const before = lstatSync17(path, { throwIfNoEntry: false, bigint: true });
|
|
34738
34746
|
if (before === undefined)
|
|
34739
34747
|
return refuse3();
|
|
34740
34748
|
if (!before.isFile() || before.isSymbolicLink() || before.size > BigInt(MAX_DOCUMENT_BYTES))
|
|
@@ -34825,7 +34833,7 @@ function assertWitnessShape(value) {
|
|
|
34825
34833
|
const row = candidate;
|
|
34826
34834
|
const remote = row.installation === "remote-receipt";
|
|
34827
34835
|
const local = row.installation === "local-marketplace";
|
|
34828
|
-
if (!exactKeys(row, ["role", "pluginId", "namespace", "pluginParent", "installation", "manifestSha256", "hooksSha256"], remote ? ["remotePluginId", "receiptSha256"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || row.role !== "reviewed-hook" || !identifier4(row.namespace) || typeof row.pluginId !== "string" || !/^[A-Za-z0-9_-]{1,64}@[A-Za-z0-9_-]{1,64}$/.test(row.pluginId) || typeof row.pluginParent !== "string" || !validPluginParent(String(witness.cacheRoot), row.pluginParent, row.namespace, row.pluginId) || remote && (typeof row.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(row.remotePluginId) || !digest(row.receiptSha256)) || local && (typeof row.marketplaceSourcePath !== "string" || !isAbsolute15(row.marketplaceSourcePath) || resolve15(row.marketplaceSourcePath) !== row.marketplaceSourcePath ||
|
|
34836
|
+
if (!exactKeys(row, ["role", "pluginId", "namespace", "pluginParent", "installation", "manifestSha256", "hooksSha256"], remote ? ["remotePluginId", "receiptSha256"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || row.role !== "reviewed-hook" || !identifier4(row.namespace) || typeof row.pluginId !== "string" || !/^[A-Za-z0-9_-]{1,64}@[A-Za-z0-9_-]{1,64}$/.test(row.pluginId) || typeof row.pluginParent !== "string" || !validPluginParent(String(witness.cacheRoot), row.pluginParent, row.namespace, row.pluginId) || remote && (typeof row.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(row.remotePluginId) || !digest(row.receiptSha256)) || local && (typeof row.marketplaceSourcePath !== "string" || !isAbsolute15(row.marketplaceSourcePath) || resolve15(row.marketplaceSourcePath) !== row.marketplaceSourcePath || basename10(row.marketplaceSourcePath) !== "marketplace.json" || !digest(row.marketplaceSha256)) || !remote && !local || !digest(row.manifestSha256) || !digest(row.hooksSha256) || hookParentPaths.has(row.pluginParent) || controlParents.has(row.pluginParent) || appOnlyParentPaths.has(row.pluginParent))
|
|
34829
34837
|
refuse3();
|
|
34830
34838
|
hookParentPaths.add(row.pluginParent);
|
|
34831
34839
|
}
|
|
@@ -34857,23 +34865,23 @@ function assertWitnessShape(value) {
|
|
|
34857
34865
|
function assertCanonicalDirectory(path) {
|
|
34858
34866
|
if (resolve15(path) !== path || realpathSync6(path) !== path)
|
|
34859
34867
|
refuse3();
|
|
34860
|
-
for (let cursor = path;; cursor =
|
|
34861
|
-
const stat2 =
|
|
34868
|
+
for (let cursor = path;; cursor = dirname17(cursor)) {
|
|
34869
|
+
const stat2 = lstatSync17(cursor, { throwIfNoEntry: false });
|
|
34862
34870
|
if (stat2 && (!stat2.isDirectory() || stat2.isSymbolicLink()))
|
|
34863
34871
|
refuse3();
|
|
34864
|
-
if (
|
|
34872
|
+
if (dirname17(cursor) === cursor)
|
|
34865
34873
|
break;
|
|
34866
34874
|
}
|
|
34867
34875
|
}
|
|
34868
34876
|
function walkSafeTree(path, state, depth = 0, root = path) {
|
|
34869
34877
|
if (depth > 64 || ++state.entries > 16384)
|
|
34870
34878
|
refuse3();
|
|
34871
|
-
const names =
|
|
34879
|
+
const names = readdirSync8(path).sort();
|
|
34872
34880
|
const files = [];
|
|
34873
34881
|
for (const name of names) {
|
|
34874
34882
|
if (!name || name === "." || name === ".." || name.includes(sep9) || ++state.entries > 16384)
|
|
34875
34883
|
refuse3();
|
|
34876
|
-
const child2 =
|
|
34884
|
+
const child2 = join22(path, name), stat2 = lstatSync17(child2, { bigint: true });
|
|
34877
34885
|
state.members.push(child2);
|
|
34878
34886
|
state.signature.push(`${relative6(root, child2)}\x00${stat2.mode}\x00${stat2.dev}\x00${stat2.ino}\x00${stat2.isDirectory() ? 0 : stat2.size}`);
|
|
34879
34887
|
state.timestamps.set(child2, `${stat2.mtimeNs}\x00${stat2.ctimeNs}`);
|
|
@@ -34890,7 +34898,7 @@ function walkSafeTree(path, state, depth = 0, root = path) {
|
|
|
34890
34898
|
}
|
|
34891
34899
|
function treeSnapshot(cacheRoot) {
|
|
34892
34900
|
const state = { entries: 0, members: [], signature: [], timestamps: new Map };
|
|
34893
|
-
const rootStat =
|
|
34901
|
+
const rootStat = lstatSync17(cacheRoot, { throwIfNoEntry: false, bigint: true });
|
|
34894
34902
|
if (rootStat === undefined)
|
|
34895
34903
|
return refuse3();
|
|
34896
34904
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink() || realpathSync6(cacheRoot) !== cacheRoot)
|
|
@@ -34910,7 +34918,7 @@ function assertSameTree(before, after, semanticPaths) {
|
|
|
34910
34918
|
function trackedBoundedRead(read) {
|
|
34911
34919
|
const observed = new Map;
|
|
34912
34920
|
const stableStat = (path, max) => {
|
|
34913
|
-
const stat2 =
|
|
34921
|
+
const stat2 = lstatSync17(path, { throwIfNoEntry: false, bigint: true });
|
|
34914
34922
|
if (stat2 === undefined)
|
|
34915
34923
|
return refuse3();
|
|
34916
34924
|
if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.size > BigInt(max) || realpathSync6(path) !== path)
|
|
@@ -34966,7 +34974,7 @@ function controlProjection(controls, read) {
|
|
|
34966
34974
|
...control.mcpSha256 === undefined ? {} : { mcpSha256: control.mcpSha256 }
|
|
34967
34975
|
};
|
|
34968
34976
|
if (row.remotePluginId !== undefined) {
|
|
34969
|
-
const receipt =
|
|
34977
|
+
const receipt = join22(row.pluginParent, ".codex-remote-plugin-install.json"), stat2 = lstatSync17(receipt, { throwIfNoEntry: false });
|
|
34970
34978
|
if (!stat2?.isFile() || stat2.isSymbolicLink() || stat2.size > 16384)
|
|
34971
34979
|
refuse3();
|
|
34972
34980
|
try {
|
|
@@ -34998,10 +35006,10 @@ function appOnlyParentProjection(cacheRoot, parents2, read) {
|
|
|
34998
35006
|
if (resolve15(parent.pluginParent) !== parent.pluginParent || parts.length !== 2 || parts.some((part) => !identifier4(part)) || parent.pluginId !== `${parent.namespace}@${parts[0]}` || parts[1] !== parent.namespace || seen.has(parent.pluginParent))
|
|
34999
35007
|
refuse3();
|
|
35000
35008
|
seen.add(parent.pluginParent);
|
|
35001
|
-
const parentStat =
|
|
35009
|
+
const parentStat = lstatSync17(parent.pluginParent, { throwIfNoEntry: false });
|
|
35002
35010
|
if (!parentStat?.isDirectory() || parentStat.isSymbolicLink() || realpathSync6(parent.pluginParent) !== parent.pluginParent)
|
|
35003
35011
|
refuse3();
|
|
35004
|
-
const receipt =
|
|
35012
|
+
const receipt = join22(parent.pluginParent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync17(receipt, { throwIfNoEntry: false });
|
|
35005
35013
|
if (!receiptStat?.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > 16384)
|
|
35006
35014
|
refuse3();
|
|
35007
35015
|
let receiptText = "";
|
|
@@ -35014,13 +35022,13 @@ function appOnlyParentProjection(cacheRoot, parents2, read) {
|
|
|
35014
35022
|
} catch {
|
|
35015
35023
|
refuse3();
|
|
35016
35024
|
}
|
|
35017
|
-
const versions2 =
|
|
35025
|
+
const versions2 = readdirSync8(parent.pluginParent).filter((name) => name !== ".codex-remote-plugin-install.json");
|
|
35018
35026
|
if (!versions2.length || versions2.length > 4096)
|
|
35019
35027
|
refuse3();
|
|
35020
35028
|
const materializations = versions2.map((version2) => {
|
|
35021
35029
|
if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
|
|
35022
35030
|
refuse3();
|
|
35023
|
-
const root =
|
|
35031
|
+
const root = join22(parent.pluginParent, version2), stat2 = lstatSync17(root, { throwIfNoEntry: false });
|
|
35024
35032
|
if (!stat2?.isDirectory() || stat2.isSymbolicLink() || realpathSync6(root) !== root)
|
|
35025
35033
|
refuse3();
|
|
35026
35034
|
const rootControls2 = readCodexPluginRootControls(root, read);
|
|
@@ -35060,7 +35068,7 @@ function assertJsonValue(value, depth = 0, budget2 = { members: 0 }) {
|
|
|
35060
35068
|
}
|
|
35061
35069
|
}
|
|
35062
35070
|
function reviewedHookControls(root, read) {
|
|
35063
|
-
const manifestPath =
|
|
35071
|
+
const manifestPath = join22(root, ".codex-plugin/plugin.json"), hooksPath = join22(root, "hooks/hooks.json");
|
|
35064
35072
|
let manifest, manifestSha256, hooks, hooksSha256;
|
|
35065
35073
|
try {
|
|
35066
35074
|
const manifestText = read(manifestPath);
|
|
@@ -35073,7 +35081,7 @@ function reviewedHookControls(root, read) {
|
|
|
35073
35081
|
} catch {
|
|
35074
35082
|
return refuse3();
|
|
35075
35083
|
}
|
|
35076
|
-
if (!plainObject(manifest) || !exactKeys(manifest, ["name", "version", "hooks"], ["description"]) || !identifier4(manifest.name) || typeof manifest.version !== "string" || manifest.version !==
|
|
35084
|
+
if (!plainObject(manifest) || !exactKeys(manifest, ["name", "version", "hooks"], ["description"]) || !identifier4(manifest.name) || typeof manifest.version !== "string" || manifest.version !== basename10(root) || manifest.hooks !== "./hooks/hooks.json" || manifest.description !== undefined && (typeof manifest.description !== "string" || !manifest.description.trim() || manifest.description.length > 1024))
|
|
35077
35085
|
refuse3();
|
|
35078
35086
|
const manifestRecord = manifest;
|
|
35079
35087
|
if (!plainObject(hooks) || !exactKeys(hooks, ["hooks"], ["description"]) || !plainObject(hooks.hooks) || hooks.description !== undefined && typeof hooks.description !== "string")
|
|
@@ -35104,16 +35112,16 @@ function reviewedHookParentProjection(cacheRoot, parents2, read) {
|
|
|
35104
35112
|
const seen = new Set, rows = [];
|
|
35105
35113
|
for (const parent of parents2) {
|
|
35106
35114
|
const remote = parent?.installation === "remote-receipt", local = parent?.installation === "local-marketplace";
|
|
35107
|
-
if (!parent || !exactKeys(parent, ["installation", "namespace", "pluginId", "pluginParent", "role"], remote ? ["remotePluginId"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || parent.role !== "reviewed-hook" || !identifier4(parent.namespace) || !/^[A-Za-z0-9_-]{1,64}@[A-Za-z0-9_-]{1,64}$/.test(parent.pluginId) || typeof parent.pluginParent !== "string" || remote && (typeof parent.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(parent.remotePluginId)) || local && (typeof parent.marketplaceSourcePath !== "string" || !isAbsolute15(parent.marketplaceSourcePath) || resolve15(parent.marketplaceSourcePath) !== parent.marketplaceSourcePath ||
|
|
35115
|
+
if (!parent || !exactKeys(parent, ["installation", "namespace", "pluginId", "pluginParent", "role"], remote ? ["remotePluginId"] : local ? ["marketplaceSourcePath", "marketplaceSha256"] : []) || parent.role !== "reviewed-hook" || !identifier4(parent.namespace) || !/^[A-Za-z0-9_-]{1,64}@[A-Za-z0-9_-]{1,64}$/.test(parent.pluginId) || typeof parent.pluginParent !== "string" || remote && (typeof parent.remotePluginId !== "string" || !/^[A-Za-z0-9_~-]{1,1024}$/.test(parent.remotePluginId)) || local && (typeof parent.marketplaceSourcePath !== "string" || !isAbsolute15(parent.marketplaceSourcePath) || resolve15(parent.marketplaceSourcePath) !== parent.marketplaceSourcePath || basename10(parent.marketplaceSourcePath) !== "marketplace.json" || !digest(parent.marketplaceSha256)) || !remote && !local)
|
|
35108
35116
|
refuse3();
|
|
35109
35117
|
const parts = relative6(cacheRoot, parent.pluginParent).split(sep9);
|
|
35110
35118
|
if (!isAbsolute15(parent.pluginParent) || resolve15(parent.pluginParent) !== parent.pluginParent || parts.length !== 2 || parts.some((part) => !identifier4(part)) || parts[1] !== parent.namespace || parent.pluginId !== `${parent.namespace}@${parts[0]}` || seen.has(parent.pluginParent))
|
|
35111
35119
|
refuse3();
|
|
35112
35120
|
seen.add(parent.pluginParent);
|
|
35113
|
-
const parentStat =
|
|
35121
|
+
const parentStat = lstatSync17(parent.pluginParent, { throwIfNoEntry: false });
|
|
35114
35122
|
if (!parentStat?.isDirectory() || parentStat.isSymbolicLink() || realpathSync6(parent.pluginParent) !== parent.pluginParent)
|
|
35115
35123
|
refuse3();
|
|
35116
|
-
const receiptPath =
|
|
35124
|
+
const receiptPath = join22(parent.pluginParent, ".codex-remote-plugin-install.json"), receiptStat = lstatSync17(receiptPath, { throwIfNoEntry: false });
|
|
35117
35125
|
let receiptText;
|
|
35118
35126
|
if (remote) {
|
|
35119
35127
|
if (!receiptStat?.isFile() || receiptStat.isSymbolicLink() || receiptStat.size > MAX_RECEIPT_BYTES)
|
|
@@ -35140,10 +35148,10 @@ function reviewedHookParentProjection(cacheRoot, parents2, read) {
|
|
|
35140
35148
|
if (createHash18("sha256").update(marketplaceText).digest("hex") !== parent.marketplaceSha256 || !codexLocalMarketplaceMapsPlugin(marketplaceText, parts[0], parent.namespace))
|
|
35141
35149
|
refuse3();
|
|
35142
35150
|
}
|
|
35143
|
-
const materializations =
|
|
35151
|
+
const materializations = readdirSync8(parent.pluginParent).filter((name) => name !== ".codex-remote-plugin-install.json").map((version2) => {
|
|
35144
35152
|
if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(version2))
|
|
35145
35153
|
refuse3();
|
|
35146
|
-
const root =
|
|
35154
|
+
const root = join22(parent.pluginParent, version2), stat2 = lstatSync17(root, { throwIfNoEntry: false });
|
|
35147
35155
|
if (!stat2?.isDirectory() || stat2.isSymbolicLink() || realpathSync6(root) !== root)
|
|
35148
35156
|
refuse3();
|
|
35149
35157
|
const controls = reviewedHookControls(root, read);
|
|
@@ -35172,17 +35180,17 @@ function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files,
|
|
|
35172
35180
|
const rel = relative6(cacheRoot, file2), parts = rel.split(sep9);
|
|
35173
35181
|
if (parts.length < 3 || !identifier4(parts[0]) || !identifier4(parts[1]))
|
|
35174
35182
|
refuse3();
|
|
35175
|
-
actual.add(
|
|
35183
|
+
actual.add(join22(cacheRoot, parts[0], parts[1]));
|
|
35176
35184
|
}
|
|
35177
|
-
const actualMarkets =
|
|
35185
|
+
const actualMarkets = readdirSync8(cacheRoot);
|
|
35178
35186
|
if (actualMarkets.length !== expectedMarkets.size || actualMarkets.some((market) => !expectedMarkets.has(market)))
|
|
35179
35187
|
refuse3();
|
|
35180
35188
|
for (const market of actualMarkets) {
|
|
35181
|
-
const marketPath =
|
|
35189
|
+
const marketPath = join22(cacheRoot, market), marketStat = lstatSync17(marketPath);
|
|
35182
35190
|
if (!identifier4(market) || !marketStat.isDirectory() || marketStat.isSymbolicLink())
|
|
35183
35191
|
refuse3();
|
|
35184
|
-
for (const plugin of
|
|
35185
|
-
const parent =
|
|
35192
|
+
for (const plugin of readdirSync8(marketPath)) {
|
|
35193
|
+
const parent = join22(marketPath, plugin), stat2 = lstatSync17(parent);
|
|
35186
35194
|
if (!identifier4(plugin) || !stat2.isDirectory() || stat2.isSymbolicLink())
|
|
35187
35195
|
refuse3();
|
|
35188
35196
|
actual.add(parent);
|
|
@@ -35194,8 +35202,8 @@ function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files,
|
|
|
35194
35202
|
const parts = relative6(cacheRoot, member).split(sep9);
|
|
35195
35203
|
if (parts.length < 3)
|
|
35196
35204
|
continue;
|
|
35197
|
-
const parent =
|
|
35198
|
-
const root =
|
|
35205
|
+
const parent = join22(cacheRoot, parts[0], parts[1]);
|
|
35206
|
+
const root = join22(parent, parts[2]);
|
|
35199
35207
|
const base = parts[parts.length - 1], folded = foldCodexPluginEntryName(base);
|
|
35200
35208
|
if (parts.length === 3 && (codexPluginRootCapabilityEntry(base) !== null || isCodexSkillDocumentName(base)))
|
|
35201
35209
|
refuse3();
|
|
@@ -35208,11 +35216,11 @@ function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files,
|
|
|
35208
35216
|
refuse3();
|
|
35209
35217
|
if (parts.some((part) => CODEX_PLUGIN_MANIFEST_DIRECTORIES.includes(foldCodexPluginEntryName(part))) && (parts.length < 4 || parts[3] !== ".codex-plugin" || (parts.length === 4 ? base !== ".codex-plugin" : parts.length !== 5 || base !== "plugin.json")))
|
|
35210
35218
|
refuse3();
|
|
35211
|
-
if ([".app.json", ".mcp.json"].includes(folded) && (parts.length !== 4 ||
|
|
35219
|
+
if ([".app.json", ".mcp.json"].includes(folded) && (parts.length !== 4 || dirname17(member) !== root))
|
|
35212
35220
|
refuse3();
|
|
35213
35221
|
if ([".app.json", ".mcp.json"].includes(folded) && hookParents.some((reviewed) => reviewed.pluginParent === parent))
|
|
35214
35222
|
refuse3();
|
|
35215
|
-
if ((rootEntry === "hooks" || folded === "hooks.json") && (![4, 5].includes(parts.length) || parts[3] !== "hooks" || (parts.length === 4 ? base !== "hooks" : base !== "hooks.json") || !hookParents.some((reviewed) => reviewed.pluginParent ===
|
|
35223
|
+
if ((rootEntry === "hooks" || folded === "hooks.json") && (![4, 5].includes(parts.length) || parts[3] !== "hooks" || (parts.length === 4 ? base !== "hooks" : base !== "hooks.json") || !hookParents.some((reviewed) => reviewed.pluginParent === join22(cacheRoot, parts[0], parts[1]))))
|
|
35216
35224
|
refuse3();
|
|
35217
35225
|
}
|
|
35218
35226
|
}
|
|
@@ -35242,14 +35250,14 @@ function assertSkillMaterializations(cacheRoot, controls, files, read) {
|
|
|
35242
35250
|
const expectedNames = new Set(rows.map((row) => row.name));
|
|
35243
35251
|
if (expectedNames.size !== rows.length)
|
|
35244
35252
|
refuse3();
|
|
35245
|
-
const entries =
|
|
35253
|
+
const entries = readdirSync8(parent);
|
|
35246
35254
|
let roots = 0;
|
|
35247
35255
|
for (const entry of entries) {
|
|
35248
35256
|
if (entry === ".codex-remote-plugin-install.json")
|
|
35249
35257
|
continue;
|
|
35250
35258
|
if (!/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(entry))
|
|
35251
35259
|
refuse3();
|
|
35252
|
-
const root =
|
|
35260
|
+
const root = join22(parent, entry), stat2 = lstatSync17(root, { throwIfNoEntry: false });
|
|
35253
35261
|
if (!stat2?.isDirectory() || stat2.isSymbolicLink() || realpathSync6(root) !== root)
|
|
35254
35262
|
refuse3();
|
|
35255
35263
|
const actualControls = readCodexPluginRootControls(root, read);
|
|
@@ -35274,8 +35282,8 @@ function assertSkillMaterializations(cacheRoot, controls, files, read) {
|
|
|
35274
35282
|
const rel = relative6(cacheRoot, file2).split(sep9);
|
|
35275
35283
|
if (rel.length < 4)
|
|
35276
35284
|
refuse3();
|
|
35277
|
-
const parent =
|
|
35278
|
-
if (!byParent.has(parent) || !expectedByRoot.has(`${byParent.get(parent)[0].pluginId}\x00${
|
|
35285
|
+
const parent = join22(cacheRoot, rel[0], rel[1]);
|
|
35286
|
+
if (!byParent.has(parent) || !expectedByRoot.has(`${byParent.get(parent)[0].pluginId}\x00${join22(parent, rel[2])}`))
|
|
35279
35287
|
refuse3();
|
|
35280
35288
|
}
|
|
35281
35289
|
return expectedByRoot;
|
|
@@ -35336,11 +35344,11 @@ function captureCodexSemanticCacheWitness(options) {
|
|
|
35336
35344
|
const rootNames = new Map;
|
|
35337
35345
|
for (const document2 of docs) {
|
|
35338
35346
|
const rel = relative6(options.cacheRoot, document2).split(sep9);
|
|
35339
|
-
if (appOnlyParents.some((parent) => parent.pluginParent ===
|
|
35347
|
+
if (appOnlyParents.some((parent) => parent.pluginParent === join22(options.cacheRoot, rel[0], rel[1])))
|
|
35340
35348
|
refuse3();
|
|
35341
|
-
if (hookParents.some((parent) => parent.pluginParent ===
|
|
35349
|
+
if (hookParents.some((parent) => parent.pluginParent === join22(options.cacheRoot, rel[0], rel[1])))
|
|
35342
35350
|
refuse3();
|
|
35343
|
-
const documentStat =
|
|
35351
|
+
const documentStat = lstatSync17(document2, { throwIfNoEntry: false });
|
|
35344
35352
|
if (!documentStat?.isFile() || documentStat.isSymbolicLink() || documentStat.size > MAX_DOCUMENT_BYTES)
|
|
35345
35353
|
refuse3();
|
|
35346
35354
|
const identity4 = classifyCodexPluginCacheDocument(document2, options.cacheRoot, read);
|
|
@@ -35474,8 +35482,8 @@ var init_codex_node_modules = __esm(() => {
|
|
|
35474
35482
|
});
|
|
35475
35483
|
|
|
35476
35484
|
// src/lib/managed-policy.ts
|
|
35477
|
-
import { closeSync as closeSync14, constants as constants11, fstatSync as fstatSync14, lstatSync as
|
|
35478
|
-
import { join as
|
|
35485
|
+
import { closeSync as closeSync14, constants as constants11, fstatSync as fstatSync14, lstatSync as lstatSync18, openSync as openSync14, readSync as readSync8 } from "fs";
|
|
35486
|
+
import { join as join23 } from "path";
|
|
35479
35487
|
function refusal(reason2 = "is unreadable") {
|
|
35480
35488
|
return new SkillSelectionError("INVALID_AGENT_POLICY", `The Skills agent loading policy ${reason2}; refusing legacy fallback.`);
|
|
35481
35489
|
}
|
|
@@ -35500,10 +35508,10 @@ function parseManagedSkillPolicy(text2) {
|
|
|
35500
35508
|
return value;
|
|
35501
35509
|
}
|
|
35502
35510
|
function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
|
|
35503
|
-
const path =
|
|
35511
|
+
const path = join23(dataDir2, "agent-policy.json");
|
|
35504
35512
|
let descriptor, observed = false;
|
|
35505
35513
|
try {
|
|
35506
|
-
const stat2 =
|
|
35514
|
+
const stat2 = lstatSync18(path);
|
|
35507
35515
|
observed = true;
|
|
35508
35516
|
if (!stat2.isFile() || stat2.isSymbolicLink())
|
|
35509
35517
|
throw refusal();
|
|
@@ -35529,7 +35537,7 @@ function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
|
|
|
35529
35537
|
return { text: text2, value: parseManagedSkillPolicy(text2) };
|
|
35530
35538
|
} catch (error61) {
|
|
35531
35539
|
if (error61.code === "ENOENT" && !observed) {
|
|
35532
|
-
if (
|
|
35540
|
+
if (lstatSync18(path, { throwIfNoEntry: false }) === undefined)
|
|
35533
35541
|
return null;
|
|
35534
35542
|
}
|
|
35535
35543
|
if (error61 instanceof SkillSelectionError)
|
|
@@ -35655,8 +35663,8 @@ var init_hook_diagnostics = __esm(() => {
|
|
|
35655
35663
|
|
|
35656
35664
|
// src/lib/agent-sumi.ts
|
|
35657
35665
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
35658
|
-
import { accessSync, constants as constants12, existsSync as existsSync8, lstatSync as
|
|
35659
|
-
import { delimiter, isAbsolute as isAbsolute16, join as
|
|
35666
|
+
import { accessSync, constants as constants12, existsSync as existsSync8, lstatSync as lstatSync19, realpathSync as realpathSync7, statSync as statSync8 } from "fs";
|
|
35667
|
+
import { delimiter, isAbsolute as isAbsolute16, join as join24, resolve as resolve16 } from "path";
|
|
35660
35668
|
function recordWithKeys(value, keys) {
|
|
35661
35669
|
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key2) => Object.hasOwn(value, key2));
|
|
35662
35670
|
}
|
|
@@ -35706,11 +35714,11 @@ function validPathPlan(value, home, cwd) {
|
|
|
35706
35714
|
const legacyConfigRoot = value.legacyRoots.config;
|
|
35707
35715
|
if (typeof configRoot !== "string" || legacyConfigRoot !== null && typeof legacyConfigRoot !== "string")
|
|
35708
35716
|
return false;
|
|
35709
|
-
if (value.configFiles.canonical !==
|
|
35717
|
+
if (value.configFiles.canonical !== join24(configRoot, "sumi.json") || value.skillRoots.canonical !== join24(configRoot, "skills"))
|
|
35710
35718
|
return false;
|
|
35711
35719
|
if (legacyConfigRoot === null)
|
|
35712
35720
|
return value.configFiles.legacy === null && value.skillRoots.legacy === null;
|
|
35713
|
-
return value.configFiles.legacy ===
|
|
35721
|
+
return value.configFiles.legacy === join24(legacyConfigRoot, "sumi.json") && value.skillRoots.legacy === join24(legacyConfigRoot, "skills");
|
|
35714
35722
|
}
|
|
35715
35723
|
function sumiPathPlan(home, cwd = process.cwd(), env = process.env) {
|
|
35716
35724
|
for (const key2 of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
|
|
@@ -35761,7 +35769,7 @@ function selectedConfigDirectory(plan) {
|
|
|
35761
35769
|
const canonical9 = plan.roots.config, legacy = plan.legacyRoots.config;
|
|
35762
35770
|
if (legacy === null)
|
|
35763
35771
|
return existsSync8(canonical9) ? realpathSync7(canonical9) : canonical9;
|
|
35764
|
-
const canonicalStat =
|
|
35772
|
+
const canonicalStat = lstatSync19(canonical9, { throwIfNoEntry: false }), legacyStat = lstatSync19(legacy, { throwIfNoEntry: false });
|
|
35765
35773
|
if (canonicalStat && legacyStat && realpathSync7(canonical9) !== realpathSync7(legacy))
|
|
35766
35774
|
throw new Error("Sumi config roots conflict; complete native home adoption before Skills integration");
|
|
35767
35775
|
const selected = canonicalStat ? canonical9 : legacyStat ? legacy : canonical9;
|
|
@@ -35776,7 +35784,7 @@ function sumiConfigDirectory(home, env = process.env, cwd = process.cwd()) {
|
|
|
35776
35784
|
return selectedConfigDirectory(sumiPathPlan(home, cwd, env));
|
|
35777
35785
|
}
|
|
35778
35786
|
function sumiConfigPath(home, cwd = process.cwd(), env = process.env) {
|
|
35779
|
-
return
|
|
35787
|
+
return join24(sumiConfigDirectory(home, env, cwd), "sumi.json");
|
|
35780
35788
|
}
|
|
35781
35789
|
var SUMI_PATH_SELECTORS, SUMI_PATH_KEYS, SUMI_PATH_OUTPUT_LIMIT, SumiPathResolverError;
|
|
35782
35790
|
var init_agent_sumi = __esm(() => {
|
|
@@ -35795,9 +35803,9 @@ var init_agent_sumi = __esm(() => {
|
|
|
35795
35803
|
});
|
|
35796
35804
|
|
|
35797
35805
|
// src/lib/codex-hook-trust-files.ts
|
|
35798
|
-
import { closeSync as closeSync15, constants as constants13, fstatSync as fstatSync15, fsyncSync as fsyncSync3, lstatSync as
|
|
35806
|
+
import { closeSync as closeSync15, constants as constants13, fstatSync as fstatSync15, fsyncSync as fsyncSync3, lstatSync as lstatSync20, openSync as openSync15, readlinkSync as readlinkSync4, readSync as readSync9, writeFileSync as writeFileSync4 } from "fs";
|
|
35799
35807
|
import { createHash as createHash20 } from "crypto";
|
|
35800
|
-
import { dirname as
|
|
35808
|
+
import { dirname as dirname18, isAbsolute as isAbsolute17, resolve as resolve17 } from "path";
|
|
35801
35809
|
function need8(value, code) {
|
|
35802
35810
|
if (!value)
|
|
35803
35811
|
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
@@ -35806,18 +35814,18 @@ function trustedAncestorOwner(uid2) {
|
|
|
35806
35814
|
return BigInt(uid2) === 0n || BigInt(uid2) === BigInt(process.getuid());
|
|
35807
35815
|
}
|
|
35808
35816
|
function safeParents(file2) {
|
|
35809
|
-
for (let p =
|
|
35810
|
-
const s =
|
|
35817
|
+
for (let p = dirname18(file2);; p = dirname18(p)) {
|
|
35818
|
+
const s = lstatSync20(p);
|
|
35811
35819
|
need8(s.isDirectory() && !s.isSymbolicLink() && trustedAncestorOwner(s.uid), "UNSAFE_PARENT");
|
|
35812
35820
|
need8((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
35813
|
-
if (
|
|
35821
|
+
if (dirname18(p) === p)
|
|
35814
35822
|
break;
|
|
35815
35823
|
}
|
|
35816
35824
|
}
|
|
35817
35825
|
function snapshot(file2, privateFile = false, options = {}) {
|
|
35818
35826
|
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
35819
35827
|
safeParents(file2);
|
|
35820
|
-
const initial =
|
|
35828
|
+
const initial = lstatSync20(file2, { bigint: true });
|
|
35821
35829
|
need8(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");
|
|
35822
35830
|
need8(initial.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
35823
35831
|
const fd = openSync15(file2, constants13.O_RDONLY | constants13.O_NOFOLLOW | constants13.O_NONBLOCK);
|
|
@@ -35832,7 +35840,7 @@ function snapshot(file2, privateFile = false, options = {}) {
|
|
|
35832
35840
|
break;
|
|
35833
35841
|
length += n2;
|
|
35834
35842
|
}
|
|
35835
|
-
need8(length === Number(before.size) && sameStat(before, fstatSync15(fd, { bigint: true })) && sameStat(before,
|
|
35843
|
+
need8(length === Number(before.size) && sameStat(before, fstatSync15(fd, { bigint: true })) && sameStat(before, lstatSync20(file2, { bigint: true })), "INPUT_CHANGED");
|
|
35836
35844
|
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
35837
35845
|
return { file: file2, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash20("sha256").update(content).digest("hex") };
|
|
35838
35846
|
} finally {
|
|
@@ -35899,25 +35907,25 @@ var init_runtime_launcher = __esm(() => {
|
|
|
35899
35907
|
|
|
35900
35908
|
// src/lib/retained-review-artifacts.ts
|
|
35901
35909
|
import { createHash as createHash21 } from "crypto";
|
|
35902
|
-
import { constants as constants14, closeSync as closeSync16, fstatSync as fstatSync16, fsyncSync as fsyncSync4, lstatSync as
|
|
35903
|
-
import { dirname as
|
|
35910
|
+
import { constants as constants14, closeSync as closeSync16, fstatSync as fstatSync16, fsyncSync as fsyncSync4, lstatSync as lstatSync21, mkdirSync as mkdirSync6, openSync as openSync16, readSync as readSync10, writeSync as writeSync3 } from "fs";
|
|
35911
|
+
import { dirname as dirname19, isAbsolute as isAbsolute18, join as join25, resolve as resolve18, sep as sep10 } from "path";
|
|
35904
35912
|
function keys(value, names) {
|
|
35905
35913
|
return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === names.length && names.every((name) => Object.hasOwn(value, name)));
|
|
35906
35914
|
}
|
|
35907
35915
|
function safe4(path) {
|
|
35908
35916
|
need9(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute18(path) && resolve18(path) === path && !/[\x00-\x1f\x7f]/.test(path));
|
|
35909
|
-
for (let cursor = path;; cursor =
|
|
35910
|
-
const stat2 =
|
|
35917
|
+
for (let cursor = path;; cursor = dirname19(cursor)) {
|
|
35918
|
+
const stat2 = lstatSync21(cursor, { throwIfNoEntry: false });
|
|
35911
35919
|
need9(!stat2?.isSymbolicLink());
|
|
35912
35920
|
if (cursor !== path && stat2)
|
|
35913
35921
|
need9(stat2.isDirectory());
|
|
35914
|
-
if (
|
|
35922
|
+
if (dirname19(cursor) === cursor)
|
|
35915
35923
|
break;
|
|
35916
35924
|
}
|
|
35917
35925
|
}
|
|
35918
35926
|
function readExact(path) {
|
|
35919
35927
|
safe4(path);
|
|
35920
|
-
const before =
|
|
35928
|
+
const before = lstatSync21(path, { throwIfNoEntry: false });
|
|
35921
35929
|
need9(before?.isFile() && before.nlink === 1 && before.size <= AGENT_POLICY_LIMITS.discoveryRawSourceBytes && (before.mode & 63) === 0 && (process.getuid === undefined || before.uid === process.getuid()));
|
|
35922
35930
|
const fd = openSync16(path, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
|
|
35923
35931
|
try {
|
|
@@ -35931,7 +35939,7 @@ function readExact(path) {
|
|
|
35931
35939
|
offset += count;
|
|
35932
35940
|
}
|
|
35933
35941
|
need9(readSync10(fd, Buffer.alloc(1), 0, 1, null) === 0);
|
|
35934
|
-
const after = fstatSync16(fd), current =
|
|
35942
|
+
const after = fstatSync16(fd), current = lstatSync21(path, { throwIfNoEntry: false });
|
|
35935
35943
|
safe4(path);
|
|
35936
35944
|
need9(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);
|
|
35937
35945
|
const text2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
@@ -35948,20 +35956,20 @@ function catalogDigest(text2) {
|
|
|
35948
35956
|
} catch {
|
|
35949
35957
|
return refuse4();
|
|
35950
35958
|
}
|
|
35951
|
-
need9(catalog && typeof catalog === "object" && !Array.isArray(catalog) && Object.keys(catalog).every((key2) => ["version", "cwd", "skills", "plugins"].includes(key2)) && typeof catalog.version === "string" && supportsCodexNativeCapability(catalog.version, "installed-plugin-review"));
|
|
35959
|
+
need9(catalog && typeof catalog === "object" && !Array.isArray(catalog) && Object.keys(catalog).every((key2) => ["version", "cwd", "skills", "plugins", "remoteReceipts"].includes(key2)) && typeof catalog.version === "string" && supportsCodexNativeCapability(catalog.version, "installed-plugin-review"));
|
|
35952
35960
|
const skills = projectCodexNativeSkillCatalog({ data: [{ cwd: catalog.cwd, errors: [], skills: catalog.skills }] }, catalog.cwd);
|
|
35953
35961
|
const plugins = catalog.plugins === undefined ? undefined : projectCodexInstalledPluginEntries(catalog.plugins);
|
|
35954
35962
|
return sha3(JSON.stringify({ version: catalog.version, cwd: catalog.cwd, skills, ...plugins === undefined ? {} : { plugins } }));
|
|
35955
35963
|
}
|
|
35956
35964
|
function retainedArtifactPath(metadata) {
|
|
35957
|
-
return
|
|
35965
|
+
return join25(metadata.storeRoot, "agent-discovery", "artifacts", metadata.sha256, "catalog.json");
|
|
35958
35966
|
}
|
|
35959
35967
|
function validRetainedArtifact(value) {
|
|
35960
35968
|
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" && isAbsolute18(path) && resolve18(path) === path && path.length <= AGENT_POLICY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(path));
|
|
35961
35969
|
}
|
|
35962
35970
|
function privateStore(storeRoot) {
|
|
35963
35971
|
safe4(storeRoot);
|
|
35964
|
-
const stat2 =
|
|
35972
|
+
const stat2 = lstatSync21(storeRoot, { throwIfNoEntry: false });
|
|
35965
35973
|
need9(!stat2 || stat2.isDirectory() && (stat2.mode & 18) === 0 && (process.getuid === undefined || stat2.uid === process.getuid()));
|
|
35966
35974
|
}
|
|
35967
35975
|
function verifyRetainedReviewArtifact(source, storeRoot) {
|
|
@@ -35970,8 +35978,8 @@ function verifyRetainedReviewArtifact(source, storeRoot) {
|
|
|
35970
35978
|
privateStore(artifact.storeRoot);
|
|
35971
35979
|
const text2 = readExact(source.path);
|
|
35972
35980
|
need9(sha3(text2) === artifact.sha256 && catalogDigest(text2) === artifact.catalogSha256);
|
|
35973
|
-
for (let parent =
|
|
35974
|
-
const stat2 =
|
|
35981
|
+
for (let parent = dirname19(source.path);parent !== artifact.storeRoot; parent = dirname19(parent)) {
|
|
35982
|
+
const stat2 = lstatSync21(parent);
|
|
35975
35983
|
need9(stat2.isDirectory() && (stat2.mode & 63) === 0 && (process.getuid === undefined || stat2.uid === process.getuid()));
|
|
35976
35984
|
}
|
|
35977
35985
|
}
|
|
@@ -35991,6 +35999,8 @@ var init_retained_review_artifacts = __esm(() => {
|
|
|
35991
35999
|
var init_agent_integration = __esm(() => {
|
|
35992
36000
|
init_sumi_settings_witness();
|
|
35993
36001
|
init_codex_corpus_write();
|
|
36002
|
+
init_codex_hook_rpc();
|
|
36003
|
+
init_codex_native_config();
|
|
35994
36004
|
init_codex_plugin_skill_controls();
|
|
35995
36005
|
init_codex_native_skill_policy();
|
|
35996
36006
|
init_codex_native_skill_catalog();
|
|
@@ -36050,20 +36060,20 @@ var init_skill_aliases = __esm(() => {
|
|
|
36050
36060
|
});
|
|
36051
36061
|
|
|
36052
36062
|
// src/lib/project-state.ts
|
|
36053
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as
|
|
36054
|
-
import { join as
|
|
36063
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync15, writeFileSync as writeFileSync5 } from "fs";
|
|
36064
|
+
import { join as join26 } from "path";
|
|
36055
36065
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
36056
|
-
return
|
|
36066
|
+
return join26(targetDir, SKILLS_PROJECT_DIR);
|
|
36057
36067
|
}
|
|
36058
36068
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
36059
|
-
return
|
|
36069
|
+
return join26(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
36060
36070
|
}
|
|
36061
36071
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
36062
36072
|
const path = getProjectConfigPath(targetDir);
|
|
36063
36073
|
if (!existsSync9(path))
|
|
36064
36074
|
return null;
|
|
36065
36075
|
try {
|
|
36066
|
-
return normalizeProjectConfig(JSON.parse(
|
|
36076
|
+
return normalizeProjectConfig(JSON.parse(readFileSync15(path, "utf-8")));
|
|
36067
36077
|
} catch {
|
|
36068
36078
|
return null;
|
|
36069
36079
|
}
|
|
@@ -36171,8 +36181,8 @@ var init_project_state = __esm(() => {
|
|
|
36171
36181
|
});
|
|
36172
36182
|
|
|
36173
36183
|
// src/lib/installer.ts
|
|
36174
|
-
import { existsSync as existsSync10, readFileSync as
|
|
36175
|
-
import { join as
|
|
36184
|
+
import { existsSync as existsSync10, readFileSync as readFileSync16, rmSync as rmSync2 } from "fs";
|
|
36185
|
+
import { join as join27 } from "path";
|
|
36176
36186
|
import { homedir as homedir2 } from "os";
|
|
36177
36187
|
function getSkillPath(name) {
|
|
36178
36188
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
@@ -36182,7 +36192,7 @@ function getSkillPath(name) {
|
|
|
36182
36192
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
36183
36193
|
if (extensionPath)
|
|
36184
36194
|
return extensionPath;
|
|
36185
|
-
return
|
|
36195
|
+
return join27(getPortableSkillsRoot(), skillName);
|
|
36186
36196
|
}
|
|
36187
36197
|
function getCanonicalSkillName(name) {
|
|
36188
36198
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
@@ -36236,11 +36246,11 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
36236
36246
|
const base = projectDir || process.cwd();
|
|
36237
36247
|
switch (agent) {
|
|
36238
36248
|
case "pi":
|
|
36239
|
-
return scope === "project" ?
|
|
36249
|
+
return scope === "project" ? join27(base, ".pi", "skills") : join27(homedir2(), ".pi", "agent", "skills");
|
|
36240
36250
|
case "opencode":
|
|
36241
|
-
return scope === "project" ?
|
|
36251
|
+
return scope === "project" ? join27(base, ".opencode", "skills") : join27(homedir2(), ".config", "opencode", "skills");
|
|
36242
36252
|
default:
|
|
36243
|
-
return scope === "project" ?
|
|
36253
|
+
return scope === "project" ? join27(base, `.${agent}`, "skills") : join27(homedir2(), `.${agent}`, "skills");
|
|
36244
36254
|
}
|
|
36245
36255
|
}
|
|
36246
36256
|
function warnMissingDependencies(name, targetDir) {
|
|
@@ -36255,11 +36265,11 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
36255
36265
|
}
|
|
36256
36266
|
}
|
|
36257
36267
|
function readBundledSkillVersion(name) {
|
|
36258
|
-
const pkgPath =
|
|
36268
|
+
const pkgPath = join27(getSkillPath(name), "package.json");
|
|
36259
36269
|
if (!existsSync10(pkgPath))
|
|
36260
36270
|
return "unknown";
|
|
36261
36271
|
try {
|
|
36262
|
-
const pkg = JSON.parse(
|
|
36272
|
+
const pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
|
|
36263
36273
|
return pkg.version || "unknown";
|
|
36264
36274
|
} catch {
|
|
36265
36275
|
return "unknown";
|
|
@@ -36324,16 +36334,16 @@ var init_skill_doc_file = __esm(() => {
|
|
|
36324
36334
|
});
|
|
36325
36335
|
|
|
36326
36336
|
// src/lib/skillinfo.ts
|
|
36327
|
-
import { existsSync as existsSync11, readFileSync as
|
|
36328
|
-
import { join as
|
|
36337
|
+
import { existsSync as existsSync11, readFileSync as readFileSync17 } from "fs";
|
|
36338
|
+
import { join as join28 } from "path";
|
|
36329
36339
|
function isInstructionSkillDir(skillPath, meta3) {
|
|
36330
36340
|
if (meta3?.kind === "instruction")
|
|
36331
36341
|
return true;
|
|
36332
|
-
const skillMdPath =
|
|
36342
|
+
const skillMdPath = join28(skillPath, "SKILL.md");
|
|
36333
36343
|
if (!existsSync11(skillMdPath))
|
|
36334
36344
|
return false;
|
|
36335
36345
|
try {
|
|
36336
|
-
return parseSkillFrontmatter(
|
|
36346
|
+
return parseSkillFrontmatter(readFileSync17(skillMdPath, "utf-8"))?.kind === "instruction";
|
|
36337
36347
|
} catch {
|
|
36338
36348
|
return false;
|
|
36339
36349
|
}
|
|
@@ -36343,9 +36353,9 @@ function getSkillDocs(name) {
|
|
|
36343
36353
|
if (!existsSync11(skillPath))
|
|
36344
36354
|
return null;
|
|
36345
36355
|
return {
|
|
36346
|
-
skillMd: readIfExists(
|
|
36347
|
-
readme: readIfExists(
|
|
36348
|
-
claudeMd: readIfExists(
|
|
36356
|
+
skillMd: readIfExists(join28(skillPath, "SKILL.md")),
|
|
36357
|
+
readme: readIfExists(join28(skillPath, "README.md")),
|
|
36358
|
+
claudeMd: readIfExists(join28(skillPath, "CLAUDE.md"))
|
|
36349
36359
|
};
|
|
36350
36360
|
}
|
|
36351
36361
|
function getSkillBestDoc(name, file2) {
|
|
@@ -36361,14 +36371,14 @@ function getSkillRequirements(name) {
|
|
|
36361
36371
|
return null;
|
|
36362
36372
|
const texts = [];
|
|
36363
36373
|
for (const file2 of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
36364
|
-
const content = readIfExists(
|
|
36374
|
+
const content = readIfExists(join28(skillPath, file2));
|
|
36365
36375
|
if (content)
|
|
36366
36376
|
texts.push(content);
|
|
36367
36377
|
}
|
|
36368
36378
|
const meta3 = getSkill(name);
|
|
36369
36379
|
let dependencies = {};
|
|
36370
36380
|
try {
|
|
36371
|
-
dependencies = JSON.parse(
|
|
36381
|
+
dependencies = JSON.parse(readFileSync17(join28(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
36372
36382
|
} catch {}
|
|
36373
36383
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta3);
|
|
36374
36384
|
}
|
|
@@ -36430,13 +36440,13 @@ async function runSkill(name, args, options = {}) {
|
|
|
36430
36440
|
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'.`
|
|
36431
36441
|
};
|
|
36432
36442
|
}
|
|
36433
|
-
const pkgPath =
|
|
36443
|
+
const pkgPath = join28(skillPath, "package.json");
|
|
36434
36444
|
if (!existsSync11(pkgPath)) {
|
|
36435
36445
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
36436
36446
|
}
|
|
36437
36447
|
let entryPoint2;
|
|
36438
36448
|
try {
|
|
36439
|
-
const pkg = JSON.parse(
|
|
36449
|
+
const pkg = JSON.parse(readFileSync17(pkgPath, "utf-8"));
|
|
36440
36450
|
if (pkg.bin) {
|
|
36441
36451
|
const binValues = Object.values(pkg.bin);
|
|
36442
36452
|
entryPoint2 = binValues[0];
|
|
@@ -36450,12 +36460,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
36450
36460
|
} catch {
|
|
36451
36461
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
36452
36462
|
}
|
|
36453
|
-
const entryPath =
|
|
36463
|
+
const entryPath = join28(skillPath, entryPoint2);
|
|
36454
36464
|
if (!existsSync11(entryPath)) {
|
|
36455
36465
|
return { exitCode: 1, error: `Entry point '${entryPoint2}' not found in skill '${name}'` };
|
|
36456
36466
|
}
|
|
36457
36467
|
const env = { ...process.env, ...options.env };
|
|
36458
|
-
if (!existsSync11(
|
|
36468
|
+
if (!existsSync11(join28(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
|
|
36459
36469
|
const failure = await prepareSkillDependencies(skillPath, env, options.preparationTimeoutMs);
|
|
36460
36470
|
if (failure)
|
|
36461
36471
|
return failure;
|
|
@@ -36481,7 +36491,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
36481
36491
|
function detectProjectSkills(cwd = process.cwd()) {
|
|
36482
36492
|
let pkg;
|
|
36483
36493
|
try {
|
|
36484
|
-
pkg = JSON.parse(
|
|
36494
|
+
pkg = JSON.parse(readFileSync17(join28(cwd, "package.json"), "utf8"));
|
|
36485
36495
|
} catch {
|
|
36486
36496
|
return { detected: [], recommended: [] };
|
|
36487
36497
|
}
|
|
@@ -36518,7 +36528,7 @@ function extractEnvVars(text2) {
|
|
|
36518
36528
|
function readIfExists(path) {
|
|
36519
36529
|
try {
|
|
36520
36530
|
if (existsSync11(path)) {
|
|
36521
|
-
return
|
|
36531
|
+
return readFileSync17(path, "utf-8");
|
|
36522
36532
|
}
|
|
36523
36533
|
} catch {}
|
|
36524
36534
|
return null;
|
|
@@ -36846,7 +36856,7 @@ var init_selected_manifest = __esm(() => {
|
|
|
36846
36856
|
});
|
|
36847
36857
|
|
|
36848
36858
|
// src/lib/plugin-admission.ts
|
|
36849
|
-
import { isAbsolute as isAbsolute19, join as
|
|
36859
|
+
import { isAbsolute as isAbsolute19, join as join29, resolve as resolve19 } from "path";
|
|
36850
36860
|
function validatePluginTarget(value) {
|
|
36851
36861
|
pluginKeys(value, ["schemaVersion", "pluginId", "registrations", "native", "resolver"]);
|
|
36852
36862
|
pluginNeed(value.schemaVersion === 1, "Invalid plugin admission target");
|
|
@@ -37007,12 +37017,12 @@ function pluginResolverCommand(binding) {
|
|
|
37007
37017
|
}
|
|
37008
37018
|
function pluginBindingPath(storeRoot, id) {
|
|
37009
37019
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
37010
|
-
return
|
|
37020
|
+
return join29(storeRoot, "bindings", `${id}.json`);
|
|
37011
37021
|
}
|
|
37012
37022
|
function pluginReceiptPath(storeRoot, id, digest2) {
|
|
37013
37023
|
pluginNeed(/^[a-f0-9]{64}$/.test(id), "Invalid plugin binding identifier");
|
|
37014
37024
|
pluginDigest(digest2);
|
|
37015
|
-
return
|
|
37025
|
+
return join29(storeRoot, "receipts", id, `${digest2.slice(7)}.json`);
|
|
37016
37026
|
}
|
|
37017
37027
|
function readPluginBinding(storeRoot, id) {
|
|
37018
37028
|
const value = readPluginJson(pluginBindingPath(storeRoot, id));
|
|
@@ -37032,7 +37042,7 @@ function readPluginAdmissionReceipt(storeRoot, id, digest2) {
|
|
|
37032
37042
|
pluginNeed(receipt.plan.bindingId === id && receipt.plan.planDigest === digest2, "Plugin receipt identity differs from its filename");
|
|
37033
37043
|
const binding = readPluginBinding(storeRoot, id);
|
|
37034
37044
|
pluginNeed(canonicalJson(binding) === canonicalJson(receipt.plan.binding) && receipt.plan.sourceCommand === pluginResolverCommand(binding), "Plugin receipt binding changed");
|
|
37035
|
-
pluginNeed(receipt.materializedPath ===
|
|
37045
|
+
pluginNeed(receipt.materializedPath === join29(storeRoot, "objects", id, digest2.slice(7)), "Plugin receipt points outside its immutable materialization");
|
|
37036
37046
|
pluginText(receipt.admittedAt, 64);
|
|
37037
37047
|
pluginNeed(Number.isFinite(Date.parse(receipt.admittedAt)), "Invalid plugin admission time");
|
|
37038
37048
|
return receipt;
|
|
@@ -37049,8 +37059,8 @@ var init_plugin_admission = __esm(() => {
|
|
|
37049
37059
|
});
|
|
37050
37060
|
|
|
37051
37061
|
// src/lib/plugin-discovery.ts
|
|
37052
|
-
import { closeSync as closeSync17, constants as constants15, fstatSync as fstatSync17, lstatSync as
|
|
37053
|
-
import { basename as
|
|
37062
|
+
import { closeSync as closeSync17, constants as constants15, fstatSync as fstatSync17, lstatSync as lstatSync22, openSync as openSync17, opendirSync as opendirSync3, readSync as readSync11 } from "fs";
|
|
37063
|
+
import { basename as basename11, dirname as dirname20, isAbsolute as isAbsolute20, join as join30, resolve as resolve20 } from "path";
|
|
37054
37064
|
function validateManagedPluginWitnesses(value) {
|
|
37055
37065
|
pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
|
|
37056
37066
|
const seen = new Set;
|
|
@@ -37065,15 +37075,15 @@ function validateManagedPluginWitnesses(value) {
|
|
|
37065
37075
|
function safe5(path) {
|
|
37066
37076
|
pluginText(path);
|
|
37067
37077
|
pluginNeed(isAbsolute20(path) && resolve20(path) === path, "Invalid plugin registry path");
|
|
37068
|
-
for (let at = path;; at =
|
|
37069
|
-
pluginNeed(!
|
|
37070
|
-
if (at ===
|
|
37078
|
+
for (let at = path;; at = dirname20(at)) {
|
|
37079
|
+
pluginNeed(!lstatSync22(at, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
37080
|
+
if (at === dirname20(at))
|
|
37071
37081
|
break;
|
|
37072
37082
|
}
|
|
37073
37083
|
}
|
|
37074
37084
|
function readRegistry(path) {
|
|
37075
37085
|
safe5(path);
|
|
37076
|
-
const initial =
|
|
37086
|
+
const initial = lstatSync22(path);
|
|
37077
37087
|
pluginNeed(initial.isFile() && initial.size <= 1024 * 1024, "Plugin registry is not a bounded regular file");
|
|
37078
37088
|
const fd = openSync17(path, constants15.O_RDONLY | constants15.O_NOFOLLOW | constants15.O_NONBLOCK);
|
|
37079
37089
|
try {
|
|
@@ -37087,7 +37097,7 @@ function readRegistry(path) {
|
|
|
37087
37097
|
break;
|
|
37088
37098
|
length += count;
|
|
37089
37099
|
}
|
|
37090
|
-
const after = fstatSync17(fd), current =
|
|
37100
|
+
const after = fstatSync17(fd), current = lstatSync22(path);
|
|
37091
37101
|
safe5(path);
|
|
37092
37102
|
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");
|
|
37093
37103
|
let value;
|
|
@@ -37117,7 +37127,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
37117
37127
|
seen.add(target.pluginId);
|
|
37118
37128
|
const rows = plugins[target.pluginId];
|
|
37119
37129
|
pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
|
|
37120
|
-
const [name, market] = target.pluginId.split("@"), cacheRoot =
|
|
37130
|
+
const [name, market] = target.pluginId.split("@"), cacheRoot = join30(dirname20(path), "cache", market, name);
|
|
37121
37131
|
const scopes = new Set, approvals = new Map, currentFiles = new Map;
|
|
37122
37132
|
plugins[target.pluginId] = rows.map((row) => {
|
|
37123
37133
|
pluginNeed(pluginObject(row), "Invalid managed plugin registration");
|
|
@@ -37130,10 +37140,10 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
37130
37140
|
pluginText(row.sourceProducerPath);
|
|
37131
37141
|
pluginText(row.lastUpdated, 64);
|
|
37132
37142
|
pluginNeed(Number.isFinite(Date.parse(row.lastUpdated)), "Invalid managed plugin update timestamp");
|
|
37133
|
-
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath ===
|
|
37143
|
+
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join30(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
37134
37144
|
const approval = (producer) => {
|
|
37135
37145
|
pluginText(producer);
|
|
37136
|
-
const digest2 = `sha256:${
|
|
37146
|
+
const digest2 = `sha256:${basename11(producer)}`;
|
|
37137
37147
|
const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest2);
|
|
37138
37148
|
pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
|
|
37139
37149
|
if (!verified.has(producer)) {
|
|
@@ -37160,7 +37170,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
37160
37170
|
return Object.fromEntries(Object.entries(row).filter(([key2]) => !["version", "installPath", "sourceProducerPath", "previousProducerPaths", "lastUpdated"].includes(key2)));
|
|
37161
37171
|
});
|
|
37162
37172
|
safe5(cacheRoot);
|
|
37163
|
-
const before =
|
|
37173
|
+
const before = lstatSync22(cacheRoot);
|
|
37164
37174
|
pluginNeed(before.isDirectory(), "Invalid managed plugin cache root");
|
|
37165
37175
|
const directory = opendirSync3(cacheRoot), names = [];
|
|
37166
37176
|
try {
|
|
@@ -37173,17 +37183,17 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
37173
37183
|
directory.closeSync();
|
|
37174
37184
|
}
|
|
37175
37185
|
for (const version2 of names.sort()) {
|
|
37176
|
-
const files = pluginFileWitnesses(snapshotPluginTree(
|
|
37186
|
+
const files = pluginFileWitnesses(snapshotPluginTree(join30(cacheRoot, version2), { nativeRuntime: `claude-${target.native.version}` }));
|
|
37177
37187
|
verifiedBytes += files.reduce((total, file2) => total + file2.size, 0);
|
|
37178
37188
|
pluginNeed(verifiedBytes <= 256 * 1024 * 1024, "Managed plugin verification exceeds its aggregate byte budget");
|
|
37179
37189
|
const serialized = JSON.stringify(files);
|
|
37180
|
-
const expected = currentFiles.get(
|
|
37190
|
+
const expected = currentFiles.get(join30(cacheRoot, version2));
|
|
37181
37191
|
pluginNeed(expected === undefined || serialized === expected, "Current native cache differs from its exact registered producer receipt");
|
|
37182
37192
|
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");
|
|
37183
37193
|
}
|
|
37184
37194
|
for (const row of rows)
|
|
37185
37195
|
pluginNeed(names.includes(row.version), "Managed native plugin installation is missing");
|
|
37186
|
-
const after =
|
|
37196
|
+
const after = lstatSync22(cacheRoot);
|
|
37187
37197
|
safe5(cacheRoot);
|
|
37188
37198
|
pluginNeed(before.dev === after.dev && before.ino === after.ino && before.mtimeMs === after.mtimeMs && before.ctimeMs === after.ctimeMs, "Managed cache version membership changed during verification");
|
|
37189
37199
|
}
|
|
@@ -37198,8 +37208,8 @@ var init_plugin_discovery = __esm(() => {
|
|
|
37198
37208
|
|
|
37199
37209
|
// src/lib/claude-marketplace-registry.ts
|
|
37200
37210
|
import { createHash as createHash22 } from "crypto";
|
|
37201
|
-
import { closeSync as closeSync18, constants as constants16, fstatSync as fstatSync18, lstatSync as
|
|
37202
|
-
import { basename as
|
|
37211
|
+
import { closeSync as closeSync18, constants as constants16, fstatSync as fstatSync18, lstatSync as lstatSync23, openSync as openSync18, readSync as readSync12 } from "fs";
|
|
37212
|
+
import { basename as basename12, dirname as dirname21, isAbsolute as isAbsolute21, resolve as resolve21 } from "path";
|
|
37203
37213
|
function need10(value, reason2) {
|
|
37204
37214
|
if (!value)
|
|
37205
37215
|
throw new Error(`Claude marketplace registry ${reason2}`);
|
|
@@ -37209,19 +37219,19 @@ function absolutePath4(value) {
|
|
|
37209
37219
|
}
|
|
37210
37220
|
function parents2(path) {
|
|
37211
37221
|
const result = [];
|
|
37212
|
-
for (let at =
|
|
37213
|
-
const stat2 =
|
|
37222
|
+
for (let at = dirname21(path);; at = dirname21(at)) {
|
|
37223
|
+
const stat2 = lstatSync23(at, { bigint: true });
|
|
37214
37224
|
need10(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
37215
37225
|
result.push([at, stat2]);
|
|
37216
|
-
if (at ===
|
|
37226
|
+
if (at === dirname21(at))
|
|
37217
37227
|
return result;
|
|
37218
37228
|
}
|
|
37219
37229
|
}
|
|
37220
37230
|
function readRegistry2(path, budget2) {
|
|
37221
37231
|
absolutePath4(path);
|
|
37222
|
-
need10(
|
|
37232
|
+
need10(basename12(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
37223
37233
|
need10(Number.isSafeInteger(budget2.remaining) && budget2.remaining >= 0, "has an invalid byte budget");
|
|
37224
|
-
const ancestors2 = parents2(path), initial =
|
|
37234
|
+
const ancestors2 = parents2(path), initial = lstatSync23(path, { bigint: true });
|
|
37225
37235
|
need10(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
37226
37236
|
need10(initial.size <= BigInt(budget2.remaining), "exceeds its aggregate byte limit");
|
|
37227
37237
|
const fd = openSync18(path, constants16.O_RDONLY | constants16.O_NOFOLLOW | constants16.O_NONBLOCK);
|
|
@@ -37236,10 +37246,10 @@ function readRegistry2(path, budget2) {
|
|
|
37236
37246
|
break;
|
|
37237
37247
|
length += count;
|
|
37238
37248
|
}
|
|
37239
|
-
const after = fstatSync18(fd, { bigint: true }), current =
|
|
37249
|
+
const after = fstatSync18(fd, { bigint: true }), current = lstatSync23(path, { bigint: true });
|
|
37240
37250
|
need10(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
37241
37251
|
for (const [ancestor, before] of ancestors2) {
|
|
37242
|
-
const now =
|
|
37252
|
+
const now = lstatSync23(ancestor, { bigint: true });
|
|
37243
37253
|
need10(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
37244
37254
|
}
|
|
37245
37255
|
budget2.remaining -= length;
|
|
@@ -37426,8 +37436,8 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
37426
37436
|
|
|
37427
37437
|
// src/lib/agent-discovery.ts
|
|
37428
37438
|
import { createHash as createHash24 } from "crypto";
|
|
37429
|
-
import { lstatSync as
|
|
37430
|
-
import { basename as
|
|
37439
|
+
import { lstatSync as lstatSync24, readFileSync as readFileSync18, readdirSync as readdirSync9, realpathSync as realpathSync8 } from "fs";
|
|
37440
|
+
import { basename as basename13, dirname as dirname22, isAbsolute as isAbsolute22, join as join31, relative as relative7, resolve as resolve22, sep as sep11 } from "path";
|
|
37431
37441
|
import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
|
|
37432
37442
|
function discoveryExecutable(agent) {
|
|
37433
37443
|
const command = DISCOVERY_RUNTIME_COMMANDS[agent];
|
|
@@ -37450,10 +37460,10 @@ function parseConfig(text2, path, toml = false) {
|
|
|
37450
37460
|
function safe6(path) {
|
|
37451
37461
|
if (!isAbsolute22(path) || path.includes("\x00"))
|
|
37452
37462
|
throw new Error("Expected an absolute native discovery path");
|
|
37453
|
-
for (let cursor = path;; cursor =
|
|
37454
|
-
if (
|
|
37463
|
+
for (let cursor = path;; cursor = dirname22(cursor)) {
|
|
37464
|
+
if (lstatSync24(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
37455
37465
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
37456
|
-
if (
|
|
37466
|
+
if (dirname22(cursor) === cursor)
|
|
37457
37467
|
break;
|
|
37458
37468
|
}
|
|
37459
37469
|
}
|
|
@@ -37461,19 +37471,19 @@ function read(path, changes) {
|
|
|
37461
37471
|
safe6(path);
|
|
37462
37472
|
if (changes?.has(path))
|
|
37463
37473
|
return changes.get(path);
|
|
37464
|
-
const stat2 =
|
|
37474
|
+
const stat2 = lstatSync24(path, { throwIfNoEntry: false });
|
|
37465
37475
|
if (!stat2)
|
|
37466
37476
|
return null;
|
|
37467
37477
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
37468
37478
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
37469
|
-
return
|
|
37479
|
+
return readFileSync18(path, "utf8");
|
|
37470
37480
|
}
|
|
37471
37481
|
function assertReviewedClaudeCacheClosures(home, config2, review, canonical9) {
|
|
37472
37482
|
const enabledIds = Object.entries(config2.enabledPlugins ?? {}).filter(([, enabled]) => enabled === true).map(([id]) => id);
|
|
37473
37483
|
if (enabledIds.length === 0)
|
|
37474
37484
|
return;
|
|
37475
|
-
const registryPath = canonical9(
|
|
37476
|
-
const cacheAliasRoot =
|
|
37485
|
+
const registryPath = canonical9(join31(home, ".claude/plugins/installed_plugins.json"));
|
|
37486
|
+
const cacheAliasRoot = join31(home, ".claude/plugins/cache");
|
|
37477
37487
|
const cacheRoot = canonical9(cacheAliasRoot);
|
|
37478
37488
|
const registryText = read(registryPath);
|
|
37479
37489
|
if (registryText === null)
|
|
@@ -37494,7 +37504,7 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical9) {
|
|
|
37494
37504
|
throw new Error("Reviewed Claude enabled plugin registration requires an object with an installPath string");
|
|
37495
37505
|
}
|
|
37496
37506
|
if ([cacheAliasRoot, cacheRoot].some((root) => row.installPath === root || row.installPath.startsWith(root + sep11))) {
|
|
37497
|
-
if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" ||
|
|
37507
|
+
if (!cachePath(row.installPath) || row.installPath.length > AGENT_POLICY_LIMITS.pathCharacters || row.version !== undefined && (typeof row.version !== "string" || basename13(row.installPath) !== row.version)) {
|
|
37498
37508
|
throw new Error("Reviewed Claude discovery has a malformed active cache registration");
|
|
37499
37509
|
}
|
|
37500
37510
|
if (row.scope === "user" && (row.projectPath === undefined || row.projectPath === null)) {} else if (row.scope === "project" && typeof row.projectPath === "string" && isAbsolute22(row.projectPath) && resolve22(row.projectPath) === row.projectPath && row.projectPath.length <= AGENT_POLICY_LIMITS.pathCharacters) {} else
|
|
@@ -37515,11 +37525,11 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical9) {
|
|
|
37515
37525
|
};
|
|
37516
37526
|
for (const root of activeRoots) {
|
|
37517
37527
|
safe6(root);
|
|
37518
|
-
const rootStat =
|
|
37528
|
+
const rootStat = lstatSync24(root, { throwIfNoEntry: false });
|
|
37519
37529
|
if (!rootStat?.isDirectory() || realpathSync8(root) !== root)
|
|
37520
37530
|
throw new Error("Reviewed Claude active cache plugin root is missing or unsafe");
|
|
37521
|
-
const manifestPath =
|
|
37522
|
-
const manifestStat =
|
|
37531
|
+
const manifestPath = join31(root, ".claude-plugin/plugin.json");
|
|
37532
|
+
const manifestStat = lstatSync24(manifestPath, { throwIfNoEntry: false });
|
|
37523
37533
|
let manifest;
|
|
37524
37534
|
if (manifestStat) {
|
|
37525
37535
|
if (!manifestStat.isFile())
|
|
@@ -37534,8 +37544,8 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical9) {
|
|
|
37534
37544
|
} 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)) {
|
|
37535
37545
|
throw new Error("Reviewed Claude active cache plugin manifest absence requires a path-bytes witness");
|
|
37536
37546
|
}
|
|
37537
|
-
const roots = new Set([
|
|
37538
|
-
if (
|
|
37547
|
+
const roots = new Set([join31(root, "skills")]);
|
|
37548
|
+
if (lstatSync24(join31(root, "SKILL.md"), { throwIfNoEntry: false })?.isFile())
|
|
37539
37549
|
roots.add(root);
|
|
37540
37550
|
const declared = manifest?.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
37541
37551
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
@@ -37544,13 +37554,13 @@ function assertReviewedClaudeCacheClosures(home, config2, review, canonical9) {
|
|
|
37544
37554
|
const path = resolve22(root, value);
|
|
37545
37555
|
if (path !== root && !path.startsWith(root + sep11))
|
|
37546
37556
|
throw new Error("Reviewed Claude active cache plugin skill path escapes its root");
|
|
37547
|
-
roots.add(path.endsWith(`${sep11}SKILL.md`) ?
|
|
37557
|
+
roots.add(path.endsWith(`${sep11}SKILL.md`) ? dirname22(path) : path);
|
|
37548
37558
|
}
|
|
37549
37559
|
for (const skillRoot of roots)
|
|
37550
37560
|
if (!review.roots.includes(skillRoot))
|
|
37551
37561
|
throw new Error("Reviewed Claude active cache plugin skill root is not covered");
|
|
37552
|
-
const hooksPath =
|
|
37553
|
-
const hooksStat =
|
|
37562
|
+
const hooksPath = join31(root, "hooks/hooks.json");
|
|
37563
|
+
const hooksStat = lstatSync24(hooksPath, { throwIfNoEntry: false });
|
|
37554
37564
|
if (hooksStat) {
|
|
37555
37565
|
if (!hooksStat.isFile())
|
|
37556
37566
|
throw new Error("Reviewed Claude plugin hook manifest is unsupported");
|
|
@@ -37688,18 +37698,18 @@ function absentCodexSkillRoots(binding, tolerance) {
|
|
|
37688
37698
|
return [];
|
|
37689
37699
|
if (binding.agent !== "codex" || !Array.isArray(controls) || controls.length > 4096)
|
|
37690
37700
|
throw new Error("Invalid disabled Codex discovery proof");
|
|
37691
|
-
if (binding.method !== "reviewed" || controls.every((control) =>
|
|
37701
|
+
if (binding.method !== "reviewed" || controls.every((control) => lstatSync24(control.pluginParent, { throwIfNoEntry: false })))
|
|
37692
37702
|
return [];
|
|
37693
|
-
const cache =
|
|
37703
|
+
const cache = dirname22(dirname22(controls[0].pluginParent)), config2 = join31(dirname22(dirname22(cache)), "config.toml");
|
|
37694
37704
|
const source = binding.sources.find((source2) => source2.path === config2 && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
37695
37705
|
if (!source || !codexConfigWitnessCurrent(source, tolerance))
|
|
37696
37706
|
throw new Error("Missing current disabled Codex configuration witness");
|
|
37697
37707
|
const rules = Bun.TOML.parse(read(config2)).skills?.config ?? [];
|
|
37698
37708
|
return [...new Set(controls.map((control) => control.pluginParent))].filter((parent) => !codexDirectHookSelects(cache, parent) && absentDisabledCodexPluginParent(cache, parent, controls, rules));
|
|
37699
37709
|
}
|
|
37700
|
-
function codexDirectHookSelects(cache, root, configPath =
|
|
37701
|
-
const codex =
|
|
37702
|
-
const hooks = read(
|
|
37710
|
+
function codexDirectHookSelects(cache, root, configPath = join31(dirname22(dirname22(cache)), "config.toml")) {
|
|
37711
|
+
const codex = dirname22(configPath), config2 = Bun.TOML.parse(read(configPath) ?? "");
|
|
37712
|
+
const hooks = read(join31(codex, "hooks.json"));
|
|
37703
37713
|
if (hooks !== null)
|
|
37704
37714
|
hashNativeJsonControls(hooks);
|
|
37705
37715
|
return JSON.stringify(config2.hooks ?? {}).includes(root) || hooks !== null && JSON.stringify(JSON.parse(hooks)).includes(root);
|
|
@@ -37711,7 +37721,7 @@ function retiredCodexRoots(binding, tolerance) {
|
|
|
37711
37721
|
const controls = binding.codexDisabledPluginSkills;
|
|
37712
37722
|
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)
|
|
37713
37723
|
throw new Error("Invalid retired Codex materialization proof");
|
|
37714
|
-
const cache =
|
|
37724
|
+
const cache = dirname22(dirname22(controls[0].pluginParent)), config2 = join31(dirname22(dirname22(cache)), "config.toml");
|
|
37715
37725
|
const source = binding.sources.find((source2) => source2.path === config2 && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
37716
37726
|
if (!source || !codexConfigWitnessCurrent(source, tolerance))
|
|
37717
37727
|
throw new Error("Missing current retired Codex configuration witness");
|
|
@@ -37719,7 +37729,7 @@ function retiredCodexRoots(binding, tolerance) {
|
|
|
37719
37729
|
if ((proof.parents ?? []).some((parent) => codexDirectHookSelects(cache, parent) || !reviewedDisabledCodexPluginParent(cache, parent, controls, rules)) || !reviewedCodexPluginCapabilitiesUnchanged(cache, controls, (path) => read(path), rules))
|
|
37720
37730
|
throw new Error("Retired Codex parent capabilities changed");
|
|
37721
37731
|
for (const root of proof.roots) {
|
|
37722
|
-
const manifest = binding.sources.find((source2) => source2.path ===
|
|
37732
|
+
const manifest = binding.sources.find((source2) => source2.path === join31(root, ".codex-plugin/plugin.json") && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && [undefined, "bytes"].includes(source2.hashMode));
|
|
37723
37733
|
if (!manifest || codexDirectHookSelects(cache, root) || !reviewedRetiredCodexRoot(cache, root, controls, rules, (path) => read(path), true))
|
|
37724
37734
|
throw new Error("Retired Codex materialization changed");
|
|
37725
37735
|
}
|
|
@@ -37730,7 +37740,7 @@ function retainableAbsentWitness(source) {
|
|
|
37730
37740
|
return null;
|
|
37731
37741
|
if ([undefined, "bytes"].includes(source.hashMode))
|
|
37732
37742
|
return "bytes";
|
|
37733
|
-
if (source.hashMode === "claude-plugin-manifest-v1" && source.sha256 !== null && source.path.endsWith(
|
|
37743
|
+
if (source.hashMode === "claude-plugin-manifest-v1" && source.sha256 !== null && source.path.endsWith(join31(sep11, ".claude-plugin", "plugin.json")))
|
|
37734
37744
|
return "claude-plugin-manifest-v1";
|
|
37735
37745
|
if (source.hashMode === CLAUDE_ORPHAN_MARKER_MODE && source.sha256 !== null && isClaudePluginCacheOrphanMarker(source.path))
|
|
37736
37746
|
return CLAUDE_ORPHAN_MARKER_MODE;
|
|
@@ -37755,11 +37765,11 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
37755
37765
|
const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(sep11);
|
|
37756
37766
|
if (parts.length < 4 || parts.slice(0, 3).some((part) => !part || part === "." || part === ".."))
|
|
37757
37767
|
continue;
|
|
37758
|
-
const root =
|
|
37768
|
+
const root = join31(cache, ...parts.slice(0, 3));
|
|
37759
37769
|
safe6(root);
|
|
37760
|
-
if (
|
|
37770
|
+
if (lstatSync24(root, { throwIfNoEntry: false }))
|
|
37761
37771
|
continue;
|
|
37762
|
-
const claude =
|
|
37772
|
+
const claude = dirname22(dirname22(cache)), settings = join31(claude, "settings.json"), registry2 = join31(claude, "plugins/installed_plugins.json");
|
|
37763
37773
|
const full = (path) => binding.sources.find((item) => item.path === path && item.sha256 !== null && item.format === undefined && item.fields === undefined);
|
|
37764
37774
|
const configSource = full(settings), registrySource = full(registry2);
|
|
37765
37775
|
if (!configSource || !registrySource || projected(configSource) !== configSource.sha256 || projected(registrySource) !== registrySource.sha256)
|
|
@@ -37802,9 +37812,9 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
37802
37812
|
if (!targetValid || !targetScopes.has("user\x00"))
|
|
37803
37813
|
continue;
|
|
37804
37814
|
const active = rows[0]?.installPath;
|
|
37805
|
-
if (typeof active !== "string" || rows[0]?.version !==
|
|
37815
|
+
if (typeof active !== "string" || rows[0]?.version !== basename13(active) || dirname22(active) !== dirname22(root) || active === root || !lstatSync24(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync8(active) !== active)
|
|
37806
37816
|
continue;
|
|
37807
|
-
const activeManifest = full(
|
|
37817
|
+
const activeManifest = full(join31(active, ".claude-plugin/plugin.json"));
|
|
37808
37818
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
37809
37819
|
continue;
|
|
37810
37820
|
result.add(root);
|
|
@@ -37815,10 +37825,10 @@ function codexSemanticCacheSourceRole(source, cacheRoot, parents3, hookParents =
|
|
|
37815
37825
|
if (!isAbsolute22(source.path) || resolve22(source.path) !== source.path || /[\x00-\x1f\x7f]/.test(source.path) || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.reviewArtifact !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes")
|
|
37816
37826
|
return false;
|
|
37817
37827
|
const parts = relative7(cacheRoot, source.path).split(sep11);
|
|
37818
|
-
if (parts.length < 3 || !parents3.includes(
|
|
37828
|
+
if (parts.length < 3 || !parents3.includes(join31(cacheRoot, parts[0], parts[1])))
|
|
37819
37829
|
return false;
|
|
37820
37830
|
const tail = parts.slice(3).join("/");
|
|
37821
|
-
const parent =
|
|
37831
|
+
const parent = join31(cacheRoot, parts[0], parts[1]);
|
|
37822
37832
|
return parts.length === 5 && tail === ".codex-plugin/plugin.json" && source.sha256 !== null || parts.length === 4 && [".app.json", ".mcp.json"].includes(tail) && source.sha256 !== null || parts.length === 5 && tail === "hooks/hooks.json" && hookParents.includes(parent) && source.sha256 !== null || source.sha256 === null && (parts.length === 4 && tail === "SKILL.md" || parts.length === 5 && tail === "hooks/hooks.json");
|
|
37823
37833
|
}
|
|
37824
37834
|
function codexSemanticCacheDirectoryRole(path, cacheRoot) {
|
|
@@ -37827,9 +37837,9 @@ function codexSemanticCacheDirectoryRole(path, cacheRoot) {
|
|
|
37827
37837
|
function assertCodexSemanticCacheHookSafety(cacheRoot, parents3, configPath, hookRootAlias = null) {
|
|
37828
37838
|
const selectionRoots = [cacheRoot, ...parents3];
|
|
37829
37839
|
if (hookRootAlias !== null) {
|
|
37830
|
-
if (!hookRootAlias || Object.keys(hookRootAlias).length !== 2 || [hookRootAlias.alias, hookRootAlias.target].some((path) => typeof path !== "string" || !isAbsolute22(path) || resolve22(path) !== path || /[\x00-\x1f\x7f]/.test(path)) || hookRootAlias.target !==
|
|
37840
|
+
if (!hookRootAlias || Object.keys(hookRootAlias).length !== 2 || [hookRootAlias.alias, hookRootAlias.target].some((path) => typeof path !== "string" || !isAbsolute22(path) || resolve22(path) !== path || /[\x00-\x1f\x7f]/.test(path)) || hookRootAlias.target !== dirname22(configPath) || cacheRoot !== join31(hookRootAlias.target, "plugins/cache") || !lstatSync24(hookRootAlias.alias, { throwIfNoEntry: false })?.isSymbolicLink() || realpathSync8(hookRootAlias.alias) !== hookRootAlias.target || realpathSync8(hookRootAlias.target) !== hookRootAlias.target)
|
|
37831
37841
|
throw new Error("Reviewed semantic cache hook alias changed");
|
|
37832
|
-
selectionRoots.push(...selectionRoots.map((root) =>
|
|
37842
|
+
selectionRoots.push(...selectionRoots.map((root) => join31(hookRootAlias.alias, relative7(hookRootAlias.target, root))));
|
|
37833
37843
|
}
|
|
37834
37844
|
selectionRoots.push("plugins/cache");
|
|
37835
37845
|
if (selectionRoots.some((parent) => codexDirectHookSelects(cacheRoot, parent, configPath)))
|
|
@@ -37849,7 +37859,7 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
|
|
|
37849
37859
|
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))
|
|
37850
37860
|
throw new Error("Invalid Codex semantic cache discovery proof");
|
|
37851
37861
|
const cacheRoot = proof.witness.cacheRoot;
|
|
37852
|
-
if (controls.some((control) =>
|
|
37862
|
+
if (controls.some((control) => dirname22(dirname22(control.pluginParent)) !== cacheRoot))
|
|
37853
37863
|
throw new Error("Codex semantic cache names another enrolled cache");
|
|
37854
37864
|
const reviewedHookParents = proof.reviewedHookParents ?? [];
|
|
37855
37865
|
if (!Array.isArray(reviewedHookParents) || reviewedHookParents.length > 4096 || reviewedHookParents.some((parent) => !parent || !(parent.installation === "remote-receipt" && Object.keys(parent).sort().join(",") === "installation,namespace,pluginId,pluginParent,remotePluginId,role" && typeof parent.remotePluginId === "string" || parent.installation === "local-marketplace" && Object.keys(parent).sort().join(",") === "installation,marketplaceSha256,marketplaceSourcePath,namespace,pluginId,pluginParent,role" && typeof parent.marketplaceSourcePath === "string" && /^[a-f0-9]{64}$/.test(parent.marketplaceSha256 ?? "")) || parent.role !== "reviewed-hook" || typeof parent.pluginId !== "string" || typeof parent.namespace !== "string" || typeof parent.pluginParent !== "string") || new Set(reviewedHookParents.map((parent) => parent.pluginParent)).size !== reviewedHookParents.length || !isDeepStrictEqual5((proof.witness.hookParents ?? []).map(({ manifestSha256: _manifest, hooksSha256: _hooks, receiptSha256: _receipt, ...parent }) => parent), reviewedHookParents)) {
|
|
@@ -37865,7 +37875,7 @@ function verifyCodexSemanticCacheDiscovery(binding, reviewedRootAliases) {
|
|
|
37865
37875
|
if (!directories.length || !isDeepStrictEqual5(sources, proof.supersededSources) || !isDeepStrictEqual5(directories, proof.supersededDirectories))
|
|
37866
37876
|
throw new Error("Codex semantic cache provenance changed");
|
|
37867
37877
|
const configPath = proof.configPath;
|
|
37868
|
-
if (!isAbsolute22(configPath) || resolve22(configPath) !== configPath ||
|
|
37878
|
+
if (!isAbsolute22(configPath) || resolve22(configPath) !== configPath || basename13(configPath) !== "config.toml" || /[\x00-\x1f\x7f]/.test(configPath))
|
|
37869
37879
|
throw new Error("Invalid semantic cache configuration source");
|
|
37870
37880
|
const configSource = binding.sources.find((source) => source.path === configPath && source.sha256 !== null && source.format === undefined && source.fields === undefined);
|
|
37871
37881
|
if (!configSource || projected(configSource) !== configSource.sha256)
|
|
@@ -37898,7 +37908,7 @@ function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases, witne
|
|
|
37898
37908
|
const projection = binding.codexRetiredMaterializations.directories.filter((directory) => !semanticDirectory(directory.path));
|
|
37899
37909
|
if (projection.length !== ordinary.length || projection.some((item, index) => item.path !== ordinary[index]?.path))
|
|
37900
37910
|
throw new Error("Missing retired Codex directory projection");
|
|
37901
|
-
const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !
|
|
37911
|
+
const omitted = [...retiredRoots, ...(binding.codexRetiredMaterializations.parents ?? []).filter((parent) => !lstatSync24(parent, { throwIfNoEntry: false }))];
|
|
37902
37912
|
if (projection.every((item) => Array.isArray(item.entries)))
|
|
37903
37913
|
verifyDiscoveryDirectoryProjection(projection, omitted, witnessTolerance);
|
|
37904
37914
|
else {
|
|
@@ -37915,7 +37925,7 @@ function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases, witne
|
|
|
37915
37925
|
verifyDiscoveryDirectories(ordinary, [], witnessTolerance);
|
|
37916
37926
|
verifyDiscoveryDirectories(projected2, installationRoots, witnessTolerance);
|
|
37917
37927
|
}
|
|
37918
|
-
const absentRoots = [...absentCodexSkillRoots(binding, witnessTolerance), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root) => !
|
|
37928
|
+
const absentRoots = [...absentCodexSkillRoots(binding, witnessTolerance), ...absentRetiredClaudeRoots(binding), ...retiredRoots.filter((root) => !lstatSync24(root, { throwIfNoEntry: false }))];
|
|
37919
37929
|
const budget2 = discoveryByteBudget();
|
|
37920
37930
|
for (const source of binding.sources) {
|
|
37921
37931
|
assertMarketplaceBinding(binding, source);
|
|
@@ -37953,12 +37963,12 @@ function verifyAgentDiscovery(binding, codexRecovery, reviewedRootAliases, witne
|
|
|
37953
37963
|
safe6(root);
|
|
37954
37964
|
for (const root of absentRoots) {
|
|
37955
37965
|
safe6(root);
|
|
37956
|
-
if (
|
|
37966
|
+
if (lstatSync24(root, { throwIfNoEntry: false }))
|
|
37957
37967
|
throw new Error("Retired native materialization changed during discovery verification");
|
|
37958
37968
|
}
|
|
37959
37969
|
}
|
|
37960
37970
|
function claudeControlSource(source) {
|
|
37961
|
-
return CLAUDE_CONTROL_WITNESS_MODES.has(source.hashMode ?? "") || CLAUDE_CONTROL_FILES.has(
|
|
37971
|
+
return CLAUDE_CONTROL_WITNESS_MODES.has(source.hashMode ?? "") || CLAUDE_CONTROL_FILES.has(basename13(source.path)) && !source.path.includes(`${sep11}.claude${sep11}plugins${sep11}cache${sep11}`);
|
|
37962
37972
|
}
|
|
37963
37973
|
function retainedAbsentClaudeRoot(absentRoots, source) {
|
|
37964
37974
|
return claudeControlSource(source) ? undefined : retainedAbsentRoot(absentRoots, source);
|
|
@@ -37969,13 +37979,13 @@ function codexInstallationRoots(binding) {
|
|
|
37969
37979
|
return [];
|
|
37970
37980
|
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)
|
|
37971
37981
|
throw new Error("Invalid native installation input proof");
|
|
37972
|
-
const cache =
|
|
37973
|
-
const config2 =
|
|
37982
|
+
const cache = dirname22(dirname22(proof.plugins[0].pluginParent));
|
|
37983
|
+
const config2 = join31(dirname22(dirname22(cache)), "config.toml"), home = dirname22(dirname22(dirname22(cache)));
|
|
37974
37984
|
const configSource = binding.sources.find((source) => source.path === config2 && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
37975
|
-
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) =>
|
|
37976
|
-
if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot + sep11) || input2.sourceRoot.startsWith(root + sep11)) || binding.sources.some((source) =>
|
|
37985
|
+
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join31(home, path));
|
|
37986
|
+
if (!configSource || proof.plugins.some((input2) => nativeRoots.some((root) => root === input2.sourceRoot || root.startsWith(input2.sourceRoot + sep11) || input2.sourceRoot.startsWith(root + sep11)) || binding.sources.some((source) => basename13(source.path) === "config.toml" && (source.path === input2.sourceRoot || source.path.startsWith(input2.sourceRoot + sep11)))))
|
|
37977
37987
|
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
37978
|
-
if (proof.plugins.some((input2) =>
|
|
37988
|
+
if (proof.plugins.some((input2) => dirname22(dirname22(input2.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join31(input2.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
37979
37989
|
throw new Error("Missing native installation input source witness");
|
|
37980
37990
|
return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
|
|
37981
37991
|
const text2 = read(path);
|
|
@@ -37991,13 +38001,13 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
37991
38001
|
throw new Error("Provider executable witnesses require explicit reviewed Codex V6");
|
|
37992
38002
|
if (source.hashMode === "codex-settings-v6" && (new Set(binding.sources.map((row) => row.path)).size !== binding.sources.length || !Array.isArray(source.hookSources) || source.hookSources.some((hook) => !binding.sources.some((row) => row.path === hook.path && row.sha256 === hook.sha256 && [undefined, "bytes"].includes(row.hashMode) && row.format === undefined && row.fields === undefined))))
|
|
37993
38003
|
throw new Error("Missing independently reviewed Codex hook source population");
|
|
37994
|
-
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" ||
|
|
38004
|
+
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename13(source.path) !== "plugin.json" || !source.path.endsWith(join31(sep11, ".claude-plugin", "plugin.json"))))
|
|
37995
38005
|
throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
|
|
37996
|
-
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" ||
|
|
38006
|
+
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename13(source.path) !== "sumi.json"))
|
|
37997
38007
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
37998
|
-
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" || source.hashMode === "codex-settings-v6")) && (binding.agent !== "codex" || binding.method !== "reviewed" ||
|
|
38008
|
+
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" || source.hashMode === "codex-settings-v6")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename13(source.path) !== "config.toml"))
|
|
37999
38009
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
38000
|
-
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" ||
|
|
38010
|
+
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "claude-settings-v4")) && (binding.agent !== "claude" || binding.method !== "reviewed" || basename13(source.path) !== "settings.json"))
|
|
38001
38011
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
38002
38012
|
if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
38003
38013
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
@@ -38005,11 +38015,11 @@ function assertMarketplaceBinding(binding, source) {
|
|
|
38005
38015
|
throw new Error("Claude marketplace entry witnesses require explicit reviewed Claude discovery of one named entry");
|
|
38006
38016
|
}
|
|
38007
38017
|
function hashReviewedExecutable(path, budget2) {
|
|
38008
|
-
const before =
|
|
38018
|
+
const before = lstatSync24(path, { bigint: true });
|
|
38009
38019
|
if (before.size < 0n || before.size > BigInt(budget2.remaining))
|
|
38010
38020
|
throw new Error("Discovery aggregate executable byte limit exceeded");
|
|
38011
38021
|
const digest3 = pluginExecutableDigest(path).slice(7);
|
|
38012
|
-
const after =
|
|
38022
|
+
const after = lstatSync24(path, { bigint: true });
|
|
38013
38023
|
for (const key2 of ["dev", "ino", "size", "mode", "uid", "gid", "nlink", "mtimeNs", "ctimeNs"]) {
|
|
38014
38024
|
if (before[key2] !== after[key2])
|
|
38015
38025
|
throw new Error("Discovery executable changed during budgeted capture");
|
|
@@ -38020,7 +38030,7 @@ function hashReviewedExecutable(path, budget2) {
|
|
|
38020
38030
|
function agentDiscoveryConfigPath(home, agent) {
|
|
38021
38031
|
if (agent === "sumi")
|
|
38022
38032
|
return sumiConfigPath(home);
|
|
38023
|
-
return
|
|
38033
|
+
return join31(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
38024
38034
|
}
|
|
38025
38035
|
function resolveAgentDiscovery(options) {
|
|
38026
38036
|
const canonical9 = options.canonical ?? resolve22, home = resolve22(options.home), agent = options.agent;
|
|
@@ -38044,42 +38054,42 @@ function resolveAgentDiscovery(options) {
|
|
|
38044
38054
|
const review = options.reviewed?.agents.find((item) => item.agent === agent);
|
|
38045
38055
|
if (agent === "sumi") {
|
|
38046
38056
|
const directory = sumiConfigDirectory(home);
|
|
38047
|
-
if (witness(
|
|
38057
|
+
if (witness(join31(directory, "sumi.jsonc")) !== null)
|
|
38048
38058
|
unresolved("JSONC configuration requires a supported format adapter");
|
|
38049
|
-
for (const root of [directory,
|
|
38059
|
+
for (const root of [directory, join31(home, ".claude"), join31(home, ".agents")])
|
|
38050
38060
|
for (const name of ["skill", "skills"])
|
|
38051
|
-
roots.add(canonical9(
|
|
38061
|
+
roots.add(canonical9(join31(root, name)));
|
|
38052
38062
|
if (config2.skills !== undefined && (!Array.isArray(config2.skills) || config2.skills.some((path) => typeof path !== "string")))
|
|
38053
38063
|
unresolved("skills must be a string array");
|
|
38054
38064
|
for (const value of config2.skills ?? []) {
|
|
38055
38065
|
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute22(value) || value.startsWith("~/")))
|
|
38056
38066
|
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
38057
|
-
roots.add(canonical9(value.startsWith("~/") ?
|
|
38067
|
+
roots.add(canonical9(value.startsWith("~/") ? join31(home, value.slice(2)) : value));
|
|
38058
38068
|
}
|
|
38059
38069
|
for (const key2 of ["plugin", "plugins"])
|
|
38060
38070
|
if (config2[key2] !== undefined && !Array.isArray(config2[key2]))
|
|
38061
38071
|
unresolved(`${key2} must be an array`);
|
|
38062
|
-
const plugins = [
|
|
38072
|
+
const plugins = [join31(directory, "plugin"), join31(directory, "plugins")];
|
|
38063
38073
|
for (const path of plugins) {
|
|
38064
38074
|
safe6(path);
|
|
38065
|
-
if (
|
|
38066
|
-
for (const name of
|
|
38075
|
+
if (lstatSync24(path, { throwIfNoEntry: false })?.isDirectory())
|
|
38076
|
+
for (const name of readdirSync9(path).sort()) {
|
|
38067
38077
|
if (name === "skills-cli.js" && path === plugins[1])
|
|
38068
38078
|
continue;
|
|
38069
|
-
const target =
|
|
38070
|
-
if (!
|
|
38079
|
+
const target = join31(path, name);
|
|
38080
|
+
if (!lstatSync24(target).isFile())
|
|
38071
38081
|
unresolved("local plugin packages need a dedicated discovery adapter");
|
|
38072
38082
|
witness(target);
|
|
38073
38083
|
}
|
|
38074
38084
|
}
|
|
38075
38085
|
for (const root of roots) {
|
|
38076
38086
|
safe6(root);
|
|
38077
|
-
if (
|
|
38087
|
+
if (lstatSync24(root, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(root).some((name) => name.endsWith(".md")))
|
|
38078
38088
|
unresolved("flat markdown skills require a dedicated native migration adapter");
|
|
38079
38089
|
}
|
|
38080
38090
|
}
|
|
38081
38091
|
if (agent === "hermes") {
|
|
38082
|
-
const profile = witness(
|
|
38092
|
+
const profile = witness(join31(home, ".hermes/active_profile"));
|
|
38083
38093
|
if (profile?.trim() && profile.trim() !== "default")
|
|
38084
38094
|
unresolved("a non-default profile is active");
|
|
38085
38095
|
const declared = config2.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
|
|
@@ -38093,7 +38103,7 @@ function resolveAgentDiscovery(options) {
|
|
|
38093
38103
|
continue;
|
|
38094
38104
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
38095
38105
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
38096
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ?
|
|
38106
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join31(home, normalized.slice(2)) : resolve22(home, ".hermes", normalized);
|
|
38097
38107
|
safe6(path);
|
|
38098
38108
|
roots.add(path);
|
|
38099
38109
|
}
|
|
@@ -38102,24 +38112,24 @@ function resolveAgentDiscovery(options) {
|
|
|
38102
38112
|
const executable = options.executable === undefined ? discoveryExecutable(agent) : options.executable;
|
|
38103
38113
|
if (executable) {
|
|
38104
38114
|
let packageRoot;
|
|
38105
|
-
for (let directory =
|
|
38106
|
-
const path =
|
|
38115
|
+
for (let directory = dirname22(executable.target), depth = 0;depth < 8; directory = dirname22(directory), depth++) {
|
|
38116
|
+
const path = join31(directory, "package.json"), raw = read(path);
|
|
38107
38117
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
38108
38118
|
packageRoot = directory;
|
|
38109
38119
|
witness(path);
|
|
38110
38120
|
break;
|
|
38111
38121
|
}
|
|
38112
|
-
if (
|
|
38122
|
+
if (dirname22(directory) === directory)
|
|
38113
38123
|
break;
|
|
38114
38124
|
}
|
|
38115
38125
|
if (!packageRoot)
|
|
38116
38126
|
unresolved("installed Gemini package layout is not recognized");
|
|
38117
|
-
const builtinRoot =
|
|
38127
|
+
const builtinRoot = join31(packageRoot, "bundle/builtin");
|
|
38118
38128
|
safe6(builtinRoot);
|
|
38119
|
-
if (!
|
|
38129
|
+
if (!lstatSync24(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
38120
38130
|
unresolved("installed Gemini builtin root is missing");
|
|
38121
|
-
for (const name of
|
|
38122
|
-
const text2 = witness(
|
|
38131
|
+
for (const name of readdirSync9(builtinRoot).sort()) {
|
|
38132
|
+
const text2 = witness(join31(builtinRoot, name, "SKILL.md"));
|
|
38123
38133
|
const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
|
|
38124
38134
|
if (!match?.[1] || builtinNames.includes(match[1]))
|
|
38125
38135
|
unresolved("installed Gemini builtin name is missing or ambiguous");
|
|
@@ -38165,10 +38175,10 @@ function resolveAgentDiscovery(options) {
|
|
|
38165
38175
|
if (agent === "claude" && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && source.reviewArtifact === undefined && [undefined, "bytes", "path-bytes"].includes(source.hashMode) && isClaudePluginCacheOrphanMarker(source.path)) {
|
|
38166
38176
|
return { path: source.path, hashMode: CLAUDE_ORPHAN_MARKER_MODE, sha256: hashClaudePluginCacheOrphanMarker(source.path) };
|
|
38167
38177
|
}
|
|
38168
|
-
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" ||
|
|
38178
|
+
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename13(source.path) !== "plugin.json" || !source.path.endsWith(join31(sep11, ".claude-plugin", "plugin.json")))
|
|
38169
38179
|
return source;
|
|
38170
|
-
const pluginRoot =
|
|
38171
|
-
const hookStat =
|
|
38180
|
+
const pluginRoot = dirname22(dirname22(source.path)), hooksPath = join31(pluginRoot, "hooks/hooks.json");
|
|
38181
|
+
const hookStat = lstatSync24(hooksPath, { throwIfNoEntry: false });
|
|
38172
38182
|
const text2 = read(source.path);
|
|
38173
38183
|
if (text2 === null)
|
|
38174
38184
|
throw new Error("Reviewed Claude plugin manifest is missing");
|
|
@@ -38196,7 +38206,7 @@ function resolveAgentDiscovery(options) {
|
|
|
38196
38206
|
assertReviewedClaudeCacheClosures(home, config2, review, canonical9);
|
|
38197
38207
|
for (const root of absentRoots) {
|
|
38198
38208
|
safe6(root);
|
|
38199
|
-
if (
|
|
38209
|
+
if (lstatSync24(root, { throwIfNoEntry: false }))
|
|
38200
38210
|
throw new Error("Retired native materialization changed during discovery review");
|
|
38201
38211
|
}
|
|
38202
38212
|
const combined = [...reviewedSources, ...reviewedSourcesWithManifestProjection];
|
|
@@ -38206,39 +38216,39 @@ function resolveAgentDiscovery(options) {
|
|
|
38206
38216
|
function plugin(root) {
|
|
38207
38217
|
root = canonical9(root);
|
|
38208
38218
|
safe6(root);
|
|
38209
|
-
const manifestPath =
|
|
38219
|
+
const manifestPath = join31(root, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
38210
38220
|
const raw = witness(manifestPath, undefined, undefined, agent === "claude" ? "claude-plugin-manifest-v1" : undefined);
|
|
38211
38221
|
if (raw === null)
|
|
38212
38222
|
unresolved("plugin manifest missing");
|
|
38213
38223
|
const manifest = parseConfig(raw, manifestPath);
|
|
38214
|
-
const hooks = witness(
|
|
38224
|
+
const hooks = witness(join31(root, "hooks/hooks.json"));
|
|
38215
38225
|
if (manifest.hooks !== undefined || hooks !== null)
|
|
38216
38226
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
38217
|
-
const commands =
|
|
38227
|
+
const commands = join31(root, "commands");
|
|
38218
38228
|
safe6(commands);
|
|
38219
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
38229
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync24(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
|
|
38220
38230
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
38221
|
-
const rootSkill = witness(
|
|
38231
|
+
const rootSkill = witness(join31(root, "SKILL.md"));
|
|
38222
38232
|
if (rootSkill !== null)
|
|
38223
38233
|
roots.add(root);
|
|
38224
38234
|
const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
38225
38235
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
38226
38236
|
unresolved("unsupported plugin skill paths");
|
|
38227
38237
|
if (agent === "claude")
|
|
38228
|
-
roots.add(
|
|
38238
|
+
roots.add(join31(root, "skills"));
|
|
38229
38239
|
for (const value of declared) {
|
|
38230
38240
|
const path = resolve22(root, value);
|
|
38231
38241
|
if (path !== root && !path.startsWith(root + sep11))
|
|
38232
38242
|
unresolved("plugin skill path escapes its root");
|
|
38233
|
-
roots.add(path.endsWith(`${sep11}SKILL.md`) ?
|
|
38243
|
+
roots.add(path.endsWith(`${sep11}SKILL.md`) ? dirname22(path) : path);
|
|
38234
38244
|
}
|
|
38235
38245
|
}
|
|
38236
38246
|
if (agent === "claude") {
|
|
38237
|
-
const registrations = witness(
|
|
38238
|
-
const installed = registrations === null ? {} : parseConfig(registrations,
|
|
38239
|
-
const commands = canonical9(
|
|
38247
|
+
const registrations = witness(join31(home, ".claude/plugins/installed_plugins.json"));
|
|
38248
|
+
const installed = registrations === null ? {} : parseConfig(registrations, join31(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
38249
|
+
const commands = canonical9(join31(home, ".claude/commands"));
|
|
38240
38250
|
safe6(commands);
|
|
38241
|
-
if (
|
|
38251
|
+
if (lstatSync24(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
|
|
38242
38252
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
38243
38253
|
for (const [id, enabled] of Object.entries(config2.enabledPlugins ?? {})) {
|
|
38244
38254
|
if (enabled === false)
|
|
@@ -38260,16 +38270,16 @@ function resolveAgentDiscovery(options) {
|
|
|
38260
38270
|
const market = config2.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
38261
38271
|
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute22(market.source))
|
|
38262
38272
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
38263
|
-
const catalogText = witness(
|
|
38273
|
+
const catalogText = witness(join31(market.source, ".agents/plugins/marketplace.json"));
|
|
38264
38274
|
if (catalogText === null)
|
|
38265
38275
|
unresolved("marketplace catalog missing");
|
|
38266
|
-
const catalog = parseConfig(catalogText,
|
|
38276
|
+
const catalog = parseConfig(catalogText, join31(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
38267
38277
|
if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
|
|
38268
38278
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
38269
38279
|
plugin(resolve22(market.source, matches[0].source.path));
|
|
38270
38280
|
}
|
|
38271
38281
|
} else if (agent === "opencode") {
|
|
38272
|
-
if (witness(
|
|
38282
|
+
if (witness(join31(home, ".config/opencode/opencode.jsonc")) !== null || witness(join31(home, ".config/opencode/config.json")) !== null)
|
|
38273
38283
|
unresolved("additional config layers require review");
|
|
38274
38284
|
if ((config2.plugin?.length ?? 0) > 0 || config2.skills?.urls?.length)
|
|
38275
38285
|
unresolved("external plugin or remote skill source");
|
|
@@ -38278,17 +38288,17 @@ function resolveAgentDiscovery(options) {
|
|
|
38278
38288
|
unresolved("relative or malformed added skill root");
|
|
38279
38289
|
roots.add(path);
|
|
38280
38290
|
}
|
|
38281
|
-
const localPlugins =
|
|
38291
|
+
const localPlugins = join31(home, ".config/opencode/plugins");
|
|
38282
38292
|
safe6(localPlugins);
|
|
38283
|
-
if (
|
|
38293
|
+
if (lstatSync24(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
38284
38294
|
unresolved("additional local plugin hooks require review");
|
|
38285
38295
|
} else if (agent === "sumi") {
|
|
38286
|
-
if ((config2.plugin?.length ?? 0) > 0 || (config2.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical9(configPath) && source.path !== canonical9(
|
|
38296
|
+
if ((config2.plugin?.length ?? 0) > 0 || (config2.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical9(configPath) && source.path !== canonical9(join31(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
|
|
38287
38297
|
unresolved("external or foreign local plugins require review");
|
|
38288
38298
|
} else if (agent === "hermes") {
|
|
38289
|
-
for (const directory of [
|
|
38299
|
+
for (const directory of [join31(home, ".hermes/plugins"), join31(home, ".hermes/hermes-agent")]) {
|
|
38290
38300
|
safe6(directory);
|
|
38291
|
-
if (
|
|
38301
|
+
if (lstatSync24(directory, { throwIfNoEntry: false }))
|
|
38292
38302
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
38293
38303
|
}
|
|
38294
38304
|
if (Bun.which("hermes") || Object.keys(config2.plugins ?? {}).length)
|
|
@@ -38296,24 +38306,24 @@ function resolveAgentDiscovery(options) {
|
|
|
38296
38306
|
} else if (agent === "gemini") {
|
|
38297
38307
|
if (Object.keys(config2.extensions ?? {}).length || config2.skills?.paths?.length)
|
|
38298
38308
|
unresolved("custom extension or skill paths");
|
|
38299
|
-
const directory =
|
|
38309
|
+
const directory = join31(home, ".gemini/extensions");
|
|
38300
38310
|
safe6(directory);
|
|
38301
|
-
if (
|
|
38302
|
-
for (const name of
|
|
38303
|
-
const root =
|
|
38311
|
+
if (lstatSync24(directory, { throwIfNoEntry: false }))
|
|
38312
|
+
for (const name of readdirSync9(directory)) {
|
|
38313
|
+
const root = join31(directory, name);
|
|
38304
38314
|
safe6(root);
|
|
38305
|
-
if (!
|
|
38315
|
+
if (!lstatSync24(root)?.isDirectory())
|
|
38306
38316
|
continue;
|
|
38307
|
-
const raw = witness(
|
|
38317
|
+
const raw = witness(join31(root, "gemini-extension.json"));
|
|
38308
38318
|
if (raw === null)
|
|
38309
38319
|
unresolved("extension registration missing");
|
|
38310
|
-
const manifest = parseConfig(raw,
|
|
38311
|
-
if (manifest.hooks !== undefined || witness(
|
|
38320
|
+
const manifest = parseConfig(raw, join31(root, "gemini-extension.json"));
|
|
38321
|
+
if (manifest.hooks !== undefined || witness(join31(root, "hooks/hooks.json")) !== null || witness(join31(root, ".gemini-extension-install.json")) !== null)
|
|
38312
38322
|
unresolved("extension hooks or linked registration require review");
|
|
38313
|
-
roots.add(
|
|
38323
|
+
roots.add(join31(root, "skills"));
|
|
38314
38324
|
}
|
|
38315
38325
|
}
|
|
38316
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([
|
|
38326
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join31(home, ".hermes/plugins"), join31(home, ".hermes/hermes-agent")].map((path) => canonical9(path))) } : {} };
|
|
38317
38327
|
}
|
|
38318
38328
|
var DISCOVERY_RUNTIME_COMMANDS, realpathOrNull = (path) => {
|
|
38319
38329
|
try {
|
|
@@ -38358,9 +38368,9 @@ var init_agent_discovery = __esm(() => {
|
|
|
38358
38368
|
});
|
|
38359
38369
|
|
|
38360
38370
|
// src/lib/authoring-path.ts
|
|
38361
|
-
import { lstatSync as
|
|
38371
|
+
import { lstatSync as lstatSync25, realpathSync as realpathSync9 } from "fs";
|
|
38362
38372
|
import { homedir as homedir3 } from "os";
|
|
38363
|
-
import { basename as
|
|
38373
|
+
import { basename as basename14, dirname as dirname23, join as join32, resolve as resolve23, sep as sep12 } from "path";
|
|
38364
38374
|
function pathParts(path) {
|
|
38365
38375
|
return resolve23(path).split(sep12).filter(Boolean);
|
|
38366
38376
|
}
|
|
@@ -38378,9 +38388,9 @@ function nativeRootMatch(path) {
|
|
|
38378
38388
|
function physicalPath(path) {
|
|
38379
38389
|
let cursor = resolve23(path);
|
|
38380
38390
|
const suffix = [];
|
|
38381
|
-
while (!
|
|
38382
|
-
suffix.unshift(
|
|
38383
|
-
const parent =
|
|
38391
|
+
while (!lstatSync25(cursor, { throwIfNoEntry: false })) {
|
|
38392
|
+
suffix.unshift(basename14(cursor));
|
|
38393
|
+
const parent = dirname23(cursor);
|
|
38384
38394
|
if (parent === cursor)
|
|
38385
38395
|
return resolve23(path);
|
|
38386
38396
|
cursor = parent;
|
|
@@ -38391,7 +38401,7 @@ function contains(root, path) {
|
|
|
38391
38401
|
return path === root || path.startsWith(root + sep12);
|
|
38392
38402
|
}
|
|
38393
38403
|
function configuredRoots(home, explicitHome) {
|
|
38394
|
-
const homeData =
|
|
38404
|
+
const homeData = join32(home, ".hasna", "skills");
|
|
38395
38405
|
const homePolicy = readManagedSkillPolicySnapshot(homeData);
|
|
38396
38406
|
const configuredPolicy = !explicitHome && resolve23(getDataDirReadOnly()) !== resolve23(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
|
|
38397
38407
|
const policy = homePolicy ?? configuredPolicy;
|
|
@@ -38422,8 +38432,8 @@ function configuredRoots(home, explicitHome) {
|
|
|
38422
38432
|
admitBinding(binding);
|
|
38423
38433
|
continue;
|
|
38424
38434
|
}
|
|
38425
|
-
const nativeHome =
|
|
38426
|
-
if (!
|
|
38435
|
+
const nativeHome = join32(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
|
|
38436
|
+
if (!lstatSync25(nativeHome, { throwIfNoEntry: false }))
|
|
38427
38437
|
continue;
|
|
38428
38438
|
roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
|
|
38429
38439
|
}
|
|
@@ -38437,8 +38447,8 @@ function assertPortableAuthoringPath(path, options = {}) {
|
|
|
38437
38447
|
const candidates = [lexical, physical];
|
|
38438
38448
|
let native = candidates.map(nativeRootMatch).find(Boolean);
|
|
38439
38449
|
const home = resolve23(options.homeDir ?? homedir3());
|
|
38440
|
-
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) =>
|
|
38441
|
-
defaults.push(
|
|
38450
|
+
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join32(home, ...parts));
|
|
38451
|
+
defaults.push(join32(home, ".codex/plugins/cache"), join32(home, ".claude/plugins/cache"), join32(home, ".claude/plugins/synced"), join32(home, ".gemini/extensions"));
|
|
38442
38452
|
for (const root of defaults) {
|
|
38443
38453
|
if (candidates.some((candidate) => contains(resolve23(root), candidate) || contains(physicalPath(root), candidate)))
|
|
38444
38454
|
native ??= root;
|
|
@@ -38467,29 +38477,29 @@ import {
|
|
|
38467
38477
|
existsSync as existsSync12,
|
|
38468
38478
|
mkdirSync as mkdirSync8,
|
|
38469
38479
|
mkdtempSync,
|
|
38470
|
-
readdirSync as
|
|
38480
|
+
readdirSync as readdirSync10,
|
|
38471
38481
|
realpathSync as realpathSync10,
|
|
38472
38482
|
renameSync as renameSync3,
|
|
38473
38483
|
rmSync as rmSync3,
|
|
38474
38484
|
statSync as statSync9,
|
|
38475
38485
|
writeFileSync as writeFileSync6
|
|
38476
38486
|
} from "fs";
|
|
38477
|
-
import { basename as
|
|
38487
|
+
import { basename as basename15, dirname as dirname24, isAbsolute as isAbsolute23, join as join33, normalize as normalize4, relative as relative8, resolve as resolve24, sep as sep13 } from "path";
|
|
38478
38488
|
function getPortableSkillsRoot(options = {}) {
|
|
38479
38489
|
return resolvePortableSkillsRoot(options, true);
|
|
38480
38490
|
}
|
|
38481
38491
|
function resolvePortableSkillsRoot(options, migrate) {
|
|
38482
38492
|
if (options.rootDir)
|
|
38483
38493
|
return options.rootDir;
|
|
38484
|
-
const appDir = options.homeDir ?
|
|
38485
|
-
const cache =
|
|
38494
|
+
const appDir = options.homeDir ? join33(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
|
|
38495
|
+
const cache = join33(appDir, SKILLS_CACHE_DIRNAME);
|
|
38486
38496
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
|
|
38487
38497
|
return cache;
|
|
38488
|
-
const installed =
|
|
38498
|
+
const installed = join33(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
38489
38499
|
return installed;
|
|
38490
38500
|
}
|
|
38491
38501
|
function getPortableSkillPath(name, options = {}) {
|
|
38492
|
-
return
|
|
38502
|
+
return join33(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
38493
38503
|
}
|
|
38494
38504
|
function findPortableSkill(name, options = {}) {
|
|
38495
38505
|
let normalized;
|
|
@@ -38512,10 +38522,10 @@ function listPortableSkills(options = {}) {
|
|
|
38512
38522
|
if (!safeIsDirectory(root))
|
|
38513
38523
|
return [];
|
|
38514
38524
|
const skills = [];
|
|
38515
|
-
for (const entry of
|
|
38525
|
+
for (const entry of readdirSync10(root).sort()) {
|
|
38516
38526
|
if (entry.startsWith("."))
|
|
38517
38527
|
continue;
|
|
38518
|
-
const path =
|
|
38528
|
+
const path = join33(root, entry);
|
|
38519
38529
|
if (!safeIsDirectory(path))
|
|
38520
38530
|
continue;
|
|
38521
38531
|
try {
|
|
@@ -38548,9 +38558,9 @@ function isOfficialSkillName(name) {
|
|
|
38548
38558
|
function scaffoldPortableSkill(name, options = {}) {
|
|
38549
38559
|
const skillName = normalizeNewPortableSkillName(name);
|
|
38550
38560
|
const readOnlyRoot = resolvePortableSkillsRoot(options, false);
|
|
38551
|
-
assertPortableAuthoringPath(
|
|
38561
|
+
assertPortableAuthoringPath(join33(readOnlyRoot, skillName), options);
|
|
38552
38562
|
const root = getPortableSkillsRoot(options);
|
|
38553
|
-
const skillPath =
|
|
38563
|
+
const skillPath = join33(root, skillName);
|
|
38554
38564
|
assertPortableAuthoringPath(skillPath, options);
|
|
38555
38565
|
if (existsSync12(skillPath)) {
|
|
38556
38566
|
if (!options.overwrite)
|
|
@@ -38572,10 +38582,10 @@ function physicalImportPath(path) {
|
|
|
38572
38582
|
let ancestor = resolve24(path);
|
|
38573
38583
|
const suffix = [];
|
|
38574
38584
|
while (!existsSync12(ancestor)) {
|
|
38575
|
-
suffix.unshift(
|
|
38576
|
-
ancestor =
|
|
38585
|
+
suffix.unshift(basename15(ancestor));
|
|
38586
|
+
ancestor = dirname24(ancestor);
|
|
38577
38587
|
}
|
|
38578
|
-
return
|
|
38588
|
+
return join33(realpathSync10(ancestor), ...suffix);
|
|
38579
38589
|
}
|
|
38580
38590
|
function assertDisjointImportPaths(source, destination) {
|
|
38581
38591
|
const sourcePath = realpathSync10(source);
|
|
@@ -38597,15 +38607,15 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
38597
38607
|
const explicitName = options.name != null;
|
|
38598
38608
|
const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
|
|
38599
38609
|
if (isOfficialSkillName(skillName) && !options.allowShadow) {
|
|
38600
|
-
const sourceSlug = safeNormalizeName(
|
|
38601
|
-
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${
|
|
38610
|
+
const sourceSlug = safeNormalizeName(basename15(absoluteSource));
|
|
38611
|
+
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename15(absoluteSource)}')` : ""} matches a bundled official skill.`;
|
|
38602
38612
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
38603
38613
|
}
|
|
38604
|
-
const readOnlyDestination =
|
|
38614
|
+
const readOnlyDestination = join33(resolvePortableSkillsRoot(options, false), skillName);
|
|
38605
38615
|
assertPortableAuthoringPath(readOnlyDestination, options);
|
|
38606
38616
|
assertDisjointImportPaths(absoluteSource, readOnlyDestination);
|
|
38607
38617
|
const root = getPortableSkillsRoot(options);
|
|
38608
|
-
const destination =
|
|
38618
|
+
const destination = join33(root, skillName);
|
|
38609
38619
|
assertPortableAuthoringPath(destination, options);
|
|
38610
38620
|
assertDisjointImportPaths(absoluteSource, destination);
|
|
38611
38621
|
if (existsSync12(destination)) {
|
|
@@ -38613,7 +38623,7 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
38613
38623
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
38614
38624
|
rmSync3(destination, { recursive: true, force: true });
|
|
38615
38625
|
}
|
|
38616
|
-
mkdirSync8(
|
|
38626
|
+
mkdirSync8(dirname24(destination), { recursive: true });
|
|
38617
38627
|
copySkillDirectory(absoluteSource, destination);
|
|
38618
38628
|
const base = {
|
|
38619
38629
|
...inferred,
|
|
@@ -38632,18 +38642,29 @@ function safeNormalizeName(name) {
|
|
|
38632
38642
|
}
|
|
38633
38643
|
function validatePortableSkillDirectory(name, skillPath) {
|
|
38634
38644
|
const normalizedName = normalizePortableSkillName(name);
|
|
38635
|
-
|
|
38645
|
+
let manifest;
|
|
38646
|
+
let manifestError;
|
|
38647
|
+
if (existsSync12(skillPath)) {
|
|
38648
|
+
try {
|
|
38649
|
+
manifest = readPortableSkillManifest(skillPath, normalizedName);
|
|
38650
|
+
} catch (error61) {
|
|
38651
|
+
manifestError = error61;
|
|
38652
|
+
}
|
|
38653
|
+
}
|
|
38654
|
+
const base = validateSkillDirectory(normalizedName, skillPath, undefined, { kind: manifest?.kind });
|
|
38636
38655
|
const issues = [...base.issues];
|
|
38637
38656
|
const warnings = [...base.warnings];
|
|
38638
|
-
let manifest;
|
|
38639
38657
|
if (existsSync12(skillPath)) {
|
|
38640
|
-
const skillJsonPath =
|
|
38641
|
-
const skillMdPath =
|
|
38658
|
+
const skillJsonPath = join33(skillPath, "skill.json");
|
|
38659
|
+
const skillMdPath = join33(skillPath, "SKILL.md");
|
|
38642
38660
|
if (!existsSync12(skillJsonPath) && !existsSync12(skillMdPath)) {
|
|
38643
38661
|
add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
38644
38662
|
}
|
|
38645
38663
|
try {
|
|
38646
|
-
|
|
38664
|
+
if (manifestError)
|
|
38665
|
+
throw manifestError;
|
|
38666
|
+
if (!manifest)
|
|
38667
|
+
throw new Error("Portable manifest could not be read");
|
|
38647
38668
|
const isInstruction = manifest.kind === "instruction";
|
|
38648
38669
|
if (manifest.name !== normalizedName) {
|
|
38649
38670
|
add3(issues, "portable.name_mismatch", `Portable manifest name '${manifest.name}' does not match '${normalizedName}'`);
|
|
@@ -38658,27 +38679,11 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
38658
38679
|
add3(issues, "portable.version_missing", "Portable manifest missing version");
|
|
38659
38680
|
}
|
|
38660
38681
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
38661
|
-
strict: existsSync12(
|
|
38682
|
+
strict: existsSync12(join33(skillPath, "skill.json")),
|
|
38662
38683
|
skillPath
|
|
38663
38684
|
});
|
|
38664
38685
|
for (const issue2 of contractIssues)
|
|
38665
38686
|
add3(issues, issue2.code, issue2.message);
|
|
38666
|
-
if (manifest.kind === "instruction") {
|
|
38667
|
-
const executableOnlyCodes = new Set([
|
|
38668
|
-
"package.missing",
|
|
38669
|
-
"package.bin_missing",
|
|
38670
|
-
"skill.src_missing",
|
|
38671
|
-
"skill.src_index_missing",
|
|
38672
|
-
"skill.runtime_entrypoint_unsafe",
|
|
38673
|
-
"skill.runtime_entrypoint_missing",
|
|
38674
|
-
"skill.runtime_entrypoint_symlink",
|
|
38675
|
-
"skill.runtime_entrypoint_not_file"
|
|
38676
|
-
]);
|
|
38677
|
-
for (let i = issues.length - 1;i >= 0; i--) {
|
|
38678
|
-
if (executableOnlyCodes.has(issues[i].code))
|
|
38679
|
-
issues.splice(i, 1);
|
|
38680
|
-
}
|
|
38681
|
-
}
|
|
38682
38687
|
if (!isInstruction && (!Array.isArray(manifest.inputs) || manifest.inputs.length === 0)) {
|
|
38683
38688
|
add3(issues, "portable.inputs_missing", "Portable manifest must declare inputs");
|
|
38684
38689
|
}
|
|
@@ -38698,7 +38703,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
38698
38703
|
add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
38699
38704
|
continue;
|
|
38700
38705
|
}
|
|
38701
|
-
const entryPath =
|
|
38706
|
+
const entryPath = join33(skillPath, command.entry);
|
|
38702
38707
|
if (!existsSync12(entryPath))
|
|
38703
38708
|
add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
38704
38709
|
else if (statSync9(entryPath).isDirectory())
|
|
@@ -38709,7 +38714,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
38709
38714
|
} catch (error61) {
|
|
38710
38715
|
add3(issues, "portable.manifest_invalid", error61.message);
|
|
38711
38716
|
}
|
|
38712
|
-
if (manifest?.kind !== "instruction" && !existsSync12(
|
|
38717
|
+
if (manifest?.kind !== "instruction" && !existsSync12(join33(skillPath, "AGENTS.md"))) {
|
|
38713
38718
|
add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
38714
38719
|
}
|
|
38715
38720
|
}
|
|
@@ -38847,8 +38852,8 @@ var init_registry_types = __esm(() => {
|
|
|
38847
38852
|
});
|
|
38848
38853
|
|
|
38849
38854
|
// src/lib/registry.ts
|
|
38850
|
-
import { existsSync as existsSync13, readFileSync as
|
|
38851
|
-
import { join as
|
|
38855
|
+
import { existsSync as existsSync13, readFileSync as readFileSync19, readdirSync as readdirSync11 } from "fs";
|
|
38856
|
+
import { join as join34 } from "path";
|
|
38852
38857
|
function parseSkillMdFrontmatter(content) {
|
|
38853
38858
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
38854
38859
|
if (!match)
|
|
@@ -38885,16 +38890,16 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
38885
38890
|
return [];
|
|
38886
38891
|
const result = [];
|
|
38887
38892
|
try {
|
|
38888
|
-
const entries =
|
|
38893
|
+
const entries = readdirSync11(dir, { withFileTypes: true });
|
|
38889
38894
|
for (const entry of entries) {
|
|
38890
38895
|
if (!entry.isDirectory())
|
|
38891
38896
|
continue;
|
|
38892
|
-
const skillMdPath =
|
|
38897
|
+
const skillMdPath = join34(dir, entry.name, "SKILL.md");
|
|
38893
38898
|
if (!existsSync13(skillMdPath))
|
|
38894
38899
|
continue;
|
|
38895
38900
|
let content;
|
|
38896
38901
|
try {
|
|
38897
|
-
content =
|
|
38902
|
+
content = readFileSync19(skillMdPath, "utf-8");
|
|
38898
38903
|
} catch {
|
|
38899
38904
|
continue;
|
|
38900
38905
|
}
|
|
@@ -38909,7 +38914,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
38909
38914
|
category: fm.category || "Development Tools",
|
|
38910
38915
|
tags: fm.tags || [],
|
|
38911
38916
|
...fm.kind ? { kind: fm.kind } : {},
|
|
38912
|
-
...isHostedMetadataSkillDir(
|
|
38917
|
+
...isHostedMetadataSkillDir(join34(dir, entry.name)) ? { serverOwned: true } : {},
|
|
38913
38918
|
source
|
|
38914
38919
|
});
|
|
38915
38920
|
}
|
|
@@ -38921,17 +38926,17 @@ function findExtensionSkillPath(name) {
|
|
|
38921
38926
|
if (!config2.extensionsDir || !existsSync13(config2.extensionsDir))
|
|
38922
38927
|
return null;
|
|
38923
38928
|
try {
|
|
38924
|
-
const entries =
|
|
38929
|
+
const entries = readdirSync11(config2.extensionsDir, { withFileTypes: true });
|
|
38925
38930
|
for (const entry of entries) {
|
|
38926
38931
|
if (!entry.isDirectory())
|
|
38927
38932
|
continue;
|
|
38928
|
-
const skillDir =
|
|
38929
|
-
const skillMdPath =
|
|
38933
|
+
const skillDir = join34(config2.extensionsDir, entry.name);
|
|
38934
|
+
const skillMdPath = join34(skillDir, "SKILL.md");
|
|
38930
38935
|
if (!existsSync13(skillMdPath))
|
|
38931
38936
|
continue;
|
|
38932
38937
|
let content;
|
|
38933
38938
|
try {
|
|
38934
|
-
content =
|
|
38939
|
+
content = readFileSync19(skillMdPath, "utf-8");
|
|
38935
38940
|
} catch {
|
|
38936
38941
|
continue;
|
|
38937
38942
|
}
|
|
@@ -40143,14 +40148,14 @@ var init_remote_workspace_leave = __esm(() => {
|
|
|
40143
40148
|
});
|
|
40144
40149
|
|
|
40145
40150
|
// src/lib/auth-store.ts
|
|
40146
|
-
import { chmodSync, existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as
|
|
40147
|
-
import { basename as
|
|
40151
|
+
import { chmodSync, existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync20, renameSync as renameSync4, statSync as statSync10, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
40152
|
+
import { basename as basename16, dirname as dirname25, join as join35 } from "path";
|
|
40148
40153
|
function getAuthFilePath(env = process.env) {
|
|
40149
40154
|
return skillsCredentialFilePath(env);
|
|
40150
40155
|
}
|
|
40151
40156
|
function getIdentityFilePath(env = process.env) {
|
|
40152
40157
|
const file2 = skillsCredentialFilePath(env);
|
|
40153
|
-
return
|
|
40158
|
+
return join35(dirname25(file2), basename16(file2).replace(/^credentials/, "identity") + ".json");
|
|
40154
40159
|
}
|
|
40155
40160
|
function getApiUrl(action, env = process.env, options = {}) {
|
|
40156
40161
|
return requireSkillsApiOrigin(action, env, options);
|
|
@@ -40485,6 +40490,130 @@ var init_remote_permissions = __esm(() => {
|
|
|
40485
40490
|
};
|
|
40486
40491
|
});
|
|
40487
40492
|
|
|
40493
|
+
// src/lib/revision.ts
|
|
40494
|
+
import { createHash as createHash26 } from "crypto";
|
|
40495
|
+
function revisionIdOf(content) {
|
|
40496
|
+
const canonicalContent = {
|
|
40497
|
+
slug: content.slug,
|
|
40498
|
+
displayName: content.displayName,
|
|
40499
|
+
description: content.description,
|
|
40500
|
+
category: content.category,
|
|
40501
|
+
tags: content.tags,
|
|
40502
|
+
source: content.source,
|
|
40503
|
+
kind: content.kind,
|
|
40504
|
+
version: content.version ?? null,
|
|
40505
|
+
skillMd: content.skillMd ?? null,
|
|
40506
|
+
bundleSha256: content.bundleSha256 ?? null,
|
|
40507
|
+
bundleByteSize: content.bundleByteSize ?? null
|
|
40508
|
+
};
|
|
40509
|
+
if (content.lifecycle === "archived" || content.archiveReason !== undefined || content.replacementSlug !== undefined) {
|
|
40510
|
+
canonicalContent.lifecycle = content.lifecycle ?? "active";
|
|
40511
|
+
canonicalContent.archiveReason = content.archiveReason ?? null;
|
|
40512
|
+
canonicalContent.replacementSlug = content.replacementSlug ?? null;
|
|
40513
|
+
}
|
|
40514
|
+
const canonical9 = JSON.stringify(canonicalContent);
|
|
40515
|
+
return createHash26("sha256").update(canonical9).digest("hex");
|
|
40516
|
+
}
|
|
40517
|
+
var REVISION_ID_PATTERN;
|
|
40518
|
+
var init_revision = __esm(() => {
|
|
40519
|
+
REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
40520
|
+
});
|
|
40521
|
+
|
|
40522
|
+
// src/lib/skill-metadata-update.ts
|
|
40523
|
+
function metadataPatch(value) {
|
|
40524
|
+
if (!object7(value))
|
|
40525
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_PATCH");
|
|
40526
|
+
const keys2 = Object.keys(value);
|
|
40527
|
+
if (!keys2.length || keys2.some((key2) => !["category", "tags"].includes(key2)))
|
|
40528
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_PATCH");
|
|
40529
|
+
const copy = {};
|
|
40530
|
+
if (Object.hasOwn(value, "category"))
|
|
40531
|
+
copy.category = value.category;
|
|
40532
|
+
if (Object.hasOwn(value, "tags")) {
|
|
40533
|
+
const tags = value.tags;
|
|
40534
|
+
copy.tags = Array.isArray(tags) ? Array.from(tags) : tags;
|
|
40535
|
+
}
|
|
40536
|
+
if (Object.hasOwn(copy, "category") && !text3(copy.category))
|
|
40537
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_PATCH");
|
|
40538
|
+
if (Object.hasOwn(copy, "tags") && (!Array.isArray(copy.tags) || copy.tags.length > 100 || copy.tags.some((tag) => !text3(tag)) || new Set(copy.tags).size !== copy.tags.length))
|
|
40539
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_PATCH");
|
|
40540
|
+
return copy;
|
|
40541
|
+
}
|
|
40542
|
+
function metadataSnapshot(value, etag) {
|
|
40543
|
+
if (!object7(value) || !text3(value.slug) || !/^[a-z0-9][a-z0-9._-]*$/.test(value.slug) || ![value.displayName, value.description, value.category, value.publishedSource].every((field3) => typeof field3 === "string") || !Array.isArray(value.tags) || value.tags.some((tag) => typeof tag !== "string") || !["instruction", "executable"].includes(String(value.kind)) || typeof value.revisionId !== "string" || !REVISION_ID_PATTERN.test(value.revisionId) || etag !== `"${value.revisionId}"`)
|
|
40544
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_SNAPSHOT");
|
|
40545
|
+
const content = {
|
|
40546
|
+
slug: value.slug,
|
|
40547
|
+
displayName: value.displayName,
|
|
40548
|
+
description: value.description,
|
|
40549
|
+
category: value.category,
|
|
40550
|
+
tags: [...value.tags],
|
|
40551
|
+
source: value.publishedSource,
|
|
40552
|
+
kind: value.kind
|
|
40553
|
+
};
|
|
40554
|
+
for (const key2 of ["version", "skillMd", "bundleSha256", "archiveReason", "replacementSlug"]) {
|
|
40555
|
+
if (value[key2] !== undefined) {
|
|
40556
|
+
if (typeof value[key2] !== "string")
|
|
40557
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_SNAPSHOT");
|
|
40558
|
+
content[key2] = value[key2];
|
|
40559
|
+
}
|
|
40560
|
+
}
|
|
40561
|
+
if (value.bundleByteSize !== undefined) {
|
|
40562
|
+
if (!Number.isSafeInteger(value.bundleByteSize) || value.bundleByteSize < 0)
|
|
40563
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_SNAPSHOT");
|
|
40564
|
+
content.bundleByteSize = value.bundleByteSize;
|
|
40565
|
+
}
|
|
40566
|
+
if (value.lifecycle !== undefined) {
|
|
40567
|
+
if (value.lifecycle !== "active" && value.lifecycle !== "archived")
|
|
40568
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_SNAPSHOT");
|
|
40569
|
+
content.lifecycle = value.lifecycle;
|
|
40570
|
+
}
|
|
40571
|
+
if (revisionIdOf(content) !== value.revisionId)
|
|
40572
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_SNAPSHOT");
|
|
40573
|
+
return { content, revisionId: value.revisionId };
|
|
40574
|
+
}
|
|
40575
|
+
function metadataPlan(value) {
|
|
40576
|
+
if (!object7(value) || Object.keys(value).sort().join(",") !== "authority,before,expectedRevisionId,organizationId,originalDocument,patch,schemaVersion" || value.schemaVersion !== 1 || !text3(value.authority) || !text3(value.organizationId) || !object7(value.before) || typeof value.originalDocument !== "string" || Buffer.byteLength(value.originalDocument) > 2 * 1024 * 1024 || typeof value.expectedRevisionId !== "string" || !REVISION_ID_PATTERN.test(value.expectedRevisionId))
|
|
40577
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_PLAN");
|
|
40578
|
+
const before = metadataSnapshot({ ...value.before, publishedSource: value.before.source, revisionId: value.expectedRevisionId }, `"${value.expectedRevisionId}"`).content;
|
|
40579
|
+
let original;
|
|
40580
|
+
try {
|
|
40581
|
+
original = JSON.parse(value.originalDocument);
|
|
40582
|
+
} catch {
|
|
40583
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_PLAN");
|
|
40584
|
+
}
|
|
40585
|
+
const preserved = metadataSnapshot(original, `"${value.expectedRevisionId}"`);
|
|
40586
|
+
if (preserved.revisionId !== value.expectedRevisionId)
|
|
40587
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_PLAN");
|
|
40588
|
+
return {
|
|
40589
|
+
schemaVersion: 1,
|
|
40590
|
+
authority: value.authority,
|
|
40591
|
+
organizationId: value.organizationId,
|
|
40592
|
+
expectedRevisionId: value.expectedRevisionId,
|
|
40593
|
+
originalDocument: value.originalDocument,
|
|
40594
|
+
before,
|
|
40595
|
+
patch: metadataPatch(value.patch)
|
|
40596
|
+
};
|
|
40597
|
+
}
|
|
40598
|
+
var SkillMetadataUpdateError, object7 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), text3 = (value) => typeof value === "string" && value.length > 0 && value.length <= 512 && !/[\x00-\x1f\x7f]/.test(value);
|
|
40599
|
+
var init_skill_metadata_update = __esm(() => {
|
|
40600
|
+
init_revision();
|
|
40601
|
+
SkillMetadataUpdateError = class SkillMetadataUpdateError extends Error {
|
|
40602
|
+
code;
|
|
40603
|
+
constructor(code) {
|
|
40604
|
+
super({
|
|
40605
|
+
METADATA_AUTH_REQUIRED: "Metadata updates require a signed-in Skills connection; use skills login.",
|
|
40606
|
+
INVALID_METADATA_PATCH: "Metadata patch accepts only category (a nonempty string) and tags (an array of unique nonempty strings).",
|
|
40607
|
+
INVALID_METADATA_SNAPSHOT: "The current skill must carry a matching quoted revision ETag and complete verifiable metadata, body and bundle identity.",
|
|
40608
|
+
INVALID_METADATA_PLAN: "The saved metadata plan must name its original revision, authority, organization, complete original content and category/tags-only patch.",
|
|
40609
|
+
METADATA_REVISION_CONFLICT: "The skill revision changed after preview; inspect it and prepare a new plan.",
|
|
40610
|
+
METADATA_UPDATE_UNCONFIRMED: "Metadata update could not be confirmed by authoritative readback; inspect the current revision before preparing another write."
|
|
40611
|
+
}[code]);
|
|
40612
|
+
this.code = code;
|
|
40613
|
+
}
|
|
40614
|
+
};
|
|
40615
|
+
});
|
|
40616
|
+
|
|
40488
40617
|
// src/lib/remote-client.ts
|
|
40489
40618
|
var exports_remote_client = {};
|
|
40490
40619
|
__export(exports_remote_client, {
|
|
@@ -40562,6 +40691,89 @@ class RemoteSkillsClient {
|
|
|
40562
40691
|
return null;
|
|
40563
40692
|
return res.json();
|
|
40564
40693
|
}
|
|
40694
|
+
async metadataOrganization() {
|
|
40695
|
+
const identity4 = await this.getIdentity();
|
|
40696
|
+
const organization2 = identity4.organization;
|
|
40697
|
+
if (typeof organization2?.id !== "string" || !organization2.id)
|
|
40698
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_SNAPSHOT");
|
|
40699
|
+
return organization2.id;
|
|
40700
|
+
}
|
|
40701
|
+
async readMetadataSnapshot(slug2) {
|
|
40702
|
+
const response = await this.request(`/api/v1/skills/${encodeURIComponent(slug2)}`);
|
|
40703
|
+
if (!response.ok)
|
|
40704
|
+
throw new RemoteRequestError("/api/v1/skills/:slug", response.status);
|
|
40705
|
+
const bytes = await readBoundedResponse(response, 2 * 1024 * 1024);
|
|
40706
|
+
const originalDocument = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
40707
|
+
let value;
|
|
40708
|
+
try {
|
|
40709
|
+
value = JSON.parse(originalDocument);
|
|
40710
|
+
} catch {
|
|
40711
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_SNAPSHOT");
|
|
40712
|
+
}
|
|
40713
|
+
const snapshot2 = metadataSnapshot(value, response.headers.get("etag"));
|
|
40714
|
+
if (snapshot2.content.slug !== slug2)
|
|
40715
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_SNAPSHOT");
|
|
40716
|
+
return { ...snapshot2, originalDocument };
|
|
40717
|
+
}
|
|
40718
|
+
async prepareSkillMetadataUpdate(slug2, patch) {
|
|
40719
|
+
const captured = metadataPatch(patch);
|
|
40720
|
+
const organizationId = await this.metadataOrganization();
|
|
40721
|
+
const snapshot2 = await this.readMetadataSnapshot(slug2);
|
|
40722
|
+
return metadataPlan({
|
|
40723
|
+
schemaVersion: 1,
|
|
40724
|
+
authority: this.apiUrl,
|
|
40725
|
+
organizationId,
|
|
40726
|
+
expectedRevisionId: snapshot2.revisionId,
|
|
40727
|
+
originalDocument: snapshot2.originalDocument,
|
|
40728
|
+
before: snapshot2.content,
|
|
40729
|
+
patch: captured
|
|
40730
|
+
});
|
|
40731
|
+
}
|
|
40732
|
+
async applySkillMetadataUpdate(input2) {
|
|
40733
|
+
const plan = metadataPlan(input2);
|
|
40734
|
+
if (plan.authority !== this.apiUrl || await this.metadataOrganization() !== plan.organizationId)
|
|
40735
|
+
throw new SkillMetadataUpdateError("INVALID_METADATA_PLAN");
|
|
40736
|
+
const access = await this.getCapabilities({ refresh: true });
|
|
40737
|
+
if (access.permissions?.publish !== true)
|
|
40738
|
+
throw new RemoteSkillsPermissionError("publish");
|
|
40739
|
+
const current = await this.readMetadataSnapshot(plan.before.slug);
|
|
40740
|
+
if (current.revisionId !== plan.expectedRevisionId)
|
|
40741
|
+
throw new SkillMetadataUpdateError("METADATA_REVISION_CONFLICT");
|
|
40742
|
+
const expected = revisionIdOf({ ...plan.before, ...plan.patch });
|
|
40743
|
+
if (expected === current.revisionId)
|
|
40744
|
+
return { status: "unchanged", revisionId: expected };
|
|
40745
|
+
let uncertain = false;
|
|
40746
|
+
try {
|
|
40747
|
+
const response = await this.request(`/api/v1/skills/${encodeURIComponent(plan.before.slug)}`, {
|
|
40748
|
+
method: "PATCH",
|
|
40749
|
+
headers: { "If-Match": `"${plan.expectedRevisionId}"` },
|
|
40750
|
+
body: JSON.stringify(plan.patch)
|
|
40751
|
+
});
|
|
40752
|
+
if (!response.ok && response.status < 500)
|
|
40753
|
+
throw new RemoteRequestError("/api/v1/skills/:slug", response.status);
|
|
40754
|
+
if (!response.ok)
|
|
40755
|
+
uncertain = true;
|
|
40756
|
+
else {
|
|
40757
|
+
const bytes = await readBoundedResponse(response, 2 * 1024 * 1024);
|
|
40758
|
+
const written = metadataSnapshot(JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes)), response.headers.get("etag"));
|
|
40759
|
+
if (written.revisionId !== expected)
|
|
40760
|
+
throw new SkillMetadataUpdateError("METADATA_UPDATE_UNCONFIRMED");
|
|
40761
|
+
}
|
|
40762
|
+
} catch (error61) {
|
|
40763
|
+
if (error61 instanceof RemoteRequestError && error61.status < 500)
|
|
40764
|
+
throw error61;
|
|
40765
|
+
uncertain = true;
|
|
40766
|
+
}
|
|
40767
|
+
let verified;
|
|
40768
|
+
try {
|
|
40769
|
+
verified = await this.readMetadataSnapshot(plan.before.slug);
|
|
40770
|
+
} catch {
|
|
40771
|
+
throw new SkillMetadataUpdateError("METADATA_UPDATE_UNCONFIRMED");
|
|
40772
|
+
}
|
|
40773
|
+
if (verified.revisionId !== expected)
|
|
40774
|
+
throw new SkillMetadataUpdateError("METADATA_UPDATE_UNCONFIRMED");
|
|
40775
|
+
return { status: uncertain ? "reconciled" : "applied", revisionId: expected };
|
|
40776
|
+
}
|
|
40565
40777
|
async getSkillStatus(slug2) {
|
|
40566
40778
|
const res = await this.request(`/api/v1/skills/${encodeURIComponent(slug2)}`, { method: "GET" });
|
|
40567
40779
|
let body = null;
|
|
@@ -41432,6 +41644,8 @@ var init_remote_client = __esm(() => {
|
|
|
41432
41644
|
init_remote_credit_checkout();
|
|
41433
41645
|
init_remote_quote_errors();
|
|
41434
41646
|
init_remote_permissions();
|
|
41647
|
+
init_skill_metadata_update();
|
|
41648
|
+
init_revision();
|
|
41435
41649
|
RemoteRouteUnsupportedError = class RemoteRouteUnsupportedError extends Error {
|
|
41436
41650
|
path;
|
|
41437
41651
|
status;
|
|
@@ -41619,7 +41833,7 @@ var init_remote_invitation_recovery = __esm(() => {
|
|
|
41619
41833
|
});
|
|
41620
41834
|
|
|
41621
41835
|
// src/lib/remote-private-publications.ts
|
|
41622
|
-
import { createHash as
|
|
41836
|
+
import { createHash as createHash27 } from "crypto";
|
|
41623
41837
|
function checkedPrivateSkillCreate(value) {
|
|
41624
41838
|
const refuse5 = (field3, accepted) => {
|
|
41625
41839
|
throw new PrivatePublicationError("INVALID_SKILL_CREATE_INPUT", `Invalid ${field3}. ${accepted}`);
|
|
@@ -41915,7 +42129,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, skillCreateFailures, failures2, PrivatePublic
|
|
|
41915
42129
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
41916
42130
|
}, invalid4 = () => {
|
|
41917
42131
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
41918
|
-
}, 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), record10 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record10(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) =>
|
|
42132
|
+
}, 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), record10 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record10(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) => createHash27("sha256").update(bytes).digest("hex");
|
|
41919
42133
|
var init_remote_private_publications = __esm(() => {
|
|
41920
42134
|
init_fleet_credentials();
|
|
41921
42135
|
init_remote_workspace_selection();
|
|
@@ -41986,8 +42200,8 @@ async function requestAuthApi(instance, path, options) {
|
|
|
41986
42200
|
apiUrl: safeUrl
|
|
41987
42201
|
});
|
|
41988
42202
|
}
|
|
41989
|
-
const
|
|
41990
|
-
const body =
|
|
42203
|
+
const text4 = await res.text();
|
|
42204
|
+
const body = text4 ? parseJsonBody(text4) : {};
|
|
41991
42205
|
if (!res.ok) {
|
|
41992
42206
|
const record11 = isRecord6(body) ? body : {};
|
|
41993
42207
|
const detail = typeof record11.detail === "string" ? record11.detail : undefined;
|
|
@@ -42003,15 +42217,15 @@ async function requestAuthApi(instance, path, options) {
|
|
|
42003
42217
|
}
|
|
42004
42218
|
return body;
|
|
42005
42219
|
}
|
|
42006
|
-
function parseJsonBody(
|
|
42220
|
+
function parseJsonBody(text4) {
|
|
42007
42221
|
try {
|
|
42008
|
-
return JSON.parse(
|
|
42222
|
+
return JSON.parse(text4);
|
|
42009
42223
|
} catch {
|
|
42010
|
-
return { detail: condenseErrorBody(
|
|
42224
|
+
return { detail: condenseErrorBody(text4) };
|
|
42011
42225
|
}
|
|
42012
42226
|
}
|
|
42013
|
-
function condenseErrorBody(
|
|
42014
|
-
const stripped = /<[a-z!/]/i.test(
|
|
42227
|
+
function condenseErrorBody(text4) {
|
|
42228
|
+
const stripped = /<[a-z!/]/i.test(text4) ? text4.replace(/<(script|style)[\s\S]*?<\/\1>/gi, " ").replace(/<[^>]*>/g, " ") : text4;
|
|
42015
42229
|
const collapsed = stripped.replace(/\s+/g, " ").trim();
|
|
42016
42230
|
if (collapsed.length <= MAX_ERROR_DETAIL_LENGTH)
|
|
42017
42231
|
return collapsed;
|
|
@@ -42202,10 +42416,10 @@ var init_remote_auth = __esm(() => {
|
|
|
42202
42416
|
});
|
|
42203
42417
|
|
|
42204
42418
|
// src/lib/workspace-profile.ts
|
|
42205
|
-
import { constants as constants17, closeSync as closeSync19, fstatSync as fstatSync19, lstatSync as
|
|
42419
|
+
import { constants as constants17, closeSync as closeSync19, fstatSync as fstatSync19, lstatSync as lstatSync26, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync2, openSync as openSync19, readFileSync as readFileSync21, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
42206
42420
|
function stat2(path) {
|
|
42207
42421
|
try {
|
|
42208
|
-
return
|
|
42422
|
+
return lstatSync26(path);
|
|
42209
42423
|
} catch (error61) {
|
|
42210
42424
|
if (error61.code === "ENOENT")
|
|
42211
42425
|
return null;
|
|
@@ -42220,18 +42434,18 @@ function safeText(file2) {
|
|
|
42220
42434
|
const s = fstatSync19(fd);
|
|
42221
42435
|
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
42222
42436
|
return fail("The selected profile must use bounded owner-only regular files.");
|
|
42223
|
-
return
|
|
42437
|
+
return readFileSync21(fd, "utf8");
|
|
42224
42438
|
} finally {
|
|
42225
42439
|
closeSync19(fd);
|
|
42226
42440
|
}
|
|
42227
42441
|
}
|
|
42228
42442
|
function checkIdentityMetadata(file2, identity4) {
|
|
42229
|
-
const
|
|
42230
|
-
if (
|
|
42443
|
+
const text4 = safeText(file2);
|
|
42444
|
+
if (text4 === null)
|
|
42231
42445
|
return;
|
|
42232
42446
|
let value;
|
|
42233
42447
|
try {
|
|
42234
|
-
value = JSON.parse(
|
|
42448
|
+
value = JSON.parse(text4);
|
|
42235
42449
|
} catch {
|
|
42236
42450
|
return fail("The profile identity metadata is invalid. Sign in again before managing this workspace.");
|
|
42237
42451
|
}
|
|
@@ -42434,8 +42648,8 @@ var init_recurring_customer = __esm(() => {
|
|
|
42434
42648
|
});
|
|
42435
42649
|
|
|
42436
42650
|
// src/lib/recurring-recovery.ts
|
|
42437
|
-
import { constants as constants18, closeSync as closeSync20, fsyncSync as fsyncSync5, fstatSync as fstatSync20, lstatSync as
|
|
42438
|
-
import { dirname as
|
|
42651
|
+
import { constants as constants18, closeSync as closeSync20, fsyncSync as fsyncSync5, fstatSync as fstatSync20, lstatSync as lstatSync27, mkdirSync as mkdirSync11, openSync as openSync20, readSync as readSync13, realpathSync as realpathSync11, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync9 } from "fs";
|
|
42652
|
+
import { dirname as dirname26, isAbsolute as isAbsolute24, join as join36, resolve as resolve25 } from "path";
|
|
42439
42653
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
42440
42654
|
|
|
42441
42655
|
class RecoveryOwner {
|
|
@@ -42445,12 +42659,12 @@ class RecoveryOwner {
|
|
|
42445
42659
|
this.directory = directory;
|
|
42446
42660
|
if (!isAbsolute24(directory) || resolve25(directory) !== directory || realpathSync11(directory) !== directory)
|
|
42447
42661
|
invalid5();
|
|
42448
|
-
for (let path = directory;; path =
|
|
42449
|
-
const stat3 =
|
|
42662
|
+
for (let path = directory;; path = dirname26(path)) {
|
|
42663
|
+
const stat3 = lstatSync27(path);
|
|
42450
42664
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
42451
42665
|
invalid5();
|
|
42452
42666
|
this.parents.push({ path, dev: stat3.dev, ino: stat3.ino });
|
|
42453
|
-
if (path ===
|
|
42667
|
+
if (path === dirname26(path))
|
|
42454
42668
|
break;
|
|
42455
42669
|
}
|
|
42456
42670
|
this.assert();
|
|
@@ -42459,17 +42673,17 @@ class RecoveryOwner {
|
|
|
42459
42673
|
if (realpathSync11(this.directory) !== this.directory)
|
|
42460
42674
|
invalid5();
|
|
42461
42675
|
for (const prior of this.parents) {
|
|
42462
|
-
const now =
|
|
42676
|
+
const now = lstatSync27(prior.path);
|
|
42463
42677
|
if (!now.isDirectory() || now.isSymbolicLink() || now.dev !== prior.dev || now.ino !== prior.ino)
|
|
42464
42678
|
invalid5();
|
|
42465
42679
|
}
|
|
42466
|
-
const own2 =
|
|
42680
|
+
const own2 = lstatSync27(this.directory);
|
|
42467
42681
|
if ((own2.mode & 511) !== 448 || (own2.mode & 3584) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
42468
42682
|
invalid5();
|
|
42469
42683
|
}
|
|
42470
42684
|
read(name) {
|
|
42471
42685
|
this.assert();
|
|
42472
|
-
const fd = openSync20(
|
|
42686
|
+
const fd = openSync20(join36(this.directory, name), constants18.O_RDONLY | constants18.O_NOFOLLOW | constants18.O_NONBLOCK);
|
|
42473
42687
|
try {
|
|
42474
42688
|
const before = fstatSync20(fd);
|
|
42475
42689
|
if (!before.isFile() || before.nlink !== 1 || (before.mode & 4095) !== 384 || before.size < 1 || before.size > 8192 || process.getuid && before.uid !== process.getuid())
|
|
@@ -42482,7 +42696,7 @@ class RecoveryOwner {
|
|
|
42482
42696
|
break;
|
|
42483
42697
|
size += n2;
|
|
42484
42698
|
}
|
|
42485
|
-
const after = fstatSync20(fd), path =
|
|
42699
|
+
const after = fstatSync20(fd), path = lstatSync27(join36(this.directory, name));
|
|
42486
42700
|
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())
|
|
42487
42701
|
invalid5();
|
|
42488
42702
|
this.assert();
|
|
@@ -42495,7 +42709,7 @@ class RecoveryOwner {
|
|
|
42495
42709
|
this.assert();
|
|
42496
42710
|
const bytes = canonicalJson2(value, 8192) + `
|
|
42497
42711
|
`;
|
|
42498
|
-
const fd = openSync20(
|
|
42712
|
+
const fd = openSync20(join36(this.directory, name), constants18.O_WRONLY | constants18.O_CREAT | constants18.O_EXCL | constants18.O_NOFOLLOW, 384);
|
|
42499
42713
|
try {
|
|
42500
42714
|
writeFileSync9(fd, bytes);
|
|
42501
42715
|
fsyncSync5(fd);
|
|
@@ -42522,14 +42736,14 @@ class RecoveryOwner {
|
|
|
42522
42736
|
if (this.read("state.json") !== expected)
|
|
42523
42737
|
invalid5();
|
|
42524
42738
|
this.assert();
|
|
42525
|
-
renameSync6(
|
|
42739
|
+
renameSync6(join36(this.directory, name), join36(this.directory, "state.json"));
|
|
42526
42740
|
this.sync();
|
|
42527
42741
|
}
|
|
42528
42742
|
async locked(action) {
|
|
42529
42743
|
this.assert();
|
|
42530
42744
|
let fd;
|
|
42531
42745
|
try {
|
|
42532
|
-
fd = openSync20(
|
|
42746
|
+
fd = openSync20(join36(this.directory, "operation.lock"), constants18.O_WRONLY | constants18.O_CREAT | constants18.O_EXCL | constants18.O_NOFOLLOW, 384);
|
|
42533
42747
|
} catch {
|
|
42534
42748
|
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.");
|
|
42535
42749
|
}
|
|
@@ -42542,10 +42756,10 @@ class RecoveryOwner {
|
|
|
42542
42756
|
} finally {
|
|
42543
42757
|
closeSync20(fd);
|
|
42544
42758
|
this.assert();
|
|
42545
|
-
const now =
|
|
42759
|
+
const now = lstatSync27(join36(this.directory, "operation.lock"));
|
|
42546
42760
|
if (owner2.dev !== now.dev || owner2.ino !== now.ino || !now.isFile() || now.isSymbolicLink())
|
|
42547
42761
|
invalid5();
|
|
42548
|
-
unlinkSync5(
|
|
42762
|
+
unlinkSync5(join36(this.directory, "operation.lock"));
|
|
42549
42763
|
this.sync();
|
|
42550
42764
|
}
|
|
42551
42765
|
}
|
|
@@ -42578,7 +42792,7 @@ function base(customer, organizationId) {
|
|
|
42578
42792
|
};
|
|
42579
42793
|
}
|
|
42580
42794
|
function create(directory, intent) {
|
|
42581
|
-
if (!isAbsolute24(directory) || resolve25(directory) !== directory || realpathSync11(
|
|
42795
|
+
if (!isAbsolute24(directory) || resolve25(directory) !== directory || realpathSync11(dirname26(directory)) !== dirname26(directory))
|
|
42582
42796
|
invalid5();
|
|
42583
42797
|
mkdirSync11(directory, { mode: 448 });
|
|
42584
42798
|
const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -44315,17 +44529,17 @@ var init_tool_primitives = __esm(() => {
|
|
|
44315
44529
|
|
|
44316
44530
|
// src/lib/compact-output.ts
|
|
44317
44531
|
function truncateText(value, maxChars = 96) {
|
|
44318
|
-
const
|
|
44319
|
-
if (
|
|
44320
|
-
return
|
|
44321
|
-
return `${
|
|
44532
|
+
const text4 = String(value ?? "").replace(/\s+/g, " ").trim();
|
|
44533
|
+
if (text4.length <= maxChars)
|
|
44534
|
+
return text4;
|
|
44535
|
+
return `${text4.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
|
|
44322
44536
|
}
|
|
44323
44537
|
function previewText(value, maxChars = DEFAULT_PREVIEW_CHARS) {
|
|
44324
|
-
const
|
|
44538
|
+
const text4 = String(value ?? "");
|
|
44325
44539
|
return {
|
|
44326
|
-
text:
|
|
44327
|
-
length:
|
|
44328
|
-
truncated:
|
|
44540
|
+
text: text4.length > maxChars ? `${text4.slice(0, Math.max(0, maxChars - 3))}...` : text4,
|
|
44541
|
+
length: text4.length,
|
|
44542
|
+
truncated: text4.length > maxChars
|
|
44329
44543
|
};
|
|
44330
44544
|
}
|
|
44331
44545
|
function parsePageLimit(value, fallback, options = {}) {
|
|
@@ -44675,21 +44889,21 @@ var init_credential_state = __esm(() => {
|
|
|
44675
44889
|
});
|
|
44676
44890
|
|
|
44677
44891
|
// src/lib/run-state.ts
|
|
44678
|
-
import { createHash as
|
|
44679
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as
|
|
44680
|
-
import { extname, join as
|
|
44892
|
+
import { createHash as createHash28, randomBytes } from "crypto";
|
|
44893
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync22, readdirSync as readdirSync12, statSync as statSync11, writeFileSync as writeFileSync10 } from "fs";
|
|
44894
|
+
import { extname, join as join37, relative as relative9 } from "path";
|
|
44681
44895
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
44682
44896
|
const now = new Date;
|
|
44683
44897
|
const id = createRunId(now);
|
|
44684
44898
|
const day = now.toISOString().slice(0, 10);
|
|
44685
44899
|
const skillName = normalizeSkillName(params.skill);
|
|
44686
44900
|
const root = getProjectStateDir(targetDir);
|
|
44687
|
-
const runDir =
|
|
44688
|
-
const logsDir =
|
|
44689
|
-
const exportDir =
|
|
44901
|
+
const runDir = join37(root, "runs", day, id);
|
|
44902
|
+
const logsDir = join37(runDir, "logs");
|
|
44903
|
+
const exportDir = join37(root, "exports", skillName, id);
|
|
44690
44904
|
mkdirSync12(logsDir, { recursive: true });
|
|
44691
44905
|
mkdirSync12(exportDir, { recursive: true });
|
|
44692
|
-
mkdirSync12(
|
|
44906
|
+
mkdirSync12(join37(root, "tmp"), { recursive: true });
|
|
44693
44907
|
const record11 = {
|
|
44694
44908
|
id,
|
|
44695
44909
|
skill: skillName,
|
|
@@ -44741,22 +44955,22 @@ function updateSkillRun(context2, patch) {
|
|
|
44741
44955
|
return context2.record;
|
|
44742
44956
|
}
|
|
44743
44957
|
function writeRunLogs(context2, stdout = "", stderr = "") {
|
|
44744
|
-
writeFileSync10(
|
|
44745
|
-
writeFileSync10(
|
|
44958
|
+
writeFileSync10(join37(context2.logsDir, "stdout.log"), stdout);
|
|
44959
|
+
writeFileSync10(join37(context2.logsDir, "stderr.log"), stderr);
|
|
44746
44960
|
}
|
|
44747
44961
|
function appendRunEvent(context2, event, data = {}) {
|
|
44748
44962
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
44749
44963
|
`;
|
|
44750
|
-
const path =
|
|
44751
|
-
const previous = existsSync15(path) ?
|
|
44964
|
+
const path = join37(context2.runDir, "events.ndjson");
|
|
44965
|
+
const previous = existsSync15(path) ? readFileSync22(path, "utf-8") : "";
|
|
44752
44966
|
writeFileSync10(path, previous + line);
|
|
44753
44967
|
}
|
|
44754
44968
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
44755
|
-
const runsRoot =
|
|
44969
|
+
const runsRoot = join37(getProjectStateDir(targetDir), "runs");
|
|
44756
44970
|
if (!existsSync15(runsRoot))
|
|
44757
44971
|
return null;
|
|
44758
|
-
for (const day of
|
|
44759
|
-
const record11 = readRunRecord(
|
|
44972
|
+
for (const day of readdirSync12(runsRoot)) {
|
|
44973
|
+
const record11 = readRunRecord(join37(runsRoot, day, runId));
|
|
44760
44974
|
if (record11)
|
|
44761
44975
|
return record11;
|
|
44762
44976
|
}
|
|
@@ -44773,11 +44987,11 @@ function skillRunEnv(context2) {
|
|
|
44773
44987
|
};
|
|
44774
44988
|
}
|
|
44775
44989
|
function writeRunRecord(context2) {
|
|
44776
|
-
writeFileSync10(
|
|
44990
|
+
writeFileSync10(join37(context2.runDir, "run.json"), JSON.stringify(context2.record, null, 2) + `
|
|
44777
44991
|
`);
|
|
44778
44992
|
}
|
|
44779
44993
|
function writeArtifactsManifest(context2, artifacts) {
|
|
44780
|
-
writeFileSync10(
|
|
44994
|
+
writeFileSync10(join37(context2.runDir, "artifacts.json"), JSON.stringify({ runId: context2.record.id, artifacts }, null, 2) + `
|
|
44781
44995
|
`);
|
|
44782
44996
|
}
|
|
44783
44997
|
function collectRunArtifacts(context2) {
|
|
@@ -44786,30 +45000,30 @@ function collectRunArtifacts(context2) {
|
|
|
44786
45000
|
const artifacts = [];
|
|
44787
45001
|
for (const path of walkFiles(context2.exportDir)) {
|
|
44788
45002
|
const stat3 = statSync11(path);
|
|
44789
|
-
const bytes =
|
|
45003
|
+
const bytes = readFileSync22(path);
|
|
44790
45004
|
artifacts.push({
|
|
44791
45005
|
path: toProjectRelative(context2.targetDir, path),
|
|
44792
45006
|
mime: mimeForPath(path),
|
|
44793
|
-
sha256:
|
|
45007
|
+
sha256: createHash28("sha256").update(bytes).digest("hex"),
|
|
44794
45008
|
sizeBytes: stat3.size
|
|
44795
45009
|
});
|
|
44796
45010
|
}
|
|
44797
45011
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
44798
45012
|
}
|
|
44799
45013
|
function readRunRecord(runDir) {
|
|
44800
|
-
const path =
|
|
45014
|
+
const path = join37(runDir, "run.json");
|
|
44801
45015
|
if (!existsSync15(path))
|
|
44802
45016
|
return null;
|
|
44803
45017
|
try {
|
|
44804
|
-
return JSON.parse(
|
|
45018
|
+
return JSON.parse(readFileSync22(path, "utf-8"));
|
|
44805
45019
|
} catch {
|
|
44806
45020
|
return null;
|
|
44807
45021
|
}
|
|
44808
45022
|
}
|
|
44809
45023
|
function walkFiles(dir) {
|
|
44810
45024
|
const files = [];
|
|
44811
|
-
for (const entry of
|
|
44812
|
-
const full =
|
|
45025
|
+
for (const entry of readdirSync12(dir)) {
|
|
45026
|
+
const full = join37(dir, entry);
|
|
44813
45027
|
if (statSync11(full).isDirectory())
|
|
44814
45028
|
files.push(...walkFiles(full));
|
|
44815
45029
|
else
|
|
@@ -45062,11 +45276,11 @@ var init_cloud_executions = __esm(() => {
|
|
|
45062
45276
|
// node_modules/@hasna/secrets/dist/sdk.js
|
|
45063
45277
|
import { isIP as isIP2 } from "net";
|
|
45064
45278
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
45065
|
-
import { closeSync as closeSync21, fstatSync as fstatSync21, openSync as openSync21, readFileSync as
|
|
45279
|
+
import { closeSync as closeSync21, fstatSync as fstatSync21, openSync as openSync21, readFileSync as readFileSync23 } from "fs";
|
|
45066
45280
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
45067
45281
|
import { createRequire as createRequire2 } from "module";
|
|
45068
45282
|
import { hostname as osHostname2 } from "os";
|
|
45069
|
-
import { isAbsolute as isAbsolute26, join as
|
|
45283
|
+
import { isAbsolute as isAbsolute26, join as join38 } from "path";
|
|
45070
45284
|
import { createRequire as createRequire22 } from "module";
|
|
45071
45285
|
function envToken2(name) {
|
|
45072
45286
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -45097,14 +45311,14 @@ function hasnaHomeDir2(env) {
|
|
|
45097
45311
|
if (override)
|
|
45098
45312
|
return override;
|
|
45099
45313
|
const home = homeDir2(env);
|
|
45100
|
-
return home ?
|
|
45314
|
+
return home ? join38(home, HASNA_HOME_DIR2) : null;
|
|
45101
45315
|
}
|
|
45102
45316
|
function appConfigDir2(name, env) {
|
|
45103
45317
|
const configRoot = absoluteOverride2(env, HASNA_CONFIG_HOME_ENV_KEY2);
|
|
45104
45318
|
if (configRoot)
|
|
45105
|
-
return
|
|
45319
|
+
return join38(configRoot, name);
|
|
45106
45320
|
const root = hasnaHomeDir2(env);
|
|
45107
|
-
return root ?
|
|
45321
|
+
return root ? join38(root, name, CONFIG_SUBDIR2) : null;
|
|
45108
45322
|
}
|
|
45109
45323
|
function credentialDiskSourceList2(name, env, profile = null) {
|
|
45110
45324
|
if (!SAFE_APP_SLUG2.test(name))
|
|
@@ -45113,7 +45327,7 @@ function credentialDiskSourceList2(name, env, profile = null) {
|
|
|
45113
45327
|
if (!directory2)
|
|
45114
45328
|
return [];
|
|
45115
45329
|
const file2 = profile ? `${CREDENTIALS_FILE2}-${profile}` : CREDENTIALS_FILE2;
|
|
45116
|
-
return [{ path:
|
|
45330
|
+
return [{ path: join38(directory2, file2), tier: "disk" }];
|
|
45117
45331
|
}
|
|
45118
45332
|
function credentialDiskSources2(name, env) {
|
|
45119
45333
|
return credentialDiskSourceList2(name, env, null).map((s) => s.path);
|
|
@@ -45121,10 +45335,10 @@ function credentialDiskSources2(name, env) {
|
|
|
45121
45335
|
function profileDiskSources2(name, env, profile) {
|
|
45122
45336
|
return credentialDiskSourceList2(name, env, profile).map((s) => s.path);
|
|
45123
45337
|
}
|
|
45124
|
-
function parseEnvFile2(
|
|
45338
|
+
function parseEnvFile2(text4) {
|
|
45125
45339
|
const values = new Map;
|
|
45126
45340
|
const unusable = new Set;
|
|
45127
|
-
for (const rawLine of
|
|
45341
|
+
for (const rawLine of text4.split(/\r?\n/)) {
|
|
45128
45342
|
const line = rawLine.trim();
|
|
45129
45343
|
if (line.length === 0 || line.startsWith("#"))
|
|
45130
45344
|
continue;
|
|
@@ -45188,7 +45402,7 @@ function readAppConfigFile2(path) {
|
|
|
45188
45402
|
unsafe("the file is not owned by the current user");
|
|
45189
45403
|
if (before.size > MAX_CREDENTIAL_FILE_BYTES2)
|
|
45190
45404
|
unsafe("the file exceeds the size limit");
|
|
45191
|
-
const bytes =
|
|
45405
|
+
const bytes = readFileSync23(fd);
|
|
45192
45406
|
const after = fstatSync21(fd);
|
|
45193
45407
|
if (!configFileReadsCoherent2(before, after)) {
|
|
45194
45408
|
unsafe("the file changed while being read");
|
|
@@ -45364,8 +45578,8 @@ function keychainAccount2(env, options) {
|
|
|
45364
45578
|
const user = env.USER?.trim();
|
|
45365
45579
|
return user || null;
|
|
45366
45580
|
}
|
|
45367
|
-
function keychainFailureHint2(
|
|
45368
|
-
const line =
|
|
45581
|
+
function keychainFailureHint2(text4) {
|
|
45582
|
+
const line = text4.split(/\r?\n/).find((entry) => entry.trim().length > 0)?.trim() ?? "";
|
|
45369
45583
|
const clean = line.replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 200);
|
|
45370
45584
|
return clean ? `: ${clean}` : "";
|
|
45371
45585
|
}
|
|
@@ -45943,12 +46157,12 @@ function createHasnaHttpTransportInternal(options, requestBindingProvider) {
|
|
|
45943
46157
|
await response.body?.cancel();
|
|
45944
46158
|
} catch {}
|
|
45945
46159
|
} else {
|
|
45946
|
-
const
|
|
45947
|
-
if (
|
|
46160
|
+
const text4 = await response.text();
|
|
46161
|
+
if (text4.length > 0) {
|
|
45948
46162
|
try {
|
|
45949
|
-
parsed = JSON.parse(
|
|
46163
|
+
parsed = JSON.parse(text4);
|
|
45950
46164
|
} catch {
|
|
45951
|
-
parsed =
|
|
46165
|
+
parsed = text4;
|
|
45952
46166
|
}
|
|
45953
46167
|
}
|
|
45954
46168
|
}
|
|
@@ -46051,13 +46265,13 @@ class SecretsClient {
|
|
|
46051
46265
|
headers,
|
|
46052
46266
|
redirect: "manual"
|
|
46053
46267
|
});
|
|
46054
|
-
const
|
|
46268
|
+
const text4 = await response.text();
|
|
46055
46269
|
let body = undefined;
|
|
46056
|
-
if (
|
|
46270
|
+
if (text4) {
|
|
46057
46271
|
try {
|
|
46058
|
-
body = JSON.parse(
|
|
46272
|
+
body = JSON.parse(text4);
|
|
46059
46273
|
} catch {
|
|
46060
|
-
body =
|
|
46274
|
+
body = text4;
|
|
46061
46275
|
}
|
|
46062
46276
|
}
|
|
46063
46277
|
if (!response.ok) {
|
|
@@ -46459,7 +46673,7 @@ async function resolveSelectedSecrets(bindings, createClient = createSecretsClie
|
|
|
46459
46673
|
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.");
|
|
46460
46674
|
}
|
|
46461
46675
|
}
|
|
46462
|
-
function redactExecutionSecrets(
|
|
46676
|
+
function redactExecutionSecrets(text4, env) {
|
|
46463
46677
|
const values = new Set(Object.values(env).flatMap((value) => {
|
|
46464
46678
|
let encoded = "";
|
|
46465
46679
|
try {
|
|
@@ -46468,8 +46682,8 @@ function redactExecutionSecrets(text3, env) {
|
|
|
46468
46682
|
return [value, JSON.stringify(value).slice(1, -1), Buffer.from(value).toString("base64"), encoded];
|
|
46469
46683
|
}));
|
|
46470
46684
|
for (const value of [...values].filter(Boolean).sort((a, b) => b.length - a.length))
|
|
46471
|
-
|
|
46472
|
-
return
|
|
46685
|
+
text4 = text4.split(value).join("[REDACTED]");
|
|
46686
|
+
return text4;
|
|
46473
46687
|
}
|
|
46474
46688
|
var init_execution_secrets = __esm(() => {
|
|
46475
46689
|
init_sdk();
|
|
@@ -46608,10 +46822,10 @@ __export(exports_selected_run, {
|
|
|
46608
46822
|
executeSelectedLocal: () => executeSelectedLocal,
|
|
46609
46823
|
declaredOperation: () => declaredOperation
|
|
46610
46824
|
});
|
|
46611
|
-
import { createHash as
|
|
46825
|
+
import { createHash as createHash29 } from "crypto";
|
|
46612
46826
|
import { spawn as spawn2 } from "child_process";
|
|
46613
46827
|
import { mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync11, realpathSync as realpathSync13 } from "fs";
|
|
46614
|
-
import { dirname as
|
|
46828
|
+
import { dirname as dirname27, join as join39, resolve as resolve26 } from "path";
|
|
46615
46829
|
import { tmpdir, hostname as stationHostname2 } from "os";
|
|
46616
46830
|
async function resolveSelectedRun(spec, profileId, options = {}) {
|
|
46617
46831
|
const context2 = await resolveSelectionContext(profileId, options);
|
|
@@ -46734,7 +46948,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
46734
46948
|
throw new SkillSelectionError("INVALID_SECRET_BINDINGS", "Explicit environment values must be bounded strings without NUL bytes.");
|
|
46735
46949
|
secretEnv[name] = value;
|
|
46736
46950
|
}
|
|
46737
|
-
const runDirectory = mkdtempSync3(
|
|
46951
|
+
const runDirectory = mkdtempSync3(join39(tmpdir(), "skills-execution-"));
|
|
46738
46952
|
const paths = new SkillEntryPaths;
|
|
46739
46953
|
for (const entry of entries) {
|
|
46740
46954
|
paths.add(entry.path, 100, () => {
|
|
@@ -46742,8 +46956,8 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
46742
46956
|
}, () => {
|
|
46743
46957
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
46744
46958
|
});
|
|
46745
|
-
const destination =
|
|
46746
|
-
mkdirSync13(
|
|
46959
|
+
const destination = join39(runDirectory, entry.path);
|
|
46960
|
+
mkdirSync13(dirname27(destination), { recursive: true, mode: 448 });
|
|
46747
46961
|
writeFileSync11(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
46748
46962
|
}
|
|
46749
46963
|
env.SKILLS_INPUT_JSON = input2;
|
|
@@ -46770,7 +46984,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
46770
46984
|
}
|
|
46771
46985
|
if (bindings)
|
|
46772
46986
|
secretEnv = await resolveSelectedSecrets(bindings, options.createSecretsClient);
|
|
46773
|
-
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [],
|
|
46987
|
+
const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], join39(runDirectory, declaredEntry), ...args], runDirectory, { ...env, ...secretEnv }, input2, timeoutMs);
|
|
46774
46988
|
result.stdout = redactExecutionSecrets(result.stdout, secretEnv);
|
|
46775
46989
|
result.stderr = redactExecutionSecrets(result.stderr, secretEnv);
|
|
46776
46990
|
const receipt = {
|
|
@@ -46778,13 +46992,13 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
46778
46992
|
target: "local",
|
|
46779
46993
|
runtime: runtimeName,
|
|
46780
46994
|
entrypoint: declaredEntry,
|
|
46781
|
-
inputDigest: `sha256:${
|
|
46995
|
+
inputDigest: `sha256:${createHash29("sha256").update(input2).digest("hex")}`,
|
|
46782
46996
|
runDirectory,
|
|
46783
46997
|
...executionGrant ? { executionGrant } : {},
|
|
46784
46998
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
46785
46999
|
...result
|
|
46786
47000
|
};
|
|
46787
|
-
writeFileSync11(
|
|
47001
|
+
writeFileSync11(join39(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
|
|
46788
47002
|
return receipt;
|
|
46789
47003
|
}
|
|
46790
47004
|
async function subprocess(command, cwd, env, input2, timeoutMs) {
|
|
@@ -46973,8 +47187,8 @@ var init_blog_article = __esm(() => {
|
|
|
46973
47187
|
});
|
|
46974
47188
|
|
|
46975
47189
|
// src/mcp/operation-tools.ts
|
|
46976
|
-
import { existsSync as existsSync16, readdirSync as
|
|
46977
|
-
import { join as
|
|
47190
|
+
import { existsSync as existsSync16, readdirSync as readdirSync13, statSync as statSync12 } from "fs";
|
|
47191
|
+
import { join as join40 } from "path";
|
|
46978
47192
|
function registerOperationTools(server) {
|
|
46979
47193
|
server.registerTool("cloud_skill_eligibility", {
|
|
46980
47194
|
title: "Cloud Skill Eligibility",
|
|
@@ -47455,8 +47669,8 @@ function registerOperationTools(server) {
|
|
|
47455
47669
|
let skillCount = 0;
|
|
47456
47670
|
if (exists) {
|
|
47457
47671
|
try {
|
|
47458
|
-
skillCount =
|
|
47459
|
-
const full =
|
|
47672
|
+
skillCount = readdirSync13(agentSkillsPath).filter((f) => {
|
|
47673
|
+
const full = join40(agentSkillsPath, f);
|
|
47460
47674
|
return !f.startsWith(".") && statSync12(full).isDirectory();
|
|
47461
47675
|
}).length;
|
|
47462
47676
|
} catch {}
|
|
@@ -47524,14 +47738,14 @@ var init_operation_tools = __esm(() => {
|
|
|
47524
47738
|
|
|
47525
47739
|
// src/lib/feedback.ts
|
|
47526
47740
|
import { appendFileSync, existsSync as existsSync17, mkdirSync as mkdirSync14 } from "fs";
|
|
47527
|
-
import { dirname as
|
|
47741
|
+
import { dirname as dirname28, join as join41 } from "path";
|
|
47528
47742
|
import { Database } from "bun:sqlite";
|
|
47529
47743
|
function getFeedbackDbPath() {
|
|
47530
|
-
return
|
|
47744
|
+
return join41(getDataDir(), "skills.db");
|
|
47531
47745
|
}
|
|
47532
47746
|
function getFeedbackDb() {
|
|
47533
47747
|
const dbPath = getFeedbackDbPath();
|
|
47534
|
-
const dir =
|
|
47748
|
+
const dir = dirname28(dbPath);
|
|
47535
47749
|
if (!existsSync17(dir))
|
|
47536
47750
|
mkdirSync14(dir, { recursive: true });
|
|
47537
47751
|
const db = new Database(dbPath);
|
|
@@ -47559,8 +47773,8 @@ function saveFeedback(input2) {
|
|
|
47559
47773
|
throw new Error("Feedback message is required");
|
|
47560
47774
|
const category = input2.category ?? "general";
|
|
47561
47775
|
if (isApiMode()) {
|
|
47562
|
-
const path =
|
|
47563
|
-
const dir =
|
|
47776
|
+
const path = join41(getDataDir(), "feedback.jsonl");
|
|
47777
|
+
const dir = dirname28(path);
|
|
47564
47778
|
if (!existsSync17(dir))
|
|
47565
47779
|
mkdirSync14(dir, { recursive: true });
|
|
47566
47780
|
appendFileSync(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
|
|
@@ -47723,23 +47937,23 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
47723
47937
|
});
|
|
47724
47938
|
|
|
47725
47939
|
// src/lib/scheduler.ts
|
|
47726
|
-
import { existsSync as existsSync18, readFileSync as
|
|
47727
|
-
import { join as
|
|
47940
|
+
import { existsSync as existsSync18, readFileSync as readFileSync24, writeFileSync as writeFileSync12, mkdirSync as mkdirSync15 } from "fs";
|
|
47941
|
+
import { join as join42 } from "path";
|
|
47728
47942
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
47729
|
-
return
|
|
47943
|
+
return join42(targetDir, ".skills", "schedules.json");
|
|
47730
47944
|
}
|
|
47731
47945
|
function loadSchedules(targetDir = process.cwd()) {
|
|
47732
47946
|
const path = getSchedulesPath(targetDir);
|
|
47733
47947
|
if (existsSync18(path)) {
|
|
47734
47948
|
try {
|
|
47735
|
-
return JSON.parse(
|
|
47949
|
+
return JSON.parse(readFileSync24(path, "utf-8"));
|
|
47736
47950
|
} catch {}
|
|
47737
47951
|
}
|
|
47738
47952
|
return { version: 1, schedules: [] };
|
|
47739
47953
|
}
|
|
47740
47954
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
47741
47955
|
const path = getSchedulesPath(targetDir);
|
|
47742
|
-
const dir =
|
|
47956
|
+
const dir = join42(targetDir, ".skills");
|
|
47743
47957
|
if (!existsSync18(dir))
|
|
47744
47958
|
mkdirSync15(dir, { recursive: true });
|
|
47745
47959
|
writeFileSync12(path, JSON.stringify(data, null, 2));
|
|
@@ -48011,16 +48225,16 @@ var init_schedule_tools = __esm(() => {
|
|
|
48011
48225
|
});
|
|
48012
48226
|
|
|
48013
48227
|
// src/lib/native-storage.ts
|
|
48014
|
-
import { createHash as
|
|
48228
|
+
import { createHash as createHash30, createHmac } from "crypto";
|
|
48015
48229
|
import {
|
|
48016
48230
|
existsSync as existsSync19,
|
|
48017
48231
|
mkdirSync as mkdirSync16,
|
|
48018
|
-
readFileSync as
|
|
48019
|
-
readdirSync as
|
|
48232
|
+
readFileSync as readFileSync25,
|
|
48233
|
+
readdirSync as readdirSync14,
|
|
48020
48234
|
statSync as statSync13,
|
|
48021
48235
|
writeFileSync as writeFileSync13
|
|
48022
48236
|
} from "fs";
|
|
48023
|
-
import { dirname as
|
|
48237
|
+
import { dirname as dirname29, join as join43, normalize as normalize5, relative as relative10, sep as sep14 } from "path";
|
|
48024
48238
|
function resolveSkillsNativeStorageConfig(env = process.env) {
|
|
48025
48239
|
assertNoRetiredModeEnvVars(env, {
|
|
48026
48240
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -48061,7 +48275,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
48061
48275
|
local: {
|
|
48062
48276
|
dataDir: getDataDir(),
|
|
48063
48277
|
projectStateDir: getProjectStateDir(targetDir),
|
|
48064
|
-
feedbackDbPath:
|
|
48278
|
+
feedbackDbPath: join43(getDataDir(), "skills.db")
|
|
48065
48279
|
},
|
|
48066
48280
|
remote: {
|
|
48067
48281
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -48083,12 +48297,12 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
48083
48297
|
const files = [];
|
|
48084
48298
|
if (existsSync19(projectStateDir)) {
|
|
48085
48299
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
48086
|
-
const bytes =
|
|
48300
|
+
const bytes = readFileSync25(filePath);
|
|
48087
48301
|
const relativePath = toPosix(relative10(targetDir, filePath));
|
|
48088
48302
|
files.push({
|
|
48089
48303
|
path: relativePath,
|
|
48090
48304
|
sizeBytes: bytes.byteLength,
|
|
48091
|
-
sha256:
|
|
48305
|
+
sha256: createHash30("sha256").update(bytes).digest("hex"),
|
|
48092
48306
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
48093
48307
|
});
|
|
48094
48308
|
}
|
|
@@ -48141,8 +48355,8 @@ function parsePositiveInteger(value) {
|
|
|
48141
48355
|
}
|
|
48142
48356
|
function walkFiles2(dir) {
|
|
48143
48357
|
const files = [];
|
|
48144
|
-
for (const entry of
|
|
48145
|
-
const full =
|
|
48358
|
+
for (const entry of readdirSync14(dir)) {
|
|
48359
|
+
const full = join43(dir, entry);
|
|
48146
48360
|
const stats = statSync13(full);
|
|
48147
48361
|
if (stats.isDirectory())
|
|
48148
48362
|
files.push(...walkFiles2(full));
|
|
@@ -48408,20 +48622,20 @@ var init_private_publication_customer = __esm(() => {
|
|
|
48408
48622
|
});
|
|
48409
48623
|
|
|
48410
48624
|
// src/lib/private-publication-recovery.ts
|
|
48411
|
-
import { constants as constants20, closeSync as closeSync23, fsyncSync as fsyncSync6, fstatSync as fstatSync23, lstatSync as
|
|
48412
|
-
import { dirname as
|
|
48625
|
+
import { constants as constants20, closeSync as closeSync23, fsyncSync as fsyncSync6, fstatSync as fstatSync23, lstatSync as lstatSync28, mkdirSync as mkdirSync17, openSync as openSync23, readSync as readSync15, realpathSync as realpathSync14, renameSync as renameSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
|
|
48626
|
+
import { dirname as dirname30, isAbsolute as isAbsolute27, join as join44, resolve as resolve27 } from "path";
|
|
48413
48627
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
48414
48628
|
function safeDirectory(directory2) {
|
|
48415
48629
|
if (!isAbsolute27(directory2) || directory2 !== resolve27(directory2) || realpathSync14(directory2) !== directory2)
|
|
48416
48630
|
return fail2();
|
|
48417
|
-
for (let path = directory2;; path =
|
|
48418
|
-
const stat3 =
|
|
48631
|
+
for (let path = directory2;; path = dirname30(path)) {
|
|
48632
|
+
const stat3 = lstatSync28(path);
|
|
48419
48633
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
48420
48634
|
return fail2();
|
|
48421
|
-
if (path ===
|
|
48635
|
+
if (path === dirname30(path))
|
|
48422
48636
|
break;
|
|
48423
48637
|
}
|
|
48424
|
-
const own2 =
|
|
48638
|
+
const own2 = lstatSync28(directory2);
|
|
48425
48639
|
if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
48426
48640
|
return fail2();
|
|
48427
48641
|
return { dev: own2.dev, ino: own2.ino };
|
|
@@ -48432,7 +48646,7 @@ function unchangedDirectory(directory2, identity4) {
|
|
|
48432
48646
|
return fail2();
|
|
48433
48647
|
}
|
|
48434
48648
|
function readOwned(directory2, name, max) {
|
|
48435
|
-
const identity4 = safeDirectory(directory2), file2 =
|
|
48649
|
+
const identity4 = safeDirectory(directory2), file2 = join44(directory2, name);
|
|
48436
48650
|
const fd = openSync23(file2, constants20.O_RDONLY | constants20.O_NOFOLLOW);
|
|
48437
48651
|
try {
|
|
48438
48652
|
const stat3 = fstatSync23(fd);
|
|
@@ -48456,7 +48670,7 @@ function readOwned(directory2, name, max) {
|
|
|
48456
48670
|
}
|
|
48457
48671
|
}
|
|
48458
48672
|
function writeOwned(directory2, name, bytes) {
|
|
48459
|
-
const fd = openSync23(
|
|
48673
|
+
const fd = openSync23(join44(directory2, name), constants20.O_WRONLY | constants20.O_CREAT | constants20.O_EXCL | constants20.O_NOFOLLOW, 384);
|
|
48460
48674
|
try {
|
|
48461
48675
|
writeFileSync14(fd, bytes);
|
|
48462
48676
|
fsyncSync6(fd);
|
|
@@ -48469,7 +48683,7 @@ function save(directory2, value) {
|
|
|
48469
48683
|
writeOwned(directory2, temporary, JSON.stringify(value) + `
|
|
48470
48684
|
`);
|
|
48471
48685
|
unchangedDirectory(directory2, identity4);
|
|
48472
|
-
renameSync7(
|
|
48686
|
+
renameSync7(join44(directory2, temporary), join44(directory2, "receipt.json"));
|
|
48473
48687
|
const fd = openSync23(directory2, constants20.O_RDONLY | constants20.O_NOFOLLOW);
|
|
48474
48688
|
try {
|
|
48475
48689
|
fsyncSync6(fd);
|
|
@@ -48482,7 +48696,7 @@ function bind(client, receipt) {
|
|
|
48482
48696
|
throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
|
|
48483
48697
|
}
|
|
48484
48698
|
async function locked(directory2, action) {
|
|
48485
|
-
const identity4 = safeDirectory(directory2), file2 =
|
|
48699
|
+
const identity4 = safeDirectory(directory2), file2 = join44(directory2, "operation.lock");
|
|
48486
48700
|
let fd;
|
|
48487
48701
|
try {
|
|
48488
48702
|
fd = openSync23(file2, constants20.O_WRONLY | constants20.O_CREAT | constants20.O_EXCL | constants20.O_NOFOLLOW, 384);
|
|
@@ -48498,7 +48712,7 @@ async function locked(directory2, action) {
|
|
|
48498
48712
|
} finally {
|
|
48499
48713
|
closeSync23(fd);
|
|
48500
48714
|
unchangedDirectory(directory2, identity4);
|
|
48501
|
-
const now =
|
|
48715
|
+
const now = lstatSync28(file2);
|
|
48502
48716
|
if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
|
|
48503
48717
|
fail2();
|
|
48504
48718
|
unlinkSync6(file2);
|
|
@@ -48550,11 +48764,11 @@ async function preparePrivatePublication(client, sourceDirectory, recoveryDirect
|
|
|
48550
48764
|
phase: "prepared",
|
|
48551
48765
|
intent: null
|
|
48552
48766
|
};
|
|
48553
|
-
if (!isAbsolute27(recoveryDirectory) || resolve27(recoveryDirectory) !== recoveryDirectory || realpathSync14(
|
|
48767
|
+
if (!isAbsolute27(recoveryDirectory) || resolve27(recoveryDirectory) !== recoveryDirectory || realpathSync14(dirname30(recoveryDirectory)) !== dirname30(recoveryDirectory))
|
|
48554
48768
|
return fail2();
|
|
48555
48769
|
mkdirSync17(recoveryDirectory, { mode: 448 });
|
|
48556
48770
|
safeDirectory(recoveryDirectory);
|
|
48557
|
-
const parent = openSync23(
|
|
48771
|
+
const parent = openSync23(dirname30(recoveryDirectory), constants20.O_RDONLY | constants20.O_NOFOLLOW);
|
|
48558
48772
|
try {
|
|
48559
48773
|
fsyncSync6(parent);
|
|
48560
48774
|
} finally {
|
|
@@ -49005,13 +49219,13 @@ function legacyInputSchema(rest) {
|
|
|
49005
49219
|
function jsonSchema(schema, io) {
|
|
49006
49220
|
if (schema === undefined || schema === null)
|
|
49007
49221
|
return;
|
|
49008
|
-
const
|
|
49009
|
-
const def =
|
|
49222
|
+
const object8 = isRawShape(schema) ? exports_external.object(schema) : schema;
|
|
49223
|
+
const def = object8._zod?.def;
|
|
49010
49224
|
if (!def)
|
|
49011
49225
|
throw new Error("Skills MCP tool schemas must be built with this package's zod 4");
|
|
49012
49226
|
if (def.type !== "object" && def.shape === undefined)
|
|
49013
49227
|
return;
|
|
49014
|
-
return exports_external.toJSONSchema(
|
|
49228
|
+
return exports_external.toJSONSchema(object8, { target: "draft-7", io });
|
|
49015
49229
|
}
|
|
49016
49230
|
var EMPTY_OBJECT_JSON_SCHEMA;
|
|
49017
49231
|
var init_package_tool_list = __esm(() => {
|